#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); }