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

typedef  void (*iapfun)(void);	
iapfun jump2app;

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

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.
	}
}

typedef void (*pFunction)(void);
void jump_to_app(uint32_t app_addr)
{
    // Step 1: 关闭中断
    __disable_irq();
    
    // Step 2: 将设备的运行代码地址设置为主堆栈指针(MSP)
    __set_MSP(*(volatile uint32_t*)app_addr);
    
    // Step 3: 跳转到设备的运行代码
    pFunction app_entry = (pFunction)(*(volatile uint32_t*)(app_addr + 4));
    app_entry();
}

uint8_t YmodemID;
uint8_t startFrame[40] = {0};
uint16_t version[4];
uint16_t length[3];

uint8_t binName[32] = {0};
uint8_t binLength[10] = {0};
uint8_t binMd5[16] = {0};

uint16_t iapbinMd5[8] = {0};
uint16_t FileBuffArray[512];  
uint16_t FileBuffArray1[512]; 
uint16_t start_addr = 0;
uint16_t packIndex = 0;
uint16_t packTotalNum = 0;
uint16_t packIndexbak = 0; 
uint16_t crcIAP = 0;
uint16_t crcTerminal = 0;
uint32_t AddrToWrite = Application_Buffer_Addr;
int FileLength_IAP; 
uint32_t update_flag = 0;
//uint16_t iapbigbuf[20000];

int tag = 0;
int lenindex=0;
//int indexbuf=0;


void Process_CMD_IAP_Update(void)
{

	int lenRx1;
	int i;
	USART_IAP_FLAG = 0;
	packIndex = USART_IAP_RX[8] << 8 | USART_IAP_RX[9];
	
	lenRx1 = USART_PUB_LENGTH;

	uint8_t ERR_Arr[8] = "error\r\n";
//	uint8_t ACK_Arr[16] = "acknowlege=ok";
	
	YmodemID = USART_IAP_RX[7];
	memset(FileBuffArray, 0, sizeof(FileBuffArray));
	memset(FileBuffArray1, 0, sizeof(FileBuffArray1));
	
	
	
	switch (YmodemID)
	{
		case 0x01: //起始帧与结束帧解析  根据包序号判别该帧为起始帧还是结束帧
			memcpy(startFrame, &USART_IAP_RX[10], 40);
			crcIAP = crc16_xmodem(&USART_IAP_RX[10], 128); 
			crcTerminal = (USART_IAP_RX[lenRx1 - 4] << 8) | USART_IAP_RX[lenRx1 - 3];
		
			if (crcIAP == crcTerminal)
			{
/*升级起始帧标记0*/				
				for (i = 0; i < 88; ++i)
				{
					if (*(unsigned char *)(StartMode_Addr + i + 4) != USART_IAP_RX[10 + i])
						break;
				}
				if (i < 50)
				{
					for (i = 0; i < 25; i++)
					{
						FileBuffArray[i] = (uint16_t)(USART_IAP_RX[i * 2 + 11] << 8 | USART_IAP_RX[i * 2 + 10]);
					}
					Flash_WriteBytes(FileBuffArray, StartMode_Addr + 4, 25); //从StartMode_Addr+4 ，开始写入数据
					delay_sys_us(50);
/*升级起始帧标记1*/	
					
/*IAP总长度标记0*/	

					
#if	indexfl == 4	
   	lenindex =0;//长度为4位数
#else	
	
   	lenindex =1;//长度为5位数
#endif	

					readFlashToArr(binLength, StartMode_Addr+27);
					if(lenindex != 0)
					{
						FileLength_IAP = ((binLength[0]&0xF)*10000) + ((binLength[1]&0xF) *1000) +((binLength[2]&0xF) *100) +\
																((binLength[3]&0xF) *10)  + ((binLength[4]&0xF) );
					}
					else
					{
						FileLength_IAP = ((binLength[0]&0xF)*1000) + ((binLength[1]&0xF) *100) +((binLength[2]&0xF) *10) +\
																((binLength[3]&0xF) *1) ;
					}
					

					
					all_len = FileLength_IAP;
					
					
					erase_flash(LENGTH_ADDR);
					HAL_FLASH_Unlock();  // 解锁Flash
					HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, LENGTH_ADDR, all_len);
					HAL_FLASH_Lock();  // 上锁Flash
/*IAP总长度标记1*/		
					
/*IAP_MD5标记0*/
					if(lenindex!=0)
					{
						Flash_ReadBytes(iapbinMd5, StartMode_Addr + 33, 16);

						Flash_WriteBytes(iapbinMd5, MD5_ADDR, 8);
						for (int i = 0; i < 8; i++) {
							iapbinMd5[i] = ((iapbinMd5[i] >> 8) & 0xFF) | ((iapbinMd5[i] << 8) & 0xFF00);
						}
					}
					else
					{
						Flash_ReadBytes(iapbinMd5, StartMode_Addr + 32, 16);

						Flash_WriteBytes(iapbinMd5, MD5_ADDR, 8);
						for (int i = 0; i < 8; i++) {
							iapbinMd5[i] = ((iapbinMd5[i] >> 8) & 0xFF) | ((iapbinMd5[i] << 8) & 0xFF00);
						}
					}

						
				
/*IAP_MD5标记1*/	
					
					AddrToWrite = Application_Buffer_Addr;
				}

				memset(USART_IAP_RX, 0, sizeof(USART_IAP_RX));	
				delay_sys_us(80);
				receive_modbus_9_1(initial_address, USART_MODBUS_RX[1], ((uint16_t)USART_MODBUS_RX[2] << 8) | USART_MODBUS_RX[3], \
									((uint16_t)USART_MODBUS_RX[4] << 8) | USART_MODBUS_RX[5], USART_MODBUS_RX[6]);

				
				__NOP();
			}

			else
			{
				memset(USART_IAP_RX, 0, sizeof(USART_IAP_RX));
				HAL_UART_Transmit(&huart1, ERR_Arr, strlen((char *)ERR_Arr), 100);
			}
			
			memset(FileBuffArray, 0, sizeof(FileBuffArray));
			memset(FileBuffArray1, 0, sizeof(FileBuffArray1));
			break;
			
/***
 *	存储并迁移下载区
 */			
			
		case 0x02:														//有效载荷帧数据处理
			crcIAP = crc16_xmodem(&USART_IAP_RX[10], 128); 
			crcTerminal = (USART_IAP_RX[lenRx1 - 4] << 8) + USART_IAP_RX[lenRx1 - 3];
		

		
			if (crcIAP == crcTerminal)
			{
				for (i = 0; i < 64; i++)
				{
					FileBuffArray[i] = (uint16_t)(USART_IAP_RX[i * 2 + 11] << 8 | USART_IAP_RX[i * 2 + 10]);
				}

				Flash_WriteBytes(FileBuffArray, AddrToWrite, 64);
				AddrToWrite += 128;
				
				
				

//				Flash_ReadBytes(&iapbigbuf[indexbuf], AddrToWrite, 128);
//				indexbuf+=128;

				
				
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
				HAL_Delay(1);  
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
				
				if((AddrToWrite & 0xffff) != (USART_IAP_RX[2] << 8 | USART_IAP_RX[3]))
				{
					HAL_UART_Transmit(&huart1, ERR_Arr, strlen((char *)ERR_Arr), 100);
					break;
				}
				
				
				memset(USART_IAP_RX, 0, sizeof(USART_IAP_RX));	
				delay_sys_us(80);
				
				receive_modbus_9_1(initial_address, USART_MODBUS_RX[1], ((uint16_t)USART_MODBUS_RX[2] << 8) | USART_MODBUS_RX[3], \
									((uint16_t)USART_MODBUS_RX[4] << 8) | USART_MODBUS_RX[5], USART_MODBUS_RX[6]);

			}				
			break;
			
			
		case 0x04:
			{				
				
				crcIAP = crc16_xmodem(&USART_IAP_RX[10], 128); 
				crcTerminal = (USART_IAP_RX[lenRx1 - 4] << 8) + USART_IAP_RX[lenRx1 - 3];
				if (crcIAP == crcTerminal)
				{
//					int txLen;
//					txLen = sprintf((char *)USART_IAP_RX, "%s\r\n", ACK_Arr);
//					HAL_UART_Transmit_IT(&huart1,USART_IAP_RX,txLen);		
//					while (huart1.gState == HAL_UART_STATE_BUSY_TX)
//					{
//						HAL_Delay(1);
//					}
					
/*系统版本标记0*/					
					Flash_ReadBytes(version, StartMode_Addr + 14, 8);
					for (int i = 0; i < 4; i++) {
						version[i] = ((version[i] >> 8) & 0xFF) | ((version[i] << 8) & 0xFF00);
					}
					convertHexToAscii(version, &System_version);
					erase_flash(VERSION_ADDR);
					HAL_FLASH_Unlock();  // 解锁Flash
					HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, VERSION_ADDR, System_version);
					HAL_FLASH_Lock();  // 上锁Flash
/*系统版本标记1*/	
					
					
					tag = App2_MD5_Check(Application_Buffer_Addr,all_len);
					
					if(tag)
					{
						
						Set_Update_Down(); //设定标志位  下次启动时进行程序拷贝
						
					}else{
						int	txLen = sprintf((char *)USART_IAP_RX,"check=error\r\n");
						delay_sys_us(80);
						HAL_UART_Transmit_IT(&huart1,USART_IAP_RX,txLen);					
						while (huart1.gState == HAL_UART_STATE_BUSY_TX)
						{
							HAL_Delay(1);
						}
					}

				}
				else
				{
					delay_sys_us(80);
					HAL_UART_Transmit(&huart1, ERR_Arr, strlen((char *)ERR_Arr), 100);
					delay_sys_us(80);
				}
			}
			break;
		default:
			break;
	}
}


uint8_t buffer[BUFFER_SIZE_length];
uint8_t buffer_length[100];
unsigned int all_len;
int i;
unsigned int ModeStart;

void Start_BootLoader(void)
{
	
	uint16_t ModeStart1[2];
	Flash_ReadBytes(ModeStart1, StartMode_Addr, 2);
	
	ModeStart = (ModeStart1[0] << 16) | ModeStart1[1];
	all_len = FileLength_IAP;
	int tag;
	int txLen;
	memset(USART_IAP_RX, 0, sizeof(USART_IAP_RX));	
	
	
    update_iaplength(LENGTH_ADDR);
//	uint16_t pagenum =  (all_len+2048)/2048;
	
	switch (ModeStart)
	{
		case Startup_Normal: // 正常启动  在APP2中可以设定此标志位   使得下次重启之后进入APP1
		{
//			txLen = sprintf((char *)USART_IAP_RX, "normalStart");
//			HAL_UART_Transmit_IT(&huart1,USART_IAP_RX,txLen);		
			break;
		}
		
		
		case Startup_Update: /*启动最新的程序 */
//			{
//				FLASH_EraseInitTypeDef erase_init;
//				erase_init.TypeErase = FLASH_TYPEERASE_PAGES;  // 擦除类型为页擦除
//				erase_init.PageAddress = ADD_UPDATE_PROG;  
//				erase_init.NbPages = pagenum;  // 擦除的页数
//				uint32_t page_error = 0;
//				HAL_FLASH_Unlock();  // 解锁Flash
//				HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_init, &page_error);  // 执行擦除操作
//				HAL_FLASH_Lock();  // 上锁Flash
//			}
			all_len = FileLength_IAP;
			
			tag = App2_MD5_Check(Application_Buffer_Addr,all_len);
			if (tag)
			{
				iap_write_appbin(ADD_UPDATE_PROG,Application_Buffer_Addr,all_len);

				HAL_Delay(80);
				txLen = sprintf((char *)USART_IAP_RX, "updating");
				HAL_UART_Transmit_IT(&huart1,USART_IAP_RX,txLen);		
				while (huart1.gState == HAL_UART_STATE_BUSY_TX)
				{
					HAL_Delay(1);
				}	
				
				
			}
			else
			{
				txLen = sprintf((char *)USART_IAP_RX,"checkfail");
				delay_sys_us(80);
				HAL_UART_Transmit_IT(&huart1,USART_IAP_RX,txLen);					
				while (huart1.gState == HAL_UART_STATE_BUSY_TX)
				{
					HAL_Delay(1);
				}
				return ;
			}	
			
			if (App2_MD5_Check(ADD_UPDATE_PROG,all_len))
			{		
				txLen = sprintf((char *)USART_IAP_RX, "checkok");
				HAL_UART_Transmit_IT(&huart1,USART_IAP_RX,txLen);			
				while (huart1.gState == HAL_UART_STATE_BUSY_TX)
				{
					HAL_Delay(1);
				}
				
				Set_App2_Flag();
//				iap_load_app(ADD_UPDATE_PROG);
			}
//			break;

		case Startup_APP2: /*启动最新的程序 */

//			txLen = sprintf((char *)USART_IAP_RX, "jump");
//			HAL_UART_Transmit_IT(&huart1,USART_IAP_RX,txLen);		
			if ((all_len<0x20000) && App2_MD5_Check(ADD_UPDATE_PROG,all_len))
			{
				__set_FAULTMASK(0);			   //先关闭全局中断
//				iap_load_app(ADD_UPDATE_PROG); //执行FLASH APP2代码
				jump_to_app(ADD_UPDATE_PROG);
			}
			
			
//			__set_FAULTMASK(0);		
//			Set_normal_Flag();
			
//			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
//			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
//			Set_App2_Flag();
//			
//			__set_FAULTMASK(0);			   //先关闭全局中断
//			iap_load_app(ADD_UPDATE_PROG);
			
			

//			Set_jump_Flag();
////	
//		case Jump_app:
			
//			__set_FAULTMASK(0);			   //先关闭全局中断
////			Set_normal_Flag();
//			IAP_ExecuteApp(0x8020000); //执行FLASH APP2代码
//			
			break;
		default: // 启动失败
		{
			return;
		}
	}
}

