diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a0fed19f..d319216f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,30 @@ lib_xua Change Log ================== +2.0.0 +----- + + * ADDED: Function to get a Report item description + * CHANGED: Check HID Usage Page when changing a Report item description + * CHANGED: HID event ID from list to bit and byte location in HID Report + * CHANGED: Interface to UserHIDRecordEvent() + * ADDED: Support for multiple flash specs defined by DFU_FLASH_DEVICE + * ADDED: Nullable c_aud_ctl chan-end optimisation for fixed rate devices + +1.3.0 +----- + + * CHANGED: Move HID descriptors to ease maintenance + * CHANGED: Move legacy tests to separate directory + * CHANGED: Replace unused GPI-specific HID event names with generic ones + * ADDED: Build default HID Report descriptor at boot-time + * ADDED: Function to return length of HID Report + * CHANGED: HID Report to return multiple bytes + * CHANGED: NO_USB conditional compilation switch with XUA_USB_EN + * REMOVED: XS1 support + * CHANGED: Clock blocks used for BCLK and MCLK + * REMOVED: Arguments no longer supported by XUD_Main + 1.2.0 ----- diff --git a/Jenkinsfile b/Jenkinsfile index 092948c7..905b2301 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -27,11 +27,70 @@ pipeline { xcoreLibraryChecks("${REPO}") } } - stage('Tests') { - steps { - runXmostest("${REPO}", 'tests') + stage('XS2 Tests') { + failFast true + parallel { + stage('Legacy tests') { + steps { + runXmostest("${REPO}", 'legacy_tests') + } + } + stage('Unit tests') { + steps { + dir("${REPO}") { + dir('tests') { + dir('xua_unit_tests') { + withVenv { + runWaf('.', "configure clean build --target=xcore200") +// runWaf('.', "configure clean build --target=xcoreai") +// stash name: 'xua_unit_tests', includes: 'bin/*xcoreai.xe, ' + viewEnv() { + runPython("TARGET=XCORE200 pytest -n 1") + } + } + } + } + } + } + } } } +// stage('xcore.ai Verification') { +// agent { +// label 'xcore.ai-explorer' +// } +// options { +// skipDefaultCheckout() +// } +// stages{ +// stage('Get View') { +// steps { +// xcorePrepareSandbox("${VIEW}", "${REPO}") +// } +// } +// stage('Unit tests') { +// steps { +// dir("${REPO}") { +// dir('tests') { +// dir('xua_unit_tests') { +// withVenv { +// unstash 'xua_unit_tests' +// viewEnv() { +// runPython("TARGET=XCOREAI pytest -s") +// } +// } +// } +// } +// } +// } +// } +// } // stages +// post { +// cleanup { +// cleanWs() +// } +// } +// } stage('xCORE builds') { steps { dir("${REPO}") { diff --git a/examples/AN00246_xua_example/Makefile b/examples/AN00246_xua_example/Makefile index 9bdea14b..35489717 100644 --- a/examples/AN00246_xua_example/Makefile +++ b/examples/AN00246_xua_example/Makefile @@ -3,8 +3,9 @@ APP_NAME = app_xua_simple TARGET = xk-audio-216-mc.xn # The flags passed to xcc when building the application -XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report -fsubword-select -save-temps \ - -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] -fxscope +XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report -save-temps \ + -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES \ + -DXUD_CORE_CLOCK=600 -DUSB_TILE=tile[1] -fxscope #-DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope diff --git a/examples/AN00246_xua_example/src/app_xua_simple.xc b/examples/AN00246_xua_example/src/app_xua_simple.xc index 131a04db..f8302423 100644 --- a/examples/AN00246_xua_example/src/app_xua_simple.xc +++ b/examples/AN00246_xua_example/src/app_xua_simple.xc @@ -60,7 +60,6 @@ int main() /* Low level USB device layer core */ on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2, c_sof, epTypeTableOut, epTypeTableIn, - null, null, -1 , XUD_SPEED_HS, XUD_PWR_SELF); /* Endpoint 0 core from lib_xua */ diff --git a/examples/AN00246_xua_example/src/hid_report_descriptor.h b/examples/AN00246_xua_example/src/hid_report_descriptor.h new file mode 100644 index 00000000..a049576e --- /dev/null +++ b/examples/AN00246_xua_example/src/hid_report_descriptor.h @@ -0,0 +1,112 @@ +// 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" + +#if 0 +/* Existing static report descriptor kept for reference */ +unsigned char hidReportDescriptor[] = +{ + 0x05, 0x0c, /* Usage Page (Consumer Device) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x09, 0xb0, /* Usage (Play) */ + 0x09, 0xb5, /* Usage (Scan Next Track) */ + 0x09, 0xb6, /* Usage (Scan Previous Track) */ + 0x09, 0xe9, /* Usage (Volume Up) */ + 0x09, 0xea, /* Usage (Volume Down) */ + 0x09, 0xe2, /* Usage (Mute) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x06, /* Report Count (6) */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ + 0xc0 /* End collection */ +}; +#endif + +/* + * 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 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 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 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 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 + +/* + * List the configurable items in the HID Report descriptor. + */ +static USB_HID_Short_Item_t* const hidConfigurableItems[] = { + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5 +}; + +/* + * List Usage pages in the HID Report descriptor, one per byte. + */ +static const USB_HID_Short_Item_t* const hidUsagePages[] = { + &hidUsagePageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &hidUsagePageConsumer, + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidLogicalMinimum0, + &hidLogicalMaximum1, + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5, + &hidReportSize1, + &hidReportCount6, + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount2, + &hidInputConstArray, + &hidCollectionEnd +}; + +/* + * Define the length of the HID Report. + * This value must match the number of Report bytes defined by hidReportDescriptorItems. + */ +#define HID_REPORT_LENGTH ( 1 ) + +#endif // __hid_report_descriptor_h__ diff --git a/examples/AN00246_xua_example/src/xk-audio-216-mc.xn b/examples/AN00246_xua_example/src/xk-audio-216-mc.xn index c2e90f16..88e6d699 100644 --- a/examples/AN00246_xua_example/src/xk-audio-216-mc.xn +++ b/examples/AN00246_xua_example/src/xk-audio-216-mc.xn @@ -75,7 +75,7 @@ - + diff --git a/examples/AN00247_xua_example_spdif_tx/Makefile b/examples/AN00247_xua_example_spdif_tx/Makefile index cedcb1c7..f5b953ec 100644 --- a/examples/AN00247_xua_example_spdif_tx/Makefile +++ b/examples/AN00247_xua_example_spdif_tx/Makefile @@ -3,9 +3,9 @@ APP_NAME = app_xua_simple TARGET = xk-audio-216-mc.xn # The flags passed to xcc when building the application -XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report -fsubword-select -save-temps \ - -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] \ - -DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope +XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report -save-temps \ + -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES \ + -DXUD_CORE_CLOCK=600 -DUSB_TILE=tile[1] -DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope # The USED_MODULES variable lists other module used by the application. These # modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables. diff --git a/examples/AN00247_xua_example_spdif_tx/src/app_xua_simple.xc b/examples/AN00247_xua_example_spdif_tx/src/app_xua_simple.xc index 704479b8..d19f52c3 100644 --- a/examples/AN00247_xua_example_spdif_tx/src/app_xua_simple.xc +++ b/examples/AN00247_xua_example_spdif_tx/src/app_xua_simple.xc @@ -61,7 +61,7 @@ int main() par { /* Low level USB device layer core */ - on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2, c_sof, epTypeTableOut, epTypeTableIn, null, null, -1, XUD_SPEED_HS, XUD_PWR_SELF); + on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2, c_sof, epTypeTableOut, epTypeTableIn, XUD_SPEED_HS, XUD_PWR_SELF); /* Endpoint 0 core from lib_xua */ /* Note, since we are not using many features we pass in null for quite a few params.. */ diff --git a/examples/AN00247_xua_example_spdif_tx/src/hid_report_descriptor.h b/examples/AN00247_xua_example_spdif_tx/src/hid_report_descriptor.h new file mode 100644 index 00000000..a049576e --- /dev/null +++ b/examples/AN00247_xua_example_spdif_tx/src/hid_report_descriptor.h @@ -0,0 +1,112 @@ +// 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" + +#if 0 +/* Existing static report descriptor kept for reference */ +unsigned char hidReportDescriptor[] = +{ + 0x05, 0x0c, /* Usage Page (Consumer Device) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x09, 0xb0, /* Usage (Play) */ + 0x09, 0xb5, /* Usage (Scan Next Track) */ + 0x09, 0xb6, /* Usage (Scan Previous Track) */ + 0x09, 0xe9, /* Usage (Volume Up) */ + 0x09, 0xea, /* Usage (Volume Down) */ + 0x09, 0xe2, /* Usage (Mute) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x06, /* Report Count (6) */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ + 0xc0 /* End collection */ +}; +#endif + +/* + * 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 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 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 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 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 + +/* + * List the configurable items in the HID Report descriptor. + */ +static USB_HID_Short_Item_t* const hidConfigurableItems[] = { + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5 +}; + +/* + * List Usage pages in the HID Report descriptor, one per byte. + */ +static const USB_HID_Short_Item_t* const hidUsagePages[] = { + &hidUsagePageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &hidUsagePageConsumer, + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidLogicalMinimum0, + &hidLogicalMaximum1, + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5, + &hidReportSize1, + &hidReportCount6, + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount2, + &hidInputConstArray, + &hidCollectionEnd +}; + +/* + * Define the length of the HID Report. + * This value must match the number of Report bytes defined by hidReportDescriptorItems. + */ +#define HID_REPORT_LENGTH ( 1 ) + +#endif // __hid_report_descriptor_h__ diff --git a/examples/AN00247_xua_example_spdif_tx/src/hwsupport.xc b/examples/AN00247_xua_example_spdif_tx/src/hwsupport.xc index 203fa38e..84e0464b 100644 --- a/examples/AN00247_xua_example_spdif_tx/src/hwsupport.xc +++ b/examples/AN00247_xua_example_spdif_tx/src/hwsupport.xc @@ -22,7 +22,6 @@ out port p_gpio = on tile[0]:XS1_PORT_8C; void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) { - unsigned char data[1] = {0}; unsigned char gpioVal = 0; /* Set master clock select appropriately and put ADC and DAC into reset */ diff --git a/examples/AN00247_xua_example_spdif_tx/src/xk-audio-216-mc.xn b/examples/AN00247_xua_example_spdif_tx/src/xk-audio-216-mc.xn index c2e90f16..88e6d699 100644 --- a/examples/AN00247_xua_example_spdif_tx/src/xk-audio-216-mc.xn +++ b/examples/AN00247_xua_example_spdif_tx/src/xk-audio-216-mc.xn @@ -75,7 +75,7 @@ - + diff --git a/examples/AN00248_xua_example_pdm_mics/Makefile b/examples/AN00248_xua_example_pdm_mics/Makefile index 8681d0b5..e14afb94 100644 --- a/examples/AN00248_xua_example_pdm_mics/Makefile +++ b/examples/AN00248_xua_example_pdm_mics/Makefile @@ -3,9 +3,9 @@ APP_NAME = app_xua_simple TARGET = mic_array_ref.xn # The flags passed to xcc when building the application -XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report -fsubword-select -save-temps \ - -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] \ - -DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope +XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -O3 -report -save-temps \ + -g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES \ + -DXUD_CORE_CLOCK=600 -DUSB_TILE=tile[1] -DSDA_HIGH=2 -DSCL_HIGH=1 -fxscope # The USED_MODULES variable lists other module used by the application. These # modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables. diff --git a/examples/AN00248_xua_example_pdm_mics/src/app_xua_simple.xc b/examples/AN00248_xua_example_pdm_mics/src/app_xua_simple.xc index 6b7b299e..a3263ac8 100644 --- a/examples/AN00248_xua_example_pdm_mics/src/app_xua_simple.xc +++ b/examples/AN00248_xua_example_pdm_mics/src/app_xua_simple.xc @@ -65,7 +65,7 @@ int main() par { /* Low level USB device layer core */ - on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2, c_sof, epTypeTableOut, epTypeTableIn, null, null, -1, XUD_SPEED_HS, XUD_PWR_BUS); + on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2, c_sof, epTypeTableOut, epTypeTableIn, XUD_SPEED_HS, XUD_PWR_BUS); /* Endpoint 0 core from lib_xua */ /* Note, since we are not using many features we pass in null for quite a few params.. */ diff --git a/examples/AN00248_xua_example_pdm_mics/src/hid_report_descriptor.h b/examples/AN00248_xua_example_pdm_mics/src/hid_report_descriptor.h new file mode 100644 index 00000000..a049576e --- /dev/null +++ b/examples/AN00248_xua_example_pdm_mics/src/hid_report_descriptor.h @@ -0,0 +1,112 @@ +// 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" + +#if 0 +/* Existing static report descriptor kept for reference */ +unsigned char hidReportDescriptor[] = +{ + 0x05, 0x0c, /* Usage Page (Consumer Device) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x09, 0xb0, /* Usage (Play) */ + 0x09, 0xb5, /* Usage (Scan Next Track) */ + 0x09, 0xb6, /* Usage (Scan Previous Track) */ + 0x09, 0xe9, /* Usage (Volume Up) */ + 0x09, 0xea, /* Usage (Volume Down) */ + 0x09, 0xe2, /* Usage (Mute) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x06, /* Report Count (6) */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ + 0xc0 /* End collection */ +}; +#endif + +/* + * 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 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 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 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 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 + +/* + * List the configurable items in the HID Report descriptor. + */ +static USB_HID_Short_Item_t* const hidConfigurableItems[] = { + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5 +}; + +/* + * List Usage pages in the HID Report descriptor, one per byte. + */ +static const USB_HID_Short_Item_t* const hidUsagePages[] = { + &hidUsagePageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &hidUsagePageConsumer, + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidLogicalMinimum0, + &hidLogicalMaximum1, + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5, + &hidReportSize1, + &hidReportCount6, + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount2, + &hidInputConstArray, + &hidCollectionEnd +}; + +/* + * Define the length of the HID Report. + * This value must match the number of Report bytes defined by hidReportDescriptorItems. + */ +#define HID_REPORT_LENGTH ( 1 ) + +#endif // __hid_report_descriptor_h__ diff --git a/examples/AN00248_xua_example_pdm_mics/src/mic_array_ref.xn b/examples/AN00248_xua_example_pdm_mics/src/mic_array_ref.xn index 66caa132..a9e1b9b4 100644 --- a/examples/AN00248_xua_example_pdm_mics/src/mic_array_ref.xn +++ b/examples/AN00248_xua_example_pdm_mics/src/mic_array_ref.xn @@ -81,7 +81,7 @@ - + diff --git a/tests/app_test_i2s_loopback/Makefile b/legacy_tests/app_test_i2s_loopback/Makefile similarity index 97% rename from tests/app_test_i2s_loopback/Makefile rename to legacy_tests/app_test_i2s_loopback/Makefile index 4f54fc80..81a8e145 100644 --- a/tests/app_test_i2s_loopback/Makefile +++ b/legacy_tests/app_test_i2s_loopback/Makefile @@ -3,7 +3,7 @@ TARGET = xk-audio-216-mc.xn USED_MODULES = lib_xua \ module_i2c_shared module_i2c_single_port lib_logging -BUILD_FLAGS = -O0 -g -lflash -DXUD_SERIES_SUPPORT=4 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1] +BUILD_FLAGS = -O0 -g -lflash -DXUD_SERIES_SUPPORT=4 -DXUD_CORE_CLOCK=600 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1] BUILD_FLAGS_i2s_master_2in_2out_48khz = $(BUILD_FLAGS) \ -D ADAT_RX=0 -D ADAT_TX=0 -D SPDIF_RX=0 -D SPDIF_TX=0 -D MIDI=0 \ diff --git a/tests/app_test_i2s_loopback/debug_conf.h b/legacy_tests/app_test_i2s_loopback/debug_conf.h similarity index 100% rename from tests/app_test_i2s_loopback/debug_conf.h rename to legacy_tests/app_test_i2s_loopback/debug_conf.h diff --git a/legacy_tests/app_test_i2s_loopback/hid_report_descriptor.h b/legacy_tests/app_test_i2s_loopback/hid_report_descriptor.h new file mode 100644 index 00000000..a049576e --- /dev/null +++ b/legacy_tests/app_test_i2s_loopback/hid_report_descriptor.h @@ -0,0 +1,112 @@ +// 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" + +#if 0 +/* Existing static report descriptor kept for reference */ +unsigned char hidReportDescriptor[] = +{ + 0x05, 0x0c, /* Usage Page (Consumer Device) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x09, 0xb0, /* Usage (Play) */ + 0x09, 0xb5, /* Usage (Scan Next Track) */ + 0x09, 0xb6, /* Usage (Scan Previous Track) */ + 0x09, 0xe9, /* Usage (Volume Up) */ + 0x09, 0xea, /* Usage (Volume Down) */ + 0x09, 0xe2, /* Usage (Mute) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x06, /* Report Count (6) */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ + 0xc0 /* End collection */ +}; +#endif + +/* + * 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 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 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 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 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 + +/* + * List the configurable items in the HID Report descriptor. + */ +static USB_HID_Short_Item_t* const hidConfigurableItems[] = { + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5 +}; + +/* + * List Usage pages in the HID Report descriptor, one per byte. + */ +static const USB_HID_Short_Item_t* const hidUsagePages[] = { + &hidUsagePageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &hidUsagePageConsumer, + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidLogicalMinimum0, + &hidLogicalMaximum1, + &hidUsageByte0Bit0, + &hidUsageByte0Bit1, + &hidUsageByte0Bit2, + &hidUsageByte0Bit3, + &hidUsageByte0Bit4, + &hidUsageByte0Bit5, + &hidReportSize1, + &hidReportCount6, + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount2, + &hidInputConstArray, + &hidCollectionEnd +}; + +/* + * Define the length of the HID Report. + * This value must match the number of Report bytes defined by hidReportDescriptorItems. + */ +#define HID_REPORT_LENGTH ( 1 ) + +#endif // __hid_report_descriptor_h__ diff --git a/tests/app_test_i2s_loopback/main.xc b/legacy_tests/app_test_i2s_loopback/main.xc similarity index 100% rename from tests/app_test_i2s_loopback/main.xc rename to legacy_tests/app_test_i2s_loopback/main.xc diff --git a/tests/app_test_i2s_loopback/simulation.xc b/legacy_tests/app_test_i2s_loopback/simulation.xc similarity index 100% rename from tests/app_test_i2s_loopback/simulation.xc rename to legacy_tests/app_test_i2s_loopback/simulation.xc diff --git a/tests/app_test_i2s_loopback/usb_device.h b/legacy_tests/app_test_i2s_loopback/usb_device.h similarity index 100% rename from tests/app_test_i2s_loopback/usb_device.h rename to legacy_tests/app_test_i2s_loopback/usb_device.h diff --git a/tests/app_test_i2s_loopback/usb_device.xc b/legacy_tests/app_test_i2s_loopback/usb_device.xc similarity index 100% rename from tests/app_test_i2s_loopback/usb_device.xc rename to legacy_tests/app_test_i2s_loopback/usb_device.xc diff --git a/tests/app_test_i2s_loopback/xk_216_mc/audiohw.xc b/legacy_tests/app_test_i2s_loopback/xk_216_mc/audiohw.xc similarity index 100% rename from tests/app_test_i2s_loopback/xk_216_mc/audiohw.xc rename to legacy_tests/app_test_i2s_loopback/xk_216_mc/audiohw.xc diff --git a/tests/app_test_i2s_loopback/xk_216_mc/cs2100.h b/legacy_tests/app_test_i2s_loopback/xk_216_mc/cs2100.h similarity index 100% rename from tests/app_test_i2s_loopback/xk_216_mc/cs2100.h rename to legacy_tests/app_test_i2s_loopback/xk_216_mc/cs2100.h diff --git a/tests/app_test_i2s_loopback/xk_216_mc/cs4384.h b/legacy_tests/app_test_i2s_loopback/xk_216_mc/cs4384.h similarity index 100% rename from tests/app_test_i2s_loopback/xk_216_mc/cs4384.h rename to legacy_tests/app_test_i2s_loopback/xk_216_mc/cs4384.h diff --git a/tests/app_test_i2s_loopback/xk_216_mc/cs5368.h b/legacy_tests/app_test_i2s_loopback/xk_216_mc/cs5368.h similarity index 100% rename from tests/app_test_i2s_loopback/xk_216_mc/cs5368.h rename to legacy_tests/app_test_i2s_loopback/xk_216_mc/cs5368.h diff --git a/tests/app_test_i2s_loopback/xk_216_mc/gpio_access.c b/legacy_tests/app_test_i2s_loopback/xk_216_mc/gpio_access.c similarity index 100% rename from tests/app_test_i2s_loopback/xk_216_mc/gpio_access.c rename to legacy_tests/app_test_i2s_loopback/xk_216_mc/gpio_access.c diff --git a/tests/app_test_i2s_loopback/xk_216_mc/gpio_access.h b/legacy_tests/app_test_i2s_loopback/xk_216_mc/gpio_access.h similarity index 100% rename from tests/app_test_i2s_loopback/xk_216_mc/gpio_access.h rename to legacy_tests/app_test_i2s_loopback/xk_216_mc/gpio_access.h diff --git a/tests/app_test_i2s_loopback/xk_216_mc/xk-audio-216-mc.xn b/legacy_tests/app_test_i2s_loopback/xk_216_mc/xk-audio-216-mc.xn similarity index 93% rename from tests/app_test_i2s_loopback/xk_216_mc/xk-audio-216-mc.xn rename to legacy_tests/app_test_i2s_loopback/xk_216_mc/xk-audio-216-mc.xn index a9f765b0..cffd732f 100644 --- a/tests/app_test_i2s_loopback/xk_216_mc/xk-audio-216-mc.xn +++ b/legacy_tests/app_test_i2s_loopback/xk_216_mc/xk-audio-216-mc.xn @@ -83,10 +83,12 @@ - + + + diff --git a/tests/app_test_i2s_loopback/xua_conf.h b/legacy_tests/app_test_i2s_loopback/xua_conf.h similarity index 96% rename from tests/app_test_i2s_loopback/xua_conf.h rename to legacy_tests/app_test_i2s_loopback/xua_conf.h index bec236b1..a1120f49 100644 --- a/tests/app_test_i2s_loopback/xua_conf.h +++ b/legacy_tests/app_test_i2s_loopback/xua_conf.h @@ -4,7 +4,7 @@ #define __custom_defines_h__ #define EXCLUDE_USB_AUDIO_MAIN -#define NUM_PDM_MICS 0 +#define XUA_NUM_PDM_MICS 0 #define XUD_TILE 1 #define AUDIO_IO_TILE 0 #define MIXER 0 diff --git a/tests/pass.expect b/legacy_tests/pass.expect similarity index 100% rename from tests/pass.expect rename to legacy_tests/pass.expect diff --git a/tests/runtests.py b/legacy_tests/runtests.py similarity index 100% rename from tests/runtests.py rename to legacy_tests/runtests.py diff --git a/tests/test_i2s_loopback.py b/legacy_tests/test_i2s_loopback.py similarity index 100% rename from tests/test_i2s_loopback.py rename to legacy_tests/test_i2s_loopback.py diff --git a/lib_xua/api/xua_endpoint0.h b/lib_xua/api/xua_endpoint0.h index b7cfdfc6..05d56d6d 100644 --- a/lib_xua/api/xua_endpoint0.h +++ b/lib_xua/api/xua_endpoint0.h @@ -15,7 +15,10 @@ * \param c_ep0_out Chanend connected to the XUD_Manager() out endpoint array * \param c_ep0_in Chanend connected to the XUD_Manager() in endpoint array * \param c_audioCtrl Chanend connected to the decouple thread for control - * audio (sample rate changes etc.) + * audio (sample rate changes etc.). Note when nulled, the + * audio device only supports single sample rate/format and + * DFU is not supported either since this channel is used + * to carry messages about format, rate and DFU state * \param c_mix_ctl Optional chanend to be connected to the mixer thread if * present * \param c_clk_ctl Optional chanend to be connected to the clockgen thread if @@ -25,7 +28,7 @@ * \param c_EANativeTransport_ctrl Optional chanend to be connected to EA Native * endpoint manager if present */ -void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCtrl, +void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend ?c_audioCtrl, chanend ?c_mix_ctl,chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctr, client interface i_dfu ?dfuInterface VENDOR_REQUESTS_PARAMS_DEC_); diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index 67df655e..6de9f46c 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -1,8 +1,8 @@ -VERSION = 1.2.0 +VERSION = 2.0.0 DEPENDENT_MODULES = lib_logging(>=3.0.0) \ lib_xassert(>=4.0.0) \ - lib_xud(>=1.0.0) \ + lib_xud(>=2.0.0) \ lib_spdif(>=4.0.0) \ lib_mic_array(>=4.0.0) @@ -40,7 +40,6 @@ INCLUDE_DIRS = $(EXPORT_INCLUDE_DIRS) \ src/core/pdm_mics \ src/core/ports \ src/core/support \ - src/core/support/powersave \ src/core/user \ src/core/user/audiostream \ src/core/user/hid \ @@ -58,7 +57,6 @@ SOURCE_DIRS = src/core \ src/core/pdm_mics \ src/core/ports \ src/core/support \ - src/core/support/powersave \ src/core/user/audiostream \ src/core/user/hostactive \ src/core/xuduser \ diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index 50f475bd..eb6b373a 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -21,8 +21,9 @@ #include "testct_byref.h" #if( 0 < HID_CONTROLS ) +#include "xua_hid_report_descriptor.h" #include "user_hid.h" -unsigned char g_hidData[HID_DATA_BYTES] = {0}; +unsigned char g_hidData[HID_MAX_DATA_BYTES] = {0}; #endif void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max); @@ -371,7 +372,10 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #if( 0 < HID_CONTROLS ) - XUD_SetReady_In(ep_hid, g_hidData, 1); + { + int hidDataLength = hidGetReportLength(); + XUD_SetReady_In(ep_hid, g_hidData, hidDataLength); + } #endif #if (AUDIO_CLASS == 1) @@ -885,9 +889,9 @@ void XUA_Buffer_Ep(register chanend c_aud_out, /* HID Report Data */ case XUD_SetData_Select(c_hid, ep_hid, result): { - g_hidData[0]=0; + int hidDataLength = hidGetReportLength(); UserHIDGetData(g_hidData); - XUD_SetReady_In(ep_hid, g_hidData, 1); + XUD_SetReady_In(ep_hid, g_hidData, hidDataLength); } break; #endif diff --git a/lib_xua/src/core/endpoint0/vendorrequests.c b/lib_xua/src/core/endpoint0/vendorrequests.c index 66a1ac09..e5384b9c 100644 --- a/lib_xua/src/core/endpoint0/vendorrequests.c +++ b/lib_xua/src/core/endpoint0/vendorrequests.c @@ -7,12 +7,12 @@ #include "vendorrequests.h" int VendorAudioRequests(XUD_ep ep0_out, XUD_ep ep0_in, unsigned char bRequest, unsigned char cs, unsigned char cn, - unsigned short unitId, unsigned char direction, chanend c_audioControl, + unsigned short unitId, unsigned char direction, NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctL)) __attribute__ ((weak)); int VendorAudioRequests(XUD_ep ep0_out, XUD_ep ep0_in, unsigned char bRequest, unsigned char cs, unsigned char cn, - unsigned short unitId, unsigned char direction, chanend c_audioControl, + unsigned short unitId, unsigned char direction, NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctL)) { diff --git a/lib_xua/src/core/endpoint0/vendorrequests.h b/lib_xua/src/core/endpoint0/vendorrequests.h index c241011d..d00a5873 100644 --- a/lib_xua/src/core/endpoint0/vendorrequests.h +++ b/lib_xua/src/core/endpoint0/vendorrequests.h @@ -33,7 +33,7 @@ #endif int VendorAudioRequests(XUD_ep ep0_out, XUD_ep ep0_in, unsigned char bRequest, unsigned char cs, unsigned char cn, - unsigned short unitId, unsigned char direction, chanend c_audioControl, + unsigned short unitId, unsigned char direction, NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctL)); diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index 40064918..a89f6330 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "xua.h" #if XUA_USB_EN @@ -23,18 +24,24 @@ #include "vendorrequests.h" #include "xc_ptr.h" #include "xua_ep0_uacreqs.h" + #if( 0 < HID_CONTROLS ) #include "hid.h" +#include "xua_hid.h" +#include "xua_hid_report_descriptor.h" #endif + #if DSD_CHANS_DAC > 0 #include "dsd_support.h" #endif + #define DEBUG_UNIT XUA_EP0 + #ifndef DEBUG_PRINT_ENABLE_XUA_EP0 #define DEBUG_PRINT_ENABLE_XUA_EP0 0 #endif // DEBUG_PRINT_ENABLE_XUA_EP0 -#include "debug_print.h" +#include "debug_print.h" #include "xua_usb_params_funcs.h" #ifndef __XC__ @@ -51,7 +58,7 @@ #if ((AUDIO_CLASS == 1) || (AUDIO_CLASS_FALLBACK)) && defined(DFU) #warning DFU will not be enabled in AUDIO 1.0 mode due to Windows requesting driver #endif -#endif +#endif // FORCE_UAC1_DFU /* MIDI not supported in Audio 1.0 mode */ #if ((AUDIO_CLASS == 1) || (AUDIO_CLASS_FALLBACK)) && defined(MIDI) @@ -85,9 +92,6 @@ extern void device_reboot(void); #endif -#if( 0 < HID_CONTROLS ) -#include "xua_hid.h" -#endif #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif @@ -391,7 +395,7 @@ void XUA_Endpoint0_setBcdDevice(unsigned short bcd) { #endif // AUDIO_CLASS == 1} } -void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, +void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(chanend, c_audioControl), chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { ep0_out = XUD_InitEp(c_ep0_out); @@ -478,6 +482,8 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCont /* Check if device has started in DFU mode */ if (DFUReportResetState(null)) { + assert((c_audioControl != NULL) && msg("DFU not supported when c_audioControl is null")); + /* Stop audio */ outuint(c_audioControl, SET_SAMPLE_FREQ); outuint(c_audioControl, AUDIO_STOP_FOR_DFU); @@ -518,9 +524,25 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioCont #endif +#if( 0 < HID_CONTROLS ) + hidPrepareReportDescriptor(); + + size_t hidReportDescriptorLength = hidGetReportDescriptorLength(); + unsigned char hidReportDescriptorLengthLo = hidReportDescriptorLength & 0xFF; + unsigned char hidReportDescriptorLengthHi = (hidReportDescriptorLength & 0xFF00) >> 8; + +#if( AUDIO_CLASS == 1 ) + cfgDesc_Audio1[USB_HID_DESCRIPTOR_OFFSET + HID_DESCRIPTOR_LENGTH_FIELD_OFFSET ] = hidReportDescriptorLengthLo; + cfgDesc_Audio1[USB_HID_DESCRIPTOR_OFFSET + HID_DESCRIPTOR_LENGTH_FIELD_OFFSET + 1] = hidReportDescriptorLengthHi; +#endif + + hidDescriptor[HID_DESCRIPTOR_LENGTH_FIELD_OFFSET ] = hidReportDescriptorLengthLo; + hidDescriptor[HID_DESCRIPTOR_LENGTH_FIELD_OFFSET + 1] = hidReportDescriptorLengthHi; +#endif // 0 < HID_CONTROLS + } -void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, +void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(chanend, c_audioControl), chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { if (result == XUD_RES_OKAY) @@ -547,6 +569,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 /* Only send change if we need to */ if((sp.wValue > 0) && (g_curStreamAlt_Out != sp.wValue)) { + assert((c_audioControl != null) && msg("Format change not supported when c_audioControl is null")); g_curStreamAlt_Out = sp.wValue; /* Send format of data onto buffering */ @@ -582,6 +605,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 /* Only send change if we need to */ if((sp.wValue > 0) && (g_curStreamAlt_In != sp.wValue)) { + assert((c_audioControl != null) && msg("Format change not supported when c_audioControl is null")); g_curStreamAlt_In = sp.wValue; /* Send format of data onto buffering */ @@ -729,15 +753,22 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 switch (descriptorType) { case HID_HID: - /* Return HID Descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, - sizeof(hidDescriptor), sp.wLength); + { + /* Return HID Descriptor */ + result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, + sizeof(hidDescriptor), sp.wLength); + } break; case HID_REPORT: - /* Return HID report descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, - sizeof(hidReportDescriptor), sp.wLength); - break; + { + /* Return HID report descriptor */ + unsigned char* hidReportDescriptorPtr; + hidReportDescriptorPtr = hidGetReportDescriptor(); + size_t hidReportDescriptorLength = hidGetReportDescriptorLength(); + result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptorPtr, + hidReportDescriptorLength, sp.wLength); + } + break; } } break; @@ -819,6 +850,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 if ((DFU_IF == INTERFACE_NUMBER_DFU) && (sp.bRequest != XMOS_DFU_SAVESTATE) && (sp.bRequest != XMOS_DFU_RESTORESTATE)) { + assert((c_audioControl != null) && msg("DFU not supported when c_audioControl is null")); // Stop audio outuint(c_audioControl, SET_SAMPLE_FREQ); outuint(c_audioControl, AUDIO_STOP_FOR_DFU); @@ -1061,7 +1093,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0 } /* Endpoint 0 function. Handles all requests to the device */ -void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, +void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(chanend, c_audioControl), chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { USB_SetupPacket_t sp; diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index 4e219a58..d8513888 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -15,7 +15,7 @@ #include "usbaudio20.h" /* Defines from the USB Audio 2.0 Specifications */ #include "usbaudiocommon.h" #include "xud_device.h" -#include "usbaudio20.h" /* Defines from USB Audio 2.0 spec */ +#include "xua_hid_descriptor.h" #ifdef IAP_EA_NATIVE_TRANS #include "iap2.h" /* Defines iAP EA Native Transport protocol name */ @@ -580,33 +580,6 @@ unsigned char devQualDesc_Null[] = #define MIXER_LENGTH (0) #endif -#if( 0 < HID_CONTROLS ) -unsigned char hidReportDescriptor[] = /* Voice Command usage as per request #HUTRR45 */ -{ - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x06, /* Usage (Keyboard) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x04, /* Report Count (4) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x00, /* Logical Maximum (0) */ - 0x81, 0x01, /* Input (Cnst, Ary, Abs, No Wrap, Lin, Pref, No Nul) */ - 0x95, 0x01, /* Report Count (1) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x05, 0x0C, /* Usage Page (Consumer) */ - 0x0a, 0x21, 0x02, /* Usage (AC Search) */ - 0x81, 0x02, /* Input (Data, Var, Abs, No Wrap, Lin, Pref, No Nul) */ - 0x0a, 0x26, 0x02, /* Usage (AC Stop) */ - 0x81, 0x02, /* Input (Data, Var, Abs, No Wrap, Lin, Pref, No Nul) */ - 0x95, 0x02, /* Report Count (2) */ - 0x05, 0x07, /* Usage Page (Key Codes) */ - 0x19, 0x72, /* Usage Minimum (Keyboard F23) */ - 0x29, 0x73, /* Usage Maximum (Keyboard F24) */ - 0x81, 0x02, /* Input (Data, Var, Abs, No Wrap, Lin, Pref, No Nul) */ - 0xc0 /* End collection (Application) */ -}; -#endif - /* Max packet sizes: * Samples per channel. e.g (192000+7999/8000) = 24 * Must allow 1 sample extra per chan (24 + 1) = 25 @@ -808,7 +781,7 @@ typedef struct #if( 0 < HID_CONTROLS ) USB_Descriptor_Interface_t HID_Interface; - unsigned char hidDesc[9]; //TODO ideally we would have a struct for this. + USB_HID_Descriptor_t HID_Descriptor; USB_Descriptor_Endpoint_t HID_In_Endpoint; #endif @@ -1939,7 +1912,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .wLockDelay = 0x0008, }, #endif /* (INPUT_FORMAT_COUNT > 2) */ -#endif /* #if(NUM_USB_CHAN_IN > 0) */ +#endif /* (NUM_USB_CHAN_IN > 0) */ #ifdef MIDI /* MIDI Descriptors */ @@ -2204,60 +2177,24 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= #endif /* IAP */ #if( 0 < HID_CONTROLS ) - .HID_Interface = - { - 9, /* 0 bLength : Size of descriptor in Bytes */ - 4, /* 1 bDescriptorType (Interface: 0x04)*/ - INTERFACE_NUMBER_HID, /* 2 bInterfaceNumber : Number of interface */ - 0, /* 3 bAlternateSetting : Value used alternate interfaces using SetInterface Request */ - 1, /* 4: bNumEndpoints : Number of endpoitns for this interface (excluding 0) */ - 3, /* 5: bInterfaceClass */ - 0, /* 6: bInterfaceSubClass - no boot device */ - 0, /* 7: bInterfaceProtocol*/ - 0, /* 8 iInterface */ - }, - - { - 9, /* 0 bLength : Size of descriptor in Bytes */ - 0x21, /* 1 bDescriptorType (HID) */ - 0x10, /* 2 bcdHID */ - 0x01, /* 3 bcdHID */ - 0, /* 4 bCountryCode */ - 1, /* 5 bNumDescriptors */ - 0x22, /* 6 bDescriptorType[0] (Report) */ - sizeof(hidReportDescriptor) & 0xff,/* 7 wDescriptorLength[0] */ - sizeof(hidReportDescriptor) >> 8, /* 8 wDescriptorLength[0] */ - }, - - .HID_In_Endpoint = - { - /* Endpoint descriptor (IN) */ - 0x7, /* 0 bLength */ - 5, /* 1 bDescriptorType */ - ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ - 3, /* 3 bmAttributes (INTERRUPT) */ - 64, /* 4 wMaxPacketSize */ - ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */ - } + #include "xua_hid_descriptors.h" #endif }; #endif /* (AUDIO_CLASS == 2) */ #if( 0 < HID_CONTROLS ) +#if (AUDIO_CLASS ==1 ) unsigned char hidDescriptor[] = { - 0x09, /* 0 bLength : Size of descriptor in Bytes */ - 0x21, /* 1 bDescriptorType (HID) */ - 0x10, /* 2 bcdHID */ - 0x01, /* 3 bcdHID */ - 0x00, /* 4 bCountryCode */ - 0x01, /* 5 bNumDescriptors */ - 0x22, /* 6 bDescriptorType[0] (Report) */ - sizeof(hidReportDescriptor) & 0xff, /* 7 wDescriptorLength[0] */ - sizeof(hidReportDescriptor) >> 8, /* 8 wDescriptorLength[0] */ + #include "xua_hid_descriptor_contents.h" }; +#elif (AUDIO_CLASS == 2) +unsigned char* hidDescriptor = (unsigned char*) &cfgDesc_Audio2.HID_Descriptor; +#else + #error "Unknown Audio Class" #endif +#endif // 0 < HID_CONTROLS /* Configuration Descriptor for Null device */ @@ -2362,6 +2299,12 @@ const unsigned num_freqs_a1 = MAX(3, (0 #endif #if( 0 < HID_CONTROLS ) +/* + * The value of HID_INTERFACE_BYTES must match the length of the descriptors defined in + * - xua_hid_descriptor_contents.h + * - xua_hid_endpoint_descriptor_contents.h and + * - xua_hid_interface_descriptor_contents.h + */ #define HID_INTERFACE_BYTES ( 9 + 9 + 7 ) #define HID_INTERFACES_A1 1 #else @@ -2403,6 +2346,10 @@ const unsigned num_freqs_a1 = MAX(3, (0 #endif +#if( 0 < HID_CONTROLS ) + #define USB_HID_DESCRIPTOR_OFFSET (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + INTERFACE_DESCRIPTOR_BYTES) +#endif + #define CHARIFY_SR(x) (x & 0xff),((x & 0xff00)>> 8),((x & 0xff0000)>> 16) #if (MIN_FREQ_FS < 12000) && (MAX_FREQ_FS > 48000) @@ -2906,36 +2853,7 @@ unsigned char cfgDesc_Audio1[] = #endif #if( 0 < HID_CONTROLS ) - /* HID interface descriptor */ - 0x09, /* 0 bLength : Size of descriptor in Bytes */ - 0x04, /* 1 bDescriptorType (Interface: 0x04)*/ - INTERFACE_NUMBER_HID, /* 2 bInterfaceNumber : Number of interface */ - 0x00, /* 3 bAlternateSetting : Value used alternate interfaces using SetInterface Request */ - 0x01, /* 4: bNumEndpoints : Number of endpoitns for this interface (excluding 0) */ - 0x03, /* 5: bInterfaceClass */ - 0x00, /* 6: bInterfaceSubClass - no boot device */ - 0x00, /* 7: bInterfaceProtocol*/ - 0x00, /* 8 iInterface */ - - /* HID descriptor */ - 0x09, /* 0 bLength : Size of descriptor in Bytes */ - 0x21, /* 1 bDescriptorType (HID) */ - 0x10, /* 2 bcdHID */ - 0x01, /* 3 bcdHID */ - 0x00, /* 4 bCountryCode */ - 0x01, /* 5 bNumDescriptors */ - 0x22, /* 6 bDescriptorType[0] (Report) */ - sizeof(hidReportDescriptor) & 0xff, /* 7 wDescriptorLength[0] */ - sizeof(hidReportDescriptor) >> 8, /* 8 wDescriptorLength[0] */ - - /* HID Endpoint descriptor (IN) */ - 0x07, /* 0 bLength */ - 0x05, /* 1 bDescriptorType */ - ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ - 0x03, /* 3 bmAttributes (INTERRUPT) */ - 0x40, /* 4 wMaxPacketSize */ - 0x00, /* 5 wMaxPacketSize */ - ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */ + #include "xua_hid_descriptors.h" #endif }; diff --git a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc index 89169336..18d53f4d 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc @@ -1285,4 +1285,4 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket return XUD_RES_ERR; } #endif -#endif /* NO_USB */ +#endif /* XUA_USB_EN */ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 421793f2..afa1602e 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -187,20 +187,20 @@ on tile[XUD_TILE] : clock clk_spd_rx = CLKBLK_SPDIF_RX; #endif #if (XUA_NUM_PDM_MICS > 0) -in port p_pdm_clk = PORT_PDM_CLK; +in port p_pdm_clk = PORT_PDM_CLK; -in buffered port:32 p_pdm_mics = PORT_PDM_DATA; +in buffered port:32 p_pdm_mics = PORT_PDM_DATA; #if (PDM_TILE != AUDIO_IO_TILE) /* If Mics and I2S are not the same tile we need a separate MCLK port */ -in port p_pdm_mclk = PORT_PDM_MCLK; +in port p_pdm_mclk = PORT_PDM_MCLK; #endif #endif -#if(XUD_SERIES_SUPPORT == XUD_L_SERIES) && (ADAT_RX) +#if (defined(__XS2A__) && (ADAT_RX)) /* Cannot use default clock (CLKBLK_REF) for ADAT RX since it is tied to the -60MHz USB clock on G/L series parts. */ +60MHz USB clock on XS2 processors. */ on tile[XUD_TILE] : clock clk_adat_rx = CLKBLK_ADAT_RX; #endif @@ -212,15 +212,14 @@ on tile[XUD_TILE] : clock clk_audio_mclk_usb = CLKBLK_MCLK; on tile[XUD_TILE] : in port p_mclk_in_usb = PORT_MCLK_IN_USB; #endif -on tile[AUDIO_IO_TILE] : clock clk_audio_bclk = CLKBLK_I2S_BIT; /* Bit clock */ +on tile[AUDIO_IO_TILE] : clock clk_audio_bclk = CLKBLK_I2S_BIT; /* Bit clock */ /* L/G Series needs a port to use for USB reset */ -#if (XUD_SERIES_SUPPORT != XUD_U_SERIES) && defined(PORT_USB_RESET) +#if ((defined(__XS2A__) || defined (__XS3A__)) && defined(PORT_USB_RESET)) /* This define is checked since it could be on a shift reg or similar */ on tile[XUD_TILE] : out port p_usb_rst = PORT_USB_RESET; #else -/* Reset port not required for U series due to built in Phy */ #define p_usb_rst null #endif @@ -346,8 +345,7 @@ VENDOR_REQUESTS_PARAMS_DEC_ /* USB Interface Core */ XUD_Main(c_xud_out, ENDPOINT_COUNT_OUT, c_xud_in, ENDPOINT_COUNT_IN, - c_sof, epTypeTableOut, epTypeTableIn, p_usb_rst, - null, 0, usbSpeed, XUD_PWR_CFG); + c_sof, epTypeTableOut, epTypeTableIn, usbSpeed, XUD_PWR_CFG); } /* USB Packet buffering Core */ @@ -727,8 +725,8 @@ int main() { set_thread_fast_mode_on(); -#if(XUD_SERIES_SUPPORT == XUD_L_SERIES) - /* Can't use REF clock on L-series as this is usb clock */ +#if defined(__XS2A__) + /* Can't use REF clock as this is usb clock */ set_port_clock(p_adat_rx, clk_adat_rx); start_clock(clk_adat_rx); #endif diff --git a/lib_xua/src/core/support/powersave/archU_powerSaving.h b/lib_xua/src/core/support/powersave/archU_powerSaving.h deleted file mode 100644 index 51f8281d..00000000 --- a/lib_xua/src/core/support/powersave/archU_powerSaving.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2013-2021 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. -#ifndef ARCH_U_POWER_SAVING_ -#define ARCH_U_POWER_SAVING_ - -/* Sets the voltage down by VOLTAGE_REDUCTION_mV (voltage is set to 10 * X + 600 mV), - * and adjusts other features to save power - */ -void archU_powerSaving(); - -#endif /*ARCH_U_POWER_SAVING_*/ diff --git a/lib_xua/src/core/support/powersave/archU_powerSaving.xc b/lib_xua/src/core/support/powersave/archU_powerSaving.xc deleted file mode 100644 index e6cd04c5..00000000 --- a/lib_xua/src/core/support/powersave/archU_powerSaving.xc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2013-2021 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#if (XUD_SERIES_SUPPORT==1) -#include "archU_powerSaving.h" -#include -#include -#include -#include - -#if (XCC_MAJOR_VERSION >= 1300) -#include -#else -#define hwtimer_t timer -#endif - -#ifndef VOLTAGE_REDUCTION_mV -#define VOLTAGE_REDUCTION_mV 20 -#endif - -unsigned get_tile_id(tileref t); // Required for use with 12.0 tools. get_tile_id() available in xs1.h with 13.0 tools. - -#define ARCH_U_VOLTAGE_FIRST_STEP 39 // First step down from 1V -#define ARCH_U_SSWITCH_PRESCALER 8 // Sswitch down to 1/8 clk freq - -void archU_powerSaving() -{ - if (get_local_tile_id() == get_tile_id(tile[0])) - { - unsigned writeval[1]; - unsigned char writevalc[1]; - - // Reduce the VDDCORE voltage level - for (unsigned count=0; count < (VOLTAGE_REDUCTION_mV/10); count++) - { - hwtimer_t t; - int time; - - writeval[0] = (ARCH_U_VOLTAGE_FIRST_STEP - count); - write_periph_32(usb_tile, XS1_SU_PER_PWR_CHANEND_NUM, XS1_SU_PER_PWR_VOUT1_LVL_NUM, 1, writeval); - - t :> time; - time += (1 * PLATFORM_REFERENCE_MHZ); // Wait 1us per step - t when timerafter(time) :> void; - } - - // Set switch prescaler down - write_node_config_reg(tile[0], XS1_SSWITCH_CLK_DIVIDER_NUM, (ARCH_U_SSWITCH_PRESCALER - 1)); // PLL clk will be divided by value + 1 - - // Both DC-DCs in PWM mode, I/O and PLL supply on, Analogue & core on - writeval[0] = XS1_SU_PWR_VOUT1_EN_SET(0, 1); - writeval[0] = XS1_SU_PWR_VOUT2_EN_SET(writeval[0], 1); - writeval[0] = XS1_SU_PWR_VOUT5_EN_SET(writeval[0], 1); - writeval[0] = XS1_SU_PWR_VOUT6_EN_SET(writeval[0], 1); - write_periph_32(usb_tile, XS1_SU_PER_PWR_CHANEND_NUM, XS1_SU_PER_PWR_STATE_AWAKE_NUM, 1, writeval); - - // USB suspend off, voltage adjustable, sleep clock 32KHz - writeval[0] = XS1_SU_PWR_USB_PD_EN_SET(0, 1); - writeval[0] = XS1_SU_PWR_RST_VOUT_LVL_SET(writeval[0], 1); - writeval[0] = XS1_SU_PWR_LD_AWAKE_SET(writeval[0], 1); - write_periph_32(usb_tile, XS1_SU_PER_PWR_CHANEND_NUM, XS1_SU_PER_PWR_MISC_CTRL_NUM, 1, writeval); - - // Turn off on-chip silicon oscillator (20MHz or 32KHz) - writevalc[0] = XS1_SU_ON_SI_OSC_EN_SET(0, 1); - writevalc[0] = XS1_SU_ON_SI_OSC_SLOW_SET(writevalc[0], 1); - write_periph_8(usb_tile, XS1_SU_PER_OSC_CHANEND_NUM, XS1_SU_PER_OSC_ON_SI_CTRL_NUM, 1, writevalc); - } -} -#endif - diff --git a/lib_xua/src/core/support/reboot.xc b/lib_xua/src/core/support/reboot.xc index d4c33d27..e3f4eb2a 100644 --- a/lib_xua/src/core/support/reboot.xc +++ b/lib_xua/src/core/support/reboot.xc @@ -5,18 +5,9 @@ #include #include -#define XS1_SU_PERIPH_USB_ID 0x1 - -//Normally we would enumerate the XUD_SERIES_SUPPORT possibilities using defines in -//xud.h but we have hard coded them to remove dependancy of sc_xud - -#if (XUD_SERIES_SUPPORT == 4) #include "xs2_su_registers.h" #define XS2_SU_PERIPH_USB_ID 0x1 #define PLL_MASK 0x3FFFFFFF -#else -#define PLL_MASK 0xFFFFFFFF -#endif /* Note, this function is prototyped in xs1.h only from 13 tools onwards */ unsigned get_tile_id(tileref); @@ -38,25 +29,17 @@ static void reset_tile(unsigned const tileId) */ void device_reboot(void) { -#if (XUD_SERIES_SUPPORT == 1) - /* Disconnect from bus */ - unsigned data[] = {4}; - write_periph_32(usb_tile, XS1_SU_PERIPH_USB_ID, XS1_SU_PER_UIFM_FUNC_CONTROL_NUM, 1, data); - - /* Ideally we would reset SU1 here but then we loose power to the xcore and therefore the DFU flag */ - /* Disable USB and issue reset to xcore only - not analogue chip */ - write_node_config_reg(usb_tile, XS1_SU_CFG_RST_MISC_NUM,0b10); -#else - unsigned int localTileId = get_local_tile_id(); unsigned int tileId; unsigned int tileArrayLength; unsigned int localTileNum; -#if (XUD_SERIES_SUPPORT == 4) +#if defined(__XS2A__) /* Disconnect from bus */ unsigned data[] = {4}; write_periph_32(usb_tile, XS2_SU_PERIPH_USB_ID, XS1_GLX_PER_UIFM_FUNC_CONTROL_NUM, 1, data); +#elif defined(__XS3A__) + #warning Assuming that tile reset also resets USB in XS3 architectures #endif tileArrayLength = sizeof(tile)/sizeof(tileref); @@ -75,24 +58,14 @@ void device_reboot(void) } } -#if defined(__XS2A__) || defined(__XS3A__) /* Reset all even tiles, starting from the remote ones */ for(int tileNum = tileArrayLength-2; tileNum>=0; tileNum-=2) -#else - /* Reset all tiles, starting from the remote ones */ - for(int tileNum = tileArrayLength-1; tileNum>=0; tileNum--) -#endif { /* Cannot cast tileref to unsigned! */ tileId = get_tile_id(tile[tileNum]); /* Do not reboot local tile (or tiles residing on the same node) yet */ -#if defined(__XS2A__) || defined(__XS3A__) if((localTileNum | 1) != (tileNum | 1)) - -#else - if(localTileNum != tileNum) -#endif { reset_tile(tileId); } @@ -100,7 +73,6 @@ void device_reboot(void) /* Finally reboot the node this tile resides on */ reset_tile(localTileId); -#endif while (1); } diff --git a/lib_xua/src/core/uac_hwresources.h b/lib_xua/src/core/uac_hwresources.h index 0142a2a9..a0b82d58 100644 --- a/lib_xua/src/core/uac_hwresources.h +++ b/lib_xua/src/core/uac_hwresources.h @@ -4,46 +4,14 @@ #ifndef _UAC_HWRESOURCES_H_ #define _UAC_HWRESOURCES_H_ -#if XUA_USB_EN -#include "xud.h" /* XMOS USB Device Layer defines and functions */ -#endif - -#if ((XUD_SERIES_SUPPORT != XUD_U_SERIES) && (XUD_SERIES_SUPPORT != XUD_X200_SERIES)) - -/* XUD_L_SERIES and XUD_G_SERIES */ - -#if (AUDIO_IO_TILE == XUD_TILE) -/* Note: L series ref clocked clocked from USB clock when USB enabled - use another clockblock for MIDI - * if MIDI and XUD on same tile. See XUD documentation. - * - * This is a clash with S/PDIF Tx but simultaneous S/PDIF and MIDI not currently supported on single tile device - * - */ -#define CLKBLK_MIDI XS1_CLKBLK_1; -#else -#define CLKBLK_MIDI XS1_CLKBLK_REF; -#endif - -#define CLKBLK_SPDIF_TX XS1_CLKBLK_1 -#define CLKBLK_SPDIF_RX XS1_CLKBLK_1 -#define CLKBLK_MCLK XS1_CLKBLK_2 /* Note, potentially used twice */ -#define CLKBLK_ADAT_RX XS1_CLKBLK_3 -#define CLKBLK_USB_RST XS1_CLKBLK_4 /* Clock block passed into L/G series XUD */ -#define CLKBLK_FLASHLIB XS1_CLKBLK_5 /* Clock block for use by flash lib */ - -#define CLKBLK_I2S_BIT XS1_CLKBLK_3 - -#else - /* XUD_U_SERIES, XUD_X200_SERIES */ /* Note, U-series XUD uses clock blocks 4 and 5 - see XUD_Ports.xc */ #define CLKBLK_MIDI XS1_CLKBLK_REF; #define CLKBLK_SPDIF_TX XS1_CLKBLK_1 #define CLKBLK_SPDIF_RX XS1_CLKBLK_1 -#define CLKBLK_MCLK XS1_CLKBLK_2 /* Note, potentially used twice */ +#define CLKBLK_MCLK XS1_CLKBLK_4 #define CLKBLK_FLASHLIB XS1_CLKBLK_3 /* Clock block for use by flash lib */ #define CLKBLK_ADAT_RX XS1_CLKBLK_REF /* Use REF for ADAT_RX on U/x200 series */ -#define CLKBLK_I2S_BIT XS1_CLKBLK_3 -#endif +#define CLKBLK_I2S_BIT XS1_CLKBLK_5 #endif /* _UAC_HWRESOURCES_H_ */ diff --git a/lib_xua/src/core/user/hid/user_hid.h b/lib_xua/src/core/user/hid/user_hid.h index 72d47abb..3fcb52ee 100644 --- a/lib_xua/src/core/user/hid/user_hid.h +++ b/lib_xua/src/core/user/hid/user_hid.h @@ -5,49 +5,19 @@ #define __USER_HID_H__ /** - * \brief HID event identifiers + * \brief HID event * - * This enumeration defines a constant value for each HID event. - * It defines one value for each of the four GPI pins supported in the standard voice products. - * It defines a further 28 values for generic events. + * This struct identifies the location within the HID Report for an event and + * The value to report for that location. + * It assumes only single bit flags within the HID Report. */ -typedef enum hidEventId_t { - HID_EVENT_ID_GPI0 = 0, - HID_EVENT_ID_GPI1, - HID_EVENT_ID_GPI2, - HID_EVENT_ID_GPI3, - HID_EVENT_ID_EVT0, - HID_EVENT_ID_EVT1, - HID_EVENT_ID_EVT2, - HID_EVENT_ID_EVT3, - HID_EVENT_ID_EVT4, - HID_EVENT_ID_EVT5, - HID_EVENT_ID_EVT6, - HID_EVENT_ID_EVT7, - HID_EVENT_ID_EVT8, - HID_EVENT_ID_EVT9, - HID_EVENT_ID_EVT10, - HID_EVENT_ID_EVT11, - HID_EVENT_ID_EVT12, - HID_EVENT_ID_EVT13, - HID_EVENT_ID_EVT14, - HID_EVENT_ID_EVT15, - HID_EVENT_ID_EVT16, - HID_EVENT_ID_EVT17, - HID_EVENT_ID_EVT18, - HID_EVENT_ID_EVT19, - HID_EVENT_ID_EVT20, - HID_EVENT_ID_EVT21, - HID_EVENT_ID_EVT22, - HID_EVENT_ID_EVT23, - HID_EVENT_ID_EVT24, - HID_EVENT_ID_EVT25, - HID_EVENT_ID_EVT26, - HID_EVENT_ID_EVT27, - HID_EVENT_ID_INVALID = 0xffffffff, -} hidEventId_t; +typedef struct hidEvent_t { + unsigned bit; + unsigned byte; + unsigned value; +} hidEvent_t; -#define HID_DATA_BYTES 4 +#define HID_MAX_DATA_BYTES 4 #if( 0 < HID_CONTROLS ) @@ -60,7 +30,7 @@ typedef enum hidEventId_t { * * \param{out} hidData The HID data */ -void UserHIDGetData( unsigned char hidData[ HID_DATA_BYTES ]); +void UserHIDGetData( unsigned char hidData[ HID_MAX_DATA_BYTES ]); /** * \brief Initialize HID processing @@ -70,17 +40,15 @@ void UserHIDInit( void ); /** * \brief Record that a HID event has occurred * - * \param{in} hidEventId The identifier of an event which has occurred - * \param{in} hidEventData A list of data associated with the event - * \param{in} hidEventDataSize The length of the event data list + * \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. * - * \note At present, this function only takes a single element of event data, i.e. - * hidEventDataSize must equal 1. - * - * \note At present, this function treats the event data as a Boolean flag. - * Zero means False; all other values mean True. + * \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 */ -void UserHIDRecordEvent( const hidEventId_t hidEventId, const int * hidEventData, const unsigned hidEventDataSize ); +unsigned UserHIDRecordEvent( const hidEvent_t hidEvent[], const unsigned hidEventCnt ); #endif /* ( 0 < HID_CONTROLS ) */ #endif /* __USER_HID_H__ */ diff --git a/lib_xua/src/dfu/dfu.xc b/lib_xua/src/dfu/dfu.xc index 1570c7eb..43064281 100644 --- a/lib_xua/src/dfu/dfu.xc +++ b/lib_xua/src/dfu/dfu.xc @@ -5,19 +5,17 @@ #include #include -#ifndef NO_USB +#if XUA_USB_EN #include "xud_device.h" #include "dfu_types.h" #include "flash_interface.h" #include "dfu_interface.h" -#if (XUD_SERIES_SUPPORT==4) -/* xCORE-200 */ +#if defined(__XS3A__) +#define FLAG_ADDRESS 0xfffcc +#elif defined(__XS2A__) /* Note range 0x7FFC8 - 0x7FFFF guarenteed to be untouched by tools */ #define FLAG_ADDRESS 0x7ffcc -#else -/* Note range 0x1FFC8 - 0x1FFFF guarenteed to be untouched by tools */ -#define FLAG_ADDRESS 0x1ffcc #endif /* Store Flag to fixed address */ @@ -581,6 +579,6 @@ int DFUDeviceRequests(XUD_ep ep0_out, XUD_ep &?ep0_in, USB_SetupPacket_t &sp, ch } return returnVal; } -#endif /* NO_USB */ +#endif /* XUA_USB_EN */ #endif diff --git a/lib_xua/src/dfu/flashlib_user.c b/lib_xua/src/dfu/flashlib_user.c index 2ef7e47a..323afb86 100644 --- a/lib_xua/src/dfu/flashlib_user.c +++ b/lib_xua/src/dfu/flashlib_user.c @@ -90,9 +90,9 @@ int flash_cmd_enable_ports() #ifdef DFU_FLASH_DEVICE #ifdef QUAD_SPI_FLASH - result = fl_connectToDevice(&p_qflash, flash_devices, 1); + result = fl_connectToDevice(&p_qflash, flash_devices, sizeof(flash_devices) / sizeof(fl_QuadDeviceSpec)); #else - result = fl_connectToDevice(&p_flash, flash_devices, 1); + result = fl_connectToDevice(&p_flash, flash_devices, sizeof(flash_devices) / sizeof(fl_DeviceSpec)); #endif #else /* Use default flash list */ diff --git a/lib_xua/src/hid/hid_report_descriptor.c b/lib_xua/src/hid/hid_report_descriptor.c new file mode 100644 index 00000000..a9cb3bab --- /dev/null +++ b/lib_xua/src/hid/hid_report_descriptor.c @@ -0,0 +1,272 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include +#include +#include "xua_hid_report_descriptor.h" +#include "hid_report_descriptor.h" + +#include + +#define HID_REPORT_ITEM_LOCATION_SIZE ( 1 ) +#define HID_REPORT_DESCRIPTOR_ITEM_COUNT ( sizeof hidReportDescriptorItems / sizeof ( USB_HID_Short_Item_t* )) +#define HID_REPORT_DESCRIPTOR_MAX_LENGTH ( HID_REPORT_DESCRIPTOR_ITEM_COUNT * \ + ( sizeof ( USB_HID_Short_Item_t ) - HID_REPORT_ITEM_LOCATION_SIZE )) + +static unsigned char hidReportDescriptor[ HID_REPORT_DESCRIPTOR_MAX_LENGTH ]; +static size_t hidReportDescriptorLength = 0; +static unsigned hidReportDescriptorPrepared = 0; + +/** + * @brief Get the bit position from the location of an Item + * + * Parameters: + * + * @param[in] location The \c location field from a \c USB_HID_Short_Item + * + * @return The bit position of the Item + */ +static unsigned hidGetItemBitLocation( const unsigned char header ); + +/** + * @brief Get the byte position from the location of an Item + * + * Parameters: + * + * @param[in] location The \c location field from a \c USB_HID_Short_Item + * + * @return The byte position of the Item within the HID Report + */ +static unsigned hidGetItemByteLocation( const unsigned char header ); + +/** + * @brief Get the number of data bytes from the header of an Item + * + * Parameters: + * + * @param[in] header The \c header field from a \c USB_HID_Short_Item + * + * @return The amount of data for the Item + */ +static unsigned hidGetItemSize( const unsigned char header ); + +/** + * @brief Get the Tag from the header of an Item + * + * Parameters: + * + * @param[in] header The \c header field from a \c USB_HID_Short_Item + * + * @return The Tag of the Item + */ +static unsigned hidGetItemTag( const unsigned char header ); + +/** + * @brief Get the Type from the header of an Item + * + * Parameters: + * + * @param[in] header The \c header field from a \c USB_HID_Short_Item + * + * @return The Type of the Item + */ +static unsigned hidGetItemType( const unsigned char header ); + +/** + * @brief Get the Usage Page number for a given byte in the HID Report + * + * Parameters: + * + * @param[in] byte The byte location in the HID Report + * + * @return The USB HID Usage Page code or zero if the \a byte parameter is out-of-range + */ +static unsigned hidGetUsagePage( const unsigned byte ); + +/** + * @brief Translate an Item from the \c USB_HID_Short_Item format to raw bytes + * + * Parameters: + * + * @param[in] inPtr A pointer to a \c USB_HID_Short_Item + * @param[in,out] outPtrPtr A pointer to a pointer to the next available space in the raw + * byte buffer. Passed as a pointer to a pointer to allow this + * function to return the updated pointer to the raw byte buffer. + * + * @return The number of bytes placed in the raw byte buffer + */ +static size_t hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char** outPtrPtr ); + + +static unsigned hidGetItemBitLocation( const unsigned char location ) +{ + unsigned bBit = ( location & HID_REPORT_ITEM_LOC_BIT_MASK ) >> HID_REPORT_ITEM_LOC_BIT_SHIFT; + return bBit; +} + +static unsigned hidGetItemByteLocation( const unsigned char location ) +{ + unsigned bByte = ( location & HID_REPORT_ITEM_LOC_BYTE_MASK ) >> HID_REPORT_ITEM_LOC_BYTE_SHIFT; + return bByte; +} + +static unsigned hidGetItemSize( const unsigned char header ) +{ + unsigned bSize = ( header & HID_REPORT_ITEM_HDR_SIZE_MASK ) >> HID_REPORT_ITEM_HDR_SIZE_SHIFT; + return bSize; +} + +static unsigned hidGetItemTag( const unsigned char header ) +{ + unsigned bTag = ( header & HID_REPORT_ITEM_HDR_TAG_MASK ) >> HID_REPORT_ITEM_HDR_TAG_SHIFT; + return bTag; +} + +static unsigned hidGetItemType( const unsigned char header ) +{ + unsigned bType = ( header & HID_REPORT_ITEM_HDR_TYPE_MASK ) >> HID_REPORT_ITEM_HDR_TYPE_SHIFT; + return bType; +} + +unsigned char* hidGetReportDescriptor( void ) +{ + unsigned char* retVal = NULL; + + if( hidReportDescriptorPrepared ) { + retVal = hidReportDescriptor; + } + + return retVal; +} + +size_t hidGetReportDescriptorLength( void ) +{ + size_t retVal = ( hidReportDescriptorPrepared ) ? hidReportDescriptorLength : 0; + return retVal; +} + +#define HID_CONFIGURABLE_ITEM_COUNT ( sizeof hidConfigurableItems / sizeof ( USB_HID_Short_Item_t* )) +unsigned hidGetReportItem( + const unsigned byte, + const unsigned bit, + unsigned char* const page, + unsigned char* const header, + unsigned char data[] +) +{ + unsigned retVal = HID_STATUS_BAD_LOCATION; + for( unsigned itemIdx = 0; itemIdx < HID_CONFIGURABLE_ITEM_COUNT; ++itemIdx ) { + USB_HID_Short_Item_t item = *hidConfigurableItems[ itemIdx ]; + unsigned bBit = hidGetItemBitLocation( item.location ); + unsigned bByte = hidGetItemByteLocation( item.location ); + + if(( bit == bBit ) && ( byte == bByte )) { + *page = hidGetUsagePage( byte ); + *header = item.header; + + for( unsigned dataIdx = 0; dataIdx < HID_REPORT_ITEM_MAX_SIZE; ++data, ++dataIdx ) { + *data = item.data[ dataIdx ]; + } + + retVal = HID_STATUS_GOOD; + break; + } + } + return retVal; +} + +size_t hidGetReportLength( void ) +{ + size_t retVal = ( hidReportDescriptorPrepared ) ? HID_REPORT_LENGTH : 0; + return retVal; +} + +static unsigned hidGetUsagePage( const unsigned byte ) +{ + unsigned retVal = ( byte < HID_REPORT_LENGTH ) ? hidUsagePages[ byte ]->data[ 0 ] : 0; + return retVal; +} + +void hidPrepareReportDescriptor( void ) +{ + if( !hidReportDescriptorPrepared ) { + hidReportDescriptorLength = 0; + unsigned char* ptr = hidReportDescriptor; + for( unsigned idx = 0; idx < HID_REPORT_DESCRIPTOR_ITEM_COUNT; ++idx ) { + hidReportDescriptorLength += hidTranslateItem( hidReportDescriptorItems[ idx ], &ptr ); + } + + hidReportDescriptorPrepared = 1; + } +} + +void hidResetReportDescriptor( void ) +{ + hidReportDescriptorPrepared = 0; +} + +unsigned hidSetReportItem( + const unsigned byte, + const unsigned bit, + const unsigned char page, + const unsigned char header, + const unsigned char data[] +) +{ + unsigned retVal = HID_STATUS_IN_USE; + + if( !hidReportDescriptorPrepared ) { + retVal = HID_STATUS_BAD_LOCATION; + unsigned bSize = hidGetItemSize( header ); + unsigned bTag = hidGetItemTag ( header ); + unsigned bType = hidGetItemType( header ); + + if(( HID_REPORT_ITEM_MAX_SIZE < bSize ) || + ( HID_REPORT_ITEM_USAGE_TAG != bTag ) || + ( HID_REPORT_ITEM_USAGE_TYPE != bType )) { + retVal = HID_STATUS_BAD_HEADER; + } else { + for( unsigned itemIdx = 0; itemIdx < HID_CONFIGURABLE_ITEM_COUNT; ++itemIdx ) { + USB_HID_Short_Item_t item = *hidConfigurableItems[ itemIdx ]; + unsigned bBit = hidGetItemBitLocation( item.location ); + unsigned bByte = hidGetItemByteLocation( item.location ); + + if(( bit == bBit ) && ( byte == bByte )) { + unsigned pg = hidGetUsagePage( byte ); + + if( page == pg ) { + item.header = header; + + for( unsigned dataIdx = 0; dataIdx < bSize; ++dataIdx ) { + item.data[ dataIdx ] = data[ dataIdx ]; + } + + *hidConfigurableItems[ itemIdx ] = item; + retVal = HID_STATUS_GOOD; + } else { + retVal = HID_STATUS_BAD_PAGE; + } + + break; + } + } + } + } + + return retVal; +} + +static size_t hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char** outPtrPtr ) +{ + size_t count = 0; + *(*outPtrPtr)++ = inPtr->header; + ++count; + + unsigned dataLength = hidGetItemSize( inPtr->header ); + for( unsigned idx = 0; idx < dataLength; ++idx ) { + *(*outPtrPtr)++ = inPtr->data[ idx ]; + ++count; + } + + return count; +} diff --git a/lib_xua/src/hid/xua_hid_descriptor.h b/lib_xua/src/hid/xua_hid_descriptor.h new file mode 100644 index 00000000..4dd44007 --- /dev/null +++ b/lib_xua/src/hid/xua_hid_descriptor.h @@ -0,0 +1,28 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) descriptor + * + * This file defines the structure of the HID descriptor. + * Document section numbers refer to the HID Device Class Definition, version 1.11. + */ + +#ifndef _HID_DESCRIPTOR_ +#define _HID_DESCRIPTOR_ + +#define HID_DESCRIPTOR_LENGTH_FIELD_OFFSET ( 7 ) + +/* USB HID Descriptor (section 6.2.1) */ +typedef struct +{ + unsigned char bLength; /* Size of the descriptor (bytes) */ + unsigned char bDescriptorType0; /* Descriptor type, a constant, 0x21 (section 7.1) */ + unsigned char bcdHID[2]; /* HID class specification release */ + unsigned char bCountryCode; /* Country code of localized hardware */ + unsigned char bNumDescriptors; /* Number of class descriptors */ + unsigned char bDescriptorType1; /* Type of 1st class descriptor (section 7.1) */ + unsigned char wDescriptorLength1[2]; /* Length in bytes of the 1st class descriptor */ +} __attribute__((packed)) USB_HID_Descriptor_t; + +#endif // _HID_DESCRIPTOR_ diff --git a/lib_xua/src/hid/xua_hid_descriptor_contents.h b/lib_xua/src/hid/xua_hid_descriptor_contents.h new file mode 100644 index 00000000..766c323e --- /dev/null +++ b/lib_xua/src/hid/xua_hid_descriptor_contents.h @@ -0,0 +1,64 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) Endpoint descriptors + * + * This file lists the contents of the HID Endpoint descriptor returned during enumeration. + */ + +#ifndef _HID_DESCRIPTOR_CONTENTS_ +#define _HID_DESCRIPTOR_CONTENTS_ + +#include "xua_hid_descriptor.h" + +#define HID_DESCRIPTOR_LENGTH_0 ( 0x09 ) /* Size of descriptor in Bytes */ +#define HID_DESCRIPTOR_TYPE_0 ( 0x21 ) /* HID 0x21 */ +#define HID_BCD_VERSION_LO ( 0x10 ) /* HID class specification release */ +#define HID_BCD_VERSION_HI ( 0x01 ) +#define HID_COUNTRY_CODE ( 0x00 ) /* Country code of localized hardware */ +#define HID_NUM_DESCRIPTORS ( 0x01 ) /* Number of class descriptors */ +#define HID_DESCRIPTOR_TYPE_1 ( 0x22 ) /* Type of 1st class descriptor, Report 0x22 */ +#define HID_DESCRIPTOR_LENGTH_1_LO ( 0x00 ) /* Length of 1st class descriptor, set to zero */ +#define HID_DESCRIPTOR_LENGTH_1_HI ( 0x00 ) /* since only pre-processor directives allowed here */ + +#endif // _HID_DESCRIPTOR_CONTENTS_ + +#if (AUDIO_CLASS == 1) + + /* HID descriptor */ + HID_DESCRIPTOR_LENGTH_0, /* 0 bLength */ + HID_DESCRIPTOR_TYPE_0, /* 1 bDescriptorType (HID) */ + HID_BCD_VERSION_LO, /* 2 bcdHID */ + HID_BCD_VERSION_HI, /* 3 bcdHID */ + HID_COUNTRY_CODE, /* 4 bCountryCode */ + HID_NUM_DESCRIPTORS, /* 5 bNumDescriptors */ + HID_DESCRIPTOR_TYPE_1, /* 6 bDescriptorType[0] */ + HID_DESCRIPTOR_LENGTH_1_LO, /* 7 wDescriptorLength[0] */ + HID_DESCRIPTOR_LENGTH_1_HI, /* 8 wDescriptorLength[0] */ + +#elif (AUDIO_CLASS == 2) + + .HID_Descriptor = + { + /* HID descriptor */ + .bLength = sizeof(USB_HID_Descriptor_t), + .bDescriptorType0 = HID_DESCRIPTOR_TYPE_0, + .bcdHID = + { + HID_BCD_VERSION_LO, + HID_BCD_VERSION_HI, + }, + .bCountryCode = HID_COUNTRY_CODE, + .bNumDescriptors = HID_NUM_DESCRIPTORS, + .bDescriptorType1 = HID_DESCRIPTOR_TYPE_1, + .wDescriptorLength1 = + { + HID_DESCRIPTOR_LENGTH_1_LO, + HID_DESCRIPTOR_LENGTH_1_HI, + }, + }, + +#else + #error "Unknown Audio Class" +#endif diff --git a/lib_xua/src/hid/xua_hid_descriptors.h b/lib_xua/src/hid/xua_hid_descriptors.h new file mode 100644 index 00000000..e06ab90b --- /dev/null +++ b/lib_xua/src/hid/xua_hid_descriptors.h @@ -0,0 +1,20 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) descriptors + * + * This file lists the contents of the HID descriptors returned during enumeration. + * The full definition of the enumerated descriptors appears in xua_ep0_descriptors.h. + * That file should #include the contents of this one at an appropriate point in the + * definition of the cfgDesc_Audio1 and cfgDesc_Audio2 arrays. + */ + +#ifndef _HID_DESCRIPTORS_ +#define _HID_DESCRIPTORS_ + +#include "xua_hid_interface_descriptor_contents.h" +#include "xua_hid_descriptor_contents.h" +#include "xua_hid_endpoint_descriptor_contents.h" + +#endif // _HID_DESCRIPTORS_ diff --git a/lib_xua/src/hid/xua_hid_endpoint_descriptor_contents.h b/lib_xua/src/hid/xua_hid_endpoint_descriptor_contents.h new file mode 100644 index 00000000..d6bcc6b3 --- /dev/null +++ b/lib_xua/src/hid/xua_hid_endpoint_descriptor_contents.h @@ -0,0 +1,49 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) Endpoint descriptors + * + * This file lists the contents of the HID Endpoint descriptor returned during enumeration. + */ + +#ifndef _HID_ENDPOINT_DESCRIPTOR_CONTENTS_ +#define _HID_ENDPOINT_DESCRIPTOR_CONTENTS_ + +#include "descriptor_defs.h" + +#define HID_ENDPOINT_DESCRIPTOR_LENGTH ( 0x07 ) /* Size of descriptor in Bytes */ +#define HID_ENDPOINT_DESCRIPTOR_TYPE ( 0x05 ) /* Endpoint 0x05 */ +#define HID_ENDPOINT_ATTRIBUTES ( 0x03 ) /* Interrupt */ +#define HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_LO ( 0x40 ) +#define HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_HI ( 0x00 ) + +#endif // _HID_ENDPOINT_DESCRIPTOR_CONTENTS_ + +#if (AUDIO_CLASS == 1) + + /* HID Endpoint descriptor (IN) */ + HID_ENDPOINT_DESCRIPTOR_LENGTH, /* 0 bLength */ + HID_ENDPOINT_DESCRIPTOR_TYPE, /* 1 bDescriptorType */ + ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ + HID_ENDPOINT_ATTRIBUTES, /* 3 bmAttributes (INTERRUPT) */ + HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_LO, /* 4 wMaxPacketSize */ + HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_HI, /* 5 wMaxPacketSize */ + ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */ + +#elif (AUDIO_CLASS == 2) + + .HID_In_Endpoint = + { + /* Endpoint descriptor (IN) */ + .bLength = sizeof(USB_Descriptor_Endpoint_t), + .bDescriptorType = HID_ENDPOINT_DESCRIPTOR_TYPE, + .bEndpointAddress = ENDPOINT_ADDRESS_IN_HID, + .bmAttributes = HID_ENDPOINT_ATTRIBUTES, + .wMaxPacketSize = HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_LO, + .bInterval = ENDPOINT_INT_INTERVAL_IN_HID, + }, + +#else + #error "Unknown Audio Class" +#endif diff --git a/lib_xua/src/hid/xua_hid_interface_descriptor_contents.h b/lib_xua/src/hid/xua_hid_interface_descriptor_contents.h new file mode 100644 index 00000000..83d69fbd --- /dev/null +++ b/lib_xua/src/hid/xua_hid_interface_descriptor_contents.h @@ -0,0 +1,57 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) Interface descriptor + * + * This file lists the contents of the HID Interface descriptor returned during enumeration. + */ + +#ifndef _HID_INTERFACE_DESCRIPTOR_CONTENTS_ +#define _HID_INTERFACE_DESCRIPTOR_CONTENTS_ + +#include "descriptor_defs.h" + +#define HID_INTERFACE_DESCRIPTOR_LENGTH ( 0x09 ) /* Size of descriptor in Bytes */ +#define HID_INTERFACE_DESCRIPTOR_TYPE ( 0x04 ) /* Interface 0x04 */ +#define HID_INTERFACE_ALTERNATE_SETTING ( 0x00 ) /* Value used alternate interfaces using SetInterface Request */ +#define HID_INTERFACE_NUMBER_OF_ENDPOINTS ( 0x01 ) /* Number of endpoitns for this interface (excluding 0) */ +#define HID_INTERFACE_CLASS ( 0x03 ) +#define HID_INTERFACE_SUBCLASS ( 0x00 ) /* No boot device */ +#define HID_INTERFACE_PROTOCOL ( 0x00 ) +#define HID_INTERFACE_STRING_DESCRIPTOR_INDEX ( 0x00 ) + +#endif // _HID_INTERFACE_DESCRIPTOR_CONTENTS_ + +#if (AUDIO_CLASS == 1) + + /* HID interface descriptor */ + HID_INTERFACE_DESCRIPTOR_LENGTH, /* 0 bLength */ + HID_INTERFACE_DESCRIPTOR_TYPE, /* 1 bDescriptorType */ + INTERFACE_NUMBER_HID, /* 2 bInterfaceNumber : Number of interface */ + HID_INTERFACE_ALTERNATE_SETTING, /* 3 bAlternateSetting */ + HID_INTERFACE_NUMBER_OF_ENDPOINTS, /* 4: bNumEndpoints */ + HID_INTERFACE_CLASS, /* 5: bInterfaceClass */ + HID_INTERFACE_SUBCLASS, /* 6: bInterfaceSubClass */ + HID_INTERFACE_PROTOCOL, /* 7: bInterfaceProtocol*/ + HID_INTERFACE_STRING_DESCRIPTOR_INDEX, /* 8 iInterface */ + +#elif (AUDIO_CLASS == 2) + + .HID_Interface = + { + /* HID interface descriptor */ + .bLength = sizeof(USB_Descriptor_Interface_t), + .bDescriptorType = HID_INTERFACE_DESCRIPTOR_TYPE, + .bInterfaceNumber = INTERFACE_NUMBER_HID, + .bAlternateSetting = HID_INTERFACE_ALTERNATE_SETTING, + .bNumEndpoints = HID_INTERFACE_NUMBER_OF_ENDPOINTS, + .bInterfaceClass = HID_INTERFACE_CLASS, + .bInterfaceSubClass = HID_INTERFACE_SUBCLASS, + .bInterfaceProtocol = HID_INTERFACE_PROTOCOL, + .iInterface = HID_INTERFACE_STRING_DESCRIPTOR_INDEX, + }, + +#else + #error "Unknown Audio Class" +#endif diff --git a/lib_xua/src/hid/xua_hid_report_descriptor.h b/lib_xua/src/hid/xua_hid_report_descriptor.h new file mode 100644 index 00000000..dc8878ae --- /dev/null +++ b/lib_xua/src/hid/xua_hid_report_descriptor.h @@ -0,0 +1,175 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/** + * @brief Human Interface Device (HID) Report descriptor + * + * This file defines the structure of the HID Report descriptor and declares + * functions for manipulating it. + * Because the Report descriptor defines the length of the HID Report, this file + * declares a function for obtaining the Report length as well. + * The using application has the responsibility to define the report descriptor + * structure and default contents in their hid_report_descriptor.h file. + * Document section numbers refer to the HID Device Class Definition, version 1.11. + */ + +#ifndef _HID_REPORT_DESCRIPTOR_ +#define _HID_REPORT_DESCRIPTOR_ + +#include + +#define HID_REPORT_ITEM_HDR_SIZE_MASK ( 0x03 ) +#define HID_REPORT_ITEM_HDR_SIZE_SHIFT ( 0 ) + +#define HID_REPORT_ITEM_HDR_TAG_MASK ( 0xF0 ) +#define HID_REPORT_ITEM_HDR_TAG_SHIFT ( 4 ) + +#define HID_REPORT_ITEM_HDR_TYPE_MASK ( 0x0C ) +#define HID_REPORT_ITEM_HDR_TYPE_SHIFT ( 2 ) + +#define HID_REPORT_ITEM_LOC_BIT_MASK ( 0x70 ) +#define HID_REPORT_ITEM_LOC_BIT_SHIFT ( 4 ) + +#define HID_REPORT_ITEM_LOC_BYTE_MASK ( 0x0F ) +#define HID_REPORT_ITEM_LOC_BYTE_SHIFT ( 0 ) + +#define HID_REPORT_ITEM_MAX_SIZE ( 2 ) + +#define HID_REPORT_ITEM_USAGE_TAG ( 0 ) +#define HID_REPORT_ITEM_USAGE_TYPE ( 2 ) + +#define HID_STATUS_GOOD ( 0 ) +#define HID_STATUS_BAD_HEADER ( 1 ) +#define HID_STATUS_BAD_LOCATION ( 2 ) +#define HID_STATUS_BAD_PAGE ( 3 ) +#define HID_STATUS_IN_USE ( 4 ) + +/** + * @brief USB HID Report Descriptor. Short Item + * + * @note + * To reduce memory use, this type does not support Short Items with 4 data bytes. + * See section 6.2.2.2 + * + * Elements: + * + * header - the item prefix containing the size, type and tag fields (see 6.2.2.2) + * Format (bit range): bSize (0:1), bType (2:3), bTag (4:7) + * data - a two byte array for holding the item's data + * The bSize field indicates which data bytes are in use + * location - a non-standard extension locating the item within the HID Report + * Format (bit range): iByte (0:3), iBit (4:6), Reserved (7) + */ +typedef struct +{ + unsigned char header; + unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; + unsigned char location; +} USB_HID_Short_Item_t; + +/** + * @brief Get the HID Report descriptor + * + * This function returns a pointer to the USB HID Report descriptor. + * It returns NULL if the Report descriptor has not been prepared, + * i.e., no one has called \c hidPrepareReportDescriptor(). + * + * @note An XC-callable version of this function has not been provided. + * XC requires explicit declaration of the kind of pointer returned, + * hence an XC implementation of the function. + * + * @return A pointer to a list of unsigned char containing the Report descriptor + */ +#if !defined(__XC__) +unsigned char* hidGetReportDescriptor( void ); +#endif + +/** + * @brief Get the length of the HID Report descriptor + * + * This function returns the length of the USB HID Report descriptor. + * It returns zero if the Report descriptor has not been prepared, + * i.e., no one has called \c hidPrepareReportDescriptor(). + * + * @return The length of the Report descriptor in bytes + */ +size_t hidGetReportDescriptorLength( void ); + +/** + * @brief Get a HID Report descriptor item + * + * Parameters: + * + * @param[in] byte The byte position of the control within the HID Report + * @param[in] bit The bit position of the control within the \a byte + * @param[out] page The USB HID Usage Page code for the Item (see 5.5) + * @param[out] header The LSB of the Item containing the bSize, bType and bTag fields (see 6.2.2.2) + * @param[out] data A two element array containing data bytes for the Item + * + * @return A status value + * @retval \c HID_STATUS_GOOD Item successfully returned + * @retval \c HID_STATUS_BAD_LOCATION The \a bit or \a byte arguments specify a location outside + * of the HID Report + */ +#if defined(__XC__) +unsigned hidGetReportItem( const unsigned byte, const unsigned bit, unsigned char* unsafe const page, unsigned char* unsafe const header, unsigned char* unsafe const data); +#else +unsigned hidGetReportItem( const unsigned byte, const unsigned bit, unsigned char* const page, unsigned char* const header, unsigned char data[]); +#endif + +/** + * @brief Get the length of the HID Report + * + * This function returns the length of the USB HID Report. + * It returns zero if the Report descriptor has not been prepared, + * i.e., no one has called \c hidPrepareReportDescriptor(). + * + * @return The length of the Report in bytes + */ +size_t hidGetReportLength( void ); + +/** + * @brief Prepare the USB HID Report descriptor + * + * After preparation, \c hidGetReportDescriptor() returns a list suitable for transmission over USB. + * Call this function after altering one or more Report Items using \c hidSetReportItem(). + */ +void hidPrepareReportDescriptor( void ); + +/** + * @brief Reset the USB HID Report descriptor + * + * After reset, \c hidGetReportDescriptor() returns NULL until a subsequent call to + * \c hidPrepareReportDescriptor() occurs. + * Call this function before altering one or more Report Items using \c hidSetReportItem(). + */ +void hidResetReportDescriptor( void ); + +/** + * @brief Modify a HID Report descriptor item + * + * @warning This function does not check that the length of the \a data array matches the value of + * the bSize field in the \a header. For safe operation use a \a data array of at least + * \c HID_REPORT_ITEM_MAX_SIZE bytes in length. + * + * Parameters: + * + * @param[in] byte The byte position of the control within the HID Report + * @param[in] bit The bit position of the control within the \a byte + * @param[in] page The USB HID Usage Page code for the Item (see 5.5) + * @param[in] header The LSB of the Item containing the bSize, bType and bTag fields (see 6.2.2.2) + * @param[in] data An array containing data bytes or NULL for an Item with no data + * + * @return A status value + * @retval \c HID_STATUS_GOOD Item successfully updated + * @retval \c HID_STATUS_BAD_HEADER The Item header specified a data size greater than 2 or + * a Tag or Type inconsistent with a Usage Item + * @retval \c HID_STATUS_BAD_LOCATION The \a bit or \a byte arguments specify a location outside + * of the HID Report + * @retval \c HID_STATUS_BAD_PAGE The \a byte argument specifies a location for controls from + * a Usage Page other than the one given by the \a page parameter + * @retval \c HID_STATUS_IN_USE The Report descriptor is in use + */ +unsigned hidSetReportItem( const unsigned byte, const unsigned bit, const unsigned char page, const unsigned char header, const unsigned char data[]); + +#endif // _HID_REPORT_DESCRIPTOR_ diff --git a/python/setup.py b/python/setup.py index 98d3d6a5..d3a7c32c 100644 --- a/python/setup.py +++ b/python/setup.py @@ -14,6 +14,8 @@ setuptools.setup( packages=setuptools.find_packages(), install_requires=[ 'flake8~=3.8', + 'pytest~=6.0', + 'pytest-xdist~=1.34', ], dependency_links=[ ], diff --git a/requirements.txt b/requirements.txt index 99e7dd7b..a9ebc4e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,6 +18,8 @@ # same modules should appear in the setup.py list as given below. flake8==3.8.3 +pytest==6.0.0 +pytest-xdist==1.34.0 # Development dependencies # diff --git a/tests/.gitignore b/tests/.gitignore index f0bcfb69..3bbde6ff 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1 +1,2 @@ +*/runners/* test_results.csv diff --git a/tests/xua_unit_tests/CMakeLists.txt b/tests/xua_unit_tests/CMakeLists.txt new file mode 100644 index 00000000..9e09a11b --- /dev/null +++ b/tests/xua_unit_tests/CMakeLists.txt @@ -0,0 +1,104 @@ +cmake_minimum_required(VERSION 3.13) + +set(XMOS_TOOLS_PATH $ENV{XMOS_TOOL_PATH}/bin) + +#********************** +# Setup XMOS toolchain +#********************** +if(NOT DEFINED ENV{XUA_PATH}) + message(FATAL_ERROR "XUA_PATH environment variable not defined") + # some more commands +endif() +include("$ENV{XUA_PATH}/cmake_utils/xmos_toolchain.cmake") + +#********************** +# Project +#********************** +# Disable in-source build. +#if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") +# message(FATAL_ERROR "In-source build is not allowed! Please specify a build folder.\n\tex:cmake -B build") +#endif() + + +## Define project +project(xua_unit_tests VERSION 0.1.0) + +## Enable languages for project +enable_language(CXX XC C ASM) + +message(STATUS "CAME HERE") +add_custom_target("runners" ALL) +add_custom_command( + TARGET runners + COMMAND python generate_unity_runners.py + COMMENT "generate unity runners" +) + +message(STATUS "CAME HERE 1") +file( GLOB APP_SOURCES src/test*.xc ) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) +foreach( testsourcefile ${APP_SOURCES} ) + get_filename_component(ITEM_NAME ${testsourcefile} NAME_WE) + message(STATUS "item_name " ${ITEM_NAME}) + add_executable(${ITEM_NAME}) + set(APP_COMPILER_FLAGS + "-O2" + "-g" + "-Wall" + "-report" + "-fxscope" + "-target=XCORE-AI-EXPLORER" + "${CMAKE_CURRENT_SOURCE_DIR}/config.xscope" + "-DUNITY_SUPPORT_64" + "-DUNITY_INCLUDE_DOUBLE" + ) + set_source_files_properties( + "runners/${ITEM_NAME}/${ITEM_NAME}_Runner.c" + PROPERTIES GENERATED TRUE + ) + + set(APP_SRCS + ${testsourcefile} + "runners/${ITEM_NAME}/${ITEM_NAME}_Runner.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../../../Unity/src/unity.c" + ) + set(APP_INCLUDES + "src" + "${CMAKE_CURRENT_SOURCE_DIR}/../../../Unity/src" + ) + set(APP_DEPENDENT_MODULES + "lib_xua(>=2.0.0)" + "lib_logging(>=3.0.0)" + "lib_xassert(>=4.0.0)" + "lib_xud(>=2.0.0)" + "lib_spdif(>=4.0.0)" + "lib_mic_array(>=4.0.0)" + ) + + include("$ENV{XUA_PATH}/cmake_utils/xua.cmake") + 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_sources(${ITEM_NAME} + PRIVATE ${APP_SRCS} + PRIVATE ${XUA_SRCS_ALL} + ) + add_dependencies(${ITEM_NAME} runners) + target_link_options(${ITEM_NAME} PRIVATE ${APP_COMPILER_FLAGS}) + ## Set any additional flags only for C++ + set(CMAKE_CXX_FLAGS "-std=c++11") + +endforeach( testsourcefile ${APP_SOURCES} ) + +message(STATUS ${APP_SOURCES}) + +message(STATUS "CAME HERE 2") +## Register the application +#XMOS_REGISTER_APP() diff --git a/tests/xua_unit_tests/README.md b/tests/xua_unit_tests/README.md new file mode 100644 index 00000000..d09cf8cc --- /dev/null +++ b/tests/xua_unit_tests/README.md @@ -0,0 +1,32 @@ +# xua_unit_tests test application + +This example builds the xua_unit_tests application for XCORE AI + +## Prerequisites for building + +[XMOS Toolchain 15.0.3](https://www.xmos.com/software/tools/) or newer. + +Install [CMake](https://cmake.org/download/) version 3.13 or newer. + +## Building for xCORE + +Set environment variable for lib_xua path: + + > export XUA_PATH= + +cd to lib_xua/tests/xua_unit_tests + +Run cmake and build + + > cmake . + > make + +## Run on hardware + +Ensure your XCORE AI EXPLORER board is powered up and connected to the XTAG debugger. +Make sure the input.wav file is copied into the build directory + + > pytest -n 1 + + +You should see the tests collected by pytest pass diff --git a/tests/xua_unit_tests/config.xscope b/tests/xua_unit_tests/config.xscope new file mode 100644 index 00000000..bfdf1f86 --- /dev/null +++ b/tests/xua_unit_tests/config.xscope @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xua_unit_tests/conftest.py b/tests/xua_unit_tests/conftest.py new file mode 100644 index 00000000..e2e1a54a --- /dev/null +++ b/tests/xua_unit_tests/conftest.py @@ -0,0 +1,115 @@ +# Copyright 2021 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. +from __future__ import print_function +from builtins import str +import os.path +import pytest +import subprocess + +target = os.environ.get('TARGET', 'all_possible') +print("target = ", target) + +def pytest_collect_file(parent, path): + if(path.ext == ".xe"): + if(target == 'all_possible'): + return UnityTestSource.from_parent(parent, fspath=path) + if(target == 'XCOREAI' and ('xcoreai' in path.basename)): + return UnityTestSource.from_parent(parent, fspath=path) + if(target == 'XCORE200' and ('xcore200' in path.basename)): + return UnityTestSource.from_parent(parent, fspath=path) + + +class UnityTestSource(pytest.File): + def collect(self): + # Find the binary built from the runner for this test file + # + # Assume the following directory layout: + # unit_tests/ <- Test root directory + # |-- bin/ <- Compiled binaries of the test runners + # |-- conftest.py <- This file + # |-- runners/ <- Auto-generated buildable source of test binaries + # |-- src/ <- Unity test functions + # `-- wscript <- Build system file used to generate/build runners + xe_name = ((os.path.basename(self.name)).split("."))[0] + ".xe" + test_bin_path = os.path.join('bin', xe_name) + + yield UnityTestExecutable.from_parent(self, name=self.name) + + +class UnityTestExecutable(pytest.Item): + def __init__(self, name, parent): + super(UnityTestExecutable, self).__init__(name, parent) + self._nodeid = self.name # Override the naming to suit C better + + def runtest(self): + # Run the binary in the simulator + simulator_fail = False + test_output = None + try: + if('xcore200' in self.name): + print("run axe for executable ", self.name) + test_output = subprocess.check_output(['axe', self.name], text=True) + else: + print("run xrun for executable ", self.name) + test_output = subprocess.check_output(['xrun', '--io', '--id', '0', self.name], text=True, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + # Unity exits non-zero if an assertion fails + simulator_fail = True + test_output = e.output + + # Parse the Unity output + unity_pass = False + test_output = test_output.split('\n') + for line in test_output: + if 'test' in line: + test_report = line.split(':') + # Unity output is as follows: + # :::PASS + # :::FAIL: + test_source = test_report[0] + line_number = test_report[1] + test_case = test_report[2] + result = test_report[3] + failure_reason = None + print(('\n {}()'.format(test_case)), end=' ') + if result == 'PASS': + unity_pass = True + continue + if result == 'FAIL': + failure_reason = test_report[4] + print('') # Insert line break after test_case print + raise UnityTestException(self, {'test_source': test_source, + 'line_number': line_number, + 'test_case': test_case, + 'failure_reason': + failure_reason}) + + if simulator_fail: + raise Exception(self, "Simulation failed.") + if not unity_pass: + raise Exception(self, "Unity test output not found.") + print('') # Insert line break after final test_case which passed + + def repr_failure(self, excinfo): + if isinstance(excinfo.value, UnityTestException): + return '\n'.join([str(self.parent).strip('<>'), + '{}:{}:{}()'.format( + excinfo.value[1]['test_source'], + excinfo.value[1]['line_number'], + excinfo.value[1]['test_case']), + 'Failure reason:', + excinfo.value[1]['failure_reason']]) + else: + return str(excinfo.value) + + def reportinfo(self): + # It's not possible to give sensible line number info for an executable + # so we return it as 0. + # + # The source line number will instead be recovered from the Unity print + # statements. + return self.fspath, 0, self.name + + +class UnityTestException(Exception): + pass diff --git a/tests/xua_unit_tests/generate_unity_runners.py b/tests/xua_unit_tests/generate_unity_runners.py new file mode 100644 index 00000000..f2fe0f04 --- /dev/null +++ b/tests/xua_unit_tests/generate_unity_runners.py @@ -0,0 +1,120 @@ +# Copyright 2021 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. +import glob +import os.path +import subprocess +import sys + +UNITY_TEST_DIR = 'src' +UNITY_TEST_PREFIX = 'test_' +UNITY_RUNNER_DIR = 'runners' +UNITY_RUNNER_SUFFIX = '_Runner' +project_root = os.path.join('..', '..', '..') + +def get_ruby(): + """ + Check ruby is avaliable and return the command to invoke it. + """ + interpreter_name = 'ruby' + try: + dev_null = open(os.devnull, 'w') + # Call the version command to check the interpreter can be run + subprocess.check_call([interpreter_name, '--version'], + stdout=dev_null, + close_fds=True) + except OSError as e: + print("Failed to run Ruby interpreter: {}".format(e), file=sys.stderr) + exit(1) # TODO: Check this is the correct way to kill xwaf on error + + return interpreter_name + +def get_unity_runner_generator(project_root_path): + """ + Check the Unity generate_test_runner script is avaliable, and return the + path to it. + """ + unity_runner_generator = os.path.join( + project_root_path, 'Unity', 'auto', 'generate_test_runner.rb') + if not os.path.exists(unity_runner_generator): + print("Unity repo not found in workspace", file=sys.stderr) + exit(1) # TODO: Check this is the correct way to kill xwaf on error + return unity_runner_generator + + +def get_test_name(test_path): + """ + Return the test name by removing the extension from the filename. + """ + return os.path.splitext(os.path.basename(test_path))[0] + + +def get_file_type(filename): + """ + Return the extension from the filename. + """ + return filename.rsplit('.')[-1:][0] + + +def generate_unity_runner(project_root_path, unity_test_path, unity_runner_dir, + unity_runner_suffix): + """ + Invoke the Unity runner generation script for the given test file, and + return the path to the generated file. The output directory will be created + if it does not already exist. + """ + runner_path = os.path.join(os.path.join(unity_runner_dir, get_test_name(unity_test_path))) + if not os.path.exists(runner_path): + os.makedirs(runner_path) + + unity_runner_path = os.path.join( + runner_path, get_test_name(unity_test_path) + unity_runner_suffix + + '.' + 'c') + + try: + subprocess.check_call([get_ruby(), + get_unity_runner_generator(project_root_path), + unity_test_path, + unity_runner_path]) + except OSError as e: + print("Ruby generator failed for {}\n\t{}".format(unity_test_path, e), + file=sys.stderr) + exit(1) # TODO: Check this is the correct way to kill xwaf on error + + +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+'*')) + + +def find_unity_tests(unity_test_dir, unity_test_prefix): + """ + Return a dictionary of all {test names, test language} pairs with the + unity_test_prefix found in the unity_test_dir. + """ + unity_test_paths = find_unity_test_paths(unity_test_dir, unity_test_prefix) + print('unity_test_paths = ', unity_test_paths) + return {get_test_name(path): get_file_type(path) + for path in unity_test_paths} + +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+'*')) + + +def generate_runners(): + UNITY_TESTS = find_unity_tests(UNITY_TEST_DIR, UNITY_TEST_PREFIX) + print('UNITY_TESTS = ',UNITY_TESTS) + unity_test_paths = find_unity_test_paths(UNITY_TEST_DIR, UNITY_TEST_PREFIX) + print('unity_test_paths = ',unity_test_paths) + for unity_test_path in unity_test_paths: + generate_unity_runner(project_root, unity_test_path, UNITY_RUNNER_DIR, UNITY_RUNNER_SUFFIX) + + +if __name__ == "__main__": + generate_runners() diff --git a/tests/xua_unit_tests/src/hid_report_descriptor.h b/tests/xua_unit_tests/src/hid_report_descriptor.h new file mode 100644 index 00000000..a70075ba --- /dev/null +++ b/tests/xua_unit_tests/src/hid_report_descriptor.h @@ -0,0 +1,102 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef __hid_report_descriptor_h__ +#define __hid_report_descriptor_h__ + +#include "xua_hid_report_descriptor.h" + +#define MAX_VALID_BIT ( 7 ) +#define MAX_VALID_BYTE ( 1 ) + +#define MIN_VALID_BIT ( 0 ) +#define MIN_VALID_BYTE ( 0 ) + +/* + * Define non-configurable items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t hidCollectionApplication = { .header = 0xA1, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidCollectionEnd = { .header = 0xC0, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidCollectionLogical = { .header = 0xA1, .data = { 0x02, 0x00 }, .location = 0x00 }; + +static const USB_HID_Short_Item_t hidInputConstArray = { .header = 0x81, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidInputDataVar = { .header = 0x81, .data = { 0x02, 0x00 }, .location = 0x00 }; + +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { .header = 0x25, .data = { 0x00, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { .header = 0x25, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { .header = 0x15, .data = { 0x00, 0x00 }, .location = 0x00 }; + +static const USB_HID_Short_Item_t hidReportCount1 = { .header = 0x95, .data = { 0x01, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidReportCount6 = { .header = 0x95, .data = { 0x06, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidReportCount7 = { .header = 0x95, .data = { 0x07, 0x00 }, .location = 0x00 }; +static const USB_HID_Short_Item_t hidReportSize1 = { .header = 0x75, .data = { 0x01, 0x00 }, .location = 0x00 }; + +static const USB_HID_Short_Item_t hidUsageConsumerControl = { .header = 0x09, .data = { 0x01, 0x00 }, .location = 0x00 }; + +static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }, .location = 0x00 }; + +/* + * Define configurable items in the HID Report descriptor. + */ +static USB_HID_Short_Item_t hidUsageByte0Bit0 = { .header = 0x09, .data = { 0xE2, 0x00 }, .location = 0x00 }; // Mute + +static USB_HID_Short_Item_t hidUsageByte1Bit7 = { .header = 0x09, .data = { 0xEA, 0x00 }, .location = 0x71 }; // Vol- +static USB_HID_Short_Item_t hidUsageByte1Bit0 = { .header = 0x09, .data = { 0xE9, 0x00 }, .location = 0x01 }; // Vol+ + +/* + * List the configurable items in the HID Report descriptor. + */ +static USB_HID_Short_Item_t* const hidConfigurableItems[] = { + &hidUsageByte0Bit0, + &hidUsageByte1Bit0, + &hidUsageByte1Bit7 +}; + +/* + * List Usage pages in the HID Report descriptor, one per byte. + */ +static const USB_HID_Short_Item_t* const hidUsagePages[] = { + &hidUsagePageConsumer, + &hidUsagePageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &hidUsagePageConsumer, + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidReportSize1, + &hidLogicalMinimum0, + &hidCollectionLogical, // Byte 0 + &hidLogicalMaximum1, + &hidReportCount1, + &hidUsageByte0Bit0, + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount7, + &hidInputConstArray, + &hidCollectionEnd, + &hidCollectionLogical, // Byte 1 + &hidLogicalMaximum1, + &hidReportCount1, + &hidUsageByte1Bit0, + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount6, + &hidInputConstArray, + &hidLogicalMaximum1, + &hidUsageByte1Bit7, + &hidInputDataVar, + &hidCollectionEnd, + &hidCollectionEnd +}; + +/* + * Define the length of the HID Report. + * This value must match the number of Report bytes defined by hidReportDescriptorItems. + */ +#define HID_REPORT_LENGTH ( 2 ) + +#endif // __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_hid.c b/tests/xua_unit_tests/src/test_hid.c new file mode 100644 index 00000000..079ca654 --- /dev/null +++ b/tests/xua_unit_tests/src/test_hid.c @@ -0,0 +1,477 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include + +#include "xua_unit_tests.h" +#include "xua_hid_report_descriptor.h" +#include "hid_report_descriptor.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 ) + +#define CONSUMER_CONTROL_PAGE ( 0x0C ) +#define LOUDNESS_CONTROL ( 0xE7 ) + +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 ) +{ + hidResetReportDescriptor(); +} + +// Basic report descriptor tests +void test_unprepared_hidGetReportDescriptor( void ) +{ + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NULL( reportDescPtr ); + + unsigned reportLength = hidGetReportLength(); + TEST_ASSERT_EQUAL_UINT( 0, reportLength ); +} + +void test_prepared_hidGetReportDescriptor( void ) +{ + hidPrepareReportDescriptor(); + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NOT_NULL( reportDescPtr ); + + unsigned reportLength = hidGetReportLength(); + TEST_ASSERT_EQUAL_UINT( HID_REPORT_LENGTH, 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 ); +} + +// Basic item tests +void test_max_loc_hidGetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( CONSUMER_CONTROL_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( 0xEA, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); +} + +void test_min_loc_hidGetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + TEST_ASSERT_EQUAL_UINT( CONSUMER_CONTROL_PAGE, page ); + TEST_ASSERT_EQUAL_UINT( 0x09, header ); + TEST_ASSERT_EQUAL_UINT( 0xE2, data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( 0x00, data[ 1 ]); +} + +void test_overflow_bit_hidGetReportItem( void ) +{ + 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 ); + 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 ) +{ + 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 ); + 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 ) +{ + 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 ); + 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 ) +{ + 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 ); + 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 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_nonconfigurable_item_hidSetReportItem( void ) +{ + 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 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +// Bit range tests +void test_max_bit_hidSetReportItem( void ) +{ + 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 char header = construct_usage_header( 0 ); + const unsigned char page = CONSUMER_CONTROL_PAGE; + + unsigned retVal = hidSetReportItem( byte, bit, page, header, NULL ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_min_bit_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_overflow_bit_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +void test_underflow_bit_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +// Byte range tests +void test_max_byte_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_min_byte_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_overflow_byte_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +void test_underflow_byte_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_LOCATION, retVal ); +} + +// Size range tests +void test_max_size_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_min_size_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_unsupported_size_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); +} + +// Header tag and type tests +void test_bad_tag_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); + } +} + +void test_global_type_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); +} + +void test_local_type_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); +} + +void test_main_type_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); +} + +void test_reserved_type_hidSetReportItem( void ) +{ + 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_BAD_HEADER, retVal ); +} + +// Combined function tests +void test_initial_modification_without_subsequent_preparation( void ) +{ + 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 ); + 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 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 ); + 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( void ) +{ + const unsigned bit = MIN_VALID_BIT; + const unsigned byte = 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_CONTROL_PAGE; + + unsigned setRetVal = hidSetReportItem( 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 ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, getRetVal ); + TEST_ASSERT_EQUAL_UINT( get_page, set_page ); + TEST_ASSERT_EQUAL_UINT( get_header, set_header ); + TEST_ASSERT_EQUAL_UINT( get_data[ 0 ], set_data[ 0 ]); + TEST_ASSERT_EQUAL_UINT( get_data[ 1 ], set_data[ 1 ]); +} + +void test_modification_without_subsequent_preparation( void ) +{ + hidPrepareReportDescriptor(); + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NOT_NULL( reportDescPtr ); + + 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; + + hidResetReportDescriptor(); + unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NULL( reportDescPtr ); +} + +void test_modification_with_subsequent_preparation( void ) +{ + hidPrepareReportDescriptor(); + unsigned char* reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NOT_NULL( reportDescPtr ); + + 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; + + hidResetReportDescriptor(); + unsigned retVal = hidSetReportItem( byte, bit, page, header, data ); + TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); + + hidPrepareReportDescriptor(); + reportDescPtr = hidGetReportDescriptor(); + TEST_ASSERT_NOT_NULL( reportDescPtr ); +} diff --git a/tests/xua_unit_tests/src/xua_conf.h b/tests/xua_unit_tests/src/xua_conf.h new file mode 100644 index 00000000..798c5e43 --- /dev/null +++ b/tests/xua_unit_tests/src/xua_conf.h @@ -0,0 +1,37 @@ +// Copyright 2017-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#define NUM_USB_CHAN_OUT 2 +#define NUM_USB_CHAN_IN 2 +#define I2S_CHANS_DAC 2 +#define I2S_CHANS_ADC 2 +#define MCLK_441 (512 * 44100) +#define MCLK_48 (512 * 48000) +#define MIN_FREQ 48000 +#define MAX_FREQ 48000 + +#define EXCLUDE_USB_AUDIO_MAIN +#define XUA_NUM_PDM_MICS 0 + +#define PDM_TILE 2 +#define XUD_TILE 1 +#define AUDIO_IO_TILE 1 + +#define MIXER 0 + +#define SPDIF_TX_INDEX 0 +#define VENDOR_STR "XMOS" +#define VENDOR_ID 0x20B1 +#define PRODUCT_STR_A2 "XMOS USB Audio Class" +#define PRODUCT_STR_A1 "XMOS USB Audio Class" +#define PID_AUDIO_1 1 +#define PID_AUDIO_2 2 +#define AUDIO_CLASS 2 +#define AUDIO_CLASS_FALLBACK 0 +#define BCD_DEVICE 0x1234 +#define XUA_DFU_EN 0 + +/* TODO */ +#define XUA_DFU XUA_DFU_EN + +#define FB_USE_REF_CLOCK 1 diff --git a/tests/xua_unit_tests/src/xua_unit_test_helper.xc b/tests/xua_unit_tests/src/xua_unit_test_helper.xc new file mode 100644 index 00000000..d4c2911c --- /dev/null +++ b/tests/xua_unit_tests/src/xua_unit_test_helper.xc @@ -0,0 +1,28 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#ifdef __XC__ + +#include +#include +#include + +#endif // __XC__ + + +in port p_mclk_in = XS1_PORT_1D; + +/* Clock-block declarations */ +clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_1; /* Bit clock */ +clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_4; /* Master clock */ + +// Supply missing but unused function +void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) +{ + ; // nothing +} + +// Supply missing but unused function +void AudioHwInit() +{ + ; // nothing +} diff --git a/tests/xua_unit_tests/src/xua_unit_tests.h b/tests/xua_unit_tests/src/xua_unit_tests.h new file mode 100644 index 00000000..0b1d82d9 --- /dev/null +++ b/tests/xua_unit_tests/src/xua_unit_tests.h @@ -0,0 +1,9 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#ifndef XUA_UNIT_TESTS_H_ +#define XUA_UNIT_TESTS_H_ + +#include "unity.h" +#include "xua_conf.h" + +#endif /* XUA_UNIT_TESTS_H_ */ diff --git a/tests/xua_unit_tests/wscript b/tests/xua_unit_tests/wscript new file mode 100644 index 00000000..0f162c19 --- /dev/null +++ b/tests/xua_unit_tests/wscript @@ -0,0 +1,250 @@ +from __future__ import print_function +import glob +import os.path +import subprocess +import sys +from waflib import Options +from waflib.Build import BuildContext, CleanContext + +TARGETS = ['xcore200', 'xcoreai'] + +def get_ruby(): + """ + Check ruby is avaliable and return the command to invoke it. + """ + interpreter_name = 'ruby' + try: + dev_null = open(os.devnull, 'w') + # Call the version command to check the interpreter can be run + subprocess.check_call([interpreter_name, '--version'], + stdout=dev_null, + close_fds=True) + except OSError as e: + print("Failed to run Ruby interpreter: {}".format(e), file=sys.stderr) + exit(1) # TODO: Check this is the correct way to kill xwaf on error + + return interpreter_name + + +def get_unity_runner_generator(project_root_path): + """ + Check the Unity generate_test_runner script is avaliable, and return the + path to it. + """ + unity_runner_generator = os.path.join( + project_root_path, 'Unity', 'auto', 'generate_test_runner.rb') + if not os.path.exists(unity_runner_generator): + print("Unity repo not found in workspace", file=sys.stderr) + exit(1) # TODO: Check this is the correct way to kill xwaf on error + return unity_runner_generator + + +def get_test_name(test_path): + """ + Return the test name by removing the extension from the filename. + """ + return os.path.splitext(os.path.basename(test_path))[0] + + +def get_file_type(filename): + """ + Return the extension from the filename. + """ + return filename.rsplit('.')[-1:][0] + + +def generate_unity_runner(project_root_path, unity_test_path, unity_runner_dir, + unity_runner_suffix): + """ + Invoke the Unity runner generation script for the given test file, and + return the path to the generated file. The output directory will be created + if it does not already exist. + """ + runner_path = os.path.join(os.path.join(unity_runner_dir, get_test_name(unity_test_path))) + if not os.path.exists(runner_path): + os.makedirs(runner_path) + + unity_runner_path = os.path.join( + runner_path, get_test_name(unity_test_path) + unity_runner_suffix + + '.' + 'c') + + try: + subprocess.check_call([get_ruby(), + get_unity_runner_generator(project_root_path), + unity_test_path, + unity_runner_path]) + except OSError as e: + print("Ruby generator failed for {}\n\t{}".format(unity_test_path, e), + file=sys.stderr) + exit(1) # TODO: Check this is the correct way to kill xwaf on error + + +def add_unity_runner_build_config(waf_conf, project_root_path, unity_test_path, + unity_runner_build_flags, target): + """ + Add a config to xwaf to build each Unity test runner into an xCORE + executable. + """ + print(f"get_test_name(unity_test_path) = {get_test_name(unity_test_path)}. target = {target}") + waf_conf.setenv(get_test_name(unity_test_path) + '_' + target) + waf_conf.load('xwaf.compiler_xcc') + waf_conf.env.XCC_FLAGS = unity_runner_build_flags + waf_conf.env.PROJECT_ROOT = project_root_path + # TODO: can the xwaf boilerplate help here? + + +def prepare_unity_test_for_build(waf_conf, project_root_path, unity_test_path, + unity_runner_dir, unity_runner_suffix, target): + 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 + add_unity_runner_build_config(waf_conf, project_root_path, unity_test_path, + runner_build_flags, target) + + +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+'*')) + + +def find_unity_tests(unity_test_dir, unity_test_prefix): + """ + Return a dictionary of all {test names, test language} pairs with the + 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) + for path in unity_test_paths} + + +def generate_all_unity_runners(waf_conf, project_root_path, + unity_test_dir, unity_test_prefix, + unity_runner_dir, unity_runner_suffix): + """ + Generate a runner and a build config for each test file in the + unity_test_dir. + """ + # FIXME: pass unity_tests in? + unity_test_paths = find_unity_test_paths(unity_test_dir, unity_test_prefix) + for trgt in TARGETS: + for unity_test_path in unity_test_paths: + prepare_unity_test_for_build(waf_conf, project_root_path, + unity_test_path, + unity_runner_dir, unity_runner_suffix, trgt) + + +# 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 ctx in (BuildContext, CleanContext): + raw_context = ctx.__name__.replace('Context', '').lower() + + class tmp(ctx): + cmd = raw_context + '_' + test_name + '_' + trgt + variant = test_name + '_' + trgt + #cmd = raw_context + '_' + test_name + #variant = test_name + language = test_language + target = trgt + runner = test_name + print(f"cmd {cmd}, variant {variant}, language {language}") + + +UNITY_TEST_DIR = 'src' +UNITY_TEST_PREFIX = 'test_' +UNITY_RUNNER_DIR = 'runners' +UNITY_RUNNER_SUFFIX = '_Runner' +UNITY_TESTS = find_unity_tests(UNITY_TEST_DIR, UNITY_TEST_PREFIX) + +create_waf_contexts(UNITY_TESTS) + +def options(opt): + opt.add_option('--target', action='store', default='xcore200') + opt.load('xwaf.xcommon') + +def configure(conf): + # TODO: move the call to generate_all_unity_runners() to build() + project_root = os.path.join('..', '..', '..') + generate_all_unity_runners(conf, project_root, + UNITY_TEST_DIR, UNITY_TEST_PREFIX, + UNITY_RUNNER_DIR, UNITY_RUNNER_SUFFIX) + conf.load('xwaf.xcommon') + + +def build(bld): + if not bld.variant: + print('Adding test runners to build queue') + trgt = [ + c for c in TARGETS if c == bld.options.target + ] + + if len(trgt) == 0: + bld.fatal('specify a target with --target.\nAvailable targets: {}'.format(', '.join(TARGETS))) + return + + for name in UNITY_TESTS: + Options.commands.insert(0, 'build_' + name + '_' + trgt[0]) + #Options.commands.insert(0, 'build_' + name) + print('Build queue {}'.format(Options.commands)) + else: + print('Building runner {}'.format(bld.runner)) + bld.env.XSCOPE = bld.path.find_resource('config.xscope') + + depends_on = ['lib_xua', + 'lib_xud', + 'lib_spdif', + 'lib_mic_array', + 'lib_logging', + 'lib_xassert', + 'Unity'] + + makefile_opts = {} + makefile_opts['SOURCE_DIRS'] = ['src', os.path.join('runners',bld.runner)] + if(bld.target == 'xcoreai'): + print('TARGET XCOREAI') + makefile_opts['TARGET'] = ['XCORE-AI-EXPLORER'] + else: + print('TARGET XCORE200') + makefile_opts['TARGET'] = ['XCORE-200-EXPLORER'] + + makefile_opts['INCLUDE_DIRS'] = ['src', + '../../lib_xua/api', + '../../lib_xua/src/core/pdm_mics', + '../../lib_xua/src/hid', + '../../../lib_xud/lib_xud/src/user/class'] + + makefile_opts['XCC_FLAGS'] = ['-O2', + '-g', + '-Wall', + '-DUNITY_SUPPORT_64', + '-DUNITY_INCLUDE_DOUBLE', + '-DXUD_CORE_CLOCK=600', + '-DXUD_SERIES_SUPPORT=4'] + + makefile_opts['APP_NAME'] = [bld.variant] + makefile_opts['USED_MODULES'] = depends_on + makefile_opts['XCOMMON_MAKEFILE'] = ['Makefile.common'] + bld.do_xcommon(makefile_opts) + + +def test(bld): + # Call pytest to run Unity tests inside axe or xsim + try: + test_output = subprocess.check_output(['pytest']) + except subprocess.CalledProcessError as e: + # pytest exits non-zero if an assertion fails + test_output = e.output + print(test_output) + + +# TODO: ensure clean deletes the runners dir/ +def dist(ctx): + ctx.load('xwaf.xcommon') + +def distcheck(ctx): + ctx.load('xwaf.xcommon')