引用:
CRC16
KV键值系统
自动检测剩余空间是否支持备份升级,防止升级失败变砖。
#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" #include "business_gpio.h" #include "business_function.h" #include "dfu.h" #include "main.h" #define LOG(...) do { bsp_uart_send_nbyte(BSP_UART_0, NULL, sprintf((char *)bsp_uart_get_txbuff(BSP_UART_0), __VA_ARGS__)); } while (0U) #define CRC_LEN 2 #define PACK_HEAD_LEN 2 #define CRC16_INIT_VAL 0xFFFF 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--检测完成 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] = ' '; if (strncmp((const char *)data, "FILE_INFO=", strlen("FILE_INFO=")) == 0) { dfu_file_info_data((data + strlen("FILE_INFO=")), len - strlen("FILE_INFO=")); } else if (strncmp((const char *)data, "CHECK_FILE=", strlen("CHECK_FILE=")) == 0) { dfu_check_file((data + strlen("CHECK_FILE=")), len - strlen("CHECK_FILE=")); } } static void atcmd_chip_lock(uint8_t *data, uint16_t len) { uint16_t uid_crc = 0; if (len < 2) { return; } // 得到上位机发送的校验值 uid_crc = (*data) << 8 | (*(data + 1)); g_boot_info.boot_state = BOOT_STATE_RUN_APP; g_boot_info.chip_lock = uid_crc; // 填写特殊码解锁烧录 kv_set_env(BS_KV_KEY_BOOT_INFO, (uint8_t *)&g_boot_info, sizeof(boot_info_t)); // 判断上位机的校验值于自身校验值是否匹配 if (g_cal_crc == uid_crc) { LOG("AT^OK,UNLOCKrn"); delay_ms(5); sys_reset(); } else { #if !DEBUG_MODE // 关闭SWD功能 配置PC7和PD1的端子功能模式 周边模块功能模式使能 RCC->UNLOCK = 0x55AA6699; RCC->SWDIOCR = (0x5A69 << RCC_SWDIOCR_KEY_Pos); RCC->UNLOCK = 0x55AA6698; LOG("AT^OK,LOCKrn"); #else LOG("AT^OK,LOCK,%04x|%04xrn", g_cal_crc, uid_crc); #endif } } static void uart0_rx_callback(void) { uint8_t temp; uint8_t *buff = bsp_uart_get_rxbuff(BSP_UART_0); uint16_t len = bsp_uart_get_rxbuff_position(BSP_UART_0); bool flag = 0; if (len >= (BS_UART0_CACHE_SIZE - 1)) { bsp_uart_reset_rxbuff(BSP_UART_0); return; } if (len >= 10 && strncmp((const char *)buff, "UP^DATA=", strlen("UP^DATA=")) == 0) { temp = strlen("UP^DATA=") + PACK_HEAD_LEN + CRC_LEN; if (len - temp - 1 == *(buff + strlen("UP^DATA=") + 1)) { dfu_file_data((buff + strlen("UP^DATA=")), len - strlen("UP^DATA=") - 1); flag = true; g_dfu_tickstart = HAL_GetTick(); } } else if (len >= 10 && strncmp((const char *)buff, "AT^LOCK=", strlen("AT^LOCK=")) == 0) { atcmd_chip_lock((buff + strlen("AT^LOCK=")), 2); flag = true; } else if (len >= 11 && strncmp((const char *)buff, "AT^XJQ=1995", strlen("AT^XJQ=1995")) == 0) { bsp_flash_erase_page(BS_FLASH_APP_ADDR, (BS_FLASH_APP_SIZE / BS_FLASH_PAGE_SIZE) + 1); bsp_flash_erase_page(BS_KV_base_ADDR, BS_FLASH_KV_PAGE); bsp_flash_erase_page(BS_FLASH_START_ADDR + BS_FLASH_PAGE_SIZE, (BS_FLASH_BOOT_SIZE / BS_FLASH_PAGE_SIZE) + 1); } else if (len >= 10 && strncmp((const char *)buff, "bootloader", strlen("bootloader")) == 0) { LOG("UP^OK,dfu modern"); flag = true; } else if (len >= 2 && buff[len - 1] == 'n' && buff[len - 2] == 'r') { if (strncmp((const char *)buff, "UP^", strlen("UP^")) == 0) { dfu_data_analysis((buff + strlen("UP^")), len - strlen("UP^")); } flag = true; } else { if (len >= (BS_UART0_CACHE_SIZE - 1)) { flag = true; } } if (flag) { bsp_uart_reset_rxbuff(BSP_UART_0); } } static void uart0_rx_full_callback(void) { memset(bsp_uart_get_rxbuff(BSP_UART_0), 0, BS_UART0_CACHE_SIZE); bsp_uart_reset_rxbuff(BSP_UART_0); } void dfu_main(void) { uint32_t dfu_tick_current = 0; uint32_t tick_led = 0; bool key_flag = false; uint8_t key_tick = false; bool erase_flag = false; bsp_uart_init(BSP_UART_0); LOG("UP^OK,dfu mode,%04xrn", g_uid_sum); bsp_uart_rx_irq_callback(BSP_UART_0, uart0_rx_full_callback); memset(&dfu_file_info, 0, sizeof(dfu_file_info_t)); g_dfu_tickstart = HAL_GetTick(); while (1) { // 超时机制 if ((g_boot_info.boot_state == BOOT_STATE_IN_DFU) && (!g_dfu_timeout_flag)) { dfu_tick_current = HAL_GetTick(); if (dfu_tick_current - g_dfu_tickstart > g_dfu_timeout_ms) { g_dfu_timeout_flag = true; sys_jump_app(); } } tick_led ++; if(tick_led % 0xFFF == 0) { // boot 模式 指示灯闪烁 bsp_gpio_set_toggle(BS_LED0_GPIO_PORT, BS_LED0_PIN); } if (!g_dfu_timeout_flag) { // boot 模式进行自毁工作 if (erase_flag) { bsp_flash_erase_page(BS_FLASH_APP_ADDR, (BS_FLASH_APP_SIZE / BS_FLASH_PAGE_SIZE) + 1); bsp_flash_erase_page(BS_KV_base_ADDR, BS_FLASH_KV_PAGE); sys_reset(); } if (bsp_gpio_get_state(BOARD_BUTTON_SYS_PORT, BOARD_BUTTON_SYS_PIN) == BOARD_BUTTON_SYS_PRESS_LEVEL) { if (!key_flag) { continue; } else { key_tick ++; key_flag = false; if (key_tick > 9) { key_tick = 0; erase_flag = true; } } } else { if (!key_flag) { key_flag = true; } } } uart0_rx_callback(); } }
#ifndef __DFU_H #define __DFU_H #include#include typedef struct { uint16_t file_crc16; uint32_t file_size; uint32_t current_size; uint8_t old_pack_id; bool flash_flag; } dfu_file_info_t; void dfu_main(void); #endif


![[单片机框架][DFU] Dfu升级例子 带crc校验+超时机制+led指示灯+芯片加锁+芯片自擦 [单片机框架][DFU] Dfu升级例子 带crc校验+超时机制+led指示灯+芯片加锁+芯片自擦](http://www.mshxw.com/aiimages/31/739125.png)
