Files
qianbian/docs/protocol.md
T

153 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BLE 协议规范(4.2寸墨水屏设备 · 实现标准)
> 状态:**单一事实来源**。实现 `src/ppclock` 以本文件为准。
> 证据来源:`analysis/web/protocol-raw.md`(Web JS),APK/固件互证结果以"互证"标注;未互证项以 ⚠ 标注。
## 1. 设备与 GATT
| 项 | 值 |
|---|---|
| 广播名前缀 | `NRF-` |
| EPD Service | `13187b10-eba9-a3ba-044e-83d3217d9a38` |
| EPD Characteristic(图像+刷屏,write+notify) | `4b646063-6264-f3a7-8941-e65356ea82fe` |
| RXTX Service | `00001f10-0000-1000-8000-00805f9b34fb` |
| RXTX Characteristic(命令,write+read+notify) | `00001f1f-0000-1000-8000-00805f9b34fb` |
| `0000221f-...` | 预留,未使用 |
连接顺序:先 EPD service → 再 RXTX;写均用 write-with-response(`triggerRxTxCmd2` 例外,without-response)。
## 2. 屏幕参数
| 参数 | 值 |
|---|---|
| 分辨率 | 400 × 300 |
| 色彩 | 黑/白/红 三色(亦可切黑白模式) |
| 像素打包 | 1bpp,MSB first,行主序(y:0→300, x:0→400) |
| 平面 | bw 平面 15000B + 红平面 15000B(红仅三色模式) |
| bw 位值 | R,G,B 任一>0 → 1(白),全 0 → 0(黑)⚠即"非黑即白" |
| 红平面位值 | R>0,G=0,B=0 → 1(红) |
| 日历小图 | 280×100(3500B)或 400×180(9000B),同 1bpp |
## 3. 帧格式
### 3.1 图像数据块(EPD 通道)
```
[cod:1B][code:1B][offset:2B BE][payload:≤240B]
```
| 字段 | 值 |
|---|---|
| cod | `03`=整图;`04`=日历小图(数据总长 3500B 或 9000B 时) |
| code | `ff`=bw 平面;`00`=红平面 |
| offset | 本块在平面内的字节偏移,大端 |
| payload | ≤240 字节;按 offset 顺序连发,块间无应用层 ACK |
结束:全部块发完延时 ≥300ms → 整图发 `01`;日历小图发 `AA`。
### 3.2 刷屏(EPD 通道)
`00{param}` 后接 `01`。
### 3.3 时间设置(RXTX 通道)
```
dd [unix:4B BE][year:2B BE][month:1B][day:1B][week:1B] → 随后发 e2
```
- unix = 本地时区修正秒(`now_utc + tz`);week:周一=1 … 周日=7。
- 测试向量:2026-07-24 15:30:00 (UTC+8) 周五 → `dd 6982a7f0 07ea 07 18 05`(unix=1785475800=0x6982A7D8 ⚠按实现时实际值校验,此处仅示意格式)→ 待真机/互证校准。
### 3.4 倒计时(RXTX 通道)
- 日期:`ff00{YYYY}{MM}{DD}`(时钟界面)/ `ffff{YYYY}{MM}{DD}`(日历界面);YYYY=4 位十进制 ASCII。
- 前缀文字位图(时钟界面,16px 字格):≤4 字符(中文=1,英文=0.5)单包 `0{charCount}{位图hex}`;>4 拆两包:`04{前128B}` 然后 `0{charCount}{剩余}`。
- 前缀文字位图(日历界面,24px 字格):每字符一包 `990{索引}{72B}`,包间隔 1s。
- 位图打包:1bpp MSB first 行主序。
- 收尾 `E2`;关闭倒计时 `FA` → 1s → `E2`。
- 日历中文字设置:`990*` → `FA` → `e10103` → `E2`。
### 3.5 激活与设备 ID(RXTX 通道)
1. 请求 ID:发 `EFEF` → notify 收 **14 字节**(可打印即 ASCII,否则 hex 表示)。
2. 激活码:原流程 `GET http://4638e813e4.qicp.vip:8889/key_generator.php?id={用户ID}&key={设备ID}` → 返回 ≥32 hex(正则 `激活码1:([0-9A-F]{32,})`)。⚠算法在服务端,本地化方案见 §7。
3. 下发:`EF{激活码hex大写}` → 400ms → `e2`。
### 3.6 WiFi 配置(RXTX 通道)
ASCII UTF-8 直发:`WIFI_SSID:{ssid};WIFI_PASS:{pass};CITY:{城市代码}`(城市代码为天气代码,如 `101010100`)。
## 4. 命令 opcode 总表(RXTX 通道,除注明外)
| 命令 | 含义 |
|---|---|
| `e2` | 提交/刷新(多数命令收尾) |
| `dd…` | 设置时间(§3.3) |
| `2300` / `2301` | 三色模式 / 黑白模式 |
| `14` | 12/24 小时制切换 |
| `15` | 时钟颜色切换 |
| `e3` | 反色模式 |
| `e4` | 时钟字体切换 |
| `e5` | 旋转 180° |
| `e10000`–`e10003` | 图片模式:显示图一~图四 |
| `e10103` / `e10104` / `e10105` | 日历模式一/二/三 |
| `e10201` / `e10202` / `e10203` | 时钟模式一/二/三 |
| `E6{01-0f}` / `E6{10-f0}` | 红 / 黑 LUT 校准(越大越深;0 无效) |
| `FB01{HH}{MM}` / `FB00{HH}{MM}` | 开启 / 关闭休眠时段 |
| `e901{n}{01\|00}` | 轮播间隔 n(01=分钟,00=小时) |
| `EA0{0-3}` | 上传目标槽位(图一~图四) |
| `EA000{0-3}` | 轮播数量 1–4(值=n-1) |
| `EF{hex}` | 激活码下发 |
| `EF{数字逐位双写}` | 停车牌号码("12"→`EF1122`) |
| `EFEF` | 请求设备 ID |
| `FA` | 关闭倒计时 |
| `ff00…` / `ffff…` / `990…` / `04…` / `0…` | 倒计时(§3.4) |
| `00{xx}`+`01`(EPD) | 刷屏 |
| `01`(EPD) | 整图传输结束刷新 |
| `AA`(EPD) | 小图传输结束 |
模式切换命令(`e1xx`/`23xx`/`14`/`15`/`e3`-`e5`)发后 300ms 补 `e2`(setri 模式)。
## 5. 抖动算法参数(图像管线)
| 算法 | 参数 |
|---|---|
| none | 阈值化,threshold 默认 125 |
| floydsteinberg | 误差核 7/16,3/16,5/16,1/16 |
| atkinson | 6 邻域 ×1/8 |
| bayer | 4×4 矩阵 [[15,135,45,165],[195,75,225,105],[60,180,30,150],[240,120,210,90]] |
| stucki | /42 核 |
| jarvis | /48 核 |
| bwr_* | 同上 6 种三色版;红色判定 `r>g*1.5 && r>b*1.5 && r>threshold` |
预处理:亮度 ±255·v/100;对比度 (c+100)/100(128 中点);饱和度=灰度插值(0.299/0.587/0.114);diffusion 0–100/100 误差缩放。
## 6. 标准会话流程
1. 扫描(namePrefix `NRF-`)→ 连接 → EPD service → RXTX service → 订阅两通道 notify。
2. (可选)`EFEF` 取设备 ID。
3. 对时:`dd…` + `e2`。
4. 操作:模式切换(+`e2`)/ 传图(`EA0{slot}` → 数据块×N → `01`/`AA`)/ 倒计时 / WiFi。
5. 断线自动重连 ≤5 次。
## 7. 本地化(去云)清单
| 云依赖 | 本地化方案 |
|---|---|
| key_generator.php 激活码 | 分析固件校验逻辑(见 docs/firmware-analysis.md),本地实现算法或固件补丁绕过 ⚠待固件分析 |
| file_down.php 固件下载 | 固件已本地存档 app/ |
| qbsg.top 自助激活 | 同上激活方案 |
| 天气(CITY 代码) | 本地化=不依赖天气;CLI 提供 `wifi-config` 透传 |
| qrcodejs CDN(模板用) | CLI 用本地 qrcode 库 |
## 8. 测试向量(实现前必须写入 tests/)
> 来源:analysis/web/protocol-raw.md 各节;标 ⚠ 的待 APK/固件互证确认。
1. setTime 布局(§3.3)⚠
2. 图像块帧头:400×300 bw 平面首块 → `03 ff 0000` + 240B ⚠
3. 小图判定:3500B → cod=`04`;15000B → cod=`03`
4. 停车牌 "12" → `EF1122`
5. 轮播 5 分钟 → `e9010501`
6. 槽位 3 上传前置 → `EA02`;轮播数量 4 → `EA0003`
7. 停车牌/激活/取 ID 的 `EF` 前缀区分:`EFEF`=取ID、双写数字=车牌、≥32hex=激活