mOTA源码阅读笔记
先调用初始化函数,分别对数据传输
,传输协议
,固件管理
进行初始化
示例配置为 3 分区方案(APP + download + factory)
将片内 512K 的 Flash 划出 4 个 32K 的分区来,分别对应 Bootload,APP,download,factory
上电先检查标志位,如果标志为没有设为更新固件或恢复出厂。则将 Bootloader 执行流程设为查找固件并运行
flowchart LR app{"校检\nAPP区"} --> |Y| sp{应用程序SP\n是否指向\n片内RAM} sp -->|Y| ok(FM_ERR_OK); sp-->|N| err(FM_ERR_JUMP_TO_APP_ERR); app -->|N| fpk{检验\n下载区或\n恢复区} fpk -->|Y| check{"是否以\nfpk开头"} -->|Y| ok check -->|N| err fpk -->|N| err
flowchart LR id{"更新方式\n将Version信息\n写入APP区"} old_version("从APP区末尾的读取FPK信息\n将old_version存到\n_fpk_head.fw_old_ver中") check{"比较_fpk_head中\nfw_old_ver跟\nfw_new_ver\n是否相同"} id -->|Y| old_version --> check id -->|N| check check -->|相同| 不需更新 check -->|不同| 需要更新
重要的数据类型
classDiagram class FIRMWARE_UPDATE_INFO { + BOOT_STATUS status + BOOT_EXE_FLOW exe_flow + BOOT_UPDATE_STEP step + PP_CMD_EXE_RESULT cmd_exe_result + PP_CMD_ERR_CODE cmd_exe_err_code + uint8_t start + uint8_t total_progress } <> FIRMWARE_UPDATE_INFO class FPK_HEAD { + char name[4] + uint8_t cnfig[4] + char fw_old_ver[FPK_VERSION_SIZE] + char fw_new_ver[FPK_VERSION_SIZE] + char user_string[FPK_USER_STRING_SIZE] + char part_name[FPK_PART_NAME_SIZE] + uint32_t raw_size + uint32_t pkg_size + uint32_t raw_crc + uint32_t pkg_crc + uint32_t head_crc } < > FPK_HEAD
程序更新状态图
stateDiagram state "检查APP区" as __check_app state update <> state verify < > state "跳转至APP区运行" as __jump_to_app state "检查downlad区" as __check_download EXE_FLOW_FIND_RUNNING_FIRMWARE : 在APP、download、factory\n分区查找有无可以固件 EXE_FLOW_NEED_HOST_SEND_FIRMWARE : 需要主机发送固件 [*] --> EXE_FLOW_FIND_RUNNING_FIRMWARE EXE_FLOW_FIND_RUNNING_FIRMWARE --> EXE_FLOW_NEED_HOST_SEND_FIRMWARE : 所有分区\n都无有效固件 EXE_FLOW_FIND_RUNNING_FIRMWARE --> update : download区\n有固件 update --> __check_app: 需要\n更新固件 update --> __jump_to_app : 不需\n更新固件 __check_app --> verify verify --> __jump_to_app : APP区\nCRC校验通过 verify --> __check_download : APP区\nCRC校验失败
按键驱动框架
按键相关数据结构
按键状态机
stateDiagram state "初始状" as s0 state "第1次按键按下状态" as s1 state "已有1次单击事件发生状态" as s2 state "第2次按键按下过状态" as s3 state "按键处于长按状态" as s4 state KEY_CLICK_EVENT_WHEN_DBLCLICK <> state PRESS_TICK < > state PRESS_s2 < > s0 --> s1 : 有按键按下 s1 --> KEY_CLICK_EVENT_WHEN_DBLCLICK : 按键已释放 KEY_CLICK_EVENT_WHEN_DBLCLICK --> 触发单击事件处理 : 双击事件依旧\n触发单击事件 触发单击事件处理 --> s2 KEY_CLICK_EVENT_WHEN_DBLCLICK --> s2 : 双击事件\n不触发单击事件 s1 --> PRESS_TICK : 按键仍然处于按下状态 PRESS_TICK --> 触发长按事件处理 : 按下时间大于\n长按测试时间 PRESS_TICK --> 按下时间递增 : 按下时间小于等于\n长按测试时间 按下时间递增 --> s1 触发长按事件处理 --> s4 s4 --> s0 : 按键已释放 s4 --> s4 : 按键仍然牌按下状态 s2 --> 释放时间递增 : 按键处于释放状态 释放时间递增 --> PRESS_s2 s2 --> 触发双击事件处理 : 按键处于按下状态 PRESS_s2 --> 单击事件处理 : 释放时间大于\n双击间隔时间 PRESS_s2 --> s2 : 释放时间小于等于\n双击间隔时间 单击事件处理 --> s0 触发双击事件处理 --> s3 s3 --> s0 : 按键已释放 s3 --> s3 : 按键未释放
stateDiagram state "初始状态" as s0 state "第1次按下状态" as s1 state "第1次释放状态" as s2 state "第2次按下状态" as s3 state "长按按下状态" as s4 [*] --> s0 s0 --> s1 : 有键按下\n触发按键按下事件 s1 --> s4 : 按下时长大\n于长按时间\n触发长按事件 s4 --> s0 : 按键释放 s4 --> s4 : 按键未释放\n触发长按保持事件 s1 --> s2 : 按键释放 s2 --> s3 : 按键按下\n触发双击事件 s2 --> s0 : 超时按键未按下\n触发单击事件 s3 --> s0 : 按键释放 s3 --> s3 : 按键未释放
从上面状态图可以看出,该按键框架支持“按键首次按下”,“按键单击”,“按键双击”,“按键长按”,“按键长按并保持”5 种事件的处理
数据传输层
传输层相关的数据结构
classDiagram class DATA_TRANSFER { uint8_t if_id uint8_t *rx_buff uint16_t *rx_len uint32_t rx_buff_size }
重要的函数功能框图
DT_Init
数据传输层初始化
flowchart LR s("初台化\nDATA_TRANSFER\n结构体") subgraph DT_Port_Init %% direction TB id1("底层\n接口\n硬件\n初始\n化") id1 --> if1{"是否\n启用断帧\n检测"} id2("初始化\n断帧检测\n定时器") end if1 --> |Y| id2 --> e(返回) if1 --> |N| e s --> DT_Port_Init
底层接口硬件初始化
flowchart TB subgraph BSP_UART_Init direction LR s("根据DATA_TRANSFER\n中的if_id找到对应\nUART_STRUCT设备") s --> if1{是否\n已初始化} --> |Y| err(BSP_UART_ERR_NO_INIT) subgraph BSP_UART_Port_Init direction TB sub1("初始化全局\n接收回调函数指针\n_UART_RxCallback") sub2("初始化全局\n接收空闲回调函数指针\n_UART_RxIdleCallback") sub3("初始化全局\nDMA接收回调函数指针\n_UART_DMA_RxCallback") sub4("初始化全局\nDMA接收回调函数指针\n_UART_DMA_TxCallback") sub5("初始化UART_STRUCT\n设备中的handle结构体") sub6("如果使用DMA发送\n初始化DMA对象的父对象") sub1 --> sub2 --> sub3 --> sub4 --> sub5 --> sub6 end if1 --> |N| BSP_UART_Port_Init BSP_UART_Port_Init --> id1(设置UART_STRUCT\n为已初始化) id1 --> e(BSP_UART_ERR_OK) end id2("挂载用户数据到if_id对应的UART_STRUCT结构体中") subgraph BSP_UART_EnableReceive direction LR s2("初始化UART_STRUCT\n的接收缓冲区、大小、长度") subgraph BSP_UART_Port_EnableReceive sif1{"是否启用\nDMA接收"} --> |N| ss2_1("开启硬件\n接收中断") sif1 --> |Y| ss2_2("初始化DMA\n并开启对应中断") end s2 --> BSP_UART_Port_EnableReceive end BSP_UART_Init --> id2 --> BSP_UART_EnableReceive
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 唐国林的个人博客!