fix(keys): 插孔消抖 + 音量 ramp 3s 上限 + 亮度写日志 — 耳机插拔 ADC 幽灵音量键修复

真机实证(meow_20260901_034946.log): 4.4 插入瞬间电气瞬态在 jz_adc_aux(event2)
产生 VOL_UP 幽灵按住, vol_ramp 24%→上限50 (225391 ramp 起→227213 爬满,
紧随 audiod jack changed). 修(限 meow_launcherd/+meow_watchdog/):
① launcher audio.c + watchdog 各自读 /sys/class/switch/{headset,balance}/state
  (节流缓存 1s/500ms, 热路径不每圈读文件), 变化后 800ms 内忽略音量键边沿
  (vol_ramp_begin 不起/在爬 ramp 中止/wd_vol_adj 单步忽略)
② ramp 总时长上限 VOL_RAMP_MAX_MS=3000 兜底防一次幽灵打满(正常长按 24→50 ~1.4s 不伤)
③ write_brightness(val,src) 全 10 调用点带源+逐写 logmsg, 亮度跳上限下次可定位
  (grep 全库: 写 backlight 仅 launcher/watchdog/svc_power/bootmenu, 无确定 255 路径)
宿主: 新 test_vol_ramp_jack 15/15 PASS(单击/长按回归+3s cap+消抖忽略/中止/恢复);
test_wd_fw 17/17 + test_settings_brightness + test_notif_tf PASS; MIPS -Wall -Wextra 0 warning
(顺带修 watchdog 既有 sys/poll.h→poll.h 重定向 warning).
watchdog 已热更设备 /usr/data(baa997ea); launcher 7be1d4eb 待固件. fw_content.conf 已更新.
遗留: SDK meow_ui_input.c 音量键路径需同款消抖(sdk/ 有主未动)
This commit is contained in:
MeowOS committed 2026-09-01 04:28:10 +08:00
1 parent 44d170413d
commit 4bafdb5d69
13 files changed
+348 -20

No files matched your search

Binary file not shown.
+63 -4
View File
@@ -20,6 +20,8 @@
* 让位,绝不与 launcher 抢屏/抢键);launcher 画菜单,本进程不自绘。
* 电源长按 ≥8s -> 强制关机兜底(仅当菜单未生效/launcher 未接管)。
* 音量±(115/114) -> 写真实 DAC(CS43198 amixer numid=1/2)+ 持久化 settings.conf(同 launcher 同源)。
* 插孔消抖:/sys/class/switch/{headset,balance} 变化后 800ms 内忽略音量键边沿
* (插拔电气瞬态会在 ADC 键上产生幽灵按下,真机实证 2026-09-01)。
* 播放/上下曲(164/165/163/19) -> 捕获 + 日志 + 消费,不路由(媒体会话落地后转活跃会话)。
* (8s 强关的「防误触 / pm_interacted」逻辑在 launcher 的 show_power_menu 内,此进程只做兜底。)
* - M2.86(226) SDK 框架 App 让位:启动时经 /proc/<pid>/exe 读同目录 app.json 的 framework
@@ -46,7 +48,7 @@
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <poll.h>
#include <sys/syscall.h>
#include <stdint.h>
#include <time.h>
@@ -379,6 +381,55 @@ static void wd_vol_save(void)
wd_log("vol: saved volume=%d(max=%d,step=%d)", wd_vol, wd_vol_max, wd_vol_step);
}
/* ---- 插孔消抖(2026-09-01,与 launcher audio.c 同款,真机日志实证)----
* 4.4/3.5 耳机插拔的电气瞬态在音量键 ADC(jz_adc_aux,event2)上产生幽灵按下
* (launcher 侧实证:VOL_UP 假按住 → ramp 24%→上限 50,紧随 audiod「jack changed」)。
* /sys/class/switch/{headset,balance}/state 任一变化后 WD_JACK_DEBOUNCE_MS 内忽略音量键
* 边沿(插拔耳机时没人按音量,误伤可忽略)。读文件走节流缓存,不每圈读。 */
#define WD_JACK_HS_STATE "/sys/class/switch/headset/state"
#define WD_JACK_BAL_STATE "/sys/class/switch/balance/state"
#define WD_JACK_POLL_MS 500 /* 节流读取间隔(主循环 100ms,5 圈一读) */
#define WD_JACK_DEBOUNCE_MS 800 /* 插孔变化后忽略音量键边沿的窗口 */
static int wd_jack_combo = -1; /* hs*2+bal;-1=未初始化/节点缺失 */
static unsigned long long wd_jack_poll_at = 0;
static unsigned long long wd_jack_changed_at = 0; /* 0=未检测到变化 */
static int wd_read_int_file(const char *path)
{
int fd = open(path, O_RDONLY);
if (fd < 0) return -1;
char buf[16];
int n = read(fd, buf, sizeof buf - 1);
close(fd);
if (n <= 0) return -1;
buf[n] = 0;
return atoi(buf);
}
static void wd_jack_tick(void)
{
unsigned long long now = now_ms();
if (now - wd_jack_poll_at < WD_JACK_POLL_MS) return;
wd_jack_poll_at = now;
int hs = wd_read_int_file(WD_JACK_HS_STATE);
int bal = wd_read_int_file(WD_JACK_BAL_STATE);
if (hs < 0 && bal < 0) return; /* 节点缺失:不更新缓存,不误判变化 */
int c = (hs > 0 ? 2 : 0) | (bal > 0 ? 1 : 0);
if (wd_jack_combo >= 0 && c != wd_jack_combo) {
wd_jack_changed_at = now;
wd_log("jack state changed (%d -> %d), vol-key debounce %dms",
wd_jack_combo, c, WD_JACK_DEBOUNCE_MS);
}
wd_jack_combo = c;
}
static int wd_jack_debounce(void)
{
return wd_jack_changed_at &&
(now_ms() - wd_jack_changed_at < (unsigned long long)WD_JACK_DEBOUNCE_MS);
}
/* 音量步进:+1/-1(每按下边沿一次;clamp 到极大/最小)。 */
static void wd_vol_adj(int dir)
{
@@ -612,10 +663,17 @@ int main(int argc, char **argv)
} else if (type == EV_KEY && code == KEY_POWER) {
handle_power(val); /* M2.22(A)/M2.24:电源单击=息屏/亮屏,长按 tick 里判菜单 */
} else if (type == EV_KEY && code == KEY_VOLUMEUP) {
/* M2.86(226):SDK 框架 App 前台 -> 音量键让位 SDK(防双步进)。 */
if (val == 1 && !g_fw_app) wd_vol_adj(+1); /* M2.24:音量+ = 系统音量 */
/* M2.86(226):SDK 框架 App 前台 -> 音量键让位 SDK(防双步进)。
* 插孔消抖:插拔瞬态的 ADC 幽灵按下直接忽略。 */
if (val == 1 && !g_fw_app) {
if (wd_jack_debounce()) wd_log("volume UP ignored (jack debounce)");
else wd_vol_adj(+1); /* M2.24:音量+ = 系统音量 */
}
} else if (type == EV_KEY && code == KEY_VOLUMEDOWN) {
if (val == 1 && !g_fw_app) wd_vol_adj(-1); /* M2.24:音量- = 系统音量 */
if (val == 1 && !g_fw_app) {
if (wd_jack_debounce()) wd_log("volume DOWN ignored (jack debounce)");
else wd_vol_adj(-1); /* M2.24:音量- = 系统音量 */
}
} else if (type == EV_KEY && (code == KEY_PLAYPAUSE || code == KEY_PREVIOUSSONG ||
code == KEY_NEXTSONG || code == KEY_PREVIOUS)) {
/* M2.86(226):框架 App 前台 -> 媒体键让位 SDK(接媒体会话路由)。 */
@@ -626,6 +684,7 @@ int main(int argc, char **argv)
}
}
wd_power_tick(); /* M2.24:电源长按检测(3s 菜单 / 8s 强关 / 菜单期让位) */
wd_jack_tick(); /* 插孔状态节流轮询(消抖音量键幽灵按下) */
elapsed += 100;
}
return 0;