otaEvent.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #include "otaEvent.h"
  2. #include "usart.h"
  3. #include "systick.h"
  4. #include "w25q32.h"
  5. #include "main.h"
  6. #define APPBLOCKNB 2 //下载的程序位于block的第3块中
  7. #define OTA_EVENT_BLOCKNB 1 //OTA事件完成标志存储的位置位于第2块中
  8. #define SOH 0x01 // XMOD协议帧头
  9. #define ACK 0X06 // 应答标志
  10. #define NAK 0x15 // 非应答标志
  11. #define EOT 0x04 // 结束标志
  12. int8_t xmodem(uint16_t timeout);
  13. OTA_T ota_data;
  14. uint8_t w25q32_data[256]; //存放w25q32数据
  15. uint16_t Xmodem_CRC16(uint8_t *data, uint16_t datalen);
  16. /*
  17. * 函数名:uint8_t check_ota_event()
  18. * 输入参数:无
  19. * 输出参数:无
  20. * 返回值:无
  21. * 函数作用:判断ota事件是否产生是否要进入更新部分
  22. */
  23. int8_t check_ota_event()
  24. {
  25. //关闭看门狗
  26. // 当标志位为1时证明ota事件产生,将进入ota升级路线
  27. if (ota_data.ota_flag == 1)
  28. {
  29. W25Q32_Erase64K(APPBLOCKNB); //程序文件在第三block以后
  30. int8_t recvSta = xmodem(1000);
  31. if (recvSta == 0)
  32. {
  33. return 0;
  34. }
  35. else
  36. {
  37. NVIC_SystemReset();
  38. }
  39. }
  40. else
  41. return 0;
  42. }
  43. int8_t xmodem(uint16_t timeout)
  44. {
  45. int startTime = gettick();
  46. ota_data.done=0;
  47. OTA_flag data_flag;
  48. data_flag.flag=0;
  49. data_flag.xmodemNB=0;
  50. while(1)
  51. {
  52. task_fwdgt_reload(); //喂狗
  53. if(gettick()-startTime>timeout*1000)return 0;
  54. usart_data_transmit(COM_232, 'C');
  55. delay_1ms(1000);
  56. if(ota_data.done==1)break;
  57. }
  58. // 判断数据帧头是否符合标准
  59. while (gettick() - startTime < timeout * 1000)
  60. {
  61. if (ota_data.done == 1)
  62. {
  63. task_fwdgt_reload(); //喂狗
  64. if (ota_data.data[0] == SOH && ota_data.data_cnt == 133)
  65. {
  66. uint16_t XCRC = Xmodem_CRC16(ota_data.data + 3, 128);
  67. if (XCRC == ota_data.data[131] * 256 + ota_data.data[132]) // 经过校验的数据一致时将进行数据处理
  68. {
  69. data_flag.xmodemNB++;
  70. //因为W25Q32只支持按页写入数据、所以将128字节数据找了一个暂存空间,两次应答才进行一次数据写入,最后在结束语句判断是否为奇数在进行
  71. //数据尾部的处理
  72. if(ota_data.data[1]%2==0)
  73. {
  74. memcpy(w25q32_data+128,ota_data.data + 3,128);
  75. W25Q32_PageWrite(w25q32_data,APPBLOCKNB*256+(data_flag.xmodemNB-1)/2);
  76. memset(w25q32_data,0,256);
  77. }
  78. else
  79. {
  80. memcpy(w25q32_data,ota_data.data + 3,128);
  81. }
  82. ota_data.data_cnt = 0;
  83. memset(ota_data.data, 0, 133);
  84. ota_data.done = 0;
  85. usart_data_transmit(COM_232, ACK);
  86. }
  87. else
  88. {
  89. ota_data.data_cnt = 0;
  90. memset(ota_data.data, 0, 133);
  91. ota_data.done = 0;
  92. usart_data_transmit(COM_232, NAK);
  93. }
  94. }
  95. //进入结束的包处理
  96. else if (ota_data.data[0] == EOT && ota_data.data_cnt == 1)
  97. {
  98. if(data_flag.xmodemNB%2!=0) //将可能为奇数的数据写入进去
  99. {
  100. W25Q32_PageWrite(w25q32_data,APPBLOCKNB*256+(data_flag.xmodemNB-1)/2);
  101. }
  102. usart_data_transmit(COM_232, ACK);
  103. //完成xmodem协议的交互将完成的标志存储到内存中
  104. OTA_MESSAGE ota_message;
  105. ota_message.Completion_flag=1U;
  106. ota_message.XmodemByte=data_flag.xmodemNB*128;//后续补齐的0x1A还需要进一步考虑
  107. W25Q32_Erase64K(OTA_EVENT_BLOCKNB);//擦除原先的数据
  108. W25Q32_PageWrite((uint8_t *)&ota_message,OTA_EVENT_BLOCKNB*256);
  109. delay_1ms(50);
  110. // 写入事件完成标志后重启设备,其他状态页无需回滚,写入完成会执行重启指令
  111. return 1;
  112. }
  113. else
  114. {
  115. ota_data.data_cnt = 0;
  116. memset(ota_data.data, 0, 133);
  117. ota_data.done = 0;
  118. usart_data_transmit(COM_232, NAK);
  119. }
  120. }
  121. delay_1ms(1);
  122. }
  123. return 0;
  124. }
  125. /*-------------------------------------------------*/
  126. /*函数名:Xmodem_CRC16校验 */
  127. /*参 数:data:数据指针 datalen:数据长度 */
  128. /*返回值:校验后的数据 */
  129. /*-------------------------------------------------*/
  130. uint16_t Xmodem_CRC16(uint8_t *data, uint16_t datalen)
  131. {
  132. uint8_t i; // 用于for循环
  133. uint16_t Crcinit = 0x0000; // Xmdoem CRC校验的初始值,必须是0x0000
  134. uint16_t Crcipoly = 0x1021; // Xmdoem CRC校验的多项式,必须是0x1021
  135. while (datalen--)
  136. { // 根据datalen大小,有多少字节循环多少次
  137. Crcinit = (*data << 8) ^ Crcinit; // 先将带校验的字节,挪到高8位
  138. for (i = 0; i < 8; i++)
  139. { // 每个字节8个二进制位,循环8次
  140. if (Crcinit & 0x8000) // 判断BIT15是1还是0,是1的话,进入if
  141. Crcinit = (Crcinit << 1) ^ Crcipoly; // 是1的话,先左移,再异或多项式
  142. else // 判断BIT15是1还是0,是0的话,进入else
  143. Crcinit = (Crcinit << 1); // 是0的话,只左移
  144. }
  145. data++; // 下移,计算一个字节数据
  146. }
  147. return Crcinit; // 返回校验后的数据
  148. }