Compare commits

...

2 Commits

Author SHA1 Message Date
caf8d5acc6 feat(mode_switch): 添加无效模式枚举值并更新事件处理
添加 MODE_SWITCH_INVALID 枚举值到 mode_switch_mode 中,
用于表示无效的模式状态。同时更新相关的事件处理逻辑,
确保在模式切换时能够正确处理无效模式的情况。

refactor(mode_policy): 简化模块上下文结构并优化模式策略

将模块上下文中的 ble_adv_suspended 和 usb_enabled 标志位
替换为 active_mode 枚举值,简化了数据结构。重新设计了
模式策略应用逻辑,使其更清晰易懂,并改进了BLE和USB设备
的启用/暂停控制流程。

refactor(usb_device): 重构USB设备生命周期管理

移除了 USB_STACK_DISABLED 状态,简化了USB栈的状态管理。
改进了USB设备的启动和停止逻辑,更好地与模块生命周期
集成。现在USB状态事件仅在模块初始化后提交,避免了
不必要的事件发布。

feat(logging): 增加详细的状态转换日志记录

为BLE NUS模块添加了业务状态转换的日志记录功能,
增加了详细的错误和警告日志,包括生命周期状态、
业务状态和连接信息,便于调试和问题排查。

refactor(mode_switch): 优化模式检测和报告机制

修改了模式切换采样的判断逻辑,移除了force_report和
mode_valid标志位,改用last_mode状态来决定是否提交
模式切换事件,使代码更简洁且易于理解。
2026-04-18 11:27:48 +08:00
ceebaaa600 feat: 添加模块生命周期管理框架并重构现有模块
添加了模块生命周期管理头文件 module_lifecycle.h,定义了完整的生命周期状态机,
包括初始化、运行、停止、挂起和错误状态。同时将电池模块、BLE BAS模块、BLE HID
模块和BLE NUS模块重构为使用新的生命周期框架进行状态管理。

提升日志缓冲区大小以支持更详细的调试信息记录。
2026-04-17 19:12:57 +08:00
22 changed files with 1615 additions and 1200 deletions

View File

@@ -9,6 +9,7 @@ extern "C" {
#endif #endif
enum mode_switch_mode { enum mode_switch_mode {
MODE_SWITCH_INVALID,
MODE_SWITCH_USB, MODE_SWITCH_USB,
MODE_SWITCH_24G, MODE_SWITCH_24G,
MODE_SWITCH_BLE, MODE_SWITCH_BLE,

204
inc/module_lifecycle.h Normal file
View File

@@ -0,0 +1,204 @@
#ifndef MODULE_LIFECYCLE_H_
#define MODULE_LIFECYCLE_H_
#include <errno.h>
#include <stdbool.h>
#include <caf/events/module_state_event.h>
enum module_lifecycle {
LC_UNINIT,
LC_RUNNING,
LC_STOPPED,
LC_SUSPENDED,
LC_ERROR,
};
enum module_lifecycle_mode {
ML_MODE_NONE,
ML_MODE_POWER,
ML_MODE_SUSPEND,
};
struct module_lifecycle_ops {
int (*do_init)(void);
int (*do_start)(void);
int (*do_stop)(void);
};
struct module_lifecycle_cfg {
enum module_lifecycle_mode mode;
enum module_state stopped_state;
};
struct module_lifecycle_ctx {
enum module_lifecycle state;
const struct module_lifecycle_cfg *cfg;
const struct module_lifecycle_ops *ops;
};
static inline bool module_lifecycle_is_running(
const struct module_lifecycle_ctx *ctx)
{
return ctx->state == LC_RUNNING;
}
static inline bool module_lifecycle_is_initialized(
const struct module_lifecycle_ctx *ctx)
{
return (ctx->state != LC_UNINIT) && (ctx->state != LC_ERROR);
}
static inline bool module_lifecycle_reports_stopped_state(
const struct module_lifecycle_ctx *ctx)
{
return ctx->cfg->mode != ML_MODE_NONE;
}
static inline int module_lifecycle_report_state(
struct module_lifecycle_ctx *ctx,
enum module_lifecycle state)
{
switch (state) {
case LC_RUNNING:
module_set_state(MODULE_STATE_READY);
return 0;
case LC_STOPPED:
if (!module_lifecycle_reports_stopped_state(ctx)) {
return 0;
}
module_set_state(ctx->cfg->stopped_state);
return 0;
case LC_SUSPENDED:
module_set_state(MODULE_STATE_SUSPENDED);
return 0;
case LC_ERROR:
module_set_state(MODULE_STATE_ERROR);
return 0;
case LC_UNINIT:
default:
return -EINVAL;
}
}
static inline int module_lifecycle_fail(struct module_lifecycle_ctx *ctx, int err)
{
ctx->state = LC_ERROR;
(void)module_lifecycle_report_state(ctx, LC_ERROR);
return err ? err : -EIO;
}
static inline int module_lifecycle_do_init(struct module_lifecycle_ctx *ctx)
{
int err = ctx->ops->do_init();
if (err) {
return module_lifecycle_fail(ctx, err);
}
return 0;
}
static inline int module_lifecycle_do_start(struct module_lifecycle_ctx *ctx,
enum module_lifecycle target)
{
int err = ctx->ops->do_start();
if (err) {
return module_lifecycle_fail(ctx, err);
}
ctx->state = target;
return module_lifecycle_report_state(ctx, target);
}
static inline int module_lifecycle_do_stop(struct module_lifecycle_ctx *ctx,
enum module_lifecycle target)
{
int err = ctx->ops->do_stop();
if (err) {
return module_lifecycle_fail(ctx, err);
}
ctx->state = target;
return module_lifecycle_report_state(ctx, target);
}
static inline int module_set_lifecycle(struct module_lifecycle_ctx *ctx,
enum module_lifecycle target)
{
if ((ctx == NULL) || (ctx->cfg == NULL) || (ctx->ops == NULL) ||
(ctx->ops->do_init == NULL) || (ctx->ops->do_start == NULL) ||
(ctx->ops->do_stop == NULL)) {
return -EINVAL;
}
if (ctx->state == LC_ERROR) {
return -EFAULT;
}
if (ctx->state == target) {
return 0;
}
if (target == LC_ERROR) {
return module_lifecycle_fail(ctx, -EIO);
}
switch (ctx->state) {
case LC_UNINIT:
if (target == LC_RUNNING) {
int err = module_lifecycle_do_init(ctx);
if (err) {
return err;
}
ctx->state = LC_STOPPED;
return module_lifecycle_do_start(ctx, LC_RUNNING);
}
if (target == LC_STOPPED) {
int err = module_lifecycle_do_init(ctx);
if (err) {
return err;
}
ctx->state = LC_STOPPED;
return module_lifecycle_report_state(ctx, LC_STOPPED);
}
break;
case LC_RUNNING:
if ((target == LC_STOPPED) || (target == LC_SUSPENDED)) {
return module_lifecycle_do_stop(ctx, target);
}
break;
case LC_STOPPED:
case LC_SUSPENDED:
if (target == LC_RUNNING) {
return module_lifecycle_do_start(ctx, LC_RUNNING);
}
break;
case LC_ERROR:
default:
break;
}
return -EPERM;
}
#endif /* MODULE_LIFECYCLE_H_ */

View File

@@ -26,7 +26,10 @@ CONFIG_FLASH_MAP=y
CONFIG_NVS=y CONFIG_NVS=y
CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_HEAP_MEM_POOL_SIZE=4096
CONFIG_LOG=y CONFIG_LOG=y
CONFIG_LOG_BUFFER_SIZE=16384
CONFIG_LOG_BACKEND_RTT_OUTPUT_BUFFER_SIZE=16384
CONFIG_ASSERT=y CONFIG_ASSERT=y
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=16384
CONFIG_APP_EVENT_MANAGER_MAX_EVENT_CNT=64 CONFIG_APP_EVENT_MANAGER_MAX_EVENT_CNT=64
CONFIG_LED_STRIP=y CONFIG_LED_STRIP=y
CONFIG_WS2812_STRIP_SPI=y CONFIG_WS2812_STRIP_SPI=y

View File

@@ -18,6 +18,7 @@
#include <zephyr/pm/device.h> #include <zephyr/pm/device.h>
#include "bat_state_event.h" #include "bat_state_event.h"
#include "module_lifecycle.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
@@ -32,17 +33,43 @@ BUILD_ASSERT(DT_NODE_HAS_STATUS(VBATT_NODE, okay),
BUILD_ASSERT(DT_NODE_HAS_STATUS(IP5306_NODE, okay), BUILD_ASSERT(DT_NODE_HAS_STATUS(IP5306_NODE, okay),
"Missing ip5306 node in devicetree"); "Missing ip5306 node in devicetree");
static const struct device *const vbatt_dev = DEVICE_DT_GET(VBATT_NODE); struct battery_module_ctx {
static const struct device *const ip5306_dev = DEVICE_DT_GET(IP5306_NODE); struct module_lifecycle_ctx lc;
static struct k_work_delayable battery_sample_work; const struct device *vbatt_dev;
static struct { const struct device *ip5306_dev;
struct k_work_delayable battery_sample_work;
struct {
bool valid; bool valid;
uint8_t soc; uint8_t soc;
bool charging; bool charging;
bool full; bool full;
} last_bat_state; } last_bat_state;
static bool initialized; };
static bool running;
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 battery_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.vbatt_dev = DEVICE_DT_GET(VBATT_NODE),
.ip5306_dev = DEVICE_DT_GET(IP5306_NODE),
};
static int sensor_value_to_mv(const struct sensor_value *value) static int sensor_value_to_mv(const struct sensor_value *value)
{ {
@@ -53,7 +80,7 @@ static int measurement_enable(bool enable)
{ {
enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME
: PM_DEVICE_ACTION_SUSPEND; : PM_DEVICE_ACTION_SUSPEND;
int err = pm_device_action_run(vbatt_dev, action); int err = pm_device_action_run(ctx.vbatt_dev, action);
if (err && (err != -EALREADY) && (err != -ENOTSUP)) { if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
LOG_ERR("Cannot %s vbatt sensor (%d)", enable ? "resume" : "suspend", err); LOG_ERR("Cannot %s vbatt sensor (%d)", enable ? "resume" : "suspend", err);
@@ -90,23 +117,23 @@ static void battery_sample_fn(struct k_work *work)
ARG_UNUSED(work); ARG_UNUSED(work);
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return;
} }
err = sensor_sample_fetch(vbatt_dev); err = sensor_sample_fetch(ctx.vbatt_dev);
if (err) { if (err) {
LOG_WRN("Battery sample fetch failed (%d)", err); LOG_WRN("Battery sample fetch failed (%d)", err);
goto reschedule; goto reschedule;
} }
err = sensor_channel_get(vbatt_dev, SENSOR_CHAN_VOLTAGE, &voltage); err = sensor_channel_get(ctx.vbatt_dev, SENSOR_CHAN_VOLTAGE, &voltage);
if (err) { if (err) {
LOG_WRN("Battery channel get failed (%d)", err); LOG_WRN("Battery channel get failed (%d)", err);
goto reschedule; goto reschedule;
} }
err = ip5306_get_status(ip5306_dev, &pmic_status); err = ip5306_get_status(ctx.ip5306_dev, &pmic_status);
if (err) { if (err) {
LOG_WRN("IP5306 status read failed (%d)", err); LOG_WRN("IP5306 status read failed (%d)", err);
goto reschedule; goto reschedule;
@@ -115,53 +142,53 @@ static void battery_sample_fn(struct k_work *work)
voltage_mv = sensor_value_to_mv(&voltage); voltage_mv = sensor_value_to_mv(&voltage);
uint8_t soc = battery_soc_from_mv(voltage_mv); uint8_t soc = battery_soc_from_mv(voltage_mv);
if (!last_bat_state.valid || if (!ctx.last_bat_state.valid ||
(last_bat_state.soc != soc) || (ctx.last_bat_state.soc != soc) ||
(last_bat_state.charging != pmic_status.charging) || (ctx.last_bat_state.charging != pmic_status.charging) ||
(last_bat_state.full != pmic_status.full)) { (ctx.last_bat_state.full != pmic_status.full)) {
last_bat_state.valid = true; ctx.last_bat_state.valid = true;
last_bat_state.soc = soc; ctx.last_bat_state.soc = soc;
last_bat_state.charging = pmic_status.charging; ctx.last_bat_state.charging = pmic_status.charging;
last_bat_state.full = pmic_status.full; ctx.last_bat_state.full = pmic_status.full;
submit_bat_state_event(soc, pmic_status.charging, pmic_status.full); submit_bat_state_event(soc, pmic_status.charging, pmic_status.full);
} }
reschedule: reschedule:
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
k_work_reschedule(&battery_sample_work, BATTERY_SAMPLE_INTERVAL); k_work_reschedule(&ctx.battery_sample_work, BATTERY_SAMPLE_INTERVAL);
} }
} }
static int module_init(void) static int do_init(void)
{ {
if (!device_is_ready(vbatt_dev)) { if (!device_is_ready(ctx.vbatt_dev)) {
LOG_ERR("vbatt device not ready"); LOG_ERR("vbatt device not ready");
return -ENODEV; return -ENODEV;
} }
if (!device_is_ready(ip5306_dev)) { if (!device_is_ready(ctx.ip5306_dev)) {
LOG_ERR("ip5306 device not ready"); LOG_ERR("ip5306 device not ready");
return -ENODEV; return -ENODEV;
} }
int err = ip5306_init(ip5306_dev); int err = ip5306_init(ctx.ip5306_dev);
if (err) { if (err) {
LOG_ERR("ip5306 init failed (%d)", err); LOG_ERR("ip5306 init failed (%d)", err);
return err; return err;
} }
k_work_init_delayable(&battery_sample_work, battery_sample_fn); k_work_init_delayable(&ctx.battery_sample_work, battery_sample_fn);
memset(&last_bat_state, 0, sizeof(last_bat_state)); memset(&ctx.last_bat_state, 0, sizeof(ctx.last_bat_state));
power_manager_restrict(MODULE_IDX(MODULE), POWER_MANAGER_LEVEL_SUSPENDED); power_manager_restrict(MODULE_IDX(MODULE), POWER_MANAGER_LEVEL_SUSPENDED);
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
int err; int err;
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
@@ -170,21 +197,21 @@ static int module_start(void)
return err; return err;
} }
running = true; k_work_reschedule(&ctx.battery_sample_work, K_NO_WAIT);
k_work_reschedule(&battery_sample_work, K_NO_WAIT);
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
(void)k_work_cancel_delayable(&battery_sample_work); (void)k_work_cancel_delayable(&ctx.battery_sample_work);
(void)measurement_enable(false); (void)measurement_enable(false);
running = false;
return 0;
} }
static bool app_event_handler(const struct app_event_header *aeh) static bool app_event_handler(const struct app_event_header *aeh)
@@ -193,47 +220,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
const struct module_state_event *event = cast_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)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err; (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -11,34 +11,54 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include "bat_state_event.h" #include "bat_state_event.h"
#include "module_lifecycle.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
static uint8_t current_soc = 100U; struct ble_bas_module_ctx {
static bool initialized; struct module_lifecycle_ctx lc;
static bool running; uint8_t current_soc;
static bool ble_ready; bool ble_ready;
};
static int module_init(void) 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_NONE,
.stopped_state = MODULE_STATE_OFF,
};
static const struct module_lifecycle_ops lifecycle_ops = {
.do_init = do_init,
.do_start = do_start,
.do_stop = do_stop,
};
static struct ble_bas_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.current_soc = 100U,
};
static int do_init(void)
{ {
return 0; return 0;
} }
static int module_start(void) static int bas_update_level(void)
{ {
int err; int err = bt_bas_set_battery_level(ctx.current_soc);
if (running) { if ((err == -EAGAIN) || (err == -ENOTCONN)) {
LOG_INF("BAS notify deferred (%d)", err);
return 0; return 0;
} }
running = true;
if (!ble_ready) {
return 0;
}
err = bt_bas_set_battery_level(current_soc);
if (err) { if (err) {
LOG_WRN("bt_bas_set_battery_level failed (%d)", err); LOG_WRN("bt_bas_set_battery_level failed (%d)", err);
return err; return err;
@@ -47,21 +67,30 @@ static int module_start(void)
return 0; return 0;
} }
static void module_pause(void) static int do_start(void)
{ {
running = false; if (module_lifecycle_is_running(&ctx.lc)) {
return 0;
}
if (!ctx.ble_ready) {
return 0;
}
return bas_update_level();
}
static int do_stop(void)
{
return 0;
} }
static bool handle_bat_state_event(const struct bat_state_event *event) static bool handle_bat_state_event(const struct bat_state_event *event)
{ {
current_soc = event->soc; ctx.current_soc = event->soc;
if (running && ble_ready) { if (module_lifecycle_is_running(&ctx.lc) && ctx.ble_ready) {
int err = bt_bas_set_battery_level(current_soc); (void)bas_update_level();
if (err) {
LOG_WRN("bt_bas_set_battery_level failed (%d)", err);
}
} }
return false; return false;
@@ -75,38 +104,22 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh); const struct module_state_event *event = cast_module_state_event(aeh);
int err;
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (!initialized) { (void)module_set_lifecycle(&ctx.lc,
err = module_init(); ctx.ble_ready ? LC_RUNNING :
if (err) { LC_STOPPED);
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
}
return false; return false;
} }
if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
ble_ready = true; ctx.ble_ready = true;
if (running) { if (ctx.lc.state == LC_STOPPED) {
err = bt_bas_set_battery_level(current_soc); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) { } else if (module_lifecycle_is_running(&ctx.lc)) {
LOG_WRN("bt_bas_set_battery_level failed (%d)", err); (void)bas_update_level();
} }
}
module_set_state(MODULE_STATE_READY);
return false; return false;
} }

View File

@@ -18,6 +18,7 @@
#include "hid_report_sent_event.h" #include "hid_report_sent_event.h"
#include "hid_tx_report_event.h" #include "hid_tx_report_event.h"
#include "keyboard_core.h" #include "keyboard_core.h"
#include "module_lifecycle.h"
#include "set_protocol_event.h" #include "set_protocol_event.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
@@ -40,15 +41,40 @@ BT_HIDS_DEF(hids_obj,
KEYBOARD_CONSUMER_REPORT_SIZE, KEYBOARD_CONSUMER_REPORT_SIZE,
BLE_HID_KEYS_LED_REPORT_SIZE); BLE_HID_KEYS_LED_REPORT_SIZE);
static struct bt_conn *active_conn; struct ble_hid_module_ctx {
static struct in_flight_report in_flight; struct module_lifecycle_ctx lc;
static enum keyboard_protocol_mode protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; struct bt_conn *active_conn;
static bool initialized; struct in_flight_report in_flight;
static bool running; enum keyboard_protocol_mode protocol_mode;
static bool secured; bool secured;
static bool keyboard_report_notify_enabled; bool keyboard_report_notify_enabled;
static bool consumer_report_notify_enabled; bool consumer_report_notify_enabled;
static bool boot_keyboard_notify_enabled; bool boot_keyboard_notify_enabled;
};
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 ble_hid_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
};
static const uint8_t hid_report_desc[] = { static const uint8_t hid_report_desc[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */ 0x05, 0x01, /* Usage Page (Generic Desktop) */
@@ -100,24 +126,25 @@ static const uint8_t hid_report_desc[] = {
static void submit_ble_transport_state_event(void) static void submit_ble_transport_state_event(void)
{ {
bool ready = running && secured && (active_conn != NULL); bool ready = module_lifecycle_is_running(&ctx.lc) &&
ctx.secured && (ctx.active_conn != NULL);
uint8_t report_ready_bm = 0U; uint8_t report_ready_bm = 0U;
if (ready && ((protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? if (ready && ((ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ?
boot_keyboard_notify_enabled : ctx.boot_keyboard_notify_enabled :
keyboard_report_notify_enabled)) { ctx.keyboard_report_notify_enabled)) {
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_KEYS); report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_KEYS);
} }
if (ready && (protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT) && if (ready && (ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT) &&
consumer_report_notify_enabled) { ctx.consumer_report_notify_enabled) {
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_CONSUMER); report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_CONSUMER);
} }
submit_hid_channel_state_event( submit_hid_channel_state_event(
HID_SEND_CH_BLE_SHARED, HID_SEND_CH_BLE_SHARED,
report_ready_bm, report_ready_bm,
protocol_mode); ctx.protocol_mode);
} }
static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_evt evt) static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_evt evt)
@@ -125,9 +152,9 @@ static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_e
bool enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED); bool enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
if (report_id == BLE_HID_KEYS_REPORT_ID) { if (report_id == BLE_HID_KEYS_REPORT_ID) {
keyboard_report_notify_enabled = enabled; ctx.keyboard_report_notify_enabled = enabled;
} else if (report_id == BLE_HID_CONSUMER_REPORT_ID) { } else if (report_id == BLE_HID_CONSUMER_REPORT_ID) {
consumer_report_notify_enabled = enabled; ctx.consumer_report_notify_enabled = enabled;
} }
submit_ble_transport_state_event(); submit_ble_transport_state_event();
@@ -135,7 +162,7 @@ static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_e
static void boot_keyboard_notify_handler(enum bt_hids_notify_evt evt) static void boot_keyboard_notify_handler(enum bt_hids_notify_evt evt)
{ {
boot_keyboard_notify_enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED); ctx.boot_keyboard_notify_enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
submit_ble_transport_state_event(); submit_ble_transport_state_event();
} }
@@ -144,14 +171,14 @@ static void hid_report_complete_cb(struct bt_conn *conn, void *user_data)
ARG_UNUSED(conn); ARG_UNUSED(conn);
ARG_UNUSED(user_data); ARG_UNUSED(user_data);
if (!in_flight.active) { if (!ctx.in_flight.active) {
return; return;
} }
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED, submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
in_flight.report_type, ctx.in_flight.report_type,
in_flight.sequence, false); ctx.in_flight.sequence, false);
in_flight.active = false; ctx.in_flight.active = false;
} }
static void keyboard_led_report_common(struct bt_hids_rep *rep, bool write) static void keyboard_led_report_common(struct bt_hids_rep *rep, bool write)
@@ -187,22 +214,22 @@ static void pm_evt_handler(enum bt_hids_pm_evt evt, struct bt_conn *conn)
switch (evt) { switch (evt) {
case BT_HIDS_PM_EVT_BOOT_MODE_ENTERED: case BT_HIDS_PM_EVT_BOOT_MODE_ENTERED:
protocol_mode = KEYBOARD_PROTOCOL_MODE_BOOT; ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_BOOT;
break; break;
case BT_HIDS_PM_EVT_REPORT_MODE_ENTERED: case BT_HIDS_PM_EVT_REPORT_MODE_ENTERED:
protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
break; break;
default: default:
return; return;
} }
submit_set_protocol_event(HID_TRANSPORT_BLE, protocol_mode); submit_set_protocol_event(HID_TRANSPORT_BLE, ctx.protocol_mode);
submit_ble_transport_state_event(); submit_ble_transport_state_event();
} }
static int module_init(void) static int do_init(void)
{ {
struct bt_hids_init_param hids_init_param = { 0 }; struct bt_hids_init_param hids_init_param = { 0 };
struct bt_hids_inp_rep *input_report; struct bt_hids_inp_rep *input_report;
@@ -239,38 +266,38 @@ static int module_init(void)
return bt_hids_init(&hids_obj, &hids_init_param); return bt_hids_init(&hids_obj, &hids_init_param);
} }
static int module_start(void) static int do_start(void)
{ {
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
running = true;
submit_ble_transport_state_event(); submit_ble_transport_state_event();
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
in_flight.active = false; ctx.in_flight.active = false;
running = false;
submit_ble_transport_state_event(); submit_ble_transport_state_event();
return 0;
} }
static void reset_connection_state(void) static void reset_connection_state(void)
{ {
active_conn = NULL; ctx.active_conn = NULL;
secured = false; ctx.secured = false;
keyboard_report_notify_enabled = false; ctx.keyboard_report_notify_enabled = false;
consumer_report_notify_enabled = false; ctx.consumer_report_notify_enabled = false;
boot_keyboard_notify_enabled = false; ctx.boot_keyboard_notify_enabled = false;
protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
in_flight.active = false; ctx.in_flight.active = false;
} }
static bool handle_ble_peer_event(const struct ble_peer_event *event) static bool handle_ble_peer_event(const struct ble_peer_event *event)
@@ -279,13 +306,13 @@ static bool handle_ble_peer_event(const struct ble_peer_event *event)
switch (event->state) { switch (event->state) {
case PEER_STATE_CONNECTED: case PEER_STATE_CONNECTED:
if (active_conn != NULL) { if (ctx.active_conn != NULL) {
return false; return false;
} }
active_conn = event->id; ctx.active_conn = event->id;
protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
submit_set_protocol_event(HID_TRANSPORT_BLE, protocol_mode); submit_set_protocol_event(HID_TRANSPORT_BLE, ctx.protocol_mode);
err = bt_hids_connected(&hids_obj, event->id); err = bt_hids_connected(&hids_obj, event->id);
if (err) { if (err) {
LOG_ERR("bt_hids_connected failed (%d)", err); LOG_ERR("bt_hids_connected failed (%d)", err);
@@ -294,16 +321,16 @@ static bool handle_ble_peer_event(const struct ble_peer_event *event)
return false; return false;
case PEER_STATE_SECURED: case PEER_STATE_SECURED:
if (active_conn != event->id) { if (ctx.active_conn != event->id) {
return false; return false;
} }
secured = true; ctx.secured = true;
submit_ble_transport_state_event(); submit_ble_transport_state_event();
return false; return false;
case PEER_STATE_DISCONNECTED: case PEER_STATE_DISCONNECTED:
if (active_conn != event->id) { if (ctx.active_conn != event->id) {
return false; return false;
} }
@@ -325,34 +352,35 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
{ {
int err; int err;
if (!running || (event->channel != HID_SEND_CH_BLE_SHARED) || if (!module_lifecycle_is_running(&ctx.lc) ||
in_flight.active) { (event->channel != HID_SEND_CH_BLE_SHARED) ||
ctx.in_flight.active) {
return false; return false;
} }
if ((active_conn == NULL) || !secured) { if ((ctx.active_conn == NULL) || !ctx.secured) {
return false; return false;
} }
if (event->report_type == KEYBOARD_REPORT_TYPE_KEYS) { if (event->report_type == KEYBOARD_REPORT_TYPE_KEYS) {
if (event->protocol_mode != protocol_mode) { if (event->protocol_mode != ctx.protocol_mode) {
LOG_WRN("Drop BLE keys report due to protocol mismatch"); LOG_WRN("Drop BLE keys report due to protocol mismatch");
return false; return false;
} }
in_flight.active = true; ctx.in_flight.active = true;
in_flight.report_type = event->report_type; ctx.in_flight.report_type = event->report_type;
in_flight.sequence = event->sequence; ctx.in_flight.sequence = event->sequence;
if (protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) { if (ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) {
err = bt_hids_boot_kb_inp_rep_send(&hids_obj, err = bt_hids_boot_kb_inp_rep_send(&hids_obj,
active_conn, ctx.active_conn,
event->dyndata.data, event->dyndata.data,
(uint8_t)event->dyndata.size, (uint8_t)event->dyndata.size,
hid_report_complete_cb); hid_report_complete_cb);
} else { } else {
err = bt_hids_inp_rep_send(&hids_obj, err = bt_hids_inp_rep_send(&hids_obj,
active_conn, ctx.active_conn,
BLE_HID_KEYS_REPORT_IDX, BLE_HID_KEYS_REPORT_IDX,
event->dyndata.data, event->dyndata.data,
(uint8_t)event->dyndata.size, (uint8_t)event->dyndata.size,
@@ -360,7 +388,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
} }
if (err) { if (err) {
in_flight.active = false; ctx.in_flight.active = false;
LOG_WRN("BLE keyboard report submit failed (%d)", err); LOG_WRN("BLE keyboard report submit failed (%d)", err);
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED, submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
KEYBOARD_REPORT_TYPE_KEYS, KEYBOARD_REPORT_TYPE_KEYS,
@@ -371,23 +399,23 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
} }
if (event->report_type == KEYBOARD_REPORT_TYPE_CONSUMER) { if (event->report_type == KEYBOARD_REPORT_TYPE_CONSUMER) {
if (protocol_mode != KEYBOARD_PROTOCOL_MODE_REPORT) { if (ctx.protocol_mode != KEYBOARD_PROTOCOL_MODE_REPORT) {
LOG_WRN("Drop BLE consumer report in boot mode"); LOG_WRN("Drop BLE consumer report in boot mode");
return false; return false;
} }
in_flight.active = true; ctx.in_flight.active = true;
in_flight.report_type = event->report_type; ctx.in_flight.report_type = event->report_type;
in_flight.sequence = event->sequence; ctx.in_flight.sequence = event->sequence;
err = bt_hids_inp_rep_send(&hids_obj, err = bt_hids_inp_rep_send(&hids_obj,
active_conn, ctx.active_conn,
BLE_HID_CONSUMER_REPORT_IDX, BLE_HID_CONSUMER_REPORT_IDX,
event->dyndata.data, event->dyndata.data,
(uint8_t)event->dyndata.size, (uint8_t)event->dyndata.size,
hid_report_complete_cb); hid_report_complete_cb);
if (err) { if (err) {
in_flight.active = false; ctx.in_flight.active = false;
LOG_WRN("BLE consumer report submit failed (%d)", err); LOG_WRN("BLE consumer report submit failed (%d)", err);
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED, submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
KEYBOARD_REPORT_TYPE_CONSUMER, KEYBOARD_REPORT_TYPE_CONSUMER,
@@ -410,48 +438,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh); const struct module_state_event *event = cast_module_state_event(aeh);
int err;
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (!initialized) { (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -13,6 +13,7 @@
#include <zephyr/bluetooth/services/nus.h> #include <zephyr/bluetooth/services/nus.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include "module_lifecycle.h"
#include "proto_rx_event.h" #include "proto_rx_event.h"
#include "proto_transport_state_event.h" #include "proto_transport_state_event.h"
#include "proto_tx_event.h" #include "proto_tx_event.h"
@@ -27,20 +28,85 @@ enum ble_nus_business_state {
}; };
struct ble_nus_ctx { struct ble_nus_ctx {
enum module_state lifecycle; struct module_lifecycle_ctx lc;
enum ble_nus_business_state business; enum ble_nus_business_state business;
struct bt_conn *active_conn; struct bt_conn *active_conn;
}; };
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 ble_nus_ctx ctx = { static struct ble_nus_ctx ctx = {
.lifecycle = MODULE_STATE_OFF, .lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.business = BLE_NUS_STACK_OFFLINE, .business = BLE_NUS_STACK_OFFLINE,
.active_conn = NULL, .active_conn = NULL,
}; };
static const char *lifecycle_name(enum module_lifecycle state)
{
switch (state) {
case LC_UNINIT:
return "UNINIT";
case LC_RUNNING:
return "RUNNING";
case LC_STOPPED:
return "STOPPED";
case LC_SUSPENDED:
return "SUSPENDED";
case LC_ERROR:
return "ERROR";
default:
return "?";
}
}
static const char *business_state_name(enum ble_nus_business_state state)
{
switch (state) {
case BLE_NUS_STACK_OFFLINE:
return "STACK_OFFLINE";
case BLE_NUS_IDLE:
return "IDLE";
case BLE_NUS_WAIT_NOTIFY:
return "WAIT_NOTIFY";
case BLE_NUS_SESSION_READY:
return "SESSION_READY";
default:
return "?";
}
}
static const char *link_state_name(enum proto_transport_link_state state)
{
switch (state) {
case PROTO_TRANSPORT_LINK_DOWN:
return "DOWN";
case PROTO_TRANSPORT_LINK_READY:
return "READY";
default:
return "?";
}
}
static bool lifecycle_is_ready(void) static bool lifecycle_is_ready(void)
{ {
return ctx.lifecycle == MODULE_STATE_READY; return module_lifecycle_is_running(&ctx.lc);
} }
static enum proto_transport_link_state transport_link_state_get(void) static enum proto_transport_link_state transport_link_state_get(void)
@@ -51,11 +117,11 @@ static enum proto_transport_link_state transport_link_state_get(void)
PROTO_TRANSPORT_LINK_DOWN; PROTO_TRANSPORT_LINK_DOWN;
} }
static void state_reconcile(enum module_state old_lifecycle, static void state_reconcile(enum module_lifecycle old_lifecycle,
enum ble_nus_business_state old_business) enum ble_nus_business_state old_business)
{ {
enum proto_transport_link_state old_link = enum proto_transport_link_state old_link =
((old_lifecycle == MODULE_STATE_READY) && ((old_lifecycle == LC_RUNNING) &&
(old_business == BLE_NUS_SESSION_READY)) ? (old_business == BLE_NUS_SESSION_READY)) ?
PROTO_TRANSPORT_LINK_READY : PROTO_TRANSPORT_LINK_READY :
PROTO_TRANSPORT_LINK_DOWN; PROTO_TRANSPORT_LINK_DOWN;
@@ -67,29 +133,18 @@ static void state_reconcile(enum module_state old_lifecycle,
} }
} }
static void lifecycle_set(enum module_state new_state)
{
enum module_state old_lifecycle = ctx.lifecycle;
enum ble_nus_business_state old_business = ctx.business;
if (ctx.lifecycle == new_state) {
return;
}
ctx.lifecycle = new_state;
state_reconcile(old_lifecycle, old_business);
module_set_state(new_state);
}
static void business_state_set(enum ble_nus_business_state new_state) static void business_state_set(enum ble_nus_business_state new_state)
{ {
enum module_state old_lifecycle = ctx.lifecycle; enum module_lifecycle old_lifecycle = ctx.lc.state;
enum ble_nus_business_state old_business = ctx.business; enum ble_nus_business_state old_business = ctx.business;
if (ctx.business == new_state) { if (ctx.business == new_state) {
return; return;
} }
LOG_INF("BLE NUS business %s -> %s",
business_state_name(ctx.business),
business_state_name(new_state));
ctx.business = new_state; ctx.business = new_state;
state_reconcile(old_lifecycle, old_business); state_reconcile(old_lifecycle, old_business);
} }
@@ -130,6 +185,11 @@ static void received(struct bt_conn *conn, const void *data, uint16_t len,
if (!lifecycle_is_ready() || (ctx.business == BLE_NUS_STACK_OFFLINE) || if (!lifecycle_is_ready() || (ctx.business == BLE_NUS_STACK_OFFLINE) ||
(conn != ctx.active_conn)) { (conn != ctx.active_conn)) {
LOG_WRN("BLE NUS drop RX len:%u lc:%s business:%s active_conn:%p conn:%p link:%s",
len, lifecycle_name(ctx.lc.state),
business_state_name(ctx.business),
(void *)ctx.active_conn, (void *)conn,
link_state_name(transport_link_state_get()));
return; return;
} }
@@ -150,7 +210,7 @@ static void reset_connection_state(void)
} }
} }
static int module_init(void) static int do_init(void)
{ {
int err; int err;
@@ -160,23 +220,36 @@ static int module_init(void)
return err; return err;
} }
ctx = (struct ble_nus_ctx) { ctx.business = BLE_NUS_STACK_OFFLINE;
.lifecycle = MODULE_STATE_OFF, ctx.active_conn = NULL;
.business = BLE_NUS_STACK_OFFLINE,
.active_conn = NULL,
};
return 0; return 0;
} }
static void module_start(void) static int do_start(void)
{ {
lifecycle_set(MODULE_STATE_READY); return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
lifecycle_set(MODULE_STATE_STANDBY); return 0;
}
static int apply_lifecycle(enum module_lifecycle target)
{
enum module_lifecycle old_lifecycle = ctx.lc.state;
enum ble_nus_business_state old_business = ctx.business;
int err = module_set_lifecycle(&ctx.lc, target);
if (!err) {
state_reconcile(old_lifecycle, old_business);
} else {
LOG_WRN("BLE NUS lifecycle change failed target:%s err:%d",
lifecycle_name(target), err);
}
return err;
} }
static bool handle_ble_peer_event(const struct ble_peer_event *event) static bool handle_ble_peer_event(const struct ble_peer_event *event)
@@ -243,27 +316,13 @@ static bool app_event_handler(const struct app_event_header *aeh)
cast_module_state_event(aeh); cast_module_state_event(aeh);
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (ctx.lifecycle == MODULE_STATE_OFF) { (void)apply_lifecycle(LC_RUNNING);
int err = module_init();
if (err) {
lifecycle_set(MODULE_STATE_ERROR);
return false;
}
}
module_start();
return false; return false;
} }
if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
business_state_set_stack_ready(); business_state_set_stack_ready();
if (lifecycle_is_ready()) {
lifecycle_set(MODULE_STATE_READY);
}
return false; return false;
} }
@@ -271,16 +330,16 @@ static bool app_event_handler(const struct app_event_header *aeh)
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (ctx.lifecycle != MODULE_STATE_OFF) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)apply_lifecycle(LC_STOPPED);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (ctx.lifecycle != MODULE_STATE_OFF) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_start(); (void)apply_lifecycle(LC_RUNNING);
} }
return false; return false;

View File

@@ -16,6 +16,7 @@
#include "bat_state_event.h" #include "bat_state_event.h"
#include "datetime_event.h" #include "datetime_event.h"
#include "hid_led_event.h" #include "hid_led_event.h"
#include "module_lifecycle.h"
#include "mode_switch_event.h" #include "mode_switch_event.h"
#include "theme_rgb_update_event.h" #include "theme_rgb_update_event.h"
#include "theme_color.h" #include "theme_color.h"
@@ -27,46 +28,74 @@ BUILD_ASSERT(DT_HAS_CHOSEN(zephyr_display), "Missing zephyr,display chosen node"
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_ALIAS(backlight), okay), BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_ALIAS(backlight), okay),
"Missing backlight alias"); "Missing backlight alias");
static const struct device *const display_dev = struct display_module_ctx {
DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); struct module_lifecycle_ctx lc;
static const struct device *const backlight_dev = const struct device *display_dev;
DEVICE_DT_GET(DT_PARENT(DT_ALIAS(backlight))); const struct device *backlight_dev;
static const uint32_t backlight_idx = DT_NODE_CHILD_IDX(DT_ALIAS(backlight)); uint32_t backlight_idx;
static struct ui_main_model ui_model = { struct ui_main_model ui_model;
bool lvgl_initialized;
char date_text[DATETIME_EVENT_DATE_TEXT_LEN];
char time_text[DATETIME_EVENT_TIME_TEXT_LEN];
};
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 display_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)),
.backlight_dev = DEVICE_DT_GET(DT_PARENT(DT_ALIAS(backlight))),
.backlight_idx = DT_NODE_CHILD_IDX(DT_ALIAS(backlight)),
.ui_model = {
.theme_color = LV_COLOR_MAKE(BLINKY_THEME_DEFAULT_R, .theme_color = LV_COLOR_MAKE(BLINKY_THEME_DEFAULT_R,
BLINKY_THEME_DEFAULT_G, BLINKY_THEME_DEFAULT_G,
BLINKY_THEME_DEFAULT_B), BLINKY_THEME_DEFAULT_B),
.inactive_border_color = LV_COLOR_MAKE(0x3A, 0x44, 0x52), .inactive_border_color = LV_COLOR_MAKE(0x3A, 0x44, 0x52),
.mode = MODE_SWITCH_BLE, .mode = MODE_SWITCH_BLE,
},
.date_text = "1970/01/01",
.time_text = "00:00:00",
}; };
static bool initialized;
static bool running;
static bool lvgl_initialized;
static char date_text[DATETIME_EVENT_DATE_TEXT_LEN] = "1970/01/01";
static char time_text[DATETIME_EVENT_TIME_TEXT_LEN] = "00:00:00";
static int backlight_set(bool on) static int backlight_set(bool on)
{ {
if (on) { if (on) {
return led_on(backlight_dev, backlight_idx); return led_on(ctx.backlight_dev, ctx.backlight_idx);
} }
return led_off(backlight_dev, backlight_idx); return led_off(ctx.backlight_dev, ctx.backlight_idx);
} }
static int module_init(void) static int do_init(void)
{ {
int err; int err;
LOG_INF("Display init on %s", display_dev->name); LOG_INF("Display init on %s", ctx.display_dev->name);
if (!device_is_ready(display_dev)) { if (!device_is_ready(ctx.display_dev)) {
LOG_ERR("Display device %s not ready", display_dev->name); LOG_ERR("Display device %s not ready", ctx.display_dev->name);
return -ENODEV; return -ENODEV;
} }
if (!device_is_ready(backlight_dev)) { if (!device_is_ready(ctx.backlight_dev)) {
LOG_ERR("Backlight device %s not ready", backlight_dev->name); LOG_ERR("Backlight device %s not ready", ctx.backlight_dev->name);
return -ENODEV; return -ENODEV;
} }
@@ -79,25 +108,25 @@ static int module_init(void)
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
int err; int err;
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
if (!lvgl_initialized) { if (!ctx.lvgl_initialized) {
err = lvgl_init(); err = lvgl_init();
if (err) { if (err) {
LOG_ERR("lvgl_init failed (%d)", err); LOG_ERR("lvgl_init failed (%d)", err);
return err; return err;
} }
lvgl_initialized = true; ctx.lvgl_initialized = true;
lvgl_lock(); lvgl_lock();
ui_main_init(&ui_model, date_text, time_text); ui_main_init(&ctx.ui_model, ctx.date_text, ctx.time_text);
lvgl_unlock(); lvgl_unlock();
} }
@@ -107,39 +136,39 @@ static int module_start(void)
return err; return err;
} }
err = display_blanking_off(display_dev); err = display_blanking_off(ctx.display_dev);
if (err) { if (err) {
LOG_ERR("display_blanking_off failed (%d)", err); LOG_ERR("display_blanking_off failed (%d)", err);
(void)backlight_set(false); (void)backlight_set(false);
return err; return err;
} }
running = true;
LOG_INF("LVGL display started"); LOG_INF("LVGL display started");
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
(void)display_blanking_on(display_dev); (void)display_blanking_on(ctx.display_dev);
(void)backlight_set(false); (void)backlight_set(false);
running = false;
LOG_INF("LVGL display paused"); LOG_INF("LVGL display paused");
return 0;
} }
static void refresh_ui(void) static void refresh_ui(void)
{ {
if (!lvgl_initialized) { if (!ctx.lvgl_initialized) {
return; return;
} }
lvgl_lock(); lvgl_lock();
ui_main_refresh_all(&ui_model, date_text, time_text); ui_main_refresh_all(&ctx.ui_model, ctx.date_text, ctx.time_text);
lvgl_unlock(); lvgl_unlock();
} }
@@ -148,9 +177,9 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_bat_state_event(aeh)) { if (is_bat_state_event(aeh)) {
const struct bat_state_event *event = cast_bat_state_event(aeh); const struct bat_state_event *event = cast_bat_state_event(aeh);
ui_model.battery_level = event->soc; ctx.ui_model.battery_level = event->soc;
ui_model.charging = event->charging; ctx.ui_model.charging = event->charging;
ui_model.full = event->full; ctx.ui_model.full = event->full;
refresh_ui(); refresh_ui();
return false; return false;
} }
@@ -158,7 +187,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_mode_switch_event(aeh)) { if (is_mode_switch_event(aeh)) {
const struct mode_switch_event *event = cast_mode_switch_event(aeh); const struct mode_switch_event *event = cast_mode_switch_event(aeh);
ui_model.mode = event->mode; ctx.ui_model.mode = event->mode;
refresh_ui(); refresh_ui();
return false; return false;
} }
@@ -166,7 +195,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_hid_led_event(aeh)) { if (is_hid_led_event(aeh)) {
const struct hid_led_event *event = cast_hid_led_event(aeh); const struct hid_led_event *event = cast_hid_led_event(aeh);
ui_model.led_mask = event->led_bm; ctx.ui_model.led_mask = event->led_bm;
refresh_ui(); refresh_ui();
return false; return false;
} }
@@ -175,7 +204,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
const struct theme_rgb_update_event *event = const struct theme_rgb_update_event *event =
cast_theme_rgb_update_event(aeh); cast_theme_rgb_update_event(aeh);
ui_model.theme_color = (lv_color_t)LV_COLOR_MAKE(event->theme.r, ctx.ui_model.theme_color = (lv_color_t)LV_COLOR_MAKE(event->theme.r,
event->theme.g, event->theme.g,
event->theme.b); event->theme.b);
refresh_ui(); refresh_ui();
@@ -185,58 +214,35 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_datetime_event(aeh)) { if (is_datetime_event(aeh)) {
const struct datetime_event *event = cast_datetime_event(aeh); const struct datetime_event *event = cast_datetime_event(aeh);
strncpy(date_text, event->date_text, sizeof(date_text)); strncpy(ctx.date_text, event->date_text, sizeof(ctx.date_text));
date_text[sizeof(date_text) - 1] = '\0'; ctx.date_text[sizeof(ctx.date_text) - 1] = '\0';
strncpy(time_text, event->time_text, sizeof(time_text)); strncpy(ctx.time_text, event->time_text, sizeof(ctx.time_text));
time_text[sizeof(time_text) - 1] = '\0'; ctx.time_text[sizeof(ctx.time_text) - 1] = '\0';
refresh_ui(); refresh_ui();
return false; return false;
} }
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh); const struct module_state_event *event = cast_module_state_event(aeh);
int err;
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (!initialized) { (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -13,6 +13,7 @@
#include <zephyr/pm/device.h> #include <zephyr/pm/device.h>
#include "encoder_event.h" #include "encoder_event.h"
#include "module_lifecycle.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
@@ -22,17 +23,41 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
BUILD_ASSERT(DT_NODE_EXISTS(ENCODER_QDEC_NODE), "Missing qdec0 alias"); BUILD_ASSERT(DT_NODE_EXISTS(ENCODER_QDEC_NODE), "Missing qdec0 alias");
static const struct device *const qdec_dev = DEVICE_DT_GET(ENCODER_QDEC_NODE); struct encoder_module_ctx {
struct module_lifecycle_ctx lc;
static struct k_work encoder_report_work; const struct device *qdec_dev;
static struct sensor_trigger encoder_trigger = { struct k_work encoder_report_work;
.type = SENSOR_TRIG_DATA_READY, struct sensor_trigger encoder_trigger;
.chan = SENSOR_CHAN_ROTATION, int64_t angle_remainder_udeg;
}; };
static bool initialized; static int do_init(void);
static bool running; static int do_start(void);
static int64_t angle_remainder_udeg; 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 encoder_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.qdec_dev = DEVICE_DT_GET(ENCODER_QDEC_NODE),
.encoder_trigger = {
.type = SENSOR_TRIG_DATA_READY,
.chan = SENSOR_CHAN_ROTATION,
},
};
static int64_t sensor_value_to_udeg(const struct sensor_value *value) static int64_t sensor_value_to_udeg(const struct sensor_value *value)
{ {
@@ -68,25 +93,26 @@ static void encoder_report_work_handler(struct k_work *work)
ARG_UNUSED(work); ARG_UNUSED(work);
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return;
} }
err = sensor_sample_fetch(qdec_dev); err = sensor_sample_fetch(ctx.qdec_dev);
if (err) { if (err) {
LOG_WRN("QDEC sample fetch failed (%d)", err); LOG_WRN("QDEC sample fetch failed (%d)", err);
return; return;
} }
err = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &rotation); err = sensor_channel_get(ctx.qdec_dev, SENSOR_CHAN_ROTATION, &rotation);
if (err) { if (err) {
LOG_WRN("QDEC channel get failed (%d)", err); LOG_WRN("QDEC channel get failed (%d)", err);
return; return;
} }
total_udeg = angle_remainder_udeg + sensor_value_to_udeg(&rotation); total_udeg = ctx.angle_remainder_udeg + sensor_value_to_udeg(&rotation);
detents = (int32_t)(total_udeg / ENCODER_DETENT_UDEG); detents = (int32_t)(total_udeg / ENCODER_DETENT_UDEG);
angle_remainder_udeg = total_udeg - ((int64_t)detents * ENCODER_DETENT_UDEG); ctx.angle_remainder_udeg =
total_udeg - ((int64_t)detents * ENCODER_DETENT_UDEG);
if (detents != 0) { if (detents != 0) {
submit_detents_batched(detents); submit_detents_batched(detents);
@@ -99,26 +125,27 @@ static void encoder_trigger_handler(const struct device *dev,
ARG_UNUSED(dev); ARG_UNUSED(dev);
ARG_UNUSED(trigger); ARG_UNUSED(trigger);
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return;
} }
k_work_submit(&encoder_report_work); k_work_submit(&ctx.encoder_report_work);
} }
static int module_init(void) static int do_init(void)
{ {
int err; int err;
if (!device_is_ready(qdec_dev)) { if (!device_is_ready(ctx.qdec_dev)) {
LOG_ERR("QDEC device not ready"); LOG_ERR("QDEC device not ready");
return -ENODEV; return -ENODEV;
} }
k_work_init(&encoder_report_work, encoder_report_work_handler); k_work_init(&ctx.encoder_report_work, encoder_report_work_handler);
angle_remainder_udeg = 0; ctx.angle_remainder_udeg = 0;
err = sensor_trigger_set(qdec_dev, &encoder_trigger, encoder_trigger_handler); err = sensor_trigger_set(ctx.qdec_dev, &ctx.encoder_trigger,
encoder_trigger_handler);
if (err) { if (err) {
LOG_ERR("Cannot set QDEC trigger (%d)", err); LOG_ERR("Cannot set QDEC trigger (%d)", err);
return err; return err;
@@ -127,41 +154,41 @@ static int module_init(void)
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
int err; int err;
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
err = pm_device_action_run(qdec_dev, PM_DEVICE_ACTION_RESUME); err = pm_device_action_run(ctx.qdec_dev, PM_DEVICE_ACTION_RESUME);
if (err && (err != -EALREADY) && (err != -ENOTSUP)) { if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
LOG_ERR("Cannot resume QDEC device (%d)", err); LOG_ERR("Cannot resume QDEC device (%d)", err);
return err; return err;
} }
angle_remainder_udeg = 0; ctx.angle_remainder_udeg = 0;
running = true;
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
int err; int err;
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
err = pm_device_action_run(qdec_dev, PM_DEVICE_ACTION_SUSPEND); err = pm_device_action_run(ctx.qdec_dev, PM_DEVICE_ACTION_SUSPEND);
if (err && (err != -EALREADY) && (err != -ENOTSUP)) { if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
LOG_WRN("Cannot suspend QDEC device (%d)", err); LOG_WRN("Cannot suspend QDEC device (%d)", err);
} }
angle_remainder_udeg = 0; ctx.angle_remainder_udeg = 0;
running = false;
return 0;
} }
static bool app_event_handler(const struct app_event_header *aeh) static bool app_event_handler(const struct app_event_header *aeh)
@@ -170,47 +197,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
const struct module_state_event *event = cast_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)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err; (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -7,6 +7,8 @@
static const char *mode_name(enum mode_switch_mode mode) static const char *mode_name(enum mode_switch_mode mode)
{ {
switch (mode) { switch (mode) {
case MODE_SWITCH_INVALID:
return "INVALID";
case MODE_SWITCH_USB: case MODE_SWITCH_USB:
return "USB"; return "USB";
case MODE_SWITCH_24G: case MODE_SWITCH_24G:

View File

@@ -5,6 +5,8 @@
static const char *mode_name(enum mode_switch_mode mode) static const char *mode_name(enum mode_switch_mode mode)
{ {
switch (mode) { switch (mode) {
case MODE_SWITCH_INVALID:
return "INVALID";
case MODE_SWITCH_USB: case MODE_SWITCH_USB:
return "USB"; return "USB";
case MODE_SWITCH_24G: case MODE_SWITCH_24G:

View File

@@ -15,6 +15,7 @@
#include "hid_tx_report_event.h" #include "hid_tx_report_event.h"
#include "keyboard_core.h" #include "keyboard_core.h"
#include "keyboard_hid_report_event.h" #include "keyboard_hid_report_event.h"
#include "module_lifecycle.h"
#include "mode_switch_event.h" #include "mode_switch_event.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
@@ -49,7 +50,42 @@ struct in_flight_report {
uint16_t sequence; uint16_t sequence;
}; };
static struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT] = { struct hid_flowctrl_module_ctx {
struct module_lifecycle_ctx lc;
struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT];
struct pending_report pending_keys;
struct pending_report pending_consumer_latest;
struct queued_report consumer_fifo[HID_FLOWCTRL_FIFO_DEPTH];
uint8_t consumer_fifo_head;
uint8_t consumer_fifo_tail;
uint8_t consumer_fifo_count;
struct in_flight_report in_flight[HID_SEND_CH_COUNT];
enum mode_switch_mode current_mode;
uint16_t next_sequence;
};
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 hid_flowctrl_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.channel_state = {
[HID_SEND_CH_USB_KEYS] = { [HID_SEND_CH_USB_KEYS] = {
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
}, },
@@ -59,18 +95,21 @@ static struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT] = {
[HID_SEND_CH_BLE_SHARED] = { [HID_SEND_CH_BLE_SHARED] = {
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
}, },
},
}; };
static struct pending_report pending_keys;
static struct pending_report pending_consumer_latest; #define lifecycle ctx.lc
static struct queued_report consumer_fifo[HID_FLOWCTRL_FIFO_DEPTH]; #define channel_state ctx.channel_state
static uint8_t consumer_fifo_head; #define pending_keys ctx.pending_keys
static uint8_t consumer_fifo_tail; #define pending_consumer_latest ctx.pending_consumer_latest
static uint8_t consumer_fifo_count; #define consumer_fifo ctx.consumer_fifo
static struct in_flight_report in_flight[HID_SEND_CH_COUNT]; #define consumer_fifo_head ctx.consumer_fifo_head
static enum mode_switch_mode current_mode; #define consumer_fifo_tail ctx.consumer_fifo_tail
static uint16_t next_sequence; #define consumer_fifo_count ctx.consumer_fifo_count
static bool initialized; #define in_flight ctx.in_flight
static bool running; #define current_mode ctx.current_mode
#define next_sequence ctx.next_sequence
#define running module_lifecycle_is_running(&ctx.lc)
static bool current_mode_to_channel(enum keyboard_report_type report_type, static bool current_mode_to_channel(enum keyboard_report_type report_type,
enum hid_send_channel *channel) enum hid_send_channel *channel)
@@ -359,7 +398,7 @@ static bool handle_mode_switch_event(const struct mode_switch_event *event)
return false; return false;
} }
static int module_init(void) static int do_init(void)
{ {
clear_pending_reports(); clear_pending_reports();
current_mode = MODE_SWITCH_USB; current_mode = MODE_SWITCH_USB;
@@ -374,25 +413,25 @@ static int module_init(void)
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
if (running) { if (running) {
return 0; return 0;
} }
running = true;
try_send_next(); try_send_next();
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!running) {
return; return 0;
} }
clear_pending_reports(); clear_pending_reports();
running = false;
return 0;
} }
static bool app_event_handler(const struct app_event_header *aeh) static bool app_event_handler(const struct app_event_header *aeh)
@@ -421,47 +460,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
cast_module_state_event(aeh); cast_module_state_event(aeh);
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err; (void)module_set_lifecycle(&lifecycle, LC_RUNNING);
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&lifecycle)) {
module_pause(); (void)module_set_lifecycle(&lifecycle, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&lifecycle)) {
int err = module_start(); (void)module_set_lifecycle(&lifecycle, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -19,6 +19,7 @@
#include "function_bitmap_update_event.h" #include "function_bitmap_update_event.h"
#include "keyboard_core.h" #include "keyboard_core.h"
#include "keyboard_hid_report_event.h" #include "keyboard_hid_report_event.h"
#include "module_lifecycle.h"
#include "mode_switch_event.h" #include "mode_switch_event.h"
#include "set_protocol_event.h" #include "set_protocol_event.h"
@@ -85,17 +86,51 @@ static const uint16_t consumer_usage_map[KEYBOARD_CONSUMER_CTRL_COUNT] = {
[KEYBOARD_CONSUMER_CTRL_PREV_TRACK] = 0x00B6, [KEYBOARD_CONSUMER_CTRL_PREV_TRACK] = 0x00B6,
}; };
static struct keyboard_state keyboard_state; struct keyboard_core_module_ctx {
static struct keyboard_reports_cache reports_cache; struct module_lifecycle_ctx lc;
static uint8_t function_usage_mask[KEYBOARD_PROTOCOL_BITMAP_BYTES]; struct keyboard_state keyboard_state;
static enum keyboard_protocol_mode transport_protocol_modes[HID_TRANSPORT_COUNT] = { struct keyboard_reports_cache reports_cache;
uint8_t function_usage_mask[KEYBOARD_PROTOCOL_BITMAP_BYTES];
enum keyboard_protocol_mode transport_protocol_modes[HID_TRANSPORT_COUNT];
enum mode_switch_mode current_mode;
bool mode_valid;
};
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 keyboard_core_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.transport_protocol_modes = {
[HID_TRANSPORT_USB] = KEYBOARD_PROTOCOL_MODE_REPORT, [HID_TRANSPORT_USB] = KEYBOARD_PROTOCOL_MODE_REPORT,
[HID_TRANSPORT_BLE] = KEYBOARD_PROTOCOL_MODE_REPORT, [HID_TRANSPORT_BLE] = KEYBOARD_PROTOCOL_MODE_REPORT,
},
}; };
static enum mode_switch_mode current_mode;
static bool initialized; #define lifecycle ctx.lc
static bool running; #define keyboard_state ctx.keyboard_state
static bool mode_valid; #define reports_cache ctx.reports_cache
#define function_usage_mask ctx.function_usage_mask
#define transport_protocol_modes ctx.transport_protocol_modes
#define current_mode ctx.current_mode
#define mode_valid ctx.mode_valid
#define running module_lifecycle_is_running(&ctx.lc)
static bool mode_to_transport(enum mode_switch_mode mode, enum hid_transport *transport) static bool mode_to_transport(enum mode_switch_mode mode, enum hid_transport *transport)
{ {
@@ -440,7 +475,7 @@ static void emit_release_reports(enum mode_switch_mode mode)
} }
} }
static int module_init(void) static int do_init(void)
{ {
keyboard_state_clear(); keyboard_state_clear();
reports_cache_invalidate(); reports_cache_invalidate();
@@ -454,20 +489,19 @@ static int module_init(void)
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
if (running) { if (running) {
return 0; return 0;
} }
running = true;
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!running) {
return; return 0;
} }
if (mode_valid) { if (mode_valid) {
@@ -478,7 +512,8 @@ static void module_pause(void)
keyboard_state_clear(); keyboard_state_clear();
reports_cache_invalidate(); reports_cache_invalidate();
mode_valid = false; mode_valid = false;
running = false;
return 0;
} }
static bool handle_button_event(const struct button_event *event) static bool handle_button_event(const struct button_event *event)
@@ -630,47 +665,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
const struct module_state_event *event = cast_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)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err; (void)module_set_lifecycle(&lifecycle, LC_RUNNING);
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&lifecycle)) {
module_pause(); (void)module_set_lifecycle(&lifecycle, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&lifecycle)) {
int err = module_start(); (void)module_set_lifecycle(&lifecycle, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -18,6 +18,7 @@
#include "led_effect/led_effect.h" #include "led_effect/led_effect.h"
#include "led_strip_en_event.h" #include "led_strip_en_event.h"
#include "module_lifecycle.h"
#include "theme_rgb_update_event.h" #include "theme_rgb_update_event.h"
#include "theme_color.h" #include "theme_color.h"
@@ -34,9 +35,16 @@ BUILD_ASSERT(DT_NODE_HAS_PROP(LED_STRIP_NODE, supply_gpios),
BUILD_ASSERT(LED_STRIP_NUM_PIXELS == 17U, BUILD_ASSERT(LED_STRIP_NUM_PIXELS == 17U,
"LED strip key map expects 17 pixels"); "LED strip key map expects 17 pixels");
static const struct device *const strip = DEVICE_DT_GET(LED_STRIP_NODE); struct led_strip_module_ctx {
static const struct gpio_dt_spec strip_en = struct module_lifecycle_ctx lc;
GPIO_DT_SPEC_GET(LED_STRIP_NODE, supply_gpios); const struct device *strip;
struct gpio_dt_spec strip_en;
struct led_rgb pixels[LED_STRIP_NUM_PIXELS];
struct k_work_delayable effect_work;
struct led_effect *effect;
struct theme_rgb current_theme;
bool enabled;
};
static const struct led_key_map led_key_map[] = { static const struct led_key_map led_key_map[] = {
{ KEY_ID(0, 1), 0U }, { KEY_ID(0, 1), 0U },
@@ -65,28 +73,47 @@ static const struct led_effect_config effect_cfg = {
.default_brightness = 0xFFU, .default_brightness = 0xFFU,
}; };
static struct led_rgb pixels[LED_STRIP_NUM_PIXELS]; static int do_init(void);
static struct k_work_delayable effect_work; static int do_start(void);
static struct led_effect *effect; static int do_stop(void);
static struct theme_rgb current_theme = {
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 led_strip_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.strip = DEVICE_DT_GET(LED_STRIP_NODE),
.strip_en = GPIO_DT_SPEC_GET(LED_STRIP_NODE, supply_gpios),
.current_theme = {
.r = BLINKY_THEME_DEFAULT_R, .r = BLINKY_THEME_DEFAULT_R,
.g = BLINKY_THEME_DEFAULT_G, .g = BLINKY_THEME_DEFAULT_G,
.b = BLINKY_THEME_DEFAULT_B, .b = BLINKY_THEME_DEFAULT_B,
},
.enabled = true,
}; };
static bool initialized;
static bool running;
static bool enabled = true;
static void clear_pixels(void) static void clear_pixels(void)
{ {
memset(pixels, 0, sizeof(pixels)); memset(ctx.pixels, 0, sizeof(ctx.pixels));
} }
static int submit_frame(void) static int submit_frame(void)
{ {
int err; int err;
err = led_strip_update_rgb(strip, pixels, ARRAY_SIZE(pixels)); err = led_strip_update_rgb(ctx.strip, ctx.pixels, ARRAY_SIZE(ctx.pixels));
if (err) { if (err) {
LOG_WRN("led_strip_update_rgb failed (%d)", err); LOG_WRN("led_strip_update_rgb failed (%d)", err);
} }
@@ -98,7 +125,7 @@ static int set_strip_power(bool on)
{ {
int err; int err;
err = gpio_pin_set_dt(&strip_en, on ? 1 : 0); err = gpio_pin_set_dt(&ctx.strip_en, on ? 1 : 0);
if (err) { if (err) {
LOG_WRN("LED strip EN set failed (%d)", err); LOG_WRN("LED strip EN set failed (%d)", err);
} }
@@ -114,12 +141,12 @@ static int refresh_idle_frame(void)
static void stop_effect_work(void) static void stop_effect_work(void)
{ {
k_work_cancel_delayable(&effect_work); k_work_cancel_delayable(&ctx.effect_work);
} }
static void schedule_effect_tick(k_timeout_t delay) static void schedule_effect_tick(k_timeout_t delay)
{ {
k_work_reschedule(&effect_work, delay); k_work_reschedule(&ctx.effect_work, delay);
} }
static int enable_strip_output(void) static int enable_strip_output(void)
@@ -148,13 +175,15 @@ static void effect_work_handler(struct k_work *work)
ARG_UNUSED(work); ARG_UNUSED(work);
if (!running || !enabled || (effect == NULL)) { if (!module_lifecycle_is_running(&ctx.lc) || !ctx.enabled ||
(ctx.effect == NULL)) {
return; return;
} }
keep_running = effect->ops->tick(effect, k_ticks_to_ms_floor32( keep_running = ctx.effect->ops->tick(ctx.effect,
k_ticks_to_ms_floor32(
LED_STRIP_TICK_INTERVAL.ticks), LED_STRIP_TICK_INTERVAL.ticks),
pixels, ARRAY_SIZE(pixels)); ctx.pixels, ARRAY_SIZE(ctx.pixels));
(void)submit_frame(); (void)submit_frame();
if (keep_running) { if (keep_running) {
@@ -162,90 +191,85 @@ static void effect_work_handler(struct k_work *work)
} }
} }
static int module_init(void) static int do_init(void)
{ {
int err; int err;
if (!device_is_ready(strip)) { if (!device_is_ready(ctx.strip)) {
LOG_ERR("LED strip device %s not ready", strip->name); LOG_ERR("LED strip device %s not ready", ctx.strip->name);
return -ENODEV; return -ENODEV;
} }
if (!gpio_is_ready_dt(&strip_en)) { if (!gpio_is_ready_dt(&ctx.strip_en)) {
LOG_ERR("LED strip supply GPIO not ready"); LOG_ERR("LED strip supply GPIO not ready");
return -ENODEV; return -ENODEV;
} }
err = gpio_pin_configure_dt(&strip_en, GPIO_OUTPUT_INACTIVE); err = gpio_pin_configure_dt(&ctx.strip_en, GPIO_OUTPUT_INACTIVE);
if (err) { if (err) {
LOG_ERR("Failed to configure LED strip supply GPIO (%d)", err); LOG_ERR("Failed to configure LED strip supply GPIO (%d)", err);
return err; return err;
} }
k_work_init_delayable(&effect_work, effect_work_handler); k_work_init_delayable(&ctx.effect_work, effect_work_handler);
clear_pixels(); clear_pixels();
effect = led_effect_get_mutable(LED_EFFECT_ID_KEY_FADE); ctx.effect = led_effect_get_mutable(LED_EFFECT_ID_KEY_FADE);
if ((effect == NULL) || (effect->ops == NULL)) { if ((ctx.effect == NULL) || (ctx.effect->ops == NULL)) {
LOG_ERR("LED effect not available"); LOG_ERR("LED effect not available");
return -ENOENT; return -ENOENT;
} }
err = effect->ops->init(effect, &effect_cfg); err = ctx.effect->ops->init(ctx.effect, &effect_cfg);
if (err) { if (err) {
LOG_ERR("LED effect init failed (%d)", err); LOG_ERR("LED effect init failed (%d)", err);
return err; return err;
} }
effect->ops->set_theme(effect, &current_theme); ctx.effect->ops->set_theme(ctx.effect, &ctx.current_theme);
LOG_INF("LED strip ready len:%u", (uint32_t)led_strip_length(strip)); LOG_INF("LED strip ready len:%u", (uint32_t)led_strip_length(ctx.strip));
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
int err; int err;
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
running = true; if (!ctx.enabled) {
if (!enabled) {
return 0; return 0;
} }
err = enable_strip_output(); err = enable_strip_output();
if (err) {
running = false;
}
return err; return err;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
if ((effect != NULL) && (effect->ops != NULL)) { if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) {
effect->ops->reset(effect); ctx.effect->ops->reset(ctx.effect);
} }
disable_strip_output(); disable_strip_output();
running = false; return 0;
} }
static bool handle_button_event(const struct button_event *event) static bool handle_button_event(const struct button_event *event)
{ {
if (!running || !enabled || (effect == NULL) || !event->pressed) { if (!module_lifecycle_is_running(&ctx.lc) || !ctx.enabled ||
(ctx.effect == NULL) || !event->pressed) {
return false; return false;
} }
effect->ops->on_key_press(effect, event->key_id); ctx.effect->ops->on_key_press(ctx.effect, event->key_id);
schedule_effect_tick(K_NO_WAIT); schedule_effect_tick(K_NO_WAIT);
return false; return false;
@@ -253,22 +277,23 @@ static bool handle_button_event(const struct button_event *event)
static bool handle_led_strip_en_event(const struct led_strip_en_event *event) static bool handle_led_strip_en_event(const struct led_strip_en_event *event)
{ {
enabled = event->enabled; ctx.enabled = event->enabled;
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return false; return false;
} }
if (enabled) { if (ctx.enabled) {
int err = enable_strip_output(); int err = enable_strip_output();
if (err) { if (err) {
module_set_state(MODULE_STATE_ERROR); LOG_WRN("LED strip enable request failed (%d)", err);
ctx.enabled = false;
return false; return false;
} }
} else { } else {
if ((effect != NULL) && (effect->ops != NULL)) { if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) {
effect->ops->reset(effect); ctx.effect->ops->reset(ctx.effect);
} }
disable_strip_output(); disable_strip_output();
@@ -279,13 +304,14 @@ static bool handle_led_strip_en_event(const struct led_strip_en_event *event)
static bool handle_theme_rgb_update_event(const struct theme_rgb_update_event *event) static bool handle_theme_rgb_update_event(const struct theme_rgb_update_event *event)
{ {
current_theme = event->theme; ctx.current_theme = event->theme;
if ((effect != NULL) && (effect->ops != NULL)) { if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) {
effect->ops->set_theme(effect, &current_theme); ctx.effect->ops->set_theme(ctx.effect, &ctx.current_theme);
} }
if (running && enabled && (effect != NULL) && effect->ops->is_active(effect)) { if (module_lifecycle_is_running(&ctx.lc) && ctx.enabled &&
(ctx.effect != NULL) && ctx.effect->ops->is_active(ctx.effect)) {
schedule_effect_tick(K_NO_WAIT); schedule_effect_tick(K_NO_WAIT);
} }
@@ -310,47 +336,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
const struct module_state_event *event = cast_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)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err; (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -9,82 +9,152 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include "module_lifecycle.h"
#include "mode_switch_event.h" #include "mode_switch_event.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
static bool initialized; struct mode_policy_module_ctx {
static bool running; struct module_lifecycle_ctx lc;
static bool ble_adv_suspended = true; enum mode_switch_mode active_mode;
static bool usb_enabled; };
static void broadcast_ble_adv_req(bool suspend) 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_policy_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.active_mode = MODE_SWITCH_USB,
};
static void mode_policy_set_ble(bool enable)
{ {
if (suspend) { if (enable) {
struct module_suspend_req_event *event = new_module_suspend_req_event();
event->sink_module_id = MODULE_ID(ble_adv);
event->src_module_id = MODULE_ID(MODULE);
APP_EVENT_SUBMIT(event);
} else {
struct module_resume_req_event *event = new_module_resume_req_event(); struct module_resume_req_event *event = new_module_resume_req_event();
event->sink_module_id = MODULE_ID(ble_adv);
event->src_module_id = MODULE_ID(MODULE);
APP_EVENT_SUBMIT(event);
} else {
struct module_suspend_req_event *event = new_module_suspend_req_event();
event->sink_module_id = MODULE_ID(ble_adv); event->sink_module_id = MODULE_ID(ble_adv);
event->src_module_id = MODULE_ID(MODULE); event->src_module_id = MODULE_ID(MODULE);
APP_EVENT_SUBMIT(event); APP_EVENT_SUBMIT(event);
} }
} }
static void apply_mode_policy(enum mode_switch_mode mode) static void mode_policy_set_usb(bool enable)
{ {
bool should_suspend_ble_adv = (mode != MODE_SWITCH_BLE); if (enable) {
bool should_enable_usb = (mode == MODE_SWITCH_USB); struct module_resume_req_event *event = new_module_resume_req_event();
if (should_suspend_ble_adv != ble_adv_suspended) {
ble_adv_suspended = should_suspend_ble_adv;
broadcast_ble_adv_req(should_suspend_ble_adv);
}
if (should_enable_usb != usb_enabled) {
usb_enabled = should_enable_usb;
if (usb_enabled) {
struct module_resume_req_event *event =
new_module_resume_req_event();
event->sink_module_id = MODULE_ID(usb_device_module); event->sink_module_id = MODULE_ID(usb_device_module);
event->src_module_id = MODULE_ID(MODULE); event->src_module_id = MODULE_ID(MODULE);
APP_EVENT_SUBMIT(event); APP_EVENT_SUBMIT(event);
} else { } else {
struct module_suspend_req_event *event = struct module_suspend_req_event *event = new_module_suspend_req_event();
new_module_suspend_req_event();
event->sink_module_id = MODULE_ID(usb_device_module); event->sink_module_id = MODULE_ID(usb_device_module);
event->src_module_id = MODULE_ID(MODULE); event->src_module_id = MODULE_ID(MODULE);
APP_EVENT_SUBMIT(event); APP_EVENT_SUBMIT(event);
} }
}
static void apply_active_mode(void)
{
switch (ctx.active_mode) {
case MODE_SWITCH_BLE:
mode_policy_set_ble(true);
mode_policy_set_usb(false);
break;
case MODE_SWITCH_USB:
mode_policy_set_ble(false);
mode_policy_set_usb(true);
break;
case MODE_SWITCH_24G:
mode_policy_set_ble(false);
mode_policy_set_usb(false);
break;
default:
break;
} }
} }
static int module_init(void) static void apply_ble_mode_policy(void)
{ {
ble_adv_suspended = true; switch (ctx.active_mode) {
usb_enabled = false; case MODE_SWITCH_BLE:
return 0; mode_policy_set_ble(true);
} break;
static int module_start(void) case MODE_SWITCH_USB:
{ mode_policy_set_ble(false);
if (running) { break;
return 0;
case MODE_SWITCH_24G:
mode_policy_set_ble(false);
break;
default:
break;
} }
}
running = true; static void apply_usb_mode_policy(void)
{
switch (ctx.active_mode) {
case MODE_SWITCH_BLE:
mode_policy_set_usb(false);
break;
case MODE_SWITCH_USB:
mode_policy_set_usb(true);
break;
case MODE_SWITCH_24G:
mode_policy_set_usb(false);
break;
default:
break;
}
}
static int do_init(void)
{
ctx.active_mode = MODE_SWITCH_USB;
return 0; return 0;
} }
static void module_pause(void) static int do_start(void)
{ {
running = false; apply_active_mode();
return 0;
}
static int do_stop(void)
{
return 0;
} }
static bool app_event_handler(const struct app_event_header *aeh) static bool app_event_handler(const struct app_event_header *aeh)
@@ -92,8 +162,9 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_mode_switch_event(aeh)) { if (is_mode_switch_event(aeh)) {
const struct mode_switch_event *event = cast_mode_switch_event(aeh); const struct mode_switch_event *event = cast_mode_switch_event(aeh);
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
apply_mode_policy(event->mode); ctx.active_mode = event->mode;
apply_active_mode();
} }
return false; return false;
@@ -103,23 +174,21 @@ static bool app_event_handler(const struct app_event_header *aeh)
const struct module_state_event *event = cast_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)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err; (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false; return false;
} }
initialized = true; if (check_state(event, MODULE_ID(ble_adv), MODULE_STATE_READY)) {
if (module_lifecycle_is_running(&ctx.lc)) {
apply_ble_mode_policy();
}
return false;
} }
err = module_start(); if (check_state(event, MODULE_ID(usb_device_module),
if (err) { MODULE_STATE_READY)) {
module_set_state(MODULE_STATE_ERROR); if (module_lifecycle_is_running(&ctx.lc)) {
} else { apply_usb_mode_policy();
module_set_state(MODULE_STATE_READY);
} }
} }
@@ -127,23 +196,16 @@ static bool app_event_handler(const struct app_event_header *aeh)
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -14,6 +14,7 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/pm/device.h> #include <zephyr/pm/device.h>
#include "module_lifecycle.h"
#include "mode_switch_event.h" #include "mode_switch_event.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
@@ -26,15 +27,36 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
BUILD_ASSERT(DT_NODE_EXISTS(MODE_SWITCH_ADC_NODE), BUILD_ASSERT(DT_NODE_EXISTS(MODE_SWITCH_ADC_NODE),
"Missing mode_switch_adc node in devicetree"); "Missing mode_switch_adc node in devicetree");
static const struct device *const mode_switch_adc_dev = struct mode_switch_module_ctx {
DEVICE_DT_GET(MODE_SWITCH_ADC_NODE); 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 struct k_work_delayable mode_switch_sample_work; static int do_init(void);
static bool initialized; static int do_start(void);
static bool running; static int do_stop(void);
static bool force_report;
static bool mode_valid; static const struct module_lifecycle_cfg lifecycle_cfg = {
static enum mode_switch_mode last_mode; .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) static enum mode_switch_mode detect_mode(uint16_t voltage_mv)
{ {
@@ -53,7 +75,7 @@ static int mode_switch_enable(bool enable)
{ {
enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME
: PM_DEVICE_ACTION_SUSPEND; : PM_DEVICE_ACTION_SUSPEND;
int err = pm_device_action_run(mode_switch_adc_dev, action); int err = pm_device_action_run(ctx.mode_switch_adc_dev, action);
if (err && (err != -EALREADY) && (err != -ENOTSUP)) { if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
LOG_ERR("Cannot %s mode switch ADC (%d)", LOG_ERR("Cannot %s mode switch ADC (%d)",
@@ -71,17 +93,18 @@ static void mode_switch_sample_fn(struct k_work *work)
ARG_UNUSED(work); ARG_UNUSED(work);
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return;
} }
err = sensor_sample_fetch(mode_switch_adc_dev); err = sensor_sample_fetch(ctx.mode_switch_adc_dev);
if (err) { if (err) {
LOG_WRN("Mode switch ADC sample fetch failed (%d)", err); LOG_WRN("Mode switch ADC sample fetch failed (%d)", err);
goto reschedule; goto reschedule;
} }
err = sensor_channel_get(mode_switch_adc_dev, SENSOR_CHAN_VOLTAGE, &voltage); err = sensor_channel_get(ctx.mode_switch_adc_dev, SENSOR_CHAN_VOLTAGE,
&voltage);
if (err) { if (err) {
LOG_WRN("Mode switch ADC channel get failed (%d)", err); LOG_WRN("Mode switch ADC channel get failed (%d)", err);
goto reschedule; goto reschedule;
@@ -90,39 +113,37 @@ static void mode_switch_sample_fn(struct k_work *work)
uint16_t sample_mv = (uint16_t)((voltage.val1 * 1000) + (voltage.val2 / 1000)); uint16_t sample_mv = (uint16_t)((voltage.val1 * 1000) + (voltage.val2 / 1000));
enum mode_switch_mode mode = detect_mode(sample_mv); enum mode_switch_mode mode = detect_mode(sample_mv);
if (force_report || !mode_valid || (mode != last_mode)) { if ((ctx.last_mode == MODE_SWITCH_INVALID) || (mode != ctx.last_mode)) {
submit_mode_switch_event(mode, sample_mv); submit_mode_switch_event(mode, sample_mv);
last_mode = mode; ctx.last_mode = mode;
mode_valid = true;
force_report = false;
} }
reschedule: reschedule:
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
k_work_reschedule(&mode_switch_sample_work, MODE_SWITCH_SAMPLE_INTERVAL); k_work_reschedule(&ctx.mode_switch_sample_work,
MODE_SWITCH_SAMPLE_INTERVAL);
} }
} }
static int module_init(void) static int do_init(void)
{ {
if (!device_is_ready(mode_switch_adc_dev)) { if (!device_is_ready(ctx.mode_switch_adc_dev)) {
LOG_ERR("Mode switch ADC device not ready"); LOG_ERR("Mode switch ADC device not ready");
return -ENODEV; return -ENODEV;
} }
k_work_init_delayable(&mode_switch_sample_work, mode_switch_sample_fn); k_work_init_delayable(&ctx.mode_switch_sample_work, mode_switch_sample_fn);
mode_valid = false; ctx.last_mode = MODE_SWITCH_INVALID;
force_report = false;
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
int err; int err;
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
@@ -131,22 +152,21 @@ static int module_start(void)
return err; return err;
} }
running = true; k_work_reschedule(&ctx.mode_switch_sample_work, K_NO_WAIT);
force_report = true;
k_work_reschedule(&mode_switch_sample_work, K_NO_WAIT);
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
(void)k_work_cancel_delayable(&mode_switch_sample_work); (void)k_work_cancel_delayable(&ctx.mode_switch_sample_work);
(void)mode_switch_enable(false); (void)mode_switch_enable(false);
running = false;
return 0;
} }
static bool app_event_handler(const struct app_event_header *aeh) static bool app_event_handler(const struct app_event_header *aeh)
@@ -155,47 +175,32 @@ static bool app_event_handler(const struct app_event_header *aeh)
const struct module_state_event *event = cast_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)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err; (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false; return false;
} }
initialized = true; if (check_state(event, MODULE_ID(mode_policy_module),
} MODULE_STATE_READY)) {
if (ctx.last_mode != MODE_SWITCH_INVALID) {
err = module_start(); submit_mode_switch_event(ctx.last_mode, 0U);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
} }
return false;
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -21,6 +21,7 @@
#include "function_bitmap_state_event.h" #include "function_bitmap_state_event.h"
#include "function_bitmap_update_event.h" #include "function_bitmap_update_event.h"
#include "hid_led_event.h" #include "hid_led_event.h"
#include "module_lifecycle.h"
#include "proto_rx_event.h" #include "proto_rx_event.h"
#include "proto_transport_state_event.h" #include "proto_transport_state_event.h"
#include "proto_tx_event.h" #include "proto_tx_event.h"
@@ -38,16 +39,85 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
#define PROTOCOL_CAPABILITY_FLAGS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4)) #define PROTOCOL_CAPABILITY_FLAGS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4))
#define PROTOCOL_MAX_MSG_LEN 128U #define PROTOCOL_MAX_MSG_LEN 128U
static bool initialized;
static bool running;
enum proto_session_state { enum proto_session_state {
PROTO_SESSION_DOWN = 0, PROTO_SESSION_DOWN = 0,
PROTO_SESSION_WAIT_HELLO, PROTO_SESSION_WAIT_HELLO,
PROTO_SESSION_ACTIVE, PROTO_SESSION_ACTIVE,
}; };
static enum proto_session_state session_state[PROTO_TRANSPORT_COUNT]; struct protocol_module_ctx {
struct module_lifecycle_ctx lc;
enum proto_session_state session_state[PROTO_TRANSPORT_COUNT];
};
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 protocol_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
};
#define session_state ctx.session_state
static const char *lifecycle_name(enum module_lifecycle state)
{
switch (state) {
case LC_UNINIT:
return "UNINIT";
case LC_RUNNING:
return "RUNNING";
case LC_STOPPED:
return "STOPPED";
case LC_SUSPENDED:
return "SUSPENDED";
case LC_ERROR:
return "ERROR";
default:
return "?";
}
}
static const char *proto_session_name(enum proto_session_state state)
{
switch (state) {
case PROTO_SESSION_DOWN:
return "DOWN";
case PROTO_SESSION_WAIT_HELLO:
return "WAIT_HELLO";
case PROTO_SESSION_ACTIVE:
return "ACTIVE";
default:
return "?";
}
}
static const char *proto_transport_name(enum proto_transport transport)
{
switch (transport) {
case PROTO_TRANSPORT_USB_CDC:
return "usb_cdc";
case PROTO_TRANSPORT_BLE_NUS:
return "ble_nus";
default:
return "?";
}
}
static int decode_body(const uint8_t *payload, size_t payload_len, static int decode_body(const uint8_t *payload, size_t payload_len,
CdcPacketBody *body) CdcPacketBody *body)
@@ -157,7 +227,7 @@ static int encode_function_bitmap_state(const uint8_t *bitmap, uint8_t *payload,
return encode_body(&body, payload, payload_buf_size, payload_len); return encode_body(&body, payload, payload_buf_size, payload_len);
} }
static int module_init(void) static int do_init(void)
{ {
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) { for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
session_state[i] = PROTO_SESSION_DOWN; session_state[i] = PROTO_SESSION_DOWN;
@@ -166,27 +236,26 @@ static int module_init(void)
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
running = true;
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) { for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
session_state[i] = PROTO_SESSION_DOWN; session_state[i] = PROTO_SESSION_DOWN;
} }
running = false; return 0;
} }
int protocol_module_process_message(enum proto_transport transport, int protocol_module_process_message(enum proto_transport transport,
@@ -204,7 +273,10 @@ int protocol_module_process_message(enum proto_transport transport,
return -EINVAL; return -EINVAL;
} }
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
LOG_WRN("Reject proto msg transport:%s len:%u lc:%s",
proto_transport_name(transport), (uint32_t)req_payload_len,
lifecycle_name(ctx.lc.state));
return -EAGAIN; return -EAGAIN;
} }
@@ -216,6 +288,10 @@ int protocol_module_process_message(enum proto_transport transport,
switch (body.which_body) { switch (body.which_body) {
case CdcPacketBody_hello_req_tag: case CdcPacketBody_hello_req_tag:
if (session_state[transport] == PROTO_SESSION_DOWN) { if (session_state[transport] == PROTO_SESSION_DOWN) {
LOG_WRN("Reject HelloReq transport:%s session:%s lc:%s",
proto_transport_name(transport),
proto_session_name(session_state[transport]),
lifecycle_name(ctx.lc.state));
return -EAGAIN; return -EAGAIN;
} }
@@ -317,7 +393,7 @@ static bool handle_proto_rx_event(const struct proto_rx_event *event)
size_t rsp_payload_len = 0U; size_t rsp_payload_len = 0U;
int err; int err;
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return false; return false;
} }
@@ -329,7 +405,11 @@ static bool handle_proto_rx_event(const struct proto_rx_event *event)
&rsp_payload_len); &rsp_payload_len);
if (err) { if (err) {
if (err != -ENOTSUP) { if (err != -ENOTSUP) {
LOG_WRN("Protocol processing failed (%d)", err); LOG_WRN("Protocol processing failed (%d) transport:%s session:%s lc:%s len:%u",
err, proto_transport_name(event->transport),
proto_session_name(session_state[event->transport]),
lifecycle_name(ctx.lc.state),
(uint32_t)event->dyndata.size);
} }
return false; return false;
@@ -373,7 +453,7 @@ static bool handle_function_bitmap_state_event(
size_t payload_len; size_t payload_len;
int err; int err;
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return false; return false;
} }
@@ -406,7 +486,7 @@ static bool handle_hid_led_event(const struct hid_led_event *event)
int err; int err;
enum proto_transport transport; enum proto_transport transport;
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return false; return false;
} }
@@ -454,25 +534,9 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh); const struct module_state_event *event = cast_module_state_event(aeh);
int err;
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (!initialized) { (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
return false; return false;
} }
@@ -481,23 +545,16 @@ static bool app_event_handler(const struct app_event_header *aeh)
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -13,18 +13,43 @@
#include <zephyr/sys/printk.h> #include <zephyr/sys/printk.h>
#include "datetime_event.h" #include "datetime_event.h"
#include "module_lifecycle.h"
#include "time_sync_event.h" #include "time_sync_event.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
#define TIME_SYNC_REFRESH_PERIOD K_SECONDS(1) #define TIME_SYNC_REFRESH_PERIOD K_SECONDS(1)
static struct k_work_delayable refresh_work; struct time_sync_module_ctx {
static bool initialized; struct module_lifecycle_ctx lc;
static bool running; struct k_work_delayable refresh_work;
static int32_t timezone_min; int32_t timezone_min;
static uint64_t utc_ms_base; uint64_t utc_ms_base;
static int64_t uptime_ms_base; int64_t uptime_ms_base;
};
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 time_sync_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
};
static void publish_datetime_event(void) static void publish_datetime_event(void)
{ {
@@ -34,9 +59,9 @@ static void publish_datetime_event(void)
char date_text[DATETIME_EVENT_DATE_TEXT_LEN]; char date_text[DATETIME_EVENT_DATE_TEXT_LEN];
char time_text[DATETIME_EVENT_TIME_TEXT_LEN]; char time_text[DATETIME_EVENT_TIME_TEXT_LEN];
local_ms = (int64_t)utc_ms_base + local_ms = (int64_t)ctx.utc_ms_base +
(k_uptime_get() - uptime_ms_base) + (k_uptime_get() - ctx.uptime_ms_base) +
((int64_t)timezone_min * 60LL * 1000LL); ((int64_t)ctx.timezone_min * 60LL * 1000LL);
if (local_ms < 0) { if (local_ms < 0) {
local_ms = 0; local_ms = 0;
} }
@@ -67,43 +92,43 @@ static void refresh_work_handler(struct k_work *work)
{ {
ARG_UNUSED(work); ARG_UNUSED(work);
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return;
} }
publish_datetime_event(); publish_datetime_event();
k_work_reschedule(&refresh_work, TIME_SYNC_REFRESH_PERIOD); k_work_reschedule(&ctx.refresh_work, TIME_SYNC_REFRESH_PERIOD);
} }
static int module_init(void) static int do_init(void)
{ {
timezone_min = 0; ctx.timezone_min = 0;
utc_ms_base = 0U; ctx.utc_ms_base = 0U;
uptime_ms_base = k_uptime_get(); ctx.uptime_ms_base = k_uptime_get();
k_work_init_delayable(&refresh_work, refresh_work_handler); k_work_init_delayable(&ctx.refresh_work, refresh_work_handler);
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
running = true; k_work_reschedule(&ctx.refresh_work, K_NO_WAIT);
k_work_reschedule(&refresh_work, K_NO_WAIT);
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
k_work_cancel_delayable(&refresh_work); k_work_cancel_delayable(&ctx.refresh_work);
running = false;
return 0;
} }
static bool handle_time_sync_event(const struct time_sync_event *event) static bool handle_time_sync_event(const struct time_sync_event *event)
@@ -113,12 +138,12 @@ static bool handle_time_sync_event(const struct time_sync_event *event)
return false; return false;
} }
timezone_min = event->timezone_min; ctx.timezone_min = event->timezone_min;
utc_ms_base = event->utc_ms; ctx.utc_ms_base = event->utc_ms;
uptime_ms_base = k_uptime_get(); ctx.uptime_ms_base = k_uptime_get();
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
k_work_reschedule(&refresh_work, K_NO_WAIT); k_work_reschedule(&ctx.refresh_work, K_NO_WAIT);
} }
return false; return false;
@@ -132,48 +157,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh); const struct module_state_event *event = cast_module_state_event(aeh);
int err;
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (!initialized) { (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -16,6 +16,7 @@
#include <zephyr/sys/ring_buffer.h> #include <zephyr/sys/ring_buffer.h>
#include <zephyr/sys/util.h> #include <zephyr/sys/util.h>
#include "module_lifecycle.h"
#include "proto_rx_event.h" #include "proto_rx_event.h"
#include "proto_transport_state_event.h" #include "proto_transport_state_event.h"
#include "proto_tx_event.h" #include "proto_tx_event.h"
@@ -38,33 +39,53 @@ enum usb_cdc_business_state {
}; };
struct usb_cdc_ctx { struct usb_cdc_ctx {
enum module_state lifecycle; struct module_lifecycle_ctx lc;
enum usb_cdc_business_state business; enum usb_cdc_business_state business;
const struct device *cdc_dev;
uint8_t rx_ring_buffer[USB_CDC_RX_RING_BUF_SIZE];
uint8_t tx_ring_buffer[USB_CDC_TX_RING_BUF_SIZE];
struct ring_buf rx_ringbuf;
struct ring_buf tx_ringbuf;
struct k_work rx_work;
struct k_work_delayable rx_flush_work;
uint8_t proto_rx_buf[USB_CDC_PROTO_RX_BUF_SIZE];
bool usb_active; bool usb_active;
size_t proto_rx_len; size_t proto_rx_len;
}; };
static int do_init(void);
static int do_start(void);
static int do_stop(void);
static const struct device *const cdc_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart); 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 uint8_t rx_ring_buffer[USB_CDC_RX_RING_BUF_SIZE];
static uint8_t tx_ring_buffer[USB_CDC_TX_RING_BUF_SIZE];
static struct ring_buf rx_ringbuf;
static struct ring_buf tx_ringbuf;
static struct k_work rx_work;
static struct k_work_delayable rx_flush_work;
static uint8_t proto_rx_buf[USB_CDC_PROTO_RX_BUF_SIZE];
static struct usb_cdc_ctx ctx = { static struct usb_cdc_ctx ctx = {
.lifecycle = MODULE_STATE_OFF, .lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.business = USB_CDC_BUS_OFFLINE, .business = USB_CDC_BUS_OFFLINE,
.cdc_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart),
.usb_active = false, .usb_active = false,
.proto_rx_len = 0U, .proto_rx_len = 0U,
}; };
#define proto_rx_buf ctx.proto_rx_buf
static void validate_line_coding(void); static void validate_line_coding(void);
static bool lifecycle_is_ready(void) static bool lifecycle_is_ready(void)
{ {
return ctx.lifecycle == MODULE_STATE_READY; return module_lifecycle_is_running(&ctx.lc);
} }
static enum proto_transport_link_state transport_link_state_get(void) static enum proto_transport_link_state transport_link_state_get(void)
@@ -75,44 +96,36 @@ static enum proto_transport_link_state transport_link_state_get(void)
PROTO_TRANSPORT_LINK_DOWN; PROTO_TRANSPORT_LINK_DOWN;
} }
static bool control_poll_needed(enum module_state lifecycle,
enum usb_cdc_business_state business)
{
ARG_UNUSED(lifecycle);
ARG_UNUSED(business);
return false;
}
static void reset_ring_buffers(void) static void reset_ring_buffers(void)
{ {
unsigned int key = irq_lock(); unsigned int key = irq_lock();
ring_buf_init(&rx_ringbuf, sizeof(rx_ring_buffer), rx_ring_buffer); ring_buf_init(&ctx.rx_ringbuf, sizeof(ctx.rx_ring_buffer), ctx.rx_ring_buffer);
ring_buf_init(&tx_ringbuf, sizeof(tx_ring_buffer), tx_ring_buffer); ring_buf_init(&ctx.tx_ringbuf, sizeof(ctx.tx_ring_buffer), ctx.tx_ring_buffer);
irq_unlock(key); irq_unlock(key);
} }
static void disable_uart_io(void) static void disable_uart_io(void)
{ {
uart_irq_rx_disable(cdc_dev); uart_irq_rx_disable(ctx.cdc_dev);
uart_irq_tx_disable(cdc_dev); uart_irq_tx_disable(ctx.cdc_dev);
ctx.proto_rx_len = 0U; ctx.proto_rx_len = 0U;
k_work_cancel_delayable(&rx_flush_work); k_work_cancel_delayable(&ctx.rx_flush_work);
reset_ring_buffers(); reset_ring_buffers();
} }
static void state_reconcile(enum module_state old_lifecycle, static void state_reconcile(enum module_lifecycle old_lifecycle,
enum usb_cdc_business_state old_business) enum usb_cdc_business_state old_business)
{ {
enum proto_transport_link_state old_link = enum proto_transport_link_state old_link =
((old_lifecycle == MODULE_STATE_READY) && ((old_lifecycle == LC_RUNNING) &&
(old_business == USB_CDC_SESSION_READY)) ? (old_business == USB_CDC_SESSION_READY)) ?
PROTO_TRANSPORT_LINK_READY : PROTO_TRANSPORT_LINK_READY :
PROTO_TRANSPORT_LINK_DOWN; PROTO_TRANSPORT_LINK_DOWN;
enum proto_transport_link_state new_link = transport_link_state_get(); enum proto_transport_link_state new_link = transport_link_state_get();
if ((old_lifecycle == MODULE_STATE_READY) && if ((old_lifecycle == LC_RUNNING) &&
(old_business == USB_CDC_SESSION_READY) && (old_business == USB_CDC_SESSION_READY) &&
(new_link == PROTO_TRANSPORT_LINK_DOWN)) { (new_link == PROTO_TRANSPORT_LINK_DOWN)) {
disable_uart_io(); disable_uart_io();
@@ -124,17 +137,17 @@ static void state_reconcile(enum module_state old_lifecycle,
validate_line_coding(); validate_line_coding();
err = uart_line_ctrl_set(cdc_dev, UART_LINE_CTRL_DCD, 1); err = uart_line_ctrl_set(ctx.cdc_dev, UART_LINE_CTRL_DCD, 1);
if (err) { if (err) {
LOG_WRN("Failed to set DCD (%d)", err); LOG_WRN("Failed to set DCD (%d)", err);
} }
err = uart_line_ctrl_set(cdc_dev, UART_LINE_CTRL_DSR, 1); err = uart_line_ctrl_set(ctx.cdc_dev, UART_LINE_CTRL_DSR, 1);
if (err) { if (err) {
LOG_WRN("Failed to set DSR (%d)", err); LOG_WRN("Failed to set DSR (%d)", err);
} }
uart_irq_rx_enable(cdc_dev); uart_irq_rx_enable(ctx.cdc_dev);
} }
if (old_link != new_link) { if (old_link != new_link) {
@@ -143,23 +156,9 @@ static void state_reconcile(enum module_state old_lifecycle,
} }
} }
static void lifecycle_set(enum module_state new_state)
{
enum module_state old_lifecycle = ctx.lifecycle;
enum usb_cdc_business_state old_business = ctx.business;
if (ctx.lifecycle == new_state) {
return;
}
ctx.lifecycle = new_state;
state_reconcile(old_lifecycle, old_business);
module_set_state(new_state);
}
static void business_state_set(enum usb_cdc_business_state new_state) static void business_state_set(enum usb_cdc_business_state new_state)
{ {
enum module_state old_lifecycle = ctx.lifecycle; enum module_lifecycle old_lifecycle = ctx.lc.state;
enum usb_cdc_business_state old_business = ctx.business; enum usb_cdc_business_state old_business = ctx.business;
if (ctx.business == new_state) { if (ctx.business == new_state) {
@@ -192,7 +191,7 @@ static void kick_tx(void)
return; return;
} }
uart_irq_tx_enable(cdc_dev); uart_irq_tx_enable(ctx.cdc_dev);
} }
static void validate_line_coding(void) static void validate_line_coding(void)
@@ -200,7 +199,7 @@ static void validate_line_coding(void)
uint32_t baudrate = 0U; uint32_t baudrate = 0U;
int err; int err;
err = uart_line_ctrl_get(cdc_dev, UART_LINE_CTRL_BAUD_RATE, &baudrate); err = uart_line_ctrl_get(ctx.cdc_dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
if (err) { if (err) {
LOG_WRN("Failed to get CDC baudrate (%d)", err); LOG_WRN("Failed to get CDC baudrate (%d)", err);
} else { } else {
@@ -215,7 +214,7 @@ static void validate_line_coding(void)
{ {
struct uart_config cfg; struct uart_config cfg;
err = uart_config_get(cdc_dev, &cfg); err = uart_config_get(ctx.cdc_dev, &cfg);
if (err) { if (err) {
LOG_WRN("uart_config_get failed (%d)", err); LOG_WRN("uart_config_get failed (%d)", err);
} else { } else {
@@ -243,7 +242,7 @@ static void rx_work_handler(struct k_work *work)
uint32_t len; uint32_t len;
unsigned int key = irq_lock(); unsigned int key = irq_lock();
len = ring_buf_get(&rx_ringbuf, buffer, sizeof(buffer)); len = ring_buf_get(&ctx.rx_ringbuf, buffer, sizeof(buffer));
irq_unlock(key); irq_unlock(key);
if (len == 0U) { if (len == 0U) {
@@ -259,7 +258,7 @@ static void rx_work_handler(struct k_work *work)
if (len > 0U) { if (len > 0U) {
memcpy(&proto_rx_buf[ctx.proto_rx_len], buffer, len); memcpy(&proto_rx_buf[ctx.proto_rx_len], buffer, len);
ctx.proto_rx_len += len; ctx.proto_rx_len += len;
k_work_reschedule(&rx_flush_work, USB_CDC_PROTO_RX_FLUSH_DELAY); k_work_reschedule(&ctx.rx_flush_work, USB_CDC_PROTO_RX_FLUSH_DELAY);
} }
} }
} }
@@ -296,7 +295,7 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
uint32_t written; uint32_t written;
unsigned int key = irq_lock(); unsigned int key = irq_lock();
written = ring_buf_put(&rx_ringbuf, buffer, written = ring_buf_put(&ctx.rx_ringbuf, buffer,
(uint32_t)recv_len); (uint32_t)recv_len);
irq_unlock(key); irq_unlock(key);
@@ -305,7 +304,7 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
recv_len - (int)written); recv_len - (int)written);
} }
k_work_submit(&rx_work); k_work_submit(&ctx.rx_work);
} }
} }
@@ -315,7 +314,7 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
int sent_len; int sent_len;
unsigned int key = irq_lock(); unsigned int key = irq_lock();
len = ring_buf_get(&tx_ringbuf, buffer, sizeof(buffer)); len = ring_buf_get(&ctx.tx_ringbuf, buffer, sizeof(buffer));
irq_unlock(key); irq_unlock(key);
if (len == 0U) { if (len == 0U) {
@@ -335,37 +334,52 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
} }
} }
static int module_init(void) static int do_init(void)
{ {
if (!device_is_ready(cdc_dev)) { if (!device_is_ready(ctx.cdc_dev)) {
LOG_ERR("CDC ACM device not ready"); LOG_ERR("CDC ACM device not ready");
return -ENODEV; return -ENODEV;
} }
reset_ring_buffers(); reset_ring_buffers();
k_work_init(&rx_work, rx_work_handler); k_work_init(&ctx.rx_work, rx_work_handler);
k_work_init_delayable(&rx_flush_work, rx_flush_work_handler); k_work_init_delayable(&ctx.rx_flush_work, rx_flush_work_handler);
uart_irq_callback_set(cdc_dev, cdc_interrupt_handler); uart_irq_callback_set(ctx.cdc_dev, cdc_interrupt_handler);
ctx = (struct usb_cdc_ctx) { ctx.business = USB_CDC_BUS_OFFLINE;
.lifecycle = MODULE_STATE_OFF, ctx.usb_active = false;
.business = USB_CDC_BUS_OFFLINE, ctx.proto_rx_len = 0U;
.usb_active = false,
.proto_rx_len = 0U,
};
return 0; return 0;
} }
static void module_start(void) static int do_start(void)
{ {
lifecycle_set(MODULE_STATE_READY); return 0;
business_state_sync_from_usb();
} }
static void module_pause(void) static int do_stop(void)
{ {
business_state_set(USB_CDC_BUS_OFFLINE); ctx.business = USB_CDC_BUS_OFFLINE;
lifecycle_set(MODULE_STATE_STANDBY); return 0;
}
static int apply_lifecycle(enum module_lifecycle target)
{
enum module_lifecycle old_lifecycle = ctx.lc.state;
enum usb_cdc_business_state old_business = ctx.business;
int err = module_set_lifecycle(&ctx.lc, target);
if (err) {
return err;
}
state_reconcile(old_lifecycle, old_business);
if (target == LC_RUNNING) {
business_state_sync_from_usb();
}
return 0;
} }
static bool handle_usb_state_event(const struct usb_state_event *event) static bool handle_usb_state_event(const struct usb_state_event *event)
@@ -384,7 +398,7 @@ static bool handle_usb_state_event(const struct usb_state_event *event)
static bool handle_usb_control_event(const struct usb_control_event *event) static bool handle_usb_control_event(const struct usb_control_event *event)
{ {
if (event->dev != cdc_dev) { if (event->dev != ctx.cdc_dev) {
return false; return false;
} }
@@ -449,7 +463,7 @@ static bool handle_proto_tx_event(const struct proto_tx_event *event)
} }
key = irq_lock(); key = irq_lock();
written = ring_buf_put(&tx_ringbuf, event->dyndata.data, written = ring_buf_put(&ctx.tx_ringbuf, event->dyndata.data,
(uint32_t)event->dyndata.size); (uint32_t)event->dyndata.size);
irq_unlock(key); irq_unlock(key);
@@ -483,32 +497,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
cast_module_state_event(aeh); cast_module_state_event(aeh);
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (ctx.lifecycle == MODULE_STATE_OFF) { (void)apply_lifecycle(LC_RUNNING);
int err = module_init();
if (err) {
lifecycle_set(MODULE_STATE_ERROR);
return false;
}
}
module_start();
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (ctx.lifecycle != MODULE_STATE_OFF) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)apply_lifecycle(LC_STOPPED);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (ctx.lifecycle != MODULE_STATE_OFF) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_start(); (void)apply_lifecycle(LC_RUNNING);
} }
return false; return false;

View File

@@ -15,6 +15,7 @@
#include <caf/events/power_manager_event.h> #include <caf/events/power_manager_event.h>
#include "module_lifecycle.h"
#include "usb_function_hook.h" #include "usb_function_hook.h"
#include "usb_control_event.h" #include "usb_control_event.h"
#include "usb_state_event.h" #include "usb_state_event.h"
@@ -40,12 +41,8 @@ static const char *const class_blocklist[] = {
NULL, NULL,
}; };
static bool initialized;
static bool running;
enum usb_stack_state { enum usb_stack_state {
USB_STACK_UNINITIALIZED = 0, USB_STACK_UNINITIALIZED = 0,
USB_STACK_DISABLED,
USB_STACK_READY, USB_STACK_READY,
USB_STACK_ENABLED, USB_STACK_ENABLED,
}; };
@@ -58,19 +55,43 @@ enum usb_bus_state {
}; };
struct usb_owner_ctx { struct usb_owner_ctx {
struct module_lifecycle_ctx lc;
enum usb_stack_state stack; enum usb_stack_state stack;
enum usb_bus_state bus; enum usb_bus_state bus;
}; };
static int do_init(void);
static int do_start(void);
static int do_stop(void);
/* Project exception: mode policy suspend/resume controls USB availability,
* while global power events still map to standby lifecycle transitions.
*/
static const struct module_lifecycle_cfg lifecycle_cfg = {
.mode = ML_MODE_SUSPEND,
.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 usb_owner_ctx usb_ctx = { static struct usb_owner_ctx usb_ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.stack = USB_STACK_UNINITIALIZED, .stack = USB_STACK_UNINITIALIZED,
.bus = USB_BUS_DISCONNECTED, .bus = USB_BUS_DISCONNECTED,
}; };
static inline enum usb_state usb_public_state_get(void) static inline enum usb_state usb_public_state_get(void)
{ {
if ((usb_ctx.stack == USB_STACK_UNINITIALIZED) || if (!module_lifecycle_is_running(&usb_ctx.lc) ||
(usb_ctx.stack == USB_STACK_DISABLED)) { (usb_ctx.stack == USB_STACK_UNINITIALIZED)) {
return USB_STATE_DISABLED; return USB_STATE_DISABLED;
} }
@@ -88,11 +109,6 @@ static inline enum usb_state usb_public_state_get(void)
} }
} }
static inline bool usb_stack_was_initialized(void)
{
return (usb_ctx.stack != USB_STACK_UNINITIALIZED);
}
static inline void usb_bus_set(enum usb_bus_state state) static inline void usb_bus_set(enum usb_bus_state state)
{ {
if (usb_ctx.bus == state) { if (usb_ctx.bus == state) {
@@ -100,7 +116,10 @@ static inline void usb_bus_set(enum usb_bus_state state)
} }
usb_ctx.bus = state; usb_ctx.bus = state;
if (module_lifecycle_is_initialized(&usb_ctx.lc)) {
submit_usb_state(usb_public_state_get()); submit_usb_state(usb_public_state_get());
}
} }
static void update_power_manager_restriction(bool vbus_present) static void update_power_manager_restriction(bool vbus_present)
@@ -200,31 +219,30 @@ static void usbd_msg_cb(struct usbd_context *const usbd_ctx,
switch (msg->type) { switch (msg->type) {
case USBD_MSG_VBUS_READY: case USBD_MSG_VBUS_READY:
update_power_manager_restriction(true); update_power_manager_restriction(true);
usb_bus_set(USB_BUS_POWERED);
if (usb_ctx.stack == USB_STACK_READY) { if (module_lifecycle_is_running(&usb_ctx.lc) &&
int err = usbd_enable(&blinky_usbd); (usb_ctx.stack == USB_STACK_READY)) {
int err = do_start();
if (err) { if (err) {
LOG_ERR("usbd_enable failed (%d)", err); LOG_ERR("USB start on VBUS ready failed (%d)", err);
} else {
usb_ctx.stack = USB_STACK_ENABLED;
usb_bus_set(USB_BUS_POWERED);
} }
} }
break; break;
case USBD_MSG_VBUS_REMOVED: case USBD_MSG_VBUS_REMOVED:
update_power_manager_restriction(false);
if (usb_ctx.stack == USB_STACK_ENABLED) { if (usb_ctx.stack == USB_STACK_ENABLED) {
int err = usbd_disable(&blinky_usbd); int err = do_stop();
if (err) { if (err) {
LOG_ERR("usbd_disable failed (%d)", err); LOG_ERR("USB stop on VBUS removed failed (%d)", err);
} }
} else {
update_power_manager_restriction(false);
} }
if (usb_ctx.stack != USB_STACK_DISABLED) { if (usb_ctx.stack != USB_STACK_UNINITIALIZED) {
usb_ctx.stack = USB_STACK_READY; usb_ctx.stack = USB_STACK_READY;
} }
@@ -256,16 +274,13 @@ static void usbd_msg_cb(struct usbd_context *const usbd_ctx,
} }
} }
static int usb_stack_init_once(void) static int do_init(void)
{ {
int err; int err;
if (usb_stack_was_initialized()) { usb_ctx.stack = USB_STACK_UNINITIALIZED;
if (usb_ctx.stack == USB_STACK_DISABLED) { usb_ctx.bus = USB_BUS_DISCONNECTED;
usb_ctx.stack = USB_STACK_READY; update_power_manager_restriction(false);
}
return 0;
}
STRUCT_SECTION_FOREACH(usb_function_hook, hook) { STRUCT_SECTION_FOREACH(usb_function_hook, hook) {
if (hook->pre_stack_init == NULL) { if (hook->pre_stack_init == NULL) {
@@ -299,6 +314,17 @@ static int usb_stack_init_once(void)
usb_ctx.stack = USB_STACK_READY; usb_ctx.stack = USB_STACK_READY;
return 0;
}
static int do_start(void)
{
int err;
if (usb_ctx.stack == USB_STACK_ENABLED) {
return 0;
}
if (!usbd_can_detect_vbus(&blinky_usbd)) { if (!usbd_can_detect_vbus(&blinky_usbd)) {
err = usbd_enable(&blinky_usbd); err = usbd_enable(&blinky_usbd);
if (err) { if (err) {
@@ -307,24 +333,15 @@ static int usb_stack_init_once(void)
} }
usb_ctx.stack = USB_STACK_ENABLED; usb_ctx.stack = USB_STACK_ENABLED;
usb_bus_set(USB_BUS_POWERED); usb_ctx.bus = USB_BUS_POWERED;
} update_power_manager_restriction(true);
return 0;
}
if (usb_ctx.bus == USB_BUS_DISCONNECTED) {
return 0; return 0;
}
static int usb_stack_enable_if_needed(void)
{
int err;
err = usb_stack_init_once();
if (err) {
return err;
} }
if ((usb_ctx.stack == USB_STACK_READY) &&
(!usbd_can_detect_vbus(&blinky_usbd) ||
(usb_ctx.bus != USB_BUS_DISCONNECTED))) {
err = usbd_enable(&blinky_usbd); err = usbd_enable(&blinky_usbd);
if (err) { if (err) {
LOG_ERR("usbd_enable failed (%d)", err); LOG_ERR("usbd_enable failed (%d)", err);
@@ -332,92 +349,35 @@ static int usb_stack_enable_if_needed(void)
} }
usb_ctx.stack = USB_STACK_ENABLED; usb_ctx.stack = USB_STACK_ENABLED;
update_power_manager_restriction(true);
if (usb_ctx.bus == USB_BUS_DISCONNECTED) {
usb_bus_set(USB_BUS_POWERED);
} else {
submit_usb_state(usb_public_state_get());
}
return 0;
}
submit_usb_state(usb_public_state_get());
return 0; return 0;
} }
static int usb_stack_disable_if_needed(void) static int do_stop(void)
{ {
if (usb_ctx.stack == USB_STACK_ENABLED) { int err;
int err = usbd_disable(&blinky_usbd);
if (usb_ctx.stack == USB_STACK_ENABLED) {
err = usbd_disable(&blinky_usbd);
if (err) { if (err) {
LOG_ERR("usbd_disable failed (%d)", err); LOG_ERR("usbd_disable failed (%d)", err);
return err; return err;
} }
} }
usb_ctx.stack = USB_STACK_DISABLED; usb_ctx.stack = USB_STACK_READY;
update_power_manager_restriction(false); update_power_manager_restriction(false);
submit_usb_state(usb_public_state_get());
return 0; return 0;
} }
static int module_init(void)
{
usb_ctx.stack = USB_STACK_UNINITIALIZED;
usb_ctx.bus = USB_BUS_DISCONNECTED;
update_power_manager_restriction(false);
return 0;
}
static int module_start(void)
{
if (running) {
return 0;
}
running = true;
submit_usb_state(usb_public_state_get());
return 0;
}
static void module_pause(void)
{
if (!running) {
return;
}
running = false;
submit_usb_state(usb_public_state_get());
}
static bool handle_module_state_event(const struct module_state_event *event) static bool handle_module_state_event(const struct module_state_event *event)
{ {
if (!check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (!check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
return false; return false;
} }
if (!initialized) { if (module_set_lifecycle(&usb_ctx.lc, LC_RUNNING) == 0) {
int err = module_init(); submit_usb_state(usb_public_state_get());
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
if (!running) {
int err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else if (usb_stack_was_initialized()) {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
@@ -426,37 +386,28 @@ static bool handle_module_state_event(const struct module_state_event *event)
static bool handle_module_suspend_req_event( static bool handle_module_suspend_req_event(
const struct module_suspend_req_event *event) const struct module_suspend_req_event *event)
{ {
if ((event->sink_module_id != MODULE_ID(MODULE)) || !running) { if ((event->sink_module_id != MODULE_ID(MODULE)) ||
(usb_ctx.lc.state != LC_RUNNING)) {
return false; return false;
} }
int err = usb_stack_disable_if_needed(); if (module_set_lifecycle(&usb_ctx.lc, LC_SUSPENDED) == 0) {
submit_usb_state(usb_public_state_get());
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
} }
module_set_state(MODULE_STATE_READY);
return false; return false;
} }
static bool handle_module_resume_req_event( static bool handle_module_resume_req_event(
const struct module_resume_req_event *event) const struct module_resume_req_event *event)
{ {
if ((event->sink_module_id != MODULE_ID(MODULE)) || !running) { if ((event->sink_module_id != MODULE_ID(MODULE)) ||
(usb_ctx.lc.state != LC_SUSPENDED)) {
return false; return false;
} }
int err = usb_stack_enable_if_needed(); if (module_set_lifecycle(&usb_ctx.lc, LC_RUNNING) == 0) {
submit_usb_state(usb_public_state_get());
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
if (usb_stack_was_initialized()) {
module_set_state(MODULE_STATE_READY);
} }
return false; return false;
@@ -479,22 +430,19 @@ static bool app_event_handler(const struct app_event_header *aeh)
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&usb_ctx.lc)) {
module_pause(); if (module_set_lifecycle(&usb_ctx.lc, LC_STOPPED) == 0) {
module_set_state(MODULE_STATE_STANDBY); submit_usb_state(usb_public_state_get());
}
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&usb_ctx.lc)) {
int err = module_start(); if (module_set_lifecycle(&usb_ctx.lc, LC_RUNNING) == 0) {
submit_usb_state(usb_public_state_get());
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else if (usb_stack_was_initialized()) {
module_set_state(MODULE_STATE_READY);
} }
} }

View File

@@ -18,32 +18,57 @@
#include "hid_report_sent_event.h" #include "hid_report_sent_event.h"
#include "hid_tx_report_event.h" #include "hid_tx_report_event.h"
#include "keyboard_core.h" #include "keyboard_core.h"
#include "module_lifecycle.h"
#include "usb_function_hook.h" #include "usb_function_hook.h"
#include "usb_state_event.h" #include "usb_state_event.h"
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
static const struct device *const hid_dev =
DEVICE_DT_GET(DT_NODELABEL(hid_consumer));
static const uint8_t consumer_report_desc[] = { static const uint8_t consumer_report_desc[] = {
0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x15, 0x00, 0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x15, 0x00,
0x26, 0xFF, 0x03, 0x19, 0x00, 0x2A, 0xFF, 0x03, 0x26, 0xFF, 0x03, 0x19, 0x00, 0x2A, 0xFF, 0x03,
0x75, 0x10, 0x95, 0x01, 0x81, 0x00, 0xC0 0x75, 0x10, 0x95, 0x01, 0x81, 0x00, 0xC0
}; };
static bool initialized; struct usb_hid_consumer_module_ctx {
static bool running; struct module_lifecycle_ctx lc;
static bool usb_active; const struct device *hid_dev;
static bool iface_ready; bool usb_active;
static bool report_in_flight; bool iface_ready;
static uint16_t in_flight_sequence; bool report_in_flight;
uint16_t in_flight_sequence;
};
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 usb_hid_consumer_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.hid_dev = DEVICE_DT_GET(DT_NODELABEL(hid_consumer)),
};
UDC_STATIC_BUF_DEFINE(consumer_tx_buf, KEYBOARD_CONSUMER_REPORT_SIZE); UDC_STATIC_BUF_DEFINE(consumer_tx_buf, KEYBOARD_CONSUMER_REPORT_SIZE);
static void publish_consumer_state(void) static void publish_consumer_state(void)
{ {
bool ready = running && usb_active && iface_ready; bool ready = module_lifecycle_is_running(&ctx.lc) &&
ctx.usb_active && ctx.iface_ready;
submit_hid_channel_state_event(HID_SEND_CH_USB_CONSUMER, submit_hid_channel_state_event(HID_SEND_CH_USB_CONSUMER,
ready ? BIT(KEYBOARD_REPORT_TYPE_CONSUMER) : 0U, ready ? BIT(KEYBOARD_REPORT_TYPE_CONSUMER) : 0U,
@@ -54,12 +79,13 @@ static void consumer_iface_ready(const struct device *dev, const bool ready)
{ {
ARG_UNUSED(dev); ARG_UNUSED(dev);
iface_ready = ready; ctx.iface_ready = ready;
if (!ready) { if (!ready) {
report_in_flight = false; ctx.report_in_flight = false;
} }
LOG_INF("%s interface %s", hid_dev->name, ready ? "ready" : "not ready"); LOG_INF("%s interface %s", ctx.hid_dev->name,
ready ? "ready" : "not ready");
publish_consumer_state(); publish_consumer_state();
} }
@@ -117,10 +143,10 @@ static void consumer_input_report_done(const struct device *dev,
ARG_UNUSED(dev); ARG_UNUSED(dev);
ARG_UNUSED(report); ARG_UNUSED(report);
report_in_flight = false; ctx.report_in_flight = false;
submit_hid_report_sent_event(HID_SEND_CH_USB_CONSUMER, submit_hid_report_sent_event(HID_SEND_CH_USB_CONSUMER,
KEYBOARD_REPORT_TYPE_CONSUMER, KEYBOARD_REPORT_TYPE_CONSUMER,
in_flight_sequence, false); ctx.in_flight_sequence, false);
} }
static void consumer_output_report(const struct device *dev, static void consumer_output_report(const struct device *dev,
@@ -145,59 +171,59 @@ static const struct hid_device_ops consumer_ops = {
static int usb_hid_consumer_register_device(void) static int usb_hid_consumer_register_device(void)
{ {
if (!device_is_ready(hid_dev)) { if (!device_is_ready(ctx.hid_dev)) {
LOG_ERR("HID device %s not ready", hid_dev->name); LOG_ERR("HID device %s not ready", ctx.hid_dev->name);
return -ENODEV; return -ENODEV;
} }
return hid_device_register(hid_dev, consumer_report_desc, return hid_device_register(ctx.hid_dev, consumer_report_desc,
sizeof(consumer_report_desc), &consumer_ops); sizeof(consumer_report_desc), &consumer_ops);
} }
USB_FUNCTION_HOOK_DEFINE(usb_hid_consumer_hook, usb_hid_consumer_register_device); USB_FUNCTION_HOOK_DEFINE(usb_hid_consumer_hook, usb_hid_consumer_register_device);
static int module_init(void) static int do_init(void)
{ {
usb_active = false; ctx.usb_active = false;
iface_ready = false; ctx.iface_ready = false;
report_in_flight = false; ctx.report_in_flight = false;
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
running = true;
publish_consumer_state(); publish_consumer_state();
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
running = false; ctx.report_in_flight = false;
report_in_flight = false;
publish_consumer_state(); publish_consumer_state();
return 0;
} }
static bool handle_usb_state_event(const struct usb_state_event *event) static bool handle_usb_state_event(const struct usb_state_event *event)
{ {
bool new_usb_active = (event->state == USB_STATE_ACTIVE); bool new_usb_active = (event->state == USB_STATE_ACTIVE);
if (new_usb_active == usb_active) { if (new_usb_active == ctx.usb_active) {
return false; return false;
} }
usb_active = new_usb_active; ctx.usb_active = new_usb_active;
if (!usb_active) { if (!ctx.usb_active) {
iface_ready = false; ctx.iface_ready = false;
report_in_flight = false; ctx.report_in_flight = false;
} }
publish_consumer_state(); publish_consumer_state();
@@ -208,7 +234,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
{ {
int err; int err;
if (!running || !usb_active || if (!module_lifecycle_is_running(&ctx.lc) || !ctx.usb_active ||
(event->channel != HID_SEND_CH_USB_CONSUMER)) { (event->channel != HID_SEND_CH_USB_CONSUMER)) {
return false; return false;
} }
@@ -217,17 +243,17 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
return false; return false;
} }
if (!iface_ready) { if (!ctx.iface_ready) {
return false; return false;
} }
if (report_in_flight) { if (ctx.report_in_flight) {
LOG_WRN("Drop USB consumer report while previous report is in flight"); LOG_WRN("Drop USB consumer report while previous report is in flight");
return false; return false;
} }
memcpy(consumer_tx_buf, event->dyndata.data, event->dyndata.size); memcpy(consumer_tx_buf, event->dyndata.data, event->dyndata.size);
err = hid_device_submit_report(hid_dev, (uint16_t)event->dyndata.size, err = hid_device_submit_report(ctx.hid_dev, (uint16_t)event->dyndata.size,
consumer_tx_buf); consumer_tx_buf);
if (err) { if (err) {
LOG_WRN("USB consumer report submit failed (%d)", err); LOG_WRN("USB consumer report submit failed (%d)", err);
@@ -235,8 +261,8 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
KEYBOARD_REPORT_TYPE_CONSUMER, KEYBOARD_REPORT_TYPE_CONSUMER,
event->sequence, true); event->sequence, true);
} else { } else {
report_in_flight = true; ctx.report_in_flight = true;
in_flight_sequence = event->sequence; ctx.in_flight_sequence = event->sequence;
} }
return false; return false;
@@ -254,48 +280,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh); const struct module_state_event *event = cast_module_state_event(aeh);
int err;
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (!initialized) { (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;

View File

@@ -19,6 +19,7 @@
#include "hid_report_sent_event.h" #include "hid_report_sent_event.h"
#include "hid_tx_report_event.h" #include "hid_tx_report_event.h"
#include "keyboard_core.h" #include "keyboard_core.h"
#include "module_lifecycle.h"
#include "set_protocol_event.h" #include "set_protocol_event.h"
#include "usb_function_hook.h" #include "usb_function_hook.h"
#include "usb_state_event.h" #include "usb_state_event.h"
@@ -28,8 +29,6 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
#define KBD_LED_REPORT_SIZE 1U #define KBD_LED_REPORT_SIZE 1U
#define KBD_LED_REPORT_WITH_ID_SIZE (KBD_LED_REPORT_SIZE + 1U) #define KBD_LED_REPORT_WITH_ID_SIZE (KBD_LED_REPORT_SIZE + 1U)
static const struct device *const hid_dev = DEVICE_DT_GET(DT_NODELABEL(hid_kbd));
static const uint8_t keyboard_report_desc[] = { static const uint8_t keyboard_report_desc[] = {
0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07,
0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01,
@@ -41,36 +40,64 @@ static const uint8_t keyboard_report_desc[] = {
0x75, 0x03, 0x95, 0x01, 0x91, 0x01, 0xC0 0x75, 0x03, 0x95, 0x01, 0x91, 0x01, 0xC0
}; };
static enum keyboard_protocol_mode keyboard_protocol_mode = struct usb_hid_keyboard_module_ctx {
KEYBOARD_PROTOCOL_MODE_REPORT; struct module_lifecycle_ctx lc;
static bool initialized; const struct device *hid_dev;
static bool running; enum keyboard_protocol_mode keyboard_protocol_mode;
static bool usb_active; bool usb_active;
static bool iface_ready; bool iface_ready;
static bool report_in_flight; bool report_in_flight;
static uint16_t in_flight_sequence; uint16_t in_flight_sequence;
};
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 usb_hid_keyboard_module_ctx ctx = {
.lc = {
.state = LC_UNINIT,
.cfg = &lifecycle_cfg,
.ops = &lifecycle_ops,
},
.hid_dev = DEVICE_DT_GET(DT_NODELABEL(hid_kbd)),
.keyboard_protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
};
UDC_STATIC_BUF_DEFINE(keyboard_tx_buf, KEYBOARD_NKRO_REPORT_SIZE); UDC_STATIC_BUF_DEFINE(keyboard_tx_buf, KEYBOARD_NKRO_REPORT_SIZE);
static void publish_keyboard_state(void) static void publish_keyboard_state(void)
{ {
bool ready = running && usb_active && iface_ready; bool ready = module_lifecycle_is_running(&ctx.lc) &&
ctx.usb_active && ctx.iface_ready;
submit_hid_channel_state_event(HID_SEND_CH_USB_KEYS, submit_hid_channel_state_event(HID_SEND_CH_USB_KEYS,
ready ? BIT(KEYBOARD_REPORT_TYPE_KEYS) : 0U, ready ? BIT(KEYBOARD_REPORT_TYPE_KEYS) : 0U,
keyboard_protocol_mode); ctx.keyboard_protocol_mode);
} }
static void keyboard_iface_ready(const struct device *dev, const bool ready) static void keyboard_iface_ready(const struct device *dev, const bool ready)
{ {
ARG_UNUSED(dev); ARG_UNUSED(dev);
iface_ready = ready; ctx.iface_ready = ready;
if (!ready) { if (!ready) {
report_in_flight = false; ctx.report_in_flight = false;
} }
LOG_INF("%s interface %s", hid_dev->name, ready ? "ready" : "not ready"); LOG_INF("%s interface %s", ctx.hid_dev->name,
ready ? "ready" : "not ready");
publish_keyboard_state(); publish_keyboard_state();
} }
@@ -164,11 +191,11 @@ static void keyboard_set_protocol(const struct device *dev, const uint8_t proto)
enum keyboard_protocol_mode new_mode = usb_proto_to_keyboard_proto(proto); enum keyboard_protocol_mode new_mode = usb_proto_to_keyboard_proto(proto);
if (keyboard_protocol_mode == new_mode) { if (ctx.keyboard_protocol_mode == new_mode) {
return; return;
} }
keyboard_protocol_mode = new_mode; ctx.keyboard_protocol_mode = new_mode;
LOG_INF("USB keyboard protocol -> %s", LOG_INF("USB keyboard protocol -> %s",
(new_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? "boot" : "report"); (new_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? "boot" : "report");
submit_set_protocol_event(HID_TRANSPORT_USB, new_mode); submit_set_protocol_event(HID_TRANSPORT_USB, new_mode);
@@ -181,10 +208,10 @@ static void keyboard_input_report_done(const struct device *dev,
ARG_UNUSED(dev); ARG_UNUSED(dev);
ARG_UNUSED(report); ARG_UNUSED(report);
report_in_flight = false; ctx.report_in_flight = false;
submit_hid_report_sent_event(HID_SEND_CH_USB_KEYS, submit_hid_report_sent_event(HID_SEND_CH_USB_KEYS,
KEYBOARD_REPORT_TYPE_KEYS, KEYBOARD_REPORT_TYPE_KEYS,
in_flight_sequence, false); ctx.in_flight_sequence, false);
} }
static void keyboard_output_report(const struct device *dev, static void keyboard_output_report(const struct device *dev,
@@ -211,60 +238,60 @@ static const struct hid_device_ops keyboard_ops = {
static int usb_hid_keyboard_register_device(void) static int usb_hid_keyboard_register_device(void)
{ {
if (!device_is_ready(hid_dev)) { if (!device_is_ready(ctx.hid_dev)) {
LOG_ERR("HID device %s not ready", hid_dev->name); LOG_ERR("HID device %s not ready", ctx.hid_dev->name);
return -ENODEV; return -ENODEV;
} }
return hid_device_register(hid_dev, keyboard_report_desc, return hid_device_register(ctx.hid_dev, keyboard_report_desc,
sizeof(keyboard_report_desc), &keyboard_ops); sizeof(keyboard_report_desc), &keyboard_ops);
} }
USB_FUNCTION_HOOK_DEFINE(usb_hid_keyboard_hook, usb_hid_keyboard_register_device); USB_FUNCTION_HOOK_DEFINE(usb_hid_keyboard_hook, usb_hid_keyboard_register_device);
static int module_init(void) static int do_init(void)
{ {
keyboard_protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; ctx.keyboard_protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
usb_active = false; ctx.usb_active = false;
iface_ready = false; ctx.iface_ready = false;
report_in_flight = false; ctx.report_in_flight = false;
return 0; return 0;
} }
static int module_start(void) static int do_start(void)
{ {
if (running) { if (module_lifecycle_is_running(&ctx.lc)) {
return 0; return 0;
} }
running = true;
publish_keyboard_state(); publish_keyboard_state();
return 0; return 0;
} }
static void module_pause(void) static int do_stop(void)
{ {
if (!running) { if (!module_lifecycle_is_running(&ctx.lc)) {
return; return 0;
} }
running = false; ctx.report_in_flight = false;
report_in_flight = false;
publish_keyboard_state(); publish_keyboard_state();
return 0;
} }
static bool handle_usb_state_event(const struct usb_state_event *event) static bool handle_usb_state_event(const struct usb_state_event *event)
{ {
bool new_usb_active = (event->state == USB_STATE_ACTIVE); bool new_usb_active = (event->state == USB_STATE_ACTIVE);
if (new_usb_active == usb_active) { if (new_usb_active == ctx.usb_active) {
return false; return false;
} }
usb_active = new_usb_active; ctx.usb_active = new_usb_active;
if (!usb_active) { if (!ctx.usb_active) {
iface_ready = false; ctx.iface_ready = false;
report_in_flight = false; ctx.report_in_flight = false;
} }
publish_keyboard_state(); publish_keyboard_state();
@@ -275,7 +302,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
{ {
int err; int err;
if (!running || !usb_active || if (!module_lifecycle_is_running(&ctx.lc) || !ctx.usb_active ||
(event->channel != HID_SEND_CH_USB_KEYS)) { (event->channel != HID_SEND_CH_USB_KEYS)) {
return false; return false;
} }
@@ -284,22 +311,22 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
return false; return false;
} }
if (event->protocol_mode != keyboard_protocol_mode) { if (event->protocol_mode != ctx.keyboard_protocol_mode) {
LOG_WRN("Drop USB keys report due to protocol mismatch"); LOG_WRN("Drop USB keys report due to protocol mismatch");
return false; return false;
} }
if (!iface_ready) { if (!ctx.iface_ready) {
return false; return false;
} }
if (report_in_flight) { if (ctx.report_in_flight) {
LOG_WRN("Drop USB keyboard report while previous report is in flight"); LOG_WRN("Drop USB keyboard report while previous report is in flight");
return false; return false;
} }
memcpy(keyboard_tx_buf, event->dyndata.data, event->dyndata.size); memcpy(keyboard_tx_buf, event->dyndata.data, event->dyndata.size);
err = hid_device_submit_report(hid_dev, (uint16_t)event->dyndata.size, err = hid_device_submit_report(ctx.hid_dev, (uint16_t)event->dyndata.size,
keyboard_tx_buf); keyboard_tx_buf);
if (err) { if (err) {
LOG_WRN("USB keyboard report submit failed (%d)", err); LOG_WRN("USB keyboard report submit failed (%d)", err);
@@ -307,8 +334,8 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
KEYBOARD_REPORT_TYPE_KEYS, KEYBOARD_REPORT_TYPE_KEYS,
event->sequence, true); event->sequence, true);
} else { } else {
report_in_flight = true; ctx.report_in_flight = true;
in_flight_sequence = event->sequence; ctx.in_flight_sequence = event->sequence;
} }
return false; return false;
@@ -326,48 +353,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
if (is_module_state_event(aeh)) { if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh); const struct module_state_event *event = cast_module_state_event(aeh);
int err;
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
if (!initialized) { (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;
} }
if (is_power_down_event(aeh)) { if (is_power_down_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
module_pause(); (void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
module_set_state(MODULE_STATE_STANDBY);
} }
return false; return false;
} }
if (is_wake_up_event(aeh)) { if (is_wake_up_event(aeh)) {
if (initialized) { if (module_lifecycle_is_initialized(&ctx.lc)) {
int err = module_start(); (void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
} }
return false; return false;