From ceebaaa600ca54d80e0ea374342c556edc561769 Mon Sep 17 00:00:00 2001 From: skiinder Date: Fri, 17 Apr 2026 19:12:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F=E7=AE=A1=E7=90=86=E6=A1=86?= =?UTF-8?q?=E6=9E=B6=E5=B9=B6=E9=87=8D=E6=9E=84=E7=8E=B0=E6=9C=89=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加了模块生命周期管理头文件 module_lifecycle.h,定义了完整的生命周期状态机, 包括初始化、运行、停止、挂起和错误状态。同时将电池模块、BLE BAS模块、BLE HID 模块和BLE NUS模块重构为使用新的生命周期框架进行状态管理。 提升日志缓冲区大小以支持更详细的调试信息记录。 --- inc/module_lifecycle.h | 204 ++++++++++++++++++++++++++++++++++ prj.conf | 3 + src/battery_module.c | 143 ++++++++++++------------ src/ble_bas_module.c | 109 ++++++++++-------- src/ble_hid_module.c | 193 ++++++++++++++++---------------- src/ble_nus_module.c | 100 +++++++++-------- src/display_module.c | 162 ++++++++++++++------------- src/encoder_module.c | 125 +++++++++++---------- src/hid_flowctrl_module.c | 123 +++++++++++--------- src/keyboard_core_module.c | 101 +++++++++-------- src/led_strip_module.c | 180 +++++++++++++++--------------- src/mode_policy_module.c | 95 ++++++++-------- src/mode_switch_module.c | 126 ++++++++++----------- src/protocol_module.c | 90 +++++++-------- src/time_sync_module.c | 118 ++++++++++---------- src/usb_cdc_module.c | 177 +++++++++++++++-------------- src/usb_device_module.c | 96 ++++++++-------- src/usb_hid_consumer_module.c | 141 +++++++++++------------ src/usb_hid_keyboard_module.c | 154 ++++++++++++------------- 19 files changed, 1361 insertions(+), 1079 deletions(-) create mode 100644 inc/module_lifecycle.h diff --git a/inc/module_lifecycle.h b/inc/module_lifecycle.h new file mode 100644 index 0000000..a5cd8c3 --- /dev/null +++ b/inc/module_lifecycle.h @@ -0,0 +1,204 @@ +#ifndef MODULE_LIFECYCLE_H_ +#define MODULE_LIFECYCLE_H_ + +#include +#include + +#include + +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_ */ diff --git a/prj.conf b/prj.conf index 7c6cda3..66bbfb2 100644 --- a/prj.conf +++ b/prj.conf @@ -26,7 +26,10 @@ CONFIG_FLASH_MAP=y CONFIG_NVS=y CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_LOG=y +CONFIG_LOG_BUFFER_SIZE=16384 +CONFIG_LOG_BACKEND_RTT_OUTPUT_BUFFER_SIZE=16384 CONFIG_ASSERT=y +CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=16384 CONFIG_APP_EVENT_MANAGER_MAX_EVENT_CNT=64 CONFIG_LED_STRIP=y CONFIG_WS2812_STRIP_SPI=y diff --git a/src/battery_module.c b/src/battery_module.c index c83ecfc..87c7f82 100644 --- a/src/battery_module.c +++ b/src/battery_module.c @@ -18,6 +18,7 @@ #include #include "bat_state_event.h" +#include "module_lifecycle.h" 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), "Missing ip5306 node in devicetree"); -static const struct device *const vbatt_dev = DEVICE_DT_GET(VBATT_NODE); -static const struct device *const ip5306_dev = DEVICE_DT_GET(IP5306_NODE); -static struct k_work_delayable battery_sample_work; -static struct { - bool valid; - uint8_t soc; - bool charging; - bool full; -} last_bat_state; -static bool initialized; -static bool running; +struct battery_module_ctx { + struct module_lifecycle_ctx lc; + const struct device *vbatt_dev; + const struct device *ip5306_dev; + struct k_work_delayable battery_sample_work; + struct { + bool valid; + uint8_t soc; + bool charging; + bool full; + } last_bat_state; +}; + +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) { @@ -53,7 +80,7 @@ static int measurement_enable(bool enable) { enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME : 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)) { 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); - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return; } - err = sensor_sample_fetch(vbatt_dev); + err = sensor_sample_fetch(ctx.vbatt_dev); if (err) { LOG_WRN("Battery sample fetch failed (%d)", err); 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) { LOG_WRN("Battery channel get failed (%d)", err); goto reschedule; } - err = ip5306_get_status(ip5306_dev, &pmic_status); + err = ip5306_get_status(ctx.ip5306_dev, &pmic_status); if (err) { LOG_WRN("IP5306 status read failed (%d)", err); goto reschedule; @@ -115,53 +142,53 @@ static void battery_sample_fn(struct k_work *work) voltage_mv = sensor_value_to_mv(&voltage); uint8_t soc = battery_soc_from_mv(voltage_mv); - if (!last_bat_state.valid || - (last_bat_state.soc != soc) || - (last_bat_state.charging != pmic_status.charging) || - (last_bat_state.full != pmic_status.full)) { - last_bat_state.valid = true; - last_bat_state.soc = soc; - last_bat_state.charging = pmic_status.charging; - last_bat_state.full = pmic_status.full; + if (!ctx.last_bat_state.valid || + (ctx.last_bat_state.soc != soc) || + (ctx.last_bat_state.charging != pmic_status.charging) || + (ctx.last_bat_state.full != pmic_status.full)) { + ctx.last_bat_state.valid = true; + ctx.last_bat_state.soc = soc; + ctx.last_bat_state.charging = pmic_status.charging; + ctx.last_bat_state.full = pmic_status.full; submit_bat_state_event(soc, pmic_status.charging, pmic_status.full); } reschedule: - if (running) { - k_work_reschedule(&battery_sample_work, BATTERY_SAMPLE_INTERVAL); + if (module_lifecycle_is_running(&ctx.lc)) { + 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"); return -ENODEV; } - if (!device_is_ready(ip5306_dev)) { + if (!device_is_ready(ctx.ip5306_dev)) { LOG_ERR("ip5306 device not ready"); return -ENODEV; } - int err = ip5306_init(ip5306_dev); + int err = ip5306_init(ctx.ip5306_dev); if (err) { LOG_ERR("ip5306 init failed (%d)", err); return err; } - k_work_init_delayable(&battery_sample_work, battery_sample_fn); - memset(&last_bat_state, 0, sizeof(last_bat_state)); + k_work_init_delayable(&ctx.battery_sample_work, battery_sample_fn); + memset(&ctx.last_bat_state, 0, sizeof(ctx.last_bat_state)); power_manager_restrict(MODULE_IDX(MODULE), POWER_MANAGER_LEVEL_SUSPENDED); return 0; } -static int module_start(void) +static int do_start(void) { int err; - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } @@ -170,21 +197,21 @@ static int module_start(void) return err; } - running = true; - k_work_reschedule(&battery_sample_work, K_NO_WAIT); + k_work_reschedule(&ctx.battery_sample_work, K_NO_WAIT); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } - (void)k_work_cancel_delayable(&battery_sample_work); + (void)k_work_cancel_delayable(&ctx.battery_sample_work); (void)measurement_enable(false); - running = false; + + return 0; } 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); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - int err; - - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/ble_bas_module.c b/src/ble_bas_module.c index 36ba566..22da91c 100644 --- a/src/ble_bas_module.c +++ b/src/ble_bas_module.c @@ -11,34 +11,54 @@ #include #include "bat_state_event.h" +#include "module_lifecycle.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); -static uint8_t current_soc = 100U; -static bool initialized; -static bool running; -static bool ble_ready; +struct ble_bas_module_ctx { + struct module_lifecycle_ctx lc; + uint8_t current_soc; + 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; } -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; } - running = true; - - if (!ble_ready) { - return 0; - } - - err = bt_bas_set_battery_level(current_soc); if (err) { LOG_WRN("bt_bas_set_battery_level failed (%d)", err); return err; @@ -47,21 +67,30 @@ static int module_start(void) 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) { - current_soc = event->soc; + ctx.current_soc = event->soc; - if (running && ble_ready) { - int err = bt_bas_set_battery_level(current_soc); - - if (err) { - LOG_WRN("bt_bas_set_battery_level failed (%d)", err); - } + if (module_lifecycle_is_running(&ctx.lc) && ctx.ble_ready) { + (void)bas_update_level(); } return false; @@ -75,38 +104,22 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); - int err; - if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - 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); - } + (void)module_set_lifecycle(&ctx.lc, + ctx.ble_ready ? LC_RUNNING : + LC_STOPPED); return false; } if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) { - ble_ready = true; + ctx.ble_ready = true; - if (running) { - err = bt_bas_set_battery_level(current_soc); - if (err) { - LOG_WRN("bt_bas_set_battery_level failed (%d)", err); - } + if (ctx.lc.state == LC_STOPPED) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); + } else if (module_lifecycle_is_running(&ctx.lc)) { + (void)bas_update_level(); } - - module_set_state(MODULE_STATE_READY); return false; } diff --git a/src/ble_hid_module.c b/src/ble_hid_module.c index 402cd6b..18383f8 100644 --- a/src/ble_hid_module.c +++ b/src/ble_hid_module.c @@ -18,6 +18,7 @@ #include "hid_report_sent_event.h" #include "hid_tx_report_event.h" #include "keyboard_core.h" +#include "module_lifecycle.h" #include "set_protocol_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); @@ -40,15 +41,40 @@ BT_HIDS_DEF(hids_obj, KEYBOARD_CONSUMER_REPORT_SIZE, BLE_HID_KEYS_LED_REPORT_SIZE); -static struct bt_conn *active_conn; -static struct in_flight_report in_flight; -static enum keyboard_protocol_mode protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; -static bool initialized; -static bool running; -static bool secured; -static bool keyboard_report_notify_enabled; -static bool consumer_report_notify_enabled; -static bool boot_keyboard_notify_enabled; +struct ble_hid_module_ctx { + struct module_lifecycle_ctx lc; + struct bt_conn *active_conn; + struct in_flight_report in_flight; + enum keyboard_protocol_mode protocol_mode; + bool secured; + bool keyboard_report_notify_enabled; + bool consumer_report_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[] = { 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) { - 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; - if (ready && ((protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? - boot_keyboard_notify_enabled : - keyboard_report_notify_enabled)) { + if (ready && ((ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? + ctx.boot_keyboard_notify_enabled : + ctx.keyboard_report_notify_enabled)) { report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_KEYS); } - if (ready && (protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT) && - consumer_report_notify_enabled) { + if (ready && (ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT) && + ctx.consumer_report_notify_enabled) { report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_CONSUMER); } submit_hid_channel_state_event( HID_SEND_CH_BLE_SHARED, report_ready_bm, - protocol_mode); + ctx.protocol_mode); } 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); 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) { - consumer_report_notify_enabled = enabled; + ctx.consumer_report_notify_enabled = enabled; } 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) { - 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(); } @@ -144,14 +171,14 @@ static void hid_report_complete_cb(struct bt_conn *conn, void *user_data) ARG_UNUSED(conn); ARG_UNUSED(user_data); - if (!in_flight.active) { + if (!ctx.in_flight.active) { return; } submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED, - in_flight.report_type, - in_flight.sequence, false); - in_flight.active = false; + ctx.in_flight.report_type, + ctx.in_flight.sequence, false); + ctx.in_flight.active = false; } 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) { case BT_HIDS_PM_EVT_BOOT_MODE_ENTERED: - protocol_mode = KEYBOARD_PROTOCOL_MODE_BOOT; + ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_BOOT; break; case BT_HIDS_PM_EVT_REPORT_MODE_ENTERED: - protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; + ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; break; default: 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(); } -static int module_init(void) +static int do_init(void) { struct bt_hids_init_param hids_init_param = { 0 }; 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); } -static int module_start(void) +static int do_start(void) { - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - running = true; submit_ble_transport_state_event(); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } - in_flight.active = false; - running = false; + ctx.in_flight.active = false; submit_ble_transport_state_event(); + + return 0; } static void reset_connection_state(void) { - active_conn = NULL; - secured = false; - keyboard_report_notify_enabled = false; - consumer_report_notify_enabled = false; - boot_keyboard_notify_enabled = false; - protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; - in_flight.active = false; + ctx.active_conn = NULL; + ctx.secured = false; + ctx.keyboard_report_notify_enabled = false; + ctx.consumer_report_notify_enabled = false; + ctx.boot_keyboard_notify_enabled = false; + ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; + ctx.in_flight.active = false; } 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) { case PEER_STATE_CONNECTED: - if (active_conn != NULL) { + if (ctx.active_conn != NULL) { return false; } - active_conn = event->id; - protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; - submit_set_protocol_event(HID_TRANSPORT_BLE, protocol_mode); + ctx.active_conn = event->id; + ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; + submit_set_protocol_event(HID_TRANSPORT_BLE, ctx.protocol_mode); err = bt_hids_connected(&hids_obj, event->id); if (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; case PEER_STATE_SECURED: - if (active_conn != event->id) { + if (ctx.active_conn != event->id) { return false; } - secured = true; + ctx.secured = true; submit_ble_transport_state_event(); return false; case PEER_STATE_DISCONNECTED: - if (active_conn != event->id) { + if (ctx.active_conn != event->id) { return false; } @@ -325,34 +352,35 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event) { int err; - if (!running || (event->channel != HID_SEND_CH_BLE_SHARED) || - in_flight.active) { + if (!module_lifecycle_is_running(&ctx.lc) || + (event->channel != HID_SEND_CH_BLE_SHARED) || + ctx.in_flight.active) { return false; } - if ((active_conn == NULL) || !secured) { + if ((ctx.active_conn == NULL) || !ctx.secured) { return false; } 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"); return false; } - in_flight.active = true; - in_flight.report_type = event->report_type; - in_flight.sequence = event->sequence; + ctx.in_flight.active = true; + ctx.in_flight.report_type = event->report_type; + 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, - active_conn, + ctx.active_conn, event->dyndata.data, (uint8_t)event->dyndata.size, hid_report_complete_cb); } else { err = bt_hids_inp_rep_send(&hids_obj, - active_conn, + ctx.active_conn, BLE_HID_KEYS_REPORT_IDX, event->dyndata.data, (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) { - in_flight.active = false; + ctx.in_flight.active = false; LOG_WRN("BLE keyboard report submit failed (%d)", err); submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED, 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 (protocol_mode != KEYBOARD_PROTOCOL_MODE_REPORT) { + if (ctx.protocol_mode != KEYBOARD_PROTOCOL_MODE_REPORT) { LOG_WRN("Drop BLE consumer report in boot mode"); return false; } - in_flight.active = true; - in_flight.report_type = event->report_type; - in_flight.sequence = event->sequence; + ctx.in_flight.active = true; + ctx.in_flight.report_type = event->report_type; + ctx.in_flight.sequence = event->sequence; err = bt_hids_inp_rep_send(&hids_obj, - active_conn, + ctx.active_conn, BLE_HID_CONSUMER_REPORT_IDX, event->dyndata.data, (uint8_t)event->dyndata.size, hid_report_complete_cb); if (err) { - in_flight.active = false; + ctx.in_flight.active = false; LOG_WRN("BLE consumer report submit failed (%d)", err); submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED, 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)) { const struct module_state_event *event = cast_module_state_event(aeh); - int err; if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/ble_nus_module.c b/src/ble_nus_module.c index 9256c77..00518b6 100644 --- a/src/ble_nus_module.c +++ b/src/ble_nus_module.c @@ -13,6 +13,7 @@ #include #include +#include "module_lifecycle.h" #include "proto_rx_event.h" #include "proto_transport_state_event.h" #include "proto_tx_event.h" @@ -27,20 +28,39 @@ enum ble_nus_business_state { }; struct ble_nus_ctx { - enum module_state lifecycle; + struct module_lifecycle_ctx lc; enum ble_nus_business_state business; 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 = { - .lifecycle = MODULE_STATE_OFF, + .lc = { + .state = LC_UNINIT, + .cfg = &lifecycle_cfg, + .ops = &lifecycle_ops, + }, .business = BLE_NUS_STACK_OFFLINE, .active_conn = NULL, }; 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) @@ -51,11 +71,11 @@ static enum proto_transport_link_state transport_link_state_get(void) 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 proto_transport_link_state old_link = - ((old_lifecycle == MODULE_STATE_READY) && + ((old_lifecycle == LC_RUNNING) && (old_business == BLE_NUS_SESSION_READY)) ? PROTO_TRANSPORT_LINK_READY : PROTO_TRANSPORT_LINK_DOWN; @@ -67,23 +87,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 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) { - enum module_state old_lifecycle = ctx.lifecycle; + enum module_lifecycle old_lifecycle = ctx.lc.state; enum ble_nus_business_state old_business = ctx.business; if (ctx.business == new_state) { @@ -150,7 +156,7 @@ static void reset_connection_state(void) } } -static int module_init(void) +static int do_init(void) { int err; @@ -160,23 +166,33 @@ static int module_init(void) return err; } - ctx = (struct ble_nus_ctx) { - .lifecycle = MODULE_STATE_OFF, - .business = BLE_NUS_STACK_OFFLINE, - .active_conn = NULL, - }; + ctx.business = BLE_NUS_STACK_OFFLINE; + ctx.active_conn = NULL; 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); + } + + return err; } static bool handle_ble_peer_event(const struct ble_peer_event *event) @@ -243,27 +259,13 @@ static bool app_event_handler(const struct app_event_header *aeh) cast_module_state_event(aeh); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - if (ctx.lifecycle == MODULE_STATE_OFF) { - int err = module_init(); - - if (err) { - lifecycle_set(MODULE_STATE_ERROR); - return false; - } - } - - module_start(); - + (void)apply_lifecycle(LC_RUNNING); return false; } if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) { business_state_set_stack_ready(); - if (lifecycle_is_ready()) { - lifecycle_set(MODULE_STATE_READY); - } - return false; } @@ -271,16 +273,16 @@ static bool app_event_handler(const struct app_event_header *aeh) } if (is_power_down_event(aeh)) { - if (ctx.lifecycle != MODULE_STATE_OFF) { - module_pause(); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)apply_lifecycle(LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (ctx.lifecycle != MODULE_STATE_OFF) { - module_start(); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)apply_lifecycle(LC_RUNNING); } return false; diff --git a/src/display_module.c b/src/display_module.c index 08d773a..bc9ebca 100644 --- a/src/display_module.c +++ b/src/display_module.c @@ -16,6 +16,7 @@ #include "bat_state_event.h" #include "datetime_event.h" #include "hid_led_event.h" +#include "module_lifecycle.h" #include "mode_switch_event.h" #include "theme_rgb_update_event.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), "Missing backlight alias"); -static const struct device *const display_dev = - DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); -static const struct device *const backlight_dev = - DEVICE_DT_GET(DT_PARENT(DT_ALIAS(backlight))); -static const uint32_t backlight_idx = DT_NODE_CHILD_IDX(DT_ALIAS(backlight)); -static struct ui_main_model ui_model = { - .theme_color = LV_COLOR_MAKE(BLINKY_THEME_DEFAULT_R, - BLINKY_THEME_DEFAULT_G, - BLINKY_THEME_DEFAULT_B), - .inactive_border_color = LV_COLOR_MAKE(0x3A, 0x44, 0x52), - .mode = MODE_SWITCH_BLE, +struct display_module_ctx { + struct module_lifecycle_ctx lc; + const struct device *display_dev; + const struct device *backlight_dev; + uint32_t backlight_idx; + 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, + BLINKY_THEME_DEFAULT_G, + BLINKY_THEME_DEFAULT_B), + .inactive_border_color = LV_COLOR_MAKE(0x3A, 0x44, 0x52), + .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) { 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; - 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)) { - LOG_ERR("Display device %s not ready", display_dev->name); + if (!device_is_ready(ctx.display_dev)) { + LOG_ERR("Display device %s not ready", ctx.display_dev->name); return -ENODEV; } - if (!device_is_ready(backlight_dev)) { - LOG_ERR("Backlight device %s not ready", backlight_dev->name); + if (!device_is_ready(ctx.backlight_dev)) { + LOG_ERR("Backlight device %s not ready", ctx.backlight_dev->name); return -ENODEV; } @@ -79,25 +108,25 @@ static int module_init(void) return 0; } -static int module_start(void) +static int do_start(void) { int err; - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - if (!lvgl_initialized) { + if (!ctx.lvgl_initialized) { err = lvgl_init(); if (err) { LOG_ERR("lvgl_init failed (%d)", err); return err; } - lvgl_initialized = true; + ctx.lvgl_initialized = true; 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(); } @@ -107,39 +136,39 @@ static int module_start(void) return err; } - err = display_blanking_off(display_dev); + err = display_blanking_off(ctx.display_dev); if (err) { LOG_ERR("display_blanking_off failed (%d)", err); (void)backlight_set(false); return err; } - running = true; LOG_INF("LVGL display started"); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } - (void)display_blanking_on(display_dev); + (void)display_blanking_on(ctx.display_dev); (void)backlight_set(false); - running = false; LOG_INF("LVGL display paused"); + + return 0; } static void refresh_ui(void) { - if (!lvgl_initialized) { + if (!ctx.lvgl_initialized) { return; } 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(); } @@ -148,9 +177,9 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_bat_state_event(aeh)) { const struct bat_state_event *event = cast_bat_state_event(aeh); - ui_model.battery_level = event->soc; - ui_model.charging = event->charging; - ui_model.full = event->full; + ctx.ui_model.battery_level = event->soc; + ctx.ui_model.charging = event->charging; + ctx.ui_model.full = event->full; refresh_ui(); return false; } @@ -158,7 +187,7 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_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(); return false; } @@ -166,7 +195,7 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_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(); return false; } @@ -175,9 +204,9 @@ static bool app_event_handler(const struct app_event_header *aeh) const struct theme_rgb_update_event *event = cast_theme_rgb_update_event(aeh); - ui_model.theme_color = (lv_color_t)LV_COLOR_MAKE(event->theme.r, - event->theme.g, - event->theme.b); + ctx.ui_model.theme_color = (lv_color_t)LV_COLOR_MAKE(event->theme.r, + event->theme.g, + event->theme.b); refresh_ui(); return false; } @@ -185,58 +214,35 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_datetime_event(aeh)) { const struct datetime_event *event = cast_datetime_event(aeh); - strncpy(date_text, event->date_text, sizeof(date_text)); - date_text[sizeof(date_text) - 1] = '\0'; - strncpy(time_text, event->time_text, sizeof(time_text)); - time_text[sizeof(time_text) - 1] = '\0'; + strncpy(ctx.date_text, event->date_text, sizeof(ctx.date_text)); + ctx.date_text[sizeof(ctx.date_text) - 1] = '\0'; + strncpy(ctx.time_text, event->time_text, sizeof(ctx.time_text)); + ctx.time_text[sizeof(ctx.time_text) - 1] = '\0'; refresh_ui(); return false; } if (is_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 (!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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/encoder_module.c b/src/encoder_module.c index a902e0e..81a32b4 100644 --- a/src/encoder_module.c +++ b/src/encoder_module.c @@ -13,6 +13,7 @@ #include #include "encoder_event.h" +#include "module_lifecycle.h" 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"); -static const struct device *const qdec_dev = DEVICE_DT_GET(ENCODER_QDEC_NODE); - -static struct k_work encoder_report_work; -static struct sensor_trigger encoder_trigger = { - .type = SENSOR_TRIG_DATA_READY, - .chan = SENSOR_CHAN_ROTATION, +struct encoder_module_ctx { + struct module_lifecycle_ctx lc; + const struct device *qdec_dev; + struct k_work encoder_report_work; + struct sensor_trigger encoder_trigger; + int64_t angle_remainder_udeg; }; -static bool initialized; -static bool running; -static int64_t angle_remainder_udeg; +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 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) { @@ -68,25 +93,26 @@ static void encoder_report_work_handler(struct k_work *work) ARG_UNUSED(work); - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return; } - err = sensor_sample_fetch(qdec_dev); + err = sensor_sample_fetch(ctx.qdec_dev); if (err) { LOG_WRN("QDEC sample fetch failed (%d)", err); return; } - err = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &rotation); + err = sensor_channel_get(ctx.qdec_dev, SENSOR_CHAN_ROTATION, &rotation); if (err) { LOG_WRN("QDEC channel get failed (%d)", err); 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); - 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) { submit_detents_batched(detents); @@ -99,26 +125,27 @@ static void encoder_trigger_handler(const struct device *dev, ARG_UNUSED(dev); ARG_UNUSED(trigger); - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { 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; - if (!device_is_ready(qdec_dev)) { + if (!device_is_ready(ctx.qdec_dev)) { LOG_ERR("QDEC device not ready"); return -ENODEV; } - k_work_init(&encoder_report_work, encoder_report_work_handler); - angle_remainder_udeg = 0; + k_work_init(&ctx.encoder_report_work, encoder_report_work_handler); + 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) { LOG_ERR("Cannot set QDEC trigger (%d)", err); return err; @@ -127,41 +154,41 @@ static int module_init(void) return 0; } -static int module_start(void) +static int do_start(void) { int err; - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { 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)) { LOG_ERR("Cannot resume QDEC device (%d)", err); return err; } - angle_remainder_udeg = 0; - running = true; + ctx.angle_remainder_udeg = 0; return 0; } -static void module_pause(void) +static int do_stop(void) { int err; - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + 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)) { LOG_WRN("Cannot suspend QDEC device (%d)", err); } - angle_remainder_udeg = 0; - running = false; + ctx.angle_remainder_udeg = 0; + + return 0; } 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); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - int err; - - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/hid_flowctrl_module.c b/src/hid_flowctrl_module.c index 2436853..e0d450c 100644 --- a/src/hid_flowctrl_module.c +++ b/src/hid_flowctrl_module.c @@ -15,6 +15,7 @@ #include "hid_tx_report_event.h" #include "keyboard_core.h" #include "keyboard_hid_report_event.h" +#include "module_lifecycle.h" #include "mode_switch_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); @@ -49,28 +50,66 @@ struct in_flight_report { uint16_t sequence; }; -static struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT] = { - [HID_SEND_CH_USB_KEYS] = { - .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, +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, }, - [HID_SEND_CH_USB_CONSUMER] = { - .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, - }, - [HID_SEND_CH_BLE_SHARED] = { - .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, + .channel_state = { + [HID_SEND_CH_USB_KEYS] = { + .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, + }, + [HID_SEND_CH_USB_CONSUMER] = { + .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, + }, + [HID_SEND_CH_BLE_SHARED] = { + .protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT, + }, }, }; -static struct pending_report pending_keys; -static struct pending_report pending_consumer_latest; -static struct queued_report consumer_fifo[HID_FLOWCTRL_FIFO_DEPTH]; -static uint8_t consumer_fifo_head; -static uint8_t consumer_fifo_tail; -static uint8_t consumer_fifo_count; -static struct in_flight_report in_flight[HID_SEND_CH_COUNT]; -static enum mode_switch_mode current_mode; -static uint16_t next_sequence; -static bool initialized; -static bool running; + +#define lifecycle ctx.lc +#define channel_state ctx.channel_state +#define pending_keys ctx.pending_keys +#define pending_consumer_latest ctx.pending_consumer_latest +#define consumer_fifo ctx.consumer_fifo +#define consumer_fifo_head ctx.consumer_fifo_head +#define consumer_fifo_tail ctx.consumer_fifo_tail +#define consumer_fifo_count ctx.consumer_fifo_count +#define in_flight ctx.in_flight +#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, enum hid_send_channel *channel) @@ -359,7 +398,7 @@ static bool handle_mode_switch_event(const struct mode_switch_event *event) return false; } -static int module_init(void) +static int do_init(void) { clear_pending_reports(); current_mode = MODE_SWITCH_USB; @@ -374,25 +413,25 @@ static int module_init(void) return 0; } -static int module_start(void) +static int do_start(void) { if (running) { return 0; } - running = true; try_send_next(); return 0; } -static void module_pause(void) +static int do_stop(void) { if (!running) { - return; + return 0; } clear_pending_reports(); - running = false; + + return 0; } 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); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - int err; - - 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); - } + (void)module_set_lifecycle(&lifecycle, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&lifecycle)) { + (void)module_set_lifecycle(&lifecycle, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&lifecycle)) { + (void)module_set_lifecycle(&lifecycle, LC_RUNNING); } return false; diff --git a/src/keyboard_core_module.c b/src/keyboard_core_module.c index e53675d..d5aa94f 100644 --- a/src/keyboard_core_module.c +++ b/src/keyboard_core_module.c @@ -19,6 +19,7 @@ #include "function_bitmap_update_event.h" #include "keyboard_core.h" #include "keyboard_hid_report_event.h" +#include "module_lifecycle.h" #include "mode_switch_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, }; -static struct keyboard_state keyboard_state; -static struct keyboard_reports_cache reports_cache; -static uint8_t function_usage_mask[KEYBOARD_PROTOCOL_BITMAP_BYTES]; -static enum keyboard_protocol_mode transport_protocol_modes[HID_TRANSPORT_COUNT] = { - [HID_TRANSPORT_USB] = KEYBOARD_PROTOCOL_MODE_REPORT, - [HID_TRANSPORT_BLE] = KEYBOARD_PROTOCOL_MODE_REPORT, +struct keyboard_core_module_ctx { + struct module_lifecycle_ctx lc; + struct keyboard_state keyboard_state; + 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 enum mode_switch_mode current_mode; -static bool initialized; -static bool running; -static 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_BLE] = KEYBOARD_PROTOCOL_MODE_REPORT, + }, +}; + +#define lifecycle ctx.lc +#define keyboard_state ctx.keyboard_state +#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) { @@ -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(); reports_cache_invalidate(); @@ -454,20 +489,19 @@ static int module_init(void) return 0; } -static int module_start(void) +static int do_start(void) { if (running) { return 0; } - running = true; return 0; } -static void module_pause(void) +static int do_stop(void) { if (!running) { - return; + return 0; } if (mode_valid) { @@ -478,7 +512,8 @@ static void module_pause(void) keyboard_state_clear(); reports_cache_invalidate(); mode_valid = false; - running = false; + + return 0; } 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); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - int err; - - 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); - } + (void)module_set_lifecycle(&lifecycle, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&lifecycle)) { + (void)module_set_lifecycle(&lifecycle, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&lifecycle)) { + (void)module_set_lifecycle(&lifecycle, LC_RUNNING); } return false; diff --git a/src/led_strip_module.c b/src/led_strip_module.c index 81a67aa..730cf96 100644 --- a/src/led_strip_module.c +++ b/src/led_strip_module.c @@ -18,6 +18,7 @@ #include "led_effect/led_effect.h" #include "led_strip_en_event.h" +#include "module_lifecycle.h" #include "theme_rgb_update_event.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, "LED strip key map expects 17 pixels"); -static const struct device *const strip = DEVICE_DT_GET(LED_STRIP_NODE); -static const struct gpio_dt_spec strip_en = - GPIO_DT_SPEC_GET(LED_STRIP_NODE, supply_gpios); +struct led_strip_module_ctx { + struct module_lifecycle_ctx lc; + 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[] = { { KEY_ID(0, 1), 0U }, @@ -65,28 +73,47 @@ static const struct led_effect_config effect_cfg = { .default_brightness = 0xFFU, }; -static struct led_rgb pixels[LED_STRIP_NUM_PIXELS]; -static struct k_work_delayable effect_work; -static struct led_effect *effect; -static struct theme_rgb current_theme = { - .r = BLINKY_THEME_DEFAULT_R, - .g = BLINKY_THEME_DEFAULT_G, - .b = BLINKY_THEME_DEFAULT_B, +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 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, + .g = BLINKY_THEME_DEFAULT_G, + .b = BLINKY_THEME_DEFAULT_B, + }, + .enabled = true, }; -static bool initialized; -static bool running; -static bool enabled = true; static void clear_pixels(void) { - memset(pixels, 0, sizeof(pixels)); + memset(ctx.pixels, 0, sizeof(ctx.pixels)); } static int submit_frame(void) { 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) { LOG_WRN("led_strip_update_rgb failed (%d)", err); } @@ -98,7 +125,7 @@ static int set_strip_power(bool on) { 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) { 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) { - k_work_cancel_delayable(&effect_work); + k_work_cancel_delayable(&ctx.effect_work); } 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) @@ -148,13 +175,15 @@ static void effect_work_handler(struct k_work *work) ARG_UNUSED(work); - if (!running || !enabled || (effect == NULL)) { + if (!module_lifecycle_is_running(&ctx.lc) || !ctx.enabled || + (ctx.effect == NULL)) { return; } - keep_running = effect->ops->tick(effect, k_ticks_to_ms_floor32( - LED_STRIP_TICK_INTERVAL.ticks), - pixels, ARRAY_SIZE(pixels)); + keep_running = ctx.effect->ops->tick(ctx.effect, + k_ticks_to_ms_floor32( + LED_STRIP_TICK_INTERVAL.ticks), + ctx.pixels, ARRAY_SIZE(ctx.pixels)); (void)submit_frame(); 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; - if (!device_is_ready(strip)) { - LOG_ERR("LED strip device %s not ready", strip->name); + if (!device_is_ready(ctx.strip)) { + LOG_ERR("LED strip device %s not ready", ctx.strip->name); 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"); 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) { LOG_ERR("Failed to configure LED strip supply GPIO (%d)", err); return err; } - k_work_init_delayable(&effect_work, effect_work_handler); + k_work_init_delayable(&ctx.effect_work, effect_work_handler); clear_pixels(); - effect = led_effect_get_mutable(LED_EFFECT_ID_KEY_FADE); - if ((effect == NULL) || (effect->ops == NULL)) { + ctx.effect = led_effect_get_mutable(LED_EFFECT_ID_KEY_FADE); + if ((ctx.effect == NULL) || (ctx.effect->ops == NULL)) { LOG_ERR("LED effect not available"); return -ENOENT; } - err = effect->ops->init(effect, &effect_cfg); + err = ctx.effect->ops->init(ctx.effect, &effect_cfg); if (err) { LOG_ERR("LED effect init failed (%d)", err); return err; } - effect->ops->set_theme(effect, ¤t_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; } -static int module_start(void) +static int do_start(void) { int err; - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - running = true; - - if (!enabled) { + if (!ctx.enabled) { return 0; } err = enable_strip_output(); - if (err) { - running = false; - } - return err; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } - if ((effect != NULL) && (effect->ops != NULL)) { - effect->ops->reset(effect); + if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) { + ctx.effect->ops->reset(ctx.effect); } disable_strip_output(); - running = false; + return 0; } 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; } - 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); 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) { - enabled = event->enabled; + ctx.enabled = event->enabled; - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return false; } - if (enabled) { + if (ctx.enabled) { int err = enable_strip_output(); if (err) { - module_set_state(MODULE_STATE_ERROR); + LOG_WRN("LED strip enable request failed (%d)", err); + ctx.enabled = false; return false; } } else { - if ((effect != NULL) && (effect->ops != NULL)) { - effect->ops->reset(effect); + if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) { + ctx.effect->ops->reset(ctx.effect); } 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) { - current_theme = event->theme; + ctx.current_theme = event->theme; - if ((effect != NULL) && (effect->ops != NULL)) { - effect->ops->set_theme(effect, ¤t_theme); + if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) { + 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); } @@ -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); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - int err; - - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/mode_policy_module.c b/src/mode_policy_module.c index 7cd6abb..8cc3733 100644 --- a/src/mode_policy_module.c +++ b/src/mode_policy_module.c @@ -9,14 +9,40 @@ #include +#include "module_lifecycle.h" #include "mode_switch_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); -static bool initialized; -static bool running; -static bool ble_adv_suspended = true; -static bool usb_enabled; +struct mode_policy_module_ctx { + struct module_lifecycle_ctx lc; + bool ble_adv_suspended; + bool usb_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 mode_policy_module_ctx ctx = { + .lc = { + .state = LC_UNINIT, + .cfg = &lifecycle_cfg, + .ops = &lifecycle_ops, + }, + .ble_adv_suspended = true, +}; static void broadcast_ble_adv_req(bool suspend) { @@ -40,14 +66,14 @@ static void apply_mode_policy(enum mode_switch_mode mode) bool should_suspend_ble_adv = (mode != MODE_SWITCH_BLE); bool should_enable_usb = (mode == MODE_SWITCH_USB); - if (should_suspend_ble_adv != ble_adv_suspended) { - ble_adv_suspended = should_suspend_ble_adv; + if (should_suspend_ble_adv != ctx.ble_adv_suspended) { + ctx.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) { + if (should_enable_usb != ctx.usb_enabled) { + ctx.usb_enabled = should_enable_usb; + if (ctx.usb_enabled) { struct module_resume_req_event *event = new_module_resume_req_event(); @@ -65,26 +91,25 @@ static void apply_mode_policy(enum mode_switch_mode mode) } } -static int module_init(void) +static int do_init(void) { - ble_adv_suspended = true; - usb_enabled = false; + ctx.ble_adv_suspended = true; + ctx.usb_enabled = false; return 0; } -static int module_start(void) +static int do_start(void) { - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - running = true; return 0; } -static void module_pause(void) +static int do_stop(void) { - running = false; + return 0; } static bool app_event_handler(const struct app_event_header *aeh) @@ -92,7 +117,7 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_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); } @@ -103,47 +128,23 @@ static bool app_event_handler(const struct app_event_header *aeh) const struct module_state_event *event = cast_module_state_event(aeh); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - int err; - - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/mode_switch_module.c b/src/mode_switch_module.c index 8015f8f..0afc280 100644 --- a/src/mode_switch_module.c +++ b/src/mode_switch_module.c @@ -14,6 +14,7 @@ #include #include +#include "module_lifecycle.h" #include "mode_switch_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); @@ -26,15 +27,38 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); BUILD_ASSERT(DT_NODE_EXISTS(MODE_SWITCH_ADC_NODE), "Missing mode_switch_adc node in devicetree"); -static const struct device *const mode_switch_adc_dev = - DEVICE_DT_GET(MODE_SWITCH_ADC_NODE); +struct mode_switch_module_ctx { + struct module_lifecycle_ctx lc; + const struct device *mode_switch_adc_dev; + struct k_work_delayable mode_switch_sample_work; + bool force_report; + bool mode_valid; + enum mode_switch_mode last_mode; +}; -static struct k_work_delayable mode_switch_sample_work; -static bool initialized; -static bool running; -static bool force_report; -static bool mode_valid; -static enum mode_switch_mode last_mode; +static int do_init(void); +static int do_start(void); +static int do_stop(void); + +static const struct module_lifecycle_cfg lifecycle_cfg = { + .mode = ML_MODE_POWER, + .stopped_state = MODULE_STATE_STANDBY, +}; + +static const struct module_lifecycle_ops lifecycle_ops = { + .do_init = do_init, + .do_start = do_start, + .do_stop = do_stop, +}; + +static struct mode_switch_module_ctx ctx = { + .lc = { + .state = LC_UNINIT, + .cfg = &lifecycle_cfg, + .ops = &lifecycle_ops, + }, + .mode_switch_adc_dev = DEVICE_DT_GET(MODE_SWITCH_ADC_NODE), +}; static enum mode_switch_mode detect_mode(uint16_t voltage_mv) { @@ -53,7 +77,7 @@ static int mode_switch_enable(bool enable) { enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME : PM_DEVICE_ACTION_SUSPEND; - int err = pm_device_action_run(mode_switch_adc_dev, action); + int err = pm_device_action_run(ctx.mode_switch_adc_dev, action); if (err && (err != -EALREADY) && (err != -ENOTSUP)) { LOG_ERR("Cannot %s mode switch ADC (%d)", @@ -71,17 +95,18 @@ static void mode_switch_sample_fn(struct k_work *work) ARG_UNUSED(work); - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return; } - err = sensor_sample_fetch(mode_switch_adc_dev); + err = sensor_sample_fetch(ctx.mode_switch_adc_dev); if (err) { LOG_WRN("Mode switch ADC sample fetch failed (%d)", err); goto reschedule; } - err = sensor_channel_get(mode_switch_adc_dev, SENSOR_CHAN_VOLTAGE, &voltage); + err = sensor_channel_get(ctx.mode_switch_adc_dev, SENSOR_CHAN_VOLTAGE, + &voltage); if (err) { LOG_WRN("Mode switch ADC channel get failed (%d)", err); goto reschedule; @@ -90,39 +115,40 @@ static void mode_switch_sample_fn(struct k_work *work) uint16_t sample_mv = (uint16_t)((voltage.val1 * 1000) + (voltage.val2 / 1000)); enum mode_switch_mode mode = detect_mode(sample_mv); - if (force_report || !mode_valid || (mode != last_mode)) { + if (ctx.force_report || !ctx.mode_valid || (mode != ctx.last_mode)) { submit_mode_switch_event(mode, sample_mv); - last_mode = mode; - mode_valid = true; - force_report = false; + ctx.last_mode = mode; + ctx.mode_valid = true; + ctx.force_report = false; } reschedule: - if (running) { - k_work_reschedule(&mode_switch_sample_work, MODE_SWITCH_SAMPLE_INTERVAL); + if (module_lifecycle_is_running(&ctx.lc)) { + 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"); return -ENODEV; } - k_work_init_delayable(&mode_switch_sample_work, mode_switch_sample_fn); - mode_valid = false; - force_report = false; + k_work_init_delayable(&ctx.mode_switch_sample_work, mode_switch_sample_fn); + ctx.mode_valid = false; + ctx.force_report = false; return 0; } -static int module_start(void) +static int do_start(void) { int err; - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } @@ -131,22 +157,22 @@ static int module_start(void) return err; } - running = true; - force_report = true; - k_work_reschedule(&mode_switch_sample_work, K_NO_WAIT); + ctx.force_report = true; + k_work_reschedule(&ctx.mode_switch_sample_work, K_NO_WAIT); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + 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); - running = false; + + return 0; } static bool app_event_handler(const struct app_event_header *aeh) @@ -155,47 +181,23 @@ static bool app_event_handler(const struct app_event_header *aeh) const struct module_state_event *event = cast_module_state_event(aeh); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - int err; - - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/protocol_module.c b/src/protocol_module.c index 1315fdf..c441eee 100644 --- a/src/protocol_module.c +++ b/src/protocol_module.c @@ -21,6 +21,7 @@ #include "function_bitmap_state_event.h" #include "function_bitmap_update_event.h" #include "hid_led_event.h" +#include "module_lifecycle.h" #include "proto_rx_event.h" #include "proto_transport_state_event.h" #include "proto_tx_event.h" @@ -38,16 +39,41 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); #define PROTOCOL_CAPABILITY_FLAGS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4)) #define PROTOCOL_MAX_MSG_LEN 128U -static bool initialized; -static bool running; - enum proto_session_state { PROTO_SESSION_DOWN = 0, PROTO_SESSION_WAIT_HELLO, 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 int decode_body(const uint8_t *payload, size_t payload_len, CdcPacketBody *body) @@ -157,7 +183,7 @@ static int encode_function_bitmap_state(const uint8_t *bitmap, uint8_t *payload, 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++) { session_state[i] = PROTO_SESSION_DOWN; @@ -166,27 +192,26 @@ static int module_init(void) return 0; } -static int module_start(void) +static int do_start(void) { - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - running = true; return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) { session_state[i] = PROTO_SESSION_DOWN; } - running = false; + return 0; } int protocol_module_process_message(enum proto_transport transport, @@ -204,7 +229,7 @@ int protocol_module_process_message(enum proto_transport transport, return -EINVAL; } - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return -EAGAIN; } @@ -317,7 +342,7 @@ static bool handle_proto_rx_event(const struct proto_rx_event *event) size_t rsp_payload_len = 0U; int err; - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return false; } @@ -373,7 +398,7 @@ static bool handle_function_bitmap_state_event( size_t payload_len; int err; - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return false; } @@ -406,7 +431,7 @@ static bool handle_hid_led_event(const struct hid_led_event *event) int err; enum proto_transport transport; - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return false; } @@ -454,25 +479,9 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); - int err; if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); return false; } @@ -481,23 +490,16 @@ static bool app_event_handler(const struct app_event_header *aeh) } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/time_sync_module.c b/src/time_sync_module.c index e020780..7126ce5 100644 --- a/src/time_sync_module.c +++ b/src/time_sync_module.c @@ -13,18 +13,43 @@ #include #include "datetime_event.h" +#include "module_lifecycle.h" #include "time_sync_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); #define TIME_SYNC_REFRESH_PERIOD K_SECONDS(1) -static struct k_work_delayable refresh_work; -static bool initialized; -static bool running; -static int32_t timezone_min; -static uint64_t utc_ms_base; -static int64_t uptime_ms_base; +struct time_sync_module_ctx { + struct module_lifecycle_ctx lc; + struct k_work_delayable refresh_work; + int32_t timezone_min; + uint64_t utc_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) { @@ -34,9 +59,9 @@ static void publish_datetime_event(void) char date_text[DATETIME_EVENT_DATE_TEXT_LEN]; char time_text[DATETIME_EVENT_TIME_TEXT_LEN]; - local_ms = (int64_t)utc_ms_base + - (k_uptime_get() - uptime_ms_base) + - ((int64_t)timezone_min * 60LL * 1000LL); + local_ms = (int64_t)ctx.utc_ms_base + + (k_uptime_get() - ctx.uptime_ms_base) + + ((int64_t)ctx.timezone_min * 60LL * 1000LL); if (local_ms < 0) { local_ms = 0; } @@ -67,43 +92,43 @@ static void refresh_work_handler(struct k_work *work) { ARG_UNUSED(work); - if (!running) { + if (!module_lifecycle_is_running(&ctx.lc)) { return; } 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; - utc_ms_base = 0U; - uptime_ms_base = k_uptime_get(); - k_work_init_delayable(&refresh_work, refresh_work_handler); + ctx.timezone_min = 0; + ctx.utc_ms_base = 0U; + ctx.uptime_ms_base = k_uptime_get(); + k_work_init_delayable(&ctx.refresh_work, refresh_work_handler); return 0; } -static int module_start(void) +static int do_start(void) { - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - running = true; - k_work_reschedule(&refresh_work, K_NO_WAIT); + k_work_reschedule(&ctx.refresh_work, K_NO_WAIT); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } - k_work_cancel_delayable(&refresh_work); - running = false; + k_work_cancel_delayable(&ctx.refresh_work); + + return 0; } 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; } - timezone_min = event->timezone_min; - utc_ms_base = event->utc_ms; - uptime_ms_base = k_uptime_get(); + ctx.timezone_min = event->timezone_min; + ctx.utc_ms_base = event->utc_ms; + ctx.uptime_ms_base = k_uptime_get(); - if (running) { - k_work_reschedule(&refresh_work, K_NO_WAIT); + if (module_lifecycle_is_running(&ctx.lc)) { + k_work_reschedule(&ctx.refresh_work, K_NO_WAIT); } return false; @@ -132,48 +157,25 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); - int err; if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/usb_cdc_module.c b/src/usb_cdc_module.c index 30b4655..aa54c3b 100644 --- a/src/usb_cdc_module.c +++ b/src/usb_cdc_module.c @@ -16,6 +16,7 @@ #include #include +#include "module_lifecycle.h" #include "proto_rx_event.h" #include "proto_transport_state_event.h" #include "proto_tx_event.h" @@ -38,33 +39,53 @@ enum usb_cdc_business_state { }; struct usb_cdc_ctx { - enum module_state lifecycle; + struct module_lifecycle_ctx lc; 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; 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 = { - .lifecycle = MODULE_STATE_OFF, + .lc = { + .state = LC_UNINIT, + .cfg = &lifecycle_cfg, + .ops = &lifecycle_ops, + }, .business = USB_CDC_BUS_OFFLINE, + .cdc_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart), .usb_active = false, .proto_rx_len = 0U, }; +#define proto_rx_buf ctx.proto_rx_buf + static void validate_line_coding(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) @@ -75,44 +96,36 @@ static enum proto_transport_link_state transport_link_state_get(void) 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) { unsigned int key = irq_lock(); - ring_buf_init(&rx_ringbuf, sizeof(rx_ring_buffer), rx_ring_buffer); - ring_buf_init(&tx_ringbuf, sizeof(tx_ring_buffer), tx_ring_buffer); + ring_buf_init(&ctx.rx_ringbuf, sizeof(ctx.rx_ring_buffer), ctx.rx_ring_buffer); + ring_buf_init(&ctx.tx_ringbuf, sizeof(ctx.tx_ring_buffer), ctx.tx_ring_buffer); irq_unlock(key); } static void disable_uart_io(void) { - uart_irq_rx_disable(cdc_dev); - uart_irq_tx_disable(cdc_dev); + uart_irq_rx_disable(ctx.cdc_dev); + uart_irq_tx_disable(ctx.cdc_dev); ctx.proto_rx_len = 0U; - k_work_cancel_delayable(&rx_flush_work); + k_work_cancel_delayable(&ctx.rx_flush_work); 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 proto_transport_link_state old_link = - ((old_lifecycle == MODULE_STATE_READY) && + ((old_lifecycle == LC_RUNNING) && (old_business == USB_CDC_SESSION_READY)) ? PROTO_TRANSPORT_LINK_READY : PROTO_TRANSPORT_LINK_DOWN; 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) && (new_link == PROTO_TRANSPORT_LINK_DOWN)) { disable_uart_io(); @@ -124,17 +137,17 @@ static void state_reconcile(enum module_state old_lifecycle, 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) { 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) { 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) { @@ -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) { - enum module_state old_lifecycle = ctx.lifecycle; + enum module_lifecycle old_lifecycle = ctx.lc.state; enum usb_cdc_business_state old_business = ctx.business; if (ctx.business == new_state) { @@ -192,7 +191,7 @@ static void kick_tx(void) return; } - uart_irq_tx_enable(cdc_dev); + uart_irq_tx_enable(ctx.cdc_dev); } static void validate_line_coding(void) @@ -200,7 +199,7 @@ static void validate_line_coding(void) uint32_t baudrate = 0U; 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) { LOG_WRN("Failed to get CDC baudrate (%d)", err); } else { @@ -215,7 +214,7 @@ static void validate_line_coding(void) { struct uart_config cfg; - err = uart_config_get(cdc_dev, &cfg); + err = uart_config_get(ctx.cdc_dev, &cfg); if (err) { LOG_WRN("uart_config_get failed (%d)", err); } else { @@ -243,7 +242,7 @@ static void rx_work_handler(struct k_work *work) uint32_t len; 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); if (len == 0U) { @@ -259,7 +258,7 @@ static void rx_work_handler(struct k_work *work) if (len > 0U) { memcpy(&proto_rx_buf[ctx.proto_rx_len], buffer, 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; unsigned int key = irq_lock(); - written = ring_buf_put(&rx_ringbuf, buffer, + written = ring_buf_put(&ctx.rx_ringbuf, buffer, (uint32_t)recv_len); irq_unlock(key); @@ -305,7 +304,7 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data) 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; 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); 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"); return -ENODEV; } reset_ring_buffers(); - k_work_init(&rx_work, rx_work_handler); - k_work_init_delayable(&rx_flush_work, rx_flush_work_handler); - uart_irq_callback_set(cdc_dev, cdc_interrupt_handler); - ctx = (struct usb_cdc_ctx) { - .lifecycle = MODULE_STATE_OFF, - .business = USB_CDC_BUS_OFFLINE, - .usb_active = false, - .proto_rx_len = 0U, - }; + k_work_init(&ctx.rx_work, rx_work_handler); + k_work_init_delayable(&ctx.rx_flush_work, rx_flush_work_handler); + uart_irq_callback_set(ctx.cdc_dev, cdc_interrupt_handler); + ctx.business = USB_CDC_BUS_OFFLINE; + ctx.usb_active = false; + ctx.proto_rx_len = 0U; return 0; } -static void module_start(void) +static int do_start(void) { - lifecycle_set(MODULE_STATE_READY); - business_state_sync_from_usb(); + return 0; } -static void module_pause(void) +static int do_stop(void) { - business_state_set(USB_CDC_BUS_OFFLINE); - lifecycle_set(MODULE_STATE_STANDBY); + ctx.business = USB_CDC_BUS_OFFLINE; + 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) @@ -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) { - if (event->dev != cdc_dev) { + if (event->dev != ctx.cdc_dev) { return false; } @@ -449,7 +463,7 @@ static bool handle_proto_tx_event(const struct proto_tx_event *event) } 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); irq_unlock(key); @@ -483,32 +497,23 @@ static bool app_event_handler(const struct app_event_header *aeh) cast_module_state_event(aeh); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - if (ctx.lifecycle == MODULE_STATE_OFF) { - int err = module_init(); - - if (err) { - lifecycle_set(MODULE_STATE_ERROR); - return false; - } - } - - module_start(); + (void)apply_lifecycle(LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (ctx.lifecycle != MODULE_STATE_OFF) { - module_pause(); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)apply_lifecycle(LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (ctx.lifecycle != MODULE_STATE_OFF) { - module_start(); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)apply_lifecycle(LC_RUNNING); } return false; diff --git a/src/usb_device_module.c b/src/usb_device_module.c index 83ed9bd..4956915 100644 --- a/src/usb_device_module.c +++ b/src/usb_device_module.c @@ -15,6 +15,7 @@ #include +#include "module_lifecycle.h" #include "usb_function_hook.h" #include "usb_control_event.h" #include "usb_state_event.h" @@ -40,9 +41,6 @@ static const char *const class_blocklist[] = { NULL, }; -static bool initialized; -static bool running; - enum usb_stack_state { USB_STACK_UNINITIALIZED = 0, USB_STACK_DISABLED, @@ -58,11 +56,35 @@ enum usb_bus_state { }; struct usb_owner_ctx { + struct module_lifecycle_ctx lc; enum usb_stack_state stack; 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 = { + .lc = { + .state = LC_UNINIT, + .cfg = &lifecycle_cfg, + .ops = &lifecycle_ops, + }, .stack = USB_STACK_UNINITIALIZED, .bus = USB_BUS_DISCONNECTED, }; @@ -363,7 +385,7 @@ static int usb_stack_disable_if_needed(void) return 0; } -static int module_init(void) +static int do_init(void) { usb_ctx.stack = USB_STACK_UNINITIALIZED; usb_ctx.bus = USB_BUS_DISCONNECTED; @@ -372,25 +394,25 @@ static int module_init(void) return 0; } -static int module_start(void) +static int do_start(void) { - if (running) { + if (module_lifecycle_is_running(&usb_ctx.lc)) { return 0; } - running = true; submit_usb_state(usb_public_state_get()); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&usb_ctx.lc)) { + return 0; } - running = false; submit_usb_state(usb_public_state_get()); + + return 0; } static bool handle_module_state_event(const struct module_state_event *event) @@ -399,26 +421,7 @@ static bool handle_module_state_event(const struct module_state_event *event) return false; } - if (!initialized) { - int err = module_init(); - - 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); - } - } + (void)module_set_lifecycle(&usb_ctx.lc, LC_RUNNING); return false; } @@ -426,38 +429,38 @@ static bool handle_module_state_event(const struct module_state_event *event) static bool handle_module_suspend_req_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; } int err = usb_stack_disable_if_needed(); if (err) { - module_set_state(MODULE_STATE_ERROR); + LOG_WRN("USB suspend request failed (%d)", err); return false; } - module_set_state(MODULE_STATE_READY); + (void)module_set_lifecycle(&usb_ctx.lc, LC_SUSPENDED); return false; } static bool handle_module_resume_req_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; } int err = usb_stack_enable_if_needed(); if (err) { - module_set_state(MODULE_STATE_ERROR); + LOG_WRN("USB resume request failed (%d)", err); return false; } - if (usb_stack_was_initialized()) { - module_set_state(MODULE_STATE_READY); - } + (void)module_set_lifecycle(&usb_ctx.lc, LC_RUNNING); return false; } @@ -479,23 +482,16 @@ static bool app_event_handler(const struct app_event_header *aeh) } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&usb_ctx.lc)) { + (void)module_set_lifecycle(&usb_ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else if (usb_stack_was_initialized()) { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&usb_ctx.lc)) { + (void)module_set_lifecycle(&usb_ctx.lc, LC_RUNNING); } return false; diff --git a/src/usb_hid_consumer_module.c b/src/usb_hid_consumer_module.c index 0f95847..da66aaf 100644 --- a/src/usb_hid_consumer_module.c +++ b/src/usb_hid_consumer_module.c @@ -18,32 +18,57 @@ #include "hid_report_sent_event.h" #include "hid_tx_report_event.h" #include "keyboard_core.h" +#include "module_lifecycle.h" #include "usb_function_hook.h" #include "usb_state_event.h" 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[] = { 0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x15, 0x00, 0x26, 0xFF, 0x03, 0x19, 0x00, 0x2A, 0xFF, 0x03, 0x75, 0x10, 0x95, 0x01, 0x81, 0x00, 0xC0 }; -static bool initialized; -static bool running; -static bool usb_active; -static bool iface_ready; -static bool report_in_flight; -static uint16_t in_flight_sequence; +struct usb_hid_consumer_module_ctx { + struct module_lifecycle_ctx lc; + const struct device *hid_dev; + bool usb_active; + bool iface_ready; + 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); 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, 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); - iface_ready = ready; + ctx.iface_ready = 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(); } @@ -117,10 +143,10 @@ static void consumer_input_report_done(const struct device *dev, ARG_UNUSED(dev); ARG_UNUSED(report); - report_in_flight = false; + ctx.report_in_flight = false; submit_hid_report_sent_event(HID_SEND_CH_USB_CONSUMER, KEYBOARD_REPORT_TYPE_CONSUMER, - in_flight_sequence, false); + ctx.in_flight_sequence, false); } 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) { - if (!device_is_ready(hid_dev)) { - LOG_ERR("HID device %s not ready", hid_dev->name); + if (!device_is_ready(ctx.hid_dev)) { + LOG_ERR("HID device %s not ready", ctx.hid_dev->name); 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); } 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; - iface_ready = false; - report_in_flight = false; + ctx.usb_active = false; + ctx.iface_ready = false; + ctx.report_in_flight = false; return 0; } -static int module_start(void) +static int do_start(void) { - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - running = true; publish_consumer_state(); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } - running = false; - report_in_flight = false; + ctx.report_in_flight = false; publish_consumer_state(); + + return 0; } static bool handle_usb_state_event(const struct usb_state_event *event) { bool new_usb_active = (event->state == USB_STATE_ACTIVE); - if (new_usb_active == usb_active) { + if (new_usb_active == ctx.usb_active) { return false; } - usb_active = new_usb_active; - if (!usb_active) { - iface_ready = false; - report_in_flight = false; + ctx.usb_active = new_usb_active; + if (!ctx.usb_active) { + ctx.iface_ready = false; + ctx.report_in_flight = false; } publish_consumer_state(); @@ -208,7 +234,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event) { int err; - if (!running || !usb_active || + if (!module_lifecycle_is_running(&ctx.lc) || !ctx.usb_active || (event->channel != HID_SEND_CH_USB_CONSUMER)) { return false; } @@ -217,17 +243,17 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event) return false; } - if (!iface_ready) { + if (!ctx.iface_ready) { return false; } - if (report_in_flight) { + if (ctx.report_in_flight) { LOG_WRN("Drop USB consumer report while previous report is in flight"); return false; } 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); if (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, event->sequence, true); } else { - report_in_flight = true; - in_flight_sequence = event->sequence; + ctx.report_in_flight = true; + ctx.in_flight_sequence = event->sequence; } return false; @@ -254,48 +280,25 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); - int err; if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; diff --git a/src/usb_hid_keyboard_module.c b/src/usb_hid_keyboard_module.c index e5f9375..32546ab 100644 --- a/src/usb_hid_keyboard_module.c +++ b/src/usb_hid_keyboard_module.c @@ -19,6 +19,7 @@ #include "hid_report_sent_event.h" #include "hid_tx_report_event.h" #include "keyboard_core.h" +#include "module_lifecycle.h" #include "set_protocol_event.h" #include "usb_function_hook.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_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[] = { 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 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 }; -static enum keyboard_protocol_mode keyboard_protocol_mode = - KEYBOARD_PROTOCOL_MODE_REPORT; -static bool initialized; -static bool running; -static bool usb_active; -static bool iface_ready; -static bool report_in_flight; -static uint16_t in_flight_sequence; +struct usb_hid_keyboard_module_ctx { + struct module_lifecycle_ctx lc; + const struct device *hid_dev; + enum keyboard_protocol_mode keyboard_protocol_mode; + bool usb_active; + bool iface_ready; + 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_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); 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, 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) { ARG_UNUSED(dev); - iface_ready = ready; + ctx.iface_ready = 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(); } @@ -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); - if (keyboard_protocol_mode == new_mode) { + if (ctx.keyboard_protocol_mode == new_mode) { return; } - keyboard_protocol_mode = new_mode; + ctx.keyboard_protocol_mode = new_mode; LOG_INF("USB keyboard protocol -> %s", (new_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? "boot" : "report"); 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(report); - report_in_flight = false; + ctx.report_in_flight = false; submit_hid_report_sent_event(HID_SEND_CH_USB_KEYS, KEYBOARD_REPORT_TYPE_KEYS, - in_flight_sequence, false); + ctx.in_flight_sequence, false); } 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) { - if (!device_is_ready(hid_dev)) { - LOG_ERR("HID device %s not ready", hid_dev->name); + if (!device_is_ready(ctx.hid_dev)) { + LOG_ERR("HID device %s not ready", ctx.hid_dev->name); 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); } 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; - usb_active = false; - iface_ready = false; - report_in_flight = false; + ctx.keyboard_protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT; + ctx.usb_active = false; + ctx.iface_ready = false; + ctx.report_in_flight = false; return 0; } -static int module_start(void) +static int do_start(void) { - if (running) { + if (module_lifecycle_is_running(&ctx.lc)) { return 0; } - running = true; publish_keyboard_state(); return 0; } -static void module_pause(void) +static int do_stop(void) { - if (!running) { - return; + if (!module_lifecycle_is_running(&ctx.lc)) { + return 0; } - running = false; - report_in_flight = false; + ctx.report_in_flight = false; publish_keyboard_state(); + + return 0; } static bool handle_usb_state_event(const struct usb_state_event *event) { bool new_usb_active = (event->state == USB_STATE_ACTIVE); - if (new_usb_active == usb_active) { + if (new_usb_active == ctx.usb_active) { return false; } - usb_active = new_usb_active; - if (!usb_active) { - iface_ready = false; - report_in_flight = false; + ctx.usb_active = new_usb_active; + if (!ctx.usb_active) { + ctx.iface_ready = false; + ctx.report_in_flight = false; } publish_keyboard_state(); @@ -275,7 +302,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event) { int err; - if (!running || !usb_active || + if (!module_lifecycle_is_running(&ctx.lc) || !ctx.usb_active || (event->channel != HID_SEND_CH_USB_KEYS)) { return false; } @@ -284,22 +311,22 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event) 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"); return false; } - if (!iface_ready) { + if (!ctx.iface_ready) { return false; } - if (report_in_flight) { + if (ctx.report_in_flight) { LOG_WRN("Drop USB keyboard report while previous report is in flight"); return false; } 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); if (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, event->sequence, true); } else { - report_in_flight = true; - in_flight_sequence = event->sequence; + ctx.report_in_flight = true; + ctx.in_flight_sequence = event->sequence; } return false; @@ -326,48 +353,25 @@ static bool app_event_handler(const struct app_event_header *aeh) if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); - int err; if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - 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); - } + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false; } if (is_power_down_event(aeh)) { - if (initialized) { - module_pause(); - module_set_state(MODULE_STATE_STANDBY); + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_STOPPED); } return false; } if (is_wake_up_event(aeh)) { - if (initialized) { - int err = module_start(); - - if (err) { - module_set_state(MODULE_STATE_ERROR); - } else { - module_set_state(MODULE_STATE_READY); - } + if (module_lifecycle_is_initialized(&ctx.lc)) { + (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); } return false;