Countdown 模块
模块简介
Countdown 是一个倒计时管理模块,提供了多票源倒计时机制。该模块支持多个倒计时源(配网、网络错误、待机、OTA等),根据优先级自动选择活跃的倒计时,并在倒计时结束时自动进入深度睡眠模式。该模块封装了定时器管理和倒计时裁决逻辑,为上层应用提供统一的倒计时管理接口。
核心特性
多票源支持: 支持多个倒计时源同时存在
优先级管理: 根据优先级自动选择活跃倒计时
自动睡眠: 倒计时结束时自动进入深度睡眠
OTA 暂停: OTA 事件时自动暂停倒计时
灵活配置: 支持自定义各票源的倒计时时长
线程安全: 使用定时器机制,线程安全
模块架构
Countdown 模块架构如下:
应用层 (Application)
↓
Countdown API (countdown.h, countdown_app.h)
↓
倒计时裁决 (update_countdown)
↓
定时器管理 (start_countdown/stop_countdown)
↓
RTOS 定时器 (oneshot timer)
↓
深度睡眠 (Deep Sleep)
工作流程
倒计时更新流程
update_countdown() 详细流程:
1. 检查 OTA 暂停票
- 如果存在 OTA 票,停止倒计时并返回
↓
2. 遍历票源(按优先级)
- COUNTDOWN_TICKET_PROVISIONING (最高优先级)
- COUNTDOWN_TICKET_NETWORK_ERROR
- COUNTDOWN_TICKET_STANDBY (最低优先级)
↓
3. 选择第一个活跃的票源
- 检查 s_active_tickets 位掩码
↓
4. 应用倒计时
- 如果票源改变,停止旧定时器
- 启动新定时器,使用对应时长
↓
倒计时更新完成
倒计时启动流程
start_countdown() 详细流程:
1. 检查定时器状态
- 如果定时器未初始化,创建新定时器
- 如果定时器已存在,重新加载
↓
2. 初始化定时器
- rtos_init_oneshot_timer()
- 设置回调函数 CountdownCallback
↓
3. 启动定时器
- rtos_start_oneshot_timer()
- 或 rtos_oneshot_reload_timer_ex()
↓
定时器运行中
倒计时停止流程
stop_countdown() 详细流程:
1. 检查定时器状态
- rtos_is_oneshot_timer_init()
↓
2. 停止定时器
- 如果正在运行,调用 rtos_stop_oneshot_timer()
↓
3. 销毁定时器
- rtos_deinit_oneshot_timer()
↓
定时器已停止
倒计时到期处理
CountdownCallback() 回调流程:
1. 定时器到期触发回调
↓
2. 记录日志
- "Standy time is up, start enter deepsleep"
↓
3. 进入深度睡眠
- bk_reboot_ex(RESET_SOURCE_FORCE_DEEPSLEEP)
↓
系统进入深度睡眠
重要接口
倒计时控制接口
/**
* @brief 启动倒计时定时器
*
* 创建并启动一个单次定时器。当倒计时到期时,系统将自动进入深度睡眠模式。
* 如果定时器已存在,将使用新的超时值重新加载。
*
* @param time_ms 倒计时时长(毫秒)
*
* @note 当倒计时到期时,会触发强制深度睡眠 (RESET_SOURCE_FORCE_DEEPSLEEP)
*/
void start_countdown(uint32_t time_ms);
/**
* @brief 停止倒计时定时器
*
* 停止并删除倒计时定时器,释放相关资源。
* 即使定时器未初始化或未运行,也可以安全调用此函数。
*
* @note 调用此函数后,定时器完全销毁。需要再次调用 start_countdown() 来重新创建。
*/
void stop_countdown(void);
倒计时更新接口
/**
* @brief 更新倒计时状态
*
* 根据活跃票源更新倒计时。该函数会根据优先级选择活跃的倒计时源,
* 并启动或更新相应的倒计时定时器。
*
* @param s_active_tickets 活跃票源的位掩码
*
* @note OTA 票具有特殊逻辑,会暂停所有倒计时
*/
void update_countdown(uint32_t s_active_tickets);
票源类型定义
typedef enum {
COUNTDOWN_TICKET_PROVISIONING, // 配网倒计时(5分钟), 最高优先级
COUNTDOWN_TICKET_NETWORK_ERROR, // 网络错误倒计时(5分钟), 中优先级
COUNTDOWN_TICKET_STANDBY, // 待机倒计时(3分钟), 低优先级
COUNTDOWN_TICKET_OTA, // OTA 事件,特殊逻辑,不参与比较
COUNTDOWN_TICKET_MAX
} countdown_ticket_t;
主要宏定义
配置宏
// 启用 Countdown 模块
CONFIG_COUNTDOWN=y
倒计时时长配置
倒计时时长在 countdown_app.c 中的 s_ticket_durations[] 数组中配置:
static const uint32_t s_ticket_durations[COUNTDOWN_TICKET_MAX] = {
[COUNTDOWN_TICKET_PROVISIONING] = 5 * 60 * 1000, // 5分钟
[COUNTDOWN_TICKET_NETWORK_ERROR] = 5 * 60 * 1000, // 5分钟
[COUNTDOWN_TICKET_STANDBY] = 3 * 60 * 1000, // 3分钟
[COUNTDOWN_TICKET_OTA] = COUNTDOWN_INFINITE, // 无限(暂停倒计时)
};
特殊值
// 无限倒计时(用于暂停)
#define COUNTDOWN_INFINITE 0xFFFFFFFF
使用示例
基本使用
#include "countdown_app.h"
void example_usage(void)
{
uint32_t active_tickets = 0;
// 设置配网倒计时票
active_tickets |= (1 << COUNTDOWN_TICKET_PROVISIONING);
// 更新倒计时(将启动 5 分钟倒计时)
update_countdown(active_tickets);
// 清除配网票,设置待机票
active_tickets &= ~(1 << COUNTDOWN_TICKET_PROVISIONING);
active_tickets |= (1 << COUNTDOWN_TICKET_STANDBY);
// 更新倒计时(将启动 3 分钟倒计时)
update_countdown(active_tickets);
// OTA 事件,暂停倒计时
active_tickets |= (1 << COUNTDOWN_TICKET_OTA);
update_countdown(active_tickets); // 倒计时停止
// 清除所有票,停止倒计时
active_tickets = 0;
update_countdown(active_tickets); // 倒计时停止
}
优先级示例
void priority_example(void)
{
uint32_t active_tickets = 0;
// 同时设置多个票源
active_tickets |= (1 << COUNTDOWN_TICKET_PROVISIONING); // 5分钟
active_tickets |= (1 << COUNTDOWN_TICKET_STANDBY); // 3分钟
// 更新倒计时
// 由于配网票优先级更高,将使用 5 分钟倒计时
update_countdown(active_tickets);
// 清除配网票后,待机票生效,倒计时变为 3 分钟
active_tickets &= ~(1 << COUNTDOWN_TICKET_PROVISIONING);
update_countdown(active_tickets);
}
注意事项
优先级顺序: 票源按枚举顺序确定优先级,PROVISIONING > NETWORK_ERROR > STANDBY
OTA 特殊处理: OTA 票存在时会暂停所有倒计时
深度睡眠: 倒计时到期时会强制进入深度睡眠,无法取消
时长配置: 修改倒计时时长需要修改
s_ticket_durations[]数组