feat(meowpanel): 阶段C收尾——实时画面+远程遥控 (agent-224) — /api/screen.jpeg(fb0活动帧→自研最小baseline JPEG编码器,480x720≈24KB/帧,无libm零依赖) + /api/input/tap(坐标注入,BTN_TOUCH先行时序,本机触摸优先5s仲裁); 前端「屏幕」页(1fps可调,点击映射,息屏提示)

meowpanel→e98aec66 已部署; 真机验证: jpeg非全黑+注入tap拉起Files(日志+截图双证)
注: 注入走 write event1(实测本机可投递,未用uinput)
This commit is contained in:
MeowOS committed 2026-08-31 16:21:11 +08:00
1 parent 6c78a88b8c
commit fbdd77a72e
8 files changed
+333 -7

No files matched your search

+41 -4
View File
@@ -28,10 +28,12 @@ cd /home/Aska/Project/R3ProII/patch_v2/meowpanel
- 两分支均以 `-Os -Wall -Wextra` 复核,**0 warning**。
- 产出(本次构建实测):
- `meowpanel`:mipsel 静态,`ELF 32-bit LSB executable, MIPS, MIPS32 rel2, statically linked, stripped`,
体积约 **183 KB**(固件阈值内)。md5:`f91856a44de0c8d12aba00cd40b44b91`。
- `meowpanel_host`:aarch64 动态链接(宿主编译,仅供调试),体积约 **142 KB**。
体积约 **202 KB**(固件阈值内)。md5:`e98aec6682b7387a035ab5f63c6777e7`。
- `meowpanel_host`:aarch64 动态链接(宿主编译,仅供调试),体积约 **146 KB**。
- 依赖:仅 libc + Linux 内核头(`linux/input.h`),零第三方库(设备无 python3/lua)。鉴权用**内联 SHA-256**(拷贝自
`meow_verify/sha256.c` 公有领域参考写法,前缀 `mp_sha256_*` 避免符号冲突;**未改 `meow_verify/` 目录**)。
阶段 C 实时画面用**自研最小 baseline JPEG 编码器** `mp_jpeg.c`(顺序 DCT + 4:2:0 + 标准 Huffman 表 Annex K;
无 libm、零依赖,仅 malloc/realloc),质量 70 下 480×720 帧约 24 KB。
- 头文件引用:`-I patch_v2/meow_launcherd`(`meow_ipc.h` 帧格式 / `m_perf_*`/`m_power_*`/`POWER_*`,
**header 为权威源**,结构体字段以它为准)。
@@ -78,6 +80,8 @@ http://<host>.local:8080/
| 方法 | 路径 | 说明 | 实现 |
|---|---|---|---|
| GET | `/`、`/meowpanel.css`、`/meowpanel.js`、`/assets/<f>` | 静态托管 | ✅ |
| GET | `/api/screen.jpeg` | 实时画面:fb0 当前帧 → RGB565→JPEG(`?q=1-100` 质量,默认 70) | ✅(阶段 C) |
| POST | `/api/input/tap` | 触摸注入:`{x,y}`(480×720 原生坐标;write 进 goodix event1,本机实测可投递);本机触摸后 5s 内忽略注入 | ✅(阶段 C) |
| GET | `/api/auth/status` | 鉴权状态(enabled/会话有效) | ✅(公开) |
| POST | `/api/auth/login` | 密码登录发 token(sha256 带盐校验) | ✅(公开;错→401) |
| POST | `/api/auth/logout` | 登出失效 token | ✅(公开;幂等) |
@@ -233,6 +237,25 @@ http://<host>.local:8080/
首次进入以 `/api/auth/status` 决定是否弹登录。设置页「面板鉴权」卡片含开关(`panel.auth_enabled`)+「设置/修改密码」
按钮(`panel.auth_pass`,走 `passwordDlg` 输入)。
### 5.10 实时画面(`/api/screen.jpeg`)+ 触摸注入(`/api/input/tap`)— 阶段 C
- **实时画面**:`GET /api/screen.jpeg` 读 `/dev/fb0` **当前显示帧**(`FBIOGET_VSCREENINFO` 取 `yoffset`/`xres`/`yres`/`bpp`,
`FBIOGET_FSCREENINFO` 取 `line_length`,`pread` 活动缓冲,**只读,不影响渲染**;16bpp RGB565)→
`mp_jpeg_encode_rgb565()` 编码为内存 JPEG(自研最小 baseline 编码器,见 §1),返回 `Content-Type: image/jpeg`。
`?q=1-100` 控制质量(默认 70)。恢复 `line_length != xres*2`(行尾填充)时先压缩为紧凑 RGB565。
- **触摸注入**:`POST /api/input/tap`,body `{x,y}`(0..479 × 0..719 原生像素坐标,前端按 480×720 映射,后端再 clamp)。
**机制 = write 进 goodix evdev(`/dev/input/event1`)**——**本机实测 write 注入可投递**(见 §7 修正历史结论),
事件序列与真实 goodix 一致:先 `BTN_TOUCH=1`(按下边沿)**后** `ABS_MT_*`/`ABS_X/Y`(坐标),`SYN` → 按住 100ms →
`BTN_TOUCH=0` + `ABS_MT_TRACKING_ID=-1` + `SYN`。**关键**:launcher/`meow_touch` 在按下边沿会**重置坐标 -1**,
只在 down 之后到来的首个有效 ABS 才锁原点(goodix 时序免疫)——故坐标必须**在 BTN_TOUCH=1 之后**,否则原点永不
锁定 → 抬手被判无效 tap(只高亮不启动)。注入前不写 uinput(本设备厂商内核 write 进 goodix 即可投递,逐 UB 少)。
- **仲裁(本机优先打断)**:注入前 `touch_last_local_ms()` 排空 event1,取「最近一次本机真实触摸」的单调毫秒时间
(剔除本进程自注入事件:事件时间 ≤ 上次注入时刻+200ms),若 `now-last < 5000` → **忽略注入**,返回
`{"dispatched":false,"reason":"local_touch_active","cooldown_ms":N}`;否则注入并返回 `{"dispatched":true,"x","y"}`。
MIPS 的 `struct input_event` 无 `time` 成员(ABI),按 launcher 同款读裸 16 字节取偏移 0/4 的 `tv_sec/tv_usec`(单调时钟)。
- **前端「屏幕」页**(`web/#/screen`,导航「屏幕」):`<img>` 轮询 `GET /api/screen.jpeg?t=…&q=70`(`fetch`→blob→objectURL,
防重叠 + 旧 URL 回收;后端不可达提示「后端未连接」);默认 **1fps**,滑条 **0.2–2fps**(存 `screen.fps`,页面隐藏/切走即停刷,
`visibilitychange` 回前台续刷);点击画面按 480×720 比例换算坐标 → `POST /api/input/tap`,`dispatched:false` 时 toast「本机触摸中」。
---
## 6. 与协议的出入(「实现为准 + 原因」,供回改 MEOWPANEL_PROTOCOL.md)
@@ -259,6 +282,9 @@ http://<host>.local:8080/
恒 ENOTDIR 失败)。上传体上限 `MAX_UPLOAD_BODY`=8MB,超限 → 413 `PAYLOAD_TOO_LARGE`。
10. **TF 卡根可覆盖(宿主测试)**:`env MEOW_TF_ROOT` 覆盖卡根(设备上不设,恒用 `/usr/data/mnt/sd_0`);`env MEOW_NOTIF_LOG`
覆盖通知转储日志路径。设 `MEOW_TF_ROOT` 时 `tf_present()` 恒真(测试用)。
11. **实时画面/触摸注入(阶段 C)**:协议 §6 待定案项称「实时画面(`/api/frame` 等,本文件暂未定义)」。本面板落地为
**`GET /api/screen.jpeg` + `POST /api/input/tap`**(命名自定:`.jpeg` 表达二进制帧 + `input/tap` 表达触摸注入),
见 §5.10。回改协议时可补这两端点(以及 `frames` 语义、`/api/input/tap` 的 `dispatched:false/reason` 软失败约定)。
---
@@ -282,6 +308,15 @@ http://<host>.local:8080/
- **上传为「限长缓冲」非全流式**:multipart 请求体整体读入(上限 8MB,超限 413),下载为流式(8KB 分块)。严格「socket 逐字节流式上传
解析」未实现(需增量 multipart 解析器),列为后续;14MB 内存约束下 8MB 上限 + 流式下载已覆盖大文件读侧。
- **存储为 `meowpanel` 编译时刻写死**的 socket/路径会因 `--sock-perf/--sock-power`(qemu sim)可覆盖,但默认走 `/usr/data/meow_*.sock`。
- **触摸注入在设备息屏时不生效**:launcher 主界面在 `meow_screen_on==0` 时**不处理触摸**(main_menu.c,息屏防误触);设备自动息屏
(30s 空闲)后注入的 tap 会被 launcher 忽略——面板无法用触摸唤醒(需先电源键点亮)。前端「屏幕」页已提示「设备息屏请先点亮」;
对「正在看」设备的正常使用场景(屏幕亮着)注入即有效。
- **实时画面读取 fb0 当前帧(只读)**:双层缓冲下 `pread` 活动缓冲,存在翻页瞬间撕裂一行的可能(1fps 预览可接受);
`/dev/fb0` 不可读/非 16bpp → 500 `INTERNAL`(绝不静默)。
- **JPEG 编码器为 baseline 4:2:0**:质量 70 下 480×720 ≈ 24KB;质量越高体积越大(`q=100` 约 60-80KB)。编码为单线程
串行(面板本就单线程),一帧编码约几十 ms(MIPS 单核),1fps 轮询无压力。
- **触摸注入为即时性注入**:不维护长按/多指手势状态机(与按键注入一致);`dispatched:false`(本机触摸仲裁)属软失败,
前端可按 `reason` 提示,不视为错误。
---
@@ -289,9 +324,11 @@ http://<host>.local:8080/
```
patch_v2/meowpanel/
├── meowpanel.c # 后端源码(单文件,约 3667 行,-Wall -Wextra 0 warning;含可选鉴权/内联 SHA-256)
├── meowpanel.c # 后端源码(约 3650 行,-Wall -Wextra 0 warning;含可选鉴权/内联 SHA-256/实时画面/触摸注入)
├── mp_jpeg.c # 最小 baseline JPEG 编码器(顺序 DCT + 4:2:0 + 标准 Huffman,无 libm,-Wall -Wextra 0 warning)
├── mp_jpeg.h # mp_jpeg.c 接口(RGB565 → 内存 JPEG)
├── build_meowpanel.sh # 交叉编译 + host 分支(-Wall -Wextra 0 warning)
├── meowpanel # 交叉产物(mipsel 静态,约 183 KB,md5 f91856a4…)
├── meowpanel # 交叉产物(mipsel 静态,约 202 KB,md5 e98aec66…)
├── meowpanel_host # 宿主编译(本机 ld,调试用)
├── services.d/
│ └── meowpanel.conf # 部署到 TF 卡 MeowOS/services.d/meowpanel.conf