forked from PAWPAW-Mirror/lib_xua
4
.gitignore
vendored
4
.gitignore
vendored
@@ -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
23
Jenkinsfile
vendored
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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/")
|
||||
|
||||
|
||||
81
tests/midi_test_helpers.py
Normal file
81
tests/midi_test_helpers.py
Normal 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
37
tests/test_midi/Makefile
Normal 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
|
||||
186
tests/test_midi/src/app_midi_simple.xc
Normal file
186
tests/test_midi/src/app_midi_simple.xc
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
47
tests/test_midi/src/hwsupport.xc
Normal file
47
tests/test_midi/src/hwsupport.xc
Normal 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)
|
||||
{
|
||||
}
|
||||
|
||||
28
tests/test_midi/src/xua_conf.h
Normal file
28
tests/test_midi/src/xua_conf.h
Normal 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
|
||||
8
tests/test_midi/src/xud_conf.h
Normal file
8
tests/test_midi/src/xud_conf.h
Normal 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
|
||||
60
tests/test_midi_loopback.py
Normal file
60
tests/test_midi_loopback.py
Normal 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
61
tests/test_midi_rx.py
Normal 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
59
tests/test_midi_tx.py
Normal 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
178
tests/uart_rx_checker.py
Normal 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
246
tests/uart_tx_checker.py
Normal 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)))
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
59
tests/xua_unit_tests/generate_unity_runner.py
Executable file
59
tests/xua_unit_tests/generate_unity_runner.py
Executable 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
|
||||
@@ -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()
|
||||
183
tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c
Normal file
183
tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
77
tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c
Normal file
77
tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c
Normal 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++;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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')
|
||||
Reference in New Issue
Block a user