#include #include #define MODULE mode_policy_module #include #include #include #include "module_lifecycle.h" #include "mode_switch_event.h" #include "transport_policy_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); struct transport_policy_state { enum hid_transport_policy hid_transport; enum ble_profile_policy ble_profile; }; struct mode_policy_module_ctx { struct module_lifecycle_ctx lc; enum mode_switch_mode active_mode; struct transport_policy_state policy; }; 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 mode_policy_module_ctx ctx = { .lc = { .state = LC_UNINIT, .cfg = &lifecycle_cfg, .ops = &lifecycle_ops, }, .active_mode = MODE_SWITCH_USB, .policy = { .hid_transport = HID_TRANSPORT_POLICY_USB, .ble_profile = BLE_PROFILE_POLICY_NONE, }, }; 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); } static void mode_policy_set_ble(bool enable) { if (enable) { struct module_resume_req_event *event = new_module_resume_req_event(); event->sink_module_id = MODULE_ID(ble_adv); event->src_module_id = MODULE_ID(MODULE); APP_EVENT_SUBMIT(event); } else { struct module_suspend_req_event *event = new_module_suspend_req_event(); event->sink_module_id = MODULE_ID(ble_adv); event->src_module_id = MODULE_ID(MODULE); APP_EVENT_SUBMIT(event); } } static void mode_policy_set_usb(bool enable) { 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(); event->sink_module_id = MODULE_ID(usb_device_module); event->src_module_id = MODULE_ID(MODULE); APP_EVENT_SUBMIT(event); } } static void apply_stack_policy(void) { switch (ctx.active_mode) { case MODE_SWITCH_BLE: mode_policy_set_ble(true); mode_policy_set_usb(false); break; case MODE_SWITCH_USB: mode_policy_set_ble(false); mode_policy_set_usb(true); break; case MODE_SWITCH_24G: mode_policy_set_ble(true); 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: mode_policy_set_ble(true); 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; } } 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(); } static int do_init(void) { ctx.active_mode = MODE_SWITCH_USB; build_policy_from_mode(ctx.active_mode, &ctx.policy); return 0; } static int do_start(void) { broadcast_policy(); apply_stack_policy(); return 0; } static int do_stop(void) { return 0; } static bool app_event_handler(const struct app_event_header *aeh) { if (is_mode_switch_event(aeh)) { const struct mode_switch_event *event = cast_mode_switch_event(aeh); if (module_lifecycle_is_running(&ctx.lc)) { update_mode_policy(event->mode); } return false; } 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)) { (void)module_set_lifecycle(&ctx.lc, LC_RUNNING); 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(); } } 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);