Added mixer control unit tests (#316)

* Added test_mixer_routing_output_ctrl
* Added test_mixer_routing_input_ctrl 
* Some minor mixer test and code improvements
* Update lib_xud dep version requirement
This commit is contained in:
Ross Owen
2023-03-08 10:53:33 +00:00
committed by GitHub
parent 3fe4593b52
commit 208491fe51
19 changed files with 754 additions and 80 deletions

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@ _build*
.DS_Store
*.*~
*.swp
*.swn
*~
*.swo

View File

@@ -13,7 +13,7 @@ DEPENDENT_MODULES = lib_locks(>=2.1.0) \
lib_mic_array(>=4.5.0) \
lib_spdif(>=4.2.1) \
lib_xassert(>=4.1.0) \
lib_xud(>=2.2.1) \
lib_xud(>=2.2.2) \
lib_adat(>=1.0.0)
MODULE_XCC_FLAGS = $(XCC_FLAGS) \

View File

@@ -381,9 +381,8 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
outuint(c_dig_rx, 0);
#endif
#if (XUA_SPDIF_TX_EN) && (NUM_USB_CHAN_OUT > 0)
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to S/PDIF Tx thread */
unsigned sample = samplesOut[SPDIF_TX_INDEX + 1];
outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward samples to S/PDIF Tx thread */
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX + 1]);
#endif
#if (XUA_NUM_PDM_MICS > 0)

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
@@ -13,14 +13,14 @@
#include "spdif.h"
#endif
#define LOCAL_CLOCK_INCREMENT 166667
#define LOCAL_CLOCK_MARGIN 1666
#define LOCAL_CLOCK_INCREMENT (166667)
#define LOCAL_CLOCK_MARGIN (1666)
#define MAX_SAMPLES 64 /* Must be power of 2 */
#define MAX_SAMPLES (64) /* Must be power of 2 */
#define MAX_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
#define MAX_ADAT_SAMPLES (8 * MAX_SAMPLES) /* Must be power of 2 */
#define SPDIF_FRAME_ERRORS_THRESH 40
#define SPDIF_FRAME_ERRORS_THRESH (40)
unsigned g_digData[10];
@@ -241,12 +241,7 @@ extern int samples_to_host_inputs_buff[NUM_USB_CHAN_IN];
int VendorAudCoreReqs(unsigned cmd, chanend c);
#pragma unsafe arrays
//#if (AUDIO_IO_TILE == PLL_REF_TILE)
#if 0
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, out port p, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
#else
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
#endif
{
timer t_local;
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
@@ -723,7 +718,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
/* Mixer requests data */
/* AudioHub requests data */
case inuint_byref(c_dig_rx, tmp):
#if (XUA_SPDIF_RX_EN)
if(spdifUnderflow)

View File

@@ -266,6 +266,49 @@ void XUA_Endpoint0_setVendorId(unsigned short vid) {
#endif // AUDIO_CLASS == 1}
}
#if (MIXER)
void InitLocalMixerState()
{
for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
{
mixer1Weights[i] = 0x8001; //-inf
}
/* Configure default connections */
// TODO this should be a loop using defines.
mixer1Weights[0] = 0;
mixer1Weights[9] = 0;
mixer1Weights[18] = 0;
mixer1Weights[27] = 0;
mixer1Weights[36] = 0;
mixer1Weights[45] = 0;
mixer1Weights[54] = 0;
mixer1Weights[63] = 0;
#if NUM_USB_CHAN_OUT > 0
/* Setup up audio output channel mapping */
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
channelMapAud[i] = i;
}
#endif
#if NUM_USB_CHAN_IN > 0
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
}
#endif
/* Init mixer inputs */
for(int j = 0; j < MAX_MIX_COUNT; j++)
for(int i = 0; i < MIX_INPUTS; i++)
{
mixSel[j][i] = i;
}
}
#endif
void concatenateAndCopyStrings(char* string1, char* string2, char* string_buffer) {
debug_printf("concatenateAndCopyStrings() for \"%s\" and \"%s\"\n", string1, string2);
@@ -412,62 +455,11 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
XUA_Endpoint0_setStrTable();
#if 0
/* Dont need to init globals.. */
/* Init tables for volumes (+ 1 for master) */
for(int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
{
volsOut[i] = 0;
mutesOut[i] = 0;
}
for(int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
{
volsIn[i] = 0;
mutesIn[i] = 0;
}
#endif
VendorRequests_Init(VENDOR_REQUESTS_PARAMS);
#if (MIXER)
/* Set up mixer default state */
for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
{
mixer1Weights[i] = 0x8001; //-inf
}
/* Configure default connections */
// TODO this should be a loop using defines.
mixer1Weights[0] = 0;
mixer1Weights[9] = 0;
mixer1Weights[18] = 0;
mixer1Weights[27] = 0;
mixer1Weights[36] = 0;
mixer1Weights[45] = 0;
mixer1Weights[54] = 0;
mixer1Weights[63] = 0;
#if NUM_USB_CHAN_OUT > 0
/* Setup up audio output channel mapping */
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
channelMapAud[i] = i;
}
#endif
#if NUM_USB_CHAN_IN > 0
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
}
#endif
/* Init mixer inputs */
for(int j = 0; j < MAX_MIX_COUNT; j++)
for(int i = 0; i < MIX_INPUTS; i++)
{
mixSel[j][i] = i;
}
InitLocalMixerState();
#endif
#ifdef VENDOR_AUDIO_REQS
@@ -520,7 +512,6 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
cfgDesc_Audio1[USB_AS_OUT_INTERFACE_DESCRIPTOR_OFFSET_FREQ + 3*i + 2] = (get_usb_to_device_rate() & 0xff0000)>> 16;
}
cfgDesc_Audio1[USB_AS_OUT_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE] = ((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff; //max packet size
cfgDesc_Audio1[USB_AS_OUT_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE + 1] = (((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff00) >> 8; //max packet size
#endif // NUM_USB_CHAN_OUT

View File

@@ -129,7 +129,7 @@ static unsigned longMul(unsigned a, unsigned b, int prec)
}
/* Update master volume i.e. i.e update weights for all channels */
static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
static void updateMasterVol(int unitID, chanend ?c_mix_ctl)
{
int x;
#if (OUT_VOLUME_IN_MIXER == 0)
@@ -138,7 +138,7 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
#if (IN_VOLUME_IN_MIXER == 0)
xc_ptr p_multIn = array_to_xc_ptr(multIn);
#endif
switch( unitID)
switch(unitID)
{
case FU_USBOUT:
{
@@ -307,7 +307,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
/* Inspect request, NOTE: these are class specific requests */
switch( sp.bRequest )
{
/* CUR Request*/
case CUR:
{
@@ -668,7 +667,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
{
return result;
}
if (dst < NUM_USB_CHAN_OUT)
{
channelMapAud[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
@@ -790,7 +789,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
if((cs > 0) && (cs < (MAX_MIX_COUNT+1)))
{
(buffer, unsigned char[])[0] = mixSel[cs-1][cn];
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, 1 );
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, 1);
}
}
}
@@ -1137,7 +1136,7 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
/* Allow time for the change - feedback to stabilise */
FeedbackStabilityDelay();
}
}
}
return XUD_SetBuffer(ep0_in, (buffer, unsigned char[]), 0);
}

View File

@@ -197,9 +197,9 @@ void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
/* Note, we don't currently support a mix input dervived from another mix
* This is not trivial to test since the current mixer implementation only allows for one
* config update per "trigger"
*/
* This is not trivial to test since the current mixer implementation only allows for one
* config update per "trigger"
*/
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
debug_printf("Iteration: %d\n", testIter);

View File

@@ -0,0 +1,45 @@
# Copyright 2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
import Pyxsim
from Pyxsim import testers
import os
import sys
def do_test(options, capfd, test_file, test_seed):
testname, _ = os.path.splitext(os.path.basename(test_file))
binary = f"{testname}/bin/{testname}.xe"
tester = testers.ComparisonTester(open("pass.expect"))
max_cycles = 15000000
simargs = [
"--max-cycles",
str(max_cycles),
]
build_options = []
build_options += ["TEST_SEED=" + str(test_seed)]
result = Pyxsim.run_on_simulator(
binary,
tester=tester,
build_options=build_options,
simargs=simargs,
capfd=capfd,
instTracing=options.enabletracing,
vcdTracing=options.enablevcdtracing,
)
return result
def test_mixer_routing_output(options, capfd, test_file, test_seed):
result = do_test(options, capfd, test_file, test_seed)
assert result

View File

@@ -0,0 +1,19 @@
DEBUG ?= 0
ifeq ($(DEBUG),1)
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
else
TEST_DEBUG_FLAGS =
endif
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -DXUD_WEAK_API=1
XCC_FLAGS = -O3 $(TEST_FLAGS)
TARGET = test_xs3_600.xn
USED_MODULES = lib_xua lib_logging lib_random
XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -0,0 +1,200 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* This tests checks the parsing of control requests to endpoint 0 cause the correct changes in mixer output routing */
#include <stdint.h>
#include <stddef.h>
#include "platform.h"
#include "xua.h"
#include "debug_print.h"
#include "assert.h"
#include "xud.h"
#include "usbaudio20.h"
#include "random.h"
#ifndef TEST_ITERATIONS
#define TEST_ITERATIONS (100)
#endif
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
/* Mixer input mapping - from xua_endpoint0.c */
extern unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
/* From xua_ep0_uacreqs.xc */
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
/* From xua_endpoint0.c */
void InitLocalMixerState();
int g_src = 0;
/* Override func in lib_xud/src/user/client/XUD_EpFunctions.c for testing purposes */
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))
{
buffer[0] = g_src;
return XUD_RES_OKAY;
}
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)
{
return XUD_RES_OKAY;
}
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)
{
assert(g_src == buffer[0]);
assert(datalength == 1);
return XUD_RES_OKAY;
}
unsafe
{
extern int volatile * const unsafe samples_to_device_map;
extern int volatile * const unsafe samples_to_host_map;
}
void Fake_Endpoint0(chanend c_mix_ctl)
{
XUD_ep ep0_out; /* Never initialised but not used */
XUD_ep ep0_in; /* Never initialised but not used */
USB_SetupPacket_t sp;
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
InitLocalMixerState();
sp.bmRequestType.Type = USB_BM_REQTYPE_TYPE_CLASS; // Note, parsing of this won't be tested since we call AudioClassRequests directly
sp.bmRequestType.Recipient = USB_BM_REQTYPE_RECIP_INTER; // Note, parsing of this won't be tested since we call AudioClassRequests directly
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
{
int unitId = ID_XU_MIXSEL;
unsigned mix = (random_get_random_number(rg) % (MAX_MIX_COUNT + 1)); // Mixs indexed from 1
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
/* Note, we don't currently support a mix input dervived from another mix
* This is not trivial to test since the current mixer implementation only allows for one
* config update per "trigger"
*/
unsigned src = random_get_random_number(rg) % (NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT);
debug_printf("Mapping mix %d input %d", mix, input);
debug_printf(" from %d", src);
PrintSourceString(src);
debug_printf("\n");
/* Create Control request data for routing change */
int cs = mix;
int cn = input;
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_H2D;
sp.bRequest = CUR;
sp.wValue = cn | (cs << 8);
sp.wIndex = (unitId << 8);
sp.wLength = 1;
g_src = src; /* This will get picked up by out implementation of XUD_GetBuffer */
/* Call the function used by Endpoint0 to parse the control data and update the mixer output routing */
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
/* Note, there is a race risk here. This could be resolved by adding a handshake to UpdateMixerOutputRouting() etc */
/* Now check the mixer setting have been modified as expected. To do this we inspect "internal"
* mixer and endpoint 0 state.
*
* Going forward we might wish to enhance the mixer API such that it can be tested as a black box.
* This would require the addition of "GET" API over it's ctrl channel
*/
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_D2H;
if(mix == 0)
{
/* If mix is 0 then we need to check that all mixers have been updated */
for(int i = 0; i < MAX_MIX_COUNT; i++)
{
assert(g_src == mixSel[i][cn]);
/* Need to read back from each mixer individually */
sp.wValue = cn | ((i + 1)<< 8);
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
}
}
else
{
assert(g_src == mixSel[cs-1][cn]);
/* Test read back. Note, the checking is in our overridden implementation of XUD_SetBuffer_EpMax*/
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
}
}
printstrln("PASS");
exit(0);
}
void Fake_XUA_AudioHub_CtrlTest(chanend c_mix_aud)
{
int readBuffNo = 0;
unsigned underflowWord = 0;
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
while(1)
{
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
}
}
void Fake_XUA_Buffer_Decouple_CtrlTest(chanend c_dec_mix)
{
unsigned samplesIn[NUM_USB_CHAN_IN];
unsigned underflowSample;
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
while(1)
{
select
{
case inuint_byref(c_dec_mix, underflowSample):
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
outuint(c_dec_mix, 0);
}
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
samplesIn[i] = inuint(c_dec_mix);
}
break;
}
}
}
int main()
{
chan c_dec_mix;
chan c_mix_aud;
chan c_mix_ctl;
par
{
/* We need "fake" versions of the AudioHub and Decouple to keep the mixer running and taking updates via
* it's control channel */
Fake_XUA_Buffer_Decouple_CtrlTest(c_dec_mix);
Fake_XUA_AudioHub_CtrlTest(c_mix_aud);
/* Mixer from lib_xua */
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
Fake_Endpoint0(c_mix_ctl);
}
/* TODO to hit this we need to fully close down i.e. kill mixer */
return 0;
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-FB265">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Tile Number="0" Reference="tile[0]"/>
<Tile Number="1" Reference="tile[1]"/>
</Node>
</Nodes>
</Package>
</Packages>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,45 @@
// Copyright 2016-2023 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 (10)
#define NUM_USB_CHAN_IN (10)
#define I2S_CHANS_DAC (10)
#define I2S_CHANS_ADC (10)
#define EXCLUDE_USB_AUDIO_MAIN
#define MIXER (1)
#define MAX_MIX_COUNT (8)
#define UAC_FORCE_FEEDBACK_EP (0)
#define XUA_NUM_PDM_MICS 0
#define XUD_TILE 1
#define AUDIO_IO_TILE 0
#ifndef MCLK_441
#define MCLK_441 (512 * 44100)
#endif
#ifndef MCLK_48
#define MCLK_48 (512 * 48000)
#endif
#define MIN_FREQ (44100)
#define MAX_FREQ (192000)
#define SPDIF_TX_INDEX 0
#define VENDOR_STR "XMOS"
#define VENDOR_ID 0x20B1
#define PRODUCT_STR_A2 "Test device"
#define PRODUCT_STR_A1 "Test device"
#define PID_AUDIO_1 1
#define PID_AUDIO_2 2
#define AUDIO_CLASS 2
#define AUDIO_CLASS_FALLBACK 0
#define BCD_DEVICE 0x1234
#define XUA_DFU_EN 0
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
#define XUA_MIC_FRAME_SIZE 240
#endif

View File

@@ -100,7 +100,7 @@ void UpdateModel(uint32_t modelOut[CHANNEL_MAP_AUD_SIZE], uint32_t modelMixerOut
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
{
uint32_t modelOut[CHANNEL_MAP_AUD_SIZE];
uint32_t modelIn[NUM_USB_CHAN_IN];
uint32_t modelIn[CHANNEL_MAP_USB_SIZE];
uint32_t modelMixerOut[MAX_MIX_COUNT];
uint32_t testCmd[] = {SET_SAMPLES_TO_HOST_MAP, SET_SAMPLES_TO_DEVICE_MAP};
@@ -146,8 +146,8 @@ void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
{
/* Make a random update to the routing - route a random source to a random destination */
unsigned map = testCmd[random_get_random_number(rg) % (sizeof(testCmd)/sizeof(testCmd[0]))];
unsigned dst = random_get_random_number(rg) % CHANNEL_MAP_AUD_SIZE;
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_OUT;
unsigned dst = random_get_random_number(rg) % CHANNEL_MAP_AUD_SIZE; // TODO this should be CHANNEL_MAP_USB_SIZE for SET_SAMPLES_TO_HOST_MAP
unsigned src = random_get_random_number(rg) % (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
switch(map)
{

View File

@@ -11,6 +11,8 @@
*/
#define CHANNEL_MAP_AUD_SIZE NUM_USB_CHAN_OUT
#define CHANNEL_MAP_USB_SIZE NUM_USB_CHAN_IN
/* Number of channel sources, the channel ordering is as follows
* i.e.
* [0:NUM_USB_CHAN_OUT-1] : Channels from USB Host

View File

@@ -0,0 +1,45 @@
# Copyright 2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
import Pyxsim
from Pyxsim import testers
import os
import sys
def do_test(options, capfd, test_file, test_seed):
testname, _ = os.path.splitext(os.path.basename(test_file))
binary = f"{testname}/bin/{testname}.xe"
tester = testers.ComparisonTester(open("pass.expect"))
max_cycles = 15000000
simargs = [
"--max-cycles",
str(max_cycles),
]
build_options = []
build_options += ["TEST_SEED=" + str(test_seed)]
result = Pyxsim.run_on_simulator(
binary,
tester=tester,
build_options=build_options,
simargs=simargs,
capfd=capfd,
instTracing=options.enabletracing,
vcdTracing=options.enablevcdtracing,
)
return result
def test_mixer_routing_output(options, capfd, test_file, test_seed):
result = do_test(options, capfd, test_file, test_seed)
assert result

View File

@@ -0,0 +1,19 @@
DEBUG ?= 0
ifeq ($(DEBUG),1)
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
else
TEST_DEBUG_FLAGS =
endif
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -DXUD_WEAK_API=1
XCC_FLAGS = -O3 $(TEST_FLAGS)
TARGET = test_xs3_600.xn
USED_MODULES = lib_xua lib_logging lib_random
XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -0,0 +1,221 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* This tests checks the parsing of control requests to endpoint 0 cause the correct changes in mixer output routing */
#include <stdint.h>
#include <stddef.h>
#include "platform.h"
#include "xua.h"
#include "debug_print.h"
#include "assert.h"
#include "xud.h"
#include "usbaudio20.h"
#include "random.h"
#ifndef TEST_ITERATIONS
#define TEST_ITERATIONS (100)
#endif
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
/* Device channel mapping */
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
extern unsigned char channelMapUsb[NUM_USB_CHAN_IN];
/* From xua_ep0_uacreqs.xc */
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
/* From xua_endpoint0.c */
void InitLocalMixerState();
int g_src = 0;
/* Override func in lib_xud/src/user/client/XUD_EpFunctions.c for testing purposes */
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))
{
buffer[0] = g_src;
return XUD_RES_OKAY;
}
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)
{
return XUD_RES_OKAY;
}
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)
{
assert(g_src == buffer[0]);
assert(datalength == 1);
return XUD_RES_OKAY;
}
unsafe
{
extern int volatile * const unsafe samples_to_device_map;
extern int volatile * const unsafe samples_to_host_map;
}
void Fake_Endpoint0(chanend c_mix_ctl)
{
XUD_ep ep0_out; /* Never initialised but not used */
XUD_ep ep0_in; /* Never initialised but not used */
unsigned unitIds[] = {ID_XU_OUT, ID_XU_IN};
USB_SetupPacket_t sp;
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
InitLocalMixerState();
sp.bmRequestType.Type = USB_BM_REQTYPE_TYPE_CLASS; // Note, parsing of this won't be tested since we call AudioClassRequests directly
sp.bmRequestType.Recipient = USB_BM_REQTYPE_RECIP_INTER; // Note, parsing of this won't be tested since we call AudioClassRequests directly
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
{
int unitId = unitIds[random_get_random_number(rg) % (sizeof(unitIds)/sizeof(unitIds[0]))];
unsigned dst = random_get_random_number(rg);
/* Note, we don't currently support a mix input derived from another mix
* This is not trivial to test since the current mixer implementation only allows for one
* config update per "trigger"
*/
int src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
switch(unitId)
{
case ID_XU_OUT:
dst %= CHANNEL_MAP_AUD_SIZE;
debug_printf("Mapping output to AudioIF: %d", dst);
debug_printf(" from %d", src);
PrintSourceString(src);
debug_printf("\n");
break;
case ID_XU_IN:
dst %= CHANNEL_MAP_USB_SIZE;
debug_printf("Mapping output to Host : %d", dst);
debug_printf(" from %d", src);
PrintSourceString(src);
debug_printf("\n");
break;
default:
printstr("ERROR: Bad cmd in stim(): ");
printintln(unitId);
break;
}
/* Create Control request data for routing change */
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_H2D;
sp.bRequest = CUR;
sp.wValue = dst & 0xff;
sp.wIndex = (unitId << 8);
sp.wLength = 1;
g_src = src; /* This will get picked up by out implementation of XUD_GetBuffer */
/* Call the function used by Endpoint0() to parse the control data and update the mixer output routing */
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
/* Note, there is a race risk here. This could be resolved by adding a handshake to UpdateMixerOutputRouting() etc */
/* Now check the mixer setting have been modified as expected. To do this we inspect "internal"
* mixer and endpoint 0 state.
*
* Going forward we might wish to enhance the mixer API such that it can be tested as a black box.
* This would require the addition of "GET" API over it's ctrl channel
*/
switch(unitId)
{
case ID_XU_OUT:
assert(g_src == channelMapAud[dst]);
unsafe
{
assert(g_src == samples_to_device_map[dst]);
}
break;
case ID_XU_IN:
assert(g_src == channelMapUsb[dst]);
unsafe
{
assert(g_src == samples_to_host_map[dst]);
}
break;
default:
assert(0);
break;
}
/* Test read back. Note, the checking is our overridden implementation of XUD_SetBuffer_EpMax*/
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_D2H;
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
}
printstrln("PASS");
exit(0);
}
void Fake_XUA_AudioHub_CtrlTest(chanend c_mix_aud)
{
int readBuffNo = 0;
unsigned underflowWord = 0;
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
while(1)
{
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
}
}
void Fake_XUA_Buffer_Decouple_CtrlTest(chanend c_dec_mix)
{
unsigned samplesIn[NUM_USB_CHAN_IN];
unsigned underflowSample;
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
while(1)
{
select
{
case inuint_byref(c_dec_mix, underflowSample):
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
outuint(c_dec_mix, 0);
}
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
samplesIn[i] = inuint(c_dec_mix);
}
break;
}
}
}
int main()
{
chan c_dec_mix;
chan c_mix_aud;
chan c_mix_ctl;
par
{
/* We need "fake" versions of the AudioHub and Decouple to keep the mixer running and taking updates via
* it's control channel */
Fake_XUA_Buffer_Decouple_CtrlTest(c_dec_mix);
Fake_XUA_AudioHub_CtrlTest(c_mix_aud);
/* Mixer from lib_xua */
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
Fake_Endpoint0(c_mix_ctl);
}
/* TODO to hit this we need to fully close down i.e. kill mixer */
return 0;
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-FB265">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Tile Number="0" Reference="tile[0]"/>
<Tile Number="1" Reference="tile[1]"/>
</Node>
</Nodes>
</Package>
</Packages>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,45 @@
// Copyright 2016-2023 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 (10)
#define NUM_USB_CHAN_IN (10)
#define I2S_CHANS_DAC (10)
#define I2S_CHANS_ADC (10)
#define EXCLUDE_USB_AUDIO_MAIN
#define MIXER (1)
#define MAX_MIX_COUNT (8)
#define UAC_FORCE_FEEDBACK_EP (0)
#define XUA_NUM_PDM_MICS 0
#define XUD_TILE 1
#define AUDIO_IO_TILE 0
#ifndef MCLK_441
#define MCLK_441 (512 * 44100)
#endif
#ifndef MCLK_48
#define MCLK_48 (512 * 48000)
#endif
#define MIN_FREQ (44100)
#define MAX_FREQ (192000)
#define SPDIF_TX_INDEX 0
#define VENDOR_STR "XMOS"
#define VENDOR_ID 0x20B1
#define PRODUCT_STR_A2 "Test device"
#define PRODUCT_STR_A1 "Test device"
#define PID_AUDIO_1 1
#define PID_AUDIO_2 2
#define AUDIO_CLASS 2
#define AUDIO_CLASS_FALLBACK 0
#define BCD_DEVICE 0x1234
#define XUA_DFU_EN 0
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
#define XUA_MIC_FRAME_SIZE 240
#endif