/********************************************************************************//*!
 * @file  mb_sample.c
 * @brief  Sample program using Mailbox Client IP from Nios II.
 * 
 * @details  Includes implementation examples for controlling the following:
 *            - Read voltage/temperature sensor
 *            - Remote system update
 *            - Access to QSPI Flash
 * 
 * @note  nothing. 
 * 
 * @date <b> History: \<Date\> \<Rev\> \<Keyword\> \<Details\> </b>
 * @date 2023/01/24  ---  #46372  Create new.
 * 
 * @attention 
 * Copyright (C) 2023 MACNICA,Inc. All Rights Reserved.\n
 *   This software is licensed "AS IS". 
 *   Please perform use of this software by a user's own responsibility and expense.
 *   It cannot guarantee in the maker side about the damage which occurred by the ab-
 *   ility not to use or use this software, and all damage that occurred secondarily.
 **//*******************************************************************************/

#include "system.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <altera_s10_mailbox_client.h>
#include <altera_s10_mailbox_client_flash.h>
#include "io.h"

#define FACTORY_ADDR 0x00110000
#define APP0_ADDR 0x00500000

/***********************************************************************************
 *  Main function
 ***********************************************************************************/
int main()
{
	//General
	int i = 0, n = 0;
	int num=0;
	int result = 0;

	//Command
	int argument_length, command_length;
	alt_u32 response_length, cmd;
	alt_u32 argument[2];
	alt_u32 response_stored[10];
	alt_u32 write_data_cmd[1];
	alt_u8  id;

	//Mailbox Client IP
	intel_mailbox_client* fd;

	//Remote System Upgrade(RSU)
	int rsu_addr=0;

	//QSPI access
	//info
	flash_region* info;
	int number_of_regions;
	int offset=0, region_size=0, number_of_blocks=0, block_size=0;
	//Buffer dump
	int dump_sel = 0;
	int dump_size=0;
	int dump_data = 0;
	//Erase/read/write
	int block_num=0;
	int block_offset=0;
	//read
	int read_addr=0, read_data=0;
	//write
	int write_addr=0, write_data=0;
	//write fill
	char source[1024];
	int length=0;
	//device ID
	int device_id[2];
	//other
	int end_loop=0;

	printf("Mailbox Client IP Sample Start!\n\n");

	//Mailbox Client Open
	fd = mailbox_client_open(S10_MAILBOX_CLIENT_1_NAME);
	if(result == 0) printf("result=%d, Mailbox Client IP Open Success\n",result);
	else printf("result=%d, Mailbox Client IP  Open Fail\n",result);
	printf("\n");

	while(1){
		/***********************************************************************************
		 *  Menu
		 ***********************************************************************************/
		printf("=====Menu=====\n");
		printf("0: Temperature/Voltage Sensor\n");
		printf("1: Remote System Upgrade(RSU)\n");
		printf("2: QSPI access\n");
		printf("3: Sample Finish\n");
		printf("==============\n");
		scanf("%d",&n);

		/***********************************************************************************
		 *  0: Temperature/Voltage Sensor
		 ***********************************************************************************/
		if(n == 0){
			while(1){
				printf("\n");
				printf("=====Menu=====\n");
				printf("0: Voltage Sensor\n");
				printf("1: Temperature Sensor\n");
				printf("2: Finish\n");
				printf("==============\n");
				scanf("%d",&n);

				// Voltage Sensor
				if(n==0){
					printf("---Get Voltage value---\n");
					printf("Channel: ");
					scanf("%d",&i);

					cmd                 = 0x18; //GET_VOLTAGE code
					id                  = MAILBOX_FLASH_ID;
					argument[0]         = 1; // Channel
					argument_length     = 1;
					command_length      = 1;
					write_data_cmd[0]   = 0;
					response_length     = 1;

					for(num=0 ; num < 10 ; num++){ //initialize response_stored[]
						response_stored[num]=0;
					}

					argument[0] = 0x00000001 << i; // channel
					result = mailbox_client_send_cmd(fd, id, cmd, argument,
							argument_length, command_length, write_data_cmd,
							response_stored, response_length);
					if(result == 0) printf("result=%d, Get Voltage Success\n",result);
					else printf("result=%d, Get Voltage Fail\n",result);

					printf("==========\n");
					printf("Channel %d\n",i);
					printf("Voltage Value is 0x%08lx\n",response_stored[0]);
					printf("==========\n\n");
				}
				//Temperature Sensor
				else if(n==1){
					printf("---Get Temperature value---\n");
					printf("dump_select Channel: ");
					scanf("%d",&i);

					cmd                 = 0x19; //GET_TEMPERATURE code
					id                  = MAILBOX_FLASH_ID;
					argument[0]         = 0; // Channel
					argument_length     = 1;
					command_length      = 1;
					write_data_cmd[0]   = 0;
					response_length     = 1;

					for(num=0 ; num < 10 ; num++){//initialize response_stored[]
						response_stored[num]=0;
					}

					argument[0] = 0x00000001 << i; // channel
					result = mailbox_client_send_cmd(fd, id, cmd, argument,
							argument_length, command_length, write_data_cmd,
							response_stored, response_length);
					if(result == 0) printf("result=%d, Get Temperature value Success\n",result);
					else printf("result=%d, Get Temperature value Fail\n",result);

					printf("==========\n");
					printf("Channel %d\n",i);
					printf("Temperature value is 0x%08lx\n",response_stored[0]);
					printf("==========\n\n");

				}
				else if (n==2){
					printf("Finish\n");
					break;
				}
				else {
					printf("incorrect input!\n");
				}
			}
		}

		/***********************************************************************************
		 *  1: Remote System Upgrade(RSU)
		 ***********************************************************************************/
		else if(n == 1){
			while(1){
				printf("\n");
				printf("=====Menu=====\n");
				printf("0: check current Image Address\n");
				printf("1: Remote System Upgrade(RSU)\n");
				printf("2: Finish\n");
				printf("==============\n");
				scanf("%d",&n);

				if(n == 0){
					//check current Image
					cmd                 = 0x5B; //RSU_STATUS code
					id                  = MAILBOX_FLASH_ID;
					argument_length     = 0;
					command_length      = 0;
					write_data_cmd[0]   = 0;
					response_length     = 9;

					result = mailbox_client_send_cmd(fd, id, cmd, 0,
							argument_length, command_length, write_data_cmd,
							response_stored, response_length);

					printf("=====Current status=====\n");
					printf("Current Image Address = 0x%08lx\n",response_stored[0]);
					printf("========================\n\n");
				}

				else if(n == 1){
					//Message
					printf("Note. Jtag Connection is disconnected by RSU.\n");
					printf("Please reconnect the debugger again.\n\n");

					//Remote System Upgrade
					printf("=====choose IMG=====\n");
					printf("0: Factory IMG(0x%08x)\n",FACTORY_ADDR);
					printf("1: APP0(0x%08x)\n",APP0_ADDR);
					printf("2: Other Image\n");
					printf("====================\n");
					scanf("%d",&n);

					if(n == 0) rsu_addr = FACTORY_ADDR;
					else if(n == 1) rsu_addr = APP0_ADDR;
					else if (n == 2) {
						printf("Please input address that image is stored.\n");
						scanf("%d",&rsu_addr);
					}

					printf("Upgrading the image...\n");
					printf("If error doesn't appear, probably RSU is success.\n");

					cmd                 = 0x5C;     //RSU image update code
					id                  = MAILBOX_FLASH_ID;
					argument[0]         = rsu_addr; //[31:0]QSPI address
					argument[1]         = 0;        //[64:0]QSPI address
					argument_length     = 2;
					command_length      = 2;
					write_data_cmd[0]   = 0;
					response_length     = 0;

					result = mailbox_client_send_cmd(fd, id, cmd, argument,
							argument_length, command_length, write_data_cmd,
							response_stored, response_length);

					if(result != 0) printf("result = %d, Error: Remote System Upgrade Fail\n", result);
					while(1);
				}

				else if(n == 2){
					printf("Finish");
					break;
				}
				else {
					printf("incorrect Input");
				}
			}
		}

		/***********************************************************************************
		 *  2: QSPI Access
		 ***********************************************************************************/
		else if(n == 2){
			end_loop=0;

			//Flash(QSPI) Open
			result = mailbox_client_flash_open(fd);
			if(result == 0) printf("result=%d, QSPI Flash Open Success\n",result);
			else printf("result=%d, QSPI Flash Open Fail\n",result);

			//Get Info
			result = mailbox_client_flash_get_info(fd, &info, &number_of_regions);
			if(result == 0) printf("result=%d, getinfo Success\n",result);
			else printf("result=%d, getinfo Fail\n",result);
			offset = info->offset;
			region_size = info->region_size;
			number_of_blocks = info->number_of_blocks;
			block_size = info->block_size;
			printf("\n");

			//MENU
			while(1){
				printf("=========================================\n");
				printf("QSPI Access MENU\n");
				printf("0: Get QSPI Flash Info\n");
				printf("1: Buffer Initialize(Sector size(0x%x Byte))\n",block_size);
				printf("2: Buffer Dump(4/16/64/SectorSize(0x%x) Byte)\n",block_size);
				printf("3: Erase Sector\n");
				printf("4: Read Data\n");
				printf("5: Read Sector\n");
				printf("6: Write Data\n");
				printf("7: Flash Fill Data\n");
				printf("8: QSPI Flash Close\n");
				printf("=========================================\n");
				printf("\n");
				printf("Enter number: ");
				scanf("%d",&n);

				switch(n){
				case 0: //Print Flash Info
					printf("~~~ 0: Get QSPI Flash Info ~~~\n");
					printf("offset = %d\n", offset);
					printf("region_size = 0x%x\n", region_size);
					printf("number_of_blocks(number of sector) = %d\n", number_of_blocks);
					printf("block_size(sector size) = 0x%x (decimal: %d)\n", block_size, block_size);
					printf("number_of_regions = %d\n", number_of_regions);
					printf("\n");
					break;

				case 1: //Buffer Initialize
					printf("~~~ 1: Buffer Initialize(Sector size(0x%x)) ~~~\n",block_size);
					for (i = 0 ; i*4 < block_size ; i++){
						IOWR(BUFFER_0_BASE, i, 0);
					}
					printf("Buffer Initialization finish\n");
					printf("\n");
					break;

				case 2: //Buffer dump
					printf("~~~ 2: Buffer dump ~~~\n");
					printf("=====DumpSize=====\n");
					printf("0: 4Byte(1word)\n");
					printf("1: 16Byte(4word)\n");
					printf("2: 64Byte(16word)\n");
					printf("3: 1KByte\n");
					printf("4: sector Size(0x%xByte)\n\n", block_size);
					printf("Select dump size: \n");
					printf("=================\n");
					scanf("%d",&dump_sel);
					if(dump_sel == 0) dump_size = 4;
					else if(dump_sel == 1) dump_size = 16;
					else if(dump_sel == 2) dump_size = 64;
					else if(dump_sel == 3) dump_size = 1024;
					else if(dump_sel == 4) dump_size = block_size;
					else {
						printf("Input number isn't correct\n\n");
						break;
					}
					printf("Dump Size is %d Byte\n", dump_size);
					for (i = 0 ; i*4 < dump_size ; i++){
						if(i%4 == 0) printf("Addr 0x%08x:   ",i*4);
						dump_data = IORD(BUFFER_0_BASE, i);
						printf("0x%08x  ", dump_data);
						if ((i+1)%4 == 0) printf("\n");
					}
					printf("\n");
					break;

				case 3: //Flash erase
					printf("~~~ 3: Erase Sector ~~~\n");
					printf("Please Input Sector number(0 ~ %d): ", number_of_blocks);
					scanf("%d", &block_num);
					block_offset = block_num * block_size;
					result = mailbox_client_flash_erase_block(fd, block_offset);
					if(result == 0) printf("result=%d, Erase Success\n",result);
					else printf("result=%d, Erase Fail\n",result);
					printf("\n");
					break;

				case 4: //Flash read(1word(32bit))
					printf("~~~ 4: Read Data(1word(32bit)) ~~~\n");
					printf("Read addr(hex): ");
					scanf("%x", &read_addr);
					result = mailbox_client_flash_read(fd, read_addr, (int*)BUFFER_0_BASE, 4);
					read_data = IORD(BUFFER_0_BASE, 0);
					if(result == 0) printf("result=%d, Read Success\n",result);
					else printf("result=%d, Read Fail\n",result);
					printf("Read Data is 0x%08x\n", read_data);
					printf("\n");
					break;

				case 5: //Flash Sector read
					printf("~~~ 5: Read Sector ~~~\n");
					printf("Please Input Sector number(0 ~ %d): ", number_of_blocks);
					scanf("%d", &block_num);
					read_addr = block_num * block_size;
					result = mailbox_client_flash_read(fd, read_addr, (int*)BUFFER_0_BASE, block_size);
					if(result == 0) printf("result=%d, Read Sector Success\n",result);
					else printf("result=%d, Read Sector Fail\n",result);
					printf("Read Sector data is stored to buffer\n");
					printf("\n");
					break;

				case 6: //Flash write(1word(32bit))
					printf("~~~ 6: Write Data(1word(32bit)) ~~~\n");
					printf("write addr(hex): ");
					scanf("%x",&write_addr);
					printf("write data(hex): ");
					scanf("%x",&write_data);
					block_num = write_addr / block_size;
					block_offset = block_size * block_num;
					result = mailbox_client_flash_read(fd, block_offset, (int*)BUFFER_0_BASE, block_size);
					write_addr = write_addr - block_offset;
					IOWR(BUFFER_0_BASE + write_addr, 0 , write_data);
					result = mailbox_client_flash_write(fd, block_offset, (int*)BUFFER_0_BASE, block_size);
					if(result == 0) printf("result=%d, Write Success\n",result);
					else printf("result=%d, Write Fail\n",result);
					printf("\n");
					break;

				case 7: //Flash Fill data
					printf("~~~ 7: Flash Fill data ~~~\n");
					printf("Please Input Write Address(hex): ");
					scanf("%x", &write_addr);
					printf("Please Input Write Byte data(hex): ");
					scanf("%x", &write_data);
					printf("Please Input length (0~1024)(decimal): ");
					scanf("%d", &length);
					memset(source, write_data, 1024); //1KB
					block_num = write_addr / block_size;
					block_offset = block_num * block_size;
					result = mailbox_client_flash_erase_block(fd, block_offset);
					if(result != 0) {
						printf("result=%d, Erase in Flash Fill Data is fail\n",result);
						break;
					}
					result = mailbox_client_flash_write_block(fd, block_offset, write_addr, source, length);
					if(result == 0) printf("result=%d, Flash Fill data Success\n",result);
					else printf("result=%d, Flash Fill data Fail\n",result);
					printf("\n");
					break;   //			  write_addr = write_addr - block_offset; ga irukamo

				case 8:
					//QSPI Close
					printf("~~~ 8: QSPI Flash Close ~~~\n");
					result = mailbox_client_flash_close(fd);
					if(result == 0) printf("result=%d, QSPI Flash Close Success\n\n", result);
					else printf("result=%d, QSPI Flash Close Fail\n\n", result);
					end_loop=1;
					break;

				default:
					printf("Enter number again\n");
					n=0;
				}
				if (end_loop == 1) break;
			}
		}
		else if(n == 3){
			printf("Mailbox Client IP Sample Finish!\n");
			break;
		}


		else {
			printf("Incorrect input! Please enter a number from 0 to 3.\n");
		}
	}

	return 0;
}
