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校验失败
按键驱动框架
按键相关数据结构




1](/mOTA%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/cf013621a512bb3691944f41d48a3ce2431d701a122d274e705495b604276b09.png)
按键状态机
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 许可协议。转载请注明来自 唐国林的个人博客!
