feat: 添加模块生命周期管理框架并重构现有模块
添加了模块生命周期管理头文件 module_lifecycle.h,定义了完整的生命周期状态机, 包括初始化、运行、停止、挂起和错误状态。同时将电池模块、BLE BAS模块、BLE HID 模块和BLE NUS模块重构为使用新的生命周期框架进行状态管理。 提升日志缓冲区大小以支持更详细的调试信息记录。
This commit is contained in:
204
inc/module_lifecycle.h
Normal file
204
inc/module_lifecycle.h
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
#ifndef MODULE_LIFECYCLE_H_
|
||||||
|
#define MODULE_LIFECYCLE_H_
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <caf/events/module_state_event.h>
|
||||||
|
|
||||||
|
enum module_lifecycle {
|
||||||
|
LC_UNINIT,
|
||||||
|
LC_RUNNING,
|
||||||
|
LC_STOPPED,
|
||||||
|
LC_SUSPENDED,
|
||||||
|
LC_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum module_lifecycle_mode {
|
||||||
|
ML_MODE_NONE,
|
||||||
|
ML_MODE_POWER,
|
||||||
|
ML_MODE_SUSPEND,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct module_lifecycle_ops {
|
||||||
|
int (*do_init)(void);
|
||||||
|
int (*do_start)(void);
|
||||||
|
int (*do_stop)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct module_lifecycle_cfg {
|
||||||
|
enum module_lifecycle_mode mode;
|
||||||
|
enum module_state stopped_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct module_lifecycle_ctx {
|
||||||
|
enum module_lifecycle state;
|
||||||
|
const struct module_lifecycle_cfg *cfg;
|
||||||
|
const struct module_lifecycle_ops *ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool module_lifecycle_is_running(
|
||||||
|
const struct module_lifecycle_ctx *ctx)
|
||||||
|
{
|
||||||
|
return ctx->state == LC_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool module_lifecycle_is_initialized(
|
||||||
|
const struct module_lifecycle_ctx *ctx)
|
||||||
|
{
|
||||||
|
return (ctx->state != LC_UNINIT) && (ctx->state != LC_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool module_lifecycle_reports_stopped_state(
|
||||||
|
const struct module_lifecycle_ctx *ctx)
|
||||||
|
{
|
||||||
|
return ctx->cfg->mode != ML_MODE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int module_lifecycle_report_state(
|
||||||
|
struct module_lifecycle_ctx *ctx,
|
||||||
|
enum module_lifecycle state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case LC_RUNNING:
|
||||||
|
module_set_state(MODULE_STATE_READY);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case LC_STOPPED:
|
||||||
|
if (!module_lifecycle_reports_stopped_state(ctx)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
module_set_state(ctx->cfg->stopped_state);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case LC_SUSPENDED:
|
||||||
|
module_set_state(MODULE_STATE_SUSPENDED);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case LC_ERROR:
|
||||||
|
module_set_state(MODULE_STATE_ERROR);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case LC_UNINIT:
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int module_lifecycle_fail(struct module_lifecycle_ctx *ctx, int err)
|
||||||
|
{
|
||||||
|
ctx->state = LC_ERROR;
|
||||||
|
(void)module_lifecycle_report_state(ctx, LC_ERROR);
|
||||||
|
|
||||||
|
return err ? err : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int module_lifecycle_do_init(struct module_lifecycle_ctx *ctx)
|
||||||
|
{
|
||||||
|
int err = ctx->ops->do_init();
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return module_lifecycle_fail(ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int module_lifecycle_do_start(struct module_lifecycle_ctx *ctx,
|
||||||
|
enum module_lifecycle target)
|
||||||
|
{
|
||||||
|
int err = ctx->ops->do_start();
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return module_lifecycle_fail(ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->state = target;
|
||||||
|
return module_lifecycle_report_state(ctx, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int module_lifecycle_do_stop(struct module_lifecycle_ctx *ctx,
|
||||||
|
enum module_lifecycle target)
|
||||||
|
{
|
||||||
|
int err = ctx->ops->do_stop();
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return module_lifecycle_fail(ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->state = target;
|
||||||
|
return module_lifecycle_report_state(ctx, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int module_set_lifecycle(struct module_lifecycle_ctx *ctx,
|
||||||
|
enum module_lifecycle target)
|
||||||
|
{
|
||||||
|
if ((ctx == NULL) || (ctx->cfg == NULL) || (ctx->ops == NULL) ||
|
||||||
|
(ctx->ops->do_init == NULL) || (ctx->ops->do_start == NULL) ||
|
||||||
|
(ctx->ops->do_stop == NULL)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->state == LC_ERROR) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->state == target) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target == LC_ERROR) {
|
||||||
|
return module_lifecycle_fail(ctx, -EIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx->state) {
|
||||||
|
case LC_UNINIT:
|
||||||
|
if (target == LC_RUNNING) {
|
||||||
|
int err = module_lifecycle_do_init(ctx);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->state = LC_STOPPED;
|
||||||
|
return module_lifecycle_do_start(ctx, LC_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target == LC_STOPPED) {
|
||||||
|
int err = module_lifecycle_do_init(ctx);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->state = LC_STOPPED;
|
||||||
|
return module_lifecycle_report_state(ctx, LC_STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LC_RUNNING:
|
||||||
|
if ((target == LC_STOPPED) || (target == LC_SUSPENDED)) {
|
||||||
|
return module_lifecycle_do_stop(ctx, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LC_STOPPED:
|
||||||
|
case LC_SUSPENDED:
|
||||||
|
if (target == LC_RUNNING) {
|
||||||
|
return module_lifecycle_do_start(ctx, LC_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LC_ERROR:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MODULE_LIFECYCLE_H_ */
|
||||||
3
prj.conf
3
prj.conf
@@ -26,7 +26,10 @@ CONFIG_FLASH_MAP=y
|
|||||||
CONFIG_NVS=y
|
CONFIG_NVS=y
|
||||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
|
CONFIG_LOG_BUFFER_SIZE=16384
|
||||||
|
CONFIG_LOG_BACKEND_RTT_OUTPUT_BUFFER_SIZE=16384
|
||||||
CONFIG_ASSERT=y
|
CONFIG_ASSERT=y
|
||||||
|
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=16384
|
||||||
CONFIG_APP_EVENT_MANAGER_MAX_EVENT_CNT=64
|
CONFIG_APP_EVENT_MANAGER_MAX_EVENT_CNT=64
|
||||||
CONFIG_LED_STRIP=y
|
CONFIG_LED_STRIP=y
|
||||||
CONFIG_WS2812_STRIP_SPI=y
|
CONFIG_WS2812_STRIP_SPI=y
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <zephyr/pm/device.h>
|
#include <zephyr/pm/device.h>
|
||||||
|
|
||||||
#include "bat_state_event.h"
|
#include "bat_state_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
|
|
||||||
@@ -32,17 +33,43 @@ BUILD_ASSERT(DT_NODE_HAS_STATUS(VBATT_NODE, okay),
|
|||||||
BUILD_ASSERT(DT_NODE_HAS_STATUS(IP5306_NODE, okay),
|
BUILD_ASSERT(DT_NODE_HAS_STATUS(IP5306_NODE, okay),
|
||||||
"Missing ip5306 node in devicetree");
|
"Missing ip5306 node in devicetree");
|
||||||
|
|
||||||
static const struct device *const vbatt_dev = DEVICE_DT_GET(VBATT_NODE);
|
struct battery_module_ctx {
|
||||||
static const struct device *const ip5306_dev = DEVICE_DT_GET(IP5306_NODE);
|
struct module_lifecycle_ctx lc;
|
||||||
static struct k_work_delayable battery_sample_work;
|
const struct device *vbatt_dev;
|
||||||
static struct {
|
const struct device *ip5306_dev;
|
||||||
|
struct k_work_delayable battery_sample_work;
|
||||||
|
struct {
|
||||||
bool valid;
|
bool valid;
|
||||||
uint8_t soc;
|
uint8_t soc;
|
||||||
bool charging;
|
bool charging;
|
||||||
bool full;
|
bool full;
|
||||||
} last_bat_state;
|
} last_bat_state;
|
||||||
static bool initialized;
|
};
|
||||||
static bool running;
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct battery_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.vbatt_dev = DEVICE_DT_GET(VBATT_NODE),
|
||||||
|
.ip5306_dev = DEVICE_DT_GET(IP5306_NODE),
|
||||||
|
};
|
||||||
|
|
||||||
static int sensor_value_to_mv(const struct sensor_value *value)
|
static int sensor_value_to_mv(const struct sensor_value *value)
|
||||||
{
|
{
|
||||||
@@ -53,7 +80,7 @@ static int measurement_enable(bool enable)
|
|||||||
{
|
{
|
||||||
enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME
|
enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME
|
||||||
: PM_DEVICE_ACTION_SUSPEND;
|
: PM_DEVICE_ACTION_SUSPEND;
|
||||||
int err = pm_device_action_run(vbatt_dev, action);
|
int err = pm_device_action_run(ctx.vbatt_dev, action);
|
||||||
|
|
||||||
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
||||||
LOG_ERR("Cannot %s vbatt sensor (%d)", enable ? "resume" : "suspend", err);
|
LOG_ERR("Cannot %s vbatt sensor (%d)", enable ? "resume" : "suspend", err);
|
||||||
@@ -90,23 +117,23 @@ static void battery_sample_fn(struct k_work *work)
|
|||||||
|
|
||||||
ARG_UNUSED(work);
|
ARG_UNUSED(work);
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sensor_sample_fetch(vbatt_dev);
|
err = sensor_sample_fetch(ctx.vbatt_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("Battery sample fetch failed (%d)", err);
|
LOG_WRN("Battery sample fetch failed (%d)", err);
|
||||||
goto reschedule;
|
goto reschedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sensor_channel_get(vbatt_dev, SENSOR_CHAN_VOLTAGE, &voltage);
|
err = sensor_channel_get(ctx.vbatt_dev, SENSOR_CHAN_VOLTAGE, &voltage);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("Battery channel get failed (%d)", err);
|
LOG_WRN("Battery channel get failed (%d)", err);
|
||||||
goto reschedule;
|
goto reschedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ip5306_get_status(ip5306_dev, &pmic_status);
|
err = ip5306_get_status(ctx.ip5306_dev, &pmic_status);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("IP5306 status read failed (%d)", err);
|
LOG_WRN("IP5306 status read failed (%d)", err);
|
||||||
goto reschedule;
|
goto reschedule;
|
||||||
@@ -115,53 +142,53 @@ static void battery_sample_fn(struct k_work *work)
|
|||||||
voltage_mv = sensor_value_to_mv(&voltage);
|
voltage_mv = sensor_value_to_mv(&voltage);
|
||||||
uint8_t soc = battery_soc_from_mv(voltage_mv);
|
uint8_t soc = battery_soc_from_mv(voltage_mv);
|
||||||
|
|
||||||
if (!last_bat_state.valid ||
|
if (!ctx.last_bat_state.valid ||
|
||||||
(last_bat_state.soc != soc) ||
|
(ctx.last_bat_state.soc != soc) ||
|
||||||
(last_bat_state.charging != pmic_status.charging) ||
|
(ctx.last_bat_state.charging != pmic_status.charging) ||
|
||||||
(last_bat_state.full != pmic_status.full)) {
|
(ctx.last_bat_state.full != pmic_status.full)) {
|
||||||
last_bat_state.valid = true;
|
ctx.last_bat_state.valid = true;
|
||||||
last_bat_state.soc = soc;
|
ctx.last_bat_state.soc = soc;
|
||||||
last_bat_state.charging = pmic_status.charging;
|
ctx.last_bat_state.charging = pmic_status.charging;
|
||||||
last_bat_state.full = pmic_status.full;
|
ctx.last_bat_state.full = pmic_status.full;
|
||||||
submit_bat_state_event(soc, pmic_status.charging, pmic_status.full);
|
submit_bat_state_event(soc, pmic_status.charging, pmic_status.full);
|
||||||
}
|
}
|
||||||
|
|
||||||
reschedule:
|
reschedule:
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
k_work_reschedule(&battery_sample_work, BATTERY_SAMPLE_INTERVAL);
|
k_work_reschedule(&ctx.battery_sample_work, BATTERY_SAMPLE_INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
if (!device_is_ready(vbatt_dev)) {
|
if (!device_is_ready(ctx.vbatt_dev)) {
|
||||||
LOG_ERR("vbatt device not ready");
|
LOG_ERR("vbatt device not ready");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device_is_ready(ip5306_dev)) {
|
if (!device_is_ready(ctx.ip5306_dev)) {
|
||||||
LOG_ERR("ip5306 device not ready");
|
LOG_ERR("ip5306 device not ready");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = ip5306_init(ip5306_dev);
|
int err = ip5306_init(ctx.ip5306_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("ip5306 init failed (%d)", err);
|
LOG_ERR("ip5306 init failed (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_work_init_delayable(&battery_sample_work, battery_sample_fn);
|
k_work_init_delayable(&ctx.battery_sample_work, battery_sample_fn);
|
||||||
memset(&last_bat_state, 0, sizeof(last_bat_state));
|
memset(&ctx.last_bat_state, 0, sizeof(ctx.last_bat_state));
|
||||||
power_manager_restrict(MODULE_IDX(MODULE), POWER_MANAGER_LEVEL_SUSPENDED);
|
power_manager_restrict(MODULE_IDX(MODULE), POWER_MANAGER_LEVEL_SUSPENDED);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,21 +197,21 @@ static int module_start(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
k_work_reschedule(&ctx.battery_sample_work, K_NO_WAIT);
|
||||||
k_work_reschedule(&battery_sample_work, K_NO_WAIT);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)k_work_cancel_delayable(&battery_sample_work);
|
(void)k_work_cancel_delayable(&ctx.battery_sample_work);
|
||||||
(void)measurement_enable(false);
|
(void)measurement_enable(false);
|
||||||
running = false;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool app_event_handler(const struct app_event_header *aeh)
|
static bool app_event_handler(const struct app_event_header *aeh)
|
||||||
@@ -193,47 +220,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
int err;
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -11,34 +11,54 @@
|
|||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
#include "bat_state_event.h"
|
#include "bat_state_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
|
|
||||||
static uint8_t current_soc = 100U;
|
struct ble_bas_module_ctx {
|
||||||
static bool initialized;
|
struct module_lifecycle_ctx lc;
|
||||||
static bool running;
|
uint8_t current_soc;
|
||||||
static bool ble_ready;
|
bool ble_ready;
|
||||||
|
};
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_NONE,
|
||||||
|
.stopped_state = MODULE_STATE_OFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ble_bas_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.current_soc = 100U,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int bas_update_level(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err = bt_bas_set_battery_level(ctx.current_soc);
|
||||||
|
|
||||||
if (running) {
|
if ((err == -EAGAIN) || (err == -ENOTCONN)) {
|
||||||
|
LOG_INF("BAS notify deferred (%d)", err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
|
|
||||||
if (!ble_ready) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bt_bas_set_battery_level(current_soc);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("bt_bas_set_battery_level failed (%d)", err);
|
LOG_WRN("bt_bas_set_battery_level failed (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
@@ -47,21 +67,30 @@ static int module_start(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
running = false;
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.ble_ready) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bas_update_level();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_stop(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_bat_state_event(const struct bat_state_event *event)
|
static bool handle_bat_state_event(const struct bat_state_event *event)
|
||||||
{
|
{
|
||||||
current_soc = event->soc;
|
ctx.current_soc = event->soc;
|
||||||
|
|
||||||
if (running && ble_ready) {
|
if (module_lifecycle_is_running(&ctx.lc) && ctx.ble_ready) {
|
||||||
int err = bt_bas_set_battery_level(current_soc);
|
(void)bas_update_level();
|
||||||
|
|
||||||
if (err) {
|
|
||||||
LOG_WRN("bt_bas_set_battery_level failed (%d)", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -75,38 +104,22 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
|
|
||||||
if (is_module_state_event(aeh)) {
|
if (is_module_state_event(aeh)) {
|
||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&ctx.lc,
|
||||||
err = module_init();
|
ctx.ble_ready ? LC_RUNNING :
|
||||||
if (err) {
|
LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
|
||||||
ble_ready = true;
|
ctx.ble_ready = true;
|
||||||
|
|
||||||
if (running) {
|
if (ctx.lc.state == LC_STOPPED) {
|
||||||
err = bt_bas_set_battery_level(current_soc);
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
if (err) {
|
} else if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
LOG_WRN("bt_bas_set_battery_level failed (%d)", err);
|
(void)bas_update_level();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "hid_report_sent_event.h"
|
#include "hid_report_sent_event.h"
|
||||||
#include "hid_tx_report_event.h"
|
#include "hid_tx_report_event.h"
|
||||||
#include "keyboard_core.h"
|
#include "keyboard_core.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "set_protocol_event.h"
|
#include "set_protocol_event.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
@@ -40,15 +41,40 @@ BT_HIDS_DEF(hids_obj,
|
|||||||
KEYBOARD_CONSUMER_REPORT_SIZE,
|
KEYBOARD_CONSUMER_REPORT_SIZE,
|
||||||
BLE_HID_KEYS_LED_REPORT_SIZE);
|
BLE_HID_KEYS_LED_REPORT_SIZE);
|
||||||
|
|
||||||
static struct bt_conn *active_conn;
|
struct ble_hid_module_ctx {
|
||||||
static struct in_flight_report in_flight;
|
struct module_lifecycle_ctx lc;
|
||||||
static enum keyboard_protocol_mode protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
struct bt_conn *active_conn;
|
||||||
static bool initialized;
|
struct in_flight_report in_flight;
|
||||||
static bool running;
|
enum keyboard_protocol_mode protocol_mode;
|
||||||
static bool secured;
|
bool secured;
|
||||||
static bool keyboard_report_notify_enabled;
|
bool keyboard_report_notify_enabled;
|
||||||
static bool consumer_report_notify_enabled;
|
bool consumer_report_notify_enabled;
|
||||||
static bool boot_keyboard_notify_enabled;
|
bool boot_keyboard_notify_enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ble_hid_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||||
|
};
|
||||||
|
|
||||||
static const uint8_t hid_report_desc[] = {
|
static const uint8_t hid_report_desc[] = {
|
||||||
0x05, 0x01, /* Usage Page (Generic Desktop) */
|
0x05, 0x01, /* Usage Page (Generic Desktop) */
|
||||||
@@ -100,24 +126,25 @@ static const uint8_t hid_report_desc[] = {
|
|||||||
|
|
||||||
static void submit_ble_transport_state_event(void)
|
static void submit_ble_transport_state_event(void)
|
||||||
{
|
{
|
||||||
bool ready = running && secured && (active_conn != NULL);
|
bool ready = module_lifecycle_is_running(&ctx.lc) &&
|
||||||
|
ctx.secured && (ctx.active_conn != NULL);
|
||||||
uint8_t report_ready_bm = 0U;
|
uint8_t report_ready_bm = 0U;
|
||||||
|
|
||||||
if (ready && ((protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ?
|
if (ready && ((ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ?
|
||||||
boot_keyboard_notify_enabled :
|
ctx.boot_keyboard_notify_enabled :
|
||||||
keyboard_report_notify_enabled)) {
|
ctx.keyboard_report_notify_enabled)) {
|
||||||
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_KEYS);
|
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_KEYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ready && (protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT) &&
|
if (ready && (ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT) &&
|
||||||
consumer_report_notify_enabled) {
|
ctx.consumer_report_notify_enabled) {
|
||||||
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_CONSUMER);
|
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_CONSUMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
submit_hid_channel_state_event(
|
submit_hid_channel_state_event(
|
||||||
HID_SEND_CH_BLE_SHARED,
|
HID_SEND_CH_BLE_SHARED,
|
||||||
report_ready_bm,
|
report_ready_bm,
|
||||||
protocol_mode);
|
ctx.protocol_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_evt evt)
|
static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_evt evt)
|
||||||
@@ -125,9 +152,9 @@ static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_e
|
|||||||
bool enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
|
bool enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
|
||||||
|
|
||||||
if (report_id == BLE_HID_KEYS_REPORT_ID) {
|
if (report_id == BLE_HID_KEYS_REPORT_ID) {
|
||||||
keyboard_report_notify_enabled = enabled;
|
ctx.keyboard_report_notify_enabled = enabled;
|
||||||
} else if (report_id == BLE_HID_CONSUMER_REPORT_ID) {
|
} else if (report_id == BLE_HID_CONSUMER_REPORT_ID) {
|
||||||
consumer_report_notify_enabled = enabled;
|
ctx.consumer_report_notify_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
submit_ble_transport_state_event();
|
submit_ble_transport_state_event();
|
||||||
@@ -135,7 +162,7 @@ static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_e
|
|||||||
|
|
||||||
static void boot_keyboard_notify_handler(enum bt_hids_notify_evt evt)
|
static void boot_keyboard_notify_handler(enum bt_hids_notify_evt evt)
|
||||||
{
|
{
|
||||||
boot_keyboard_notify_enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
|
ctx.boot_keyboard_notify_enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
|
||||||
submit_ble_transport_state_event();
|
submit_ble_transport_state_event();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,14 +171,14 @@ static void hid_report_complete_cb(struct bt_conn *conn, void *user_data)
|
|||||||
ARG_UNUSED(conn);
|
ARG_UNUSED(conn);
|
||||||
ARG_UNUSED(user_data);
|
ARG_UNUSED(user_data);
|
||||||
|
|
||||||
if (!in_flight.active) {
|
if (!ctx.in_flight.active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
||||||
in_flight.report_type,
|
ctx.in_flight.report_type,
|
||||||
in_flight.sequence, false);
|
ctx.in_flight.sequence, false);
|
||||||
in_flight.active = false;
|
ctx.in_flight.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_led_report_common(struct bt_hids_rep *rep, bool write)
|
static void keyboard_led_report_common(struct bt_hids_rep *rep, bool write)
|
||||||
@@ -187,22 +214,22 @@ static void pm_evt_handler(enum bt_hids_pm_evt evt, struct bt_conn *conn)
|
|||||||
|
|
||||||
switch (evt) {
|
switch (evt) {
|
||||||
case BT_HIDS_PM_EVT_BOOT_MODE_ENTERED:
|
case BT_HIDS_PM_EVT_BOOT_MODE_ENTERED:
|
||||||
protocol_mode = KEYBOARD_PROTOCOL_MODE_BOOT;
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_BOOT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BT_HIDS_PM_EVT_REPORT_MODE_ENTERED:
|
case BT_HIDS_PM_EVT_REPORT_MODE_ENTERED:
|
||||||
protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
submit_set_protocol_event(HID_TRANSPORT_BLE, protocol_mode);
|
submit_set_protocol_event(HID_TRANSPORT_BLE, ctx.protocol_mode);
|
||||||
submit_ble_transport_state_event();
|
submit_ble_transport_state_event();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
struct bt_hids_init_param hids_init_param = { 0 };
|
struct bt_hids_init_param hids_init_param = { 0 };
|
||||||
struct bt_hids_inp_rep *input_report;
|
struct bt_hids_inp_rep *input_report;
|
||||||
@@ -239,38 +266,38 @@ static int module_init(void)
|
|||||||
return bt_hids_init(&hids_obj, &hids_init_param);
|
return bt_hids_init(&hids_obj, &hids_init_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
submit_ble_transport_state_event();
|
submit_ble_transport_state_event();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_flight.active = false;
|
ctx.in_flight.active = false;
|
||||||
running = false;
|
|
||||||
submit_ble_transport_state_event();
|
submit_ble_transport_state_event();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset_connection_state(void)
|
static void reset_connection_state(void)
|
||||||
{
|
{
|
||||||
active_conn = NULL;
|
ctx.active_conn = NULL;
|
||||||
secured = false;
|
ctx.secured = false;
|
||||||
keyboard_report_notify_enabled = false;
|
ctx.keyboard_report_notify_enabled = false;
|
||||||
consumer_report_notify_enabled = false;
|
ctx.consumer_report_notify_enabled = false;
|
||||||
boot_keyboard_notify_enabled = false;
|
ctx.boot_keyboard_notify_enabled = false;
|
||||||
protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
||||||
in_flight.active = false;
|
ctx.in_flight.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
||||||
@@ -279,13 +306,13 @@ static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
|||||||
|
|
||||||
switch (event->state) {
|
switch (event->state) {
|
||||||
case PEER_STATE_CONNECTED:
|
case PEER_STATE_CONNECTED:
|
||||||
if (active_conn != NULL) {
|
if (ctx.active_conn != NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
active_conn = event->id;
|
ctx.active_conn = event->id;
|
||||||
protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
||||||
submit_set_protocol_event(HID_TRANSPORT_BLE, protocol_mode);
|
submit_set_protocol_event(HID_TRANSPORT_BLE, ctx.protocol_mode);
|
||||||
err = bt_hids_connected(&hids_obj, event->id);
|
err = bt_hids_connected(&hids_obj, event->id);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("bt_hids_connected failed (%d)", err);
|
LOG_ERR("bt_hids_connected failed (%d)", err);
|
||||||
@@ -294,16 +321,16 @@ static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
case PEER_STATE_SECURED:
|
case PEER_STATE_SECURED:
|
||||||
if (active_conn != event->id) {
|
if (ctx.active_conn != event->id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
secured = true;
|
ctx.secured = true;
|
||||||
submit_ble_transport_state_event();
|
submit_ble_transport_state_event();
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case PEER_STATE_DISCONNECTED:
|
case PEER_STATE_DISCONNECTED:
|
||||||
if (active_conn != event->id) {
|
if (ctx.active_conn != event->id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,34 +352,35 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!running || (event->channel != HID_SEND_CH_BLE_SHARED) ||
|
if (!module_lifecycle_is_running(&ctx.lc) ||
|
||||||
in_flight.active) {
|
(event->channel != HID_SEND_CH_BLE_SHARED) ||
|
||||||
|
ctx.in_flight.active) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((active_conn == NULL) || !secured) {
|
if ((ctx.active_conn == NULL) || !ctx.secured) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->report_type == KEYBOARD_REPORT_TYPE_KEYS) {
|
if (event->report_type == KEYBOARD_REPORT_TYPE_KEYS) {
|
||||||
if (event->protocol_mode != protocol_mode) {
|
if (event->protocol_mode != ctx.protocol_mode) {
|
||||||
LOG_WRN("Drop BLE keys report due to protocol mismatch");
|
LOG_WRN("Drop BLE keys report due to protocol mismatch");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_flight.active = true;
|
ctx.in_flight.active = true;
|
||||||
in_flight.report_type = event->report_type;
|
ctx.in_flight.report_type = event->report_type;
|
||||||
in_flight.sequence = event->sequence;
|
ctx.in_flight.sequence = event->sequence;
|
||||||
|
|
||||||
if (protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) {
|
if (ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) {
|
||||||
err = bt_hids_boot_kb_inp_rep_send(&hids_obj,
|
err = bt_hids_boot_kb_inp_rep_send(&hids_obj,
|
||||||
active_conn,
|
ctx.active_conn,
|
||||||
event->dyndata.data,
|
event->dyndata.data,
|
||||||
(uint8_t)event->dyndata.size,
|
(uint8_t)event->dyndata.size,
|
||||||
hid_report_complete_cb);
|
hid_report_complete_cb);
|
||||||
} else {
|
} else {
|
||||||
err = bt_hids_inp_rep_send(&hids_obj,
|
err = bt_hids_inp_rep_send(&hids_obj,
|
||||||
active_conn,
|
ctx.active_conn,
|
||||||
BLE_HID_KEYS_REPORT_IDX,
|
BLE_HID_KEYS_REPORT_IDX,
|
||||||
event->dyndata.data,
|
event->dyndata.data,
|
||||||
(uint8_t)event->dyndata.size,
|
(uint8_t)event->dyndata.size,
|
||||||
@@ -360,7 +388,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
in_flight.active = false;
|
ctx.in_flight.active = false;
|
||||||
LOG_WRN("BLE keyboard report submit failed (%d)", err);
|
LOG_WRN("BLE keyboard report submit failed (%d)", err);
|
||||||
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
||||||
KEYBOARD_REPORT_TYPE_KEYS,
|
KEYBOARD_REPORT_TYPE_KEYS,
|
||||||
@@ -371,23 +399,23 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event->report_type == KEYBOARD_REPORT_TYPE_CONSUMER) {
|
if (event->report_type == KEYBOARD_REPORT_TYPE_CONSUMER) {
|
||||||
if (protocol_mode != KEYBOARD_PROTOCOL_MODE_REPORT) {
|
if (ctx.protocol_mode != KEYBOARD_PROTOCOL_MODE_REPORT) {
|
||||||
LOG_WRN("Drop BLE consumer report in boot mode");
|
LOG_WRN("Drop BLE consumer report in boot mode");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_flight.active = true;
|
ctx.in_flight.active = true;
|
||||||
in_flight.report_type = event->report_type;
|
ctx.in_flight.report_type = event->report_type;
|
||||||
in_flight.sequence = event->sequence;
|
ctx.in_flight.sequence = event->sequence;
|
||||||
|
|
||||||
err = bt_hids_inp_rep_send(&hids_obj,
|
err = bt_hids_inp_rep_send(&hids_obj,
|
||||||
active_conn,
|
ctx.active_conn,
|
||||||
BLE_HID_CONSUMER_REPORT_IDX,
|
BLE_HID_CONSUMER_REPORT_IDX,
|
||||||
event->dyndata.data,
|
event->dyndata.data,
|
||||||
(uint8_t)event->dyndata.size,
|
(uint8_t)event->dyndata.size,
|
||||||
hid_report_complete_cb);
|
hid_report_complete_cb);
|
||||||
if (err) {
|
if (err) {
|
||||||
in_flight.active = false;
|
ctx.in_flight.active = false;
|
||||||
LOG_WRN("BLE consumer report submit failed (%d)", err);
|
LOG_WRN("BLE consumer report submit failed (%d)", err);
|
||||||
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
||||||
KEYBOARD_REPORT_TYPE_CONSUMER,
|
KEYBOARD_REPORT_TYPE_CONSUMER,
|
||||||
@@ -410,48 +438,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
|
|
||||||
if (is_module_state_event(aeh)) {
|
if (is_module_state_event(aeh)) {
|
||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <zephyr/bluetooth/services/nus.h>
|
#include <zephyr/bluetooth/services/nus.h>
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "proto_rx_event.h"
|
#include "proto_rx_event.h"
|
||||||
#include "proto_transport_state_event.h"
|
#include "proto_transport_state_event.h"
|
||||||
#include "proto_tx_event.h"
|
#include "proto_tx_event.h"
|
||||||
@@ -27,20 +28,39 @@ enum ble_nus_business_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ble_nus_ctx {
|
struct ble_nus_ctx {
|
||||||
enum module_state lifecycle;
|
struct module_lifecycle_ctx lc;
|
||||||
enum ble_nus_business_state business;
|
enum ble_nus_business_state business;
|
||||||
struct bt_conn *active_conn;
|
struct bt_conn *active_conn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
static struct ble_nus_ctx ctx = {
|
static struct ble_nus_ctx ctx = {
|
||||||
.lifecycle = MODULE_STATE_OFF,
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
.business = BLE_NUS_STACK_OFFLINE,
|
.business = BLE_NUS_STACK_OFFLINE,
|
||||||
.active_conn = NULL,
|
.active_conn = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool lifecycle_is_ready(void)
|
static bool lifecycle_is_ready(void)
|
||||||
{
|
{
|
||||||
return ctx.lifecycle == MODULE_STATE_READY;
|
return module_lifecycle_is_running(&ctx.lc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum proto_transport_link_state transport_link_state_get(void)
|
static enum proto_transport_link_state transport_link_state_get(void)
|
||||||
@@ -51,11 +71,11 @@ static enum proto_transport_link_state transport_link_state_get(void)
|
|||||||
PROTO_TRANSPORT_LINK_DOWN;
|
PROTO_TRANSPORT_LINK_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void state_reconcile(enum module_state old_lifecycle,
|
static void state_reconcile(enum module_lifecycle old_lifecycle,
|
||||||
enum ble_nus_business_state old_business)
|
enum ble_nus_business_state old_business)
|
||||||
{
|
{
|
||||||
enum proto_transport_link_state old_link =
|
enum proto_transport_link_state old_link =
|
||||||
((old_lifecycle == MODULE_STATE_READY) &&
|
((old_lifecycle == LC_RUNNING) &&
|
||||||
(old_business == BLE_NUS_SESSION_READY)) ?
|
(old_business == BLE_NUS_SESSION_READY)) ?
|
||||||
PROTO_TRANSPORT_LINK_READY :
|
PROTO_TRANSPORT_LINK_READY :
|
||||||
PROTO_TRANSPORT_LINK_DOWN;
|
PROTO_TRANSPORT_LINK_DOWN;
|
||||||
@@ -67,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)
|
static void business_state_set(enum ble_nus_business_state new_state)
|
||||||
{
|
{
|
||||||
enum module_state old_lifecycle = ctx.lifecycle;
|
enum module_lifecycle old_lifecycle = ctx.lc.state;
|
||||||
enum ble_nus_business_state old_business = ctx.business;
|
enum ble_nus_business_state old_business = ctx.business;
|
||||||
|
|
||||||
if (ctx.business == new_state) {
|
if (ctx.business == new_state) {
|
||||||
@@ -150,7 +156,7 @@ static void reset_connection_state(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -160,23 +166,33 @@ static int module_init(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = (struct ble_nus_ctx) {
|
ctx.business = BLE_NUS_STACK_OFFLINE;
|
||||||
.lifecycle = MODULE_STATE_OFF,
|
ctx.active_conn = NULL;
|
||||||
.business = BLE_NUS_STACK_OFFLINE,
|
|
||||||
.active_conn = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
lifecycle_set(MODULE_STATE_READY);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
lifecycle_set(MODULE_STATE_STANDBY);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_lifecycle(enum module_lifecycle target)
|
||||||
|
{
|
||||||
|
enum module_lifecycle old_lifecycle = ctx.lc.state;
|
||||||
|
enum ble_nus_business_state old_business = ctx.business;
|
||||||
|
int err = module_set_lifecycle(&ctx.lc, target);
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
state_reconcile(old_lifecycle, old_business);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
||||||
@@ -243,27 +259,13 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
cast_module_state_event(aeh);
|
cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (ctx.lifecycle == MODULE_STATE_OFF) {
|
(void)apply_lifecycle(LC_RUNNING);
|
||||||
int err = module_init();
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
lifecycle_set(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module_start();
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
|
||||||
business_state_set_stack_ready();
|
business_state_set_stack_ready();
|
||||||
|
|
||||||
if (lifecycle_is_ready()) {
|
|
||||||
lifecycle_set(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,16 +273,16 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)apply_lifecycle(LC_STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_start();
|
(void)apply_lifecycle(LC_RUNNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "bat_state_event.h"
|
#include "bat_state_event.h"
|
||||||
#include "datetime_event.h"
|
#include "datetime_event.h"
|
||||||
#include "hid_led_event.h"
|
#include "hid_led_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "mode_switch_event.h"
|
#include "mode_switch_event.h"
|
||||||
#include "theme_rgb_update_event.h"
|
#include "theme_rgb_update_event.h"
|
||||||
#include "theme_color.h"
|
#include "theme_color.h"
|
||||||
@@ -27,46 +28,74 @@ BUILD_ASSERT(DT_HAS_CHOSEN(zephyr_display), "Missing zephyr,display chosen node"
|
|||||||
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_ALIAS(backlight), okay),
|
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_ALIAS(backlight), okay),
|
||||||
"Missing backlight alias");
|
"Missing backlight alias");
|
||||||
|
|
||||||
static const struct device *const display_dev =
|
struct display_module_ctx {
|
||||||
DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
|
struct module_lifecycle_ctx lc;
|
||||||
static const struct device *const backlight_dev =
|
const struct device *display_dev;
|
||||||
DEVICE_DT_GET(DT_PARENT(DT_ALIAS(backlight)));
|
const struct device *backlight_dev;
|
||||||
static const uint32_t backlight_idx = DT_NODE_CHILD_IDX(DT_ALIAS(backlight));
|
uint32_t backlight_idx;
|
||||||
static struct ui_main_model ui_model = {
|
struct ui_main_model ui_model;
|
||||||
|
bool lvgl_initialized;
|
||||||
|
char date_text[DATETIME_EVENT_DATE_TEXT_LEN];
|
||||||
|
char time_text[DATETIME_EVENT_TIME_TEXT_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct display_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)),
|
||||||
|
.backlight_dev = DEVICE_DT_GET(DT_PARENT(DT_ALIAS(backlight))),
|
||||||
|
.backlight_idx = DT_NODE_CHILD_IDX(DT_ALIAS(backlight)),
|
||||||
|
.ui_model = {
|
||||||
.theme_color = LV_COLOR_MAKE(BLINKY_THEME_DEFAULT_R,
|
.theme_color = LV_COLOR_MAKE(BLINKY_THEME_DEFAULT_R,
|
||||||
BLINKY_THEME_DEFAULT_G,
|
BLINKY_THEME_DEFAULT_G,
|
||||||
BLINKY_THEME_DEFAULT_B),
|
BLINKY_THEME_DEFAULT_B),
|
||||||
.inactive_border_color = LV_COLOR_MAKE(0x3A, 0x44, 0x52),
|
.inactive_border_color = LV_COLOR_MAKE(0x3A, 0x44, 0x52),
|
||||||
.mode = MODE_SWITCH_BLE,
|
.mode = MODE_SWITCH_BLE,
|
||||||
|
},
|
||||||
|
.date_text = "1970/01/01",
|
||||||
|
.time_text = "00:00:00",
|
||||||
};
|
};
|
||||||
static bool initialized;
|
|
||||||
static bool running;
|
|
||||||
static bool lvgl_initialized;
|
|
||||||
static char date_text[DATETIME_EVENT_DATE_TEXT_LEN] = "1970/01/01";
|
|
||||||
static char time_text[DATETIME_EVENT_TIME_TEXT_LEN] = "00:00:00";
|
|
||||||
|
|
||||||
static int backlight_set(bool on)
|
static int backlight_set(bool on)
|
||||||
{
|
{
|
||||||
if (on) {
|
if (on) {
|
||||||
return led_on(backlight_dev, backlight_idx);
|
return led_on(ctx.backlight_dev, ctx.backlight_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return led_off(backlight_dev, backlight_idx);
|
return led_off(ctx.backlight_dev, ctx.backlight_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
LOG_INF("Display init on %s", display_dev->name);
|
LOG_INF("Display init on %s", ctx.display_dev->name);
|
||||||
|
|
||||||
if (!device_is_ready(display_dev)) {
|
if (!device_is_ready(ctx.display_dev)) {
|
||||||
LOG_ERR("Display device %s not ready", display_dev->name);
|
LOG_ERR("Display device %s not ready", ctx.display_dev->name);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device_is_ready(backlight_dev)) {
|
if (!device_is_ready(ctx.backlight_dev)) {
|
||||||
LOG_ERR("Backlight device %s not ready", backlight_dev->name);
|
LOG_ERR("Backlight device %s not ready", ctx.backlight_dev->name);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,25 +108,25 @@ static int module_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lvgl_initialized) {
|
if (!ctx.lvgl_initialized) {
|
||||||
err = lvgl_init();
|
err = lvgl_init();
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("lvgl_init failed (%d)", err);
|
LOG_ERR("lvgl_init failed (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
lvgl_initialized = true;
|
ctx.lvgl_initialized = true;
|
||||||
|
|
||||||
lvgl_lock();
|
lvgl_lock();
|
||||||
ui_main_init(&ui_model, date_text, time_text);
|
ui_main_init(&ctx.ui_model, ctx.date_text, ctx.time_text);
|
||||||
lvgl_unlock();
|
lvgl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,39 +136,39 @@ static int module_start(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = display_blanking_off(display_dev);
|
err = display_blanking_off(ctx.display_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("display_blanking_off failed (%d)", err);
|
LOG_ERR("display_blanking_off failed (%d)", err);
|
||||||
(void)backlight_set(false);
|
(void)backlight_set(false);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
LOG_INF("LVGL display started");
|
LOG_INF("LVGL display started");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)display_blanking_on(display_dev);
|
(void)display_blanking_on(ctx.display_dev);
|
||||||
(void)backlight_set(false);
|
(void)backlight_set(false);
|
||||||
running = false;
|
|
||||||
LOG_INF("LVGL display paused");
|
LOG_INF("LVGL display paused");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_ui(void)
|
static void refresh_ui(void)
|
||||||
{
|
{
|
||||||
if (!lvgl_initialized) {
|
if (!ctx.lvgl_initialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lvgl_lock();
|
lvgl_lock();
|
||||||
ui_main_refresh_all(&ui_model, date_text, time_text);
|
ui_main_refresh_all(&ctx.ui_model, ctx.date_text, ctx.time_text);
|
||||||
lvgl_unlock();
|
lvgl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +177,9 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
if (is_bat_state_event(aeh)) {
|
if (is_bat_state_event(aeh)) {
|
||||||
const struct bat_state_event *event = cast_bat_state_event(aeh);
|
const struct bat_state_event *event = cast_bat_state_event(aeh);
|
||||||
|
|
||||||
ui_model.battery_level = event->soc;
|
ctx.ui_model.battery_level = event->soc;
|
||||||
ui_model.charging = event->charging;
|
ctx.ui_model.charging = event->charging;
|
||||||
ui_model.full = event->full;
|
ctx.ui_model.full = event->full;
|
||||||
refresh_ui();
|
refresh_ui();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -158,7 +187,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
if (is_mode_switch_event(aeh)) {
|
if (is_mode_switch_event(aeh)) {
|
||||||
const struct mode_switch_event *event = cast_mode_switch_event(aeh);
|
const struct mode_switch_event *event = cast_mode_switch_event(aeh);
|
||||||
|
|
||||||
ui_model.mode = event->mode;
|
ctx.ui_model.mode = event->mode;
|
||||||
refresh_ui();
|
refresh_ui();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -166,7 +195,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
if (is_hid_led_event(aeh)) {
|
if (is_hid_led_event(aeh)) {
|
||||||
const struct hid_led_event *event = cast_hid_led_event(aeh);
|
const struct hid_led_event *event = cast_hid_led_event(aeh);
|
||||||
|
|
||||||
ui_model.led_mask = event->led_bm;
|
ctx.ui_model.led_mask = event->led_bm;
|
||||||
refresh_ui();
|
refresh_ui();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -175,7 +204,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
const struct theme_rgb_update_event *event =
|
const struct theme_rgb_update_event *event =
|
||||||
cast_theme_rgb_update_event(aeh);
|
cast_theme_rgb_update_event(aeh);
|
||||||
|
|
||||||
ui_model.theme_color = (lv_color_t)LV_COLOR_MAKE(event->theme.r,
|
ctx.ui_model.theme_color = (lv_color_t)LV_COLOR_MAKE(event->theme.r,
|
||||||
event->theme.g,
|
event->theme.g,
|
||||||
event->theme.b);
|
event->theme.b);
|
||||||
refresh_ui();
|
refresh_ui();
|
||||||
@@ -185,58 +214,35 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
if (is_datetime_event(aeh)) {
|
if (is_datetime_event(aeh)) {
|
||||||
const struct datetime_event *event = cast_datetime_event(aeh);
|
const struct datetime_event *event = cast_datetime_event(aeh);
|
||||||
|
|
||||||
strncpy(date_text, event->date_text, sizeof(date_text));
|
strncpy(ctx.date_text, event->date_text, sizeof(ctx.date_text));
|
||||||
date_text[sizeof(date_text) - 1] = '\0';
|
ctx.date_text[sizeof(ctx.date_text) - 1] = '\0';
|
||||||
strncpy(time_text, event->time_text, sizeof(time_text));
|
strncpy(ctx.time_text, event->time_text, sizeof(ctx.time_text));
|
||||||
time_text[sizeof(time_text) - 1] = '\0';
|
ctx.time_text[sizeof(ctx.time_text) - 1] = '\0';
|
||||||
refresh_ui();
|
refresh_ui();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_module_state_event(aeh)) {
|
if (is_module_state_event(aeh)) {
|
||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <zephyr/pm/device.h>
|
#include <zephyr/pm/device.h>
|
||||||
|
|
||||||
#include "encoder_event.h"
|
#include "encoder_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
|
|
||||||
@@ -22,17 +23,41 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
|||||||
|
|
||||||
BUILD_ASSERT(DT_NODE_EXISTS(ENCODER_QDEC_NODE), "Missing qdec0 alias");
|
BUILD_ASSERT(DT_NODE_EXISTS(ENCODER_QDEC_NODE), "Missing qdec0 alias");
|
||||||
|
|
||||||
static const struct device *const qdec_dev = DEVICE_DT_GET(ENCODER_QDEC_NODE);
|
struct encoder_module_ctx {
|
||||||
|
struct module_lifecycle_ctx lc;
|
||||||
static struct k_work encoder_report_work;
|
const struct device *qdec_dev;
|
||||||
static struct sensor_trigger encoder_trigger = {
|
struct k_work encoder_report_work;
|
||||||
.type = SENSOR_TRIG_DATA_READY,
|
struct sensor_trigger encoder_trigger;
|
||||||
.chan = SENSOR_CHAN_ROTATION,
|
int64_t angle_remainder_udeg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool initialized;
|
static int do_init(void);
|
||||||
static bool running;
|
static int do_start(void);
|
||||||
static int64_t angle_remainder_udeg;
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct encoder_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.qdec_dev = DEVICE_DT_GET(ENCODER_QDEC_NODE),
|
||||||
|
.encoder_trigger = {
|
||||||
|
.type = SENSOR_TRIG_DATA_READY,
|
||||||
|
.chan = SENSOR_CHAN_ROTATION,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static int64_t sensor_value_to_udeg(const struct sensor_value *value)
|
static int64_t sensor_value_to_udeg(const struct sensor_value *value)
|
||||||
{
|
{
|
||||||
@@ -68,25 +93,26 @@ static void encoder_report_work_handler(struct k_work *work)
|
|||||||
|
|
||||||
ARG_UNUSED(work);
|
ARG_UNUSED(work);
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sensor_sample_fetch(qdec_dev);
|
err = sensor_sample_fetch(ctx.qdec_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("QDEC sample fetch failed (%d)", err);
|
LOG_WRN("QDEC sample fetch failed (%d)", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &rotation);
|
err = sensor_channel_get(ctx.qdec_dev, SENSOR_CHAN_ROTATION, &rotation);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("QDEC channel get failed (%d)", err);
|
LOG_WRN("QDEC channel get failed (%d)", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_udeg = angle_remainder_udeg + sensor_value_to_udeg(&rotation);
|
total_udeg = ctx.angle_remainder_udeg + sensor_value_to_udeg(&rotation);
|
||||||
detents = (int32_t)(total_udeg / ENCODER_DETENT_UDEG);
|
detents = (int32_t)(total_udeg / ENCODER_DETENT_UDEG);
|
||||||
angle_remainder_udeg = total_udeg - ((int64_t)detents * ENCODER_DETENT_UDEG);
|
ctx.angle_remainder_udeg =
|
||||||
|
total_udeg - ((int64_t)detents * ENCODER_DETENT_UDEG);
|
||||||
|
|
||||||
if (detents != 0) {
|
if (detents != 0) {
|
||||||
submit_detents_batched(detents);
|
submit_detents_batched(detents);
|
||||||
@@ -99,26 +125,27 @@ static void encoder_trigger_handler(const struct device *dev,
|
|||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
ARG_UNUSED(trigger);
|
ARG_UNUSED(trigger);
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_work_submit(&encoder_report_work);
|
k_work_submit(&ctx.encoder_report_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!device_is_ready(qdec_dev)) {
|
if (!device_is_ready(ctx.qdec_dev)) {
|
||||||
LOG_ERR("QDEC device not ready");
|
LOG_ERR("QDEC device not ready");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_work_init(&encoder_report_work, encoder_report_work_handler);
|
k_work_init(&ctx.encoder_report_work, encoder_report_work_handler);
|
||||||
angle_remainder_udeg = 0;
|
ctx.angle_remainder_udeg = 0;
|
||||||
|
|
||||||
err = sensor_trigger_set(qdec_dev, &encoder_trigger, encoder_trigger_handler);
|
err = sensor_trigger_set(ctx.qdec_dev, &ctx.encoder_trigger,
|
||||||
|
encoder_trigger_handler);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Cannot set QDEC trigger (%d)", err);
|
LOG_ERR("Cannot set QDEC trigger (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
@@ -127,41 +154,41 @@ static int module_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pm_device_action_run(qdec_dev, PM_DEVICE_ACTION_RESUME);
|
err = pm_device_action_run(ctx.qdec_dev, PM_DEVICE_ACTION_RESUME);
|
||||||
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
||||||
LOG_ERR("Cannot resume QDEC device (%d)", err);
|
LOG_ERR("Cannot resume QDEC device (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
angle_remainder_udeg = 0;
|
ctx.angle_remainder_udeg = 0;
|
||||||
running = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pm_device_action_run(qdec_dev, PM_DEVICE_ACTION_SUSPEND);
|
err = pm_device_action_run(ctx.qdec_dev, PM_DEVICE_ACTION_SUSPEND);
|
||||||
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
||||||
LOG_WRN("Cannot suspend QDEC device (%d)", err);
|
LOG_WRN("Cannot suspend QDEC device (%d)", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
angle_remainder_udeg = 0;
|
ctx.angle_remainder_udeg = 0;
|
||||||
running = false;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool app_event_handler(const struct app_event_header *aeh)
|
static bool app_event_handler(const struct app_event_header *aeh)
|
||||||
@@ -170,47 +197,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
int err;
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "hid_tx_report_event.h"
|
#include "hid_tx_report_event.h"
|
||||||
#include "keyboard_core.h"
|
#include "keyboard_core.h"
|
||||||
#include "keyboard_hid_report_event.h"
|
#include "keyboard_hid_report_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "mode_switch_event.h"
|
#include "mode_switch_event.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
@@ -49,7 +50,42 @@ struct in_flight_report {
|
|||||||
uint16_t sequence;
|
uint16_t sequence;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT] = {
|
struct hid_flowctrl_module_ctx {
|
||||||
|
struct module_lifecycle_ctx lc;
|
||||||
|
struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT];
|
||||||
|
struct pending_report pending_keys;
|
||||||
|
struct pending_report pending_consumer_latest;
|
||||||
|
struct queued_report consumer_fifo[HID_FLOWCTRL_FIFO_DEPTH];
|
||||||
|
uint8_t consumer_fifo_head;
|
||||||
|
uint8_t consumer_fifo_tail;
|
||||||
|
uint8_t consumer_fifo_count;
|
||||||
|
struct in_flight_report in_flight[HID_SEND_CH_COUNT];
|
||||||
|
enum mode_switch_mode current_mode;
|
||||||
|
uint16_t next_sequence;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct hid_flowctrl_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.channel_state = {
|
||||||
[HID_SEND_CH_USB_KEYS] = {
|
[HID_SEND_CH_USB_KEYS] = {
|
||||||
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||||
},
|
},
|
||||||
@@ -59,18 +95,21 @@ static struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT] = {
|
|||||||
[HID_SEND_CH_BLE_SHARED] = {
|
[HID_SEND_CH_BLE_SHARED] = {
|
||||||
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
static struct pending_report pending_keys;
|
|
||||||
static struct pending_report pending_consumer_latest;
|
#define lifecycle ctx.lc
|
||||||
static struct queued_report consumer_fifo[HID_FLOWCTRL_FIFO_DEPTH];
|
#define channel_state ctx.channel_state
|
||||||
static uint8_t consumer_fifo_head;
|
#define pending_keys ctx.pending_keys
|
||||||
static uint8_t consumer_fifo_tail;
|
#define pending_consumer_latest ctx.pending_consumer_latest
|
||||||
static uint8_t consumer_fifo_count;
|
#define consumer_fifo ctx.consumer_fifo
|
||||||
static struct in_flight_report in_flight[HID_SEND_CH_COUNT];
|
#define consumer_fifo_head ctx.consumer_fifo_head
|
||||||
static enum mode_switch_mode current_mode;
|
#define consumer_fifo_tail ctx.consumer_fifo_tail
|
||||||
static uint16_t next_sequence;
|
#define consumer_fifo_count ctx.consumer_fifo_count
|
||||||
static bool initialized;
|
#define in_flight ctx.in_flight
|
||||||
static bool running;
|
#define current_mode ctx.current_mode
|
||||||
|
#define next_sequence ctx.next_sequence
|
||||||
|
#define running module_lifecycle_is_running(&ctx.lc)
|
||||||
|
|
||||||
static bool current_mode_to_channel(enum keyboard_report_type report_type,
|
static bool current_mode_to_channel(enum keyboard_report_type report_type,
|
||||||
enum hid_send_channel *channel)
|
enum hid_send_channel *channel)
|
||||||
@@ -359,7 +398,7 @@ static bool handle_mode_switch_event(const struct mode_switch_event *event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
clear_pending_reports();
|
clear_pending_reports();
|
||||||
current_mode = MODE_SWITCH_USB;
|
current_mode = MODE_SWITCH_USB;
|
||||||
@@ -374,25 +413,25 @@ static int module_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (running) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
try_send_next();
|
try_send_next();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!running) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_pending_reports();
|
clear_pending_reports();
|
||||||
running = false;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool app_event_handler(const struct app_event_header *aeh)
|
static bool app_event_handler(const struct app_event_header *aeh)
|
||||||
@@ -421,47 +460,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
cast_module_state_event(aeh);
|
cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
int err;
|
(void)module_set_lifecycle(&lifecycle, LC_RUNNING);
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&lifecycle)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&lifecycle, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&lifecycle)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&lifecycle, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "function_bitmap_update_event.h"
|
#include "function_bitmap_update_event.h"
|
||||||
#include "keyboard_core.h"
|
#include "keyboard_core.h"
|
||||||
#include "keyboard_hid_report_event.h"
|
#include "keyboard_hid_report_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "mode_switch_event.h"
|
#include "mode_switch_event.h"
|
||||||
#include "set_protocol_event.h"
|
#include "set_protocol_event.h"
|
||||||
|
|
||||||
@@ -85,17 +86,51 @@ static const uint16_t consumer_usage_map[KEYBOARD_CONSUMER_CTRL_COUNT] = {
|
|||||||
[KEYBOARD_CONSUMER_CTRL_PREV_TRACK] = 0x00B6,
|
[KEYBOARD_CONSUMER_CTRL_PREV_TRACK] = 0x00B6,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct keyboard_state keyboard_state;
|
struct keyboard_core_module_ctx {
|
||||||
static struct keyboard_reports_cache reports_cache;
|
struct module_lifecycle_ctx lc;
|
||||||
static uint8_t function_usage_mask[KEYBOARD_PROTOCOL_BITMAP_BYTES];
|
struct keyboard_state keyboard_state;
|
||||||
static enum keyboard_protocol_mode transport_protocol_modes[HID_TRANSPORT_COUNT] = {
|
struct keyboard_reports_cache reports_cache;
|
||||||
|
uint8_t function_usage_mask[KEYBOARD_PROTOCOL_BITMAP_BYTES];
|
||||||
|
enum keyboard_protocol_mode transport_protocol_modes[HID_TRANSPORT_COUNT];
|
||||||
|
enum mode_switch_mode current_mode;
|
||||||
|
bool mode_valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct keyboard_core_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.transport_protocol_modes = {
|
||||||
[HID_TRANSPORT_USB] = KEYBOARD_PROTOCOL_MODE_REPORT,
|
[HID_TRANSPORT_USB] = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||||
[HID_TRANSPORT_BLE] = KEYBOARD_PROTOCOL_MODE_REPORT,
|
[HID_TRANSPORT_BLE] = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
static enum mode_switch_mode current_mode;
|
|
||||||
static bool initialized;
|
#define lifecycle ctx.lc
|
||||||
static bool running;
|
#define keyboard_state ctx.keyboard_state
|
||||||
static bool mode_valid;
|
#define reports_cache ctx.reports_cache
|
||||||
|
#define function_usage_mask ctx.function_usage_mask
|
||||||
|
#define transport_protocol_modes ctx.transport_protocol_modes
|
||||||
|
#define current_mode ctx.current_mode
|
||||||
|
#define mode_valid ctx.mode_valid
|
||||||
|
#define running module_lifecycle_is_running(&ctx.lc)
|
||||||
|
|
||||||
static bool mode_to_transport(enum mode_switch_mode mode, enum hid_transport *transport)
|
static bool mode_to_transport(enum mode_switch_mode mode, enum hid_transport *transport)
|
||||||
{
|
{
|
||||||
@@ -440,7 +475,7 @@ static void emit_release_reports(enum mode_switch_mode mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
keyboard_state_clear();
|
keyboard_state_clear();
|
||||||
reports_cache_invalidate();
|
reports_cache_invalidate();
|
||||||
@@ -454,20 +489,19 @@ static int module_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (running) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!running) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode_valid) {
|
if (mode_valid) {
|
||||||
@@ -478,7 +512,8 @@ static void module_pause(void)
|
|||||||
keyboard_state_clear();
|
keyboard_state_clear();
|
||||||
reports_cache_invalidate();
|
reports_cache_invalidate();
|
||||||
mode_valid = false;
|
mode_valid = false;
|
||||||
running = false;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_button_event(const struct button_event *event)
|
static bool handle_button_event(const struct button_event *event)
|
||||||
@@ -630,47 +665,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
int err;
|
(void)module_set_lifecycle(&lifecycle, LC_RUNNING);
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&lifecycle)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&lifecycle, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&lifecycle)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&lifecycle, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "led_effect/led_effect.h"
|
#include "led_effect/led_effect.h"
|
||||||
#include "led_strip_en_event.h"
|
#include "led_strip_en_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "theme_rgb_update_event.h"
|
#include "theme_rgb_update_event.h"
|
||||||
#include "theme_color.h"
|
#include "theme_color.h"
|
||||||
|
|
||||||
@@ -34,9 +35,16 @@ BUILD_ASSERT(DT_NODE_HAS_PROP(LED_STRIP_NODE, supply_gpios),
|
|||||||
BUILD_ASSERT(LED_STRIP_NUM_PIXELS == 17U,
|
BUILD_ASSERT(LED_STRIP_NUM_PIXELS == 17U,
|
||||||
"LED strip key map expects 17 pixels");
|
"LED strip key map expects 17 pixels");
|
||||||
|
|
||||||
static const struct device *const strip = DEVICE_DT_GET(LED_STRIP_NODE);
|
struct led_strip_module_ctx {
|
||||||
static const struct gpio_dt_spec strip_en =
|
struct module_lifecycle_ctx lc;
|
||||||
GPIO_DT_SPEC_GET(LED_STRIP_NODE, supply_gpios);
|
const struct device *strip;
|
||||||
|
struct gpio_dt_spec strip_en;
|
||||||
|
struct led_rgb pixels[LED_STRIP_NUM_PIXELS];
|
||||||
|
struct k_work_delayable effect_work;
|
||||||
|
struct led_effect *effect;
|
||||||
|
struct theme_rgb current_theme;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
static const struct led_key_map led_key_map[] = {
|
static const struct led_key_map led_key_map[] = {
|
||||||
{ KEY_ID(0, 1), 0U },
|
{ KEY_ID(0, 1), 0U },
|
||||||
@@ -65,28 +73,47 @@ static const struct led_effect_config effect_cfg = {
|
|||||||
.default_brightness = 0xFFU,
|
.default_brightness = 0xFFU,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct led_rgb pixels[LED_STRIP_NUM_PIXELS];
|
static int do_init(void);
|
||||||
static struct k_work_delayable effect_work;
|
static int do_start(void);
|
||||||
static struct led_effect *effect;
|
static int do_stop(void);
|
||||||
static struct theme_rgb current_theme = {
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct led_strip_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.strip = DEVICE_DT_GET(LED_STRIP_NODE),
|
||||||
|
.strip_en = GPIO_DT_SPEC_GET(LED_STRIP_NODE, supply_gpios),
|
||||||
|
.current_theme = {
|
||||||
.r = BLINKY_THEME_DEFAULT_R,
|
.r = BLINKY_THEME_DEFAULT_R,
|
||||||
.g = BLINKY_THEME_DEFAULT_G,
|
.g = BLINKY_THEME_DEFAULT_G,
|
||||||
.b = BLINKY_THEME_DEFAULT_B,
|
.b = BLINKY_THEME_DEFAULT_B,
|
||||||
|
},
|
||||||
|
.enabled = true,
|
||||||
};
|
};
|
||||||
static bool initialized;
|
|
||||||
static bool running;
|
|
||||||
static bool enabled = true;
|
|
||||||
|
|
||||||
static void clear_pixels(void)
|
static void clear_pixels(void)
|
||||||
{
|
{
|
||||||
memset(pixels, 0, sizeof(pixels));
|
memset(ctx.pixels, 0, sizeof(ctx.pixels));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int submit_frame(void)
|
static int submit_frame(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = led_strip_update_rgb(strip, pixels, ARRAY_SIZE(pixels));
|
err = led_strip_update_rgb(ctx.strip, ctx.pixels, ARRAY_SIZE(ctx.pixels));
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("led_strip_update_rgb failed (%d)", err);
|
LOG_WRN("led_strip_update_rgb failed (%d)", err);
|
||||||
}
|
}
|
||||||
@@ -98,7 +125,7 @@ static int set_strip_power(bool on)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = gpio_pin_set_dt(&strip_en, on ? 1 : 0);
|
err = gpio_pin_set_dt(&ctx.strip_en, on ? 1 : 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("LED strip EN set failed (%d)", err);
|
LOG_WRN("LED strip EN set failed (%d)", err);
|
||||||
}
|
}
|
||||||
@@ -114,12 +141,12 @@ static int refresh_idle_frame(void)
|
|||||||
|
|
||||||
static void stop_effect_work(void)
|
static void stop_effect_work(void)
|
||||||
{
|
{
|
||||||
k_work_cancel_delayable(&effect_work);
|
k_work_cancel_delayable(&ctx.effect_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void schedule_effect_tick(k_timeout_t delay)
|
static void schedule_effect_tick(k_timeout_t delay)
|
||||||
{
|
{
|
||||||
k_work_reschedule(&effect_work, delay);
|
k_work_reschedule(&ctx.effect_work, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int enable_strip_output(void)
|
static int enable_strip_output(void)
|
||||||
@@ -148,13 +175,15 @@ static void effect_work_handler(struct k_work *work)
|
|||||||
|
|
||||||
ARG_UNUSED(work);
|
ARG_UNUSED(work);
|
||||||
|
|
||||||
if (!running || !enabled || (effect == NULL)) {
|
if (!module_lifecycle_is_running(&ctx.lc) || !ctx.enabled ||
|
||||||
|
(ctx.effect == NULL)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
keep_running = effect->ops->tick(effect, k_ticks_to_ms_floor32(
|
keep_running = ctx.effect->ops->tick(ctx.effect,
|
||||||
|
k_ticks_to_ms_floor32(
|
||||||
LED_STRIP_TICK_INTERVAL.ticks),
|
LED_STRIP_TICK_INTERVAL.ticks),
|
||||||
pixels, ARRAY_SIZE(pixels));
|
ctx.pixels, ARRAY_SIZE(ctx.pixels));
|
||||||
(void)submit_frame();
|
(void)submit_frame();
|
||||||
|
|
||||||
if (keep_running) {
|
if (keep_running) {
|
||||||
@@ -162,90 +191,85 @@ static void effect_work_handler(struct k_work *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!device_is_ready(strip)) {
|
if (!device_is_ready(ctx.strip)) {
|
||||||
LOG_ERR("LED strip device %s not ready", strip->name);
|
LOG_ERR("LED strip device %s not ready", ctx.strip->name);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gpio_is_ready_dt(&strip_en)) {
|
if (!gpio_is_ready_dt(&ctx.strip_en)) {
|
||||||
LOG_ERR("LED strip supply GPIO not ready");
|
LOG_ERR("LED strip supply GPIO not ready");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gpio_pin_configure_dt(&strip_en, GPIO_OUTPUT_INACTIVE);
|
err = gpio_pin_configure_dt(&ctx.strip_en, GPIO_OUTPUT_INACTIVE);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Failed to configure LED strip supply GPIO (%d)", err);
|
LOG_ERR("Failed to configure LED strip supply GPIO (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_work_init_delayable(&effect_work, effect_work_handler);
|
k_work_init_delayable(&ctx.effect_work, effect_work_handler);
|
||||||
clear_pixels();
|
clear_pixels();
|
||||||
|
|
||||||
effect = led_effect_get_mutable(LED_EFFECT_ID_KEY_FADE);
|
ctx.effect = led_effect_get_mutable(LED_EFFECT_ID_KEY_FADE);
|
||||||
if ((effect == NULL) || (effect->ops == NULL)) {
|
if ((ctx.effect == NULL) || (ctx.effect->ops == NULL)) {
|
||||||
LOG_ERR("LED effect not available");
|
LOG_ERR("LED effect not available");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = effect->ops->init(effect, &effect_cfg);
|
err = ctx.effect->ops->init(ctx.effect, &effect_cfg);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("LED effect init failed (%d)", err);
|
LOG_ERR("LED effect init failed (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
effect->ops->set_theme(effect, ¤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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
if (!ctx.enabled) {
|
||||||
|
|
||||||
if (!enabled) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = enable_strip_output();
|
err = enable_strip_output();
|
||||||
if (err) {
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((effect != NULL) && (effect->ops != NULL)) {
|
if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) {
|
||||||
effect->ops->reset(effect);
|
ctx.effect->ops->reset(ctx.effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
disable_strip_output();
|
disable_strip_output();
|
||||||
running = false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_button_event(const struct button_event *event)
|
static bool handle_button_event(const struct button_event *event)
|
||||||
{
|
{
|
||||||
if (!running || !enabled || (effect == NULL) || !event->pressed) {
|
if (!module_lifecycle_is_running(&ctx.lc) || !ctx.enabled ||
|
||||||
|
(ctx.effect == NULL) || !event->pressed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
effect->ops->on_key_press(effect, event->key_id);
|
ctx.effect->ops->on_key_press(ctx.effect, event->key_id);
|
||||||
schedule_effect_tick(K_NO_WAIT);
|
schedule_effect_tick(K_NO_WAIT);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -253,22 +277,23 @@ static bool handle_button_event(const struct button_event *event)
|
|||||||
|
|
||||||
static bool handle_led_strip_en_event(const struct led_strip_en_event *event)
|
static bool handle_led_strip_en_event(const struct led_strip_en_event *event)
|
||||||
{
|
{
|
||||||
enabled = event->enabled;
|
ctx.enabled = event->enabled;
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled) {
|
if (ctx.enabled) {
|
||||||
int err = enable_strip_output();
|
int err = enable_strip_output();
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
LOG_WRN("LED strip enable request failed (%d)", err);
|
||||||
|
ctx.enabled = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((effect != NULL) && (effect->ops != NULL)) {
|
if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) {
|
||||||
effect->ops->reset(effect);
|
ctx.effect->ops->reset(ctx.effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
disable_strip_output();
|
disable_strip_output();
|
||||||
@@ -279,13 +304,14 @@ static bool handle_led_strip_en_event(const struct led_strip_en_event *event)
|
|||||||
|
|
||||||
static bool handle_theme_rgb_update_event(const struct theme_rgb_update_event *event)
|
static bool handle_theme_rgb_update_event(const struct theme_rgb_update_event *event)
|
||||||
{
|
{
|
||||||
current_theme = event->theme;
|
ctx.current_theme = event->theme;
|
||||||
|
|
||||||
if ((effect != NULL) && (effect->ops != NULL)) {
|
if ((ctx.effect != NULL) && (ctx.effect->ops != NULL)) {
|
||||||
effect->ops->set_theme(effect, ¤t_theme);
|
ctx.effect->ops->set_theme(ctx.effect, &ctx.current_theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (running && enabled && (effect != NULL) && effect->ops->is_active(effect)) {
|
if (module_lifecycle_is_running(&ctx.lc) && ctx.enabled &&
|
||||||
|
(ctx.effect != NULL) && ctx.effect->ops->is_active(ctx.effect)) {
|
||||||
schedule_effect_tick(K_NO_WAIT);
|
schedule_effect_tick(K_NO_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,47 +336,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
int err;
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -9,14 +9,40 @@
|
|||||||
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "mode_switch_event.h"
|
#include "mode_switch_event.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
|
|
||||||
static bool initialized;
|
struct mode_policy_module_ctx {
|
||||||
static bool running;
|
struct module_lifecycle_ctx lc;
|
||||||
static bool ble_adv_suspended = true;
|
bool ble_adv_suspended;
|
||||||
static bool usb_enabled;
|
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)
|
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_suspend_ble_adv = (mode != MODE_SWITCH_BLE);
|
||||||
bool should_enable_usb = (mode == MODE_SWITCH_USB);
|
bool should_enable_usb = (mode == MODE_SWITCH_USB);
|
||||||
|
|
||||||
if (should_suspend_ble_adv != ble_adv_suspended) {
|
if (should_suspend_ble_adv != ctx.ble_adv_suspended) {
|
||||||
ble_adv_suspended = should_suspend_ble_adv;
|
ctx.ble_adv_suspended = should_suspend_ble_adv;
|
||||||
broadcast_ble_adv_req(should_suspend_ble_adv);
|
broadcast_ble_adv_req(should_suspend_ble_adv);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_enable_usb != usb_enabled) {
|
if (should_enable_usb != ctx.usb_enabled) {
|
||||||
usb_enabled = should_enable_usb;
|
ctx.usb_enabled = should_enable_usb;
|
||||||
if (usb_enabled) {
|
if (ctx.usb_enabled) {
|
||||||
struct module_resume_req_event *event =
|
struct module_resume_req_event *event =
|
||||||
new_module_resume_req_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;
|
ctx.ble_adv_suspended = true;
|
||||||
usb_enabled = false;
|
ctx.usb_enabled = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
return 0;
|
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)
|
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)) {
|
if (is_mode_switch_event(aeh)) {
|
||||||
const struct mode_switch_event *event = cast_mode_switch_event(aeh);
|
const struct mode_switch_event *event = cast_mode_switch_event(aeh);
|
||||||
|
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
apply_mode_policy(event->mode);
|
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);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
int err;
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
#include <zephyr/pm/device.h>
|
#include <zephyr/pm/device.h>
|
||||||
|
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "mode_switch_event.h"
|
#include "mode_switch_event.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
@@ -26,15 +27,38 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
|||||||
BUILD_ASSERT(DT_NODE_EXISTS(MODE_SWITCH_ADC_NODE),
|
BUILD_ASSERT(DT_NODE_EXISTS(MODE_SWITCH_ADC_NODE),
|
||||||
"Missing mode_switch_adc node in devicetree");
|
"Missing mode_switch_adc node in devicetree");
|
||||||
|
|
||||||
static const struct device *const mode_switch_adc_dev =
|
struct mode_switch_module_ctx {
|
||||||
DEVICE_DT_GET(MODE_SWITCH_ADC_NODE);
|
struct module_lifecycle_ctx lc;
|
||||||
|
const struct device *mode_switch_adc_dev;
|
||||||
|
struct k_work_delayable mode_switch_sample_work;
|
||||||
|
bool force_report;
|
||||||
|
bool mode_valid;
|
||||||
|
enum mode_switch_mode last_mode;
|
||||||
|
};
|
||||||
|
|
||||||
static struct k_work_delayable mode_switch_sample_work;
|
static int do_init(void);
|
||||||
static bool initialized;
|
static int do_start(void);
|
||||||
static bool running;
|
static int do_stop(void);
|
||||||
static bool force_report;
|
|
||||||
static bool mode_valid;
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
static enum mode_switch_mode last_mode;
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mode_switch_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.mode_switch_adc_dev = DEVICE_DT_GET(MODE_SWITCH_ADC_NODE),
|
||||||
|
};
|
||||||
|
|
||||||
static enum mode_switch_mode detect_mode(uint16_t voltage_mv)
|
static enum mode_switch_mode detect_mode(uint16_t voltage_mv)
|
||||||
{
|
{
|
||||||
@@ -53,7 +77,7 @@ static int mode_switch_enable(bool enable)
|
|||||||
{
|
{
|
||||||
enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME
|
enum pm_device_action action = enable ? PM_DEVICE_ACTION_RESUME
|
||||||
: PM_DEVICE_ACTION_SUSPEND;
|
: PM_DEVICE_ACTION_SUSPEND;
|
||||||
int err = pm_device_action_run(mode_switch_adc_dev, action);
|
int err = pm_device_action_run(ctx.mode_switch_adc_dev, action);
|
||||||
|
|
||||||
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
||||||
LOG_ERR("Cannot %s mode switch ADC (%d)",
|
LOG_ERR("Cannot %s mode switch ADC (%d)",
|
||||||
@@ -71,17 +95,18 @@ static void mode_switch_sample_fn(struct k_work *work)
|
|||||||
|
|
||||||
ARG_UNUSED(work);
|
ARG_UNUSED(work);
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sensor_sample_fetch(mode_switch_adc_dev);
|
err = sensor_sample_fetch(ctx.mode_switch_adc_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("Mode switch ADC sample fetch failed (%d)", err);
|
LOG_WRN("Mode switch ADC sample fetch failed (%d)", err);
|
||||||
goto reschedule;
|
goto reschedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sensor_channel_get(mode_switch_adc_dev, SENSOR_CHAN_VOLTAGE, &voltage);
|
err = sensor_channel_get(ctx.mode_switch_adc_dev, SENSOR_CHAN_VOLTAGE,
|
||||||
|
&voltage);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("Mode switch ADC channel get failed (%d)", err);
|
LOG_WRN("Mode switch ADC channel get failed (%d)", err);
|
||||||
goto reschedule;
|
goto reschedule;
|
||||||
@@ -90,39 +115,40 @@ static void mode_switch_sample_fn(struct k_work *work)
|
|||||||
uint16_t sample_mv = (uint16_t)((voltage.val1 * 1000) + (voltage.val2 / 1000));
|
uint16_t sample_mv = (uint16_t)((voltage.val1 * 1000) + (voltage.val2 / 1000));
|
||||||
enum mode_switch_mode mode = detect_mode(sample_mv);
|
enum mode_switch_mode mode = detect_mode(sample_mv);
|
||||||
|
|
||||||
if (force_report || !mode_valid || (mode != last_mode)) {
|
if (ctx.force_report || !ctx.mode_valid || (mode != ctx.last_mode)) {
|
||||||
submit_mode_switch_event(mode, sample_mv);
|
submit_mode_switch_event(mode, sample_mv);
|
||||||
|
|
||||||
last_mode = mode;
|
ctx.last_mode = mode;
|
||||||
mode_valid = true;
|
ctx.mode_valid = true;
|
||||||
force_report = false;
|
ctx.force_report = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
reschedule:
|
reschedule:
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
k_work_reschedule(&mode_switch_sample_work, MODE_SWITCH_SAMPLE_INTERVAL);
|
k_work_reschedule(&ctx.mode_switch_sample_work,
|
||||||
|
MODE_SWITCH_SAMPLE_INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
if (!device_is_ready(mode_switch_adc_dev)) {
|
if (!device_is_ready(ctx.mode_switch_adc_dev)) {
|
||||||
LOG_ERR("Mode switch ADC device not ready");
|
LOG_ERR("Mode switch ADC device not ready");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_work_init_delayable(&mode_switch_sample_work, mode_switch_sample_fn);
|
k_work_init_delayable(&ctx.mode_switch_sample_work, mode_switch_sample_fn);
|
||||||
mode_valid = false;
|
ctx.mode_valid = false;
|
||||||
force_report = false;
|
ctx.force_report = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,22 +157,22 @@ static int module_start(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
ctx.force_report = true;
|
||||||
force_report = true;
|
k_work_reschedule(&ctx.mode_switch_sample_work, K_NO_WAIT);
|
||||||
k_work_reschedule(&mode_switch_sample_work, K_NO_WAIT);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)k_work_cancel_delayable(&mode_switch_sample_work);
|
(void)k_work_cancel_delayable(&ctx.mode_switch_sample_work);
|
||||||
(void)mode_switch_enable(false);
|
(void)mode_switch_enable(false);
|
||||||
running = false;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool app_event_handler(const struct app_event_header *aeh)
|
static bool app_event_handler(const struct app_event_header *aeh)
|
||||||
@@ -155,47 +181,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
int err;
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "function_bitmap_state_event.h"
|
#include "function_bitmap_state_event.h"
|
||||||
#include "function_bitmap_update_event.h"
|
#include "function_bitmap_update_event.h"
|
||||||
#include "hid_led_event.h"
|
#include "hid_led_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "proto_rx_event.h"
|
#include "proto_rx_event.h"
|
||||||
#include "proto_transport_state_event.h"
|
#include "proto_transport_state_event.h"
|
||||||
#include "proto_tx_event.h"
|
#include "proto_tx_event.h"
|
||||||
@@ -38,16 +39,41 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
|||||||
#define PROTOCOL_CAPABILITY_FLAGS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4))
|
#define PROTOCOL_CAPABILITY_FLAGS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4))
|
||||||
#define PROTOCOL_MAX_MSG_LEN 128U
|
#define PROTOCOL_MAX_MSG_LEN 128U
|
||||||
|
|
||||||
static bool initialized;
|
|
||||||
static bool running;
|
|
||||||
|
|
||||||
enum proto_session_state {
|
enum proto_session_state {
|
||||||
PROTO_SESSION_DOWN = 0,
|
PROTO_SESSION_DOWN = 0,
|
||||||
PROTO_SESSION_WAIT_HELLO,
|
PROTO_SESSION_WAIT_HELLO,
|
||||||
PROTO_SESSION_ACTIVE,
|
PROTO_SESSION_ACTIVE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum proto_session_state session_state[PROTO_TRANSPORT_COUNT];
|
struct protocol_module_ctx {
|
||||||
|
struct module_lifecycle_ctx lc;
|
||||||
|
enum proto_session_state session_state[PROTO_TRANSPORT_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct protocol_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define session_state ctx.session_state
|
||||||
|
|
||||||
static int decode_body(const uint8_t *payload, size_t payload_len,
|
static int decode_body(const uint8_t *payload, size_t payload_len,
|
||||||
CdcPacketBody *body)
|
CdcPacketBody *body)
|
||||||
@@ -157,7 +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);
|
return encode_body(&body, payload, payload_buf_size, payload_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
|
||||||
session_state[i] = PROTO_SESSION_DOWN;
|
session_state[i] = PROTO_SESSION_DOWN;
|
||||||
@@ -166,27 +192,26 @@ static int module_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
|
||||||
session_state[i] = PROTO_SESSION_DOWN;
|
session_state[i] = PROTO_SESSION_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int protocol_module_process_message(enum proto_transport transport,
|
int protocol_module_process_message(enum proto_transport transport,
|
||||||
@@ -204,7 +229,7 @@ int protocol_module_process_message(enum proto_transport transport,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +342,7 @@ static bool handle_proto_rx_event(const struct proto_rx_event *event)
|
|||||||
size_t rsp_payload_len = 0U;
|
size_t rsp_payload_len = 0U;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +398,7 @@ static bool handle_function_bitmap_state_event(
|
|||||||
size_t payload_len;
|
size_t payload_len;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +431,7 @@ static bool handle_hid_led_event(const struct hid_led_event *event)
|
|||||||
int err;
|
int err;
|
||||||
enum proto_transport transport;
|
enum proto_transport transport;
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,25 +479,9 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
|
|
||||||
if (is_module_state_event(aeh)) {
|
if (is_module_state_event(aeh)) {
|
||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -481,23 +490,16 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -13,18 +13,43 @@
|
|||||||
#include <zephyr/sys/printk.h>
|
#include <zephyr/sys/printk.h>
|
||||||
|
|
||||||
#include "datetime_event.h"
|
#include "datetime_event.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "time_sync_event.h"
|
#include "time_sync_event.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
|
|
||||||
#define TIME_SYNC_REFRESH_PERIOD K_SECONDS(1)
|
#define TIME_SYNC_REFRESH_PERIOD K_SECONDS(1)
|
||||||
|
|
||||||
static struct k_work_delayable refresh_work;
|
struct time_sync_module_ctx {
|
||||||
static bool initialized;
|
struct module_lifecycle_ctx lc;
|
||||||
static bool running;
|
struct k_work_delayable refresh_work;
|
||||||
static int32_t timezone_min;
|
int32_t timezone_min;
|
||||||
static uint64_t utc_ms_base;
|
uint64_t utc_ms_base;
|
||||||
static int64_t uptime_ms_base;
|
int64_t uptime_ms_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct time_sync_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static void publish_datetime_event(void)
|
static void publish_datetime_event(void)
|
||||||
{
|
{
|
||||||
@@ -34,9 +59,9 @@ static void publish_datetime_event(void)
|
|||||||
char date_text[DATETIME_EVENT_DATE_TEXT_LEN];
|
char date_text[DATETIME_EVENT_DATE_TEXT_LEN];
|
||||||
char time_text[DATETIME_EVENT_TIME_TEXT_LEN];
|
char time_text[DATETIME_EVENT_TIME_TEXT_LEN];
|
||||||
|
|
||||||
local_ms = (int64_t)utc_ms_base +
|
local_ms = (int64_t)ctx.utc_ms_base +
|
||||||
(k_uptime_get() - uptime_ms_base) +
|
(k_uptime_get() - ctx.uptime_ms_base) +
|
||||||
((int64_t)timezone_min * 60LL * 1000LL);
|
((int64_t)ctx.timezone_min * 60LL * 1000LL);
|
||||||
if (local_ms < 0) {
|
if (local_ms < 0) {
|
||||||
local_ms = 0;
|
local_ms = 0;
|
||||||
}
|
}
|
||||||
@@ -67,43 +92,43 @@ static void refresh_work_handler(struct k_work *work)
|
|||||||
{
|
{
|
||||||
ARG_UNUSED(work);
|
ARG_UNUSED(work);
|
||||||
|
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
publish_datetime_event();
|
publish_datetime_event();
|
||||||
k_work_reschedule(&refresh_work, TIME_SYNC_REFRESH_PERIOD);
|
k_work_reschedule(&ctx.refresh_work, TIME_SYNC_REFRESH_PERIOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
timezone_min = 0;
|
ctx.timezone_min = 0;
|
||||||
utc_ms_base = 0U;
|
ctx.utc_ms_base = 0U;
|
||||||
uptime_ms_base = k_uptime_get();
|
ctx.uptime_ms_base = k_uptime_get();
|
||||||
k_work_init_delayable(&refresh_work, refresh_work_handler);
|
k_work_init_delayable(&ctx.refresh_work, refresh_work_handler);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
k_work_reschedule(&ctx.refresh_work, K_NO_WAIT);
|
||||||
k_work_reschedule(&refresh_work, K_NO_WAIT);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_work_cancel_delayable(&refresh_work);
|
k_work_cancel_delayable(&ctx.refresh_work);
|
||||||
running = false;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_time_sync_event(const struct time_sync_event *event)
|
static bool handle_time_sync_event(const struct time_sync_event *event)
|
||||||
@@ -113,12 +138,12 @@ static bool handle_time_sync_event(const struct time_sync_event *event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
timezone_min = event->timezone_min;
|
ctx.timezone_min = event->timezone_min;
|
||||||
utc_ms_base = event->utc_ms;
|
ctx.utc_ms_base = event->utc_ms;
|
||||||
uptime_ms_base = k_uptime_get();
|
ctx.uptime_ms_base = k_uptime_get();
|
||||||
|
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
k_work_reschedule(&refresh_work, K_NO_WAIT);
|
k_work_reschedule(&ctx.refresh_work, K_NO_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -132,48 +157,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
|
|
||||||
if (is_module_state_event(aeh)) {
|
if (is_module_state_event(aeh)) {
|
||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <zephyr/sys/ring_buffer.h>
|
#include <zephyr/sys/ring_buffer.h>
|
||||||
#include <zephyr/sys/util.h>
|
#include <zephyr/sys/util.h>
|
||||||
|
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "proto_rx_event.h"
|
#include "proto_rx_event.h"
|
||||||
#include "proto_transport_state_event.h"
|
#include "proto_transport_state_event.h"
|
||||||
#include "proto_tx_event.h"
|
#include "proto_tx_event.h"
|
||||||
@@ -38,33 +39,53 @@ enum usb_cdc_business_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct usb_cdc_ctx {
|
struct usb_cdc_ctx {
|
||||||
enum module_state lifecycle;
|
struct module_lifecycle_ctx lc;
|
||||||
enum usb_cdc_business_state business;
|
enum usb_cdc_business_state business;
|
||||||
|
const struct device *cdc_dev;
|
||||||
|
uint8_t rx_ring_buffer[USB_CDC_RX_RING_BUF_SIZE];
|
||||||
|
uint8_t tx_ring_buffer[USB_CDC_TX_RING_BUF_SIZE];
|
||||||
|
struct ring_buf rx_ringbuf;
|
||||||
|
struct ring_buf tx_ringbuf;
|
||||||
|
struct k_work rx_work;
|
||||||
|
struct k_work_delayable rx_flush_work;
|
||||||
|
uint8_t proto_rx_buf[USB_CDC_PROTO_RX_BUF_SIZE];
|
||||||
bool usb_active;
|
bool usb_active;
|
||||||
size_t proto_rx_len;
|
size_t proto_rx_len;
|
||||||
};
|
};
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
static const struct device *const cdc_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
static uint8_t rx_ring_buffer[USB_CDC_RX_RING_BUF_SIZE];
|
|
||||||
static uint8_t tx_ring_buffer[USB_CDC_TX_RING_BUF_SIZE];
|
|
||||||
static struct ring_buf rx_ringbuf;
|
|
||||||
static struct ring_buf tx_ringbuf;
|
|
||||||
static struct k_work rx_work;
|
|
||||||
static struct k_work_delayable rx_flush_work;
|
|
||||||
static uint8_t proto_rx_buf[USB_CDC_PROTO_RX_BUF_SIZE];
|
|
||||||
static struct usb_cdc_ctx ctx = {
|
static struct usb_cdc_ctx ctx = {
|
||||||
.lifecycle = MODULE_STATE_OFF,
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
.business = USB_CDC_BUS_OFFLINE,
|
.business = USB_CDC_BUS_OFFLINE,
|
||||||
|
.cdc_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart),
|
||||||
.usb_active = false,
|
.usb_active = false,
|
||||||
.proto_rx_len = 0U,
|
.proto_rx_len = 0U,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define proto_rx_buf ctx.proto_rx_buf
|
||||||
|
|
||||||
static void validate_line_coding(void);
|
static void validate_line_coding(void);
|
||||||
|
|
||||||
static bool lifecycle_is_ready(void)
|
static bool lifecycle_is_ready(void)
|
||||||
{
|
{
|
||||||
return ctx.lifecycle == MODULE_STATE_READY;
|
return module_lifecycle_is_running(&ctx.lc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum proto_transport_link_state transport_link_state_get(void)
|
static enum proto_transport_link_state transport_link_state_get(void)
|
||||||
@@ -75,44 +96,36 @@ static enum proto_transport_link_state transport_link_state_get(void)
|
|||||||
PROTO_TRANSPORT_LINK_DOWN;
|
PROTO_TRANSPORT_LINK_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool control_poll_needed(enum module_state lifecycle,
|
|
||||||
enum usb_cdc_business_state business)
|
|
||||||
{
|
|
||||||
ARG_UNUSED(lifecycle);
|
|
||||||
ARG_UNUSED(business);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reset_ring_buffers(void)
|
static void reset_ring_buffers(void)
|
||||||
{
|
{
|
||||||
unsigned int key = irq_lock();
|
unsigned int key = irq_lock();
|
||||||
|
|
||||||
ring_buf_init(&rx_ringbuf, sizeof(rx_ring_buffer), rx_ring_buffer);
|
ring_buf_init(&ctx.rx_ringbuf, sizeof(ctx.rx_ring_buffer), ctx.rx_ring_buffer);
|
||||||
ring_buf_init(&tx_ringbuf, sizeof(tx_ring_buffer), tx_ring_buffer);
|
ring_buf_init(&ctx.tx_ringbuf, sizeof(ctx.tx_ring_buffer), ctx.tx_ring_buffer);
|
||||||
|
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_uart_io(void)
|
static void disable_uart_io(void)
|
||||||
{
|
{
|
||||||
uart_irq_rx_disable(cdc_dev);
|
uart_irq_rx_disable(ctx.cdc_dev);
|
||||||
uart_irq_tx_disable(cdc_dev);
|
uart_irq_tx_disable(ctx.cdc_dev);
|
||||||
ctx.proto_rx_len = 0U;
|
ctx.proto_rx_len = 0U;
|
||||||
k_work_cancel_delayable(&rx_flush_work);
|
k_work_cancel_delayable(&ctx.rx_flush_work);
|
||||||
reset_ring_buffers();
|
reset_ring_buffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void state_reconcile(enum module_state old_lifecycle,
|
static void state_reconcile(enum module_lifecycle old_lifecycle,
|
||||||
enum usb_cdc_business_state old_business)
|
enum usb_cdc_business_state old_business)
|
||||||
{
|
{
|
||||||
enum proto_transport_link_state old_link =
|
enum proto_transport_link_state old_link =
|
||||||
((old_lifecycle == MODULE_STATE_READY) &&
|
((old_lifecycle == LC_RUNNING) &&
|
||||||
(old_business == USB_CDC_SESSION_READY)) ?
|
(old_business == USB_CDC_SESSION_READY)) ?
|
||||||
PROTO_TRANSPORT_LINK_READY :
|
PROTO_TRANSPORT_LINK_READY :
|
||||||
PROTO_TRANSPORT_LINK_DOWN;
|
PROTO_TRANSPORT_LINK_DOWN;
|
||||||
enum proto_transport_link_state new_link = transport_link_state_get();
|
enum proto_transport_link_state new_link = transport_link_state_get();
|
||||||
|
|
||||||
if ((old_lifecycle == MODULE_STATE_READY) &&
|
if ((old_lifecycle == LC_RUNNING) &&
|
||||||
(old_business == USB_CDC_SESSION_READY) &&
|
(old_business == USB_CDC_SESSION_READY) &&
|
||||||
(new_link == PROTO_TRANSPORT_LINK_DOWN)) {
|
(new_link == PROTO_TRANSPORT_LINK_DOWN)) {
|
||||||
disable_uart_io();
|
disable_uart_io();
|
||||||
@@ -124,17 +137,17 @@ static void state_reconcile(enum module_state old_lifecycle,
|
|||||||
|
|
||||||
validate_line_coding();
|
validate_line_coding();
|
||||||
|
|
||||||
err = uart_line_ctrl_set(cdc_dev, UART_LINE_CTRL_DCD, 1);
|
err = uart_line_ctrl_set(ctx.cdc_dev, UART_LINE_CTRL_DCD, 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("Failed to set DCD (%d)", err);
|
LOG_WRN("Failed to set DCD (%d)", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = uart_line_ctrl_set(cdc_dev, UART_LINE_CTRL_DSR, 1);
|
err = uart_line_ctrl_set(ctx.cdc_dev, UART_LINE_CTRL_DSR, 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("Failed to set DSR (%d)", err);
|
LOG_WRN("Failed to set DSR (%d)", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_irq_rx_enable(cdc_dev);
|
uart_irq_rx_enable(ctx.cdc_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_link != new_link) {
|
if (old_link != new_link) {
|
||||||
@@ -143,23 +156,9 @@ static void state_reconcile(enum module_state old_lifecycle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lifecycle_set(enum module_state new_state)
|
|
||||||
{
|
|
||||||
enum module_state old_lifecycle = ctx.lifecycle;
|
|
||||||
enum usb_cdc_business_state old_business = ctx.business;
|
|
||||||
|
|
||||||
if (ctx.lifecycle == new_state) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.lifecycle = new_state;
|
|
||||||
state_reconcile(old_lifecycle, old_business);
|
|
||||||
module_set_state(new_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void business_state_set(enum usb_cdc_business_state new_state)
|
static void business_state_set(enum usb_cdc_business_state new_state)
|
||||||
{
|
{
|
||||||
enum module_state old_lifecycle = ctx.lifecycle;
|
enum module_lifecycle old_lifecycle = ctx.lc.state;
|
||||||
enum usb_cdc_business_state old_business = ctx.business;
|
enum usb_cdc_business_state old_business = ctx.business;
|
||||||
|
|
||||||
if (ctx.business == new_state) {
|
if (ctx.business == new_state) {
|
||||||
@@ -192,7 +191,7 @@ static void kick_tx(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_irq_tx_enable(cdc_dev);
|
uart_irq_tx_enable(ctx.cdc_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void validate_line_coding(void)
|
static void validate_line_coding(void)
|
||||||
@@ -200,7 +199,7 @@ static void validate_line_coding(void)
|
|||||||
uint32_t baudrate = 0U;
|
uint32_t baudrate = 0U;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = uart_line_ctrl_get(cdc_dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
|
err = uart_line_ctrl_get(ctx.cdc_dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("Failed to get CDC baudrate (%d)", err);
|
LOG_WRN("Failed to get CDC baudrate (%d)", err);
|
||||||
} else {
|
} else {
|
||||||
@@ -215,7 +214,7 @@ static void validate_line_coding(void)
|
|||||||
{
|
{
|
||||||
struct uart_config cfg;
|
struct uart_config cfg;
|
||||||
|
|
||||||
err = uart_config_get(cdc_dev, &cfg);
|
err = uart_config_get(ctx.cdc_dev, &cfg);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("uart_config_get failed (%d)", err);
|
LOG_WRN("uart_config_get failed (%d)", err);
|
||||||
} else {
|
} else {
|
||||||
@@ -243,7 +242,7 @@ static void rx_work_handler(struct k_work *work)
|
|||||||
uint32_t len;
|
uint32_t len;
|
||||||
unsigned int key = irq_lock();
|
unsigned int key = irq_lock();
|
||||||
|
|
||||||
len = ring_buf_get(&rx_ringbuf, buffer, sizeof(buffer));
|
len = ring_buf_get(&ctx.rx_ringbuf, buffer, sizeof(buffer));
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
|
|
||||||
if (len == 0U) {
|
if (len == 0U) {
|
||||||
@@ -259,7 +258,7 @@ static void rx_work_handler(struct k_work *work)
|
|||||||
if (len > 0U) {
|
if (len > 0U) {
|
||||||
memcpy(&proto_rx_buf[ctx.proto_rx_len], buffer, len);
|
memcpy(&proto_rx_buf[ctx.proto_rx_len], buffer, len);
|
||||||
ctx.proto_rx_len += len;
|
ctx.proto_rx_len += len;
|
||||||
k_work_reschedule(&rx_flush_work, USB_CDC_PROTO_RX_FLUSH_DELAY);
|
k_work_reschedule(&ctx.rx_flush_work, USB_CDC_PROTO_RX_FLUSH_DELAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,7 +295,7 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
|
|||||||
uint32_t written;
|
uint32_t written;
|
||||||
unsigned int key = irq_lock();
|
unsigned int key = irq_lock();
|
||||||
|
|
||||||
written = ring_buf_put(&rx_ringbuf, buffer,
|
written = ring_buf_put(&ctx.rx_ringbuf, buffer,
|
||||||
(uint32_t)recv_len);
|
(uint32_t)recv_len);
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
|
|
||||||
@@ -305,7 +304,7 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
|
|||||||
recv_len - (int)written);
|
recv_len - (int)written);
|
||||||
}
|
}
|
||||||
|
|
||||||
k_work_submit(&rx_work);
|
k_work_submit(&ctx.rx_work);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +314,7 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
|
|||||||
int sent_len;
|
int sent_len;
|
||||||
unsigned int key = irq_lock();
|
unsigned int key = irq_lock();
|
||||||
|
|
||||||
len = ring_buf_get(&tx_ringbuf, buffer, sizeof(buffer));
|
len = ring_buf_get(&ctx.tx_ringbuf, buffer, sizeof(buffer));
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
|
|
||||||
if (len == 0U) {
|
if (len == 0U) {
|
||||||
@@ -335,37 +334,52 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
if (!device_is_ready(cdc_dev)) {
|
if (!device_is_ready(ctx.cdc_dev)) {
|
||||||
LOG_ERR("CDC ACM device not ready");
|
LOG_ERR("CDC ACM device not ready");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_ring_buffers();
|
reset_ring_buffers();
|
||||||
k_work_init(&rx_work, rx_work_handler);
|
k_work_init(&ctx.rx_work, rx_work_handler);
|
||||||
k_work_init_delayable(&rx_flush_work, rx_flush_work_handler);
|
k_work_init_delayable(&ctx.rx_flush_work, rx_flush_work_handler);
|
||||||
uart_irq_callback_set(cdc_dev, cdc_interrupt_handler);
|
uart_irq_callback_set(ctx.cdc_dev, cdc_interrupt_handler);
|
||||||
ctx = (struct usb_cdc_ctx) {
|
ctx.business = USB_CDC_BUS_OFFLINE;
|
||||||
.lifecycle = MODULE_STATE_OFF,
|
ctx.usb_active = false;
|
||||||
.business = USB_CDC_BUS_OFFLINE,
|
ctx.proto_rx_len = 0U;
|
||||||
.usb_active = false,
|
|
||||||
.proto_rx_len = 0U,
|
|
||||||
};
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
lifecycle_set(MODULE_STATE_READY);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_stop(void)
|
||||||
|
{
|
||||||
|
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();
|
business_state_sync_from_usb();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
return 0;
|
||||||
{
|
|
||||||
business_state_set(USB_CDC_BUS_OFFLINE);
|
|
||||||
lifecycle_set(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_usb_state_event(const struct usb_state_event *event)
|
static bool handle_usb_state_event(const struct usb_state_event *event)
|
||||||
@@ -384,7 +398,7 @@ static bool handle_usb_state_event(const struct usb_state_event *event)
|
|||||||
|
|
||||||
static bool handle_usb_control_event(const struct usb_control_event *event)
|
static bool handle_usb_control_event(const struct usb_control_event *event)
|
||||||
{
|
{
|
||||||
if (event->dev != cdc_dev) {
|
if (event->dev != ctx.cdc_dev) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,7 +463,7 @@ static bool handle_proto_tx_event(const struct proto_tx_event *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
key = irq_lock();
|
key = irq_lock();
|
||||||
written = ring_buf_put(&tx_ringbuf, event->dyndata.data,
|
written = ring_buf_put(&ctx.tx_ringbuf, event->dyndata.data,
|
||||||
(uint32_t)event->dyndata.size);
|
(uint32_t)event->dyndata.size);
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
|
|
||||||
@@ -483,32 +497,23 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
cast_module_state_event(aeh);
|
cast_module_state_event(aeh);
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (ctx.lifecycle == MODULE_STATE_OFF) {
|
(void)apply_lifecycle(LC_RUNNING);
|
||||||
int err = module_init();
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
lifecycle_set(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module_start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)apply_lifecycle(LC_STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_start();
|
(void)apply_lifecycle(LC_RUNNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <caf/events/power_manager_event.h>
|
#include <caf/events/power_manager_event.h>
|
||||||
|
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "usb_function_hook.h"
|
#include "usb_function_hook.h"
|
||||||
#include "usb_control_event.h"
|
#include "usb_control_event.h"
|
||||||
#include "usb_state_event.h"
|
#include "usb_state_event.h"
|
||||||
@@ -40,9 +41,6 @@ static const char *const class_blocklist[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool initialized;
|
|
||||||
static bool running;
|
|
||||||
|
|
||||||
enum usb_stack_state {
|
enum usb_stack_state {
|
||||||
USB_STACK_UNINITIALIZED = 0,
|
USB_STACK_UNINITIALIZED = 0,
|
||||||
USB_STACK_DISABLED,
|
USB_STACK_DISABLED,
|
||||||
@@ -58,11 +56,35 @@ enum usb_bus_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct usb_owner_ctx {
|
struct usb_owner_ctx {
|
||||||
|
struct module_lifecycle_ctx lc;
|
||||||
enum usb_stack_state stack;
|
enum usb_stack_state stack;
|
||||||
enum usb_bus_state bus;
|
enum usb_bus_state bus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
/* Project exception: mode policy suspend/resume controls USB availability,
|
||||||
|
* while global power events still map to standby lifecycle transitions.
|
||||||
|
*/
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_SUSPEND,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
static struct usb_owner_ctx usb_ctx = {
|
static struct usb_owner_ctx usb_ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
.stack = USB_STACK_UNINITIALIZED,
|
.stack = USB_STACK_UNINITIALIZED,
|
||||||
.bus = USB_BUS_DISCONNECTED,
|
.bus = USB_BUS_DISCONNECTED,
|
||||||
};
|
};
|
||||||
@@ -363,7 +385,7 @@ static int usb_stack_disable_if_needed(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
usb_ctx.stack = USB_STACK_UNINITIALIZED;
|
usb_ctx.stack = USB_STACK_UNINITIALIZED;
|
||||||
usb_ctx.bus = USB_BUS_DISCONNECTED;
|
usb_ctx.bus = USB_BUS_DISCONNECTED;
|
||||||
@@ -372,25 +394,25 @@ static int module_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&usb_ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
submit_usb_state(usb_public_state_get());
|
submit_usb_state(usb_public_state_get());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&usb_ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = false;
|
|
||||||
submit_usb_state(usb_public_state_get());
|
submit_usb_state(usb_public_state_get());
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_module_state_event(const struct module_state_event *event)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&usb_ctx.lc, LC_RUNNING);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
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(
|
static bool handle_module_suspend_req_event(
|
||||||
const struct module_suspend_req_event *event)
|
const struct module_suspend_req_event *event)
|
||||||
{
|
{
|
||||||
if ((event->sink_module_id != MODULE_ID(MODULE)) || !running) {
|
if ((event->sink_module_id != MODULE_ID(MODULE)) ||
|
||||||
|
(usb_ctx.lc.state != LC_RUNNING)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = usb_stack_disable_if_needed();
|
int err = usb_stack_disable_if_needed();
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
LOG_WRN("USB suspend request failed (%d)", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
(void)module_set_lifecycle(&usb_ctx.lc, LC_SUSPENDED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_module_resume_req_event(
|
static bool handle_module_resume_req_event(
|
||||||
const struct module_resume_req_event *event)
|
const struct module_resume_req_event *event)
|
||||||
{
|
{
|
||||||
if ((event->sink_module_id != MODULE_ID(MODULE)) || !running) {
|
if ((event->sink_module_id != MODULE_ID(MODULE)) ||
|
||||||
|
(usb_ctx.lc.state != LC_SUSPENDED)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = usb_stack_enable_if_needed();
|
int err = usb_stack_enable_if_needed();
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
LOG_WRN("USB resume request failed (%d)", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usb_stack_was_initialized()) {
|
(void)module_set_lifecycle(&usb_ctx.lc, LC_RUNNING);
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -479,23 +482,16 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&usb_ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&usb_ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&usb_ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&usb_ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else if (usb_stack_was_initialized()) {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -18,32 +18,57 @@
|
|||||||
#include "hid_report_sent_event.h"
|
#include "hid_report_sent_event.h"
|
||||||
#include "hid_tx_report_event.h"
|
#include "hid_tx_report_event.h"
|
||||||
#include "keyboard_core.h"
|
#include "keyboard_core.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "usb_function_hook.h"
|
#include "usb_function_hook.h"
|
||||||
#include "usb_state_event.h"
|
#include "usb_state_event.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||||
|
|
||||||
static const struct device *const hid_dev =
|
|
||||||
DEVICE_DT_GET(DT_NODELABEL(hid_consumer));
|
|
||||||
|
|
||||||
static const uint8_t consumer_report_desc[] = {
|
static const uint8_t consumer_report_desc[] = {
|
||||||
0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x15, 0x00,
|
0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x15, 0x00,
|
||||||
0x26, 0xFF, 0x03, 0x19, 0x00, 0x2A, 0xFF, 0x03,
|
0x26, 0xFF, 0x03, 0x19, 0x00, 0x2A, 0xFF, 0x03,
|
||||||
0x75, 0x10, 0x95, 0x01, 0x81, 0x00, 0xC0
|
0x75, 0x10, 0x95, 0x01, 0x81, 0x00, 0xC0
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool initialized;
|
struct usb_hid_consumer_module_ctx {
|
||||||
static bool running;
|
struct module_lifecycle_ctx lc;
|
||||||
static bool usb_active;
|
const struct device *hid_dev;
|
||||||
static bool iface_ready;
|
bool usb_active;
|
||||||
static bool report_in_flight;
|
bool iface_ready;
|
||||||
static uint16_t in_flight_sequence;
|
bool report_in_flight;
|
||||||
|
uint16_t in_flight_sequence;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct usb_hid_consumer_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.hid_dev = DEVICE_DT_GET(DT_NODELABEL(hid_consumer)),
|
||||||
|
};
|
||||||
|
|
||||||
UDC_STATIC_BUF_DEFINE(consumer_tx_buf, KEYBOARD_CONSUMER_REPORT_SIZE);
|
UDC_STATIC_BUF_DEFINE(consumer_tx_buf, KEYBOARD_CONSUMER_REPORT_SIZE);
|
||||||
|
|
||||||
static void publish_consumer_state(void)
|
static void publish_consumer_state(void)
|
||||||
{
|
{
|
||||||
bool ready = running && usb_active && iface_ready;
|
bool ready = module_lifecycle_is_running(&ctx.lc) &&
|
||||||
|
ctx.usb_active && ctx.iface_ready;
|
||||||
|
|
||||||
submit_hid_channel_state_event(HID_SEND_CH_USB_CONSUMER,
|
submit_hid_channel_state_event(HID_SEND_CH_USB_CONSUMER,
|
||||||
ready ? BIT(KEYBOARD_REPORT_TYPE_CONSUMER) : 0U,
|
ready ? BIT(KEYBOARD_REPORT_TYPE_CONSUMER) : 0U,
|
||||||
@@ -54,12 +79,13 @@ static void consumer_iface_ready(const struct device *dev, const bool ready)
|
|||||||
{
|
{
|
||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
iface_ready = ready;
|
ctx.iface_ready = ready;
|
||||||
if (!ready) {
|
if (!ready) {
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INF("%s interface %s", hid_dev->name, ready ? "ready" : "not ready");
|
LOG_INF("%s interface %s", ctx.hid_dev->name,
|
||||||
|
ready ? "ready" : "not ready");
|
||||||
publish_consumer_state();
|
publish_consumer_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,10 +143,10 @@ static void consumer_input_report_done(const struct device *dev,
|
|||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
ARG_UNUSED(report);
|
ARG_UNUSED(report);
|
||||||
|
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
submit_hid_report_sent_event(HID_SEND_CH_USB_CONSUMER,
|
submit_hid_report_sent_event(HID_SEND_CH_USB_CONSUMER,
|
||||||
KEYBOARD_REPORT_TYPE_CONSUMER,
|
KEYBOARD_REPORT_TYPE_CONSUMER,
|
||||||
in_flight_sequence, false);
|
ctx.in_flight_sequence, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void consumer_output_report(const struct device *dev,
|
static void consumer_output_report(const struct device *dev,
|
||||||
@@ -145,59 +171,59 @@ static const struct hid_device_ops consumer_ops = {
|
|||||||
|
|
||||||
static int usb_hid_consumer_register_device(void)
|
static int usb_hid_consumer_register_device(void)
|
||||||
{
|
{
|
||||||
if (!device_is_ready(hid_dev)) {
|
if (!device_is_ready(ctx.hid_dev)) {
|
||||||
LOG_ERR("HID device %s not ready", hid_dev->name);
|
LOG_ERR("HID device %s not ready", ctx.hid_dev->name);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hid_device_register(hid_dev, consumer_report_desc,
|
return hid_device_register(ctx.hid_dev, consumer_report_desc,
|
||||||
sizeof(consumer_report_desc), &consumer_ops);
|
sizeof(consumer_report_desc), &consumer_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
USB_FUNCTION_HOOK_DEFINE(usb_hid_consumer_hook, usb_hid_consumer_register_device);
|
USB_FUNCTION_HOOK_DEFINE(usb_hid_consumer_hook, usb_hid_consumer_register_device);
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
usb_active = false;
|
ctx.usb_active = false;
|
||||||
iface_ready = false;
|
ctx.iface_ready = false;
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
publish_consumer_state();
|
publish_consumer_state();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = false;
|
ctx.report_in_flight = false;
|
||||||
report_in_flight = false;
|
|
||||||
publish_consumer_state();
|
publish_consumer_state();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_usb_state_event(const struct usb_state_event *event)
|
static bool handle_usb_state_event(const struct usb_state_event *event)
|
||||||
{
|
{
|
||||||
bool new_usb_active = (event->state == USB_STATE_ACTIVE);
|
bool new_usb_active = (event->state == USB_STATE_ACTIVE);
|
||||||
|
|
||||||
if (new_usb_active == usb_active) {
|
if (new_usb_active == ctx.usb_active) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_active = new_usb_active;
|
ctx.usb_active = new_usb_active;
|
||||||
if (!usb_active) {
|
if (!ctx.usb_active) {
|
||||||
iface_ready = false;
|
ctx.iface_ready = false;
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
publish_consumer_state();
|
publish_consumer_state();
|
||||||
@@ -208,7 +234,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!running || !usb_active ||
|
if (!module_lifecycle_is_running(&ctx.lc) || !ctx.usb_active ||
|
||||||
(event->channel != HID_SEND_CH_USB_CONSUMER)) {
|
(event->channel != HID_SEND_CH_USB_CONSUMER)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -217,17 +243,17 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iface_ready) {
|
if (!ctx.iface_ready) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (report_in_flight) {
|
if (ctx.report_in_flight) {
|
||||||
LOG_WRN("Drop USB consumer report while previous report is in flight");
|
LOG_WRN("Drop USB consumer report while previous report is in flight");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(consumer_tx_buf, event->dyndata.data, event->dyndata.size);
|
memcpy(consumer_tx_buf, event->dyndata.data, event->dyndata.size);
|
||||||
err = hid_device_submit_report(hid_dev, (uint16_t)event->dyndata.size,
|
err = hid_device_submit_report(ctx.hid_dev, (uint16_t)event->dyndata.size,
|
||||||
consumer_tx_buf);
|
consumer_tx_buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("USB consumer report submit failed (%d)", err);
|
LOG_WRN("USB consumer report submit failed (%d)", err);
|
||||||
@@ -235,8 +261,8 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
KEYBOARD_REPORT_TYPE_CONSUMER,
|
KEYBOARD_REPORT_TYPE_CONSUMER,
|
||||||
event->sequence, true);
|
event->sequence, true);
|
||||||
} else {
|
} else {
|
||||||
report_in_flight = true;
|
ctx.report_in_flight = true;
|
||||||
in_flight_sequence = event->sequence;
|
ctx.in_flight_sequence = event->sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -254,48 +280,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
|
|
||||||
if (is_module_state_event(aeh)) {
|
if (is_module_state_event(aeh)) {
|
||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "hid_report_sent_event.h"
|
#include "hid_report_sent_event.h"
|
||||||
#include "hid_tx_report_event.h"
|
#include "hid_tx_report_event.h"
|
||||||
#include "keyboard_core.h"
|
#include "keyboard_core.h"
|
||||||
|
#include "module_lifecycle.h"
|
||||||
#include "set_protocol_event.h"
|
#include "set_protocol_event.h"
|
||||||
#include "usb_function_hook.h"
|
#include "usb_function_hook.h"
|
||||||
#include "usb_state_event.h"
|
#include "usb_state_event.h"
|
||||||
@@ -28,8 +29,6 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
|||||||
#define KBD_LED_REPORT_SIZE 1U
|
#define KBD_LED_REPORT_SIZE 1U
|
||||||
#define KBD_LED_REPORT_WITH_ID_SIZE (KBD_LED_REPORT_SIZE + 1U)
|
#define KBD_LED_REPORT_WITH_ID_SIZE (KBD_LED_REPORT_SIZE + 1U)
|
||||||
|
|
||||||
static const struct device *const hid_dev = DEVICE_DT_GET(DT_NODELABEL(hid_kbd));
|
|
||||||
|
|
||||||
static const uint8_t keyboard_report_desc[] = {
|
static const uint8_t keyboard_report_desc[] = {
|
||||||
0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07,
|
0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07,
|
||||||
0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01,
|
0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01,
|
||||||
@@ -41,36 +40,64 @@ static const uint8_t keyboard_report_desc[] = {
|
|||||||
0x75, 0x03, 0x95, 0x01, 0x91, 0x01, 0xC0
|
0x75, 0x03, 0x95, 0x01, 0x91, 0x01, 0xC0
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum keyboard_protocol_mode keyboard_protocol_mode =
|
struct usb_hid_keyboard_module_ctx {
|
||||||
KEYBOARD_PROTOCOL_MODE_REPORT;
|
struct module_lifecycle_ctx lc;
|
||||||
static bool initialized;
|
const struct device *hid_dev;
|
||||||
static bool running;
|
enum keyboard_protocol_mode keyboard_protocol_mode;
|
||||||
static bool usb_active;
|
bool usb_active;
|
||||||
static bool iface_ready;
|
bool iface_ready;
|
||||||
static bool report_in_flight;
|
bool report_in_flight;
|
||||||
static uint16_t in_flight_sequence;
|
uint16_t in_flight_sequence;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_init(void);
|
||||||
|
static int do_start(void);
|
||||||
|
static int do_stop(void);
|
||||||
|
|
||||||
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
||||||
|
.mode = ML_MODE_POWER,
|
||||||
|
.stopped_state = MODULE_STATE_STANDBY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
||||||
|
.do_init = do_init,
|
||||||
|
.do_start = do_start,
|
||||||
|
.do_stop = do_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct usb_hid_keyboard_module_ctx ctx = {
|
||||||
|
.lc = {
|
||||||
|
.state = LC_UNINIT,
|
||||||
|
.cfg = &lifecycle_cfg,
|
||||||
|
.ops = &lifecycle_ops,
|
||||||
|
},
|
||||||
|
.hid_dev = DEVICE_DT_GET(DT_NODELABEL(hid_kbd)),
|
||||||
|
.keyboard_protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||||
|
};
|
||||||
|
|
||||||
UDC_STATIC_BUF_DEFINE(keyboard_tx_buf, KEYBOARD_NKRO_REPORT_SIZE);
|
UDC_STATIC_BUF_DEFINE(keyboard_tx_buf, KEYBOARD_NKRO_REPORT_SIZE);
|
||||||
|
|
||||||
static void publish_keyboard_state(void)
|
static void publish_keyboard_state(void)
|
||||||
{
|
{
|
||||||
bool ready = running && usb_active && iface_ready;
|
bool ready = module_lifecycle_is_running(&ctx.lc) &&
|
||||||
|
ctx.usb_active && ctx.iface_ready;
|
||||||
|
|
||||||
submit_hid_channel_state_event(HID_SEND_CH_USB_KEYS,
|
submit_hid_channel_state_event(HID_SEND_CH_USB_KEYS,
|
||||||
ready ? BIT(KEYBOARD_REPORT_TYPE_KEYS) : 0U,
|
ready ? BIT(KEYBOARD_REPORT_TYPE_KEYS) : 0U,
|
||||||
keyboard_protocol_mode);
|
ctx.keyboard_protocol_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_iface_ready(const struct device *dev, const bool ready)
|
static void keyboard_iface_ready(const struct device *dev, const bool ready)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
iface_ready = ready;
|
ctx.iface_ready = ready;
|
||||||
if (!ready) {
|
if (!ready) {
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INF("%s interface %s", hid_dev->name, ready ? "ready" : "not ready");
|
LOG_INF("%s interface %s", ctx.hid_dev->name,
|
||||||
|
ready ? "ready" : "not ready");
|
||||||
publish_keyboard_state();
|
publish_keyboard_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,11 +191,11 @@ static void keyboard_set_protocol(const struct device *dev, const uint8_t proto)
|
|||||||
|
|
||||||
enum keyboard_protocol_mode new_mode = usb_proto_to_keyboard_proto(proto);
|
enum keyboard_protocol_mode new_mode = usb_proto_to_keyboard_proto(proto);
|
||||||
|
|
||||||
if (keyboard_protocol_mode == new_mode) {
|
if (ctx.keyboard_protocol_mode == new_mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
keyboard_protocol_mode = new_mode;
|
ctx.keyboard_protocol_mode = new_mode;
|
||||||
LOG_INF("USB keyboard protocol -> %s",
|
LOG_INF("USB keyboard protocol -> %s",
|
||||||
(new_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? "boot" : "report");
|
(new_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ? "boot" : "report");
|
||||||
submit_set_protocol_event(HID_TRANSPORT_USB, new_mode);
|
submit_set_protocol_event(HID_TRANSPORT_USB, new_mode);
|
||||||
@@ -181,10 +208,10 @@ static void keyboard_input_report_done(const struct device *dev,
|
|||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
ARG_UNUSED(report);
|
ARG_UNUSED(report);
|
||||||
|
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
submit_hid_report_sent_event(HID_SEND_CH_USB_KEYS,
|
submit_hid_report_sent_event(HID_SEND_CH_USB_KEYS,
|
||||||
KEYBOARD_REPORT_TYPE_KEYS,
|
KEYBOARD_REPORT_TYPE_KEYS,
|
||||||
in_flight_sequence, false);
|
ctx.in_flight_sequence, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_output_report(const struct device *dev,
|
static void keyboard_output_report(const struct device *dev,
|
||||||
@@ -211,60 +238,60 @@ static const struct hid_device_ops keyboard_ops = {
|
|||||||
|
|
||||||
static int usb_hid_keyboard_register_device(void)
|
static int usb_hid_keyboard_register_device(void)
|
||||||
{
|
{
|
||||||
if (!device_is_ready(hid_dev)) {
|
if (!device_is_ready(ctx.hid_dev)) {
|
||||||
LOG_ERR("HID device %s not ready", hid_dev->name);
|
LOG_ERR("HID device %s not ready", ctx.hid_dev->name);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hid_device_register(hid_dev, keyboard_report_desc,
|
return hid_device_register(ctx.hid_dev, keyboard_report_desc,
|
||||||
sizeof(keyboard_report_desc), &keyboard_ops);
|
sizeof(keyboard_report_desc), &keyboard_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
USB_FUNCTION_HOOK_DEFINE(usb_hid_keyboard_hook, usb_hid_keyboard_register_device);
|
USB_FUNCTION_HOOK_DEFINE(usb_hid_keyboard_hook, usb_hid_keyboard_register_device);
|
||||||
|
|
||||||
static int module_init(void)
|
static int do_init(void)
|
||||||
{
|
{
|
||||||
keyboard_protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
ctx.keyboard_protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
||||||
usb_active = false;
|
ctx.usb_active = false;
|
||||||
iface_ready = false;
|
ctx.iface_ready = false;
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int module_start(void)
|
static int do_start(void)
|
||||||
{
|
{
|
||||||
if (running) {
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
|
||||||
publish_keyboard_state();
|
publish_keyboard_state();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_pause(void)
|
static int do_stop(void)
|
||||||
{
|
{
|
||||||
if (!running) {
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = false;
|
ctx.report_in_flight = false;
|
||||||
report_in_flight = false;
|
|
||||||
publish_keyboard_state();
|
publish_keyboard_state();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_usb_state_event(const struct usb_state_event *event)
|
static bool handle_usb_state_event(const struct usb_state_event *event)
|
||||||
{
|
{
|
||||||
bool new_usb_active = (event->state == USB_STATE_ACTIVE);
|
bool new_usb_active = (event->state == USB_STATE_ACTIVE);
|
||||||
|
|
||||||
if (new_usb_active == usb_active) {
|
if (new_usb_active == ctx.usb_active) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_active = new_usb_active;
|
ctx.usb_active = new_usb_active;
|
||||||
if (!usb_active) {
|
if (!ctx.usb_active) {
|
||||||
iface_ready = false;
|
ctx.iface_ready = false;
|
||||||
report_in_flight = false;
|
ctx.report_in_flight = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
publish_keyboard_state();
|
publish_keyboard_state();
|
||||||
@@ -275,7 +302,7 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!running || !usb_active ||
|
if (!module_lifecycle_is_running(&ctx.lc) || !ctx.usb_active ||
|
||||||
(event->channel != HID_SEND_CH_USB_KEYS)) {
|
(event->channel != HID_SEND_CH_USB_KEYS)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -284,22 +311,22 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->protocol_mode != keyboard_protocol_mode) {
|
if (event->protocol_mode != ctx.keyboard_protocol_mode) {
|
||||||
LOG_WRN("Drop USB keys report due to protocol mismatch");
|
LOG_WRN("Drop USB keys report due to protocol mismatch");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iface_ready) {
|
if (!ctx.iface_ready) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (report_in_flight) {
|
if (ctx.report_in_flight) {
|
||||||
LOG_WRN("Drop USB keyboard report while previous report is in flight");
|
LOG_WRN("Drop USB keyboard report while previous report is in flight");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(keyboard_tx_buf, event->dyndata.data, event->dyndata.size);
|
memcpy(keyboard_tx_buf, event->dyndata.data, event->dyndata.size);
|
||||||
err = hid_device_submit_report(hid_dev, (uint16_t)event->dyndata.size,
|
err = hid_device_submit_report(ctx.hid_dev, (uint16_t)event->dyndata.size,
|
||||||
keyboard_tx_buf);
|
keyboard_tx_buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_WRN("USB keyboard report submit failed (%d)", err);
|
LOG_WRN("USB keyboard report submit failed (%d)", err);
|
||||||
@@ -307,8 +334,8 @@ static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|||||||
KEYBOARD_REPORT_TYPE_KEYS,
|
KEYBOARD_REPORT_TYPE_KEYS,
|
||||||
event->sequence, true);
|
event->sequence, true);
|
||||||
} else {
|
} else {
|
||||||
report_in_flight = true;
|
ctx.report_in_flight = true;
|
||||||
in_flight_sequence = event->sequence;
|
ctx.in_flight_sequence = event->sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -326,48 +353,25 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
|||||||
|
|
||||||
if (is_module_state_event(aeh)) {
|
if (is_module_state_event(aeh)) {
|
||||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||||
if (!initialized) {
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
err = module_init();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = module_start();
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_power_down_event(aeh)) {
|
if (is_power_down_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
module_pause();
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
||||||
module_set_state(MODULE_STATE_STANDBY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_wake_up_event(aeh)) {
|
if (is_wake_up_event(aeh)) {
|
||||||
if (initialized) {
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
||||||
int err = module_start();
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
module_set_state(MODULE_STATE_ERROR);
|
|
||||||
} else {
|
|
||||||
module_set_state(MODULE_STATE_READY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user