sync fps with C3

This commit is contained in:
Steven Dan
2026-06-22 16:21:58 +08:00
parent ca3141b77f
commit 6bbf4fbe9b
22 changed files with 4152 additions and 1562 deletions

View File

@@ -21,13 +21,37 @@
#include "xua_hid_report.h"
#include "nau88c21.h"
#include "tile1_clk.h"
#include "dfu_upgrade.h"
#if MQA_EN
#include "MQA_XMOS.h"
#endif
extern "C" {
#include "sw_pll.h"
#include "dfu_upgrade.h"
extern unsigned g_sync_t0_to_t1_cmd;
extern unsigned g_sync_t0_to_t1_data;
/* 改动原因tile0/tile1 内存不共享sync 第二数据字用于上电经 0x03 传递 FPS 三模块使能 */
extern unsigned g_sync_t0_to_t1_data2;
extern unsigned g_fps_game_select;
extern unsigned g_fps_level_select;
extern unsigned g_fps_drc_enable;
extern unsigned g_fps_sub_enable;
extern unsigned g_fps_eq_enable;
extern unsigned g_fps_drc_mode;
#if XMOS_FPS_EN
#include "fps_eq_sync.h"
/* 改动原因HID 0xBF/0xB5/0xBD/0xB7/0xB9经tile同步后调用FPS库接口不在DSP任务内轮询 */
void fps_apply_game_level_select(void);
void fps_apply_module_enable(void);
void fps_apply_drc_mode(void);
void fps_apply_eq_mode(void);
void fps_apply_eq_band_gain(unsigned band, int16_t gain);
void fps_eq_boot_publish_to_tile1(void);
void fps_drc_boot_sync_to_tile1(void);
void fps_boot_load_from_flash(void);
void sync_t0_promote_pending_to_tile1(void);
#endif
}
#define TIMER_PERIOD 2000000
@@ -529,8 +553,52 @@ static void codec_init_on_i2c(client interface i2c_master_if i2c)
void save_value(unsigned char * unsafe path, unsigned char value);
unsigned char load_value(unsigned char * unsafe path);
#define C1_MODE_INFO_PATH "c1_mode"
#if XMOS_FPS_EN
/* 改动原因:将 g_sync_t0_to_t1_cmd 经 c_app_sync 发到 tile1供定时器与上电 flush 复用 */
static int tile0_send_one_sync_to_tile1(chanend c_app_sync)
{
unsigned sync_cmd = 0;
GET_SHARED_GLOBAL(sync_cmd, g_sync_t0_to_t1_cmd);
if (sync_cmd == 0) {
return 0;
}
{
unsigned sync_data = 0;
unsigned sync_data2 = 0;
GET_SHARED_GLOBAL(sync_data, g_sync_t0_to_t1_data);
GET_SHARED_GLOBAL(sync_data2, g_sync_t0_to_t1_data2);
c_app_sync <: (unsigned)(0x80 | sync_cmd);
c_app_sync <: sync_data;
c_app_sync <: sync_data2;
SET_SHARED_GLOBAL(g_sync_t0_to_t1_cmd, 0);
SET_SHARED_GLOBAL(g_sync_t0_to_t1_data2, 0);
sync_t0_promote_pending_to_tile1();
debug_printf("tile0: Sent sync 0x%02X to tile1, data=%u data2=%u\n",
sync_cmd, sync_data, sync_data2);
}
return 1;
}
/* 改动原因:上电 fps_boot_load 会排队 0x03+0x0C+0x09+五包0x0B须立即 drain 而非等 20ms 定时器 */
static void tile0_flush_sync_queue_to_tile1(chanend c_app_sync)
{
unsigned sync_cmd = 0;
do {
while (tile0_send_one_sync_to_tile1(c_app_sync) != 0) {}
sync_t0_promote_pending_to_tile1();
GET_SHARED_GLOBAL(sync_cmd, g_sync_t0_to_t1_cmd);
} while (sync_cmd != 0);
}
#endif
/* 改动原因c_dfu 仅接收 FIRMWARE_UPGRADE_START在此线程执行 handle_firmware_upgrade_start */
void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, client interface c1_led_ctrl_if i_c1_led_ctrl, chanend c_erase, streaming chanend c_dfu)
void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, client interface c1_led_ctrl_if i_c1_led_ctrl, streaming chanend c_dfu, chanend c_app_sync)
{
unsigned cmd;
int value;
@@ -683,6 +751,14 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli
old_adc_vol = boot_effective_adc_vol;
}
#if XMOS_FPS_EN
/* 改动原因C1 无 UART/MCU不经过 c_uart_sync上电直接在 tile0 从 Flash 恢复 FPS 并 sync 到 tile1 */
/* 改动原因tile1 app_control_slave 有约 100ms 延时,此处再等 50ms 确保 c_sync 已进 select */
delay_milliseconds(50);
fps_boot_load_from_flash();
tile0_flush_sync_queue_to_tile1(c_app_sync);
#endif
while(1)
{
select
@@ -1091,6 +1167,10 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli
#if ((HID_CONTROLS == 1) && (EQ_EN == 1))
// 改动原因检测tile0到tile1的同步命令如果有命令则通过channel发送到tile1
#if XMOS_FPS_EN
(void)tile0_send_one_sync_to_tile1(c_app_sync);
#endif
// 改动原因检测增益模式变化请求当g_request_gain_mode != -1且与当前模式不同时应用
{
unsigned request_gain_mode, gain_mode;
@@ -1187,7 +1267,8 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli
g_last_mute_switch = current_mute;
}
// 改动原因规格DNR无指示灯按键长按切换后通过HID 0xB5主动上报APP与0xB4监听开关上报方式一致
// 改动原因规格DNR无指示灯按键长按切换后通过HID主动上报APP
// 改动原因XMOS_FPS_EN 时 0xB5 为 SET_FPS_MODULE_ENABLEDNR 上报改用 0xC5
{
unsigned current_dnr;
GET_SHARED_GLOBAL(current_dnr, g_dnr_enable);
@@ -1197,12 +1278,16 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli
{
unsigned char * unsafe reportPtr = g_hid_pass_data;
reportPtr[0] = 0x77;
#if XMOS_FPS_EN
reportPtr[1] = 0xC5; // GET_DNR_ENABLEFPS 构建下与 0xB5 区分)
#else
reportPtr[1] = 0xB5; // GET_DNR_ENABLE
#endif
reportPtr[2] = (unsigned char)current_dnr;
for (int i = 3; i < 63; i++) reportPtr[i] = 0x00;
hidSetChangePending(0x1);
}
debug_printf("DNR enable changed: %d -> %d, HID 0xB5 report prepared\n", g_last_dnr_enable, current_dnr);
debug_printf("DNR enable changed: %d -> %d, HID report prepared\n", g_last_dnr_enable, current_dnr);
}
g_last_dnr_enable = current_dnr;
}
@@ -1570,6 +1655,11 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli
}
}
// 改动原因用于tile0到tile1同步命令的共享变量
unsigned g_sync_t0_to_t1_cmd = 0; // 0=无命令0x01=SET_GAME_MODE
unsigned g_sync_t0_to_t1_data = 0; // 命令数据
unsigned g_sync_t0_to_t1_data2 = 0; // 改动原因sync 第二数据字,上电 0x03 携带 FPS 模块使能
extern void SetKeyFlag(unsigned x);
void flag_handler()
{
@@ -1588,14 +1678,14 @@ void flag_handler()
}
void AudioHwRemote(streaming chanend c, client interface c1_led_ctrl_if i_c1_led_ctrl, chanend c_erase, streaming chanend c_dfu)
void AudioHwRemote(streaming chanend c, client interface c1_led_ctrl_if i_c1_led_ctrl, streaming chanend c_dfu, chanend c_app_sync)
{
i2c_master_if i2c[1];
par
{
i2c_master(i2c, 1, p_scl, p_sda, 100);
AudioHwRemote2(c, i2c[0], i_c1_led_ctrl, c_erase, c_dfu);
AudioHwRemote2(c, i2c[0], i_c1_led_ctrl, c_dfu, c_app_sync);
}
}
@@ -1985,7 +2075,7 @@ static inline void apply_c1_panel_leds(unsigned mode_led_color_idx, unsigned mic
p_mode_led_blue <: (mode_blue ? 0 : 1);
}
void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl)
void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl, chanend c_sync)
{
// 改动原因tile1 先于 tile0 运行,上电先把硬件灯全灯且不调用 apply避免用占位 mic/mode 组合误亮shadow 置为全灯灯电平便于首包 set_* 时 apply 与端口一致。
unsigned led_shadow = 0xF;
@@ -2022,6 +2112,154 @@ void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl)
mic_mute_switch = (mute_state != 0) ? 1 : 0;
apply_c1_panel_leds(mode_led_color_idx, mic_mute_switch, led_shadow);
break;
// 改动原因接收从tile0通过channel发送的同步命令命令码 >= 0x80表示tile0到tile1的命令
case c_sync :> unsigned sync_cmd:
if ((sync_cmd & 0x80) != 0) {
// 这是从tile0发送的命令
unsigned sync_data1, sync_data2;
c_sync :> sync_data1;
c_sync :> sync_data2;
unsigned actual_cmd = sync_cmd & 0x7F; // 去掉0x80标志
if (actual_cmd == 0x01) { // SYNC_CMD_T0_TO_T1_SET_GAME_MODE
debug_printf("tile1: Received SET_GAME_MODE command from tile0 via channel, game_mode=%d\n", sync_data1);
// 改动原因调用UART 0x5A命令处理函数将命令透传给MCU
#if EQ_EN
process_uart_set_game_mode((uint8_t)sync_data1);
#endif
}
else if (actual_cmd == 0x02) { // SYNC_CMD_T0_TO_T1_SET_UAC_MODE
debug_printf("tile1: Received SET_UAC_MODE command from tile0 via channel, uac_mode=%d\n", sync_data1);
// 改动原因调用UART 0x51命令处理函数将命令透传给MCU
#if EQ_EN
process_uart_set_uac_mode((uint8_t)sync_data1);
#endif
}
else if (actual_cmd == 0x03) { // SYNC_CMD_T0_TO_T1_SET_FPS_XMOS_GAME_SELECT
// 改动原因sync_data1中同时打包了game和level低8位为game高8位为level
unsigned game_select = (sync_data1 & 0xFF);
unsigned level_select = ((sync_data1 >> 8) & 0xFF);
if (game_select > 2) {
game_select = 0;
}
// 改动原因tile1 与 tile0/协议一致level 有效 0-4无效时回默认 2与 0xBF 一致)
if (level_select > 4) {
level_select = 2;
}
debug_printf("tile1: Received SET_FPS_XMOS_GAME_SELECT command from tile0 via channel, game=%u level=%u\n",
game_select, level_select);
// 改动原因更新全局变量后由fps_apply_game_level_select调用fps_xmos_xc_game_selectDSP任务内不再轮询
SET_SHARED_GLOBAL(g_fps_game_select, game_select);
SET_SHARED_GLOBAL(g_fps_level_select, level_select);
#if XMOS_FPS_EN
fps_apply_game_level_select();
/* 改动原因tile0/tile1 内存不共享,上电使能经 sync data2(bit31) 下发后再 apply */
if ((sync_data2 & (1u << 31)) != 0) {
unsigned drc_enable = (sync_data2 & 0xFF);
unsigned fps_sub_enable = ((sync_data2 >> 8) & 0xFF);
unsigned eq_enable = ((sync_data2 >> 16) & 0xFF);
if (drc_enable > 1) { drc_enable = 0; }
if (fps_sub_enable > 1) { fps_sub_enable = 1; }
if (eq_enable > 1) { eq_enable = 0; }
debug_printf("tile1: boot FPS module enable from sync drc=%u fps=%u eq=%u\n",
drc_enable, fps_sub_enable, eq_enable);
SET_SHARED_GLOBAL(g_fps_drc_enable, drc_enable);
SET_SHARED_GLOBAL(g_fps_sub_enable, fps_sub_enable);
SET_SHARED_GLOBAL(g_fps_eq_enable, eq_enable);
}
fps_apply_module_enable();
/* 改动原因fps_eq 由后续排队 sync 0x09+0x0B 应用,此处不读 tile1 默认 pack */
#endif
}
else if (actual_cmd == 0x09) { // SYNC_CMD_T0_TO_T1_SET_FPS_EQ_MODE
unsigned mode = (sync_data1 & 0xFF);
if (mode >= 5) {
mode = 0;
}
debug_printf("tile1: SET_FPS_EQ_MODE %u\n", mode);
SET_SHARED_GLOBAL(g_fps_eq_mode, mode);
/* 改动原因:增益由紧随的 0x0B 包同步,末包 apply 时再 fps_apply_eq_mode */
}
else if (actual_cmd == 0x0B) { // SYNC_CMD_T0_TO_T1_SET_FPS_EQ_PACK
unsigned pack_idx = (sync_data1 & 0xFF);
unsigned apply_eq = ((sync_data1 >> 8) & 0xFF);
int32_t pack_val = (int32_t)sync_data2;
if (pack_idx < 5) {
debug_printf("tile1: SET_FPS_EQ_PACK idx=%u apply=%u\n", pack_idx, apply_eq);
switch (pack_idx) {
case 0: SET_SHARED_GLOBAL(g_fps_eq_pack0, pack_val); break;
case 1: SET_SHARED_GLOBAL(g_fps_eq_pack1, pack_val); break;
case 2: SET_SHARED_GLOBAL(g_fps_eq_pack2, pack_val); break;
case 3: SET_SHARED_GLOBAL(g_fps_eq_pack3, pack_val); break;
case 4: SET_SHARED_GLOBAL(g_fps_eq_pack4, pack_val); break;
default: break;
}
#if XMOS_FPS_EN
if (apply_eq != 0) {
fps_apply_eq_mode();
}
#endif
}
}
else if (actual_cmd == 0x0A) { // SYNC_CMD_T0_TO_T1_SET_FPS_EQ_BAND_GAIN
unsigned band = (sync_data1 & 0xFF);
int16_t gain = (int16_t)((sync_data1 >> 8) & 0xFFFF);
debug_printf("tile1: SET_FPS_EQ_BAND band=%u gain=%d\n", band, (int)gain);
#if XMOS_FPS_EN
fps_apply_eq_band_gain(band, gain);
#endif
}
else if (actual_cmd == 0x08) { // SYNC_CMD_T0_TO_T1_SET_FPS_MODULE_ENABLE
unsigned drc_enable = (sync_data1 & 0xFF);
unsigned fps_sub_enable = ((sync_data1 >> 8) & 0xFF);
unsigned eq_enable = ((sync_data1 >> 16) & 0xFF);
/* 改动原因sync 包无效字节时与上电默认一致DRC/fps_eq 关FPS 开 */
if (drc_enable > 1) { drc_enable = 0; }
if (fps_sub_enable > 1) { fps_sub_enable = 1; }
if (eq_enable > 1) { eq_enable = 0; }
debug_printf("tile1: SET_FPS_MODULE_ENABLE drc=%u fps=%u eq=%u\n",
drc_enable, fps_sub_enable, eq_enable);
SET_SHARED_GLOBAL(g_fps_drc_enable, drc_enable);
SET_SHARED_GLOBAL(g_fps_sub_enable, fps_sub_enable);
SET_SHARED_GLOBAL(g_fps_eq_enable, eq_enable);
#if XMOS_FPS_EN
fps_apply_module_enable();
#endif
}
else if (actual_cmd == 0x0C) { // SYNC_CMD_T0_TO_T1_SET_FPS_DRC_MODE
unsigned drc_mode = (sync_data1 & 0xFF);
/* 改动原因mode仅0=low、1=high无效时回默认0 */
if (drc_mode > 1) {
drc_mode = 0;
}
debug_printf("tile1: SET_FPS_DRC_MODE mode=%u\n", drc_mode);
SET_SHARED_GLOBAL(g_fps_drc_mode, drc_mode);
#if XMOS_FPS_EN
fps_apply_drc_mode();
#endif
}
else if (actual_cmd == 0x04) { // SYNC_CMD_T0_TO_T1_SET_INPUT_SOURCE
debug_printf("tile1: Received SET_INPUT_SOURCE command from tile0 via channel, input_source=%d\n", sync_data1);
#if EQ_EN
process_uart_set_input_source((uint8_t)sync_data1);
#endif
}
else if (actual_cmd == 0x05) { // SYNC_CMD_T0_TO_T1_SET_MUTE_SWITCH
debug_printf("tile1: Received SET_MUTE_SWITCH command from tile0 via channel, mute=%d\n", sync_data1);
#if EQ_EN
process_uart_set_mute_switch((uint8_t)sync_data1);
#endif
}
else if (actual_cmd == 0x07) { // SYNC_CMD_T0_TO_T1_SET_LISTEN_SWITCH
debug_printf("tile1: Received SET_LISTEN_SWITCH command from tile0 via channel, listen=%d\n", sync_data1);
#if EQ_EN
process_uart_set_listen_switch((uint8_t)sync_data1);
#endif
}
}
break;
}
}
}

View File

@@ -100,59 +100,4 @@ void dsp_main (chanend_t c_data , chanend_t cc_br_eof) {
#endif
}
extern uint8_t opt_key_read(uint8_t key[], unsigned offset);
extern unsigned dnr_init_flag;
void validate_algo(chanend_t c_validate)
{
#if BR_ALGO
uint8_t uid[20] = {0};
char hex_string[41] = {0};
while (!dnr_init_flag) {
delay_milliseconds(1);
}
opt_key_read(uid, 2);
delay_milliseconds(10);
for (int i = 0; i < 20; i++) {
sprintf(hex_string + i * 2, "%02x", uid[i]);
}
hex_string[40] = '\0';
flash_cmd_init();
int res = br_validate(c_validate, hex_string);
flash_cmd_deinit();
debug_printf("Validate status: %d\n", res); // check validate status
#endif
}
extern void set_core_high_priority_on(void);
void br_dsp_proc_task(chanend_t c_validate, chanend_t cc_br_eof)
{
#if BR_ALGO
set_core_high_priority_on();
int channel_flag = 4;
int is_br_on = 1;
int cnt = 0;
br_init(c_validate);
int validate = br_get_validate_status();
debug_printf("After Validate status: %d\n", validate); // check validate status
while (1)
{
int tmp;
int cur_pos;
chan_in_buf_word (cc_br_eof, &tmp, 1);
cur_pos = pos == 0 ? 1 : 0;
if (channel_flag <= 2) {
is_br_on = 0;
}
else {
is_br_on = 1;
}
br_apply(dsp_br_input_buf[cur_pos], dsp_br_out_buf[cur_pos], is_br_on);
channel_flag = br_get_channel_flag();
}
#endif
}

View File

@@ -590,6 +590,17 @@ unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len)
return STATUS_SUCCESS;
}
// 改动原因HID 0xAE 设备重启;补全缺失的 handle_device_reboot调用 eq.c 中已有的 device_reboot() 避免链接错误
unsigned char handle_device_reboot(uint8_t data[], uint16_t len)
{
(void)data;
(void)len;
debug_printf("Firmware upgrade DEVICE_REBOOT (0xAE)\n");
device_reboot();
while (1);
return STATUS_SUCCESS;
}
// 固件升级主处理函数
// 改动原因处理所有HID固件升级命令分发到相应的处理函数
// 参数:

File diff suppressed because it is too large Load Diff

View File

@@ -7,15 +7,15 @@
#include <stdint.h>
#include <stdbool.h>
#define NUM_EQ_MODES 10
#define NUM_EQ_MODES 15
#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
#define EQ_DISABLED_MODE 15 // 禁用EQ的模式编号改动原因模式扩展至15后禁用模式编号同步改为15
#define EQ_PRESET_MODE_MIN 0 // 预设模式最小编号
#define EQ_PRESET_MODE_MAX 12 // 预设模式最大编号(0-12共13个预设含音乐与游戏曲线
#define EQ_USER_MODE_MIN 13 // 用户模式最小编号改动原因仅保留2个用户自定义模式
#define EQ_USER_MODE_MAX 14 // 用户模式最大编号user 1-2
#define EQ_MODE_MAX (NUM_EQ_MODES) // 有效模式上界0-14为可用模式15为禁用
// Filter type definition
@@ -130,10 +130,6 @@ uint8_t process_uart_get_led_status(uint8_t led_index, uint8_t * unsafe response
uint8_t process_uart_get_led_count(uint8_t * unsafe response, uint8_t response_size);
uint8_t process_uart_get_uac_mode_info(uint8_t * unsafe response, uint8_t response_size);
void process_uart_set_uac_mode(uint8_t uac_mode);
void process_uart_set_input_source(uint8_t input_source); // 设置输入源(0=USB,1=OPT,2=COAX)HID 0xB0透传MCU
void process_uart_set_mute_switch(uint8_t mute); // 设置静音开关(0=关,1=开)HID 0xB1透传MCU
void process_uart_set_listen_switch(uint8_t listen); // 设置监听开关(0=关,1=开)HID 0xB3透传MCU
void process_uart_send_get_mute_request(void); // 向MCU发送0x5F获取静音请求
uint8_t process_uart_get_current_uac_mode(uint8_t * unsafe response, uint8_t response_size);
uint8_t process_uart_set_eq_enable(uint8_t enable);
uint8_t process_uart_get_eq_enable_response(uint8_t result, uint8_t enable, uint8_t * unsafe response, uint8_t response_size);
@@ -146,6 +142,11 @@ uint8_t process_uart_get_filter_mode(uint8_t * unsafe response, uint8_t response
void process_uart_set_game_mode(uint8_t game_mode);
uint8_t process_uart_get_game_mode(uint8_t * unsafe response, uint8_t response_size);
uint8_t process_uart_get_firmware_version(uint8_t * unsafe response, uint8_t response_size);
/* 改动原因:添加 0xB0-0xB4 相关 UART 处理与静音值回传XC 侧声明HID 在 tile0、UART 在 tile1 时由 tile1 调用 */
void process_uart_set_input_source(uint8_t input_source);
void process_uart_set_mute_switch(uint8_t mute);
void process_uart_send_get_mute_request(void);
void process_uart_set_listen_switch(uint8_t listen);
#else
// 独立的增益和名称设置/获取函数
@@ -171,10 +172,6 @@ uint8_t process_uart_get_led_status(uint8_t led_index, uint8_t *response, uint8_
uint8_t process_uart_get_led_count(uint8_t *response, uint8_t response_size);
uint8_t process_uart_get_uac_mode_info(uint8_t *response, uint8_t response_size);
void process_uart_set_uac_mode(uint8_t uac_mode);
void process_uart_set_input_source(uint8_t input_source); // 设置输入源(0=USB,1=OPT,2=COAX)HID 0xB0透传MCU
void process_uart_set_mute_switch(uint8_t mute); // 设置静音开关(0=关,1=开)HID 0xB1透传MCU
void process_uart_set_listen_switch(uint8_t listen); // 设置监听开关(0=关,1=开)HID 0xB3透传MCU
void process_uart_send_get_mute_request(void); // 向MCU发送0x5F获取静音请求
uint8_t process_uart_get_current_uac_mode(uint8_t *response, uint8_t response_size);
uint8_t process_uart_set_eq_enable(uint8_t enable);
uint8_t process_uart_get_eq_enable_response(uint8_t result, uint8_t enable, uint8_t *response, uint8_t response_size);
@@ -187,7 +184,11 @@ uint8_t process_uart_get_filter_mode(uint8_t *response, uint8_t response_size);
void process_uart_set_game_mode(uint8_t game_mode);
uint8_t process_uart_get_game_mode(uint8_t *response, uint8_t response_size);
uint8_t process_uart_get_firmware_version(uint8_t *response, uint8_t response_size);
/* 改动原因:添加 0xB0-0xB4 相关 UART 处理与静音值回传C 侧声明) */
void process_uart_set_input_source(uint8_t input_source);
void process_uart_set_mute_switch(uint8_t mute);
void process_uart_send_get_mute_request(void);
void process_uart_set_listen_switch(uint8_t listen);
#endif
void init_mode_info(void);

View File

@@ -53,10 +53,23 @@ from filter_utils import (BiquadFilterCalculator, make_biquad_bypass, make_biqua
# 常量定义
MAX_EQ_BANDS = 8 # 最大EQ滤波器数量 (0-7)
NUM_EQ_MODES = 10 # EQ模式数量
EQ_DISABLED_MODE = 10 # 禁用EQ的模式编号
NUM_EQ_MODES = 15 # EQ模式数量改动原因13预设+2用户共15模式
EQ_DISABLED_MODE = 15 # 禁用EQ的模式编号改动原因与NUM_EQ_MODES对齐
# 预设模式0-12用户模式13-14
EQ_PRESET_MODE_MAX = 12
EQ_USER_MODE_MIN = 13
EQ_USER_MODE_MAX = 14
# HID 固件升级命令码(使用命令名代替裸命令码
# 模式下拉列表显示名称改动原因与固件default_names及新增游戏曲线一致
MODE_COMBO_ITEMS = [
"JAZZ(0)", "POP(1)", "ROCK(2)", "CLASIC(3)",
"暗区突围(4)", "3A Game(5)", "战地6(6)",
"APEX(7)", "和平精英(8)", "逃离塔科夫(9)",
"穿越火线(10)", "守望先锋(11)", "永劫无望(12)",
"用户模式1(13)", "用户模式2(14)", "禁用EQ"
]
# HID 固件升级命令码(与 eq_hid_protocol_ds1 一致0xA7-0xAE
FIRMWARE_UPGRADE_START = 0xA7 # 开始固件升级
FIRMWARE_UPGRADE_DATA = 0xA8 # 传输固件数据块
FIRMWARE_UPGRADE_END = 0xA9 # 结束固件升级
@@ -65,6 +78,20 @@ FIRMWARE_UPGRADE_ABORT = 0xAB # 中止固件升级
FIRMWARE_UPGRADE_ERASE = 0xAC # 擦除现有升级镜像
DEVICE_REBOOT = 0xAE # 设备重启(通用命令)
# FPS XMOS 命令改动原因0xA7/0xA8 保留固件升级game/level 放在 DRC 0xBD/0xBE 之后为 0xBF/0xC0
SET_FPS_XMOS_GAME_SELECT = 0xBF
GET_FPS_XMOS_GAME_SELECT = 0xC0
SET_FPS_MODULE_ENABLE = 0xB5
GET_FPS_MODULE_ENABLE = 0xB6
SET_FPS_EQ_MODE = 0xB7
GET_FPS_EQ_MODE = 0xB8
SET_FPS_EQ_BAND_GAIN = 0xB9
GET_FPS_EQ_BAND_GAIN = 0xBA
SET_FPS_EQ_MODE_NAME = 0xBB
GET_FPS_EQ_MODE_NAME = 0xBC
SET_FPS_DRC_MODE = 0xBD
GET_FPS_DRC_MODE = 0xBE
class BandFilter(QGroupBox):
"""单个滤波器带控件"""
def __init__(self, band_id, parent=None):
@@ -536,7 +563,7 @@ class EQDesigner(QMainWindow):
mode_layout = QFormLayout(mode_group)
self.mode_label = QLabel("音效模式:")
self.mode_combo = QComboBox()
self.mode_combo.addItems(["预设模式1", "预设模式2", "预设模式3", "预设模式4", "预设模式5", "预设模式6", "用户模式1", "用户模式2", "用户模式3", "bypass", "禁用EQ"])
self.mode_combo.addItems(MODE_COMBO_ITEMS)
self.mode_combo.currentIndexChanged.connect(self.on_mode_changed)
mode_layout.addRow(self.mode_label, self.mode_combo)
@@ -912,6 +939,129 @@ class EQDesigner(QMainWindow):
listen_switch_layout.addRow(listen_switch_btn_layout)
left_content_layout.addWidget(listen_switch_group)
# FPS XMOS 算法控制HID 0xBF/0xC0 游戏档位0xB5/0xB6 三子模块使能)
fps_xmos_group = QGroupBox("FPS算法控制")
self.ui_groups['fps_xmos'] = fps_xmos_group
fps_xmos_layout = QFormLayout(fps_xmos_group)
fps_game_layout = QHBoxLayout()
self.fps_xmos_game_combo = QComboBox()
self.fps_xmos_game_combo.addItem("CS2 (0)", 0)
self.fps_xmos_game_combo.addItem("PUBG (1)", 1)
self.fps_xmos_game_combo.addItem("DELTA (2)", 2)
fps_game_layout.addWidget(QLabel("游戏类型:"))
fps_game_layout.addWidget(self.fps_xmos_game_combo)
fps_xmos_layout.addRow(fps_game_layout)
fps_level_layout = QHBoxLayout()
# 改动原因:与固件默认增益档位一致,默认 level=2
self.fps_xmos_level_spin = QSpinBox()
self.fps_xmos_level_spin.setRange(0, 4)
self.fps_xmos_level_spin.setValue(2)
fps_level_layout.addWidget(QLabel("增益档位(0-4):"))
fps_level_layout.addWidget(self.fps_xmos_level_spin)
fps_xmos_layout.addRow(fps_level_layout)
fps_game_btn_layout = QHBoxLayout()
self.set_fps_xmos_game_btn = QPushButton("设置游戏/档位 (0xBF)")
self.set_fps_xmos_game_btn.clicked.connect(self.on_set_fps_xmos_game_select)
self.get_fps_xmos_game_btn = QPushButton("查询档位 (0xC0)")
self.get_fps_xmos_game_btn.clicked.connect(self.on_get_fps_xmos_game_select)
fps_game_btn_layout.addWidget(self.set_fps_xmos_game_btn)
fps_game_btn_layout.addWidget(self.get_fps_xmos_game_btn)
fps_xmos_layout.addRow(fps_game_btn_layout)
self.fps_xmos_game_status_label = QLabel("游戏档位: 未查询")
fps_xmos_layout.addRow("状态:", self.fps_xmos_game_status_label)
# 改动原因与固件默认一致——FPS 主处理开DRC/fps_eq 关
self.fps_drc_enable_combo = QComboBox()
self.fps_drc_enable_combo.addItems(["关 (0)", "开 (1)"])
self.fps_drc_enable_combo.setCurrentIndex(0)
fps_xmos_layout.addRow("DRC:", self.fps_drc_enable_combo)
self.fps_sub_enable_combo = QComboBox()
self.fps_sub_enable_combo.addItems(["关 (0)", "开 (1)"])
self.fps_sub_enable_combo.setCurrentIndex(1)
fps_xmos_layout.addRow("FPS主处理:", self.fps_sub_enable_combo)
self.fps_eq_enable_combo = QComboBox()
self.fps_eq_enable_combo.addItems(["关 (0)", "开 (1)"])
self.fps_eq_enable_combo.setCurrentIndex(0)
fps_xmos_layout.addRow("fps_eq:", self.fps_eq_enable_combo)
fps_module_btn_layout = QHBoxLayout()
self.set_fps_module_enable_btn = QPushButton("设置使能 (0xB5)")
self.set_fps_module_enable_btn.clicked.connect(self.on_set_fps_module_enable)
self.get_fps_module_enable_btn = QPushButton("读取使能 (0xB6)")
self.get_fps_module_enable_btn.clicked.connect(self.on_get_fps_module_enable)
fps_module_btn_layout.addWidget(self.set_fps_module_enable_btn)
fps_module_btn_layout.addWidget(self.get_fps_module_enable_btn)
fps_xmos_layout.addRow(fps_module_btn_layout)
# 改动原因DRC压缩模式与DRC使能独立HID 0xBD/0xBE默认0=low柔和压缩
self.fps_drc_mode_combo = QComboBox()
self.fps_drc_mode_combo.addItem("low 柔和压缩 (0)", 0)
self.fps_drc_mode_combo.addItem("high 强力压缩 (1)", 1)
self.fps_drc_mode_combo.setCurrentIndex(0)
fps_xmos_layout.addRow("DRC压缩模式:", self.fps_drc_mode_combo)
fps_drc_mode_btn_layout = QHBoxLayout()
self.set_fps_drc_mode_btn = QPushButton("设置DRC模式 (0xBD)")
self.set_fps_drc_mode_btn.clicked.connect(self.on_set_fps_drc_mode)
self.get_fps_drc_mode_btn = QPushButton("读取DRC模式 (0xBE)")
self.get_fps_drc_mode_btn.clicked.connect(self.on_get_fps_drc_mode)
fps_drc_mode_btn_layout.addWidget(self.set_fps_drc_mode_btn)
fps_drc_mode_btn_layout.addWidget(self.get_fps_drc_mode_btn)
fps_xmos_layout.addRow(fps_drc_mode_btn_layout)
self.fps_eq_mode_spin = QSpinBox()
self.fps_eq_mode_spin.setRange(0, 4)
self.fps_eq_mode_spin.setValue(0)
fps_xmos_layout.addRow("fps_eq模式(0-4):", self.fps_eq_mode_spin)
fps_eq_mode_btn = QHBoxLayout()
self.set_fps_eq_mode_btn = QPushButton("设置模式 (0xB7)")
self.set_fps_eq_mode_btn.clicked.connect(self.on_set_fps_eq_mode)
self.get_fps_eq_mode_btn = QPushButton("读取模式 (0xB8)")
self.get_fps_eq_mode_btn.clicked.connect(self.on_get_fps_eq_mode)
fps_eq_mode_btn.addWidget(self.set_fps_eq_mode_btn)
fps_eq_mode_btn.addWidget(self.get_fps_eq_mode_btn)
fps_xmos_layout.addRow(fps_eq_mode_btn)
fps_name_layout = QHBoxLayout()
self.fps_eq_mode_name_edit = QLineEdit()
self.fps_eq_mode_name_edit.setPlaceholderText("模式名称(最多15字符)")
fps_name_layout.addWidget(self.fps_eq_mode_name_edit)
self.set_fps_eq_mode_name_btn = QPushButton("设置名称 (0xBB)")
self.set_fps_eq_mode_name_btn.clicked.connect(self.on_set_fps_eq_mode_name)
self.get_fps_eq_mode_name_btn = QPushButton("读取名称 (0xBC)")
self.get_fps_eq_mode_name_btn.clicked.connect(self.on_get_fps_eq_mode_name)
fps_name_layout.addWidget(self.set_fps_eq_mode_name_btn)
fps_name_layout.addWidget(self.get_fps_eq_mode_name_btn)
fps_xmos_layout.addRow("fps_eq模式名:", fps_name_layout)
fps_band_layout = QHBoxLayout()
self.fps_eq_band_spin = QSpinBox()
self.fps_eq_band_spin.setRange(0, 9)
self.fps_eq_gain_spin = QSpinBox()
self.fps_eq_gain_spin.setRange(-600, 600)
self.fps_eq_gain_spin.setValue(1)
fps_band_layout.addWidget(QLabel("频段:"))
fps_band_layout.addWidget(self.fps_eq_band_spin)
fps_band_layout.addWidget(QLabel("增益(0.01dB):"))
fps_band_layout.addWidget(self.fps_eq_gain_spin)
fps_xmos_layout.addRow(fps_band_layout)
fps_band_btn = QHBoxLayout()
self.set_fps_eq_band_btn = QPushButton("设置频段 (0xB9)")
self.set_fps_eq_band_btn.clicked.connect(self.on_set_fps_eq_band_gain)
self.get_fps_eq_band_btn = QPushButton("读取频段 (0xBA)")
self.get_fps_eq_band_btn.clicked.connect(self.on_get_fps_eq_band_gain)
fps_band_btn.addWidget(self.set_fps_eq_band_btn)
fps_band_btn.addWidget(self.get_fps_eq_band_btn)
fps_xmos_layout.addRow(fps_band_btn)
left_content_layout.addWidget(fps_xmos_group)
# 添加EQ使能控制组
eq_enable_group = QGroupBox("EQ使能控制")
self.ui_groups['eq_enable'] = eq_enable_group # 保存引用
@@ -1097,6 +1247,7 @@ class EQDesigner(QMainWindow):
'input_source': '输入源控制',
'mute_switch': '静音开关',
'listen_switch': '监听开关',
'fps_xmos': 'FPS算法控制',
'eq_enable': 'EQ使能控制',
'firmware': '固件升级',
'dfs': '动态降频'
@@ -1131,6 +1282,7 @@ class EQDesigner(QMainWindow):
'input_source': '输入源控制',
'mute_switch': '静音开关',
'listen_switch': '监听开关',
'fps_xmos': 'FPS算法控制',
'eq_enable': 'EQ使能控制',
'firmware': '固件升级'
}
@@ -1804,7 +1956,11 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
fs = 48000
log_message(LOG_LEVEL_DEBUG, f" 图像显示采样率: {fs} Hz", self.log_level)
mode = self.current_mode
# 改动原因读取参数时以UI当前选择模式为准避免self.current_mode被异步查询结果覆盖后读取到错误模式。
requested_mode = self.mode_combo.currentIndex()
if requested_mode == NUM_EQ_MODES:
requested_mode = EQ_DISABLED_MODE
mode = requested_mode
# 读取所有MAX_EQ_BANDS个EQ参数
for eq_index in range(MAX_EQ_BANDS):
@@ -1839,9 +1995,15 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
log_message(LOG_LEVEL_ERROR, f"错误: 无效的响应同步头: 0x{reply[1]:02x} 0x{reply[2]:02x}", self.log_level)
continue
# 模式值
mode = reply[3]
log_message(LOG_LEVEL_DEBUG, f" 模式值: {mode}", self.log_level)
# 模式值(设备回包)
resp_mode = reply[3]
log_message(LOG_LEVEL_DEBUG, f" 模式值: {resp_mode}", self.log_level)
if resp_mode != requested_mode:
log_message(
LOG_LEVEL_WARN,
f" 警告: 请求模式={requested_mode}, 回包模式={resp_mode},后续仍按请求模式继续读取",
self.log_level
)
# EQ索引
eq_idx = reply[4]
@@ -1882,7 +2044,9 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
log_message(LOG_LEVEL_DEBUG, f" 带宽: {bw:.2f} Hz", self.log_level)
# 增益 (4字节) - 位置18-21
gain = struct.unpack('<f', bytes(reply[18:22]))[0]
gain_bytes = bytes(reply[18:22])
gain = struct.unpack('<f', gain_bytes)[0]
log_message(LOG_LEVEL_DEBUG, f" gain bytes: {gain_bytes.hex()}", self.log_level)
log_message(LOG_LEVEL_DEBUG, f" 增益: {gain:.2f} dB", self.log_level)
# 更新UI显示
@@ -1896,7 +2060,7 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
# 打印读取到的参数
log_message(LOG_LEVEL_INFO, f"成功读取EQ {eq_index} 的参数:", self.log_level)
log_message(LOG_LEVEL_INFO, f" 模式值: {mode}", self.log_level)
log_message(LOG_LEVEL_INFO, f" 模式值: {resp_mode}", self.log_level)
log_message(LOG_LEVEL_INFO, f" 类型: {filter_type}", self.log_level)
log_message(LOG_LEVEL_INFO, f" 频率: {fc} Hz", self.log_level)
log_message(LOG_LEVEL_INFO, f" Q值: {q:.2f}", self.log_level)
@@ -2295,7 +2459,7 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
self,
"错误",
f"无效的模式值: {mode}\n\n"
f"有效范围: 0-9 (0-5预设模式, 6-8用户模式, 9: bypass)"
f"有效范围: 0-14 (0-12预设模式, 13-14用户模式, 15=禁用EQ)"
)
return
@@ -3670,6 +3834,357 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"读取固件版本时出错: {str(e)}", self.log_level)
def on_set_fps_xmos_game_select(self):
"""设置 FPS XMOS 游戏类型与档位HID 0xBFtile0→tile1"""
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
return
game = self.fps_xmos_game_combo.currentData()
level = self.fps_xmos_level_spin.value()
game_name = self.fps_xmos_game_combo.currentText()
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = SET_FPS_XMOS_GAME_SELECT
data[2] = game
data[3] = level
log_message(LOG_LEVEL_INFO,
f"设置 FPS 游戏/档位: {game_name}, level={level} (HID 0xBF)...",
self.log_level)
h.write([0x01] + list(data))
self.fps_xmos_game_status_label.setText(f"游戏档位: game={game}, level={level} (已发送)")
QMessageBox.information(self, "已发送",
f"已设置 FPS 游戏/档位:\n{game_name}\n档位: {level}")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"设置 FPS 游戏/档位时出错: {str(e)}", self.log_level)
def on_get_fps_xmos_game_select(self):
"""查询指定 game 的档位HID 0xC0"""
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
return
game = self.fps_xmos_game_combo.currentData()
try:
import time
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = GET_FPS_XMOS_GAME_SELECT
data[2] = game
log_message(LOG_LEVEL_INFO,
f"查询 FPS game={game} 的档位 (HID 0xC0)...",
self.log_level)
h.write([0x01] + list(data))
time.sleep(0.05)
reply = h.get_input_report(0x01, 64)
if (reply and len(reply) == 64 and reply[0] == 0x01
and reply[1] == 0x77 and reply[2] == GET_FPS_XMOS_GAME_SELECT):
resp_game = reply[3]
resp_level = reply[4]
self.fps_xmos_game_status_label.setText(
f"游戏档位: game={resp_game}, level={resp_level}")
if resp_game <= 2:
idx = self.fps_xmos_game_combo.findData(resp_game)
if idx >= 0:
self.fps_xmos_game_combo.setCurrentIndex(idx)
if resp_level <= 4:
self.fps_xmos_level_spin.setValue(resp_level)
QMessageBox.information(self, "FPS 游戏档位",
f"game={resp_game}, level={resp_level}")
else:
log_message(LOG_LEVEL_ERROR, "未收到有效的 0xC0 响应", self.log_level)
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"查询 FPS 游戏档位时出错: {str(e)}", self.log_level)
def on_set_fps_module_enable(self):
"""设置 FPS 库 DRC / FPS主处理 / fps_eq 使能HID 0xB5"""
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
return
drc = self.fps_drc_enable_combo.currentIndex()
fps_sub = self.fps_sub_enable_combo.currentIndex()
eq_en = self.fps_eq_enable_combo.currentIndex()
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = SET_FPS_MODULE_ENABLE
data[2] = drc
data[3] = fps_sub
data[4] = eq_en
log_message(LOG_LEVEL_INFO,
f"设置 FPS 模块使能: DRC={drc}, FPS={fps_sub}, EQ={eq_en} (HID 0xB5)...",
self.log_level)
h.write([0x01] + list(data))
log_message(LOG_LEVEL_DEBUG, "发送的数据:", self.log_level)
log_message(LOG_LEVEL_DEBUG, " ".join(f"0x{byte:02x}" for byte in ([0x01] + list[int](data))), self.log_level)
QMessageBox.information(self, "已发送",
f"DRC={drc}, FPS主处理={fps_sub}, fps_eq={eq_en}\n(0=关, 1=开)")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"设置 FPS 模块使能时出错: {str(e)}", self.log_level)
def on_get_fps_module_enable(self):
"""读取 FPS 库三模块使能HID 0xB6"""
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
return
try:
import time
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = GET_FPS_MODULE_ENABLE
log_message(LOG_LEVEL_INFO, "读取 FPS 模块使能 (HID 0xB6)...", self.log_level)
h.write([0x01] + list(data))
time.sleep(0.05)
reply = h.get_input_report(0x01, 64)
if (reply and len(reply) == 64 and reply[0] == 0x01
and reply[1] == 0x77 and reply[2] == GET_FPS_MODULE_ENABLE):
drc = reply[3]
fps_sub = reply[4]
eq_en = reply[5]
self.fps_drc_enable_combo.setCurrentIndex(1 if drc else 0)
self.fps_sub_enable_combo.setCurrentIndex(1 if fps_sub else 0)
self.fps_eq_enable_combo.setCurrentIndex(1 if eq_en else 0)
log_message(LOG_LEVEL_DEBUG, "读取到的响应数据:", self.log_level)
log_message(LOG_LEVEL_DEBUG, " ".join(f"0x{byte:02x}" for byte in reply), self.log_level)
log_message(LOG_LEVEL_INFO,
f"FPS 模块使能: DRC={drc}, FPS={fps_sub}, EQ={eq_en}",
self.log_level)
QMessageBox.information(self, "FPS 模块使能",
f"DRC={drc}\nFPS主处理={fps_sub}\nfps_eq={eq_en}\n(0=关, 1=开)")
else:
log_message(LOG_LEVEL_ERROR, "未收到有效的 0xB6 响应", self.log_level)
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"读取 FPS 模块使能时出错: {str(e)}", self.log_level)
def on_set_fps_drc_mode(self):
"""设置 DRC 压缩模式HID 0xBD0=low柔和1=high强力"""
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
return
mode = self.fps_drc_mode_combo.currentData()
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = SET_FPS_DRC_MODE
data[2] = mode
mode_name = self.fps_drc_mode_combo.currentText()
log_message(LOG_LEVEL_INFO,
f"设置 DRC 压缩模式: {mode_name} (HID 0xBD)...",
self.log_level)
h.write([0x01] + list(data))
QMessageBox.information(self, "已发送", f"DRC模式={mode}\n(0=low, 1=high)")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"设置 DRC 压缩模式时出错: {str(e)}", self.log_level)
def on_get_fps_drc_mode(self):
"""读取 DRC 压缩模式HID 0xBE"""
if self.device_combo.currentData() is None:
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
return
try:
import time
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = GET_FPS_DRC_MODE
log_message(LOG_LEVEL_INFO, "读取 DRC 压缩模式 (HID 0xBE)...", self.log_level)
h.write([0x01] + list(data))
time.sleep(0.05)
reply = h.get_input_report(0x01, 64)
if (reply and len(reply) == 64 and reply[0] == 0x01
and reply[1] == 0x77 and reply[2] == GET_FPS_DRC_MODE):
mode = reply[3]
idx = self.fps_drc_mode_combo.findData(mode)
if idx >= 0:
self.fps_drc_mode_combo.setCurrentIndex(idx)
log_message(LOG_LEVEL_INFO, f"DRC 压缩模式: {mode} (0=low, 1=high)", self.log_level)
QMessageBox.information(self, "DRC 压缩模式", f"mode={mode}\n(0=low, 1=high)")
else:
log_message(LOG_LEVEL_ERROR, "未收到有效的 0xBE 响应", self.log_level)
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"读取 DRC 压缩模式时出错: {str(e)}", self.log_level)
def on_set_fps_eq_mode(self):
"""设置 fps_eq 预设模式 0-4HID 0xB7"""
if self.device_combo.currentData() is None:
return
mode = self.fps_eq_mode_spin.value()
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
data = bytearray(63)
data[0] = 0x77
data[1] = SET_FPS_EQ_MODE
data[2] = mode
h.write([0x01] + list(data))
h.close()
QMessageBox.information(self, "已发送", f"fps_eq 模式已设为 {mode}")
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"设置 fps_eq 模式失败: {e}", self.log_level)
def on_get_fps_eq_mode(self):
"""读取 fps_eq 当前模式HID 0xB8"""
if self.device_combo.currentData() is None:
return
try:
import time
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = GET_FPS_EQ_MODE
h.write([0x01] + list(data))
time.sleep(0.05)
reply = h.get_input_report(0x01, 64)
if (reply and len(reply) >= 4 and reply[0] == 0x01
and reply[1] == 0x77 and reply[2] == GET_FPS_EQ_MODE):
mode = reply[3]
self.fps_eq_mode_spin.setValue(mode)
QMessageBox.information(self, "fps_eq 模式", f"当前模式: {mode}")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"读取 fps_eq 模式失败: {e}", self.log_level)
def on_set_fps_eq_mode_name(self):
"""设置 fps_eq 模式名称HID 0xBB"""
if self.device_combo.currentData() is None:
return
mode = self.fps_eq_mode_spin.value()
mode_name = self.fps_eq_mode_name_edit.text().strip()
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
data = bytearray(63)
data[0] = 0x77
data[1] = SET_FPS_EQ_MODE_NAME
data[2] = mode
encoded = mode_name.encode('utf-8', errors='ignore')[:15]
data[3:3 + len(encoded)] = encoded
data[3 + len(encoded)] = 0x00
h.write([0x01] + list(data))
h.close()
QMessageBox.information(self, "已发送", f"模式{mode} 名称已设置为: {mode_name}")
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"设置 fps_eq 模式名失败: {e}", self.log_level)
def on_get_fps_eq_mode_name(self):
"""读取 fps_eq 模式名称HID 0xBC"""
if self.device_combo.currentData() is None:
return
mode = self.fps_eq_mode_spin.value()
try:
import time
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = GET_FPS_EQ_MODE_NAME
data[2] = mode
h.write([0x01] + list(data))
time.sleep(0.05)
reply = h.get_input_report(0x01, 64)
log_message(LOG_LEVEL_DEBUG, f"0xBC响应原始数据: {' '.join(f'0x{byte:02x}' for byte in reply[:16])}", self.log_level)
if (reply and len(reply) >= 20 and reply[0] == 0x01
and reply[1] == 0x77 and reply[2] == GET_FPS_EQ_MODE_NAME):
resp_mode = reply[3]
raw_name = bytes(reply[4:20]).split(b'\x00', 1)[0]
log_message(LOG_LEVEL_DEBUG, f"raw_name: {raw_name}", self.log_level)
mode_name = raw_name.decode('utf-8', errors='ignore')
self.fps_eq_mode_spin.setValue(resp_mode if resp_mode <= 4 else 0)
self.fps_eq_mode_name_edit.setText(mode_name)
QMessageBox.information(self, "fps_eq 模式名", f"模式{resp_mode} 名称: {mode_name}")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"读取 fps_eq 模式名失败: {e}", self.log_level)
def on_set_fps_eq_band_gain(self):
"""设置当前模式单段增益HID 0xB9"""
if self.device_combo.currentData() is None:
return
band = self.fps_eq_band_spin.value()
gain = self.fps_eq_gain_spin.value()
try:
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
data = bytearray(63)
data[0] = 0x77
data[1] = SET_FPS_EQ_BAND_GAIN
data[2] = band
data[3] = gain & 0xFF
data[4] = (gain >> 8) & 0xFF
h.write([0x01] + list(data))
h.close()
QMessageBox.information(self, "已发送", f"band={band}, gain={gain} (0.01dB)")
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"设置 fps_eq 频段失败: {e}", self.log_level)
def on_get_fps_eq_band_gain(self):
"""读取当前模式单段增益HID 0xBA"""
if self.device_combo.currentData() is None:
return
band = self.fps_eq_band_spin.value()
try:
import time
device_info = self.device_combo.currentData()
h = hid.device()
h.open(device_info['vendor_id'], device_info['product_id'])
h.set_nonblocking(1)
data = bytearray(63)
data[0] = 0x77
data[1] = GET_FPS_EQ_BAND_GAIN
data[2] = band
h.write([0x01] + list(data))
time.sleep(0.05)
reply = h.get_input_report(0x01, 64)
# 改动原因64字节含ReportID[0]=0x01协议载荷从[1]起77 BA band gain_lo gain_hi
if (reply and len(reply) >= 6 and reply[0] == 0x01
and reply[1] == 0x77 and reply[2] == GET_FPS_EQ_BAND_GAIN):
resp_band = reply[3]
gain = struct.unpack('<h', bytes(reply[4:6]))[0]
self.fps_eq_gain_spin.setValue(gain)
QMessageBox.information(
self, "fps_eq 增益",
f"band={resp_band}, gain={gain} (0.01dB)")
h.close()
except Exception as e:
log_message(LOG_LEVEL_ERROR, f"读取 fps_eq 频段失败: {e}", self.log_level)
def on_browse_firmware(self):
"""浏览选择固件文件"""
# 改动原因:打开文件对话框选择固件文件
@@ -3720,7 +4235,7 @@ eq_mode_data_t sEQ_data_{int(fs)}HZ[NUM_EQ_MODES][NUM_EQ_CHANS] = {{
改动原因:实现可靠的响应等待机制,确保每个命令发送后都等待设备响应后再继续
参数:
h: HID设备对象
expected_cmd: 期望的命令码如0xA7, 0xA8等)
expected_cmd: 期望的命令码如0xBF, 0xC0等)
timeout: 超时时间(秒)
max_retries: 最大重试次数
返回:

View File

@@ -94,11 +94,7 @@ static int get_sample_rate_index(uint32_t sample_rate) {
*/
static eq_mode_data_t (*get_eq_array_ptr(uint32_t sample_rate))[NUM_EQ_MODES][NUM_EQ_CHANS] {
// 改动原因所有采样率共用44100Hz数组
#if !UAC1
return &sEQ_data_44100HZ;
#else
return 0;
#endif
}
/**
@@ -170,6 +166,7 @@ int eq_flash_init(void) {
while (retry_count < 3 && lfs_init_result != 0) {
lfs_init_result = lfs_init();
if (lfs_init_result != 0) {
lfs_deinit(); // 释放session锁避免下次循环自死锁
retry_count++;
DPRINTF("Failed to initialize LFS, retry %d/3\n", retry_count);
if (retry_count < 3) {
@@ -233,6 +230,13 @@ int eq_flash_load_mode(uint8_t mode) {
DPRINTF(" Error: Invalid mode %d (max: %d)\n", mode, NUM_EQ_MODES - 1);
return -1;
}
// 改动原因模式扩展后0-12为固化预设曲线不允许被Flash历史数据覆盖。
// 仅用户模式(13-14)从Flash加载避免旧版本遗留mode7/8/9文件覆盖新预设导致读回曲线异常如32Hz/0dB直线
if (mode < EQ_USER_MODE_MIN) {
DPRINTF(" Mode %d is preset mode, skip Flash override and keep built-in preset parameters\n", mode);
return 0;
}
// 获取当前采样率的EQ数组指针
eq_mode_data_t (*eq_array)[NUM_EQ_MODES][NUM_EQ_CHANS] = get_eq_array_ptr(g_eq_sample_rate);
@@ -240,7 +244,14 @@ int eq_flash_load_mode(uint8_t mode) {
DPRINTF(" Error: Failed to get EQ array for current sample rate %lu\n", (unsigned long)g_eq_sample_rate);
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// user_func.c通过load_eq_mode_from_flash()调用此函数,此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_flash_load_mode\n");
return -1;
}
// 加载左右两个声道的数据
for (int ch = 0; ch < NUM_EQ_CHANS; ch++) {
// 构建文件路径
@@ -434,7 +445,8 @@ int eq_flash_load_mode(uint8_t mode) {
DPRINTF(" Successfully loaded EQ parameters for mode %d, channel %d\n", mode, ch);
}
lfs_deinit();
return 0;
}
@@ -818,7 +830,14 @@ int eq_save_dirty_params(void) {
DPRINTF(" Error: Flash storage not initialized\n");
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// audiohw.xc直接调用此函数但之前没有会话保护可能与其他core的Flash操作冲突。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_save_dirty_params\n");
return -1;
}
//DPRINTF(" Single param database count: %d\n", single_param_database.param_count);
int saved_count = 0;
@@ -859,6 +878,7 @@ int eq_save_dirty_params(void) {
if (saved_count > 0) {
DPRINTF(" Saved %d dirty single parameters\n", saved_count);
}
lfs_deinit();
return 0;
}
/**
@@ -877,14 +897,23 @@ int eq_save_dirty_gain(void) {
return 0;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// audiohw.xc直接调用此函数此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_save_dirty_gain\n");
return -1;
}
DPRINTF(" Saving dirty gain\n");
// 使用新的独立保存函数
if (eq_save_gain() == 0) {
gain_dirty = 0; // 只清除增益脏标志
DPRINTF(" Successfully saved gain\n");
lfs_deinit();
return 0;
} else {
DPRINTF(" Error: Failed to save gain\n");
lfs_deinit();
return -1;
}
}
@@ -904,6 +933,13 @@ int eq_save_dirty_names(void) {
return 0;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// audiohw.xc直接调用此函数此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_save_dirty_names\n");
return -1;
}
DPRINTF(" Saving dirty mode names\n");
// 使用新的独立保存函数逐个保存每个用户模式的name
int saved_count = 0;
@@ -923,12 +959,15 @@ int eq_save_dirty_names(void) {
if (saved_count > 0) {
DPRINTF(" Successfully saved %d mode name(s), skipped %d\n", saved_count, skipped_count);
lfs_deinit();
return 0;
} else if (skipped_count > 0) {
DPRINTF(" All mode names skipped (same as default or empty), %d skipped\n", skipped_count);
lfs_deinit();
return 0; // 跳过是正常的,不算错误
} else {
DPRINTF(" Error: Failed to save mode names\n");
lfs_deinit();
return -1;
}
}
@@ -1081,6 +1120,13 @@ int eq_save_name(uint8_t mode) {
int eq_save_gain_and_names(void) {
int ret = 0;
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// 此函数为公共API调用了eq_save_gain和eq_save_name均直接操作Flash必须提供会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_save_gain_and_names\n");
return -1;
}
// 保存gain
if (eq_save_gain() != 0) {
ret = -1;
@@ -1095,6 +1141,7 @@ int eq_save_gain_and_names(void) {
// result == 1 表示跳过,这是正常的
}
lfs_deinit();
return ret;
}
@@ -1260,6 +1307,13 @@ int eq_load_name(uint8_t mode) {
int eq_load_gain_and_names(void) {
int ret = 0;
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// dsp_core0.xc在eq_flash_init()完成(释放锁)后直接调用此函数,此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_load_gain_and_names\n");
return -1;
}
// 加载gain
if (eq_load_gain() != 0) {
ret = -1; // 文件不存在是正常的,使用默认值
@@ -1273,6 +1327,7 @@ int eq_load_gain_and_names(void) {
}
DPRINTF("Successfully loaded gain and mode names\n");
lfs_deinit();
return ret;
}
@@ -1300,7 +1355,14 @@ int eq_load_all_params_and_calculate_coefficients(uint32_t sample_rate, uint8_t
DPRINTF(" Error: Failed to get EQ array for sample rate %u\n", sample_rate);
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// dsp_core0.xc在eq_flash_init()完成后直接调用此函数,此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_load_all_params_and_calculate_coefficients\n");
return -1;
}
int loaded_count = 0;
// 简化加载逻辑只从44100Hz channel 0加载参数然后应用到所有采样率和通道
@@ -1313,7 +1375,8 @@ int eq_load_all_params_and_calculate_coefficients(uint32_t sample_rate, uint8_t
//DPRINTF(" Loaded %d single parameters and calculated coefficients for mode %d\n",
// loaded_count, mode);
lfs_deinit();
return 0;
}
@@ -1367,7 +1430,14 @@ int eq_flash_save_mode(uint8_t mode) {
DPRINTF(" Error: Failed to get EQ array for current sample rate %lu\n", (unsigned long)g_eq_sample_rate);
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// 此前该函数直接调用lfs_write_config而无会话保护多core同时访问会导致数据损坏。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_flash_save_mode\n");
return -1;
}
// 保存左右两个声道的数据
for (int ch = 0; ch < NUM_EQ_CHANS; ch++) {
// 构建文件路径
@@ -1421,7 +1491,8 @@ int eq_flash_save_mode(uint8_t mode) {
#endif
DPRINTF(" Successfully saved EQ parameters for mode %d, channel %d\n", mode, ch);
}
lfs_deinit();
return 0;
}
@@ -1604,7 +1675,14 @@ int delete_flash_eq_params(uint8_t mode) {
DPRINTF(" Error: Flash storage not initialized\n");
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// eq.c的reset_eq_params()直接调用此函数,此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in delete_flash_eq_params\n");
return -1;
}
int deleted_count = 0;
if (mode == 0xFF) {
@@ -1646,6 +1724,7 @@ int delete_flash_eq_params(uint8_t mode) {
}
DPRINTF(" Deleted %d parameter files\n", deleted_count);
lfs_deinit();
return 0;
}
@@ -1656,7 +1735,7 @@ int delete_flash_eq_params(uint8_t mode) {
*
* 改动原因:修改为按模式删除,只删除指定模式的增益和名称,而不是删除所有文件
* - 如果mode == 0xFF删除所有用户模式的增益和名称文件
* - 如果mode是用户模式(6-8),只删除该模式的名称文件,并将该模式的增益恢复为默认值(0)
* - 如果mode是用户模式(13-14),只删除该模式的名称文件,并将该模式的增益恢复为默认值(0)
* - 如果mode是预设模式(0-5)不需要删除预设模式的增益和名称不存储在Flash中
*/
int delete_flash_gain_and_names(uint8_t mode) {
@@ -1666,7 +1745,14 @@ int delete_flash_gain_and_names(uint8_t mode) {
DPRINTF(" Error: Flash storage not initialized\n");
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// eq.c的reset_eq_params()直接调用此函数,此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in delete_flash_gain_and_names\n");
return -1;
}
// 处理删除所有模式的情况
if (mode == 0xFF) {
DPRINTF(" Deleting all user mode gains and names\n");
@@ -1693,23 +1779,26 @@ int delete_flash_gain_and_names(uint8_t mode) {
}
}
}
lfs_deinit();
return 0;
}
// 检查模式有效性
if (mode >= NUM_EQ_MODES) {
DPRINTF(" Error: Invalid mode %d\n", mode);
lfs_deinit();
return -1;
}
// 预设模式(0-5)的增益和名称不存储在Flash中不需要删除
if (mode < EQ_USER_MODE_MIN) {
DPRINTF(" Mode %d is a preset mode, no Flash data to delete\n", mode);
lfs_deinit();
return 0;
}
// 只处理用户模式(6-8)
// 只处理用户模式(13-14)
if (mode >= EQ_USER_MODE_MIN && mode <= EQ_USER_MODE_MAX) {
// 删除该模式的名称文件
char file_path[FILE_PATH_MAX_LENGTH];
@@ -1763,12 +1852,14 @@ int delete_flash_gain_and_names(uint8_t mode) {
} else {
DPRINTF(" Gains file does not exist: %s\n", file_path);
}
lfs_deinit();
return 0;
}
// 其他模式如模式9不需要处理
DPRINTF(" Mode %d does not require Flash data deletion\n", mode);
lfs_deinit();
return 0;
}
@@ -1864,7 +1955,14 @@ int eq_flash_save_eq_enable(uint8_t enable)
DPRINTF(" Error: Invalid EQ enable value %d (valid range: 0-1)\n", enable);
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// 此前该函数直接调用lfs_write_config而无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_flash_save_eq_enable\n");
return -1;
}
// 构建独立文件路径
// 改动原因使用独立的文件名存储eq_enable与模式存储完全分离
char file_path[FILE_PATH_MAX_LENGTH];
@@ -1891,6 +1989,7 @@ int eq_flash_save_eq_enable(uint8_t enable)
// 写入文件
lfs_write_config(file_path, file_data, sizeof(file_data));
DPRINTF(" Successfully saved EQ enable %d to Flash (independent file: %s)\n", enable, file_path);
lfs_deinit();
return 0;
}
@@ -1911,11 +2010,19 @@ int eq_flash_save_current_mode(uint8_t mode)
}
// 验证模式值范围
if (mode > 9) {
DPRINTF(" Error: Invalid mode %d (valid range: 0-9)\n", mode);
// 改动原因EQ模式数量扩展到15允许保存模式范围0-14。
if (mode >= NUM_EQ_MODES) {
DPRINTF(" Error: Invalid mode %d (valid range: 0-%d)\n", mode, NUM_EQ_MODES - 1);
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥
// 防止多core并发访问导致数据损坏。此前该函数直接调用lfs_write_config而无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_flash_save_current_mode\n");
return -1;
}
// 构建独立文件路径
// 改动原因使用独立的文件名存储模式与eq_enable存储完全分离
char file_path[FILE_PATH_MAX_LENGTH];
@@ -1942,6 +2049,7 @@ int eq_flash_save_current_mode(uint8_t mode)
// 写入文件
lfs_write_config(file_path, file_data, sizeof(file_data));
DPRINTF(" Successfully saved EQ mode %d to Flash (independent file: %s)\n", mode, file_path);
lfs_deinit();
return 0;
}
@@ -1961,10 +2069,17 @@ int eq_flash_load_current_mode(void)
DPRINTF(" Error: Flash storage not initialized\n");
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// dsp_core0.xc在eq_flash_init()完成后直接调用此函数,此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_flash_load_current_mode\n");
return -1;
}
// 加载模式(从独立文件)
char mode_file_path[FILE_PATH_MAX_LENGTH];
snprintf(mode_file_path, sizeof(mode_file_path), "%s", g_eq_flash_mode_file);
snprintf(mode_file_path, sizeof(mode_file_path), "%s/%s", g_eq_flash_base_dir, g_eq_flash_mode_file);
if (lfs_file_exists(mode_file_path)) {
eq_file_header_t header;
@@ -1976,7 +2091,8 @@ int eq_flash_load_current_mode(void)
mode = file_header_data[sizeof(header)];
// 验证模式值范围
if (mode > 9) {
// 改动原因EQ模式数量扩展到15加载时按NUM_EQ_MODES校验范围0-14
if (mode >= NUM_EQ_MODES) {
DPRINTF(" Error: Invalid mode value %d in file\n", mode);
mode = 0; // 使用默认值
} else {
@@ -2001,7 +2117,7 @@ int eq_flash_load_current_mode(void)
// 加载使能状态(从独立文件)
char enable_file_path[FILE_PATH_MAX_LENGTH];
snprintf(enable_file_path, sizeof(enable_file_path), "%s", g_eq_flash_enable_file);
snprintf(enable_file_path, sizeof(enable_file_path), "%s/%s", g_eq_flash_base_dir, g_eq_flash_enable_file);
if (lfs_file_exists(enable_file_path)) {
eq_file_header_t header;
@@ -2041,6 +2157,7 @@ int eq_flash_load_current_mode(void)
g_eq_enable = eq_enable;
DPRINTF(" Successfully loaded mode %d and EQ enable %d from Flash (independent files)\n", mode, eq_enable);
lfs_deinit();
return mode;
}
@@ -2059,7 +2176,14 @@ int eq_flash_load_eq_enable(void)
DPRINTF(" Error: Flash storage not initialized\n");
return -1;
}
// 改动原因所有Flash I/O必须在lfs_init()/lfs_deinit()会话内执行确保QSPI Flash访问互斥。
// 此函数为公共API直接进行Flash读操作此前无会话保护。
if (lfs_init() != 0) {
DPRINTF(" Error: Failed to open flash session in eq_flash_load_eq_enable\n");
return -1;
}
// 加载使能状态(从独立文件)
char enable_file_path[FILE_PATH_MAX_LENGTH];
snprintf(enable_file_path, sizeof(enable_file_path), "%s", g_eq_flash_enable_file);
@@ -2102,6 +2226,7 @@ int eq_flash_load_eq_enable(void)
g_eq_enable = eq_enable;
DPRINTF(" Successfully loaded EQ enable %d from Flash (independent file)\n", eq_enable);
lfs_deinit();
return eq_enable;
}

View File

@@ -10,7 +10,7 @@
#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_MODES 15 // 最大模式数量改动原因EQ模式扩展至15
#define EQ_FLASH_MAX_CHANNELS 2 // 最大通道数量
// 支持的采样率列表
@@ -46,9 +46,9 @@ typedef struct {
uint32_t crc32; // CRC32校验
} __attribute__((packed)) eq_gain_header_t;
// 模式增益数据(只存储用户模式6-8
// 模式增益数据(只存储用户模式13-14
typedef struct {
int32_t mode_gains[3]; // 用户模式增益数组mode 6, 7, 8每个4字节
int32_t mode_gains[2]; // 用户模式增益数组mode 13, 14每个4字节改动原因用户模式由3个减为2个
} __attribute__((packed)) eq_gain_data_t;
// 单个模式名称存储结构

View File

@@ -16,7 +16,7 @@
| 0x8F | GET_DEVICE_INFO | 获取设备信息 | 主机→设备 | 读取设备PID、VID、产品字符串等信息 |
| 0x90 | RESET_EQ_PARAMS | 复位EQ参数 | 主机→设备 | 删除Flash中的EQ参数并恢复头文件预设参数 |
| 0x91 | GET_EQ_MODE_COUNT | 获取EQ模式总数 | 主机→设备 | 返回预定义加用户模式的总数(不包含禁用模式) |
| 0x92 | SET_AND_SAVE_EQ_MODE | 设置并保存EQ模式 | 主机→设备 | 设置当前EQ模式(0-9)并保存到Flash开机时自动恢复 |
| 0x92 | SET_AND_SAVE_EQ_MODE | 设置并保存EQ模式 | 主机→设备 | 设置当前EQ模式(0-14)并保存到Flash开机时自动恢复 |
| 0x93 | SET_VOLUME | 设置音量级别 | 主机→设备 | 设置设备音量级别0-255 |
| 0x94 | GET_VOLUME | 获取音量级别 | 主机→设备 | 读取设备当前音量级别0-255 |
| 0x95 | GET_LED_INFO | 获取LED信息 | 主机→设备 | 读取LED索引和LED名称 |
@@ -37,13 +37,30 @@
| 0xA4 | SET_GAME_MODE | 设置游戏模式 | 主机→设备 | 设置游戏模式0=无音效1=FPS2=虚拟7.1 |
| 0xA5 | GET_GAME_MODE | 获取游戏模式 | 主机→设备 | 读取当前游戏模式0-2 |
| 0xA6 | GET_FIRMWARE_VERSION | 获取固件版本 | 主机→设备 | 读取设备固件版本号BCD格式主版本.次版本.修订版本) |
| 0xB0 | SET_INPUT_SOURCE | 设置输入源模式 | 主机→设备 | 设置输入源模式0=USB, 1=OPT, 2=COAX通过UART 0x5D透传给MCU |
| 0xB1 | SET_MUTE_SWITCH | 设置静音开关 | 主机→设备 | 设置静音开关0=关1=开通过UART 0x5E透传给MCU |
| 0xB2 | GET_MUTE_SWITCH | 获取静音开关状态 | 主机→设备 | 读取静音开关状态0=关1=开设备通过串口向MCU请求后返回 |
| 0xB3 | SET_LISTEN_SWITCH | 设置监听开关 | 主机→设备 | 设置监听开关0=关1=开通过UART 0x60透传给MCU |
| 0xB4 | GET_LISTEN_SWITCH | 获取监听开关状态 | 主机→设备 | 读取监听开关状态0=关1=开),直接返回 g_adc_loop 的值,不经过串口 |
| 0xB6 | SET_TILE1_DIV | 设置tile1动态降频分频值 | 主机→设备 | 设置tile1低功耗分频值Ncore clock=600MHz/N仅FPS镜像(C1_DFS_EN)生效tile1空闲时降频 |
| 0xB7 | GET_TILE1_DIV | 获取tile1动态降频分频值 | 主机→设备 | 读取当前tile1低功耗分频值N动态降频仅FPS镜像(C1_DFS_EN)生效 |
| 0xA7 | FIRMWARE_UPGRADE_START | 开始固件升级 | 主机→设备 | 初始化升级流程,设置固件大小(与 eq_hid_protocol_ds1 一致) |
| 0xA8 | FIRMWARE_UPGRADE_DATA | 传输固件数据块 | 主机→设备 | 固定57字节数据块 |
| 0xA9 | FIRMWARE_UPGRADE_END | 结束固件升级 | 主机→设备 | 验证镜像 |
| 0xAA | FIRMWARE_UPGRADE_STATUS | 获取升级状态 | 主机→设备 | 进度与状态 |
| 0xAB | FIRMWARE_UPGRADE_ABORT | 中止固件升级 | 主机→设备 | 中止并清理 |
| 0xAC | FIRMWARE_UPGRADE_ERASE | 擦除升级镜像 | 主机→设备 | 擦除 Flash 升级区 |
| 0xAE | DEVICE_REBOOT | 设备重启 | 主机→设备 | 通用重启命令 |
| 0xB0 | SET_INPUT_SOURCE | 设置输入源模式 | 主机→设备 | 设置输入源模式0=USB, 1=OPT, 2=COAXtile0 经 sync 0x04 到 tile1 发 UART 0x5D 透传 MCU |
| 0xB1 | SET_MUTE_SWITCH | 设置静音开关 | 主机→设备 | 设置静音开关0=关1=开tile0 经 sync 0x05 到 tile1 发 UART 0x5E 透传 MCU |
| 0xB2 | GET_MUTE_SWITCH | 获取静音开关状态 | 主机→设备 | 读取静音开关状态0=关1=开tile0 经 sync 0x06 让 tile1 向 MCU 发 0x5FMCU 返回后 tile1 经 sync 0x0E 回传静音值 |
| 0xB3 | SET_LISTEN_SWITCH | 设置监听开关 | 主机→设备 | 设置监听开关0=关1=开tile0 经 sync 0x07 到 tile1 发 UART 0x60 透传 MCU |
| 0xB4 | GET_LISTEN_SWITCH | 获取监听开关状态 | 主机→设备 | 读取监听开关状态0=关1=开),直接返回 tile0 的 g_adc_loop 值(由 tile1 经 sync 0x0D 同步),不经过串口 |
| 0xB5 | SET_FPS_MODULE_ENABLE | 设置FPS库子模块使能 | 主机→设备 | 设置DRC/FPS主处理/fps_eq使能(0=旁路,1=开启)tile0存Flash后经sync 0x08同步tile1 |
| 0xB6 | GET_FPS_MODULE_ENABLE | 获取FPS库子模块使能 | 主机→设备 | 从Flash读取三模块使能状态(0/1) |
| 0xB7 | SET_FPS_EQ_MODE | 设置fps_eq预设模式 | 主机→设备 | 模式0-4(共5套)默认0tile0写Flash后sync 0x09到tile1加载该模式10段增益 |
| 0xB8 | GET_FPS_EQ_MODE | 获取fps_eq当前模式 | 主机→设备 | 返回当前模式0-4 |
| 0xB9 | SET_FPS_EQ_BAND_GAIN | 设置当前模式单段增益 | 主机→设备 | band(0-9)+gain int16 LE(0.01dB,-600~600)tile0存Flashsync 0x0A到tile1调用eq_set_band_gain |
| 0xBA | GET_FPS_EQ_BAND_GAIN | 获取当前模式单段增益 | 主机→设备 | 请求band(0-9)返回gain int16 LE |
| 0xBB | SET_FPS_EQ_MODE_NAME | 设置fps_eq模式名称 | 主机→设备 | 设置模式0-4的名称(16字节含\0截断)tile0写Flash断电保存 |
| 0xBC | GET_FPS_EQ_MODE_NAME | 获取fps_eq模式名称 | 主机→设备 | 请求模式0-4返回该模式16字节名称 |
| 0xBD | SET_FPS_DRC_MODE | 设置DRC压缩模式 | 主机→设备 | mode 0=low柔和压缩、1=high强力压缩默认0tile0存Flash后经sync 0x0C同步tile1 |
| 0xBE | GET_FPS_DRC_MODE | 获取DRC压缩模式 | 主机→设备 | 返回当前DRC压缩模式(0/1) |
| 0xBF | SET_FPS_XMOS_GAME_SELECT | 设置FPS XMOS游戏与增益 | 主机→设备 | 设置game(0-2)及该game绑定的level(0-4)每种game单独存level(fps_level_g0/g1/g2)默认level为2 |
| 0xC0 | GET_FPS_XMOS_GAME_SELECT | 获取指定game的level | 主机→设备 | 请求字节2指定game(0-2)返回该game及其在Flash中保存的level(0-4) |
### 1.3 数据包格式
- **Report ID**: 0x01 (HID报告ID)
@@ -62,7 +79,7 @@
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8A | 命令码
2 | 1 | uint8 | 模式值 (0-5: 预设模式, 6-8: 用户模式, 9: bypass)
2 | 1 | uint8 | 模式值 (0-12: 预设模式, 13-14: 用户模式, 15: 禁用EQ)
3-62 | 60 | 0x00 | 保留字节
```
@@ -76,13 +93,13 @@
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8B | 命令码
2 | 1 | uint8 | 模式值 (0-9: 有效模式值, 0xFF: 获取当前模式信息)
2 | 1 | uint8 | 模式值 (0-14: 有效模式值, 0xFF: 获取当前模式信息)
3-62 | 60 | 0x00 | 保留字节
```
**设备端处理**:
- 如果mode值为0xFF返回当前模式值、整体增益和模式名称
- 如果mode值为有效模式值(0-9),返回指定模式值、整体增益和模式名称
- 如果mode值为有效模式值(0-14),返回指定模式值、整体增益和模式名称
@@ -101,7 +118,7 @@
**使用说明**:
- 发送mode=0xFF时返回当前激活的EQ模式信息
- 发送mode=0-9时,返回指定模式的增益和名称信息(不切换当前模式)
- 发送mode=0-14时,返回指定模式的增益和名称信息(不切换当前模式)
### 2.3 0x8C - SET_MODE_GAIN_AND_NAME (设置模式整体增益和名称)
**功能**: 设置EQ模式整体增益和名称
@@ -112,7 +129,7 @@
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8C | 命令码
2 | 1 | uint8 | 模式值 (0-9)
2 | 1 | uint8 | 模式值 (0-14)
3-6 | 4 | int32 | 增益值 (范围0到-50dB有符号整数)
7-22 | 16 | char | 模式名称 (UTF-8编码16字节)
23-62 | 40 | 0x00 | 保留字节
@@ -132,7 +149,7 @@
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8D | 命令码
2 | 1 | uint8 | 模式值 (0-9)
2 | 1 | uint8 | 模式值 (0-14)
3 | 1 | uint8 | 滤波器Band索引 (0-7)
4 | 1 | uint8 | 滤波器类型
5-8 | 4 | float | 中心频率 (Hz)
@@ -166,7 +183,7 @@
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8E | 命令码
2 | 1 | uint8 | 模式值 (0-9)
2 | 1 | uint8 | 模式值 (0-14)
3 | 1 | uint8 | EQ索引 (0-7)
4-62 | 59 | 0x00 | 保留字节
```
@@ -178,7 +195,7 @@
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x8E | 同步头2
3 | 1 | uint8 | 模式值 (0-9)
3 | 1 | uint8 | 模式值 (0-14)
4 | 1 | uint8 | 滤波器Band索引 (0-7)
5 | 1 | uint8 | 滤波器类型
6-9 | 4 | float | 中心频率 (Hz)
@@ -224,7 +241,7 @@
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x90 | 命令码
2 | 1 | uint8 | 模式号 (0-9, 0xFF表示恢复所有包括EQ参数总体增益模式名称 )
2 | 1 | uint8 | 模式号 (0-14, 0xFF表示恢复所有包括EQ参数总体增益模式名称 )
3-62 | 60 | 0x00 | 保留字节
```
@@ -258,8 +275,8 @@
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x91 | 同步头2
3 | 1 | uint8 | 模式总数 (当前为9包含0-8共9个模式,不包含禁用模式)
4 | 1 | uint8 | 预定义模式数量 (当前为6包含0-5共6个预设模式)
3 | 1 | uint8 | 模式总数 (当前为15包含0-14共15个模式,不包含禁用模式15)
4 | 1 | uint8 | 预定义模式数量 (当前为13包含0-12共13个预设模式)
5-62 | 58 | 0x00 | 保留字节
```
@@ -272,7 +289,7 @@
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x92 | 命令码
2 | 1 | uint8 | 模式值 (0-9: 0-5预设模式, 6-8用户模式, 9: bypass)
2 | 1 | uint8 | 模式值 (0-14: 0-12预设模式, 13-14用户模式, 15=禁用EQ)
3-62 | 60 | 0x00 | 保留字节
```
@@ -665,7 +682,7 @@
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x9E | 同步头2
3 | 1 | uint8 | EQ使能开关状态 (0=OFF禁用, 1=ON启用)
4 | 1 | uint8 | 保存的模式值 (0-9如果之前有保存0xFF表示未保存)
4 | 1 | uint8 | 保存的模式值 (0-14如果之前有保存0xFF表示未保存)
5-62 | 58 | 0x00 | 保留字节
```
@@ -863,9 +880,221 @@
- 3个字节分别表示主版本号、次版本号、修订版本号
- 例如0x01 0x00 0x0C 表示版本 1.0.12
### 2.30 0xB0 - SET_INPUT_SOURCE (设置输入源模式)
**功能**: 设置输入源模式USB/OPT/COAX通过UART 0x5D命令透传给MCU处理
**方向**: 主机→设备(XMOS)→MCU
### 2.30 0xB5 - SET_FPS_MODULE_ENABLE (设置FPS库 DRC / FPS主处理 / fps_eq 使能)
**功能**: 设置 FPS 算法库三个子模块的运行时开关,对应 `fps_xmos_xc_set_module_enable(drc_enable, fps_enable, eq_enable)`。0=旁路非0=开启。
**方向**: 主机→设备(tile0)→tile1
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB5 | 命令码
2 | 1 | uint8 | drc_enable (0/1)
3 | 1 | uint8 | fps_enableFPS主处理子模块 (0/1)
4 | 1 | uint8 | eq_enablefps_eq子模块 (0/1)
5-62 | 58 | 0x00 | 保留字节
```
**Flash 存储**:
- `fps_drc_enable` / `fps_sub_enable` / `fps_eq_enable`:各 0 或 1未存或无效(>1) 时默认 DRC=0、FPS主处理=1、fps_eq=0。
**设备端处理**:
- tile0写 Flash 与共享全局 `g_fps_drc_enable``g_fps_sub_enable``g_fps_eq_enable`
- 打包 `packed = drc | (fps_sub<<8) | (eq<<16)``g_sync_t0_to_t1_cmd=0x08``g_sync_t0_to_t1_data=packed`
- tile1解包后调用 `fps_apply_module_enable()``fps_xmos_xc_set_module_enable()`
**上电恢复**: `SYNC_CMD_LOAD_CONFIGS` 中从 Flash 读取三键并触发 sync 0x08。
### 2.31 0xB6 - GET_FPS_MODULE_ENABLE (获取FPS库子模块使能)
**功能**: 读取 DRC / FPS主处理 / fps_eq 当前使能状态(来自 tile0 运行时全局 `g_fps_*`,与 0xB5 写入一致,避免紧接读 Flash 滞后)。
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB6 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xB6 | 同步头2
3 | 1 | uint8 | drc_enable (0/1)
4 | 1 | uint8 | fps_enable (0/1)
5 | 1 | uint8 | eq_enable (0/1)
6-62 | 57 | 0x00 | 保留字节
```
### 2.32 0xBD - SET_FPS_DRC_MODE (设置 DRC 压缩模式)
**功能**: 设置 FPS 算法库 DRC 压缩强度,对应 `fps_xmos_xc_drc_set_mode(mode)`。0=low柔和压缩1=high强力压缩
**方向**: 主机→设备(tile0)→tile1
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xBD | 命令码
2 | 1 | uint8 | drc_mode (0=low, 1=high)
3-62 | 60 | 0x00 | 保留字节
```
**Flash 键**: `fps_drc_mode`,未存或无效(>1) 时默认 **0**low
### 2.33 0xBE - GET_FPS_DRC_MODE (获取 DRC 压缩模式)
**功能**: 读取当前 DRC 压缩模式(来自 tile0 运行时全局 `g_fps_drc_mode`,与 0xBD 写入一致)。
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xBE | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xBE | 同步头2
3 | 1 | uint8 | drc_mode (0=low, 1=high)
4-62 | 59 | 0x00 | 保留字节
```
### 2.34 0xBF - SET_FPS_XMOS_GAME_SELECT (设置FPS XMOS游戏类型与增益等级)
**功能**: 设置当前FPS游戏类型(game)及**该game绑定的**增益等级(level),用于 `fps_xmos_game_select(game, level)`。game 与 level 绑定:三种 game(0/1/2) 各有各自保存的 level(0/1/2/3/4),选择某 game 时使用该 game 对应的 level默认 level 为 2。
**方向**: 主机→设备(XMOS tile0)→tile1
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xBF | 命令码
2 | 1 | uint8 | 游戏类型 game (0/1/2)
3 | 1 | uint8 | 该 game 的增益等级 level (0/1/2/3/4),默认 2
4-62 | 59 | 0x00 | 保留字节
```
**参数说明**:
- **game字节2** 游戏类型0/1/2对应 `fps_xmos_game_select` 的第一个参数。
- **level字节3** 当前选中的 game 的增益等级0/1/2/3/4对应 `fps_xmos_game_select` 的第二个参数。若主机未发或无效(>4),设备按默认 2 处理。
- **绑定关系:** 设置 (game, level) 后,仅该 game 的 level 被更新;切换 game 时(含上电恢复)会查该 game 对应的已保存 level。
**Flash 存储(按 game 分别存 level**:
- `fps_game_select`:当前选中的 game (0/1/2)。
- `fps_level_g0` / `fps_level_g1` / `fps_level_g2`:分别表示 game 0、1、2 的 level (0/1/2/3/4),默认 2。
- 0xBF 设置 (game, level) 时:写入 `fps_game_select=game`,并将 level 写入对应键game 0→fps_level_g0game 1→fps_level_g1game 2→fps_level_g2
- 上电恢复:在 `fps_boot_load_from_flash` 中读 `fps_game_select`,再根据 game 查对应 level读 fps_level_g0/g1/g2得到当前 (game, level) 后同步到 tile1。
**设备端处理**:
- tile0 解析 data[2]=game、data[3]=levellevel 无效(>4) 时按 2。
- 保存:`save_value("fps_game_select", game)`,并按 game 写 `save_value("fps_level_g0"/"fps_level_g1"/"fps_level_g2", level)`
- 打包 `packed_fps = (game<<0) | (level<<8)`,设置 g_sync_t0_to_t1_cmd=0x03、g_sync_t0_to_t1_data=packed_fps更新 g_fps_game_select、g_fps_level_select。
- tile1 解包后设置 g_fps_game_select、g_fps_level_selectfps1_dsp_proc_task 调用 fps_xmos_game_select(game, level)。
**同步机制**:
- HID 0xBF 在 tile0 接收 → 按 game 写入对应 level 键 → 设置 sync 0x03 + packed_fps → tile1 解包并设置 g_fps_game_select、g_fps_level_select → fps1_dsp_proc_task 调用 fps_xmos_game_select(game, level)。
**返回值**:
无直接返回值。当前 game 及该 game 的 level 可用 GET_FPS_XMOS_GAME_SELECT (0xC0) 读取。
### 2.35 0xC0 - GET_FPS_XMOS_GAME_SELECT (获取指定 game 的 level)
**功能**: 按主机指定的 game(0/1/2) 查询该 game 绑定的 level(0/1/2/3/4),返回**指定 game** 及其在 Flash 中保存的 level非当前选中的 game
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xC0 | 命令码
2 | 1 | uint8 | 要查询的 game (0/1/2),不传或无效时设备按 0 处理
3-62 | 60 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xC0 | 同步头2
3 | 1 | uint8 | 请求的 game (0/1/2)
4 | 1 | uint8 | 该 game 绑定的 level (0/1/2/3/4),来自 Flash fps_level_g0/g1/g2
5-62 | 58 | 0x00 | 保留字节
```
**说明**:
- 请求字节2指定要查询的 game未传或 >2 时设备按 game=0 查询。
### 2.36 0xB7 - SET_FPS_EQ_MODE (设置 fps_eq 预设模式)
**功能**: 选择 5 套 fps_eq 增益预设之一(模式 **04**,默认 **0**)。切换后 tile1 对该模式全部 10 段调用 `fps_xmos_xc_eq_set_all_gains`
**数据包**: `[0x77][0xB7][mode]`mode 无效(>4) 拒绝。
**Flash**: 文件 `fps_eq_store`,含 `current_mode``gains[5][10]`,每段默认 **1** (0.01dB)。
**同步**: tile0 写 Flash → 发布共享 pack 字 → `g_sync_t0_to_t1_cmd=0x09`
### 2.35 0xB8 - GET_FPS_EQ_MODE
**响应**: `[0x77][0xB8][mode]`mode 为当前选中模式 04。
### 2.36 0xB9 - SET_FPS_EQ_BAND_GAIN (设置当前模式单段增益)
**功能**: 调节**当前模式**下某一频段增益tile1 调用 `fps_xmos_xc_eq_set_band_gain(band, gain)`
**数据包**:
```
0: 0x77 1: 0xB9 2: band(0-9) 3-4: gain int16 LE (0.01dB, -600~600)
```
tile0 更新 Flash 中 `gains[current_mode][band]`sync **0x0A**
### 2.37 0xBA - GET_FPS_EQ_BAND_GAIN
**请求**: `[0x77][0xBA][band]`
**响应(含 Report ID 的 64 字节 HID 报告)**:
```
字节 | 内容
-----|------
0 | 0x01 Report ID
1 | 0x77
2 | 0xBA
3 | band (0-9)
4-5 | gain int16 小端 (0.01dB, -600~600)
```
主机解析增益应使用 **字节 45**,勿与字节 3band拼接。
### 2.38 0xBB - SET_FPS_EQ_MODE_NAME (设置 fps_eq 模式名称)
**功能**: 设置 fps_eq 预设模式名称(模式 0~4对应 5 套增益)。
**请求格式**:
```
0:0x77 1:0xBB 2:mode(0-4) 3..18:name[16]
```
**说明**:
- 名称最大 15 个可见字符,第 16 字节用于 `\0` 结尾(设备侧强制截断)。
- 名称写入 tile0 Flash (`fps_eq_store`),支持断电保存。
### 2.39 0xBC - GET_FPS_EQ_MODE_NAME (读取 fps_eq 模式名称)
**请求**: `[0x77][0xBC][mode]`
**响应(含 Report ID 的 64 字节 HID 报告)**:
```
字节 | 内容
-----|------
0 | 0x01 Report ID
1 | 0x77
2 | 0xBC
3 | mode(0-4)
4..19| name[16]\0 结尾不足补0
```
### 2.40 0xB0 - SET_INPUT_SOURCE (设置输入源模式)
**功能**: 设置输入源模式0=USB, 1=OPT, 2=COAX
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
@@ -875,161 +1104,61 @@
2 | 1 | uint8 | 输入源模式值 (0=USB, 1=OPT, 2=COAX)
3-62 | 60 | 0x00 | 保留字节
```
**设备端处理c3_fps 双 tile**:
- tile0HID收到 0xB0 后设置 g_sync_t0_to_t1_cmd=0x04、g_sync_t0_to_t1_data=输入源
- tile1 的 app_control_slave 收到 sync 后调用 process_uart_set_input_source构建 UART 0x5D 包透传 MCU
**设备端处理**:
- XMOS设备接收到HID 0xB0命令后将其转换为UART 0x5D命令格式
- 通过UART接口将完整的0x5D数据包透传给MCU
- MCU负责处理输入源切换USB/OPT/COAX
- 本命令不返回HID响应
**透传机制**:
- HID 0xB0命令 → XMOS设备转换为UART 0x5D命令 → 透传给MCU
- UART 0x5D数据包格式0x55 0xAA 0x00 0x5D [长度] [输入源模式值] [校验和]
- MCU根据输入源模式值执行相应的输入切换操作
### 2.31 0xB1 - SET_MUTE_SWITCH (设置静音开关)
**功能**: 设置静音开关0=关1=开通过UART 0x5E命令透传给MCU处理
**方向**: 主机→设备(XMOS)→MCU
### 2.33 0xB1 - SET_MUTE_SWITCH (设置静音开关)
**功能**: 设置静音开关0=关1=开)
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB1 | 命令码
2 | 1 | uint8 | 静音开关值 (0=关1=开)
2 | 1 | uint8 | 静音开关值 (0=关, 1=开)
3-62 | 60 | 0x00 | 保留字节
```
**设备端处理c3_fps 双 tile**:
- tile0 收到 0xB1 后设置 sync 0x05 及数据tile1 调用 process_uart_set_mute_switch发 UART 0x5E 透传 MCU
**设备端处理**:
- XMOS设备接收到HID 0xB1命令后将其转换为UART 0x5E命令格式并透传给MCU
- MCU负责处理静音开关状态
- 本命令不返回HID响应
### 2.34 0xB2 - GET_MUTE_SWITCH (获取静音开关状态)
**功能**: 读取静音开关状态0=关1=开),设备向 MCU 请求后返回
**方向**: 主机→设备
**请求**: 同步头 0x77 + 0xB2 + 保留字节
**响应**: 0x01 0x77 0xB2 + 1 字节静音值 (0=关, 1=开)
**设备端处理c3_fps 双 tile**:
- tile0 收到 0xB2 后置 is_get_mute_switch_request并设置 sync 0x06tile1 调用 process_uart_send_get_mute_request 向 MCU 发 UART 0x5F
- MCU 返回 0x5F+1 字节后tile1 的 user_uart 调用 sync_to_tile0(0x0E, mute_value, 0)tile0 的 audiohw 收到 0x0E 后设置 g_mute_switch
- 主机执行 HID 读时process_read_params 直接读 g_mute_switch 返回。建议发送 0xB2 后延时约 50ms 再执行 HID 读
### 2.32 0xB2 - GET_MUTE_SWITCH (获取静音开关状态)
**功能**: 读取静音开关状态0=关1=开设备通过串口向MCU发送0x5F请求MCU返回状态后设备再通过HID响应返回给主机
**方向**: 主机→设备→MCU→设备→主机
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB2 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**状态变化上报**: 当静音开关状态发生变化(如 MCU 通过 0x5F 返回、tile1 经 sync 0x0E 回传)时,设备会主动通过 HID 上报数据格式与上述响应一致0x77 0xB2 + 1 字节静音值与音量变化上报0x94方式相同。
**设备端处理**:
- 主机发送0xB2后XMOS向MCU发送UART 0x5FGET请求
- MCU返回UART 0x5F响应含静音开关值
- 主机随后通过HID读报告获取响应
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xB2 | 同步头2
3 | 1 | uint8 | 静音开关状态 (0=关1=开)
4-62 | 59 | 0x00 | 保留字节
```
**说明**: 主机发送0xB2后建议稍作延时如50ms再执行HID读以确保MCU已返回数据。
**状态变化上报**: 当静音开关状态发生变化(如 MCU 通过 0x5F 返回新值)时,设备会主动通过 HID 上报数据格式与上述响应一致0x77 0xB2 + 1 字节静音值与音量变化上报0x94方式相同主机可通过 HID 读或中断 IN 获取。
### 2.33 0xB3 - SET_LISTEN_SWITCH (设置监听开关)
**功能**: 设置监听开关0=关1=开通过UART 0x60命令透传给MCU处理
**方向**: 主机→设备(XMOS)→MCU
### 2.35 0xB3 - SET_LISTEN_SWITCH (设置监听开关)
**功能**: 设置监听开关0=关1=开
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB3 | 命令码
2 | 1 | uint8 | 监听开关值 (0=关1=开)
2 | 1 | uint8 | 监听开关值 (0=关, 1=开)
3-62 | 60 | 0x00 | 保留字节
```
**设备端处理c3_fps 双 tile**:
- tile0 收到 0xB3 后设置 sync 0x07 及数据tile1 调用 process_uart_set_listen_switch发 UART 0x60 透传 MCU对应 g_adc_loop 语义)
**设备端处理**:
- XMOS设备接收到HID 0xB3命令后将其转换为UART 0x60命令格式并透传给MCU
- MCU负责处理监听开关对应 g_adc_loop 语义)
- 本命令不返回HID响应
### 2.34 0xB4 - GET_LISTEN_SWITCH (获取监听开关状态)
**功能**: 读取监听开关状态0=关1=开),设备直接返回 g_adc_loop 的值,不经过串口
### 2.36 0xB4 - GET_LISTEN_SWITCH (获取监听开关状态)
**功能**: 读取监听开关状态0=关1=开),直接返回 g_adc_loop 的值,不经过串口
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB4 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**请求**: 同步头 0x77 + 0xB4 + 保留字节
**响应**: 0x01 0x77 0xB4 + 1 字节监听开关状态 (0=关, 1=开)
**设备端处理c3_fps 双 tile**:
- tile0 收到 0xB4 后置 is_get_listen_switch_requestHID 读时 process_read_params 直接读取 tile0 的 g_adc_loop由 tile1 经 sync 0x0D 同步)填入响应字节 3
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xB4 | 同步头2
3 | 1 | uint8 | 监听开关状态 (0=关1=开),即 g_adc_loop 的值
4-62 | 59 | 0x00 | 保留字节
```
**设备端处理**:
- 设备直接读取 g_adc_loop填入响应字节 3无需向 MCU 请求
**状态变化上报**: 当监听开关状态g_adc_loop发生变化时设备会主动通过 HID 上报数据格式与上述响应一致0x77 0xB4 + 1 字节监听状态与音量变化上报0x94方式相同主机可通过 HID 读或中断 IN 获取。
### 2.35 0xB6 - SET_TILE1_DIV (设置tile1动态降频分频值)
**功能**: 设置 tile[1] 动态降频(动态降频)的低功耗分频值 N。tile[1] core clock = 600 MHz / N。
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB6 | 命令码
2 | 1 | uint8 | 分频值 N (1-2550视为1N=1为全速600MHzN=40约15MHz)
3-62 | 60 | 0x00 | 保留字节
```
**设备端处理**:
- 仅在 FPS 镜像(编译宏 `C1_DFS_EN=1`,默认等于 `XMOS_FPS_EN`)生效;其它镜像(如 factory忽略此命令。
- 写入全局 `g_tile1_lp_div`。tile[1] 电源状态机下次进入 CLOCKED_DOWNFPS 关闭或音频流停止、grace 超时后)时按此分频值降频;若当前已处于 CLOCKED_DOWN则下次状态机 tick 立即按新值重写分频寄存器。
- 全速运行FPS 开启且音频流活跃)时不影响 tile[1] 实时时钟,仅更新待用分频值。
**返回值**:
无直接返回值。如需确认,请使用 GET_TILE1_DIV (0xB7) 读取当前分频值。
### 2.36 0xB7 - GET_TILE1_DIV (获取tile1动态降频分频值)
**功能**: 读取 tile[1] 动态降频当前的低功耗分频值 N。
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB7 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xB7 | 同步头2
3 | 1 | uint8 | 当前分频值 N (1-255)
4-62 | 59 | 0x00 | 保留字节
```
**设备端处理**:
- 仅在 FPS 镜像(`C1_DFS_EN=1`)生效,返回 `g_tile1_lp_div`
- 注意:返回的 N 为"待用/当前低功耗分频值"并非实时核心频率读数tile[1] 是否实际处于降频状态取决于 FPS 开关与音频流状态FPS 关闭或音频停止后才会真正降频)。
**状态变化上报**: 当监听开关状态g_adc_loop发生变化时设备会主动通过 HID 上报数据格式与上述响应一致0x77 0xB4 + 1 字节监听状态与音量变化上报0x94方式相同。
## 5. 关键特性

View File

@@ -0,0 +1,47 @@
#ifndef __FPS_API_H__
#define __FPS_API_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* 初始化 FPS 处理链及默认运行状态。 */
void fps_xmos_xc_init(void);
/* 选择游戏配置和档位。game: 0~20=cs21=pubg2=deltalevel: 0~4。 */
void fps_xmos_xc_game_select(int game, int level);
/* DRC 模式切换。mode: 0=low柔和压缩1=high强力压缩。 */
void fps_xmos_xc_drc_set_mode(int mode);
/*
* 设置运行时三个子模块的开关。
* drc_enable: 0 表示旁路,非 0 表示开启 DRC
* fps_enable: 0 表示旁路 FPS 主处理,非 0 表示开启
* eq_enable: 0 表示在 FPS 阶段旁路 EQ非 0 表示开启
*/
void fps_xmos_xc_set_module_enable(int drc_enable, int fps_enable, int eq_enable);
/* 初始化运行,调节过程中不运行。 */
/* 设置 10 段 EQ 的全部增益,单位为 0.01 dB范围 -600 ~ 600。 */
void fps_xmos_xc_eq_set_all_gains(int16_t *gains);
/* 初始化不运行,调节过程中运行。 */
/* 设置单个 EQ 频段增益,单位为 0.01 dB范围 -600 ~ 600。 */
void fps_xmos_xc_eq_set_band_gain(int band, int16_t gain);
/*
* 处理一个双声道块。
* input/output 数据格式为解交织的平面双声道:
* input[0..511] : 左声道
* input[512..1023] : 右声道
*/
void fps_xmos_xc_process(int16_t *input, int16_t *output);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,173 @@
/* 改动原因FPS fps_eq 五模式增益在tile0侧LittleFS持久化 */
#include <string.h>
#include <stdio.h>
#include "fps_eq_flash.h"
#include "lfs_io.h"
#include "debug_print.h"
#define FPS_EQ_FLASH_PATH "fps_eq_store"
#define FPS_EQ_FLASH_VERSION 0x01u
static void fps_eq_default_name(uint8_t mode, char out_name[FPS_EQ_NAME_LEN])
{
/* 改动原因:按协议约定提供小写默认模式名 fps_eq_0 ~ fps_eq_4 */
snprintf(out_name, FPS_EQ_NAME_LEN, "fps_eq_%u", (unsigned)mode);
}
/* 改动原因仅判断“是否历史已存名称”不做ASCII限制兼容中文/多语言UTF-8 */
static int fps_eq_name_has_saved_value(const char name[FPS_EQ_NAME_LEN])
{
int i;
int all_zero = 1;
int all_ff = 1;
int has_terminator = 0;
unsigned char first = (unsigned char)name[0];
for (i = 0; i < FPS_EQ_NAME_LEN; i++) {
unsigned char c = (unsigned char)name[i];
if (c != 0x00) {
all_zero = 0;
}
if (c != 0xFF) {
all_ff = 0;
}
if (c == '\0') {
has_terminator = 1;
break;
}
}
/* 旧数据或未初始化全0或全0xFF视为“未存名称” */
if (all_zero || all_ff) {
return 0;
}
/* 改动原因:旧布局中常见 0x01 0x00...(增益=1会误判为“有名称”首字节为控制字节时视为未存 */
if (first < 0x20) {
return 0;
}
/* 有数据但无\0终止视为旧布局残留回退默认名 */
if (!has_terminator) {
return 0;
}
return 1;
}
void fps_eq_flash_set_defaults(fps_eq_flash_store_t *store)
{
int m, b;
memset(store, 0, sizeof(*store));
store->magic = FPS_EQ_FLASH_MAGIC;
store->version = FPS_EQ_FLASH_VERSION;
store->current_mode = 0;
for (m = 0; m < FPS_EQ_MODE_COUNT; m++) {
fps_eq_default_name((uint8_t)m, store->mode_names[m]);
for (b = 0; b < FPS_EQ_BAND_COUNT; b++) {
store->gains[m][b] = FPS_EQ_GAIN_DEFAULT;
}
}
}
int16_t fps_eq_clamp_gain(int16_t gain)
{
if (gain < FPS_EQ_GAIN_MIN) {
return FPS_EQ_GAIN_MIN;
}
if (gain > FPS_EQ_GAIN_MAX) {
return FPS_EQ_GAIN_MAX;
}
return gain;
}
int fps_eq_flash_load(fps_eq_flash_store_t *out)
{
fps_eq_flash_store_t tmp;
int m;
int need_repair = 0;
fps_eq_flash_set_defaults(out);
if (lfs_init() != 0) {
return -1;
}
lfs_read_config((unsigned char *)FPS_EQ_FLASH_PATH,
(unsigned char *)&tmp,
sizeof(tmp));
lfs_deinit();
if (tmp.magic != FPS_EQ_FLASH_MAGIC) {
debug_printf("fps_eq_flash: invalid magic, use defaults\n");
return -1;
}
if (tmp.version != FPS_EQ_FLASH_VERSION) {
debug_printf("fps_eq_flash: version mismatch, reset defaults\n");
return -1;
}
if (tmp.current_mode >= FPS_EQ_MODE_COUNT) {
tmp.current_mode = 0;
need_repair = 1;
}
for (m = 0; m < FPS_EQ_MODE_COUNT; m++) {
tmp.mode_names[m][FPS_EQ_NAME_LEN - 1] = '\0';
if (!fps_eq_name_has_saved_value(tmp.mode_names[m])) {
fps_eq_default_name((uint8_t)m, tmp.mode_names[m]);
need_repair = 1;
}
}
*out = tmp;
/* 改动原因:检测到历史脏数据时自动修复并回写,后续读取稳定显示 */
if (need_repair) {
(void)fps_eq_flash_save(out);
}
return 0;
}
int fps_eq_flash_save(const fps_eq_flash_store_t *store)
{
fps_eq_flash_store_t to_write = *store;
int m;
to_write.magic = FPS_EQ_FLASH_MAGIC;
to_write.version = FPS_EQ_FLASH_VERSION;
if (to_write.current_mode >= FPS_EQ_MODE_COUNT) {
to_write.current_mode = 0;
}
for (m = 0; m < FPS_EQ_MODE_COUNT; m++) {
to_write.mode_names[m][FPS_EQ_NAME_LEN - 1] = '\0';
if (to_write.mode_names[m][0] == '\0') {
fps_eq_default_name((uint8_t)m, to_write.mode_names[m]);
}
}
if (lfs_init() != 0) {
return -1;
}
lfs_write_config((unsigned char *)FPS_EQ_FLASH_PATH,
(unsigned char *)&to_write,
sizeof(to_write));
lfs_deinit();
return 0;
}
void fps_eq_name_get(const fps_eq_flash_store_t *store, uint8_t mode, char out_name[FPS_EQ_NAME_LEN])
{
if (mode >= FPS_EQ_MODE_COUNT) {
mode = 0;
}
memcpy(out_name, store->mode_names[mode], FPS_EQ_NAME_LEN);
out_name[FPS_EQ_NAME_LEN - 1] = '\0';
}
void fps_eq_name_set(fps_eq_flash_store_t *store, uint8_t mode, const char *name)
{
if (mode >= FPS_EQ_MODE_COUNT || name == NULL) {
return;
}
memset(store->mode_names[mode], 0, FPS_EQ_NAME_LEN);
strncpy(store->mode_names[mode], name, FPS_EQ_NAME_LEN - 1);
store->mode_names[mode][FPS_EQ_NAME_LEN - 1] = '\0';
}

View File

@@ -0,0 +1,32 @@
#ifndef FPS_EQ_FLASH_H
#define FPS_EQ_FLASH_H
#include <stdint.h>
/* 改动原因FPS库fps_eq五套预设(模式0-4)每套10段增益单位0.01dB存于tile0 Flash */
#define FPS_EQ_MODE_COUNT 5
#define FPS_EQ_BAND_COUNT 10
#define FPS_EQ_NAME_LEN 16
#define FPS_EQ_GAIN_DEFAULT 1
#define FPS_EQ_GAIN_MIN (-600)
#define FPS_EQ_GAIN_MAX 600
#define FPS_EQ_FLASH_MAGIC 0x46505345u /* "FPSE" */
typedef struct {
uint32_t magic;
uint8_t version;
uint8_t current_mode;
uint8_t reserved[2];
char mode_names[FPS_EQ_MODE_COUNT][FPS_EQ_NAME_LEN];
int16_t gains[FPS_EQ_MODE_COUNT][FPS_EQ_BAND_COUNT];
} fps_eq_flash_store_t;
void fps_eq_flash_set_defaults(fps_eq_flash_store_t *store);
int fps_eq_flash_load(fps_eq_flash_store_t *out_data);
int fps_eq_flash_save(const fps_eq_flash_store_t *store);
int16_t fps_eq_clamp_gain(int16_t gain);
void fps_eq_name_get(const fps_eq_flash_store_t *store, uint8_t mode, char out_name[FPS_EQ_NAME_LEN]);
void fps_eq_name_set(fps_eq_flash_store_t *store, uint8_t mode, const char *name);
#endif

View File

@@ -0,0 +1,22 @@
#ifndef FPS_EQ_SYNC_H
#define FPS_EQ_SYNC_H
#include <stdint.h>
#include "fps_eq_flash.h"
/* 改动原因int16增益经5个int32共享字在tile0/tile1间传递(dp仅支持32位SHARED_GLOBAL) */
extern unsigned g_fps_eq_mode;
extern int32_t g_fps_eq_pack0;
extern int32_t g_fps_eq_pack1;
extern int32_t g_fps_eq_pack2;
extern int32_t g_fps_eq_pack3;
extern int32_t g_fps_eq_pack4;
void fps_eq_unpack_gains(int16_t out_gains[FPS_EQ_BAND_COUNT]);
void fps_eq_publish_gains_to_shared(const int16_t gains[FPS_EQ_BAND_COUNT]);
void fps_eq_publish_mode_and_gains(unsigned mode, const int16_t gains[FPS_EQ_BAND_COUNT]);
void fps_apply_eq_mode(void);
void fps_apply_eq_band_gain(unsigned band, int16_t gain);
#endif

View File

@@ -0,0 +1,93 @@
// Copyright 2024 XMOS LIMITED.
// 改动原因tile0→tile1 FPS 同步命令排队,解决单槽 g_sync_t0_to_t1_cmd 被覆盖及跨 tile 全局无效问题
#include <stdint.h>
#include "xc_ptr.h"
#include "debug_print.h"
#include "fps_tile_sync.h"
#include "fps_eq_sync.h"
#include "user_uart.h"
#define SYNC_T0_PENDING_MAX 12
extern unsigned g_sync_t0_to_t1_cmd;
extern unsigned g_sync_t0_to_t1_data;
extern unsigned g_sync_t0_to_t1_data2;
static struct {
unsigned cmd;
unsigned data;
unsigned data2;
} s_sync_t0_pending[SYNC_T0_PENDING_MAX];
static unsigned s_sync_t0_pending_count = 0;
void sync_t0_enqueue_to_tile1(unsigned cmd, unsigned data, unsigned data2)
{
if (s_sync_t0_pending_count >= SYNC_T0_PENDING_MAX) {
debug_printf("sync_t0: pending full, drop cmd 0x%02X\n", cmd);
return;
}
s_sync_t0_pending[s_sync_t0_pending_count].cmd = cmd;
s_sync_t0_pending[s_sync_t0_pending_count].data = data;
s_sync_t0_pending[s_sync_t0_pending_count].data2 = data2;
s_sync_t0_pending_count++;
}
void sync_t0_send_or_enqueue_to_tile1(unsigned cmd, unsigned data, unsigned data2)
{
unsigned cur = 0;
GET_SHARED_GLOBAL(cur, g_sync_t0_to_t1_cmd);
if (cur == 0) {
SET_SHARED_GLOBAL(g_sync_t0_to_t1_cmd, cmd);
SET_SHARED_GLOBAL(g_sync_t0_to_t1_data, data);
SET_SHARED_GLOBAL(g_sync_t0_to_t1_data2, data2);
} else {
sync_t0_enqueue_to_tile1(cmd, data, data2);
}
}
void sync_t0_promote_pending_to_tile1(void)
{
unsigned cur = 0;
unsigned i;
GET_SHARED_GLOBAL(cur, g_sync_t0_to_t1_cmd);
if (cur != 0 || s_sync_t0_pending_count == 0) {
return;
}
SET_SHARED_GLOBAL(g_sync_t0_to_t1_cmd, s_sync_t0_pending[0].cmd);
SET_SHARED_GLOBAL(g_sync_t0_to_t1_data, s_sync_t0_pending[0].data);
SET_SHARED_GLOBAL(g_sync_t0_to_t1_data2, s_sync_t0_pending[0].data2);
for (i = 1; i < s_sync_t0_pending_count; i++) {
s_sync_t0_pending[i - 1] = s_sync_t0_pending[i];
}
s_sync_t0_pending_count--;
}
void fps_eq_queue_pack_words_to_tile1(unsigned apply_on_last, unsigned enqueue_only)
{
int32_t packs[5];
unsigned i;
GET_SHARED_GLOBAL(packs[0], g_fps_eq_pack0);
GET_SHARED_GLOBAL(packs[1], g_fps_eq_pack1);
GET_SHARED_GLOBAL(packs[2], g_fps_eq_pack2);
GET_SHARED_GLOBAL(packs[3], g_fps_eq_pack3);
GET_SHARED_GLOBAL(packs[4], g_fps_eq_pack4);
for (i = 0; i < 5; i++) {
unsigned data1 = i;
unsigned apply_flag = (apply_on_last != 0 && i == 4) ? 1u : 0u;
data1 |= (apply_flag << 8);
if (enqueue_only) {
sync_t0_enqueue_to_tile1(SYNC_CMD_T0_TO_T1_SET_FPS_EQ_PACK, data1, (unsigned)packs[i]);
} else {
sync_t0_send_or_enqueue_to_tile1(SYNC_CMD_T0_TO_T1_SET_FPS_EQ_PACK, data1, (unsigned)packs[i]);
}
}
}

View File

@@ -0,0 +1,16 @@
#ifndef FPS_TILE_SYNC_H
#define FPS_TILE_SYNC_H
/* 改动原因tile0/tile1 内存不共享FPS 配置须经 channel 排队同步到 tile1 */
void sync_t0_enqueue_to_tile1(unsigned cmd, unsigned data, unsigned data2);
void sync_t0_send_or_enqueue_to_tile1(unsigned cmd, unsigned data, unsigned data2);
void sync_t0_promote_pending_to_tile1(void);
/* 改动原因:将 tile0 上已发布的 g_fps_eq_pack0..4 经 sync 0x0B 传到 tile1末包 apply=1 时调用 fps_apply_eq_mode */
void fps_eq_queue_pack_words_to_tile1(unsigned apply_on_last, unsigned enqueue_only);
/* 改动原因C1 无 UART/MCU 串口,上电在 tile0 直接从 Flash 恢复 FPS 并排队 sync 到 tile1原 c3_fps 由 uart_handler 经 c_uart_sync 触发) */
void fps_boot_load_from_flash(void);
#endif

View File

@@ -10,33 +10,119 @@
#include "xc_ptr.h"
#include "xua_conf.h"
extern void fps_xmos_init();
extern void fps_xmos_process(int16_t * input, int16_t* output, int channel);
/* 改动原因FPS库V1.5改为单核xc接口使用fps_api.h中的fps_xmos_xc_*声明 */
#include "fps_api.h"
#include "fps_eq_sync.h"
#define FPS_SLOT_NUM 3
#define FPS_FRAME_SIZE 512
#define FPS_NUM_OUT 2
short __attribute__((aligned (4))) dsp_fps_input_buf[FPS_SLOT_NUM][2][FPS_FRAME_SIZE];
short __attribute__((aligned (4))) dsp_fps_out_buf[FPS_SLOT_NUM][2][FPS_FRAME_SIZE];
/* 改动原因新库process接口为平面双声道左0..511、右512..1023每槽1024个sample */
#define FPS_PLANAR_SAMPLES (FPS_FRAME_SIZE * 2)
unsigned fps1_buf_ready = 0;
unsigned fps2_buf_ready = 0;
unsigned fps_write_pos = 0;
unsigned fps_process_pos = 0;
short __attribute__((aligned (4))) dsp_fps_input_buf[FPS_SLOT_NUM][FPS_PLANAR_SAMPLES];
short __attribute__((aligned (4))) dsp_fps_out_buf[FPS_SLOT_NUM][FPS_PLANAR_SAMPLES];
unsigned fps_buf_ready = 0;
unsigned fps_write_pos = 0;
unsigned fps_process_pos = 0;
/* 改动原因tile0/tile1 内存不共享game/level/使能/fps_eq 须经 channel sync 写入 tile1 副本 */
unsigned g_fps_game_select = 1;
unsigned g_fps_level_select = 2;
/* 改动原因FPS 默认开、DRC/fps_eq 默认关;与 audiohw 中 g_fps_enable(模式选择) 区分命名 */
unsigned g_fps_drc_enable = 0;
unsigned g_fps_sub_enable = 1;
unsigned g_fps_eq_enable = 0;
/* 改动原因DRC压缩模式默认0=low柔和压缩HID 0xBD/断电保存fps_drc_mode后经sync同步到tile1 */
unsigned g_fps_drc_mode = 0;
/* 改动原因fps_eq当前模式(0-4)与10段增益经5个pack字在tile0/tile1共享 */
unsigned g_fps_eq_mode = 0;
int32_t g_fps_eq_pack0 = 0;
int32_t g_fps_eq_pack1 = 0;
int32_t g_fps_eq_pack2 = 0;
int32_t g_fps_eq_pack3 = 0;
int32_t g_fps_eq_pack4 = 0;
static int32_t fps_eq_make_pack(int16_t lo, int16_t hi)
{
return ((int32_t)(uint16_t)lo) | (((int32_t)(uint16_t)hi) << 16);
}
static int16_t fps_eq_pack_lo(int32_t w)
{
return (int16_t)(w & 0xFFFF);
}
static int16_t fps_eq_pack_hi(int32_t w)
{
return (int16_t)((w >> 16) & 0xFFFF);
}
void fps_eq_unpack_gains(int16_t out_gains[FPS_EQ_BAND_COUNT])
{
int32_t p0, p1, p2, p3, p4;
GET_SHARED_GLOBAL(p0, g_fps_eq_pack0);
GET_SHARED_GLOBAL(p1, g_fps_eq_pack1);
GET_SHARED_GLOBAL(p2, g_fps_eq_pack2);
GET_SHARED_GLOBAL(p3, g_fps_eq_pack3);
GET_SHARED_GLOBAL(p4, g_fps_eq_pack4);
out_gains[0] = fps_eq_pack_lo(p0);
out_gains[1] = fps_eq_pack_hi(p0);
out_gains[2] = fps_eq_pack_lo(p1);
out_gains[3] = fps_eq_pack_hi(p1);
out_gains[4] = fps_eq_pack_lo(p2);
out_gains[5] = fps_eq_pack_hi(p2);
out_gains[6] = fps_eq_pack_lo(p3);
out_gains[7] = fps_eq_pack_hi(p3);
out_gains[8] = fps_eq_pack_lo(p4);
out_gains[9] = fps_eq_pack_hi(p4);
}
void fps_eq_publish_gains_to_shared(const int16_t gains[FPS_EQ_BAND_COUNT])
{
SET_SHARED_GLOBAL(g_fps_eq_pack0, fps_eq_make_pack(gains[0], gains[1]));
SET_SHARED_GLOBAL(g_fps_eq_pack1, fps_eq_make_pack(gains[2], gains[3]));
SET_SHARED_GLOBAL(g_fps_eq_pack2, fps_eq_make_pack(gains[4], gains[5]));
SET_SHARED_GLOBAL(g_fps_eq_pack3, fps_eq_make_pack(gains[6], gains[7]));
SET_SHARED_GLOBAL(g_fps_eq_pack4, fps_eq_make_pack(gains[8], gains[9]));
}
void fps_eq_publish_mode_and_gains(unsigned mode, const int16_t gains[FPS_EQ_BAND_COUNT])
{
SET_SHARED_GLOBAL(g_fps_eq_mode, mode);
fps_eq_publish_gains_to_shared(gains);
}
void fps_apply_eq_mode(void)
{
int16_t gains[FPS_EQ_BAND_COUNT];
fps_eq_unpack_gains(gains);
/* 改动原因切换模式时用eq_set_all_gains一次性加载当前模式10段增益 */
fps_xmos_xc_eq_set_all_gains(gains);
}
void fps_apply_eq_band_gain(unsigned band, int16_t gain)
{
if (band >= FPS_EQ_BAND_COUNT) {
return;
}
/* 改动原因运行中单段调节使用fps_xmos_xc_eq_set_band_gain */
fps_xmos_xc_eq_set_band_gain((int)band, gain);
}
void fps_main (chanend_t c_data ) {
int input[2];
int output[2];
int count = 0;
unsigned write_pos = 0;
unsigned process_pos = 0;
unsigned write_pos = 0;
unsigned read_pos = 0;
while (1) {
chan_in_buf_word (c_data , input, 2) ;
@@ -44,19 +130,12 @@ void fps_main (chanend_t c_data ) {
if (count == 0)
read_pos = (write_pos + 1 + FPS_SLOT_NUM) % FPS_SLOT_NUM;
// 修改原因: 写入当前buffer读取前一个已处理完的buffer实现1帧延时
// 写入位置write_pos当前正在填充的buffer
for (int i = 0; i <2; i++)
{
dsp_fps_input_buf[write_pos][i][count] = (short)(input[i] >> 16);
}
/* 改动原因按fps_xmos_xc_process要求的平面格式写入左声道在前512右声道在后512 */
dsp_fps_input_buf[write_pos][count] = (short)(input[0] >> 16);
dsp_fps_input_buf[write_pos][FPS_FRAME_SIZE + count] = (short)(input[1] >> 16);
// 读取位置read_pos前一个已经DSP处理完成的buffer
// 这样可以实现最小延时1帧避免原来的3帧延时问题
for (int i = 0; i < 2; i++)
{
output[i] = (int)(dsp_fps_out_buf[read_pos][i][count]) << 16;
}
output[0] = (int)(dsp_fps_out_buf[read_pos][count]) << 16;
output[1] = (int)(dsp_fps_out_buf[read_pos][FPS_FRAME_SIZE + count]) << 16;
if (count != (FPS_FRAME_SIZE - 1))
{
@@ -64,84 +143,118 @@ void fps_main (chanend_t c_data ) {
}
else
{
// 一帧完成,进行缓冲区切换
count = 0;
// 修改原因: 实现1帧延时的三缓冲机制
// 步骤1: 将当前完成的写入buffer交给DSP处理任务
SET_SHARED_GLOBAL(fps_process_pos, write_pos);
// 步骤2: 切换到下一个buffer进行写入三缓冲循环0→1→2→0
write_pos = (write_pos + 1) % FPS_SLOT_NUM;
SET_SHARED_GLOBAL(fps_write_pos, write_pos);
SET_SHARED_GLOBAL(fps1_buf_ready, 1);
SET_SHARED_GLOBAL(fps2_buf_ready, 1);
/* 改动原因单核处理整帧立体声仅需一个ready标志 */
SET_SHARED_GLOBAL(fps_buf_ready, 1);
}
}
}
unsigned long get_reference_time();
/* 改动原因按全局变量同步DRC压缩模式到算法库fps_xmos_xc_drc_set_mode */
void fps_apply_drc_mode(void)
{
unsigned drc_mode;
GET_SHARED_GLOBAL(drc_mode, g_fps_drc_mode);
/* 改动原因mode仅允许0=low、1=high无效值回默认0 */
if (drc_mode > 1) {
drc_mode = 0;
}
fps_xmos_xc_drc_set_mode((int)drc_mode);
}
/* 改动原因按全局变量同步DRC/FPS主处理/fps_eq三模块开关到算法库 */
void fps_apply_module_enable(void)
{
unsigned drc_enable;
unsigned fps_sub_enable;
unsigned eq_enable;
GET_SHARED_GLOBAL(drc_enable, g_fps_drc_enable);
GET_SHARED_GLOBAL(fps_sub_enable, g_fps_sub_enable);
GET_SHARED_GLOBAL(eq_enable, g_fps_eq_enable);
fps_xmos_xc_set_module_enable(
(drc_enable != 0) ? 1 : 0,
(fps_sub_enable != 0) ? 1 : 0,
(eq_enable != 0) ? 1 : 0);
}
/* 改动原因HID/tile0同步时在audiohw.xc中调用供tile1在收到 sync 0x03(来自 HID 0xBF)时更新FPS算法参数 */
void fps_apply_game_level_select(void)
{
unsigned game_select;
unsigned level_select;
GET_SHARED_GLOBAL(game_select, g_fps_game_select);
GET_SHARED_GLOBAL(level_select, g_fps_level_select);
if (game_select > 2) {
game_select = 0;
}
/* 改动原因:无效 level 默认档位 2与 fps_level_g0/g1/g2 及 g_fps_level_select 一致 */
if (level_select > 4) {
level_select = 2;
}
fps_xmos_xc_game_select((int)game_select, (int)level_select);
}
/* 改动原因集中FPS库初始化顺序——init→fps_eq全段增益→game/level→三模块使能 */
static void fps_xmos_modules_init(void)
{
unsigned game_select;
unsigned level_select;
int16_t gains[FPS_EQ_BAND_COUNT];
fps_xmos_xc_init();
/* 改动原因从tile0已同步的共享pack字解出当前模式10段增益后初始化fps_eq */
fps_eq_unpack_gains(gains);
fps_xmos_xc_eq_set_all_gains(gains);
GET_SHARED_GLOBAL(game_select, g_fps_game_select);
GET_SHARED_GLOBAL(level_select, g_fps_level_select);
if (game_select > 2) {
game_select = 0;
}
/* 改动原因:上电/初始化时无效 level 默认档位 2 */
if (level_select > 4) {
level_select = 2;
}
fps_xmos_xc_game_select((int)game_select, (int)level_select);
/* 改动原因:上电/HID设置后须在module_enable前应用DRC压缩模式 */
fps_apply_drc_mode();
fps_apply_module_enable();
}
void fps1_dsp_proc_task()
{
fps_xmos_init();
#if 1
fps_xmos_modules_init();
while (1)
{
unsigned ready1;
// 修改原因: 使用声道0独立的ready标志与声道1完全独立避免竞态
GET_SHARED_GLOBAL(ready1, fps1_buf_ready);
while (ready1)
{
// 修改原因: 关键修复 - 直接读取fps_main设置好的process_pos避免自己计算导致的竞态
unsigned cur_pos;
GET_SHARED_GLOBAL(cur_pos, fps_process_pos);
#if 0
for (int i = 0; i < FPS_FRAME_SIZE; i++)
{
dsp_fps_out_buf[cur_pos][0][i] = dsp_fps_input_buf[cur_pos][0][i];
}
#else
// 处理声道0数据
fps_xmos_process(&dsp_fps_input_buf[cur_pos][0], &dsp_fps_out_buf[cur_pos][0], 0);
#endif
unsigned ready;
ready1 = 0;
SET_SHARED_GLOBAL(fps1_buf_ready, 0);
}
}
#endif
}
void fps2_dsp_proc_task()
{
#if 1
while (1)
{
unsigned ready2;
GET_SHARED_GLOBAL(ready2, fps2_buf_ready);
while (ready2)
GET_SHARED_GLOBAL(ready, fps_buf_ready);
while (ready)
{
unsigned cur_pos;
GET_SHARED_GLOBAL(cur_pos, fps_process_pos);
// 处理声道1数据
unsigned long start_time = get_reference_time();
#if 0
for (int i = 0; i < FPS_FRAME_SIZE; i++)
{
dsp_fps_out_buf[cur_pos][1][i] = dsp_fps_input_buf[cur_pos][1][i];
}
#else
fps_xmos_process(&dsp_fps_input_buf[cur_pos][1], &dsp_fps_out_buf[cur_pos][1], 1);
#endif
unsigned long end_time = get_reference_time();
// printf("fps2_dsp_proc_task time: %d ms\n", end_time - start_time);
// 修改原因: 只清除自己的ready标志不影响声道0
ready2 = 0;
SET_SHARED_GLOBAL(fps2_buf_ready, 0);
/* 改动原因:单核一次处理左右声道平面块,不再分声道两次调用 */
fps_xmos_xc_process(dsp_fps_input_buf[cur_pos], dsp_fps_out_buf[cur_pos]);
ready = 0;
SET_SHARED_GLOBAL(fps_buf_ready, 0);
}
}
#endif
}

View File

@@ -14,6 +14,8 @@
#include <xs1.h>
#include <xclib.h>
#include <print.h>
/* 改动原因FPS 移植自 c3_fpsmain.xc 中 fps_main/fps1_dsp_proc_task 启动日志需要 debug_printf */
#include "debug_print.h"
#ifdef XSCOPE
#include <xscope.h>
#endif
@@ -422,7 +424,6 @@ void usb_audio_io(chanend ?c_aud_in,
#if XMOS_FPS_EN
extern void fps_main(chanend c_data);
extern void fps1_dsp_proc_task();
extern void fps2_dsp_proc_task();
#endif
/* Main for USB Audio Applications */
@@ -521,17 +522,16 @@ int main()
#if XMOS_FPS_EN
on tile[1]: {
debug_printf("start fps_main\n");
set_core_high_priority_on();
fps_main(c_data_transport);
}
on tile[1]: {
/* 改动原因FPS库改为单核xc_process仅需一个DSP任务处理整帧立体声 */
debug_printf("start fps1_dsp_proc_task\n");
set_core_high_priority_on();
fps1_dsp_proc_task();
}
on tile[1]: {
set_core_high_priority_on();
fps2_dsp_proc_task();
}
#else
#if UAC1
on tile[1]: {

View File

@@ -16,7 +16,7 @@ interface c1_led_ctrl_if {
void switch_handler(void);
void flag_handler();
/* 改动原因:固件升级 START 在 AudioHwRemote2 处理,需传入 c_dfu其余升级命令在 process_send_params 直接处理 */
void AudioHwRemote(streaming chanend c, client interface c1_led_ctrl_if i_c1_led_ctrl, chanend c_erase, streaming chanend c_dfu);
void AudioHwRemote(streaming chanend c, client interface c1_led_ctrl_if i_c1_led_ctrl, streaming chanend c_dfu, chanend c_app_sync);
void i2s_driver(chanend c);
extern unsafe chanend uc_i2s;
extern unsafe chanend uc_br_data;
@@ -24,61 +24,47 @@ extern unsafe chanend uc_eq_data;
extern void UserBufferManagementSetChan(chanend c);
extern void dsp_main (chanend c_data , chanend cc_br_eof);
extern void br_dsp_proc_task(chanend c_validate, chanend cc_br_eof);
extern void validate_algo(chanend c_validate);
void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl);
void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl, chanend c_sync);
extern void dnr_dsp_proc_task(void);
extern void dsp_core0(void);
extern void eq_dsp_main(chanend c_data);
extern unsafe streaming chanend uc_audiohw;
extern unsafe streaming chanend uc_dfu;
extern void fps1_dsp_proc_task(void);
extern void fps2_dsp_proc_task(void);
/* 改动原因FPS库单核处理fps2_dsp_proc_task已合并到fps1 */
extern void fps_apply_game_level_select(void);
extern void fps_apply_module_enable(void);
extern void fps_apply_drc_mode(void);
extern void fps_apply_eq_mode(void);
extern void fps_apply_eq_band_gain(unsigned band, int16_t gain);
extern void fps_eq_boot_publish_to_tile1(void);
extern void fps_drc_boot_sync_to_tile1(void);
extern void fps_boot_load_from_flash(void);
extern unsigned g_fps_drc_enable;
extern unsigned g_fps_sub_enable;
extern unsigned g_fps_eq_enable;
extern unsigned g_fps_drc_mode;
#define USER_MAIN_DECLARATIONS chan c_data_transport, cc_br_eof, c_validate; \
streaming chan c_audiohw; streaming chan c_dfu; interface c1_led_ctrl_if i_c1_led_ctrl; \
#define USER_MAIN_DECLARATIONS streaming chan c_audiohw; streaming chan c_dfu; interface c1_led_ctrl_if i_c1_led_ctrl; \
chan c_usb_to_io; chan c_io_to_usb; chan c_io_to_dspL; chan c_dspL_to_io; chan c_io_to_dspR; chan c_dspR_to_io; \
chan c_erase;
chan c_app_sync, c_data_transport;
#if !UAC1
#define USER_MAIN_CORES on tile[0]: {\
unsafe { \
uc_audiohw = (chanend) c_audiohw;\
uc_dfu = (chanend) c_dfu;\
} \
flag_handler(); \
}\
on tile[0]: {\
AudioHwRemote(c_audiohw, i_c1_led_ctrl, c_erase, c_dfu);\
}\
on tile[AUDIO_IO_TILE]: par {\
dsp_core0();\
} \
\
on tile[1]: app_control_slave(i_c1_led_ctrl); \
\
#else
#define USER_MAIN_CORES on tile[0]: {\
dnr_dsp_proc_task();\
}\
on tile[0]: {\
unsafe { \
uc_audiohw = (chanend) c_audiohw;\
/* 改动原因FPS/BR 音频经 c_data_transport 与 tile1 fps_main 交换;未赋值 uc_br_data 会导致 UserBufferManagement buffer_exchange ECALL */\
uc_br_data = (chanend) c_data_transport;\
uc_dfu = (chanend) c_dfu;\
} \
validate_algo(c_validate); \
}\
on tile[0]: {\
AudioHwRemote(c_audiohw, i_c1_led_ctrl, c_erase, c_dfu);\
AudioHwRemote(c_audiohw, i_c1_led_ctrl, c_dfu, c_app_sync);\
}\
on tile[1]: { br_dsp_proc_task(c_validate, cc_br_eof); } \
on tile[1]: app_control_slave(i_c1_led_ctrl); \
on tile[1]: app_control_slave(i_c1_led_ctrl, c_app_sync); \
\
#endif
#else
#define USER_MAIN_DECLARATIONS_A

View File

@@ -1,11 +1,11 @@
#ifndef _UART_H_
#define _UART_H_
#include <platform.h>
#include <stdint.h>
#include <stdio.h>
#include <xclib.h>
#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include <stdio.h>
#include <stdint.h>
typedef enum {
AUDIO_PCM_44100 = 0,
@@ -263,4 +263,42 @@ typedef struct {
unsigned char pendingReboot;
} UserCmdConfig;
// Tile1到Tile0同步命令枚举
// 改动原因定义同步命令类型用于tile1通过channel向tile0发送需要同步的操作
typedef enum {
SYNC_CMD_NONE = 0x00,
SYNC_CMD_LOAD_CONFIGS = 0x01, // 加载配置从Flash读取
SYNC_CMD_SAVE_CONFIGS = 0x02, // 保存配置写入Flash
SYNC_CMD_SAVE_PRODUCT_INFO = 0x03, // 保存产品信息
SYNC_CMD_SAVE_POWERUP_INFO = 0x04, // 保存上电配置
SYNC_CMD_SAVE_USERCONFIG = 0x05, // 保存用户配置
SYNC_CMD_GET_PID_VID = 0x06, // 获取并设置PID/VID
SYNC_CMD_SET_DAC_VOLUME = 0x07, // 设置DAC音量
SYNC_CMD_SET_ADC_VOLUME = 0x08, // 设置ADC音量
SYNC_CMD_SET_3D_FPS = 0x09, // 设置3D FPS0x33命令
SYNC_CMD_SET_ROLE_SWITCH = 0x0A, // 设置RoleSwitchFlagoleSwitchFlag
SYNC_CMD_STORE_MEMORY = 0x0B, // 存储内存数据store_memory
SYNC_CMD_SET_LED_MODE = 0x0C, // 设置LED模式0x34命令
SYNC_CMD_SET_ADC_LOOP = 0x0D, // 设置ADC Loop0x31命令
SYNC_CMD_MUTE_VALUE_FROM_MCU = 0x0E, // tile1收到MCU 0x5F响应后将静音值传回tile0
} SyncCmdType;
// Tile0到Tile1同步命令枚举
// 改动原因定义反向同步命令类型用于tile0通过channel向tile1发送需要同步的操作
typedef enum {
SYNC_CMD_T0_TO_T1_NONE = 0x00,
SYNC_CMD_T0_TO_T1_SET_GAME_MODE = 0x01, // 设置游戏模式HID 0xA4 -> UART 0x5A
SYNC_CMD_T0_TO_T1_SET_UAC_MODE = 0x02, // 设置UAC模式HID 0x9B -> UART 0x51
SYNC_CMD_T0_TO_T1_SET_FPS_XMOS_GAME_SELECT = 0x03, // 设置FPS XMOS游戏选择HID 0xBF -> fps_xmos_game_select
SYNC_CMD_T0_TO_T1_SET_INPUT_SOURCE = 0x04, // 设置输入源HID 0xB0 -> UART 0x5D
SYNC_CMD_T0_TO_T1_SET_FPS_MODULE_ENABLE = 0x08, // 设置FPS库DRC/FPS/fps_eq使能HID 0xB5 -> fps_xmos_xc_set_module_enable
SYNC_CMD_T0_TO_T1_SET_FPS_EQ_MODE = 0x09, // 切换fps_eq模式并加载10段增益HID 0xB7
SYNC_CMD_T0_TO_T1_SET_FPS_EQ_BAND_GAIN = 0x0A, // 设置fps_eq单段增益HID 0xB9
SYNC_CMD_T0_TO_T1_SET_FPS_EQ_PACK = 0x0B, // 同步fps_eq pack字到tile1上电/HID 0xB7
SYNC_CMD_T0_TO_T1_SET_FPS_DRC_MODE = 0x0C, // 设置DRC压缩模式HID 0xBD -> fps_xmos_xc_drc_set_mode
SYNC_CMD_T0_TO_T1_SET_MUTE_SWITCH = 0x05, // 设置静音开关HID 0xB1 -> UART 0x5E
SYNC_CMD_T0_TO_T1_SEND_GET_MUTE_REQUEST = 0x06, // 向MCU发0x5F获取静音HID 0xB2
SYNC_CMD_T0_TO_T1_SET_LISTEN_SWITCH = 0x07, // 设置监听开关HID 0xB3 -> UART 0x60
} SyncCmdT0ToT1Type;
#endif

View File

@@ -34,6 +34,7 @@ extern "C" {
#define RCV_CMD_TIMEOUT (500000000) //5s
#define SEND_CMD_TIMEOUT (20000000) //200ms
#define VOLUME_TIMEOUT (5500000) //55ms delay
#define BEAT_DELAY (500000) //10ms delay
#define START_COUNTS (4)
@@ -67,6 +68,22 @@ unsigned char g_save_configs = 0;
unsigned g_usb_state = 1;
unsigned int g_xu316_id;
/* 改动原因0x07/0x08/0x09/0x0C/0x0D/0x0E 仅在值变化时同步到 tile0用 pending 存 UART 下发的值last_sync 存上次已同步的值,初值 -1 */
unsigned g_pending_dac_vol = (unsigned)(-1);
unsigned g_pending_adc_vol = (unsigned)(-1);
unsigned g_pending_3d_fps = (unsigned)(-1);
unsigned g_pending_led_mode = (unsigned)(-1);
unsigned g_pending_adc_loop = (unsigned)(-1);
unsigned g_pending_mute_switch = (unsigned)(-1);
unsigned g_pending_mcu_mute = (unsigned)(-1);
unsigned g_last_sync_dac_vol = (unsigned)(-1);
unsigned g_last_sync_adc_vol = (unsigned)(-1);
unsigned g_last_sync_3d_fps = (unsigned)(-1);
unsigned g_last_sync_led_mode = (unsigned)(-1);
unsigned g_last_sync_adc_loop = (unsigned)(-1);
unsigned g_last_sync_mute_switch = (unsigned)(-1);
unsigned g_last_sync_mcu_mute = (unsigned)(-1);
extern audio_sampling g_playback_format;
extern audio_type g_audio_type;
extern unsigned g_led_mode;
@@ -76,15 +93,18 @@ extern unsigned int read_key(void);
extern unsigned g_dac_vol;
extern unsigned g_adc_vol;
extern unsigned g_adc_loop;
extern unsigned g_mute_switch; // 改动原因与g_adc_loop一致UART收到0x5F响应时直接设置供HID变化上报
extern unsigned g_3d_fps;
extern unsigned g_dac_mode;
extern unsigned g_new_dac_mode;
extern unsigned g_sync_t0_to_t1_cmd;
extern unsigned g_sync_t0_to_t1_data;
#if EQ_EN
extern unsigned int g_current_eq_mode; // EQ当前模式
extern unsigned int g_old_eq_mode; // EQ当前模式
extern int process_eq_params_from_uart(uint8_t eq_mode, uint8_t eq_index, uint32_t sample_rate, float coefficients[5]);
// EQ命令处理函数现在在eq.c中实现
extern void process_uart_set_game_mode(uint8_t game_mode); // 改动原因声明UART设置游戏模式函数用于tile0到tile1同步
extern void process_uart_set_uac_mode(uint8_t uac_mode); // 改动原因声明UART设置UAC模式函数用于tile0到tile1同步
#endif
extern void read_uid_did(uint8_t uid[]);
@@ -92,6 +112,41 @@ void device_reboot(void);
uint8_t send_data[MAX_BUFFER_LEN] = {0};
// 改动原因用于存储需要同步的数据缓冲区用于Flash操作等需要传递数据指针的情况
static uint8_t sync_buffer[128];
// 改动原因全局同步channel用于process_command中需要同步的操作使用unsafe chanend因为需要在函数间传递
static unsafe chanend g_c_uart_sync;
// 改动原因实现tile1到tile0的同步函数用于将需要在tile0执行的操作通过channel发送
static void sync_to_tile0(unsigned cmd, unsigned data1, unsigned data2)
{
unsigned result;
unsafe {
g_c_uart_sync <: cmd;
g_c_uart_sync <: data1;
g_c_uart_sync <: data2;
g_c_uart_sync :> result;
}
}
// 改动原因实现tile1到tile0的数据传输函数用于传输数据块因为tile0和tile1内存不共享
static void sync_data_to_tile0(unsigned cmd, uint8_t *data, unsigned len, unsigned extra_data)
{
unsigned result;
unsigned i;
unsafe {
g_c_uart_sync <: cmd;
g_c_uart_sync <: len; // 先发送数据长度
g_c_uart_sync <: extra_data; // 发送额外数据
// 逐字节传输数据因为tile0和tile1内存不共享不能传递指针
for(i = 0; i < len; i++)
{
g_c_uart_sync <: data[i];
}
g_c_uart_sync :> result;
}
}
UserCmdConfig cmdConfig={0};
extern unsigned g_in_fw_upgrade;
@@ -203,7 +258,7 @@ uint8_t send_user_cmd(uint8_t *request, uint8_t func_code, unsigned char version
case START_FINISH:
unsigned mode_code = 0;
unsigned mode = GetRoleSwitchFlag();
unsigned mode =BT_IN_FLAG;
switch (mode)
{
case UAC1_IN_FLAG:
@@ -224,6 +279,7 @@ uint8_t send_user_cmd(uint8_t *request, uint8_t func_code, unsigned char version
default:
break;
}
mode_code = 0x800100;
request[4] = FINISH_CMD_DATA_LEN;
request[5] = 0;
@@ -256,10 +312,10 @@ uint8_t send_user_cmd(uint8_t *request, uint8_t func_code, unsigned char version
}
debug_printf("boot to user_mode %08x\n", mode_code);
SetRoleSwitchFlag(mode_code);
delay_milliseconds(1);
device_reboot();
while(1);
//sync_to_tile0(0x0A, mode_code, 0); // SYNC_CMD_SET_ROLE_SWITCH
//delay_milliseconds(20);
//device_reboot();
//while(1);
}
break;
@@ -309,7 +365,6 @@ void update_button(unsigned char b)
debug_printf("update_button %02x\n", 1<<b);
#endif
}
void user_set_hidpass(unsigned char * unsafe data);
void process_command(uint8_t *data)
{
@@ -356,12 +411,18 @@ void process_command(uint8_t *data)
break;
case READ_AUDIO_MODE:
store_memory(&data[CMD_DATA_POS], 5);
// 改动原因:store_memory需要在tile0执行Flash访问通过同步channel发送
// 改动原因tile0和tile1内存不共享需要实际传输数据内容不能传递指针
unsafe {
memcpy(sync_buffer, &data[CMD_DATA_POS], 5);
sync_data_to_tile0(0x0B, sync_buffer, 5, 0); // SYNC_CMD_STORE_MEMORY
}
unsigned mode_code = 0;
unsigned audio_mode = (data[CMD_DATA_POS] << 24) | (data[CMD_DATA_POS + 1] << 16) | (data[CMD_DATA_POS + 2] << 8) | data[CMD_DATA_POS + 3] ;
debug_printf("read audio_mode 0x%08x\n", audio_mode);
delay_milliseconds(2);
save_configs(g_save_configs);
// 改动原因save_configs需要在tile0执行Flash访问通过同步channel发送
save_userconfig_info(&data[CMD_DATA_POS]);
// sync_to_tile0(0x02, g_save_configs, 0); // SYNC_CMD_SAVE_CONFIGS
switch (audio_mode)
{
case 0x10806510:
@@ -383,14 +444,21 @@ void process_command(uint8_t *data)
}
debug_printf("reboot to audio_mode 0x%08x\n", mode_code);
SetRoleSwitchFlag(mode_code);
delay_milliseconds(1);
device_reboot();
while(1);
// 改动原因:SetRoleSwitchFlag需要在tile0执行通过同步channel发送
sync_to_tile0(0x0A, mode_code, 0); // SYNC_CMD_SET_ROLE_SWITCH
//delay_milliseconds(1);
// device_reboot();
// while(1);
break;
case READ_USER_CONFIG:
save_userconfig_info(&data[CMD_DATA_POS]);
// 改动原因:save_userconfig_info需要在tile0执行Flash访问通过同步channel发送
// 改动原因tile0和tile1内存不共享需要实际传输数据内容不能传递指针
unsafe {
memcpy(sync_buffer, &data[CMD_DATA_POS], CONFIG_CMD_DATA_LEN);
sync_data_to_tile0(0x05, sync_buffer, CONFIG_CMD_DATA_LEN, 0); // SYNC_CMD_SAVE_USERCONFIG
}
save_userconfig_info(&data[CMD_DATA_POS]);
unsigned audio_mode = (data[CMD_DATA_POS] << 24) | (data[CMD_DATA_POS + 1] << 16) | (data[CMD_DATA_POS + 2] << 8) | data[CMD_DATA_POS + 3] ;
// print_buff(data, 6 + length);
debug_printf("current audio_mode 0x%08x\n", audio_mode);
@@ -402,9 +470,9 @@ void process_command(uint8_t *data)
break;
case REPORT_APP_STATUS:
unsigned mode = GetRoleSwitchFlag();
debug_printf("mode %08x\n", mode);
xmos_printf((unsigned char *)&mode, 4);
unsigned old_mode = 0x800100;
debug_printf("report app status %08x\n", old_mode);
xmos_printf((unsigned char *)&old_mode, 4);
break;
@@ -419,8 +487,13 @@ void process_command(uint8_t *data)
break;
case SWITCH_AUDIO_MODE:
store_memory(&data[CMD_DATA_POS], 5);
unsigned mode_code = 0, old_mode = 0;
// 改动原因:store_memory需要在tile0执行Flash访问通过同步channel发送
// 改动原因tile0和tile1内存不共享需要实际传输数据内容不能传递指针
unsafe {
memcpy(sync_buffer, &data[CMD_DATA_POS], 5);
sync_data_to_tile0(0x0B, sync_buffer, 5, 0); // SYNC_CMD_STORE_MEMORY
}
unsigned mode_code = 0, old_mode = BT_IN_FLAG;
unsigned audio_mode = (data[CMD_DATA_POS] << 24) | (data[CMD_DATA_POS + 1] << 16) | (data[CMD_DATA_POS + 2] << 8) | data[CMD_DATA_POS + 3] ;
switch (audio_mode)
{
@@ -445,10 +518,11 @@ void process_command(uint8_t *data)
send_len = send_user_cmd(send_data, SWITCH_AUDIO_MODE, 1, 0);
xmos_printf(send_data, send_len);
old_mode = GetRoleSwitchFlag();
if (old_mode != mode_code)
{
SetRoleSwitchFlag(mode_code);
// 改动原因:SetRoleSwitchFlag需要在tile0执行通过同步channel发送
sync_to_tile0(0x0A, mode_code, 0); // SYNC_CMD_SET_ROLE_SWITCH
//delay_milliseconds(20);
debug_printf("switch audio_mode 0x%08x\n", mode_code);
cmdConfig.pendingReboot = 1;
}
@@ -463,9 +537,9 @@ void process_command(uint8_t *data)
break;
case SET_DAC_VOLUME:
SET_SHARED_GLOBAL(g_dac_vol, data[CMD_DATA_POS]);
// 改动原因:仅记录待同步值,在 859 区域定时检测到值变化时才同步到 tile0
SET_SHARED_GLOBAL(g_pending_dac_vol, (unsigned)data[CMD_DATA_POS]);
send_len = send_user_cmd(send_data, SET_DAC_VOLUME, 1, 0);
SET_SHARED_GLOBAL(g_dac_vol, data[CMD_DATA_POS]);
debug_printf("set dac vol %d\n", data[CMD_DATA_POS]);
xmos_printf(send_data, send_len);
break;
@@ -477,47 +551,59 @@ void process_command(uint8_t *data)
xmos_printf(send_data, send_len);
break;
case HID_PASS_THROUGH:
user_set_hidpass(data);
debug_printf("hid_pass_through\n");
break;
case SET_ADC_VOLUME:
SET_SHARED_GLOBAL(g_adc_vol, data[CMD_DATA_POS]);
// 改动原因:仅记录待同步值,在 859 区域定时检测到值变化时才同步到 tile0
SET_SHARED_GLOBAL(g_pending_adc_vol, (unsigned)data[CMD_DATA_POS]);
send_len = send_user_cmd(send_data, SET_ADC_VOLUME, 1, 0);
xmos_printf(send_data, send_len);
break;
case SET_ADC_LOOP:
SET_SHARED_GLOBAL(g_adc_loop, data[CMD_DATA_POS]);
// 改动原因:仅记录待同步值,在 859 区域定时检测到值变化时才同步到 tile0
SET_SHARED_GLOBAL(g_pending_adc_loop, (unsigned)data[CMD_DATA_POS]);
debug_printf("set adc loop %d\n", data[CMD_DATA_POS]);
send_len = send_user_cmd(send_data, SET_ADC_LOOP, 1, 0);
xmos_printf(send_data, send_len);
break;
// 改动原因0x61 MCU主动设置静音状态给XU316与0x31 SET_ADC_LOOP一致直接设置g_mute_switch
case SET_MCU_MUTE_STATE:
if (length >= 1) {
unsigned mute_val = (data[CMD_DATA_POS] > 1) ? 0 : (unsigned)data[CMD_DATA_POS];
SET_SHARED_GLOBAL(g_mute_switch, mute_val);
debug_printf("set mcu mute state (0x61) %d\n", mute_val);
send_len = send_user_cmd(send_data, SET_MCU_MUTE_STATE, 0, 0);
xmos_printf(send_data, send_len);
}
break;
#if UAC1
case SET_3D_FPS:
SET_SHARED_GLOBAL(g_3d_fps, data[CMD_DATA_POS]);
// 改动原因:仅记录待同步值,在 859 区域定时检测到值变化时才同步到 tile0
SET_SHARED_GLOBAL(g_pending_3d_fps, (unsigned)data[CMD_DATA_POS]);
debug_printf("set 3d fps %d\n", data[CMD_DATA_POS]);
send_len = send_user_cmd(send_data, SET_3D_FPS, 1, 0);
xmos_printf(send_data, send_len);
break;
#endif
case SET_LED_MODE:
SET_SHARED_GLOBAL(g_led_mode, data[CMD_DATA_POS]);
// 改动原因:仅记录待同步值,在 859 区域定时检测到值变化时才同步到 tile0
SET_SHARED_GLOBAL(g_pending_led_mode, (unsigned)data[CMD_DATA_POS]);
debug_printf("set led mode %d\n", data[CMD_DATA_POS]);
send_len = send_user_cmd(send_data, SET_LED_MODE, 1, 0);
xmos_printf(send_data, send_len);
break;
// 改动原因0x5D/0x5E/0x60 仅由 XMOS 主动发给 MCUtile1 收到 tile0 sync 后发MCU 不会主动发这些0x5F 响应由 MCU 发回
case GET_MUTE_SWITCH:
// 改动原因MCU 对 0x5F 请求的响应1 字节静音值),与监听开关(g_adc_loop)一致先缓存为pending再在定时块按变化同步到tile0
if (length >= 1) {
unsigned mute_val = (data[CMD_DATA_POS] > 1) ? 0 : (unsigned)data[CMD_DATA_POS];
SET_SHARED_GLOBAL(g_pending_mute_switch, mute_val);
}
break;
// 改动原因0x61 MCU设置静音状态给XU316与0x31 SET_ADC_LOOP一致先缓存为pending定时块按变化同步到tile0sync 0x0E
case SET_MCU_MUTE_STATE:
if (length >= 1) {
unsigned mute_val = (data[CMD_DATA_POS] > 1) ? 0 : (unsigned)data[CMD_DATA_POS];
SET_SHARED_GLOBAL(g_pending_mute_switch, mute_val);
debug_printf("set mcu mute state (0x61) %d\n", mute_val);
send_len = send_user_cmd(send_data, SET_MCU_MUTE_STATE, 0, 0);
xmos_printf(send_data, send_len);
}
break;
case SET_INPUT_SOURCE:
case SET_MUTE_SWITCH:
case SET_LISTEN_SWITCH:
// 改动原因0x5D/0x5E/0x60 仅由 XMOS 发给 MCU若 MCU 发来则忽略
break;
case FW_VERSION:
send_len = send_user_cmd(send_data, FW_VERSION, 0, 3);
xmos_printf(send_data, send_len);
@@ -527,382 +613,12 @@ void process_command(uint8_t *data)
send_len = send_user_cmd(send_data, FLASH_ID, 0, 20);
xmos_printf(send_data, send_len);
break;
#if EQ_EN
// EQ命令处理 - 调用eq.c中的函数
case SET_EQ_MODE:
{
uint8_t mode = data[CMD_DATA_POS];
uint8_t result = process_uart_set_eq_mode(mode);
uint8_t send_len = 0;
// 发送确认响应
send_len = send_user_cmd(send_data, SET_EQ_MODE, 0, 0);
xmos_printf(send_data, send_len);
}
break;
case GET_EQ_MODE:
{
uint8_t response[64];
// 检查是否有模式参数(数据长度>0表示有参数
if (length > 0) {
uint8_t query_mode = data[CMD_DATA_POS];
debug_printf("GET_EQ_MODE with mode parameter: %d\n", query_mode);
// 如果mode不是0xFF临时设置request模式用于查询
if (query_mode != 0xFF) {
SET_SHARED_GLOBAL(g_request_eq_mode, query_mode);
}
}
uint8_t len = process_uart_get_eq_mode(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_MODE_GAIN_AND_NAME:
{
uint8_t result = process_uart_set_mode_gain_and_name(data);
uint8_t send_len = 0;
// 发送确认响应
send_len = send_user_cmd(send_data, SET_MODE_GAIN_AND_NAME, 0, 0);
xmos_printf(send_data, send_len);
}
break;
case SET_EQ_PARAMS:
{
uint8_t result = process_uart_set_eq_params(data);
uint8_t send_len = 0;
// 发送确认响应
send_len = send_user_cmd(send_data, SET_EQ_PARAMS, 0, 0);
xmos_printf(send_data, send_len);
}
break;
case GET_EQ_PARAMS:
{
uint8_t response[64];
uint8_t len = process_uart_get_eq_params(data, response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case RESET_EQ_PARAMS:
{
uint8_t result = process_uart_reset_eq_params(data);
uint8_t send_len = 0;
// 发送响应
send_data[CMD_DATA_POS] = result;
send_len = send_user_cmd(send_data, RESET_EQ_PARAMS, 0, 1);
xmos_printf(send_data, send_len);
}
break;
case GET_DEVICE_INFO:
{
uint8_t response[64];
uint8_t len = process_uart_get_device_info(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case GET_EQ_MODE_COUNT:
{
uint8_t response[64];
uint8_t len = process_uart_get_eq_mode_count(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_AND_SAVE_EQ_MODE:
{
uint8_t result = process_uart_set_and_save_eq_mode(data);
uint8_t send_len = 0;
// 发送响应
send_data[CMD_DATA_POS] = result;
send_len = send_user_cmd(send_data, SET_AND_SAVE_EQ_MODE, 0, 1);
xmos_printf(send_data, send_len);
}
break;
case SET_VOLUME:
// 改动原因使用g_dac_vol参考SET_DAC_VOLUME的实现方式直接设置全局变量
SET_SHARED_GLOBAL(g_dac_vol, data[CMD_DATA_POS]);
send_len = send_user_cmd(send_data, SET_VOLUME, 1, 0);
SET_SHARED_GLOBAL(g_dac_vol, data[CMD_DATA_POS]);
debug_printf("set volume %d\n", data[CMD_DATA_POS]);
xmos_printf(send_data, send_len);
break;
case GET_VOLUME:
// 改动原因直接读取g_dac_vol的值并返回参考SET_DAC_VOLUME的实现方式
{
uint8_t response[64];
unsigned dac_vol;
GET_SHARED_GLOBAL(dac_vol, g_dac_vol);
// 构建响应数据包0x55 0xAA 0x00 0x4A 0x01 [volume] [checksum]
response[0] = 0x55; // 帧头1
response[1] = 0xAA; // 帧头2
response[2] = 0x00; // 版本
response[3] = GET_VOLUME; // 命令码
response[4] = 0x01; // 数据长度
response[5] = (uint8_t)dac_vol; // 音量级别
// 计算校验和
uint8_t checksum_pos = 6;
// 改动原因使用check_sum函数计算校验和与send_user_cmd函数保持一致
unsafe {
response[checksum_pos] = check_sum(response, checksum_pos);
}
uint8_t len = checksum_pos + 1;
debug_printf("get volume %d\n", dac_vol);
xmos_printf(response, len);
}
break;
case GET_LED_INFO:
{
uint8_t led_index = data[CMD_DATA_POS];
uint8_t response[64];
uint8_t len = process_uart_get_led_info(led_index, response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_LED_SWITCH:
// 改动原因参考SET_LED_MODE直接设置g_led_mode的值0=关1=开
{
uint8_t led_index = data[CMD_DATA_POS];
uint8_t led_switch = data[CMD_DATA_POS + 1];
SET_SHARED_GLOBAL(g_led_mode, led_switch);
debug_printf("set led switch (g_led_mode) %d\n", led_switch);
uint8_t send_len = 0;
// 发送响应
send_data[CMD_DATA_POS] = 0; // 状态码:成功
send_len = send_user_cmd(send_data, SET_LED_SWITCH, 0, 1);
xmos_printf(send_data, send_len);
}
break;
case GET_LED_SWITCH:
// 改动原因参考SET_LED_MODE直接读取g_led_mode的值0=关1=开
{
uint8_t led_index = data[CMD_DATA_POS];
uint8_t response[64];
unsigned led_mode;
GET_SHARED_GLOBAL(led_mode, g_led_mode);
// 构建响应数据包0x55 0xAA 0x00 0x4D 0x02 [led_index] [led_mode] [checksum]
response[0] = 0x55; // 帧头1
response[1] = 0xAA; // 帧头2
response[2] = 0x00; // 版本
response[3] = GET_LED_SWITCH; // 命令码
response[4] = 0x02; // 数据长度
response[5] = led_index; // LED索引
response[6] = (uint8_t)led_mode; // LED开关状态
// 计算校验和
uint8_t checksum_pos = 7;
unsafe {
response[checksum_pos] = check_sum(response, checksum_pos);
}
uint8_t len = checksum_pos + 1;
debug_printf("get led switch (g_led_mode) %d\n", led_mode);
xmos_printf(response, len);
}
break;
case GET_LED_STATUS:
{
uint8_t led_index = data[CMD_DATA_POS];
uint8_t response[64];
uint8_t len = process_uart_get_led_status(led_index, response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case GET_LED_COUNT:
{
uint8_t response[64];
uint8_t len = process_uart_get_led_count(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case GET_UAC_MODE_INFO:
{
uint8_t response[64];
uint8_t len = process_uart_get_uac_mode_info(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_UAC_MODE:
{
uint8_t uac_mode = data[CMD_DATA_POS];
// process_uart_set_uac_mode(uac_mode);
// 设备重启,无响应
}
break;
case GET_CURRENT_UAC_MODE:
{
uint8_t response[64];
uint8_t len = process_uart_get_current_uac_mode(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_EQ_ENABLE:
{
uint8_t enable = data[CMD_DATA_POS];
uint8_t result = process_uart_set_eq_enable(enable);
uint8_t response[64];
uint8_t len = process_uart_get_eq_enable_response(result, enable, response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case GET_EQ_ENABLE:
{
debug_printf("user_uart.xc: GET_EQ_ENABLE command received, start processing\n");
uint8_t response[64];
uint8_t len = process_uart_get_eq_enable(response, sizeof(response));
debug_printf("user_uart.xc: GET_EQ_ENABLE process_uart_get_eq_enable returned len=%d\n", len);
if (len > 0) {
debug_printf("user_uart.xc: GET_EQ_ENABLE sending response, length=%d, data: ", len);
for (int i = 0; i < len && i < 16; i++) {
debug_printf("%02X ", response[i]);
}
debug_printf("\n");
xmos_printf(response, len);
debug_printf("user_uart.xc: GET_EQ_ENABLE response sent\n");
} else {
debug_printf("user_uart.xc: GET_EQ_ENABLE error - process_uart_get_eq_enable returned len=0\n");
}
}
break;
case GET_SAMPLE_FORMAT:
{
uint8_t response[64];
uint8_t len = process_uart_get_sample_format(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_GAIN_MODE:
{
uint8_t gain_mode = data[CMD_DATA_POS];
uint8_t result = process_uart_set_gain_mode(gain_mode);
// 无需发送响应,根据协议描述
}
break;
case GET_GAIN_MODE:
{
uint8_t response[64];
uint8_t len = process_uart_get_gain_mode(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_FILTER_MODE:
{
uint8_t filter_mode = data[CMD_DATA_POS];
uint8_t result = process_uart_set_filter_mode(filter_mode);
// 无需发送响应,根据协议描述
}
break;
case GET_FILTER_MODE:
{
uint8_t response[64];
uint8_t len = process_uart_get_filter_mode(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case SET_GAME_MODE:
{
uint8_t game_mode = data[CMD_DATA_POS];
// 改动原因UART 0x5A命令透传给MCU处理MCU负责执行模式设置和参数保存
// process_uart_set_game_mode(game_mode);
// 无需发送响应,根据协议描述
}
break;
case GET_GAME_MODE:
{
uint8_t response[64];
uint8_t len = process_uart_get_game_mode(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
case GET_FIRMWARE_VERSION:
{
uint8_t response[64];
uint8_t len = process_uart_get_firmware_version(response, sizeof(response));
if (len > 0) {
xmos_printf(response, len);
}
}
break;
// 改动原因添加0x5D SET_INPUT_SOURCE由HID 0xB0触发后XMOS主动发给MCU若MCU发来0x5D则忽略
case SET_INPUT_SOURCE:
break;
// 改动原因添加0x5E SET_MUTE_SWITCH由HID 0xB1触发后XMOS发给MCU若MCU发来0x5E则忽略
case SET_MUTE_SWITCH:
break;
// 改动原因0x5F GET_MUTE_SWITCH 响应由MCU发来含1字节静音值与g_adc_loop一致直接设置g_mute_switch0xB2读与变化上报均用g_mute_switch
case GET_MUTE_SWITCH:
if (length >= 1) {
unsigned mute_val = (data[CMD_DATA_POS] > 1) ? 0 : (unsigned)data[CMD_DATA_POS];
SET_SHARED_GLOBAL(g_mute_switch, mute_val);
}
break;
// 改动原因添加0x60 SET_LISTEN_SWITCH由HID 0xB3触发后XMOS发给MCU若MCU发来0x60则忽略
case SET_LISTEN_SWITCH:
break;
#endif
}
}
cmdConfig.cmdCount = 0;
}
void xmos_uart_receive(void)
{
static unsigned cmd_start_time = 0;
@@ -1137,115 +853,113 @@ void heatTick(unsigned long boot_time)
}
extern unsigned GetDFUFlag();
extern uint8_t key_validate(uint8_t offset);
extern void flash_opt_unlock(void);
/* 改动原因:固件升级 START 已移至 AudioHwRemote2不再在此接收 c_dfu */
void uart_handler(streaming chanend c_tx, streaming chanend c_rx)
void uart_handler(streaming chanend c_tx, streaming chanend c_rx,chanend c_sync)
{
unsigned long boot_time = get_reference_time();
long int flag = 0;
long int dfu_flag = 0x11042011;
uint8_t uart_rx_byte;
g_xu316_id = read_key();
unsigned long heat_tick_time = get_reference_time() + BEAT_DELAY * 10;
// 改动原因保存同步channel到全局变量供process_command使用使用unsafe转换
unsafe {
g_c_uart_sync = (chanend)c_sync;
}
cmdConfig.pendingReboot = 0;
cmdConfig.cmdPending = CMD_NONE;
unsigned long se_time = 0;
timer se_tmr;
se_tmr :> se_time;
se_time += 2000000;
#if UAC1
delay_milliseconds(100);
#endif
#if XUA_DFU_EN
flag = GetDFUFlag();
#endif
// delay_milliseconds(100);
if (key_validate(1) == 1)
{
SetKeyFlag(0x20241224);
}
flash_opt_unlock();
#if BOOT_MODE
load_configs();
#if (XUA_DFU_EN == 1)
get_pid_vid();
if (flag == dfu_flag)
SET_SHARED_GLOBAL(g_usb_state, 1);
#if (FACT_MODE == 1)
SET_SHARED_GLOBAL(g_usb_state, 1);
return;
#endif
#endif
#else
cmdConfig.startApp = 3;
#if (NUM_USB_CHAN_OUT != 0) || (NUM_USB_CHAN_IN != 0)
load_configs();
get_pid_vid();
SET_SHARED_GLOBAL(g_usb_state, 1);
#endif
// 改动原因:load_configs和get_pid_vid需要在tile0执行Flash访问和PID/VID设置通过同步channel发送
// 注意此时g_c_uart_sync已经设置可以直接使用
sync_to_tile0(0x01, 0, 0); // SYNC_CMD_LOAD_CONFIGS
sync_to_tile0(0x06, 0, 0); // SYNC_CMD_GET_PID_VID
#endif
boot_time = get_reference_time();
static unsigned char heat_tick_first_executed = 0; // 改动原因跟踪heatTick是否已执行过第一次
while(1)
{
select {
case c_rx :> uart_rx_byte:
#if HID_DFU_EN
if (!g_in_fw_upgrade)
#endif
{
X_RXbuff[X_Rxfp] = uart_rx_byte;
X_Rxfp = (X_Rxfp + 1) % MAX_RX_LEN;
//debug_printf("in[%02x] %d %d len %d\n", uart_rx_byte, X_Rxfp, X_Rxrp, MAX_RX_LEN - ((X_Rxfp - X_Rxrp + MAX_RX_LEN) % MAX_RX_LEN));
xmos_uart_receive();
}
break;
case se_tmr when timerafter(se_time) :> void :
se_time += 400000;
/* 改动原因:若有固件升级开始/结束通知,先组包 0x62 发给 MCU再清零标志 */
#if HID_DFU_EN
{
unsigned notify = get_firmware_upgrade_mcu_notify();
if (notify != 0)
{
unsigned char response[8];
response[0] = 0x55;
response[1] = 0xAA;
response[2] = 0x01;
response[3] = (unsigned char)FIRMWARE_UPGRADE_NOTIFY;
response[4] = 0x01;
response[5] = (unsigned char)notify;
unsafe {
response[6] = check_sum((unsigned char *)response, 6);
}
xmos_printf(response, 7);
clear_firmware_upgrade_mcu_notify();
}
}
#endif
#if XUA_DFU_EN
if (flag != dfu_flag)
#endif
{
xmos_printf_pross(c_tx);
heatTick(boot_time);
// 改动原因第一次执行要在boot_time后200ms后续一直执行
unsigned long tick_now = get_reference_time();
if (heat_tick_first_executed == 0) {
// 第一次执行检查是否已经过了boot_time + 200ms
if (timeafter(tick_now, boot_time + 20000000)) { // 200ms = 20000000 时间单位参考SEND_CMD_TIMEOUT
heatTick(boot_time);
heat_tick_first_executed = 1;
}
} else {
// 后续执行:一直执行
heatTick(boot_time);
}
}
/* 改动原因0x07/0x08/0x09/0x0C/0x0D/0x0E 仅当 pending 与 last_sync 不同时才同步到 tile0 */
{
unsigned pending_val, last_val;
GET_SHARED_GLOBAL(pending_val, g_pending_dac_vol);
GET_SHARED_GLOBAL(last_val, g_last_sync_dac_vol);
if (pending_val != last_val) {
sync_to_tile0(0x07, pending_val, 0); /* SYNC_CMD_SET_DAC_VOLUME */
SET_SHARED_GLOBAL(g_last_sync_dac_vol, pending_val);
}
GET_SHARED_GLOBAL(pending_val, g_pending_adc_vol);
GET_SHARED_GLOBAL(last_val, g_last_sync_adc_vol);
if (pending_val != last_val) {
sync_to_tile0(0x08, pending_val, 0); /* SYNC_CMD_SET_ADC_VOLUME */
SET_SHARED_GLOBAL(g_last_sync_adc_vol, pending_val);
}
#if UAC1
GET_SHARED_GLOBAL(pending_val, g_pending_3d_fps);
GET_SHARED_GLOBAL(last_val, g_last_sync_3d_fps);
if (pending_val != last_val) {
sync_to_tile0(0x09, pending_val, 0); /* SYNC_CMD_SET_3D_FPS */
SET_SHARED_GLOBAL(g_last_sync_3d_fps, pending_val);
}
#endif
GET_SHARED_GLOBAL(pending_val, g_pending_led_mode);
GET_SHARED_GLOBAL(last_val, g_last_sync_led_mode);
if (pending_val != last_val) {
sync_to_tile0(0x0C, pending_val, 0); /* SYNC_CMD_SET_LED_MODE */
SET_SHARED_GLOBAL(g_last_sync_led_mode, pending_val);
}
GET_SHARED_GLOBAL(pending_val, g_pending_adc_loop);
GET_SHARED_GLOBAL(last_val, g_last_sync_adc_loop);
if (pending_val != last_val) {
sync_to_tile0(0x0D, pending_val, 0); /* SYNC_CMD_SET_ADC_LOOP */
SET_SHARED_GLOBAL(g_last_sync_adc_loop, pending_val);
}
GET_SHARED_GLOBAL(pending_val, g_pending_mute_switch);
GET_SHARED_GLOBAL(last_val, g_last_sync_mute_switch);
if (pending_val != last_val) {
sync_to_tile0(0x0E, pending_val, 0); /* SYNC_CMD_MUTE_VALUE_FROM_MCU */
SET_SHARED_GLOBAL(g_last_sync_mute_switch, pending_val);
}
GET_SHARED_GLOBAL(pending_val, g_pending_mcu_mute);
GET_SHARED_GLOBAL(last_val, g_last_sync_mcu_mute);
if (pending_val != last_val) {
sync_to_tile0(0x0F, pending_val, 0); /* SYNC_CMD_SET_MCU_MUTE_STATE */
SET_SHARED_GLOBAL(g_last_sync_mcu_mute, pending_val);
}
}
if (cmdConfig.pendingReboot == 1)
{