mirror of
https://github.com/bybrooklyn/openbitdo.git
synced 2026-03-19 12:12:57 -04:00
release prep: rc.1 baseline and gating updates
This commit is contained in:
@@ -20,10 +20,30 @@ pub enum CommandId {
|
||||
ExitBootloader,
|
||||
FirmwareChunk,
|
||||
FirmwareCommit,
|
||||
Jp108ReadDedicatedMappings,
|
||||
Jp108WriteDedicatedMapping,
|
||||
Jp108ReadFeatureFlags,
|
||||
Jp108WriteFeatureFlags,
|
||||
Jp108ReadVoice,
|
||||
Jp108WriteVoice,
|
||||
U2GetCurrentSlot,
|
||||
U2ReadConfigSlot,
|
||||
U2WriteConfigSlot,
|
||||
U2ReadButtonMap,
|
||||
U2WriteButtonMap,
|
||||
U2SetMode,
|
||||
Jp108EnterBootloader,
|
||||
Jp108FirmwareChunk,
|
||||
Jp108FirmwareCommit,
|
||||
Jp108ExitBootloader,
|
||||
U2EnterBootloader,
|
||||
U2FirmwareChunk,
|
||||
U2FirmwareCommit,
|
||||
U2ExitBootloader,
|
||||
}
|
||||
|
||||
impl CommandId {
|
||||
pub const ALL: [CommandId; 17] = [
|
||||
pub const ALL: [CommandId; 37] = [
|
||||
CommandId::GetPid,
|
||||
CommandId::GetReportRevision,
|
||||
CommandId::GetMode,
|
||||
@@ -41,6 +61,26 @@ impl CommandId {
|
||||
CommandId::ExitBootloader,
|
||||
CommandId::FirmwareChunk,
|
||||
CommandId::FirmwareCommit,
|
||||
CommandId::Jp108ReadDedicatedMappings,
|
||||
CommandId::Jp108WriteDedicatedMapping,
|
||||
CommandId::Jp108ReadFeatureFlags,
|
||||
CommandId::Jp108WriteFeatureFlags,
|
||||
CommandId::Jp108ReadVoice,
|
||||
CommandId::Jp108WriteVoice,
|
||||
CommandId::U2GetCurrentSlot,
|
||||
CommandId::U2ReadConfigSlot,
|
||||
CommandId::U2WriteConfigSlot,
|
||||
CommandId::U2ReadButtonMap,
|
||||
CommandId::U2WriteButtonMap,
|
||||
CommandId::U2SetMode,
|
||||
CommandId::Jp108EnterBootloader,
|
||||
CommandId::Jp108FirmwareChunk,
|
||||
CommandId::Jp108FirmwareCommit,
|
||||
CommandId::Jp108ExitBootloader,
|
||||
CommandId::U2EnterBootloader,
|
||||
CommandId::U2FirmwareChunk,
|
||||
CommandId::U2FirmwareCommit,
|
||||
CommandId::U2ExitBootloader,
|
||||
];
|
||||
|
||||
pub fn all() -> &'static [CommandId] {
|
||||
|
||||
82
sdk/crates/bitdo_proto/src/command_registry_table.rs
Normal file
82
sdk/crates/bitdo_proto/src/command_registry_table.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
// Hardcoded command declaration table.
|
||||
//
|
||||
// Policy model:
|
||||
// - Confirmed commands can be enabled by default.
|
||||
// - Inferred safe reads can run only behind experimental/advanced mode.
|
||||
// - Inferred writes and unsafe paths stay blocked until confirmed.
|
||||
pub const COMMAND_REGISTRY: &[crate::registry::CommandRegistryRow] = &[
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetReportRevision, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x04;byte5=0x01", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetModeAlt, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetSuperButton, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::SetModeDInput, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 0, 81, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Idle, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Version, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte1=0x22", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::ReadProfile, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 6, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::WriteProfile, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 7, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::EnterBootloaderA, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[5, 0, 80, 1, 0, 0], expected_response: "none", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::EnterBootloaderB, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[0, 81, 0, 0, 0, 0], expected_response: "none", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::EnterBootloaderC, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[0, 80, 0, 0, 0], expected_response: "none", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::ExitBootloader, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[5, 0, 81, 1, 0, 0], expected_response: "none", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::FirmwareChunk, safety_class: crate::types::SafetyClass::UnsafeFirmware, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::FirmwareCommit, safety_class: crate::types::SafetyClass::UnsafeFirmware, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[], operation_group: "Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108ReadDedicatedMappings, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 48, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[21001, 21002], operation_group: "JP108Dedicated" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108WriteDedicatedMapping, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 49, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[21001, 21002], operation_group: "JP108Dedicated" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108ReadFeatureFlags, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 50, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[21001, 21002], operation_group: "JP108Dedicated" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108WriteFeatureFlags, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 51, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[21001, 21002], operation_group: "JP108Dedicated" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108ReadVoice, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 52, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[21001, 21002], operation_group: "JP108Dedicated" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108WriteVoice, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 53, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[21001, 21002], operation_group: "JP108Dedicated" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2GetCurrentSlot, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 64, 18, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[24594, 24595], operation_group: "Ultimate2Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2ReadConfigSlot, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 65, 18, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[24594, 24595], operation_group: "Ultimate2Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2WriteConfigSlot, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 66, 18, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[24594, 24595], operation_group: "Ultimate2Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2ReadButtonMap, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 67, 18, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[24594, 24595], operation_group: "Ultimate2Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2WriteButtonMap, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 68, 18, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[24594, 24595], operation_group: "Ultimate2Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2SetMode, safety_class: crate::types::SafetyClass::SafeWrite, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 5, 69, 18, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[24594, 24595], operation_group: "Ultimate2Core" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108EnterBootloader, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[5, 0, 80, 1, 0, 0], expected_response: "none", applies_to: &[21001, 21002], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108FirmwareChunk, safety_class: crate::types::SafetyClass::UnsafeFirmware, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 96, 16, 32, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[21001, 21002], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108FirmwareCommit, safety_class: crate::types::SafetyClass::UnsafeFirmware, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 96, 17, 32, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[21001, 21002], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::Jp108ExitBootloader, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[5, 0, 81, 1, 0, 0], expected_response: "none", applies_to: &[21001, 21002], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2EnterBootloader, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[5, 0, 80, 1, 0, 0], expected_response: "none", applies_to: &[24594, 24595], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2FirmwareChunk, safety_class: crate::types::SafetyClass::UnsafeFirmware, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 96, 16, 96, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[24594, 24595], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2FirmwareCommit, safety_class: crate::types::SafetyClass::UnsafeFirmware, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[129, 96, 17, 96, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02", applies_to: &[24594, 24595], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::U2ExitBootloader, safety_class: crate::types::SafetyClass::UnsafeBoot, confidence: crate::types::CommandConfidence::Inferred, experimental_default: true, report_id: 129, request: &[5, 0, 81, 1, 0, 0], expected_response: "none", applies_to: &[24594, 24595], operation_group: "Firmware" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[12544], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[12544], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[12544], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[12549], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[12549], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[12549], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[8448], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[8448], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[8448], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[8449], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[8449], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[8449], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[36890], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[36890], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[36890], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[24582], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[24582], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[24582], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[20995], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[20995], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[20995], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[20996], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[20996], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[20996], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[12314], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[12314], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[12314], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[36904], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[36904], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[36904], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[12326], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[12326], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[12326], operation_group: "FirmwarePreflight" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetPid, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 5, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05;byte4=0xC1", applies_to: &[12327], operation_group: "CoreDiag" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetMode, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x05", applies_to: &[12327], operation_group: "ModeProfileRead" },
|
||||
crate::registry::CommandRegistryRow { id: crate::command::CommandId::GetControllerVersion, safety_class: crate::types::SafetyClass::SafeRead, confidence: crate::types::CommandConfidence::Confirmed, experimental_default: false, report_id: 129, request: &[129, 4, 33, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], expected_response: "byte0=0x02;byte1=0x22", applies_to: &[12327], operation_group: "FirmwarePreflight" },
|
||||
]
|
||||
;
|
||||
@@ -1,5 +1,3 @@
|
||||
#![cfg(feature = "hidapi-backend")]
|
||||
|
||||
use crate::error::{BitdoError, Result};
|
||||
use crate::transport::Transport;
|
||||
use crate::types::VidPid;
|
||||
|
||||
@@ -21,10 +21,11 @@ pub use registry::{
|
||||
};
|
||||
pub use session::{
|
||||
validate_response, CommandExecutionReport, DeviceSession, DiagCommandStatus, DiagProbeResult,
|
||||
FirmwareTransferReport, IdentifyResult, ModeState, RetryPolicy, SessionConfig, TimeoutProfile,
|
||||
DiagSeverity, FirmwareTransferReport, IdentifyResult, ModeState, RetryPolicy, SessionConfig,
|
||||
TimeoutProfile,
|
||||
};
|
||||
pub use transport::{MockTransport, Transport};
|
||||
pub use types::{
|
||||
CommandConfidence, DeviceProfile, PidCapability, ProtocolFamily, SafetyClass, SupportEvidence,
|
||||
SupportLevel, VidPid,
|
||||
CommandConfidence, CommandRuntimePolicy, DeviceProfile, EvidenceConfidence, PidCapability,
|
||||
ProtocolFamily, SafetyClass, SupportEvidence, SupportLevel, SupportTier, VidPid,
|
||||
};
|
||||
|
||||
68
sdk/crates/bitdo_proto/src/pid_registry_table.rs
Normal file
68
sdk/crates/bitdo_proto/src/pid_registry_table.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
// Hardcoded PID registry.
|
||||
//
|
||||
// Design note:
|
||||
// - Every known PID from sanitized evidence/spec is declared here.
|
||||
// - Declaration breadth is broad, but runtime execution remains conservative
|
||||
// through session/runtime policy gates in `session.rs`.
|
||||
// - PID values are unique here by policy; legacy aliases are documented in
|
||||
// `spec/alias_index.md` instead of duplicated in runtime tables.
|
||||
pub const PID_REGISTRY: &[crate::registry::PidRegistryRow] = &[
|
||||
crate::registry::PidRegistryRow { name: "PID_None", pid: 0, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Unknown },
|
||||
crate::registry::PidRegistryRow { name: "PID_IDLE", pid: 12553, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_SN30Plus", pid: 24578, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_USB_Ultimate", pid: 12544, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_USB_Ultimate2", pid: 12549, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_USB_UltimateClasses", pid: 12548, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Xcloud", pid: 8448, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Xcloud2", pid: 8449, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_ArcadeStick", pid: 36890, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Pro2", pid: 24579, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Pro2_CY", pid: 24582, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Pro2_Wired", pid: 12304, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Ultimate_PC", pid: 12305, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Ultimate2_4", pid: 12306, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Ultimate2_4RR", pid: 12307, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_UltimateBT", pid: 24583, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_UltimateBTRR", pid: 12550, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_JP", pid: 20992, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_JPUSB", pid: 20993, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_NUMPAD", pid: 20995, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_NUMPADRR", pid: 20996, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_QINGCHUN2", pid: 12554, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_QINGCHUN2RR", pid: 12316, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_Xinput", pid: 12555, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_Pro3", pid: 24585, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_Pro3USB", pid: 24586, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_Pro3DOCK", pid: 24589, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_108JP", pid: 21001, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_108JPUSB", pid: 21002, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_XBOXJP", pid: 8232, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_XBOXJPUSB", pid: 8238, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_NGCDIY", pid: 22352, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_NGCRR", pid: 36906, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Ultimate2", pid: 24594, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_Ultimate2RR", pid: 24595, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_UltimateBT2", pid: 24591, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_UltimateBT2RR", pid: 24593, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_Mouse", pid: 20997, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_MouseRR", pid: 20998, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_SaturnRR", pid: 36907, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_UltimateBT2C", pid: 12314, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Lashen", pid: 12318, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_HitBox", pid: 24587, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_HitBoxRR", pid: 24588, support_level: crate::types::SupportLevel::Full, support_tier: crate::types::SupportTier::Full, protocol_family: crate::types::ProtocolFamily::DInput },
|
||||
crate::registry::PidRegistryRow { name: "PID_N64BT", pid: 12313, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_N64", pid: 12292, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_N64RR", pid: 36904, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_XBOXUK", pid: 12326, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_XBOXUKUSB", pid: 12327, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_LashenX", pid: 8203, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_68JP", pid: 8250, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_68JPUSB", pid: 8265, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::CandidateReadOnly, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
crate::registry::PidRegistryRow { name: "PID_N64JoySticks", pid: 12321, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_DoubleSuper", pid: 8254, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Cube2RR", pid: 8278, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_Cube2", pid: 8249, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::Standard64 },
|
||||
crate::registry::PidRegistryRow { name: "PID_ASLGJP", pid: 8282, support_level: crate::types::SupportLevel::DetectOnly, support_tier: crate::types::SupportTier::DetectOnly, protocol_family: crate::types::ProtocolFamily::JpHandshake },
|
||||
]
|
||||
;
|
||||
@@ -1,14 +1,17 @@
|
||||
use crate::command::CommandId;
|
||||
use crate::types::{
|
||||
CommandConfidence, DeviceProfile, PidCapability, ProtocolFamily, SafetyClass, SupportEvidence,
|
||||
SupportLevel, VidPid,
|
||||
CommandConfidence, CommandRuntimePolicy, DeviceProfile, EvidenceConfidence, PidCapability,
|
||||
ProtocolFamily, SafetyClass, SupportEvidence, SupportLevel, SupportTier, VidPid,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct PidRegistryRow {
|
||||
pub name: &'static str,
|
||||
pub pid: u16,
|
||||
pub support_level: SupportLevel,
|
||||
pub support_tier: SupportTier,
|
||||
pub protocol_family: ProtocolFamily,
|
||||
}
|
||||
|
||||
@@ -21,12 +24,43 @@ pub struct CommandRegistryRow {
|
||||
pub report_id: u8,
|
||||
pub request: &'static [u8],
|
||||
pub expected_response: &'static str,
|
||||
pub applies_to: &'static [u16],
|
||||
pub operation_group: &'static str,
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/generated_pid_registry.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/generated_command_registry.rs"));
|
||||
// Registry data is intentionally hardcoded in source files so support coverage
|
||||
// is explicit in Rust code and does not depend on build-time CSV generation.
|
||||
include!("pid_registry_table.rs");
|
||||
include!("command_registry_table.rs");
|
||||
|
||||
impl CommandRegistryRow {
|
||||
/// Convert evidence confidence into a stable reporting enum.
|
||||
pub fn evidence_confidence(&self) -> EvidenceConfidence {
|
||||
match self.confidence {
|
||||
CommandConfidence::Confirmed => EvidenceConfidence::Confirmed,
|
||||
CommandConfidence::Inferred => EvidenceConfidence::Inferred,
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime policy used by the session gate checker.
|
||||
///
|
||||
/// Policy rationale:
|
||||
/// - Confirmed paths are enabled by default.
|
||||
/// - Inferred safe reads can run only when experimental mode is enabled.
|
||||
/// - Inferred write/unsafe paths stay blocked until explicit confirmation.
|
||||
pub fn runtime_policy(&self) -> CommandRuntimePolicy {
|
||||
match (self.confidence, self.safety_class) {
|
||||
(CommandConfidence::Confirmed, _) => CommandRuntimePolicy::EnabledDefault,
|
||||
(CommandConfidence::Inferred, SafetyClass::SafeRead) => {
|
||||
CommandRuntimePolicy::ExperimentalGate
|
||||
}
|
||||
(CommandConfidence::Inferred, _) => CommandRuntimePolicy::BlockedUntilConfirmed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pid_registry() -> &'static [PidRegistryRow] {
|
||||
ensure_unique_pid_rows();
|
||||
PID_REGISTRY
|
||||
}
|
||||
|
||||
@@ -35,27 +69,133 @@ pub fn command_registry() -> &'static [CommandRegistryRow] {
|
||||
}
|
||||
|
||||
pub fn find_pid(pid: u16) -> Option<&'static PidRegistryRow> {
|
||||
PID_REGISTRY.iter().find(|row| row.pid == pid)
|
||||
pid_registry().iter().find(|row| row.pid == pid)
|
||||
}
|
||||
|
||||
pub fn find_command(id: CommandId) -> Option<&'static CommandRegistryRow> {
|
||||
COMMAND_REGISTRY.iter().find(|row| row.id == id)
|
||||
}
|
||||
|
||||
pub fn command_applies_to_pid(row: &CommandRegistryRow, pid: u16) -> bool {
|
||||
row.applies_to.is_empty() || row.applies_to.contains(&pid)
|
||||
}
|
||||
|
||||
pub fn default_capability_for(
|
||||
support_level: SupportLevel,
|
||||
_protocol_family: ProtocolFamily,
|
||||
pid: u16,
|
||||
support_tier: SupportTier,
|
||||
protocol_family: ProtocolFamily,
|
||||
) -> PidCapability {
|
||||
match support_level {
|
||||
SupportLevel::Full => PidCapability::full(),
|
||||
SupportLevel::DetectOnly => PidCapability::identify_only(),
|
||||
if support_tier == SupportTier::DetectOnly {
|
||||
return PidCapability::identify_only();
|
||||
}
|
||||
|
||||
const STANDARD_CANDIDATE_READ_DIAG_PIDS: &[u16] = &[
|
||||
0x6002, 0x6003, 0x3010, 0x3011, 0x3012, 0x3013, 0x3004, 0x3019, 0x3100, 0x3105, 0x2100,
|
||||
0x2101, 0x901a, 0x6006, 0x5203, 0x5204, 0x301a, 0x9028, 0x3026, 0x3027,
|
||||
];
|
||||
const JP_CANDIDATE_DIAG_PIDS: &[u16] = &[0x5200, 0x5201, 0x203a, 0x2049, 0x2028, 0x202e];
|
||||
|
||||
match (support_tier, pid) {
|
||||
(SupportTier::CandidateReadOnly, 0x6002)
|
||||
| (SupportTier::CandidateReadOnly, 0x6003)
|
||||
| (SupportTier::CandidateReadOnly, 0x3010)
|
||||
| (SupportTier::CandidateReadOnly, 0x3011)
|
||||
| (SupportTier::CandidateReadOnly, 0x3012)
|
||||
| (SupportTier::CandidateReadOnly, 0x3013)
|
||||
| (SupportTier::CandidateReadOnly, 0x3004)
|
||||
| (SupportTier::CandidateReadOnly, 0x3019)
|
||||
| (SupportTier::CandidateReadOnly, 0x3100)
|
||||
| (SupportTier::CandidateReadOnly, 0x3105)
|
||||
| (SupportTier::CandidateReadOnly, 0x2100)
|
||||
| (SupportTier::CandidateReadOnly, 0x2101)
|
||||
| (SupportTier::CandidateReadOnly, 0x901a)
|
||||
| (SupportTier::CandidateReadOnly, 0x6006)
|
||||
| (SupportTier::CandidateReadOnly, 0x5203)
|
||||
| (SupportTier::CandidateReadOnly, 0x5204)
|
||||
| (SupportTier::CandidateReadOnly, 0x301a)
|
||||
| (SupportTier::CandidateReadOnly, 0x9028)
|
||||
| (SupportTier::CandidateReadOnly, 0x3026)
|
||||
| (SupportTier::CandidateReadOnly, 0x3027) => PidCapability {
|
||||
supports_mode: true,
|
||||
supports_profile_rw: true,
|
||||
supports_boot: false,
|
||||
supports_firmware: false,
|
||||
supports_jp108_dedicated_map: false,
|
||||
supports_u2_slot_config: false,
|
||||
supports_u2_button_map: false,
|
||||
},
|
||||
(SupportTier::CandidateReadOnly, 0x5200)
|
||||
| (SupportTier::CandidateReadOnly, 0x5201)
|
||||
| (SupportTier::CandidateReadOnly, 0x203a)
|
||||
| (SupportTier::CandidateReadOnly, 0x2049)
|
||||
| (SupportTier::CandidateReadOnly, 0x2028)
|
||||
| (SupportTier::CandidateReadOnly, 0x202e) => PidCapability {
|
||||
supports_mode: false,
|
||||
supports_profile_rw: false,
|
||||
supports_boot: false,
|
||||
supports_firmware: false,
|
||||
supports_jp108_dedicated_map: false,
|
||||
supports_u2_slot_config: false,
|
||||
supports_u2_button_map: false,
|
||||
},
|
||||
(SupportTier::CandidateReadOnly, _) if STANDARD_CANDIDATE_READ_DIAG_PIDS.contains(&pid) => {
|
||||
PidCapability {
|
||||
supports_mode: true,
|
||||
supports_profile_rw: true,
|
||||
supports_boot: false,
|
||||
supports_firmware: false,
|
||||
supports_jp108_dedicated_map: false,
|
||||
supports_u2_slot_config: false,
|
||||
supports_u2_button_map: false,
|
||||
}
|
||||
}
|
||||
(SupportTier::CandidateReadOnly, _) if JP_CANDIDATE_DIAG_PIDS.contains(&pid) => {
|
||||
PidCapability {
|
||||
supports_mode: false,
|
||||
supports_profile_rw: false,
|
||||
supports_boot: false,
|
||||
supports_firmware: false,
|
||||
supports_jp108_dedicated_map: false,
|
||||
supports_u2_slot_config: false,
|
||||
supports_u2_button_map: false,
|
||||
}
|
||||
}
|
||||
(_, 0x5209) | (_, 0x520a) => PidCapability {
|
||||
supports_mode: false,
|
||||
supports_profile_rw: false,
|
||||
supports_boot: true,
|
||||
supports_firmware: true,
|
||||
supports_jp108_dedicated_map: true,
|
||||
supports_u2_slot_config: false,
|
||||
supports_u2_button_map: false,
|
||||
},
|
||||
(_, 0x6012) | (_, 0x6013) => PidCapability {
|
||||
supports_mode: true,
|
||||
supports_profile_rw: true,
|
||||
supports_boot: true,
|
||||
supports_firmware: true,
|
||||
supports_jp108_dedicated_map: false,
|
||||
supports_u2_slot_config: true,
|
||||
supports_u2_button_map: true,
|
||||
},
|
||||
_ => {
|
||||
let mut cap = PidCapability::full();
|
||||
if protocol_family == ProtocolFamily::JpHandshake {
|
||||
cap.supports_mode = false;
|
||||
cap.supports_profile_rw = false;
|
||||
}
|
||||
cap.supports_jp108_dedicated_map = false;
|
||||
cap.supports_u2_slot_config = false;
|
||||
cap.supports_u2_button_map = false;
|
||||
cap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_evidence_for(support_level: SupportLevel) -> SupportEvidence {
|
||||
match support_level {
|
||||
SupportLevel::Full => SupportEvidence::Confirmed,
|
||||
SupportLevel::DetectOnly => SupportEvidence::Inferred,
|
||||
pub fn default_evidence_for(support_tier: SupportTier) -> SupportEvidence {
|
||||
match support_tier {
|
||||
SupportTier::Full => SupportEvidence::Confirmed,
|
||||
SupportTier::CandidateReadOnly | SupportTier::DetectOnly => SupportEvidence::Inferred,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,18 +205,35 @@ pub fn device_profile_for(vid_pid: VidPid) -> DeviceProfile {
|
||||
vid_pid,
|
||||
name: row.name.to_owned(),
|
||||
support_level: row.support_level,
|
||||
support_tier: row.support_tier,
|
||||
protocol_family: row.protocol_family,
|
||||
capability: default_capability_for(row.support_level, row.protocol_family),
|
||||
evidence: default_evidence_for(row.support_level),
|
||||
capability: default_capability_for(row.pid, row.support_tier, row.protocol_family),
|
||||
evidence: default_evidence_for(row.support_tier),
|
||||
}
|
||||
} else {
|
||||
DeviceProfile {
|
||||
vid_pid,
|
||||
name: "PID_UNKNOWN".to_owned(),
|
||||
support_level: SupportLevel::DetectOnly,
|
||||
support_tier: SupportTier::DetectOnly,
|
||||
protocol_family: ProtocolFamily::Unknown,
|
||||
capability: PidCapability::identify_only(),
|
||||
evidence: SupportEvidence::Untested,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_unique_pid_rows() {
|
||||
static CHECK: OnceLock<()> = OnceLock::new();
|
||||
CHECK.get_or_init(|| {
|
||||
let mut seen = HashSet::new();
|
||||
for row in PID_REGISTRY {
|
||||
assert!(
|
||||
seen.insert(row.pid),
|
||||
"duplicate pid in runtime registry: {:#06x} ({})",
|
||||
row.pid,
|
||||
row.name
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ use crate::command::CommandId;
|
||||
use crate::error::{BitdoError, BitdoErrorCode, Result};
|
||||
use crate::frame::{CommandFrame, ResponseFrame, ResponseStatus};
|
||||
use crate::profile::ProfileBlob;
|
||||
use crate::registry::{device_profile_for, find_command, find_pid, CommandRegistryRow};
|
||||
use crate::registry::{
|
||||
command_applies_to_pid, device_profile_for, find_command, find_pid, CommandRegistryRow,
|
||||
};
|
||||
use crate::transport::Transport;
|
||||
use crate::types::{
|
||||
CommandConfidence, DeviceProfile, PidCapability, ProtocolFamily, SafetyClass, SupportEvidence,
|
||||
SupportLevel, VidPid,
|
||||
CommandRuntimePolicy, DeviceProfile, EvidenceConfidence, PidCapability, ProtocolFamily,
|
||||
SafetyClass, SupportEvidence, SupportLevel, SupportTier, VidPid,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
@@ -83,15 +85,26 @@ pub struct CommandExecutionReport {
|
||||
pub struct DiagCommandStatus {
|
||||
pub command: CommandId,
|
||||
pub ok: bool,
|
||||
pub confidence: EvidenceConfidence,
|
||||
pub is_experimental: bool,
|
||||
pub severity: DiagSeverity,
|
||||
pub error_code: Option<BitdoErrorCode>,
|
||||
pub detail: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum DiagSeverity {
|
||||
Ok,
|
||||
Warning,
|
||||
NeedsAttention,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct DiagProbeResult {
|
||||
pub target: VidPid,
|
||||
pub profile_name: String,
|
||||
pub support_level: SupportLevel,
|
||||
pub support_tier: SupportTier,
|
||||
pub protocol_family: ProtocolFamily,
|
||||
pub capability: PidCapability,
|
||||
pub evidence: SupportEvidence,
|
||||
@@ -104,6 +117,7 @@ pub struct IdentifyResult {
|
||||
pub target: VidPid,
|
||||
pub profile_name: String,
|
||||
pub support_level: SupportLevel,
|
||||
pub support_tier: SupportTier,
|
||||
pub protocol_family: ProtocolFamily,
|
||||
pub capability: PidCapability,
|
||||
pub evidence: SupportEvidence,
|
||||
@@ -187,6 +201,7 @@ impl<T: Transport> DeviceSession<T> {
|
||||
target: self.target,
|
||||
profile_name: profile.name,
|
||||
support_level: profile.support_level,
|
||||
support_tier: profile.support_tier,
|
||||
protocol_family: profile.protocol_family,
|
||||
capability: profile.capability,
|
||||
evidence: profile.evidence,
|
||||
@@ -195,33 +210,66 @@ impl<T: Transport> DeviceSession<T> {
|
||||
}
|
||||
|
||||
pub fn diag_probe(&mut self) -> DiagProbeResult {
|
||||
let checks = [
|
||||
let target_pid = self.target.pid;
|
||||
let checks_to_run = [
|
||||
CommandId::GetPid,
|
||||
CommandId::GetReportRevision,
|
||||
CommandId::GetMode,
|
||||
CommandId::GetControllerVersion,
|
||||
// Inferred safe reads are intentionally included in diagnostics so
|
||||
// users always see signal quality, but results are labeled
|
||||
// experimental and only strict safety conditions escalate.
|
||||
CommandId::GetSuperButton,
|
||||
CommandId::ReadProfile,
|
||||
]
|
||||
.iter()
|
||||
.map(|cmd| match self.send_command(*cmd, None) {
|
||||
Ok(_) => DiagCommandStatus {
|
||||
command: *cmd,
|
||||
ok: true,
|
||||
error_code: None,
|
||||
detail: "ok".to_owned(),
|
||||
},
|
||||
Err(err) => DiagCommandStatus {
|
||||
command: *cmd,
|
||||
ok: false,
|
||||
error_code: Some(err.code()),
|
||||
detail: err.to_string(),
|
||||
},
|
||||
.filter_map(|cmd| {
|
||||
let row = find_command(*cmd)?;
|
||||
if row.safety_class != SafetyClass::SafeRead {
|
||||
return None;
|
||||
}
|
||||
if !command_applies_to_pid(row, target_pid) {
|
||||
return None;
|
||||
}
|
||||
Some((*cmd, row.runtime_policy(), row.evidence_confidence()))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut checks = Vec::with_capacity(checks_to_run.len());
|
||||
for (cmd, runtime_policy, confidence) in checks_to_run {
|
||||
match self.send_command(cmd, None) {
|
||||
Ok(_) => checks.push(DiagCommandStatus {
|
||||
command: cmd,
|
||||
ok: true,
|
||||
confidence,
|
||||
is_experimental: runtime_policy == CommandRuntimePolicy::ExperimentalGate,
|
||||
severity: DiagSeverity::Ok,
|
||||
error_code: None,
|
||||
detail: "ok".to_owned(),
|
||||
}),
|
||||
Err(err) => checks.push(DiagCommandStatus {
|
||||
command: cmd,
|
||||
ok: false,
|
||||
confidence,
|
||||
is_experimental: runtime_policy == CommandRuntimePolicy::ExperimentalGate,
|
||||
severity: classify_diag_failure(
|
||||
cmd,
|
||||
runtime_policy,
|
||||
confidence,
|
||||
err.code(),
|
||||
self.target.pid,
|
||||
),
|
||||
error_code: Some(err.code()),
|
||||
detail: err.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
DiagProbeResult {
|
||||
target: self.target,
|
||||
profile_name: self.profile.name.clone(),
|
||||
support_level: self.profile.support_level,
|
||||
support_tier: self.profile.support_tier,
|
||||
protocol_family: self.profile.protocol_family,
|
||||
capability: self.profile.capability,
|
||||
evidence: self.profile.evidence,
|
||||
@@ -290,6 +338,116 @@ impl<T: Transport> DeviceSession<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn jp108_read_dedicated_mappings(&mut self) -> Result<Vec<(u8, u16)>> {
|
||||
let resp = self.send_command(CommandId::Jp108ReadDedicatedMappings, None)?;
|
||||
Ok(parse_indexed_u16_table(&resp.raw, 10))
|
||||
}
|
||||
|
||||
pub fn jp108_write_dedicated_mapping(
|
||||
&mut self,
|
||||
index: u8,
|
||||
target_hid_usage: u16,
|
||||
) -> Result<()> {
|
||||
let row = self.ensure_command_allowed(CommandId::Jp108WriteDedicatedMapping)?;
|
||||
let mut payload = row.request.to_vec();
|
||||
if payload.len() < 7 {
|
||||
return Err(BitdoError::InvalidInput(
|
||||
"Jp108WriteDedicatedMapping payload shorter than expected".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
payload[4] = index;
|
||||
let usage = target_hid_usage.to_le_bytes();
|
||||
payload[5] = usage[0];
|
||||
payload[6] = usage[1];
|
||||
self.send_row(row, Some(&payload))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn u2_get_current_slot(&mut self) -> Result<u8> {
|
||||
let resp = self.send_command(CommandId::U2GetCurrentSlot, None)?;
|
||||
Ok(resp.parsed_fields.get("slot").copied().unwrap_or(0) as u8)
|
||||
}
|
||||
|
||||
pub fn u2_read_config_slot(&mut self, slot: u8) -> Result<Vec<u8>> {
|
||||
let row = self.ensure_command_allowed(CommandId::U2ReadConfigSlot)?;
|
||||
let mut payload = row.request.to_vec();
|
||||
if payload.len() > 4 {
|
||||
payload[4] = slot;
|
||||
}
|
||||
let resp = self.send_row(row, Some(&payload))?;
|
||||
Ok(resp.raw)
|
||||
}
|
||||
|
||||
pub fn u2_write_config_slot(&mut self, slot: u8, config_blob: &[u8]) -> Result<()> {
|
||||
let row = self.ensure_command_allowed(CommandId::U2WriteConfigSlot)?;
|
||||
let mut payload = row.request.to_vec();
|
||||
if payload.len() < 8 {
|
||||
return Err(BitdoError::InvalidInput(
|
||||
"U2WriteConfigSlot payload shorter than expected".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
payload[4] = slot;
|
||||
let copy_len = config_blob.len().min(payload.len().saturating_sub(8));
|
||||
if copy_len > 0 {
|
||||
payload[8..8 + copy_len].copy_from_slice(&config_blob[..copy_len]);
|
||||
}
|
||||
|
||||
self.send_row(row, Some(&payload))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn u2_read_button_map(&mut self, slot: u8) -> Result<Vec<(u8, u16)>> {
|
||||
let row = self.ensure_command_allowed(CommandId::U2ReadButtonMap)?;
|
||||
let mut payload = row.request.to_vec();
|
||||
if payload.len() > 4 {
|
||||
payload[4] = slot;
|
||||
}
|
||||
let resp = self.send_row(row, Some(&payload))?;
|
||||
Ok(parse_indexed_u16_table(&resp.raw, 17))
|
||||
}
|
||||
|
||||
pub fn u2_write_button_map(&mut self, slot: u8, mappings: &[(u8, u16)]) -> Result<()> {
|
||||
let row = self.ensure_command_allowed(CommandId::U2WriteButtonMap)?;
|
||||
let mut payload = row.request.to_vec();
|
||||
if payload.len() < 8 {
|
||||
return Err(BitdoError::InvalidInput(
|
||||
"U2WriteButtonMap payload shorter than expected".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
payload[4] = slot;
|
||||
for (index, usage) in mappings {
|
||||
let pos = 8usize.saturating_add((*index as usize).saturating_mul(2));
|
||||
if pos + 1 < payload.len() {
|
||||
let bytes = usage.to_le_bytes();
|
||||
payload[pos] = bytes[0];
|
||||
payload[pos + 1] = bytes[1];
|
||||
}
|
||||
}
|
||||
|
||||
self.send_row(row, Some(&payload))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn u2_set_mode(&mut self, mode: u8) -> Result<ModeState> {
|
||||
let row = self.ensure_command_allowed(CommandId::U2SetMode)?;
|
||||
let mut payload = row.request.to_vec();
|
||||
if payload.len() < 5 {
|
||||
return Err(BitdoError::InvalidInput(
|
||||
"U2SetMode payload shorter than expected".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
payload[4] = mode;
|
||||
self.send_row(row, Some(&payload))?;
|
||||
Ok(ModeState {
|
||||
mode,
|
||||
source: "U2SetMode".to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn enter_bootloader(&mut self) -> Result<()> {
|
||||
self.send_command(CommandId::EnterBootloaderA, None)?;
|
||||
self.send_command(CommandId::EnterBootloaderB, None)?;
|
||||
@@ -529,12 +687,28 @@ impl<T: Transport> DeviceSession<T> {
|
||||
fn ensure_command_allowed(&self, command: CommandId) -> Result<&'static CommandRegistryRow> {
|
||||
let row = find_command(command).ok_or(BitdoError::UnknownCommand(command))?;
|
||||
|
||||
if row.confidence == CommandConfidence::Inferred && !self.config.experimental {
|
||||
return Err(BitdoError::ExperimentalRequired { command });
|
||||
// Gate 1: confidence/runtime policy.
|
||||
// We intentionally keep inferred write/unsafe paths non-executable until
|
||||
// they are upgraded to confirmed evidence.
|
||||
match row.runtime_policy() {
|
||||
CommandRuntimePolicy::EnabledDefault => {}
|
||||
CommandRuntimePolicy::ExperimentalGate => {
|
||||
if !self.config.experimental {
|
||||
return Err(BitdoError::ExperimentalRequired { command });
|
||||
}
|
||||
}
|
||||
CommandRuntimePolicy::BlockedUntilConfirmed => {
|
||||
return Err(BitdoError::UnsupportedForPid {
|
||||
command,
|
||||
pid: self.target.pid,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Gate 2: PID/family/capability applicability.
|
||||
if !is_command_allowed_by_family(self.profile.protocol_family, command)
|
||||
|| !is_command_allowed_by_capability(self.profile.capability, command)
|
||||
|| !command_applies_to_pid(row, self.target.pid)
|
||||
{
|
||||
return Err(BitdoError::UnsupportedForPid {
|
||||
command,
|
||||
@@ -542,8 +716,19 @@ impl<T: Transport> DeviceSession<T> {
|
||||
});
|
||||
}
|
||||
|
||||
// Gate 3: support-tier restrictions.
|
||||
if self.profile.support_tier == SupportTier::CandidateReadOnly
|
||||
&& !is_command_allowed_for_candidate_pid(self.target.pid, command, row.safety_class)
|
||||
{
|
||||
return Err(BitdoError::UnsupportedForPid {
|
||||
command,
|
||||
pid: self.target.pid,
|
||||
});
|
||||
}
|
||||
|
||||
// Gate 4: explicit unsafe confirmation requirements.
|
||||
if row.safety_class.is_unsafe() {
|
||||
if self.profile.support_level != SupportLevel::Full {
|
||||
if self.profile.support_tier != SupportTier::Full {
|
||||
return Err(BitdoError::UnsupportedForPid {
|
||||
command,
|
||||
pid: self.target.pid,
|
||||
@@ -555,7 +740,7 @@ impl<T: Transport> DeviceSession<T> {
|
||||
}
|
||||
|
||||
if row.safety_class == SafetyClass::SafeWrite
|
||||
&& self.profile.support_level == SupportLevel::DetectOnly
|
||||
&& self.profile.support_tier != SupportTier::Full
|
||||
{
|
||||
return Err(BitdoError::UnsupportedForPid {
|
||||
command,
|
||||
@@ -567,6 +752,83 @@ impl<T: Transport> DeviceSession<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_diag_failure(
|
||||
command: CommandId,
|
||||
runtime_policy: CommandRuntimePolicy,
|
||||
confidence: EvidenceConfidence,
|
||||
code: BitdoErrorCode,
|
||||
pid: u16,
|
||||
) -> DiagSeverity {
|
||||
if runtime_policy != CommandRuntimePolicy::ExperimentalGate
|
||||
|| confidence != EvidenceConfidence::Inferred
|
||||
{
|
||||
return DiagSeverity::Warning;
|
||||
}
|
||||
|
||||
// Escalation is intentionally narrow for inferred checks:
|
||||
// - identity mismatch / impossible transitions
|
||||
// - command/schema applicability mismatch
|
||||
// - precondition/capability mismatches implied by unsupported errors
|
||||
let identity_or_transition_issue = matches!(
|
||||
(command, code),
|
||||
(CommandId::GetPid, BitdoErrorCode::InvalidResponse)
|
||||
| (CommandId::GetPid, BitdoErrorCode::MalformedResponse)
|
||||
| (CommandId::GetMode, BitdoErrorCode::InvalidResponse)
|
||||
| (CommandId::GetModeAlt, BitdoErrorCode::InvalidResponse)
|
||||
| (CommandId::ReadProfile, BitdoErrorCode::InvalidResponse)
|
||||
| (
|
||||
CommandId::GetControllerVersion,
|
||||
BitdoErrorCode::InvalidResponse
|
||||
)
|
||||
| (CommandId::Version, BitdoErrorCode::InvalidResponse)
|
||||
);
|
||||
if identity_or_transition_issue {
|
||||
return DiagSeverity::NeedsAttention;
|
||||
}
|
||||
|
||||
if code == BitdoErrorCode::UnsupportedForPid
|
||||
&& find_command(command)
|
||||
.map(|row| command_applies_to_pid(row, pid))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return DiagSeverity::NeedsAttention;
|
||||
}
|
||||
|
||||
DiagSeverity::Warning
|
||||
}
|
||||
|
||||
fn is_command_allowed_for_candidate_pid(pid: u16, command: CommandId, safety: SafetyClass) -> bool {
|
||||
if safety != SafetyClass::SafeRead {
|
||||
return false;
|
||||
}
|
||||
|
||||
const BASE_DIAG_READS: &[CommandId] = &[
|
||||
CommandId::GetPid,
|
||||
CommandId::GetReportRevision,
|
||||
CommandId::GetControllerVersion,
|
||||
CommandId::Version,
|
||||
CommandId::Idle,
|
||||
];
|
||||
const STANDARD_CANDIDATE_PIDS: &[u16] = &[
|
||||
0x6002, 0x6003, 0x3010, 0x3011, 0x3012, 0x3013, 0x3004, 0x3019, 0x3100, 0x3105, 0x2100,
|
||||
0x2101, 0x901a, 0x6006, 0x5203, 0x5204, 0x301a, 0x9028, 0x3026, 0x3027,
|
||||
];
|
||||
const JP_CANDIDATE_PIDS: &[u16] = &[0x5200, 0x5201, 0x203a, 0x2049, 0x2028, 0x202e];
|
||||
|
||||
if BASE_DIAG_READS.contains(&command) {
|
||||
return STANDARD_CANDIDATE_PIDS.contains(&pid) || JP_CANDIDATE_PIDS.contains(&pid);
|
||||
}
|
||||
|
||||
if STANDARD_CANDIDATE_PIDS.contains(&pid) {
|
||||
return matches!(
|
||||
command,
|
||||
CommandId::GetMode | CommandId::GetModeAlt | CommandId::ReadProfile
|
||||
);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn is_command_allowed_by_capability(cap: PidCapability, command: CommandId) -> bool {
|
||||
match command {
|
||||
CommandId::GetPid
|
||||
@@ -580,8 +842,29 @@ fn is_command_allowed_by_capability(cap: PidCapability, command: CommandId) -> b
|
||||
CommandId::EnterBootloaderA
|
||||
| CommandId::EnterBootloaderB
|
||||
| CommandId::EnterBootloaderC
|
||||
| CommandId::ExitBootloader => cap.supports_boot,
|
||||
CommandId::FirmwareChunk | CommandId::FirmwareCommit => cap.supports_firmware,
|
||||
| CommandId::ExitBootloader
|
||||
| CommandId::Jp108EnterBootloader
|
||||
| CommandId::Jp108ExitBootloader
|
||||
| CommandId::U2EnterBootloader
|
||||
| CommandId::U2ExitBootloader => cap.supports_boot,
|
||||
CommandId::FirmwareChunk
|
||||
| CommandId::FirmwareCommit
|
||||
| CommandId::Jp108FirmwareChunk
|
||||
| CommandId::Jp108FirmwareCommit
|
||||
| CommandId::U2FirmwareChunk
|
||||
| CommandId::U2FirmwareCommit => cap.supports_firmware,
|
||||
CommandId::Jp108ReadDedicatedMappings
|
||||
| CommandId::Jp108WriteDedicatedMapping
|
||||
| CommandId::Jp108ReadFeatureFlags
|
||||
| CommandId::Jp108WriteFeatureFlags
|
||||
| CommandId::Jp108ReadVoice
|
||||
| CommandId::Jp108WriteVoice => cap.supports_jp108_dedicated_map,
|
||||
CommandId::U2GetCurrentSlot
|
||||
| CommandId::U2ReadConfigSlot
|
||||
| CommandId::U2WriteConfigSlot => cap.supports_u2_slot_config,
|
||||
CommandId::U2ReadButtonMap | CommandId::U2WriteButtonMap | CommandId::U2SetMode => {
|
||||
cap.supports_u2_button_map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,6 +885,16 @@ fn is_command_allowed_by_family(family: ProtocolFamily, command: CommandId) -> b
|
||||
| CommandId::WriteProfile
|
||||
| CommandId::FirmwareChunk
|
||||
| CommandId::FirmwareCommit
|
||||
| CommandId::U2GetCurrentSlot
|
||||
| CommandId::U2ReadConfigSlot
|
||||
| CommandId::U2WriteConfigSlot
|
||||
| CommandId::U2ReadButtonMap
|
||||
| CommandId::U2WriteButtonMap
|
||||
| CommandId::U2SetMode
|
||||
| CommandId::U2EnterBootloader
|
||||
| CommandId::U2FirmwareChunk
|
||||
| CommandId::U2FirmwareCommit
|
||||
| CommandId::U2ExitBootloader
|
||||
),
|
||||
ProtocolFamily::DS4Boot => matches!(
|
||||
command,
|
||||
@@ -653,6 +946,21 @@ pub fn validate_response(command: CommandId, response: &[u8]) -> ResponseStatus
|
||||
ResponseStatus::Invalid
|
||||
}
|
||||
}
|
||||
CommandId::Jp108ReadDedicatedMappings
|
||||
| CommandId::Jp108ReadFeatureFlags
|
||||
| CommandId::Jp108ReadVoice
|
||||
| CommandId::U2ReadConfigSlot
|
||||
| CommandId::U2ReadButtonMap
|
||||
| CommandId::U2GetCurrentSlot => {
|
||||
if response.len() < 6 {
|
||||
return ResponseStatus::Malformed;
|
||||
}
|
||||
if response[0] == 0x02 && response[1] == 0x05 {
|
||||
ResponseStatus::Ok
|
||||
} else {
|
||||
ResponseStatus::Invalid
|
||||
}
|
||||
}
|
||||
CommandId::GetControllerVersion | CommandId::Version => {
|
||||
if response.len() < 5 {
|
||||
return ResponseStatus::Malformed;
|
||||
@@ -689,6 +997,12 @@ fn minimum_response_len(command: CommandId) -> usize {
|
||||
CommandId::GetPid => 24,
|
||||
CommandId::GetReportRevision => 6,
|
||||
CommandId::GetMode | CommandId::GetModeAlt => 6,
|
||||
CommandId::U2GetCurrentSlot => 6,
|
||||
CommandId::Jp108ReadDedicatedMappings
|
||||
| CommandId::Jp108ReadFeatureFlags
|
||||
| CommandId::Jp108ReadVoice
|
||||
| CommandId::U2ReadConfigSlot
|
||||
| CommandId::U2ReadButtonMap => 12,
|
||||
CommandId::GetControllerVersion | CommandId::Version => 5,
|
||||
_ => 2,
|
||||
}
|
||||
@@ -709,7 +1023,27 @@ fn parse_fields(command: CommandId, response: &[u8]) -> BTreeMap<String, u32> {
|
||||
parsed.insert("version_x100".to_owned(), fw);
|
||||
parsed.insert("beta".to_owned(), response[4] as u32);
|
||||
}
|
||||
CommandId::U2GetCurrentSlot if response.len() >= 6 => {
|
||||
parsed.insert("slot".to_owned(), response[5] as u32);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
parsed
|
||||
}
|
||||
|
||||
fn parse_indexed_u16_table(raw: &[u8], expected_items: usize) -> Vec<(u8, u16)> {
|
||||
let mut out = Vec::with_capacity(expected_items);
|
||||
let offset = if raw.len() >= 8 { 8 } else { 2 };
|
||||
|
||||
for idx in 0..expected_items {
|
||||
let pos = offset + idx * 2;
|
||||
let usage = if pos + 1 < raw.len() {
|
||||
u16::from_le_bytes([raw[pos], raw[pos + 1]])
|
||||
} else {
|
||||
0
|
||||
};
|
||||
out.push((idx as u8, usage));
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
@@ -50,6 +50,13 @@ pub enum SupportLevel {
|
||||
DetectOnly,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SupportTier {
|
||||
DetectOnly,
|
||||
CandidateReadOnly,
|
||||
Full,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SafetyClass {
|
||||
SafeRead,
|
||||
@@ -70,6 +77,24 @@ pub enum CommandConfidence {
|
||||
Inferred,
|
||||
}
|
||||
|
||||
/// Runtime execution policy for a declared command path.
|
||||
///
|
||||
/// This allows us to hardcode every evidenced command in the registry while
|
||||
/// still keeping unsafe or low-confidence paths blocked by default.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CommandRuntimePolicy {
|
||||
EnabledDefault,
|
||||
ExperimentalGate,
|
||||
BlockedUntilConfirmed,
|
||||
}
|
||||
|
||||
/// Evidence confidence used by policy/reporting surfaces.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum EvidenceConfidence {
|
||||
Confirmed,
|
||||
Inferred,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SupportEvidence {
|
||||
Confirmed,
|
||||
@@ -83,6 +108,9 @@ pub struct PidCapability {
|
||||
pub supports_profile_rw: bool,
|
||||
pub supports_boot: bool,
|
||||
pub supports_firmware: bool,
|
||||
pub supports_jp108_dedicated_map: bool,
|
||||
pub supports_u2_slot_config: bool,
|
||||
pub supports_u2_button_map: bool,
|
||||
}
|
||||
|
||||
impl PidCapability {
|
||||
@@ -92,6 +120,9 @@ impl PidCapability {
|
||||
supports_profile_rw: true,
|
||||
supports_boot: true,
|
||||
supports_firmware: true,
|
||||
supports_jp108_dedicated_map: true,
|
||||
supports_u2_slot_config: true,
|
||||
supports_u2_button_map: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +132,9 @@ impl PidCapability {
|
||||
supports_profile_rw: false,
|
||||
supports_boot: false,
|
||||
supports_firmware: false,
|
||||
supports_jp108_dedicated_map: false,
|
||||
supports_u2_slot_config: false,
|
||||
supports_u2_button_map: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,6 +144,7 @@ pub struct DeviceProfile {
|
||||
pub vid_pid: VidPid,
|
||||
pub name: String,
|
||||
pub support_level: SupportLevel,
|
||||
pub support_tier: SupportTier,
|
||||
pub protocol_family: ProtocolFamily,
|
||||
pub capability: PidCapability,
|
||||
pub evidence: SupportEvidence,
|
||||
|
||||
Reference in New Issue
Block a user