Merge pull request #378 from ed-xmos/feature/midi_test

MIDI tests
This commit is contained in:
Ed
2024-04-25 10:55:37 +01:00
committed by GitHub
27 changed files with 1637 additions and 513 deletions

4
.gitignore vendored
View File

@@ -48,3 +48,7 @@ host_usb_mixer_control/xmos_mixer
**/.vscode/**
**.egg-info
*tests/logs/*
midi_tx_cmds.txt
midi_rx_cmds.txt
trace.txt
tests/xua_unit_tests/src.runners

23
Jenkinsfile vendored
View File

@@ -1,4 +1,4 @@
@Library('xmos_jenkins_shared_library@v0.24.0') _
@Library('xmos_jenkins_shared_library@v0.27.0') _
getApproval()
@@ -7,6 +7,7 @@ pipeline {
environment {
REPO = 'lib_xua'
VIEW = getViewName(REPO)
TOOLS_VERSION = "15.2.1" // For unit tests
}
options {
skipDefaultCheckout()
@@ -35,7 +36,8 @@ pipeline {
dir("${REPO}/tests"){
viewEnv(){
withVenv{
runPytest('--numprocesses=4')
sh "xmake -C test_midi -j" // Xdist does not like building so do here
runPytest('--numprocesses=auto -vvv')
}
}
}
@@ -43,15 +45,14 @@ pipeline {
}
stage('Unity tests') {
steps {
dir("${REPO}") {
dir('tests') {
dir('xua_unit_tests') {
withVenv {
runWaf('.', "configure clean build --target=xcore200")
viewEnv() {
runPython("TARGET=XCORE200 pytest -s --junitxml=pytest_unity.xml")
junit "pytest_unity.xml"
}
dir("${REPO}/tests/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"
}
}
}

View File

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

View File

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

View File

@@ -1,8 +1,11 @@
# 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
import Pyxsim
from pathlib import Path
from midi_test_helpers import MIDI_TEST_CONFIGS
import subprocess
@pytest.fixture()
def test_file(request):
@@ -39,3 +42,16 @@ def pytest_addoption(parser):
@pytest.fixture
def options(request):
yield request.config.option
# We use the same binary multiple times so just build once for all MIDI tests
@pytest.fixture(scope="session")
def build_midi():
cmd = "xmake -C test_midi -j"
# result = subprocess.run(cmd, capture_output=True, text=True, shell=True)
# return_code = result.returncode
return_code = 0
assert return_code == 0, f"{result.stderr}\n{result.stdout}"
return str(Path(__file__).parent / f"test_midi/bin/")

View File

@@ -0,0 +1,81 @@
# 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(dir=os.getcwd())
def cleanup():
shutil.rmtree(dirpath)
with cd(dirpath, cleanup):
yield dirpath
class midi_expect_tx:
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 + "\n"
class midi_expect_rx:
def __init(self):
pass
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 + "\n"
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)
# Test/dev only
if __name__ == "__main__":
with tempdir() as td:
print(td)
create_midi_tx_file()
input("PRESS ENTER TO CONTINUE")

37
tests/test_midi/Makefile Normal file
View File

@@ -0,0 +1,37 @@
# 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
else
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
# 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

View File

@@ -0,0 +1,186 @@
// 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 <xs1.h>
#include <platform.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <xclib.h>
#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;
#define MAX_TEST_COMMANDS 100
#define TEST_COMMAND_FILE_TX "midi_tx_cmds.txt"
#define TEST_COMMAND_FILE_RX "midi_rx_cmds.txt"
#define DEBUG 0 // Prints for debugging. Turn off for actual test
#if DEBUG
#define dprintf(...) printf(__VA_ARGS__)
#else
#define dprintf(...)
#endif
/* See hwsupport.xc */
void board_setup();
#define CABLE_NUM 0
unsigned midi_in_parse_helper(unsigned midi[3]){
struct midi_in_parse_state m_state;
reset_midi_state(m_state);
unsigned valid = 0;
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;
}
}
return 0;
}
{unsigned, unsigned} read_config_file(uint8_t commands[MAX_TEST_COMMANDS][3])
{
unsigned tx_line_count = 0;
FILE * movable fptr_tx = fopen(TEST_COMMAND_FILE_TX,"rt");
if (fptr_tx == NULL) {
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));
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_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 rx_packet;
// Counters for Rx and Tx
unsigned tx_cmd_count = 0;
unsigned rx_cmd_count = 0;
timer tmr;
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{
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(byterev(rx_packet));
// 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;
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);
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;
tx_end += max_tx_time;
break;
}
}
dprintf("Tx and Rx count met - exiting after last tx complete.\n");
tmr when timerafter(tx_end) :> int _; // wait until packet definitely departed
exit(0);
}
int main(void)
{
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);
// Setup HW so we can run this on the MC board
on tile[0]: board_setup();
}
return 0;
}

View File

@@ -0,0 +1,47 @@
// Copyright 2017-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include <platform.h>
#include "xua.h"
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
* [6] - EXT_PLL_SEL (CS2100:0, SI: 1)
* [7] - MCLK_DIR (Out:0, In: 1)
*/
#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
/* Board setup for XU316 MC Audio (1v1) */
void board_setup()
{
/* "Drive high mode" - drive high for 1, non-driving for 0 */
set_port_drive_high(p_ctrl);
/* 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] */
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)
{
}

View File

@@ -0,0 +1,28 @@
// Copyright 2017-2024 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

View File

@@ -0,0 +1,8 @@
// Copyright 2017-2024 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

View File

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

61
tests/test_midi_rx.py Normal file
View File

@@ -0,0 +1,61 @@
# 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_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
#####
# 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", 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(len(midi_commands))
create_midi_tx_file()
expected = midi_expect_rx().expect(midi_commands)
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
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)]
#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"])
# with capfd.disabled(): # use to see xsim and tester output
Pyxsim.run_with_pyxsim(
xe,
simthreads=simthreads,
timeout=120,
simargs=simargs,
)
capture = capfd.readouterr().out
result = tester.run(capture.split("\n"))
assert result, f"expected: {expected}\n capture: {capture}"

59
tests/test_midi_tx.py Normal file
View File

@@ -0,0 +1,59 @@
# 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 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
#####
# 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", MIDI_TEST_CONFIGS)
def test_tx(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_tx_file(midi_commands)
create_midi_rx_file()
expected = midi_expect_tx().expect(midi_commands)
tester = testers.ComparisonTester(expected, ordered = True)
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)
simthreads = [
UARTTxChecker(tx_port, parity, baud, length_of_test, stop, bpb, 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"])
# with capfd.disabled(): # use to see xsim and tester output
Pyxsim.run_with_pyxsim(
xe,
simthreads=simthreads,
timeout=120,
simargs=simargs,
)
capture = capfd.readouterr().out
result = tester.run(capture.split("\n"))
assert result, f"expected: {expected}\n capture: {capture}"

178
tests/uart_rx_checker.py Normal file
View File

@@ -0,0 +1,178 @@
# 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 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
)
# 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):
self._p = p
def run(self):
xsi = self.xsi
xsi.drive_port_pins(self._p, 1);
class UARTRxChecker(px.SimThread):
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.
:param rx_port: Receive 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._tx_port = tx_port
self._rx_port = rx_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(f"Checker sent 0x{byte:02x}")
for x in range(self._bits_per_byte):
# print(f" Sending bit {x}")
xsi.drive_port_pins(self._rx_port, (byte & (0x01 << x)) >= 1)
# print(f" (x): {((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 * time_scaling_factor
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)

246
tests/uart_tx_checker.py Normal file
View File

@@ -0,0 +1,246 @@
# 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 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)
# 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):
"""
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, tx_port, parity, baud, length, stop_bits, bpb, debug=False):
"""
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
self.debug = debug
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 * time_scaling_factor
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)
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)))
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
# The tx line should go low for 1 bit time
if self.get_val_timeout(xsi, self._tx_port) == 0:
if self.debug: 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
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)
# Get the stop bit
self.check_stopbit(xsi)
# Print a new line to split bytes in output
if self.debug: 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:
if self.debug: 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
if self.debug: 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("uart_tx_checker:", " ".join(map((lambda x: "0x%02x" % ord(x)), K)))

View File

@@ -1,103 +1,96 @@
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.21)
include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake)
set(XMOS_TOOLS_PATH $ENV{XMOS_TOOL_PATH}/bin)
#**********************
# Setup XMOS toolchain
#**********************
if(NOT DEFINED ENV{XUA_PATH})
message(FATAL_ERROR "XUA_PATH environment variable not defined")
# some more commands
# 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)
# Set unity runner generate script
set(GEN_RUNNER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_unity_runner.py)
# Create directory for runner files
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)
# 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})
message(STATUS "Processing unit test: ${TESTNAME}")
# 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 ${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 python ${GEN_RUNNER_SCRIPT} ${GEN_RUNNER_SCRIPT_ARGS}
COMMENT "Generate XUA Unit Test Runner" )
##########################
## Do xcommon cmake build
##########################
set(APP_HW_TARGET XK-EVK-XU316)
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
-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()
## Define project
project(xua_unit_tests VERSION 0.1.0)
# 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})
## Enable languages for project
enable_language(CXX XC C ASM)
set(APP_C_SRCS ${RUNNER_FILE_RELATIVE}
${UNIT_TEST_SOURCE_RELATIVE}
)
message(STATUS "CAME HERE")
add_custom_target("runners" ALL)
add_custom_command(
TARGET runners
COMMAND python generate_unity_runners.py
COMMENT "generate unity runners"
)
message(STATUS "CAME HERE 1")
file( GLOB APP_SOURCES src/test*.xc )
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
foreach( testsourcefile ${APP_SOURCES} )
get_filename_component(ITEM_NAME ${testsourcefile} NAME_WE)
message(STATUS "item_name " ${ITEM_NAME})
add_executable(${ITEM_NAME})
set(APP_COMPILER_FLAGS
"-O2"
"-g"
"-Wall"
"-report"
"-fxscope"
"-target=XCORE-AI-EXPLORER"
"${CMAKE_CURRENT_SOURCE_DIR}/config.xscope"
"-DHID_CONTROLS=1"
"-DUNITY_SUPPORT_64"
"-DUNITY_INCLUDE_DOUBLE"
)
set_source_files_properties(
"runners/${ITEM_NAME}/${ITEM_NAME}_Runner.c"
PROPERTIES GENERATED TRUE
)
get_filename_component(TEST_FILE_DIR ${TESTFILE} DIRECTORY)
set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src
${TEST_FILE_DIR}
${XMOS_SANDBOX_DIR}/lib_xud/lib_xud/src/user/class)
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)"
)
XMOS_REGISTER_APP()
include("$ENV{XUA_PATH}/cmake_utils/xua.cmake")
set_target_properties(${ITEM_NAME} PROPERTIES OUTPUT_NAME ${ITEM_NAME}.xe)
target_compile_options(${ITEM_NAME} PRIVATE ${APP_COMPILER_FLAGS})
target_include_directories(${ITEM_NAME}
PRIVATE ${APP_INCLUDES}
PRIVATE ${XUA_INCLUDES_ALL}
)
target_sources(${ITEM_NAME}
PRIVATE ${APP_SRCS}
PRIVATE ${XUA_SRCS_ALL}
)
add_dependencies(${ITEM_NAME} runners)
target_link_options(${ITEM_NAME} PRIVATE ${APP_COMPILER_FLAGS})
## Set any additional flags only for C++
set(CMAKE_CXX_FLAGS "-std=c++11")
endforeach( testsourcefile ${APP_SOURCES} )
message(STATUS ${APP_SOURCES})
message(STATUS "CAME HERE 2")
## Register the application
#XMOS_REGISTER_APP()
endforeach()

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,183 @@
// Copyright 2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <stddef.h>
#include <stdio.h>
#include "xua_unit_tests.h"
#include "../../../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 DATA_RANGE 128
#define DATA_MASK (DATA_RANGE - 1)
#define NUM_TESTS_PER_TEST 30
#define CABLE_NUM 2
#define RANDOM_SEED 6031769
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;
void * mips = &m_state;
reset_midi_state_c_wrapper(mips);
unsigned valid = 0;
unsigned packed = 0;
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_c_wrapper(mips, CABLE_NUM, midi[1], &valid, &packed);
// printf("Valid: %d data: %u\n", valid, packed);
if(valid){
return 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;
}
return 0;
}
unsigned rndm = RANDOM_SEED;
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 = 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]);
}
}
}
}
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 = 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]);
}
}
}
}
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 = 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]);
}
}
}
}
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 = 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]);
}
}
}
}
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 = 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]);
}
}
}
}
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 = 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]);
}
}
}
}
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]);
}
}
}
}

View File

@@ -0,0 +1,77 @@
// Copyright 2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <stddef.h>
#include <stdio.h>
#include "xua_unit_tests.h"
#include "../../../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
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
unsigned rndm = RANDOM_SEED;
void test_midi_queue_init(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));
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++;
}
}

View File

@@ -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 <stddef.h>
#include <stdio.h>
@@ -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;

View File

@@ -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 <stddef.h>
#include <stdio.h>
@@ -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;

View File

@@ -1,10 +1,13 @@
// 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__
#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include "../../../lib_xua/src/midi/midiinparse.h"
#include "../../../lib_xua/src/midi/midioutparse.h"
#include "../../../lib_xua/src/midi/queue.h"
#endif // __XC__
@@ -26,3 +29,87 @@ 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_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_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_c_wrapper(void * unsafe mips){
unsafe{
struct midi_in_parse_state * unsafe ptr = mips;
reset_midi_state(*ptr);
}
}
/////////////////////// Wrappers for queue test
void queue_init_c_wrapper(queue_t *q, unsigned size) {
unsafe{
queue_init(*q, size);
}
}
int queue_is_empty_c_wrapper(queue_t *unsafe q) {
unsafe{
return queue_is_empty(*q);
}
}
int queue_is_full_c_wrapper(queue_t *unsafe q) {
unsafe{
return queue_is_full(*q);
}
}
void queue_push_word_c_wrapper(queue_t *q, unsigned array[], unsigned data){
unsafe{
queue_push_word(*q, array, data);
}
}
unsigned queue_pop_word_c_wrapper(queue_t *q, unsigned array[]){
unsafe{
return queue_pop_word(*q, array);
}
}
void queue_push_byte_c_wrapper(queue_t *q, unsigned char array[], unsigned data){
unsafe{
queue_push_byte(*q, array, data);
}
}
unsigned queue_pop_byte_c_wrapper(queue_t *q, unsigned char array[]){
unsafe{
return queue_pop_byte(*q, array);
}
}
unsigned queue_items_c_wrapper(const queue_t *q){
unsafe{
return queue_items(*q);
}
}
unsigned queue_space_c_wrapper(const queue_t *q){
unsafe{
return queue_space(*q);
}
}

View File

@@ -1,9 +1,28 @@
// 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_
#include "unity.h"
#include "xua_conf.h"
#include "../../../lib_xua/src/midi/queue.h"
#ifndef __XC__
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_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
#endif /* XUA_UNIT_TESTS_H_ */

View File

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