自动检测剩余空间是否支持备份升级,防止升级失败变砖。
/********************************************************************************
* @file main.c
* @author jianqiang.xue
* @Version V1.0.0
* @Date 2021-04-03
* @brief NULL
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include #include #include #include #include "RTE_Components.h" #include CMSIS_device_header #include "bsp_system_clock.h" #include "bsp_gpio.h" #include "bsp_uart.h" #include "bsp_flash.h" #include "sys_api.h" #include "crc16.h" #include "check_uid.h" #include "errorno.h" #include "str_hex.h" #include "x_strtok.h" #include "kv_sys.h" /* Private Includes ----------------------------------------------------------*/ #include "business_gpio.h" #include "business_function.h" #include "dfu.h" #include "main.h" /* Private Define ------------------------------------------------------------*/ #define LOG(...) do { bsp_uart_send_nbyte(BSP_UART_0, NULL, sprintf((char *)bsp_uart_get_txbuff(BSP_UART_0), __VA_ARGS__)); } while (0U) /* Private Typedef -----------------------------------------------------------*/ /* Private Define ------------------------------------------------------------*/ #define CRC_LEN 2 #define PACK_HEAD_LEN 2 #define CRC16_INIT_VAL 0xFFFF /* Private Macro -------------------------------------------------------------*/ /* Private Variables ---------------------------------------------------------*/ uint32_t g_write_flash_addr = 0; // DFU 超时机制 15s没有数据达到,则判断app是否存在,如果存在则跳转至app static dfu_file_info_t dfu_file_info = {0}; uint32_t g_dfu_tickstart = 0; uint16_t g_dfu_timeout_ms = 15000; bool g_dfu_timeout_flag = 0; // 0 -- 未检测 1--检测完成 /* Private Function Prototypes -----------------------------------------------*/ static void dfu_file_info_data(uint8_t *data, uint16_t len) { char *token_r; char *argv[2]; char *arg; uint8_t argc = 0; uint8_t crc[2] = {0, 0}; uint8_t crc_len = 0; uint16_t crc16 = 0; // LOG("data:%s, len:%drn", data, len); arg = x_strtok_s((char*)data, ",", &token_r); while (arg != NULL) { argv[argc++] = arg; arg = x_strtok_s(NULL, ",", &token_r); } if (argc == 2) { crc_len = str_to_hex(argv[0], crc); if (crc_len == CRC_LEN) { crc16 = (crc[0] << 8) | crc[1]; } else { goto end; } memset(&dfu_file_info, 0, sizeof(dfu_file_info_t)); dfu_file_info.file_crc16 = crc16; dfu_file_info.file_size = atoi(argv[1]); // LOG("UP^OK,0,crc:%x, size:%drn", crc16, atoi(argv[1])); LOG("UP^OK,0,%drn", BS_UART0_CACHE_SIZE); } else { end: LOG("UP^FAIL,%drn", E_INVAL_PARM); } } static void dfu_file_data(uint8_t *data, uint16_t len) { uint16_t rx_crc; uint16_t cal_crc; uint8_t pack_id; uint8_t pack_len; uint8_t *pack_data; uint8_t pdu_len; if (len < PACK_HEAD_LEN + CRC_LEN) { //LOG("UP^FAIL,%drn", E_INVAL_LEN); LOG("UP^FAIL,LENrn"); return; } pack_len = *(data + 1); pdu_len = pack_len + PACK_HEAD_LEN; if (len != pdu_len + CRC_LEN) { //LOG("UP^FAIL,%d,%d,%drn", E_INVAL_DATA, pdu_len + CRC_LEN, len); LOG("UP^FAIL,LEN1rn"); return; } pack_id = *(data + 0); pack_data = (data + 2); // pack的最后两个字节为crc值, 这里的len是按1计算的,所以按数组时,要多减1. rx_crc = (*(data + len - 2) << 8) | *(data + len - 1); cal_crc = crc16(CRC16_INIT_VAL, pack_data, pack_len); // LOG("CRC,rx:%x,cal:%xrn",rx_crc, cal_crc); if (rx_crc != cal_crc) { //LOG("UP^FAIL,%d,R:%x,C:%x,L:%drn", E_CRC, rx_crc, cal_crc, pack_len); LOG("UP^FAIL,CRC1rn"); return; } // 第一次接到数据,则擦除flash if (dfu_file_info.flash_flag == false && dfu_file_info.file_size != 0) { dfu_file_info.flash_flag = true; // 如果固件大小 < APP容量的一半,则使用备份升级 if (dfu_file_info.file_size < (BS_FLASH_APP_SIZE / 2)) { g_write_flash_addr = BS_FLASH_OTA_ADDR; sys_disable_irq(); bsp_flash_erase_page(g_write_flash_addr, ((BS_FLASH_APP_SIZE / 2) / BS_FLASH_PAGE_SIZE) + 1); sys_enable_irq(); } else { g_write_flash_addr = BS_FLASH_APP_ADDR; sys_disable_irq(); bsp_flash_erase_page(g_write_flash_addr, (BS_FLASH_APP_SIZE / BS_FLASH_PAGE_SIZE) + 1); sys_enable_irq(); } return; } if ((pack_id == dfu_file_info.old_pack_id) || (pack_id < dfu_file_info.old_pack_id) || (pack_id > dfu_file_info.old_pack_id && (pack_id - dfu_file_info.old_pack_id != 1))) { LOG("UP^FAIL,%d,%d,%drn", E_MSG, dfu_file_info.old_pack_id, pack_id); return; } dfu_file_info.old_pack_id = pack_id; if (dfu_file_info.flash_flag == true && dfu_file_info.file_size != 0) { if (g_write_flash_addr == 0) { return; } bsp_flash_write_nbyte_s(g_write_flash_addr + dfu_file_info.current_size, pack_data, pack_len); dfu_file_info.current_size += pack_len; LOG("UP^OK,%drn", pack_id); } } static void dfu_check_file(uint8_t *data, uint16_t len) { if (dfu_file_info.flash_flag == false || dfu_file_info.file_size == 0 || dfu_file_info.file_size != dfu_file_info.current_size || g_write_flash_addr == 0) { LOG("UP^FAIL,FILErn"); return; } uint16_t cal_crc; cal_crc = crc16(CRC16_INIT_VAL, (uint8_t *)g_write_flash_addr, dfu_file_info.current_size); if (cal_crc != dfu_file_info.file_crc16) { // LOG("UP^FAIL,%x %xrn", cal_crc, dfu_file_info.file_crc16); LOG("UP^FAIL,CRCrn"); } else { LOG("UP^OK,UPrn"); g_boot_info.app_crc = dfu_file_info.file_crc16; g_boot_info.boot_carry_size = dfu_file_info.current_size; if (g_write_flash_addr == BS_FLASH_OTA_ADDR) { g_boot_info.boot_state = BOOT_STATE_MOVE_OTA_IN_APP; kv_set_env(BS_KV_KEY_BOOT_INFO, (uint8_t *)&g_boot_info, sizeof(boot_info_t)); delay_ms(5); } else if (g_boot_info.boot_state < 2) { g_boot_info.boot_state = BOOT_STATE_RUN_APP; kv_set_env(BS_KV_KEY_BOOT_INFO, (uint8_t *)&g_boot_info, sizeof(boot_info_t)); delay_ms(5); } // 跳转启动 sys_reset(); } } static void dfu_data_analysis(uint8_t *data, uint16_t len) { data[len] = '