### StringRange::start Source: https://docs.rs/hidparser/latest/hidparser/report_data_types/struct.StringRange.html Returns the starting index of the range. ```APIDOC ## StringRange::start ### Description Returns the starting index of the range. ### Method pub fn start(&self) -> u32 ### Parameters None ### Returns - **u32** - The starting index of the range. ``` -------------------------------- ### Parse a HID Boot Keyboard Report Descriptor Source: https://docs.rs/hidparser This example demonstrates parsing a raw byte slice representing a boot keyboard report descriptor and verifying the structure of the resulting input and output reports. ```rust let BOOT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MAXIMUM (0) 0x25, 0x01, // LOGICAL_MINIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Const) (Reserved Byte) 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (1) 0x29, 0x05, // USAGE_MAXIMUM (5) 0x91, 0x02, // OUTPUT (Data, Var, Abs) (LED report) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x91, 0x02, // OUTPUT (Constant) (LED report padding) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 00, // LOGICAL_MAXIMUM (255) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0x00, // USAGE_MINIMUM (0) 0x2a, 0xff, 00, // USAGE_MAXIMUM (255) 0x81, 0x00, // INPUT (Data, Array) 0xc0, // END_COLLECTION ]; let descriptor = parse_report_descriptor(BOOT_KEYBOARD_REPORT_DESCRIPTOR).unwrap(); // singleton input/output reports with no report id. assert_eq!(descriptor.input_reports.len(), 1); assert_eq!(descriptor.output_reports.len(), 1); assert_eq!(descriptor.input_reports[0].report_id, None); assert_eq!(descriptor.output_reports[0].report_id, None); //Input report field[4] is right control - Usage Page 7, Usage 0xE4, occupying bit 4 of the input report. let ReportField::Variable(ref field) = descriptor.input_reports[0].fields[4] else {panic!("Unexpected field type.")}; let usage = Usage::from_page_and_id(Some(UsagePage::from(0x07)), Usage::from(0xe4)); assert_eq!(field.usage, usage); assert_eq!(field.bits, 4..5); //Input report field[8] is padding, occupying bit 8 through 15 of the input report. let ReportField::Padding(ref field) = descriptor.input_reports[0].fields[8] else {panic!("Unexpected field type.")}; assert_eq!(field.bits, 8..16); //Input report field[9] is the first keycode byte, occupying bit 16 through 23 of the input report. //The key code can have usages in Usage Page 7, in the range 0x00 to 0xFF let ReportField::Array(ref field) = descriptor.input_reports[0].fields[9] else {panic!("Unexpected field type.")}; assert_eq!(field.bits, 16..24); assert_eq!(field.usage_list, Vec::from([UsageRange::from(0x00070000..=0x000700ff)])); //Output report field[1] is caps lock - Usage Page 8, Usage 0x01, occupying bit 1 of the output report. let ReportField::Variable(ref field) = descriptor.output_reports[0].fields[1] else {panic!("Unexpected field type.")}; let usage = Usage::from_page_and_id(Some(UsagePage::from(0x08)), Usage::from(0x02)); assert_eq!(field.usage, usage); assert_eq!(field.bits, 1..2); ``` -------------------------------- ### Parse a boot keyboard report descriptor and inspect fields Source: https://docs.rs/hidparser/latest/index.html This example defines a boot keyboard report descriptor as a byte array, parses it with parse_report_descriptor, and asserts properties of the resulting input and output reports, including field types, usages, and bit ranges. It demonstrates usage of ReportField, Usage, UsagePage, and UsageRange types. ```rust let BOOT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MAXIMUM (0) 0x25, 0x01, // LOGICAL_MINIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Const) (Reserved Byte) 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (1) 0x29, 0x05, // USAGE_MAXIMUM (5) 0x91, 0x02, // OUTPUT (Data, Var, Abs) (LED report) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x91, 0x02, // OUTPUT (Constant) (LED report padding) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 00, // LOGICAL_MAXIMUM (255) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0x00, // USAGE_MINIMUM (0) 0x2a, 0xff, 00, // USAGE_MAXIMUM (255) 0x81, 0x00, // INPUT (Data, Array) 0xc0, // END_COLLECTION ]; let descriptor = parse_report_descriptor(BOOT_KEYBOARD_REPORT_DESCRIPTOR).unwrap(); // singleton input/output reports with no report id. assert_eq!(descriptor.input_reports.len(), 1); assert_eq!(descriptor.output_reports.len(), 1); assert_eq!(descriptor.input_reports[0].report_id, None); assert_eq!(descriptor.output_reports[0].report_id, None); //Input report field[4] is right control - Usage Page 7, Usage 0xE4, occupying bit 4 of the input report. let ReportField::Variable(ref field) = descriptor.input_reports[0].fields[4] else {panic!("Unexpected field type.")}; let usage = Usage::from_page_and_id(Some(UsagePage::from(0x07)), Usage::from(0xe4)); assert_eq!(field.usage, usage); assert_eq!(field.bits, 4..5); //Input report field[8] is padding, occupying bit 8 through 15 of the input report. let ReportField::Padding(ref field) = descriptor.input_reports[0].fields[8] else {panic!("Unexpected field type.")}; assert_eq!(field.bits, 8..16); //Input report field[9] is the first keycode byte, occupying bit 16 through 23 of the input report. //The key code can have usages in Usage Page 7, in the range 0x00 to 0xFF let ReportField::Array(ref field) = descriptor.input_reports[0].fields[9] else {panic!("Unexpected field type.")}; assert_eq!(field.bits, 16..24); assert_eq!(field.usage_list, Vec::from([UsageRange::from(0x00070000..=0x000700ff)])); //Output report field[1] is caps lock - Usage Page 8, Usage 0x01, occupying bit 1 of the output report. let ReportField::Variable(ref field) = descriptor.output_reports[0].fields[1] else {panic!("Unexpected field type.")}; let usage = Usage::from_page_and_id(Some(UsagePage::from(0x08)), Usage::from(0x02)); assert_eq!(field.usage, usage); assert_eq!(field.bits, 1..2); ``` -------------------------------- ### DesignatorRange::start Source: https://docs.rs/hidparser/latest/hidparser/report_data_types/struct.DesignatorRange.html Returns the start index of the designator range. ```APIDOC ## DesignatorRange::start ### Description Returns the start index of the designator range. ### Method pub fn start(&self) -> u32 ### Parameters None ### Returns u32 - The start index of the range. ``` -------------------------------- ### Retrieving field range Source: https://docs.rs/hidparser/latest/src/hidparser/lib.rs.html Example of initializing a VariableField for range retrieval. ```rust let mut field = VariableField { logical_minimum: LogicalMinimum::from(-127i32), logical_maximum: LogicalMaximum::from(127i32), ..Default::default() }; ``` -------------------------------- ### Usage::from_page_and_id Source: https://docs.rs/hidparser/latest/hidparser/report_data_types/struct.Usage.html Creates a Usage from an optional UsagePage and an id. ```APIDOC ## Usage::from_page_and_id ### Description Creates a Usage from the optional UsagePage and Id. ### Method `pub fn from_page_and_id(page: Option, id: Usage) -> Self` ### Parameters - `page` (Option) - Optional usage page. - `id` (Usage) - The usage id. ### Returns - `Self` - A new Usage instance. ``` -------------------------------- ### Test boot keyboard report descriptor parsing Source: https://docs.rs/hidparser/latest/src/hidparser/report_descriptor_parser.rs.html Defines a boot keyboard report descriptor and a test that parses it. The test verifies the input report has no report ID, 15 fields, and 64 bits, then checks the first 8 modifier fields for attributes, bit ranges, usages, and logical min/max values. ```rust static BOOT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Const) (Reserved Byte) 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (1) 0x29, 0x05, // USAGE_MAXIMUM (5) 0x91, 0x02, // OUTPUT (Data, Var, Abs) (LED report) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x91, 0x02, // OUTPUT (Constant) (LED report padding) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 00, // LOGICAL_MAXIMUM (255) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0x00, // USAGE_MINIMUM (0) 0x2a, 0xff, 00, // USAGE_MAXIMUM (255) 0x81, 0x00, // INPUT (Data, Array) 0xc0, // END_COLLECTION ]; ``` ```rust #[test] fn test_keyboard_report_descriptor() { let report_descriptor = ReportDescriptorParser::parse(BOOT_KEYBOARD_REPORT_DESCRIPTOR).unwrap(); // Verify input report assert_eq!(report_descriptor.input_reports.len(), 1); let report = &report_descriptor.input_reports[0]; assert_eq!(report.report_id, None); assert_eq!(report.fields.len(), 15); assert_eq!(report.size_in_bits, 64); // Modifier keys let mut bit: u32 = 0; for (field, usage) in report.fields[0..8].iter().zip(0xe0..0xe7) { let ReportField::Variable(field) = field else { panic!("Incorrect Field type") }; assert_eq!(field.attributes, ReportAttributes { variable: true, ..Default::default() }); assert_eq!(field.bits, bit..bit + 1); assert_eq!(field.usage, Usage::from_page_and_id(Some(UsagePage::from(0x07)), Usage::from(usage))); assert_eq!(field.logical_minimum, LogicalMinimum::from(0)); assert_eq!(field.logical_maximum, LogicalMaximum::from(1)); bit += 1; } } ``` -------------------------------- ### Setting field values in a buffer Source: https://docs.rs/hidparser/latest/src/hidparser/lib.rs.html Shows how to use set_field_value to write data into a buffer, including error handling for invalid buffer sizes or field values. ```rust let mut field = VariableField { logical_minimum: LogicalMinimum::from(0i32), logical_maximum: LogicalMaximum::from(0xffi32), ..Default::default() }; let mut buffer: [u8; 10] = [0x00; 10]; field.bits = 0..8; field.set_field_value(0xaai64, &mut buffer).unwrap(); assert_eq!(buffer[0], 0xaa); assert_eq!(buffer[1..], [0x0u8; 9]); let mut buffer: [u8; 10] = [0x00; 10]; field.bits = 4..12; field.set_field_value(0xaai64, &mut buffer).unwrap(); assert_eq!(buffer[0..2], [0xa0, 0x0a]); assert_eq!(buffer[2..], [0x0u8; 8]); let mut buffer: [u8; 1] = [0x00; 1]; field.bits = 4..12; assert_eq!(field.set_field_value(0xaa, &mut buffer), Err(FieldAccessError::InvalidBufferSize)); assert_eq!(field.set_field_value(0xaaa, &mut buffer), Err(FieldAccessError::InvalidFieldValue)); ``` -------------------------------- ### Test module with sample descriptor Source: https://docs.rs/hidparser/latest/src/hidparser/report_descriptor_parser.rs.html Test module for the report descriptor parser, including a sample digitizer report descriptor with comments explaining global state inheritance quirks. ```rust #[cfg(test)] mod tests { use alloc::vec::Vec; use crate::{ report_data_types::{ LogicalMaximum, LogicalMinimum, PhysicalMaximum, PhysicalMinimum, ReportAttributes, ReportId, Unit, UnitExponent, Usage, UsagePage, UsageRange, }, report_descriptor_parser::ReportDescriptorError, ReportDescriptor, ReportField, }; use super::ReportDescriptorParser; //Sample descriptor from: //https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchscreen-sample-report-descriptors //NOTE: this descriptor does not reset global state (e.g. units) in places where it would be intuitive to do so; so //things like "vendor defined" fields at the end inherit global state like units/physical extent. The tests below //account for this, even though it is unlikely that the author of this descriptor intends that "vendor defined fields" //would have physical extents or units. static DIGITIZER_REPORT_DESCRIPTOR: &[u8] = &[ 0x05, 0x0d, // USAGE_PAGE (Digitizers) 0x09, 0x04, // USAGE (Touch Screen) 0xa1, 0x01, // COLLECTION (Application) ]; ``` -------------------------------- ### Boot keyboard report descriptors with invalid items Source: https://docs.rs/hidparser/latest/src/hidparser/report_descriptor_parser.rs.html Two static byte arrays representing boot keyboard report descriptors with invalid main and global items, respectively. The first uses a valid main item (0x81, 0x02) but the second uses an invalid global item (0xf5, 0x01) for REPORT_SIZE. These are used as test inputs for parser validation. ```rust static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_MAIN_ITEM: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0xc0, // END_COLLECTION ]; ``` ```rust static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_GLOBAL_ITEM: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0xf5, 0x01, // REPORT_SIZE (1) (invalid global item) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0xc0, // END_COLLECTION ]; ``` -------------------------------- ### Extracting field values with VariableField Source: https://docs.rs/hidparser/latest/src/hidparser/lib.rs.html Demonstrates how to extract values from a buffer using different logical minimums, maximums, and bit ranges. ```rust assert_eq!(field.field_value(&buffer), Some(-17i64)); let buffer = (127i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(127i64)); field.logical_minimum = LogicalMinimum::from(-1024i32); field.logical_maximum = LogicalMaximum::from(1024i32); field.bits = 1..12; let buffer = (-1i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-1i64)); let buffer = (-18i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-9i64)); let buffer = (128i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(64i64)); field.logical_minimum = LogicalMinimum::from(-1024i32); field.logical_maximum = LogicalMaximum::from(1024i32); field.bits = 0..12; let buffer = (1025i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), None); let buffer = (-1025i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), None); field.logical_minimum = LogicalMinimum::from(0); field.logical_maximum = LogicalMaximum::from(u32::MAX); let buffer = (1025i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(1025)); let mut field = VariableField { logical_minimum: LogicalMinimum::from(-127_i32), logical_maximum: LogicalMaximum::from(127_i32), bits: 0..8, ..Default::default() }; let buffer = (-1i8).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-1i64)); let buffer = (-17i8).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-17i64)); let buffer = (127i8).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(127i64)); field.logical_minimum = LogicalMinimum::from(-1024i32); field.logical_maximum = LogicalMaximum::from(1024i32); field.bits = 0..11; let buffer = (-1i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-1i64)); let buffer = (-17i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-17i64)); let buffer = (127i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(127i64)); field.logical_minimum = LogicalMinimum::from(-1024i32); field.logical_maximum = LogicalMaximum::from(1024i32); field.bits = 1..12; let buffer = (-1i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-1i64)); let buffer = (-18i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(-9i64)); let buffer = (128i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(64i64)); field.logical_minimum = LogicalMinimum::from(-1024i32); field.logical_maximum = LogicalMaximum::from(1024i32); field.bits = 0..12; let buffer = (1025i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), None); let buffer = (-1025i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), None); field.logical_minimum = LogicalMinimum::from(0); field.logical_maximum = LogicalMaximum::from(u32::MAX); let buffer = (1025i16).to_le_bytes(); assert_eq!(field.field_value(&buffer), Some(1025)); ``` -------------------------------- ### Test Module with Integrated Windows Pen TLC Report Descriptor Source: https://docs.rs/hidparser/latest/src/hidparser/item_tokenizer.rs.html Contains unit tests for the tokenizer, including a static TEST_REPORT_DESCRIPTOR byte array representing an Integrated Windows Pen TLC report descriptor. The descriptor includes usage pages, collections, report IDs, and input items. ```Rust #[cfg(test)] mod tests { use super::{DescriptorItemTokenizer, ReportItem, ReportItemType}; use alloc::vec::Vec; static TEST_REPORT_DESCRIPTOR: &[u8] = &[ // Integrated Windows Pen TLC 0x05, 0x0d, // USAGE_PAGE (Digitizers) 0x09, 0x02, // USAGE (Pen) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (Pen) 0x09, 0x20, // USAGE (Stylus) 0xa1, 0x00, // COLLECTION (Physical) 0x09, 0x42, // USAGE (Tip Switch) 0x09, 0x44, // USAGE (Barrel Switch) 0x09, 0x3c, // USAGE (Invert) 0x09, 0x45, // USAGE (Eraser Switch) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x04, // REPORT_COUNT (4) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x03, // INPUT (Cnst,Var,Abs) ]; } ``` -------------------------------- ### Usage::page Source: https://docs.rs/hidparser/latest/hidparser/report_data_types/struct.Usage.html Returns the page component of the usage. ```APIDOC ## Usage::page ### Description Returns the page component of the usage. ### Method `pub fn page(&self) -> u16` ### Parameters - `self` - The Usage instance. ### Returns - `u16` - The page value. ``` -------------------------------- ### Bogus boot keyboard report descriptor test fixtures Source: https://docs.rs/hidparser/latest/src/hidparser/report_descriptor_parser.rs.html These Rust static byte arrays define bogus HID report descriptors for boot keyboards, each omitting or inserting an invalid item to test parser error handling. They are used as test fixtures for invalid POP, unsupported DELIMITER, missing REPORT_COUNT, and missing LOGICAL_MINIMUM cases. ```rust static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_INVALID_POP: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0xb4, // POP (Invalid) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0xc0, // END_COLLECTION ]; ``` ```rust static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_DELIMITER: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0xA8, // DELIMITER (unsupported) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0xc0, // END_COLLECTION ]; ``` ```rust static BOGUS_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_REPORT_COUNT: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0xc0, // END_COLLECTION ]; ``` ```rust static BOGUS_MINIMAL_BOOT_KEYBOARD_REPORT_DESCRIPTOR_NO_LOG_MIN: &[u8] = &[ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x05, 0x07, // USAGE_PAGE (Key Codes) 0x19, 0xE0, // USAGE_MINIMUM (224) 0x29, 0xE7, // USAGE_MAXIMUM (231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x81, 0x02, // INPUT (Data, Var, Abs) (Modifier Byte) 0xc0, // END_COLLECTION ]; ``` -------------------------------- ### Field Data Setting Tests Source: https://docs.rs/hidparser/latest/src/hidparser/lib.rs.html Unit tests demonstrating set_field_data functionality, including buffer size validation. ```rust #[test] fn set_field_data_should_set_field_data() { let mut field: VariableField = Default::default(); let mut buffer: [u8; 10] = [0x00; 10]; field.bits = 0..8; field.set_field_data(&[0xaa], &mut buffer).unwrap(); assert_eq!(buffer[0], 0xaa); assert_eq!(buffer[1..], [0x0u8; 9]); let mut buffer: [u8; 10] = [0x00; 10]; field.bits = 4..12; field.set_field_data(&[0xaa], &mut buffer).unwrap(); assert_eq!(buffer[0..2], [0xa0, 0x0a]); assert_eq!(buffer[2..], [0x0u8; 8]); let mut buffer: [u8; 1] = [0x00; 1]; field.bits = 4..12; assert_eq!(field.set_field_data(&[0xaa], &mut buffer), Err(FieldAccessError::InvalidBufferSize)); } ``` -------------------------------- ### Test tokenizer produces expected items Source: https://docs.rs/hidparser/latest/src/hidparser/item_tokenizer.rs.html Creates a DescriptorItemTokenizer from TEST_REPORT_DESCRIPTOR, collects items, and asserts the count and each item matches EXPECTED_ITEMS. Fails with a message if the count is wrong or an item differs. ```rust #[test] fn item_tokenizer_should_tokenize_items() { let tokenizer = DescriptorItemTokenizer::new(TEST_REPORT_DESCRIPTOR); let items: Result, _> = tokenizer.collect(); let items = items.unwrap(); assert_eq!(items.len(), EXPECTED_ITEMS.len(), "tokenizer did not produce the correct number of items"); for (index, (item, expected_item)) in items.iter().zip(EXPECTED_ITEMS.iter()).enumerate() { assert_eq!(item, expected_item, "invalid tokenization of item at index {index:?}"); } } ``` -------------------------------- ### Calculate Field Range for VariableField Source: https://docs.rs/hidparser/latest/src/hidparser/lib.rs.html Demonstrates various scenarios for calculating the field range of a VariableField, including handling negative values, zero, and maximum integer bounds. ```rust assert_eq!(field.field_range(), Some(254u32)); field.logical_minimum = LogicalMinimum::from(-127i32); field.logical_maximum = LogicalMaximum::from(-120i32); assert_eq!(field.field_range(), Some(7u32)); field.logical_minimum = LogicalMinimum::from(128i32); field.logical_maximum = LogicalMaximum::from(384i32); assert_eq!(field.field_range(), Some(256u32)); field.logical_minimum = LogicalMinimum::from(0i32); field.logical_maximum = LogicalMaximum::from(u32::MAX); assert_eq!(field.field_range(), Some(u32::MAX)); field.logical_minimum = LogicalMinimum::from(0i32); field.logical_maximum = LogicalMaximum::from(0u32); assert_eq!(field.field_range(), None); field.logical_minimum = LogicalMinimum::from(-127i32); field.logical_maximum = LogicalMaximum::from(-127i32); assert_eq!(field.field_range(), None); field.logical_minimum = LogicalMinimum::from(-1i32); field.logical_maximum = LogicalMaximum::from(-127i32); assert_eq!(field.field_range(), None); field.logical_minimum = LogicalMinimum::from(i32::MAX); field.logical_maximum = LogicalMaximum::from(0); assert_eq!(field.field_range(), None); // tricky: abs(i32::MIN) > i32:MAX field.logical_minimum = LogicalMinimum::from(i32::MIN + 1); field.logical_maximum = LogicalMaximum::from(0); assert_eq!(field.field_range(), Some(i32::MAX as u32)); ``` -------------------------------- ### Return reports and bad reports Source: https://docs.rs/hidparser/latest/src/hidparser/report_descriptor_parser.rs.html Returns the tuple of reports and bad reports from the parsing function. ```rust (reports, bad_reports) ``` -------------------------------- ### Define CFU HID report descriptor byte array in Rust Source: https://docs.rs/hidparser/latest/src/hidparser/report_descriptor_parser.rs.html Rust static byte array defining a CFU HID report descriptor sample. Includes usage page, collection, logical limits, report IDs, sizes, counts, and input item; comments show the corresponding HID item names. ```rust // Sample descriptor from: // https://github.com/microsoft/CFU/blob/89ef6b6ffd221fe82f9ac9d5d0f884a4a965b486/Host/CFUFirmwareSimulation/sys/DmfInterface.c#L33C12-L33C12 static CFU_REPORT_DESCRIPTOR: &[u8] = &[ 0x06, 0x00, 0xFA, // USAGE_PAGE(0xFA00) 0x09, 0xF5, // Usage::from(0xF5) 0xA1, 0x01, // COLLECTION(0x01) 0x15, 0x00, // LOGICAL_MINIMUM(0) 0x27, 0xFF, 0xFF, 0xFF, 0xFF, // LOGICAL_MAXIMUM(-1) 0x85, 0x20, // REPORT_ID(32) 0x75, 0x08, // REPORT SIZE(8) 0x95, 0x01, // REPORT COUNT(1) 0x09, 0x52, // Usage::from(0x52) 0x81, 0x02, // INPUT(0x02) 0x85, 0x22, // REPORT_ID(34) 0x75, 0x20, // REPORT SIZE(32) ``` -------------------------------- ### Convert byte slices to integers with u16_from_bytes, u32_from_bytes, i32_from_bytes Source: https://docs.rs/hidparser/latest/src/hidparser/utils.rs.html Provides conversion functions for variable-length byte slices into integer types. Returns 0 for empty input. For i32_from_bytes, sign-extends when the most significant bit of the last byte is set. ```rust //! Parser Utility Functions //! //! This module contains utility functions used to do conversions of variable length byte slices into integer types. //! //! ## License //! //! Copyright (C) Microsoft Corporation. All rights reserved. //! //! SPDX-License-Identifier: BSD-2-Clause-Patent //! pub fn u16_from_bytes(bytes: &[u8]) -> u16 { if bytes.is_empty() { return 0; } let mut u16_bytes = [0_u8; 2]; u16_bytes[..bytes.len()].clone_from_slice(bytes); u16::from_le_bytes(u16_bytes) } pub fn u32_from_bytes(bytes: &[u8]) -> u32 { if bytes.is_empty() { return 0; } let mut u32_bytes = [0_u8; 4]; u32_bytes[..bytes.len()].clone_from_slice(bytes); u32::from_le_bytes(u32_bytes) } pub fn i32_from_bytes(bytes: &[u8]) -> i32 { if bytes.is_empty() { return 0; } let mut i32_bytes = [0_u8; 4]; //sign-extend if bytes.last().is_some_and(|byte| byte & 0x80 != 0) { i32_bytes.fill(0xff); } i32_bytes[..bytes.len()].clone_from_slice(bytes); i32::from_le_bytes(i32_bytes) } ``` -------------------------------- ### Usage::id Source: https://docs.rs/hidparser/latest/hidparser/report_data_types/struct.Usage.html Returns the id component of the usage. ```APIDOC ## Usage::id ### Description Returns the id component of the usage. ### Method `pub fn id(&self) -> u16` ### Parameters - `self` - The Usage instance. ### Returns - `u16` - The id value. ``` -------------------------------- ### From> for StringRange Source: https://docs.rs/hidparser/latest/hidparser/report_data_types/struct.StringRange.html Converts a RangeInclusive into a StringRange. ```APIDOC ## From> for StringRange ### Description Converts a RangeInclusive into a StringRange. ### Method fn from(val: RangeInclusive) -> Self ### Parameters - **val** (RangeInclusive) - Required - The range to convert. ### Returns - **StringRange** - The resulting StringRange. ``` -------------------------------- ### Raw HID Descriptor Byte Array Source: https://docs.rs/hidparser/latest/src/hidparser/item_tokenizer.rs.html A partial byte array representing HID report descriptor commands. ```rust 134 0x09, 0x32, // USAGE (In Range) 135 0x81, 0x02, // INPUT (Data,Var,Abs) 136 0x95, 0x02, // REPORT_COUNT (2) 137 0x81, 0x03, // INPUT (Cnst,Var,Abs) 138 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 139 0x09, 0x30, // USAGE (X) 140 0x75, 0x10, // REPORT_SIZE (16) 141 0x95, 0x01, // REPORT_COUNT (1) 142 0xa4, // PUSH 143 0x55, 0x0d, // UNIT_EXPONENT (-3) 144 0x65, 0x13, // UNIT (Inch,EngLinear) 145 0x35, 0x00, // PHYSICAL_MINIMUM (0) 146 0x46, 0x3a, 0x20, // PHYSICAL_MAXIMUM (8250) 147 0x26, 0xf8, 0x52, // LOGICAL_MAXIMUM (21240) 148 0x81, 0x02, // INPUT (Data,Var,Abs) 149 0x09, 0x31, // USAGE (Y) 150 0x46, 0x2c, 0x18, // PHYSICAL_MAXIMUM (6188) 151 0x26, 0x6c, 0x3e, // LOGICAL_MAXIMUM (15980) 152 0x81, 0x02, // INPUT (Data,Var,Abs) 153 0xb4, // POP 154 0x05, 0x0d, // USAGE_PAGE (Digitizers) 155 0x09, 0x30, // USAGE (Tip Pressure) 156 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 157 0x81, 0x02, // INPUT (Data,Var,Abs) 158 0x75, 0x08, // REPORT_SIZE (8) 159 0x09, 0x3d, // USAGE (X Tilt) 160 0x15, 0x81, // LOGICAL_MINIMUM (-127) 161 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 162 0x81, 0x02, // INPUT (Data,Var,Abs) 163 0x09, 0x3e, // USAGE (Y Tilt) 164 0x15, 0x81, // LOGICAL_MINIMUM (-127) 165 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 166 0x81, 0x02, // INPUT (Data,Var,Abs) 167 0xc0, // END_COLLECTION 168 0xc0, // END_COLLECTION 169 ]; ``` -------------------------------- ### Report and ReportDescriptor Structures Source: https://docs.rs/hidparser/latest/src/hidparser/lib.rs.html Core data structures for representing HID reports and the collection of reports parsed from a descriptor. ```rust #[derive(Debug, PartialEq, Eq)] pub struct Report { /// The (optional) report id associated with the report. pub report_id: Option, /// The size in bits of the report. pub size_in_bits: usize, /// The list of fields in the report. pub fields: Vec, } /// A collection of input/output/feature reports that are described by a given Report Descriptor. #[derive(Debug, PartialEq, Eq)] pub struct ReportDescriptor { /// The list of input reports from this report descriptor. pub input_reports: Vec, /// The list of input reports (if any) that failed to parse. pub bad_input_reports: Vec<(Option, ReportDescriptorError)>, /// The list of output reports from this report descriptor. pub output_reports: Vec, /// The list of output reports (if any) that failed to parse. pub bad_output_reports: Vec<(Option, ReportDescriptorError)>, /// The list of feature reports from this report descriptor. pub features: Vec, /// The list of feature reports (if any) that failed to parse. pub bad_features: Vec<(Option, ReportDescriptorError)>, } ``` -------------------------------- ### Push report to collection Source: https://docs.rs/hidparser/latest/src/hidparser/report_descriptor_parser.rs.html Adds a completed Report with its ID, size in bits, and fields to the reports collection. ```rust reports.push(Report { report_id: *id, size_in_bits: bit_position as usize, fields }); ```