forked from PAWPAW-Mirror/lib_xua
Compare commits
253 Commits
experiment
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4da4c5653 | ||
|
|
3a78f44872 | ||
|
|
425eb89e07 | ||
|
|
aef5311a4b | ||
|
|
24a62d5cfd | ||
|
|
5caee234e5 | ||
|
|
e92665174d | ||
|
|
aa769dabb4 | ||
|
|
5daee760af | ||
|
|
a96a137533 | ||
|
|
a982c24303 | ||
|
|
974ede7aab | ||
|
|
c7d0449a1f | ||
|
|
f401831766 | ||
|
|
6b055755d8 | ||
|
|
cf80a9aeaf | ||
|
|
6adf19ad93 | ||
|
|
d32ff7b3f6 | ||
|
|
a9f4f51f03 | ||
|
|
0595d8c8f7 | ||
|
|
4b2cd1c5ca | ||
|
|
ec3b8a2832 | ||
|
|
99a0535198 | ||
|
|
c9f3c53228 | ||
|
|
cb690527c9 | ||
|
|
1308f3a1cb | ||
|
|
a11195b54a | ||
|
|
89541bb88f | ||
|
|
b635b0a64b | ||
|
|
70a45d219c | ||
|
|
e4517f3776 | ||
|
|
ac0e1ebe7b | ||
|
|
7ea3ead62d | ||
|
|
a942c8af3d | ||
|
|
708f65b3e9 | ||
|
|
d861d358c4 | ||
|
|
09269c61fa | ||
|
|
f7df5fca20 | ||
|
|
4a74c81a96 | ||
|
|
ad91d19f94 | ||
|
|
f97f4dbf9b | ||
|
|
823eed0725 | ||
|
|
a9762e048a | ||
|
|
67b90f6c8c | ||
|
|
62b74a0419 | ||
|
|
a73bb8217b | ||
|
|
e1352e93d8 | ||
|
|
7a52b7dd83 | ||
|
|
8c4043fd4c | ||
|
|
6023af906e | ||
|
|
3d5b9608dc | ||
|
|
82bcb360a4 | ||
|
|
653bd73143 | ||
|
|
1ec2c28ded | ||
|
|
a81bd2ba48 | ||
|
|
415bd8605d | ||
|
|
a19d968a8b | ||
|
|
6c49d5fe36 | ||
|
|
d8cc579518 | ||
|
|
3f00a9ae10 | ||
|
|
509cd4fc2e | ||
|
|
ebf4d0e387 | ||
|
|
28a530685f | ||
|
|
d429068bcf | ||
|
|
d57559764f | ||
|
|
45ad7bc425 | ||
|
|
8627ef9744 | ||
|
|
98cfaffd4b | ||
|
|
19a18c2db5 | ||
|
|
867da0d9c9 | ||
|
|
787ffee132 | ||
|
|
7acd4ffe99 | ||
|
|
9ddfff1d60 | ||
|
|
92fd8aa11b | ||
|
|
6562a35b73 | ||
|
|
c2da737961 | ||
|
|
c5b44caeff | ||
|
|
4e4a026261 | ||
|
|
d163ccc7ef | ||
|
|
32ddf24e39 | ||
|
|
a3670d6b85 | ||
|
|
9201d7a570 | ||
|
|
655612c673 | ||
|
|
873f5bedd8 | ||
|
|
e83bbf51cf | ||
|
|
8a90660f7c | ||
|
|
ba0f07d355 | ||
|
|
cd497a0c78 | ||
|
|
bee1d878af | ||
|
|
365e9bf014 | ||
|
|
d02561da19 | ||
|
|
d55ade4ecf | ||
|
|
1848209a63 | ||
|
|
7fbf400ded | ||
|
|
ca3a7eb1f9 | ||
|
|
bbd0f2693d | ||
|
|
76ab4060d5 | ||
|
|
8a991dd638 | ||
|
|
9a8dfea641 | ||
|
|
25cd5ffafc | ||
|
|
5f4aa1f7a2 | ||
|
|
e5fb428880 | ||
|
|
aecffab0c6 | ||
|
|
82f7649079 | ||
|
|
7853807790 | ||
|
|
fb6cdbb57b | ||
|
|
5822ec7037 | ||
|
|
7967275001 | ||
|
|
c960d82233 | ||
|
|
b15eb3a329 | ||
|
|
36b32a36db | ||
|
|
540fb4baa5 | ||
|
|
398d966145 | ||
|
|
a6969a8610 | ||
|
|
53bd0e4c29 | ||
|
|
098c39b659 | ||
|
|
977408d3bf | ||
|
|
4e4ae01a35 | ||
|
|
17206d4b8f | ||
|
|
2fbeb47191 | ||
|
|
255ca79718 | ||
|
|
4589319151 | ||
|
|
e789da24d3 | ||
|
|
7ffeaf3dde | ||
|
|
9ba6425d83 | ||
|
|
8f63590956 | ||
|
|
6235c168a1 | ||
|
|
f3a0dbc79f | ||
|
|
68a1a793cc | ||
|
|
0fc8aec495 | ||
|
|
4e893d4565 | ||
|
|
c11e62e27f | ||
|
|
57d5ea7613 | ||
|
|
03a646f95d | ||
|
|
05c8c44619 | ||
|
|
0d913cdce3 | ||
|
|
165417962f | ||
|
|
cffb7a272d | ||
|
|
41566b3970 | ||
|
|
7847a5ee42 | ||
|
|
8ec5f8c7fc | ||
|
|
4d3fe82113 | ||
|
|
5980d0edea | ||
|
|
e72a386fa2 | ||
|
|
0d1f81276d | ||
|
|
7febbfdcd0 | ||
|
|
44049ecfca | ||
|
|
d49c6b4656 | ||
|
|
3be17bf8cc | ||
|
|
e8317eae36 | ||
|
|
5669a5b021 | ||
|
|
fc708fe4e9 | ||
|
|
f32955a419 | ||
|
|
a9ed38252c | ||
|
|
27a7d185d1 | ||
|
|
7126b91848 | ||
|
|
cb84d69231 | ||
|
|
8b58fe5aaa | ||
|
|
fe6afc93de | ||
|
|
eb4b19ce16 | ||
|
|
3d9d174dcc | ||
|
|
f0709d35fc | ||
|
|
4edf86b3a6 | ||
|
|
de0279d769 | ||
|
|
a12111ba55 | ||
|
|
1b6a785b03 | ||
|
|
2d1585b8b1 | ||
|
|
eb6ed9f56e | ||
|
|
af9a6b18b2 | ||
|
|
ca16467158 | ||
|
|
aac2b4b7fb | ||
|
|
c0a844c303 | ||
|
|
103aa8840b | ||
|
|
a4e6fd0194 | ||
|
|
57debd0558 | ||
|
|
de6210d1dd | ||
|
|
ce987622d9 | ||
|
|
e04ecf5fc9 | ||
|
|
d81b510102 | ||
|
|
8ef63fcdf5 | ||
|
|
529aea28dc | ||
|
|
edbadca0cd | ||
|
|
13d9229f52 | ||
|
|
a0610fc1e0 | ||
|
|
334f36e5e1 | ||
|
|
c412c81fe3 | ||
|
|
9abfa167ca | ||
|
|
c6a970d7c0 | ||
|
|
3291a05493 | ||
|
|
91d23fb1d6 | ||
|
|
2fcc9ca2ac | ||
|
|
6d8d66f823 | ||
|
|
23f1a8d48e | ||
|
|
e6899afbb9 | ||
|
|
87a105d8f6 | ||
|
|
3003ce7241 | ||
|
|
ccaaf40ab3 | ||
|
|
dc81964f22 | ||
|
|
a3419fdba7 | ||
|
|
4962cebc9c | ||
|
|
56d728f349 | ||
|
|
7f8f07b4b6 | ||
|
|
8e161707a5 | ||
|
|
b242c54574 | ||
|
|
702e8d14b9 | ||
|
|
ace59f63a4 | ||
|
|
780a407519 | ||
|
|
61f17f3fe9 | ||
|
|
d644775e4c | ||
|
|
2133598347 | ||
|
|
7b843b1d56 | ||
|
|
f035e1dc13 | ||
|
|
c5496ea994 | ||
|
|
b0db22a50b | ||
|
|
1f74f8c601 | ||
|
|
9f8a4e737f | ||
|
|
c57079cd4a | ||
|
|
5a78b5079f | ||
|
|
5b5ee132e0 | ||
|
|
15c3007d1c | ||
|
|
ab7a94a821 | ||
|
|
29156d5b19 | ||
|
|
5e5b2b7bd5 | ||
|
|
eebbb88fee | ||
|
|
db63b93ac1 | ||
|
|
32c783795b | ||
|
|
5b37c4d224 | ||
|
|
8fbe410e0e | ||
|
|
52b72285e0 | ||
|
|
2cfaff9221 | ||
|
|
0f4cb1ccb5 | ||
|
|
bd702db2c6 | ||
|
|
764fe0bfe9 | ||
|
|
f1d902306f | ||
|
|
74894341d1 | ||
|
|
a89df80da8 | ||
|
|
07ffd9221a | ||
|
|
7bbaff49af | ||
|
|
f970623edf | ||
|
|
b4c1587478 | ||
|
|
be682f2b72 | ||
|
|
86f531b6ea | ||
|
|
66e6894f95 | ||
|
|
a8a0feaf52 | ||
|
|
fc3e3636ec | ||
|
|
a796e1ee36 | ||
|
|
b49bd69abe | ||
|
|
ae550d5fc9 | ||
|
|
a485ffe41a | ||
|
|
f25a9eeade | ||
|
|
f7331a1ed3 | ||
|
|
15036f2bcc | ||
|
|
fa5723947f |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -48,3 +48,7 @@ host_usb_mixer_control/xmos_mixer
|
|||||||
**/.vscode/**
|
**/.vscode/**
|
||||||
**.egg-info
|
**.egg-info
|
||||||
*tests/logs/*
|
*tests/logs/*
|
||||||
|
midi_tx_cmds.txt
|
||||||
|
midi_rx_cmds.txt
|
||||||
|
trace.txt
|
||||||
|
tests/xua_unit_tests/src.runners
|
||||||
|
|||||||
@@ -1,6 +1,72 @@
|
|||||||
lib_xua Change Log
|
lib_xua change log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
4.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* ADDED: MIDI unit and sub-system tests
|
||||||
|
* CHANGED: Only the minimum number of ADAT input formats are enabled based
|
||||||
|
on the supported sample rates
|
||||||
|
* CHANGED: Enabling ADAT tx enables different channel count interface alts,
|
||||||
|
based on sample rate
|
||||||
|
* CHANGED: Input audio buffer size and the exit condition underflow modified
|
||||||
|
to to fix buffer underflow in some configurations
|
||||||
|
* CHANGED: CT_END token based handshake in MIDI channels transactions,
|
||||||
|
reducing opportuninity for deadlock
|
||||||
|
* FIXED: Device fails to enumerate when ADAT and S/PDIF transmit are
|
||||||
|
enabled
|
||||||
|
* FIXED: Update software PLL at the correct rate for ADAT S/MUX
|
||||||
|
* FIXED: Incorrect internal input EP count for input only devices
|
||||||
|
* FIXED: Samples transferred to ADAT tx too frequently in TDM mode
|
||||||
|
* FIXED: S/MUX not initialised to a value based on DEFAULT_FREQ in
|
||||||
|
clockgen
|
||||||
|
* FIXED: Trap when moving to DSD mode on XS3A based devices
|
||||||
|
|
||||||
|
* Changes to dependencies:
|
||||||
|
|
||||||
|
- lib_adat: 1.0.1 -> 1.2.0
|
||||||
|
|
||||||
|
- lib_locks: 2.1.0 -> 2.2.0
|
||||||
|
|
||||||
|
- lib_logging: 3.1.1 -> 3.2.0
|
||||||
|
|
||||||
|
- lib_sw_pll: 2.1.0 -> 2.2.0
|
||||||
|
|
||||||
|
- lib_xassert: 4.1.0 -> 4.2.0
|
||||||
|
|
||||||
|
4.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* ADDED: Support for XCommon CMake build system
|
||||||
|
* FIXED: Output volume control not enabled by default when MIXER disabled
|
||||||
|
* FIXED: Full 32bit result of volume processing not calculated when
|
||||||
|
required
|
||||||
|
* FIXED: Input stream sending an erroneous zero-length packet when exiting
|
||||||
|
underflow state
|
||||||
|
* FIXED Build failures when XUA_USB_EN = 0
|
||||||
|
* FIXED: Clock configuration issues when ADAT and S/PDIF receive are
|
||||||
|
enabled (#352)
|
||||||
|
* FIXED: Repeated old S/PDIF and ADAT samples when entering underflow
|
||||||
|
state
|
||||||
|
* CHANGED: QUAD_SPI_FLASH replaced by XUA_QUAD_SPI_FLASH (default: 1)
|
||||||
|
* CHANGED: UserBufferManagementInit() now takes a sample rate parameter
|
||||||
|
* CHANGED: xcore.ai targets use sigma-delta software PLL for clock recovery
|
||||||
|
of digital Rx streams and synchronous USB audio by default
|
||||||
|
* CHANGED: Windows host mixer control application now requires driver GUID
|
||||||
|
option
|
||||||
|
|
||||||
|
* Changes to dependencies:
|
||||||
|
|
||||||
|
- lib_dsp: 6.2.1 -> 6.3.0
|
||||||
|
|
||||||
|
- lib_mic_array: 4.5.0 -> 4.6.0
|
||||||
|
|
||||||
|
- lib_spdif: 5.0.1 -> 6.1.0
|
||||||
|
|
||||||
|
- lib_sw_pll: Added dependency 2.1.0
|
||||||
|
|
||||||
|
- lib_xud: 2.2.3 -> 2.3.1
|
||||||
|
|
||||||
3.5.1
|
3.5.1
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|||||||
20
Jenkinsfile
vendored
20
Jenkinsfile
vendored
@@ -1,4 +1,4 @@
|
|||||||
@Library('xmos_jenkins_shared_library@v0.24.0') _
|
@Library('xmos_jenkins_shared_library@v0.27.0') _
|
||||||
|
|
||||||
getApproval()
|
getApproval()
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@ pipeline {
|
|||||||
environment {
|
environment {
|
||||||
REPO = 'lib_xua'
|
REPO = 'lib_xua'
|
||||||
VIEW = getViewName(REPO)
|
VIEW = getViewName(REPO)
|
||||||
|
TOOLS_VERSION = "15.2.1" // For unit tests
|
||||||
}
|
}
|
||||||
options {
|
options {
|
||||||
skipDefaultCheckout()
|
skipDefaultCheckout()
|
||||||
@@ -35,7 +36,8 @@ pipeline {
|
|||||||
dir("${REPO}/tests"){
|
dir("${REPO}/tests"){
|
||||||
viewEnv(){
|
viewEnv(){
|
||||||
withVenv{
|
withVenv{
|
||||||
runPytest('--numprocesses=4')
|
sh "xmake -C test_midi -j" // Xdist does not like building so do here
|
||||||
|
runPytest('--numprocesses=auto -vvv')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,14 +45,14 @@ pipeline {
|
|||||||
}
|
}
|
||||||
stage('Unity tests') {
|
stage('Unity tests') {
|
||||||
steps {
|
steps {
|
||||||
dir("${REPO}") {
|
dir("${REPO}/tests/xua_unit_tests") {
|
||||||
dir('tests') {
|
withTools("${env.TOOLS_VERSION}") {
|
||||||
dir('xua_unit_tests') {
|
|
||||||
withVenv {
|
withVenv {
|
||||||
runWaf('.', "configure clean build --target=xcore200")
|
withEnv(["XMOS_CMAKE_PATH=${WORKSPACE}/xcommon_cmake"]) {
|
||||||
viewEnv() {
|
sh "cmake -G 'Unix Makefiles' -B build"
|
||||||
runPython("TARGET=XCORE200 pytest -s")
|
sh 'xmake -C build -j'
|
||||||
}
|
runPython("pytest -s --junitxml=pytest_unity.xml")
|
||||||
|
junit "pytest_unity.xml"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
lib_xua
|
lib_xua
|
||||||
#######
|
#######
|
||||||
|
|
||||||
:Version: 3.5.0
|
:Version: 4.0.0
|
||||||
:Vendor: XMOS
|
:Vendor: XMOS
|
||||||
|
|
||||||
:Scope: General Use
|
:Scope: General Use
|
||||||
|
|
||||||
Summary
|
Summary
|
||||||
@@ -81,14 +82,15 @@ The following application notes use this library:
|
|||||||
Required Software (dependencies)
|
Required Software (dependencies)
|
||||||
================================
|
================================
|
||||||
|
|
||||||
|
* lib_adat (www.github.com/xmos/lib_adat)
|
||||||
* lib_locks (www.github.com/xmos/lib_locks)
|
* lib_locks (www.github.com/xmos/lib_locks)
|
||||||
* lib_logging (www.github.com/xmos/lib_logging)
|
* lib_logging (www.github.com/xmos/lib_logging)
|
||||||
* lib_mic_array (www.github.com/xmos/lib_mic_array)
|
* lib_mic_array (www.github.com/xmos/lib_mic_array)
|
||||||
* lib_xassert (www.github.com/xmos/lib_xassert)
|
* lib_xassert (www.github.com/xmos/lib_xassert)
|
||||||
* lib_dsp (www.github.com/xmos/lib_dsp)
|
* lib_dsp (www.github.com/xmos/lib_dsp)
|
||||||
* lib_spdif (www.github.com/xmos/lib_spdif)
|
* lib_spdif (www.github.com/xmos/lib_spdif)
|
||||||
|
* lib_sw_pll (www.github.com/xmos/lib_sw_pll)
|
||||||
* lib_xud (www.github.com/xmos/lib_xud)
|
* lib_xud (www.github.com/xmos/lib_xud)
|
||||||
* lib_adat (www.github.com/xmos/lib_adat)
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
=============
|
=============
|
||||||
@@ -99,4 +101,3 @@ Support
|
|||||||
=======
|
=======
|
||||||
|
|
||||||
This package is supported by XMOS Ltd. Issues can be raised against the software at: http://www.xmos.com/support
|
This package is supported by XMOS Ltd. Issues can be raised against the software at: http://www.xmos.com/support
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Required hardware
|
|||||||
.................
|
.................
|
||||||
|
|
||||||
The example code provided with the application has been implemented
|
The example code provided with the application has been implemented
|
||||||
and tested on the xCORE-200 Multi-channel Audio Board
|
and tested on the xCORE.ai Multi-channel Audio Board
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
.............
|
.............
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
// Copyright 2017-2022 XMOS LIMITED.
|
// Copyright 2017-2024 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>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
#include "../../shared/apppll.h"
|
extern "C"{
|
||||||
|
#include "sw_pll.h"
|
||||||
|
}
|
||||||
|
|
||||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||||
|
|
||||||
@@ -38,19 +40,26 @@ void AudioHwInit()
|
|||||||
delay_milliseconds(100);
|
delay_milliseconds(100);
|
||||||
|
|
||||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||||
AppPllEnable_SampleRate(DEFAULT_FREQ);
|
if(DEFAULT_FREQ % 22050 == 0)
|
||||||
|
{
|
||||||
|
sw_pll_fixed_clock(MCLK_441);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sw_pll_fixed_clock(MCLK_48);
|
||||||
|
}
|
||||||
|
|
||||||
delay_milliseconds(100);
|
delay_milliseconds(100);
|
||||||
|
|
||||||
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
||||||
* It holds DAC in reset until it gets clocks anyway.
|
* It holds DAC in reset until it gets clocks anyway.
|
||||||
* Note, this example doesn't use the ADC's
|
* Note, this example doesn't use the ADCs
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configures the external audio hardware for the required sample frequency */
|
/* Configures the external audio hardware for the required sample frequency */
|
||||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||||
{
|
{
|
||||||
AppPllEnable_SampleRate(samFreq);
|
sw_pll_fixed_clock(mClk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
// Copyright 2017-2022 XMOS LIMITED.
|
// Copyright 2017-2024 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>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
#include "../../shared/apppll.h"
|
#include "xassert.h"
|
||||||
|
extern "C"{
|
||||||
|
#include "sw_pll.h"
|
||||||
|
}
|
||||||
|
|
||||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||||
|
|
||||||
@@ -38,19 +41,26 @@ void AudioHwInit()
|
|||||||
delay_milliseconds(100);
|
delay_milliseconds(100);
|
||||||
|
|
||||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||||
AppPllEnable_SampleRate(DEFAULT_FREQ);
|
if(DEFAULT_FREQ % 22050 == 0)
|
||||||
|
{
|
||||||
|
sw_pll_fixed_clock(MCLK_441);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sw_pll_fixed_clock(MCLK_48);
|
||||||
|
}
|
||||||
|
|
||||||
delay_milliseconds(100);
|
delay_milliseconds(100);
|
||||||
|
|
||||||
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
||||||
* It holds DAC in reset until it gets clocks anyway.
|
* It holds DAC in reset until it gets clocks anyway.
|
||||||
* Note, this example doesn't use the ADC's
|
* Note, this example doesn't use the ADCs
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configures the external audio hardware for the required sample frequency */
|
/* Configures the external audio hardware for the required sample frequency */
|
||||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||||
{
|
{
|
||||||
AppPllEnable_SampleRate(samFreq);
|
sw_pll_fixed_clock(mClk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
// Copyright 2022 XMOS LIMITED.
|
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "xassert.h"
|
|
||||||
|
|
||||||
// App PLL setup
|
|
||||||
#define APP_PLL_CTL_BYPASS (0) // 0 = no bypass, 1 = bypass.
|
|
||||||
#define APP_PLL_CTL_INPUT_SEL (0) // 0 = XTAL, 1 = sysPLL
|
|
||||||
#define APP_PLL_CTL_ENABLE (1) // 0 = disabled, 1 = enabled.
|
|
||||||
|
|
||||||
// 24MHz in, 24.576MHz out, integer mode
|
|
||||||
// Found exact solution: IN 24000000.0, OUT 24576000.0, VCO 2457600000.0, RD 5, FD 512, OD 10, FOD 10
|
|
||||||
#define APP_PLL_CTL_OD_48 (4) // Output divider = (OD+1)
|
|
||||||
#define APP_PLL_CTL_F_48 (511) // FB divider = (F+1)/2
|
|
||||||
#define APP_PLL_CTL_R_48 (4) // Ref divider = (R+1)
|
|
||||||
|
|
||||||
#define APP_PLL_CTL_48 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
|
|
||||||
(APP_PLL_CTL_OD_48 << 23) | (APP_PLL_CTL_F_48 << 8) | APP_PLL_CTL_R_48)
|
|
||||||
|
|
||||||
// Fractional divide is M/N
|
|
||||||
#define APP_PLL_FRAC_EN_48 (0) // 0 = disabled
|
|
||||||
#define APP_PLL_FRAC_NPLUS1_CYCLES_48 (0) // M value is this reg value + 1.
|
|
||||||
#define APP_PLL_FRAC_TOTAL_CYCLES_48 (0) // N value is this reg value + 1.
|
|
||||||
#define APP_PLL_FRAC_48 ((APP_PLL_FRAC_EN_48 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_48 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_48)
|
|
||||||
|
|
||||||
// 24MHz in, 22.5792MHz out (44.1kHz * 512), frac mode
|
|
||||||
// Found exact solution: IN 24000000.0, OUT 22579200.0, VCO 2257920000.0, RD 5, FD 470.400 (m = 2, n = 5), OD 5, FOD 10
|
|
||||||
#define APP_PLL_CTL_OD_441 (4) // Output divider = (OD+1)
|
|
||||||
#define APP_PLL_CTL_F_441 (469) // FB divider = (F+1)/2
|
|
||||||
#define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
|
|
||||||
|
|
||||||
#define APP_PLL_CTL_441 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
|
|
||||||
(APP_PLL_CTL_OD_441 << 23) | (APP_PLL_CTL_F_441 << 8) | APP_PLL_CTL_R_441)
|
|
||||||
|
|
||||||
#define APP_PLL_FRAC_EN_44 (1) // 1 = enabled
|
|
||||||
#define APP_PLL_FRAC_NPLUS1_CYCLES_44 (1) // M value is this reg value + 1.
|
|
||||||
#define APP_PLL_FRAC_TOTAL_CYCLES_44 (4) // N value is this reg value + 1.define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
|
|
||||||
#define APP_PLL_FRAC_44 ((APP_PLL_FRAC_EN_44 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_44 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_44)
|
|
||||||
|
|
||||||
#define APP_PLL_DIV_INPUT_SEL (1) // 0 = sysPLL, 1 = app_PLL
|
|
||||||
#define APP_PLL_DIV_DISABLE (0) // 1 = disabled (pin connected to X1D11), 0 = enabled divider output to pin.
|
|
||||||
#define APP_PLL_DIV_VALUE (4) // Divide by N+1 - remember there's a /2 also afterwards for 50/50 duty cycle.
|
|
||||||
#define APP_PLL_DIV ((APP_PLL_DIV_INPUT_SEL << 31) | (APP_PLL_DIV_DISABLE << 16) | APP_PLL_DIV_VALUE)
|
|
||||||
|
|
||||||
/* TODO support more than two freqs..*/
|
|
||||||
void AppPllEnable(int32_t clkFreq_hz)
|
|
||||||
{
|
|
||||||
switch(clkFreq_hz)
|
|
||||||
{
|
|
||||||
case 44100*512:
|
|
||||||
|
|
||||||
// Disable the PLL
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
|
|
||||||
// Enable the PLL to invoke a reset on the appPLL.
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
|
||||||
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
|
||||||
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
|
||||||
|
|
||||||
// Set the fractional divider if used
|
|
||||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_44);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 48000*512:
|
|
||||||
|
|
||||||
// Disable the PLL
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
|
|
||||||
// Enable the PLL to invoke a reset on the appPLL.
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
|
||||||
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
|
||||||
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
|
|
||||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
|
||||||
|
|
||||||
// Set the fractional divider if used
|
|
||||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_48);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for PLL output frequency to stabilise due to fractional divider enable
|
|
||||||
delay_microseconds(100);
|
|
||||||
|
|
||||||
// Turn on the clock output
|
|
||||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppPllEnable_SampleRate(int32_t sampleRate_hz)
|
|
||||||
{
|
|
||||||
assert(sampleRate_hz >= 22050);
|
|
||||||
|
|
||||||
if(sampleRate_hz % 22050 == 0)
|
|
||||||
{
|
|
||||||
AppPllEnable(44100*512);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AppPllEnable(48000*512);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022-2023 XMOS LIMITED.
|
// Copyright 2022-2024 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 <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -14,10 +14,20 @@
|
|||||||
// TODO
|
// TODO
|
||||||
// res, min, max
|
// res, min, max
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
int mixer_init(TCHAR guid[GUID_STR_LEN])
|
||||||
|
#else
|
||||||
int mixer_init(void)
|
int mixer_init(void)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
int ret = usb_mixer_connect(guid);
|
||||||
|
#else
|
||||||
|
int ret = usb_mixer_connect();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Open the connection to the USB mixer */
|
/* Open the connection to the USB mixer */
|
||||||
if (usb_mixer_connect() == USB_MIXER_FAILURE)
|
if (ret == USB_MIXER_FAILURE)
|
||||||
{
|
{
|
||||||
return USB_MIXER_FAILURE;
|
return USB_MIXER_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -381,8 +391,15 @@ void print_levels(const char* levelTitle, unsigned char* levels, int levelBytes)
|
|||||||
|
|
||||||
|
|
||||||
void mixer_display_usage(void) {
|
void mixer_display_usage(void) {
|
||||||
fprintf(stderr, "Usage :\n");
|
fprintf(stderr, "Usage: xmos_mixer "
|
||||||
|
#ifdef _WIN32
|
||||||
|
"-g<GUID> "
|
||||||
|
#endif
|
||||||
|
"<options>\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
#ifdef _WIN32
|
||||||
|
" -g<GUID> Driver GUID string, eg. -g{E5A2658B-817D-4A02-A1DE-B628A93DDF5D}\n"
|
||||||
|
#endif
|
||||||
" --display-info\n"
|
" --display-info\n"
|
||||||
" --display-mixer-nodes mixer_id\n"
|
" --display-mixer-nodes mixer_id\n"
|
||||||
" --display-min mixer_id\n"
|
" --display-min mixer_id\n"
|
||||||
@@ -421,97 +438,124 @@ int main (int argc, char **argv) {
|
|||||||
unsigned int mixer_index = 0;
|
unsigned int mixer_index = 0;
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
|
|
||||||
|
int min_argc;
|
||||||
|
// arg_idx is the position in the arguments to start parsing to skip the "-g" GUID option on Windows
|
||||||
|
int arg_idx;
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Driver GUID string is required on Windows
|
||||||
|
min_argc = 3;
|
||||||
|
arg_idx = 2;
|
||||||
|
#else
|
||||||
|
min_argc = 2;
|
||||||
|
arg_idx = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (argc < min_argc) {
|
||||||
if (argc < 2) {
|
|
||||||
fprintf(stderr, "ERROR :: No options passed to mixer application\n");
|
fprintf(stderr, "ERROR :: No options passed to mixer application\n");
|
||||||
mixer_display_usage();
|
mixer_display_usage();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
TCHAR driver_guid[GUID_STR_LEN];
|
||||||
|
|
||||||
|
if (strncmp(argv[1], "-g", 2) == 0) {
|
||||||
|
swprintf(driver_guid, GUID_STR_LEN, L"%hs", argv[1]+2);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR :: First option must be driver GUID\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (strcmp(argv[1], "--help") == 0) {
|
if (strcmp(argv[1], "--help") == 0) {
|
||||||
mixer_display_usage();
|
mixer_display_usage();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mixer_init() != USB_MIXER_SUCCESS) {
|
#ifdef _WIN32
|
||||||
|
int ret = mixer_init(driver_guid);
|
||||||
|
#else
|
||||||
|
int ret = mixer_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret != USB_MIXER_SUCCESS) {
|
||||||
fprintf(stderr, "ERROR :: Cannot connect\n");
|
fprintf(stderr, "ERROR :: Cannot connect\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(argv[1], "--display-info") == 0)
|
if (strcmp(argv[arg_idx], "--display-info") == 0)
|
||||||
{
|
{
|
||||||
mixer_display_info();
|
mixer_display_info();
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--display-mixer-nodes") == 0)
|
else if (strcmp(argv[arg_idx], "--display-mixer-nodes") == 0)
|
||||||
{
|
{
|
||||||
if (argv[2])
|
if (argv[arg_idx+1])
|
||||||
{
|
{
|
||||||
mixer_index = atoi(argv[2]);
|
mixer_index = atoi(argv[arg_idx+1]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||||
} else if (strcmp(argv[1], "--display-mixer-nodes") == 0) {
|
} else if (strcmp(argv[arg_idx], "--display-mixer-nodes") == 0) {
|
||||||
if (argv[2]) {
|
if (argv[2]) {
|
||||||
mixer_index = atoi(argv[2]);
|
mixer_index = atoi(argv[arg_idx+1]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||||
} else if (strcmp(argv[1], "--display-min") == 0) {
|
} else if (strcmp(argv[arg_idx], "--display-min") == 0) {
|
||||||
if (argv[2]) {
|
if (argv[arg_idx+1]) {
|
||||||
mixer_index = atoi(argv[2]);
|
mixer_index = atoi(argv[arg_idx+1]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MIN);
|
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MIN);
|
||||||
} else if (strcmp(argv[1], "--display-max") == 0) {
|
} else if (strcmp(argv[arg_idx], "--display-max") == 0) {
|
||||||
if (argv[2]) {
|
if (argv[arg_idx+1]) {
|
||||||
mixer_index = atoi(argv[2]);
|
mixer_index = atoi(argv[arg_idx+1]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MAX);
|
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MAX);
|
||||||
} else if (strcmp(argv[1], "--display-res") == 0) {
|
} else if (strcmp(argv[arg_idx], "--display-res") == 0) {
|
||||||
if (argv[2]) {
|
if (argv[arg_idx+1]) {
|
||||||
mixer_index = atoi(argv[2]);
|
mixer_index = atoi(argv[arg_idx+1]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_RES);
|
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_RES);
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--set-value") == 0) {
|
else if (strcmp(argv[arg_idx], "--set-value") == 0) {
|
||||||
unsigned int mixer_unit = 0;
|
unsigned int mixer_unit = 0;
|
||||||
double value = 0;
|
double value = 0;
|
||||||
if (argc < 5) {
|
if (argc - arg_idx < 4) {
|
||||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer_index = atoi(argv[2]);
|
mixer_index = atoi(argv[arg_idx+1]);
|
||||||
mixer_unit = atoi(argv[3]);
|
mixer_unit = atoi(argv[arg_idx+2]);
|
||||||
if (strcmp(argv[4],"-inf")==0)
|
if (strcmp(argv[arg_idx+3],"-inf")==0)
|
||||||
value = -128;
|
value = -128;
|
||||||
else
|
else
|
||||||
value = atof(argv[4]);
|
value = atof(argv[arg_idx+3]);
|
||||||
|
|
||||||
usb_mixer_set_value(mixer_index, mixer_unit, value);
|
usb_mixer_set_value(mixer_index, mixer_unit, value);
|
||||||
} else if (strcmp(argv[1], "--get-value") == 0) {
|
} else if (strcmp(argv[arg_idx], "--get-value") == 0) {
|
||||||
unsigned int mixer_unit = 0;
|
unsigned int mixer_unit = 0;
|
||||||
double result = 0;
|
double result = 0;
|
||||||
if (argc < 4) {
|
if (argc - arg_idx < 3) {
|
||||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer_index = atoi(argv[2]);
|
mixer_index = atoi(argv[arg_idx+1]);
|
||||||
mixer_unit = atoi(argv[3]);
|
mixer_unit = atoi(argv[arg_idx+2]);
|
||||||
|
|
||||||
result = usb_mixer_get_value(mixer_index, mixer_unit);
|
result = usb_mixer_get_value(mixer_index, mixer_unit);
|
||||||
if (result <= -127.996)
|
if (result <= -127.996)
|
||||||
@@ -519,99 +563,99 @@ int main (int argc, char **argv) {
|
|||||||
else
|
else
|
||||||
printf("%g\n",result);
|
printf("%g\n",result);
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--display-current-mixer-sources") == 0)
|
else if (strcmp(argv[arg_idx], "--display-current-mixer-sources") == 0)
|
||||||
{
|
{
|
||||||
if(argc < 3)
|
if(argc - arg_idx < 2)
|
||||||
{
|
{
|
||||||
usage_error();
|
usage_error();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
display_mixer_sources(atoi(argv[2]));
|
display_mixer_sources(atoi(argv[arg_idx+1]));
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--display-available-mixer-sources") == 0)
|
else if (strcmp(argv[arg_idx], "--display-available-mixer-sources") == 0)
|
||||||
{
|
{
|
||||||
if(argc < 3)
|
if(argc - arg_idx < 2)
|
||||||
{
|
{
|
||||||
usage_error();
|
usage_error();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
display_available_mixer_sources(atoi(argv[2]));
|
display_available_mixer_sources(atoi(argv[arg_idx+1]));
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[1], "--set-mixer-source") == 0)
|
else if(strcmp(argv[arg_idx], "--set-mixer-source") == 0)
|
||||||
{
|
{
|
||||||
if(argc < 5)
|
if(argc - arg_idx < 4)
|
||||||
{
|
{
|
||||||
usage_error();
|
usage_error();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_mixer_source(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
|
set_mixer_source(atoi(argv[arg_idx+1]), atoi(argv[arg_idx+2]), atoi(argv[arg_idx+3]));
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--display-aud-channel-map") == 0)
|
else if (strcmp(argv[arg_idx], "--display-aud-channel-map") == 0)
|
||||||
{
|
{
|
||||||
/* Display the channel mapping to the devices audio outputs */
|
/* Display the channel mapping to the devices audio outputs */
|
||||||
display_aud_channel_map();
|
display_aud_channel_map();
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--display-aud-channel-map-sources") == 0)
|
else if (strcmp(argv[arg_idx], "--display-aud-channel-map-sources") == 0)
|
||||||
{
|
{
|
||||||
display_aud_channel_map_sources();
|
display_aud_channel_map_sources();
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--display-daw-channel-map") == 0)
|
else if (strcmp(argv[arg_idx], "--display-daw-channel-map") == 0)
|
||||||
{
|
{
|
||||||
/* Display the channel mapping to the devices DAW output to host */
|
/* Display the channel mapping to the devices DAW output to host */
|
||||||
display_daw_channel_map();
|
display_daw_channel_map();
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--display-daw-channel-map-sources") == 0)
|
else if (strcmp(argv[arg_idx], "--display-daw-channel-map-sources") == 0)
|
||||||
{
|
{
|
||||||
display_daw_channel_map_sources();
|
display_daw_channel_map_sources();
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--set-aud-channel-map") == 0)
|
else if (strcmp(argv[arg_idx], "--set-aud-channel-map") == 0)
|
||||||
{
|
{
|
||||||
unsigned int dst = 0;
|
unsigned int dst = 0;
|
||||||
unsigned int src = 0;
|
unsigned int src = 0;
|
||||||
if (argc != 4)
|
if (argc - arg_idx != 3)
|
||||||
{
|
{
|
||||||
usage_error();
|
usage_error();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dst = atoi(argv[2]);
|
dst = atoi(argv[arg_idx+1]);
|
||||||
src = atoi(argv[3]);
|
src = atoi(argv[arg_idx+2]);
|
||||||
|
|
||||||
usb_set_aud_channel_map(dst, src);
|
usb_set_aud_channel_map(dst, src);
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "--set-daw-channel-map") == 0)
|
else if (strcmp(argv[arg_idx], "--set-daw-channel-map") == 0)
|
||||||
{
|
{
|
||||||
unsigned int dst = 0;
|
unsigned int dst = 0;
|
||||||
unsigned int src = 0;
|
unsigned int src = 0;
|
||||||
if (argc != 4)
|
if (argc - arg_idx != 3)
|
||||||
{
|
{
|
||||||
usage_error();
|
usage_error();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dst = atoi(argv[2]);
|
dst = atoi(argv[arg_idx+1]);
|
||||||
src = atoi(argv[3]);
|
src = atoi(argv[arg_idx+2]);
|
||||||
|
|
||||||
usb_set_usb_channel_map(dst, src);
|
usb_set_usb_channel_map(dst, src);
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[1], "--get-mixer-levels-input") == 0 ||
|
else if(strcmp(argv[arg_idx], "--get-mixer-levels-input") == 0 ||
|
||||||
strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
strcmp(argv[arg_idx],"--get-mixer-levels-output") == 0)
|
||||||
{
|
{
|
||||||
unsigned int dst = 0;
|
unsigned int dst = 0;
|
||||||
unsigned char levels[64];
|
unsigned char levels[64];
|
||||||
int datalength = 0;
|
int datalength = 0;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc - arg_idx < 2) {
|
||||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
if(strcmp(argv[arg_idx],"--get-mixer-levels-output") == 0)
|
||||||
offset = 1;
|
offset = 1;
|
||||||
|
|
||||||
for(int i = 0; i < 64; i++)
|
for(int i = 0; i < 64; i++)
|
||||||
levels[i] = 0;
|
levels[i] = 0;
|
||||||
|
|
||||||
dst = atoi(argv[2]);
|
dst = atoi(argv[arg_idx+1]);
|
||||||
|
|
||||||
/* Mem request to mixer with offset of 0 gives input levels */
|
/* Mem request to mixer with offset of 0 gives input levels */
|
||||||
datalength = usb_mixer_mem_get(dst, offset, levels);
|
datalength = usb_mixer_mem_get(dst, offset, levels);
|
||||||
@@ -628,7 +672,7 @@ int main (int argc, char **argv) {
|
|||||||
print_levels("Mixer Input", levels, datalength);
|
print_levels("Mixer Input", levels, datalength);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[1], "--vendor-audio-request-get") == 0)
|
else if(strcmp(argv[arg_idx], "--vendor-audio-request-get") == 0)
|
||||||
{
|
{
|
||||||
unsigned int bRequest = 0;
|
unsigned int bRequest = 0;
|
||||||
unsigned int cs = 0;
|
unsigned int cs = 0;
|
||||||
@@ -637,7 +681,7 @@ int main (int argc, char **argv) {
|
|||||||
int datalength = 0;
|
int datalength = 0;
|
||||||
unsigned char data[64];
|
unsigned char data[64];
|
||||||
|
|
||||||
if(argc < 6)
|
if(argc - arg_idx < 5)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -646,10 +690,10 @@ int main (int argc, char **argv) {
|
|||||||
for(int i = 0; i < 64; i++)
|
for(int i = 0; i < 64; i++)
|
||||||
data[i] = 0;
|
data[i] = 0;
|
||||||
|
|
||||||
bRequest = atoi(argv[2]);
|
bRequest = atoi(argv[arg_idx+1]);
|
||||||
cs = atoi(argv[3]);
|
cs = atoi(argv[arg_idx+2]);
|
||||||
cn = atoi(argv[4]);
|
cn = atoi(argv[arg_idx+3]);
|
||||||
unitId = atoi(argv[5]);
|
unitId = atoi(argv[arg_idx+4]);
|
||||||
|
|
||||||
/* Do request */
|
/* Do request */
|
||||||
datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data);
|
datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data);
|
||||||
@@ -666,7 +710,7 @@ int main (int argc, char **argv) {
|
|||||||
printf("0x%02x\n" ,data[i]);
|
printf("0x%02x\n" ,data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(strcmp(argv[1], "--vendor-audio-request-set") == 0)
|
else if(strcmp(argv[arg_idx], "--vendor-audio-request-set") == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
unsigned int bRequest = 0;
|
unsigned int bRequest = 0;
|
||||||
@@ -680,23 +724,23 @@ int main (int argc, char **argv) {
|
|||||||
data[i] = 0;
|
data[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(argc < 7)
|
if(argc - arg_idx < 6)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed - no data passed\n");
|
fprintf(stderr, "ERROR :: incorrect number of arguments passed - no data passed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
bRequest = atoi(argv[2]);
|
bRequest = atoi(argv[arg_idx+1]);
|
||||||
cs = atoi(argv[3]);
|
cs = atoi(argv[arg_idx+2]);
|
||||||
cn = atoi(argv[4]);
|
cn = atoi(argv[arg_idx+3]);
|
||||||
unitId = atoi(argv[5]);
|
unitId = atoi(argv[arg_idx+4]);
|
||||||
|
|
||||||
/* Get data */
|
/* Get data */
|
||||||
for(int i=0; i < argc-6; i++)
|
for(int i=0; i < argc-arg_idx-5; i++)
|
||||||
{
|
{
|
||||||
data[i] = atoi(argv[i+6]);
|
data[i] = atoi(argv[i+arg_idx+5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-6);
|
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-arg_idx-5);
|
||||||
|
|
||||||
if(result < 0)
|
if(result < 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022-2023 XMOS LIMITED.
|
// Copyright 2022-2024 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 <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -800,14 +800,18 @@ static int find_xmos_device(unsigned int id)
|
|||||||
|
|
||||||
// End of libusb interface functions
|
// End of libusb interface functions
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
int usb_mixer_connect(TCHAR guid[GUID_STR_LEN])
|
||||||
|
#else
|
||||||
int usb_mixer_connect()
|
int usb_mixer_connect()
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// Allocate internal storage
|
// Allocate internal storage
|
||||||
usb_mixers = (usb_mixer_handle *)malloc(sizeof(usb_mixer_handle));
|
usb_mixers = (usb_mixer_handle *)malloc(sizeof(usb_mixer_handle));
|
||||||
memset(usb_mixers, 0, sizeof(usb_mixer_handle));
|
memset(usb_mixers, 0, sizeof(usb_mixer_handle));
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
gDrvApi.LoadByGUID(_T("{E5A2658B-817D-4A02-A1DE-B628A93DDF5D}"));
|
gDrvApi.LoadByGUID(guid);
|
||||||
TUsbAudioStatus st = gDrvApi.TUSBAUDIO_EnumerateDevices();
|
TUsbAudioStatus st = gDrvApi.TUSBAUDIO_EnumerateDevices();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022-2023 XMOS LIMITED.
|
// Copyright 2022-2024 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.
|
||||||
|
|
||||||
#define USB_MIXER_SUCCESS 0
|
#define USB_MIXER_SUCCESS 0
|
||||||
@@ -22,7 +22,14 @@ enum usb_chan_type {
|
|||||||
#define RANGE (2)
|
#define RANGE (2)
|
||||||
#define MEM (3)
|
#define MEM (3)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <tchar.h>
|
||||||
|
// GUID strings are 36 characters, plus a pair of braces and NUL-termination
|
||||||
|
#define GUID_STR_LEN (36+2+1)
|
||||||
|
int usb_mixer_connect(TCHAR guid[GUID_STR_LEN]);
|
||||||
|
#else
|
||||||
int usb_mixer_connect();
|
int usb_mixer_connect();
|
||||||
|
#endif
|
||||||
int usb_mixer_disconnect();
|
int usb_mixer_disconnect();
|
||||||
|
|
||||||
/* MIXER UNIT(s) INTERFACE */
|
/* MIXER UNIT(s) INTERFACE */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
#ifndef _XUA_AUDIOHUB_H_
|
#ifndef _XUA_AUDIOHUB_H_
|
||||||
#define _XUA_AUDIOHUB_H_
|
#define _XUA_AUDIOHUB_H_
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
#include "dfu_interface.h"
|
#include "dfu_interface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "xua_clocking.h"
|
||||||
|
|
||||||
/** The audio driver thread.
|
/** The audio driver thread.
|
||||||
*
|
*
|
||||||
* This function drives I2S ports and handles samples to/from other digital
|
* This function drives I2S ports and handles samples to/from other digital
|
||||||
@@ -28,16 +30,24 @@
|
|||||||
*
|
*
|
||||||
* \param p_lrclk Nullable port for I2S sample clock
|
* \param p_lrclk Nullable port for I2S sample clock
|
||||||
*
|
*
|
||||||
* \param p_bclk Nullable port for I2S bit
|
* \param p_bclk Nullable port for I2S bit clock
|
||||||
*
|
*
|
||||||
* \param p_i2s_dac Nullable array of ports for I2S data output lines
|
* \param p_i2s_dac Nullable array of ports for I2S data output lines
|
||||||
*
|
*
|
||||||
* \param p_i2s_adc Nullable array of ports for I2S data input lines
|
* \param p_i2s_adc Nullable array of ports for I2S data input lines
|
||||||
*
|
*
|
||||||
* \param c_spdif_tx Channel connected to S/PDIF transmiter core from lib_spdif
|
* \param i_SoftPll Interface to software PLL task
|
||||||
|
*
|
||||||
|
* \param c_spdif_tx Channel connected to S/PDIF transmitter core from lib_spdif
|
||||||
*
|
*
|
||||||
* \param c_dig Channel connected to the clockGen() thread for
|
* \param c_dig Channel connected to the clockGen() thread for
|
||||||
* receiving/transmitting samples
|
* receiving/transmitting samples
|
||||||
|
*
|
||||||
|
* \param c_audio_rate_change Channel notifying ep_buffer of an mclk frequency change and sync for stable clock
|
||||||
|
*
|
||||||
|
* \param dfuInterface Interface supporting DFU methods
|
||||||
|
*
|
||||||
|
* \param c_pdm_in Channel for receiving decimated PDM samples
|
||||||
*/
|
*/
|
||||||
void XUA_AudioHub(chanend ?c_aud,
|
void XUA_AudioHub(chanend ?c_aud,
|
||||||
clock ?clk_audio_mclk,
|
clock ?clk_audio_mclk,
|
||||||
@@ -53,10 +63,13 @@ void XUA_AudioHub(chanend ?c_aud,
|
|||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__))
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__))
|
||||||
, chanend c_dig
|
, chanend c_dig
|
||||||
#endif
|
#endif
|
||||||
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN || defined(__DOXYGEN__))
|
||||||
|
, chanend c_audio_rate_change
|
||||||
|
#endif
|
||||||
|
#if (((XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)) || defined(__DOXYGEN__))
|
||||||
, server interface i_dfu ?dfuInterface
|
, server interface i_dfu ?dfuInterface
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_NUM_PDM_MICS > 0)
|
#if (XUA_NUM_PDM_MICS > 0 || defined(__DOXYGEN__))
|
||||||
, chanend c_pdm_in
|
, chanend c_pdm_in
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
@@ -76,8 +89,29 @@ void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode,
|
|||||||
|
|
||||||
#endif // __XC__
|
#endif // __XC__
|
||||||
|
|
||||||
void UserBufferManagementInit();
|
/**
|
||||||
|
* @brief User buffer management code
|
||||||
|
*
|
||||||
|
* This function is called at the sample rate of the USB Audio stack (e.g,. 48 kHz) and between the two parameter arrays
|
||||||
|
* contain a full multi-channel audio-frame. The first array carries all the data that has been received from the USB host
|
||||||
|
* and is to be presented to the audio interfaces. The second array carries all the data received from the interfaces and
|
||||||
|
* is to be presented to the USB host. The user can chose to intercept and overwrite the samples stored in these arrays.
|
||||||
|
*
|
||||||
|
* \param sampsFromUsbToAudio Samples received from USB host and to be presented to audio interfaces
|
||||||
|
*
|
||||||
|
* \param sampsFromAudioToUsb Samples received from the audio interfaces and to be presented to the USB host
|
||||||
|
*/
|
||||||
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User buffer managment init code
|
||||||
|
*
|
||||||
|
* This function is called once, before the first call to UserBufferManagement(), and can be used to initialise any
|
||||||
|
* related user state
|
||||||
|
*
|
||||||
|
* \param sampFreq The initial sample frequency
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void UserBufferManagementInit(unsigned sampFreq);
|
||||||
|
|
||||||
#endif // _XUA_AUDIOHUB_H_
|
#endif // _XUA_AUDIOHUB_H_
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
#ifndef __XUA_BUFFER_H__
|
#ifndef _XUA_BUFFER_H_
|
||||||
#define __XUA_BUFFER_H__
|
#define _XUA_BUFFER_H_
|
||||||
|
|
||||||
#if __XC__
|
#if __XC__
|
||||||
|
|
||||||
@@ -25,7 +25,9 @@
|
|||||||
* \param c_aud_ctl Audio control channel connected to Endpoint0()
|
* \param c_aud_ctl Audio control channel connected to Endpoint0()
|
||||||
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
|
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
|
||||||
* \param c_aud Channel connected to XUA_AudioHub() core
|
* \param c_aud Channel connected to XUA_AudioHub() core
|
||||||
|
* \param c_audio_rate_change Channel to notify and synchronise on audio rate change
|
||||||
* \param i_pll_ref Interface to task that toggles reference pin to CS2100
|
* \param i_pll_ref Interface to task that toggles reference pin to CS2100
|
||||||
|
* \param c_swpll_update Channel connected to software PLL task. Expects master clock counts based on USB frames.
|
||||||
*/
|
*/
|
||||||
void XUA_Buffer(
|
void XUA_Buffer(
|
||||||
chanend c_aud_out,
|
chanend c_aud_out,
|
||||||
@@ -51,8 +53,14 @@ void XUA_Buffer(
|
|||||||
, chanend c_hid
|
, chanend c_hid
|
||||||
#endif
|
#endif
|
||||||
, chanend c_aud
|
, chanend c_aud
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOXYGEN__)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
|
||||||
|
, chanend c_audio_rate_change
|
||||||
|
#if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||||
, client interface pll_ref_if i_pll_ref
|
, client interface pll_ref_if i_pll_ref
|
||||||
|
#endif
|
||||||
|
#if (XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||||
|
, chanend c_swpll_update
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -81,11 +89,18 @@ void XUA_Buffer_Ep(chanend c_aud_out,
|
|||||||
#ifdef CHAN_BUFF_CTRL
|
#ifdef CHAN_BUFF_CTRL
|
||||||
, chanend c_buff_ctrl
|
, chanend c_buff_ctrl
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOXYGEN__)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
|
||||||
|
, chanend c_audio_rate_change
|
||||||
|
#if (!XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||||
, client interface pll_ref_if i_pll_ref
|
, client interface pll_ref_if i_pll_ref
|
||||||
|
#endif
|
||||||
|
#if (XUA_USE_SW_PLL) || defined(__DOXYGEN__)
|
||||||
|
, chanend c_swpll_update
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/** Manage the data transfer between the USB audio buffer and the
|
/** Manage the data transfer between the USB audio buffer and the
|
||||||
* Audio I/O driver.
|
* Audio I/O driver.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
|
|
||||||
#ifndef _CLOCKING_H_
|
#ifndef _CLOCKING_H_
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <xs1.h>
|
#include <xs1.h>
|
||||||
|
|
||||||
|
#include "sw_pll_wrapper.h"
|
||||||
|
|
||||||
interface pll_ref_if
|
interface pll_ref_if
|
||||||
{
|
{
|
||||||
void toggle();
|
void toggle();
|
||||||
@@ -25,8 +27,24 @@ void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_sync);
|
|||||||
* \param c_clk_ctl channel connected to Endpoint0() for configuration of the
|
* \param c_clk_ctl channel connected to Endpoint0() for configuration of the
|
||||||
* clock
|
* clock
|
||||||
* \param c_clk_int channel connected to the decouple() thread for clock
|
* \param c_clk_int channel connected to the decouple() thread for clock
|
||||||
interrupts
|
* interrupts
|
||||||
|
* \param c_audio_rate_change channel to notify of master clock change
|
||||||
|
* \param p_for_mclk_count_aud port used for counting mclk and providing a timestamp
|
||||||
|
* \param c_sw_pll channel used to communicate with software PLL task
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void clockGen(streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_audio, 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_audio,
|
||||||
|
chanend c_clk_ctl,
|
||||||
|
chanend c_clk_int,
|
||||||
|
chanend c_audio_rate_change
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
, port p_for_mclk_count_aud
|
||||||
|
, chanend c_sw_pll
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
/*
|
/*
|
||||||
* @brief Defines relating to device configuration and customisation of lib_xua
|
* @brief Defines relating to device configuration and customisation of lib_xua
|
||||||
@@ -11,7 +11,9 @@
|
|||||||
#include "xua_conf.h"
|
#include "xua_conf.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Default tile arrangement */
|
/*
|
||||||
|
* Tile arrangement defines
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Location (tile) of audio I/O. Default: 0
|
* @brief Location (tile) of audio I/O. Default: 0
|
||||||
@@ -55,12 +57,9 @@
|
|||||||
#define PLL_REF_TILE AUDIO_IO_TILE
|
#define PLL_REF_TILE AUDIO_IO_TILE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* @brief Disable USB functionalty just leaving AudioHub
|
* Channel based defines
|
||||||
*/
|
*/
|
||||||
#ifndef XUA_USB_EN
|
|
||||||
#define XUA_USB_EN (1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Number of input channels (device to host). Default: NONE (Must be defined by app)
|
* @brief Number of input channels (device to host). Default: NONE (Must be defined by app)
|
||||||
@@ -79,7 +78,18 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Number of DSD output channels. Default: 0 (disabled)
|
* @brief Number of PDM microphones in the design.
|
||||||
|
*
|
||||||
|
* Default: 0
|
||||||
|
*/
|
||||||
|
#ifndef XUA_NUM_PDM_MICS
|
||||||
|
#define XUA_NUM_PDM_MICS (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of DSD output channels.
|
||||||
|
*
|
||||||
|
* Default: 0 (disabled)
|
||||||
*/
|
*/
|
||||||
#if defined(DSD_CHANS_DAC) && (DSD_CHANS_DAC != 0)
|
#if defined(DSD_CHANS_DAC) && (DSD_CHANS_DAC != 0)
|
||||||
#if defined(NATIVE_DSD) && (NATIVE_DSD == 0)
|
#if defined(NATIVE_DSD) && (NATIVE_DSD == 0)
|
||||||
@@ -91,6 +101,34 @@
|
|||||||
#define DSD_CHANS_DAC 0
|
#define DSD_CHANS_DAC 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of I2S channesl to DAC/CODEC. Must be a multiple of 2.
|
||||||
|
*
|
||||||
|
* Default: NONE (Must be defined by app)
|
||||||
|
*/
|
||||||
|
#ifndef I2S_CHANS_DAC
|
||||||
|
#error I2S_CHANS_DAC not defined
|
||||||
|
#define I2S_CHANS_DAC 2 /* Define anyway for doxygen */
|
||||||
|
#else
|
||||||
|
#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2.
|
||||||
|
*
|
||||||
|
* Default: NONE (Must be defined by app)
|
||||||
|
*/
|
||||||
|
#ifndef I2S_CHANS_ADC
|
||||||
|
#error I2S_CHANS_ADC not defined
|
||||||
|
#define I2S_CHANS_ADC 2 /* Define anyway for doxygen */
|
||||||
|
#else
|
||||||
|
#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defines relating to the interface to external audio hardware i.e. DAC/ADC
|
||||||
|
*/
|
||||||
|
|
||||||
#define XUA_PCM_FORMAT_I2S (0)
|
#define XUA_PCM_FORMAT_I2S (0)
|
||||||
#define XUA_PCM_FORMAT_TDM (1)
|
#define XUA_PCM_FORMAT_TDM (1)
|
||||||
/**
|
/**
|
||||||
@@ -120,30 +158,17 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Number of IS2 channesl to DAC/CODEC. Must be a multiple of 2.
|
* @brief Number of bits per channel for I2S/TDM. Supported values: 16/32-bit.
|
||||||
*
|
*
|
||||||
* Default: NONE (Must be defined by app)
|
* Default: 32 bits
|
||||||
*/
|
*/
|
||||||
#ifndef I2S_CHANS_DAC
|
#ifndef XUA_I2S_N_BITS
|
||||||
#error I2S_CHANS_DAC not defined
|
#define XUA_I2S_N_BITS (32)
|
||||||
#define I2S_CHANS_DAC 2 /* Define anyway for doxygen */
|
|
||||||
#else
|
|
||||||
#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (XUA_I2S_N_BITS != 16) && (XUA_I2S_N_BITS != 32)
|
||||||
/**
|
#error Unsupported value for XUA_I2S_N_BITS (only values 16/32 supported)
|
||||||
* @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2.
|
|
||||||
*
|
|
||||||
* Default: NONE (Must be defined by app)
|
|
||||||
*/
|
|
||||||
#ifndef I2S_CHANS_ADC
|
|
||||||
#error I2S_CHANS_ADC not defined
|
|
||||||
#define I2S_CHANS_ADC 2 /* Define anyway for doxygen */
|
|
||||||
#else
|
|
||||||
#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,35 +222,32 @@
|
|||||||
#define I2S_DOWNSAMPLE_CHANS_IN I2S_CHANS_ADC
|
#define I2S_DOWNSAMPLE_CHANS_IN I2S_CHANS_ADC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* @brief Number of bits per channel for I2S/TDM. Supported values: 16/32-bit.
|
* Clocking related defines
|
||||||
*
|
|
||||||
* Default: 32 bits
|
|
||||||
*/
|
*/
|
||||||
#ifndef XUA_I2S_N_BITS
|
|
||||||
#define XUA_I2S_N_BITS (32)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (XUA_I2S_N_BITS != 16) && (XUA_I2S_N_BITS != 32)
|
|
||||||
#error Unsupported value for XUA_I2S_N_BITS (only values 16/32 supported)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Max supported sample frequency for device (Hz). Default: 192000
|
* @brief Max supported sample frequency for device (Hz).
|
||||||
|
*
|
||||||
|
* Default: 192000Hz
|
||||||
*/
|
*/
|
||||||
#ifndef MAX_FREQ
|
#ifndef MAX_FREQ
|
||||||
#define MAX_FREQ (192000)
|
#define MAX_FREQ (192000)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Min supported sample frequency for device (Hz). Default 44100
|
* @brief Min supported sample frequency for device (Hz).
|
||||||
|
*
|
||||||
|
* Default: 44100Hz
|
||||||
*/
|
*/
|
||||||
#ifndef MIN_FREQ
|
#ifndef MIN_FREQ
|
||||||
#define MIN_FREQ (44100)
|
#define MIN_FREQ (44100)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Master clock defines for 44100 rates (in Hz). Default: NONE (Must be defined by app)
|
* @brief Master clock defines for 44100 rates (in Hz).
|
||||||
|
*
|
||||||
|
* Default: NONE (Must be defined by app)
|
||||||
*/
|
*/
|
||||||
#ifndef MCLK_441
|
#ifndef MCLK_441
|
||||||
#error MCLK_441 not defined
|
#error MCLK_441 not defined
|
||||||
@@ -233,7 +255,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Master clock defines for 48000 rates (in Hz). Default: NONE (Must be defined by app)
|
* @brief Master clock defines for 48000 rates (in Hz).
|
||||||
|
*
|
||||||
|
* Default: NONE (Must be defined by app)
|
||||||
*/
|
*/
|
||||||
#ifndef MCLK_48
|
#ifndef MCLK_48
|
||||||
#error MCLK_48 not defined
|
#error MCLK_48 not defined
|
||||||
@@ -241,26 +265,61 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Default device sample frequency. A safe default should be used. Default: MIN_FREQ
|
* @brief Enable/disable the use of the secondary/application PLL for generating and recovering master-clocks.
|
||||||
|
* Only available on xcore.ai devices.
|
||||||
|
*
|
||||||
|
* Default: Enabled (for xcore.ai devices)
|
||||||
|
*/
|
||||||
|
#ifndef XUA_USE_SW_PLL
|
||||||
|
#if defined(__XS3A__)
|
||||||
|
#define XUA_USE_SW_PLL (1)
|
||||||
|
#else
|
||||||
|
#define XUA_USE_SW_PLL (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default device sample frequency. A safe default should be used.
|
||||||
|
*
|
||||||
|
* Default: MIN_FREQ
|
||||||
*/
|
*/
|
||||||
#ifndef DEFAULT_FREQ
|
#ifndef DEFAULT_FREQ
|
||||||
#define DEFAULT_FREQ (MIN_FREQ)
|
#define DEFAULT_FREQ (MIN_FREQ)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Audio Class Defines */
|
#define DEFAULT_MCLK (((DEFAULT_FREQ % 7350) == 0) ? MCLK_441 : MCLK_48)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USB Audio Class Version. Default: 2 (Audio Class version 2.0)
|
* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)
|
||||||
|
*
|
||||||
|
* 0: XMOS is I2S master. 1: CODEC is I2s master.
|
||||||
|
*
|
||||||
|
* Default: 0 (XMOS is master)
|
||||||
|
*/
|
||||||
|
#ifndef CODEC_MASTER
|
||||||
|
#define CODEC_MASTER (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Audio Class defines
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB Audio Class Version
|
||||||
|
*
|
||||||
|
* Default: 2 (Audio Class version 2.0)
|
||||||
*/
|
*/
|
||||||
#ifndef AUDIO_CLASS
|
#ifndef AUDIO_CLASS
|
||||||
#define AUDIO_CLASS 2
|
#define AUDIO_CLASS (2)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether or not to fall back to Audio Class 1.0 in USB Full-speed. Default: 0 (Disabled)
|
* @brief Enable/disable fall back to Audio Class 1.0 in USB Full-speed.
|
||||||
|
*
|
||||||
|
* Default: Disabled
|
||||||
*/
|
*/
|
||||||
#ifndef AUDIO_CLASS_FALLBACK
|
#ifndef AUDIO_CLASS_FALLBACK
|
||||||
#define AUDIO_CLASS_FALLBACK 0 /* Default to not falling back to UAC 1 */
|
#define AUDIO_CLASS_FALLBACK (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,14 +348,17 @@
|
|||||||
#error AUDIO_CLASS set to 1 and FULL_SPEED_AUDIO_2 enabled!
|
#error AUDIO_CLASS set to 1 and FULL_SPEED_AUDIO_2 enabled!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
/* Feature defines */
|
* Feature defines
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Number of PDM microphones in the design. Default: None
|
* @brief Disable USB functionalty just leaving AudioHub
|
||||||
|
*
|
||||||
|
* Default: Enabled
|
||||||
*/
|
*/
|
||||||
#ifndef XUA_NUM_PDM_MICS
|
#ifndef XUA_USB_EN
|
||||||
#define XUA_NUM_PDM_MICS (0)
|
#define XUA_USB_EN (1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -350,6 +412,28 @@
|
|||||||
#define SPDIF_TX_INDEX (0)
|
#define SPDIF_TX_INDEX (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables SPDIF Rx. Default: 0 (Disabled)
|
||||||
|
*/
|
||||||
|
#ifndef XUA_SPDIF_RX_EN
|
||||||
|
#define XUA_SPDIF_RX_EN (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief S/PDIF Rx first channel index, defines which channels S/PDIF will be input on.
|
||||||
|
* Note, indexed from 0.
|
||||||
|
*
|
||||||
|
* Default: NONE (Must be defined by app when SPDIF_RX enabled)
|
||||||
|
*/
|
||||||
|
#if (XUA_SPDIF_RX_EN) || defined (__DOXYGEN__)
|
||||||
|
#ifndef SPDIF_RX_INDEX
|
||||||
|
#error SPDIF_RX_INDEX not defined and XUA_SPDIF_RX_EN defined
|
||||||
|
#define SPDIF_RX_INDEX 0 /* Default define for doxygen */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables ADAT Tx. Default: 0 (Disabled)
|
* @brief Enables ADAT Tx. Default: 0 (Disabled)
|
||||||
*/
|
*/
|
||||||
@@ -357,20 +441,35 @@
|
|||||||
#define XUA_ADAT_TX_EN (0)
|
#define XUA_ADAT_TX_EN (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Calculate max ADAT channels based on sample rate range. Used for Tx and Rx */
|
||||||
|
#if (MIN_FREQ < 88200)
|
||||||
|
#define ADAT_MAX_CHANS (8)
|
||||||
|
#elif (MIN_FREQ < 176400)
|
||||||
|
#define ADAT_MAX_CHANS (4)
|
||||||
|
#else
|
||||||
|
#define ADAT_MAX_CHANS (2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set the maximum number of channels for ADAT */
|
||||||
|
#if XUA_ADAT_TX_EN
|
||||||
|
#define ADAT_TX_MAX_CHANS ADAT_MAX_CHANS
|
||||||
|
#else
|
||||||
|
#define ADAT_TX_MAX_CHANS (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Defines which output channels (8) should be output on ADAT. Note, Output channels indexed from 0.
|
* @brief Defines which output channels (8) should be output on ADAT. Note, Output channels indexed from 0.
|
||||||
*
|
*
|
||||||
* Default: 0 (i.e. channels [0:7])
|
* Default: 0 (i.e. channels [0:7])
|
||||||
* */
|
* */
|
||||||
#ifndef ADAT_TX_INDEX
|
#if (XUA_ADAT_TX_EN) || defined(__DOXYGEN__)
|
||||||
#define ADAT_TX_INDEX (0)
|
#ifndef ADAT_TX_INDEX
|
||||||
#endif
|
#define ADAT_TX_INDEX (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
#if (ADAT_TX_INDEX + ADAT_TX_MAX_CHANS > NUM_USB_CHAN_OUT)
|
||||||
* @brief Enables SPDIF Rx. Default: 0 (Disabled)
|
#error Not enough channels for ADAT Tx
|
||||||
*/
|
#endif
|
||||||
#ifndef XUA_SPDIF_RX_EN
|
|
||||||
#define XUA_SPDIF_RX_EN (0)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -380,17 +479,11 @@
|
|||||||
#define XUA_ADAT_RX_EN (0)
|
#define XUA_ADAT_RX_EN (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/* Set the maximum number of channels for ADAT */
|
||||||
* @brief S/PDIF Rx first channel index, defines which channels S/PDIF will be input on.
|
#if XUA_ADAT_RX_EN
|
||||||
* Note, indexed from 0.
|
#define ADAT_RX_MAX_CHANS ADAT_MAX_CHANS
|
||||||
*
|
#else
|
||||||
* Default: NONE (Must be defined by app when SPDIF_RX enabled)
|
#define ADAT_RX_MAX_CHANS (0)
|
||||||
*/
|
|
||||||
#if (XUA_SPDIF_RX_EN) || defined (__DOXYGEN__)
|
|
||||||
#ifndef SPDIF_RX_INDEX
|
|
||||||
#error SPDIF_RX_INDEX not defined and XUA_SPDIF_RX_EN defined
|
|
||||||
#define SPDIF_RX_INDEX 0 /* Default define for doxygen */
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -400,30 +493,80 @@
|
|||||||
* Default: NONE (Must be defined by app when XUA_ADAT_RX_EN is true)
|
* Default: NONE (Must be defined by app when XUA_ADAT_RX_EN is true)
|
||||||
*/
|
*/
|
||||||
#if (XUA_ADAT_RX_EN) || defined(__DOXYGEN__)
|
#if (XUA_ADAT_RX_EN) || defined(__DOXYGEN__)
|
||||||
#ifndef ADAT_RX_INDEX
|
#ifndef ADAT_RX_INDEX
|
||||||
#error ADAT_RX_INDEX not defined and XUA_ADAT_RX_EN is true
|
#error ADAT_RX_INDEX not defined and XUA_ADAT_RX_EN is true
|
||||||
#define ADAT_RX_INDEX (0) /* Default define for doxygen */
|
#define ADAT_RX_INDEX (0) /* Default define for doxygen */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (ADAT_RX_INDEX + ADAT_RX_MAX_CHANS > NUM_USB_CHAN_IN)
|
||||||
|
#error Not enough channels for ADAT Rx
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (ADAT_RX_INDEX + 8 > NUM_USB_CHAN_IN)
|
|
||||||
#error Not enough channels for ADAT
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (XUA_ADAT_RX_EN)
|
|
||||||
|
|
||||||
/* Setup input stream formats for ADAT */
|
/* Setup input stream formats for ADAT */
|
||||||
#if(MAX_FREQ > 96000)
|
#if (XUA_ADAT_RX_EN)
|
||||||
#define INPUT_FORMAT_COUNT 3
|
#if (MAX_FREQ > 96000)
|
||||||
#elif(MAX_FREQ > 48000)
|
#if (MIN_FREQ > 96000)
|
||||||
#define INPUT_FORMAT_COUNT 2
|
#define INPUT_FORMAT_COUNT 1
|
||||||
#else
|
#define HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT NUM_USB_CHAN_IN
|
||||||
#define INPUT_FORMAT_COUNT 1
|
#elif (MIN_FREQ > 48000)
|
||||||
|
#define INPUT_FORMAT_COUNT 2
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT NUM_USB_CHAN_IN
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_2_CHAN_COUNT (NUM_USB_CHAN_IN - 2)
|
||||||
|
#else
|
||||||
|
#define INPUT_FORMAT_COUNT 3
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT NUM_USB_CHAN_IN
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_2_CHAN_COUNT (NUM_USB_CHAN_IN - 4)
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_3_CHAN_COUNT (NUM_USB_CHAN_IN - 6)
|
||||||
|
#endif
|
||||||
|
#elif (MAX_FREQ > 48000)
|
||||||
|
#if (MIN_FREQ > 48000)
|
||||||
|
#define INPUT_FORMAT_COUNT 1
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT NUM_USB_CHAN_IN
|
||||||
|
#else
|
||||||
|
#define INPUT_FORMAT_COUNT 2
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT NUM_USB_CHAN_IN
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_2_CHAN_COUNT (NUM_USB_CHAN_IN - 4)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define INPUT_FORMAT_COUNT 1
|
||||||
|
#define HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT NUM_USB_CHAN_IN
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT NUM_USB_CHAN_IN
|
/* Setup output stream formats for ADAT */
|
||||||
#define HS_STREAM_FORMAT_INPUT_2_CHAN_COUNT (NUM_USB_CHAN_IN - 4)
|
#if (XUA_ADAT_TX_EN)
|
||||||
#define HS_STREAM_FORMAT_INPUT_3_CHAN_COUNT (NUM_USB_CHAN_IN - 6)
|
#if (MAX_FREQ > 96000)
|
||||||
|
#if (MIN_FREQ > 96000)
|
||||||
|
#define OUTPUT_FORMAT_COUNT 1
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#elif (MIN_FREQ > 48000)
|
||||||
|
#define OUTPUT_FORMAT_COUNT 2
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT (NUM_USB_CHAN_OUT - 2)
|
||||||
|
#else
|
||||||
|
#define OUTPUT_FORMAT_COUNT 3
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT (NUM_USB_CHAN_OUT - 4)
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT (NUM_USB_CHAN_OUT - 6)
|
||||||
|
#endif
|
||||||
|
#elif (MAX_FREQ > 48000)
|
||||||
|
#if (MIN_FREQ > 48000)
|
||||||
|
#define OUTPUT_FORMAT_COUNT 1
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#else
|
||||||
|
#define OUTPUT_FORMAT_COUNT 2
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT (NUM_USB_CHAN_OUT - 4)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define OUTPUT_FORMAT_COUNT 1
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#endif
|
||||||
|
#define STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS 24
|
||||||
|
#define STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS 24
|
||||||
|
#define STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS 24
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -461,12 +604,11 @@
|
|||||||
* You must also supply your own function to deal with the HID endpoint(s)
|
* You must also supply your own function to deal with the HID endpoint(s)
|
||||||
* in this case.
|
* in this case.
|
||||||
*/
|
*/
|
||||||
#if( 0 < HID_CONTROLS )
|
#if (HID_CONTROLS) || defined (__DOXYGEN__)
|
||||||
#define XUA_HID_ENABLED (1)
|
#define XUA_HID_ENABLED (1)
|
||||||
#define XUA_OR_STATIC_HID_ENABLED (1)
|
#define XUA_OR_STATIC_HID_ENABLED (1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(__static_hid_report_h_exists__)
|
#if defined(__static_hid_report_h_exists__)
|
||||||
#define XUA_OR_STATIC_HID_ENABLED (1)
|
#define XUA_OR_STATIC_HID_ENABLED (1)
|
||||||
#endif
|
#endif
|
||||||
@@ -482,17 +624,6 @@
|
|||||||
#define HID_OUT_REQUIRED (0)
|
#define HID_OUT_REQUIRED (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)
|
|
||||||
*
|
|
||||||
* 0: XMOS is I2S master. 1: CODEC is I2s master.
|
|
||||||
*
|
|
||||||
* Default: 0 (XMOS is master)
|
|
||||||
*/
|
|
||||||
#ifndef CODEC_MASTER
|
|
||||||
#define CODEC_MASTER (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Serial Number String used by the device
|
* @brief Serial Number String used by the device
|
||||||
*
|
*
|
||||||
@@ -912,7 +1043,18 @@
|
|||||||
#define HS_STREAM_FORMAT_INPUT_3_CHAN_COUNT NUM_USB_CHAN_IN
|
#define HS_STREAM_FORMAT_INPUT_3_CHAN_COUNT NUM_USB_CHAN_IN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Channel count defines for output streams */
|
||||||
|
#ifndef HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT
|
||||||
|
#define HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT NUM_USB_CHAN_OUT
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sample sub-slot size (bytes) of input stream Alternate 1 when running in high-speed
|
* @brief Sample sub-slot size (bytes) of input stream Alternate 1 when running in high-speed
|
||||||
@@ -1135,7 +1277,11 @@
|
|||||||
|
|
||||||
/* Handle out volume control in the mixer - enabled by default */
|
/* Handle out volume control in the mixer - enabled by default */
|
||||||
#ifndef OUT_VOLUME_IN_MIXER
|
#ifndef OUT_VOLUME_IN_MIXER
|
||||||
#define OUT_VOLUME_IN_MIXER (1)
|
#if MIXER
|
||||||
|
#define OUT_VOLUME_IN_MIXER (1)
|
||||||
|
#else
|
||||||
|
#define OUT_VOLUME_IN_MIXER (0)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
|
/* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
|
||||||
@@ -1148,7 +1294,7 @@
|
|||||||
#define IN_VOLUME_IN_MIXER (0)
|
#define IN_VOLUME_IN_MIXER (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
|
/* Apply in volume controls after the mix. Only relevant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
|
||||||
#ifndef IN_VOLUME_AFTER_MIX
|
#ifndef IN_VOLUME_AFTER_MIX
|
||||||
#define IN_VOLUME_AFTER_MIX (1)
|
#define IN_VOLUME_AFTER_MIX (1)
|
||||||
#endif
|
#endif
|
||||||
@@ -1172,7 +1318,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
#if (XUA_SPDIF_RX_EN|| ADAT_RX)
|
#if (XUA_SPDIF_RX_EN|| XUA_ADAT_RX_EN)
|
||||||
#error "Digital input streams not supported in Sync mode"
|
#error "Digital input streams not supported in Sync mode"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -1190,7 +1336,9 @@ enum USBEndpointNumber_In
|
|||||||
#if (NUM_USB_CHAN_IN == 0) || defined (UAC_FORCE_FEEDBACK_EP)
|
#if (NUM_USB_CHAN_IN == 0) || defined (UAC_FORCE_FEEDBACK_EP)
|
||||||
ENDPOINT_NUMBER_IN_FEEDBACK,
|
ENDPOINT_NUMBER_IN_FEEDBACK,
|
||||||
#endif
|
#endif
|
||||||
|
#if (NUM_USB_CHAN_IN != 0)
|
||||||
ENDPOINT_NUMBER_IN_AUDIO,
|
ENDPOINT_NUMBER_IN_AUDIO,
|
||||||
|
#endif
|
||||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
|
||||||
ENDPOINT_NUMBER_IN_INTERRUPT, /* Audio interrupt/status EP */
|
ENDPOINT_NUMBER_IN_INTERRUPT, /* Audio interrupt/status EP */
|
||||||
#endif
|
#endif
|
||||||
@@ -1349,7 +1497,7 @@ enum USBEndpointNumber_Out
|
|||||||
/* Some defines that allow us to remove unused code */
|
/* Some defines that allow us to remove unused code */
|
||||||
|
|
||||||
/* Useful for dropping lower part of macs in volume processing... */
|
/* Useful for dropping lower part of macs in volume processing... */
|
||||||
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
|
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \
|
||||||
(((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \
|
(((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \
|
||||||
(((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2))
|
(((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2))
|
||||||
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1
|
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1
|
||||||
@@ -1383,29 +1531,29 @@ enum USBEndpointNumber_Out
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Useful for dropping lower part of macs in volume processing... */
|
/* Useful for dropping lower part of macs in volume processing... */
|
||||||
#if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (FS_STREAM_FORMAT_INPUT_2_RESOLUTION_BITS > 24)
|
#if (FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS > 24)
|
||||||
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1
|
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 1
|
||||||
#else
|
#else
|
||||||
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0
|
#define STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4))
|
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 4))
|
||||||
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1
|
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 1
|
||||||
#else
|
#else
|
||||||
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0
|
#define STREAM_FORMAT_INPUT_SUBSLOT_4_USED 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3))
|
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 3))
|
||||||
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1
|
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 1
|
||||||
#else
|
#else
|
||||||
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0
|
#define STREAM_FORMAT_INPUT_SUBSLOT_3_USED 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2))
|
#if((FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2) || (HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES == 2))
|
||||||
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1
|
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 1
|
||||||
#else
|
#else
|
||||||
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0
|
#define STREAM_FORMAT_INPUT_SUBSLOT_2_USED 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_FREQ < MIN_FREQ
|
#if MAX_FREQ < MIN_FREQ
|
||||||
#error MAX_FREQ should be >= MIN_FREQ!!
|
#error MAX_FREQ should be >= MIN_FREQ!!
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
#ifndef _XUA_MIDI_H_
|
#ifndef _XUA_MIDI_H_
|
||||||
#define _XUA_MIDI_H_
|
#define _XUA_MIDI_H_
|
||||||
@@ -57,24 +57,25 @@ void midi_get_ack_or_data(chanend c, int &is_ack, unsigned int &datum);
|
|||||||
INLINE void midi_get_ack_or_data(chanend c, int &is_ack, unsigned int &datum) {
|
INLINE void midi_get_ack_or_data(chanend c, int &is_ack, unsigned int &datum) {
|
||||||
if (testct(c)) {
|
if (testct(c)) {
|
||||||
is_ack = 1;
|
is_ack = 1;
|
||||||
(void) inct(c); // read 1-bytes control token
|
chkct(c, XS1_CT_END);
|
||||||
(void) inuchar(c);
|
|
||||||
(void) inuchar(c);
|
|
||||||
(void) inuchar(c);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
is_ack = 0;
|
is_ack = 0;
|
||||||
datum = inuint(c);
|
datum = inuint(c);
|
||||||
|
chkct(c, XS1_CT_END);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
INLINE void midi_send_ack(chanend c) {
|
INLINE void midi_send_ack(chanend c) {
|
||||||
outct(c, MIDI_ACK);
|
outct(c, XS1_CT_END);
|
||||||
outuchar(c, 0);
|
|
||||||
outuchar(c, 0);
|
|
||||||
outuchar(c, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE void midi_send_data(chanend c, unsigned int datum) {
|
||||||
|
outuint(c, datum);
|
||||||
|
outct(c, XS1_CT_END);
|
||||||
|
}
|
||||||
|
|
||||||
#define MIDI_RATE (31250)
|
#define MIDI_RATE (31250)
|
||||||
#define MIDI_BITTIME (XS1_TIMER_MHZ * 1000000 / MIDI_RATE)
|
#define MIDI_BITTIME (XS1_TIMER_MHZ * 1000000 / MIDI_RATE)
|
||||||
#define MIDI_BITTIME_2 (MIDI_BITTIME>>1)
|
#define MIDI_BITTIME_2 (MIDI_BITTIME>>1)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ Frequencies and Clocks
|
|||||||
.. doxygendefine:: DEFAULT_FREQ
|
.. doxygendefine:: DEFAULT_FREQ
|
||||||
.. doxygendefine:: MCLK_441
|
.. doxygendefine:: MCLK_441
|
||||||
.. doxygendefine:: MCLK_48
|
.. doxygendefine:: MCLK_48
|
||||||
|
.. doxygendefine:: XUA_USE_SW_PLL
|
||||||
|
|
||||||
Audio Class
|
Audio Class
|
||||||
-----------
|
-----------
|
||||||
|
|||||||
@@ -1,74 +1,49 @@
|
|||||||
Required User Function Definitions
|
|newpage|
|
||||||
==================================
|
|
||||||
|
|
||||||
The following functions need to be defined by an application using the XMOS USB Audio framework.
|
User Function Definitions
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The following functions can be defined by an application using `lib_xua`.
|
||||||
|
|
||||||
|
.. note:: Default, empty, implementations of these functions are provided in `lib_xua`. These are marked
|
||||||
|
as weak symbols so the application can simply define its own version of them.
|
||||||
|
|
||||||
External Audio Hardware Configuration Functions
|
External Audio Hardware Configuration Functions
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
.. c:function:: void AudioHwInit(chanend ?c_codec)
|
The following functions can be optionally used by the design to configure external audio hardware.
|
||||||
|
As a minimum, in most applications, it is expected that a implementation of `AudioHwConfig()` will need
|
||||||
|
to be provided.
|
||||||
|
|
||||||
This function is called when the audio core starts after the
|
.. doxygenfunction:: AudioHwInit
|
||||||
device boots up and should initialize the external audio harware e.g. clocking, DAC, ADC etc
|
.. doxygenfunction:: AudioHwConfig
|
||||||
|
.. doxygenfunction:: AudioHwConfig_Mute
|
||||||
:param c_codec: An optional chanend that was original passed into
|
.. doxygenfunction:: AudioHwConfig_UnMute
|
||||||
:c:func:`audio` that can be used to communicate
|
|
||||||
with other cores.
|
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: void AudioHwConfig(unsigned samFreq, unsigned mclk, chanend ?c_codec, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
Audio Stream Start/Stop Functions
|
||||||
|
---------------------------------
|
||||||
This function is called when the audio core starts or changes
|
|
||||||
sample rate. It should configure the extenal audio hardware to run at the specified
|
|
||||||
sample rate given the supplied master clock frequency.
|
|
||||||
|
|
||||||
:param samFreq: The sample frequency in Hz that the hardware should be configured to (in Hz).
|
|
||||||
|
|
||||||
:param mclk: The master clock frequency that is required in Hz.
|
|
||||||
|
|
||||||
:param c_codec: An optional chanend that was original passed into
|
|
||||||
:c:func:`audio` that can be used to communicate
|
|
||||||
with other cores.
|
|
||||||
|
|
||||||
:param dsdMode: Signifies if the audio hardware should be configured for DSD operation
|
|
||||||
|
|
||||||
:param sampRes_DAC: The sample resolution of the DAC stream
|
|
||||||
|
|
||||||
:param sampRes_ADC: The sample resolution of the ADC stream
|
|
||||||
|
|
||||||
|
|
||||||
Audio Streaming Functions
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
The following functions can be optionally used by the design. They can be useful for mute lines etc.
|
The following functions can be optionally used by the design. They can be useful for mute lines etc.
|
||||||
|
|
||||||
.. c:function:: void AudioStreamStart(void)
|
.. doxygenfunction:: UserAudioStreamStart
|
||||||
|
.. doxygenfunction:: UserAudioStreamStop
|
||||||
|
.. doxygenfunction:: UserAudioInputStreamStart
|
||||||
|
.. doxygenfunction:: UserAudioInputStreamStop
|
||||||
|
.. doxygenfunction:: UserAudioOutputStreamStart
|
||||||
|
.. doxygenfunction:: UserAudioOutputStreamStop
|
||||||
|
|
||||||
This function is called when the audio stream from device to host
|
Host Active Functions
|
||||||
starts.
|
---------------------
|
||||||
|
|
||||||
.. c:function:: void AudioStreamStop(void)
|
|
||||||
|
|
||||||
This function is called when the audio stream from device to host stops.
|
|
||||||
|
|
||||||
Host Active
|
|
||||||
-----------
|
|
||||||
|
|
||||||
The following function can be used to signal that the device is connected to a valid host.
|
The following function can be used to signal that the device is connected to a valid host.
|
||||||
|
|
||||||
This is called on a change in state.
|
.. doxygenfunction:: UserHostActive
|
||||||
|
|
||||||
.. c:function:: void AudioStreamStart(int active)
|
|
||||||
|
|
||||||
:param active: Indicates if the host is active or not. 1 for active else 0.
|
|
||||||
|
|
||||||
|
|
||||||
HID Controls
|
HID Controls
|
||||||
------------
|
------------
|
||||||
|
|
||||||
The following function is called when the device wishes to read physical user input (buttons etc).
|
The following function is called when the device wishes to read physical user input (buttons etc).
|
||||||
|
The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used.
|
||||||
|
|
||||||
.. c:function:: void UserReadHIDButtons(unsigned char hidData[])
|
.. doxygenfunction:: UserHIDGetData
|
||||||
|
|
||||||
:param hidData: The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used.
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ In addition :ref:`usb_audio_optional_components` shows optional components that
|
|||||||
* - Clockgen
|
* - Clockgen
|
||||||
- Drives an external frequency generator (PLL) and manages
|
- Drives an external frequency generator (PLL) and manages
|
||||||
changes between internal clocks and external clocks arising
|
changes between internal clocks and external clocks arising
|
||||||
from digital input.
|
from digital input. On xcore.ai Clockgen may also work in
|
||||||
|
conjunction with lib_sw_pll to produce a local clock from
|
||||||
|
the XCORE which is locked to the incoming digital stream.
|
||||||
* - MIDI
|
* - MIDI
|
||||||
- Outputs and inputs MIDI over a serial UART interface.
|
- Outputs and inputs MIDI over a serial UART interface.
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,11 @@ The S/PDIF receiver should be called on the appropriate tile::
|
|||||||
With the steps above an S/PDIF stream can be captured by the xCORE. To be functionally useful the audio
|
With the steps above an S/PDIF stream can be captured by the xCORE. To be functionally useful the audio
|
||||||
master clock must be able to synchronise to this external digital stream. Additionally, the host can be
|
master clock must be able to synchronise to this external digital stream. Additionally, the host can be
|
||||||
notified regarding changes in the validity of this stream, it's frequency etc. To synchronise to external
|
notified regarding changes in the validity of this stream, it's frequency etc. To synchronise to external
|
||||||
streams the codebase assumes the use of an external Cirrus Logic CS2100 device.
|
streams the codebase assumes the use of an external Cirrus Logic CS2100 device or lib_sw_pll on xcore.ai designs.
|
||||||
|
|
||||||
The ``ClockGen()`` task from ``lib_xua`` provides the reference signal to the CS2100 device and also handles
|
The ``ClockGen()`` task from ``lib_xua`` provides the reference signal to the CS2100 device or timing information
|
||||||
recording of clock validity etc. See :ref:`usb_audio_sec_clock_recovery` for full details regarding ``ClockGen()``.
|
to lib_sw_pll and also handles recording of clock validity etc.
|
||||||
|
See :ref:`usb_audio_sec_clock_recovery` for full details regarding ``ClockGen()``.
|
||||||
|
|
||||||
It also provides a small FIFO for S/PDIF samples before they are forwarded to the ``AudioHub`` core.
|
It also provides a small FIFO for S/PDIF samples before they are forwarded to the ``AudioHub`` core.
|
||||||
As such it requires to be inserted in the communication path between the S/PDIF receiver and the
|
As such it requires to be inserted in the communication path between the S/PDIF receiver and the
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ Three methods of generating an audio master clock are provided on the board:
|
|||||||
|
|
||||||
* A Skyworks Si5351B PLL device. The Si5351 is an I2C configurable clock generator that is ideally suited for replacing crystals, crystal oscillators, VCXOs, phase-locked loops (PLLs), and fanout buffers.
|
* A Skyworks Si5351B PLL device. The Si5351 is an I2C configurable clock generator that is ideally suited for replacing crystals, crystal oscillators, VCXOs, phase-locked loops (PLLs), and fanout buffers.
|
||||||
|
|
||||||
* xCORE.ai devices are equipped with a secondary (or 'application') PLL which can be used to generate audio clocks
|
* xCORE.ai devices are equipped with a secondary (or 'application') PLL which can be used to generate fixed audio clocks or recover external clocks using lib_sw_pll.
|
||||||
|
|
||||||
Selection between these methods is done via writing to bits 6 and 7 of PORT 8D on tile[0].
|
Selection between these methods is done via writing to bits 6 and 7 of PORT 8D on tile[0].
|
||||||
|
|
||||||
Either the locally generated clock (from the PL611) or the recovered low jitter clock (from the CS2100) may be selected to clock the audio stages; the xCORE-200, the ADC/DAC and Digital output stages. Selection is controlled via an additional I/O, bit 5 of PORT 8C, see :ref:`hw_316_ctrlport`.
|
Either the locally generated clock (from the PL611) or the recovered low jitter clock (from the CS2100) may be selected to clock the audio stages; the xcore.ai, the ADC/DAC and Digital output stages. Selection is controlled via an additional I/O, bit 5 of PORT 8C, see :ref:`hw_316_ctrlport`.
|
||||||
|
|
||||||
.. _hw_316_ctrlport:
|
.. _hw_316_ctrlport:
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ This must be a 1-bit port, for example::
|
|||||||
|
|
||||||
<Port Location="XS1_PORT_1A" Name="PORT_SPDIF_IN"/>
|
<Port Location="XS1_PORT_1A" Name="PORT_SPDIF_IN"/>
|
||||||
|
|
||||||
When S/PDIF receive is enabled the codebase expects to drive a synchronisation signal to an external
|
When S/PDIF receive is enabled the codebase expects to either drive a synchronisation signal to an external
|
||||||
Cirrus Logic CS2100 device for master-clock generation.
|
Cirrus Logic CS2100 device or use lib_swp_pll (xcore.ai only) for master-clock generation.
|
||||||
|
|
||||||
The programmer should ensure the define in :ref:`opt_spdif_rx_ref_defines` is set appropriately.
|
The programmer should ensure the define in :ref:`opt_spdif_rx_ref_defines` is set appropriately.
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,11 @@ Setting the synchronisation mode of the device is done using the define in :ref:
|
|||||||
- USB synchronisation mode
|
- USB synchronisation mode
|
||||||
- ``XUA_SYNCMODE_ASYNC``
|
- ``XUA_SYNCMODE_ASYNC``
|
||||||
|
|
||||||
When operating in synchronous mode an external Cirrus Logic CS2100 device is required for master clock
|
When operating in synchronous mode a local master clock must be generated that is synchronised to the incoming
|
||||||
generation. The codebase expects to drive a synchronisation signal to this external device
|
SoF rate from USB. Either an external Cirrus Logic CS2100 device is required for this purpose
|
||||||
|
or, on xcore.ai devices, the on-chip application PLL may be used via lib_sw_pll.
|
||||||
|
In the case of using the CS2100, the codebase expects to drive a synchronisation signal to this external device
|
||||||
|
as a reference.
|
||||||
|
|
||||||
The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately.
|
The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately.
|
||||||
|
|
||||||
@@ -56,8 +59,11 @@ The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set ap
|
|||||||
* - ``PLL_REF_TILE``
|
* - ``PLL_REF_TILE``
|
||||||
- Tile location of reference to CS2100 device
|
- Tile location of reference to CS2100 device
|
||||||
- ``AUDIO_IO_TILE``
|
- ``AUDIO_IO_TILE``
|
||||||
|
* - ``XUA_USE_SW_PLL``
|
||||||
|
- Whether or not to use sw_pll to recover the clock (xcore.ai only)
|
||||||
|
- 1 for xcore.ai targets. May be overridden to 0 in ``xua_conf.h``
|
||||||
|
|
||||||
The codebase expects this reference signal port to be defined in the application XN file as ``PORT_PLL_REF``.
|
The codebase expects the CS2100 reference signal port to be defined in the application XN file as ``PORT_PLL_REF``.
|
||||||
This may be a port of any bit-width, however, connection to bit[0] is assumed::
|
This may be a port of any bit-width, however, connection to bit[0] is assumed::
|
||||||
|
|
||||||
<Port Location="XS1_PORT_1A" Name="PORT_PLL_REF"/>
|
<Port Location="XS1_PORT_1A" Name="PORT_PLL_REF"/>
|
||||||
|
|||||||
@@ -15,32 +15,35 @@ the xCORE.
|
|||||||
|
|
||||||
Using an external PLL/Clock Multiplier allows an Asynchronous mode design to lock to an external
|
Using an external PLL/Clock Multiplier allows an Asynchronous mode design to lock to an external
|
||||||
clock source from a digital stream (e.g. S/PDIF or ADAT input). The codebase supports the Cirrus
|
clock source from a digital stream (e.g. S/PDIF or ADAT input). The codebase supports the Cirrus
|
||||||
Logic CS2100 device for this purpose. Other devices may be supported via code modification.
|
Logic CS2100 device or use of lib_sw_pll (xcore.ai only) for this purpose. Other devices may be
|
||||||
|
supported via code modification.
|
||||||
|
|
||||||
.. note::
|
The Clock Recovery core (Clock Gen) is responsible for either generating the reference frequency
|
||||||
|
to the CS2100 device or driving lib_sw_pll from time measurements based on the local master clock
|
||||||
|
and the time of received samples. Clock Gen (via CS2100 or lib_sw_pll) generates the master clock
|
||||||
|
used over the whole design. This core also serves as a smaller buffer between ADAT and S/PDIF
|
||||||
|
receiving cores and the Audio Hub core.
|
||||||
|
|
||||||
It is expected that in a future release the secondary PLL in xCORE.ai devices, coupled with
|
When using lib_sw_pll (xcore.ai only) an further core is instantiated which performs the sigma-delta
|
||||||
associated software changes, will be capable of replacing the CS2100 part for most designs.
|
modulation of the xCORE PLL to ensure the lowest jitter over the audio band. See lib_sw_pll
|
||||||
|
documentation for further details.
|
||||||
The Clock Recovery core (Clock Gen) is responsible for generating the reference frequency
|
|
||||||
to the CS2100 device. This, in turn, generates the master clock used over the whole design.
|
|
||||||
This core also serves as a smaller buffer between ADAT and S/PDIF receiving cores and the Audio Hub
|
|
||||||
core.
|
|
||||||
|
|
||||||
When running in *Internal Clock* mode this core simply generates this clock using a local
|
When running in *Internal Clock* mode this core simply generates this clock using a local
|
||||||
timer, based on the XMOS reference clock.
|
timer, based on the XMOS reference clock.
|
||||||
|
|
||||||
When running in an external clock mode (i.e. S/PDIF Clock" or "ADAT Clock" mode) samples are
|
When running in an external clock mode (i.e. S/PDIF Clock" or "ADAT Clock" mode) samples are
|
||||||
received from the S/PDIF and/or ADAT receive core. The external frequency is calculated through
|
received from the S/PDIF and/or ADAT receive core. The external frequency is calculated through
|
||||||
counting samples in a given period. The reference clock to the CS2100 is then generated based on
|
counting samples in a given period. Either the reference clock to the CS2100 is then generated based on
|
||||||
the reception of these samples.
|
the reception of these samples or the timing information is provided to lib_sw_pll to generate
|
||||||
|
the phase-locked clock on-chip (xcore.ai only).
|
||||||
|
|
||||||
If an external stream becomes invalid, the *Internal Clock* timer event will fire to ensure that
|
If an external stream becomes invalid, the *Internal Clock* timer event will fire to ensure that
|
||||||
valid master clock generation continues regardless of cable unplugs etc. Efforts are made to
|
valid master clock generation continues regardless of cable unplugs etc. Efforts are made to
|
||||||
ensure the transition between these clocks are relatively seamless. Additionally efforts are also
|
ensure the transition between these clocks are relatively seamless. Additionally efforts are also
|
||||||
made to try and keep the jitter on the reference clock as low as possibly, regardless of activity
|
made to try and keep the jitter on the reference clock as low as possible, regardless of activity
|
||||||
level of the Clock Gen core. The is achieved though the use of port times to schedule pin toggling
|
level of the Clock Gen core. The is achieved though the use of port times to schedule pin toggling
|
||||||
rather than directly outputting to the port.
|
rather than directly outputting to the port in the case of using the CS2100. For lib_sw_pll cases the
|
||||||
|
last setting is kept for the sigma-delta modulator ensuring clock continuity.
|
||||||
|
|
||||||
The Clock Gen core gets clock selection Get/Set commands from Endpoint 0 via the ``c_clk_ctl``
|
The Clock Gen core gets clock selection Get/Set commands from Endpoint 0 via the ``c_clk_ctl``
|
||||||
channel. This core also records the validity of external clocks, which is also queried
|
channel. This core also records the validity of external clocks, which is also queried
|
||||||
|
|||||||
@@ -3,11 +3,26 @@
|
|||||||
MIDI
|
MIDI
|
||||||
====
|
====
|
||||||
|
|
||||||
The MIDI core implements a 31250 baud UART for both input and output. On receiving 32=bit USB MIDI events
|
The MIDI core implements a 31250 baud UART (8-N-1) for both input and output. It uses a single dedicated thread which performs multiple functions:
|
||||||
from the Endpoint Buffer core, it parses these and translates them to 8-bit MIDI messages which are sent
|
|
||||||
over UART. Similarly, incoming 8-bit MIDI messages are aggregated into 32-bit USB MIDI events and
|
- UART Tx peripheral.
|
||||||
passed on to the Endpoint Buffer core. The MIDI core is implemented in the file ``usb_midi.xc``.
|
- UART Tx FIFO of 1024 bytes (may be configured by the user).
|
||||||
|
- Decoding of USB MIDI message to bytes.
|
||||||
|
- UART Rx peripheral.
|
||||||
|
- Packing of received MIDI bytes into USB MIDI messages/events.
|
||||||
|
|
||||||
|
It is connected via a channel to the Endpoint Buffer core meaning that it can be placed on any XCORE tile in the system subject to resource availability. The channel uses an optimised low level protocol meaning that it always occupies a switch path.
|
||||||
|
|
||||||
|
The Endpoint Buffer core implements the two Bulk endpoints (one In and one Out) as well as interacting with small, shared-memory, FIFOs for each endpoint.
|
||||||
|
|
||||||
|
On receiving 32-bit USB MIDI events from the Endpoint Buffer core over the channel, the MIDI core parses these and translates them to 8-bit MIDI messages which are sent
|
||||||
|
out over the UART. Up to 1024 bytes may be buffered by the MIDI task for outgoing messages in the default configuration. If the outgoing buffer is full then it will cause the USB endpoint to be NACKed which provides flow control in the case that the host application sends messages faster than the UART can transmit them. This is important because the USB bandwidth far exceeds the MIDI UART bandwidth by many orders of magnitude. The combination of buffering and flow control ensures outgoing messages are not dropped during normal operation.
|
||||||
|
|
||||||
|
Incoming 8-bit MIDI messages from the UART receiver are packed into 32-bit USB MIDI events and passed on to the Endpoint Buffer core. Since the rate of ingress
|
||||||
|
to the MIDI port is tiny in comparison to the host USB bandwidth, no buffering is required in the MIDI core and the MIDI events are always forwarded on directly to USB immediately.
|
||||||
|
|
||||||
|
All MIDI message types are supported including `Sysex` (MIDI System Exclusive) strings allowing custom function such as bank updates and patches, backup and device firmware upgrade (DFU) where supported by the MIDI device.
|
||||||
|
|
||||||
|
The MIDI core is implemented in the file ``usb_midi.xc`` and the USB buffering is handled in the file ``ep_buffer.xc``.
|
||||||
|
|
||||||
The Endpoint Buffer core implements the two Bulk endpoints (one In and one Out) as well as interacting
|
|
||||||
with small, shared-memory, FIFOs for each endpoint.
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
XMOSNEWSTYLE = 2
|
XMOSNEWSTYLE = 2
|
||||||
DOXYGEN_DIRS=../../api
|
DOXYGEN_DIRS=../../api ../../src/core/user/audiostream ../../src/core/user/hostactive ../../src/core/user/hid ../../src/core/user/audiohw
|
||||||
SOURCE_INCLUDE_DIRS=../../../lib_xua
|
SOURCE_INCLUDE_DIRS=../../../lib_xua
|
||||||
SPHINX_MASTER_DOC=lib_xua
|
SPHINX_MASTER_DOC=lib_xua
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,4 @@
|
|||||||
|
|
||||||
xmosdfu: xmosdfu.cpp
|
xmosdfu: xmosdfu.cpp
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
g++ -D_GNU_SOURCE -Wall -g -o bin/xmosdfu -Ilibusb/Rasp -lusb-1.0 -x c xmosdfu.cpp -std=c99
|
g++ -D_GNU_SOURCE -Wall -g -o bin/xmosdfu -Ilibusb/Rasp -x c xmosdfu.cpp -std=c99 -lusb-1.0
|
||||||
|
|||||||
53
lib_xua/lib_build_info.cmake
Normal file
53
lib_xua/lib_build_info.cmake
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
set(LIB_NAME lib_xua)
|
||||||
|
set(LIB_VERSION 4.1.0)
|
||||||
|
set(LIB_INCLUDES api
|
||||||
|
src/core
|
||||||
|
src/core/audiohub
|
||||||
|
src/core/buffer/ep
|
||||||
|
src/core/endpoint0
|
||||||
|
src/dfu
|
||||||
|
src/core/buffer/decouple
|
||||||
|
src/core/clocking
|
||||||
|
src/core/mixer
|
||||||
|
src/core/pdm_mics
|
||||||
|
src/core/ports
|
||||||
|
src/core/support
|
||||||
|
src/core/user
|
||||||
|
src/core/user/audiostream
|
||||||
|
src/core/user/audiohw
|
||||||
|
src/core/user/hid
|
||||||
|
src/core/user/hostactive
|
||||||
|
src/hid
|
||||||
|
src/midi)
|
||||||
|
set(LIB_OPTIONAL_HEADERS xua_conf.h static_hid_report.h)
|
||||||
|
set(LIB_DEPENDENT_MODULES "lib_adat(1.2.0)"
|
||||||
|
"lib_locks(2.2.0)"
|
||||||
|
"lib_logging(3.2.0)"
|
||||||
|
"lib_mic_array(4.6.0)"
|
||||||
|
"lib_spdif(6.1.0)"
|
||||||
|
"lib_sw_pll(2.2.0)"
|
||||||
|
"lib_xassert(4.2.0)"
|
||||||
|
"lib_xud(2.3.1)")
|
||||||
|
|
||||||
|
set(LIB_COMPILER_FLAGS -O3 -DREF_CLK_FREQ=100 -fasm-linenum -fcomment-asm)
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
list(APPEND LIB_COMPILER_FLAGS -DXASSERT_ENABLE_ASSERTIONS=1
|
||||||
|
-DXASSERT_ENABLE_DEBUG=1
|
||||||
|
-DXASSERT_ENBALE_LINE_NUMBERS=1)
|
||||||
|
else()
|
||||||
|
list(APPEND LIB_COMPILER_FLAGS -DXASSERT_ENABLE_ASSERTIONS=0
|
||||||
|
-DXASSERT_ENABLE_DEBUG=0
|
||||||
|
-DXASSERT_ENABLE_LINE_NUMBERS=0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(LIB_COMPILER_FLAGS_xua_endpoint0.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
set(LIB_COMPILER_FLAGS_xua_ep0_uacreqs.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
set(LIB_COMPILER_FLAGS_dbcalc.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
set(LIB_COMPILER_FLAGS_audioports.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
set(LIB_COMPILER_FLAGS_audioports.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
set(LIB_COMPILER_FLAGS_dfu.xc ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
set(LIB_COMPILER_FLAGS_flash_interface.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
set(LIB_COMPILER_FLAGS_flashlib_user.c ${LIB_COMPILER_FLAGS} -Os -mno-dual-issue)
|
||||||
|
|
||||||
|
XMOS_REGISTER_MODULE()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
VERSION = 3.5.1
|
VERSION = 4.1.0
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
|
|
||||||
@@ -8,13 +8,14 @@ else
|
|||||||
DEBUG_FLAGS = -DXASSERT_ENABLE_ASSERTIONS=0 -DXASSERT_ENABLE_DEBUG=0 -DXASSERT_ENABLE_LINE_NUMBERS=0
|
DEBUG_FLAGS = -DXASSERT_ENABLE_ASSERTIONS=0 -DXASSERT_ENABLE_DEBUG=0 -DXASSERT_ENABLE_LINE_NUMBERS=0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
DEPENDENT_MODULES = lib_adat(>=1.2.0) \
|
||||||
lib_logging(>=3.1.1) \
|
lib_locks(>=2.2.0) \
|
||||||
lib_mic_array(>=4.5.0) \
|
lib_logging(>=3.2.0) \
|
||||||
lib_spdif(>=5.0.0) \
|
lib_mic_array(>=4.6.0) \
|
||||||
lib_xassert(>=4.1.0) \
|
lib_spdif(>=6.1.0) \
|
||||||
lib_xud(>=2.2.3) \
|
lib_sw_pll(>=2.2.0) \
|
||||||
lib_adat(>=1.0.0)
|
lib_xassert(>=4.2.0) \
|
||||||
|
lib_xud(>=2.3.1)
|
||||||
|
|
||||||
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
||||||
-O3 \
|
-O3 \
|
||||||
@@ -53,6 +54,7 @@ INCLUDE_DIRS = $(EXPORT_INCLUDE_DIRS) \
|
|||||||
src/core/support \
|
src/core/support \
|
||||||
src/core/user \
|
src/core/user \
|
||||||
src/core/user/audiostream \
|
src/core/user/audiostream \
|
||||||
|
src/core/user/audiohw \
|
||||||
src/core/user/hid \
|
src/core/user/hid \
|
||||||
src/core/user/hostactive \
|
src/core/user/hostactive \
|
||||||
src/hid \
|
src/hid \
|
||||||
@@ -69,6 +71,7 @@ SOURCE_DIRS = src/core \
|
|||||||
src/core/ports \
|
src/core/ports \
|
||||||
src/core/support \
|
src/core/support \
|
||||||
src/core/user/audiostream \
|
src/core/user/audiostream \
|
||||||
|
src/core/user/audiohw \
|
||||||
src/core/user/hostactive \
|
src/core/user/hostactive \
|
||||||
src/core/xuduser \
|
src/core/xuduser \
|
||||||
src/dfu \
|
src/dfu \
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
// Copyright 2018-2022 XMOS LIMITED.
|
// Copyright 2018-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.
|
||||||
|
|
||||||
unsigned adatCounter = 0;
|
unsigned adatCounter = 0;
|
||||||
unsigned adatSamples[8];
|
unsigned adatSamples[8];
|
||||||
|
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samplesFromHost[], int smux, int handshake)
|
static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samplesFromHost[], int smux, int handshake)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Do some re-arranging for SMUX.. */
|
/* Do some re-arranging for SMUX.. */
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
@@ -29,7 +27,6 @@ static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samp
|
|||||||
|
|
||||||
if(adatCounter == smux)
|
if(adatCounter == smux)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef ADAT_TX_USE_SHARED_BUFF
|
#ifdef ADAT_TX_USE_SHARED_BUFF
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
/**
|
/**
|
||||||
* @file xua_audiohub.xc
|
* @file xua_audiohub.xc
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
|
|
||||||
|
#include "audiohw.h"
|
||||||
#include "audioports.h"
|
#include "audioports.h"
|
||||||
#include "mic_array_conf.h"
|
#include "mic_array_conf.h"
|
||||||
#if (XUA_SPDIF_TX_EN)
|
#if (XUA_SPDIF_TX_EN)
|
||||||
@@ -241,12 +242,12 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
|||||||
}
|
}
|
||||||
#endif // ((DEBUG_MIC_ARRAY == 1) && (XUA_NUM_PDM_MICS > 0))
|
#endif // ((DEBUG_MIC_ARRAY == 1) && (XUA_NUM_PDM_MICS > 0))
|
||||||
|
|
||||||
UserBufferManagementInit();
|
UserBufferManagementInit(curSamFreq);
|
||||||
|
|
||||||
unsigned command = DoSampleTransfer(c_out, readBuffNo, underflowWord);
|
unsigned command = DoSampleTransfer(c_out, readBuffNo, underflowWord);
|
||||||
|
|
||||||
// Reinitialise user state before entering the main loop
|
// Reinitialise user state before entering the main loop
|
||||||
UserBufferManagementInit();
|
UserBufferManagementInit(curSamFreq);
|
||||||
|
|
||||||
#if (XUA_ADAT_TX_EN)
|
#if (XUA_ADAT_TX_EN)
|
||||||
unsafe{
|
unsafe{
|
||||||
@@ -374,13 +375,12 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
|||||||
}
|
}
|
||||||
#endif // (I2S_CHANS_DAC != 0)
|
#endif // (I2S_CHANS_DAC != 0)
|
||||||
|
|
||||||
|
if(frameCount == 0)
|
||||||
|
{
|
||||||
#if (XUA_ADAT_TX_EN)
|
#if (XUA_ADAT_TX_EN)
|
||||||
TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 1);
|
TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(frameCount == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
/* Sync with clockgen */
|
/* Sync with clockgen */
|
||||||
inuint(c_dig_rx);
|
inuint(c_dig_rx);
|
||||||
@@ -641,6 +641,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
|||||||
#if (XUA_ADAT_RX_EN || XUA_SPDIF_RX_EN)
|
#if (XUA_ADAT_RX_EN || XUA_SPDIF_RX_EN)
|
||||||
, chanend c_dig_rx
|
, chanend c_dig_rx
|
||||||
#endif
|
#endif
|
||||||
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
|
, chanend c_audio_rate_change
|
||||||
|
#endif
|
||||||
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
||||||
, server interface i_dfu ?dfuInterface
|
, server interface i_dfu ?dfuInterface
|
||||||
#endif
|
#endif
|
||||||
@@ -666,7 +669,6 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
|||||||
/* Note, marked unsafe since other cores may be using this mclk port */
|
/* Note, marked unsafe since other cores may be using this mclk port */
|
||||||
configure_clock_src(clk_audio_mclk, p_mclk_in);
|
configure_clock_src(clk_audio_mclk, p_mclk_in);
|
||||||
|
|
||||||
start_clock(clk_audio_mclk);
|
|
||||||
|
|
||||||
#if (DSD_CHANS_DAC > 0)
|
#if (DSD_CHANS_DAC > 0)
|
||||||
/* Make sure the DSD ports are on and buffered - just in case they are not shared with I2S */
|
/* Make sure the DSD ports are on and buffered - just in case they are not shared with I2S */
|
||||||
@@ -678,15 +680,12 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_ADAT_TX_EN)
|
#if (XUA_ADAT_TX_EN)
|
||||||
/* Share SPDIF clk blk */
|
configure_out_port_no_ready(p_adat_tx, clk_audio_mclk, 0);
|
||||||
configure_clock_src(clk_mst_spd, p_mclk_in);
|
set_clock_fall_delay(clk_audio_mclk, 7);
|
||||||
configure_out_port_no_ready(p_adat_tx, clk_mst_spd, 0);
|
|
||||||
set_clock_fall_delay(clk_mst_spd, 7);
|
|
||||||
#if (XUA_SPDIF_TX_EN == 0)
|
|
||||||
start_clock(clk_mst_spd);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
start_clock(clk_audio_mclk);
|
||||||
|
|
||||||
/* Perform required CODEC/ADC/DAC initialisation */
|
/* Perform required CODEC/ADC/DAC initialisation */
|
||||||
AudioHwInit();
|
AudioHwInit();
|
||||||
|
|
||||||
@@ -799,14 +798,30 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Configure Clocking/CODEC/DAC/ADC for SampleFreq/MClk */
|
/* Configure Clocking/CODEC/DAC/ADC for SampleFreq/MClk */
|
||||||
|
|
||||||
|
/* User should mute audio hardware */
|
||||||
|
AudioHwConfig_Mute();
|
||||||
|
|
||||||
|
/* User code should configure audio harware for SampleFreq/MClk etc */
|
||||||
AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC);
|
AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC);
|
||||||
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
|
/* Notify clockgen of new mCLk */
|
||||||
|
c_audio_rate_change <: mClk;
|
||||||
|
c_audio_rate_change <: curFreq;
|
||||||
|
|
||||||
|
/* Wait for ACK back from clockgen or ep_buffer to signal clocks all good */
|
||||||
|
c_audio_rate_change :> int _;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* User should unmute audio hardware */
|
||||||
|
AudioHwConfig_UnMute();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!firstRun)
|
if(!firstRun)
|
||||||
{
|
{
|
||||||
/* TODO wait for good mclk instead of delay */
|
/* TODO wait for good mclk instead of delay */
|
||||||
/* No delay for DFU modes */
|
/* No delay for DFU modes */
|
||||||
if (((curSamFreq / AUD_TO_USB_RATIO) != AUDIO_REBOOT_FROM_DFU) && ((curSamFreq / AUD_TO_USB_RATIO) != AUDIO_STOP_FOR_DFU) && command)
|
if (((curSamFreq / AUD_TO_USB_RATIO) != AUDIO_STOP_FOR_DFU) && command)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
/* User should ensure MCLK is stable in AudioHwConfig */
|
/* User should ensure MCLK is stable in AudioHwConfig */
|
||||||
@@ -916,13 +931,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
|||||||
#else
|
#else
|
||||||
dummy_deliver(c_aud, command);
|
dummy_deliver(c_aud, command);
|
||||||
#endif
|
#endif
|
||||||
|
/* Note, we do not expect to reach here */
|
||||||
curSamFreq = inuint(c_aud);
|
curSamFreq = inuint(c_aud);
|
||||||
|
|
||||||
if (curSamFreq == AUDIO_START_FROM_DFU)
|
|
||||||
{
|
|
||||||
outct(c_aud, XS1_CT_END);
|
outct(c_aud, XS1_CT_END);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// Copyright 2016-2021 XMOS LIMITED.
|
// Copyright 2016-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 "xccompat.h"
|
#include "xccompat.h"
|
||||||
#include "xua_audiohub.h"
|
#include "xua_audiohub.h"
|
||||||
|
|
||||||
/* Default implementation for UserBufferManagementInit() */
|
/* Default implementation for UserBufferManagementInit() */
|
||||||
void __attribute__ ((weak)) UserBufferManagementInit()
|
void __attribute__ ((weak)) UserBufferManagementInit(unsigned sampFreq)
|
||||||
{
|
{
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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 "xua.h"
|
#include "xua.h"
|
||||||
|
|
||||||
@@ -42,8 +42,13 @@
|
|||||||
#define MAX_DEVICE_AUD_PACKET_SIZE_OUT (MAX(MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS, MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS))
|
#define MAX_DEVICE_AUD_PACKET_SIZE_OUT (MAX(MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS, MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS))
|
||||||
|
|
||||||
/*** BUFFER SIZES ***/
|
/*** BUFFER SIZES ***/
|
||||||
|
/* How many packets too allow for in buffer - minimum is 5.
|
||||||
#define BUFFER_PACKET_COUNT (4) /* How many packets too allow for in buffer - minimum is 4 */
|
2 for having in the aud_to_host buffer when it comes out of underflow, space available for 2 more for to accomodate cases when
|
||||||
|
2 pkts from audio hub get written into the aud_to_host buffer within 1 SOF period, and space for 1 extra packet to ensure that
|
||||||
|
when the 4th packet gets written to the buffer, there's space to accomodate the next packet, otherwise handle_audio_request() will
|
||||||
|
drop packets after writing the 4th packet in the buffer
|
||||||
|
*/
|
||||||
|
#define BUFFER_PACKET_COUNT (5)
|
||||||
|
|
||||||
#define BUFF_SIZE_OUT_HS MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS * BUFFER_PACKET_COUNT
|
#define BUFF_SIZE_OUT_HS MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS * BUFFER_PACKET_COUNT
|
||||||
#define BUFF_SIZE_OUT_FS MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS * BUFFER_PACKET_COUNT
|
#define BUFF_SIZE_OUT_FS MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS * BUFFER_PACKET_COUNT
|
||||||
@@ -150,27 +155,19 @@ unsigned unpackData = 0;
|
|||||||
unsigned packState = 0;
|
unsigned packState = 0;
|
||||||
unsigned packData = 0;
|
unsigned packData = 0;
|
||||||
|
|
||||||
static inline void SendSamples4(chanend c_mix_out)
|
static inline void _send_sample_4(chanend c_mix_out, int ch)
|
||||||
{
|
{
|
||||||
/* Doing this checking allows us to unroll */
|
|
||||||
if(g_numUsbChan_Out == NUM_USB_CHAN_OUT)
|
|
||||||
{
|
|
||||||
/* Buffering not underflow condition send out some samples...*/
|
|
||||||
#pragma loop unroll
|
|
||||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
|
||||||
{
|
|
||||||
int sample;
|
int sample;
|
||||||
int mult;
|
|
||||||
int h;
|
|
||||||
unsigned l;
|
|
||||||
|
|
||||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||||
g_aud_from_host_rdptr+=4;
|
g_aud_from_host_rdptr+=4;
|
||||||
|
|
||||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||||
|
int mult;
|
||||||
|
int h;
|
||||||
|
unsigned l;
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
mult = multOutPtr[i];
|
mult = multOutPtr[ch];
|
||||||
}
|
}
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
h <<= 3;
|
h <<= 3;
|
||||||
@@ -182,36 +179,41 @@ static inline void SendSamples4(chanend c_mix_out)
|
|||||||
#else
|
#else
|
||||||
outuint(c_mix_out, sample);
|
outuint(c_mix_out, sample);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void SendSamples4(chanend c_mix_out)
|
||||||
|
{
|
||||||
|
/* Doing this allows us to unroll */
|
||||||
|
if(g_numUsbChan_Out == HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT)
|
||||||
|
{
|
||||||
|
#pragma loop unroll
|
||||||
|
for(int i = 0; i < HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT; i++)
|
||||||
|
{
|
||||||
|
_send_sample_4(c_mix_out, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(g_numUsbChan_Out == HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT)
|
||||||
|
{
|
||||||
|
#pragma loop unroll
|
||||||
|
for(int i = 0; i < HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT; i++)
|
||||||
|
{
|
||||||
|
_send_sample_4(c_mix_out, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(g_numUsbChan_Out == HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT)
|
||||||
|
{
|
||||||
|
#pragma loop unroll
|
||||||
|
for(int i = 0; i < HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT; i++)
|
||||||
|
{
|
||||||
|
_send_sample_4(c_mix_out, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#pragma loop unroll
|
#pragma loop unroll
|
||||||
for(int i = 0; i < NUM_USB_CHAN_OUT_FS; i++)
|
for(int i = 0; i < NUM_USB_CHAN_OUT_FS; i++)
|
||||||
{
|
{
|
||||||
int sample;
|
_send_sample_4(c_mix_out, i);
|
||||||
int mult;
|
|
||||||
int h;
|
|
||||||
unsigned l;
|
|
||||||
|
|
||||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
|
||||||
g_aud_from_host_rdptr+=4;
|
|
||||||
|
|
||||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
mult = multOutPtr[i];
|
|
||||||
}
|
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
|
||||||
h <<= 3;
|
|
||||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
|
||||||
h |= (l >>29) & 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
|
||||||
// Note: We need all 32bits for Native DSD
|
|
||||||
#endif
|
|
||||||
outuint(c_mix_out, h);
|
|
||||||
#else
|
|
||||||
outuint(c_mix_out, sample);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -514,7 +516,7 @@ __builtin_unreachable();
|
|||||||
{
|
{
|
||||||
/* Finished creating packet - commit it to the FIFO */
|
/* Finished creating packet - commit it to the FIFO */
|
||||||
/* Total samps to write could start at 0 (i.e. no MCLK) so need to check for < 0) */
|
/* Total samps to write could start at 0 (i.e. no MCLK) so need to check for < 0) */
|
||||||
if (sampsToWrite <= 0)
|
if(sampsToWrite <= 0)
|
||||||
{
|
{
|
||||||
int speed, wrPtr;
|
int speed, wrPtr;
|
||||||
packState = 0;
|
packState = 0;
|
||||||
@@ -651,6 +653,7 @@ __builtin_unreachable();
|
|||||||
|
|
||||||
#if (NUM_USB_CHAN_IN > 0)
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
|
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
|
||||||
|
/* TODO We should properly size zeros packet rather than using "mid" */
|
||||||
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
|
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
|
||||||
xc_ptr aud_to_host_zeros)
|
xc_ptr aud_to_host_zeros)
|
||||||
{
|
{
|
||||||
@@ -659,8 +662,8 @@ static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned samp
|
|||||||
|
|
||||||
/* Set IN stream packet size to something sensible. We expect the buffer to
|
/* Set IN stream packet size to something sensible. We expect the buffer to
|
||||||
* over flow and this to be reset */
|
* over flow and this to be reset */
|
||||||
SET_SHARED_GLOBAL(sampsToWrite, 0);
|
SET_SHARED_GLOBAL(sampsToWrite, mid);
|
||||||
SET_SHARED_GLOBAL(totalSampsToWrite, 0);
|
SET_SHARED_GLOBAL(totalSampsToWrite, mid);
|
||||||
|
|
||||||
mid *= g_numUsbChan_In * slotSize;
|
mid *= g_numUsbChan_In * slotSize;
|
||||||
|
|
||||||
@@ -821,6 +824,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_USB_CHAN_OUT > 0)
|
||||||
/* Reset OUT buffer state */
|
/* Reset OUT buffer state */
|
||||||
outUnderflow = 1;
|
outUnderflow = 1;
|
||||||
SET_SHARED_GLOBAL(g_aud_from_host_rdptr, aud_from_host_fifo_start);
|
SET_SHARED_GLOBAL(g_aud_from_host_rdptr, aud_from_host_fifo_start);
|
||||||
@@ -830,9 +834,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
if(outOverflow)
|
if(outOverflow)
|
||||||
{
|
{
|
||||||
/* If we were previously in overflow we wont have marked as ready */
|
/* If we were previously in overflow we wont have marked as ready */
|
||||||
XUD_SetReady_OutPtr(aud_from_host_usb_ep, aud_from_host_fifo_start+4);
|
XUD_SetReady_OutPtr(aud_from_host_usb_ep, aud_from_host_fifo_start + 4);
|
||||||
outOverflow = 0;
|
outOverflow = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for handshake back and pass back up */
|
/* Wait for handshake back and pass back up */
|
||||||
@@ -906,6 +911,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
GET_SHARED_GLOBAL(dataFormat, g_formatChange_DataFormat);
|
GET_SHARED_GLOBAL(dataFormat, g_formatChange_DataFormat);
|
||||||
GET_SHARED_GLOBAL(sampRes, g_formatChange_SampRes);
|
GET_SHARED_GLOBAL(sampRes, g_formatChange_SampRes);
|
||||||
|
|
||||||
|
#if (NUM_USB_CHAN_OUT > 0)
|
||||||
/* Reset OUT buffer state */
|
/* Reset OUT buffer state */
|
||||||
SET_SHARED_GLOBAL(g_aud_from_host_rdptr, aud_from_host_fifo_start);
|
SET_SHARED_GLOBAL(g_aud_from_host_rdptr, aud_from_host_fifo_start);
|
||||||
SET_SHARED_GLOBAL(g_aud_from_host_wrptr, aud_from_host_fifo_start);
|
SET_SHARED_GLOBAL(g_aud_from_host_wrptr, aud_from_host_fifo_start);
|
||||||
@@ -921,6 +927,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
XUD_SetReady_OutPtr(aud_from_host_usb_ep, aud_from_host_fifo_start+4);
|
XUD_SetReady_OutPtr(aud_from_host_usb_ep, aud_from_host_fifo_start+4);
|
||||||
outOverflow = 0;
|
outOverflow = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef NATIVE_DSD
|
#ifdef NATIVE_DSD
|
||||||
if(dataFormat == UAC_FORMAT_TYPEI_RAW_DATA)
|
if(dataFormat == UAC_FORMAT_TYPEI_RAW_DATA)
|
||||||
@@ -1041,7 +1048,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
|
|
||||||
DISABLE_INTERRUPTS();
|
DISABLE_INTERRUPTS();
|
||||||
|
|
||||||
if (inUnderflow)
|
if(inUnderflow)
|
||||||
{
|
{
|
||||||
int fillLevel;
|
int fillLevel;
|
||||||
GET_SHARED_GLOBAL(fillLevel, g_aud_to_host_fill_level);
|
GET_SHARED_GLOBAL(fillLevel, g_aud_to_host_fill_level);
|
||||||
@@ -1049,7 +1056,21 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
assert(fillLevel <= BUFF_SIZE_IN);
|
assert(fillLevel <= BUFF_SIZE_IN);
|
||||||
|
|
||||||
/* Check if we have come out of underflow */
|
/* Check if we have come out of underflow */
|
||||||
if (fillLevel >= IN_BUFFER_PREFILL)
|
unsigned sampFreq;
|
||||||
|
GET_SHARED_GLOBAL(sampFreq, g_freqChange_sampFreq);
|
||||||
|
int min, mid, max;
|
||||||
|
GetADCCounts(sampFreq, min, mid, max);
|
||||||
|
const int min_pkt_size = ((min * g_curSubSlot_In * g_numUsbChan_In + 3) & ~0x3) + 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Come out of underflow if there are exactly 2 packets in the buffer.
|
||||||
|
This ensures that handle_audio_request() does not drop packets when writing packets into the aud_to_host buffer
|
||||||
|
when aud_to_host buffer is not in underflow.
|
||||||
|
For example, coming out of underflow with 3 packets in the buffer would mean handle_audio_request()
|
||||||
|
drops packets if 2 pkts are received from audio hub in 1 SOF period. Coming out of underflow with 4
|
||||||
|
packets would mean handle_audio_request would drop packets after writing 1 packet to the aud_to_host buffer.
|
||||||
|
*/
|
||||||
|
if ((fillLevel >= (min_pkt_size*2)) && (fillLevel < (min_pkt_size*3)))
|
||||||
{
|
{
|
||||||
int aud_to_host_rdptr;
|
int aud_to_host_rdptr;
|
||||||
GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr);
|
GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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 "xua.h"
|
#include "xua.h"
|
||||||
#if XUA_USB_EN
|
#if XUA_USB_EN
|
||||||
@@ -105,7 +105,12 @@ void XUA_Buffer(
|
|||||||
#endif
|
#endif
|
||||||
, chanend c_aud
|
, chanend c_aud
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
, chanend c_audio_rate_change
|
||||||
|
#if(XUA_USE_SW_PLL)
|
||||||
|
, chanend c_sw_pll
|
||||||
|
#else
|
||||||
, client interface pll_ref_if i_pll_ref
|
, client interface pll_ref_if i_pll_ref
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -141,7 +146,12 @@ void XUA_Buffer(
|
|||||||
, c_buff_ctrl
|
, c_buff_ctrl
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
, c_audio_rate_change
|
||||||
|
#if(XUA_USE_SW_PLL)
|
||||||
|
, c_sw_pll
|
||||||
|
#else
|
||||||
, i_pll_ref
|
, i_pll_ref
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -190,8 +200,13 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
#ifdef CHAN_BUFF_CTRL
|
#ifdef CHAN_BUFF_CTRL
|
||||||
, chanend c_buff_ctrl
|
, chanend c_buff_ctrl
|
||||||
#endif
|
#endif
|
||||||
#if XUA_SYNCMODE == XUA_SYNCMODE_SYNC
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
, chanend c_audio_rate_change
|
||||||
|
#if (XUA_USE_SW_PLL)
|
||||||
|
, chanend c_sw_pll
|
||||||
|
#else
|
||||||
, client interface pll_ref_if i_pll_ref
|
, client interface pll_ref_if i_pll_ref
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -247,7 +262,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
#if (NUM_USB_CHAN_IN > 0)
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
unsigned bufferIn = 1;
|
unsigned bufferIn = 1;
|
||||||
#endif
|
#endif
|
||||||
unsigned sofCount = 0;
|
int sofCount = 0;
|
||||||
|
|
||||||
unsigned mod_from_last_time = 0;
|
unsigned mod_from_last_time = 0;
|
||||||
#ifdef FB_TOLERANCE_TEST
|
#ifdef FB_TOLERANCE_TEST
|
||||||
@@ -294,7 +309,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
unsigned iap_ea_native_interface_alt_setting = 0;
|
unsigned iap_ea_native_interface_alt_setting = 0;
|
||||||
unsigned iap_ea_native_control_to_send = 0;
|
unsigned iap_ea_native_control_to_send = 0;
|
||||||
unsigned iap_ea_native_incoming = 0;
|
unsigned iap_ea_native_incoming = 0;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -357,6 +371,24 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
#ifndef LOCAL_CLOCK_MARGIN
|
#ifndef LOCAL_CLOCK_MARGIN
|
||||||
#define LOCAL_CLOCK_MARGIN (1000)
|
#define LOCAL_CLOCK_MARGIN (1000)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (XUA_USE_SW_PLL)
|
||||||
|
/* Setup the phase frequency detector */
|
||||||
|
const unsigned controller_rate_hz = 100;
|
||||||
|
const unsigned pfd_ppm_max = 2000; /* PPM range before we assume unlocked */
|
||||||
|
|
||||||
|
sw_pll_pfd_state_t sw_pll_pfd;
|
||||||
|
sw_pll_pfd_init(&sw_pll_pfd,
|
||||||
|
1, /* How often the PFD is invoked per call */
|
||||||
|
masterClockFreq / controller_rate_hz, /* pll ratio integer */
|
||||||
|
0, /* Assume precise timing of sampling */
|
||||||
|
pfd_ppm_max);
|
||||||
|
outuint(c_sw_pll, masterClockFreq);
|
||||||
|
outct(c_sw_pll, XS1_CT_END);
|
||||||
|
inuint(c_sw_pll); /* receive ACK */
|
||||||
|
inct(c_sw_pll);
|
||||||
|
|
||||||
|
#else /* XUA_USE_SW_PLL */
|
||||||
timer t_sofCheck;
|
timer t_sofCheck;
|
||||||
unsigned timeLastEdge;
|
unsigned timeLastEdge;
|
||||||
unsigned timeNextEdge;
|
unsigned timeNextEdge;
|
||||||
@@ -365,6 +397,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
i_pll_ref.toggle();
|
i_pll_ref.toggle();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
XUD_Result_t result;
|
XUD_Result_t result;
|
||||||
@@ -427,7 +461,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
/* Reset FB */
|
/* Reset FB */
|
||||||
/* Note, Endpoint 0 will hold off host for a sufficient period to allow our feedback
|
/* Note, Endpoint 0 will hold off host for a sufficient period to allow our feedback
|
||||||
* to stabilise (i.e. sofCount == 128 to fire) */
|
* to stabilise (i.e. sofCount == 128 to fire) */
|
||||||
sofCount = 1;
|
sofCount = 0;
|
||||||
clocks = 0;
|
clocks = 0;
|
||||||
clockcounter = 0;
|
clockcounter = 0;
|
||||||
mod_from_last_time = 0;
|
mod_from_last_time = 0;
|
||||||
@@ -450,7 +484,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
masterClockFreq = MCLK_441;
|
masterClockFreq = MCLK_441;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* (MAX_FREQ != MIN_FREQ) */
|
||||||
/* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this
|
/* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this
|
||||||
* core locked, it must stay responsive to packets (MIDI etc) and SOFs. So, set a flag and check for
|
* core locked, it must stay responsive to packets (MIDI etc) and SOFs. So, set a flag and check for
|
||||||
* handshake elsewhere */
|
* handshake elsewhere */
|
||||||
@@ -502,13 +536,13 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Pass on sample freq change to decouple() via global flag (saves a chanend) */
|
/* Pass on sample freq change to decouple() via global flag (saves a chanend) */
|
||||||
/* Note: freqChange flags now used to communicate other commands also */
|
/* Note: freqChange_flag now used to communicate other commands also */
|
||||||
SET_SHARED_GLOBAL0(g_freqChange, cmd); /* Set command */
|
SET_SHARED_GLOBAL0(g_freqChange, cmd); /* Set command */
|
||||||
SET_SHARED_GLOBAL(g_freqChange_flag, cmd); /* Set Flag */
|
SET_SHARED_GLOBAL(g_freqChange_flag, cmd); /* Set Flag */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_SW_PLL)
|
||||||
case t_sofCheck when timerafter(timeNextEdge) :> void:
|
case t_sofCheck when timerafter(timeNextEdge) :> void:
|
||||||
i_pll_ref.toggle();
|
i_pll_ref.toggle();
|
||||||
timeLastEdge = timeNextEdge;
|
timeLastEdge = timeNextEdge;
|
||||||
@@ -523,28 +557,61 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
/* SOF notification from XUD_Manager() */
|
/* SOF notification from XUD_Manager() */
|
||||||
case inuint_byref(c_sof, u_tmp):
|
case inuint_byref(c_sof, u_tmp):
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
/* This really could (should) be done in decouple. However, for a quick demo this is okay
|
|
||||||
* Decouple expects a 16:16 number in fixed point stored in the global g_speed */
|
|
||||||
unsigned usbSpeed;
|
unsigned usbSpeed;
|
||||||
int framesPerSec;
|
|
||||||
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
||||||
static int sofCount = 0;
|
static int sofCount = 0;
|
||||||
|
#if (XUA_USE_SW_PLL)
|
||||||
|
/* Run PFD and sw_pll controller at 100Hz */
|
||||||
|
const int sofFreqDivider = (usbSpeed == XUD_SPEED_HS) ? (8000 / controller_rate_hz) : (1000 / controller_rate_hz);
|
||||||
|
#else /* (XUA_USE_SW_PLL) */
|
||||||
|
/* 1000 toggles per second for CS2100 reference -> 500 Hz */
|
||||||
|
const int toggleRateHz = 1000;
|
||||||
|
const int sofFreqDivider = (usbSpeed == XUD_SPEED_HS) ? (8000 / toggleRateHz) : (1000 / toggleRateHz);
|
||||||
|
#endif /* (XUA_USE_SW_PLL) */
|
||||||
|
|
||||||
framesPerSec = (usbSpeed == XUD_SPEED_HS) ? 8000 : 1000;
|
sofCount++;
|
||||||
|
if (sofCount == sofFreqDivider)
|
||||||
clocks = ((int64_t) sampleFreq << 16) / framesPerSec;
|
|
||||||
|
|
||||||
asm volatile("stw %0, dp[g_speed]"::"r"(clocks));
|
|
||||||
|
|
||||||
sofCount += 1000;
|
|
||||||
if (sofCount == framesPerSec)
|
|
||||||
{
|
{
|
||||||
|
#if (XUA_USE_SW_PLL)
|
||||||
|
/* Grab port timer count, run through PFD and send to sw_pll */
|
||||||
|
unsigned short mclk_pt;
|
||||||
|
asm volatile("getts %0, res[%1]" : "=r" (mclk_pt) : "r" (p_off_mclk));
|
||||||
|
|
||||||
|
uint8_t first_loop = 0;
|
||||||
|
unsafe{
|
||||||
|
sw_pll_calc_error_from_port_timers(&sw_pll_pfd, &first_loop, mclk_pt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
if(!first_loop)
|
||||||
|
{
|
||||||
|
error = sw_pll_pfd.mclk_diff;
|
||||||
|
}
|
||||||
|
sw_pll_pfd.mclk_pt_last = mclk_pt;
|
||||||
|
|
||||||
|
/* Send error to sw_pll */
|
||||||
|
outuint(c_sw_pll, error);
|
||||||
|
outct(c_sw_pll, XS1_CT_END);
|
||||||
|
|
||||||
|
#else /* (XUA_USE_SW_PLL) */
|
||||||
|
/* Do toggle for CS2100 reference clock */
|
||||||
/* Port is accessed via interface to allow flexibilty with location */
|
/* Port is accessed via interface to allow flexibilty with location */
|
||||||
i_pll_ref.toggle();
|
i_pll_ref.toggle();
|
||||||
t_sofCheck :> timeLastEdge;
|
t_sofCheck :> timeLastEdge;
|
||||||
sofCount = 0;
|
|
||||||
timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||||
|
#endif /* (XUA_USE_SW_PLL) */
|
||||||
|
sofCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This really could (should) be done in decouple. However, for a quick demo this is okay
|
||||||
|
* Decouple expects a 16:16 number in fixed point stored in the global g_speed */
|
||||||
|
|
||||||
|
const int framesPerSec = (usbSpeed == XUD_SPEED_HS) ? 8000 : 1000;
|
||||||
|
|
||||||
|
clocks = ((int64_t) sampleFreq << 16) / framesPerSec;
|
||||||
|
asm volatile("stw %0, dp[g_speed]"::"r"(clocks));
|
||||||
|
|
||||||
|
|
||||||
#elif (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
#elif (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||||
|
|
||||||
/* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to
|
/* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to
|
||||||
@@ -646,7 +713,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
clockcounter = 0;
|
clockcounter = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Assuming 48kHz from a 24.576 master clock (0.0407uS period)
|
/* Assuming 48kHz from a 24.576 master clock (0.0407uS period)
|
||||||
* MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF.
|
* MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF.
|
||||||
* expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format.
|
* expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format.
|
||||||
@@ -691,7 +757,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
clocks < (expected_fb + FB_TOLERANCE))
|
clocks < (expected_fb + FB_TOLERANCE))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int usb_speed;
|
|
||||||
asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
|
asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
|
||||||
|
|
||||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||||
@@ -774,7 +839,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
if (midi_data_remaining_to_device)
|
if (midi_data_remaining_to_device)
|
||||||
{
|
{
|
||||||
read_via_xc_ptr(datum, midi_from_host_rdptr);
|
read_via_xc_ptr(datum, midi_from_host_rdptr);
|
||||||
outuint(c_midi, datum);
|
midi_send_data(c_midi, datum);
|
||||||
midi_from_host_rdptr += 4;
|
midi_from_host_rdptr += 4;
|
||||||
midi_data_remaining_to_device -= 4;
|
midi_data_remaining_to_device -= 4;
|
||||||
}
|
}
|
||||||
@@ -897,7 +962,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if XUA_HID_ENABLED
|
#if (XUA_HID_ENABLED)
|
||||||
/* HID Report Data */
|
/* HID Report Data */
|
||||||
case XUD_SetData_Select(c_hid, ep_hid, result):
|
case XUD_SetData_Select(c_hid, ep_hid, result):
|
||||||
hid_ready_flag = 0U;
|
hid_ready_flag = 0U;
|
||||||
@@ -927,7 +992,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
{
|
{
|
||||||
/* Read another word from the fifo and output it to MIDI thread */
|
/* Read another word from the fifo and output it to MIDI thread */
|
||||||
read_via_xc_ptr(datum, midi_from_host_rdptr);
|
read_via_xc_ptr(datum, midi_from_host_rdptr);
|
||||||
outuint(c_midi, datum);
|
midi_send_data(c_midi, datum);
|
||||||
midi_from_host_rdptr += 4;
|
midi_from_host_rdptr += 4;
|
||||||
midi_data_remaining_to_device -= 4;
|
midi_data_remaining_to_device -= 4;
|
||||||
}
|
}
|
||||||
@@ -963,6 +1028,33 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
|||||||
break;
|
break;
|
||||||
#endif /* ifdef MIDI */
|
#endif /* ifdef MIDI */
|
||||||
|
|
||||||
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
case c_audio_rate_change :> u_tmp:
|
||||||
|
unsigned selected_mclk_rate = u_tmp;
|
||||||
|
c_audio_rate_change :> u_tmp; /* Sample rate is discarded as only care about mclk */
|
||||||
|
#if (XUA_USE_SW_PLL)
|
||||||
|
sw_pll_pfd_init(&sw_pll_pfd,
|
||||||
|
1, /* How often the PFD is invoked per call */
|
||||||
|
selected_mclk_rate / controller_rate_hz, /* pll muliplication ratio integer */
|
||||||
|
0, /* Assume precise timing of sampling */
|
||||||
|
pfd_ppm_max);
|
||||||
|
restart_sigma_delta(c_sw_pll, selected_mclk_rate);
|
||||||
|
/* Delay ACK until sw_pll says it is ready */
|
||||||
|
#else
|
||||||
|
c_audio_rate_change <: 0; /* ACK back to audio to release I2S immediately */
|
||||||
|
#endif /* XUA_USE_SW_PLL */
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if (XUA_USE_SW_PLL)
|
||||||
|
/* This is fired when sw_pll has completed initialising a new mclk_rate */
|
||||||
|
case inuint_byref(c_sw_pll, u_tmp):
|
||||||
|
inct(c_sw_pll);
|
||||||
|
c_audio_rate_change <: 0; /* ACK back to audio to release */
|
||||||
|
|
||||||
|
break;
|
||||||
|
#endif /* (XUA_USE_SW_PLL) */
|
||||||
|
#endif /* (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) */
|
||||||
|
|
||||||
#ifdef IAP
|
#ifdef IAP
|
||||||
/* Received word from iap thread - Check for ACK or Data */
|
/* Received word from iap thread - Check for ACK or Data */
|
||||||
case iap_get_ack_or_reset_or_data(c_iap, is_ack_iap, is_reset, datum_iap):
|
case iap_get_ack_or_reset_or_data(c_iap, is_ack_iap, is_reset, datum_iap):
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <print.h>
|
#include <print.h>
|
||||||
@@ -26,11 +25,11 @@ unsigned g_digData[10];
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int receivedSamples;
|
int receivedSamples; /* Uses by clockgen to count number of dig rx samples to ascertain clock specs */
|
||||||
int samples;
|
int samples; /* Raw sample count - rolling int and never reset */
|
||||||
int savedSamples;
|
int savedSamples; /* Used by validSamples() to store state of last raw sample count */
|
||||||
int lastDiff;
|
int lastDiff; /* Used by validSamples() to store state of last sample count diff */
|
||||||
unsigned identicaldiffs;
|
unsigned identicaldiffs; /* Used by validSamples() to store state of number of identical diffs */
|
||||||
int samplesPerTick;
|
int samplesPerTick;
|
||||||
} Counter;
|
} Counter;
|
||||||
|
|
||||||
@@ -39,6 +38,7 @@ static int clockValid[NUM_CLOCKS]; /* Store current val
|
|||||||
static int clockInt[NUM_CLOCKS]; /* Interupt flag for clocks */
|
static int clockInt[NUM_CLOCKS]; /* Interupt flag for clocks */
|
||||||
static int clockId[NUM_CLOCKS];
|
static int clockId[NUM_CLOCKS];
|
||||||
|
|
||||||
|
|
||||||
[[distributable]]
|
[[distributable]]
|
||||||
void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_pll_ref)
|
void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_pll_ref)
|
||||||
{
|
{
|
||||||
@@ -88,27 +88,10 @@ static int abs(int x)
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int channelContainsControlToken(chanend x)
|
|
||||||
{
|
|
||||||
unsigned char tmpc;
|
|
||||||
|
|
||||||
select
|
|
||||||
{
|
|
||||||
case inct_byref(x, tmpc):
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void outInterrupt(chanend c_interruptControl, int value)
|
static void outInterrupt(chanend c_interruptControl, int value)
|
||||||
{
|
{
|
||||||
/* Non-blocking check for control token */
|
|
||||||
//if (channelContainsControlToken(c_interruptControl))
|
|
||||||
{
|
|
||||||
outuint(c_interruptControl, value);
|
outuint(c_interruptControl, value);
|
||||||
outct(c_interruptControl, XS1_CT_END);
|
outct(c_interruptControl, XS1_CT_END);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -141,9 +124,6 @@ static inline void setClockValidity(chanend c_interruptControl, int clkIndex, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Returns 1 for valid clock found else 0 */
|
/* Returns 1 for valid clock found else 0 */
|
||||||
static inline int validSamples(Counter &counter, int clockIndex)
|
static inline int validSamples(Counter &counter, int clockIndex)
|
||||||
{
|
{
|
||||||
@@ -210,7 +190,7 @@ static inline int validSamples(Counter &counter, int clockIndex)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else /* No valid frequency found - reset state */
|
||||||
{
|
{
|
||||||
counter.identicaldiffs = 0;
|
counter.identicaldiffs = 0;
|
||||||
counter.lastDiff = diff;
|
counter.lastDiff = diff;
|
||||||
@@ -219,16 +199,11 @@ static inline int validSamples(Counter &counter, int clockIndex)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if XUA_USE_SW_PLL
|
||||||
//:badParity
|
unsafe
|
||||||
/* Returns 1 for bad parity, else 0 */
|
|
||||||
static inline int badParity(unsigned x)
|
|
||||||
{
|
{
|
||||||
unsigned X = (x>>4);
|
unsigned * unsafe selected_mclk_rate_ptr = NULL;
|
||||||
crc32(X, 0, 1);
|
|
||||||
return X & 1;
|
|
||||||
}
|
}
|
||||||
//:
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LEVEL_METER_LEDS
|
#ifdef LEVEL_METER_LEDS
|
||||||
@@ -241,15 +216,42 @@ 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
|
||||||
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,
|
||||||
|
chanend c_audio_rate_change
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
, port p_for_mclk_count_aud
|
||||||
|
, chanend c_sw_pll
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
timer t_local;
|
timer t_local;
|
||||||
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
||||||
unsigned clkMode = CLOCK_INTERNAL; /* Current clocking mode in operation */
|
unsigned clkMode = CLOCK_INTERNAL; /* Current clocking mode in operation */
|
||||||
unsigned tmp;
|
unsigned tmp;
|
||||||
|
|
||||||
/* start in no-SMUX (8-channel) mode */
|
/* Start in no-SMUX (8-channel) mode */
|
||||||
int smux = 0;
|
int smux;
|
||||||
|
// Initialise smux based based on the DEFAULT_FREQ
|
||||||
|
if(DEFAULT_FREQ < 88200)
|
||||||
|
{
|
||||||
|
/* No SMUX */
|
||||||
|
smux = 0;
|
||||||
|
}
|
||||||
|
else if(DEFAULT_FREQ < 176400)
|
||||||
|
{
|
||||||
|
/* SMUX */
|
||||||
|
smux = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* SMUX II */
|
||||||
|
smux = 2;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LEVEL_METER_LEDS
|
#ifdef LEVEL_METER_LEDS
|
||||||
timer t_level;
|
timer t_level;
|
||||||
@@ -258,6 +260,16 @@ 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)
|
||||||
timer t_external;
|
timer t_external;
|
||||||
|
unsigned selected_mclk_rate = MCLK_48; // Assume 24.576MHz initial clock
|
||||||
|
unsigned selected_sample_rate = 0;
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
|
||||||
|
unsigned mclks_per_sample = 0;
|
||||||
|
unsigned short mclk_time_stamp = 0;
|
||||||
|
|
||||||
|
/* Get MCLK count */
|
||||||
|
asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud));
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
@@ -269,9 +281,10 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
int spdifUnderflow = 1;
|
int spdifUnderflow = 1;
|
||||||
int spdifSamps = 0; /* Number of samples in buffer */
|
int spdifSamps = 0; /* Number of samples in buffer */
|
||||||
Counter spdifCounters;
|
Counter spdifCounters;
|
||||||
int spdifReceivedTime;
|
int spdifRxTime;
|
||||||
unsigned tmp2;
|
unsigned tmp2;
|
||||||
unsigned spdifLeft = 0;
|
unsigned spdifLeft = 0;
|
||||||
|
unsigned spdifRxData;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_ADAT_RX_EN)
|
#if (XUA_ADAT_RX_EN)
|
||||||
@@ -296,21 +309,21 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Init clock unit state */
|
/* Init clock unit state */
|
||||||
|
clockFreq[CLOCK_INTERNAL] = 0;
|
||||||
|
clockId[CLOCK_INTERNAL] = ID_CLKSRC_INT;
|
||||||
|
clockValid[CLOCK_INTERNAL] = 0;
|
||||||
|
clockInt[CLOCK_INTERNAL] = 0;
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
clockFreq[CLOCK_SPDIF_INDEX] = 0;
|
clockFreq[CLOCK_SPDIF] = 0;
|
||||||
clockValid[CLOCK_SPDIF_INDEX] = 0;
|
clockValid[CLOCK_SPDIF] = 0;
|
||||||
clockInt[CLOCK_SPDIF_INDEX] = 0;
|
clockInt[CLOCK_SPDIF] = 0;
|
||||||
clockId[CLOCK_SPDIF_INDEX] = ID_CLKSRC_SPDIF;
|
clockId[CLOCK_SPDIF] = ID_CLKSRC_SPDIF;
|
||||||
#endif
|
#endif
|
||||||
clockFreq[CLOCK_INTERNAL_INDEX] = 0;
|
|
||||||
clockId[CLOCK_INTERNAL_INDEX] = ID_CLKSRC_INT;
|
|
||||||
clockValid[CLOCK_INTERNAL_INDEX] = 0;
|
|
||||||
clockInt[CLOCK_INTERNAL_INDEX] = 0;
|
|
||||||
#if (XUA_ADAT_RX_EN)
|
#if (XUA_ADAT_RX_EN)
|
||||||
clockFreq[CLOCK_ADAT_INDEX] = 0;
|
clockFreq[CLOCK_ADAT] = 0;
|
||||||
clockInt[CLOCK_ADAT_INDEX] = 0;
|
clockInt[CLOCK_ADAT] = 0;
|
||||||
clockValid[CLOCK_ADAT_INDEX] = 0;
|
clockValid[CLOCK_ADAT] = 0;
|
||||||
clockId[CLOCK_ADAT_INDEX] = ID_CLKSRC_ADAT;
|
clockId[CLOCK_ADAT] = ID_CLKSRC_ADAT;
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
spdifCounters.receivedSamples = 0;
|
spdifCounters.receivedSamples = 0;
|
||||||
@@ -330,7 +343,6 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
adatCounters.samplesPerTick = 0;
|
adatCounters.samplesPerTick = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
t_local :> timeNextEdge;
|
t_local :> timeNextEdge;
|
||||||
timeLastEdge = timeNextEdge;
|
timeLastEdge = timeNextEdge;
|
||||||
timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT / 2);
|
timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT / 2);
|
||||||
@@ -349,6 +361,12 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
/* Initial ref clock output and get timestamp */
|
/* Initial ref clock output and get timestamp */
|
||||||
i_pll_ref.init();
|
i_pll_ref.init();
|
||||||
|
|
||||||
|
#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||||
|
int reset_sw_pll_pfd = 1;
|
||||||
|
int require_ack_to_audio = 0;
|
||||||
|
restart_sigma_delta(c_sw_pll, MCLK_48); /* default to 48kHz - this will be reset shortly when host selects rate */
|
||||||
|
#endif
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
select
|
select
|
||||||
@@ -405,13 +423,9 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
|
|
||||||
case SET_SEL:
|
case SET_SEL:
|
||||||
/* Update clock mode */
|
/* Update clock mode */
|
||||||
tmp = inuint(c_clk_ctl);
|
clkMode = inuint(c_clk_ctl);
|
||||||
chkct(c_clk_ctl, XS1_CT_END);
|
chkct(c_clk_ctl, XS1_CT_END);
|
||||||
|
|
||||||
if(tmp!=0)
|
|
||||||
{
|
|
||||||
clkMode = tmp;
|
|
||||||
}
|
|
||||||
#ifdef CLOCK_VALIDITY_CALL
|
#ifdef CLOCK_VALIDITY_CALL
|
||||||
switch(clkMode)
|
switch(clkMode)
|
||||||
{
|
{
|
||||||
@@ -420,12 +434,12 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
break;
|
break;
|
||||||
#if (XUA_ADAT_RX_EN)
|
#if (XUA_ADAT_RX_EN)
|
||||||
case CLOCK_ADAT:
|
case CLOCK_ADAT:
|
||||||
VendorClockValidity(clockValid[CLOCK_ADAT_INDEX]);
|
VendorClockValidity(clockValid[CLOCK_ADAT]);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
case CLOCK_SPDIF:
|
case CLOCK_SPDIF:
|
||||||
VendorClockValidity(clockValid[CLOCK_SPDIF_INDEX]);
|
VendorClockValidity(clockValid[CLOCK_SPDIF]);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -470,9 +484,12 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
/* Generate local clock from timer */
|
/* Generate local clock from timer */
|
||||||
case t_local when timerafter(timeNextEdge) :> void:
|
case t_local when timerafter(timeNextEdge) :> void:
|
||||||
|
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
/* Do nothing - hold the most recent sw_pll setting */
|
||||||
|
#else
|
||||||
/* Setup next local clock edge */
|
/* Setup next local clock edge */
|
||||||
i_pll_ref.toggle_timed(0);
|
i_pll_ref.toggle_timed(0);
|
||||||
|
#endif
|
||||||
/* Record time of edge */
|
/* Record time of edge */
|
||||||
timeLastEdge = timeNextEdge;
|
timeLastEdge = timeNextEdge;
|
||||||
|
|
||||||
@@ -499,58 +516,89 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
case t_external when timerafter(timeNextClockDetection) :> void:
|
case t_external when timerafter(timeNextClockDetection) :> void:
|
||||||
|
{
|
||||||
|
int valid;
|
||||||
timeNextClockDetection += (LOCAL_CLOCK_INCREMENT);
|
timeNextClockDetection += (LOCAL_CLOCK_INCREMENT);
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
tmp = spdifCounters.samplesPerTick;
|
|
||||||
|
|
||||||
/* Returns 1 if valid clock found */
|
/* Returns 1 if valid clock found */
|
||||||
tmp = validSamples(spdifCounters, CLOCK_SPDIF_INDEX);
|
valid = validSamples(spdifCounters, CLOCK_SPDIF);
|
||||||
setClockValidity(c_clk_int, CLOCK_SPDIF_INDEX, tmp, clkMode);
|
setClockValidity(c_clk_int, CLOCK_SPDIF, valid, clkMode);
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_ADAT_RX_EN)
|
#if (XUA_ADAT_RX_EN)
|
||||||
tmp = validSamples(adatCounters, CLOCK_ADAT_INDEX);
|
/* Returns 1 if valid clock found */
|
||||||
setClockValidity(c_clk_int, CLOCK_ADAT_INDEX, tmp, clkMode);
|
valid = validSamples(adatCounters, CLOCK_ADAT);
|
||||||
|
setClockValidity(c_clk_int, CLOCK_ADAT, valid, clkMode);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||||
|
case inuint_byref(c_sw_pll, tmp):
|
||||||
|
inct(c_sw_pll);
|
||||||
|
/* Send ACK back to audiohub to allow I2S to start
|
||||||
|
This happens only on SDM restart and only once */
|
||||||
|
if(require_ack_to_audio)
|
||||||
|
{
|
||||||
|
c_audio_rate_change <: tmp;
|
||||||
|
require_ack_to_audio = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
|
/* Receive notification of audio streaming settings change and store */
|
||||||
|
case c_audio_rate_change :> selected_mclk_rate:
|
||||||
|
c_audio_rate_change :> selected_sample_rate;
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
mclks_per_sample = selected_mclk_rate / selected_sample_rate;
|
||||||
|
restart_sigma_delta(c_sw_pll, selected_mclk_rate);
|
||||||
|
reset_sw_pll_pfd = 1;
|
||||||
|
/* We will shedule an ACK when sigma delta is up and running */
|
||||||
|
require_ack_to_audio = 1;
|
||||||
|
#else
|
||||||
|
/* Send ACK immediately as we are good to go if not using SW_PLL */
|
||||||
|
c_audio_rate_change <: 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
/* Receive sample from S/PDIF RX thread (steaming chan) */
|
/* Receive sample from S/PDIF RX thread (streaming chan) */
|
||||||
case c_spdif_rx :> tmp:
|
case c_spdif_rx :> spdifRxData:
|
||||||
|
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
/* Record time of sample */
|
/* Record time of sample */
|
||||||
t_local :> spdifReceivedTime;
|
asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud));
|
||||||
|
#endif
|
||||||
|
t_local :> spdifRxTime;
|
||||||
|
|
||||||
/* Check parity and ignore if bad */
|
/* Check parity and ignore if bad */
|
||||||
if(badParity(tmp))
|
if(spdif_rx_check_parity(spdifRxData))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Get pre-amble */
|
/* Get preamble */
|
||||||
tmp2 = tmp & 0xF;
|
unsigned preamble = spdifRxData & SPDIF_RX_PREAMBLE_MASK;
|
||||||
switch(tmp2)
|
|
||||||
|
switch(preamble)
|
||||||
{
|
{
|
||||||
/* LEFT */
|
/* LEFT */
|
||||||
case SPDIF_FRAME_X:
|
case SPDIF_FRAME_X:
|
||||||
case SPDIF_FRAME_Z:
|
case SPDIF_FRAME_Z:
|
||||||
|
spdifLeft = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData);
|
||||||
spdifLeft = tmp << 4;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* RIGHT */
|
/* RIGHT */
|
||||||
case SPDIF_FRAME_Y:
|
case SPDIF_FRAME_Y:
|
||||||
|
|
||||||
/* Only store sample if not in overflow and stream is reasonably valid */
|
/* Only store sample if not in overflow and stream is reasonably valid */
|
||||||
if(!spdifOverflow && clockValid[CLOCK_SPDIF_INDEX])
|
if(!spdifOverflow && clockValid[CLOCK_SPDIF])
|
||||||
{
|
{
|
||||||
/* Store left and right sample pair to buffer */
|
/* Store left and right sample pair to buffer */
|
||||||
spdifSamples[spdifWr] = spdifLeft;
|
spdifSamples[spdifWr] = spdifLeft;
|
||||||
spdifSamples[spdifWr+1] = tmp << 4;
|
spdifSamples[spdifWr+1] = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData);
|
||||||
|
|
||||||
spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1);
|
spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1);
|
||||||
|
|
||||||
@@ -578,7 +626,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
|
|
||||||
spdifCounters.samples += 1;
|
spdifCounters.samples += 1;
|
||||||
|
|
||||||
if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF_INDEX])
|
if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF])
|
||||||
{
|
{
|
||||||
spdifCounters.receivedSamples+=1;
|
spdifCounters.receivedSamples+=1;
|
||||||
|
|
||||||
@@ -586,17 +634,24 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick))
|
if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick))
|
||||||
{
|
{
|
||||||
/* Check edge is about right... S/PDIF may have changed freq... */
|
/* Check edge is about right... S/PDIF may have changed freq... */
|
||||||
if(timeafter(spdifReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
|
if(timeafter(spdifRxTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN)))
|
||||||
{
|
{
|
||||||
/* Record edge time */
|
/* Record edge time */
|
||||||
timeLastEdge = spdifReceivedTime;
|
timeLastEdge = spdifRxTime;
|
||||||
|
|
||||||
/* Setup for next edge */
|
/* Setup for next edge */
|
||||||
timeNextEdge = spdifReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||||
|
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp,
|
||||||
|
mclks_per_sample,
|
||||||
|
c_sw_pll,
|
||||||
|
spdifCounters.receivedSamples,
|
||||||
|
reset_sw_pll_pfd);
|
||||||
|
#else
|
||||||
/* Toggle edge */
|
/* Toggle edge */
|
||||||
i_pll_ref.toggle_timed(1);
|
i_pll_ref.toggle_timed(1);
|
||||||
|
#endif
|
||||||
/* Reset counters */
|
/* Reset counters */
|
||||||
spdifCounters.receivedSamples = 0;
|
spdifCounters.receivedSamples = 0;
|
||||||
}
|
}
|
||||||
@@ -607,7 +662,11 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
#if (XUA_ADAT_RX_EN)
|
#if (XUA_ADAT_RX_EN)
|
||||||
/* receive sample from ADAT rx thread (streaming channel with CT_END) */
|
/* receive sample from ADAT rx thread (streaming channel with CT_END) */
|
||||||
case inuint_byref(c_adat_rx, tmp):
|
case inuint_byref(c_adat_rx, tmp):
|
||||||
|
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
/* record time of sample */
|
/* record time of sample */
|
||||||
|
asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud));
|
||||||
|
#endif
|
||||||
t_local :> adatReceivedTime;
|
t_local :> adatReceivedTime;
|
||||||
|
|
||||||
/* Sync is: 1 | (user_byte << 4) */
|
/* Sync is: 1 | (user_byte << 4) */
|
||||||
@@ -627,7 +686,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
if (adatChannel == 8)
|
if (adatChannel == 8)
|
||||||
{
|
{
|
||||||
/* only store left samples if not in overflow and stream is reasonably valid */
|
/* only store left samples if not in overflow and stream is reasonably valid */
|
||||||
if (!adatOverflow && clockValid[CLOCK_ADAT_INDEX])
|
if (!adatOverflow && clockValid[CLOCK_ADAT])
|
||||||
{
|
{
|
||||||
/* Unpick the SMUX.. */
|
/* Unpick the SMUX.. */
|
||||||
if(smux == 2)
|
if(smux == 2)
|
||||||
@@ -680,11 +739,18 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(adatChannel == 4 || adatChannel == 8)
|
|
||||||
|
/* An edge needs to be recorded/toggled in the following cases:
|
||||||
|
* smux = 0: adatChannel = 4, 8
|
||||||
|
* smux = 1: adatChannel = 2, 4, 6, 8
|
||||||
|
* smux = 2: adatChannel = 1, 2, 3, 4, 5, 6, 7, 8
|
||||||
|
* This is simplified to a shift-and-mask in the if-condition below.
|
||||||
|
*/
|
||||||
|
if ((adatChannel != 0) && ((adatChannel << smux) & 3) == 0)
|
||||||
{
|
{
|
||||||
adatCounters.samples += 1;
|
adatCounters.samples += 1;
|
||||||
|
|
||||||
if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT_INDEX])
|
if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT])
|
||||||
{
|
{
|
||||||
adatCounters.receivedSamples += 1;
|
adatCounters.receivedSamples += 1;
|
||||||
|
|
||||||
@@ -700,12 +766,19 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
/* Setup for next edge */
|
/* Setup for next edge */
|
||||||
timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||||
|
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp,
|
||||||
|
mclks_per_sample,
|
||||||
|
c_sw_pll,
|
||||||
|
adatCounters.receivedSamples,
|
||||||
|
reset_sw_pll_pfd);
|
||||||
|
#else
|
||||||
/* Toggle edge */
|
/* Toggle edge */
|
||||||
i_pll_ref.toggle_timed(1);
|
i_pll_ref.toggle_timed(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Reset counters */
|
/* Reset counters */
|
||||||
adatCounters.receivedSamples = 0;
|
adatCounters.receivedSamples = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -714,8 +787,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
adatChannel = 0;
|
adatChannel = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif // XUA_ADAT_RX_EN
|
||||||
|
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
/* AudioHub requests data */
|
/* AudioHub requests data */
|
||||||
@@ -742,7 +814,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
spdifSamps -= 2;
|
spdifSamps -= 2;
|
||||||
|
|
||||||
/* spdifSamps could go to -1 */
|
/* spdifSamps could go to -1 */
|
||||||
if(spdifSamps < 0)
|
if(spdifSamps <= 0)
|
||||||
{
|
{
|
||||||
/* We're out of S/PDIF samples, mark underflow condition */
|
/* We're out of S/PDIF samples, mark underflow condition */
|
||||||
spdifUnderflow = 1;
|
spdifUnderflow = 1;
|
||||||
@@ -756,7 +828,6 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
spdifOverflow = 0;
|
spdifOverflow = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_ADAT_RX_EN)
|
#if (XUA_ADAT_RX_EN)
|
||||||
if (adatUnderflow)
|
if (adatUnderflow)
|
||||||
@@ -824,7 +895,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* adatSamps could go to -1 */
|
/* adatSamps could go to -1 */
|
||||||
if (adatSamps < 0)
|
if (adatSamps <= 0)
|
||||||
{
|
{
|
||||||
/* we're out of ADAT samples, mark underflow condition */
|
/* we're out of ADAT samples, mark underflow condition */
|
||||||
adatUnderflow = 1;
|
adatUnderflow = 1;
|
||||||
@@ -841,9 +912,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
|||||||
outuint(c_dig_rx, 1);
|
outuint(c_dig_rx, 1);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
} /* select */
|
||||||
|
} /* while(1) */
|
||||||
}
|
} /* clkgen task scope */
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
57
lib_xua/src/core/clocking/sw_pll_wrapper.h
Normal file
57
lib_xua/src/core/clocking/sw_pll_wrapper.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
#ifndef _SW_PLL_WRAPPPER_H_
|
||||||
|
#define _SW_PLL_WRAPPPER_H_
|
||||||
|
|
||||||
|
#include "xua.h"
|
||||||
|
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "sw_pll.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special control value to disable SDM. Outside of normal range which is less than 16b.*/
|
||||||
|
#define DISABLE_SDM 0x10000000
|
||||||
|
|
||||||
|
|
||||||
|
/** Task that receives an error term, passes it through a PI controller and periodically
|
||||||
|
* calclulates a sigma delta output value and sends it to the PLL fractional register.
|
||||||
|
*
|
||||||
|
* \param c_sw_pll Channel connected to the clocking thread to pass raw error terms.
|
||||||
|
*/
|
||||||
|
void sw_pll_task(chanend c_sw_pll);
|
||||||
|
|
||||||
|
/** Helper function that sends a special restart command. It causes the SDM task
|
||||||
|
* to quit and restart using the new mclk.
|
||||||
|
*
|
||||||
|
* \param c_sw_pll Channel connected to the clocking thread to pass raw error terms.
|
||||||
|
* \param mclk_Rate The mclk frequency in Hz.
|
||||||
|
*/
|
||||||
|
void restart_sigma_delta(chanend c_sw_pll, unsigned mclk_rate);
|
||||||
|
|
||||||
|
/** Performs a frequency comparsion between the incoming digital Rx stream and the local mclk.
|
||||||
|
*
|
||||||
|
* \param mclk_time_stamp The captured mclk count (using port timer) at the time of sample Rx.
|
||||||
|
* \param mclks_per_sample The nominal number of mclks per audio sample.
|
||||||
|
* \param c_sw_pll Channel connected to the sigma delta and controller thread.
|
||||||
|
* \param receivedSamples The number of received samples since tha last call to this function.
|
||||||
|
* \param reset_sw_pll_pfd Reference to a flag which will be used to signal reset of this function's state.
|
||||||
|
*/
|
||||||
|
void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp,
|
||||||
|
unsigned mclks_per_sample,
|
||||||
|
chanend c_sw_pll,
|
||||||
|
int receivedSamples,
|
||||||
|
int &reset_sw_pll_pfd);
|
||||||
|
|
||||||
|
/** Initilaises the software PLL both hardware and state. Sets the mclk frequency to a nominal point.
|
||||||
|
*
|
||||||
|
* \param sw_pll Reference to a software pll state struct to be initialised.
|
||||||
|
* \param mClk The current nominal mClk frequency.
|
||||||
|
*
|
||||||
|
* returns The SDM update interval in ticks and the initial DCO setting for nominal frequency */
|
||||||
|
{unsigned, unsigned} InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk);
|
||||||
|
|
||||||
|
#endif /* XUA_USE_SW_PLL */
|
||||||
|
#endif /* _SW_PLL_WRAPPPER_H_ */
|
||||||
202
lib_xua/src/core/clocking/sw_pll_wrapper.xc
Normal file
202
lib_xua/src/core/clocking/sw_pll_wrapper.xc
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
// Copyright 2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#include <xs1.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <print.h>
|
||||||
|
|
||||||
|
#include "sw_pll_wrapper.h"
|
||||||
|
#include "xua.h"
|
||||||
|
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
|
||||||
|
|
||||||
|
{unsigned, unsigned} init_sw_pll(sw_pll_state_t &sw_pll, unsigned mClk)
|
||||||
|
{
|
||||||
|
/* Autogenerated SDM App PLL setup by dco_model.py using 22.5792_1M profile */
|
||||||
|
/* Input freq: 24000000
|
||||||
|
F: 134
|
||||||
|
R: 0
|
||||||
|
f: 8
|
||||||
|
p: 18
|
||||||
|
OD: 5
|
||||||
|
ACD: 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define APP_PLL_CTL_REG_22 0x0A808600
|
||||||
|
#define APP_PLL_DIV_REG_22 0x80000005
|
||||||
|
#define APP_PLL_FRAC_REG_22 0x80000812
|
||||||
|
#define SW_PLL_SDM_CTRL_MID_22 498283
|
||||||
|
#define SW_PLL_SDM_RATE_22 1000000
|
||||||
|
|
||||||
|
/* Autogenerated SDM App PLL setup by dco_model.py using 24.576_1M profile */
|
||||||
|
/* Input freq: 24000000
|
||||||
|
F: 146
|
||||||
|
R: 0
|
||||||
|
f: 4
|
||||||
|
p: 10
|
||||||
|
OD: 5
|
||||||
|
ACD: 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define APP_PLL_CTL_REG_24 0x0A809200
|
||||||
|
#define APP_PLL_DIV_REG_24 0x80000005
|
||||||
|
#define APP_PLL_FRAC_REG_24 0x8000040A
|
||||||
|
#define SW_PLL_SDM_CTRL_MID_24 478151
|
||||||
|
#define SW_PLL_SDM_RATE_24 1000000
|
||||||
|
|
||||||
|
|
||||||
|
const uint32_t app_pll_ctl_reg[2] = {APP_PLL_CTL_REG_22, APP_PLL_CTL_REG_24};
|
||||||
|
const uint32_t app_pll_div_reg[2] = {APP_PLL_DIV_REG_22, APP_PLL_DIV_REG_24};
|
||||||
|
const uint32_t app_pll_frac_reg[2] = {APP_PLL_FRAC_REG_22, APP_PLL_FRAC_REG_24};
|
||||||
|
const uint32_t sw_pll_sdm_ctrl_mid[2] = {SW_PLL_SDM_CTRL_MID_22, SW_PLL_SDM_CTRL_MID_24};
|
||||||
|
const uint32_t sw_pll_sdm_rate[2] = {SW_PLL_SDM_RATE_22, SW_PLL_SDM_RATE_24};
|
||||||
|
|
||||||
|
const int clkIndex = mClk == MCLK_48 ? 1 : 0;
|
||||||
|
|
||||||
|
sw_pll_sdm_init(&sw_pll,
|
||||||
|
SW_PLL_15Q16(0.0),
|
||||||
|
SW_PLL_15Q16(32.0),
|
||||||
|
SW_PLL_15Q16(0.25),
|
||||||
|
0, /* LOOP COUNT Don't care for this API */
|
||||||
|
0, /* PLL_RATIO Don't care for this API */
|
||||||
|
0, /* No jitter compensation needed */
|
||||||
|
app_pll_ctl_reg[clkIndex],
|
||||||
|
app_pll_div_reg[clkIndex],
|
||||||
|
app_pll_frac_reg[clkIndex],
|
||||||
|
sw_pll_sdm_ctrl_mid[clkIndex],
|
||||||
|
3000 /* PPM_RANGE (FOR PFD) Don't care for this API*/ );
|
||||||
|
|
||||||
|
/* Reset SDM too */
|
||||||
|
sw_pll_init_sigma_delta(&sw_pll.sdm_state);
|
||||||
|
|
||||||
|
return {XS1_TIMER_HZ / sw_pll_sdm_rate[clkIndex], sw_pll_sdm_ctrl_mid[clkIndex]};
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp,
|
||||||
|
unsigned mclks_per_sample,
|
||||||
|
chanend c_sw_pll,
|
||||||
|
int receivedSamples,
|
||||||
|
int &reset_sw_pll_pfd)
|
||||||
|
{
|
||||||
|
const unsigned control_loop_rate_divider = 6; /* 300Hz * 2 edges / 6 -> 100Hz loop rate */
|
||||||
|
static unsigned control_loop_counter = 0;
|
||||||
|
static unsigned total_received_samples = 0;
|
||||||
|
|
||||||
|
/* Keep a store of the last mclk time stamp so we can work out the increment */
|
||||||
|
static unsigned short last_mclk_time_stamp = 0;
|
||||||
|
|
||||||
|
control_loop_counter++;
|
||||||
|
|
||||||
|
total_received_samples += receivedSamples;
|
||||||
|
|
||||||
|
if(control_loop_counter == control_loop_rate_divider)
|
||||||
|
{
|
||||||
|
/* Calculate what the zero-error mclk count increment should be for this many samples */
|
||||||
|
const unsigned expected_mclk_inc = mclks_per_sample * total_received_samples / 2; /* divide by 2 because this fn is called per edge */
|
||||||
|
|
||||||
|
/* Calculate actualy time-stamped mclk count increment is */
|
||||||
|
const unsigned short actual_mclk_inc = mclk_time_stamp - last_mclk_time_stamp;
|
||||||
|
|
||||||
|
/* The difference is the raw error in terms of mclk counts */
|
||||||
|
short f_error = (int)actual_mclk_inc - (int)expected_mclk_inc;
|
||||||
|
if(reset_sw_pll_pfd)
|
||||||
|
{
|
||||||
|
f_error = 0; /* Skip first measurement as it will likely be very out */
|
||||||
|
reset_sw_pll_pfd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send PFD output to the sigma delta thread */
|
||||||
|
outuint(c_sw_pll, (int) f_error);
|
||||||
|
outct(c_sw_pll, XS1_CT_END);
|
||||||
|
|
||||||
|
last_mclk_time_stamp = mclk_time_stamp;
|
||||||
|
control_loop_counter = 0;
|
||||||
|
total_received_samples = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sw_pll_task(chanend c_sw_pll){
|
||||||
|
/* Zero is an invalid number and the SDM will not write the frac reg until
|
||||||
|
the first control value has been received. This avoids issues with
|
||||||
|
channel lockup if two tasks (eg. init and SDM) try to write at the same time. */
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
unsigned selected_mclk_rate = inuint(c_sw_pll);
|
||||||
|
inct(c_sw_pll);
|
||||||
|
|
||||||
|
int f_error = 0;
|
||||||
|
int dco_setting = 0; /* gets set at init_sw_pll */
|
||||||
|
unsigned sdm_interval = 0; /* gets set at init_sw_pll */
|
||||||
|
sw_pll_state_t sw_pll;
|
||||||
|
|
||||||
|
/* initialse the SDM and gather SDM initial settings */
|
||||||
|
{sdm_interval, dco_setting} = init_sw_pll(sw_pll, selected_mclk_rate);
|
||||||
|
|
||||||
|
tileref_t this_tile = get_local_tile_id();
|
||||||
|
|
||||||
|
timer tmr;
|
||||||
|
int32_t time_trigger;
|
||||||
|
tmr :> time_trigger;
|
||||||
|
time_trigger += sdm_interval; /* ensure first loop has correct delay */
|
||||||
|
int running = 1;
|
||||||
|
|
||||||
|
outuint(c_sw_pll, 0); /* Signal back via clockgen to audio to start I2S */
|
||||||
|
outct(c_sw_pll, XS1_CT_END);
|
||||||
|
|
||||||
|
unsigned rx_word = 0;
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
/* Poll for new SDM control value */
|
||||||
|
select
|
||||||
|
{
|
||||||
|
case inuint_byref(c_sw_pll, rx_word):
|
||||||
|
inct(c_sw_pll);
|
||||||
|
if(rx_word == DISABLE_SDM)
|
||||||
|
{
|
||||||
|
f_error = 0;
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f_error = (int32_t)rx_word;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
sw_pll_sdm_do_control_from_error(&sw_pll, -f_error);
|
||||||
|
dco_setting = sw_pll.sdm_state.current_ctrl_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Do nothing & fall-through. Above case polls only once per loop */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until the timer value has been reached
|
||||||
|
This implements a timing barrier and keeps
|
||||||
|
the loop rate constant. */
|
||||||
|
select
|
||||||
|
{
|
||||||
|
case tmr when timerafter(time_trigger) :> int _:
|
||||||
|
time_trigger += sdm_interval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting);
|
||||||
|
}
|
||||||
|
} /* while running */
|
||||||
|
} /* while(1) */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void restart_sigma_delta(chanend c_sw_pll, unsigned selected_mclk_rate)
|
||||||
|
{
|
||||||
|
outuint(c_sw_pll, DISABLE_SDM); /* Resets SDM */
|
||||||
|
outct(c_sw_pll, XS1_CT_END);
|
||||||
|
outuint(c_sw_pll, selected_mclk_rate);
|
||||||
|
outct(c_sw_pll, XS1_CT_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* XUA_USE_SW_PLL */
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
/**
|
/**
|
||||||
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
||||||
@@ -245,7 +245,6 @@ const unsigned g_dataFormat_In[INPUT_FORMAT_COUNT] = {STREAM_FORMAT_INPUT_1
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Channel count */
|
/* Channel count */
|
||||||
/* Note, currently only input changes.. */
|
|
||||||
const unsigned g_chanCount_In_HS[INPUT_FORMAT_COUNT] = {HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT,
|
const unsigned g_chanCount_In_HS[INPUT_FORMAT_COUNT] = {HS_STREAM_FORMAT_INPUT_1_CHAN_COUNT,
|
||||||
#if(INPUT_FORMAT_COUNT > 1)
|
#if(INPUT_FORMAT_COUNT > 1)
|
||||||
HS_STREAM_FORMAT_INPUT_2_CHAN_COUNT,
|
HS_STREAM_FORMAT_INPUT_2_CHAN_COUNT,
|
||||||
@@ -255,6 +254,15 @@ const unsigned g_chanCount_In_HS[INPUT_FORMAT_COUNT] = {HS_STREAM_FORMAT_I
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const unsigned g_chanCount_Out_HS[OUTPUT_FORMAT_COUNT] = {HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT,
|
||||||
|
#if(OUTPUT_FORMAT_COUNT > 1)
|
||||||
|
HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT,
|
||||||
|
#endif
|
||||||
|
#if(OUTPUT_FORMAT_COUNT > 2)
|
||||||
|
HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
XUD_ep ep0_out;
|
XUD_ep ep0_out;
|
||||||
XUD_ep ep0_in;
|
XUD_ep ep0_in;
|
||||||
|
|
||||||
@@ -580,7 +588,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
|
|||||||
|
|
||||||
if(g_curUsbSpeed == XUD_SPEED_HS)
|
if(g_curUsbSpeed == XUD_SPEED_HS)
|
||||||
{
|
{
|
||||||
outuint(c_audioControl, NUM_USB_CHAN_OUT); /* Channel count */
|
outuint(c_audioControl, g_chanCount_Out_HS[sp.wValue-1]); /* Channel count */
|
||||||
outuint(c_audioControl, g_subSlot_Out_HS[sp.wValue-1]); /* Subslot */
|
outuint(c_audioControl, g_subSlot_Out_HS[sp.wValue-1]); /* Subslot */
|
||||||
outuint(c_audioControl, g_sampRes_Out_HS[sp.wValue-1]); /* Resolution */
|
outuint(c_audioControl, g_sampRes_Out_HS[sp.wValue-1]); /* Resolution */
|
||||||
}
|
}
|
||||||
@@ -814,7 +822,14 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
|
|||||||
{
|
{
|
||||||
unsigned epNum = sp.wIndex & 0xff;
|
unsigned epNum = sp.wIndex & 0xff;
|
||||||
|
|
||||||
if ((epNum == ENDPOINT_ADDRESS_OUT_AUDIO) || (epNum == ENDPOINT_ADDRESS_IN_AUDIO))
|
// Ensure we only check for AUDIO EPs if enabled
|
||||||
|
#if (NUM_USB_CHAN_IN != 0 && NUM_USB_CHAN_OUT == 0)
|
||||||
|
if (epNum == ENDPOINT_ADDRESS_IN_AUDIO)
|
||||||
|
#elif (NUM_USB_CHAN_IN == 0 && NUM_USB_CHAN_OUT != 0)
|
||||||
|
if (epNum == ENDPOINT_ADDRESS_OUT_AUDIO)
|
||||||
|
#elif (NUM_USB_CHAN_IN != 0 && NUM_USB_CHAN_OUT != 0)
|
||||||
|
if ((epNum == ENDPOINT_ADDRESS_IN_AUDIO) || (epNum == ENDPOINT_ADDRESS_OUT_AUDIO))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK)
|
#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK)
|
||||||
if(g_curUsbSpeed == XUD_SPEED_FS)
|
if(g_curUsbSpeed == XUD_SPEED_FS)
|
||||||
@@ -961,20 +976,20 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
|
|||||||
cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES;
|
cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES;
|
||||||
cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS;
|
cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS;
|
||||||
cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE;
|
cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE;
|
||||||
cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT;
|
cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT;
|
||||||
#endif
|
#endif
|
||||||
#if (OUTPUT_FORMAT_COUNT > 1)
|
#if (OUTPUT_FORMAT_COUNT > 1)
|
||||||
cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES;
|
cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES;
|
||||||
cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS;
|
cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS;
|
||||||
cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE;
|
cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE;
|
||||||
cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT;
|
cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (OUTPUT_FORMAT_COUNT > 2)
|
#if (OUTPUT_FORMAT_COUNT > 2)
|
||||||
cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES;
|
cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES;
|
||||||
cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS;
|
cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS;
|
||||||
cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE;
|
cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE;
|
||||||
cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT;
|
cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if (NUM_USB_CHAN_IN > 0)
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
/**
|
/**
|
||||||
* @file xua_ep0_descriptors.h
|
* @file xua_ep0_descriptors.h
|
||||||
@@ -772,6 +772,11 @@ typedef struct
|
|||||||
unsigned char configDesc_DFU[DFU_LENGTH];
|
unsigned char configDesc_DFU[DFU_LENGTH];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_CONTROL_DESCS
|
||||||
|
/* Inferface descriptor for control */
|
||||||
|
unsigned char itfDesc_control[9];
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef IAP
|
#ifdef IAP
|
||||||
USB_Descriptor_Interface_t iAP_Interface;
|
USB_Descriptor_Interface_t iAP_Interface;
|
||||||
USB_Descriptor_Endpoint_t iAP_Out_Endpoint;
|
USB_Descriptor_Endpoint_t iAP_Out_Endpoint;
|
||||||
@@ -1117,9 +1122,9 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
.wTerminalType = UAC_TT_OUTPUT_TERMTYPE_SPEAKER,
|
.wTerminalType = UAC_TT_OUTPUT_TERMTYPE_SPEAKER,
|
||||||
0x00, /* 6 bAssocTerminal */
|
0x00, /* 6 bAssocTerminal */
|
||||||
#if (OUTPUT_VOLUME_CONTROL == 1)
|
#if (OUTPUT_VOLUME_CONTROL == 1)
|
||||||
FU_USBOUT, /* 7 bSourceID Connect to analog input feature unit*/
|
FU_USBOUT, /* 7 bSourceID Connect to analog output feature unit */
|
||||||
#else
|
#else
|
||||||
ID_IT_USB, /* 7 bSourceID Connect to analog input feature unit*/
|
ID_IT_USB, /* 7 bSourceID Connect to USB streaming input term */
|
||||||
#endif
|
#endif
|
||||||
ID_CLKSEL, /* 8 bCSourceUD */
|
ID_CLKSEL, /* 8 bCSourceUD */
|
||||||
0x0000, /* 9 bmControls */
|
0x0000, /* 9 bmControls */
|
||||||
@@ -1455,8 +1460,8 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
ID_IT_USB, /* 3 bTerminalLink (Linked to USB input terminal) */
|
ID_IT_USB, /* 3 bTerminalLink (Linked to USB input terminal) */
|
||||||
0x00, /* 4 bmControls */
|
0x00, /* 4 bmControls */
|
||||||
UAC_FORMAT_TYPE_I, /* 5 bFormatType */
|
UAC_FORMAT_TYPE_I, /* 5 bFormatType */
|
||||||
STREAM_FORMAT_OUTPUT_1_DATAFORMAT,/* 6:10 bmFormats (note this is a bitmap) */
|
STREAM_FORMAT_OUTPUT_1_DATAFORMAT, /* 6:10 bmFormats (note this is a bitmap) */
|
||||||
NUM_USB_CHAN_OUT, /* 11 bNrChannels */
|
HS_STREAM_FORMAT_OUTPUT_1_CHAN_COUNT, /* 11 bNrChannels */
|
||||||
0x00000000, /* 12:14: bmChannelConfig */
|
0x00000000, /* 12:14: bmChannelConfig */
|
||||||
.iChannelNames = offsetof(StringDescTable_t, outputChanStr_1)/sizeof(char *),
|
.iChannelNames = offsetof(StringDescTable_t, outputChanStr_1)/sizeof(char *),
|
||||||
},
|
},
|
||||||
@@ -1546,8 +1551,8 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
ID_IT_USB, /* 3 bTerminalLink (Linked to USB input terminal) */
|
ID_IT_USB, /* 3 bTerminalLink (Linked to USB input terminal) */
|
||||||
0x00, /* 4 bmControls */
|
0x00, /* 4 bmControls */
|
||||||
UAC_FORMAT_TYPE_I, /* 5 bFormatType */
|
UAC_FORMAT_TYPE_I, /* 5 bFormatType */
|
||||||
STREAM_FORMAT_OUTPUT_2_DATAFORMAT,/* 6:10 bmFormats (note this is a bitmap) */
|
STREAM_FORMAT_OUTPUT_2_DATAFORMAT, /* 6:10 bmFormats (note this is a bitmap) */
|
||||||
NUM_USB_CHAN_OUT, /* 11 bNrChannels */
|
HS_STREAM_FORMAT_OUTPUT_2_CHAN_COUNT, /* 11 bNrChannels */
|
||||||
0x00000000, /* 12:14: bmChannelConfig */
|
0x00000000, /* 12:14: bmChannelConfig */
|
||||||
.iChannelNames = (offsetof(StringDescTable_t, outputChanStr_1)/sizeof(char *)),
|
.iChannelNames = (offsetof(StringDescTable_t, outputChanStr_1)/sizeof(char *)),
|
||||||
},
|
},
|
||||||
@@ -1637,8 +1642,8 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
ID_IT_USB, /* 3 bTerminalLink (Linked to USB input terminal) */
|
ID_IT_USB, /* 3 bTerminalLink (Linked to USB input terminal) */
|
||||||
0x00, /* 4 bmControls */
|
0x00, /* 4 bmControls */
|
||||||
UAC_FORMAT_TYPE_I, /* 5 bFormatType */
|
UAC_FORMAT_TYPE_I, /* 5 bFormatType */
|
||||||
STREAM_FORMAT_OUTPUT_3_DATAFORMAT,/* 6:10 bmFormats (note this is a bitmap) */
|
STREAM_FORMAT_OUTPUT_3_DATAFORMAT, /* 6:10 bmFormats (note this is a bitmap) */
|
||||||
NUM_USB_CHAN_OUT, /* 11 bNrChannels */
|
HS_STREAM_FORMAT_OUTPUT_3_CHAN_COUNT, /* 11 bNrChannels */
|
||||||
0x00000000, /* 12:14: bmChannelConfig */
|
0x00000000, /* 12:14: bmChannelConfig */
|
||||||
.iChannelNames = offsetof(StringDescTable_t, outputChanStr_1)/sizeof(char *),
|
.iChannelNames = offsetof(StringDescTable_t, outputChanStr_1)/sizeof(char *),
|
||||||
},
|
},
|
||||||
@@ -2104,6 +2109,21 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
#endif
|
#endif
|
||||||
#endif /* (XUA_DFU_EN == 1) */
|
#endif /* (XUA_DFU_EN == 1) */
|
||||||
|
|
||||||
|
#ifdef USB_CONTROL_DESCS
|
||||||
|
{
|
||||||
|
/* Control interface descriptor */
|
||||||
|
0x09, /* 0 bLength : Size of this descriptor, in bytes. (field size 1 bytes) */
|
||||||
|
0x04, /* 1 bDescriptorType : INTERFACE descriptor. (field size 1 bytes) */
|
||||||
|
(INTERFACE_NUMBER_MISC_CONTROL), /* 2 bInterfaceNumber */
|
||||||
|
0x00, /* 3 bAlternateSetting : Index of this setting. (field size 1 bytes) */
|
||||||
|
0x00, /* 4 bNumEndpoints : 0 endpoints. (field size 1 bytes) */
|
||||||
|
USB_CLASS_VENDOR_SPECIFIC, /* 5 bInterfaceClass : Vendor specific. (field size 1 bytes) */
|
||||||
|
0xFF, /* 6 bInterfaceSubclass : (field size 1 bytes) */
|
||||||
|
0xFF, /* 7 bInterfaceProtocol : Unused. (field size 1 bytes) */
|
||||||
|
offsetof(StringDescTable_t, ctrlStr)/sizeof(char *), /* 8 iInterface */
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef IAP
|
#ifdef IAP
|
||||||
/* Interface descriptor */
|
/* Interface descriptor */
|
||||||
.iAP_Interface =
|
.iAP_Interface =
|
||||||
|
|||||||
@@ -456,34 +456,35 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
(buffer, unsigned char[])[0] = 1;
|
(buffer, unsigned char[])[0] = 1;
|
||||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||||
break;
|
break;
|
||||||
|
#if (XUA_SPDIF_RX_EN)
|
||||||
case ID_CLKSRC_SPDIF:
|
case ID_CLKSRC_SPDIF:
|
||||||
|
|
||||||
/* Interogate clockgen thread for validity */
|
/* Interogate clockgen thread for validity */
|
||||||
if (!isnull(c_clk_ctl))
|
if (!isnull(c_clk_ctl))
|
||||||
{
|
{
|
||||||
outuint(c_clk_ctl, GET_VALID);
|
outuint(c_clk_ctl, GET_VALID);
|
||||||
outuint(c_clk_ctl, CLOCK_SPDIF_INDEX);
|
outuint(c_clk_ctl, CLOCK_SPDIF);
|
||||||
outct(c_clk_ctl, XS1_CT_END);
|
outct(c_clk_ctl, XS1_CT_END);
|
||||||
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
||||||
chkct(c_clk_ctl, XS1_CT_END);
|
chkct(c_clk_ctl, XS1_CT_END);
|
||||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#if (XUA_ADAT_RX_EN)
|
||||||
case ID_CLKSRC_ADAT:
|
case ID_CLKSRC_ADAT:
|
||||||
|
|
||||||
if (!isnull(c_clk_ctl))
|
if (!isnull(c_clk_ctl))
|
||||||
{
|
{
|
||||||
outuint(c_clk_ctl, GET_VALID);
|
outuint(c_clk_ctl, GET_VALID);
|
||||||
outuint(c_clk_ctl, CLOCK_ADAT_INDEX);
|
outuint(c_clk_ctl, CLOCK_ADAT);
|
||||||
outct(c_clk_ctl, XS1_CT_END);
|
outct(c_clk_ctl, XS1_CT_END);
|
||||||
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
||||||
chkct(c_clk_ctl, XS1_CT_END);
|
chkct(c_clk_ctl, XS1_CT_END);
|
||||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//Unknown Unit ID in Clock Valid Control Request
|
//Unknown Unit ID in Clock Valid Control Request
|
||||||
@@ -513,19 +514,23 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for correct datalength for clock sel */
|
|
||||||
if(datalength == 1)
|
if(datalength == 1)
|
||||||
{
|
{
|
||||||
if (!isnull(c_clk_ctl))
|
int clockIndex = (int) (buffer, unsigned char[])[0];
|
||||||
|
clockIndex -= 1; /* Index to/from host is 1-based */
|
||||||
|
|
||||||
|
if((clockIndex >= 0) && (clockIndex < CLOCK_COUNT))
|
||||||
|
{
|
||||||
|
if(!isnull(c_clk_ctl))
|
||||||
{
|
{
|
||||||
outuint(c_clk_ctl, SET_SEL);
|
outuint(c_clk_ctl, SET_SEL);
|
||||||
outuint(c_clk_ctl, (buffer, unsigned char[])[0]);
|
outuint(c_clk_ctl, clockIndex);
|
||||||
outct(c_clk_ctl, XS1_CT_END);
|
outct(c_clk_ctl, XS1_CT_END);
|
||||||
}
|
}
|
||||||
/* Send 0 Length as status stage */
|
/* Send 0 Length as status stage */
|
||||||
return XUD_DoSetRequestStatus(ep0_in);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -533,13 +538,15 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
(buffer, unsigned char[])[0] = 1;
|
(buffer, unsigned char[])[0] = 1;
|
||||||
if (!isnull(c_clk_ctl))
|
if (!isnull(c_clk_ctl))
|
||||||
{
|
{
|
||||||
|
int clockIndex;
|
||||||
outuint(c_clk_ctl, GET_SEL);
|
outuint(c_clk_ctl, GET_SEL);
|
||||||
outct(c_clk_ctl, XS1_CT_END);
|
outct(c_clk_ctl, XS1_CT_END);
|
||||||
(buffer, unsigned char[])[0] = inuint(c_clk_ctl);
|
clockIndex = inuint(c_clk_ctl);
|
||||||
|
clockIndex += 1; /* Index to/from host is 1-based */
|
||||||
|
(buffer, unsigned char[])[0] = (unsigned char) clockIndex;
|
||||||
chkct(c_clk_ctl, XS1_CT_END);
|
chkct(c_clk_ctl, XS1_CT_END);
|
||||||
}
|
}
|
||||||
return XUD_DoGetRequest( ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength );
|
return XUD_DoGetRequest( ep0_out, ep0_in, (buffer, unsigned char[]), 1, sp.wLength);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -916,17 +923,20 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
{
|
{
|
||||||
storeFreq((buffer, unsigned char[]), i, currentFreq44);
|
storeFreq((buffer, unsigned char[]), i, currentFreq44);
|
||||||
num_freqs++;
|
num_freqs++;
|
||||||
currentFreq44*=2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if((currentFreq48 <= maxFreq))
|
currentFreq44*=2;
|
||||||
|
|
||||||
|
if((currentFreq48 <= maxFreq) && (currentFreq48 >= MIN_FREQ))
|
||||||
{
|
{
|
||||||
/* Note i passed byref here */
|
/* Note i passed byref here */
|
||||||
storeFreq((buffer, unsigned char[]), i, currentFreq48);
|
storeFreq((buffer, unsigned char[]), i, currentFreq48);
|
||||||
num_freqs++;
|
num_freqs++;
|
||||||
currentFreq48*=2;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
currentFreq48*=2;
|
||||||
|
|
||||||
|
if((currentFreq48 > MAX_FREQ) && (currentFreq44 > MAX_FREQ))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2012-2023 XMOS LIMITED.
|
// Copyright 2012-2024 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 "xua.h" /* Device specific defines */
|
#include "xua.h" /* Device specific defines */
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
#include "iap.h"
|
#include "iap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_SPDIF_TX_EN)
|
||||||
#include "spdif.h"
|
#include "spdif.h" /* From lib_spdif */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_ADAT_RX_EN)
|
#if (XUA_ADAT_RX_EN)
|
||||||
@@ -42,10 +42,6 @@
|
|||||||
#include "xua_pdm_mic.h"
|
#include "xua_pdm_mic.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_SPDIF_TX_EN)
|
|
||||||
#include "spdif.h" /* From lib_spdif */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (XUA_DFU_EN == 1)
|
#if (XUA_DFU_EN == 1)
|
||||||
[[distributable]]
|
[[distributable]]
|
||||||
void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
|
void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
|
||||||
@@ -148,6 +144,11 @@ on tile[XUD_TILE] : in port p_spdif_rx = PORT_SPDIF_IN;
|
|||||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
/* Reference to external clock multiplier */
|
/* Reference to external clock multiplier */
|
||||||
on tile[PLL_REF_TILE] : out port p_pll_ref = PORT_PLL_REF;
|
on tile[PLL_REF_TILE] : out port p_pll_ref = PORT_PLL_REF;
|
||||||
|
#ifdef __XS3A__
|
||||||
|
on tile[AUDIO_IO_TILE] : port p_for_mclk_count_audio = PORT_MCLK_COUNT_2;
|
||||||
|
#else /* __XS3A__ */
|
||||||
|
#define p_for_mclk_count_audio null
|
||||||
|
#endif /* __XS3A__ */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MIDI
|
#ifdef MIDI
|
||||||
@@ -314,6 +315,13 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
, client interface pll_ref_if i_pll_ref
|
, client interface pll_ref_if i_pll_ref
|
||||||
#endif
|
#endif
|
||||||
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
, chanend c_audio_rate_change
|
||||||
|
#endif
|
||||||
|
#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||||
|
, port p_for_mclk_count_aud
|
||||||
|
, chanend c_sw_pll
|
||||||
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
#if (MIXER)
|
#if (MIXER)
|
||||||
@@ -322,9 +330,14 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
chan c_dig_rx;
|
chan c_dig_rx;
|
||||||
#else
|
chan c_audio_rate_change; /* Notification of new mclk freq to clockgen and synch */
|
||||||
#define c_dig_rx null
|
#if XUA_USE_SW_PLL
|
||||||
#endif
|
/* Connect p_for_mclk_count_aud to clk_audio_mclk so we can count mclks/timestamp in digital rx*/
|
||||||
|
unsigned x = 0;
|
||||||
|
asm("ldw %0, dp[clk_audio_mclk]":"=r"(x));
|
||||||
|
asm("setclk res[%0], %1"::"r"(p_for_mclk_count_aud), "r"(x));
|
||||||
|
#endif /* XUA_USE_SW_PLL */
|
||||||
|
#endif /* (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) */
|
||||||
|
|
||||||
#if (XUA_NUM_PDM_MICS > 0) && (PDM_TILE == AUDIO_IO_TILE)
|
#if (XUA_NUM_PDM_MICS > 0) && (PDM_TILE == AUDIO_IO_TILE)
|
||||||
/* Configure clocks ports - sharing mclk port with I2S */
|
/* Configure clocks ports - sharing mclk port with I2S */
|
||||||
@@ -340,7 +353,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
|
|
||||||
par
|
par
|
||||||
{
|
{
|
||||||
#if (MIXER)
|
#if (MIXER && XUA_USB_EN)
|
||||||
/* Mixer cores(s) */
|
/* Mixer cores(s) */
|
||||||
{
|
{
|
||||||
thread_speed();
|
thread_speed();
|
||||||
@@ -370,6 +383,9 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
, c_dig_rx
|
, c_dig_rx
|
||||||
#endif
|
#endif
|
||||||
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
|
, c_audio_rate_change
|
||||||
|
#endif
|
||||||
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
|
||||||
, dfuInterface
|
, dfuInterface
|
||||||
#endif
|
#endif
|
||||||
@@ -389,12 +405,22 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
* However, due to the use of an interface the pll reference signal port can be on another tile
|
* However, due to the use of an interface the pll reference signal port can be on another tile
|
||||||
*/
|
*/
|
||||||
thread_speed();
|
thread_speed();
|
||||||
clockGen(c_spdif_rx, c_adat_rx, i_pll_ref, c_dig_rx, c_clk_ctl, c_clk_int);
|
clockGen( c_spdif_rx,
|
||||||
|
c_adat_rx,
|
||||||
|
i_pll_ref,
|
||||||
|
c_dig_rx,
|
||||||
|
c_clk_ctl,
|
||||||
|
c_clk_int,
|
||||||
|
c_audio_rate_change
|
||||||
|
#if XUA_USE_SW_PLL
|
||||||
|
, p_for_mclk_count_aud
|
||||||
|
, c_sw_pll
|
||||||
|
#endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//:
|
} // par
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USER_MAIN_DECLARATIONS
|
#ifndef USER_MAIN_DECLARATIONS
|
||||||
@@ -441,7 +467,7 @@ int main()
|
|||||||
#define c_adat_rx null
|
#define c_adat_rx null
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||||
chan c_spdif_tx;
|
chan c_spdif_tx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -467,9 +493,16 @@ int main()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !XUA_USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) )
|
||||||
interface pll_ref_if i_pll_ref;
|
interface pll_ref_if i_pll_ref;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||||
|
chan c_sw_pll;
|
||||||
|
#endif
|
||||||
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
chan c_audio_rate_change; /* Notification of new mclk freq to ep_buffer */
|
||||||
|
#endif
|
||||||
chan c_sof;
|
chan c_sof;
|
||||||
chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
|
chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
|
||||||
chan c_xud_in[ENDPOINT_COUNT_IN];
|
chan c_xud_in[ENDPOINT_COUNT_IN];
|
||||||
@@ -491,20 +524,18 @@ int main()
|
|||||||
{
|
{
|
||||||
USER_MAIN_CORES
|
USER_MAIN_CORES
|
||||||
|
|
||||||
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !XUA_USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN))
|
||||||
on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref);
|
on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref);
|
||||||
#endif
|
#endif
|
||||||
on tile[XUD_TILE]:
|
on tile[XUD_TILE]:
|
||||||
par
|
par
|
||||||
{
|
{
|
||||||
#if (XUD_TILE == 0)
|
#if XUA_USB_EN
|
||||||
|
#if ((XUD_TILE == 0) && (XUA_DFU_EN == 1))
|
||||||
/* Check if USB is on the flash tile (tile 0) */
|
/* Check if USB is on the flash tile (tile 0) */
|
||||||
#if (XUA_DFU_EN == 1)
|
|
||||||
[[distribute]]
|
[[distribute]]
|
||||||
DFUHandler(dfuInterface, null);
|
DFUHandler(dfuInterface, null);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
#if XUA_USB_EN
|
|
||||||
|
|
||||||
/* Core USB task, buffering, USB etc */
|
/* Core USB task, buffering, USB etc */
|
||||||
{
|
{
|
||||||
@@ -564,7 +595,12 @@ int main()
|
|||||||
#endif
|
#endif
|
||||||
, c_mix_out
|
, c_mix_out
|
||||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
, c_audio_rate_change
|
||||||
|
#if (!XUA_USE_SW_PLL)
|
||||||
, i_pll_ref
|
, i_pll_ref
|
||||||
|
#else
|
||||||
|
, c_sw_pll
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
//:
|
//:
|
||||||
@@ -579,8 +615,13 @@ int main()
|
|||||||
#endif /* XUA_USB_EN */
|
#endif /* XUA_USB_EN */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||||
|
on tile[AUDIO_IO_TILE]: sw_pll_task(c_sw_pll);
|
||||||
|
#endif
|
||||||
|
|
||||||
on tile[AUDIO_IO_TILE]:
|
on tile[AUDIO_IO_TILE]:
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Audio I/O task, includes mixing etc */
|
/* Audio I/O task, includes mixing etc */
|
||||||
usb_audio_io(c_mix_out
|
usb_audio_io(c_mix_out
|
||||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||||
@@ -594,13 +635,16 @@ int main()
|
|||||||
, dfuInterface
|
, dfuInterface
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_NUM_PDM_MICS > 0)
|
#if (XUA_NUM_PDM_MICS > 0)
|
||||||
#if (PDM_TILE == AUDIO_IO_TILE)
|
|
||||||
, c_ds_output
|
|
||||||
#endif
|
|
||||||
, c_pdm_pcm
|
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
, i_pll_ref
|
, i_pll_ref
|
||||||
|
#endif
|
||||||
|
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||||
|
, c_audio_rate_change
|
||||||
|
#endif
|
||||||
|
#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL)
|
||||||
|
, p_for_mclk_count_audio
|
||||||
|
, c_sw_pll
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -643,7 +687,7 @@ int main()
|
|||||||
on tile[XUD_TILE]:
|
on tile[XUD_TILE]:
|
||||||
{
|
{
|
||||||
thread_speed();
|
thread_speed();
|
||||||
spdif_rx(c_spdif_rx,p_spdif_rx,clk_spd_rx,192000);
|
spdif_rx(c_spdif_rx, p_spdif_rx, clk_spd_rx, 192000);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2023 XMOS LIMITED.
|
// Copyright 2011-2024 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>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
@@ -36,7 +36,10 @@ void ConfigAudioPorts(
|
|||||||
#ifdef __XS3A__
|
#ifdef __XS3A__
|
||||||
/* Increase drive strength of clock ports to 8mA */
|
/* Increase drive strength of clock ports to 8mA */
|
||||||
asm volatile ("setc res[%0], %1" :: "r" (p_bclk), "r" (0x200006));
|
asm volatile ("setc res[%0], %1" :: "r" (p_bclk), "r" (0x200006));
|
||||||
|
if(!isnull(p_lrclk))
|
||||||
|
{
|
||||||
asm volatile ("setc res[%0], %1" :: "r" (p_lrclk), "r" (0x200006));
|
asm volatile ("setc res[%0], %1" :: "r" (p_lrclk), "r" (0x200006));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Note this call to stop_clock() will pause forever if the port clocking the clock-block is not low.
|
/* Note this call to stop_clock() will pause forever if the port clocking the clock-block is not low.
|
||||||
|
|||||||
29
lib_xua/src/core/user/audiohw/audiohw.c
Normal file
29
lib_xua/src/core/user/audiohw/audiohw.c
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2023-2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
/* Default implementations of AudioHwInit(), AudioHwConfig(), AudioHwConfig_Mute() and AudioHwConfig_UnMute() */
|
||||||
|
|
||||||
|
void AudioHwInit() __attribute__ ((weak));
|
||||||
|
void AudioHwInit()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) __attribute__ ((weak));
|
||||||
|
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioHwConfig_Mute() __attribute__ ((weak));
|
||||||
|
void AudioHwConfig_Mute()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioHwConfig_UnMute() __attribute__ ((weak));
|
||||||
|
void AudioHwConfig_UnMute()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
54
lib_xua/src/core/user/audiohw/audiohw.h
Normal file
54
lib_xua/src/core/user/audiohw/audiohw.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2023-2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#ifndef _AUDIO_HW_H_
|
||||||
|
#define _AUDIO_HW_H_
|
||||||
|
|
||||||
|
/* The functions below should be implemented for the external audio hardware arrangement of a specific design.
|
||||||
|
* Note, default (empty) implementations of these are provided in audiohub_user.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User audio hardware initialisation code
|
||||||
|
*
|
||||||
|
* This function is called when the device starts up and should contain user code to perform any required audio hardware initialisation
|
||||||
|
*/
|
||||||
|
void AudioHwInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User audio hardware configuration code
|
||||||
|
*
|
||||||
|
* This function is called when on sample rate change and should contain user code to configure audio hardware
|
||||||
|
* (clocking, CODECs etc) for a specific mClk/Sample frequency
|
||||||
|
*
|
||||||
|
* \param samFreq The new sample frequency (in Hz)
|
||||||
|
*
|
||||||
|
* \param mClk The new master clock frequency (in Hz)
|
||||||
|
*
|
||||||
|
* \param dsdMode DSD mode, DSD_MODE_NATIVE, DSD_MODE_DOP or DSD_MODE_OFF
|
||||||
|
*
|
||||||
|
* \param sampRes_DAC Playback sample resolution (in bits)
|
||||||
|
*
|
||||||
|
* \param sampRes_ADC Record sample resolution (in bits)
|
||||||
|
*/
|
||||||
|
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User code mute audio hardware
|
||||||
|
*
|
||||||
|
* This function is called before AudioHwConfig() and should contain user code to mute audio hardware before a
|
||||||
|
* sample rate change in order to reduced audible pops/clicks
|
||||||
|
*
|
||||||
|
* Note, if using the application PLL of a xcore.ai device this function will be called before the master-clock is
|
||||||
|
* changed
|
||||||
|
*/
|
||||||
|
void AudioHwConfig_Mute(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User code to un-mute audio hardware
|
||||||
|
*
|
||||||
|
* This function is called after AudioHwConfig() and should contain user code to un-mute audio hardware after a
|
||||||
|
* sample rate change
|
||||||
|
*/
|
||||||
|
void AudioHwConfig_UnMute(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,30 +1,51 @@
|
|||||||
// Copyright 2011-2021 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
#ifndef _AUDIOSTREAM_H_
|
#ifndef _AUDIOSTREAM_H_
|
||||||
#define _AUDIOSTREAM_H_
|
#define _AUDIOSTREAM_H_
|
||||||
|
|
||||||
/* Functions that handle functions that must occur on stream start/stop e.g. DAC mute/un-mute
|
/* Functions that handle functionality that occur on stream start/stop e.g. DAC mute/un-mute.
|
||||||
*
|
* They should be implemented for the external audio hardware arrangement of a specific design.
|
||||||
* THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN
|
*/
|
||||||
*
|
|
||||||
* */
|
|
||||||
|
|
||||||
/* Any actions required for stream start e.g. DAC un-mute - run every stream start */
|
/**
|
||||||
|
* @brief User stream start code
|
||||||
|
*
|
||||||
|
* User code to perform any actions required at every stream start - either input or output
|
||||||
|
*/
|
||||||
void UserAudioStreamStart(void);
|
void UserAudioStreamStart(void);
|
||||||
|
|
||||||
/* Any actions required on stream stop e.g. DAC mute - run every steam stop */
|
/**
|
||||||
|
* @brief User stream stop code
|
||||||
|
*
|
||||||
|
* User code to perform any actions required on every stream stop - either input or output*/
|
||||||
void UserAudioStreamStop(void);
|
void UserAudioStreamStop(void);
|
||||||
|
|
||||||
/* Any actions required on input stream start */
|
/**
|
||||||
|
* @brief User input stream stop code
|
||||||
|
*
|
||||||
|
* User code to perform any actions required on input stream start i.e. device to host
|
||||||
|
*/
|
||||||
void UserAudioInputStreamStart(void);
|
void UserAudioInputStreamStart(void);
|
||||||
|
|
||||||
/* Any actions required on input stream stop */
|
/**
|
||||||
|
* @brief User input stream stop code
|
||||||
|
*
|
||||||
|
* User code to perform any actions required on input stream stop i.e. device to host
|
||||||
|
*/
|
||||||
void UserAudioInputStreamStop(void);
|
void UserAudioInputStreamStop(void);
|
||||||
|
|
||||||
/* Any actions required on output stream start */
|
/**
|
||||||
|
* @brief User output stream start code
|
||||||
|
*
|
||||||
|
* User code to perform any actions required on output stream start i.e. host to device
|
||||||
|
*/
|
||||||
void UserAudioOutputStreamStart(void);
|
void UserAudioOutputStreamStart(void);
|
||||||
|
|
||||||
/* Any actions required on output stream stop */
|
/**
|
||||||
|
* @brief User output stream stop code
|
||||||
|
*
|
||||||
|
* User code to perfrom any actions required on output stream stop i.e. host to device
|
||||||
|
*/
|
||||||
void UserAudioOutputStreamStop(void);
|
void UserAudioOutputStreamStop(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2013-2023 XMOS LIMITED.
|
// Copyright 2013-2024 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.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
* Document section numbers refer to the HID Device Class Definition, version 1.11.
|
* Document section numbers refer to the HID Device Class Definition, version 1.11.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __USER_HID_H__
|
#ifndef _USER_HID_H_
|
||||||
#define __USER_HID_H__
|
#define _USER_HID_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -34,15 +34,9 @@ typedef struct hidEvent_t {
|
|||||||
#define HID_MAX_DATA_BYTES ( 4 )
|
#define HID_MAX_DATA_BYTES ( 4 )
|
||||||
#define HID_EVENT_INVALID_ID ( 0x100 )
|
#define HID_EVENT_INVALID_ID ( 0x100 )
|
||||||
|
|
||||||
#if XUA_HID_ENABLED
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get the data for the next HID Report
|
* \brief Get the data for the next HID Report
|
||||||
*
|
*
|
||||||
* \note This function returns the HID data as a list of unsigned char because the
|
|
||||||
* \c XUD_SetReady_In() accepts data for transmission to the USB Host using
|
|
||||||
* this type.
|
|
||||||
*
|
|
||||||
* \param[in] id The HID Report ID (see 5.6, 6.2.2.7, 8.1 and 8.2)
|
* \param[in] id The HID Report ID (see 5.6, 6.2.2.7, 8.1 and 8.2)
|
||||||
* Set to zero if the application provides only one HID Report
|
* Set to zero if the application provides only one HID Report
|
||||||
* which does not include a Report ID
|
* which does not include a Report ID
|
||||||
@@ -61,5 +55,4 @@ size_t UserHIDGetData( const unsigned id, unsigned char hidData[ HID_MAX_DATA_BY
|
|||||||
*/
|
*/
|
||||||
void UserHIDInit( void );
|
void UserHIDInit( void );
|
||||||
|
|
||||||
#endif /* ( 0 < HID_CONTROLS ) */
|
#endif /* _USER_HID_H_ */
|
||||||
#endif /* __USER_HID_H__ */
|
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
// Copyright 2013-2021 XMOS LIMITED.
|
// Copyright 2013-2024 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.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User host active code
|
||||||
|
*
|
||||||
|
* This function can be used to perform user defined actions based on host present/not-present events.
|
||||||
|
* This function is called on a change in state.
|
||||||
|
*
|
||||||
|
* \param active Indicates if the host is active or not. 1 for active, else 0
|
||||||
|
*/
|
||||||
void UserHostActive(int active);
|
void UserHostActive(int active);
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// Copyright 2011-2021 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.
|
||||||
|
#ifndef _XUA_COMMANDS_H_
|
||||||
#ifndef __XUA_INTERNAL_CMDS_H__
|
#define _XUA_COMMANDS_H_
|
||||||
#define __XUA_INTERNAL_CMDS_H__
|
|
||||||
|
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
|
|
||||||
@@ -11,20 +10,19 @@
|
|||||||
#define SET_SEL 1 /* Set value of clock selector */
|
#define SET_SEL 1 /* Set value of clock selector */
|
||||||
#define GET_FREQ 2 /* Get current freq */
|
#define GET_FREQ 2 /* Get current freq */
|
||||||
#define GET_VALID 3 /* Get current validity */
|
#define GET_VALID 3 /* Get current validity */
|
||||||
|
#define SET_SMUX 7 /* Set SMUX mode (ADAT) */
|
||||||
|
|
||||||
#define CLOCK_INTERNAL 1
|
enum
|
||||||
#define CLOCK_SPDIF 2
|
{
|
||||||
#if SPDIF_RX
|
CLOCK_INTERNAL = 0,
|
||||||
#define CLOCK_ADAT 3
|
#if XUA_SPDIF_RX_EN
|
||||||
#else
|
CLOCK_SPDIF,
|
||||||
#define CLOCK_ADAT 2
|
|
||||||
#endif
|
#endif
|
||||||
|
#if XUA_ADAT_RX_EN
|
||||||
#define CLOCK_INTERNAL_INDEX (CLOCK_INTERNAL - 1)
|
CLOCK_ADAT,
|
||||||
#define CLOCK_ADAT_INDEX (CLOCK_ADAT - 1)
|
#endif
|
||||||
#define CLOCK_SPDIF_INDEX (CLOCK_SPDIF - 1)
|
CLOCK_COUNT
|
||||||
|
};
|
||||||
#define SET_SMUX 7
|
|
||||||
|
|
||||||
/* c_audioControl */
|
/* c_audioControl */
|
||||||
#define SET_SAMPLE_FREQ 4
|
#define SET_SAMPLE_FREQ 4
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2021 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>
|
||||||
#include <flash.h>
|
#include <flash.h>
|
||||||
@@ -72,7 +72,7 @@ int flash_cmd_init(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QUAD_SPI_FLASH
|
#if (!XUA_QUAD_SPI_FLASH)
|
||||||
// Disable flash protection
|
// Disable flash protection
|
||||||
fl_setProtection(0);
|
fl_setProtection(0);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// Copyright 2012-2021 XMOS LIMITED.
|
// Copyright 2012-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 "xua.h"
|
#include "xua.h"
|
||||||
#if (XUA_DFU_EN == 1)
|
#if (XUA_DFU_EN == 1)
|
||||||
#include "uac_hwresources.h"
|
#include "uac_hwresources.h"
|
||||||
#include <xs1.h>
|
#include <xs1.h>
|
||||||
#include <xclib.h>
|
#include <xclib.h>
|
||||||
#ifdef QUAD_SPI_FLASH
|
#if (XUA_QUAD_SPI_FLASH)
|
||||||
#include <quadflashlib.h>
|
#include <quadflashlib.h>
|
||||||
#else
|
#else
|
||||||
#include <flashlib.h>
|
#include <flashlib.h>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#ifdef DFU_FLASH_DEVICE
|
#ifdef DFU_FLASH_DEVICE
|
||||||
|
|
||||||
#ifdef QUAD_SPI_FLASH
|
#if (XUA_QUAD_SPI_FLASH)
|
||||||
/* Using specified flash device rather than all supported in tools */
|
/* Using specified flash device rather than all supported in tools */
|
||||||
fl_QuadDeviceSpec flash_devices[] = {DFU_FLASH_DEVICE};
|
fl_QuadDeviceSpec flash_devices[] = {DFU_FLASH_DEVICE};
|
||||||
#else
|
#else
|
||||||
@@ -29,7 +29,7 @@ fl_DeviceSpec flash_devices[] = {DFU_FLASH_DEVICE};
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef QUAD_SPI_FLASH
|
#if (XUA_QUAD_SPI_FLASH)
|
||||||
/*
|
/*
|
||||||
typedef struct {
|
typedef struct {
|
||||||
out port qspiCS;
|
out port qspiCS;
|
||||||
@@ -60,7 +60,7 @@ fl_PortHolderStruct p_flash =
|
|||||||
int flash_cmd_enable_ports()
|
int flash_cmd_enable_ports()
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
#ifdef QUAD_SPI_FLASH
|
#if (XUA_QUAD_SPI_FLASH)
|
||||||
/* Ports not shared */
|
/* Ports not shared */
|
||||||
#else
|
#else
|
||||||
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
||||||
@@ -89,14 +89,14 @@ int flash_cmd_enable_ports()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DFU_FLASH_DEVICE
|
#ifdef DFU_FLASH_DEVICE
|
||||||
#ifdef QUAD_SPI_FLASH
|
#if (XUA_QUAD_SPI_FLASH)
|
||||||
result = fl_connectToDevice(&p_qflash, flash_devices, sizeof(flash_devices) / sizeof(fl_QuadDeviceSpec));
|
result = fl_connectToDevice(&p_qflash, flash_devices, sizeof(flash_devices) / sizeof(fl_QuadDeviceSpec));
|
||||||
#else
|
#else
|
||||||
result = fl_connectToDevice(&p_flash, flash_devices, sizeof(flash_devices) / sizeof(fl_DeviceSpec));
|
result = fl_connectToDevice(&p_flash, flash_devices, sizeof(flash_devices) / sizeof(fl_DeviceSpec));
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
/* Use default flash list */
|
/* Use default flash list */
|
||||||
#ifdef QUAD_SPI_FLASH
|
#if (XUA_QUAD_SPI_FLASH)
|
||||||
result = fl_connect(&p_qflash);
|
result = fl_connect(&p_qflash);
|
||||||
#else
|
#else
|
||||||
result = fl_connect(&p_flash);
|
result = fl_connect(&p_flash);
|
||||||
@@ -117,7 +117,7 @@ int flash_cmd_disable_ports()
|
|||||||
{
|
{
|
||||||
fl_disconnect();
|
fl_disconnect();
|
||||||
|
|
||||||
#ifndef QUAD_SPI_FLASH
|
#if (!XUA_QUAD_SPI_FLASH)
|
||||||
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
||||||
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
|
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
|
||||||
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
|
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2021 XMOS LIMITED.
|
// Copyright 2011-2024 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#ifndef MIDIINPARSE_XH
|
#ifndef MIDIINPARSE_XH
|
||||||
#define MIDIINPARSE_XH
|
#define MIDIINPARSE_XH
|
||||||
@@ -19,8 +19,11 @@ struct midi_in_parse_state {
|
|||||||
unsigned codeIndexNumber;
|
unsigned codeIndexNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
void dump_midi_in_parse_state(struct midi_in_parse_state &s);
|
|
||||||
|
#ifdef __XC__
|
||||||
void reset_midi_state(struct midi_in_parse_state &mips);
|
void reset_midi_state(struct midi_in_parse_state &mips);
|
||||||
|
void dump_midi_in_parse_state(struct midi_in_parse_state &s);
|
||||||
{unsigned int , unsigned int} midi_in_parse(struct midi_in_parse_state &mips, unsigned cable_number, unsigned char b);
|
{unsigned int , unsigned int} midi_in_parse(struct midi_in_parse_state &mips, unsigned cable_number, unsigned char b);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
// Copyright 2011-2021 XMOS LIMITED.
|
// Copyright 2011-2024 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.
|
||||||
#ifndef MIDIOUTPARSE_XH
|
#ifndef MIDIOUTPARSE_XH
|
||||||
#define MIDIOUTPARSE_XH
|
#define MIDIOUTPARSE_XH
|
||||||
|
|
||||||
|
// If for any reason we pop a message when not needed (should never happen) this will cause midiparse out to send a size of 0 (drops packet)
|
||||||
|
#define MIDI_OUT_NULL_MESSAGE 0x00000000
|
||||||
|
|
||||||
|
#ifdef __XC__
|
||||||
|
// Takes a MIDI packet and decomoses it into up to 3 data bytes followed by a byte count.
|
||||||
{unsigned, unsigned, unsigned, unsigned} midi_out_parse(unsigned event);
|
{unsigned, unsigned, unsigned, unsigned} midi_out_parse(unsigned event);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
// Copyright 2013-2021 XMOS LIMITED.
|
// Copyright 2013-2024 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.
|
||||||
#ifndef QUEUE_H_
|
#ifndef QUEUE_H_
|
||||||
#define QUEUE_H_
|
#define QUEUE_H_
|
||||||
|
|
||||||
#define assert(x) asm("ecallf %0"::"r"(x));
|
#include "midioutparse.h"
|
||||||
|
#include "xassert.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct queue_t {
|
typedef struct queue_t {
|
||||||
/// Read index.
|
/// Read index.
|
||||||
@@ -14,12 +16,14 @@ typedef struct queue_t {
|
|||||||
unsigned mask;
|
unsigned mask;
|
||||||
} queue_t;
|
} queue_t;
|
||||||
|
|
||||||
|
#ifdef __XC__
|
||||||
|
|
||||||
inline int is_power_of_2(unsigned x) {
|
inline int is_power_of_2(unsigned x) {
|
||||||
return x != 0 && (x & (x - 1)) == 0;
|
return x != 0 && (x & (x - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void queue_init(queue_t &q, unsigned size) {
|
inline void queue_init(queue_t &q, unsigned size) {
|
||||||
assert(is_power_of_2(size));
|
xassert(is_power_of_2(size) && "MIDI FIFO size must be a power of 2"); // Keep this enabled as will be discovered duirng dev time
|
||||||
q.rdptr = 0;
|
q.rdptr = 0;
|
||||||
q.wrptr = 0;
|
q.wrptr = 0;
|
||||||
q.size = size;
|
q.size = size;
|
||||||
@@ -36,25 +40,26 @@ inline int queue_is_full(const queue_t &q) {
|
|||||||
|
|
||||||
inline void queue_push_word(queue_t &q, unsigned array[], unsigned data)
|
inline void queue_push_word(queue_t &q, unsigned array[], unsigned data)
|
||||||
{
|
{
|
||||||
assert(!queue_is_full(q));
|
|
||||||
|
if(queue_is_full(q)) {
|
||||||
|
xassert(0 && "Unexpected push to MIDI queue when full");
|
||||||
|
// Silently drop message if asserts not enabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
array[q.wrptr++ & q.mask] = data;
|
array[q.wrptr++ & q.mask] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned queue_pop_word(queue_t &q, unsigned array[]) {
|
inline unsigned queue_pop_word(queue_t &q, unsigned array[]) {
|
||||||
assert(!queue_is_empty(q));
|
if(queue_is_empty(q)){
|
||||||
|
xassert(0 && "Unexpected pop from MIDI queue when empty");
|
||||||
|
// Return NULL messaqe if asserts not enabled
|
||||||
|
return MIDI_OUT_NULL_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
return array[q.rdptr++ & q.mask];
|
return array[q.rdptr++ & q.mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void queue_push_byte(queue_t &q, unsigned char array[], unsigned data)
|
|
||||||
{
|
|
||||||
assert(!queue_is_full(q));
|
|
||||||
array[q.wrptr++ & q.mask] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned queue_pop_byte(queue_t &q, unsigned char array[]) {
|
|
||||||
assert(!queue_is_empty(q));
|
|
||||||
return array[q.rdptr++ & q.mask];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned queue_items(const queue_t &q) {
|
inline unsigned queue_items(const queue_t &q) {
|
||||||
return q.wrptr - q.rdptr;
|
return q.wrptr - q.rdptr;
|
||||||
@@ -64,4 +69,6 @@ inline unsigned queue_space(const queue_t &q) {
|
|||||||
return q.size - queue_items(q);
|
return q.size - queue_items(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // __XC__
|
||||||
|
|
||||||
#endif /* QUEUE_H_ */
|
#endif /* QUEUE_H_ */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2013-2021 XMOS LIMITED.
|
// Copyright 2013-2024 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
|
||||||
@@ -9,7 +9,5 @@ extern inline int queue_is_empty(const queue_t &q);
|
|||||||
extern inline int queue_is_full(const queue_t &q);
|
extern inline int queue_is_full(const queue_t &q);
|
||||||
extern inline void queue_push_word(queue_t &q, unsigned array[], unsigned data);
|
extern inline void queue_push_word(queue_t &q, unsigned array[], unsigned data);
|
||||||
extern inline unsigned queue_pop_word(queue_t &q, unsigned array[]);
|
extern inline unsigned queue_pop_word(queue_t &q, unsigned array[]);
|
||||||
extern inline void queue_push_byte(queue_t &q, unsigned char array[], unsigned data);
|
|
||||||
extern inline unsigned queue_pop_byte(queue_t &q, unsigned char array[]);
|
|
||||||
extern inline unsigned queue_space(const queue_t &q);
|
extern inline unsigned queue_space(const queue_t &q);
|
||||||
extern inline unsigned queue_items(const queue_t &q);
|
extern inline unsigned queue_items(const queue_t &q);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2024 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>
|
||||||
#include <xclib.h>
|
#include <xclib.h>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
#include "iap_user.h"
|
#include "iap_user.h"
|
||||||
#include "coprocessor_user.h"
|
#include "coprocessor_user.h"
|
||||||
#endif
|
#endif
|
||||||
//#define MIDI_LOOPBACK 1
|
|
||||||
int icount = 0;
|
int icount = 0;
|
||||||
static unsigned makeSymbol(unsigned data)
|
static unsigned makeSymbol(unsigned data)
|
||||||
{
|
{
|
||||||
@@ -89,9 +89,9 @@ void usb_midi(
|
|||||||
|
|
||||||
struct midi_in_parse_state mips;
|
struct midi_in_parse_state mips;
|
||||||
|
|
||||||
// the symbol fifo (to go out of uart)
|
// the symbol fifo (to go out of uart).
|
||||||
queue_t symbol_fifo;
|
queue_t symbol_fifo;
|
||||||
unsigned symbol_fifo_arr[USB_MIDI_DEVICE_OUT_FIFO_SIZE]; // Used for 32bit USB MIDI events
|
unsigned symbol_fifo_arr[USB_MIDI_DEVICE_OUT_FIFO_SIZE]; // Used for outgoing UART symbols (which include the start and stop bit)
|
||||||
|
|
||||||
unsigned rxPT, txPT;
|
unsigned rxPT, txPT;
|
||||||
int midi_from_host_overflow = 0;
|
int midi_from_host_overflow = 0;
|
||||||
@@ -197,7 +197,7 @@ void usb_midi(
|
|||||||
{
|
{
|
||||||
// send data
|
// send data
|
||||||
// printstr("uart->decouple: ");
|
// printstr("uart->decouple: ");
|
||||||
outuint(c_midi, event);
|
midi_send_data(c_midi, event);
|
||||||
waiting_for_ack = 1;
|
waiting_for_ack = 1;
|
||||||
th_count++;
|
th_count++;
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ void usb_midi(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
// Received as packet from USB
|
||||||
case !authenticating => midi_get_ack_or_data(c_midi, is_ack, datum):
|
case !authenticating => midi_get_ack_or_data(c_midi, is_ack, datum):
|
||||||
|
|
||||||
if (is_ack)
|
if (is_ack)
|
||||||
@@ -272,7 +272,7 @@ void usb_midi(
|
|||||||
// have we got more data to send
|
// have we got more data to send
|
||||||
if (!queue_is_empty(midi_to_host_fifo))
|
if (!queue_is_empty(midi_to_host_fifo))
|
||||||
{
|
{
|
||||||
outuint(c_midi, queue_pop_word(midi_to_host_fifo, midi_to_host_fifo_arr));
|
midi_send_data(c_midi, queue_pop_word(midi_to_host_fifo, midi_to_host_fifo_arr));
|
||||||
th_count++;
|
th_count++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -281,6 +281,7 @@ void usb_midi(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
// A midi packet from the host
|
||||||
{
|
{
|
||||||
unsigned midi[3];
|
unsigned midi[3];
|
||||||
unsigned size;
|
unsigned size;
|
||||||
@@ -295,7 +296,7 @@ void usb_midi(
|
|||||||
{
|
{
|
||||||
// send data
|
// send data
|
||||||
event = byterev(event);
|
event = byterev(event);
|
||||||
outuint(c_midi, event);
|
midi_send_data(c_midi, event);
|
||||||
th_count++;
|
th_count++;
|
||||||
waiting_for_ack = 1;
|
waiting_for_ack = 1;
|
||||||
}
|
}
|
||||||
@@ -327,7 +328,7 @@ void usb_midi(
|
|||||||
midi_from_host_overflow = 1;
|
midi_from_host_overflow = 1;
|
||||||
}
|
}
|
||||||
// Drop through to the isTX guarded case
|
// Drop through to the isTX guarded case
|
||||||
if (!isTX)
|
if (!isTX && size > 0) // do not start tx'ing if this packet has no size
|
||||||
{
|
{
|
||||||
t :> txT; // Should be enough to trigger the other case
|
t :> txT; // Should be enough to trigger the other case
|
||||||
isTX = 1;
|
isTX = 1;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
# Copyright 2022-2023 XMOS LIMITED.
|
# Copyright 2022-2024 XMOS LIMITED.
|
||||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
import pytest
|
import pytest
|
||||||
import time
|
import time
|
||||||
|
import Pyxsim
|
||||||
|
from pathlib import Path
|
||||||
|
from midi_test_helpers import MIDI_TEST_CONFIGS
|
||||||
|
import subprocess
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def test_file(request):
|
def test_file(request):
|
||||||
@@ -39,3 +42,16 @@ def pytest_addoption(parser):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def options(request):
|
def options(request):
|
||||||
yield request.config.option
|
yield request.config.option
|
||||||
|
|
||||||
|
# We use the same binary multiple times so just build once for all MIDI tests
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def build_midi():
|
||||||
|
cmd = "xmake -C test_midi -j"
|
||||||
|
# result = subprocess.run(cmd, capture_output=True, text=True, shell=True)
|
||||||
|
# return_code = result.returncode
|
||||||
|
return_code = 0
|
||||||
|
|
||||||
|
assert return_code == 0, f"{result.stderr}\n{result.stdout}"
|
||||||
|
|
||||||
|
return str(Path(__file__).parent / f"test_midi/bin/")
|
||||||
|
|
||||||
|
|||||||
81
tests/midi_test_helpers.py
Normal file
81
tests/midi_test_helpers.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# Copyright 2024 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
MIDI_TEST_CONFIGS = ["xs2", "xs3"]
|
||||||
|
MIDI_RATE = 31250
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def cd(newdir, cleanup=lambda: True):
|
||||||
|
prevdir = os.getcwd()
|
||||||
|
os.chdir(os.path.expanduser(newdir))
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
os.chdir(prevdir)
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def tempdir():
|
||||||
|
dirpath = tempfile.mkdtemp(dir=os.getcwd())
|
||||||
|
def cleanup():
|
||||||
|
shutil.rmtree(dirpath)
|
||||||
|
with cd(dirpath, cleanup):
|
||||||
|
yield dirpath
|
||||||
|
|
||||||
|
class midi_expect_tx:
|
||||||
|
def __init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def expect(self, commands):
|
||||||
|
expected = ""
|
||||||
|
for command in commands:
|
||||||
|
while len(command) < 3:
|
||||||
|
command.append(0)
|
||||||
|
expected += "uart_tx_checker: " + " ".join([f"0x{byte:02x}" for byte in command]) + "\n"
|
||||||
|
|
||||||
|
return expected + "\n"
|
||||||
|
|
||||||
|
class midi_expect_rx:
|
||||||
|
def __init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def expect(self, commands):
|
||||||
|
expected = ""
|
||||||
|
for command in commands:
|
||||||
|
while len(command) < 3:
|
||||||
|
command.append(0)
|
||||||
|
expected += "dut_midi_rx: " + " ".join([f"{byte}" for byte in command]) + "\n"
|
||||||
|
|
||||||
|
return expected + "\n"
|
||||||
|
|
||||||
|
midi_tx_file = "midi_tx_cmds.txt"
|
||||||
|
midi_rx_file = "midi_rx_cmds.txt"
|
||||||
|
|
||||||
|
def create_midi_tx_file(commands=None):
|
||||||
|
with open(midi_tx_file, "wt") as mt:
|
||||||
|
if commands is None:
|
||||||
|
return
|
||||||
|
for command in commands:
|
||||||
|
while len(command) < 3:
|
||||||
|
command.append(0)
|
||||||
|
text = " ".join([str(byte) for byte in command]) + "\n"
|
||||||
|
mt.write(text)
|
||||||
|
|
||||||
|
def create_midi_rx_file(num_commands=0):
|
||||||
|
with open(midi_rx_file, "wt") as mr:
|
||||||
|
text = f"{num_commands}\n"
|
||||||
|
mr.write(text)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Test/dev only
|
||||||
|
if __name__ == "__main__":
|
||||||
|
with tempdir() as td:
|
||||||
|
print(td)
|
||||||
|
create_midi_tx_file()
|
||||||
|
input("PRESS ENTER TO CONTINUE")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2016-2022 XMOS LIMITED.
|
// Copyright 2016-2024 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.
|
||||||
#ifdef HARDWARE
|
#ifdef HARDWARE
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
/* CS2100 lists typical lock time as 100 * input period */
|
/* CS2100 lists typical lock time as 100 * input period */
|
||||||
#define AUDIO_PLL_LOCK_DELAY (40000000)
|
#define AUDIO_PLL_LOCK_DELAY (40000000)
|
||||||
|
|
||||||
#if defined(SPDIF_RX) || defined(ADAT_RX)
|
#if defined(XUA_SPDIF_RX_EN) || defined(XUA_ADAT_RX_EN)
|
||||||
#define USE_FRACTIONAL_N 1
|
#define USE_FRACTIONAL_N 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ port p_i2c = on tile[0]:PORT_I2C;
|
|||||||
|
|
||||||
#ifdef USE_FRACTIONAL_N
|
#ifdef USE_FRACTIONAL_N
|
||||||
|
|
||||||
#if !(defined(SPDIF_RX) || defined(ADAT_RX))
|
#if !(defined(XUA_SPDIF_RX_EN) || defined(XUA_ADAT_RX_EN))
|
||||||
/* Choose a frequency the xcore can easily generate internally */
|
/* Choose a frequency the xcore can easily generate internally */
|
||||||
#define PLL_SYNC_FREQ 1000000
|
#define PLL_SYNC_FREQ 1000000
|
||||||
#else
|
#else
|
||||||
@@ -95,7 +95,7 @@ void PllMult(unsigned output, unsigned ref, client interface i2c_master_if i2c)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !(defined(SPDIF_RX) || defined(ADAT_RX)) && defined(USE_FRACTIONAL_N)
|
#if !(defined(XUA_SPDIF_RX_EN) || defined(XUA_ADAT_RX_EN)) && defined(USE_FRACTIONAL_N)
|
||||||
on tile[AUDIO_IO_TILE] : out port p_pll_clk = PORT_PLL_REF;
|
on tile[AUDIO_IO_TILE] : out port p_pll_clk = PORT_PLL_REF;
|
||||||
on tile[AUDIO_IO_TILE] : clock clk_pll_sync = XS1_CLKBLK_5;
|
on tile[AUDIO_IO_TILE] : clock clk_pll_sync = XS1_CLKBLK_5;
|
||||||
#endif
|
#endif
|
||||||
@@ -111,7 +111,7 @@ void wait_us(int microseconds)
|
|||||||
|
|
||||||
void AudioHwInit(chanend ?c_codec)
|
void AudioHwInit(chanend ?c_codec)
|
||||||
{
|
{
|
||||||
#if !(defined(SPDIF_RX) || defined(ADAT_RX)) && defined(USE_FRACTIONAL_N)
|
#if !(defined(XUA_SPDIF_RX_EN) || defined(XUA_ADAT_RX_EN)) && defined(USE_FRACTIONAL_N)
|
||||||
/* Output a fixed sync clock to the pll */
|
/* Output a fixed sync clock to the pll */
|
||||||
configure_clock_rate(clk_pll_sync, 100, 100/(PLL_SYNC_FREQ/1000000));
|
configure_clock_rate(clk_pll_sync, 100, 100/(PLL_SYNC_FREQ/1000000));
|
||||||
configure_port_clock_output(p_pll_clk, clk_pll_sync);
|
configure_port_clock_output(p_pll_clk, clk_pll_sync);
|
||||||
|
|||||||
37
tests/test_midi/Makefile
Normal file
37
tests/test_midi/Makefile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# The TARGET variable determines what target system the application is
|
||||||
|
# compiled for. It either refers to an XN file in the source directories
|
||||||
|
# or a valid argument for the --target option when compiling.
|
||||||
|
|
||||||
|
ifeq ($(CONFIG), xs2)
|
||||||
|
TARGET = XCORE-200-EXPLORER
|
||||||
|
else
|
||||||
|
TARGET = XCORE-AI-EXPLORER #for xs3 and also loopback test
|
||||||
|
endif
|
||||||
|
|
||||||
|
# The APP_NAME variable determines the name of the final .xe file. It should
|
||||||
|
# not include the .xe postfix. If left blank the name will default to
|
||||||
|
# the project name
|
||||||
|
|
||||||
|
APP_NAME =
|
||||||
|
|
||||||
|
# The flags passed to xcc when building the application
|
||||||
|
# You can also set the following to override flags for a particular language:
|
||||||
|
#
|
||||||
|
# XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS
|
||||||
|
#
|
||||||
|
# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to
|
||||||
|
# xcc for the final link (mapping) stage.
|
||||||
|
XCC_FLAGS_xs2 = $(EXTRA_BUILD_FLAGS) -O2 -g
|
||||||
|
XCC_FLAGS_xs3 = $(EXTRA_BUILD_FLAGS) -O2 -g
|
||||||
|
XCC_FLAGS_LOOPBACK = $(EXTRA_BUILD_FLAGS) -O2 -g -DMIDI_LOOPBACK=1
|
||||||
|
|
||||||
|
# The USED_MODULES variable lists other module used by the application.
|
||||||
|
USED_MODULES = lib_xua
|
||||||
|
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# The following part of the Makefile includes the common build infrastructure
|
||||||
|
# for compiling XMOS applications. You should not need to edit below here.
|
||||||
|
|
||||||
|
XMOS_MAKE_PATH ?= ../..
|
||||||
|
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||||
182
tests/test_midi/src/app_midi_simple.xc
Normal file
182
tests/test_midi/src/app_midi_simple.xc
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
// Copyright 2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
#include <xs1.h>
|
||||||
|
#include <platform.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <xclib.h>
|
||||||
|
|
||||||
|
#include "xua.h"
|
||||||
|
#include "xud_device.h"
|
||||||
|
#include "midiinparse.h"
|
||||||
|
#include "midioutparse.h"
|
||||||
|
|
||||||
|
on tile[MIDI_TILE] : port p_midi_tx = XS1_PORT_4C;
|
||||||
|
#if(MIDI_RX_PORT_WIDTH == 4)
|
||||||
|
on tile[MIDI_TILE] : buffered in port:4 p_midi_rx = XS1_PORT_1F;
|
||||||
|
#elif(MIDI_RX_PORT_WIDTH == 1)
|
||||||
|
on tile[MIDI_TILE] : buffered in port:1 p_midi_rx = XS1_PORT_1F;
|
||||||
|
#endif
|
||||||
|
#define CLKBLK_MIDI XS1_CLKBLK_2
|
||||||
|
on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI;
|
||||||
|
|
||||||
|
#define MAX_TEST_COMMANDS 100
|
||||||
|
#define TEST_COMMAND_FILE_TX "midi_tx_cmds.txt"
|
||||||
|
#define TEST_COMMAND_FILE_RX "midi_rx_cmds.txt"
|
||||||
|
|
||||||
|
#define DEBUG 0 // Prints for debugging. Turn off for actual test
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#define dprintf(...) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dprintf(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* See hwsupport.xc */
|
||||||
|
void board_setup();
|
||||||
|
|
||||||
|
#ifndef CABLE_NUM
|
||||||
|
#define CABLE_NUM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned midi_in_parse_helper(unsigned midi[3], struct midi_in_parse_state &m_state){
|
||||||
|
|
||||||
|
unsigned valid = 0;
|
||||||
|
unsigned packed = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; i++){
|
||||||
|
dprintf("Packing byte %d 0x%x\n", i, midi[i]);
|
||||||
|
{valid, packed} = midi_in_parse(m_state, CABLE_NUM, midi[i]);
|
||||||
|
if(valid){
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
{unsigned, unsigned} read_config_file(uint8_t commands[MAX_TEST_COMMANDS][3])
|
||||||
|
{
|
||||||
|
unsigned tx_line_count = 0;
|
||||||
|
|
||||||
|
FILE * movable fptr_tx = fopen(TEST_COMMAND_FILE_TX,"rt");
|
||||||
|
if (fptr_tx == NULL) {
|
||||||
|
dprintf("WARNING: TX command file %s not found or unable to open.\n", TEST_COMMAND_FILE_TX);
|
||||||
|
} else {
|
||||||
|
unsigned a,b,c;
|
||||||
|
while (fscanf(fptr_tx, "%u %u %u\n", &a, &b, &c) == 3) {
|
||||||
|
commands[tx_line_count][0] = a;
|
||||||
|
commands[tx_line_count][1] = b;
|
||||||
|
commands[tx_line_count][2] = c;
|
||||||
|
//printf("Line %u params: 0x%x 0x%x 0x%x\n", tx_line_count, commands[tx_line_count][0], commands[tx_line_count][1], commands[tx_line_count][2]);
|
||||||
|
tx_line_count++;
|
||||||
|
if(tx_line_count > MAX_TEST_COMMANDS){
|
||||||
|
printf("ERROR: Too many lines in TX command file\n");
|
||||||
|
tx_line_count = MAX_TEST_COMMANDS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(move(fptr_tx));
|
||||||
|
|
||||||
|
|
||||||
|
unsigned rx_cmd_count = 0;
|
||||||
|
|
||||||
|
FILE * movable fptr_rx = fopen(TEST_COMMAND_FILE_RX,"rt");
|
||||||
|
if (fptr_rx == NULL) {
|
||||||
|
dprintf("WARNING: RX command file %s not found or unable to open.\n", TEST_COMMAND_FILE_RX);
|
||||||
|
} else {
|
||||||
|
if(fscanf(fptr_rx, "%u\n", &rx_cmd_count) != 1){
|
||||||
|
printf("ERROR: Not enough or too many items in RX command file line\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(move(fptr_rx));
|
||||||
|
|
||||||
|
return {tx_line_count, rx_cmd_count};
|
||||||
|
}
|
||||||
|
|
||||||
|
void test(chanend c_midi){
|
||||||
|
uint8_t commands[MAX_TEST_COMMANDS][3] = {{0}};
|
||||||
|
unsigned num_to_tx = 0;
|
||||||
|
unsigned num_to_rx = 0;
|
||||||
|
{num_to_tx, num_to_rx} = read_config_file(commands);
|
||||||
|
dprintf("Sending %u MIDI command line(s) and receiving %u MIDI command(s)\n", num_to_tx, num_to_rx);
|
||||||
|
|
||||||
|
// For MIDI Rx
|
||||||
|
int is_ack;
|
||||||
|
unsigned rx_packet;
|
||||||
|
|
||||||
|
// Midi in parse state
|
||||||
|
struct midi_in_parse_state m_state;
|
||||||
|
reset_midi_state(m_state);
|
||||||
|
|
||||||
|
// Counters for Rx and Tx
|
||||||
|
unsigned tx_cmd_count = 0;
|
||||||
|
unsigned rx_cmd_count = 0;
|
||||||
|
|
||||||
|
timer tmr;
|
||||||
|
|
||||||
|
int t_tx; // Used for delay between Txs
|
||||||
|
int tx_end; // Used to wait for packet to have fully left
|
||||||
|
tmr :> t_tx;
|
||||||
|
tmr :> tx_end;
|
||||||
|
|
||||||
|
const int max_tx_time = XS1_TIMER_HZ / 31250 * 3 * (8 + 1 + 1); // 30 bits at 31.25 kbps is 0.96ms
|
||||||
|
const int tx_interval = XS1_TIMER_HZ / 8000; // SoF rate on HS
|
||||||
|
tx_end += max_tx_time; // One whole packet
|
||||||
|
|
||||||
|
while(tx_cmd_count < num_to_tx || rx_cmd_count < num_to_rx ){
|
||||||
|
select{
|
||||||
|
case midi_get_ack_or_data(c_midi, is_ack, rx_packet):
|
||||||
|
if(is_ack){
|
||||||
|
dprintf("ACK from Tx\n");
|
||||||
|
tx_cmd_count++;
|
||||||
|
} else {
|
||||||
|
unsigned midi_data[3] = {0};
|
||||||
|
unsigned byte_count = 0;
|
||||||
|
// Even though this is an Rx from MIDI we use midi_out_parse so we can decode the packet
|
||||||
|
{midi_data[0], midi_data[1], midi_data[2], byte_count} = midi_out_parse(byterev(rx_packet));
|
||||||
|
dprintf("Got packet from MIDI: 0x%8x\n", rx_packet);
|
||||||
|
// Note this needs to always print for capfd in pytest to pick it up
|
||||||
|
printf("dut_midi_rx: %u %u %u\n", midi_data[0], midi_data[1], midi_data[2]);
|
||||||
|
rx_cmd_count++;
|
||||||
|
midi_send_ack(c_midi);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case tx_cmd_count < num_to_tx => tmr when timerafter(t_tx) :> int _:
|
||||||
|
unsigned midi[] = {commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2]};
|
||||||
|
// Even though this is a Tx to MIDI we use midi_in_parse_helper to form the packet from bytes
|
||||||
|
unsigned tx_packet = midi_in_parse_helper(midi, m_state);
|
||||||
|
midi_send_data(c_midi, byterev(tx_packet));
|
||||||
|
dprintf("Sent packet to midi: %u %u %u (0x%8x)\n", commands[tx_cmd_count][0], commands[tx_cmd_count][1], commands[tx_cmd_count][2], tx_packet);
|
||||||
|
t_tx += tx_interval;
|
||||||
|
tx_end += max_tx_time;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("Tx and Rx count met - exiting after last tx complete.\n");
|
||||||
|
tmr when timerafter(tx_end) :> int _; // wait until packet definitely departed
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
chan c_midi;
|
||||||
|
|
||||||
|
par
|
||||||
|
{
|
||||||
|
on tile[0]: test(c_midi);
|
||||||
|
on tile[1]: usb_midi(p_midi_rx, p_midi_tx, clk_midi, c_midi, 0);
|
||||||
|
|
||||||
|
// Setup HW so we can run this on the MC board
|
||||||
|
on tile[0]: board_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
47
tests/test_midi/src/hwsupport.xc
Normal file
47
tests/test_midi/src/hwsupport.xc
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2017-2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#include <xs1.h>
|
||||||
|
#include <platform.h>
|
||||||
|
#include "xua.h"
|
||||||
|
|
||||||
|
|
||||||
|
on tile[0]: out port p_ctrl = XS1_PORT_8D; /* p_ctrl:
|
||||||
|
* [0:3] - Unused
|
||||||
|
* [4] - EN_3v3_N (1v0 hardware only)
|
||||||
|
* [5] - EN_3v3A
|
||||||
|
* [6] - EXT_PLL_SEL (CS2100:0, SI: 1)
|
||||||
|
* [7] - MCLK_DIR (Out:0, In: 1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USE_FRACTIONAL_N (0)
|
||||||
|
|
||||||
|
#if (USE_FRACTIONAL_N)
|
||||||
|
#define EXT_PLL_SEL__MCLK_DIR (0x00)
|
||||||
|
#else
|
||||||
|
#define EXT_PLL_SEL__MCLK_DIR (0x80)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Board setup for XU316 MC Audio (1v1) */
|
||||||
|
void board_setup()
|
||||||
|
{
|
||||||
|
/* "Drive high mode" - drive high for 1, non-driving for 0 */
|
||||||
|
set_port_drive_high(p_ctrl);
|
||||||
|
|
||||||
|
/* Drive control port to turn on 3V3 and mclk direction appropriately.
|
||||||
|
* Bits set to low will be high-z, pulled down */
|
||||||
|
p_ctrl <: EXT_PLL_SEL__MCLK_DIR | 0x20;
|
||||||
|
|
||||||
|
/* Wait for power supplies to be up and stable */
|
||||||
|
delay_milliseconds(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configures the external audio hardware at startup. Note this runs on Tile[1] */
|
||||||
|
void AudioHwInit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configures the external audio hardware for the required sample frequency */
|
||||||
|
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
28
tests/test_midi/src/xua_conf.h
Normal file
28
tests/test_midi/src/xua_conf.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2017-2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
#ifndef _XUA_CONF_H_
|
||||||
|
#define _XUA_CONF_H_
|
||||||
|
|
||||||
|
#define NUM_USB_CHAN_OUT 2 /* Number of channels from host to device */
|
||||||
|
#define NUM_USB_CHAN_IN 0 /* Number of channels from device to host */
|
||||||
|
#define I2S_CHANS_DAC 2 /* Number of I2S channels out of xCORE */
|
||||||
|
#define I2S_CHANS_ADC 0 /* Number of I2S channels in to xCORE */
|
||||||
|
#define MCLK_441 (512 * 44100) /* 44.1kHz family master clock frequency */
|
||||||
|
#define MCLK_48 (512 * 48000) /* 48kHz family master clock frequency */
|
||||||
|
#define MIN_FREQ 48000 /* Minimum sample rate */
|
||||||
|
#define MAX_FREQ 48000 /* Maximum sample rate */
|
||||||
|
|
||||||
|
#define EXCLUDE_USB_AUDIO_MAIN
|
||||||
|
|
||||||
|
#define MIDI 1
|
||||||
|
#define MIDI_TILE 1
|
||||||
|
#define VENDOR_STR "XMOS"
|
||||||
|
#define VENDOR_ID 0x20B1
|
||||||
|
#define PRODUCT_STR_A2 "XUA Example"
|
||||||
|
#define PRODUCT_STR_A1 "XUA Example"
|
||||||
|
#define PID_AUDIO_1 1
|
||||||
|
#define PID_AUDIO_2 2
|
||||||
|
#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example */
|
||||||
|
|
||||||
|
#endif
|
||||||
8
tests/test_midi/src/xud_conf.h
Normal file
8
tests/test_midi/src/xud_conf.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2017-2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
#include "xua_conf.h"
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
#define XUD_UAC_NUM_USB_CHAN_OUT NUM_USB_CHAN_OUT
|
||||||
|
#define XUD_UAC_NUM_USB_CHAN_IN NUM_USB_CHAN_IN
|
||||||
62
tests/test_midi_loopback.py
Normal file
62
tests/test_midi_loopback.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Copyright 2014-2024 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import Pyxsim
|
||||||
|
from Pyxsim import testers
|
||||||
|
from pathlib import Path
|
||||||
|
from uart_rx_checker import UARTRxChecker
|
||||||
|
from midi_test_helpers import midi_expect_rx, create_midi_rx_file, create_midi_tx_file, tempdir, MIDI_RATE
|
||||||
|
from distutils.dir_util import copy_tree # we're using python 3.7 and dirs_exist_ok=True isn't available until 3.8 :(
|
||||||
|
|
||||||
|
MAX_CYCLES = 15000000
|
||||||
|
|
||||||
|
|
||||||
|
#####
|
||||||
|
# This test takes the built binary, copies it to a tmp dir and runs the midi loopback test which sends some commands
|
||||||
|
# the firmware receives them, prints and compares with the expected output
|
||||||
|
#####
|
||||||
|
def test_midi_loopback(capfd, build_midi):
|
||||||
|
# Need tempdir as we use the same config files and this causes issues when using xdist
|
||||||
|
with tempdir() as tmpdirname:
|
||||||
|
config = "LOOPBACK"
|
||||||
|
copy_tree(build_midi, tmpdirname)
|
||||||
|
xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe")
|
||||||
|
|
||||||
|
midi_commands = [
|
||||||
|
[0x90, 60, 81], #note on
|
||||||
|
[0xc0, 15], #instr select
|
||||||
|
[0xe0, 0, 96], #pitch bend
|
||||||
|
[0xff], #MIDI reset
|
||||||
|
[0x80, 60, 81], #note off
|
||||||
|
[0xf0, 0x00, 0x21], [0x1D, 0x0b, 0x33], [0x3f, 0x1e, 0xf7], # Sysex, Ableton, 0b33f1e, terminator
|
||||||
|
[0xc0, 17], #instr select
|
||||||
|
]
|
||||||
|
|
||||||
|
create_midi_rx_file(len(midi_commands))
|
||||||
|
create_midi_tx_file(midi_commands)
|
||||||
|
|
||||||
|
expected = midi_expect_rx().expect(midi_commands)
|
||||||
|
tester = testers.ComparisonTester(expected, ordered = True)
|
||||||
|
|
||||||
|
simthreads = []
|
||||||
|
|
||||||
|
simargs = ["--max-cycles", str(MAX_CYCLES)]
|
||||||
|
#This is just for local debug so we can capture the traces if needed. It slows xsim down a lot
|
||||||
|
# simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"])
|
||||||
|
|
||||||
|
Pyxsim.run_with_pyxsim(
|
||||||
|
xe,
|
||||||
|
simthreads=simthreads,
|
||||||
|
timeout=180,
|
||||||
|
simargs=simargs,
|
||||||
|
)
|
||||||
|
capture = capfd.readouterr().out
|
||||||
|
result = tester.run(capture.split("\n"))
|
||||||
|
|
||||||
|
# Print to console
|
||||||
|
with capfd.disabled():
|
||||||
|
print("CAPTURE:", capture)
|
||||||
|
print("EXPECTED:", expected)
|
||||||
|
|
||||||
|
assert result
|
||||||
71
tests/test_midi_rx.py
Normal file
71
tests/test_midi_rx.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Copyright 2014-2024 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import Pyxsim
|
||||||
|
from Pyxsim import testers
|
||||||
|
from pathlib import Path
|
||||||
|
from uart_rx_checker import UARTRxChecker
|
||||||
|
from midi_test_helpers import midi_expect_rx, create_midi_rx_file, create_midi_tx_file, tempdir, MIDI_TEST_CONFIGS, MIDI_RATE
|
||||||
|
from distutils.dir_util import copy_tree # we're using python 3.7 and dirs_exist_ok=True isn't available until 3.8 :(
|
||||||
|
|
||||||
|
MAX_CYCLES = 15000000
|
||||||
|
|
||||||
|
|
||||||
|
#####
|
||||||
|
# This test takes the built binary, copies it to a tmp dir and runs the midi Rx test which sends some commands
|
||||||
|
# to using the UARTRX checker and the firmware receives them
|
||||||
|
#####
|
||||||
|
@pytest.mark.parametrize("config", MIDI_TEST_CONFIGS)
|
||||||
|
def test_rx(capfd, config, build_midi):
|
||||||
|
# Need tempdir as we use the same config files and this causes issues when using xdist
|
||||||
|
with tempdir() as tmpdirname:
|
||||||
|
copy_tree(build_midi, tmpdirname)
|
||||||
|
xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe")
|
||||||
|
|
||||||
|
midi_commands = [[0x90, 0x91, 0x90],# Invalid and should be discarded
|
||||||
|
[0x90, 60, 81], # Note on
|
||||||
|
[0x80, 60, 81]] # Note off
|
||||||
|
|
||||||
|
midi_command_expected = midi_commands[1:] # should skip invalid first message
|
||||||
|
|
||||||
|
create_midi_rx_file(len(midi_command_expected))
|
||||||
|
create_midi_tx_file()
|
||||||
|
|
||||||
|
expected = midi_expect_rx().expect(midi_command_expected)
|
||||||
|
tester = testers.ComparisonTester(expected, ordered = True)
|
||||||
|
|
||||||
|
rx_port = "tile[1]:XS1_PORT_1F"
|
||||||
|
tx_port = "tile[1]:XS1_PORT_4C" # Needed so that UARTRxChecker (a transmitter) knows when to start
|
||||||
|
baud = MIDI_RATE
|
||||||
|
bpb = 8
|
||||||
|
parity = 0
|
||||||
|
stop = 1
|
||||||
|
|
||||||
|
midi_commands_flattened = [item for row in midi_commands for item in row]
|
||||||
|
|
||||||
|
simthreads = [
|
||||||
|
UARTRxChecker(tx_port, rx_port, parity, baud, stop, bpb, midi_commands_flattened, debug=False)
|
||||||
|
]
|
||||||
|
|
||||||
|
simargs = ["--max-cycles", str(MAX_CYCLES)]
|
||||||
|
#This is just for local debug so we can capture the traces if needed. It slows xsim down so not good for Jenkins
|
||||||
|
# simargs.extend(["--trace-to", "trace.txt", "--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"])
|
||||||
|
|
||||||
|
# with capfd.disabled(): # use to see xsim and tester output
|
||||||
|
Pyxsim.run_with_pyxsim(
|
||||||
|
xe,
|
||||||
|
simthreads=simthreads,
|
||||||
|
timeout=120,
|
||||||
|
simargs=simargs,
|
||||||
|
)
|
||||||
|
capture = capfd.readouterr().out
|
||||||
|
result = tester.run(capture.split("\n"))
|
||||||
|
|
||||||
|
# Print to console
|
||||||
|
with capfd.disabled():
|
||||||
|
print("CAPTURE:", capture)
|
||||||
|
print("EXPECTED:", expected)
|
||||||
|
|
||||||
|
|
||||||
|
assert result, f"expected: {expected}\n capture: {capture}"
|
||||||
80
tests/test_midi_tx.py
Normal file
80
tests/test_midi_tx.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Copyright 2014-2024 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import Pyxsim
|
||||||
|
from Pyxsim import testers
|
||||||
|
from pathlib import Path
|
||||||
|
from uart_tx_checker import UARTTxChecker
|
||||||
|
from midi_test_helpers import midi_expect_tx, create_midi_tx_file, create_midi_rx_file, tempdir, MIDI_TEST_CONFIGS, MIDI_RATE
|
||||||
|
from distutils.dir_util import copy_tree # we're using python 3.7 and dirs_exist_ok=True isn't available until 3.8 :(
|
||||||
|
|
||||||
|
MAX_CYCLES = 15000000
|
||||||
|
|
||||||
|
#####
|
||||||
|
# This test takes the built binary, copies it to a tmp dir and runs the midi Tx test which sends some commands
|
||||||
|
# to the firmware and then receives them using the UARTTX checker
|
||||||
|
#####
|
||||||
|
@pytest.mark.parametrize("config", MIDI_TEST_CONFIGS)
|
||||||
|
def test_tx(capfd, config, build_midi):
|
||||||
|
|
||||||
|
# Need tempdir as we use the same config files and this causes issues when using xdist
|
||||||
|
with tempdir() as tmpdirname:
|
||||||
|
copy_tree(build_midi, tmpdirname)
|
||||||
|
xe = str(Path(tmpdirname) / f"{config}/test_midi_{config}.xe")
|
||||||
|
|
||||||
|
midi_commands = [[0x90, 0x91, 0x90],# Invalid and should be discarded
|
||||||
|
[0x90, 60, 81], # Note on
|
||||||
|
[0x80, 60, 81]] # Note off
|
||||||
|
|
||||||
|
# Make a 1D list from the 2D list [1:] because first is invalid and we expect to skip it
|
||||||
|
midi_command_expected = [[item for row in midi_commands[1:] for item in row]]
|
||||||
|
|
||||||
|
create_midi_tx_file(midi_commands)
|
||||||
|
create_midi_rx_file()
|
||||||
|
|
||||||
|
expected = midi_expect_tx().expect(midi_command_expected)
|
||||||
|
tester = testers.ComparisonTester(expected, ordered = True)
|
||||||
|
|
||||||
|
tx_port = "tile[1]:XS1_PORT_4C"
|
||||||
|
baud = MIDI_RATE
|
||||||
|
bpb = 8
|
||||||
|
parity = 0
|
||||||
|
stop = 1
|
||||||
|
length_of_test = sum(len(cmd) for cmd in midi_command_expected)
|
||||||
|
|
||||||
|
simthreads = [
|
||||||
|
UARTTxChecker(tx_port, parity, baud, length_of_test, stop, bpb, debug=False)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
simargs = ["--max-cycles", str(MAX_CYCLES), "--trace-to", "trace.txt"]
|
||||||
|
#This is just for local debug so we can capture the traces if needed. It slows xsim down so not needed
|
||||||
|
# simargs.extend(["--vcd-tracing", "-tile tile[1] -ports -o trace.vcd"])
|
||||||
|
|
||||||
|
# with capfd.disabled(): # use to see xsim and tester output
|
||||||
|
Pyxsim.run_with_pyxsim(
|
||||||
|
xe,
|
||||||
|
simthreads=simthreads,
|
||||||
|
timeout=120,
|
||||||
|
simargs=simargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
capture = capfd.readouterr().out
|
||||||
|
result = tester.run(capture.split("\n"))
|
||||||
|
|
||||||
|
# Print to console
|
||||||
|
with capfd.disabled():
|
||||||
|
print("CAPTURE:", capture)
|
||||||
|
print("EXPECTED:", expected)
|
||||||
|
|
||||||
|
# Show tail of trace if there is an error
|
||||||
|
if not result:
|
||||||
|
with capfd.disabled():
|
||||||
|
print("Simulator trace tail:")
|
||||||
|
with open("trace.txt") as trace:
|
||||||
|
output = trace.readlines()
|
||||||
|
print("".join(output[-25:]))
|
||||||
|
|
||||||
|
|
||||||
|
assert result, f"expected: {expected}\n capture: {capture}"
|
||||||
@@ -3,10 +3,12 @@ TEST_FLAGS ?=
|
|||||||
|
|
||||||
XCC_FLAGS_HS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
XCC_FLAGS_HS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
||||||
-DBUS_SPEED=2 \
|
-DBUS_SPEED=2 \
|
||||||
|
-DXUA_USE_SW_PLL=0 \
|
||||||
$(TEST_FLAGS)
|
$(TEST_FLAGS)
|
||||||
|
|
||||||
XCC_FLAGS_FS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
XCC_FLAGS_FS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
||||||
-DBUS_SPEED=1 \
|
-DBUS_SPEED=1 \
|
||||||
|
-DXUA_USE_SW_PLL=0 \
|
||||||
$(TEST_FLAGS)
|
$(TEST_FLAGS)
|
||||||
|
|
||||||
TARGET = test_xs3_600.xn
|
TARGET = test_xs3_600.xn
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 XMOS LIMITED.
|
// Copyright 2022-2024 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.
|
||||||
|
|
||||||
/* Simple test to ensure reference clock to CS2100 device continues when SOF clock not available
|
/* Simple test to ensure reference clock to CS2100 device continues when SOF clock not available
|
||||||
@@ -173,6 +173,7 @@ int main()
|
|||||||
chan c_in[EP_COUNT_IN];
|
chan c_in[EP_COUNT_IN];
|
||||||
chan c_sof;
|
chan c_sof;
|
||||||
chan c_aud_ctl;
|
chan c_aud_ctl;
|
||||||
|
chan c_audio_rate_change;
|
||||||
|
|
||||||
interface pll_ref_if i_pll_ref;
|
interface pll_ref_if i_pll_ref;
|
||||||
|
|
||||||
@@ -185,7 +186,7 @@ int main()
|
|||||||
|
|
||||||
XUA_Buffer_Ep(c_out[1], /* USB Audio Out*/
|
XUA_Buffer_Ep(c_out[1], /* USB Audio Out*/
|
||||||
c_in[1], /* USB Audio In */
|
c_in[1], /* USB Audio In */
|
||||||
c_sof, c_aud_ctl, p_off_mclk, i_pll_ref
|
c_sof, c_aud_ctl, p_off_mclk, c_audio_rate_change, i_pll_ref
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,4 +194,6 @@ int main()
|
|||||||
|
|
||||||
checker();
|
checker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
178
tests/uart_rx_checker.py
Normal file
178
tests/uart_rx_checker.py
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
# Copyright 2022-2024 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
import Pyxsim as px
|
||||||
|
from typing import Sequence
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
# We need to disable output buffering for this test to work on MacOS; this has
|
||||||
|
# no effect on Linux systems. Let's redefine print once to avoid putting the
|
||||||
|
# same argument everywhere.
|
||||||
|
print = partial(print, flush=True)
|
||||||
|
|
||||||
|
Parity = dict(
|
||||||
|
UART_PARITY_EVEN=0,
|
||||||
|
UART_PARITY_ODD=1,
|
||||||
|
UART_PARITY_NONE=2,
|
||||||
|
UART_PARITY_BAD=3
|
||||||
|
)
|
||||||
|
|
||||||
|
# From tools 15.2.1 we need to add an extra factor to go from ps to fs
|
||||||
|
time_scaling_factor = 1000
|
||||||
|
|
||||||
|
class DriveHigh(px.SimThread):
|
||||||
|
def __init__(self, p):
|
||||||
|
self._p = p
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
xsi = self.xsi
|
||||||
|
|
||||||
|
xsi.drive_port_pins(self._p, 1);
|
||||||
|
|
||||||
|
|
||||||
|
class UARTRxChecker(px.SimThread):
|
||||||
|
def __init__(self, tx_port, rx_port, parity, baud, stop_bits, bpb, data=[0x7f, 0x00, 0x2f, 0xff],
|
||||||
|
intermittent=False, debug=False):
|
||||||
|
"""
|
||||||
|
Create a UARTRxChecker instance.
|
||||||
|
|
||||||
|
:param rx_port: Receive port of the UART device under test.
|
||||||
|
:param parity: Parity of the UART connection.
|
||||||
|
:param baud: BAUD rate of the UART connection.
|
||||||
|
:param stop_bits: Number of stop_bits for each UART byte.
|
||||||
|
:param bpb: Number of data bits per "byte" of UART data.
|
||||||
|
:param data: A list of bytes to send (default: [0x7f, 0x00, 0x2f, 0xff])
|
||||||
|
:param intermittent: Add a random delay between sent bytes.
|
||||||
|
"""
|
||||||
|
self._tx_port = tx_port
|
||||||
|
self._rx_port = rx_port
|
||||||
|
self._parity = parity
|
||||||
|
self._baud = baud
|
||||||
|
self._stop_bits = stop_bits
|
||||||
|
self._bits_per_byte = bpb
|
||||||
|
self._data = data
|
||||||
|
self._intermittent = intermittent
|
||||||
|
# Hex value of stop bits, as MSB 1st char, e.g. 0b11 : 0xC0
|
||||||
|
|
||||||
|
def send_byte(self, xsi, byte):
|
||||||
|
"""
|
||||||
|
Send a byte to the rx_port
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param byte: Byte to send
|
||||||
|
"""
|
||||||
|
# Send start bit
|
||||||
|
self.send_start(xsi)
|
||||||
|
|
||||||
|
# Send data
|
||||||
|
self.send_data(xsi, byte)
|
||||||
|
|
||||||
|
# Send parity
|
||||||
|
self.send_parity(xsi, byte)
|
||||||
|
|
||||||
|
# Send stop bit(s)
|
||||||
|
self.send_stop(xsi)
|
||||||
|
|
||||||
|
|
||||||
|
def send_start(self, xsi):
|
||||||
|
"""
|
||||||
|
Send a start bit.
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
"""
|
||||||
|
xsi.drive_port_pins(self._rx_port, 0)
|
||||||
|
self.wait_baud_time(xsi)
|
||||||
|
|
||||||
|
def send_data(self, xsi, byte):
|
||||||
|
"""
|
||||||
|
Write the data bits to the rx_port
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param byte: Data to send.
|
||||||
|
"""
|
||||||
|
# print(f"Checker sent 0x{byte:02x}")
|
||||||
|
for x in range(self._bits_per_byte):
|
||||||
|
# print(f" Sending bit {x}")
|
||||||
|
xsi.drive_port_pins(self._rx_port, (byte & (0x01 << x)) >= 1)
|
||||||
|
# print(f" (x): {((byte & (0x01 << x))>=1)}")
|
||||||
|
self.wait_baud_time(xsi)
|
||||||
|
|
||||||
|
def send_parity(self, xsi, byte):
|
||||||
|
"""
|
||||||
|
Send the parity bit to the rx_port
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param byte: Data to send parity of.
|
||||||
|
"""
|
||||||
|
parity = (self._parity - 1) % 3 #parity enum in lib_uart (old XC) different from SDK
|
||||||
|
if parity < 2:
|
||||||
|
crc_sum = 0
|
||||||
|
for x in range(self._bits_per_byte):
|
||||||
|
crc_sum += ((byte & (0x01 << x)) >= 1)
|
||||||
|
crc_sum += parity
|
||||||
|
# print "Parity for 0x%02x: %d" % (byte, crc_sum%2)
|
||||||
|
xsi.drive_port_pins(self._rx_port, crc_sum % 2)
|
||||||
|
self.wait_baud_time(xsi)
|
||||||
|
elif parity == Parity['UART_PARITY_BAD']:
|
||||||
|
# print "Sending bad parity bit"
|
||||||
|
self.send_bad_parity(xsi)
|
||||||
|
|
||||||
|
def send_stop(self, xsi):
|
||||||
|
"""
|
||||||
|
Send the stop bit(s) to the rx_port
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
"""
|
||||||
|
for x in range(self._stop_bits):
|
||||||
|
xsi.drive_port_pins(self._rx_port, 1)
|
||||||
|
self.wait_baud_time(xsi)
|
||||||
|
|
||||||
|
def send_bad_parity(self, xsi):
|
||||||
|
"""
|
||||||
|
Send a parity bit of 1 to simulate an incorrect parity state.
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
"""
|
||||||
|
# Always send a parity bit of 1
|
||||||
|
xsi.drive_port_pins(self._rx_port, 0)
|
||||||
|
self.wait_baud_time(xsi)
|
||||||
|
|
||||||
|
def get_bit_time(self):
|
||||||
|
"""
|
||||||
|
Returns the expected time between bits for the currently set BAUD rate.
|
||||||
|
|
||||||
|
Returns float value in nanoseconds.
|
||||||
|
"""
|
||||||
|
# Return float value in ps
|
||||||
|
return (1.0 / self._baud) * 1e12 * time_scaling_factor
|
||||||
|
|
||||||
|
def wait_baud_time(self, xsi):
|
||||||
|
"""
|
||||||
|
Wait for 1 bit time, as determined by the baud rate.
|
||||||
|
"""
|
||||||
|
self.wait_until(xsi.get_time() + self.get_bit_time())
|
||||||
|
|
||||||
|
def wait_half_baud_time(self, xsi):
|
||||||
|
"""
|
||||||
|
Wait for half a bit time, as determined by the baud rate.
|
||||||
|
"""
|
||||||
|
self.wait_until(xsi.get_time() + (self.get_bit_time() / 2))
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
xsi = self.xsi
|
||||||
|
# Drive the uart line high.
|
||||||
|
xsi.drive_port_pins(self._rx_port, 1)
|
||||||
|
|
||||||
|
# Wait for the device to bring up it's tx port, indicating it is ready
|
||||||
|
self.wait((lambda _x: self.xsi.is_port_driving(self._tx_port)))
|
||||||
|
|
||||||
|
# If we're doing an intermittent send, add a delay between each byte
|
||||||
|
# sent. Delay is in ns. 20,000ns = 20ms, 100,000ns = 100ms. Delays could
|
||||||
|
# be more variable, but it hurts test time substantially.
|
||||||
|
if self._intermittent:
|
||||||
|
for x in self._data:
|
||||||
|
k = randint(20000, 100000)
|
||||||
|
self.wait_until(xsi.get_time() + k)
|
||||||
|
self.send_byte(xsi, x)
|
||||||
|
else:
|
||||||
|
for x in self._data:
|
||||||
|
self.send_byte(xsi, x)
|
||||||
248
tests/uart_tx_checker.py
Normal file
248
tests/uart_tx_checker.py
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
# Copyright 2022-2024 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
import Pyxsim as px
|
||||||
|
from typing import Sequence
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
# We need to disable output buffering for this test to work on MacOS; this has
|
||||||
|
# no effect on Linux systems. Let's redefine print once to avoid putting the
|
||||||
|
# same argument everywhere.
|
||||||
|
print = partial(print, flush=True)
|
||||||
|
|
||||||
|
# From tools 15.2.1 we need to add an extra factor to go from ps to fs
|
||||||
|
time_scaling_factor = 1000
|
||||||
|
|
||||||
|
class UARTTxChecker(px.SimThread):
|
||||||
|
"""
|
||||||
|
This simulator thread will act as a UART device, and will check sent and
|
||||||
|
transations caused by the device, by looking at the tx pins.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, tx_port, parity, baud, length, stop_bits, bpb, debug=False):
|
||||||
|
"""
|
||||||
|
Create a UARTTxChecker instance.
|
||||||
|
|
||||||
|
:param tx_port: Transmit port of the UART device under test.
|
||||||
|
:param parity: Parity of the UART connection.
|
||||||
|
:param baud: BAUD rate of the UART connection.
|
||||||
|
:param length: Length of transmission to check.
|
||||||
|
:param stop_bits: Number of stop_bits for each UART byte.
|
||||||
|
:param bpb: Number of data bits per "byte" of UART data.
|
||||||
|
"""
|
||||||
|
self._tx_port = tx_port
|
||||||
|
self._parity = parity
|
||||||
|
self._baud = baud
|
||||||
|
self._length = length
|
||||||
|
self._stop_bits = stop_bits
|
||||||
|
self._bits_per_byte = bpb
|
||||||
|
# Hex value of stop bits, as MSB 1st char, e.g. 0b11 : 0xC0
|
||||||
|
self.debug = debug
|
||||||
|
|
||||||
|
def get_port_val(self, xsi, port):
|
||||||
|
"""
|
||||||
|
Sample the state of a port
|
||||||
|
|
||||||
|
:rtype: int
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param port: Port to sample.
|
||||||
|
"""
|
||||||
|
is_driving = xsi.is_port_driving(port)
|
||||||
|
if not is_driving:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return xsi.sample_port_pins(port)
|
||||||
|
|
||||||
|
def get_bit_time(self):
|
||||||
|
"""
|
||||||
|
Returns the expected time between bits for the currently set BAUD rate.
|
||||||
|
|
||||||
|
Returns float value in nanoseconds.
|
||||||
|
:rtype: float
|
||||||
|
"""
|
||||||
|
# Return float value in ps
|
||||||
|
return (1.0/self._baud) * 1e12 * time_scaling_factor
|
||||||
|
|
||||||
|
def wait_baud_time(self, xsi):
|
||||||
|
"""
|
||||||
|
Wait for 1 bit time, as determined by the baud rate.
|
||||||
|
"""
|
||||||
|
self.wait_until(xsi.get_time() + self.get_bit_time())
|
||||||
|
return True
|
||||||
|
|
||||||
|
def wait_half_baud_time(self, xsi):
|
||||||
|
"""
|
||||||
|
Wait for half a bit time, as determined by the baud rate.
|
||||||
|
"""
|
||||||
|
self.wait_until(xsi.get_time() + (self.get_bit_time() / 2))
|
||||||
|
|
||||||
|
def read_packet(self, xsi, parity, length=4):
|
||||||
|
"""
|
||||||
|
Read a given number of bytes of UART traffic sent by the device.
|
||||||
|
|
||||||
|
Returns a list of bytes sent by the device.
|
||||||
|
|
||||||
|
:rtype: list
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param parity: The UART partiy setting. See Parity.
|
||||||
|
:param length: The number of bytes to read. Defaults to 4.
|
||||||
|
"""
|
||||||
|
packet = []
|
||||||
|
start_time = 0
|
||||||
|
got_start_bit = False
|
||||||
|
|
||||||
|
initial_port_val = self.get_port_val(xsi, self._tx_port)
|
||||||
|
if self.debug: print("tx starts high: %s" % ("True" if initial_port_val else "False"))
|
||||||
|
|
||||||
|
for x in range(length):
|
||||||
|
byte = self.read_byte(xsi, parity)
|
||||||
|
if self.debug: print(f"Checker got byte: {byte}")
|
||||||
|
packet.append(chr(byte))
|
||||||
|
return packet
|
||||||
|
|
||||||
|
def read_byte(self, xsi, parity):
|
||||||
|
"""
|
||||||
|
Read 1 byte of UART traffic sent by the device
|
||||||
|
|
||||||
|
Returns an int, representing a byte read from the uart. Should be in the range 0 <= x < 2^bits_per_byte
|
||||||
|
|
||||||
|
:rtype: int
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param parity: The UART partiy setting. See Parity.
|
||||||
|
"""
|
||||||
|
byte = 0
|
||||||
|
val = 0
|
||||||
|
|
||||||
|
# Recv start bit
|
||||||
|
initial_port_val = self.get_port_val(xsi, self._tx_port)
|
||||||
|
|
||||||
|
if initial_port_val == 1:
|
||||||
|
self.wait_for_port_pins_change([self._tx_port])
|
||||||
|
#else go for it as assume tx has just fallen with no interframe gap
|
||||||
|
|
||||||
|
# The tx line should go low for 1 bit time
|
||||||
|
if self.get_val_timeout(xsi, self._tx_port) == 0:
|
||||||
|
if self.debug: print("Start bit recv'd")
|
||||||
|
else:
|
||||||
|
print("Start bit issue")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# recv the byte
|
||||||
|
crc_sum = 0
|
||||||
|
for j in range(self._bits_per_byte):
|
||||||
|
val = self.get_val_timeout(xsi, self._tx_port)
|
||||||
|
byte += (val << j)
|
||||||
|
crc_sum += val
|
||||||
|
|
||||||
|
if self.debug: print(f"Sampled {self._bits_per_byte} data bits: 0x{hex(byte)}")
|
||||||
|
|
||||||
|
# Check the parity if needs be
|
||||||
|
self.check_parity(xsi, crc_sum, parity)
|
||||||
|
|
||||||
|
# Get the stop bit
|
||||||
|
self.check_stopbit(xsi)
|
||||||
|
|
||||||
|
# Print a new line to split bytes in output
|
||||||
|
if self.debug: print()
|
||||||
|
|
||||||
|
return byte
|
||||||
|
|
||||||
|
def check_parity(self, xsi, crc_sum, parity):
|
||||||
|
"""
|
||||||
|
Read the parity bit and check it against a crc sum. Print correctness.
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param crc_sum: The checksum to test parity against.
|
||||||
|
:param parity: The UART partiy setting. See Parity.
|
||||||
|
"""
|
||||||
|
if parity > 0:
|
||||||
|
parity_val = 0 if parity == 1 else 1
|
||||||
|
read = self.get_val_timeout(xsi, self._tx_port)
|
||||||
|
if read == (crc_sum + parity_val) % 2:
|
||||||
|
print("Parity bit correct")
|
||||||
|
else:
|
||||||
|
print("Parity bit incorrect. Got %d, expected %d" % (read, (crc_sum + parity_val) % 2))
|
||||||
|
else:
|
||||||
|
if self.debug: print("Parity bit correct")
|
||||||
|
|
||||||
|
def check_stopbit(self, xsi):
|
||||||
|
"""
|
||||||
|
Read the stop bit(s) of a UART transmission and print correctness.
|
||||||
|
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
"""
|
||||||
|
stop_bits_correct = True
|
||||||
|
for i in range(self._stop_bits):
|
||||||
|
# The stop bits should stay high for this time
|
||||||
|
if self.get_val_timeout(xsi, self._tx_port) == 0:
|
||||||
|
stop_bits_correct = False
|
||||||
|
if self.debug: print("Stop bit correct: %s" % ("True" if stop_bits_correct else "False"))
|
||||||
|
|
||||||
|
def get_val_timeout(self, xsi, port):
|
||||||
|
"""
|
||||||
|
Get a value from a given port of the device, with a timeout determined
|
||||||
|
by the BAUD rate.
|
||||||
|
|
||||||
|
Returns whether the pin is high (True) or low (False)
|
||||||
|
|
||||||
|
:rtype: bool
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param port: The port to sample.
|
||||||
|
"""
|
||||||
|
# This intentionally has a 0.3% slop. It is per-byte and gives some
|
||||||
|
# wiggle-room if the clock doesn't divide into ns nicely.
|
||||||
|
timeout = self.get_bit_time() * 0.5
|
||||||
|
short_timeout = self.get_bit_time() * 0.2485
|
||||||
|
|
||||||
|
# Allow for "rise" time
|
||||||
|
self.wait_until(xsi.get_time() + short_timeout)
|
||||||
|
|
||||||
|
# Get val
|
||||||
|
K = self.wait_time_or_pin_change(xsi, timeout, port)
|
||||||
|
|
||||||
|
# Allow for "fall" time
|
||||||
|
self.wait_until(xsi.get_time() + short_timeout)
|
||||||
|
return K
|
||||||
|
|
||||||
|
def wait_time_or_pin_change(self, xsi, timeout, port):
|
||||||
|
"""
|
||||||
|
Waits for a given timeout, or until a port changes state. Which ever
|
||||||
|
occurs 1st. Prints an error if the former causes the function to break.
|
||||||
|
|
||||||
|
Returns whether the pin is high (True) or low (False)
|
||||||
|
|
||||||
|
:rtype: bool
|
||||||
|
:param xsi: XMOS Simulator Instance.
|
||||||
|
:param timeout: Time to wait.
|
||||||
|
:param port: Port to sample.
|
||||||
|
"""
|
||||||
|
start_time = xsi.get_time()
|
||||||
|
start_val = self.get_port_val(xsi, port)
|
||||||
|
transitioned_during_wait = False
|
||||||
|
|
||||||
|
def _continue(_timeout, _start_time, _start_val):
|
||||||
|
if xsi.get_time() >= _start_time + _timeout:
|
||||||
|
return True
|
||||||
|
if self.get_port_val(xsi, port) != _start_val:
|
||||||
|
transitioned_during_wait = True
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
wait_fun = (lambda x: _continue(timeout, start_time, start_val))
|
||||||
|
self.wait(wait_fun)
|
||||||
|
|
||||||
|
# Start value should *not* have changed during timeout
|
||||||
|
if transitioned_during_wait:
|
||||||
|
print("FAIL :: Unexpected Transition.")
|
||||||
|
|
||||||
|
return start_val
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# Wait for the xcore to bring the uart tx port up
|
||||||
|
self.wait((lambda x: self.xsi.is_port_driving(self._tx_port)))
|
||||||
|
self.wait((lambda x: self.get_port_val(self.xsi, self._tx_port) == 1))
|
||||||
|
|
||||||
|
K = self.read_packet(self.xsi, self._parity, self._length)
|
||||||
|
|
||||||
|
# Print each member of K as a hex byte
|
||||||
|
# inline lambda function mapped over a list? awh yiss.
|
||||||
|
print("uart_tx_checker:", " ".join(map((lambda x: "0x%02x" % ord(x)), K)))
|
||||||
|
|
||||||
@@ -1,103 +1,97 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.21)
|
||||||
|
include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake)
|
||||||
|
|
||||||
set(XMOS_TOOLS_PATH $ENV{XMOS_TOOL_PATH}/bin)
|
# Auto-generate schedule and top level config files
|
||||||
|
if( NOT ${Python3_FOUND} )
|
||||||
#**********************
|
message(FATAL_ERROR "Python3 not found for running . ")
|
||||||
# Setup XMOS toolchain
|
|
||||||
#**********************
|
|
||||||
if(NOT DEFINED ENV{XUA_PATH})
|
|
||||||
message(FATAL_ERROR "XUA_PATH environment variable not defined")
|
|
||||||
# some more commands
|
|
||||||
endif()
|
endif()
|
||||||
include("$ENV{XUA_PATH}/cmake_utils/xmos_toolchain.cmake")
|
|
||||||
|
|
||||||
#**********************
|
#copy conftest.py in the build directory since pytest_collect_file only collects tests from the directory tree where conftest.py is present
|
||||||
# Project
|
configure_file( conftest.py conftest.py COPYONLY )
|
||||||
#**********************
|
|
||||||
# Disable in-source build.
|
|
||||||
#if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
|
|
||||||
# message(FATAL_ERROR "In-source build is not allowed! Please specify a build folder.\n\tex:cmake -B build")
|
|
||||||
#endif()
|
|
||||||
|
|
||||||
|
## executable output directory
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||||
|
|
||||||
## Define project
|
# Set unity runner generate script
|
||||||
project(xua_unit_tests VERSION 0.1.0)
|
set(GEN_RUNNER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_unity_runner.py)
|
||||||
|
|
||||||
## Enable languages for project
|
# Create directory for runner files
|
||||||
enable_language(CXX XC C ASM)
|
set(RUNNERS_DIR ${CMAKE_CURRENT_LIST_DIR}/src.runners )
|
||||||
|
file(MAKE_DIRECTORY ${RUNNERS_DIR} )
|
||||||
|
|
||||||
message(STATUS "CAME HERE")
|
# Find unit test files
|
||||||
add_custom_target("runners" ALL)
|
file(GLOB_RECURSE TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_*/*.c)
|
||||||
add_custom_command(
|
|
||||||
TARGET runners
|
|
||||||
COMMAND python generate_unity_runners.py
|
|
||||||
COMMENT "generate unity runners"
|
|
||||||
)
|
|
||||||
|
|
||||||
message(STATUS "CAME HERE 1")
|
# For every source file in xua_unit_tests/
|
||||||
file( GLOB APP_SOURCES src/test*.xc )
|
foreach(TESTFILE ${TEST_SOURCES})
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||||
foreach( testsourcefile ${APP_SOURCES} )
|
|
||||||
get_filename_component(ITEM_NAME ${testsourcefile} NAME_WE)
|
# Get test name from C file stem
|
||||||
message(STATUS "item_name " ${ITEM_NAME})
|
cmake_path(GET TESTFILE STEM TESTNAME)
|
||||||
add_executable(${ITEM_NAME})
|
project(${TESTNAME})
|
||||||
set(APP_COMPILER_FLAGS
|
message(STATUS "Processing unit test: ${TESTNAME}")
|
||||||
"-O2"
|
|
||||||
"-g"
|
# Create runner file directory
|
||||||
"-Wall"
|
file(MAKE_DIRECTORY ${RUNNERS_DIR}/${TESTNAME})
|
||||||
"-report"
|
|
||||||
"-fxscope"
|
#####################
|
||||||
"-target=XCORE-AI-EXPLORER"
|
## Create runner file
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/config.xscope"
|
#####################
|
||||||
"-DHID_CONTROLS=1"
|
set( RUNNER_FILE ${RUNNERS_DIR}/${TESTNAME}/${TESTNAME}_Runner.c )
|
||||||
"-DUNITY_SUPPORT_64"
|
set( GEN_RUNNER_SCRIPT_BYPRODUCTS ${RUNNER_FILE})
|
||||||
"-DUNITY_INCLUDE_DOUBLE"
|
|
||||||
)
|
unset(GEN_RUNNER_SCRIPT_ARGS)
|
||||||
set_source_files_properties(
|
list(APPEND GEN_RUNNER_SCRIPT_ARGS --project-root ${XMOS_SANDBOX_DIR})
|
||||||
"runners/${ITEM_NAME}/${ITEM_NAME}_Runner.c"
|
list(APPEND GEN_RUNNER_SCRIPT_ARGS --source-file ${TESTFILE})
|
||||||
PROPERTIES GENERATED TRUE
|
list(APPEND GEN_RUNNER_SCRIPT_ARGS --runner-file ${RUNNER_FILE})
|
||||||
|
|
||||||
|
## Add command to generate runner file
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${RUNNER_FILE}
|
||||||
|
COMMAND python ${GEN_RUNNER_SCRIPT} ${GEN_RUNNER_SCRIPT_ARGS}
|
||||||
|
COMMENT "Generate XUA Unit Test Runner" )
|
||||||
|
|
||||||
|
##########################
|
||||||
|
## Do xcommon cmake build
|
||||||
|
##########################
|
||||||
|
set(APP_HW_TARGET XK-EVK-XU316)
|
||||||
|
set(APP_DEPENDENT_MODULES "lib_xua"
|
||||||
|
"lib_unity(2.5.2)")
|
||||||
|
# set(APP_PCA_ENABLE ON)
|
||||||
|
set(APP_COMPILER_FLAGS ${EXTRA_BUILD_FLAGS} -fcomment-asm
|
||||||
|
-Wall
|
||||||
|
-O2
|
||||||
|
-report
|
||||||
|
-g
|
||||||
|
-fxscope
|
||||||
|
-DUSB_TILE=tile[0]
|
||||||
|
-DUNITY_SUPPORT_64
|
||||||
|
-DUNITY_INCLUDE_DOUBLE
|
||||||
|
-DXUD_CORE_CLOCK=600
|
||||||
|
-DXUD_SERIES_SUPPORT=4
|
||||||
|
-DXASSERT_ENABLE_ASSERTIONS=0
|
||||||
)
|
)
|
||||||
|
|
||||||
set(APP_SRCS
|
# For HID tests only enable HID
|
||||||
${testsourcefile}
|
if(${TESTFILE} MATCHES ".+hid.*")
|
||||||
"runners/${ITEM_NAME}/${ITEM_NAME}_Runner.c"
|
list(APPEND APP_COMPILER_FLAGS "-DHID_CONTROLS=1")
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../Unity/src/unity.c"
|
endif()
|
||||||
)
|
|
||||||
set(APP_INCLUDES
|
|
||||||
"src"
|
# Workaround for xcommon cmake pre-pending CMAKE_CURRENT_LIST_DIR
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../Unity/src"
|
string(REPLACE ${CMAKE_CURRENT_LIST_DIR} "" UNIT_TEST_SOURCE_RELATIVE ${TESTFILE})
|
||||||
)
|
string(REPLACE ${CMAKE_CURRENT_LIST_DIR} "" RUNNER_FILE_RELATIVE ${RUNNER_FILE})
|
||||||
set(APP_DEPENDENT_MODULES
|
|
||||||
"lib_xua(>=2.0.0)"
|
set(APP_C_SRCS ${RUNNER_FILE_RELATIVE}
|
||||||
"lib_logging(>=3.0.0)"
|
${UNIT_TEST_SOURCE_RELATIVE}
|
||||||
"lib_xassert(>=4.0.0)"
|
|
||||||
"lib_xud(>=2.0.0)"
|
|
||||||
"lib_spdif(>=4.0.0)"
|
|
||||||
"lib_mic_array(>=4.0.0)"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
include("$ENV{XUA_PATH}/cmake_utils/xua.cmake")
|
|
||||||
set_target_properties(${ITEM_NAME} PROPERTIES OUTPUT_NAME ${ITEM_NAME}.xe)
|
|
||||||
target_compile_options(${ITEM_NAME} PRIVATE ${APP_COMPILER_FLAGS})
|
|
||||||
|
|
||||||
target_include_directories(${ITEM_NAME}
|
get_filename_component(TEST_FILE_DIR ${TESTFILE} DIRECTORY)
|
||||||
PRIVATE ${APP_INCLUDES}
|
set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src
|
||||||
PRIVATE ${XUA_INCLUDES_ALL}
|
${TEST_FILE_DIR}
|
||||||
)
|
${XMOS_SANDBOX_DIR}/lib_xud/lib_xud/src/user/class)
|
||||||
|
|
||||||
target_sources(${ITEM_NAME}
|
XMOS_REGISTER_APP()
|
||||||
PRIVATE ${APP_SRCS}
|
|
||||||
PRIVATE ${XUA_SRCS_ALL}
|
|
||||||
)
|
|
||||||
add_dependencies(${ITEM_NAME} runners)
|
|
||||||
target_link_options(${ITEM_NAME} PRIVATE ${APP_COMPILER_FLAGS})
|
|
||||||
## Set any additional flags only for C++
|
|
||||||
set(CMAKE_CXX_FLAGS "-std=c++11")
|
|
||||||
|
|
||||||
endforeach( testsourcefile ${APP_SOURCES} )
|
endforeach()
|
||||||
|
|
||||||
message(STATUS ${APP_SOURCES})
|
|
||||||
|
|
||||||
message(STATUS "CAME HERE 2")
|
|
||||||
## Register the application
|
|
||||||
#XMOS_REGISTER_APP()
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2021-2022 XMOS LIMITED.
|
# Copyright 2021-2024 XMOS LIMITED.
|
||||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from builtins import str
|
from builtins import str
|
||||||
@@ -28,7 +28,7 @@ class UnityTestSource(pytest.File):
|
|||||||
# unit_tests/ <- Test root directory
|
# unit_tests/ <- Test root directory
|
||||||
# |-- bin/ <- Compiled binaries of the test runners
|
# |-- bin/ <- Compiled binaries of the test runners
|
||||||
# |-- conftest.py <- This file
|
# |-- conftest.py <- This file
|
||||||
# |-- runners/ <- Auto-generated buildable source of test binaries
|
# |-- src.runners <- Auto-generated buildable source of test binaries
|
||||||
# |-- src/ <- Unity test functions
|
# |-- src/ <- Unity test functions
|
||||||
# `-- wscript <- Build system file used to generate/build runners
|
# `-- wscript <- Build system file used to generate/build runners
|
||||||
xe_name = ((os.path.basename(self.name)).split("."))[0] + ".xe"
|
xe_name = ((os.path.basename(self.name)).split("."))[0] + ".xe"
|
||||||
@@ -51,9 +51,9 @@ class UnityTestExecutable(pytest.Item):
|
|||||||
print("run axe for executable ", self.name)
|
print("run axe for executable ", self.name)
|
||||||
test_output = subprocess.check_output(["axe", self.name], text=True)
|
test_output = subprocess.check_output(["axe", self.name], text=True)
|
||||||
else:
|
else:
|
||||||
print("run xrun for executable ", self.name)
|
print("run xsim for executable ", self.name)
|
||||||
test_output = subprocess.check_output(
|
test_output = subprocess.check_output(
|
||||||
["xrun", "--io", "--id", "0", self.name],
|
["xsim", self.name],
|
||||||
text=True,
|
text=True,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
)
|
)
|
||||||
|
|||||||
59
tests/xua_unit_tests/generate_unity_runner.py
Executable file
59
tests/xua_unit_tests/generate_unity_runner.py
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
# Copyright 2024 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os.path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
def parse_arguments():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--project-root", nargs='?', help="Project root directory")
|
||||||
|
parser.add_argument("--source-file", nargs='?', help="source file.")
|
||||||
|
parser.add_argument("--runner-file", nargs='?', help="runner file.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
return args
|
||||||
|
|
||||||
|
def get_ruby():
|
||||||
|
"""
|
||||||
|
Check ruby is avaliable and return the command to invoke it.
|
||||||
|
"""
|
||||||
|
interpreter_name = 'ruby'
|
||||||
|
try:
|
||||||
|
dev_null = open(os.devnull, 'w')
|
||||||
|
# Call the version command to check the interpreter can be run
|
||||||
|
subprocess.check_call([interpreter_name, '--version'],
|
||||||
|
stdout=dev_null,
|
||||||
|
close_fds=True)
|
||||||
|
except OSError as e:
|
||||||
|
print("Failed to run Ruby interpreter: {}".format(e), file=sys.stderr)
|
||||||
|
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
||||||
|
|
||||||
|
return interpreter_name
|
||||||
|
|
||||||
|
def get_unity_runner_generator(project_root_path):
|
||||||
|
"""
|
||||||
|
Check the Unity generate_test_runner script is avaliable, and return the
|
||||||
|
path to it.
|
||||||
|
"""
|
||||||
|
unity_runner_generator = os.path.join(
|
||||||
|
project_root_path, 'Unity', 'auto', 'generate_test_runner.rb')
|
||||||
|
if not os.path.exists(unity_runner_generator):
|
||||||
|
print("Unity repo not found in workspace", file=sys.stderr)
|
||||||
|
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
||||||
|
return unity_runner_generator
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = parse_arguments()
|
||||||
|
print(f"in python: root {args.project_root}, source {args.source_file}, runner {args.runner_file}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.check_call([get_ruby(),
|
||||||
|
get_unity_runner_generator(args.project_root),
|
||||||
|
args.source_file,
|
||||||
|
args.runner_file])
|
||||||
|
except OSError as e:
|
||||||
|
print("Ruby generator failed for {}\n\t{}".format(unity_test_path, e),
|
||||||
|
file=sys.stderr)
|
||||||
|
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
# Copyright 2021-2022 XMOS LIMITED.
|
|
||||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
|
||||||
import glob
|
|
||||||
import os.path
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
UNITY_TEST_DIR = "src"
|
|
||||||
UNITY_TEST_PREFIX = "test_"
|
|
||||||
UNITY_RUNNER_DIR = "runners"
|
|
||||||
UNITY_RUNNER_SUFFIX = "_Runner"
|
|
||||||
project_root = os.path.join("..", "..", "..")
|
|
||||||
|
|
||||||
|
|
||||||
def get_ruby():
|
|
||||||
"""
|
|
||||||
Check ruby is avaliable and return the command to invoke it.
|
|
||||||
"""
|
|
||||||
interpreter_name = "ruby"
|
|
||||||
try:
|
|
||||||
dev_null = open(os.devnull, "w")
|
|
||||||
# Call the version command to check the interpreter can be run
|
|
||||||
subprocess.check_call(
|
|
||||||
[interpreter_name, "--version"], stdout=dev_null, close_fds=True
|
|
||||||
)
|
|
||||||
except OSError as e:
|
|
||||||
print("Failed to run Ruby interpreter: {}".format(e), file=sys.stderr)
|
|
||||||
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
|
||||||
|
|
||||||
return interpreter_name
|
|
||||||
|
|
||||||
|
|
||||||
def get_unity_runner_generator(project_root_path):
|
|
||||||
"""
|
|
||||||
Check the Unity generate_test_runner script is avaliable, and return the
|
|
||||||
path to it.
|
|
||||||
"""
|
|
||||||
unity_runner_generator = os.path.join(
|
|
||||||
project_root_path, "Unity", "auto", "generate_test_runner.rb"
|
|
||||||
)
|
|
||||||
if not os.path.exists(unity_runner_generator):
|
|
||||||
print("Unity repo not found in workspace", file=sys.stderr)
|
|
||||||
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
|
||||||
return unity_runner_generator
|
|
||||||
|
|
||||||
|
|
||||||
def get_test_name(test_path):
|
|
||||||
"""
|
|
||||||
Return the test name by removing the extension from the filename.
|
|
||||||
"""
|
|
||||||
return os.path.splitext(os.path.basename(test_path))[0]
|
|
||||||
|
|
||||||
|
|
||||||
def get_file_type(filename):
|
|
||||||
"""
|
|
||||||
Return the extension from the filename.
|
|
||||||
"""
|
|
||||||
return filename.rsplit(".")[-1:][0]
|
|
||||||
|
|
||||||
|
|
||||||
def generate_unity_runner(
|
|
||||||
project_root_path, unity_test_path, unity_runner_dir, unity_runner_suffix
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Invoke the Unity runner generation script for the given test file, and
|
|
||||||
return the path to the generated file. The output directory will be created
|
|
||||||
if it does not already exist.
|
|
||||||
"""
|
|
||||||
runner_path = os.path.join(
|
|
||||||
os.path.join(unity_runner_dir, get_test_name(unity_test_path))
|
|
||||||
)
|
|
||||||
if not os.path.exists(runner_path):
|
|
||||||
os.makedirs(runner_path)
|
|
||||||
|
|
||||||
unity_runner_path = os.path.join(
|
|
||||||
runner_path, get_test_name(unity_test_path) + unity_runner_suffix + "." + "c"
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
subprocess.check_call(
|
|
||||||
[
|
|
||||||
get_ruby(),
|
|
||||||
get_unity_runner_generator(project_root_path),
|
|
||||||
unity_test_path,
|
|
||||||
unity_runner_path,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
except OSError as e:
|
|
||||||
print(
|
|
||||||
"Ruby generator failed for {}\n\t{}".format(unity_test_path, e),
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
|
||||||
|
|
||||||
|
|
||||||
def find_unity_test_paths(unity_test_dir, unity_test_prefix):
|
|
||||||
"""
|
|
||||||
Return a list of all file paths with the unity_test_prefix found in the
|
|
||||||
unity_test_dir.
|
|
||||||
"""
|
|
||||||
return glob.glob(os.path.join(unity_test_dir, unity_test_prefix + "*"))
|
|
||||||
|
|
||||||
|
|
||||||
def find_unity_tests(unity_test_dir, unity_test_prefix):
|
|
||||||
"""
|
|
||||||
Return a dictionary of all {test names, test language} pairs with the
|
|
||||||
unity_test_prefix found in the unity_test_dir.
|
|
||||||
"""
|
|
||||||
unity_test_paths = find_unity_test_paths(unity_test_dir, unity_test_prefix)
|
|
||||||
print("unity_test_paths = ", unity_test_paths)
|
|
||||||
return {get_test_name(path): get_file_type(path) for path in unity_test_paths}
|
|
||||||
|
|
||||||
|
|
||||||
def find_unity_test_paths(unity_test_dir, unity_test_prefix):
|
|
||||||
"""
|
|
||||||
Return a list of all file paths with the unity_test_prefix found in the
|
|
||||||
unity_test_dir.
|
|
||||||
"""
|
|
||||||
return glob.glob(os.path.join(unity_test_dir, unity_test_prefix + "*"))
|
|
||||||
|
|
||||||
|
|
||||||
def generate_runners():
|
|
||||||
UNITY_TESTS = find_unity_tests(UNITY_TEST_DIR, UNITY_TEST_PREFIX)
|
|
||||||
print("UNITY_TESTS = ", UNITY_TESTS)
|
|
||||||
unity_test_paths = find_unity_test_paths(UNITY_TEST_DIR, UNITY_TEST_PREFIX)
|
|
||||||
print("unity_test_paths = ", unity_test_paths)
|
|
||||||
for unity_test_path in unity_test_paths:
|
|
||||||
generate_unity_runner(
|
|
||||||
project_root, unity_test_path, UNITY_RUNNER_DIR, UNITY_RUNNER_SUFFIX
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
generate_runners()
|
|
||||||
222
tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c
Normal file
222
tests/xua_unit_tests/src/test_midi_parse/test_midi_parse.c
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
// Copyright 2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "xua_unit_tests.h"
|
||||||
|
#include "../../../lib_xua/src/midi/midiinparse.h"
|
||||||
|
|
||||||
|
#define NUM_CHANS 16
|
||||||
|
#define NOTE_OFF 128
|
||||||
|
#define NOTE_ON 144
|
||||||
|
#define PRESSURE 160
|
||||||
|
#define CONTROL 176
|
||||||
|
#define PROGRAM 192
|
||||||
|
#define PRESSURE_VAL 208
|
||||||
|
#define RANGE 224
|
||||||
|
#define SYSEX_SOM 240
|
||||||
|
#define SYSEX_EOM 247
|
||||||
|
|
||||||
|
#define DATA_RANGE 128
|
||||||
|
#define DATA_MASK (DATA_RANGE - 1)
|
||||||
|
|
||||||
|
#ifndef NUM_TESTS_PER_TEST
|
||||||
|
#define NUM_TESTS_PER_TEST 30
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CABLE_NUM
|
||||||
|
#define CABLE_NUM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RANDOM_SEED 6031769
|
||||||
|
|
||||||
|
unsigned midi_in_parse_ut(unsigned midi[3]){
|
||||||
|
// printf("Composing data: 0x%x 0x%x 0x%x\n", midi[0], midi[1], midi[2]);
|
||||||
|
|
||||||
|
struct midi_in_parse_state m_state;
|
||||||
|
void * mips = &m_state;
|
||||||
|
reset_midi_state_c_wrapper(mips);
|
||||||
|
|
||||||
|
unsigned valid = 0;
|
||||||
|
unsigned packed = 0;
|
||||||
|
|
||||||
|
midi_in_parse_c_wrapper(mips, CABLE_NUM, midi[0], &valid, &packed);
|
||||||
|
// printf("Valid: %d data: %u\n", valid, packed);
|
||||||
|
if(valid){
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
midi_in_parse_c_wrapper(mips, CABLE_NUM, midi[1], &valid, &packed);
|
||||||
|
// printf("Valid: %d data: %u\n", valid, packed);
|
||||||
|
if(valid){
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
midi_in_parse_c_wrapper(mips, CABLE_NUM, midi[2], &valid, &packed);
|
||||||
|
// printf("Valid: %d data: %u\n", valid, packed);
|
||||||
|
if(valid){
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned rndm = RANDOM_SEED;
|
||||||
|
|
||||||
|
|
||||||
|
void test_midi_note(void) {
|
||||||
|
for(int cmd = NOTE_OFF; cmd < NOTE_ON + NUM_CHANS; cmd++){
|
||||||
|
for(int test = 0; test < NUM_TESTS_PER_TEST; test++){
|
||||||
|
unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK};
|
||||||
|
unsigned packed = midi_in_parse_ut(midi_ref);
|
||||||
|
|
||||||
|
unsigned midi_dut[3] = {0};
|
||||||
|
unsigned size = 0;
|
||||||
|
midi_out_parse_c_wrapper(packed, midi_dut, &size);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]);
|
||||||
|
//TEST_ASSERT_EQUAL_UINT32_ARRAY not working!?
|
||||||
|
for(int i = 0; i < size; i++){
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_midi_pressure(void) {
|
||||||
|
for(int cmd = PRESSURE; cmd < PRESSURE + NUM_CHANS; cmd++){
|
||||||
|
for(int test = 0; test < NUM_TESTS_PER_TEST; test++){
|
||||||
|
unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK};
|
||||||
|
unsigned packed = midi_in_parse_ut(midi_ref);
|
||||||
|
|
||||||
|
unsigned midi_dut[3] = {0};
|
||||||
|
unsigned size = 0;
|
||||||
|
midi_out_parse_c_wrapper(packed, midi_dut, &size);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]);
|
||||||
|
//TEST_ASSERT_EQUAL_UINT32_ARRAY not working!?
|
||||||
|
for(int i = 0; i < size; i++){
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_midi_control(void) {
|
||||||
|
for(int cmd = CONTROL; cmd < CONTROL + NUM_CHANS; cmd++){
|
||||||
|
for(int test = 0; test < NUM_TESTS_PER_TEST; test++){
|
||||||
|
unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK};
|
||||||
|
unsigned packed = midi_in_parse_ut(midi_ref);
|
||||||
|
|
||||||
|
unsigned midi_dut[3] = {0};
|
||||||
|
unsigned size = 0;
|
||||||
|
midi_out_parse_c_wrapper(packed, midi_dut, &size);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]);
|
||||||
|
//TEST_ASSERT_EQUAL_UINT32_ARRAY not working!?
|
||||||
|
for(int i = 0; i < size; i++){
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_midi_program(void) {
|
||||||
|
for(int cmd = PROGRAM; cmd < PROGRAM + NUM_CHANS; cmd++){
|
||||||
|
for(int test = 0; test < NUM_TESTS_PER_TEST; test++){
|
||||||
|
unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK};
|
||||||
|
unsigned packed = midi_in_parse_ut(midi_ref);
|
||||||
|
|
||||||
|
unsigned midi_dut[3] = {0};
|
||||||
|
unsigned size = 0;
|
||||||
|
midi_out_parse_c_wrapper(packed, midi_dut, &size);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]);
|
||||||
|
//TEST_ASSERT_EQUAL_UINT32_ARRAY not working!?
|
||||||
|
for(int i = 0; i < size; i++){
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_midi_pressure_val(void) {
|
||||||
|
for(int cmd = PRESSURE_VAL; cmd < PRESSURE_VAL + NUM_CHANS; cmd++){
|
||||||
|
for(int test = 0; test < NUM_TESTS_PER_TEST; test++){
|
||||||
|
unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK};
|
||||||
|
unsigned packed = midi_in_parse_ut(midi_ref);
|
||||||
|
|
||||||
|
unsigned midi_dut[3] = {0};
|
||||||
|
unsigned size = 0;
|
||||||
|
midi_out_parse_c_wrapper(packed, midi_dut, &size);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]);
|
||||||
|
//TEST_ASSERT_EQUAL_UINT32_ARRAY not working!?
|
||||||
|
for(int i = 0; i < size; i++){
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_midi_range(void) {
|
||||||
|
for(int cmd = RANGE; cmd < RANGE + NUM_CHANS; cmd++){
|
||||||
|
for(int test = 0; test < NUM_TESTS_PER_TEST; test++){
|
||||||
|
unsigned midi_ref[3] = {cmd, random(&rndm) & DATA_MASK, random(&rndm) & DATA_MASK};
|
||||||
|
unsigned packed = midi_in_parse_ut(midi_ref);
|
||||||
|
|
||||||
|
unsigned midi_dut[3] = {0};
|
||||||
|
unsigned size = 0;
|
||||||
|
midi_out_parse_c_wrapper(packed, midi_dut, &size);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_ref[0], midi_ref[1], midi_ref[2]);
|
||||||
|
// printf("size: %d data: 0x%x 0x%x 0x%x\n", size, midi_dut[0], midi_dut[1], midi_dut[2]);
|
||||||
|
//TEST_ASSERT_EQUAL_UINT32_ARRAY not working!?
|
||||||
|
for(int i = 0; i < size; i++){
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://cmtext.indiana.edu/MIDI/chapter3_system_messages.php
|
||||||
|
void test_midi_sys_ex(void) {
|
||||||
|
const unsigned MAX_SYS_EX_LENGTH = 200; // https://cycling74.com/forums/maximu-sysex-length
|
||||||
|
|
||||||
|
for(int sys_ex_length = 1; sys_ex_length < MAX_SYS_EX_LENGTH; sys_ex_length++){
|
||||||
|
unsigned midi_ref[1 + MAX_SYS_EX_LENGTH + 1] = {0}; // Add SOM + EOM.
|
||||||
|
unsigned msg_len = 1 + sys_ex_length + 1;
|
||||||
|
|
||||||
|
// Build message
|
||||||
|
midi_ref[0] = SYSEX_SOM;
|
||||||
|
midi_ref[1] = 0x00; // Extended manf ID
|
||||||
|
midi_ref[2] = random(&rndm) & DATA_MASK; // Manf ID 0
|
||||||
|
midi_ref[3] = random(&rndm) & DATA_MASK; // Manf ID 1
|
||||||
|
for(unsigned i = 4; i < msg_len - 1; i++){
|
||||||
|
midi_ref[i] = random(&rndm) & DATA_MASK; // Some data
|
||||||
|
}
|
||||||
|
midi_ref[msg_len - 1] = SYSEX_EOM; // End of sys-ex
|
||||||
|
|
||||||
|
unsigned midi_dut[1 + MAX_SYS_EX_LENGTH + 1 + 2] = {0}; // Add SOM + EOM. Add 2 because msg_size % 3 may be up to 2.
|
||||||
|
|
||||||
|
struct midi_in_parse_state mips;
|
||||||
|
reset_midi_state_c_wrapper(&mips);
|
||||||
|
unsigned valid = 0;
|
||||||
|
unsigned packed = 0;
|
||||||
|
|
||||||
|
unsigned out_idx = 0;
|
||||||
|
for(unsigned i = 0; i < msg_len; i++){
|
||||||
|
// printf("Ref byte: %d - 0x%x\n", i, midi_ref[i]);
|
||||||
|
midi_in_parse_c_wrapper((void * )&mips, CABLE_NUM, midi_ref[i], &valid, &packed);
|
||||||
|
if(valid){
|
||||||
|
unsigned size = 0;
|
||||||
|
midi_out_parse_c_wrapper(packed, &midi_dut[out_idx], &size);
|
||||||
|
// printf("SIZE: %u PACKED: 0x%8x, 0x%x 0x%x 0x%x\n", size, packed, midi_dut[out_idx + 0], midi_dut[out_idx + 1], midi_dut[out_idx + 2]);
|
||||||
|
out_idx += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < msg_len; i++){
|
||||||
|
// printf("%d Ref: 0x%x DUT: 0x%x\n", i, midi_ref[i], midi_dut[i]);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(midi_ref[i], midi_dut[i]);
|
||||||
|
}
|
||||||
|
printf("Sysex PASS length: %u\n", msg_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
115
tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c
Normal file
115
tests/xua_unit_tests/src/test_midi_queue/test_midi_queue.c
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Copyright 2024 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "xua_unit_tests.h"
|
||||||
|
#include "../../../lib_xua/src/midi/queue.h"
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#define dprintf(...) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dprintf(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define RANDOM_SEED 55378008
|
||||||
|
#define USB_MIDI_DEVICE_OUT_FIFO_SIZE 1024
|
||||||
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||||
|
|
||||||
|
unsigned rndm = RANDOM_SEED;
|
||||||
|
|
||||||
|
|
||||||
|
void test_midi_queue_init(void) {
|
||||||
|
queue_t symbol_fifo;
|
||||||
|
unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE];
|
||||||
|
memset(symbol_fifo_storage, USB_MIDI_DEVICE_OUT_FIFO_SIZE * sizeof(unsigned), 0xdb); // Non zero
|
||||||
|
|
||||||
|
queue_init_c_wrapper(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage));
|
||||||
|
|
||||||
|
int empty = queue_is_empty_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(1, empty);
|
||||||
|
|
||||||
|
int full = queue_is_full_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(0, full);
|
||||||
|
|
||||||
|
unsigned items = queue_items_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(0, items);
|
||||||
|
|
||||||
|
unsigned space = queue_space_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(USB_MIDI_DEVICE_OUT_FIFO_SIZE, space);
|
||||||
|
|
||||||
|
// Pop empty queue
|
||||||
|
unsigned entry = queue_pop_word_c_wrapper(&symbol_fifo, symbol_fifo_storage);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(MIDI_OUT_NULL_MESSAGE, entry);
|
||||||
|
|
||||||
|
space = queue_space_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(USB_MIDI_DEVICE_OUT_FIFO_SIZE, space);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_midi_queue_full(void) {
|
||||||
|
queue_t symbol_fifo;
|
||||||
|
unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE];
|
||||||
|
queue_init_c_wrapper(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage));
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < USB_MIDI_DEVICE_OUT_FIFO_SIZE; i++){
|
||||||
|
queue_push_word_c_wrapper(&symbol_fifo, symbol_fifo_storage, 1111);
|
||||||
|
}
|
||||||
|
|
||||||
|
int empty = queue_is_empty_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(0, empty);
|
||||||
|
|
||||||
|
int full = queue_is_full_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(1, full);
|
||||||
|
|
||||||
|
unsigned items = queue_items_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(USB_MIDI_DEVICE_OUT_FIFO_SIZE, items);
|
||||||
|
|
||||||
|
unsigned space = queue_space_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(0, space);
|
||||||
|
|
||||||
|
// We want no exception here and this to be ignored
|
||||||
|
queue_push_word_c_wrapper(&symbol_fifo, symbol_fifo_storage, 2222);
|
||||||
|
|
||||||
|
unsigned entry = queue_pop_word_c_wrapper(&symbol_fifo, symbol_fifo_storage);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(1111, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_midi_queue_push_pop(void) {
|
||||||
|
queue_t symbol_fifo;
|
||||||
|
unsigned symbol_fifo_storage[USB_MIDI_DEVICE_OUT_FIFO_SIZE];
|
||||||
|
queue_init_c_wrapper(&symbol_fifo, ARRAY_SIZE(symbol_fifo_storage));
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < USB_MIDI_DEVICE_OUT_FIFO_SIZE; i++){
|
||||||
|
int items = queue_items_c_wrapper(&symbol_fifo);
|
||||||
|
dprintf("Pre i: %u items: %d\n", i, items);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(i, items);
|
||||||
|
|
||||||
|
unsigned entry = i + 1000;
|
||||||
|
queue_push_word_c_wrapper(&symbol_fifo, symbol_fifo_storage, entry);
|
||||||
|
dprintf("pushed: %u\n", entry);
|
||||||
|
|
||||||
|
items = queue_items_c_wrapper(&symbol_fifo);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(i + 1, items);
|
||||||
|
|
||||||
|
dprintf("Post items: %d\n", items);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned counter = 0;
|
||||||
|
for(int i = USB_MIDI_DEVICE_OUT_FIFO_SIZE; i > 0; i--){
|
||||||
|
int items = queue_items_c_wrapper(&symbol_fifo);
|
||||||
|
dprintf("i: %u items: %d\n", i, items);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(i, items);
|
||||||
|
|
||||||
|
unsigned entry = queue_pop_word_c_wrapper(&symbol_fifo, symbol_fifo_storage);
|
||||||
|
unsigned expected = 1000 + counter;
|
||||||
|
|
||||||
|
dprintf("expected: %u got: %d\n", expected, entry);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(expected, entry);
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021-2022 XMOS LIMITED.
|
// Copyright 2021-2024 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -47,23 +47,26 @@ static unsigned construct_usage_header( unsigned size )
|
|||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUp( void )
|
void test_init( void )
|
||||||
{
|
{
|
||||||
hidReportInit();
|
hidReportInit();
|
||||||
hidResetReportDescriptor();
|
hidResetReportDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_validate_report( void ) {
|
void test_validate_report( void ) {
|
||||||
|
test_init();
|
||||||
unsigned retVal = hidReportValidate();
|
unsigned retVal = hidReportValidate();
|
||||||
TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal );
|
TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal );
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_reportid_in_use( void ) {
|
void test_reportid_in_use( void ) {
|
||||||
|
test_init();
|
||||||
unsigned reportIdInUse = hidIsReportIdInUse();
|
unsigned reportIdInUse = hidIsReportIdInUse();
|
||||||
TEST_ASSERT_EQUAL_UINT( 1, reportIdInUse );
|
TEST_ASSERT_EQUAL_UINT( 1, reportIdInUse );
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_get_next_valid_report_id( void ) {
|
void test_get_next_valid_report_id( void ) {
|
||||||
|
test_init();
|
||||||
unsigned reportId = 0U;
|
unsigned reportId = 0U;
|
||||||
|
|
||||||
reportId = hidGetNextValidReportId(reportId);
|
reportId = hidGetNextValidReportId(reportId);
|
||||||
@@ -80,6 +83,7 @@ void test_get_next_valid_report_id( void ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_is_report_id_valid( void ) {
|
void test_is_report_id_valid( void ) {
|
||||||
|
test_init();
|
||||||
unsigned isValid = 0;
|
unsigned isValid = 0;
|
||||||
|
|
||||||
unsigned reportId = 0;
|
unsigned reportId = 0;
|
||||||
@@ -106,6 +110,7 @@ void test_is_report_id_valid( void ) {
|
|||||||
// Basic report descriptor tests
|
// Basic report descriptor tests
|
||||||
void test_unprepared_hidGetReportDescriptor( void )
|
void test_unprepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
||||||
TEST_ASSERT_NULL( reportDescPtr );
|
TEST_ASSERT_NULL( reportDescPtr );
|
||||||
|
|
||||||
@@ -118,6 +123,7 @@ void test_unprepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_prepared_hidGetReportDescriptor( void )
|
void test_prepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
||||||
TEST_ASSERT_NOT_NULL( reportDescPtr );
|
TEST_ASSERT_NOT_NULL( reportDescPtr );
|
||||||
@@ -137,6 +143,7 @@ void test_prepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_reset_unprepared_hidGetReportDescriptor( void )
|
void test_reset_unprepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
hidResetReportDescriptor();
|
hidResetReportDescriptor();
|
||||||
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
||||||
@@ -145,6 +152,7 @@ void test_reset_unprepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_reset_prepared_hidGetReportDescriptor( void )
|
void test_reset_prepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
hidResetReportDescriptor();
|
hidResetReportDescriptor();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
@@ -154,6 +162,7 @@ void test_reset_prepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_report_id_limit( void )
|
void test_report_id_limit( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportIdLimit = hidGetReportIdLimit();
|
unsigned reportIdLimit = hidGetReportIdLimit();
|
||||||
TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit );
|
TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit );
|
||||||
}
|
}
|
||||||
@@ -161,6 +170,7 @@ void test_report_id_limit( void )
|
|||||||
// Basic item tests
|
// Basic item tests
|
||||||
void test_max_loc_hidGetReportItem( void )
|
void test_max_loc_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ];
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ];
|
||||||
unsigned char header;
|
unsigned char header;
|
||||||
unsigned char page;
|
unsigned char page;
|
||||||
@@ -199,6 +209,7 @@ void test_max_loc_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_min_loc_hidGetReportItem( void )
|
void test_min_loc_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ];
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ];
|
||||||
unsigned char header;
|
unsigned char header;
|
||||||
unsigned char page;
|
unsigned char page;
|
||||||
@@ -236,6 +247,7 @@ void test_min_loc_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_invalid_report_id( void )
|
void test_invalid_report_id( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 };
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 };
|
||||||
unsigned char header = 0x33;
|
unsigned char header = 0x33;
|
||||||
unsigned char page = 0x44;
|
unsigned char page = 0x44;
|
||||||
@@ -253,6 +265,7 @@ void test_invalid_report_id( void )
|
|||||||
|
|
||||||
void test_unused_report_id( void )
|
void test_unused_report_id( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 };
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD2 };
|
||||||
unsigned char header = 0x33;
|
unsigned char header = 0x33;
|
||||||
unsigned char page = 0x44;
|
unsigned char page = 0x44;
|
||||||
@@ -270,6 +283,7 @@ void test_unused_report_id( void )
|
|||||||
|
|
||||||
void test_overflow_bit_hidGetReportItem( void )
|
void test_overflow_bit_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
||||||
unsigned char header = 0xAA;
|
unsigned char header = 0xAA;
|
||||||
unsigned char page = 0x44;
|
unsigned char page = 0x44;
|
||||||
@@ -307,6 +321,7 @@ void test_overflow_bit_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_overflow_byte_hidGetReportItem( void )
|
void test_overflow_byte_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
||||||
unsigned char header = 0xAA;
|
unsigned char header = 0xAA;
|
||||||
unsigned char page = 0x44;
|
unsigned char page = 0x44;
|
||||||
@@ -344,6 +359,7 @@ void test_overflow_byte_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_bit_hidGetReportItem( void )
|
void test_underflow_bit_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
||||||
unsigned char header = 0xAA;
|
unsigned char header = 0xAA;
|
||||||
unsigned char page = 0x44;
|
unsigned char page = 0x44;
|
||||||
@@ -381,6 +397,7 @@ void test_underflow_bit_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_byte_hidGetReportItem( void )
|
void test_underflow_byte_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ] = { 0xBA, 0xD1 };
|
||||||
unsigned char header = 0xAA;
|
unsigned char header = 0xAA;
|
||||||
unsigned char page = 0x44;
|
unsigned char page = 0x44;
|
||||||
@@ -419,6 +436,7 @@ void test_underflow_byte_hidGetReportItem( void )
|
|||||||
// Configurable and non-configurable item tests
|
// Configurable and non-configurable item tests
|
||||||
void test_configurable_item_hidSetReportItem( void )
|
void test_configurable_item_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 1;
|
const unsigned reportId = 1;
|
||||||
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
||||||
@@ -440,6 +458,7 @@ void test_configurable_item_hidSetReportItem( void )
|
|||||||
// Testing that the high byte of the report gets correctly cleared
|
// Testing that the high byte of the report gets correctly cleared
|
||||||
void test_configurable_item_hidSetReportItem_multibyte_orig( void )
|
void test_configurable_item_hidSetReportItem_multibyte_orig( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 2;
|
const unsigned reportId = 2;
|
||||||
const unsigned bit = 1; // This byte&bit combo is originally set be 2 bytes long in the header
|
const unsigned bit = 1; // This byte&bit combo is originally set be 2 bytes long in the header
|
||||||
const unsigned byte = 0;
|
const unsigned byte = 0;
|
||||||
@@ -460,6 +479,7 @@ void test_configurable_item_hidSetReportItem_multibyte_orig( void )
|
|||||||
|
|
||||||
void test_nonconfigurable_item_hidSetReportItem( void )
|
void test_nonconfigurable_item_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 1;
|
const unsigned reportId = 1;
|
||||||
const unsigned bit = 1; // This bit and byte combination should not appear in the
|
const unsigned bit = 1; // This bit and byte combination should not appear in the
|
||||||
const unsigned byte = 0; // hidConfigurableElements list in hid_report_descriptors.c.
|
const unsigned byte = 0; // hidConfigurableElements list in hid_report_descriptors.c.
|
||||||
@@ -474,6 +494,7 @@ void test_nonconfigurable_item_hidSetReportItem( void )
|
|||||||
// Bit range tests
|
// Bit range tests
|
||||||
void test_max_bit_hidSetReportItem( void )
|
void test_max_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned char header = construct_usage_header( 0 );
|
const unsigned char header = construct_usage_header( 0 );
|
||||||
|
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
@@ -500,6 +521,7 @@ void test_max_bit_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_min_bit_hidSetReportItem( void )
|
void test_min_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned char header = construct_usage_header( 0 );
|
const unsigned char header = construct_usage_header( 0 );
|
||||||
|
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
@@ -526,6 +548,7 @@ void test_min_bit_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_overflow_bit_hidSetReportItem( void )
|
void test_overflow_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned char header = construct_usage_header( 0 );
|
const unsigned char header = construct_usage_header( 0 );
|
||||||
|
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
@@ -552,6 +575,7 @@ void test_overflow_bit_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_bit_hidSetReportItem( void )
|
void test_underflow_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned char header = construct_usage_header( 0 );
|
const unsigned char header = construct_usage_header( 0 );
|
||||||
|
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
@@ -578,6 +602,7 @@ void test_underflow_bit_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_overflow_byte_hidSetReportItem( void )
|
void test_overflow_byte_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned char header = construct_usage_header( 0 );
|
const unsigned char header = construct_usage_header( 0 );
|
||||||
|
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
@@ -604,6 +629,7 @@ void test_overflow_byte_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_byte_hidSetReportItem( void )
|
void test_underflow_byte_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned char header = construct_usage_header( 0 );
|
const unsigned char header = construct_usage_header( 0 );
|
||||||
|
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
@@ -631,6 +657,7 @@ void test_underflow_byte_hidSetReportItem( void )
|
|||||||
// Size range tests
|
// Size range tests
|
||||||
void test_max_size_hidSetReportItem( void )
|
void test_max_size_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 1;
|
const unsigned reportId = 1;
|
||||||
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
||||||
@@ -644,6 +671,7 @@ void test_max_size_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_min_size_hidSetReportItem( void )
|
void test_min_size_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 1;
|
const unsigned reportId = 1;
|
||||||
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
||||||
@@ -656,6 +684,7 @@ void test_min_size_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_unsupported_size_hidSetReportItem( void )
|
void test_unsupported_size_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
const unsigned bit = REPORT1_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
const unsigned byte = REPORT1_MIN_VALID_BYTE;
|
||||||
@@ -669,6 +698,7 @@ void test_unsupported_size_hidSetReportItem( void )
|
|||||||
// Combined function tests
|
// Combined function tests
|
||||||
void test_initial_modification_without_subsequent_preparation( void )
|
void test_initial_modification_without_subsequent_preparation( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 2;
|
const unsigned reportId = 2;
|
||||||
const unsigned bit = REPORT2_MIN_VALID_BIT;
|
const unsigned bit = REPORT2_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT2_MIN_VALID_BYTE;
|
const unsigned byte = REPORT2_MIN_VALID_BYTE;
|
||||||
@@ -685,6 +715,7 @@ void test_initial_modification_without_subsequent_preparation( void )
|
|||||||
|
|
||||||
void test_initial_modification_with_subsequent_preparation( void )
|
void test_initial_modification_with_subsequent_preparation( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 2;
|
const unsigned reportId = 2;
|
||||||
const unsigned bit = REPORT2_MIN_VALID_BIT;
|
const unsigned bit = REPORT2_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT2_MIN_VALID_BYTE;
|
const unsigned byte = REPORT2_MIN_VALID_BYTE;
|
||||||
@@ -702,6 +733,7 @@ void test_initial_modification_with_subsequent_preparation( void )
|
|||||||
|
|
||||||
void test_initial_modification_with_subsequent_verification_1( void )
|
void test_initial_modification_with_subsequent_verification_1( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 2;
|
const unsigned reportId = 2;
|
||||||
const unsigned bit = REPORT2_MIN_VALID_BIT;
|
const unsigned bit = REPORT2_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT2_MIN_VALID_BYTE;
|
const unsigned byte = REPORT2_MIN_VALID_BYTE;
|
||||||
@@ -727,6 +759,7 @@ void test_initial_modification_with_subsequent_verification_1( void )
|
|||||||
|
|
||||||
void test_initial_modification_with_subsequent_verification_2( void )
|
void test_initial_modification_with_subsequent_verification_2( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 3;
|
const unsigned reportId = 3;
|
||||||
const unsigned bit = REPORT3_MIN_VALID_BIT;
|
const unsigned bit = REPORT3_MIN_VALID_BIT;
|
||||||
const unsigned byte = REPORT3_MIN_VALID_BYTE;
|
const unsigned byte = REPORT3_MIN_VALID_BYTE;
|
||||||
@@ -775,6 +808,7 @@ void test_initial_modification_with_subsequent_verification_2( void )
|
|||||||
//setIdle and associated timing functionality tests
|
//setIdle and associated timing functionality tests
|
||||||
void test_set_idle( void )
|
void test_set_idle( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
unsigned reportId2 = 2;
|
unsigned reportId2 = 2;
|
||||||
|
|
||||||
@@ -794,6 +828,7 @@ void test_set_idle( void )
|
|||||||
|
|
||||||
void test_set_all_idle( void )
|
void test_set_all_idle( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
unsigned reportId2 = 2;
|
unsigned reportId2 = 2;
|
||||||
|
|
||||||
@@ -812,6 +847,7 @@ void test_set_all_idle( void )
|
|||||||
|
|
||||||
void test_change_pending( void )
|
void test_change_pending( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
unsigned reportId2 = 2;
|
unsigned reportId2 = 2;
|
||||||
|
|
||||||
@@ -831,6 +867,7 @@ void test_change_pending( void )
|
|||||||
|
|
||||||
void test_change_pending_all( void )
|
void test_change_pending_all( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportId = 1;
|
unsigned reportId = 1;
|
||||||
|
|
||||||
unsigned changePending = hidIsChangePending( reportId );
|
unsigned changePending = hidIsChangePending( reportId );
|
||||||
@@ -845,6 +882,7 @@ void test_change_pending_all( void )
|
|||||||
|
|
||||||
void test_report_time( void )
|
void test_report_time( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportTime1 = 123;
|
unsigned reportTime1 = 123;
|
||||||
unsigned reportTime2 = 456;
|
unsigned reportTime2 = 456;
|
||||||
|
|
||||||
@@ -859,6 +897,7 @@ void test_report_time( void )
|
|||||||
|
|
||||||
void test_report_time_calc( void )
|
void test_report_time_calc( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportTime1 = 123;
|
unsigned reportTime1 = 123;
|
||||||
unsigned reportTime2 = 456;
|
unsigned reportTime2 = 456;
|
||||||
unsigned reportPeriod1 = 10;
|
unsigned reportPeriod1 = 10;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021-2022 XMOS LIMITED.
|
// Copyright 2021-2024 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -34,23 +34,26 @@ static unsigned construct_usage_header( unsigned size )
|
|||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUp( void )
|
void test_init( void )
|
||||||
{
|
{
|
||||||
hidReportInit();
|
hidReportInit();
|
||||||
hidResetReportDescriptor();
|
hidResetReportDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_validate_report( void ) {
|
void test_validate_report( void ) {
|
||||||
|
test_init();
|
||||||
unsigned retVal = hidReportValidate();
|
unsigned retVal = hidReportValidate();
|
||||||
TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal );
|
TEST_ASSERT_EQUAL_UINT( HID_STATUS_GOOD, retVal );
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_reportid_in_use( void ) {
|
void test_reportid_in_use( void ) {
|
||||||
|
test_init();
|
||||||
unsigned reportIdInUse = hidIsReportIdInUse();
|
unsigned reportIdInUse = hidIsReportIdInUse();
|
||||||
TEST_ASSERT_EQUAL_UINT( 0, reportIdInUse );
|
TEST_ASSERT_EQUAL_UINT( 0, reportIdInUse );
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_get_next_valid_report_id( void ) {
|
void test_get_next_valid_report_id( void ) {
|
||||||
|
test_init();
|
||||||
unsigned reportId = 0U;
|
unsigned reportId = 0U;
|
||||||
|
|
||||||
reportId = hidGetNextValidReportId(reportId);
|
reportId = hidGetNextValidReportId(reportId);
|
||||||
@@ -61,6 +64,7 @@ void test_get_next_valid_report_id( void ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_is_report_id_valid( void ) {
|
void test_is_report_id_valid( void ) {
|
||||||
|
test_init();
|
||||||
unsigned isValid = 0;
|
unsigned isValid = 0;
|
||||||
|
|
||||||
unsigned reportId = 0;
|
unsigned reportId = 0;
|
||||||
@@ -75,6 +79,7 @@ void test_is_report_id_valid( void ) {
|
|||||||
// Basic report descriptor tests
|
// Basic report descriptor tests
|
||||||
void test_unprepared_hidGetReportDescriptor( void )
|
void test_unprepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
||||||
TEST_ASSERT_NULL( reportDescPtr );
|
TEST_ASSERT_NULL( reportDescPtr );
|
||||||
@@ -85,6 +90,7 @@ void test_unprepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_prepared_hidGetReportDescriptor( void )
|
void test_prepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
|
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
@@ -97,6 +103,7 @@ void test_prepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_reset_unprepared_hidGetReportDescriptor( void )
|
void test_reset_unprepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
hidResetReportDescriptor();
|
hidResetReportDescriptor();
|
||||||
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
||||||
@@ -105,6 +112,7 @@ void test_reset_unprepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_reset_prepared_hidGetReportDescriptor( void )
|
void test_reset_prepared_hidGetReportDescriptor( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
hidResetReportDescriptor();
|
hidResetReportDescriptor();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
@@ -114,6 +122,7 @@ void test_reset_prepared_hidGetReportDescriptor( void )
|
|||||||
|
|
||||||
void test_report_id_limit( void )
|
void test_report_id_limit( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportIdLimit = hidGetReportIdLimit();
|
unsigned reportIdLimit = hidGetReportIdLimit();
|
||||||
TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit );
|
TEST_ASSERT_EQUAL_UINT( HID_REPORTID_LIMIT, reportIdLimit );
|
||||||
}
|
}
|
||||||
@@ -121,6 +130,7 @@ void test_report_id_limit( void )
|
|||||||
// Basic item tests
|
// Basic item tests
|
||||||
void test_max_loc_hidGetReportItem( void )
|
void test_max_loc_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MAX_VALID_BIT;
|
const unsigned bit = MAX_VALID_BIT;
|
||||||
const unsigned byte = MAX_VALID_BYTE;
|
const unsigned byte = MAX_VALID_BYTE;
|
||||||
@@ -138,6 +148,7 @@ void test_max_loc_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_min_loc_hidGetReportItem( void )
|
void test_min_loc_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -155,6 +166,7 @@ void test_min_loc_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_overflow_bit_hidGetReportItem( void )
|
void test_overflow_bit_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MAX_VALID_BIT + 1;
|
const unsigned bit = MAX_VALID_BIT + 1;
|
||||||
const unsigned byte = MAX_VALID_BYTE;
|
const unsigned byte = MAX_VALID_BYTE;
|
||||||
@@ -172,6 +184,7 @@ void test_overflow_bit_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_overflow_byte_hidGetReportItem( void )
|
void test_overflow_byte_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MAX_VALID_BIT;
|
const unsigned bit = MAX_VALID_BIT;
|
||||||
const unsigned byte = MAX_VALID_BYTE + 1;
|
const unsigned byte = MAX_VALID_BYTE + 1;
|
||||||
@@ -189,6 +202,7 @@ void test_overflow_byte_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_bit_hidGetReportItem( void )
|
void test_underflow_bit_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const int bit = MIN_VALID_BIT - 1;
|
const int bit = MIN_VALID_BIT - 1;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -206,6 +220,7 @@ void test_underflow_bit_hidGetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_byte_hidGetReportItem( void )
|
void test_underflow_byte_hidGetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const int byte = MIN_VALID_BYTE - 1;
|
const int byte = MIN_VALID_BYTE - 1;
|
||||||
@@ -224,6 +239,7 @@ void test_underflow_byte_hidGetReportItem( void )
|
|||||||
// Configurable and non-configurable item tests
|
// Configurable and non-configurable item tests
|
||||||
void test_configurable_item_hidSetReportItem( void )
|
void test_configurable_item_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -237,6 +253,7 @@ void test_configurable_item_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_nonconfigurable_item_hidSetReportItem( void )
|
void test_nonconfigurable_item_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MAX_VALID_BIT; // This bit and byte combination should not appear in the
|
const unsigned bit = MAX_VALID_BIT; // This bit and byte combination should not appear in the
|
||||||
const unsigned byte = MIN_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c.
|
const unsigned byte = MIN_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c.
|
||||||
@@ -251,6 +268,7 @@ void test_nonconfigurable_item_hidSetReportItem( void )
|
|||||||
// Bit range tests
|
// Bit range tests
|
||||||
void test_max_bit_hidSetReportItem( void )
|
void test_max_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MAX_VALID_BIT; // Only byte 1 has bit 7 not reserved, See the
|
const unsigned bit = MAX_VALID_BIT; // Only byte 1 has bit 7 not reserved, See the
|
||||||
const unsigned byte = MAX_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c.
|
const unsigned byte = MAX_VALID_BYTE; // hidConfigurableElements list in hid_report_descriptors.c.
|
||||||
@@ -263,6 +281,7 @@ void test_max_bit_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_min_bit_hidSetReportItem( void )
|
void test_min_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -275,6 +294,7 @@ void test_min_bit_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_overflow_bit_hidSetReportItem( void )
|
void test_overflow_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MAX_VALID_BIT + 1;
|
const unsigned bit = MAX_VALID_BIT + 1;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -287,6 +307,7 @@ void test_overflow_bit_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_bit_hidSetReportItem( void )
|
void test_underflow_bit_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const int bit = MIN_VALID_BIT - 1;
|
const int bit = MIN_VALID_BIT - 1;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -300,6 +321,7 @@ void test_underflow_bit_hidSetReportItem( void )
|
|||||||
// Byte range tests
|
// Byte range tests
|
||||||
void test_max_byte_hidSetReportItem( void )
|
void test_max_byte_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MAX_VALID_BYTE;
|
const unsigned byte = MAX_VALID_BYTE;
|
||||||
@@ -312,6 +334,7 @@ void test_max_byte_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_min_byte_hidSetReportItem( void )
|
void test_min_byte_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -324,6 +347,7 @@ void test_min_byte_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_overflow_byte_hidSetReportItem( void )
|
void test_overflow_byte_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MAX_VALID_BYTE + 1;
|
const unsigned byte = MAX_VALID_BYTE + 1;
|
||||||
@@ -336,6 +360,7 @@ void test_overflow_byte_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_underflow_byte_hidSetReportItem( void )
|
void test_underflow_byte_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const int byte = MIN_VALID_BYTE - 1;
|
const int byte = MIN_VALID_BYTE - 1;
|
||||||
@@ -349,6 +374,7 @@ void test_underflow_byte_hidSetReportItem( void )
|
|||||||
// Size range tests
|
// Size range tests
|
||||||
void test_max_size_hidSetReportItem( void )
|
void test_max_size_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -362,6 +388,7 @@ void test_max_size_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_min_size_hidSetReportItem( void )
|
void test_min_size_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -374,6 +401,7 @@ void test_min_size_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_unsupported_size_hidSetReportItem( void )
|
void test_unsupported_size_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -387,6 +415,7 @@ void test_unsupported_size_hidSetReportItem( void )
|
|||||||
// Header tag and type tests
|
// Header tag and type tests
|
||||||
void test_bad_tag_hidSetReportItem( void )
|
void test_bad_tag_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -402,6 +431,7 @@ void test_bad_tag_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_global_type_hidSetReportItem( void )
|
void test_global_type_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -415,6 +445,7 @@ void test_global_type_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_local_type_hidSetReportItem( void )
|
void test_local_type_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -428,6 +459,7 @@ void test_local_type_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_main_type_hidSetReportItem( void )
|
void test_main_type_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -441,6 +473,7 @@ void test_main_type_hidSetReportItem( void )
|
|||||||
|
|
||||||
void test_reserved_type_hidSetReportItem( void )
|
void test_reserved_type_hidSetReportItem( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -455,6 +488,7 @@ void test_reserved_type_hidSetReportItem( void )
|
|||||||
// Combined function tests
|
// Combined function tests
|
||||||
void test_initial_modification_without_subsequent_preparation( void )
|
void test_initial_modification_without_subsequent_preparation( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -471,6 +505,7 @@ void test_initial_modification_without_subsequent_preparation( void )
|
|||||||
|
|
||||||
void test_initial_modification_with_subsequent_preparation( void )
|
void test_initial_modification_with_subsequent_preparation( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -488,6 +523,7 @@ void test_initial_modification_with_subsequent_preparation( void )
|
|||||||
|
|
||||||
void test_initial_modification_with_subsequent_verification_1( void )
|
void test_initial_modification_with_subsequent_verification_1( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -513,6 +549,7 @@ void test_initial_modification_with_subsequent_verification_1( void )
|
|||||||
|
|
||||||
void test_initial_modification_with_subsequent_verification_2( void )
|
void test_initial_modification_with_subsequent_verification_2( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
const unsigned reportId = 0;
|
const unsigned reportId = 0;
|
||||||
const unsigned bit = MIN_VALID_BIT;
|
const unsigned bit = MIN_VALID_BIT;
|
||||||
const unsigned byte = MIN_VALID_BYTE;
|
const unsigned byte = MIN_VALID_BYTE;
|
||||||
@@ -560,6 +597,7 @@ void test_initial_modification_with_subsequent_verification_2( void )
|
|||||||
|
|
||||||
void test_modification_without_subsequent_preparation( void )
|
void test_modification_without_subsequent_preparation( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
||||||
TEST_ASSERT_NOT_NULL( reportDescPtr );
|
TEST_ASSERT_NOT_NULL( reportDescPtr );
|
||||||
@@ -581,6 +619,7 @@ void test_modification_without_subsequent_preparation( void )
|
|||||||
|
|
||||||
void test_modification_with_subsequent_preparation( void )
|
void test_modification_with_subsequent_preparation( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
hidPrepareReportDescriptor();
|
hidPrepareReportDescriptor();
|
||||||
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
unsigned char* reportDescPtr = hidGetReportDescriptor();
|
||||||
TEST_ASSERT_NOT_NULL( reportDescPtr );
|
TEST_ASSERT_NOT_NULL( reportDescPtr );
|
||||||
@@ -604,6 +643,7 @@ void test_modification_with_subsequent_preparation( void )
|
|||||||
//setIdle functionality tests
|
//setIdle functionality tests
|
||||||
void test_set_idle( void )
|
void test_set_idle( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportId = 0;
|
unsigned reportId = 0;
|
||||||
|
|
||||||
unsigned setIdle = hidIsIdleActive( reportId );
|
unsigned setIdle = hidIsIdleActive( reportId );
|
||||||
@@ -616,6 +656,7 @@ void test_set_idle( void )
|
|||||||
|
|
||||||
void test_change_pending( void )
|
void test_change_pending( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportId = 0;
|
unsigned reportId = 0;
|
||||||
|
|
||||||
unsigned changePending = hidIsChangePending( reportId );
|
unsigned changePending = hidIsChangePending( reportId );
|
||||||
@@ -632,6 +673,7 @@ void test_change_pending( void )
|
|||||||
|
|
||||||
void test_report_time( void )
|
void test_report_time( void )
|
||||||
{
|
{
|
||||||
|
test_init();
|
||||||
unsigned reportTime = 123;
|
unsigned reportTime = 123;
|
||||||
unsigned reportPeriod = 10;
|
unsigned reportPeriod = 10;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
// Copyright 2021 XMOS LIMITED.
|
// Copyright 2021-2024 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#ifdef __XC__
|
#ifdef __XC__
|
||||||
|
|
||||||
#include <xs1.h>
|
#include <xs1.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include <xclib.h>
|
#include <xclib.h>
|
||||||
|
#include "../../../lib_xua/src/midi/midiinparse.h"
|
||||||
|
#include "../../../lib_xua/src/midi/midioutparse.h"
|
||||||
|
#include "../../../lib_xua/src/midi/queue.h"
|
||||||
|
|
||||||
#endif // __XC__
|
#endif // __XC__
|
||||||
|
|
||||||
@@ -26,3 +29,75 @@ void AudioHwInit()
|
|||||||
{
|
{
|
||||||
; // nothing
|
; // nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned random(unsigned &x){
|
||||||
|
crc32(x, -1, 0xEB31D82E);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////// Wrappers for midi parse because C doesn't support return tuples
|
||||||
|
void midi_in_parse_c_wrapper(void * unsafe mips, unsigned cable_number, unsigned char b, unsigned * unsafe valid, unsigned *unsafe packed){
|
||||||
|
unsafe{
|
||||||
|
struct midi_in_parse_state * unsafe ptr = mips;
|
||||||
|
{*valid, *packed} = midi_in_parse(*ptr, cable_number, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void midi_out_parse_c_wrapper(unsigned tx_data, unsigned midi[3], unsigned * unsafe size){
|
||||||
|
unsafe{
|
||||||
|
{midi[0], midi[1], midi[2], *size} = midi_out_parse(tx_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_midi_state_c_wrapper(void * unsafe mips){
|
||||||
|
unsafe{
|
||||||
|
struct midi_in_parse_state * unsafe ptr = mips;
|
||||||
|
reset_midi_state(*ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////// Wrappers for queue test
|
||||||
|
|
||||||
|
|
||||||
|
void queue_init_c_wrapper(queue_t *q, unsigned size) {
|
||||||
|
unsafe{
|
||||||
|
queue_init(*q, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int queue_is_empty_c_wrapper(queue_t *unsafe q) {
|
||||||
|
unsafe{
|
||||||
|
return queue_is_empty(*q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int queue_is_full_c_wrapper(queue_t *unsafe q) {
|
||||||
|
unsafe{
|
||||||
|
return queue_is_full(*q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_push_word_c_wrapper(queue_t *q, unsigned array[], unsigned data){
|
||||||
|
unsafe{
|
||||||
|
queue_push_word(*q, array, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned queue_pop_word_c_wrapper(queue_t *q, unsigned array[]){
|
||||||
|
unsafe{
|
||||||
|
return queue_pop_word(*q, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned queue_items_c_wrapper(const queue_t *q){
|
||||||
|
unsafe{
|
||||||
|
return queue_items(*q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned queue_space_c_wrapper(const queue_t *q){
|
||||||
|
unsafe{
|
||||||
|
return queue_space(*q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
// Copyright 2021 XMOS LIMITED.
|
// Copyright 2021-2024 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#ifndef XUA_UNIT_TESTS_H_
|
#ifndef XUA_UNIT_TESTS_H_
|
||||||
#define XUA_UNIT_TESTS_H_
|
#define XUA_UNIT_TESTS_H_
|
||||||
|
|
||||||
#include "unity.h"
|
#include "unity.h"
|
||||||
#include "xua_conf.h"
|
#include "xua_conf.h"
|
||||||
|
#include "../../../lib_xua/src/midi/queue.h"
|
||||||
|
|
||||||
|
#ifndef __XC__
|
||||||
|
void midi_in_parse_c_wrapper(void * mips, unsigned cable_number, unsigned char b, unsigned * valid, unsigned * packed);
|
||||||
|
void midi_out_parse_c_wrapper(unsigned tx_data, unsigned midi[3], unsigned * size);
|
||||||
|
void reset_midi_state_c_wrapper(void *mips);
|
||||||
|
unsigned random(unsigned *x);
|
||||||
|
|
||||||
|
void queue_init_c_wrapper(queue_t *q, unsigned size);
|
||||||
|
int queue_is_empty_c_wrapper(const queue_t *q);
|
||||||
|
int queue_is_full_c_wrapper(const queue_t *q);
|
||||||
|
void queue_push_word_c_wrapper(queue_t *q, unsigned array[], unsigned data);
|
||||||
|
unsigned queue_pop_word_c_wrapper(queue_t *q, unsigned array[]);
|
||||||
|
void queue_push_byte_c_wrapper(queue_t *q, unsigned char array[], unsigned data);
|
||||||
|
unsigned queue_pop_byte_c_wrapper(queue_t *q, unsigned char array[]);
|
||||||
|
unsigned queue_items_c_wrapper(const queue_t *q);
|
||||||
|
unsigned queue_space_c_wrapper(const queue_t *q);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* XUA_UNIT_TESTS_H_ */
|
#endif /* XUA_UNIT_TESTS_H_ */
|
||||||
|
|||||||
@@ -1,260 +0,0 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import glob
|
|
||||||
import os.path
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
from waflib import Options
|
|
||||||
from waflib.Build import BuildContext, CleanContext
|
|
||||||
|
|
||||||
TARGETS = ['xcore200', 'xcoreai']
|
|
||||||
|
|
||||||
def get_ruby():
|
|
||||||
"""
|
|
||||||
Check ruby is avaliable and return the command to invoke it.
|
|
||||||
"""
|
|
||||||
interpreter_name = 'ruby'
|
|
||||||
try:
|
|
||||||
dev_null = open(os.devnull, 'w')
|
|
||||||
# Call the version command to check the interpreter can be run
|
|
||||||
subprocess.check_call([interpreter_name, '--version'],
|
|
||||||
stdout=dev_null,
|
|
||||||
close_fds=True)
|
|
||||||
except OSError as e:
|
|
||||||
print("Failed to run Ruby interpreter: {}".format(e), file=sys.stderr)
|
|
||||||
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
|
||||||
|
|
||||||
return interpreter_name
|
|
||||||
|
|
||||||
|
|
||||||
def get_unity_runner_generator(project_root_path):
|
|
||||||
"""
|
|
||||||
Check the Unity generate_test_runner script is avaliable, and return the
|
|
||||||
path to it.
|
|
||||||
"""
|
|
||||||
unity_runner_generator = os.path.join(
|
|
||||||
project_root_path, 'Unity', 'auto', 'generate_test_runner.rb')
|
|
||||||
if not os.path.exists(unity_runner_generator):
|
|
||||||
print("Unity repo not found in workspace", file=sys.stderr)
|
|
||||||
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
|
||||||
return unity_runner_generator
|
|
||||||
|
|
||||||
|
|
||||||
def get_test_name(test_path):
|
|
||||||
"""
|
|
||||||
Return the test name by removing the extension from the filename.
|
|
||||||
"""
|
|
||||||
return os.path.splitext(os.path.basename(test_path))[0]
|
|
||||||
|
|
||||||
|
|
||||||
def get_file_type(filename):
|
|
||||||
"""
|
|
||||||
Return the extension from the filename.
|
|
||||||
"""
|
|
||||||
return filename.rsplit('.')[-1:][0]
|
|
||||||
|
|
||||||
|
|
||||||
def generate_unity_runner(project_root_path, unity_test_path, unity_runner_dir,
|
|
||||||
unity_runner_suffix):
|
|
||||||
"""
|
|
||||||
Invoke the Unity runner generation script for the given test file, and
|
|
||||||
return the path to the generated file. The output directory will be created
|
|
||||||
if it does not already exist.
|
|
||||||
"""
|
|
||||||
runner_path = os.path.join(os.path.join(unity_runner_dir, get_test_name(unity_test_path)))
|
|
||||||
if not os.path.exists(runner_path):
|
|
||||||
os.makedirs(runner_path)
|
|
||||||
|
|
||||||
unity_runner_path = os.path.join(
|
|
||||||
runner_path, get_test_name(unity_test_path) + unity_runner_suffix
|
|
||||||
+ '.' + 'c')
|
|
||||||
|
|
||||||
try:
|
|
||||||
subprocess.check_call([get_ruby(),
|
|
||||||
get_unity_runner_generator(project_root_path),
|
|
||||||
unity_test_path,
|
|
||||||
unity_runner_path])
|
|
||||||
except OSError as e:
|
|
||||||
print("Ruby generator failed for {}\n\t{}".format(unity_test_path, e),
|
|
||||||
file=sys.stderr)
|
|
||||||
exit(1) # TODO: Check this is the correct way to kill xwaf on error
|
|
||||||
|
|
||||||
|
|
||||||
def add_unity_runner_build_config(waf_conf, project_root_path, unity_test_path,
|
|
||||||
unity_runner_build_flags, target):
|
|
||||||
"""
|
|
||||||
Add a config to xwaf to build each Unity test runner into an xCORE
|
|
||||||
executable.
|
|
||||||
"""
|
|
||||||
print(f"get_test_name(unity_test_path) = {get_test_name(unity_test_path)}. target = {target}")
|
|
||||||
waf_conf.setenv(get_test_name(unity_test_path) + '_' + target)
|
|
||||||
waf_conf.load('xwaf.compiler_xcc')
|
|
||||||
waf_conf.env.XCC_FLAGS = unity_runner_build_flags
|
|
||||||
waf_conf.env.PROJECT_ROOT = project_root_path
|
|
||||||
# TODO: can the xwaf boilerplate help here?
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_unity_test_for_build(waf_conf, project_root_path, unity_test_path,
|
|
||||||
unity_runner_dir, unity_runner_suffix, target):
|
|
||||||
print("unity_test_path: " + str(unity_test_path))
|
|
||||||
generate_unity_runner(project_root_path, unity_test_path,
|
|
||||||
unity_runner_dir, unity_runner_suffix)
|
|
||||||
runner_build_flags = '' # Could extract flags from the test name
|
|
||||||
add_unity_runner_build_config(waf_conf, project_root_path, unity_test_path,
|
|
||||||
runner_build_flags, target)
|
|
||||||
|
|
||||||
|
|
||||||
def find_unity_test_paths(unity_test_dir, unity_test_prefix):
|
|
||||||
"""
|
|
||||||
Return a list of all file paths with the unity_test_prefix found in the
|
|
||||||
unity_test_dir.
|
|
||||||
"""
|
|
||||||
file_list = []
|
|
||||||
for root, dirs, files in os.walk(unity_test_dir):
|
|
||||||
for f in files:
|
|
||||||
if f.startswith(unity_test_prefix):
|
|
||||||
file_list.append(os.path.join(root,f))
|
|
||||||
return file_list
|
|
||||||
|
|
||||||
|
|
||||||
def find_unity_tests(unity_test_dir, unity_test_prefix):
|
|
||||||
"""
|
|
||||||
Return a dictionary of all {test names, test language} pairs with the
|
|
||||||
unity_test_prefix found in the unity_test_dir.
|
|
||||||
"""
|
|
||||||
unity_test_paths = find_unity_test_paths(unity_test_dir, unity_test_prefix)
|
|
||||||
return {get_test_name(path): {"language": get_file_type(path), "dir": os.path.dirname(path)}
|
|
||||||
for path in unity_test_paths}
|
|
||||||
|
|
||||||
|
|
||||||
def generate_all_unity_runners(waf_conf, project_root_path,
|
|
||||||
unity_test_dir, unity_test_prefix,
|
|
||||||
unity_runner_dir, unity_runner_suffix):
|
|
||||||
"""
|
|
||||||
Generate a runner and a build config for each test file in the
|
|
||||||
unity_test_dir.
|
|
||||||
"""
|
|
||||||
# FIXME: pass unity_tests in?
|
|
||||||
unity_test_paths = find_unity_test_paths(unity_test_dir, unity_test_prefix)
|
|
||||||
for trgt in TARGETS:
|
|
||||||
for unity_test_path in unity_test_paths:
|
|
||||||
prepare_unity_test_for_build(waf_conf, project_root_path,
|
|
||||||
unity_test_path,
|
|
||||||
unity_runner_dir, unity_runner_suffix, trgt)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: can the xwaf boilerplate help here?
|
|
||||||
def create_waf_contexts(configs):
|
|
||||||
for trgt in TARGETS:
|
|
||||||
for test_name, params in configs.items():
|
|
||||||
print(f"test_name {test_name}, test_language {params['language']}")
|
|
||||||
for ctx in (BuildContext, CleanContext):
|
|
||||||
raw_context = ctx.__name__.replace('Context', '').lower()
|
|
||||||
|
|
||||||
class tmp(ctx):
|
|
||||||
cmd = raw_context + '_' + test_name + '_' + trgt
|
|
||||||
variant = test_name + '_' + trgt
|
|
||||||
#cmd = raw_context + '_' + test_name
|
|
||||||
#variant = test_name
|
|
||||||
language = params["language"]
|
|
||||||
target = trgt
|
|
||||||
runner = test_name
|
|
||||||
directory = params["dir"]
|
|
||||||
print(f"cmd {cmd}, variant {variant}, language {language}")
|
|
||||||
|
|
||||||
|
|
||||||
UNITY_TEST_DIR = 'src'
|
|
||||||
UNITY_TEST_PREFIX = 'test_'
|
|
||||||
UNITY_RUNNER_DIR = 'runners'
|
|
||||||
UNITY_RUNNER_SUFFIX = '_Runner'
|
|
||||||
UNITY_TESTS = find_unity_tests(UNITY_TEST_DIR, UNITY_TEST_PREFIX)
|
|
||||||
|
|
||||||
print("UNITY_TESTS: " + str(UNITY_TESTS))
|
|
||||||
|
|
||||||
create_waf_contexts(UNITY_TESTS)
|
|
||||||
|
|
||||||
def options(opt):
|
|
||||||
opt.add_option('--target', action='store', default='xcore200')
|
|
||||||
opt.load('xwaf.xcommon')
|
|
||||||
|
|
||||||
def configure(conf):
|
|
||||||
# TODO: move the call to generate_all_unity_runners() to build()
|
|
||||||
project_root = os.path.join('..', '..', '..')
|
|
||||||
generate_all_unity_runners(conf, project_root,
|
|
||||||
UNITY_TEST_DIR, UNITY_TEST_PREFIX,
|
|
||||||
UNITY_RUNNER_DIR, UNITY_RUNNER_SUFFIX)
|
|
||||||
conf.load('xwaf.xcommon')
|
|
||||||
|
|
||||||
def build(bld):
|
|
||||||
if not bld.variant:
|
|
||||||
print('Adding test runners to build queue')
|
|
||||||
trgt = [
|
|
||||||
c for c in TARGETS if c == bld.options.target
|
|
||||||
]
|
|
||||||
|
|
||||||
if len(trgt) == 0:
|
|
||||||
bld.fatal('specify a target with --target.\nAvailable targets: {}'.format(', '.join(TARGETS)))
|
|
||||||
return
|
|
||||||
|
|
||||||
for name in UNITY_TESTS:
|
|
||||||
Options.commands.insert(0, 'build_' + name + '_' + trgt[0])
|
|
||||||
#Options.commands.insert(0, 'build_' + name)
|
|
||||||
print('Build queue {}'.format(Options.commands))
|
|
||||||
else:
|
|
||||||
print('Building runner {}'.format(bld.runner))
|
|
||||||
bld.env.XSCOPE = bld.path.find_resource('config.xscope')
|
|
||||||
|
|
||||||
depends_on = ['lib_xua',
|
|
||||||
'lib_xud',
|
|
||||||
'lib_spdif',
|
|
||||||
'lib_mic_array',
|
|
||||||
'lib_logging',
|
|
||||||
'lib_xassert',
|
|
||||||
'Unity']
|
|
||||||
|
|
||||||
makefile_opts = {}
|
|
||||||
makefile_opts['SOURCE_DIRS'] = ['src', bld.directory, os.path.join('runners',bld.runner)]
|
|
||||||
if(bld.target == 'xcoreai'):
|
|
||||||
print('TARGET XCOREAI')
|
|
||||||
makefile_opts['TARGET'] = ['XCORE-AI-EXPLORER']
|
|
||||||
else:
|
|
||||||
print('TARGET XCORE200')
|
|
||||||
makefile_opts['TARGET'] = ['XCORE-200-EXPLORER']
|
|
||||||
|
|
||||||
makefile_opts['INCLUDE_DIRS'] = ['src',
|
|
||||||
bld.directory,
|
|
||||||
'../../lib_xua/api',
|
|
||||||
'../../lib_xua/src/core/pdm_mics',
|
|
||||||
'../../lib_xua/src/hid',
|
|
||||||
'../../../lib_xud/lib_xud/src/user/class']
|
|
||||||
|
|
||||||
makefile_opts['XCC_FLAGS'] = ['-O2',
|
|
||||||
'-g',
|
|
||||||
'-Wall',
|
|
||||||
'-DHID_CONTROLS=1',
|
|
||||||
'-DUNITY_SUPPORT_64',
|
|
||||||
'-DUNITY_INCLUDE_DOUBLE',
|
|
||||||
'-DXUD_CORE_CLOCK=600',
|
|
||||||
'-DXUD_SERIES_SUPPORT=4']
|
|
||||||
|
|
||||||
makefile_opts['APP_NAME'] = [bld.variant]
|
|
||||||
makefile_opts['USED_MODULES'] = depends_on
|
|
||||||
makefile_opts['XCOMMON_MAKEFILE'] = ['Makefile.common']
|
|
||||||
bld.do_xcommon(makefile_opts)
|
|
||||||
|
|
||||||
|
|
||||||
def test(bld):
|
|
||||||
# Call pytest to run Unity tests inside axe or xsim
|
|
||||||
try:
|
|
||||||
test_output = subprocess.check_output(['pytest'])
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
# pytest exits non-zero if an assertion fails
|
|
||||||
test_output = e.output
|
|
||||||
print(test_output)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: ensure clean deletes the runners dir/
|
|
||||||
def dist(ctx):
|
|
||||||
ctx.load('xwaf.xcommon')
|
|
||||||
|
|
||||||
def distcheck(ctx):
|
|
||||||
ctx.load('xwaf.xcommon')
|
|
||||||
Reference in New Issue
Block a user