diff --git a/.gitignore b/.gitignore index 5b2ff009..466872d6 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ test_results.csv _build* **/.venv/** +**/.vscode/** +**.egg-info # waf build files .lock-waf_* diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7de64616..518aab7b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ lib_xua Change Log ================== +3.0.0 +----- + + * ADDED: Support for HID Report IDs + * REMOVED: Support for HID Reports containing controls from mixed Usage + pages + * CHANGED: Renamed the HID API file xua_hid_report_descriptor.h to + xua_hid_report.h + 2.1.1 ----- diff --git a/Jenkinsfile b/Jenkinsfile index 905b2301..61fd5394 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -45,7 +45,7 @@ pipeline { // runWaf('.', "configure clean build --target=xcoreai") // stash name: 'xua_unit_tests', includes: 'bin/*xcoreai.xe, ' viewEnv() { - runPython("TARGET=XCORE200 pytest -n 1") + runPython("TARGET=XCORE200 pytest -s") } } } diff --git a/examples/AN00246_xua_example/src/hid_report_descriptor.h b/examples/AN00246_xua_example/src/hid_report_descriptor.h index a049576e..cd789971 100644 --- a/examples/AN00246_xua_example/src/hid_report_descriptor.h +++ b/examples/AN00246_xua_example/src/hid_report_descriptor.h @@ -3,7 +3,7 @@ #ifndef __hid_report_descriptor_h__ #define __hid_report_descriptor_h__ -#include "xua_hid_report_descriptor.h" +#include "xua_hid_report.h" #if 0 /* Existing static report descriptor kept for reference */ @@ -32,38 +32,92 @@ unsigned char hidReportDescriptor[] = /* * Define non-configurable items in the HID Report descriptor. */ -static const USB_HID_Short_Item_t hidCollectionApplication = { .header = 0xA1, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidCollectionEnd = { .header = 0xC0, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidInputConstArray = { .header = 0x81, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidInputDataVar = { .header = 0x81, .data = { 0x02, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMaximum0 = { .header = 0x25, .data = { 0x00, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMaximum1 = { .header = 0x25, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMinimum0 = { .header = 0x15, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount2 = { .header = 0x95, .data = { 0x02, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportCount6 = { .header = 0x95, .data = { 0x06, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportSize1 = { .header = 0x75, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidReportCount2 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x02, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsageConsumerControl = { .header = 0x09, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }, .location = 0x00 }; +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Report_Element_t hidReportPageConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) +}; /* * Define configurable items in the HID Report descriptor. */ -static USB_HID_Short_Item_t hidUsageByte0Bit5 = { .header = 0x09, .data = { 0xE2, 0x00 }, .location = 0x50 }; // Mute -static USB_HID_Short_Item_t hidUsageByte0Bit4 = { .header = 0x09, .data = { 0xEA, 0x00 }, .location = 0x40 }; // Vol- -static USB_HID_Short_Item_t hidUsageByte0Bit3 = { .header = 0x09, .data = { 0xE9, 0x00 }, .location = 0x30 }; // Vol+ -static USB_HID_Short_Item_t hidUsageByte0Bit2 = { .header = 0x09, .data = { 0xB6, 0x00 }, .location = 0x20 }; // Scan Prev -static USB_HID_Short_Item_t hidUsageByte0Bit1 = { .header = 0x09, .data = { 0xB5, 0x00 }, .location = 0x10 }; // Scan Next -static USB_HID_Short_Item_t hidUsageByte0Bit0 = { .header = 0x09, .data = { 0xB0, 0x00 }, .location = 0x00 }; // Play +static USB_HID_Report_Element_t hidUsageByte0Bit5 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 5) +}; // Mute +static USB_HID_Report_Element_t hidUsageByte0Bit4 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 4) +}; // Vol- +static USB_HID_Report_Element_t hidUsageByte0Bit3 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 3) +}; // Vol+ +static USB_HID_Report_Element_t hidUsageByte0Bit2 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB6, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 2) +}; // Scan Prev +static USB_HID_Report_Element_t hidUsageByte0Bit1 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB5, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 1) +}; // Scan Next +static USB_HID_Report_Element_t hidUsageByte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB0, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 0) +}; // Play /* - * List the configurable items in the HID Report descriptor. + * List the configurable elements in the HID Report descriptor. */ -static USB_HID_Short_Item_t* const hidConfigurableItems[] = { +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { &hidUsageByte0Bit0, &hidUsageByte0Bit1, &hidUsageByte0Bit2, @@ -73,27 +127,28 @@ static USB_HID_Short_Item_t* const hidConfigurableItems[] = { }; /* - * List Usage pages in the HID Report descriptor, one per byte. + * List HID Reports, one per Report ID. This should be a usage page item with the relevant + * If not using report IDs - still have one with report ID 0 */ -static const USB_HID_Short_Item_t* const hidUsagePages[] = { - &hidUsagePageConsumer +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportPageConsumer }; /* * List all items in the HID Report descriptor. */ static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { - &hidUsagePageConsumer, + &(hidReportPageConsumer.item), &hidUsageConsumerControl, &hidCollectionApplication, &hidLogicalMinimum0, &hidLogicalMaximum1, - &hidUsageByte0Bit0, - &hidUsageByte0Bit1, - &hidUsageByte0Bit2, - &hidUsageByte0Bit3, - &hidUsageByte0Bit4, - &hidUsageByte0Bit5, + &(hidUsageByte0Bit0.item), + &(hidUsageByte0Bit1.item), + &(hidUsageByte0Bit2.item), + &(hidUsageByte0Bit3.item), + &(hidUsageByte0Bit4.item), + &(hidUsageByte0Bit5.item), &hidReportSize1, &hidReportCount6, &hidInputDataVar, @@ -104,9 +159,10 @@ static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { }; /* - * Define the length of the HID Report. - * This value must match the number of Report bytes defined by hidReportDescriptorItems. + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) */ -#define HID_REPORT_LENGTH ( 1 ) +#define HID_REPORT_COUNT ( 1 ) #endif // __hid_report_descriptor_h__ diff --git a/examples/AN00247_xua_example_spdif_tx/src/hid_report_descriptor.h b/examples/AN00247_xua_example_spdif_tx/src/hid_report_descriptor.h index a049576e..cd789971 100644 --- a/examples/AN00247_xua_example_spdif_tx/src/hid_report_descriptor.h +++ b/examples/AN00247_xua_example_spdif_tx/src/hid_report_descriptor.h @@ -3,7 +3,7 @@ #ifndef __hid_report_descriptor_h__ #define __hid_report_descriptor_h__ -#include "xua_hid_report_descriptor.h" +#include "xua_hid_report.h" #if 0 /* Existing static report descriptor kept for reference */ @@ -32,38 +32,92 @@ unsigned char hidReportDescriptor[] = /* * Define non-configurable items in the HID Report descriptor. */ -static const USB_HID_Short_Item_t hidCollectionApplication = { .header = 0xA1, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidCollectionEnd = { .header = 0xC0, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidInputConstArray = { .header = 0x81, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidInputDataVar = { .header = 0x81, .data = { 0x02, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMaximum0 = { .header = 0x25, .data = { 0x00, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMaximum1 = { .header = 0x25, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMinimum0 = { .header = 0x15, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount2 = { .header = 0x95, .data = { 0x02, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportCount6 = { .header = 0x95, .data = { 0x06, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportSize1 = { .header = 0x75, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidReportCount2 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x02, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsageConsumerControl = { .header = 0x09, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }, .location = 0x00 }; +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Report_Element_t hidReportPageConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) +}; /* * Define configurable items in the HID Report descriptor. */ -static USB_HID_Short_Item_t hidUsageByte0Bit5 = { .header = 0x09, .data = { 0xE2, 0x00 }, .location = 0x50 }; // Mute -static USB_HID_Short_Item_t hidUsageByte0Bit4 = { .header = 0x09, .data = { 0xEA, 0x00 }, .location = 0x40 }; // Vol- -static USB_HID_Short_Item_t hidUsageByte0Bit3 = { .header = 0x09, .data = { 0xE9, 0x00 }, .location = 0x30 }; // Vol+ -static USB_HID_Short_Item_t hidUsageByte0Bit2 = { .header = 0x09, .data = { 0xB6, 0x00 }, .location = 0x20 }; // Scan Prev -static USB_HID_Short_Item_t hidUsageByte0Bit1 = { .header = 0x09, .data = { 0xB5, 0x00 }, .location = 0x10 }; // Scan Next -static USB_HID_Short_Item_t hidUsageByte0Bit0 = { .header = 0x09, .data = { 0xB0, 0x00 }, .location = 0x00 }; // Play +static USB_HID_Report_Element_t hidUsageByte0Bit5 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 5) +}; // Mute +static USB_HID_Report_Element_t hidUsageByte0Bit4 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 4) +}; // Vol- +static USB_HID_Report_Element_t hidUsageByte0Bit3 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 3) +}; // Vol+ +static USB_HID_Report_Element_t hidUsageByte0Bit2 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB6, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 2) +}; // Scan Prev +static USB_HID_Report_Element_t hidUsageByte0Bit1 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB5, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 1) +}; // Scan Next +static USB_HID_Report_Element_t hidUsageByte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB0, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 0) +}; // Play /* - * List the configurable items in the HID Report descriptor. + * List the configurable elements in the HID Report descriptor. */ -static USB_HID_Short_Item_t* const hidConfigurableItems[] = { +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { &hidUsageByte0Bit0, &hidUsageByte0Bit1, &hidUsageByte0Bit2, @@ -73,27 +127,28 @@ static USB_HID_Short_Item_t* const hidConfigurableItems[] = { }; /* - * List Usage pages in the HID Report descriptor, one per byte. + * List HID Reports, one per Report ID. This should be a usage page item with the relevant + * If not using report IDs - still have one with report ID 0 */ -static const USB_HID_Short_Item_t* const hidUsagePages[] = { - &hidUsagePageConsumer +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportPageConsumer }; /* * List all items in the HID Report descriptor. */ static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { - &hidUsagePageConsumer, + &(hidReportPageConsumer.item), &hidUsageConsumerControl, &hidCollectionApplication, &hidLogicalMinimum0, &hidLogicalMaximum1, - &hidUsageByte0Bit0, - &hidUsageByte0Bit1, - &hidUsageByte0Bit2, - &hidUsageByte0Bit3, - &hidUsageByte0Bit4, - &hidUsageByte0Bit5, + &(hidUsageByte0Bit0.item), + &(hidUsageByte0Bit1.item), + &(hidUsageByte0Bit2.item), + &(hidUsageByte0Bit3.item), + &(hidUsageByte0Bit4.item), + &(hidUsageByte0Bit5.item), &hidReportSize1, &hidReportCount6, &hidInputDataVar, @@ -104,9 +159,10 @@ static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { }; /* - * Define the length of the HID Report. - * This value must match the number of Report bytes defined by hidReportDescriptorItems. + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) */ -#define HID_REPORT_LENGTH ( 1 ) +#define HID_REPORT_COUNT ( 1 ) #endif // __hid_report_descriptor_h__ diff --git a/examples/AN00248_xua_example_pdm_mics/src/hid_report_descriptor.h b/examples/AN00248_xua_example_pdm_mics/src/hid_report_descriptor.h index a049576e..cd789971 100644 --- a/examples/AN00248_xua_example_pdm_mics/src/hid_report_descriptor.h +++ b/examples/AN00248_xua_example_pdm_mics/src/hid_report_descriptor.h @@ -3,7 +3,7 @@ #ifndef __hid_report_descriptor_h__ #define __hid_report_descriptor_h__ -#include "xua_hid_report_descriptor.h" +#include "xua_hid_report.h" #if 0 /* Existing static report descriptor kept for reference */ @@ -32,38 +32,92 @@ unsigned char hidReportDescriptor[] = /* * Define non-configurable items in the HID Report descriptor. */ -static const USB_HID_Short_Item_t hidCollectionApplication = { .header = 0xA1, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidCollectionEnd = { .header = 0xC0, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidInputConstArray = { .header = 0x81, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidInputDataVar = { .header = 0x81, .data = { 0x02, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMaximum0 = { .header = 0x25, .data = { 0x00, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMaximum1 = { .header = 0x25, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMinimum0 = { .header = 0x15, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount2 = { .header = 0x95, .data = { 0x02, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportCount6 = { .header = 0x95, .data = { 0x06, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportSize1 = { .header = 0x75, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidReportCount2 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x02, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsageConsumerControl = { .header = 0x09, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }, .location = 0x00 }; +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Report_Element_t hidReportPageConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) +}; /* * Define configurable items in the HID Report descriptor. */ -static USB_HID_Short_Item_t hidUsageByte0Bit5 = { .header = 0x09, .data = { 0xE2, 0x00 }, .location = 0x50 }; // Mute -static USB_HID_Short_Item_t hidUsageByte0Bit4 = { .header = 0x09, .data = { 0xEA, 0x00 }, .location = 0x40 }; // Vol- -static USB_HID_Short_Item_t hidUsageByte0Bit3 = { .header = 0x09, .data = { 0xE9, 0x00 }, .location = 0x30 }; // Vol+ -static USB_HID_Short_Item_t hidUsageByte0Bit2 = { .header = 0x09, .data = { 0xB6, 0x00 }, .location = 0x20 }; // Scan Prev -static USB_HID_Short_Item_t hidUsageByte0Bit1 = { .header = 0x09, .data = { 0xB5, 0x00 }, .location = 0x10 }; // Scan Next -static USB_HID_Short_Item_t hidUsageByte0Bit0 = { .header = 0x09, .data = { 0xB0, 0x00 }, .location = 0x00 }; // Play +static USB_HID_Report_Element_t hidUsageByte0Bit5 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 5) +}; // Mute +static USB_HID_Report_Element_t hidUsageByte0Bit4 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 4) +}; // Vol- +static USB_HID_Report_Element_t hidUsageByte0Bit3 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 3) +}; // Vol+ +static USB_HID_Report_Element_t hidUsageByte0Bit2 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB6, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 2) +}; // Scan Prev +static USB_HID_Report_Element_t hidUsageByte0Bit1 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB5, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 1) +}; // Scan Next +static USB_HID_Report_Element_t hidUsageByte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB0, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 0) +}; // Play /* - * List the configurable items in the HID Report descriptor. + * List the configurable elements in the HID Report descriptor. */ -static USB_HID_Short_Item_t* const hidConfigurableItems[] = { +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { &hidUsageByte0Bit0, &hidUsageByte0Bit1, &hidUsageByte0Bit2, @@ -73,27 +127,28 @@ static USB_HID_Short_Item_t* const hidConfigurableItems[] = { }; /* - * List Usage pages in the HID Report descriptor, one per byte. + * List HID Reports, one per Report ID. This should be a usage page item with the relevant + * If not using report IDs - still have one with report ID 0 */ -static const USB_HID_Short_Item_t* const hidUsagePages[] = { - &hidUsagePageConsumer +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportPageConsumer }; /* * List all items in the HID Report descriptor. */ static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { - &hidUsagePageConsumer, + &(hidReportPageConsumer.item), &hidUsageConsumerControl, &hidCollectionApplication, &hidLogicalMinimum0, &hidLogicalMaximum1, - &hidUsageByte0Bit0, - &hidUsageByte0Bit1, - &hidUsageByte0Bit2, - &hidUsageByte0Bit3, - &hidUsageByte0Bit4, - &hidUsageByte0Bit5, + &(hidUsageByte0Bit0.item), + &(hidUsageByte0Bit1.item), + &(hidUsageByte0Bit2.item), + &(hidUsageByte0Bit3.item), + &(hidUsageByte0Bit4.item), + &(hidUsageByte0Bit5.item), &hidReportSize1, &hidReportCount6, &hidInputDataVar, @@ -104,9 +159,10 @@ static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { }; /* - * Define the length of the HID Report. - * This value must match the number of Report bytes defined by hidReportDescriptorItems. + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) */ -#define HID_REPORT_LENGTH ( 1 ) +#define HID_REPORT_COUNT ( 1 ) #endif // __hid_report_descriptor_h__ diff --git a/legacy_tests/app_test_i2s_loopback/hid_report_descriptor.h b/legacy_tests/app_test_i2s_loopback/hid_report_descriptor.h index a049576e..e0b185f8 100644 --- a/legacy_tests/app_test_i2s_loopback/hid_report_descriptor.h +++ b/legacy_tests/app_test_i2s_loopback/hid_report_descriptor.h @@ -3,7 +3,7 @@ #ifndef __hid_report_descriptor_h__ #define __hid_report_descriptor_h__ -#include "xua_hid_report_descriptor.h" +#include "xua_hid_report.h" #if 0 /* Existing static report descriptor kept for reference */ @@ -32,38 +32,91 @@ unsigned char hidReportDescriptor[] = /* * Define non-configurable items in the HID Report descriptor. */ -static const USB_HID_Short_Item_t hidCollectionApplication = { .header = 0xA1, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidCollectionEnd = { .header = 0xC0, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidInputConstArray = { .header = 0x81, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidInputDataVar = { .header = 0x81, .data = { 0x02, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMaximum0 = { .header = 0x25, .data = { 0x00, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMaximum1 = { .header = 0x25, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMinimum0 = { .header = 0x15, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount2 = { .header = 0x95, .data = { 0x02, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportCount6 = { .header = 0x95, .data = { 0x06, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportSize1 = { .header = 0x75, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidReportCount2 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x02, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsageConsumerControl = { .header = 0x09, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }, .location = 0x00 }; +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Report_Element_t hidReportPageConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 1, 0, 0 ) }; /* * Define configurable items in the HID Report descriptor. */ -static USB_HID_Short_Item_t hidUsageByte0Bit5 = { .header = 0x09, .data = { 0xE2, 0x00 }, .location = 0x50 }; // Mute -static USB_HID_Short_Item_t hidUsageByte0Bit4 = { .header = 0x09, .data = { 0xEA, 0x00 }, .location = 0x40 }; // Vol- -static USB_HID_Short_Item_t hidUsageByte0Bit3 = { .header = 0x09, .data = { 0xE9, 0x00 }, .location = 0x30 }; // Vol+ -static USB_HID_Short_Item_t hidUsageByte0Bit2 = { .header = 0x09, .data = { 0xB6, 0x00 }, .location = 0x20 }; // Scan Prev -static USB_HID_Short_Item_t hidUsageByte0Bit1 = { .header = 0x09, .data = { 0xB5, 0x00 }, .location = 0x10 }; // Scan Next -static USB_HID_Short_Item_t hidUsageByte0Bit0 = { .header = 0x09, .data = { 0xB0, 0x00 }, .location = 0x00 }; // Play +static USB_HID_Report_Element_t hidUsageByte0Bit5 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 0, 0, 5 ) +}; // Mute +static USB_HID_Report_Element_t hidUsageByte0Bit4 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 0, 0, 4 ) +}; // Vol- +static USB_HID_Report_Element_t hidUsageByte0Bit3 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 0, 0, 3 ) +}; // Vol+ +static USB_HID_Report_Element_t hidUsageByte0Bit2 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB6, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 0, 0, 2 ) +}; // Scan Prev +static USB_HID_Report_Element_t hidUsageByte0Bit1 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB5, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 0, 0, 1 ) +}; // Scan Next +static USB_HID_Report_Element_t hidUsageByte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xB0, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 0, 0, 0 ) +}; // Play /* * List the configurable items in the HID Report descriptor. */ -static USB_HID_Short_Item_t* const hidConfigurableItems[] = { +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { &hidUsageByte0Bit0, &hidUsageByte0Bit1, &hidUsageByte0Bit2, @@ -73,27 +126,28 @@ static USB_HID_Short_Item_t* const hidConfigurableItems[] = { }; /* - * List Usage pages in the HID Report descriptor, one per byte. + * List HID Reports, one per Report ID. This should be a usage page item with the relevant + * If not using report IDs - still have one with report ID 0 */ -static const USB_HID_Short_Item_t* const hidUsagePages[] = { - &hidUsagePageConsumer +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportPageConsumer }; /* * List all items in the HID Report descriptor. */ -static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { - &hidUsagePageConsumer, +static const USB_HID_Short_Item_t * const hidReportDescriptorItems[] = { + &(hidReportPageConsumer.item), &hidUsageConsumerControl, &hidCollectionApplication, &hidLogicalMinimum0, &hidLogicalMaximum1, - &hidUsageByte0Bit0, - &hidUsageByte0Bit1, - &hidUsageByte0Bit2, - &hidUsageByte0Bit3, - &hidUsageByte0Bit4, - &hidUsageByte0Bit5, + &(hidUsageByte0Bit0.item), + &(hidUsageByte0Bit1.item), + &(hidUsageByte0Bit2.item), + &(hidUsageByte0Bit3.item), + &(hidUsageByte0Bit4.item), + &(hidUsageByte0Bit5.item), &hidReportSize1, &hidReportCount6, &hidInputDataVar, @@ -104,9 +158,10 @@ static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { }; /* - * Define the length of the HID Report. - * This value must match the number of Report bytes defined by hidReportDescriptorItems. + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) */ -#define HID_REPORT_LENGTH ( 1 ) +#define HID_REPORT_COUNT ( 1 ) #endif // __hid_report_descriptor_h__ diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index 38db0d98..a1db834c 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1244,10 +1244,6 @@ enum USBEndpointNumber_Out #define MAX_VOL (0x20000000) -#if defined(SU1_ADC_ENABLE) && (SU1_ADC_ENABLE == 0) -#undef SU1_ADC_ENABLE -#endif - #if defined(LEVEL_METER_LEDS) && !defined(LEVEL_UPDATE_RATE) #define LEVEL_UPDATE_RATE 400000 #endif diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index 39b0476e..e566c11b 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -1,4 +1,4 @@ -VERSION = 2.1.1 +VERSION = 3.0.0 DEPENDENT_MODULES = lib_logging(>=3.0.0) \ lib_xassert(>=4.0.0) \ diff --git a/lib_xua/src/core/buffer/decouple/interrupt.h b/lib_xua/src/core/buffer/decouple/interrupt.h index 1aec8cd9..894ebd49 100644 --- a/lib_xua/src/core/buffer/decouple/interrupt.h +++ b/lib_xua/src/core/buffer/decouple/interrupt.h @@ -72,13 +72,8 @@ //int ksp_enter, ksp_exit, r11_store; -#if defined(__XS2A__) || defined(__XS3A__) #define ISSUE_MODE_SINGLE ".issue_mode single\n" #define ISSUE_MODE_DUAL ".issue_mode dual\n" -#else -#define ISSUE_MODE_SINGLE -#define ISSUE_MODE_DUAL -#endif #define do_interrupt_handler(f,args) \ asm(ISSUE_MODE_SINGLE\ diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index eb6b373a..e2f81ef4 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -21,9 +21,10 @@ #include "testct_byref.h" #if( 0 < HID_CONTROLS ) -#include "xua_hid_report_descriptor.h" +#include "xua_hid_report.h" #include "user_hid.h" -unsigned char g_hidData[HID_MAX_DATA_BYTES] = {0}; +#include "xua_hid.h" +unsigned char g_hidData[HID_MAX_DATA_BYTES] = {0U}; #endif void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max); @@ -372,10 +373,16 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #if( 0 < HID_CONTROLS ) - { - int hidDataLength = hidGetReportLength(); - XUD_SetReady_In(ep_hid, g_hidData, hidDataLength); - } + UserHIDInit(); + + while (!hidIsReportDescriptorPrepared()) + ; + + /* Get the a report - we don't really care which it is, so long as there's some data we can grab. */ + int hidReportLength = (int) UserHIDGetData(hidGetNextValidReportId(0), g_hidData); + + XUD_SetReady_In(ep_hid, g_hidData, hidReportLength); + #endif #if (AUDIO_CLASS == 1) @@ -887,11 +894,22 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #if( 0 < HID_CONTROLS ) /* HID Report Data */ - case XUD_SetData_Select(c_hid, ep_hid, result): + case (hidIsChangePending(0U) || !HidIsSetIdleSilenced(0U)) => XUD_SetData_Select(c_hid, ep_hid, result): { - int hidDataLength = hidGetReportLength(); - UserHIDGetData(g_hidData); - XUD_SetReady_In(ep_hid, g_hidData, hidDataLength); + timer tmr; + unsigned reportTime; + tmr :> reportTime; + + for(unsigned id = hidIsReportIdInUse(); id < hidGetReportIdLimit(); ++id) { + if(0U == id || (hidIsChangePending(id) || !HidIsSetIdleSilenced(id))) { + hidCaptureReportTime(id, reportTime); + int hidDataLength = (int) UserHIDGetData(id, g_hidData); + XUD_SetReady_In(ep_hid, g_hidData, hidDataLength); + hidCalcNextReportTime(id); + hidClearChangePending(id); + break; + } + } } break; #endif diff --git a/lib_xua/src/core/endpoint0/descriptor_defs.h b/lib_xua/src/core/endpoint0/descriptor_defs.h index b4dc692b..42567878 100644 --- a/lib_xua/src/core/endpoint0/descriptor_defs.h +++ b/lib_xua/src/core/endpoint0/descriptor_defs.h @@ -66,7 +66,7 @@ enum USBInterfaceNumber INTERFACE_COUNT /* End marker */ }; -#if( 0 < HID_CONTROLS ) +#ifndef ENDPOINT_INT_INTERVAL_IN_HID #define ENDPOINT_INT_INTERVAL_IN_HID 0x08 #endif diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index a89f6330..b282319b 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -28,7 +28,7 @@ #if( 0 < HID_CONTROLS ) #include "hid.h" #include "xua_hid.h" -#include "xua_hid_report_descriptor.h" +#include "xua_hid_report.h" #endif #if DSD_CHANS_DAC > 0 @@ -525,6 +525,7 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c #endif #if( 0 < HID_CONTROLS ) + hidReportInit(); hidPrepareReportDescriptor(); size_t hidReportDescriptorLength = hidGetReportDescriptorLength(); diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index afa1602e..26ef4d39 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -196,14 +196,6 @@ in port p_pdm_mclk = PORT_PDM_MCLK; #endif #endif - - -#if (defined(__XS2A__) && (ADAT_RX)) -/* Cannot use default clock (CLKBLK_REF) for ADAT RX since it is tied to the -60MHz USB clock on XS2 processors. */ -on tile[XUD_TILE] : clock clk_adat_rx = CLKBLK_ADAT_RX; -#endif - on tile[AUDIO_IO_TILE] : clock clk_audio_mclk = CLKBLK_MCLK; /* Master clock */ #if(AUDIO_IO_TILE != XUD_TILE) && XUA_USB_EN @@ -214,15 +206,6 @@ on tile[XUD_TILE] : in port p_mclk_in_usb = PORT_MCLK_IN_USB; on tile[AUDIO_IO_TILE] : clock clk_audio_bclk = CLKBLK_I2S_BIT; /* Bit clock */ - -/* L/G Series needs a port to use for USB reset */ -#if ((defined(__XS2A__) || defined (__XS3A__)) && defined(PORT_USB_RESET)) -/* This define is checked since it could be on a shift reg or similar */ -on tile[XUD_TILE] : out port p_usb_rst = PORT_USB_RESET; -#else -#define p_usb_rst null -#endif - #ifdef IAP /* I2C ports - in a struct for use with module_i2c_shared & module_i2c_simple/module_i2c_single_port */ #ifdef PORT_I2C @@ -443,7 +426,7 @@ void SpdifTxWrapper(chanend c_spdif_tx) } #endif -void usb_audio_io(chanend ?c_aud_in, chanend ?c_adc, +void usb_audio_io(chanend ?c_aud_in, #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) chanend c_spdif_tx, #endif @@ -571,11 +554,6 @@ int main() chan c_ea_data; #endif #endif -#ifdef SU1_ADC_ENABLE - chan c_adc; -#else -#define c_adc null -#endif #ifdef MIXER chan c_mix_ctl; @@ -659,7 +637,7 @@ int main() on tile[AUDIO_IO_TILE]: { - usb_audio_io(c_mix_out, c_adc + usb_audio_io(c_mix_out #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) , c_spdif_tx #endif @@ -725,11 +703,6 @@ int main() { set_thread_fast_mode_on(); -#if defined(__XS2A__) - /* Can't use REF clock as this is usb clock */ - set_port_clock(p_adat_rx, clk_adat_rx); - start_clock(clk_adat_rx); -#endif while (1) { adatReceiver48000(p_adat_rx, c_adat_rx); @@ -765,11 +738,6 @@ int main() #endif /*MIC_PROCESSING_USE_INTERFACE*/ #endif /*XUA_NUM_PDM_MICS > 0*/ #endif /*PDM_RECORD*/ - - -#ifdef SU1_ADC_ENABLE - xs1_su_adc_service(c_adc); -#endif } return 0; diff --git a/lib_xua/src/core/mixer/fastmix.S b/lib_xua/src/core/mixer/fastmix.S index c8828a38..9f298115 100644 --- a/lib_xua/src/core/mixer/fastmix.S +++ b/lib_xua/src/core/mixer/fastmix.S @@ -1,13 +1,9 @@ // Copyright 2018-2021 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. -//#include "devicedefines.h" #define MAX_MIX_COUNT 8 #define MIX_INPUTS 18 - -#if defined(__XS2A__) || defined(__XS3A__) - #define DOMIX_TOP(i) \ .cc_top doMix##i.function,doMix##i; \ .align 4 ;\ @@ -50,52 +46,6 @@ doMix##i##: ;\ .size doMix##i, .-doMix##i; \ .cc_bottom doMix##i##.function; -#else - - -#define DOMIX_TOP(i) \ -.cc_top doMix##i.function,doMix##i; \ - .align 4 ;\ -.globl doMix##i ;\ -.type doMix##i, @function ;\ -.globl doMix##i##.nstackwords ;\ -.globl doMix##i##.maxthreads ; \ -.globl doMix##i##.maxtimers ; \ -.globl doMix##i##.maxchanends ; \ -.globl doMix##i##.maxsync ;\ -.linkset doMix##i##.locnoside, 1; \ -.linkset doMix##i##.locnochandec, 1;\ -.linkset doMix##i##.nstackwords, 0 ;\ -.linkset doMix##i##.maxchanends, 0 ;\ -.linkset doMix##i##.maxtimers, 0 ;\ -.linkset doMix##i##.maxthreads, 1; \ -doMix##i##: ;\ - set cp, r0; \ - set dp, r1; \ - lsub r0, r1, r0, r0, r0;\ - .label_##i##: - -#define DOMIX_BOT(i) \ - ldap r11, _dp; \ - set dp, r11;\ - ldap r11, _cp;\ - set cp, r11;\ -\ - mov r0, r1;\ - ldc r2, 0x19;\ - sext r0, r2;\ - eq r0, r0, r1;\ - bf r0, .L20; \ -\ - shl r0, r1, 0x7;\ - retsp 0x0;\ -\ -\ -.size doMix##i, .-doMix##i; \ -.cc_bottom doMix##i##.function; - -#endif - #define N MIX_INPUTS #define BODY(i) \ ldw r2,cp[i]; \ @@ -115,8 +65,6 @@ doMix##i##: ;\ retsp 0x0; \ - - #if(MAX_MIX_COUNT > 0) DOMIX_TOP(0) #include "repeat.h" diff --git a/lib_xua/src/core/ports/audioports.xc b/lib_xua/src/core/ports/audioports.xc index 330b7f96..1f40b89e 100644 --- a/lib_xua/src/core/ports/audioports.xc +++ b/lib_xua/src/core/ports/audioports.xc @@ -62,37 +62,12 @@ unsigned int divide, unsigned curSamFreq) } #endif -#if defined(__XS2A__) || defined(__XS3A__) unsafe { /* Clock bitclock clock block from master clock pin (divided) */ configure_clock_src_divide(clk_audio_bclk, (port) p_mclk_in, (divide/2)); configure_port_clock_output(p_bclk, clk_audio_bclk); } -#else - #error XS1 no longer supported in audio core - /* For a divide of one (i.e. bitclock == master-clock) BClk is set to clock_output mode. - * In this mode it outputs an edge clock on every tick of itsassociated clock_block. - * - * For all other divides, BClk is clocked by the master clock and data - * will be output to p_bclk to generate the bit clock. - */ - if (divide == 1) /* e.g. 176.4KHz from 11.2896 */ - { - configure_port_clock_output(p_bclk, clk_audio_mclk); - - /* Generate bit clock block straight from mclk */ - configure_clock_src(clk_audio_bclk, p_mclk_in); - } - else - { - /* bit clock port from master clock clock-clock block */ - configure_out_port_no_ready(p_bclk, clk_audio_mclk, 0); - - /* Generate bit clock block from pin */ - configure_clock_src(clk_audio_bclk, p_bclk); - } -#endif if(!isnull(p_lrclk)) { diff --git a/lib_xua/src/core/support/reboot.xc b/lib_xua/src/core/support/reboot.xc index e3f4eb2a..7c78928e 100644 --- a/lib_xua/src/core/support/reboot.xc +++ b/lib_xua/src/core/support/reboot.xc @@ -38,8 +38,6 @@ void device_reboot(void) /* Disconnect from bus */ unsigned data[] = {4}; write_periph_32(usb_tile, XS2_SU_PERIPH_USB_ID, XS1_GLX_PER_UIFM_FUNC_CONTROL_NUM, 1, data); -#elif defined(__XS3A__) - #warning Assuming that tile reset also resets USB in XS3 architectures #endif tileArrayLength = sizeof(tile)/sizeof(tileref); diff --git a/lib_xua/src/core/user/hid/user_hid.h b/lib_xua/src/core/user/hid/user_hid.h index 3fcb52ee..b17a4dd5 100644 --- a/lib_xua/src/core/user/hid/user_hid.h +++ b/lib_xua/src/core/user/hid/user_hid.h @@ -1,36 +1,60 @@ // Copyright 2013-2021 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. +/** + * @brief Human Interface Device (HID) API + * + * This file defines the Application Programming Interface (API) used to record HID + * events and retrieve a HID Report for sending to a host. + * The using application has the responsibility to fulfill this API. + * Document section numbers refer to the HID Device Class Definition, version 1.11. + */ + #ifndef __USER_HID_H__ #define __USER_HID_H__ +#include + /** * \brief HID event * - * This struct identifies the location within the HID Report for an event and - * The value to report for that location. + * This struct identifies: + * - the HID Report that reports an event, i.e., the ID, + * - the location within the HID Report for the event, i.e., the byte and bit, and + * - the value to report for that location (typically interpreted as a Boolean). * It assumes only single bit flags within the HID Report. */ typedef struct hidEvent_t { unsigned bit; unsigned byte; + unsigned id; unsigned value; } hidEvent_t; -#define HID_MAX_DATA_BYTES 4 +#define HID_MAX_DATA_BYTES ( 4 ) +#define HID_EVENT_INVALID_ID ( 0x100 ) #if( 0 < HID_CONTROLS ) /** - * \brief Get the data for the next HID report + * \brief Get the data for the next HID Report * * \note This function returns the HID data as a list of unsigned char because the * \c XUD_SetReady_In() accepts data for transmission to the USB Host using * this type. * - * \param{out} hidData The HID data + * \param[in] id The HID Report ID (see 5.6, 6.2.2.7, 8.1 and 8.2) + * Set to zero if the application provides only one HID Report + * which does not include a Report ID + * \param[out] hidData The HID data + * If using Report IDs, this function places the Report ID in + * the first element; otherwise the first element holds the + * first byte of HID event data. + * + * \returns The length of the HID Report in the \a hidData argument + * \retval Zero means no new HID event data has been recorded for the given \a id */ -void UserHIDGetData( unsigned char hidData[ HID_MAX_DATA_BYTES ]); +size_t UserHIDGetData( const unsigned id, unsigned char hidData[ HID_MAX_DATA_BYTES ]); /** * \brief Initialize HID processing @@ -40,15 +64,18 @@ void UserHIDInit( void ); /** * \brief Record that a HID event has occurred * - * \param{in} hidEvent A list of events which have occurred. - * Each element specifies a bit and byte in the HID Report and the value for it. - * \param{in} hidEventCnt The length of the \a hidEvent list. + * \param[in] hidEvent A list of events which have occurred. + * Each element specifies a HID Report ID, a bit and byte + * within the HID Report and the value for it. + * Set the Report ID to zero if not using Report IDs + * (see 5.6, 6.2.2.7, 8.1 and 8.2). + * \param[in] hidEventCnt The length of the \a hidEvent list. * - * \returns A Boolean flag indicating the status of the operation - * \retval False No recording of the event(s) occurred - * \retval True Recording of the event(s) occurred + * \returns The index of the first unrecorded event in \a hidEvent + * \retval Zero indicates no events were recorded + * \retval \a hidEventCnt indicates all events were recorded */ -unsigned UserHIDRecordEvent( const hidEvent_t hidEvent[], const unsigned hidEventCnt ); +size_t UserHIDRecordEvent( const hidEvent_t hidEvent[], const size_t hidEventCnt ); #endif /* ( 0 < HID_CONTROLS ) */ #endif /* __USER_HID_H__ */ diff --git a/lib_xua/src/dfu/dfu.xc b/lib_xua/src/dfu/dfu.xc index 43064281..849f4e28 100644 --- a/lib_xua/src/dfu/dfu.xc +++ b/lib_xua/src/dfu/dfu.xc @@ -11,11 +11,12 @@ #include "flash_interface.h" #include "dfu_interface.h" -#if defined(__XS3A__) -#define FLAG_ADDRESS 0xfffcc -#elif defined(__XS2A__) +#if defined(__XS2A__) /* Note range 0x7FFC8 - 0x7FFFF guarenteed to be untouched by tools */ #define FLAG_ADDRESS 0x7ffcc +#else +/* Note range 0xFFFC8 - 0xFFFFF guarenteed to be untouched by tools */ +#define FLAG_ADDRESS 0xfffcc #endif /* Store Flag to fixed address */ diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc index f3c741a1..0c09d609 100644 --- a/lib_xua/src/hid/hid.xc +++ b/lib_xua/src/hid/hid.xc @@ -7,38 +7,15 @@ #include "xud.h" #include "xud_std_requests.h" #include "xua_hid.h" +#include "xua_hid_report.h" #if( 0 < HID_CONTROLS ) -#define MS_IN_TICKS 100000U - -static unsigned s_hidChangePending = 0U; -static unsigned s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; -static unsigned s_hidIdleActive = 0U; -static unsigned s_hidIndefiniteDuration = 0U; -static unsigned s_hidNextReportTime = 0U; -static unsigned s_hidReportTime = 0U; - -unsafe { - volatile unsigned * unsafe s_hidChangePendingPtr = &s_hidChangePending; -} - static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ); static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ); static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ); static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t &sp ); static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ); -void HidCalcNextReportTime( void ) -{ - s_hidNextReportTime = s_hidReportTime + s_hidCurrentPeriod; -} - -void HidCaptureReportTime( void ) -{ - timer tmr; - tmr :> s_hidReportTime; -} - XUD_Result_t HidInterfaceClassRequests( XUD_ep c_ep0_out, XUD_ep c_ep0_in, @@ -58,41 +35,22 @@ XUD_Result_t HidInterfaceClassRequests( return result; } -void HidClearChangePending( void ) +unsigned HidIsSetIdleSilenced( const unsigned id ) { - unsafe { - *s_hidChangePendingPtr = 0U; - } -} + unsigned isSilenced = hidIsIdleActive( id ); -unsigned HidIsChangePending( void ) -{ - return( s_hidChangePending != 0 ); -} - -unsigned HidIsSetIdleSilenced( void ) -{ - unsigned isSilenced = s_hidIdleActive; - - if( s_hidIdleActive ) { + if( !isSilenced ) { unsigned currentTime; // Use inline assembly to access the time without creating a side-effect. // The mapper complains if the time comes from an XC timer because this function is called in the guard of a select case. // Appearently the use of a timer creates a side-effect that prohibits the operation of the select functionality. asm volatile( "gettime %0" : "=r" ( currentTime )); - isSilenced = ( s_hidIndefiniteDuration || ( timeafter( s_hidNextReportTime, currentTime ))); + isSilenced = ( 0U == hidGetReportPeriod( id ) || ( timeafter( hidGetNextReportTime( id ), currentTime ))); } return isSilenced; } -void HidSetChangePending( void ) -{ - unsafe { - *s_hidChangePendingPtr = 1; - } -} - /** * \brief Calculate the timer value for sending the next HID Report. * @@ -112,7 +70,7 @@ void HidSetChangePending( void ) */ static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ) { - unsigned nextReportTime = 0; + unsigned nextReportTime = 0U; if( HidFindSetIdleActivationPoint( currentPeriod, reportToSetIdleInterval )) { /* Activate immediately after sending the next HID Report */ @@ -171,6 +129,31 @@ static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, con return result; } +/** + * \brief Configure a hid report's next report time and idle status based on a setidle request + * + * \param[in] reportId -- The report ID to modify + * \param[in] reportDuration -- The duration of the setidle request + * + */ +static void HidUpdateReportPeriod( unsigned reportId, unsigned reportDuration ) { + unsigned currentPeriod = hidGetReportPeriod( reportId ); + + hidSetIdle( reportId, ( 0U == reportDuration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < reportDuration )); + + if( hidIsIdleActive( reportId )) { + unsigned reportTime = hidGetReportTime( reportId ); + unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( reportTime ); + unsigned nextReportTime = HidCalcNewReportTime( currentPeriod, reportTime, reportToSetIdleInterval, reportDuration * MS_IN_TICKS ); + hidSetNextReportTime( reportId, nextReportTime ); + currentPeriod = reportDuration * MS_IN_TICKS; + } else { + currentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; + } + + hidSetReportPeriod( reportId, currentPeriod ); +} + /** * \brief Process a Set Idle request * @@ -208,20 +191,24 @@ static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host. */ - if(( 0U == reportId ) && ( INTERFACE_NUMBER_HID == interfaceNum )) { - s_hidIdleActive = (( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration )); + if( INTERFACE_NUMBER_HID == interfaceNum ) { + if( hidIsReportIdValid( reportId ) ) { + HidUpdateReportPeriod( reportId, duration ); - if( s_hidIdleActive ) { - unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime ); - s_hidNextReportTime = HidCalcNewReportTime( s_hidCurrentPeriod, s_hidReportTime, reportToSetIdleInterval, duration * MS_IN_TICKS ); - s_hidCurrentPeriod = duration * MS_IN_TICKS; - s_hidIndefiniteDuration = ( 0U == duration ); - } else { - s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; - s_hidIndefiniteDuration = 0U; + result = XUD_DoSetRequestStatus( c_ep0_in ); } + else if ( reportId == 0U ) { + // Wildcard request - set all report IDs to idle + unsigned startReportId = hidGetNextValidReportId(reportId); - result = XUD_DoSetRequestStatus( c_ep0_in ); + reportId = startReportId; + do { + HidUpdateReportPeriod( reportId, duration ); + reportId = hidGetNextValidReportId( reportId ); + } while( reportId != startReportId); + + result = XUD_DoSetRequestStatus( c_ep0_in ); + } } return result; diff --git a/lib_xua/src/hid/hid_report.c b/lib_xua/src/hid/hid_report.c new file mode 100644 index 00000000..a647204e --- /dev/null +++ b/lib_xua/src/hid/hid_report.c @@ -0,0 +1,799 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include +#include +#include +#include + +#include "descriptor_defs.h" +#include "xua_hid_report.h" +#include "hid_report_descriptor.h" + + +#define HID_REPORT_ITEM_LOCATION_SIZE ( 1 ) +#define HID_REPORT_DESCRIPTOR_ITEM_COUNT ( sizeof hidReportDescriptorItems / sizeof ( USB_HID_Short_Item_t* )) +#define HID_REPORT_DESCRIPTOR_MAX_LENGTH ( HID_REPORT_DESCRIPTOR_ITEM_COUNT * \ + ( sizeof ( USB_HID_Short_Item_t ) - HID_REPORT_ITEM_LOCATION_SIZE )) +/* + * Each element in s_hidChangePending corresponds to an element in hidReports. + */ +static unsigned s_hidChangePending[ HID_REPORT_COUNT ]; +static unsigned char s_hidReportDescriptor[ HID_REPORT_DESCRIPTOR_MAX_LENGTH ]; +static size_t s_hidReportDescriptorLength; +static unsigned s_hidReportDescriptorPrepared; + +static unsigned s_hidCurrentPeriod[ HID_REPORT_COUNT ]; +static unsigned s_hidIdleActive[ HID_REPORT_COUNT ]; +static unsigned s_hidNextReportTime[ HID_REPORT_COUNT ]; +static unsigned s_hidReportTime[ HID_REPORT_COUNT ]; + +/** + * @brief Get the bit position from the location of a report element + * + * Parameters: + * + * @param[in] location The \c location field from a \c USB_HID_Report_Element_t + * + * @return The bit position of the report element + */ +static unsigned hidGetElementBitLocation( const unsigned short location ); + +/** + * @brief Get the byte position from the location of a report element + * + * Parameters: + * + * @param[in] location The \c location field from a \c USB_HID_Report_Element_t + * + * @return The byte position of the report element within the HID report + */ +static unsigned hidGetElementByteLocation( const unsigned short location ); + +/** + * @brief Get the report identifier from the location of a report element + * + * Parameters: + * + * @param[in] location The \c location field from a \c USB_HID_Report_Element_t + * + * @return The report id of the report element within the HID report + */ +static unsigned hidGetElementReportId( const unsigned short location ); + +/** + * @brief Get the report length from the location of a report element + * + * Parameters: + * + * @param[in] location The \c location field from a \c USB_HID_Report_Element_t + * + * @return The length of the HID report + */ +static size_t hidGetElementReportLength( const unsigned short location ); + +/** + * @brief Get the number of data bytes from the header of an Item + * + * Parameters: + * + * @param[in] header The \c header field from a \c USB_HID_Short_Item + * + * @return The amount of data for the Item + */ +static unsigned hidGetItemSize( const unsigned char header ); + +/** + * @brief Get the Tag from the header of an Item + * + * Parameters: + * + * @param[in] header The \c header field from a \c USB_HID_Short_Item + * + * @return The Tag of the Item + */ +static unsigned hidGetItemTag( const unsigned char header ); + +/** + * @brief Get the Type from the header of an Item + * + * Parameters: + * + * @param[in] header The \c header field from a \c USB_HID_Short_Item + * + * @return The Type of the Item + */ +static unsigned hidGetItemType( const unsigned char header ); + +/** + * @brief Get the Usage Page number for a given byte in the HID Report + * + * Parameters: + * + * @param[in] id The HID Report ID for the Usage Page. + * A value of zero means the application does not use Report IDs. + * + * @return The USB HID Usage Page code or zero if the \a id parameter is out-of-range + */ +static unsigned hidGetUsagePage( const unsigned id ); + +/** + * @brief Translate an Item from the \c USB_HID_Short_Item format to raw bytes + * + * Parameters: + * + * @param[in] inPtr A pointer to a \c USB_HID_Short_Item + * @param[in,out] outPtrPtr A pointer to a pointer to the next available space in the raw + * byte buffer. Passed as a pointer to a pointer to allow this + * function to return the updated pointer to the raw byte buffer. + * + * @return The number of bytes placed in the raw byte buffer + */ +static size_t hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char** outPtrPtr ); + + +void hidCalcNextReportTime( const unsigned id ) +{ + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + s_hidNextReportTime[ idx ] = s_hidReportTime[ idx ] + s_hidCurrentPeriod[ idx ]; + } + } +} + +void hidCaptureReportTime( const unsigned id, const unsigned time ) +{ + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + s_hidReportTime[ idx ] = time; + } + } +} + +void hidClearChangePending( const unsigned id ) +{ + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if(( id == 0U ) || ( id == hidGetElementReportId( hidReports[ idx ]->location ))) { + s_hidChangePending[ idx ] = 0U; + break; + } + } +} + +static unsigned hidGetElementBitLocation( const unsigned short location ) +{ + unsigned bBit = ( location & HID_REPORT_ELEMENT_LOC_BIT_MASK ) >> HID_REPORT_ELEMENT_LOC_BIT_SHIFT; + return bBit; +} + +static unsigned hidGetElementByteLocation( const unsigned short location ) +{ + unsigned bByte = ( location & HID_REPORT_ELEMENT_LOC_BYTE_MASK ) >> HID_REPORT_ELEMENT_LOC_BYTE_SHIFT; + return bByte; +} + +static unsigned hidGetElementReportId( const unsigned short location ) +{ + unsigned bReportId = ( location & HID_REPORT_ELEMENT_LOC_ID_MASK ) >> HID_REPORT_ELEMENT_LOC_ID_SHIFT; + return bReportId; +} + +static size_t hidGetElementReportLength( const unsigned short location ) +{ + size_t bReportLen = (size_t)( location & HID_REPORT_ELEMENT_LOC_LEN_MASK ) >> HID_REPORT_ELEMENT_LOC_LEN_SHIFT; + return bReportLen; +} + +static unsigned hidGetItemSize( const unsigned char header ) +{ + unsigned bSize = ( header & HID_REPORT_ITEM_HDR_SIZE_MASK ) >> HID_REPORT_ITEM_HDR_SIZE_SHIFT; + return bSize; +} + +static unsigned hidGetItemTag( const unsigned char header ) +{ + unsigned bTag = ( header & HID_REPORT_ITEM_HDR_TAG_MASK ) >> HID_REPORT_ITEM_HDR_TAG_SHIFT; + return bTag; +} + +static unsigned hidGetItemType( const unsigned char header ) +{ + unsigned bType = ( header & HID_REPORT_ITEM_HDR_TYPE_MASK ) >> HID_REPORT_ITEM_HDR_TYPE_SHIFT; + return bType; +} + +unsigned hidGetNextReportTime( const unsigned id ) { + unsigned retVal = 0U; + + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + retVal = s_hidNextReportTime[ idx ]; + } + } + return retVal; +} + +unsigned hidIsReportDescriptorPrepared( void ) +{ + return s_hidReportDescriptorPrepared; +} + +unsigned char* hidGetReportDescriptor( void ) +{ + unsigned char* retVal = NULL; + + if( s_hidReportDescriptorPrepared ) { + retVal = s_hidReportDescriptor; + } + + return retVal; +} + +size_t hidGetReportDescriptorLength( void ) +{ + size_t retVal = ( s_hidReportDescriptorPrepared ) ? s_hidReportDescriptorLength : 0U; + return retVal; +} + +unsigned hidGetReportIdLimit ( void ) { + unsigned retVal = 0U; + + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + unsigned reportId = hidGetElementReportId( hidReports[ idx ]->location ); + if( reportId >= retVal ) { + retVal = reportId + 1; + } + } + return retVal; +} + +unsigned hidIsReportIdInUse ( void ) { + if ( hidGetElementReportId( hidReports[ 0 ]->location ) ) { + return 1; + } + return 0; +} + +unsigned hidIsReportIdValid ( unsigned id ) { + size_t retVal = 0; + + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + unsigned reportId = hidGetElementReportId( hidReports[ idx ]->location ); + if( reportId == id ) { + retVal = 1; + break; + } + } + + return retVal; +} + +unsigned hidGetNextValidReportId ( unsigned idPrev ) { + size_t retIndex = 0; + + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + unsigned reportId = hidGetElementReportId( hidReports[ idx ]->location ); + if( reportId == idPrev ) { + retIndex = (idx + 1) % HID_REPORT_COUNT; + break; + } + } + + return hidGetElementReportId( hidReports[ retIndex ]->location ); +} + +#define HID_CONFIGURABLE_ELEMENT_COUNT ( sizeof hidConfigurableElements / sizeof ( USB_HID_Report_Element_t* )) +unsigned hidGetReportItem( + const unsigned id, + const unsigned byte, + const unsigned bit, + unsigned char* const page, + unsigned char* const header, + unsigned char data[] +) +{ + unsigned retVal = HID_STATUS_BAD_ID; + for( size_t elementIdx = 0U; elementIdx < HID_CONFIGURABLE_ELEMENT_COUNT; ++elementIdx ) { + USB_HID_Report_Element_t element = *hidConfigurableElements[ elementIdx ]; + unsigned bBit = hidGetElementBitLocation( element.location ); + unsigned bByte = hidGetElementByteLocation( element.location ); + unsigned bId = hidGetElementReportId( element.location ); + + if( id == bId ) { + retVal = HID_STATUS_BAD_LOCATION; + + if(( bit == bBit ) && ( byte == bByte )) { + *page = hidGetUsagePage( id ); + *header = element.item.header; + + for( size_t dataIdx = 0U; dataIdx < HID_REPORT_ITEM_MAX_SIZE; ++data, ++dataIdx ) { + *data = element.item.data[ dataIdx ]; + } + + retVal = HID_STATUS_GOOD; + break; + } + } + } + return retVal; +} + +size_t hidGetReportLength( const unsigned id ) +{ + size_t retVal = 0U; + if( s_hidReportDescriptorPrepared ) { + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + retVal = hidGetElementReportLength( hidReports[ idx ]->location ); + } + } + } + return retVal; +} + +unsigned hidGetReportPeriod( const unsigned id ) +{ + unsigned retVal = 0U; + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + retVal = s_hidCurrentPeriod[ idx ]; + break; + } + } + return retVal; +} + +unsigned hidGetReportTime( const unsigned id ) { + unsigned retVal = 0U; + + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + retVal = s_hidReportTime[ idx ]; + } + } + return retVal; +} + +static unsigned hidGetUsagePage( const unsigned id ) +{ + unsigned retVal = 0U; + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + retVal = hidReports[ idx ]->item.data[ 0 ]; + break; + } + } + return retVal; +} + +unsigned hidIsChangePending( const unsigned id ) +{ + unsigned retVal = 0U; + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if( id == 0U && s_hidChangePending[ idx ] != 0U ) { + retVal = 1; + } else if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + retVal = ( s_hidChangePending[ idx ] != 0U ); + break; + } + } + return retVal; +} + +unsigned hidIsIdleActive( const unsigned id ) +{ + unsigned retVal = 0U; + if( 0U == id ) { + retVal = 1U; + } + + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if( id == 0U ) { + retVal &= ( s_hidIdleActive[ idx ] != 0U ); + } else if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + retVal = ( s_hidIdleActive[ idx ] != 0U ); + break; + } + } + return retVal; +} + +void hidPrepareReportDescriptor( void ) +{ + if( !s_hidReportDescriptorPrepared ) { + s_hidReportDescriptorLength = 0U; + unsigned char* ptr = s_hidReportDescriptor; + + for( size_t idx = 0U; idx < HID_REPORT_DESCRIPTOR_ITEM_COUNT; ++idx ) { + s_hidReportDescriptorLength += hidTranslateItem( hidReportDescriptorItems[ idx ], &ptr ); + } + + s_hidReportDescriptorPrepared = 1U; + } +} + +void hidReportInit( void ) +{ + for( unsigned idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + s_hidCurrentPeriod[ idx ] = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; + } + memset( s_hidIdleActive, 0, sizeof( s_hidIdleActive ) ); + memset( s_hidChangePending, 0, sizeof( s_hidChangePending ) ); +} + +void hidResetReportDescriptor( void ) +{ + s_hidReportDescriptorPrepared = 0U; +} + +void hidSetChangePending( const unsigned id ) +{ + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + s_hidChangePending[ idx ] = 1U; + break; + } + } +} + +void hidSetIdle( const unsigned id, const unsigned state ) +{ + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + s_hidIdleActive[ idx ] = ( state != 0U ); + break; + } + } +} + +void hidSetNextReportTime( const unsigned id, const unsigned time ) +{ + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx ) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + s_hidNextReportTime[ idx ] = time; + } + } +} + +unsigned hidSetReportItem( + const unsigned id, + const unsigned byte, + const unsigned bit, + const unsigned char page, + const unsigned char header, + const unsigned char data[] +) +{ + unsigned retVal = HID_STATUS_IN_USE; + + if( !s_hidReportDescriptorPrepared ) { + retVal = HID_STATUS_BAD_ID; + unsigned bSize = hidGetItemSize( header ); + unsigned bTag = hidGetItemTag ( header ); + unsigned bType = hidGetItemType( header ); + + if(( HID_REPORT_ITEM_MAX_SIZE < bSize ) || + ( HID_REPORT_ITEM_USAGE_TAG != bTag ) || + ( HID_REPORT_ITEM_USAGE_TYPE != bType )) { + retVal = HID_STATUS_BAD_HEADER; + } else { + for( size_t elementIdx = 0U; elementIdx < HID_CONFIGURABLE_ELEMENT_COUNT; ++elementIdx ) { + USB_HID_Report_Element_t element = *hidConfigurableElements[ elementIdx ]; + unsigned bBit = hidGetElementBitLocation( element.location ); + unsigned bByte = hidGetElementByteLocation( element.location ); + unsigned bId = hidGetElementReportId( element.location ); + + if( id == bId ) { + retVal = HID_STATUS_BAD_PAGE; + unsigned pg = hidGetUsagePage( id ); + + if( page == pg ) { + retVal = HID_STATUS_BAD_LOCATION; + + if(( bit == bBit ) && ( byte == bByte )) { + element.item.header = header; + + for( size_t dataIdx = 0U; dataIdx < bSize; ++dataIdx ) { + element.item.data[ dataIdx ] = data[ dataIdx ]; + } + + for( size_t dataIdx = bSize; dataIdx < HID_REPORT_ITEM_MAX_SIZE; ++dataIdx ) { + element.item.data[ dataIdx ] = 0U; + } + + *hidConfigurableElements[ elementIdx ] = element; + retVal = HID_STATUS_GOOD; + break; + } + } + } + } + } + } + + return retVal; +} + +void hidSetReportPeriod( const unsigned id, const unsigned period ) +{ + for( size_t idx = 0U; idx < HID_REPORT_COUNT; ++idx) { + if( id == hidGetElementReportId( hidReports[ idx ]->location )) { + s_hidCurrentPeriod[ idx ] = period; + break; + } + } +} + +static size_t hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char** outPtrPtr ) +{ + size_t count = 0U; + *(*outPtrPtr)++ = inPtr->header; + ++count; + + unsigned dataLength = hidGetItemSize( inPtr->header ); + for( size_t idx = 0U; idx < dataLength; ++idx ) { + *(*outPtrPtr)++ = inPtr->data[ idx ]; + ++count; + } + + return count; +} + +// hid_report_descriptor.h validation functions for development purposes + +/** + * @brief Internal HID Report Descriptor validation state + */ +struct HID_validation_info { + int collectionOpenedCount; //!< Current count of open collections (to track that they are all closed) + int reportCount; //!< Current count of defined reports (to count them) + + int currentReportIdx; //!< Index of current report in hidReports array + int currentConfigurableElementIdx; //!< Index of current configurable element in hidConfigurableElements array + + unsigned char reportIds[HID_REPORT_COUNT]; // Array of report IDs (for general validation & duplication detection) + unsigned reportUsagePage[HID_REPORT_COUNT]; // Array of the usage page for each report (for general validation) + + unsigned current_bit_size; // State tracker for the current set report bit width (todo: should technically be a stack) + unsigned current_bit_count; // State tracker for the current set report count (todo: should technically be a stack) + unsigned current_bit_offset; // Current bit offset into this report (for location validation) +}; + +/** + * @brief Validation step for hidReportValidate, checking the info struct to ensure correctness of Report IDs + * + * @param info The info struct that has been built by hidReportValidate to check + * @return unsigned HID_STATUS value + */ +static unsigned hidReportValidateInfoStructReportIDs( struct HID_validation_info *info ) { + if ( info->reportCount != HID_REPORT_COUNT) { + if ( !( info->reportCount == 0 && HID_REPORT_COUNT == 1 ) ) { + // (Only if report IDs are being used) + printf("Error: The number of actual reports does not match HID_REPORT_COUNT.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + } + for ( size_t idx1 = 0; idx1 < HID_REPORT_COUNT; ++idx1 ) { + for ( size_t idx2 = idx1 + 1; idx2 < HID_REPORT_COUNT; ++idx2 ) { + if ( info->reportIds[idx1] == info->reportIds[idx2] ) { + printf("Error: Duplicate report ID 0x%02x.\n", info->reportIds[idx1]); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + } + } + for ( size_t idx = 0; idx < HID_REPORT_COUNT; ++idx ) { + if ( info->reportIds[idx] != hidGetElementReportId( hidReports[idx]->location ) ) { + printf("Error: Report ID in descriptor does not match report ID in hidReports.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + if ( info->reportCount && info->reportIds[idx] == 0 ) { + printf("Error: Report ID 0 is invalid.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + } + return HID_STATUS_GOOD; +} + +/** + * @brief Validation step for hidReportValidate, checking reports are the correct length specified in their location field + * + * @param info The info struct that has been built by hidReportValidate to check + * @return unsigned HID_STATUS value + */ +static unsigned hidReportValidateInfoStructReportLength( struct HID_validation_info *info ) { + if ( info->current_bit_offset % 8 ) { + printf("Error: HID Report not byte aligned (%d bits).\n", info->current_bit_offset); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + if ( ( info->current_bit_offset / 8 ) != hidGetElementReportLength( hidReports[info->currentReportIdx]->location ) ) { + printf("Error: Actual report length does not match value in location field %d != %d.\n", + ( info->current_bit_offset / 8 ), + hidGetElementReportLength( hidReports[info->currentReportIdx]->location )); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + return HID_STATUS_GOOD; +} + +/** + * @brief Validation step for hidReportValidate, collections are correctly opened and closed + * + * @param info The info struct that has been built by hidReportValidate to check + * @return unsigned HID_STATUS value + */ +static unsigned hidReportValidateInfoStructCollections( struct HID_validation_info *info ) { + if ( info->collectionOpenedCount ) { + printf("Error: Collections not equally opened and closed.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + return HID_STATUS_GOOD; +} + +/** + * @brief Validation step for hidReportValidate, High level - Checks the summarised information in the info struct by calling + * the subroutines for checking. + * + * @param info The info struct that has been built by hidReportValidate to check + * @return unsigned HID_STATUS value + */ +static unsigned hidReportValidateInfoStruct( struct HID_validation_info *info ) { + unsigned status = hidReportValidateInfoStructCollections( info ); + if( status == HID_STATUS_GOOD ) { + status = hidReportValidateInfoStructReportIDs( info ); + } + if( status == HID_STATUS_GOOD ) { + status = hidReportValidateInfoStructReportLength( info ); + } + return status; +} + +/** + * @brief Preparation step for hidReportValidate, Adds a report ID field into the information struct for validation + * + * @param info The info struct being built by hidReportValidate + * @param item The ReportId item being added + * @return unsigned HID_STATUS value + */ +static unsigned hidReportValidateAddReportId( struct HID_validation_info *info, const USB_HID_Short_Item_t *item ) { + if ( info->reportCount == 0 ) { + if ( info->current_bit_offset ) { + printf("Error: Some elements not associated with report ID.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + info->reportUsagePage[0] = 0; + } else { + unsigned status = hidReportValidateInfoStructReportLength( info ); + if ( status ) { + return status; + } + } + + if ( hidGetItemSize(item->header) != 1 ) { + printf("Error: ReportId field has invalid length %d (expected 1)\n", hidGetItemSize(item->header)); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + + info->reportIds[info->reportCount] = item->data[0]; + info->currentReportIdx = info->reportCount; + info->reportCount += 1; + info->current_bit_offset = 0; + if ( info->reportCount > HID_REPORT_COUNT ) { + printf("Error: HID_REPORT_COUNT does not match number of report IDs in descriptor.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + + return HID_STATUS_GOOD; +} + +/** + * @brief Preparation step for hidReportValidate, Adds a Usage Page field into the information struct for validation + * + * @param info The info struct being built by hidReportValidate + * @param item The UsagePage item being added + * @return unsigned HID_STATUS value + */ +static unsigned hidReportValidateAddUsagePageItem( struct HID_validation_info *info, const USB_HID_Short_Item_t *item ) { + + if ( info->collectionOpenedCount == 0 ) { + return HID_STATUS_GOOD; + } + if ( info->reportUsagePage[info->currentReportIdx] ) { + printf("Error: Multiple usage pages per report ID not supported by this implementation.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + + switch (hidGetItemSize(item->header)){ + case 1: + info->reportUsagePage[info->currentReportIdx] = item->data[0]; + break; + case 2: + info->reportUsagePage[info->currentReportIdx] = ((unsigned) item->data[1] << 8) + item->data[0]; + break; + default: + printf("Error: Invalid size for UsagePage report descriptor item.\n"); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + + return HID_STATUS_GOOD; +} + +/** + * @brief Preparation step for hidReportValidate, Adds a Usage field into the information struct for validation + * + * @param info The info struct being built by hidReportValidate + * @param item The Usage item being added + * @return unsigned HID_STATUS value + */ +static unsigned hidReportValidateAddUsageItem( struct HID_validation_info *info, const USB_HID_Short_Item_t *item) { + if ( ( info->currentConfigurableElementIdx < HID_CONFIGURABLE_ELEMENT_COUNT ) && + ( &(hidConfigurableElements[info->currentConfigurableElementIdx]->item) == item ) ) { + + USB_HID_Report_Element_t *element = hidConfigurableElements[info->currentConfigurableElementIdx]; + unsigned bBit = hidGetElementBitLocation( element->location ); + unsigned bByte = hidGetElementByteLocation( element->location ); + unsigned bReportId = hidGetElementReportId( element->location ); + + if ( bBit != ( info->current_bit_offset % 8 ) || bByte != ( info->current_bit_offset / 8 ) ) { + printf("Error: Locator bit/byte setting incorrect for configurable element index %d.\n", info->currentConfigurableElementIdx); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + if ( bReportId != info->reportIds[info->currentReportIdx] ) { + printf("Error: Locator report ID setting incorrect for configurable element index %d.\n", info->currentConfigurableElementIdx); + return HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + + info->currentConfigurableElementIdx += 1; + } + return HID_STATUS_GOOD; +} + +unsigned hidReportValidate( void ) +{ + struct HID_validation_info info = {}; + unsigned status = HID_STATUS_GOOD; + + // Fill in the validation info struct by iterating through the hid report items + for ( size_t idx = 0; idx < HID_REPORT_DESCRIPTOR_ITEM_COUNT; ++idx ) { + const USB_HID_Short_Item_t *item = hidReportDescriptorItems[idx]; + unsigned bTag = hidGetItemTag ( item->header ); + unsigned bType = hidGetItemType( item->header ); + + if ( bTag == HID_REPORT_ITEM_TAG_COLLECTION && bType == HID_REPORT_ITEM_TYPE_MAIN ) { + info.collectionOpenedCount += 1; + } + else if ( bTag == HID_REPORT_ITEM_TAG_END_COLLECTION && bType == HID_REPORT_ITEM_TYPE_MAIN ) { + info.collectionOpenedCount -= 1; + if ( info.collectionOpenedCount < 0 ) { + printf("Error: Collection closed while there is no collection open.\n"); + status = HID_STATUS_BAD_REPORT_DESCRIPTOR; + } + } + else if ( bTag == HID_REPORT_ITEM_TAG_INPUT && bType == HID_REPORT_ITEM_TYPE_MAIN ) { + info.current_bit_offset += (info.current_bit_size * info.current_bit_count); + } + else if ( bTag == HID_REPORT_ITEM_TAG_REPORT_SIZE && bType == HID_REPORT_ITEM_TYPE_GLOBAL ) { + info.current_bit_size = item->data[0]; + } + else if ( bTag == HID_REPORT_ITEM_TAG_REPORT_COUNT && bType == HID_REPORT_ITEM_TYPE_GLOBAL ) { + info.current_bit_count = item->data[0]; + } + else if ( bTag == HID_REPORT_ITEM_TAG_REPORT_ID && bType == HID_REPORT_ITEM_TYPE_GLOBAL ) { + status = hidReportValidateAddReportId( &info, item ); + } + else if ( bTag == HID_REPORT_ITEM_TAG_USAGE_PAGE && bType == HID_REPORT_ITEM_TYPE_GLOBAL ) { + status = hidReportValidateAddUsagePageItem( &info, item ); + } + else if ( bTag == HID_REPORT_ITEM_TAG_USAGE && bType == HID_REPORT_ITEM_TYPE_LOCAL ) { + status = hidReportValidateAddUsageItem( &info, item ); + } + + if ( status ) { + break; + } + } + + if(status) { + return status; + } else { + return hidReportValidateInfoStruct( &info ); + } +} \ No newline at end of file diff --git a/lib_xua/src/hid/hid_report_descriptor.c b/lib_xua/src/hid/hid_report_descriptor.c deleted file mode 100644 index 1b899aaf..00000000 --- a/lib_xua/src/hid/hid_report_descriptor.c +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2021 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. -#include -#include -#include -#include "xua_hid_report_descriptor.h" -#include "hid_report_descriptor.h" - -#include - -#define HID_REPORT_ITEM_LOCATION_SIZE ( 1 ) -#define HID_REPORT_DESCRIPTOR_ITEM_COUNT ( sizeof hidReportDescriptorItems / sizeof ( USB_HID_Short_Item_t* )) -#define HID_REPORT_DESCRIPTOR_MAX_LENGTH ( HID_REPORT_DESCRIPTOR_ITEM_COUNT * \ - ( sizeof ( USB_HID_Short_Item_t ) - HID_REPORT_ITEM_LOCATION_SIZE )) - -static unsigned char hidReportDescriptor[ HID_REPORT_DESCRIPTOR_MAX_LENGTH ]; -static size_t hidReportDescriptorLength = 0; -static unsigned hidReportDescriptorPrepared = 0; - -/** - * @brief Get the bit position from the location of an Item - * - * Parameters: - * - * @param[in] location The \c location field from a \c USB_HID_Short_Item - * - * @return The bit position of the Item - */ -static unsigned hidGetItemBitLocation( const unsigned char header ); - -/** - * @brief Get the byte position from the location of an Item - * - * Parameters: - * - * @param[in] location The \c location field from a \c USB_HID_Short_Item - * - * @return The byte position of the Item within the HID Report - */ -static unsigned hidGetItemByteLocation( const unsigned char header ); - -/** - * @brief Get the number of data bytes from the header of an Item - * - * Parameters: - * - * @param[in] header The \c header field from a \c USB_HID_Short_Item - * - * @return The amount of data for the Item - */ -static unsigned hidGetItemSize( const unsigned char header ); - -/** - * @brief Get the Tag from the header of an Item - * - * Parameters: - * - * @param[in] header The \c header field from a \c USB_HID_Short_Item - * - * @return The Tag of the Item - */ -static unsigned hidGetItemTag( const unsigned char header ); - -/** - * @brief Get the Type from the header of an Item - * - * Parameters: - * - * @param[in] header The \c header field from a \c USB_HID_Short_Item - * - * @return The Type of the Item - */ -static unsigned hidGetItemType( const unsigned char header ); - -/** - * @brief Get the Usage Page number for a given byte in the HID Report - * - * Parameters: - * - * @param[in] byte The byte location in the HID Report - * - * @return The USB HID Usage Page code or zero if the \a byte parameter is out-of-range - */ -static unsigned hidGetUsagePage( const unsigned byte ); - -/** - * @brief Translate an Item from the \c USB_HID_Short_Item format to raw bytes - * - * Parameters: - * - * @param[in] inPtr A pointer to a \c USB_HID_Short_Item - * @param[in,out] outPtrPtr A pointer to a pointer to the next available space in the raw - * byte buffer. Passed as a pointer to a pointer to allow this - * function to return the updated pointer to the raw byte buffer. - * - * @return The number of bytes placed in the raw byte buffer - */ -static size_t hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char** outPtrPtr ); - - -static unsigned hidGetItemBitLocation( const unsigned char location ) -{ - unsigned bBit = ( location & HID_REPORT_ITEM_LOC_BIT_MASK ) >> HID_REPORT_ITEM_LOC_BIT_SHIFT; - return bBit; -} - -static unsigned hidGetItemByteLocation( const unsigned char location ) -{ - unsigned bByte = ( location & HID_REPORT_ITEM_LOC_BYTE_MASK ) >> HID_REPORT_ITEM_LOC_BYTE_SHIFT; - return bByte; -} - -static unsigned hidGetItemSize( const unsigned char header ) -{ - unsigned bSize = ( header & HID_REPORT_ITEM_HDR_SIZE_MASK ) >> HID_REPORT_ITEM_HDR_SIZE_SHIFT; - return bSize; -} - -static unsigned hidGetItemTag( const unsigned char header ) -{ - unsigned bTag = ( header & HID_REPORT_ITEM_HDR_TAG_MASK ) >> HID_REPORT_ITEM_HDR_TAG_SHIFT; - return bTag; -} - -static unsigned hidGetItemType( const unsigned char header ) -{ - unsigned bType = ( header & HID_REPORT_ITEM_HDR_TYPE_MASK ) >> HID_REPORT_ITEM_HDR_TYPE_SHIFT; - return bType; -} - -unsigned char* hidGetReportDescriptor( void ) -{ - unsigned char* retVal = NULL; - - if( hidReportDescriptorPrepared ) { - retVal = hidReportDescriptor; - } - - return retVal; -} - -size_t hidGetReportDescriptorLength( void ) -{ - size_t retVal = ( hidReportDescriptorPrepared ) ? hidReportDescriptorLength : 0; - return retVal; -} - -#define HID_CONFIGURABLE_ITEM_COUNT ( sizeof hidConfigurableItems / sizeof ( USB_HID_Short_Item_t* )) -unsigned hidGetReportItem( - const unsigned byte, - const unsigned bit, - unsigned char* const page, - unsigned char* const header, - unsigned char data[] -) -{ - unsigned retVal = HID_STATUS_BAD_LOCATION; - for( unsigned itemIdx = 0; itemIdx < HID_CONFIGURABLE_ITEM_COUNT; ++itemIdx ) { - USB_HID_Short_Item_t item = *hidConfigurableItems[ itemIdx ]; - unsigned bBit = hidGetItemBitLocation( item.location ); - unsigned bByte = hidGetItemByteLocation( item.location ); - - if(( bit == bBit ) && ( byte == bByte )) { - *page = hidGetUsagePage( byte ); - *header = item.header; - - for( unsigned dataIdx = 0; dataIdx < HID_REPORT_ITEM_MAX_SIZE; ++data, ++dataIdx ) { - *data = item.data[ dataIdx ]; - } - - retVal = HID_STATUS_GOOD; - break; - } - } - return retVal; -} - -size_t hidGetReportLength( void ) -{ - size_t retVal = ( hidReportDescriptorPrepared ) ? HID_REPORT_LENGTH : 0; - return retVal; -} - -static unsigned hidGetUsagePage( const unsigned byte ) -{ - unsigned retVal = ( byte < HID_REPORT_LENGTH ) ? hidUsagePages[ byte ]->data[ 0 ] : 0; - return retVal; -} - -void hidPrepareReportDescriptor( void ) -{ - if( !hidReportDescriptorPrepared ) { - hidReportDescriptorLength = 0; - unsigned char* ptr = hidReportDescriptor; - for( unsigned idx = 0; idx < HID_REPORT_DESCRIPTOR_ITEM_COUNT; ++idx ) { - hidReportDescriptorLength += hidTranslateItem( hidReportDescriptorItems[ idx ], &ptr ); - } - - hidReportDescriptorPrepared = 1; - } -} - -void hidResetReportDescriptor( void ) -{ - hidReportDescriptorPrepared = 0; -} - -unsigned hidSetReportItem( - const unsigned byte, - const unsigned bit, - const unsigned char page, - const unsigned char header, - const unsigned char data[] -) -{ - unsigned retVal = HID_STATUS_IN_USE; - - if( !hidReportDescriptorPrepared ) { - retVal = HID_STATUS_BAD_LOCATION; - unsigned bSize = hidGetItemSize( header ); - unsigned bTag = hidGetItemTag ( header ); - unsigned bType = hidGetItemType( header ); - - if(( HID_REPORT_ITEM_MAX_SIZE < bSize ) || - ( HID_REPORT_ITEM_USAGE_TAG != bTag ) || - ( HID_REPORT_ITEM_USAGE_TYPE != bType )) { - retVal = HID_STATUS_BAD_HEADER; - } else { - for( unsigned itemIdx = 0; itemIdx < HID_CONFIGURABLE_ITEM_COUNT; ++itemIdx ) { - USB_HID_Short_Item_t item = *hidConfigurableItems[ itemIdx ]; - unsigned bBit = hidGetItemBitLocation( item.location ); - unsigned bByte = hidGetItemByteLocation( item.location ); - - if(( bit == bBit ) && ( byte == bByte )) { - unsigned pg = hidGetUsagePage( byte ); - - if( page == pg ) { - item.header = header; - - for( unsigned dataIdx = 0; dataIdx < bSize; ++dataIdx ) { - item.data[ dataIdx ] = data[ dataIdx ]; - } - - for( unsigned dataIdx = bSize; dataIdx < HID_REPORT_ITEM_MAX_SIZE; ++dataIdx ) { - item.data[ dataIdx ] = 0; - } - - *hidConfigurableItems[ itemIdx ] = item; - retVal = HID_STATUS_GOOD; - } else { - retVal = HID_STATUS_BAD_PAGE; - } - - break; - } - } - } - } - - return retVal; -} - -static size_t hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char** outPtrPtr ) -{ - size_t count = 0; - *(*outPtrPtr)++ = inPtr->header; - ++count; - - unsigned dataLength = hidGetItemSize( inPtr->header ); - for( unsigned idx = 0; idx < dataLength; ++idx ) { - *(*outPtrPtr)++ = inPtr->data[ idx ]; - ++count; - } - - return count; -} diff --git a/lib_xua/src/hid/xua_hid.h b/lib_xua/src/hid/xua_hid.h index 1344b5a2..6e5d31b2 100644 --- a/lib_xua/src/hid/xua_hid.h +++ b/lib_xua/src/hid/xua_hid.h @@ -1,6 +1,12 @@ // Copyright 2019-2021 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. +/** + * @brief Human Interface Device (HID) Class Request functions + * + * Document section numbers refer to the HID Device Class Definition, version 1.11. + */ + #ifndef __XUA_HID_H__ #define __XUA_HID_H__ @@ -9,49 +15,11 @@ #include "xud.h" #include "xud_std_requests.h" -/** - * \brief Calculate the next time to respond with a HID Report. - * - * If the USB Host has previously sent a valid HID Set_Idle request with - * a duration of zero or greater than the default reporting interval, - * the device sends HID Reports periodically or when the value of the - * payload has changed. - * - * This function calculates the time for sending the next periodic - * HID Report. - */ -void HidCalcNextReportTime( void ); - -/** - * \brief Capture the time of sending the current HID Report. - * - * If the USB Host has previously sent a valid HID Set_Idle request with - * a duration of zero or greater than the default reporting interval, - * the device sends HID Reports periodically or when the value of the - * payload has changed. - * - * This function captures the time when the HID Report was sent so that - * a subsequent call to HidCalNextReportTime() can calculate the time - * to send the next periodic HID Report. - */ -void HidCaptureReportTime( void ); - XUD_Result_t HidInterfaceClassRequests( XUD_ep c_ep0_out, XUD_ep c_ep0_in, REFERENCE_PARAM( USB_SetupPacket_t, sp )); -/** - * \brief Register that previously changed HID Report data has reported - * to the USB Host. - */ -void HidClearChangePending( void ); - -/** - * \brief Indicate if a change to the HID Report data has been received. - */ -unsigned HidIsChangePending( void ); - /** * \brief Indicate whether to send a HID Report based on elapsed time. * @@ -64,15 +32,15 @@ unsigned HidIsChangePending( void ); * whether or not the time to send the next periodic HID Report has * elapsed. * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * * \return A Boolean value indicating whether or not to send the HID Report. * \retval 1 -- Do not send the HID Report * \retval 0 -- Send the HID Report */ -unsigned HidIsSetIdleSilenced( void ); - -/** - * \brief Register that a change to the HID Report data has been received. - */ -void HidSetChangePending( void ); +unsigned HidIsSetIdleSilenced( const unsigned id ); #endif // __XUA_HID_H__ diff --git a/lib_xua/src/hid/xua_hid_report.h b/lib_xua/src/hid/xua_hid_report.h new file mode 100644 index 00000000..e05810da --- /dev/null +++ b/lib_xua/src/hid/xua_hid_report.h @@ -0,0 +1,556 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) Report descriptor + * + * This file defines the structure of the HID Report descriptor and declares + * functions for manipulating it. + * Because the Report descriptor defines the length of the HID Report, this file + * declares a function for obtaining the Report length as well. + * The using application has the responsibility to define the report descriptor + * structure and default contents in their hid_report_descriptor.h file. + * Document section numbers refer to the HID Device Class Definition, version 1.11. + */ + +#ifndef _XUA_HID_REPORT_ +#define _XUA_HID_REPORT_ + +#include + +#include "xua_hid_report_descriptor_constants.h" + +#define HID_REPORT_ITEM_HDR_SIZE_MASK ( 0x03 ) +#define HID_REPORT_ITEM_HDR_SIZE_SHIFT ( 0U ) + +#define HID_REPORT_ITEM_HDR_TAG_MASK ( 0xF0 ) +#define HID_REPORT_ITEM_HDR_TAG_SHIFT ( 4U ) + +#define HID_REPORT_ITEM_HDR_TYPE_MASK ( 0x0C ) +#define HID_REPORT_ITEM_HDR_TYPE_SHIFT ( 2U ) + +#define HID_REPORT_ELEMENT_LOC_BIT_MASK ( 0x0070 ) +#define HID_REPORT_ELEMENT_LOC_BIT_SHIFT ( 4U ) + +#define HID_REPORT_ELEMENT_LOC_BYTE_MASK ( 0x000F ) +#define HID_REPORT_ELEMENT_LOC_BYTE_SHIFT ( 0U ) + +#define HID_REPORT_ELEMENT_LOC_ID_MASK ( 0xF000 ) +#define HID_REPORT_ELEMENT_LOC_ID_SHIFT ( 12U ) + +#define HID_REPORT_ELEMENT_LOC_LEN_MASK ( 0x0F00 ) +#define HID_REPORT_ELEMENT_LOC_LEN_SHIFT ( 8U ) + +#define HID_REPORT_ITEM_MAX_SIZE ( 2U ) + +#define HID_REPORT_ITEM_USAGE_TAG ( 0U ) +#define HID_REPORT_ITEM_USAGE_TYPE ( 2U ) + +/** + * @brief Helper macro to configure the location field of USB_HID_Report_Element_t. + * + * @param id The report ID that this element is within. + * @param len (only relevant for the usage_page elements in hidReports) The length + * of the report under this report ID. + * @param byte The byte location of this element in the report. + * @param bit The bit location (within the byte) of this element in the report. + */ +#define HID_REPORT_SET_LOC(id, len, byte, bit) (\ + (( id << HID_REPORT_ELEMENT_LOC_ID_SHIFT ) & HID_REPORT_ELEMENT_LOC_ID_MASK ) | \ + (( len << HID_REPORT_ELEMENT_LOC_LEN_SHIFT ) & HID_REPORT_ELEMENT_LOC_LEN_MASK ) | \ + (( byte << HID_REPORT_ELEMENT_LOC_BYTE_SHIFT ) & HID_REPORT_ELEMENT_LOC_BYTE_MASK ) | \ + (( bit << HID_REPORT_ELEMENT_LOC_BIT_SHIFT ) & HID_REPORT_ELEMENT_LOC_BIT_MASK )) + +/** + * @brief Helper macro to configure the header field of USB_HID_Short_Item_t + * + * @param size The size of the report descriptor item (valid values: 0, 1, 2) + * @param type The type of the report descriptor item + * @param tag The tag + */ +#define HID_REPORT_SET_HEADER(size, type, tag) (\ + (( size << HID_REPORT_ITEM_HDR_SIZE_SHIFT) & HID_REPORT_ITEM_HDR_SIZE_MASK ) |\ + (( type << HID_REPORT_ITEM_HDR_TYPE_SHIFT) & HID_REPORT_ITEM_HDR_TYPE_MASK ) |\ + (( tag << HID_REPORT_ITEM_HDR_TAG_SHIFT ) & HID_REPORT_ITEM_HDR_TAG_MASK ) ) + +#define HID_STATUS_GOOD ( 0U ) +#define HID_STATUS_BAD_HEADER ( 1U ) +#define HID_STATUS_BAD_ID ( 2U ) +#define HID_STATUS_BAD_LOCATION ( 3U ) +#define HID_STATUS_BAD_PAGE ( 4U ) +#define HID_STATUS_IN_USE ( 5U ) +#define HID_STATUS_BAD_REPORT_DESCRIPTOR ( 6U ) + +#define MS_IN_TICKS 100000U + +/** + * @brief USB HID Report Descriptor Short Item + * + * @note + * To reduce memory use, this type does not support Short Items with 4 data bytes. + * See section 6.2.2.2 + * + * Elements: + * + * header - the item prefix containing the size, type and tag fields (see 6.2.2.2) + * Format (bit range): bSize (0:1), bType (2:3), bTag (4:7) + * data - a two byte array for holding the item's data + * The bSize field indicates which data bytes are in use + * id - a non-standard extension identifying the HID Report ID associated with + * the item (see 5.6, 6.2.2.7, 8.1 and 8.2) + * location - a non-standard extension locating the item within the HID Report + * Format (bit range): iByte (0:3), iBit (4:6), Reserved (7) + */ +typedef struct +{ + unsigned char header; + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; +} USB_HID_Short_Item_t; + +typedef struct +{ + USB_HID_Short_Item_t item; + unsigned short location; +} USB_HID_Report_Element_t; + +/** + * \brief Register that a previously changed HID Report data has been sent + * to the USB Host. + * + * HID processing maintains a list of HID Reports with changed data not yet + * reported to the USB Host. + * + * Applications that have only one HID Report may or may not use a Report ID. + * Applications that have more than one HID Report must use Report IDs. + * + * For applications that do not use Report IDs, the list contains one element. + * That element tracks whether or not an unreported change has occurred in the + * HID data. + * For applications that use Report IDs, the list contains one element per + * Report ID. + * Each element tracks unreported changes for the corresponding Report ID. + * + * Calling this function for a given Report ID indicates that the changed + * HID data has been reported to the USB Host. + * + * \warning This function will fail silently if given an id that is not + * either the value zero, or a Report ID that is in use. + * + * \param[in] id A HID Report ID. + * Zero clears the pending status of all Report IDs. + * Use zero if the application does not use Report IDs. + */ +void hidClearChangePending( const unsigned id ); + +/** + * @brief Indicate if the HID Report descriptor has been prepared + * + * \returns A Boolean indicating whether the HID Report descriptor has been prepared. + * \retval True The HID Report descriptor has been prepared. + * \retval False The HID Report descriptor has not been prepared. + */ + unsigned hidIsReportDescriptorPrepared( void ); + +/** + * @brief Get the HID Report descriptor + * + * This function returns a pointer to the USB HID Report descriptor. + * It returns NULL if the Report descriptor has not been prepared, + * i.e., no one has called \c hidPrepareReportDescriptor(). + * + * @note An XC-callable version of this function has not been provided. + * XC requires explicit declaration of the kind of pointer returned, + * hence an XC implementation of the function. + * + * @return A pointer to a list of unsigned char containing the Report descriptor + */ +#if !defined(__XC__) +unsigned char* hidGetReportDescriptor( void ); +#endif + +/** + * @brief Get the length of the HID Report descriptor + * + * This function returns the length of the USB HID Report descriptor. + * It returns zero if the Report descriptor has not been prepared, + * i.e., no one has called \c hidPrepareReportDescriptor(). + * + * @return The length of the Report descriptor in bytes + */ +size_t hidGetReportDescriptorLength( void ); + +/** + * \brief Get the upper limit of HID Report identifiers + * + * This function returns the upper limit of the HID Report identifiers. + * The upper limit has a value one greater than the maximum HID Report identifier. + * In the case that HID Report identifiers are not in use, this function returns the value 1. + * + * \returns The upper limit of HID Report identifiers + */ +unsigned hidGetReportIdLimit ( void ); + +/** + * @brief Does the application use Report IDs? + * + * If the application is not using Report IDs, then the id value that is passed around + * everywhere can just be zero. Otherwise zero is an invalid ID that has a special meaning + * in some cases (read the documentation for each function). + * + * @return Boolean + * @retval 1 Report IDs are in use + * @retval 0 Report IDs are not in use + */ +unsigned hidIsReportIdInUse ( void ); + +/** + * @brief Is the provided report ID valid for passing to other functions. + * + * e.g If Report IDs are not in use, then only 0 will return true. + * e.g If Report IDs are in use, then 0 will return false and the report IDs that + * are in use will return true when passed to thsi function. + * + * @param id The ID to check + * @return boolean + * @retval 0 The report ID is not valid, other functions may fail silently + * @retval 1 The report ID is valid and can be used as the argument to other functions + */ +unsigned hidIsReportIdValid ( unsigned id ); + +/** + * @brief Get the next valid report ID - iterator style. + * + * This function will loop around and start returning the first report ID again once it has + * returned all valid report IDs. + * + * @param idPrev The previous returned id, or 0 if this is the first call + * @return unsigned The next valid report ID. + */ +unsigned hidGetNextValidReportId ( unsigned idPrev ); + +/** + * @brief Get a HID Report descriptor item + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2). + * A value of zero means the application does not use Report IDs. + * @param[in] byte The byte position of the control within the HID Report + * @param[in] bit The bit position of the control within the \a byte + * @param[out] page The USB HID Usage Page code for the Item (see 5.5) + * @param[out] header The LSB of the Item containing the bSize, bType and bTag fields (see 6.2.2.2) + * @param[out] data A two element array containing data bytes for the Item + * + * @return A status value + * @retval \c HID_STATUS_GOOD Item successfully returned + * @retval \c HID_STATUS_BAD_ID The \a id argument specifies a non-existant HID Report + * @retval \c HID_STATUS_BAD_LOCATION The \a bit or \a byte arguments specify a location outside + * of the HID Report + */ +#if defined(__XC__) +unsigned hidGetReportItem( + const unsigned id, + const unsigned byte, + const unsigned bit, + unsigned char* unsafe const page, + unsigned char* unsafe const header, + unsigned char* unsafe const data); +#else +unsigned hidGetReportItem( + const unsigned id, + const unsigned byte, + const unsigned bit, + unsigned char* const page, + unsigned char* const header, + unsigned char data[]); +#endif + +/** + * \brief Calculate the next time to respond with a HID Report. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function calculates the time for sending the next periodic + * HID Report. + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + */ +void hidCalcNextReportTime( const unsigned id ); + +/** + * \brief Capture the time of sending the current HID Report. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function captures the time when the HID Report was sent so that + * a subsequent call to HidCalNextReportTime() can calculate the time + * to send the next periodic HID Report. + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @param[in] time The time when the HID Report for the given \a id was sent. + */ +void hidCaptureReportTime( const unsigned id, const unsigned time ); + +/** + * @brief Get the time to send the next HID Report for the given \a id + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @returns The time at which to send the next HID Report for the given \a id + */ +unsigned hidGetNextReportTime( const unsigned id ); + +/** + * @brief Get the length of the HID Report + * + * This function returns the length of the USB HID Report. + * It returns zero if the Report descriptor has not been prepared, + * i.e., no one has called \c hidPrepareReportDescriptor(), + * or if the \a id argument specifies a non-existent HID Report + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @return The length of the Report in bytes + */ +size_t hidGetReportLength( const unsigned id ); + +/** + * @brief Get the HID Report period for the given \a id + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @returns The period for the given HID Report \a id in units of ms. + * The value zero means the period is indefinite. + */ +unsigned hidGetReportPeriod( const unsigned id ); + +/** + * @brief Get the HID Report time for the given \a id + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @returns The time of the last call to \c hidCaptureReportTime() + */ +unsigned hidGetReportTime( const unsigned id ); + +/** + * \brief Indicate if a change to the HID Report data has been received. + * + * HID processing maintains a list of HID Reports with changed data not yet + * reported to the USB Host. + * + * Applications that have only one HID Report may or may not use a Report ID. + * Applications that have more than one HID Report must use Report IDs. + * + * For applications that do not use Report IDs, the list contains one element. + * That element tracks whether or not an unreported change has occurred in the + * HID data. + * For applications that use Report IDs, the list contains one element per + * Report ID. + * Each element tracks unreported changes for the corresponding Report ID. + * + * Calling this function with a given Report ID returns an indication of + * whether unreported HID data exists for that Report ID. + * + * \warning This function will return zero if given an id that is not + * either the value zero, or a Report ID that is in use. + * + * \param[in] id A HID Report ID. + * Zero reports the pending status of all Report IDs. + * Use zero if the application does not use Report IDs. + * + * \returns A Boolean indicating whether the given \a id has a changed + * HID Report not yet sent to the USB Host. + * \retval True The given \a id has changed HID Report data. + * For an \a id of zero, some HID Report has changed data. + * \retval False The given \a id does not have changed HID Report data. + * For an \a id of zero, no HID Report has changed data. + */ +unsigned hidIsChangePending( const unsigned id ); + +/** + * @brief Indicate if the HID report for the given \a id is idle + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero returns the collective Idle state. + * + * \returns A Boolean indicating whether the HID Report for the given \a id is idle. + * \retval True The HID Report is idle. + * For an \a id of zero, all HID Reports are idle. + * \retval False The HID Report is not idle. + * For an \a id of zero, at least one HID Report is not idle. + */ +unsigned hidIsIdleActive( const unsigned id ); + +/** + * @brief Prepare the USB HID Report descriptor + * + * After preparation, \c hidGetReportDescriptor() returns a list suitable for transmission over USB. + * Call this function after altering one or more Report Items using \c hidSetReportItem(). + */ +void hidPrepareReportDescriptor( void ); + +/** + * @brief Initialise the USB HID Report functionality + * + * Call this function before using any other functions in this API. + */ +void hidReportInit( void ); + +/** + * @brief Reset the USB HID Report descriptor + * + * After reset, \c hidGetReportDescriptor() returns NULL until a subsequent call to + * \c hidPrepareReportDescriptor() occurs. + * Call this function before altering one or more Report Items using \c hidSetReportItem(). + */ +void hidResetReportDescriptor( void ); + +/** + * \brief Register that a change to the HID Report data has been received. + * + * HID processing maintains a list of HID Reports with changed data not yet + * reported to the USB Host. + * + * Applications that have only one HID Report may or may not use a Report ID. + * Applications that have more than one HID Report must use Report IDs. + * + * For applications that do not use Report IDs, the list contains one element. + * That element tracks whether or not an unreported change has occurred in the + * HID data. + * For applications that use Report IDs, the list contains one element per + * Report ID. + * Each element tracks unreported changes for the corresponding Report ID. + * + * Calling this function with a given Report ID indicates that the HID data + * for that Report ID has changed and has not yet been reported to the USB + * Host. + * + * \warning This function will fail silently if given an id that is not + * either the value zero, or a Report ID that is in use. + * + * \param[in] id A HID Report ID. + * Use zero if the application does not use Report IDs. + */ +void hidSetChangePending( const unsigned id ); + +/** + * @brief Set the HID Report Idle state for the given \a id + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @param[in] state A Boolean indicating the Idle state + * If true, the HID Report for the given \a id is Idle, otherwise it + * is not Idle. + */ +void hidSetIdle( const unsigned id, const unsigned state ); + +/** + * @brief Set the time to send the HID Report for the given \a id + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @param[in] time The time to send the HID Report for the given \a id. + */ +void hidSetNextReportTime( const unsigned id, const unsigned time ); + +/** + * @brief Modify a HID Report descriptor item + * + * @warning This function does not check that the length of the \a data array matches the value of + * the bSize field in the \a header. For safe operation use a \a data array of at least + * \c HID_REPORT_ITEM_MAX_SIZE bytes in length. + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * @param[in] byte The byte position of the control within the HID Report + * @param[in] bit The bit position of the control within the \a byte + * @param[in] page The USB HID Usage Page code for the Item (see 5.5) + * @param[in] header The LSB of the Item containing the bSize, bType and bTag fields (see 6.2.2.2) + * @param[in] data An array containing data bytes or NULL for an Item with no data + * + * @return A status value + * @retval \c HID_STATUS_GOOD Item successfully updated + * @retval \c HID_STATUS_BAD_HEADER The Item header specified a data size greater than 2 or + * a Tag or Type inconsistent with a Usage Item + * @retval \c HID_STATUS_BAD_ID The \a id argument specifies a non-existent HID Report + * @retval \c HID_STATUS_BAD_LOCATION The \a bit or \a byte arguments specify a location outside + * of the HID Report + * @retval \c HID_STATUS_BAD_PAGE The \a byte argument specifies a location for controls from + * a Usage Page other than the one given by the \a page parameter + * @retval \c HID_STATUS_IN_USE The Report descriptor is in use + */ +unsigned hidSetReportItem( + const unsigned id, + const unsigned byte, + const unsigned bit, + const unsigned char page, + const unsigned char header, + const unsigned char data[]); + +/** + * @brief Set the HID Report period for the given \a id + * + * Parameters: + * + * @param[in] id The identifier for the HID Report (see 5.6, 6.2.2.7, 8.1 and 8.2) + * A value of zero means the application does not use Report IDs. + * + * @param[in] period The period for sending the HID Report in units of ms. + * This period must be a multiple of 4 ms. + * Use zero to indicate an indefinite period. + */ +void hidSetReportPeriod( const unsigned id, const unsigned period ); + +/** + * @brief Development function: Validate the contents of hid_report_descriptor.h for common errors, printing + * error messages if any issues were found. + * + * This function is intended for use when developing the contents of hid_report_descriptor.h, which is static, + * so shouldn't be required for use in a production application. + * + * @return Validation result + * @retval HID_STATUS_GOOD The validation found no issues with the data structures defined + * in hid_report_descriptor.h + * @retval HID_STATUS_BAD_REPORT_DESCRIPTOR The validation encountered an issue with the data structures + * defined in hid_report_descriptor.h . More information is + * provided in the printed messages. + */ +unsigned hidReportValidate( void ); + +#endif // _XUA_HID_REPORT_ diff --git a/lib_xua/src/hid/xua_hid_report_descriptor.h b/lib_xua/src/hid/xua_hid_report_descriptor.h deleted file mode 100644 index dc8878ae..00000000 --- a/lib_xua/src/hid/xua_hid_report_descriptor.h +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2021 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -/** - * @brief Human Interface Device (HID) Report descriptor - * - * This file defines the structure of the HID Report descriptor and declares - * functions for manipulating it. - * Because the Report descriptor defines the length of the HID Report, this file - * declares a function for obtaining the Report length as well. - * The using application has the responsibility to define the report descriptor - * structure and default contents in their hid_report_descriptor.h file. - * Document section numbers refer to the HID Device Class Definition, version 1.11. - */ - -#ifndef _HID_REPORT_DESCRIPTOR_ -#define _HID_REPORT_DESCRIPTOR_ - -#include - -#define HID_REPORT_ITEM_HDR_SIZE_MASK ( 0x03 ) -#define HID_REPORT_ITEM_HDR_SIZE_SHIFT ( 0 ) - -#define HID_REPORT_ITEM_HDR_TAG_MASK ( 0xF0 ) -#define HID_REPORT_ITEM_HDR_TAG_SHIFT ( 4 ) - -#define HID_REPORT_ITEM_HDR_TYPE_MASK ( 0x0C ) -#define HID_REPORT_ITEM_HDR_TYPE_SHIFT ( 2 ) - -#define HID_REPORT_ITEM_LOC_BIT_MASK ( 0x70 ) -#define HID_REPORT_ITEM_LOC_BIT_SHIFT ( 4 ) - -#define HID_REPORT_ITEM_LOC_BYTE_MASK ( 0x0F ) -#define HID_REPORT_ITEM_LOC_BYTE_SHIFT ( 0 ) - -#define HID_REPORT_ITEM_MAX_SIZE ( 2 ) - -#define HID_REPORT_ITEM_USAGE_TAG ( 0 ) -#define HID_REPORT_ITEM_USAGE_TYPE ( 2 ) - -#define HID_STATUS_GOOD ( 0 ) -#define HID_STATUS_BAD_HEADER ( 1 ) -#define HID_STATUS_BAD_LOCATION ( 2 ) -#define HID_STATUS_BAD_PAGE ( 3 ) -#define HID_STATUS_IN_USE ( 4 ) - -/** - * @brief USB HID Report Descriptor. Short Item - * - * @note - * To reduce memory use, this type does not support Short Items with 4 data bytes. - * See section 6.2.2.2 - * - * Elements: - * - * header - the item prefix containing the size, type and tag fields (see 6.2.2.2) - * Format (bit range): bSize (0:1), bType (2:3), bTag (4:7) - * data - a two byte array for holding the item's data - * The bSize field indicates which data bytes are in use - * location - a non-standard extension locating the item within the HID Report - * Format (bit range): iByte (0:3), iBit (4:6), Reserved (7) - */ -typedef struct -{ - unsigned char header; - unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; - unsigned char location; -} USB_HID_Short_Item_t; - -/** - * @brief Get the HID Report descriptor - * - * This function returns a pointer to the USB HID Report descriptor. - * It returns NULL if the Report descriptor has not been prepared, - * i.e., no one has called \c hidPrepareReportDescriptor(). - * - * @note An XC-callable version of this function has not been provided. - * XC requires explicit declaration of the kind of pointer returned, - * hence an XC implementation of the function. - * - * @return A pointer to a list of unsigned char containing the Report descriptor - */ -#if !defined(__XC__) -unsigned char* hidGetReportDescriptor( void ); -#endif - -/** - * @brief Get the length of the HID Report descriptor - * - * This function returns the length of the USB HID Report descriptor. - * It returns zero if the Report descriptor has not been prepared, - * i.e., no one has called \c hidPrepareReportDescriptor(). - * - * @return The length of the Report descriptor in bytes - */ -size_t hidGetReportDescriptorLength( void ); - -/** - * @brief Get a HID Report descriptor item - * - * Parameters: - * - * @param[in] byte The byte position of the control within the HID Report - * @param[in] bit The bit position of the control within the \a byte - * @param[out] page The USB HID Usage Page code for the Item (see 5.5) - * @param[out] header The LSB of the Item containing the bSize, bType and bTag fields (see 6.2.2.2) - * @param[out] data A two element array containing data bytes for the Item - * - * @return A status value - * @retval \c HID_STATUS_GOOD Item successfully returned - * @retval \c HID_STATUS_BAD_LOCATION The \a bit or \a byte arguments specify a location outside - * of the HID Report - */ -#if defined(__XC__) -unsigned hidGetReportItem( const unsigned byte, const unsigned bit, unsigned char* unsafe const page, unsigned char* unsafe const header, unsigned char* unsafe const data); -#else -unsigned hidGetReportItem( const unsigned byte, const unsigned bit, unsigned char* const page, unsigned char* const header, unsigned char data[]); -#endif - -/** - * @brief Get the length of the HID Report - * - * This function returns the length of the USB HID Report. - * It returns zero if the Report descriptor has not been prepared, - * i.e., no one has called \c hidPrepareReportDescriptor(). - * - * @return The length of the Report in bytes - */ -size_t hidGetReportLength( void ); - -/** - * @brief Prepare the USB HID Report descriptor - * - * After preparation, \c hidGetReportDescriptor() returns a list suitable for transmission over USB. - * Call this function after altering one or more Report Items using \c hidSetReportItem(). - */ -void hidPrepareReportDescriptor( void ); - -/** - * @brief Reset the USB HID Report descriptor - * - * After reset, \c hidGetReportDescriptor() returns NULL until a subsequent call to - * \c hidPrepareReportDescriptor() occurs. - * Call this function before altering one or more Report Items using \c hidSetReportItem(). - */ -void hidResetReportDescriptor( void ); - -/** - * @brief Modify a HID Report descriptor item - * - * @warning This function does not check that the length of the \a data array matches the value of - * the bSize field in the \a header. For safe operation use a \a data array of at least - * \c HID_REPORT_ITEM_MAX_SIZE bytes in length. - * - * Parameters: - * - * @param[in] byte The byte position of the control within the HID Report - * @param[in] bit The bit position of the control within the \a byte - * @param[in] page The USB HID Usage Page code for the Item (see 5.5) - * @param[in] header The LSB of the Item containing the bSize, bType and bTag fields (see 6.2.2.2) - * @param[in] data An array containing data bytes or NULL for an Item with no data - * - * @return A status value - * @retval \c HID_STATUS_GOOD Item successfully updated - * @retval \c HID_STATUS_BAD_HEADER The Item header specified a data size greater than 2 or - * a Tag or Type inconsistent with a Usage Item - * @retval \c HID_STATUS_BAD_LOCATION The \a bit or \a byte arguments specify a location outside - * of the HID Report - * @retval \c HID_STATUS_BAD_PAGE The \a byte argument specifies a location for controls from - * a Usage Page other than the one given by the \a page parameter - * @retval \c HID_STATUS_IN_USE The Report descriptor is in use - */ -unsigned hidSetReportItem( const unsigned byte, const unsigned bit, const unsigned char page, const unsigned char header, const unsigned char data[]); - -#endif // _HID_REPORT_DESCRIPTOR_ diff --git a/lib_xua/src/hid/xua_hid_report_descriptor_constants.h b/lib_xua/src/hid/xua_hid_report_descriptor_constants.h new file mode 100644 index 00000000..f35d7bd3 --- /dev/null +++ b/lib_xua/src/hid/xua_hid_report_descriptor_constants.h @@ -0,0 +1,66 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) Report descriptor constants + * + * This file defines a collection of constants from the USB HID documents. + * This includes constants from: + * - Device Class Definition for Human Interface Devices, version 1.11 + * - HID Usage Tables for Universal Serial Bus, version 1.22 + * + * This file is incomplete, but can be expanded with new constants as necessary. + */ + +#ifndef _XUA_HID_REPORT_DESCRIPTOR_CONSTANTS_ +#define _XUA_HID_REPORT_DESCRIPTOR_CONSTANTS_ + + +// Constants from the USB Device Class Definition for HID for type +#define HID_REPORT_ITEM_TYPE_MAIN ( 0x00 ) +#define HID_REPORT_ITEM_TYPE_GLOBAL ( 0x01 ) +#define HID_REPORT_ITEM_TYPE_LOCAL ( 0x02 ) +#define HID_REPORT_ITEM_TYPE_RESERVED ( 0x03 ) + +// Constants from the USB Device Class Definition for HID for tag +// Main items +#define HID_REPORT_ITEM_TAG_INPUT ( 0x08 ) +#define HID_REPORT_ITEM_TAG_OUTPUT ( 0x09 ) +#define HID_REPORT_ITEM_TAG_FEATURE ( 0x0B ) +#define HID_REPORT_ITEM_TAG_COLLECTION ( 0x0A ) +#define HID_REPORT_ITEM_TAG_END_COLLECTION ( 0x0C ) + +// Global items +#define HID_REPORT_ITEM_TAG_USAGE_PAGE ( 0x00 ) +#define HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM ( 0x01 ) +#define HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM ( 0x02 ) +#define HID_REPORT_ITEM_TAG_PHYSICAL_MINIMUM ( 0x03 ) +#define HID_REPORT_ITEM_TAG_PHYSICAL_MAXIMUM ( 0x04 ) +#define HID_REPORT_ITEM_TAG_UNIT_EXPONENT ( 0x05 ) +#define HID_REPORT_ITEM_TAG_UNIT ( 0x06 ) +#define HID_REPORT_ITEM_TAG_REPORT_SIZE ( 0x07 ) +#define HID_REPORT_ITEM_TAG_REPORT_ID ( 0x08 ) +#define HID_REPORT_ITEM_TAG_REPORT_COUNT ( 0x09 ) +#define HID_REPORT_ITEM_TAG_PUSH ( 0x0A ) +#define HID_REPORT_ITEM_TAG_POP ( 0x0B ) + +// Local items +#define HID_REPORT_ITEM_TAG_USAGE ( 0x00 ) +#define HID_REPORT_ITEM_TAG_USAGE_MINIMUM ( 0x01 ) +#define HID_REPORT_ITEM_TAG_USAGE_MAXIMUM ( 0x02 ) +#define HID_REPORT_ITEM_TAG_DESIGNATOR_INDEX ( 0x03 ) +#define HID_REPORT_ITEM_TAG_DESIGNATOR_MINIMUM ( 0x04 ) +#define HID_REPORT_ITEM_TAG_DESIGNATOR_MAXIMUM ( 0x05 ) +#define HID_REPORT_ITEM_TAG_STRING_INDEX ( 0x07 ) +#define HID_REPORT_ITEM_TAG_STRING_MINIMUM ( 0x08 ) +#define HID_REPORT_ITEM_TAG_STRING_MAXIMUM ( 0x09 ) +#define HID_REPORT_ITEM_TAG_DELIMITER ( 0x0A ) + +// Constants from HID Usage Tables +// Usage page IDs (incomplete) +#define USB_HID_USAGE_PAGE_ID_GENERIC_DESKTOP ( 0x01 ) +#define USB_HID_USAGE_PAGE_ID_KEYBOARD ( 0x07 ) +#define USB_HID_USAGE_PAGE_ID_TELEPHONY_DEVICE ( 0x0B ) +#define USB_HID_USAGE_PAGE_ID_CONSUMER ( 0x0C ) + +#endif // _XUA_HID_REPORT_DESCRIPTOR_CONSTANTS_ diff --git a/tests/xua_unit_tests/CMakeLists.txt b/tests/xua_unit_tests/CMakeLists.txt index 9e09a11b..9487a471 100644 --- a/tests/xua_unit_tests/CMakeLists.txt +++ b/tests/xua_unit_tests/CMakeLists.txt @@ -79,12 +79,10 @@ foreach( testsourcefile ${APP_SOURCES} ) set_target_properties(${ITEM_NAME} PROPERTIES OUTPUT_NAME ${ITEM_NAME}.xe) target_compile_options(${ITEM_NAME} PRIVATE ${APP_COMPILER_FLAGS}) - - - target_include_directories(${ITEM_NAME} - PRIVATE ${APP_INCLUDES} - PRIVATE ${XUA_INCLUDES_ALL} - ) + target_include_directories(${ITEM_NAME} + PRIVATE ${APP_INCLUDES} + PRIVATE ${XUA_INCLUDES_ALL} + ) target_sources(${ITEM_NAME} PRIVATE ${APP_SRCS} diff --git a/tests/xua_unit_tests/src/hid_report_descriptor.h b/tests/xua_unit_tests/src/hid_report_descriptor.h deleted file mode 100644 index a70075ba..00000000 --- a/tests/xua_unit_tests/src/hid_report_descriptor.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2021 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#ifndef __hid_report_descriptor_h__ -#define __hid_report_descriptor_h__ - -#include "xua_hid_report_descriptor.h" - -#define MAX_VALID_BIT ( 7 ) -#define MAX_VALID_BYTE ( 1 ) - -#define MIN_VALID_BIT ( 0 ) -#define MIN_VALID_BYTE ( 0 ) - -/* - * Define non-configurable items in the HID Report descriptor. - */ -static const USB_HID_Short_Item_t hidCollectionApplication = { .header = 0xA1, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidCollectionEnd = { .header = 0xC0, .data = { 0x00, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidCollectionLogical = { .header = 0xA1, .data = { 0x02, 0x00 }, .location = 0x00 }; - -static const USB_HID_Short_Item_t hidInputConstArray = { .header = 0x81, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidInputDataVar = { .header = 0x81, .data = { 0x02, 0x00 }, .location = 0x00 }; - -static const USB_HID_Short_Item_t hidLogicalMaximum0 = { .header = 0x25, .data = { 0x00, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMaximum1 = { .header = 0x25, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidLogicalMinimum0 = { .header = 0x15, .data = { 0x00, 0x00 }, .location = 0x00 }; - -static const USB_HID_Short_Item_t hidReportCount1 = { .header = 0x95, .data = { 0x01, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportCount6 = { .header = 0x95, .data = { 0x06, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportCount7 = { .header = 0x95, .data = { 0x07, 0x00 }, .location = 0x00 }; -static const USB_HID_Short_Item_t hidReportSize1 = { .header = 0x75, .data = { 0x01, 0x00 }, .location = 0x00 }; - -static const USB_HID_Short_Item_t hidUsageConsumerControl = { .header = 0x09, .data = { 0x01, 0x00 }, .location = 0x00 }; - -static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }, .location = 0x00 }; - -/* - * Define configurable items in the HID Report descriptor. - */ -static USB_HID_Short_Item_t hidUsageByte0Bit0 = { .header = 0x09, .data = { 0xE2, 0x00 }, .location = 0x00 }; // Mute - -static USB_HID_Short_Item_t hidUsageByte1Bit7 = { .header = 0x09, .data = { 0xEA, 0x00 }, .location = 0x71 }; // Vol- -static USB_HID_Short_Item_t hidUsageByte1Bit0 = { .header = 0x09, .data = { 0xE9, 0x00 }, .location = 0x01 }; // Vol+ - -/* - * List the configurable items in the HID Report descriptor. - */ -static USB_HID_Short_Item_t* const hidConfigurableItems[] = { - &hidUsageByte0Bit0, - &hidUsageByte1Bit0, - &hidUsageByte1Bit7 -}; - -/* - * List Usage pages in the HID Report descriptor, one per byte. - */ -static const USB_HID_Short_Item_t* const hidUsagePages[] = { - &hidUsagePageConsumer, - &hidUsagePageConsumer -}; - -/* - * List all items in the HID Report descriptor. - */ -static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { - &hidUsagePageConsumer, - &hidUsageConsumerControl, - &hidCollectionApplication, - &hidReportSize1, - &hidLogicalMinimum0, - &hidCollectionLogical, // Byte 0 - &hidLogicalMaximum1, - &hidReportCount1, - &hidUsageByte0Bit0, - &hidInputDataVar, - &hidLogicalMaximum0, - &hidReportCount7, - &hidInputConstArray, - &hidCollectionEnd, - &hidCollectionLogical, // Byte 1 - &hidLogicalMaximum1, - &hidReportCount1, - &hidUsageByte1Bit0, - &hidInputDataVar, - &hidLogicalMaximum0, - &hidReportCount6, - &hidInputConstArray, - &hidLogicalMaximum1, - &hidUsageByte1Bit7, - &hidInputDataVar, - &hidCollectionEnd, - &hidCollectionEnd -}; - -/* - * Define the length of the HID Report. - * This value must match the number of Report bytes defined by hidReportDescriptorItems. - */ -#define HID_REPORT_LENGTH ( 2 ) - -#endif // __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_multi_report/hid_report_descriptor.h b/tests/xua_unit_tests/src/test_multi_report/hid_report_descriptor.h new file mode 100644 index 00000000..e01361aa --- /dev/null +++ b/tests/xua_unit_tests/src/test_multi_report/hid_report_descriptor.h @@ -0,0 +1,296 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef __hid_report_descriptor_h__ +#define __hid_report_descriptor_h__ + +#include "xua_hid_report.h" + +#define USB_HID_REPORT_ID_KEYBOARD ( 0x01 ) +#define USB_HID_REPORT_ID_CONSUMER ( 0x02 ) +#define USB_HID_REPORT_ID_TELEPHONY ( 0x03 ) + +/* + * Define non-configurable items in the HID Report descriptor. + * (These are short items as the location field isn't relevant for them) + */ +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; + + +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; + +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; + +static const USB_HID_Short_Item_t hidReportCount1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount4 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x04, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount7 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x07, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; + +static const USB_HID_Short_Item_t hidUsagePageGenericDesktop = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .data = { USB_HID_USAGE_PAGE_ID_GENERIC_DESKTOP, 0x00 }}; +static const USB_HID_Short_Item_t hidUsagePageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }}; +static const USB_HID_Short_Item_t hidUsagePageTelephony = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .data = { USB_HID_USAGE_PAGE_ID_TELEPHONY_DEVICE, 0x00 }}; + +static const USB_HID_Short_Item_t hidUsageKeyboard = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x06, 0x00 }}; +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 }}; +static const USB_HID_Short_Item_t hidUsageTelephonyHeadset = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x05, 0x00 }}; + +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Short_Item_t hidReportId1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_ID), + .data = { USB_HID_REPORT_ID_KEYBOARD, 0x00 } }; +static const USB_HID_Short_Item_t hidReportId2 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_ID), + .data = { USB_HID_REPORT_ID_CONSUMER, 0x00 } }; +static const USB_HID_Short_Item_t hidReportId3 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_ID), + .data = { USB_HID_REPORT_ID_TELEPHONY, 0x00 } }; + +static const USB_HID_Report_Element_t hidReportKeyboard = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_KEYBOARD, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_KEYBOARD, 1, 0, 0 ) +}; + +static const USB_HID_Report_Element_t hidReportConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 2, 0, 0 ) +}; + +static const USB_HID_Report_Element_t hidReportTelephony = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_TELEPHONY_DEVICE, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_TELEPHONY, 1, 0, 0 ) +}; + +/* + * Define configurable elements in the HID Report descriptor. + */ +static USB_HID_Report_Element_t hidUsageReport1Byte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0x17, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_KEYBOARD, 0, 0, 0 ) +}; // 't' + +static USB_HID_Report_Element_t hidUsageReport1Byte0Bit2 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0x72, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_KEYBOARD, 0, 0, 2 ) +}; // F23 + +static USB_HID_Report_Element_t hidUsageReport1Byte0Bit3 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0x73, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_KEYBOARD, 0, 0, 3 ) +}; // F24 + +static USB_HID_Report_Element_t hidUsageReport2Byte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(2, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0x26, 0x02 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 0, 0, 0 ) +}; // AC Stop + +static USB_HID_Report_Element_t hidUsageReport2Byte0Bit1 = { + .item.header = HID_REPORT_SET_HEADER(2, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0x21, 0x02 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 0, 0, 1 ) +}; // AC Search + +static USB_HID_Report_Element_t hidUsageReport2Byte0Bit2 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 0, 0, 2 ) +}; // Mute + +static USB_HID_Report_Element_t hidUsageReport2Byte0Bit4 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xCF, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 0, 0, 4 ) +}; // Voice Command + +static USB_HID_Report_Element_t hidUsageReport2Byte0Bit6 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 0, 0, 6 ) +}; // Vol+ + +static USB_HID_Report_Element_t hidUsageReport2Byte0Bit7 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 0, 0, 7 ) +}; // Vol- + +static USB_HID_Report_Element_t hidUsageReport2Byte1Bit7 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE5, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_CONSUMER, 0, 1, 7 ) +}; // Bass boost + +static USB_HID_Report_Element_t hidUsageReport3Byte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0x20, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_TELEPHONY, 0, 0, 0 ) +}; // Hook Switch + +static USB_HID_Report_Element_t hidUsageReport3Byte0Bit1 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0x2F, 0x00 }, + .location = HID_REPORT_SET_LOC( USB_HID_REPORT_ID_TELEPHONY, 0, 0, 1 ) +}; // Phone Mute + +/* + * List the configurable elements in the HID Report. + */ +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { + &hidUsageReport1Byte0Bit0, + &hidUsageReport1Byte0Bit2, + &hidUsageReport1Byte0Bit3, + + &hidUsageReport2Byte0Bit0, + &hidUsageReport2Byte0Bit1, + &hidUsageReport2Byte0Bit2, + &hidUsageReport2Byte0Bit4, + &hidUsageReport2Byte0Bit6, + &hidUsageReport2Byte0Bit7, + &hidUsageReport2Byte1Bit7, + + &hidUsageReport3Byte0Bit0, + &hidUsageReport3Byte0Bit1 +}; + +/* + * List HID Reports, one per Report ID. This should be a usage page item with the locator filled out with ID and size + * If not using report IDs - still have one with report ID 0 + */ +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportKeyboard, + &hidReportConsumer, + &hidReportTelephony +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &hidUsagePageGenericDesktop, + &hidUsageKeyboard, + &hidReportSize1, + &hidLogicalMinimum0, + &hidCollectionApplication, // Report 1 + &hidReportId1, + &(hidReportKeyboard.item), + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageReport1Byte0Bit0.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidInputConstArray, + &hidLogicalMaximum1, + &(hidUsageReport1Byte0Bit2.item), + &hidInputDataVar, + &(hidUsageReport1Byte0Bit3.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount4, + &hidInputConstArray, + &hidCollectionEnd, + &hidUsagePageConsumerControl, + &hidUsageConsumerControl, + &hidCollectionApplication, // Report 2 + &hidReportId2, + &(hidReportConsumer.item), + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageReport2Byte0Bit0.item), + &hidInputDataVar, + &(hidUsageReport2Byte0Bit1.item), + &hidInputDataVar, + &(hidUsageReport2Byte0Bit2.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidInputConstArray, + &hidLogicalMaximum1, + &(hidUsageReport2Byte0Bit4.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidInputConstArray, + &hidLogicalMaximum1, + &(hidUsageReport2Byte0Bit6.item), + &hidInputDataVar, + &(hidUsageReport2Byte0Bit7.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount7, + &hidInputConstArray, + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageReport2Byte1Bit7.item), + &hidInputDataVar, + &hidCollectionEnd, + &hidUsagePageTelephony, + &hidUsageTelephonyHeadset, + &hidCollectionApplication, // Report 3 + &hidReportId3, + &(hidReportTelephony.item), + &(hidUsageReport3Byte0Bit0.item), + &hidInputDataVar, + &(hidUsageReport3Byte0Bit1.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount6, + &hidInputConstArray, + &hidCollectionEnd, +}; + +/* + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) + */ +#define HID_REPORT_COUNT ( 3 ) + +#endif // __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c new file mode 100644 index 00000000..bad4c699 --- /dev/null +++ b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c @@ -0,0 +1,915 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include + +#include "xua_unit_tests.h" +#include "xua_hid_report.h" + +// Test constants related to the report descriptor defined in hid_report_descriptor.h +#define REPORT1_MAX_VALID_BIT ( 3 ) +#define REPORT1_MAX_VALID_BYTE ( 0 ) +#define REPORT1_MIN_VALID_BIT ( 0 ) +#define REPORT1_MIN_VALID_BYTE ( 0 ) + +#define REPORT2_MAX_VALID_BIT ( 7 ) +#define REPORT2_MAX_VALID_BYTE ( 1 ) +#define REPORT2_MIN_VALID_BIT ( 0 ) +#define REPORT2_MIN_VALID_BYTE ( 0 ) + +#define REPORT3_MAX_VALID_BIT ( 1 ) +#define REPORT3_MAX_VALID_BYTE ( 0 ) +#define REPORT3_MIN_VALID_BIT ( 0 ) +#define REPORT3_MIN_VALID_BYTE ( 0 ) + +#define HID_REPORT_LENGTH ( 3 ) +#define HID_REPORT_COUNT ( 3 ) +#define HID_REPORTID_LIMIT ( 4 ) + +// Constants from USB HID Usage Tables +#define KEYBOARD_PAGE ( 0x07 ) +#define CONSUMER_PAGE ( 0x0C ) +#define TELEPHONY_DEVICE_PAGE ( 0x0B ) +#define LOUDNESS_CONTROL ( 0xE7 ) +#define PHONE_KEY_9 ( 0xB9 ) +#define KEYBOARD_X ( 0x1B ) +#define PHONE_HOST_HOLD ( 0x010A ) + +static unsigned construct_usage_header( unsigned size ) +{ + unsigned header = 0x00; + + header |= ( HID_REPORT_ITEM_USAGE_TAG << HID_REPORT_ITEM_HDR_TAG_SHIFT ) & HID_REPORT_ITEM_HDR_TAG_MASK; + header |= ( HID_REPORT_ITEM_USAGE_TYPE << HID_REPORT_ITEM_HDR_TYPE_SHIFT ) & HID_REPORT_ITEM_HDR_TYPE_MASK; + + header |= ( size << HID_REPORT_ITEM_HDR_SIZE_SHIFT ) & HID_REPORT_ITEM_HDR_SIZE_MASK; + + return header; +} + +void setUp( void ) +{ + hidReportInit(); + hidResetReportDescriptor(); +} + +void test_validate_report( void ) { + unsigned retVal = hidReportValidate(); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_reportid_in_use( void ) { + unsigned reportIdInUse = hidIsReportIdInUse(); + TEST_ASSERT_EQUAL_UINT( 1, reportIdInUse ); +} + +void test_get_next_valid_report_id( void ) { + unsigned reportId = 0U; + + reportId = hidGetNextValidReportId(reportId); + TEST_ASSERT_EQUAL_UINT( 1, reportId ); + + reportId = hidGetNextValidReportId(reportId); + TEST_ASSERT_EQUAL_UINT( 2, reportId ); + + reportId = hidGetNextValidReportId(reportId); + TEST_ASSERT_EQUAL_UINT( 3, reportId ); + + reportId = hidGetNextValidReportId(reportId); + TEST_ASSERT_EQUAL_UINT( 1, reportId ); +} + +void test_is_report_id_valid( void ) { + unsigned isValid = 0; + + unsigned reportId = 0; + isValid = hidIsReportIdValid( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, isValid ); + + reportId = 1; + isValid = hidIsReportIdValid( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, isValid ); + + reportId = 2; + isValid = hidIsReportIdValid( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, isValid ); + + reportId = 3; + isValid = hidIsReportIdValid( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, isValid ); + + reportId = 4; + isValid = hidIsReportIdValid( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, isValid ); +} + +// Basic report descriptor tests +void test_unprepared_hidGetReportDescriptor( void ) +{ + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NULL( reportDescPtr ); + + for (unsigned reportId = 1; reportId <= HID_REPORT_COUNT; reportId++) + { + unsigned reportLength = hidGetReportLength( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, reportLength ); + } +} + +void test_prepared_hidGetReportDescriptor( void ) +{ + hidPrepareReportDescriptor(); + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NOT_NULL( reportDescPtr ); + + unsigned reportId = 1; + unsigned reportLength = hidGetReportLength( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, reportLength ); + + reportId = 2; + reportLength = hidGetReportLength( reportId ); + TEST_ASSERT_EQUAL_UINT( 2, reportLength ); + + reportId = 3; + reportLength = hidGetReportLength( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, reportLength ); +} + +void test_reset_unprepared_hidGetReportDescriptor( void ) +{ + hidPrepareReportDescriptor(); + hidResetReportDescriptor(); + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NULL( reportDescPtr ); +} + +void test_reset_prepared_hidGetReportDescriptor( void ) +{ + hidPrepareReportDescriptor(); + hidResetReportDescriptor(); + hidPrepareReportDescriptor(); + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NOT_NULL( reportDescPtr ); +} + +void test_report_id_limit( void ) +{ + unsigned reportIdLimit = hidGetReportIdLimit(); + TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit ); +} + +// Basic item tests +void test_max_loc_hidGetReportItem( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; + unsigned char header; + unsigned char page; + + unsigned reportId = 1; + unsigned bit = REPORT1_MAX_VALID_BIT; + unsigned byte = REPORT1_MAX_VALID_BYTE; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( KEYBOARD_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( 0x73, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); + + reportId = 2; + bit = REPORT2_MAX_VALID_BIT; + byte = REPORT2_MAX_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( CONSUMER_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( 0xE5, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); + + reportId = 3; + bit = REPORT3_MAX_VALID_BIT; + byte = REPORT3_MAX_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( TELEPHONY_DEVICE_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( 0x2F, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); +} + + +void test_min_loc_hidGetReportItem( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; + unsigned char header; + unsigned char page; + + unsigned reportId = 1; + unsigned bit = REPORT1_MIN_VALID_BIT; + unsigned byte = REPORT1_MIN_VALID_BYTE; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( KEYBOARD_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( 0x17, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); + + reportId = 2; + bit = REPORT2_MIN_VALID_BIT; + byte = REPORT2_MIN_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( CONSUMER_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x0A, header ); + TEST_ASSERT_EQUAL_UINT( 0x26, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x02, data[ 1 ]); + + reportId = 3; + bit = REPORT3_MIN_VALID_BIT; + byte = REPORT3_MIN_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( TELEPHONY_DEVICE_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( 0x20, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); +} + +void test_invalid_report_id( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 }; + unsigned char header = 0x33; + unsigned char page = 0x44; + + unsigned reportId = 0; + unsigned bit = REPORT1_MIN_VALID_BIT; + unsigned byte = REPORT1_MIN_VALID_BYTE; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_ID, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0x33, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD2, data[ 1 ]); +} + +void test_unused_report_id( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 }; + unsigned char header = 0x33; + unsigned char page = 0x44; + + unsigned reportId = 8; + unsigned bit = REPORT1_MIN_VALID_BIT; + unsigned byte = REPORT1_MIN_VALID_BYTE; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_ID, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0x33, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD2, data[ 1 ]); +} + +void test_overflow_bit_hidGetReportItem( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; + unsigned char header = 0xAA; + unsigned char page = 0x44; + + unsigned reportId = 1; + unsigned bit = REPORT1_MAX_VALID_BIT + 1; + unsigned byte = REPORT1_MAX_VALID_BYTE; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 2; + bit = REPORT2_MAX_VALID_BIT + 1; + byte = REPORT2_MAX_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 3; + bit = REPORT3_MAX_VALID_BIT + 1; + byte = REPORT3_MAX_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); +} + +void test_overflow_byte_hidGetReportItem( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; + unsigned char header = 0xAA; + unsigned char page = 0x44; + + unsigned reportId = 1; + unsigned bit = REPORT1_MAX_VALID_BIT; + unsigned byte = REPORT1_MAX_VALID_BYTE + 1; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 2; + bit = REPORT2_MAX_VALID_BIT; + byte = REPORT2_MAX_VALID_BYTE + 1; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 3; + bit = REPORT3_MAX_VALID_BIT; + byte = REPORT3_MAX_VALID_BYTE + 1; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); +} + +void test_underflow_bit_hidGetReportItem( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; + unsigned char header = 0xAA; + unsigned char page = 0x44; + + unsigned reportId = 1; + unsigned bit = REPORT1_MIN_VALID_BIT - 1; + unsigned byte = REPORT1_MIN_VALID_BYTE; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 2; + bit = REPORT2_MIN_VALID_BIT - 1; + byte = REPORT2_MIN_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 3; + bit = REPORT3_MIN_VALID_BIT - 1; + byte = REPORT3_MIN_VALID_BYTE; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); +} + +void test_underflow_byte_hidGetReportItem( void ) +{ + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; + unsigned char header = 0xAA; + unsigned char page = 0x44; + + unsigned reportId = 1; + unsigned bit = REPORT1_MIN_VALID_BIT; + unsigned byte = REPORT1_MIN_VALID_BYTE - 1; + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 2; + bit = REPORT2_MIN_VALID_BIT; + byte = REPORT2_MIN_VALID_BYTE - 1; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); + + reportId = 3; + bit = REPORT3_MIN_VALID_BIT; + byte = REPORT3_MIN_VALID_BYTE - 1; + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + TEST_ASSERT_EQUAL_UINT( 0x44, page ); + TEST_ASSERT_EQUAL_UINT( 0xAA, header ); + TEST_ASSERT_EQUAL_UINT( 0xBA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0xD1, data[ 1 ]); +} + +// Configurable and non-configurable item tests +void test_configurable_item_hidSetReportItem( void ) +{ + const unsigned reportId = 1; + const unsigned bit = REPORT1_MIN_VALID_BIT; + const unsigned byte = REPORT1_MIN_VALID_BYTE; + unsigned char data[ 1 ] = { KEYBOARD_X }; + unsigned char header = construct_usage_header( sizeof( data ) / sizeof( unsigned char )); + unsigned char page = KEYBOARD_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( KEYBOARD_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( KEYBOARD_X, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); +} + +// Testing that the high byte of the report gets correctly cleared +void test_configurable_item_hidSetReportItem_multibyte_orig( void ) +{ + const unsigned reportId = 2; + const unsigned bit = 1; // This byte&bit combo is originally set be 2 bytes long in the header + const unsigned byte = 0; + unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; + unsigned char header = construct_usage_header( sizeof( data ) / sizeof( unsigned char )); + unsigned char page = CONSUMER_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( CONSUMER_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( LOUDNESS_CONTROL, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); +} + +void test_nonconfigurable_item_hidSetReportItem( void ) +{ + const unsigned reportId = 1; + const unsigned bit = 1; // This bit and byte combination should not appear in the + const unsigned byte = 0; // hidConfigurableElements list in hid_report_descriptors.c. + const unsigned char data[ 1 ] = { KEYBOARD_X }; + const unsigned char header = construct_usage_header( sizeof data / sizeof( unsigned char )); + const unsigned char page = KEYBOARD_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +// Bit range tests +void test_max_bit_hidSetReportItem( void ) +{ + const unsigned char header = construct_usage_header( 0 ); + + unsigned reportId = 1; + unsigned bit = REPORT1_MAX_VALID_BIT; // See the hidConfigurableElements list in hid_report_descriptors.c. + unsigned byte = REPORT1_MAX_VALID_BYTE; + unsigned char page = KEYBOARD_PAGE; + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + reportId = 2; + bit = REPORT2_MAX_VALID_BIT; + byte = REPORT2_MAX_VALID_BYTE; + page = CONSUMER_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + reportId = 3; + bit = REPORT3_MAX_VALID_BIT; + byte = REPORT3_MAX_VALID_BYTE; + page = TELEPHONY_DEVICE_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_min_bit_hidSetReportItem( void ) +{ + const unsigned char header = construct_usage_header( 0 ); + + unsigned reportId = 1; + unsigned bit = REPORT1_MIN_VALID_BIT; // See the hidConfigurableElements list in hid_report_descriptors.c. + unsigned byte = REPORT1_MIN_VALID_BYTE; + unsigned char page = KEYBOARD_PAGE; + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + reportId = 2; + bit = REPORT2_MIN_VALID_BIT; + byte = REPORT2_MIN_VALID_BYTE; + page = CONSUMER_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + reportId = 3; + bit = REPORT3_MIN_VALID_BIT; + byte = REPORT3_MIN_VALID_BYTE; + page = TELEPHONY_DEVICE_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_overflow_bit_hidSetReportItem( void ) +{ + const unsigned char header = construct_usage_header( 0 ); + + unsigned reportId = 1; + unsigned bit = REPORT1_MAX_VALID_BIT + 1; // See the hidConfigurableElements list in hid_report_descriptors.c. + unsigned byte = REPORT1_MAX_VALID_BYTE; + unsigned char page = KEYBOARD_PAGE; + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 2; + bit = REPORT2_MAX_VALID_BIT + 1; + byte = REPORT2_MAX_VALID_BYTE; + page = CONSUMER_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 3; + bit = REPORT3_MAX_VALID_BIT + 1; + byte = REPORT3_MAX_VALID_BYTE; + page = TELEPHONY_DEVICE_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +void test_underflow_bit_hidSetReportItem( void ) +{ + const unsigned char header = construct_usage_header( 0 ); + + unsigned reportId = 1; + unsigned bit = REPORT1_MIN_VALID_BIT - 1; // See the hidConfigurableElements list in hid_report_descriptors.c. + unsigned byte = REPORT1_MIN_VALID_BYTE; + unsigned char page = KEYBOARD_PAGE; + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 2; + bit = REPORT2_MIN_VALID_BIT - 1; + byte = REPORT2_MIN_VALID_BYTE; + page = CONSUMER_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 3; + bit = REPORT3_MIN_VALID_BIT - 1; + byte = REPORT3_MIN_VALID_BYTE; + page = TELEPHONY_DEVICE_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +void test_overflow_byte_hidSetReportItem( void ) +{ + const unsigned char header = construct_usage_header( 0 ); + + unsigned reportId = 1; + unsigned bit = REPORT1_MAX_VALID_BIT; // See the hidConfigurableElements list in hid_report_descriptors.c. + unsigned byte = REPORT1_MAX_VALID_BYTE + 1; + unsigned char page = KEYBOARD_PAGE; + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 2; + bit = REPORT2_MAX_VALID_BIT; + byte = REPORT2_MAX_VALID_BYTE + 1; + page = CONSUMER_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 3; + bit = REPORT3_MAX_VALID_BIT; + byte = REPORT3_MAX_VALID_BYTE + 1; + page = TELEPHONY_DEVICE_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +void test_underflow_byte_hidSetReportItem( void ) +{ + const unsigned char header = construct_usage_header( 0 ); + + unsigned reportId = 1; + unsigned bit = REPORT1_MIN_VALID_BIT; // See the hidConfigurableElements list in hid_report_descriptors.c. + unsigned byte = REPORT1_MIN_VALID_BYTE - 1; + unsigned char page = KEYBOARD_PAGE; + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 2; + bit = REPORT2_MIN_VALID_BIT; + byte = REPORT2_MIN_VALID_BYTE - 1; + page = CONSUMER_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); + + reportId = 3; + bit = REPORT3_MIN_VALID_BIT; + byte = REPORT3_MIN_VALID_BYTE - 1; + page = TELEPHONY_DEVICE_PAGE; + retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +// Size range tests +void test_max_size_hidSetReportItem( void ) +{ + const unsigned reportId = 1; + const unsigned bit = REPORT1_MIN_VALID_BIT; + const unsigned byte = REPORT1_MIN_VALID_BYTE; + const unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0x00 }; + const unsigned char header = construct_usage_header( HID_REPORT_ITEM_MAX_SIZE ); + const unsigned char page = KEYBOARD_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_min_size_hidSetReportItem( void ) +{ + const unsigned reportId = 1; + const unsigned bit = REPORT1_MIN_VALID_BIT; + const unsigned byte = REPORT1_MIN_VALID_BYTE; + const unsigned char header = construct_usage_header( 0x00 ); + const unsigned char page = KEYBOARD_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_unsupported_size_hidSetReportItem( void ) +{ + const unsigned reportId = 0; + const unsigned bit = REPORT1_MIN_VALID_BIT; + const unsigned byte = REPORT1_MIN_VALID_BYTE; + const unsigned char header = construct_usage_header( 0x03 ); + const unsigned char page = KEYBOARD_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); +} + +// Combined function tests +void test_initial_modification_without_subsequent_preparation( void ) +{ + const unsigned reportId = 2; + const unsigned bit = REPORT2_MIN_VALID_BIT; + const unsigned byte = REPORT2_MIN_VALID_BYTE; + const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; + const unsigned char header = construct_usage_header( sizeof data / sizeof( unsigned char )); + const unsigned char page = CONSUMER_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NULL( reportDescPtr ); +} + +void test_initial_modification_with_subsequent_preparation( void ) +{ + const unsigned reportId = 2; + const unsigned bit = REPORT2_MIN_VALID_BIT; + const unsigned byte = REPORT2_MIN_VALID_BYTE; + const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; + const unsigned char header = construct_usage_header( sizeof data / sizeof( unsigned char )); + const unsigned char page = CONSUMER_PAGE; + + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + hidPrepareReportDescriptor(); + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NOT_NULL( reportDescPtr ); +} + +void test_initial_modification_with_subsequent_verification_1( void ) +{ + const unsigned reportId = 2; + const unsigned bit = REPORT2_MIN_VALID_BIT; + const unsigned byte = REPORT2_MIN_VALID_BYTE; + + unsigned char get_data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xFF, 0xFF }; + unsigned char get_header = 0xFF; + unsigned char get_page = 0xFF; + + const unsigned char set_data[ 1 ] = { LOUDNESS_CONTROL }; + const unsigned char set_header = construct_usage_header( sizeof set_data / sizeof( unsigned char )); + const unsigned char set_page = CONSUMER_PAGE; + + unsigned setRetVal = hidSetReportItem( reportId, byte, bit, set_page, set_header, set_data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, setRetVal ); + + unsigned getRetVal = hidGetReportItem( reportId, byte, bit, &get_page, &get_header, get_data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, getRetVal ); + TEST_ASSERT_EQUAL_UINT( set_page, get_page ); + TEST_ASSERT_EQUAL_UINT( set_header, get_header ); + TEST_ASSERT_EQUAL_UINT( set_data[ 0 ], get_data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0, get_data[ 1 ]); // Should be MSB of data from hidUsageByte0Bit0 in hid_report_descriptor.h +} + +void test_initial_modification_with_subsequent_verification_2( void ) +{ + const unsigned reportId = 3; + const unsigned bit = REPORT3_MIN_VALID_BIT; + const unsigned byte = REPORT3_MIN_VALID_BYTE; + + { + unsigned char get_data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xFF, 0xFF }; + unsigned char get_header = 0xFF; + unsigned char get_page = 0xFF; + + const unsigned char set_data[ 2 ] = {( PHONE_HOST_HOLD & 0x00FF ), (( PHONE_HOST_HOLD & 0xFF00 ) >> 8 )}; + const unsigned char set_header = construct_usage_header( sizeof set_data / sizeof( unsigned char )); + const unsigned char set_page = TELEPHONY_DEVICE_PAGE; + + unsigned setRetVal = hidSetReportItem( reportId, byte, bit, set_page, set_header, set_data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, setRetVal ); + + unsigned getRetVal = hidGetReportItem( reportId, byte, bit, &get_page, &get_header, get_data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, getRetVal ); + TEST_ASSERT_EQUAL_UINT( set_page, get_page ); + TEST_ASSERT_EQUAL_UINT( set_header, get_header ); + TEST_ASSERT_EQUAL_UINT( set_data[ 0 ], get_data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( set_data[ 1 ], get_data[ 1 ]); + } + + { + unsigned char get_data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xFF, 0xFF }; + unsigned char get_header = 0xFF; + unsigned char get_page = 0xFF; + + const unsigned char set_data[ 1 ] = { PHONE_KEY_9 }; + const unsigned char set_header = construct_usage_header( sizeof set_data / sizeof( unsigned char )); + const unsigned char set_page = TELEPHONY_DEVICE_PAGE; + + unsigned setRetVal = hidSetReportItem( reportId, byte, bit, set_page, set_header, set_data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, setRetVal ); + + unsigned getRetVal = hidGetReportItem( reportId, byte, bit, &get_page, &get_header, get_data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, getRetVal ); + TEST_ASSERT_EQUAL_UINT( set_page, get_page ); + TEST_ASSERT_EQUAL_UINT( set_header, get_header ); + TEST_ASSERT_EQUAL_UINT( set_data[ 0 ], get_data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0, get_data[ 1 ]); // The call to hidSetReportItem with size 1 in the header should return the MSB to zero + } +} + +//setIdle and associated timing functionality tests +void test_set_idle( void ) +{ + unsigned reportIdAll = 0; + unsigned reportId = 1; + unsigned reportId2 = 2; + + unsigned setIdle = hidIsIdleActive( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + setIdle = hidIsIdleActive( reportId2 ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + setIdle = hidIsIdleActive( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + hidSetIdle( reportId, 1 ); + setIdle = hidIsIdleActive( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, setIdle ); + + setIdle = hidIsIdleActive( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + setIdle = hidIsIdleActive( reportId2 ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); +} + +void test_set_all_idle( void ) +{ + unsigned reportIdAll = 0; + unsigned reportId = 1; + unsigned reportId2 = 2; + + unsigned setIdle = hidIsIdleActive( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + setIdle = hidIsIdleActive( reportId2 ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + setIdle = hidIsIdleActive( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + for ( reportId = 1; reportId <= HID_REPORT_COUNT; ++reportId ) { + hidSetIdle( reportId, 1 ); + setIdle = hidIsIdleActive( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, setIdle ); + } + + setIdle = hidIsIdleActive( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 1, setIdle ); +} + +void test_change_pending( void ) +{ + unsigned reportIdAll = 0; + unsigned reportId = 1; + unsigned reportId2 = 2; + + unsigned changePending = hidIsChangePending( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); + + changePending = hidIsChangePending( reportId2 ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); + + changePending = hidIsChangePending( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); + + hidSetChangePending( reportId ); + changePending = hidIsChangePending( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, changePending ); + + changePending = hidIsChangePending( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 1, changePending ); + + changePending = hidIsChangePending( reportId2 ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); +} + +void test_change_pending_all( void ) +{ + unsigned reportIdAll = 0; + unsigned reportId = 1; + + unsigned changePending = hidIsChangePending( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); + + changePending = hidIsChangePending( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); + + for ( reportId = 1; reportId <= HID_REPORT_COUNT; ++reportId ) { + hidSetChangePending( reportId ); + changePending = hidIsChangePending( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, changePending ); + } + + changePending = hidIsChangePending( reportIdAll ); + TEST_ASSERT_EQUAL_UINT( 1, changePending ); +} + +void test_report_time( void ) +{ + unsigned reportTime1 = 123; + unsigned reportTime2 = 456; + + hidCaptureReportTime(1, reportTime1); + hidCaptureReportTime(2, reportTime2); + reportTime1 = hidGetReportTime(1); + reportTime2 = hidGetReportTime(2); + + TEST_ASSERT_EQUAL_UINT(123, reportTime1); + TEST_ASSERT_EQUAL_UINT(456, reportTime2); +} + +void test_report_time_calc( void ) +{ + unsigned reportTime1 = 123; + unsigned reportTime2 = 456; + unsigned reportPeriod1 = 10; + unsigned reportPeriod2 = 5; + + hidCaptureReportTime(1, reportTime1); + hidCaptureReportTime(2, reportTime2); + hidSetReportPeriod(1, reportPeriod1); + hidSetReportPeriod(2, reportPeriod2); + reportTime1 = hidGetReportTime(1); + reportTime2 = hidGetReportTime(2); + reportPeriod1 = hidGetReportPeriod(1); + reportPeriod2 = hidGetReportPeriod(2); + + TEST_ASSERT_EQUAL_UINT(123, reportTime1); + TEST_ASSERT_EQUAL_UINT(456, reportTime2); + TEST_ASSERT_EQUAL_UINT(10, reportPeriod1); + TEST_ASSERT_EQUAL_UINT(5, reportPeriod2); + + hidCalcNextReportTime(1); + hidCalcNextReportTime(2); + unsigned nextReportTime1 = hidGetNextReportTime(1); + unsigned nextReportTime2 = hidGetNextReportTime(2); + TEST_ASSERT_EQUAL_UINT( reportTime1 + reportPeriod1, nextReportTime1 ); + TEST_ASSERT_EQUAL_UINT( reportTime2 + reportPeriod2, nextReportTime2 ); +} diff --git a/tests/xua_unit_tests/src/test_simple/hid_report_descriptor.h b/tests/xua_unit_tests/src/test_simple/hid_report_descriptor.h new file mode 100644 index 00000000..330d95e6 --- /dev/null +++ b/tests/xua_unit_tests/src/test_simple/hid_report_descriptor.h @@ -0,0 +1,145 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef __hid_report_descriptor_h__ +#define __hid_report_descriptor_h__ + +#include "xua_hid_report.h" + +/* + * Define non-configurable items in the HID Report descriptor. + * (These are short items as the location field isn't relevant for them) + */ +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionLogical = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x02, 0x00 } }; + +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; + +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; + +static const USB_HID_Short_Item_t hidReportCount1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount7 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x07, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; + +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 } }; + +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Report_Element_t hidReportPageConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) +}; + +/* + * Define configurable items in the HID Report descriptor. + */ +static USB_HID_Report_Element_t hidUsageByte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 0) +}; // Mute + +static USB_HID_Report_Element_t hidUsageByte1Bit7 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 1, 7) +}; // Vol- +static USB_HID_Report_Element_t hidUsageByte1Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 1, 0) +}; // Vol+ + +/* + * List the configurable elements in the HID Report descriptor. + */ +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { + &hidUsageByte0Bit0, + &hidUsageByte1Bit0, + &hidUsageByte1Bit7 +}; + +/* + * List HID Reports, one per Report ID. This should be a usage page item with the relevant + * If not using report IDs - still have one with report ID 0 + */ +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportPageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &(hidReportPageConsumer.item), + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidReportSize1, + &hidLogicalMinimum0, + &hidCollectionLogical, // Byte 0 + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageByte0Bit0.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount7, + &hidInputConstArray, + &hidCollectionEnd, + &hidCollectionLogical, // Byte 1 + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageByte1Bit0.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount6, + &hidInputConstArray, + &hidReportCount1, + &hidLogicalMaximum1, + &(hidUsageByte1Bit7.item), + &hidInputDataVar, + &hidCollectionEnd, + &hidCollectionEnd +}; + +/* + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) + */ +#define HID_REPORT_COUNT ( 1 ) + +#endif // __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_hid.c b/tests/xua_unit_tests/src/test_simple/test_hid.c similarity index 69% rename from tests/xua_unit_tests/src/test_hid.c rename to tests/xua_unit_tests/src/test_simple/test_hid.c index 965c7f90..856edd79 100644 --- a/tests/xua_unit_tests/src/test_hid.c +++ b/tests/xua_unit_tests/src/test_simple/test_hid.c @@ -4,14 +4,20 @@ #include #include "xua_unit_tests.h" -#include "xua_hid_report_descriptor.h" -#include "hid_report_descriptor.h" +#include "xua_hid_report.h" -#define HID_REPORT_ITEM_TYPE_GLOBAL ( 0x01 ) -#define HID_REPORT_ITEM_TYPE_LOCAL ( 0x02 ) -#define HID_REPORT_ITEM_TYPE_MAIN ( 0x00 ) -#define HID_REPORT_ITEM_TYPE_RESERVED ( 0x03 ) +// Test constants related to the report descriptor defined in hid_report_descriptor.h +#define MAX_VALID_BIT ( 7 ) +#define MAX_VALID_BYTE ( 1 ) +#define MIN_VALID_BIT ( 0 ) +#define MIN_VALID_BYTE ( 0 ) + +#define HID_REPORT_LENGTH ( 2 ) +#define HID_REPORT_COUNT ( 1 ) +#define HID_REPORTID_LIMIT ( 1 ) + +// Constants from the USB HID Usage Tables #define CONSUMER_CONTROL_PAGE ( 0x0C ) #define LOUDNESS_CONTROL ( 0xE7 ) #define AL_CONTROL_PANEL ( 0x019F ) @@ -30,26 +36,62 @@ static unsigned construct_usage_header( unsigned size ) void setUp( void ) { + hidReportInit(); hidResetReportDescriptor(); } +void test_validate_report( void ) { + unsigned retVal = hidReportValidate(); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_reportid_in_use( void ) { + unsigned reportIdInUse = hidIsReportIdInUse(); + TEST_ASSERT_EQUAL_UINT( 0, reportIdInUse ); +} + +void test_get_next_valid_report_id( void ) { + unsigned reportId = 0U; + + reportId = hidGetNextValidReportId(reportId); + TEST_ASSERT_EQUAL_UINT( 0, reportId ); + + reportId = hidGetNextValidReportId(reportId); + TEST_ASSERT_EQUAL_UINT( 0, reportId ); +} + +void test_is_report_id_valid( void ) { + unsigned isValid = 0; + + unsigned reportId = 0; + isValid = hidIsReportIdValid( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, isValid ); + + reportId = 1; + isValid = hidIsReportIdValid( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, isValid ); +} + // Basic report descriptor tests void test_unprepared_hidGetReportDescriptor( void ) { + const unsigned reportId = 0; unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NULL( reportDescPtr ); - unsigned reportLength = hidGetReportLength(); + unsigned reportLength = hidGetReportLength( reportId ); TEST_ASSERT_EQUAL_UINT( 0, reportLength ); } void test_prepared_hidGetReportDescriptor( void ) { + const unsigned reportId = 0; + hidPrepareReportDescriptor(); unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NOT_NULL( reportDescPtr ); - unsigned reportLength = hidGetReportLength(); + unsigned reportLength = hidGetReportLength( reportId ); TEST_ASSERT_EQUAL_UINT( HID_REPORT_LENGTH, reportLength ); } @@ -70,16 +112,23 @@ void test_reset_prepared_hidGetReportDescriptor( void ) TEST_ASSERT_NOT_NULL( reportDescPtr ); } +void test_report_id_limit( void ) +{ + unsigned reportIdLimit = hidGetReportIdLimit(); + TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit ); +} + // Basic item tests void test_max_loc_hidGetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; const unsigned byte = MAX_VALID_BYTE; unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; unsigned char header; unsigned char page; - unsigned retVal = hidGetReportItem( byte, bit, &page, &header, data ); + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); TEST_ASSERT_EQUAL_UINT( CONSUMER_CONTROL_PAGE, page ); TEST_ASSERT_EQUAL_UINT( 0x09, header ); @@ -89,13 +138,14 @@ void test_max_loc_hidGetReportItem( void ) void test_min_loc_hidGetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; unsigned char header; unsigned char page; - unsigned retVal = hidGetReportItem( byte, bit, &page, &header, data ); + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); TEST_ASSERT_EQUAL_UINT( CONSUMER_CONTROL_PAGE, page ); TEST_ASSERT_EQUAL_UINT( 0x09, header ); @@ -105,13 +155,14 @@ void test_min_loc_hidGetReportItem( void ) void test_overflow_bit_hidGetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT + 1; const unsigned byte = MAX_VALID_BYTE; unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; - unsigned retVal = hidGetReportItem( byte, bit, &page, &header, data ); + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); TEST_ASSERT_EQUAL_UINT( 0x44, page ); TEST_ASSERT_EQUAL_UINT( 0xAA, header ); @@ -121,13 +172,14 @@ void test_overflow_bit_hidGetReportItem( void ) void test_overflow_byte_hidGetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; const unsigned byte = MAX_VALID_BYTE + 1; unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; - unsigned retVal = hidGetReportItem( byte, bit, &page, &header, data ); + unsigned retVal = hidGetReportItem( reportId, byte, bit, &page, &header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); TEST_ASSERT_EQUAL_UINT( 0x44, page ); TEST_ASSERT_EQUAL_UINT( 0xAA, header ); @@ -137,13 +189,14 @@ void test_overflow_byte_hidGetReportItem( void ) void test_underflow_bit_hidGetReportItem( void ) { - const int bit = MIN_VALID_BIT - 1; + const unsigned reportId = 0; + const int bit = MIN_VALID_BIT - 1; const unsigned byte = MIN_VALID_BYTE; unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; - unsigned retVal = hidGetReportItem( byte, ( unsigned ) bit, &page, &header, data ); + unsigned retVal = hidGetReportItem( reportId, byte, ( unsigned ) bit, &page, &header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); TEST_ASSERT_EQUAL_UINT( 0x44, page ); TEST_ASSERT_EQUAL_UINT( 0xAA, header ); @@ -153,13 +206,14 @@ void test_underflow_bit_hidGetReportItem( void ) void test_underflow_byte_hidGetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const int byte = MIN_VALID_BYTE - 1; unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; - unsigned retVal = hidGetReportItem(( unsigned ) byte, bit, &page, &header, data ); + unsigned retVal = hidGetReportItem( reportId, ( unsigned ) byte, bit, &page, &header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); TEST_ASSERT_EQUAL_UINT( 0x44, page ); TEST_ASSERT_EQUAL_UINT( 0xAA, header ); @@ -170,226 +224,245 @@ void test_underflow_byte_hidGetReportItem( void ) // Configurable and non-configurable item tests void test_configurable_item_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; const unsigned char header = construct_usage_header( sizeof data / sizeof( unsigned char )); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_nonconfigurable_item_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; // This bit and byte combination should not appear in the - const unsigned byte = MIN_VALID_BYTE; // hidConfigurableItems list in hid_report_descriptors.c. + const unsigned byte = MIN_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c. const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; const unsigned char header = construct_usage_header( sizeof data / sizeof( unsigned char )); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); } // Bit range tests void test_max_bit_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; // Only byte 1 has bit 7 not reserved, See the - const unsigned byte = MAX_VALID_BYTE; // hidConfigurableItems list in hid_report_descriptors.c. + const unsigned byte = MAX_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c. const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_min_bit_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_overflow_bit_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT + 1; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); } void test_underflow_bit_hidSetReportItem( void ) { + const unsigned reportId = 0; const int bit = MIN_VALID_BIT - 1; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, ( unsigned ) bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, ( unsigned ) bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); } // Byte range tests void test_max_byte_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MAX_VALID_BYTE; const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_min_byte_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_overflow_byte_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MAX_VALID_BYTE + 1; const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); } void test_underflow_byte_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const int byte = MIN_VALID_BYTE - 1; const unsigned char header = construct_usage_header( 0 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( ( unsigned ) byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, ( unsigned ) byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); } // Size range tests void test_max_size_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0x00 }; const unsigned char header = construct_usage_header( HID_REPORT_ITEM_MAX_SIZE ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_min_size_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = construct_usage_header( 0x00 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_unsupported_size_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = construct_usage_header( 0x03 ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); } // Header tag and type tests void test_bad_tag_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char good_header = construct_usage_header( 0x00 ); const unsigned char page = CONSUMER_CONTROL_PAGE; for( unsigned tag = 0x01; tag <= 0x0F; ++tag ) { - unsigned char bad_header = good_header | (( 0x0F << HID_REPORT_ITEM_HDR_TAG_SHIFT ) & HID_REPORT_ITEM_HDR_TAG_MASK ); - unsigned retVal = hidSetReportItem( byte, bit, page, bad_header, NULL ); + unsigned char bad_header = good_header | (( tag << HID_REPORT_ITEM_HDR_TAG_SHIFT ) & HID_REPORT_ITEM_HDR_TAG_MASK ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, bad_header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); } } void test_global_type_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = ( construct_usage_header( 0x00 ) & ~HID_REPORT_ITEM_HDR_TYPE_MASK ) | (( HID_REPORT_ITEM_TYPE_GLOBAL << HID_REPORT_ITEM_HDR_TYPE_SHIFT ) & HID_REPORT_ITEM_HDR_TYPE_MASK ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); } void test_local_type_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = ( construct_usage_header( 0x00 ) & ~HID_REPORT_ITEM_HDR_TYPE_MASK ) | (( HID_REPORT_ITEM_TYPE_LOCAL << HID_REPORT_ITEM_HDR_TYPE_SHIFT ) & HID_REPORT_ITEM_HDR_TYPE_MASK ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_main_type_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = ( construct_usage_header( 0x00 ) & ~HID_REPORT_ITEM_HDR_TYPE_MASK ) | (( HID_REPORT_ITEM_TYPE_MAIN << HID_REPORT_ITEM_HDR_TYPE_SHIFT ) & HID_REPORT_ITEM_HDR_TYPE_MASK ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); } void test_reserved_type_hidSetReportItem( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char header = ( construct_usage_header( 0x00 ) & ~HID_REPORT_ITEM_HDR_TYPE_MASK ) | (( HID_REPORT_ITEM_TYPE_RESERVED << HID_REPORT_ITEM_HDR_TYPE_SHIFT ) & HID_REPORT_ITEM_HDR_TYPE_MASK ); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, NULL ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); } // Combined function tests void test_initial_modification_without_subsequent_preparation( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; const unsigned char header = construct_usage_header( sizeof data / sizeof( unsigned char )); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); unsigned char* reportDescPtr = hidGetReportDescriptor(); @@ -398,13 +471,14 @@ void test_initial_modification_without_subsequent_preparation( void ) void test_initial_modification_with_subsequent_preparation( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; const unsigned char header = construct_usage_header( sizeof data / sizeof( unsigned char )); const unsigned char page = CONSUMER_CONTROL_PAGE; - unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); hidPrepareReportDescriptor(); @@ -414,6 +488,7 @@ void test_initial_modification_with_subsequent_preparation( void ) void test_initial_modification_with_subsequent_verification_1( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -425,10 +500,10 @@ void test_initial_modification_with_subsequent_verification_1( void ) const unsigned char set_header = construct_usage_header( sizeof set_data / sizeof( unsigned char )); const unsigned char set_page = CONSUMER_CONTROL_PAGE; - unsigned setRetVal = hidSetReportItem( byte, bit, set_page, set_header, set_data ); + unsigned setRetVal = hidSetReportItem( reportId, byte, bit, set_page, set_header, set_data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, setRetVal ); - unsigned getRetVal = hidGetReportItem( byte, bit, &get_page, &get_header, get_data ); + unsigned getRetVal = hidGetReportItem( reportId, byte, bit, &get_page, &get_header, get_data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, getRetVal ); TEST_ASSERT_EQUAL_UINT( set_page, get_page ); TEST_ASSERT_EQUAL_UINT( set_header, get_header ); @@ -438,6 +513,7 @@ void test_initial_modification_with_subsequent_verification_1( void ) void test_initial_modification_with_subsequent_verification_2( void ) { + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -450,10 +526,10 @@ void test_initial_modification_with_subsequent_verification_2( void ) const unsigned char set_header = construct_usage_header( sizeof set_data / sizeof( unsigned char )); const unsigned char set_page = CONSUMER_CONTROL_PAGE; - unsigned setRetVal = hidSetReportItem( byte, bit, set_page, set_header, set_data ); + unsigned setRetVal = hidSetReportItem( reportId, byte, bit, set_page, set_header, set_data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, setRetVal ); - unsigned getRetVal = hidGetReportItem( byte, bit, &get_page, &get_header, get_data ); + unsigned getRetVal = hidGetReportItem( reportId, byte, bit, &get_page, &get_header, get_data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, getRetVal ); TEST_ASSERT_EQUAL_UINT( set_page, get_page ); TEST_ASSERT_EQUAL_UINT( set_header, get_header ); @@ -470,10 +546,10 @@ void test_initial_modification_with_subsequent_verification_2( void ) const unsigned char set_header = construct_usage_header( sizeof set_data / sizeof( unsigned char )); const unsigned char set_page = CONSUMER_CONTROL_PAGE; - unsigned setRetVal = hidSetReportItem( byte, bit, set_page, set_header, set_data ); + unsigned setRetVal = hidSetReportItem( reportId, byte, bit, set_page, set_header, set_data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, setRetVal ); - unsigned getRetVal = hidGetReportItem( byte, bit, &get_page, &get_header, get_data ); + unsigned getRetVal = hidGetReportItem( reportId, byte, bit, &get_page, &get_header, get_data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, getRetVal ); TEST_ASSERT_EQUAL_UINT( set_page, get_page ); TEST_ASSERT_EQUAL_UINT( set_header, get_header ); @@ -488,6 +564,7 @@ void test_modification_without_subsequent_preparation( void ) unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NOT_NULL( reportDescPtr ); + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; @@ -495,7 +572,7 @@ void test_modification_without_subsequent_preparation( void ) const unsigned char page = CONSUMER_CONTROL_PAGE; hidResetReportDescriptor(); - unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); reportDescPtr = hidGetReportDescriptor(); @@ -508,6 +585,7 @@ void test_modification_with_subsequent_preparation( void ) unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NOT_NULL( reportDescPtr ); + const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; const unsigned char data[ 1 ] = { LOUDNESS_CONTROL }; @@ -515,10 +593,58 @@ void test_modification_with_subsequent_preparation( void ) const unsigned char page = CONSUMER_CONTROL_PAGE; hidResetReportDescriptor(); - unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + unsigned retVal = hidSetReportItem( reportId, byte, bit, page, header, data ); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); hidPrepareReportDescriptor(); reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NOT_NULL( reportDescPtr ); } + +//setIdle functionality tests +void test_set_idle( void ) +{ + unsigned reportId = 0; + + unsigned setIdle = hidIsIdleActive( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, setIdle ); + + hidSetIdle( reportId, 1 ); + setIdle = hidIsIdleActive( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, setIdle ); +} + +void test_change_pending( void ) +{ + unsigned reportId = 0; + + unsigned changePending = hidIsChangePending( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); + + hidSetChangePending( reportId ); + changePending = hidIsChangePending( reportId ); + TEST_ASSERT_EQUAL_UINT( 1, changePending ); + + hidClearChangePending( reportId ); + changePending = hidIsChangePending( reportId ); + TEST_ASSERT_EQUAL_UINT( 0, changePending ); +} + +void test_report_time( void ) +{ + unsigned reportTime = 123; + unsigned reportPeriod = 10; + + hidSetReportPeriod(0, reportPeriod); + hidCaptureReportTime(0, reportTime); + reportTime = hidGetReportTime(0); + reportPeriod = hidGetReportPeriod(0); + + TEST_ASSERT_EQUAL_UINT(123, reportTime); + TEST_ASSERT_EQUAL_UINT(10, reportPeriod); + + hidCalcNextReportTime(0); + + unsigned nextReportTime = hidGetNextReportTime(0); + TEST_ASSERT_EQUAL_UINT(133, nextReportTime); +} diff --git a/tests/xua_unit_tests/wscript b/tests/xua_unit_tests/wscript index 0f162c19..da0e1fc2 100644 --- a/tests/xua_unit_tests/wscript +++ b/tests/xua_unit_tests/wscript @@ -95,6 +95,7 @@ def add_unity_runner_build_config(waf_conf, project_root_path, unity_test_path, def prepare_unity_test_for_build(waf_conf, project_root_path, unity_test_path, unity_runner_dir, unity_runner_suffix, target): + print("unity_test_path: " + str(unity_test_path)) generate_unity_runner(project_root_path, unity_test_path, unity_runner_dir, unity_runner_suffix) runner_build_flags = '' # Could extract flags from the test name @@ -107,7 +108,12 @@ def find_unity_test_paths(unity_test_dir, unity_test_prefix): Return a list of all file paths with the unity_test_prefix found in the unity_test_dir. """ - return glob.glob(os.path.join(unity_test_dir, unity_test_prefix+'*')) + file_list = [] + for root, dirs, files in os.walk(unity_test_dir): + for f in files: + if f.startswith(unity_test_prefix): + file_list.append(os.path.join(root,f)) + return file_list def find_unity_tests(unity_test_dir, unity_test_prefix): @@ -116,7 +122,7 @@ def find_unity_tests(unity_test_dir, unity_test_prefix): unity_test_prefix found in the unity_test_dir. """ unity_test_paths = find_unity_test_paths(unity_test_dir, unity_test_prefix) - return {get_test_name(path): get_file_type(path) + return {get_test_name(path): {"language": get_file_type(path), "dir": os.path.dirname(path)} for path in unity_test_paths} @@ -139,8 +145,8 @@ def generate_all_unity_runners(waf_conf, project_root_path, # TODO: can the xwaf boilerplate help here? def create_waf_contexts(configs): for trgt in TARGETS: - for test_name, test_language in configs.items(): - print(f"test_name {test_name}, test_language {test_language}") + for test_name, params in configs.items(): + print(f"test_name {test_name}, test_language {params['language']}") for ctx in (BuildContext, CleanContext): raw_context = ctx.__name__.replace('Context', '').lower() @@ -149,9 +155,10 @@ def create_waf_contexts(configs): variant = test_name + '_' + trgt #cmd = raw_context + '_' + test_name #variant = test_name - language = test_language + language = params["language"] target = trgt runner = test_name + directory = params["dir"] print(f"cmd {cmd}, variant {variant}, language {language}") @@ -161,6 +168,8 @@ UNITY_RUNNER_DIR = 'runners' UNITY_RUNNER_SUFFIX = '_Runner' UNITY_TESTS = find_unity_tests(UNITY_TEST_DIR, UNITY_TEST_PREFIX) +print("UNITY_TESTS: " + str(UNITY_TESTS)) + create_waf_contexts(UNITY_TESTS) def options(opt): @@ -175,7 +184,6 @@ def configure(conf): UNITY_RUNNER_DIR, UNITY_RUNNER_SUFFIX) conf.load('xwaf.xcommon') - def build(bld): if not bld.variant: print('Adding test runners to build queue') @@ -204,7 +212,7 @@ def build(bld): 'Unity'] makefile_opts = {} - makefile_opts['SOURCE_DIRS'] = ['src', os.path.join('runners',bld.runner)] + makefile_opts['SOURCE_DIRS'] = ['src', bld.directory, os.path.join('runners',bld.runner)] if(bld.target == 'xcoreai'): print('TARGET XCOREAI') makefile_opts['TARGET'] = ['XCORE-AI-EXPLORER'] @@ -213,6 +221,7 @@ def build(bld): makefile_opts['TARGET'] = ['XCORE-200-EXPLORER'] makefile_opts['INCLUDE_DIRS'] = ['src', + bld.directory, '../../lib_xua/api', '../../lib_xua/src/core/pdm_mics', '../../lib_xua/src/hid',