2026-04-10 19:28:20 +08:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
|
|
|
#include <app_event_manager.h>
|
|
|
|
|
|
2026-04-15 15:13:44 +08:00
|
|
|
#define MODULE mode_policy_module
|
2026-04-10 19:28:20 +08:00
|
|
|
#include <caf/events/module_state_event.h>
|
|
|
|
|
#include <caf/events/module_suspend_event.h>
|
|
|
|
|
|
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
#include "module_lifecycle.h"
|
2026-04-10 19:28:20 +08:00
|
|
|
#include "mode_switch_event.h"
|
2026-04-23 09:48:06 +08:00
|
|
|
#include "transport_policy_event.h"
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
struct transport_policy_state {
|
|
|
|
|
enum hid_transport_policy hid_transport;
|
|
|
|
|
enum ble_profile_policy ble_profile;
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
struct mode_policy_module_ctx {
|
|
|
|
|
struct module_lifecycle_ctx lc;
|
2026-04-18 11:27:48 +08:00
|
|
|
enum mode_switch_mode active_mode;
|
2026-04-23 09:48:06 +08:00
|
|
|
struct transport_policy_state policy;
|
2026-04-17 19:12:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int do_init(void);
|
|
|
|
|
static int do_start(void);
|
|
|
|
|
static int do_stop(void);
|
|
|
|
|
|
|
|
|
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
2026-04-18 14:17:23 +08:00
|
|
|
.mode = ML_MODE_NONE,
|
|
|
|
|
.stopped_state = MODULE_STATE_OFF,
|
2026-04-17 19:12:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
},
|
2026-04-18 11:27:48 +08:00
|
|
|
.active_mode = MODE_SWITCH_USB,
|
2026-04-23 09:48:06 +08:00
|
|
|
.policy = {
|
|
|
|
|
.hid_transport = HID_TRANSPORT_POLICY_USB,
|
|
|
|
|
.ble_profile = BLE_PROFILE_POLICY_NONE,
|
|
|
|
|
},
|
2026-04-17 19:12:57 +08:00
|
|
|
};
|
2026-04-10 19:28:20 +08:00
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
static void build_policy_from_mode(enum mode_switch_mode mode,
|
|
|
|
|
struct transport_policy_state *policy)
|
|
|
|
|
{
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case MODE_SWITCH_USB:
|
|
|
|
|
policy->hid_transport = HID_TRANSPORT_POLICY_USB;
|
|
|
|
|
policy->ble_profile = BLE_PROFILE_POLICY_NONE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_BLE:
|
|
|
|
|
policy->hid_transport = HID_TRANSPORT_POLICY_BLE;
|
|
|
|
|
policy->ble_profile = BLE_PROFILE_POLICY_GENERAL;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_24G:
|
|
|
|
|
policy->hid_transport = HID_TRANSPORT_POLICY_BLE;
|
|
|
|
|
policy->ble_profile = BLE_PROFILE_POLICY_DONGLE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
policy->hid_transport = HID_TRANSPORT_POLICY_NONE;
|
|
|
|
|
policy->ble_profile = BLE_PROFILE_POLICY_NONE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool policy_equal(const struct transport_policy_state *a,
|
|
|
|
|
const struct transport_policy_state *b)
|
|
|
|
|
{
|
|
|
|
|
return (a->hid_transport == b->hid_transport) &&
|
|
|
|
|
(a->ble_profile == b->ble_profile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void broadcast_policy(void)
|
|
|
|
|
{
|
|
|
|
|
submit_transport_policy_event(ctx.active_mode, ctx.policy.hid_transport,
|
|
|
|
|
ctx.policy.ble_profile);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-18 11:27:48 +08:00
|
|
|
static void mode_policy_set_ble(bool enable)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-18 11:27:48 +08:00
|
|
|
if (enable) {
|
|
|
|
|
struct module_resume_req_event *event = new_module_resume_req_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
event->sink_module_id = MODULE_ID(ble_adv);
|
|
|
|
|
event->src_module_id = MODULE_ID(MODULE);
|
|
|
|
|
APP_EVENT_SUBMIT(event);
|
|
|
|
|
} else {
|
2026-04-18 11:27:48 +08:00
|
|
|
struct module_suspend_req_event *event = new_module_suspend_req_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
event->sink_module_id = MODULE_ID(ble_adv);
|
|
|
|
|
event->src_module_id = MODULE_ID(MODULE);
|
|
|
|
|
APP_EVENT_SUBMIT(event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-18 11:27:48 +08:00
|
|
|
static void mode_policy_set_usb(bool enable)
|
2026-04-15 15:13:44 +08:00
|
|
|
{
|
2026-04-18 11:27:48 +08:00
|
|
|
if (enable) {
|
|
|
|
|
struct module_resume_req_event *event = new_module_resume_req_event();
|
|
|
|
|
|
|
|
|
|
event->sink_module_id = MODULE_ID(usb_device_module);
|
|
|
|
|
event->src_module_id = MODULE_ID(MODULE);
|
|
|
|
|
APP_EVENT_SUBMIT(event);
|
|
|
|
|
} else {
|
|
|
|
|
struct module_suspend_req_event *event = new_module_suspend_req_event();
|
2026-04-15 15:13:44 +08:00
|
|
|
|
2026-04-18 11:27:48 +08:00
|
|
|
event->sink_module_id = MODULE_ID(usb_device_module);
|
|
|
|
|
event->src_module_id = MODULE_ID(MODULE);
|
|
|
|
|
APP_EVENT_SUBMIT(event);
|
2026-04-15 15:13:44 +08:00
|
|
|
}
|
2026-04-18 11:27:48 +08:00
|
|
|
}
|
2026-04-15 15:13:44 +08:00
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
static void apply_stack_policy(void)
|
2026-04-18 11:27:48 +08:00
|
|
|
{
|
|
|
|
|
switch (ctx.active_mode) {
|
|
|
|
|
case MODE_SWITCH_BLE:
|
|
|
|
|
mode_policy_set_ble(true);
|
|
|
|
|
mode_policy_set_usb(false);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_USB:
|
|
|
|
|
mode_policy_set_ble(false);
|
|
|
|
|
mode_policy_set_usb(true);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_24G:
|
2026-04-23 09:48:06 +08:00
|
|
|
mode_policy_set_ble(true);
|
2026-04-18 11:27:48 +08:00
|
|
|
mode_policy_set_usb(false);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void apply_ble_mode_policy(void)
|
|
|
|
|
{
|
|
|
|
|
switch (ctx.active_mode) {
|
|
|
|
|
case MODE_SWITCH_BLE:
|
|
|
|
|
mode_policy_set_ble(true);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_USB:
|
|
|
|
|
mode_policy_set_ble(false);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_24G:
|
2026-04-23 09:48:06 +08:00
|
|
|
mode_policy_set_ble(true);
|
2026-04-18 11:27:48 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void apply_usb_mode_policy(void)
|
|
|
|
|
{
|
|
|
|
|
switch (ctx.active_mode) {
|
|
|
|
|
case MODE_SWITCH_BLE:
|
|
|
|
|
mode_policy_set_usb(false);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_USB:
|
|
|
|
|
mode_policy_set_usb(true);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MODE_SWITCH_24G:
|
|
|
|
|
mode_policy_set_usb(false);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2026-04-15 15:13:44 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
static void update_mode_policy(enum mode_switch_mode mode)
|
|
|
|
|
{
|
|
|
|
|
struct transport_policy_state next_policy;
|
|
|
|
|
bool mode_changed = (ctx.active_mode != mode);
|
|
|
|
|
bool policy_changed;
|
|
|
|
|
|
|
|
|
|
build_policy_from_mode(mode, &next_policy);
|
|
|
|
|
policy_changed = !policy_equal(&ctx.policy, &next_policy);
|
|
|
|
|
|
|
|
|
|
ctx.active_mode = mode;
|
|
|
|
|
ctx.policy = next_policy;
|
|
|
|
|
|
|
|
|
|
if (policy_changed || mode_changed) {
|
|
|
|
|
broadcast_policy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
apply_stack_policy();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_init(void)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-18 11:27:48 +08:00
|
|
|
ctx.active_mode = MODE_SWITCH_USB;
|
2026-04-23 09:48:06 +08:00
|
|
|
build_policy_from_mode(ctx.active_mode, &ctx.policy);
|
2026-04-10 19:28:20 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_start(void)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-23 09:48:06 +08:00
|
|
|
broadcast_policy();
|
|
|
|
|
apply_stack_policy();
|
2026-04-10 19:28:20 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_stop(void)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-17 19:12:57 +08:00
|
|
|
return 0;
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool app_event_handler(const struct app_event_header *aeh)
|
|
|
|
|
{
|
|
|
|
|
if (is_mode_switch_event(aeh)) {
|
2026-04-15 15:13:44 +08:00
|
|
|
const struct mode_switch_event *event = cast_mode_switch_event(aeh);
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
2026-04-23 09:48:06 +08:00
|
|
|
update_mode_policy(event->mode);
|
2026-04-15 15:13:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_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)) {
|
2026-04-17 19:12:57 +08:00
|
|
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
2026-04-18 11:27:48 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (check_state(event, MODULE_ID(ble_adv), MODULE_STATE_READY)) {
|
|
|
|
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
|
|
|
|
apply_ble_mode_policy();
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (check_state(event, MODULE_ID(usb_device_module),
|
|
|
|
|
MODULE_STATE_READY)) {
|
|
|
|
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
|
|
|
|
apply_usb_mode_policy();
|
|
|
|
|
}
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
|
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, mode_switch_event);
|
|
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|