当前位置:网站首页>[MCU framework][dfu] DFU upgrade example with CRC verification + timeout mechanism +led indicator + chip locking + chip self erasure
[MCU framework][dfu] DFU upgrade example with CRC verification + timeout mechanism +led indicator + chip locking + chip self erasure
2022-06-29 03:39:00 【jianqiang. xue】
quote :
CRC16
KV Key value system
Automatically detect whether the remaining space supports backup and upgrade , Prevent brick changing due to upgrade failure .
/******************************************************************************** * @file main.c * @author jianqiang.xue * @Version V1.0.0 * @Date 2021-04-03 * @brief NULL ********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#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 Timeout mechanism 15s No data reached , Then judge app Whether there is , If it exists, go to 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 -- Not detected 1-- Test complete
/* 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:%d\r\n", 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:%d\r\n", crc16, atoi(argv[1]));
LOG("UP^OK,0,%d\r\n", BS_UART0_CACHE_SIZE);
}
else
{
end:
LOG("UP^FAIL,%d\r\n", 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,%d\r\n", E_INVAL_LEN);
LOG("UP^FAIL,LEN\r\n");
return;
}
pack_len = *(data + 1);
pdu_len = pack_len + PACK_HEAD_LEN;
if (len != pdu_len + CRC_LEN)
{
//LOG("UP^FAIL,%d,%d,%d\r\n", E_INVAL_DATA, pdu_len + CRC_LEN, len);
LOG("UP^FAIL,LEN1\r\n");
return;
}
pack_id = *(data + 0);
pack_data = (data + 2);
// pack The last two bytes of are crc value , there len Is in accordance with the 1 Calculated , So when you press array , To reduce more 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:%x\r\n",rx_crc, cal_crc);
if (rx_crc != cal_crc)
{
//LOG("UP^FAIL,%d,R:%x,C:%x,L:%d\r\n", E_CRC, rx_crc, cal_crc, pack_len);
LOG("UP^FAIL,CRC1\r\n");
return;
}
// Receiving data for the first time , Then erase flash
if (dfu_file_info.flash_flag == false && dfu_file_info.file_size != 0)
{
dfu_file_info.flash_flag = true;
// If the firmware size < APP Half the capacity , Use backup to upgrade
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,%d\r\n", 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,%d\r\n", 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,FILE\r\n");
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 %x\r\n", cal_crc, dfu_file_info.file_crc16);
LOG("UP^FAIL,CRC\r\n");
}
else
{
LOG("UP^OK,UP\r\n");
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);
}
// Jump start
sys_reset();
}
}
static void dfu_data_analysis(uint8_t *data, uint16_t len)
{
data[len] = '\0';
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;
}
// Get the verification value sent by the upper computer
uid_crc = (*data) << 8 | (*(data + 1));
g_boot_info.boot_state = BOOT_STATE_RUN_APP;
g_boot_info.chip_lock = uid_crc; // Fill in the special code to unlock the burning
kv_set_env(BS_KV_KEY_BOOT_INFO, (uint8_t *)&g_boot_info, sizeof(boot_info_t));
// Judge whether the upper computer's verification value matches its own verification value
if (g_cal_crc == uid_crc)
{
LOG("AT^OK,UNLOCK\r\n");
delay_ms(5);
sys_reset();
}
else
{
#if !DEBUG_MODE
// close SWD function To configure PC7 and PD1 Terminal function mode Peripheral module function mode enable
RCC->UNLOCK = 0x55AA6699;
RCC->SWDIOCR = (0x5A69 << RCC_SWDIOCR_KEY_Pos);
RCC->UNLOCK = 0x55AA6698;
LOG("AT^OK,LOCK\r\n");
#else
LOG("AT^OK,LOCK,%04x|%04x\r\n", 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 mode\r\n");
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);
}
/* Public Function Prototypes -----------------------------------------------*/
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,%04x\r\n", 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)
{
// Timeout mechanism
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 Pattern The indicator flashes
bsp_gpio_set_toggle(BS_LED0_GPIO_PORT, BS_LED0_PIN);
}
if (!g_dfu_timeout_flag)
{
// boot Mode for self destructing
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();
}
}
/******************************************************************************** * @file dfu.h * @author jianqiang.xue * @version V1.0.0 * @date 2021-04-09 * @brief NULL ********************************************************************************/
#ifndef __DFU_H
#define __DFU_H
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
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;
/* Public Function Prototypes ------------------------------------------------*/
void dfu_main(void);
#endif
边栏推荐
- 相同的树[从部分到整体]
- 二叉树的层序遍历 II[层序遍历方式之一 ->递归遍历 + level]
- 初探元宇宙存储,数据存储市场下一个爆点?
- 高性能限流器 Guava RateLimiter
- DevOps笔记-05:IT行业中BA、SM、PO、PM、PD、Dev、Ops、QA都是什么角色
- Digital twin application of smart Park Based on Web GIS aerial photography
- Gartner“客户之声”最高分,用户体验成中国数据库一大突破口
- Gartner's "voice of customers" has the highest score, and the user experience has become a major breakthrough for China's database
- Different binary search trees [bottom-up backtracking spanning tree + memory search -- space for time]
- 深度解析“链动2+1”模式的商业逻辑
猜你喜欢

High performance current limiter guava ratelimiter

【TcaplusDB知识库】TcaplusDB-tcaplusadmin工具介绍

88.(cesium篇)cesium聚合图

Set hardware breakpoint instruction for ejtag under the PMON of the Godson development board

seekbar 自定义图片上下左右显示不全 / bitmapToDrawable / bitmapToDrawable互转 / paddingStart/paddingEnd /thumbOffset

go实现分布式锁

MySQL advanced SQL statement (Part 2)

分享 60 个神级 VS Code 插件

Gartner's "voice of customers" has the highest score, and the user experience has become a major breakthrough for China's database

【资料上新】基于3568开发板的NPU开发资料全面升级
随机推荐
【TcaplusDB知识库】查看tcapdir目录服务器
Linear and nonlinear structures
Django model generates docx database design documents
87.(cesium篇)cesium热力图(贴地形)
88.(cesium篇)cesium聚合图
分布式id解决方案
[thread communication]
Supplement to the scheme of gateway+nacos+knife4j (swagger)
Restore the binary search tree [simulate according to the meaning of the question - > find the problem - > analyze the problem - > see the bidding]
The four traversal methods of the map set can be seen at a glance
How to keep source code secret in embedded development
Yyds dry inventory everything a primary developer should know about activity
【TcaplusDB知识库】TcaplusDB-tcapsvrmgr工具介绍(一)
Do you feel confused when you study at three in the morning?
[Ubuntu] [MySQL] Ubuntu installs mysql, but the compilation error is mysql h: No such file or directory
【TcaplusDB知识库】TcaplusDB-tcapsvrmgr工具介绍(三)
87.(cesium篇)cesium热力图(贴地形)
vim配置与使用
SSH无密码登陆
Probe into metacosmic storage, the next explosive point in the data storage market?