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/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);
|
||||||
@@ -123,12 +159,52 @@ static int qdec_init(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INF("QDEC initialized: %d deg/step, <=1 step per %d ms",
|
LOG_INF("QDEC initialized: %d deg/step, <=1 step per %d ms",
|
||||||
QDEC_DEG_PER_STEP_EVENT, QDEC_EVENT_INTERVAL_MS);
|
QDEC_DEG_PER_STEP_EVENT, QDEC_EVENT_INTERVAL_MS);
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
Reference in New Issue
Block a user