Files
blinky/src/mode_switch_module.c
skiinder e0817a7b44 feat(module_lifecycle): 完善模块生命周期管理功能
- 添加了模块生命周期状态转换验证函数,包括目标状态允许性检查和路径允许性检查
- 实现了模块操作验证功能,确保必要的回调函数存在
- 更新了状态报告逻辑,增加了模式检查以防止无效状态转换
- 修改了生命周期转换流程,区分运行启动和停止操作
- 优化了错误处理机制,返回适当的错误码

refactor(ble_modules): 简化BLE模块生命周期配置

- 将多个BLE模块(lifecycle_cfg)的模式从ML_MODE_POWER改为ML_MODE_NONE
- 移除了power_event相关依赖和事件订阅
- 更新了BLE BAS模块的状态转换逻辑
- 简化了BLE HID/NUS/Protocol模块的电源管理相关代码

fix(mode_switch): 修复唤醒后模式恢复功能

- 在唤醒事件处理中添加了最后模式的恢复逻辑
- 确保设备唤醒后能够重新提交之前的模式切换事件
2026-04-18 14:17:23 +08:00

221 lines
4.9 KiB
C

#include <stdbool.h>
#include <stdint.h>
#include <app_event_manager.h>
#define MODULE mode_switch_module
#include <caf/events/module_state_event.h>
#include <caf/events/power_event.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include "module_lifecycle.h"
#include "mode_switch_event.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
#define MODE_SWITCH_ADC_NODE DT_NODELABEL(mode_switch_adc)
#define MODE_SWITCH_SAMPLE_INTERVAL K_MSEC(500)
#define MODE_SWITCH_USB_MAX_MV 825
#define MODE_SWITCH_24G_MAX_MV 2475
BUILD_ASSERT(DT_NODE_EXISTS(MODE_SWITCH_ADC_NODE),
"Missing mode_switch_adc node in devicetree");
struct mode_switch_module_ctx {
struct module_lifecycle_ctx lc;
const struct device *mode_switch_adc_dev;
struct k_work_delayable mode_switch_sample_work;
enum mode_switch_mode last_mode;
};
static int do_init(void);
static int do_start(void);
static int do_stop(void);
static const struct module_lifecycle_cfg lifecycle_cfg = {
.mode = ML_MODE_POWER,
.stopped_state = MODULE_STATE_STANDBY,
};
static const struct module_lifecycle_ops lifecycle_ops = {
.do_init = do_init,
.do_start = do_start,
.do_stop = do_stop,
};
static struct mode_switch_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.mode_switch_adc_dev = DEVICE_DT_GET(MODE_SWITCH_ADC_NODE),
};
static enum mode_switch_mode detect_mode(uint16_t voltage_mv)
{
if (voltage_mv < MODE_SWITCH_USB_MAX_MV) {
return MODE_SWITCH_USB;
}
if (voltage_mv < MODE_SWITCH_24G_MAX_MV) {
return MODE_SWITCH_24G;
}
return MODE_SWITCH_BLE;
}
static int mode_switch_enable(bool enable)
{
enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME
: PM_DEVICE_ACTION_SUSPEND;
int err = pm_device_action_run(ctx.mode_switch_adc_dev, action);
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
LOG_ERR("Cannot %s mode switch ADC (%d)",
enable ? "resume" : "suspend", err);
return err;
}
return 0;
}
static void mode_switch_sample_fn(struct k_work *work)
{
struct sensor_value voltage;
int err;
ARG_UNUSED(work);
if (!module_lifecycle_is_running(&ctx.lc)) {
return;
}
err = sensor_sample_fetch(ctx.mode_switch_adc_dev);
if (err) {
LOG_WRN("Mode switch ADC sample fetch failed (%d)", err);
goto reschedule;
}
err = sensor_channel_get(ctx.mode_switch_adc_dev, SENSOR_CHAN_VOLTAGE,
&voltage);
if (err) {
LOG_WRN("Mode switch ADC channel get failed (%d)", err);
goto reschedule;
}
uint16_t sample_mv = (uint16_t)((voltage.val1 * 1000) + (voltage.val2 / 1000));
enum mode_switch_mode mode = detect_mode(sample_mv);
if ((ctx.last_mode == MODE_SWITCH_INVALID) || (mode != ctx.last_mode)) {
submit_mode_switch_event(mode, sample_mv);
ctx.last_mode = mode;
}
reschedule:
if (module_lifecycle_is_running(&ctx.lc)) {
k_work_reschedule(&ctx.mode_switch_sample_work,
MODE_SWITCH_SAMPLE_INTERVAL);
}
}
static int do_init(void)
{
if (!device_is_ready(ctx.mode_switch_adc_dev)) {
LOG_ERR("Mode switch ADC device not ready");
return -ENODEV;
}
k_work_init_delayable(&ctx.mode_switch_sample_work, mode_switch_sample_fn);
ctx.last_mode = MODE_SWITCH_INVALID;
return 0;
}
static int do_start(void)
{
int err;
if (module_lifecycle_is_running(&ctx.lc)) {
return 0;
}
err = mode_switch_enable(true);
if (err) {
return err;
}
k_work_reschedule(&ctx.mode_switch_sample_work, K_NO_WAIT);
return 0;
}
static int do_stop(void)
{
if (!module_lifecycle_is_running(&ctx.lc)) {
return 0;
}
(void)k_work_cancel_delayable(&ctx.mode_switch_sample_work);
(void)mode_switch_enable(false);
return 0;
}
static bool app_event_handler(const struct app_event_header *aeh)
{
if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh);
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
return false;
}
if (check_state(event, MODULE_ID(mode_policy_module),
MODULE_STATE_READY)) {
if (ctx.last_mode != MODE_SWITCH_INVALID) {
submit_mode_switch_event(ctx.last_mode, 0U);
}
return false;
}
return false;
}
if (is_power_down_event(aeh)) {
if (module_lifecycle_is_initialized(&ctx.lc)) {
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
}
return false;
}
if (is_wake_up_event(aeh)) {
if (module_lifecycle_is_initialized(&ctx.lc)) {
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (ctx.last_mode != MODE_SWITCH_INVALID) {
submit_mode_switch_event(ctx.last_mode, 0U);
}
}
return false;
}
__ASSERT_NO_MSG(false);
return false;
}
APP_EVENT_LISTENER(MODULE, app_event_handler);
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);