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:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@ _build*
|
||||
.DS_Store
|
||||
*.*~
|
||||
*.swp
|
||||
*.swn
|
||||
*~
|
||||
*.swo
|
||||
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
45
tests/test_mixer_routing_input_ctrl.py
Normal file
45
tests/test_mixer_routing_input_ctrl.py
Normal 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
|
||||
19
tests/test_mixer_routing_input_ctrl/Makefile
Normal file
19
tests/test_mixer_routing_input_ctrl/Makefile
Normal 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
|
||||
200
tests/test_mixer_routing_input_ctrl/src/main.xc
Normal file
200
tests/test_mixer_routing_input_ctrl/src/main.xc
Normal 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;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_input_ctrl/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_input_ctrl/src/test_xs3_600.xn
Normal 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>
|
||||
45
tests/test_mixer_routing_input_ctrl/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_input_ctrl/src/xua_conf.h
Normal 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
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
45
tests/test_mixer_routing_output_ctrl.py
Normal file
45
tests/test_mixer_routing_output_ctrl.py
Normal 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
|
||||
19
tests/test_mixer_routing_output_ctrl/Makefile
Normal file
19
tests/test_mixer_routing_output_ctrl/Makefile
Normal 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
|
||||
221
tests/test_mixer_routing_output_ctrl/src/main.xc
Normal file
221
tests/test_mixer_routing_output_ctrl/src/main.xc
Normal 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;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_output_ctrl/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_output_ctrl/src/test_xs3_600.xn
Normal 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>
|
||||
45
tests/test_mixer_routing_output_ctrl/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_output_ctrl/src/xua_conf.h
Normal 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
|
||||
Reference in New Issue
Block a user