add app_usb_aud_phaten_golden_6ch

This commit is contained in:
Steven Dan
2026-03-23 21:01:33 +08:00
parent 90df0a435a
commit 36db777fe9
62 changed files with 20545 additions and 0 deletions

View File

@@ -0,0 +1,224 @@
cmake_minimum_required(VERSION 3.21)
include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake)
project(app_usb_aud_phaten_gs)
set(APP_HW_TARGET synido.xn)
include(${CMAKE_CURRENT_LIST_DIR}/../deps.cmake)
set(APP_PCA_ENABLE ON)
###=========================================================================###
set(TARGET_HW_PHATEN_GSV2 ON)
set(CODEC_IS_AIC3204 ON)
# Configure host os detection here... (Windows or Non-Windows)
#-----------------------------------------------------------------------------#
# Host OS detection, set HOST_OS_DETECTION to ON
set(HOST_OS_DETECTION ON)
###=========================================================================###
# Customer
if (TARGET_HW_PHATEN_GSV2)
message("-- Building for PHATEN_GSv2 ---")
set(TARGET_BOARD PHATEN_GSV2)
set(APP_HW_TARGET synido.xn)
endif()
# CODEC IC
if (CODEC_IS_AIC3204)
message("-- DAC: AIC3204 ---")
set(CODEC_IC CODEC_AIC3204)
endif()
# Host OS detection
if (HOST_OS_DETECTION)
message("-- Host OS detection (Windows/Non-Windows) enabled ---")
set(EXTRA_BUILD_FLAGS ${EXTRA_BUILD_FLAGS} -DHOST_OS_DETECTION)
endif()
set(SW_USB_AUDIO_FLAGS ${EXTRA_BUILD_FLAGS} -Os
-report
-L${CMAKE_CURRENT_LIST_DIR}/../../lib_ex3d/lib_ex3d/lib
-lquadflash
-g
#-fxscope
-DUSB_TILE=tile[0]
-DXUA_QUAD_SPI_FLASH=1
-D${TARGET_BOARD}
-DBCD_DEVICE_J=1
-DBCD_DEVICE_M=0
-DBCD_DEVICE_N=0
-D${CODEC_IC}
-DWINDOWS_OS_DESCRIPTOR_SUPPORT
-DDEBUG_PRINT_ENABLE=0)
LINK_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/../../lib_dnr/lib_dnr)
set(APP_COMPILER_FLAGS_ex3d_UAC1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DI2S_CHANS_ADC=0
-DAUDIO_CLASS=1
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DUSE_EX3D
-DMIXER=0
-DAIZIP_DNR=0 #-ldnr_50ms
-llib_ex3d_stereo_2k
-DNUM_USB_CHAN_OUT=2
-DNUM_USB_CHAN_OUT_FS=2
-DNUM_USB_CHAN_IN=0
-DSTREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS=16
-DSTREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS=16
-DSTREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS=16
-DSTREAM_FORMAT_INPUT_1_RESOLUTION_BITS=16
-DSTREAM_FORMAT_INPUT_2_RESOLUTION_BITS=16
-DSTREAM_FORMAT_INPUT_3_RESOLUTION_BITS=16
-DNUM_EX3D_CHAN_OUT=2
-DINPUT_VOLUME_CONTROL=0
-DUAC1_MODE=1
-DOUTPUT_VOLUME_CONTROL=0
-DXUA_DFU_EN=0
-DSTEREO_2K
-DHID_CONTROLS=0)
#set(APP_COMPILER_FLAGS_ex3d_stereo_2k ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
# -DI2S_CHANS_ADC=2
# #-DAUDIO_CLASS=1
# -DMIN_FREQ=48000
# -DMAX_FREQ=48000
# -DUSE_EX3D
# -DMIXER=0
# -DAIZIP_DNR=0 #-ldnr_50ms
# -llib_ex3d_stereo_2k
# -DNUM_USB_CHAN_OUT=2
# -DNUM_USB_CHAN_IN=2
# -DEQ_EN=1
# -DSTREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_INPUT_1_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_INPUT_2_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_INPUT_3_RESOLUTION_BITS=16
# -DNUM_EX3D_CHAN_OUT=2
# -DINPUT_VOLUME_CONTROL=1
# -DOUTPUT_VOLUME_CONTROL=1
# -DXUA_DFU_EN=1
# -DSTEREO_2K
# -DHID_CONTROLS=1)
#
#set(APP_COMPILER_FLAGS_ex3d_stereo_8k ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
# -DI2S_CHANS_ADC=0
# -DMIN_FREQ=48000
# -DMAX_FREQ=48000
# -DUSE_EX3D
# -DMIXER=0
# -DAIZIP_DNR=0 #-ldnr_50ms
# -llib_ex3d_stereo_8k
# -DNUM_USB_CHAN_OUT=2
# -DNUM_USB_CHAN_IN=2
# -DSTREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_INPUT_1_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_INPUT_2_RESOLUTION_BITS=16
# -DSTREAM_FORMAT_INPUT_3_RESOLUTION_BITS=16
# -DNUM_EX3D_CHAN_OUT=2
# -DXUA_DFU_EN=1
# -DINPUT_VOLUME_CONTROL=1
# -DOUTPUT_VOLUME_CONTROL=1
# -DSTEREO_8K
# -DHID_CONTROLS=1)
## IR switching mode
set(APP_COMPILER_FLAGS_ex3d_71_all ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DI2S_CHANS_ADC=2
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DUSE_EX3D
-DMIXER=0
-ldnr_50ms
-llib_ex3d_all
-DEQ_EN=1
-DEX3D_SF_NUM=3
-DNUM_USB_CHAN_OUT=8
-DNUM_USB_CHAN_IN=2
-DNUM_EX3D_CHAN_OUT=2
-DMIN_VOLUME=0xE000
-DINPUT_VOLUME_CONTROL=1
-DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1
-DIR_SWITCHING_MODE
-DHID_CONTROLS=1)
set(APP_COMPILER_FLAGS_ex3d_71_game ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DI2S_CHANS_ADC=2
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DUSE_EX3D
-DMIXER=0
-DAIZIP_DNR=0 #-ldnr_50ms
-llib_ex3d_game
-DEQ_EN=1
-DNUM_USB_CHAN_OUT=8
-DNUM_USB_CHAN_IN=2
-DNUM_EX3D_CHAN_OUT=2
-DMIN_VOLUME=0xE000
-DINPUT_VOLUME_CONTROL=1
-DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1
-DSPATIAL_GAME
-DHID_CONTROLS=1)
set(APP_COMPILER_FLAGS_ex3d_71_music ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DI2S_CHANS_ADC=2
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DUSE_EX3D
-DMIXER=0
-DAIZIP_DNR=0 #-ldnr_50ms
-llib_ex3d_music
-DNUM_USB_CHAN_OUT=8
-DNUM_USB_CHAN_IN=2
-DNUM_EX3D_CHAN_OUT=2
-DMIN_VOLUME=0xE000
-DSPATIAL_MUSIC
-DHID_CONTROLS=1)
set(APP_COMPILER_FLAGS_ex3d_71_movie ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DI2S_CHANS_ADC=2
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DUSE_EX3D
-DMIXER=0
-DAIZIP_DNR=0 #-ldnr_50ms
-DEQ_EN=1
-llib_ex3d_movie
-DNUM_USB_CHAN_OUT=8
-DNUM_USB_CHAN_IN=2
-DNUM_EX3D_CHAN_OUT=2
-DMIN_VOLUME=0xE000
-DXUA_DFU_EN=1
-DSPATIAL_MOVIE
-DHID_CONTROLS=1)
set(APP_COMPILER_FLAGS_ex3d_71_drama ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DI2S_CHANS_ADC=2
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DUSE_EX3D
-DMIXER=0
-DAIZIP_DNR=0 #-ldnr_50ms
-llib_ex3d_drama
-DNUM_USB_CHAN_OUT=8
-DNUM_USB_CHAN_IN=2
-DNUM_EX3D_CHAN_OUT=2
-DMIN_VOLUME=0xE000
-DSPATIAL_DRAMA
-DHID_CONTROLS=1)
set(APP_INCLUDES src src/core src/extensions ../../lib_dnr/lib_dnr)
set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
XMOS_REGISTER_APP()

View File

@@ -0,0 +1 @@
xflash bin/factory/fact.xe --loader loader.o --upgrade 2 bin\ex3d_UAC1\app_usb_aud_phaten_gs_ex3d_UAC1.xe --upgrade 4 bin/ex3d_stereo_2k/app_usb_aud_phaten_gs_ex3d_stereo_2k.xe --upgrade 1 bin\ex3d_71_game\app_usb_aud_phaten_gs_ex3d_71_game.xe --upgrade 3 bin\ex3d_71_movie\app_usb_aud_phaten_gs_ex3d_71_movie.xe -o %1

View File

@@ -0,0 +1,2 @@
xflash --factory-version 15.3 --target-file src/core/synido.xn --upgrade 2 bin\ex3d_UAC1\app_usb_aud_phaten_gs_ex3d_UAC1.xe --upgrade 4 bin/ex3d_stereo_2k/app_usb_aud_phaten_gs_ex3d_stereo_2k.xe --upgrade 1 bin\ex3d_71_game\app_usb_aud_phaten_gs_ex3d_71_game.xe --upgrade 3 bin\ex3d_71_movie\app_usb_aud_phaten_gs_ex3d_71_movie.xe -o %1

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Declarations>
<Declaration>tileref tile[2]</Declaration>
<Declaration>tileref usb_tile</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-QF60A">
<Nodes>
<!-- Note that this clock setting is overridden by the app by writing directly to the PLL -->
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" SystemFrequency="600MHz" Oscillator="24MHz" referencefrequency="100MHz">
<Boot>
<Source Location="bootFlash"/>
</Boot>
<!-- <Extmem sizeMbit="1024" Frequency="175MHz">
<Padctrl clk="0x0" cke="0x0" cs_n="0x0" we_n="0x0" cas_n="0x0" ras_n="0x0" addr="0x0" ba="0x0" dq="0x0" dqs="0x0" dm="0x0"/>
<Lpddr lmr_opcode="0x0" emr_opcode="0x0"/>
</Extmem> -->
<Tile Number="0" Reference="tile[0]">
<!-- QSPI ports -->
<Port Location="XS1_PORT_1B" Name="PORT_SQI_CS_0"/>
<Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK_0"/>
<Port Location="XS1_PORT_4B" Name="PORT_SQI_SIO_0"/>
<!-- SPI ports -->
<Port Location="XS1_PORT_1A" Name="PORT_SSB"/>
<Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK_0"/>
<Port Location="XS1_PORT_1D" Name="PORT_SPI_MOSI"/>
<Port Location="XS1_PORT_1P" Name="PORT_SPI_MISO"/>
<!-- I2C ports -->
<Port Location="XS1_PORT_1N" Name="PORT_I2C_SCL"/>
<Port Location="XS1_PORT_1O" Name="PORT_I2C_SDA"/>
<!-- GPIO ports -->
<Port Location="XS1_PORT_8C" Name="PORT_GPO"/>
<Port Location="XS1_PORT_8D" Name="PORT_GPI"/>
<Port Location="XS1_PORT_1P" Name="PORT_ADC_RST"/>
<!-- Used for keeping XUA happy only -->
<Port Location="XS1_PORT_1G" Name="PORT_NOT_IN_PACKAGE_0"/>
<Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/>
<Port Location="XS1_PORT_1D" Name="PORT_MCLK_IN_USB"/>
</Tile>
<Tile Number="1" Reference="tile[1]">
<!-- MIC related ports -->
<Port Location="XS1_PORT_1G" Name="PORT_PDM_CLK"/>
<Port Location="XS1_PORT_1F" Name="PORT_PDM_DATA"/>
<!-- Audio ports -->
<Port Location="XS1_PORT_1D" Name="PORT_MCLK_IN"/>
<Port Location="XS1_PORT_1C" Name="PORT_I2S_BCLK"/>
<Port Location="XS1_PORT_1B" Name="PORT_I2S_LRCLK"/>
<Port Location="XS1_PORT_1K" Name="PORT_I2S_ADC0"/>
<Port Location="XS1_PORT_1A" Name="PORT_I2S_DAC0"/>
</Tile>
</Node>
</Nodes>
</Package>
</Packages>
<Nodes>
<Node Id="2" Type="device:" RoutingId="0x8000">
<Service Id="0" Proto="xscope_host_data(chanend c);">
<Chanend Identifier="c" end="3"/>
</Service>
</Node>
</Nodes>
<Links>
<Link Encoding="2wire" Delays="5clk" Flags="XSCOPE">
<LinkEndpoint NodeId="0" Link="XL0"/>
<LinkEndpoint NodeId="2" Chanend="1"/>
</Link>
</Links>
<ExternalDevices>
<Device NodeId="0" Tile="0" Class="SQIFlash" Name="bootFlash">
<Attribute Name="PORT_SQI_CS" Value="PORT_SQI_CS_0"/>
<Attribute Name="PORT_SQI_SCLK" Value="PORT_SQI_SCLK_0"/>
<Attribute Name="PORT_SQI_SIO" Value="PORT_SQI_SIO_0"/>
</Device>
</ExternalDevices>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Type>Board</Type>
<Name>xcore.ai MC Audio Board</Name>
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-TQ128">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Boot>
<Source Location="bootFlash"/>
</Boot>
<Tile Number="0" Reference="tile[0]">
<Port Location="XS1_PORT_1B" Name="PORT_SQI_CS"/>
<Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK"/>
<Port Location="XS1_PORT_4B" Name="PORT_SQI_SIO"/>
<!-- I2C -->
<Port Location="XS1_PORT_1P" Name="PORT_I2C_SCL"/> <!-- orig 1L, Synido 1P -->
<Port Location="XS1_PORT_1O" Name="PORT_I2C_SDA"/> <!-- orig 1M, Synido 1O -->
<!-- HRT3236 -->
<Port Location="XS1_PORT_1N" Name="PORT_HTR3236_SDB"/>
<!-- Mic Encoder -->
<Port Location="XS1_PORT_4F" Name="PORT_MIC_GAIN_ENCODER1"/> <!-- 4F1: FOOTSTEPS ENHANCEMENT; 4F2: MIC_GAIN_ENCODER_INPUT_1; 4F3: MIC MUTE -->
<Port Location="XS1_PORT_4E" Name="PORT_MIC_GAIN_ENCODER2"/> <!-- 4E2: MIC_GAIN_ENCODER_INPUT_2; 4E3: AI DENOISE ONOFF -->
<!-- HP Encoder -->
<Port Location="XS1_PORT_8D" Name="PORT_HP_GAIN_ENCODER"/> <!-- 8D4: HP_GAIN_ENCODER_INPUT_1; 8D5: HP_GAIN_ENCODER_INPUT_2; 8D6: HP MUTE -->
<!-- Buttons -->
<Port Location="XS1_PORT_1A" Name="PORT_BUTTON_MUSIC_MODE"/>
<Port Location="XS1_PORT_1L" Name="PORT_BUTTON_GAME_MODE"/>
<Port Location="XS1_PORT_1M" Name="PORT_BUTTON_AI71_ONOFF"/>
<!-- Clocking -->
<Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/>
<Port Location="XS1_PORT_1D" Name="PORT_MCLK_IN_USB"/>
</Tile>
<Tile Number="1" Reference="tile[1]">
<!-- Audio Ports: I2S -->
<Port Location="XS1_PORT_1D" Name="PORT_MCLK_IN"/>
<Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT_2"/>
<Port Location="XS1_PORT_1B" Name="PORT_I2S_LRCLK"/>
<Port Location="XS1_PORT_1C" Name="PORT_I2S_BCLK"/>
<Port Location="XS1_PORT_1K" Name="PORT_I2S_DAC0"/> <!-- orig 1P, Synido 1K -->
<Port Location="XS1_PORT_1A" Name="PORT_I2S_ADC0"/> <!-- orig 1I, Synido 1A -->
<Port Location="XS1_PORT_4D" Name="PORT_CTL_MUTE"/> <!-- Tile1 4D0 -->
</Tile>
</Node>
</Nodes>
</Package>
</Packages>
<!--
<Nodes>
<Node Id="2" Type="device:" RoutingId="0x8000">
<Service Id="0" Proto="xscope_host_data(chanend c);">
<Chanend Identifier="c" end="3"/>
</Service>
</Node>
</Nodes>
<Links>
<Link Encoding="2wire" Delays="5clk" Flags="XSCOPE">
<LinkEndpoint NodeId="0" Link="XL0"/>
<LinkEndpoint NodeId="2" Chanend="1"/>
</Link>
</Links>
-->
<ExternalDevices>
<Device NodeId="0" Tile="0" Class="SQIFlash" Name="bootFlash" PageSize="256" SectorSize="4096" NumPages="16384">
<Attribute Name="PORT_SQI_CS" Value="PORT_SQI_CS"/>
<Attribute Name="PORT_SQI_SCLK" Value="PORT_SQI_SCLK"/>
<Attribute Name="PORT_SQI_SIO" Value="PORT_SQI_SIO"/>
</Device>
</ExternalDevices>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,347 @@
/**
* @file xua_conf.h
* @brief Defines relating to device configuration and customisation.
* For xCORE.ai Audio MC Board
* @author Ross Owen, XMOS Limited
*/
#ifndef _XUA_CONF_H_
#define _XUA_CONF_H_
#include "../../../shared/version.h"
/*
* Device configuration option defines to override default defines found in lib_xua/api/xua_conf_default.h
*
* Build can be customised but changing and adding defines here
*
* Note, we check if they are already defined in Makefile
*/
/*** Defines relating to basic functionality ***/
/* Enable/Disable MIDI - Default is MIDI off */
#ifndef MIDI
#define MIDI (0)
#endif
/* Enable/Disable S/PDIF output - Default is S/PDIF off */
#ifndef XUA_SPDIF_TX_EN
#define XUA_SPDIF_TX_EN (0)
#endif
/* Enable/Disable S/PDIF input - Default is S/PDIF off */
#ifndef XUA_SPDIF_RX_EN
#define XUA_SPDIF_RX_EN (0)
#endif
/* Enable/Disable ADAT output - Default is ADAT off */
#ifndef XUA_ADAT_TX_EN
#define XUA_ADAT_TX_EN (0)
#endif
/* Enable/Disable ADAT input - Default is ADAT off */
#ifndef XUA_ADAT_RX_EN
#define XUA_ADAT_RX_EN (0)
#endif
/* Enable/Disable Mixing core(s) - Default is on */
#ifndef MIXER
#define MIXER (0)
#endif
#ifndef _XUA_BMAX_POWER
#define _XUA_BMAX_POWER (50)
#endif
/* Set the number of mixes to perform - Default is 0 i.e mixing disabled */
#ifndef MAX_MIX_COUNT
#define MAX_MIX_COUNT (0)
#endif
/* Audio Class version - Default is 2.0 */
#ifndef AUDIO_CLASS
#define AUDIO_CLASS (2)
#endif
/*** Defines relating to channel counts ***/
/* Number of I2S channels to DACs*/
#ifndef I2S_CHANS_DAC
#define I2S_CHANS_DAC (8)
#endif
/* Number of I2S channels from ADCs */
#ifndef I2S_CHANS_ADC
#define I2S_CHANS_ADC (8)
#endif
/* Number of USB streaming channels - by default calculate by counting audio interfaces */
#ifndef NUM_USB_CHAN_IN
#define NUM_USB_CHAN_IN (I2S_CHANS_ADC + 2*XUA_SPDIF_RX_EN + 8*XUA_ADAT_RX_EN) /* Device to Host */
#endif
#ifndef NUM_USB_CHAN_OUT
#define NUM_USB_CHAN_OUT (I2S_CHANS_DAC + 2*XUA_SPDIF_TX_EN + 8*XUA_ADAT_TX_EN) /* Host to Device */
#endif
/*** Defines relating to channel arrangement/indices ***/
/* Channel index of S/PDIF Tx channels: separate channels after analogue channels (if they fit) */
#ifndef SPDIF_TX_INDEX
#if (I2S_CHANS_DAC + 2*XUA_SPDIF_TX_EN) <= NUM_USB_CHAN_OUT
#define SPDIF_TX_INDEX (I2S_CHANS_DAC)
#else
#define SPDIF_TX_INDEX (0)
#endif
#endif
/* Channel index of S/PDIF Rx channels: separate channels after analogue channels */
#ifndef SPDIF_RX_INDEX
#define SPDIF_RX_INDEX (I2S_CHANS_ADC)
#endif
/* Channel index of ADAT Tx channels: separate channels after S/PDIF channels (if they fit) */
#ifndef ADAT_TX_INDEX
#define ADAT_TX_INDEX (I2S_CHANS_DAC + 2*XUA_SPDIF_TX_EN)
#endif
/* Channel index of ADAT Rx channels: separate channels after S/PDIF channels */
#ifndef ADAT_RX_INDEX
#define ADAT_RX_INDEX (I2S_CHANS_ADC + 2*XUA_SPDIF_RX_EN)
#endif
/*** Defines relating to audio frequencies ***/
/* Master clock defines (in Hz) */
#ifndef MCLK_441
#define MCLK_441 (256*44100) /* 44.1, 88.2 etc */
#endif
#ifndef MCLK_48
#define MCLK_48 (256*48000) /* 48, 96 etc */
#endif
/* Minumum sample frequency device runs at */
#ifndef MIN_FREQ
#define MIN_FREQ (48000) //(44100)
#endif
/* Maximum sample frequency device runs at */
#ifndef MAX_FREQ
#define MAX_FREQ (48000)
#endif
/*** Defines relating to feature placement regarding tiles ***/
#define XUD_TILE (0)
#define PLL_REF_TILE (0)
#define AUDIO_IO_TILE (1)
#define MIDI_TILE (1)
/*** Defines relating to USB descriptor strings and ID's ***/
#define VENDOR_ID (0x20B1) /* XMOS Vendor ID*/
#ifndef PID_AUDIO_2
#if defined (STEREO_2K)
#define PID_AUDIO_2 (0x0017)
#elif defined (SPATIAL_MOVIE)
#define PID_AUDIO_2 (0x0018)
#else
#define PID_AUDIO_2 (0x0016)
#endif
#endif
#ifndef PID_AUDIO_1
#define PID_AUDIO_1 (0x0017)
#endif
#define PRODUCT_STR_A2 "XMOS True AI7.1"
#define PRODUCT_STR_A1 "XMOS True AI7.1"
/* Board power source - Default is bus-powered */
#ifndef XUA_POWERMODE
#define XUA_POWERMODE XUA_POWERMODE_BUS
#endif
/* Enable/Disable example HID code - Default is off */
#ifndef HID_CONTROLS
#define HID_CONTROLS (0)
#endif
#define EXCLUDE_USB_AUDIO_MAIN (1)
/*
* New spispec for QF60 board
* */
#define FL_QUADDEVICE_XT25F16F \
{ \
0, /* XT25F16F - Just specify 0 as flash_id */ \
256, /* page size */ \
8192, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0x0B4015, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x0,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_WINBOND_W25Q16JW \
{ \
0, /* W25Q16JW - Just specify 0 as flash_id */ \
256, /* page size */ \
8192, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0xEF4015, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x3C,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_UC25HQ16B \
{ \
0, /* W25Q16JW - Just specify 0 as flash_id */ \
256, /* page size */ \
8192, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0xB36015, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x3C,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
/*
* New spispec for QF60 3V3 board
* */
#define FL_QUADDEVICE_WINBOND_W25Q32JVxxxM \
{ \
0, /* W25Q32JV - Just specify 0 as flash_id */ \
256, /* page size */ \
16384, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0xEF4016, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x3C,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
/*
* New spispec for xcore-AI explorer board
* */
#define FL_QUADDEVICE_MX25R3235 \
{ \
0, /* MX25R3235 - Just specify 0 as flash_id */ \
256, /* page size */ \
16384, /* num pages */ \
3, /* address size */ \
3, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0xC22816, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x3C,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_MX25L160E \
{ \
0, /* MX25R3235 - Just specify 0 as flash_id */ \
256, /* page size */ \
8192, /* num pages */ \
3, /* address size */ \
3, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0xC22017, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x3C,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
// DFU_FLASH_DEVICE is a comma-separated list of flash spec structures
// This define is used in lib_xua/lib_xua/src/dfu/flashlib_user.c
#define DFU_FLASH_DEVICE FL_QUADDEVICE_XT25F16F, FL_QUADDEVICE_WINBOND_W25Q16JW, FL_QUADDEVICE_UC25HQ16B, FL_QUADDEVICE_WINBOND_W25Q32JVxxxM, FL_QUADDEVICE_MX25R3235, FL_QUADDEVICE_MX25L160E
//:
#include "user_main.h"
#endif

View File

@@ -0,0 +1,12 @@
#include <print.h>
#include "xua.h"
on tile[XUD_TILE]: in port p_vbus = XS1_PORT_4C;
unsigned int XUD_HAL_GetVBusState(void)
{
unsigned vBus;
p_vbus :> vBus;
return !vBus;
}

View File

@@ -0,0 +1,7 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
void agc_init_interface(void);

View File

@@ -0,0 +1,64 @@
#ifndef AZP_H_
#define AZP_H_
#include "stdint.h"
typedef enum
{
errAZP_NoError = 0,
errAZP_NotReady,
errAZP_InvalidParam,
errAZP_InvalidLicense,
errAZP_BufferOverflow,
errAZP_BufferTooSmall,
}AZP_STATUS;
typedef struct
{
int8_t *buffer1;
int8_t *buffer2;
int32_t buffer1_size;
int32_t buffer2_size;
int32_t sample_rate;
}azp_dnr_pram_t;
/// @brief DNR initialization
/// @param param Configuration parameters
/// @return License status
/// @brief DNR initialization
/// @param param Configuration parameters
/// @return License status
AZP_STATUS AI_DNR_init(azp_dnr_pram_t *pram);
/// @brief DNR processing
/// @param audio Q31 input and output
/// @return License status
AZP_STATUS AI_DNR_Processing(int32_t *audio);
/// @brief Get version number
/// @return If not licensed, returns NULL
char * AI_DNR_Version();
/// @brief 初始化
/// @param buffer 公共区buffer
/// @param buf_size 公共区buffer size
/// @param buffer2 私有区buffer
/// @param buffer2_size 私有区buffer size
/// @return
//AZP_STATUS azp_dnr_init(int8_t *buffer, int32_t buf_size,int8_t *buffer2,int32_t buffer2_size);
/// @brief DNR 处理
/// @param audio 32bit Q31 单声道
/// @return
//AZP_STATUS Aizip_DNR_Processing(int32_t *audio);
/// @brief 获取工作buffer大小
/// @param buf_size
/// @param buf_size2
void getBufferSize(int32_t *buf_size, int32_t *buf_size2);/// @brief 设置是否开启EQ ,默认开启
/// @param status
//void setEQ_Status(int8_t status);
/// @brief 设置是否开启AGC ,默认开启
/// @param status
//void setAGC_Status(int8_t status);
/// @brief Set the noise reduction depth
/// @param dB Range (-200 to 0 dB)
/// -200: Maximum noise reduction
/// 0: No noise reduction
void setNoisy_mix_factor(float dB);
#endif // AZP_H_

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the
// XMOS Public License: Version 1
#ifndef AUDIO_PIPELINE_DSP_H_
#define AUDIO_PIPELINE_DSP_H_
#include <stdint.h>
//#include "agc_api.h"
//typedef struct agc_stage_ctx {
// agc_meta_data_t md;
// agc_state_t state;
//} agc_stage_ctx_t;
#endif /* AUDIO_PIPELINE_DSP_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
#include <platform.h>
//on tile[0]: out port p_leds = XS1_PORT_4F;
void UserAudioStreamStart(void)
{
/* Turn all LEDs on */
// p_leds <: 0xF;
}
void UserAudioStreamStop(void)
{
/* Turn all LEDs off */
// p_leds <: 0x0;
}

View File

@@ -0,0 +1,316 @@
#include "biquad_standalone.h"
#include <math.h>
#include <limits.h>
// 常量定义
#define Q_factor 30
#define BOOST_BSHIFT 2
// 如果没有定义M_PI则手动定义
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
static const float pi = (float)M_PI;
static const float log_2 = 0.69314718055f;
static const float db_2 = 6.02059991328f; // 20*log10(2)
// 辅助函数实现
static inline int32_t _float2fixed(float x, int32_t q) {
if (x < 0.0f) return (((float)(1u << q)) * x - 0.5f);
if (x > 0.0f) return (((float)((1u << q) - 1)) * x + 0.5f);
return 0;
}
static inline int32_t _float2fixed_assert(float x, int32_t q) {
float max_val = (float)(1 << (31 - q));
// 简单的断言检查,如果超出范围则返回边界值
if (x > max_val) x = max_val;
if (x < -max_val) x = -max_val;
return _float2fixed(x, q);
}
// 简单的三角函数实现,使用标准库 - 重命名以避免冲突
static inline float biquad_sin(float x) {
return sinf(x);
}
static inline float biquad_cos(float x) {
return cosf(x);
}
static inline float _check_fc(float fc, float fs) {
float fc_sat = fc;
// saturate if > fs/2
if (fc_sat >= fs / 2.0f) {
fc_sat = fs / 2.0f;
}
return fc_sat;
}
static inline float _check_gain(float gain, float max_gain) {
float gain_sat = gain;
// saturate if > max_gain
if (gain_sat >= max_gain) {
gain_sat = max_gain;
}
return gain_sat;
}
void eq_biquad_bypass(q2_30 coeffs[5]) {
coeffs[0] = 1 << Q_factor;
coeffs[1] = 0;
coeffs[2] = 0;
coeffs[3] = 0;
coeffs[4] = 0;
}
void eq_biquad_mute(q2_30 coeffs[5]) {
coeffs[0] = 0;
coeffs[1] = 0;
coeffs[2] = 0;
coeffs[3] = 0;
coeffs[4] = 0;
}
left_shift_t eq_biquad_gain(q2_30 coeffs[5], const float gain_db) {
float A = powf(10.0f, (gain_db * (1.0f / 20.0f)));
coeffs[0] = _float2fixed_assert(A, Q_factor - BOOST_BSHIFT);
coeffs[1] = 0;
coeffs[2] = 0;
coeffs[3] = 0;
coeffs[4] = 0;
return BOOST_BSHIFT;
}
void eq_biquad_lowpass(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q) {
float fc_sat = _check_fc(fc, fs);
// Compute common factors
float K = tanf(pi * fc_sat / fs);
float KK = K * K;
float KQ = K / filter_Q;
float norm = 1.0f / (1.0f + KQ + KK);
// Compute coeffs
float b0 = KK * norm;
float b1 = 2.0f * b0;
float b2 = b0;
float a1 = 2.0f * (KK - 1.0f) * norm;
float a2 = (1.0f - KQ + KK) * norm;
//DPRINTF("b0: %f \n b1: %f \n b2: %f \n a1: %f \n a2: %f\n", b0, b1, b2, a1, a2);
// Store as fixed-point values
coeffs[0] = _float2fixed_assert(b0, Q_factor);
coeffs[1] = _float2fixed_assert(b1, Q_factor);
coeffs[2] = _float2fixed_assert(b2, Q_factor);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
}
void eq_biquad_highpass(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q) {
float fc_sat = _check_fc(fc, fs);
// Compute common factors
float K = tanf(pi * fc_sat / fs);
float KK = K * K;
float KQ = K / filter_Q;
float norm = 1.0f / (1.0f + KQ + KK);
// Compute coeffs
float b0 = norm;
float b1 = -2.0f * b0;
float b2 = b0;
float a1 = 2.0f * (KK - 1.0f) * norm;
float a2 = (1.0f - KQ + KK) * norm;
// Store as fixed-point values
coeffs[0] = _float2fixed_assert(b0, Q_factor);
coeffs[1] = _float2fixed_assert(b1, Q_factor);
coeffs[2] = _float2fixed_assert(b2, Q_factor);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
}
void eq_biquad_allpass(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q) {
float fc_sat = _check_fc(fc, fs);
float K = tanf(pi * fc_sat / fs);
float norm = 1.0f / (1.0f + K / filter_Q + K * K);
float b0 = (1.0f - K / filter_Q + K * K) * norm;
float b1 = 2.0f * (K * K - 1.0f) * norm;
float b2 = 1.0f;
float a1 = b1;
float a2 = b0;
coeffs[0] = _float2fixed_assert(b0, Q_factor);
coeffs[1] = _float2fixed_assert(b1, Q_factor);
coeffs[2] = _float2fixed_assert(b2, Q_factor);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
}
// 动态计算bshift的函数
static left_shift_t calculate_bshift(float b0, float b1, float b2) {
float max_b = fabsf(b0);
if (fabsf(b1) > max_b) max_b = fabsf(b1);
if (fabsf(b2) > max_b) max_b = fabsf(b2);
if (max_b == 0.0f) return 0;
int bshift = 0;
if (max_b >= 1.0f) {
float temp = max_b;
while (temp >= 2.0f) { temp /= 2.0f; bshift++; }
} else {
float temp = max_b;
while (temp < 1.0f) { temp *= 2.0f; bshift--; }
bshift--;
}
return (bshift >= 0) ? bshift : 0;
}
left_shift_t eq_biquad_peaking(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q, const float gain_db) {
float gain_db_sat = _check_gain(gain_db, 20.0f * db_2);
float fc_sat = _check_fc(fc, fs);
float V = powf(10.0f, fabsf(gain_db_sat) / 20.0f);
float K = tanf(pi * fc_sat / fs);
float norm, b0, b1, b2, a1, a2;
if (gain_db_sat >= 0) {
norm = 1.0f / (1.0f + 1.0f/filter_Q * K + K * K);
b0 = (1.0f + V/filter_Q * K + K * K) * norm;
b1 = 2.0f * (K * K - 1.0f) * norm;
b2 = (1.0f - V/filter_Q * K + K * K) * norm;
a1 = b1;
a2 = (1.0f - 1.0f/filter_Q * K + K * K) * norm;
} else {
norm = 1.0f / (1.0f + V/filter_Q * K + K * K);
b0 = (1.0f + 1.0f/filter_Q * K + K * K) * norm;
b1 = 2.0f * (K * K - 1.0f) * norm;
b2 = (1.0f - 1.0f/filter_Q * K + K * K) * norm;
a1 = b1;
a2 = (1.0f - V/filter_Q * K + K * K) * norm;
}
left_shift_t bshift = calculate_bshift(b0, b1, b2);
coeffs[0] = _float2fixed_assert(b0, Q_factor - bshift);
coeffs[1] = _float2fixed_assert(b1, Q_factor - bshift);
coeffs[2] = _float2fixed_assert(b2, Q_factor - bshift);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
return bshift;
}
left_shift_t eq_biquad_lowshelf(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q, const float gain_db) {
float gain_db_sat = _check_gain(gain_db, 20.0f * db_2);
float fc_sat = _check_fc(fc, fs);
// 使用与Python端BiquadFilterCalculator.calculate("lowshelf")完全一致的算法
float V = powf(10.0f, fabsf(gain_db_sat) / 20.0f); // 与Python端一致
float K = tanf(pi * fc_sat / fs); // 与Python端一致K = tan(π * Fc / Fs)
float norm = 0.0f;
// 根据增益正负选择不同的计算方式与Python端完全一致
if (gain_db_sat >= 0) {
norm = 1.0f / (1.0f + sqrtf(2.0f) * K + K * K);
float b0 = (1.0f + sqrtf(2.0f * V) * K + V * K * K) * norm;
float b1 = 2.0f * (V * K * K - 1.0f) * norm;
float b2 = (1.0f - sqrtf(2.0f * V) * K + V * K * K) * norm;
float a1 = 2.0f * (K * K - 1.0f) * norm;
float a2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
// DPRINTF("b0: %f \n b1: %f \n b2: %f \n a1: %f \n a2: %f\n", b0, b1, b2, a1, a2);
// 动态计算bshift
left_shift_t bshift = calculate_bshift(b0, b1, b2);
// Store as fixed-point values
coeffs[0] = _float2fixed_assert(b0, Q_factor - bshift);
coeffs[1] = _float2fixed_assert(b1, Q_factor - bshift);
coeffs[2] = _float2fixed_assert(b2, Q_factor - bshift);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
return bshift;
} else {
norm = 1.0f / (1.0f + sqrtf(2.0f * V) * K + V * K * K);
float b0 = (1.0f + sqrtf(2.0f) * K + K * K) * norm;
float b1 = 2.0f * (K * K - 1.0f) * norm;
float b2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
float a1 = 2.0f * (V * K * K - 1.0f) * norm;
float a2 = (1.0f - sqrtf(2.0f * V) * K + V * K * K) * norm;
// DPRINTF("b0: %f \n b1: %f \n b2: %f \n a1: %f \n a2: %f\n", b0, b1, b2, a1, a2);
// 动态计算bshift
left_shift_t bshift = calculate_bshift(b0, b1, b2);
// Store as fixed-point values
coeffs[0] = _float2fixed_assert(b0, Q_factor - bshift);
coeffs[1] = _float2fixed_assert(b1, Q_factor - bshift);
coeffs[2] = _float2fixed_assert(b2, Q_factor - bshift);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
return bshift;
}
}
left_shift_t eq_biquad_highshelf(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q, const float gain_db) {
float gain_db_sat = _check_gain(gain_db, 20.0f * db_2);
float fc_sat = _check_fc(fc, fs);
// 使用与Python端BiquadFilterCalculator.calculate("highshelf")完全一致的算法
float V = powf(10.0f, fabsf(gain_db_sat) / 20.0f); // 与Python端一致
float K = tanf(pi * fc_sat / fs); // 与Python端一致K = tan(π * Fc / Fs)
float norm = 0.0f;
// 根据增益正负选择不同的计算方式与Python端完全一致
if (gain_db_sat >= 0) {
norm = 1.0f / (1.0f + sqrtf(2.0f) * K + K * K);
float b0 = (V + sqrtf(2.0f * V) * K + K * K) * norm;
float b1 = 2.0f * (K * K - V) * norm;
float b2 = (V - sqrtf(2.0f * V) * K + K * K) * norm;
float a1 = 2.0f * (K * K - 1.0f) * norm;
float a2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
// DPRINTF("b0: %f \n b1: %f \n b2: %f \n a1: %f \n a2: %f\n", b0, b1, b2, a1, a2);
// 动态计算bshift
left_shift_t bshift = calculate_bshift(b0, b1, b2);
// Store as fixed-point values
coeffs[0] = _float2fixed_assert(b0, Q_factor - bshift);
coeffs[1] = _float2fixed_assert(b1, Q_factor - bshift);
coeffs[2] = _float2fixed_assert(b2, Q_factor - bshift);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
return bshift;
} else {
norm = 1.0f / (V + sqrtf(2.0f * V) * K + K * K);
float b0 = (1.0f + sqrtf(2.0f) * K + K * K) * norm;
float b1 = 2.0f * (K * K - 1.0f) * norm;
float b2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
float a1 = 2.0f * (K * K - V) * norm;
float a2 = (V - sqrtf(2.0f * V) * K + K * K) * norm;
// DPRINTF("b0: %f \n b1: %f \n b2: %f \n a1: %f \n a2: %f\n", b0, b1, b2, a1, a2);
// 动态计算bshift
left_shift_t bshift = calculate_bshift(b0, b1, b2);
// Store as fixed-point values
coeffs[0] = _float2fixed_assert(b0, Q_factor - bshift);
coeffs[1] = _float2fixed_assert(b1, Q_factor - bshift);
coeffs[2] = _float2fixed_assert(b2, Q_factor - bshift);
coeffs[3] = _float2fixed_assert(-a1, Q_factor);
coeffs[4] = _float2fixed_assert(-a2, Q_factor);
return bshift;
}
}
/* Removed unused filters: bandpass, bandstop, notch, const_q, linkwitz */

View File

@@ -0,0 +1,26 @@
#ifndef BIQUAD_STANDALONE_H
#define BIQUAD_STANDALONE_H
#include <stdint.h>
#include "xmath/types.h" // 包含 lib_xcore_math 的类型定义
// 注意q2_30, left_shift_t, right_shift_t 已在 lib_xcore_math 中定义,不需要重复定义
// 函数声明
void eq_biquad_bypass(q2_30 coeffs[5]);
void eq_biquad_mute(q2_30 coeffs[5]);
left_shift_t eq_biquad_gain(q2_30 coeffs[5], const float gain_db);
void eq_biquad_lowpass(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q);
void eq_biquad_highpass(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q);
void eq_biquad_allpass(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q);
left_shift_t eq_biquad_peaking(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q, const float gain_db);
left_shift_t eq_biquad_lowshelf(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q, const float gain_db);
left_shift_t eq_biquad_highshelf(q2_30 coeffs[5], const float fc, const float fs, const float filter_Q, const float gain_db);
// 辅助函数声明 - 重命名以避免与系统库冲突
static inline int32_t _float2fixed(float x, int32_t q);
static inline int32_t _float2fixed_assert(float x, int32_t q);
static inline float biquad_sin(float x); // 重命名为 biquad_sin
static inline float biquad_cos(float x); // 重命名为 biquad_cos
#endif // BIQUAD_STANDALONE_H

View File

@@ -0,0 +1,48 @@
// Copyright 2024 XMOS LIMITED.
#define DEBUG_PRINT_ENABLE 0
#include "debug_print.h"
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <print.h>
#include <stdio.h>
#include <string.h>
#include <platform.h>
#include <xs1.h>
#include <xcore/chanend.h>
#include <xcore/channel.h>
#include "xc_ptr.h"
#include "xua_conf.h"
#include "share_buffer.h"
void dnr_exchange_buffer(int32_t *data);
void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]) {
chan_out_buf_word (c_data, sampsFromUsbToAudio, 2);
chan_out_buf_word (c_data, sampsFromAudioToUsb, 2);
chan_in_buf_word (c_data , sampsFromUsbToAudio, 2);
chan_in_buf_word (c_data , sampsFromAudioToUsb, 2);
}
void dsp_main (chanend_t c_data) {
int play_input[NUM_USB_CHAN_OUT];
int play_output[I2S_CHANS_DAC];
int mic_input[NUM_USB_CHAN_IN];
int mic_output[I2S_CHANS_ADC];
int count = 0;
unsigned ch[1] = {2};
while (1) {
chan_in_buf_word (c_data , play_input, 2) ;
chan_in_buf_word (c_data , mic_input, 2) ;
chan_out_buf_word (c_data , play_output, I2S_CHANS_DAC);
chan_out_buf_word (c_data , mic_output, I2S_CHANS_ADC);
write_to_ring_buffer(0, play_input[0]);
write_to_ring_buffer(1, play_input[1]);
play_output[0] = read_from_ring_buffer(2);
play_output[1] = read_from_ring_buffer(3);
dnr_exchange_buffer(mic_input);
mic_output[0] = mic_input[0];
mic_output[1] = mic_input[1];
// dnr_exchange_buffer((int32_t *)mic_input, (int32_t *)mic_output);
}
}

View File

@@ -0,0 +1,22 @@
#ifndef _C_DSP_H_
#define _C_DSP_H_
#include <stdint.h>
// #define AUDIO_T_16
#if defined(AUDIO_T_16)
typedef int16_t AUDIO_T;
#else // defined(AUDIO_T_32)
typedef int32_t AUDIO_T;
#endif
#define FRAME_SIZE 8 //128 samples / 48kHz = 2.6ms
void hid_update(unsigned char hid_data);
// mic level
#define MIN_MIC_LEVEL 0
#define MAX_MIC_LEVEL 9
#define DEFAULT_MIC_LEVEL 5
#endif

View File

@@ -0,0 +1,77 @@
// Copyright 2020-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef AIC3204_H_
#define AIC3204_H_
// TLV320AIC3204 Device I2C Address
#define AIC3204_I2C_DEVICE_ADDR 0x18
#define CODEC_I2C_DEVICE_ADDR AIC3204_I2C_DEVICE_ADDR
// TLV320AIC3204 Register Addresses
// Page 0
#define AIC3204_PAGE_CTRL 0x00 // Register 0 - Page Control
#define AIC3204_SW_RST 0x01 // Register 1 - Software Reset
#define AIC3204_NDAC 0x0B // Register 11 - NDAC Divider Value
#define AIC3204_MDAC 0x0C // Register 12 - MDAC Divider Value
#define AIC3204_DOSR_MSB 0x0d // Register 14 - DOSR Divider Value (MS Byte)
#define AIC3204_DOSR_LSB 0x0e // Register 14 - DOSR Divider Value (LS Byte)
#define AIC3204_NADC 0x12 // Register 18 - NADC Divider Value
#define AIC3204_MADC 0x13 // Register 19 - MADC Divider Value
#define AIC3204_AOSR 0x14 // Register 20 - AOSR Divider Value
#define AIC3204_CLK_MUL 0x19 // Register 25
#define AIC3204_CLK_DIV 0x1A // Register 26
#define AIC3204_CODEC_IF 0x1B // Register 27 - CODEC Interface Control
#define AIC3204_D_OFFSET 0x1C // Register 28 -
#define AIC3204_LOOPBACK 0x1D // Register 29 -
#define AIC3204_BCLK_DIV 0x1E // Register 30 - --------
#define AIC3204_CLK_MUL 0x1F // Register 31 -
#define AIC3204_BCLK_SEL 0x20 // Register 32 - 0:Primary; 1:Second
#define AIC3204_DAC_SIG_PROC 0x3C // Register 60 - DAC Sig Processing Block Control
#define AIC3204_ADC_SIG_PROC 0x3D // Register 61 - ADC Sig Processing Block Control
#define AIC3204_DAC_CH_SET1 0x3F // Register 63 - DAC Channel Setup 1
#define AIC3204_DAC_CH_SET2 0x40 // Register 64 - DAC Channel Setup 2
#define AIC3204_DACL_VOL_D 0x41 // Register 65 - DAC Left Digital Vol Control
#define AIC3204_DACR_VOL_D 0x42 // Register 66 - DAC Right Digital Vol Control
#define AIC3204_HEADSET_DET 0x43 // Register 67 - Headset Detection configuration
#define AIC3204_DRC_CON1 0x44 // Register 68 - DRC control reg1
#define AIC3204_DRC_CON2 0x45 // Register 69 - DRC control reg2
#define AIC3204_DRC_CON3 0x46 // Register 70 - DRC control reg3
#define AIC3204_ADC_CH_SET 0x51 // Register 81 - ADC Channel Setup
#define AIC3204_ADC_FGA_MUTE 0x52 // Register 82 - ADC Fine Gain Adjust/Mute
#define AIC3204_ADC_CH1_SET 0x53 // Register 83 - ADC L_CH vol
#define AIC3204_ADC_CH2_SET 0x54 // Register 84 - ADC R_CH vol
#define AIC3204_ADC_PHA_SET 0x55 // Register 84 - ADC Phase Adjust Reg
//0x56~0x5c: L-CH agc control regs
//0x5e~0x65: R-CH agc control regs
///0x66~0x67: DC measurement regs
//0x68~0x6d: DC Measurement output regs
// Page 1
#define AIC3204_PAGE_SEL1 0x00 // Register 0 - Page Select Reg
#define AIC3204_PWR_CFG 0x01 // Register 1 - Power Config
#define AIC3204_LDO_CTRL 0x02 // Register 2 - LDO Control
#define AIC3204_PLAY_CFG1 0x03 // Register 3 - Playback Config 1
#define AIC3204_PLAY_CFG2 0x04 // Register 4 - Playback Config 2
#define AIC3204_OP_PWR_CTRL 0x09 // Register 9 - Output Driver Power Control
#define AIC3204_CM_CTRL 0x0A // Register 10 - Common Mode Control
#define AIC3204_HPL_ROUTE 0x0C // Register 12 - HPL Routing Select
#define AIC3204_HPR_ROUTE 0x0D // Register 13 - HPR Routing Select
#define AIC3204_HPL_GAIN 0x10 // Register 16 - HPL Driver Gain
#define AIC3204_HPR_GAIN 0x11 // Register 17 - HPR Driver Gain
#define AIC3204_HP_START 0x14 // Register 20 - Headphone Driver Startup
#define AIC3204_LPGA_P_ROUTE 0x34 // Register 52 - Left PGA Positive Input Route
#define AIC3204_LPGA_N_ROUTE 0x36 // Register 54 - Left PGA Negative Input Route
#define AIC3204_RPGA_P_ROUTE 0x37 // Register 55 - Right PGA Positive Input Route
#define AIC3204_RPGA_N_ROUTE 0x39 // Register 57 - Right PGA Negative Input Route
#define AIC3204_LPGA_VOL 0x3B // Register 59 - Left PGA Volume
#define AIC3204_RPGA_VOL 0x3C // Register 60 - Right PGA Volume
#define AIC3204_ADC_PTM 0x3D // Register 61 - ADC Power Tune Config
#define AIC3204_ADC_VOL 0x3E // Register 62 - ADC Analog Gain Control Flag
#define AIC3204_AN_IN_CHRG 0x47 // Register 71 - Analog Input Quick Charging Config
#define AIC3204_REF_STARTUP 0x7B // Register 123 - Reference Power Up Config
int aic3204_init(void);
#endif /* AIC3204_H_ */

View File

@@ -0,0 +1,55 @@
#ifndef AZP_H_
#define AZP_H_
#include "stdint.h"
typedef enum
{
errAZP_NoError = 0, // No error
errAZP_NotReady, // Not ready
errAZP_InvalidParam, // Invalid parameter
errAZP_InvalidLicense, // Invalid license
errAZP_BufferOverflow, // Buffer overflow
errAZP_BufferTooSmall, // Buffer too small
} AZP_STATUS;
typedef struct
{
int8_t *buffer1; // Pointer to the first buffer
int8_t *buffer2; // Pointer to the second buffer
int32_t buffer1_size; // Size of the first buffer
int32_t buffer2_size; // Size of the second buffer
int32_t sample_rate; // Sample rate, only support 16000Hz
} azp_dnr_param_t;
/// @brief DNR initialization
/// @param param Configuration parameters
/// @return License status
/// @brief DNR initialization
/// @param param Configuration parameters
/// @return License status
AZP_STATUS AI_DNR_init(azp_dnr_param_t *param);
/// @brief DNR processing
/// @param audio Q31 input and output
/// @return License status
AZP_STATUS AI_DNR_Processing(int32_t *audio);
/// @brief Get version number
/// @return If not licensed, returns NULL
char *AI_DNR_Version();
/// @brief Get the size of the working buffers
/// @param buf_size Size of the first buffer
/// @param buf_size2 Size of the second buffer
void getBufferSize(int32_t *buf_size, int32_t *buf_size2);
/// @brief Set the noise reduction depth
/// @param dB Range (-200 to 0 dB)
/// -200: Maximum noise reduction
/// 0: No noise reduction
void setNoisy_mix_factor(float dB);
#endif // AZP_H_

View File

@@ -0,0 +1,52 @@
// Copyright 2016-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#if UART_DEBUG || DEBUG_MEMORY_LOG_ENABLED
#define DEBUG_PRINT_ENABLE 1
#endif
#include <xs1.h>
#include <xua_conf.h>
#include "ringbuf.h"
#include <xcore/chanend.h>
#include <xcore/channel.h>
#include "dnr_dsp_buf.h"
#include "xc_ptr.h"
#include "debug_print.h"
unsigned g_dsp_eof = 0;
void dnr_exchange_buffer(int32_t *data) {
static unsigned buff_index = 0;
write_to_sample_in_buf(data[1], buff_index, 0);
read_from_sample_out_buf(&data[1],buff_index, 0);
data[0] = data[1];
buff_index++;
#if DNR_11MS
if (buff_index == 128)
{
#else
if (buff_index == 512)
{
#endif
buf_slot_rotate();
buff_index = 0;
SET_SHARED_GLOBAL(g_dsp_eof, 1);
}
}
void Aizip_DNR_init(void);
void dnr_dsp_proc_task(void)
{
Aizip_DNR_init();
while(1) {
unsigned dsp_eof = 0;
GET_SHARED_GLOBAL(dsp_eof, g_dsp_eof);
if (dsp_eof) {
SET_SHARED_GLOBAL(g_dsp_eof, 0);
start_dsp_processing();
}
}
}

View File

@@ -0,0 +1,95 @@
// Copyright 2011-2023 XMOS LIMITED.
//
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#if UART_DEBUG || DEBUG_MEMORY_LOG_ENABLED
#define DEBUG_PRINT_ENABLE 1
#endif
#include <xs1.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <platform.h>
#include <string.h>
#include "dnr_dsp_buf.h"
#include "aizip_dnr.h"
#include "debug_print.h"
#include "flash.h"
//for AGC
//static agc_stage_ctx_t DWORD_ALIGNED agc_stage_state = {};
static unsigned __attribute__((aligned (4))) dsp_dnr_frame_buf[BUF_SLOT_NUM][DSP_CH_NUM][DNR_DSP_FRAME_SIZE];
unsigned sample_in_buf_slot=0;
unsigned processing_buf_slot=2;
unsigned sample_out_buf_slot=1;
void dsp_buf_init()
{
sample_in_buf_slot=0;
sample_out_buf_slot=1;
processing_buf_slot=2;
}
static void buf_slot_inc(unsigned* buf_slot_input)
{
if(*buf_slot_input == BUF_SLOT_NUM-1){
*buf_slot_input = 0;
}
else{
*buf_slot_input = *buf_slot_input+1;
}
}
void buf_slot_rotate()
{
buf_slot_inc(&sample_in_buf_slot);
buf_slot_inc(&sample_out_buf_slot);
buf_slot_inc(&processing_buf_slot);
}
void write_to_sample_in_buf(unsigned data, unsigned index, unsigned ch)
{
dsp_dnr_frame_buf[sample_in_buf_slot][ch][index]=data;
}
void read_from_sample_out_buf(unsigned* read_data, unsigned index, unsigned ch)
{
*read_data = dsp_dnr_frame_buf[sample_out_buf_slot][ch][index];
}
#if DNR_11MS
int8_t buffer[4208] __attribute__((aligned(4)));
int8_t buffer2[31136] __attribute__((aligned(4)));
#else
int8_t buffer[21416] __attribute__((aligned(4)));
int8_t buffer2[31712] __attribute__((aligned(4)));
#endif
azp_dnr_param_t pram = {
.buffer1 = buffer,
.buffer1_size = sizeof(buffer),
.buffer2 = buffer2,
.buffer2_size = sizeof(buffer2),
.sample_rate = 48000};
unsigned g_dnr_init_flag = 0;
void Aizip_DNR_init(void)
{
delay_microseconds(10000);
// setFlashPortPins(XS1_PORT_1B,XS1_PORT_1C,XS1_PORT_4B, XS1_CLKBLK_3);
int sta = AI_DNR_init(&pram);
g_dnr_init_flag = 1;
debug_printf("AI_DNR_init status %d\n", sta);
}
void start_dsp_processing(void)
{
float level = -200;
setNoisy_mix_factor(level);
AI_DNR_Processing((int32_t *)&dsp_dnr_frame_buf[processing_buf_slot][0][0]);
}

View File

@@ -0,0 +1,39 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __DNR_DSP_BUF_H__
#define __DNR_DSP_BUF_H__
#include <xs1.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <platform.h>
#include <xcore/chanend.h>
#include <xcore/channel.h>
#if DNR_11MS
#define DNR_DSP_FRAME_SIZE 128
#else
#define DNR_DSP_FRAME_SIZE 512
#endif
#define BUF_SLOT_NUM 3 //one for input, one for output, one for processing
#define DSP_CH_NUM 2
#if __XC__
extern "C" {
#endif
void dnr_set_chan(chanend_t dnr_tile0_c, chanend_t dnr_tile1_c);
void dsp_buf_init();
void buf_slot_rotate();
void write_to_sample_in_buf(unsigned data, unsigned index, unsigned ch);
void read_from_sample_out_buf(unsigned* read_data, unsigned index, unsigned ch);
void start_dsp_processing(void);
void Aizip_DNR_init(void);
#if __XC__
} //extern c
#endif
#endif //RINGBUFFER_H

View File

@@ -0,0 +1,5 @@
#ifndef __FLASH_H__
#define __FLASH_H__
#include "stdint.h"
void setFlashPortPins(uint32_t cs,uint32_t sclk,uint32_t sio,uint32_t clkblk);
#endif

View File

@@ -0,0 +1,45 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __RINGBUF_H__
#define __RINGBUF_H__
#include <xs1.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <platform.h>
#if __XC__
extern "C" {
#endif
#define FRAME_SIZE 120 //101623 - from 256 to 120
#define RF_CHAN_NUM 2 //stereo. Multichannel uses NUM_USB_CHAN_OUT
//
#define RB_SIZE FRAME_SIZE*RF_CHAN_NUM*16 //2 channel, 32-bit, 16 frame
#define RB_MASK (RB_SIZE - 1)
extern uint32_t r_buffer[RB_SIZE];
typedef struct {
uint32_t * buf_addr;
int next_empty;
int next_data;
int full;
int empty;
} ring_buffer_t;
void rb_init(void);
void rb_put_word(uint32_t data);
uint32_t rb_get_word(void);
int rb_is_full(void);
int rb_is_empty(void);
#if __XC__
} //extern c
#endif
#endif //RINGBUFFER_H

View File

@@ -0,0 +1,69 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __DNR_DSP_BUF_H__
#define __DNR_DSP_BUF_H__
#include <xs1.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <platform.h>
#include "c_dsp.h"
#define DNR_50MS 1
//#define DEBUG_DNR
#if (DNR_50MS == 1)
#define DNR_DSP_FRAME_SIZE 512
#else
#define DNR_DSP_FRAME_SIZE 128
#endif
#define BUF_SLOT_NUM 3 //one for input, one for output, one for processing
#define DSP_CH_NUM 2
#if __XC__
extern "C" {
#endif
void dsp_buf_init();
void buf_slot_rotate();
void write_to_sample_in_buf(unsigned data, unsigned index, unsigned ch);
void read_from_sample_out_buf(unsigned* read_data, unsigned index, unsigned ch);
void start_dsp_processing(unsigned samFreq);
#if __XC__
} //extern c
#endif
#define AGC_ENABLED 1
#define DNR_ENABLED 1
#define KEY_MIC_VOL_DN 0x08
#define KEY_MUTE 0x10
#define KEY_MIC_VOL_UP 0x20
#define KEY_PLAY_VOL_DN 0x40
#define KEY_PLAY_VOL_UP 0x80
#define KEY_BITS (KEY_MIC_VOL_DN | KEY_MUTE | KEY_MIC_VOL_UP | KEY_PLAY_VOL_DN | KEY_PLAY_VOL_UP)
#if defined (PHATEN_GSV2)
#define DEBOUNCE_TIMEOUT 10 // in units of 2.6ms; 128 samples/frame
#else
#error "Please define DEBOUNCE_TIMEOUT"
#endif
#define MUTED_MIC 0x5A
#define UNMUTED_MIC 0xA5
// 改动原因添加HID控制命令宏定义用于button_task中的按键处理从dnr_dsp_buf.c移到这里以便dsp.c可以访问
#define HID_CONTROL_PLAYPAUSE 0x01
#define HID_CONTROL_NEXT 0x02
#define HID_CONTROL_PREV 0x04
#define HID_CONTROL_VOLUP 0x00
#define HID_CONTROL_VOLDN 0x01
#define HID_CONTROL_MUTE 0x20
#endif //RINGBUFFER_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,200 @@
#if DEBUG_MEMORY_LOG_ENABLED
#define DEBUG_PRINT_ENABLE 1
#else
#define DEBUG_PRINT_ENABLE 0
#endif
#include <xs1.h>
#include <platform.h>
#include <print.h>
#include <string.h>
#include "xmath/filter.h"
#include "stdio.h"
#include "xc_ptr.h"
#include "eq.h"
#include "share_buffer.h"
#include "debug_print.h"
#include "eq_flash_storage.h"
#if 0
#define DPRINTF(...) printf(__VA_ARGS__)
#else
#define DPRINTF(...)
#endif
#define LEN_FADE_ (2024)
// EQ Flash存储初始化标志
int eq_flash_initialized = 0;
extern unsigned int is_mode_changed(void);
extern void change_eq_mode(unsigned sample_freq);
extern void clear_eq_status(unsigned sample_freq, unsigned ch_no);
extern unsigned int g_request_eq_mode;
extern unsigned int g_eq_enable; // 改动原因添加EQ使能开关外部声明用于初始化时检查EQ状态
extern unsigned int g_saved_eq_mode; // 改动原因:添加保存模式外部声明,用于初始化时设置保存的模式
extern void debug_print_eq_params(unsigned sample_freq);
extern uint32_t get_reference_time(void);
extern void update_eq_post_gain(void);
extern unsigned g_windows_detect_done;
#pragma unsafe arrays
void dsp_core0(void)
{
unsigned t0,t1;
static int audio_in_samples[2]; // idx 0: input_samples
static int audio_out_samples[2]; // idx 0: input_samples
static unsigned int usb_to_dsp_ratio = 1;
static int buffer_in_active = 0;
static int buffer_out_active = 0;
static unsigned int sample_freq = 48000;
unsigned b_fade_in = 0;
unsigned u_in_step;
unsigned b_fade_out = 0;
unsigned u_out_step;
// EQ Flash存储初始化标志
delay_milliseconds(100);
unsigned windows_detect_done;
GET_SHARED_GLOBAL(windows_detect_done, g_windows_detect_done);
while (windows_detect_done == 0) {
asm("nop");
GET_SHARED_GLOBAL(windows_detect_done, g_windows_detect_done);
}
#if EQ_EN
uint32_t time = get_reference_time(), time2;
// EQ Flash存储初始化 - 只在第一次运行时执行
if (eq_flash_initialized == 0) {
// 延迟更长时间确保QSPI Flash完全初始化
debug_printf("Initializing EQ Flash storage system\n");
// 初始化EQ Flash存储系统
if (eq_flash_init() == 0) {
debug_printf("EQ Flash storage initialized successfully\n");
init_mode_info();
eq_load_gain_and_names();
// 检查Flash中是否有EQ参数数据
debug_printf("Loading EQ parameters from Flash using simplified storage\n");
// 简化加载逻辑:每个模式只加载一次,会自动应用到所有采样率和通道
int loaded_modes = 0;
for (int mode = EQ_USER_MODE_MIN; mode <= EQ_USER_MODE_MAX; mode++) {
if (eq_load_all_params_and_calculate_coefficients(44100, mode) == 0) {
loaded_modes++;
debug_printf("Loaded mode %d parameters from Flash (applied to all sample rates and channels)\n", mode);
}
}
debug_printf("Loaded %d EQ modes from Flash successfully\n", loaded_modes);
// 从mode info里获取gain值并相应的赋值到eq数组的post gain
update_eq_post_gain();
// 从Flash加载并设置当前EQ模式和使能状态
// 改动原因修复EQ开关逻辑问题确保从Flash加载模式时正确设置g_saved_eq_mode和g_eq_enable
// eq_flash_load_current_mode()会同时加载模式并设置g_eq_enable
int saved_mode_result = eq_flash_load_current_mode();
// 改动原因确保g_eq_enable被正确加载无论模式加载是否成功
// eq_flash_load_current_mode()已经设置了g_eq_enable这里读取确认
unsigned int eq_enable = g_eq_enable;
if (saved_mode_result >= 0 && saved_mode_result <= 9) {
uint8_t saved_mode = (uint8_t)saved_mode_result;
debug_printf("Loaded current EQ mode %d and enable %d from Flash\n", saved_mode, eq_enable);
// 改动原因将eq_enable独立为全局开关所有模式共用一个开关
// 无论EQ是否启用都设置到Flash中保存的模式eq_enable只控制EQ处理开关
g_saved_eq_mode = saved_mode;
SET_SHARED_GLOBAL(g_request_eq_mode, saved_mode);
debug_printf("EQ initialization: Set mode to %d from Flash, EQ enable: %d (global switch, independent of mode)\n",
saved_mode, eq_enable);
} else {
// Flash加载失败时使用默认模式0EQ默认禁用
// 改动原因如果模式加载失败确保g_eq_enable也被设置为默认值0
g_saved_eq_mode = 0;
SET_SHARED_GLOBAL(g_request_eq_mode, 0);
g_eq_enable = 0;
eq_enable = 0; // 同步本地变量
debug_printf("Failed to load EQ mode from Flash, using default mode 0, EQ disabled (enable: %d)\n", eq_enable);
}
} else {
debug_printf("Failed to initialize EQ Flash storage system, continuing without Flash storage\n");
// 即使Flash初始化失败也标记为已初始化避免重复尝试
// 系统将继续运行只是不使用Flash存储功能
}
eq_single_param_database_init();
time2 = get_reference_time();
debug_printf("EQ Flash storage initialized time %lu\n", time2 - time);
eq_flash_initialized = 1;
}
while (1)
{
if(is_ring_buffer_empty(0) && is_ring_buffer_empty(1))
{
// delay_microseconds(1);
}
else
{
sample_freq = 48000;
audio_in_samples[0] = read_from_ring_buffer(0);
audio_in_samples[1] = read_from_ring_buffer(1);
if (is_mode_changed() && b_fade_out == 0 && b_fade_in == 0)
{
debug_printf("mode changed ====================== \n");
//debug_print_eq_params(sample_freq);
b_fade_out=1;
u_out_step=1;
}
audio_out_samples[0] = handler_eq_filter(sample_freq, 0, audio_in_samples[0]);
audio_out_samples[1] = handler_eq_filter(sample_freq, 1, audio_in_samples[1]);
if(b_fade_out)
{
audio_out_samples[0] /= LEN_FADE_;
audio_out_samples[0] *= (LEN_FADE_-u_out_step) ;
audio_out_samples[1] /= LEN_FADE_;
audio_out_samples[1] *= (LEN_FADE_-u_out_step) ;
++u_out_step;
}
if(b_fade_out == 1 && u_out_step == LEN_FADE_){
b_fade_out = 0;
change_eq_mode(sample_freq);
clear_eq_status(sample_freq, 0);
clear_eq_status(sample_freq, 1);
clear_ring_buffer(0);
clear_ring_buffer(1);
b_fade_in=1;
u_in_step=1;
}
if (b_fade_in)
{
audio_out_samples[0] /= LEN_FADE_;
audio_out_samples[0] *= (u_in_step) ;
audio_out_samples[1] /= LEN_FADE_;
audio_out_samples[1] *= (u_in_step);
if(++u_in_step >= LEN_FADE_){
b_fade_in = 0;
}
}
write_to_ring_buffer(2, audio_out_samples[0]);
write_to_ring_buffer(3, audio_out_samples[1]);
}
}
#endif
}

View File

@@ -0,0 +1,18 @@
#define DSP_BLOCK_LENGTH (8) //DO NOT CHANGE
#define DSP_TILE_0_CHANNEL_IN_COUNT (1)
#define DSP_TILE_1_CHANNEL_IN_COUNT (1)
#define DSP_TILE_0_CHANNEL_OUT_COUNT (DSP_TILE_0_CHANNEL_IN_COUNT*2)
#define DSP_TILE_1_CHANNEL_OUT_COUNT (DSP_TILE_1_CHANNEL_IN_COUNT*2)
#define DSP_TILE_0_WORKER_COUNT (DSP_TILE_0_CHANNEL_IN_COUNT)
#define DSP_TILE_1_WORKER_COUNT (DSP_TILE_1_CHANNEL_IN_COUNT)
#define DSP_MIXER_OUTPUT_CHANNEL_COUNT (2)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
#ifndef __HEADER_EQ_HANDLER__
#define __HEADER_EQ_HANDLER__
#pragma once
#include "xmath/xmath.h"
#include <stdint.h>
#include <stdbool.h>
#define NUM_EQ_MODES 10
#define NUM_EQ_CHANS 2
#define MAX_EQ_BANDS 8
#define EQ_DISABLED_MODE 10 // 禁用EQ的模式编号
#define EQ_PRESET_MODE_MIN 0 // 预设模式最小编号
#define EQ_PRESET_MODE_MAX 6 // 预设模式最大编号preset1-preset6
#define EQ_USER_MODE_MIN 7 // 用户模式最小编号
#define EQ_USER_MODE_MAX 9 // 用户模式最大编号user 1-4
#define EQ_MODE_MAX (NUM_EQ_MODES) // 模式最大编号user 1-4
// Filter type definition
typedef enum {
FILTER_TYPE_BYPASS = 0x00,
FILTER_TYPE_ALLPASS = 0x01,
FILTER_TYPE_PEAKING = 0x02,
FILTER_TYPE_LOWPASS = 0x03,
FILTER_TYPE_HIGHPASS = 0x04,
FILTER_TYPE_BANDPASS = 0x05,
FILTER_TYPE_BANDSTOP = 0x06,
FILTER_TYPE_NOTCH = 0x07,
FILTER_TYPE_CONST_Q = 0x08,
FILTER_TYPE_LOWSHELF = 0x09,
FILTER_TYPE_HIGHSHELF = 0x0A
} filter_type_t;
// Filter parameter structure
typedef struct {
float fc; // Center frequency (Hz)
float q; // Q value
float bw; // Bandwidth (Hz)
float gain; // Gain (dB)
uint8_t index; // Filter index
filter_type_t type; // Filter type
uint8_t padding[2]; // 添加填充字节确保结构体对齐到4字节边界
} filter_params_t;
// Filter biquad structure for runtime calculation
typedef struct {
int32_t coef[5][8]; // 5×8×4 = 160字节
} filter_biquad_s32_coef_t;
// 注意:以下结构体定义暂时注释,因为它们可能在其他文件中定义
// 如果需要使用,请确保包含相应的头文件
// 优化后的Flash存储结构 - 只存储非默认滤波器
typedef struct {
uint8_t active_bands_count; // 实际使用的滤波器数量
filter_params_t active_bands[MAX_EQ_BANDS]; // 只存储非bypass的滤波器
} eq_flash_data_t;
// 单个EQ参数变化记录结构优化版
typedef struct {
uint32_t sample_rate; // 采样率
uint8_t mode; // 模式
uint8_t channel; // 通道
uint8_t band_index; // 滤波器索引
filter_params_t params; // 单个滤波器参数(不包含系数)
uint32_t timestamp; // 时间戳
uint8_t is_dirty; // 脏标志
} __attribute__((packed)) eq_single_param_t;
// 单参数存储数据库
typedef struct {
eq_single_param_t params[MAX_EQ_BANDS * 8 * 2]; // 最多存储8个模式×2通道的所有参数
uint16_t param_count; // 当前参数数量
uint16_t max_params; // 最大参数数量
uint32_t last_save_time; // 最后保存时间
} eq_single_param_database_t;
// 设备信息结构体
typedef struct {
char mode_names[NUM_EQ_MODES][16]; // 模式名称数组每个16字节
int32_t mode_gains[NUM_EQ_MODES]; // 模式增益数组每个4字节
} __attribute__((packed)) eq_mode_info_t;
// Define EQ data structure for each sample rate
typedef struct {
unsigned sample_rate; // Sample rate
int32_t total_bshift;
int32_t post_gain_db;
filter_params_t bands[MAX_EQ_BANDS]; // Filter parameters
filter_biquad_s32_t filter; // Filter data (运行时计算)
} __attribute__((packed)) eq_mode_data_t;
uint32_t init_eq_data(unsigned sample_freq);
void clear_eq_status(unsigned sample_freq, unsigned ch_no);
int32_t handler_eq_filter( unsigned sample_freq, uint32_t ch, int32_t new_sample);
void init_eq_hid_params(void);
// EQ参数处理函数 - 用于串口接收的EQ参数转换和存储
int process_eq_params_from_uart(uint8_t eq_mode, uint8_t eq_index, uint32_t sample_rate, float coefficients[5]);
// 模式信息处理函数
#ifdef __XC__
// 独立的增益和名称设置/获取函数
void set_mode_gain(uint8_t mode, int32_t gain);
void set_mode_name(uint8_t mode, const char* unsafe name);
void get_mode_gain(uint8_t mode, int32_t* unsafe gain);
void get_mode_name(uint8_t mode, char* unsafe name);
uint8_t process_uart_set_eq_mode(uint8_t mode);
uint8_t process_uart_get_eq_mode(uint8_t * unsafe response, uint8_t response_size);
uint8_t process_uart_set_mode_gain_and_name(uint8_t * unsafe data);
uint8_t process_uart_set_eq_params(uint8_t * unsafe data);
uint8_t process_uart_get_eq_params(uint8_t * unsafe data, uint8_t * unsafe response, uint8_t response_size);
uint8_t process_uart_reset_eq_params(uint8_t * unsafe data);
uint8_t process_uart_get_eq_mode_count(uint8_t * unsafe response, uint8_t response_size);
uint8_t process_uart_set_and_save_eq_mode(uint8_t * unsafe data);
#else
// 独立的增益和名称设置/获取函数
void set_mode_gain(uint8_t mode, int32_t gain);
void set_mode_name(uint8_t mode, const char* name);
void get_mode_gain(uint8_t mode, int32_t* gain);
void get_mode_name(uint8_t mode, char* name);
uint8_t process_uart_set_eq_mode(uint8_t mode);
uint8_t process_uart_get_eq_mode(uint8_t *response, uint8_t response_size);
uint8_t process_uart_set_mode_gain_and_name(uint8_t *data);
uint8_t process_uart_set_eq_params(uint8_t *data);
uint8_t process_uart_get_eq_params(uint8_t *data, uint8_t *response, uint8_t response_size);
uint8_t process_uart_reset_eq_params(uint8_t *data);
uint8_t process_uart_get_eq_mode_count(uint8_t *response, uint8_t response_size);
uint8_t process_uart_set_and_save_eq_mode(uint8_t *data);
#endif
void init_mode_info(void);
uint8_t reset_eq_params(uint8_t mode);
// 动态系数计算函数声明
int calculate_current_mode_coefficients(uint32_t sample_rate, uint8_t mode);
// 串口EQ命令处理函数声明
#endif //__HEADER_EQ_HANDLER__

View File

@@ -0,0 +1,143 @@
#define DEBUG_PRINT_ENABLE 0
#include "eq_coefficient_calculator.h"
#include "biquad_standalone.h"
#include <math.h>
#if 0 // DEBUG_PRINT_ENABLE
#define DPRINTF(...) printf(__VA_ARGS__)
#else
#define DPRINTF(...)
#endif
// 系数计算函数
int eq_calculate_coefficients_from_params(filter_params_t *params,
uint32_t sample_rate,
q2_30 coeffs[5],
int *bshift) {
if (!params || !coeffs || !bshift) {
return -1;
}
// 根据滤波器类型调用相应的biquad计算函数
switch (params->type) {
case FILTER_TYPE_BYPASS:
eq_biquad_bypass(coeffs);
*bshift = 0;
break;
case FILTER_TYPE_LOWPASS:
eq_biquad_lowpass(coeffs,
params->fc,
(float)sample_rate,
params->q);
*bshift = 0;
break;
case FILTER_TYPE_HIGHPASS:
eq_biquad_highpass(coeffs,
params->fc,
(float)sample_rate,
params->q);
*bshift = 0;
break;
case FILTER_TYPE_BANDPASS:
case FILTER_TYPE_BANDSTOP:
case FILTER_TYPE_NOTCH:
case FILTER_TYPE_CONST_Q:
// These filter types have been removed to save memory.
// Fall through to bypass behavior.
eq_biquad_bypass(coeffs);
*bshift = 0;
break;
case FILTER_TYPE_ALLPASS:
eq_biquad_allpass(coeffs,
params->fc,
(float)sample_rate,
params->q);
*bshift = 0;
break;
case FILTER_TYPE_PEAKING:
*bshift = eq_biquad_peaking(coeffs,
params->fc,
(float)sample_rate,
params->q,
params->gain);
break;
case FILTER_TYPE_LOWSHELF:
*bshift = eq_biquad_lowshelf(coeffs,
params->fc,
(float)sample_rate,
params->q,
params->gain);
break;
case FILTER_TYPE_HIGHSHELF:
*bshift = eq_biquad_highshelf(coeffs,
params->fc,
(float)sample_rate,
params->q,
params->gain);
break;
default:
// 默认使用bypass
eq_biquad_bypass(coeffs);
*bshift = 0;
break;
}
#if 1 //DEBUG_PRINT_ENABLE == 1
DPRINTF("--------------------------------\n");
for(int i = 0; i < 5; i++) {
if (coeffs[i] < 0) {
DPRINTF("coeffs[%d]: -0x%08x\n", i, (unsigned int)(-coeffs[i]));
} else {
DPRINTF("coeffs[%d]: 0x%08x\n", i, (unsigned int)coeffs[i]);
}
}
DPRINTF("--------------------------------\n");
#endif
return 0;
}
// 批量计算所有滤波器的系数
int eq_calculate_all_coefficients(eq_mode_data_t *eq_data,
uint32_t sample_rate) {
if (!eq_data) {
return -1;
}
int total_bshift = 0;
// 计算每个滤波器的系数
for (int i = 0; i < MAX_EQ_BANDS; i++) {
q2_30 coeffs[5];
int bshift;
if (eq_calculate_coefficients_from_params(&eq_data->bands[i],
sample_rate, coeffs, &bshift) == 0) {
// 存储计算出的系数
for (int j = 0; j < 5; j++) {
eq_data->filter.coef[j][i] = coeffs[j];
}
total_bshift += bshift;
}
}
// 更新总bshift
eq_data->total_bshift = total_bshift;
#if DEBUG_PRINT_ENABLE == 1
DPRINTF("total_bshift: %d\n", total_bshift);
#endif
return 0;
}

View File

@@ -0,0 +1,17 @@
#ifndef EQ_COEFFICIENT_CALCULATOR_H
#define EQ_COEFFICIENT_CALCULATOR_H
#include "eq.h"
#include "biquad_standalone.h"
// 系数计算函数
int eq_calculate_coefficients_from_params(filter_params_t *params,
uint32_t sample_rate,
q2_30 coeffs[5],
int *bshift);
// 批量计算所有滤波器的系数
int eq_calculate_all_coefficients(eq_mode_data_t *eq_data,
uint32_t sample_rate);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['eq_designer_new.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='eq_designer_new',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,423 @@
#ifndef __EQ_FLASH_STORAGE_H__
#define __EQ_FLASH_STORAGE_H__
#include <stdint.h>
#include <stdbool.h>
#include "eq.h"
// EQ Flash存储相关常量定义
#define EQ_FLASH_MAGIC 0x45515041 // "EQPA" - EQ参数文件魔数
#define EQ_FLASH_MAGIC_PARAMS 0x45515041 // "EQPA" - EQ参数文件魔数
#define EQ_FLASH_VERSION 0x00020000 // 版本2.0.0 - 优化存储格式
#define EQ_FLASH_MAX_SAMPLE_RATES 6 // 支持的采样率数量
#define EQ_FLASH_MAX_MODES 10 // 最大模式数量
#define EQ_FLASH_MAX_CHANNELS 2 // 最大通道数量
// 支持的采样率列表
#define EQ_SAMPLE_RATES {44100, 48000, 88200, 96000, 176400, 192000}
// EQ参数文件头结构 (简化版本,去除采样率字段)
typedef struct {
uint32_t magic; // 魔数: 0x45515041 ("EQPA")
uint32_t version; // 版本号
uint8_t mode; // 模式号
uint8_t channel; // 通道号
uint16_t reserved; // 保留字段
uint32_t data_size; // 数据大小
uint32_t crc32; // CRC32校验
} __attribute__((packed)) eq_file_header_t;
// 元数据结构已移除,简化存储系统
// EQ存储状态结构
typedef struct {
int is_initialized; // 是否已初始化 (0: 否, 1: 是)
int has_flash_data; // Flash中是否有数据 (0: 否, 1: 是)
uint32_t last_sync_time; // 最后同步时间
uint32_t sync_count; // 同步次数
uint32_t error_count; // 错误次数
} eq_storage_status_t;
// 增益存储结构(只存储用户模式)
typedef struct {
uint32_t magic; // 魔数: 0x4551474E ("EQGN" - EQ Gain)
uint32_t version; // 版本号
uint32_t data_size; // 数据大小
uint32_t crc32; // CRC32校验
} __attribute__((packed)) eq_gain_header_t;
// 模式增益数据只存储用户模式6-8
typedef struct {
int32_t mode_gains[3]; // 用户模式增益数组mode 6, 7, 8每个4字节
} __attribute__((packed)) eq_gain_data_t;
// 单个模式名称存储结构
typedef struct {
uint32_t magic; // 魔数: 0x45514E4D ("EQNM" - EQ Name)
uint32_t version; // 版本号
uint8_t mode; // 模式号
uint8_t reserved[3]; // 保留字段
uint32_t data_size; // 数据大小16字节
uint32_t crc32; // CRC32校验
} __attribute__((packed)) eq_name_header_t;
// 单个模式名称数据
typedef struct {
char mode_name[16]; // 模式名称16字节
} __attribute__((packed)) eq_name_data_t;
// 兼容旧格式的结构(保留用于向后兼容)
typedef struct {
uint32_t magic; // 魔数: 0x45514E47 ("EQNG" - EQ Name Gain)
uint32_t version; // 版本号
uint32_t data_size; // 数据大小
uint32_t crc32; // CRC32校验
} __attribute__((packed)) eq_gain_name_header_t;
// 模式增益和名称数据
typedef struct {
int32_t mode_gains[NUM_EQ_MODES]; // 模式增益数组每个4字节
char mode_names[NUM_EQ_MODES][16]; // 模式名称数组每个16字节
} __attribute__((packed)) eq_gain_name_data_t;
// 函数声明
/**
* @brief 初始化EQ Flash存储系统
* @return 0: 成功, -1: 失败
*/
int eq_flash_init(void);
/**
* @brief 反初始化EQ Flash存储系统
*/
void eq_flash_deinit(void);
// 注意save all 和 load all 函数已移除,使用动态单参数存储系统
/**
* @brief 从Flash加载指定模式的EQ参数
* @param mode 模式号
* @return 0: 成功, -1: 失败
*/
int eq_flash_load_mode(uint8_t mode);
/**
* @brief 保存指定模式的EQ参数到Flash
* @param mode 模式号
* @return 0: 成功, -1: 失败
*/
int eq_flash_save_mode(uint8_t mode);
/**
* @brief 同步指定模式参数到Flash(延迟写入)
* @param mode 模式号
* @return 0: 成功, -1: 失败
*/
int eq_flash_sync_mode(uint8_t mode);
/**
* @brief 同步所有待更新的参数到Flash
* @return 0: 成功, -1: 失败
*/
int eq_flash_sync_all(void);
/**
* @brief 检查Flash中是否存在EQ参数数据
* @return 1: 存在, 0: 不存在
*/
int eq_flash_has_data(void);
/**
* @brief 获取EQ存储状态
* @param status 状态结构指针
* @return 0: 成功, -1: 失败
*/
int eq_flash_get_status(eq_storage_status_t *status);
/**
* @brief 清除Flash中的所有EQ参数数据
* @return 0: 成功, -1: 失败
*/
int eq_flash_clear_all(void);
/**
* @brief 验证EQ参数文件完整性
* @param mode 模式号
* @return 1: 完整, 0: 损坏
*/
int eq_flash_verify_mode(uint8_t mode);
/**
* @brief 获取文件路径
* @param mode 模式号
* @param channel 通道号
* @param path 输出路径缓冲区
* @param max_len 缓冲区最大长度
* @return 0: 成功, -1: 失败
*/
int eq_flash_get_file_path(uint8_t mode, uint8_t channel,
char *path, size_t max_len);
/**
* @brief 计算CRC32校验值
* @param data 数据指针
* @param len 数据长度
* @return CRC32值
*/
uint32_t eq_flash_calculate_crc32(const uint8_t *data, size_t len);
/**
* @brief 检查是否需要同步参数到Flash
* @return 1: 需要同步, 0: 不需要
*/
int eq_flash_needs_sync(void);
/**
* @brief 标记参数已修改,需要同步
* @param mode 模式号
*/
void eq_flash_mark_dirty(uint8_t mode);
/**
* @brief 检查滤波器是否为默认值bypass
* @param band 滤波器参数
* @return 1: 是默认值, 0: 不是默认值
*/
int is_filter_bypass(const filter_params_t *band);
/**
* @brief 从EQ数据中提取非默认滤波器到Flash存储格式
* @param eq_data 源EQ数据
* @param flash_data 目标Flash存储数据
* @return 0: 成功, -1: 失败
*/
int extract_active_filters(const eq_mode_data_t *eq_data, eq_flash_data_t *flash_data);
/**
* @brief 从Flash存储格式恢复EQ数据
* @param flash_data 源Flash存储数据
* @param eq_data 目标EQ数据
* @return 0: 成功, -1: 失败
*/
int restore_eq_from_flash(const eq_flash_data_t *flash_data, eq_mode_data_t *eq_data);
/**
* @brief 实时计算滤波器系数
* @param eq_data EQ数据
* @param sample_rate 采样率
* @return 0: 成功, -1: 失败
*/
int calculate_filter_coefficients(eq_mode_data_t *eq_data, uint32_t sample_rate);
// ==================== 单参数动态存储系统 ====================
/**
* @brief 初始化单参数存储数据库
* @return 0: 成功, -1: 失败
*/
int eq_single_param_database_init(void);
/**
* @brief 处理0x8c/0x8d命令的单参数变化
* @param data 接收到的数据
* @param len 数据长度
* @return 0: 成功, -1: 失败
*/
int eq_process_single_param_change(uint32_t sample_rate, uint8_t mode, uint8_t channel, uint8_t band_index, filter_params_t *band);
/**
* @brief 比较单个参数是否不同
* @param old_params 旧参数
* @param new_params 新参数
* @return 1: 不同, 0: 相同
*/
int eq_single_params_different(const filter_params_t *old_params, const filter_params_t *new_params);
/**
* @brief 添加单个参数变化到数据库
* @param sample_rate 采样率
* @param mode 模式
* @param channel 通道
* @param band_index 滤波器索引
* @param new_params 新参数
* @return 0: 成功, -1: 失败
*/
int eq_add_single_param(uint32_t sample_rate, uint8_t mode, uint8_t channel,
uint8_t band_index, const filter_params_t *new_params);
/**
* @brief 保存单个参数到Flash
* @param sample_rate 采样率
* @param mode 模式
* @param channel 通道
* @param band_index 滤波器索引
* @return 0: 成功, -1: 失败
*/
int eq_save_single_param(uint32_t sample_rate, uint8_t mode, uint8_t channel, uint8_t band_index);
/**
* @brief 从Flash加载单个参数
* @param sample_rate 采样率
* @param mode 模式
* @param channel 通道
* @param band_index 滤波器索引
* @return 0: 成功, -1: 失败
*/
int eq_load_single_param(uint32_t sample_rate, uint8_t mode, uint8_t channel, uint8_t band_index);
/**
* @brief 保存所有脏参数到Flash只保存EQ参数不包括增益和名称
* @return 0: 成功, -1: 失败
*/
int eq_save_dirty_params(void);
/**
* @brief 保存脏的增益到Flash
* @return 0: 成功, -1: 失败
*/
int eq_save_dirty_gain(void);
/**
* @brief 保存脏的模式名称到Flash
* @return 0: 成功, -1: 失败
*/
int eq_save_dirty_names(void);
/**
* @brief 保存脏的增益和模式名称到Flash兼容旧接口
* @return 0: 成功, -1: 失败
*/
int eq_save_dirty_gain_and_names(void);
/**
* @brief 保存用户模式的增益到Flash只保存用户模式6-8
* @return 0: 成功, -1: 失败
*/
int eq_save_gain(void);
/**
* @brief 保存单个用户模式的名称到Flash只有与初始值不同且非空才保存
* @param mode 模式号必须是用户模式6-8
* @return 0: 成功, -1: 失败, 1: 跳过(与初始值相同或为空)
*/
int eq_save_name(uint8_t mode);
/**
* @brief 从Flash加载用户模式的增益
* @return 0: 成功, -1: 失败
*/
int eq_load_gain(void);
/**
* @brief 从Flash加载单个用户模式的名称
* @param mode 模式号必须是用户模式6-8
* @return 0: 成功, -1: 失败(文件不存在或错误)
*/
int eq_load_name(uint8_t mode);
/**
* @brief 保存增益和模式名称到Flash兼容旧接口内部调用新函数
* @return 0: 成功, -1: 失败
*/
int eq_save_gain_and_names(void);
/**
* @brief 从Flash加载增益和模式名称兼容旧接口内部调用新函数
* @return 0: 成功, -1: 失败
*/
int eq_load_gain_and_names(void);
/**
* @brief 标记增益为脏(需要保存)
*/
void eq_mark_gain_dirty(void);
/**
* @brief 标记模式名称为脏(需要保存)
*/
void eq_mark_name_dirty(void);
/**
* @brief 标记增益和模式名称为脏(需要保存)(兼容旧接口)
*/
void eq_mark_gain_name_dirty(void);
/**
* @brief 删除Flash中的EQ参数文件
* @param mode 模式号 (0-9, 0xFF表示所有模式)
* @return 0: 成功, -1: 失败
*/
int delete_flash_eq_params(uint8_t mode);
/**
* @brief 删除Flash中的增益和模式名称文件
* @param mode 模式号 (0-9, 0xFF表示所有模式)
* @return 0: 成功, -1: 失败
*/
int delete_flash_gain_and_names(uint8_t mode);
/**
* @brief 恢复默认EQ参数
* @param mode 模式号 (0-9, 0xFF表示所有模式)
* @return 0: 成功, -1: 失败
*/
int restore_default_eq_params(uint8_t mode);
/**
* @brief 系统开机时加载所有参数并计算系数
* @param sample_rate 采样率
* @param mode 模式
* @return 0: 成功, -1: 失败
*/
int eq_load_all_params_and_calculate_coefficients(uint32_t sample_rate, uint8_t mode);
/**
* @brief 获取单参数存储统计
* @param stats 输出统计信息
* @return 0: 成功, -1: 失败
*/
int eq_get_single_param_stats(eq_single_param_database_t *stats);
/**
* @brief 清空单参数存储数据库
* @return 0: 成功, -1: 失败
*/
int eq_clear_single_param_database(void);
/**
* @brief 保存EQ使能状态到Flash独立文件存储与模式存储完全分离
* @param enable EQ使能状态 (0=禁用, 1=启用)
* @return 0: 成功, -1: 失败
*
* 改动原因将eq_enable存储独立为单独文件eq_enable与模式存储完全分离互不影响
*/
int eq_flash_save_eq_enable(uint8_t enable);
/**
* @brief 从Flash加载EQ使能状态独立文件加载与模式加载完全分离
* @return 使能状态值: 成功(0或1), -1: 失败
*
* 改动原因从独立文件eq_enable加载eq_enable与模式加载完全分离互不影响
*/
int eq_flash_load_eq_enable(void);
/**
* @brief 保存当前EQ模式到Flash独立文件存储与使能状态存储完全分离
* @param mode 模式值 (0-9)
* @return 0: 成功, -1: 失败
*
* 改动原因将模式存储独立为单独文件cur_mode与eq_enable存储完全分离互不影响
*/
int eq_flash_save_current_mode(uint8_t mode);
/**
* @brief 从Flash加载当前EQ模式独立文件加载与使能状态加载完全分离
* @return 模式值: 成功(0-9), -1: 失败
*
* 改动原因从独立文件cur_mode加载模式与eq_enable加载完全分离互不影响
* 注意:此函数同时加载模式和使能状态(从两个独立文件),用于初始化
*/
int eq_flash_load_current_mode(void);
#endif // __EQ_FLASH_STORAGE_H__

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
#include "dsp/td_block_fir.h"
int32_t __attribute__((aligned (8))) coefs_ex3d_0[1024] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 536870912
};
td_block_fir_filter_t td_block_fir_filter_ex3d_0 = {
.coefs = coefs_ex3d_0,
.block_count = 128,
.accu_shr = 0,
.accu_shl = -1,
};
td_block_fir_filter_t td_block_fir_filter_ex3d_1 = {
.coefs = coefs_ex3d_0,
.block_count = 128,
.accu_shr = 0,
.accu_shl = -1,
};
td_block_fir_filter_t td_block_fir_filter_ex3d_2 = {
.coefs = coefs_ex3d_0,
.block_count = 128,
.accu_shr = 0,
.accu_shl = -1,
};
td_block_fir_filter_t td_block_fir_filter_ex3d_3 = {
.coefs = coefs_ex3d_0,
.block_count = 128,
.accu_shr = 0,
.accu_shl = -1,
};
//This is the count of int32_t words to allocate for one data channel.
//i.e. int32_t channel_data[ex3d_0_DATA_BUFFER_ELEMENTS] = { 0 };
#define ex3d_0_DATA_BUFFER_ELEMENTS (1040)
#define ex3d_0_TD_BLOCK_LENGTH (8)
#define ex3d_0_BLOCK_COUNT (128)
#define ex3d_0_FRAME_ADVANCE (8)
#define ex3d_0_FRAME_OVERLAP (0)

View File

@@ -0,0 +1,909 @@
# EX3D HID通信协议详细文档
## 1. 总体框架
### 1.1 协议概述
该协议使用HID (Human Interface Device) 协议进行主机与设备之间的通信。协议支持EX3D3D音频扩展参数设置、读取等功能。
### 1.2 命令格式说明
EX3D命令使用特殊的命令格式
- **基础命令码**: 0x80-0x94 (定义在PlbkCmdCode枚举中)
- **命令修饰符**:
- `CMD_SET(cmd)`: 清除第9位(0x0100),用于设置命令
- `CMD_GET(cmd)`: 设置第9位(0x0100),用于读取命令
- `CMD_MASK`: 提取基础命令码的掩码(~0x0F00)
- **命令结构**:
- 设置命令: `基础命令码 & ~0x0100` (例如: CMD_ONOFF = 0x82, SET命令 = 0x82)
- 读取命令: `基础命令码 | 0x0100` (例如: CMD_ONOFF = 0x82, GET命令 = 0x182)
### 1.3 数据包格式
- **数据包大小**: 最大64字节 (1字节Report ID + 63字节数据)
- **数据对齐**: 使用32位(unsigned)对齐数据从RcvData[4]开始即pRcvBuf[0]开始
- **字节序**: 小端序 (Little Endian)
## 2. 详细命令说明
### 2.1 命令列表
| 基础命令码 | 命令名称 | SET命令码 | GET命令码 | 功能 | 方向 |
|-----------|----------|-----------|-----------|------|------|
| 0x80 | CMD_CH_NUM | - | 0x180 | 获取通道数量 | 主机→设备 |
| 0x81 | CMD_OPEN | 0x81 | - | 打开EX3D | 主机→设备 |
| 0x82 | CMD_ONOFF | 0x82 | 0x182 | 设置/获取EX3D开关 | 主机↔设备 |
| 0x83 | CMD_ANGLE | 0x83 | 0x183 | 设置/获取角度 | 主机↔设备 |
| 0x84 | CMD_SOUND_FIELD | 0x84 | 0x184 | 设置/获取声场模式 | 主机↔设备 |
| 0x85 | CMD_MUTE | 0x85 | 0x185 | 设置/获取静音 | 主机↔设备 |
| 0x86 | CMD_ON_GAIN | 0x86 | 0x186 | 设置/获取开启增益 | 主机↔设备 |
| 0x87 | CMD_LMT_THRESHOLD | 0x87 | 0x187 | 设置/获取限制器阈值 | 主机↔设备 |
| 0x88 | CMD_UPMIX | 0x88 | 0x188 | 设置/获取上混 | 主机↔设备 |
| 0x89 | CMD_LFE | 0x89 | 0x189 | 设置/获取LFE增益 | 主机↔设备 |
| 0x8A | CMD_OFF_GAIN | 0x8A | 0x18A | 设置/获取关闭增益 | 主机↔设备 |
| 0x8B | CMD_SOUND_FIELD_NUM | - | 0x18B | 获取声场模式数量 | 主机→设备 |
| 0x8C | CMD_SOUND_FIELD_NAME | - | 0x18C | 获取声场模式名称 | 主机→设备 |
| 0x8D | CMD_LEVEL | - | 0x18D | 获取电平 | 主机→设备 |
| 0x8E | CMD_LMT_ATTACKK_TIME | 0x8E | 0x18E | 设置/获取限制器攻击时间 | 主机↔设备 |
| 0x8F | CMD_LMT_RELEASE_TIME | 0x8F | 0x18F | 设置/获取限制器释放时间 | 主机↔设备 |
| 0x90 | CMD_TEST_CANCEL | 0x90 | - | 取消测试 | 主机→设备 |
| 0x91 | CMD_TEST_STEP | 0x91 | - | 测试步骤 | 主机→设备 |
| 0x92 | CMD_TEST_ROTATE | 0x92 | - | 测试旋转 | 主机→设备 |
| 0x93 | CMD_EXPAND_GAIN | 0x93 | 0x193 | 设置/获取扩展增益 | 主机↔设备 |
| 0x94 | CMD_REDUCE_GAIN | 0x94 | 0x194 | 设置/获取减少增益 | 主机↔设备 |
### 2.2 数据包结构
#### 通用请求数据包格式
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 保留 | 保留字节(跳过)
4-7 | 4 | uint32 | 命令码 (包含SET/GET标志)
8-11 | 4 | uint32 | 参数1 (根据命令不同而不同)
12-15 | 4 | uint32 | 参数2 (根据命令不同而不同)
... | ... | ... | 其他参数
```
#### 通用响应数据包格式
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 保留 | 保留字节(跳过)
4-7 | 4 | uint32 | 命令码 (回显)
8-11 | 4 | uint32 | 返回值/参数1
12-15 | 4 | uint32 | 返回值/参数2
... | ... | ... | 其他返回值
```
### 2.3 详细命令说明
#### 2.3.1 CMD_CH_NUM (0x80) - 获取通道数量
**功能**: 获取USB音频输出通道数量
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x180 = CMD_GET(CMD_CH_NUM))
8-63 | 56 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x180回显)
8-11 | 4 | uint32 | 通道数量 (NUM_USB_CHAN_OUT)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.2 CMD_OPEN (0x81) - 打开EX3D
**功能**: 打开EX3D系统
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x81 = CMD_SET(CMD_OPEN))
8-63 | 56 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x81回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
#### 2.3.3 CMD_ONOFF (0x82) - 设置/获取EX3D开关
**功能**: 设置或获取EX3D开关状态
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x82):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x82 = CMD_SET(CMD_ONOFF))
8-11 | 4 | uint32 | 开关值 (0=关闭, 1=开启)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x82回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
**GET命令请求数据包格式** (0x182):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x182 = CMD_GET(CMD_ONOFF))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x182回显)
8-11 | 4 | uint32 | 当前开关状态 (0=关闭, 1=开启)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.4 CMD_ANGLE (0x83) - 设置/获取角度
**功能**: 设置或获取通道的角度(垂直角度和水平角度)
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x83):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x83 = CMD_SET(CMD_ANGLE))
8-11 | 4 | uint32 | 通道号 (如果 >= NUM_USB_CHAN_OUT表示设置所有通道)
12-15 | 4 | uint32 | 角度值1 (单通道) 或 角度值[0] (多通道)
16-19 | 4 | uint32 | 角度值2 (多通道,可选)
... | ... | ... | 其他通道角度值最多NUM_USB_CHAN_OUT个
```
**角度值格式**: `(VAngle << 16) | HAngle`
- VAngle: 垂直角度 (0-180度高16位)
- HAngle: 水平角度 (0-359度低16位)
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x83回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
**GET命令请求数据包格式** (0x183):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x183 = CMD_GET(CMD_ANGLE))
8-11 | 4 | uint32 | 通道号 (如果 >= NUM_USB_CHAN_OUT表示获取所有通道)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x183回显)
8-11 | 4 | uint32 | 角度值 (单通道) 或 角度值[0] (多通道)
12-15 | 4 | uint32 | 角度值[1] (多通道,可选)
... | ... | ... | 其他通道角度值最多NUM_USB_CHAN_OUT个
```
**角度值格式**: `(VAngle << 16) | HAngle`
#### 2.3.5 CMD_SOUND_FIELD (0x84) - 设置/获取声场模式
**功能**: 设置或获取当前声场模式
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x84):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x84 = CMD_SET(CMD_SOUND_FIELD))
8-11 | 4 | uint32 | 声场模式索引 (0到EX3D_SF_NUM-1)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x84回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=索引无效, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x184):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x184 = CMD_GET(CMD_SOUND_FIELD))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x184回显)
8-11 | 4 | uint32 | 当前声场模式索引 (或0)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.6 CMD_MUTE (0x85) - 设置/获取静音
**功能**: 设置或获取通道的静音状态
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x85):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x85 = CMD_SET(CMD_MUTE))
8-11 | 4 | uint32 | 通道号 (如果 >= NUM_USB_CHAN_OUT表示设置所有通道)
12-15 | 4 | uint32 | 静音值1 (单通道) 或 静音值[0] (多通道0=不静音, 1=静音)
16-19 | 4 | uint32 | 静音值2 (多通道,可选)
... | ... | ... | 其他通道静音值最多NUM_USB_CHAN_OUT个
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x85回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
**GET命令请求数据包格式** (0x185):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x185 = CMD_GET(CMD_MUTE))
8-11 | 4 | uint32 | 通道号 (如果 >= NUM_USB_CHAN_OUT表示获取所有通道)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x185回显)
8-11 | 4 | uint32 | 静音值 (单通道) 或 静音值[0] (多通道)
12-15 | 4 | uint32 | 静音值[1] (多通道,可选)
... | ... | ... | 其他通道静音值最多NUM_USB_CHAN_OUT个
```
#### 2.3.7 CMD_ON_GAIN (0x86) - 设置/获取开启增益
**功能**: 设置或获取EX3D开启时的增益值
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x86):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x86 = CMD_SET(CMD_ON_GAIN))
8-11 | 4 | int32 | 增益值 (范围-100到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x86回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x186):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x186 = CMD_GET(CMD_ON_GAIN))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x186回显)
8-11 | 4 | int32 | 当前开启增益值 (范围-100到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.8 CMD_LMT_THRESHOLD (0x87) - 设置/获取限制器阈值
**功能**: 设置或获取限制器阈值
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x87):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x87 = CMD_SET(CMD_LMT_THRESHOLD))
8-11 | 4 | int32 | 阈值 (范围-35到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x87回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x187):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x187 = CMD_GET(CMD_LMT_THRESHOLD))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x187回显)
8-11 | 4 | int32 | 当前限制器阈值 (范围-35到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.9 CMD_UPMIX (0x88) - 设置/获取上混
**功能**: 设置或获取上混状态
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x88):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x88 = CMD_SET(CMD_UPMIX))
8-11 | 4 | uint32 | 上混值 (0=关闭, 1=开启)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x88回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
**GET命令请求数据包格式** (0x188):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x188 = CMD_GET(CMD_UPMIX))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x188回显)
8-11 | 4 | uint32 | 当前上混状态 (0=关闭, 1=开启)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.10 CMD_LFE (0x89) - 设置/获取LFE增益
**功能**: 设置或获取LFE低频效果增益
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x89):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x89 = CMD_SET(CMD_LFE))
8-11 | 4 | int32 | 增益值 (范围-100到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x89回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x189):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x189 = CMD_GET(CMD_LFE))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x189回显)
8-11 | 4 | int32 | 当前LFE增益值 (范围-100到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.11 CMD_OFF_GAIN (0x8A) - 设置/获取关闭增益
**功能**: 设置或获取EX3D关闭时的增益值
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x8A):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x8A = CMD_SET(CMD_OFF_GAIN))
8-11 | 4 | int32 | 增益值 (范围-100到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x8A回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x18A):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18A = CMD_GET(CMD_OFF_GAIN))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18A回显)
8-11 | 4 | int32 | 当前关闭增益值 (范围-100到0 dB小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.12 CMD_SOUND_FIELD_NUM (0x8B) - 获取声场模式数量
**功能**: 获取可用的声场模式数量
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18B = CMD_GET(CMD_SOUND_FIELD_NUM))
8-63 | 56 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18B回显)
8-11 | 4 | uint32 | 声场模式数量 (EX3D_SF_NUM)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.13 CMD_SOUND_FIELD_NAME (0x8C) - 获取声场模式名称
**功能**: 获取指定声场模式的名称
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18C = CMD_GET(CMD_SOUND_FIELD_NAME))
8-11 | 4 | uint32 | 声场模式索引
12-63 | 52 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18C回显)
8-11 | 4 | uint32 | 名称长度 (如果索引无效则为0xFFFFFFFF)
12-15 | 4 | char | 名称字符[0-3] (UTF-8编码如果索引有效)
16-19 | 4 | char | 名称字符[4-7] (UTF-8编码可选)
... | ... | ... | 其他名称字符最多16字节
```
**注意**: 如果索引无效位置8-11返回0xFFFFFFFF后续字节为0x00
#### 2.3.14 CMD_LEVEL (0x8D) - 获取电平
**功能**: 获取通道的电平值
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18D = CMD_GET(CMD_LEVEL))
8-11 | 4 | uint32 | 通道数量
12-63 | 52 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18D回显)
8-11 | 4 | float | 电平值[0] (通道0的电平值IEEE 754格式小端序)
12-15 | 4 | float | 电平值[1] (通道1的电平值可选)
... | ... | ... | 其他通道电平值最多NUM_USB_CHAN_OUT个每个4字节float
```
#### 2.3.15 CMD_LMT_ATTACKK_TIME (0x8E) - 设置/获取限制器攻击时间
**功能**: 设置或获取限制器攻击时间
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x8E):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x8E = CMD_SET(CMD_LMT_ATTACKK_TIME))
8-11 | 4 | uint32 | 攻击时间 (范围0到10小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x8E回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x18E):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18E = CMD_GET(CMD_LMT_ATTACKK_TIME))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18E回显)
8-11 | 4 | uint32 | 当前限制器攻击时间 (范围0到10小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.16 CMD_LMT_RELEASE_TIME (0x8F) - 设置/获取限制器释放时间
**功能**: 设置或获取限制器释放时间
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x8F):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x8F = CMD_SET(CMD_LMT_RELEASE_TIME))
8-11 | 4 | uint32 | 释放时间 (范围0到100小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x8F回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x18F):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18F = CMD_GET(CMD_LMT_RELEASE_TIME))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x18F回显)
8-11 | 4 | uint32 | 当前限制器释放时间 (范围0到100小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.17 CMD_EXPAND_GAIN (0x93) - 设置/获取扩展增益
**功能**: 设置或获取扩展增益值
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x93):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x93 = CMD_SET(CMD_EXPAND_GAIN))
8-11 | 4 | int32 | 增益值 (范围0到20小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x93回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x193):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x193 = CMD_GET(CMD_EXPAND_GAIN))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x193回显)
8-11 | 4 | int32 | 当前扩展增益值 (范围0到20小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.18 CMD_REDUCE_GAIN (0x94) - 设置/获取减少增益
**功能**: 设置或获取减少增益值
**方向**: 主机↔设备
**SET命令请求数据包格式** (0x94):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x94 = CMD_SET(CMD_REDUCE_GAIN))
8-11 | 4 | int32 | 增益值 (范围-20到0小端序)
12-63 | 52 | 0x00 | 保留字节
```
**SET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x94回显)
8-11 | 4 | uint32 | 状态码 (0xFFFFFFFF=参数超出范围, 其他=成功)
12-63 | 52 | 0x00 | 保留字节
```
**GET命令请求数据包格式** (0x194):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x194 = CMD_GET(CMD_REDUCE_GAIN))
8-63 | 56 | 0x00 | 保留字节
```
**GET命令响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x194回显)
8-11 | 4 | int32 | 当前减少增益值 (范围-20到0小端序)
12-63 | 52 | 0x00 | 保留字节
```
#### 2.3.19 CMD_TEST_CANCEL (0x90) - 取消测试
**功能**: 取消EX3D测试
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x90 = CMD_SET(CMD_TEST_CANCEL))
8-63 | 56 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x90回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
#### 2.3.20 CMD_TEST_STEP (0x91) - 测试步骤
**功能**: 执行EX3D测试步骤
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x91 = CMD_SET(CMD_TEST_STEP))
8-63 | 56 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x91回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
#### 2.3.21 CMD_TEST_ROTATE (0x92) - 测试旋转
**功能**: 执行EX3D测试旋转
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x92 = CMD_SET(CMD_TEST_ROTATE))
8-63 | 56 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1-3 | 3 | 0x00 | 保留字节
4-7 | 4 | uint32 | 命令码 (0x92回显)
8-63 | 56 | 0x00 | 保留字节(无返回值)
```
## 3. 注意事项
1. **数据对齐**: 所有数据使用32位(unsigned)对齐从RcvData[4]开始
2. **命令码格式**: SET命令清除第9位GET命令设置第9位
3. **错误处理**: 当参数超出范围时返回0xFFFFFFFF表示错误
4. **多通道处理**: ANGLE和MUTE命令支持单通道或多通道批量设置
5. **字节序**: 所有多字节数据使用小端序
6. **字符串编码**: 字符串使用UTF-8编码
## 4. 实现参考
参考文件: `sw_usb_audio/app_usb_aud_phaten_golden/src/extensions/dsp.c`
- 函数: `hid_receive_task_in_c()`
- 行号: 269-598

View File

@@ -0,0 +1,324 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
滤波器工具类
包含双二阶滤波器计算器和各种滤波器类型的系数计算函数
"""
import math
import numpy as np
from typing import Dict, List, Union
class BiquadFilterCalculator:
"""双二阶滤波器计算器"""
def __init__(self):
self.coefficients = {
'a0': 0.0,
'a1': 0.0,
'a2': 0.0,
'b1': 0.0,
'b2': 0.0
}
def calculate(self, filter_type: str, Fc: float, Fs: float, Q: float, peak_gain: float, bandwidth: float = None) -> Dict[str, float]:
"""
计算滤波器系数
:param filter_type: 滤波器类型
:param Fc: 截止频率
:param Fs: 采样率
:param Q: 品质因数
:param peak_gain: 峰值增益(dB)
:return: 滤波器系数字典
"""
V = math.pow(10, abs(peak_gain) / 20)
K = math.tan(math.pi * Fc / Fs)
norm = 0.0
filter_type = filter_type.lower()
if filter_type == "lowpass":
norm = 1 / (1 + K / Q + K * K)
self.coefficients['a0'] = K * K * norm
self.coefficients['a1'] = 2 * self.coefficients['a0']
self.coefficients['a2'] = self.coefficients['a0']
self.coefficients['b1'] = 2 * (K * K - 1) * norm
self.coefficients['b2'] = (1 - K / Q + K * K) * norm
elif filter_type == "highpass":
norm = 1 / (1 + K / Q + K * K)
self.coefficients['a0'] = 1 * norm
self.coefficients['a1'] = -2 * self.coefficients['a0']
self.coefficients['a2'] = self.coefficients['a0']
self.coefficients['b1'] = 2 * (K * K - 1) * norm
self.coefficients['b2'] = (1 - K / Q + K * K) * norm
elif filter_type == "bandpass":
# 使用lib_audio_dsp中biquad.c的算法
# 使用bandwidth参数如果没有提供则使用Q作为近似值
bw = bandwidth if bandwidth is not None else Q
w0 = 2.0 * math.pi * Fc / Fs
sin_w0 = math.sin(w0)
alpha = sin_w0 * math.sinh(math.log(2) / 2.0 * bw * w0 / sin_w0)
self.coefficients['a0'] = alpha
self.coefficients['a1'] = 0
self.coefficients['a2'] = -alpha
self.coefficients['b1'] = -2.0 * math.cos(w0)
self.coefficients['b2'] = 1.0 - alpha
# 归一化
a0 = 1.0 + alpha
inv_a0 = 1.0 / a0
self.coefficients['a0'] *= inv_a0
self.coefficients['a1'] *= inv_a0
self.coefficients['a2'] *= inv_a0
self.coefficients['b1'] *= inv_a0
self.coefficients['b2'] *= inv_a0
elif filter_type == "notch":
norm = 1 / (1 + K / Q + K * K)
self.coefficients['a0'] = (1 + K * K) * norm
self.coefficients['a1'] = 2 * (K * K - 1) * norm
self.coefficients['a2'] = self.coefficients['a0']
self.coefficients['b1'] = self.coefficients['a1']
self.coefficients['b2'] = (1 - K / Q + K * K) * norm
elif filter_type == "peak":
if peak_gain >= 0:
norm = 1 / (1 + 1/Q * K + K * K)
self.coefficients['a0'] = (1 + V/Q * K + K * K) * norm
self.coefficients['a1'] = 2 * (K * K - 1) * norm
self.coefficients['a2'] = (1 - V/Q * K + K * K) * norm
self.coefficients['b1'] = self.coefficients['a1']
self.coefficients['b2'] = (1 - 1/Q * K + K * K) * norm
else:
norm = 1 / (1 + V/Q * K + K * K)
self.coefficients['a0'] = (1 + 1/Q * K + K * K) * norm
self.coefficients['a1'] = 2 * (K * K - 1) * norm
self.coefficients['a2'] = (1 - 1/Q * K + K * K) * norm
self.coefficients['b1'] = self.coefficients['a1']
self.coefficients['b2'] = (1 - V/Q * K + K * K) * norm
elif filter_type == "lowshelf":
if peak_gain >= 0:
norm = 1 / (1 + math.sqrt(2) * K + K * K)
self.coefficients['a0'] = (1 + math.sqrt(2*V) * K + V * K * K) * norm
self.coefficients['a1'] = 2 * (V * K * K - 1) * norm
self.coefficients['a2'] = (1 - math.sqrt(2*V) * K + V * K * K) * norm
self.coefficients['b1'] = 2 * (K * K - 1) * norm
self.coefficients['b2'] = (1 - math.sqrt(2) * K + K * K) * norm
else:
norm = 1 / (1 + math.sqrt(2*V) * K + V * K * K)
self.coefficients['a0'] = (1 + math.sqrt(2) * K + K * K) * norm
self.coefficients['a1'] = 2 * (K * K - 1) * norm
self.coefficients['a2'] = (1 - math.sqrt(2) * K + K * K) * norm
self.coefficients['b1'] = 2 * (V * K * K - 1) * norm
self.coefficients['b2'] = (1 - math.sqrt(2*V) * K + V * K * K) * norm
elif filter_type == "highshelf":
if peak_gain >= 0:
norm = 1 / (1 + math.sqrt(2) * K + K * K)
self.coefficients['a0'] = (V + math.sqrt(2*V) * K + K * K) * norm
self.coefficients['a1'] = 2 * (K * K - V) * norm
self.coefficients['a2'] = (V - math.sqrt(2*V) * K + K * K) * norm
self.coefficients['b1'] = 2 * (K * K - 1) * norm
self.coefficients['b2'] = (1 - math.sqrt(2) * K + K * K) * norm
else:
norm = 1 / (V + math.sqrt(2*V) * K + K * K)
self.coefficients['a0'] = (1 + math.sqrt(2) * K + K * K) * norm
self.coefficients['a1'] = 2 * (K * K - 1) * norm
self.coefficients['a2'] = (1 - math.sqrt(2) * K + K * K) * norm
self.coefficients['b1'] = 2 * (K * K - V) * norm
self.coefficients['b2'] = (V - math.sqrt(2*V) * K + K * K) * norm
else:
raise ValueError("不支持的滤波器类型")
return self.coefficients
def _check_filter_freq(filter_freq: float, fs: int) -> float:
"""检查滤波器频率是否有效"""
if filter_freq >= fs / 2:
raise ValueError(f"滤波器频率 ({filter_freq} Hz) 必须小于采样率的一半 ({fs/2} Hz)")
return filter_freq
def make_biquad_bypass(fs: int) -> List[float]:
"""创建旁路滤波器系数"""
return [1.0, 0.0, 0.0, 0.0, 0.0]
def make_biquad_lowpass(fs: int, filter_freq: float, q_factor: float) -> List[float]:
"""创建低通滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
K = math.tan(math.pi * filter_freq / fs)
norm = 1 / (1 + K / q_factor + K * K)
b0 = K * K * norm
b1 = 2 * b0
b2 = b0
a1 = 2 * (K * K - 1) * norm
a2 = (1 - K / q_factor + K * K) * norm
return [b0, b1, b2, -a1, -a2]
def make_biquad_highpass(fs: int, filter_freq: float, q_factor: float) -> List[float]:
"""创建高通滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
K = math.tan(math.pi * filter_freq / fs)
norm = 1 / (1 + K / q_factor + K * K)
b0 = norm
b1 = -2 * b0
b2 = b0
a1 = 2 * (K * K - 1) * norm
a2 = (1 - K / q_factor + K * K) * norm
return [b0, b1, b2, -a1, -a2]
def make_biquad_bandpass(fs: int, filter_freq: float, bandwidth: float) -> List[float]:
"""创建带通滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
w0 = 2.0 * math.pi * filter_freq / fs
alpha = math.sin(w0) * math.sinh(math.log(2) / 2 * bandwidth * w0 / math.sin(w0))
b0 = alpha
b1 = 0.0
b2 = -alpha
a0 = 1.0 + alpha
a1 = -2.0 * math.cos(w0)
a2 = 1.0 - alpha
return [b0/a0, b1/a0, b2/a0, -a1/a0, -a2/a0]
def make_biquad_bandstop(fs: int, filter_freq: float, bandwidth: float) -> List[float]:
"""创建带阻滤波器系数 - 使用lib_audio_dsp中biquad.c的算法"""
filter_freq = _check_filter_freq(filter_freq, fs)
w0 = 2.0 * math.pi * filter_freq / fs
sin_w0 = math.sin(w0)
alpha = sin_w0 * math.sinh(math.log(2) / 2.0 * bandwidth * w0 / sin_w0)
b0 = 1.0
b1 = -2.0 * math.cos(w0)
b2 = 1.0
a0 = 1.0 + alpha
a1 = b1 # 与lib_audio_dsp一致
a2 = 1.0 - alpha
return [b0/a0, b1/a0, b2/a0, -a1/a0, -a2/a0]
def make_biquad_notch(fs: int, filter_freq: float, q_factor: float) -> List[float]:
"""创建陷波滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
K = math.tan(math.pi * filter_freq / fs)
norm = 1 / (1 + K / q_factor + K * K)
b0 = (1 + K * K) * norm
b1 = 2 * (K * K - 1) * norm
b2 = b0
a1 = b1
a2 = (1 - K / q_factor + K * K) * norm
return [b0, b1, b2, -a1, -a2]
def make_biquad_allpass(fs: int, filter_freq: float, q_factor: float) -> List[float]:
"""创建全通滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
K = math.tan(math.pi * filter_freq / fs)
norm = 1 / (1 + K / q_factor + K * K)
b0 = (1 - K / q_factor + K * K) * norm
b1 = 2 * (K * K - 1) * norm
b2 = 1.0
a1 = b1
a2 = b0
return [b0, b1, b2, -a1, -a2]
def make_biquad_peaking(fs: int, filter_freq: float, q_factor: float, boost_db: float) -> List[float]:
"""创建峰值滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
A = math.sqrt(10 ** (boost_db / 20))
w0 = 2.0 * math.pi * filter_freq / fs
alpha = math.sin(w0) / (2.0 * q_factor)
b0 = 1.0 + alpha * A
b1 = -2.0 * math.cos(w0)
b2 = 1.0 - alpha * A
a0 = 1.0 + alpha / A
a1 = -2.0 * math.cos(w0)
a2 = 1.0 - alpha / A
return [b0/a0, b1/a0, b2/a0, -a1/a0, -a2/a0]
def make_biquad_constant_q(fs: int, filter_freq: float, q_factor: float, boost_db: float) -> List[float]:
"""创建恒定Q值滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
V = 10 ** (boost_db / 20)
w0 = 2.0 * math.pi * filter_freq / fs
K = math.tan(w0 / 2)
if boost_db > 0:
b0 = 1 + V * K / q_factor + K**2
b1 = 2 * (K**2 - 1)
b2 = 1 - V * K / q_factor + K**2
a0 = 1 + K / q_factor + K**2
a1 = 2 * (K**2 - 1)
a2 = 1 - K / q_factor + K**2
else:
V = 1 / V
b0 = 1 + K / q_factor + K**2
b1 = 2 * (K**2 - 1)
b2 = 1 - K / q_factor + K**2
a0 = 1 + V * K / q_factor + K**2
a1 = 2 * (K**2 - 1)
a2 = 1 - V * K / q_factor + K**2
return [b0/a0, b1/a0, b2/a0, -a1/a0, -a2/a0]
def make_biquad_lowshelf(fs: int, filter_freq: float, q_factor: float, boost_db: float) -> List[float]:
"""创建低架滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
A = math.pow(10, boost_db / 40)
w0 = 2.0 * math.pi * filter_freq / fs
alpha = math.sin(w0) / 2 * math.sqrt((A + 1/A) * (1/q_factor - 1) + 2)
if boost_db >= 0:
b0 = A * ((A+1) + (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha)
b1 = -2*A * ((A-1) + (A+1)*math.cos(w0))
b2 = A * ((A+1) + (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha)
a0 = (A+1) - (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha
a1 = 2*((A-1) - (A+1)*math.cos(w0))
a2 = (A+1) - (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha
else:
b0 = (A+1) - (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha
b1 = 2*((A-1) - (A+1)*math.cos(w0))
b2 = (A+1) - (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha
a0 = A*((A+1) + (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha)
a1 = -2*A*((A-1) + (A+1)*math.cos(w0))
a2 = A*((A+1) + (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha)
return [b0/a0, b1/a0, b2/a0, -a1/a0, -a2/a0]
def make_biquad_highshelf(fs: int, filter_freq: float, q_factor: float, boost_db: float) -> List[float]:
"""创建高架滤波器系数"""
filter_freq = _check_filter_freq(filter_freq, fs)
A = math.pow(10, boost_db / 40) # 将dB转换为线性增益
w0 = 2.0 * math.pi * filter_freq / fs # 归一化角频率
alpha = math.sin(w0) / 2 * math.sqrt((A + 1/A) * (1/q_factor - 1) + 2)
if boost_db >= 0: # 增益提升
b0 = A*((A+1) + (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha)
b1 = -2*A*((A-1) + (A+1)*math.cos(w0))
b2 = A*((A+1) + (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha)
a0 = (A+1) - (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha
a1 = 2*((A-1) - (A+1)*math.cos(w0))
a2 = (A+1) - (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha
else: # 增益衰减
b0 = (A+1) - (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha
b1 = 2*((A-1) - (A+1)*math.cos(w0))
b2 = (A+1) - (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha
a0 = A*((A+1) + (A-1)*math.cos(w0) + 2*math.sqrt(A)*alpha)
a1 = -2*A*((A-1) + (A+1)*math.cos(w0))
a2 = A*((A+1) + (A-1)*math.cos(w0) - 2*math.sqrt(A)*alpha)
return coeffs

View File

@@ -0,0 +1,296 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XCORE VocalFusion Licence.
#ifndef __hid_report_descriptor_h__
#define __hid_report_descriptor_h__
#include "xua_hid_report.h"
#if 0
/* Existing static report descriptor kept for reference */
#ifdef HID_CONTROLS
unsigned char hidReportDescriptor[] =
{
0x05, 0x0c, /* Usage Page (Consumer Device) */
0x09, 0x01, /* Usage (Consumer Control) */
0xa1, 0x01, /* Collection (Application) */
#ifdef DFU_CONTROL_USB_HID
0x85, 0x01, // HID_BUTTON_REPORT_ID // TODO: report ID uses the global definition
#endif
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x09, 0xb0, /* Usage (Play) */
0x09, 0xb5, /* Usage (Scan Next Track) */
0x09, 0xb6, /* Usage (Scan Previous Track) */
0x09, 0xe9, /* Usage (Volume Up) */
0x09, 0xea, /* Usage (Volume Down) */
0x09, 0xe2, /* Usage (Mute) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x06, /* Report Count (6) */
0x81, 0x02, /* Input (Data, Var, Abs) */
0x95, 0x02, /* Report Count (2) */
0x81, 0x01, /* Input (Cnst, Ary, Abs) */
0xc0 /* End collection */
#ifdef DFU_CONTROL_USB_HID
,0x06, 0x82, 0xff,
0x09, 0x01,
0xa1, 0x01,
0x09, 0x03,
0x85, 0x41, // HID_DFU_REPORT_ID // TODO: report ID uses the global definition
0x15, 0x00,
0x26, 0xff, 0x00,
0x75, 0x08,
0x95, 0x3f,
0x81, 0x02,
0x09, 0x04,
0x15, 0x00,
0x26, 0xff, 0x00,
0x75, 0x08,
0x95, 0x3f,
0x91, 0x02,
0xc0
#if 0
Usage Page (Vendor-Defined 131) 06 82 FF
Usage (Vendor-Defined 1) 09 01
Collection (Application) A1 01
Usage (Vendor-Defined 3) 09 03
Report ID (65) 85 41
Logical Minimum (0) 15 00
Logical Maximum (255) 26 FF 00
Report Size (8) 75 08
Report Count (63) 95 3F
Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02
Usage (Vendor-Defined 4) 09 04
Logical Minimum (0) 15 00
Logical Maximum (255) 26 FF 00
Report Size (8) 75 08
Report Count (63) 95 3F
Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02
End Collection C0
#endif
#endif
};
#endif
#endif
/*
* Define non-configurable items in the HID Report descriptor.
*/
static const USB_HID_Short_Item_t hidCollectionApplication = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidCollectionApplication2 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_COLLECTION),
.data = { 0x02, 0x00 } };
static const USB_HID_Short_Item_t hidCollectionEnd = {
.header = HID_REPORT_SET_HEADER(0, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_END_COLLECTION),
.data = { 0x00, 0x00 } };
static const USB_HID_Short_Item_t hidInputConstArray = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidInputDataVar = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_INPUT),
.data = { 0x02, 0x00 } };
static const USB_HID_Short_Item_t hidInputFeatureVar = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_MAIN, HID_REPORT_ITEM_TAG_FEATURE),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidLogicalMaximum0 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM),
.data = { 0x00, 0x00 } };
static const USB_HID_Short_Item_t hidLogicalMaximum1 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MAXIMUM),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidLogicalMinimum0 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_LOGICAL_MINIMUM),
.data = { 0x00, 0x00 } };
static const USB_HID_Short_Item_t hidReportCount2 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT),
.data = { 0x00, 0x00 } };
static const USB_HID_Short_Item_t hidReportCount8 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_COUNT),
.data = { 0x08, 0x00 } };
static const USB_HID_Short_Item_t hidReportSize1 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_REPORT_SIZE),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidUsageConsumerControl = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.data = { 0x01, 0x00 } };
static const USB_HID_Short_Item_t hidUsageConsumerControl2 = {
.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.data = { 0x02, 0x00 } };
/*
* Define the HID Report Descriptor Item, Usage Page, Report ID and length for each HID Report
* For internal purposes, a report element with ID of 0 must be included if report IDs are not being used.
*/
static const USB_HID_Report_Element_t hidReportPageConsumer = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE),
.item.data = { USB_HID_USAGE_PAGE_ID_CONSUMER, 0x00 },
.location = HID_REPORT_SET_LOC(0x1, 2, 0, 0 )
};
static const USB_HID_Report_Element_t hidReportPageVendor = {
.item.header = HID_REPORT_SET_HEADER(2, HID_REPORT_ITEM_TYPE_GLOBAL, HID_REPORT_ITEM_TAG_USAGE_PAGE),
.item.data = {0x83, 0xff },
.location = HID_REPORT_SET_LOC(0x2, 2, 0, 0 )
};
static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }};
static const USB_HID_Short_Item_t hidUsagePageVendor = { .header = 0x06, .data = { 0x82, 0xff }};
static const USB_HID_Short_Item_t hidUsageConsumerVendor = { .header = 0x09, .data = { 0x03, 0x00 }};
static const USB_HID_Short_Item_t hidPassReportId = { .header = 0x85, .data = { 0x1, 0x00 }};
static const USB_HID_Short_Item_t hidButtonReportId = { .header = 0x85, .data = { 0x2, 0x00 }};
static const USB_HID_Short_Item_t hidLogicalMaximum2 = { .header = 0x26, .data = { 0xFF, 0x00 }};
static const USB_HID_Short_Item_t hidReportSize = { .header = 0x75, .data = { 0x08, 0x00 }};
#if DEBUG_MEMORY_LOG_ENABLED
static const USB_HID_Short_Item_t hidPassReportCount = { .header = 0x95, .data = { 0x3F, 0x00 }};
static const USB_HID_Short_Item_t hidPassReportCount2 = { .header = 0x95, .data = { 0x3F, 0x00 }};
static const USB_HID_Short_Item_t hidPassReportCount3 = { .header = 0x95, .data = { 0x3f, 0x00 }};
#else
static const USB_HID_Short_Item_t hidPassReportCount = { .header = 0x95, .data = { 0x3f, 0x00 }};
static const USB_HID_Short_Item_t hidPassReportCount2 = { .header = 0x95, .data = { 0x3f, 0x00 }};
static const USB_HID_Short_Item_t hidPassReportCount3 = { .header = 0x95, .data = { 0x3f, 0x00 }};
#endif
static const USB_HID_Short_Item_t hidButtonReportCount = { .header = 0x95, .data = { 0x04, 0x00 }};
static const USB_HID_Short_Item_t hidUsageVendor = { .header = 0x09, .data = { 0x04, 0x00 }};
static const USB_HID_Short_Item_t hidUsageVendor2 = { .header = 0x09, .data = { 0x05, 0x00 }};
static const USB_HID_Short_Item_t hidOutputDataVar = { .header = 0x91, .data = { 0x02, 0x00 }};
/*
* Define configurable items in the HID Report descriptor.
*/
static USB_HID_Report_Element_t hidUsageByte0Bit7 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xE2, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 5)
}; // Mute
static USB_HID_Report_Element_t hidUsageByte0Bit6 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xB4, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 5)
}; // rewind
static USB_HID_Report_Element_t hidUsageByte0Bit5 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xB3, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 5)
}; // forward
static USB_HID_Report_Element_t hidUsageByte0Bit4 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xB6, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 2)
}; // Scan Prev
static USB_HID_Report_Element_t hidUsageByte0Bit3 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xB5, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 1)
}; // Scan Next
static USB_HID_Report_Element_t hidUsageByte0Bit2 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xCD, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 0)
}; // Play
static USB_HID_Report_Element_t hidUsageByte0Bit1 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xEA, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 4)
}; // Vol-
static USB_HID_Report_Element_t hidUsageByte0Bit0 = {
.item.header = HID_REPORT_SET_HEADER(1, HID_REPORT_ITEM_TYPE_LOCAL, HID_REPORT_ITEM_TAG_USAGE),
.item.data = { 0xE9, 0x00 },
.location = HID_REPORT_SET_LOC(0, 0, 0, 3)
}; // Vol+
/*
* List the configurable elements in the HID Report descriptor.
*/
static USB_HID_Report_Element_t* const hidConfigurableElements[] = {
&hidUsageByte0Bit0,
&hidUsageByte0Bit1,
&hidUsageByte0Bit2,
&hidUsageByte0Bit3,
&hidUsageByte0Bit4,
&hidUsageByte0Bit5,
&hidUsageByte0Bit6,
&hidUsageByte0Bit7
};
/*
* List HID Reports, one per Report ID. This should be a usage page item with the relevant
* If not using report IDs - still have one with report ID 0
*/
static const USB_HID_Report_Element_t* const hidReports[] = {
&hidReportPageVendor,
&hidReportPageConsumer
};
/*
* List all items in the HID Report descriptor.
*/
static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = {
&(hidReportPageVendor.item),
&hidUsageConsumerControl,
&hidCollectionApplication,
&hidUsageConsumerVendor,
&hidPassReportId,
&hidLogicalMinimum0,
&hidLogicalMaximum2,
&hidReportSize,
&hidPassReportCount2,
&hidInputDataVar,
&hidUsageVendor,
&hidLogicalMinimum0,
&hidLogicalMaximum2,
&hidReportSize,
&hidPassReportCount,
&hidOutputDataVar,
&hidUsageVendor2,
&hidReportSize,
&hidPassReportCount3,
&hidInputFeatureVar,
&hidCollectionEnd,
&(hidReportPageConsumer.item),
&hidUsageConsumerControl,
&hidCollectionApplication,
&hidButtonReportId,
&hidLogicalMinimum0,
&hidLogicalMaximum1,
&(hidUsageByte0Bit0.item),
&(hidUsageByte0Bit1.item),
&(hidUsageByte0Bit2.item),
&(hidUsageByte0Bit3.item),
&(hidUsageByte0Bit4.item),
&(hidUsageByte0Bit5.item),
&(hidUsageByte0Bit6.item),
&(hidUsageByte0Bit7.item),
&hidReportSize1,
&hidReportCount8,
&hidInputDataVar,
&hidReportCount2,
&hidInputConstArray,
&hidCollectionEnd,
};
/*
* Define the number of HID Reports
* Due to XC not supporting designated initializers, this constant has a hard-coded value.
* It must equal ( sizeof hidReports / sizeof ( USB_HID_Report_Element_t* ))
*/
#define HID_REPORT_COUNT ( 2 )
#endif // __hid_report_descriptor_h__

View File

@@ -0,0 +1,153 @@
#define DEBUG_PRINT_ENABLE 1
#include <xs1.h>
#include <platform.h>
#include "xua_conf.h"
#include "user_hid.h"
#include "xua_hid_report.h"
#include "xc_ptr.h"
#include "xud.h"
#include "hid.h"
#include "debug_print.h"
#if HID_CONTROLS > 0
#ifdef XSCOPE
#include "print.h"
#endif
#ifdef DFU_CONTROL_USB_HID
#include <xccompat.h>
#define HID_DFU_REPORT_ID 0x41
#endif
#define P_GPI_BUTA_SHIFT 0x00
#define P_GPI_BUTA_MASK (1<<P_GPI_BUTA_SHIFT)
#define P_GPI_BUTB_SHIFT 0x01
#define P_GPI_BUTB_MASK (1<<P_GPI_BUTB_SHIFT)
#define P_GPI_BUTC_SHIFT 0x02
#define P_GPI_BUTC_MASK (1<<P_GPI_BUTC_SHIFT)
#define P_GPI_SW1_SHIFT 0x03
#define P_GPI_SW1_MASK (1<<P_GPI_SW1_SHIFT)
/* Write HID Report Data into hidData array
*
* Bits are as follows:
* 0: Play/Pause
* 1: Scan Next Track
* 2: Scan Prev Track
* 3: Volume Up
* 4: Volume Down
* 5: Mute
*/
unsigned multicontrol_count = 0;
unsigned wait_counter =0;
unsigned long get_reference_time();
#define THRESH 1
#define MULTIPRESS_WAIT 25
#define HID_CONTROL_NEXT 0x02
#define HID_CONTROL_PLAYPAUSE 0x01
#define HID_CONTROL_PREV 0x04
#define HID_CONTROL VOLUP 0x08
#define HID_CONTROL_VOLDN 0x10
#define HID_CONTROL_MUTE 0x20
typedef enum
{
STATE_IDLE = 0x00,
STATE_PLAY = 0x01,
STATE_NEXTPREV = 0x02,
}t_controlState;
t_controlState state;
unsigned lastA;
unsigned g_ButtonVal = 0;
unsigned char g_hid_pass_data0;
unsigned char g_hid_pass_data1;
unsigned char g_hid_pass_data2;
unsigned char g_hid_pass_data3;
unsigned char g_hid_pass_data4;
unsigned char g_hid_pass_data5;
unsigned char g_hid_pass_data6;
unsigned char g_hid_pass_data7;
void UserReadHIDButtons(unsigned char hidData[])
{
unsigned tmp;
GET_SHARED_GLOBAL(tmp, g_ButtonVal);
hidData[0] = tmp;
}
void UserReadHIDPass(unsigned char hidPassData[])
{
int i = 0;
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data0);
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data1);
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data2);
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data3);
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data4);
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data5);
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data6);
GET_SHARED_GLOBAL(hidPassData[i++], g_hid_pass_data7);
SET_SHARED_GLOBAL(g_hid_pass_data0, 0);
SET_SHARED_GLOBAL(g_hid_pass_data1, 0);
SET_SHARED_GLOBAL(g_hid_pass_data2, 0);
SET_SHARED_GLOBAL(g_hid_pass_data3, 0);
SET_SHARED_GLOBAL(g_hid_pass_data4, 0);
SET_SHARED_GLOBAL(g_hid_pass_data5, 0);
SET_SHARED_GLOBAL(g_hid_pass_data6, 0);
SET_SHARED_GLOBAL(g_hid_pass_data7, 0);
}
#if DEBUG_MEMORY_LOG_ENABLED
extern unsigned int debug_memory_log_buffer_index;
#define DEBUG_MEMORY_LOG_BUFFER_SIZE 2048
extern unsigned char debug_memory_log_buffer[DEBUG_MEMORY_LOG_BUFFER_SIZE];
unsigned int log_index = 0;
void UserReadHIDLog(unsigned char hidLogData[])
{
unsafe
{
unsigned char * unsafe logPtr = debug_memory_log_buffer;
unsigned size = (debug_memory_log_buffer_index - log_index >= 64) ? 64 : (debug_memory_log_buffer_index - log_index);
if (size > 0)
{
for (int i = 0; i < size; i++)
{
hidLogData[i] = logPtr[log_index + i];
}
log_index += size;
if (log_index >= debug_memory_log_buffer_index)
{
log_index = 0;
SET_SHARED_GLOBAL(debug_memory_log_buffer_index, 0);
}
}
else
{
for (int i = 0; i < 64; i++)
{
hidLogData[i] = 0;
}
}
}
}
#endif
#endif

View File

@@ -0,0 +1,102 @@
#ifndef _HOST_OS_DETECT_H_
#define _HOST_OS_DETECT_H_
#include "xua.h"
#include "xc_ptr.h"
#include "xassert.h"
#if XUA_USB_EN
#ifndef WINDOWS_OS_DESCRIPTOR_SUPPORT
#define WINDOWS_OS_DESCRIPTOR_SUPPORT
#endif
#define EP0_MAX_REQUEST_SIZE 2048
#include "xud.h"
#include "vendorrequests.h"
unsigned g_host_os = 0; // 1 -> Windows, 0 -> Others
int VendorAudioRequests(XUD_ep ep0_out, XUD_ep ep0_in, unsigned char bRequest, unsigned char cs, unsigned char cn,
unsigned short unitId, unsigned char direction, NULLABLE_RESOURCE(chanend, c_aud_ctl),
NULLABLE_RESOURCE(chanend, c_mix_ctl),
NULLABLE_RESOURCE(chanend, c_clk_ctL))
{
return XUD_RES_ERR;
}
enum { OS_WIN = 1, OS_OTHERS = 2 };
#if 1
int VendorRequests(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp) VENDOR_REQUESTS_PARAMS_DEC_)
{
XUD_Result_t result = XUD_RES_ERR;
unsigned char request_data[EP0_MAX_REQUEST_SIZE];
unsigned len;
int a = 0;
unsigned k = 5;
//SET_SHARED_GLOBAL(g_host_os, k);
switch ((sp->bmRequestType.Direction << 7) | (sp->bmRequestType.Type << 5) | (sp->bmRequestType.Recipient)) {
case USB_BMREQ_H2D_VENDOR_DEV:
result = XUD_GetBuffer(ep0_out, request_data, len);
if (result == XUD_RES_OKAY) {
if (a/*control_process_usb_set_request(sp.wIndex, sp.wValue, sp.wLength, request_data, i_control) == CONTROL_SUCCESS*/) {
/* zero length data to indicate success
* on control error, go to standard requests, which will issue STALL
*/
result = XUD_DoSetRequestStatus(ep0_in);
} else {
result = XUD_RES_ERR;
}
}
break;
case USB_BMREQ_D2H_VENDOR_DEV:
/* application retrieval latency inside the control library call
* XUD task defers further calls by NAKing USB transactions
*/
// if (a/*control_process_usb_get_request(sp.wIndex, sp.wValue, sp.wLength, request_data, i_control) == CONTROL_SUCCESS*/) {
// len = sp->wLength;
// result = XUD_DoGetRequest(ep0_out, ep0_in, request_data, len, len);
// /* on control error, go to standard requests, which will issue STALL */
// }
#ifdef WINDOWS_OS_DESCRIPTOR_SUPPORT
// else
if(sp->bRequest == 0x01) // GET_MS_DESCRIPTOR, same as the OS_STR_DESC last byte
{
// dwLength, 4bytes: 16 bytes
request_data[0] = 0x10; request_data[1] = 0x00; request_data[2] = 0x00; request_data[3] = 0x00;
// bcdVersion, 2bytes: For version 1.00, bcdVersion is set to 0x0100.
request_data[4] = 0x00; request_data[5] = 0x01;
// wIndex, 2bytes: 0x04 for extended compat ID descriptors
request_data[6] = 0x04; request_data[7] = 0x00;
// bCount, 1byte: 0
request_data[8] = 0x00;
// RESERVED, 7bytes: all 0
request_data[9] = 0x00; request_data[10] = 0x00; request_data[11] = 0x00;
request_data[12] = 0x00; request_data[13] = 0x00; request_data[14] = 0x00; request_data[15] = 0x00;
result = XUD_DoGetRequest(ep0_out, ep0_in, request_data, 16, sp->wLength);
//xassert(busSpeed == XUD_SPEED_HS);
k = OS_WIN;
SET_SHARED_GLOBAL(g_host_os, k);
}
else {
//xassert(busSpeed == XUD_SPEED_FS);
k = OS_OTHERS;
SET_SHARED_GLOBAL(g_host_os, k);
result = XUD_RES_ERR;
}
#endif
break;
}
return result;
}
#endif
void VendorRequests_Init(VENDOR_REQUESTS_PARAMS_DEC)
{
}
#endif /* XUA_USB_EN */
#endif

View File

@@ -0,0 +1,21 @@
#include <platform.h>
/* This is provided as simple example but disabled due to the port clash with audiostream.xc */
#if 0
on tile[0]: out port p_leds = XS1_PORT_4F;
void UserHostActive(int active)
{
if(active)
{
/* Turn all LEDs on */
p_leds <: 0xF;
}
else
{
/* Turn all LEDs off */
p_leds <: 0x0;
}
}
#endif

View File

@@ -0,0 +1,203 @@
/**
* @file htr3236.h
* @brief HTR3236 36-Channel LED PWM Driver Driver for XMOS Platform
* @version 1.1
*/
#ifndef HTR3236_H
#define HTR3236_H
#include <xccompat.h>
#include <stdint.h>
#include <i2c.h>
/*=========================================================================
I2C 寄存器地址定义
-----------------------------------------------------------------------*/
#define HTR3236_REG_SHUTDOWN 0x00 // 软件关断寄存器
#define HTR3236_REG_PWM_START 0x01 // PWM 寄存器起始地址 (OUT1)
#define HTR3236_REG_PWM_END 0x24 // PWM 寄存器结束地址 (OUT36)
#define HTR3236_REG_PWM_UPDATE 0x25 // PWM 更新寄存器
#define HTR3236_REG_LED_CTRL_START 0x26 // LED 控制寄存器起始地址 (OUT1)
#define HTR3236_REG_LED_CTRL_END 0x49 // LED 控制寄存器结束地址 (OUT36)
#define HTR3236_REG_GLOBAL_CTRL 0x4A // 全局控制寄存器
#define HTR3236_REG_FREQ_SET 0x4B // 频率设置寄存器
#define HTR3236_REG_RESET 0x4F // 复位寄存器
/*=========================================================================
寄存器位定义
-----------------------------------------------------------------------*/
// 关断寄存器 (00h)
#define HTR3236_SHUTDOWN_MASK 0x01
#define HTR3236_SHUTDOWN_SOFT 0x00
#define HTR3236_NORMAL_OP 0x01
// LED 控制寄存器位 (26h~49h)
#define HTR3236_LED_OUT_MASK 0x01
#define HTR3236_LED_CURRENT_SHIFT 1
#define HTR3236_LED_CURRENT_MASK (0x03 << 1)
// 全局控制寄存器 (4Ah)
#define HTR3236_GLOBAL_EN_MASK 0x01
// 频率设置寄存器 (4Bh)
// #define HTR3236_FREQ_3KHZ 0x00
// #define HTR3236_FREQ_22KHZ 0x01
// #define HTR3236_FREQ_MASK 0x01
/*=========================================================================
数据类型定义
-----------------------------------------------------------------------*/
typedef enum {
HTR3236_CURRENT_FULL = 0, // IMAX
HTR3236_CURRENT_HALF = 1, // IMAX/2
HTR3236_CURRENT_THIRD = 2, // IMAX/3
HTR3236_CURRENT_QUARTER = 3 // IMAX/4
} htr3236_current_t;
typedef enum {
HTR3236_FREQ_3KHZ = 0,
HTR3236_FREQ_22KHZ = 1
} htr3236_freq_t;
typedef enum {
HTR3236_ADDR_GND = 0x3C, // AD = GND: 8位地址 0x78
HTR3236_ADDR_SCL = 0x3D, // AD = SCL: 8位地址 0x7A
HTR3236_ADDR_SDA = 0x3E, // AD = SDA: 8位地址 0x7C
HTR3236_ADDR_VCC = 0x3F // AD = VCC: 8位地址 0x7E
} htr3236_addr_t;
/**
* @brief HTR3236 设备结构体
*/
typedef struct {
uint8_t i2c_addr; // I2C 设备地址
} htr3236_t;
/*=========================================================================
API 函数声明
-----------------------------------------------------------------------*/
/**
* @brief 初始化 HTR3236 设备
* @param dev 设备结构体指针
* @param i2c I2C 主控接口
* @param addr I2C 设备地址
* @param sdb_port SDB 控制端口
* @param sdb_pin SDB 引脚号
*/
void htr3236_init(htr3236_t *dev, uint8_t addr);
/**
* @brief 硬件使能 (SDB 拉高)
* @param dev 设备结构体指针
*/
void htr3236_hw_enable(htr3236_t *dev);
/**
* @brief 硬件关断 (SDB 拉低)
* @param dev 设备结构体指针
*/
void htr3236_hw_disable(htr3236_t *dev);
/**
* @brief 软件唤醒 (正常模式)
* @param dev 设备结构体指针
* @return 0:成功, -1:失败
*/
int htr3236_software_wake(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c));
/**
* @brief 软件关断
* @param dev 设备结构体指针
* @return 0:成功, -1:失败
*/
int htr3236_software_shutdown(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c));
/**
* @brief 软件复位所有寄存器
* @param dev 设备结构体指针
* @return 0:成功, -1:失败
*/
int htr3236_software_reset(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c));
/**
* @brief 设置单路 PWM 亮度
* @param dev 设备结构体指针
* @param channel 通道号 (1-36)
* @param brightness 亮度值 (0-255)
* @return 0:成功, -1:失败
*/
int htr3236_set_pwm(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t channel, uint8_t brightness);
/**
* @brief 批量设置多路 PWM 亮度 (使用自动地址递增)
* @param dev 设备结构体指针
* @param start_ch 起始通道号 (1-36)
* @param values 亮度值数组
* @param len 通道数量
* @return 0:成功, -1:失败
*/
int htr3236_set_pwm_bulk(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t start_ch,
const uint8_t *values, uint8_t len);
/**
* @brief 设置单路 LED 电流档位和使能状态
* @param dev 设备结构体指针
* @param channel 通道号 (1-36)
* @param current 电流档位
* @param enable LED 使能 (1:开启, 0:关闭)
* @return 0:成功, -1:失败
*/
int htr3236_set_led_config(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t channel,
htr3236_current_t current, uint8_t enable);
/**
* @brief 批量设置多路 LED 配置
* @param dev 设备结构体指针
* @param start_ch 起始通道号 (1-36)
* @param configs 配置数据数组 (每个字节: bit0=使能, bit2-1=电流档位)
* @param len 通道数量
* @return 0:成功, -1:失败
*/
int htr3236_set_led_config_bulk(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t start_ch,
const uint8_t *configs, uint8_t len);
/**
* @brief 更新 PWM 和 LED 配置 (写入 25h 寄存器)
* @param dev 设备结构体指针
* @return 0:成功, -1:失败
*/
int htr3236_update(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c));
/**
* @brief 全局 LED 使能控制
* @param dev 设备结构体指针
* @param enable 1:关闭所有LED, 0:正常模式
* @return 0:成功, -1:失败
*/
int htr3236_global_enable(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t enable);
/**
* @brief 设置 PWM 频率
* @param dev 设备结构体指针
* @param freq 频率 (0:3kHz, 1:22kHz)
* @return 0:成功, -1:失败
*/
int htr3236_set_frequency(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), htr3236_freq_t freq);
/**
* @brief Gamma 校正查找表 (32级)
* @param index Gamma 索引 (0-31)
* @return PWM 值 (0-255)
*/
uint8_t htr3236_gamma_32(uint8_t index);
/**
* @brief Gamma 校正查找表 (64级)
* @param index Gamma 索引 (0-63)
* @return PWM 值 (0-255)
*/
uint8_t htr3236_gamma_64(uint8_t index);
#endif /* HTR3236_H */

View File

@@ -0,0 +1,252 @@
/**
* @file htr3236.c
* @brief HTR3236 36-Channel LED PWM Driver Implementation for XMOS
* @version 1.1
*/
#include "htr3236.h"
#include <xccompat.h>
#include <platform.h>
out port p_htr3235_sdb = PORT_HTR3236_SDB; /* 连接到HTR3236的SDB引脚用于控制其电源状态 */
/*=========================================================================
Gamma 校正查找表
-----------------------------------------------------------------------*/
static const uint8_t gamma_table_32[32] = {
0, 1, 2, 4, 6, 10, 13, 18,
22, 28, 33, 39, 46, 53, 61, 69,
78, 86, 96, 106, 116, 126, 138, 149,
161, 173, 186, 199, 212, 226, 240, 255
};
static const uint8_t gamma_table_64[64] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 10, 12, 14, 16, 18, 20, 22,
24, 26, 29, 32, 35, 38, 41, 44,
47, 50, 53, 57, 61, 65, 69, 73,
77, 81, 85, 89, 94, 99, 104, 109,
114, 119, 124, 129, 134, 140, 146, 152,
158, 164, 170, 176, 182, 188, 195, 202,
209, 216, 223, 230, 237, 244, 251, 255
};
/*=========================================================================
内部函数
-----------------------------------------------------------------------*/
/**
* @brief 写单字节到寄存器
*/
static int write_reg(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t reg, uint8_t data)
{
uint8_t buf[2] = {reg, data};
size_t n;
i2c.write(dev->i2c_addr, buf, 2, n, 1);
if (n == 0)
{
return I2C_REGOP_DEVICE_NACK;
}
if (n < 2)
{
return I2C_REGOP_INCOMPLETE;
}
return I2C_REGOP_SUCCESS;
}
/**
* @brief 写多字节到寄存器 (支持自动地址递增)
*/
static int write_reg_bulk(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t start_reg,
const uint8_t *data, uint8_t len)
{
uint8_t buf[36 + 1];
size_t n;
buf[0] = start_reg;
for (int i = 0; i < len; i++) {
buf[i + 1] = data[i];
}
i2c.write(dev->i2c_addr, buf, len + 1, n, 1);
if (n == 0)
{
return I2C_REGOP_DEVICE_NACK;
}
if (n < 2)
{
return I2C_REGOP_INCOMPLETE;
}
return I2C_REGOP_SUCCESS;
}
/**
* @brief 读取寄存器值
*/
static int read_reg(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t reg, i2c_regop_res_t &result)
{
uint8_t a_reg[1] = {reg};
uint8_t data[1] = {0};
size_t n;
i2c_res_t res;
unsafe
{
res = i2c.write(dev->i2c_addr, a_reg, 1, n, 0);
if (n != 1)
{
result = I2C_REGOP_DEVICE_NACK;
i2c.send_stop_bit();
return 0;
}
res = i2c.read(dev->i2c_addr, data, 1, 1);
}
if (res == I2C_ACK)
{
result = I2C_REGOP_SUCCESS;
}
else
{
result = I2C_REGOP_DEVICE_NACK;
}
return data[0];
}
/*=========================================================================
API 函数实现
-----------------------------------------------------------------------*/
void htr3236_init(htr3236_t *dev, uint8_t addr)
{
dev->i2c_addr = addr;
// 默认 SDB 拉高,使能芯片
//htr3236_hw_enable(dev);
}
void htr3236_hw_enable(htr3236_t *dev)
{
p_htr3235_sdb <: 1;
}
void htr3236_hw_disable(htr3236_t *dev)
{
p_htr3235_sdb <: 0;
}
int htr3236_software_wake(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c))
{
return write_reg(dev, i2c, HTR3236_REG_SHUTDOWN, HTR3236_NORMAL_OP);
}
int htr3236_software_shutdown(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c))
{
return write_reg(dev, i2c, HTR3236_REG_SHUTDOWN, HTR3236_SHUTDOWN_SOFT);
}
int htr3236_software_reset(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c))
{
return write_reg(dev, i2c, HTR3236_REG_RESET, 0x00);
}
int htr3236_set_pwm(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t channel, uint8_t brightness)
{
if (channel < 1 || channel > 36) {
return -1;
}
uint8_t reg = HTR3236_REG_PWM_START + (channel - 1);
return write_reg(dev, i2c, reg, brightness);
}
int htr3236_set_pwm_bulk(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t start_ch,
const uint8_t *values, uint8_t len)
{
if (start_ch < 1 || start_ch > 36 || len == 0) {
return -1;
}
// 检查是否会超出寄存器范围
if (start_ch + len - 1 > 36) {
return -1;
}
uint8_t start_reg = HTR3236_REG_PWM_START + (start_ch - 1);
return write_reg_bulk(dev, i2c, start_reg, values, len);
}
int htr3236_set_led_config(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t channel,
htr3236_current_t current, uint8_t enable)
{
if (channel < 1 || channel > 36) {
return -1;
}
uint8_t reg = HTR3236_REG_LED_CTRL_START + (channel - 1);
uint8_t data = (enable ? 1 : 0) | (current << 1);
return write_reg(dev, i2c, reg, data);
}
int htr3236_set_led_config_bulk(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t start_ch,
const uint8_t *configs, uint8_t len)
{
if (start_ch < 1 || start_ch > 36 || len == 0) {
return -1;
}
// 检查是否会超出寄存器范围
if (start_ch + len - 1 > 36) {
return -1;
}
uint8_t start_reg = HTR3236_REG_LED_CTRL_START + (start_ch - 1);
return write_reg_bulk(dev, i2c, start_reg, configs, len);
}
int htr3236_update(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c))
{
// 写入任意值到更新寄存器使配置生效
return write_reg(dev, i2c, HTR3236_REG_PWM_UPDATE, 0x00);
}
int htr3236_global_enable(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), uint8_t enable)
{
uint8_t data = enable ? 1 : 0;
return write_reg(dev, i2c, HTR3236_REG_GLOBAL_CTRL, data);
}
int htr3236_set_frequency(htr3236_t *dev, CLIENT_INTERFACE(i2c_master_if, i2c), htr3236_freq_t freq)
{
uint8_t data = (freq == HTR3236_FREQ_22KHZ) ? 1 : 0;
return write_reg(dev, i2c, HTR3236_REG_FREQ_SET, data);
}
uint8_t htr3236_gamma_32(uint8_t index)
{
if (index >= 32) {
index = 31;
}
return gamma_table_32[index];
}
uint8_t htr3236_gamma_64(uint8_t index)
{
if (index >= 64) {
index = 63;
}
return gamma_table_64[index];
}

View File

@@ -0,0 +1,17 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __KEYS_H__
#define __KEYS_H__
#define KEY_MIC_VOL_DN 0x08
#define KEY_MUTE 0x10
#define KEY_MIC_VOL_UP 0x20
#define KEY_PLAY_VOL_DN 0x40
#define KEY_PLAY_VOL_UP 0x80
#define KEY_BITS (KEY_MIC_VOL_DN | KEY_MUTE | KEY_MIC_VOL_UP | KEY_PLAY_VOL_DN | KEY_PLAY_VOL_UP)
#define MUTED_MIC 0x5A
#define UNMUTED_MIC 0xA5
#endif

View File

@@ -0,0 +1,265 @@
/**
* @file led_control.c
* @brief LED控制API实现 (基于HTR3236)
* @version 1.0
*/
#include "led_control.h"
#include <string.h>
#include <math.h>
#include <timer.h>
/*=========================================================================
内部函数
-----------------------------------------------------------------------*/
/**
* @brief 检查LED ID是否有效
*/
static int is_valid_led(led_id_t led)
{
return (led >= 1 && led <= 36 && led != 36); // OUT36未使用
}
/**
* @brief 获取LED组起始和结束索引
*/
static void get_group_range(led_group_t group, uint8_t *start, uint8_t *end)
{
switch (group) {
case LED_GROUP_L_SERIES:
*start = LED_L1;
*end = LED_L15;
break;
case LED_GROUP_D_SERIES:
*start = LED_D1;
*end = LED_D15;
break;
// case LED_GROUP_FUNCTION:
// *start = LED_ANC;
// *end = LED_GAME_MODE;
// break;
case LED_GROUP_ALL:
default:
*start = 1;
*end = 35; // 排除OUT36
break;
}
}
/*=========================================================================
LED物理映射表
-----------------------------------------------------------------------*/
// 根据测试结果LED_L1-L15的实际OUT口
const uint8_t led_l_physical_map[15] = {
15, // LED_L1 -> OUT15
14, // LED_L2 -> OUT14
13, // LED_L3 -> OUT13
11, // LED_L4 -> OUT11
10, // LED_L5 -> OUT10
9, // LED_L6 -> OUT9
8, // LED_L7 -> OUT8
7, // LED_L8 -> OUT7
6, // LED_L9 -> OUT6
5, // LED_L10 -> OUT5
4, // LED_L11 -> OUT4
12, // LED_L12 -> OUT12 *
18, // LED_L13 -> OUT18 *
17, // LED_L14 -> OUT17
16, // LED_L15 -> OUT16
};
// 根据测试结果LED_D1-D15的实际OUT口
const uint8_t led_d_physical_map[15] = {
21, // LED_D1 -> OUT21
20, // LED_D2 -> OUT20
19, // LED_D3 -> OUT19
26, // LED_D4 -> OUT26 *
33, // LED_D5 -> OUT33 *
32, // LED_D6 -> OUT32
31, // LED_D7 -> OUT31
30, // LED_D8 -> OUT30
29, // LED_D9 -> OUT29
28, // LED_D10 -> OUT28
27, // LED_D11 -> OUT27
25, // LED_D12 -> OUT25
24, // LED_D13 -> OUT24
23, // LED_D14 -> OUT23
22, // LED_D15 -> OUT22
};
const uint8_t mic_gain_to_led[39] = {
0, // [-1] 增益-1: 0个LED这个设计未启用
0, // [0] 增益0: 0个LED
0, // [1] 增益1: 0个LED
0, // [2] 增益2: 0个LED
1, // [3] 增益3: 1个LED
1, // [4] 增益4: 1个LED
1, // [5] 增益5: 1个LED
2, // [6] 增益6: 2个LED
2, // [7] 增益7: 2个LED
2, // [8] 增益8: 2个LED
3, // [9] 增益9: 3个LED
3, // [10] 增益10: 3个LED
3, // [11] 增益11: 3个LED
4, // [12] 增益12: 4个LED
4, // [13] 增益13: 4个LED
4, // [14] 增益14: 4个LED
5, // [15] 增益15: 5个LED
5, // [16] 增益16: 5个LED
6, // [17] 增益17: 6个LED
6, // [18] 增益18: 6个LED
7, // [19] 增益19: 7个LED
7, // [20] 增益20: 7个LED
8, // [21] 增益21: 8个LED
8, // [22] 增益22: 8个LED
9, // [23] 增益23: 9个LED
9, // [24] 增益24: 9个LED
10, // [25] 增益25: 10个LED
10, // [26] 增益26: 10个LED
11, // [27] 增益27: 11个LED
11, // [28] 增益28: 11个LED
12, // [29] 增益29: 12个LED
12, // [30] 增益30: 12个LED
13, // [31] 增益31: 13个LED
13, // [32] 增益32: 13个LED
14, // [33] 增益33: 14个LED
14, // [34] 增益34: 14个LED
15, // [35] 增益35: 15个LED
15, // [36] 增益36: 15个LED
15 // [37] 增益36+1.5 digitial gain: 15个LED
};
/*=========================================================================
内部函数 - 获取实际OUT口
-----------------------------------------------------------------------*/
static uint8_t get_physical_out(led_id_t led)
{
// 如果是L系列LED
if (led >= LED_L1 && led <= LED_L15) {
uint8_t index = led - LED_L1;
return led_l_physical_map[index];
}
else if (led >= LED_D1 && led <= LED_D15) {
uint8_t index = led - LED_D1;
return led_d_physical_map[index];
}
// 其他LED直接返回原值
return (uint8_t)led;
}
/*=========================================================================
基础控制API实现
-----------------------------------------------------------------------*/
void led_control_init(led_control_t *ctx,
htr3236_t *dev,
CLIENT_INTERFACE(i2c_master_if,i2c))
{
ctx->htr3236_dev = dev;
ctx->i2c = i2c;
// 初始化亮度缓存
memset(ctx->brightness, 0, sizeof(ctx->brightness));
// 配置所有LED通道的电流 (使用IMAX/2)
for (int led = 1; led <= 35; led++) { // 跳过OUT36
htr3236_set_led_config(ctx->htr3236_dev, ctx->i2c,
led, HTR3236_CURRENT_HALF, 1);
}
// 初始关闭所有LED
for (int led = 1; led <= 35; led++) {
htr3236_set_pwm(ctx->htr3236_dev, ctx->i2c, led, 0);
}
htr3236_update(ctx->htr3236_dev, ctx->i2c);
}
int led_set_brightness(led_control_t *ctx,
led_id_t led,
uint8_t brightness)
{
if (!is_valid_led(led)) {
return -1;
}
ctx->brightness[led - 1] = brightness;
return htr3236_set_pwm(ctx->htr3236_dev, ctx->i2c, led, brightness);
}
int led_on(led_control_t *ctx, led_id_t led)
{
return led_set_brightness(ctx, led, 1/*255*/);
}
int led_off(led_control_t *ctx, led_id_t led)
{
return led_set_brightness(ctx, led, 0);
}
int led_toggle(led_control_t *ctx, led_id_t led)
{
if (!is_valid_led(led)) {
return -1;
}
uint8_t new_brightness = (ctx->brightness[led - 1] == 0) ? 255 : 0;
return led_set_brightness(ctx, led, new_brightness);
}
int led_update_all(led_control_t *ctx)
{
return htr3236_update(ctx->htr3236_dev, ctx->i2c);
}
/*=========================================================================
组控制API实现
-----------------------------------------------------------------------*/
int led_group_set_brightness(led_control_t *ctx,
led_group_t group,
uint8_t brightness)
{
uint8_t start, end;
get_group_range(group, &start, &end);
if (group == LED_GROUP_FUNCTION) {
// 功能LED需要单独处理每个LED
led_id_t function_leds[] = {
LED_MUSIC, LED_ANC, LED_FOOTSTEP_MODE, LED_AI7_1, LED_GAME_MODE
};
for (int i = 0; i < 5; i++) {
led_id_t led = function_leds[i];
uint8_t physical_out = get_physical_out(led); // 如果有映射
ctx->brightness[physical_out - 1] = brightness;
htr3236_set_pwm(ctx->htr3236_dev, ctx->i2c, led, brightness);
}
}
else
{
for (uint8_t led = start; led <= end; led++) {
if (led == 36) continue; // 跳过未使用的OUT36
if((group == LED_GROUP_L_SERIES) || (group == LED_GROUP_D_SERIES))
{
uint8_t physical_out = get_physical_out(led);
ctx->brightness[physical_out - 1] = brightness;
}
else ctx->brightness[led - 1] = brightness;
htr3236_set_pwm(ctx->htr3236_dev, ctx->i2c, led, brightness);
}
}
return htr3236_update(ctx->htr3236_dev, ctx->i2c);
}
int led_group_on(led_control_t *ctx, led_group_t group)
{
return led_group_set_brightness(ctx, group, 255);
}
int led_group_off(led_control_t *ctx, led_group_t group)
{
return led_group_set_brightness(ctx, group, 0);
}

View File

@@ -0,0 +1,161 @@
/**
* @file led_control.h
* @brief LED控制API (基于HTR3236)
* @version 1.0
*/
#ifndef LED_CONTROL_H
#define LED_CONTROL_H
#include <stdint.h>
#include "htr3236.h"
#ifdef __XC__
extern "C" {
#endif
/*=========================================================================
LED类型定义
-----------------------------------------------------------------------*/
typedef enum {
// 功能LED (单个LED)
LED_MUSIC = 2, // OUT2 - 音乐模式
LED_ANC = 1, // OUT1 - ANC模式
LED_FOOTSTEP_MODE = 3, // OUT3 - 脚步模式
LED_AI7_1 = 34, // OUT34 - AI7.1模式
LED_GAME_MODE = 35, // OUT35 - 游戏模式
// OUT36未使用
// L系列LED (OUT4-OUT18)
LED_L1 = 4, LED_L2 = 5, LED_L3 = 6, LED_L4 = 7, LED_L5 = 8,
LED_L6 = 9, LED_L7 = 10, LED_L8 = 11, LED_L9 = 12, LED_L10 = 13,
LED_L11 = 14, LED_L12 = 15, LED_L13 = 16, LED_L14 = 17, LED_L15 = 18,
// D系列LED (OUT19-OUT33)
LED_D1 = 19, LED_D2 = 20, LED_D3 = 21, LED_D4 = 22, LED_D5 = 23,
LED_D6 = 24, LED_D7 = 25, LED_D8 = 26, LED_D9 = 27, LED_D10 = 28,
LED_D11 = 29, LED_D12 = 30, LED_D13 = 31, LED_D14 = 32, LED_D15 = 33,
LED_MAX = 36
} led_id_t;
/*=========================================================================
LED组定义
-----------------------------------------------------------------------*/
typedef enum {
LED_GROUP_L_SERIES, // L1-L15
LED_GROUP_D_SERIES, // D1-D15
LED_GROUP_FUNCTION, // 功能LED (ANC, MUSIC, FOOTSTEP, AI7_7, GAME)
LED_GROUP_ALL // 所有LED
} led_group_t;
/*=========================================================================
LED控制上下文
-----------------------------------------------------------------------*/
typedef struct {
htr3236_t *htr3236_dev; // HTR3236设备指针
CLIENT_INTERFACE(i2c_master_if,i2c); // I2C接口
uint8_t brightness[36]; // 当前亮度缓存
} led_control_t;
/*=========================================================================
LED物理映射表
-----------------------------------------------------------------------*/
// 逻辑LED编号到物理OUT口的映射表
extern const uint8_t led_l_physical_map[15];
extern const uint8_t led_d_physical_map[15];
extern const uint8_t mic_gain_to_led[39];
/*=========================================================================
基础控制API
-----------------------------------------------------------------------*/
/**
* @brief 初始化LED控制系统
* @param ctx 上下文指针
* @param dev HTR3236设备指针
* @param i2c I2C接口
*/
void led_control_init(led_control_t *ctx,
htr3236_t *dev,
CLIENT_INTERFACE(i2c_master_if,i2c));
/**
* @brief 设置单个LED亮度
* @param ctx 上下文指针
* @param led LED ID
* @param brightness 亮度值 (0-255)
* @return 0:成功, -1:失败
*/
int led_set_brightness(led_control_t *ctx,
led_id_t led,
uint8_t brightness);
/**
* @brief 开启单个LED (最大亮度)
* @param ctx 上下文指针
* @param led LED ID
* @return 0:成功, -1:失败
*/
int led_on(led_control_t *ctx, led_id_t led);
/**
* @brief 关闭单个LED
* @param ctx 上下文指针
* @param led LED ID
* @return 0:成功, -1:失败
*/
int led_off(led_control_t *ctx, led_id_t led);
/**
* @brief 切换LED状态
* @param ctx 上下文指针
* @param led LED ID
* @return 0:成功, -1:失败
*/
int led_toggle(led_control_t *ctx, led_id_t led);
/**
* @brief 更新所有LED显示 (调用htr3236_update)
* @param ctx 上下文指针
* @return 0:成功, -1:失败
*/
int led_update_all(led_control_t *ctx);
/*=========================================================================
组控制API
-----------------------------------------------------------------------*/
/**
* @brief 设置一组LED的亮度
* @param ctx 上下文指针
* @param group LED组
* @param brightness 亮度值 (0-255)
* @return 0:成功, -1:失败
*/
int led_group_set_brightness(led_control_t *ctx,
led_group_t group,
uint8_t brightness);
/**
* @brief 开启一组LED
* @param ctx 上下文指针
* @param group LED组
* @return 0:成功, -1:失败
*/
int led_group_on(led_control_t *ctx, led_group_t group);
/**
* @brief 关闭一组LED
* @param ctx 上下文指针
* @param group LED组
* @return 0:成功, -1:失败
*/
int led_group_off(led_control_t *ctx, led_group_t group);
#ifdef __XC__
}
#endif
#endif /* LED_CONTROL_H */

View File

@@ -0,0 +1,13 @@
#ifndef _LFS_IO_H_
#define _LFS_IO_H_
int lfs_init(void);
void lfs_deinit(void);
void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned size);
void lfs_write_config(unsigned char * config, unsigned char * buffer, unsigned size);
// EQ参数专用函数
void lfs_read_eq_config(const char * file_path, unsigned char * buffer, unsigned size);
void lfs_write_eq_config(const char * file_path, unsigned char * buffer, unsigned size);
int lfs_file_exists(const char * file_path);
int lfs_remove_file(const char * file_path);
int lfs_create_directory(const char * dir_path);
#endif

View File

@@ -0,0 +1,233 @@
#include <stdlib.h>
#include <xs1.h>
#include <platform.h>
#include "lfs.h"
#include "rtos_qspi_flash.h"
#include "swlock.h"
#include "debug_print.h"
// variables used by the filesystem
lfs_t lfs;
lfs_file_t file;
swlock_t lfs_lock = SWLOCK_INITIAL_VALUE;
static rtos_qspi_flash_t qspi_flash_ctx_s;
#define FLASH_CLKBLK XS1_CLKBLK_3
#ifndef FS_BASE_ADDR
#define FS_BASE_ADDR 0x1a0000
#endif
#define SECTOR_SIZE 4096
rtos_qspi_flash_t *qspi_flash_ctx = &qspi_flash_ctx_s;
__attribute__((fptrgroup(" local_block_device_read_fptr_grp")))
int local_block_device_read(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size)
{
unsigned address = (FS_BASE_ADDR + block * SECTOR_SIZE + off);
qspi_flash_ctx->read(qspi_flash_ctx, buffer, address, size);
return 0;
}
__attribute__((fptrgroup(" local_block_device_prog_fptr_grp")))
int local_block_device_prog(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size)
{
unsigned address = (FS_BASE_ADDR + block * SECTOR_SIZE + off);
qspi_flash_ctx->write(qspi_flash_ctx, buffer, address, size);
return 0;
}
__attribute__((fptrgroup(" local_block_device_erase_fptr_grp")))
int local_block_device_erase(const struct lfs_config *c, lfs_block_t block)
{
unsigned address = (FS_BASE_ADDR + block * SECTOR_SIZE);
qspi_flash_ctx->erase(qspi_flash_ctx, address, SECTOR_SIZE);
return 0;
}
__attribute__((fptrgroup(" local_block_device_sync_fptr_grp")))
int local_block_device_sync(const struct lfs_config *c)
{
return 0;
}
// configuration of the filesystem is provided by this struct
const struct lfs_config cfg = {
// block device operations
.read = local_block_device_read,
.prog = local_block_device_prog,
.erase = local_block_device_erase,
.sync = local_block_device_sync,
// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
};
int lfs_init(void) {
swlock_acquire(&lfs_lock);
rtos_qspi_flash_init(
qspi_flash_ctx,
FLASH_CLKBLK,
XS1_PORT_1B,
XS1_PORT_1C,
XS1_PORT_4B,
NULL);
// mount the filesystem
int err = lfs_mount(&lfs, &cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
debug_printf("no lfs partiton is found, formating ...\n");
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
swlock_release(&lfs_lock);
return -1;
}
swlock_release(&lfs_lock);
return 0;
}
void lfs_deinit(void) {
swlock_acquire(&lfs_lock);
lfs_unmount(&lfs);
swlock_release(&lfs_lock);
}
#pragma stackfunction 1300
void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned size)
{
swlock_acquire(&lfs_lock);
debug_printf("lfs_read_config: %s, size: %d\n", config, size);
int result = lfs_file_open(&lfs, &file, config, LFS_O_RDWR | LFS_O_CREAT);
debug_printf("lfs_read_config: %s, result: %d\n", config, result);
if (result != 0) {
debug_printf("lfs_read_config: %s, open file failed\n", config);
swlock_release(&lfs_lock);
return;
}
debug_printf("lfs_read_config: %s, file opened\n", config);
result = lfs_file_read(&lfs, &file, buffer, size);
debug_printf("lfs_read_config: %s, result: %d\n", config, result);
if (result < 0) {
debug_printf("lfs_read_config: %s, read file failed, error: %d\n", config, result);
// Update: Added lfs_file_close to ensure file is closed even on error.
// Missing this caused subsequent open calls to assert/crash.
lfs_file_close(&lfs, &file);
swlock_release(&lfs_lock);
return;
}
lfs_file_close(&lfs, &file);
swlock_release(&lfs_lock);
}
#pragma stackfunction 1300
void lfs_write_config(unsigned char * config, unsigned char * buffer, unsigned size)
{
swlock_acquire(&lfs_lock);
debug_printf("lfs_write_config: %s, size: %d\n", config, size);
int result = lfs_file_open(&lfs, &file, config, LFS_O_RDWR | LFS_O_CREAT);
if (result != 0) {
debug_printf("lfs_write_config: open file failed\n");
swlock_release(&lfs_lock);
return;
}
result = lfs_file_rewind(&lfs, &file);
if (result != 0) {
debug_printf("lfs_write_config: rewind file failed\n");
// Update: Added lfs_file_close to prevent file remaining open if rewind fails.
lfs_file_close(&lfs, &file);
swlock_release(&lfs_lock);
return;
}
lfs_file_write(&lfs, &file, buffer, size);
lfs_file_close(&lfs, &file);
swlock_release(&lfs_lock);
}
// 检查文件是否存在
int lfs_file_exists(const char * file_path)
{
swlock_acquire(&lfs_lock);
lfs_file_t file;
int result = lfs_file_open(&lfs, &file, file_path, LFS_O_RDONLY);
if (result == 0) {
lfs_file_close(&lfs, &file);
swlock_release(&lfs_lock);
return 1; // 文件存在
}
swlock_release(&lfs_lock);
return 0; // 文件不存在
}
// EQ参数专用读写函数
void lfs_read_eq_config(const char * file_path, unsigned char * buffer, unsigned size)
{
lfs_file_open(&lfs, &file, file_path, LFS_O_RDONLY);
lfs_file_read(&lfs, &file, buffer, size);
lfs_file_close(&lfs, &file);
}
void lfs_write_eq_config(const char * file_path, unsigned char * buffer, unsigned size)
{
lfs_file_open(&lfs, &file, file_path, LFS_O_RDWR | LFS_O_CREAT);
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, buffer, size);
lfs_file_close(&lfs, &file);
}
// 删除文件
int lfs_remove_file(const char * file_path)
{
return lfs_remove(&lfs, file_path);
}
// 创建目录(通过创建临时文件然后删除)
int lfs_create_directory(const char * dir_path)
{
char temp_file[256];
snprintf(temp_file, sizeof(temp_file), "%s/.dir", dir_path);
lfs_file_t file;
int result = lfs_file_open(&lfs, &file, temp_file, LFS_O_RDWR | LFS_O_CREAT);
if (result == 0) {
lfs_file_close(&lfs, &file);
lfs_remove(&lfs, temp_file);
return 0; // 成功
}
return -1; // 失败
}
#if 0
// read current count
uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
// update boot count
boot_count += 1;
lfs_file_rewind(&lfs, &file);
for (int i = 0; i < 100; i++)
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully
lfs_file_close(&lfs, &file);
// release any resources we were using
lfs_unmount(&lfs);
// print the boot count
printf("boot_count: %d\n", boot_count);
#endif

View File

@@ -0,0 +1,733 @@
// Copyright 2012-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h" /* Device specific defines */
#ifdef EXCLUDE_USB_AUDIO_MAIN
/**
* @file main.xc
* @brief Top level for XMOS USB 2.0 Audio 2.0 Reference Designs.
* @author Ross Owen, XMOS Semiconductor Ltd
*/
#include <syscall.h>
#include <platform.h>
#include <xs1.h>
#include <xclib.h>
#include <print.h>
#ifdef XSCOPE
#include <xscope.h>
#endif
#if XUA_USB_EN
#include "xud_device.h" /* XMOS USB Device Layer defines and functions */
#include "xua_endpoint0.h"
#endif
#include "uac_hwresources.h"
#ifdef IAP
#include "i2c_shared.h"
#include "iap.h"
#endif
#if (XUA_SPDIF_RX_EN || XUA_SPDIF_TX_EN)
#include "spdif.h" /* From lib_spdif */
#endif
#if (XUA_ADAT_RX_EN)
#include "adat_rx.h"
#endif
#if (XUA_NUM_PDM_MICS > 0)
#include "xua_pdm_mic.h"
#endif
#if (XUA_DFU_EN == 1)
[[distributable]]
void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd);
#endif
/* Audio I/O - Port declarations */
#if I2S_WIRES_DAC > 0
on tile[AUDIO_IO_TILE] : buffered out port:32 p_i2s_dac[I2S_WIRES_DAC] =
{PORT_I2S_DAC0,
#endif
#if I2S_WIRES_DAC > 1
PORT_I2S_DAC1,
#endif
#if I2S_WIRES_DAC > 2
PORT_I2S_DAC2,
#endif
#if I2S_WIRES_DAC > 3
PORT_I2S_DAC3,
#endif
#if I2S_WIRES_DAC > 4
PORT_I2S_DAC4,
#endif
#if I2S_WIRES_DAC > 5
PORT_I2S_DAC5,
#endif
#if I2S_WIRES_DAC > 6
PORT_I2S_DAC6,
#endif
#if I2S_WIRES_DAC > 7
#error I2S_WIRES_DAC value is too large!
#endif
#if I2S_WIRES_DAC > 0
};
#else
#define p_i2s_dac null
#endif
#if I2S_WIRES_ADC > 0
on tile[AUDIO_IO_TILE] : buffered in port:32 p_i2s_adc[I2S_WIRES_ADC] =
{PORT_I2S_ADC0,
#endif
#if I2S_WIRES_ADC > 1
PORT_I2S_ADC1,
#endif
#if I2S_WIRES_ADC > 2
PORT_I2S_ADC2,
#endif
#if I2S_WIRES_ADC > 3
PORT_I2S_ADC3,
#endif
#if I2S_WIRES_ADC > 4
PORT_I2S_ADC4,
#endif
#if I2S_WIRES_ADC > 5
PORT_I2S_ADC5,
#endif
#if I2S_WIRES_ADC > 6
PORT_I2S_ADC6,
#endif
#if I2S_WIRES_ADC > 7
#error I2S_WIRES_ADC value is too large!
#endif
#if I2S_WIRES_ADC > 0
};
#else
#define p_i2s_adc null
#endif
#if CODEC_MASTER
on tile[AUDIO_IO_TILE] : buffered in port:32 p_lrclk = PORT_I2S_LRCLK;
on tile[AUDIO_IO_TILE] : buffered in port:32 p_bclk = PORT_I2S_BCLK;
#else
on tile[AUDIO_IO_TILE] : buffered out port:32 p_lrclk = PORT_I2S_LRCLK;
on tile[AUDIO_IO_TILE] : buffered out port:32 p_bclk = PORT_I2S_BCLK;
#endif
#if (!CODEC_MASTER) || XUA_SPDIF_TX_EN || XUA_ADAT_TX_EN || ((AUDIO_IO_TILE == XUD_TILE) && XUA_USB_EN)
/* Audio master clock input */
on tile[AUDIO_IO_TILE] : in port p_mclk_in = PORT_MCLK_IN;
#else
#define p_mclk_in null
#endif
#if (AUDIO_IO_TILE != XUD_TILE) && XUA_USB_EN
/* If audio I/O and USB running on different tiles we need a separate port for
* the master clock input (to use for USB async feedback calculation) */
on tile[XUD_TILE] : in port p_mclk_in_usb = PORT_MCLK_IN_USB;
#endif
#if XUA_USB_EN
on tile[XUD_TILE] : in port p_for_mclk_count = PORT_MCLK_COUNT;
#endif
#if (XUA_SPDIF_TX_EN)
on tile[SPDIF_TX_TILE] : buffered out port:32 p_spdif_tx = PORT_SPDIF_OUT;
#endif
#if (XUA_ADAT_TX_EN)
on stdcore[AUDIO_IO_TILE] : buffered out port:32 p_adat_tx = PORT_ADAT_OUT;
#endif
#if (XUA_ADAT_RX_EN)
on stdcore[XUD_TILE] : buffered in port:32 p_adat_rx = PORT_ADAT_IN;
#endif
#if (XUA_SPDIF_RX_EN)
on tile[XUD_TILE] : in port p_spdif_rx = PORT_SPDIF_IN;
#endif
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
/* Reference to external clock multiplier */
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
#ifdef MIDI
on tile[MIDI_TILE] : port p_midi_tx = PORT_MIDI_OUT;
#if(MIDI_RX_PORT_WIDTH == 4)
on tile[MIDI_TILE] : buffered in port:4 p_midi_rx = PORT_MIDI_IN;
#elif(MIDI_RX_PORT_WIDTH == 1)
on tile[MIDI_TILE] : buffered in port:1 p_midi_rx = PORT_MIDI_IN;
#endif
#endif
#ifdef MIDI
on tile[MIDI_TILE] : clock clk_midi = CLKBLK_MIDI;
#endif
#if (XUA_SPDIF_TX_EN || XUA_ADAT_TX_EN)
on tile[SPDIF_TX_TILE] : clock clk_mst_spd = CLKBLK_SPDIF_TX;
#endif
#if (XUA_SPDIF_RX_EN)
on tile[XUD_TILE] : clock clk_spd_rx = CLKBLK_SPDIF_RX;
#endif
on tile[AUDIO_IO_TILE] : clock clk_audio_mclk = CLKBLK_MCLK; /* Master clock */
#if (AUDIO_IO_TILE != XUD_TILE) && XUA_USB_EN
/* Separate clock/port for USB feedback calculation */
on tile[XUD_TILE] : clock clk_audio_mclk_usb = CLKBLK_MCLK; /* Master clock */
#endif
on tile[AUDIO_IO_TILE] : clock clk_audio_bclk = CLKBLK_I2S_BIT; /* Bit clock */
#ifdef IAP
/* I2C ports - in a struct for use with module_i2c_shared & module_i2c_simple/module_i2c_single_port */
#ifdef PORT_I2C
on tile [IAP_TILE] : struct r_i2c r_i2c = {PORT_I2C};
#else
on tile [IAP_TILE] : struct r_i2c r_i2c = {PORT_I2C_SCL, PORT_I2C_SDA};
#endif
#endif
#if XUA_USB_EN
/* Endpoint type tables for XUD */
XUD_EpType epTypeTableOut[ENDPOINT_COUNT_OUT] = { XUD_EPTYPE_CTL | XUD_STATUS_ENABLE,
#if (NUM_USB_CHAN_IN > 0)
XUD_EPTYPE_ISO, /* Audio */
#endif
#ifdef MIDI
XUD_EPTYPE_BUL, /* MIDI */
#endif
#if HID_OUT_REQUIRED
XUD_EPTYPE_INT,
#endif
#ifdef IAP
XUD_EPTYPE_BUL, /* iAP */
#ifdef IAP_EA_NATIVE_TRANS
XUD_EPTYPE_BUL, /* EA Native Transport */
#endif
#endif
};
XUD_EpType epTypeTableIn[ENDPOINT_COUNT_IN] = { XUD_EPTYPE_CTL | XUD_STATUS_ENABLE,
#if (NUM_USB_CHAN_IN > 0)
XUD_EPTYPE_ISO,
#endif
#if (NUM_USB_CHAN_OUT > 0) && ((NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP))
XUD_EPTYPE_ISO, /* Async feedback endpoint */
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
XUD_EPTYPE_INT,
#endif
#ifdef MIDI
XUD_EPTYPE_BUL,
#endif
#if XUA_OR_STATIC_HID_ENABLED
XUD_EPTYPE_INT,
#endif
#ifdef IAP
XUD_EPTYPE_BUL | XUD_STATUS_ENABLE,
#ifdef IAP_INT_EP
XUD_EPTYPE_BUL | XUD_STATUS_ENABLE,
#endif
#ifdef IAP_EA_NATIVE_TRANS
XUD_EPTYPE_BUL | XUD_STATUS_ENABLE,
#endif
#endif
};
#endif /* XUA_USB_EN */
void thread_speed()
{
#ifdef FAST_MODE
#warning Building with fast mode enabled
set_thread_fast_mode_on();
#else
set_thread_fast_mode_off();
#endif
}
#ifdef XSCOPE
void xscope_user_init()
{
xscope_register(0, 0, "", 0, "");
xscope_config_io(XSCOPE_IO_BASIC);
}
#endif
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
void SpdifTxWrapper(chanend c_spdif_tx)
{
unsigned portId;
//configure_clock_src(clk, p_mclk);
// TODO could share clock block here..
// NOTE, Assuming SPDIF tile == USB tile here..
asm("ldw %0, dp[p_mclk_in_usb]":"=r"(portId));
asm("setclk res[%0], %1"::"r"(clk_mst_spd), "r"(portId));
configure_out_port_no_ready(p_spdif_tx, clk_mst_spd, 0);
set_clock_fall_delay(clk_mst_spd, 7);
start_clock(clk_mst_spd);
while(1)
{
spdif_tx(p_spdif_tx, c_spdif_tx);
}
}
#endif
void usb_audio_io(chanend ?c_aud_in,
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
chanend c_spdif_tx,
#endif
#if (MIXER)
chanend c_mix_ctl,
#endif
streaming chanend ?c_spdif_rx,
streaming chanend ?c_adat_rx,
chanend ?c_clk_ctl,
chanend ?c_clk_int
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
, server interface i_dfu ?dfuInterface
#endif
#if (XUA_NUM_PDM_MICS > 0)
, chanend c_pdm_pcm
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
, client interface pll_ref_if i_pll_ref
#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)
chan c_mix_out;
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
chan c_dig_rx;
chan c_audio_rate_change; /* Notification of new mclk freq to clockgen and synch */
#if XUA_USE_SW_PLL
/* 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_SPDIF_TX_EN) && (SPDIF_TX_TILE == AUDIO_IO_TILE)
chan c_spdif_tx;
/* Setup S/PDIF tx port - note this is done before par since sharing clock-block/port */
spdif_tx_port_config(p_spdif_tx, clk_audio_mclk, p_mclk_in, 7);
#endif
par
{
#if (MIXER && XUA_USB_EN)
/* Mixer cores(s) */
{
thread_speed();
mixer(c_aud_in, c_mix_out, c_mix_ctl);
}
#endif
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE == AUDIO_IO_TILE)
while(1)
{
spdif_tx(p_spdif_tx, c_spdif_tx);
}
#endif
/* Audio I/O core (pars additional S/PDIF TX Core) */
{
thread_speed();
#if (MIXER)
#define AUDIO_CHANNEL c_mix_out
#else
#define AUDIO_CHANNEL c_aud_in
#endif
XUA_AudioHub(AUDIO_CHANNEL, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
, c_spdif_tx
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
, c_dig_rx
#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)
, dfuInterface
#endif
#if (XUA_NUM_PDM_MICS > 0)
, c_pdm_pcm
#endif
);
}
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
{
/* ClockGen must currently run on same tile as AudioHub due to shared memory buffer
* However, due to the use of an interface the pll reference signal port can be on another tile
*/
thread_speed();
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
} // par
}
#ifndef USER_MAIN_DECLARATIONS
#define USER_MAIN_DECLARATIONS
#endif
#ifndef USER_MAIN_CORES
#define USER_MAIN_CORES
#endif
/* Main for USB Audio Applications */
int main()
{
#if !XUA_USB_EN
#define c_mix_out null
#else
chan c_mix_out;
#endif
#ifdef MIDI
chan c_midi;
#endif
#ifdef IAP
chan c_iap;
#ifdef IAP_EA_NATIVE_TRANS
chan c_ea_data;
#endif
#endif
#if (MIXER)
chan c_mix_ctl;
#endif
#if (XUA_SPDIF_RX_EN)
streaming chan c_spdif_rx;
#else
#define c_spdif_rx null
#endif
#if (XUA_ADAT_RX_EN)
streaming chan c_adat_rx;
#else
#define c_adat_rx null
#endif
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
chan c_spdif_tx;
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
chan c_clk_ctl;
chan c_clk_int;
#else
#define c_clk_int null
#define c_clk_ctl null
#endif
#if (XUA_DFU_EN == 1)
interface i_dfu dfuInterface;
#else
#define dfuInterface null
#endif
#if (XUA_NUM_PDM_MICS > 0)
chan c_pdm_pcm;
#endif
#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;
#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_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
chan c_xud_in[ENDPOINT_COUNT_IN];
/* Used to communicate controls/setting from XUA_Endpoint0() to the Audio/Buffering sub-system */
chan c_aud_ctl;
#if (!MIXER)
#define c_mix_ctl null
#endif
#ifdef IAP_EA_NATIVE_TRANS
chan c_EANativeTransport_ctrl;
#else
#define c_EANativeTransport_ctrl null
#endif
//#if (HID_CONTROLS > 0)
// chan c_hid;
//#endif
USER_MAIN_DECLARATIONS
par
{
USER_MAIN_CORES
#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);
#endif
on tile[XUD_TILE]:
par
{
#if XUA_USB_EN
#if ((XUD_TILE == 0) && (XUA_DFU_EN == 1))
/* Check if USB is on the flash tile (tile 0) */
/* Expect to be distrbuted into XUA_Endpoint0() */
[[distribute]]
DFUHandler(dfuInterface, null);
#endif
/* Core USB task, buffering, USB etc */
{
#ifdef XUD_PRIORITY_HIGH
set_core_high_priority_on();
#endif
/* Run UAC2.0 at high-speed, UAC1.0 at full-speed */
unsigned usbSpeed = (AUDIO_CLASS == 2) ? XUD_SPEED_HS : XUD_SPEED_FS;
unsigned xudPwrCfg = (XUA_POWERMODE == XUA_POWERMODE_SELF) ? XUD_PWR_SELF : XUD_PWR_BUS;
/* USB interface core */
XUD_Main(c_xud_out, ENDPOINT_COUNT_OUT, c_xud_in, ENDPOINT_COUNT_IN,
c_sof, epTypeTableOut, epTypeTableIn, usbSpeed, xudPwrCfg);
}
#if (NUM_USB_CHAN_OUT > 0) || (NUM_USB_CHAN_IN > 0) || XUA_HID_ENABLED || defined(MIDI)
/* Core USB audio task, buffering, USB etc */
{
unsigned x;
thread_speed();
/* Attach mclk count port to mclk clock-block (for feedback) */
//set_port_clock(p_for_mclk_count, clk_audio_mclk);
#if(AUDIO_IO_TILE != XUD_TILE)
set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb);
set_port_clock(p_for_mclk_count, clk_audio_mclk_usb);
start_clock(clk_audio_mclk_usb);
#else
/* Clock port from same clock-block as I2S */
/* TODO remove asm() */
asm("ldw %0, dp[clk_audio_mclk]":"=r"(x));
asm("setclk res[%0], %1"::"r"(p_for_mclk_count), "r"(x));
#endif
/* Endpoint & audio buffering cores - buffers all EP's other than 0 */
XUA_Buffer(
#if (NUM_USB_CHAN_OUT > 0)
c_xud_out[ENDPOINT_NUMBER_OUT_AUDIO], /* Audio Out*/
#endif
#if (NUM_USB_CHAN_IN > 0)
c_xud_in[ENDPOINT_NUMBER_IN_AUDIO], /* Audio In */
#endif
#if (NUM_USB_CHAN_OUT > 0) && ((NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP))
c_xud_in[ENDPOINT_NUMBER_IN_FEEDBACK], /* Audio FB */
#endif
#ifdef MIDI
c_xud_out[ENDPOINT_NUMBER_OUT_MIDI], /* MIDI Out */ // 2
c_xud_in[ENDPOINT_NUMBER_IN_MIDI], /* MIDI In */ // 4
c_midi,
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
/* Audio Interrupt - only used for interrupts on external clock change */
c_xud_in[ENDPOINT_NUMBER_IN_INTERRUPT],
c_clk_int,
#endif
c_sof, c_aud_ctl, p_for_mclk_count
#if (XUA_HID_ENABLED)
, c_xud_in[ENDPOINT_NUMBER_IN_HID]
#endif
, c_mix_out
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
, c_audio_rate_change
#if (!XUA_USE_SW_PLL)
, i_pll_ref
#else
, c_sw_pll
#endif
#endif
);
//:
}
#endif
/* Endpoint 0 Core */
{
thread_speed();
#if (USE_EX3D == 1) && (HID_CONTROLS > 0)
XUA_Endpoint0( c_xud_out[0], c_xud_in[0], c_hidRcvData, c_aud_ctl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_);
#else
XUA_Endpoint0( c_xud_out[0], c_xud_in[0], c_aud_ctl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_);
#endif
}
#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]:
{
/* Audio I/O task, includes mixing etc */
usb_audio_io(
#if (NUM_USB_CHAN_OUT > 0) || (NUM_USB_CHAN_IN > 0)
/* Connect audio system to XUA_Buffer(); */
c_mix_out
#else
/* Connect to XUA_Endpoint0() */
c_aud_ctl
#endif
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
, c_spdif_tx
#endif
#if (MIXER)
, c_mix_ctl
#endif
, c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int
#if (XUD_TILE != 0) && (AUDIO_IO_TILE == 0) && (XUA_DFU_EN == 1)
, dfuInterface
#endif
#if (XUA_NUM_PDM_MICS > 0)
, c_pdm_pcm
#endif
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
, 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
);
}
//:
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
on tile[SPDIF_TX_TILE]:
{
thread_speed();
SpdifTxWrapper(c_spdif_tx);
}
#endif
#if defined(MIDI) && defined(IAP) && (IAP_TILE == MIDI_TILE)
/* MIDI and IAP share a core */
on tile[IAP_TILE]:
{
thread_speed();
usb_midi(p_midi_rx, p_midi_tx, clk_midi, c_midi, 0, c_iap, null, null, null);
}
#else
#if defined(MIDI)
/* MIDI core */
on tile[MIDI_TILE]:
{
thread_speed();
usb_midi(p_midi_rx, p_midi_tx, clk_midi, c_midi, 0);
}
#endif
#if defined(IAP)
on tile[IAP_TILE]:
{
thread_speed();
iAP(c_iap, null, null, null);
}
#endif
#endif
#if (XUA_SPDIF_RX_EN)
on tile[XUD_TILE]:
{
thread_speed();
spdif_rx(c_spdif_rx, p_spdif_rx, clk_spd_rx, 192000);
}
#endif
#if (XUA_ADAT_RX_EN)
on stdcore[XUD_TILE] :
{
set_thread_fast_mode_on();
while (1)
{
adatReceiver48000(p_adat_rx, c_adat_rx);
adatReceiver44100(p_adat_rx, c_adat_rx);
}
}
#endif
#if XUA_USB_EN
#if (XUD_TILE != 0) && (AUDIO_IO_TILE != 0) && (XUA_DFU_EN == 1)
/* Run flash code on its own - hope it gets combined */
//#warning Running DFU flash code on its own
on stdcore[0]: DFUHandler(dfuInterface, null);
#endif
#endif
#if (XUA_NUM_PDM_MICS > 0)
/* PDM Mics running on a separate to AudioHub */
on stdcore[PDM_TILE]:
{
mic_array_task(c_mic_pcm);
}
#endif /*XUA_NUM_PDM_MICS > 0*/
}
return 0;
}
#endif

View File

@@ -0,0 +1,98 @@
/*
*
* nau88c22.h
*
*/
#ifndef NAU88C22_H_
#define NAU88C22_H_
uint16_t nau88c22_registers[][4] = {
{0x00, 0x00, 0x00, 0x00},
{0x00, 0x01, 0x0D, 0xFF},
{0x00, 0x03, 0x20, 0x50},
{0x00, 0x04, 0x00, 0x00},
{0x00, 0x05, 0x00, 0xBC},
{0x00, 0x06, 0x00, 0x08},
{0x00, 0x07, 0x00, 0x10},
{0x00, 0x08, 0x40, 0x00},
{0x00, 0x09, 0x69, 0x00},
{0x00, 0x0A, 0x00, 0x31},
{0x00, 0x0B, 0x26, 0xE9},
{0x00, 0x0D, 0xC0, 0x00},
{0x00, 0x0F, 0x00, 0x00},
{0x00, 0x10, 0x00, 0x00},
{0x00, 0x11, 0x00, 0x00},
{0x00, 0x12, 0xFF, 0xFF},
{0x00, 0x13, 0x00, 0x00},
{0x00, 0x1A, 0x00, 0x00},
{0x00, 0x1B, 0x00, 0x00},
{0x00, 0x1C, 0x00, 0x0E},
{0x00, 0x1D, 0x20, 0x02},
{0x00, 0x1E, 0x00, 0x00},
{0x00, 0x1F, 0x00, 0x00},
{0x00, 0x21, 0x00, 0x00},
{0x00, 0x22, 0x00, 0x00},
{0x00, 0x23, 0x00, 0x00},
{0x00, 0x24, 0x00, 0x00},
{0x00, 0x25, 0x00, 0x00},
{0x00, 0x26, 0x00, 0x00},
{0x00, 0x27, 0x00, 0x00},
{0x00, 0x28, 0x00, 0x00},
{0x00, 0x29, 0x00, 0x00},
{0x00, 0x2A, 0x00, 0x00},
{0x00, 0x2B, 0x40, 0x02}, // ADC Right Channel Source Select, bit 3, set to 1, 3rd byte 0x40 = Latch left channel analog data input into the right channel filter
{0x00, 0x2C, 0x00, 0x82},
{0x00, 0x2D, 0x00, 0x00},
{0x00, 0x2F, 0x00, 0x00},
{0x00, 0x30, 0x00, 0x40},
{0x00, 0x31, 0x00, 0x00},
{0x00, 0x32, 0x00, 0x00},
{0x00, 0x34, 0xCF, 0xCF},
{0x00, 0x35, 0xCF, 0xCF},
{0x00, 0x36, 0x14, 0x86},
{0x00, 0x37, 0x0F, 0x12},
{0x00, 0x38, 0x25, 0xFF},
{0x00, 0x39, 0x34, 0x57},
{0x00, 0x3A, 0x14, 0x86},
{0x00, 0x3B, 0x0F, 0x12},
{0x00, 0x3C, 0x25, 0xF9},
{0x00, 0x3D, 0x34, 0x57},
{0x00, 0x41, 0x00, 0x00},
{0x00, 0x42, 0x00, 0x00},
{0x00, 0x43, 0x00, 0x00},
{0x00, 0x44, 0x00, 0x00},
{0x00, 0x45, 0x00, 0x00},
{0x00, 0x46, 0x00, 0x00},
{0x00, 0x47, 0x00, 0x00},
{0x00, 0x48, 0x00, 0x00},
{0x00, 0x49, 0x00, 0x00},
{0x00, 0x4A, 0x00, 0x00},
{0x00, 0x4B, 0x20, 0x07},
{0x00, 0x4C, 0x00, 0x00},
{0x00, 0x4D, 0x00, 0x00},
{0x00, 0x53, 0x02, 0x78},
{0x00, 0x54, 0x00, 0x02},
{0x00, 0x55, 0x00, 0x00},
{0x00, 0x58, 0x1B, 0x22},
{0x00, 0x59, 0x20, 0x00},
{0x00, 0x66, 0x00, 0x60},
{0x00, 0x68, 0x00, 0x00},
{0x00, 0x69, 0x00, 0x00},
{0x00, 0x6A, 0x10, 0x03},
{0x00, 0x6B, 0x00, 0x00},
{0x00, 0x71, 0x00, 0x11},
{0x00, 0x72, 0x04, 0x70},
{0x00, 0x73, 0x33, 0x08},
{0x00, 0x74, 0x15, 0x06},
{0x00, 0x76, 0x31, 0x40},
{0x00, 0x77, 0x00, 0x12},
{0x00, 0x7E, 0x01, 0x01},
{0x00, 0x7F, 0xC0, 0x3F},
{0x00, 0x80, 0x07, 0x20},
{0x00, 0x81, 0x00, 0x08},
{0x00, 0x82, 0x00, 0x60},
};
#endif

View File

@@ -0,0 +1,652 @@
#define DEBUG_PRINT_ENABLE 0
#include <stdint.h>
#include "debug_print.h"
#include <quadflashlib.h>
#include <xcore/chanend.h>
#include <xcore/channel.h>
#include "xua_conf.h"
#define WRITE_ENABLE_COMMAND (0x06)
#define WRITE_DISABLE_COMMAND (0x04)
#define ERASE_CHIP_COMMAND (0xC7)
#define READ_STATUS_REG_COMMAND (0x05)
#define READ_ID_COMMAND (0x9F)
#define READ_UID_COMMAND (0x4B)
#define WRITE_ENABLE_STATUS_COMMAND (0x50)
#define WRITE_STATUS_REG1_COMMAND (0x01)
#define READ_STATUS_REG2_COMMAND (0x35)
#define WRITE_STATUS_REG2_COMMAND (0x31)
#define READ_STATUS_REG3_COMMAND (0x15)
#define WRITE_STATUS_REG3_COMMAND (0x11)
#define RDSTATUS_COMMAND (0x35)
#define WRSTATUS_COMMAND (0x31)
#define PRSCUR_COMMAND (0x42)
#define ERSCUR_COMMAND (0x44)
#define RDSCUR_COMMAND (0x48)
#define HMAC_LEN 60
#define HMAC_GEN_LEN 20
extern unsigned short XUA_Endpoint0_getProductId();
extern unsigned short XUA_Endpoint0_getVendorId();
unsigned char hid_reply[64] = {0};
#if 0
void printArrayHex1(uint8_t array[], int size, int elementsPerLine) {
for (int i = 0; i < size; i++) {
printf("0x%x, ", array[i]);
// 在达到每行元素个数时换行
if ((i + 1) % elementsPerLine == 0) {
printf("\n");
}
}
printf("\n");
}
#endif
#define settw(a,b) {__asm__ __volatile__("settw res[%0], %1": : "r" (a) , "r" (b));}
#define setc(a,b) {__asm__ __volatile__("setc res[%0], %1": : "r" (a) , "r" (b));}
#define setclk(a,b) {__asm__ __volatile__("setclk res[%0], %1": : "r" (a) , "r" (b));}
#define portin(a,b) {__asm__ __volatile__("in %0, res[%1]": "=r" (b) : "r" (a));}
#define portout(a,b) {__asm__ __volatile__("out res[%0], %1": : "r" (a) , "r" (b));}
#ifdef DFU_FLASH_DEVICE
#if (XUA_QUAD_SPI_FLASH)
/* Using specified flash device rather than all supported in tools */
fl_QuadDeviceSpec opt_flash_devices[] = {DFU_FLASH_DEVICE};
#else
/* Using specified flash device rather than all supported in tools */
fl_DeviceSpec opt_flash_devices[] = {DFU_FLASH_DEVICE};
#endif
#endif
/*
typedef struct {
out port qspiCS;
out port qspiSCLK;
out buffered port:32 qspiSIO;
clock qspiClkblk;
} fl_QSPIPorts;
*/
fl_QSPIPorts p_opt_qflash_tile0 =
{
XS1_PORT_1B,
XS1_PORT_1C,
XS1_PORT_4B,
XS1_CLKBLK_1
};
fl_QSPIPorts p_opt_qflash_tile1 =
{
XS1_PORT_1F,
XS1_PORT_1G,
XS1_PORT_4D,
XS1_CLKBLK_1
};
#define KEY_ADDRESS 0xFFFD0
/* Store Flag to fixed address */
static void SetKeyFlag(unsigned x)
{
asm volatile("stw %0, %1[0]" :: "r"(x), "r"(KEY_ADDRESS));
}
/* Load flag from fixed address */
unsigned GetKeyFlag()
{
unsigned x;
asm volatile("ldw %0, %1[0]" : "=r"(x) : "r"(KEY_ADDRESS));
return x;
}
/* return 1 for opened ports successfully */
int flash_opt_enable_ports(fl_QSPIPorts *p_qflash)
{
int result = 0;
#ifdef DFU_FLASH_DEVICE
result = fl_connectToDevice(p_qflash, opt_flash_devices, sizeof(opt_flash_devices) / sizeof(fl_QuadDeviceSpec));
#else
/* Use default flash list */
result = fl_connect(p_qflash);
#endif
if (!result)
{
/* All okay.. */
return 1;
}
else
{
return 0;
}
}
int flash_opt_disable_ports()
{
fl_disconnect();
return 1;
}
void flash_cmd_opt(unsigned int cmd,
unsigned char input[], unsigned int num_in,
unsigned char output[], unsigned int num_out)
{
debug_printf("flash_cmd_opt: cmd = %02x, num_in = %d, num_out = %d\n", cmd, num_in, num_out);
for (size_t i = 0; i < num_in; i++)
{
debug_printf("input[%d] = %02x\n", i, input[i]);
}
for (size_t i = 0; i < num_out; i++)
{
debug_printf("output[%d] = %02x\n", i, output[i]);
}
fl_command(cmd,input,num_in,output, num_out);
}
void flash_opt_erase()
{
uint8_t cmd[4] = {0, 0x10, 0x0, 0};
uint8_t data[4] = {0, 0x10, 0x0, 0};
flash_cmd_opt(WRITE_ENABLE_COMMAND, cmd, 0, data, 0);
delay_milliseconds(1);
flash_cmd_opt(ERSCUR_COMMAND, cmd, 3, data, 0);
delay_milliseconds(50);
}
void flash_opt_read_did(uint8_t data[], unsigned char len)
{
uint8_t cmd[3] = {0x3, 0x10, 0x0};
flash_cmd_opt(READ_ID_COMMAND, cmd, 0, data, len);
// printArrayHex1(data, len, 20);
}
void flash_opt_unlock(void)
{
uint8_t cmd[1] = {0};
uint8_t data[1] = {0};
uint8_t sr1, sr2, sr3;
uint8_t did[3];
/* Reason: 使用 tile0 端口连接 Flash保持原有逻辑 */
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0) {
debug_printf("flash_opt_unlock failed\n");
return;
}
/* Reason: 增加 Flash 厂商ID检查仅针对 Winbond (0xEF) 执行特定解锁逻辑 */
flash_opt_read_did(did, 3);
if (did[0] != 0xEF)
{
debug_printf("Not Winbond flash (DID: %02x), skip unlock\n", did[0]);
flash_opt_disable_ports();
return;
}
debug_printf("Unlock Winbond Flash...\n");
/* Reason: 解锁 Status Register 1。
参考 flash_api_ext.c 逻辑,清除 Bit 2-6 (BP0-BP4, TB, SEC)
Mask: 0x7C (0111 1100) */
flash_cmd_opt(READ_STATUS_REG_COMMAND, cmd, 0, data, 1);
sr1 = data[0];
if (sr1 & 0x7C)
{
debug_printf("Unlock SR1: %02x -> %02x\n", sr1, sr1 & ~0x7C);
flash_cmd_opt(WRITE_ENABLE_STATUS_COMMAND, cmd, 0, data, 0);
data[0] = sr1 & ~0x7C;
flash_cmd_opt(WRITE_STATUS_REG1_COMMAND, data, 1, cmd, 0);
delay_milliseconds(10); /* 等待写入完成 */
}
/* Reason: 解锁 Status Register 2。
参考 flash_api_ext.c 逻辑,清除 Bit 6 (CMP)
Mask: 0x40 (0100 0000) */
flash_cmd_opt(READ_STATUS_REG2_COMMAND, cmd, 0, data, 1);
sr2 = data[0];
if ((sr2 & 0x40) || ((sr2 & 0x2) == 0))
{
debug_printf("Unlock SR2: %02x -> %02x\n", sr2, (sr2 & ~0x40) | 0x2);
flash_cmd_opt(WRITE_ENABLE_STATUS_COMMAND, cmd, 0, data, 0);
data[0] = (sr2 & ~0x40) | 0x2;
flash_cmd_opt(WRITE_STATUS_REG2_COMMAND, data, 1, cmd, 0);
delay_milliseconds(10);
}
/* Reason: 解锁 Status Register 3。
参考 flash_api_ext.c 逻辑,清除 Bit 2 (WPS)
Mask: 0x04 (0000 0100) */
flash_cmd_opt(READ_STATUS_REG3_COMMAND, cmd, 0, data, 1);
sr3 = data[0];
if (sr3 & 0x04)
{
debug_printf("Unlock SR3: %02x -> %02x\n", sr3, sr3 & ~0x04);
flash_cmd_opt(WRITE_ENABLE_STATUS_COMMAND, cmd, 0, data, 0);
data[0] = sr3 & ~0x04;
flash_cmd_opt(WRITE_STATUS_REG3_COMMAND, data, 1, cmd, 0);
delay_milliseconds(10);
}
flash_opt_disable_ports();
debug_printf("Unlock Winbond Flash done\n");
}
void flash_opt_write2(uint8_t data[], unsigned char len)
{
uint8_t d[1];
uint8_t cmd[256] = {0, 0x10, 0x0};
for (int i = 0; i < len; i++)
{
cmd[i + 3] = data[i];
}
flash_opt_erase();
flash_cmd_opt(WRITE_ENABLE_COMMAND, cmd, 0, d, 0);
flash_cmd_opt(PRSCUR_COMMAND, cmd, 3 + len, d, 0);
delay_milliseconds(50);
}
void flash_opt_read(uint8_t data[], unsigned char len)
{
uint8_t cmd[3] = {0x00, 0x10, 0x00};
flash_cmd_opt(RDSCUR_COMMAND, cmd, 3, data, len);
//printf("read sec key:\n");
//printArrayHex1(data, len, 20);
}
void flash_opt_read_uid(uint8_t data[], unsigned char len)
{
uint8_t cmd[3] = {0x3, 0x10, 0x0};
flash_cmd_opt(READ_UID_COMMAND, cmd, 0, data, len);
// printArrayHex1(data, len, 20);
}
unsigned compare_buff_diff(const uint8_t* actual, const uint8_t* expected, unsigned len)
{
for (int i = 0; i < len; ++i)
{
if (actual[i] != expected[i])
{
debug_printf("compare_buff_diff: %d %02x %02x\n", i, actual[i], expected[i]);
return 0;
}
}
return 1;
}
extern void hmac_sha1(const unsigned char *, unsigned long, const unsigned char * , unsigned long, unsigned char * );
void cal_hmac(uint8_t uid[], uint8_t did[], uint8_t hmac_bin[])
{
{
uint8_t key_bin[HMAC_GEN_LEN] = {0x76, 0x37, 0x0b, 0xb8, 0xbd, 0xe5, 0x54, 0x82, 0x8f, 0x13, 0x29, 0xa6, 0x26, 0x07, 0x2d, 0xe1, 0x11, 0x6c, 0xfb, 0x07};
uint8_t msg_bin[HMAC_GEN_LEN];
for (int i = 0; i < 3; i++)
{
msg_bin[i] = did[i];
}
for (int i = 3; i < 20; i++)
{
msg_bin[i] = uid[i];
}
#if 0
printf("msg_bin: \n");
printArrayHex1(msg_bin, HMAC_GEN_LEN, 20);
#endif
hmac_sha1(key_bin, HMAC_GEN_LEN, msg_bin, HMAC_GEN_LEN, hmac_bin);
#if 0
printf("hmac_bin: \n");
printArrayHex1(hmac_bin, HMAC_LEN, 20);
#endif
}
}
uint8_t key_verify_old(unsigned sec_write, uint8_t expected_bin[], unsigned offset)
{
uint8_t read_bin[HMAC_LEN + 1];
uint8_t comp_bin[HMAC_LEN + 1];
uint8_t uid[20];
uint8_t did[4];
uint8_t ret = 0;
uint8_t hmac_bin[20];
flash_opt_read(read_bin, HMAC_LEN + 1);
flash_opt_read_uid(uid, 20);
flash_opt_read_did(did, 3);
cal_hmac(uid, did, hmac_bin);
if (sec_write)
{
if (offset == 0)
{
for (int i = 0; i < 20; i++)
{
read_bin[i + 1] = expected_bin[i];
}
}
else if (offset == 1)
{
for (int i = 0; i < 20; i++)
{
read_bin[i + 21] = expected_bin[i];
}
}
flash_opt_write2(&read_bin[1], HMAC_LEN);
delay_milliseconds(10);
flash_opt_read(comp_bin, HMAC_LEN + 1);
if (compare_buff_diff(&comp_bin[1], &read_bin[1], HMAC_LEN) == 1)
{
debug_printf("compare OK\n");
ret = 1;
}
}
else
{
if (offset == 0)
{
flash_opt_read(read_bin, HMAC_LEN + 1);
if (compare_buff_diff(hmac_bin, &read_bin[1], 20) == 1)
{
debug_printf("key_verified\n");
ret = 1;
}
}
else if (offset == 1)
{
flash_opt_read(read_bin, HMAC_LEN + 1);
if (compare_buff_diff(hmac_bin, &read_bin[21], 20) == 1)
{
debug_printf("key_verified\n");
ret = 1;
}
}
}
return ret;
}
void flash_read_uid(uint8_t *uid)
{
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
return;
}
flash_opt_read_uid(uid, 20);
flash_opt_disable_ports();
}
void flash_read_did(uint8_t *did)
{
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
return;
}
flash_opt_read_did(did, 3);
flash_opt_disable_ports();
}
void get_key_ret(uint8_t *buffer)
{
//printf("get_key_ret2\n");
for (int i = 0; i < 64; i ++)
{
buffer[i] = hid_reply[i];
hid_reply[i] = 0;
}
//printArrayHex1(buffer, 20, 20);
}
unsigned char g_hid_pass_data[64];
extern void hidSetChangePending(unsigned int);
void user_read_hidpass(unsigned char * hidPassData)
{
int i = 0;
for (i = 0; i < 64; i++)
{
hidPassData[i] = g_hid_pass_data[i];
debug_printf("hidPassData[%d] = %02x\n", i, hidPassData[i]);
g_hid_pass_data[i] = 0;
}
}
void user_set_hidpass(unsigned char *data)
{
#if HID_CONTROLS
for (int i = 0; i < 63; i++)
{
g_hid_pass_data[i] = data[i];
debug_printf("g_hid_pass_data[%d] = %02x\n", i, g_hid_pass_data[i]);
}
hidSetChangePending(0x1);
#endif
}
static chanend_t g_flash_opt_c;
void flash_opt_set_chan(chanend_t c) {
g_flash_opt_c = c;
//debug_printf("flash_opt_set_chan\n");
}
void flash_opt_exchange_buffer(uint8_t in[64], uint8_t out[64]) {
//debug_printf("flash_opt_exchange_buffer\n");
chan_out_buf_byte (g_flash_opt_c , in, 40) ;
//debug_printf("flash_opt_exchange_buffer1\n");
chan_in_buf_byte(g_flash_opt_c, out, 40);
}
void flash_opt_key(chanend_t c) {
uint8_t buffer[64], reply[40] = {0, 0, 0, 0};
uint32_t ret;
delay_milliseconds(2);
while (1) {
chan_in_buf_byte(c, buffer, 40);
if (flash_opt_enable_ports(&p_opt_qflash_tile1) == 0) {
reply[0] = 0;
}
else
{
switch (buffer[3])
{
case 9:
flash_opt_read_did(&reply[1], 3);
reply[0] = 0x55;
break;
case 10:
flash_opt_read_uid(&reply[1], 21);
reply[0] = 0x55;
break;
case 8:
ret = key_verify_old(1, &buffer[4], 0);
if (ret == 1)
{
debug_printf("write key ret 0x55\n");
reply[0] = 0x55;
}
else
{
reply[0] = 0;
}
break;
}
flash_opt_disable_ports();
chan_out_buf_byte(c, reply, 40) ;
}
}
}
uint8_t key_validate(void)
{
uint8_t ret = 0;
uint8_t data[1] = {0};
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
return 0;
}
ret = key_verify_old(0, data, 0);
if (ret == 1)
{
SetKeyFlag(0x20241224);
}
ret = key_verify_old(0, data, 1);
if (ret == 1)
{
SetKeyFlag(0x20241224);
}
flash_opt_disable_ports();
return ret;
}
void program_key(uint8_t *buffer, int datalength)
{
if (buffer[0] == 0x77 && buffer[1] == 0x5B)
{
uint8_t ret = 0;
switch (buffer[2])
{
case 1:
debug_printf("verify key\n");
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
uint8_t data[1] = {0};
ret = key_verify_old(0, data, 0);
if (ret == 1)
{
hid_reply[0] = 0x55;
}
else
{
hid_reply[0] = 0;
}
flash_opt_disable_ports();
}
break;
case 2:
debug_printf("write key\n");
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
ret = key_verify_old(1, &buffer[3], 0);
debug_printf("write key ret %d\n", ret);
if (ret == 1)
{
hid_reply[0] = 0x55;
}
else
{
hid_reply[0] = 0;
}
flash_opt_disable_ports();
}
break;
case 3:
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
flash_opt_read_did(&hid_reply[1], 3);
debug_printf("return did\n");
hid_reply[0] = 0x55;
flash_opt_disable_ports();
}
break;
case 4:
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
debug_printf("return uid\n");
flash_opt_read_uid(&hid_reply[1], 21);
hid_reply[0] = 0x55;
flash_opt_disable_ports();
}
break;
case 5:
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
debug_printf("erase key\n");
flash_opt_erase();
hid_reply[0] = 0x55;
flash_opt_disable_ports();
}
break;
case 6:
debug_printf("get pid vid\n");
unsigned short pid = XUA_Endpoint0_getProductId();
unsigned short vid = XUA_Endpoint0_getVendorId();
hid_reply[2] = (pid >> 8) & 0xff;
hid_reply[1] = pid & 0xff;
hid_reply[4] = (vid >> 8) & 0xff;
hid_reply[3] = vid & 0xff;
hid_reply[0] = 0x55;
break;
case 7:
break;
case 8:
case 9:
case 10:
//flash_opt_exchange_buffer(buffer, hid_reply);
// debug_printf("write aizip key tile 0 %02x\n", hid_reply[0]);
for (int i = 0; i < datalength; i++)
hid_reply[i] = 0;
break;
}
}
else
{
//xmos_printf(&buffer[1], datalength - 1);
}
}

View File

@@ -0,0 +1,95 @@
#include "share_buffer.h"
#define RING_BUFFER_SIZE 512
typedef struct {
int buffer[RING_BUFFER_SIZE];
int head;
int tail;
int count;
} RingBuffer;
// 两路环形缓冲区
RingBuffer ring_buffers[4];
// 初始化环形缓冲区
void init_ring_buffer(int channel) {
if (channel < 0 || channel > 1) return;
ring_buffers[channel].head = 0;
ring_buffers[channel].tail = 0;
ring_buffers[channel].count = 0;
}
// 初始化所有环形缓冲区
void init_all_ring_buffers() {
init_ring_buffer(0);
init_ring_buffer(1);
}
// 判断环形缓冲区是否为空
int is_ring_buffer_empty(int channel) {
if (channel < 0 || channel > 3) return 1;
return (ring_buffers[channel].count == 0);
}
// 判断环形缓冲区是否已满
int is_ring_buffer_full(int channel) {
if (channel < 0 || channel > 3) return 0;
return (ring_buffers[channel].count == RING_BUFFER_SIZE);
}
// 获取环形缓冲区中的数据数量
int get_ring_buffer_count(int channel) {
if (channel < 0 || channel > 3) return 0;
return ring_buffers[channel].count;
}
// 向环形缓冲区写入数据
int write_to_ring_buffer(int channel, int value) {
if (channel < 0 || channel > 3) return -1;
if (is_ring_buffer_full(channel)) {
return -1; // 缓冲区已满
}
ring_buffers[channel].buffer[ring_buffers[channel].head] = value;
ring_buffers[channel].head = (ring_buffers[channel].head + 1) % RING_BUFFER_SIZE;
ring_buffers[channel].count++;
return 0; // 写入成功
}
// 从环形缓冲区读取数据
int read_from_ring_buffer(int channel) {
int value = 0;
if (channel == 0 || channel == 1 || channel == 2 || channel == 3) {
if (is_ring_buffer_empty(channel)) {
return 0;
}
value = ring_buffers[channel].buffer[ring_buffers[channel].tail];
ring_buffers[channel].tail = (ring_buffers[channel].tail + 1) % RING_BUFFER_SIZE;
ring_buffers[channel].count--;
}
return value;
}
// 清空环形缓冲区
void clear_ring_buffer(int channel) {
if (channel < 0 || channel > 3) return;
ring_buffers[channel].head = 0;
ring_buffers[channel].tail = 0;
ring_buffers[channel].count = 0;
}
// 清空所有环形缓冲区
void clear_all_ring_buffers() {
clear_ring_buffer(0);
clear_ring_buffer(1);
clear_ring_buffer(2);
clear_ring_buffer(3);
}

View File

@@ -0,0 +1,10 @@
void init_ring_buffer(int channel);
void init_all_ring_buffers();
int is_ring_buffer_empty(int channel);
int is_ring_buffer_full(int channel);
int get_ring_buffer_count(int channel);
int write_to_ring_buffer(int channel, int value);
int read_from_ring_buffer(int channel);
void clear_ring_buffer(int channel);
void clear_all_ring_buffers();

View File

@@ -0,0 +1,233 @@
#if UART_DEBUG || DEBUG_MEMORY_LOG_ENABLED
#define DEBUG_PRINT_ENABLE 1
#endif
#include <stdio.h>
#include <stdint.h>
#include "user_func.h"
#include "lfs_io.h"
#include "debug_print.h"
ProductInfo productInfo;
AppConfigs appPowerOnConf, appRunningState, appUserConf;
AudioMode appAudioMode;
#define PRODUCT_INFO_PATH "product_info"
#define POWERON_INFO_PATH "poweron_info"
uint32_t calculate_crc32(uint8_t *buf, int len) {
uint32_t crc = 0xFFFFFFFF;
uint32_t poly = 0xEDB88320;
for (int i = 0; i < len; i++) {
crc ^= (uint32_t)buf[i];
for (int j = 8; j > 0; j--) {
if (crc & 1) {
crc = (crc >> 1) ^ poly;
} else {
crc >>= 1;
}
}
}
return ~crc;
}
unsigned char check_sum(unsigned char *pbuf, unsigned len)
{
unsigned char i;
unsigned short sum;
sum = 0;
for(i = 0; i < len; i++)
{
sum += pbuf[i];
}
i = sum % 256;
return i;
}
uint32_t get_reference_time();
void load_configs(void)
{
//uint32_t t = get_reference_time();
if (lfs_init() == 0)
{
lfs_read_config(PRODUCT_INFO_PATH, (unsigned char*) &productInfo, sizeof(productInfo));
lfs_read_config(POWERON_INFO_PATH, (unsigned char*) &appPowerOnConf, sizeof(appPowerOnConf));
//printf("load configs\n");
// printf("load pid 0x%04x vid 0x%04x\n", productInfo.pid2, productInfo.vid2);
}
lfs_deinit();
//printf("bytes read time %lu\n", get_reference_time() - t);
}
void save_configs(unsigned char save)
{
if (save != 0)
{
//uint32_t t = get_reference_time();
if (lfs_init() == 0)
{
if (save & 0x1)
lfs_write_config(PRODUCT_INFO_PATH, (unsigned char*) &productInfo, sizeof(productInfo));
if (save & 0x2)
lfs_write_config(POWERON_INFO_PATH, (unsigned char*) &appPowerOnConf, sizeof(appPowerOnConf));
}
//printf("save ... pid 0x%04x vid 0x%04x\n", productInfo.pid2, productInfo.vid2);
lfs_deinit();
//printf("bytes write time %lu\n", get_reference_time() - t);
}
}
void save_value(unsigned char *path, unsigned char value)
{
//uint32_t t = get_reference_time();
if (lfs_init() == 0)
{
lfs_write_config(path, (unsigned char*) &value, sizeof(value));
}
lfs_deinit();
}
unsigned char load_value(unsigned char *path)
{
unsigned char value = 255;
if (lfs_init() == 0)
{
lfs_read_config(path, (unsigned char*) &value, sizeof(value));
}
else
{
debug_printf("lfs_init failed\n");
}
lfs_deinit();
return value;
}
#if (NUM_USB_CHAN_OUT != 0) || (NUM_USB_CHAN_IN != 0)
unsigned short XUA_Endpoint0_getProductId();
unsigned short XUA_Endpoint0_getVendorId();
void XUA_Endpoint0_setProductId(unsigned short pid);
void XUA_Endpoint0_setVendorStr(char* vendor_str);
void XUA_Endpoint0_setProductStr(char* product_str);
void XUA_Endpoint0_setSerialStr(char* serial_str);
void XUA_Endpoint0_setVendorId(unsigned short vid);
void get_pid_vid()
{
unsigned crc;
if ((productInfo.vid1 != 0) || (productInfo.vid2 != 0)
|| (productInfo.pid1 != 0 ) || (productInfo.pid2 != 0))
{
unsigned char tmp[17];
crc = calculate_crc32((unsigned char *) &productInfo, sizeof(productInfo) - 4);
if (NTOHL(crc) == productInfo.crc || crc == productInfo.crc)
{
debug_printf("crc is correct\n");
#if (AUDIO_CLASS == 1)
{
XUA_Endpoint0_setProductId(NTOHS(productInfo.pid1));
XUA_Endpoint0_setVendorId(NTOHS(productInfo.vid1));
debug_printf(" pid %04x vid %04x\n", NTOHS(productInfo.pid1), NTOHS(productInfo.vid1));
}
#else
{
XUA_Endpoint0_setProductId(NTOHS(productInfo.pid2));
XUA_Endpoint0_setVendorId(NTOHS(productInfo.vid2));
debug_printf(" pid %04x vid %04x\n", NTOHS(productInfo.pid2), NTOHS(productInfo.vid2));
}
#endif
memcpy (tmp, productInfo.ManufactureName, 16);
tmp[16] = 0;
XUA_Endpoint0_setVendorStr(tmp);
memcpy (tmp, productInfo.ProductName, 16);
XUA_Endpoint0_setProductStr(tmp);
memcpy (tmp, productInfo.SerialNumber, 16);
XUA_Endpoint0_setSerialStr(tmp);
}
else
{
debug_printf("crc error %08x actual %08x\n", NTOHL(crc), productInfo.crc);
}
}
}
#endif
void fill_boot_cmd(unsigned char *buffer)
{
int count = 0;
unsigned short vid, pid;
buffer[count++] = 0;
if (productInfo.vid1 == 0 && productInfo.vid2 == 0
&& productInfo.pid1 == 0 && productInfo.pid2 == 0)
{
#if (NUM_USB_CHAN_OUT != 0) || (NUM_USB_CHAN_IN != 0)
pid = XUA_Endpoint0_getProductId();
vid = XUA_Endpoint0_getVendorId();
buffer[count++] = vid >> 8;
buffer[count++] = vid & 0xff;
buffer[count++] = pid >> 8;
buffer[count++] = pid & 0xff;
buffer[count++] = vid >> 8;
buffer[count++] = vid & 0xff;
buffer[count++] = pid >> 8;
buffer[count++] = pid & 0xff;
for(int i = 0; i < 8; i++)
buffer[count++] = 0;
#endif
}
else
{
buffer[count++] = productInfo.vid1 & 0xff;
buffer[count++] = productInfo.vid1 >> 8;
buffer[count++] = productInfo.pid1 & 0xff;
buffer[count++] = productInfo.pid1 >> 8;
buffer[count++] = productInfo.vid2 & 0xff;
buffer[count++] = productInfo.vid2 >> 8;
buffer[count++] = productInfo.pid2 & 0xff;
buffer[count++] = productInfo.pid2 >> 8;
buffer[count++] = productInfo.crc & 0xff;
buffer[count++] = (productInfo.crc >> 8) & 0xff;
buffer[count++] = (productInfo.crc >> 16) & 0xff;
buffer[count++] = (productInfo.crc >> 24) & 0xff;
buffer[count++] = appPowerOnConf.crc & 0xff;
buffer[count++] = (appPowerOnConf.crc >> 8) & 0xff;
buffer[count++] = (appPowerOnConf.crc >> 16) & 0xff;
buffer[count++] = (appPowerOnConf.crc >> 24) & 0xff;
}
}
void fill_finish_cmd(unsigned char *buffer)
{
memcpy(buffer, (unsigned char *)&appUserConf, sizeof(appUserConf));
}
void save_product_info(unsigned char *buffer)
{
memcpy((unsigned char *)&productInfo, buffer, sizeof(productInfo));
}
void save_powerup_info(unsigned char *buffer)
{
memcpy((unsigned char *)&appPowerOnConf, buffer, sizeof(appPowerOnConf));
}
void save_userconfig_info(unsigned char *buffer)
{
memcpy((unsigned char *)&appUserConf, buffer, sizeof(appUserConf));
}

View File

@@ -0,0 +1,52 @@
#ifndef _USER_FUNC_H_
#define _USER_FUNC_H_
#include <xs1.h>
#include <print.h>
#include <platform.h>
#include <xclib.h>
#include <xscope.h>
#include <assert.h>
#include "user_uart.h"
// 32-bit macros for converting between host and network byte order
#define HTONL(value) ( \
(((value) >> 24) & 0x000000FF) | \
(((value) >> 8) & 0x0000FF00) | \
(((value) << 8) & 0x00FF0000) | \
(((value) << 24) & 0xFF000000) \
)
#define NTOHL(value) HTONL(value) // Since the transformation is the same
// 16-bit macros for converting between host and network byte order
#define HTONS(value) ( \
(((value) >> 8) & 0x00FF) | \
(((value) << 8) & 0xFF00) \
)
#define NTOHS(value) HTONS(value) // Since the transformation is the same
#ifdef __XC__
uint32_t calculate_crc32(uint8_t *unsafe buf, int len);
unsigned char check_sum(uint8_t *unsafe pbuf, unsigned len);
void fill_boot_cmd(unsigned char *unsafe buffer);
void save_product_info(unsigned char *unsafe buffer);
void save_powerup_info(unsigned char *unsafe buffer);
void fill_finish_cmd(unsigned char *unsafe buffer);
void save_userconfig_info(unsigned char *unsafe buffer);
#else
uint32_t calculate_crc32(uint8_t *buf, int len);
unsigned char check_sum(uint8_t *pbuf, unsigned len);
void fill_boot_cmd(unsigned char *buffer);
void save_product_info(unsigned char *buffer);
void save_powerup_info(unsigned char *buffer);
void fill_finish_cmd(unsigned char *buffer);
void save_userconfig_info(unsigned char *buffer);
#endif
void load_configs(void);
void save_configs(unsigned char save);
void get_pid_vid();
#endif

View File

@@ -0,0 +1,134 @@
#ifndef _USER_MAIN_H_
#define _USER_MAIN_H_
#ifdef __XC__
#include "i2c.h"
#include <print.h>
#include <xs1.h>
#include <platform.h>
#include "DSBuild.h"
//extern unsafe client interface i2c_master_if i_i2c_client;
//extern unsafe client interface i2c_master_if i_i2c_client_t0;
extern void interface_saver(client interface i2c_master_if i);
extern void dsp_core0(void);
extern void board_setup();
extern void dsp_main (chanend c_data);
extern void SetEqDataChan (chanend c);
/* I2C interface ports */
extern port p_scl;
extern port p_sda;
extern int dsp_worker_tile(chanend c_dsp_to_ex3d, int worker_id);
//extern int dsp_worker_tile_1(chanend c_dsp_to_ex3d, int worker_id);
extern void ex3d_task();
extern void hid_button_task(chanend cc_mic_level, chanend c_hid, chanend c_hidSendData, chanend c_uac_vol);
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol);
extern void dnr_dsp_proc_task(void);
//XUA_DFU_EN do i need it?
// tile[0]
// 3 DSP processors
// XUD_Main
// Core USB audio task, buffering, USB etc
// Endpoint 0 Core
// i2c_master
// DFUHandler???
//IAP??
//tile[1]:
// ex3d
// hid + buttons
// 4 DSP processors
// usb_audio_io
//
extern unsafe chanend uc_dsp_to_ex3d[DSP_WORKER_COUNT];
extern unsafe chanend uc_dsp_to_dnr_t1;
extern unsafe chanend uc_key_to_ubm_t0;
extern unsafe chanend uc_audiohw;
extern void key_sender(chanend c_key);
extern void key_receiver(chanend c_key);
#if AIZIP_DNR == 1
#define USER_MAIN_DECLARATIONS \
chan c_dsp_to_ex3d[DSP_WORKER_COUNT]; \
chan cc_dsp_in; chan cc_dsp_eof; chan cc_mic_level; chan c;
#define USER_MAIN_CORES on tile[1]: {\
par\
{\
ex3d_task();\
par(int i=0;i<DSP_WORKER_COUNT;i++) dsp_worker_tile(c_dsp_to_ex3d[i], i);\
unsafe\
{\
uc_audiohw = (chanend) c;\
for(int i=0;i<DSP_WORKER_COUNT;i++)\
uc_dsp_to_ex3d[i] = (chanend) c_dsp_to_ex3d[i];\
uc_dsp_to_dnr_t1 = (chanend) cc_dsp_in;\
}\
hid_button_task(cc_mic_level, c_hid, c_hidSendData);\
}\
}\
on tile[0]: {\
par\
{\
unsafe\
{\
board_setup();\
} \
AudioHwRemote(c);\
dnr_dsp_buffer_task(cc_dsp_in, cc_dsp_eof, cc_mic_level);\
dnr_dsp_proc_task(cc_dsp_eof);\
}\
}
#else
#define USER_MAIN_DECLARATIONS \
chan c_dsp_to_ex3d[DSP_WORKER_COUNT]; chan cc_mic_level; chan c_key; chan c_hidSendData; chan c_hidRcvData; chan c_eq_data; chan c_uac_vol;
#define USER_MAIN_CORES on tile[1]: {\
par\
{\
hid_button_task(cc_mic_level, c_hidRcvData, c_hidSendData, c_uac_vol);\
par(int i=0;i<DSP_WORKER_COUNT;i++) dsp_worker_tile(c_dsp_to_ex3d[i], i);\
unsafe\
{\
SetEqDataChan(c_eq_data); \
key_sender(c_key);\
for(int i=0;i<DSP_WORKER_COUNT;i++)\
uc_dsp_to_ex3d[i] = (chanend) c_dsp_to_ex3d[i];\
ex3d_task();\
}\
}\
}\
on tile[0]: {\
par\
{\
{ \
unsafe\
{\
key_receiver(c_key);\
}\
AudioHwRemote(c_hidSendData, cc_mic_level, c_uac_vol);\
} \
}\
}\
on tile[0]: {\
{ dsp_core0(); } \
}\
on tile[0]: {dsp_main(c_eq_data); } \
on tile[0]: {dnr_dsp_proc_task(); } \
#endif // AIZIP_DNR
#endif // __XC__
#endif // _USER_MAIN_H_

View File

@@ -0,0 +1,263 @@
#ifndef _UART_H_
#define _UART_H_
#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include <stdio.h>
#include <stdint.h>
typedef enum {
AUDIO_PCM_44100 = 0,
AUDIO_PCM_48000,
AUDIO_PCM_88200,
AUDIO_PCM_96000,
AUDIO_PCM_176400,
AUDIO_PCM_192000,
AUDIO_PCM_352800,
AUDIO_PCM_384000,
AUDIO_PCM_705600,
AUDIO_PCM_768000,
AUDIO_PCM_1441200,
AUDIO_PCM_1536000,
AUDIO_PCM_32000,
AUDIO_PCM_64000,
AUDIO_PCM_128000,
AUDIO_PCM_256000,
AUDIO_PCM_512000,
AUDIO_DSD_64,
AUDIO_DSD_128,
AUDIO_DSD_256,
AUDIO_DSD_512,
AUDIO_DSD_1024,
AUDIO_MQA_44100,
AUDIO_MQA_88200,
AUDIO_MQA_176400,
AUDIO_MQA_352800,
AUDIO_MQA_705600,
AUDIO_MQA_1411200,
AUDIO_MQA_2822400,
AUDIO_MQA_5644800,
AUDIO_MQA_48000,
AUDIO_MQA_96000,
AUDIO_MQA_192000,
AUDIO_MQA_384000,
AUDIO_MQA_768000,
AUDIO_MQA_1536000,
AUDIO_MQA_3072000,
AUDIO_MQA_6144000,
AUDIO_MQA_64000,
AUDIO_MQA_128000,
AUDIO_MQA_256000,
AUDIO_MQA_512000,
AUDIO_MQA_1024000,
AUDIO_MQA_2048000,
AUDIO_MQA_4096000,
AUDIO_MQA_8192000,
AUDIO_NO_USED = 0xFF,
} audio_sampling;
typedef enum {
PCM = 0, /**< PCM */
Reserve = 1, /**< Reserved */
MQA = 2, /**< MQA */
MQB = 3, /**< MQB */
MQA_Studio = 4, /**< MQA Studio */
DSD = 5, /**< DSD Native*/
} audio_type;
typedef enum
{
USER_CMD_VOL_UP = 0x00,
USER_CMD_VOL_DOWN,
USER_CMD_PLAY,
USER_CMD_NEXT,
USER_CMD_PREV,
USER_CMD_FORWARD,
USER_CMD_REWIND,
USER_CMD_MUTE
} ButtonEvent;
typedef enum {
AUDIO_FREQ_44100 = 0,
AUDIO_FREQ_48000,
AUDIO_FREQ_88200,
AUDIO_FREQ_96000,
AUDIO_FREQ_176400,
AUDIO_FREQ_192000,
AUDIO_FREQ_352800,
AUDIO_FREQ_384000,
AUDIO_FREQ_705600,
AUDIO_FREQ_768000,
AUDIO_FREQ_1411200,
AUDIO_FREQ_1536000
} AudioFreq;
typedef enum {
AUDIO_CLASS_UAC1 = 0,
AUDIO_CLASS_UAC2
} AudioClass;
typedef enum {
AUDIO_WIDTH_16BIT = 0,
AUDIO_WIDTH_24BIT = 1,
AUDIO_WIDTH_32BIT = 2
} AudioWidth;
typedef enum {
MODE_USB = 0,
MODE_OPT,
MODE_COAX,
MODE_BT,
MODE_HDMI_ARC,
MODE_WIFI,
MODE_AIRPLAY,
MODE_SPOTIFY
} UserMode;
typedef enum {
START_BOOT = 0,
READ_PRODUCT = 1,
READ_POR_CONFIG = 2,
READ_AUDIO_MODE = 3,
READ_USER_CONFIG = 4,
START_FINISH = 5,
REPORT_APP_STATUS = 0x20,
MEDIA_CONTROL = 0x21,
SEND_AUDIO_FORMAT = 0x22,
SWITCH_AUDIO_MODE = 0x23,
SEND_OUT_VOLUME = 0x24,
SEND_IN_VOLUME = 0x25,
SET_DAC_VOLUME = 0x26,
SET_DAC_MODE = 0x27,
SET_DAC_M_GAIN = 0x32,
TEST_CMD = 0xF0,
FW_VERSION = 0xF1,
FLASH_ID = 0xF2,
// EQ命令定义 (0x40-0x5C)
SET_EQ_MODE = 0x40, // 切换EQ模式
GET_EQ_MODE = 0x41, // 获取当前EQ模式信息
SET_MODE_GAIN_AND_NAME = 0x42, // 设置模式整体增益和名称
SET_EQ_PARAMS = 0x43, // 发送EQ参数
GET_EQ_PARAMS = 0x44, // 读取EQ参数
GET_DEVICE_INFO = 0x45, // 获取设备信息
RESET_EQ_PARAMS = 0x46, // 复位EQ参数
GET_EQ_MODE_COUNT = 0x47, // 获取EQ模式总数
SET_AND_SAVE_EQ_MODE = 0x48, // 设置并保存EQ模式
SET_VOLUME = 0x49, // 设置音量级别
GET_VOLUME = 0x4A, // 获取音量级别
GET_LED_INFO = 0x4B, // 获取LED信息
SET_LED_SWITCH = 0x4C, // 设置LED开关
GET_LED_SWITCH = 0x4D, // 获取LED开关
GET_LED_STATUS = 0x4E, // 获取LED状态
GET_LED_COUNT = 0x4F, // 获取LED总数
GET_UAC_MODE_INFO = 0x50, // 获取UAC模式信息
SET_UAC_MODE = 0x51, // 设置UAC模式
GET_CURRENT_UAC_MODE = 0x52, // 获取当前UAC模式
SET_EQ_ENABLE = 0x53, // 设置EQ使能开关
GET_EQ_ENABLE = 0x54, // 获取EQ使能开关
GET_SAMPLE_FORMAT = 0x55, // 获取采样率和格式
SET_GAIN_MODE = 0x56, // 设置增益模式
GET_GAIN_MODE = 0x57, // 获取增益模式
SET_FILTER_MODE = 0x58, // 设置滤波器模式
GET_FILTER_MODE = 0x59, // 获取滤波器模式
SET_GAME_MODE = 0x5A, // 设置游戏模式
GET_GAME_MODE = 0x5B, // 获取游戏模式
GET_FIRMWARE_VERSION = 0x5C, // 获取固件版本
CMD_NONE = 0xFF
} UartCmdType;
#define CMD_HEAD1_POS 0
#define CMD_HEAD2_POS 1
#define CMD_VERSION_POS 2
#define CMD_CMD_POS 3
#define CMD_DATA_LEN_POS 4
#define CMD_DATA_POS 5
#define BOOT_CMD_DATA_LEN 17
#define FINISH_CMD_DATA_LEN 15
#define PRODUCT_CMD_DATA_LEN 61
#define CONFIG_CMD_DATA_LEN 14
#define AUDIO_MODE_CMD_DATA_LEN 5
#define UART_HEAD1 0x55
#define UART_HEAD2 0xAA
#define UART_HEAD 0x55
#define UART_HEAD_LEN 0x05
#if !__XC__
typedef struct {
uint8_t I2S_Mode : 1; // I2S Mode: 0 - Master, 1 - Slave
uint8_t Sync_Mode : 1; // Sync Mode: 0 - Async, 1 - Sync
uint8_t MIDI_Enable : 1; // MIDI Enable: 0 - Disable, 1 - Enable
uint8_t SPDIF_In : 1; // SPDIF Input: 0 - Disable, 1 - Enable
uint8_t SPDIF_Out : 1; // SPDIF Output: 0 - Disable, 1 - Enable
uint8_t ADAT_In : 1; // ADAT Input: 0 - Disable, 1 - Enable
uint8_t ADAT_Out : 1; // ADAT Output: 0 - Disable, 1 - Enable
uint8_t DSD_Out : 1; // DSD Output: 0 - Disable, 1 - Enable
uint8_t Audio_Sample_Rate : 4; // Audio Sample Rate
uint8_t MQA_Enable : 1; // MQA Enable: 0 - Disable, 1 - Enable
uint8_t Audio_Class : 1; // Audio Class: 0 - UAC 1.0, 1 - USB UAC 2.0
uint8_t Audio_Width : 2; // Audio Width: 0 - 16bit, 1 - 24bit, 2 - 32bit
uint16_t Input_Channel : 6; // Input Channel Count
uint16_t Output_Channel : 6; // Output Channel Count
uint16_t Other_Cfg : 4; // Other Configuration
UserMode Mode; // Mode
} AudioMode;
typedef struct {
uint16_t vid1;
uint16_t pid1;
uint16_t vid2;
uint16_t pid2;
uint8_t ManufactureName[16];
uint8_t ProductName[16];
uint8_t SerialNumber[16];
uint32_t crc;
} ProductInfo;
typedef struct {
AudioMode audioMode;
uint16_t muteTime;
uint8_t micVol;
uint8_t dacLvol;
uint8_t dacRvol;
uint32_t crc;
} AppConfigs;
#endif
typedef enum {
USB_MODE = 1 ,
OPT_MODE ,
COAX_MODE ,
BT_MODE ,
HDMI_ARC_MODE ,
WIFI_MODE ,
AIRPLAY_MODE ,
SPOTIFY_MODE ,
} UsbMode;
typedef struct {
unsigned char startFlag;
unsigned char startConfig;
unsigned char startApp;
unsigned char cmdCount;
unsigned char cmdPending;
unsigned char pendingReboot;
} UserCmdConfig;
#endif