From 255ca79718cb6202fe0cee309487d0a9fabb4b56 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 12 Apr 2024 17:29:58 +0100 Subject: [PATCH 01/40] WIP unit test for midi parse --- lib_xua/src/midi/midiinparse.h | 5 +- .../test_midi_parse/hid_report_descriptor.h | 145 ++++++++++++++++++ .../src/test_midi_parse/test_midi_parse.c | 42 +++++ .../src/xua_unit_test_helper.xc | 24 ++- tests/xua_unit_tests/src/xua_unit_tests.h | 6 + 5 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h create mode 100644 tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c diff --git a/lib_xua/src/midi/midiinparse.h b/lib_xua/src/midi/midiinparse.h index 257820fd..bd03f385 100644 --- a/lib_xua/src/midi/midiinparse.h +++ b/lib_xua/src/midi/midiinparse.h @@ -19,8 +19,11 @@ struct midi_in_parse_state { unsigned codeIndexNumber; }; -void dump_midi_in_parse_state(struct midi_in_parse_state &s); + +#ifdef __XC__ void reset_midi_state(struct midi_in_parse_state &mips); +void dump_midi_in_parse_state(struct midi_in_parse_state &s); {unsigned int , unsigned int} midi_in_parse(struct midi_in_parse_state &mips, unsigned cable_number, unsigned char b); +#endif #endif diff --git a/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h b/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h new file mode 100644 index 00000000..ced88b83 --- /dev/null +++ b/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h @@ -0,0 +1,145 @@ +// Copyright 2021-2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef __hid_report_descriptor_h__ +#define __hid_report_descriptor_h__ + +#include "xua_hid_report.h" + +/* + * Define non-configurable items in the HID Report descriptor. + * (These are short items as the location field isn't relevant for them) + */ +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionLogical = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x02, 0x00 } }; + +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; + +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; + +static const USB_HID_Short_Item_t hidReportCount1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount7 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x07, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; + +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 } }; + +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Report_Element_t hidReportPageConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) +}; + +/* + * Define configurable items in the HID Report descriptor. + */ +static USB_HID_Report_Element_t hidUsageByte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 0) +}; // Mute + +static USB_HID_Report_Element_t hidUsageByte1Bit7 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 1, 7) +}; // Vol- +static USB_HID_Report_Element_t hidUsageByte1Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 1, 0) +}; // Vol+ + +/* + * List the configurable elements in the HID Report descriptor. + */ +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { + &hidUsageByte0Bit0, + &hidUsageByte1Bit0, + &hidUsageByte1Bit7 +}; + +/* + * List HID Reports, one per Report ID. This should be a usage page item with the relevant + * If not using report IDs - still have one with report ID 0 + */ +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportPageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &(hidReportPageConsumer.item), + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidReportSize1, + &hidLogicalMinimum0, + &hidCollectionLogical, // Byte 0 + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageByte0Bit0.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount7, + &hidInputConstArray, + &hidCollectionEnd, + &hidCollectionLogical, // Byte 1 + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageByte1Bit0.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount6, + &hidInputConstArray, + &hidReportCount1, + &hidLogicalMaximum1, + &(hidUsageByte1Bit7.item), + &hidInputDataVar, + &hidCollectionEnd, + &hidCollectionEnd +}; + +/* + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) + */ +#define HID_REPORT_COUNT ( 1 ) + +#endif // __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c new file mode 100644 index 00000000..5d9f66a1 --- /dev/null +++ b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c @@ -0,0 +1,42 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include + +#include "xua_unit_tests.h" +#include "../../../lib_xua/src/midi/midiinparse.h" + + +#define CABLE_NUM 0 + +#define NOTE_ON 0x90 +#define PITCH 60 +#define VELOCITY 80 + +void something(void){ + + struct midi_in_parse_state m_state; + void * mips = &m_state; + reset_midi_state_wrap(mips); + + unsigned valid = 0; + unsigned packed = 0; + midi_in_parse_wrap(mips, CABLE_NUM, NOTE_ON, &valid, &packed); + printf("Valid: %d data: %u\n", valid, packed); + midi_in_parse_wrap(mips, CABLE_NUM, PITCH, &valid, &packed); + printf("Valid: %d data: %u\n", valid, packed); + midi_in_parse_wrap(mips, CABLE_NUM, VELOCITY, &valid, &packed); + printf("Valid: %d data: %u\n", valid, packed); + + + unsigned midi[3]; + unsigned size = 0; + + midi_out_parse_wrap(packed, midi, &size); + printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi[0], midi[1], midi[2]); +} + +void test_midi_tx(void) { + TEST_ASSERT_EQUAL_UINT(3, 3); + something(); +} diff --git a/tests/xua_unit_tests/src/xua_unit_test_helper.xc b/tests/xua_unit_tests/src/xua_unit_test_helper.xc index a2df0db9..aa151ddf 100644 --- a/tests/xua_unit_tests/src/xua_unit_test_helper.xc +++ b/tests/xua_unit_tests/src/xua_unit_test_helper.xc @@ -5,7 +5,8 @@ #include #include #include - +#include "../../../lib_xua/src/midi/midiinparse.h" +#include "../../../lib_xua/src/midi/midioutparse.h" #endif // __XC__ @@ -26,3 +27,24 @@ void AudioHwInit() { ; // nothing } + +// Wrappers for midi parse because C doesn't support return tuples +void midi_in_parse_wrap(void * unsafe mips, unsigned cable_number, unsigned char b, unsigned * unsafe valid, unsigned *unsafe packed){ + unsafe{ + struct midi_in_parse_state * unsafe ptr = mips; + {*valid, *packed} = midi_in_parse(*ptr, cable_number, b); + } +} + +void midi_out_parse_wrap(unsigned tx_data, unsigned midi[3], unsigned * unsafe size){ + unsafe{ + {midi[0], midi[1], midi[2], *size} = midi_out_parse(tx_data); + } +} + +void reset_midi_state_wrap(void * unsafe mips){ + unsafe{ + struct midi_in_parse_state * unsafe ptr = mips; + reset_midi_state(*ptr); + } +} diff --git a/tests/xua_unit_tests/src/xua_unit_tests.h b/tests/xua_unit_tests/src/xua_unit_tests.h index 0b1d82d9..a8536150 100644 --- a/tests/xua_unit_tests/src/xua_unit_tests.h +++ b/tests/xua_unit_tests/src/xua_unit_tests.h @@ -6,4 +6,10 @@ #include "unity.h" #include "xua_conf.h" +#ifndef __XC__ +void midi_in_parse_wrap(void * mips, unsigned cable_number, unsigned char b, unsigned * valid, unsigned * packed); +void midi_out_parse_wrap(unsigned tx_data, unsigned midi[3], unsigned * size); +void reset_midi_state_wrap(void *mips); +#endif + #endif /* XUA_UNIT_TESTS_H_ */ From 2fbeb471915cae6c6f419c779aeb8b29b1ef41e8 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Apr 2024 10:38:19 +0100 Subject: [PATCH 02/40] Midi parse test passing --- lib_xua/src/midi/midiinparse.h | 2 +- .../test_midi_parse/hid_report_descriptor.h | 2 +- .../src/test_midi_parse/test_midi_parse.c | 179 ++++++++++++++++-- .../src/xua_unit_test_helper.xc | 7 +- tests/xua_unit_tests/src/xua_unit_tests.h | 3 +- 5 files changed, 170 insertions(+), 23 deletions(-) diff --git a/lib_xua/src/midi/midiinparse.h b/lib_xua/src/midi/midiinparse.h index bd03f385..4b55f872 100644 --- a/lib_xua/src/midi/midiinparse.h +++ b/lib_xua/src/midi/midiinparse.h @@ -1,4 +1,4 @@ -// Copyright 2011-2021 XMOS LIMITED. +// Copyright 2011-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef MIDIINPARSE_XH #define MIDIINPARSE_XH diff --git a/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h b/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h index ced88b83..3824814e 100644 --- a/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h +++ b/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h @@ -1,4 +1,4 @@ -// Copyright 2021-2022 XMOS LIMITED. +// Copyright 2021-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c index 5d9f66a1..89989429 100644 --- a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c +++ b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c @@ -6,14 +6,26 @@ #include "xua_unit_tests.h" #include "../../../lib_xua/src/midi/midiinparse.h" +#define NUM_CHANS 16 +#define NOTE_OFF 128 +#define NOTE_ON 144 +#define PRESSURE 160 +#define CONTROL 176 +#define PROGRAM 192 +#define PRESSURE_VAL 208 +#define RANGE 224 +#define MANUFACTURE_ID 240 -#define CABLE_NUM 0 +#define DATA_RANGE 128 +#define DATA_MASK (DATA_RANGE - 1) -#define NOTE_ON 0x90 -#define PITCH 60 -#define VELOCITY 80 +#define NUM_TESTS_PER_TEST 10 -void something(void){ +#define CABLE_NUM 2 +#define RANDOM_SEED 6031769 + +unsigned mini_in_parse_ut(unsigned midi[3]){ + // printf("Composing data: 0x%x 0x%x 0x%x\n", midi[0], midi[1], midi[2]); struct midi_in_parse_state m_state; void * mips = &m_state; @@ -21,22 +33,151 @@ void something(void){ unsigned valid = 0; unsigned packed = 0; - midi_in_parse_wrap(mips, CABLE_NUM, NOTE_ON, &valid, &packed); - printf("Valid: %d data: %u\n", valid, packed); - midi_in_parse_wrap(mips, CABLE_NUM, PITCH, &valid, &packed); - printf("Valid: %d data: %u\n", valid, packed); - midi_in_parse_wrap(mips, CABLE_NUM, VELOCITY, &valid, &packed); - printf("Valid: %d data: %u\n", valid, packed); + midi_in_parse_wrap(mips, CABLE_NUM, midi[0], &valid, &packed); + // printf("Valid: %d data: %u\n", valid, packed); + if(valid){ + return packed; + } + midi_in_parse_wrap(mips, CABLE_NUM, midi[1], &valid, &packed); + // printf("Valid: %d data: %u\n", valid, packed); + if(valid){ + return packed; + } + midi_in_parse_wrap(mips, CABLE_NUM, midi[2], &valid, &packed); + // printf("Valid: %d data: %u\n", valid, packed); + if(valid){ + return packed; + } - unsigned midi[3]; - unsigned size = 0; - - midi_out_parse_wrap(packed, midi, &size); - printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi[0], midi[1], midi[2]); + return 0; } -void test_midi_tx(void) { - TEST_ASSERT_EQUAL_UINT(3, 3); - something(); +unsigned rndm = RANDOM_SEED; + + +void test_note(void) { + for(int cmd = NOTE_OFF; cmd < NOTE_ON + NUM_CHANS; cmd++){ + for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ + unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; + unsigned packed = mini_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; + unsigned size = 0; + midi_out_parse_wrap(packed, midi_dut, &size); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); + //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? + for(int i = 0; i < size; i++){ + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + } + } } + +void test_pressure(void) { + for(int cmd = PRESSURE; cmd < PRESSURE + NUM_CHANS; cmd++){ + for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ + unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; + unsigned packed = mini_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; + unsigned size = 0; + midi_out_parse_wrap(packed, midi_dut, &size); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); + //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? + for(int i = 0; i < size; i++){ + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + } + } +} + +void test_control(void) { + for(int cmd = CONTROL; cmd < CONTROL + NUM_CHANS; cmd++){ + for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ + unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; + unsigned packed = mini_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; + unsigned size = 0; + midi_out_parse_wrap(packed, midi_dut, &size); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); + //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? + for(int i = 0; i < size; i++){ + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + } + } +} + +void test_program(void) { + for(int cmd = PROGRAM; cmd < PROGRAM + NUM_CHANS; cmd++){ + for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ + unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; + unsigned packed = mini_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; + unsigned size = 0; + midi_out_parse_wrap(packed, midi_dut, &size); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); + //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? + for(int i = 0; i < size; i++){ + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + } + } +} + +void test_pressure_val(void) { + for(int cmd = PRESSURE_VAL; cmd < PRESSURE_VAL + NUM_CHANS; cmd++){ + for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ + unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; + unsigned packed = mini_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; + unsigned size = 0; + midi_out_parse_wrap(packed, midi_dut, &size); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); + //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? + for(int i = 0; i < size; i++){ + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + } + } +} + +void test_range(void) { + for(int cmd = RANGE; cmd < RANGE + NUM_CHANS; cmd++){ + for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ + unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; + unsigned packed = mini_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; + unsigned size = 0; + midi_out_parse_wrap(packed, midi_dut, &size); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); + //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? + for(int i = 0; i < size; i++){ + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + } + } +} + +void test_manufacturer_id(void) { + for(int cmd = MANUFACTURE_ID; cmd < MANUFACTURE_ID + NUM_CHANS; cmd++){ + for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ + unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; + unsigned packed = mini_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; + unsigned size = 0; + midi_out_parse_wrap(packed, midi_dut, &size); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); + // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); + //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? + for(int i = 0; i < size; i++){ + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + } + } +} \ No newline at end of file diff --git a/tests/xua_unit_tests/src/xua_unit_test_helper.xc b/tests/xua_unit_tests/src/xua_unit_test_helper.xc index aa151ddf..48f82d3f 100644 --- a/tests/xua_unit_tests/src/xua_unit_test_helper.xc +++ b/tests/xua_unit_tests/src/xua_unit_test_helper.xc @@ -1,4 +1,4 @@ -// Copyright 2021 XMOS LIMITED. +// Copyright 2021-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifdef __XC__ @@ -28,6 +28,11 @@ void AudioHwInit() ; // nothing } +unsigned random(unsigned &x){ + crc32(x, -1, 0xEB31D82E); + return x; +} + // Wrappers for midi parse because C doesn't support return tuples void midi_in_parse_wrap(void * unsafe mips, unsigned cable_number, unsigned char b, unsigned * unsafe valid, unsigned *unsafe packed){ unsafe{ diff --git a/tests/xua_unit_tests/src/xua_unit_tests.h b/tests/xua_unit_tests/src/xua_unit_tests.h index a8536150..7763b97a 100644 --- a/tests/xua_unit_tests/src/xua_unit_tests.h +++ b/tests/xua_unit_tests/src/xua_unit_tests.h @@ -1,4 +1,4 @@ -// Copyright 2021 XMOS LIMITED. +// Copyright 2021-2024 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_ @@ -10,6 +10,7 @@ void midi_in_parse_wrap(void * mips, unsigned cable_number, unsigned char b, unsigned * valid, unsigned * packed); void midi_out_parse_wrap(unsigned tx_data, unsigned midi[3], unsigned * size); void reset_midi_state_wrap(void *mips); +unsigned random(unsigned *x); #endif #endif /* XUA_UNIT_TESTS_H_ */ From 17206d4b8fc5102910b5284021ae8cec79d4ac38 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Apr 2024 11:49:50 +0100 Subject: [PATCH 03/40] Initial test FW app for MIDI --- tests/test_midi/src/app_midi_simple.xc | 113 +++++++++++++++++++++++++ tests/test_midi/src/hwsupport.xc | 43 ++++++++++ tests/test_midi/src/xua_conf.h | 28 ++++++ tests/test_midi/src/xud_conf.h | 8 ++ 4 files changed, 192 insertions(+) create mode 100644 tests/test_midi/src/app_midi_simple.xc create mode 100644 tests/test_midi/src/hwsupport.xc create mode 100644 tests/test_midi/src/xua_conf.h create mode 100644 tests/test_midi/src/xud_conf.h diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc new file mode 100644 index 00000000..70f1ca32 --- /dev/null +++ b/tests/test_midi/src/app_midi_simple.xc @@ -0,0 +1,113 @@ +// Copyright 2017-2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* A very simple *example* of a USB audio application (and as such is un-verified for production) + * + * It uses the main blocks from the lib_xua + * + * - 2 channels out I2S only + * - No DFU + * - I2S only + * + */ + +#include +#include +#include +#include +#include + +#include "xua.h" +#include "xud_device.h" +#include "midiinparse.h" +#include "midioutparse.h" + +on tile[MIDI_TILE] : port p_midi_tx = XS1_PORT_4C; +#if(MIDI_RX_PORT_WIDTH == 4) +on tile[MIDI_TILE] : buffered in port:4 p_midi_rx = XS1_PORT_1F; +#elif(MIDI_RX_PORT_WIDTH == 1) +on tile[MIDI_TILE] : buffered in port:1 p_midi_rx = XS1_PORT_1F; +#endif +#define CLKBLK_MIDI XS1_CLKBLK_2 +on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; + + +/* Port declarations for I2C to config ADC's */ +on tile[0]: port p_scl = XS1_PORT_1L; +on tile[0]: port p_sda = XS1_PORT_1M; + +/* See hwsupport.xc */ +void ctrlPort(); + +#define CABLE_NUM 0 + +#define NOTE_ON 0x90 +#define PITCH 60 +#define VELOCITY 80 + +void test(chanend c_midi){ + printf("Test\n"); + + struct midi_in_parse_state mips; + reset_midi_state(mips); + + unsigned valid = 0; + unsigned tx_data = 0; + {valid, tx_data} = midi_in_parse(mips,CABLE_NUM, NOTE_ON); + printf("Valid: %d data: %u\n", valid, tx_data); + {valid, tx_data} = midi_in_parse(mips, CABLE_NUM, PITCH); + printf("Valid: %d data: %u\n", valid, tx_data); + {valid, tx_data} = midi_in_parse(mips, CABLE_NUM, VELOCITY); + printf("Valid: %d data: %u\n", valid, tx_data); + + + char midi[3]; + unsigned size = 0; + {midi[0], midi[1], midi[2], size} = midi_out_parse(tx_data); + printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi[0], midi[1], midi[2]); + + + int is_ack; + unsigned int datum; + + unsigned count = 0; + while(1){ + select{ + case midi_get_ack_or_data(c_midi, is_ack, datum): + printf("ACK: %d Datum: 0x%x\n", is_ack, datum); + count++; + if(count == 3){ + delay_microseconds(200); // Allow frame to complete + exit(0); + } + break; + + default: + outuint(c_midi, byterev(tx_data)); + printf("SEND TO MIDI\n"); + delay_milliseconds(2); // 30 bits at 31.25 kbps is 0.96ms + break; + } + } + +} + + +int main() +{ + chan c_midi; + + + par + { + on tile[0]: test(c_midi); + on tile[1]: usb_midi(p_midi_rx, p_midi_tx, clk_midi, c_midi, 0); + + + on tile[0]: ctrlPort(); + } + + return 0; +} + + diff --git a/tests/test_midi/src/hwsupport.xc b/tests/test_midi/src/hwsupport.xc new file mode 100644 index 00000000..2b722c75 --- /dev/null +++ b/tests/test_midi/src/hwsupport.xc @@ -0,0 +1,43 @@ +// Copyright 2017-2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include +#include "xua.h" + + +on tile[0]: out port p_ctrl = XS1_PORT_8D; + +/* p_ctrl: + * [0:3] - Unused + * [4] - EN_3v3_N + * [5] - EN_3v3A + * [6] - EXT_PLL_SEL (CS2100:0, SI: 1) + * [7] - MCLK_DIR (Out:0, In: 1) + */ +#define EXT_PLL_SEL__MCLK_DIR (0x80) + +/* Note, this runs on Tile[0] */ +void ctrlPort() +{ + // Drive control port to turn on 3V3 and set MCLK_DIR + // Note, "soft-start" to reduce current spike + // Note, 3v3_EN is inverted + for (int i = 0; i < 30; i++) + { + p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x30; /* 3v3: off, 3v3A: on */ + delay_microseconds(5); + p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x20; /* 3v3: on, 3v3A: on */ + delay_microseconds(5); + } +} + +/* Configures the external audio hardware at startup. Note this runs on Tile[1] */ +void AudioHwInit() +{ +} + +/* Configures the external audio hardware for the required sample frequency */ +void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) +{ +} + diff --git a/tests/test_midi/src/xua_conf.h b/tests/test_midi/src/xua_conf.h new file mode 100644 index 00000000..d9b68145 --- /dev/null +++ b/tests/test_midi/src/xua_conf.h @@ -0,0 +1,28 @@ +// Copyright 2017-2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef _XUA_CONF_H_ +#define _XUA_CONF_H_ + +#define NUM_USB_CHAN_OUT 2 /* Number of channels from host to device */ +#define NUM_USB_CHAN_IN 0 /* Number of channels from device to host */ +#define I2S_CHANS_DAC 2 /* Number of I2S channels out of xCORE */ +#define I2S_CHANS_ADC 0 /* Number of I2S channels in to xCORE */ +#define MCLK_441 (512 * 44100) /* 44.1kHz family master clock frequency */ +#define MCLK_48 (512 * 48000) /* 48kHz family master clock frequency */ +#define MIN_FREQ 48000 /* Minimum sample rate */ +#define MAX_FREQ 48000 /* Maximum sample rate */ + +#define EXCLUDE_USB_AUDIO_MAIN + +#define MIDI 1 +#define MIDI_TILE 1 +#define VENDOR_STR "XMOS" +#define VENDOR_ID 0x20B1 +#define PRODUCT_STR_A2 "XUA Example" +#define PRODUCT_STR_A1 "XUA Example" +#define PID_AUDIO_1 1 +#define PID_AUDIO_2 2 +#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example */ + +#endif diff --git a/tests/test_midi/src/xud_conf.h b/tests/test_midi/src/xud_conf.h new file mode 100644 index 00000000..3fc13baf --- /dev/null +++ b/tests/test_midi/src/xud_conf.h @@ -0,0 +1,8 @@ +// Copyright 2017-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include "xua_conf.h" + +/* TODO */ +#define XUD_UAC_NUM_USB_CHAN_OUT NUM_USB_CHAN_OUT +#define XUD_UAC_NUM_USB_CHAN_IN NUM_USB_CHAN_IN From 4e4ae01a352a318c8bc452beabbf66fff49652ee Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Apr 2024 12:59:55 +0100 Subject: [PATCH 04/40] Add initial test tx + checkers from fwk_io --- tests/test_midi/src/app_midi_simple.xc | 4 +- tests/test_midi_tx.py | 83 +++++++++ tests/uart_rx_checker.py | 177 ++++++++++++++++++ tests/uart_tx_checker.py | 244 +++++++++++++++++++++++++ 4 files changed, 505 insertions(+), 3 deletions(-) create mode 100644 tests/test_midi_tx.py create mode 100644 tests/uart_rx_checker.py create mode 100644 tests/uart_tx_checker.py diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index 70f1ca32..c00d1bbb 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -46,8 +46,6 @@ void ctrlPort(); #define VELOCITY 80 void test(chanend c_midi){ - printf("Test\n"); - struct midi_in_parse_state mips; reset_midi_state(mips); @@ -103,7 +101,7 @@ int main() on tile[0]: test(c_midi); on tile[1]: usb_midi(p_midi_rx, p_midi_tx, clk_midi, c_midi, 0); - + // Setup HW so we can run this on the MC board on tile[0]: ctrlPort(); } diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py new file mode 100644 index 00000000..ad61e509 --- /dev/null +++ b/tests/test_midi_tx.py @@ -0,0 +1,83 @@ +# Copyright 2014-2024 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. + +import pytest +import Pyxsim +from Pyxsim import testers +from pathlib import Path +from uart_tx_checker import UARTTxChecker +# from spdif_test_utils import ( +# Clock, +# Spdif_rx, +# Frames, +# freq_for_sample_rate, +# ) + +MAX_CYCLES = 15000000 +MIDI_RATE = 31250 +CONFIGS = ["xs2", "xs3"] +CONFIGS = ["xs3"] + + +class Midi_expect: + def __init(self): + pass + + def expect(self): + expected = "Hello" + return expected + + + +##### +# This test builds the spdif transmitter app with a verity of presets and tests that the output matches those presets +##### +@pytest.mark.parametrize("config", CONFIGS) +def test_tx(capfd, config): + xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") + p_midi_out = "tile[1]:XS1_PORT_4C" + + + # tester = testers.ComparisonTester( + # Frames(channels=audio, no_of_blocks=no_of_blocks, sam_freq=sam_freq).expect()[ + # : no_of_samples * len(audio) + # ] + # ) + tester = testers.ComparisonTester(Midi_expect().expect()) + + tx_port = "tile[1]:XS1_PORT_4C" + rx_port = None + baud = MIDI_RATE + bpb = 8 + parity = 0 + stop = 1 + length_of_test = 3 # characters + + simthreads = [ + # UARTTxChecker(rx_port, tx_port, parity, baud, length_of_test, stop, bpb) + ] + + simargs = ["--max-cycles", str(MAX_CYCLES)] + simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) #This is just for local debug so we can capture the run, pass as kwarg to run_with_pyxsim + + # result = Pyxsim.run_on_simulator( + result = Pyxsim.run_on_simulator( + xe, + simthreads=simthreads, + instTracing=True, + # clean_before_build=True, + clean_before_build=False, + tester=tester, + # capfd=capfd, + capfd=None, + timeout=1500, + simargs=simargs, + build_options=[ + "-j", + f"CONFIG={config}", + "EXTRA_BUILD_FLAGS=" + + f" -DMIDI_RATE_HZ={MIDI_RATE}" + , + ], + ) + assert result \ No newline at end of file diff --git a/tests/uart_rx_checker.py b/tests/uart_rx_checker.py new file mode 100644 index 00000000..7ff1d5d1 --- /dev/null +++ b/tests/uart_rx_checker.py @@ -0,0 +1,177 @@ +# Copyright 2022 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. +import Pyxsim as px +from typing import Sequence +from functools import partial + +# We need to disable output buffering for this test to work on MacOS; this has +# no effect on Linux systems. Let's redefine print once to avoid putting the +# same argument everywhere. +print = partial(print, flush=True) + +Parity = dict( + UART_PARITY_EVEN=0, + UART_PARITY_ODD=1, + UART_PARITY_NONE=2, + UART_PARITY_BAD=3 +) + + +class DriveHigh(px.SimThread): + def __init__(self, p): + self._p = p + + def run(self): + xsi = self.xsi + + xsi.drive_port_pins(self._p, 1); + + +class UARTRxChecker(px.SimThread): + def __init__(self, rx_port, tx_port, parity, baud, stop_bits, bpb, data=[0x7f, 0x00, 0x2f, 0xff], + intermittent=False): + """ + Create a UARTRxChecker instance. + + :param rx_port: Receive port of the UART device under test. + :param tx_port: Transmit port of the UART device under test. + :param parity: Parity of the UART connection. + :param baud: BAUD rate of the UART connection. + :param stop_bits: Number of stop_bits for each UART byte. + :param bpb: Number of data bits per "byte" of UART data. + :param data: A list of bytes to send (default: [0x7f, 0x00, 0x2f, 0xff]) + :param intermittent: Add a random delay between sent bytes. + """ + self._rx_port = rx_port + self._tx_port = tx_port + self._parity = parity + self._baud = baud + self._stop_bits = stop_bits + self._bits_per_byte = bpb + self._data = data + self._intermittent = intermittent + # Hex value of stop bits, as MSB 1st char, e.g. 0b11 : 0xC0 + + def send_byte(self, xsi, byte): + """ + Send a byte to the rx_port + + :param xsi: XMOS Simulator Instance. + :param byte: Byte to send + """ + # Send start bit + self.send_start(xsi) + + # Send data + self.send_data(xsi, byte) + + # Send parity + self.send_parity(xsi, byte) + + # Send stop bit(s) + self.send_stop(xsi) + + + def send_start(self, xsi): + """ + Send a start bit. + + :param xsi: XMOS Simulator Instance. + """ + xsi.drive_port_pins(self._rx_port, 0) + self.wait_baud_time(xsi) + + def send_data(self, xsi, byte): + """ + Write the data bits to the rx_port + + :param xsi: XMOS Simulator Instance. + :param byte: Data to send. + """ + # print "0x%02x:" % byte + for x in range(self._bits_per_byte): + # print " Sending bit %d of 0x%02x (%d)" % (x, byte, (byte >> x) & 0x01) + xsi.drive_port_pins(self._rx_port, (byte & (0x01 << x)) >= 1) + # print " (x): %d" % ((byte & (0x01 << x))>=1) + self.wait_baud_time(xsi) + + def send_parity(self, xsi, byte): + """ + Send the parity bit to the rx_port + + :param xsi: XMOS Simulator Instance. + :param byte: Data to send parity of. + """ + parity = (self._parity - 1) % 3 #parity enum in lib_uart (old XC) different from SDK + if parity < 2: + crc_sum = 0 + for x in range(self._bits_per_byte): + crc_sum += ((byte & (0x01 << x)) >= 1) + crc_sum += parity + # print "Parity for 0x%02x: %d" % (byte, crc_sum%2) + xsi.drive_port_pins(self._rx_port, crc_sum % 2) + self.wait_baud_time(xsi) + elif parity == Parity['UART_PARITY_BAD']: + # print "Sending bad parity bit" + self.send_bad_parity(xsi) + + def send_stop(self, xsi): + """ + Send the stop bit(s) to the rx_port + + :param xsi: XMOS Simulator Instance. + """ + for x in range(self._stop_bits): + xsi.drive_port_pins(self._rx_port, 1) + self.wait_baud_time(xsi) + + def send_bad_parity(self, xsi): + """ + Send a parity bit of 1 to simulate an incorrect parity state. + + :param xsi: XMOS Simulator Instance. + """ + # Always send a parity bit of 1 + xsi.drive_port_pins(self._rx_port, 0) + self.wait_baud_time(xsi) + + def get_bit_time(self): + """ + Returns the expected time between bits for the currently set BAUD rate. + + Returns float value in nanoseconds. + """ + # Return float value in ps + return (1.0 / self._baud) * 1e12 + + def wait_baud_time(self, xsi): + """ + Wait for 1 bit time, as determined by the baud rate. + """ + self.wait_until(xsi.get_time() + self.get_bit_time()) + + def wait_half_baud_time(self, xsi): + """ + Wait for half a bit time, as determined by the baud rate. + """ + self.wait_until(xsi.get_time() + (self.get_bit_time() / 2)) + + def run(self): + xsi = self.xsi + # Drive the uart line high. + xsi.drive_port_pins(self._rx_port, 1) + + # Wait for the device to bring up it's tx port, indicating it is ready + self.wait((lambda _x: self.xsi.is_port_driving(self._tx_port))) + + # If we're doing an intermittent send, add a delay between each byte + # sent. Delay is in ns. 20,000ns = 20ms, 100,000ns = 100ms. Delays could + # be more variable, but it hurts test time substantially. + if self._intermittent: + for x in self._data: + k = randint(20000, 100000) + self.wait_until(xsi.get_time() + k) + self.send_byte(xsi, x) + else: + for x in self._data: + self.send_byte(xsi, x) diff --git a/tests/uart_tx_checker.py b/tests/uart_tx_checker.py new file mode 100644 index 00000000..cdeb7dea --- /dev/null +++ b/tests/uart_tx_checker.py @@ -0,0 +1,244 @@ +# Copyright 2022 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. +import Pyxsim as px +from typing import Sequence +from functools import partial + +# We need to disable output buffering for this test to work on MacOS; this has +# no effect on Linux systems. Let's redefine print once to avoid putting the +# same argument everywhere. +print = partial(print, flush=True) + + +class UARTTxChecker(px.SimThread): + """ + This simulator thread will act as a UART device, and will check sent and + transations caused by the device, by looking at the tx pins. + """ + + def __init__(self, rx_port, tx_port, parity, baud, length, stop_bits, bpb): + """ + Create a UARTTxChecker instance. + + :param tx_port: Transmit port of the UART device under test. + :param parity: Parity of the UART connection. + :param baud: BAUD rate of the UART connection. + :param length: Length of transmission to check. + :param stop_bits: Number of stop_bits for each UART byte. + :param bpb: Number of data bits per "byte" of UART data. + """ + self._tx_port = tx_port + self._parity = parity + self._baud = baud + self._length = length + self._stop_bits = stop_bits + self._bits_per_byte = bpb + # Hex value of stop bits, as MSB 1st char, e.g. 0b11 : 0xC0 + + def get_port_val(self, xsi, port): + """ + Sample the state of a port + + :rtype: int + :param xsi: XMOS Simulator Instance. + :param port: Port to sample. + """ + is_driving = xsi.is_port_driving(port) + if not is_driving: + return 1 + else: + return xsi.sample_port_pins(port) + + def get_bit_time(self): + """ + Returns the expected time between bits for the currently set BAUD rate. + + Returns float value in nanoseconds. + :rtype: float + """ + # Return float value in ps + return (1.0/self._baud) * 1e12 + + def wait_baud_time(self, xsi): + """ + Wait for 1 bit time, as determined by the baud rate. + """ + self.wait_until(xsi.get_time() + self.get_bit_time()) + return True + + def wait_half_baud_time(self, xsi): + """ + Wait for half a bit time, as determined by the baud rate. + """ + self.wait_until(xsi.get_time() + (self.get_bit_time() / 2)) + + def read_packet(self, xsi, parity, length=4): + """ + Read a given number of bytes of UART traffic sent by the device. + + Returns a list of bytes sent by the device. + + :rtype: list + :param xsi: XMOS Simulator Instance. + :param parity: The UART partiy setting. See Parity. + :param length: The number of bytes to read. Defaults to 4. + """ + packet = [] + start_time = 0 + got_start_bit = False + + initial_port_val = self.get_port_val(xsi, self._tx_port) + print("tx starts high: %s" % ("True" if initial_port_val else "False")) + + for x in range(length): + packet.append(chr(self.read_byte(xsi, parity))) + return packet + + def read_byte(self, xsi, parity): + """ + Read 1 byte of UART traffic sent by the device + + Returns an int, representing a byte read from the uart. Should be in the range 0 <= x < 2^bits_per_byte + + :rtype: int + :param xsi: XMOS Simulator Instance. + :param parity: The UART partiy setting. See Parity. + """ + byte = 0 + val = 0 + + # Recv start bit + initial_port_val = self.get_port_val(xsi, self._tx_port) + + if initial_port_val == 1: + self.wait_for_port_pins_change([self._tx_port]) + #else go for it as assume tx has just fallen with no interframe gap + # print("Byte start time: ", xsi.get_time()) + + # The tx line should go low for 1 bit time + if self.get_val_timeout(xsi, self._tx_port) == 0: + print("Start bit recv'd") + else: + print("Start bit issue") + return False + + # recv the byte + crc_sum = 0 + for j in range(self._bits_per_byte): + val = self.get_val_timeout(xsi, self._tx_port) + byte += (val << j) + crc_sum += val + + print(f"Sampled {self._bits_per_byte} data bits") + + # Check the parity if needs be + self.check_parity(xsi, crc_sum, parity) + + # Get the stop bit + self.check_stopbit(xsi) + + # Print a new line to split bytes in output + print() + + return byte + + def check_parity(self, xsi, crc_sum, parity): + """ + Read the parity bit and check it against a crc sum. Print correctness. + + :param xsi: XMOS Simulator Instance. + :param crc_sum: The checksum to test parity against. + :param parity: The UART partiy setting. See Parity. + """ + if parity > 0: + parity_val = 0 if parity == 1 else 1 + read = self.get_val_timeout(xsi, self._tx_port) + if read == (crc_sum + parity_val) % 2: + print("Parity bit correct") + else: + print("Parity bit incorrect. Got %d, expected %d" % (read, (crc_sum + parity_val) % 2)) + else: + print("Parity bit correct") + + def check_stopbit(self, xsi): + """ + Read the stop bit(s) of a UART transmission and print correctness. + + :param xsi: XMOS Simulator Instance. + """ + stop_bits_correct = True + for i in range(self._stop_bits): + # The stop bits should stay high for this time + if self.get_val_timeout(xsi, self._tx_port) == 0: + stop_bits_correct = False + print("Stop bit correct: %s" % ("True" if stop_bits_correct else "False")) + + def get_val_timeout(self, xsi, port): + """ + Get a value from a given port of the device, with a timeout determined + by the BAUD rate. + + Returns whether the pin is high (True) or low (False) + + :rtype: bool + :param xsi: XMOS Simulator Instance. + :param port: The port to sample. + """ + # This intentionally has a 0.3% slop. It is per-byte and gives some + # wiggle-room if the clock doesn't divide into ns nicely. + timeout = self.get_bit_time() * 0.5 + short_timeout = self.get_bit_time() * 0.2485 + + # Allow for "rise" time + self.wait_until(xsi.get_time() + short_timeout) + + # Get val + K = self.wait_time_or_pin_change(xsi, timeout, port) + + # Allow for "fall" time + self.wait_until(xsi.get_time() + short_timeout) + return K + + def wait_time_or_pin_change(self, xsi, timeout, port): + """ + Waits for a given timeout, or until a port changes state. Which ever + occurs 1st. Prints an error if the former causes the function to break. + + Returns whether the pin is high (True) or low (False) + + :rtype: bool + :param xsi: XMOS Simulator Instance. + :param timeout: Time to wait. + :param port: Port to sample. + """ + start_time = xsi.get_time() + start_val = self.get_port_val(xsi, port) + transitioned_during_wait = False + + def _continue(_timeout, _start_time, _start_val): + if xsi.get_time() >= _start_time + _timeout: + return True + if self.get_port_val(xsi, port) != _start_val: + transitioned_during_wait = True + return True + return False + wait_fun = (lambda x: _continue(timeout, start_time, start_val)) + self.wait(wait_fun) + + # Start value should *not* have changed during timeout + if transitioned_during_wait: + print("FAIL :: Unexpected Transition.") + + return start_val + + def run(self): + # Wait for the xcore to bring the uart tx port up + self.wait((lambda x: self.xsi.is_port_driving(self._tx_port))) + self.wait((lambda x: self.get_port_val(self.xsi, self._tx_port) == 1)) + + K = self.read_packet(self.xsi, self._parity, self._length) + + # Print each member of K as a hex byte + # inline lambda function mapped over a list? awh yiss. + print(", ".join(map((lambda x: "0x%02x" % ord(x)), K))) + From 977408d3bf2020db058389e7224eaed668d4bdf9 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Apr 2024 17:32:03 +0100 Subject: [PATCH 05/40] Initial passing tx test using pyxsim --- .gitignore | 1 + tests/test_midi/src/app_midi_simple.xc | 95 +++++++++++++++++--------- tests/test_midi_tx.py | 42 ++++++++---- tests/uart_tx_checker.py | 22 +++--- 4 files changed, 104 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index 663e8294..885ecb54 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ host_usb_mixer_control/xmos_mixer **/.vscode/** **.egg-info *tests/logs/* +midi_tx_cmds.txt diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index c00d1bbb..53a65315 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "xua.h" @@ -31,59 +32,92 @@ on tile[MIDI_TILE] : buffered in port:1 p_midi_rx = XS1_PORT_1F; #define CLKBLK_MIDI XS1_CLKBLK_2 on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; - -/* Port declarations for I2C to config ADC's */ -on tile[0]: port p_scl = XS1_PORT_1L; -on tile[0]: port p_sda = XS1_PORT_1M; +#define MAX_TEST_COMMANDS 10 +#define TEST_COMMAND_FILE "midi_tx_cmds.txt" /* See hwsupport.xc */ void ctrlPort(); #define CABLE_NUM 0 -#define NOTE_ON 0x90 -#define PITCH 60 -#define VELOCITY 80 -void test(chanend c_midi){ - struct midi_in_parse_state mips; - reset_midi_state(mips); +unsigned mini_in_parse_helper(unsigned midi[3]){ + // printf("Composing data: 0x%x 0x%x 0x%x\n", midi[0], midi[1], midi[2]); + + struct midi_in_parse_state m_state; + reset_midi_state(m_state); unsigned valid = 0; - unsigned tx_data = 0; - {valid, tx_data} = midi_in_parse(mips,CABLE_NUM, NOTE_ON); - printf("Valid: %d data: %u\n", valid, tx_data); - {valid, tx_data} = midi_in_parse(mips, CABLE_NUM, PITCH); - printf("Valid: %d data: %u\n", valid, tx_data); - {valid, tx_data} = midi_in_parse(mips, CABLE_NUM, VELOCITY); - printf("Valid: %d data: %u\n", valid, tx_data); + unsigned packed = 0; + for(int i = 0; i < 3; i++){ + {valid, packed} = midi_in_parse(m_state, CABLE_NUM, midi[i]); + if(valid){ + return packed; + } + } + return 0; +} - char midi[3]; - unsigned size = 0; - {midi[0], midi[1], midi[2], size} = midi_out_parse(tx_data); - printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi[0], midi[1], midi[2]); +unsigned parse_cmd_line(uint8_t commands[MAX_TEST_COMMANDS][3]) +{ + FILE * movable fptr_tx = fopen(TEST_COMMAND_FILE,"rt"); + if (fptr_tx == NULL) { + printf("ERROR: TX command file %s not found or unable to open.\n", TEST_COMMAND_FILE); + fclose(move(fptr_tx)); + return 0; + } + unsigned line = 0; + + unsigned a,b,c; + while (fscanf(fptr_tx, "%u %u %u\n", &a, &b, &c) == 3) { + commands[line][0] = a; + commands[line][1] = b; + commands[line][2] = c; + // printf("Line %u params: 0x%x 0x%x 0x%x\n", line, commands[line][0], commands[line][1], commands[line][2]); + line++; + if(line > MAX_TEST_COMMANDS){ + printf("ERROR: Too many lines in TX command file\n"); + + fclose(move(fptr_tx)); + return MAX_TEST_COMMANDS; + } + } + + fclose(move(fptr_tx)); + return line; +} + +void test(chanend c_midi){ + uint8_t commands[MAX_TEST_COMMANDS][3] = {{0}}; + unsigned num_tx = parse_cmd_line(commands); int is_ack; - unsigned int datum; + unsigned datum; - unsigned count = 0; + unsigned line = 0; while(1){ select{ case midi_get_ack_or_data(c_midi, is_ack, datum): - printf("ACK: %d Datum: 0x%x\n", is_ack, datum); - count++; - if(count == 3){ + // printf("ACK: %d Datum: 0x%x\n", is_ack, datum); + line++; + if(line == num_tx){ delay_microseconds(200); // Allow frame to complete exit(0); } break; default: - outuint(c_midi, byterev(tx_data)); - printf("SEND TO MIDI\n"); - delay_milliseconds(2); // 30 bits at 31.25 kbps is 0.96ms + if(num_tx){ + unsigned midi[] = {commands[line][0], commands[line][1], commands[line][2]}; + unsigned tx_packet = mini_in_parse_helper(midi); + outuint(c_midi, byterev(tx_packet)); + // printf("SEND TO MIDI: 0x%x\n", tx_packet); + delay_milliseconds(2); // 30 bits at 31.25 kbps is 0.96ms + } else { + exit(0); + } break; } } @@ -91,11 +125,10 @@ void test(chanend c_midi){ } -int main() +int main(void) { chan c_midi; - par { on tile[0]: test(c_midi); diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index ad61e509..62db6d6c 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -23,11 +23,23 @@ class Midi_expect: def __init(self): pass - def expect(self): - expected = "Hello" + def expect(self, commands): + expected = "" + for command in commands: + while len(command) < 3: + command.append(0) + expected += "uart_tx_checker: " + " ".join([f"0x{byte:02x}" for byte in command]) + "\n" + return expected +def create_midi_tx_file(commands): + with open("midi_tx_cmds.txt", "wt") as mt: + for command in commands: + while len(command) < 3: + command.append(0) + text = " ".join([str(byte) for byte in command]) + "\n" + mt.write(text) ##### # This test builds the spdif transmitter app with a verity of presets and tests that the output matches those presets @@ -36,17 +48,16 @@ class Midi_expect: def test_tx(capfd, config): xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") p_midi_out = "tile[1]:XS1_PORT_4C" - - # tester = testers.ComparisonTester( - # Frames(channels=audio, no_of_blocks=no_of_blocks, sam_freq=sam_freq).expect()[ - # : no_of_samples * len(audio) - # ] - # ) - tester = testers.ComparisonTester(Midi_expect().expect()) + midi_commands = [[0x90, 60, 81]] + create_midi_tx_file(midi_commands) + + tester = testers.ComparisonTester(Midi_expect().expect(midi_commands), + regexp = "uart_tx_checker:.+", + ordered = True) + tx_port = "tile[1]:XS1_PORT_4C" - rx_port = None baud = MIDI_RATE bpb = 8 parity = 0 @@ -54,11 +65,11 @@ def test_tx(capfd, config): length_of_test = 3 # characters simthreads = [ - # UARTTxChecker(rx_port, tx_port, parity, baud, length_of_test, stop, bpb) + UARTTxChecker(tx_port, parity, baud, length_of_test, stop, bpb, debug=False) ] simargs = ["--max-cycles", str(MAX_CYCLES)] - simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) #This is just for local debug so we can capture the run, pass as kwarg to run_with_pyxsim + # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) #This is just for local debug so we can capture the run, pass as kwarg to run_with_pyxsim # result = Pyxsim.run_on_simulator( result = Pyxsim.run_on_simulator( @@ -68,9 +79,9 @@ def test_tx(capfd, config): # clean_before_build=True, clean_before_build=False, tester=tester, - # capfd=capfd, - capfd=None, - timeout=1500, + capfd=capfd, + # capfd=None, + timeout=120, simargs=simargs, build_options=[ "-j", @@ -80,4 +91,5 @@ def test_tx(capfd, config): , ], ) + assert result \ No newline at end of file diff --git a/tests/uart_tx_checker.py b/tests/uart_tx_checker.py index cdeb7dea..a5de85ab 100644 --- a/tests/uart_tx_checker.py +++ b/tests/uart_tx_checker.py @@ -9,6 +9,8 @@ from functools import partial # same argument everywhere. print = partial(print, flush=True) +# From tools 15.2.1 we need to add an extra factor to go from ps to fs +time_scaling_factor = 1000 class UARTTxChecker(px.SimThread): """ @@ -16,7 +18,7 @@ class UARTTxChecker(px.SimThread): transations caused by the device, by looking at the tx pins. """ - def __init__(self, rx_port, tx_port, parity, baud, length, stop_bits, bpb): + def __init__(self, tx_port, parity, baud, length, stop_bits, bpb, debug=False): """ Create a UARTTxChecker instance. @@ -34,6 +36,7 @@ class UARTTxChecker(px.SimThread): self._stop_bits = stop_bits self._bits_per_byte = bpb # Hex value of stop bits, as MSB 1st char, e.g. 0b11 : 0xC0 + self.debug = debug def get_port_val(self, xsi, port): """ @@ -57,7 +60,7 @@ class UARTTxChecker(px.SimThread): :rtype: float """ # Return float value in ps - return (1.0/self._baud) * 1e12 + return (1.0/self._baud) * 1e12 * time_scaling_factor def wait_baud_time(self, xsi): """ @@ -88,7 +91,7 @@ class UARTTxChecker(px.SimThread): got_start_bit = False initial_port_val = self.get_port_val(xsi, self._tx_port) - print("tx starts high: %s" % ("True" if initial_port_val else "False")) + if self.debug: print("tx starts high: %s" % ("True" if initial_port_val else "False")) for x in range(length): packet.append(chr(self.read_byte(xsi, parity))) @@ -113,11 +116,10 @@ class UARTTxChecker(px.SimThread): if initial_port_val == 1: self.wait_for_port_pins_change([self._tx_port]) #else go for it as assume tx has just fallen with no interframe gap - # print("Byte start time: ", xsi.get_time()) # The tx line should go low for 1 bit time if self.get_val_timeout(xsi, self._tx_port) == 0: - print("Start bit recv'd") + if self.debug: print("Start bit recv'd") else: print("Start bit issue") return False @@ -129,7 +131,7 @@ class UARTTxChecker(px.SimThread): byte += (val << j) crc_sum += val - print(f"Sampled {self._bits_per_byte} data bits") + if self.debug: print(f"Sampled {self._bits_per_byte} data bits: 0x{hex(byte)}") # Check the parity if needs be self.check_parity(xsi, crc_sum, parity) @@ -138,7 +140,7 @@ class UARTTxChecker(px.SimThread): self.check_stopbit(xsi) # Print a new line to split bytes in output - print() + if self.debug: print() return byte @@ -158,7 +160,7 @@ class UARTTxChecker(px.SimThread): else: print("Parity bit incorrect. Got %d, expected %d" % (read, (crc_sum + parity_val) % 2)) else: - print("Parity bit correct") + if self.debug: print("Parity bit correct") def check_stopbit(self, xsi): """ @@ -171,7 +173,7 @@ class UARTTxChecker(px.SimThread): # The stop bits should stay high for this time if self.get_val_timeout(xsi, self._tx_port) == 0: stop_bits_correct = False - print("Stop bit correct: %s" % ("True" if stop_bits_correct else "False")) + if self.debug: print("Stop bit correct: %s" % ("True" if stop_bits_correct else "False")) def get_val_timeout(self, xsi, port): """ @@ -240,5 +242,5 @@ class UARTTxChecker(px.SimThread): # Print each member of K as a hex byte # inline lambda function mapped over a list? awh yiss. - print(", ".join(map((lambda x: "0x%02x" % ord(x)), K))) + print("uart_tx_checker:", " ".join(map((lambda x: "0x%02x" % ord(x)), K))) From 098c39b6594ffe248c4f176d9e11f29e21734f55 Mon Sep 17 00:00:00 2001 From: Ed Date: Mon, 15 Apr 2024 17:38:58 +0100 Subject: [PATCH 06/40] Source check --- tests/test_midi/src/app_midi_simple.xc | 2 +- tests/test_midi/src/xua_conf.h | 2 +- tests/test_midi/src/xud_conf.h | 2 +- tests/uart_rx_checker.py | 2 +- tests/uart_tx_checker.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index 53a65315..e17efe6e 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -1,4 +1,4 @@ -// Copyright 2017-2022 XMOS LIMITED. +// Copyright 2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* A very simple *example* of a USB audio application (and as such is un-verified for production) diff --git a/tests/test_midi/src/xua_conf.h b/tests/test_midi/src/xua_conf.h index d9b68145..b2042156 100644 --- a/tests/test_midi/src/xua_conf.h +++ b/tests/test_midi/src/xua_conf.h @@ -1,4 +1,4 @@ -// Copyright 2017-2022 XMOS LIMITED. +// Copyright 2017-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef _XUA_CONF_H_ diff --git a/tests/test_midi/src/xud_conf.h b/tests/test_midi/src/xud_conf.h index 3fc13baf..374cbe34 100644 --- a/tests/test_midi/src/xud_conf.h +++ b/tests/test_midi/src/xud_conf.h @@ -1,4 +1,4 @@ -// Copyright 2017-2021 XMOS LIMITED. +// Copyright 2017-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include "xua_conf.h" diff --git a/tests/uart_rx_checker.py b/tests/uart_rx_checker.py index 7ff1d5d1..1aa6e6cc 100644 --- a/tests/uart_rx_checker.py +++ b/tests/uart_rx_checker.py @@ -1,4 +1,4 @@ -# Copyright 2022 XMOS LIMITED. +# Copyright 2022-2024 XMOS LIMITED. # This Software is subject to the terms of the XMOS Public Licence: Version 1. import Pyxsim as px from typing import Sequence diff --git a/tests/uart_tx_checker.py b/tests/uart_tx_checker.py index a5de85ab..e0476c76 100644 --- a/tests/uart_tx_checker.py +++ b/tests/uart_tx_checker.py @@ -1,4 +1,4 @@ -# Copyright 2022 XMOS LIMITED. +# Copyright 2022-2024 XMOS LIMITED. # This Software is subject to the terms of the XMOS Public Licence: Version 1. import Pyxsim as px from typing import Sequence From a6969a86107303d0a4bdb1483a3557d531281c86 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 16 Apr 2024 13:37:29 +0100 Subject: [PATCH 07/40] Enhanced app_midi_simple to support file based commands and readiness for Rx testing --- tests/midi_test_helpers.py | 24 +++++ tests/test_midi/src/app_midi_simple.xc | 127 ++++++++++++++++--------- tests/test_midi_tx.py | 10 +- tests/uart_rx_checker.py | 10 +- 4 files changed, 111 insertions(+), 60 deletions(-) create mode 100644 tests/midi_test_helpers.py diff --git a/tests/midi_test_helpers.py b/tests/midi_test_helpers.py new file mode 100644 index 00000000..5bf8b4f5 --- /dev/null +++ b/tests/midi_test_helpers.py @@ -0,0 +1,24 @@ +# Copyright 2024 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. + +class Midi_expect: + def __init(self): + pass + + def expect(self, commands): + expected = "" + for command in commands: + while len(command) < 3: + command.append(0) + expected += "uart_tx_checker: " + " ".join([f"0x{byte:02x}" for byte in command]) + "\n" + + return expected + + +def create_midi_tx_file(commands): + with open("midi_tx_cmds.txt", "wt") as mt: + for command in commands: + while len(command) < 3: + command.append(0) + text = " ".join([str(byte) for byte in command]) + "\n" + mt.write(text) diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index e17efe6e..71f11ce8 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -32,8 +32,15 @@ on tile[MIDI_TILE] : buffered in port:1 p_midi_rx = XS1_PORT_1F; #define CLKBLK_MIDI XS1_CLKBLK_2 on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; -#define MAX_TEST_COMMANDS 10 -#define TEST_COMMAND_FILE "midi_tx_cmds.txt" +#define MAX_TEST_COMMANDS 100 +#define TEST_COMMAND_FILE_TX "midi_tx_cmds.txt" +#define TEST_COMMAND_FILE_RX "midi_rx_cmds.txt" + +#ifndef DEBUG +#define dprintf(...) +#else +#define dprintf(...) printf(__VA_ARGS__) +#endif /* See hwsupport.xc */ void ctrlPort(); @@ -42,8 +49,6 @@ void ctrlPort(); unsigned mini_in_parse_helper(unsigned midi[3]){ - // printf("Composing data: 0x%x 0x%x 0x%x\n", midi[0], midi[1], midi[2]); - struct midi_in_parse_state m_state; reset_midi_state(m_state); @@ -59,69 +64,97 @@ unsigned mini_in_parse_helper(unsigned midi[3]){ return 0; } -unsigned parse_cmd_line(uint8_t commands[MAX_TEST_COMMANDS][3]) +{unsigned, unsigned} read_config_file(uint8_t commands[MAX_TEST_COMMANDS][3]) { - FILE * movable fptr_tx = fopen(TEST_COMMAND_FILE,"rt"); + unsigned tx_line_count = 0; + + FILE * movable fptr_tx = fopen(TEST_COMMAND_FILE_TX,"rt"); if (fptr_tx == NULL) { - printf("ERROR: TX command file %s not found or unable to open.\n", TEST_COMMAND_FILE); - fclose(move(fptr_tx)); - return 0; - } - - unsigned line = 0; - - unsigned a,b,c; - while (fscanf(fptr_tx, "%u %u %u\n", &a, &b, &c) == 3) { - commands[line][0] = a; - commands[line][1] = b; - commands[line][2] = c; - // printf("Line %u params: 0x%x 0x%x 0x%x\n", line, commands[line][0], commands[line][1], commands[line][2]); - line++; - if(line > MAX_TEST_COMMANDS){ - printf("ERROR: Too many lines in TX command file\n"); - - fclose(move(fptr_tx)); - return MAX_TEST_COMMANDS; + dprintf("WARNING: TX command file %s not found or unable to open.\n", TEST_COMMAND_FILE_TX); + } else { + unsigned a,b,c; + while (fscanf(fptr_tx, "%u %u %u\n", &a, &b, &c) == 3) { + commands[tx_line_count][0] = a; + commands[tx_line_count][1] = b; + commands[tx_line_count][2] = c; + //printf("Line %u params: 0x%x 0x%x 0x%x\n", tx_line_count, commands[tx_line_count][0], commands[tx_line_count][1], commands[tx_line_count][2]); + tx_line_count++; + if(tx_line_count > MAX_TEST_COMMANDS){ + printf("ERROR: Too many lines in TX command file\n"); + tx_line_count = MAX_TEST_COMMANDS; + } } } - fclose(move(fptr_tx)); - return line; + + + unsigned rx_cmd_count = 0; + + FILE * movable fptr_rx = fopen(TEST_COMMAND_FILE_RX,"rt"); + if (fptr_rx == NULL) { + dprintf("WARNING: RX command file %s not found or unable to open.\n", TEST_COMMAND_FILE_RX); + } else { + if(fscanf(fptr_rx, "%u\n", &rx_cmd_count) != 1){ + printf("ERROR: Not enough or too many items in RX command file line\n"); + } + } + fclose(move(fptr_rx)); + + return {tx_line_count, rx_cmd_count}; } void test(chanend c_midi){ uint8_t commands[MAX_TEST_COMMANDS][3] = {{0}}; - unsigned num_tx = parse_cmd_line(commands); + unsigned num_to_tx = 0; + unsigned num_to_rx = 0; + {num_to_tx, num_to_rx} = read_config_file(commands); + dprintf("Sending %u MIDI command line(s) and receiving %u MIDI command(s)\n", num_to_tx, num_to_rx); + // For MIDI Rx int is_ack; - unsigned datum; + unsigned rx_packet; - unsigned line = 0; - while(1){ + // Counters for Rx and Tx + unsigned tx_cmd_count = 0; + unsigned rx_cmd_count = 0; + + timer tmr; + + int t_tx; + tmr :> t_tx; + + const int max_tx_time = XS1_TIMER_HZ / 31250 * 3 * (8 + 1 + 1); // 30 bits at 31.25 kbps is 0.96ms + + while(tx_cmd_count < num_to_tx || rx_cmd_count < num_to_rx ){ select{ - case midi_get_ack_or_data(c_midi, is_ack, datum): - // printf("ACK: %d Datum: 0x%x\n", is_ack, datum); - line++; - if(line == num_tx){ - delay_microseconds(200); // Allow frame to complete - exit(0); + case midi_get_ack_or_data(c_midi, is_ack, rx_packet): + if(is_ack){ + dprintf("ACK from Tx\n"); + tx_cmd_count++; + } else { + unsigned midi_data[3] = {0}; + unsigned byte_count = 0; + {midi_data[0], midi_data[1], midi_data[2], byte_count} = midi_out_parse(rx_packet); + dprintf("dut_midi_rx: %u %u %u\n", midi_data[0], midi_data[1], midi_data[2]); + rx_cmd_count++; } break; - default: - if(num_tx){ - unsigned midi[] = {commands[line][0], commands[line][1], commands[line][2]}; - unsigned tx_packet = mini_in_parse_helper(midi); - outuint(c_midi, byterev(tx_packet)); - // printf("SEND TO MIDI: 0x%x\n", tx_packet); - delay_milliseconds(2); // 30 bits at 31.25 kbps is 0.96ms - } else { - exit(0); - } + case tx_cmd_count < num_to_tx => tmr when timerafter(t_tx) :> int _: + unsigned midi[] = {commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]}; + unsigned tx_packet = mini_in_parse_helper(midi); + outuint(c_midi, byterev(tx_packet)); + dprintf("Sent packet to midi: %u %u %u\n", commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]); + t_tx += max_tx_time; break; } } + dprintf("Tx and Rx count met - exiting after last tx complete.\n"); + tmr when timerafter(t_tx) :> int _; // wait until packet definitely departed + + delay_ticks(max_tx_time / 4); // Allow a few more bit times about to allow TXChecker to do it's thing + exit(0); } diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index 62db6d6c..7f3aa12b 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -6,12 +6,7 @@ import Pyxsim from Pyxsim import testers from pathlib import Path from uart_tx_checker import UARTTxChecker -# from spdif_test_utils import ( -# Clock, -# Spdif_rx, -# Frames, -# freq_for_sample_rate, -# ) + MAX_CYCLES = 15000000 MIDI_RATE = 31250 @@ -47,7 +42,6 @@ def create_midi_tx_file(commands): @pytest.mark.parametrize("config", CONFIGS) def test_tx(capfd, config): xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") - p_midi_out = "tile[1]:XS1_PORT_4C" midi_commands = [[0x90, 60, 81]] create_midi_tx_file(midi_commands) @@ -62,7 +56,7 @@ def test_tx(capfd, config): bpb = 8 parity = 0 stop = 1 - length_of_test = 3 # characters + length_of_test = sum(len(cmd) for cmd in midi_commands) simthreads = [ UARTTxChecker(tx_port, parity, baud, length_of_test, stop, bpb, debug=False) diff --git a/tests/uart_rx_checker.py b/tests/uart_rx_checker.py index 1aa6e6cc..c313ae5b 100644 --- a/tests/uart_rx_checker.py +++ b/tests/uart_rx_checker.py @@ -16,6 +16,8 @@ Parity = dict( UART_PARITY_BAD=3 ) +# From tools 15.2.1 we need to add an extra factor to go from ps to fs +time_scaling_factor = 1000 class DriveHigh(px.SimThread): def __init__(self, p): @@ -28,13 +30,12 @@ class DriveHigh(px.SimThread): class UARTRxChecker(px.SimThread): - def __init__(self, rx_port, tx_port, parity, baud, stop_bits, bpb, data=[0x7f, 0x00, 0x2f, 0xff], - intermittent=False): + def __init__(self, rx_port, parity, baud, stop_bits, bpb, data=[0x7f, 0x00, 0x2f, 0xff], + intermittent=False, debug=False): """ Create a UARTRxChecker instance. :param rx_port: Receive port of the UART device under test. - :param tx_port: Transmit port of the UART device under test. :param parity: Parity of the UART connection. :param baud: BAUD rate of the UART connection. :param stop_bits: Number of stop_bits for each UART byte. @@ -43,7 +44,6 @@ class UARTRxChecker(px.SimThread): :param intermittent: Add a random delay between sent bytes. """ self._rx_port = rx_port - self._tx_port = tx_port self._parity = parity self._baud = baud self._stop_bits = stop_bits @@ -142,7 +142,7 @@ class UARTRxChecker(px.SimThread): Returns float value in nanoseconds. """ # Return float value in ps - return (1.0 / self._baud) * 1e12 + return (1.0 / self._baud) * 1e12 * time_scaling_factor def wait_baud_time(self, xsi): """ From 398d96614569b5e7fb47ce3fae06d38bc6bf47e0 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 16 Apr 2024 15:21:58 +0100 Subject: [PATCH 08/40] Initial MIDI Rx test using pyxsim --- .gitignore | 1 + tests/midi_test_helpers.py | 28 ++++++++-- tests/test_midi/src/app_midi_simple.xc | 15 +++--- tests/test_midi_rx.py | 71 ++++++++++++++++++++++++++ tests/test_midi_tx.py | 26 +--------- tests/uart_rx_checker.py | 9 ++-- 6 files changed, 113 insertions(+), 37 deletions(-) create mode 100644 tests/test_midi_rx.py diff --git a/.gitignore b/.gitignore index 885ecb54..d84e3249 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ host_usb_mixer_control/xmos_mixer **.egg-info *tests/logs/* midi_tx_cmds.txt +midi_rx_cmds.txt diff --git a/tests/midi_test_helpers.py b/tests/midi_test_helpers.py index 5bf8b4f5..d9852d8a 100644 --- a/tests/midi_test_helpers.py +++ b/tests/midi_test_helpers.py @@ -1,7 +1,7 @@ # Copyright 2024 XMOS LIMITED. # This Software is subject to the terms of the XMOS Public Licence: Version 1. -class Midi_expect: +class midi_expect_tx: def __init(self): pass @@ -14,11 +14,33 @@ class Midi_expect: return expected +class midi_expect_rx: + def __init(self): + pass -def create_midi_tx_file(commands): - with open("midi_tx_cmds.txt", "wt") as mt: + def expect(self, commands): + expected = "" + for command in commands: + while len(command) < 3: + command.append(0) + expected += "dut_midi_rx: " + " ".join([f"{byte}" for byte in command]) + "\n" + + return expected + +midi_tx_file = "midi_tx_cmds.txt" +midi_rx_file = "midi_rx_cmds.txt" + +def create_midi_tx_file(commands=None): + with open(midi_tx_file, "wt") as mt: + if commands is None: + return for command in commands: while len(command) < 3: command.append(0) text = " ".join([str(byte) for byte in command]) + "\n" mt.write(text) + +def create_midi_rx_file(num_commands=0): + with open(midi_rx_file, "wt") as mr: + text = f"{num_commands}\n" + mr.write(text) diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index 71f11ce8..5f86f1cd 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -36,10 +36,12 @@ on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; #define TEST_COMMAND_FILE_TX "midi_tx_cmds.txt" #define TEST_COMMAND_FILE_RX "midi_rx_cmds.txt" -#ifndef DEBUG -#define dprintf(...) -#else +#define DEBUG 0 + +#if DEBUG #define dprintf(...) printf(__VA_ARGS__) +#else +#define dprintf(...) #endif /* See hwsupport.xc */ @@ -134,8 +136,9 @@ void test(chanend c_midi){ } else { unsigned midi_data[3] = {0}; unsigned byte_count = 0; - {midi_data[0], midi_data[1], midi_data[2], byte_count} = midi_out_parse(rx_packet); - dprintf("dut_midi_rx: %u %u %u\n", midi_data[0], midi_data[1], midi_data[2]); + {midi_data[0], midi_data[1], midi_data[2], byte_count} = midi_out_parse(byterev(rx_packet)); + // Note this needs to always print for capff to pick it up + printf("dut_midi_rx: %u %u %u\n", midi_data[0], midi_data[1], midi_data[2]); rx_cmd_count++; } break; @@ -143,7 +146,7 @@ void test(chanend c_midi){ case tx_cmd_count < num_to_tx => tmr when timerafter(t_tx) :> int _: unsigned midi[] = {commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]}; unsigned tx_packet = mini_in_parse_helper(midi); - outuint(c_midi, byterev(tx_packet)); + outuint(c_midi, byterev(tx_packet)); dprintf("Sent packet to midi: %u %u %u\n", commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]); t_tx += max_tx_time; break; diff --git a/tests/test_midi_rx.py b/tests/test_midi_rx.py new file mode 100644 index 00000000..c87000c2 --- /dev/null +++ b/tests/test_midi_rx.py @@ -0,0 +1,71 @@ +# Copyright 2014-2024 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. + +import pytest +import Pyxsim +from Pyxsim import testers +from pathlib import Path +from uart_rx_checker import UARTRxChecker +from midi_test_helpers import midi_expect_rx, create_midi_rx_file, create_midi_tx_file + +MAX_CYCLES = 15000000 +MIDI_RATE = 31250 +CONFIGS = ["xs2", "xs3"] +CONFIGS = ["xs3"] + + +##### +# This test builds the spdif transmitter app with a verity of presets and tests that the output matches those presets +##### +@pytest.mark.parametrize("config", CONFIGS) +def test_rx(capfd, config): + xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") + + midi_commands = [[0x90, 60, 81]] + create_midi_rx_file(1) + create_midi_tx_file() + + + tester = testers.ComparisonTester(midi_expect_rx().expect(midi_commands), + regexp = "uart_tx_checker:.+", + ordered = True) + + rx_port = "tile[1]:XS1_PORT_1F" + tx_port = "tile[1]:XS1_PORT_4C" # Needed so that UARTRxChecker (a transmitter) knows when to start + baud = MIDI_RATE + bpb = 8 + parity = 0 + stop = 1 + + midi_commands_flattened = [item for row in midi_commands for item in row] + # midi_commands_flattened.append(0x00) # send a null afterwards to give RXChecker to complete + + simthreads = [ + UARTRxChecker(tx_port, rx_port, parity, baud, stop, bpb, midi_commands_flattened, debug=False) + ] + + simargs = ["--max-cycles", str(MAX_CYCLES)] + simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) #This is just for local debug so we can capture the run, pass as kwarg to run_with_pyxsim + + # result = Pyxsim.run_on_simulator( + result = Pyxsim.run_on_simulator( + xe, + simthreads=simthreads, + instTracing=True, + # clean_before_build=True, + clean_before_build=False, + tester=tester, + capfd=capfd, + # capfd=None, + timeout=120, + simargs=simargs, + build_options=[ + "-j", + f"CONFIG={config}", + "EXTRA_BUILD_FLAGS=" + + f" -DMIDI_RATE_HZ={MIDI_RATE}" + , + ], + ) + + assert result \ No newline at end of file diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index 7f3aa12b..9b7aa842 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -6,7 +6,7 @@ import Pyxsim from Pyxsim import testers from pathlib import Path from uart_tx_checker import UARTTxChecker - +from midi_test_helpers import midi_expect_tx, create_midi_tx_file MAX_CYCLES = 15000000 MIDI_RATE = 31250 @@ -14,28 +14,6 @@ CONFIGS = ["xs2", "xs3"] CONFIGS = ["xs3"] -class Midi_expect: - def __init(self): - pass - - def expect(self, commands): - expected = "" - for command in commands: - while len(command) < 3: - command.append(0) - expected += "uart_tx_checker: " + " ".join([f"0x{byte:02x}" for byte in command]) + "\n" - - return expected - - -def create_midi_tx_file(commands): - with open("midi_tx_cmds.txt", "wt") as mt: - for command in commands: - while len(command) < 3: - command.append(0) - text = " ".join([str(byte) for byte in command]) + "\n" - mt.write(text) - ##### # This test builds the spdif transmitter app with a verity of presets and tests that the output matches those presets ##### @@ -46,7 +24,7 @@ def test_tx(capfd, config): midi_commands = [[0x90, 60, 81]] create_midi_tx_file(midi_commands) - tester = testers.ComparisonTester(Midi_expect().expect(midi_commands), + tester = testers.ComparisonTester(midi_expect_tx().expect(midi_commands), regexp = "uart_tx_checker:.+", ordered = True) diff --git a/tests/uart_rx_checker.py b/tests/uart_rx_checker.py index c313ae5b..79f57f27 100644 --- a/tests/uart_rx_checker.py +++ b/tests/uart_rx_checker.py @@ -30,7 +30,7 @@ class DriveHigh(px.SimThread): class UARTRxChecker(px.SimThread): - def __init__(self, rx_port, parity, baud, stop_bits, bpb, data=[0x7f, 0x00, 0x2f, 0xff], + def __init__(self, tx_port, rx_port, parity, baud, stop_bits, bpb, data=[0x7f, 0x00, 0x2f, 0xff], intermittent=False, debug=False): """ Create a UARTRxChecker instance. @@ -43,6 +43,7 @@ class UARTRxChecker(px.SimThread): :param data: A list of bytes to send (default: [0x7f, 0x00, 0x2f, 0xff]) :param intermittent: Add a random delay between sent bytes. """ + self._tx_port = tx_port self._rx_port = rx_port self._parity = parity self._baud = baud @@ -88,11 +89,11 @@ class UARTRxChecker(px.SimThread): :param xsi: XMOS Simulator Instance. :param byte: Data to send. """ - # print "0x%02x:" % byte + # print(f"Checker sent 0x{byte:02x}") for x in range(self._bits_per_byte): - # print " Sending bit %d of 0x%02x (%d)" % (x, byte, (byte >> x) & 0x01) + # print(f" Sending bit {x}") xsi.drive_port_pins(self._rx_port, (byte & (0x01 << x)) >= 1) - # print " (x): %d" % ((byte & (0x01 << x))>=1) + # print(f" (x): {((byte & (0x01 << x))>=1)}") self.wait_baud_time(xsi) def send_parity(self, xsi, byte): From 540fb4baa58575ca282297c25e25e01a637448c0 Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 17 Apr 2024 11:21:05 +0100 Subject: [PATCH 09/40] Add tmpdirs and initial build so test works with xdist --- .gitignore | 1 + tests/conftest.py | 19 +++++++- tests/midi_test_helpers.py | 39 +++++++++++++++- tests/test_midi_rx.py | 95 ++++++++++++++++++-------------------- tests/test_midi_tx.py | 93 ++++++++++++++++++------------------- 5 files changed, 148 insertions(+), 99 deletions(-) diff --git a/.gitignore b/.gitignore index d84e3249..29cab6ac 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ host_usb_mixer_control/xmos_mixer *tests/logs/* midi_tx_cmds.txt midi_rx_cmds.txt +trace.txt diff --git a/tests/conftest.py b/tests/conftest.py index 3117626c..58ced38c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,9 @@ # This Software is subject to the terms of the XMOS Public Licence: Version 1. import pytest import time - +import Pyxsim +from pathlib import Path +from midi_test_helpers import MIDI_TEST_CONFIGS @pytest.fixture() def test_file(request): @@ -39,3 +41,18 @@ def pytest_addoption(parser): @pytest.fixture def options(request): yield request.config.option + +# We use the same binary multiple times so just build once +@pytest.fixture(scope="session") +def build_midi(): + all_build_success = True + for config in MIDI_TEST_CONFIGS: + xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") + + success, output = Pyxsim._build(xe, build_options=["-j"]) + all_build_success |= success + + if not all_build_success: + print(f"ERROR MIDI Build failed: {output}") + + return str(Path(__file__).parent / f"test_midi/bin/") if all_build_success else False diff --git a/tests/midi_test_helpers.py b/tests/midi_test_helpers.py index d9852d8a..2653c85e 100644 --- a/tests/midi_test_helpers.py +++ b/tests/midi_test_helpers.py @@ -1,6 +1,32 @@ # Copyright 2024 XMOS LIMITED. # This Software is subject to the terms of the XMOS Public Licence: Version 1. +import contextlib +import os +import shutil +import tempfile + +MIDI_TEST_CONFIGS = ["xs2", "xs3"] +MIDI_RATE = 31250 + +@contextlib.contextmanager +def cd(newdir, cleanup=lambda: True): + prevdir = os.getcwd() + os.chdir(os.path.expanduser(newdir)) + try: + yield + finally: + os.chdir(prevdir) + cleanup() + +@contextlib.contextmanager +def tempdir(): + dirpath = tempfile.mkdtemp() + def cleanup(): + shutil.rmtree(dirpath) + with cd(dirpath, cleanup): + yield dirpath + class midi_expect_tx: def __init(self): pass @@ -12,7 +38,7 @@ class midi_expect_tx: command.append(0) expected += "uart_tx_checker: " + " ".join([f"0x{byte:02x}" for byte in command]) + "\n" - return expected + return expected + "\n" class midi_expect_rx: def __init(self): @@ -25,7 +51,7 @@ class midi_expect_rx: command.append(0) expected += "dut_midi_rx: " + " ".join([f"{byte}" for byte in command]) + "\n" - return expected + return expected + "\n" midi_tx_file = "midi_tx_cmds.txt" midi_rx_file = "midi_rx_cmds.txt" @@ -44,3 +70,12 @@ def create_midi_rx_file(num_commands=0): with open(midi_rx_file, "wt") as mr: text = f"{num_commands}\n" mr.write(text) + + + +# Test/dev only +if __name__ == "__main__": + with tempdir() as td: + print(td) + create_midi_tx_file() + input("PRESS ENTER TO CONTINUE") diff --git a/tests/test_midi_rx.py b/tests/test_midi_rx.py index c87000c2..aa9fc05d 100644 --- a/tests/test_midi_rx.py +++ b/tests/test_midi_rx.py @@ -6,66 +6,63 @@ import Pyxsim from Pyxsim import testers from pathlib import Path from uart_rx_checker import UARTRxChecker -from midi_test_helpers import midi_expect_rx, create_midi_rx_file, create_midi_tx_file +from midi_test_helpers import midi_expect_rx, create_midi_rx_file, create_midi_tx_file, tempdir, MIDI_TEST_CONFIGS, MIDI_RATE +from distutils.dir_util import copy_tree # we're using python 3.7 and dirs_exist_ok=True isn't available until 3.8 :( MAX_CYCLES = 15000000 -MIDI_RATE = 31250 -CONFIGS = ["xs2", "xs3"] -CONFIGS = ["xs3"] ##### -# This test builds the spdif transmitter app with a verity of presets and tests that the output matches those presets +# This test takes the built binary, copies it to a tmp dir and runs the midi Rx test which sends some commands +# to using the UARTRX checker and the firmware receives them ##### -@pytest.mark.parametrize("config", CONFIGS) -def test_rx(capfd, config): - xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") +@pytest.mark.parametrize("config", MIDI_TEST_CONFIGS) +def test_rx(capfd, config, build_midi): + # Need tempdir as we use the same config files and this causes issues when using xdist + with tempdir() as tmpdirname: + copy_tree(build_midi, tmpdirname) + xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe") - midi_commands = [[0x90, 60, 81]] - create_midi_rx_file(1) - create_midi_tx_file() + midi_commands = [[0x90, 60, 81]] + create_midi_rx_file(1) + create_midi_tx_file() + expected = midi_expect_rx().expect(midi_commands) + tester = testers.ComparisonTester(midi_expect_rx().expect(midi_commands), + ordered = True) + + rx_port = "tile[1]:XS1_PORT_1F" + tx_port = "tile[1]:XS1_PORT_4C" # Needed so that UARTRxChecker (a transmitter) knows when to start + baud = MIDI_RATE + bpb = 8 + parity = 0 + stop = 1 - tester = testers.ComparisonTester(midi_expect_rx().expect(midi_commands), - regexp = "uart_tx_checker:.+", - ordered = True) - - rx_port = "tile[1]:XS1_PORT_1F" - tx_port = "tile[1]:XS1_PORT_4C" # Needed so that UARTRxChecker (a transmitter) knows when to start - baud = MIDI_RATE - bpb = 8 - parity = 0 - stop = 1 + midi_commands_flattened = [item for row in midi_commands for item in row] + # midi_commands_flattened.append(0x00) # send a null afterwards to give RXChecker to complete - midi_commands_flattened = [item for row in midi_commands for item in row] - # midi_commands_flattened.append(0x00) # send a null afterwards to give RXChecker to complete + simthreads = [ + UARTRxChecker(tx_port, rx_port, parity, baud, stop, bpb, midi_commands_flattened, debug=False) + ] - simthreads = [ - UARTRxChecker(tx_port, rx_port, parity, baud, stop, bpb, midi_commands_flattened, debug=False) - ] + simargs = ["--max-cycles", str(MAX_CYCLES)] + #This is just for local debug so we can capture the traces if needed. It slows xsim down so not needed + # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) - simargs = ["--max-cycles", str(MAX_CYCLES)] - simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) #This is just for local debug so we can capture the run, pass as kwarg to run_with_pyxsim + # Print to console + # with capfd.disabled(): + # print("++++", expected, "++++") + # print("****", capture, "****") + # print("****", capture.split("\n"), "****") + # print(xe) - # result = Pyxsim.run_on_simulator( - result = Pyxsim.run_on_simulator( - xe, - simthreads=simthreads, - instTracing=True, - # clean_before_build=True, - clean_before_build=False, - tester=tester, - capfd=capfd, - # capfd=None, - timeout=120, - simargs=simargs, - build_options=[ - "-j", - f"CONFIG={config}", - "EXTRA_BUILD_FLAGS=" - + f" -DMIDI_RATE_HZ={MIDI_RATE}" - , - ], - ) + Pyxsim.run_with_pyxsim( + xe, + simthreads=simthreads, + timeout=1200, + simargs=simargs, + ) + capture = capfd.readouterr().out + result = tester.run(capture.split("\n")) - assert result \ No newline at end of file + assert result \ No newline at end of file diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index 9b7aa842..605bfba1 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -6,62 +6,61 @@ import Pyxsim from Pyxsim import testers from pathlib import Path from uart_tx_checker import UARTTxChecker -from midi_test_helpers import midi_expect_tx, create_midi_tx_file +from midi_test_helpers import midi_expect_tx, create_midi_tx_file, create_midi_rx_file, tempdir, MIDI_TEST_CONFIGS, MIDI_RATE +from distutils.dir_util import copy_tree # we're using python 3.7 and dirs_exist_ok=True isn't available until 3.8 :( MAX_CYCLES = 15000000 -MIDI_RATE = 31250 -CONFIGS = ["xs2", "xs3"] -CONFIGS = ["xs3"] - ##### -# This test builds the spdif transmitter app with a verity of presets and tests that the output matches those presets +# This test takes the built binary, copies it to a tmp dir and runs the midi Tx test which sends some commands +# to the firmware and then receives them using the UARTTX checker ##### -@pytest.mark.parametrize("config", CONFIGS) -def test_tx(capfd, config): - xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") +@pytest.mark.parametrize("config", MIDI_TEST_CONFIGS) +def test_tx(capfd, config, build_midi): - midi_commands = [[0x90, 60, 81]] - create_midi_tx_file(midi_commands) + # Need tempdir as we use the same config files and this causes issues when using xdist + with tempdir() as tmpdirname: + copy_tree(build_midi, tmpdirname) + xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe") - tester = testers.ComparisonTester(midi_expect_tx().expect(midi_commands), - regexp = "uart_tx_checker:.+", - ordered = True) + midi_commands = [[0x90, 60, 81]] + create_midi_tx_file(midi_commands) + create_midi_rx_file() - - tx_port = "tile[1]:XS1_PORT_4C" - baud = MIDI_RATE - bpb = 8 - parity = 0 - stop = 1 - length_of_test = sum(len(cmd) for cmd in midi_commands) + expected = midi_expect_tx().expect(midi_commands) + tester = testers.ComparisonTester( expected, + ordered = True) - simthreads = [ - UARTTxChecker(tx_port, parity, baud, length_of_test, stop, bpb, debug=False) - ] + tx_port = "tile[1]:XS1_PORT_4C" + baud = MIDI_RATE + bpb = 8 + parity = 0 + stop = 1 + length_of_test = sum(len(cmd) for cmd in midi_commands) - simargs = ["--max-cycles", str(MAX_CYCLES)] - # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) #This is just for local debug so we can capture the run, pass as kwarg to run_with_pyxsim + simthreads = [ + UARTTxChecker(tx_port, parity, baud, length_of_test, stop, bpb, debug=False) + ] - # result = Pyxsim.run_on_simulator( - result = Pyxsim.run_on_simulator( - xe, - simthreads=simthreads, - instTracing=True, - # clean_before_build=True, - clean_before_build=False, - tester=tester, - capfd=capfd, - # capfd=None, - timeout=120, - simargs=simargs, - build_options=[ - "-j", - f"CONFIG={config}", - "EXTRA_BUILD_FLAGS=" - + f" -DMIDI_RATE_HZ={MIDI_RATE}" - , - ], - ) - assert result \ No newline at end of file + simargs = ["--max-cycles", str(MAX_CYCLES)] + #This is just for local debug so we can capture the traces if needed. It slows xsim down so not needed + # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) + + Pyxsim.run_with_pyxsim( + xe, + simthreads=simthreads, + timeout=1200, + simargs=simargs, + ) + capture = capfd.readouterr().out + result = tester.run(capture.split("\n")) + + # Print to console + # with capfd.disabled(): + # print("++++", expected, "++++") + # print("****", capture, "****") + # print("****", capture.split("\n"), "****") + # print(xe) + + assert result \ No newline at end of file From 36b32a36dbd7276306f7057dc24ed22a01198627 Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 17 Apr 2024 15:12:41 +0100 Subject: [PATCH 10/40] Initial queue unit test --- lib_xua/src/midi/queue.h | 4 + tests/conftest.py | 2 +- tests/test_midi/src/app_midi_simple.xc | 2 +- .../test_midi_queue/hid_report_descriptor.h | 145 ++++++++++++++++++ .../src/test_midi_queue/test_midi_queue.c | 25 +++ .../src/xua_unit_test_helper.xc | 58 ++++++- tests/xua_unit_tests/src/xua_unit_tests.h | 7 + 7 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h create mode 100644 tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c diff --git a/lib_xua/src/midi/queue.h b/lib_xua/src/midi/queue.h index af67e6e5..b056c309 100644 --- a/lib_xua/src/midi/queue.h +++ b/lib_xua/src/midi/queue.h @@ -14,6 +14,8 @@ typedef struct queue_t { unsigned mask; } queue_t; +#ifdef __XC__ + inline int is_power_of_2(unsigned x) { return x != 0 && (x & (x - 1)) == 0; } @@ -64,4 +66,6 @@ inline unsigned queue_space(const queue_t &q) { return q.size - queue_items(q); } +#endif // __XC__ + #endif /* QUEUE_H_ */ diff --git a/tests/conftest.py b/tests/conftest.py index 58ced38c..b1973ed1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -# Copyright 2022-2023 XMOS LIMITED. +# Copyright 2022-2024 XMOS LIMITED. # This Software is subject to the terms of the XMOS Public Licence: Version 1. import pytest import time diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index 5f86f1cd..eecae28b 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -36,7 +36,7 @@ on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; #define TEST_COMMAND_FILE_TX "midi_tx_cmds.txt" #define TEST_COMMAND_FILE_RX "midi_rx_cmds.txt" -#define DEBUG 0 +#define DEBUG 0 #if DEBUG #define dprintf(...) printf(__VA_ARGS__) diff --git a/tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h b/tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h new file mode 100644 index 00000000..3824814e --- /dev/null +++ b/tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h @@ -0,0 +1,145 @@ +// Copyright 2021-2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef __hid_report_descriptor_h__ +#define __hid_report_descriptor_h__ + +#include "xua_hid_report.h" + +/* + * Define non-configurable items in the HID Report descriptor. + * (These are short items as the location field isn't relevant for them) + */ +static const USB_HID_Short_Item_t hidCollectionApplication = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionEnd = { + .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidCollectionLogical = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), + .data = { 0x02, 0x00 } }; + +static const USB_HID_Short_Item_t hidInputConstArray = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidInputDataVar = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), + .data = { 0x02, 0x00 } }; + +static const USB_HID_Short_Item_t hidLogicalMaximum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x00, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMaximum1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidLogicalMinimum0 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), + .data = { 0x00, 0x00 } }; + +static const USB_HID_Short_Item_t hidReportCount1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x01, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount6 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x06, 0x00 } }; +static const USB_HID_Short_Item_t hidReportCount7 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), + .data = { 0x07, 0x00 } }; +static const USB_HID_Short_Item_t hidReportSize1 = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), + .data = { 0x01, 0x00 } }; + +static const USB_HID_Short_Item_t hidUsageConsumerControl = { + .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .data = { 0x01, 0x00 } }; + +/* + * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report + * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. + */ +static const USB_HID_Report_Element_t hidReportPageConsumer = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), + .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, + .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) +}; + +/* + * Define configurable items in the HID Report descriptor. + */ +static USB_HID_Report_Element_t hidUsageByte0Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE2, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 0, 0) +}; // Mute + +static USB_HID_Report_Element_t hidUsageByte1Bit7 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xEA, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 1, 7) +}; // Vol- +static USB_HID_Report_Element_t hidUsageByte1Bit0 = { + .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), + .item.data = { 0xE9, 0x00 }, + .location = HID_REPORT_SET_LOC(0, 0, 1, 0) +}; // Vol+ + +/* + * List the configurable elements in the HID Report descriptor. + */ +static USB_HID_Report_Element_t* const hidConfigurableElements[] = { + &hidUsageByte0Bit0, + &hidUsageByte1Bit0, + &hidUsageByte1Bit7 +}; + +/* + * List HID Reports, one per Report ID. This should be a usage page item with the relevant + * If not using report IDs - still have one with report ID 0 + */ +static const USB_HID_Report_Element_t* const hidReports[] = { + &hidReportPageConsumer +}; + +/* + * List all items in the HID Report descriptor. + */ +static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { + &(hidReportPageConsumer.item), + &hidUsageConsumerControl, + &hidCollectionApplication, + &hidReportSize1, + &hidLogicalMinimum0, + &hidCollectionLogical, // Byte 0 + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageByte0Bit0.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount7, + &hidInputConstArray, + &hidCollectionEnd, + &hidCollectionLogical, // Byte 1 + &hidLogicalMaximum1, + &hidReportCount1, + &(hidUsageByte1Bit0.item), + &hidInputDataVar, + &hidLogicalMaximum0, + &hidReportCount6, + &hidInputConstArray, + &hidReportCount1, + &hidLogicalMaximum1, + &(hidUsageByte1Bit7.item), + &hidInputDataVar, + &hidCollectionEnd, + &hidCollectionEnd +}; + +/* + * Define the number of HID Reports + * Due to XC not supporting designated initializers, this constant has a hard-coded value. + * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) + */ +#define HID_REPORT_COUNT ( 1 ) + +#endif // __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c b/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c new file mode 100644 index 00000000..07161054 --- /dev/null +++ b/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c @@ -0,0 +1,25 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include + +#include "xua_unit_tests.h" +#include "../../../lib_xua/src/midi/queue.h" + + +#define RANDOM_SEED 55378008 +#define USB_MIDI_DEVICE_OUT_FIFO_SIZE 1024 +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +unsigned rndm = RANDOM_SEED; + + +void test_queue(void) { + queue_t symbol_fifo; + unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE]; + queue_init_wrap(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage)); + + int empty = queue_is_empty_wrap(&symbol_fifo); + TEST_ASSERT_EQUAL_UINT32(1, empty); + +} \ No newline at end of file diff --git a/tests/xua_unit_tests/src/xua_unit_test_helper.xc b/tests/xua_unit_tests/src/xua_unit_test_helper.xc index 48f82d3f..611f95b7 100644 --- a/tests/xua_unit_tests/src/xua_unit_test_helper.xc +++ b/tests/xua_unit_tests/src/xua_unit_test_helper.xc @@ -7,6 +7,8 @@ #include #include "../../../lib_xua/src/midi/midiinparse.h" #include "../../../lib_xua/src/midi/midioutparse.h" +#include "../../../lib_xua/src/midi/queue.h" + #endif // __XC__ @@ -33,7 +35,7 @@ unsigned random(unsigned &x){ return x; } -// Wrappers for midi parse because C doesn't support return tuples +////////////////////// Wrappers for midi parse because C doesn't support return tuples void midi_in_parse_wrap(void * unsafe mips, unsigned cable_number, unsigned char b, unsigned * unsafe valid, unsigned *unsafe packed){ unsafe{ struct midi_in_parse_state * unsafe ptr = mips; @@ -53,3 +55,57 @@ void reset_midi_state_wrap(void * unsafe mips){ reset_midi_state(*ptr); } } + +/////////////////////// Wrappers for queue test + + +void queue_init_wrap(queue_t *q, unsigned size) { + unsafe{ + queue_init(*q, size); + } +} + +int queue_is_empty_wrap(queue_t *unsafe q) { + unsafe{ + return queue_is_empty(*q); + } +} + +int queue_is_full_wrap(queue_t *unsafe q) { + unsafe{ + return queue_is_full(*q); + } +} + +/* +inline void queue_push_word(queue_t &q, unsigned array[], unsigned data) +{ + assert(!queue_is_full(q)); + array[q.wrptr++ & q.mask] = data; +} + +inline unsigned queue_pop_word(queue_t &q, unsigned array[]) { + assert(!queue_is_empty(q)); + return array[q.rdptr++ & q.mask]; +} + +inline void queue_push_byte(queue_t &q, unsigned char array[], unsigned data) +{ + assert(!queue_is_full(q)); + array[q.wrptr++ & q.mask] = data; +} + +inline unsigned queue_pop_byte(queue_t &q, unsigned char array[]) { + assert(!queue_is_empty(q)); + return array[q.rdptr++ & q.mask]; +} + +inline unsigned queue_items(const queue_t &q) { + return q.wrptr - q.rdptr; +} + +inline unsigned queue_space(const queue_t &q) { + return q.size - queue_items(q); +} + +*/ \ No newline at end of file diff --git a/tests/xua_unit_tests/src/xua_unit_tests.h b/tests/xua_unit_tests/src/xua_unit_tests.h index 7763b97a..53cf0dcd 100644 --- a/tests/xua_unit_tests/src/xua_unit_tests.h +++ b/tests/xua_unit_tests/src/xua_unit_tests.h @@ -5,12 +5,19 @@ #include "unity.h" #include "xua_conf.h" +#include "../../../lib_xua/src/midi/queue.h" #ifndef __XC__ void midi_in_parse_wrap(void * mips, unsigned cable_number, unsigned char b, unsigned * valid, unsigned * packed); void midi_out_parse_wrap(unsigned tx_data, unsigned midi[3], unsigned * size); void reset_midi_state_wrap(void *mips); unsigned random(unsigned *x); + +void queue_init_wrap(queue_t *q, unsigned size); +int queue_is_empty_wrap(const queue_t *q); +int queue_is_full_wrap(const queue_t *q); + + #endif #endif /* XUA_UNIT_TESTS_H_ */ From b15eb3a3296c50deeba992db6e3caf4ca37bec81 Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 17 Apr 2024 15:21:22 +0100 Subject: [PATCH 11/40] Make sure dir is off cwd --- tests/midi_test_helpers.py | 2 +- tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/midi_test_helpers.py b/tests/midi_test_helpers.py index 2653c85e..ab612d15 100644 --- a/tests/midi_test_helpers.py +++ b/tests/midi_test_helpers.py @@ -21,7 +21,7 @@ def cd(newdir, cleanup=lambda: True): @contextlib.contextmanager def tempdir(): - dirpath = tempfile.mkdtemp() + dirpath = tempfile.mkdtemp(dir=os.getcwd()) def cleanup(): shutil.rmtree(dirpath) with cd(dirpath, cleanup): diff --git a/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c b/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c index 07161054..a203e88b 100644 --- a/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c +++ b/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c @@ -14,7 +14,7 @@ unsigned rndm = RANDOM_SEED; -void test_queue(void) { +void test_midi_queue(void) { queue_t symbol_fifo; unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE]; queue_init_wrap(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage)); From c960d822336630dda26d896df5ada3cadb9abee2 Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 17 Apr 2024 16:24:07 +0100 Subject: [PATCH 12/40] Debug Jenkins failure --- Jenkinsfile | 2 ++ tests/test_midi_tx.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 3479f03c..d8a35ff7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -39,6 +39,8 @@ pipeline { } } } + // Temp debug + archiveArtifacts artifacts: "${REPO}/**/*.pdf", fingerprint: true, allowEmptyArchive: true } } stage('Unity tests') { diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index 605bfba1..ff2f71ac 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -18,6 +18,10 @@ MAX_CYCLES = 15000000 @pytest.mark.parametrize("config", MIDI_TEST_CONFIGS) def test_tx(capfd, config, build_midi): + with open("dir.txt", "wt") as db: + import subprocess, shutil + output = subprocess.run("tree", capture_output=True, text=True) + # Need tempdir as we use the same config files and this causes issues when using xdist with tempdir() as tmpdirname: copy_tree(build_midi, tmpdirname) From 79672750017ba3525152871e61a0cf133bc608cd Mon Sep 17 00:00:00 2001 From: Ed Date: Thu, 18 Apr 2024 09:34:33 +0100 Subject: [PATCH 13/40] Queue unit tests --- lib_xua/src/midi/queue.h | 2 +- .../src/test_midi_parse/test_midi_parse.c | 36 +++++------ .../src/test_midi_queue/test_midi_queue.c | 60 +++++++++++++++++-- .../src/xua_unit_test_helper.xc | 56 +++++++++-------- tests/xua_unit_tests/src/xua_unit_tests.h | 19 +++--- 5 files changed, 117 insertions(+), 56 deletions(-) diff --git a/lib_xua/src/midi/queue.h b/lib_xua/src/midi/queue.h index b056c309..3e51b328 100644 --- a/lib_xua/src/midi/queue.h +++ b/lib_xua/src/midi/queue.h @@ -1,4 +1,4 @@ -// Copyright 2013-2021 XMOS LIMITED. +// Copyright 2013-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef QUEUE_H_ #define QUEUE_H_ diff --git a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c index 89989429..e99e8115 100644 --- a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c +++ b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c @@ -29,22 +29,22 @@ unsigned mini_in_parse_ut(unsigned midi[3]){ struct midi_in_parse_state m_state; void * mips = &m_state; - reset_midi_state_wrap(mips); + reset_midi_state_c_wrapper(mips); unsigned valid = 0; unsigned packed = 0; - midi_in_parse_wrap(mips, CABLE_NUM, midi[0], &valid, &packed); + midi_in_parse_c_wrapper(mips, CABLE_NUM, midi[0], &valid, &packed); // printf("Valid: %d data: %u\n", valid, packed); if(valid){ return packed; } - midi_in_parse_wrap(mips, CABLE_NUM, midi[1], &valid, &packed); + midi_in_parse_c_wrapper(mips, CABLE_NUM, midi[1], &valid, &packed); // printf("Valid: %d data: %u\n", valid, packed); if(valid){ return packed; } - midi_in_parse_wrap(mips, CABLE_NUM, midi[2], &valid, &packed); + midi_in_parse_c_wrapper(mips, CABLE_NUM, midi[2], &valid, &packed); // printf("Valid: %d data: %u\n", valid, packed); if(valid){ return packed; @@ -56,14 +56,14 @@ unsigned mini_in_parse_ut(unsigned midi[3]){ unsigned rndm = RANDOM_SEED; -void test_note(void) { +void test_midi_note(void) { for(int cmd = NOTE_OFF; cmd < NOTE_ON + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; unsigned packed = mini_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; - midi_out_parse_wrap(packed, midi_dut, &size); + midi_out_parse_c_wrapper(packed, midi_dut, &size); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? @@ -74,14 +74,14 @@ void test_note(void) { } } -void test_pressure(void) { +void test_midi_pressure(void) { for(int cmd = PRESSURE; cmd < PRESSURE + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; unsigned packed = mini_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; - midi_out_parse_wrap(packed, midi_dut, &size); + midi_out_parse_c_wrapper(packed, midi_dut, &size); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? @@ -92,14 +92,14 @@ void test_pressure(void) { } } -void test_control(void) { +void test_midi_control(void) { for(int cmd = CONTROL; cmd < CONTROL + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; unsigned packed = mini_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; - midi_out_parse_wrap(packed, midi_dut, &size); + midi_out_parse_c_wrapper(packed, midi_dut, &size); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? @@ -110,14 +110,14 @@ void test_control(void) { } } -void test_program(void) { +void test_midi_program(void) { for(int cmd = PROGRAM; cmd < PROGRAM + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; unsigned packed = mini_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; - midi_out_parse_wrap(packed, midi_dut, &size); + midi_out_parse_c_wrapper(packed, midi_dut, &size); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? @@ -128,14 +128,14 @@ void test_program(void) { } } -void test_pressure_val(void) { +void test_midi_pressure_val(void) { for(int cmd = PRESSURE_VAL; cmd < PRESSURE_VAL + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; unsigned packed = mini_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; - midi_out_parse_wrap(packed, midi_dut, &size); + midi_out_parse_c_wrapper(packed, midi_dut, &size); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? @@ -146,14 +146,14 @@ void test_pressure_val(void) { } } -void test_range(void) { +void test_midi_range(void) { for(int cmd = RANGE; cmd < RANGE + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; unsigned packed = mini_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; - midi_out_parse_wrap(packed, midi_dut, &size); + midi_out_parse_c_wrapper(packed, midi_dut, &size); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? @@ -164,14 +164,14 @@ void test_range(void) { } } -void test_manufacturer_id(void) { +void test_midi_manufacturer_id(void) { for(int cmd = MANUFACTURE_ID; cmd < MANUFACTURE_ID + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; unsigned packed = mini_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; - midi_out_parse_wrap(packed, midi_dut, &size); + midi_out_parse_c_wrapper(packed, midi_dut, &size); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]); // printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]); //TEST_ASSERT_EQUAL_UINT32_ARRAY not working!? diff --git a/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c b/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c index a203e88b..07e643e0 100644 --- a/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c +++ b/tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c @@ -6,6 +6,14 @@ #include "xua_unit_tests.h" #include "../../../lib_xua/src/midi/queue.h" +#define DEBUG 0 + +#if DEBUG +#define dprintf(...) printf(__VA_ARGS__) +#else +#define dprintf(...) +#endif + #define RANDOM_SEED 55378008 #define USB_MIDI_DEVICE_OUT_FIFO_SIZE 1024 @@ -14,12 +22,56 @@ unsigned rndm = RANDOM_SEED; -void test_midi_queue(void) { +void test_midi_queue_init(void) { queue_t symbol_fifo; unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE]; - queue_init_wrap(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage)); + queue_init_c_wrapper(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage)); - int empty = queue_is_empty_wrap(&symbol_fifo); - TEST_ASSERT_EQUAL_UINT32(1, empty); + int empty = queue_is_empty_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_INT32(1, empty); + int full = queue_is_full_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_INT32(0, full); + + unsigned items = queue_items_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_UINT32(0, items); + + unsigned space = queue_space_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_UINT32(USB_MIDI_DEVICE_OUT_FIFO_SIZE, space); +} + +void test_midi_queue_push_pop(void) { + queue_t symbol_fifo; + unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE]; + queue_init_c_wrapper(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage)); + + for(unsigned i = 0; i < USB_MIDI_DEVICE_OUT_FIFO_SIZE; i++){ + int items = queue_items_c_wrapper(&symbol_fifo); + dprintf("Pre i: %u items: %d\n", i, items); + TEST_ASSERT_EQUAL_UINT32(i, items); + + unsigned entry = i + 1000; + queue_push_word_c_wrapper(&symbol_fifo, symbol_fifo_storage, entry); + dprintf("pushed: %u\n", entry); + + items = queue_items_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_UINT32(i + 1, items); + + dprintf("Post items: %d\n", items); + } + + unsigned counter = 0; + for(int i = USB_MIDI_DEVICE_OUT_FIFO_SIZE; i > 0; i--){ + int items = queue_items_c_wrapper(&symbol_fifo); + dprintf("i: %u items: %d\n", i, items); + TEST_ASSERT_EQUAL_UINT32(i, items); + + unsigned entry = queue_pop_word_c_wrapper(&symbol_fifo, symbol_fifo_storage); + unsigned expected = 1000 + counter; + + dprintf("expected: %u got: %d\n", expected, entry); + TEST_ASSERT_EQUAL_UINT32(expected, entry); + + counter++; + } } \ No newline at end of file diff --git a/tests/xua_unit_tests/src/xua_unit_test_helper.xc b/tests/xua_unit_tests/src/xua_unit_test_helper.xc index 611f95b7..cb7c321b 100644 --- a/tests/xua_unit_tests/src/xua_unit_test_helper.xc +++ b/tests/xua_unit_tests/src/xua_unit_test_helper.xc @@ -36,20 +36,20 @@ unsigned random(unsigned &x){ } ////////////////////// Wrappers for midi parse because C doesn't support return tuples -void midi_in_parse_wrap(void * unsafe mips, unsigned cable_number, unsigned char b, unsigned * unsafe valid, unsigned *unsafe packed){ +void midi_in_parse_c_wrapper(void * unsafe mips, unsigned cable_number, unsigned char b, unsigned * unsafe valid, unsigned *unsafe packed){ unsafe{ struct midi_in_parse_state * unsafe ptr = mips; {*valid, *packed} = midi_in_parse(*ptr, cable_number, b); } } -void midi_out_parse_wrap(unsigned tx_data, unsigned midi[3], unsigned * unsafe size){ +void midi_out_parse_c_wrapper(unsigned tx_data, unsigned midi[3], unsigned * unsafe size){ unsafe{ {midi[0], midi[1], midi[2], *size} = midi_out_parse(tx_data); } } -void reset_midi_state_wrap(void * unsafe mips){ +void reset_midi_state_c_wrapper(void * unsafe mips){ unsafe{ struct midi_in_parse_state * unsafe ptr = mips; reset_midi_state(*ptr); @@ -59,53 +59,57 @@ void reset_midi_state_wrap(void * unsafe mips){ /////////////////////// Wrappers for queue test -void queue_init_wrap(queue_t *q, unsigned size) { +void queue_init_c_wrapper(queue_t *q, unsigned size) { unsafe{ queue_init(*q, size); } } -int queue_is_empty_wrap(queue_t *unsafe q) { +int queue_is_empty_c_wrapper(queue_t *unsafe q) { unsafe{ return queue_is_empty(*q); } } -int queue_is_full_wrap(queue_t *unsafe q) { +int queue_is_full_c_wrapper(queue_t *unsafe q) { unsafe{ return queue_is_full(*q); } } -/* -inline void queue_push_word(queue_t &q, unsigned array[], unsigned data) -{ - assert(!queue_is_full(q)); - array[q.wrptr++ & q.mask] = data; +void queue_push_word_c_wrapper(queue_t *q, unsigned array[], unsigned data){ + unsafe{ + queue_push_word(*q, array, data); + } } -inline unsigned queue_pop_word(queue_t &q, unsigned array[]) { - assert(!queue_is_empty(q)); - return array[q.rdptr++ & q.mask]; +unsigned queue_pop_word_c_wrapper(queue_t *q, unsigned array[]){ + unsafe{ + return queue_pop_word(*q, array); + } } -inline void queue_push_byte(queue_t &q, unsigned char array[], unsigned data) -{ - assert(!queue_is_full(q)); - array[q.wrptr++ & q.mask] = data; +void queue_push_byte_c_wrapper(queue_t *q, unsigned char array[], unsigned data){ + unsafe{ + queue_push_byte(*q, array, data); + } } -inline unsigned queue_pop_byte(queue_t &q, unsigned char array[]) { - assert(!queue_is_empty(q)); - return array[q.rdptr++ & q.mask]; +unsigned queue_pop_byte_c_wrapper(queue_t *q, unsigned char array[]){ + unsafe{ + return queue_pop_byte(*q, array); + } } -inline unsigned queue_items(const queue_t &q) { - return q.wrptr - q.rdptr; +unsigned queue_items_c_wrapper(const queue_t *q){ + unsafe{ + return queue_items(*q); + } } -inline unsigned queue_space(const queue_t &q) { - return q.size - queue_items(q); +unsigned queue_space_c_wrapper(const queue_t *q){ + unsafe{ + return queue_space(*q); + } } -*/ \ No newline at end of file diff --git a/tests/xua_unit_tests/src/xua_unit_tests.h b/tests/xua_unit_tests/src/xua_unit_tests.h index 53cf0dcd..5deec2dc 100644 --- a/tests/xua_unit_tests/src/xua_unit_tests.h +++ b/tests/xua_unit_tests/src/xua_unit_tests.h @@ -8,15 +8,20 @@ #include "../../../lib_xua/src/midi/queue.h" #ifndef __XC__ -void midi_in_parse_wrap(void * mips, unsigned cable_number, unsigned char b, unsigned * valid, unsigned * packed); -void midi_out_parse_wrap(unsigned tx_data, unsigned midi[3], unsigned * size); -void reset_midi_state_wrap(void *mips); +void midi_in_parse_c_wrapper(void * mips, unsigned cable_number, unsigned char b, unsigned * valid, unsigned * packed); +void midi_out_parse_c_wrapper(unsigned tx_data, unsigned midi[3], unsigned * size); +void reset_midi_state_c_wrapper(void *mips); unsigned random(unsigned *x); -void queue_init_wrap(queue_t *q, unsigned size); -int queue_is_empty_wrap(const queue_t *q); -int queue_is_full_wrap(const queue_t *q); - +void queue_init_c_wrapper(queue_t *q, unsigned size); +int queue_is_empty_c_wrapper(const queue_t *q); +int queue_is_full_c_wrapper(const queue_t *q); +void queue_push_word_c_wrapper(queue_t *q, unsigned array[], unsigned data); +unsigned queue_pop_word_c_wrapper(queue_t *q, unsigned array[]); +void queue_push_byte_c_wrapper(queue_t *q, unsigned char array[], unsigned data); +unsigned queue_pop_byte_c_wrapper(queue_t *q, unsigned char array[]); +unsigned queue_items_c_wrapper(const queue_t *q); +unsigned queue_space_c_wrapper(const queue_t *q); #endif From 5822ec70370b350bdf0ffb5ad7a6c7877b964c20 Mon Sep 17 00:00:00 2001 From: Ed Date: Thu, 18 Apr 2024 15:31:09 +0100 Subject: [PATCH 14/40] Initial copy of lib_ic UT cmake --- tests/xua_unit_tests/CMakeLists.txt | 164 +++++++++++++--------------- 1 file changed, 74 insertions(+), 90 deletions(-) diff --git a/tests/xua_unit_tests/CMakeLists.txt b/tests/xua_unit_tests/CMakeLists.txt index 6bccf6d6..23b172f5 100644 --- a/tests/xua_unit_tests/CMakeLists.txt +++ b/tests/xua_unit_tests/CMakeLists.txt @@ -1,103 +1,87 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.21) -set(XMOS_TOOLS_PATH $ENV{XMOS_TOOL_PATH}/bin) +## App name +set( APP_NAME xua_unit_tests ) -#********************** -# Setup XMOS toolchain -#********************** -if(NOT DEFINED ENV{XUA_PATH}) - message(FATAL_ERROR "XUA_PATH environment variable not defined") - # some more commands +# Auto-generate schedule and top level config files + +if( NOT ${Python3_FOUND} ) + message(FATAL_ERROR "Python3 not found for running . ") 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() +#copy conftest.py in the build directory since pytest_collect_file only collects tests from the directory tree where conftest.py is present +configure_file( conftest.py conftest.py COPYONLY ) +## executable output directory +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) -## Define project -project(xua_unit_tests VERSION 0.1.0) +# Set unity runner generate script +set( GEN_RUNNER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_unity_runner.py ) -## Enable languages for project -enable_language(CXX XC C ASM) +# Create directory for runner files +set( RUNNERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/src.runners ) +file( MAKE_DIRECTORY ${RUNNERS_DIR} ) -message(STATUS "CAME HERE") -add_custom_target("runners" ALL) -add_custom_command( - TARGET runners - COMMAND python generate_unity_runners.py - COMMENT "generate unity runners" -) +file( GLOB TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c ) -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" - "-DHID_CONTROLS=1" - "-DUNITY_SUPPORT_64" - "-DUNITY_INCLUDE_DOUBLE" - ) - set_source_files_properties( - "runners/${ITEM_NAME}/${ITEM_NAME}_Runner.c" - PROPERTIES GENERATED TRUE +# For every source file in ic_unit_tests/src +foreach(testfile ${TEST_SOURCES}) + # Get test name + #cmake_path( GET testfile STEM TESTNAME ) + get_filename_component(TESTNAME ${testfile} NAME_WLE) + + # Create runner file directory + file( MAKE_DIRECTORY ${RUNNERS_DIR}/${TESTNAME} ) + + ######### + ## Create runner file + set( RUNNER_FILE ${RUNNERS_DIR}/${TESTNAME}/${TESTNAME}_Runner.c ) + set( GEN_RUNNER_SCRIPT_BYPRODUCTS ${RUNNER_FILE} ) + + unset(GEN_RUNNER_SCRIPT_ARGS) + list(APPEND GEN_RUNNER_SCRIPT_ARGS --project-root ${UNITY_PATH}/.. ) + list(APPEND GEN_RUNNER_SCRIPT_ARGS --source-file ${testfile} ) + list(APPEND GEN_RUNNER_SCRIPT_ARGS --runner-file ${RUNNER_FILE}) + + ## Add command to generate runner file + add_custom_command( + OUTPUT ${RUNNER_FILE} + COMMAND ${Python3_EXECUTABLE} ${GEN_RUNNER_SCRIPT} ${GEN_RUNNER_SCRIPT_ARGS} + COMMENT "Generating XUA Unit Test Runner" ) + + ######### + ## Add a build target + add_executable(xua_unit_${TESTNAME}) + + target_sources(xua_unit_${TESTNAME} + PRIVATE + ${testfile} + ${RUNNER_FILE}) + + target_include_directories(xua_unit_${TESTNAME} + PRIVATE + src + ${CMAKE_CURRENT_SOURCE_DIR}/../../../modules/lib_ic/src ) - 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)" - ) + # target_link_libraries(fwk_voice_${TESTNAME} + # PUBLIC + # fwk_voice::ic + # fwk_voice::test::shared::test_utils + # fwk_voice::test::shared::unity) - 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}) + if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) + target_compile_options(xua_unit_${TESTNAME} + PRIVATE + "-DUNITY_SUPPORT_64" + "-Wno-xcore-fptrgroup" + "-report" + "-DSPEEDUP_FACTOR=${TEST_SPEEDUP_FACTOR}") - 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() + target_link_options(xua_unit_${TESTNAME} + PRIVATE + "-target=${XCORE_TARGET}") + else() + target_link_libraries(xua_unit_${TESTNAME} m) + endif() +endforeach() \ No newline at end of file From fb6cdbb57beee51d47d16bbced1e875c9bad735c Mon Sep 17 00:00:00 2001 From: Ed Date: Thu, 18 Apr 2024 16:48:52 +0100 Subject: [PATCH 15/40] Nearly working xcommon cmake UT --- tests/xua_unit_tests/CMakeLists.txt | 68 ++++++++++++++--------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/xua_unit_tests/CMakeLists.txt b/tests/xua_unit_tests/CMakeLists.txt index 23b172f5..a457c644 100644 --- a/tests/xua_unit_tests/CMakeLists.txt +++ b/tests/xua_unit_tests/CMakeLists.txt @@ -1,8 +1,10 @@ cmake_minimum_required(VERSION 3.21) +include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake) ## App name set( APP_NAME xua_unit_tests ) + # Auto-generate schedule and top level config files if( NOT ${Python3_FOUND} ) @@ -22,16 +24,26 @@ set( GEN_RUNNER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_unity_runner.py ) set( RUNNERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/src.runners ) file( MAKE_DIRECTORY ${RUNNERS_DIR} ) -file( GLOB TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c ) +file( GLOB_RECURSE TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_*/*.c ) -# For every source file in ic_unit_tests/src +message(STATUS "HERE: ${TEST_SOURCES}") + + +# For every source file in xua_unit_tests/ foreach(testfile ${TEST_SOURCES}) + message(STATUS "Processing: ${testfile}") + # Get test name #cmake_path( GET testfile STEM TESTNAME ) get_filename_component(TESTNAME ${testfile} NAME_WLE) + + message(STATUS "Unit test name: ${TESTNAME}") + project(${TESTNAME}) + + # Create runner file directory - file( MAKE_DIRECTORY ${RUNNERS_DIR}/${TESTNAME} ) + file(MAKE_DIRECTORY ${RUNNERS_DIR}/${TESTNAME} ) ######### ## Create runner file @@ -49,39 +61,27 @@ foreach(testfile ${TEST_SOURCES}) COMMAND ${Python3_EXECUTABLE} ${GEN_RUNNER_SCRIPT} ${GEN_RUNNER_SCRIPT_ARGS} COMMENT "Generating XUA Unit Test Runner" ) - ######### - ## Add a build target - add_executable(xua_unit_${TESTNAME}) + ########################## + ## Do xcommon cmake build + ########################## - target_sources(xua_unit_${TESTNAME} - PRIVATE - ${testfile} - ${RUNNER_FILE}) + set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) - target_include_directories(xua_unit_${TESTNAME} - PRIVATE - src - ${CMAKE_CURRENT_SOURCE_DIR}/../../../modules/lib_ic/src - ) + set(APP_HW_TARGET XK-EVK-XU316) + set(APP_DEPENDENT_MODULES "lib_xua") + set(APP_PCA_ENABLE ON) + set(APP_COMPILER_FLAGS ${EXTRA_BUILD_FLAGS} -fcomment-asm + -Wall + -O3 + -report + -g + -fxscope + -DUSB_TILE=tile[0] + ) - # target_link_libraries(fwk_voice_${TESTNAME} - # PUBLIC - # fwk_voice::ic - # fwk_voice::test::shared::test_utils - # fwk_voice::test::shared::unity) + set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src + ${CMAKE_CURRENT_LIST_DIR}/../../../Unity/src) - if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) - target_compile_options(xua_unit_${TESTNAME} - PRIVATE - "-DUNITY_SUPPORT_64" - "-Wno-xcore-fptrgroup" - "-report" - "-DSPEEDUP_FACTOR=${TEST_SPEEDUP_FACTOR}") + XMOS_REGISTER_APP() - target_link_options(xua_unit_${TESTNAME} - PRIVATE - "-target=${XCORE_TARGET}") - else() - target_link_libraries(xua_unit_${TESTNAME} m) - endif() -endforeach() \ No newline at end of file +endforeach() From 785380779023f6fc2960e9beeb51e396d5e4cbf8 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 08:14:00 +0100 Subject: [PATCH 16/40] Working xcommon cmake unit test build --- tests/xua_unit_tests/CMakeLists.txt | 64 ++++---- .../test_midi_parse/hid_report_descriptor.h | 145 ------------------ .../test_midi_queue/hid_report_descriptor.h | 145 ------------------ 3 files changed, 36 insertions(+), 318 deletions(-) delete mode 100644 tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h delete mode 100644 tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h diff --git a/tests/xua_unit_tests/CMakeLists.txt b/tests/xua_unit_tests/CMakeLists.txt index a457c644..da0b80a9 100644 --- a/tests/xua_unit_tests/CMakeLists.txt +++ b/tests/xua_unit_tests/CMakeLists.txt @@ -1,12 +1,7 @@ cmake_minimum_required(VERSION 3.21) include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake) -## App name -set( APP_NAME xua_unit_tests ) - - # Auto-generate schedule and top level config files - if( NOT ${Python3_FOUND} ) message(FATAL_ERROR "Python3 not found for running . ") endif() @@ -24,35 +19,28 @@ set( GEN_RUNNER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_unity_runner.py ) set( RUNNERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/src.runners ) file( MAKE_DIRECTORY ${RUNNERS_DIR} ) +# Find unit test files file( GLOB_RECURSE TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_*/*.c ) -message(STATUS "HERE: ${TEST_SOURCES}") - - # For every source file in xua_unit_tests/ -foreach(testfile ${TEST_SOURCES}) - message(STATUS "Processing: ${testfile}") - - # Get test name - #cmake_path( GET testfile STEM TESTNAME ) - get_filename_component(TESTNAME ${testfile} NAME_WLE) - - message(STATUS "Unit test name: ${TESTNAME}") +foreach(TESTFILE ${TEST_SOURCES}) + # Get test name from C file stem + cmake_path(GET TESTFILE STEM TESTNAME) project(${TESTNAME}) + message(STATUS "Processing unit test: ${TESTNAME}") - - # Create runner file directory - file(MAKE_DIRECTORY ${RUNNERS_DIR}/${TESTNAME} ) + file(MAKE_DIRECTORY ${RUNNERS_DIR}/${TESTNAME}) - ######### + ##################### ## Create runner file + ##################### set( RUNNER_FILE ${RUNNERS_DIR}/${TESTNAME}/${TESTNAME}_Runner.c ) - set( GEN_RUNNER_SCRIPT_BYPRODUCTS ${RUNNER_FILE} ) + set( GEN_RUNNER_SCRIPT_BYPRODUCTS ${RUNNER_FILE}) unset(GEN_RUNNER_SCRIPT_ARGS) - list(APPEND GEN_RUNNER_SCRIPT_ARGS --project-root ${UNITY_PATH}/.. ) - list(APPEND GEN_RUNNER_SCRIPT_ARGS --source-file ${testfile} ) + list(APPEND GEN_RUNNER_SCRIPT_ARGS --project-root ${UNITY_PATH}/..) + list(APPEND GEN_RUNNER_SCRIPT_ARGS --source-file ${TESTFILE}) list(APPEND GEN_RUNNER_SCRIPT_ARGS --runner-file ${RUNNER_FILE}) ## Add command to generate runner file @@ -64,23 +52,43 @@ foreach(testfile ${TEST_SOURCES}) ########################## ## Do xcommon cmake build ########################## - set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) - set(APP_HW_TARGET XK-EVK-XU316) set(APP_DEPENDENT_MODULES "lib_xua") - set(APP_PCA_ENABLE ON) + # set(APP_PCA_ENABLE ON) set(APP_COMPILER_FLAGS ${EXTRA_BUILD_FLAGS} -fcomment-asm -Wall - -O3 + -O2 -report -g -fxscope -DUSB_TILE=tile[0] + -DUNITY_SUPPORT_64 + -DUNITY_INCLUDE_DOUBLE + -DXUD_CORE_CLOCK=600 + -DXUD_SERIES_SUPPORT=4 ) + # For HID tests only enable HID + if(${TESTFILE} MATCHES ".+hid.*") + list(APPEND APP_COMPILER_FLAGS "-DHID_CONTROLS=1") + endif() + + + # Workaround for xcommon cmake pre-pending CMAKE_CURRENT_LIST_DIR + string(REPLACE ${CMAKE_CURRENT_LIST_DIR} "" UNIT_TEST_SOURCE_RELATIVE ${TESTFILE}) + + set(APP_C_SRCS runners/${TESTNAME}/${TESTNAME}_Runner.c + ${UNIT_TEST_SOURCE_RELATIVE} + ../../../Unity/src/unity.c + ) + + + get_filename_component(TEST_FILE_DIR ${TESTFILE} DIRECTORY) set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src - ${CMAKE_CURRENT_LIST_DIR}/../../../Unity/src) + ${TEST_FILE_DIR} + ${XMOS_SANDBOX_DIR}/Unity/src + ${XMOS_SANDBOX_DIR}/lib_xud/lib_xud/src/user/class) XMOS_REGISTER_APP() diff --git a/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h b/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h deleted file mode 100644 index 3824814e..00000000 --- a/tests/xua_unit_tests/src/test_midi_parse/hid_report_descriptor.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2021-2024 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#ifndef __hid_report_descriptor_h__ -#define __hid_report_descriptor_h__ - -#include "xua_hid_report.h" - -/* - * Define non-configurable items in the HID Report descriptor. - * (These are short items as the location field isn't relevant for them) - */ -static const USB_HID_Short_Item_t hidCollectionApplication = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidCollectionEnd = { - .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), - .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidCollectionLogical = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), - .data = { 0x02, 0x00 } }; - -static const USB_HID_Short_Item_t hidInputConstArray = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidInputDataVar = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), - .data = { 0x02, 0x00 } }; - -static const USB_HID_Short_Item_t hidLogicalMaximum0 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), - .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMaximum1 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMinimum0 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), - .data = { 0x00, 0x00 } }; - -static const USB_HID_Short_Item_t hidReportCount1 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount6 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), - .data = { 0x06, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount7 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), - .data = { 0x07, 0x00 } }; -static const USB_HID_Short_Item_t hidReportSize1 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), - .data = { 0x01, 0x00 } }; - -static const USB_HID_Short_Item_t hidUsageConsumerControl = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .data = { 0x01, 0x00 } }; - -/* - * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report - * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. - */ -static const USB_HID_Report_Element_t hidReportPageConsumer = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), - .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, - .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) -}; - -/* - * Define configurable items in the HID Report descriptor. - */ -static USB_HID_Report_Element_t hidUsageByte0Bit0 = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .item.data = { 0xE2, 0x00 }, - .location = HID_REPORT_SET_LOC(0, 0, 0, 0) -}; // Mute - -static USB_HID_Report_Element_t hidUsageByte1Bit7 = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .item.data = { 0xEA, 0x00 }, - .location = HID_REPORT_SET_LOC(0, 0, 1, 7) -}; // Vol- -static USB_HID_Report_Element_t hidUsageByte1Bit0 = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .item.data = { 0xE9, 0x00 }, - .location = HID_REPORT_SET_LOC(0, 0, 1, 0) -}; // Vol+ - -/* - * List the configurable elements in the HID Report descriptor. - */ -static USB_HID_Report_Element_t* const hidConfigurableElements[] = { - &hidUsageByte0Bit0, - &hidUsageByte1Bit0, - &hidUsageByte1Bit7 -}; - -/* - * List HID Reports, one per Report ID. This should be a usage page item with the relevant - * If not using report IDs - still have one with report ID 0 - */ -static const USB_HID_Report_Element_t* const hidReports[] = { - &hidReportPageConsumer -}; - -/* - * List all items in the HID Report descriptor. - */ -static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { - &(hidReportPageConsumer.item), - &hidUsageConsumerControl, - &hidCollectionApplication, - &hidReportSize1, - &hidLogicalMinimum0, - &hidCollectionLogical, // Byte 0 - &hidLogicalMaximum1, - &hidReportCount1, - &(hidUsageByte0Bit0.item), - &hidInputDataVar, - &hidLogicalMaximum0, - &hidReportCount7, - &hidInputConstArray, - &hidCollectionEnd, - &hidCollectionLogical, // Byte 1 - &hidLogicalMaximum1, - &hidReportCount1, - &(hidUsageByte1Bit0.item), - &hidInputDataVar, - &hidLogicalMaximum0, - &hidReportCount6, - &hidInputConstArray, - &hidReportCount1, - &hidLogicalMaximum1, - &(hidUsageByte1Bit7.item), - &hidInputDataVar, - &hidCollectionEnd, - &hidCollectionEnd -}; - -/* - * Define the number of HID Reports - * Due to XC not supporting designated initializers, this constant has a hard-coded value. - * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) - */ -#define HID_REPORT_COUNT ( 1 ) - -#endif // __hid_report_descriptor_h__ diff --git a/tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h b/tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h deleted file mode 100644 index 3824814e..00000000 --- a/tests/xua_unit_tests/src/test_midi_queue/hid_report_descriptor.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2021-2024 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#ifndef __hid_report_descriptor_h__ -#define __hid_report_descriptor_h__ - -#include "xua_hid_report.h" - -/* - * Define non-configurable items in the HID Report descriptor. - * (These are short items as the location field isn't relevant for them) - */ -static const USB_HID_Short_Item_t hidCollectionApplication = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidCollectionEnd = { - .header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION), - .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidCollectionLogical = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION), - .data = { 0x02, 0x00 } }; - -static const USB_HID_Short_Item_t hidInputConstArray = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidInputDataVar = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT), - .data = { 0x02, 0x00 } }; - -static const USB_HID_Short_Item_t hidLogicalMaximum0 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), - .data = { 0x00, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMaximum1 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidLogicalMinimum0 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM), - .data = { 0x00, 0x00 } }; - -static const USB_HID_Short_Item_t hidReportCount1 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), - .data = { 0x01, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount6 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), - .data = { 0x06, 0x00 } }; -static const USB_HID_Short_Item_t hidReportCount7 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT), - .data = { 0x07, 0x00 } }; -static const USB_HID_Short_Item_t hidReportSize1 = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE), - .data = { 0x01, 0x00 } }; - -static const USB_HID_Short_Item_t hidUsageConsumerControl = { - .header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .data = { 0x01, 0x00 } }; - -/* - * Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report - * For internal purposes, a report element with ID of 0 must be included if report IDs are not being used. - */ -static const USB_HID_Report_Element_t hidReportPageConsumer = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE), - .item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 }, - .location = HID_REPORT_SET_LOC( 0, 2, 0, 0 ) -}; - -/* - * Define configurable items in the HID Report descriptor. - */ -static USB_HID_Report_Element_t hidUsageByte0Bit0 = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .item.data = { 0xE2, 0x00 }, - .location = HID_REPORT_SET_LOC(0, 0, 0, 0) -}; // Mute - -static USB_HID_Report_Element_t hidUsageByte1Bit7 = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .item.data = { 0xEA, 0x00 }, - .location = HID_REPORT_SET_LOC(0, 0, 1, 7) -}; // Vol- -static USB_HID_Report_Element_t hidUsageByte1Bit0 = { - .item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE), - .item.data = { 0xE9, 0x00 }, - .location = HID_REPORT_SET_LOC(0, 0, 1, 0) -}; // Vol+ - -/* - * List the configurable elements in the HID Report descriptor. - */ -static USB_HID_Report_Element_t* const hidConfigurableElements[] = { - &hidUsageByte0Bit0, - &hidUsageByte1Bit0, - &hidUsageByte1Bit7 -}; - -/* - * List HID Reports, one per Report ID. This should be a usage page item with the relevant - * If not using report IDs - still have one with report ID 0 - */ -static const USB_HID_Report_Element_t* const hidReports[] = { - &hidReportPageConsumer -}; - -/* - * List all items in the HID Report descriptor. - */ -static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = { - &(hidReportPageConsumer.item), - &hidUsageConsumerControl, - &hidCollectionApplication, - &hidReportSize1, - &hidLogicalMinimum0, - &hidCollectionLogical, // Byte 0 - &hidLogicalMaximum1, - &hidReportCount1, - &(hidUsageByte0Bit0.item), - &hidInputDataVar, - &hidLogicalMaximum0, - &hidReportCount7, - &hidInputConstArray, - &hidCollectionEnd, - &hidCollectionLogical, // Byte 1 - &hidLogicalMaximum1, - &hidReportCount1, - &(hidUsageByte1Bit0.item), - &hidInputDataVar, - &hidLogicalMaximum0, - &hidReportCount6, - &hidInputConstArray, - &hidReportCount1, - &hidLogicalMaximum1, - &(hidUsageByte1Bit7.item), - &hidInputDataVar, - &hidCollectionEnd, - &hidCollectionEnd -}; - -/* - * Define the number of HID Reports - * Due to XC not supporting designated initializers, this constant has a hard-coded value. - * It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* )) - */ -#define HID_REPORT_COUNT ( 1 ) - -#endif // __hid_report_descriptor_h__ From 82f764907908d7dc156503bef0a2c7c1e98f0ad0 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 08:32:16 +0100 Subject: [PATCH 17/40] Jenkins using xcommon cmake for UT --- Jenkinsfile | 9 +- tests/xua_unit_tests/wscript | 260 ----------------------------------- 2 files changed, 5 insertions(+), 264 deletions(-) delete mode 100644 tests/xua_unit_tests/wscript diff --git a/Jenkinsfile b/Jenkinsfile index d8a35ff7..31698573 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('xmos_jenkins_shared_library@v0.24.0') _ +@Library('xmos_jenkins_shared_library@v0.27.0') _ getApproval() @@ -49,9 +49,10 @@ pipeline { dir('tests') { dir('xua_unit_tests') { withVenv { - runWaf('.', "configure clean build --target=xcore200") - viewEnv() { - runPython("TARGET=XCORE200 pytest -s --junitxml=pytest_unity.xml") + withEnv(["XMOS_CMAKE_PATH=${WORKSPACE}/xcommon_cmake"]) { + sh "cmake -G 'Unix Makefiles' -B build" + sh 'xmake -C build -j' + runPython("pytest -s --junitxml=pytest_unity.xml") junit "pytest_unity.xml" } } diff --git a/tests/xua_unit_tests/wscript b/tests/xua_unit_tests/wscript deleted file mode 100644 index a31dbfaf..00000000 --- a/tests/xua_unit_tests/wscript +++ /dev/null @@ -1,260 +0,0 @@ -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): - print("unity_test_path: " + str(unity_test_path)) - generate_unity_runner(project_root_path, unity_test_path, - unity_runner_dir, unity_runner_suffix) - runner_build_flags = '' # Could extract flags from the test name - 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. - """ - file_list = [] - for root, dirs, files in os.walk(unity_test_dir): - for f in files: - if f.startswith(unity_test_prefix): - file_list.append(os.path.join(root,f)) - return file_list - - -def find_unity_tests(unity_test_dir, unity_test_prefix): - """ - 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): {"language": get_file_type(path), "dir": os.path.dirname(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, params in configs.items(): - print(f"test_name {test_name}, test_language {params['language']}") - for ctx in (BuildContext, CleanContext): - raw_context = ctx.__name__.replace('Context', '').lower() - - class tmp(ctx): - cmd = raw_context + '_' + test_name + '_' + trgt - variant = test_name + '_' + trgt - #cmd = raw_context + '_' + test_name - #variant = test_name - language = params["language"] - target = trgt - runner = test_name - directory = params["dir"] - 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) - -print("UNITY_TESTS: " + str(UNITY_TESTS)) - -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', bld.directory, 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', - bld.directory, - '../../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', - '-DHID_CONTROLS=1', - '-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') From aecffab0c60a4cd0fcc5175f132546456a6240a4 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 09:48:25 +0100 Subject: [PATCH 18/40] Add tools for UT --- Jenkinsfile | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 31698573..3a9c7b4c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,6 +11,12 @@ pipeline { options { skipDefaultCheckout() } + environment { + REPO = 'sw_usb_audio' + VIEW = getViewName(REPO) + TOOLS_VERSION = "15.2.1" + XTAGCTL_VERSION = "v2.0.0" + } stages { stage('Basic tests') { agent { @@ -45,16 +51,14 @@ pipeline { } stage('Unity tests') { steps { - dir("${REPO}") { - dir('tests') { - dir('xua_unit_tests') { - withVenv { - withEnv(["XMOS_CMAKE_PATH=${WORKSPACE}/xcommon_cmake"]) { - sh "cmake -G 'Unix Makefiles' -B build" - sh 'xmake -C build -j' - runPython("pytest -s --junitxml=pytest_unity.xml") - junit "pytest_unity.xml" - } + dir("${REPO}/test/xua_unit_tests") { + withTools("${env.TOOLS_VERSION}") { + withVenv { + withEnv(["XMOS_CMAKE_PATH=${WORKSPACE}/xcommon_cmake"]) { + sh "cmake -G 'Unix Makefiles' -B build" + sh 'xmake -C build -j' + runPython("pytest -s --junitxml=pytest_unity.xml") + junit "pytest_unity.xml" } } } From e5fb428880729846918978fe1480a084e151721c Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 09:50:42 +0100 Subject: [PATCH 19/40] Jenkinsfile fix --- Jenkinsfile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3a9c7b4c..6fc52752 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,16 +7,11 @@ pipeline { environment { REPO = 'lib_xua' VIEW = getViewName(REPO) + TOOLS_VERSION = "15.2.1" // For unit tests } options { skipDefaultCheckout() } - environment { - REPO = 'sw_usb_audio' - VIEW = getViewName(REPO) - TOOLS_VERSION = "15.2.1" - XTAGCTL_VERSION = "v2.0.0" - } stages { stage('Basic tests') { agent { From 5f4aa1f7a26b586d792526b760c6c849ff818e7f Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 09:54:38 +0100 Subject: [PATCH 20/40] Typo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6fc52752..6615467d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -46,7 +46,7 @@ pipeline { } stage('Unity tests') { steps { - dir("${REPO}/test/xua_unit_tests") { + dir("${REPO}/tests/xua_unit_tests") { withTools("${env.TOOLS_VERSION}") { withVenv { withEnv(["XMOS_CMAKE_PATH=${WORKSPACE}/xcommon_cmake"]) { From 25cd5ffafca18e7c12b9418622da77d8e6f8fafa Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 10:34:56 +0100 Subject: [PATCH 21/40] Rejig runner gen --- .gitignore | 1 + tests/xua_unit_tests/CMakeLists.txt | 20 +-- tests/xua_unit_tests/conftest.py | 4 +- tests/xua_unit_tests/generate_unity_runner.py | 59 ++++++++ .../xua_unit_tests/generate_unity_runners.py | 134 ------------------ 5 files changed, 73 insertions(+), 145 deletions(-) create mode 100755 tests/xua_unit_tests/generate_unity_runner.py delete mode 100644 tests/xua_unit_tests/generate_unity_runners.py diff --git a/.gitignore b/.gitignore index 29cab6ac..4ca12179 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ host_usb_mixer_control/xmos_mixer midi_tx_cmds.txt midi_rx_cmds.txt trace.txt +tests/xua_unit_tests/src.runners diff --git a/tests/xua_unit_tests/CMakeLists.txt b/tests/xua_unit_tests/CMakeLists.txt index da0b80a9..f8b0ad6d 100644 --- a/tests/xua_unit_tests/CMakeLists.txt +++ b/tests/xua_unit_tests/CMakeLists.txt @@ -13,17 +13,19 @@ configure_file( conftest.py conftest.py COPYONLY ) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) # Set unity runner generate script -set( GEN_RUNNER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_unity_runner.py ) +set(GEN_RUNNER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_unity_runner.py) # Create directory for runner files -set( RUNNERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/src.runners ) -file( MAKE_DIRECTORY ${RUNNERS_DIR} ) +set(RUNNERS_DIR ${CMAKE_CURRENT_LIST_DIR}/src.runners ) +file(MAKE_DIRECTORY ${RUNNERS_DIR} ) # Find unit test files -file( GLOB_RECURSE TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_*/*.c ) +file(GLOB_RECURSE TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_*/*.c) # For every source file in xua_unit_tests/ foreach(TESTFILE ${TEST_SOURCES}) + set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) + # Get test name from C file stem cmake_path(GET TESTFILE STEM TESTNAME) project(${TESTNAME}) @@ -39,20 +41,19 @@ foreach(TESTFILE ${TEST_SOURCES}) set( GEN_RUNNER_SCRIPT_BYPRODUCTS ${RUNNER_FILE}) unset(GEN_RUNNER_SCRIPT_ARGS) - list(APPEND GEN_RUNNER_SCRIPT_ARGS --project-root ${UNITY_PATH}/..) + list(APPEND GEN_RUNNER_SCRIPT_ARGS --project-root ${XMOS_SANDBOX_DIR}) list(APPEND GEN_RUNNER_SCRIPT_ARGS --source-file ${TESTFILE}) list(APPEND GEN_RUNNER_SCRIPT_ARGS --runner-file ${RUNNER_FILE}) ## Add command to generate runner file add_custom_command( OUTPUT ${RUNNER_FILE} - COMMAND ${Python3_EXECUTABLE} ${GEN_RUNNER_SCRIPT} ${GEN_RUNNER_SCRIPT_ARGS} - COMMENT "Generating XUA Unit Test Runner" ) + COMMAND python ${GEN_RUNNER_SCRIPT} ${GEN_RUNNER_SCRIPT_ARGS} + COMMENT "Generate XUA Unit Test Runner" ) ########################## ## Do xcommon cmake build ########################## - set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) set(APP_HW_TARGET XK-EVK-XU316) set(APP_DEPENDENT_MODULES "lib_xua") # set(APP_PCA_ENABLE ON) @@ -77,8 +78,9 @@ foreach(TESTFILE ${TEST_SOURCES}) # Workaround for xcommon cmake pre-pending CMAKE_CURRENT_LIST_DIR string(REPLACE ${CMAKE_CURRENT_LIST_DIR} "" UNIT_TEST_SOURCE_RELATIVE ${TESTFILE}) + string(REPLACE ${CMAKE_CURRENT_LIST_DIR} "" RUNNER_FILE_RELATIVE ${RUNNER_FILE}) - set(APP_C_SRCS runners/${TESTNAME}/${TESTNAME}_Runner.c + set(APP_C_SRCS ${RUNNER_FILE_RELATIVE} ${UNIT_TEST_SOURCE_RELATIVE} ../../../Unity/src/unity.c ) diff --git a/tests/xua_unit_tests/conftest.py b/tests/xua_unit_tests/conftest.py index 2128a9b7..b25f534f 100644 --- a/tests/xua_unit_tests/conftest.py +++ b/tests/xua_unit_tests/conftest.py @@ -1,4 +1,4 @@ -# Copyright 2021-2022 XMOS LIMITED. +# Copyright 2021-2024 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 @@ -28,7 +28,7 @@ class UnityTestSource(pytest.File): # 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.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" diff --git a/tests/xua_unit_tests/generate_unity_runner.py b/tests/xua_unit_tests/generate_unity_runner.py new file mode 100755 index 00000000..7d8dfef1 --- /dev/null +++ b/tests/xua_unit_tests/generate_unity_runner.py @@ -0,0 +1,59 @@ +# Copyright 2024 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 +import argparse + +def parse_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument("--project-root", nargs='?', help="Project root directory") + parser.add_argument("--source-file", nargs='?', help="source file.") + parser.add_argument("--runner-file", nargs='?', help="runner file.") + args = parser.parse_args() + return args + +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 + +if __name__ == "__main__": + args = parse_arguments() + print(f"in python: root {args.project_root}, source {args.source_file}, runner {args.runner_file}") + + try: + subprocess.check_call([get_ruby(), + get_unity_runner_generator(args.project_root), + args.source_file, + args.runner_file]) + 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 diff --git a/tests/xua_unit_tests/generate_unity_runners.py b/tests/xua_unit_tests/generate_unity_runners.py deleted file mode 100644 index 7276d969..00000000 --- a/tests/xua_unit_tests/generate_unity_runners.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2021-2022 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() From 9a8dfea641c231dc6b406f196f71b1449c316906 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 10:42:23 +0100 Subject: [PATCH 22/40] xrun -> xsim --- tests/xua_unit_tests/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/xua_unit_tests/conftest.py b/tests/xua_unit_tests/conftest.py index b25f534f..bac3e416 100644 --- a/tests/xua_unit_tests/conftest.py +++ b/tests/xua_unit_tests/conftest.py @@ -51,9 +51,9 @@ class UnityTestExecutable(pytest.Item): 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) + print("run xsim for executable ", self.name) test_output = subprocess.check_output( - ["xrun", "--io", "--id", "0", self.name], + ["xsim", self.name], text=True, stderr=subprocess.STDOUT, ) From 8a991dd6380ef659343ad37aa20d6df959c7c768 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 10:57:49 +0100 Subject: [PATCH 23/40] Debug copy_tree error --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6615467d..79266956 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -40,8 +40,8 @@ pipeline { } } } - // Temp debug - archiveArtifacts artifacts: "${REPO}/**/*.pdf", fingerprint: true, allowEmptyArchive: true + // Temp debug used by test_tx + archiveArtifacts artifacts: "${REPO}/tests/*.txt", fingerprint: true, allowEmptyArchive: true } } stage('Unity tests') { From 76ab4060d5343673ced0a8e4fd59f274f078ffda Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 11:21:18 +0100 Subject: [PATCH 24/40] try again to archive --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 79266956..5da7ce8e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -41,7 +41,7 @@ pipeline { } } // Temp debug used by test_tx - archiveArtifacts artifacts: "${REPO}/tests/*.txt", fingerprint: true, allowEmptyArchive: true + archiveArtifacts artifacts: "${REPO}/**/*.txt", fingerprint: true, allowEmptyArchive: true } } stage('Unity tests') { From bbd0f2693d7fe61331f0bda30ccb86b922ff1d66 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 11:21:41 +0100 Subject: [PATCH 25/40] try again to archive #2 --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 5da7ce8e..00320dc7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -40,8 +40,6 @@ pipeline { } } } - // Temp debug used by test_tx - archiveArtifacts artifacts: "${REPO}/**/*.txt", fingerprint: true, allowEmptyArchive: true } } stage('Unity tests') { @@ -77,6 +75,8 @@ pipeline { } post { cleanup { + // Temp debug used by test_tx + archiveArtifacts artifacts: "${REPO}/**/*.txt", fingerprint: true, allowEmptyArchive: true xcoreCleanSandbox() } } From ca3a7eb1f9abb9f63cc3783fe02b0937bfa08d4e Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 12:01:58 +0100 Subject: [PATCH 26/40] More efficient midi test bin build --- tests/conftest.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index b1973ed1..5af8bac1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ import time import Pyxsim from pathlib import Path from midi_test_helpers import MIDI_TEST_CONFIGS +import subprocess @pytest.fixture() def test_file(request): @@ -42,17 +43,11 @@ def pytest_addoption(parser): def options(request): yield request.config.option -# We use the same binary multiple times so just build once +# We use the same binary multiple times so just build once for all MIDI tests @pytest.fixture(scope="session") def build_midi(): - all_build_success = True - for config in MIDI_TEST_CONFIGS: - xe = str(Path(__file__).parent / f"test_midi/bin/{config}/test_midi_{config}.xe") + cmd = "xmake -C test_midi -j" + result = subprocess.run(cmd, capture_output=True, text=True, shell=True) + all_build_success = result.returncode - success, output = Pyxsim._build(xe, build_options=["-j"]) - all_build_success |= success - - if not all_build_success: - print(f"ERROR MIDI Build failed: {output}") - - return str(Path(__file__).parent / f"test_midi/bin/") if all_build_success else False + return str(Path(__file__).parent / f"test_midi/bin/") if all_build_success == 0 else False From 7fbf400ded9158e46fe26ef9190436669117d373 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 12:03:26 +0100 Subject: [PATCH 27/40] Debug fix --- tests/test_midi_tx.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index ff2f71ac..47915189 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -19,8 +19,9 @@ MAX_CYCLES = 15000000 def test_tx(capfd, config, build_midi): with open("dir.txt", "wt") as db: - import subprocess, shutil - output = subprocess.run("tree", capture_output=True, text=True) + import subprocess + output = subprocess.run("tree", capture_output=True, text=True, shell=True) + db.write(output.stdout) # Need tempdir as we use the same config files and this causes issues when using xdist with tempdir() as tmpdirname: From 1848209a6338b4c42309926cfad0f3f2dbb0b24c Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 12:32:37 +0100 Subject: [PATCH 28/40] run only midi tests --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 00320dc7..c5ecc0ec 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,7 +36,8 @@ pipeline { dir("${REPO}/tests"){ viewEnv(){ withVenv{ - runPytest('--numprocesses=4') + // runPytest('--numprocesses=4') + runPytest('-k "midi" -s') } } } From d55ade4ecfd3cd9b58bc58c722beb9121da069f2 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 12:40:46 +0100 Subject: [PATCH 29/40] Debug midi build --- tests/conftest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 5af8bac1..ba8b0a74 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -50,4 +50,7 @@ def build_midi(): result = subprocess.run(cmd, capture_output=True, text=True, shell=True) all_build_success = result.returncode + with open("midi_build.txt", "wt") as mb: + mb.write(str(result)) + return str(Path(__file__).parent / f"test_midi/bin/") if all_build_success == 0 else False From d02561da19c587e32deaa79cc7870977d33f9f86 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 14:15:14 +0100 Subject: [PATCH 30/40] Add missing makefile --- tests/test_midi/Makefile | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/test_midi/Makefile diff --git a/tests/test_midi/Makefile b/tests/test_midi/Makefile new file mode 100644 index 00000000..ddc2011f --- /dev/null +++ b/tests/test_midi/Makefile @@ -0,0 +1,40 @@ +# The TARGET variable determines what target system the application is +# compiled for. It either refers to an XN file in the source directories +# or a valid argument for the --target option when compiling. + +ifeq ($(CONFIG), xs2) + TARGET = XCORE-200-EXPLORER +endif +ifeq ($(CONFIG), xs3) + TARGET = XCORE-AI-EXPLORER +else + TARGET = XCORE-AI-EXPLORER +endif + +# The APP_NAME variable determines the name of the final .xe file. It should +# not include the .xe postfix. If left blank the name will default to +# the project name + +APP_NAME = + +# The flags passed to xcc when building the application +# You can also set the following to override flags for a particular language: +# +# XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS +# +# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to +# xcc for the final link (mapping) stage. +XCC_FLAGS_xs2 = $(EXTRA_BUILD_FLAGS) -O2 -g +XCC_FLAGS_xs3 = $(EXTRA_BUILD_FLAGS) -O2 -g +XCC_FLAGS_LOOPBACK = $(EXTRA_BUILD_FLAGS) -O2 -g -DMIDI_LOOPBACK=1 + +# The USED_MODULES variable lists other module used by the application. +USED_MODULES = lib_xua + + +#============================================================================= +# The following part of the Makefile includes the common build infrastructure +# for compiling XMOS applications. You should not need to edit below here. + +XMOS_MAKE_PATH ?= ../.. +include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common \ No newline at end of file From 365e9bf01457fc0ef397a25c2c7532a24af992c4 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 14:18:49 +0100 Subject: [PATCH 31/40] Tidy debug --- Jenkinsfile | 5 +---- tests/conftest.py | 6 +++--- tests/test_midi_tx.py | 5 ----- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c5ecc0ec..31b66517 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,8 +36,7 @@ pipeline { dir("${REPO}/tests"){ viewEnv(){ withVenv{ - // runPytest('--numprocesses=4') - runPytest('-k "midi" -s') + runPytest('--numprocesses=4') } } } @@ -76,8 +75,6 @@ pipeline { } post { cleanup { - // Temp debug used by test_tx - archiveArtifacts artifacts: "${REPO}/**/*.txt", fingerprint: true, allowEmptyArchive: true xcoreCleanSandbox() } } diff --git a/tests/conftest.py b/tests/conftest.py index ba8b0a74..58787c57 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -50,7 +50,7 @@ def build_midi(): result = subprocess.run(cmd, capture_output=True, text=True, shell=True) all_build_success = result.returncode - with open("midi_build.txt", "wt") as mb: - mb.write(str(result)) + assert all_build_success == 0, f"{result.stderr}\n{result.stdout}" + + return str(Path(__file__).parent / f"test_midi/bin/") - return str(Path(__file__).parent / f"test_midi/bin/") if all_build_success == 0 else False diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index 47915189..605bfba1 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -18,11 +18,6 @@ MAX_CYCLES = 15000000 @pytest.mark.parametrize("config", MIDI_TEST_CONFIGS) def test_tx(capfd, config, build_midi): - with open("dir.txt", "wt") as db: - import subprocess - output = subprocess.run("tree", capture_output=True, text=True, shell=True) - db.write(output.stdout) - # Need tempdir as we use the same config files and this causes issues when using xdist with tempdir() as tmpdirname: copy_tree(build_midi, tmpdirname) From bee1d878af7a04c9854ee0d5c6b76ccc33cce477 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 16:35:32 +0100 Subject: [PATCH 32/40] Add MIDI loopback test and fix app_midi_simple Tx --- tests/test_midi/src/app_midi_simple.xc | 18 +++++--- tests/test_midi_loopback.py | 60 ++++++++++++++++++++++++++ tests/test_midi_rx.py | 19 +++----- tests/test_midi_tx.py | 13 ++---- 4 files changed, 81 insertions(+), 29 deletions(-) create mode 100644 tests/test_midi_loopback.py diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index eecae28b..2dbca5e5 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -36,7 +36,7 @@ on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; #define TEST_COMMAND_FILE_TX "midi_tx_cmds.txt" #define TEST_COMMAND_FILE_RX "midi_rx_cmds.txt" -#define DEBUG 0 +#define DEBUG 0 // Prints for debugging. Turn off for actual test #if DEBUG #define dprintf(...) printf(__VA_ARGS__) @@ -58,6 +58,7 @@ unsigned mini_in_parse_helper(unsigned midi[3]){ unsigned packed = 0; for(int i = 0; i < 3; i++){ + dprintf("Packing byte %d 0x%x\n", i, midi[i]); {valid, packed} = midi_in_parse(m_state, CABLE_NUM, midi[i]); if(valid){ return packed; @@ -122,10 +123,14 @@ void test(chanend c_midi){ timer tmr; - int t_tx; + int t_tx; // Used for delay between Txs + int tx_end; // Used to wait for packet to have fully left tmr :> t_tx; + tmr :> tx_end; const int max_tx_time = XS1_TIMER_HZ / 31250 * 3 * (8 + 1 + 1); // 30 bits at 31.25 kbps is 0.96ms + const int tx_interval = XS1_TIMER_HZ / 8000; // SoF rate on HS + tx_end += max_tx_time; // One whole packet while(tx_cmd_count < num_to_tx || rx_cmd_count < num_to_rx ){ select{ @@ -137,9 +142,10 @@ void test(chanend c_midi){ unsigned midi_data[3] = {0}; unsigned byte_count = 0; {midi_data[0], midi_data[1], midi_data[2], byte_count} = midi_out_parse(byterev(rx_packet)); - // Note this needs to always print for capff to pick it up + // Note this needs to always print for capfd in pytest to pick it up printf("dut_midi_rx: %u %u %u\n", midi_data[0], midi_data[1], midi_data[2]); rx_cmd_count++; + midi_send_ack(c_midi); } break; @@ -148,15 +154,15 @@ void test(chanend c_midi){ unsigned tx_packet = mini_in_parse_helper(midi); outuint(c_midi, byterev(tx_packet)); dprintf("Sent packet to midi: %u %u %u\n", commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]); - t_tx += max_tx_time; + t_tx += tx_interval; + tx_end += max_tx_time; break; } } dprintf("Tx and Rx count met - exiting after last tx complete.\n"); - tmr when timerafter(t_tx) :> int _; // wait until packet definitely departed + tmr when timerafter(tx_end) :> int _; // wait until packet definitely departed - delay_ticks(max_tx_time / 4); // Allow a few more bit times about to allow TXChecker to do it's thing exit(0); } diff --git a/tests/test_midi_loopback.py b/tests/test_midi_loopback.py new file mode 100644 index 00000000..4a21a753 --- /dev/null +++ b/tests/test_midi_loopback.py @@ -0,0 +1,60 @@ +# Copyright 2014-2024 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. + +import pytest +import Pyxsim +from Pyxsim import testers +from pathlib import Path +from uart_rx_checker import UARTRxChecker +from midi_test_helpers import midi_expect_rx, create_midi_rx_file, create_midi_tx_file, tempdir, MIDI_RATE +from distutils.dir_util import copy_tree # we're using python 3.7 and dirs_exist_ok=True isn't available until 3.8 :( + +MAX_CYCLES = 15000000 + + +##### +# This test takes the built binary, copies it to a tmp dir and runs the midi loopback test which sends some commands +# the firmware receives them, prints and compares with the expected output +##### +def test_midi_loopback(capfd, build_midi): + # Need tempdir as we use the same config files and this causes issues when using xdist + with tempdir() as tmpdirname: + config = "LOOPBACK" + copy_tree(build_midi, tmpdirname) + xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe") + + midi_commands = [ + [0x90, 60, 81], #note on + [0xc0, 15], #instr select + [0xe0, 0, 96], #pitch bend + [0xff], #MIDI reset + [0x80, 60, 81], #note off + ] + create_midi_rx_file(len(midi_commands)) + create_midi_tx_file(midi_commands) + + expected = midi_expect_rx().expect(midi_commands) + tester = testers.ComparisonTester(expected, ordered = True) + + simthreads = [] + + simargs = ["--max-cycles", str(MAX_CYCLES)] + #This is just for local debug so we can capture the traces if needed. It slows xsim down so not needed + # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) + + Pyxsim.run_with_pyxsim( + xe, + simthreads=simthreads, + timeout=120, + simargs=simargs, + ) + capture = capfd.readouterr().out + result = tester.run(capture.split("\n")) + + # Print to console + # with capfd.disabled(): + # print("++++", capture, "++++") + # print("----", expected, "----") + + + assert result \ No newline at end of file diff --git a/tests/test_midi_rx.py b/tests/test_midi_rx.py index aa9fc05d..37b7ece1 100644 --- a/tests/test_midi_rx.py +++ b/tests/test_midi_rx.py @@ -24,12 +24,11 @@ def test_rx(capfd, config, build_midi): xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe") midi_commands = [[0x90, 60, 81]] - create_midi_rx_file(1) + create_midi_rx_file(len(midi_commands)) create_midi_tx_file() expected = midi_expect_rx().expect(midi_commands) - tester = testers.ComparisonTester(midi_expect_rx().expect(midi_commands), - ordered = True) + tester = testers.ComparisonTester(expected, ordered = True) rx_port = "tile[1]:XS1_PORT_1F" tx_port = "tile[1]:XS1_PORT_4C" # Needed so that UARTRxChecker (a transmitter) knows when to start @@ -46,20 +45,14 @@ def test_rx(capfd, config, build_midi): ] simargs = ["--max-cycles", str(MAX_CYCLES)] - #This is just for local debug so we can capture the traces if needed. It slows xsim down so not needed + #This is just for local debug so we can capture the traces if needed. It slows xsim down so not good for Jenkins # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) - - # Print to console - # with capfd.disabled(): - # print("++++", expected, "++++") - # print("****", capture, "****") - # print("****", capture.split("\n"), "****") - # print(xe) - + + # with capfd.disabled(): # use to see xsim and tester output Pyxsim.run_with_pyxsim( xe, simthreads=simthreads, - timeout=1200, + timeout=120, simargs=simargs, ) capture = capfd.readouterr().out diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index 605bfba1..bbf41bbb 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -28,8 +28,7 @@ def test_tx(capfd, config, build_midi): create_midi_rx_file() expected = midi_expect_tx().expect(midi_commands) - tester = testers.ComparisonTester( expected, - ordered = True) + tester = testers.ComparisonTester(expected, ordered = True) tx_port = "tile[1]:XS1_PORT_4C" baud = MIDI_RATE @@ -47,20 +46,14 @@ def test_tx(capfd, config, build_midi): #This is just for local debug so we can capture the traces if needed. It slows xsim down so not needed # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) + # with capfd.disabled(): # use to see xsim and tester output Pyxsim.run_with_pyxsim( xe, simthreads=simthreads, - timeout=1200, + timeout=120, simargs=simargs, ) capture = capfd.readouterr().out result = tester.run(capture.split("\n")) - # Print to console - # with capfd.disabled(): - # print("++++", expected, "++++") - # print("****", capture, "****") - # print("****", capture.split("\n"), "****") - # print(xe) - assert result \ No newline at end of file From cd497a0c788589a25d00cd686706a2e199310386 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 16:59:40 +0100 Subject: [PATCH 33/40] Add debug on fail and lengthen unit tests --- tests/test_midi_rx.py | 2 +- tests/test_midi_tx.py | 2 +- tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_midi_rx.py b/tests/test_midi_rx.py index 37b7ece1..1997dd73 100644 --- a/tests/test_midi_rx.py +++ b/tests/test_midi_rx.py @@ -58,4 +58,4 @@ def test_rx(capfd, config, build_midi): capture = capfd.readouterr().out result = tester.run(capture.split("\n")) - assert result \ No newline at end of file + assert result, f"expected: {expected}\n capture: {capture}" \ No newline at end of file diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index bbf41bbb..ade525d6 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -56,4 +56,4 @@ def test_tx(capfd, config, build_midi): capture = capfd.readouterr().out result = tester.run(capture.split("\n")) - assert result \ No newline at end of file + assert result, f"expected: {expected}\n capture: {capture}" \ No newline at end of file diff --git a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c index e99e8115..39c74cec 100644 --- a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c +++ b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c @@ -19,7 +19,7 @@ #define DATA_RANGE 128 #define DATA_MASK (DATA_RANGE - 1) -#define NUM_TESTS_PER_TEST 10 +#define NUM_TESTS_PER_TEST 30 #define CABLE_NUM 2 #define RANDOM_SEED 6031769 From ba0f07d355d8cce10f576caa512609a446a91f09 Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 17:10:30 +0100 Subject: [PATCH 34/40] Speedup pytest --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 31b66517..e063b361 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,7 +36,7 @@ pipeline { dir("${REPO}/tests"){ viewEnv(){ withVenv{ - runPytest('--numprocesses=4') + runPytest('--numprocesses=auto -vvv') } } } From 8a90660f7c444cba3608d03000ee49175819eada Mon Sep 17 00:00:00 2001 From: Ed Date: Fri, 19 Apr 2024 17:24:29 +0100 Subject: [PATCH 35/40] Take build of pytest and do in Jenkins --- Jenkinsfile | 1 + tests/conftest.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e063b361..5ab20179 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,6 +36,7 @@ pipeline { dir("${REPO}/tests"){ viewEnv(){ withVenv{ + sh "xmake -C test_midi -j" // Xdist does not like building so do here runPytest('--numprocesses=auto -vvv') } } diff --git a/tests/conftest.py b/tests/conftest.py index 58787c57..f0845cc9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,10 +47,11 @@ def options(request): @pytest.fixture(scope="session") def build_midi(): cmd = "xmake -C test_midi -j" - result = subprocess.run(cmd, capture_output=True, text=True, shell=True) - all_build_success = result.returncode + # result = subprocess.run(cmd, capture_output=True, text=True, shell=True) + # return_code = result.returncode + return_code = 0 - assert all_build_success == 0, f"{result.stderr}\n{result.stdout}" + assert return_code == 0, f"{result.stderr}\n{result.stdout}" return str(Path(__file__).parent / f"test_midi/bin/") From e83bbf51cfa16e8cb31e3f1808e447a5c3a9b7fb Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 24 Apr 2024 12:01:52 +0100 Subject: [PATCH 36/40] Review feedback --- tests/test_midi/Makefile | 5 +- tests/test_midi/src/app_midi_simple.xc | 8 +-- tests/test_midi/src/hwsupport.xc | 54 ++++++++++++------- tests/xua_unit_tests/CMakeLists.txt | 5 +- .../src/test_midi_parse/test_midi_parse.c | 16 +++--- 5 files changed, 49 insertions(+), 39 deletions(-) diff --git a/tests/test_midi/Makefile b/tests/test_midi/Makefile index ddc2011f..66ef5e05 100644 --- a/tests/test_midi/Makefile +++ b/tests/test_midi/Makefile @@ -4,11 +4,8 @@ ifeq ($(CONFIG), xs2) TARGET = XCORE-200-EXPLORER -endif -ifeq ($(CONFIG), xs3) - TARGET = XCORE-AI-EXPLORER else - TARGET = XCORE-AI-EXPLORER + TARGET = XCORE-AI-EXPLORER #for xs3 and also loopback test endif # The APP_NAME variable determines the name of the final .xe file. It should diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index 2dbca5e5..ac4bc7df 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -45,12 +45,12 @@ on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; #endif /* See hwsupport.xc */ -void ctrlPort(); +void board_setup(); #define CABLE_NUM 0 -unsigned mini_in_parse_helper(unsigned midi[3]){ +unsigned midi_in_parse_helper(unsigned midi[3]){ struct midi_in_parse_state m_state; reset_midi_state(m_state); @@ -151,7 +151,7 @@ void test(chanend c_midi){ case tx_cmd_count < num_to_tx => tmr when timerafter(t_tx) :> int _: unsigned midi[] = {commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]}; - unsigned tx_packet = mini_in_parse_helper(midi); + unsigned tx_packet = midi_in_parse_helper(midi); outuint(c_midi, byterev(tx_packet)); dprintf("Sent packet to midi: %u %u %u\n", commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]); t_tx += tx_interval; @@ -177,7 +177,7 @@ int main(void) on tile[1]: usb_midi(p_midi_rx, p_midi_tx, clk_midi, c_midi, 0); // Setup HW so we can run this on the MC board - on tile[0]: ctrlPort(); + on tile[0]: board_setup(); } return 0; diff --git a/tests/test_midi/src/hwsupport.xc b/tests/test_midi/src/hwsupport.xc index 2b722c75..697f6e58 100644 --- a/tests/test_midi/src/hwsupport.xc +++ b/tests/test_midi/src/hwsupport.xc @@ -5,30 +5,44 @@ #include "xua.h" -on tile[0]: out port p_ctrl = XS1_PORT_8D; +out port p_ctrl = PORT_CTRL; /* p_ctrl: + * [0:3] - Unused + * [4] - EN_3v3_N (1v0 hardware only) + * [5] - EN_3v3A + * [6] - EXT_PLL_SEL (CS2100:0, SI: 1) + * [7] - MCLK_DIR (Out:0, In: 1) + */ -/* p_ctrl: - * [0:3] - Unused - * [4] - EN_3v3_N - * [5] - EN_3v3A - * [6] - EXT_PLL_SEL (CS2100:0, SI: 1) - * [7] - MCLK_DIR (Out:0, In: 1) - */ +on tile[0]: in port p_margin = XS1_PORT_1G; /* CORE_POWER_MARGIN: Driven 0: 0.925v + * Pull down: 0.922v + * High-z: 0.9v + * Pull-up: 0.854v + * Driven 1: 0.85v + */ + +#define USE_FRACTIONAL_N (0) + +#if (USE_FRACTIONAL_N) +#define EXT_PLL_SEL__MCLK_DIR (0x00) +#else #define EXT_PLL_SEL__MCLK_DIR (0x80) +#endif -/* Note, this runs on Tile[0] */ -void ctrlPort() +/* Board setup for XU316 MC Audio (1v1) */ +void board_setup() { - // Drive control port to turn on 3V3 and set MCLK_DIR - // Note, "soft-start" to reduce current spike - // Note, 3v3_EN is inverted - for (int i = 0; i < 30; i++) - { - p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x30; /* 3v3: off, 3v3A: on */ - delay_microseconds(5); - p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x20; /* 3v3: on, 3v3A: on */ - delay_microseconds(5); - } + /* "Drive high mode" - drive high for 1, non-driving for 0 */ + set_port_drive_high(p_ctrl); + + /* Ensure high-z for 0.9v */ + p_margin :> void; + + /* Drive control port to turn on 3V3 and mclk direction appropriately. + * Bits set to low will be high-z, pulled down */ + p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x20; + + /* Wait for power supplies to be up and stable */ + delay_milliseconds(10); } /* Configures the external audio hardware at startup. Note this runs on Tile[1] */ diff --git a/tests/xua_unit_tests/CMakeLists.txt b/tests/xua_unit_tests/CMakeLists.txt index f8b0ad6d..8316cf96 100644 --- a/tests/xua_unit_tests/CMakeLists.txt +++ b/tests/xua_unit_tests/CMakeLists.txt @@ -55,7 +55,8 @@ foreach(TESTFILE ${TEST_SOURCES}) ## Do xcommon cmake build ########################## set(APP_HW_TARGET XK-EVK-XU316) - set(APP_DEPENDENT_MODULES "lib_xua") + set(APP_DEPENDENT_MODULES "lib_xua" + "lib_unity(2.5.2)") # set(APP_PCA_ENABLE ON) set(APP_COMPILER_FLAGS ${EXTRA_BUILD_FLAGS} -fcomment-asm -Wall @@ -82,14 +83,12 @@ foreach(TESTFILE ${TEST_SOURCES}) set(APP_C_SRCS ${RUNNER_FILE_RELATIVE} ${UNIT_TEST_SOURCE_RELATIVE} - ../../../Unity/src/unity.c ) get_filename_component(TEST_FILE_DIR ${TESTFILE} DIRECTORY) set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src ${TEST_FILE_DIR} - ${XMOS_SANDBOX_DIR}/Unity/src ${XMOS_SANDBOX_DIR}/lib_xud/lib_xud/src/user/class) XMOS_REGISTER_APP() diff --git a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c index 39c74cec..b2a4e45e 100644 --- a/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c +++ b/tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c @@ -24,7 +24,7 @@ #define CABLE_NUM 2 #define RANDOM_SEED 6031769 -unsigned mini_in_parse_ut(unsigned midi[3]){ +unsigned midi_in_parse_ut(unsigned midi[3]){ // printf("Composing data: 0x%x 0x%x 0x%x\n", midi[0], midi[1], midi[2]); struct midi_in_parse_state m_state; @@ -60,7 +60,7 @@ void test_midi_note(void) { for(int cmd = NOTE_OFF; cmd < NOTE_ON + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; - unsigned packed = mini_in_parse_ut(midi_ref); + unsigned packed = midi_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -78,7 +78,7 @@ void test_midi_pressure(void) { for(int cmd = PRESSURE; cmd < PRESSURE + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; - unsigned packed = mini_in_parse_ut(midi_ref); + unsigned packed = midi_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -96,7 +96,7 @@ void test_midi_control(void) { for(int cmd = CONTROL; cmd < CONTROL + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; - unsigned packed = mini_in_parse_ut(midi_ref); + unsigned packed = midi_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -114,7 +114,7 @@ void test_midi_program(void) { for(int cmd = PROGRAM; cmd < PROGRAM + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; - unsigned packed = mini_in_parse_ut(midi_ref); + unsigned packed = midi_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -132,7 +132,7 @@ void test_midi_pressure_val(void) { for(int cmd = PRESSURE_VAL; cmd < PRESSURE_VAL + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; - unsigned packed = mini_in_parse_ut(midi_ref); + unsigned packed = midi_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -150,7 +150,7 @@ void test_midi_range(void) { for(int cmd = RANGE; cmd < RANGE + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; - unsigned packed = mini_in_parse_ut(midi_ref); + unsigned packed = midi_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -168,7 +168,7 @@ void test_midi_manufacturer_id(void) { for(int cmd = MANUFACTURE_ID; cmd < MANUFACTURE_ID + NUM_CHANS; cmd++){ for(int test = 0; test < NUM_TESTS_PER_TEST; test++){ unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK}; - unsigned packed = mini_in_parse_ut(midi_ref); + unsigned packed = midi_in_parse_ut(midi_ref); unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); From 873f5bedd8f3ad5843c5a25a4bda64565047fa07 Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 24 Apr 2024 12:06:49 +0100 Subject: [PATCH 37/40] Fix port ref --- tests/test_midi/src/hwsupport.xc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_midi/src/hwsupport.xc b/tests/test_midi/src/hwsupport.xc index 697f6e58..7fed92ab 100644 --- a/tests/test_midi/src/hwsupport.xc +++ b/tests/test_midi/src/hwsupport.xc @@ -5,7 +5,7 @@ #include "xua.h" -out port p_ctrl = PORT_CTRL; /* p_ctrl: +out port p_ctrl = XS1_PORT_8D; /* p_ctrl: * [0:3] - Unused * [4] - EN_3v3_N (1v0 hardware only) * [5] - EN_3v3A From 655612c6731f210ffd5285227df7186d1debb6bb Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 24 Apr 2024 12:27:23 +0100 Subject: [PATCH 38/40] Manual setUp in HID unity tests --- .../test_multi_report/test_hid_multi_report.c | 41 ++++++++++++++++- .../xua_unit_tests/src/test_simple/test_hid.c | 44 ++++++++++++++++++- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c index d9fbac7c..4f0bdffd 100644 --- a/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c +++ b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c @@ -47,23 +47,26 @@ static unsigned construct_usage_header( unsigned size ) return header; } -void setUp( void ) +void test_init( void ) { hidReportInit(); hidResetReportDescriptor(); } void test_validate_report( void ) { + test_init(); unsigned retVal = hidReportValidate(); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_reportid_in_use( void ) { + test_init(); unsigned reportIdInUse = hidIsReportIdInUse(); TEST_ASSERT_EQUAL_UINT( 1, reportIdInUse ); } void test_get_next_valid_report_id( void ) { + test_init(); unsigned reportId = 0U; reportId = hidGetNextValidReportId(reportId); @@ -80,6 +83,7 @@ void test_get_next_valid_report_id( void ) { } void test_is_report_id_valid( void ) { + test_init(); unsigned isValid = 0; unsigned reportId = 0; @@ -106,6 +110,7 @@ void test_is_report_id_valid( void ) { // Basic report descriptor tests void test_unprepared_hidGetReportDescriptor( void ) { + test_init(); unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NULL( reportDescPtr ); @@ -118,6 +123,7 @@ void test_unprepared_hidGetReportDescriptor( void ) void test_prepared_hidGetReportDescriptor( void ) { + test_init(); hidPrepareReportDescriptor(); unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NOT_NULL( reportDescPtr ); @@ -137,6 +143,7 @@ void test_prepared_hidGetReportDescriptor( void ) void test_reset_unprepared_hidGetReportDescriptor( void ) { + test_init(); hidPrepareReportDescriptor(); hidResetReportDescriptor(); unsigned char* reportDescPtr = hidGetReportDescriptor(); @@ -145,6 +152,7 @@ void test_reset_unprepared_hidGetReportDescriptor( void ) void test_reset_prepared_hidGetReportDescriptor( void ) { + test_init(); hidPrepareReportDescriptor(); hidResetReportDescriptor(); hidPrepareReportDescriptor(); @@ -154,6 +162,7 @@ void test_reset_prepared_hidGetReportDescriptor( void ) void test_report_id_limit( void ) { + test_init(); unsigned reportIdLimit = hidGetReportIdLimit(); TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit ); } @@ -161,6 +170,7 @@ void test_report_id_limit( void ) // Basic item tests void test_max_loc_hidGetReportItem( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; unsigned char header; unsigned char page; @@ -199,6 +209,7 @@ void test_max_loc_hidGetReportItem( void ) void test_min_loc_hidGetReportItem( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ]; unsigned char header; unsigned char page; @@ -236,6 +247,7 @@ void test_min_loc_hidGetReportItem( void ) void test_invalid_report_id( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 }; unsigned char header = 0x33; unsigned char page = 0x44; @@ -253,6 +265,7 @@ void test_invalid_report_id( void ) void test_unused_report_id( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 }; unsigned char header = 0x33; unsigned char page = 0x44; @@ -270,6 +283,7 @@ void test_unused_report_id( void ) void test_overflow_bit_hidGetReportItem( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; @@ -307,6 +321,7 @@ void test_overflow_bit_hidGetReportItem( void ) void test_overflow_byte_hidGetReportItem( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; @@ -344,6 +359,7 @@ void test_overflow_byte_hidGetReportItem( void ) void test_underflow_bit_hidGetReportItem( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; @@ -381,6 +397,7 @@ void test_underflow_bit_hidGetReportItem( void ) void test_underflow_byte_hidGetReportItem( void ) { + test_init(); unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 }; unsigned char header = 0xAA; unsigned char page = 0x44; @@ -419,6 +436,7 @@ void test_underflow_byte_hidGetReportItem( void ) // Configurable and non-configurable item tests void test_configurable_item_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 1; const unsigned bit = REPORT1_MIN_VALID_BIT; const unsigned byte = REPORT1_MIN_VALID_BYTE; @@ -440,6 +458,7 @@ void test_configurable_item_hidSetReportItem( void ) // Testing that the high byte of the report gets correctly cleared void test_configurable_item_hidSetReportItem_multibyte_orig( void ) { + test_init(); const unsigned reportId = 2; const unsigned bit = 1; // This byte&bit combo is originally set be 2 bytes long in the header const unsigned byte = 0; @@ -460,6 +479,7 @@ void test_configurable_item_hidSetReportItem_multibyte_orig( void ) void test_nonconfigurable_item_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 1; const unsigned bit = 1; // This bit and byte combination should not appear in the const unsigned byte = 0; // hidConfigurableElements list in hid_report_descriptors.c. @@ -474,6 +494,7 @@ void test_nonconfigurable_item_hidSetReportItem( void ) // Bit range tests void test_max_bit_hidSetReportItem( void ) { + test_init(); const unsigned char header = construct_usage_header( 0 ); unsigned reportId = 1; @@ -500,6 +521,7 @@ void test_max_bit_hidSetReportItem( void ) void test_min_bit_hidSetReportItem( void ) { + test_init(); const unsigned char header = construct_usage_header( 0 ); unsigned reportId = 1; @@ -526,6 +548,7 @@ void test_min_bit_hidSetReportItem( void ) void test_overflow_bit_hidSetReportItem( void ) { + test_init(); const unsigned char header = construct_usage_header( 0 ); unsigned reportId = 1; @@ -552,6 +575,7 @@ void test_overflow_bit_hidSetReportItem( void ) void test_underflow_bit_hidSetReportItem( void ) { + test_init(); const unsigned char header = construct_usage_header( 0 ); unsigned reportId = 1; @@ -578,6 +602,7 @@ void test_underflow_bit_hidSetReportItem( void ) void test_overflow_byte_hidSetReportItem( void ) { + test_init(); const unsigned char header = construct_usage_header( 0 ); unsigned reportId = 1; @@ -604,6 +629,7 @@ void test_overflow_byte_hidSetReportItem( void ) void test_underflow_byte_hidSetReportItem( void ) { + test_init(); const unsigned char header = construct_usage_header( 0 ); unsigned reportId = 1; @@ -631,6 +657,7 @@ void test_underflow_byte_hidSetReportItem( void ) // Size range tests void test_max_size_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 1; const unsigned bit = REPORT1_MIN_VALID_BIT; const unsigned byte = REPORT1_MIN_VALID_BYTE; @@ -644,6 +671,7 @@ void test_max_size_hidSetReportItem( void ) void test_min_size_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 1; const unsigned bit = REPORT1_MIN_VALID_BIT; const unsigned byte = REPORT1_MIN_VALID_BYTE; @@ -656,6 +684,7 @@ void test_min_size_hidSetReportItem( void ) void test_unsupported_size_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = REPORT1_MIN_VALID_BIT; const unsigned byte = REPORT1_MIN_VALID_BYTE; @@ -669,6 +698,7 @@ void test_unsupported_size_hidSetReportItem( void ) // Combined function tests void test_initial_modification_without_subsequent_preparation( void ) { + test_init(); const unsigned reportId = 2; const unsigned bit = REPORT2_MIN_VALID_BIT; const unsigned byte = REPORT2_MIN_VALID_BYTE; @@ -685,6 +715,7 @@ void test_initial_modification_without_subsequent_preparation( void ) void test_initial_modification_with_subsequent_preparation( void ) { + test_init(); const unsigned reportId = 2; const unsigned bit = REPORT2_MIN_VALID_BIT; const unsigned byte = REPORT2_MIN_VALID_BYTE; @@ -702,6 +733,7 @@ void test_initial_modification_with_subsequent_preparation( void ) void test_initial_modification_with_subsequent_verification_1( void ) { + test_init(); const unsigned reportId = 2; const unsigned bit = REPORT2_MIN_VALID_BIT; const unsigned byte = REPORT2_MIN_VALID_BYTE; @@ -727,6 +759,7 @@ void test_initial_modification_with_subsequent_verification_1( void ) void test_initial_modification_with_subsequent_verification_2( void ) { + test_init(); const unsigned reportId = 3; const unsigned bit = REPORT3_MIN_VALID_BIT; const unsigned byte = REPORT3_MIN_VALID_BYTE; @@ -775,6 +808,7 @@ void test_initial_modification_with_subsequent_verification_2( void ) //setIdle and associated timing functionality tests void test_set_idle( void ) { + test_init(); unsigned reportId = 1; unsigned reportId2 = 2; @@ -794,6 +828,7 @@ void test_set_idle( void ) void test_set_all_idle( void ) { + test_init(); unsigned reportId = 1; unsigned reportId2 = 2; @@ -812,6 +847,7 @@ void test_set_all_idle( void ) void test_change_pending( void ) { + test_init(); unsigned reportId = 1; unsigned reportId2 = 2; @@ -831,6 +867,7 @@ void test_change_pending( void ) void test_change_pending_all( void ) { + test_init(); unsigned reportId = 1; unsigned changePending = hidIsChangePending( reportId ); @@ -845,6 +882,7 @@ void test_change_pending_all( void ) void test_report_time( void ) { + test_init(); unsigned reportTime1 = 123; unsigned reportTime2 = 456; @@ -859,6 +897,7 @@ void test_report_time( void ) void test_report_time_calc( void ) { + test_init(); unsigned reportTime1 = 123; unsigned reportTime2 = 456; unsigned reportPeriod1 = 10; diff --git a/tests/xua_unit_tests/src/test_simple/test_hid.c b/tests/xua_unit_tests/src/test_simple/test_hid.c index 3bd930bc..513b3ea3 100644 --- a/tests/xua_unit_tests/src/test_simple/test_hid.c +++ b/tests/xua_unit_tests/src/test_simple/test_hid.c @@ -34,23 +34,26 @@ static unsigned construct_usage_header( unsigned size ) return header; } -void setUp( void ) +void test_init( void ) { hidReportInit(); hidResetReportDescriptor(); } void test_validate_report( void ) { + test_init(); unsigned retVal = hidReportValidate(); TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal ); } void test_reportid_in_use( void ) { + test_init(); unsigned reportIdInUse = hidIsReportIdInUse(); TEST_ASSERT_EQUAL_UINT( 0, reportIdInUse ); } void test_get_next_valid_report_id( void ) { + test_init(); unsigned reportId = 0U; reportId = hidGetNextValidReportId(reportId); @@ -61,6 +64,7 @@ void test_get_next_valid_report_id( void ) { } void test_is_report_id_valid( void ) { + test_init(); unsigned isValid = 0; unsigned reportId = 0; @@ -75,6 +79,7 @@ void test_is_report_id_valid( void ) { // Basic report descriptor tests void test_unprepared_hidGetReportDescriptor( void ) { + test_init(); const unsigned reportId = 0; unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NULL( reportDescPtr ); @@ -85,6 +90,7 @@ void test_unprepared_hidGetReportDescriptor( void ) void test_prepared_hidGetReportDescriptor( void ) { + test_init(); const unsigned reportId = 0; hidPrepareReportDescriptor(); @@ -97,6 +103,7 @@ void test_prepared_hidGetReportDescriptor( void ) void test_reset_unprepared_hidGetReportDescriptor( void ) { + test_init(); hidPrepareReportDescriptor(); hidResetReportDescriptor(); unsigned char* reportDescPtr = hidGetReportDescriptor(); @@ -105,6 +112,7 @@ void test_reset_unprepared_hidGetReportDescriptor( void ) void test_reset_prepared_hidGetReportDescriptor( void ) { + test_init(); hidPrepareReportDescriptor(); hidResetReportDescriptor(); hidPrepareReportDescriptor(); @@ -114,6 +122,7 @@ void test_reset_prepared_hidGetReportDescriptor( void ) void test_report_id_limit( void ) { + test_init(); unsigned reportIdLimit = hidGetReportIdLimit(); TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit ); } @@ -121,6 +130,7 @@ void test_report_id_limit( void ) // Basic item tests void test_max_loc_hidGetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; const unsigned byte = MAX_VALID_BYTE; @@ -138,6 +148,7 @@ void test_max_loc_hidGetReportItem( void ) void test_min_loc_hidGetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -155,6 +166,7 @@ void test_min_loc_hidGetReportItem( void ) void test_overflow_bit_hidGetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT + 1; const unsigned byte = MAX_VALID_BYTE; @@ -172,6 +184,7 @@ void test_overflow_bit_hidGetReportItem( void ) void test_overflow_byte_hidGetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; const unsigned byte = MAX_VALID_BYTE + 1; @@ -189,6 +202,7 @@ void test_overflow_byte_hidGetReportItem( void ) void test_underflow_bit_hidGetReportItem( void ) { + test_init(); const unsigned reportId = 0; const int bit = MIN_VALID_BIT - 1; const unsigned byte = MIN_VALID_BYTE; @@ -206,6 +220,7 @@ void test_underflow_bit_hidGetReportItem( void ) void test_underflow_byte_hidGetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const int byte = MIN_VALID_BYTE - 1; @@ -224,6 +239,7 @@ void test_underflow_byte_hidGetReportItem( void ) // Configurable and non-configurable item tests void test_configurable_item_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -237,6 +253,7 @@ void test_configurable_item_hidSetReportItem( void ) void test_nonconfigurable_item_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; // This bit and byte combination should not appear in the const unsigned byte = MIN_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c. @@ -251,6 +268,7 @@ void test_nonconfigurable_item_hidSetReportItem( void ) // Bit range tests void test_max_bit_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT; // Only byte 1 has bit 7 not reserved, See the const unsigned byte = MAX_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c. @@ -263,6 +281,7 @@ void test_max_bit_hidSetReportItem( void ) void test_min_bit_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -275,6 +294,7 @@ void test_min_bit_hidSetReportItem( void ) void test_overflow_bit_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MAX_VALID_BIT + 1; const unsigned byte = MIN_VALID_BYTE; @@ -287,6 +307,7 @@ void test_overflow_bit_hidSetReportItem( void ) void test_underflow_bit_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const int bit = MIN_VALID_BIT - 1; const unsigned byte = MIN_VALID_BYTE; @@ -300,6 +321,7 @@ void test_underflow_bit_hidSetReportItem( void ) // Byte range tests void test_max_byte_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MAX_VALID_BYTE; @@ -312,6 +334,7 @@ void test_max_byte_hidSetReportItem( void ) void test_min_byte_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -324,6 +347,7 @@ void test_min_byte_hidSetReportItem( void ) void test_overflow_byte_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MAX_VALID_BYTE + 1; @@ -336,6 +360,7 @@ void test_overflow_byte_hidSetReportItem( void ) void test_underflow_byte_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const int byte = MIN_VALID_BYTE - 1; @@ -349,6 +374,7 @@ void test_underflow_byte_hidSetReportItem( void ) // Size range tests void test_max_size_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -362,6 +388,7 @@ void test_max_size_hidSetReportItem( void ) void test_min_size_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -374,6 +401,7 @@ void test_min_size_hidSetReportItem( void ) void test_unsupported_size_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -387,6 +415,7 @@ void test_unsupported_size_hidSetReportItem( void ) // Header tag and type tests void test_bad_tag_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -402,6 +431,7 @@ void test_bad_tag_hidSetReportItem( void ) void test_global_type_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -415,6 +445,7 @@ void test_global_type_hidSetReportItem( void ) void test_local_type_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -428,6 +459,7 @@ void test_local_type_hidSetReportItem( void ) void test_main_type_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -441,6 +473,7 @@ void test_main_type_hidSetReportItem( void ) void test_reserved_type_hidSetReportItem( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -455,6 +488,7 @@ void test_reserved_type_hidSetReportItem( void ) // Combined function tests void test_initial_modification_without_subsequent_preparation( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -471,6 +505,7 @@ void test_initial_modification_without_subsequent_preparation( void ) void test_initial_modification_with_subsequent_preparation( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -488,6 +523,7 @@ void test_initial_modification_with_subsequent_preparation( void ) void test_initial_modification_with_subsequent_verification_1( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -513,6 +549,7 @@ void test_initial_modification_with_subsequent_verification_1( void ) void test_initial_modification_with_subsequent_verification_2( void ) { + test_init(); const unsigned reportId = 0; const unsigned bit = MIN_VALID_BIT; const unsigned byte = MIN_VALID_BYTE; @@ -560,6 +597,7 @@ void test_initial_modification_with_subsequent_verification_2( void ) void test_modification_without_subsequent_preparation( void ) { + test_init(); hidPrepareReportDescriptor(); unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NOT_NULL( reportDescPtr ); @@ -581,6 +619,7 @@ void test_modification_without_subsequent_preparation( void ) void test_modification_with_subsequent_preparation( void ) { + test_init(); hidPrepareReportDescriptor(); unsigned char* reportDescPtr = hidGetReportDescriptor(); TEST_ASSERT_NOT_NULL( reportDescPtr ); @@ -604,6 +643,7 @@ void test_modification_with_subsequent_preparation( void ) //setIdle functionality tests void test_set_idle( void ) { + test_init(); unsigned reportId = 0; unsigned setIdle = hidIsIdleActive( reportId ); @@ -616,6 +656,7 @@ void test_set_idle( void ) void test_change_pending( void ) { + test_init(); unsigned reportId = 0; unsigned changePending = hidIsChangePending( reportId ); @@ -632,6 +673,7 @@ void test_change_pending( void ) void test_report_time( void ) { + test_init(); unsigned reportTime = 123; unsigned reportPeriod = 10; From 9201d7a570461589580944151d3aa7bb594e5468 Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 24 Apr 2024 12:35:42 +0100 Subject: [PATCH 39/40] Missing tile designator --- tests/test_midi/src/hwsupport.xc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_midi/src/hwsupport.xc b/tests/test_midi/src/hwsupport.xc index 7fed92ab..a8c9c914 100644 --- a/tests/test_midi/src/hwsupport.xc +++ b/tests/test_midi/src/hwsupport.xc @@ -5,7 +5,7 @@ #include "xua.h" -out port p_ctrl = XS1_PORT_8D; /* p_ctrl: +on tile[0]: out port p_ctrl = XS1_PORT_8D; /* p_ctrl: * [0:3] - Unused * [4] - EN_3v3_N (1v0 hardware only) * [5] - EN_3v3A From a3670d6b851345d1ece29c9c4ae126d10bdfcf55 Mon Sep 17 00:00:00 2001 From: Ed Date: Wed, 24 Apr 2024 12:45:26 +0100 Subject: [PATCH 40/40] Copyright and port clash fix --- tests/test_midi/src/hwsupport.xc | 10 ---------- .../src/test_multi_report/test_hid_multi_report.c | 2 +- tests/xua_unit_tests/src/test_simple/test_hid.c | 2 +- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/test_midi/src/hwsupport.xc b/tests/test_midi/src/hwsupport.xc index a8c9c914..02b36a6b 100644 --- a/tests/test_midi/src/hwsupport.xc +++ b/tests/test_midi/src/hwsupport.xc @@ -13,13 +13,6 @@ on tile[0]: out port p_ctrl = XS1_PORT_8D; /* p_ctrl: * [7] - MCLK_DIR (Out:0, In: 1) */ -on tile[0]: in port p_margin = XS1_PORT_1G; /* CORE_POWER_MARGIN: Driven 0: 0.925v - * Pull down: 0.922v - * High-z: 0.9v - * Pull-up: 0.854v - * Driven 1: 0.85v - */ - #define USE_FRACTIONAL_N (0) #if (USE_FRACTIONAL_N) @@ -34,9 +27,6 @@ void board_setup() /* "Drive high mode" - drive high for 1, non-driving for 0 */ set_port_drive_high(p_ctrl); - /* Ensure high-z for 0.9v */ - p_margin :> void; - /* Drive control port to turn on 3V3 and mclk direction appropriately. * Bits set to low will be high-z, pulled down */ p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x20; diff --git a/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c index 4f0bdffd..fbb9a7da 100644 --- a/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c +++ b/tests/xua_unit_tests/src/test_multi_report/test_hid_multi_report.c @@ -1,4 +1,4 @@ -// Copyright 2021-2022 XMOS LIMITED. +// Copyright 2021-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include #include diff --git a/tests/xua_unit_tests/src/test_simple/test_hid.c b/tests/xua_unit_tests/src/test_simple/test_hid.c index 513b3ea3..28250bd6 100644 --- a/tests/xua_unit_tests/src/test_simple/test_hid.c +++ b/tests/xua_unit_tests/src/test_simple/test_hid.c @@ -1,4 +1,4 @@ -// Copyright 2021-2022 XMOS LIMITED. +// Copyright 2021-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include #include