feat(qdec_module): 添加电源管理功能支持

- 引入pm/device.h和sys/atomic.h头文件以支持电源管理和原子操作
- 添加active原子变量来跟踪模块激活状态
- 实现qdec_module_suspend()和qdec_module_resume()函数处理挂起和唤醒
- 集成power_event事件订阅,在电源下电时挂起模块,在唤醒时恢复模块
- 修改工作调度逻辑,确保仅在活动状态下执行旋转编码器数据处理
- 重构初始化逻辑,使用qdec_reset_state()函数重置内部状态
This commit is contained in:
2026-04-01 16:18:52 +08:00
parent e369567998
commit 881b36274c

View File

@@ -3,8 +3,11 @@
#include <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/drivers/sensor.h> #include <zephyr/drivers/sensor.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/atomic.h>
#include <app_event_manager.h> #include <app_event_manager.h>
#include <caf/events/power_event.h>
#define MODULE qdec #define MODULE qdec
#include <caf/events/module_state_event.h> #include <caf/events/module_state_event.h>
@@ -24,6 +27,7 @@ struct qdec_ctx {
const struct device *dev; const struct device *dev;
struct sensor_trigger trigger; struct sensor_trigger trigger;
struct k_work_delayable emit_work; struct k_work_delayable emit_work;
atomic_t active;
int32_t acc_deg; int32_t acc_deg;
bool emit_scheduled; bool emit_scheduled;
}; };
@@ -36,8 +40,31 @@ static struct qdec_ctx qdec = {
}, },
}; };
static void qdec_reset_state(void)
{
qdec.acc_deg = 0;
qdec.emit_scheduled = false;
}
static int qdec_device_set_enabled(bool enable)
{
int err = pm_device_action_run(qdec.dev,
enable ? PM_DEVICE_ACTION_RESUME :
PM_DEVICE_ACTION_SUSPEND);
if ((err == 0) || (err == -EALREADY)) {
return 0;
}
return err;
}
static void schedule_emit_work(void) static void schedule_emit_work(void)
{ {
if (!atomic_get(&qdec.active)) {
return;
}
if (qdec.emit_scheduled) { if (qdec.emit_scheduled) {
return; return;
} }
@@ -52,6 +79,11 @@ static void qdec_emit_work_handler(struct k_work *work)
ARG_UNUSED(work); ARG_UNUSED(work);
if (!atomic_get(&qdec.active)) {
qdec.emit_scheduled = false;
return;
}
qdec.emit_scheduled = false; qdec.emit_scheduled = false;
if ((qdec.acc_deg < QDEC_DEG_PER_STEP_EVENT) && if ((qdec.acc_deg < QDEC_DEG_PER_STEP_EVENT) &&
@@ -83,6 +115,10 @@ static void qdec_data_handler(const struct device *dev,
ARG_UNUSED(trigger); ARG_UNUSED(trigger);
if (!atomic_get(&qdec.active)) {
return;
}
err = sensor_sample_fetch_chan(dev, SENSOR_CHAN_ROTATION); err = sensor_sample_fetch_chan(dev, SENSOR_CHAN_ROTATION);
if (err) { if (err) {
LOG_ERR("QDEC sample fetch failed: %d", err); LOG_ERR("QDEC sample fetch failed: %d", err);
@@ -113,8 +149,8 @@ static int qdec_init(void)
return -ENODEV; return -ENODEV;
} }
qdec.acc_deg = 0; qdec_reset_state();
qdec.emit_scheduled = false; atomic_set(&qdec.active, false);
k_work_init_delayable(&qdec.emit_work, qdec_emit_work_handler); k_work_init_delayable(&qdec.emit_work, qdec_emit_work_handler);
err = sensor_trigger_set(qdec.dev, &qdec.trigger, qdec_data_handler); err = sensor_trigger_set(qdec.dev, &qdec.trigger, qdec_data_handler);
@@ -129,6 +165,46 @@ static int qdec_init(void)
return 0; return 0;
} }
static void qdec_module_suspend(void)
{
int err;
if (!atomic_get(&qdec.active)) {
return;
}
atomic_set(&qdec.active, false);
(void)k_work_cancel_delayable(&qdec.emit_work);
qdec_reset_state();
err = qdec_device_set_enabled(false);
if (err) {
LOG_WRN("QDEC suspend failed: %d", err);
}
module_set_state(MODULE_STATE_STANDBY);
}
static void qdec_module_resume(void)
{
int err;
if (atomic_get(&qdec.active)) {
return;
}
err = qdec_device_set_enabled(true);
if (err) {
LOG_ERR("QDEC resume failed: %d", err);
module_set_state(MODULE_STATE_ERROR);
return;
}
qdec_reset_state();
atomic_set(&qdec.active, true);
module_set_state(MODULE_STATE_READY);
}
static bool app_event_handler(const struct app_event_header *aeh) static bool app_event_handler(const struct app_event_header *aeh)
{ {
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
@@ -140,16 +216,28 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (err) { if (err) {
module_set_state(MODULE_STATE_ERROR); module_set_state(MODULE_STATE_ERROR);
} else { } else {
module_set_state(MODULE_STATE_READY); qdec_module_resume();
} }
} }
return false; return false;
} }
if (is_power_down_event(aeh)) {
qdec_module_suspend();
return false;
}
if (is_wake_up_event(aeh)) {
qdec_module_resume();
return false;
}
__ASSERT_NO_MSG(false); __ASSERT_NO_MSG(false);
return false; return false;
} }
APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_LISTENER(MODULE, app_event_handler);
APP_EVENT_SUBSCRIBE(MODULE, module_state_event); APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);