v71 led effects

This commit is contained in:
Steven Dan
2026-06-02 21:04:01 +08:00
parent 40315d2826
commit 5ed3d0ee40
6 changed files with 258 additions and 50 deletions

View File

@@ -4,6 +4,7 @@
#include <xs1.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <xcore/parallel.h>
#include <xcore/channel.h>
#include <xcore/hwtimer.h>
@@ -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<UBM_TO_EX3D_CHANS;ch++) {
ubm_egress[ch][frame_index] = sampsFromUsbToAudio[ch];
#if (HID_CONTROLS > 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

View File

@@ -841,8 +841,6 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
// 多数命令经 g_ex3d_hid_chanend 到 tile1CMD_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) |

View File

@@ -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 <stddef.h>
/* 改动原因:顺时针星形灯位 — 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 / 3A7 颗星FC,FL,FR,SL,SR,BL,BR均随幅值变化不做掩码 */
}

View File

@@ -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 点=FCFL D12, FC D1, FR D2, SL D10, SR D4, BL D9, BR D5。
*/
#ifndef TX1_AUDIO_LEVEL_H
#define TX1_AUDIO_LEVEL_H
#include <stdint.h>
#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 */

View File

@@ -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 */

View File

@@ -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 <string.h>
/* 改动原因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 uLevelFPS20 仅 SL/SR7.1 档 7 颗星全亮 */
tx1_azimuth_refresh_from_flevel(game_mode);
tx1_azimuth_effect_loop(dev, i2c);
return;