#include "main.h"
#include "string.h"
#include "stdio.h"
#include "usart.h"
#include "iap.h"
#include "stmflash.h"
#include "md5c.h"

extern void __set_FAULTMASK(uint32_t faultMask);

iapfun jump2app;
uint16_t iapbuf[1024];

__asm void MSR_MSP(uint32_t addr) 
{
    MSR MSP, r0 			//set Main Stack value
    BX r14
}

void Flash_ReadBytes(uint16_t* sorBuf,uint32_t FlashAddr,uint16_t len)
{
	uint16_t* p = sorBuf;
	uint8_t i = 0,j = 0;
	uint32_t addr = FlashAddr;
	while(len--)
	{
		i = *(uint32_t*)addr++;
		j = *(uint32_t*)addr++;
		*p++ = j<<8|i;
	}
}

uint16_t Flashbuf[2048]__attribute__ ((at(0X20001000)));

void Flash_WriteBytes(uint16_t* sorBuf,uint32_t FlashAddr,uint16_t len)
{

	uint32_t Offset_ADDR = 0,Page_StartAddr = 0,i = 0;
	Offset_ADDR = FlashAddr%0x800;
	Page_StartAddr = FlashAddr - Offset_ADDR;
	//设置PageError
	uint32_t PageError = 0;
	FLASH_EraseInitTypeDef f;

	f.TypeErase = FLASH_TYPEERASE_PAGES;
	__nop();
	f.PageAddress =Page_StartAddr;
	f.NbPages = 1;

	Flash_ReadBytes(Flashbuf,Page_StartAddr,0x400);
	
	for(i = 0;i<len;i++)
		Flashbuf[Offset_ADDR/2+i] = sorBuf[i];
	
	//1、解锁FLASH
  HAL_FLASH_Unlock();
	__nop();

  //2、擦除FLASH
  //初始化FLASH_EraseInitTypeDef

  //调用擦除函数
  HAL_FLASHEx_Erase(&f, &PageError);
	
	__nop();
  //3、对FLASH烧写
  for(uint16_t i = 0;i< 0x400 ;i++)
  {
      HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD , Page_StartAddr + (i * 2), Flashbuf[i]);
  }

    //4、锁住FLASH
    HAL_FLASH_Lock();
	
}


int App2_MD5_Check(uint32_t addr,unsigned int all_len)
{
	unsigned char digest[16];
	
	unsigned int i,update_len;
	MD5_CTX md5c;
	all_len -= 16;
	MD5Init(&md5c);
	for(i=0;i<all_len;)
	{
		if(all_len>(i+512))
			update_len = 512;
		else
			update_len = all_len-i;
		memcpy(iapbuf,(const void *)(addr+i),update_len);
		MD5Update (&md5c, (unsigned char *)iapbuf, update_len);
		i += update_len;
		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
	}
	MD5Final(digest,&md5c);
	for(i=0;i<16;++i)
	{
		if(digest[i]!=*(unsigned char *)(addr+all_len+i))
			break;
	}
	if(i>=16)
		return 1;
	else
		return 0;
}
// appxaddr:应用程序的起始地址
// appbuf:应用程序CODE.
// appsize:应用程序大小(字节).
void iap_write_appbin(uint32_t appxaddr, uint8_t *appbuf, uint32_t appsize)
{
	uint32_t t;
	uint16_t i = 0;
	uint16_t temp;
	uint32_t fwaddr = appxaddr; //当前写入的地址
	uint8_t *dfu = appbuf;
	for (t = 0; t < appsize; t += 2)
	{
		temp = (uint16_t)dfu[1] << 8;
		temp += (uint16_t)dfu[0];
		dfu += 2; //偏移2个字节
		iapbuf[i++] = temp;
		if (i == 1024)
		{
			i = 0;
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
			STMFLASH_Write(fwaddr, iapbuf, 1024);
			fwaddr += 2048; //偏移2048  16=2*8.所以要乘以2.
		}
		
	}
	if (i)
		STMFLASH_Write(fwaddr, iapbuf, i); //将最后的一些内容字节写进去.
}

//跳转到应用程序段
// appxaddr:用户代码起始地址.
void iap_load_app(uint32_t appxaddr)
{
	if (((*(uint32_t *)appxaddr) & 0x2FFE0000) == 0x20000000) //检查栈顶地址是否合法.
	{
		jump2app = (iapfun) * (uint32_t *)(appxaddr + 4); //用户代码区第二个字为程序开始地址(复位地址)
		MSR_MSP(*(uint32_t *)appxaddr);					  //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		jump2app();										  //跳转到APP.
	}
}
	unsigned int update_flag = 0xAAAAAAAA; ///< 对应bootloader的启动步骤
	unsigned int ModeStart;
	unsigned int i,all_len;
/**
 * @bieaf 进行BootLoader的启动
 *
 * @param none
 * @return none
 */
void Start_BootLoader(void)
{
	uint16_t ModeStart1[2];
	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
	Flash_ReadBytes(ModeStart1, StartMode_Addr, 2);
	ModeStart = ModeStart1[0];
	ModeStart <<= 16;
	ModeStart |= ModeStart1[1];
	switch (ModeStart) ///< 读取是否启动应用程序 */
	{
		case Startup_Normal: ///< 正常启动 */   //在APP2中可以设定此标志位   使得下次重启之后进入APP1
		{
			;
			break;
		}
		case Startup_Update: /*启动最新的程序 */
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
			for (i = 0, all_len = 0; i < 4; ++i)
			{
					all_len = all_len << 8;
					all_len |= *(unsigned char *)(StartMode_Addr + 68 + i);
			}
			if (App2_MD5_Check(Application_Buffer_Addr,all_len))
			{
				iap_write_appbin(ADD_UPDATE_PROG,(uint8_t *)Application_Buffer_Addr,all_len);
				HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
				Flash_WriteBytes((uint16_t*)(StartMode_Addr + 68), StartMode_Addr+132, 2);
			}
			Set_App2_Flag();
		case Startup_APP2: /*启动最新的程序 */
			for (i = 0, all_len = 0; i < 4; ++i)
				{
					all_len = all_len << 8;
					all_len |= *(unsigned char *)(StartMode_Addr + 132 + i);
				}
				if ((all_len<0x20000) && App2_MD5_Check(ADD_UPDATE_PROG,all_len))
				{
					__set_FAULTMASK(0);			   //先关闭全局中断
					iap_load_app(ADD_UPDATE_PROG); //执行FLASH APP2代码
				}
			break;
		default: ///< 启动失败
		{
			return;
		}
	}
}

uint8_t YmodemID	  = 0;
uint16_t packIndex 	  = 0;
uint16_t packTotalNum = 0;
uint16_t packIndexbak = 0; //当前包号，总包数
uint16_t crcIAP;
uint16_t crcIAP1;
uint16_t crcTerminal;
uint16_t FileBuffArray[512]  = {0};  // MD5校验
uint16_t FileBuffArray1[512] = {0}; // MD5校验
uint32_t FileLength_IAP = 0;  //文件长度
uint32_t AddrToWrite = Application_Buffer_Addr;
uint32_t DataReadFlash;
uint32_t DataReadFlash1;
uint32_t update_flag;

void Set_Update_Down(void)
{
	uint16_t update_flag1[2];
	update_flag = Startup_Update; ///< 对应bootloader的启动步骤
	update_flag1[0] = (uint16_t)update_flag;
	update_flag1[1] = (uint16_t)(update_flag >> 16);
	Flash_WriteBytes(update_flag1, StartMode_Addr, 2);
	__set_FAULTMASK(1);
	NVIC_SystemReset();
}

void Res_Update_Down(void)
{
	uint16_t update_flag1[2];
	update_flag = Startup_Normal; ///< 对应bootloader的启动步骤
	update_flag1[0] = (uint16_t)update_flag;
	update_flag1[1] = (uint16_t)(update_flag >> 16);
	Flash_WriteBytes(update_flag1, StartMode_Addr, 2);
	__set_FAULTMASK(1);
	NVIC_SystemReset();
}


void Set_App2_Flag(void)
{
	uint16_t update_flag1[2];
	update_flag = Startup_APP2; ///< 对应bootloader的启动步骤
	update_flag1[1] = (uint16_t)update_flag;
	update_flag1[0] = (uint16_t)(update_flag >> 16);
	Flash_WriteBytes(update_flag1, StartMode_Addr, 2);
}

void Process_CMD_IAP_Update(void)
{

	int lenRx1, lenRx2;
	int i;
	
	for (i = 0; i < 512; i++)
	{
		FileBuffArray[i] = 0;
		FileBuffArray1[i] = 0;
	}
	packIndex = (USART2_RX_BUF002[5] << 8) + USART2_RX_BUF002[6];
	packTotalNum = (USART2_RX_BUF002[7] << 8) + USART2_RX_BUF002[8];
	lenRx1 = data_lengthU2;
	YmodemID = USART2_RX_BUF002[4]; //只能是01,02
	data_lengthU2 = 0;
	uint8_t ERR_Arr[8] = "error\r\n";
	uint8_t ACK_Arr[16] = "acknowlege";

	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
	switch (YmodemID)
	{
	case 0x01: //起始帧与结束帧解析  根据包序号判别该帧为起始帧还是结束帧
		if (packIndex == 1)
		{ //起始帧处理
			FileLength_IAP = (USART2_RX_BUF002[73] << 24) + (USART2_RX_BUF002[74] << 16) + (USART2_RX_BUF002[75] << 8) + (USART2_RX_BUF002[76]);
			crcIAP = LIB_CRC_MODBUS(&USART2_RX_BUF002[4], 133); //
			crcTerminal = (USART2_RX_BUF002[lenRx1 - 5] << 8) + USART2_RX_BUF002[lenRx1 - 6];
			if (crcIAP == crcTerminal)
			{
				for (i = 0; i < 88; ++i)
				{
					if (*(unsigned char *)(StartMode_Addr + i + 4) != USART2_RX_BUF002[9 + i])
						break;
				}
				if (i < 88)
				{
					for (i = 0; i < 44; i++)
					{
						FileBuffArray[i] = (uint16_t)(USART2_RX_BUF002[i * 2 + 10] << 8 | USART2_RX_BUF002[i * 2 + 9]);
					}
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
					Flash_WriteBytes(FileBuffArray, StartMode_Addr + 4, 44);
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
					packIndexbak = 0;
					AddrToWrite = Application_Buffer_Addr;
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
				}
				else
				{
					if(packIndexbak>1)
						packIndexbak-=1;
				}

				{
					static uint16_t txLen;
					for (i = 0; i < 1024; i++)
					{
						USART2_RX_BUF002[i] = 0;
					}
					txLen = sprintf((char *)FileBuffArray, "file=%d\r\n", packIndexbak);
					delay_sys_us(80);
					HAL_UART_Transmit_IT(&huart1,(unsigned char *)FileBuffArray,txLen);		
					while (huart1.gState == HAL_UART_STATE_BUSY_TX)
					{
						HAL_Delay(1);
					}
				}
			}
			else
			{
				for (i = 0; i < 1024; i++)
				{
					USART2_RX_BUF002[i] = 0;
				}
				HAL_UART_Transmit(&huart1, ERR_Arr, strlen((char *)ERR_Arr), 100);
				
			}
			
		}
		else
		{
			
		}
		break;
	case 0x02:														//有效载荷帧数据处理
		crcIAP = LIB_CRC_MODBUS(&USART2_RX_BUF002[4], lenRx1 - 10); //
		crcTerminal = (USART2_RX_BUF002[lenRx1 - 5] << 8) + USART2_RX_BUF002[lenRx1 - 6];
		if ((crcIAP == crcTerminal) && (((packIndexbak + 1) == packIndex) || ((packIndexbak) == packIndex)))
		{
			if ((packIndexbak + 1) == packIndex)
			{
				lenRx2 = (lenRx1 - 15) % 2;
				if (!lenRx2)
				{
					for (i = 0; i < ((lenRx1 - 15) / 2); i++)
					{
						FileBuffArray[i] = (uint16_t)(USART2_RX_BUF002[i * 2 + 10] << 8 | USART2_RX_BUF002[i * 2 + 9]);
						FileBuffArray1[i] = (uint16_t)(USART2_RX_BUF002[i * 2 + 10] << 8 | USART2_RX_BUF002[i * 2 + 9]);
					}
					Flash_WriteBytes(FileBuffArray, AddrToWrite, ((lenRx1 - 15) / 2));
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
					Flash_ReadBytes(FileBuffArray1, AddrToWrite, ((lenRx1 - 15) / 2));
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
				}
				else
				{
					for (i = 0; i < ((lenRx1 - 16) / 2); i++)
					{
						FileBuffArray[i] = (uint16_t)(USART2_RX_BUF002[i * 2 + 10] << 8 | USART2_RX_BUF002[i * 2 + 9]);
						FileBuffArray1[i] = (uint16_t)(USART2_RX_BUF002[i * 2 + 10] << 8 | USART2_RX_BUF002[i * 2 + 9]);
					}
					FileBuffArray[(lenRx1 - 16) / 2] = USART2_RX_BUF002[(lenRx1 - 16 + 10)] << 8;
					FileBuffArray1[(lenRx1 - 16) / 2] = USART2_RX_BUF002[(lenRx1 - 16 + 10)] << 8;
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
					Flash_WriteBytes(FileBuffArray, AddrToWrite, ((lenRx1 - 15 + 1) / 2));
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
					Flash_ReadBytes(FileBuffArray1, AddrToWrite, ((lenRx1 - 15 + 1) / 2));
					HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
				}
				AddrToWrite += lenRx1 - 15;
				DataReadFlash = *((uint32_t *)(AddrToWrite));
				DataReadFlash1 = (*(__IO uint32_t *)AddrToWrite);
				HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
			}
			if (DataReadFlash == DataReadFlash1)
			{
				
				HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
				packIndexbak = packIndex;
			}

			{
				int txLen;
				for (i = 0; i < 1024; i++)
				{
					USART2_RX_BUF002[i] = 0;
				}
				txLen = sprintf((char *)USART2_RX_BUF002, "%s=%d\r\n", ACK_Arr, packIndex);
				HAL_UART_Transmit_IT(&huart1,USART2_RX_BUF002,txLen);		
				while (huart1.gState == HAL_UART_STATE_BUSY_TX)
				{
					delay_sys_us(1);
				}
			}
		}
		else
		{
			delay_sys_us(80);
			HAL_UART_Transmit(&huart1, ERR_Arr, strlen((char *)ERR_Arr), 100);
		}
		break;
	case 3:
		{														 //结束帧处理
			int i,all_len;
			crcIAP1 = LIB_CRC_MODBUS(&USART2_RX_BUF002[4], 133); //
			crcTerminal = (USART2_RX_BUF002[lenRx1 - 5] << 8) + USART2_RX_BUF002[lenRx1 - 6];
			if (crcIAP1 == crcTerminal)
			{
				int txLen;
				txLen = sprintf((char *)USART2_RX_BUF002, "%s\r\n", ACK_Arr);
				HAL_UART_Transmit_IT(&huart1,USART2_RX_BUF002,txLen);		
				while (huart1.gState == HAL_UART_STATE_BUSY_TX)
				{
					delay_sys_us(1);
				}
				for (i = 0, all_len = 0; i < 4; ++i)
				{
					all_len = all_len << 8;
					all_len |= *(unsigned char *)(StartMode_Addr + 68 + i);
				}
			if (1)//App2_MD5_Check(Application_Buffer_Addr,all_len))
			{
				txLen = sprintf((char *)USART2_RX_BUF002, "md5 check=ok\r\n");
				delay_sys_us(80);
				HAL_UART_Transmit_IT(&huart1,USART2_RX_BUF002,txLen);		
				while (huart1.gState == HAL_UART_STATE_BUSY_TX)
				{
					delay_sys_us(1);
				}
				Set_Update_Down(); //设定标志位  下次启动时进行程序拷贝
			}
			else
			{
				txLen = sprintf((char *)USART2_RX_BUF002,"md5 check=error\r\n");
			}
				HAL_UART_Transmit_IT(&huart1,USART2_RX_BUF002,txLen);		
				while (huart1.gState == HAL_UART_STATE_BUSY_TX)
				{
					delay_sys_us(1);
				}
			}
			else
			{
				delay_sys_us(80);
				HAL_UART_Transmit(&huart1, ERR_Arr, strlen((char *)ERR_Arr), 100);
			}
		}
		break;
	default:
		break;
	}
}

