diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/core/xu316_qf60.xn b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/core/xu316_qf60.xn index 88013e0..21eb2f4 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/core/xu316_qf60.xn +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/core/xu316_qf60.xn @@ -42,13 +42,15 @@ - - - - - - + + + + + + + + diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc index 922325a..5be05df 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc @@ -13,6 +13,7 @@ #include #include "debug_print.h" #include "user_uart.h" +#include "htr3236.h" #include "eq_flash_storage.h" #include "lfs_io.h" #include "roleswitchflag.h" @@ -97,172 +98,73 @@ unsigned g_request_factory_reset = 0; // CODEC I2C lines on tile[0]: port p_scl = PORT_I2C_SCL; 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: mic mute led green -on tile[1]: out port p_mic_mute_led_blue = XS1_PORT_1G; +// TX1 Button ports (from Portmap_TX1.xls) +on tile[0]: in port p_button_fps_game_mic = XS1_PORT_4F; // bit3=FPS, bit2=GAME, bit1=MIC_MUTE +on tile[0]: in port p_button_vol = XS1_PORT_4E; // bit3=VOL+, bit2=VOL- + +// TX1 GPIO LEDs on tile[0] +on tile[0]: out port p_led_tile0 = XS1_PORT_8D; // bit7=D10_GREEN, bit6=D8_GREEN, bit5=D11_BLUE, bit4=D9_BLUE + +// TX1 GPIO LEDs on tile[1] - declared in tx1_led_helper.xc + +// TX1 HTR3236 RGB LED driver control - declared in tx1_led_helper.xc + +// TX1 Button bit masks +#define TX1_BIT_FPS_MODE (1<<3) // 4F bit3 +#define TX1_BIT_GAME_MODE (1<<2) // 4F bit2 +#define TX1_BIT_MIC_MUTE (1<<1) // 4F bit1 +#define TX1_BIT_VOL_PLUS (1<<3) // 4E bit3 +#define TX1_BIT_VOL_MINUS (1<<2) // 4E bit2 + +// TX1 Button timing thresholds (in 50ms ticks) +#define TX1_SHORT_PRESS_TICKS 1 // 50ms minimum press +#define TX1_LONG_PRESS_TICKS 20 // 1s = 20 * 50ms +#define TX1_FACTORY_RESET_TICKS 212 // 10.6s = 212 * 50ms + +// TX1 LED bit masks for tile[0] (XS1_PORT_8D bits 7-4) +#define TX1_LED_D10_GREEN_BIT 7 +#define TX1_LED_D8_GREEN_BIT 6 +#define TX1_LED_D11_BLUE_BIT 5 +#define TX1_LED_D9_BLUE_BIT 4 + +// TX1 LED bit masks for tile[1] (XS1_PORT_4D) +#define TX1_LED_D4_GAME_BIT 3 +#define TX1_LED_D7_3A_BIT 2 +#define TX1_LED_D6_FPS71_BIT 0 + +// TX1 Game modes +typedef enum { + GAME_MODE_BYPASS = 0, + GAME_MODE_FPS20 = 1, + GAME_MODE_FPS71 = 2, + GAME_MODE_3A = 3 +} tx1_game_mode_t; + +// TX1 Feature modes (for volume adjustment target) +typedef enum { + FEATURE_MODE_NONE = 0, + FEATURE_MODE_SYSTEM_VOLUME = 1, + FEATURE_MODE_GUNSHOT_LEVEL = 2, + FEATURE_MODE_FOOTSTEPS_LEVEL = 3, + FEATURE_MODE_MIC_LEVEL = 4 +} tx1_feature_mode_t; timer tm; -#define SE_DELAY (2000000000) //20s delay -#define BOOT_TIMEOUT (1000000000) //5s delay +#define SE_DELAY (100000000) //20s delay #define MUTE_ENABLE_DELAY (100000000) //1s delay #define UMUTE_DELAY (15000000) //150ms delay #define FORMAT_DELAY (30000000) //300ms delay #define EQ_MODE_DELAY (100000000) //100ms delay #define EQ_SYNC_DELAY (50000000) //500ms delay for EQ parameter sync -// 改动原因:C1四个实体按键全部接在XS1_PORT_8D的bit4-bit7,统一定义位掩码,避免在按键状态机中直接使用魔数。 -#define C1_KEY_MODE_MASK 0x10 -#define C1_KEY_VOL_DOWN_MASK 0x20 -#define C1_KEY_MIC_MUTE_MASK 0x40 -#define C1_KEY_VOL_UP_MASK 0x80 - -// 改动原因:g_dac_vol在C1中按NAU88C22 DAC音量寄存器值保存,限制在现有dac_volume注释对应的-66dB~0dB范围内。 -#define C1_DAC_VOL_MIN 0x4B -#define C1_DAC_VOL_MAX 0xCF -#define C1_DAC_MUTE 0x00 -// 改动原因:DAC寄存器按2个码值对应1dB,按键每次调节步进固定为2,确保与硬件音量刻度一致。 -#define C1_DAC_VOL_STEP 0x02 - -// 改动原因:C1的TIMER_PERIOD为20ms,按DS1同类短按/长按模型换算阈值;mode/mic 仍用 LONG 区分短按窗口;音量键已取消长按连调故不再使用 REPEAT 间隔宏。 -#define C1_KEY_SHORT_TICKS 1 -#define C1_KEY_LONG_TICKS 50 -// 改动原因:规格要求 mic 键长按 1.5s 切换 g_dnr_enable(AI 通话降噪/DNR);20ms*75=1.5s,与 mode 键 LONG 解耦,避免误触。 -#define C1_KEY_MIC_DNR_LONG_TICKS 75 -// 改动原因:双击第二下需在首击释放后约 500ms 内按下,否则判为单击静音;20ms*25=500ms。 -#define C1_MIC_DOUBLE_DEFER_TICKS 25 -// 改动原因:新增C1模式持久化文件路径,使用LittleFS保存mode按键状态,保证断电重启后可恢复。 -#define C1_MODE_VALUE_PATH "c1_mode_value" - -// 改动原因: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" -// 改动原因:与 FORMAT_DELAY(30000000) 相同时间基准(get_reference_time 滴答),用户停止调节 300ms 后再写 Flash,减少磨损并满足需求。 -#define C1_DAC_VOL_SAVE_DELAY (30000000) - -// 改动原因:XS1_PORT_4E 耳机/MIC 插入检测位定义——bit2 高=耳机插入;bit3 低=MIC 插入、高=拔出(与硬件原理图一致)。 -#define C1_HP_DETECT_MASK 0x04u -#define C1_MIC_DETECT_MASK 0x08u -// 改动原因:插入后延迟与 EQ_SYNC_DELAY 相同 tick(get_reference_time),固定 500ms 再恢复 DAC/ADC 硬件音量,减轻插拔 pop。 -#define C1_JACK_RESTORE_DELAY EQ_SYNC_DELAY -// 改动原因: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) -{ - if (v == C1_DAC_MUTE) - return 1; - if (v >= C1_DAC_VOL_MIN && v <= C1_DAC_VOL_MAX) - return 1; - return 0; -} - -// 改动原因:灯索引与 c1_mode 同值;仅钳位非法 Flash 读数,合法值原样下发 tile1,避免误映射。 -static inline unsigned c1_mode_to_tile_mode_led_code(unsigned mode_value) -{ - 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: -#if !BYPASS_UAC2 - SetRoleSwitchFlag(MODE_BYPASS_UAC2); - reboot_need = 1; -#endif - break; - case 2: -#if !BR_UAC2 - SetRoleSwitchFlag(MODE_BR_UAC2); - reboot_need = 1; -#endif - break; - case 3: -#if !V71_UAC2 - SetRoleSwitchFlag(MODE_V71_UAC2); - reboot_need = 1; -#endif - break; - case 4: -#if !FPS_UAC2 - SetRoleSwitchFlag(MODE_FPS_UAC2); - reboot_need = 1; -#endif - break; - case 5: -#if !FPS_UAC2 - SetRoleSwitchFlag(MODE_FPS_UAC2); - reboot_need = 0; -#endif - 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) #define NAU88L21_PGA_GAIN_REG_MAX_VALUE 0x25+1 // 0x25=37, 36dB. +1 is for extra 1.5dB digital gain #define NAU88L21_PGA_GAIN_REG_DEFAULT_VALUE (NAU88L21_PGA_GAIN_REG_MAX_VALUE) -// 改动原因:4E 为耳机/MIC 检测输入(读 bit2/bit3),原先声明为 out 无法采样;改为 in port 与硬件方向一致。 -on tile[0]: in port p_mic_phone_detect = XS1_PORT_4E; -on tile[0]: out port p_gpio = XS1_PORT_4F; - -#define LED_OFF 0x7F // 修改:清除最高位,只保留低7位 -#define LED_RED 0b01011111 // 修改:清除最高位,只保留低7位 -#define LED_GREEN 0b01101111 // 修改:清除最高位,只保留低7am -#define LED_BLUE 0b00111111 // 修改:清除最高位,只保留低7位 -#define LED_YELLOW (LED_RED & LED_GREEN) -#define LED_CYAN (LED_GREEN & LED_BLUE) -#define LED_PURPLE (LED_RED & LED_BLUE) -#define LED_WHITE (LED_RED & LED_GREEN & LED_BLUE) -enum { OS_WIN = 1, OS_OTHERS = 2 }; -unsigned g_led_blink_count = 0; -unsigned g_led_blink_is_white = 0; - // 改动原因:g_hid_pass_data[] 定义已上移至与其它 HID 全局量同块,避免 extern 无实体导致链接失败。 static unsigned g_last_dac_vol = 0xFF; // 改动原因:改为检测g_dac_vol的变化,初始化为0xFF表示未初始化 static unsigned g_last_mute_switch = 0xFF; // 改动原因:检测静音开关变化并上报0xB2,0xFF=未初始化 @@ -282,8 +184,7 @@ unsigned g_uac_mode = 1; // 2 for UAC2.0, 1 for UAC1.0 unsigned g_uac_mode = 2; // 2 for UAC2.0, 1 for UAC1.0 #endif -// 改动原因:XS1_PORT_8D现在作为C1四个实体按键端口p_button使用;旧p_8ch_in只在#if 0代码块中引用,继续声明会造成重复端口映射错误。 -// on tile[0]: in port p_8ch_in = XS1_PORT_8D; + void device_reboot(void); @@ -356,6 +257,7 @@ static inline void NAU88C22_REGREAD(unsigned reg, unsigned &val, client interfac { i2c_regop_res_t result; val = i2c.read_reg16(NAU88_I2C_DEVICE_ADDR, reg, result); + debug_printf("NAU88C22_REGREAD: reg=%d, val=%d\n", reg, val); } static inline i2c_regop_res_t NAU88C22_REGWRITE(unsigned reg, unsigned val, client interface i2c_master_if i2c) @@ -364,11 +266,7 @@ static inline i2c_regop_res_t NAU88C22_REGWRITE(unsigned reg, unsigned val, clie if(result != I2C_REGOP_SUCCESS) { - debug_printf("I2C write failed: reg="); - printhex(reg); - debug_printf(", val="); - printhex(val); - debug_printf("\n"); + debug_printf("I2C write failed: reg=%d, val=%d\n", reg, val); } else { @@ -387,8 +285,8 @@ static inline void HT5943_REGREAD(unsigned device, unsigned reg, unsigned &val, static inline void HT5943_REGWRITE(unsigned device, unsigned reg, unsigned val, client interface i2c_master_if i2c) { - // debug_printf("HT5943_REGWRITE: device = 0x%02X, reg = 0x%02X, val = 0x%02X\n", device, reg, val); i2c.write_reg(device, reg, val); + debug_printf("HT5943_REGWRITE: device = 0x%02X, reg = 0x%02X, val = 0x%02X\n", device, reg, val); } @@ -442,7 +340,6 @@ void codec_init(void) else CODEC_REGWRITE(NAU88_I2C_DEVICE_ADDR, 0x007E, NAU88L21_PGA_GAIN_REG_DEFAULT_VALUE << 8); - debug_printf("Codec init finished\n"); } @@ -479,15 +376,103 @@ void mic_volume(unsigned level, client interface i2c_master_if i2c) } } +/* 改动原因:按 phaten_golden_6ch/audiohw.xc 流程初始化——先 SDB 使能并延时,再 wake/freq/通道配置, + * 带 I2C 重试。xC 禁止 client interface 全局变量,SDB 在本函数内直接用 led_if 控制(不经 htr3236_hw_enable)。 */ +static void tx1_htr3236_bringup(htr3236_t *dev, client interface i2c_master_if i2c, + client interface tx1_led_if led_if) +{ + int ch; + unsigned retry; + uint8_t zeros[36]; + + led_if.init(); + led_if.set_htr3236_sdb(1); + delay_milliseconds(2); + + htr3236_init(dev, HTR3236_ADDR_GND); + + retry = 0; + while (htr3236_software_wake(dev, i2c) != I2C_REGOP_SUCCESS && retry < 10) { + retry++; + delay_milliseconds(1); + debug_printf("HTR3236 wake retry %u\n", retry); + } + if (retry >= 10) { + debug_printf("HTR3236 LED driver wake failed\n"); + } else { + debug_printf("HTR3236 LED driver wake ok\n"); + } + + retry = 0; + while (htr3236_set_frequency(dev, i2c, HTR3236_FREQ_22KHZ) != I2C_REGOP_SUCCESS && retry < 10) { + retry++; + delay_milliseconds(1); + debug_printf("HTR3236 freq retry %u\n", retry); + } + if (retry >= 10) { + debug_printf("HTR3236 set frequency failed\n"); + } else { + debug_printf("HTR3236 set frequency ok\n"); + } + + for (ch = 1; ch <= 35; ch++) { + htr3236_set_led_config(dev, i2c, ch, HTR3236_CURRENT_HALF, 1); + } + htr3236_global_enable(dev, i2c, 1); + + for (ch = 0; ch < 36; ch++) { + zeros[ch] = 0; + } + htr3236_set_pwm_bulk(dev, i2c, 1, zeros, 36); + htr3236_update(dev, i2c); +} + +// RGB LED to HTR3236 OUT channel mapping (D1-D12) +// Each LED: {out_b, out_g, out_r} +static const uint8_t rgb_led_map[13][3] = { + {0, 0, 0}, // [0] invalid + {24, 23, 22}, // D1 + {21, 20, 19}, // D2 + {18, 17, 16}, // D3 + {15, 14, 13}, // D4 + {12, 11, 10}, // D5 + {9, 8, 7}, // D6 + {6, 5, 4}, // D7 + {3, 2, 1}, // D8 + {36, 35, 34}, // D9 + {33, 32, 31}, // D10 + {30, 29, 28}, // D11 + {27, 26, 25} // D12 +}; + +static void tx1_rgb_led_set(htr3236_t *dev, client interface i2c_master_if i2c, + uint8_t led, uint8_t r, uint8_t g, uint8_t b) +{ + if (led < 1 || led > 12) return; + htr3236_set_pwm(dev, i2c, rgb_led_map[led][0], b); + htr3236_set_pwm(dev, i2c, rgb_led_map[led][1], g); + htr3236_set_pwm(dev, i2c, rgb_led_map[led][2], r); + /* 改动原因:HTR3236 须写 PWM_UPDATE 后输出才刷新,golden 的 led_update_all 亦如此 */ + htr3236_update(dev, i2c); +} + +static void tx1_rgb_led_all_off(htr3236_t *dev, client interface i2c_master_if i2c) +{ + uint8_t zeros[36]; + int i; + for (i = 0; i < 36; i++) zeros[i] = 0; + htr3236_set_pwm_bulk(dev, i2c, 1, zeros, 36); + htr3236_update(dev, i2c); +} + void save_value(unsigned char * unsafe path, unsigned char value); unsigned char load_value(unsigned char * unsafe path); -#define C1_MODE_INFO_PATH "c1_mode" /* 改动原因:c_dfu 仅接收 FIRMWARE_UPGRADE_START,在此线程执行 handle_firmware_upgrade_start。 * 移除未使用的 chanend c_erase:原占位参数无任何 select/通信,会导致 main 侧被迫接 dummy 通道且与当前拓扑无关。 */ #if HID_DFU_EN -void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, client interface c1_led_ctrl_if i_c1_led_ctrl, streaming chanend c_dfu) +void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, streaming chanend c_dfu, client interface tx1_led_if led_if) #else -void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, client interface c1_led_ctrl_if i_c1_led_ctrl) +void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, client interface tx1_led_if led_if) #endif { unsigned cmd; @@ -496,51 +481,36 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli unsigned eq_mode_time = 0; unsigned se_time = 0; unsigned se_count = 0; - timer tmr, se_tmr, eq_mode_timer, eq_sync_timer, button_tmr; + timer tmr, se_tmr, eq_mode_timer, eq_sync_timer; unsigned eq_sync_time = 0; unsigned old_format = 14; unsigned unmute_dac_state; unsigned old_dac_vol = 0; unsigned old_adc_vol = 0; + /* 改动原因:参考 fosi_c1 / xk_316 流程,上电后首轮定时器必须写 NAU88C22 0x0034; + * 若 old_dac_vol 与 g_dac_vol 初值相同则永不写寄存器导致播放无声。 */ + { + unsigned init_dac_vol; + GET_SHARED_GLOBAL(init_dac_vol, g_dac_vol); + old_dac_vol = ~init_dac_vol; + } unsigned old_dac_mode = 0; - // 改动原因:记录上次用于防抖持久化的 g_dac_vol;deadline=0 表示当前无待写入 Flash 的定时保存任务。 - unsigned dac_vol_persist_snapshot = 0; - unsigned dac_vol_persist_deadline = 0; - // 改动原因:耳机拔出强制 DAC 寄存器静音(不改 g_dac_vol,类比 phaten 的 dac_det_muted);插入后延时再写回逻辑音量。 - unsigned hp_jack_dac_mute = 0; - unsigned hp_restore_deadline = 0; - unsigned hp_stable_prev = 0xFFFFFFFFu; - unsigned hp_db_cnt = 0; - unsigned hp_cand = 0xFFFFFFFFu; - unsigned hp_stable = 0; - // 改动原因:记录上次写入 0x0034 时的“插拔强制哑音”组合态(耳机拔出 | MIC 拔出 | MIC 插入),任一路变化都要重推寄存器。 - unsigned old_dac_jack_force_mute = 0; - // 改动原因:MIC 拔出瞬间哑 DAC(参考 phaten MIC_DET_DAC_MUTE),拔出边沿起 500ms 后恢复 DAC 寄存器;不改 g_dac_vol。 - unsigned mic_pull_dac_mute = 0; - unsigned mic_pull_dac_deadline = 0; - // 改动原因:MIC 插入(去抖稳定后)立即哑 DAC 防 pop,稳定插入起再计 500ms 后恢复 DAC;拔出时清零;不改 g_dac_vol。 - unsigned mic_insert_dac_mute = 0; - unsigned mic_insert_dac_deadline = 0; - // 改动原因:MIC 拔出强制 ADC mute;插入 500ms 后按 g_mute_switch+g_adc_vol 恢复,不修改 g_mute_switch,故 mic mute LED 不受插拔影响。 - unsigned mic_jack_adc_mute = 0; - unsigned mic_restore_deadline = 0; - unsigned mic_stable_prev = 0xFFFFFFFFu; - unsigned mic_db_cnt = 0; - unsigned mic_cand = 0xFFFFFFFFu; - unsigned mic_stable = 0; - // 改动原因:按DS1按键状态机思路保存每个按键按下时长;mode/mic 仍用短/长按窗口区分,音量键仅用于释放时短按去抖(不支持长按连调)。 - unsigned mode_press_ticks = 0; - unsigned vol_down_press_ticks = 0; - unsigned mic_mute_press_ticks = 0; - unsigned vol_up_press_ticks = 0; - // 改动原因:mic 键双击需延迟首轮短按的静音动作,用 stage1=等超时单击 / stage2=已收到第二下按下等释放;与长按 DNR 互斥靠 mic_dnr_long_fired。 - unsigned mic_dbl_stage = 0; - unsigned mic_defer_left = 0; - unsigned mic_dnr_long_fired = 0; - // 改动原因:变声/美声仅按键+灯,tile0 保存状态供 set_mic_voice_fx 下发 mic 橙灯。 - unsigned c1_mic_voice_fx = 0; - // 改动原因:mic mute红灯通过interface下发到tile1,仅在状态变化时发送,减少无意义跨tile调用。 - unsigned last_mute_switch_for_led = 0xFFFFFFFF; + + // TX1 game/feature mode state + tx1_game_mode_t game_mode = GAME_MODE_BYPASS; + tx1_feature_mode_t feature_mode = FEATURE_MODE_NONE; + unsigned feature_volume = 6; // 0-12 range + unsigned mic_muted = 0; + unsigned dnr_enabled = 1; + unsigned high_perf_mode = 0; + + htr3236_t htr3236_dev; + + // TX1 LED state + unsigned led_tile0_shadow = 0xF0; // bits 7-4 all off (active low) + unsigned feature_timeout_ticks = 0; + #define FEATURE_TIMEOUT_MAX 160 // 8s / 50ms = 160 ticks + unsigned host_os = 0; tmr :> time; /* Input time */ time += TIMER_PERIOD; /* Add time */ @@ -550,64 +520,43 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli eq_mode_time += EQ_MODE_DELAY; eq_sync_timer :> eq_sync_time; eq_sync_time += EQ_SYNC_DELAY; - unsigned c1_mode = load_value(C1_MODE_INFO_PATH); + + // TX1: Initialize tile[0] GPIO LEDs (all off, active low) + led_tile0_shadow = 0xF0; + p_led_tile0 <: led_tile0_shadow; + + // TX1: tile[1] GPIO + HTR3236 SDB,再经 I2C 按 golden 流程配置 HTR3236 + tx1_htr3236_bringup(&htr3236_dev, i2c, led_if); + + // TX1 button previous state (active low: 0=pressed, 1=released) + unsigned prev_fps = 1, prev_game = 1, prev_mic = 1; + unsigned prev_vol_plus = 1, prev_vol_minus = 1; + unsigned fps_press_time = 0, game_press_time = 0, mic_press_time = 0; + unsigned vol_plus_press_time = 0, vol_minus_press_time = 0; + unsigned fps_long_fired = 0, game_long_fired = 0, mic_long_fired = 0; + unsigned vol_plus_long_fired = 0, vol_minus_long_fired = 0; + + // TX1 combo key state + typedef enum { COMBO_NONE = 0, COMBO_GAME_MIC, COMBO_VOL_UP_DOWN } tx1_combo_t; + tx1_combo_t current_combo = COMBO_NONE; + unsigned combo_triggered = 0; + unsigned combo_release_time = 0; + unsigned combo_just_released = 0; + + // TX1 factory reset state + unsigned factory_reset_counting = 0; + unsigned factory_reset_start_time = 0; + unsigned factory_reset_6s_fired = 0; + unsigned factory_reset_10s_fired = 0; + unsigned factory_reset_done = 0; + + // TX1 LED effect state for game mode indicators + unsigned gpio_leds_dirty = 1; // refresh LEDs on first tick #if HID_DFU_EN firmware_upgrade_init(); #endif - if (c1_mode > C1_MODE_VALUE_MAX || c1_mode < C1_MODE_VALUE_MIN) - { - 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++) - { - GET_SHARED_GLOBAL(host_os, g_host_os); - if (host_os == OS_WIN) { - debug_printf("Detected Windows OS (OS_WIN) host_os: %d\n", host_os); - break; - } - delay_milliseconds(1); - } - - if (host_os == OS_WIN) { - debug_printf("Detected Windows OS (OS_WIN) c1_mode: %d\n", c1_mode); - switch_mode_by_c1_mode(c1_mode, 1); - } - else - { - switch_mode_by_c1_mode(c1_mode, 0); - } -#endif - - - // 改动原因:开机从 LittleFS 恢复 DAC 音量寄存器码;无效或未写过时用最大音量 C1_DAC_VOL_MAX,避免误用默认值或垃圾数据。 - { - unsigned char loaded_dac_vol = load_value(C1_DAC_VOL_INFO_PATH); - unsigned init_dac_vol; - if (c1_saved_dac_vol_is_valid(loaded_dac_vol) == 0) - init_dac_vol = C1_DAC_VOL_MAX; - else - init_dac_vol = loaded_dac_vol; - SET_SHARED_GLOBAL(g_dac_vol, init_dac_vol); - // 改动原因:强制首轮定时器路径执行 NAU88C22 写音量(含 mute=0 时 old_dac_vol 初值也为 0 的情况)。 - old_dac_vol = ~init_dac_vol; - dac_vol_persist_snapshot = init_dac_vol; - dac_vol_persist_deadline = 0; - } - - // 改动原因: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) { @@ -633,6 +582,7 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli c :> device; c :> regAddr; c :> regValue; + // debug_printf("AUDIOHW_CMD_REGWRITE: device=%02x, regAddr=%d, regValue=%d\n", device, regAddr, regValue); if (device == NAU88_I2C_DEVICE_ADDR) { NAU88C22_REGWRITE(regAddr, regValue, i2c); @@ -695,387 +645,38 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli } } } - // 改动原因:耳机/MIC 插拔检测——写 NAU88C22(0x0034 / mic_volume);不修改 g_dac_vol、g_mute_switch;MIC 插/拔均对 DAC 做瞬时静音+500ms 恢复防 pop。 - { - unsigned raw_det; - p_mic_phone_detect :> raw_det; - unsigned hp_now = ((raw_det & C1_HP_DETECT_MASK) != 0) ? 1u : 0u; - unsigned mic_now = ((raw_det & C1_MIC_DETECT_MASK) == 0) ? 1u : 0u; - if (hp_cand == 0xFFFFFFFFu) { - hp_cand = hp_now; - hp_stable = hp_now; - hp_db_cnt = 0; - } else if (hp_now == hp_cand) { - hp_db_cnt++; - if (hp_db_cnt >= C1_JACK_DEBOUNCE_SAMPLES) { - hp_stable = hp_cand; - } - } else { - hp_cand = hp_now; - hp_db_cnt = 1; - } - if (mic_cand == 0xFFFFFFFFu) { - mic_cand = mic_now; - mic_stable = mic_now; - mic_db_cnt = 0; - } else if (mic_now == mic_cand) { - mic_db_cnt++; - if (mic_db_cnt >= C1_JACK_DEBOUNCE_SAMPLES) { - mic_stable = mic_cand; - } - } else { - mic_cand = mic_now; - mic_db_cnt = 1; - } - if (hp_stable_prev == 0xFFFFFFFFu) { - hp_stable_prev = hp_stable; - mic_stable_prev = mic_stable; - } else { - if (!hp_stable) { - hp_jack_dac_mute = 1; - hp_restore_deadline = 0; - } else { - if (hp_stable && !hp_stable_prev) { - hp_restore_deadline = now + C1_JACK_RESTORE_DELAY; - } - if (hp_jack_dac_mute && hp_restore_deadline != 0 && timeafter(now, hp_restore_deadline)) { - hp_jack_dac_mute = 0; - } - } - if (!mic_stable) { - mic_jack_adc_mute = 1; - mic_restore_deadline = 0; - mic_insert_dac_mute = 0; - mic_insert_dac_deadline = 0; - // 改动原因:MIC 拔出边沿立即拉 DAC 寄存器静音,减轻瞬态 pop;满 500ms(相对拔出时刻)后 mic_pull_dac_mute 清零恢复 g_dac_vol 对应音量。 - if (mic_stable_prev) { - mic_pull_dac_mute = 1; - mic_pull_dac_deadline = now + C1_JACK_RESTORE_DELAY; - } - if (mic_pull_dac_deadline != 0 && timeafter(now, mic_pull_dac_deadline)) { - mic_pull_dac_mute = 0; - mic_pull_dac_deadline = 0; - } - } else { - mic_pull_dac_mute = 0; - mic_pull_dac_deadline = 0; - // 改动原因:去抖后由拔出→插入的边沿:立刻 mic_insert_dac_mute 哑 DAC;自该稳定插入时刻起 500ms 后清除以恢复 g_dac_vol(与 ADC 的 mic_restore 同源边沿,时间基准一致)。 - if (mic_stable && !mic_stable_prev) { - mic_restore_deadline = now + C1_JACK_RESTORE_DELAY; - mic_insert_dac_mute = 1; - mic_insert_dac_deadline = now + C1_JACK_RESTORE_DELAY; - } - if (mic_jack_adc_mute && mic_restore_deadline != 0 && timeafter(now, mic_restore_deadline)) { - mic_jack_adc_mute = 0; - } - if (mic_insert_dac_mute && mic_insert_dac_deadline != 0 && timeafter(now, mic_insert_dac_deadline)) { - mic_insert_dac_mute = 0; - mic_insert_dac_deadline = 0; - } - } - hp_stable_prev = hp_stable; - mic_stable_prev = mic_stable; - } - } GET_SHARED_GLOBAL(dac_vol, g_dac_vol); GET_SHARED_GLOBAL(adc_vol, g_adc_vol); unsigned mute_switch; GET_SHARED_GLOBAL(mute_switch, g_mute_switch); - if (last_mute_switch_for_led != mute_switch) - { - // 改动原因:需求规定mic mute=0亮红灯,否则灭灯;LED端口在tile1,因此在tile0检测状态变化后用interface同步。 - i_c1_led_ctrl.set_mic_mute_state(mute_switch); - last_mute_switch_for_led = mute_switch; - } - // 改动原因:MIC 物理拔出时 mic_jack_adc_mute 强制 ADC 静音;插入 500ms 内仍保持静音,之后恢复 g_mute_switch 与 g_adc_vol 决定的电平(不触碰 LED 条件 mute_switch)。 - unsigned effective_adc_vol = mic_jack_adc_mute ? 0 : ((mute_switch != 0) ? 0 : adc_vol); - // 改动原因:耳机拔出或 MIC 插/拔防 pop 时写 C1_DAC_MUTE(不改 g_dac_vol);各事件满 500ms 或互斥清除后按 g_dac_vol 写回 0x0034。 + // DAC volume update { - unsigned dac_jack_force_mute = hp_jack_dac_mute | mic_pull_dac_mute | mic_insert_dac_mute; - unsigned dac_reg = dac_jack_force_mute ? C1_DAC_MUTE : (dac_vol & 0xff); - if (old_dac_vol != dac_vol || old_type != audio_type || old_dac_jack_force_mute != dac_jack_force_mute) { + unsigned dac_reg = dac_vol & 0xff; + if (old_dac_vol != dac_vol || old_type != audio_type) { old_dac_vol = dac_vol; - old_dac_jack_force_mute = dac_jack_force_mute; NAU88C22_REGWRITE(0x0034, ((dac_reg & 0xff) << 8) | (dac_reg & 0xff), i2c); SET_SHARED_GLOBAL(g_old_audio_type, audio_type); - debug_printf("set dac_reg 0x%x (hp=%d mic_pull=%d mic_ins=%d) audio_type %d \n", dac_reg, hp_jack_dac_mute, mic_pull_dac_mute, mic_insert_dac_mute, audio_type); + debug_printf("set dac_reg 0x%x audio_type %d\n", dac_reg, audio_type); } } - // 改动原因:音量键/HID/UART 任一修改 g_dac_vol 后不立即写 Flash;仅当读回值相对 persist_snapshot 稳定满 300ms 再 save_value,满足防抖与关机保存。 + // ADC volume update { - if (dac_vol != dac_vol_persist_snapshot) + unsigned effective_adc_vol = (mute_switch != 0) ? 0 : adc_vol; + if (old_adc_vol != effective_adc_vol) { - dac_vol_persist_snapshot = dac_vol; - dac_vol_persist_deadline = now + C1_DAC_VOL_SAVE_DELAY; - } - else if (dac_vol_persist_deadline != 0 && timeafter(now, dac_vol_persist_deadline)) - { - save_value(C1_DAC_VOL_INFO_PATH, (unsigned char)(dac_vol & 0xff)); - dac_vol_persist_deadline = 0; - } - } - - if (old_adc_vol != effective_adc_vol) - { - if ((effective_adc_vol <= 0xff) && (effective_adc_vol >= 0)) - { - old_adc_vol = effective_adc_vol; - // 改动原因:mic mute按键会改变g_mute_switch并影响effective_adc_vol;这里复用现有mic_volume接口让静音立即作用到ADC通路。 - mic_volume(effective_adc_vol, i2c); + if ((effective_adc_vol <= 0xff) && (effective_adc_vol >= 0)) + { + old_adc_vol = effective_adc_vol; + mic_volume(effective_adc_vol, i2c); + } } } GET_SHARED_GLOBAL(dac_mode, g_dac_mode); GET_SHARED_GLOBAL(new_dac_mode, g_new_dac_mode); - // --- C1实体按键逻辑处理 --- - // 改动原因:参考DS1按键处理模型,在主定时循环中读取端口、按低电平有效判断按下;mode/mic 用计数器区分短按窗口,音量键仅在释放时步进一档(无长按连调)。 - { - unsigned button_state; - unsigned mode_pressed; - unsigned vol_down_pressed; - unsigned mic_mute_pressed; - unsigned vol_up_pressed; - unsigned pressed_count; - - p_button :> button_state; - mode_pressed = ((button_state & C1_KEY_MODE_MASK) == 0); - vol_down_pressed = ((button_state & C1_KEY_VOL_DOWN_MASK) == 0); - mic_mute_pressed = ((button_state & C1_KEY_MIC_MUTE_MASK) == 0); - 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++; - // 改动原因:同一时刻只允许一个实体键生效,切到mode键时清除其它键计时,避免滑键后释放误触发。 - vol_down_press_ticks = 0; - mic_mute_press_ticks = 0; - vol_up_press_ticks = 0; - } - else if (vol_down_pressed) - { - vol_down_press_ticks++; - // 改动原因:同一时刻只允许音量-键生效,清除其它键状态以匹配DS1单键状态机处理方式。 - mode_press_ticks = 0; - mic_mute_press_ticks = 0; - vol_up_press_ticks = 0; - } - else if (mic_mute_pressed) - { - // 改动原因:双击窗口内第二下按下,取消延迟单击静音,改为等待释放后判双击变声。 - if (mic_dbl_stage == 1) - { - mic_defer_left = 0; - mic_dbl_stage = 2; - } - mic_mute_press_ticks++; - // 改动原因:按住满 1.5s 翻转 g_dnr_enable,extra_i2s 中 GET_SHARED_GLOBAL 决定是否走 DNR;松手时靠 mic_dnr_long_fired 屏蔽短按/双击。 - if (mic_mute_press_ticks == C1_KEY_MIC_DNR_LONG_TICKS) - { - unsigned dnr_enable; - GET_SHARED_GLOBAL(dnr_enable, g_dnr_enable); - dnr_enable = (dnr_enable != 0) ? 0 : 1; - SET_SHARED_GLOBAL(g_dnr_enable, dnr_enable); - mic_dnr_long_fired = 1; - debug_printf("C1 mic DNR toggle (hold 1.5s): %d\n", dnr_enable); - } - // 改动原因:同一时刻只允许mic mute键生效,清除其它键状态,避免释放时误执行音量或mode短按。 - mode_press_ticks = 0; - vol_down_press_ticks = 0; - vol_up_press_ticks = 0; - } - else if (vol_up_pressed) - { - vol_up_press_ticks++; - // 改动原因:同一时刻只允许音量+键生效,清除其它键状态以匹配DS1单键状态机处理方式。 - mode_press_ticks = 0; - vol_down_press_ticks = 0; - mic_mute_press_ticks = 0; - } - } - else - { - if (pressed_count == 0) - { - // 改动原因: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)) - { - c1_mode ++; - if (c1_mode > C1_MODE_VALUE_MAX) - { - c1_mode = C1_MODE_VALUE_MIN; - } - save_value(C1_MODE_INFO_PATH, c1_mode); - - 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)); - } - - // 改动原因:音量键仅短按——释放时若已满足去抖时长则步进一档,与按住时长无关(已取消长按连调)。 - if (vol_down_press_ticks >= C1_KEY_SHORT_TICKS) - { - unsigned current_dac_vol; - GET_SHARED_GLOBAL(current_dac_vol, g_dac_vol); - // 改动原因:短按执行“最小值再按一次直达mute(0x00)”规则。 - if (current_dac_vol == C1_DAC_VOL_MIN) - { - current_dac_vol = C1_DAC_MUTE; - SET_SHARED_GLOBAL(g_dac_vol, current_dac_vol); - debug_printf("C1 key volume down short to mute: %d\n", current_dac_vol); - } - // 改动原因:短按按步进2减小(1dB);并钳位到0x4B,避免进入最小值以下的无效区间。 - else if (current_dac_vol > C1_DAC_VOL_MIN) - { - if (current_dac_vol <= (C1_DAC_VOL_MIN + C1_DAC_VOL_STEP)) - current_dac_vol = C1_DAC_VOL_MIN; - else - current_dac_vol -= C1_DAC_VOL_STEP; - SET_SHARED_GLOBAL(g_dac_vol, current_dac_vol); - debug_printf("C1 key volume down short: %d\n", current_dac_vol); - } - } - - // 改动原因:mic:短按静音延迟单击(防双击);双击变声 mic 橙灯;长按1.5s 切 g_dnr_enable 无灯;长按与短/双互斥。 - { - unsigned mic_snap = mic_mute_press_ticks; - if (mic_snap > 0) - { - if ((mic_snap >= C1_KEY_MIC_DNR_LONG_TICKS) || mic_dnr_long_fired) - { - if (mic_dbl_stage == 2) - mic_dbl_stage = 0; - } - else if ((mic_snap >= C1_KEY_SHORT_TICKS) && (mic_snap < C1_KEY_MIC_DNR_LONG_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_dnr_long_fired = 0; - } - } - - // 改动原因:音量键仅短按——释放时若已满足去抖时长则步进一档(已取消长按连调)。 - if (vol_up_press_ticks >= C1_KEY_SHORT_TICKS) - { - unsigned current_dac_vol; - GET_SHARED_GLOBAL(current_dac_vol, g_dac_vol); - // 改动原因:短按从mute恢复时先到0x4B,保证UI和听感从可听最小档开始。 - if (current_dac_vol < C1_DAC_VOL_MIN) - { - current_dac_vol = C1_DAC_VOL_MIN; - SET_SHARED_GLOBAL(g_dac_vol, current_dac_vol); - debug_printf("C1 key volume up short from mute: %d\n", current_dac_vol); - } - // 改动原因:短按按步进2增加(1dB);并钳位到0xCF,不越界。 - else if (current_dac_vol < C1_DAC_VOL_MAX) - { - if (current_dac_vol >= (C1_DAC_VOL_MAX - C1_DAC_VOL_STEP)) - current_dac_vol = C1_DAC_VOL_MAX; - else - current_dac_vol += C1_DAC_VOL_STEP; - SET_SHARED_GLOBAL(g_dac_vol, current_dac_vol); - debug_printf("C1 key volume up short: %d\n", current_dac_vol); - } - } - } - else if (pressed_count > 1) - { - // 改动原因:多键同按时取消 mic 双击等待,避免组合键松手后误触发延迟静音。 - mic_dbl_stage = 0; - mic_defer_left = 0; - } - - // 改动原因:多键同时按下不映射功能,立即清除本轮计时,避免组合键抖动误触发单键动作。 - mode_press_ticks = 0; - vol_down_press_ticks = 0; - mic_mute_press_ticks = 0; - vol_up_press_ticks = 0; - } - } - -#if 0// UAC1 - unsigned p_8ch_in_val; - p_8ch_in :> p_8ch_in_val; - if ((p_8ch_in_val & 0x40) == 0x40) - { - g_dnr_enable = 0; - } - else - { - g_dnr_enable = 1; - } - - if ((p_8ch_in_val & 0xa0) == 0xa0) - { - g_fps_enable = 1; - g_3d_enable = 0; - } - else if ((p_8ch_in_val & 0xa0) == 0x20) - { - g_3d_enable = 1; - g_fps_enable = 0; - } - else - { - g_3d_enable = 0; - g_fps_enable = 0; - } -#endif - #if ((HID_CONTROLS == 1) && (EQ_EN == 1)) // 改动原因:检测增益模式变化请求,当g_request_gain_mode != -1且与当前模式不同时应用 @@ -1450,6 +1051,285 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli } #endif + // ========== TX1 BUTTON SCANNING ========== + { + unsigned btn1, btn2; + p_button_fps_game_mic :> btn1; // bit3=FPS, bit2=GAME, bit1=MIC + p_button_vol :> btn2; // bit3=VOL+, bit2=VOL- + + // Extract button states (active low: 0=pressed, 1=released) + unsigned fps = (btn1 & TX1_BIT_FPS_MODE) ? 1 : 0; + unsigned game = (btn1 & TX1_BIT_GAME_MODE) ? 1 : 0; + unsigned mic = (btn1 & TX1_BIT_MIC_MUTE) ? 1 : 0; + unsigned vol_plus = (btn2 & TX1_BIT_VOL_PLUS) ? 1 : 0; + unsigned vol_minus = (btn2 & TX1_BIT_VOL_MINUS) ? 1 : 0; + + // Combo key detection (highest priority) + tx1_combo_t new_combo = COMBO_NONE; + if (game == 0 && mic == 0) { + new_combo = COMBO_GAME_MIC; + } else if (vol_plus == 0 && vol_minus == 0) { + new_combo = COMBO_VOL_UP_DOWN; + } + + // Handle combo state changes + if (new_combo != current_combo) { + if (current_combo != COMBO_NONE && new_combo == COMBO_NONE) { + combo_release_time = now; + combo_just_released = 1; + } + current_combo = new_combo; + combo_triggered = 0; + } + + // Trigger combo action once + if (current_combo != COMBO_NONE && !combo_triggered) { + combo_triggered = 1; + if (current_combo == COMBO_GAME_MIC) { + // Toggle high performance mode + high_perf_mode = !high_perf_mode; + gpio_leds_dirty = 1; + debug_printf("TX1: GAME+MIC combo - high_perf_mode=%d\n", high_perf_mode); + } else if (current_combo == COMBO_VOL_UP_DOWN) { + // Cycle LED effects in BYPASS mode only + if (game_mode == GAME_MODE_BYPASS && feature_mode == FEATURE_MODE_NONE) { + // For now, just toggle feature mode indicator + debug_printf("TX1: VOL++VOL- combo - LED effect cycle\n"); + } + } + } + + // Combo release silence window (50ms) + if (combo_just_released) { + if ((now - combo_release_time) >= 5000000) { // 50ms in 10ns ticks + combo_just_released = 0; + } + } + + // Factory reset detection (FPS + GAME held for 10.6s) + if (fps == 0 && game == 0 && current_combo == COMBO_NONE) { + if (!factory_reset_counting) { + factory_reset_counting = 1; + factory_reset_start_time = now; + factory_reset_6s_fired = 0; + factory_reset_10s_fired = 0; + factory_reset_done = 0; + debug_printf("TX1: Factory reset countdown started\n"); + } else if (!factory_reset_done) { + unsigned elapsed = now - factory_reset_start_time; + if (elapsed >= 10600000000ull && !factory_reset_done) { // 10.6s + factory_reset_done = 1; + debug_printf("TX1: FACTORY RESET TRIGGERED!\n"); + SET_SHARED_GLOBAL(g_request_factory_reset, 1); + } else if (elapsed >= 10000000000ull && !factory_reset_10s_fired) { + factory_reset_10s_fired = 1; + debug_printf("TX1: Factory reset 10s warning\n"); + } else if (elapsed >= 6000000000ull && !factory_reset_6s_fired) { + factory_reset_6s_fired = 1; + debug_printf("TX1: Factory reset 6s warning\n"); + } + } + } else { + if (factory_reset_counting) { + factory_reset_counting = 0; + debug_printf("TX1: Factory reset cancelled\n"); + } + } + + // Individual button processing (only when no combo active and outside silence window) + if (current_combo == COMBO_NONE && !combo_just_released) { + + // FPS button - cycle feature modes + if (fps != prev_fps) { + if (fps == 0) { // Pressed + fps_press_time = now; + fps_long_fired = 0; + } else { // Released + if (!fps_long_fired && (now - fps_press_time) < 1000000000ull) { + // Short press: cycle feature mode + feature_mode = (feature_mode + 1) % 5; + feature_timeout_ticks = 0; + gpio_leds_dirty = 1; + debug_printf("TX1: FPS short press - feature_mode=%d\n", feature_mode); + } + } + prev_fps = fps; + } + + // GAME button - cycle game modes + if (game != prev_game) { + if (game == 0) { + game_press_time = now; + game_long_fired = 0; + } else { + if (!game_long_fired && (now - game_press_time) < 1000000000ull) { + // Short press: cycle game mode + game_mode = (game_mode + 1) % 4; + gpio_leds_dirty = 1; + SET_SHARED_GLOBAL(g_3d_fps, game_mode); + debug_printf("TX1: GAME short press - game_mode=%d\n", game_mode); + } + } + prev_game = game; + } + + // MIC button - toggle mute + if (mic != prev_mic) { + if (mic == 0) { + mic_press_time = now; + mic_long_fired = 0; + } else { + if (!mic_long_fired && (now - mic_press_time) < 1000000000ull) { + // Short press: toggle mic mute + mic_muted = !mic_muted; + gpio_leds_dirty = 1; + debug_printf("TX1: MIC short press - mic_muted=%d\n", mic_muted); + } + } + prev_mic = mic; + } + + // MIC long press - toggle DNR + if (mic == 0 && !mic_long_fired && (now - mic_press_time) >= 1000000000ull) { + mic_long_fired = 1; + dnr_enabled = !dnr_enabled; + SET_SHARED_GLOBAL(g_dnr_on, dnr_enabled); + debug_printf("TX1: MIC long press - dnr_enabled=%d\n", dnr_enabled); + } + + // VOL+ continuous adjustment + if (vol_plus != prev_vol_plus) { + if (vol_plus == 0) { + vol_plus_press_time = now; + vol_plus_long_fired = 0; + } + prev_vol_plus = vol_plus; + } + if (vol_plus == 0 && !vol_plus_long_fired && (now - vol_plus_press_time) >= 1000000000ull) { + vol_plus_long_fired = 1; + } + if (vol_plus == 0 && vol_plus_long_fired) { + // Adjust volume every 100ms + static unsigned last_vol_plus_trigger = 0; + if ((now - last_vol_plus_trigger) >= 100000000ull) { + last_vol_plus_trigger = now; + if (feature_mode == FEATURE_MODE_NONE || feature_mode == FEATURE_MODE_SYSTEM_VOLUME) { + // System volume up + unsigned vol; + GET_SHARED_GLOBAL(vol, g_volume_level); + if (vol < 100) { + vol++; + SET_SHARED_GLOBAL(g_volume_level, vol); + SET_SHARED_GLOBAL(g_request_volume_set, 1); + } + } else { + // Feature volume up + if (feature_volume < 12) feature_volume++; + } + gpio_leds_dirty = 1; + } + } + + // VOL- continuous adjustment + if (vol_minus != prev_vol_minus) { + if (vol_minus == 0) { + vol_minus_press_time = now; + vol_minus_long_fired = 0; + } + prev_vol_minus = vol_minus; + } + if (vol_minus == 0 && !vol_minus_long_fired && (now - vol_minus_press_time) >= 1000000000ull) { + vol_minus_long_fired = 1; + } + if (vol_minus == 0 && vol_minus_long_fired) { + static unsigned last_vol_minus_trigger = 0; + if ((now - last_vol_minus_trigger) >= 100000000ull) { + last_vol_minus_trigger = now; + if (feature_mode == FEATURE_MODE_NONE || feature_mode == FEATURE_MODE_SYSTEM_VOLUME) { + unsigned vol; + GET_SHARED_GLOBAL(vol, g_volume_level); + if (vol > 0) { + vol--; + SET_SHARED_GLOBAL(g_volume_level, vol); + SET_SHARED_GLOBAL(g_request_volume_set, 1); + } + } else { + if (feature_volume > 0) feature_volume--; + } + gpio_leds_dirty = 1; + } + } + } + + // Feature mode timeout (8s) + if (feature_mode != FEATURE_MODE_NONE) { + feature_timeout_ticks++; + if (feature_timeout_ticks >= FEATURE_TIMEOUT_MAX) { + feature_mode = FEATURE_MODE_NONE; + feature_timeout_ticks = 0; + gpio_leds_dirty = 1; + debug_printf("TX1: Feature mode timeout\n"); + } + } + } + + // ========== TX1 LED UPDATE ========== + if (gpio_leds_dirty) { + gpio_leds_dirty = 0; + + // Update tile[0] GPIO LEDs (D10_GREEN, D8_GREEN, D11_BLUE, D9_BLUE) + led_tile0_shadow = 0xF0; // All off (active low) + // D10_GREEN = System Volume indicator (feature_mode == SYSTEM_VOLUME) + if (feature_mode == FEATURE_MODE_SYSTEM_VOLUME) { + led_tile0_shadow &= ~(1 << TX1_LED_D10_GREEN_BIT); + } + // D8_GREEN = DNR indicator + if (dnr_enabled) { + led_tile0_shadow &= ~(1 << TX1_LED_D8_GREEN_BIT); + } + // D11_BLUE = MIC Level indicator (feature_mode == MIC_LEVEL) + if (feature_mode == FEATURE_MODE_MIC_LEVEL) { + led_tile0_shadow &= ~(1 << TX1_LED_D11_BLUE_BIT); + } + // D9_BLUE = High Performance indicator + if (high_perf_mode) { + led_tile0_shadow &= ~(1 << TX1_LED_D9_BLUE_BIT); + } + p_led_tile0 <: led_tile0_shadow; + + // Update tile[1] GPIO LEDs via interface + led_if.all_off(); + + // Game mode indicators (D4=GAME, D5=FPS20, D6=FPS71, D7=3A) + switch (game_mode) { + case GAME_MODE_BYPASS: + led_if.led_on(TX1_GPIO_LED_D4); // D4 ON = BYPASS + break; + case GAME_MODE_FPS20: + led_if.led_on(TX1_GPIO_LED_D5); // D5 ON = FPS20 + break; + case GAME_MODE_FPS71: + led_if.led_on(TX1_GPIO_LED_D6); // D6 ON = FPS71 + break; + case GAME_MODE_3A: + led_if.led_on(TX1_GPIO_LED_D7); // D7 ON = 3A + break; + } + + // Feature mode indicators (D1=FOOTSTEPS, D3=GUNSHOT, D2=MIC_MUTE) + if (feature_mode == FEATURE_MODE_FOOTSTEPS_LEVEL) { + led_if.led_on(TX1_GPIO_LED_D1); + } + if (feature_mode == FEATURE_MODE_GUNSHOT_LEVEL) { + led_if.led_on(TX1_GPIO_LED_D3); + } + + // MIC mute indicator (D2) + if (mic_muted) { + led_if.led_on(TX1_GPIO_LED_D2); + } + } + break; case se_tmr when timerafter(se_time) :> void : se_time += SE_DELAY; @@ -1540,25 +1420,27 @@ extern void SetKeyFlag(unsigned x); /* 改动原因:与 AudioHwRemote2 一致——HID_DFU_EN=0 时不声明 c_dfu,避免 main 必须挂接无发送端的 streaming chan。 */ #if HID_DFU_EN -void AudioHwRemote(streaming chanend c, client interface c1_led_ctrl_if i_c1_led_ctrl, streaming chanend c_dfu) +void AudioHwRemote(streaming chanend c, streaming chanend c_dfu, client interface tx1_led_if led_if) { i2c_master_if i2c[1]; par { - i2c_master(i2c, 1, p_scl, p_sda, 100); - AudioHwRemote2(c, i2c[0], i_c1_led_ctrl, c_dfu); + /* 改动原因:与 golden_6ch 一致使用 300kHz I2C,原 100kHz 非 HTR3236 失效主因但统一时序 */ + i2c_master(i2c, 1, p_scl, p_sda, 300); + AudioHwRemote2(c, i2c[0], c_dfu, led_if); } } #else -void AudioHwRemote(streaming chanend c, client interface c1_led_ctrl_if i_c1_led_ctrl) +void AudioHwRemote(streaming chanend c, client interface tx1_led_if led_if) { i2c_master_if i2c[1]; par { - i2c_master(i2c, 1, p_scl, p_sda, 100); - AudioHwRemote2(c, i2c[0], i_c1_led_ctrl); + /* 改动原因:与 golden_6ch 一致使用 300kHz I2C,原 100kHz 非 HTR3236 失效主因但统一时序 */ + i2c_master(i2c, 1, p_scl, p_sda, 300); + AudioHwRemote2(c, i2c[0], led_if); } } #endif @@ -1568,8 +1450,7 @@ void AudioHwRemote(streaming chanend c, client interface c1_led_ctrl_if i_c1_led void AudioHwInit() { debug_printf("AudioHwInit\n"); - /* 改动原因:main 中 tile[0] 绑定 uc_audiohw 与 usb_audio_io→AudioHwInit 同属外层 par,无固定顺序;短延时让 USER_MAIN 核先跑完 unsafe。 - * 不能用普通全局标志跨 par 握手(违反 xC parallel usage rules)。 */ + delay_milliseconds(100); if((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) @@ -1588,11 +1469,13 @@ void AudioHwInit() } } - set_gpio(P_GPIO_MUTE, MUTE); - debug_printf("mute_dac ======== \n"); + // set_gpio(P_GPIO_MUTE, MUTE); + // debug_printf("mute_dac ======== \n"); delay_milliseconds(10); + debug_printf("AudioHwInit start codec_init\n"); + codec_init(); debug_printf("AudioHwInit completed\n"); @@ -1606,7 +1489,7 @@ void unmute_dac(void) { unsigned samFreq; GET_SHARED_GLOBAL(samFreq, g_samfreq); - set_gpio(P_GPIO_MUTE, UNMUTE); + // set_gpio(P_GPIO_MUTE, UNMUTE); debug_printf("unmute_dac ======== \n"); } @@ -1628,7 +1511,7 @@ void mute_dac(void) unsigned adc_loop; GET_SHARED_GLOBAL(adc_loop, g_adc_loop); - set_gpio(P_GPIO_MUTE, MUTE); + // set_gpio(P_GPIO_MUTE, MUTE); debug_printf("mute_dac %d======== \n", samFreq); #if 0 if (adc_loop == 0) @@ -1638,12 +1521,12 @@ void mute_dac(void) } else { - set_gpio(P_GPIO_MUTE, UNMUTE); + // set_gpio(P_GPIO_MUTE, UNMUTE); debug_printf("mute_dac %d======== \n", samFreq); } #endif #else - set_gpio(P_GPIO_MUTE, MUTE); + // set_gpio(P_GPIO_MUTE, MUTE); debug_printf("mute_dac %d======== \n", samFreq); #endif } @@ -1827,7 +1710,7 @@ void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, SET_SHARED_GLOBAL(g_samfreq, samFreq); SET_SHARED_GLOBAL(g_dsd_mode, dsdMode); - set_gpio(P_GPIO_MUTE, MUTE); + // set_gpio(P_GPIO_MUTE, MUTE); debug_printf("mute_dac %d======== \n", samFreq); delay_milliseconds(1); @@ -1896,106 +1779,3 @@ void AudioHwConfig_UnMute(void) debug_printf("don't unmute at boot\n"); } } - -// 改动原因: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; - // 改动原因:与 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; - } - - 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 &= ~0xF; - led_shadow |= (mode_green ? 0x0 : 0x1); - led_shadow |= (mode_blue ? 0x0 : 0x2); - led_shadow |= (mic_red ? 0x0 : 0x4); - led_shadow |= (mic_green ? 0x0 : 0x8); - p_leds <: led_shadow; - // 改动原因:该蓝灯当前不参与功能,保持熄灭(低电平有效下输出1表示灭)。 - p_mic_mute_led_blue <: 1; -} - -void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl) -{ - // 改动原因: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(); - - unsigned eq_mode_time = 0; - timer eq_mode_timer; - eq_mode_timer :> eq_mode_time; - eq_mode_time += EQ_MODE_DELAY; - - - - delay_milliseconds(100); - - - while(1) - { - unsafe { - select{ - case i_c1_led_ctrl.set_mode_led_color(unsigned color_idx): - // 改动原因: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, 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_v71/src/extensions/gpio_access.c b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/gpio_access.c deleted file mode 100644 index 573152e..0000000 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/gpio_access.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "gpio_access.h" -#include "swlock.h" -#include - -swlock_t gpo_swlock = SWLOCK_INITIAL_VALUE; - -void p_gpio_lock() -{ - swlock_acquire(&gpo_swlock); -} - -void p_gpio_unlock() -{ - swlock_release(&gpo_swlock); -} - -unsigned p_gpio_peek() -{ - unsigned portId, x; - - // Wrapped in lock to ensure it's safe from multiple logical cores - swlock_acquire(&gpo_swlock); - - asm("ldw %0, dp[p_gpio]":"=r"(portId)); - asm volatile("peek %0, res[%1]":"=r"(x):"r"(portId)); - - return x; -} - -void p_gpio_out(unsigned x) -{ - unsigned portId; - - asm("ldw %0, dp[p_gpio]":"=r"(portId)); - asm volatile("out res[%0], %1"::"r"(portId),"r"(x)); - - // Wrapped in lock to ensure it's safe from multiple logical cores - swlock_release(&gpo_swlock); -} - -void set_gpio(unsigned bit, unsigned value) -{ - unsigned port_shadow; - port_shadow = p_gpio_peek(); // Read port pin value - if (value == 0) port_shadow &= ~bit; // If writing a 0, generate mask and AND with current val - else port_shadow |= bit; // Else use mask and OR to set bit - p_gpio_out(port_shadow); // Write back to port. Will make port an output if not already -} - - diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/hidbuttons.xc b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/hidbuttons.xc index 538715a..635122f 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/hidbuttons.xc +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/hidbuttons.xc @@ -1,4 +1,3 @@ -#define DEBUG_PRINT_ENABLE 1 #include #include #include "xua_conf.h" @@ -12,101 +11,8 @@ #include "hid.h" #include "debug_print.h" -#if HID_CONTROLS > 0 +static unsigned char lastHidData; -#ifdef XSCOPE -#include "print.h" -#endif - -#ifdef DFU_CONTROL_USB_HID -#include - -#define HID_DFU_REPORT_ID 0x41 -#endif - -#define P_GPI_BUTA_SHIFT 0x00 -#define P_GPI_BUTA_MASK (1< tile[1] communication + interface tx1_led_if i_tx1_led; par { @@ -579,23 +582,16 @@ int main() key_sender(c_key); for (int i = 0; i < DSP_WORKER_COUNT; i++) uc_dsp_to_ex3d[i] = (chanend)c_dsp_to_ex3d[i]; - ex3d_task(c_ex3d_to_ubm); + ex3d_task(c_ex3d_to_ubm); } #endif } } - /* 改动原因:C1 硬件插拔检测与 DAC/MIC 哑音逻辑已并入 tile0 button_task(见 audiohw.xc),不再使用原 mute_handler + p_ctl_det 方案。 */ - on tile[1]: app_control_slave(i_c1_led_ctrl); + on tile[1]: tx1_led_helper_task(i_tx1_led); - /* 改动原因:XUA_AudioHub 与 AudioHwRemote/dsp 并行启动;AudioHwInit→codec_init 经 CODEC_REGWRITE 使用 uc_audiohw。 - * 若仅在 dsp_main 内赋值,AudioHub 先跑到 codec_init 时 uc_audiohw 未绑定会 ET_ILLEGAL_RESOURCE。 - * 与 fosi_c1 user_main.h 一致:在 tile[0]、启动 AudioHwRemote 之前绑定 streaming chan 发送端句柄。 */ on tile[0] : { - unsafe { - uc_audiohw = (streaming chanend)c_audiohw; - } - par { + par { { /* 改动原因:参数顺序与类型对齐 audiohw.xc 的 AudioHwRemote,修复链接阶段符号类型不一致。 */ { @@ -608,30 +604,33 @@ int main() #endif #if HID_DFU_EN - AudioHwRemote(c_audiohw, i_c1_led_ctrl, c_dfu); + AudioHwRemote(c_audiohw, c_dfu, i_tx1_led); #else - AudioHwRemote(c_audiohw, i_c1_led_ctrl); + AudioHwRemote(c_audiohw, i_tx1_led); #endif } } } } -#if EQ_EN == 1 on tile[0] : { - { + { + #if HID_DFU_EN unsafe { uc_dfu = (streaming chanend)c_dfu; } #endif + unsafe { + uc_audiohw = (streaming chanend)c_audiohw; + } +#if EQ_EN == 1 dsp_core0(); +#endif } } - /* 改动原因:uc_audiohw 已在上文 tile[0] AudioHwRemote 父块入口绑定,此处删除重复赋值,避免误读为唯一初始化点。 */ on tile[0] : { dsp_main(c_eq_data); } -#endif #if DNR_ENABLE == 1 on tile[0] : { dnr_dsp_proc_task(); } @@ -656,7 +655,7 @@ int main() #ifdef XUD_PRIORITY_HIGH set_core_high_priority_on(); #endif - /* Run UAC2.0 at high-speed, UAC1.0 at full-speed */ + /* Run UAC2.0 at high-speed, UAC1.0 at full-speed */ unsigned usbSpeed = (AUDIO_CLASS == 2) ? XUD_SPEED_HS : XUD_SPEED_FS; unsigned xudPwrCfg = (XUA_POWERMODE == XUA_POWERMODE_SELF) ? XUD_PWR_SELF : XUD_PWR_BUS; diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_helper.xc b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_helper.xc new file mode 100644 index 0000000..3af39f6 --- /dev/null +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_helper.xc @@ -0,0 +1,122 @@ +#include +#include +#include "user_main.h" + +// TX1 GPIO LEDs on tile[1] - port declarations (moved from audiohw.xc) +on tile[1]: out port p_led_d5 = XS1_PORT_1A; // FPS20 indicator +on tile[1]: out port p_led_d1 = XS1_PORT_1B; // FOOTSTEPS indicator +on tile[1]: out port p_led_d2 = XS1_PORT_1C; // MIC MUTE indicator +on tile[1]: out port p_led_d3 = XS1_PORT_4A; // GUNSHOT indicator (uses 4A bit3) +on tile[1]: out port p_led_d4_d7_d6 = XS1_PORT_4D; // bit3=D4_GAME, bit2=D7_3A, bit0=D6_FPS71 + +// TX1 HTR3236 RGB LED driver control +// 改动原因:与 xu316_qf60.xn 中 PORT_HTR3236_SDB 一致,避免硬编码端口与 xn 脱节 +on tile[1]: out port p_htr3236_sdb = PORT_HTR3236_SDB; +on tile[1]: out port p_ctl_mute = XS1_PORT_1F; // Amplifier mute control + +// tile[1] LED helper task - controls tile[1] GPIO LED ports +// Receives commands via tx1_led_if interface from AudioHwRemote2 on tile[0] +void tx1_led_helper_task(server interface tx1_led_if led_if) +{ + // Local state mirrors for tile[1] ports + unsigned d1_state = 1; // active low: 1=off, 0=on + unsigned d2_state = 1; + unsigned d3_state = 0xF; // 4-bit port, bit3 controls D3 + unsigned d5_state = 1; + unsigned d4_d7_d6_state = 0xF; // bit3=D4, bit2=D7, bit0=D6 + + // Init all LEDs off + p_led_d1 <: 1; + p_led_d2 <: 1; + p_led_d3 <: 0xF; + p_led_d5 <: 1; + p_led_d4_d7_d6 <: 0xF; + p_htr3236_sdb <: 0; // HTR3236 disabled initially + p_ctl_mute <: 1; // Muted initially + + while (1) + { + select + { + case led_if.led_on(tx1_gpio_led_t led): + switch (led) + { + case TX1_GPIO_LED_D1: d1_state = 0; p_led_d1 <: 0; break; + case TX1_GPIO_LED_D2: d2_state = 0; p_led_d2 <: 0; break; + case TX1_GPIO_LED_D3: d3_state &= ~0x8; p_led_d3 <: d3_state; break; + case TX1_GPIO_LED_D4: d4_d7_d6_state &= ~0x8; p_led_d4_d7_d6 <: d4_d7_d6_state; break; + case TX1_GPIO_LED_D5: d5_state = 0; p_led_d5 <: 0; break; + case TX1_GPIO_LED_D6: d4_d7_d6_state &= ~0x1; p_led_d4_d7_d6 <: d4_d7_d6_state; break; + case TX1_GPIO_LED_D7: d4_d7_d6_state &= ~0x4; p_led_d4_d7_d6 <: d4_d7_d6_state; break; + default: break; + } + break; + + case led_if.led_off(tx1_gpio_led_t led): + switch (led) + { + case TX1_GPIO_LED_D1: d1_state = 1; p_led_d1 <: 1; break; + case TX1_GPIO_LED_D2: d2_state = 1; p_led_d2 <: 1; break; + case TX1_GPIO_LED_D3: d3_state |= 0x8; p_led_d3 <: d3_state; break; + case TX1_GPIO_LED_D4: d4_d7_d6_state |= 0x8; p_led_d4_d7_d6 <: d4_d7_d6_state; break; + case TX1_GPIO_LED_D5: d5_state = 1; p_led_d5 <: 1; break; + case TX1_GPIO_LED_D6: d4_d7_d6_state |= 0x1; p_led_d4_d7_d6 <: d4_d7_d6_state; break; + case TX1_GPIO_LED_D7: d4_d7_d6_state |= 0x4; p_led_d4_d7_d6 <: d4_d7_d6_state; break; + default: break; + } + break; + + case led_if.set_d4_d7_d6(unsigned d4, unsigned d7, unsigned d6): + d4_d7_d6_state = 0xF; // all off + if (d4) d4_d7_d6_state &= ~0x8; + if (d7) d4_d7_d6_state &= ~0x4; + if (d6) d4_d7_d6_state &= ~0x1; + p_led_d4_d7_d6 <: d4_d7_d6_state; + break; + + case led_if.set_all_leds(unsigned d1, unsigned d2, unsigned d3, + unsigned d4, unsigned d5, unsigned d6, unsigned d7): + p_led_d1 <: d1 ? 0 : 1; + p_led_d2 <: d2 ? 0 : 1; + d3_state = d3 ? 0x0 : 0xF; + p_led_d3 <: d3_state; + p_led_d5 <: d5 ? 0 : 1; + d4_d7_d6_state = 0xF; + if (d4) d4_d7_d6_state &= ~0x8; + if (d7) d4_d7_d6_state &= ~0x4; + if (d6) d4_d7_d6_state &= ~0x1; + p_led_d4_d7_d6 <: d4_d7_d6_state; + break; + + case led_if.all_off(void): + p_led_d1 <: 1; + p_led_d2 <: 1; + p_led_d3 <: 0xF; + p_led_d5 <: 1; + p_led_d4_d7_d6 <: 0xF; + d1_state = 1; d2_state = 1; d3_state = 0xF; + d5_state = 1; d4_d7_d6_state = 0xF; + break; + + case led_if.set_htr3236_sdb(unsigned value): + p_htr3236_sdb <: value; + break; + + case led_if.set_mute(unsigned value): + //p_ctl_mute <: value; + break; + + case led_if.init(void): + p_led_d1 <: 1; + p_led_d2 <: 1; + p_led_d3 <: 0xF; + p_led_d5 <: 1; + p_led_d4_d7_d6 <: 0xF; + p_htr3236_sdb <: 1; // Enable HTR3236 + //p_ctl_mute <: 1; // Muted + d1_state = 1; d2_state = 1; d3_state = 0xF; + d5_state = 1; d4_d7_d6_state = 0xF; + break; + } + } +} diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/user_main.h b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/user_main.h index a311baa..f1694fb 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/user_main.h +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/user_main.h @@ -1,4 +1,3 @@ - #ifndef _USER_MAIN_H_ #define _USER_MAIN_H_ @@ -10,18 +9,48 @@ #include #include "DSBuild.h" -/* 改动原因:与 fosi_c1 一致,mode/mic 物理灯在 tile[1],tile[0] 的 button_task 通过 client interface 下发状态,由 app_control_slave 统一驱动 GPIO。 */ -interface c1_led_ctrl_if { - void set_mode_led_color(unsigned color_idx); - void set_mic_mute_state(unsigned mute_switch); - void set_mic_voice_fx(unsigned voice_fx_enabled); +#define USER_MAIN_DECLARATIONS + +// TX1 LED commands for tile[1] LED helper +typedef enum { + TX1_LED_CMD_NONE = 0, + TX1_LED_CMD_ON, // led_id + TX1_LED_CMD_OFF, // led_id + TX1_LED_CMD_SET_D4D7D6, // d4, d7, d6 (0/1 each, on=1) + TX1_LED_CMD_SET_ALL, // d1,d2,d3,d4,d5,d6,d7 (7 bytes, 0/1) + TX1_LED_CMD_HTR3236_SDB, // value (0/1) + TX1_LED_CMD_MUTE, // value (0/1) + TX1_LED_CMD_INIT, + TX1_LED_CMD_ALL_OFF +} tx1_led_cmd_t; + +// tile[1] GPIO LED IDs +typedef enum { + TX1_GPIO_LED_D1 = 0, // FOOTSTEPS + TX1_GPIO_LED_D2, // MIC MUTE + TX1_GPIO_LED_D3, // GUNSHOT + TX1_GPIO_LED_D4, // GAME/BYPASS + TX1_GPIO_LED_D5, // FPS20 + TX1_GPIO_LED_D6, // FPS71 + TX1_GPIO_LED_D7, // 3A + TX1_GPIO_LED_MAX +} tx1_gpio_led_t; + +// Interface for tile[1] LED control from tile[0] +interface tx1_led_if { + void led_on(tx1_gpio_led_t led); + void led_off(tx1_gpio_led_t led); + void set_d4_d7_d6(unsigned d4, unsigned d7, unsigned d6); + void set_all_leds(unsigned d1, unsigned d2, unsigned d3, + unsigned d4, unsigned d5, unsigned d6, unsigned d7); + void all_off(void); + void set_htr3236_sdb(unsigned value); + void set_mute(unsigned value); + void init(void); }; -void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl); - -/* 改动原因:v71 main.xc 自行展开任务拓扑,此处不注入额外 chan/interface 声明,避免宏续行空定义导致预处理异常。 */ -#define USER_MAIN_DECLARATIONS +void tx1_led_helper_task(server interface tx1_led_if led_if); #endif // __XC__ -#endif // _USER_MAIN_H_ +#endif // _USER_MAIN_H_ \ No newline at end of file