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:
@@ -3,8 +3,11 @@
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
|
||||
#include <app_event_manager.h>
|
||||
#include <caf/events/power_event.h>
|
||||
|
||||
#define MODULE qdec
|
||||
#include <caf/events/module_state_event.h>
|
||||
@@ -24,6 +27,7 @@ struct qdec_ctx {
|
||||
const struct device *dev;
|
||||
struct sensor_trigger trigger;
|
||||
struct k_work_delayable emit_work;
|
||||
atomic_t active;
|
||||
int32_t acc_deg;
|
||||
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)
|
||||
{
|
||||
if (!atomic_get(&qdec.active)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (qdec.emit_scheduled) {
|
||||
return;
|
||||
}
|
||||
@@ -52,6 +79,11 @@ static void qdec_emit_work_handler(struct k_work *work)
|
||||
|
||||
ARG_UNUSED(work);
|
||||
|
||||
if (!atomic_get(&qdec.active)) {
|
||||
qdec.emit_scheduled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
qdec.emit_scheduled = false;
|
||||
|
||||
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);
|
||||
|
||||
if (!atomic_get(&qdec.active)) {
|
||||
return;
|
||||
}
|
||||
|
||||
err = sensor_sample_fetch_chan(dev, SENSOR_CHAN_ROTATION);
|
||||
if (err) {
|
||||
LOG_ERR("QDEC sample fetch failed: %d", err);
|
||||
@@ -113,8 +149,8 @@ static int qdec_init(void)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
qdec.acc_deg = 0;
|
||||
qdec.emit_scheduled = false;
|
||||
qdec_reset_state();
|
||||
atomic_set(&qdec.active, false);
|
||||
k_work_init_delayable(&qdec.emit_work, qdec_emit_work_handler);
|
||||
|
||||
err = sensor_trigger_set(qdec.dev, &qdec.trigger, qdec_data_handler);
|
||||
@@ -129,6 +165,46 @@ static int qdec_init(void)
|
||||
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)
|
||||
{
|
||||
if (is_module_state_event(aeh)) {
|
||||
@@ -140,16 +216,28 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
} else {
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
qdec_module_resume();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user