iap_upgrade.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include "iap_upgrade.h"
  2. #include "Callback.h"
  3. #include "cmsis_os.h" //osDelay
  4. #include "uType.h"
  5. //BootParams g_bootParams;
  6. JsonDat_Root JsRoot;
  7. static uint32_t upgrade_offset = 0;
  8. uint16_t upgrade_mode_subcode = 0; // 记录使用的subcode(0x0100 或 0x0200)
  9. uint32_t expected_file_size = 0; // 升级文件大小值
  10. static uint8_t expected_md5_0200[4]; // 接收的MD5码头4字节
  11. static uint8_t expected_md5_0100[16]; // 接收的MD5码16字节
  12. static uint32_t current_packet_index = 0;
  13. static bool upgrade_in_progress = false; // 确保先收到起始帧再允许数据帧执行
  14. bool erase_APP2 = false;
  15. bool erase_APPdata_buffer = false;
  16. bool save_JsRoot_0100_flag = false;
  17. uint32_t data4001_last_data_time = 0; // 上次收到数据帧的时间戳(单位:毫秒)
  18. //static uint32_t upgrade_target_addr = IAPDataBuffer_ADDR; // 固定写入缓存区static uint32_t upgrade_target_addr = 0;
  19. // 应答起始帧 状态码+固定6字节(00 00 01 00 00 00)
  20. // (状态码:0=成功,其他为错误)
  21. void send_upgrade_start_response(uint8_t func_code, uint16_t reg_addr, uint8_t status_code, uint16_t sliceCount)
  22. {
  23. static uint8_t tx_buf[32] __attribute__((aligned(4)));
  24. uint16_t len = 0;
  25. tx_buf[len++] = JsRoot.addr;
  26. tx_buf[len++] = func_code;
  27. tx_buf[len++] = reg_addr >> 8;
  28. tx_buf[len++] = reg_addr & 0xFF;
  29. tx_buf[len++] = 0x41; // 自定义应答命令
  30. tx_buf[len++] = 0x00;
  31. tx_buf[len++] = status_code; // 状态码
  32. tx_buf[len++] = sliceCount >> 8;
  33. tx_buf[len++] = sliceCount & 0xFF;
  34. tx_buf[len++] = 0x01;
  35. tx_buf[len++] = 0x00;
  36. tx_buf[len++] = 0x00;
  37. tx_buf[len++] = 0x00;
  38. uint16_t crc = modbus_crc16(tx_buf, len);
  39. tx_buf[len++] = crc & 0xFF;
  40. tx_buf[len++] = (crc >> 8) & 0xFF;
  41. // DEBUG_PRINTF("TX_BUF: ");
  42. // for (uint16_t i = 0; i < len; i++) {
  43. // DEBUG_PRINTF("%02X ", tx_buf[i]);
  44. // }
  45. // DEBUG_PRINTF("\r\n");
  46. // HAL_GPIO_WritePin(GPIOB, RS485_RE_Pin, GPIO_PIN_SET);
  47. // HAL_UART_Transmit_DMA(&huart1, tx_buf, len);
  48. uart485send(tx_buf, len);
  49. if(Systemmode != releasemode)
  50. taskprinttx(tx_buf,len);
  51. }
  52. // 应答数据帧 状态码 + 固定2字节(00 00)
  53. // (状态码:0=成功,其他为错误)
  54. void send_upgrade_data_response(uint8_t func_code, uint16_t reg_addr, uint8_t status_code, uint16_t sliceCount)
  55. {
  56. static uint8_t tx_buf[32] __attribute__((aligned(4)));
  57. uint16_t len = 0;
  58. tx_buf[len++] = JsRoot.addr;
  59. tx_buf[len++] = func_code;
  60. tx_buf[len++] = reg_addr >> 8;
  61. tx_buf[len++] = reg_addr & 0xFF;
  62. tx_buf[len++] = 0x41; // 自定义应答命令
  63. tx_buf[len++] = 0x00;
  64. tx_buf[len++] = status_code; // 状态码
  65. tx_buf[len++] = sliceCount >> 8;
  66. tx_buf[len++] = sliceCount & 0xFF;
  67. tx_buf[len++] = 0x00;
  68. tx_buf[len++] = 0x00;
  69. tx_buf[len++] = 0x00;
  70. tx_buf[len++] = 0x00;
  71. uint16_t crc = modbus_crc16(tx_buf, len);
  72. tx_buf[len++] = crc & 0xFF;
  73. tx_buf[len++] = (crc >> 8) & 0xFF;
  74. // DEBUG_PRINTF("TX_BUF: ");
  75. // for (uint16_t i = 0; i < len; i++) {
  76. // DEBUG_PRINTF("%02X ", tx_buf[i]);
  77. // }
  78. // DEBUG_PRINTF("\r\n");
  79. // HAL_GPIO_WritePin(GPIOB, RS485_RE_Pin, GPIO_PIN_SET);
  80. // HAL_UART_Transmit_DMA(&huart1, tx_buf, len);
  81. uart485send(tx_buf, len);
  82. if(Systemmode != releasemode)
  83. taskprinttx(tx_buf,len);
  84. }
  85. // 应答结束帧 状态码 + 固定2字节(00 00)
  86. // (状态码:0=成功,其他为错误)
  87. void send_upgrade_end_response(uint8_t func_code, uint16_t reg_addr, uint8_t status_code, uint16_t sliceCount)
  88. {
  89. static uint8_t tx_buf[32] __attribute__((aligned(4)));
  90. uint16_t len = 0;
  91. tx_buf[len++] = JsRoot.addr;
  92. tx_buf[len++] = func_code;
  93. tx_buf[len++] = reg_addr >> 8;
  94. tx_buf[len++] = reg_addr & 0xFF;
  95. tx_buf[len++] = 0x41; // 自定义应答命令
  96. tx_buf[len++] = 0x00;
  97. tx_buf[len++] = status_code; // 状态码
  98. tx_buf[len++] = sliceCount >> 8;
  99. tx_buf[len++] = sliceCount & 0xFF;
  100. tx_buf[len++] = 0x00;
  101. tx_buf[len++] = 0x00;
  102. tx_buf[len++] = 0x00;
  103. tx_buf[len++] = 0x00;
  104. uint16_t crc = modbus_crc16(tx_buf, len);
  105. tx_buf[len++] = crc & 0xFF;
  106. tx_buf[len++] = (crc >> 8) & 0xFF;
  107. // DEBUG_PRINTF("TX_BUF: ");
  108. // for (uint16_t i = 0; i < len; i++) {
  109. // DEBUG_PRINTF("%02X ", tx_buf[i]);
  110. // }
  111. // DEBUG_PRINTF("\r\n");
  112. // HAL_GPIO_WritePin(GPIOB, RS485_RE_Pin, GPIO_PIN_SET);
  113. // HAL_UART_Transmit_DMA(&huart1, tx_buf, len);
  114. uart485send(tx_buf, len);
  115. if(Systemmode != releasemode)
  116. taskprinttx(tx_buf,len);
  117. }
  118. /*
  119. 状态码值:
  120. 00:正常
  121. 01:busy
  122. 02:升级文件大小超限
  123. 03:单帧切片大小超限
  124. 04:切片索引错误
  125. 05:校验错误
  126. 06:参数错误
  127. 07:命令码错误
  128. 08:执行错误(如无起始帧却先收到了数据帧)
  129. */
  130. // 处理起始帧 (0x4000)
  131. void handle_upgrade_start_frame(uint8_t *data)
  132. {
  133. DEBUG_PRINTF("\r\n============================\r\n");
  134. DEBUG_PRINTF("=== Upgrade start ===\r\n");
  135. DEBUG_PRINTF("0x4000 start\r\n");
  136. uint16_t subcode = (data[6] << 8 | data[7]);
  137. upgrade_mode_subcode = subcode; // 记录本次升级的 subcode
  138. data4001_last_data_time = HAL_GetTick(); // 收到起始帧数据更新时间戳
  139. if (upgrade_mode_subcode == 0x0100) { // md5校验码16个字节签名在bin文件最后
  140. DEBUG_PRINTF("subcode: 0x0100\r\n");
  141. expected_file_size = (data[23] << 24) | (data[24] << 16) | (data[25] << 8) | data[26];
  142. DEBUG_PRINTF("expected_file_size[0x%04x]\r\n",expected_file_size);
  143. if (expected_file_size > APP_SIZE) {
  144. send_upgrade_start_response(0x42, 0xAABB, 0x02,0x0000); // 文件过大
  145. return;
  146. }
  147. erase_APPdata_buffer = true; // 擦除APP2缓存区
  148. upgrade_offset = 0;
  149. current_packet_index = 0;
  150. upgrade_in_progress = true; // 证明收到起始帧,数据帧允许接收
  151. save_JsRoot_0100_flag = true; // 写入升级subcode以及文件大小
  152. send_upgrade_start_response(0x42, 0xAABB, 0x00,0x0000); // 特殊起始帧应答
  153. Systemmode = IAPbootloader;
  154. DEBUG_PRINTF("0x4000 end\r\n");
  155. DEBUG_PRINTF("============================\r\n");
  156. } else if (upgrade_mode_subcode == 0x0200) { // 无签名,md5校验码直接在起始帧负载里
  157. DEBUG_PRINTF("subcode: 0x0200\r\n");
  158. expected_file_size = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11];
  159. memcpy(expected_md5_0200, &data[12], 4); // 支持MD5的头4字节
  160. save_JsRoot_0100_flag = true; // 写入升级subcode以及文件大小
  161. DEBUG_PRINTF("expected_file_size[0x%04x]\r\n",expected_file_size);
  162. DEBUG_PRINTF("expected_md5_0200:");
  163. for (int i = 0; i < 4; i++)
  164. {
  165. DEBUG_PRINTF(" %02X", expected_md5_0200[i]);
  166. if ((i + 1) % 4 == 0)
  167. {
  168. DEBUG_PRINTF("\n");
  169. }
  170. }
  171. DEBUG_PRINTF("\n");
  172. DEBUG_PRINTF("============================\r\n");
  173. send_upgrade_start_response(0x42, 0xAABB, 0x00,0x0000); // 特殊起始帧应答
  174. Flash_ErasePages(IAPDataBuffer_ADDR, APP_SIZE / 4); // 擦除APP缓存区数据等待写入
  175. Systemmode = IAPbootloader;
  176. }else{
  177. send_upgrade_start_response(0x42, 0xAABB, 0x06, 0x0000); // 参数错误
  178. }
  179. }
  180. // 处理数据帧 (0x4001)
  181. void handle_upgrade_data_frame(uint8_t *data)
  182. {
  183. if (!upgrade_in_progress) {
  184. send_upgrade_data_response(0x42, 0xAABB, 0x08, 0x0000); // 执行错误08(无起始帧却先收到数据帧)
  185. return;
  186. }
  187. if ((data[4] << 8 | data[5]) != 0x4001) return;
  188. data4001_last_data_time = HAL_GetTick(); // 每次收到数据更新时间戳
  189. uint16_t index = data[6] << 8 | data[7];
  190. if (index != current_packet_index) {
  191. send_upgrade_data_response(0x42, 0xAABB, 0x04, 0x0000 );
  192. reset_upgrade_state();
  193. return;
  194. }
  195. Flash_Write64(IAPDataBuffer_ADDR + upgrade_offset, (uint64_t*)&data[8], PACKET_SIZE / 8);
  196. upgrade_offset += PACKET_SIZE;
  197. current_packet_index++;
  198. send_upgrade_data_response(0x42, 0xAABB, 0x00, current_packet_index);
  199. }
  200. // 处理结束帧 (0x4002)
  201. void handle_upgrade_end_frame(void)
  202. {
  203. uint8_t result_md5[16];
  204. MD5_CTX context;
  205. send_upgrade_end_response(0x42, 0xAABB, 0x00, 0x0000); // 应答表示收到结束帧
  206. bool md5_pass = false;
  207. if(upgrade_mode_subcode == 0x0100)
  208. {
  209. MD5Init(&context);
  210. MD5Update(&context, (uint8_t*)IAPDataBuffer_ADDR, expected_file_size - 16); // 0100 -16
  211. MD5Final(result_md5, &context); // 计算收到的整体数据的MD5
  212. // 从 IAPDataBuffer 最后 16 字节读取 MD5 签名
  213. Flash_ReadBytes(IAPDataBuffer_ADDR + expected_file_size - 16, expected_md5_0100, 16); // 从 IAPDataBuffer 最后16字节读取 MD5 校验码
  214. DEBUG_PRINTF("result_md5:");
  215. for (int i = 0; i < 16; i++)
  216. {
  217. DEBUG_PRINTF(" %02X", result_md5[i]);
  218. if ((i + 1) % 16 == 0) //
  219. {
  220. DEBUG_PRINTF("\n");
  221. }
  222. }
  223. DEBUG_PRINTF("\n");
  224. DEBUG_PRINTF("expected_md5_0100:"); // 收到MD5码16字节
  225. for (uint16_t i = 0; i < 16; i++)
  226. {
  227. DEBUG_PRINTF(" %02X", expected_md5_0100[i]);
  228. if ((i + 1) % 16 == 0) // 每行打印16字节
  229. {
  230. DEBUG_PRINTF("\n");
  231. }
  232. }
  233. DEBUG_PRINTF("\n");
  234. md5_pass = (memcmp(result_md5, expected_md5_0100, 16) == 0);
  235. // 比较APP数据缓存区的自计算的MD5和收到的MD5码是否一致,一致则表示APP缓存区接收和写入的没问题。
  236. } else if(upgrade_mode_subcode == 0x0200){
  237. MD5Init(&context);
  238. MD5Update(&context, (uint8_t*)IAPDataBuffer_ADDR, expected_file_size); // 0200 -0
  239. MD5Final(result_md5, &context); // 计算APP缓存区的MD5
  240. DEBUG_PRINTF("expected_md5_0200: "); // 收到的MD5码
  241. for (uint16_t i = 0; i < 4; i++) {
  242. DEBUG_PRINTF(" %02X", expected_md5_0200[i]);
  243. }
  244. DEBUG_PRINTF("\n");
  245. DEBUG_PRINTF("result_md5 (first 4 bytes): "); // 计算的MD5码
  246. for (uint16_t i = 0; i < 4; i++) {
  247. DEBUG_PRINTF(" %02X", result_md5[i]);
  248. }
  249. DEBUG_PRINTF("\n");
  250. md5_pass = (memcmp(result_md5, expected_md5_0200, 4) == 0); // 因为收到的只有4字节MD5码,所以只验证前四字节对不对
  251. }
  252. if (md5_pass) //如果验证APP数据缓存区的MD5码通过
  253. {
  254. DEBUG_PRINTF(" MD5 check passed \r\n");
  255. JsRoot.iapLoadStatus = 300;
  256. DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_IAP_LOAD , JsRoot.iapLoadStatus ); // 存入到SNAPSHOT数据库
  257. // 将每个字节转换为两位16进制字符
  258. for(int i = 0; i < 4; i++) {
  259. sprintf(&JsRoot.iapMd5[i*2], "%02X", result_md5[i]);
  260. }
  261. JsRoot.iapMd5[8] = '\0';
  262. DB_SaveChar(DB_ID_SNAPSHOT, KV_KEY_IAP_MD5 , JsRoot.iapMd5 ); // 存入MD5到SNAPSHOT数据库
  263. osDelay(500);
  264. NVIC_SystemReset();
  265. } else {
  266. // 收到的APP数据缓存区的数据不完整,就擦除掉缓存区的数据
  267. DEBUG_PRINTF (" MD5 check fails, Erase IAPDataBuffer_ADDR Flash \r\n");
  268. Flash_ErasePages(IAPDataBuffer_ADDR, APP_SIZE / 4); // 擦除整个 IAPDataBuffer 区域(80KB)擦除 40 页(2048字节/页)
  269. send_upgrade_end_response(0x42, 0xAABB, 0x05, 0x0000); //MD5校验错误
  270. }
  271. reset_upgrade_state(); // 清除相关升级状态标志
  272. // 4.09.06
  273. }
  274. // 清除升级状态(在失败或完成后调用)
  275. void reset_upgrade_state(void)
  276. {
  277. upgrade_offset = 0;
  278. expected_file_size = 0;
  279. memset(expected_md5_0100, 0, sizeof(expected_md5_0100));
  280. memset(expected_md5_0200, 0, sizeof(expected_md5_0200));
  281. current_packet_index = 0;
  282. upgrade_in_progress = false;
  283. }
  284. void check_upgrade_data4001_timeout(void)
  285. {
  286. if (upgrade_in_progress)
  287. {
  288. if (HAL_GetTick() - data4001_last_data_time > UPGRADE_TIMEOUT_MS)
  289. {
  290. DEBUG_PRINTF("Upgrade timeout\r\n");
  291. reset_upgrade_state(); // 清除升级状态
  292. }
  293. }
  294. }
  295. void handle_rollback_request(void) // 回退
  296. {
  297. JsRoot.iapLoadStatus = 0;
  298. JsRoot.ubootback = 1;
  299. DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_IAP_LOAD , JsRoot.iapLoadStatus ); // 存入到SNAPSHOT数据库
  300. DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_UBOOTBACK , JsRoot.ubootback ); // 存入到SNAPSHOT数据库
  301. osDelay(300);
  302. NVIC_SystemReset();
  303. }
  304. void app_jump_check_and_jump(void) // 初始化完成之后,检查状态是否跳转
  305. {
  306. if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)){ // 是否有看门狗导致复位
  307. printf ("\r\n IWDG_RST flag");
  308. // 增加计数
  309. }else{
  310. printf ("\r\n No IWDG_RST flag");
  311. }
  312. if (JsRoot.iapLoadStatus == 2) {
  313. printf ("\r\n valid APP2. Run APP2\r\n");
  314. if (!JumpToApp(APP2_ADDR)) {
  315. printf("\r\n Jump failed. Run APP1" );
  316. }
  317. } else if(JsRoot.iapLoadStatus == 0){
  318. // 运行当前 APP1 程序
  319. printf ("\r\n No valid APP2. Run APP1\r\n");
  320. }
  321. }
  322. bool JumpToApp(uint32_t addr)
  323. {
  324. // APP1: sp = 0x100037A8 ; pc = 0x08014281;
  325. // APP2: sp = 0x100037A8 ; pc = 0x08000281;
  326. uint32_t sp = *(volatile uint32_t*)addr;// *(volatile uint32_t*)addr;// 0x100037A8;//
  327. uint32_t pc = *(volatile uint32_t*)(addr + 4);// *(volatile uint32_t*)(addr + 4);// 0x08014281;//
  328. if( sp ==0x100037A8 && pc == 0x08014281) // 跳转到APP2区域
  329. {
  330. DEBUG_PRINTF("\r\n Jumping app_address. SP=0x%08X, PC=0x%08X \r\n", sp, pc);
  331. DEBUG_PRINTF("\r\n Jumping app_address success");
  332. HAL_RCC_DeInit(); // 复位时钟
  333. HAL_DeInit(); // 复位外设
  334. SCB->VTOR = addr; // 设置向量表基地址
  335. __set_MSP(sp); // 设置主堆栈指针
  336. __disable_irq(); // 关闭总中断
  337. void (*jump)(void) = (void (*)(void))pc;
  338. jump(); // 跳转到APP
  339. return true;
  340. }else{
  341. printf("\r\n Jumping app_address. SP=0x%08X, PC=0x%08X \r\n", sp, pc);
  342. printf("\r\n Jumping app_address fail");
  343. return false;
  344. }
  345. }