/*
 * @brief CCAN on-chip driver example
 *
 * @note
 * Copyright(C) NXP Semiconductors, 2012
 * All rights reserved.
 *
 * @par
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * LPC products.  This software is supplied "AS IS" without any warranties of
 * any kind, and NXP Semiconductors and its licensor disclaim any and
 * all warranties, express or implied, including all implied warranties of
 * merchantability, fitness for a particular purpose and non-infringement of
 * intellectual property rights.  NXP Semiconductors assumes no responsibility
 * or liability for the use of the software, conveys no license or rights under any
 * patent, copyright, mask work right, or any other intellectual property rights in
 * or to any products. NXP Semiconductors reserves the right to make changes
 * in the software without notification. NXP Semiconductors also makes no
 * representation or warranty that such application will be suitable for the
 * specified use without further testing or modification.
 *
 * @par
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, under NXP Semiconductors' and its
 * licensor's relevant copyrights in the software, without fee, provided that it
 * is used in conjunction with NXP Semiconductors microcontrollers.  This
 * copyright, permission, and disclaimer notice must appear in all copies of
 * this code.
 */

#include "board.h"
#include "chip.h"
#include "IAP.h"
#include "systick.h"
/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/

#define TEST_CCAN_BAUD_RATE 500000

#define INFO 1
#define READID 2
#define BLANKCHK 3
#define ERASE 4
#define DEMO 5
#define RUN 6
#define HELP 7

#define HAVE_DATA 0
#define HAVE_NO_DATA 1

#define APP_START_ADDR 0x6000

/* Local constants */
static const char intro[] =
   "\n\n"
   "+-----------------------------------------------------------------------+\n"
   "|                LPC11Cxx Bootloader via CAN                             |\n";
static const char help[] = 
   "+ command ------------------+ function ---------------------------------+\n"
   "| info                      | display the bootloader info               |\n"
   "| readID                    | read part ID                              |\n"
   "| blkchk [sectors]          | check if flash sectors are blank          |\n"
   "| erase [sectors]           | erase flash sectors                       |\n"
   "| run [addr]                | Run application in internal FLASH         |\n"
   "|                           | [addr - app. address, default=0x6000      |\n"
   "| demo                      | Run Demo Program, Wait Code...            |\n"
   "| HELP                      | displays this help                        |\n"
   "+---------------------------+-------------------------------------------+\n";

uint8_t app_code[4096] = {0};

uint8_t str[10];
uint32_t i;
uint8_t have_data = HAVE_NO_DATA;

CCAN_MSG_OBJ_T msg_obj;

/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/

/*****************************************************************************
 * Private functions
 ****************************************************************************/
uint8_t DB_GetChar_1(void)
{
	uint8_t data;
	while(!(LPC_USART->LSR&0x01))
	{
	 if(ticks>2)
		{
			i=0;
			str[0] = 0;
		}
	}
	data = LPC_USART->RBR;
	return data;		
}


uint8_t* DB_GetString_1(void)
{
	uint8_t* str1;
	i=0;
	while(str[i-1] != '\n')
	{
		while(!(LPC_USART->LSR&0x01));
		str[i] = LPC_USART->RBR;
		printf("%c",str[i]);
		ticks = 0;
		i++;
	}
	str1 = str;
	return str1;
	
}


void List_Cmd(void)
{
	printf(intro);
	printf(help);
	printf("Cmd>");
}

uint8_t Judge_Cmd(void)
{
	uint8_t *str;
	str=DB_GetString_1();
	if(str[0]=='i'&&str[1]=='n'&&str[2]=='f'&&str[3]=='o')
	return INFO;
	else if(str[0]=='r'&&str[1]=='e'&&str[2]=='a'&&str[3]=='d'&&str[4]=='I'&&str[5]=='D')
	return READID;
	else if(str[0]=='b'&&str[1]=='l'&&str[2]=='k'&&str[3]=='c'&&str[4]=='h'&&str[5]=='k'&&str[6]==' '&&str[7]=='6')
	return BLANKCHK;
	else if(str[0]=='e'&&str[1]=='r'&&str[2]=='a'&&str[3]=='s'&&str[4]=='e'&&str[5]==' '&&str[6]=='6')
	return ERASE;	
	else if(str[0]=='d'&&str[1]=='e'&&str[2]=='m'&&str[3]=='o')
	return DEMO;
	if(str[0]=='r'&&str[1]=='u'&&str[2]=='n'&&str[3]==' '&&str[4]=='0'&&str[5]=='x'&&str[6]=='6'&&str[7]=='0'&&str[8]=='0'&&str[9]=='0')
	return RUN;
	if(str[0]=='h'&&str[1]=='e'&&str[2]=='l'&&str[3]=='p')
	return HELP;
	else
	return ERROR;
}


void Display_Info(void)
{
	
	printf("  Bootloader:\n");
	printf("  		Entry: 0x0\n");
	printf("  		Version: Jan 26 2015\n");
	printf("Cmd>\n");
}
void Display_ReadID(void)
{

	printf("Part ID:\n");
	printf("0x%.8X\n",u32IAP_PartIdRead());
	printf("Cmd>");
}

void Erase_Sector(void)
{
	uint8_t ucErr;
	u32IAP_PrepareSectors(6,6);
	ucErr = u32IAP_EraseSectors(6,6);
	if(ucErr==IAP_STA_CMD_SUCCESS)
	 printf("erase success\n");
	else printf("erase failed\n");
	printf("Cmd>\n");
}

void Blank_Check(void)
{
	uint32_t *pu32Result = 0;
	uint8_t ucErr;
	uint32_t m;
	
	ucErr = u32IAP_BlankCheckSectors(6, 6, pu32Result);
	for(m=0;m<10000;m++);//delay
	if(ucErr==IAP_STA_SECTOR_NOT_BLANK)
		printf("sector 6 is not blank\n");
	else 
		printf("sector 6 is blank\n");
	printf("\nCmd>");
}

void RX_TX_Bouncing(void)
{ 
	uint32_t j;
	uint32_t count = 0;
  
	while(count<4096)
	{
		if(have_data==HAVE_DATA)
		{
			have_data = HAVE_NO_DATA;
			 for(j = 0;j<8;j++)
			{
				//DB_PutDec(msg_obj.data[j]);
				//DB_PutChar(' ');
				app_code[count] = msg_obj.data[j];
				count++;
                if(count==sizeof(app_code)/10)
                {
                    printf("Transmitting...");
                	printf("10%%");
                }
                else if(count==sizeof(app_code)/10*2)
                    printf("\b\b\b20%%");
                else if(count==sizeof(app_code)/10*3)
                    printf("\b\b\b30%%");
                else if(count==sizeof(app_code)/10*4)
                    printf("\b\b\b40%%");
                else if(count==sizeof(app_code)/10*5)
                    printf("\b\b\b50%%");
                else if(count==sizeof(app_code)/10*6)
                    printf("\b\b\b60%%");
                else if(count==sizeof(app_code)/10*7)
                    printf("\b\b\b70%%");
                else if(count==sizeof(app_code)/10*8)
                    printf("\b\b\b80%%");
                else if(count==sizeof(app_code)/10*9)
                    printf("\b\b\b90%%");
				
			}
		}
	}
	printf("\b\b\b100%%\n");
	count = 0;
		
	
}


uint8_t Copy_App(void)
{
	uint8_t  ucErr;
	DisableIRQ();
	u32IAP_PrepareSectors(6,6);
	u32IAP_EraseSectors(6,6);
	
	u32IAP_PrepareSectors(6,6);
	ucErr = u32IAP_CopyRAMToFlash(APP_START_ADDR,(uint32_t)app_code,4096);
	EnableIRQ();
	return ucErr;
}
void Demo(void)
{
	uint8_t  ucEr;
	NVIC_EnableIRQ(CAN_IRQn);
	printf("waiting for the code....\n");
	RX_TX_Bouncing();
	NVIC_DisableIRQ(CAN_IRQn);
	
	ucEr = Copy_App();
	while(ucEr != IAP_STA_CMD_SUCCESS);
	printf("finished\n");
	printf("code has copied in the secoter 6\n");
	printf("Cmd>");
	
}

void Prepare_Copy( uint32_t * src, uint32_t * dst, uint32_t len )
{
    if(dst != src)
    {
        while(len)
        {
            *dst++ = *src++;

            len -= 4;
        }
    }
}

void Run_App(void)
{
	unsigned int entry;
	printf("run the app.....\n");
	
	
	SysTick->CTRL = ~(1<<0);
	NVIC_DisableIRQ(SysTick_IRQn);
	
	__disable_irq();   
	Prepare_Copy((uint32_t *)APP_START_ADDR, (uint32_t *)0x10000000, 512);
	LPC_SYSCTL -> SYSMEMREMAP = 0x01;
    __enable_irq();
    
    __set_MSP(*(uint32_t *)APP_START_ADDR);
	entry = *((volatile unsigned int *)(APP_START_ADDR + 4));
	((void(*)(void))entry)();

	printf("Cmd>\n");
	
}

void Function_Select(void)
{

	while(1)
	{
		switch(Judge_Cmd())
		{
			case INFO:
				  Display_Info();
			    break;
			case READID:
					Display_ReadID();
			    break;
			case BLANKCHK:
			  	Blank_Check();
				  break;
			case ERASE:
				  Erase_Sector();
			    break;
			case RUN:
			  	Run_App();
			    break;
			case DEMO:
				  Demo();
			    break;
			case HELP:
				  List_Cmd();
			    break;
			case ERROR:
				printf("cmd error.\n");
				printf("Cmd>");
				break;
			default:
				  break;
		}
  }
}
 
void baudrateCalculate(uint32_t baud_rate, uint32_t *can_api_timing_cfg)
{
	uint32_t pClk, div, quanta, segs, seg1, seg2, clk_per_bit, can_sjw;
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN);
	pClk = Chip_Clock_GetMainClockRate();

	clk_per_bit = pClk / baud_rate;

	for (div = 0; div <= 15; div++) {
		for (quanta = 1; quanta <= 32; quanta++) {
			for (segs = 3; segs <= 17; segs++) {
				if (clk_per_bit == (segs * quanta * (div + 1))) {
					segs -= 3;
					seg1 = segs / 2;
					seg2 = segs - seg1;
					can_sjw = seg1 > 3 ? 3 : seg1;
					can_api_timing_cfg[0] = div;
					can_api_timing_cfg[1] =
						((quanta - 1) & 0x3F) | (can_sjw & 0x03) << 6 | (seg1 & 0x0F) << 8 | (seg2 & 0x07) << 12;
					return;
				}
			}
		}
	}
}

/*	CAN receive callback */
/*	Function is executed by the Callback handler after
    a CAN message has been received */
void CAN_rx(uint8_t msg_obj_num) {
	/* Determine which CAN message has been received */
	msg_obj.msgobj = msg_obj_num;
	/* Now load up the msg_obj structure with the CAN message */
	LPC_CCAN_API->can_receive(&msg_obj);
	if (msg_obj_num == 1) 
	{
    have_data = HAVE_DATA;
	}
}

/*	CAN transmit callback */
/*	Function is executed by the Callback handler after
    a CAN message has been transmitted */
void CAN_tx(uint8_t msg_obj_num) {}

/*	CAN error callback */
/*	Function is executed by the Callback handler after
    an error has occured on the CAN bus */
void CAN_error(uint32_t error_info) {}

/**
 * @brief	CCAN Interrupt Handler
 * @return	Nothing
 * @note	The CCAN interrupt handler must be provided by the user application.
 *	It's function is to call the isr() API located in the ROM
 */
void CAN_IRQHandler(void) {
	LPC_CCAN_API->isr();
}

/*****************************************************************************
 * Public functions
 ****************************************************************************/


/**
 * @brief	Main routine for CCAN_ROM example
 * @return	Nothing
 */
int main(void)
{
	uint32_t CanApiClkInitTable[2];
	/* Publish CAN Callback Functions */
	CCAN_CALLBACKS_T callbacks = {
		CAN_rx,
		CAN_tx,
		CAN_error,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
	};
	SystemCoreClockUpdate();
	SysTick_Config(SystemCoreClock/100);
	Board_Init();
	baudrateCalculate(TEST_CCAN_BAUD_RATE, CanApiClkInitTable);

	LPC_CCAN_API->init_can(&CanApiClkInitTable[0], TRUE);
	/* Configure the CAN callback functions */
	LPC_CCAN_API->config_calb(&callbacks);
	/* Enable the CAN Interrupt */
	msg_obj.msgobj = 1;
	msg_obj.mode_id = 0x400;
	msg_obj.mask = 0x000;
	LPC_CCAN_API->config_rxmsgobj(&msg_obj);	
	NVIC_DisableIRQ(CAN_IRQn);

	List_Cmd();
	Function_Select();
	return 0;
}
