From 5ed3d0ee4074a980a2cc65525601ffcb004b95e1 Mon Sep 17 00:00:00 2001 From: Steven Dan Date: Tue, 2 Jun 2026 21:04:01 +0800 Subject: [PATCH] v71 led effects --- .../src/extensions/dsp.c | 46 ++++-- .../src/extensions/eq.c | 7 +- .../src/extensions/tx1_audio_level.c | 134 ++++++++++++++++++ .../src/extensions/tx1_audio_level.h | 61 ++++++++ .../src/extensions/tx1_led_effects.h | 3 + .../src/extensions/tx1_led_effects.xc | 57 +++----- 6 files changed, 258 insertions(+), 50 deletions(-) create mode 100644 sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.c create mode 100644 sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.h diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/dsp.c b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/dsp.c index c5011cd..5792d64 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/dsp.c +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/dsp.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -329,6 +330,12 @@ void UserBufferManagementInit(unsigned sampFreq) memset(ubm_ingress, 0, sizeof(ubm_ingress)); // 清掉哑帧输出 } float fLevel[NUM_USB_CHAN_OUT] = {0,}; +/* 改动原因:灯效/C 映射用 uint16 定点电平(0~65535),与 fLevel 同步,避免 .xc 传 float* 给 C */ +uint16_t uLevel[NUM_USB_CHAN_OUT] = {0,}; +/* 改动原因:每 DSP 块内保持峰值再写入 fLevel,供 HID/灯效读取,避免仅末采样值 */ +#if (HID_CONTROLS > 0) +static float fLevel_peak[NUM_USB_CHAN_OUT]; +#endif #if USE_EX3D == 1 && (HID_CONTROLS > 0) /* CMD_GET(CMD_LEVEL) = 0x8D | 0x0100 */ @@ -339,24 +346,19 @@ float fLevel[NUM_USB_CHAN_OUT] = {0,}; void ex3d_hid_fill_cmd_level_on_tile0(unsigned *send_buf_words, uint32_t ch_num) { unsigned idx = 1; - unsigned ex3d_en = 0; uint32_t ch; if (ch_num > (uint32_t)NUM_USB_CHAN_OUT) { ch_num = (uint32_t)NUM_USB_CHAN_OUT; } - GET_SHARED_GLOBAL(ex3d_en, g_3d_enable); send_buf_words[idx++] = EX3D_HID_CMD_GET_LEVEL; for (ch = 0; ch < ch_num; ch++) { union { float f; unsigned u; } conv; - if (ex3d_en) { - conv.f = fLevel[ch]; - } else { - conv.f = 0.0f; - } + /* 改动原因:CMD_LEVEL 定义为通道电平读取,返回输入真实电平,不受 3D 开关影响 */ + conv.f = fLevel[ch]; send_buf_words[idx++] = conv.u; } } @@ -381,20 +383,33 @@ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudi #if (HID_CONTROLS > 0) AUDIO_T absVal, maxVal; #endif + /* 改动原因:新 DSP 块开始时清零峰值累加器 */ +#if (HID_CONTROLS > 0) + if (frame_index == 0) { + for (int pch = 0; pch < NUM_USB_CHAN_OUT; pch++) { + fLevel_peak[pch] = 0.0f; + } + } +#endif + //Frame the samples going from the usb to the DAC into frames of 8 for(int ch=0;ch 0) + float lvl; maxVal = 0; absVal = ubm_egress[ch][frame_index]; if(absVal < 0) absVal = -absVal; if(maxVal < absVal) maxVal = absVal; #if defined(AUDIO_T_16) - fLevel[ch] = (float)maxVal / 32768; + lvl = (float)maxVal / 32768; #else - fLevel[ch] = (float)maxVal / 2147483648; + lvl = (float)maxVal / 2147483648; #endif + if (ch < NUM_USB_CHAN_OUT && lvl > fLevel_peak[ch]) { + fLevel_peak[ch] = lvl; + } #endif } @@ -457,6 +472,19 @@ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudi if(frame_index == DSP_BLOCK_LENGTH){ // When the frame is full then send out the mul;ti-channel data to the FIR processors on tile 0 then tile 1. +#if (HID_CONTROLS > 0) + for (int pch = 0; pch < NUM_USB_CHAN_OUT; pch++) { + fLevel[pch] = fLevel_peak[pch]; + /* 改动原因:方位灯 tx1_audio_level 接口使用 uLevel[](uint16 满幅=65535) */ + if (fLevel_peak[pch] <= 0.0f) { + uLevel[pch] = 0u; + } else if (fLevel_peak[pch] >= 1.0f) { + uLevel[pch] = 65535u; + } else { + uLevel[pch] = (uint16_t)(fLevel_peak[pch] * 65535.0f + 0.5f); + } + } +#endif frame_index = 0; chan_out_buf_word(uc_ex3d_to_ubm, (const uint32_t *)ubm_egress, UBM_TO_EX3D_CHANS * DSP_BLOCK_LENGTH); // And get a stereo frames worth of data back from the mixer process diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/eq.c b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/eq.c index 7c5adda..c37da56 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/eq.c +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/eq.c @@ -841,8 +841,6 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) { // 多数命令经 g_ex3d_hid_chanend 到 tile1;CMD_LEVEL(0x18D) 在 tile0 读 fLevel,不转发 tile1 if (data[1] == 0xB0 || data[1] == 0xB1) { #if (USE_EX3D == 1) && (HID_CONTROLS == 1) - if (!g_ex3d_hid_chanend) return false; - // 提取EX3D命令码(4字节,小端序) uint32_t ex3d_cmd = (uint32_t)data[2] | ((uint32_t)data[3] << 8) | ((uint32_t)data[4] << 16) | ((uint32_t)data[5] << 24); @@ -856,7 +854,8 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) { ex3d_request.pending_cmd = data[1]; /* 改动原因:HID/UBM 同在 tile0,电平由 UserBufferManagement 写入 fLevel[]; - * GET CMD_LEVEL 无需经 tile1,避免读 tile1 空副本。 */ + * GET CMD_LEVEL 无需经 tile1,避免读 tile1 空副本。 + * 同时避免 g_ex3d_hid_chanend 未就绪时被提前 return false。 */ if (data[1] == 0xB1 && ex3d_cmd == 0x18Du) { uint32_t ch_num = 0; @@ -869,6 +868,8 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) { return true; } + if (!g_ex3d_hid_chanend) return false; + // 若是SET CMD_EXPAND_GAIN (0x93),同步更新footstep LED状态 if (data[1] == 0xB0 && ex3d_cmd == 0x93 && params_len >= 4) { uint32_t gain_val = (uint32_t)data[6] | ((uint32_t)data[7] << 8) | diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.c b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.c new file mode 100644 index 0000000..2dd2cf2 --- /dev/null +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.c @@ -0,0 +1,134 @@ +/** + * @file tx1_audio_level.c + * @brief fLevel → 方位灯 PWM 映射(纯 C,可在 PC 上运行 tx1_audio_level_host_test.c) + */ +#include "tx1_audio_level.h" +#include + +/* 改动原因:顺时针星形灯位 — 12点 FC=D1, 11点 FL=D12, 1点 FR=D2, 9点 SL=D10, 3点 SR=D4, 8点 BL=D9, 4点 BR=D5 */ +const uint8_t tx1_star_led_dindex[TX1_AZIMUTH_MAX] = { + 12, 1, 2, 10, 4, 9, 5 +}; + +/* 改动原因:uLevel 满幅 65535,与归一化 fLevel [0,1] 对应 */ +#define TX1_LEVEL_U16_MAX 65535u +/* 静音门限:归一化电平低于此视为无声(约等于 u16 < 197) */ +#define TX1_LEVEL_SILENCE_F 0.003f +#define TX1_LEVEL_SILENCE_U16 ((uint16_t)(TX1_LEVEL_SILENCE_F * (float)TX1_LEVEL_U16_MAX)) +/* 显示增益:典型聆听电平映射到可见亮度(可在实机微调) */ +#define TX1_LEVEL_DISPLAY_GAIN 5.0f +#define TX1_LEVEL_PWM_MAX 255u + +static float tx1_clamp01(float x) +{ + if (x <= 0.0f) { + return 0.0f; + } + if (x >= 1.0f) { + return 1.0f; + } + return x; +} + +uint8_t tx1_audio_level_float_to_pwm(float level_norm) +{ + float scaled; + + level_norm = tx1_clamp01(level_norm); + if (level_norm < TX1_LEVEL_SILENCE_F) { + return 0; + } + + scaled = level_norm * TX1_LEVEL_DISPLAY_GAIN; + if (scaled > 1.0f) { + scaled = 1.0f; + } + return (uint8_t)(scaled * (float)TX1_LEVEL_PWM_MAX + 0.5f); +} + +/* 改动原因:usb_levels 为 uint16 定点,先转 [0,1] 再走既有增益/门限逻辑 */ +static uint8_t tx1_audio_level_u16_to_pwm(uint16_t level_u16) +{ + float level_norm; + + if (level_u16 < TX1_LEVEL_SILENCE_U16) { + return 0; + } + level_norm = (float)level_u16 / (float)TX1_LEVEL_U16_MAX; + return tx1_audio_level_float_to_pwm(level_norm); +} + +void tx1_audio_level_map_usb_to_azimuth(const uint16_t *usb_levels, int num_usb, + uint8_t *azimuth_pwm) +{ + uint16_t z = 0u; + uint16_t fl = z, fr = z, fc = z, bl = z, br = z, sl = z, sr = z; + + if (azimuth_pwm == NULL) { + return; + } + + if (usb_levels != NULL && num_usb > 0) { + if (num_usb > 0) fl = usb_levels[0]; + if (num_usb > 1) fr = usb_levels[1]; + if (num_usb > 2) fc = usb_levels[2]; + /* usb[3]=LFE 不参与星形灯 */ + if (num_usb > 4) bl = usb_levels[4]; + if (num_usb > 5) br = usb_levels[5]; + if (num_usb > 6) sl = usb_levels[6]; + if (num_usb > 7) sr = usb_levels[7]; + } + + azimuth_pwm[TX1_AZ_CH_FL] = tx1_audio_level_u16_to_pwm(fl); + azimuth_pwm[TX1_AZ_CH_FC] = tx1_audio_level_u16_to_pwm(fc); + azimuth_pwm[TX1_AZ_CH_FR] = tx1_audio_level_u16_to_pwm(fr); + azimuth_pwm[TX1_AZ_CH_SL] = tx1_audio_level_u16_to_pwm(sl); + azimuth_pwm[TX1_AZ_CH_SR] = tx1_audio_level_u16_to_pwm(sr); + azimuth_pwm[TX1_AZ_CH_BL] = tx1_audio_level_u16_to_pwm(bl); + azimuth_pwm[TX1_AZ_CH_BR] = tx1_audio_level_u16_to_pwm(br); +} + +void tx1_audio_level_apply_fps20_star_mask(uint8_t *azimuth_pwm) +{ + int ch; + + for (ch = 0; ch < TX1_AZIMUTH_MAX; ch++) { + if (ch != TX1_AZ_CH_SL && ch != TX1_AZ_CH_SR) { + azimuth_pwm[ch] = 0; + } + } +} + +static void tx1_audio_level_apply_fps20_flfr_only(uint8_t *azimuth_pwm) +{ + uint8_t fl; + uint8_t fr; + int ch; + + if (azimuth_pwm == NULL) { + return; + } + + /* 改动原因:FPS2.0 仅 SL(9点) 与 SR(3点) 两颗星激活,分别显示 FL/FR 幅值 */ + fl = azimuth_pwm[TX1_AZ_CH_FL]; + fr = azimuth_pwm[TX1_AZ_CH_FR]; + + for (ch = 0; ch < TX1_AZIMUTH_MAX; ch++) { + azimuth_pwm[ch] = 0; + } + azimuth_pwm[TX1_AZ_CH_SL] = fl; + azimuth_pwm[TX1_AZ_CH_SR] = fr; +} + +void tx1_audio_level_refresh_azimuth_pwm(const uint16_t *usb_levels, int num_usb, + unsigned game_mode, + uint8_t *out_pwm) +{ + tx1_audio_level_map_usb_to_azimuth(usb_levels, num_usb, out_pwm); + + /* 改动原因:FPS2.0 用 SL/SR 两灯显示 FL/FR;不再显示原 SL/SR 声道 */ + if (game_mode == TX1_GAME_MODE_FPS20) { + tx1_audio_level_apply_fps20_flfr_only(out_pwm); + } + /* FPS71 / 3A:7 颗星(FC,FL,FR,SL,SR,BL,BR)均随幅值变化,不做掩码 */ +} diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.h b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.h new file mode 100644 index 0000000..47fd27b --- /dev/null +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_audio_level.h @@ -0,0 +1,61 @@ +/** + * @file tx1_audio_level.h + * @brief USB fLevel → 方位星形灯亮度(0~255),供 tx1_led_effects 与主机侧单元测试 + * + * 改动原因:方位 RGB 需按声道实时亮度;电平来自 tile0 UserBufferManagement 的 uLevel[](0~65535,由 fLevel 量化)。 + * USB 8ch 顺序与 dsp.c 一致:0=FL,1=FR,2=FC,3=LFE,4=BL,5=BR,6=SL,7=SR。 + * 星形灯 D 编号(顺时针,12 点=FC):FL D12, FC D1, FR D2, SL D10, SR D4, BL D9, BR D5。 + */ +#ifndef TX1_AUDIO_LEVEL_H +#define TX1_AUDIO_LEVEL_H + +#include + +#ifndef TX1_AZIMUTH_MAX +#define TX1_AZIMUTH_MAX 7 +#endif + +/* 与 audiohw tx1_game_mode_t 一致:0=FPS20, 1=FPS71, 2=3A */ +#define TX1_GAME_MODE_FPS20 0u +#define TX1_GAME_MODE_FPS71 1u +#define TX1_GAME_MODE_3A 2u + +typedef enum { + TX1_AZ_CH_FL = 0, + TX1_AZ_CH_FC = 1, + TX1_AZ_CH_FR = 2, + TX1_AZ_CH_SL = 3, + TX1_AZ_CH_SR = 4, + TX1_AZ_CH_BL = 5, + TX1_AZ_CH_BR = 6 +} tx1_azimuth_ch_t; + +/** D1~D12 星形灯索引(1-based),与 tx1_rgb_led_map 一致 */ +extern const uint8_t tx1_star_led_dindex[TX1_AZIMUTH_MAX]; + +/** + * 将归一化电平 [0,1] 映射为 PWM 亮度 [0,255](含静音门限与增益,便于与中低音量匹配) + */ +uint8_t tx1_audio_level_float_to_pwm(float level_norm); + +/** + * USB uLevel[0..num_usb-1](uint16 0~65535,满幅=65535)→ 7 路方位亮度(未做 FPS20 掩码) + */ +/* 改动原因:与 HID/灯效统一用定点电平;XCC 下指针须 *unsafe(同 user_func.h) */ +#ifdef __XC__ +void tx1_audio_level_map_usb_to_azimuth(const uint16_t *unsafe usb_levels, int num_usb, + uint8_t *unsafe azimuth_pwm); +void tx1_audio_level_apply_fps20_star_mask(uint8_t *unsafe azimuth_pwm); +void tx1_audio_level_refresh_azimuth_pwm(const uint16_t *unsafe usb_levels, int num_usb, + unsigned game_mode, + uint8_t *unsafe out_pwm); +#else +void tx1_audio_level_map_usb_to_azimuth(const uint16_t *usb_levels, int num_usb, + uint8_t *azimuth_pwm); +void tx1_audio_level_apply_fps20_star_mask(uint8_t *azimuth_pwm); +void tx1_audio_level_refresh_azimuth_pwm(const uint16_t *usb_levels, int num_usb, + unsigned game_mode, + uint8_t *out_pwm); +#endif + +#endif /* TX1_AUDIO_LEVEL_H */ diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.h b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.h index 92d73e8..3684a66 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.h +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.h @@ -57,4 +57,7 @@ extern uint8_t g_tx1_audio_voltage[TX1_AZIMUTH_MAX]; void tx1_azimuth_clear_all_decay(void); void tx1_azimuth_update_all_voltages(const uint8_t voltages[TX1_AZIMUTH_MAX]); +/* 改动原因:从 tile0 UserBufferManagement 的 uLevel[] 刷新方位亮度后驱动星形 RGB */ +void tx1_azimuth_refresh_from_flevel(unsigned game_mode); + #endif /* TX1_LED_EFFECTS_H */ diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.xc b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.xc index 65320bb..b976f79 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.xc +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/tx1_led_effects.xc @@ -5,9 +5,14 @@ #include "tx1_led_effects.h" #include "tx1_rgb_brightness.h" #include "tx1_ex3d_game.h" +#include "tx1_audio_level.h" +#include "xua_conf.h" #include "xc_ptr.h" #include +/* 改动原因:uLevel 在 tile0 dsp.c 与 fLevel 同步更新,供 C 灯效映射(uint16 0~65535) */ +extern uint16_t uLevel[NUM_USB_CHAN_OUT]; + #define TX1_RGB_LED_MAX 12 /* 改动原因:灯效亮度与 jok rgb_led_set_global_brightness(10) 一致,使用 TX1_RGB_SCALE8 */ @@ -373,27 +378,21 @@ static void tx1_effect_gradient(htr3236_t *dev, client interface i2c_master_if i #define TX1_MODE3A_COLOR_G TX1_RGB_SCALE8(91) #define TX1_MODE3A_COLOR_B TX1_RGB_SCALE8(246) -/* jok channel_led_map: FL D12, FC D1, FR D2, SL D10, SR D4, RL D9, RR D5 */ -static const uint8_t tx1_azimuth_led_index[TX1_AZIMUTH_MAX] = { - 12, 1, 2, 10, 4, 9, 5 -}; - uint8_t g_tx1_audio_voltage[TX1_AZIMUTH_MAX] = {0}; static uint8_t tx1_azimuth_brightness[TX1_AZIMUTH_MAX] = {0}; -static unsigned tx1_azimuth_fx_step = 0; - -/* 改动原因:与 jok CURRENT_TEST TEST_SCAN_CCW 一致,无实时电平输入时演示方位灯效 */ -#define TX1_AZIMUTH_SCAN_HOLD 4 - -static int tx1_cw_hold_count = 0; -static int tx1_cw_current_index = 0; - -static const int tx1_scan_ccw_order[TX1_AZIMUTH_MAX] = { - 0, 3, 5, 6, 4, 2, 1 /* FL→SL→RL→RR→SR→FR→FC,同 jok counterclockwise_order */ -}; static uint8_t tx1_fmax_u8(uint8_t a, uint8_t b) { return (a > b) ? a : b; } +/* 改动原因:用 uLevel 驱动 g_tx1_audio_voltage,再经既有 FPS/3A 衰减渲染到星形灯 */ +void tx1_azimuth_refresh_from_flevel(unsigned game_mode) +{ + /* 改动原因:C 实现(tx1_audio_level.c) 的指针与 XC 调用须 unsafe 块匹配,否则最终 xcc 链接报类型不一致 */ + unsafe { + tx1_audio_level_refresh_azimuth_pwm(uLevel, NUM_USB_CHAN_OUT, game_mode, + g_tx1_audio_voltage); + } +} + void tx1_azimuth_clear_all_decay(void) { int ch; @@ -410,21 +409,6 @@ void tx1_azimuth_update_all_voltages(const uint8_t voltages[TX1_AZIMUTH_MAX]) } } -/* 改动原因:jok test_scan_counterclockwise,每 50ms 步进驱动 g_tx1_audio_voltage */ -static void tx1_azimuth_test_scan_ccw(void) -{ - uint8_t voltages[TX1_AZIMUTH_MAX] = {0}; - - if (tx1_cw_hold_count >= TX1_AZIMUTH_SCAN_HOLD) { - tx1_cw_hold_count = 0; - tx1_cw_current_index = (tx1_cw_current_index + 1) % TX1_AZIMUTH_MAX; - } - voltages[tx1_scan_ccw_order[tx1_cw_current_index]] = 255; - tx1_cw_hold_count++; - tx1_azimuth_clear_all_decay(); - tx1_azimuth_update_all_voltages(voltages); -} - static void tx1_azimuth_update_fps(htr3236_t *dev, client interface i2c_master_if i2c) { uint8_t new_brightness[TX1_AZIMUTH_MAX] = {0}; @@ -453,7 +437,7 @@ static void tx1_azimuth_update_fps(htr3236_t *dev, client interface i2c_master_i uint8_t r = (TX1_FPS_COLOR_R * new_brightness[ch]) / 255; uint8_t g = (TX1_FPS_COLOR_G * new_brightness[ch]) / 255; uint8_t b = (TX1_FPS_COLOR_B * new_brightness[ch]) / 255; - tx1_fx_pwm_led(dev, i2c, tx1_azimuth_led_index[ch], r, g, b); + tx1_fx_pwm_led(dev, i2c, tx1_star_led_dindex[ch], r, g, b); } } tx1_fx_update(dev, i2c); @@ -488,7 +472,7 @@ static void tx1_azimuth_update_3a(htr3236_t *dev, client interface i2c_master_if uint8_t r = (TX1_MODE3A_COLOR_R * brightness) / 255; uint8_t g = (TX1_MODE3A_COLOR_G * brightness) / 255; uint8_t b = (TX1_MODE3A_COLOR_B * brightness) / 255; - tx1_fx_pwm_led(dev, i2c, tx1_azimuth_led_index[ch], r, g, b); + tx1_fx_pwm_led(dev, i2c, tx1_star_led_dindex[ch], r, g, b); } } tx1_fx_update(dev, i2c); @@ -517,7 +501,6 @@ void tx1_led_effects_periodic(htr3236_t *dev, client interface i2c_master_if i2c unsigned feature_mode, unsigned led_pattern_step) { - (void)game_mode; (void)led_pattern_step; if (g_tx1_factory_reset_state != TX1_FACTORY_RESET_IDLE) { @@ -529,10 +512,8 @@ void tx1_led_effects_periodic(htr3236_t *dev, client interface i2c_master_if i2c return; } - tx1_azimuth_fx_step++; - - /* 改动原因:三档均有 EX3D 方位灯效,不再区分 BYPASS 装饰灯效 */ - tx1_azimuth_test_scan_ccw(); + /* 改动原因:实时电平来自 tile0 uLevel;FPS20 仅 SL/SR,7.1 档 7 颗星全亮 */ + tx1_azimuth_refresh_from_flevel(game_mode); tx1_azimuth_effect_loop(dev, i2c); return;