Files
2025-09-17 09:11:22 +08:00

1181 lines
34 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "app.h"
extern void MX_DMA_DeInit (void);
extern void MX_USART_DeInit (void);
struct recv_data_t {
uint8_t bufRx[YM_MSG_SIZE_MAX + 16]; /* 设备底层数据接收缓存区 */
uint16_t lenRx; /* 指示缓存区接收到的数据量,单位 byte */
uint8_t isUpkHead; /* 是否为固件包头的标志位 */
uint8_t dataHdr[UPK_HEAD_SIZE]; /* 暂存固件包头信息 */
uint8_t dataPkg[YM_BODY_SIZE_MAX]; /* 暂存固件包体数据 */
uint16_t lenPkg; /* 固件包体大小,包含两个字节的数据长度 */
};
static struct recv_data_t gRecv;
static struct drv_timer_t timerLed; /* LED 的闪烁 timer */
static struct drv_timer_t timerWait; /* 检测主机数据发送超时的 timer */
#if (ENABLE_FACTORY_FIRMWARE_BUTTON)
static struct drv_timer_t timerKey; /* 用于按键扫描的 timer */
static struct BSP_KEY keyRecovery; /* 用于恢复出厂固件的按键 */
#endif
static struct transfer_t fdUart; /* 数据传输的接口 */
static struct upgrade_t gUP;
static void timerLedFlashCallback (void *user_data)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
printf(".");
}
static void timerWaitDataTimeoutCallback (void *user_data)
{
gUP.flow = EXE_FLOW_FIND_RUNNING_FIRMWARE;
printf(" time over ");
}
/**
* @brief 跳转至APP的处理函数
* @note 若选择直接跳转至 APP ,则需要注意使用到的外设要进行 deinit ,否则会对 APP 的运行有影响
* @retval None
*/
static void boot_JumpToAPP (void)
{
static uint32_t _stack_addr; /* APP 栈顶地址 */
static uint32_t _reset_handler; /* APP reset handler 地址 */
typedef void(*APP_MAIN_FUNC)(void);
APP_MAIN_FUNC APP_Main;
_stack_addr = *(volatile uint32_t *)BASE_APPLICATION;
_reset_handler = *(volatile uint32_t *)(BASE_APPLICATION + 4);
/* 设置所有时钟到默认状态,使用HSI时钟 */
HAL_RCC_DeInit();
/* 关闭全局中断 */
__disable_irq();
/* 关闭滴答定时器,复位到默认值 */
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
/* 关闭所有中断,清除所有中断挂起标志 */
for (uint8_t i = 0; i < 8; i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
/* 外设 deinit */
HAL_DeInit();
MX_USART_DeInit();
MX_DMA_DeInit();
/* 设置主堆栈指针 */
__set_MSP(_stack_addr);
/* 在 RTOS 工程,这条语句很重要,设置为特权级模式,使用 MSP 指针 */
__set_CONTROL(0);
/* 设置中断向量表 */
SCB->VTOR = BASE_APPLICATION;
/* 跳转到 APP ,首地址是 MSP ,地址 +4 是复位中断服务程序地址 */
APP_Main = (APP_MAIN_FUNC)_reset_handler;
APP_Main();
/* 复位或跳转成功的话,不会执行到这里 */
while (1) {
}
}
/**
* @brief 回复指令的执行情况,协议会自动组包
* @note 根据当前执行的指令和执行情况,发送对应数据
* @param[in] cmd: 正在执行的指令
* @param[out] result: 指令执行结果
* @param[out] data: 需要响应的数据
* @param[out] data_len: 需要响应的数据长度,单位 byte
* @retval None
*/
static void boot_SetReplyInfo (eYmCMD cmd, eRESULT *result, uint8_t *data, uint16_t *data_len)
{
*result = gUP.result;
if ((gUP.result == YM_RESULT_CANCEL)||(gUP.result == YM_RESULT_FAILED)) {
printf("errCode: %.2X\r\n", gUP.errCode);
}
}
/**
* @brief 负责接收协议解析出来的数据
* @note 通过协议的指令包,设置程序的执行流程
* @param[in] cmd: 接收到的指令
* @param[in] data: 接收到的参数
* @param[in] data_len: 接收到的参数长度,单位 byte
* @retval None
*/
static void boot_ProtocolDataHandle (eYmCMD cmd, uint8_t *data, uint16_t data_len)
{
static uint8_t eot_flag = 0;
gUP.result = YM_RESULT_PROCESS;
switch (cmd) {
case YM_CMD_SOH:
case YM_CMD_STX: {
/* 重置 timer 为等待主机下发固件包的定时器 */
drv_timer_pause(&timerWait);
drv_timer_init(&timerWait,
timerWaitDataTimeoutCallback,
(10 * 1000),
TIMER_RUN_FOREVER);
drv_timer_start(&timerWait);
/* 最后一个 SOH 空数据帧 */
if (eot_flag && cmd == YM_CMD_SOH) {
eot_flag = 0;
gUP.result = YM_RESULT_OK;
gUP.flow = EXE_FLOW_UPDATE_FIRMWARE;
break;
}
/* 正常数据帧的处理 */
gUP.state = BOOT_STATUS_ENTER_UPDATE_MODE;
/* 拷贝数据 */
gRecv.lenPkg = data_len;
memcpy(gRecv.dataPkg, data, gRecv.lenPkg);
/* 第一个 SOH 数据帧,包含文件名和文件大小等信息 */
if ((cmd == YM_CMD_SOH) && (gUP.start == 0)) {
gUP.start = 1;
char *file_name = (char *)gRecv.dataPkg;
char *file_size = (char *)&gRecv.dataPkg[strlen(file_name) + 1];
printf("\r\nupk file : '%s' length : %d\r\n", file_name, atoi(file_size));
gUP.result = YM_RESULT_OK;
break;
}
/* 固件包头,单独处理 */
if (gRecv.isUpkHead == 0) {
gRecv.isUpkHead = 1;
memcpy(&gRecv.dataHdr[0], &data[0], UPK_HEAD_SIZE);
gUP.flow = EXE_FLOW_VERIFY_FIRMWARE_HEAD;
} else { /* 固件包体 */
gUP.flow = EXE_FLOW_VERIFY_FIRMWARE_PKG;
}
break;
}
case YM_CMD_EOT: {
eot_flag = 1;
gUP.result = YM_RESULT_OK;
break;
}
case YM_CMD_CAN: {
eot_flag = 0;
gRecv.isUpkHead = 0;
gUP.result = YM_RESULT_OK;
gUP.flow = EXE_FLOW_FIND_RUNNING_FIRMWARE;
break;
}
default: {
gUP.result = YM_RESULT_OK;
break;
}
}
}
static void sendDataHandler (uint8_t *data, uint16_t len, uint32_t timeout)
{
DT_Send(&fdUart, data, len);
}
static void recvDataHandler (void)
{
/* 轮询方式,防止应用阻塞 */
if (DT_PollingReceive(&fdUart) == X_RESULT_RECV_FRAME) {
drv_timer_restart(&timerWait);
/* 调用协议析构层的处理函数并将接收到的一帧数据导入 */
if (ymodemHandler(gRecv.bufRx, gRecv.lenRx) != ERR_OK) {
ymodemConfig(YM_MODE_RESET, NULL);
//printf("uart recv len: %d\r\n", gRecv.lenRx);
}
gRecv.lenRx = 0;
} else {
ymodemHandler(NULL, 0);
}
}
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
/**
* @brief 自动更新固件的处理函数
* @note
* @param[in] part_name: 固件所在的分区名
* @retval eErrCode
*/
static eErrCode boot_AutoUpdate (const char *part_name)
{
static uint8_t value = 0;
eErrCode result = ERR_OK;
/* 设置为正在意外更新固件的状态 */
gUP.state = BOOT_STATUS_ACCIDENT_UPDATE;
/* 禁止接收主机的指令 */
ymodemConfig(YM_MODE_RECV, &value);
/* 读取固件包头 */
result = FM_ReadFirmwareHead(part_name);
if (result != ERR_OK) {
//printf("%s: err: %d\r\n", __func__, __LINE__);
return result;
}
/* 校验固件正确性 */
printf("%s:%d - %s\r\n", __func__, __LINE__, part_name);
result = FM_VerifyFirmware(part_name, FM_GetPackageCRC32(), 0);
if (result != ERR_OK) {
//p_Printf("%s: err: %d\r\n", __func__, __LINE__);
return result;
}
/* 检测 APP 分区是否为空,不为空时擦除分区 */
result = FM_IsEmpty(NAME_PART_APPLICATION);
if (result != ERR_OK) {
//printf("%s: app is not empty\r\n", __func__);
result = FM_EraseFirmware(NAME_PART_APPLICATION);
}
/* 将固件更新至 APP 分区 */
result = FM_UpdateToAPP(part_name);
if (result != ERR_OK) {
//printf("%s: err: %d\r\n", __func__, __LINE__);
return result;
}
/* 校验 APP 分区的固件 */
printf("%s:%d - %s\r\n", __func__, __LINE__, NAME_PART_APPLICATION);
result = FM_VerifyFirmware(NAME_PART_APPLICATION, FM_GetRawCRC32(), 1);
if (result != ERR_OK) {
//printf("%s: err: %d\r\n", __func__, __LINE__);
return result;
}
#if ((CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD)||(CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP))
/* 记录固件版本在 flash 的方案,需更新记录的固件版本 */
result = FM_UpdateFirmwareVersion(part_name);
#endif
/* 将剩余的数据写入 APP 分区 */
result = FM_WriteFirmwareDone(NAME_PART_APPLICATION);
#if (CONFIG_AUTO_UPDATE_MODE == MODE_CLEAR_DOWNLOAD_PART)
/* 擦除 download 分区的方案,需直接擦除 */
result = FM_EraseFirmware(part_name);
#endif
//if (result != ERR_OK) {
// printf("%s: err: %d\r\n", __func__, __LINE__);}
return result;
}
/**
* @brief 检查各分区是否有可用的固件
* @note bit2: APP 分区。bit1: download 分区。bit0: factory 分区
* @retval 0: 无固件。1: 有固件
*/
static uint8_t boot_CheckFirmware (void)
{
uint8_t fw_sta = 0;
fw_sta = (!FM_CheckFirmwareIntegrity(BASE_APPLICATION) << 2);
fw_sta |= (!FM_CheckFirmwareIntegrity(BASE_DOWNLOAD) << 1);
if (BASE_FACTORY) {
fw_sta |= !FM_CheckFirmwareIntegrity(BASE_FACTORY);
}
printf("\r\n");
return fw_sta;
}
/**
* @brief 固件的检查和处理函数
* @note 上电时检查 或 更新失败时检查,执行的优先级低于主机指令,因此需确认主机不需要更新固件时才可执行
* @retval None
*/
static void boot_CheckAndHandle (void)
{
uint8_t is_try_auto_update = 0;
uint8_t fw_sta = boot_CheckFirmware();
/* 本函数的处理逻辑较复杂。为了提高执行效率,减少资源占用,使用了 goto 。
\\ 阅读时建议结合《固件检测和处理机制》文档查看 */
/* 没有任何可用的固件 */
if (fw_sta == 0) {
gUP.state = BOOT_STATUS_NO_FIRMWARE;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
}
#if (CONFIG_AUTO_UPDATE_MODE)
/* download 分区有固件 */
if ((fw_sta & 0x02) == 0x02) {
#if (CONFIG_AUTO_UPDATE_MODE == MODE_CLEAR_DOWNLOAD_PART)
/* 本方案是检测到 download 分区有可用固件则开始自动更新 */
if (boot_AutoUpdate(NAME_PART_DOWNLOAD)) {
is_try_auto_update = 1;
goto __check_app;
} else {
goto __jump_to_app;
}
#elif ((CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD)||(CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP))
/* 本方案是检测 download 分区固件包头的版本信息,以判断是否需要自动更新 */
/* 读固件包头 */
gUP.errCode = FM_ReadFirmwareHead(NAME_PART_DOWNLOAD);
if (gUP.errCode != ERR_OK) {
goto __check_app;
}
/* 需要自动更新 */
if (FM_IsNeedAutoUpdate()) {
if (boot_AutoUpdate(NAME_PART_DOWNLOAD)) {
is_try_auto_update = 1;
goto __check_app;
} else {
goto __jump_to_app;
}
}
#endif
}
#endif
__check_app:
/* APP 分区有固件 */
if ((fw_sta & 0x04) == 0x04) {
#if (CONFIG_CHECK_APP_SECURITY)
/* 启用 APP 固件检查 且 download 分区有固件 */
if ((fw_sta & 0x02) == 0x02) {
/* 读固件包头 */
gUP.errCode = FM_ReadFirmwareHead(NAME_PART_DOWNLOAD);
#if ((CONFIG_CHECK_APP_SECURITY == AUTO_UPDATE_APP)||(CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY))
/* 启用 APP 固件检查的自动更新方案,则跳转至检查 download 分区固件 */
if (gUP.errCode != ERR_OK) {
goto __check_download;
}
#else
/* 未启用 APP 固件检查的自动更新方案,则不继续执行,报错即可 */
if (gUP.errCode != ERR_OK) {
/* 设置为读取 download 分区失败的状态 */
gUP.state = BOOT_STATUS_READ_PART_ERR;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
}
#endif
/* 校验 APP 固件 */
printf("%s:%d - %s\r\n", __func__, __LINE__, NAME_PART_APPLICATION);
gUP.errCode = FM_VerifyFirmware(NAME_PART_APPLICATION, FM_GetRawCRC32(), 0);
#if ((CONFIG_CHECK_APP_SECURITY == AUTO_UPDATE_APP)||(CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY))
/* 启用 APP 固件检查的自动更新方案,则跳转至检查 download 分区固件 */
if (gUP.errCode != ERR_OK) {
goto __check_download;
}
#else
/* 未启用 APP 固件检查的自动更新方案,则不继续执行,报错即可 */
if (gUP.errCode != ERR_OK) {
/* 设置为 APP 固件校验失败的状态 */
gUP.state = BOOT_STATUS_APP_VERIFY_ERR;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
}
#endif
/* 到这一步,说明 APP 校验成功 */
goto __jump_to_app;
}
#if (CONFIG_CHIP_PARTS == USE_TRIPLE_PARTITION)
/* 启用 APP 固件检查的自动更新方案 且 download 分区无固件 */
else {
/* factory 分区有固件 */
if ((fw_sta & 0x01) == 0x01) {
/* 读固件包头 */
gUP.errCode = FM_ReadFirmwareHead(NAME_PART_FACTORY);
#if ((CONFIG_CHECK_APP_SECURITY == AUTO_UPDATE_APP)||(CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY))
/* 启用 APP 固件检查的自动更新方案,则跳转至检查 factory 分区固件 */
if (gUP.errCode != ERR_OK) {
goto __check_factory;
}
#else
/* 未启用 APP 固件检查的自动更新方案,则不继续执行,报错即可 */
if (gUP.errCode != ERR_OK) {
/* 设置为读取 factory 分区失败的状态 */
gUP.state = BOOT_STATUS_READ_PART_ERR;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
}
#endif
/* 校验 APP 固件 */
printf("%s:%d - %s\r\n", __func__, __LINE__, NAME_PART_APPLICATION);
gUP.errCode = FM_VerifyFirmware(NAME_PART_APPLICATION, FM_GetRawCRC32(), 0);
#if ((CONFIG_CHECK_APP_SECURITY == AUTO_UPDATE_APP)||(CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY))
/* 启用 APP 固件检查的自动更新方案,则跳转至检查 factory 分区固件 */
if (gUP.errCode != ERR_OK) {
goto __check_factory;
}
#else
/* 未启用 APP 固件检查的自动更新方案,则不继续执行,报错即可 */
if (gUP.errCode != ERR_OK) {
/* 设置为 APP 固件校验失败的状态 */
gUP.state = BOOT_STATUS_APP_VERIFY_ERR;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
}
#endif
/* 到这一步,说明 APP 校验成功 */
goto __jump_to_app;
} else { /* 启用 APP 固件检查 且 download 分区无固件 且 factory 分区无固件 */
#if (CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY)
goto __jump_to_app;
#else
/* 设置为 APP 固件为无法检查的状态 */
gUP.state = BOOT_STATUS_APP_CAN_NOT_VERIFY;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
#endif
}
}
#else
/* 不是三分区方案 */
/* 启用 APP 固件检查 且 download 分区无固件 */
#if (CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY)
goto __jump_to_app;
#else
/* 设置为 APP 固件为无法检查的状态 */
gUP.state = BOOT_STATUS_APP_CAN_NOT_VERIFY;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
#endif
#endif /* #if (CONFIG_CHIP_PARTS == USE_TRIPLE_PARTITION) */
#else
/* APP 分区有固件 且 未启用 APP 固件检查 */
goto __jump_to_app;
#endif /* #if (CONFIG_CHECK_APP_SECURITY) */
}
#if (CONFIG_AUTO_UPDATE_MODE == MODE_NOT_AUTO_UPDATE)
/* APP 分区无固件 且 未启用自动更新 */
else {
/* 设置为 APP 固件异常的状态 */
gUP.state = BOOT_STATUS_NO_APP;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
}
#endif
__check_download:
/* 执行到此处,意味着已经发生以下情况:
* APP 没有固件 或 校验不通过 或 APP 的自动更新失败
*/
/* 还未执行过自动更新 */
if (is_try_auto_update == 0) {
#if (CONFIG_AUTO_UPDATE_MODE&&((CONFIG_CHECK_APP_SECURITY==AUTO_UPDATE_APP)||(CONFIG_CHECK_APP_SECURITY==CHECK_UNLESS_EMPTY)))
/* 启用自动更新 且 download 分区有固件 */
if ((fw_sta & 0x02) == 0x02) {
if (boot_AutoUpdate(NAME_PART_DOWNLOAD)) {
goto __check_factory;
} else {
goto __jump_to_app;
}
}
#if (CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY)
/* 启用自动更新 但 download 分区没有固件 */
else {
goto __check_factory;
}
#endif
#else
/* 未启用自动更新 */
/* 设置为缺失 APP 固件的状态 */
gUP.state = BOOT_STATUS_NO_APP;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
#endif
}
__check_factory:
/* 执行到此处,意味着已经发生以下情况:
* 1. APP 没有固件 或 校验不通过 或 APP 的自动更新失败
* 2. download 分区没有可用的固件 或 download 分区固件包更新至 APP 失败
*/
#if (CONFIG_FACTORY_RESTORE)
/* 可以使用 factory 的固件 */
/* factory 分区有固件 */
if ((fw_sta & 0x01) == 0x01) {
if (boot_AutoUpdate(NAME_PART_FACTORY) == ERR_OK) {
goto __jump_to_app;
}
}
#endif
#if (CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY)
/* 运行到这里,说明 download 分区和 factory 分区无可用的固件 */
/* 若 APP 分区有固件,则跳转 */
if ((fw_sta & 0x04) == 0x04) {
goto __jump_to_app;
} else {
/* 设置为需主机发送固件的状态 */
gUP.state = BOOT_STATUS_AUTO_UPDATE_FAILED;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
}
#else
/* 设置为需主机发送固件的状态 */
gUP.state = BOOT_STATUS_AUTO_UPDATE_FAILED;
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
return;
#endif
__jump_to_app:
printf("Jump to 'app'. bye~\r\n\r\n");
boot_JumpToAPP();
}
#endif /* #if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION) */
#if (ENABLE_FACTORY_FIRMWARE_BUTTON)
/**
* @brief 按键的事件处理
* @note
* @param[in] id: 按键的 ID
* @param[in] event: 按键的事件
* @retval None
*/
static void keyEventCallback (uint8_t id, KEY_EVENT event)
{
printf("[ key ] You just press the button[%d], event: %d\r\n\r\n", id, event);
if (event == KEY_LONG_PRESS)
{
if (gUP.flow == EXE_FLOW_NOTHING
|| gUP.flow == EXE_FLOW_NEED_HOST_SEND_FIRMWARE
|| gUP.flow == EXE_FLOW_FIND_RUNNING_FIRMWARE
|| gUP.flow == EXE_FLOW_JUMP_TO_APP
|| gUP.flow == EXE_FLOW_FAILED) {
gUP.flow = EXE_FLOW_RECOVERY;
}
}
}
/**
* @brief 读取按键的电平值
* @note
* @retval 电平值
*/
static uint8_t keyGetLevel(void)
{
return HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin);
}
/**
* @brief 扫描按键的任务
* @note
* @param[in] user_data: 用户数据
* @retval None
*/
static void timerScanKeyCallback(void *user_data)
{
BSP_Key_Handler(2);
}
#endif /* #if (ENABLE_FACTORY_FIRMWARE_BUTTON) */
/**
* @brief 外设初始化前的一些处理
* @note 执行到此处,内核时钟已初始化
* @retval None
*/
void System_Init (void)
{
/* TODO: 此处的 ASSERT 最佳实现方式应为编译阶段即可报错,但尚未找到方法 */
ASSERT(CONFIG_CHIP_PARTS >= USE_SINGLE_PARTITION && CONFIG_CHIP_PARTS <= USE_TRIPLE_PARTITION);
ASSERT(sizeof(AES256_KEY) != 32);
ASSERT(sizeof(AES256_IV) != 16);
ASSERT((CONFIG_AUTO_UPDATE_MODE >= MODE_NOT_AUTO_UPDATE)
&&(CONFIG_AUTO_UPDATE_MODE <= MODE_UPDATE_DOWNLOAD_HEAD));
ASSERT((CONFIG_CHECK_APP_SECURITY >= DO_NOT_CHECK)
&&(CONFIG_CHECK_APP_SECURITY <= DO_NOT_DO_ANYTHING));
ASSERT(ONCHIP_FLASH_ERASE_GRANULARITY > 0);
ASSERT(SIZE_ONCHIP_FLASH > 0);
ASSERT(SIZE_PART_APPLICATION > 0);
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
ASSERT(SIZE_PART_DOWNLOAD > 0);
#endif
#if (CONFIG_CHIP_PARTS > USE_DOUBLE_PARTITION)
ASSERT(SIZE_PART_FACTORY > 0);
#endif
ASSERT(CONFIG_TIMEOUT_HOST_START > 1000);
}
/**
* @brief 应用初始化
* @note 此时外设已经初始化完毕
* @retval None
*/
void APP_Init (void)
{
#if (ENABLE_FACTORY_FIRMWARE_BUTTON)
BSP_Key_Init(&keyRecovery, 0, keyGetLevel, FACTORY_FIRMWARE_BUTTON_PRESS);
BSP_Key_Register(&keyRecovery, KEY_LONG_PRESS, keyEventCallback);
BSP_Key_Start(&keyRecovery);
drv_timer_init(&timerKey,
timerScanKeyCallback,
2,
TIMER_RUN_FOREVER);
drv_timer_start(&timerKey);
#endif
// led blink @ 5 Hz
drv_timer_init(&timerLed,
timerLedFlashCallback,
100,
TIMER_RUN_FOREVER);
drv_timer_start(&timerLed);
// 5s -> 30s
drv_timer_init(&timerWait,
timerWaitDataTimeoutCallback,
CONFIG_TIMEOUT_HOST_START,
TIMER_RUN_FOREVER);
drv_timer_start(&timerWait);
DT_Init(&fdUart, BSP_UART1, gRecv.bufRx, &gRecv.lenRx, YM_MSG_SIZE_MAX + 16);
ymodem_init(sendDataHandler, boot_ProtocolDataHandle, boot_SetReplyInfo);
FM_Init();
}
void APP_Running (void)
{
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
/* 记录当前操作的固件分区 */
char *part_name = NULL;
#endif
while (1) {
recvDataHandler();
switch (gUP.flow) {
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
/* 无须更新固件 或 更新固件过程中等待主机指令超时 或 更新失败时 的处理逻辑 */
case EXE_FLOW_FIND_RUNNING_FIRMWARE: {
boot_CheckAndHandle();
break;
}
#else
/* 单分区 */
case EXE_FLOW_FIND_RUNNING_FIRMWARE:
case EXE_FLOW_JUMP_TO_APP: {
if (FM_CheckFirmwareIntegrity(BASE_APPLICATION) == ERR_OK) {
printf("\r\nJump to 'app'. bye~\r\n\r\n");
boot_JumpToAPP();
} else {
printf("\r\nNo app, waiting for yModem ");
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
}
break;
}
#endif
/* 暂存和校验固件包头的流程,此时,已进入固件更新的开始阶段 */
case EXE_FLOW_VERIFY_FIRMWARE_HEAD: {
gUP.errCode = ERR_OK;
/* 取出固件包头中的分区名 */
struct upk_head_t *pHdr = (struct upk_head_t *)gRecv.dataHdr;
part_name = pHdr->part_name;
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
#if (CONFIG_AUTO_CORRECT)
/* 自动将固件包指定的 APP 分区修正为 download 分区 */
if (strncmp(part_name, NAME_PART_APPLICATION, MAX_NAME_LEN) == 0)
part_name = NAME_PART_DOWNLOAD;
#else
/* 固件包指定的存放分区合法性检查,多分区方案时,不能指定放在 APP 分区 */
if (strncmp(part_name, NAME_PART_APPLICATION, MAX_NAME_LEN) == 0) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
gUP.errCode = ERR_CAN_NOT_PLACE_IN_APP;
break;
}
#endif
#endif
/* 检测固件包是否超过了分区大小 */
#if (CONFIG_CHECK_SIZE)
#if (CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP)
if (pHdr->raw_size > (SIZE_PART_APPLICATION - UPK_VERSION_SIZE))
#else
if (pHdr->raw_size > SIZE_PART_APPLICATION)
#endif
{
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
gUP.errCode = ERR_FIRMWARE_OVERSIZE;
printf("over size > %lu\r\n", SIZE_PART_APPLICATION - UPK_VERSION_SIZE);
break;
}
#if (CONFIG_CHIP_PARTS == USE_DOUBLE_PARTITION)
if (pHdr->pkg_size > SIZE_PART_DOWNLOAD) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
gUP.errCode = ERR_FIRMWARE_OVERSIZE;
break;
}
#elif (CONFIG_CHIP_PARTS == USE_TRIPLE_PARTITION)
if (strncmp(part_name, NAME_PART_DOWNLOAD, MAX_NAME_LEN) == 0) {
if (pHdr->pkg_size > SIZE_PART_DOWNLOAD) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
gUP.errCode = ERR_FIRMWARE_OVERSIZE;
break;
}
} else if (strncmp(part_name, NAME_PART_FACTORY, MAX_NAME_LEN) == 0) {
#if (CONFIG_CHIP_PARTS == USE_TRIPLE_PARTITION)
if (pHdr->pkg_size > SIZE_PART_FACTORY) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
gUP.errCode = ERR_FIRMWARE_OVERSIZE;
break;
}
#else
/* 双分区的方案不可能存在 factory 分区 */
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
gUP.errCode = ERR_DOES_NOT_EXIST_FACTORY;
break;
#endif
}
#endif
#endif
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
/* 因单分区的方案无视固件包指定的分区,因此不需要判断分区存不存在 */
gUP.errCode = FM_StorageFirmwareHead(NAME_PART_APPLICATION, gRecv.dataHdr);
#else
/* 暂存固件包头 */
gUP.errCode = FM_StorageFirmwareHead(part_name, gRecv.dataHdr);
#endif
if (gUP.errCode == ERR_OK) {
gUP.flow = EXE_FLOW_ERASE_OLD_FIRMWARE;
printf("upgrade start ==>\r\n");
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
}
break;
}
/* 单分区: 擦除 APP 固件。多分区: 将需要放入固件的分区擦除 */
case EXE_FLOW_ERASE_OLD_FIRMWARE: {
/* 判断分区是否为空 */
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.errCode = FM_IsEmpty(NAME_PART_APPLICATION);
#else
gUP.errCode = FM_IsEmpty(part_name);
#endif
if (gUP.errCode == ERR_OK) {
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.result = YM_RESULT_OK;
gUP.flow = EXE_FLOW_ERASE_OLD_FIRMWARE_DONE;
#else
gUP.flow = EXE_FLOW_WRITE_FIRMWARE_HEAD;
#endif
printf("Empty part.\r\n");
break;
} else if (gUP.errCode != ERR_FLASH_NO_EMPTY) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
printf("Part read failed.\r\n");
break;
}
printf("Erasing ... ");
/* 分区不为空时才擦除 */
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.errCode = FM_EraseFirmware(NAME_PART_APPLICATION);
#else
gUP.errCode = FM_EraseFirmware(part_name);
#endif
if (gUP.errCode == ERR_OK) {
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.result = YM_RESULT_OK;
gUP.flow = EXE_FLOW_ERASE_OLD_FIRMWARE_DONE;
#else
gUP.flow = EXE_FLOW_WRITE_FIRMWARE_HEAD;
#endif
printf("done.\r\n");
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
printf("failed.\r\n");
}
break;
}
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
/* 将固件包头写入 flash */
case EXE_FLOW_WRITE_FIRMWARE_HEAD: {
gUP.errCode = FM_WriteFirmwareSubPackage(part_name, gRecv.dataHdr, UPK_HEAD_SIZE);
if (gUP.errCode == ERR_OK) {
gUP.flow = EXE_FLOW_WRITE_FIRMWARE_HEAD_DONE;
gUP.result = YM_RESULT_OK;
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
printf("write failed.\r\n");
}
break;
}
#endif
/* 校验收到的固件分包的数据正确性。说明主机下发了固件分包 */
case EXE_FLOW_VERIFY_FIRMWARE_PKG: {
/* 因 YModem 协议已进行校验,因此这个流程跳过即可,直接进入下一步 */
gUP.flow = EXE_FLOW_WRITE_NEW_FIRMWARE;
break;
}
/* 将固件分包写入分区中 */
case EXE_FLOW_WRITE_NEW_FIRMWARE: {
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.errCode = FM_WriteFirmwareSubPackage(NAME_PART_APPLICATION, gRecv.dataPkg, gRecv.lenPkg);
#else
gUP.errCode = FM_WriteFirmwareSubPackage(part_name, gRecv.dataPkg, gRecv.lenPkg);
#endif
if (gUP.errCode == ERR_OK) {
gUP.flow = EXE_FLOW_WRITE_NEW_FIRMWARE_DONE;
gUP.result = YM_RESULT_OK;
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
printf("write failed.\r\n");
}
break;
}
/* 固件已接收完毕。此时将分区首地址的 4 个字节写入 */
case EXE_FLOW_UPDATE_FIRMWARE: {
printf("\r\nFirmware ... ");
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.errCode = FM_WriteFirmwareDone(NAME_PART_APPLICATION);
#else
gUP.errCode = FM_WriteFirmwareDone(part_name);
#endif
if (gUP.errCode == ERR_OK) {
gUP.progress = 0;
gUP.flow = EXE_FLOW_VERIFY_FIRMWARE;
printf("done.\r\n");
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
printf("failed.\r\n");
}
break;
}
/* 校验下载好的固件包体数据的正确性。单分区: 执行成功则 100% 完成,多分区: 执行成功则完成 25% */
/* 意外更新时,也从这个流程开始 */
case EXE_FLOW_ACCIDENT_UPDATE:
case EXE_FLOW_VERIFY_FIRMWARE: {
gUP.stage = STEP_VERIFY_FIRMWARE;
printf("Verifing ... \r\n");
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.stage = STEP_ERASE_DOWNLOAD;
gUP.errCode = FM_VerifyFirmware(NAME_PART_APPLICATION, FM_GetRawCRC32(), 0);
#else
/* 取出固件包头中的分区名 */
part_name = FM_GetPartName();
#if (CONFIG_AUTO_CORRECT)
/* 自动将固件包指定的 APP 分区修正为 download 分区 */
if (strncmp(part_name, NAME_PART_APPLICATION, MAX_NAME_LEN) == 0) {
part_name = NAME_PART_DOWNLOAD;
}
#else
/* 固件包指定的存放分区合法性检查,多分区方案时,不能指定放在 APP 分区 */
if (strncmp(part_name, NAME_PART_APPLICATION, MAX_NAME_LEN) == 0) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
gUP.errCode = ERR_CAN_NOT_PLACE_IN_APP;
break;
}
#endif
/* 校验固件 */
gUP.errCode = FM_VerifyFirmware(part_name, FM_GetPackageCRC32(), 0);
#endif
if (gUP.errCode == ERR_OK) {
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
gUP.progress = 100;
gUP.result = YM_RESULT_OK;
gUP.flow = EXE_FLOW_JUMP_TO_APP;
#else
gUP.progress = 20;
gUP.flow = EXE_FLOW_ERASE_APP;
#endif
printf("Verify ok.\r\n");
printf("upgrade done. <==\r\n");
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
printf("Verify failed.\r\n");
}
printf("%s: stage 1 !!!\r\n", __func__);
break;
}
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
/* 擦除 APP 分区的固件,准备写入新的固件 */
case EXE_FLOW_ERASE_APP: {
gUP.stage = STEP_ERASE_APP;
/* 判断 APP 分区是否为空 */
gUP.errCode = FM_IsEmpty(NAME_PART_APPLICATION);
if (gUP.errCode == ERR_OK) {
gUP.progress = 40;
gUP.flow = EXE_FLOW_UPDATE_TO_APP;
break;
} else if (gUP.errCode != ERR_FLASH_NO_EMPTY) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
break;
}
/* 为空时才擦除分区 */
gUP.errCode = FM_EraseFirmware(NAME_PART_APPLICATION);
if (gUP.errCode == ERR_OK) {
gUP.progress = 40;
gUP.flow = EXE_FLOW_UPDATE_TO_APP;
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
}
printf("%s: stage 2 !!!\r\n", __func__);
break;
}
/* 将新的固件写入 APP 分区中,边解密边写入 */
case EXE_FLOW_UPDATE_TO_APP: {
gUP.stage = STEP_UPDATE_TO_APP;
gUP.errCode = FM_UpdateToAPP(part_name);
if (gUP.errCode == ERR_OK) {
gUP.progress = 60;
gUP.flow = EXE_FLOW_VERIFY_APP;
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
}
printf("%s: stage 3 !!!\r\n", __func__);
break;
}
/* 校验 APP 分区的固件数据正确性 */
case EXE_FLOW_VERIFY_APP: {
gUP.stage = STEP_VERIFY_APP;
/* 因此时 APP 分区的首地址数据仍未写入,因此需要让 FM_VerifyFirmware 自动填充以进行校验 */
gUP.errCode = FM_VerifyFirmware(NAME_PART_APPLICATION, FM_GetRawCRC32(), 1);
if (gUP.errCode == ERR_OK) {
gUP.progress = 80;
gUP.flow = EXE_FLOW_UPDATE_TO_APP_DONE;
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
}
printf("%s: stage 4 !!!\r\n", __func__);
break;
}
/* 校验 APP 分区固件通过后,将剩余数据写入 */
case EXE_FLOW_UPDATE_TO_APP_DONE: {
#if ((CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD)||(CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP))
/* 更新记录的固件版本 */
gUP.errCode = FM_UpdateFirmwareVersion(part_name);
if (gUP.errCode != ERR_OK) {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
}
#endif
gUP.errCode = FM_WriteFirmwareDone(NAME_PART_APPLICATION);
if (gUP.errCode == ERR_OK) {
gUP.flow = EXE_FLOW_ERASE_DOWNLOAD;
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
}
break;
}
/* 擦除暂存固件的分区。如果是 factory 分区,则不需要擦除 */
case EXE_FLOW_ERASE_DOWNLOAD: {
gUP.stage = STEP_ERASE_DOWNLOAD;
if (strncmp(part_name, NAME_PART_FACTORY, MAX_NAME_LEN) == 0) {
gUP.errCode = ERR_OK;
} else {
#if (CONFIG_AUTO_UPDATE_MODE == MODE_CLEAR_DOWNLOAD_PART)
gUP.errCode = FM_EraseFirmware(part_name);
#else
gUP.errCode = ERR_OK;
#endif
}
if (gUP.errCode == ERR_OK) {
gUP.progress = 100;
gUP.result = YM_RESULT_OK;
gUP.state = BOOT_STATUS_UPDATE_SUCCESS;
gUP.flow = EXE_FLOW_JUMP_TO_APP;
} else {
gUP.flow = EXE_FLOW_FAILED;
gUP.result = YM_RESULT_CANCEL;
}
printf("%s: stage 5 !!!\r\n", __func__);
break;
}
/* 跳转至 APP */
case EXE_FLOW_JUMP_TO_APP: {
if (FM_CheckFirmwareIntegrity(BASE_APPLICATION) == ERR_OK) {
printf("\r\nmulty part : jump to 'app'. bye~\r\n\r\n");
boot_JumpToAPP();
} else {
gUP.flow = EXE_FLOW_NEED_HOST_SEND_FIRMWARE;
}
break;
}
#endif /* #if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION) */
/* 主机下发的恢复出厂固件的指令 或 APP 传递了需要恢复出厂固件的信息 */
case EXE_FLOW_RECOVERY: {
#if (CONFIG_CHIP_PARTS != USE_TRIPLE_PARTITION)
gUP.flow = EXE_FLOW_FIND_RUNNING_FIRMWARE;
gUP.result = YM_RESULT_FAILED;
gUP.errCode = ERR_DOES_NOT_EXIST_FACTORY;
#else
/* 检测 factory 是否有可用的固件 */
if ((boot_CheckFirmware() & 0x01) == 0) {
gUP.flow = EXE_FLOW_FIND_RUNNING_FIRMWARE;
gUP.result = YM_RESULT_FAILED;
gUP.errCode = ERR_NO_FACTORY_FIRMWARE;
break;
}
gUP.errCode = FM_ReadFirmwareHead(NAME_PART_FACTORY);
if (gUP.errCode == ERR_OK) {
gUP.flow = EXE_FLOW_VERIFY_FIRMWARE;
} else {
gUP.flow = EXE_FLOW_FIND_RUNNING_FIRMWARE;
gUP.result = YM_RESULT_FAILED;
}
#endif
break;
}
/* 固件更新失败的处理逻辑 */
case EXE_FLOW_FAILED: {
gRecv.isUpkHead = 0;
gUP.start = 0;
gUP.stage = STEP_VERIFY_FIRMWARE;
gUP.state = BOOT_STATUS_UPDATE_FAILED;
gUP.flow = EXE_FLOW_NOTHING;
printf("upgrade failed.\r\n");
break;
}
default:
break;
}
if (gUP.errCode != ERR_OK) {
printf(" errCode 0x%02X\n\r", gUP.errCode);
gUP.errCode = ERR_OK;
}
}
}
/**
* @brief 固件写入时的回调函数
* @note
* @param[in] progress: 进度(0-10000
* @retval None
*/
void Firmware_OperateCallback (uint16_t progress)
{
/* 更新固件更新进度百分比 */
gUP.progress = (gUP.stage * 20) + (progress / 500);
/* 处理主机的数据,防止阻塞 */
recvDataHandler();
//printf("%s: progress: %d\r\n", __func__, gUP.progress);
}
/**
* @brief 参数检查错误时的处理函数
* @note
* @param[in] func: 错误发生的所在函数
* @param[in] line: 错误发生的所在 c 文件的行数
* @retval None
*/
void Assert_Failed(uint8_t *func, uint32_t line)
{
printf("\r\n[ error ]: %s(%d)\r\n\r\n", func, line);
while (1);
}