/*
 * @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 <intrinsics.h>
#include "board.h"
#include "can_uart.h"
#include "IAP.h"
#include "systick.h"
/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/

#define TEST_CCAN_BAUD_RATE 500000
#define APP_START_ADDR 0x4000

#define SEND 1
#define RUN  2
#define HELP 3


/* 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 [from_idx] [to_idx]| check if flash sectors are blank          |\n"
//   "| ERASE [from_idx] [to_idx] | erase flash sectors                       |\n"
   "| run [addr]                | Run application in internal FLASH         |\n"
   "|                           | [addr - app. address, default=0x4000      |\n"
   "| send                      | Send Program Code to Target Board         |\n"
   "| help                      | displays this help                        |\n"
   "+---------------------------+-------------------------------------------+\n";


uint8_t msgbuffer[]="\n\r***  CAN TX Only Demo is running  ***\n\r";

uint8_t str[10];
uint8_t i;

CCAN_MSG_OBJ_T msg_obj;
CCAN_MSG_OBJ_T can_buff[5];


/*****************************************************************************
 * Private functions
 ****************************************************************************/
 uint8_t DB_GetChar_1(void)
{
	uint8_t data;
	while(!(LPC_USART->LSR&0x01));
	data = LPC_USART->RBR;
	return data;		
}


uint8_t* DB_GetString_1(void)
{
	uint8_t* str1;
	i=0;
	while(str[i-1] != '\n')
	{
		str[i] = DB_GetChar_1();
		DB_PutChar(str[i]);
		ticks = 0;
		i++;
	}
	str1 = str;
	return str1;
	
}


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

uint8_t Judge_Cmd(void)
{
	uint8_t *str;
	str=DB_GetString_1();
	if(str[0]=='s'&&str[1]=='e'&&str[2]=='n'&&str[3]=='d')
	return SEND;
	else if(str[0]=='r'&&str[1]=='u'&&str[2]=='n'&&str[3]==' '&&str[4]=='0'&&str[5]=='x'&&str[6]=='4'&&str[7]=='0'&&str[8]=='0'&&str[9]=='0')
	return RUN;
	else if(str[0]=='h'&&str[1]=='e'&&str[2]=='l'&&str[3]=='p')
	return HELP;	
	else
	return ERROR;	
}

void Send_AppCode(void)
{
	uint8_t *src = (uint8_t *)0x4000;
	uint32_t count_code,i,j; 
	uint32_t count = 0;
	/* Configure message object 1 to receive all 11-bit messages */
	msg_obj.msgobj = 1;
	msg_obj.mode_id = 0x400;
	msg_obj.mask = 0x00;
	LPC_CCAN_API->config_rxmsgobj(&msg_obj);	
	
	
    can_buff[0].mode_id      = 0x001;	/* standard frame */
    can_buff[0].dlc     = 0x08;		/* Length = 8 */
    can_buff[0].data[0] = 0;
    can_buff[0].data[1] = 1;
    can_buff[0].data[2] = 2;
    can_buff[0].data[3] = 3;
    can_buff[0].data[4] = 4;
    can_buff[0].data[5] = 5;
    can_buff[0].data[6] = 6;
    can_buff[0].data[7] = 7;
    DB_PutStr("\nsending the code now......");
    for(count_code=0;count_code<512;count_code++)
    {
        for(i=0;i<8;i++)
		{
		  can_buff[0].data[i] = *src++;
			//DB_PutDec(can_buff[0].data[i]);
			//DB_PutChar(' ');
			count++;
			if(count==4096/10)
				DB_PutStr("\nwaiting for the code....have finshed 10%");
			else if(count==4096/10*2)
				DB_PutStr("\nwaiting for the code....have finshed 20%");
			else if(count==4096/10*3)
				DB_PutStr("\nwaiting for the code....have finshed 30%");
			else if(count==4096/10*4)
				DB_PutStr("\nwaiting for the code....have finshed 40%");
			else if(count==4096/10*5)
				DB_PutStr("\nwaiting for the code....have finshed 50%");
			else if(count==4096/10*6)
				DB_PutStr("\nwaiting for the code....have finshed 60%");
			else if(count==4096/10*7)
				DB_PutStr("\nwaiting for the code....have finshed 70%");
			else if(count==4096/10*8)
				DB_PutStr("\nwaiting for the code....have finshed 80%");
			else if(count==4096/10*9)
				DB_PutStr("\nwaiting for the code....have finshed 90%");
		}
		LPC_CCAN_API->can_transmit(&can_buff[0]);
		for (j=0;j<20000;j++);
		
	}
	DB_PutStr("\nsend success");
	DB_PutStr("\nCmd>");
}

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;
	
	//while ( Judge_Cmd()!= RUN);
	DB_PutStr("\nrun the app....");

	SysTick->CTRL = ~(1<<0);//shut down SYSTICK
	NVIC_DisableIRQ(SysTick_IRQn);
	
	__disable_irq();   
	Prepare_Copy((uint32_t *)0x4000, (uint32_t *)0x10000000, 512);
	LPC_SYSCTL -> SYSMEMREMAP = 0x01;
	__enable_irq();
    
  __set_MSP(*(uint32_t *)APP_START_ADDR); //setup SP pointer for main
	entry = *((volatile unsigned int *)0x4004);
	((void(*)(void))entry)();
	
//	((void(*)())0x4001)(); // this also can be work

//	DB_PutStr("\nCmd>");
}

void Function_Select(void)
{
	
	while(1)
	{
		switch(Judge_Cmd())
		{
			case SEND:
				Send_AppCode();
			    break;
			case RUN:
					Run_App();
			    break;
			case HELP:
				DB_PutStr(help);
				DB_PutStr("Cmd>");
				break;
			case ERROR:
				DB_PutStr("cmd error.\n");
				DB_PutStr("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) {
		/* Simply transmit CAN frame (echo) with with ID +0x100 via buffer 2 */
		msg_obj.msgobj = 2;
		msg_obj.mode_id += 0x100;
		LPC_CCAN_API->can_transmit(&msg_obj);
	}
}

/*	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();
	UART_Init();
	NVIC_DisableIRQ(UART0_IRQn);
	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 */
	NVIC_EnableIRQ(CAN_IRQn);

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