diff --git a/tests/test_midi/src/app_midi_simple.xc b/tests/test_midi/src/app_midi_simple.xc index ac4bc7df..064dcb89 100644 --- a/tests/test_midi/src/app_midi_simple.xc +++ b/tests/test_midi/src/app_midi_simple.xc @@ -1,16 +1,6 @@ // 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) - * - * It uses the main blocks from the lib_xua - * - * - 2 channels out I2S only - * - No DFU - * - I2S only - * - */ - #include #include #include @@ -47,12 +37,11 @@ on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI; /* See hwsupport.xc */ void board_setup(); +#ifndef CABLE_NUM #define CABLE_NUM 0 +#endif - -unsigned midi_in_parse_helper(unsigned midi[3]){ - struct midi_in_parse_state m_state; - reset_midi_state(m_state); +unsigned midi_in_parse_helper(unsigned midi[3], struct midi_in_parse_state &m_state){ unsigned valid = 0; unsigned packed = 0; @@ -117,6 +106,10 @@ void test(chanend c_midi){ int is_ack; unsigned rx_packet; + // Midi in parse state + struct midi_in_parse_state m_state; + reset_midi_state(m_state); + // Counters for Rx and Tx unsigned tx_cmd_count = 0; unsigned rx_cmd_count = 0; @@ -151,7 +144,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 = midi_in_parse_helper(midi); + unsigned tx_packet = midi_in_parse_helper(midi, m_state); 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; diff --git a/tests/test_midi_loopback.py b/tests/test_midi_loopback.py index 4a21a753..fec656fe 100644 --- a/tests/test_midi_loopback.py +++ b/tests/test_midi_loopback.py @@ -29,7 +29,10 @@ def test_midi_loopback(capfd, build_midi): [0xe0, 0, 96], #pitch bend [0xff], #MIDI reset [0x80, 60, 81], #note off + [0xf0, 0x00, 0x21], [0x1D, 0x0b, 0x33], [0x3f, 0x1e, 0xf7], # Sysex, Ableton, 0b33f1e, terminator + [0xc0, 17], #instr select ] + create_midi_rx_file(len(midi_commands)) create_midi_tx_file(midi_commands) @@ -39,22 +42,21 @@ def test_midi_loopback(capfd, build_midi): 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 + #This is just for local debug so we can capture the traces if needed. It slows xsim down a lot # simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) Pyxsim.run_with_pyxsim( xe, simthreads=simthreads, - timeout=120, + timeout=180, simargs=simargs, ) capture = capfd.readouterr().out result = tester.run(capture.split("\n")) # Print to console - # with capfd.disabled(): - # print("++++", capture, "++++") - # print("----", expected, "----") + with capfd.disabled(): + print("CAPTURE:", capture) + print("EXPECTED:", expected) - - assert result \ No newline at end of file + assert result diff --git a/tests/test_midi_rx.py b/tests/test_midi_rx.py index 1997dd73..49af60f8 100644 --- a/tests/test_midi_rx.py +++ b/tests/test_midi_rx.py @@ -23,11 +23,16 @@ def test_rx(capfd, config, build_midi): copy_tree(build_midi, tmpdirname) xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe") - midi_commands = [[0x90, 60, 81]] - create_midi_rx_file(len(midi_commands)) + midi_commands = [[0x90, 0x91, 0x90],# Invalid and should be discarded + [0x90, 60, 81], # Note on + [0x80, 60, 81]] # Note off + + midi_command_expected = midi_commands[1:] # should skip invalid first message + + create_midi_rx_file(len(midi_command_expected)) create_midi_tx_file() - expected = midi_expect_rx().expect(midi_commands) + expected = midi_expect_rx().expect(midi_command_expected) tester = testers.ComparisonTester(expected, ordered = True) rx_port = "tile[1]:XS1_PORT_1F" @@ -38,7 +43,6 @@ def test_rx(capfd, config, build_midi): 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) @@ -58,4 +62,10 @@ def test_rx(capfd, config, build_midi): capture = capfd.readouterr().out result = tester.run(capture.split("\n")) - assert result, f"expected: {expected}\n capture: {capture}" \ No newline at end of file + # Print to console + with capfd.disabled(): + print("CAPTURE:", capture) + print("EXPECTED:", expected) + + + assert result, f"expected: {expected}\n capture: {capture}" diff --git a/tests/test_midi_tx.py b/tests/test_midi_tx.py index ade525d6..1932a587 100644 --- a/tests/test_midi_tx.py +++ b/tests/test_midi_tx.py @@ -23,11 +23,23 @@ def test_tx(capfd, config, build_midi): copy_tree(build_midi, tmpdirname) xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe") - midi_commands = [[0x90, 60, 81]] + # midi_commands = [[0x90, 0x91, 0x90],# Invalid and should be discarded + # [0x90, 60, 81], # Note on + # [0x80, 60, 81]] # Note off + + midi_commands = [ + [0x90, 60, 81], # Note on + [0x80, 60, 81]] # Note off + + + # midi_command_expected = midi_commands[1:] # should skip invalid first message + # Make a 1D list from the 2D list + midi_command_expected = [[item for row in midi_commands for item in row]] + create_midi_tx_file(midi_commands) create_midi_rx_file() - expected = midi_expect_tx().expect(midi_commands) + expected = midi_expect_tx().expect(midi_command_expected) tester = testers.ComparisonTester(expected, ordered = True) tx_port = "tile[1]:XS1_PORT_4C" @@ -42,9 +54,9 @@ def test_tx(capfd, config, build_midi): ] - simargs = ["--max-cycles", str(MAX_CYCLES)] + simargs = ["--max-cycles", str(MAX_CYCLES), "-o", "trace.txt"] #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.extend(["--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"]) # with capfd.disabled(): # use to see xsim and tester output Pyxsim.run_with_pyxsim( @@ -56,4 +68,18 @@ def test_tx(capfd, config, build_midi): capture = capfd.readouterr().out result = tester.run(capture.split("\n")) - assert result, f"expected: {expected}\n capture: {capture}" \ No newline at end of file + # Print to console + with capfd.disabled(): + print("CAPTURE:", capture) + print("EXPECTED:", expected) + + # Show tail of trace if there is an error + if not result: + with capfd.disabled(): + print("Simulator trace tail:") + with open("trace.txt") as trace: + output = trace.readlines() + print("".join(output[-25:])) + + + assert result, f"expected: {expected}\n capture: {capture}" 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 b2a4e45e..b35fc1db 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 @@ -14,14 +14,20 @@ #define PROGRAM 192 #define PRESSURE_VAL 208 #define RANGE 224 -#define MANUFACTURE_ID 240 +#define SYSEX_SOM 240 +#define SYSEX_EOM 247 #define DATA_RANGE 128 #define DATA_MASK (DATA_RANGE - 1) -#define NUM_TESTS_PER_TEST 30 +#ifndef NUM_TESTS_PER_TEST +#define NUM_TESTS_PER_TEST 30 +#endif + +#ifndef CABLE_NUM +#define CABLE_NUM 0 +#endif -#define CABLE_NUM 2 #define RANDOM_SEED 6031769 unsigned midi_in_parse_ut(unsigned midi[3]){ @@ -61,6 +67,7 @@ void test_midi_note(void) { 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 = midi_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -79,6 +86,7 @@ void test_midi_pressure(void) { 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 = midi_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -97,6 +105,7 @@ void test_midi_control(void) { 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 = midi_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -115,6 +124,7 @@ void test_midi_program(void) { 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 = midi_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -133,6 +143,7 @@ void test_midi_pressure_val(void) { 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 = midi_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -151,6 +162,7 @@ void test_midi_range(void) { 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 = midi_in_parse_ut(midi_ref); + unsigned midi_dut[3] = {0}; unsigned size = 0; midi_out_parse_c_wrapper(packed, midi_dut, &size); @@ -164,20 +176,47 @@ void test_midi_range(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 = midi_in_parse_ut(midi_ref); - unsigned midi_dut[3] = {0}; - unsigned size = 0; - 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!? - for(int i = 0; i < size; i++){ - TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); +// https://cmtext.indiana.edu/MIDI/chapter3_system_messages.php +void test_midi_sys_ex(void) { + const unsigned MAX_SYS_EX_LENGTH = 200; // https://cycling74.com/forums/maximu-sysex-length + + for(int sys_ex_length = 1; sys_ex_length < MAX_SYS_EX_LENGTH; sys_ex_length++){ + unsigned midi_ref[1 + MAX_SYS_EX_LENGTH + 1] = {0}; // Add SOM + EOM. + unsigned msg_len = 1 + sys_ex_length + 1; + + // Build message + midi_ref[0] = SYSEX_SOM; + midi_ref[1] = 0x00; // Extended manf ID + midi_ref[2] = random(&rndm) & DATA_MASK; // Manf ID 0 + midi_ref[3] = random(&rndm) & DATA_MASK; // Manf ID 1 + for(unsigned i = 4; i < msg_len - 1; i++){ + midi_ref[i] = random(&rndm) & DATA_MASK; // Some data + } + midi_ref[msg_len - 1] = SYSEX_EOM; // End of sys-ex + + unsigned midi_dut[1 + MAX_SYS_EX_LENGTH + 1 + 2] = {0}; // Add SOM + EOM. Add 2 because msg_size % 3 may be up to 2. + + struct midi_in_parse_state mips; + reset_midi_state_c_wrapper(&mips); + unsigned valid = 0; + unsigned packed = 0; + + unsigned out_idx = 0; + for(unsigned i = 0; i < msg_len; i++){ + // printf("Ref byte: %d - 0x%x\n", i, midi_ref[i]); + midi_in_parse_c_wrapper((void * )&mips, CABLE_NUM, midi_ref[i], &valid, &packed); + if(valid){ + unsigned size = 0; + midi_out_parse_c_wrapper(packed, &midi_dut[out_idx], &size); + // printf("SIZE: %u PACKED: 0x%8x, 0x%x 0x%x 0x%x\n", size, packed, midi_dut[out_idx + 0], midi_dut[out_idx + 1], midi_dut[out_idx + 2]); + out_idx += size; } } + + for(unsigned i = 0; i < msg_len; i++){ + // printf("%d Ref: 0x%x DUT: 0x%x\n", i, midi_ref[i], midi_dut[i]); + TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]); + } + printf("Sysex PASS length: %u\n", msg_len); } -} \ No newline at end of file +} 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 07e643e0..ae48988c 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 @@ -40,6 +40,28 @@ void test_midi_queue_init(void) { TEST_ASSERT_EQUAL_UINT32(USB_MIDI_DEVICE_OUT_FIFO_SIZE, space); } +void test_midi_queue_full(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++){ + queue_push_word_c_wrapper(&symbol_fifo, symbol_fifo_storage, 0); + } + + int empty = queue_is_empty_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_INT32(0, empty); + + int full = queue_is_full_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_INT32(1, full); + + unsigned items = queue_items_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_UINT32(USB_MIDI_DEVICE_OUT_FIFO_SIZE, items); + + unsigned space = queue_space_c_wrapper(&symbol_fifo); + TEST_ASSERT_EQUAL_UINT32(0, space); +} + void test_midi_queue_push_pop(void) { queue_t symbol_fifo; unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE];