/********************************************************************************
* @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 超时机制 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:%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的最后两个字节为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:%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;
}
// 第一次接到数据,则擦除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,%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);
}
// 跳转启动
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;
}
// 得到上位机发送的校验值
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,UNLOCK\r\n");
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,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)
{
// 超时机制
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();
}
}
/********************************************************************************
* @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