implement gunshot and footstep feature volume control

Map feature bar 0-12 to CMD_LMT_THRESHOLD (-35..0) and CMD_EXPAND_GAIN (0..20). Panel VOL+/- saves to Flash, syncs tile1 via 0xFA/0xFD, and reports 0xB1 GET to host. HID SET from eq.c also persists and applies.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Steven Dan
2026-06-01 14:49:30 +08:00
parent c71149219c
commit 454f291286
4 changed files with 293 additions and 16 deletions

View File

@@ -573,8 +573,123 @@ static void tx1_apply_mic_hid_level(unsigned hid_level)
SET_SHARED_GLOBAL(g_request_mic_volume_set, 1);
}
/* 改动原因:枪声/脚步 feature 条 0~12 格映射 EX3D 协议范围LMT -35~0 dBEXPAND 0~20 */
#define TX1_LMT_THRESHOLD_MIN (-35)
#define TX1_LMT_THRESHOLD_MAX (0)
#define TX1_EXPAND_GAIN_MAX 20
static int tx1_bar_to_lmt_threshold(unsigned bar)
{
if (bar > TX1_VOL_BAR_MAX) {
bar = TX1_VOL_BAR_MAX;
}
return TX1_LMT_THRESHOLD_MIN +
(int)((bar * 35u + (TX1_VOL_BAR_MAX / 2u)) / TX1_VOL_BAR_MAX);
}
static unsigned tx1_bar_to_expand_gain(unsigned bar)
{
if (bar > TX1_VOL_BAR_MAX) {
bar = TX1_VOL_BAR_MAX;
}
return (bar * 20u + (TX1_VOL_BAR_MAX / 2u)) / TX1_VOL_BAR_MAX;
}
static unsigned tx1_lmt_threshold_to_bar(int threshold)
{
if (threshold < TX1_LMT_THRESHOLD_MIN) {
threshold = TX1_LMT_THRESHOLD_MIN;
}
if (threshold > TX1_LMT_THRESHOLD_MAX) {
threshold = TX1_LMT_THRESHOLD_MAX;
}
return (unsigned)((threshold - TX1_LMT_THRESHOLD_MIN) * TX1_VOL_BAR_MAX + 17) / 35u;
}
static unsigned tx1_expand_gain_to_bar(unsigned gain)
{
if (gain > TX1_EXPAND_GAIN_MAX) {
gain = TX1_EXPAND_GAIN_MAX;
}
return (gain * TX1_VOL_BAR_MAX + 10u) / 20u;
}
static void tx1_send_lmt_threshold_to_tile1(chanend cc_mic_level, int threshold)
{
if (threshold < TX1_LMT_THRESHOLD_MIN) {
threshold = TX1_LMT_THRESHOLD_MIN;
}
if (threshold > TX1_LMT_THRESHOLD_MAX) {
threshold = TX1_LMT_THRESHOLD_MAX;
}
cc_mic_level <: TX1_CC_CMD_LMT_THRESHOLD;
cc_mic_level <: (unsigned)threshold;
debug_printf("cc_mic_level send lmt_threshold=%d\n", threshold);
}
static void tx1_send_expand_gain_to_tile1(chanend cc_mic_level, unsigned gain)
{
if (gain > TX1_EXPAND_GAIN_MAX) {
gain = TX1_EXPAND_GAIN_MAX;
}
cc_mic_level <: TX1_CC_CMD_EXPAND_GAIN;
cc_mic_level <: gain;
debug_printf("cc_mic_level send expand_gain=%u\n", gain);
}
/* 改动原因:面板调节枪声/脚步后,按 0xB1 GET_EX3D 格式主动上报,便于主机同步 UI */
static void tx1_hid_report_ex3d_get_value(unsigned ex3d_get_cmd, int value)
{
unsigned uval = (unsigned)value;
unsafe {
unsigned char * unsafe reportPtr = g_hid_pass_data;
reportPtr[0] = 0x77;
reportPtr[1] = 0xB1;
reportPtr[2] = (unsigned char)(ex3d_get_cmd & 0xFF);
reportPtr[3] = (unsigned char)((ex3d_get_cmd >> 8) & 0xFF);
reportPtr[4] = (unsigned char)((ex3d_get_cmd >> 16) & 0xFF);
reportPtr[5] = (unsigned char)((ex3d_get_cmd >> 24) & 0xFF);
reportPtr[6] = (unsigned char)(uval & 0xFF);
reportPtr[7] = (unsigned char)((uval >> 8) & 0xFF);
reportPtr[8] = (unsigned char)((uval >> 16) & 0xFF);
reportPtr[9] = (unsigned char)((uval >> 24) & 0xFF);
for (int i = 10; i < 63; i++) {
reportPtr[i] = 0x00;
}
hidSetChangePending(0x1);
}
}
static unsigned tx1_apply_gunshot_bar(unsigned bar, chanend cc_mic_level, int &gunshot_thr)
{
int th = tx1_bar_to_lmt_threshold(bar);
unsigned char save_code = tx1_lmt_threshold_to_save_code(th);
gunshot_thr = th;
tx1_save_lmt_threshold_code(save_code);
tx1_send_lmt_threshold_to_tile1(cc_mic_level, th);
tx1_hid_report_ex3d_get_value(TX1_HID_GET_LMT_THRESHOLD, th);
debug_printf("TX1: gunshot bar=%u threshold=%d\n", bar, th);
return 1;
}
static unsigned tx1_apply_footstep_bar(unsigned bar, chanend cc_mic_level, unsigned &footstep_gain)
{
unsigned gain = tx1_bar_to_expand_gain(bar);
footstep_gain = gain;
tx1_save_expand_gain((unsigned char)gain);
tx1_send_expand_gain_to_tile1(cc_mic_level, gain);
tx1_hid_report_ex3d_get_value(TX1_HID_GET_EXPAND_GAIN, (int)gain);
debug_printf("TX1: footstep bar=%u expand_gain=%u\n", bar, gain);
return 1;
}
/* 改动原因FPS 切换 feature 时,把当前硬件音量同步到 0~12 格 RGB 条 */
static void tx1_sync_feature_volume_from_hw(tx1_feature_mode_t mode, unsigned &feature_volume)
static void tx1_sync_feature_volume_from_hw(tx1_feature_mode_t mode, unsigned &feature_volume,
int gunshot_thr, unsigned footstep_gain)
{
unsigned hid;
@@ -587,6 +702,12 @@ static void tx1_sync_feature_volume_from_hw(tx1_feature_mode_t mode, unsigned &f
GET_SHARED_GLOBAL(hid, g_mic_volume_level);
feature_volume = tx1_hid_level_to_bar(hid);
break;
case FEATURE_MODE_GUNSHOT_LEVEL:
feature_volume = tx1_lmt_threshold_to_bar(gunshot_thr);
break;
case FEATURE_MODE_FOOTSTEPS_LEVEL:
feature_volume = tx1_expand_gain_to_bar(footstep_gain);
break;
default:
break;
}
@@ -838,7 +959,8 @@ static void tx1_sync_game_mode_state(unsigned mode, unsigned persist,
* SYSTEM_VOLUME 按 12 格步进 DAC HID(0~48) 并写寄存器+FlashMIC_LEVEL 同理写 ADC。
* 返回 1 表示需要 gpio_leds_dirty。
*/
static unsigned tx1_vol_plus_step(tx1_feature_mode_t mode, unsigned &feature_volume)
static unsigned tx1_vol_plus_step(tx1_feature_mode_t mode, unsigned &feature_volume,
chanend cc_mic_level, int &gunshot_thr, unsigned &footstep_gain)
{
switch (mode) {
case FEATURE_MODE_NONE:
@@ -857,11 +979,17 @@ static unsigned tx1_vol_plus_step(tx1_feature_mode_t mode, unsigned &feature_vol
return 1;
}
case FEATURE_MODE_GUNSHOT_LEVEL:
case FEATURE_MODE_FOOTSTEPS_LEVEL:
if (feature_volume < TX1_VOL_BAR_MAX) {
feature_volume++;
if (feature_volume >= TX1_VOL_BAR_MAX) {
return 0;
}
return 1;
feature_volume++;
return tx1_apply_gunshot_bar(feature_volume, cc_mic_level, gunshot_thr);
case FEATURE_MODE_FOOTSTEPS_LEVEL:
if (feature_volume >= TX1_VOL_BAR_MAX) {
return 0;
}
feature_volume++;
return tx1_apply_footstep_bar(feature_volume, cc_mic_level, footstep_gain);
case FEATURE_MODE_MIC_LEVEL:
if (feature_volume < TX1_VOL_BAR_MAX) {
feature_volume++;
@@ -876,7 +1004,8 @@ static unsigned tx1_vol_plus_step(tx1_feature_mode_t mode, unsigned &feature_vol
/**
* 改动原因:对齐 jok on_vol_minus_short_press逻辑同 tx1_vol_plus_step 方向相反。
*/
static unsigned tx1_vol_minus_step(tx1_feature_mode_t mode, unsigned &feature_volume)
static unsigned tx1_vol_minus_step(tx1_feature_mode_t mode, unsigned &feature_volume,
chanend cc_mic_level, int &gunshot_thr, unsigned &footstep_gain)
{
switch (mode) {
case FEATURE_MODE_NONE:
@@ -895,11 +1024,17 @@ static unsigned tx1_vol_minus_step(tx1_feature_mode_t mode, unsigned &feature_vo
return 1;
}
case FEATURE_MODE_GUNSHOT_LEVEL:
case FEATURE_MODE_FOOTSTEPS_LEVEL:
if (feature_volume > 0) {
feature_volume--;
if (feature_volume == 0) {
return 0;
}
return 1;
feature_volume--;
return tx1_apply_gunshot_bar(feature_volume, cc_mic_level, gunshot_thr);
case FEATURE_MODE_FOOTSTEPS_LEVEL:
if (feature_volume == 0) {
return 0;
}
feature_volume--;
return tx1_apply_footstep_bar(feature_volume, cc_mic_level, footstep_gain);
case FEATURE_MODE_MIC_LEVEL:
if (feature_volume > 0) {
feature_volume--;
@@ -975,6 +1110,7 @@ static void tx1_send_ex3d_onoff_to_tile1(chanend cc_mic_level, unsigned onoff)
cc_mic_level <: onoff;
debug_printf("cc_mic_level send ex3d_onoff=%u\n", onoff);
}
/* 改动原因c_dfu 仅接收 FIRMWARE_UPGRADE_START在此线程执行 handle_firmware_upgrade_start。
* 移除未使用的 chanend c_erase原占位参数无任何 select/通信,会导致 main 侧被迫接 dummy 通道且与当前拓扑无关。 */
#if HID_DFU_EN
@@ -1009,6 +1145,9 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
/* 改动原因:超时退出后再次 FPS 短按恢复上次调节项;首次进入默认系统音量。 */
tx1_feature_mode_t last_feature_mode = FEATURE_MODE_SYSTEM_VOLUME;
unsigned feature_volume = 12; // 改动原因:与 jok ui_app gunshot/footstep/mic 默认 12 一致
/* 改动原因:枪声 LMT_THRESHOLD(-35~0)、脚步 EXPAND_GAIN(0~20),与 EX3D HID 一致,断电 Flash 恢复 */
int gunshot_lmt_threshold = -15;
unsigned footstep_expand_gain = 12;
unsigned mic_muted = 0;
/* 改动原因:与 phaten golden 相同 LFS 键名,断电保存 MIC 静音255=首次无记录默认未静音 */
unsigned char mic_mute_path[] = "mic_mute";
@@ -1126,6 +1265,18 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
debug_printf("TX1: Loaded game_mode from flash: %u\n", (unsigned)game_mode);
}
/* 改动原因:开机从 Flash 恢复枪声阈值/脚步增益并同步 tile1 EX3D0xFA/0xFD */
{
unsigned char lmt_code = tx1_load_lmt_threshold_code();
unsigned char exp_gain = tx1_load_expand_gain();
gunshot_lmt_threshold = tx1_lmt_threshold_from_save_code(lmt_code);
footstep_expand_gain = (unsigned)exp_gain;
tx1_send_lmt_threshold_to_tile1(cc_mic_level, gunshot_lmt_threshold);
tx1_send_expand_gain_to_tile1(cc_mic_level, footstep_expand_gain);
debug_printf("TX1: Loaded ex3d lmt=%d expand=%u\n", gunshot_lmt_threshold, footstep_expand_gain);
}
#if defined(FPS71_UAC2)
debug_printf("FPS71_UAC2 running, g_3d_fps=%u\n", (unsigned)game_mode);
#endif
@@ -1305,6 +1456,43 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
}
}
/* 改动原因HID 0xB0 SET CMD_LMT_THRESHOLD/EXPAND_GAIN 经 eq.c 置位后,保存 Flash 并同步 tile1 */
{
unsigned req_lmt;
GET_SHARED_GLOBAL(req_lmt, g_hid_lmt_threshold_request);
if (req_lmt != (unsigned)-1) {
SET_SHARED_GLOBAL(g_hid_lmt_threshold_request, (unsigned)-1);
if (req_lmt >= 1 && req_lmt <= 36) {
gunshot_lmt_threshold = tx1_lmt_threshold_from_save_code((unsigned char)req_lmt);
tx1_save_lmt_threshold_code((unsigned char)req_lmt);
tx1_send_lmt_threshold_to_tile1(cc_mic_level, gunshot_lmt_threshold);
if (feature_mode == FEATURE_MODE_GUNSHOT_LEVEL) {
feature_volume = tx1_lmt_threshold_to_bar(gunshot_lmt_threshold);
gpio_leds_dirty = 1;
}
debug_printf("HID SET LMT_THRESHOLD: save_code=%u thr=%d\n",
req_lmt, gunshot_lmt_threshold);
}
}
}
{
unsigned req_exp;
GET_SHARED_GLOBAL(req_exp, g_hid_expand_gain_request);
if (req_exp != (unsigned)-1) {
SET_SHARED_GLOBAL(g_hid_expand_gain_request, (unsigned)-1);
if (req_exp <= TX1_EXPAND_GAIN_MAX) {
footstep_expand_gain = req_exp;
tx1_save_expand_gain((unsigned char)req_exp);
tx1_send_expand_gain_to_tile1(cc_mic_level, footstep_expand_gain);
if (feature_mode == FEATURE_MODE_FOOTSTEPS_LEVEL) {
feature_volume = tx1_expand_gain_to_bar(footstep_expand_gain);
gpio_leds_dirty = 1;
}
debug_printf("HID SET EXPAND_GAIN: %u\n", footstep_expand_gain);
}
}
}
GET_SHARED_GLOBAL(dac_vol, g_dac_vol);
GET_SHARED_GLOBAL(adc_vol, g_adc_vol);
unsigned mute_switch;
@@ -1880,7 +2068,9 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
if (!fps_long_fired && (now - fps_press_time) < 1000000000ull) {
tx1_feature_mode_fps_short_press(feature_mode, last_feature_mode);
feature_timeout_ticks = 0;
tx1_sync_feature_volume_from_hw(feature_mode, feature_volume);
tx1_sync_feature_volume_from_hw(feature_mode, feature_volume,
gunshot_lmt_threshold,
footstep_expand_gain);
gpio_leds_dirty = 1;
debug_printf("TX1: FPS short press - feature_mode=%d last=%d\n",
feature_mode, last_feature_mode);
@@ -1942,7 +2132,8 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
} else {
if (!vol_plus_long_fired
&& (now - vol_plus_press_time) < TX1_LONG_PRESS_TICKS) {
if (tx1_vol_plus_step(feature_mode, feature_volume)) {
if (tx1_vol_plus_step(feature_mode, feature_volume, cc_mic_level,
gunshot_lmt_threshold, footstep_expand_gain)) {
/* 改动原因:在 feature 模式下检测到 VOL+ 有效加值后,立即清零超时计数,
* 防止用户持续调节时被 TX1_FEATURE_TIMEOUT_MAX 误判超时退出。 */
feature_timeout_ticks = 0;
@@ -1961,7 +2152,8 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
static unsigned last_vol_plus_trigger = 0;
if ((now - last_vol_plus_trigger) >= TX1_VOL_REPEAT_TICKS) {
last_vol_plus_trigger = now;
if (tx1_vol_plus_step(feature_mode, feature_volume)) {
if (tx1_vol_plus_step(feature_mode, feature_volume, cc_mic_level,
gunshot_lmt_threshold, footstep_expand_gain)) {
/* 改动原因:长按连发期间每次检测到 VOL+ 有效加值都重置 feature_timeout_ticks
* 保证 feature 页面在用户连续操作时保持激活。 */
feature_timeout_ticks = 0;
@@ -1978,7 +2170,8 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
} else {
if (!vol_minus_long_fired
&& (now - vol_minus_press_time) < TX1_LONG_PRESS_TICKS) {
if (tx1_vol_minus_step(feature_mode, feature_volume)) {
if (tx1_vol_minus_step(feature_mode, feature_volume, cc_mic_level,
gunshot_lmt_threshold, footstep_expand_gain)) {
/* 改动原因:在 feature 模式下检测到 VOL- 有效减值后,立即清零超时计数,
* 避免用户调整参数时触发 feature 超时返回。 */
feature_timeout_ticks = 0;
@@ -1997,7 +2190,8 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface
static unsigned last_vol_minus_trigger = 0;
if ((now - last_vol_minus_trigger) >= TX1_VOL_REPEAT_TICKS) {
last_vol_minus_trigger = now;
if (tx1_vol_minus_step(feature_mode, feature_volume)) {
if (tx1_vol_minus_step(feature_mode, feature_volume, cc_mic_level,
gunshot_lmt_threshold, footstep_expand_gain)) {
/* 改动原因:长按连发期间每次检测到 VOL- 有效减值都重置 feature_timeout_ticks
* 与短按行为一致,避免连续减值过程中超时退出。 */
feature_timeout_ticks = 0;

View File

@@ -36,4 +36,12 @@ extern unsigned g_3d_enable;
/* tile0 audiohw → tile1 hid_button_task0xFB + onoff(0/1) → audio_ex3d_set_onoff */
#define TX1_CC_CMD_EX3D_ONOFF 0xFB
/* tile0 → tile1与 dsp.c hid_button_task 中 0xFA/0xFD 一致 */
#define TX1_CC_CMD_LMT_THRESHOLD 0xFA
#define TX1_CC_CMD_EXPAND_GAIN 0xFD
/* 主动 HID 上报用 GET 命令码ex3d_protocol CMD_GET */
#define TX1_HID_GET_LMT_THRESHOLD 0x187
#define TX1_HID_GET_EXPAND_GAIN 0x193
#endif /* TX1_EX3D_GAME_H */

View File

@@ -185,6 +185,73 @@ unsigned char tx1_load_mic_volume(void)
return v;
}
/* 改动原因Flash 存 save_code=(-threshold)+1范围 1~36避免 0 作未初始化哨兵(与 eq.c HID 一致) */
static unsigned char tx1_lmt_thr_lfs_path[] = "tx1_lmt_thr";
static unsigned char tx1_expand_gain_lfs_path[] = "tx1_exp_gain";
void tx1_save_lmt_threshold_code(unsigned char save_code)
{
if (save_code < 1) {
save_code = 1;
}
if (save_code > 36) {
save_code = 36;
}
save_value(tx1_lmt_thr_lfs_path, save_code);
}
unsigned char tx1_load_lmt_threshold_code(void)
{
unsigned char v = load_value(tx1_lmt_thr_lfs_path);
if (v == 255 || v < 1 || v > 36) {
v = tx1_lmt_threshold_to_save_code(-15);
save_value(tx1_lmt_thr_lfs_path, v);
}
return v;
}
int tx1_lmt_threshold_from_save_code(unsigned char save_code)
{
if (save_code < 1) {
save_code = 1;
}
if (save_code > 36) {
save_code = 36;
}
return -(int)(save_code - 1);
}
unsigned char tx1_lmt_threshold_to_save_code(int threshold)
{
if (threshold > 0) {
threshold = 0;
}
if (threshold < -35) {
threshold = -35;
}
return (unsigned char)(-threshold + 1);
}
void tx1_save_expand_gain(unsigned char gain)
{
if (gain > 20) {
gain = 20;
}
save_value(tx1_expand_gain_lfs_path, gain);
}
unsigned char tx1_load_expand_gain(void)
{
unsigned char v = load_value(tx1_expand_gain_lfs_path);
if (v == 255 || v > 20) {
v = 12;
save_value(tx1_expand_gain_lfs_path, v);
}
return v;
}
unsigned char load_value(unsigned char *path)
{
unsigned char value = 255;

View File

@@ -70,5 +70,13 @@ unsigned char tx1_load_dac_volume(void);
void tx1_save_mic_volume(unsigned char level);
unsigned char tx1_load_mic_volume(void);
/* 改动原因:枪声 CMD_LMT_THRESHOLD(-35~0) 与脚步声 CMD_EXPAND_GAIN(0~20) 断电记忆,编码同 eq.c HID 0xB0 */
void tx1_save_lmt_threshold_code(unsigned char save_code);
unsigned char tx1_load_lmt_threshold_code(void);
int tx1_lmt_threshold_from_save_code(unsigned char save_code);
unsigned char tx1_lmt_threshold_to_save_code(int threshold);
void tx1_save_expand_gain(unsigned char gain);
unsigned char tx1_load_expand_gain(void);
#endif