From 3f90d04a5020750f0d94ffa04f1df637b53b2b92 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 2 Sep 2026 16:52:59 -0600 Subject: [PATCH 1/5] Add persistent controller profile foundation --- CMakeLists.txt | 5 + bluepad32_input_backend.cpp | 358 ++++- bluepad32_input_backend.h | 11 +- configuration_service.cpp | 4 + configuration_service.h | 1 + controller_identity.cpp | 82 ++ controller_identity.h | 30 + controller_profile.cpp | 725 ++++++++++ controller_profile.h | 191 +++ pico_profile_storage.cpp | 126 ++ pico_profile_storage.h | 5 + profile_service.cpp | 548 ++++++++ profile_service.h | 83 ++ profile_storage.cpp | 301 ++++ profile_storage.h | 78 ++ src/switch_pico_bridge/config_manager.py | 1376 ++++++++++++++++++- switch-pico.cpp | 6 +- tests/bluepad32_backend_lifecycle_test.cpp | 466 ++++++- tests/bluepad32_native_stubs/uni.h | 50 + tests/controller_profile_test.cpp | 162 +++ tests/profile_service_test.cpp | 186 +++ tests/profile_storage_test.cpp | 235 ++++ tests/test_config_manager.py | 620 ++++++++- tests/test_controller_profile_native.py | 30 + tests/test_profile_service_native.py | 33 + tests/test_profile_storage_native.py | 31 + tests/usb_configuration_management_test.cpp | 259 ++++ usb_configuration_management.cpp | 201 +++ usb_configuration_management.h | 24 +- 29 files changed, 6157 insertions(+), 70 deletions(-) create mode 100644 controller_identity.cpp create mode 100644 controller_identity.h create mode 100644 controller_profile.cpp create mode 100644 controller_profile.h create mode 100644 pico_profile_storage.cpp create mode 100644 pico_profile_storage.h create mode 100644 profile_service.cpp create mode 100644 profile_service.h create mode 100644 profile_storage.cpp create mode 100644 profile_storage.h create mode 100644 tests/controller_profile_test.cpp create mode 100644 tests/profile_service_test.cpp create mode 100644 tests/profile_storage_test.cpp create mode 100644 tests/test_controller_profile_native.py create mode 100644 tests/test_profile_service_native.py create mode 100644 tests/test_profile_storage_native.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fb3461..167d8b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,11 @@ add_executable(switch-pico if(SWITCH_PICO_INPUT_BACKEND STREQUAL "BLUEPAD32") target_sources(switch-pico PRIVATE bluepad32_input_backend.cpp + controller_identity.cpp + controller_profile.cpp + profile_storage.cpp + profile_service.cpp + pico_profile_storage.cpp bootsel_pairing_button.cpp adapter_configuration.cpp configuration_storage.cpp diff --git a/bluepad32_input_backend.cpp b/bluepad32_input_backend.cpp index 057669d..b78ed88 100644 --- a/bluepad32_input_backend.cpp +++ b/bluepad32_input_backend.cpp @@ -1,6 +1,7 @@ #include "bluepad32_input_backend.h" #include "controller_hotkey_config.h" #include "configuration_service.h" +#include "profile_service.h" #include #include @@ -111,9 +112,21 @@ struct FeedbackEnvelope { uint8_t strong_magnitude; }; +// Security Manager identity events arrive before Bluepad32 publishes a ready +// device. Retain only the four live handle/address associations so a BLE RPA +// is never promoted to a stable identity on its own. +struct BleIdentityMapping { + bool used; + hci_con_handle_t connection_handle; + bd_addr_t connection_address; + uint8_t identity_address_type; + bd_addr_t identity_address; +}; + struct BackendSlot { ControllerState state; + ControllerIdentity identity; // Non-null with active=false is a connected device still becoming ready. uni_hid_device_t* device; uint32_t state_generation; @@ -132,6 +145,7 @@ struct BackendSlot { critical_section_t g_state_lock; BackendSlot g_slots[kSlotCount]; +BleIdentityMapping g_ble_identity_mappings[kSlotCount]{}; // These acknowledgement generations and the pairing request producer are only // used by Core 0. The request is transferred under the cross-core state lock. @@ -148,6 +162,7 @@ btstack_timer_source_t g_rumble_timer{}; btstack_timer_source_t g_configuration_timer{}; ConnectionStatus g_connection_status = ConnectionStatus::Initializing; btstack_packet_callback_registration_t g_pairing_event_callback{}; +btstack_packet_callback_registration_t g_identity_event_callback{}; ConnectionPolicyState g_connection_policy_state = ConnectionPolicyState::Uninitialized; uint32_t g_pairing_window_deadline_ms = 0; @@ -203,6 +218,186 @@ int slot_for_device(const uni_hid_device_t* device) { const int slot = uni_hid_device_get_idx_for_instance(device); return slot >= 0 && slot < kSlotCount ? slot : -1; } + +bool addresses_equal(const bd_addr_t first, const bd_addr_t second) { + return memcmp(first, second, sizeof(bd_addr_t)) == 0; +} + +BleIdentityMapping* find_ble_identity_mapping( + hci_con_handle_t connection_handle, + const bd_addr_t connection_address) { + for (BleIdentityMapping& mapping : g_ble_identity_mappings) { + if (mapping.used && + mapping.connection_handle == connection_handle && + addresses_equal(mapping.connection_address, + connection_address)) { + return &mapping; + } + } + return nullptr; +} + +BleIdentityMapping* find_ble_identity_mapping_for_handle( + hci_con_handle_t connection_handle) { + for (BleIdentityMapping& mapping : g_ble_identity_mappings) { + if (mapping.used && + mapping.connection_handle == connection_handle) { + return &mapping; + } + } + return nullptr; +} + +BleIdentityMapping* reserve_ble_identity_mapping( + hci_con_handle_t connection_handle) { + BleIdentityMapping* available = nullptr; + for (BleIdentityMapping& mapping : g_ble_identity_mappings) { + if (mapping.used && + mapping.connection_handle == connection_handle) { + return &mapping; + } + if (!mapping.used && available == nullptr) { + available = &mapping; + } + } + return available; +} + +ControllerIdentity make_ble_identity( + const BleIdentityMapping& mapping, const uni_hid_device_t* device) { + ControllerIdentity identity{}; + identity.stable = true; + identity.transport = ControllerTransport::kBle; + identity.address_type = mapping.identity_address_type; + memcpy(identity.address, mapping.identity_address, + sizeof(identity.address)); + identity.vendor_id = device->vendor_id; + identity.product_id = device->product_id; + return identity; +} + +ControllerIdentity identity_for_device(const uni_hid_device_t* device) { + if (device == nullptr) { + return controller_identity_global(); + } + if (device->conn.protocol == UNI_BT_CONN_PROTOCOL_BR_EDR) { + ControllerIdentity identity{}; + identity.stable = true; + identity.transport = ControllerTransport::kClassic; + identity.address_type = BD_ADDR_TYPE_UNKNOWN; + memcpy(identity.address, device->conn.btaddr, + sizeof(identity.address)); + identity.vendor_id = device->vendor_id; + identity.product_id = device->product_id; + return identity; + } + if (device->conn.protocol == UNI_BT_CONN_PROTOCOL_BLE) { + const BleIdentityMapping* mapping = find_ble_identity_mapping( + device->conn.handle, device->conn.btaddr); + if (mapping != nullptr) { + return make_ble_identity(*mapping, device); + } + } + return controller_identity_global(); +} + +void publish_ble_identity(const BleIdentityMapping& mapping) { + ControllerIdentity observed_identity{}; + bool observe_identity = false; + critical_section_enter_blocking(&g_state_lock); + for (BackendSlot& slot : g_slots) { + if (slot.device != nullptr && + slot.device->conn.protocol == UNI_BT_CONN_PROTOCOL_BLE && + slot.device->conn.handle == mapping.connection_handle && + addresses_equal(slot.device->conn.btaddr, + mapping.connection_address)) { + slot.identity = make_ble_identity(mapping, slot.device); + if (slot.active) { + observed_identity = slot.identity; + observe_identity = true; + } + } + } + critical_section_exit(&g_state_lock); + if (observe_identity) { + profile_service_observe_identity_on_storage_core( + observed_identity); + } +} + +void record_ble_identity(hci_con_handle_t connection_handle, + const bd_addr_t connection_address, + uint8_t identity_address_type, + const bd_addr_t identity_address) { + BleIdentityMapping* mapping = + reserve_ble_identity_mapping(connection_handle); + if (mapping == nullptr) { + return; + } + *mapping = {}; + mapping->used = true; + mapping->connection_handle = connection_handle; + memcpy(mapping->connection_address, connection_address, + sizeof(mapping->connection_address)); + mapping->identity_address_type = identity_address_type; + memcpy(mapping->identity_address, identity_address, + sizeof(mapping->identity_address)); + publish_ble_identity(*mapping); +} + +void clear_ble_identity_for_handle(hci_con_handle_t connection_handle) { + for (BleIdentityMapping& mapping : g_ble_identity_mappings) { + if (mapping.used && + mapping.connection_handle == connection_handle) { + mapping = {}; + } + } + + critical_section_enter_blocking(&g_state_lock); + for (BackendSlot& slot : g_slots) { + if (slot.device != nullptr && + slot.device->conn.protocol == UNI_BT_CONN_PROTOCOL_BLE && + slot.device->conn.handle == connection_handle) { + slot.identity = controller_identity_global(); + } + } + critical_section_exit(&g_state_lock); +} + +void clear_ble_identity_for_device(const uni_hid_device_t* device) { + if (device == nullptr || + device->conn.protocol != UNI_BT_CONN_PROTOCOL_BLE) { + return; + } + for (BleIdentityMapping& mapping : g_ble_identity_mappings) { + if (mapping.used && + mapping.connection_handle == device->conn.handle && + addresses_equal(mapping.connection_address, + device->conn.btaddr)) { + mapping = {}; + } + } +} + +void connection_address_for_handle(hci_con_handle_t connection_handle, + const bd_addr_t fallback, + bd_addr_t output) { + const uni_hid_device_t* device = + uni_hid_device_get_instance_for_connection_handle( + connection_handle); + if (device != nullptr) { + memcpy(output, device->conn.btaddr, sizeof(bd_addr_t)); + return; + } + const BleIdentityMapping* mapping = + find_ble_identity_mapping_for_handle(connection_handle); + if (mapping != nullptr) { + memcpy(output, mapping->connection_address, sizeof(bd_addr_t)); + return; + } + memcpy(output, fallback, sizeof(bd_addr_t)); +} + void apply_slot_lighting(uint8_t slot_index, uni_hid_device_t* device) { const SwitchRgbColor color = switch_pro_get_slot_light_color(slot_index); @@ -249,6 +444,7 @@ void publish_all_neutral() { critical_section_enter_blocking(&g_state_lock); for (BackendSlot& slot : g_slots) { slot.state = make_neutral_state(); + slot.identity = controller_identity_global(); slot.device = nullptr; slot.active = false; slot.rumble_pending = false; @@ -256,6 +452,9 @@ void publish_all_neutral() { ++slot.connection_generation; } critical_section_exit(&g_state_lock); + for (BleIdentityMapping& mapping : g_ble_identity_mappings) { + mapping = {}; + } g_connection_status = ConnectionStatus::Initializing; g_connection_policy_state = ConnectionPolicyState::FailedClosed; g_pairing_window_open = false; @@ -498,18 +697,101 @@ bool pairing_window_active_at(uint32_t now_ms) { static_cast(now_ms - g_pairing_window_deadline_ms) < 0; } -void handle_pairing_hci_event(uint8_t packet_type, uint16_t channel, - uint8_t* packet, uint16_t size) { +void handle_btstack_event(uint8_t packet_type, uint16_t channel, + uint8_t* packet, uint16_t size) { (void)channel; - if (packet_type != HCI_EVENT_PACKET || packet == nullptr || size < 8) { + if (packet_type != HCI_EVENT_PACKET || packet == nullptr || size < 2) { return; } bd_addr_t address{}; + bd_addr_t identity_address{}; + bd_addr_t connection_address{}; + hci_con_handle_t connection_handle = 0; const bool pairing_open = pairing_window_active_at(btstack_run_loop_get_time_ms()); switch (hci_event_packet_get_type(packet)) { + case SM_EVENT_IDENTITY_RESOLVING_STARTED: + if (size >= 11) { + clear_ble_identity_for_handle( + sm_event_identity_resolving_started_get_handle(packet)); + } + break; + case SM_EVENT_IDENTITY_RESOLVING_FAILED: + if (size >= 11) { + clear_ble_identity_for_handle( + sm_event_identity_resolving_failed_get_handle(packet)); + } + break; + case SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED: + if (size >= 20) { + connection_handle = + sm_event_identity_resolving_succeeded_get_handle(packet); + sm_event_identity_resolving_succeeded_get_address( + packet, connection_address); + sm_event_identity_resolving_succeeded_get_identity_address( + packet, identity_address); + record_ble_identity( + connection_handle, connection_address, + sm_event_identity_resolving_succeeded_get_identity_addr_type( + packet), + identity_address); + } + break; + case SM_EVENT_IDENTITY_CREATED: + if (size >= 20) { + connection_handle = + sm_event_identity_created_get_handle(packet); + sm_event_identity_created_get_address(packet, address); + sm_event_identity_created_get_identity_address( + packet, identity_address); + connection_address_for_handle( + connection_handle, address, connection_address); + record_ble_identity( + connection_handle, connection_address, + sm_event_identity_created_get_identity_addr_type(packet), + identity_address); + } + break; + case SM_EVENT_REENCRYPTION_STARTED: + if (size >= 11) { + connection_handle = + sm_event_reencryption_started_get_handle(packet); + sm_event_reencryption_started_get_address( + packet, identity_address); + connection_address_for_handle( + connection_handle, identity_address, + connection_address); + record_ble_identity( + connection_handle, connection_address, + sm_event_reencryption_started_get_addr_type(packet), + identity_address); + } + break; + case SM_EVENT_REENCRYPTION_COMPLETE: + if (size >= 12) { + connection_handle = + sm_event_reencryption_complete_get_handle(packet); + if (sm_event_reencryption_complete_get_status(packet) == + ERROR_CODE_SUCCESS) { + sm_event_reencryption_complete_get_address( + packet, identity_address); + connection_address_for_handle( + connection_handle, identity_address, + connection_address); + record_ble_identity( + connection_handle, connection_address, + sm_event_reencryption_complete_get_addr_type(packet), + identity_address); + } else { + clear_ble_identity_for_handle(connection_handle); + } + } + break; case HCI_EVENT_USER_CONFIRMATION_REQUEST: + if (size < 8) { + break; + } hci_event_user_confirmation_request_get_bd_addr(packet, address); if (pairing_open) { gap_ssp_confirmation_response(address); @@ -518,6 +800,9 @@ void handle_pairing_hci_event(uint8_t packet_type, uint16_t channel, } break; case HCI_EVENT_USER_PASSKEY_REQUEST: + if (size < 8) { + break; + } hci_event_user_passkey_request_get_bd_addr(packet, address); if (pairing_open) { gap_ssp_passkey_response(address, 0); @@ -634,6 +919,7 @@ void process_clear_pairings(uint32_t now_ms) { BackendSlot& slot = g_slots[slot_index]; devices[slot_index] = slot.device; slot.state = make_neutral_state(); + slot.identity = controller_identity_global(); slot.device = nullptr; slot.active = false; slot.rumble_pending = false; @@ -648,6 +934,9 @@ void process_clear_pairings(uint32_t now_ms) { if (!requested) { return; } + for (BleIdentityMapping& mapping : g_ble_identity_mappings) { + mapping = {}; + } g_pairing_window_open = false; gap_set_bondable_mode(false); @@ -733,8 +1022,9 @@ void update_status_led() { } void process_configuration_timer(btstack_timer_source_t* timer) { - configuration_service_task_on_storage_core( - btstack_run_loop_get_time_ms()); + const uint32_t now_ms = btstack_run_loop_get_time_ms(); + configuration_service_task_on_storage_core(now_ms); + profile_service_task_on_storage_core(now_ms); btstack_run_loop_set_timer(timer, kConfigurationPollIntervalMs); btstack_run_loop_add_timer(timer); } @@ -828,7 +1118,9 @@ void platform_on_init_complete() { gap_set_bondable_mode(false); sm_set_accepted_stk_generation_methods(0); gap_ssp_set_auto_accept(false); - g_pairing_event_callback.callback = handle_pairing_hci_event; + g_pairing_event_callback.callback = handle_btstack_event; + g_identity_event_callback.callback = handle_btstack_event; + sm_add_event_handler(&g_identity_event_callback); hci_add_event_handler(&g_pairing_event_callback); refresh_pairing_snapshot(); // Keep Bluepad32 autoconnect active whenever at least one slot is free. @@ -869,6 +1161,8 @@ void platform_on_device_connected(uni_hid_device_t* device) { if (slot_index < 0) { return; } + const ControllerIdentity connection_identity = + identity_for_device(device); bool tracked_connection = false; critical_section_enter_blocking(&g_state_lock); @@ -881,6 +1175,9 @@ void platform_on_device_connected(uni_hid_device_t* device) { } else { tracked_connection = slot.device == device; } + if (tracked_connection) { + slot.identity = connection_identity; + } critical_section_exit(&g_state_lock); if (tracked_connection) { @@ -898,18 +1195,18 @@ void platform_on_device_disconnected(uni_hid_device_t* device) { critical_section_enter_blocking(&g_state_lock); BackendSlot& slot = g_slots[slot_index]; if (slot.device == device) { - if (slot.active) { - slot.state = make_neutral_state(); - ++slot.state_generation; - } + slot.state = make_neutral_state(); + slot.identity = controller_identity_global(); slot.device = nullptr; slot.active = false; slot.rumble_pending = false; reset_slot_hotkeys(slot); + ++slot.state_generation; ++slot.connection_generation; disconnected_tracked_device = true; } critical_section_exit(&g_state_lock); + clear_ble_identity_for_device(device); if (disconnected_tracked_device) { // Re-evaluate from scratch: resume discovery only after the final @@ -929,6 +1226,8 @@ uni_error_t platform_on_device_ready(uni_hid_device_t* device) { if (slot_index < 0) { return UNI_ERROR_NO_SLOTS; } + const ControllerIdentity connection_identity = + identity_for_device(device); bool occupied_mismatch = false; bool became_active = false; @@ -936,6 +1235,7 @@ uni_error_t platform_on_device_ready(uni_hid_device_t* device) { BackendSlot& slot = g_slots[slot_index]; occupied_mismatch = slot.device != nullptr && slot.device != device; if (!occupied_mismatch) { + slot.identity = connection_identity; slot.device = device; if (!slot.active) { slot.state = make_neutral_state(); @@ -953,6 +1253,10 @@ uni_error_t platform_on_device_ready(uni_hid_device_t* device) { } if (became_active) { apply_slot_lighting(static_cast(slot_index), device); + if (connection_identity.stable) { + profile_service_observe_identity_on_storage_core( + connection_identity); + } } @@ -1021,6 +1325,7 @@ uni_platform* get_platform() { halt_wireless_backend(); } configuration_service_initialize_on_storage_core(); + profile_service_initialize_on_storage_core(); if (cyw43_arch_init() != 0) { halt_wireless_backend(); } @@ -1047,14 +1352,17 @@ void bluepad32_input_backend_init() { critical_section_init(&g_state_lock); configuration_service_prepare(); + profile_service_prepare(); for (uint8_t slot_index = 0; slot_index < kSlotCount; ++slot_index) { BackendSlot& slot = g_slots[slot_index]; slot = {}; slot.state = make_neutral_state(); + slot.identity = controller_identity_global(); slot.pending_rumble.slot = slot_index; reset_slot_hotkeys(slot); g_consumed_generation[slot_index] = 0; g_last_snapshot_generation[slot_index] = 0; + g_ble_identity_mappings[slot_index] = {}; } g_pairing_window_requested = false; g_pairing_snapshot_requested = false; @@ -1139,27 +1447,29 @@ void bluepad32_input_backend_pairing_snapshot( } -bool bluepad32_input_backend_snapshot(uint8_t slot_index, - ControllerState* out) { - if (out == nullptr || !valid_slot(slot_index)) { - return false; +void bluepad32_input_backend_snapshot(uint8_t slot_index, + Bluepad32SlotSnapshot* out) { + if (out == nullptr) { + return; } - if (!g_initialized) { - *out = make_neutral_state(); - return false; + *out = {}; + if (!valid_slot(slot_index) || !g_initialized) { + return; } critical_section_enter_blocking(&g_state_lock); - *out = g_slots[slot_index].state; - const bool controller_active = g_slots[slot_index].active; - const uint32_t generation = g_slots[slot_index].state_generation; + const BackendSlot& slot = g_slots[slot_index]; + out->active = slot.active; + out->connection_generation = slot.connection_generation; + out->identity = slot.identity; + out->state = slot.state; + const uint32_t state_generation = slot.state_generation; critical_section_exit(&g_state_lock); - if (generation == g_consumed_generation[slot_index]) { - out->motion_sample_count = 0; + if (state_generation == g_consumed_generation[slot_index]) { + out->state.motion_sample_count = 0; } - g_last_snapshot_generation[slot_index] = generation; - return controller_active; + g_last_snapshot_generation[slot_index] = state_generation; } void bluepad32_input_backend_report_sent(uint8_t slot_index) { diff --git a/bluepad32_input_backend.h b/bluepad32_input_backend.h index d7bdaa6..4d359b8 100644 --- a/bluepad32_input_backend.h +++ b/bluepad32_input_backend.h @@ -3,6 +3,7 @@ #include #include "controller_color.h" +#include "controller_identity.h" #include "controller_state.h" #include "switch_haptics.h" @@ -32,13 +33,21 @@ struct Bluepad32PairingSnapshot { bool overflow; Bluepad32PairingRecord records[BLUEPAD32_PAIRING_RECORD_CAPACITY]; }; +struct Bluepad32SlotSnapshot { + bool active; + uint32_t connection_generation; + ControllerIdentity identity; + ControllerState state; +}; + void bluepad32_input_backend_init(); void bluepad32_input_backend_start(); void bluepad32_input_backend_open_pairing_window(); void bluepad32_input_backend_clear_pairings(); -bool bluepad32_input_backend_snapshot(uint8_t slot, ControllerState* out); +void bluepad32_input_backend_snapshot(uint8_t slot, + Bluepad32SlotSnapshot* out); void bluepad32_input_backend_request_pairing_snapshot(); void bluepad32_input_backend_pairing_snapshot( Bluepad32PairingSnapshot* out); diff --git a/configuration_service.cpp b/configuration_service.cpp index e693947..d41199c 100644 --- a/configuration_service.cpp +++ b/configuration_service.cpp @@ -171,6 +171,10 @@ ConfigurationTransactionStatus configuration_service_reset( if (status == ConfigurationTransactionStatus::kReceiving) { status = g_transaction.finish(transaction_id); } + if (status == ConfigurationTransactionStatus::kPending && + g_snapshot.reset_generation != UINT32_MAX) { + ++g_snapshot.reset_generation; + } g_snapshot.transaction = g_transaction.snapshot(); critical_section_exit(&g_lock); return status; diff --git a/configuration_service.h b/configuration_service.h index 5a12709..9eb8ceb 100644 --- a/configuration_service.h +++ b/configuration_service.h @@ -17,6 +17,7 @@ struct ConfigurationServiceSnapshot { AdapterConfiguration configuration{}; uint32_t generation = 0; uint32_t payload_crc = 0; + uint32_t reset_generation = 0; ConfigurationTransactionSnapshot transaction{}; }; diff --git a/controller_identity.cpp b/controller_identity.cpp new file mode 100644 index 0000000..bfe32b3 --- /dev/null +++ b/controller_identity.cpp @@ -0,0 +1,82 @@ +#include "controller_identity.h" + +#include + +namespace { + +bool controller_identity_valid(const ControllerIdentity& identity) { + const uint8_t transport = static_cast(identity.transport); + if (transport > static_cast(ControllerTransport::kBle)) { + return false; + } + if (identity.stable) { + return identity.transport != ControllerTransport::kUnknown; + } + return controller_identity_is_global(identity); +} + +} // namespace + +ControllerIdentity controller_identity_global() { + return {}; +} + +bool controller_identity_is_global(const ControllerIdentity& identity) { + const ControllerIdentity global{}; + return controller_identity_equal(identity, global); +} + +bool controller_identity_equal(const ControllerIdentity& first, + const ControllerIdentity& second) { + return first.stable == second.stable && + first.transport == second.transport && + first.address_type == second.address_type && + memcmp(first.address, second.address, sizeof(first.address)) == 0 && + first.vendor_id == second.vendor_id && + first.product_id == second.product_id; +} + +bool controller_identity_encode(const ControllerIdentity& identity, + uint8_t* output, size_t output_size) { + if (output == nullptr || output_size < CONTROLLER_IDENTITY_ENCODED_SIZE || + !controller_identity_valid(identity)) { + return false; + } + + output[0] = identity.stable ? 1 : 0; + output[1] = static_cast(identity.transport); + output[2] = identity.address_type; + output[3] = 0; + memcpy(&output[4], identity.address, sizeof(identity.address)); + output[10] = static_cast(identity.vendor_id); + output[11] = static_cast(identity.vendor_id >> 8); + output[12] = static_cast(identity.product_id); + output[13] = static_cast(identity.product_id >> 8); + return true; +} + +bool controller_identity_decode(const uint8_t* input, size_t input_size, + ControllerIdentity* output) { + if (input == nullptr || output == nullptr || + input_size != CONTROLLER_IDENTITY_ENCODED_SIZE || input[0] > 1 || + input[1] > static_cast(ControllerTransport::kBle) || + input[3] != 0) { + return false; + } + + ControllerIdentity decoded{}; + decoded.stable = input[0] != 0; + decoded.transport = static_cast(input[1]); + decoded.address_type = input[2]; + memcpy(decoded.address, &input[4], sizeof(decoded.address)); + decoded.vendor_id = static_cast(input[10]) | + static_cast(input[11] << 8); + decoded.product_id = static_cast(input[12]) | + static_cast(input[13] << 8); + if (!controller_identity_valid(decoded)) { + return false; + } + + *output = decoded; + return true; +} diff --git a/controller_identity.h b/controller_identity.h new file mode 100644 index 0000000..c363991 --- /dev/null +++ b/controller_identity.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +constexpr size_t CONTROLLER_IDENTITY_ENCODED_SIZE = 14; + +enum class ControllerTransport : uint8_t { + kUnknown = 0, + kClassic = 1, + kBle = 2, +}; + +struct ControllerIdentity { + bool stable = false; + ControllerTransport transport = ControllerTransport::kUnknown; + uint8_t address_type = 0; + uint8_t address[6]{}; + uint16_t vendor_id = 0; + uint16_t product_id = 0; +}; + +ControllerIdentity controller_identity_global(); +bool controller_identity_is_global(const ControllerIdentity& identity); +bool controller_identity_equal(const ControllerIdentity& first, + const ControllerIdentity& second); +bool controller_identity_encode(const ControllerIdentity& identity, + uint8_t* output, size_t output_size); +bool controller_identity_decode(const uint8_t* input, size_t input_size, + ControllerIdentity* output); diff --git a/controller_profile.cpp b/controller_profile.cpp new file mode 100644 index 0000000..9b3c47f --- /dev/null +++ b/controller_profile.cpp @@ -0,0 +1,725 @@ +#include "controller_profile.h" + +#include + +namespace { + +constexpr uint8_t kDatabaseMagic[4] = {'S', 'P', 'D', 'B'}; +constexpr size_t kFallbackOffset = CONTROLLER_PROFILE_DATABASE_HEADER_SIZE; +constexpr size_t kEntriesOffset = + kFallbackOffset + CONTROLLER_PROFILE_COUNT * + CONTROLLER_PROFILE_ENCODED_SIZE; +constexpr uint8_t kStickInvertX = 1u << 0; +constexpr uint8_t kStickInvertY = 1u << 1; +constexpr uint8_t kMacroOverrideMask = + kControllerProfileOverrideButtons | + kControllerProfileOverrideLeftStick | + kControllerProfileOverrideRightStick | + kControllerProfileOverrideLeftTrigger | + kControllerProfileOverrideRightTrigger; + +uint16_t profile_read_u16(const uint8_t* input) { + return static_cast(input[0]) | + (static_cast(input[1]) << 8); +} + +int16_t profile_read_i16(const uint8_t* input) { + return static_cast(profile_read_u16(input)); +} + +void profile_write_u16(uint8_t* output, uint16_t value) { + output[0] = static_cast(value); + output[1] = static_cast(value >> 8); +} + +void profile_write_i16(uint8_t* output, int16_t value) { + profile_write_u16(output, static_cast(value)); +} + +bool profile_bytes_are_zero(const uint8_t* data, size_t size) { + for (size_t index = 0; index < size; ++index) { + if (data[index] != 0) { + return false; + } + } + return true; +} + +bool valid_button(uint8_t button) { + return button < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT || + button == CONTROLLER_PROFILE_NO_BUTTON; +} + +bool valid_macro_step(const ControllerProfileMacroStep& step, + bool must_end) { + if (must_end) { + return step.type == ControllerProfileMacroStepType::kEnd && + step.override_flags == 0 && step.duration_ms == 0 && + step.output_button_mask == 0 && step.left_stick_x == 0 && + step.left_stick_y == 0 && step.right_stick_x == 0 && + step.right_stick_y == 0 && step.left_trigger == 0 && + step.right_trigger == 0; + } + if (step.type != ControllerProfileMacroStepType::kState || + (step.override_flags & ~kMacroOverrideMask) != 0 || + step.duration_ms > CONTROLLER_PROFILE_MAX_WAIT_MS) { + return false; + } + if ((step.override_flags & kControllerProfileOverrideButtons) == 0 && + step.output_button_mask != 0) { + return false; + } + if ((step.override_flags & kControllerProfileOverrideLeftStick) == 0 && + (step.left_stick_x != 0 || step.left_stick_y != 0)) { + return false; + } + if ((step.override_flags & kControllerProfileOverrideRightStick) == 0 && + (step.right_stick_x != 0 || step.right_stick_y != 0)) { + return false; + } + if ((step.override_flags & kControllerProfileOverrideLeftTrigger) == 0 && + step.left_trigger != 0) { + return false; + } + if ((step.override_flags & kControllerProfileOverrideRightTrigger) == 0 && + step.right_trigger != 0) { + return false; + } + return true; +} + +void copy_overlap(size_t range_offset, uint8_t* output, + size_t output_size, size_t field_offset, + const uint8_t* field, size_t field_size) { + const size_t range_end = range_offset + output_size; + const size_t field_end = field_offset + field_size; + if (range_offset >= field_end || field_offset >= range_end) { + return; + } + const size_t start = range_offset > field_offset + ? range_offset + : field_offset; + const size_t end = range_end < field_end ? range_end : field_end; + memcpy(&output[start - range_offset], &field[start - field_offset], + end - start); +} + +bool read_zero_region(ControllerProfileDatabaseRead read, void* context, + size_t offset, size_t size) { + uint8_t buffer[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + while (size != 0) { + const size_t chunk = size < sizeof(buffer) ? size : sizeof(buffer); + if (!read(context, offset, buffer, chunk) || + !profile_bytes_are_zero(buffer, chunk)) { + return false; + } + offset += chunk; + size -= chunk; + } + return true; +} + +} // namespace + +ControllerProfile controller_profile_default(const ControllerIdentity& identity, + uint8_t profile_index) { + (void)identity; + (void)profile_index; + ControllerProfile profile{}; + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; ++index) { + profile.button_map[index] = index; + profile.turbo_modes[index] = ControllerProfileTurboMode::kOff; + } + for (ControllerProfileStickConfiguration& stick : profile.sticks) { + stick.center_x = 0; + stick.center_y = 0; + stick.inner_deadzone = 0; + stick.outer_saturation = 32767; + stick.curve_q8_8 = 256; + stick.invert_x = false; + stick.invert_y = false; + } + for (ControllerProfileTriggerConfiguration& trigger : profile.triggers) { + trigger.lower_deadzone = 0; + trigger.upper_saturation = UINT16_MAX; + trigger.curve_q8_8 = 256; + trigger.digital_threshold = 0x8000; + } + profile.weak_rumble_scale = UINT8_MAX; + profile.strong_rumble_scale = UINT8_MAX; + profile.confirmation_policy = + ControllerProfileConfirmationPolicy::kRumbleAndLed; + profile.switching_chord = 0; + profile.macro_trigger = CONTROLLER_PROFILE_NO_BUTTON; + profile.macro_cancel = CONTROLLER_PROFILE_NO_BUTTON; + profile.macro_step_count = 1; + for (ControllerProfileMacroStep& step : profile.macro_steps) { + step = {}; + step.type = ControllerProfileMacroStepType::kEnd; + } + return profile; +} + +bool controller_profile_validate(const ControllerProfile& profile) { + for (uint8_t output : profile.button_map) { + if (!valid_button(output)) { + return false; + } + } + for (const ControllerProfileStickConfiguration& stick : profile.sticks) { + if (stick.inner_deadzone >= stick.outer_saturation || + stick.outer_saturation > 32767 || stick.curve_q8_8 == 0) { + return false; + } + } + for (const ControllerProfileTriggerConfiguration& trigger : + profile.triggers) { + if (trigger.lower_deadzone >= trigger.upper_saturation || + trigger.curve_q8_8 == 0 || + trigger.digital_threshold < trigger.lower_deadzone || + trigger.digital_threshold > trigger.upper_saturation) { + return false; + } + } + if (static_cast(profile.confirmation_policy) > + static_cast( + ControllerProfileConfirmationPolicy::kRumbleAndLed) || + !valid_button(profile.macro_trigger) || + !valid_button(profile.macro_cancel) || + profile.macro_step_count == 0 || + profile.macro_step_count > CONTROLLER_PROFILE_MACRO_STEP_CAPACITY) { + return false; + } + for (ControllerProfileTurboMode mode : profile.turbo_modes) { + if (static_cast(mode) > + static_cast(ControllerProfileTurboMode::kAutoBurst)) { + return false; + } + } + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_MACRO_STEP_CAPACITY; ++index) { + const bool must_end = index >= profile.macro_step_count - 1; + if (!valid_macro_step(profile.macro_steps[index], must_end)) { + return false; + } + } + return true; +} + +bool controller_profile_encode(const ControllerProfile& profile, + uint8_t* output, size_t output_size) { + if (output == nullptr || output_size != CONTROLLER_PROFILE_ENCODED_SIZE || + !controller_profile_validate(profile)) { + return false; + } + memset(output, 0, output_size); + profile_write_u16(&output[0], CONTROLLER_PROFILE_SCHEMA_VERSION); + profile_write_u16(&output[2], CONTROLLER_PROFILE_ENCODED_SIZE); + memcpy(&output[4], profile.button_map, + CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT); + for (uint8_t index = 0; index < 2; ++index) { + const ControllerProfileStickConfiguration& stick = + profile.sticks[index]; + uint8_t* encoded = &output[20 + index * 16]; + profile_write_i16(&encoded[0], stick.center_x); + profile_write_i16(&encoded[2], stick.center_y); + profile_write_u16(&encoded[4], stick.inner_deadzone); + profile_write_u16(&encoded[6], stick.outer_saturation); + profile_write_u16(&encoded[8], stick.curve_q8_8); + encoded[10] = (stick.invert_x ? kStickInvertX : 0) | + (stick.invert_y ? kStickInvertY : 0); + } + for (uint8_t index = 0; index < 2; ++index) { + const ControllerProfileTriggerConfiguration& trigger = + profile.triggers[index]; + uint8_t* encoded = &output[52 + index * 10]; + profile_write_u16(&encoded[0], trigger.lower_deadzone); + profile_write_u16(&encoded[2], trigger.upper_saturation); + profile_write_u16(&encoded[4], trigger.curve_q8_8); + profile_write_u16(&encoded[6], trigger.digital_threshold); + } + output[72] = profile.weak_rumble_scale; + output[73] = profile.strong_rumble_scale; + output[74] = static_cast(profile.confirmation_policy); + profile_write_u16(&output[76], profile.switching_chord); + output[78] = profile.macro_trigger; + output[79] = profile.macro_cancel; + output[80] = profile.macro_step_count; + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; ++index) { + output[82 + index] = + static_cast(profile.turbo_modes[index]); + } + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_MACRO_STEP_CAPACITY; ++index) { + const ControllerProfileMacroStep& step = profile.macro_steps[index]; + uint8_t* encoded = &output[100 + index * 19]; + encoded[0] = static_cast(step.type); + encoded[1] = step.override_flags; + profile_write_u16(&encoded[2], step.duration_ms); + profile_write_u16(&encoded[4], step.output_button_mask); + profile_write_i16(&encoded[6], step.left_stick_x); + profile_write_i16(&encoded[8], step.left_stick_y); + profile_write_i16(&encoded[10], step.right_stick_x); + profile_write_i16(&encoded[12], step.right_stick_y); + profile_write_u16(&encoded[14], step.left_trigger); + profile_write_u16(&encoded[16], step.right_trigger); + } + return true; +} + +bool controller_profile_decode(const uint8_t* input, size_t input_size, + ControllerProfile* output) { + if (input == nullptr || output == nullptr || + input_size != CONTROLLER_PROFILE_ENCODED_SIZE || + profile_read_u16(&input[0]) != CONTROLLER_PROFILE_SCHEMA_VERSION || + profile_read_u16(&input[2]) != CONTROLLER_PROFILE_ENCODED_SIZE || + !profile_bytes_are_zero(&input[31], 5) || !profile_bytes_are_zero(&input[47], 5) || + !profile_bytes_are_zero(&input[60], 2) || !profile_bytes_are_zero(&input[70], 2) || + input[75] != 0 || input[81] != 0 || + !profile_bytes_are_zero(&input[98], 2) || !profile_bytes_are_zero(&input[252], 4)) { + return false; + } + + ControllerProfile profile{}; + memcpy(profile.button_map, &input[4], + CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT); + for (uint8_t index = 0; index < 2; ++index) { + ControllerProfileStickConfiguration& stick = profile.sticks[index]; + const uint8_t* encoded = &input[20 + index * 16]; + if ((encoded[10] & ~(kStickInvertX | kStickInvertY)) != 0) { + return false; + } + stick.center_x = profile_read_i16(&encoded[0]); + stick.center_y = profile_read_i16(&encoded[2]); + stick.inner_deadzone = profile_read_u16(&encoded[4]); + stick.outer_saturation = profile_read_u16(&encoded[6]); + stick.curve_q8_8 = profile_read_u16(&encoded[8]); + stick.invert_x = (encoded[10] & kStickInvertX) != 0; + stick.invert_y = (encoded[10] & kStickInvertY) != 0; + } + for (uint8_t index = 0; index < 2; ++index) { + ControllerProfileTriggerConfiguration& trigger = + profile.triggers[index]; + const uint8_t* encoded = &input[52 + index * 10]; + trigger.lower_deadzone = profile_read_u16(&encoded[0]); + trigger.upper_saturation = profile_read_u16(&encoded[2]); + trigger.curve_q8_8 = profile_read_u16(&encoded[4]); + trigger.digital_threshold = profile_read_u16(&encoded[6]); + } + profile.weak_rumble_scale = input[72]; + profile.strong_rumble_scale = input[73]; + profile.confirmation_policy = + static_cast(input[74]); + profile.switching_chord = profile_read_u16(&input[76]); + profile.macro_trigger = input[78]; + profile.macro_cancel = input[79]; + profile.macro_step_count = input[80]; + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; ++index) { + profile.turbo_modes[index] = + static_cast(input[82 + index]); + } + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_MACRO_STEP_CAPACITY; ++index) { + ControllerProfileMacroStep& step = profile.macro_steps[index]; + const uint8_t* encoded = &input[100 + index * 19]; + if (encoded[18] != 0) { + return false; + } + step.type = static_cast(encoded[0]); + step.override_flags = encoded[1]; + step.duration_ms = profile_read_u16(&encoded[2]); + step.output_button_mask = profile_read_u16(&encoded[4]); + step.left_stick_x = profile_read_i16(&encoded[6]); + step.left_stick_y = profile_read_i16(&encoded[8]); + step.right_stick_x = profile_read_i16(&encoded[10]); + step.right_stick_y = profile_read_i16(&encoded[12]); + step.left_trigger = profile_read_u16(&encoded[14]); + step.right_trigger = profile_read_u16(&encoded[16]); + } + if (!controller_profile_validate(profile)) { + return false; + } + *output = profile; + return true; +} + +void controller_profile_database_default(ControllerProfileDatabase* database) { + if (database == nullptr) { + return; + } + database->fallback_active_profile = 0; + const ControllerIdentity global = controller_identity_global(); + for (ControllerProfileDatabaseEntry& entry : database->entries) { + entry.used = false; + entry.identity = global; + entry.active_profile = 0; + } + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + database->fallback_profiles[profile_index] = + controller_profile_default(global, profile_index); + } +} + +bool controller_profile_database_validate( + const ControllerProfileDatabase& database) { + if (database.fallback_active_profile >= CONTROLLER_PROFILE_COUNT) { + return false; + } + for (const ControllerProfile& profile : database.fallback_profiles) { + if (!controller_profile_validate(profile)) { + return false; + } + } + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY; ++index) { + const ControllerProfileDatabaseEntry& entry = database.entries[index]; + if (!entry.used) { + continue; + } + if (!entry.identity.stable || + controller_identity_is_global(entry.identity) || + entry.active_profile >= CONTROLLER_PROFILE_COUNT) { + return false; + } + for (uint8_t prior = 0; prior < index; ++prior) { + if (database.entries[prior].used && + controller_identity_equal(database.entries[prior].identity, + entry.identity)) { + return false; + } + } + for (const ControllerProfile& profile : entry.profiles) { + if (!controller_profile_validate(profile)) { + return false; + } + } + } + return true; +} + +bool controller_profile_database_encode_range( + const ControllerProfileDatabase& database, size_t offset, + uint8_t* output, size_t size) { + if (output == nullptr || offset > CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE || + size > CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset || + !controller_profile_database_validate(database)) { + return false; + } + memset(output, 0, size); + uint8_t header[CONTROLLER_PROFILE_DATABASE_HEADER_SIZE]{}; + memcpy(header, kDatabaseMagic, sizeof(kDatabaseMagic)); + profile_write_u16(&header[4], + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION); + profile_write_u16(&header[6], CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE); + header[8] = CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY; + header[9] = CONTROLLER_PROFILE_COUNT; + header[10] = database.fallback_active_profile; + uint8_t used_count = 0; + for (const ControllerProfileDatabaseEntry& entry : database.entries) { + used_count += entry.used ? 1 : 0; + } + header[11] = used_count; + copy_overlap(offset, output, size, 0, header, sizeof(header)); + + uint8_t encoded_profile[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const size_t profile_offset = + kFallbackOffset + + profile_index * CONTROLLER_PROFILE_ENCODED_SIZE; + if (offset < profile_offset + CONTROLLER_PROFILE_ENCODED_SIZE && + offset + size > profile_offset) { + if (!controller_profile_encode( + database.fallback_profiles[profile_index], + encoded_profile, sizeof(encoded_profile))) { + return false; + } + copy_overlap(offset, output, size, profile_offset, + encoded_profile, sizeof(encoded_profile)); + } + } + + for (uint8_t entry_index = 0; + entry_index < CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY; + ++entry_index) { + const ControllerProfileDatabaseEntry& entry = + database.entries[entry_index]; + if (!entry.used) { + continue; + } + const size_t entry_offset = + kEntriesOffset + entry_index * CONTROLLER_PROFILE_DATABASE_ENTRY_SIZE; + uint8_t entry_header[CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE]{}; + if (!controller_identity_encode(entry.identity, entry_header, + CONTROLLER_IDENTITY_ENCODED_SIZE)) { + return false; + } + entry_header[14] = entry.active_profile; + entry_header[15] = 1; + copy_overlap(offset, output, size, entry_offset, entry_header, + sizeof(entry_header)); + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const size_t profile_offset = + entry_offset + CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE + + profile_index * CONTROLLER_PROFILE_ENCODED_SIZE; + if (offset < profile_offset + CONTROLLER_PROFILE_ENCODED_SIZE && + offset + size > profile_offset) { + if (!controller_profile_encode(entry.profiles[profile_index], + encoded_profile, + sizeof(encoded_profile))) { + return false; + } + copy_overlap(offset, output, size, profile_offset, + encoded_profile, sizeof(encoded_profile)); + } + } + } + return true; +} + +bool controller_profile_database_decode( + ControllerProfileDatabaseRead read, void* context, + ControllerProfileDatabase* output) { + if (read == nullptr || output == nullptr) { + return false; + } + uint8_t header[CONTROLLER_PROFILE_DATABASE_HEADER_SIZE]{}; + if (!read(context, 0, header, sizeof(header)) || + memcmp(header, kDatabaseMagic, sizeof(kDatabaseMagic)) != 0 || + profile_read_u16(&header[4]) != + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION || + profile_read_u16(&header[6]) != CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE || + header[8] != CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY || + header[9] != CONTROLLER_PROFILE_COUNT || + header[10] >= CONTROLLER_PROFILE_COUNT || + header[11] > CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY || + !profile_bytes_are_zero(&header[12], sizeof(header) - 12)) { + return false; + } + + controller_profile_database_default(output); + output->fallback_active_profile = header[10]; + uint8_t encoded_profile[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const size_t profile_offset = + kFallbackOffset + + profile_index * CONTROLLER_PROFILE_ENCODED_SIZE; + if (!read(context, profile_offset, encoded_profile, + sizeof(encoded_profile)) || + !controller_profile_decode( + encoded_profile, sizeof(encoded_profile), + &output->fallback_profiles[profile_index])) { + controller_profile_database_default(output); + return false; + } + } + + uint8_t decoded_used_count = 0; + for (uint8_t entry_index = 0; + entry_index < CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY; + ++entry_index) { + const size_t entry_offset = + kEntriesOffset + entry_index * CONTROLLER_PROFILE_DATABASE_ENTRY_SIZE; + uint8_t entry_header[CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE]{}; + if (!read(context, entry_offset, entry_header, + sizeof(entry_header))) { + controller_profile_database_default(output); + return false; + } + if (entry_header[15] == 0) { + if (!profile_bytes_are_zero(entry_header, sizeof(entry_header)) || + !read_zero_region( + read, context, + entry_offset + CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE, + CONTROLLER_PROFILE_COUNT * + CONTROLLER_PROFILE_ENCODED_SIZE)) { + controller_profile_database_default(output); + return false; + } + continue; + } + if (entry_header[15] != 1 || + entry_header[14] >= CONTROLLER_PROFILE_COUNT) { + controller_profile_database_default(output); + return false; + } + ControllerProfileDatabaseEntry& entry = output->entries[entry_index]; + if (!controller_identity_decode(entry_header, + CONTROLLER_IDENTITY_ENCODED_SIZE, + &entry.identity) || + !entry.identity.stable || + controller_identity_is_global(entry.identity)) { + controller_profile_database_default(output); + return false; + } + entry.used = true; + entry.active_profile = entry_header[14]; + ++decoded_used_count; + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const size_t profile_offset = + entry_offset + CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE + + profile_index * CONTROLLER_PROFILE_ENCODED_SIZE; + if (!read(context, profile_offset, encoded_profile, + sizeof(encoded_profile)) || + !controller_profile_decode(encoded_profile, + sizeof(encoded_profile), + &entry.profiles[profile_index])) { + controller_profile_database_default(output); + return false; + } + } + } + if (decoded_used_count != header[11] || + !controller_profile_database_validate(*output)) { + controller_profile_database_default(output); + return false; + } + return true; +} + +const ControllerProfileDatabaseEntry* controller_profile_database_find( + const ControllerProfileDatabase& database, + const ControllerIdentity& identity) { + if (!identity.stable || controller_identity_is_global(identity)) { + return nullptr; + } + for (const ControllerProfileDatabaseEntry& entry : database.entries) { + if (entry.used && + controller_identity_equal(entry.identity, identity)) { + return &entry; + } + } + return nullptr; +} + +ControllerProfileDatabaseEntry* controller_profile_database_find( + ControllerProfileDatabase* database, + const ControllerIdentity& identity) { + if (database == nullptr) { + return nullptr; + } + return const_cast( + controller_profile_database_find(*database, identity)); +} + +ControllerProfileDatabaseResult controller_profile_database_ensure( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + ControllerProfileDatabaseEntry** output) { + if (database == nullptr || output == nullptr || !identity.stable || + controller_identity_is_global(identity)) { + return ControllerProfileDatabaseResult::kInvalidArgument; + } + if (ControllerProfileDatabaseEntry* found = + controller_profile_database_find(database, identity)) { + *output = found; + return ControllerProfileDatabaseResult::kOk; + } + for (ControllerProfileDatabaseEntry& entry : database->entries) { + if (!entry.used) { + entry.active_profile = 0; + entry.used = true; + entry.identity = identity; + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + entry.profiles[profile_index] = + controller_profile_default(identity, profile_index); + } + *output = &entry; + return ControllerProfileDatabaseResult::kOk; + } + } + return ControllerProfileDatabaseResult::kFull; +} + +const ControllerProfile* controller_profile_database_get( + const ControllerProfileDatabase& database, + const ControllerIdentity& identity, uint8_t profile_index) { + if (profile_index >= CONTROLLER_PROFILE_COUNT) { + return nullptr; + } + if (controller_identity_is_global(identity)) { + return &database.fallback_profiles[profile_index]; + } + const ControllerProfileDatabaseEntry* entry = + controller_profile_database_find(database, identity); + return entry == nullptr ? nullptr : &entry->profiles[profile_index]; +} + +ControllerProfileDatabaseResult controller_profile_database_set( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + uint8_t profile_index, const ControllerProfile& profile) { + if (database == nullptr || profile_index >= CONTROLLER_PROFILE_COUNT || + !controller_profile_validate(profile)) { + return ControllerProfileDatabaseResult::kInvalidArgument; + } + if (controller_identity_is_global(identity)) { + database->fallback_profiles[profile_index] = profile; + return ControllerProfileDatabaseResult::kOk; + } + ControllerProfileDatabaseEntry* entry = nullptr; + const ControllerProfileDatabaseResult result = + controller_profile_database_ensure(database, identity, &entry); + if (result == ControllerProfileDatabaseResult::kOk) { + entry->profiles[profile_index] = profile; + } + return result; +} + +ControllerProfileDatabaseResult controller_profile_database_reset( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + uint8_t profile_index) { + if (database == nullptr || + (profile_index != CONTROLLER_PROFILE_ALL && + profile_index >= CONTROLLER_PROFILE_COUNT)) { + return ControllerProfileDatabaseResult::kInvalidArgument; + } + if (controller_identity_is_global(identity)) { + for (uint8_t index = 0; index < CONTROLLER_PROFILE_COUNT; ++index) { + if (profile_index == CONTROLLER_PROFILE_ALL || + profile_index == index) { + database->fallback_profiles[index] = + controller_profile_default(identity, index); + } + } + return ControllerProfileDatabaseResult::kOk; + } + ControllerProfileDatabaseEntry* entry = nullptr; + const ControllerProfileDatabaseResult result = + controller_profile_database_ensure(database, identity, &entry); + if (result != ControllerProfileDatabaseResult::kOk) { + return result; + } + for (uint8_t index = 0; index < CONTROLLER_PROFILE_COUNT; ++index) { + if (profile_index == CONTROLLER_PROFILE_ALL || + profile_index == index) { + entry->profiles[index] = controller_profile_default(identity, index); + } + } + return ControllerProfileDatabaseResult::kOk; +} + +ControllerProfileDatabaseResult controller_profile_database_activate( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + uint8_t profile_index) { + if (database == nullptr || profile_index >= CONTROLLER_PROFILE_COUNT) { + return ControllerProfileDatabaseResult::kInvalidArgument; + } + if (controller_identity_is_global(identity)) { + database->fallback_active_profile = profile_index; + return ControllerProfileDatabaseResult::kOk; + } + ControllerProfileDatabaseEntry* entry = nullptr; + const ControllerProfileDatabaseResult result = + controller_profile_database_ensure(database, identity, &entry); + if (result == ControllerProfileDatabaseResult::kOk) { + entry->active_profile = profile_index; + } + return result; +} diff --git a/controller_profile.h b/controller_profile.h new file mode 100644 index 0000000..14b30db --- /dev/null +++ b/controller_profile.h @@ -0,0 +1,191 @@ +#pragma once + +#include +#include + +#include "controller_identity.h" + +constexpr uint16_t CONTROLLER_PROFILE_SCHEMA_VERSION = 1; +constexpr size_t CONTROLLER_PROFILE_ENCODED_SIZE = 256; +constexpr uint8_t CONTROLLER_PROFILE_COUNT = 4; +constexpr uint8_t CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT = 16; +constexpr uint8_t CONTROLLER_PROFILE_MACRO_STEP_CAPACITY = 8; +constexpr uint16_t CONTROLLER_PROFILE_MAX_WAIT_MS = 10000; +constexpr uint8_t CONTROLLER_PROFILE_NO_BUTTON = 0xff; +constexpr uint8_t CONTROLLER_PROFILE_ALL = 0xff; + +constexpr uint8_t CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY = 16; +constexpr uint16_t CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION = 1; +constexpr size_t CONTROLLER_PROFILE_DATABASE_HEADER_SIZE = 32; +constexpr size_t CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE = 16; +constexpr size_t CONTROLLER_PROFILE_DATABASE_ENTRY_SIZE = + CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE + + CONTROLLER_PROFILE_COUNT * CONTROLLER_PROFILE_ENCODED_SIZE; +constexpr size_t CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE = + CONTROLLER_PROFILE_DATABASE_HEADER_SIZE + + CONTROLLER_PROFILE_COUNT * CONTROLLER_PROFILE_ENCODED_SIZE + + CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY * + CONTROLLER_PROFILE_DATABASE_ENTRY_SIZE; + +static_assert(CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE == 17696, + "profile database wire size changed"); +enum class ControllerProfileLogicalButton : uint8_t { + kSouth = 0, + kEast = 1, + kWest = 2, + kNorth = 3, + kLeftShoulder = 4, + kRightShoulder = 5, + kSelect = 6, + kStart = 7, + kSystem = 8, + kCapture = 9, + kLeftStick = 10, + kRightStick = 11, + kDpadUp = 12, + kDpadDown = 13, + kDpadLeft = 14, + kDpadRight = 15, +}; +static_assert( + static_cast(ControllerProfileLogicalButton::kDpadRight) + 1 == + CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT); + + +enum class ControllerProfileConfirmationPolicy : uint8_t { + kNone = 0, + kRumble = 1, + kLed = 2, + kRumbleAndLed = 3, +}; + +enum class ControllerProfileTurboMode : uint8_t { + kOff = 0, + kTurbo = 1, + kAutoBurst = 2, +}; + +enum class ControllerProfileMacroStepType : uint8_t { + kState = 0, + kEnd = 1, +}; + +enum ControllerProfileMacroOverride : uint8_t { + kControllerProfileOverrideButtons = 1u << 0, + kControllerProfileOverrideLeftStick = 1u << 1, + kControllerProfileOverrideRightStick = 1u << 2, + kControllerProfileOverrideLeftTrigger = 1u << 3, + kControllerProfileOverrideRightTrigger = 1u << 4, +}; + +struct ControllerProfileStickConfiguration { + int16_t center_x = 0; + int16_t center_y = 0; + uint16_t inner_deadzone = 0; + uint16_t outer_saturation = 32767; + uint16_t curve_q8_8 = 256; + bool invert_x = false; + bool invert_y = false; +}; + +struct ControllerProfileTriggerConfiguration { + uint16_t lower_deadzone = 0; + uint16_t upper_saturation = UINT16_MAX; + uint16_t curve_q8_8 = 256; + uint16_t digital_threshold = 0x8000; +}; + +struct ControllerProfileMacroStep { + ControllerProfileMacroStepType type = + ControllerProfileMacroStepType::kEnd; + uint8_t override_flags = 0; + uint16_t duration_ms = 0; + uint16_t output_button_mask = 0; + int16_t left_stick_x = 0; + int16_t left_stick_y = 0; + int16_t right_stick_x = 0; + int16_t right_stick_y = 0; + uint16_t left_trigger = 0; + uint16_t right_trigger = 0; +}; + +struct ControllerProfile { + uint8_t button_map[CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT]{}; + ControllerProfileStickConfiguration sticks[2]{}; + ControllerProfileTriggerConfiguration triggers[2]{}; + uint8_t weak_rumble_scale = UINT8_MAX; + uint8_t strong_rumble_scale = UINT8_MAX; + ControllerProfileConfirmationPolicy confirmation_policy = + ControllerProfileConfirmationPolicy::kRumbleAndLed; + uint16_t switching_chord = 0; + uint8_t macro_trigger = CONTROLLER_PROFILE_NO_BUTTON; + uint8_t macro_cancel = CONTROLLER_PROFILE_NO_BUTTON; + uint8_t macro_step_count = 1; + ControllerProfileTurboMode + turbo_modes[CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT]{}; + ControllerProfileMacroStep + macro_steps[CONTROLLER_PROFILE_MACRO_STEP_CAPACITY]{}; +}; + +struct ControllerProfileDatabaseEntry { + bool used = false; + ControllerIdentity identity{}; + uint8_t active_profile = 0; + ControllerProfile profiles[CONTROLLER_PROFILE_COUNT]{}; +}; + +struct ControllerProfileDatabase { + uint8_t fallback_active_profile = 0; + ControllerProfile fallback_profiles[CONTROLLER_PROFILE_COUNT]{}; + ControllerProfileDatabaseEntry + entries[CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY]{}; +}; + +enum class ControllerProfileDatabaseResult : uint8_t { + kOk = 0, + kInvalidArgument = 1, + kFull = 2, +}; + +using ControllerProfileDatabaseRead = bool (*)( + void* context, size_t offset, uint8_t* output, size_t size); + +ControllerProfile controller_profile_default(const ControllerIdentity& identity, + uint8_t profile_index); +bool controller_profile_validate(const ControllerProfile& profile); +bool controller_profile_encode(const ControllerProfile& profile, + uint8_t* output, size_t output_size); +bool controller_profile_decode(const uint8_t* input, size_t input_size, + ControllerProfile* output); + +void controller_profile_database_default(ControllerProfileDatabase* database); +bool controller_profile_database_validate( + const ControllerProfileDatabase& database); +bool controller_profile_database_encode_range( + const ControllerProfileDatabase& database, size_t offset, + uint8_t* output, size_t size); +bool controller_profile_database_decode( + ControllerProfileDatabaseRead read, void* context, + ControllerProfileDatabase* output); + +const ControllerProfileDatabaseEntry* controller_profile_database_find( + const ControllerProfileDatabase& database, + const ControllerIdentity& identity); +ControllerProfileDatabaseEntry* controller_profile_database_find( + ControllerProfileDatabase* database, + const ControllerIdentity& identity); +ControllerProfileDatabaseResult controller_profile_database_ensure( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + ControllerProfileDatabaseEntry** output); +const ControllerProfile* controller_profile_database_get( + const ControllerProfileDatabase& database, + const ControllerIdentity& identity, uint8_t profile_index); +ControllerProfileDatabaseResult controller_profile_database_set( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + uint8_t profile_index, const ControllerProfile& profile); +ControllerProfileDatabaseResult controller_profile_database_reset( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + uint8_t profile_index); +ControllerProfileDatabaseResult controller_profile_database_activate( + ControllerProfileDatabase* database, const ControllerIdentity& identity, + uint8_t profile_index); diff --git a/pico_profile_storage.cpp b/pico_profile_storage.cpp new file mode 100644 index 0000000..03bf425 --- /dev/null +++ b/pico_profile_storage.cpp @@ -0,0 +1,126 @@ +#include "pico_profile_storage.h" + +#include + +#include "configuration_storage.h" +#include "hardware/flash.h" +#include "pico/btstack_flash_bank.h" +#include "pico/flash.h" +#include "pico/platform.h" + +extern "C" char __flash_binary_end; + +namespace { + +constexpr size_t kConfigurationStorageSize = + CONFIGURATION_STORAGE_COPY_COUNT * FLASH_SECTOR_SIZE; +constexpr uint32_t kConfigurationStorageOffset = + PICO_FLASH_BANK_STORAGE_OFFSET - kConfigurationStorageSize; +constexpr uint32_t kProfileStorageOffset = + kConfigurationStorageOffset - PROFILE_STORAGE_TOTAL_SIZE; + +static_assert(FLASH_SECTOR_SIZE == PROFILE_STORAGE_SECTOR_SIZE, + "profile storage sector size does not match Pico flash"); +static_assert(FLASH_PAGE_SIZE == PROFILE_STORAGE_PAGE_SIZE, + "profile storage page size does not match Pico flash"); +static_assert(PICO_FLASH_BANK_STORAGE_OFFSET >= + kConfigurationStorageSize + PROFILE_STORAGE_TOTAL_SIZE, + "profile storage offset underflows flash"); +static_assert(kProfileStorageOffset + PROFILE_STORAGE_TOTAL_SIZE <= + kConfigurationStorageOffset, + "profile storage overlaps adapter configuration storage"); +static_assert(kConfigurationStorageOffset + kConfigurationStorageSize <= + PICO_FLASH_BANK_STORAGE_OFFSET, + "adapter configuration storage overlaps BTstack bonds"); +static_assert(PICO_FLASH_BANK_STORAGE_OFFSET + + PICO_FLASH_BANK_TOTAL_SIZE <= + PICO_FLASH_SIZE_BYTES, + "BTstack storage exceeds flash"); + +struct FlashMutation { + bool erase; + uint32_t offset; + const uint8_t* data; +}; + +void perform_flash_mutation(void* context) { + const auto* mutation = static_cast(context); + if (mutation->erase) { + flash_range_erase(mutation->offset, FLASH_SECTOR_SIZE); + } else { + flash_range_program(mutation->offset, mutation->data, + FLASH_PAGE_SIZE); + } +} + +bool storage_region_available() { + const uintptr_t binary_end = + reinterpret_cast(&__flash_binary_end) - XIP_BASE; + return binary_end <= kProfileStorageOffset; +} + +bool read_storage(void*, uint8_t bank, size_t offset, uint8_t* output, + size_t size) { + if (bank >= PROFILE_STORAGE_BANK_COUNT || output == nullptr || + offset > PROFILE_STORAGE_BANK_SIZE || + size > PROFILE_STORAGE_BANK_SIZE - offset || + !storage_region_available()) { + return false; + } + const uintptr_t address = + XIP_BASE + kProfileStorageOffset + + bank * PROFILE_STORAGE_BANK_SIZE + offset; + memcpy(output, reinterpret_cast(address), size); + return true; +} + +bool erase_storage_sector(void*, uint8_t bank, size_t offset) { + if (bank >= PROFILE_STORAGE_BANK_COUNT || + offset % FLASH_SECTOR_SIZE != 0 || + offset > PROFILE_STORAGE_BANK_SIZE || + FLASH_SECTOR_SIZE > PROFILE_STORAGE_BANK_SIZE - offset || + !storage_region_available()) { + return false; + } + FlashMutation mutation{ + true, + static_cast( + kProfileStorageOffset + bank * PROFILE_STORAGE_BANK_SIZE + offset), + nullptr, + }; + return flash_safe_execute(perform_flash_mutation, &mutation, + UINT32_MAX) == PICO_OK; +} + +bool program_storage(void*, uint8_t bank, size_t offset, + const uint8_t* data, size_t size) { + if (bank >= PROFILE_STORAGE_BANK_COUNT || data == nullptr || + size != FLASH_PAGE_SIZE || offset % FLASH_PAGE_SIZE != 0 || + offset > PROFILE_STORAGE_BANK_SIZE || + size > PROFILE_STORAGE_BANK_SIZE - offset || + !storage_region_available()) { + return false; + } + FlashMutation mutation{ + false, + static_cast( + kProfileStorageOffset + bank * PROFILE_STORAGE_BANK_SIZE + offset), + data, + }; + return flash_safe_execute(perform_flash_mutation, &mutation, + UINT32_MAX) == PICO_OK; +} + +} // namespace + +ProfileStorageIo pico_profile_storage_io() { + return { + nullptr, + PROFILE_STORAGE_BANK_SIZE, + FLASH_SECTOR_SIZE, + FLASH_PAGE_SIZE, + read_storage, + erase_storage_sector, + program_storage, + }; +} diff --git a/pico_profile_storage.h b/pico_profile_storage.h new file mode 100644 index 0000000..3fd8b42 --- /dev/null +++ b/pico_profile_storage.h @@ -0,0 +1,5 @@ +#pragma once + +#include "profile_storage.h" + +ProfileStorageIo pico_profile_storage_io(); diff --git a/profile_service.cpp b/profile_service.cpp new file mode 100644 index 0000000..f646b38 --- /dev/null +++ b/profile_service.cpp @@ -0,0 +1,548 @@ +#include "profile_service.h" + +#include + +#include "pico/critical_section.h" +#include "pico_profile_storage.h" +#include "profile_storage.h" + +namespace { + +constexpr uint32_t kMinimumCommitIntervalMs = 1000; + +enum class PendingCommandType : uint8_t { + kNone = 0, + kReset = 1, + kActivate = 2, +}; + +struct PendingCommand { + PendingCommandType type = PendingCommandType::kNone; + ControllerIdentity identity{}; + uint8_t profile_index = 0; +}; + +struct ProfileTransaction { + ControllerIdentity identity{}; + uint8_t profile_index = 0; + ConfigurationTransactionSnapshot snapshot{}; + uint8_t payload[CONTROLLER_PROFILE_ENCODED_SIZE]{}; +}; + +critical_section_t g_lock; +bool g_prepared = false; +ProfileStorage g_storage; +ControllerProfileDatabase g_database; +ProfileServiceMetadata g_metadata; +ProfileServiceListSnapshot g_list; +ProfileServiceSelectedSnapshot g_selected; +ProfileTransaction g_transaction; +PendingCommand g_command; +bool g_identity_dirty = false; +bool g_has_committed = false; +uint32_t g_last_commit_ms = 0; + +bool valid_identity(const ControllerIdentity& identity) { + uint8_t encoded[CONTROLLER_IDENTITY_ENCODED_SIZE]{}; + return (controller_identity_is_global(identity) || identity.stable) && + controller_identity_encode(identity, encoded, sizeof(encoded)); +} + +void refresh_list_locked() { + g_list = {}; + g_list.metadata = g_metadata; + g_list.count = 1; + g_list.rows[0].identity = controller_identity_global(); + g_list.rows[0].active_profile = + g_database.fallback_active_profile; + for (const ControllerProfileDatabaseEntry& entry : g_database.entries) { + if (!entry.used || g_list.count >= PROFILE_SERVICE_LIST_CAPACITY) { + continue; + } + ProfileServiceListRow& row = g_list.rows[g_list.count++]; + row.identity = entry.identity; + row.active_profile = entry.active_profile; + } +} + +void refresh_selected_locked() { + g_selected.metadata = g_metadata; + const ControllerProfile* profile = controller_profile_database_get( + g_database, g_selected.identity, g_selected.profile_index); + if (profile == nullptr) { + g_selected.valid = false; + g_selected.status = ConfigurationTransactionStatus::kMalformed; + return; + } + g_selected.profile = *profile; + g_selected.valid = true; + g_selected.status = ConfigurationTransactionStatus::kCommitted; +} + +void refresh_metadata_locked(ProfileServiceState state) { + const ProfileStorageSnapshot& stored = g_storage.snapshot(); + g_metadata.state = state; + g_metadata.generation = stored.valid ? stored.generation : 0; + g_metadata.payload_crc = stored.valid ? stored.payload_crc : 0; + refresh_list_locked(); + refresh_selected_locked(); +} + +ConfigurationTransactionStatus database_result_status( + ControllerProfileDatabaseResult result) { + switch (result) { + case ControllerProfileDatabaseResult::kOk: + return ConfigurationTransactionStatus::kPending; + case ControllerProfileDatabaseResult::kFull: + return ConfigurationTransactionStatus::kTooLarge; + case ControllerProfileDatabaseResult::kInvalidArgument: + return ConfigurationTransactionStatus::kMalformed; + } + return ConfigurationTransactionStatus::kStorageError; +} + +bool mutation_ready(uint32_t now_ms) { + return !g_has_committed || + static_cast(now_ms - g_last_commit_ms) >= + kMinimumCommitIntervalMs; +} + +void finish_mutation(ConfigurationTransactionStatus status, + bool clear_command) { + const ProfileStorageSnapshot& stored = g_storage.snapshot(); + critical_section_enter_blocking(&g_lock); + g_transaction.snapshot.status = status; + g_transaction.snapshot.stored_generation = + stored.valid ? stored.generation : 0; + g_transaction.snapshot.stored_crc = + stored.valid ? stored.payload_crc : 0; + if (clear_command) { + g_command = {}; + } + refresh_metadata_locked( + status == ConfigurationTransactionStatus::kStorageError + ? ProfileServiceState::kStorageError + : ProfileServiceState::kReady); + critical_section_exit(&g_lock); +} + +} // namespace + +void profile_service_prepare() { + if (g_prepared) { + return; + } + critical_section_init(&g_lock); + g_metadata = {}; + g_list = {}; + g_selected = {}; + g_selected.identity = controller_identity_global(); + g_selected.profile_index = 0; + g_transaction = {}; + g_command = {}; + g_identity_dirty = false; + g_has_committed = false; + g_last_commit_ms = 0; + g_prepared = true; +} + +void profile_service_initialize_on_storage_core() { + if (!g_prepared) { + profile_service_prepare(); + } + const bool initialized = + g_storage.initialize(pico_profile_storage_io(), &g_database); + critical_section_enter_blocking(&g_lock); + refresh_metadata_locked(initialized ? ProfileServiceState::kReady + : ProfileServiceState::kStorageError); + critical_section_exit(&g_lock); +} + +bool profile_service_observe_identity_on_storage_core( + const ControllerIdentity& identity) { + if (!g_prepared || !identity.stable || + controller_identity_is_global(identity) || + !valid_identity(identity)) { + return false; + } + critical_section_enter_blocking(&g_lock); + if (g_metadata.state != ProfileServiceState::kReady) { + critical_section_exit(&g_lock); + return false; + } + ControllerProfileDatabaseEntry* entry = + controller_profile_database_find(&g_database, identity); + if (entry != nullptr) { + critical_section_exit(&g_lock); + return true; + } + const ControllerProfileDatabaseResult result = + controller_profile_database_ensure(&g_database, identity, &entry); + if (result == ControllerProfileDatabaseResult::kOk) { + g_identity_dirty = true; + refresh_list_locked(); + } + critical_section_exit(&g_lock); + return result == ControllerProfileDatabaseResult::kOk; +} + + +void profile_service_task_on_storage_core(uint32_t now_ms) { + PendingCommand command{}; + bool process_write = false; + bool process_identity = false; + ControllerIdentity write_identity{}; + uint8_t write_profile_index = 0; + uint8_t write_payload[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + + critical_section_enter_blocking(&g_lock); + if (mutation_ready(now_ms)) { + if (g_command.type != PendingCommandType::kNone) { + command = g_command; + } else if (g_transaction.snapshot.status == + ConfigurationTransactionStatus::kPending) { + process_write = true; + write_identity = g_transaction.identity; + write_profile_index = g_transaction.profile_index; + memcpy(write_payload, g_transaction.payload, + sizeof(write_payload)); + } else if (g_identity_dirty) { + process_identity = true; + } + } + critical_section_exit(&g_lock); + + if (!process_write && !process_identity && + command.type == PendingCommandType::kNone) { + return; + } + + ControllerProfileDatabaseResult database_result = + ControllerProfileDatabaseResult::kInvalidArgument; + if (process_identity) { + database_result = ControllerProfileDatabaseResult::kOk; + } else if (process_write) { + ControllerProfile profile{}; + if (controller_profile_decode(write_payload, sizeof(write_payload), + &profile)) { + critical_section_enter_blocking(&g_lock); + database_result = controller_profile_database_set( + &g_database, write_identity, write_profile_index, profile); + critical_section_exit(&g_lock); + } + } else if (command.type == PendingCommandType::kReset) { + critical_section_enter_blocking(&g_lock); + database_result = controller_profile_database_reset( + &g_database, command.identity, command.profile_index); + critical_section_exit(&g_lock); + } else if (command.type == PendingCommandType::kActivate) { + critical_section_enter_blocking(&g_lock); + database_result = controller_profile_database_activate( + &g_database, command.identity, command.profile_index); + critical_section_exit(&g_lock); + } + + if (database_result != ControllerProfileDatabaseResult::kOk) { + finish_mutation(database_result_status(database_result), + !process_write); + return; + } + + const ProfileStorageResult storage_result = g_storage.commit(g_database); + ConfigurationTransactionStatus status = + ConfigurationTransactionStatus::kStorageError; + if (storage_result == ProfileStorageResult::kOk) { + status = ConfigurationTransactionStatus::kCommitted; + g_has_committed = true; + g_last_commit_ms = now_ms; + } else if (storage_result == ProfileStorageResult::kUnchanged) { + status = ConfigurationTransactionStatus::kUnchanged; + } else { + critical_section_enter_blocking(&g_lock); + const bool restored = + g_storage.initialize(pico_profile_storage_io(), &g_database); + critical_section_exit(&g_lock); + if (!restored) { + status = ConfigurationTransactionStatus::kStorageError; + } + } + if (process_identity) { + critical_section_enter_blocking(&g_lock); + g_identity_dirty = false; + refresh_metadata_locked( + status == ConfigurationTransactionStatus::kStorageError + ? ProfileServiceState::kStorageError + : ProfileServiceState::kReady); + critical_section_exit(&g_lock); + return; + } + critical_section_enter_blocking(&g_lock); + g_identity_dirty = false; + critical_section_exit(&g_lock); + finish_mutation(status, !process_write); +} + +ConfigurationTransactionStatus profile_service_select( + const ControllerIdentity& identity, uint8_t profile_index) { + if (!g_prepared) { + profile_service_prepare(); + } + critical_section_enter_blocking(&g_lock); + ConfigurationTransactionStatus status = + ConfigurationTransactionStatus::kCommitted; + if (!valid_identity(identity) || + profile_index >= CONTROLLER_PROFILE_COUNT) { + status = ConfigurationTransactionStatus::kMalformed; + g_selected.metadata = g_metadata; + g_selected.identity = identity; + g_selected.profile_index = profile_index; + g_selected.valid = false; + g_selected.status = status; + } else if (g_metadata.state != ProfileServiceState::kReady) { + status = g_metadata.state == ProfileServiceState::kLoading + ? ConfigurationTransactionStatus::kPending + : ConfigurationTransactionStatus::kStorageError; + g_selected.metadata = g_metadata; + g_selected.identity = identity; + g_selected.profile_index = profile_index; + g_selected.valid = false; + g_selected.status = status; + } else { + g_selected.identity = identity; + g_selected.profile_index = profile_index; + refresh_selected_locked(); + status = g_selected.status; + } + critical_section_exit(&g_lock); + return status; +} + +ConfigurationTransactionStatus profile_service_begin( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index, uint16_t schema_version, size_t payload_size, + uint32_t payload_crc) { + if (!g_prepared) { + profile_service_prepare(); + } + critical_section_enter_blocking(&g_lock); + if (g_command.type != PendingCommandType::kNone || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kReceiving || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kPending) { + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kBusy; + } + g_transaction = {}; + g_transaction.snapshot.transaction_id = transaction_id; + g_transaction.identity = identity; + g_transaction.profile_index = profile_index; + if (transaction_id == 0 || !valid_identity(identity) || + profile_index >= CONTROLLER_PROFILE_COUNT || payload_size == 0) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kMalformed; + } else if (schema_version != CONTROLLER_PROFILE_SCHEMA_VERSION) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kUnsupportedSchema; + } else if (payload_size > CONTROLLER_PROFILE_ENCODED_SIZE) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kTooLarge; + } else if (payload_size != CONTROLLER_PROFILE_ENCODED_SIZE) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kMalformed; + } else { + g_transaction.snapshot.expected_size = + static_cast(payload_size); + g_transaction.snapshot.expected_crc = payload_crc; + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kReceiving; + } + const ConfigurationTransactionStatus status = + g_transaction.snapshot.status; + critical_section_exit(&g_lock); + return status; +} + +ConfigurationTransactionStatus profile_service_append( + uint32_t transaction_id, size_t offset, const uint8_t* data, + size_t size) { + critical_section_enter_blocking(&g_lock); + if (g_transaction.snapshot.status != + ConfigurationTransactionStatus::kReceiving) { + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kBusy; + } + if (transaction_id != g_transaction.snapshot.transaction_id || + data == nullptr || size == 0 || + offset != g_transaction.snapshot.received_size || + offset > g_transaction.snapshot.expected_size || + size > g_transaction.snapshot.expected_size - offset) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kOutOfOrder; + } else { + memcpy(&g_transaction.payload[offset], data, size); + g_transaction.snapshot.received_size = + static_cast(offset + size); + } + const ConfigurationTransactionStatus status = + g_transaction.snapshot.status; + critical_section_exit(&g_lock); + return status; +} + +ConfigurationTransactionStatus profile_service_commit( + uint32_t transaction_id) { + critical_section_enter_blocking(&g_lock); + if (g_transaction.snapshot.status != + ConfigurationTransactionStatus::kReceiving || + transaction_id != g_transaction.snapshot.transaction_id || + g_transaction.snapshot.received_size != + g_transaction.snapshot.expected_size) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kOutOfOrder; + } else if (profile_storage_crc32( + g_transaction.payload, + g_transaction.snapshot.expected_size) != + g_transaction.snapshot.expected_crc) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kBadCrc; + } else { + ControllerProfile profile{}; + g_transaction.snapshot.status = + controller_profile_decode( + g_transaction.payload, + g_transaction.snapshot.expected_size, &profile) + ? ConfigurationTransactionStatus::kPending + : ConfigurationTransactionStatus::kMalformed; + } + const ConfigurationTransactionStatus status = + g_transaction.snapshot.status; + critical_section_exit(&g_lock); + return status; +} + +ConfigurationTransactionStatus profile_service_reset( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index) { + if (!g_prepared) { + profile_service_prepare(); + } + critical_section_enter_blocking(&g_lock); + if (g_command.type != PendingCommandType::kNone || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kReceiving || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kPending) { + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kBusy; + } + g_transaction = {}; + g_transaction.snapshot.transaction_id = transaction_id; + g_transaction.identity = identity; + g_transaction.profile_index = profile_index; + if (transaction_id == 0 || !valid_identity(identity) || + (profile_index != CONTROLLER_PROFILE_ALL && + profile_index >= CONTROLLER_PROFILE_COUNT)) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kMalformed; + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kMalformed; + } + g_transaction.snapshot.status = ConfigurationTransactionStatus::kPending; + g_command.type = PendingCommandType::kReset; + g_command.identity = identity; + g_command.profile_index = profile_index; + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kPending; +} + +ConfigurationTransactionStatus profile_service_activate( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index) { + if (!g_prepared) { + profile_service_prepare(); + } + critical_section_enter_blocking(&g_lock); + if (g_command.type != PendingCommandType::kNone || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kReceiving || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kPending) { + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kBusy; + } + g_transaction = {}; + g_transaction.snapshot.transaction_id = transaction_id; + g_transaction.identity = identity; + g_transaction.profile_index = profile_index; + if (transaction_id == 0 || !valid_identity(identity) || + profile_index >= CONTROLLER_PROFILE_COUNT) { + g_transaction.snapshot.status = + ConfigurationTransactionStatus::kMalformed; + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kMalformed; + } + g_transaction.snapshot.status = ConfigurationTransactionStatus::kPending; + g_command.type = PendingCommandType::kActivate; + g_command.identity = identity; + g_command.profile_index = profile_index; + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kPending; +} + +void profile_service_list_snapshot(ProfileServiceListSnapshot* output) { + if (output == nullptr) { + return; + } + critical_section_enter_blocking(&g_lock); + *output = g_list; + critical_section_exit(&g_lock); +} + +void profile_service_selected_snapshot( + ProfileServiceSelectedSnapshot* output) { + if (output == nullptr) { + return; + } + critical_section_enter_blocking(&g_lock); + *output = g_selected; + critical_section_exit(&g_lock); +} + +void profile_service_transaction_snapshot( + ProfileServiceTransactionSnapshot* output) { + if (output == nullptr) { + return; + } + critical_section_enter_blocking(&g_lock); + output->metadata = g_metadata; + output->identity = g_transaction.identity; + output->profile_index = g_transaction.profile_index; + output->transaction = g_transaction.snapshot; + critical_section_exit(&g_lock); +} + +bool profile_service_active_profile(const ControllerIdentity& identity, + ControllerProfile* output, + uint8_t* profile_index) { + if (output == nullptr || profile_index == nullptr || + !valid_identity(identity)) { + return false; + } + critical_section_enter_blocking(&g_lock); + if (g_metadata.state != ProfileServiceState::kReady) { + critical_section_exit(&g_lock); + return false; + } + const ControllerProfileDatabaseEntry* entry = + controller_profile_database_find(g_database, identity); + if (entry != nullptr) { + *profile_index = entry->active_profile; + *output = entry->profiles[entry->active_profile]; + } else { + *profile_index = g_database.fallback_active_profile; + *output = g_database.fallback_profiles[*profile_index]; + } + critical_section_exit(&g_lock); + return true; +} diff --git a/profile_service.h b/profile_service.h new file mode 100644 index 0000000..b96b04a --- /dev/null +++ b/profile_service.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +#include "configuration_transaction.h" +#include "controller_profile.h" + +constexpr uint8_t PROFILE_SERVICE_LIST_CAPACITY = + CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY + 1; + +enum class ProfileServiceState : uint8_t { + kLoading = 0, + kReady = 1, + kStorageError = 2, +}; + +struct ProfileServiceMetadata { + ProfileServiceState state = ProfileServiceState::kLoading; + uint32_t generation = 0; + uint32_t payload_crc = 0; +}; + +struct ProfileServiceListRow { + ControllerIdentity identity{}; + uint8_t active_profile = 0; +}; + +struct ProfileServiceListSnapshot { + ProfileServiceMetadata metadata{}; + uint8_t count = 0; + ProfileServiceListRow rows[PROFILE_SERVICE_LIST_CAPACITY]{}; +}; + +struct ProfileServiceSelectedSnapshot { + ProfileServiceMetadata metadata{}; + bool valid = false; + ConfigurationTransactionStatus status = + ConfigurationTransactionStatus::kIdle; + ControllerIdentity identity{}; + uint8_t profile_index = 0; + ControllerProfile profile{}; +}; + +struct ProfileServiceTransactionSnapshot { + ProfileServiceMetadata metadata{}; + ControllerIdentity identity{}; + uint8_t profile_index = 0; + ConfigurationTransactionSnapshot transaction{}; +}; + +void profile_service_prepare(); +void profile_service_initialize_on_storage_core(); +void profile_service_task_on_storage_core(uint32_t now_ms); +bool profile_service_observe_identity_on_storage_core( + const ControllerIdentity& identity); + +ConfigurationTransactionStatus profile_service_select( + const ControllerIdentity& identity, uint8_t profile_index); +ConfigurationTransactionStatus profile_service_begin( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index, uint16_t schema_version, size_t payload_size, + uint32_t payload_crc); +ConfigurationTransactionStatus profile_service_append( + uint32_t transaction_id, size_t offset, const uint8_t* data, + size_t size); +ConfigurationTransactionStatus profile_service_commit( + uint32_t transaction_id); +ConfigurationTransactionStatus profile_service_reset( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index); +ConfigurationTransactionStatus profile_service_activate( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index); + +void profile_service_list_snapshot(ProfileServiceListSnapshot* output); +void profile_service_selected_snapshot( + ProfileServiceSelectedSnapshot* output); +void profile_service_transaction_snapshot( + ProfileServiceTransactionSnapshot* output); +bool profile_service_active_profile(const ControllerIdentity& identity, + ControllerProfile* output, + uint8_t* profile_index); diff --git a/profile_storage.cpp b/profile_storage.cpp new file mode 100644 index 0000000..14af5ab --- /dev/null +++ b/profile_storage.cpp @@ -0,0 +1,301 @@ +#include "profile_storage.h" + +#include + +namespace { + +constexpr uint8_t kRecordMagic[4] = {'S', 'P', 'P', 'F'}; +constexpr uint16_t kRecordFormatVersion = 1; +constexpr size_t kHeaderFieldsSize = 24; +constexpr size_t kHeaderCrcOffset = 20; + +uint16_t storage_read_u16(const uint8_t* input) { + return static_cast(input[0]) | + (static_cast(input[1]) << 8); +} + +uint32_t storage_read_u32(const uint8_t* input) { + return static_cast(input[0]) | + (static_cast(input[1]) << 8) | + (static_cast(input[2]) << 16) | + (static_cast(input[3]) << 24); +} + +void storage_write_u16(uint8_t* output, uint16_t value) { + output[0] = static_cast(value); + output[1] = static_cast(value >> 8); +} + +void storage_write_u32(uint8_t* output, uint32_t value) { + output[0] = static_cast(value); + output[1] = static_cast(value >> 8); + output[2] = static_cast(value >> 16); + output[3] = static_cast(value >> 24); +} + +uint32_t crc32_update(uint32_t crc, const uint8_t* data, size_t size) { + for (size_t index = 0; index < size; ++index) { + crc ^= data[index]; + for (uint8_t bit = 0; bit < 8; ++bit) { + crc = (crc >> 1) ^ + (0xedb88320u & + static_cast( + -static_cast(crc & 1u))); + } + } + return crc; +} + +bool generation_is_newer(uint32_t candidate, uint32_t current) { + return static_cast(candidate - current) > 0; +} + +struct DatabaseReadContext { + const ProfileStorageIo* io; + uint8_t bank; +}; + +bool read_database(void* context, size_t offset, uint8_t* output, + size_t size) { + const auto* read_context = + static_cast(context); + return read_context->io->read( + read_context->io->context, read_context->bank, + PROFILE_STORAGE_RECORD_HEADER_SIZE + offset, output, size); +} + +} // namespace + +uint32_t profile_storage_crc32(const uint8_t* data, size_t size) { + if (data == nullptr && size != 0) { + return 0; + } + return ~crc32_update(0xffffffffu, data, size); +} + +bool ProfileStorage::initialize(const ProfileStorageIo& io, + ControllerProfileDatabase* database) { + io_ = io; + snapshot_ = {}; + initialized_ = database != nullptr && io_.read != nullptr && + io_.erase_sector != nullptr && io_.program != nullptr && + io_.bank_size >= PROFILE_STORAGE_BANK_SIZE && + io_.sector_size == PROFILE_STORAGE_SECTOR_SIZE && + io_.page_size == PROFILE_STORAGE_PAGE_SIZE && + io_.bank_size % io_.sector_size == 0 && + io_.sector_size % io_.page_size == 0; + if (!initialized_) { + return false; + } + + controller_profile_database_default(database); + BankHeader headers[PROFILE_STORAGE_BANK_COUNT]{}; + bool valid[PROFILE_STORAGE_BANK_COUNT]{}; + for (uint8_t bank = 0; bank < PROFILE_STORAGE_BANK_COUNT; ++bank) { + valid[bank] = read_header(bank, &headers[bank]) && + validate_payload(bank, headers[bank].payload_crc); + } + + uint8_t first = 0; + uint8_t second = 1; + if (valid[1] && + (!valid[0] || generation_is_newer(headers[1].generation, + headers[0].generation))) { + first = 1; + second = 0; + } + const uint8_t order[PROFILE_STORAGE_BANK_COUNT] = {first, second}; + for (uint8_t candidate : order) { + if (!valid[candidate] || !decode_bank(candidate, database)) { + continue; + } + snapshot_.valid = true; + snapshot_.generation = headers[candidate].generation; + snapshot_.payload_crc = headers[candidate].payload_crc; + snapshot_.active_bank = candidate; + return true; + } + controller_profile_database_default(database); + return true; +} + +ProfileStorageResult ProfileStorage::commit( + const ControllerProfileDatabase& database) { + if (!initialized_ || !controller_profile_database_validate(database)) { + return ProfileStorageResult::kInvalidArgument; + } + if (snapshot_.valid && payload_matches(snapshot_.active_bank, database)) { + return ProfileStorageResult::kUnchanged; + } + + uint8_t page[PROFILE_STORAGE_PAGE_SIZE]{}; + uint32_t crc = 0xffffffffu; + for (size_t offset = 0; + offset < CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE; + offset += sizeof(page)) { + const size_t size = + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset < sizeof(page) + ? CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset + : sizeof(page); + if (!controller_profile_database_encode_range(database, offset, + page, size)) { + return ProfileStorageResult::kInvalidArgument; + } + crc = crc32_update(crc, page, size); + } + crc = ~crc; + + const uint8_t target_bank = snapshot_.valid + ? snapshot_.active_bank ^ 1u + : 0; + for (size_t offset = 0; offset < PROFILE_STORAGE_BANK_SIZE; + offset += PROFILE_STORAGE_SECTOR_SIZE) { + if (!io_.erase_sector(io_.context, target_bank, offset)) { + return ProfileStorageResult::kIoError; + } + } + + for (size_t offset = 0; + offset < CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE; + offset += sizeof(page)) { + memset(page, 0, sizeof(page)); + const size_t size = + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset < sizeof(page) + ? CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset + : sizeof(page); + if (!controller_profile_database_encode_range(database, offset, + page, size) || + !io_.program(io_.context, target_bank, + PROFILE_STORAGE_RECORD_HEADER_SIZE + offset, + page, sizeof(page))) { + return ProfileStorageResult::kIoError; + } + } + + uint8_t stored_page[PROFILE_STORAGE_PAGE_SIZE]{}; + uint32_t stored_crc = 0xffffffffu; + bool stored_payload_matches = true; + for (size_t offset = 0; + offset < CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE; + offset += sizeof(stored_page)) { + const size_t size = + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset < + sizeof(stored_page) + ? CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset + : sizeof(stored_page); + if (!io_.read(io_.context, target_bank, + PROFILE_STORAGE_RECORD_HEADER_SIZE + offset, + stored_page, size)) { + return ProfileStorageResult::kIoError; + } + if (!controller_profile_database_encode_range(database, offset, + page, size)) { + return ProfileStorageResult::kInvalidArgument; + } + for (size_t index = 0; index < size; ++index) { + stored_payload_matches &= + stored_page[index] == page[index]; + } + stored_crc = crc32_update(stored_crc, stored_page, size); + } + if (!stored_payload_matches || ~stored_crc != crc) { + return ProfileStorageResult::kIoError; + } + + memset(page, 0, sizeof(page)); + memcpy(page, kRecordMagic, sizeof(kRecordMagic)); + storage_write_u16(&page[4], kRecordFormatVersion); + storage_write_u16(&page[6], + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION); + const uint32_t generation = + snapshot_.valid ? snapshot_.generation + 1u : 1u; + storage_write_u32(&page[8], generation); + storage_write_u32(&page[12], + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE); + storage_write_u32(&page[16], crc); + storage_write_u32(&page[kHeaderCrcOffset], + profile_storage_crc32(page, kHeaderCrcOffset)); + if (!io_.program(io_.context, target_bank, 0, page, sizeof(page))) { + return ProfileStorageResult::kIoError; + } + + snapshot_.valid = true; + snapshot_.generation = generation; + snapshot_.payload_crc = crc; + snapshot_.active_bank = target_bank; + return ProfileStorageResult::kOk; +} + +const ProfileStorageSnapshot& ProfileStorage::snapshot() const { + return snapshot_; +} + +bool ProfileStorage::read_header(uint8_t bank, BankHeader* output) const { + uint8_t header[kHeaderFieldsSize]{}; + if (bank >= PROFILE_STORAGE_BANK_COUNT || output == nullptr || + !io_.read(io_.context, bank, 0, header, sizeof(header)) || + memcmp(header, kRecordMagic, sizeof(kRecordMagic)) != 0 || + storage_read_u16(&header[4]) != kRecordFormatVersion || + storage_read_u16(&header[6]) != + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION || + storage_read_u32(&header[12]) != + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE || + profile_storage_crc32(header, kHeaderCrcOffset) != + storage_read_u32(&header[kHeaderCrcOffset])) { + return false; + } + output->generation = storage_read_u32(&header[8]); + output->payload_crc = storage_read_u32(&header[16]); + return true; +} + +bool ProfileStorage::validate_payload(uint8_t bank, + uint32_t expected_crc) const { + uint8_t page[PROFILE_STORAGE_PAGE_SIZE]{}; + uint32_t crc = 0xffffffffu; + for (size_t offset = 0; + offset < CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE; + offset += sizeof(page)) { + const size_t size = + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset < sizeof(page) + ? CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset + : sizeof(page); + if (!io_.read(io_.context, bank, + PROFILE_STORAGE_RECORD_HEADER_SIZE + offset, + page, size)) { + return false; + } + crc = crc32_update(crc, page, size); + } + return ~crc == expected_crc; +} + +bool ProfileStorage::decode_bank( + uint8_t bank, ControllerProfileDatabase* database) const { + DatabaseReadContext context{&io_, bank}; + return controller_profile_database_decode(read_database, &context, + database); +} + +bool ProfileStorage::payload_matches( + uint8_t bank, const ControllerProfileDatabase& database) const { + uint8_t stored[PROFILE_STORAGE_PAGE_SIZE]{}; + uint8_t encoded[PROFILE_STORAGE_PAGE_SIZE]{}; + for (size_t offset = 0; + offset < CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE; + offset += sizeof(stored)) { + const size_t size = + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset < sizeof(stored) + ? CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE - offset + : sizeof(stored); + if (!io_.read(io_.context, bank, + PROFILE_STORAGE_RECORD_HEADER_SIZE + offset, + stored, size) || + !controller_profile_database_encode_range(database, offset, + encoded, size) || + memcmp(stored, encoded, size) != 0) { + return false; + } + } + return true; +} diff --git a/profile_storage.h b/profile_storage.h new file mode 100644 index 0000000..ec6d8fd --- /dev/null +++ b/profile_storage.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include + +#include "controller_profile.h" + +constexpr uint8_t PROFILE_STORAGE_BANK_COUNT = 2; +constexpr size_t PROFILE_STORAGE_SECTOR_SIZE = 4096; +constexpr size_t PROFILE_STORAGE_SECTORS_PER_BANK = 5; +constexpr size_t PROFILE_STORAGE_BANK_SIZE = + PROFILE_STORAGE_SECTOR_SIZE * PROFILE_STORAGE_SECTORS_PER_BANK; +constexpr size_t PROFILE_STORAGE_TOTAL_SIZE = + PROFILE_STORAGE_BANK_COUNT * PROFILE_STORAGE_BANK_SIZE; +constexpr size_t PROFILE_STORAGE_PAGE_SIZE = 256; +constexpr size_t PROFILE_STORAGE_RECORD_HEADER_SIZE = + PROFILE_STORAGE_PAGE_SIZE; + +static_assert(PROFILE_STORAGE_BANK_SIZE == 20 * 1024); +static_assert(PROFILE_STORAGE_TOTAL_SIZE == 40 * 1024); +static_assert(PROFILE_STORAGE_RECORD_HEADER_SIZE + + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE <= + PROFILE_STORAGE_BANK_SIZE, + "profile database does not fit a storage bank"); + +enum class ProfileStorageResult : uint8_t { + kOk = 0, + kUnchanged = 1, + kInvalidArgument = 2, + kIoError = 3, +}; + +struct ProfileStorageIo { + void* context = nullptr; + size_t bank_size = 0; + size_t sector_size = 0; + size_t page_size = 0; + bool (*read)(void* context, uint8_t bank, size_t offset, + uint8_t* output, size_t size) = nullptr; + bool (*erase_sector)(void* context, uint8_t bank, + size_t offset) = nullptr; + bool (*program)(void* context, uint8_t bank, size_t offset, + const uint8_t* data, size_t size) = nullptr; +}; + +struct ProfileStorageSnapshot { + bool valid = false; + uint32_t generation = 0; + uint32_t payload_crc = 0; + uint8_t active_bank = 0; +}; + +uint32_t profile_storage_crc32(const uint8_t* data, size_t size); + +class ProfileStorage { +public: + bool initialize(const ProfileStorageIo& io, + ControllerProfileDatabase* database); + ProfileStorageResult commit(const ControllerProfileDatabase& database); + const ProfileStorageSnapshot& snapshot() const; + +private: + struct BankHeader { + uint32_t generation = 0; + uint32_t payload_crc = 0; + }; + + bool read_header(uint8_t bank, BankHeader* output) const; + bool validate_payload(uint8_t bank, uint32_t expected_crc) const; + bool decode_bank(uint8_t bank, + ControllerProfileDatabase* database) const; + bool payload_matches(uint8_t bank, + const ControllerProfileDatabase& database) const; + + ProfileStorageIo io_{}; + ProfileStorageSnapshot snapshot_{}; + bool initialized_ = false; +}; diff --git a/src/switch_pico_bridge/config_manager.py b/src/switch_pico_bridge/config_manager.py index 3d7169d..8d5fcc3 100755 --- a/src/switch_pico_bridge/config_manager.py +++ b/src/switch_pico_bridge/config_manager.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 -"""Manage switch-pico persistent configuration and pairings over USB EP0.""" +"""Manage switch-pico persistent configuration, profiles, and pairings.""" from __future__ import annotations import argparse +import json import secrets import struct import sys @@ -11,6 +12,7 @@ import time import zlib from collections.abc import Iterable, Sequence from dataclasses import dataclass +from pathlib import Path from typing import Any, Protocol, cast import usb.core @@ -22,7 +24,7 @@ PROTOCOL_VERSION = 1 REQUEST_HEADER_SIZE = 16 RESPONSE_HEADER_SIZE = 20 MAXIMUM_REQUEST_SIZE = 64 -MAXIMUM_RESPONSE_SIZE = 152 +MAXIMUM_RESPONSE_SIZE = 293 MAXIMUM_CHUNK_SIZE = 40 USB_TIMEOUT_MS = 1000 @@ -36,6 +38,15 @@ OP_TRANSACTION_STATUS = 0x15 OP_PAIRING_READ = 0x20 OP_PAIRING_REFRESH = 0x21 OP_PAIRING_CLEAR = 0x22 +OP_PROFILE_LIST = 0x30 +OP_PROFILE_SELECT = 0x31 +OP_PROFILE_READ = 0x32 +OP_PROFILE_BEGIN = 0x33 +OP_PROFILE_CHUNK = 0x34 +OP_PROFILE_COMMIT = 0x35 +OP_PROFILE_RESET = 0x36 +OP_PROFILE_ACTIVATE = 0x37 +OP_PROFILE_TRANSACTION_STATUS = 0x38 STATUS_OK = 0 STATUS_PENDING = 1 @@ -55,8 +66,50 @@ PAIRING_WINDOW_SECONDS_MIN = 10 PAIRING_WINDOW_SECONDS_MAX = 300 PAIRING_RECORD_SIZE = 8 PAIRING_RECORD_CAPACITY = 16 +TRANSPORT_UNKNOWN = 0 TRANSPORT_CLASSIC = 1 TRANSPORT_BLE = 2 +PROFILE_SCHEMA_VERSION = 1 +PROFILE_SIZE = 256 +PROFILE_CAPACITY = 4 +PROFILE_IDENTITY_CAPACITY = 16 +PROFILE_LIST_CAPACITY = PROFILE_IDENTITY_CAPACITY + 1 +CONTROLLER_IDENTITY_SIZE = 14 +PROFILE_LIST_ROW_SIZE = 16 +PROFILE_NONE_BUTTON = 0xFF +PROFILE_MACRO_STEP_CAPACITY = 8 +PROFILE_MACRO_STEP_SIZE = 19 +PROFILE_MAXIMUM_WAIT_MS = 10000 + +LOGICAL_BUTTONS = ( + "south", + "east", + "west", + "north", + "left_shoulder", + "right_shoulder", + "select", + "start", + "system", + "capture", + "left_stick", + "right_stick", + "dpad_up", + "dpad_down", + "dpad_left", + "dpad_right", +) +RUMBLE_POLICIES = ("none", "rumble", "led", "rumble_and_led") +TURBO_MODES = ("off", "turbo", "auto_burst") +MACRO_STEP_TYPES = ("state", "end") +MACRO_OVERRIDE_NAMES = ( + "buttons", + "left_stick", + "right_stick", + "left_trigger", + "right_trigger", +) +MACRO_OVERRIDE_MASK = (1 << len(MACRO_OVERRIDE_NAMES)) - 1 class ConfigManagerError(RuntimeError): @@ -152,6 +205,934 @@ class PairingSnapshot: records: tuple[PairingRecord, ...] +def _require_int(value: Any, name: str, minimum: int, maximum: int) -> int: + if type(value) is not int or not minimum <= value <= maximum: + raise ConfigManagerError( + f"{name} must be an integer from {minimum} to {maximum}" + ) + return value + + +def _require_bool(value: Any, name: str) -> bool: + if type(value) is not bool: + raise ConfigManagerError(f"{name} must be true or false") + return value + + +def _require_object( + value: Any, fields: Sequence[str], name: str +) -> dict[str, Any]: + if type(value) is not dict: + raise ConfigManagerError(f"{name} must be a JSON object") + expected = set(fields) + actual = set(value) + missing = sorted(expected - actual) + unknown = sorted(actual - expected) + if missing or unknown: + details: list[str] = [] + if missing: + details.append("missing " + ", ".join(missing)) + if unknown: + details.append("unknown " + ", ".join(unknown)) + raise ConfigManagerError(f"invalid {name}: {'; '.join(details)}") + return value + + +def _require_enum(value: Any, choices: Sequence[str], name: str) -> int: + if type(value) is not str or value not in choices: + raise ConfigManagerError( + f"{name} must be one of {', '.join(choices)}" + ) + return choices.index(value) + + +def _button_index(value: Any, name: str) -> int: + if value is None: + return PROFILE_NONE_BUTTON + if type(value) is not str or value not in LOGICAL_BUTTONS: + raise ConfigManagerError( + f"{name} must be a logical button name or null" + ) + return LOGICAL_BUTTONS.index(value) + + +def _button_name(value: int) -> str | None: + if value == PROFILE_NONE_BUTTON: + return None + return LOGICAL_BUTTONS[value] + + +def _button_mask_from_json(value: Any, name: str) -> int: + if type(value) is not list: + raise ConfigManagerError(f"{name} must be a JSON array") + mask = 0 + for entry in value: + index = _button_index(entry, name) + if index == PROFILE_NONE_BUTTON: + raise ConfigManagerError(f"{name} cannot contain null") + bit = 1 << index + if mask & bit: + raise ConfigManagerError(f"{name} contains a duplicate button") + mask |= bit + return mask + + +def _button_mask_to_json(mask: int) -> list[str]: + return [ + name + for index, name in enumerate(LOGICAL_BUTTONS) + if mask & (1 << index) + ] + + +@dataclass(frozen=True) +class ControllerIdentity: + stable: bool + transport: int + address_type: int + address: bytes + vendor_id: int + product_id: int + + def __post_init__(self) -> None: + _require_bool(self.stable, "identity stable") + _require_int(self.transport, "identity transport", 0, 2) + _require_int(self.address_type, "identity address_type", 0, 0xFF) + if type(self.address) is not bytes or len(self.address) != 6: + raise ConfigManagerError("identity address must contain six bytes") + _require_int(self.vendor_id, "identity vendor_id", 0, 0xFFFF) + _require_int(self.product_id, "identity product_id", 0, 0xFFFF) + if self.stable: + if self.transport not in (TRANSPORT_CLASSIC, TRANSPORT_BLE): + raise ConfigManagerError( + "stable identity transport must be Classic or BLE" + ) + elif ( + self.transport != TRANSPORT_UNKNOWN + or self.address_type != 0 + or self.address != bytes(6) + or self.vendor_id != 0 + or self.product_id != 0 + ): + raise ConfigManagerError( + "unstable identity must be the all-zero global fallback" + ) + + @classmethod + def global_fallback(cls) -> ControllerIdentity: + return cls(False, TRANSPORT_UNKNOWN, 0, bytes(6), 0, 0) + + @classmethod + def from_bytes(cls, payload: bytes) -> ControllerIdentity: + payload = bytes(payload) + if len(payload) != CONTROLLER_IDENTITY_SIZE: + raise ConfigManagerError("invalid controller identity size") + stable, transport, address_type, reserved = payload[:4] + if stable not in (0, 1) or reserved != 0: + raise ConfigManagerError("invalid controller identity encoding") + vendor_id, product_id = struct.unpack_from(" bytes: + return ( + bytes( + [ + int(self.stable), + self.transport, + self.address_type, + 0, + ] + ) + + self.address + + struct.pack(" bool: + return not self.stable + + @property + def address_text(self) -> str: + return ":".join(f"{octet:02X}" for octet in self.address) + + @property + def transport_text(self) -> str: + if self.transport == TRANSPORT_CLASSIC: + return "Classic" + if self.transport == TRANSPORT_BLE: + return "BLE" + return "Unknown" + + +@dataclass(frozen=True) +class ProfileListEntry: + identity: ControllerIdentity + active_profile_index: int + + def __post_init__(self) -> None: + if not isinstance(self.identity, ControllerIdentity): + raise ConfigManagerError( + "profile-list identity must be a ControllerIdentity" + ) + _require_int( + self.active_profile_index, + "active profile index", + 0, + PROFILE_CAPACITY - 1, + ) + + +@dataclass(frozen=True) +class StickConfig: + center_x: int + center_y: int + inner_deadzone: int + outer_saturation: int + curve_q8_8: int + invert_x: bool + invert_y: bool + + def __post_init__(self) -> None: + _require_int(self.center_x, "stick center_x", -0x8000, 0x7FFF) + _require_int(self.center_y, "stick center_y", -0x8000, 0x7FFF) + _require_int( + self.inner_deadzone, "stick inner_deadzone", 0, 0x7FFF + ) + _require_int( + self.outer_saturation, "stick outer_saturation", 1, 0x7FFF + ) + if self.inner_deadzone >= self.outer_saturation: + raise ConfigManagerError( + "stick inner_deadzone must be below outer_saturation" + ) + _require_int(self.curve_q8_8, "stick curve_q8_8", 1, 0xFFFF) + _require_bool(self.invert_x, "stick invert_x") + _require_bool(self.invert_y, "stick invert_y") + + @classmethod + def from_bytes(cls, payload: bytes) -> StickConfig: + if len(payload) != 16 or payload[11:] != bytes(5): + raise ConfigManagerError("invalid stick configuration encoding") + center_x, center_y, inner, outer, curve_q8_8, flags = struct.unpack( + " bytes: + flags = int(self.invert_x) | (int(self.invert_y) << 1) + return struct.pack( + " dict[str, Any]: + return { + "center_x": self.center_x, + "center_y": self.center_y, + "inner_deadzone": self.inner_deadzone, + "outer_saturation": self.outer_saturation, + "curve_q8_8": self.curve_q8_8, + "invert_x": self.invert_x, + "invert_y": self.invert_y, + } + + @classmethod + def from_json_object(cls, value: Any, name: str) -> StickConfig: + fields = ( + "center_x", + "center_y", + "inner_deadzone", + "outer_saturation", + "curve_q8_8", + "invert_x", + "invert_y", + ) + obj = _require_object(value, fields, name) + return cls( + _require_int(obj["center_x"], f"{name}.center_x", -0x8000, 0x7FFF), + _require_int(obj["center_y"], f"{name}.center_y", -0x8000, 0x7FFF), + _require_int( + obj["inner_deadzone"], + f"{name}.inner_deadzone", + 0, + 0x7FFF, + ), + _require_int( + obj["outer_saturation"], + f"{name}.outer_saturation", + 1, + 0x7FFF, + ), + _require_int( + obj["curve_q8_8"], f"{name}.curve_q8_8", 1, 0xFFFF + ), + _require_bool(obj["invert_x"], f"{name}.invert_x"), + _require_bool(obj["invert_y"], f"{name}.invert_y"), + ) + + +@dataclass(frozen=True) +class TriggerConfig: + lower_deadzone: int + upper_saturation: int + curve_q8_8: int + digital_threshold: int + + def __post_init__(self) -> None: + _require_int( + self.lower_deadzone, "trigger lower_deadzone", 0, 0xFFFF + ) + _require_int( + self.upper_saturation, "trigger upper_saturation", 1, 0xFFFF + ) + if self.lower_deadzone >= self.upper_saturation: + raise ConfigManagerError( + "trigger lower_deadzone must be below upper_saturation" + ) + _require_int(self.curve_q8_8, "trigger curve_q8_8", 1, 0xFFFF) + _require_int( + self.digital_threshold, + "trigger digital_threshold", + self.lower_deadzone, + self.upper_saturation, + ) + + @classmethod + def from_bytes(cls, payload: bytes) -> TriggerConfig: + if len(payload) != 10 or payload[8:] != b"\x00\x00": + raise ConfigManagerError("invalid trigger configuration encoding") + return cls(*struct.unpack(" bytes: + return struct.pack( + " dict[str, int]: + return { + "lower_deadzone": self.lower_deadzone, + "upper_saturation": self.upper_saturation, + "curve_q8_8": self.curve_q8_8, + "digital_threshold": self.digital_threshold, + } + + @classmethod + def from_json_object(cls, value: Any, name: str) -> TriggerConfig: + fields = ( + "lower_deadzone", + "upper_saturation", + "curve_q8_8", + "digital_threshold", + ) + obj = _require_object(value, fields, name) + return cls( + _require_int( + obj["lower_deadzone"], + f"{name}.lower_deadzone", + 0, + 0xFFFF, + ), + _require_int( + obj["upper_saturation"], + f"{name}.upper_saturation", + 1, + 0xFFFF, + ), + _require_int( + obj["curve_q8_8"], f"{name}.curve_q8_8", 1, 0xFFFF + ), + _require_int( + obj["digital_threshold"], + f"{name}.digital_threshold", + 0, + 0xFFFF, + ), + ) + + +@dataclass(frozen=True) +class MacroStep: + step_type: int + override_flags: int + duration_ms: int + output_button_mask: int + left_stick_x: int + left_stick_y: int + right_stick_x: int + right_stick_y: int + left_trigger: int + right_trigger: int + + def __post_init__(self) -> None: + _require_int(self.step_type, "macro step type", 0, 1) + _require_int( + self.override_flags, "macro override flags", 0, MACRO_OVERRIDE_MASK + ) + _require_int( + self.duration_ms, + "macro duration_ms", + 0, + PROFILE_MAXIMUM_WAIT_MS, + ) + _require_int( + self.output_button_mask, "macro output button mask", 0, 0xFFFF + ) + for name in ( + "left_stick_x", + "left_stick_y", + "right_stick_x", + "right_stick_y", + ): + _require_int( + getattr(self, name), f"macro {name}", -0x8000, 0x7FFF + ) + _require_int(self.left_trigger, "macro left_trigger", 0, 0xFFFF) + _require_int(self.right_trigger, "macro right_trigger", 0, 0xFFFF) + if self.step_type == 1 and any( + ( + self.override_flags, + self.duration_ms, + self.output_button_mask, + self.left_stick_x, + self.left_stick_y, + self.right_stick_x, + self.right_stick_y, + self.left_trigger, + self.right_trigger, + ) + ): + raise ConfigManagerError("end macro step must otherwise be zero") + if self.step_type == 0: + if ( + not self.override_flags & 1 + and self.output_button_mask != 0 + ): + raise ConfigManagerError( + "macro buttons require the buttons override" + ) + if ( + not self.override_flags & 2 + and (self.left_stick_x != 0 or self.left_stick_y != 0) + ): + raise ConfigManagerError( + "macro left stick values require the left_stick override" + ) + if ( + not self.override_flags & 4 + and (self.right_stick_x != 0 or self.right_stick_y != 0) + ): + raise ConfigManagerError( + "macro right stick values require the right_stick override" + ) + if not self.override_flags & 8 and self.left_trigger != 0: + raise ConfigManagerError( + "macro left trigger requires the left_trigger override" + ) + if not self.override_flags & 16 and self.right_trigger != 0: + raise ConfigManagerError( + "macro right trigger requires the right_trigger override" + ) + + @classmethod + def end(cls) -> MacroStep: + return cls(1, 0, 0, 0, 0, 0, 0, 0, 0, 0) + + @classmethod + def from_bytes(cls, payload: bytes) -> MacroStep: + if len(payload) != PROFILE_MACRO_STEP_SIZE or payload[18] != 0: + raise ConfigManagerError("invalid macro step encoding") + return cls(*struct.unpack(" bytes: + return struct.pack( + " dict[str, Any]: + return { + "type": MACRO_STEP_TYPES[self.step_type], + "overrides": [ + name + for index, name in enumerate(MACRO_OVERRIDE_NAMES) + if self.override_flags & (1 << index) + ], + "duration_ms": self.duration_ms, + "output_buttons": _button_mask_to_json( + self.output_button_mask + ), + "left_stick": { + "x": self.left_stick_x, + "y": self.left_stick_y, + }, + "right_stick": { + "x": self.right_stick_x, + "y": self.right_stick_y, + }, + "triggers": { + "left": self.left_trigger, + "right": self.right_trigger, + }, + } + + @classmethod + def from_json_object(cls, value: Any, name: str) -> MacroStep: + fields = ( + "type", + "overrides", + "duration_ms", + "output_buttons", + "left_stick", + "right_stick", + "triggers", + ) + obj = _require_object(value, fields, name) + overrides = obj["overrides"] + if type(overrides) is not list: + raise ConfigManagerError(f"{name}.overrides must be a JSON array") + override_flags = 0 + for override in overrides: + index = _require_enum( + override, MACRO_OVERRIDE_NAMES, f"{name}.overrides" + ) + bit = 1 << index + if override_flags & bit: + raise ConfigManagerError( + f"{name}.overrides contains a duplicate" + ) + override_flags |= bit + left = _require_object( + obj["left_stick"], ("x", "y"), f"{name}.left_stick" + ) + right = _require_object( + obj["right_stick"], ("x", "y"), f"{name}.right_stick" + ) + triggers = _require_object( + obj["triggers"], ("left", "right"), f"{name}.triggers" + ) + return cls( + _require_enum(obj["type"], MACRO_STEP_TYPES, f"{name}.type"), + override_flags, + _require_int( + obj["duration_ms"], + f"{name}.duration_ms", + 0, + PROFILE_MAXIMUM_WAIT_MS, + ), + _button_mask_from_json( + obj["output_buttons"], f"{name}.output_buttons" + ), + _require_int( + left["x"], f"{name}.left_stick.x", -0x8000, 0x7FFF + ), + _require_int( + left["y"], f"{name}.left_stick.y", -0x8000, 0x7FFF + ), + _require_int( + right["x"], f"{name}.right_stick.x", -0x8000, 0x7FFF + ), + _require_int( + right["y"], f"{name}.right_stick.y", -0x8000, 0x7FFF + ), + _require_int( + triggers["left"], + f"{name}.triggers.left", + 0, + 0xFFFF, + ), + _require_int( + triggers["right"], + f"{name}.triggers.right", + 0, + 0xFFFF, + ), + ) + + +@dataclass(frozen=True) +class ControllerProfile: + button_map: tuple[int, ...] + left_stick: StickConfig + right_stick: StickConfig + left_trigger: TriggerConfig + right_trigger: TriggerConfig + weak_rumble_scale: int + strong_rumble_scale: int + confirmation_policy: int + switching_chord: int + macro_trigger: int + macro_cancel: int + macro_steps: tuple[MacroStep, ...] + turbo_modes: tuple[int, ...] + + def __post_init__(self) -> None: + if type(self.button_map) is not tuple or len(self.button_map) != len( + LOGICAL_BUTTONS + ): + raise ConfigManagerError( + "button map must contain 16 logical mappings" + ) + for mapping in self.button_map: + if type(mapping) is not int or ( + mapping != PROFILE_NONE_BUTTON + and not 0 <= mapping < len(LOGICAL_BUTTONS) + ): + raise ConfigManagerError("invalid logical button mapping") + if not isinstance(self.left_stick, StickConfig) or not isinstance( + self.right_stick, StickConfig + ): + raise ConfigManagerError("profile sticks must be StickConfig values") + if not isinstance(self.left_trigger, TriggerConfig) or not isinstance( + self.right_trigger, TriggerConfig + ): + raise ConfigManagerError( + "profile triggers must be TriggerConfig values" + ) + _require_int( + self.weak_rumble_scale, "weak rumble scale", 0, 0xFF + ) + _require_int( + self.strong_rumble_scale, "strong rumble scale", 0, 0xFF + ) + _require_int( + self.confirmation_policy, + "confirmation policy", + 0, + len(RUMBLE_POLICIES) - 1, + ) + _require_int(self.switching_chord, "switching chord", 0, 0xFFFF) + for value, name in ( + (self.macro_trigger, "macro trigger"), + (self.macro_cancel, "macro cancel"), + ): + if type(value) is not int or ( + value != PROFILE_NONE_BUTTON + and not 0 <= value < len(LOGICAL_BUTTONS) + ): + raise ConfigManagerError(f"invalid {name}") + if ( + type(self.macro_steps) is not tuple + or not 1 <= len(self.macro_steps) <= PROFILE_MACRO_STEP_CAPACITY + or not all(isinstance(step, MacroStep) for step in self.macro_steps) + ): + raise ConfigManagerError("macro must contain one to eight steps") + if any(step.step_type != 0 for step in self.macro_steps[:-1]): + raise ConfigManagerError("only the final macro step may be end") + if self.macro_steps[-1] != MacroStep.end(): + raise ConfigManagerError("final macro step must be canonical end") + if type(self.turbo_modes) is not tuple or len( + self.turbo_modes + ) != len(LOGICAL_BUTTONS): + raise ConfigManagerError("Turbo modes must contain 16 entries") + for mode in self.turbo_modes: + _require_int(mode, "Turbo mode", 0, len(TURBO_MODES) - 1) + + @classmethod + def default(cls) -> ControllerProfile: + stick = StickConfig(0, 0, 0, 0x7FFF, 256, False, False) + trigger = TriggerConfig(0, 0xFFFF, 256, 0x8000) + return cls( + button_map=tuple(range(len(LOGICAL_BUTTONS))), + left_stick=stick, + right_stick=stick, + left_trigger=trigger, + right_trigger=trigger, + weak_rumble_scale=0xFF, + strong_rumble_scale=0xFF, + confirmation_policy=3, + switching_chord=0, + macro_trigger=PROFILE_NONE_BUTTON, + macro_cancel=PROFILE_NONE_BUTTON, + macro_steps=(MacroStep.end(),), + turbo_modes=(0,) * len(LOGICAL_BUTTONS), + ) + + @classmethod + def from_bytes(cls, payload: bytes) -> ControllerProfile: + payload = bytes(payload) + if len(payload) != PROFILE_SIZE: + raise ConfigManagerError("invalid profile size") + version, size = struct.unpack_from(" bytes: + payload = bytearray(PROFILE_SIZE) + struct.pack_into( + " dict[str, Any]: + return { + "schema_version": PROFILE_SCHEMA_VERSION, + "size": PROFILE_SIZE, + "button_map": { + name: _button_name(self.button_map[index]) + for index, name in enumerate(LOGICAL_BUTTONS) + }, + "sticks": { + "left": self.left_stick.to_json_object(), + "right": self.right_stick.to_json_object(), + }, + "triggers": { + "left": self.left_trigger.to_json_object(), + "right": self.right_trigger.to_json_object(), + }, + "rumble": { + "weak_scale": self.weak_rumble_scale, + "strong_scale": self.strong_rumble_scale, + "confirmation_policy": RUMBLE_POLICIES[ + self.confirmation_policy + ], + }, + "switching_chord": _button_mask_to_json(self.switching_chord), + "macro": { + "trigger": _button_name(self.macro_trigger), + "cancel": _button_name(self.macro_cancel), + "steps": [ + step.to_json_object() for step in self.macro_steps + ], + }, + "turbo": { + name: TURBO_MODES[self.turbo_modes[index]] + for index, name in enumerate(LOGICAL_BUTTONS) + }, + } + + def to_json(self) -> str: + return json.dumps(self.to_json_object(), indent=2) + "\n" + + @classmethod + def from_json_object(cls, value: Any) -> ControllerProfile: + fields = ( + "schema_version", + "size", + "button_map", + "sticks", + "triggers", + "rumble", + "switching_chord", + "macro", + "turbo", + ) + obj = _require_object(value, fields, "profile") + if ( + _require_int( + obj["schema_version"], "profile.schema_version", 0, 0xFFFF + ) + != PROFILE_SCHEMA_VERSION + or _require_int(obj["size"], "profile.size", 0, 0xFFFF) + != PROFILE_SIZE + ): + raise ConfigManagerError("unsupported profile schema") + button_map = _require_object( + obj["button_map"], LOGICAL_BUTTONS, "profile.button_map" + ) + sticks = _require_object( + obj["sticks"], ("left", "right"), "profile.sticks" + ) + triggers = _require_object( + obj["triggers"], ("left", "right"), "profile.triggers" + ) + rumble = _require_object( + obj["rumble"], + ("weak_scale", "strong_scale", "confirmation_policy"), + "profile.rumble", + ) + macro = _require_object( + obj["macro"], ("trigger", "cancel", "steps"), "profile.macro" + ) + turbo = _require_object( + obj["turbo"], LOGICAL_BUTTONS, "profile.turbo" + ) + steps = macro["steps"] + if type(steps) is not list or not ( + 1 <= len(steps) <= PROFILE_MACRO_STEP_CAPACITY + ): + raise ConfigManagerError( + "profile.macro.steps must contain one to eight steps" + ) + return cls( + button_map=tuple( + _button_index( + button_map[name], f"profile.button_map.{name}" + ) + for name in LOGICAL_BUTTONS + ), + left_stick=StickConfig.from_json_object( + sticks["left"], "profile.sticks.left" + ), + right_stick=StickConfig.from_json_object( + sticks["right"], "profile.sticks.right" + ), + left_trigger=TriggerConfig.from_json_object( + triggers["left"], "profile.triggers.left" + ), + right_trigger=TriggerConfig.from_json_object( + triggers["right"], "profile.triggers.right" + ), + weak_rumble_scale=_require_int( + rumble["weak_scale"], + "profile.rumble.weak_scale", + 0, + 0xFF, + ), + strong_rumble_scale=_require_int( + rumble["strong_scale"], + "profile.rumble.strong_scale", + 0, + 0xFF, + ), + confirmation_policy=_require_enum( + rumble["confirmation_policy"], + RUMBLE_POLICIES, + "profile.rumble.confirmation_policy", + ), + switching_chord=_button_mask_from_json( + obj["switching_chord"], "profile.switching_chord" + ), + macro_trigger=_button_index( + macro["trigger"], "profile.macro.trigger" + ), + macro_cancel=_button_index( + macro["cancel"], "profile.macro.cancel" + ), + macro_steps=tuple( + MacroStep.from_json_object( + step, f"profile.macro.steps[{index}]" + ) + for index, step in enumerate(steps) + ), + turbo_modes=tuple( + _require_enum( + turbo[name], TURBO_MODES, f"profile.turbo.{name}" + ) + for name in LOGICAL_BUTTONS + ), + ) + + @classmethod + def from_json(cls, payload: str) -> ControllerProfile: + try: + value = json.loads(payload, object_pairs_hook=_unique_json_object) + except json.JSONDecodeError as exc: + raise ConfigManagerError(f"invalid profile JSON: {exc.msg}") from exc + return cls.from_json_object(value) + + +def _unique_json_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]: + result: dict[str, Any] = {} + for key, value in pairs: + if key in result: + raise ConfigManagerError(f"duplicate JSON field {key}") + result[key] = value + return result + + def _crc32(payload: bytes) -> int: return zlib.crc32(payload) & 0xFFFFFFFF @@ -362,6 +1343,197 @@ def reset_configuration(device: UsbDevice, timeout: float) -> TransactionStatus: return _wait_for_transaction(device, transaction_id, timeout) +def parse_profile_list(envelope: Envelope) -> tuple[ProfileListEntry, ...]: + _raise_status(envelope) + if envelope.schema_version != PROFILE_SCHEMA_VERSION: + raise ConfigManagerError("unsupported profile-list schema") + if not envelope.payload: + raise ConfigManagerError("short profile-list payload") + count = envelope.payload[0] + if ( + not 1 <= count <= PROFILE_LIST_CAPACITY + or len(envelope.payload) != 1 + count * PROFILE_LIST_ROW_SIZE + ): + raise ConfigManagerError("invalid profile-list count") + entries: list[ProfileListEntry] = [] + identities: set[ControllerIdentity] = set() + for index in range(count): + offset = 1 + index * PROFILE_LIST_ROW_SIZE + identity = ControllerIdentity.from_bytes( + envelope.payload[offset : offset + CONTROLLER_IDENTITY_SIZE] + ) + active_profile_index = envelope.payload[offset + 14] + if envelope.payload[offset + 15] != 0: + raise ConfigManagerError("profile-list reserved field is nonzero") + if index == 0 and not identity.is_global_fallback: + raise ConfigManagerError( + "profile list does not begin with global fallback" + ) + if index != 0 and identity.is_global_fallback: + raise ConfigManagerError("duplicate global fallback profile entry") + if identity in identities: + raise ConfigManagerError("duplicate identity in profile list") + identities.add(identity) + entries.append(ProfileListEntry(identity, active_profile_index)) + return tuple(entries) + + +def list_profiles(device: UsbDevice) -> tuple[ProfileListEntry, ...]: + return parse_profile_list(_control_in(device, OP_PROFILE_LIST)) + + +def _validate_profile_index(profile_index: int) -> None: + _require_int( + profile_index, + "profile index", + 0, + PROFILE_CAPACITY - 1, + ) + + +def select_profile( + device: UsbDevice, + identity: ControllerIdentity, + profile_index: int, +) -> None: + _validate_profile_index(profile_index) + _control_out( + device, + OP_PROFILE_SELECT, + identity.to_bytes() + bytes((profile_index,)), + ) + + +def read_selected_profile(device: UsbDevice) -> ControllerProfile: + envelope = _control_in(device, OP_PROFILE_READ) + _raise_status(envelope) + if envelope.schema_version != PROFILE_SCHEMA_VERSION: + raise ConfigManagerError("unsupported profile schema") + return ControllerProfile.from_bytes(envelope.payload) + + +def read_profile( + device: UsbDevice, + identity: ControllerIdentity, + profile_index: int, +) -> ControllerProfile: + select_profile(device, identity, profile_index) + return read_selected_profile(device) + + +def read_profile_transaction_status(device: UsbDevice) -> TransactionStatus: + envelope = _control_in(device, OP_PROFILE_TRANSACTION_STATUS) + _raise_status(envelope, pending_ok=True) + if ( + envelope.schema_version != PROFILE_SCHEMA_VERSION + or len(envelope.payload) != 20 + ): + raise ConfigManagerError("invalid profile transaction-status payload") + values = struct.unpack(" TransactionStatus: + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + envelope = _control_in(device, OP_PROFILE_TRANSACTION_STATUS) + if ( + envelope.schema_version != PROFILE_SCHEMA_VERSION + or len(envelope.payload) != 20 + ): + raise ConfigManagerError( + "invalid profile transaction-status payload" + ) + values = struct.unpack(" TransactionStatus: + _validate_profile_index(profile_index) + if not isinstance(profile, ControllerProfile): + raise ConfigManagerError("profile must be a ControllerProfile") + payload = profile.to_bytes() + transaction_id = secrets.randbits(32) or 1 + begin = ( + struct.pack(" TransactionStatus: + wire_index = PROFILE_NONE_BUTTON + if profile_index is not None: + _validate_profile_index(profile_index) + wire_index = profile_index + transaction_id = secrets.randbits(32) or 1 + _control_out( + device, + OP_PROFILE_RESET, + struct.pack(" TransactionStatus: + _validate_profile_index(profile_index) + transaction_id = secrets.randbits(32) or 1 + _control_out( + device, + OP_PROFILE_ACTIVATE, + struct.pack(" PairingSnapshot: _raise_status(envelope, pending_ok=True) if len(envelope.payload) < 4: @@ -484,10 +1656,96 @@ def _print_pairings(snapshot: PairingSnapshot) -> None: print("Warning: additional pairings did not fit in the response.") +def _print_profiles(entries: Sequence[ProfileListEntry]) -> None: + for index, entry in enumerate(entries): + identity = entry.identity + if identity.is_global_fallback: + description = "global fallback" + else: + description = ( + f"{identity.transport_text} {identity.address_text} " + f"address-type {identity.address_type} " + f"VID:PID {identity.vendor_id:04X}:{identity.product_id:04X}" + ) + print( + f"{index}: {description} " + f"(active profile {entry.active_profile_index + 1})" + ) + + +def _resolve_profile_identity( + entries: Sequence[ProfileListEntry], identity_index: int +) -> ControllerIdentity: + if not 0 <= identity_index < len(entries): + raise ConfigManagerError( + f"identity index {identity_index} is out of range; " + f"use profiles list to see indices 0 through {len(entries) - 1}" + ) + return entries[identity_index].identity + + +def _load_profile(path: Path) -> ControllerProfile: + try: + payload = path.read_text(encoding="utf-8") + except OSError as exc: + raise ConfigManagerError( + f"could not read profile JSON {path}: {exc}" + ) from exc + return ControllerProfile.from_json(payload) + + +def _save_profile(path: Path, profile: ControllerProfile) -> None: + try: + path.write_text(profile.to_json(), encoding="utf-8") + except OSError as exc: + raise ConfigManagerError( + f"could not write profile JSON {path}: {exc}" + ) from exc + + +def _profile_number(value: str) -> int: + try: + number = int(value) + except ValueError as exc: + raise argparse.ArgumentTypeError( + "profile must be a number from 1 to 4" + ) from exc + if not 1 <= number <= PROFILE_CAPACITY: + raise argparse.ArgumentTypeError("profile must be a number from 1 to 4") + return number - 1 + + +def _identity_index(value: str) -> int: + try: + index = int(value) + except ValueError as exc: + raise argparse.ArgumentTypeError( + "identity must be a non-negative list index" + ) from exc + if index < 0: + raise argparse.ArgumentTypeError( + "identity must be a non-negative list index" + ) + return index + + +def _add_identity_argument(parser: argparse.ArgumentParser) -> None: + parser.add_argument( + "--identity", + type=_identity_index, + default=0, + metavar="N", + help="identity index from profiles list (default: 0)", + ) + + def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( prog="switch-pico-config", - description="Manage switch-pico persistent configuration and pairings.", + description=( + "Manage switch-pico persistent configuration, profiles, " + "and pairings." + ), ) parser.add_argument("--bus", type=int, help="USB bus number") parser.add_argument("--address", type=int, help="USB device address") @@ -513,6 +1771,49 @@ def build_parser() -> argparse.ArgumentParser: config_reset = config_commands.add_parser("reset", help="restore defaults") config_reset.add_argument("--yes", action="store_true") + profiles = commands.add_parser( + "profiles", help="list, import, export, or select controller profiles" + ) + profile_commands = profiles.add_subparsers( + dest="profile_command", required=True + ) + profile_commands.add_parser( + "list", help="list profile identities and active profiles" + ) + profile_export = profile_commands.add_parser( + "export", help="export a profile as JSON" + ) + profile_export.add_argument( + "profile_index", type=_profile_number, metavar="PROFILE" + ) + profile_export.add_argument("path", type=Path, metavar="PATH") + _add_identity_argument(profile_export) + profile_import = profile_commands.add_parser( + "import", help="import a profile from JSON" + ) + profile_import.add_argument( + "profile_index", type=_profile_number, metavar="PROFILE" + ) + profile_import.add_argument("path", type=Path, metavar="PATH") + _add_identity_argument(profile_import) + profile_reset = profile_commands.add_parser( + "reset", help="reset one or all profiles" + ) + profile_reset.add_argument( + "profile_index", + type=lambda value: None if value == "all" else _profile_number(value), + metavar="PROFILE|all", + ) + _add_identity_argument(profile_reset) + profile_reset.add_argument("--yes", action="store_true") + profile_activate = profile_commands.add_parser( + "activate", help="activate a profile" + ) + profile_activate.add_argument( + "profile_index", type=_profile_number, metavar="PROFILE" + ) + _add_identity_argument(profile_activate) + pairings = commands.add_parser("pairings", help="list or clear pairings") pairing_commands = pairings.add_subparsers( dest="pairing_command", required=True @@ -528,14 +1829,32 @@ def main(argv: Sequence[str] | None = None) -> int: if args.timeout <= 0: print("error: --timeout must be positive", file=sys.stderr) return 2 - if args.command == "config" and args.config_command == "reset" and not args.yes: + if ( + args.command == "config" + and args.config_command == "reset" + and not args.yes + ): print("error: config reset requires --yes", file=sys.stderr) return 2 - if args.command == "pairings" and args.pairing_command == "clear" and not args.yes: + if ( + args.command == "pairings" + and args.pairing_command == "clear" + and not args.yes + ): print("error: pairings clear requires --yes", file=sys.stderr) return 2 + if ( + args.command == "profiles" + and args.profile_command == "reset" + and not args.yes + ): + print("error: profiles reset requires --yes", file=sys.stderr) + return 2 + imported_profile: ControllerProfile | None = None try: + if args.command == "profiles" and args.profile_command == "import": + imported_profile = _load_profile(args.path) device = find_pico(args.bus, args.address, args.timeout) if args.command == "status": info = read_info(device) @@ -581,6 +1900,53 @@ def main(argv: Sequence[str] | None = None) -> int: "Reset configuration at generation " f"{status.stored_generation}." ) + elif args.command == "profiles": + entries = list_profiles(device) + if args.profile_command == "list": + _print_profiles(entries) + else: + identity = _resolve_profile_identity(entries, args.identity) + if args.profile_command == "export": + profile = read_profile( + device, identity, args.profile_index + ) + _save_profile(args.path, profile) + print( + f"Exported profile {args.profile_index + 1} " + f"for identity {args.identity} to {args.path}." + ) + elif args.profile_command == "import": + status = write_profile( + device, + identity, + args.profile_index, + cast(ControllerProfile, imported_profile), + args.timeout, + ) + print( + f"Stored profile {args.profile_index + 1} " + f"for identity {args.identity} at generation " + f"{status.stored_generation} " + f"(CRC {status.stored_crc:08x})." + ) + elif args.profile_command == "reset": + reset_profile( + device, identity, args.profile_index, args.timeout + ) + target = ( + "all profiles" + if args.profile_index is None + else f"profile {args.profile_index + 1}" + ) + print(f"Reset {target} for identity {args.identity}.") + else: + activate_profile( + device, identity, args.profile_index, args.timeout + ) + print( + f"Activated profile {args.profile_index + 1} " + f"for identity {args.identity}." + ) elif args.pairing_command == "list": _print_pairings(refresh_pairings(device, args.timeout)) else: diff --git a/switch-pico.cpp b/switch-pico.cpp index 361021f..90aac7b 100644 --- a/switch-pico.cpp +++ b/switch-pico.cpp @@ -290,8 +290,10 @@ int main() { } for (uint8_t instance = 0; instance < BLUEPAD32_INPUT_BACKEND_SLOT_COUNT; ++instance) { - bluepad32_input_backend_snapshot(instance, - &g_user_states[instance]); + Bluepad32SlotSnapshot snapshot{}; + bluepad32_input_backend_snapshot(instance, &snapshot); + g_user_states[instance] = + snapshot.active ? snapshot.state : controller_neutral_state(); #ifdef SWITCH_PICO_ADAPTER_FEASIBILITY bool sent = false; if (adapter_host_probe_mode() == AdapterUsbMode::kXInput) { diff --git a/tests/bluepad32_backend_lifecycle_test.cpp b/tests/bluepad32_backend_lifecycle_test.cpp index 4f0d280..d498f7c 100644 --- a/tests/bluepad32_backend_lifecycle_test.cpp +++ b/tests/bluepad32_backend_lifecycle_test.cpp @@ -25,6 +25,7 @@ bool ssp_auto_accept = true; uint8_t accepted_stk_methods = 0xff; uint16_t link_supervision_timeout = 0; btstack_packet_handler_t pairing_event_handler = nullptr; +btstack_packet_handler_t identity_event_handler = nullptr; int confirmation_accepts = 0; int confirmation_rejections = 0; int passkey_accepts = 0; @@ -43,6 +44,8 @@ int cyw43_init_calls = 0; int uni_init_calls = 0; int device_disconnect_calls = 0; uni_hid_device_t* last_disconnected_device = nullptr; +uni_hid_device_t* lookup_devices[8]{}; +size_t lookup_device_count = 0; struct CoreStopped {}; @@ -82,11 +85,21 @@ uni_hid_device_t device( result.idx = idx; result.gamepad = gamepad; result.conn.protocol = protocol; + result.conn.handle = static_cast(0x40 + idx); result.conn.btaddr[5] = static_cast(idx + 1); + result.vendor_id = static_cast(0x1000 + idx); + result.product_id = static_cast(0x2000 + idx); result.report_parser.play_dual_rumble = play_rumble; return result; } +void register_lookup_device(uni_hid_device_t* candidate) { + require(lookup_device_count < + sizeof(lookup_devices) / sizeof(lookup_devices[0]), + "test BLE lookup registry overflow"); + lookup_devices[lookup_device_count++] = candidate; +} + } // namespace @@ -98,6 +111,16 @@ int uni_hid_device_get_idx_for_instance(const uni_hid_device_t* device) { return device == nullptr ? -1 : device->idx; } +uni_hid_device_t* uni_hid_device_get_instance_for_connection_handle( + hci_con_handle_t handle) { + for (size_t index = 0; index < lookup_device_count; ++index) { + if (lookup_devices[index]->conn.handle == handle) { + return lookup_devices[index]; + } + } + return nullptr; +} + void uni_hid_device_disconnect(uni_hid_device_t* device) { ++device_disconnect_calls; last_disconnected_device = device; @@ -226,6 +249,11 @@ void hci_add_event_handler( pairing_event_handler = callback_handler->callback; } +void sm_add_event_handler( + btstack_packet_callback_registration_t* callback_handler) { + identity_event_handler = callback_handler->callback; +} + uint8_t hci_event_packet_get_type(const uint8_t* packet) { return packet[0]; } @@ -246,6 +274,108 @@ void hci_event_user_passkey_request_get_bd_addr( copy_event_address(packet, address); } +hci_con_handle_t sm_event_handle(const uint8_t* packet) { + return static_cast(packet[2]) | + static_cast(packet[3] << 8); +} + +void copy_sm_event_address(const uint8_t* packet, size_t offset, + bd_addr_t address) { + for (size_t index = 0; index < sizeof(bd_addr_t); ++index) { + address[index] = packet[offset + sizeof(bd_addr_t) - 1 - index]; + } +} + +hci_con_handle_t sm_event_identity_resolving_started_get_handle( + const uint8_t* packet) { + return sm_event_handle(packet); +} + +hci_con_handle_t sm_event_identity_resolving_failed_get_handle( + const uint8_t* packet) { + return sm_event_handle(packet); +} + +hci_con_handle_t sm_event_identity_resolving_succeeded_get_handle( + const uint8_t* packet) { + return sm_event_handle(packet); +} + +uint8_t sm_event_identity_resolving_succeeded_get_addr_type( + const uint8_t* packet) { + return packet[4]; +} + +void sm_event_identity_resolving_succeeded_get_address( + const uint8_t* packet, bd_addr_t address) { + copy_sm_event_address(packet, 5, address); +} + +uint8_t sm_event_identity_resolving_succeeded_get_identity_addr_type( + const uint8_t* packet) { + return packet[11]; +} + +void sm_event_identity_resolving_succeeded_get_identity_address( + const uint8_t* packet, bd_addr_t address) { + copy_sm_event_address(packet, 12, address); +} + +hci_con_handle_t sm_event_identity_created_get_handle( + const uint8_t* packet) { + return sm_event_handle(packet); +} + +void sm_event_identity_created_get_address( + const uint8_t* packet, bd_addr_t address) { + copy_sm_event_address(packet, 5, address); +} + +uint8_t sm_event_identity_created_get_identity_addr_type( + const uint8_t* packet) { + return packet[11]; +} + +void sm_event_identity_created_get_identity_address( + const uint8_t* packet, bd_addr_t address) { + copy_sm_event_address(packet, 12, address); +} + +hci_con_handle_t sm_event_reencryption_started_get_handle( + const uint8_t* packet) { + return sm_event_handle(packet); +} + +uint8_t sm_event_reencryption_started_get_addr_type( + const uint8_t* packet) { + return packet[4]; +} + +void sm_event_reencryption_started_get_address( + const uint8_t* packet, bd_addr_t address) { + copy_sm_event_address(packet, 5, address); +} + +hci_con_handle_t sm_event_reencryption_complete_get_handle( + const uint8_t* packet) { + return sm_event_handle(packet); +} + +uint8_t sm_event_reencryption_complete_get_addr_type( + const uint8_t* packet) { + return packet[4]; +} + +void sm_event_reencryption_complete_get_address( + const uint8_t* packet, bd_addr_t address) { + copy_sm_event_address(packet, 5, address); +} + +uint8_t sm_event_reencryption_complete_get_status( + const uint8_t* packet) { + return packet[11]; +} + void uni_platform_set_custom(uni_platform* platform) { installed_platform = platform; @@ -284,10 +414,26 @@ uint32_t btstack_run_loop_get_time_ms() { } +#include "../controller_identity.cpp" #include "../bluepad32_input_backend.cpp" +ControllerIdentity observed_profile_identities[8]{}; +size_t observed_profile_identity_count = 0; void configuration_service_prepare() {} void configuration_service_initialize_on_storage_core() {} void configuration_service_task_on_storage_core(uint32_t) {} +void profile_service_prepare() {} +void profile_service_initialize_on_storage_core() {} +void profile_service_task_on_storage_core(uint32_t) {} +bool profile_service_observe_identity_on_storage_core( + const ControllerIdentity& identity) { + require(observed_profile_identity_count < + sizeof(observed_profile_identities) / + sizeof(observed_profile_identities[0]), + "profile identity observation fixture overflow"); + observed_profile_identities[observed_profile_identity_count++] = + identity; + return true; +} void configuration_service_snapshot(ConfigurationServiceSnapshot* output) { *output = {}; output->state = ConfigurationServiceState::kReady; @@ -319,6 +465,15 @@ SwitchRgbColor switch_pro_get_slot_light_color(uint8_t instance) { namespace { +bool read_controller_state(uint8_t slot, ControllerState* output) { + Bluepad32SlotSnapshot snapshot{}; + bluepad32_input_backend_snapshot(slot, &snapshot); + if (output != nullptr) { + *output = snapshot.state; + } + return snapshot.active; +} + void start_backend() { bluepad32_input_backend_init(); platform_on_init_complete(); @@ -327,8 +482,9 @@ void start_backend() { link_supervision_timeout == kClassicLinkSupervisionTimeout && !bondable && accepted_stk_methods == 0 && - !ssp_auto_accept && pairing_event_handler != nullptr, - "initialization must configure liveness and pairing policy"); + !ssp_auto_accept && pairing_event_handler != nullptr && + identity_event_handler != nullptr, + "initialization must register Classic and BLE identity policy"); } void start_pairing_backend() { start_backend(); @@ -344,6 +500,114 @@ void dispatch_pairing_event(uint8_t event_type) { pairing_event_handler(HCI_EVENT_PACKET, 0, packet, sizeof(packet)); } +void write_event_address(uint8_t* packet, size_t offset, + const bd_addr_t address) { + for (size_t index = 0; index < sizeof(bd_addr_t); ++index) { + packet[offset + index] = + address[sizeof(bd_addr_t) - 1 - index]; + } +} + +void dispatch_identity_event(uint8_t event_type, + const uni_hid_device_t& controller, + uint8_t identity_address_type, + const bd_addr_t identity_address, + uint8_t status = ERROR_CODE_SUCCESS) { + uint8_t packet[20]{}; + size_t packet_size = 0; + packet[0] = event_type; + packet[2] = static_cast(controller.conn.handle); + packet[3] = static_cast(controller.conn.handle >> 8); + switch (event_type) { + case SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED: + packet_size = sizeof(packet); + packet[4] = BD_ADDR_TYPE_LE_RANDOM; + write_event_address(packet, 5, controller.conn.btaddr); + packet[11] = identity_address_type; + write_event_address(packet, 12, identity_address); + break; + case SM_EVENT_IDENTITY_CREATED: + packet_size = sizeof(packet); + packet[4] = identity_address_type; + write_event_address(packet, 5, identity_address); + packet[11] = identity_address_type; + write_event_address(packet, 12, identity_address); + break; + case SM_EVENT_REENCRYPTION_STARTED: + packet_size = 11; + packet[4] = identity_address_type; + write_event_address(packet, 5, identity_address); + break; + case SM_EVENT_REENCRYPTION_COMPLETE: + packet_size = 12; + packet[4] = identity_address_type; + write_event_address(packet, 5, identity_address); + packet[11] = status; + break; + default: + require(false, "unsupported identity event fixture"); + } + packet[1] = static_cast(packet_size - 2); + identity_event_handler( + HCI_EVENT_PACKET, 0, packet, + static_cast(packet_size)); +} + +void require_identity(const ControllerIdentity& actual, bool stable, + ControllerTransport transport, uint8_t address_type, + const bd_addr_t address, uint16_t vendor_id, + uint16_t product_id, const char* message) { + ControllerIdentity expected{}; + expected.stable = stable; + expected.transport = transport; + expected.address_type = address_type; + memcpy(expected.address, address, sizeof(expected.address)); + expected.vendor_id = vendor_id; + expected.product_id = product_id; + require(controller_identity_equal(actual, expected), message); +} + +void test_identity_encoding_contract() { + ControllerIdentity identity{}; + identity.stable = true; + identity.transport = ControllerTransport::kBle; + identity.address_type = BD_ADDR_TYPE_LE_RANDOM_IDENTITY; + const bd_addr_t address = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + memcpy(identity.address, address, sizeof(address)); + identity.vendor_id = 0x1234; + identity.product_id = 0xabcd; + + uint8_t encoded[CONTROLLER_IDENTITY_ENCODED_SIZE]{}; + const uint8_t expected[CONTROLLER_IDENTITY_ENCODED_SIZE] = { + 1, 2, 3, 0, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x34, 0x12, 0xcd, 0xab}; + require(controller_identity_encode(identity, encoded, sizeof(encoded)) && + memcmp(encoded, expected, sizeof(expected)) == 0, + "controller identity wire encoding changed"); + + ControllerIdentity decoded{}; + require(controller_identity_decode(encoded, sizeof(encoded), &decoded) && + controller_identity_equal(identity, decoded), + "controller identity wire round trip failed"); + decoded.product_id ^= 1; + require(!controller_identity_equal(identity, decoded), + "controller identity equality must include every field"); + encoded[3] = 1; + require(!controller_identity_decode(encoded, sizeof(encoded), &decoded), + "controller identity decoder must reject a nonzero reserved byte"); + + const ControllerIdentity global = controller_identity_global(); + memset(encoded, 0xff, sizeof(encoded)); + require(controller_identity_is_global(global) && + controller_identity_encode(global, encoded, + sizeof(encoded)), + "global identity helper must produce an encodable fallback"); + for (uint8_t byte : encoded) { + require(byte == 0, + "global fallback identity must encode as all zeroes"); + } +} + @@ -376,7 +640,7 @@ void test_ready_order(bool reverse) { for (int ready = 0; ready <= position; ++ready) { expected_active = expected_active || order[ready] == candidate; } - require(bluepad32_input_backend_snapshot(candidate, &snapshot) == + require(read_controller_state(candidate, &snapshot) == expected_active, "only ready indexed slots may become active"); } @@ -403,7 +667,7 @@ void test_ready_order(bool reverse) { for (int candidate = 0; candidate < kSlotCount; ++candidate) { ControllerState snapshot{}; - require(bluepad32_input_backend_snapshot(candidate, &snapshot) == + require(read_controller_state(candidate, &snapshot) == (candidate != slot), "disconnect must preserve every surviving slot"); } @@ -444,7 +708,7 @@ void test_rejections() { collision_data.gamepad.buttons = BUTTON_B; platform_on_controller_data(&collision, &collision_data); ControllerState snapshot{}; - require(bluepad32_input_backend_snapshot(0, &snapshot), + require(read_controller_state(0, &snapshot), "occupied slot must stay active"); require(!snapshot.button_east, "mismatched device input must not enter the occupied slot"); @@ -453,13 +717,13 @@ void test_rejections() { slot_zero_data.klass = UNI_CONTROLLER_CLASS_GAMEPAD; slot_zero_data.gamepad.accel[0] = 8192; platform_on_controller_data(&slot_zero, &slot_zero_data); - require(bluepad32_input_backend_snapshot(0, &snapshot) && + require(read_controller_state(0, &snapshot) && snapshot.motion_sample_count == 3, "valid slot input must remain observable"); - require(!bluepad32_input_backend_snapshot(4, &snapshot), + require(!read_controller_state(4, &snapshot), "public snapshot must reject slot 4"); bluepad32_input_backend_report_sent(4); - require(bluepad32_input_backend_snapshot(0, &snapshot) && + require(read_controller_state(0, &snapshot) && snapshot.motion_sample_count == 3, "slot 4 acknowledgement must not consume slot 0 IMU"); bluepad32_input_backend_queue_rumble(4, ControllerRumbleOutput{1, 2}); @@ -469,6 +733,7 @@ void test_rejections() { } void test_independent_lifecycle() { + test_identity_encoding_contract(); start_pairing_backend(); uni_hid_device_t aborted = device(0); @@ -500,7 +765,40 @@ void test_independent_lifecycle() { "pre-ready disconnect must restart Classic and BLE scans"); uni_hid_device_t devices[kSlotCount] = { - device(0), device(1), device(2), device(3)}; + device(0, true, UNI_BT_CONN_PROTOCOL_BR_EDR), + device(1, true, UNI_BT_CONN_PROTOCOL_BLE), + device(2, true, UNI_BT_CONN_PROTOCOL_BLE), + device(3, true, UNI_BT_CONN_PROTOCOL_BLE)}; + const bd_addr_t classic_address = + {0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + const bd_addr_t resolved_connection_address = + {0x41, 0x21, 0x22, 0x23, 0x24, 0x25}; + const bd_addr_t created_connection_address = + {0x42, 0x31, 0x32, 0x33, 0x34, 0x35}; + const bd_addr_t reencrypted_connection_address = + {0x43, 0x41, 0x42, 0x43, 0x44, 0x45}; + memcpy(devices[0].conn.btaddr, classic_address, + sizeof(classic_address)); + memcpy(devices[1].conn.btaddr, resolved_connection_address, + sizeof(resolved_connection_address)); + memcpy(devices[2].conn.btaddr, created_connection_address, + sizeof(created_connection_address)); + memcpy(devices[3].conn.btaddr, reencrypted_connection_address, + sizeof(reencrypted_connection_address)); + const bd_addr_t resolved_address = + {0x20, 0x21, 0x22, 0x23, 0x24, 0x25}; + const bd_addr_t reencrypted_address = + {0x30, 0x31, 0x32, 0x33, 0x34, 0x35}; + dispatch_identity_event( + SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED, devices[1], + BD_ADDR_TYPE_LE_PUBLIC, resolved_address); + register_lookup_device(&devices[3]); + dispatch_identity_event( + SM_EVENT_REENCRYPTION_STARTED, devices[3], + BD_ADDR_TYPE_LE_RANDOM, reencrypted_address); + dispatch_identity_event( + SM_EVENT_REENCRYPTION_COMPLETE, devices[3], + BD_ADDR_TYPE_LE_RANDOM, reencrypted_address); for (int slot = 0; slot < kSlotCount; ++slot) { platform_on_device_connected(&devices[slot]); require(g_slots[slot].device == &devices[slot] && @@ -539,6 +837,73 @@ void test_independent_lifecycle() { !scanning_enabled && !incoming_connections, "four ready lifecycle devices must stop connection policy"); + Bluepad32SlotSnapshot lifecycle_snapshots[kSlotCount]{}; + uint32_t baseline_connection_generations[kSlotCount]{}; + for (int slot = 0; slot < kSlotCount; ++slot) { + bluepad32_input_backend_snapshot( + static_cast(slot), &lifecycle_snapshots[slot]); + require(lifecycle_snapshots[slot].active, + "ready slot snapshot must publish active state"); + baseline_connection_generations[slot] = + lifecycle_snapshots[slot].connection_generation; + } + require_identity( + lifecycle_snapshots[0].identity, true, + ControllerTransport::kClassic, BD_ADDR_TYPE_UNKNOWN, + devices[0].conn.btaddr, devices[0].vendor_id, + devices[0].product_id, + "Classic snapshot identity must use the connected device address"); + require_identity( + lifecycle_snapshots[1].identity, true, + ControllerTransport::kBle, BD_ADDR_TYPE_LE_PUBLIC, + resolved_address, devices[1].vendor_id, devices[1].product_id, + "resolved BLE snapshot must use the stable identity address"); + require(controller_identity_is_global( + lifecycle_snapshots[2].identity), + "unresolved BLE snapshot must use the global unstable identity"); + require_identity( + lifecycle_snapshots[3].identity, true, + ControllerTransport::kBle, BD_ADDR_TYPE_LE_RANDOM, + reencrypted_address, devices[3].vendor_id, + devices[3].product_id, + "reencrypted BLE snapshot must use the bonded identity address"); + require(observed_profile_identity_count == 3 && + controller_identity_equal( + observed_profile_identities[0], + lifecycle_snapshots[1].identity) && + controller_identity_equal( + observed_profile_identities[1], + lifecycle_snapshots[3].identity) && + controller_identity_equal( + observed_profile_identities[2], + lifecycle_snapshots[0].identity), + "only stable ready identities must be enrolled for profiles"); + require(baseline_connection_generations[0] == + first_pending_generation + 1 && + baseline_connection_generations[1] == + baseline_connection_generations[2] && + baseline_connection_generations[2] == + baseline_connection_generations[3], + "connection generations must isolate each slot lifecycle"); + + const bd_addr_t created_address = + {0x40, 0x41, 0x42, 0x43, 0x44, 0x45}; + register_lookup_device(&devices[2]); + dispatch_identity_event( + SM_EVENT_IDENTITY_CREATED, devices[2], + BD_ADDR_TYPE_LE_RANDOM, created_address); + bluepad32_input_backend_snapshot(2, &lifecycle_snapshots[2]); + require_identity( + lifecycle_snapshots[2].identity, true, + ControllerTransport::kBle, BD_ADDR_TYPE_LE_RANDOM, + created_address, devices[2].vendor_id, devices[2].product_id, + "new BLE identity event must update an active slot snapshot"); + require(observed_profile_identity_count == 4 && + controller_identity_equal( + observed_profile_identities[3], + lifecycle_snapshots[2].identity), + "late BLE identity creation must enroll the stable identity"); + const uint32_t buttons[kSlotCount] = { BUTTON_B, BUTTON_A, BUTTON_X, BUTTON_Y}; uni_controller_t data[kSlotCount]{}; @@ -552,7 +917,7 @@ void test_independent_lifecycle() { ControllerState states[kSlotCount]{}; for (int slot = 0; slot < kSlotCount; ++slot) { - require(bluepad32_input_backend_snapshot(slot, &states[slot]) && + require(read_controller_state(slot, &states[slot]) && states[slot].motion_sample_count == 3, "every slot must expose independent input and IMU"); } @@ -571,13 +936,13 @@ void test_independent_lifecycle() { bluepad32_input_backend_report_sent(3); for (int slot = 0; slot < kSlotCount; ++slot) { - require(bluepad32_input_backend_snapshot(slot, &states[slot]) && + require(read_controller_state(slot, &states[slot]) && states[slot].motion_sample_count == (slot == 3 ? 0 : 3), "slot 3 acknowledgement must not consume slots 0-2 IMU"); } for (int slot = 0; slot < 3; ++slot) { bluepad32_input_backend_report_sent(slot); - require(bluepad32_input_backend_snapshot(slot, &states[slot]) && + require(read_controller_state(slot, &states[slot]) && states[slot].motion_sample_count == 0, "each slot acknowledgement must consume only its own IMU"); } @@ -605,24 +970,43 @@ void test_independent_lifecycle() { bluepad32_input_backend_queue_rumble(3, ControllerRumbleOutput{55, 66}); const uint32_t disconnected_generation = - g_slots[3].connection_generation; + baseline_connection_generations[3]; const int starts_before_slot_three_disconnect = scan_starts; platform_on_device_disconnected(&devices[3]); require(scan_starts == starts_before_slot_three_disconnect + 1 && scanning_enabled && incoming_connections, "slot 3 disconnect must resume scanning and incoming connections"); - require(!bluepad32_input_backend_snapshot(3, &states[3]) && + require(!read_controller_state(3, &states[3]) && !states[3].button_north && states[3].left_stick_x == 0, "slot 3 disconnect must publish protocol-neutral state"); - require(bluepad32_input_backend_snapshot(0, &states[0]) && + bluepad32_input_backend_snapshot(3, &lifecycle_snapshots[3]); + require(!lifecycle_snapshots[3].active && + lifecycle_snapshots[3].connection_generation == + disconnected_generation + 1 && + controller_identity_is_global( + lifecycle_snapshots[3].identity) && + !lifecycle_snapshots[3].state.button_north && + lifecycle_snapshots[3].state.left_stick_x == 0, + "disconnect snapshot must atomically publish neutral state, " + "cleared identity, and a new connection generation"); + for (int survivor = 0; survivor < 3; ++survivor) { + bluepad32_input_backend_snapshot( + static_cast(survivor), + &lifecycle_snapshots[survivor]); + require(lifecycle_snapshots[survivor].active && + lifecycle_snapshots[survivor].connection_generation == + baseline_connection_generations[survivor], + "disconnect generation must not leak into surviving slots"); + } + require(read_controller_state(0, &states[0]) && states[0].button_east && - bluepad32_input_backend_snapshot(1, &states[1]) && + read_controller_state(1, &states[1]) && states[1].button_south && - bluepad32_input_backend_snapshot(2, &states[2]) && + read_controller_state(2, &states[2]) && states[2].button_west, "slot 3 disconnect must preserve slots 0-2"); platform_on_controller_data(&devices[0], &data[0]); - require(bluepad32_input_backend_snapshot(0, &states[0]) && + require(read_controller_state(0, &states[0]) && states[0].button_east, "slot 0 input must continue while slot 3 is disconnected"); const int slot_zero_calls_while_scanning = devices[0].rumble_calls; @@ -633,13 +1017,26 @@ void test_independent_lifecycle() { devices[0].last_high == 116, "slot 0 rumble must continue while slot 3 is disconnected"); - uni_hid_device_t slot_three_replacement = device(3); + uni_hid_device_t slot_three_replacement = + device(3, true, UNI_BT_CONN_PROTOCOL_BLE); + memcpy(slot_three_replacement.conn.btaddr, + devices[3].conn.btaddr, sizeof(devices[3].conn.btaddr)); require(platform_on_device_ready(&slot_three_replacement) == UNI_ERROR_SUCCESS, "slot 3 replacement must bind to the freed indexed slot"); process_rumble_timer(&g_rumble_timer); require(slot_three_replacement.rumble_calls == 0, "slot 3 replacement must not receive disconnected device rumble"); + bluepad32_input_backend_snapshot(3, &lifecycle_snapshots[3]); + require(lifecycle_snapshots[3].active && + lifecycle_snapshots[3].connection_generation == + disconnected_generation + 1 && + controller_identity_is_global( + lifecycle_snapshots[3].identity), + "replacement must keep the new generation and cannot inherit " + "the disconnected BLE identity"); + require(observed_profile_identity_count == 4, + "unstable replacement must not be enrolled for profiles"); g_slots[3].pending_rumble = { 3, disconnected_generation, ControllerRumbleOutput{77, 88}}; @@ -653,14 +1050,14 @@ void test_independent_lifecycle() { replacement_data.gamepad.buttons = BUTTON_Y; replacement_data.gamepad.accel[0] = 9000; platform_on_controller_data(&slot_three_replacement, &replacement_data); - require(bluepad32_input_backend_snapshot(3, &states[3]) && + require(read_controller_state(3, &states[3]) && states[3].button_north && states[3].motion_sample_count == 3, "replacement input and IMU must populate only slot 3"); - require(bluepad32_input_backend_snapshot(0, &states[0]) && + require(read_controller_state(0, &states[0]) && states[0].button_east && - bluepad32_input_backend_snapshot(1, &states[1]) && + read_controller_state(1, &states[1]) && states[1].button_south && - bluepad32_input_backend_snapshot(2, &states[2]) && + read_controller_state(2, &states[2]) && states[2].button_west, "slot 3 replacement must not disturb slots 0-2"); @@ -706,15 +1103,14 @@ void test_independent_lifecycle() { require(scan_starts == starts_before_disconnect + 1 && scanning_enabled && incoming_connections, "disconnecting slots 0-2 must resume connection policy"); - require(!bluepad32_input_backend_snapshot(slot, &states[slot]) && + require(!read_controller_state(slot, &states[slot]) && states[slot].left_stick_x == 0, "disconnect must publish protocol-neutral state"); for (int survivor = 0; survivor < kSlotCount; ++survivor) { if (survivor == slot) { continue; } - require(bluepad32_input_backend_snapshot(survivor, - &states[survivor]), + require(read_controller_state(survivor, &states[survivor]), "disconnect must preserve all three survivors"); } require(platform_on_device_ready(&replacements[slot]) == @@ -898,7 +1294,7 @@ void test_abxy_hotkey() { input.gamepad.buttons = BUTTON_A; platform_on_controller_data(&slot_zero, &input); ControllerState snapshot{}; - require(bluepad32_input_backend_snapshot(0, &snapshot), + require(read_controller_state(0, &snapshot), "slot 0 ABXY state was not published"); require_south_button_mapping( snapshot, kDefaultSwapAbxy, @@ -908,7 +1304,7 @@ void test_abxy_hotkey() { kAbxyHotkeyButtonMask | BUTTON_A; input.gamepad.misc_buttons = kAbxyHotkeyMiscMask; platform_on_controller_data(&slot_zero, &input); - require(bluepad32_input_backend_snapshot(0, &snapshot), + require(read_controller_state(0, &snapshot), "toggled slot 0 state was not published"); require_south_button_mapping( snapshot, !kDefaultSwapAbxy, @@ -960,7 +1356,7 @@ void test_abxy_hotkey() { peer_input.klass = UNI_CONTROLLER_CLASS_GAMEPAD; peer_input.gamepad.buttons = BUTTON_A; platform_on_controller_data(&slot_one, &peer_input); - require(bluepad32_input_backend_snapshot(1, &snapshot), + require(read_controller_state(1, &snapshot), "slot 1 ABXY state was not published"); require_south_button_mapping( snapshot, kDefaultSwapAbxy, @@ -988,7 +1384,7 @@ void test_motion_hotkey() { input.gamepad.accel[0] = 8192; platform_on_controller_data(&slot_zero, &input); ControllerState snapshot{}; - require(bluepad32_input_backend_snapshot(0, &snapshot) && + require(read_controller_state(0, &snapshot) && snapshot.motion_sample_count == (kDefaultMotionEnabled ? 3 : 0), "slot 0 did not start with configured motion state"); @@ -997,7 +1393,7 @@ void test_motion_hotkey() { input.gamepad.buttons = kMotionHotkeyButtonMask; input.gamepad.misc_buttons = kMotionHotkeyMiscMask; platform_on_controller_data(&slot_zero, &input); - require(bluepad32_input_backend_snapshot(0, &snapshot) && + require(read_controller_state(0, &snapshot) && snapshot.motion_sample_count == (kDefaultMotionEnabled ? 0 : 3) && !snapshot.dpad_up && !snapshot.button_right_shoulder && @@ -1030,7 +1426,7 @@ void test_motion_hotkey() { peer_input.klass = UNI_CONTROLLER_CLASS_GAMEPAD; peer_input.gamepad.accel[0] = 8192; platform_on_controller_data(&slot_one, &peer_input); - require(bluepad32_input_backend_snapshot(1, &snapshot) && + require(read_controller_state(1, &snapshot) && snapshot.motion_sample_count == (kDefaultMotionEnabled ? 3 : 0), "slot 0 motion chord changed slot 1 motion state"); @@ -1042,7 +1438,7 @@ void test_motion_hotkey() { input.gamepad.buttons = kMotionHotkeyButtonMask; input.gamepad.misc_buttons = kMotionHotkeyMiscMask; platform_on_controller_data(&slot_zero, &input); - require(bluepad32_input_backend_snapshot(0, &snapshot) && + require(read_controller_state(0, &snapshot) && snapshot.motion_sample_count == (kDefaultMotionEnabled ? 3 : 0), "released motion chord did not re-arm or restore motion"); @@ -1078,7 +1474,7 @@ void test_protocol_neutral_analog_state() { platform_on_controller_data(&controller, &input); ControllerState state{}; - require(bluepad32_input_backend_snapshot(0, &state), + require(read_controller_state(0, &state), "analog state was not published"); require(state.left_stick_x == INT16_MIN && state.left_stick_y == 0 && @@ -1096,7 +1492,7 @@ void test_protocol_neutral_analog_state() { input.gamepad.buttons = BUTTON_TRIGGER_L | BUTTON_TRIGGER_R; platform_on_controller_data(&controller, &input); - require(bluepad32_input_backend_snapshot(0, &state) && + require(read_controller_state(0, &state) && state.left_trigger == UINT16_MAX && state.right_trigger == UINT16_MAX, "digital trigger buttons did not map to full analog range"); diff --git a/tests/bluepad32_native_stubs/uni.h b/tests/bluepad32_native_stubs/uni.h index 7ee86a8..5fdc72e 100644 --- a/tests/bluepad32_native_stubs/uni.h +++ b/tests/bluepad32_native_stubs/uni.h @@ -6,6 +6,7 @@ typedef uint8_t bd_addr_t[6]; typedef uint8_t link_key_t[16]; typedef uint8_t sm_key_t[16]; typedef int link_key_type_t; +typedef uint16_t hci_con_handle_t; enum bd_addr_type_t { BD_ADDR_TYPE_LE_PUBLIC = 0, @@ -29,6 +30,12 @@ enum { HCI_EVENT_PACKET = 4, HCI_EVENT_USER_CONFIRMATION_REQUEST = 0x33, HCI_EVENT_USER_PASSKEY_REQUEST = 0x34, + SM_EVENT_IDENTITY_RESOLVING_STARTED = 0xcd, + SM_EVENT_IDENTITY_RESOLVING_FAILED = 0xce, + SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED = 0xcf, + SM_EVENT_IDENTITY_CREATED = 0xd3, + SM_EVENT_REENCRYPTION_STARTED = 0xd6, + SM_EVENT_REENCRYPTION_COMPLETE = 0xd7, SM_STK_GENERATION_METHOD_JUST_WORKS = 0x01, SM_STK_GENERATION_METHOD_OOB = 0x02, SM_STK_GENERATION_METHOD_PASSKEY = 0x04, @@ -114,10 +121,13 @@ enum uni_bt_conn_protocol_t { struct uni_bt_conn_t { bd_addr_t btaddr; + hci_con_handle_t handle; uni_bt_conn_protocol_t protocol; }; struct uni_hid_device_t { + uint16_t vendor_id; + uint16_t product_id; uni_bt_conn_t conn; int idx; bool gamepad; @@ -154,6 +164,8 @@ struct uni_platform { bool uni_hid_device_is_gamepad(const uni_hid_device_t* device); int uni_hid_device_get_idx_for_instance(const uni_hid_device_t* device); void uni_hid_device_disconnect(uni_hid_device_t* device); +uni_hid_device_t* uni_hid_device_get_instance_for_connection_handle( + hci_con_handle_t handle); void uni_bt_allow_incoming_connections(bool enabled); void uni_bt_start_scanning_and_autoconnect_unsafe(); void uni_bt_stop_scanning_unsafe(); @@ -181,10 +193,48 @@ int gap_ssp_passkey_response(const bd_addr_t address, uint32_t passkey); int gap_ssp_passkey_negative(const bd_addr_t address); void hci_add_event_handler( btstack_packet_callback_registration_t* callback_handler); +void sm_add_event_handler( + btstack_packet_callback_registration_t* callback_handler); uint8_t hci_event_packet_get_type(const uint8_t* packet); void hci_event_user_confirmation_request_get_bd_addr( const uint8_t* packet, bd_addr_t address); void hci_event_user_passkey_request_get_bd_addr( const uint8_t* packet, bd_addr_t address); +hci_con_handle_t sm_event_identity_resolving_started_get_handle( + const uint8_t* packet); +hci_con_handle_t sm_event_identity_resolving_failed_get_handle( + const uint8_t* packet); +hci_con_handle_t sm_event_identity_resolving_succeeded_get_handle( + const uint8_t* packet); +uint8_t sm_event_identity_resolving_succeeded_get_addr_type( + const uint8_t* packet); +void sm_event_identity_resolving_succeeded_get_address( + const uint8_t* packet, bd_addr_t address); +uint8_t sm_event_identity_resolving_succeeded_get_identity_addr_type( + const uint8_t* packet); +void sm_event_identity_resolving_succeeded_get_identity_address( + const uint8_t* packet, bd_addr_t address); +hci_con_handle_t sm_event_identity_created_get_handle( + const uint8_t* packet); +void sm_event_identity_created_get_address( + const uint8_t* packet, bd_addr_t address); +uint8_t sm_event_identity_created_get_identity_addr_type( + const uint8_t* packet); +void sm_event_identity_created_get_identity_address( + const uint8_t* packet, bd_addr_t address); +hci_con_handle_t sm_event_reencryption_started_get_handle( + const uint8_t* packet); +uint8_t sm_event_reencryption_started_get_addr_type( + const uint8_t* packet); +void sm_event_reencryption_started_get_address( + const uint8_t* packet, bd_addr_t address); +hci_con_handle_t sm_event_reencryption_complete_get_handle( + const uint8_t* packet); +uint8_t sm_event_reencryption_complete_get_addr_type( + const uint8_t* packet); +void sm_event_reencryption_complete_get_address( + const uint8_t* packet, bd_addr_t address); +uint8_t sm_event_reencryption_complete_get_status( + const uint8_t* packet); void uni_platform_set_custom(uni_platform* platform); int uni_init(int argc, const char** argv); diff --git a/tests/controller_profile_test.cpp b/tests/controller_profile_test.cpp new file mode 100644 index 0000000..a235a26 --- /dev/null +++ b/tests/controller_profile_test.cpp @@ -0,0 +1,162 @@ +#include "controller_identity.h" +#include "controller_profile.h" + +#include +#include +#include + +namespace { + +uint8_t encoded_database[CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE]{}; +ControllerProfileDatabase database{}; +ControllerProfileDatabase decoded_database{}; + +void require(bool condition, const char* message) { + if (!condition) { + std::cerr << message << '\n'; + std::exit(1); + } +} + +ControllerIdentity identity(uint8_t suffix) { + ControllerIdentity value{}; + value.stable = true; + value.transport = ControllerTransport::kClassic; + value.address[5] = suffix; + value.vendor_id = 0x057e; + value.product_id = static_cast(0x2000u + suffix); + return value; +} + +bool read_encoded_database(void*, size_t offset, uint8_t* output, + size_t size) { + if (offset > sizeof(encoded_database) || + size > sizeof(encoded_database) - offset) { + return false; + } + memcpy(output, &encoded_database[offset], size); + return true; +} + +void test_profile_wire_schema() { + const ControllerProfile profile = + controller_profile_default(controller_identity_global(), 0); + uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + require(controller_profile_encode(profile, encoded, sizeof(encoded)), + "default profile did not encode"); + require(encoded[0] == 1 && encoded[1] == 0 && + encoded[2] == 0 && encoded[3] == 1, + "profile header is not little-endian v1/256"); + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; ++index) { + require(encoded[4 + index] == index, + "default direct mapping is not identity"); + } + require(encoded[26] == 0xff && encoded[27] == 0x7f && + encoded[30] == 0, + "default stick encoding changed"); + require(encoded[54] == 0xff && encoded[55] == 0xff && + encoded[58] == 0x00 && encoded[59] == 0x80, + "default trigger encoding changed"); + require(encoded[72] == 0xff && encoded[73] == 0xff && + encoded[74] == 3 && encoded[78] == 0xff && + encoded[79] == 0xff && encoded[80] == 1, + "default rumble or macro encoding changed"); + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_MACRO_STEP_CAPACITY; ++index) { + require(encoded[100 + index * 19] == 1, + "unused macro step is not canonical end"); + } + + ControllerProfile decoded{}; + require(controller_profile_decode(encoded, sizeof(encoded), &decoded), + "default profile did not decode"); + encoded[252] = 1; + require(!controller_profile_decode(encoded, sizeof(encoded), &decoded), + "nonzero reserved profile byte was accepted"); + + ControllerProfile invalid = profile; + invalid.button_map[0] = 16; + require(!controller_profile_validate(invalid), + "invalid direct output was accepted"); + invalid = profile; + invalid.sticks[0].inner_deadzone = + invalid.sticks[0].outer_saturation; + require(!controller_profile_validate(invalid), + "empty stick range was accepted"); + invalid = profile; + invalid.triggers[0].digital_threshold = 0; + invalid.triggers[0].lower_deadzone = 1; + require(!controller_profile_validate(invalid), + "trigger threshold outside its range was accepted"); + invalid = profile; + invalid.turbo_modes[0] = + static_cast(3); + require(!controller_profile_validate(invalid), + "invalid Turbo mode was accepted"); + invalid = profile; + invalid.macro_step_count = 2; + invalid.macro_steps[0].type = + ControllerProfileMacroStepType::kState; + invalid.macro_steps[0].duration_ms = + CONTROLLER_PROFILE_MAX_WAIT_MS + 1; + require(!controller_profile_validate(invalid), + "unbounded macro wait was accepted"); + invalid.macro_steps[0].duration_ms = + CONTROLLER_PROFILE_MAX_WAIT_MS; + invalid.macro_steps[1].type = + ControllerProfileMacroStepType::kState; + require(!controller_profile_validate(invalid), + "macro without a final end was accepted"); +} + +void test_database_round_trip_and_capacity() { + controller_profile_database_default(&database); + for (uint8_t index = 0; + index < CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY; ++index) { + ControllerProfileDatabaseEntry* entry = nullptr; + require(controller_profile_database_ensure( + &database, identity(static_cast(index + 1)), + &entry) == ControllerProfileDatabaseResult::kOk && + entry != nullptr, + "stable identity was not added"); + entry->active_profile = index % CONTROLLER_PROFILE_COUNT; + } + ControllerProfileDatabaseEntry* rejected = nullptr; + require(controller_profile_database_ensure( + &database, identity(99), &rejected) == + ControllerProfileDatabaseResult::kFull, + "seventeenth stable identity was not rejected"); + require(controller_profile_database_find(database, identity(1)) != + nullptr, + "full-table rejection evicted an existing identity"); + + for (size_t offset = 0; offset < sizeof(encoded_database); + offset += CONTROLLER_PROFILE_ENCODED_SIZE) { + const size_t size = sizeof(encoded_database) - offset < + CONTROLLER_PROFILE_ENCODED_SIZE + ? sizeof(encoded_database) - offset + : CONTROLLER_PROFILE_ENCODED_SIZE; + require(controller_profile_database_encode_range( + database, offset, &encoded_database[offset], size), + "database range did not encode"); + } + require(controller_profile_database_decode( + read_encoded_database, nullptr, &decoded_database), + "database did not decode"); + require(controller_profile_database_find( + decoded_database, identity(16)) != nullptr, + "last database identity did not round trip"); + + encoded_database[12] = 1; + require(!controller_profile_database_decode( + read_encoded_database, nullptr, &decoded_database), + "nonzero database header reservation was accepted"); +} + +} // namespace +int main() { + test_profile_wire_schema(); + test_database_round_trip_and_capacity(); + return 0; +} diff --git a/tests/profile_service_test.cpp b/tests/profile_service_test.cpp new file mode 100644 index 0000000..0239a39 --- /dev/null +++ b/tests/profile_service_test.cpp @@ -0,0 +1,186 @@ +#include "controller_identity.h" +#include "controller_profile.h" +#include "pico_profile_storage.h" +#include "profile_service.h" +#include "profile_storage.h" + +#include +#include +#include + +namespace { + +struct FakeFlash { + uint8_t bytes[PROFILE_STORAGE_BANK_COUNT][PROFILE_STORAGE_BANK_SIZE]; +}; + +FakeFlash flash{}; + +void require(bool condition, const char* message) { + if (!condition) { + std::cerr << message << '\n'; + std::exit(1); + } +} + +bool fake_read(void* context, uint8_t bank, size_t offset, + uint8_t* output, size_t size) { + auto* storage = static_cast(context); + if (bank >= PROFILE_STORAGE_BANK_COUNT || output == nullptr || + offset > PROFILE_STORAGE_BANK_SIZE || + size > PROFILE_STORAGE_BANK_SIZE - offset) { + return false; + } + memcpy(output, &storage->bytes[bank][offset], size); + return true; +} + +bool fake_erase_sector(void* context, uint8_t bank, size_t offset) { + auto* storage = static_cast(context); + if (bank >= PROFILE_STORAGE_BANK_COUNT || + offset % PROFILE_STORAGE_SECTOR_SIZE != 0 || + offset > PROFILE_STORAGE_BANK_SIZE || + PROFILE_STORAGE_SECTOR_SIZE > PROFILE_STORAGE_BANK_SIZE - offset) { + return false; + } + memset(&storage->bytes[bank][offset], 0xff, + PROFILE_STORAGE_SECTOR_SIZE); + return true; +} + +bool fake_program(void* context, uint8_t bank, size_t offset, + const uint8_t* data, size_t size) { + auto* storage = static_cast(context); + if (bank >= PROFILE_STORAGE_BANK_COUNT || data == nullptr || + size != PROFILE_STORAGE_PAGE_SIZE || + offset % PROFILE_STORAGE_PAGE_SIZE != 0 || + offset > PROFILE_STORAGE_BANK_SIZE || + size > PROFILE_STORAGE_BANK_SIZE - offset) { + return false; + } + for (size_t index = 0; index < size; ++index) { + storage->bytes[bank][offset + index] &= data[index]; + } + return true; +} + +ProfileStorageIo fake_io() { + return { + &flash, + PROFILE_STORAGE_BANK_SIZE, + PROFILE_STORAGE_SECTOR_SIZE, + PROFILE_STORAGE_PAGE_SIZE, + fake_read, + fake_erase_sector, + fake_program, + }; +} + +ProfileServiceTransactionSnapshot transaction_snapshot() { + ProfileServiceTransactionSnapshot snapshot{}; + profile_service_transaction_snapshot(&snapshot); + return snapshot; +} + +ControllerProfileDatabase reload_database( + const ProfileServiceTransactionSnapshot& transaction, + uint32_t expected_generation) { + ControllerProfileDatabase recovered{}; + ProfileStorage storage; + require(storage.initialize(fake_io(), &recovered) && + storage.snapshot().valid && + storage.snapshot().generation == expected_generation && + storage.snapshot().generation == + transaction.transaction.stored_generation && + storage.snapshot().payload_crc == + transaction.transaction.stored_crc, + "terminal transaction status did not identify persisted storage"); + return recovered; +} + +void test_pending_commands_are_not_decoded_as_profile_writes() { + memset(flash.bytes, 0xff, sizeof(flash.bytes)); + profile_service_prepare(); + profile_service_initialize_on_storage_core(); + + const ControllerIdentity identity = controller_identity_global(); + constexpr uint8_t kProfileIndex = 2; + ControllerProfile customized = + controller_profile_default(identity, kProfileIndex); + customized.strong_rumble_scale = 17; + uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + require(controller_profile_encode(customized, encoded, sizeof(encoded)), + "customized profile did not encode"); + + constexpr uint32_t kWriteTransactionId = 0x10203040; + require(profile_service_begin( + kWriteTransactionId, identity, kProfileIndex, + CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded), + profile_storage_crc32(encoded, sizeof(encoded))) == + ConfigurationTransactionStatus::kReceiving && + profile_service_append(kWriteTransactionId, 0, encoded, + sizeof(encoded)) == + ConfigurationTransactionStatus::kReceiving && + profile_service_commit(kWriteTransactionId) == + ConfigurationTransactionStatus::kPending, + "profile write did not reach pending"); + profile_service_task_on_storage_core(0); + require(transaction_snapshot().transaction.status == + ConfigurationTransactionStatus::kCommitted, + "profile write baseline did not commit"); + + constexpr uint32_t kResetTransactionId = 0xa5a55a5a; + require(profile_service_reset(kResetTransactionId, identity, + kProfileIndex) == + ConfigurationTransactionStatus::kPending, + "profile reset did not reach pending"); + ProfileServiceTransactionSnapshot reset = transaction_snapshot(); + require(reset.transaction.transaction_id == kResetTransactionId && + reset.transaction.status == + ConfigurationTransactionStatus::kPending, + "pending reset lost its transaction identity"); + + profile_service_task_on_storage_core(1000); + reset = transaction_snapshot(); + require(reset.transaction.transaction_id == kResetTransactionId && + reset.transaction.status == + ConfigurationTransactionStatus::kCommitted, + "one reset tick decoded profile payload or published a malformed result"); + ControllerProfileDatabase recovered = reload_database(reset, 2); + require(recovered.fallback_profiles[kProfileIndex].strong_rumble_scale == + UINT8_MAX, + "terminal reset status was published before reset persisted"); + + constexpr uint32_t kActivateTransactionId = 0x50607080; + constexpr uint8_t kActivatedProfile = 3; + require(profile_service_activate(kActivateTransactionId, identity, + kActivatedProfile) == + ConfigurationTransactionStatus::kPending, + "profile activation did not reach pending"); + ProfileServiceTransactionSnapshot activate = transaction_snapshot(); + require(activate.transaction.transaction_id == kActivateTransactionId && + activate.transaction.status == + ConfigurationTransactionStatus::kPending, + "pending activation lost its transaction identity"); + + profile_service_task_on_storage_core(2000); + activate = transaction_snapshot(); + require(activate.transaction.transaction_id == kActivateTransactionId && + activate.transaction.status == + ConfigurationTransactionStatus::kCommitted, + "one activation tick decoded profile payload or published a malformed result"); + recovered = reload_database(activate, 3); + require(recovered.fallback_active_profile == kActivatedProfile, + "terminal activation status was published before activation persisted"); +} + +} // namespace + +ProfileStorageIo pico_profile_storage_io() { + return fake_io(); +} + +int main() { + test_pending_commands_are_not_decoded_as_profile_writes(); + return 0; +} diff --git a/tests/profile_storage_test.cpp b/tests/profile_storage_test.cpp new file mode 100644 index 0000000..6301bb0 --- /dev/null +++ b/tests/profile_storage_test.cpp @@ -0,0 +1,235 @@ +#include "controller_identity.h" +#include "controller_profile.h" +#include "profile_storage.h" + +#include +#include +#include + +namespace { + +struct FakeFlash { + uint8_t bytes[PROFILE_STORAGE_BANK_COUNT][PROFILE_STORAGE_BANK_SIZE]; + int successful_programs = 0; + int fail_after_programs = -1; + bool corrupt_next_program = false; + bool fail_reads_after_header_program = false; + bool header_programmed = false; +}; + +FakeFlash flash{}; +ControllerProfileDatabase database{}; +ControllerProfileDatabase recovered_database{}; + +void require(bool condition, const char* message) { + if (!condition) { + std::cerr << message << '\n'; + std::exit(1); + } +} + +void erase_all() { + memset(flash.bytes, 0xff, sizeof(flash.bytes)); + flash.successful_programs = 0; + flash.fail_after_programs = -1; + flash.corrupt_next_program = false; + flash.fail_reads_after_header_program = false; + flash.header_programmed = false; +} + +bool fake_read(void* context, uint8_t bank, size_t offset, + uint8_t* output, size_t size) { + auto* storage = static_cast(context); + if (storage->fail_reads_after_header_program && + storage->header_programmed) { + return false; + } + if (bank >= PROFILE_STORAGE_BANK_COUNT || + offset > PROFILE_STORAGE_BANK_SIZE || + size > PROFILE_STORAGE_BANK_SIZE - offset) { + return false; + } + memcpy(output, &storage->bytes[bank][offset], size); + return true; +} + +bool fake_erase_sector(void* context, uint8_t bank, size_t offset) { + auto* storage = static_cast(context); + if (bank >= PROFILE_STORAGE_BANK_COUNT || + offset % PROFILE_STORAGE_SECTOR_SIZE != 0 || + offset > PROFILE_STORAGE_BANK_SIZE || + PROFILE_STORAGE_SECTOR_SIZE > + PROFILE_STORAGE_BANK_SIZE - offset) { + return false; + } + memset(&storage->bytes[bank][offset], 0xff, + PROFILE_STORAGE_SECTOR_SIZE); + return true; +} + +bool fake_program(void* context, uint8_t bank, size_t offset, + const uint8_t* data, size_t size) { + auto* storage = static_cast(context); + if (bank >= PROFILE_STORAGE_BANK_COUNT || data == nullptr || + size != PROFILE_STORAGE_PAGE_SIZE || + offset % PROFILE_STORAGE_PAGE_SIZE != 0 || + offset > PROFILE_STORAGE_BANK_SIZE || + size > PROFILE_STORAGE_BANK_SIZE - offset) { + return false; + } + if (storage->fail_after_programs >= 0 && + storage->successful_programs >= storage->fail_after_programs) { + return false; + } + for (size_t index = 0; index < size; ++index) { + storage->bytes[bank][offset + index] &= data[index]; + } + if (storage->corrupt_next_program) { + storage->bytes[bank][offset] ^= 1; + storage->corrupt_next_program = false; + } + if (offset == 0) { + storage->header_programmed = true; + } + ++storage->successful_programs; + return true; +} + +ProfileStorageIo fake_io() { + return { + &flash, + PROFILE_STORAGE_BANK_SIZE, + PROFILE_STORAGE_SECTOR_SIZE, + PROFILE_STORAGE_PAGE_SIZE, + fake_read, + fake_erase_sector, + fake_program, + }; +} + +void test_two_bank_recovery() { + erase_all(); + controller_profile_database_default(&database); + ProfileStorage storage; + require(storage.initialize(fake_io(), &database) && + !storage.snapshot().valid, + "erased profile storage did not initialize empty"); + require(storage.commit(database) == ProfileStorageResult::kOk && + storage.snapshot().generation == 1, + "first profile database did not commit"); + const int programs_after_first = flash.successful_programs; + require(storage.commit(database) == ProfileStorageResult::kUnchanged && + flash.successful_programs == programs_after_first, + "unchanged profile database consumed flash writes"); + + database.fallback_profiles[0].button_map[0] = 1; + require(storage.commit(database) == ProfileStorageResult::kOk && + storage.snapshot().generation == 2, + "second profile database generation did not commit"); + ProfileStorage reloaded; + require(reloaded.initialize(fake_io(), &recovered_database) && + reloaded.snapshot().generation == 2 && + recovered_database.fallback_profiles[0].button_map[0] == 1, + "latest profile database did not survive reload"); + + const uint8_t newest_bank = reloaded.snapshot().active_bank; + flash.bytes[newest_bank][PROFILE_STORAGE_RECORD_HEADER_SIZE + 4] ^= 1; + ProfileStorage after_corruption; + require(after_corruption.initialize(fake_io(), &recovered_database) && + after_corruption.snapshot().generation == 1 && + recovered_database.fallback_profiles[0].button_map[0] == 0, + "corrupt newest profile bank did not roll back"); +} + +void test_interrupted_commit_retains_previous_bank() { + erase_all(); + controller_profile_database_default(&database); + ProfileStorage storage; + require(storage.initialize(fake_io(), &database) && + storage.commit(database) == ProfileStorageResult::kOk, + "interruption baseline did not commit"); + database.fallback_profiles[1].button_map[2] = 3; + flash.fail_after_programs = flash.successful_programs + 1; + require(storage.commit(database) == ProfileStorageResult::kIoError, + "interrupted profile write reported success"); + + flash.fail_after_programs = -1; + ProfileStorage recovered; + require(recovered.initialize(fake_io(), &recovered_database) && + recovered.snapshot().generation == 1 && + recovered_database.fallback_profiles[1].button_map[2] == 2, + "interrupted profile write replaced previous bank"); +} + +void test_successful_header_program_is_commit_point() { + erase_all(); + controller_profile_database_default(&database); + ProfileStorage storage; + require(storage.initialize(fake_io(), &database) && + storage.commit(database) == ProfileStorageResult::kOk, + "commit-point baseline did not commit"); + + database.fallback_profiles[1].strong_rumble_scale = 17; + flash.header_programmed = false; + flash.fail_reads_after_header_program = true; + require(storage.commit(database) == ProfileStorageResult::kOk && + storage.snapshot().generation == 2, + "successful header program was rolled back by a later read"); + + flash.fail_reads_after_header_program = false; + ProfileStorage recovered; + require(recovered.initialize(fake_io(), &recovered_database) && + recovered.snapshot().generation == 2 && + recovered_database.fallback_profiles[1] + .strong_rumble_scale == 17, + "committed header did not recover after transient read failure"); +} + +void test_payload_corruption_prevents_header_publication() { + erase_all(); + controller_profile_database_default(&database); + ProfileStorage storage; + require(storage.initialize(fake_io(), &database) && + storage.commit(database) == ProfileStorageResult::kOk, + "corruption baseline did not commit"); + const ProfileStorageSnapshot previous = storage.snapshot(); + const uint8_t target_bank = previous.active_bank ^ 1u; + const int programs_before_corruption = flash.successful_programs; + constexpr int kPayloadProgramCount = + (CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE + + PROFILE_STORAGE_PAGE_SIZE - 1) / + PROFILE_STORAGE_PAGE_SIZE; + + database.fallback_profiles[1].button_map[2] = 3; + flash.corrupt_next_program = true; + require(storage.commit(database) == ProfileStorageResult::kIoError && + flash.successful_programs == + programs_before_corruption + kPayloadProgramCount, + "corrupt payload programming reached the header program"); + for (size_t index = 0; index < PROFILE_STORAGE_RECORD_HEADER_SIZE; + ++index) { + require(flash.bytes[target_bank][index] == 0xff, + "rejected corrupt payload published a discoverable header"); + } + require(storage.snapshot().valid == previous.valid && + storage.snapshot().generation == previous.generation && + storage.snapshot().payload_crc == previous.payload_crc && + storage.snapshot().active_bank == previous.active_bank, + "rejected corrupt programming changed the storage snapshot"); + + ProfileStorage recovered; + require(recovered.initialize(fake_io(), &recovered_database) && + recovered.snapshot().generation == previous.generation && + recovered.snapshot().active_bank == previous.active_bank && + recovered_database.fallback_profiles[1].button_map[2] == 2, + "headerless corrupt payload was recovered"); +} + +} // namespace +int main() { + test_two_bank_recovery(); + test_interrupted_commit_retains_previous_bank(); + test_successful_header_program_is_commit_point(); + test_payload_corruption_prevents_header_publication(); + return 0; +} diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index b002165..5819074 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -1,7 +1,9 @@ from __future__ import annotations +import json import struct import zlib +from pathlib import Path import pytest @@ -56,7 +58,45 @@ class FakeDevice: ), ] self.pairing_generation = 4 + self.global_identity = config_manager.ControllerIdentity.global_fallback() + self.stable_identity = config_manager.ControllerIdentity( + True, + config_manager.TRANSPORT_CLASSIC, + 0, + bytes.fromhex("102030405060"), + 0x045E, + 0x02FD, + ) + self.profile_identities = [ + self.global_identity, + self.stable_identity, + ] + self.active_profiles = { + identity.to_bytes(): index + for identity, index in zip(self.profile_identities, (0, 1)) + } + default_profile = config_manager.ControllerProfile.default().to_bytes() + self.profiles = { + (identity.to_bytes(), index): default_profile + for identity in self.profile_identities + for index in range(config_manager.PROFILE_CAPACITY) + } + self.selected_profile = (self.global_identity.to_bytes(), 0) + self.profile_generation = 7 + self.profile_transaction_id = 0 + self.profile_transaction_identity = self.global_identity.to_bytes() + self.profile_transaction_index = 0 + self.profile_transaction_payload = bytearray() + self.profile_transaction_expected_size = 0 + self.profile_transaction_expected_crc = 0 + self.profile_transaction_status = config_manager.STATUS_OK + self.fail_profile_commit_status: int | None = None + self.bad_profile_response_crc = False self.requests: list[int] = [] + self.profile_chunk_sizes: list[int] = [] + self.pending_profile_mutation: tuple[int, bytes, int] | None = None + self.profile_transaction_pending_reads = 0 + self.profile_status_responses: list[tuple[int, int]] = [] def _pairing_payload(self) -> bytes: payload = bytearray([len(self.records), 0, 0, 0]) @@ -77,6 +117,71 @@ class FakeDevice: stored_crc, ) + def _profile_list_payload(self) -> bytes: + payload = bytearray([len(self.profile_identities)]) + for identity in self.profile_identities: + payload.extend(identity.to_bytes()) + payload.extend((self.active_profiles[identity.to_bytes()], 0)) + return bytes(payload) + + def _profile_transaction_payload(self) -> bytes: + stored = self.profiles.get( + ( + self.profile_transaction_identity, + self.profile_transaction_index, + ), + bytes(config_manager.PROFILE_SIZE), + ) + return struct.pack( + " None: + assert len(payload) == 19 + self.profile_transaction_id = struct.unpack_from(" None: + assert self.pending_profile_mutation is not None + operation, identity, profile_index = self.pending_profile_mutation + if self.fail_profile_commit_status is not None: + self.profile_transaction_status = self.fail_profile_commit_status + self.pending_profile_mutation = None + return + if operation == config_manager.OP_PROFILE_RESET: + indices = ( + range(config_manager.PROFILE_CAPACITY) + if profile_index == config_manager.PROFILE_NONE_BUTTON + else (profile_index,) + ) + default = config_manager.ControllerProfile.default().to_bytes() + for reset_index in indices: + self.profiles[(identity, reset_index)] = default + else: + assert operation == config_manager.OP_PROFILE_ACTIVATE + self.active_profiles[identity] = profile_index + self.profile_generation += 1 + self.profile_transaction_status = config_manager.STATUS_OK + self.pending_profile_mutation = None + def ctrl_transfer( self, bm_request_type: int, @@ -92,7 +197,9 @@ class FakeDevice: self.requests.append(request) if bm_request_type == 0xC0: if request == config_manager.OP_INFO: - return make_response(request, bytes([0, 2, 0, 2, 0, 0, 0, 2])) + return make_response( + request, bytes([0, 2, 0, 2, 0, 0, 0, 2]) + ) if request == config_manager.OP_CONFIGURATION_READ: return make_response( request, @@ -114,6 +221,44 @@ class FakeDevice: self._pairing_payload(), generation=self.pairing_generation, ) + if request == config_manager.OP_PROFILE_LIST: + return make_response( + request, + self._profile_list_payload(), + schema=config_manager.PROFILE_SCHEMA_VERSION, + generation=self.profile_generation, + ) + if request == config_manager.OP_PROFILE_READ: + response = bytearray( + make_response( + request, + self.profiles[self.selected_profile], + schema=config_manager.PROFILE_SCHEMA_VERSION, + generation=self.profile_generation, + ) + ) + if self.bad_profile_response_crc: + response[-1] ^= 1 + return bytes(response) + if request == config_manager.OP_PROFILE_TRANSACTION_STATUS: + if self.profile_transaction_status == config_manager.STATUS_PENDING: + if self.profile_transaction_pending_reads: + self.profile_transaction_pending_reads -= 1 + elif self.pending_profile_mutation is not None: + self._complete_profile_mutation() + self.profile_status_responses.append( + ( + self.profile_transaction_id, + self.profile_transaction_status, + ) + ) + return make_response( + request, + self._profile_transaction_payload(), + status=self.profile_transaction_status, + schema=config_manager.PROFILE_SCHEMA_VERSION, + generation=self.profile_generation, + ) raise AssertionError(f"unexpected IN request {request}") assert bm_request_type == 0x40 @@ -165,11 +310,138 @@ class FakeDevice: elif request == config_manager.OP_PAIRING_CLEAR: self.records = [] self.pairing_generation += 1 + elif request == config_manager.OP_PROFILE_SELECT: + assert len(payload) == 15 + self.selected_profile = (payload[:14], payload[14]) + assert self.selected_profile in self.profiles + elif request == config_manager.OP_PROFILE_BEGIN: + assert len(payload) == 28 + self.profile_transaction_id = struct.unpack_from(" config_manager.ControllerProfile: + return config_manager.ControllerProfile( + button_map=( + 1, + 0, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 15, + config_manager.PROFILE_NONE_BUTTON, + ), + left_stick=config_manager.StickConfig( + -123, 456, 1000, 30000, 384, True, False + ), + right_stick=config_manager.StickConfig( + 789, -321, 500, 31000, 192, False, True + ), + left_trigger=config_manager.TriggerConfig(100, 65000, 320, 32000), + right_trigger=config_manager.TriggerConfig(200, 64000, 224, 33000), + weak_rumble_scale=77, + strong_rumble_scale=201, + confirmation_policy=2, + switching_chord=(1 << 6) | (1 << 7), + macro_trigger=0, + macro_cancel=1, + macro_steps=( + config_manager.MacroStep( + 0, + config_manager.MACRO_OVERRIDE_MASK, + config_manager.PROFILE_MAXIMUM_WAIT_MS, + (1 << 0) | (1 << 12), + -32768, + 32767, + -1000, + 1000, + 12345, + 54321, + ), + config_manager.MacroStep.end(), + ), + turbo_modes=(0, 1, 2) + (0,) * 13, + ) + + def test_response_validation() -> None: payload = make_response(config_manager.OP_INFO, b"12345678") envelope = config_manager.parse_response(payload, config_manager.OP_INFO) @@ -205,6 +477,352 @@ def test_configuration_transaction_and_reset() -> None: assert config_manager.read_configuration(device).pairing_window_seconds == 60 +def test_identity_and_profile_binary_json_round_trip() -> None: + identity = config_manager.ControllerIdentity( + True, + config_manager.TRANSPORT_BLE, + 3, + bytes.fromhex("A1B2C3D4E5F6"), + 0x1234, + 0xABCD, + ) + encoded_identity = identity.to_bytes() + assert encoded_identity == bytes.fromhex( + "01020300A1B2C3D4E5F63412CDAB" + ) + assert config_manager.ControllerIdentity.from_bytes(encoded_identity) == identity + assert ( + config_manager.ControllerIdentity.global_fallback().to_bytes() + == bytes(config_manager.CONTROLLER_IDENTITY_SIZE) + ) + malformed_identity = bytearray(encoded_identity) + malformed_identity[3] = 1 + with pytest.raises(config_manager.ConfigManagerError): + config_manager.ControllerIdentity.from_bytes(malformed_identity) + + profile = custom_profile() + encoded = profile.to_bytes() + assert len(encoded) == config_manager.PROFILE_SIZE + assert struct.unpack_from(" None: + device = FakeDevice() + entries = config_manager.list_profiles(device) + assert entries == ( + config_manager.ProfileListEntry(device.global_identity, 0), + config_manager.ProfileListEntry(device.stable_identity, 1), + ) + assert ( + config_manager.read_profile(device, device.stable_identity, 1) + == config_manager.ControllerProfile.default() + ) + assert device.requests[-2:] == [ + config_manager.OP_PROFILE_SELECT, + config_manager.OP_PROFILE_READ, + ] + + profile = custom_profile() + status = config_manager.write_profile( + device, device.stable_identity, 2, profile, 1.0 + ) + assert status.status == config_manager.STATUS_OK + assert status.stored_generation == 8 + assert device.profile_chunk_sizes == [40, 40, 40, 40, 40, 40, 16] + assert config_manager.OP_PROFILE_TRANSACTION_STATUS in device.requests + assert ( + config_manager.read_profile(device, device.stable_identity, 2) + == profile + ) + + +def test_profile_reset_and_activate_wait_for_correlated_transactions( + monkeypatch: pytest.MonkeyPatch, +) -> None: + device = FakeDevice() + generated_ids = iter((0, 0xA5A55A5A)) + monkeypatch.setattr( + config_manager.secrets, "randbits", lambda _bits: next(generated_ids) + ) + identity = device.stable_identity + profile_key = (identity.to_bytes(), 2) + device.profiles[profile_key] = custom_profile().to_bytes() + + reset = config_manager.reset_profile(device, identity, 2, 1.0) + + assert reset.transaction_id == device.profile_transaction_id == 1 + assert reset.status == config_manager.STATUS_OK + assert reset.stored_generation == 8 + assert device.profile_status_responses == [ + (1, config_manager.STATUS_PENDING), + (1, config_manager.STATUS_OK), + ] + assert ( + device.profiles[profile_key] + == config_manager.ControllerProfile.default().to_bytes() + ) + + device.profile_status_responses.clear() + activated = config_manager.activate_profile(device, identity, 3, 1.0) + + assert ( + activated.transaction_id + == device.profile_transaction_id + == 0xA5A55A5A + ) + assert activated.status == config_manager.STATUS_OK + assert activated.stored_generation == 9 + assert device.profile_status_responses == [ + (0xA5A55A5A, config_manager.STATUS_PENDING), + (0xA5A55A5A, config_manager.STATUS_OK), + ] + assert device.active_profiles[identity.to_bytes()] == 3 + + +def test_profile_cli_surfaces_late_storage_failure( + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], +) -> None: + device = FakeDevice() + device.fail_profile_commit_status = 8 + monkeypatch.setattr(config_manager, "_candidate_devices", lambda: [device]) + previous_active = device.active_profiles[device.stable_identity.to_bytes()] + + assert ( + config_manager.main( + ["profiles", "activate", "4", "--identity", "1"] + ) + == 1 + ) + + output = capsys.readouterr() + assert output.out == "" + assert "storage failure" in output.err + assert ( + device.active_profiles[device.stable_identity.to_bytes()] + == previous_active + ) + assert device.profile_status_responses == [ + (device.profile_transaction_id, config_manager.STATUS_PENDING), + (device.profile_transaction_id, 8), + ] + + +def test_profile_cli_json_round_trip_activate_and_reset( + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], + tmp_path: Path, +) -> None: + device = FakeDevice() + monkeypatch.setattr(config_manager, "_candidate_devices", lambda: [device]) + export_path = tmp_path / "profile.json" + + assert config_manager.main(["profiles", "list"]) == 0 + output = capsys.readouterr().out + assert "0: global fallback (active profile 1)" in output + assert "1: Classic 10:20:30:40:50:60" in output + + device.profiles[(device.stable_identity.to_bytes(), 1)] = ( + custom_profile().to_bytes() + ) + assert ( + config_manager.main( + [ + "profiles", + "export", + "2", + str(export_path), + "--identity", + "1", + ] + ) + == 0 + ) + _ = capsys.readouterr() + exported = config_manager.ControllerProfile.from_json( + export_path.read_text(encoding="utf-8") + ) + assert exported == custom_profile() + + device.profiles[(device.stable_identity.to_bytes(), 1)] = ( + config_manager.ControllerProfile.default().to_bytes() + ) + assert ( + config_manager.main( + [ + "profiles", + "import", + "2", + str(export_path), + "--identity", + "1", + ] + ) + == 0 + ) + assert ( + device.profiles[(device.stable_identity.to_bytes(), 1)] + == custom_profile().to_bytes() + ) + _ = capsys.readouterr() + + assert ( + config_manager.main( + ["profiles", "activate", "4", "--identity", "1"] + ) + == 0 + ) + assert device.active_profiles[device.stable_identity.to_bytes()] == 3 + _ = capsys.readouterr() + + before_reset_requests = len(device.requests) + assert ( + config_manager.main( + ["profiles", "reset", "2", "--identity", "1"] + ) + == 2 + ) + assert "requires --yes" in capsys.readouterr().err + assert len(device.requests) == before_reset_requests + + assert ( + config_manager.main( + [ + "profiles", + "reset", + "2", + "--identity", + "1", + "--yes", + ] + ) + == 0 + ) + assert ( + device.profiles[(device.stable_identity.to_bytes(), 1)] + == config_manager.ControllerProfile.default().to_bytes() + ) + _ = capsys.readouterr() + assert ( + config_manager.main( + [ + "profiles", + "reset", + "all", + "--identity", + "1", + "--yes", + ] + ) + == 0 + ) + + +def test_malformed_profiles_are_rejected_before_usb( + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], + tmp_path: Path, +) -> None: + malformed_binary = bytearray(config_manager.ControllerProfile.default().to_bytes()) + malformed_binary[75] = 1 + with pytest.raises( + config_manager.ConfigManagerError, match="reserved fields" + ): + config_manager.ControllerProfile.from_bytes(malformed_binary) + + profile_object = config_manager.ControllerProfile.default().to_json_object() + del profile_object["turbo"] + missing_path = tmp_path / "missing.json" + missing_path.write_text(json.dumps(profile_object), encoding="utf-8") + + profile_object = config_manager.ControllerProfile.default().to_json_object() + profile_object["reserved"] = 0 + unknown_path = tmp_path / "unknown.json" + unknown_path.write_text(json.dumps(profile_object), encoding="utf-8") + + profile_object = config_manager.ControllerProfile.default().to_json_object() + profile_object["rumble"]["confirmation_policy"] = "invalid" + enum_path = tmp_path / "enum.json" + enum_path.write_text(json.dumps(profile_object), encoding="utf-8") + + profile_object = config_manager.ControllerProfile.default().to_json_object() + profile_object["sticks"]["left"]["outer_saturation"] = 0 + range_path = tmp_path / "range.json" + range_path.write_text(json.dumps(profile_object), encoding="utf-8") + + usb_lookups = 0 + + def candidates() -> list[FakeDevice]: + nonlocal usb_lookups + usb_lookups += 1 + return [FakeDevice()] + + monkeypatch.setattr(config_manager, "_candidate_devices", candidates) + for path in (missing_path, unknown_path, enum_path, range_path): + assert ( + config_manager.main(["profiles", "import", "1", str(path)]) == 1 + ) + assert "error:" in capsys.readouterr().err + assert usb_lookups == 0 + + +def test_profile_crc_status_failures_and_identity_bounds( + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], + tmp_path: Path, +) -> None: + device = FakeDevice() + device.bad_profile_response_crc = True + with pytest.raises( + config_manager.ConfigManagerError, match="response CRC mismatch" + ): + config_manager.read_profile(device, device.global_identity, 0) + + failing_device = FakeDevice() + failing_device.fail_profile_commit_status = 6 + with pytest.raises(config_manager.ConfigManagerError, match="CRC mismatch"): + config_manager.write_profile( + failing_device, + failing_device.global_identity, + 0, + custom_profile(), + 1.0, + ) + + bounded_device = FakeDevice() + monkeypatch.setattr( + config_manager, "_candidate_devices", lambda: [bounded_device] + ) + assert ( + config_manager.main( + [ + "profiles", + "export", + "1", + str(tmp_path / "unused.json"), + "--identity", + "2", + ] + ) + == 1 + ) + assert "identity index 2 is out of range" in capsys.readouterr().err + assert config_manager.OP_PROFILE_SELECT not in bounded_device.requests + + def test_status_and_pairing_commands( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], diff --git a/tests/test_controller_profile_native.py b/tests/test_controller_profile_native.py new file mode 100644 index 0000000..3cf5575 --- /dev/null +++ b/tests/test_controller_profile_native.py @@ -0,0 +1,30 @@ +import shutil +import subprocess +from pathlib import Path + + +def test_controller_profile_native(tmp_path: Path) -> None: + root = Path(__file__).resolve().parents[1] + compiler = shutil.which("c++") or shutil.which("g++") + assert compiler is not None, "a host C++ compiler is required" + + executable = tmp_path / "controller_profile_test" + subprocess.run( + [ + compiler, + "-std=c++17", + "-Wall", + "-Wextra", + "-Werror", + "-pedantic", + f"-I{root}", + str(root / "tests" / "controller_profile_test.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + "-o", + str(executable), + ], + check=True, + cwd=root, + ) + subprocess.run([str(executable)], check=True, cwd=root) diff --git a/tests/test_profile_service_native.py b/tests/test_profile_service_native.py new file mode 100644 index 0000000..20fd48b --- /dev/null +++ b/tests/test_profile_service_native.py @@ -0,0 +1,33 @@ +import shutil +import subprocess +from pathlib import Path + + +def test_profile_service_native(tmp_path: Path) -> None: + root = Path(__file__).resolve().parents[1] + compiler = shutil.which("c++") or shutil.which("g++") + assert compiler is not None, "a host C++ compiler is required" + + executable = tmp_path / "profile_service_test" + subprocess.run( + [ + compiler, + "-std=c++17", + "-Wall", + "-Wextra", + "-Werror", + "-pedantic", + f"-I{root / 'tests' / 'bluepad32_native_stubs'}", + f"-I{root}", + str(root / "tests" / "profile_service_test.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "profile_storage.cpp"), + str(root / "profile_service.cpp"), + "-o", + str(executable), + ], + check=True, + cwd=root, + ) + subprocess.run([str(executable)], check=True, cwd=root) diff --git a/tests/test_profile_storage_native.py b/tests/test_profile_storage_native.py new file mode 100644 index 0000000..80e204f --- /dev/null +++ b/tests/test_profile_storage_native.py @@ -0,0 +1,31 @@ +import shutil +import subprocess +from pathlib import Path + + +def test_profile_storage_native(tmp_path: Path) -> None: + root = Path(__file__).resolve().parents[1] + compiler = shutil.which("c++") or shutil.which("g++") + assert compiler is not None, "a host C++ compiler is required" + + executable = tmp_path / "profile_storage_test" + subprocess.run( + [ + compiler, + "-std=c++17", + "-Wall", + "-Wextra", + "-Werror", + "-pedantic", + f"-I{root}", + str(root / "tests" / "profile_storage_test.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "profile_storage.cpp"), + "-o", + str(executable), + ], + check=True, + cwd=root, + ) + subprocess.run([str(executable)], check=True, cwd=root) diff --git a/tests/usb_configuration_management_test.cpp b/tests/usb_configuration_management_test.cpp index 1ddf306..093c8b3 100644 --- a/tests/usb_configuration_management_test.cpp +++ b/tests/usb_configuration_management_test.cpp @@ -11,6 +11,9 @@ namespace { Bluepad32PairingSnapshot current_pairings{}; ConfigurationServiceSnapshot current_configuration{}; +ProfileServiceListSnapshot current_profile_list{}; +ProfileServiceSelectedSnapshot current_profile_selected{}; +ProfileServiceTransactionSnapshot current_profile_transaction{}; bool refresh_requested = false; bool clear_requested = false; std::vector control_payload; @@ -20,6 +23,16 @@ uint32_t append_transaction_id = 0; uint32_t commit_transaction_id = 0; size_t append_offset = 0; std::vector appended_bytes; +ControllerIdentity profile_identity{}; +uint8_t profile_index = 0; +uint16_t profile_schema = 0; +size_t profile_size = 0; +uint32_t profile_crc = 0; +bool profile_reset_requested = false; +uint32_t profile_reset_transaction_id = 0; +uint32_t profile_commit_transaction_id = 0; +bool profile_activate_requested = false; +uint32_t profile_activate_transaction_id = 0; void require(bool condition, const char* message) { if (!condition) { @@ -42,6 +55,13 @@ void write_u32(std::vector* output, size_t offset, (*output)[offset + 3] = static_cast(value >> 24); } +uint32_t read_u32(const std::vector& input, size_t offset) { + return static_cast(input[offset]) | + (static_cast(input[offset + 1]) << 8) | + (static_cast(input[offset + 2]) << 16) | + (static_cast(input[offset + 3]) << 24); +} + std::vector make_request( UsbConfigurationManagement::Operation operation, const std::vector& payload) { @@ -213,6 +233,173 @@ void test_vendor_requests() { "request with invalid magic was accepted"); } +void test_profile_vendor_requests() { + using namespace UsbConfigurationManagement; + ControllerIdentity expected_identity{}; + expected_identity.stable = true; + expected_identity.transport = ControllerTransport::kClassic; + expected_identity.address[5] = 7; + expected_identity.vendor_id = 0x057e; + expected_identity.product_id = 0x2009; + + current_profile_list = {}; + current_profile_list.metadata.state = ProfileServiceState::kReady; + current_profile_list.metadata.generation = 9; + current_profile_list.count = 2; + current_profile_list.rows[0].identity = controller_identity_global(); + current_profile_list.rows[1].identity = expected_identity; + current_profile_list.rows[1].active_profile = 2; + tusb_control_request_t request = setup_request( + Operation::kProfileList, TUSB_DIR_IN, kMaximumResponseSize); + require(tud_vendor_control_xfer_cb( + 0, CONTROL_STAGE_SETUP, &request) && + control_payload.size() == kResponseHeaderSize + 33 && + control_payload[5] == + static_cast(Operation::kProfileList) && + control_payload[10] == CONTROLLER_PROFILE_SCHEMA_VERSION && + control_payload[kResponseHeaderSize] == 2 && + control_payload[kResponseHeaderSize + 31] == 2, + "profile list response was not encoded"); + + current_profile_selected = {}; + current_profile_selected.metadata.state = + ProfileServiceState::kReady; + current_profile_selected.metadata.generation = 9; + current_profile_selected.valid = true; + current_profile_selected.status = + ConfigurationTransactionStatus::kCommitted; + current_profile_selected.identity = expected_identity; + current_profile_selected.profile_index = 2; + current_profile_selected.profile = + controller_profile_default(expected_identity, 2); + request = setup_request( + Operation::kProfileRead, TUSB_DIR_IN, kMaximumResponseSize); + require(tud_vendor_control_xfer_cb( + 0, CONTROL_STAGE_SETUP, &request) && + control_payload.size() == + kResponseHeaderSize + + CONTROLLER_PROFILE_ENCODED_SIZE && + control_payload[kResponseHeaderSize] == 1 && + control_payload[kResponseHeaderSize + 2] == 0 && + control_payload[kResponseHeaderSize + 3] == 1, + "selected profile response was not encoded"); + + current_profile_transaction = {}; + current_profile_transaction.metadata.state = + ProfileServiceState::kReady; + current_profile_transaction.metadata.generation = 9; + current_profile_transaction.transaction.transaction_id = 0x01020304; + current_profile_transaction.transaction.status = + ConfigurationTransactionStatus::kPending; + request = setup_request( + Operation::kProfileTransactionStatus, TUSB_DIR_IN, + kMaximumResponseSize); + require(tud_vendor_control_xfer_cb( + 0, CONTROL_STAGE_SETUP, &request) && + control_payload.size() == kResponseHeaderSize + 20 && + control_payload[6] == + static_cast(Status::kPending) && + read_u32(control_payload, kResponseHeaderSize) == + 0x01020304, + "pending profile transaction status lost its transaction ID"); + + current_profile_transaction.transaction.status = + ConfigurationTransactionStatus::kCommitted; + current_profile_transaction.transaction.stored_generation = + 0x11223344; + current_profile_transaction.transaction.stored_crc = 0xaabbccdd; + require(tud_vendor_control_xfer_cb( + 0, CONTROL_STAGE_SETUP, &request) && + control_payload[6] == static_cast(Status::kOk) && + read_u32(control_payload, kResponseHeaderSize) == + 0x01020304 && + read_u32(control_payload, kResponseHeaderSize + 12) == + 0x11223344 && + read_u32(control_payload, kResponseHeaderSize + 16) == + 0xaabbccdd, + "final profile transaction status lost its commit result"); + + std::vector identity_payload(15); + require(controller_identity_encode( + expected_identity, identity_payload.data(), + CONTROLLER_IDENTITY_ENCODED_SIZE), + "profile test identity did not encode"); + identity_payload[14] = 2; + perform_out(Operation::kProfileSelect, identity_payload); + require(controller_identity_equal(expected_identity, + profile_identity) && + profile_index == 2, + "profile selection was not dispatched"); + + std::vector begin(28); + write_u32(&begin, 0, 0x55667788); + require(controller_identity_encode( + expected_identity, &begin[4], + CONTROLLER_IDENTITY_ENCODED_SIZE), + "profile begin identity did not encode"); + begin[18] = 1; + write_u16(&begin, 20, CONTROLLER_PROFILE_SCHEMA_VERSION); + write_u16(&begin, 22, CONTROLLER_PROFILE_ENCODED_SIZE); + write_u32(&begin, 24, 0xaabbccdd); + perform_out(Operation::kProfileBegin, begin); + require(begin_transaction_id == 0x55667788 && + profile_index == 1 && + profile_schema == CONTROLLER_PROFILE_SCHEMA_VERSION && + profile_size == CONTROLLER_PROFILE_ENCODED_SIZE && + profile_crc == 0xaabbccdd, + "profile begin was not dispatched"); + + std::vector chunk(48); + write_u32(&chunk, 0, 0x55667788); + write_u16(&chunk, 4, 0); + write_u16(&chunk, 6, 40); + perform_out(Operation::kProfileChunk, chunk); + require(append_transaction_id == 0x55667788 && + append_offset == 0 && appended_bytes.size() == 40, + "profile chunk was not dispatched"); + + std::vector commit(4); + write_u32(&commit, 0, 0x55667788); + perform_out(Operation::kProfileCommit, commit); + require(profile_commit_transaction_id == 0x55667788, + "profile commit was not dispatched"); + + std::vector mutation(19); + write_u32(&mutation, 0, 0x10203040); + require(controller_identity_encode( + expected_identity, &mutation[4], + CONTROLLER_IDENTITY_ENCODED_SIZE), + "profile mutation identity did not encode"); + mutation[18] = CONTROLLER_PROFILE_ALL; + perform_out(Operation::kProfileReset, mutation); + require(profile_reset_requested && + profile_reset_transaction_id == 0x10203040, + "profile reset transaction was not dispatched"); + write_u32(&mutation, 0, 0x50607080); + mutation[18] = 3; + perform_out(Operation::kProfileActivate, mutation); + require(profile_activate_requested && profile_index == 3 && + profile_activate_transaction_id == 0x50607080, + "profile activation transaction was not dispatched"); + + write_u32(&mutation, 0, 0); + perform_out(Operation::kProfileActivate, mutation, false); + request = setup_request( + Operation::kProfileReset, TUSB_DIR_OUT, kRequestHeaderSize + 15); + require(!tud_vendor_control_xfer_cb( + 0, CONTROL_STAGE_SETUP, &request), + "legacy profile reset payload was accepted"); + + begin[19] = 1; + perform_out(Operation::kProfileBegin, begin, false); + request = setup_request( + Operation::kProfileSelect, TUSB_DIR_OUT, + kRequestHeaderSize + 14); + require(!tud_vendor_control_xfer_cb( + 0, CONTROL_STAGE_SETUP, &request), + "short profile selection request was accepted"); +} + } // namespace uint32_t configuration_crc32(const uint8_t* data, size_t size) { @@ -256,6 +443,75 @@ ConfigurationTransactionStatus configuration_service_reset(uint32_t) { return ConfigurationTransactionStatus::kPending; } +ConfigurationTransactionStatus profile_service_select( + const ControllerIdentity& identity, uint8_t selected_profile) { + profile_identity = identity; + profile_index = selected_profile; + return ConfigurationTransactionStatus::kPending; +} + +ConfigurationTransactionStatus profile_service_begin( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t selected_profile, uint16_t schema_version, + size_t payload_size, uint32_t payload_crc) { + begin_transaction_id = transaction_id; + profile_identity = identity; + profile_index = selected_profile; + profile_schema = schema_version; + profile_size = payload_size; + profile_crc = payload_crc; + return ConfigurationTransactionStatus::kReceiving; +} + +ConfigurationTransactionStatus profile_service_append( + uint32_t transaction_id, size_t offset, const uint8_t* data, + size_t size) { + append_transaction_id = transaction_id; + append_offset = offset; + appended_bytes.assign(data, data + size); + return ConfigurationTransactionStatus::kReceiving; +} + +ConfigurationTransactionStatus profile_service_commit( + uint32_t transaction_id) { + profile_commit_transaction_id = transaction_id; + return ConfigurationTransactionStatus::kPending; +} + +ConfigurationTransactionStatus profile_service_reset( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t selected_profile) { + profile_reset_transaction_id = transaction_id; + profile_identity = identity; + profile_index = selected_profile; + profile_reset_requested = true; + return ConfigurationTransactionStatus::kPending; +} + +ConfigurationTransactionStatus profile_service_activate( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t selected_profile) { + profile_activate_transaction_id = transaction_id; + profile_identity = identity; + profile_index = selected_profile; + profile_activate_requested = true; + return ConfigurationTransactionStatus::kPending; +} + +void profile_service_list_snapshot(ProfileServiceListSnapshot* output) { + *output = current_profile_list; +} + +void profile_service_selected_snapshot( + ProfileServiceSelectedSnapshot* output) { + *output = current_profile_selected; +} + +void profile_service_transaction_snapshot( + ProfileServiceTransactionSnapshot* output) { + *output = current_profile_transaction; +} + void bluepad32_input_backend_request_pairing_snapshot() { refresh_requested = true; } @@ -288,6 +544,8 @@ bool tud_control_status(uint8_t, const tusb_control_request_t*) { } #include "../adapter_configuration.cpp" +#include "../controller_identity.cpp" +#include "../controller_profile.cpp" #include "../usb_configuration_management.cpp" int main() { @@ -297,5 +555,6 @@ int main() { test_envelope_encoding(); test_pairing_encoding(); test_vendor_requests(); + test_profile_vendor_requests(); return 0; } diff --git a/usb_configuration_management.cpp b/usb_configuration_management.cpp index 697cdb5..517651e 100644 --- a/usb_configuration_management.cpp +++ b/usb_configuration_management.cpp @@ -61,17 +61,39 @@ Status transaction_status(ConfigurationTransactionStatus status) { } return Status::kStorageError; } +Status profile_service_status(const ProfileServiceMetadata& metadata) { + if (metadata.state == ProfileServiceState::kLoading) { + return Status::kPending; + } + if (metadata.state == ProfileServiceState::kStorageError) { + return Status::kStorageError; + } + return Status::kOk; +} + bool valid_out_size(Operation operation, size_t size) { switch (operation) { case Operation::kConfigurationBegin: return size == kRequestHeaderSize + 12; + case Operation::kProfileBegin: + return size == kRequestHeaderSize + 28; case Operation::kConfigurationChunk: return size > kRequestHeaderSize + 8 && size <= kMaximumRequestSize; + case Operation::kProfileChunk: + return size > kRequestHeaderSize + 8 && + size <= kMaximumRequestSize; case Operation::kConfigurationCommit: case Operation::kConfigurationReset: return size == kRequestHeaderSize + 4; + case Operation::kProfileCommit: + return size == kRequestHeaderSize + 4; + case Operation::kProfileSelect: + return size == kRequestHeaderSize + 15; + case Operation::kProfileReset: + case Operation::kProfileActivate: + return size == kRequestHeaderSize + 19; case Operation::kPairingRefresh: case Operation::kPairingClear: return size == kRequestHeaderSize; @@ -218,6 +240,74 @@ size_t encode_pairing_snapshot(const Bluepad32PairingSnapshot& snapshot, payload, offset, output, output_size); } +size_t encode_profile_list(const ProfileServiceListSnapshot& snapshot, + uint8_t* output, size_t output_size) { + if (snapshot.count > PROFILE_SERVICE_LIST_CAPACITY) { + return 0; + } + uint8_t payload[kProfileListPayloadSize]{}; + payload[0] = snapshot.count; + size_t offset = 1; + for (uint8_t index = 0; index < snapshot.count; ++index) { + if (!controller_identity_encode(snapshot.rows[index].identity, + &payload[offset], + CONTROLLER_IDENTITY_ENCODED_SIZE) || + snapshot.rows[index].active_profile >= + CONTROLLER_PROFILE_COUNT) { + return 0; + } + payload[offset + 14] = snapshot.rows[index].active_profile; + offset += 16; + } + return encode_response( + Operation::kProfileList, profile_service_status(snapshot.metadata), + 0, CONTROLLER_PROFILE_SCHEMA_VERSION, snapshot.metadata.generation, + payload, offset, output, output_size); +} + +size_t encode_profile_read(const ProfileServiceSelectedSnapshot& snapshot, + uint8_t* output, size_t output_size) { + Status status = profile_service_status(snapshot.metadata); + if (status == Status::kOk) { + status = transaction_status(snapshot.status); + } + uint8_t payload[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + size_t payload_size = 0; + if (snapshot.valid) { + if (!controller_profile_encode(snapshot.profile, payload, + sizeof(payload))) { + return 0; + } + payload_size = sizeof(payload); + } + return encode_response( + Operation::kProfileRead, status, 0, + CONTROLLER_PROFILE_SCHEMA_VERSION, snapshot.metadata.generation, + payload, payload_size, output, output_size); +} + +size_t encode_profile_transaction( + const ProfileServiceTransactionSnapshot& snapshot, + uint8_t* output, size_t output_size) { + const ConfigurationTransactionSnapshot& transaction = + snapshot.transaction; + uint8_t payload[20]{}; + write_u32(&payload[0], transaction.transaction_id); + write_u16(&payload[4], transaction.received_size); + write_u16(&payload[6], transaction.expected_size); + write_u32(&payload[8], transaction.expected_crc); + write_u32(&payload[12], transaction.stored_generation); + write_u32(&payload[16], transaction.stored_crc); + Status status = profile_service_status(snapshot.metadata); + if (status == Status::kOk) { + status = transaction_status(transaction.status); + } + return encode_response( + Operation::kProfileTransactionStatus, status, 0, + CONTROLLER_PROFILE_SCHEMA_VERSION, snapshot.metadata.generation, + payload, sizeof(payload), output, output_size); +} + } // namespace UsbConfigurationManagement namespace { @@ -286,6 +376,96 @@ bool process_out_request() { (static_cast(payload[2]) << 16) | (static_cast(payload[3]) << 24)); return true; + case Operation::kProfileSelect: { + ControllerIdentity identity{}; + if (payload[14] >= CONTROLLER_PROFILE_COUNT || + !controller_identity_decode( + payload, CONTROLLER_IDENTITY_ENCODED_SIZE, &identity)) { + return false; + } + const ConfigurationTransactionStatus status = + profile_service_select(identity, payload[14]); + return status == ConfigurationTransactionStatus::kCommitted || + status == ConfigurationTransactionStatus::kPending; + } + case Operation::kProfileBegin: { + ControllerIdentity identity{}; + if (payload[19] != 0 || + !controller_identity_decode( + &payload[4], CONTROLLER_IDENTITY_ENCODED_SIZE, + &identity)) { + return false; + } + profile_service_begin( + static_cast(payload[0]) | + (static_cast(payload[1]) << 8) | + (static_cast(payload[2]) << 16) | + (static_cast(payload[3]) << 24), + identity, payload[18], + static_cast(payload[20] | + (payload[21] << 8)), + static_cast(payload[22] | + (payload[23] << 8)), + static_cast(payload[24]) | + (static_cast(payload[25]) << 8) | + (static_cast(payload[26]) << 16) | + (static_cast(payload[27]) << 24)); + return true; + } + case Operation::kProfileChunk: { + const uint16_t chunk_size = + static_cast(payload[6] | + (payload[7] << 8)); + if (request.payload_size != 8 + chunk_size || + chunk_size > kMaximumChunkSize) { + return false; + } + profile_service_append( + static_cast(payload[0]) | + (static_cast(payload[1]) << 8) | + (static_cast(payload[2]) << 16) | + (static_cast(payload[3]) << 24), + static_cast(payload[4] | + (payload[5] << 8)), + &payload[8], chunk_size); + return true; + } + case Operation::kProfileCommit: + profile_service_commit( + static_cast(payload[0]) | + (static_cast(payload[1]) << 8) | + (static_cast(payload[2]) << 16) | + (static_cast(payload[3]) << 24)); + return true; + case Operation::kProfileReset: + case Operation::kProfileActivate: { + const uint32_t transaction_id = + static_cast(payload[0]) | + (static_cast(payload[1]) << 8) | + (static_cast(payload[2]) << 16) | + (static_cast(payload[3]) << 24); + ControllerIdentity identity{}; + if (transaction_id == 0 || + (request.operation == Operation::kProfileActivate && + payload[18] >= CONTROLLER_PROFILE_COUNT) || + (request.operation == Operation::kProfileReset && + payload[18] != CONTROLLER_PROFILE_ALL && + payload[18] >= CONTROLLER_PROFILE_COUNT) || + !controller_identity_decode( + &payload[4], CONTROLLER_IDENTITY_ENCODED_SIZE, + &identity)) { + return false; + } + const ConfigurationTransactionStatus status = + request.operation == Operation::kProfileReset + ? profile_service_reset( + transaction_id, identity, payload[18]) + : profile_service_activate( + transaction_id, identity, payload[18]); + return status == ConfigurationTransactionStatus::kPending || + status == ConfigurationTransactionStatus::kUnchanged || + status == ConfigurationTransactionStatus::kCommitted; + } case Operation::kPairingRefresh: bluepad32_input_backend_request_pairing_snapshot(); return true; @@ -367,6 +547,27 @@ extern "C" bool tud_vendor_control_xfer_cb( snapshot, response, sizeof(response)); break; } + case Operation::kProfileList: { + ProfileServiceListSnapshot snapshot{}; + profile_service_list_snapshot(&snapshot); + response_size = encode_profile_list( + snapshot, response, sizeof(response)); + break; + } + case Operation::kProfileRead: { + ProfileServiceSelectedSnapshot snapshot{}; + profile_service_selected_snapshot(&snapshot); + response_size = encode_profile_read( + snapshot, response, sizeof(response)); + break; + } + case Operation::kProfileTransactionStatus: { + ProfileServiceTransactionSnapshot snapshot{}; + profile_service_transaction_snapshot(&snapshot); + response_size = encode_profile_transaction( + snapshot, response, sizeof(response)); + break; + } default: return false; } diff --git a/usb_configuration_management.h b/usb_configuration_management.h index 738a132..21e07f5 100644 --- a/usb_configuration_management.h +++ b/usb_configuration_management.h @@ -5,6 +5,7 @@ #include "bluepad32_input_backend.h" #include "configuration_service.h" +#include "profile_service.h" namespace UsbConfigurationManagement { @@ -16,11 +17,14 @@ constexpr size_t kResponseHeaderSize = 20; constexpr size_t kPairingRecordSize = 8; constexpr size_t kPairingPayloadHeaderSize = 4; constexpr size_t kMaximumRequestSize = 64; +constexpr size_t kProfileListPayloadSize = + 1 + PROFILE_SERVICE_LIST_CAPACITY * 16; constexpr size_t kMaximumResponseSize = - kResponseHeaderSize + kPairingPayloadHeaderSize + - BLUEPAD32_PAIRING_RECORD_CAPACITY * kPairingRecordSize; + kResponseHeaderSize + kProfileListPayloadSize; constexpr size_t kMaximumChunkSize = kMaximumRequestSize - kRequestHeaderSize - 8; +static_assert(kMaximumResponseSize == 293, + "profile list no longer fits the EP0 response buffer"); enum class Operation : uint8_t { kInfo = 0x01, @@ -33,6 +37,15 @@ enum class Operation : uint8_t { kPairingRead = 0x20, kPairingRefresh = 0x21, kPairingClear = 0x22, + kProfileList = 0x30, + kProfileSelect = 0x31, + kProfileRead = 0x32, + kProfileBegin = 0x33, + kProfileChunk = 0x34, + kProfileCommit = 0x35, + kProfileReset = 0x36, + kProfileActivate = 0x37, + kProfileTransactionStatus = 0x38, }; enum class Status : uint8_t { @@ -61,5 +74,12 @@ size_t encode_response(Operation operation, Status status, uint8_t flags, uint8_t* output, size_t output_size); size_t encode_pairing_snapshot(const Bluepad32PairingSnapshot& snapshot, uint8_t* output, size_t output_size); +size_t encode_profile_list(const ProfileServiceListSnapshot& snapshot, + uint8_t* output, size_t output_size); +size_t encode_profile_read(const ProfileServiceSelectedSnapshot& snapshot, + uint8_t* output, size_t output_size); +size_t encode_profile_transaction( + const ProfileServiceTransactionSnapshot& snapshot, + uint8_t* output, size_t output_size); } // namespace UsbConfigurationManagement From cfec816dace59a121a614fbcea7afe5cfbb050c8 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 2 Sep 2026 17:35:13 -0600 Subject: [PATCH 2/5] Apply persistent controller profiles --- CMakeLists.txt | 2 + controller_profile.cpp | 46 ++- controller_profile.h | 12 +- controller_profile_runtime.cpp | 131 ++++++ controller_profile_runtime.h | 34 ++ controller_profile_transform.cpp | 344 ++++++++++++++++ controller_profile_transform.h | 31 ++ profile_service.cpp | 83 +++- profile_service.h | 14 +- profile_storage.cpp | 6 +- src/switch_pico_bridge/config_manager.py | 78 +++- switch-pico.cpp | 45 +- switch_pro_driver.cpp | 16 +- switch_pro_driver.h | 7 +- tests/controller_profile_legacy_fixtures.h | 63 +++ tests/controller_profile_runtime_test.cpp | 273 +++++++++++++ tests/controller_profile_test.cpp | 138 ++++++- tests/controller_profile_transform_test.cpp | 385 ++++++++++++++++++ tests/profile_service_test.cpp | 37 ++ tests/profile_storage_test.cpp | 258 ++++++++++++ tests/switch_pro_driver_context_test.cpp | 61 ++- tests/test_config_manager.py | 141 ++++++- .../test_controller_profile_runtime_native.py | 32 ++ ...est_controller_profile_transform_native.py | 31 ++ tests/usb_configuration_management_test.cpp | 7 +- 25 files changed, 2179 insertions(+), 96 deletions(-) create mode 100644 controller_profile_runtime.cpp create mode 100644 controller_profile_runtime.h create mode 100644 controller_profile_transform.cpp create mode 100644 controller_profile_transform.h create mode 100644 tests/controller_profile_legacy_fixtures.h create mode 100644 tests/controller_profile_runtime_test.cpp create mode 100644 tests/controller_profile_transform_test.cpp create mode 100644 tests/test_controller_profile_runtime_native.py create mode 100644 tests/test_controller_profile_transform_native.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 167d8b4..b35736d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,8 @@ if(SWITCH_PICO_INPUT_BACKEND STREQUAL "BLUEPAD32") bluepad32_input_backend.cpp controller_identity.cpp controller_profile.cpp + controller_profile_transform.cpp + controller_profile_runtime.cpp profile_storage.cpp profile_service.cpp pico_profile_storage.cpp diff --git a/controller_profile.cpp b/controller_profile.cpp index 9b3c47f..7209944 100644 --- a/controller_profile.cpp +++ b/controller_profile.cpp @@ -17,6 +17,7 @@ constexpr uint8_t kMacroOverrideMask = kControllerProfileOverrideRightStick | kControllerProfileOverrideLeftTrigger | kControllerProfileOverrideRightTrigger; +constexpr uint16_t kLegacyDefaultDigitalThreshold = 0x8000; uint16_t profile_read_u16(const uint8_t* input) { return static_cast(input[0]) | @@ -144,7 +145,8 @@ ControllerProfile controller_profile_default(const ControllerIdentity& identity, trigger.lower_deadzone = 0; trigger.upper_saturation = UINT16_MAX; trigger.curve_q8_8 = 256; - trigger.digital_threshold = 0x8000; + trigger.digital_threshold = + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; } profile.weak_rumble_scale = UINT8_MAX; profile.strong_rumble_scale = UINT8_MAX; @@ -176,9 +178,7 @@ bool controller_profile_validate(const ControllerProfile& profile) { for (const ControllerProfileTriggerConfiguration& trigger : profile.triggers) { if (trigger.lower_deadzone >= trigger.upper_saturation || - trigger.curve_q8_8 == 0 || - trigger.digital_threshold < trigger.lower_deadzone || - trigger.digital_threshold > trigger.upper_saturation) { + trigger.curve_q8_8 == 0) { return false; } } @@ -272,13 +272,19 @@ bool controller_profile_encode(const ControllerProfile& profile, bool controller_profile_decode(const uint8_t* input, size_t input_size, ControllerProfile* output) { if (input == nullptr || output == nullptr || - input_size != CONTROLLER_PROFILE_ENCODED_SIZE || - profile_read_u16(&input[0]) != CONTROLLER_PROFILE_SCHEMA_VERSION || + input_size != CONTROLLER_PROFILE_ENCODED_SIZE) { + return false; + } + const uint16_t schema_version = profile_read_u16(&input[0]); + if ((schema_version != CONTROLLER_PROFILE_LEGACY_SCHEMA_VERSION && + schema_version != CONTROLLER_PROFILE_SCHEMA_VERSION) || profile_read_u16(&input[2]) != CONTROLLER_PROFILE_ENCODED_SIZE || - !profile_bytes_are_zero(&input[31], 5) || !profile_bytes_are_zero(&input[47], 5) || - !profile_bytes_are_zero(&input[60], 2) || !profile_bytes_are_zero(&input[70], 2) || - input[75] != 0 || input[81] != 0 || - !profile_bytes_are_zero(&input[98], 2) || !profile_bytes_are_zero(&input[252], 4)) { + !profile_bytes_are_zero(&input[31], 5) || + !profile_bytes_are_zero(&input[47], 5) || + !profile_bytes_are_zero(&input[60], 2) || + !profile_bytes_are_zero(&input[70], 2) || input[75] != 0 || + input[81] != 0 || !profile_bytes_are_zero(&input[98], 2) || + !profile_bytes_are_zero(&input[252], 4)) { return false; } @@ -307,6 +313,11 @@ bool controller_profile_decode(const uint8_t* input, size_t input_size, trigger.upper_saturation = profile_read_u16(&encoded[2]); trigger.curve_q8_8 = profile_read_u16(&encoded[4]); trigger.digital_threshold = profile_read_u16(&encoded[6]); + if (schema_version == CONTROLLER_PROFILE_LEGACY_SCHEMA_VERSION && + trigger.digital_threshold == kLegacyDefaultDigitalThreshold) { + trigger.digital_threshold = + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; + } } profile.weak_rumble_scale = input[72]; profile.strong_rumble_scale = input[73]; @@ -489,11 +500,16 @@ bool controller_profile_database_decode( return false; } uint8_t header[CONTROLLER_PROFILE_DATABASE_HEADER_SIZE]{}; - if (!read(context, 0, header, sizeof(header)) || - memcmp(header, kDatabaseMagic, sizeof(kDatabaseMagic)) != 0 || - profile_read_u16(&header[4]) != - CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION || - profile_read_u16(&header[6]) != CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE || + if (!read(context, 0, header, sizeof(header))) { + return false; + } + const uint16_t schema_version = profile_read_u16(&header[4]); + if (memcmp(header, kDatabaseMagic, sizeof(kDatabaseMagic)) != 0 || + (schema_version != + CONTROLLER_PROFILE_DATABASE_LEGACY_SCHEMA_VERSION && + schema_version != CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION) || + profile_read_u16(&header[6]) != + CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE || header[8] != CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY || header[9] != CONTROLLER_PROFILE_COUNT || header[10] >= CONTROLLER_PROFILE_COUNT || diff --git a/controller_profile.h b/controller_profile.h index 14b30db..d7e7618 100644 --- a/controller_profile.h +++ b/controller_profile.h @@ -5,7 +5,8 @@ #include "controller_identity.h" -constexpr uint16_t CONTROLLER_PROFILE_SCHEMA_VERSION = 1; +constexpr uint16_t CONTROLLER_PROFILE_LEGACY_SCHEMA_VERSION = 1; +constexpr uint16_t CONTROLLER_PROFILE_SCHEMA_VERSION = 2; constexpr size_t CONTROLLER_PROFILE_ENCODED_SIZE = 256; constexpr uint8_t CONTROLLER_PROFILE_COUNT = 4; constexpr uint8_t CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT = 16; @@ -13,9 +14,12 @@ constexpr uint8_t CONTROLLER_PROFILE_MACRO_STEP_CAPACITY = 8; constexpr uint16_t CONTROLLER_PROFILE_MAX_WAIT_MS = 10000; constexpr uint8_t CONTROLLER_PROFILE_NO_BUTTON = 0xff; constexpr uint8_t CONTROLLER_PROFILE_ALL = 0xff; +// Exact 16-bit counterpart of the existing 358-of-1023 Switch boundary. +constexpr uint16_t CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD = 22934; constexpr uint8_t CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY = 16; -constexpr uint16_t CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION = 1; +constexpr uint16_t CONTROLLER_PROFILE_DATABASE_LEGACY_SCHEMA_VERSION = 1; +constexpr uint16_t CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION = 2; constexpr size_t CONTROLLER_PROFILE_DATABASE_HEADER_SIZE = 32; constexpr size_t CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE = 16; constexpr size_t CONTROLLER_PROFILE_DATABASE_ENTRY_SIZE = @@ -92,7 +96,9 @@ struct ControllerProfileTriggerConfiguration { uint16_t lower_deadzone = 0; uint16_t upper_saturation = UINT16_MAX; uint16_t curve_q8_8 = 256; - uint16_t digital_threshold = 0x8000; + // Compared against the transformed uint16 trigger output. + uint16_t digital_threshold = + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; }; struct ControllerProfileMacroStep { diff --git a/controller_profile_runtime.cpp b/controller_profile_runtime.cpp new file mode 100644 index 0000000..681c42c --- /dev/null +++ b/controller_profile_runtime.cpp @@ -0,0 +1,131 @@ +#include "controller_profile_runtime.h" + +#include "controller_identity.h" +#include "profile_service.h" + +namespace { + +struct ControllerProfileRuntimeContext { + bool active = false; + uint32_t connection_generation = 0; + ControllerIdentity identity{}; + uint32_t database_generation = 0; + uint8_t active_profile_index = 0; + ControllerProfile profile{}; +}; + +ControllerProfileRuntimeContext + g_contexts[CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT]{}; +ControllerProfile g_default_profile{}; +ControllerProfileTransformResult g_neutral_output{}; +bool g_initialized = false; + +void initialize_defaults() { + if (g_initialized) { + return; + } + g_default_profile = + controller_profile_default(controller_identity_global(), 0); + g_neutral_output = controller_profile_transform( + controller_neutral_state(), g_default_profile); + g_initialized = true; +} + +void clear_context(ControllerProfileRuntimeContext* context) { + if (context == nullptr) { + return; + } + *context = {}; +} + +void refresh_profile(ControllerProfileRuntimeContext* context, + const ControllerIdentity& identity, + uint32_t connection_generation, + uint32_t observed_database_generation) { + ProfileServiceActiveProfileSnapshot snapshot{}; + profile_service_active_profile_snapshot(identity, &snapshot); + + context->active = true; + context->connection_generation = connection_generation; + context->identity = identity; + context->database_generation = snapshot.valid + ? snapshot.metadata.generation + : observed_database_generation; + context->active_profile_index = snapshot.valid ? snapshot.profile_index : 0; + context->profile = snapshot.valid ? snapshot.profile : g_default_profile; +} + +ControllerProfileRuntimeContext* update_context( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot) { + if (slot >= CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT) { + return nullptr; + } + + ControllerProfileRuntimeContext& context = g_contexts[slot]; + if (!snapshot.active) { + if (context.active) { + clear_context(&context); + } + return nullptr; + } + + const uint32_t database_generation = + profile_service_database_generation(); + if (!context.active || + context.connection_generation != snapshot.connection_generation || + !controller_identity_equal(context.identity, snapshot.identity) || + context.database_generation != database_generation) { + refresh_profile(&context, snapshot.identity, + snapshot.connection_generation, + database_generation); + } + return &context; +} + + +} // namespace + +void controller_profile_runtime_reset() { + g_initialized = false; + initialize_defaults(); + for (ControllerProfileRuntimeContext& context : g_contexts) { + clear_context(&context); + } +} + +ControllerProfileTransformResult controller_profile_runtime_transform( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot) { + initialize_defaults(); + ControllerProfileRuntimeContext* context = + update_context(slot, snapshot); + if (context == nullptr) { + return g_neutral_output; + } + return controller_profile_transform(snapshot.state, context->profile); +} + +ControllerRumbleOutput controller_profile_runtime_scale_host_rumble( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot, + const ControllerRumbleOutput& rumble) { + initialize_defaults(); + ControllerProfileRuntimeContext* context = + update_context(slot, snapshot); + const ControllerProfile& profile = + context == nullptr ? g_default_profile : context->profile; + return controller_profile_scale_host_rumble(rumble, profile); +} + +ControllerProfileRuntimeLocalConfirmation +controller_profile_runtime_local_confirmation( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot, + const ControllerRumbleOutput& rumble) { + initialize_defaults(); + ControllerProfileRuntimeContext* context = + update_context(slot, snapshot); + const ControllerProfile& profile = + context == nullptr ? g_default_profile : context->profile; + return { + rumble, + controller_profile_confirmation_policy(profile), + }; +} diff --git a/controller_profile_runtime.h b/controller_profile_runtime.h new file mode 100644 index 0000000..4eb246c --- /dev/null +++ b/controller_profile_runtime.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "bluepad32_input_backend.h" +#include "controller_profile_transform.h" + +constexpr uint8_t CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT = 4; + +struct ControllerProfileRuntimeLocalConfirmation { + ControllerRumbleOutput rumble{}; + ControllerProfileConfirmationPolicy policy = + ControllerProfileConfirmationPolicy::kRumbleAndLed; +}; + +// Reset all four fixed slot caches to the default profile. +void controller_profile_runtime_reset(); + +// Refresh a slot only when its connection key or database generation changes, +// then transform the raw snapshot. Inactive snapshots return neutral output and +// invalidate the slot immediately. +ControllerProfileTransformResult controller_profile_runtime_transform( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot); + +// Refresh from the current slot snapshot and scale host-originated rumble. +ControllerRumbleOutput controller_profile_runtime_scale_host_rumble( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot, + const ControllerRumbleOutput& rumble); + +// Preserve local confirmation rumble exactly while exposing profile policy. +ControllerProfileRuntimeLocalConfirmation +controller_profile_runtime_local_confirmation( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot, + const ControllerRumbleOutput& rumble); diff --git a/controller_profile_transform.cpp b/controller_profile_transform.cpp new file mode 100644 index 0000000..9039035 --- /dev/null +++ b/controller_profile_transform.cpp @@ -0,0 +1,344 @@ +#include "controller_profile_transform.h" + +#include + +namespace { + +constexpr uint32_t kQ16One = 1u << 16; + +constexpr uint16_t button_bit(ControllerProfileLogicalButton button) { + return static_cast( + 1u << static_cast(button)); +} + +int32_t clamp_centered_axis(int16_t value, int16_t center) { + const int32_t adjusted = + static_cast(value) - static_cast(center); + if (adjusted < INT16_MIN) { + return INT16_MIN; + } + if (adjusted > INT16_MAX) { + return INT16_MAX; + } + return adjusted; +} + +uint32_t absolute_axis(int32_t value) { + return value < 0 ? static_cast(-value) + : static_cast(value); +} + +// This endpoint-preserving rational curve is x / (c + (1 - c) * x), +// evaluated with x in Q16 and c in Q8.8. Values above 1.0 reduce the +// response below the linear curve; values below 1.0 increase it. +uint32_t apply_curve_q16(uint32_t input_q16, uint16_t curve_q8_8) { + if (input_q16 == 0 || input_q16 == kQ16One || curve_q8_8 == 256) { + return input_q16; + } + + const uint64_t denominator = + static_cast(curve_q8_8) * + (kQ16One - input_q16) + + static_cast(256) * input_q16; + const uint64_t numerator = + static_cast(input_q16) * 256u * kQ16One; + const uint64_t curved = (numerator + denominator / 2u) / denominator; + return curved > kQ16One ? kQ16One + : static_cast(curved); +} + +bool is_default_stick_configuration( + const ControllerProfileStickConfiguration& configuration) { + return configuration.center_x == 0 && configuration.center_y == 0 && + configuration.inner_deadzone == 0 && + configuration.outer_saturation == 32767 && + configuration.curve_q8_8 == 256 && !configuration.invert_x && + !configuration.invert_y; +} + +bool is_default_trigger_configuration( + const ControllerProfileTriggerConfiguration& configuration) { + return configuration.lower_deadzone == 0 && + configuration.upper_saturation == UINT16_MAX && + configuration.curve_q8_8 == 256; +} + +int16_t scale_stick_axis(int32_t adjusted_axis, uint32_t magnitude, + uint32_t response_q16, bool invert) { + if (adjusted_axis == 0 || magnitude == 0 || response_q16 == 0) { + return 0; + } + + bool negative = adjusted_axis < 0; + if (invert) { + negative = !negative; + } + const uint32_t axis_magnitude = absolute_axis(adjusted_axis); + const uint32_t output_limit = + negative ? static_cast(-static_cast(INT16_MIN)) + : static_cast(INT16_MAX); + const uint64_t numerator = + static_cast(axis_magnitude) * output_limit * + response_q16; + const uint64_t denominator = + static_cast(magnitude) * kQ16One; + uint32_t output_magnitude = static_cast( + (numerator + denominator / 2u) / denominator); + if (output_magnitude > output_limit) { + output_magnitude = output_limit; + } + + if (!negative) { + return static_cast(output_magnitude); + } + if (output_magnitude == + static_cast(-static_cast(INT16_MIN))) { + return INT16_MIN; + } + return static_cast(-static_cast(output_magnitude)); +} + +void transform_stick(const ControllerProfileStickConfiguration& configuration, + int16_t input_x, int16_t input_y, int16_t* output_x, + int16_t* output_y) { + if (is_default_stick_configuration(configuration)) { + *output_x = input_x; + *output_y = input_y; + return; + } + + const int32_t adjusted_x = + clamp_centered_axis(input_x, configuration.center_x); + const int32_t adjusted_y = + clamp_centered_axis(input_y, configuration.center_y); + const uint32_t magnitude_x = absolute_axis(adjusted_x); + const uint32_t magnitude_y = absolute_axis(adjusted_y); + const uint32_t magnitude = + magnitude_x > magnitude_y ? magnitude_x : magnitude_y; + + uint32_t response_q16 = 0; + if (magnitude <= configuration.inner_deadzone) { + response_q16 = 0; + } else if (magnitude >= configuration.outer_saturation) { + response_q16 = kQ16One; + } else { + const uint32_t input_range = + static_cast(configuration.outer_saturation) - + configuration.inner_deadzone; + const uint32_t input_offset = + magnitude - configuration.inner_deadzone; + const uint32_t normalized_q16 = static_cast( + (static_cast(input_offset) * kQ16One + + input_range / 2u) / + input_range); + response_q16 = + apply_curve_q16(normalized_q16, configuration.curve_q8_8); + } + + *output_x = scale_stick_axis(adjusted_x, magnitude, response_q16, + configuration.invert_x); + *output_y = scale_stick_axis(adjusted_y, magnitude, response_q16, + configuration.invert_y); +} + +uint16_t transform_trigger( + uint16_t input, + const ControllerProfileTriggerConfiguration& configuration) { + if (is_default_trigger_configuration(configuration)) { + return input; + } + if (input <= configuration.lower_deadzone) { + return 0; + } + if (input >= configuration.upper_saturation) { + return UINT16_MAX; + } + + const uint32_t input_range = + static_cast(configuration.upper_saturation) - + configuration.lower_deadzone; + const uint32_t input_offset = + static_cast(input) - configuration.lower_deadzone; + if (configuration.curve_q8_8 == 256) { + return static_cast( + (static_cast(input_offset) * UINT16_MAX + + input_range / 2u) / + input_range); + } + + const uint32_t normalized_q16 = static_cast( + (static_cast(input_offset) * kQ16One + + input_range / 2u) / + input_range); + const uint32_t curved_q16 = + apply_curve_q16(normalized_q16, configuration.curve_q8_8); + return static_cast( + (static_cast(curved_q16) * UINT16_MAX + + kQ16One / 2u) / + kQ16One); +} + +} // namespace + +uint16_t controller_profile_extract_button_mask(const ControllerState& state) { + uint16_t mask = 0; + mask |= state.button_south + ? button_bit(ControllerProfileLogicalButton::kSouth) + : 0; + mask |= state.button_east + ? button_bit(ControllerProfileLogicalButton::kEast) + : 0; + mask |= state.button_west + ? button_bit(ControllerProfileLogicalButton::kWest) + : 0; + mask |= state.button_north + ? button_bit(ControllerProfileLogicalButton::kNorth) + : 0; + mask |= state.button_left_shoulder + ? button_bit(ControllerProfileLogicalButton::kLeftShoulder) + : 0; + mask |= state.button_right_shoulder + ? button_bit(ControllerProfileLogicalButton::kRightShoulder) + : 0; + mask |= state.button_select + ? button_bit(ControllerProfileLogicalButton::kSelect) + : 0; + mask |= state.button_start + ? button_bit(ControllerProfileLogicalButton::kStart) + : 0; + mask |= state.button_system + ? button_bit(ControllerProfileLogicalButton::kSystem) + : 0; + mask |= state.button_capture + ? button_bit(ControllerProfileLogicalButton::kCapture) + : 0; + mask |= state.button_left_stick + ? button_bit(ControllerProfileLogicalButton::kLeftStick) + : 0; + mask |= state.button_right_stick + ? button_bit(ControllerProfileLogicalButton::kRightStick) + : 0; + mask |= state.dpad_up + ? button_bit(ControllerProfileLogicalButton::kDpadUp) + : 0; + mask |= state.dpad_down + ? button_bit(ControllerProfileLogicalButton::kDpadDown) + : 0; + mask |= state.dpad_left + ? button_bit(ControllerProfileLogicalButton::kDpadLeft) + : 0; + mask |= state.dpad_right + ? button_bit(ControllerProfileLogicalButton::kDpadRight) + : 0; + return mask; +} + +void controller_profile_apply_button_mask(uint16_t button_mask, + ControllerState* state) { + if (state == nullptr) { + return; + } + state->button_south = + (button_mask & button_bit(ControllerProfileLogicalButton::kSouth)) != 0; + state->button_east = + (button_mask & button_bit(ControllerProfileLogicalButton::kEast)) != 0; + state->button_west = + (button_mask & button_bit(ControllerProfileLogicalButton::kWest)) != 0; + state->button_north = + (button_mask & button_bit(ControllerProfileLogicalButton::kNorth)) != 0; + state->button_left_shoulder = + (button_mask & + button_bit(ControllerProfileLogicalButton::kLeftShoulder)) != 0; + state->button_right_shoulder = + (button_mask & + button_bit(ControllerProfileLogicalButton::kRightShoulder)) != 0; + state->button_select = + (button_mask & button_bit(ControllerProfileLogicalButton::kSelect)) != 0; + state->button_start = + (button_mask & button_bit(ControllerProfileLogicalButton::kStart)) != 0; + state->button_system = + (button_mask & button_bit(ControllerProfileLogicalButton::kSystem)) != 0; + state->button_capture = + (button_mask & button_bit(ControllerProfileLogicalButton::kCapture)) != 0; + state->button_left_stick = + (button_mask & + button_bit(ControllerProfileLogicalButton::kLeftStick)) != 0; + state->button_right_stick = + (button_mask & + button_bit(ControllerProfileLogicalButton::kRightStick)) != 0; + state->dpad_up = + (button_mask & button_bit(ControllerProfileLogicalButton::kDpadUp)) != 0; + state->dpad_down = + (button_mask & button_bit(ControllerProfileLogicalButton::kDpadDown)) != 0; + state->dpad_left = + (button_mask & button_bit(ControllerProfileLogicalButton::kDpadLeft)) != 0; + state->dpad_right = + (button_mask & button_bit(ControllerProfileLogicalButton::kDpadRight)) != 0; +} + +uint16_t controller_profile_map_button_mask( + uint16_t input_button_mask, const ControllerProfile& profile) { + uint16_t output_button_mask = 0; + for (uint8_t input = 0; + input < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; ++input) { + if ((input_button_mask & static_cast(1u << input)) == 0) { + continue; + } + const uint8_t output = profile.button_map[input]; + if (output < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT) { + output_button_mask |= static_cast(1u << output); + } + } + return output_button_mask; +} + +ControllerProfileTransformResult controller_profile_transform( + const ControllerState& input, const ControllerProfile& profile) { + ControllerProfileTransformResult result{}; + result.state = input; + const uint16_t input_button_mask = + controller_profile_extract_button_mask(input); + controller_profile_apply_button_mask( + controller_profile_map_button_mask(input_button_mask, profile), + &result.state); + + transform_stick(profile.sticks[0], input.left_stick_x, + input.left_stick_y, &result.state.left_stick_x, + &result.state.left_stick_y); + transform_stick(profile.sticks[1], input.right_stick_x, + input.right_stick_y, &result.state.right_stick_x, + &result.state.right_stick_y); + result.state.left_trigger = transform_trigger(input.left_trigger, + profile.triggers[0]); + result.state.right_trigger = transform_trigger(input.right_trigger, + profile.triggers[1]); + result.left_trigger_digital_threshold = + profile.triggers[0].digital_threshold; + result.right_trigger_digital_threshold = + profile.triggers[1].digital_threshold; + return result; +} + +uint8_t controller_profile_scale_rumble_magnitude(uint8_t magnitude, + uint8_t scale) { + const uint32_t scaled = + (static_cast(magnitude) * scale + UINT8_MAX / 2u) / + UINT8_MAX; + return scaled > UINT8_MAX ? UINT8_MAX + : static_cast(scaled); +} + +ControllerRumbleOutput controller_profile_scale_host_rumble( + const ControllerRumbleOutput& input, const ControllerProfile& profile) { + return { + controller_profile_scale_rumble_magnitude( + input.low_frequency_magnitude, profile.strong_rumble_scale), + controller_profile_scale_rumble_magnitude( + input.high_frequency_magnitude, profile.weak_rumble_scale), + }; +} + +ControllerProfileConfirmationPolicy controller_profile_confirmation_policy( + const ControllerProfile& profile) { + return profile.confirmation_policy; +} diff --git a/controller_profile_transform.h b/controller_profile_transform.h new file mode 100644 index 0000000..54c4904 --- /dev/null +++ b/controller_profile_transform.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "controller_profile.h" +#include "controller_state.h" +#include "switch_haptics.h" + +struct ControllerProfileTransformResult { + ControllerState state{}; + uint16_t left_trigger_digital_threshold = + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; + uint16_t right_trigger_digital_threshold = + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; +}; + +uint16_t controller_profile_extract_button_mask(const ControllerState& state); +void controller_profile_apply_button_mask(uint16_t button_mask, + ControllerState* state); +uint16_t controller_profile_map_button_mask( + uint16_t input_button_mask, const ControllerProfile& profile); + +ControllerProfileTransformResult controller_profile_transform( + const ControllerState& input, const ControllerProfile& profile); + +uint8_t controller_profile_scale_rumble_magnitude(uint8_t magnitude, + uint8_t scale); +ControllerRumbleOutput controller_profile_scale_host_rumble( + const ControllerRumbleOutput& input, const ControllerProfile& profile); +ControllerProfileConfirmationPolicy controller_profile_confirmation_policy( + const ControllerProfile& profile); diff --git a/profile_service.cpp b/profile_service.cpp index f646b38..12ec36c 100644 --- a/profile_service.cpp +++ b/profile_service.cpp @@ -29,13 +29,23 @@ struct ProfileTransaction { uint8_t payload[CONTROLLER_PROFILE_ENCODED_SIZE]{}; }; +struct PublishedActiveProfile { + ControllerIdentity identity{}; + uint8_t profile_index = 0; + ControllerProfile profile{}; +}; + critical_section_t g_lock; bool g_prepared = false; ProfileStorage g_storage; ControllerProfileDatabase g_database; ProfileServiceMetadata g_metadata; +uint32_t g_published_generation = 0; ProfileServiceListSnapshot g_list; ProfileServiceSelectedSnapshot g_selected; +PublishedActiveProfile + g_active_profiles[PROFILE_SERVICE_LIST_CAPACITY]{}; +uint8_t g_active_profile_count = 0; ProfileTransaction g_transaction; PendingCommand g_command; bool g_identity_dirty = false; @@ -65,6 +75,26 @@ void refresh_list_locked() { } } +void refresh_active_profiles_locked() { + g_active_profile_count = 1; + g_active_profiles[0].identity = controller_identity_global(); + g_active_profiles[0].profile_index = + g_database.fallback_active_profile; + g_active_profiles[0].profile = + g_database.fallback_profiles[g_database.fallback_active_profile]; + for (const ControllerProfileDatabaseEntry& entry : g_database.entries) { + if (!entry.used || + g_active_profile_count >= PROFILE_SERVICE_LIST_CAPACITY) { + continue; + } + PublishedActiveProfile& active = + g_active_profiles[g_active_profile_count++]; + active.identity = entry.identity; + active.profile_index = entry.active_profile; + active.profile = entry.profiles[entry.active_profile]; + } +} + void refresh_selected_locked() { g_selected.metadata = g_metadata; const ControllerProfile* profile = controller_profile_database_get( @@ -84,8 +114,11 @@ void refresh_metadata_locked(ProfileServiceState state) { g_metadata.state = state; g_metadata.generation = stored.valid ? stored.generation : 0; g_metadata.payload_crc = stored.valid ? stored.payload_crc : 0; + refresh_active_profiles_locked(); refresh_list_locked(); refresh_selected_locked(); + __atomic_store_n(&g_published_generation, g_metadata.generation, + __ATOMIC_RELEASE); } ConfigurationTransactionStatus database_result_status( @@ -134,8 +167,11 @@ void profile_service_prepare() { } critical_section_init(&g_lock); g_metadata = {}; + __atomic_store_n(&g_published_generation, 0, __ATOMIC_RELAXED); g_list = {}; g_selected = {}; + g_active_profiles[0] = {}; + g_active_profile_count = 0; g_selected.identity = controller_identity_global(); g_selected.profile_index = 0; g_transaction = {}; @@ -522,27 +558,36 @@ void profile_service_transaction_snapshot( critical_section_exit(&g_lock); } -bool profile_service_active_profile(const ControllerIdentity& identity, - ControllerProfile* output, - uint8_t* profile_index) { - if (output == nullptr || profile_index == nullptr || - !valid_identity(identity)) { - return false; +uint32_t profile_service_database_generation() { + return __atomic_load_n(&g_published_generation, __ATOMIC_ACQUIRE); +} + +void profile_service_active_profile_snapshot( + const ControllerIdentity& identity, + ProfileServiceActiveProfileSnapshot* output) { + if (output == nullptr) { + return; } + *output = {}; + if (!valid_identity(identity)) { + return; + } + critical_section_enter_blocking(&g_lock); - if (g_metadata.state != ProfileServiceState::kReady) { - critical_section_exit(&g_lock); - return false; - } - const ControllerProfileDatabaseEntry* entry = - controller_profile_database_find(g_database, identity); - if (entry != nullptr) { - *profile_index = entry->active_profile; - *output = entry->profiles[entry->active_profile]; - } else { - *profile_index = g_database.fallback_active_profile; - *output = g_database.fallback_profiles[*profile_index]; + output->metadata = g_metadata; + if (g_metadata.state == ProfileServiceState::kReady && + g_active_profile_count != 0) { + const PublishedActiveProfile* active = &g_active_profiles[0]; + for (uint8_t index = 1; index < g_active_profile_count; ++index) { + if (controller_identity_equal( + g_active_profiles[index].identity, identity)) { + active = &g_active_profiles[index]; + break; + } + } + output->profile_index = active->profile_index; + output->profile = active->profile; + output->valid = true; } critical_section_exit(&g_lock); - return true; } diff --git a/profile_service.h b/profile_service.h index b96b04a..7c0e803 100644 --- a/profile_service.h +++ b/profile_service.h @@ -42,6 +42,13 @@ struct ProfileServiceSelectedSnapshot { ControllerProfile profile{}; }; +struct ProfileServiceActiveProfileSnapshot { + ProfileServiceMetadata metadata{}; + bool valid = false; + uint8_t profile_index = 0; + ControllerProfile profile{}; +}; + struct ProfileServiceTransactionSnapshot { ProfileServiceMetadata metadata{}; ControllerIdentity identity{}; @@ -78,6 +85,7 @@ void profile_service_selected_snapshot( ProfileServiceSelectedSnapshot* output); void profile_service_transaction_snapshot( ProfileServiceTransactionSnapshot* output); -bool profile_service_active_profile(const ControllerIdentity& identity, - ControllerProfile* output, - uint8_t* profile_index); +uint32_t profile_service_database_generation(); +void profile_service_active_profile_snapshot( + const ControllerIdentity& identity, + ProfileServiceActiveProfileSnapshot* output); diff --git a/profile_storage.cpp b/profile_storage.cpp index 14af5ab..50559a3 100644 --- a/profile_storage.cpp +++ b/profile_storage.cpp @@ -236,8 +236,10 @@ bool ProfileStorage::read_header(uint8_t bank, BankHeader* output) const { !io_.read(io_.context, bank, 0, header, sizeof(header)) || memcmp(header, kRecordMagic, sizeof(kRecordMagic)) != 0 || storage_read_u16(&header[4]) != kRecordFormatVersion || - storage_read_u16(&header[6]) != - CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION || + (storage_read_u16(&header[6]) != + CONTROLLER_PROFILE_DATABASE_LEGACY_SCHEMA_VERSION && + storage_read_u16(&header[6]) != + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION) || storage_read_u32(&header[12]) != CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE || profile_storage_crc32(header, kHeaderCrcOffset) != diff --git a/src/switch_pico_bridge/config_manager.py b/src/switch_pico_bridge/config_manager.py index 8d5fcc3..d88beea 100755 --- a/src/switch_pico_bridge/config_manager.py +++ b/src/switch_pico_bridge/config_manager.py @@ -69,7 +69,8 @@ PAIRING_RECORD_CAPACITY = 16 TRANSPORT_UNKNOWN = 0 TRANSPORT_CLASSIC = 1 TRANSPORT_BLE = 2 -PROFILE_SCHEMA_VERSION = 1 +PROFILE_LEGACY_SCHEMA_VERSION = 1 +PROFILE_SCHEMA_VERSION = 2 PROFILE_SIZE = 256 PROFILE_CAPACITY = 4 PROFILE_IDENTITY_CAPACITY = 16 @@ -80,6 +81,8 @@ PROFILE_NONE_BUTTON = 0xFF PROFILE_MACRO_STEP_CAPACITY = 8 PROFILE_MACRO_STEP_SIZE = 19 PROFILE_MAXIMUM_WAIT_MS = 10000 +PROFILE_LEGACY_DEFAULT_DIGITAL_THRESHOLD = 0x8000 +PROFILE_DEFAULT_DIGITAL_THRESHOLD = 22934 LOGICAL_BUTTONS = ( "south", @@ -513,10 +516,7 @@ class TriggerConfig: ) _require_int(self.curve_q8_8, "trigger curve_q8_8", 1, 0xFFFF) _require_int( - self.digital_threshold, - "trigger digital_threshold", - self.lower_deadzone, - self.upper_saturation, + self.digital_threshold, "trigger digital_threshold", 0, 0xFFFF ) @classmethod @@ -575,6 +575,19 @@ class TriggerConfig: ), ) +def _migrate_legacy_trigger_threshold(trigger: TriggerConfig) -> TriggerConfig: + if ( + trigger.digital_threshold + != PROFILE_LEGACY_DEFAULT_DIGITAL_THRESHOLD + ): + return trigger + return TriggerConfig( + trigger.lower_deadzone, + trigger.upper_saturation, + trigger.curve_q8_8, + PROFILE_DEFAULT_DIGITAL_THRESHOLD, + ) + @dataclass(frozen=True) class MacroStep: @@ -866,7 +879,9 @@ class ControllerProfile: @classmethod def default(cls) -> ControllerProfile: stick = StickConfig(0, 0, 0, 0x7FFF, 256, False, False) - trigger = TriggerConfig(0, 0xFFFF, 256, 0x8000) + trigger = TriggerConfig( + 0, 0xFFFF, 256, PROFILE_DEFAULT_DIGITAL_THRESHOLD + ) return cls( button_map=tuple(range(len(LOGICAL_BUTTONS))), left_stick=stick, @@ -889,7 +904,11 @@ class ControllerProfile: if len(payload) != PROFILE_SIZE: raise ConfigManagerError("invalid profile size") version, size = struct.unpack_from(" TransactionStatus: def parse_profile_list(envelope: Envelope) -> tuple[ProfileListEntry, ...]: _raise_status(envelope) - if envelope.schema_version != PROFILE_SCHEMA_VERSION: + if envelope.schema_version not in ( + PROFILE_LEGACY_SCHEMA_VERSION, + PROFILE_SCHEMA_VERSION, + ): raise ConfigManagerError("unsupported profile-list schema") if not envelope.payload: raise ConfigManagerError("short profile-list payload") @@ -1407,7 +1440,10 @@ def select_profile( def read_selected_profile(device: UsbDevice) -> ControllerProfile: envelope = _control_in(device, OP_PROFILE_READ) _raise_status(envelope) - if envelope.schema_version != PROFILE_SCHEMA_VERSION: + if envelope.schema_version not in ( + PROFILE_LEGACY_SCHEMA_VERSION, + PROFILE_SCHEMA_VERSION, + ): raise ConfigManagerError("unsupported profile schema") return ControllerProfile.from_bytes(envelope.payload) diff --git a/switch-pico.cpp b/switch-pico.cpp index 90aac7b..bf889d9 100644 --- a/switch-pico.cpp +++ b/switch-pico.cpp @@ -7,6 +7,7 @@ #include "hardware/uart.h" #else #include "bluepad32_input_backend.h" +#include "controller_profile_runtime.h" #include "bootsel_pairing_button.h" #ifdef SWITCH_PICO_ADAPTER_FEASIBILITY #include "adapter_host_probe.h" @@ -33,6 +34,10 @@ #ifdef SWITCH_PICO_BLUEPAD32 static_assert(SWITCH_PICO_HID_INSTANCE_COUNT == BLUEPAD32_INPUT_BACKEND_SLOT_COUNT); +static_assert(CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT == + BLUEPAD32_INPUT_BACKEND_SLOT_COUNT); +static_assert(SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD); static bool g_last_ready[BLUEPAD32_INPUT_BACKEND_SLOT_COUNT]{}; static ControllerState g_user_states[BLUEPAD32_INPUT_BACKEND_SLOT_COUNT]{}; @@ -80,7 +85,11 @@ static void on_rumble_from_switch(uint8_t instance, if (instance >= BLUEPAD32_INPUT_BACKEND_SLOT_COUNT) { return; } - bluepad32_input_backend_queue_rumble(instance, rumble); + Bluepad32SlotSnapshot snapshot{}; + bluepad32_input_backend_snapshot(instance, &snapshot); + bluepad32_input_backend_queue_rumble( + instance, controller_profile_runtime_scale_host_rumble( + instance, snapshot, rumble)); #else if (instance != SWITCH_HID_INSTANCE) { return; @@ -217,6 +226,7 @@ int main() { #ifdef SWITCH_PICO_BLUEPAD32 bluepad32_input_backend_init(); + controller_profile_runtime_reset(); #ifdef SWITCH_PICO_ADAPTER_FEASIBILITY adapter_host_probe_init(); #endif @@ -241,13 +251,19 @@ int main() { switch_pro_set_rumble_callback(instance, on_rumble_from_switch); g_user_states[instance] = neutral_input(); - switch_pro_set_input(instance, g_user_states[instance]); + switch_pro_set_input( + instance, g_user_states[instance], + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD, + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD); } #else switch_pro_init(instance); switch_pro_set_rumble_callback(instance, on_rumble_from_switch); g_user_states[instance] = neutral_input(); - switch_pro_set_input(instance, g_user_states[instance]); + switch_pro_set_input( + instance, g_user_states[instance], + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD, + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD); #endif } #else @@ -255,7 +271,9 @@ int main() { switch_pro_set_rumble_callback(SWITCH_HID_INSTANCE, on_rumble_from_switch); g_user_state = neutral_input(); - switch_pro_set_input(SWITCH_HID_INSTANCE, g_user_state); + switch_pro_set_input(SWITCH_HID_INSTANCE, g_user_state, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); #endif #ifdef SWITCH_PICO_BLUEPAD32 @@ -292,8 +310,9 @@ int main() { instance < BLUEPAD32_INPUT_BACKEND_SLOT_COUNT; ++instance) { Bluepad32SlotSnapshot snapshot{}; bluepad32_input_backend_snapshot(instance, &snapshot); - g_user_states[instance] = - snapshot.active ? snapshot.state : controller_neutral_state(); + const ControllerProfileTransformResult transformed = + controller_profile_runtime_transform(instance, snapshot); + g_user_states[instance] = transformed.state; #ifdef SWITCH_PICO_ADAPTER_FEASIBILITY bool sent = false; if (adapter_host_probe_mode() == AdapterUsbMode::kXInput) { @@ -301,14 +320,20 @@ int main() { g_user_states[instance]); sent = xinput_feasibility_task(instance); } else { - switch_pro_set_input(instance, g_user_states[instance]); + switch_pro_set_input( + instance, g_user_states[instance], + transformed.left_trigger_digital_threshold, + transformed.right_trigger_digital_threshold); sent = switch_pro_task(instance); } if (sent) { bluepad32_input_backend_report_sent(instance); } #else - switch_pro_set_input(instance, g_user_states[instance]); + switch_pro_set_input( + instance, g_user_states[instance], + transformed.left_trigger_digital_threshold, + transformed.right_trigger_digital_threshold); if (switch_pro_task(instance)) { bluepad32_input_backend_report_sent(instance); } @@ -318,7 +343,9 @@ int main() { bool new_data = poll_uart_frames(); // Pull controller state from UART1 (void)new_data; ControllerState state = g_user_state; - switch_pro_set_input(SWITCH_HID_INSTANCE, state); + switch_pro_set_input(SWITCH_HID_INSTANCE, state, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); (void)switch_pro_task(SWITCH_HID_INSTANCE); #endif log_usb_state(); diff --git a/switch_pro_driver.cpp b/switch_pro_driver.cpp index 631ad2b..fe8a1f2 100644 --- a/switch_pro_driver.cpp +++ b/switch_pro_driver.cpp @@ -43,6 +43,10 @@ struct MotionQuaternion { struct SwitchProContext { ControllerState input_state{}; + uint16_t left_trigger_threshold = + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; + uint16_t right_trigger_threshold = + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; uint8_t report_buffer[SWITCH_PRO_ENDPOINT_SIZE]{}; SwitchProReport switch_report{}; uint8_t last_report_counter = 0; @@ -420,6 +424,8 @@ static ControllerState make_neutral_state() { static void reset_context_runtime(SwitchProContext& context, uint32_t now, bool ready_before_mount) { context.input_state = make_neutral_state(); + context.left_trigger_threshold = SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; + context.right_trigger_threshold = SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; memset(context.report_buffer, 0x00, sizeof(context.report_buffer)); context.switch_report = {}; context.switch_report.reportID = 0x30; @@ -747,7 +753,7 @@ static void update_switch_report_from_state(SwitchProContext& context) { inputs.buttonRightSL = 0; inputs.buttonR = state.button_right_shoulder; inputs.buttonZR = - state.right_trigger >= SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; + state.right_trigger >= context.right_trigger_threshold; inputs.buttonMinus = state.button_select; inputs.buttonPlus = state.button_start; inputs.buttonThumbR = state.button_right_stick; @@ -758,7 +764,7 @@ static void update_switch_report_from_state(SwitchProContext& context) { inputs.buttonLeftSL = 0; inputs.buttonL = state.button_left_shoulder; inputs.buttonZL = - state.left_trigger >= SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; + state.left_trigger >= context.left_trigger_threshold; uint16_t left_x = scale16To12(controller_axis_to_unsigned(state.left_stick_x)); @@ -813,10 +819,14 @@ void switch_pro_init(uint8_t instance) { to_ms_since_boot(get_absolute_time()), true); } -void switch_pro_set_input(uint8_t instance, const ControllerState& state) { +void switch_pro_set_input(uint8_t instance, const ControllerState& state, + uint16_t left_trigger_threshold, + uint16_t right_trigger_threshold) { SwitchProContext* context = context_for(instance); if (context != nullptr) { context->input_state = state; + context->left_trigger_threshold = left_trigger_threshold; + context->right_trigger_threshold = right_trigger_threshold; } } diff --git a/switch_pro_driver.h b/switch_pro_driver.h index bb1d9ba..5cc51f5 100644 --- a/switch_pro_driver.h +++ b/switch_pro_driver.h @@ -27,8 +27,11 @@ constexpr uint16_t SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD = // Initialize one HID instance before entering the main loop. void switch_pro_init(uint8_t instance); -// Update the desired controller state for one HID instance. -void switch_pro_set_input(uint8_t instance, const ControllerState& state); +// Update the desired controller state and digital trigger thresholds for one +// HID instance. +void switch_pro_set_input(uint8_t instance, const ControllerState& state, + uint16_t left_trigger_threshold, + uint16_t right_trigger_threshold); // Drive one Switch Pro USB state machine; returns true only when a regular // 0x30 input report was successfully queued. diff --git a/tests/controller_profile_legacy_fixtures.h b/tests/controller_profile_legacy_fixtures.h new file mode 100644 index 0000000..eb29b40 --- /dev/null +++ b/tests/controller_profile_legacy_fixtures.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include "controller_profile.h" + +constexpr uint8_t kLegacyDefaultProfile[CONTROLLER_PROFILE_ENCODED_SIZE] = { + 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +constexpr uint8_t + kLegacyNarrowRawRangeProfile[CONTROLLER_PROFILE_ENCODED_SIZE] = { + 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x75, 0x40, 0x9c, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0x30, 0x75, + 0x40, 0x9c, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +constexpr uint8_t kLegacyCustomThresholdProfile[CONTROLLER_PROFILE_ENCODED_SIZE] = { + 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x01, 0xcd, 0xab, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/tests/controller_profile_runtime_test.cpp b/tests/controller_profile_runtime_test.cpp new file mode 100644 index 0000000..92eb8d7 --- /dev/null +++ b/tests/controller_profile_runtime_test.cpp @@ -0,0 +1,273 @@ +#include "controller_profile_runtime.h" + +#include "controller_identity.h" +#include "controller_profile.h" +#include "profile_service.h" + +#include +#include +#include +#include + +namespace { + +struct FakeProfileRow { + ControllerIdentity identity{}; + uint8_t active_profile = 0; + ControllerProfile profiles[CONTROLLER_PROFILE_COUNT]{}; +}; + +std::array rows{}; +uint32_t database_generation = 7; +unsigned active_snapshot_count = 0; + +void require(bool condition, const char* message) { + if (!condition) { + std::cerr << message << '\n'; + std::exit(1); + } +} + +ControllerIdentity make_identity(uint8_t value) { + ControllerIdentity identity{}; + identity.stable = true; + identity.transport = ControllerTransport::kClassic; + identity.address[0] = value; + identity.address[5] = static_cast(value + 0x40u); + identity.vendor_id = static_cast(0x1000u + value); + identity.product_id = static_cast(0x2000u + value); + return identity; +} + +void prepare_profiles() { + database_generation = 7; + active_snapshot_count = 0; + for (uint8_t slot = 0; + slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { + FakeProfileRow& row = rows[slot]; + row = {}; + row.identity = make_identity(static_cast(slot + 1u)); + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + row.profiles[profile_index] = + controller_profile_default(row.identity, profile_index); + } + row.profiles[0].triggers[0].digital_threshold = + static_cast(1000u + slot); + row.profiles[0].triggers[1].digital_threshold = + static_cast(5000u + slot); + row.profiles[0].confirmation_policy = + slot == 0 ? ControllerProfileConfirmationPolicy::kLed + : ControllerProfileConfirmationPolicy::kRumble; + } + rows[0].profiles[0].strong_rumble_scale = 0; + rows[0].profiles[0].weak_rumble_scale = UINT8_MAX; + rows[1].profiles[0].strong_rumble_scale = UINT8_MAX; + rows[1].profiles[0].weak_rumble_scale = 0; + controller_profile_runtime_reset(); +} + +Bluepad32SlotSnapshot make_snapshot(uint8_t slot, + uint32_t connection_generation = 1) { + Bluepad32SlotSnapshot snapshot{}; + snapshot.active = true; + snapshot.connection_generation = connection_generation; + snapshot.identity = rows[slot].identity; + snapshot.state = controller_neutral_state(); + return snapshot; +} + +bool motion_equal(const ControllerState& first, + const ControllerState& second) { + return first.motion_sample_count == second.motion_sample_count && + std::memcmp(first.motion_samples, second.motion_samples, + sizeof(first.motion_samples)) == 0; +} + +void test_four_slot_cache_and_unchanged_generation() { + prepare_profiles(); + std::array + snapshots{}; + std::array + transformed{}; + for (uint8_t slot = 0; + slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { + snapshots[slot] = make_snapshot(slot); + transformed[slot] = + controller_profile_runtime_transform(slot, snapshots[slot]); + require(transformed[slot].left_trigger_digital_threshold == + static_cast(1000u + slot) && + transformed[slot].right_trigger_digital_threshold == + static_cast(5000u + slot), + "a slot did not receive its own cached profile"); + } + require(active_snapshot_count == CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT, + "initial slot loads did not fetch exactly one profile each"); + + rows[0].profiles[0].triggers[0].digital_threshold = 65000; + for (uint8_t slot = 0; + slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { + transformed[slot] = + controller_profile_runtime_transform(slot, snapshots[slot]); + } + require(active_snapshot_count == CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT, + "unchanged generations copied profiles on the report path"); + require(transformed[0].left_trigger_digital_threshold == 1000, + "an unchanged generation bypassed the slot cache"); + + snapshots[2].connection_generation = 2; + transformed[2] = + controller_profile_runtime_transform(2, snapshots[2]); + require(active_snapshot_count == + CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT + 1 && + transformed[2].left_trigger_digital_threshold == 1002, + "one slot connection generation did not refresh in isolation"); + + snapshots[3].identity = rows[1].identity; + transformed[3] = + controller_profile_runtime_transform(3, snapshots[3]); + require(active_snapshot_count == + CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT + 2 && + transformed[3].left_trigger_digital_threshold == 1001, + "an exact identity change did not refresh only its slot"); +} + +void test_activation_disconnect_and_default_preservation() { + prepare_profiles(); + Bluepad32SlotSnapshot snapshot = make_snapshot(0); + snapshot.state.button_south = true; + ControllerProfileTransformResult transformed = + controller_profile_runtime_transform(0, snapshot); + require(transformed.state.button_south && + transformed.left_trigger_digital_threshold == 1000, + "initial active profile was not applied"); + + rows[0].active_profile = 1; + rows[0].profiles[1].button_map[ + static_cast(ControllerProfileLogicalButton::kSouth)] = + static_cast(ControllerProfileLogicalButton::kNorth); + rows[0].profiles[1].triggers[0].digital_threshold = 12345; + ++database_generation; + transformed = controller_profile_runtime_transform(0, snapshot); + require(!transformed.state.button_south && transformed.state.button_north && + transformed.left_trigger_digital_threshold == 12345, + "profile activation generation did not refresh the slot cache"); + + const unsigned reads_before_disconnect = active_snapshot_count; + snapshot.active = false; + transformed = controller_profile_runtime_transform(0, snapshot); + require(!transformed.state.button_south && !transformed.state.button_north && + transformed.left_trigger_digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + active_snapshot_count == reads_before_disconnect, + "disconnect did not neutralize output without fetching a profile"); + + transformed = controller_profile_runtime_transform(0, snapshot); + require(active_snapshot_count == reads_before_disconnect, + "an unchanged inactive slot repeatedly cleared or fetched state"); + snapshot.active = true; + transformed = controller_profile_runtime_transform(0, snapshot); + require(active_snapshot_count == reads_before_disconnect + 1 && + transformed.state.button_north, + "reconnection did not reload a cleared slot cache"); + + Bluepad32SlotSnapshot default_snapshot = make_snapshot(2); + rows[2].profiles[0] = + controller_profile_default(rows[2].identity, 0); + ++database_generation; + default_snapshot.state.button_east = true; + default_snapshot.state.dpad_left = true; + default_snapshot.state.left_trigger = 32123; + default_snapshot.state.right_trigger = 54321; + default_snapshot.state.left_stick_x = -12345; + default_snapshot.state.right_stick_y = 23456; + default_snapshot.state.motion_sample_count = 2; + default_snapshot.state.motion_samples[0] = {1, 2, 3, 4, 5, 6}; + default_snapshot.state.motion_samples[1] = {-1, -2, -3, -4, -5, -6}; + transformed = controller_profile_runtime_transform(2, default_snapshot); + require(transformed.state.button_east && transformed.state.dpad_left && + transformed.state.left_trigger == 32123 && + transformed.state.right_trigger == 54321 && + transformed.state.left_stick_x == -12345 && + transformed.state.right_stick_y == 23456 && + motion_equal(transformed.state, default_snapshot.state) && + transformed.left_trigger_digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + transformed.right_trigger_digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD, + "default runtime profile changed serializer input or motion"); +} + +void test_analog_thresholds_rumble_and_local_confirmation() { + prepare_profiles(); + Bluepad32SlotSnapshot first = make_snapshot(0); + Bluepad32SlotSnapshot second = make_snapshot(1); + first.state.left_trigger = second.state.left_trigger = 23456; + first.state.right_trigger = second.state.right_trigger = 45678; + const ControllerProfileTransformResult first_output = + controller_profile_runtime_transform(0, first); + const ControllerProfileTransformResult second_output = + controller_profile_runtime_transform(1, second); + require(first_output.state.left_trigger == + second_output.state.left_trigger && + first_output.state.right_trigger == + second_output.state.right_trigger && + first_output.left_trigger_digital_threshold != + second_output.left_trigger_digital_threshold, + "digital thresholds changed XInput-visible analog trigger state"); + + const ControllerRumbleOutput host{91, 73}; + const ControllerRumbleOutput first_host = + controller_profile_runtime_scale_host_rumble(0, first, host); + const ControllerRumbleOutput second_host = + controller_profile_runtime_scale_host_rumble(1, second, host); + require(first_host.low_frequency_magnitude == 0 && + first_host.high_frequency_magnitude == 73 && + second_host.low_frequency_magnitude == 91 && + second_host.high_frequency_magnitude == 0, + "host rumble was not scaled through each slot profile"); + + const ControllerProfileRuntimeLocalConfirmation confirmation = + controller_profile_runtime_local_confirmation(0, first, host); + require(confirmation.rumble.low_frequency_magnitude == 91 && + confirmation.rumble.high_frequency_magnitude == 73 && + confirmation.policy == + ControllerProfileConfirmationPolicy::kLed, + "local confirmation was scaled or lost its profile policy"); +} + +} // namespace + +uint32_t profile_service_database_generation() { + return database_generation; +} + +void profile_service_active_profile_snapshot( + const ControllerIdentity& identity, + ProfileServiceActiveProfileSnapshot* output) { + if (output == nullptr) { + return; + } + ++active_snapshot_count; + *output = {}; + output->metadata.state = ProfileServiceState::kReady; + output->metadata.generation = database_generation; + for (const FakeProfileRow& row : rows) { + if (!controller_identity_equal(row.identity, identity)) { + continue; + } + output->valid = true; + output->profile_index = row.active_profile; + output->profile = row.profiles[row.active_profile]; + return; + } +} + +int main() { + test_four_slot_cache_and_unchanged_generation(); + test_activation_disconnect_and_default_preservation(); + test_analog_thresholds_rumble_and_local_confirmation(); + return 0; +} diff --git a/tests/controller_profile_test.cpp b/tests/controller_profile_test.cpp index a235a26..91d1bac 100644 --- a/tests/controller_profile_test.cpp +++ b/tests/controller_profile_test.cpp @@ -1,5 +1,6 @@ #include "controller_identity.h" #include "controller_profile.h" +#include "tests/controller_profile_legacy_fixtures.h" #include #include @@ -44,9 +45,9 @@ void test_profile_wire_schema() { uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{}; require(controller_profile_encode(profile, encoded, sizeof(encoded)), "default profile did not encode"); - require(encoded[0] == 1 && encoded[1] == 0 && + require(encoded[0] == 2 && encoded[1] == 0 && encoded[2] == 0 && encoded[3] == 1, - "profile header is not little-endian v1/256"); + "profile header is not little-endian v2/256"); for (uint8_t index = 0; index < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; ++index) { require(encoded[4 + index] == index, @@ -56,7 +57,12 @@ void test_profile_wire_schema() { encoded[30] == 0, "default stick encoding changed"); require(encoded[54] == 0xff && encoded[55] == 0xff && - encoded[58] == 0x00 && encoded[59] == 0x80, + encoded[58] == + static_cast( + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD) && + encoded[59] == + static_cast( + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD >> 8), "default trigger encoding changed"); require(encoded[72] == 0xff && encoded[73] == 0xff && encoded[74] == 3 && encoded[78] == 0xff && @@ -84,11 +90,35 @@ void test_profile_wire_schema() { invalid.sticks[0].outer_saturation; require(!controller_profile_validate(invalid), "empty stick range was accepted"); + ControllerProfile boundary = profile; + boundary.triggers[0].lower_deadzone = 30000; + boundary.triggers[0].upper_saturation = 40000; + boundary.triggers[0].digital_threshold = 0; + uint8_t boundary_encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + require(controller_profile_encode(boundary, boundary_encoded, + sizeof(boundary_encoded)) && + controller_profile_decode(boundary_encoded, + sizeof(boundary_encoded), + &decoded) && + decoded.triggers[0].digital_threshold == 0, + "current profile rejected zero transformed trigger threshold"); + boundary.triggers[0].digital_threshold = UINT16_MAX; + require(controller_profile_encode(boundary, boundary_encoded, + sizeof(boundary_encoded)) && + controller_profile_decode(boundary_encoded, + sizeof(boundary_encoded), + &decoded) && + decoded.triggers[0].digital_threshold == UINT16_MAX, + "current profile rejected maximum transformed trigger threshold"); invalid = profile; - invalid.triggers[0].digital_threshold = 0; - invalid.triggers[0].lower_deadzone = 1; + invalid.triggers[0].lower_deadzone = + invalid.triggers[0].upper_saturation; require(!controller_profile_validate(invalid), - "trigger threshold outside its range was accepted"); + "empty raw trigger range was accepted"); + invalid.triggers[0].lower_deadzone = UINT16_MAX; + invalid.triggers[0].upper_saturation = UINT16_MAX - 1; + require(!controller_profile_validate(invalid), + "reversed raw trigger range was accepted"); invalid = profile; invalid.turbo_modes[0] = static_cast(3); @@ -110,6 +140,97 @@ void test_profile_wire_schema() { "macro without a final end was accepted"); } +void test_legacy_profile_migration() { + ControllerProfile migrated{}; + require(controller_profile_decode( + kLegacyDefaultProfile, sizeof(kLegacyDefaultProfile), + &migrated), + "legacy default profile did not decode"); + require(migrated.triggers[0].digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + migrated.triggers[1].digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD, + "legacy inherited thresholds were not migrated"); + + uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + require(controller_profile_encode(migrated, encoded, sizeof(encoded)), + "migrated default profile did not encode"); + for (size_t index = 0; index < sizeof(encoded); ++index) { + const bool schema_byte = index == 0; + const bool threshold_byte = + (index >= 58 && index < 60) || + (index >= 68 && index < 70); + if (!schema_byte && !threshold_byte) { + require(encoded[index] == kLegacyDefaultProfile[index], + "legacy default profile changed an unrelated byte"); + } + } + require(encoded[0] == CONTROLLER_PROFILE_SCHEMA_VERSION && + encoded[58] == + static_cast( + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD) && + encoded[59] == + static_cast( + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD >> 8) && + encoded[68] == + static_cast( + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD) && + encoded[69] == + static_cast( + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD >> 8), + "migrated default profile did not encode as v2"); + + require(controller_profile_decode( + kLegacyNarrowRawRangeProfile, + sizeof(kLegacyNarrowRawRangeProfile), &migrated), + "legacy narrow-raw-range profile did not decode"); + require(migrated.triggers[0].lower_deadzone == 30000 && + migrated.triggers[0].upper_saturation == 40000 && + migrated.triggers[0].digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + migrated.triggers[1].lower_deadzone == 30000 && + migrated.triggers[1].upper_saturation == 40000 && + migrated.triggers[1].digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD, + "legacy narrow raw range or inherited threshold was not migrated"); + require(controller_profile_encode(migrated, encoded, sizeof(encoded)), + "migrated narrow-raw-range profile did not encode"); + for (size_t index = 0; index < sizeof(encoded); ++index) { + const bool schema_byte = index == 0; + const bool threshold_byte = + (index >= 58 && index < 60) || + (index >= 68 && index < 70); + if (!schema_byte && !threshold_byte) { + require( + encoded[index] == kLegacyNarrowRawRangeProfile[index], + "narrow-raw-range migration changed unrelated profile data"); + } + } + + require(controller_profile_decode( + kLegacyCustomThresholdProfile, + sizeof(kLegacyCustomThresholdProfile), &migrated), + "legacy custom-threshold profile did not decode"); + require(migrated.triggers[0].digital_threshold == 0x1234 && + migrated.triggers[1].digital_threshold == 0xabcd, + "legacy custom thresholds were not preserved"); + require(controller_profile_encode(migrated, encoded, sizeof(encoded)), + "legacy custom-threshold profile did not re-encode"); + for (size_t index = 1; index < sizeof(encoded); ++index) { + require(encoded[index] == kLegacyCustomThresholdProfile[index], + "legacy custom-threshold profile changed data"); + } + + ControllerProfile current = + controller_profile_default(controller_identity_global(), 0); + current.triggers[0].digital_threshold = 0x8000; + require(controller_profile_encode(current, encoded, sizeof(encoded)) && + controller_profile_decode(encoded, sizeof(encoded), + &migrated) && + migrated.triggers[0].digital_threshold == 0x8000, + "v2 custom threshold matching the legacy default was migrated"); +} + void test_database_round_trip_and_capacity() { controller_profile_database_default(&database); for (uint8_t index = 0; @@ -141,6 +262,10 @@ void test_database_round_trip_and_capacity() { database, offset, &encoded_database[offset], size), "database range did not encode"); } + require(encoded_database[4] == + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION && + encoded_database[5] == 0, + "database encoder did not emit v2"); require(controller_profile_database_decode( read_encoded_database, nullptr, &decoded_database), "database did not decode"); @@ -157,6 +282,7 @@ void test_database_round_trip_and_capacity() { } // namespace int main() { test_profile_wire_schema(); + test_legacy_profile_migration(); test_database_round_trip_and_capacity(); return 0; } diff --git a/tests/controller_profile_transform_test.cpp b/tests/controller_profile_transform_test.cpp new file mode 100644 index 0000000..e398638 --- /dev/null +++ b/tests/controller_profile_transform_test.cpp @@ -0,0 +1,385 @@ +#include "controller_identity.h" +#include "controller_profile.h" +#include "controller_profile_transform.h" + +#include +#include +#include +#include + +namespace { + +void require(bool condition, const char* message) { + if (!condition) { + std::cerr << message << '\n'; + std::exit(1); + } +} + +ControllerProfile default_profile() { + return controller_profile_default(controller_identity_global(), 0); +} + +bool states_equal(const ControllerState& left, const ControllerState& right) { + return left.dpad_up == right.dpad_up && + left.dpad_down == right.dpad_down && + left.dpad_left == right.dpad_left && + left.dpad_right == right.dpad_right && + left.button_south == right.button_south && + left.button_east == right.button_east && + left.button_west == right.button_west && + left.button_north == right.button_north && + left.button_left_shoulder == right.button_left_shoulder && + left.button_right_shoulder == right.button_right_shoulder && + left.button_select == right.button_select && + left.button_start == right.button_start && + left.button_system == right.button_system && + left.button_capture == right.button_capture && + left.button_left_stick == right.button_left_stick && + left.button_right_stick == right.button_right_stick && + left.left_trigger == right.left_trigger && + left.right_trigger == right.right_trigger && + left.left_stick_x == right.left_stick_x && + left.left_stick_y == right.left_stick_y && + left.right_stick_x == right.right_stick_x && + left.right_stick_y == right.right_stick_y && + left.motion_sample_count == right.motion_sample_count && + std::memcmp(left.motion_samples, right.motion_samples, + sizeof(left.motion_samples)) == 0; +} + +ControllerProfileTransformResult transform_left_stick( + const ControllerProfileStickConfiguration& configuration, int16_t x, + int16_t y) { + ControllerProfile profile = default_profile(); + profile.sticks[0] = configuration; + ControllerState state{}; + state.left_stick_x = x; + state.left_stick_y = y; + return controller_profile_transform(state, profile); +} + +uint16_t transform_left_trigger( + const ControllerProfileTriggerConfiguration& configuration, + uint16_t value) { + ControllerProfile profile = default_profile(); + profile.triggers[0] = configuration; + ControllerState state{}; + state.left_trigger = value; + return controller_profile_transform(state, profile).state.left_trigger; +} + +void test_button_masks_and_direct_mapping() { + ControllerState state{}; + controller_profile_apply_button_mask(UINT16_MAX, &state); + require(controller_profile_extract_button_mask(state) == UINT16_MAX, + "button mask application omitted a logical button"); + controller_profile_apply_button_mask(0, &state); + require(controller_profile_extract_button_mask(state) == 0, + "zero button mask did not clear every logical button"); + controller_profile_apply_button_mask(UINT16_MAX, nullptr); + + for (uint8_t input = 0; + input < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; ++input) { + ControllerProfile profile = default_profile(); + const uint8_t output = static_cast( + CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT - 1u - input); + profile.button_map[input] = output; + state = {}; + controller_profile_apply_button_mask( + static_cast(1u << input), &state); + const ControllerProfileTransformResult transformed = + controller_profile_transform(state, profile); + require(controller_profile_extract_button_mask(transformed.state) == + static_cast(1u << output), + "a logical button did not map directly to its output"); + } + + ControllerProfile profile = default_profile(); + profile.button_map[0] = 1; + profile.button_map[1] = 2; + require(controller_profile_map_button_mask(1u, profile) == 2u, + "button mapping recursively remapped an output"); + profile.button_map[1] = 1; + require(controller_profile_map_button_mask(3u, profile) == 2u, + "duplicate mapped outputs were not combined"); + profile.button_map[0] = CONTROLLER_PROFILE_NO_BUTTON; + require(controller_profile_map_button_mask(1u, profile) == 0, + "disabled button mapping still produced output"); + + ControllerProfile invalid = default_profile(); + invalid.button_map[0] = CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; + require(!controller_profile_validate(invalid), + "logical output 16 was accepted"); + invalid.button_map[0] = 0xfe; + require(!controller_profile_validate(invalid), + "logical output 0xfe was accepted"); + invalid.button_map[0] = CONTROLLER_PROFILE_NO_BUTTON; + require(controller_profile_validate(invalid), + "disabled logical output 0xff was rejected"); +} + +void test_stick_center_boundaries_and_inversion() { + ControllerProfileStickConfiguration configuration{}; + configuration.center_x = 1234; + configuration.center_y = -2345; + configuration.inner_deadzone = 1000; + configuration.outer_saturation = 20000; + configuration.curve_q8_8 = 256; + ControllerProfileTransformResult transformed = transform_left_stick( + configuration, configuration.center_x, configuration.center_y); + require(transformed.state.left_stick_x == 0 && + transformed.state.left_stick_y == 0, + "center calibration did not precede stick shaping"); + + transformed = transform_left_stick( + configuration, + static_cast(configuration.center_x + + configuration.inner_deadzone), + configuration.center_y); + require(transformed.state.left_stick_x == 0 && + transformed.state.left_stick_y == 0, + "inner deadzone boundary was not neutral"); + transformed = transform_left_stick( + configuration, + static_cast(configuration.center_x + + configuration.inner_deadzone + 1), + configuration.center_y); + require(transformed.state.left_stick_x > 0, + "first value outside inner deadzone stayed neutral"); + + configuration.center_x = 0; + configuration.center_y = 0; + configuration.inner_deadzone = 0; + configuration.outer_saturation = 20000; + transformed = transform_left_stick(configuration, 19999, 0); + require(transformed.state.left_stick_x > 0 && + transformed.state.left_stick_x < INT16_MAX, + "value below outer saturation reached an endpoint"); + transformed = transform_left_stick(configuration, 20000, 0); + require(transformed.state.left_stick_x == INT16_MAX, + "positive outer saturation boundary missed endpoint"); + transformed = transform_left_stick(configuration, -20000, 0); + require(transformed.state.left_stick_x == INT16_MIN, + "negative outer saturation boundary missed endpoint"); + + configuration.outer_saturation = 32767; + configuration.invert_x = true; + configuration.invert_y = true; + transformed = transform_left_stick(configuration, INT16_MIN, 0); + require(transformed.state.left_stick_x == INT16_MAX, + "negative stick endpoint did not invert to positive endpoint"); + transformed = transform_left_stick(configuration, 0, INT16_MAX); + require(transformed.state.left_stick_y == INT16_MIN, + "positive stick endpoint did not invert to negative endpoint"); + + configuration.invert_x = false; + configuration.invert_y = false; + configuration.outer_saturation = 20000; + transformed = transform_left_stick(configuration, 15000, 15000); + require(transformed.state.left_stick_x < INT16_MAX && + transformed.state.left_stick_y < INT16_MAX, + "stick magnitude was not Chebyshev magnitude"); +} + +void test_stick_curves_and_monotonicity() { + ControllerProfileStickConfiguration linear{}; + linear.inner_deadzone = 0; + linear.outer_saturation = 32767; + linear.curve_q8_8 = 256; + ControllerProfileStickConfiguration slow = linear; + slow.curve_q8_8 = 512; + ControllerProfileStickConfiguration fast = linear; + fast.curve_q8_8 = 128; + + const int16_t linear_mid = + transform_left_stick(linear, 16384, 0).state.left_stick_x; + const int16_t slow_mid = + transform_left_stick(slow, 16384, 0).state.left_stick_x; + const int16_t fast_mid = + transform_left_stick(fast, 16384, 0).state.left_stick_x; + require(slow_mid < linear_mid && linear_mid < fast_mid, + "stick curve directions are reversed or ineffective"); + require(transform_left_stick(slow, 0, 0).state.left_stick_x == 0 && + transform_left_stick(fast, 32767, 0) + .state.left_stick_x == INT16_MAX, + "stick response curve did not preserve endpoints"); + + const uint16_t curves[] = {1, 128, 256, 512, UINT16_MAX}; + for (uint16_t curve : curves) { + ControllerProfileStickConfiguration configuration = linear; + configuration.curve_q8_8 = curve; + int16_t previous = 0; + for (int32_t input = 0; input <= INT16_MAX; ++input) { + const int16_t output = transform_left_stick( + configuration, + static_cast(input), 0) + .state.left_stick_x; + require(output >= previous, + "stick response was not monotonic"); + previous = output; + } + require(previous == INT16_MAX, + "monotonic stick response missed positive endpoint"); + } +} + +void test_trigger_boundaries_curves_and_thresholds() { + ControllerProfileTriggerConfiguration configuration{}; + configuration.lower_deadzone = 1000; + configuration.upper_saturation = 60000; + configuration.curve_q8_8 = 256; + configuration.digital_threshold = 32000; + require(transform_left_trigger(configuration, 999) == 0 && + transform_left_trigger(configuration, 1000) == 0, + "trigger lower deadzone boundary was not zero"); + require(transform_left_trigger(configuration, 1001) > 0, + "first trigger value above lower deadzone stayed zero"); + require(transform_left_trigger(configuration, 59999) < UINT16_MAX && + transform_left_trigger(configuration, 60000) == UINT16_MAX && + transform_left_trigger(configuration, UINT16_MAX) == + UINT16_MAX, + "trigger upper saturation boundary missed full scale"); + + ControllerProfileTriggerConfiguration slow = configuration; + slow.curve_q8_8 = 512; + ControllerProfileTriggerConfiguration fast = configuration; + fast.curve_q8_8 = 128; + const uint16_t midpoint = static_cast( + (static_cast(configuration.lower_deadzone) + + configuration.upper_saturation) / + 2u); + const uint16_t linear_mid = + transform_left_trigger(configuration, midpoint); + const uint16_t slow_mid = transform_left_trigger(slow, midpoint); + const uint16_t fast_mid = transform_left_trigger(fast, midpoint); + require(slow_mid < linear_mid && linear_mid < fast_mid, + "trigger curve directions are reversed or ineffective"); + require(transform_left_trigger(slow, configuration.lower_deadzone) == 0 && + transform_left_trigger(fast, + configuration.upper_saturation) == + UINT16_MAX, + "trigger response curve did not preserve endpoints"); + + uint16_t previous = 0; + for (uint32_t input = 0; input <= UINT16_MAX; ++input) { + const uint16_t output = transform_left_trigger( + slow, static_cast(input)); + require(output >= previous, + "trigger response was not monotonic"); + previous = output; + } + + ControllerProfile profile = default_profile(); + profile.triggers[0] = slow; + profile.triggers[0].digital_threshold = 12345; + profile.triggers[1].digital_threshold = 54321; + ControllerState state{}; + state.left_trigger = midpoint; + const ControllerProfileTransformResult transformed = + controller_profile_transform(state, profile); + require(transformed.left_trigger_digital_threshold == 12345 && + transformed.right_trigger_digital_threshold == 54321, + "profile-owned digital thresholds were not returned"); +} + +void test_default_whole_state_equivalence() { + ControllerState input{}; + input.dpad_up = true; + input.dpad_right = true; + input.button_south = true; + input.button_west = true; + input.button_left_shoulder = true; + input.button_select = true; + input.button_system = true; + input.button_capture = true; + input.button_right_stick = true; + input.left_trigger = 0; + input.right_trigger = UINT16_MAX; + input.left_stick_x = INT16_MIN; + input.left_stick_y = INT16_MAX; + input.right_stick_x = INT16_MAX; + input.right_stick_y = INT16_MIN; + input.motion_sample_count = CONTROLLER_MOTION_SAMPLE_CAPACITY; + input.motion_samples[0] = + {INT16_MIN, -30000, -1, 0, 1, INT16_MAX}; + input.motion_samples[1] = {1, 2, 3, 4, 5, 6}; + input.motion_samples[2] = + {INT16_MAX, 30000, 1, 0, -1, INT16_MIN}; + + const ControllerProfile profile = default_profile(); + const ControllerProfileTransformResult transformed = + controller_profile_transform(input, profile); + require(states_equal(input, transformed.state), + "default profile changed whole controller state or motion"); + require(transformed.left_trigger_digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + transformed.right_trigger_digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD == 22934, + "default digital threshold changed"); + + for (uint32_t trigger = 0; trigger <= UINT16_MAX; ++trigger) { + ControllerState trigger_state{}; + trigger_state.left_trigger = static_cast(trigger); + trigger_state.right_trigger = static_cast(trigger); + const ControllerState output = + controller_profile_transform(trigger_state, profile).state; + require(output.left_trigger == trigger_state.left_trigger && + output.right_trigger == trigger_state.right_trigger, + "default profile lost full trigger analog precision"); + } +} + +void test_rumble_scaling_and_confirmation_policy() { + ControllerProfile profile = default_profile(); + for (uint16_t magnitude = 0; magnitude <= UINT8_MAX; ++magnitude) { + const ControllerRumbleOutput input{ + static_cast(magnitude), + static_cast(UINT8_MAX - magnitude), + }; + const ControllerRumbleOutput output = + controller_profile_scale_host_rumble(input, profile); + require(output.low_frequency_magnitude == + input.low_frequency_magnitude && + output.high_frequency_magnitude == + input.high_frequency_magnitude, + "default rumble scaling was not bit-exact identity"); + } + + profile.strong_rumble_scale = 0; + profile.weak_rumble_scale = 0; + ControllerRumbleOutput output = controller_profile_scale_host_rumble( + {UINT8_MAX, UINT8_MAX}, profile); + require(output.low_frequency_magnitude == 0 && + output.high_frequency_magnitude == 0, + "zero rumble scales did not mute both bands"); + + profile.strong_rumble_scale = 128; + profile.weak_rumble_scale = 64; + output = controller_profile_scale_host_rumble({200, 201}, profile); + require(output.low_frequency_magnitude == 100 && + output.high_frequency_magnitude == 50, + "strong/weak mid-scale rumble mapping was incorrect"); + require(controller_profile_scale_rumble_magnitude(UINT8_MAX, + UINT8_MAX) == + UINT8_MAX, + "full rumble scaling did not saturate at uint8 maximum"); + + profile.confirmation_policy = ControllerProfileConfirmationPolicy::kLed; + require(controller_profile_confirmation_policy(profile) == + ControllerProfileConfirmationPolicy::kLed, + "confirmation policy was not exposed unchanged"); +} + +} // namespace + +int main() { + test_button_masks_and_direct_mapping(); + test_stick_center_boundaries_and_inversion(); + test_stick_curves_and_monotonicity(); + test_trigger_boundaries_curves_and_thresholds(); + test_default_whole_state_equivalence(); + test_rumble_scaling_and_confirmation_policy(); + return 0; +} diff --git a/tests/profile_service_test.cpp b/tests/profile_service_test.cpp index 0239a39..646fd9b 100644 --- a/tests/profile_service_test.cpp +++ b/tests/profile_service_test.cpp @@ -82,6 +82,13 @@ ProfileServiceTransactionSnapshot transaction_snapshot() { return snapshot; } +ProfileServiceActiveProfileSnapshot active_profile_snapshot( + const ControllerIdentity& identity) { + ProfileServiceActiveProfileSnapshot snapshot{}; + profile_service_active_profile_snapshot(identity, &snapshot); + return snapshot; +} + ControllerProfileDatabase reload_database( const ProfileServiceTransactionSnapshot& transaction, uint32_t expected_generation) { @@ -102,6 +109,14 @@ void test_pending_commands_are_not_decoded_as_profile_writes() { memset(flash.bytes, 0xff, sizeof(flash.bytes)); profile_service_prepare(); profile_service_initialize_on_storage_core(); + ProfileServiceActiveProfileSnapshot active = + active_profile_snapshot(controller_identity_global()); + require(active.valid && + active.metadata.state == ProfileServiceState::kReady && + active.metadata.generation == 0 && + profile_service_database_generation() == 0 && + active.profile_index == 0, + "initial active profile snapshot was not coherent"); const ControllerIdentity identity = controller_identity_global(); constexpr uint8_t kProfileIndex = 2; @@ -128,6 +143,11 @@ void test_pending_commands_are_not_decoded_as_profile_writes() { require(transaction_snapshot().transaction.status == ConfigurationTransactionStatus::kCommitted, "profile write baseline did not commit"); + active = active_profile_snapshot(identity); + require(active.valid && active.metadata.generation == 1 && + profile_service_database_generation() == 1 && + active.profile_index == 0, + "profile write did not publish one coherent generation"); constexpr uint32_t kResetTransactionId = 0xa5a55a5a; require(profile_service_reset(kResetTransactionId, identity, @@ -150,6 +170,11 @@ void test_pending_commands_are_not_decoded_as_profile_writes() { require(recovered.fallback_profiles[kProfileIndex].strong_rumble_scale == UINT8_MAX, "terminal reset status was published before reset persisted"); + active = active_profile_snapshot(identity); + require(active.valid && active.metadata.generation == 2 && + profile_service_database_generation() == 2 && + active.profile_index == 0, + "profile reset did not refresh the active snapshot generation"); constexpr uint32_t kActivateTransactionId = 0x50607080; constexpr uint8_t kActivatedProfile = 3; @@ -162,6 +187,10 @@ void test_pending_commands_are_not_decoded_as_profile_writes() { activate.transaction.status == ConfigurationTransactionStatus::kPending, "pending activation lost its transaction identity"); + active = active_profile_snapshot(identity); + require(active.valid && active.metadata.generation == 2 && + active.profile_index == 0, + "pending activation leaked an uncommitted active profile"); profile_service_task_on_storage_core(2000); activate = transaction_snapshot(); @@ -172,6 +201,14 @@ void test_pending_commands_are_not_decoded_as_profile_writes() { recovered = reload_database(activate, 3); require(recovered.fallback_active_profile == kActivatedProfile, "terminal activation status was published before activation persisted"); + active = active_profile_snapshot(identity); + require(active.valid && active.metadata.generation == 3 && + profile_service_database_generation() == 3 && + active.profile_index == kActivatedProfile && + active.profile.strong_rumble_scale == + recovered.fallback_profiles[kActivatedProfile] + .strong_rumble_scale, + "activation did not publish profile, index, and generation together"); } } // namespace diff --git a/tests/profile_storage_test.cpp b/tests/profile_storage_test.cpp index 6301bb0..957a8cb 100644 --- a/tests/profile_storage_test.cpp +++ b/tests/profile_storage_test.cpp @@ -1,6 +1,7 @@ #include "controller_identity.h" #include "controller_profile.h" #include "profile_storage.h" +#include "tests/controller_profile_legacy_fixtures.h" #include #include @@ -15,6 +16,7 @@ struct FakeFlash { bool corrupt_next_program = false; bool fail_reads_after_header_program = false; bool header_programmed = false; + int erase_count = 0; }; FakeFlash flash{}; @@ -35,6 +37,7 @@ void erase_all() { flash.corrupt_next_program = false; flash.fail_reads_after_header_program = false; flash.header_programmed = false; + flash.erase_count = 0; } bool fake_read(void* context, uint8_t bank, size_t offset, @@ -62,6 +65,7 @@ bool fake_erase_sector(void* context, uint8_t bank, size_t offset) { PROFILE_STORAGE_BANK_SIZE - offset) { return false; } + ++storage->erase_count; memset(&storage->bytes[bank][offset], 0xff, PROFILE_STORAGE_SECTOR_SIZE); return true; @@ -107,6 +111,91 @@ ProfileStorageIo fake_io() { }; } +uint16_t fixture_read_u16(const uint8_t* input) { + return static_cast(input[0]) | + static_cast(input[1] << 8); +} + +void fixture_write_u16(uint8_t* output, uint16_t value) { + output[0] = static_cast(value); + output[1] = static_cast(value >> 8); +} + +void fixture_write_u32(uint8_t* output, uint32_t value) { + output[0] = static_cast(value); + output[1] = static_cast(value >> 8); + output[2] = static_cast(value >> 16); + output[3] = static_cast(value >> 24); +} + +void install_legacy_database_bank_fixture() { + erase_all(); + constexpr uint8_t kBank = 1; + constexpr uint32_t kGeneration = 41; + constexpr size_t kFallbackOffset = + CONTROLLER_PROFILE_DATABASE_HEADER_SIZE; + constexpr size_t kEntryOffset = + kFallbackOffset + + CONTROLLER_PROFILE_COUNT * CONTROLLER_PROFILE_ENCODED_SIZE; + constexpr uint8_t kEntryHeader[CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE] = { + 1, 1, 7, 0, 1, 2, 3, 4, 5, 6, 0x7e, 0x05, 0x09, 0x20, 3, 1, + }; + + uint8_t* const record = flash.bytes[kBank]; + uint8_t* const payload = record + PROFILE_STORAGE_RECORD_HEADER_SIZE; + memset(record, 0, PROFILE_STORAGE_RECORD_HEADER_SIZE); + memset(payload, 0, CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE); + + memcpy(payload, "SPDB", 4); + fixture_write_u16(&payload[4], + CONTROLLER_PROFILE_DATABASE_LEGACY_SCHEMA_VERSION); + fixture_write_u16( + &payload[6], + static_cast(CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE)); + payload[8] = CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY; + payload[9] = CONTROLLER_PROFILE_COUNT; + payload[10] = 2; + payload[11] = 1; + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const uint8_t* fixture = + profile_index == 0 + ? kLegacyNarrowRawRangeProfile + : profile_index == 1 ? kLegacyCustomThresholdProfile + : kLegacyDefaultProfile; + memcpy(&payload[kFallbackOffset + + profile_index * CONTROLLER_PROFILE_ENCODED_SIZE], + fixture, CONTROLLER_PROFILE_ENCODED_SIZE); + } + + memcpy(&payload[kEntryOffset], kEntryHeader, sizeof(kEntryHeader)); + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const uint8_t* fixture = + profile_index == 0 + ? kLegacyNarrowRawRangeProfile + : profile_index == 3 ? kLegacyCustomThresholdProfile + : kLegacyDefaultProfile; + memcpy(&payload[kEntryOffset + + CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE + + profile_index * CONTROLLER_PROFILE_ENCODED_SIZE], + fixture, CONTROLLER_PROFILE_ENCODED_SIZE); + } + + const uint32_t payload_crc = profile_storage_crc32( + payload, CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE); + memcpy(record, "SPPF", 4); + fixture_write_u16(&record[4], 1); + fixture_write_u16(&record[6], + CONTROLLER_PROFILE_DATABASE_LEGACY_SCHEMA_VERSION); + fixture_write_u32(&record[8], kGeneration); + fixture_write_u32( + &record[12], + static_cast(CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE)); + fixture_write_u32(&record[16], payload_crc); + fixture_write_u32(&record[20], profile_storage_crc32(record, 20)); +} + void test_two_bank_recovery() { erase_all(); controller_profile_database_default(&database); @@ -225,11 +314,180 @@ void test_payload_corruption_prevents_header_publication() { "headerless corrupt payload was recovered"); } +void test_legacy_database_bank_migration() { + install_legacy_database_bank_fixture(); + ProfileStorage storage; + require(storage.initialize(fake_io(), &recovered_database) && + storage.snapshot().valid && + storage.snapshot().active_bank == 1 && + storage.snapshot().generation == 41, + "legacy v1 database bank was not selected"); + require(flash.erase_count == 0, + "legacy bank admission erased flash"); + require(recovered_database.fallback_active_profile == 2, + "legacy fallback active profile was not preserved"); + + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const uint16_t expected_left = + profile_index == 1 + ? 0x1234 + : CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; + const uint16_t expected_right = + profile_index == 1 + ? 0xabcd + : CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; + require(recovered_database.fallback_profiles[profile_index] + .triggers[0] + .digital_threshold == expected_left && + recovered_database.fallback_profiles[profile_index] + .triggers[1] + .digital_threshold == expected_right, + "legacy fallback thresholds were not selectively migrated"); + } + require(recovered_database.fallback_profiles[0] + .triggers[0] + .lower_deadzone == 30000 && + recovered_database.fallback_profiles[0] + .triggers[0] + .upper_saturation == 40000 && + recovered_database.fallback_profiles[0] + .triggers[1] + .lower_deadzone == 30000 && + recovered_database.fallback_profiles[0] + .triggers[1] + .upper_saturation == 40000, + "legacy fallback raw trigger ranges were not preserved"); + + const ControllerProfileDatabaseEntry& entry = + recovered_database.entries[0]; + require(entry.used && entry.active_profile == 3 && + entry.identity.stable && + entry.identity.transport == ControllerTransport::kClassic && + entry.identity.address_type == 7 && + entry.identity.address[0] == 1 && + entry.identity.address[5] == 6 && + entry.identity.vendor_id == 0x057e && + entry.identity.product_id == 0x2009, + "legacy entry identity or active profile was not preserved"); + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + const uint16_t expected_left = + profile_index == 3 + ? 0x1234 + : CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; + const uint16_t expected_right = + profile_index == 3 + ? 0xabcd + : CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD; + require(entry.profiles[profile_index] + .triggers[0] + .digital_threshold == expected_left && + entry.profiles[profile_index] + .triggers[1] + .digital_threshold == expected_right, + "legacy entry thresholds were not selectively migrated"); + } + require(entry.profiles[0].triggers[0].lower_deadzone == 30000 && + entry.profiles[0].triggers[0].upper_saturation == 40000 && + entry.profiles[0].triggers[1].lower_deadzone == 30000 && + entry.profiles[0].triggers[1].upper_saturation == 40000, + "legacy entry raw trigger ranges were not preserved"); + + recovered_database.fallback_profiles[2].weak_rumble_scale = 17; + require(storage.commit(recovered_database) == + ProfileStorageResult::kOk && + storage.snapshot().active_bank == 0 && + storage.snapshot().generation == 42, + "mutation after legacy admission did not commit"); + const uint8_t* const current_record = flash.bytes[0]; + const uint8_t* const current_payload = + current_record + PROFILE_STORAGE_RECORD_HEADER_SIZE; + require(fixture_read_u16(¤t_record[6]) == + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION && + fixture_read_u16(¤t_payload[4]) == + CONTROLLER_PROFILE_DATABASE_SCHEMA_VERSION, + "post-migration commit did not emit v2 storage schemas"); + constexpr size_t kFallbackOffset = + CONTROLLER_PROFILE_DATABASE_HEADER_SIZE; + constexpr size_t kEntryOffset = + kFallbackOffset + + CONTROLLER_PROFILE_COUNT * CONTROLLER_PROFILE_ENCODED_SIZE; + for (uint8_t profile_index = 0; + profile_index < CONTROLLER_PROFILE_COUNT; ++profile_index) { + require(fixture_read_u16( + ¤t_payload[kFallbackOffset + + profile_index * + CONTROLLER_PROFILE_ENCODED_SIZE]) == + CONTROLLER_PROFILE_SCHEMA_VERSION && + fixture_read_u16( + ¤t_payload[ + kEntryOffset + + CONTROLLER_PROFILE_DATABASE_ENTRY_HEADER_SIZE + + profile_index * + CONTROLLER_PROFILE_ENCODED_SIZE]) == + CONTROLLER_PROFILE_SCHEMA_VERSION, + "post-migration commit retained a v1 profile"); + } + require(fixture_read_u16(&flash.bytes[1][6]) == + CONTROLLER_PROFILE_DATABASE_LEGACY_SCHEMA_VERSION && + fixture_read_u16( + &flash.bytes[1][PROFILE_STORAGE_RECORD_HEADER_SIZE + 4]) == + CONTROLLER_PROFILE_DATABASE_LEGACY_SCHEMA_VERSION, + "post-migration commit erased or rewrote the admitted legacy bank"); + + ProfileStorage reloaded; + require(reloaded.initialize(fake_io(), &database) && + reloaded.snapshot().generation == 42 && + database.fallback_profiles[2].weak_rumble_scale == 17 && + database.fallback_profiles[0] + .triggers[0] + .lower_deadzone == 30000 && + database.fallback_profiles[0] + .triggers[0] + .upper_saturation == 40000 && + database.fallback_profiles[0] + .triggers[0] + .digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + database.fallback_profiles[1] + .triggers[0] + .digital_threshold == 0x1234 && + database.fallback_profiles[1] + .triggers[1] + .digital_threshold == 0xabcd && + database.entries[0].used && + database.entries[0].active_profile == 3 && + database.entries[0] + .profiles[0] + .triggers[0] + .lower_deadzone == 30000 && + database.entries[0] + .profiles[0] + .triggers[0] + .upper_saturation == 40000 && + database.entries[0] + .profiles[0] + .triggers[0] + .digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && + database.entries[0] + .profiles[3] + .triggers[0] + .digital_threshold == 0x1234 && + database.entries[0] + .profiles[3] + .triggers[1] + .digital_threshold == 0xabcd, + "v2 migration commit did not reload without data loss"); +} + } // namespace int main() { test_two_bank_recovery(); test_interrupted_commit_retains_previous_bank(); test_successful_header_program_is_commit_point(); test_payload_corruption_prevents_header_publication(); + test_legacy_database_bank_migration(); return 0; } diff --git a/tests/switch_pro_driver_context_test.cpp b/tests/switch_pro_driver_context_test.cpp index 3130f38..ce7dfac 100644 --- a/tests/switch_pro_driver_context_test.cpp +++ b/tests/switch_pro_driver_context_test.cpp @@ -289,7 +289,9 @@ void test_input_reports_and_timers_are_isolated() { states[3].button_west = true; for (uint8_t instance = 0; instance < kInstanceCount; ++instance) { - switch_pro_set_input(instance, states[instance]); + switch_pro_set_input(instance, states[instance], + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); } now_ms = 15; @@ -328,7 +330,9 @@ void test_input_reports_and_timers_are_isolated() { ControllerState changed_zero = states[0]; changed_zero.button_east = false; changed_zero.button_system = true; - switch_pro_set_input(0, changed_zero); + switch_pro_set_input(0, changed_zero, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); now_ms = 30; expect(switch_pro_task(0), "instance 0 did not apply its changed input state"); @@ -341,7 +345,9 @@ void test_input_reports_and_timers_are_isolated() { ControllerState changed_three = states[3]; changed_three.button_west = false; changed_three.button_capture = true; - switch_pro_set_input(3, changed_three); + switch_pro_set_input(3, changed_three, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); now_ms = 45; expect(switch_pro_task(3), "instance 3 did not apply its changed input state"); @@ -370,8 +376,10 @@ void test_callback_send_and_imu_modes_are_isolated() { ControllerState one = zero; one.button_north = true; one.motion_samples[0] = {1001, 2002, 3003, 4004, 5005, 6006}; - switch_pro_set_input(0, zero); - switch_pro_set_input(1, one); + switch_pro_set_input(0, zero, SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); + switch_pro_set_input(1, one, SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); now_ms = 21; expect(switch_pro_task(0), "raw-IMU instance did not send input"); expect(switch_pro_task(1), "off-IMU instance timer did not send input"); @@ -400,8 +408,11 @@ void test_callback_send_and_imu_modes_are_isolated() { stationary.right_stick_x = stationary.right_stick_y = 0; stationary.motion_sample_count = 1; stationary.motion_samples[0] = {1000, 2000, 3000, 0, 0, 0}; - switch_pro_set_input(0, moving); - switch_pro_set_input(1, stationary); + switch_pro_set_input(0, moving, SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); + switch_pro_set_input(1, stationary, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); now_ms = 21; expect(switch_pro_task(0), "moving quaternion instance did not report"); expect(switch_pro_task(1), "stationary quaternion timer crossed instances"); @@ -578,7 +589,9 @@ void test_lifecycle_and_invalid_instances() { ControllerState ignored{}; ignored.button_system = true; switch_pro_init(kInvalidInstance); - switch_pro_set_input(kInvalidInstance, ignored); + switch_pro_set_input(kInvalidInstance, ignored, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); switch_pro_set_rumble_callback(kInvalidInstance, rumble_callback); expect(!switch_pro_task(kInvalidInstance), "invalid instance ran a driver task"); @@ -598,7 +611,8 @@ void test_protocol_neutral_trigger_threshold() { state.left_trigger = static_cast(SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD - 1u); state.right_trigger = SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; - switch_pro_set_input(0, state); + switch_pro_set_input(0, state, SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); now_ms = 15; expect(switch_pro_task(0), "trigger threshold report was not sent"); SwitchProReport report = copy_switch_report(latest_regular_report(0)); @@ -607,7 +621,8 @@ void test_protocol_neutral_trigger_threshold() { state.left_trigger = SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD; state.right_trigger = CONTROLLER_TRIGGER_MIN; - switch_pro_set_input(0, state); + switch_pro_set_input(0, state, SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); now_ms = 30; expect(switch_pro_task(0), "second trigger threshold report was not sent"); report = copy_switch_report(latest_regular_report(0)); @@ -615,13 +630,36 @@ void test_protocol_neutral_trigger_threshold() { "Switch trigger threshold changed at the upper boundary"); } +void test_custom_trigger_thresholds_are_isolated() { + initialize_contexts(); + ControllerState state{}; + state.left_trigger = 300; + state.right_trigger = 300; + switch_pro_set_input(0, state, 300, 301); + switch_pro_set_input(1, state, 301, 300); + + now_ms = 15; + expect(switch_pro_task(0) && switch_pro_task(1), + "custom trigger threshold reports were not sent"); + const SwitchProReport first = + copy_switch_report(latest_regular_report(0)); + const SwitchProReport second = + copy_switch_report(latest_regular_report(1)); + expect(first.inputs.buttonZL && !first.inputs.buttonZR, + "instance 0 did not use its exact left/right trigger thresholds"); + expect(!second.inputs.buttonZL && second.inputs.buttonZR, + "instance 1 trigger thresholds crossed HID contexts"); +} + void test_uart_parser_is_pure() { initialize_contexts(); ControllerState driver_state{}; driver_state.left_stick_x = driver_state.left_stick_y = driver_state.right_stick_x = driver_state.right_stick_y = 0; driver_state.button_north = true; - switch_pro_set_input(0, driver_state); + switch_pro_set_input(0, driver_state, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD, + SWITCH_PRO_DIGITAL_TRIGGER_THRESHOLD); now_ms = 15; switch_pro_task(0); @@ -724,6 +762,7 @@ int main() { test_grip_colors_are_isolated(); test_lifecycle_and_invalid_instances(); test_protocol_neutral_trigger_threshold(); + test_custom_trigger_thresholds_are_isolated(); test_uart_parser_is_pure(); if (failures != 0) { std::cerr << failures << " driver context test(s) failed\n"; diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index 5819074..0cd83d5 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -500,6 +500,13 @@ def test_identity_and_profile_binary_json_round_trip() -> None: with pytest.raises(config_manager.ConfigManagerError): config_manager.ControllerIdentity.from_bytes(malformed_identity) + default_profile = config_manager.ControllerProfile.default() + assert default_profile.left_trigger.digital_threshold == 22934 + assert default_profile.right_trigger.digital_threshold == 22934 + default_wire = default_profile.to_bytes() + assert struct.unpack_from(" None: assert config_manager.ControllerProfile.from_bytes(encoded) == profile serialized = profile.to_json() - assert serialized.startswith('{\n "schema_version": 1,\n "size": 256,') + assert serialized.startswith('{\n "schema_version": 2,\n "size": 256,') decoded = config_manager.ControllerProfile.from_json(serialized) assert decoded == profile assert decoded.to_json() == serialized + legacy_default_wire = bytearray(default_wire) + struct.pack_into( + " None: + for threshold in (0, 0xFFFF): + trigger = config_manager.TriggerConfig(30000, 40000, 256, threshold) + assert config_manager.TriggerConfig.from_bytes(trigger.to_bytes()) == trigger + assert ( + config_manager.TriggerConfig.from_json_object( + trigger.to_json_object(), "trigger" + ) + == trigger + ) + + current_wire = bytearray( + config_manager.ControllerProfile.default().to_bytes() + ) + struct.pack_into( + " None: device = FakeDevice() diff --git a/tests/test_controller_profile_runtime_native.py b/tests/test_controller_profile_runtime_native.py new file mode 100644 index 0000000..92ebce1 --- /dev/null +++ b/tests/test_controller_profile_runtime_native.py @@ -0,0 +1,32 @@ +import shutil +import subprocess +from pathlib import Path + + +def test_controller_profile_runtime_native(tmp_path: Path) -> None: + root = Path(__file__).resolve().parents[1] + compiler = shutil.which("c++") or shutil.which("g++") + assert compiler is not None, "a host C++ compiler is required" + + executable = tmp_path / "controller_profile_runtime_test" + subprocess.run( + [ + compiler, + "-std=c++17", + "-Wall", + "-Wextra", + "-Werror", + "-pedantic", + f"-I{root}", + str(root / "tests" / "controller_profile_runtime_test.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "controller_profile_transform.cpp"), + str(root / "controller_profile_runtime.cpp"), + "-o", + str(executable), + ], + check=True, + cwd=root, + ) + subprocess.run([str(executable)], check=True, cwd=root) diff --git a/tests/test_controller_profile_transform_native.py b/tests/test_controller_profile_transform_native.py new file mode 100644 index 0000000..474cdb6 --- /dev/null +++ b/tests/test_controller_profile_transform_native.py @@ -0,0 +1,31 @@ +import shutil +import subprocess +from pathlib import Path + + +def test_controller_profile_transform_native(tmp_path: Path) -> None: + root = Path(__file__).resolve().parents[1] + compiler = shutil.which("c++") or shutil.which("g++") + assert compiler is not None, "a host C++ compiler is required" + + executable = tmp_path / "controller_profile_transform_test" + subprocess.run( + [ + compiler, + "-std=c++17", + "-Wall", + "-Wextra", + "-Werror", + "-pedantic", + f"-I{root}", + str(root / "tests" / "controller_profile_transform_test.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "controller_profile_transform.cpp"), + "-o", + str(executable), + ], + check=True, + cwd=root, + ) + subprocess.run([str(executable)], check=True, cwd=root) diff --git a/tests/usb_configuration_management_test.cpp b/tests/usb_configuration_management_test.cpp index 093c8b3..27d9e2c 100644 --- a/tests/usb_configuration_management_test.cpp +++ b/tests/usb_configuration_management_test.cpp @@ -279,7 +279,12 @@ void test_profile_vendor_requests() { control_payload.size() == kResponseHeaderSize + CONTROLLER_PROFILE_ENCODED_SIZE && - control_payload[kResponseHeaderSize] == 1 && + control_payload[10] == + CONTROLLER_PROFILE_SCHEMA_VERSION && + control_payload[kResponseHeaderSize] == + static_cast( + CONTROLLER_PROFILE_SCHEMA_VERSION) && + control_payload[kResponseHeaderSize + 1] == 0 && control_payload[kResponseHeaderSize + 2] == 0 && control_payload[kResponseHeaderSize + 3] == 1, "selected profile response was not encoded"); From 114266836dfe4ae85590e26cc5bebc03622c4cfb Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 2 Sep 2026 17:55:31 -0600 Subject: [PATCH 3/5] Add deterministic macros and turbo --- CMakeLists.txt | 1 + configuration_service.cpp | 10 + configuration_service.h | 4 + controller_profile_runtime.cpp | 40 +- controller_profile_runtime.h | 10 +- controller_synthetic_input.cpp | 237 +++++++++ controller_synthetic_input.h | 34 ++ switch-pico.cpp | 12 +- tests/controller_profile_runtime_test.cpp | 196 +++++++- tests/controller_synthetic_input_test.cpp | 465 ++++++++++++++++++ .../test_controller_profile_runtime_native.py | 1 + .../test_controller_synthetic_input_native.py | 32 ++ 12 files changed, 1019 insertions(+), 23 deletions(-) create mode 100644 controller_synthetic_input.cpp create mode 100644 controller_synthetic_input.h create mode 100644 tests/controller_synthetic_input_test.cpp create mode 100644 tests/test_controller_synthetic_input_native.py diff --git a/CMakeLists.txt b/CMakeLists.txt index b35736d..4df380a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,7 @@ if(SWITCH_PICO_INPUT_BACKEND STREQUAL "BLUEPAD32") controller_identity.cpp controller_profile.cpp controller_profile_transform.cpp + controller_synthetic_input.cpp controller_profile_runtime.cpp profile_storage.cpp profile_service.cpp diff --git a/configuration_service.cpp b/configuration_service.cpp index d41199c..b71a1e0 100644 --- a/configuration_service.cpp +++ b/configuration_service.cpp @@ -14,6 +14,7 @@ bool g_prepared = false; ConfigurationStorage g_storage; ConfigurationTransaction g_transaction; ConfigurationServiceSnapshot g_snapshot; +uint32_t g_published_reset_generation = 0; bool g_has_committed = false; uint32_t g_last_commit_ms = 0; @@ -45,6 +46,7 @@ void configuration_service_prepare() { } critical_section_init(&g_lock); g_snapshot = {}; + __atomic_store_n(&g_published_reset_generation, 0, __ATOMIC_RELAXED); g_snapshot.configuration = adapter_configuration_default(); g_transaction.clear(); g_prepared = true; @@ -176,6 +178,10 @@ ConfigurationTransactionStatus configuration_service_reset( ++g_snapshot.reset_generation; } g_snapshot.transaction = g_transaction.snapshot(); + if (status == ConfigurationTransactionStatus::kPending) { + __atomic_store_n(&g_published_reset_generation, + g_snapshot.reset_generation, __ATOMIC_RELEASE); + } critical_section_exit(&g_lock); return status; } @@ -188,3 +194,7 @@ void configuration_service_snapshot(ConfigurationServiceSnapshot* output) { *output = g_snapshot; critical_section_exit(&g_lock); } + +uint32_t configuration_service_reset_generation() { + return __atomic_load_n(&g_published_reset_generation, __ATOMIC_ACQUIRE); +} diff --git a/configuration_service.h b/configuration_service.h index 9eb8ceb..e540c26 100644 --- a/configuration_service.h +++ b/configuration_service.h @@ -36,3 +36,7 @@ ConfigurationTransactionStatus configuration_service_commit( ConfigurationTransactionStatus configuration_service_reset( uint32_t transaction_id); void configuration_service_snapshot(ConfigurationServiceSnapshot* output); + +// Lock-free publication for the report path. The value changes as soon as a +// configuration reset is accepted. +uint32_t configuration_service_reset_generation(); diff --git a/controller_profile_runtime.cpp b/controller_profile_runtime.cpp index 681c42c..68da390 100644 --- a/controller_profile_runtime.cpp +++ b/controller_profile_runtime.cpp @@ -1,6 +1,8 @@ #include "controller_profile_runtime.h" +#include "configuration_service.h" #include "controller_identity.h" +#include "controller_synthetic_input.h" #include "profile_service.h" namespace { @@ -12,6 +14,10 @@ struct ControllerProfileRuntimeContext { uint32_t database_generation = 0; uint8_t active_profile_index = 0; ControllerProfile profile{}; + ControllerSyntheticInputContext synthetic{}; + bool runtime_generations_initialized = false; + AdapterUsbMode output_mode = AdapterUsbMode::kSwitchProbe; + uint32_t configuration_reset_generation = 0; }; ControllerProfileRuntimeContext @@ -41,7 +47,8 @@ void clear_context(ControllerProfileRuntimeContext* context) { void refresh_profile(ControllerProfileRuntimeContext* context, const ControllerIdentity& identity, uint32_t connection_generation, - uint32_t observed_database_generation) { + uint32_t observed_database_generation, + uint16_t current_input_button_mask) { ProfileServiceActiveProfileSnapshot snapshot{}; profile_service_active_profile_snapshot(identity, &snapshot); @@ -53,6 +60,8 @@ void refresh_profile(ControllerProfileRuntimeContext* context, : observed_database_generation; context->active_profile_index = snapshot.valid ? snapshot.profile_index : 0; context->profile = snapshot.valid ? snapshot.profile : g_default_profile; + controller_synthetic_input_cancel(&context->synthetic, + current_input_button_mask); } ControllerProfileRuntimeContext* update_context( @@ -75,9 +84,10 @@ ControllerProfileRuntimeContext* update_context( context.connection_generation != snapshot.connection_generation || !controller_identity_equal(context.identity, snapshot.identity) || context.database_generation != database_generation) { - refresh_profile(&context, snapshot.identity, - snapshot.connection_generation, - database_generation); + refresh_profile( + &context, snapshot.identity, snapshot.connection_generation, + database_generation, + controller_profile_extract_button_mask(snapshot.state)); } return &context; } @@ -94,14 +104,32 @@ void controller_profile_runtime_reset() { } ControllerProfileTransformResult controller_profile_runtime_transform( - uint8_t slot, const Bluepad32SlotSnapshot& snapshot) { + uint8_t slot, const Bluepad32SlotSnapshot& snapshot, uint32_t now_ms, + AdapterUsbMode output_mode) { initialize_defaults(); ControllerProfileRuntimeContext* context = update_context(slot, snapshot); if (context == nullptr) { return g_neutral_output; } - return controller_profile_transform(snapshot.state, context->profile); + + const uint32_t reset_generation = + configuration_service_reset_generation(); + if (!context->runtime_generations_initialized) { + context->runtime_generations_initialized = true; + context->output_mode = output_mode; + context->configuration_reset_generation = reset_generation; + } else if (context->output_mode != output_mode || + context->configuration_reset_generation != + reset_generation) { + controller_synthetic_input_cancel( + &context->synthetic, + controller_profile_extract_button_mask(snapshot.state)); + context->output_mode = output_mode; + context->configuration_reset_generation = reset_generation; + } + return controller_synthetic_input_apply( + &context->synthetic, snapshot.state, context->profile, now_ms); } ControllerRumbleOutput controller_profile_runtime_scale_host_rumble( diff --git a/controller_profile_runtime.h b/controller_profile_runtime.h index 4eb246c..85e6509 100644 --- a/controller_profile_runtime.h +++ b/controller_profile_runtime.h @@ -2,6 +2,8 @@ #include +#include "adapter_usb_mode.h" + #include "bluepad32_input_backend.h" #include "controller_profile_transform.h" @@ -17,10 +19,12 @@ struct ControllerProfileRuntimeLocalConfirmation { void controller_profile_runtime_reset(); // Refresh a slot only when its connection key or database generation changes, -// then transform the raw snapshot. Inactive snapshots return neutral output and -// invalidate the slot immediately. +// cancel synthetic state on every runtime invalidation, then apply the shared +// transform and synthetic pipeline. Inactive snapshots return neutral output +// and invalidate the slot immediately. ControllerProfileTransformResult controller_profile_runtime_transform( - uint8_t slot, const Bluepad32SlotSnapshot& snapshot); + uint8_t slot, const Bluepad32SlotSnapshot& snapshot, uint32_t now_ms, + AdapterUsbMode output_mode); // Refresh from the current slot snapshot and scale host-originated rumble. ControllerRumbleOutput controller_profile_runtime_scale_host_rumble( diff --git a/controller_synthetic_input.cpp b/controller_synthetic_input.cpp new file mode 100644 index 0000000..d777aff --- /dev/null +++ b/controller_synthetic_input.cpp @@ -0,0 +1,237 @@ +#include "controller_synthetic_input.h" + +namespace { + +constexpr uint32_t kTurboTransitionsPerSecond = 30; +constexpr uint32_t kTurboPhaseUnitsPerTransition = 1000; + +constexpr uint16_t button_bit(uint8_t button) { + return static_cast(1u << button); +} + +bool is_bound_button(uint8_t button) { + return button < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; +} + +void clear_binding(ControllerSyntheticBindingState* binding) { + *binding = {}; +} + +void start_binding(ControllerSyntheticBindingState* binding, + uint32_t now_ms) { + binding->active = true; + binding->phase_on = true; + binding->phase_units = 0; + binding->last_update_ms = now_ms; +} + +void advance_binding(ControllerSyntheticBindingState* binding, + uint32_t now_ms) { + const uint32_t elapsed_ms = now_ms - binding->last_update_ms; + const uint64_t total_units = + static_cast(binding->phase_units) + + static_cast(elapsed_ms) * kTurboTransitionsPerSecond; + const uint64_t transition_count = + total_units / kTurboPhaseUnitsPerTransition; + if ((transition_count & 1u) != 0) { + binding->phase_on = !binding->phase_on; + } + binding->phase_units = static_cast( + total_units - + transition_count * kTurboPhaseUnitsPerTransition); + binding->last_update_ms = now_ms; +} + +bool deadline_reached(uint32_t now_ms, uint32_t deadline_ms) { + return now_ms - deadline_ms < (UINT32_MAX / 2u + 1u); +} + +void stop_macro(ControllerSyntheticInputContext* context) { + context->macro_active = false; + context->macro_step_index = 0; + context->macro_deadline_ms = 0; +} + +bool start_macro(ControllerSyntheticInputContext* context, + const ControllerProfile& profile, uint32_t now_ms) { + if (profile.macro_step_count == 0 || + profile.macro_steps[0].type != + ControllerProfileMacroStepType::kState) { + stop_macro(context); + return false; + } + context->macro_active = true; + context->macro_step_index = 0; + context->macro_deadline_ms = + now_ms + profile.macro_steps[0].duration_ms; + return true; +} + +void advance_macro(ControllerSyntheticInputContext* context, + const ControllerProfile& profile, uint32_t now_ms) { + for (uint8_t transition = 0; + transition < CONTROLLER_PROFILE_MACRO_STEP_CAPACITY; + ++transition) { + if (!context->macro_active || + context->macro_step_index >= profile.macro_step_count) { + stop_macro(context); + return; + } + const ControllerProfileMacroStep& current = + profile.macro_steps[context->macro_step_index]; + if (current.type != ControllerProfileMacroStepType::kState) { + stop_macro(context); + return; + } + if (!deadline_reached(now_ms, context->macro_deadline_ms)) { + return; + } + + const uint8_t next_index = + static_cast(context->macro_step_index + 1u); + if (next_index >= profile.macro_step_count || + profile.macro_steps[next_index].type == + ControllerProfileMacroStepType::kEnd) { + stop_macro(context); + return; + } + context->macro_step_index = next_index; + context->macro_deadline_ms += + profile.macro_steps[next_index].duration_ms; + } +} + +void apply_macro_override(const ControllerProfileMacroStep& step, + ControllerState* output) { + if ((step.override_flags & kControllerProfileOverrideButtons) != 0) { + controller_profile_apply_button_mask(step.output_button_mask, + output); + } + if ((step.override_flags & kControllerProfileOverrideLeftStick) != 0) { + output->left_stick_x = step.left_stick_x; + output->left_stick_y = step.left_stick_y; + } + if ((step.override_flags & kControllerProfileOverrideRightStick) != 0) { + output->right_stick_x = step.right_stick_x; + output->right_stick_y = step.right_stick_y; + } + if ((step.override_flags & kControllerProfileOverrideLeftTrigger) != 0) { + output->left_trigger = step.left_trigger; + } + if ((step.override_flags & kControllerProfileOverrideRightTrigger) != 0) { + output->right_trigger = step.right_trigger; + } +} + +} // namespace + +void controller_synthetic_input_cancel( + ControllerSyntheticInputContext* context, + uint16_t current_input_button_mask) { + if (context == nullptr) { + return; + } + *context = {}; + context->previous_input_button_mask = current_input_button_mask; +} + +ControllerProfileTransformResult controller_synthetic_input_apply( + ControllerSyntheticInputContext* context, const ControllerState& input, + const ControllerProfile& profile, uint32_t now_ms) { + if (context == nullptr) { + return controller_profile_transform(input, profile); + } + + const uint16_t input_button_mask = + controller_profile_extract_button_mask(input); + uint16_t rising_button_mask = static_cast( + input_button_mask & ~context->previous_input_button_mask); + const bool cancel_pressed = + is_bound_button(profile.macro_cancel) && + (input_button_mask & button_bit(profile.macro_cancel)) != 0; + if (cancel_pressed) { + controller_synthetic_input_cancel(context, input_button_mask); + rising_button_mask = 0; + } + + bool macro_started = false; + if (!cancel_pressed && is_bound_button(profile.macro_trigger) && + (rising_button_mask & button_bit(profile.macro_trigger)) != 0) { + macro_started = start_macro(context, profile, now_ms); + } + if (!macro_started) { + advance_macro(context, profile, now_ms); + } + + uint16_t gated_input_button_mask = 0; + for (uint8_t input_button = 0; + input_button < CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT; + ++input_button) { + ControllerSyntheticBindingState& binding = + context->bindings[input_button]; + if (input_button == profile.macro_trigger || + input_button == profile.macro_cancel) { + clear_binding(&binding); + continue; + } + + const uint16_t bit = button_bit(input_button); + const bool pressed = (input_button_mask & bit) != 0; + const bool rising = (rising_button_mask & bit) != 0; + switch (profile.turbo_modes[input_button]) { + case ControllerProfileTurboMode::kOff: + clear_binding(&binding); + if (pressed) { + gated_input_button_mask |= bit; + } + break; + case ControllerProfileTurboMode::kTurbo: + if (!pressed) { + clear_binding(&binding); + break; + } + if (!binding.active) { + start_binding(&binding, now_ms); + } else { + advance_binding(&binding, now_ms); + } + if (binding.phase_on) { + gated_input_button_mask |= bit; + } + break; + case ControllerProfileTurboMode::kAutoBurst: + if (rising) { + if (binding.active) { + clear_binding(&binding); + } else { + start_binding(&binding, now_ms); + } + } else if (binding.active) { + advance_binding(&binding, now_ms); + } + if (binding.active && binding.phase_on) { + gated_input_button_mask |= bit; + } + break; + } + } + + ControllerState gated_input = input; + controller_profile_apply_button_mask(gated_input_button_mask, + &gated_input); + ControllerProfileTransformResult result = + controller_profile_transform(gated_input, profile); + if (context->macro_active && + context->macro_step_index < profile.macro_step_count) { + const ControllerProfileMacroStep& step = + profile.macro_steps[context->macro_step_index]; + if (step.type == ControllerProfileMacroStepType::kState) { + apply_macro_override(step, &result.state); + } else { + stop_macro(context); + } + } + + context->previous_input_button_mask = input_button_mask; + return result; +} diff --git a/controller_synthetic_input.h b/controller_synthetic_input.h new file mode 100644 index 0000000..507065c --- /dev/null +++ b/controller_synthetic_input.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "controller_profile_transform.h" + +struct ControllerSyntheticBindingState { + bool active = false; + bool phase_on = false; + uint16_t phase_units = 0; + uint32_t last_update_ms = 0; +}; + +struct ControllerSyntheticInputContext { + bool macro_active = false; + uint8_t macro_step_index = 0; + uint32_t macro_deadline_ms = 0; + uint16_t previous_input_button_mask = 0; + ControllerSyntheticBindingState + bindings[CONTROLLER_PROFILE_LOGICAL_BUTTON_COUNT]{}; +}; + +// Clear every synthetic source. Inputs already held at cancellation remain +// consumed or physical, but edge-triggered Macro and Auto Burst bindings do not +// restart until they are released and pressed again. +void controller_synthetic_input_cancel( + ControllerSyntheticInputContext* context, + uint16_t current_input_button_mask = 0); + +// Apply raw-input consumption, mapped physical contributions, Turbo/Auto Burst +// gating, and finally the active macro step's field overrides. +ControllerProfileTransformResult controller_synthetic_input_apply( + ControllerSyntheticInputContext* context, const ControllerState& input, + const ControllerProfile& profile, uint32_t now_ms); diff --git a/switch-pico.cpp b/switch-pico.cpp index bf889d9..b87c493 100644 --- a/switch-pico.cpp +++ b/switch-pico.cpp @@ -306,16 +306,24 @@ int main() { case BootselPairingButtonEvent::kNone: break; } + const uint32_t now_ms = + static_cast(to_ms_since_boot(get_absolute_time())); +#ifdef SWITCH_PICO_ADAPTER_FEASIBILITY + const AdapterUsbMode output_mode = adapter_host_probe_mode(); +#else + constexpr AdapterUsbMode output_mode = AdapterUsbMode::kSwitchProbe; +#endif for (uint8_t instance = 0; instance < BLUEPAD32_INPUT_BACKEND_SLOT_COUNT; ++instance) { Bluepad32SlotSnapshot snapshot{}; bluepad32_input_backend_snapshot(instance, &snapshot); const ControllerProfileTransformResult transformed = - controller_profile_runtime_transform(instance, snapshot); + controller_profile_runtime_transform( + instance, snapshot, now_ms, output_mode); g_user_states[instance] = transformed.state; #ifdef SWITCH_PICO_ADAPTER_FEASIBILITY bool sent = false; - if (adapter_host_probe_mode() == AdapterUsbMode::kXInput) { + if (output_mode == AdapterUsbMode::kXInput) { xinput_feasibility_set_input(instance, g_user_states[instance]); sent = xinput_feasibility_task(instance); diff --git a/tests/controller_profile_runtime_test.cpp b/tests/controller_profile_runtime_test.cpp index 92eb8d7..d2fa5c2 100644 --- a/tests/controller_profile_runtime_test.cpp +++ b/tests/controller_profile_runtime_test.cpp @@ -19,6 +19,7 @@ struct FakeProfileRow { std::array rows{}; uint32_t database_generation = 7; +uint32_t configuration_reset_generation = 3; unsigned active_snapshot_count = 0; void require(bool condition, const char* message) { @@ -41,6 +42,7 @@ ControllerIdentity make_identity(uint8_t value) { void prepare_profiles() { database_generation = 7; + configuration_reset_generation = 3; active_snapshot_count = 0; for (uint8_t slot = 0; slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { @@ -77,6 +79,14 @@ Bluepad32SlotSnapshot make_snapshot(uint8_t slot, return snapshot; } +ControllerProfileTransformResult runtime_transform( + uint8_t slot, const Bluepad32SlotSnapshot& snapshot, + uint32_t now_ms = 0, + AdapterUsbMode output_mode = AdapterUsbMode::kSwitchProbe) { + return controller_profile_runtime_transform(slot, snapshot, now_ms, + output_mode); +} + bool motion_equal(const ControllerState& first, const ControllerState& second) { return first.motion_sample_count == second.motion_sample_count && @@ -96,7 +106,7 @@ void test_four_slot_cache_and_unchanged_generation() { slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { snapshots[slot] = make_snapshot(slot); transformed[slot] = - controller_profile_runtime_transform(slot, snapshots[slot]); + runtime_transform(slot, snapshots[slot]); require(transformed[slot].left_trigger_digital_threshold == static_cast(1000u + slot) && transformed[slot].right_trigger_digital_threshold == @@ -110,7 +120,7 @@ void test_four_slot_cache_and_unchanged_generation() { for (uint8_t slot = 0; slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { transformed[slot] = - controller_profile_runtime_transform(slot, snapshots[slot]); + runtime_transform(slot, snapshots[slot]); } require(active_snapshot_count == CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT, "unchanged generations copied profiles on the report path"); @@ -119,7 +129,7 @@ void test_four_slot_cache_and_unchanged_generation() { snapshots[2].connection_generation = 2; transformed[2] = - controller_profile_runtime_transform(2, snapshots[2]); + runtime_transform(2, snapshots[2]); require(active_snapshot_count == CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT + 1 && transformed[2].left_trigger_digital_threshold == 1002, @@ -127,7 +137,7 @@ void test_four_slot_cache_and_unchanged_generation() { snapshots[3].identity = rows[1].identity; transformed[3] = - controller_profile_runtime_transform(3, snapshots[3]); + runtime_transform(3, snapshots[3]); require(active_snapshot_count == CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT + 2 && transformed[3].left_trigger_digital_threshold == 1001, @@ -139,7 +149,7 @@ void test_activation_disconnect_and_default_preservation() { Bluepad32SlotSnapshot snapshot = make_snapshot(0); snapshot.state.button_south = true; ControllerProfileTransformResult transformed = - controller_profile_runtime_transform(0, snapshot); + runtime_transform(0, snapshot); require(transformed.state.button_south && transformed.left_trigger_digital_threshold == 1000, "initial active profile was not applied"); @@ -150,25 +160,25 @@ void test_activation_disconnect_and_default_preservation() { static_cast(ControllerProfileLogicalButton::kNorth); rows[0].profiles[1].triggers[0].digital_threshold = 12345; ++database_generation; - transformed = controller_profile_runtime_transform(0, snapshot); + transformed = runtime_transform(0, snapshot); require(!transformed.state.button_south && transformed.state.button_north && transformed.left_trigger_digital_threshold == 12345, "profile activation generation did not refresh the slot cache"); const unsigned reads_before_disconnect = active_snapshot_count; snapshot.active = false; - transformed = controller_profile_runtime_transform(0, snapshot); + transformed = runtime_transform(0, snapshot); require(!transformed.state.button_south && !transformed.state.button_north && transformed.left_trigger_digital_threshold == CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD && active_snapshot_count == reads_before_disconnect, "disconnect did not neutralize output without fetching a profile"); - transformed = controller_profile_runtime_transform(0, snapshot); + transformed = runtime_transform(0, snapshot); require(active_snapshot_count == reads_before_disconnect, "an unchanged inactive slot repeatedly cleared or fetched state"); snapshot.active = true; - transformed = controller_profile_runtime_transform(0, snapshot); + transformed = runtime_transform(0, snapshot); require(active_snapshot_count == reads_before_disconnect + 1 && transformed.state.button_north, "reconnection did not reload a cleared slot cache"); @@ -186,7 +196,7 @@ void test_activation_disconnect_and_default_preservation() { default_snapshot.state.motion_sample_count = 2; default_snapshot.state.motion_samples[0] = {1, 2, 3, 4, 5, 6}; default_snapshot.state.motion_samples[1] = {-1, -2, -3, -4, -5, -6}; - transformed = controller_profile_runtime_transform(2, default_snapshot); + transformed = runtime_transform(2, default_snapshot); require(transformed.state.button_east && transformed.state.dpad_left && transformed.state.left_trigger == 32123 && transformed.state.right_trigger == 54321 && @@ -207,9 +217,9 @@ void test_analog_thresholds_rumble_and_local_confirmation() { first.state.left_trigger = second.state.left_trigger = 23456; first.state.right_trigger = second.state.right_trigger = 45678; const ControllerProfileTransformResult first_output = - controller_profile_runtime_transform(0, first); + runtime_transform(0, first); const ControllerProfileTransformResult second_output = - controller_profile_runtime_transform(1, second); + runtime_transform(1, second); require(first_output.state.left_trigger == second_output.state.left_trigger && first_output.state.right_trigger == @@ -238,12 +248,172 @@ void test_analog_thresholds_rumble_and_local_confirmation() { "local confirmation was scaled or lost its profile policy"); } +void configure_synthetic_profile(uint8_t slot) { + ControllerProfile& profile = rows[slot].profiles[0]; + profile = controller_profile_default(rows[slot].identity, 0); + profile.macro_trigger = + static_cast(ControllerProfileLogicalButton::kSouth); + profile.macro_cancel = + static_cast(ControllerProfileLogicalButton::kCapture); + profile.macro_step_count = 2; + profile.macro_steps[0].type = + ControllerProfileMacroStepType::kState; + profile.macro_steps[0].override_flags = + kControllerProfileOverrideButtons; + profile.macro_steps[0].duration_ms = 1000; + profile.macro_steps[0].output_button_mask = static_cast( + 1u << static_cast( + ControllerProfileLogicalButton::kNorth)); + profile.macro_steps[1] = {}; + profile.macro_steps[1].type = + ControllerProfileMacroStepType::kEnd; + profile.turbo_modes[static_cast( + ControllerProfileLogicalButton::kEast)] = + ControllerProfileTurboMode::kAutoBurst; +} + +void start_macro(Bluepad32SlotSnapshot* snapshot, uint32_t now_ms, + AdapterUsbMode mode = AdapterUsbMode::kSwitchProbe) { + snapshot->state = controller_neutral_state(); + (void)runtime_transform(0, *snapshot, now_ms, mode); + snapshot->state.button_south = true; + const ControllerProfileTransformResult started = + runtime_transform(0, *snapshot, now_ms + 1u, mode); + require(started.state.button_north && !started.state.button_south, + "runtime fixture did not start its macro"); + snapshot->state = controller_neutral_state(); + const ControllerProfileTransformResult held = + runtime_transform(0, *snapshot, now_ms + 2u, mode); + require(held.state.button_north, + "runtime fixture macro did not remain active"); +} + +void start_auto_burst(Bluepad32SlotSnapshot* snapshot, uint32_t now_ms, + AdapterUsbMode mode = + AdapterUsbMode::kSwitchProbe) { + snapshot->state = controller_neutral_state(); + (void)runtime_transform(0, *snapshot, now_ms, mode); + snapshot->state.button_east = true; + const ControllerProfileTransformResult started = + runtime_transform(0, *snapshot, now_ms + 1u, mode); + require(started.state.button_east, + "runtime fixture did not start Auto Burst"); + snapshot->state = controller_neutral_state(); + const ControllerProfileTransformResult latched = + runtime_transform(0, *snapshot, now_ms + 2u, mode); + require(latched.state.button_east, + "runtime fixture Auto Burst did not latch"); +} + +void require_no_synthetic_output( + const ControllerProfileTransformResult& output, + const char* message) { + require(!output.state.button_north && !output.state.button_east && + !output.state.button_south && + !output.state.button_capture, + message); +} + +void test_all_runtime_cancellation_causes() { + prepare_profiles(); + configure_synthetic_profile(0); + Bluepad32SlotSnapshot snapshot = make_snapshot(0); + start_macro(&snapshot, 10); + snapshot.active = false; + ControllerProfileTransformResult output = + runtime_transform(0, snapshot, 13); + require_no_synthetic_output( + output, "disconnect did not cancel synthetic output"); + snapshot.active = true; + output = runtime_transform(0, snapshot, 14); + require_no_synthetic_output( + output, "reconnection restored stale synthetic output"); + + prepare_profiles(); + configure_synthetic_profile(0); + snapshot = make_snapshot(0); + start_macro(&snapshot, 20); + ++snapshot.connection_generation; + output = runtime_transform(0, snapshot, 23); + require_no_synthetic_output( + output, "connection replacement did not cancel before output"); + + prepare_profiles(); + configure_synthetic_profile(0); + snapshot = make_snapshot(0); + start_macro(&snapshot, 30); + rows[0].active_profile = 1; + ++database_generation; + output = runtime_transform(0, snapshot, 33); + require_no_synthetic_output( + output, "profile/database generation change did not cancel"); + + prepare_profiles(); + configure_synthetic_profile(0); + snapshot = make_snapshot(0); + start_auto_burst(&snapshot, 40); + output = runtime_transform(0, snapshot, 43, + AdapterUsbMode::kXInput); + require_no_synthetic_output( + output, "output-mode change did not cancel Auto Burst"); + output = runtime_transform(0, snapshot, 44, + AdapterUsbMode::kXInput); + require_no_synthetic_output( + output, "output-mode cancellation left a stuck output"); + + prepare_profiles(); + configure_synthetic_profile(0); + snapshot = make_snapshot(0); + start_auto_burst(&snapshot, 50); + ++configuration_reset_generation; + output = runtime_transform(0, snapshot, 53); + require_no_synthetic_output( + output, "configuration reset did not cancel Auto Burst"); + output = runtime_transform(0, snapshot, 54); + require_no_synthetic_output( + output, "configuration reset cancellation left a stuck output"); +} + +void test_runtime_slot_synthetic_isolation() { + prepare_profiles(); + configure_synthetic_profile(0); + configure_synthetic_profile(1); + Bluepad32SlotSnapshot first = make_snapshot(0); + Bluepad32SlotSnapshot second = make_snapshot(1); + (void)runtime_transform(0, first, 0); + (void)runtime_transform(1, second, 0); + first.state.button_east = true; + second.state.button_east = true; + require(runtime_transform(0, first, 1).state.button_east && + runtime_transform(1, second, 1).state.button_east, + "runtime slots did not activate independently"); + first.state = controller_neutral_state(); + second.state = controller_neutral_state(); + require(runtime_transform(0, first, 2).state.button_east && + runtime_transform(1, second, 2).state.button_east, + "runtime Auto Burst state did not remain isolated"); + + first.state.button_capture = true; + const ControllerProfileTransformResult cancelled = + runtime_transform(0, first, 3); + const ControllerProfileTransformResult untouched = + runtime_transform(1, second, 3); + require_no_synthetic_output( + cancelled, "slot-local configured cancel did not clear its output"); + require(untouched.state.button_east, + "slot-local configured cancel affected another slot"); +} + } // namespace uint32_t profile_service_database_generation() { return database_generation; } +uint32_t configuration_service_reset_generation() { + return configuration_reset_generation; +} + void profile_service_active_profile_snapshot( const ControllerIdentity& identity, ProfileServiceActiveProfileSnapshot* output) { @@ -269,5 +439,7 @@ int main() { test_four_slot_cache_and_unchanged_generation(); test_activation_disconnect_and_default_preservation(); test_analog_thresholds_rumble_and_local_confirmation(); + test_all_runtime_cancellation_causes(); + test_runtime_slot_synthetic_isolation(); return 0; } diff --git a/tests/controller_synthetic_input_test.cpp b/tests/controller_synthetic_input_test.cpp new file mode 100644 index 0000000..7af5e26 --- /dev/null +++ b/tests/controller_synthetic_input_test.cpp @@ -0,0 +1,465 @@ +#include "controller_synthetic_input.h" + +#include +#include +#include +#include + +namespace { + +constexpr uint8_t button_index(ControllerProfileLogicalButton button) { + return static_cast(button); +} + +constexpr uint16_t button_bit(ControllerProfileLogicalButton button) { + return static_cast(1u << button_index(button)); +} + +void require(bool condition, const char* message) { + if (!condition) { + std::cerr << message << '\n'; + std::exit(1); + } +} + +ControllerState state_with_buttons(uint16_t mask) { + ControllerState state = controller_neutral_state(); + controller_profile_apply_button_mask(mask, &state); + return state; +} + +bool has_button(const ControllerProfileTransformResult& result, + ControllerProfileLogicalButton button) { + return (controller_profile_extract_button_mask(result.state) & + button_bit(button)) != 0; +} + +ControllerProfile profile_with_macro( + ControllerProfileLogicalButton trigger, + ControllerProfileLogicalButton cancel = + ControllerProfileLogicalButton::kCapture) { + ControllerProfile profile = + controller_profile_default(controller_identity_global(), 0); + profile.macro_trigger = button_index(trigger); + profile.macro_cancel = button_index(cancel); + return profile; +} + +void set_end(ControllerProfile* profile, uint8_t index) { + profile->macro_steps[index] = {}; + profile->macro_steps[index].type = + ControllerProfileMacroStepType::kEnd; +} + +void test_immediate_press_release_dpad_and_explicit_end() { + ControllerProfile profile = + profile_with_macro(ControllerProfileLogicalButton::kSouth); + profile.macro_step_count = 3; + profile.macro_steps[0].type = + ControllerProfileMacroStepType::kState; + profile.macro_steps[0].override_flags = + kControllerProfileOverrideButtons; + profile.macro_steps[0].duration_ms = 10; + profile.macro_steps[0].output_button_mask = + button_bit(ControllerProfileLogicalButton::kNorth) | + button_bit(ControllerProfileLogicalButton::kDpadUp); + profile.macro_steps[1].type = + ControllerProfileMacroStepType::kState; + profile.macro_steps[1].override_flags = + kControllerProfileOverrideButtons; + profile.macro_steps[1].duration_ms = 20; + profile.macro_steps[1].output_button_mask = 0; + set_end(&profile, 2); + + ControllerSyntheticInputContext context{}; + ControllerState input = + state_with_buttons(button_bit(ControllerProfileLogicalButton::kSouth)); + ControllerProfileTransformResult output = + controller_synthetic_input_apply(&context, input, profile, 100); + require(has_button(output, ControllerProfileLogicalButton::kNorth) && + has_button(output, ControllerProfileLogicalButton::kDpadUp) && + !has_button(output, ControllerProfileLogicalButton::kSouth), + "macro step zero was not immediate or its trigger leaked"); + + input = controller_neutral_state(); + output = controller_synthetic_input_apply(&context, input, profile, 109); + require(has_button(output, ControllerProfileLogicalButton::kNorth) && + has_button(output, ControllerProfileLogicalButton::kDpadUp), + "macro press state ended before its scheduled deadline"); + output = controller_synthetic_input_apply(&context, input, profile, 110); + require(controller_profile_extract_button_mask(output.state) == 0, + "macro release state did not replace the full button mask"); + + input = + state_with_buttons(button_bit(ControllerProfileLogicalButton::kWest)); + output = controller_synthetic_input_apply(&context, input, profile, 129); + require(!has_button(output, ControllerProfileLogicalButton::kWest), + "active macro release state did not override physical buttons"); + output = controller_synthetic_input_apply(&context, input, profile, 130); + require(has_button(output, ControllerProfileLogicalButton::kWest) && + !context.macro_active, + "explicit end did not clear overrides and restore physical input"); +} + +void test_optional_field_overrides_and_motion_preservation() { + ControllerProfile profile = + profile_with_macro(ControllerProfileLogicalButton::kSelect); + profile.macro_step_count = 2; + ControllerProfileMacroStep& step = profile.macro_steps[0]; + step.type = ControllerProfileMacroStepType::kState; + step.override_flags = kControllerProfileOverrideLeftStick | + kControllerProfileOverrideRightStick | + kControllerProfileOverrideLeftTrigger | + kControllerProfileOverrideRightTrigger; + step.duration_ms = 100; + step.left_stick_x = INT16_MIN; + step.left_stick_y = 1234; + step.right_stick_x = -2345; + step.right_stick_y = INT16_MAX; + step.left_trigger = 0; + step.right_trigger = UINT16_MAX; + set_end(&profile, 1); + + ControllerState input = state_with_buttons( + button_bit(ControllerProfileLogicalButton::kSelect) | + button_bit(ControllerProfileLogicalButton::kSouth)); + input.left_stick_x = 10; + input.left_stick_y = 20; + input.right_stick_x = 30; + input.right_stick_y = 40; + input.left_trigger = 111; + input.right_trigger = 222; + input.motion_sample_count = 2; + input.motion_samples[0] = {1, 2, 3, 4, 5, 6}; + input.motion_samples[1] = {-1, -2, -3, -4, -5, -6}; + + ControllerSyntheticInputContext context{}; + const ControllerProfileTransformResult output = + controller_synthetic_input_apply(&context, input, profile, 5); + require(has_button(output, ControllerProfileLogicalButton::kSouth) && + !has_button(output, ControllerProfileLogicalButton::kSelect), + "a trigger-only macro override changed buttons or leaked trigger"); + require(output.state.left_stick_x == INT16_MIN && + output.state.left_stick_y == 1234 && + output.state.right_stick_x == -2345 && + output.state.right_stick_y == INT16_MAX && + output.state.left_trigger == 0 && + output.state.right_trigger == UINT16_MAX, + "one or more optional macro fields were not overridden"); + require(output.state.motion_sample_count == input.motion_sample_count && + std::memcmp(output.state.motion_samples, + input.motion_samples, + sizeof(input.motion_samples)) == 0, + "synthetic processing changed motion samples"); +} + +void test_zero_max_wait_and_scheduled_catch_up() { + ControllerProfile profile = + profile_with_macro(ControllerProfileLogicalButton::kSouth); + profile.macro_step_count = 4; + profile.macro_steps[0].type = + ControllerProfileMacroStepType::kState; + profile.macro_steps[0].override_flags = + kControllerProfileOverrideButtons; + profile.macro_steps[0].duration_ms = 0; + profile.macro_steps[0].output_button_mask = + button_bit(ControllerProfileLogicalButton::kNorth); + profile.macro_steps[1].type = + ControllerProfileMacroStepType::kState; + profile.macro_steps[1].override_flags = + kControllerProfileOverrideButtons; + profile.macro_steps[1].duration_ms = CONTROLLER_PROFILE_MAX_WAIT_MS; + profile.macro_steps[1].output_button_mask = + button_bit(ControllerProfileLogicalButton::kEast); + profile.macro_steps[2].type = + ControllerProfileMacroStepType::kState; + profile.macro_steps[2].override_flags = + kControllerProfileOverrideButtons; + profile.macro_steps[2].duration_ms = 0; + profile.macro_steps[2].output_button_mask = + button_bit(ControllerProfileLogicalButton::kWest); + set_end(&profile, 3); + + ControllerSyntheticInputContext context{}; + ControllerProfileTransformResult output = + controller_synthetic_input_apply( + &context, + state_with_buttons( + button_bit(ControllerProfileLogicalButton::kSouth)), + profile, 0); + require(has_button(output, ControllerProfileLogicalButton::kNorth), + "zero-wait step zero was skipped on its trigger report"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 0); + require(has_button(output, ControllerProfileLogicalButton::kEast), + "zero wait did not advance on the next scheduler observation"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, + CONTROLLER_PROFILE_MAX_WAIT_MS - 1u); + require(has_button(output, ControllerProfileLogicalButton::kEast), + "maximum legal wait expired early"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, + CONTROLLER_PROFILE_MAX_WAIT_MS); + require(controller_profile_extract_button_mask(output.state) == 0 && + !context.macro_active, + "zero-duration catch-up did not reach the explicit end"); + + profile.macro_step_count = 4; + profile.macro_steps[0].duration_ms = 10; + profile.macro_steps[0].output_button_mask = + button_bit(ControllerProfileLogicalButton::kNorth); + profile.macro_steps[1].duration_ms = 20; + profile.macro_steps[1].output_button_mask = + button_bit(ControllerProfileLogicalButton::kEast); + profile.macro_steps[2].duration_ms = 30; + profile.macro_steps[2].output_button_mask = + button_bit(ControllerProfileLogicalButton::kWest); + context = {}; + (void)controller_synthetic_input_apply( + &context, + state_with_buttons(button_bit(ControllerProfileLogicalButton::kSouth)), + profile, 100); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 145); + require(has_button(output, ControllerProfileLogicalButton::kWest), + "catch-up used observation time instead of prior deadlines"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 1000); + require(!context.macro_active && + controller_profile_extract_button_mask(output.state) == 0, + "large time jump did not finish the bounded macro"); + + profile.macro_step_count = 2; + profile.macro_steps[0].duration_ms = 10; + profile.macro_steps[0].output_button_mask = + button_bit(ControllerProfileLogicalButton::kNorth); + set_end(&profile, 1); + context = {}; + constexpr uint32_t macro_near_wrap = UINT32_MAX - 5u; + output = controller_synthetic_input_apply( + &context, + state_with_buttons(button_bit(ControllerProfileLogicalButton::kSouth)), + profile, macro_near_wrap); + require(has_button(output, ControllerProfileLogicalButton::kNorth), + "macro did not start immediately near uint32 wrap"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 3); + require(has_button(output, ControllerProfileLogicalButton::kNorth), + "macro deadline expired early across uint32 wrap"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 4); + require(!context.macro_active && + controller_profile_extract_button_mask(output.state) == 0, + "macro deadline was not uint32-wrap safe"); +} + +void test_consumption_cancel_precedence_and_duplicate_contributors() { + ControllerProfile profile = + profile_with_macro(ControllerProfileLogicalButton::kSelect, + ControllerProfileLogicalButton::kCapture); + profile.macro_step_count = 2; + profile.macro_steps[0].type = + ControllerProfileMacroStepType::kState; + profile.macro_steps[0].override_flags = + kControllerProfileOverrideButtons; + profile.macro_steps[0].duration_ms = 100; + profile.macro_steps[0].output_button_mask = + button_bit(ControllerProfileLogicalButton::kDpadLeft); + set_end(&profile, 1); + profile.button_map[button_index(ControllerProfileLogicalButton::kSouth)] = + button_index(ControllerProfileLogicalButton::kNorth); + profile.button_map[button_index(ControllerProfileLogicalButton::kEast)] = + button_index(ControllerProfileLogicalButton::kNorth); + profile.turbo_modes[button_index(ControllerProfileLogicalButton::kSouth)] = + ControllerProfileTurboMode::kTurbo; + + ControllerSyntheticInputContext context{}; + ControllerState input = state_with_buttons( + button_bit(ControllerProfileLogicalButton::kSouth) | + button_bit(ControllerProfileLogicalButton::kEast)); + ControllerProfileTransformResult output = + controller_synthetic_input_apply(&context, input, profile, 0); + require(has_button(output, ControllerProfileLogicalButton::kNorth), + "duplicate mapped contributors were not ORed"); + output = controller_synthetic_input_apply(&context, input, profile, 34); + require(has_button(output, ControllerProfileLogicalButton::kNorth), + "Turbo gating erased a duplicate physical contributor"); + + input = state_with_buttons( + button_bit(ControllerProfileLogicalButton::kSouth) | + button_bit(ControllerProfileLogicalButton::kSelect)); + output = controller_synthetic_input_apply(&context, input, profile, 35); + require(has_button(output, ControllerProfileLogicalButton::kDpadLeft) && + !has_button(output, ControllerProfileLogicalButton::kNorth) && + !has_button(output, ControllerProfileLogicalButton::kSelect), + "macro button override did not outrank Turbo or consume trigger"); + + input = state_with_buttons( + button_bit(ControllerProfileLogicalButton::kSouth) | + button_bit(ControllerProfileLogicalButton::kCapture)); + output = controller_synthetic_input_apply(&context, input, profile, 36); + require(!context.macro_active && + !has_button(output, ControllerProfileLogicalButton::kCapture) && + has_button(output, ControllerProfileLogicalButton::kNorth), + "configured cancel leaked or failed to clear macro state"); +} + +void test_turbo_rate_release_and_uint32_wrap() { + ControllerProfile profile = + controller_profile_default(controller_identity_global(), 0); + const uint8_t south = + button_index(ControllerProfileLogicalButton::kSouth); + profile.turbo_modes[south] = ControllerProfileTurboMode::kTurbo; + const ControllerState pressed = + state_with_buttons(button_bit(ControllerProfileLogicalButton::kSouth)); + ControllerSyntheticInputContext context{}; + ControllerProfileTransformResult output = + controller_synthetic_input_apply(&context, pressed, profile, 0); + require(has_button(output, ControllerProfileLogicalButton::kSouth), + "Turbo did not begin in its ON phase"); + + constexpr std::array deltas = {17, 29, 11, 23}; + uint32_t now_ms = 0; + size_t delta_index = 0; + bool previous_on = true; + unsigned completed_activations = 0; + while (now_ms < 1000) { + uint32_t delta = deltas[delta_index++ % deltas.size()]; + if (delta > 1000 - now_ms) { + delta = 1000 - now_ms; + } + now_ms += delta; + output = controller_synthetic_input_apply( + &context, pressed, profile, now_ms); + const bool on = + has_button(output, ControllerProfileLogicalButton::kSouth); + if (previous_on && !on) { + ++completed_activations; + } + previous_on = on; + } + require(completed_activations == 15 && previous_on, + "irregular ticks did not produce exactly 15 activations per second"); + + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 1001); + require(!has_button(output, ControllerProfileLogicalButton::kSouth), + "Turbo release left a stuck output"); + output = controller_synthetic_input_apply(&context, pressed, profile, 1002); + require(has_button(output, ControllerProfileLogicalButton::kSouth), + "Turbo repress did not restart in the ON phase"); + + context = {}; + constexpr uint32_t near_wrap = UINT32_MAX - 10u; + output = controller_synthetic_input_apply( + &context, pressed, profile, near_wrap); + require(has_button(output, ControllerProfileLogicalButton::kSouth), + "Turbo wrap test did not start ON"); + output = controller_synthetic_input_apply(&context, pressed, profile, 23); + require(!has_button(output, ControllerProfileLogicalButton::kSouth), + "Turbo phase accumulation was not uint32-wrap safe"); + output = controller_synthetic_input_apply(&context, pressed, profile, 56); + require(has_button(output, ControllerProfileLogicalButton::kSouth), + "Turbo remainder was lost across uint32 wrap"); +} + +void test_auto_burst_toggle_cancel_and_external_cancel() { + ControllerProfile profile = + profile_with_macro(ControllerProfileLogicalButton::kSelect, + ControllerProfileLogicalButton::kEast); + const uint8_t west = button_index(ControllerProfileLogicalButton::kWest); + profile.turbo_modes[west] = ControllerProfileTurboMode::kAutoBurst; + const ControllerState pressed = + state_with_buttons(button_bit(ControllerProfileLogicalButton::kWest)); + ControllerSyntheticInputContext context{}; + + ControllerProfileTransformResult output = + controller_synthetic_input_apply(&context, pressed, profile, 0); + require(has_button(output, ControllerProfileLogicalButton::kWest), + "Auto Burst did not toggle on in the ON phase"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 1); + require(has_button(output, ControllerProfileLogicalButton::kWest), + "Auto Burst stopped when its physical input was released"); + output = controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 34); + require(!has_button(output, ControllerProfileLogicalButton::kWest), + "Auto Burst did not enter its OFF phase"); + output = controller_synthetic_input_apply(&context, pressed, profile, 35); + require(!has_button(output, ControllerProfileLogicalButton::kWest) && + !context.bindings[west].active, + "second Auto Burst rising press did not toggle it off"); + + (void)controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 36); + output = controller_synthetic_input_apply(&context, pressed, profile, 40); + require(has_button(output, ControllerProfileLogicalButton::kWest), + "Auto Burst did not toggle on a second time"); + output = controller_synthetic_input_apply( + &context, + state_with_buttons(button_bit(ControllerProfileLogicalButton::kEast)), + profile, 41); + require(!has_button(output, ControllerProfileLogicalButton::kWest) && + !has_button(output, ControllerProfileLogicalButton::kEast) && + !context.bindings[west].active, + "macro cancel did not clear all Auto Burst state or was not consumed"); + + (void)controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 42); + output = controller_synthetic_input_apply(&context, pressed, profile, 50); + require(has_button(output, ControllerProfileLogicalButton::kWest), + "Auto Burst could not restart after configured cancellation"); + controller_synthetic_input_cancel( + &context, button_bit(ControllerProfileLogicalButton::kWest)); + output = controller_synthetic_input_apply(&context, pressed, profile, 51); + require(!has_button(output, ControllerProfileLogicalButton::kWest), + "external cancel retriggered an already-held Auto Burst input"); + (void)controller_synthetic_input_apply( + &context, controller_neutral_state(), profile, 52); + output = controller_synthetic_input_apply(&context, pressed, profile, 53); + require(has_button(output, ControllerProfileLogicalButton::kWest), + "Auto Burst did not restart after release following cancellation"); +} + +void test_four_contexts_are_isolated() { + ControllerProfile profile = + controller_profile_default(controller_identity_global(), 0); + profile.turbo_modes[button_index(ControllerProfileLogicalButton::kSouth)] = + ControllerProfileTurboMode::kAutoBurst; + std::array contexts{}; + const ControllerState pressed = + state_with_buttons(button_bit(ControllerProfileLogicalButton::kSouth)); + + ControllerProfileTransformResult slot0 = + controller_synthetic_input_apply(&contexts[0], pressed, profile, 0); + ControllerProfileTransformResult slot1 = controller_synthetic_input_apply( + &contexts[1], controller_neutral_state(), profile, 0); + require(has_button(slot0, ControllerProfileLogicalButton::kSouth) && + !has_button(slot1, ControllerProfileLogicalButton::kSouth), + "synthetic activation leaked into another slot"); + (void)controller_synthetic_input_apply( + &contexts[0], controller_neutral_state(), profile, 1); + slot1 = controller_synthetic_input_apply(&contexts[1], pressed, profile, 10); + controller_synthetic_input_cancel(&contexts[0]); + slot0 = controller_synthetic_input_apply( + &contexts[0], controller_neutral_state(), profile, 11); + slot1 = controller_synthetic_input_apply( + &contexts[1], controller_neutral_state(), profile, 11); + require(!has_button(slot0, ControllerProfileLogicalButton::kSouth) && + has_button(slot1, ControllerProfileLogicalButton::kSouth), + "cancelling one slot changed another slot's Auto Burst state"); +} + +} // namespace + +int main() { + test_immediate_press_release_dpad_and_explicit_end(); + test_optional_field_overrides_and_motion_preservation(); + test_zero_max_wait_and_scheduled_catch_up(); + test_consumption_cancel_precedence_and_duplicate_contributors(); + test_turbo_rate_release_and_uint32_wrap(); + test_auto_burst_toggle_cancel_and_external_cancel(); + test_four_contexts_are_isolated(); + return 0; +} diff --git a/tests/test_controller_profile_runtime_native.py b/tests/test_controller_profile_runtime_native.py index 92ebce1..0fa353d 100644 --- a/tests/test_controller_profile_runtime_native.py +++ b/tests/test_controller_profile_runtime_native.py @@ -22,6 +22,7 @@ def test_controller_profile_runtime_native(tmp_path: Path) -> None: str(root / "controller_identity.cpp"), str(root / "controller_profile.cpp"), str(root / "controller_profile_transform.cpp"), + str(root / "controller_synthetic_input.cpp"), str(root / "controller_profile_runtime.cpp"), "-o", str(executable), diff --git a/tests/test_controller_synthetic_input_native.py b/tests/test_controller_synthetic_input_native.py new file mode 100644 index 0000000..aa347a8 --- /dev/null +++ b/tests/test_controller_synthetic_input_native.py @@ -0,0 +1,32 @@ +import shutil +import subprocess +from pathlib import Path + + +def test_controller_synthetic_input_native(tmp_path: Path) -> None: + root = Path(__file__).resolve().parents[1] + compiler = shutil.which("c++") or shutil.which("g++") + assert compiler is not None, "a host C++ compiler is required" + + executable = tmp_path / "controller_synthetic_input_test" + subprocess.run( + [ + compiler, + "-std=c++17", + "-Wall", + "-Wextra", + "-Werror", + "-pedantic", + f"-I{root}", + str(root / "tests" / "controller_synthetic_input_test.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "controller_profile_transform.cpp"), + str(root / "controller_synthetic_input.cpp"), + "-o", + str(executable), + ], + check=True, + cwd=root, + ) + subprocess.run([str(executable)], check=True, cwd=root) From 045edc984ef2f2fb1ee2862ae7645d0312a1a510 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 2 Sep 2026 18:45:28 -0600 Subject: [PATCH 4/5] Add persistent profile switching feedback --- bluepad32_input_backend.cpp | 483 +++++++++++++--- bluepad32_input_backend.h | 10 + controller_hotkey_config.h | 14 - controller_profile_runtime.cpp | 169 +++++- controller_profile_runtime.h | 33 +- profile_service.cpp | 70 ++- profile_service.h | 5 + switch-pico.cpp | 8 + tests/bluepad32_backend_lifecycle_test.cpp | 532 +++++++++++++++--- tests/controller_profile_runtime_test.cpp | 348 ++++++++++++ tests/profile_service_test.cpp | 95 ++++ ...test_bluepad32_backend_lifecycle_native.py | 4 +- 12 files changed, 1573 insertions(+), 198 deletions(-) diff --git a/bluepad32_input_backend.cpp b/bluepad32_input_backend.cpp index b78ed88..6ea621b 100644 --- a/bluepad32_input_backend.cpp +++ b/bluepad32_input_backend.cpp @@ -24,11 +24,9 @@ constexpr int32_t kAxisMinimum = -512; constexpr int32_t kAxisMaximum = 511; constexpr int32_t kTriggerMaximum = 1023; constexpr uint16_t kSwitchHostRumbleDurationMs = 50; -#ifdef SWITCH_PICO_ADAPTER_FEASIBILITY // XInput vibration is stateful and remains active until XInputSetState sends // a new magnitude. constexpr uint16_t kXInputHostRumbleDurationMs = UINT16_MAX; -#endif constexpr uint32_t kRumblePollIntervalMs = 5; constexpr uint32_t kConfigurationPollIntervalMs = 50; constexpr uint8_t kSlotCount = BLUEPAD32_INPUT_BACKEND_SLOT_COUNT; @@ -42,16 +40,15 @@ constexpr uint8_t kAllBlePairingMethods = SM_STK_GENERATION_METHOD_OOB | SM_STK_GENERATION_METHOD_PASSKEY | SM_STK_GENERATION_METHOD_NUMERIC_COMPARISON; -constexpr uint32_t kAbxyHotkeyButtonMask = - SWITCH_ABXY_HOTKEY_BUTTON_MASK; -constexpr uint32_t kAbxyHotkeyMiscMask = SWITCH_ABXY_HOTKEY_MISC_MASK; -constexpr bool kDefaultSwapAbxy = SWITCH_ABXY_DEFAULT_SWAPPED != 0; -constexpr uint32_t kAbxyFeedbackDurationMs = - SWITCH_ABXY_FEEDBACK_DURATION_MS; -constexpr uint8_t kAbxyFeedbackWeakMagnitude = - SWITCH_ABXY_FEEDBACK_WEAK_MAGNITUDE; -constexpr uint8_t kAbxyFeedbackStrongMagnitude = - SWITCH_ABXY_FEEDBACK_STRONG_MAGNITUDE; +constexpr uint16_t kProfileFeedbackPhaseDurationMs = 75; +constexpr uint8_t kProfileFeedbackWeakMagnitude = UINT8_MAX; +constexpr uint8_t kProfileFeedbackStrongMagnitude = UINT8_MAX; +constexpr SwitchRgbColor kProfileLightbarPalette[CONTROLLER_PROFILE_COUNT] = { + {0x00, 0x55, 0xff}, + {0x00, 0xcc, 0x66}, + {0xff, 0xaa, 0x00}, + {0xcc, 0x33, 0xff}, +}; constexpr uint32_t kMotionHotkeyDpadMask = SWITCH_MOTION_HOTKEY_DPAD_MASK; constexpr uint32_t kMotionHotkeyButtonMask = @@ -73,9 +70,8 @@ constexpr uint8_t kMotionEnabledFeedbackWeakMagnitude = constexpr uint8_t kMotionEnabledFeedbackStrongMagnitude = SWITCH_MOTION_ENABLED_FEEDBACK_STRONG_MAGNITUDE; -static_assert(kAbxyHotkeyButtonMask != 0); -static_assert(kAbxyHotkeyMiscMask != 0); -static_assert(kAbxyFeedbackDurationMs > 0); +static_assert(kProfileFeedbackPhaseDurationMs == 75); +static_assert(CONTROLLER_PROFILE_COUNT == 4); static_assert(kMotionHotkeyDpadMask != 0); static_assert(kMotionHotkeyButtonMask != 0); static_assert(kMotionHotkeyMiscMask != 0); @@ -104,6 +100,7 @@ struct RumbleEnvelope { uint8_t slot; uint32_t connection_generation; ControllerRumbleOutput rumble; + uint16_t duration_ms; }; struct FeedbackEnvelope { uint32_t connection_generation; @@ -111,6 +108,23 @@ struct FeedbackEnvelope { uint8_t weak_magnitude; uint8_t strong_magnitude; }; +struct ProfileFeedbackEnvelope { + uint32_t connection_generation; + uint8_t active_profile_number; + ControllerProfileConfirmationPolicy policy; +}; + +struct ProfileFeedbackSequence { + uint32_t connection_generation; + uint32_t phase_deadline_ms; + uint8_t pulse_count; + uint8_t pulses_started; + bool active; + bool on; + bool rumble_enabled; + bool led_enabled; +}; + // Security Manager identity events arrive before Bluepad32 publishes a ready // device. Retain only the four live handle/address associations so a BLE RPA @@ -126,6 +140,7 @@ struct BleIdentityMapping { struct BackendSlot { ControllerState state; + uint16_t pre_hotkey_button_mask; ControllerIdentity identity; // Non-null with active=false is a connected device still becoming ready. uni_hid_device_t* device; @@ -133,14 +148,17 @@ struct BackendSlot { uint32_t connection_generation; bool active; bool rumble_pending; - bool swap_abxy; - bool abxy_hotkey_latched; bool motion_enabled; bool motion_hotkey_latched; bool feedback_pending; uint32_t feedback_until_ms; + bool profile_feedback_pending; RumbleEnvelope pending_rumble; + bool retained_host_rumble_valid; + RumbleEnvelope retained_host_rumble; FeedbackEnvelope pending_feedback; + ProfileFeedbackEnvelope pending_profile_feedback; + ProfileFeedbackSequence profile_feedback; }; critical_section_t g_state_lock; @@ -409,6 +427,31 @@ void apply_slot_lighting(uint8_t slot_index, uni_hid_device_t* device) { device, static_cast(1u << slot_index)); } } +bool valid_confirmation_policy( + ControllerProfileConfirmationPolicy policy) { + return static_cast(policy) <= + static_cast( + ControllerProfileConfirmationPolicy::kRumbleAndLed); +} + +void apply_profile_lighting( + uint8_t active_profile_number, uni_hid_device_t* device) { + if (device == nullptr || active_profile_number == 0 || + active_profile_number > CONTROLLER_PROFILE_COUNT) { + return; + } + if (device->report_parser.set_lightbar_color != nullptr) { + const SwitchRgbColor color = + kProfileLightbarPalette[active_profile_number - 1u]; + device->report_parser.set_lightbar_color( + device, color.red, color.green, color.blue); + } else if (device->report_parser.set_player_leds != nullptr) { + device->report_parser.set_player_leds( + device, static_cast( + (1u << active_profile_number) - 1u)); + } +} + ConnectionStatus compute_connection_status() { @@ -430,11 +473,13 @@ ConnectionStatus compute_connection_status() { } void publish_device_state(uint8_t slot, uni_hid_device_t* device, + uint16_t pre_hotkey_button_mask, const ControllerState& state) { critical_section_enter_blocking(&g_state_lock); BackendSlot& target = g_slots[slot]; if (target.active && target.device == device) { target.state = state; + target.pre_hotkey_button_mask = pre_hotkey_button_mask; ++target.state_generation; } critical_section_exit(&g_state_lock); @@ -444,10 +489,18 @@ void publish_all_neutral() { critical_section_enter_blocking(&g_state_lock); for (BackendSlot& slot : g_slots) { slot.state = make_neutral_state(); + slot.pre_hotkey_button_mask = 0; slot.identity = controller_identity_global(); slot.device = nullptr; slot.active = false; slot.rumble_pending = false; + slot.retained_host_rumble_valid = false; + slot.retained_host_rumble = {}; + slot.feedback_pending = false; + slot.feedback_until_ms = 0; + slot.profile_feedback_pending = false; + slot.pending_profile_feedback = {}; + slot.profile_feedback = {}; ++slot.state_generation; ++slot.connection_generation; } @@ -541,32 +594,129 @@ bool has_motion(const uni_gamepad_t& gamepad) { } return false; } +constexpr uint16_t logical_button_bit( + ControllerProfileLogicalButton button) { + return static_cast( + 1u << static_cast(button)); +} + +constexpr uint16_t logical_button_mask( + uint32_t dpad, uint32_t buttons, uint32_t misc_buttons) { + return static_cast( + ((buttons & BUTTON_A) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kSouth) + : 0u) | + ((buttons & BUTTON_B) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kEast) + : 0u) | + ((buttons & BUTTON_X) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kWest) + : 0u) | + ((buttons & BUTTON_Y) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kNorth) + : 0u) | + ((buttons & BUTTON_SHOULDER_L) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kLeftShoulder) + : 0u) | + ((buttons & BUTTON_SHOULDER_R) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kRightShoulder) + : 0u) | + ((misc_buttons & MISC_BUTTON_SELECT) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kSelect) + : 0u) | + ((misc_buttons & MISC_BUTTON_START) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kStart) + : 0u) | + ((misc_buttons & MISC_BUTTON_SYSTEM) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kSystem) + : 0u) | + ((misc_buttons & MISC_BUTTON_CAPTURE) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kCapture) + : 0u) | + ((buttons & BUTTON_THUMB_L) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kLeftStick) + : 0u) | + ((buttons & BUTTON_THUMB_R) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kRightStick) + : 0u) | + ((dpad & DPAD_UP) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kDpadUp) + : 0u) | + ((dpad & DPAD_DOWN) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kDpadDown) + : 0u) | + ((dpad & DPAD_LEFT) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kDpadLeft) + : 0u) | + ((dpad & DPAD_RIGHT) != 0 + ? logical_button_bit( + ControllerProfileLogicalButton::kDpadRight) + : 0u)); +} + +constexpr uint16_t kMotionHotkeyLogicalButtonMask = + logical_button_mask( + kMotionHotkeyDpadMask, kMotionHotkeyButtonMask, + kMotionHotkeyMiscMask); + +uint16_t logical_button_mask(const uni_gamepad_t& gamepad) { + return logical_button_mask( + gamepad.dpad, gamepad.buttons, gamepad.misc_buttons); +} ControllerState map_gamepad(const uni_gamepad_t& gamepad, - bool swap_abxy, - bool motion_enabled) { + bool motion_enabled, + uint16_t button_mask) { ControllerState state = make_neutral_state(); - state.dpad_up = (gamepad.dpad & DPAD_UP) != 0; - state.dpad_down = (gamepad.dpad & DPAD_DOWN) != 0; - state.dpad_left = (gamepad.dpad & DPAD_LEFT) != 0; - state.dpad_right = (gamepad.dpad & DPAD_RIGHT) != 0; + state.dpad_up = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kDpadUp)) != 0; + state.dpad_down = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kDpadDown)) != 0; + state.dpad_left = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kDpadLeft)) != 0; + state.dpad_right = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kDpadRight)) != 0; - // Bluepad32's A/B/X/Y are positional: south/east/west/north. - state.button_south = (gamepad.buttons & BUTTON_A) != 0; - state.button_east = (gamepad.buttons & BUTTON_B) != 0; - state.button_west = (gamepad.buttons & BUTTON_X) != 0; - state.button_north = (gamepad.buttons & BUTTON_Y) != 0; - if (swap_abxy) { - bool temporary = state.button_east; - state.button_east = state.button_south; - state.button_south = temporary; - temporary = state.button_north; - state.button_north = state.button_west; - state.button_west = temporary; - } - state.button_left_shoulder = (gamepad.buttons & BUTTON_SHOULDER_L) != 0; - state.button_right_shoulder = (gamepad.buttons & BUTTON_SHOULDER_R) != 0; + // Bluepad32's A/B/X/Y are positional: south/east/west/north. Persistent + // profile mappings are the only button remapping layer. + state.button_south = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kSouth)) != 0; + state.button_east = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kEast)) != 0; + state.button_west = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kWest)) != 0; + state.button_north = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kNorth)) != 0; + state.button_left_shoulder = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kLeftShoulder)) != 0; + state.button_right_shoulder = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kRightShoulder)) != 0; state.left_trigger = (gamepad.buttons & BUTTON_TRIGGER_L) != 0 ? UINT16_MAX @@ -575,13 +725,25 @@ ControllerState map_gamepad(const uni_gamepad_t& gamepad, (gamepad.buttons & BUTTON_TRIGGER_R) != 0 ? UINT16_MAX : scale_trigger(gamepad.throttle); - state.button_left_stick = (gamepad.buttons & BUTTON_THUMB_L) != 0; - state.button_right_stick = (gamepad.buttons & BUTTON_THUMB_R) != 0; + state.button_left_stick = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kLeftStick)) != 0; + state.button_right_stick = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kRightStick)) != 0; - state.button_select = (gamepad.misc_buttons & MISC_BUTTON_SELECT) != 0; - state.button_start = (gamepad.misc_buttons & MISC_BUTTON_START) != 0; - state.button_system = (gamepad.misc_buttons & MISC_BUTTON_SYSTEM) != 0; - state.button_capture = (gamepad.misc_buttons & MISC_BUTTON_CAPTURE) != 0; + state.button_select = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kSelect)) != 0; + state.button_start = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kStart)) != 0; + state.button_system = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kSystem)) != 0; + state.button_capture = + (button_mask & logical_button_bit( + ControllerProfileLogicalButton::kCapture)) != 0; state.left_stick_x = scale_axis(gamepad.axis_x); state.left_stick_y = scale_axis(gamepad.axis_y); @@ -606,11 +768,11 @@ ControllerState map_gamepad(const uni_gamepad_t& gamepad, return state; } struct HotkeyDecision { - bool swap_abxy; bool motion_enabled; uint32_t suppress_dpad; uint32_t suppress_buttons; uint32_t suppress_misc_buttons; + uint16_t suppress_logical_buttons; }; void queue_local_feedback(BackendSlot& slot, uint16_t duration_ms, @@ -622,24 +784,23 @@ void queue_local_feedback(BackendSlot& slot, uint16_t duration_ms, strong_magnitude}; } void reset_slot_hotkeys(BackendSlot& slot) { - slot.swap_abxy = kDefaultSwapAbxy; - slot.abxy_hotkey_latched = false; slot.motion_enabled = kDefaultMotionEnabled; slot.motion_hotkey_latched = false; + slot.pre_hotkey_button_mask = 0; slot.feedback_pending = false; slot.feedback_until_ms = 0; slot.pending_feedback = {}; + slot.profile_feedback_pending = false; + slot.pending_profile_feedback = {}; + slot.profile_feedback = {}; + slot.retained_host_rumble_valid = false; + slot.retained_host_rumble = {}; } HotkeyDecision update_controller_hotkeys( uint8_t slot_index, uni_hid_device_t* device, const uni_gamepad_t& gamepad) { - const bool abxy_pressed = - (gamepad.buttons & kAbxyHotkeyButtonMask) == - kAbxyHotkeyButtonMask && - (gamepad.misc_buttons & kAbxyHotkeyMiscMask) == - kAbxyHotkeyMiscMask; const bool motion_pressed = (gamepad.dpad & kMotionHotkeyDpadMask) == kMotionHotkeyDpadMask && @@ -648,18 +809,12 @@ HotkeyDecision update_controller_hotkeys( (gamepad.misc_buttons & kMotionHotkeyMiscMask) == kMotionHotkeyMiscMask; HotkeyDecision decision{ - kDefaultSwapAbxy, kDefaultMotionEnabled, 0, 0, 0}; + kDefaultMotionEnabled, 0, 0, 0, 0}; critical_section_enter_blocking(&g_state_lock); BackendSlot& slot = g_slots[slot_index]; if (slot.active && slot.device == device) { - if (abxy_pressed && !slot.abxy_hotkey_latched) { - slot.swap_abxy = !slot.swap_abxy; - queue_local_feedback( - slot, static_cast(kAbxyFeedbackDurationMs), - kAbxyFeedbackWeakMagnitude, - kAbxyFeedbackStrongMagnitude); - } else if (motion_pressed && !slot.motion_hotkey_latched) { + if (motion_pressed && !slot.motion_hotkey_latched) { slot.motion_enabled = !slot.motion_enabled; if (slot.motion_enabled) { queue_local_feedback( @@ -673,18 +828,14 @@ HotkeyDecision update_controller_hotkeys( kMotionDisabledFeedbackStrongMagnitude); } } - slot.abxy_hotkey_latched = abxy_pressed; slot.motion_hotkey_latched = motion_pressed; - decision.swap_abxy = slot.swap_abxy; decision.motion_enabled = slot.motion_enabled; - if (abxy_pressed) { - decision.suppress_buttons |= kAbxyHotkeyButtonMask; - decision.suppress_misc_buttons |= kAbxyHotkeyMiscMask; - } if (motion_pressed) { decision.suppress_dpad |= kMotionHotkeyDpadMask; decision.suppress_buttons |= kMotionHotkeyButtonMask; decision.suppress_misc_buttons |= kMotionHotkeyMiscMask; + decision.suppress_logical_buttons |= + kMotionHotkeyLogicalButtonMask; } } critical_section_exit(&g_state_lock); @@ -995,13 +1146,56 @@ void apply_connection_policy() { } } +bool deadline_reached(uint32_t now_ms, uint32_t deadline_ms) { + return static_cast(now_ms - deadline_ms) >= 0; +} + +bool advance_profile_feedback(ProfileFeedbackSequence* sequence, + uint32_t now_ms) { + bool rumble_dispatch = false; + for (uint8_t transition = 0; + transition < CONTROLLER_PROFILE_COUNT * 2u && + sequence->active && + deadline_reached(now_ms, sequence->phase_deadline_ms); + ++transition) { + sequence->phase_deadline_ms += + kProfileFeedbackPhaseDurationMs; + if (sequence->on) { + sequence->on = false; + rumble_dispatch = false; + } else if (sequence->pulses_started >= + sequence->pulse_count) { + sequence->active = false; + } else { + sequence->on = true; + ++sequence->pulses_started; + rumble_dispatch = sequence->rumble_enabled; + } + } + return rumble_dispatch; +} + void update_status_led() { ++g_status_led_tick; const uint32_t now_ms = btstack_run_loop_get_time_ms(); - bool led_on = false; + bool profile_led_override = false; + bool profile_led_on = false; + critical_section_enter_blocking(&g_state_lock); + for (const BackendSlot& slot : g_slots) { + if (slot.profile_feedback.active && + slot.profile_feedback.led_enabled) { + profile_led_override = true; + profile_led_on = + profile_led_on || slot.profile_feedback.on; + } + } + critical_section_exit(&g_state_lock); - if (static_cast( - now_ms - g_pairing_reset_feedback_deadline_ms) < 0) { + bool led_on = false; + if (profile_led_override) { + led_on = profile_led_on; + } else if (static_cast( + now_ms - g_pairing_reset_feedback_deadline_ms) < 0) { led_on = (g_status_led_tick % 20) < 10; } else if (pairing_window_active_at(now_ms)) { const uint16_t phase = g_status_led_tick % 200; @@ -1037,17 +1231,95 @@ void process_rumble_timer(btstack_timer_source_t* timer) { if (update_pairing_window(now_ms)) { apply_connection_policy(); } + const bool xinput_host_mode = + host_rumble_duration_ms() == kXInputHostRumbleDurationMs; for (uint8_t slot_index = 0; slot_index < kSlotCount; ++slot_index) { RumbleEnvelope envelope{}; FeedbackEnvelope feedback{}; + ProfileFeedbackEnvelope profile_feedback{}; uni_hid_device_t* device = nullptr; + bool profile_lighting_dispatch = false; + bool profile_rumble_dispatch = false; bool feedback_dispatch = false; bool host_dispatch = false; critical_section_enter_blocking(&g_state_lock); BackendSlot& slot = g_slots[slot_index]; - if (slot.feedback_pending) { + if (slot.retained_host_rumble_valid && + (!xinput_host_mode || + slot.retained_host_rumble.duration_ms != + kXInputHostRumbleDurationMs || + slot.retained_host_rumble.slot != slot_index || + slot.retained_host_rumble.connection_generation != + slot.connection_generation || + !slot.active || slot.device == nullptr)) { + slot.retained_host_rumble_valid = false; + slot.retained_host_rumble = {}; + } + if (slot.profile_feedback.active && + slot.profile_feedback.connection_generation != + slot.connection_generation) { + slot.profile_feedback = {}; + } + const bool profile_feedback_was_active = + slot.profile_feedback.active; + const bool completed_feedback_had_rumble = + slot.profile_feedback.rumble_enabled; + profile_rumble_dispatch = + advance_profile_feedback(&slot.profile_feedback, now_ms); + if (profile_feedback_was_active && + !slot.profile_feedback.active && + completed_feedback_had_rumble && + slot.retained_host_rumble_valid) { + slot.pending_rumble = slot.retained_host_rumble; + slot.rumble_pending = true; + } + if (profile_rumble_dispatch) { + device = slot.device; + } + + const bool feedback_active = + static_cast(now_ms - slot.feedback_until_ms) < 0; + if (!slot.profile_feedback.active && !feedback_active && + slot.profile_feedback_pending) { + profile_feedback = slot.pending_profile_feedback; + slot.profile_feedback_pending = false; + const uint8_t policy = + static_cast(profile_feedback.policy); + if (slot.active && slot.device != nullptr && + profile_feedback.connection_generation == + slot.connection_generation && + profile_feedback.active_profile_number != 0 && + profile_feedback.active_profile_number <= + CONTROLLER_PROFILE_COUNT && + valid_confirmation_policy(profile_feedback.policy) && + profile_feedback.policy != + ControllerProfileConfirmationPolicy::kNone) { + slot.profile_feedback = { + slot.connection_generation, + now_ms + kProfileFeedbackPhaseDurationMs, + profile_feedback.active_profile_number, + 1, + true, + true, + (policy & static_cast( + ControllerProfileConfirmationPolicy:: + kRumble)) != 0, + (policy & static_cast( + ControllerProfileConfirmationPolicy:: + kLed)) != 0, + }; + device = slot.device; + profile_lighting_dispatch = + slot.profile_feedback.led_enabled; + profile_rumble_dispatch = + slot.profile_feedback.rumble_enabled; + } + } + + if (!slot.profile_feedback.active && + slot.feedback_pending) { feedback = slot.pending_feedback; feedback_dispatch = slot.active && slot.device != nullptr && @@ -1062,10 +1334,12 @@ void process_rumble_timer(btstack_timer_source_t* timer) { } } - const bool feedback_active = - static_cast(now_ms - slot.feedback_until_ms) < 0; - if (!feedback_dispatch && !feedback_active && - slot.rumble_pending) { + const bool local_feedback_active = + slot.profile_feedback.active || + static_cast( + now_ms - slot.feedback_until_ms) < 0; + if (!profile_rumble_dispatch && !feedback_dispatch && + !local_feedback_active && slot.rumble_pending) { envelope = slot.pending_rumble; slot.rumble_pending = false; host_dispatch = @@ -1079,7 +1353,17 @@ void process_rumble_timer(btstack_timer_source_t* timer) { } critical_section_exit(&g_state_lock); - if (feedback_dispatch) { + if (profile_lighting_dispatch) { + apply_profile_lighting( + profile_feedback.active_profile_number, device); + } + if (profile_rumble_dispatch && device != nullptr && + device->report_parser.play_dual_rumble != nullptr) { + device->report_parser.play_dual_rumble( + device, 0, kProfileFeedbackPhaseDurationMs, + kProfileFeedbackWeakMagnitude, + kProfileFeedbackStrongMagnitude); + } else if (feedback_dispatch) { device->report_parser.play_dual_rumble( device, 0, feedback.duration_ms, feedback.weak_magnitude, feedback.strong_magnitude); @@ -1089,7 +1373,7 @@ void process_rumble_timer(btstack_timer_source_t* timer) { envelope.rumble.low_frequency_magnitude == 0 && envelope.rumble.high_frequency_magnitude == 0; device->report_parser.play_dual_rumble( - device, 0, stop ? 0 : host_rumble_duration_ms(), + device, 0, stop ? 0 : envelope.duration_ms, envelope.rumble.high_frequency_magnitude, envelope.rumble.low_frequency_magnitude); } @@ -1273,15 +1557,20 @@ void platform_on_controller_data(uni_hid_device_t* device, } uni_gamepad_t gamepad = controller->gamepad; + const uint16_t pre_hotkey_button_mask = + logical_button_mask(gamepad); const HotkeyDecision hotkeys = update_controller_hotkeys( static_cast(slot_index), device, gamepad); gamepad.dpad &= ~hotkeys.suppress_dpad; gamepad.buttons &= ~hotkeys.suppress_buttons; gamepad.misc_buttons &= ~hotkeys.suppress_misc_buttons; + const uint16_t output_button_mask = static_cast( + pre_hotkey_button_mask & ~hotkeys.suppress_logical_buttons); publish_device_state( static_cast(slot_index), device, - map_gamepad(gamepad, hotkeys.swap_abxy, - hotkeys.motion_enabled)); + pre_hotkey_button_mask, + map_gamepad( + gamepad, hotkeys.motion_enabled, output_button_mask)); } const uni_property_t* platform_get_property(uni_property_idx_t index) { @@ -1462,6 +1751,8 @@ void bluepad32_input_backend_snapshot(uint8_t slot_index, out->active = slot.active; out->connection_generation = slot.connection_generation; out->identity = slot.identity; + out->pre_hotkey_button_mask = + slot.pre_hotkey_button_mask; out->state = slot.state; const uint32_t state_generation = slot.state_generation; critical_section_exit(&g_state_lock); @@ -1485,11 +1776,45 @@ void bluepad32_input_backend_queue_rumble( return; } + const uint16_t duration_ms = host_rumble_duration_ms(); critical_section_enter_blocking(&g_state_lock); BackendSlot& slot = g_slots[slot_index]; if (slot.active && slot.device != nullptr) { - slot.pending_rumble = {slot_index, slot.connection_generation, rumble}; + const RumbleEnvelope envelope{ + slot_index, slot.connection_generation, rumble, + duration_ms}; + slot.pending_rumble = envelope; slot.rumble_pending = true; + if (duration_ms == kXInputHostRumbleDurationMs) { + slot.retained_host_rumble = envelope; + slot.retained_host_rumble_valid = true; + } else { + slot.retained_host_rumble = {}; + slot.retained_host_rumble_valid = false; + } + } + critical_section_exit(&g_state_lock); +} + +void bluepad32_input_backend_queue_profile_feedback( + uint8_t slot_index, uint32_t connection_generation, + uint8_t active_profile_number, + ControllerProfileConfirmationPolicy policy) { + if (!g_initialized || !valid_slot(slot_index) || + active_profile_number == 0 || + active_profile_number > CONTROLLER_PROFILE_COUNT || + !valid_confirmation_policy(policy) || + policy == ControllerProfileConfirmationPolicy::kNone) { + return; + } + + critical_section_enter_blocking(&g_state_lock); + BackendSlot& slot = g_slots[slot_index]; + if (slot.active && slot.device != nullptr && + slot.connection_generation == connection_generation) { + slot.pending_profile_feedback = { + connection_generation, active_profile_number, policy}; + slot.profile_feedback_pending = true; } critical_section_exit(&g_state_lock); } diff --git a/bluepad32_input_backend.h b/bluepad32_input_backend.h index 4d359b8..0600d13 100644 --- a/bluepad32_input_backend.h +++ b/bluepad32_input_backend.h @@ -4,6 +4,7 @@ #include "controller_color.h" #include "controller_identity.h" +#include "controller_profile.h" #include "controller_state.h" #include "switch_haptics.h" @@ -37,6 +38,9 @@ struct Bluepad32SlotSnapshot { bool active; uint32_t connection_generation; ControllerIdentity identity; + // Physical logical-button state before backend hotkey consumption. + // Valid only for this snapshot's connection generation. + uint16_t pre_hotkey_button_mask; ControllerState state; }; @@ -54,3 +58,9 @@ void bluepad32_input_backend_pairing_snapshot( void bluepad32_input_backend_report_sent(uint8_t slot); void bluepad32_input_backend_queue_rumble( uint8_t slot, const ControllerRumbleOutput& rumble); +// Schedule bounded local profile confirmation only for the matching live +// connection generation. Profile numbers are one-based (1..4). +void bluepad32_input_backend_queue_profile_feedback( + uint8_t slot, uint32_t connection_generation, + uint8_t active_profile_number, + ControllerProfileConfirmationPolicy policy); diff --git a/controller_hotkey_config.h b/controller_hotkey_config.h index ebd2cc0..818515f 100644 --- a/controller_hotkey_config.h +++ b/controller_hotkey_config.h @@ -2,26 +2,12 @@ #pragma once -// Bluepad32 button masks. Default chord: L + R + SELECT + START. -#define SWITCH_ABXY_HOTKEY_BUTTON_MASK \ - (BUTTON_SHOULDER_L | BUTTON_SHOULDER_R) -#define SWITCH_ABXY_HOTKEY_MISC_MASK \ - (MISC_BUTTON_SELECT | MISC_BUTTON_START) - // Motion toggle chord: D-pad Up + R + START / Options. #define SWITCH_MOTION_HOTKEY_DPAD_MASK DPAD_UP #define SWITCH_MOTION_HOTKEY_BUTTON_MASK BUTTON_SHOULDER_R #define SWITCH_MOTION_HOTKEY_MISC_MASK MISC_BUTTON_START #define SWITCH_MOTION_DEFAULT_ENABLED 1 -// 0 starts each new connection in Nintendo positional layout; 1 starts swapped. -#define SWITCH_ABXY_DEFAULT_SWAPPED 0 - -// Local confirmation pulse sent only to the controller that toggled. -#define SWITCH_ABXY_FEEDBACK_DURATION_MS 120 -#define SWITCH_ABXY_FEEDBACK_WEAK_MAGNITUDE 0xFF -#define SWITCH_ABXY_FEEDBACK_STRONG_MAGNITUDE 0xFF - // A longer pulse confirms disabled; a shorter pulse confirms enabled. #define SWITCH_MOTION_DISABLED_FEEDBACK_DURATION_MS 180 #define SWITCH_MOTION_DISABLED_FEEDBACK_WEAK_MAGNITUDE 0xA0 diff --git a/controller_profile_runtime.cpp b/controller_profile_runtime.cpp index 68da390..0c5d6ff 100644 --- a/controller_profile_runtime.cpp +++ b/controller_profile_runtime.cpp @@ -13,11 +13,20 @@ struct ControllerProfileRuntimeContext { ControllerIdentity identity{}; uint32_t database_generation = 0; uint8_t active_profile_index = 0; + bool profile_snapshot_valid = false; ControllerProfile profile{}; ControllerSyntheticInputContext synthetic{}; bool runtime_generations_initialized = false; AdapterUsbMode output_mode = AdapterUsbMode::kSwitchProbe; uint32_t configuration_reset_generation = 0; + bool switching_chord_held = false; + bool switching_chord_armed = true; + bool switching_activation_requested = false; + uint16_t held_switching_chord = 0; + uint8_t switching_target_profile_index = 0; + uint32_t switching_transaction_id = 0; + bool profile_change_pending = false; + ControllerProfileRuntimeProfileChangeEvent pending_profile_change{}; }; ControllerProfileRuntimeContext @@ -25,6 +34,23 @@ ControllerProfileRuntimeContext ControllerProfile g_default_profile{}; ControllerProfileTransformResult g_neutral_output{}; bool g_initialized = false; +uint32_t g_next_activation_sequence = 1; + +uint32_t next_activation_transaction_id() { + const uint32_t transaction_id = + 0x80000000u | g_next_activation_sequence; + g_next_activation_sequence = + g_next_activation_sequence == 0x7fffffffu + ? 1u + : g_next_activation_sequence + 1u; + return transaction_id; +} + +uint16_t effective_switching_chord(const ControllerProfile& profile) { + return profile.switching_chord == 0 + ? CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD + : profile.switching_chord; +} void initialize_defaults() { if (g_initialized) { @@ -52,6 +78,30 @@ void refresh_profile(ControllerProfileRuntimeContext* context, ProfileServiceActiveProfileSnapshot snapshot{}; profile_service_active_profile_snapshot(identity, &snapshot); + const bool same_connection = + context->active && + context->connection_generation == connection_generation; + const bool same_identity = + same_connection && + controller_identity_equal(context->identity, identity); + const uint8_t previous_profile_index = + context->active_profile_index; + const bool previous_profile_valid = + context->profile_snapshot_valid; + if (!same_connection) { + context->runtime_generations_initialized = false; + context->switching_chord_held = false; + context->switching_chord_armed = true; + context->switching_activation_requested = false; + context->held_switching_chord = 0; + context->switching_target_profile_index = 0; + context->switching_transaction_id = 0; + context->profile_change_pending = false; + context->pending_profile_change = {}; + } + + controller_synthetic_input_cancel(&context->synthetic, + current_input_button_mask); context->active = true; context->connection_generation = connection_generation; context->identity = identity; @@ -59,9 +109,25 @@ void refresh_profile(ControllerProfileRuntimeContext* context, ? snapshot.metadata.generation : observed_database_generation; context->active_profile_index = snapshot.valid ? snapshot.profile_index : 0; + context->profile_snapshot_valid = snapshot.valid; context->profile = snapshot.valid ? snapshot.profile : g_default_profile; - controller_synthetic_input_cancel(&context->synthetic, - current_input_button_mask); + if (context->switching_chord_held && + !context->switching_activation_requested) { + context->switching_target_profile_index = + static_cast( + (context->active_profile_index + 1u) % + CONTROLLER_PROFILE_COUNT); + } + if (same_identity && previous_profile_valid && snapshot.valid && + previous_profile_index != context->active_profile_index) { + context->pending_profile_change = { + connection_generation, + context->database_generation, + static_cast(context->active_profile_index + 1u), + controller_profile_confirmation_policy(context->profile), + }; + context->profile_change_pending = true; + } } ControllerProfileRuntimeContext* update_context( @@ -91,7 +157,75 @@ ControllerProfileRuntimeContext* update_context( } return &context; } +void process_profile_switching( + ControllerProfileRuntimeContext* context, + const ControllerIdentity& identity, + uint16_t switching_input_button_mask, + uint16_t current_input_button_mask, + ControllerState* consumed_input) { + if (context == nullptr || consumed_input == nullptr) { + return; + } + if (context->switching_chord_held) { + if ((switching_input_button_mask & + context->held_switching_chord) == + context->held_switching_chord) { + controller_profile_apply_button_mask( + static_cast( + current_input_button_mask & + ~context->held_switching_chord), + consumed_input); + if (!context->switching_activation_requested) { + const ConfigurationTransactionStatus status = + profile_service_activate_internal( + context->switching_transaction_id, identity, + context->switching_target_profile_index); + if (status != ConfigurationTransactionStatus::kBusy) { + context->switching_activation_requested = true; + } + } + return; + } + context->switching_chord_held = false; + context->switching_activation_requested = false; + context->held_switching_chord = 0; + context->switching_transaction_id = 0; + } + + const uint16_t chord = + effective_switching_chord(context->profile); + const bool chord_fully_held = + (switching_input_button_mask & chord) == chord; + if (!chord_fully_held) { + context->switching_chord_armed = true; + return; + } + if (!context->switching_chord_armed) { + return; + } + + context->switching_chord_armed = false; + context->switching_chord_held = true; + context->held_switching_chord = chord; + context->switching_target_profile_index = + static_cast( + (context->active_profile_index + 1u) % + CONTROLLER_PROFILE_COUNT); + context->switching_transaction_id = + next_activation_transaction_id(); + controller_profile_apply_button_mask( + static_cast( + current_input_button_mask & ~context->held_switching_chord), + consumed_input); + const ConfigurationTransactionStatus status = + profile_service_activate_internal( + context->switching_transaction_id, identity, + context->switching_target_profile_index); + if (status != ConfigurationTransactionStatus::kBusy) { + context->switching_activation_requested = true; + } +} } // namespace @@ -101,6 +235,7 @@ void controller_profile_runtime_reset() { for (ControllerProfileRuntimeContext& context : g_contexts) { clear_context(&context); } + g_next_activation_sequence = 1; } ControllerProfileTransformResult controller_profile_runtime_transform( @@ -112,6 +247,12 @@ ControllerProfileTransformResult controller_profile_runtime_transform( if (context == nullptr) { return g_neutral_output; } + ControllerState consumed_input = snapshot.state; + const uint16_t current_input_button_mask = + controller_profile_extract_button_mask(snapshot.state); + process_profile_switching( + context, snapshot.identity, snapshot.pre_hotkey_button_mask, + current_input_button_mask, &consumed_input); const uint32_t reset_generation = configuration_service_reset_generation(); @@ -124,12 +265,32 @@ ControllerProfileTransformResult controller_profile_runtime_transform( reset_generation) { controller_synthetic_input_cancel( &context->synthetic, - controller_profile_extract_button_mask(snapshot.state)); + controller_profile_extract_button_mask(consumed_input)); context->output_mode = output_mode; context->configuration_reset_generation = reset_generation; } return controller_synthetic_input_apply( - &context->synthetic, snapshot.state, context->profile, now_ms); + &context->synthetic, consumed_input, context->profile, now_ms); +} + +bool controller_profile_runtime_take_profile_change( + uint8_t slot, ControllerProfileRuntimeProfileChangeEvent* output) { + if (output == nullptr) { + return false; + } + *output = {}; + if (slot >= CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT) { + return false; + } + + ControllerProfileRuntimeContext& context = g_contexts[slot]; + if (!context.profile_change_pending) { + return false; + } + *output = context.pending_profile_change; + context.profile_change_pending = false; + context.pending_profile_change = {}; + return true; } ControllerRumbleOutput controller_profile_runtime_scale_host_rumble( diff --git a/controller_profile_runtime.h b/controller_profile_runtime.h index 85e6509..2843643 100644 --- a/controller_profile_runtime.h +++ b/controller_profile_runtime.h @@ -8,6 +8,24 @@ #include "controller_profile_transform.h" constexpr uint8_t CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT = 4; +constexpr uint16_t CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD = + static_cast( + (1u << static_cast( + ControllerProfileLogicalButton::kLeftShoulder)) | + (1u << static_cast( + ControllerProfileLogicalButton::kRightShoulder)) | + (1u << static_cast( + ControllerProfileLogicalButton::kSelect)) | + (1u << static_cast( + ControllerProfileLogicalButton::kStart))); + +struct ControllerProfileRuntimeProfileChangeEvent { + uint32_t connection_generation = 0; + uint32_t database_generation = 0; + uint8_t active_profile_number = 0; + ControllerProfileConfirmationPolicy policy = + ControllerProfileConfirmationPolicy::kNone; +}; struct ControllerProfileRuntimeLocalConfirmation { ControllerRumbleOutput rumble{}; @@ -18,14 +36,21 @@ struct ControllerProfileRuntimeLocalConfirmation { // Reset all four fixed slot caches to the default profile. void controller_profile_runtime_reset(); -// Refresh a slot only when its connection key or database generation changes, -// cancel synthetic state on every runtime invalidation, then apply the shared -// transform and synthetic pipeline. Inactive snapshots return neutral output -// and invalidate the slot immediately. +// Refresh a slot when its identity, connection generation, or database +// generation changes; identity-only promotion preserves a held switching +// transaction. Consume pre-hotkey switching chords while transforming the +// backend-suppressed state through the shared synthetic pipeline. Inactive +// snapshots return neutral output and invalidate the slot. ControllerProfileTransformResult controller_profile_runtime_transform( uint8_t slot, const Bluepad32SlotSnapshot& snapshot, uint32_t now_ms, AdapterUsbMode output_mode); +// Take the single committed profile-index change observed by the slot. Initial +// profile loads, identity promotions, and connection replacements do not +// publish an event. +bool controller_profile_runtime_take_profile_change( + uint8_t slot, ControllerProfileRuntimeProfileChangeEvent* output); + // Refresh from the current slot snapshot and scale host-originated rumble. ControllerRumbleOutput controller_profile_runtime_scale_host_rumble( uint8_t slot, const Bluepad32SlotSnapshot& snapshot, diff --git a/profile_service.cpp b/profile_service.cpp index 12ec36c..1a33b44 100644 --- a/profile_service.cpp +++ b/profile_service.cpp @@ -18,6 +18,7 @@ enum class PendingCommandType : uint8_t { struct PendingCommand { PendingCommandType type = PendingCommandType::kNone; + uint32_t transaction_id = 0; ControllerIdentity identity{}; uint8_t profile_index = 0; }; @@ -48,6 +49,7 @@ PublishedActiveProfile uint8_t g_active_profile_count = 0; ProfileTransaction g_transaction; PendingCommand g_command; +PendingCommand g_internal_activation; bool g_identity_dirty = false; bool g_has_committed = false; uint32_t g_last_commit_ms = 0; @@ -159,6 +161,17 @@ void finish_mutation(ConfigurationTransactionStatus status, critical_section_exit(&g_lock); } +void finish_internal_activation( + ConfigurationTransactionStatus status) { + critical_section_enter_blocking(&g_lock); + g_internal_activation = {}; + refresh_metadata_locked( + status == ConfigurationTransactionStatus::kStorageError + ? ProfileServiceState::kStorageError + : ProfileServiceState::kReady); + critical_section_exit(&g_lock); +} + } // namespace void profile_service_prepare() { @@ -176,6 +189,7 @@ void profile_service_prepare() { g_selected.profile_index = 0; g_transaction = {}; g_command = {}; + g_internal_activation = {}; g_identity_dirty = false; g_has_committed = false; g_last_commit_ms = 0; @@ -226,6 +240,7 @@ bool profile_service_observe_identity_on_storage_core( void profile_service_task_on_storage_core(uint32_t now_ms) { PendingCommand command{}; bool process_write = false; + bool process_internal_activation = false; bool process_identity = false; ControllerIdentity write_identity{}; uint8_t write_profile_index = 0; @@ -242,6 +257,10 @@ void profile_service_task_on_storage_core(uint32_t now_ms) { write_profile_index = g_transaction.profile_index; memcpy(write_payload, g_transaction.payload, sizeof(write_payload)); + } else if (g_internal_activation.type != + PendingCommandType::kNone) { + command = g_internal_activation; + process_internal_activation = true; } else if (g_identity_dirty) { process_identity = true; } @@ -249,6 +268,7 @@ void profile_service_task_on_storage_core(uint32_t now_ms) { critical_section_exit(&g_lock); if (!process_write && !process_identity && + !process_internal_activation && command.type == PendingCommandType::kNone) { return; } @@ -279,8 +299,13 @@ void profile_service_task_on_storage_core(uint32_t now_ms) { } if (database_result != ControllerProfileDatabaseResult::kOk) { - finish_mutation(database_result_status(database_result), - !process_write); + const ConfigurationTransactionStatus error_status = + database_result_status(database_result); + if (process_internal_activation) { + finish_internal_activation(error_status); + } else { + finish_mutation(error_status, !process_write); + } return; } @@ -315,7 +340,11 @@ void profile_service_task_on_storage_core(uint32_t now_ms) { critical_section_enter_blocking(&g_lock); g_identity_dirty = false; critical_section_exit(&g_lock); - finish_mutation(status, !process_write); + if (process_internal_activation) { + finish_internal_activation(status); + } else { + finish_mutation(status, !process_write); + } } ConfigurationTransactionStatus profile_service_select( @@ -362,6 +391,7 @@ ConfigurationTransactionStatus profile_service_begin( } critical_section_enter_blocking(&g_lock); if (g_command.type != PendingCommandType::kNone || + g_internal_activation.type != PendingCommandType::kNone || g_transaction.snapshot.status == ConfigurationTransactionStatus::kReceiving || g_transaction.snapshot.status == @@ -465,6 +495,7 @@ ConfigurationTransactionStatus profile_service_reset( } critical_section_enter_blocking(&g_lock); if (g_command.type != PendingCommandType::kNone || + g_internal_activation.type != PendingCommandType::kNone || g_transaction.snapshot.status == ConfigurationTransactionStatus::kReceiving || g_transaction.snapshot.status == @@ -485,6 +516,7 @@ ConfigurationTransactionStatus profile_service_reset( return ConfigurationTransactionStatus::kMalformed; } g_transaction.snapshot.status = ConfigurationTransactionStatus::kPending; + g_command.transaction_id = transaction_id; g_command.type = PendingCommandType::kReset; g_command.identity = identity; g_command.profile_index = profile_index; @@ -500,6 +532,7 @@ ConfigurationTransactionStatus profile_service_activate( } critical_section_enter_blocking(&g_lock); if (g_command.type != PendingCommandType::kNone || + g_internal_activation.type != PendingCommandType::kNone || g_transaction.snapshot.status == ConfigurationTransactionStatus::kReceiving || g_transaction.snapshot.status == @@ -519,6 +552,7 @@ ConfigurationTransactionStatus profile_service_activate( return ConfigurationTransactionStatus::kMalformed; } g_transaction.snapshot.status = ConfigurationTransactionStatus::kPending; + g_command.transaction_id = transaction_id; g_command.type = PendingCommandType::kActivate; g_command.identity = identity; g_command.profile_index = profile_index; @@ -526,6 +560,36 @@ ConfigurationTransactionStatus profile_service_activate( return ConfigurationTransactionStatus::kPending; } +ConfigurationTransactionStatus profile_service_activate_internal( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index) { + if (!g_prepared) { + profile_service_prepare(); + } + critical_section_enter_blocking(&g_lock); + if (g_command.type != PendingCommandType::kNone || + g_internal_activation.type != PendingCommandType::kNone || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kReceiving || + g_transaction.snapshot.status == + ConfigurationTransactionStatus::kPending) { + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kBusy; + } + if ((transaction_id & 0x80000000u) == 0 || + !valid_identity(identity) || + profile_index >= CONTROLLER_PROFILE_COUNT) { + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kMalformed; + } + g_internal_activation.type = PendingCommandType::kActivate; + g_internal_activation.transaction_id = transaction_id; + g_internal_activation.identity = identity; + g_internal_activation.profile_index = profile_index; + critical_section_exit(&g_lock); + return ConfigurationTransactionStatus::kPending; +} + void profile_service_list_snapshot(ProfileServiceListSnapshot* output) { if (output == nullptr) { return; diff --git a/profile_service.h b/profile_service.h index 7c0e803..c922795 100644 --- a/profile_service.h +++ b/profile_service.h @@ -79,6 +79,11 @@ ConfigurationTransactionStatus profile_service_reset( ConfigurationTransactionStatus profile_service_activate( uint32_t transaction_id, const ControllerIdentity& identity, uint8_t profile_index); +// Queue a controller-originated activation without replacing the host-visible +// transaction snapshot. transaction_id must be nonzero with its high bit set. +ConfigurationTransactionStatus profile_service_activate_internal( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index); void profile_service_list_snapshot(ProfileServiceListSnapshot* output); void profile_service_selected_snapshot( diff --git a/switch-pico.cpp b/switch-pico.cpp index b87c493..97254ca 100644 --- a/switch-pico.cpp +++ b/switch-pico.cpp @@ -320,6 +320,14 @@ int main() { const ControllerProfileTransformResult transformed = controller_profile_runtime_transform( instance, snapshot, now_ms, output_mode); + ControllerProfileRuntimeProfileChangeEvent profile_change{}; + if (controller_profile_runtime_take_profile_change( + instance, &profile_change)) { + bluepad32_input_backend_queue_profile_feedback( + instance, profile_change.connection_generation, + profile_change.active_profile_number, + profile_change.policy); + } g_user_states[instance] = transformed.state; #ifdef SWITCH_PICO_ADAPTER_FEASIBILITY bool sent = false; diff --git a/tests/bluepad32_backend_lifecycle_test.cpp b/tests/bluepad32_backend_lifecycle_test.cpp index d498f7c..bbb8f85 100644 --- a/tests/bluepad32_backend_lifecycle_test.cpp +++ b/tests/bluepad32_backend_lifecycle_test.cpp @@ -1039,7 +1039,8 @@ void test_independent_lifecycle() { "unstable replacement must not be enrolled for profiles"); g_slots[3].pending_rumble = { - 3, disconnected_generation, ControllerRumbleOutput{77, 88}}; + 3, disconnected_generation, ControllerRumbleOutput{77, 88}, + kXInputHostRumbleDurationMs}; g_slots[3].rumble_pending = true; process_rumble_timer(&g_rumble_timer); require(slot_three_replacement.rumble_calls == 0, @@ -1273,102 +1274,437 @@ void test_slot_lighting() { "controller without RGB support did not receive its slot LED"); } -void require_south_button_mapping(const ControllerState& state, - bool swapped, - const char* message) { - require(state.button_east == swapped && state.button_south == !swapped && - !state.button_north && !state.button_west, - message); -} - -void test_abxy_hotkey() { +void test_profile_chord_remains_raw() { start_pairing_backend(); - uni_hid_device_t slot_zero = device(0); - uni_hid_device_t slot_one = device(1); - require(platform_on_device_ready(&slot_zero) == UNI_ERROR_SUCCESS && - platform_on_device_ready(&slot_one) == UNI_ERROR_SUCCESS, - "ABXY test controllers did not become ready"); + uni_hid_device_t controller = device(0); + require(platform_on_device_ready(&controller) == UNI_ERROR_SUCCESS, + "raw profile chord controller did not become ready"); uni_controller_t input{}; input.klass = UNI_CONTROLLER_CLASS_GAMEPAD; - input.gamepad.buttons = BUTTON_A; - platform_on_controller_data(&slot_zero, &input); - ControllerState snapshot{}; - require(read_controller_state(0, &snapshot), - "slot 0 ABXY state was not published"); - require_south_button_mapping( - snapshot, kDefaultSwapAbxy, - "slot 0 did not start in the configured ABXY layout"); - input.gamepad.buttons = - kAbxyHotkeyButtonMask | BUTTON_A; - input.gamepad.misc_buttons = kAbxyHotkeyMiscMask; - platform_on_controller_data(&slot_zero, &input); - require(read_controller_state(0, &snapshot), - "toggled slot 0 state was not published"); - require_south_button_mapping( - snapshot, !kDefaultSwapAbxy, - "hotkey did not toggle slot 0 ABXY mapping"); - require(!snapshot.button_left_shoulder && !snapshot.button_right_shoulder && - !snapshot.button_select && !snapshot.button_start, - "hotkey chord leaked into the Switch report"); - - bluepad32_input_backend_queue_rumble( - 0, ControllerRumbleOutput{0x11, 0x22}); + BUTTON_A | BUTTON_SHOULDER_L | BUTTON_SHOULDER_R; + input.gamepad.misc_buttons = + MISC_BUTTON_SELECT | MISC_BUTTON_START; + platform_on_controller_data(&controller, &input); + ControllerState snapshot{}; + require(read_controller_state(0, &snapshot) && + snapshot.button_south && !snapshot.button_east && + snapshot.button_left_shoulder && + snapshot.button_right_shoulder && + snapshot.button_select && snapshot.button_start, + "Core 1 suppressed the profile chord or mutated ABXY mapping"); process_rumble_timer(&g_rumble_timer); - require(slot_zero.rumble_calls == 1 && - slot_zero.last_high == kAbxyFeedbackWeakMagnitude && - slot_zero.last_low == kAbxyFeedbackStrongMagnitude && - slot_zero.last_high == UINT8_MAX && - slot_zero.last_low == UINT8_MAX && - g_slots[0].rumble_pending, - "ABXY confirmation was not full-strength or did not take priority"); - - platform_on_controller_data(&slot_zero, &input); - process_rumble_timer(&g_rumble_timer); - require(g_slots[0].swap_abxy == !kDefaultSwapAbxy && - slot_zero.rumble_calls == 1, - "held hotkey toggled or rumbled more than once"); - - input.gamepad = {}; - platform_on_controller_data(&slot_zero, &input); - input.gamepad.buttons = kAbxyHotkeyButtonMask | BUTTON_A; - input.gamepad.misc_buttons = kAbxyHotkeyMiscMask; - platform_on_controller_data(&slot_zero, &input); - process_rumble_timer(&g_rumble_timer); - require(g_slots[0].swap_abxy == kDefaultSwapAbxy && - slot_zero.rumble_calls == 2, - "released hotkey did not re-arm for a second toggle"); - - now_ms = kAbxyFeedbackDurationMs - 1; - process_rumble_timer(&g_rumble_timer); - require(slot_zero.rumble_calls == 2 && g_slots[0].rumble_pending, - "host rumble interrupted ABXY confirmation"); - now_ms = kAbxyFeedbackDurationMs; - process_rumble_timer(&g_rumble_timer); - require(slot_zero.rumble_calls == 3 && - slot_zero.last_high == 0x22 && - slot_zero.last_low == 0x11 && - !g_slots[0].rumble_pending, - "deferred host rumble did not resume after confirmation"); - - uni_controller_t peer_input{}; - peer_input.klass = UNI_CONTROLLER_CLASS_GAMEPAD; - peer_input.gamepad.buttons = BUTTON_A; - platform_on_controller_data(&slot_one, &peer_input); - require(read_controller_state(1, &snapshot), - "slot 1 ABXY state was not published"); - require_south_button_mapping( - snapshot, kDefaultSwapAbxy, - "slot 0 hotkey changed slot 1 layout"); - - platform_on_device_disconnected(&slot_zero); - uni_hid_device_t replacement = device(0); - require(platform_on_device_ready(&replacement) == UNI_ERROR_SUCCESS && - g_slots[0].swap_abxy == kDefaultSwapAbxy && - !g_slots[0].abxy_hotkey_latched && + require(controller.rumble_calls == 0 && !g_slots[0].feedback_pending, - "disconnect did not reset slot 0 hotkey state"); + "legacy ABXY chord still produced local feedback"); +} + +void test_profile_feedback_scheduler() { + start_pairing_backend(); + uni_hid_device_t devices[kSlotCount] = { + device(0), device(1), device(2), device(3)}; + devices[0].report_parser.set_lightbar_color = set_lightbar; + devices[1].report_parser.set_player_leds = set_player_leds; + devices[2].report_parser.set_lightbar_color = set_lightbar; + devices[3].report_parser.set_player_leds = set_player_leds; + + uint32_t generations[kSlotCount]{}; + for (uint8_t slot = 0; slot < kSlotCount; ++slot) { + require(platform_on_device_ready(&devices[slot]) == + UNI_ERROR_SUCCESS, + "profile feedback controller did not become ready"); + Bluepad32SlotSnapshot snapshot{}; + bluepad32_input_backend_snapshot(slot, &snapshot); + generations[slot] = snapshot.connection_generation; + require(devices[slot].rumble_calls == 0 && + !g_slots[slot].profile_feedback.active && + !g_slots[slot].profile_feedback_pending, + "initial controller/profile load scheduled confirmation feedback"); + bluepad32_input_backend_queue_profile_feedback( + slot, generations[slot], static_cast(slot + 1u), + ControllerProfileConfirmationPolicy::kRumble); + bluepad32_input_backend_queue_rumble( + slot, ControllerRumbleOutput{ + static_cast(0x10u + slot), + static_cast(0x20u + slot)}); + } + + now_ms = 0; + process_rumble_timer(&g_rumble_timer); + for (uint8_t slot = 0; slot < kSlotCount; ++slot) { + require(devices[slot].rumble_calls == 1 && + devices[slot].last_rumble_duration_ms == + kProfileFeedbackPhaseDurationMs && + devices[slot].last_high == UINT8_MAX && + devices[slot].last_low == UINT8_MAX && + g_slots[slot].rumble_pending && + g_slots[slot].profile_feedback.active, + "profile pulse sequence did not start at full strength"); + } + + now_ms = 74; + process_rumble_timer(&g_rumble_timer); + now_ms = 75; + process_rumble_timer(&g_rumble_timer); + for (const uni_hid_device_t& controller : devices) { + require(controller.rumble_calls == 1, + "profile pulse did not retain a 75 ms on phase"); + } + + now_ms = 149; + process_rumble_timer(&g_rumble_timer); + now_ms = 150; + process_rumble_timer(&g_rumble_timer); + require(devices[0].rumble_calls == 2 && + devices[0].last_high == 0x20 && + devices[0].last_low == 0x10 && + !g_slots[0].rumble_pending, + "one-pulse confirmation did not defer host rumble through its off phase"); + for (uint8_t slot = 1; slot < kSlotCount; ++slot) { + require(devices[slot].rumble_calls == 2 && + devices[slot].last_high == UINT8_MAX && + g_slots[slot].rumble_pending, + "second profile pulse did not start after 75 ms off"); + } + + now_ms = 225; + process_rumble_timer(&g_rumble_timer); + now_ms = 300; + process_rumble_timer(&g_rumble_timer); + require(devices[1].rumble_calls == 3 && + devices[1].last_high == 0x21 && + !g_slots[1].rumble_pending && + devices[2].rumble_calls == 3 && + devices[3].rumble_calls == 3, + "two/three/four-pulse sequences diverged at 300 ms"); + + now_ms = 375; + process_rumble_timer(&g_rumble_timer); + now_ms = 450; + process_rumble_timer(&g_rumble_timer); + require(devices[2].rumble_calls == 4 && + devices[2].last_high == 0x22 && + !g_slots[2].rumble_pending && + devices[3].rumble_calls == 4 && + devices[3].last_high == UINT8_MAX, + "three/four-pulse sequences diverged at 450 ms"); + + now_ms = 525; + process_rumble_timer(&g_rumble_timer); + now_ms = 600; + process_rumble_timer(&g_rumble_timer); + require(devices[3].rumble_calls == 5 && + devices[3].last_high == 0x23 && + !g_slots[3].rumble_pending && + devices[0].lightbar_calls == 1 && + devices[1].player_led_calls == 1 && + devices[2].lightbar_calls == 1 && + devices[3].player_led_calls == 1, + "four-pulse confirmation did not release host rumble at 600 ms"); + + const int slot_zero_lightbar_calls = devices[0].lightbar_calls; + bluepad32_input_backend_queue_profile_feedback( + 0, generations[0], 2, + ControllerProfileConfirmationPolicy::kNone); + bluepad32_input_backend_queue_rumble( + 0, ControllerRumbleOutput{0x31, 0x41}); + now_ms = 700; + process_rumble_timer(&g_rumble_timer); + require(devices[0].rumble_calls == 3 && + devices[0].last_high == 0x41 && + devices[0].lightbar_calls == + slot_zero_lightbar_calls && + !g_slots[0].profile_feedback.active, + "none policy scheduled profile rumble or lighting"); + + bluepad32_input_backend_queue_profile_feedback( + 0, generations[0], 2, + ControllerProfileConfirmationPolicy::kLed); + bluepad32_input_backend_queue_rumble( + 0, ControllerRumbleOutput{0x32, 0x42}); + now_ms = 800; + process_rumble_timer(&g_rumble_timer); + require(devices[0].rumble_calls == 3 && + devices[0].lightbar_calls == + slot_zero_lightbar_calls + 1 && + devices[0].lightbar_red == + kProfileLightbarPalette[1].red && + devices[0].lightbar_green == + kProfileLightbarPalette[1].green && + devices[0].lightbar_blue == + kProfileLightbarPalette[1].blue && + observed_status_led_on && + g_slots[0].rumble_pending, + "LED policy did not set persistent profile color and first onboard blink"); + now_ms = 875; + process_rumble_timer(&g_rumble_timer); + require(!observed_status_led_on && + devices[0].rumble_calls == 3, + "onboard profile blink did not enter its 75 ms off phase"); + now_ms = 950; + process_rumble_timer(&g_rumble_timer); + require(observed_status_led_on, + "second onboard profile blink did not start"); + now_ms = 1025; + process_rumble_timer(&g_rumble_timer); + require(!observed_status_led_on && + g_slots[0].rumble_pending, + "host rumble interrupted the final onboard off phase"); + now_ms = 1100; + process_rumble_timer(&g_rumble_timer); + require(devices[0].rumble_calls == 4 && + devices[0].last_high == 0x42 && + !g_slots[0].rumble_pending, + "LED-only sequence did not release deferred host rumble"); + + const int slot_one_player_led_calls = + devices[1].player_led_calls; + bluepad32_input_backend_queue_profile_feedback( + 1, generations[1], 3, + ControllerProfileConfirmationPolicy::kRumbleAndLed); + now_ms = 1200; + process_rumble_timer(&g_rumble_timer); + require(devices[1].rumble_calls == 4 && + devices[1].last_high == UINT8_MAX && + devices[1].player_led_calls == + slot_one_player_led_calls + 1 && + devices[1].player_leds == 0x07 && + observed_status_led_on, + "combined policy did not drive rumble, onboard LED, and player LEDs"); + for (uint32_t deadline = 1275; deadline <= 1650; + deadline += 75) { + now_ms = deadline; + process_rumble_timer(&g_rumble_timer); + } + require(devices[1].rumble_calls == + (host_rumble_duration_ms() == + kXInputHostRumbleDurationMs + ? 7 + : 6) && + !g_slots[1].profile_feedback.active, + "combined three-pulse sequence did not terminate"); + + const int old_rumble_calls = devices[2].rumble_calls; + bluepad32_input_backend_queue_profile_feedback( + 2, generations[2], 4, + ControllerProfileConfirmationPolicy::kRumbleAndLed); + platform_on_device_disconnected(&devices[2]); + uni_hid_device_t replacement = device(2); + replacement.report_parser.set_lightbar_color = set_lightbar; + require(platform_on_device_ready(&replacement) == + UNI_ERROR_SUCCESS, + "replacement feedback controller did not become ready"); + now_ms = 1700; + process_rumble_timer(&g_rumble_timer); + require(devices[2].rumble_calls == old_rumble_calls && + replacement.rumble_calls == 0 && + replacement.lightbar_calls == 1 && + !g_slots[2].profile_feedback.active && + !g_slots[2].profile_feedback_pending, + "slot replacement accepted stale queued profile feedback"); + bluepad32_input_backend_queue_profile_feedback( + 2, generations[2], 4, + ControllerProfileConfirmationPolicy::kRumbleAndLed); + now_ms = 1705; + process_rumble_timer(&g_rumble_timer); + require(replacement.rumble_calls == 0 && + replacement.lightbar_calls == 1, + "stale generation feedback reached a replacement controller"); + + const int slot_three_rumble_calls = devices[3].rumble_calls; + const int slot_three_player_led_calls = + devices[3].player_led_calls; + bluepad32_input_backend_queue_profile_feedback( + 3, generations[3], 1, + ControllerProfileConfirmationPolicy::kLed); + now_ms = 1800; + process_rumble_timer(&g_rumble_timer); + require(observed_status_led_on && + g_slots[3].profile_feedback.pulses_started == 1 && + devices[3].player_led_calls == + slot_three_player_led_calls + 1 && + devices[3].player_leds == 0x01, + "one-blink LED profile indication did not start"); + now_ms = 1875; + process_rumble_timer(&g_rumble_timer); + require(!observed_status_led_on, + "one-blink LED profile indication did not turn off"); + now_ms = 1950; + process_rumble_timer(&g_rumble_timer); + require(!g_slots[3].profile_feedback.active && + devices[3].rumble_calls == + slot_three_rumble_calls, + "one-blink LED-only profile indication did not terminate cleanly"); + + bluepad32_input_backend_queue_profile_feedback( + 3, generations[3], 4, + ControllerProfileConfirmationPolicy::kLed); + now_ms = 2000; + process_rumble_timer(&g_rumble_timer); + require(devices[3].player_leds == 0x0f, + "profile 4 did not persist four player LEDs"); + for (uint8_t pulse = 1; pulse <= 4; ++pulse) { + require(observed_status_led_on && + g_slots[3].profile_feedback.on && + g_slots[3].profile_feedback.pulses_started == + pulse, + "four-blink LED sequence missed an on phase"); + now_ms = static_cast( + 2075u + static_cast(pulse - 1u) * 150u); + process_rumble_timer(&g_rumble_timer); + require(!observed_status_led_on && + !g_slots[3].profile_feedback.on, + "four-blink LED sequence missed an off phase"); + if (pulse != 4) { + now_ms += 75; + process_rumble_timer(&g_rumble_timer); + } + } + now_ms = 2600; + process_rumble_timer(&g_rumble_timer); + require(!g_slots[3].profile_feedback.active && + devices[3].rumble_calls == + slot_three_rumble_calls, + "four-blink LED-only profile indication did not terminate"); +} + +void test_stateful_host_rumble_restore() { + start_pairing_backend(); + uni_hid_device_t devices[kSlotCount] = { + device(0), device(1), device(2), device(3)}; + uint32_t generations[kSlotCount]{}; + for (uint8_t slot = 0; slot < kSlotCount; ++slot) { + require(platform_on_device_ready(&devices[slot]) == + UNI_ERROR_SUCCESS, + "rumble restore controller did not become ready"); + Bluepad32SlotSnapshot snapshot{}; + bluepad32_input_backend_snapshot(slot, &snapshot); + generations[slot] = snapshot.connection_generation; + } + +#ifdef SWITCH_PICO_ADAPTER_FEASIBILITY + test_adapter_mode = AdapterUsbMode::kXInput; + const ControllerRumbleOutput desired[kSlotCount] = { + {0x11, 0x21}, {0x12, 0x22}, {0x13, 0x23}, {0x14, 0x24}}; + for (uint8_t slot = 0; slot < kSlotCount; ++slot) { + bluepad32_input_backend_queue_rumble(slot, desired[slot]); + } + now_ms = 0; + process_rumble_timer(&g_rumble_timer); + for (uint8_t slot = 0; slot < kSlotCount; ++slot) { + require(devices[slot].rumble_calls == 1 && + devices[slot].last_rumble_duration_ms == + kXInputHostRumbleDurationMs && + g_slots[slot].retained_host_rumble_valid, + "initial XInput rumble was not dispatched and retained"); + bluepad32_input_backend_queue_profile_feedback( + slot, generations[slot], static_cast(slot + 1u), + ControllerProfileConfirmationPolicy::kRumble); + } + now_ms = 10; + process_rumble_timer(&g_rumble_timer); + for (now_ms = 85; now_ms <= 610; now_ms += 75) { + process_rumble_timer(&g_rumble_timer); + } + for (uint8_t slot = 0; slot < kSlotCount; ++slot) { + require(devices[slot].rumble_calls == + static_cast(slot + 3u) && + devices[slot].last_low == + desired[slot].low_frequency_magnitude && + devices[slot].last_high == + desired[slot].high_frequency_magnitude && + devices[slot].last_rumble_duration_ms == + kXInputHostRumbleDurationMs && + !g_slots[slot].profile_feedback.active, + "XInput rumble did not resume after its profile pulse count"); + } + + const int stop_calls_before = devices[0].rumble_calls; + bluepad32_input_backend_queue_rumble( + 0, ControllerRumbleOutput{0x51, 0x61}); + now_ms = 700; + process_rumble_timer(&g_rumble_timer); + bluepad32_input_backend_queue_profile_feedback( + 0, generations[0], 2, + ControllerProfileConfirmationPolicy::kRumble); + now_ms = 705; + process_rumble_timer(&g_rumble_timer); + bluepad32_input_backend_queue_rumble( + 0, ControllerRumbleOutput{0, 0}); + for (now_ms = 780; now_ms <= 1005; now_ms += 75) { + process_rumble_timer(&g_rumble_timer); + } + require(devices[0].rumble_calls == stop_calls_before + 4 && + devices[0].last_rumble_duration_ms == 0 && + devices[0].last_low == 0 && + devices[0].last_high == 0 && + g_slots[0].retained_host_rumble_valid, + "newest XInput stop did not win during profile pulses"); + + test_adapter_mode = AdapterUsbMode::kSwitchProbe; + const int switch_calls_before = devices[1].rumble_calls; + bluepad32_input_backend_queue_rumble( + 1, ControllerRumbleOutput{0x31, 0x41}); + now_ms = 1100; + process_rumble_timer(&g_rumble_timer); + require(!g_slots[1].retained_host_rumble_valid, + "Switch rumble retained stale XInput desired state"); + bluepad32_input_backend_queue_profile_feedback( + 1, generations[1], 1, + ControllerProfileConfirmationPolicy::kRumble); + now_ms = 1105; + process_rumble_timer(&g_rumble_timer); + now_ms = 1180; + process_rumble_timer(&g_rumble_timer); + now_ms = 1255; + process_rumble_timer(&g_rumble_timer); + require(devices[1].rumble_calls == switch_calls_before + 2 && + devices[1].last_rumble_duration_ms == + kProfileFeedbackPhaseDurationMs, + "finite Switch rumble resumed after profile feedback"); + + test_adapter_mode = AdapterUsbMode::kXInput; + bluepad32_input_backend_queue_rumble( + 2, ControllerRumbleOutput{0x71, 0x81}); + now_ms = 1300; + process_rumble_timer(&g_rumble_timer); + bluepad32_input_backend_queue_profile_feedback( + 2, generations[2], 3, + ControllerProfileConfirmationPolicy::kRumble); + now_ms = 1305; + process_rumble_timer(&g_rumble_timer); + const int old_device_calls = devices[2].rumble_calls; + platform_on_device_disconnected(&devices[2]); + uni_hid_device_t replacement = device(2); + require(platform_on_device_ready(&replacement) == + UNI_ERROR_SUCCESS, + "rumble restore replacement did not become ready"); + now_ms = 2000; + process_rumble_timer(&g_rumble_timer); + require(devices[2].rumble_calls == old_device_calls && + replacement.rumble_calls == 0 && + !g_slots[2].retained_host_rumble_valid && + !g_slots[2].profile_feedback.active, + "stale XInput rumble resumed on a replacement connection"); +#else + bluepad32_input_backend_queue_rumble( + 0, ControllerRumbleOutput{0x31, 0x41}); + now_ms = 0; + process_rumble_timer(&g_rumble_timer); + bluepad32_input_backend_queue_profile_feedback( + 0, generations[0], 1, + ControllerProfileConfirmationPolicy::kRumble); + now_ms = 5; + process_rumble_timer(&g_rumble_timer); + now_ms = 80; + process_rumble_timer(&g_rumble_timer); + now_ms = 155; + process_rumble_timer(&g_rumble_timer); + require(devices[0].rumble_calls == 2 && + !g_slots[0].retained_host_rumble_valid, + "bounded Switch rumble resumed after profile feedback"); +#endif } void test_motion_hotkey() { @@ -1393,12 +1729,17 @@ void test_motion_hotkey() { input.gamepad.buttons = kMotionHotkeyButtonMask; input.gamepad.misc_buttons = kMotionHotkeyMiscMask; platform_on_controller_data(&slot_zero, &input); + Bluepad32SlotSnapshot backend_snapshot{}; + bluepad32_input_backend_snapshot(0, &backend_snapshot); require(read_controller_state(0, &snapshot) && + backend_snapshot.pre_hotkey_button_mask == + kMotionHotkeyLogicalButtonMask && snapshot.motion_sample_count == (kDefaultMotionEnabled ? 0 : 3) && !snapshot.dpad_up && !snapshot.button_right_shoulder && !snapshot.button_start, - "motion chord did not toggle motion or suppress its inputs"); + "motion chord was not published pre-hotkey or suppressed " + "from normal output"); process_rumble_timer(&g_rumble_timer); require(slot_zero.rumble_calls == 1 && @@ -1452,6 +1793,7 @@ void test_motion_hotkey() { require(platform_on_device_ready(&replacement) == UNI_ERROR_SUCCESS && g_slots[0].motion_enabled == kDefaultMotionEnabled && !g_slots[0].motion_hotkey_latched && + g_slots[0].pre_hotkey_button_mask == 0 && !g_slots[0].feedback_pending, "disconnect did not reset slot 0 motion hotkey state"); } @@ -1641,8 +1983,12 @@ int main(int argc, char** argv) { test_pairing_window_policy(); } else if (scenario == "slot-lighting") { test_slot_lighting(); - } else if (scenario == "abxy-hotkey") { - test_abxy_hotkey(); + } else if (scenario == "stateful-rumble") { + test_stateful_host_rumble_restore(); + } else if (scenario == "profile-chord-raw") { + test_profile_chord_remains_raw(); + } else if (scenario == "profile-feedback") { + test_profile_feedback_scheduler(); } else if (scenario == "motion-hotkey") { test_motion_hotkey(); } else if (scenario == "analog-state") { diff --git a/tests/controller_profile_runtime_test.cpp b/tests/controller_profile_runtime_test.cpp index d2fa5c2..ce48daf 100644 --- a/tests/controller_profile_runtime_test.cpp +++ b/tests/controller_profile_runtime_test.cpp @@ -16,11 +16,20 @@ struct FakeProfileRow { uint8_t active_profile = 0; ControllerProfile profiles[CONTROLLER_PROFILE_COUNT]{}; }; +struct ActivationAttempt { + uint32_t transaction_id = 0; + ControllerIdentity identity{}; + uint8_t profile_index = 0; +}; + std::array rows{}; uint32_t database_generation = 7; uint32_t configuration_reset_generation = 3; unsigned active_snapshot_count = 0; +std::array activation_attempts{}; +size_t activation_attempt_count = 0; +unsigned activation_busy_attempts = 0; void require(bool condition, const char* message) { if (!condition) { @@ -44,6 +53,9 @@ void prepare_profiles() { database_generation = 7; configuration_reset_generation = 3; active_snapshot_count = 0; + activation_attempts = {}; + activation_attempt_count = 0; + activation_busy_attempts = 0; for (uint8_t slot = 0; slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { FakeProfileRow& row = rows[slot]; @@ -78,6 +90,31 @@ Bluepad32SlotSnapshot make_snapshot(uint8_t slot, snapshot.state = controller_neutral_state(); return snapshot; } +void apply_button_masks(uint16_t pre_hotkey_mask, + uint16_t output_mask, + Bluepad32SlotSnapshot* snapshot) { + snapshot->pre_hotkey_button_mask = pre_hotkey_mask; + snapshot->state = controller_neutral_state(); + controller_profile_apply_button_mask(output_mask, &snapshot->state); +} +void apply_button_mask(uint16_t mask, Bluepad32SlotSnapshot* snapshot) { + apply_button_masks(mask, mask, snapshot); +} + +ControllerProfileRuntimeProfileChangeEvent take_profile_change( + uint8_t slot, bool* available) { + ControllerProfileRuntimeProfileChangeEvent event{}; + *available = + controller_profile_runtime_take_profile_change(slot, &event); + return event; +} + +constexpr uint16_t logical_button_bit( + ControllerProfileLogicalButton button) { + return static_cast( + 1u << static_cast(button)); +} + ControllerProfileTransformResult runtime_transform( uint8_t slot, const Bluepad32SlotSnapshot& snapshot, @@ -248,6 +285,292 @@ void test_analog_thresholds_rumble_and_local_confirmation() { "local confirmation was scaled or lost its profile policy"); } +void test_default_switching_retry_commit_and_feedback() { + prepare_profiles(); + ControllerProfile& initial_profile = rows[0].profiles[0]; + initial_profile.macro_trigger = static_cast( + ControllerProfileLogicalButton::kLeftShoulder); + initial_profile.macro_step_count = 2; + initial_profile.macro_steps[0].type = + ControllerProfileMacroStepType::kState; + initial_profile.macro_steps[0].override_flags = + kControllerProfileOverrideButtons; + initial_profile.macro_steps[0].duration_ms = 1000; + initial_profile.macro_steps[0].output_button_mask = + logical_button_bit(ControllerProfileLogicalButton::kNorth); + initial_profile.macro_steps[1].type = + ControllerProfileMacroStepType::kEnd; + + Bluepad32SlotSnapshot snapshot = make_snapshot(0); + (void)runtime_transform(0, snapshot, 0); + bool event_available = true; + (void)take_profile_change(0, &event_available); + require(!event_available, + "initial profile load published confirmation feedback"); + + activation_busy_attempts = 2; + const uint16_t held_mask = static_cast( + CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD | + logical_button_bit(ControllerProfileLogicalButton::kSouth)); + apply_button_mask(held_mask, &snapshot); + ControllerProfileTransformResult output = + runtime_transform(0, snapshot, 1); + require(activation_attempt_count == 1 && + rows[0].active_profile == 0 && + output.state.button_south && + !output.state.button_left_shoulder && + !output.state.button_right_shoulder && + !output.state.button_select && + !output.state.button_start && + !output.state.button_north, + "default chord was not consumed before a busy activation and synthetic trigger"); + output = runtime_transform(0, snapshot, 2); + output = runtime_transform(0, snapshot, 3); + require(activation_attempt_count == 3 && + activation_attempts[0].transaction_id == + activation_attempts[1].transaction_id && + activation_attempts[1].transaction_id == + activation_attempts[2].transaction_id && + (activation_attempts[0].transaction_id & 0x80000000u) != 0 && + activation_attempts[0].transaction_id != 0 && + activation_attempts[0].profile_index == 1 && + output.state.button_south && !output.state.button_north, + "held busy chord did not retry one internal activation transaction"); + + (void)runtime_transform(0, snapshot, 4); + require(activation_attempt_count == 3, + "accepted activation repeated while the chord remained held"); + (void)take_profile_change(0, &event_available); + require(!event_available, + "activation feedback was published before storage commit"); + + rows[0].active_profile = 1; + rows[0].profiles[1].button_map[ + static_cast(ControllerProfileLogicalButton::kSouth)] = + static_cast(ControllerProfileLogicalButton::kNorth); + rows[0].profiles[1].confirmation_policy = + ControllerProfileConfirmationPolicy::kLed; + ++database_generation; + output = runtime_transform(0, snapshot, 5); + const ControllerProfileRuntimeProfileChangeEvent event = + take_profile_change(0, &event_available); + require(event_available && event.connection_generation == 1 && + event.database_generation == database_generation && + event.active_profile_number == 2 && + event.policy == ControllerProfileConfirmationPolicy::kLed && + output.state.button_north && + !output.state.button_south && + !output.state.button_left_shoulder && + activation_attempt_count == 3, + "committed activation did not cancel, transform, and publish exactly one event"); + (void)take_profile_change(0, &event_available); + require(!event_available, + "committed profile change feedback was published twice"); + + apply_button_mask(0, &snapshot); + (void)runtime_transform(0, snapshot, 6); + apply_button_mask(CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD, + &snapshot); + (void)runtime_transform(0, snapshot, 7); + require(activation_attempt_count == 4 && + activation_attempts[3].profile_index == 2 && + activation_attempts[3].transaction_id != + activation_attempts[0].transaction_id && + (activation_attempts[3].transaction_id & 0x80000000u) != 0, + "release did not re-arm one activation for the next profile"); +} + +void test_identity_promotion_preserves_held_switching() { + prepare_profiles(); + Bluepad32SlotSnapshot snapshot = make_snapshot(0); + snapshot.identity = controller_identity_global(); + apply_button_mask( + CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD, &snapshot); + + const ControllerProfileTransformResult unresolved = + runtime_transform(0, snapshot, 0); + require(activation_attempt_count == 1 && + controller_identity_is_global( + activation_attempts[0].identity) && + unresolved.left_trigger_digital_threshold == + CONTROLLER_PROFILE_DEFAULT_DIGITAL_THRESHOLD, + "unresolved BLE identity did not begin one activation"); + + snapshot.identity = rows[0].identity; + const ControllerProfileTransformResult promoted = + runtime_transform(0, snapshot, 1); + bool event_available = true; + (void)take_profile_change(0, &event_available); + require(activation_attempt_count == 1 && + promoted.left_trigger_digital_threshold == 1000 && + !event_available, + "identity-only BLE promotion re-armed a held activation or " + "failed to refresh its profile"); + + (void)runtime_transform(0, snapshot, 2); + require(activation_attempt_count == 1, + "promoted BLE identity repeated an accepted held activation"); + + apply_button_mask(0, &snapshot); + (void)runtime_transform(0, snapshot, 3); + apply_button_mask( + CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD, &snapshot); + (void)runtime_transform(0, snapshot, 4); + require(activation_attempt_count == 2 && + controller_identity_equal( + activation_attempts[1].identity, + rows[0].identity), + "physical release did not re-arm the promoted identity"); +} + +void configure_motion_suppression_probe(ControllerProfile* profile) { + profile->macro_trigger = static_cast( + ControllerProfileLogicalButton::kDpadUp); + profile->macro_step_count = 2; + profile->macro_steps[0].type = + ControllerProfileMacroStepType::kState; + profile->macro_steps[0].override_flags = + kControllerProfileOverrideButtons; + profile->macro_steps[0].duration_ms = 1000; + profile->macro_steps[0].output_button_mask = + logical_button_bit(ControllerProfileLogicalButton::kNorth); + profile->macro_steps[1].type = + ControllerProfileMacroStepType::kEnd; +} + +void test_switching_uses_pre_hotkey_buttons_only() { + constexpr uint16_t kMotionHotkeyLogicalMask = + static_cast( + logical_button_bit( + ControllerProfileLogicalButton::kDpadUp) | + logical_button_bit( + ControllerProfileLogicalButton::kRightShoulder) | + logical_button_bit( + ControllerProfileLogicalButton::kStart)); + constexpr uint16_t kCustomChord = + static_cast( + kMotionHotkeyLogicalMask | + logical_button_bit( + ControllerProfileLogicalButton::kSouth)); + + for (uint8_t custom = 0; custom < 2; ++custom) { + prepare_profiles(); + ControllerProfile& profile = rows[0].profiles[0]; + configure_motion_suppression_probe(&profile); + const uint16_t switching_chord = + custom != 0 ? kCustomChord + : CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD; + profile.switching_chord = custom != 0 ? kCustomChord : 0; + + Bluepad32SlotSnapshot snapshot = make_snapshot(0); + (void)runtime_transform(0, snapshot, 0); + const uint16_t pre_hotkey_mask = static_cast( + switching_chord | kMotionHotkeyLogicalMask); + const uint16_t output_mask = static_cast( + pre_hotkey_mask & ~kMotionHotkeyLogicalMask); + apply_button_masks( + pre_hotkey_mask, output_mask, &snapshot); + ControllerProfileTransformResult output = + runtime_transform(0, snapshot, 1); + require(activation_attempt_count == 1 && + !output.state.dpad_up && + !output.state.button_right_shoulder && + !output.state.button_start && + !output.state.button_left_shoulder && + !output.state.button_select && + !output.state.button_south && + !output.state.button_north, + custom != 0 + ? "custom chord hidden by motion suppression" + : "default chord hidden by motion suppression"); + + output = runtime_transform(0, snapshot, 2); + require(activation_attempt_count == 1 && + !output.state.button_north, + "held pre-hotkey chord repeated activation or leaked " + "into synthetic input"); + } +} + +void test_custom_switching_chord_and_wrap() { + prepare_profiles(); + constexpr uint16_t kCustomChord = + static_cast( + logical_button_bit(ControllerProfileLogicalButton::kSouth) | + logical_button_bit(ControllerProfileLogicalButton::kCapture)); + rows[0].profiles[0].switching_chord = kCustomChord; + Bluepad32SlotSnapshot snapshot = make_snapshot(0); + (void)runtime_transform(0, snapshot, 0); + + apply_button_mask(CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD, + &snapshot); + ControllerProfileTransformResult output = + runtime_transform(0, snapshot, 1); + require(activation_attempt_count == 0 && + output.state.button_left_shoulder && + output.state.button_right_shoulder && + output.state.button_select && output.state.button_start, + "nonzero switching chord did not replace the default"); + + apply_button_mask(kCustomChord, &snapshot); + output = runtime_transform(0, snapshot, 2); + require(activation_attempt_count == 1 && + activation_attempts[0].profile_index == 1 && + !output.state.button_south && + !output.state.button_capture, + "custom switching chord was not consumed or activated"); + + prepare_profiles(); + rows[0].active_profile = 3; + rows[0].profiles[3].switching_chord = kCustomChord; + snapshot = make_snapshot(0); + (void)runtime_transform(0, snapshot, 10); + bool event_available = true; + (void)take_profile_change(0, &event_available); + require(!event_available, + "initial profile 4 load published a change event"); + apply_button_mask(kCustomChord, &snapshot); + (void)runtime_transform(0, snapshot, 11); + require(activation_attempt_count == 1 && + activation_attempts[0].profile_index == 0, + "profile switching did not wrap profile 4 to profile 1"); +} +void test_switching_slot_isolation() { + prepare_profiles(); + std::array + snapshots{}; + for (uint8_t slot = 0; + slot < CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT; ++slot) { + snapshots[slot] = make_snapshot(slot); + (void)runtime_transform(slot, snapshots[slot], 0); + } + + apply_button_mask(CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD, + &snapshots[2]); + (void)runtime_transform(2, snapshots[2], 1); + snapshots[0].state.button_south = true; + const ControllerProfileTransformResult untouched = + runtime_transform(0, snapshots[0], 1); + require(activation_attempt_count == 1 && + controller_identity_equal( + activation_attempts[0].identity, + rows[2].identity) && + untouched.state.button_south, + "one slot's switching chord affected another slot"); + + apply_button_mask(CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD, + &snapshots[3]); + (void)runtime_transform(2, snapshots[2], 2); + (void)runtime_transform(3, snapshots[3], 2); + require(activation_attempt_count == 2 && + controller_identity_equal( + activation_attempts[1].identity, + rows[3].identity), + "held switching state was shared between controller slots"); +} + + void configure_synthetic_profile(uint8_t slot) { ControllerProfile& profile = rows[slot].profiles[0]; profile = controller_profile_default(rows[slot].identity, 0); @@ -347,6 +670,12 @@ void test_all_runtime_cancellation_causes() { output = runtime_transform(0, snapshot, 33); require_no_synthetic_output( output, "profile/database generation change did not cancel"); + bool event_available = false; + const ControllerProfileRuntimeProfileChangeEvent cancellation_event = + take_profile_change(0, &event_available); + require(event_available && + cancellation_event.active_profile_number == 2, + "profile commit feedback was not observed with cancellation"); prepare_profiles(); configure_synthetic_profile(0); @@ -413,6 +742,20 @@ uint32_t profile_service_database_generation() { uint32_t configuration_service_reset_generation() { return configuration_reset_generation; } +ConfigurationTransactionStatus profile_service_activate_internal( + uint32_t transaction_id, const ControllerIdentity& identity, + uint8_t profile_index) { + require(activation_attempt_count < activation_attempts.size(), + "activation attempt fixture overflow"); + activation_attempts[activation_attempt_count++] = { + transaction_id, identity, profile_index}; + if (activation_busy_attempts != 0) { + --activation_busy_attempts; + return ConfigurationTransactionStatus::kBusy; + } + return ConfigurationTransactionStatus::kPending; +} + void profile_service_active_profile_snapshot( const ControllerIdentity& identity, @@ -439,6 +782,11 @@ int main() { test_four_slot_cache_and_unchanged_generation(); test_activation_disconnect_and_default_preservation(); test_analog_thresholds_rumble_and_local_confirmation(); + test_default_switching_retry_commit_and_feedback(); + test_identity_promotion_preserves_held_switching(); + test_switching_uses_pre_hotkey_buttons_only(); + test_custom_switching_chord_and_wrap(); + test_switching_slot_isolation(); test_all_runtime_cancellation_causes(); test_runtime_slot_synthetic_isolation(); return 0; diff --git a/tests/profile_service_test.cpp b/tests/profile_service_test.cpp index 646fd9b..57eacec 100644 --- a/tests/profile_service_test.cpp +++ b/tests/profile_service_test.cpp @@ -211,6 +211,100 @@ void test_pending_commands_are_not_decoded_as_profile_writes() { "activation did not publish profile, index, and generation together"); } +void test_host_and_controller_mutations_are_serialized() { + const ControllerIdentity identity = controller_identity_global(); + ControllerProfile profile = + controller_profile_default(identity, 1); + profile.weak_rumble_scale = 23; + uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{}; + require(controller_profile_encode(profile, encoded, sizeof(encoded)), + "serialization fixture profile did not encode"); + + constexpr uint32_t kHostTransactionId = 0x11223344; + constexpr uint32_t kInternalTransactionId = 0x80000019; + require(profile_service_begin( + kHostTransactionId, identity, 1, + CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded), + profile_storage_crc32(encoded, sizeof(encoded))) == + ConfigurationTransactionStatus::kReceiving, + "host write did not acquire the profile mutation boundary"); + require(profile_service_activate_internal( + kInternalTransactionId, identity, 2) == + ConfigurationTransactionStatus::kBusy, + "controller activation raced a receiving host write"); + ProfileServiceTransactionSnapshot snapshot = + transaction_snapshot(); + require(snapshot.transaction.transaction_id == + kHostTransactionId && + snapshot.transaction.status == + ConfigurationTransactionStatus::kReceiving, + "busy controller activation replaced the host transaction"); + + require(profile_service_append( + kHostTransactionId, 0, encoded, sizeof(encoded)) == + ConfigurationTransactionStatus::kReceiving && + profile_service_commit(kHostTransactionId) == + ConfigurationTransactionStatus::kPending, + "host write did not reach pending after controller contention"); + profile_service_task_on_storage_core(3000); + require(transaction_snapshot().transaction.status == + ConfigurationTransactionStatus::kCommitted, + "serialized host write did not commit"); + + constexpr uint32_t kHostActivationTransactionId = 0x22334455; + require(profile_service_activate( + kHostActivationTransactionId, identity, 0) == + ConfigurationTransactionStatus::kPending, + "host activation did not acquire the released boundary"); + require(profile_service_activate_internal( + kInternalTransactionId, identity, 2) == + ConfigurationTransactionStatus::kBusy, + "controller activation raced a pending host activation"); + snapshot = transaction_snapshot(); + require(snapshot.transaction.transaction_id == + kHostActivationTransactionId && + snapshot.transaction.status == + ConfigurationTransactionStatus::kPending && + active_profile_snapshot(identity).profile_index == 3, + "pending host activation was replaced or leaked before commit"); + profile_service_task_on_storage_core(4000); + require(active_profile_snapshot(identity).profile_index == 0, + "serialized host activation did not commit"); + require(profile_service_activate_internal( + 0x19, identity, 2) == + ConfigurationTransactionStatus::kMalformed, + "internal activation admitted a transaction without the high bit"); + + require(profile_service_activate_internal( + kInternalTransactionId, identity, 2) == + ConfigurationTransactionStatus::kPending, + "controller activation did not acquire the released boundary"); + require(profile_service_begin( + 0x55667788, identity, 0, + CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded), + profile_storage_crc32(encoded, sizeof(encoded))) == + ConfigurationTransactionStatus::kBusy, + "host write raced a pending controller activation"); + snapshot = transaction_snapshot(); + require(snapshot.transaction.transaction_id == + kHostActivationTransactionId && + snapshot.transaction.status == + ConfigurationTransactionStatus::kCommitted && + active_profile_snapshot(identity).profile_index == 0, + "pending controller activation replaced host-visible status or leaked before commit"); + + profile_service_task_on_storage_core(5000); + const ProfileServiceActiveProfileSnapshot active = + active_profile_snapshot(identity); + snapshot = transaction_snapshot(); + require(active.valid && active.profile_index == 2 && + snapshot.transaction.transaction_id == + kHostActivationTransactionId && + snapshot.transaction.status == + ConfigurationTransactionStatus::kCommitted, + "controller activation did not publish while preserving host-visible status"); +} + } // namespace ProfileStorageIo pico_profile_storage_io() { @@ -219,5 +313,6 @@ ProfileStorageIo pico_profile_storage_io() { int main() { test_pending_commands_are_not_decoded_as_profile_writes(); + test_host_and_controller_mutations_are_serialized(); return 0; } diff --git a/tests/test_bluepad32_backend_lifecycle_native.py b/tests/test_bluepad32_backend_lifecycle_native.py index 7484f39..72484d0 100644 --- a/tests/test_bluepad32_backend_lifecycle_native.py +++ b/tests/test_bluepad32_backend_lifecycle_native.py @@ -42,7 +42,9 @@ def test_bluepad32_backend_lifecycle_native(tmp_path: Path) -> None: "lifecycle", "pairing-policy", "slot-lighting", - "abxy-hotkey", + "profile-chord-raw", + "profile-feedback", + "stateful-rumble", "motion-hotkey", "analog-state", "rumble-mode", From 7358670e63cf39ba34f85d03d218e5599e1e3daf Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 2 Sep 2026 20:28:45 -0600 Subject: [PATCH 5/5] Complete controller profile runtime --- ADAPTER_PARITY_PLAN.md | 52 +++- README.md | 50 +++- bluepad32_input_backend.cpp | 155 +++++++--- bluepad32_input_backend.h | 6 +- build.py | 232 +++++++++++++++ controller_profile_runtime.cpp | 42 +++ controller_profile_runtime.h | 6 + firmware/switch-pico-adapter-feasibility.elf | Bin 4344448 -> 4659360 bytes firmware/switch-pico-adapter-feasibility.uf2 | Bin 1266176 -> 1376256 bytes firmware/switch-pico-aio.elf | Bin 4311216 -> 4611232 bytes firmware/switch-pico-aio.uf2 | Bin 1261056 -> 1366016 bytes pico_profile_storage.cpp | 110 ++++--- profile_service.cpp | 5 +- profile_storage.cpp | 169 ++++------- profile_storage.h | 19 +- src/switch_pico_bridge/config_manager.py | 8 +- switch-pico.cpp | 24 +- tests/bluepad32_backend_lifecycle_test.cpp | 279 ++++++++++++++++-- .../bluepad32_native_stubs/btstack_run_loop.h | 5 +- tests/bluepad32_native_stubs/uni.h | 9 + tests/controller_profile_runtime_test.cpp | 105 +++++++ tests/profile_service_test.cpp | 146 +++++++-- tests/profile_storage_test.cpp | 249 +++++++++++++--- ...test_bluepad32_backend_lifecycle_native.py | 1 + tests/test_build.py | 208 +++++++++++++ tests/test_config_manager.py | 9 + 26 files changed, 1565 insertions(+), 324 deletions(-) create mode 100644 tests/test_build.py diff --git a/ADAPTER_PARITY_PLAN.md b/ADAPTER_PARITY_PLAN.md index 2a4c1e9..1370863 100644 --- a/ADAPTER_PARITY_PLAN.md +++ b/ADAPTER_PARITY_PLAN.md @@ -75,21 +75,21 @@ The Bluetooth, UART, Switch, and XInput paths now share `ControllerState`: | Automatic Windows/Switch selection | Feasibility complete | Windows enumeration fix is in `db4a860`; real Windows transition and rumble were reported working. | | Windows feasibility test | Complete | `tools/Test-AdapterFeasibility.ps1` checks transition, PnP health, four XInput slots, controls, and rumble isolation. | | Protocol-neutral controller state | Complete | `ControllerState` is shared by Bluetooth, UART, Switch, and XInput paths; analog trigger precision is retained. | -| Persistent configuration protocol | Core complete | Two-copy CRC-validated flash storage, chunked transactions, generation recovery, and PC read/write/reset are hardware-tested. | +| Persistent configuration protocol | Complete | Adapter settings and identity-keyed profiles use separate two-copy CRC/generation stores with bounded transactions and recovery. | | Production USB VID/PID | Missing | Prototype uses `CAFE:4010`; obtain an appropriate project VID/PID and repeat Windows binding tests. | | DInput output | Missing | Add generic HID descriptor and report driver. | | Mac output mode | Missing | Capture/define compatible descriptor and report semantics. | | PlayStation Classic mode | Missing | Add strict one-controller legacy descriptor/report mode. | | Mega Drive mode | Missing | Add strict one-controller legacy descriptor/report mode. | | Manual output-mode selection | Missing | Add persistent PC command and controller chord. | -| General button remapping | Partial | Only per-controller ABXY swap exists. | -| Stick sensitivity | Missing in AIO | Add inner deadzone, outer saturation, curve, inversion, and center calibration. | -| Trigger ranges | Partial | Full analog values are preserved; profile-configurable lower/upper range, curve, and digital threshold remain. | -| Vibration intensity | Missing as configuration | Transport works; add per-profile weak/strong scaling. | -| Macros | Missing | Add a bounded deterministic macro engine. | -| Turbo and Auto Burst | Missing | Add exact 15 Hz behavior and cancellation rules. | -| Persistent profiles | Missing | Hotkey state currently resets on disconnect/reboot. | -| Profile switching | Missing | Add controller chord, USB command, rumble, and LED confirmation. | +| General button remapping | Complete | Sixteen positional logical inputs map directly to supported logical outputs per profile. | +| Stick sensitivity | Complete | Per-stick center calibration, inner deadzone, outer saturation, fixed-point curve, and inversion run before every output serializer. | +| Trigger ranges | Complete for current outputs | Per-trigger deadzone, saturation, curve, and digital threshold preserve analog XInput values and configured Switch thresholds. | +| Vibration intensity | Complete | Independent weak/strong profile scales apply to host rumble; local confirmation policy remains separate. | +| Macros | Complete | One bounded eight-step deterministic macro per profile supports buttons, D-pad, sticks, triggers, waits, and explicit end. | +| Turbo and Auto Burst | Complete | Fixed-point phase accumulation produces 15 activations per second with deterministic cancellation. | +| Persistent profiles | Complete | Global fallback plus sixteen stable identities each store four fixed 256-byte profiles in a two-bank atomic database. | +| Profile switching | Complete | PC commands and a configurable controller chord persist selection with isolated rumble/onboard/transient controller LED confirmation. | | Firmware updater | Partial | UF2 updating works; version query and guided reboot/install tool are missing. | | Switch 2 | Unverified | Requires real-hardware qualification. | | Windows/SteamOS/Linux/Android compatibility | Partial | Windows XInput feasibility passed; other host/output combinations need qualification. | @@ -322,7 +322,7 @@ Core completion evidence: and feasibility firmware reflash, after which reset stored the 60-second default as generation 2 -### Phase 3 — Mapping, tuning, profiles, and macros +### Phase 3 — Mapping, tuning, profiles, and macros — Complete Use four profile slots per stable controller identity. Resolve identity from Bluetooth transport, identity address, VID, and PID; use a global default when stable identity is unavailable. @@ -393,6 +393,29 @@ Acceptance: - No synthetic input remains stuck after any cancellation path. - Four controllers can use different profiles simultaneously. +Completion evidence: + +- strict 256-byte profile schema and 17,696-byte fixed database support four + profiles for the global fallback and each of sixteen stable identities +- profile and adapter stores remain separate from each other and BTstack bonds; + profile commits use one flash-safe batched inactive-bank replacement +- schema-v1 profile databases migrate inherited trigger defaults to schema v2 + without losing custom thresholds, identities, active profiles, or other data +- direct mapping, stick/trigger fixed-point transforms, Switch thresholds, + XInput analog values, rumble scaling, macros, Turbo, Auto Burst, and all + cancellation paths have deterministic native coverage +- the AIO backend uses BTstack GAP connection type for stable Classic/BLE + identity, not the stale cached Bluepad protocol field +- profile switching is serialized against host writes, applies only after + commit, and uses generation-safe per-slot feedback +- profile colors/player counts are transient on connect/switch and restore the + persistent USB slot indication after the final 75 ms gap +- 70 tests passed; UART, AIO, and feasibility variants linked and published +- hardware verified separate 8BitDo `057e:2009` and DualSense `054c:0ce6` + identities, isolated active profiles and feedback, persistent 2.2-second + profile commits, button remapping, stick tuning, 15 Hz Turbo, a releasing + macro, and transient profile-to-slot LED restoration + ### Phase 4 — Production USB output modes Implement in this order: @@ -536,8 +559,7 @@ Do not mark a host/controller combination complete from descriptor inspection or ## Next action -Begin Phase 3 now that the storage and USB transaction boundary is proven. -Define the fixed-capacity profile schema first, then add mapping and tuning -transforms before macros or Turbo. Wire profile list/import/export/activate -commands through the Phase 2 transaction protocol only after each profile -field has runtime semantics and deterministic tests. +Begin Phase 4 by placing the existing Switch and verified XInput +implementations behind one production output-driver boundary. Preserve the +Phase 3 transform/runtime seam before serialization, then add DInput, Mac, +PlayStation Classic, and Mega Drive descriptors in the documented order. diff --git a/README.md b/README.md index 0f26801..c730339 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ The Pico 2 W onboard LED reports the overall Bluetooth state: - **Pairing window expires**: new authentication and active discovery stop while a controller is active; remembered controllers may still initiate reconnects. - **Clear all pairings**: hold BOOTSEL continuously for 10 seconds, through the initial double blink, until the rapid confirmation blink starts. All controllers are disconnected and must be paired again. -### Managing configuration and pairings from a PC +### Managing configuration, profiles, and pairings from a PC Connect the Pico 2 W to the PC while the AIO firmware is running normally; do not enter the ROM BOOTSEL drive. `switch-pico-config` uses versioned private vendor requests on USB endpoint 0, so it does not add an interface or depend on Linux `hidraw` nodes. @@ -94,25 +94,34 @@ uv run switch-pico-config status uv run switch-pico-config config show uv run switch-pico-config config set --pairing-window-seconds 90 uv run switch-pico-config config reset --yes +uv run switch-pico-config profiles list +uv run switch-pico-config profiles export 1 profile.json --identity 0 +uv run switch-pico-config profiles import 2 profile.json --identity 0 +uv run switch-pico-config profiles activate 2 --identity 0 +uv run switch-pico-config profiles reset all --identity 0 --yes uv run switch-pico-config pairings list uv run switch-pico-config pairings clear --yes ``` -Configuration records use version, size, generation, and CRC fields. Writes are chunked and atomically committed between two dedicated flash sectors; interrupted or corrupt writes fall back to the previous valid generation. Those sectors do not overlap Bluepad32's separate bond store. Rewriting identical configuration does not consume a flash write, and successful writes are rate-limited. +Adapter configuration records use version, size, generation, and CRC fields in two dedicated flash sectors. Profiles use a separate two-bank atomic store before the adapter and Bluepad32 bond regions. Profile writes are chunked, verified before the new bank is committed, recover the previous generation after interruption or corruption, skip unchanged data, and are rate-limited. + +`profiles list` prints identity index `0` for the global fallback plus each stable Bluetooth identity observed by the firmware. Each identity owns four persistent profiles and one active index. Exported JSON contains direct logical button mappings, independent stick and trigger calibration/curves, digital trigger thresholds, weak/strong rumble scales, a profile-switching chord, one bounded eight-step macro, and per-button Turbo modes. Profile numbers shown to users are `1` through `4`; `--identity` uses the zero-based index from `profiles list`. `pairings list` refreshes and prints stored Bluetooth Classic and BLE addresses. `pairings clear --yes` deletes all bonds, disconnects active controllers, closes new authentication, and resumes discovery because no controllers remain. Destructive commands require `--yes`. If multiple compatible Picos are attached, select one with `--bus N --address N`; the error lists their locations. USB access errors require permission to the matching `/dev/bus/usb` device. -### Per-controller ABXY layout +### Per-controller profiles -Each connected AIO controller can toggle its own ABXY layout by pressing **L + R + Select + Start** together. On DualSense, use **L1 + R1 + Create + Options**. The controller gives one short rumble when the toggle is accepted; release the chord before toggling again. +The default profile-switching chord is **L + R + Select + Start**. On DualSense, use **L1 + R1 + Create + Options**. A profile can replace this chord with any nonzero logical-button mask; a stored zero selects the default chord. -- **Standard**: south→B, east→A, west→Y, north→X. -- **Swapped**: south→A, east→B, west→X, north→Y. -- The chord is consumed locally and is not forwarded to the Switch. -- Other controller slots are unaffected. -- Layout returns to the configured default after disconnect or reboot. +- The chord cycles persistent profiles `1 → 2 → 3 → 4 → 1`. +- Chord buttons are consumed locally and are not forwarded to the host. +- The new profile applies only after its atomic flash commit completes. +- Confirmation uses one to four 75 ms pulses matching the active profile number. +- The profile policy independently enables rumble and LED feedback. +- On connection and profile changes, RGB/player LEDs briefly show the active profile color/count, then return to the persistent USB slot color/player number. +- Each controller identity and each of the four active USB slots remain isolated. -Edit `controller_hotkey_config.h` to change the chord, default layout, or confirmation pulse. +Profile input processing is deterministic: physical input is mapped and tuned first, Turbo or Auto Burst gates configured buttons second, and active macro overrides apply last. Turbo runs at 15 activations per second while held. Auto Burst starts on one press and stops on a second press or the configured macro-cancel button. Macros contain at most eight state steps plus an explicit end and are cancelled on disconnect, profile/output-mode change, configured cancellation, or adapter configuration reset. ### Per-controller motion toggle @@ -271,7 +280,7 @@ Filters you can use: - When testing on a PC before plugging into a Switch, you can verify activity with the lightweight `switch_pico_bridge.switch_pico_uart` helper or the Windows "Game Controllers" panel. ## Building and flashing firmware -Prereqs: Pico SDK + CMake toolchain set up. +Prereqs: Pico SDK, Arm GNU toolchain, CMake, and `picotool`. ### Using `build.py` @@ -279,6 +288,14 @@ Prereqs: Pico SDK + CMake toolchain set up. were created, copies the release artifacts into `firmware/`, and flashes the ELF with `picotool`. +`build.py` automatically locates the Pico SDK and Arm GNU toolchain from valid +existing `build/`, `build-aio/`, or `build-feasibility/` CMake caches, then from +project-local `build/_deps/pico_sdk-src` and `build/toolchain` installs, and +finally from conventional user and system locations. A compiler already on +`PATH` is used without setting a toolchain override. Explicit `PICO_SDK_PATH` +and `PICO_TOOLCHAIN_PATH` values always take precedence; an invalid explicit +path is reported instead of silently falling back. + Before running it: 1. Install the Pico SDK, CMake toolchain, and `picotool`. @@ -316,16 +333,19 @@ If the tools or artifacts are in non-default locations, use these environment variables: ```sh +PICO_SDK_PATH=/path/to/pico-sdk \ +PICO_TOOLCHAIN_PATH=/path/to/arm-none-eabi-toolchain \ PICOTOOL_PATH=/path/to/picotool \ ELF_PATH=/path/to/switch-pico.elf \ UF2_PATH=/path/to/switch-pico.uf2 \ python3 build.py ``` -`PICOTOOL_PATH` selects the flashing tool, `ELF_PATH` selects the ELF that is -checked and flashed, and `UF2_PATH` selects the UF2 that is checked after the -build. Their defaults are `picotool` from `PATH`, `build/switch-pico.elf`, and -`build/switch-pico.uf2`, respectively. +`PICO_SDK_PATH` and `PICO_TOOLCHAIN_PATH` explicitly select the SDK and +cross-compiler installations. `PICOTOOL_PATH` selects the flashing tool, +`ELF_PATH` selects the ELF that is checked and flashed, and `UF2_PATH` selects +the UF2 that is checked after the build. Their defaults are `picotool` from +`PATH`, `build/switch-pico.elf`, and `build/switch-pico.uf2`, respectively. ### Manual build ```sh diff --git a/bluepad32_input_backend.cpp b/bluepad32_input_backend.cpp index 6ea621b..beab8e9 100644 --- a/bluepad32_input_backend.cpp +++ b/bluepad32_input_backend.cpp @@ -43,6 +43,10 @@ constexpr uint8_t kAllBlePairingMethods = constexpr uint16_t kProfileFeedbackPhaseDurationMs = 75; constexpr uint8_t kProfileFeedbackWeakMagnitude = UINT8_MAX; constexpr uint8_t kProfileFeedbackStrongMagnitude = UINT8_MAX; +// One initial indication can be followed by one committed switch before the +// Core 1 timer drains the queue. Profile commits are rate-limited well beyond +// the longest feedback sequence. +constexpr uint8_t kProfileFeedbackQueueCapacity = 2; constexpr SwitchRgbColor kProfileLightbarPalette[CONTROLLER_PROFILE_COUNT] = { {0x00, 0x55, 0xff}, {0x00, 0xcc, 0x66}, @@ -152,12 +156,13 @@ struct BackendSlot { bool motion_hotkey_latched; bool feedback_pending; uint32_t feedback_until_ms; - bool profile_feedback_pending; + uint8_t pending_profile_feedback_count; RumbleEnvelope pending_rumble; bool retained_host_rumble_valid; RumbleEnvelope retained_host_rumble; FeedbackEnvelope pending_feedback; - ProfileFeedbackEnvelope pending_profile_feedback; + ProfileFeedbackEnvelope + pending_profile_feedback[kProfileFeedbackQueueCapacity]; ProfileFeedbackSequence profile_feedback; }; @@ -298,23 +303,29 @@ ControllerIdentity identity_for_device(const uni_hid_device_t* device) { if (device == nullptr) { return controller_identity_global(); } - if (device->conn.protocol == UNI_BT_CONN_PROTOCOL_BR_EDR) { - ControllerIdentity identity{}; - identity.stable = true; - identity.transport = ControllerTransport::kClassic; - identity.address_type = BD_ADDR_TYPE_UNKNOWN; - memcpy(identity.address, device->conn.btaddr, - sizeof(identity.address)); - identity.vendor_id = device->vendor_id; - identity.product_id = device->product_id; - return identity; - } - if (device->conn.protocol == UNI_BT_CONN_PROTOCOL_BLE) { - const BleIdentityMapping* mapping = find_ble_identity_mapping( - device->conn.handle, device->conn.btaddr); - if (mapping != nullptr) { - return make_ble_identity(*mapping, device); + switch (gap_get_connection_type(device->conn.handle)) { + case GAP_CONNECTION_ACL: { + ControllerIdentity identity{}; + identity.stable = true; + identity.transport = ControllerTransport::kClassic; + identity.address_type = BD_ADDR_TYPE_UNKNOWN; + memcpy(identity.address, device->conn.btaddr, + sizeof(identity.address)); + identity.vendor_id = device->vendor_id; + identity.product_id = device->product_id; + return identity; } + case GAP_CONNECTION_LE: { + const BleIdentityMapping* mapping = find_ble_identity_mapping( + device->conn.handle, device->conn.btaddr); + if (mapping != nullptr) { + return make_ble_identity(*mapping, device); + } + break; + } + case GAP_CONNECTION_INVALID: + case GAP_CONNECTION_SCO: + break; } return controller_identity_global(); } @@ -325,7 +336,8 @@ void publish_ble_identity(const BleIdentityMapping& mapping) { critical_section_enter_blocking(&g_state_lock); for (BackendSlot& slot : g_slots) { if (slot.device != nullptr && - slot.device->conn.protocol == UNI_BT_CONN_PROTOCOL_BLE && + gap_get_connection_type(slot.device->conn.handle) == + GAP_CONNECTION_LE && slot.device->conn.handle == mapping.connection_handle && addresses_equal(slot.device->conn.btaddr, mapping.connection_address)) { @@ -374,7 +386,8 @@ void clear_ble_identity_for_handle(hci_con_handle_t connection_handle) { critical_section_enter_blocking(&g_state_lock); for (BackendSlot& slot : g_slots) { if (slot.device != nullptr && - slot.device->conn.protocol == UNI_BT_CONN_PROTOCOL_BLE && + gap_get_connection_type(slot.device->conn.handle) == + GAP_CONNECTION_LE && slot.device->conn.handle == connection_handle) { slot.identity = controller_identity_global(); } @@ -383,8 +396,7 @@ void clear_ble_identity_for_handle(hci_con_handle_t connection_handle) { } void clear_ble_identity_for_device(const uni_hid_device_t* device) { - if (device == nullptr || - device->conn.protocol != UNI_BT_CONN_PROTOCOL_BLE) { + if (device == nullptr) { return; } for (BleIdentityMapping& mapping : g_ble_identity_mappings) { @@ -452,6 +464,19 @@ void apply_profile_lighting( } } +bool lighting_target_is_current( + uint8_t slot_index, uint32_t connection_generation, + const uni_hid_device_t* device) { + critical_section_enter_blocking(&g_state_lock); + const bool current = + slot_index < kSlotCount && g_slots[slot_index].active && + g_slots[slot_index].device == device && + g_slots[slot_index].connection_generation == + connection_generation; + critical_section_exit(&g_state_lock); + return current; +} + ConnectionStatus compute_connection_status() { @@ -498,8 +523,11 @@ void publish_all_neutral() { slot.retained_host_rumble = {}; slot.feedback_pending = false; slot.feedback_until_ms = 0; - slot.profile_feedback_pending = false; - slot.pending_profile_feedback = {}; + slot.pending_profile_feedback_count = 0; + for (ProfileFeedbackEnvelope& feedback : + slot.pending_profile_feedback) { + feedback = {}; + } slot.profile_feedback = {}; ++slot.state_generation; ++slot.connection_generation; @@ -790,8 +818,11 @@ void reset_slot_hotkeys(BackendSlot& slot) { slot.feedback_pending = false; slot.feedback_until_ms = 0; slot.pending_feedback = {}; - slot.profile_feedback_pending = false; - slot.pending_profile_feedback = {}; + slot.pending_profile_feedback_count = 0; + for (ProfileFeedbackEnvelope& feedback : + slot.pending_profile_feedback) { + feedback = {}; + } slot.profile_feedback = {}; slot.retained_host_rumble_valid = false; slot.retained_host_rumble = {}; @@ -1216,11 +1247,11 @@ void update_status_led() { } void process_configuration_timer(btstack_timer_source_t* timer) { + btstack_run_loop_set_timer(timer, kConfigurationPollIntervalMs); + btstack_run_loop_add_timer(timer); const uint32_t now_ms = btstack_run_loop_get_time_ms(); configuration_service_task_on_storage_core(now_ms); profile_service_task_on_storage_core(now_ms); - btstack_run_loop_set_timer(timer, kConfigurationPollIntervalMs); - btstack_run_loop_add_timer(timer); } void process_rumble_timer(btstack_timer_source_t* timer) { @@ -1239,7 +1270,10 @@ void process_rumble_timer(btstack_timer_source_t* timer) { FeedbackEnvelope feedback{}; ProfileFeedbackEnvelope profile_feedback{}; uni_hid_device_t* device = nullptr; + uni_hid_device_t* profile_lighting_device = nullptr; + uint32_t profile_lighting_generation = 0; bool profile_lighting_dispatch = false; + bool profile_lighting_restore = false; bool profile_rumble_dispatch = false; bool feedback_dispatch = false; bool host_dispatch = false; @@ -1266,6 +1300,10 @@ void process_rumble_timer(btstack_timer_source_t* timer) { slot.profile_feedback.active; const bool completed_feedback_had_rumble = slot.profile_feedback.rumble_enabled; + const bool completed_feedback_had_led = + slot.profile_feedback.led_enabled; + const uint32_t completed_feedback_generation = + slot.profile_feedback.connection_generation; profile_rumble_dispatch = advance_profile_feedback(&slot.profile_feedback, now_ms); if (profile_feedback_was_active && @@ -1275,6 +1313,17 @@ void process_rumble_timer(btstack_timer_source_t* timer) { slot.pending_rumble = slot.retained_host_rumble; slot.rumble_pending = true; } + if (profile_feedback_was_active && + !slot.profile_feedback.active && + completed_feedback_had_led && slot.active && + slot.device != nullptr && + completed_feedback_generation == + slot.connection_generation) { + profile_lighting_device = slot.device; + profile_lighting_generation = + completed_feedback_generation; + profile_lighting_restore = true; + } if (profile_rumble_dispatch) { device = slot.device; } @@ -1282,9 +1331,15 @@ void process_rumble_timer(btstack_timer_source_t* timer) { const bool feedback_active = static_cast(now_ms - slot.feedback_until_ms) < 0; if (!slot.profile_feedback.active && !feedback_active && - slot.profile_feedback_pending) { - profile_feedback = slot.pending_profile_feedback; - slot.profile_feedback_pending = false; + slot.pending_profile_feedback_count != 0) { + profile_feedback = slot.pending_profile_feedback[0]; + if (slot.pending_profile_feedback_count == 2) { + slot.pending_profile_feedback[0] = + slot.pending_profile_feedback[1]; + } + --slot.pending_profile_feedback_count; + slot.pending_profile_feedback[ + slot.pending_profile_feedback_count] = {}; const uint8_t policy = static_cast(profile_feedback.policy); if (slot.active && slot.device != nullptr && @@ -1311,6 +1366,9 @@ void process_rumble_timer(btstack_timer_source_t* timer) { kLed)) != 0, }; device = slot.device; + profile_lighting_device = slot.device; + profile_lighting_generation = + slot.profile_feedback.connection_generation; profile_lighting_dispatch = slot.profile_feedback.led_enabled; profile_rumble_dispatch = @@ -1353,9 +1411,20 @@ void process_rumble_timer(btstack_timer_source_t* timer) { } critical_section_exit(&g_state_lock); - if (profile_lighting_dispatch) { + if (profile_lighting_restore && + lighting_target_is_current( + slot_index, profile_lighting_generation, + profile_lighting_device)) { + apply_slot_lighting(slot_index, + profile_lighting_device); + } + if (profile_lighting_dispatch && + lighting_target_is_current( + slot_index, profile_lighting_generation, + profile_lighting_device)) { apply_profile_lighting( - profile_feedback.active_profile_number, device); + profile_feedback.active_profile_number, + profile_lighting_device); } if (profile_rumble_dispatch && device != nullptr && device->report_parser.play_dual_rumble != nullptr) { @@ -1515,6 +1584,7 @@ uni_error_t platform_on_device_ready(uni_hid_device_t* device) { bool occupied_mismatch = false; bool became_active = false; + uint32_t lighting_generation = 0; critical_section_enter_blocking(&g_state_lock); BackendSlot& slot = g_slots[slot_index]; occupied_mismatch = slot.device != nullptr && slot.device != device; @@ -1528,6 +1598,7 @@ uni_error_t platform_on_device_ready(uni_hid_device_t* device) { reset_slot_hotkeys(slot); ++slot.state_generation; became_active = true; + lighting_generation = slot.connection_generation; } } critical_section_exit(&g_state_lock); @@ -1536,7 +1607,12 @@ uni_error_t platform_on_device_ready(uni_hid_device_t* device) { return UNI_ERROR_NO_SLOTS; } if (became_active) { - apply_slot_lighting(static_cast(slot_index), device); + if (lighting_target_is_current( + static_cast(slot_index), + lighting_generation, device)) { + apply_slot_lighting( + static_cast(slot_index), device); + } if (connection_identity.stable) { profile_service_observe_identity_on_storage_core( connection_identity); @@ -1812,9 +1888,16 @@ void bluepad32_input_backend_queue_profile_feedback( BackendSlot& slot = g_slots[slot_index]; if (slot.active && slot.device != nullptr && slot.connection_generation == connection_generation) { - slot.pending_profile_feedback = { + const ProfileFeedbackEnvelope feedback{ connection_generation, active_profile_number, policy}; - slot.profile_feedback_pending = true; + if (slot.pending_profile_feedback_count < + kProfileFeedbackQueueCapacity) { + slot.pending_profile_feedback[ + slot.pending_profile_feedback_count++] = feedback; + } else { + slot.pending_profile_feedback[ + kProfileFeedbackQueueCapacity - 1u] = feedback; + } } critical_section_exit(&g_state_lock); } diff --git a/bluepad32_input_backend.h b/bluepad32_input_backend.h index 0600d13..36ce5ae 100644 --- a/bluepad32_input_backend.h +++ b/bluepad32_input_backend.h @@ -58,8 +58,10 @@ void bluepad32_input_backend_pairing_snapshot( void bluepad32_input_backend_report_sent(uint8_t slot); void bluepad32_input_backend_queue_rumble( uint8_t slot, const ControllerRumbleOutput& rumble); -// Schedule bounded local profile confirmation only for the matching live -// connection generation. Profile numbers are one-based (1..4). +// Enqueue bounded local profile confirmation for the matching live connection +// generation. The two-entry per-slot FIFO preserves initial-then-switch +// ordering. Profile lighting is transient and restored to the steady slot +// indication after the final gap. Profile numbers are one-based (1..4). void bluepad32_input_backend_queue_profile_feedback( uint8_t slot, uint32_t connection_generation, uint8_t active_profile_number, diff --git a/build.py b/build.py index a46585d..e1360f1 100644 --- a/build.py +++ b/build.py @@ -35,6 +35,232 @@ MACROS = tuple( for component in ("R", "G", "B") ) +CMAKE_CACHE_PATHS = tuple( + build_dir / "CMakeCache.txt" + for build_dir in (BUILD_DIR, AIO_BUILD_DIR, FEASIBILITY_BUILD_DIR) +) +TOOLCHAIN_COMPILER = ( + "arm-none-eabi-gcc.exe" if os.name == "nt" else "arm-none-eabi-gcc" +) + + +class BuildEnvironmentError(RuntimeError): + """A required Pico build dependency could not be resolved.""" + + +def parse_cmake_cache(cache_path): + """Return the simple key/value entries from an existing CMake cache.""" + cache_path = Path(cache_path) + try: + lines = cache_path.read_text(encoding="utf-8").splitlines() + except (OSError, UnicodeError): + return {} + + entries = {} + for line in lines: + if not line or line.startswith(("//", "#")) or "=" not in line: + continue + key_and_type, value = line.split("=", 1) + key = key_and_type.split(":", 1)[0] + if key: + entries[key] = value + return entries + + +def _cache_path(value, cache_path): + path = Path(value).expanduser() + if not path.is_absolute(): + path = cache_path.parent / path + return path + + +def _versioned_candidates(parent): + try: + return sorted( + (path for path in parent.iterdir() if path.is_dir()), + key=lambda path: path.name, + reverse=True, + ) + except OSError: + return [] + + +def _sdk_fallback_candidates(): + yield ("project-local install", BUILD_DIR / "_deps" / "pico_sdk-src") + pico_sdk_home = Path.home() / ".pico-sdk" / "sdk" + for path in _versioned_candidates(pico_sdk_home): + yield ("user Pico SDK install", path) + yield ("user Pico SDK install", Path.home() / "pico" / "pico-sdk") + yield ("user Pico SDK install", Path.home() / "pico-sdk") + yield ("system Pico SDK install", Path("/opt/pico-sdk")) + yield ("system Pico SDK install", Path("/usr/local/pico-sdk")) + yield ("system Pico SDK install", Path("/usr/share/pico-sdk")) + + +def _toolchain_fallback_candidates(): + yield ("project-local install", BUILD_DIR / "toolchain") + pico_toolchain_home = Path.home() / ".pico-sdk" / "toolchain" + for path in _versioned_candidates(pico_toolchain_home): + yield ("user Pico toolchain install", path) + yield ( + "user Pico toolchain install", + Path.home() / "pico" / "arm-none-eabi-gcc", + ) + yield ("user Pico toolchain install", Path.home() / "arm-none-eabi-gcc") + yield ("system Pico toolchain install", Path("/opt/arm-none-eabi-gcc")) + yield ( + "system Pico toolchain install", + Path("/usr/local/arm-none-eabi-gcc"), + ) + + +def _valid_sdk(path): + return (path / "pico_sdk_init.cmake").is_file() + + +def _valid_toolchain(path): + return (path / "bin" / TOOLCHAIN_COMPILER).is_file() + + +def _first_valid_candidate(candidates, validator): + for source, candidate in candidates: + path = Path(candidate).expanduser() + if validator(path): + return path, source + return None, None + + +def _cache_candidates(cache_paths, variables): + for cache_path in cache_paths: + cache_path = Path(cache_path) + entries = parse_cmake_cache(cache_path) + for variable, compiler_path in variables: + value = entries.get(variable) + if not value: + continue + path = _cache_path(value, cache_path) + if compiler_path: + path = path.parent.parent + yield (f"cache {cache_path}", path) + + +def _explicit_path(environ, variable, validator, expected): + if variable not in environ: + return None + value = environ[variable] + if not value: + raise BuildEnvironmentError(f"{variable} is set but empty.") + path = Path(value).expanduser() + if not validator(path): + raise BuildEnvironmentError( + f"{variable} is set to {path}, but {expected} was not found." + ) + return path + + +def configure_pico_environment( + *, + environ=None, + cache_paths=None, + sdk_candidates=None, + toolchain_candidates=None, + which=None, +): + """Resolve Pico dependencies and apply auto-detected environment values.""" + environ = os.environ if environ is None else environ + cache_paths = CMAKE_CACHE_PATHS if cache_paths is None else cache_paths + + which = shutil.which if which is None else which + explicit_sdk = _explicit_path( + environ, + "PICO_SDK_PATH", + _valid_sdk, + "pico_sdk_init.cmake", + ) + explicit_toolchain = _explicit_path( + environ, + "PICO_TOOLCHAIN_PATH", + _valid_toolchain, + f"bin/{TOOLCHAIN_COMPILER}", + ) + + sdk_path = explicit_sdk + sdk_source = None + if sdk_path is None: + sdk_path, sdk_source = _first_valid_candidate( + _cache_candidates( + cache_paths, + (("PICO_SDK_PATH", False),), + ), + _valid_sdk, + ) + if sdk_path is None: + sdk_path, sdk_source = _first_valid_candidate( + ( + _sdk_fallback_candidates() + if sdk_candidates is None + else sdk_candidates + ), + _valid_sdk, + ) + + compiler_on_path = which( + TOOLCHAIN_COMPILER, + path=environ.get("PATH", ""), + ) + toolchain_path = explicit_toolchain + toolchain_source = None + if toolchain_path is None and compiler_on_path is None: + toolchain_path, toolchain_source = _first_valid_candidate( + _cache_candidates( + cache_paths, + ( + ("PICO_TOOLCHAIN_PATH", False), + ("CMAKE_C_COMPILER", True), + ("PICO_COMPILER_CC", True), + ), + ), + _valid_toolchain, + ) + if toolchain_path is None: + toolchain_path, toolchain_source = _first_valid_candidate( + ( + _toolchain_fallback_candidates() + if toolchain_candidates is None + else toolchain_candidates + ), + _valid_toolchain, + ) + + missing = [] + if sdk_path is None: + missing.append("Pico SDK (set PICO_SDK_PATH)") + if toolchain_path is None and compiler_on_path is None: + missing.append( + "Arm GNU toolchain " + "(set PICO_TOOLCHAIN_PATH or add arm-none-eabi-gcc to PATH)" + ) + if missing: + raise BuildEnvironmentError( + "Missing build prerequisite(s): " + "; ".join(missing) + "." + ) + + updates = {} + detected = [] + if explicit_sdk is None: + updates["PICO_SDK_PATH"] = str(sdk_path) + detected.append(("PICO_SDK_PATH", sdk_path, sdk_source)) + if explicit_toolchain is None and compiler_on_path is None: + updates["PICO_TOOLCHAIN_PATH"] = str(toolchain_path) + detected.append( + ("PICO_TOOLCHAIN_PATH", toolchain_path, toolchain_source) + ) + + environ.update(updates) + for variable, path, source in detected: + print(f"Auto-detected {variable}={path} ({source})") + return updates + def parse_args(): parser = argparse.ArgumentParser( description="Build and flash the project, optionally setting grip colors.", @@ -197,6 +423,12 @@ def flash(elf_path, allow_elf_override): def main(): args = parse_args() + try: + configure_pico_environment() + except BuildEnvironmentError as exc: + sys.stderr.write(f"Error: {exc}\n") + sys.exit(1) + color = None if args.random_grip_color: diff --git a/controller_profile_runtime.cpp b/controller_profile_runtime.cpp index 0c5d6ff..ddf6478 100644 --- a/controller_profile_runtime.cpp +++ b/controller_profile_runtime.cpp @@ -27,6 +27,10 @@ struct ControllerProfileRuntimeContext { uint32_t switching_transaction_id = 0; bool profile_change_pending = false; ControllerProfileRuntimeProfileChangeEvent pending_profile_change{}; + bool initial_profile_indication_resolved = false; + bool initial_profile_indication_pending = false; + ControllerProfileRuntimeProfileChangeEvent + pending_initial_profile_indication{}; }; ControllerProfileRuntimeContext @@ -98,6 +102,9 @@ void refresh_profile(ControllerProfileRuntimeContext* context, context->switching_transaction_id = 0; context->profile_change_pending = false; context->pending_profile_change = {}; + context->initial_profile_indication_resolved = false; + context->initial_profile_indication_pending = false; + context->pending_initial_profile_indication = {}; } controller_synthetic_input_cancel(&context->synthetic, @@ -111,6 +118,21 @@ void refresh_profile(ControllerProfileRuntimeContext* context, context->active_profile_index = snapshot.valid ? snapshot.profile_index : 0; context->profile_snapshot_valid = snapshot.valid; context->profile = snapshot.valid ? snapshot.profile : g_default_profile; + if (!context->initial_profile_indication_resolved && snapshot.valid) { + context->initial_profile_indication_resolved = true; + const uint8_t policy = static_cast( + controller_profile_confirmation_policy(context->profile)); + if ((policy & static_cast( + ControllerProfileConfirmationPolicy::kLed)) != 0) { + context->pending_initial_profile_indication = { + connection_generation, + context->database_generation, + static_cast(context->active_profile_index + 1u), + ControllerProfileConfirmationPolicy::kLed, + }; + context->initial_profile_indication_pending = true; + } + } if (context->switching_chord_held && !context->switching_activation_requested) { context->switching_target_profile_index = @@ -273,6 +295,26 @@ ControllerProfileTransformResult controller_profile_runtime_transform( &context->synthetic, consumed_input, context->profile, now_ms); } +bool controller_profile_runtime_take_initial_profile_indication( + uint8_t slot, ControllerProfileRuntimeProfileChangeEvent* output) { + if (output == nullptr) { + return false; + } + *output = {}; + if (slot >= CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT) { + return false; + } + + ControllerProfileRuntimeContext& context = g_contexts[slot]; + if (!context.initial_profile_indication_pending) { + return false; + } + *output = context.pending_initial_profile_indication; + context.initial_profile_indication_pending = false; + context.pending_initial_profile_indication = {}; + return true; +} + bool controller_profile_runtime_take_profile_change( uint8_t slot, ControllerProfileRuntimeProfileChangeEvent* output) { if (output == nullptr) { diff --git a/controller_profile_runtime.h b/controller_profile_runtime.h index 2843643..be8d1f1 100644 --- a/controller_profile_runtime.h +++ b/controller_profile_runtime.h @@ -27,6 +27,12 @@ struct ControllerProfileRuntimeProfileChangeEvent { ControllerProfileConfirmationPolicy::kNone; }; +// Take the one-shot LED-only indication for the first committed profile +// resolved on a connection. Identity promotion and database refresh do not +// publish it again. +bool controller_profile_runtime_take_initial_profile_indication( + uint8_t slot, ControllerProfileRuntimeProfileChangeEvent* output); + struct ControllerProfileRuntimeLocalConfirmation { ControllerRumbleOutput rumble{}; ControllerProfileConfirmationPolicy policy = diff --git a/firmware/switch-pico-adapter-feasibility.elf b/firmware/switch-pico-adapter-feasibility.elf index c564e0add1eaeaed4a24fb50953981192f4f375b..d53f4246ff0b5f2012d58098be19b9dab25154e1 100755 GIT binary patch delta 2002424 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

jgSkY5SVWP&$ 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%0AEN+ZBX>Vh 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

;QKr6T{0nPp4ev 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

d`}#WnM>4M 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 whhNL{26HU00G($vM6- zvcqxF7D89RUItWd3tP46ztgEYhI9tnrmbVlN^)(loK!4GYM?zpNnQIgN}dBE>c9rt zvtGb$7og7rrSyZWgY4Ss3bQIxx{R|2NCtpa&KglgN@ARhvzwkfWwhbqB@GJ}}| zo6443g*RKkuPXmm3VIZ&Y`G6mg4dC1Y;H=XQdMoMNtDWfscmgRS^}oFN!-&z2?e!n zCb54cMQR&wCP?-H!p#s;W%~lo|EO%eV4KPoZVyHaA7+I~9#1(_n{vlAfu`n#FJQ0g zN|gkc3YQL76|QL_j0z{CB-cF=Mui(dm@1r=_Q{g?{vI6st9_d;e3IM8!t>o8qZ2eW ztfxIhZodKZ#{kCbJ?%T>^)=8d0OR#uzSs9b?*ioYK1SykP@ek~=9o=@5Iw!LJ^ zOI}a6F2ep1NSpS6@Af$oizC+8_O8Ve}P>w);Op1A!-y7x}TMWLk$w=XIlxV@9#v6LeVQNXyplRaZS z<<}LuBVgR#*?0R`=&Jy^y{pmr0Muf@xILK!?0-@=U2LxuFW0`?*TG%|q-8Dj-JU10 zlZbV*z3EtD+Pat24klWi-XKw^BZdY7a58v%Gl#1Lw34w`#@3V$VL60JC z?*-|c^WEN1smkp!qTB))w?7E76fka=xTi-Ew_hZ7Hc^e+wOf4F@< zY~SrO!HnB$NHS>c4-)9Ry*8NK*)hSz?d=JZ+lM5=aJ!6>+@wSpZoiK(-|eNB#y{$f z+n=D@Ze?6lpI*do?dx&^x3{wUtF<4-{O1AV_Ez?Ex&2?zKLEzz_`7U`qm7}rj6~@%1*ewJM7LtTFao5?=G=&i1A|>cVmfh`*NgDe#x zw|@ij5n$Y|xUL?)+ZQSoxxG|P_BjCGXG4{O9!1gyS<%KmD_6(r3zr&-VUS{ zVB9WoPmdyQZ$<2?L^W<7h-6IM==^ve0M@| z17GnegiioQaRXoRMdDALDbsijB z54arkjHILARH-Q_m;_kiIdF$#jXn;H;W+(-qs;<#eXIUzSaL?%RuGvcw)ttt2A47E z|E)caLf{4<`V+>D*W9i+(_n5~ zTra~yu{?HpU>^dkXj7;$$k>&TaqY-qWXg9TFj+D6c49?~K~9vOy1vYLWV+`O7^=(3kucTv@WK1y z8wNxx#y$xGn6bM|H@~_7J<*aUhp@kpqj!$4x~LCIy#$>=b(PWAW=eTEWIdqx2W2^_ zK}4q`rhVuATb6xI*eIAofp9ZQe+M3V*O(&DgxeDoPwBqsq1EeE`!P%>}t0sBuG{FBn>e zpqY4#kNsvOwHW9nbompdOPa zSoX(eX{I(oH3Z7jadg?vtNhqpnc~0T&2ONs4Cs%Gby4&bI{(%PH;?fM;TJ zgct`hQbZkyJ3wXw;qxfbl1K&`$e3zE>M}c1izii05Ze`|B80OER-I|;2eW0JR-T|b zNYc2?H#!+7X@f17HN(!9uqYDioxHnbn=S~um-OxdlH0;tLbSBbAX;-#=g|YxH zelRy}e6%#4F@#eAUtpY;C*JXmbEeXD*Co!Mge5lx(Ncw#s8y%nmFTXL*c8zVi`@)g``k^Y8%?*5 z5xS}WF9_Bgcf<9Ty(NW`w@PY+u(z8L!s^wJUdCRK8e=cXvbCgN_)w`mo5s_?qv}&lZS6+`_a&+8bL?c<$j)H9gm|kPV5cL}4 zAg=+cEAf#f6=6B#eL(S<)WzE9vcG?sdmOxh@IvT%mD^k(%z2PPVa|j2vd4n+Ad*#g;Vb4iNTDppL44U4 zC?EHrT~6zc8s5uvd7EqG3OvMoV9^=3Ro!07E89568467S=^q&^iC-`ynLI$Ds_CtnMf zHK$rheRGWJ3O}X9iw%qBWE*z7j$&J>VwK?FLDOM;!*P;9P;RqVURs4J*Np~nk%Iml z2n~d2%(uODfY3;YAt1egq{$E~K^BUb0r57-F~D>>pQF?6Pfv4iUWVHGSJ39sl!O+f z-c>1)P(5zB_>ov9rPTWLM1V=DEJ$gfyizK!6#C5zG)YPSyC9s!?K9-qu*P3KRCOLs z`Kco6pC!CH@vBPVOAt*!>I1bhC9R&zw4CmX+cV6lwkh1vLt0j(G?kIp5Z;?eJ*8z5 z#Bh)y(o*_wTBIa=;r{sA;fxdEMezf}87J}((bBFGTig$&8ETO=6j2YB6RmaL0VSiQ zzT41x3y{_bUa-^`TKs&B`EGG_b}bd}8p`xhubLdC72G)T_X6g1>mMLbi_q&Qv3Eg*PDRtmiWsbB?nBBV2wROhC=typ^9$|uHUfEjFh zf^-AS>z1TFJ(NzYUfuvL;ZB9-KkHfIn^ET)#D@XNv*Bo1Nm~S>;pe}H9xMDXJPkOn z6Fo8D>?X_%ILTeXG`|ZE2hls$g@hPuu3?!XZYl*vT)#Mz*AuEqe%jW6UBI$xH6=)? zOvB*Ir(yO%0*FoX_+6!bCqa|2eLRqKKg2yCcLCH0xM6hE0Qsya&3VI_F>j5i6 zo$6spmBIB|DzK^iJL+EQx>8Bz6K-~+yfHQ(Tcxc0}|57iqN&W_eqa`%p;@&79syT)QbKA zkWg^-M?O-aBDa2oiro4U(jf`2Y4JNGqeBv&|9gyFClbrm0<{iEgfGc@2Y#8ac~sJ7 zzO$$N&)}6q!LWW_|?Ml(F5Ad#ea5JCdD-Y(g|h3);WRFqV$0DxKvuLYcE;D_b!Fn5y-AW!y$$`N} zr(`11s=7q@bEGF#TlqPrX&fT&3=fQB<(W>K`c$ujG(SOJwgTC*tln5vSi5(!bk(nn zXv{hb^8;nr5ihkXbu`qlm~}Oh{Q+ZOiJ_)^d;?3G^0*(~-A0>^Jw%PR;b^O5Op{MdZc|z) zw>uErm{68-Wf5hmM%gFu-jlLYn!WS+O6&+~RHL#qdw15gP+6B|_U^3fE7U6WElu8O zTR}t*T}QQV%Tc^i|7NQ%+$dKeiv!t4 zmmBr*KPN=Lw~B0ruPUpVTKKu-a{PwpI9379#I&@0Aou>&1 zg2_ys#)%6yR^9GTW`@7-ORQhQi-bR!DIH3R{Yb>p{yk--{kzRt`?HPG{ye0#f84aR zf5fzmCOqyX<_KtMf2LDLGadKxQd*xV?H?X3qZy9dv(zFJWG*^u6Dqk{lz&9DhVYUb zcnmG0NlhrX_)v%%kMk&_nN6rl_Vo%lr~plGLiMxf2+!|K{u*T|yt1T!1*+8HQOqhS zy75h`xmd!P#AP#9PU?<$?@7_zQL`8DiNN(42jPcu=HJ77=Y|XkgmWI_NTG9MhGHh= z)Z?d=ovDUM&bd{eAKYY!l$@>|;7l__DtYjK@${|vNZjoHN!&8wJL0cTiZ*m!pB=X+ zM?1vAccK2WXX!K;imTxPyQ%vVL5-Wv;q!BQz#WXLUW z{cF*KCLr%90c)^rLJ&|^0l!gf6QezSk@AGJA4V=6K3q#~KyTS}|3`H9w#wUT+KqDQ zr{Alhkg5)%#FFOd=CKU<)MU#45WZTgR`Ca>M5_!cCy{GXPr$xcazX+T{Rn%wLQ0&F z$HWqnF;ST6hE;6`IY}C9q8|Qx)T)2ZjTgH`dPKtGFhjvTb$zd0xEr_0gQJ zIa2U)HRco%uJ#67mx< zz6DG!*M)m1tYlMqWWeNdU3i#s*#Ww-!j#K(;VF_^3Vk17a`{MDs>x+ikW1E$ty&ni zKAirzILhktNIwCPRW3~h`Ba2*nshncBVck`4Wz6H<+LBj6@ba<<%yh5CS=^@UVQtF z(HXHgt)O-@&YTc}DdB*r|z=B`yehYFAFgex7 z?#8Fd`LOf7cu<5qFoln@AYNUJ6%9cX%Vr!|B`qy8jE%zXt;qw$4^OvLg zxQi#^QY)H7729ct)mJ1Vq@loG**%qlSMPXBxT=z=Nd_tamp^xgspz<=){JoOU6^|v zVOIiOv|}?fY`T6s>ABl@RYR9!y^i?IaB*!{IIj{~tU0snwC0q?NvL`tHG#;eS-hMO zfvYWe%B(%!bj6tjqbCwQ0INh}sPabaUGzSk;N#k7S$|{W!37%cs36aj!kP71 zmZ%F|O<`|QQTm0ODr^9BABA1Uh}|zdMq$@Mj|1f00paYsVi>m;dNz-obrogFB_XmL_L5d!{Qc?C@l_s&H!@u93zjyW3dDa3<`aNZ6XGPuaU>_)60MN* z4a8Rviy`uUh4>jDC;W|@XKH}ExSzJ?J$LwX@#D8dYbS+UGed0c#rNJ9Eg!FVYjm*l z_#N??w=%fMDRslc4$44;vH;_hy5VUGYXN$SqNm9u9pKP~o0sj#V%GC1TFv z&MM{x6f*+rVcrU4zr-Bi(r~JpV$HU!3IGKq?^rEP>-|3LoyA$EVYGzb9I%oKi?s_v zjl(IEGJ;~g0)BU(pjhz?BGV#+5)wnG*3|P-yo11Z;hsWq=FDj6q;DaI~5l;{BP?N=+Xk+Omvn#ghI(@cID-7FgB> zB=RHwlJ%092zM;8KfWzm!ojyaZ;RF%y9=52;YdytAyu3?2+ahHCHq010t$3G*2^Z< z{fSh+gZo8M3EMhtQeBgfNNG=3)4nj(UvHyEl_RhWfn=m)ylyO7aqO4G>JW}ttaTbY z8X!>X2z-qB`&L)z-`#Uw6zlPZLw%d z*RF(g2L9IISQ`r3TMA3yeeC9R?wLf_pKJ9%=b}iVmHmm{7o~s3qL&QnHmVW565|@cG|dv>YZbN-dY;16G)siKE zzW`)k&)deoJkuA|fv&8uatu`$y$qG+Q0P8@>C}Glf=;bjC&ry$eTmF+F}k?lJ=4YQ zL-bxC|6lL&Q5s!)c40{jhv_7i?5m!tt zv;0y)GyC2fdXSK}iSZ_2D$w`dO$xgJeO_S|nU;L-El^mr2Xnk0UcAG+Xnw!BRIJ#4 zYJN4L`72*@U1HP%jOMR=&E23oDNLHb@->fz9_4FplH}ARsd4k;(Yu0y`em=5lD`X~ z+Z9pu{AF)~!gfG!R+yB%?9Eo#Dd=Mg>rX9y*;}iyKcIgGG+ZC{>vFp*sP=#vu3z<= z$lX0XYc5bQTn}@t)9>&S>3Olzl*xf=dTplCh+3YjBbN=g}I)Sc{rza1!2&woW^ zTI45bk;Hzu&-e7=N%Nz<$0p;#x4g)|6kVPA8!(RmrlS82auFy}bITyVEMt|#RlRb1 zkqe+ef|X??@*}en61Cyh=;g%^&i6-9#*o@cEeUK+V1tFx+<37CjAfS+>$Dg7xNKlY zFC;nx#*T#`bAWpy;dbjCjAaWKFqVxZ6r*q5CULFFQ|oGZZ!(`c^{Y0 z?5qGq<^ZPSM1EvOLgFE~%YeUk2e$;>LH++R z6L75Ys8|$v7Zrs)*EV!)8RW&^SsbmG)J?O7Y460FEsmDyb(b+|JY{7}dKST_fdZpB zf@DnUmXJ6E_XXg8o8(UqavnpvF!f`IzwW2r^OE-=PAh(qxA}GWVVRenNewgegrDGl zO@uy6INZOGHKKP-g?pF{Pi7_d%2C%+6}4B;&8siG#1O`i!Bo55AKO-Uulldli(iKE zLzzPf8^bbh53iau{632D3P>Hh-L>i2MdPNjI~3 zIv!cTDGreXQd~p@h)N)NfLj+WTIJTV5xe_#{KMy?;duSs(NKK$15q#5(xkGBRQh{m zr&K4E<5T%&fv9z)>kLF6knSSBfS3$2LBs`!xgfU#VSYBydI%&AEV1!g?H;#{lOT#9okRfMO~GiSr{5L8P8`x+#N~U>}ma%HRaZ zF%c?*_d!mJP#Js)at>g};;J?N;#o`5EL=cqz|WYEfTIOSZ#)PmW33^+h~0^Wu{H5^ zOPQHJWQDo&u5@L5w9q+d5BzNlyCqSS@OQ2ZEj6JkB6=1aPi~s4#R6V7%9 z!?^^Znu<0Wq6tVN5!XYs1!)Z!YZNt9prBn~O%K@JBrj_Qfea9#7Sd!C*a%TFXEMlj z0OfNl&eE0^#cVe)YaL&3JdQU*&#kS_HqPPcUuYwarKj4k<7C!WV^9;Gfs$LKRZVyv z$Q-~JDCtl^oJ12|0(+6}Avkr!X|yXKyaZw;$N~|oAufV^ zAz~{;>zjFN1j0{2Yyep%;suBr(>?2R2-6lztmNpZrKjp_L&v+SHn~$%ynP1uSpp1y zG04)0xYk1y!KF_6Yzb*K`ymAGH$qx=t&I!^^pI)fqztNqj3$s@!aog|R@sF1V_WA; ztGpmBlISqgv)TY&Yq(mk_yA6!BO3Ow+^zwqFcdF%jYv@P{9;5A`TCZZy3uD;4;a&7 z_jYCwW$5Pkq=#|o_RYS86#881zm=ZFb2UAHW1f1|ujOQZrmUzPkHpAp0Mm{qflL&k zc6=+ybihPSOgR&?&|Ec0x6w!~B7EYl)M$LzSTe?UA8%=yoWVzeX zFOS9DmC>x&LeocOVe?=ob4)#qR{!)J(Z2yq|MV-!&mz=6dAFe$$kGU|$RSIS6Ma(_ ztW3a^a5<1NB2>UNL8^;T0XG3@1h`Jejq!?4MYCh3ps(7bs+otrR!-$17;9$A9T9A8 zVv_ZVAY%YioWqU0o>eG^Wf_j5Xtul*i6sfCDe&15hkziF6KL<8e#UpKXlqqF?FKgAomGXBMyX!*uFDLh5J@c%#R{!Q`x zwb8uB7lNo=E-h;J|1nic-E%g_7ZKHIv^oC7+Gyp*-RT9C`ip;4vGl(T@9i6|ybjnL zPhCgq^Ma_k^z;;KP-_3j)XB5EbaQ;zI=(QSY6hawRLP-U*##}A4If|6+!wcXlpnu^ zC>5h$5%DX;ix3+C$Gd?Wb!O8U15Om8+3k$BK)4*lNs#A7)P(4C2M3UWaASx*AiV%n zDQCw_^0RrWR-SRP8#fMW<<-bs37A?r7Gw-yYNe!ID-kDAE2qM~LGotI0J%+sYUMp3 zcZ*P^jDsu#Xya|MCbndq8u@PW|FM&PrSjjG;C)D}Q$An{sJiO}NRd_d$@d(=Ndk@V4ROpYFr zEi*_c=G3lnIkspY`539Z448ecw0r3E0J9yI4{|AB#+s%kvYzG1_14sdml0p1$Y>-+ zCZsyU$A3ICkjjrt@TC~*Z$M-UV7cw#1_OL(@iVc+UVp(5pCVg#Zk4Uev2|7CWK)vT z{@m@vzYQ>UKLoN&g!bp21=$0bU7r2K8%W6GGG zB}i;hWFu+{htZ1YsQ|cT5l9R;MwPp`Gd0mYPZEC%*Ffa%EeuT*spdM~P>Nd8@roOx z#mkKis8n39s#K`gymYzZR#J}ggmIIP7^${tmdx=dSZV^uA{X$sLCq?w3z z5S>9f0+&>Qc$ldEGYbW$P1OD{`$}3-M}v$Mp{Un`Oa{tsB^qM}w=?)(Dp*Nx+{$of zlrX{gViAZmz$8`Kn9RuiPU2qo4Cq#+QN{x%@30B^vS z_<>FQ7Tl;U@%J}HD>~VaF5k>&f(ssrSJ3|#ABnfz9IX&*!mEO9>8ZZvbtipYKDKBc z+8r%j0W%LB2-07K=Ak1&t^rKXt*CB+g2Y^O3hYUeSI<2IaBgElUbJ?ocuQLK26+>C;3({MJbPWT!T7+~>1Q`!l-g0_uO-b6L!M3v#6N~4I%t_+c zZRO1VY6LYMQ)@McH0b_`KQZX>r<(YQBXg`4ObZy2_s`KW=}G!-3h!_X?v8Z~%dhdu zo^FTbe-XMEb8eP>X-q+?-A_LTI3*$WfozM3stna*5nr?ePCbZ+K<);@`4B&Wdt z6kY~(7V4x}YavEHzzJR;yba<}khqAaA>IZ#0pz|2VU9g+G*g<|CpZb}6uYt&2I<)2 zMP$wc=G0@ArA)5?bLw%k$$*|}iF+n{r&)iE7Bd9qtUkI~2Ts)`j!80sZKD4d~g<^DE=`Y-cg=5NcdYPZ{&Qllg^o zX%S!>dbR+jAwC7NTZ9_o3m^vpQ}q><#pFOiq9MKx`!&g{w!Q=MmI&3>vml>{P;LD_ z2KFsLQL1B4-JnitGMW0r@$PPoB^nieL*Q3MQP-Zfi~;~m*Ip7N2PmP)SwyA}BJ$~o ziB}m;MTsijr63JNXh>)U(gG;!RN4?<|5&tctTvGy>n{c2B#i>s zfs7NOj`?1Y+eN5jei7t=2=(meKt2V`D3GF2;1ScYY(V$f^xLIcVt*j=o8l;)l$Oh> z-GE7`6i7)CW&{AKEJ6vj2WbnK5nvEVKfv3uJ%0ZVUPktAkMG(M&2idph#%g;FMeHR zI+ER_d%?-zpiI7isfNTd`hhKEivO^EktF31lgI{DvU$UFIO~$BKdmh1O6jM5nf*cVcoo7Ja z5h0!5fqVnFn;(y#cs^Px{{7?Zyc{w4JBrGGJDC>~Dt|-nS4EV{aGX<}fKizRk|{ze z%Yl>uEKluM9c4}W652}e0`^Ohe$s#G{IcNP&2^|PAH{Fn$8`SRD0i}ByRA^_U?iKRj%WlGE$Qi?ZQOd0<17Y3bhnuK9Hm}#!oQJwTiz% zj~dF1bigomEpNg;0hq4k1CTQ!)U|vC@&#b3pdzy)N907e@-J9FNmfN_zNrLdB9gVvsuP%E(q!WF1kz6r=%QI_srK z+m@cDv-ZX+59+I1BGDZ1`|7nutR|)geRVHb-2u~A?=;-fO<_-qye$pttS7-94|w}m z#lL@opZYw!%Dim3-p*C=@=xN{_lTF6hx@N&^)cN1DCAfsq8fy#$YqAx_< ze83!5-*09$dZrVr;IR5j1QaM$rp(LypXhTeJ?TTOA)(A4I`TVerXFua;by?p<2@ix zDh16{Bu+gJA|>kaKVTn_yqt6d$M1l=B|`Q1EXXH-o3Tx8I$K++sj)YV(R#{` ziJ{DgI+3^gN$fnb-zoA6h~Ged6|o5-X%&SC7@HK;wGs+i1yivs*qMN_sT@cd5wfW! zNOcjisZlCeL%{uHyNt@|L+4Ba%IsV8He6&&iC-Ve{8d(|18a?NOGQ^^yMc5OA;kkh z`iqd_5g@|>x7tos$l`vVn6XPE)&x}E7RnsfIZ!znx$6{BDsKguEoGRikFf_TjNun z;#|vFx?bD5nF1K)mEGP8t?m>?D>S|Z@Z&j51Xpu&G~kqhXuF0bO2DZO@j1vFA})pK zxR%9kAlwRK1IP*y-5@>!IRYdNg0M_W+)RQ)-Sj_VJxOsK!L8Tv!35yk1aS)FMG?0{ z)P96n0^r;WaRrp zcy)b@w-qQei_F3@*E)%1)!ky3b;B@qOh3W?7BC%C#SPS3z;sO6CMSCO9n-F^L{Z1o z9EoOt-!bJGv2&6qRxc6ePO)S79HP zylUSmkT*rB_I(WUp$N5vZ(?9y0rX{>2(HF#uAAVQOVDMmH>x|XuP;=9Sx(Z5S`Va-2u&uNZA{@?7pStkH^lFHmJ>21 z-_!|IW&bjZrt{`>2Hs=%Xa=^?n zJA$+qp*dzBkY0fCx}t^(6eQ-ESHr$i^78svkTD|U^{F5?h>+J~sbIGOZu6af2RP}u zXlnPJ#wa~yR3kU@AsMBv`W|HOR&42A4zg5)^gaTzR)q9E2C@xs5Bh3*6V)F9>e9*a zwGK{f>t_CyP`ek|rxaOgkAS=?LTcXwc}s+;q#$1bZbQ>umx`sIVOrS4sMJ%|c62j0 zsZ076&dt0XVG$AMfcLU!K-a-#^DeLF}D zVDkRs%HUALa?&h1*0{f~jK7bmvE)vQl@7WA?Q^53|9YETNQ196rq$gk|%8DGa z6gkmzUIlB2WRq%8Ue|(+7NwHB5#)LiD#=+OGXb~tsv;BR`liVAWb$Aw4W%6EgFzaP z79u-eku_1?3bGk6<55$j`R#R{{&>_;Q8XUyLE=fkACGz&G2NXQj7KlSdJ!-aiFvim?+<{+8=%ft&abGAX=*PNun|LAl9x>cEi3zQ+xLw zBVT~2Oqn1VB2)xrK}w5I5mX1M3b-GwHr+@}U8I>4mo|%(da7~W6Usay)vDJGk*_ZW zs@E+*@&Qw?B^|O7aT4{q3+zskSH12B(no|$84fa3giM(TGCs`1tyMTD=4+pS@bXfE zd97nTN*=d{B7ew`%ZPC+!qXJJ9mEol`v5C_7TF(TBIqgWSA;S*^dpjHf*X-puShE( zc7Z%DLNmdAAkP6ND~cL2YEY2R{owxD!Nc%hQUvAYO^_2Jl$Q@d-WQ>~dr z(gReiR=Q@=D@_-zrz~3=$}FZ`YM`xXPvBKr9iRLH)n?`D`1}``eLlZBzUc*iiLM42)WEhah+q~!LyOmH zPpct3|Kn-@)Te*fYtjT>a7WNb+SV>SG1)6yX#}RvB(w|mRFr}9AvQkFKm|BUA)edG zuTcQbT8OMC*dy2lvHiLjQwyl4f!t?cg%9z#`$^W7fbemM?I2qLQyV9lWc4JER@YGW zGXqFkwee|0_5h|fz5sF%FfNp|YbD|&YU5GZN1o)XY*WndLcI-`V*U)|QxS6E4i9-cdL=pGmj$aky;s1vx9dLi3hDhc8^)ge7(q*m^D- zFbbP;Bl`5WFiyI!48#-5BHo-p_su>dw0Ni4^ks*_@@732-~STpDSsB0UIAa-k~tSO zp8YL4XY!O3s{Hv7vaLPb)nsT1V2%%c0dfW~Cx)h&4YjGrFUuGv@g0aae}VM_z(~wC z8t+0PKT;lvm=PHVdn90aGvR9|w>3QF@^8Dj+RSw)Q3n5Wuh(q#ntkXY3^=?dkjSFQ z(n#h7{i$8{-ELa|o>P;GR1bPhduz#v3hfdU7Q~PPR~M^lL| zTV)}_aKkgh^g}Nvq*fuZ0qOo{q&?-ZvZLzrDr<%r$Vbbbt5vnAFXN0jHoSOh-`t zF$T!gIl#QETmbnIh?%z) zKCQL>gff#7#dQlbB;Hseh@=5#PLc~!LWHJ%RX{3<(43?JNIf8!N_M2FI+mVPH0xV8 zv-EJR(NwYpLisOym-q@hLv;j#HAEgJ1^TjJBFK0VIx#UFWEx;Hs;D6=p&)T$VlM1EC9gT|B9Qw;D5EPu9u{HV z&9{JU0^BdmBsUwwQY#H%_|yA&D$_6g7VK3GD*Aq2`)IVXGh%JL_fg){FRqPGILe`r z(7O12NBP;rvg_hI#DCbxh zmoh9In7|ef({9I#yiMl4vi4|-$l~R8AC^Cyj+rYVq$OWK9?wa_nm$TX zFJ$f0Q1*F=srtIF^74b2F*gUIIAF}J2vR|WYHw|jT7cVVO}yd>Ry%4KZF=eewf#vb z;v00_$P-gQCW(+IW`f)*LRp&+G7oSw9`oPJ zQO~Q#S$eG>F+`R&vdaDmX-=*5;kcrebPd(0tMXy>eA}{Sc#-I}*u03)hf%dex+g*$ z1KB5HIz+wKSlI=fIS_L|rUBuV5T`)i6tNj1_HVEcL_G;r>2*$Y0O`8;YKbXaJz27_ zeh(F!IEGZUUeXkiCV*Kl=?u~lFzY4Djg@+aiL=LhT`fm5_P$8;2K@DsM~v7QGSeei zFc}T+8o*4%cNq3`*wZ4-m8hobcfySU-a)wP`>VlG!!0=0`RW?8(^%G1d`a~Gn?!xf zJ+mgh^37OxxNb$Vqm4fye*P(qCVD=ezG6Hd*7|$$nQn1hXOyR)fOb^5H z<^_qJ3KC0nF5aPS@vXG2c3-840j~L^ONGk;iXt5xy;py=FE%l zL?otA=suKRq5q{YUG&(_mx~;w zAc2PZ0JXi>^jG3Ki><6AT&zFadgyh_>g1(6xr9_evK-)4X$e&qtcIxi5LbY77ttJI zFvvg=ogv16i~z#@AZCEveAJ82Jry0~)VwSH;VFK7O?j#6byr>%!@mbe-L}-Rs(DQx z$A&%7k1OmO?!l?YIto<5%w4K&kB2(i#%%jay5?8qXOmw+ge^T z<*y}lGoai!tBx0WTsI63f$Rlj>-xF6{x`ReLdO-xH@8+jKkOLvYry4qQ7YLg#|B>3 zL3Dmk;Md2z`2M$|*TmlCbMem=T7?gUd1>PVVU?%(K)AHmPWg0?)4dVL_^ga~xui=G zRva)sE9*f7C-Cj)e|$MI-BV=R{lfE zcQgoB9nJFU%ZIuGuoFK!o}ma+AEOo{A9CSJ&r5<0K#Y z+2AqZ$xqCRfBFvJ5^SK-918i?X#_Kh4uwn$3rW$T(3J&>4ux(qie%A0Lk�s>we? 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