1181 lines
34 KiB
C
1181 lines
34 KiB
C
|
||
|
||
#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_UART2, 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);
|
||
}
|
||
|
||
|
||
|
||
|
||
|