Merge pull request #226 from CiaranWoodward/feature/multiple_hid_reports

Support multiple HID Reports & update examples for new API
This commit is contained in:
Michael Banther
2021-12-21 16:53:54 +00:00
committed by GitHub
26 changed files with 3354 additions and 872 deletions

2
.gitignore vendored
View File

@@ -20,6 +20,8 @@
test_results.csv
_build*
**/.venv/**
**/.vscode/**
**.egg-info
# waf build files
.lock-waf_*

View File

@@ -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
-----

2
Jenkinsfile vendored
View File

@@ -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")
}
}
}

View File

@@ -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__

View File

@@ -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__

View File

@@ -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__

View File

@@ -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__

View File

@@ -1,4 +1,4 @@
VERSION = 2.1.1
VERSION = 3.0.0
DEPENDENT_MODULES = lib_logging(>=3.0.0) \
lib_xassert(>=4.0.0) \

View File

@@ -21,8 +21,9 @@
#include "testct_byref.h"
#if( 0 < HID_CONTROLS )
#include "xua_hid_report_descriptor.h"
#include "xua_hid_report.h"
#include "user_hid.h"
#include "xua_hid.h"
unsigned char g_hidData[HID_MAX_DATA_BYTES] = {0};
#endif
@@ -372,9 +373,15 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#endif
#if( 0 < HID_CONTROLS )
UserHIDInit();
{
int hidDataLength = hidGetReportLength();
XUD_SetReady_In(ep_hid, g_hidData, hidDataLength);
while (!hidIsReportDescriptorPrepared())
;
/* Get the last report - we don't really care which it is, so long as there's some data we can grab. */
int hidReportLength = (int) UserHIDGetData(hidGetReportIdLimit() - 1, g_hidData);
XUD_SetReady_In(ep_hid, g_hidData, hidReportLength);
}
#endif
@@ -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 = 0U; 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

View File

@@ -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

View File

@@ -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();

View File

@@ -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 <stddef.h>
/**
* \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__ */

View File

@@ -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 */
@@ -209,18 +167,20 @@ 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 ));
hidSetIdle( reportId, ( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < 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 );
unsigned currentPeriod = hidGetReportPeriod( reportId );
if( hidIsIdleActive( reportId )) {
unsigned reportTime = hidGetReportTime( reportId );
unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( reportTime );
unsigned nextReportTime = HidCalcNewReportTime( currentPeriod, reportTime, reportToSetIdleInterval, duration * MS_IN_TICKS );
hidSetNextReportTime( reportId, nextReportTime );
currentPeriod = duration * MS_IN_TICKS;
} else {
s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS;
s_hidIndefiniteDuration = 0U;
currentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS;
}
hidSetReportPeriod( reportId, currentPeriod );
result = XUD_DoSetRequestStatus( c_ep0_in );
}

View File

@@ -0,0 +1,785 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <xs1.h>
#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 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 );
}
}

View File

@@ -1,276 +0,0 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <assert.h>
#include <stddef.h>
#include <xs1.h>
#include "xua_hid_report_descriptor.h"
#include "hid_report_descriptor.h"
#include <stdio.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 ))
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;
}

View File

@@ -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__

View File

@@ -0,0 +1,542 @@
// 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 <stddef.h>
#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 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_

View File

@@ -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 <stddef.h>
#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_

View File

@@ -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_

View File

@@ -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}

View File

@@ -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__

View File

@@ -0,0 +1,277 @@
// 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 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 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 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_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 )
};
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[] = {
&(hidReportConsumer.item),
&hidUsageConsumerControl,
&hidCollectionApplication,
&hidReportSize1,
&hidLogicalMinimum0,
&hidCollectionLogical, // Report 1
&hidReportId1,
&(hidReportKeyboard.item),
&hidLogicalMaximum1,
&hidReportCount1,
&(hidUsageReport1Byte0Bit0.item),
&hidInputDataVar,
&hidLogicalMaximum0,
&hidInputConstArray,
&hidLogicalMaximum1,
&(hidUsageReport1Byte0Bit2.item),
&hidInputDataVar,
&(hidUsageReport1Byte0Bit3.item),
&hidInputDataVar,
&hidLogicalMaximum0,
&hidReportCount4,
&hidInputConstArray,
&hidCollectionEnd,
&hidCollectionLogical, // 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,
&hidCollectionLogical, // Report 3
&hidReportId3,
&(hidReportTelephony.item),
&(hidUsageReport3Byte0Bit0.item),
&hidInputDataVar,
&(hidUsageReport3Byte0Bit1.item),
&hidInputDataVar,
&hidLogicalMaximum0,
&hidReportCount6,
&hidInputConstArray,
&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 ( 3 )
#endif // __hid_report_descriptor_h__

View File

@@ -0,0 +1,891 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <stddef.h>
#include <stdio.h>
#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 );
}
// 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 );
}

View File

@@ -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__

View File

@@ -4,14 +4,20 @@
#include <stdio.h>
#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,50 @@ 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 );
}
// 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 +100,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 +126,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 +143,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 +160,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 +177,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 +194,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 +212,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 +459,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 +476,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 +488,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 +501,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 +514,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 +534,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 +552,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 +560,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 +573,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 +581,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);
}

View File

@@ -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',