forked from PAWPAW-Mirror/lib_xua
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
|
.DS_Store
|
||||||
*.*~
|
*.*~
|
||||||
*.swp
|
*.swp
|
||||||
|
*.swn
|
||||||
*~
|
*~
|
||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
|||||||
lib_mic_array(>=4.5.0) \
|
lib_mic_array(>=4.5.0) \
|
||||||
lib_spdif(>=4.2.1) \
|
lib_spdif(>=4.2.1) \
|
||||||
lib_xassert(>=4.1.0) \
|
lib_xassert(>=4.1.0) \
|
||||||
lib_xud(>=2.2.1) \
|
lib_xud(>=2.2.2) \
|
||||||
lib_adat(>=1.0.0)
|
lib_adat(>=1.0.0)
|
||||||
|
|
||||||
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
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);
|
outuint(c_dig_rx, 0);
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SPDIF_TX_EN) && (NUM_USB_CHAN_OUT > 0)
|
#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 */
|
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward samples to S/PDIF Tx thread */
|
||||||
unsigned sample = samplesOut[SPDIF_TX_INDEX + 1];
|
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX + 1]);
|
||||||
outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_NUM_PDM_MICS > 0)
|
#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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
#include <xs1.h>
|
#include <xs1.h>
|
||||||
@@ -13,14 +13,14 @@
|
|||||||
#include "spdif.h"
|
#include "spdif.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOCAL_CLOCK_INCREMENT 166667
|
#define LOCAL_CLOCK_INCREMENT (166667)
|
||||||
#define LOCAL_CLOCK_MARGIN 1666
|
#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_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
|
||||||
#define MAX_ADAT_SAMPLES (8 * 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];
|
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);
|
int VendorAudCoreReqs(unsigned cmd, chanend c);
|
||||||
|
|
||||||
#pragma unsafe arrays
|
#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)
|
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;
|
timer t_local;
|
||||||
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
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)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
/* Mixer requests data */
|
/* AudioHub requests data */
|
||||||
case inuint_byref(c_dig_rx, tmp):
|
case inuint_byref(c_dig_rx, tmp):
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
if(spdifUnderflow)
|
if(spdifUnderflow)
|
||||||
|
|||||||
@@ -266,6 +266,49 @@ void XUA_Endpoint0_setVendorId(unsigned short vid) {
|
|||||||
#endif // AUDIO_CLASS == 1}
|
#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) {
|
void concatenateAndCopyStrings(char* string1, char* string2, char* string_buffer) {
|
||||||
debug_printf("concatenateAndCopyStrings() for \"%s\" and \"%s\"\n", string1, string2);
|
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();
|
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);
|
VendorRequests_Init(VENDOR_REQUESTS_PARAMS);
|
||||||
|
|
||||||
#if (MIXER)
|
#if (MIXER)
|
||||||
/* Set up mixer default state */
|
/* Set up mixer default state */
|
||||||
for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
|
InitLocalMixerState();
|
||||||
{
|
|
||||||
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
|
#endif
|
||||||
|
|
||||||
#ifdef VENDOR_AUDIO_REQS
|
#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_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] = ((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
|
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
|
#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 */
|
/* 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;
|
int x;
|
||||||
#if (OUT_VOLUME_IN_MIXER == 0)
|
#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)
|
#if (IN_VOLUME_IN_MIXER == 0)
|
||||||
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
||||||
#endif
|
#endif
|
||||||
switch( unitID)
|
switch(unitID)
|
||||||
{
|
{
|
||||||
case FU_USBOUT:
|
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 */
|
/* Inspect request, NOTE: these are class specific requests */
|
||||||
switch( sp.bRequest )
|
switch( sp.bRequest )
|
||||||
{
|
{
|
||||||
|
|
||||||
/* CUR Request*/
|
/* CUR Request*/
|
||||||
case CUR:
|
case CUR:
|
||||||
{
|
{
|
||||||
@@ -668,7 +667,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst < NUM_USB_CHAN_OUT)
|
if (dst < NUM_USB_CHAN_OUT)
|
||||||
{
|
{
|
||||||
channelMapAud[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
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)))
|
if((cs > 0) && (cs < (MAX_MIX_COUNT+1)))
|
||||||
{
|
{
|
||||||
(buffer, unsigned char[])[0] = mixSel[cs-1][cn];
|
(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 */
|
/* Allow time for the change - feedback to stabilise */
|
||||||
FeedbackStabilityDelay();
|
FeedbackStabilityDelay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return XUD_SetBuffer(ep0_in, (buffer, unsigned char[]), 0);
|
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;
|
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
|
||||||
|
|
||||||
/* Note, we don't currently support a mix input dervived from another mix
|
/* 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
|
* This is not trivial to test since the current mixer implementation only allows for one
|
||||||
* config update per "trigger"
|
* config update per "trigger"
|
||||||
*/
|
*/
|
||||||
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
|
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
|
||||||
|
|
||||||
debug_printf("Iteration: %d\n", testIter);
|
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)
|
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
||||||
{
|
{
|
||||||
uint32_t modelOut[CHANNEL_MAP_AUD_SIZE];
|
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 modelMixerOut[MAX_MIX_COUNT];
|
||||||
uint32_t testCmd[] = {SET_SAMPLES_TO_HOST_MAP, SET_SAMPLES_TO_DEVICE_MAP};
|
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 */
|
/* 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 map = testCmd[random_get_random_number(rg) % (sizeof(testCmd)/sizeof(testCmd[0]))];
|
||||||
unsigned dst = random_get_random_number(rg) % CHANNEL_MAP_AUD_SIZE;
|
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;
|
unsigned src = random_get_random_number(rg) % (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
||||||
|
|
||||||
switch(map)
|
switch(map)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
*/
|
*/
|
||||||
#define CHANNEL_MAP_AUD_SIZE NUM_USB_CHAN_OUT
|
#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
|
/* Number of channel sources, the channel ordering is as follows
|
||||||
* i.e.
|
* i.e.
|
||||||
* [0:NUM_USB_CHAN_OUT-1] : Channels from USB Host
|
* [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