#include "otaEvent.h"
#include "usart.h"
#include "systick.h"
#include "w25q32.h"
#include "main.h"
#include "ec800m.h"
#include <stdio.h>
#include "string.h"

#define APPBLOCKNB 2      	//下载的程序位于block的第3块中
#define OTA_EVENT_BLOCKNB 1 //OTA事件完成标志存储的位置位于第2块中

#define SOH 0x01 // XMOD协议帧头
#define ACK 0X06 // 应答标志
#define NAK 0x15 // 非应答标志
#define EOT 0x04 // 结束标志
int8_t xmodem(uint16_t timeout);
OTA_T ota_data;
uint16_t Xmodem_CRC16(uint8_t *data, uint16_t datalen);
static OTA_MESSAGE ota_message;

#if 0
//测试用的
int WaitForReadData(uint8_t* data,int timeout,int datalen)
{
	uint32_t len = 0;
	bool timeoutFlag = false;
	if (timeout >= 0)
	{
		timeoutFlag = true;
	}
	while (1)
	{
		delay_1ms(50);
		if (UART0_RX_STAT > 0)
		{
			UART0_RX_STAT = 0;
			char *p  = strstr((char *)&UART0_RX_BUF, "CONNECT ");
			if (p)
			{
				p += 8;
				sscanf(p, "%u\r", &len);		// 读取长度
				if(len == datalen)
				{
					p = strchr(p, '\n') + 1;		// 跳过换行
					memcpy(data,p,datalen);
					Clear_DMA_Buffer();
					return datalen;
				}
				else
				{
					Clear_DMA_Buffer();
					return len;
				}
			}
			
		}
		timeout -= 50;
		if (timeoutFlag == true && timeout <= 0)
		{
			Clear_DMA_Buffer();
			return -1;
		}
	}
}
static uint8_t app_programmer[1024];
void read_ota_DATA(uint32_t app_byte)
{
	/* 打开UFS:otaDATA.txt */
	EC800MSendCmd(CLOSE_otaDATA_FILE,strlen(CLOSE_otaDATA_FILE));
	WaitResponse("QFCLOSE",1000);
	EC800MSendCmd(OPEN_otaDATA_FILE,strlen(OPEN_otaDATA_FILE));
	if(WaitResponse("QFOPEN:", 2000) == 0)
		return;
	for(uint8_t i=0;i<app_byte/1024;i++)				//一次读1KB
	{
		task_fwdgt_reload();
		memset(app_programmer,0,1024);
		// uint32_t addr=APP_PROGRAMMER_BLOCK*64*1024+i*1024;   //其在w25q32中的地址
		// W25Q32_Read(app_programmer,addr,1024);
		while(1)
		{
			int x = 0;
			EC800MSendCmd(READ_otaDATA_FILE,strlen(READ_otaDATA_FILE));
			x = WaitForReadData(app_programmer,2000,1024);
			if((x != 1024) && (x != -1))
			{
				char* SEEK_otaDATA_FILE = "";
				sprintf(SEEK_otaDATA_FILE,"AT+QFSEEK=1,%d,2\r\n",x);
				EC800MSendCmd(SEEK_otaDATA_FILE,strlen(SEEK_otaDATA_FILE));	//出错的话文件指针向左偏移1024个字节
			}
			else if(x == 1024)
			{
				break;
			}
		}
		delay_1ms(50);
	}
	//将不满1024数据单独写入
	if(app_byte % 1024 != 0)
	{
		uint32_t startAddress=(app_byte/1024)*1024;
		memset(app_programmer,0,1024);
		// uint32_t addr=APP_PROGRAMMER_BLOCK*64*1024+(app_byte/1024)*1024;   														//其在w25q32中的地址
		// W25Q32_Read(app_programmer,addr,app_byte%1024);	
		while(1)
		{
			int x = 0;
			EC800MSendCmd(READ_otaDATA_FILE,strlen(READ_otaDATA_FILE));
			x = WaitForReadData(app_programmer,2000,app_byte % 1024);
			if(x != (app_byte % 1024) && (x != -1))
			{
				char* SEEK_otaDATA_FILE = "";
				sprintf(SEEK_otaDATA_FILE,"AT+QFSEEK=1,%d,2\r\n",x);
				EC800MSendCmd(SEEK_otaDATA_FILE,strlen(SEEK_otaDATA_FILE));	//出错的话文件指针向左偏移读取字节数
			}
			else if(x == (app_byte % 1024))
			{
				break;
			}
		}		
		delay_1ms(50);																	
	}
	// 关闭保存UFS文件
	while(1)
	{
		EC800MSendCmd(CLOSE_otaDATA_FILE,strlen(CLOSE_otaDATA_FILE));
		if(WaitResponse("OK", 2000) == 1)
		{
			break;
		}
	}
}
#endif

/*
 *  函数名：uint8_t check_ota_event()
 *  输入参数：无
 *  输出参数：无
 *  返回值：无
 *  函数作用：判断ota事件是否产生是否要进入更新部分
 */
int8_t check_ota_event()
{
	                                           //关闭看门狗
	// 当标志位为1时证明ota事件产生,将进入ota升级路线
	if (ota_data.ota_flag == 1)
	{
		// W25Q32_Erase64K(APPBLOCKNB);                    //程序文件在第三block以后
		// EC800MSendCmd(DEL_otaDATA_FILE, strlen(DEL_otaDATA_FILE));	//清空OTA数据文件
		int8_t recvSta = xmodem(1000);						//在1000秒内解决OTA更新
		if (recvSta == 0)
		{
			return 0;
		}
		else
		{
			// read_ota_DATA(ota_message.XmodemByte);
			NVIC_SystemReset();
		}
	}
	else
		return 0;
}

uint8_t WaitResponse_value(int timeout)
{
	bool timeoutFlag = false;
	if (timeout >= 0)
	{
		timeoutFlag = true;
	}

	while (1)
	{
		delay_1ms(50);
		if (UART0_RX_STAT > 0)
		{
			UART0_RX_STAT = 0;
			char *p = strstr((char *)&UART0_RX_BUF, ": ") + 2;
			if (p)
			{
				uint8_t ret = 0;
				ret = strtol(p, &p, 10);
				Clear_DMA_Buffer();
				return ret;
			}
		}
		timeout -= 50;
		if (timeoutFlag == true && timeout <= 0)
		{
			Clear_DMA_Buffer();
			return 0;
		}
	};
}

int8_t xmodem(uint16_t timeout)
{
	int startTime = gettick();
	ota_data.done=0;
	OTA_flag data_flag;
	data_flag.flag=0;
	data_flag.xmodemNB=0;                         
	while(1)
	{
		task_fwdgt_reload();                                 //喂狗
		if(gettick()-startTime>timeout*1000)return 0;		//如果一直得不到上位机的xmode数据相应，超时则跳出本函数
		usart_data_transmit(COM_232, 'C');					//向上位机发送'C'，表明请求xmodem数据
		delay_1ms(1000);
		if(ota_data.done==1)
		{
			//打开otaData.txt文件
			EC800MSendCmd(CLOSE_otaDATA_FILE,strlen(CLOSE_otaDATA_FILE));
			WaitResponse("QFCLOSE",1000);
			EC800MSendCmd(OPEN_otaDATA_FILE,strlen(OPEN_otaDATA_FILE));
			if(WaitResponse("QFOPEN:", 2000) == 0)
				return 0;
			break;							//如果上位机响应请求则跳出循环等待
		}
	}
	// 判断数据帧头是否符合标准
	while (gettick() - startTime < timeout * 1000)
	{
		if (ota_data.done == 1)
		{
			task_fwdgt_reload();                                       //喂狗
			if (ota_data.data[0] == SOH && ota_data.data_cnt == 133)	//如果xmodem数据包是满的128个字节
			{
				uint16_t XCRC = Xmodem_CRC16(ota_data.data + 3, 128);	
				if (XCRC == ota_data.data[131] * 256 + ota_data.data[132]) // 经过校验的数据一致时将进行数据处理
				{
					data_flag.xmodemNB++;	//xmodem数据包计数
					// W25Q32_PageWrite(w25q32_data,APPBLOCKNB*256+(data_flag.xmodemNB-1)/2);
					uint8_t sed_flg = 0;
					while(sed_flg < 2)
					{
						EC800MSendCmd(WRITE_otaDATA_FILE,strlen(WRITE_otaDATA_FILE));
						if(WaitResponse("CONNECT", 2000) == 0)
						{
							sed_flg++;
						}
						else
						{
							sed_flg = 0;
							break;
						}	
					}
					while(sed_flg < 2)
					{
						EC800MSendCmd(ota_data.data + 3,128);
//						EC800MSendCmd(TEST_DATA,128);
						int x = WaitResponse_value(2000);
						if(x != 128)
						{
							sed_flg++;
							char* QFSEEK_CMD;
							sprintf(QFSEEK_CMD,"AT+QFSEEK=1,%d,2\r\n",x);
							EC800MSendCmd(QFSEEK_CMD,strlen(QFSEEK_CMD));	//出错的话文件指针向左偏移x个字节
						}
						else
						{
							sed_flg = 0;
							break;
						}
					}
					
					ota_data.data_cnt = 0;
					memset(ota_data.data, 0, 133);
					ota_data.done = 0;
					usart_data_transmit(COM_232, ACK);
	
				}
				else
				{
					ota_data.data_cnt = 0;
					memset(ota_data.data, 0, 133);
					ota_data.done = 0;
					usart_data_transmit(COM_232, NAK);
				}
			}
			//进入结束的包处理
			else if (ota_data.data[0] == EOT && ota_data.data_cnt == 1)
			{
				// if(data_flag.xmodemNB%2!=0)                                            //将可能为奇数的数据写入进去
				// {
					// W25Q32_PageWrite(w25q32_data,APPBLOCKNB*256+(data_flag.xmodemNB-1)/2);
				// }
				// 保存UFS文件
				uint8_t sed_flg = 0;
				while(sed_flg < 2)
				{
					EC800MSendCmd(CLOSE_otaDATA_FILE,strlen(CLOSE_otaDATA_FILE));
					if(WaitResponse("OK", 2000) == 0)
					{
						sed_flg++;
					}
					else
					{
						sed_flg = 0;
						break;
					}	
				}

				usart_data_transmit(COM_232, ACK);
				//完成xmodem协议的交互将完成的标志存储到内存中
				ota_message.Completion_flag=1U;
				ota_message.XmodemByte=data_flag.xmodemNB*128;//后续补齐的0x1A还需要进一步考虑

				while(sed_flg < 2)
				{
					EC800MSendCmd(CLOSE_otaDATA_FILE,strlen(CLOSE_otaDATA_FILE));
					WaitResponse("QFCLOSE",1000);
					EC800MSendCmd(OPEN_otaMSG_FILE,strlen(OPEN_otaMSG_FILE));
					if(WaitResponse("QFOPEN:", 2000) == 0)
					{
						sed_flg++;
					}
					else
					{
						sed_flg = 0;
						break;
					}
				}
				

				while(sed_flg < 2)
				{
					EC800MSendCmd(WRITE_otaMSG_FILE,strlen(WRITE_otaMSG_FILE));
					if(WaitResponse("CONNECT", 2000) == 0)
					{
						sed_flg++;
					}
					else
					{
						sed_flg = 0;
						break;
					}
				}

				while(sed_flg < 2)
				{
					EC800MSendCmd((uint8_t *)&ota_message,sizeof(OTA_MESSAGE));
					// delay_1ms(3000);
					int x = WaitResponse_value(2000);
					if(x != sizeof(OTA_MESSAGE))
					{
						sed_flg++;
						char* QFSEEK_CMD;
						sprintf(QFSEEK_CMD,"AT+QFSEEK=1,%d,2",x);
						EC800MSendCmd(QFSEEK_CMD,strlen(QFSEEK_CMD));	//出错的话文件指针向左偏移x个字节
					}
					else
					{
						sed_flg = 0;
						break;
					}
				}

				while(sed_flg < 2)
				{
					EC800MSendCmd(CLOSE_otaMSG_FILE,strlen(CLOSE_otaMSG_FILE));
					if(WaitResponse("OK", 2000))
					{
						sed_flg++;
					}
					else
					{
						sed_flg = 0;
						break;
					}
				}

				// W25Q32_Erase64K(OTA_EVENT_BLOCKNB);//擦除原先的数据
				// W25Q32_PageWrite((uint8_t *)&ota_message,OTA_EVENT_BLOCKNB*256);
				ota_data.data_cnt = 0;
				memset(ota_data.data, 0, 133);
				ota_data.done = 0;
				delay_1ms(50);
				// 写入事件完成标志后重启设备,其他状态页无需回滚，写入完成会执行重启指令
				return 1;
			}
			else
			{
				ota_data.data_cnt = 0;
				memset(ota_data.data, 0, 133);
				ota_data.done = 0;
				usart_data_transmit(COM_232, NAK);
			}
		}

		delay_1ms(1);
	}
	return 0;
}

/*-------------------------------------------------*/
/*函数名：Xmodem_CRC16校验                         */
/*参  数：data：数据指针  datalen：数据长度        */
/*返回值：校验后的数据                             */
/*-------------------------------------------------*/
uint16_t Xmodem_CRC16(uint8_t *data, uint16_t datalen)
{

	uint8_t i;					// 用于for循环
	uint16_t Crcinit = 0x0000;	// Xmdoem CRC校验的初始值，必须是0x0000
	uint16_t Crcipoly = 0x1021; // Xmdoem CRC校验的多项式，必须是0x1021

	while (datalen--)
	{									  // 根据datalen大小，有多少字节循环多少次
		Crcinit = (*data << 8) ^ Crcinit; // 先将带校验的字节，挪到高8位
		for (i = 0; i < 8; i++)
		{											 // 每个字节8个二进制位，循环8次
			if (Crcinit & 0x8000)					 // 判断BIT15是1还是0,是1的话，进入if
				Crcinit = (Crcinit << 1) ^ Crcipoly; // 是1的话，先左移，再异或多项式
			else									 // 判断BIT15是1还是0,是0的话，进入else
				Crcinit = (Crcinit << 1);			 // 是0的话，只左移
		}
		data++; // 下移，计算一个字节数据
	}
	return Crcinit; // 返回校验后的数据
}
