Files
qianbian/analysis/web/protocol-raw.md

182 lines
10 KiB
Markdown
Raw Permalink 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.
# 墨水屏 Web 上位机 BLE 协议提取报告(原始证据)
> 来源:analysis/web/(ble.js 4408 行 / index.html 1309 行 / moban.js 943 行 / timedjs.js 714 行 / timedjs2.js 323 行 / switch2.js 54 行 / time.js 21 行 / hex.js 15 行)
> 设备:4.2寸 400x300 黑白红三色墨水屏,DA14585,设备名前缀 `NRF-`
## 1. GATT 结构
| 项 | 值 | 证据 |
|---|---|---|
| 设备名过滤 | `namePrefix: 'NRF-'` | ble.js:4052-4054 |
| optionalServices | `0000221f-...34fb`、`00001f10-...34fb`、`13187b10-eba9-a3ba-044e-83d3217d9a38` | ble.js:4054 |
| EPD Service | `13187b10-eba9-a3ba-044e-83d3217d9a38` | ble.js:4163 |
| EPD Characteristic | `4b646063-6264-f3a7-8941-e65356ea82fe` | ble.js:4165 |
| RXTX Service | `00001f10-0000-1000-8000-00805f9b34fb` | ble.js:4101 |
| RXTX Characteristic | `00001f1f-0000-1000-8000-00805f9b34fb` | ble.js:4103 |
| `0000221f` | 仅声明未使用 | ble.js:4054 |
- epdCharacteristic:图像数据块 + 刷屏命令(`00xx`/`01`/`AA`),writeValueWithResponse(ble.js:38-44),订阅 notify(ble.js:4167-4205)。
- rxtxCharacteristic:全部控制命令(时间/模式/WiFi/激活/倒计时/模板槽位),writeValueWithResponse + 100ms 后 read(ble.js:50-71);另有 writeValueWithoutResponse(ble.js:84-90);notify 是设备ID 14 字节应答主通道(ble.js:4121-4137)。
- 连接顺序:preConnect()(ble.js:4045)→ connect()(ble.js:4158)先 EPD 后 RXTX(ble.js:4207);断线重连≤5次(ble.js:30-36)。
## 2. 命令协议
### 2.1 发送封装
| 函数 | 行为 | 证据 |
|---|---|---|
| sendCommand | EPD writeValueWithResponse | ble.js:38-44 |
| rxTxSendCommand | RXTX write+100ms read | ble.js:50-75 |
| rxTxSendCommand2 | RXTX writeWithoutResponse | ble.js:84-90 |
| triggerEpdCmd | hex→EPD | ble.js:3971-3974 |
| triggerRxTxCmd | hex→RXTX | ble.js:3963-3966 |
| triggerRxTxCmd2 | hex→RXTX(无响应) | ble.js:3967-3970 |
| setri | RXTX 发 cmd,300ms 后补 `e2` | ble.js:3956-3962 |
| clearScreen | EPD 发 `00{cmd}` 再 `01` | ble.js:45-49 |
| triggerEpdRed_lut | RXTX `E6{cmd}`(0 直接返回) | ble.js:3975-3980 |
| triggerEpdJH | RXTX `EF{cmd}`,500ms 后 `e2` | ble.js:3981-3987 |
| triggerEpdCHEPAI | 字符双写+`EF` 前缀,500ms 后 `e2` | ble.js:3988-3998 |
| triggerRxTxCmd_LED | `cmd+note+color+HH+MM` | ble.js:3999-4009 |
| triggerRxTxCmd_XM | `cmd+HH+MM` | ble.js:4010-4020 |
| triggerRxTxCmd_LB | `e901`+hex(n)+cmd | ble.js:4022-4038 |
### 2.2 Opcode 一览
**EPD 通道:**
| Opcode | 含义 | 证据 |
|---|---|---|
| `00{xx}` | 刷屏第一步 | ble.js:47 |
| `01` | 刷屏执行/整图结束刷新 | ble.js:48,160,230 |
| `AA` | 日历小图传输结束 | ble.js:159 |
| `03{ff\|00}{offset:2B BE}{data}` | 整图数据块(≤240B/块) | ble.js:98,104 |
| `04{ff\|00}{offset:2B BE}{data}` | 日历小图数据块(hex 总长 7000/18000 时) | ble.js:99,104 |
**RXTX 通道:**
| Opcode | 含义 | 证据 |
|---|---|---|
| `e2` | 提交/强制刷新(多数命令收尾) | ble.js:256,3961 等 |
| `dd{unix:4B}{year:2B}{month:1B}{day:1B}{week:1B}` | 设置时间 | ble.js:251-257 |
| `2300`/`2301` | 三色/黑白屏模式 | index.html:840-841 |
| `14` | 12/24 小时制切换 | index.html:845 |
| `15` | 时钟颜色切换 | index.html:881 |
| `e3` | 反色模式 | index.html:878 |
| `e4` | 时钟字体切换 | index.html:880 |
| `e5` | 旋转180° | index.html:886 |
| `e10000`..`e10003` | 图片模式 图一~图四 | index.html:868-873 |
| `e10103`/`e10104`/`e10105` | 日历模式一/二/三 | index.html:860-862 |
| `e10201`/`e10202`/`e10203` | 时钟模式一/二/三 | index.html:853-855 |
| `E6{lut}` | 红/黑 LUT 校准:01–0f 设红、10–f0 设黑 | ble.js:3978; index.html:885-887 |
| `FB01{HH}{MM}` / `FB00{HH}{MM}` | 开/关休眠时段 | index.html:897-898; ble.js:4017 |
| `e901{n:hex}{01\|00}` | 图片轮播间隔(01=分钟 00=小时) | ble.js:4035 |
| `EA0{slot}` | 上传选槽位 EA00–EA03 | ble.js:213,237 |
| `EA000{n-1}` | 轮播数量 1–4 | ble.js:241-249 |
| `EF{激活码hex}` | 激活设备 | ble.js:3891,3983 |
| `EF{逐位双写号码}` | 停车牌("12"→`EF1122`) | ble.js:3990-3995 |
| `EFEF` | 请求设备 ID(14B notify 应答) | ble.js:3924,4123 |
| `FA` | 关闭倒计时 | timedjs2.js:142,308 |
| `ff00{year}{MM}{dd}` | 时钟倒计时日期(year=4位十进制ASCII) | timedjs2.js:250-253 |
| `ffff{year}{MM}{dd}` | 日历倒计时日期 | timedjs2.js:245-248 |
| `04{128B hex}` + `0{charCount}{余hex}` | 时钟倒计时前缀文字位图(>4字符拆两包) | timedjs2.js:206-217 |
| `0{charCount}{位图hex}` | 同上 ≤4字符单包 | timedjs2.js:218-224 |
| `990{j}{72B hex}` | 日历倒计时文字位图(每字符一包,24x24/8) | timedjs2.js:229-233,300-304 |
| ASCII `WIFI_SSID:..;WIFI_PASS:..;CITY:..` | WiFi+天气城市配置(UTF-8 直发) | ble.js:3839-3863 |
| `{cmd}{note}{color}{HH}{MM}` | LED 变体(遗留) | ble.js:4000-4008 |
## 3. 图像传输协议(sendBufferData ble.js:92-107)
1. 分块:`my_step=480` hex 字符 = 240 数据字节/块(ble.js:9,100)。
2. 帧格式(ble.js:104):`cod`(1B: 03整图/04小图) + `code`(1B: ff=bw平面 00=红平面) + offset(2B 大端,=字节序号) + ≤240B 数据。块总长 244B。
3. cod 判定(ble.js:98-99):hex 长度 7000(=3500B=280x100/8) 或 18000(=9000B=400x180/8) 用 `04`,否则 `03`。
4. 无应用层 ACK,顺序 writeWithResponse(ble.js:102-106)。
5. 结束:delay(300) → 整图发 `01`;日历小图(宽280 或 高180)发 `AA`(ble.js:158-160)。
上传函数差异:
| 函数 | 前置 | 打包 | 结束 |
|---|---|---|---|
| upload_image | 无 | 296宽→canvas2bytes_bw;250/212宽→bw;其他→canvas2bytes 双平面 | 01/AA |
| upload_image_moban(bat) | RXTX `EA0{bat}` | 296宽→bw,否则双平面 | 01 |
| upload_image_lb(cmd) | RXTX `EA0{cmd}` | 同 upload_image | 同 |
| upload_image_lb_num(cmd) | RXTX `EA000{cmd-1}` | 不传图 | 无 |
三色 = 两次发送:bw 平面(code=ff) + 红平面(code=00)(ble.js:154-155,219-222)。
## 4. 像素打包(timedjs.js)
| 函数 | 扫描 | 位序 | 用途 | 证据 |
|---|---|---|---|---|
| canvas2bytes | 行主序 y0→H,x0→W | MSB first,8px/B | 400x300/800x480/280x100/400x180 | timedjs.js:564-584 |
| canvas2bytes_bw | 列主序 x 从 W-1→0,y0→H | MSB first | 2.9寸296x128、2.13寸 | timedjs.js:586-611 |
| canvas2bytes_to | 转置 | MSB first | 未调用 | timedjs.js:612-632 |
位值:bw 平面 R,G,B 全>0→1(白) 否则 0(黑);bwr 平面 R>0,G=0,B=0→1(红)(timedjs.js:573-576,599-601)。
400x300 → 每平面 15000B。红色判定:`r>g*1.5 && r>b*1.5 && r>threshold`(timedjs.js:255 等)。
抖动算法(dithering() 分发 timedjs.js:513-563):
- 黑白:none/floydsteinberg(7,3,5,1 /16)/atkinson(1/8×6)/bayer(4x4 [[15,135,45,165],[195,75,225,105],[60,180,30,150],[240,120,210,90]])/stucki(/42)/jarvis(/48)
- 黑白红:bwr_ 前缀同名 6 种,默认 bwr_atkinson
- threshold 默认 125;diffusion 0–100/100 误差缩放
- bwrPalette=黑白红(timedjs.js:504-508)
- 预处理 applyImageAdjustments:亮度/对比度/饱和度(timedjs.js:2-38),灰度 0.299/0.587/0.114
## 5. 时钟/日历/倒计时
setTime(ble.js:251-257)RXTX 连发 `dd…` + `e2`:
| 偏移 | 长度 | 含义 |
|---|---|---|
| 0 | 1B | `dd` |
| 1 | 4B | unix 秒(本地时区修正 Date.now()/1000 - tzOffset*60,ble.js:4222) |
| 5 | 2B | 年(大端) |
| 7 | 1B | 月 1–12 |
| 8 | 1B | 日 |
| 9 | 1B | 星期(getDay()||7:周一=1…周日=7) |
倒计时:
- 时钟界面 gridSize=16:>4 字符(中文=1 英文=0.5)拆两包 `04`+128B / `0{n}`+余;≤4 单包 `0{n}`(timedjs2.js:206-224)
- 日历界面 gridSize=24:每字符一包 `990{j}`+72B,间隔1s(timedjs2.js:228-235)
- 日期帧 `ff00{year}{MM}{dd}`(时钟)/`ffff...`(日历),year=4位十进制ASCII(timedjs2.js:244-254)
- 收尾 `E2`;关闭 `FA`+1s+`E2`(timedjs2.js:141-145)
- upload_rili:`990*`→`FA`→`e10103`→`E2`(timedjs2.js:308-312)
## 6. 模板系统(moban.js)
6 模板渲染到 #unifiedCanvas(#epdwh 选 400x300/800x480/296x128),无 BLE 代码;上传走 upload_image_moban(0)→`EA00`+图块+`01`(index.html:1243)。
| 模板 | data-template | 渲染 |
|---|---|---|
| 日程 schedule | renderPresetTemplate | moban.js:140-145,369-467 |
| 名片 businesscard | 同上 | moban.js:146-151 |
| 备忘录 memo | 同上 | moban.js:152-157 |
| 课程表 course | renderCourseTable(默认5天x4节,3–7天、2–9节) | moban.js:29-63,165-317 |
| 二维码 qrcode | renderQRCodeMode(qrcodejs CorrectLevel.M) | moban.js:81-113,501-570 |
| 自定义文本 customText | renderCustomMode(自动换行) | moban.js:572-693 |
红字语法 `【…】`(parseColoredText moban.js:470-498);反色模式 7 种(moban.js:122-137)。
## 7. 激活机制
- API:`http://4638e813e4.qicp.vip:8889/key_generator.php`(ble.js:3866)
- fullAutoActivate(ble.js:3932-3955):
1. 读 #fixedId(用户固定ID,UI 隐藏 index.html:930-935)
2. getDeviceIdFromScreen:RXTX 发 `EFEF`,8s 超时,notify 累计 14 字节(EXPECTED_ID_BYTES=14 ble.js:4123),可打印转 ASCII 否则 hex(ble.js:4121-4137)
3. requestActivationCode:GET `?id={fixedId}&key={deviceId}`(ble.js:3879-3886)
4. extractActivationCode:正则 `激活码1:([0-9A-F]{32,})` / `激活码:(…)` / 任意≥32hex(ble.js:3869-3876)
5. sendActivationToDevice:`EF`+大写激活码,400ms 后 `e2`(ble.js:3889-3902)
- 算法在服务端 key_generator.php,客户端无实现。自助站 qbsg.top,作者微信 2549294317。
- 固件下载同 host:`http://4638e813e4.qicp.vip:8889/GuJian/file_down.php`(index.html:836),型号列表在服务端。
## 8. 高级命令
index.html:919-920:#cmdcmd 任意 hex → triggerRxTxCmd 直发 RXTX。
hex.js:2-15:hexToBytes/bytesToHex/intToHex(大端 pad)。
## 9. 变体与其他
- LED=灯板变体(遗留);XM=休眠(FB00/FB01);LB=轮播(e901/EA000);CHEPAI=停车牌;JH=激活;lut=LUT 校准 E6
- 设备名前缀仅 `NRF-`(ble.js:4053)
- chinaCities 城市→天气代码表 ble.js:259 起约3580行,用于 WIFI 配置 CITY 字段
- 死代码:SendCommand(i 未初始化)、upload_image_lbs(未定义)