From db328853d1e5184edb843adb7fb467dbe2c186df Mon Sep 17 00:00:00 2001 From: Steven Dan Date: Wed, 13 May 2026 18:19:22 +0800 Subject: [PATCH] udpate button and leds --- .../src/extensions/audiohw.xc | 331 +++++++++++++----- .../src/extensions/user_main.h | 6 +- 2 files changed, 244 insertions(+), 93 deletions(-) diff --git a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc index 974487d..60d623d 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc +++ b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc @@ -83,7 +83,7 @@ on tile[0]: port p_sda = PORT_I2C_SDA; on tile[0]: in port p_button = XS1_PORT_8D; //bit 4: mode button, bit 5: volume down button, bit 6: mic mute button, bit 7: volume up button on tile[1]: out port p_mode_led_red = XS1_PORT_1F; -on tile[1]: out port p_leds = XS1_PORT_4D; //bit 0: mode led green, bit 1: mode led blue, bit 2: mic mute led red, bit 3: volume up led green +on tile[1]: out port p_leds = XS1_PORT_4D; //bit 0: mode led green, bit 1: mode led blue, bit 2: mic mute led red, bit 3: mic mute led green on tile[1]: out port p_mic_mute_led_blue = XS1_PORT_1G; timer tm; @@ -111,13 +111,17 @@ timer tm; // 改动原因:C1的TIMER_PERIOD为20ms,按DS1同类短按/长按模型换算阈值;mode/mic 仍用 LONG 区分短按窗口;音量键已取消长按连调故不再使用 REPEAT 间隔宏。 #define C1_KEY_SHORT_TICKS 1 #define C1_KEY_LONG_TICKS 50 +// 改动原因:规格要求 mic 键长按 1.5s 触发 AI 通话降噪开关;20ms*75=1.5s,与 mode 键的 C1_KEY_LONG_TICKS(1s) 解耦,避免误触。 +#define C1_KEY_MIC_AI_NR_TICKS 75 +// 改动原因:双击第二下需在首击释放后约 500ms 内按下,否则判为单击静音;20ms*25=500ms。 +#define C1_MIC_DOUBLE_DEFER_TICKS 25 // 改动原因:新增C1模式持久化文件路径,使用LittleFS保存mode按键状态,保证断电重启后可恢复。 #define C1_MODE_VALUE_PATH "c1_mode_value" -// 改动原因:新增mode默认值与有效范围常量,集中定义便于维护并确保Flash异常时能回退到安全默认值。 -#define C1_MODE_VALUE_DEFAULT 0 -#define C1_MODE_VALUE_MIN 0 -#define C1_MODE_VALUE_MAX 1 +// 改动原因:c1_mode 与 tile1 mode 灯索引一致:1=灭 2=蓝 3=绿 4=橙 5=紫;合法范围 1~5,interface 原样传 c1_mode。 +#define C1_MODE_VALUE_DEFAULT 1 +#define C1_MODE_VALUE_MIN 1 +#define C1_MODE_VALUE_MAX 5 // 改动原因:DAC 音量单独持久化路径,与 mode 的 c1_mode 文件分离,避免互相覆盖且便于维护。 #define C1_DAC_VOL_INFO_PATH "c1_dac_vol" @@ -132,6 +136,8 @@ timer tm; // 改动原因:TIMER_PERIOD≈20ms,连续 3 次采样一致再认定电平稳定,避免检测脚抖动误触发。 #define C1_JACK_DEBOUNCE_SAMPLES 3u +extern void device_reboot(void); + // 改动原因:判断 Flash 读出字节是否为合法 NAU88C22 DAC 音量码:0x00 表示按键规则下的 mute,0x4B~0xCF 为正常衰减范围。 static unsigned c1_saved_dac_vol_is_valid(unsigned char v) { @@ -142,11 +148,72 @@ static unsigned c1_saved_dac_vol_is_valid(unsigned char v) return 0; } -// 改动原因:mode值与面板LED颜色索引不是同一编码,封装转换避免业务代码散落魔数映射关系。 -static inline unsigned c1_mode_to_led_color_idx(unsigned mode_value) +// 改动原因:灯索引与 c1_mode 同值;仅钳位非法 Flash 读数,合法值原样下发 tile1,避免误映射。 +static inline unsigned c1_mode_to_tile_mode_led_code(unsigned mode_value) { - // 改动原因:需求定义0=蓝灯、1=绿灯;现有LED接口约定2=蓝灯、1=绿灯,因此做显式转换。 - return (mode_value == 0) ? 2 : 1; + if (mode_value > C1_MODE_VALUE_MAX || mode_value < C1_MODE_VALUE_MIN) + return C1_MODE_VALUE_DEFAULT; + return mode_value; +} + +void switch_mode_by_c1_mode(unsigned c1_mode, unsigned force_reboot) +{ + unsigned reboot_need = 0; +#if UAC1_MODE == 0 + switch (c1_mode) + { + case 1: + SetRoleSwitchFlag(MODE_FPS_UAC2); + reboot_need = 0; + break; + case 2: + SetRoleSwitchFlag(MODE_BR_UAC2); + reboot_need = 1; + break; + case 3: + SetRoleSwitchFlag(MODE_V71_UAC2); + reboot_need = 1; + break; + case 4: + SetRoleSwitchFlag(MODE_FPS_UAC2); + reboot_need = 1; + break; + case 5: + SetRoleSwitchFlag(MODE_FPS_UAC2); + reboot_need = 0; + break; + } +#else + switch (c1_mode) + { + case 1: + SetRoleSwitchFlag(MODE_FPS_UAC1); + reboot_need = 0; + break; + case 2: + SetRoleSwitchFlag(MODE_V71_UAC1); + reboot_need = 1; + break; + case 3: + SetRoleSwitchFlag(MODE_V71_UAC1); + reboot_need = 0; + break; + case 4: + SetRoleSwitchFlag(MODE_FPS_UAC1); + reboot_need = 1; + break; + case 5: + SetRoleSwitchFlag(MODE_FPS_UAC1); + reboot_need = 0; + break; + } +#endif + if (reboot_need || force_reboot) + { + delay_milliseconds(20); + device_reboot(); + while (1); + } } #define NAU88L21_PGA_GAIN_REG_MIN_USED_VALUE 0x0 // 0x1=1, 0dB (0x0, -1dB which is not used in this design) @@ -436,6 +503,13 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli unsigned vol_down_press_ticks = 0; unsigned mic_mute_press_ticks = 0; unsigned vol_up_press_ticks = 0; + // 改动原因:mic 键双击需延迟首轮短按的静音动作,用 stage1=等超时单击 / stage2=已收到第二下按下等释放;与长按 AI 互斥靠 mic_ai_long_fired。 + unsigned mic_dbl_stage = 0; + unsigned mic_defer_left = 0; + unsigned mic_ai_long_fired = 0; + // 改动原因:变声/美声仅按键+灯,tile0 保存状态供下发橙色 mode 区;AI 降噪无灯仅本地翻转供后续扩展。 + unsigned c1_mic_voice_fx = 0; + unsigned c1_mic_ai_nr = 0; // 改动原因:mic mute红灯通过interface下发到tile1,仅在状态变化时发送,减少无意义跨tile调用。 unsigned last_mute_switch_for_led = 0xFFFFFFFF; unsigned host_os = 0; @@ -453,14 +527,13 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli firmware_upgrade_init(); #endif - if (c1_mode > 4) + if (c1_mode > C1_MODE_VALUE_MAX || c1_mode < C1_MODE_VALUE_MIN) { - c1_mode = 0; + c1_mode = C1_MODE_VALUE_DEFAULT; save_value(C1_MODE_INFO_PATH, c1_mode); } - #if defined(WIN_OS_DETECTION) for(int i = 0; i < 500; i++) { @@ -474,35 +547,11 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli if (host_os == OS_WIN) { debug_printf("Detected Windows OS (OS_WIN) c1_mode: %d\n", c1_mode); - unsigned flag = 1; - switch (c1_mode) - { - case 1: - flag = MODE_FPS_UAC2; - break; - case 3: - flag = MODE_BR_UAC2; - break; - case 4: - flag = MODE_V71_UAC2; - break; - } - SetRoleSwitchFlag(flag); -#ifndef DISABLE_REBOOT - device_reboot(); - while (1); -#endif + switch_mode_by_c1_mode(c1_mode, 1); } else { - if (c1_mode == 5) - { - SetRoleSwitchFlag(MODE_V71_UAC1); -#ifndef DISABLE_REBOOT - device_reboot(); - while (1); -#endif - } + switch_mode_by_c1_mode(c1_mode, 0); } #endif @@ -522,8 +571,14 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli dac_vol_persist_deadline = 0; } - // 改动原因:开机后立即按Flash恢复的mode值设置面板灯色,避免首次按键前灯态与保存状态不一致。 - i_c1_led_ctrl.set_mode_led_color(c1_mode_to_led_color_idx(c1_mode)); + // 改动原因:tile1 上电已硬件全灭;先下发当前 g_mute_switch 再下发 Flash 中的 c1_mode,使首帧 apply 时 mic 已正确,避免仅 set_mode 时用占位 mic 闪错 mute 灯。 + unsigned init_mute_for_led; + GET_SHARED_GLOBAL(init_mute_for_led, g_mute_switch); + i_c1_led_ctrl.set_mic_mute_state(init_mute_for_led); + i_c1_led_ctrl.set_mode_led_color(c1_mode_to_tile_mode_led_code(c1_mode)); + // 改动原因:上电默认关闭变声灯效覆盖,避免未初始化随机亮橙。 + i_c1_led_ctrl.set_mic_voice_fx(0); + last_mute_switch_for_led = init_mute_for_led; while(1) { @@ -763,8 +818,46 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli vol_up_pressed = ((button_state & C1_KEY_VOL_UP_MASK) == 0); pressed_count = mode_pressed + vol_down_pressed + mic_mute_pressed + vol_up_pressed; + // 改动原因:mic 首击短按后延迟 500ms 再静音,以便识别双击;仅 mic 松开时递减 mic_defer_left,到 0 执行单击静音。 + if (mic_dbl_stage == 1 && mic_defer_left > 0) + { + unsigned mic_released_now = ((button_state & C1_KEY_MIC_MUTE_MASK) != 0); + if (mic_released_now) + { + mic_defer_left--; + if (mic_defer_left == 0) + { + unsigned current_mute_switch; + unsigned effective_adc_vol; + GET_SHARED_GLOBAL(effective_adc_vol, g_adc_vol); + GET_SHARED_GLOBAL(current_mute_switch, g_mute_switch); + current_mute_switch = (current_mute_switch == 0) ? 1 : 0; + + if (current_mute_switch == 0) + { + mic_volume(0, i2c); + } + else + { + mic_volume(effective_adc_vol, i2c); + } + SET_SHARED_GLOBAL(g_mute_switch, current_mute_switch); + i_c1_led_ctrl.set_mic_mute_state(current_mute_switch); + last_mute_switch_for_led = current_mute_switch; + debug_printf("C1 key mic mute toggle (deferred single): %d\n", current_mute_switch); + mic_dbl_stage = 0; + } + } + } + if (pressed_count == 1) { + // 改动原因:mic 双击等待期间若用户去按 mode/音量键,应取消延迟单击静音,避免误切 g_mute_switch。 + if (!mic_mute_pressed) + { + mic_dbl_stage = 0; + mic_defer_left = 0; + } if (mode_pressed) { mode_press_ticks++; @@ -783,6 +876,12 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli } else if (mic_mute_pressed) { + // 改动原因:双击窗口内第二下按下,取消延迟单击静音,改为等待释放后判双击变声。 + if (mic_dbl_stage == 1) + { + mic_defer_left = 0; + mic_dbl_stage = 2; + } mic_mute_press_ticks++; // 改动原因:同一时刻只允许mic mute键生效,清除其它键状态,避免释放时误执行音量或mode短按。 mode_press_ticks = 0; @@ -802,18 +901,18 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli { if (pressed_count == 0) { - // 改动原因:mode短按改为0/1切换并持久化到Flash,满足0=蓝灯、1=绿灯以及重启恢复需求。 + // 改动原因:mode 短按在 c1_mode 1~5 间循环,灯索引与 mode 同值;持久化后切角色并 set_mode_led_color(c1_mode) 下发 tile1(无重启路径必须调用否则灯不更新)。 if ((mode_press_ticks >= C1_KEY_SHORT_TICKS) && (mode_press_ticks < C1_KEY_LONG_TICKS)) { - unsigned flag; - c1_mode = (c1_mode == 0) ? 1 : 0; + c1_mode ++; + if (c1_mode > C1_MODE_VALUE_MAX) + { + c1_mode = C1_MODE_VALUE_MIN; + } save_value(C1_MODE_INFO_PATH, c1_mode); - flag = c1_mode == 1 ? USB_IN_FLAG : COAX_IN_FLAG; - SetRoleSwitchFlag(flag); - delay_milliseconds(1); - device_reboot(); - while(1); + switch_mode_by_c1_mode(c1_mode, 0); + i_c1_led_ctrl.set_mode_led_color(c1_mode_to_tile_mode_led_code(c1_mode)); } // 改动原因:音量键仅短按——释放时若已满足去抖时长则步进一档,与按住时长无关(已取消长按连调)。 @@ -840,28 +939,34 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli } } - // 改动原因:mic mute短按直接切换g_mute_switch,复用现有HID变化上报和effective_adc_vol静音路径。 - if ((mic_mute_press_ticks >= C1_KEY_SHORT_TICKS) && (mic_mute_press_ticks < C1_KEY_LONG_TICKS)) + // 改动原因:mic:短按静音改为延迟单击(防双击);双击短按切变声灯(橙R+G);按住满1.5s仅切 AI 状态变量无灯;长按与短/双互斥。 { - unsigned current_mute_switch; - unsigned effective_adc_vol; - GET_SHARED_GLOBAL(effective_adc_vol, g_adc_vol); - GET_SHARED_GLOBAL(current_mute_switch, g_mute_switch); - current_mute_switch = (current_mute_switch == 0) ? 1 : 0; - - if (current_mute_switch == 0) + unsigned mic_snap = mic_mute_press_ticks; + if (mic_snap > 0) { - mic_volume(0, i2c); + if ((mic_snap >= C1_KEY_MIC_AI_NR_TICKS) || mic_ai_long_fired) + { + if (mic_dbl_stage == 2) + mic_dbl_stage = 0; + } + else if ((mic_snap >= C1_KEY_SHORT_TICKS) && (mic_snap < C1_KEY_MIC_AI_NR_TICKS)) + { + if (mic_dbl_stage == 2) + { + c1_mic_voice_fx = (c1_mic_voice_fx ? 0 : 1); + i_c1_led_ctrl.set_mic_voice_fx(c1_mic_voice_fx); + mic_dbl_stage = 0; + mic_defer_left = 0; + debug_printf("C1 mic voice/beautifier toggle: %d\n", c1_mic_voice_fx); + } + else + { + mic_dbl_stage = 1; + mic_defer_left = C1_MIC_DOUBLE_DEFER_TICKS; + } + } + mic_ai_long_fired = 0; } - else - { - mic_volume(effective_adc_vol, i2c); - } - SET_SHARED_GLOBAL(g_mute_switch, current_mute_switch); - // 改动原因:按键切换mic mute后立即通知tile1刷新红灯,避免等待下一轮状态同步出现可见延迟。 - i_c1_led_ctrl.set_mic_mute_state(current_mute_switch); - last_mute_switch_for_led = current_mute_switch; - debug_printf("C1 key mic mute toggle: %d\n", current_mute_switch); } // 改动原因:音量键仅短按——释放时若已满足去抖时长则步进一档(已取消长按连调)。 @@ -888,6 +993,12 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli } } } + else if (pressed_count > 1) + { + // 改动原因:多键同按时取消 mic 双击等待,避免组合键松手后误触发延迟静音。 + mic_dbl_stage = 0; + mic_defer_left = 0; + } // 改动原因:多键同时按下不映射功能,立即清除本轮计时,避免组合键抖动误触发单键动作。 mode_press_ticks = 0; @@ -1779,29 +1890,60 @@ void send_eq_data(uint8_t data[]) } } -// 改动原因:封装tile1前面板LED刷新,统一执行mode灯R/G/B轮转与mic mute红灯显示策略,避免多处直接写端口造成覆盖。 -static inline void apply_c1_panel_leds(unsigned mode_led_color_idx, unsigned mic_mute_switch, unsigned &led_shadow) +// 改动原因:tile1 上电瞬间尚未收到 tile0 的 mode/mic,先把 mode 红脚与 PORT_4D 各 bit 拉到熄灭电平(低有效灯:输出 1 为灭),与 apply 中无混色时 mode 红通道熄灭写法一致。 +static inline void c1_panel_leds_force_all_off_hw(void) +{ + p_mode_led_red <: 1; + p_leds <: 0xF; + p_mic_mute_led_blue <: 1; +} + +// 改动原因:c1_mode 与灯索引一致:1=灭 2=蓝 3=绿 4=橙(R+G) 5=紫(R+B);仅驱动 mode 区(p_mode_led_red + p_leds bit0/1),不受 mic 变声影响。 +// mic_voice_fx_on:规格变声/美声橙灯在 mic 区——p_leds bit2 红 + bit3 绿同时点亮;关变声时 mic 区仅由静音决定 bit2,bit3 熄灭。 +static inline void apply_c1_panel_leds(unsigned mode_led_color_idx, unsigned mic_mute_switch, unsigned mic_voice_fx_on, unsigned &led_shadow) { unsigned mode_red = 0; unsigned mode_green = 0; unsigned mode_blue = 0; - unsigned mic_red = (mic_mute_switch == 1) ? 1 : 0; - - if (mode_led_color_idx == 0) { - mode_red = 1; - } else if (mode_led_color_idx == 1) { - mode_green = 1; - } else if (mode_led_color_idx == 2) { - mode_blue = 1; + // 改动原因:与 user_main.h 约定一致——mic_mute_switch 存的是“非静音=1、静音=0”,静音时 mic 红灯(bit2)亮。 + unsigned mic_red = 0; + unsigned mic_green = 0; + if (mic_voice_fx_on) { + // 改动原因:变声开为橙=R+G,映射到 XS1_PORT_4D 的 mic 专用 bit2/bit3,不占用 mode 的 bit0/bit1。 + mic_red = 1; + mic_green = 1; + } else { + mic_red = (mic_mute_switch == 0) ? 1 : 0; + mic_green = 0; } - // 改动原因:硬件LED为低电平点亮(1灭/0亮),因此把逻辑亮灭状态反相后再写端口。 + if (mode_led_color_idx == 1) { + mode_red = 0; + mode_green = 0; + mode_blue = 0; + } else if (mode_led_color_idx == 2) { + mode_blue = 1; + } else if (mode_led_color_idx == 3) { + mode_green = 1; + } else if (mode_led_color_idx == 4) { + mode_red = 1; + mode_green = 1; + } else if (mode_led_color_idx == 5) { + mode_red = 1; + mode_blue = 1; + } else { + mode_red = 0; + mode_green = 0; + mode_blue = 0; + } + + // 改动原因:硬件LED为低电平点亮(1灭/0亮);低四位 bit0~3 分别为 mode绿、mode蓝、mic红、mic绿,统一刷新避免旧代码固定 |=0x8 导致 bit3 永灭。 p_mode_led_red <: (mode_red ? 0 : 1); - led_shadow &= ~0x7; + led_shadow &= ~0xF; led_shadow |= (mode_green ? 0x0 : 0x1); led_shadow |= (mode_blue ? 0x0 : 0x2); led_shadow |= (mic_red ? 0x0 : 0x4); - led_shadow |= 0x8; + led_shadow |= (mic_green ? 0x0 : 0x8); p_leds <: led_shadow; // 改动原因:该蓝灯当前不参与功能,保持熄灭(低电平有效下输出1表示灭)。 p_mic_mute_led_blue <: 1; @@ -1809,16 +1951,14 @@ static inline void apply_c1_panel_leds(unsigned mode_led_color_idx, unsigned mic void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl, chanend c_eq_data) { - // 改动原因:LED端口在tile1,统一用shadow变量管理输出位,避免不同逻辑直接写端口互相覆盖。 - // 改动原因:低电平点亮,初始化全灭应写1;bit0/1/2默认置1表示G/B/红灯都灭。 - unsigned led_shadow = 0x7; - unsigned mode_led_color_idx = 0xFFFFFFFF; // 0=R,1=G,2=B, 0xFFFFFFFF=未点亮 - unsigned mic_mute_switch = 1; // 0=静音(亮红),1=非静音(灭红) - p_mode_led_red <: 0; - p_mic_mute_led_blue <: 1; - p_leds <: led_shadow; + // 改动原因:tile1 先于 tile0 运行,上电先把硬件灯全灭且不调用 apply,避免用占位 mic/mode 组合误亮;shadow 置为全灭电平便于首包 set_* 时 apply 与端口一致。 + unsigned led_shadow = 0xF; + unsigned mode_led_color_idx = 1; + unsigned mic_mute_switch = 1; + // 改动原因:变声/美声开时仅 p_leds bit2/bit3 显橙,与 set_mode_led_color 下发的 mode 灯独立;此处状态与 tile0 set_mic_voice_fx 同步。 + unsigned mic_voice_fx_on = 0; + c1_panel_leds_force_all_off_hw(); - apply_c1_panel_leds(mode_led_color_idx, mic_mute_switch, led_shadow); unsigned eq_mode_time = 0; timer eq_mode_timer; eq_mode_timer :> eq_mode_time; @@ -1835,12 +1975,19 @@ void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl, chanend c_ unsafe { select{ case i_c1_led_ctrl.set_mode_led_color(unsigned color_idx): - mode_led_color_idx = color_idx % 3; - apply_c1_panel_leds(mode_led_color_idx, mic_mute_switch, led_shadow); + // 改动原因:color_idx 与 c1_mode 同值 1~5;越界时钳位为默认灯码,避免未定义索引。 + mode_led_color_idx = color_idx; + if (mode_led_color_idx > 5 || mode_led_color_idx < 1) + mode_led_color_idx = C1_MODE_VALUE_DEFAULT; + apply_c1_panel_leds(mode_led_color_idx, mic_mute_switch, mic_voice_fx_on, led_shadow); break; case i_c1_led_ctrl.set_mic_mute_state(unsigned mute_state): mic_mute_switch = (mute_state != 0) ? 1 : 0; - apply_c1_panel_leds(mode_led_color_idx, mic_mute_switch, led_shadow); + apply_c1_panel_leds(mode_led_color_idx, mic_mute_switch, mic_voice_fx_on, led_shadow); + break; + case i_c1_led_ctrl.set_mic_voice_fx(unsigned voice_fx_enabled): + mic_voice_fx_on = (voice_fx_enabled != 0) ? 1 : 0; + apply_c1_panel_leds(mode_led_color_idx, mic_mute_switch, mic_voice_fx_on, led_shadow); break; } } diff --git a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/user_main.h b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/user_main.h index b60d35b..8d8fc9e 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/user_main.h +++ b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/user_main.h @@ -8,8 +8,12 @@ #include "app_dsp.h" // 改动原因:mode/mic mute LED物理端口在tile1,定义跨tile的LED控制interface,供tile0按键逻辑调用,tile1统一驱动硬件LED。 interface c1_led_ctrl_if { - void set_mode_led_color(unsigned color_idx); // 0=R, 1=G, 2=B + // 改动原因:与 c1_mode 同值下发 tile1:1=灭 2=蓝 3=绿 4=橙 5=紫(灯索引即 mode)。 + void set_mode_led_color(unsigned color_idx); void set_mic_mute_state(unsigned mute_switch); // mute_switch: 0=静音(亮红), 1=非静音(灭红) + // 改动原因:麦克风键双击“变声/美声”仅改灯效时,在 tile1 点亮 p_leds 的 mic 区:非0=bit2 红 + bit3 绿(橙),0=仅按静音规则驱动 bit2、bit3 熄灭。 + // 改动原因:参数名不能用 xC 保留字 on(on tile[:]: 语法),否则编译器在解析 interface 时报 parse error before "on"。 + void set_mic_voice_fx(unsigned voice_fx_enabled); }; void switch_handler(void); void flag_handler();