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