#include <stdlib.h>
#include <math.h>
#include "main.h"

//设备唯一编码，固定在0x00002800位置
const uint8_t DevMac[6] __attribute__((section(".ARM.__at_0x00002800"))) = {DEVICE_TYPE & 0xFF, (DEVICE_TYPE >> 8) & 0xFF, COMM_WAY, (ADD_NUMBER >> 16) & 0xFF, (ADD_NUMBER >> 8) & 0xFF, ADD_NUMBER & 0xFF};
//const uint8_t DevMac[6] __attribute__((at(DEV_MAC_ADDRESS)))= {0x19, 0x00, 0x02, 0x00, 0x00, 0x01};
uint32_t pdwCrc32Tbl[256];

void InitCrc32Table(uint32_t* Crc32Tbl)
{
	for (int wCnt = 0; wCnt!= 256; wCnt++){
		uint32_t dwCrc = wCnt;
		for (int ucCnt = 0; ucCnt != 8; ucCnt++){
			if (dwCrc & 1){
				dwCrc = (dwCrc >> 1) ^ 0xEDB88320;
			}
			else{
				dwCrc >>= 1;
			}
		}
		Crc32Tbl[wCnt] = dwCrc;
	}
}

uint32_t GetCrc32(int dwLen)
{
	uint32_t Data;
	uint32_t dwCrc32Data = 0xFFFFFFFF;
	for (int dwCnt = 0; dwCnt!= dwLen; ++dwCnt){
		Data = *((volatile uint8_t*)(APP_ADDRESS + dwCnt));
		uint32_t dwTbl = (dwCrc32Data ^ Data) & 0xFF;
		dwCrc32Data = ((dwCrc32Data >> 8) & 0xFFFFFF) ^ pdwCrc32Tbl[dwTbl];
	}
	return ~dwCrc32Data;
}

uint16_t CRC_Modbus(uint16_t wBase, __IO uint8_t *para, uint16_t length)
{
	uint16_t crc = 0xffff;         

	uint16_t index,i;

	for(index = 0 ; index < length;index++) {
		crc ^= para[index];
		for(i = 0; i < 8; i++) {
			if(crc & 1) {
				crc >>= 1;
				crc ^= wBase;
			}
			else
				crc >>= 1;
		}
	}
	return crc;
}

uint32_t JumpAddress;
func_ptr_t JumpToApplication;
BootLoader_t BL;

static void BootLoader1mSRoutine(void)
{
	if(BL.BootLoader1mSDlyCnt)
		BL.BootLoader1mSDlyCnt--;
	
	if(BL.UartRevTimeOutCnt > 0)
		BL.UartRevTimeOutCnt--;
	
	BL.FeedDogDlyCnt++;
}

void FeedDogHandler(void)
{
	if(BL.FeedDogDlyCnt >= 200) {
		FeedDog(); 
		BL.FeedDogDlyCnt = 0;
	}
}

void AppWriteFlash(uint32_t AddrOffset, uint8_t *wData, int wLen)
{
		FlashWrite(APP_ADDRESS + AddrOffset, (uint32_t *)wData, wLen / 4);
}

//static bool JumpToApp(uint32_t AppAddr)
//{
//	uint32_t u32StackTop = *((__IO uint32_t *)AppAddr);  

//	if ((u32StackTop > SRAM_BASE) && (u32StackTop <= (SRAM_BASE + RAM_SIZE))) {
//		JumpAddress = *(__IO uint32_t *)(AppAddr + 4);
//		JumpToApplication = (func_ptr_t)JumpAddress;
//		__set_MSP(*(__IO uint32_t *)AppAddr);
//		JumpToApplication();
//	}
//	return Error;
//}


static bool JumpToApp(uint32_t AppAddr)
{
	uint32_t u32StackTop = *((__IO uint32_t *)AppAddr);  

	if ((u32StackTop > SRAM_BASE) && (u32StackTop <= (SRAM_BASE + SRAM_SIZE))) {
		JumpAddress = *(__IO uint32_t *)(AppAddr + 4);
		JumpToApplication = (func_ptr_t)JumpAddress;
		__set_MSP(*(__IO uint32_t *)AppAddr);
		JumpToApplication();
	}
	return Error;
}

void SendGetCmd(uint8_t Cmd, uint16_t PayLoad)
{
	uint8_t sData[20], sLen;
	uint16_t crc16;
	
	FrameH Frame = (FrameH)sData;
	
	Frame->Header = 0x7a;
	Frame->SlvAddr = 0x01;
	Frame->Cmd = Cmd;
	
	if(Cmd == 0x01) {
		Frame->PayloadLen = 1;
		sData[sizeof(FrameHeader_t)] = PayLoad;
	}
	else if(Cmd == 0x02) {
		Frame->PayloadLen = 4;
		GDReq GDData = (GDReq)&sData[sizeof(FrameHeader_t)];
		GDData->PackageIndex = PayLoad;
		GDData->PackageNum = BL.AppPackageCnt;
	}
	sLen = sizeof(FrameHeader_t) + Frame->PayloadLen;
	crc16 = CRC_Modbus(CRC16_BASE, sData, sLen);
	sData[sLen++] = crc16;
	sData[sLen++] = (crc16 >> 8) & 0x00ff;
	
	DebugUartSend(sData, sLen);
}

bool AnalyzeData(uint8_t *rData, uint16_t rLen)
{
	uint16_t crc16, check;
	
	check = CRC_Modbus(CRC16_BASE, rData, rLen - 2);
	crc16 = (rData[rLen - 1] << 8) | rData[rLen - 2];
	
	if(check != crc16) {
		return false;
	}
	
	FrameH Frame = (FrameH)rData;
	if(Frame->Cmd == 0x81) {
		UDReq UpData = (UDReq)&rData[sizeof(FrameHeader_t)];
		BL.Para.AppFlag = 0;
		BL.Para.UpdateFlag = APP_UPDATE_FLAG;
		BL.Para.Crc32Check = UpData->AppCrc32;
		BL.Para.PackageCnt = UpData->PackageNum;
		BL.Para.AppSize = UpData->AppSize;
		WriteBootPara(&BL.Para);
		BL.BootLoader1mSDlyCnt = 20;
		BL.Status = BL_RESET;
		SendGetCmd(0x01, 1);
	}
	else if(Frame->Cmd == 0x82) {
		if(BL.UpDateFlag == false)
			return false;
		DownRes DownData = (DownRes)&rData[sizeof(FrameHeader_t)];
		if(BL.AppPackageIdx != DownData->PackageIndex) {
			return false;
		}
		AppWriteFlash(BL.AppPackageIdx * 200, &BL.RxBuff[sizeof(FrameHeader_t) + sizeof(DownResponse_t)], DownData->DataLen);
		BL.AppPackageIdx++;
		BL.RevErrCnt = 0;
		if(BL.AppPackageIdx < BL.AppPackageCnt) {
			BL.Status = BL_GET_DATA;
			BL.BootLoader1mSDlyCnt = 5;
			//BuzzCtrl(10, 0, 1);
		}
		else {
			uint32_t crc32 = GetCrc32(BL.Para.AppSize);
			if(crc32 == BL.Para.Crc32Check) {
				BL.Status = BL_START_APP;
				BL.Para.AppFlag = 0;					//升级成功首次启动时，把APP启动标志清除，由APP置位，下次启动便按标志启动
				BL.Para.UpdateFlag = 0;
				BL.Para.DevType = DEV_TYPE;
				WriteBootPara(&BL.Para);
			}
		}
	}
	else 
		return false;
	return true;
}

void BootLoaderLoopHandler(void)
{	
	if(BL.RxFlag) {
		BL.RxFlag = false;
		AnalyzeData(BL.RxBuff, BL.RxLen);
		TURN_OFF_STATE_LED();
	}
	
	switch(BL.Status){
		case BL_IDLE:
			break;
		
		case BL_RESET:
			if(BL.BootLoader1mSDlyCnt > 0) {
				break;
			}
			NVIC_SystemReset();
			break;
		
		case BL_START_APP:
			enIrqResign(DBGUART_IRQn);
			enIrqResign(DBGUART_EI_IRQn);
			JumpToApp(APP_ADDRESS);
			break;  
		
		case BL_ERASE_FLASH:
			FeedDog();
			EraseFlash();
			FeedDog();
			BL.Status = BL_GET_DATA;
			BL.BootLoader1mSDlyCnt = 200;
			BL.AppPackageCnt = BL.Para.PackageCnt;
			BL.RevErrCnt = 0;
			BL.UpDateFlag = true;
			break;
	
		case BL_GET_DATA:
			if(BL.BootLoader1mSDlyCnt > 0)
				break;
			SendGetCmd(0x02, BL.AppPackageIdx);
			BL.Status = BL_WAIT_REV;
			BL.BootLoader1mSDlyCnt = 500;
			break;
			
		case BL_WAIT_REV:
			if(BL.BootLoader1mSDlyCnt == 0) {
				BL.Status = BL_GET_DATA_TIMEOUT;
			}
			break;
			
		case BL_GET_DATA_TIMEOUT:
			BL.RevErrCnt++;
			if(BL.RevErrCnt < 3) {
				BL.Status = BL_GET_DATA;
			}
			else {
				BL.Status = BL_IDLE;
				BL.Para.AppFlag = 0;
				BL.RevErrCnt = 0;
				BL.Para.UpdateFlag = 0;
				WriteBootPara(&BL.Para);
				BL.UpDateFlag = false;
			}
			break;
	}
}

int32_t main(void)
{
	BSP_Init();
	InitCrc32Table(pdwCrc32Tbl);
	
	ReadBootPara(&BL.Para);
	if(BL.Para.DevType != DEV_TYPE) {		//设备类型错误，清除升级参数
		BL.Status = BL_IDLE;
		BL.Para.AppFlag = 0;
		BL.Para.UpdateFlag = 0;
		BL.Para.DevAddr = 0x01;
		BL.Para.DevType = DEV_TYPE;
		WriteBootPara(&BL.Para);
	}
	else if(BL.Para.AppFlag == APP_START_FLAG) {
		BL.Status = BL_START_APP;
	}
	else if(BL.Para.UpdateFlag == APP_UPDATE_FLAG) {
		BL.Status = BL_ERASE_FLASH;
	}
	while (1) {
		FeedDogHandler();
		BootLoaderLoopHandler();
	}
}


/*******************************************************************************
 * 中断服务函数
 ******************************************************************************/
void SysTick_IrqHandler(void)
{
	BootLoader1mSRoutine();
}

static uint16_t rLen;
static uint8_t rBuff[300];
static bool Header;
static uint16_t PayLen;

void DbgRxIrqCallback(uint8_t RxData)
{
	if(BL.UartRevTimeOutCnt == 0) {
		Header = false;
		rLen = 0;
		PayLen = 0;
	}
	BL.UartRevTimeOutCnt = 3;
	
	if(Header == false && RxData == 0x7a) {
		Header = true;
		rLen = 0;
		PayLen = 0;
		rBuff[rLen++] = RxData;
	}
	else {
		rBuff[rLen++] = RxData;
		if(rLen == 4) {
			PayLen = rBuff[3];
			if(PayLen > 256) {
				Header = false;
				return;
			}
		}
		else if(rLen == sizeof(FrameHeader_t) + PayLen + 2) {
			BL.RxLen = rLen;
			memcpy(BL.RxBuff, rBuff, BL.RxLen);
			BL.RxFlag = true;
			Header = false;
			TURN_ON_STATE_LED_GREEN();
		}
	}
}


