Compare commits
13 Commits
synido_sy1
...
nsync_6ch_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b218d47ac | ||
|
|
f5f6426a0f | ||
|
|
a15bfeb615 | ||
|
|
d5338de59b | ||
|
|
d0e98ea135 | ||
|
|
8b56f5cd2d | ||
|
|
9696395dcf | ||
|
|
7d9ea4b367 | ||
|
|
38c105d37d | ||
|
|
e9aa3b4f51 | ||
|
|
207ea21b3f | ||
|
|
5a9bdf6936 | ||
|
|
fcb0ddd7f5 |
@@ -31,9 +31,9 @@ XUD_Result_t HidInterfaceClassRequests(
|
||||
#endif
|
||||
USB_SetupPacket_t &sp )
|
||||
{
|
||||
unsigned char buffer[65] = {0};
|
||||
#if ((USE_EX3D == 1) || (EQ_EN == 1) || (DEBUG_MEMORY_LOG_ENABLED == 1) )
|
||||
unsigned datalength;
|
||||
unsigned char buffer[65] = {0};
|
||||
#endif
|
||||
XUD_Result_t result = XUD_RES_ERR;
|
||||
|
||||
@@ -83,7 +83,7 @@ XUD_Result_t HidInterfaceClassRequests(
|
||||
#endif
|
||||
}
|
||||
|
||||
if (buffer[1] == 0x77 && buffer[2] >= 0x8A)
|
||||
if (buffer[1] == 0x77 && buffer[2] >= 0x82)
|
||||
{
|
||||
process_send_params(&buffer[1], datalength - 1);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ endif()
|
||||
# Firmware version (maps to BCD_DEVICE_J.M.N in USB descriptor)
|
||||
set(FW_VER_J 1)
|
||||
set(FW_VER_M 0)
|
||||
set(FW_VER_N 0)
|
||||
set(FW_VER_N 2)
|
||||
set(FW_VERSION "v${FW_VER_J}.${FW_VER_M}.${FW_VER_N}")
|
||||
|
||||
set(SW_USB_AUDIO_FLAGS ${EXTRA_BUILD_FLAGS} -Os
|
||||
@@ -156,6 +156,7 @@ set(APP_COMPILER_FLAGS_f1_music_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC
|
||||
-DOUTPUT_VOLUME_CONTROL=1
|
||||
#-DDEBUG_MEMORY_LOG_ENABLED=1
|
||||
-DXUA_DFU_EN=1
|
||||
-DHID_DFU_EN=1
|
||||
#-DIR_SWITCHING_MODE
|
||||
-DHID_CONTROLS=1)
|
||||
|
||||
@@ -181,6 +182,7 @@ set(APP_COMPILER_FLAGS_f3_f4_fps_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
|
||||
-DOUTPUT_VOLUME_CONTROL=1
|
||||
#-DDEBUG_MEMORY_LOG_ENABLED=1
|
||||
-DXUA_DFU_EN=1
|
||||
-DHID_DFU_EN=1
|
||||
-DIR_SWITCHING_MODE
|
||||
-DHID_CONTROLS=1)
|
||||
set(APP_COMPILER_FLAGS_f6_f7_fps_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
|
||||
@@ -204,6 +206,7 @@ set(APP_COMPILER_FLAGS_f6_f7_fps_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
|
||||
-DOUTPUT_VOLUME_CONTROL=1
|
||||
#-DDEBUG_MEMORY_LOG_ENABLED=1
|
||||
-DXUA_DFU_EN=1
|
||||
-DHID_DFU_EN=1
|
||||
-DIR_SWITCHING_MODE
|
||||
-DHID_CONTROLS=1)
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
xflash --factory-version 15.3 --target-file src/core/synido.xn --upgrade 2 bin\ex3d_UAC1\app_usb_aud_phaten_gs_ex3d_UAC1.xe --upgrade 4 bin/ex3d_stereo_2k/app_usb_aud_phaten_gs_ex3d_stereo_2k.xe --upgrade 1 bin\ex3d_71_game\app_usb_aud_phaten_gs_ex3d_71_game.xe --upgrade 3 bin\ex3d_71_movie\app_usb_aud_phaten_gs_ex3d_71_movie.xe -o %1
|
||||
|
||||
xflash --factory-version 15.3 --target-file src/core/synido.xn --upgrade 2 bin/f5_music_uac1/app_usb_aud_sy102_f5_music_uac1.xe --upgrade 3 bin/f1_music_uac2/app_usb_aud_sy102_f1_music_uac2.xe --upgrade 1 bin/f3_f4_fps_uac2/app_usb_aud_sy102_f3_f4_fps_uac2.xe -o %1
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
<Port Location="XS1_PORT_8D" Name="PORT_HP_GAIN_ENCODER"/> <!-- 8D4: HP_GAIN_ENCODER_INPUT_1; 8D5: HP_GAIN_ENCODER_INPUT_2; 8D6: HP MUTE -->
|
||||
<!-- Buttons -->
|
||||
<Port Location="XS1_PORT_1A" Name="PORT_BUTTON_MUSIC_MODE"/>
|
||||
<Port Location="XS1_PORT_1L" Name="PORT_BUTTON_GAME_MODE"/>
|
||||
<Port Location="XS1_PORT_1M" Name="PORT_BUTTON_AI71_ONOFF"/>
|
||||
<Port Location="XS1_PORT_1M" Name="PORT_BUTTON_GAME_MODE"/>
|
||||
<Port Location="XS1_PORT_1L" Name="PORT_BUTTON_AI71_ONOFF"/>
|
||||
|
||||
<!-- Clocking -->
|
||||
<Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/>
|
||||
|
||||
@@ -110,19 +110,11 @@
|
||||
/*** Defines relating to audio frequencies ***/
|
||||
/* Master clock defines (in Hz) */
|
||||
#ifndef MCLK_441
|
||||
#if defined(F1_MUSIC_UAC2)
|
||||
#define MCLK_441 (1024*44100) /* 44.1, 88.2 etc */
|
||||
#else
|
||||
#define MCLK_441 (256*44100) /* 44.1, 88.2 etc */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#if defined(F1_MUSIC_UAC2)
|
||||
#define MCLK_48 (1024*48000) /* 48, 96 etc */
|
||||
#else
|
||||
#define MCLK_48 (256*48000) /* 48, 96 etc */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Minumum sample frequency device runs at */
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "debug_print.h"
|
||||
#include "roleswitchflag.h"
|
||||
#include "xua_hid_report.h"
|
||||
#include "lfs_io.h"
|
||||
|
||||
#if defined (CODEC_AIC3204)
|
||||
#include "eq_flash_storage.h"
|
||||
@@ -80,13 +81,15 @@ unsigned g_volume_level = 29, g_saved_volume_level = 29;
|
||||
unsigned g_request_volume_set = 0;
|
||||
unsigned g_init_saved_settings = 0;
|
||||
unsigned g_host_volume = 0x0;
|
||||
// HID主动上报缓冲区(被eq.c通过extern引用)
|
||||
unsigned char g_hid_status_report_data[63] = {0};
|
||||
unsigned int g_hid_status_report_index = 0;
|
||||
unsigned g_last_volume_level = 0xFF; // 上次已上报的音量级别,0xFF表示初始化未完成
|
||||
unsigned g_mic_volume_level = 37; // 麦克风PGA增益级别(0=mute, 1-37=0dB~36dB,HID可见范围)
|
||||
unsigned g_request_mic_volume_set = 0;
|
||||
unsigned g_last_mic_volume_level = 0xFF; // 上次已上报的麦克风增益级别,0xFF表示初始化未完成
|
||||
unsigned g_dnr_strength = 100; // AI降噪强度HID值(0=关,2-100=开,步进2;100→-200dB最强)
|
||||
unsigned g_last_dnr_strength = 0xFF; // 上次已上报的降噪强度,0xFF表示首次未上报(触发开机上报)
|
||||
unsigned g_request_dnr_strength_set = 0; // HID 0x85 SET_AI_NOISE_STRENGTH待处理标志
|
||||
unsigned g_monitor_switch = 0; // 耳返开关(0=关闭,1=开启),默认关闭
|
||||
unsigned g_request_monitor_switch_set = 0; // HID 0x87 SET_MONITOR_SWITCH待处理标志
|
||||
unsigned g_dac_m_gain = 0;
|
||||
unsigned g_unmute_delay_time = 0;
|
||||
unsigned g_format_delay_time = 0;
|
||||
@@ -103,16 +106,12 @@ unsigned g_disable_i2c = 0;
|
||||
unsigned g_dac_mode = 10;
|
||||
unsigned g_new_dac_mode = 0;
|
||||
unsigned g_samfreq = 48000;
|
||||
unsigned g_dsd_mode = 0;
|
||||
unsafe chanend uc_audiohw; // tile[1] end: AudioHwConfig → button_task (tile[0])
|
||||
// 改动原因:添加DSD模式全局变量,用于HID命令读取采样率和格式信息(已去掉DAC采样分辨率)
|
||||
unsigned g_dsd_mode = 0; // DSD模式:0=PCM, >0=DSD
|
||||
unsigned g_gain_mode = 0; // 0: 低阻, 1: 高阻
|
||||
// 改动原因:支持8种滤波器模式(0-7),与g_filter_map[8]数组定义一致
|
||||
unsigned g_filter_mode = 0; // 0-7: 对应8种滤波器模式
|
||||
#if HID_DFU_EN
|
||||
unsafe streaming chanend uc_dfu; // tile[1] send end: hid_button_task → button_task (tile[0])
|
||||
#endif
|
||||
// 改动原因:添加增益模式和滤波器模式的请求变量,用于HID命令设置模式
|
||||
unsigned g_request_gain_mode = -1; // -1表示无请求,0=低阻,1=高阻
|
||||
// 改动原因:支持8种滤波器模式(0-7),与g_filter_map[8]数组定义一致
|
||||
unsigned g_request_filter_mode = -1; // -1表示无请求,0-7=滤波器模式
|
||||
unsigned g_request_game_mode = -1;
|
||||
|
||||
#if EQ_EN
|
||||
@@ -211,7 +210,7 @@ void dac_volume(signed level)
|
||||
|
||||
void mic_volume(unsigned level)
|
||||
{
|
||||
if (level == 0)
|
||||
if (level == 0 || level == 1)
|
||||
{
|
||||
// mute: 关闭PGA和输出放大器
|
||||
unsafe {NAU88C22_REGWRITE(0x007E, 0, (client interface i2c_master_if)i_i2c_client);}
|
||||
@@ -273,6 +272,9 @@ in port p_button_ai71_onoff = PORT_BUTTON_AI71_ONOFF; // 1M
|
||||
|
||||
#define KEY_POLLING_INTERVAL 10000000L // 100ms polling interval
|
||||
#define TIMER_PERIOD (100000)
|
||||
#define FACTORY_RESET_HOLD_TICKS 3000 // 3000 × 1ms = 3秒
|
||||
#define FACTORY_RESET_BLINK_TICKS 400 // 每相400ms
|
||||
#define BTN_COMBO_DELAY_TICKS 40 // 单键去抖/组合检测窗口(50ms)
|
||||
|
||||
unsigned g_windows_detect_done = 0;
|
||||
|
||||
@@ -283,6 +285,7 @@ extern unsigned g_host_os; // 1 -> Windows, 2 -> Others
|
||||
extern unsigned g_mute_on_off_t0;
|
||||
extern unsigned g_uac_vol;
|
||||
extern void dnr_set_mode(unsigned char mode);
|
||||
extern void dnr_set_strength_level(unsigned char strength);
|
||||
|
||||
extern void device_reboot(void);
|
||||
|
||||
@@ -294,9 +297,36 @@ enum {IR_OFF=0, IR_GAME=1, IR_MUSIC=2, IR_MOVIE=3, IR_7_1_GAME=4, IR_7_1_MUSIC=5
|
||||
#ifndef HID_MAX_DATA_BYTES
|
||||
#define HID_MAX_DATA_BYTES ( 64 )
|
||||
#endif
|
||||
unsigned hidSendData_local[HID_MAX_DATA_BYTES / 4];
|
||||
extern unsigned hidSendData[];
|
||||
|
||||
void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx)
|
||||
#if HID_DFU_EN
|
||||
#include "dfu_upgrade.h"
|
||||
/* 将HID收到的63字节固件升级START命令打包为16个unsigned word,
|
||||
* 通过uc_dfu streaming channel发送到button_task (tile[0])执行。
|
||||
* 从eq.c的process_send_params中对0xA7命令调用此函数。 */
|
||||
void dfu_chan_forward(unsigned char data[], unsigned len)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
for (int i = 0; i < 16; i++) {
|
||||
unsigned word = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
int idx = i * 4 + j;
|
||||
if (idx < 63) {
|
||||
word |= ((unsigned)data[idx]) << (j * 8);
|
||||
}
|
||||
}
|
||||
uc_dfu <: word;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx
|
||||
#if HID_DFU_EN
|
||||
, streaming chanend c_dfu_rx
|
||||
#endif
|
||||
)
|
||||
{
|
||||
//hwtimer_t timer = hwtimer_alloc();
|
||||
unsigned time = 0;
|
||||
@@ -352,6 +382,7 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
unsigned flag_footsteps_enhancement = 2;
|
||||
// 出厂默认:AI降噪开启
|
||||
unsigned flag_aidenoise_onoff = 1;
|
||||
unsigned dnr_strength_saved = 100; // AI降噪重新开启时恢复的强度(0x85可更新)
|
||||
|
||||
// Buttons state
|
||||
unsigned push_button_music_mode_state_old = 1; // Active low
|
||||
@@ -368,6 +399,16 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
unsigned push_button_mic_mute_state_old = 1; // Active low
|
||||
unsigned push_button_hp_mute_state_old = 1; // Active low
|
||||
|
||||
// 出厂恢复长按状态机:音乐+游戏同时长按3秒
|
||||
unsigned factory_reset_hold_count = 0; // 两键同时按住计数(×1ms)
|
||||
unsigned factory_reset_blink_state = 0; // 0=空闲,1-6=闪烁相位
|
||||
unsigned factory_reset_blink_tick = 0; // 当前相位内计数
|
||||
// 组合键去抖:单键动作延迟 BTN_COMBO_DELAY_TICKS 后触发,期间若另一键也按下则切换为组合模式
|
||||
unsigned btn_music_hold_ticks = 0; // music键连续按住计数
|
||||
unsigned btn_game_hold_ticks = 0; // game键连续按住计数
|
||||
unsigned btn_combo_active = 0; // 1=处于组合键模式(单键动作已抑制)
|
||||
unsigned fr_inhibit = 0; // 1=出厂恢复重启后抑制状态,必须松键后才允许重新触发
|
||||
|
||||
int current_mic_led_pos = 0;
|
||||
|
||||
htr3236_t htr3236_dev;
|
||||
@@ -382,6 +423,9 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
unsigned char path[] = "game_mode";
|
||||
unsigned char mic_vol_path[] = "mic_vol";
|
||||
unsigned char dac_vol_path[] = "dac_vol";
|
||||
unsigned char mic_mute_path[] = "mic_mute";
|
||||
unsigned char hp_mute_path[] = "hp_mute";
|
||||
unsigned char monitor_sw_path[] = "monitor_sw";
|
||||
unsigned host_os;
|
||||
|
||||
delay_milliseconds(10);
|
||||
@@ -407,22 +451,6 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
#if defined(UAC1_MODE)
|
||||
delay_milliseconds(300);
|
||||
GET_SHARED_GLOBAL(host_os, g_host_os);
|
||||
if (saved_mode == 255) {
|
||||
#if defined(F5_MUSIC_UAC1)
|
||||
saved_mode = 1; // f5: default music mode
|
||||
#else
|
||||
saved_mode = 0; // f6/f7: default off
|
||||
#endif
|
||||
save_value(path, saved_mode);
|
||||
debug_printf("Saved game_mode to flash: %d\n", saved_mode);
|
||||
}
|
||||
#else
|
||||
if (saved_mode == 255) {
|
||||
// 出厂默认:AI7.1开启(mode=3)
|
||||
saved_mode = 3;
|
||||
save_value(path, saved_mode);
|
||||
debug_printf("Saved game_mode to flash: %d\n", saved_mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("host_os: %d\n", host_os);
|
||||
@@ -447,6 +475,25 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
|
||||
g_windows_detect_done = 1;
|
||||
|
||||
#if defined(UAC1_MODE)
|
||||
if (saved_mode == 255) {
|
||||
#if defined(F5_MUSIC_UAC1)
|
||||
saved_mode = 1; // f5: default music mode
|
||||
#else
|
||||
saved_mode = 0; // f6/f7: default off
|
||||
#endif
|
||||
save_value(path, saved_mode);
|
||||
debug_printf("Saved game_mode to flash: %d\n", saved_mode);
|
||||
}
|
||||
#else
|
||||
if (saved_mode == 255) {
|
||||
// 出厂默认:AI7.1开启(mode=3)
|
||||
saved_mode = 3;
|
||||
save_value(path, saved_mode);
|
||||
debug_printf("Saved game_mode to flash: %d\n", saved_mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
active_mode = (saved_mode <= 3) ? saved_mode : 0;
|
||||
{
|
||||
@@ -513,16 +560,54 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
dac_level = saved_dac;
|
||||
else
|
||||
save_value(dac_vol_path, (unsigned char)dac_level); // 出厂默认15(-14dB)
|
||||
|
||||
// 从Flash恢复耳返开关(默认关闭)
|
||||
unsigned char saved_monitor_sw = load_value(monitor_sw_path);
|
||||
if(saved_monitor_sw == 1)
|
||||
g_monitor_switch = 1;
|
||||
else if(saved_monitor_sw == 255) {
|
||||
// 未初始化:出厂默认关闭
|
||||
g_monitor_switch = 0;
|
||||
save_value(monitor_sw_path, (unsigned char)0);
|
||||
} else {
|
||||
g_monitor_switch = 0;
|
||||
}
|
||||
debug_printf("Loaded monitor_switch from flash: %d\n", g_monitor_switch);
|
||||
|
||||
// 从Flash恢复mic_mute状态(默认关闭=未静音)
|
||||
unsigned char saved_mic_mute = load_value(mic_mute_path);
|
||||
if(saved_mic_mute == 1)
|
||||
flag_mic_mute = 1;
|
||||
else {
|
||||
flag_mic_mute = 0;
|
||||
if(saved_mic_mute == 255)
|
||||
save_value(mic_mute_path, (unsigned char)0);
|
||||
}
|
||||
debug_printf("Loaded mic_mute from flash: %d\n", flag_mic_mute);
|
||||
|
||||
// 从Flash恢复hp_mute状态(默认关闭=未静音)
|
||||
unsigned char saved_hp_mute = load_value(hp_mute_path);
|
||||
if(saved_hp_mute == 1)
|
||||
flag_hp_mute = 1;
|
||||
else {
|
||||
flag_hp_mute = 0;
|
||||
if(saved_hp_mute == 255)
|
||||
save_value(hp_mute_path, (unsigned char)0);
|
||||
}
|
||||
debug_printf("Loaded hp_mute from flash: %d\n", flag_hp_mute);
|
||||
}
|
||||
|
||||
codec_init();
|
||||
// 同步全局音量变量与从Flash恢复的dac_level / codec_adc_pga_gain_reg_value
|
||||
g_volume_level = dac_level;
|
||||
// 麦克风HID范围上限37 (register=38的+1.5dB仅firmware内部使用)
|
||||
g_mic_volume_level = (codec_adc_pga_gain_reg_value <= 37) ? codec_adc_pga_gain_reg_value : 37;
|
||||
|
||||
// ADCL PGA default setting
|
||||
mic_volume(codec_adc_pga_gain_reg_value); // make sure to write adc reg after initialize the codec, otherwise it does not take effect because of the hardware reset in the initial code
|
||||
// ADCL PGA default setting(mic_volume内部已根据g_monitor_switch决定是否启用耳返通路)
|
||||
// 若mic_mute已从flash恢复为1,则此处先以正常gain调用,再用mute覆盖
|
||||
mic_volume(codec_adc_pga_gain_reg_value);
|
||||
{
|
||||
int mic_led_count = mic_gain_to_led[codec_adc_pga_gain_reg_value];
|
||||
int mic_led_count = flag_mic_mute ? 0 : mic_gain_to_led[codec_adc_pga_gain_reg_value];
|
||||
for(int i = 0; i < 15; i++)
|
||||
{
|
||||
if (i < mic_led_count)
|
||||
@@ -531,6 +616,17 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
led_off(&led_ctx, led_l_physical_map[i]);
|
||||
}
|
||||
}
|
||||
// 应用从flash恢复的mic_mute状态
|
||||
if(flag_mic_mute) {
|
||||
mic_volume(0);
|
||||
g_mic_volume_level = 0;
|
||||
}
|
||||
|
||||
if ((g_monitor_switch == 1) && !flag_mic_mute && codec_adc_pga_gain_reg_value >= 2) {
|
||||
unsafe { NAU88C22_REGWRITE(0x0030, 0xff00, (client interface i2c_master_if)i_i2c_client); }
|
||||
} else {
|
||||
unsafe { NAU88C22_REGWRITE(0x0030, 0x0000, (client interface i2c_master_if)i_i2c_client); }
|
||||
}
|
||||
|
||||
// DAC 默认音量(mute 时写 0x0000)
|
||||
if(dac_level == DAC_LEVEL_MIN)
|
||||
@@ -538,7 +634,7 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
else
|
||||
dac_volume(dac_level - DAC_LEVEL_MAX);
|
||||
{
|
||||
int dac_led_count = dac_gain_to_led[dac_level];
|
||||
int dac_led_count = flag_hp_mute ? 0 : dac_gain_to_led[dac_level];
|
||||
for(int i = 0; i < 15; i++)
|
||||
{
|
||||
if (i < dac_led_count)
|
||||
@@ -547,6 +643,11 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
led_off(&led_ctx, led_d_physical_map[i]);
|
||||
}
|
||||
}
|
||||
// 应用从flash恢复的hp_mute状态
|
||||
if(flag_hp_mute) {
|
||||
unsafe { NAU88C22_REGWRITE(0x0034, 0x0000, (client interface i2c_master_if)i_i2c_client); }
|
||||
g_volume_level = 0;
|
||||
}
|
||||
// Initialize mode button LEDs: at most one may be lit at a time
|
||||
led_off(&led_ctx, LED_MUSIC);
|
||||
led_off(&led_ctx, LED_GAME_MODE);
|
||||
@@ -562,7 +663,6 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
|
||||
unsigned hidData0;
|
||||
delay_milliseconds(200);
|
||||
codec_init();
|
||||
|
||||
debug_printf("button task start\n");
|
||||
|
||||
@@ -621,20 +721,27 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
last_ctrl_keys ^= KEY_MUTE;
|
||||
|
||||
|
||||
// 启动时若两键同时按住,设置抑制标志,必须松开后才允许触发出厂恢复
|
||||
{
|
||||
unsigned music_init, game_init;
|
||||
p_button_music_mode :> music_init;
|
||||
p_button_game_mode :> game_init;
|
||||
if (music_init == 0 && game_init == 0) {
|
||||
fr_inhibit = 1;
|
||||
btn_combo_active = 1;
|
||||
debug_printf("Boot: both keys held, FR inhibited until release\n");
|
||||
}
|
||||
}
|
||||
|
||||
//hwtimer_set_trigger_time(timer, hwtimer_get_time(timer) + KEY_POLLING_INTERVAL);
|
||||
tmr :> time; /* Input the time */
|
||||
time += TIMER_PERIOD; /* Increment the time */
|
||||
|
||||
|
||||
|
||||
|
||||
while (1) {
|
||||
select
|
||||
{
|
||||
case c_hidSendData :> hidData0:
|
||||
{
|
||||
unsigned *reportData = hidSendData_local;
|
||||
reportData[0] = hidData0;
|
||||
if (hidData0 == 0xffffffff) {
|
||||
debug_printf("receive end data\n");
|
||||
|
||||
@@ -727,12 +834,20 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#if (HID_CONTROLS == 1)
|
||||
for (int i=1; i<(HID_MAX_DATA_BYTES/4); i++) {
|
||||
c_hidSendData :> reportData[i];
|
||||
}
|
||||
hidSetChangePending(1);
|
||||
|
||||
#if HID_DFU_EN
|
||||
if (!g_in_fw_upgrade)
|
||||
#endif
|
||||
{
|
||||
#if (HID_CONTROLS == 1)
|
||||
unsigned *reportData = hidSendData;
|
||||
reportData[0] = hidData0;
|
||||
for (int i=1; i<(HID_MAX_DATA_BYTES/4); i++) {
|
||||
c_hidSendData :> reportData[i];
|
||||
}
|
||||
hidSetChangePending(1);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -780,21 +895,46 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
c_audiohw_rx <: 0xff;
|
||||
|
||||
#if HID_CONTROLS > 0
|
||||
g_hid_status_report_data[0] = 0x77;
|
||||
g_hid_status_report_data[1] = 0x9F;
|
||||
g_hid_status_report_data[2] = (unsigned char)(new_samfreq & 0xFF);
|
||||
g_hid_status_report_data[3] = (unsigned char)((new_samfreq >> 8) & 0xFF);
|
||||
g_hid_status_report_data[4] = (unsigned char)((new_samfreq >> 16) & 0xFF);
|
||||
g_hid_status_report_data[5] = (unsigned char)((new_samfreq >> 24) & 0xFF);
|
||||
g_hid_status_report_data[6] = (unsigned char)new_dsd_mode;
|
||||
for (int i = 7; i < 63; i++)
|
||||
g_hid_status_report_data[i] = 0x00;
|
||||
g_hid_status_report_index = 63;
|
||||
hidSetChangePending(0x1);
|
||||
#if HID_DFU_EN
|
||||
if (!g_in_fw_upgrade)
|
||||
#endif
|
||||
{
|
||||
unsafe {
|
||||
unsigned char * unsafe ptr = (unsigned char * unsafe)hidSendData;
|
||||
ptr[0] = 1;
|
||||
ptr[1] = 0x77;
|
||||
ptr[2] = 0x9F;
|
||||
ptr[3] = (unsigned char)(new_samfreq & 0xFF);
|
||||
ptr[4] = (unsigned char)((new_samfreq >> 8) & 0xFF);
|
||||
ptr[5] = (unsigned char)((new_samfreq >> 16) & 0xFF);
|
||||
ptr[6] = (unsigned char)((new_samfreq >> 24) & 0xFF);
|
||||
ptr[7] = (unsigned char)new_dsd_mode;
|
||||
for (int i = 8; i < HID_MAX_DATA_BYTES; i++)
|
||||
ptr[i] = 0x00;
|
||||
}
|
||||
hidSetChangePending(0x1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#if HID_DFU_EN
|
||||
case c_dfu_rx :> unsigned dfu_first_word:
|
||||
{
|
||||
// 接收来自tile[1] hid_button_task转发的固件升级START命令(16个word)
|
||||
unsigned dfu_words[16];
|
||||
dfu_words[0] = dfu_first_word;
|
||||
for (int i = 1; i < 16; i++)
|
||||
c_dfu_rx :> dfu_words[i];
|
||||
unsigned char cmd_buf[63];
|
||||
for (int i = 0; i < 63; i++)
|
||||
cmd_buf[i] = (dfu_words[i / 4] >> ((i % 4) * 8)) & 0xFF;
|
||||
if (cmd_buf[1] == FIRMWARE_UPGRADE_START)
|
||||
handle_firmware_upgrade_start(cmd_buf, 63);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case tmr when timerafter(time) :> void :
|
||||
{
|
||||
//hwtimer_change_trigger_time(timer, hwtimer_get_time(timer) + KEY_POLLING_INTERVAL);
|
||||
@@ -844,21 +984,111 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
unsigned mode_btn_change = 0;
|
||||
unsigned need_reboot = 0;
|
||||
|
||||
if (button_music_mode == 0) {
|
||||
if (push_button_music_mode_state_old == 1) {
|
||||
// --- Music + Game 按键:组合检测 + 去抖 ---
|
||||
// 两键同时按住3秒 → 出厂恢复;单键需持续 BTN_COMBO_DELAY_TICKS 后生效
|
||||
// (50ms 窗口内若另一键也按下则进入组合模式,单键动作取消)
|
||||
{
|
||||
int music_is_down = (button_music_mode == 0);
|
||||
int game_is_down = (button_game_mode == 0);
|
||||
int factory_combo_is_down = ( music_is_down && game_is_down);
|
||||
|
||||
// 更新各键连续按住计数(断开则清零,用于去抖和窗口判断)
|
||||
if (music_is_down && !factory_combo_is_down)
|
||||
{
|
||||
if (btn_music_hold_ticks < 0xFFFFu) btn_music_hold_ticks++;
|
||||
debug_printf("btn_music_hold_ticks=%d\n", btn_music_hold_ticks);
|
||||
}
|
||||
else
|
||||
{
|
||||
btn_music_hold_ticks = 0;
|
||||
}
|
||||
if (game_is_down && !factory_combo_is_down)
|
||||
{
|
||||
if (btn_game_hold_ticks < 0xFFFFu)
|
||||
{
|
||||
btn_game_hold_ticks++;
|
||||
}
|
||||
debug_printf("btn_game_hold_ticks=%d\n", btn_game_hold_ticks);
|
||||
}
|
||||
else
|
||||
{
|
||||
btn_game_hold_ticks = 0;
|
||||
}
|
||||
|
||||
// 场景1:两键同时按住(参照 fosi_ds1 else-if 结构)
|
||||
if (factory_combo_is_down) {
|
||||
btn_combo_active = 1; // 粘性锁定
|
||||
// fr_inhibit=1 时(出厂恢复重启后):不计时,必须松键后重新按下才触发
|
||||
if (factory_reset_blink_state == 0 && !fr_inhibit) {
|
||||
factory_reset_hold_count++;
|
||||
if (factory_reset_hold_count >= FACTORY_RESET_HOLD_TICKS) {
|
||||
factory_reset_hold_count = 0;
|
||||
factory_reset_blink_state = 1;
|
||||
factory_reset_blink_tick = 0;
|
||||
// 清除所有Flash设置并重启
|
||||
debug_printf("Factory reset: clearing flash "
|
||||
"and rebooting\n");
|
||||
unsafe {
|
||||
lfs_remove_file("game_mode");
|
||||
lfs_remove_file("mic_vol");
|
||||
lfs_remove_file("dac_vol");
|
||||
lfs_remove_file("footstep");
|
||||
lfs_remove_file("monitor_sw");
|
||||
lfs_remove_file("mic_mute");
|
||||
lfs_remove_file("hp_mute");
|
||||
}
|
||||
|
||||
led_on(&led_ctx, LED_MUSIC);
|
||||
led_on(&led_ctx, LED_ANC);
|
||||
led_on(&led_ctx, LED_FOOTSTEP_MODE);
|
||||
led_on(&led_ctx, LED_AI7_1);
|
||||
led_on(&led_ctx, LED_GAME_MODE);
|
||||
led_update_all(&led_ctx);
|
||||
debug_printf("Factory reset: 3s hold detected, starting blink\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
// 场景2:仅 Music 按住
|
||||
else if (music_is_down) {
|
||||
factory_reset_hold_count = 0;
|
||||
if (!btn_combo_active) {
|
||||
if (btn_music_hold_ticks == BTN_COMBO_DELAY_TICKS) {
|
||||
debug_printf("========= Music button pressed for %d ticks\n", BTN_COMBO_DELAY_TICKS);
|
||||
#if (F3_F4_FPS_UAC2 == 1)
|
||||
// FPS firmware: switching to music needs different USB config
|
||||
active_mode = 1;
|
||||
need_reboot = 1;
|
||||
SetRoleSwitchFlag(MODE_F1_MUSIC_UAC2);
|
||||
active_mode = 1;
|
||||
need_reboot = 1;
|
||||
SetRoleSwitchFlag(MODE_F1_MUSIC_UAC2);
|
||||
#else
|
||||
// Music-only firmware: toggle music LED locally
|
||||
active_mode = (active_mode == 1) ? 0 : 1;
|
||||
mode_btn_change = 1;
|
||||
active_mode = (active_mode == 1) ? 0 : 1;
|
||||
mode_btn_change = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
// 场景3:仅 Game 按住
|
||||
else if (game_is_down) {
|
||||
factory_reset_hold_count = 0;
|
||||
if (!btn_combo_active) {
|
||||
if (btn_game_hold_ticks == BTN_COMBO_DELAY_TICKS) {
|
||||
debug_printf("========= Game button pressed for %d ticks\n", BTN_COMBO_DELAY_TICKS);
|
||||
#if F1_MUSIC_UAC2 == 1
|
||||
active_mode = 2;
|
||||
need_reboot = 1;
|
||||
SetRoleSwitchFlag(MODE_F3_F4_FPS_UAC2);
|
||||
#else
|
||||
active_mode = (active_mode == 2) ? 0 : 2;
|
||||
mode_btn_change = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
// 场景4:两键全松开 → 解除组合锁定及抑制标志
|
||||
else {
|
||||
factory_reset_hold_count = 0;
|
||||
btn_combo_active = 0;
|
||||
fr_inhibit = 0; // 松键后允许下次同时按下重新触发出厂恢复
|
||||
}
|
||||
}
|
||||
push_button_music_mode_state_old = button_music_mode;
|
||||
|
||||
if (button_ai71_onoff == 0) {
|
||||
if (push_button_ai71_onoff_state_old == 1) {
|
||||
@@ -877,22 +1107,6 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
}
|
||||
push_button_ai71_onoff_state_old = button_ai71_onoff;
|
||||
|
||||
if (button_game_mode == 0) {
|
||||
if (push_button_game_mode_state_old == 1) {
|
||||
#if F1_MUSIC_UAC2 == 1
|
||||
// Music-only firmware: game needs FPS firmware
|
||||
active_mode = 2;
|
||||
need_reboot = 1;
|
||||
SetRoleSwitchFlag(MODE_F3_F4_FPS_UAC2);
|
||||
#else
|
||||
// FPS firmware: switch algorithm locally (toggle off or activate)
|
||||
active_mode = (active_mode == 2) ? 0 : 2;
|
||||
mode_btn_change = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
push_button_game_mode_state_old = button_game_mode;
|
||||
|
||||
// 处理HID SET_SOUND_EFFECT_MODE (0xA4) 请求,等同于按键效果
|
||||
if (!mode_btn_change && !need_reboot) {
|
||||
unsigned hid_req_mode;
|
||||
@@ -935,7 +1149,7 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
if (need_reboot) {
|
||||
// Reboot: F5 will re-detect OS and route to correct firmware
|
||||
debug_printf("Mode %d requires firmware switch, rebooting\n", active_mode);
|
||||
delay_milliseconds(20);
|
||||
delay_milliseconds(200);
|
||||
device_reboot();
|
||||
while (1);
|
||||
}
|
||||
@@ -964,6 +1178,69 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
#endif
|
||||
}
|
||||
|
||||
// 出厂恢复闪烁状态机:5个按键LED闪3次后清除Flash并重启
|
||||
if (factory_reset_blink_state > 0) {
|
||||
factory_reset_blink_tick++;
|
||||
if (factory_reset_blink_tick >= FACTORY_RESET_BLINK_TICKS) {
|
||||
factory_reset_blink_tick = 0;
|
||||
factory_reset_blink_state++;
|
||||
if (factory_reset_blink_state > 6) {
|
||||
#if 1
|
||||
// 3次闪烁完成:恢复原始LED显示
|
||||
factory_reset_blink_state = 0;
|
||||
led_off(&led_ctx, LED_MUSIC);
|
||||
led_off(&led_ctx, LED_ANC);
|
||||
led_off(&led_ctx, LED_FOOTSTEP_MODE);
|
||||
led_off(&led_ctx, LED_AI7_1);
|
||||
led_off(&led_ctx, LED_GAME_MODE);
|
||||
switch (active_mode) {
|
||||
case 1: led_on(&led_ctx, LED_MUSIC); break;
|
||||
case 2: led_on(&led_ctx, LED_GAME_MODE); break;
|
||||
case 3: led_on(&led_ctx, LED_AI7_1); break;
|
||||
default: break;
|
||||
}
|
||||
if (flag_footsteps_enhancement == 1) led_on(&led_ctx, LED_FOOTSTEP_MODE);
|
||||
else if (flag_footsteps_enhancement == 2) led_set_brightness(&led_ctx, LED_FOOTSTEP_MODE, 128);
|
||||
if (flag_aidenoise_onoff) led_on(&led_ctx, LED_ANC);
|
||||
led_update_all(&led_ctx);
|
||||
// 等待松键,防止重启后再次触发出厂恢复循环
|
||||
{
|
||||
unsigned mw, gw;
|
||||
do {
|
||||
delay_milliseconds(10);
|
||||
p_button_music_mode :> mw;
|
||||
p_button_game_mode :> gw;
|
||||
} while (mw == 0 || gw == 0);
|
||||
delay_milliseconds(100);
|
||||
}
|
||||
#endif
|
||||
// 出厂恢复默认AI7.1模式(mode=3),需要F3/F4固件
|
||||
SetRoleSwitchFlag(MODE_F3_F4_FPS_UAC2);
|
||||
delay_milliseconds(20);
|
||||
device_reboot();
|
||||
while (1);
|
||||
} else if (factory_reset_blink_state % 2 == 0) {
|
||||
// 偶数相:全灭
|
||||
led_off(&led_ctx, LED_MUSIC);
|
||||
led_off(&led_ctx, LED_ANC);
|
||||
led_off(&led_ctx, LED_FOOTSTEP_MODE);
|
||||
led_off(&led_ctx, LED_AI7_1);
|
||||
led_off(&led_ctx, LED_GAME_MODE);
|
||||
led_update_all(&led_ctx);
|
||||
delay_milliseconds(200);
|
||||
} else {
|
||||
// 奇数相:全亮
|
||||
led_on(&led_ctx, LED_MUSIC);
|
||||
led_on(&led_ctx, LED_ANC);
|
||||
led_on(&led_ctx, LED_FOOTSTEP_MODE);
|
||||
led_on(&led_ctx, LED_AI7_1);
|
||||
led_on(&led_ctx, LED_GAME_MODE);
|
||||
led_update_all(&led_ctx);
|
||||
delay_milliseconds(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_EX3D == 1
|
||||
mode_change = 0;
|
||||
if(button_footsteps_enhancement == 0)
|
||||
@@ -1052,12 +1329,14 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
if(flag_aidenoise_onoff)
|
||||
{
|
||||
led_on(&led_ctx, LED_ANC);
|
||||
dnr_set_mode(1);
|
||||
dnr_set_strength_level((unsigned char)dnr_strength_saved);
|
||||
SET_SHARED_GLOBAL(g_dnr_strength, dnr_strength_saved);
|
||||
}
|
||||
else
|
||||
{
|
||||
led_off(&led_ctx, LED_ANC);
|
||||
dnr_set_mode(0);
|
||||
dnr_set_strength_level(0);
|
||||
SET_SHARED_GLOBAL(g_dnr_strength, 0);
|
||||
}
|
||||
|
||||
//led_update_all(&led_ctx);
|
||||
@@ -1086,6 +1365,11 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
}
|
||||
}
|
||||
push_button_mic_mute_state_old = button_mic_mute;
|
||||
if(mode_change)
|
||||
{
|
||||
save_value(mic_mute_path, (unsigned char)flag_mic_mute);
|
||||
debug_printf("mic_mute changed: %d, saved to flash\n", flag_mic_mute);
|
||||
}
|
||||
if(mode_change)
|
||||
if(flag_mic_mute)
|
||||
{
|
||||
@@ -1109,34 +1393,6 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
led_on(&led_ctx, led_l_physical_map[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mic_gain = 0;
|
||||
|
||||
// if((mic_encoder1 & 0b0100) != 0) mic_gain |= 0b0010;
|
||||
// if((mic_encoder2 & 0b0100) != 0) mic_gain |= 0b1000;
|
||||
|
||||
//mic_gain >>= 4;
|
||||
|
||||
// if((mic_gain & 0b0100) == 0)
|
||||
// {
|
||||
// if(mute_down)
|
||||
// {
|
||||
// SET_SHARED_GLOBAL(g_reduct_dep, ++mic_mute % 4);
|
||||
// }
|
||||
// // if ((mic_mute % 4) == 0)
|
||||
// // set_gpio(P_GPIO_LED, 0);
|
||||
// // else
|
||||
// // set_gpio(P_GPIO_LED, 1);
|
||||
|
||||
// mute_down = 0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// mute_down = 1;
|
||||
// }
|
||||
|
||||
uint8_t rotating = (mic_encoder2 & 0b0100) == 0; // 4E2
|
||||
uint8_t encode_input1 = ((mic_encoder1 & 0b0100) != 0); // 4F2
|
||||
|
||||
@@ -1347,6 +1603,11 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
}
|
||||
}
|
||||
push_button_hp_mute_state_old = button_hp_mute;
|
||||
if(mode_change)
|
||||
{
|
||||
save_value(hp_mute_path, (unsigned char)flag_hp_mute);
|
||||
debug_printf("hp_mute changed: %d, saved to flash\n", flag_hp_mute);
|
||||
}
|
||||
if(mode_change)
|
||||
if(flag_hp_mute)
|
||||
{
|
||||
@@ -1377,74 +1638,6 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
led_update_all(&led_ctx);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
curr_ctrl_keys = (port_in(p_ctrl_keys)) & KEY_BITS;
|
||||
|
||||
|
||||
if (curr_ctrl_keys != last_ctrl_keys) {
|
||||
debounce_cnt++;
|
||||
if (debounce_cnt >= 2) {
|
||||
debounce_cnt = 0;
|
||||
keys_changed = curr_ctrl_keys ^ last_ctrl_keys;
|
||||
tmp = 0;
|
||||
switch (keys_changed) {
|
||||
case KEY_MIC_VOL_DN:
|
||||
case KEY_MIC_VOL_UP:
|
||||
|
||||
if ((isMute == 0) && ((curr_ctrl_keys & KEY_MIC_VOL_DN) == 0)) {
|
||||
tmp = KEY_MIC_VOL_DN;
|
||||
debug_printf("KEY_MIC_VOL_DN pressed\n");
|
||||
} else {
|
||||
if ((isMute == 0) && ((curr_ctrl_keys & KEY_MIC_VOL_UP) == 0)) {
|
||||
tmp = KEY_MIC_VOL_UP;
|
||||
debug_printf("KEY_MIC_VOL_UP pressed\n");
|
||||
}
|
||||
}
|
||||
if (tmp) {
|
||||
g_mic_vol_cmd_pending = (unsigned)tmp;
|
||||
}
|
||||
break;
|
||||
case KEY_MUTE:
|
||||
|
||||
if ((curr_ctrl_keys & KEY_MUTE) == 0) {
|
||||
// mute switch off (unmuted)
|
||||
isMute = 0;
|
||||
SET_SHARED_GLOBAL(g_mute_on_off_t0, MUTE_OFF); // 更新tile0静音状态
|
||||
chan_out_byte(cc_mic_level, (uint8_t) UNMUTED_MIC);
|
||||
debug_printf("MUTE: unmuted\n");
|
||||
} else {
|
||||
// mute switch on (muted)
|
||||
isMute = 1;
|
||||
SET_SHARED_GLOBAL(g_mute_on_off_t0, MUTE_ON); // 更新tile0静音状态
|
||||
chan_out_byte(cc_mic_level, (uint8_t) MUTED_MIC);
|
||||
debug_printf("MUTE: muted\n");
|
||||
}
|
||||
break;
|
||||
#if (HID_CONTROLS == 1)
|
||||
case KEY_PLAY_VOL_DN:
|
||||
|
||||
if ((curr_ctrl_keys & KEY_PLAY_VOL_DN) == 0) {
|
||||
debug_printf("KEY_PLAY_VOL_DN pressed\n");
|
||||
update_button(HID_CONTROL_VOLDN); // 更新HID报告
|
||||
}
|
||||
break;
|
||||
case KEY_PLAY_VOL_UP:
|
||||
|
||||
if ((curr_ctrl_keys & KEY_PLAY_VOL_UP) == 0) {
|
||||
update_button(HID_CONTROL_VOLUP); // 更新HID报告
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
last_ctrl_keys = curr_ctrl_keys; // 更新上次按键状态
|
||||
}
|
||||
} else {
|
||||
debounce_cnt = 0; // 状态未变化,重置防抖计数器
|
||||
}
|
||||
#endif
|
||||
|
||||
GET_SHARED_GLOBAL(uac_vol, g_uac_vol);
|
||||
if (uac_vol != last_uac_vol) {
|
||||
unsigned conv_vol = (0xffffffff - uac_vol + 1) >> 8;
|
||||
@@ -1508,17 +1701,61 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
}
|
||||
}
|
||||
|
||||
// 处理HID SET_MONITOR_SWITCH (0x87) 请求:设置耳返开关
|
||||
if (g_request_monitor_switch_set) {
|
||||
g_request_monitor_switch_set = 0;
|
||||
unsigned new_mon = g_monitor_switch;
|
||||
// 根据当前mic状态和新的耳返开关值更新reg 0x30
|
||||
if (new_mon && !flag_mic_mute && codec_adc_pga_gain_reg_value >= 2) {
|
||||
unsafe { NAU88C22_REGWRITE(0x0030, 0xff00, (client interface i2c_master_if)i_i2c_client); }
|
||||
} else {
|
||||
unsafe { NAU88C22_REGWRITE(0x0030, 0x0000, (client interface i2c_master_if)i_i2c_client); }
|
||||
}
|
||||
save_value(monitor_sw_path, (unsigned char)new_mon);
|
||||
debug_printf("HID SET_MONITOR_SWITCH: %d\n", new_mon);
|
||||
}
|
||||
|
||||
// 处理HID SET_AI_NOISE_STRENGTH (0x85) 请求
|
||||
{
|
||||
unsigned dnr_req;
|
||||
GET_SHARED_GLOBAL(dnr_req, g_request_dnr_strength_set);
|
||||
if (dnr_req) {
|
||||
SET_SHARED_GLOBAL(g_request_dnr_strength_set, 0);
|
||||
unsigned new_strength;
|
||||
GET_SHARED_GLOBAL(new_strength, g_dnr_strength);
|
||||
#if DNR_ENABLE == 1
|
||||
dnr_set_strength_level((unsigned char)new_strength);
|
||||
#endif
|
||||
if (new_strength == 0) {
|
||||
flag_aidenoise_onoff = 0;
|
||||
led_off(&led_ctx, LED_ANC);
|
||||
} else {
|
||||
flag_aidenoise_onoff = 1;
|
||||
dnr_strength_saved = new_strength;
|
||||
led_on(&led_ctx, LED_ANC);
|
||||
}
|
||||
led_update_all(&led_ctx);
|
||||
debug_printf("HID SET_AI_NOISE_STRENGTH: strength=%d\n", new_strength);
|
||||
}
|
||||
}
|
||||
|
||||
#if HID_CONTROLS == 1
|
||||
// HID监听音量变化主动上报(编码器旋转或HID命令导致的音量变化)
|
||||
{
|
||||
unsigned current_volume_level = g_volume_level;
|
||||
#if HID_DFU_EN
|
||||
if (!g_in_fw_upgrade)
|
||||
#endif
|
||||
if (g_last_volume_level != current_volume_level && g_last_volume_level != 0xFF) {
|
||||
g_hid_status_report_data[0] = 0x77; // 同步头1
|
||||
g_hid_status_report_data[1] = 0x94; // GET_VOLUME命令码
|
||||
g_hid_status_report_data[2] = (unsigned char)current_volume_level;
|
||||
for (int i = 3; i < 63; i++)
|
||||
g_hid_status_report_data[i] = 0x00;
|
||||
g_hid_status_report_index = 63;
|
||||
unsafe {
|
||||
unsigned char * unsafe ptr = (unsigned char * unsafe)hidSendData;
|
||||
ptr[0] = 1;
|
||||
ptr[1] = 0x77;
|
||||
ptr[2] = 0x94;
|
||||
ptr[3] = (unsigned char)current_volume_level;
|
||||
for (int i = 4; i < HID_MAX_DATA_BYTES; i++)
|
||||
ptr[i] = 0x00;
|
||||
}
|
||||
hidSetChangePending(0x1);
|
||||
debug_printf("Volume changed: %d -> %d, HID report sent\n",
|
||||
g_last_volume_level, current_volume_level);
|
||||
@@ -1529,19 +1766,51 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
// HID麦克风增益变化主动上报
|
||||
{
|
||||
unsigned current_mic_level = g_mic_volume_level;
|
||||
#if HID_DFU_EN
|
||||
if (!g_in_fw_upgrade)
|
||||
#endif
|
||||
if (g_last_mic_volume_level != current_mic_level && g_last_mic_volume_level != 0xFF) {
|
||||
g_hid_status_report_data[0] = 0x77; // 同步头1
|
||||
g_hid_status_report_data[1] = 0x83; // GET_MIC_VOLUME命令码
|
||||
g_hid_status_report_data[2] = (unsigned char)current_mic_level;
|
||||
for (int i = 3; i < 63; i++)
|
||||
g_hid_status_report_data[i] = 0x00;
|
||||
g_hid_status_report_index = 63;
|
||||
unsafe {
|
||||
unsigned char * unsafe ptr = (unsigned char * unsafe)hidSendData;
|
||||
ptr[0] = 1;
|
||||
ptr[1] = 0x77;
|
||||
ptr[2] = 0x83;
|
||||
ptr[3] = (unsigned char)current_mic_level;
|
||||
for (int i = 4; i < HID_MAX_DATA_BYTES; i++)
|
||||
ptr[i] = 0x00;
|
||||
}
|
||||
hidSetChangePending(0x1);
|
||||
debug_printf("Mic volume changed: %d -> %d, HID report sent\n",
|
||||
g_last_mic_volume_level, current_mic_level);
|
||||
}
|
||||
g_last_mic_volume_level = current_mic_level;
|
||||
}
|
||||
|
||||
// HID AI降噪强度变化主动上报(含首次开机上报:g_last_dnr_strength初始为0xFF)
|
||||
#if DNR_ENABLE == 1
|
||||
{
|
||||
unsigned current_dnr_strength;
|
||||
GET_SHARED_GLOBAL(current_dnr_strength, g_dnr_strength);
|
||||
#if HID_DFU_EN
|
||||
if (!g_in_fw_upgrade)
|
||||
#endif
|
||||
if (g_last_dnr_strength != current_dnr_strength) {
|
||||
unsafe {
|
||||
unsigned char * unsafe ptr = (unsigned char * unsafe)hidSendData;
|
||||
ptr[0] = 1;
|
||||
ptr[1] = 0x77;
|
||||
ptr[2] = 0x86;
|
||||
ptr[3] = (unsigned char)current_dnr_strength;
|
||||
for (int i = 4; i < HID_MAX_DATA_BYTES; i++)
|
||||
ptr[i] = 0x00;
|
||||
}
|
||||
hidSetChangePending(0x1);
|
||||
debug_printf("DNR strength changed: %d -> %d, HID report sent\n",
|
||||
g_last_dnr_strength, current_dnr_strength);
|
||||
}
|
||||
g_last_dnr_strength = current_dnr_strength;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if EQ_EN
|
||||
@@ -1600,7 +1869,11 @@ void button_task(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol,
|
||||
}
|
||||
}
|
||||
|
||||
void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx)
|
||||
void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx
|
||||
#if HID_DFU_EN
|
||||
, streaming chanend c_dfu_rx
|
||||
#endif
|
||||
)
|
||||
{
|
||||
i2c_master_if i2c[1];
|
||||
board_setup();
|
||||
@@ -1608,7 +1881,11 @@ void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vo
|
||||
i2c_master(i2c, 1, p_scl, p_sda, 300);
|
||||
{
|
||||
unsafe {i_i2c_client = i2c[0];}
|
||||
button_task(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw_rx);
|
||||
button_task(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw_rx
|
||||
#if HID_DFU_EN
|
||||
, c_dfu_rx
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#define DEBUG_PRINT_ENABLE 0
|
||||
#include <xs1.h>
|
||||
#include <flash.h>
|
||||
#include <flashlib.h>
|
||||
#include <string.h>
|
||||
#include <xclib.h>
|
||||
#include <stdio.h>
|
||||
#include "debug_print.h"
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
#if HID_DFU_EN
|
||||
|
||||
#ifndef DFU_FLASH_MAX_UPGRADE_SIZE
|
||||
#define DFU_FLASH_MAX_UPGRADE_SIZE (1600 * 1024)
|
||||
#endif
|
||||
|
||||
#define DFU_FLASH_ERROR()
|
||||
|
||||
static int dfu_flash_device_open = 0;
|
||||
static fl_BootImageInfo dfu_factory_image;
|
||||
static fl_BootImageInfo dfu_upgrade_image;
|
||||
|
||||
static int dfu_upgrade_image_valid = 0;
|
||||
static int dfu_current_flash_subpage_index = 0;
|
||||
static unsigned char dfu_current_flash_page_data[256];
|
||||
|
||||
int dfu_flash_cmd_enable_ports() __attribute__ ((weak));
|
||||
int dfu_flash_cmd_enable_ports() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfu_flash_cmd_disable_ports() __attribute__ ((weak));
|
||||
int dfu_flash_cmd_disable_ports() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DFUCustomFlashEnable() __attribute__ ((weak));
|
||||
void DFUCustomFlashEnable()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void DFUCustomFlashDisable() __attribute__ ((weak));
|
||||
void DFUCustomFlashDisable()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Returns non-zero for error */
|
||||
int dfu_flash_cmd_init(void)
|
||||
{
|
||||
debug_printf("dfu_flash_cmd_init: dfu_flash_cmd_init\n");
|
||||
fl_BootImageInfo image;
|
||||
|
||||
if (!dfu_flash_device_open)
|
||||
{
|
||||
if (dfu_flash_cmd_enable_ports())
|
||||
dfu_flash_device_open = 1;
|
||||
debug_printf("dfu_flash_cmd_init: dfu_flash_device_open = 1\n");
|
||||
}
|
||||
|
||||
if (!dfu_flash_device_open)
|
||||
{
|
||||
debug_printf("dfu_flash_cmd_init: dfu_flash_device_open = 0\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if (!XUA_QUAD_SPI_FLASH)
|
||||
// Disable flash protection
|
||||
fl_setProtection(0);
|
||||
#endif
|
||||
|
||||
if (fl_getFactoryImage(&image) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
dfu_factory_image = image;
|
||||
|
||||
if (fl_getNextBootImage(&image) == 0)
|
||||
{
|
||||
dfu_upgrade_image_valid = 1;
|
||||
dfu_upgrade_image = image;
|
||||
debug_printf("dfu_flash_cmd_init: dfu_upgrade_image_valid = 1\n");
|
||||
}
|
||||
|
||||
debug_printf("dfu_flash_cmd_init: return 0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfu_flash_cmd_deinit(void)
|
||||
{
|
||||
if (!dfu_flash_device_open)
|
||||
return 0;
|
||||
|
||||
dfu_flash_cmd_disable_ports();
|
||||
dfu_flash_device_open = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfu_flash_cmd_read_page(unsigned char *data)
|
||||
{
|
||||
if (!dfu_upgrade_image_valid)
|
||||
{
|
||||
*(unsigned int *)data = 1;
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (*(unsigned int *)data == 0)
|
||||
{
|
||||
fl_startImageRead(&dfu_upgrade_image);
|
||||
}
|
||||
|
||||
dfu_current_flash_subpage_index = 0;
|
||||
|
||||
if (fl_readImagePage(dfu_current_flash_page_data) == 0)
|
||||
{
|
||||
*(unsigned int *)data = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(unsigned int *)data = 1;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
int dfu_flash_cmd_read_page_data(unsigned char *data)
|
||||
{
|
||||
unsigned char *page_data_ptr = &dfu_current_flash_page_data[dfu_current_flash_subpage_index * 64];
|
||||
memcpy(data, page_data_ptr, 64);
|
||||
|
||||
dfu_current_flash_subpage_index++;
|
||||
|
||||
return 64;
|
||||
}
|
||||
|
||||
static int begin_write()
|
||||
{
|
||||
int result;
|
||||
// TODO this will take a long time. To minimise the amount of time spent
|
||||
// paused on this operation it would be preferable to move to this to a
|
||||
// seperate command, e.g. start_write.
|
||||
do
|
||||
{
|
||||
result = fl_startImageAdd(&dfu_factory_image, DFU_FLASH_MAX_UPGRADE_SIZE, 0);
|
||||
} while (result > 0);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
DFU_FLASH_ERROR();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int pages_written = 0;
|
||||
|
||||
int dfu_flash_cmd_write_page(unsigned char *data)
|
||||
{
|
||||
/* 改动原因:协议仅约定第一个字节为 flag(0=第一页,1=后续页,2=结束);
|
||||
* 若用 *(unsigned int *)data 读取 4 字节,而调用处只设置 data[0]=0 且未清零 data[1..3],
|
||||
* 则 flag 可能非 0,导致不进入 case 0,begin_write() 被跳过。改为仅用首字节。 */
|
||||
unsigned int flag = (unsigned int)data[0];
|
||||
if (flag == 0)
|
||||
debug_printf("dfu_flash_cmd_write_page: flag = %d\n", flag);
|
||||
|
||||
if (dfu_upgrade_image_valid)
|
||||
{
|
||||
debug_printf("dfu_flash_cmd_write_page: dfu_upgrade_image_valid = 1\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (flag)
|
||||
{
|
||||
case 0:
|
||||
// First page.
|
||||
debug_printf("dfu_flash_cmd_write_page: begin_write\n");
|
||||
int result = begin_write();
|
||||
if (result < 0)
|
||||
return result;
|
||||
pages_written = 0;
|
||||
// fallthrough
|
||||
case 1:
|
||||
// Do nothing.
|
||||
break;
|
||||
case 2:
|
||||
// Termination.
|
||||
if (fl_endWriteImage() != 0)
|
||||
DFU_FLASH_ERROR();
|
||||
|
||||
// Sanity check
|
||||
fl_BootImageInfo image = dfu_factory_image;
|
||||
if (fl_getNextBootImage(&image) != 0)
|
||||
DFU_FLASH_ERROR();
|
||||
break;
|
||||
}
|
||||
dfu_current_flash_subpage_index = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfu_flash_cmd_write_page_data(unsigned char *data)
|
||||
{
|
||||
unsigned char *page_data_ptr = &dfu_current_flash_page_data[dfu_current_flash_subpage_index * 64];
|
||||
|
||||
if (dfu_upgrade_image_valid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dfu_current_flash_subpage_index >= 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(page_data_ptr, data, 64);
|
||||
|
||||
dfu_current_flash_subpage_index++;
|
||||
|
||||
if (dfu_current_flash_subpage_index == 4)
|
||||
{
|
||||
if (fl_writeImagePage(dfu_current_flash_page_data) != 0)
|
||||
DFU_FLASH_ERROR();
|
||||
pages_written++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dfu_flash_cmd_erase_all(void)
|
||||
{
|
||||
fl_BootImageInfo tmp_image = dfu_upgrade_image;
|
||||
|
||||
if (dfu_upgrade_image_valid)
|
||||
{
|
||||
if (fl_deleteImage(&dfu_upgrade_image) != 0)
|
||||
{
|
||||
DFU_FLASH_ERROR();
|
||||
}
|
||||
|
||||
// Keep deleting all upgrade images
|
||||
// TODO Perhaps using replace would be nicer...
|
||||
while(1)
|
||||
{
|
||||
if (fl_getNextBootImage(&tmp_image) == 0)
|
||||
{
|
||||
if (fl_deleteImage(&tmp_image) != 0)
|
||||
{
|
||||
DFU_FLASH_ERROR();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dfu_upgrade_image_valid = 0;
|
||||
}
|
||||
/* 改动原因:强制升级流程中,erase 后必须允许后续第一页写执行 begin_write();
|
||||
* 若仅在上面 if 块内清零,某些路径(如删除失败或 while 未正确退出)可能导致
|
||||
* dfu_upgrade_image_valid 仍为 1,write_page(flag=0) 会直接 return 0 而不调用
|
||||
* begin_write(),导致 begin_write 未执行。此处无条件清零,保证 erase 后下一
|
||||
* 次 write_page(0) 必定执行 begin_write。 */
|
||||
dfu_upgrade_image_valid = 0;
|
||||
debug_printf("dfu_flash_cmd_erase_all: set dfu_upgrade_image_valid = 0\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2011-2021 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _dfu_flash_interface_h_
|
||||
#define _dfu_flash_interface_h_
|
||||
|
||||
int dfu_flash_cmd_init(void);
|
||||
/**
|
||||
* Prepare to write a page of a new upgrade image.
|
||||
* The first word of data should be set to 0 if it is the first page,
|
||||
* 1 for all other pages and 2 to terminate the write (no further data is sent).
|
||||
*/
|
||||
int dfu_flash_cmd_write_page(unsigned char []);
|
||||
/**
|
||||
* Provide upgrade image data. flash_cmd_write_page() must be called previously.
|
||||
* Once a page of data has been provided it is written to the device.
|
||||
*/
|
||||
int dfu_flash_cmd_write_page_data(unsigned char []);
|
||||
/**
|
||||
* Read a page of data from the upgrade image.
|
||||
* If the first word of data is 0 the page is read from the start of the
|
||||
* upgrade image, otherwise the next page in the image will be read.
|
||||
* On return the first word of data is written with 1 if there is nothing to
|
||||
* read and 0 otherwise.
|
||||
*/
|
||||
int dfu_flash_cmd_read_page(unsigned char []);
|
||||
/**
|
||||
* Get data previously read by flash_cmd_read_page().
|
||||
*/
|
||||
int dfu_flash_cmd_read_page_data(unsigned char []);
|
||||
int dfu_flash_cmd_erase_all(void);
|
||||
int dfu_flash_cmd_reboot(void);
|
||||
int dfu_flash_cmd_init(void);
|
||||
int dfu_flash_cmd_deinit(void);
|
||||
#endif /*_dfu_flash_interface_h_*/
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright 2012-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua.h"
|
||||
#if (XUA_DFU_EN == 1 || UAC1 == 1)
|
||||
#include "uac_hwresources.h"
|
||||
#include <xs1.h>
|
||||
#include <xclib.h>
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
#include <quadflashlib.h>
|
||||
#else
|
||||
#include <flashlib.h>
|
||||
#endif
|
||||
#include <print.h>
|
||||
|
||||
#define settw(a,b) {__asm__ __volatile__("settw res[%0], %1": : "r" (a) , "r" (b));}
|
||||
#define setc(a,b) {__asm__ __volatile__("setc res[%0], %1": : "r" (a) , "r" (b));}
|
||||
#define setclk(a,b) {__asm__ __volatile__("setclk res[%0], %1": : "r" (a) , "r" (b));}
|
||||
#define portin(a,b) {__asm__ __volatile__("in %0, res[%1]": "=r" (b) : "r" (a));}
|
||||
#define portout(a,b) {__asm__ __volatile__("out res[%0], %1": : "r" (a) , "r" (b));}
|
||||
|
||||
#ifdef DFU_FLASH_DEVICE
|
||||
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
/* Using specified flash device rather than all supported in tools */
|
||||
fl_QuadDeviceSpec dfu_flash_devices[] = {DFU_FLASH_DEVICE};
|
||||
#else
|
||||
/* Using specified flash device rather than all supported in tools */
|
||||
fl_DeviceSpec dfu_flash_devices[] = {DFU_FLASH_DEVICE};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
/*
|
||||
typedef struct {
|
||||
out port qspiCS;
|
||||
out port qspiSCLK;
|
||||
out buffered port:32 qspiSIO;
|
||||
clock qspiClkblk;
|
||||
} fl_QSPIPorts;
|
||||
*/
|
||||
fl_QSPIPorts dfu_p_qflash =
|
||||
{
|
||||
XS1_PORT_1B,
|
||||
XS1_PORT_1C,
|
||||
XS1_PORT_4B,
|
||||
CLKBLK_FLASHLIB
|
||||
};
|
||||
#else
|
||||
fl_PortHolderStruct p_flash =
|
||||
{
|
||||
XS1_PORT_1A,
|
||||
XS1_PORT_1B,
|
||||
XS1_PORT_1C,
|
||||
XS1_PORT_1D,
|
||||
CLKBLK_FLASHLIB
|
||||
};
|
||||
#endif
|
||||
|
||||
/* return 1 for opened ports successfully */
|
||||
int dfu_flash_cmd_enable_ports()
|
||||
{
|
||||
int result = 0;
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
/* Ports not shared */
|
||||
#else
|
||||
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiSS, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiClkblk, XS1_SETC_INUSE_OFF);
|
||||
|
||||
setc(p_flash.spiMISO, XS1_SETC_INUSE_ON);
|
||||
setc(p_flash.spiCLK, XS1_SETC_INUSE_ON);
|
||||
setc(p_flash.spiMOSI, XS1_SETC_INUSE_ON);
|
||||
setc(p_flash.spiSS, XS1_SETC_INUSE_ON);
|
||||
setc(p_flash.spiClkblk, XS1_SETC_INUSE_ON);
|
||||
setc(p_flash.spiClkblk, XS1_SETC_INUSE_ON);
|
||||
|
||||
setclk(p_flash.spiMISO, XS1_CLKBLK_REF);
|
||||
setclk(p_flash.spiCLK, XS1_CLKBLK_REF);
|
||||
setclk(p_flash.spiMOSI, XS1_CLKBLK_REF);
|
||||
setclk(p_flash.spiSS, XS1_CLKBLK_REF);
|
||||
|
||||
setc(p_flash.spiMISO, XS1_SETC_BUF_BUFFERS);
|
||||
setc(p_flash.spiMOSI, XS1_SETC_BUF_BUFFERS);
|
||||
|
||||
settw(p_flash.spiMISO, 8);
|
||||
settw(p_flash.spiMOSI, 8);
|
||||
#endif
|
||||
|
||||
#ifdef DFU_FLASH_DEVICE
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
result = fl_connectToDevice(&dfu_p_qflash, dfu_flash_devices, sizeof(dfu_flash_devices) / sizeof(fl_QuadDeviceSpec));
|
||||
#else
|
||||
result = fl_connectToDevice(&dfu_p_flash, dfu_flash_devices, sizeof(dfu_flash_devices) / sizeof(fl_DeviceSpec));
|
||||
#endif
|
||||
#else
|
||||
/* Use default flash list */
|
||||
#if (XUA_QUAD_SPI_FLASH)
|
||||
result = fl_connect(&dfu_p_qflash);
|
||||
#else
|
||||
result = fl_connect(&dfu_p_flash);
|
||||
#endif
|
||||
#endif
|
||||
if (!result)
|
||||
{
|
||||
/* All okay.. */
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int dfu_flash_cmd_disable_ports()
|
||||
{
|
||||
fl_disconnect();
|
||||
|
||||
#if (!XUA_QUAD_SPI_FLASH)
|
||||
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
|
||||
setc(p_flash.spiSS, XS1_SETC_INUSE_OFF);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,436 @@
|
||||
// Copyright 2026 Shanling.
|
||||
// HID固件升级实现文件 (adapted for app_usb_aud_phaten_golden_6ch)
|
||||
|
||||
#define DEBUG_PRINT_ENABLE 0
|
||||
#include "dfu_upgrade.h"
|
||||
#include "user_func.h"
|
||||
#include "dfu_flash_interface.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "debug_print.h"
|
||||
|
||||
#if HID_DFU_EN
|
||||
// 外部函数声明
|
||||
extern void hidSetChangePending(unsigned int id);
|
||||
extern unsigned char check_sum(unsigned char *pbuf, unsigned len);
|
||||
extern void device_reboot(void);
|
||||
extern unsigned hidSendData[];
|
||||
|
||||
// 固件升级通知MCU的标志(phaten无UART MCU,保留为静态变量供内部使用)
|
||||
static unsigned g_firmware_upgrade_mcu_notify = 0;
|
||||
unsigned g_in_fw_upgrade = 0; // 升级进行中标志,供其他模块检查以阻止非升级HID上报
|
||||
|
||||
// 升级状态(静态全局变量)
|
||||
static upgrade_status_t g_upgrade_status;
|
||||
|
||||
// 全局标志:第一页写命令是否已执行
|
||||
static uint8_t g_first_page_write_executed = 0;
|
||||
// 全局标志:是否已执行dfu_flash_cmd_erase_all
|
||||
static uint8_t g_flash_erased = 0;
|
||||
|
||||
// 初始化固件升级模块
|
||||
void firmware_upgrade_init(void)
|
||||
{
|
||||
memset(&g_upgrade_status, 0, sizeof(upgrade_status_t));
|
||||
g_upgrade_status.state = UPGRADE_IDLE;
|
||||
g_upgrade_status.expected_block_num = 0;
|
||||
debug_printf("Firmware upgrade module initialized\n");
|
||||
}
|
||||
|
||||
// 获取当前升级状态
|
||||
upgrade_state_t firmware_upgrade_get_state(void)
|
||||
{
|
||||
return g_upgrade_status.state;
|
||||
}
|
||||
|
||||
// 重置升级状态
|
||||
void firmware_upgrade_reset(void)
|
||||
{
|
||||
memset(&g_upgrade_status, 0, sizeof(upgrade_status_t));
|
||||
g_upgrade_status.state = UPGRADE_IDLE;
|
||||
g_upgrade_status.expected_block_num = 0;
|
||||
g_upgrade_status.first_page_written = 0;
|
||||
g_first_page_write_executed = 0;
|
||||
g_flash_erased = 0;
|
||||
}
|
||||
|
||||
// 发送固件升级响应(主动上报)
|
||||
// 填充hidSendData,通过UserHIDGetData上报给host
|
||||
void send_firmware_upgrade_response(uint8_t cmd, uint8_t *response_data, uint16_t data_len)
|
||||
{
|
||||
unsigned char *ptr = (unsigned char *)hidSendData;
|
||||
ptr[0] = 1;
|
||||
ptr[1] = 0x77; // 同步头
|
||||
ptr[2] = cmd; // 命令码
|
||||
|
||||
if (response_data != NULL && data_len > 0) {
|
||||
uint16_t copy_len = (data_len < 61) ? data_len : 61;
|
||||
memcpy(&ptr[3], response_data, copy_len);
|
||||
}
|
||||
|
||||
for (int i = 3 + (int)data_len; i < 64; i++) {
|
||||
ptr[i] = 0x00;
|
||||
}
|
||||
|
||||
hidSetChangePending(0x1);
|
||||
}
|
||||
|
||||
// 处理START命令
|
||||
unsigned char handle_firmware_upgrade_start(uint8_t data[], uint16_t len)
|
||||
{
|
||||
uint8_t response[64] = {0};
|
||||
|
||||
if (g_upgrade_status.state != UPGRADE_IDLE) {
|
||||
debug_printf("Firmware upgrade error: not in IDLE state (current: %d)\n", g_upgrade_status.state);
|
||||
response[0] = STATUS_FAIL;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
uint32_t firmware_size = data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24);
|
||||
|
||||
debug_printf("g_first_page_write_executed: %d\n", g_first_page_write_executed);
|
||||
|
||||
if (firmware_size == 0 || firmware_size > FLASH_MAX_UPGRADE_SIZE) {
|
||||
debug_printf("Firmware upgrade error: invalid size %lu\n", firmware_size);
|
||||
response[0] = STATUS_SIZE_INVALID;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
|
||||
return STATUS_SIZE_INVALID;
|
||||
}
|
||||
|
||||
uint32_t aligned_size = ((firmware_size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE) * FLASH_PAGE_SIZE;
|
||||
|
||||
if (dfu_flash_cmd_init() != 0) {
|
||||
debug_printf("Firmware upgrade error: flash init failed\n");
|
||||
response[0] = STATUS_FAIL;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
|
||||
debug_printf("Force upgrade: erasing existing upgrade image\n");
|
||||
dfu_flash_cmd_erase_all();
|
||||
g_flash_erased = 1;
|
||||
} else {
|
||||
debug_printf("Force upgrade: erase skipped (already erased or begin_write started)\n");
|
||||
}
|
||||
|
||||
g_upgrade_status.state = UPGRADE_PREPARING;
|
||||
g_upgrade_status.firmware_size = aligned_size;
|
||||
g_upgrade_status.total_blocks = (aligned_size + MAX_DATA_BLOCK_SIZE - 1) / MAX_DATA_BLOCK_SIZE;
|
||||
g_upgrade_status.received_blocks = 0;
|
||||
g_upgrade_status.expected_block_num = 0;
|
||||
g_upgrade_status.error_code = 0;
|
||||
|
||||
memset(g_upgrade_status.page_buf.buffer, 0, FLASH_PAGE_SIZE);
|
||||
g_upgrade_status.page_buf.offset = 0;
|
||||
g_upgrade_status.page_buf.total_pages = aligned_size / FLASH_PAGE_SIZE;
|
||||
g_upgrade_status.page_buf.written_pages = 0;
|
||||
|
||||
if (g_first_page_write_executed == 0) {
|
||||
debug_printf("Firmware upgrade: executing first page write command (flag=0) in START...\n");
|
||||
unsigned char cmd_data[16];
|
||||
memset(cmd_data, 0, sizeof(cmd_data));
|
||||
cmd_data[0] = 0;
|
||||
if (dfu_flash_cmd_write_page(cmd_data) != 0) {
|
||||
debug_printf("Firmware upgrade error: first page write command failed (begin_write error)\n");
|
||||
dfu_flash_cmd_deinit();
|
||||
g_upgrade_status.state = UPGRADE_IDLE;
|
||||
response[0] = STATUS_FAIL;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
g_first_page_write_executed = 1;
|
||||
debug_printf("Firmware upgrade: first page write command completed\n");
|
||||
} else {
|
||||
debug_printf("Firmware upgrade: first page write command already executed in ERASE, skipping %d\n", g_first_page_write_executed);
|
||||
}
|
||||
g_upgrade_status.first_page_written = 1;
|
||||
|
||||
response[0] = STATUS_SUCCESS;
|
||||
response[1] = (aligned_size >> 0) & 0xFF;
|
||||
response[2] = (aligned_size >> 8) & 0xFF;
|
||||
response[3] = (aligned_size >> 16) & 0xFF;
|
||||
response[4] = (aligned_size >> 24) & 0xFF;
|
||||
response[5] = (g_upgrade_status.total_blocks >> 0) & 0xFF;
|
||||
response[6] = (g_upgrade_status.total_blocks >> 8) & 0xFF;
|
||||
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 7);
|
||||
g_firmware_upgrade_mcu_notify = 1;
|
||||
g_in_fw_upgrade = 1;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// 处理DATA命令
|
||||
unsigned char handle_firmware_upgrade_data(uint8_t data[], uint16_t len)
|
||||
{
|
||||
uint8_t response[64] = {0};
|
||||
|
||||
if (g_upgrade_status.state != UPGRADE_PREPARING && g_upgrade_status.state != UPGRADE_TRANSFERRING) {
|
||||
debug_printf("Firmware upgrade error: not in PREPARING or TRANSFERRING state (current: %d)\n", g_upgrade_status.state);
|
||||
response[0] = STATUS_FAIL;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
uint16_t block_num = data[2] | (data[3] << 8);
|
||||
uint8_t data_len = data[4];
|
||||
|
||||
if (data_len != MAX_DATA_BLOCK_SIZE) {
|
||||
debug_printf("Firmware upgrade error: invalid data length %d (must be %d)\n", data_len, MAX_DATA_BLOCK_SIZE);
|
||||
response[0] = STATUS_SIZE_INVALID;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
|
||||
return STATUS_SIZE_INVALID;
|
||||
}
|
||||
|
||||
if (block_num != g_upgrade_status.expected_block_num) {
|
||||
debug_printf("Firmware upgrade error: block number mismatch (expected: %d, got: %d)\n",
|
||||
g_upgrade_status.expected_block_num, block_num);
|
||||
response[0] = STATUS_BLOCK_NUM_ERROR;
|
||||
response[1] = (g_upgrade_status.expected_block_num >> 0) & 0xFF;
|
||||
response[2] = (g_upgrade_status.expected_block_num >> 8) & 0xFF;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 3);
|
||||
return STATUS_BLOCK_NUM_ERROR;
|
||||
}
|
||||
|
||||
uint8_t received_checksum = data[5 + data_len];
|
||||
uint8_t calculated_checksum = check_sum(data, 5 + data_len);
|
||||
|
||||
if (received_checksum != calculated_checksum) {
|
||||
debug_printf("Firmware upgrade error: checksum mismatch (expected: 0x%02x, got: 0x%02x)\n",
|
||||
calculated_checksum, received_checksum);
|
||||
response[0] = STATUS_CHECKSUM_ERROR;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
|
||||
return STATUS_CHECKSUM_ERROR;
|
||||
}
|
||||
|
||||
if (g_upgrade_status.state == UPGRADE_PREPARING) {
|
||||
g_upgrade_status.state = UPGRADE_TRANSFERRING;
|
||||
|
||||
if (block_num == 0) {
|
||||
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
|
||||
debug_printf("Firmware upgrade: erasing existing upgrade image\n");
|
||||
dfu_flash_cmd_erase_all();
|
||||
g_flash_erased = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t buf_offset = g_upgrade_status.page_buf.offset;
|
||||
uint16_t remaining = FLASH_PAGE_SIZE - buf_offset;
|
||||
uint16_t to_copy = (data_len < remaining) ? data_len : remaining;
|
||||
|
||||
memcpy(&g_upgrade_status.page_buf.buffer[buf_offset], &data[5], to_copy);
|
||||
g_upgrade_status.page_buf.offset += to_copy;
|
||||
|
||||
if (g_upgrade_status.page_buf.offset >= FLASH_PAGE_SIZE) {
|
||||
unsigned char cmd_data[16];
|
||||
|
||||
if (g_upgrade_status.page_buf.written_pages == 0) {
|
||||
debug_printf("Firmware upgrade: writing first page data (flag=0 already executed in START)\n");
|
||||
} else {
|
||||
cmd_data[0] = 1;
|
||||
dfu_flash_cmd_write_page(cmd_data);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dfu_flash_cmd_write_page_data(&g_upgrade_status.page_buf.buffer[i * 64]);
|
||||
}
|
||||
|
||||
g_upgrade_status.page_buf.written_pages++;
|
||||
g_upgrade_status.page_buf.offset = 0;
|
||||
}
|
||||
|
||||
if (to_copy < data_len) {
|
||||
uint16_t remaining_data = data_len - to_copy;
|
||||
memcpy(&g_upgrade_status.page_buf.buffer[0], &data[5 + to_copy], remaining_data);
|
||||
g_upgrade_status.page_buf.offset = remaining_data;
|
||||
}
|
||||
|
||||
g_upgrade_status.received_blocks++;
|
||||
g_upgrade_status.expected_block_num++;
|
||||
|
||||
response[0] = STATUS_SUCCESS;
|
||||
response[1] = (block_num >> 0) & 0xFF;
|
||||
response[2] = (block_num >> 8) & 0xFF;
|
||||
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 3);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// 处理END命令
|
||||
unsigned char handle_firmware_upgrade_end(uint8_t data[], uint16_t len)
|
||||
{
|
||||
uint8_t response[64] = {0};
|
||||
|
||||
if (g_upgrade_status.state != UPGRADE_TRANSFERRING) {
|
||||
debug_printf("Firmware upgrade error: not in TRANSFERRING state (current: %d)\n", g_upgrade_status.state);
|
||||
response[0] = STATUS_FAIL;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
g_upgrade_status.state = UPGRADE_COMPLETING;
|
||||
|
||||
uint32_t firmware_size = data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24);
|
||||
debug_printf("Firmware upgrade END: firmware_size=%lu\n", firmware_size);
|
||||
|
||||
if (g_upgrade_status.page_buf.offset > 0) {
|
||||
for (uint16_t i = g_upgrade_status.page_buf.offset; i < FLASH_PAGE_SIZE; i++) {
|
||||
g_upgrade_status.page_buf.buffer[i] = 0x00;
|
||||
}
|
||||
|
||||
unsigned char cmd_data[16];
|
||||
cmd_data[0] = 1;
|
||||
dfu_flash_cmd_write_page(cmd_data);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dfu_flash_cmd_write_page_data(&g_upgrade_status.page_buf.buffer[i * 64]);
|
||||
}
|
||||
|
||||
g_upgrade_status.page_buf.written_pages++;
|
||||
debug_printf("Firmware upgrade: last page written (total pages: %d)\n",
|
||||
g_upgrade_status.page_buf.written_pages);
|
||||
}
|
||||
|
||||
unsigned char cmd_data[16];
|
||||
cmd_data[0] = 2;
|
||||
int result = dfu_flash_cmd_write_page(cmd_data);
|
||||
|
||||
if (result != 0) {
|
||||
debug_printf("Firmware upgrade error: flash write termination failed\n");
|
||||
g_upgrade_status.state = UPGRADE_ERROR;
|
||||
g_upgrade_status.error_code = STATUS_FAIL;
|
||||
response[0] = STATUS_FAIL;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
debug_printf("Firmware upgrade: image verification passed\n");
|
||||
g_upgrade_status.state = UPGRADE_COMPLETED;
|
||||
|
||||
response[0] = STATUS_SUCCESS;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
|
||||
debug_printf("Firmware upgrade completed successfully\n");
|
||||
g_firmware_upgrade_mcu_notify = 2;
|
||||
g_in_fw_upgrade = 0;
|
||||
g_upgrade_status.state = UPGRADE_IDLE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// 处理STATUS命令
|
||||
unsigned char handle_firmware_upgrade_status(uint8_t data[], uint16_t len)
|
||||
{
|
||||
uint8_t response[64] = {0};
|
||||
|
||||
response[0] = (uint8_t)g_upgrade_status.state;
|
||||
response[1] = (g_upgrade_status.received_blocks >> 0) & 0xFF;
|
||||
response[2] = (g_upgrade_status.received_blocks >> 8) & 0xFF;
|
||||
response[3] = (g_upgrade_status.total_blocks >> 0) & 0xFF;
|
||||
response[4] = (g_upgrade_status.total_blocks >> 8) & 0xFF;
|
||||
response[5] = (g_upgrade_status.page_buf.written_pages >> 0) & 0xFF;
|
||||
response[6] = (g_upgrade_status.page_buf.written_pages >> 8) & 0xFF;
|
||||
response[7] = (g_upgrade_status.page_buf.total_pages >> 0) & 0xFF;
|
||||
response[8] = (g_upgrade_status.page_buf.total_pages >> 8) & 0xFF;
|
||||
|
||||
uint32_t bytes_transferred = g_upgrade_status.received_blocks * MAX_DATA_BLOCK_SIZE;
|
||||
response[9] = (bytes_transferred >> 0) & 0xFF;
|
||||
response[10] = (bytes_transferred >> 8) & 0xFF;
|
||||
response[11] = (bytes_transferred >> 16) & 0xFF;
|
||||
response[12] = (bytes_transferred >> 24) & 0xFF;
|
||||
|
||||
response[13] = (g_upgrade_status.firmware_size >> 0) & 0xFF;
|
||||
response[14] = (g_upgrade_status.firmware_size >> 8) & 0xFF;
|
||||
response[15] = (g_upgrade_status.firmware_size >> 16) & 0xFF;
|
||||
response[16] = (g_upgrade_status.firmware_size >> 24) & 0xFF;
|
||||
|
||||
response[17] = g_upgrade_status.error_code;
|
||||
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_STATUS, response, 18);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// 处理ABORT命令
|
||||
unsigned char handle_firmware_upgrade_abort(uint8_t data[], uint16_t len)
|
||||
{
|
||||
uint8_t response[64] = {0};
|
||||
|
||||
uint8_t erase_flag = data[2];
|
||||
debug_printf("Firmware upgrade ABORT: erase_flag=0x%02x\n", erase_flag);
|
||||
|
||||
if (erase_flag == 0x01) {
|
||||
debug_printf("Firmware upgrade: erasing written data\n");
|
||||
dfu_flash_cmd_erase_all();
|
||||
}
|
||||
|
||||
dfu_flash_cmd_deinit();
|
||||
firmware_upgrade_reset();
|
||||
g_upgrade_status.state = UPGRADE_ABORTED;
|
||||
|
||||
response[0] = STATUS_SUCCESS;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ABORT, response, 1);
|
||||
g_firmware_upgrade_mcu_notify = 3;
|
||||
g_in_fw_upgrade = 0;
|
||||
g_upgrade_status.state = UPGRADE_IDLE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// 处理ERASE命令
|
||||
unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len)
|
||||
{
|
||||
uint8_t response[64] = {0};
|
||||
|
||||
debug_printf("Firmware upgrade ERASE: erasing all upgrade images\n");
|
||||
|
||||
if (dfu_flash_cmd_init() != 0) {
|
||||
debug_printf("Firmware upgrade error: flash init failed\n");
|
||||
response[0] = STATUS_FAIL;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ERASE, response, 1);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
|
||||
dfu_flash_cmd_erase_all();
|
||||
g_flash_erased = 1;
|
||||
} else {
|
||||
debug_printf("Firmware upgrade ERASE: erase skipped (already erased or begin_write started)\n");
|
||||
}
|
||||
|
||||
dfu_flash_cmd_deinit();
|
||||
|
||||
response[0] = STATUS_SUCCESS;
|
||||
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ERASE, response, 1);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// 固件升级主处理函数(分发0xA7-0xAC,0xAE由eq.c直接处理)
|
||||
unsigned char process_firmware_upgrade_cmd(uint8_t data[], uint16_t len)
|
||||
{
|
||||
if (data[0] != 0x77) {
|
||||
debug_printf("Firmware upgrade error: invalid sync header 0x%02x\n", data[0]);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
uint8_t cmd = data[1];
|
||||
debug_printf("Firmware upgrade command: 0x%02x\n", cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case FIRMWARE_UPGRADE_START:
|
||||
return handle_firmware_upgrade_start(data, len);
|
||||
case FIRMWARE_UPGRADE_DATA:
|
||||
return handle_firmware_upgrade_data(data, len);
|
||||
case FIRMWARE_UPGRADE_END:
|
||||
return handle_firmware_upgrade_end(data, len);
|
||||
case FIRMWARE_UPGRADE_STATUS:
|
||||
return handle_firmware_upgrade_status(data, len);
|
||||
case FIRMWARE_UPGRADE_ABORT:
|
||||
return handle_firmware_upgrade_abort(data, len);
|
||||
case FIRMWARE_UPGRADE_ERASE:
|
||||
return handle_firmware_upgrade_erase(data, len);
|
||||
default:
|
||||
debug_printf("Firmware upgrade error: unknown command 0x%02x\n", cmd);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HID_DFU_EN
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright 2026 Shanling.
|
||||
// HID固件升级头文件
|
||||
// 改动原因:实现通过HID协议进行固件升级的功能,提供高效、稳定、安全的升级方案
|
||||
|
||||
#ifndef _DFU_UPGRADE_H_
|
||||
#define _DFU_UPGRADE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// 固件升级命令定义
|
||||
#define FIRMWARE_UPGRADE_START 0xA7 // 开始固件升级
|
||||
#define FIRMWARE_UPGRADE_DATA 0xA8 // 传输固件数据块
|
||||
#define FIRMWARE_UPGRADE_END 0xA9 // 结束固件升级
|
||||
#define FIRMWARE_UPGRADE_STATUS 0xAA // 获取升级状态
|
||||
#define FIRMWARE_UPGRADE_ABORT 0xAB // 中止固件升级
|
||||
#define FIRMWARE_UPGRADE_ERASE 0xAC // 擦除现有升级镜像
|
||||
#define DEVICE_REBOOT 0xAE // 设备重启(通用命令,不仅限于固件升级)
|
||||
|
||||
// 升级状态定义
|
||||
typedef enum {
|
||||
UPGRADE_IDLE = 0x00, // 空闲状态,未开始升级
|
||||
UPGRADE_PREPARING = 0x01, // 准备状态,已调用START
|
||||
UPGRADE_TRANSFERRING = 0x02, // 传输状态,正在接收数据
|
||||
UPGRADE_COMPLETING = 0x03, // 完成中,正在写入最后一页
|
||||
UPGRADE_COMPLETED = 0x04, // 已完成,升级成功
|
||||
UPGRADE_ERROR = 0x05, // 错误状态,升级失败
|
||||
UPGRADE_ABORTED = 0x06 // 已中止,升级被中止
|
||||
} upgrade_state_t;
|
||||
|
||||
// 状态码定义
|
||||
#define STATUS_SUCCESS 0x00 // 成功
|
||||
#define STATUS_FAIL 0x01 // 失败
|
||||
#define STATUS_SPACE_INSUFFICIENT 0x02 // Flash空间不足
|
||||
#define STATUS_SIZE_INVALID 0x03 // 大小无效
|
||||
#define STATUS_BLOCK_NUM_ERROR 0x04 // 块序号错误
|
||||
#define STATUS_CHECKSUM_ERROR 0x05 // Checksum错误
|
||||
#define STATUS_DATA_INCOMPLETE 0x06 // 数据不完整
|
||||
#define STATUS_VERSION_INVALID 0x08 // 版本号无效
|
||||
#define STATUS_SIZE_MISMATCH 0x09 // 大小不匹配
|
||||
|
||||
// Flash参数
|
||||
#define FLASH_PAGE_SIZE 256 // Flash页大小
|
||||
// 改动原因:修正最大数据块大小,HID数据包63字节(不包括Report ID)
|
||||
// 数据包格式:同步头(1) + 命令码(1) + 块序号(2) + 数据长度(1) + 数据(N) + Checksum(1)
|
||||
// 所以最大数据长度 = 63 - 5(头部) - 1(Checksum) = 57字节
|
||||
#define MAX_DATA_BLOCK_SIZE 57 // 最大数据块大小(63字节HID数据包 - 5字节头部 - 1字节Checksum)
|
||||
#define FLASH_MAX_UPGRADE_SIZE (2000 * 1024) // 最大固件大小1400KB
|
||||
|
||||
// 页缓冲区结构
|
||||
typedef struct {
|
||||
uint8_t buffer[FLASH_PAGE_SIZE]; // Flash页缓冲区
|
||||
uint16_t offset; // 当前偏移
|
||||
uint16_t total_pages; // 总页数
|
||||
uint16_t written_pages; // 已写入页数
|
||||
} page_buffer_t;
|
||||
|
||||
// 升级状态结构
|
||||
typedef struct {
|
||||
upgrade_state_t state; // 当前状态
|
||||
uint32_t firmware_size; // 固件总大小
|
||||
uint16_t total_blocks; // 总块数
|
||||
uint16_t received_blocks; // 已接收块数
|
||||
uint16_t expected_block_num; // 期望的块序号
|
||||
// 改动原因:去掉固件版本号字段,不再存储版本号
|
||||
uint8_t error_code; // 错误码
|
||||
page_buffer_t page_buf; // 页缓冲区
|
||||
uint8_t first_page_written; // 第一页写命令是否已执行(0=未执行,1=已执行)
|
||||
} upgrade_status_t;
|
||||
|
||||
// 固件升级主处理函数
|
||||
// 改动原因:处理HID固件升级命令,支持START、DATA、END等命令
|
||||
// 参数:
|
||||
// - data: HID数据包(63字节,不包括Report ID)
|
||||
// - len: 数据长度
|
||||
// 返回值:0=成功,非0=失败
|
||||
unsigned char process_firmware_upgrade_cmd(uint8_t data[], uint16_t len);
|
||||
|
||||
/* 改动原因:声明 DFU channel 转发函数,供 eq.c (process_send_params) 调用,
|
||||
* 将 HID 固件升级命令通过 streaming channel 转发到 uart_handler 处理。
|
||||
* 实现在 audiohw.xc 中。 */
|
||||
void dfu_chan_forward(unsigned char data[], unsigned len);
|
||||
|
||||
// 各个固件升级命令的独立处理函数
|
||||
// 改动原因:在eq.c中为每个命令添加独立处理,支持HID一条一条指令发送
|
||||
// 参数:
|
||||
// - data: HID数据包(63字节,不包括Report ID)
|
||||
// - len: 数据长度
|
||||
// 返回值:0=成功,非0=失败(状态码)
|
||||
unsigned char handle_firmware_upgrade_start(uint8_t data[], uint16_t len);
|
||||
unsigned char handle_firmware_upgrade_data(uint8_t data[], uint16_t len);
|
||||
unsigned char handle_firmware_upgrade_end(uint8_t data[], uint16_t len);
|
||||
unsigned char handle_firmware_upgrade_status(uint8_t data[], uint16_t len);
|
||||
unsigned char handle_firmware_upgrade_abort(uint8_t data[], uint16_t len);
|
||||
unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len);
|
||||
|
||||
// 发送固件升级响应(主动上报)
|
||||
// 改动原因:通过HID主动上报机制发送响应,与音量上报机制一致
|
||||
// 参数:
|
||||
// - cmd: 命令码
|
||||
// - response_data: 响应数据
|
||||
// - data_len: 响应数据长度
|
||||
void send_firmware_upgrade_response(uint8_t cmd, uint8_t *response_data, uint16_t data_len);
|
||||
|
||||
// 升级进行中标志(升级期间阻止其他HID主动上报)
|
||||
extern unsigned g_in_fw_upgrade;
|
||||
|
||||
// 初始化固件升级模块
|
||||
// 改动原因:初始化升级状态和缓冲区
|
||||
void firmware_upgrade_init(void);
|
||||
|
||||
// 获取当前升级状态
|
||||
// 改动原因:供外部查询当前升级状态
|
||||
upgrade_state_t firmware_upgrade_get_state(void);
|
||||
|
||||
// 重置升级状态
|
||||
// 改动原因:升级完成或中止后重置状态
|
||||
void firmware_upgrade_reset(void);
|
||||
|
||||
// ====================== UART DFU 友好接口 ======================
|
||||
// 改动原因:为 UART 串口升级提供不依赖 g_hid_pass_data 的接口,
|
||||
// 内部仍然复用 HID DFU 的状态机和 Flash 写入流程。
|
||||
//
|
||||
// 这些函数只操作内部的 g_upgrade_status,并通过参数返回需要的字段,
|
||||
// 方便 user_uart.xc 根据 UART 协议打包响应。
|
||||
|
||||
// UART 版 START:输入固件原始大小,返回对齐后的大小和总块数
|
||||
unsigned char uart_firmware_upgrade_start(uint32_t firmware_size,
|
||||
uint32_t *aligned_size_out,
|
||||
uint16_t *total_blocks_out);
|
||||
|
||||
// UART 版 DATA:输入块号和数据,返回状态码和“确认的块号”(成功时等于块号,序号错误时为期望块号)
|
||||
unsigned char uart_firmware_upgrade_data(uint16_t block_num,
|
||||
uint8_t data_len,
|
||||
const uint8_t *data,
|
||||
uint16_t *confirmed_block_out);
|
||||
|
||||
// UART 版 END:结束升级,写入最后一页并终止 Flash 写入
|
||||
unsigned char uart_firmware_upgrade_end(uint32_t firmware_size);
|
||||
|
||||
// UART 版 STATUS:直接从 g_upgrade_status 中读取当前状态和进度
|
||||
unsigned char uart_firmware_upgrade_status(uint8_t *state_out,
|
||||
uint16_t *received_blocks_out,
|
||||
uint16_t *total_blocks_out,
|
||||
uint16_t *written_pages_out,
|
||||
uint16_t *total_pages_out,
|
||||
uint32_t *bytes_transferred_out,
|
||||
uint32_t *firmware_size_out,
|
||||
uint8_t *error_code_out);
|
||||
|
||||
// UART 版 ABORT:中止升级,可选择是否擦除已写入数据
|
||||
unsigned char uart_firmware_upgrade_abort(uint8_t erase_flag);
|
||||
|
||||
// UART 版 ERASE:擦除现有 upgrade image 并执行 begin_write 初始化
|
||||
unsigned char uart_firmware_upgrade_erase(void);
|
||||
|
||||
#endif // _DFU_UPGRADE_H_
|
||||
@@ -96,6 +96,15 @@ void dnr_set_mode(unsigned char mode)
|
||||
g_dnr_level = -200;
|
||||
}
|
||||
|
||||
// 按HID强度值(0=关,2-100步进2)设置降噪深度:strength * 2 → dB(100→-200dB)
|
||||
void dnr_set_strength_level(unsigned char strength)
|
||||
{
|
||||
if (strength == 0)
|
||||
g_dnr_level = 0;
|
||||
else
|
||||
g_dnr_level = -(float)(strength * 2);
|
||||
}
|
||||
|
||||
void start_dsp_processing(void)
|
||||
{
|
||||
setNoisy_mix_factor(g_dnr_level);
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
extern void device_reboot(void);
|
||||
|
||||
#if HID_DFU_EN
|
||||
#include "dfu_upgrade.h"
|
||||
#endif
|
||||
|
||||
// 常量定义
|
||||
#define EQ_DISABLED_MODE 10 // 禁用EQ的模式编号
|
||||
|
||||
@@ -634,6 +638,7 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
|
||||
extern unsigned g_request_mic_volume_set;
|
||||
g_mic_volume_level = mic_level;
|
||||
g_request_mic_volume_set = 1;
|
||||
read_request.pending_cmd = 0x83; // 设置后用0x83格式回报当前增益
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -644,6 +649,48 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理设置AI降噪强度命令 (0x85) - SET_AI_NOISE_STRENGTH
|
||||
// 有效值: 0(关闭), 2,4,...,100(步进2); 强度映射: strength*2 → dB (100→-200dB)
|
||||
if (data[1] == 0x85) {
|
||||
uint8_t strength = data[2];
|
||||
if (strength > 100 || (strength != 0 && strength % 2 != 0)) {
|
||||
return false;
|
||||
}
|
||||
extern unsigned g_dnr_strength;
|
||||
extern unsigned g_request_dnr_strength_set;
|
||||
g_dnr_strength = strength;
|
||||
g_request_dnr_strength_set = 1;
|
||||
read_request.pending_cmd = 0x86; // 设置后用0x86格式回报当前强度
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理读取AI降噪强度命令 (0x86) - GET_AI_NOISE_STRENGTH
|
||||
if (data[1] == 0x86) {
|
||||
read_request.pending_cmd = 0x86;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理设置耳返开关命令 (0x87) - SET_MONITOR_SWITCH
|
||||
// 0=关闭耳返(ADC不路由到耳机输出),1=开启耳返
|
||||
if (data[1] == 0x87) {
|
||||
uint8_t mon_sw = data[2];
|
||||
if (mon_sw > 1) {
|
||||
return false;
|
||||
}
|
||||
extern unsigned g_monitor_switch;
|
||||
extern unsigned g_request_monitor_switch_set;
|
||||
g_monitor_switch = mon_sw;
|
||||
g_request_monitor_switch_set = 1;
|
||||
read_request.pending_cmd = 0x88; // 设置后用0x88格式回报当前状态
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理读取耳返开关命令 (0x88) - GET_MONITOR_SWITCH
|
||||
if (data[1] == 0x88) {
|
||||
read_request.pending_cmd = 0x88;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理设置音量命令 (0x93) - SET_VOLUME
|
||||
// 范围: 0-15 (0=静音, 1-15=-28dB~0dB, 2dB/步)
|
||||
if (data[1] == 0x93) {
|
||||
@@ -733,6 +780,9 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
|
||||
lfs_remove_file("mic_vol");
|
||||
lfs_remove_file("dac_vol");
|
||||
lfs_remove_file("footstep");
|
||||
lfs_remove_file("monitor_sw");
|
||||
lfs_remove_file("mic_mute");
|
||||
lfs_remove_file("hp_mute");
|
||||
// 删除EQ flash数据
|
||||
eq_flash_clear_all();
|
||||
// 通知button_task在合适时机重启(避免在USB上下文中直接reboot)
|
||||
@@ -805,6 +855,39 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
|
||||
}
|
||||
|
||||
#endif // #if EQ_EN (for process_send_params EQ commands section starting at line 1228)
|
||||
|
||||
#if HID_DFU_EN
|
||||
// 0xA7 START: 转发到button_task (tile[0])执行,因为flash访问需要在tile[0]进行
|
||||
if (data[1] == FIRMWARE_UPGRADE_START) {
|
||||
dfu_chan_forward(data, len);
|
||||
return true;
|
||||
}
|
||||
// 0xA8 DATA / 0xA9 END / 0xAA STATUS / 0xAB ABORT / 0xAC ERASE: 直接处理
|
||||
if (data[1] >= FIRMWARE_UPGRADE_DATA && data[1] <= FIRMWARE_UPGRADE_ERASE) {
|
||||
unsigned char result;
|
||||
if (data[1] == FIRMWARE_UPGRADE_DATA)
|
||||
result = handle_firmware_upgrade_data(data, len);
|
||||
else if (data[1] == FIRMWARE_UPGRADE_END)
|
||||
result = handle_firmware_upgrade_end(data, len);
|
||||
else if (data[1] == FIRMWARE_UPGRADE_STATUS)
|
||||
result = handle_firmware_upgrade_status(data, len);
|
||||
else if (data[1] == FIRMWARE_UPGRADE_ABORT)
|
||||
result = handle_firmware_upgrade_abort(data, len);
|
||||
else
|
||||
result = handle_firmware_upgrade_erase(data, len);
|
||||
(void)result;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 0xAE DEVICE_REBOOT (通用命令,不仅限于固件升级)
|
||||
if (data[1] == 0xAE) {
|
||||
debug_printf("Received device REBOOT command (0xAE)\n");
|
||||
device_reboot();
|
||||
while(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -880,17 +963,6 @@ void init_mode_info(void) {
|
||||
#endif
|
||||
|
||||
void get_key_ret(uint8_t *buffer);
|
||||
extern unsigned char g_hid_status_report_data[63];
|
||||
extern unsigned int g_hid_status_report_index;
|
||||
void user_read_hid_status(unsigned char hidPassData[])
|
||||
{
|
||||
if (g_hid_status_report_index > 0) {
|
||||
memcpy(hidPassData, g_hid_status_report_data, 63);
|
||||
g_hid_status_report_index = 0;
|
||||
} else {
|
||||
memset(hidPassData, 0, 63);
|
||||
}
|
||||
}
|
||||
|
||||
// process_read_params: build HID response from pending request state
|
||||
unsigned char process_read_params(uint8_t response[]) {
|
||||
@@ -1003,6 +1075,29 @@ unsigned char process_read_params(uint8_t response[]) {
|
||||
read_request.pending_cmd = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理AI降噪强度请求/响应 (0x86) - GET_AI_NOISE_STRENGTH
|
||||
if (read_request.pending_cmd == 0x86) {
|
||||
RSP_HDR(response, 0x86);
|
||||
|
||||
extern unsigned g_dnr_strength;
|
||||
response[2] = (uint8_t)g_dnr_strength;
|
||||
|
||||
read_request.pending_cmd = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理耳返开关请求/响应 (0x88) - GET_MONITOR_SWITCH
|
||||
if (read_request.pending_cmd == 0x88) {
|
||||
RSP_HDR(response, 0x88);
|
||||
|
||||
extern unsigned g_monitor_switch;
|
||||
response[2] = (uint8_t)g_monitor_switch;
|
||||
|
||||
read_request.pending_cmd = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理读取音量请求 (0x94) - GET_VOLUME
|
||||
if (read_request.pending_cmd == 0x94) {
|
||||
RSP_HDR(response, 0x94);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,10 @@
|
||||
| 0x82 | SET_MIC_VOLUME | 设置麦克风增益级别 | 主机→设备 | 设置麦克风PGA增益(0=静音, 1-37=0dB~36dB, 1dB/步) |
|
||||
| 0x83 | GET_MIC_VOLUME | 获取麦克风增益级别 | 主机→设备 | 读取当前麦克风PGA增益级别(0=静音, 1-37=0dB~36dB) |
|
||||
| 0x84 | FACTORY_RESET | 恢复出厂默认设置 | 主机→设备 | 删除Flash中所有已保存参数,设备重启后自动恢复出厂默认值 |
|
||||
| 0x85 | SET_AI_NOISE_STRENGTH | 设置AI降噪强度 | 主机→设备 | 设置AI降噪强度(0=关闭,2-100偶数=强度级别,步进2;100对应最强-200dB) |
|
||||
| 0x86 | GET_AI_NOISE_STRENGTH | 获取AI降噪强度 | 主机→设备 | 读取当前AI降噪强度;强度变化(含按键切换、开机初始值)时设备主动上报 |
|
||||
| 0x87 | SET_MONITOR_SWITCH | 设置耳返开关 | 主机→设备 | 设置耳返(ADC→耳机监听)开关(0=关闭,1=开启),保存到Flash |
|
||||
| 0x88 | GET_MONITOR_SWITCH | 获取耳返开关状态 | 主机→设备 | 读取当前耳返开关状态(0=关闭,1=开启) |
|
||||
| 0x8A | SET_EQ_MODE | 切换EQ模式 | 主机→设备 | 切换EQ模式 |
|
||||
| 0x8B | GET_EQ_MODE | 获取当前EQ模式信息 | 主机→设备 | 读取设备当前EQ模式和名称 |
|
||||
| 0x8C | SET_MODE_GAIN_AND_NAME | 设置模式整体增益和名称 | 主机→设备 | 设置模式整体增益和名称 |
|
||||
@@ -120,6 +124,9 @@
|
||||
| 监听音量 | 15 (-14dB) | DAC level 15 = 0dB - 14 = -14dB |
|
||||
| EQ参数 | 头文件预设 | 删除所有用户EQ参数,恢复固件内置预设 |
|
||||
| AI降噪 | 开启 | 每次上电默认开启(不保存到Flash) |
|
||||
| 耳返开关 | 0 (关闭) | ADC→耳机监听通路默认关闭 |
|
||||
| 麦克风静音 | 0 (未静音) | 麦克风静音状态默认关闭 |
|
||||
| 监听静音 | 0 (未静音) | 耳机输出静音状态默认关闭 |
|
||||
|
||||
**设备端处理**:
|
||||
1. 删除Flash中保存的以下参数文件:
|
||||
@@ -127,6 +134,9 @@
|
||||
- `mic_vol`(麦克风音量)
|
||||
- `dac_vol`(监听音量)
|
||||
- `footstep`(脚步增强状态)
|
||||
- `monitor_sw`(耳返开关)
|
||||
- `mic_mute`(麦克风静音状态)
|
||||
- `hp_mute`(耳机静音状态)
|
||||
- 所有EQ参数文件(调用eq_flash_clear_all)
|
||||
2. 设置重启标志,约500ms后设备自动重启
|
||||
3. 重启后自动加载出厂默认参数
|
||||
@@ -147,6 +157,127 @@
|
||||
- 重启后所有参数将恢复为出厂默认值
|
||||
- 此操作不可撤销
|
||||
|
||||
### 2.0d 0x85 - SET_AI_NOISE_STRENGTH (设置AI降噪强度)
|
||||
**功能**: 设置AI降噪强度级别
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x85 | 命令码
|
||||
2 | 1 | uint8 | 强度值 (0=关闭, 2/4/.../100=强度级别, 步进2)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
- **强度值范围**: 0、2、4、6、…、100(共51个有效值)
|
||||
- **0**: 关闭AI降噪
|
||||
- **2-100(步进2)**: 开启AI降噪,强度递增;内部dB映射:`dB = -(strength × 2)`
|
||||
- 2 → -4 dB(最轻微降噪)
|
||||
- 50 → -100 dB
|
||||
- 100 → -200 dB(最强降噪,出厂默认)
|
||||
- **奇数或 >100** 为无效值,固件将拒绝(返回无响应)
|
||||
|
||||
**设备端处理**:
|
||||
- 强度=0:关闭AI降噪算法,熄灭LED_ANC,flag_aidenoise_onoff=0
|
||||
- 强度=2-100:开启AI降噪算法,点亮LED_ANC,flag_aidenoise_onoff=1,更新内部降噪深度
|
||||
- 设置成功后设备主动上报当前强度(0x86格式)
|
||||
- **不保存到Flash**;重启后AI降噪恢复为开启(强度=100,即-200dB最强)
|
||||
|
||||
**返回值**:
|
||||
无直接返回,设置成功后设备通过0x86格式主动上报当前强度值。
|
||||
|
||||
### 2.0e 0x86 - GET_AI_NOISE_STRENGTH (获取AI降噪强度)
|
||||
**功能**: 读取设备当前AI降噪强度;强度变化时设备主动上报
|
||||
**方向**: 主机→设备(请求),设备→主机(响应/主动上报)
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x86 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**(含主动上报):
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x86 | 同步头2
|
||||
3 | 1 | uint8 | 当前强度值 (0=关闭, 2-100=强度级别)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**主动上报说明**:
|
||||
- **开机时**:设备初始化完成后主动上报当前强度(出厂默认=100)
|
||||
- **按键切换**:用户按下AI降噪按键时,设备主动上报新强度(关闭时上报0,开启时上报恢复的强度)
|
||||
- **HID SET_AI_NOISE_STRENGTH(0x85)命令成功执行后**,设备主动上报新强度
|
||||
|
||||
### 2.0f 0x87 - SET_MONITOR_SWITCH (设置耳返开关)
|
||||
**功能**: 设置耳返(ADC→耳机监听)开关,控制是否将麦克风输入实时路由到耳机输出
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x87 | 命令码
|
||||
2 | 1 | uint8 | 开关值 (0=关闭, 1=开启)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
- **0**: 关闭耳返,ADC数据不路由到耳机输出(NAU88L21 reg 0x0035 = 0x0000)
|
||||
- **1**: 开启耳返,ADC数据路由到耳机输出(NAU88L21 reg 0x0035 = 0xCFCF,0dB监听音量)
|
||||
- **注意**: 耳返路由需要麦克风未静音(mic_mute=0)且麦克风增益有效(level≥2)方才生效
|
||||
|
||||
**设备端处理**:
|
||||
- 立即更新 NAU88L21 reg 0x0035(耳返音量寄存器)
|
||||
- 若麦克风当前处于静音状态,则无论耳返开关为何值,reg 0x0035保持0x0000
|
||||
- 保存到Flash(`monitor_sw`路径),断电重启后自动恢复
|
||||
- 设置成功后用0x88格式响应当前状态
|
||||
- 出厂默认:关闭(0)
|
||||
|
||||
**返回值**:
|
||||
设置成功后设备回复0x88格式响应。
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x88 | 同步头2
|
||||
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.0g 0x88 - GET_MONITOR_SWITCH (获取耳返开关状态)
|
||||
**功能**: 读取当前耳返开关状态
|
||||
**方向**: 主机→设备(请求),设备→主机(响应)
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x88 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x88 | 同步头2
|
||||
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.1 0x8A - SET_EQ_MODE (切换EQ模式)
|
||||
**功能**: 切换当前EQ模式
|
||||
**方向**: 主机→设备
|
||||
@@ -789,3 +920,133 @@
|
||||
4. **错误恢复**: 通信失败时需要重新建立连接并重试
|
||||
5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制
|
||||
|
||||
---
|
||||
|
||||
## 8. 固件升级命令 (0xA7–0xAE)
|
||||
|
||||
本节定义通过HID进行固件升级的命令。最大数据块57字节,Flash页256字节,字节序小端序。
|
||||
|
||||
### 8.1 固件升级命令列表
|
||||
|
||||
| 指令码 | 命令名称 | 功能 | 方向 |
|
||||
|--------|----------|------|------|
|
||||
| 0xA7 | FIRMWARE_UPGRADE_START | 开始固件升级 | 主机→设备 |
|
||||
| 0xA8 | FIRMWARE_UPGRADE_DATA | 传输固件数据块(固定57字节) | 主机→设备 |
|
||||
| 0xA9 | FIRMWARE_UPGRADE_END | 结束固件升级,验证镜像 | 主机→设备 |
|
||||
| 0xAA | FIRMWARE_UPGRADE_STATUS | 获取升级状态和进度 | 主机→设备 |
|
||||
| 0xAB | FIRMWARE_UPGRADE_ABORT | 中止固件升级 | 主机→设备 |
|
||||
| 0xAC | FIRMWARE_UPGRADE_ERASE | 擦除现有升级镜像 | 主机→设备 |
|
||||
| 0xAE | DEVICE_REBOOT | 设备重启(通用命令) | 主机→设备 |
|
||||
|
||||
### 8.2 0xA7 - FIRMWARE_UPGRADE_START
|
||||
|
||||
**请求**:
|
||||
```
|
||||
字节 0: 0x77 同步头
|
||||
字节 1: 0xA7 命令码
|
||||
字节 2-5: uint32 固件大小(字节,小端序)
|
||||
字节 6-62: 0x00 保留
|
||||
```
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA7
|
||||
字节 2: 状态码 (0x00=成功, 0x01=失败, 0x03=大小无效)
|
||||
字节 3-6: uint32 页对齐后的实际大小
|
||||
字节 7-8: uint16 总块数
|
||||
字节 9-62: 0x00
|
||||
```
|
||||
|
||||
### 8.3 0xA8 - FIRMWARE_UPGRADE_DATA
|
||||
|
||||
**请求**(数据块固定57字节,不足补0):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA8
|
||||
字节 2-3: uint16 块序号(从0开始,小端序)
|
||||
字节 4: uint8 数据长度(固定57)
|
||||
字节 5-61: uint8[57] 固件数据
|
||||
字节 62: uint8 Checksum(字节0-61累加 mod 256)
|
||||
```
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA8
|
||||
字节 2: 状态码 (0x00=成功, 0x04=块号错误, 0x05=Checksum错误)
|
||||
字节 3-4: uint16 已确认块序号
|
||||
字节 5-62: 0x00
|
||||
```
|
||||
|
||||
### 8.4 0xA9 - FIRMWARE_UPGRADE_END
|
||||
|
||||
**请求**:
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA9
|
||||
字节 2-5: uint32 固件总大小(用于验证)
|
||||
字节 6-62: 0x00
|
||||
```
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA9
|
||||
字节 2: 状态码 (0x00=成功, 0x01=失败)
|
||||
字节 3-62: 0x00
|
||||
```
|
||||
|
||||
### 8.5 0xAA - FIRMWARE_UPGRADE_STATUS
|
||||
|
||||
**请求**: 字节0=0x77, 字节1=0xAA, 其余0x00
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xAA
|
||||
字节 2: 升级状态 (0=空闲, 1=准备中, 2=传输中, 3=完成中, 4=已完成, 5=错误, 6=已中止)
|
||||
字节 3-4: uint16 已接收块数
|
||||
字节 5-6: uint16 总块数
|
||||
字节 7-8: uint16 已写页数
|
||||
字节 9-10: uint16 总页数
|
||||
字节 11-14: uint32 已传输字节数
|
||||
字节 15-18: uint32 总字节数
|
||||
字节 19: 错误码
|
||||
字节 20-62: 0x00
|
||||
```
|
||||
|
||||
### 8.6 0xAB - FIRMWARE_UPGRADE_ABORT
|
||||
|
||||
**请求**:
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xAB
|
||||
字节 2: 清理标志 (0x00=保留数据, 0x01=擦除数据)
|
||||
字节 3-62: 0x00
|
||||
```
|
||||
|
||||
**响应**(主动上报): 字节0=0x77, 字节1=0xAB, 字节2=状态码(0x00=成功)
|
||||
|
||||
### 8.7 0xAC - FIRMWARE_UPGRADE_ERASE
|
||||
|
||||
**请求**: 字节0=0x77, 字节1=0xAC, 其余0x00
|
||||
|
||||
**响应**(主动上报): 字节0=0x77, 字节1=0xAC, 字节2=状态码(0x00=成功)
|
||||
|
||||
### 8.8 0xAE - DEVICE_REBOOT
|
||||
|
||||
**请求**: 字节0=0x77, 字节1=0xAE, 其余0x00
|
||||
|
||||
**响应**: 无响应,设备立即重启。
|
||||
|
||||
### 8.9 标准升级流程
|
||||
|
||||
```
|
||||
1. (可选) ERASE — 擦除现有upgrade image
|
||||
2. START — 设置固件大小,等待响应(SUCCESS)
|
||||
3. 循环 DATA — 逐块发送,每块等待响应确认
|
||||
4. END — 完成写入,等待响应(SUCCESS)
|
||||
5. REBOOT — 重启加载新固件
|
||||
```
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ typedef enum {
|
||||
LED_MUSIC = 2, // OUT2 - 音乐模式
|
||||
LED_ANC = 1, // OUT1 - ANC模式
|
||||
LED_FOOTSTEP_MODE = 3, // OUT3 - 脚步模式
|
||||
LED_AI7_1 = 34, // OUT34 - AI7.1模式
|
||||
LED_GAME_MODE = 35, // OUT35 - 游戏模式
|
||||
LED_AI7_1 = 35, // OUT34 - AI7.1模式
|
||||
LED_GAME_MODE = 34, // OUT35 - 游戏模式
|
||||
// OUT36未使用
|
||||
|
||||
// L系列LED (OUT4-OUT18)
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
#ifndef _LFS_IO_H_
|
||||
#define _LFS_IO_H_
|
||||
#if __XC__
|
||||
int lfs_init(void);
|
||||
void lfs_deinit(void);
|
||||
void lfs_read_config(unsigned char * unsafe config, unsigned char * unsafe buffer, unsigned size);
|
||||
void lfs_write_config(unsigned char * unsafe config, unsigned char * unsafe buffer, unsigned size);
|
||||
// EQ参数专用函数
|
||||
void lfs_read_eq_config(const char * unsafe file_path, unsigned char * unsafe buffer, unsigned size);
|
||||
void lfs_write_eq_config(const char * unsafe file_path, unsigned char * unsafe buffer, unsigned size);
|
||||
int lfs_file_exists(const char * unsafe file_path);
|
||||
int lfs_remove_file(const char * unsafe file_path);
|
||||
int lfs_create_directory(const char * unsafe dir_path);
|
||||
#else
|
||||
|
||||
int lfs_init(void);
|
||||
void lfs_deinit(void);
|
||||
void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned size);
|
||||
@@ -10,4 +23,6 @@ void lfs_write_eq_config(const char * file_path, unsigned char * buffer, unsigne
|
||||
int lfs_file_exists(const char * file_path);
|
||||
int lfs_remove_file(const char * file_path);
|
||||
int lfs_create_directory(const char * dir_path);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -431,13 +431,20 @@ extern int dsp_worker_tile(chanend c_dsp_to_ex3d, int worker_id);
|
||||
//extern int dsp_worker_tile_1(chanend c_dsp_to_ex3d, int worker_id);
|
||||
extern void ex3d_task();
|
||||
extern void hid_button_task(chanend cc_mic_level, chanend c_hid, chanend c_hidSendData, chanend c_uac_vol, chanend c_ex3d_hid_cmd);
|
||||
#if HID_DFU_EN
|
||||
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx, streaming chanend c_dfu_rx);
|
||||
#else
|
||||
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx);
|
||||
#endif
|
||||
extern void dnr_dsp_proc_task(void);
|
||||
|
||||
extern unsafe chanend uc_dsp_to_ex3d[DSP_WORKER_COUNT];
|
||||
extern unsafe chanend uc_dsp_to_dnr_t1;
|
||||
extern unsafe chanend uc_key_to_ubm_t0;
|
||||
extern unsafe chanend uc_audiohw;
|
||||
#if HID_DFU_EN
|
||||
extern unsafe streaming chanend uc_dfu;
|
||||
#endif
|
||||
extern void key_sender(chanend c_key);
|
||||
extern void key_receiver(chanend c_key);
|
||||
|
||||
@@ -535,6 +542,9 @@ int main()
|
||||
chan c_dsp_to_ex3d[DSP_WORKER_COUNT];
|
||||
chan cc_mic_level;
|
||||
chan c_audiohw;
|
||||
#if HID_DFU_EN
|
||||
streaming chan c_dfu;
|
||||
#endif
|
||||
chan c_key; chan c_hidSendData;
|
||||
chan c_hidRcvData;
|
||||
chan c_eq_data;
|
||||
@@ -572,13 +582,24 @@ int main()
|
||||
#if USE_EX3D == 1
|
||||
unsafe { key_receiver(c_key); }
|
||||
#endif
|
||||
AudioHwRemote(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw);
|
||||
AudioHwRemote(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw
|
||||
#if HID_DFU_EN
|
||||
, c_dfu
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if EQ_EN == 1
|
||||
on tile[0] : {
|
||||
{
|
||||
|
||||
#if HID_DFU_EN
|
||||
unsafe {
|
||||
uc_dfu = (streaming chanend)c_dfu;
|
||||
}
|
||||
#endif
|
||||
|
||||
dsp_core0();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,938 @@
|
||||
# EQ HID通信协议详细文档
|
||||
|
||||
## 1. 总体框架
|
||||
|
||||
### 1.1 协议概述
|
||||
该协议使用HID (Human Interface Device) 协议进行主机与设备之间的通信。协议支持EQ参数设置、读取、模式切换等功能。
|
||||
|
||||
### 1.2 支持的指令列表
|
||||
| 指令码 | 命令名称 | 功能 | 方向 | 描述 |
|
||||
|--------|----------|------|------|------|
|
||||
| 0x82 | SET_MIC_VOLUME | 设置麦克风增益级别 | 主机→设备 | 设置麦克风PGA增益(0=静音, 1-37=0dB~36dB, 1dB/步) |
|
||||
| 0x83 | GET_MIC_VOLUME | 获取麦克风增益级别 | 主机→设备 | 读取当前麦克风PGA增益级别(0=静音, 1-37=0dB~36dB) |
|
||||
| 0x84 | FACTORY_RESET | 恢复出厂默认设置 | 主机→设备 | 删除Flash中所有已保存参数,设备重启后自动恢复出厂默认值 |
|
||||
| 0x87 | SET_MONITOR_SWITCH | 设置耳返开关 | 主机→设备 | 设置耳返(ADC→耳机监听)开关(0=关闭,1=开启),保存到Flash |
|
||||
| 0x88 | GET_MONITOR_SWITCH | 获取耳返开关状态 | 主机→设备 | 读取当前耳返开关状态(0=关闭,1=开启) |
|
||||
| 0x8A | SET_EQ_MODE | 切换EQ模式 | 主机→设备 | 切换EQ模式 |
|
||||
| 0x8B | GET_EQ_MODE | 获取当前EQ模式信息 | 主机→设备 | 读取设备当前EQ模式和名称 |
|
||||
| 0x8C | SET_MODE_GAIN_AND_NAME | 设置模式整体增益和名称 | 主机→设备 | 设置模式整体增益和名称 |
|
||||
| 0x8D | SET_EQ_PARAMS | 发送EQ参数 | 主机→设备 | 发送单个滤波器的参数 |
|
||||
| 0x8E | GET_EQ_PARAMS | 读取EQ参数 | 主机→设备 | 读取单个滤波器的参数 |
|
||||
| 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,开机时自动恢复 |
|
||||
| 0x93 | SET_VOLUME | 设置监听音量级别 | 主机→设备 | 设置设备监听音量级别(0=静音, 1-29=-28dB~0dB, 1dB/步) |
|
||||
| 0x94 | GET_VOLUME | 获取监听音量级别 | 主机→设备 | 读取设备当前监听音量级别(0=静音, 1-29=-28dB~0dB, 1dB/步) |
|
||||
| 0x9D | SET_EQ_ENABLE | 设置EQ使能开关 | 主机→设备 | 设置EQ使能开关(ON/OFF),禁用时保存当前模式,启用时恢复之前模式 |
|
||||
| 0x9E | GET_EQ_ENABLE | 获取EQ使能开关 | 主机→设备 | 读取EQ使能开关状态(ON/OFF) |
|
||||
| 0x9F | GET_SAMPLE_FORMAT | 获取采样率和格式 | 主机→设备 | 读取当前采样率、DSD模式和DAC采样分辨率 |
|
||||
| 0xA4 | SET_SOUND_EFFECT_MODE | 设置音效模式 | 主机→设备 | 设置音效模式(0=无音效,1=音乐模式,2=游戏模式,3=AI7.1模式) |
|
||||
| 0xA5 | GET_SOUND_EFFECT_MODE | 获取音效模式 | 主机→设备 | 读取当前音效模式(0-3) |
|
||||
| 0xA6 | GET_FIRMWARE_VERSION | 获取固件版本 | 主机→设备 | 读取设备固件版本号(BCD格式:主版本.次版本.修订版本) |
|
||||
| 0xA7 | FIRMWARE_UPGRADE_START | 开始固件升级 | 主机→设备 |
|
||||
| 0xA8 | FIRMWARE_UPGRADE_DATA | 传输固件数据块(固定57字节) | 主机→设备 |
|
||||
| 0xA9 | FIRMWARE_UPGRADE_END | 结束固件升级,验证镜像 | 主机→设备 |
|
||||
| 0xAA | FIRMWARE_UPGRADE_STATUS | 获取升级状态和进度 | 主机→设备 |
|
||||
| 0xAB | FIRMWARE_UPGRADE_ABORT | 中止固件升级 | 主机→设备 |
|
||||
| 0xAC | FIRMWARE_UPGRADE_ERASE | 擦除现有升级镜像 | 主机→设备 |
|
||||
| 0xAE | DEVICE_REBOOT | 设备重启(通用命令) | 主机→设备 |
|
||||
| 0xB0 | SET_EX3D_CMD | 发送EX3D命令 | 主机→设备 | 发送EX3D设置命令(封装所有EX3D SET命令) |
|
||||
| 0xB1 | GET_EX3D_CMD | 读取EX3D命令 | 主机→设备 | 读取EX3D参数(封装所有EX3D GET命令) |
|
||||
|
||||
### 1.3 数据包格式
|
||||
- **Report ID**: 0x01 (HID报告ID)
|
||||
- **数据包大小**: 64字节 (1字节Report ID + 63字节数据)
|
||||
- **同步头**: 0x77 (所有命令的第一个字节)
|
||||
- **字节序**: 小端序 (Little Endian)
|
||||
|
||||
## 2. 详细指令说明
|
||||
|
||||
### 2.0 0x82 - SET_MIC_VOLUME (设置麦克风增益级别)
|
||||
**功能**: 设置麦克风PGA增益级别
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x82 | 命令码
|
||||
2 | 1 | uint8 | 增益级别 (0=静音, 1-37=0dB~36dB, 1dB/步)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
- **增益级别范围:** 0-37(共38级)
|
||||
- 0:静音(mute)
|
||||
- 1:0dB(最小有效增益)
|
||||
- 2:1dB
|
||||
- ...(1dB/步)
|
||||
- 37:36dB(最大HID可设置增益)
|
||||
|
||||
**返回值**:
|
||||
无直接返回值。设备端增益变化会主动上报0x83格式数据包。
|
||||
|
||||
### 2.0b 0x83 - GET_MIC_VOLUME (获取麦克风增益级别)
|
||||
**功能**: 读取设备当前麦克风PGA增益级别;设备端增益变化时也会主动上报
|
||||
**方向**: 主机→设备(请求),设备→主机(响应/主动上报)
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x83 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**(含主动上报):
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x83 | 同步头2
|
||||
3 | 1 | uint8 | 当前增益级别 (0=静音, 1-37=0dB~36dB)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.0c 0x84 - FACTORY_RESET (恢复出厂默认设置)
|
||||
**功能**: 删除Flash中所有已保存的用户参数,设备重启后自动恢复出厂默认值
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x84 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**出厂默认参数**:
|
||||
| 参数 | 出厂默认值 | 说明 |
|
||||
|------|-----------|------|
|
||||
| AI7.1音效模式 | 3 (AI7.1开启) | 音效模式 0=无音效, 1=音乐, 2=游戏, 3=AI7.1 |
|
||||
| 脚步增强 | 12dB (全亮, 状态2) | LED全亮, 扩展增益12dB |
|
||||
| 麦克风音量 | 22 (21dB) | PGA寄存器值22 = 21dB |
|
||||
| 监听音量 | 15 (-14dB) | DAC level 15 = 0dB - 14 = -14dB |
|
||||
| EQ参数 | 头文件预设 | 删除所有用户EQ参数,恢复固件内置预设 |
|
||||
| AI降噪 | 开启 | 每次上电默认开启(不保存到Flash) |
|
||||
| 耳返开关 | 0 (关闭) | ADC→耳机监听通路默认关闭 |
|
||||
| 麦克风静音 | 0 (未静音) | 麦克风静音状态默认关闭 |
|
||||
| 监听静音 | 0 (未静音) | 耳机输出静音状态默认关闭 |
|
||||
|
||||
**设备端处理**:
|
||||
1. 删除Flash中保存的以下参数文件:
|
||||
- `game_mode`(音效模式)
|
||||
- `mic_vol`(麦克风音量)
|
||||
- `dac_vol`(监听音量)
|
||||
- `footstep`(脚步增强状态)
|
||||
- `monitor_sw`(耳返开关)
|
||||
- `mic_mute`(麦克风静音状态)
|
||||
- `hp_mute`(耳机静音状态)
|
||||
- 所有EQ参数文件(调用eq_flash_clear_all)
|
||||
2. 设置重启标志,约500ms后设备自动重启
|
||||
3. 重启后自动加载出厂默认参数
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x84 | 同步头2
|
||||
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**注意**:
|
||||
- 执行后设备将在约500ms后自动重启,USB连接会短暂断开后重连
|
||||
- 重启后所有参数将恢复为出厂默认值
|
||||
- 此操作不可撤销
|
||||
|
||||
### 2.0d 0x87 - SET_MONITOR_SWITCH (设置耳返开关)
|
||||
**功能**: 设置耳返(ADC→耳机监听)开关,控制是否将麦克风输入实时路由到耳机输出
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x87 | 命令码
|
||||
2 | 1 | uint8 | 开关值 (0=关闭, 1=开启)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
- **0**: 关闭耳返,ADC数据不路由到耳机输出(NAU88L21 reg 0x0035 = 0x0000)
|
||||
- **1**: 开启耳返,ADC数据路由到耳机输出(NAU88L21 reg 0x0035 = 0xCFCF,0dB监听音量)
|
||||
- **注意**: 耳返路由需要麦克风未静音(mic_mute=0)且麦克风增益有效(level≥2)方才生效
|
||||
|
||||
**设备端处理**:
|
||||
- 立即更新 NAU88L21 reg 0x0035(耳返音量寄存器)
|
||||
- 若麦克风当前处于静音状态,则无论耳返开关为何值,reg 0x0035保持0x0000
|
||||
- 保存到Flash(`monitor_sw`路径),断电重启后自动恢复
|
||||
- 设置成功后用0x88格式响应当前状态
|
||||
|
||||
**返回值**:
|
||||
设置成功后设备回复0x88格式响应。
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x88 | 同步头2
|
||||
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.0e 0x88 - GET_MONITOR_SWITCH (获取耳返开关状态)
|
||||
**功能**: 读取当前耳返开关状态
|
||||
**方向**: 主机→设备(请求),设备→主机(响应)
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x88 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x88 | 同步头2
|
||||
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.1 0x8A - SET_EQ_MODE (切换EQ模式)
|
||||
**功能**: 切换当前EQ模式
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x8A | 命令码
|
||||
2 | 1 | uint8 | 模式值 (0-9: 预设模式, 10-11: 用户模式)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
|
||||
## 2.2 0x8B - GET_EQ_MODE (读取EQ模式信息)
|
||||
**功能**: 读取EQ模式信息
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x8B | 命令码
|
||||
2 | 1 | uint8 | 模式值 (0-11: 有效模式值, 0xFF: 获取当前模式信息)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**设备端处理**:
|
||||
- 如果mode值为0xFF,返回当前模式值、整体增益和模式名称
|
||||
- 如果mode值为有效模式值(0-11),返回指定模式值、整体增益和模式名称
|
||||
|
||||
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x8B | 同步头2
|
||||
3 | 1 | uint8 | 模式值 (当前模式或指定模式)
|
||||
4-7 | 4 | int32 | 增益值 (范围0到-50dB,有符号整数)
|
||||
8-23 | 16 | char | 模式名称 (UTF-8编码,16字节)
|
||||
24-62 | 39 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**使用说明**:
|
||||
- 发送mode=0xFF时,返回当前激活的EQ模式信息
|
||||
- 发送mode=0-11时,返回指定模式的增益和名称信息(不切换当前模式)
|
||||
|
||||
### 2.3 0x8C - SET_MODE_GAIN_AND_NAME (设置模式整体增益和名称)
|
||||
**功能**: 设置EQ模式整体增益和名称
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x8C | 命令码
|
||||
2 | 1 | uint8 | 模式值 (0-11)
|
||||
3-6 | 4 | int32 | 增益值 (范围0到-50dB,有符号整数)
|
||||
7-22 | 16 | char | 模式名称 (UTF-8编码,16字节)
|
||||
23-62 | 40 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**使用场景**:
|
||||
- 需要为特定模式设置整体增益补偿和自定义名称
|
||||
- 自动应用到所有采样率以确保一致性
|
||||
|
||||
|
||||
### 2.4 0x8D - SET_EQ_PARAMS (发送EQ参数)
|
||||
**功能**: 发送单个滤波器的参数
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x8D | 命令码
|
||||
2 | 1 | uint8 | 模式值 (0-11)
|
||||
3 | 1 | uint8 | 滤波器Band索引 (0-7)
|
||||
4 | 1 | uint8 | 滤波器类型
|
||||
5-8 | 4 | float | 中心频率 (Hz)
|
||||
9-12 | 4 | float | Q值
|
||||
13-16 | 4 | float | 带宽 (Hz)
|
||||
17-20 | 4 | float | 增益 (dB)
|
||||
21-62 | 42 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**滤波器类型码**:
|
||||
| 类型码 | 滤波器类型 |
|
||||
|--------|------------|
|
||||
| 0x00 | bypass滤波器 |
|
||||
| 0x01 | 全通滤波器 |
|
||||
| 0x02 | 峰值滤波器 |
|
||||
| 0x03 | 低通滤波器 |
|
||||
| 0x04 | 高通滤波器 |
|
||||
| 0x09 | 低架滤波器 |
|
||||
| 0x0A | 高架滤波器 |
|
||||
|
||||
### 2.5 0x8E - GET_EQ_PARAMS (读取EQ参数)
|
||||
**功能**: 读取单个滤波器的参数
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x8E | 命令码
|
||||
2 | 1 | uint8 | 模式值 (0-11)
|
||||
3 | 1 | uint8 | EQ索引 (0-7)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x8E | 同步头2
|
||||
3 | 1 | uint8 | 模式值 (0-11)
|
||||
4 | 1 | uint8 | 滤波器Band索引 (0-7)
|
||||
5 | 1 | uint8 | 滤波器类型
|
||||
6-9 | 4 | float | 中心频率 (Hz)
|
||||
10-13 | 4 | float | Q值
|
||||
14-17 | 4 | float | 带宽 (Hz)
|
||||
18-21 | 4 | float | 增益 (dB)
|
||||
22-62 | 41 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.6 0x8F - GET_DEVICE_INFO (获取设备信息)
|
||||
**功能**: 获取设备基本信息
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x8F | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x8F | 同步头2
|
||||
3-4 | 2 | uint16 | 产品ID (PID)
|
||||
5-6 | 2 | uint16 | 厂商ID (VID)
|
||||
7-22 | 16 | char | 产品字符串 (UTF-8编码,16字节)
|
||||
23-38 | 16 | char | 厂商字符串 (UTF-8编码,16字节)
|
||||
39-54 | 16 | char | 序列号字符串 (UTF-8编码,16字节)
|
||||
55-62 | 8 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.7 0x90 - RESET_EQ_PARAMS (复位EQ参数)
|
||||
**功能**: 删除客户定制EQ参数并恢复预设参数
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x90 | 命令码
|
||||
2 | 1 | uint8 | 模式号 (0-11, 0xFF表示恢复所有包括EQ参数,总体增益,模式名称 )
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x90 | 同步头2
|
||||
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.8 0x91 - GET_EQ_MODE_COUNT (获取EQ模式总数)
|
||||
**功能**: 获取预定义加用户模式的总数(不包含禁用模式)
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x91 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x91 | 同步头2
|
||||
3 | 1 | uint8 | 模式总数 (当前为12,包含0-11共12个模式,不包含禁用模式)
|
||||
4 | 1 | uint8 | 预定义模式数量 (当前为10,包含0-9共10个预设模式)
|
||||
5-62 | 58 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.9 0x92 - SET_AND_SAVE_EQ_MODE (设置并保存EQ模式)
|
||||
**功能**: 设置当前EQ模式并保存到Flash,开机时自动恢复
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x92 | 命令码
|
||||
2 | 1 | uint8 | 模式值 (0-11: 0-9预设模式, 10-11用户模式)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**设备端处理**:
|
||||
- 将模式值保存到Flash
|
||||
- 开机时自动从Flash读取并恢复该模式
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x92 | 同步头2
|
||||
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.10 0x93 - SET_VOLUME (设置监听音量级别)
|
||||
**功能**: 设置设备监听(耳机/DAC)音量级别
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x93 | 命令码
|
||||
2 | 1 | uint8 | 音量级别 (0-29: 0=静音, 1=-28dB, ..., 29=0dB)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
- **音量级别范围:** 0-29(共30级)
|
||||
- **说明:** 控制设备监听输出(DAC/耳机)音量级别
|
||||
- 0: 静音(mute,DAC完全静音)
|
||||
- 1: -28dB(最小有效音量)
|
||||
- 2: -27dB
|
||||
- ...(每级1dB步进)
|
||||
- 29: 0dB(最大音量)
|
||||
|
||||
**返回值**:
|
||||
无直接返回值。如需确认音量是否设置成功,请使用GET_VOLUME命令读取当前音量。设备端音量变化(含编码器旋转引起的变化)会主动通过0x94格式上报。
|
||||
|
||||
### 2.11 0x94 - GET_VOLUME (获取监听音量级别)
|
||||
**功能**: 读取设备当前监听音量级别;设备端音量变化时也会主动上报此格式
|
||||
**方向**: 主机→设备(请求),设备→主机(响应/主动上报)
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x94 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**(含主动上报):
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x94 | 同步头2
|
||||
3 | 1 | uint8 | 当前音量级别 (0-29: 0=静音, 1-29=-28dB~0dB, 1dB/步)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
### 2.20 0x9D - SET_EQ_ENABLE (设置EQ使能开关)
|
||||
**功能**: 设置EQ使能开关(启用/禁用)
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x9D | 命令码
|
||||
2 | 1 | uint8 | EQ使能开关 (0=OFF禁用, 1=ON启用)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x9D | 同步头2
|
||||
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
|
||||
4 | 1 | uint8 | 当前EQ使能状态 (0=OFF, 1=ON)
|
||||
5-62 | 58 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.21 0x9E - GET_EQ_ENABLE (获取EQ使能开关)
|
||||
**功能**: 读取EQ使能开关状态
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x9E | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x9E | 同步头2
|
||||
3 | 1 | uint8 | EQ使能开关状态 (0=OFF禁用, 1=ON启用)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**设备端处理**:
|
||||
- 返回当前EQ使能开关状态(0=OFF, 1=ON)
|
||||
|
||||
|
||||
### 2.22 0x9F - GET_SAMPLE_FORMAT (获取采样率和格式)
|
||||
**功能**: 读取当前采样率和DSD模式
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0x9F | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x9F | 同步头2
|
||||
3-6 | 4 | uint32 | 采样率 (samFreq,小端序,单位:Hz)
|
||||
7 | 1 | uint8 | DSD模式 (dsdMode: 0=PCM, 1=DOP, 2=Native DSD)
|
||||
8-62 | 55 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**设备端处理**:
|
||||
- 返回当前采样率(32位无符号整数,小端序,单位:Hz)
|
||||
- 返回DSD模式(0表示PCM格式,>0表示DSD格式)
|
||||
- 设备会在采样率或DSD模式发生变化时自动上报此信息(通过HID状态报告)
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0x9E | 同步头2
|
||||
3 | 1 | uint8 | EQ使能开关状态 (0=OFF禁用, 1=ON启用)
|
||||
4 | 1 | uint8 | 保存的模式值 (0-9,如果之前有保存,0xFF表示未保存)
|
||||
5-62 | 58 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**设备端处理**:
|
||||
- 返回当前EQ使能开关状态
|
||||
- 返回之前保存的模式值(如果存在)
|
||||
|
||||
### 2.27 0xA4 - SET_SOUND_EFFECT_MODE (设置音效模式)
|
||||
**功能**: 设置音效模式
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0xA4 | 命令码
|
||||
2 | 1 | uint8 | 音效模式值 (0=无音效, 1=音乐模式, 2=游戏模式, 3=AI7.1模式)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
- **音效模式范围:** 0-3
|
||||
- **说明:** 选择音效模式,与硬件按键效果相同
|
||||
- 0: 无音效 — 所有模式按键灯灭,EQ算法关闭,EX3D算法关闭
|
||||
- 1: 音乐模式 — 音乐键灯亮,EQ算法开启,EX3D算法关闭
|
||||
- 2: 游戏模式 — 游戏键灯亮,EQ算法开启,EX3D游戏声场(SF=0)开启
|
||||
- 3: AI7.1模式 — AI7.1键灯亮,EQ算法开启,EX3D AI7.1声场(SF=1)开启
|
||||
|
||||
**返回值**:
|
||||
无直接返回值。如需确认音效模式是否设置成功,请使用GET_SOUND_EFFECT_MODE命令读取当前音效模式。
|
||||
|
||||
### 2.28 0xA5 - GET_SOUND_EFFECT_MODE (获取音效模式)
|
||||
**功能**: 读取设备当前音效模式
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0xA5 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0xA5 | 同步头2
|
||||
3 | 1 | uint8 | 当前音效模式 (0=无音效, 1=音乐模式, 2=游戏模式, 3=AI7.1模式)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.29 0xA6 - GET_FIRMWARE_VERSION (获取固件版本)
|
||||
**功能**: 读取设备固件版本号
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0xA6 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0xA6 | 同步头2
|
||||
3 | 1 | uint8 | 主版本号 (BCD格式,如0x01表示1)
|
||||
4 | 1 | uint8 | 次版本号 (BCD格式,如0x00表示0)
|
||||
5 | 1 | uint8 | 修订版本号 (BCD格式,如0x0C表示12)
|
||||
6-62 | 57 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**版本号格式说明**:
|
||||
- 版本号采用BCD(Binary Coded Decimal)格式
|
||||
- 3个字节分别表示:主版本号、次版本号、修订版本号
|
||||
- 例如:0x01 0x00 0x0C 表示版本 1.0.12
|
||||
|
||||
### 2.30 0xB0 - SET_EX3D_CMD (发送EX3D命令)
|
||||
**功能**: 发送EX3D设置命令,封装所有EX3D SET命令
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0xB0 | 命令码
|
||||
2-5 | 4 | uint32 | EX3D命令码(包含SET标志)
|
||||
6-9 | 4 | uint32 | 参数1(根据EX3D命令不同而不同)
|
||||
10-13 | 4 | uint32 | 参数2(根据EX3D命令不同而不同)
|
||||
14-17 | 4 | uint32 | 参数3(根据EX3D命令不同而不同)
|
||||
18-62 | 45 | 0x00 | 保留字节或扩展参数
|
||||
```
|
||||
|
||||
**EX3D命令码说明**:
|
||||
- 基础命令码范围: 0x80-0x94
|
||||
- SET命令格式: `基础命令码 & ~0x0100`(清除第9位)
|
||||
- 支持的SET命令:
|
||||
- 0x81: CMD_OPEN(打开EX3D)
|
||||
- 0x82: CMD_ONOFF(设置EX3D开关)
|
||||
- 0x83: CMD_ANGLE(设置角度)
|
||||
- 0x84: CMD_SOUND_FIELD(设置声场模式)
|
||||
- 0x85: CMD_MUTE(设置静音)
|
||||
- 0x86: CMD_ON_GAIN(设置开启增益)
|
||||
- 0x87: CMD_LMT_THRESHOLD(设置限制器阈值)
|
||||
- 0x88: CMD_UPMIX(设置上混)
|
||||
- 0x89: CMD_LFE(设置LFE增益)
|
||||
- 0x8A: CMD_OFF_GAIN(设置关闭增益)
|
||||
- 0x8E: CMD_LMT_ATTACKK_TIME(设置限制器攻击时间)
|
||||
- 0x8F: CMD_LMT_RELEASE_TIME(设置限制器释放时间)
|
||||
- 0x90: CMD_TEST_CANCEL(取消测试)
|
||||
- 0x91: CMD_TEST_STEP(测试步骤)
|
||||
- 0x92: CMD_TEST_ROTATE(测试旋转)
|
||||
- 0x93: CMD_EXPAND_GAIN(设置扩展增益)
|
||||
- 0x94: CMD_REDUCE_GAIN(设置减少增益)
|
||||
|
||||
**设备端处理**:
|
||||
- 解析EX3D命令码,提取基础命令码和参数
|
||||
- 根据命令类型执行相应的设置操作
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0xB0 | 同步头2
|
||||
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
|
||||
4-7 | 4 | uint32 | EX3D命令码(回显)
|
||||
8-11 | 4 | uint32 | 返回值(某些命令返回0xFFFFFFFF表示参数错误)
|
||||
12-62 | 51 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
### 2.31 0xB1 - GET_EX3D_CMD (读取EX3D命令)
|
||||
**功能**: 读取EX3D参数,封装所有EX3D GET命令
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0xB1 | 命令码
|
||||
2-5 | 4 | uint32 | EX3D命令码(包含GET标志)
|
||||
6-9 | 4 | uint32 | 参数1(根据EX3D命令不同而不同,如通道号、索引等)
|
||||
10-62 | 53 | 0x00 | 保留字节或扩展参数
|
||||
```
|
||||
|
||||
**EX3D命令码说明**:
|
||||
- 基础命令码范围: 0x80-0x94
|
||||
- GET命令格式: `基础命令码 | 0x0100`(设置第9位)
|
||||
- 支持的GET命令:
|
||||
- 0x180: CMD_CH_NUM(获取通道数量)
|
||||
- 0x182: CMD_ONOFF(获取EX3D开关)
|
||||
- 0x183: CMD_ANGLE(获取角度)
|
||||
- 0x184: CMD_SOUND_FIELD(获取声场模式)
|
||||
- 0x185: CMD_MUTE(获取静音)
|
||||
- 0x186: CMD_ON_GAIN(获取开启增益)
|
||||
- 0x187: CMD_LMT_THRESHOLD(获取限制器阈值)
|
||||
- 0x188: CMD_UPMIX(获取上混)
|
||||
- 0x189: CMD_LFE(获取LFE增益)
|
||||
- 0x18A: CMD_OFF_GAIN(获取关闭增益)
|
||||
- 0x18B: CMD_SOUND_FIELD_NUM(获取声场模式数量)
|
||||
- 0x18C: CMD_SOUND_FIELD_NAME(获取声场模式名称)
|
||||
- 0x18D: CMD_LEVEL(获取电平)
|
||||
- 0x18E: CMD_LMT_ATTACKK_TIME(获取限制器攻击时间)
|
||||
- 0x18F: CMD_LMT_RELEASE_TIME(获取限制器释放时间)
|
||||
- 0x193: CMD_EXPAND_GAIN(获取扩展增益)
|
||||
- 0x194: CMD_REDUCE_GAIN(获取减少增益)
|
||||
|
||||
**设备端处理**:
|
||||
- 解析EX3D命令码,提取基础命令码和参数
|
||||
- 调用相应的EX3D处理函数(hid_receive_task_in_c)
|
||||
- 返回当前参数值
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0xB1 | 同步头2
|
||||
3-6 | 4 | uint32 | EX3D命令码(回显)
|
||||
7-10 | 4 | uint32 | 返回值1(根据命令不同而不同)
|
||||
11-14 | 4 | uint32 | 返回值2(某些命令需要多个返回值,如角度、多通道数据等)
|
||||
15-18 | 4 | uint32 | 返回值3(扩展返回值,如多通道数据)
|
||||
... | ... | ... | 其他返回值(最多可返回14个uint32值,总长度不超过63字节)
|
||||
```
|
||||
|
||||
**返回值说明**:
|
||||
- 返回值数量和格式取决于具体的EX3D命令
|
||||
- 单值命令:返回1个uint32值
|
||||
- 多值命令(如角度、多通道数据):返回多个uint32值
|
||||
- 字符串命令(如声场名称):先返回长度(uint32),然后返回字符串数据
|
||||
- 详细的返回值格式请参考ex3d_protocol.md文档
|
||||
|
||||
**使用说明**:
|
||||
- 该命令用于统一封装所有EX3D读取命令
|
||||
- 参数格式与原始EX3D协议保持一致
|
||||
- 详细的EX3D命令说明请参考ex3d_protocol.md文档
|
||||
|
||||
|
||||
## 5. 关键特性
|
||||
|
||||
### 5.1 设备端系数计算
|
||||
- 主机只发送参数 (fc, Q, bw, gain)
|
||||
- 设备端根据参数实时计算滤波器系数
|
||||
|
||||
### 5.2 参数格式
|
||||
- **浮点参数**: fc, Q, bw, gain 使用IEEE 754 float格式传输
|
||||
- **字节序**: 所有多字节数据使用小端序
|
||||
|
||||
### 5.3 错误处理
|
||||
- 数据包长度检查
|
||||
- 同步头验证
|
||||
- 参数范围检查
|
||||
- 滤波器索引边界检查
|
||||
|
||||
### 5.4 模式管理
|
||||
- 支持12个EQ模式 (0-11: 0-9预设模式, 10,11, 用户模式)
|
||||
- 模式切换时自动清除滤波器状态
|
||||
|
||||
## 7. 注意事项
|
||||
|
||||
1. **时序要求**: 发送参数后需要等待设备处理完成再发送下一条命令
|
||||
2. **数据完整性**: 所有8个滤波器的参数都需要发送,即使某些滤波器未使用
|
||||
3. **模式同步**: 设置模式后需要调用读取模式确保数据同步
|
||||
4. **错误恢复**: 通信失败时需要重新建立连接并重试
|
||||
5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制
|
||||
|
||||
---
|
||||
|
||||
## 8. 固件升级命令 (0xA7–0xAE)
|
||||
|
||||
本节定义通过HID进行固件升级的命令。最大数据块57字节,Flash页256字节,字节序小端序。
|
||||
|
||||
### 8.1 固件升级命令列表
|
||||
|
||||
### 8.2 0xA7 - FIRMWARE_UPGRADE_START
|
||||
|
||||
**请求**:
|
||||
```
|
||||
字节 0: 0x77 同步头
|
||||
字节 1: 0xA7 命令码
|
||||
字节 2-5: uint32 固件大小(字节,小端序)
|
||||
字节 6-62: 0x00 保留
|
||||
```
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA7
|
||||
字节 2: 状态码 (0x00=成功, 0x01=失败, 0x03=大小无效)
|
||||
字节 3-6: uint32 页对齐后的实际大小
|
||||
字节 7-8: uint16 总块数
|
||||
字节 9-62: 0x00
|
||||
```
|
||||
|
||||
### 8.3 0xA8 - FIRMWARE_UPGRADE_DATA
|
||||
|
||||
**请求**(数据块固定57字节,不足补0):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA8
|
||||
字节 2-3: uint16 块序号(从0开始,小端序)
|
||||
字节 4: uint8 数据长度(固定57)
|
||||
字节 5-61: uint8[57] 固件数据
|
||||
字节 62: uint8 Checksum(字节0-61累加 mod 256)
|
||||
```
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA8
|
||||
字节 2: 状态码 (0x00=成功, 0x04=块号错误, 0x05=Checksum错误)
|
||||
字节 3-4: uint16 已确认块序号
|
||||
字节 5-62: 0x00
|
||||
```
|
||||
|
||||
### 8.4 0xA9 - FIRMWARE_UPGRADE_END
|
||||
|
||||
**请求**:
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA9
|
||||
字节 2-5: uint32 固件总大小(用于验证)
|
||||
字节 6-62: 0x00
|
||||
```
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xA9
|
||||
字节 2: 状态码 (0x00=成功, 0x01=失败)
|
||||
字节 3-62: 0x00
|
||||
```
|
||||
|
||||
### 8.5 0xAA - FIRMWARE_UPGRADE_STATUS
|
||||
|
||||
**请求**: 字节0=0x77, 字节1=0xAA, 其余0x00
|
||||
|
||||
**响应**(主动上报):
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xAA
|
||||
字节 2: 升级状态 (0=空闲, 1=准备中, 2=传输中, 3=完成中, 4=已完成, 5=错误, 6=已中止)
|
||||
字节 3-4: uint16 已接收块数
|
||||
字节 5-6: uint16 总块数
|
||||
字节 7-8: uint16 已写页数
|
||||
字节 9-10: uint16 总页数
|
||||
字节 11-14: uint32 已传输字节数
|
||||
字节 15-18: uint32 总字节数
|
||||
字节 19: 错误码
|
||||
字节 20-62: 0x00
|
||||
```
|
||||
|
||||
### 8.6 0xAB - FIRMWARE_UPGRADE_ABORT
|
||||
|
||||
**请求**:
|
||||
```
|
||||
字节 0: 0x77
|
||||
字节 1: 0xAB
|
||||
字节 2: 清理标志 (0x00=保留数据, 0x01=擦除数据)
|
||||
字节 3-62: 0x00
|
||||
```
|
||||
|
||||
**响应**(主动上报): 字节0=0x77, 字节1=0xAB, 字节2=状态码(0x00=成功)
|
||||
|
||||
### 8.7 0xAC - FIRMWARE_UPGRADE_ERASE
|
||||
|
||||
**请求**: 字节0=0x77, 字节1=0xAC, 其余0x00
|
||||
|
||||
**响应**(主动上报): 字节0=0x77, 字节1=0xAC, 字节2=状态码(0x00=成功)
|
||||
|
||||
### 8.8 0xAE - DEVICE_REBOOT
|
||||
|
||||
**请求**: 字节0=0x77, 字节1=0xAE, 其余0x00
|
||||
|
||||
**响应**: 无响应,设备立即重启。
|
||||
|
||||
### 8.9 标准升级流程
|
||||
|
||||
```
|
||||
1. (可选) ERASE — 擦除现有upgrade image
|
||||
2. START — 设置固件大小,等待响应(SUCCESS)
|
||||
3. 循环 DATA — 逐块发送,每块等待响应确认
|
||||
4. END — 完成写入,等待响应(SUCCESS)
|
||||
5. REBOOT — 重启加载新固件
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user