284 lines
21 KiB
Markdown
284 lines
21 KiB
Markdown
# firmware-PP_da14585_4.2_CH.img 逆向分析报告
|
||
|
||
> 目标文件:`app/firmware-PP_da14585_4.2_CH.img`,72228 字节
|
||
> 平台:Dialog DA14585(ARM Cortex-M0,仅 Thumb),SysRAM 96KB @ 0x07FC0000–0x07FD8000
|
||
> 工具:`analysis/firmware/fw_parse.py`(头解析+CRC)、`analysis/firmware/disasm.py`(capstone 线性扫描)、`analysis/firmware/find_cmds.py`(命令立即数扫描)、`analysis/firmware/fw.asm`(全量反汇编,32098 指令)
|
||
> 地址约定:文件偏移 = 映射地址 - 0x07FC0000 + 0x40(映射地址 = 文件偏移 - 0x40 + 0x07FC0000)
|
||
|
||
## 0. 结论速览
|
||
|
||
| 问题 | 结论 |
|
||
|---|---|
|
||
| 固件是否可控 | **完全可控**。BLE 命令处理无任何鉴权/加密门槛,全部命令(图像、刷新、模式、时间)连接即可用;激活只是云端生意,固件侧不锁功能 |
|
||
| 如何实现 OTA | 固件内置完整 **SPOTA 协议栈**(自定义任务 0xFC,MEM_DEV/GPIO_MAP/MEM_INFO/PATCH_DATA 四消息),接收方校验 `70 51`+`AA` 头后写入 SPI Flash 0x38000 备bank,可直接复用本镜像格式做 OTA |
|
||
| 命令解析在哪 | EPD 通道分发 @ 0x07FCBC64(handle 2/7/0xB);RXTX 命令分发器 @ **0x07FCBDE4**(0xDD–0xEF 跳表 @ 0x07FCBEEA + 0x14/0x15/0x23/0x88/0x99/0xCC/0xFA/0xFB/0xFF 直比链) |
|
||
| 墨水屏驱动 | **SSD1683 兼容**(主路径,cmd 0x01 传 0x2B 0x01=300 行、0x44/0x45 设 50×300、0x24/0x26 双平面)+ 备选 **UC8151/IL0373 兼容** 路径(state[0x1c] 切换);波形用驱动 IC 内部 OTP LUT,固件无 LUT 表 |
|
||
| 激活机制 | **本地弱哈希,可离线算出**。激活码 = 6 字节,`code[i] = rol2((MAC[i]<<1 & 0xFF) ^ 0xEF) % 101`,MAC 即设备 BD 地址(BLE 广播可见 / EFEF 应答的 14 字符设备 ID 可完整还原) |
|
||
|
||
---
|
||
|
||
## 1. 镜像格式(任务1)
|
||
|
||
### 1.1 头结构(64 字节,Dialog SUOTA/multi-image 格式)
|
||
|
||
| 偏移 | 字段 | 值 | 验证 |
|
||
|---|---|---|---|
|
||
| 0x00 | magic | `70 51`('pQ',LE 0x5170 = IMAGE_VALID) | ✓ |
|
||
| 0x02 | signature | `AA 01`(OTA 接收方校验首字节==0xAA,见 0x07FCB4F2 处 `cmp r0,#0xaa`) | ✓ |
|
||
| 0x04 | code_size | `E4 19 01 00` = 0x119E4 = **72164 = 文件长 72228 - 64** | ✓ 精确匹配 |
|
||
| 0x08 | CRC32 | `10 4D 89 6C` = 0x6C894D10 | ✓ = **标准 zlib CRC32**(poly 0xEDB88320,init/xorout 0xFFFFFFFF)over 数据区 72164 字节(fw_parse.py 实测 match=True;BZIP2/MPEG-2/POSIX 变体均不匹配) |
|
||
| 0x0C–0x3F | reserved | 0xFF,仅 0x20 处一字节为 0x00 | ✓ |
|
||
|
||
### 1.2 镜像布局图
|
||
|
||
```
|
||
文件偏移 映射地址 内容
|
||
0x000000 - 64B 镜像头('pQ' + len + CRC32)
|
||
0x000040 0x07FC0000 向量表:SP=0x07FD2B58, Reset=0x07FC0525, SysTick=0x07FC522B,
|
||
IRQ0=0x07FC221D, IRQ1=0x07FCA975(BLE), IRQ2=0x07F0271D(ROM), ...
|
||
0x0000C0~ 0x07FC0080~ 代码(Thumb)+ 内嵌字库/模板数据
|
||
~0x00C800 ~0x07FCC800 点阵字库区(大量 16px 字形位图,如 f0x00de30 起)
|
||
~0x00F900 ~0x07FCF8C0 GATT 描述符/UUID 表/消息handler表/DIS 属性表
|
||
0x010000~ 0x07FD0000~ 初始化数据区:DIS 字符串、22 个祝福词、adv 数据模板、TLV 记录
|
||
0x0119E4 0x07FD19E4 代码区结束(= code_size)
|
||
- 0x07FD19E8 BSS:全局状态结构体 state(激活码/设备ID/时间/显示参数)
|
||
- 0x07FD2B58 初始栈顶
|
||
```
|
||
|
||
SPI Flash 布局(由固件内常量推得,芯片 ≥ 512KB):
|
||
|
||
| Flash 偏移 | 用途 | 证据 |
|
||
|---|---|---|
|
||
| 0x00000 | 主固件 bank(boot ROM 加载到 SysRAM) | 标准 DA14585 boot |
|
||
| 0x2E000–0x35FFF | 显示帧缓存(8×4KB sector 擦除后顺序写,整图双平面 30000B) | cmd 03 处理 0x07FCBD0C:`movs r0,#0x17; lsls r5,r0,#0xd`=0x2E000,循环 8 次 `bl 0x07FCAB74`(sector 擦除),写函数 0x07FCAE4C |
|
||
| 0x38000 | **OTA 备 bank**:+0x00 产品头(校验 `70 52` 'pR'),+0x40 镜像头(校验 `70 51`+`AA`) | OTA 接收 0x07FCB4AA:`bl 0x07FC5AC4` 读 0xC 字节后 `cmp #0x70`/`cmp #0x52`;0x07FCB4F8 `cmp #0x70`/`cmp #0x51`、0x07FCB4F2 `cmp #0xaa` |
|
||
| 0x3F0EF+sum(MAC[0:3]) / 0x3F1DE+sum(MAC[0:6]) | 激活码写入槽(6B×2,地址由 MAC 求和混淆) | 0x07FC7C18:`ldr r1,=0x0003F0EF`(literal @0x07FC7C58);0x07FC7C28 `adds r1,#0xef`;存于 state[0x3C]/state[0x40] |
|
||
|
||
## 2. GATT 表(任务3)
|
||
|
||
### 2.1 UUID 出现位置(均小端存储)
|
||
|
||
| UUID | 文件偏移 | 映射地址 | 说明 |
|
||
|---|---|---|---|
|
||
| EPD Service `13187b10-…-83d3217d9a38` | 0x00FF0C | 0x07FCFECC | 128-bit 原始 16 字节 |
|
||
| EPD Char `4b646063-…-e65356ea82fe` | 0x00F972 | 0x07FCF932 | 128-bit,被 0x07FCFD7C 处描述符引用 |
|
||
| RXTX Service 0x1F10 | 0x00FF28(16B 项起于 0x00FF20) | 0x07FCFEE8 | 以 128-bit 蓝牙基 UUID 形式 `FB 34 9B 5F 80 00 00 80 00 10 00 00 10 1F 00 00` |
|
||
| RXTX Char 0x1F1F | 0x00F98E(项起于 0x00F982) | 0x07FCF94E | 同上形式 |
|
||
| 第三 Service 0x221F | 0x00FF38(项起于 0x00FF30) | 0x07FCFEF8 | web 端声明但未用——**疑似 SUOTA 通道** |
|
||
| Char 0x331F | 0x00F99E(项起于 0x00F992) | 0x07FCF95E | 0x1F10/0x221F 服务下的另一特征 |
|
||
| DIS 属性表(0x2800/0x2803 + 0x2A29/24/25/27/26/23/2A/50) | 0x00FF3C 起 | 0x07FCFEFC 起 | 12 字节/项 {uuid32, perm, aux},被 0x07FC7094 处注册代码引用 |
|
||
| GAP/BAS 表(0x2A00/0x2A01/0x2A19 电量 + 0x2902 CCC) | 0x00FBB0 起 | 0x07FCFB70 起 | BASS 任务消息 0x2400/0x2402 @0x07FCFBC4 |
|
||
|
||
EPD svc UUID 被 0x07FCFD64 引用、EPD char UUID 被 0x07FCFD7C 引用(GATT DB 描述符簇 0x07FCFD54–0x07FCFE68,三个服务各一簇)。
|
||
|
||
**SPOTA/SUOTA UUID(0xFEF6–0xFEFB)在镜像中不存在**(搜 f6fe/f7fe/…/fbfe 仅命中 BL 指令编码,无相邻簇),但:
|
||
|
||
- 广播数据模板含完整 16-bit 服务列表 **0x180A(DIS)+0xFEF5(SPOTA)**:0x07FD094A `05 03 0a 18 f5 fe`(证据:文件 0x01098A)
|
||
- SUOTA 功能以自定义任务 0xFC + 自定义 service(疑似 0x221F)实现,见 §5
|
||
|
||
### 2.2 应用消息 handler 表(ke_msg_handler {u32 id, u32 func})
|
||
|
||
- GAPM 表 @ 0x07FCFE68:0x0C13→0x07FC7EE5、0x0C15→0x07FC80C1、0x0C17→0x07FC7C6D、0x0C00→0x07FC7D19…
|
||
- 显示/应用任务 0xFD 表:0xFD06→0x07FC6B9D、0xFD03→0x07FC6C1D、0xFD08→0x07FC6B25、0xFD0E→0x07FC6591、0xFD05→0x07FC6C41(@0x07FCFE88 起)
|
||
- GATTC 表 @ 0x07FCFB00:0x0E08→0x07FC79F1、0x0E13→0x07FC7619、0x0E15→0x07FC7529、0x0E17→0x07FC7939、0x0E19→0x07FC7921、0x0D15→0x07FC7A51、0x0D21/0x0D22→0x07FC7C69/0x07FC7C65
|
||
- **SUOTA 任务 0xFC 表 @ 0x07FCFB50**:`FC00→0x07FCB6F9`、`FC01→0x07FCAEED`、`FC02→0x07FCB6B9`、`FC03→0x07FCB3F1`(文件 0x00FB90–0x00FBAF)
|
||
|
||
## 3. 命令解析(任务4)
|
||
|
||
### 3.1 写入口
|
||
|
||
GATT 写总入口 **0x07FCBC64**(4 个 BL 调用方:0x07FC58B6/0x07FC757E/0x07FC7784/0x07FC7AB8,均为 GAP/GATT 事件包装)。按消息 id(0xFD04/0xFD0D/0xFD0A,literal @0x07FCBDB8–0x07FCBDC0)分流;0xFD0A 按 handle 分流:
|
||
|
||
| handle | 去向 | 证据 |
|
||
|---|---|---|
|
||
| 2 | EPD 数据通道(0xAA/03/04/01) | 0x07FCBC84 `cmp r0,#2` |
|
||
| 7 | RXTX 命令分发器 0x07FCBDE4 | 0x07FCBC80 `cmp r0,#7` |
|
||
| 0x0B | 同上(第二命令特征,疑 0x331F) | 0x07FCBC7C `cmp r0,#0xb` |
|
||
|
||
写参数结构:`[r4,#2]`=handle,`[r4,#4]`=len,`[r4,#6]`=opcode,`[r4,#7..]`=payload。
|
||
|
||
### 3.2 EPD 通道(图像数据)
|
||
|
||
@ 0x07FCBC94:`ldrb r0,[r4,#6]` 后依次比 `0xAA / 3 / 4 / 1`:
|
||
|
||
| opcode | 处理 | 证据 |
|
||
|---|---|---|
|
||
| `03` | **整图**:首包擦除 Flash 0x2E000 起 8 sector,随后按 state[0x2A] 累计偏移经 0x07FCAE4C 顺序写 Flash(忽略包内 offset 与平面字节),长度=len-4 | 0x07FCBD0C–0x07FCBDB6 |
|
||
| `04` | **日历小图**:按包内 BE offset 写 RAM:`[7]==0xFF`→0x07FD4B18+off(无边界检查!);`[7]==0x00`→0x07FD0A0A+off(边界 0xAA9);数据=r4+0xA,len-4 | 0x07FCBD3C–0x07FCBD80;literal @0x07FCBDC8/0x07FCBDD8/0x07FCBDDC |
|
||
| `01` | 整图结束:state 清零 + `bl 0x07FC6E98`(Flash 落盘/刷屏准备) | 0x07FCBCA2–0x07FCBCAE |
|
||
| `AA` | 小图结束:置标志 + `bl 0x07FCA880(0)` 触发刷新编排 | 0x07FCBD82–0x07FCBD8E |
|
||
| `00` | 忽略(web 的 clearScreen 第一步是固件侧 no-op) | 0x07FCBC9A 链无匹配落 0x07FCBD02 |
|
||
|
||
### 3.3 RXTX 命令分发器 0x07FCBDE4(文件 0x00BDA4)
|
||
|
||
前置:opcode 0–4 且 len≥0x1F → 数据写(拷贝 (op&7)×32 字节到 0x07FD17BD,op 记入 0x07FD09D0);opcode 5–8 且 len≥0x1F → 写 0x07FD183D。这覆盖 web 的 `04{128B}` 倒计时前缀位图(op 4→128B ✓)。
|
||
随后 `subs r1,#0xdd; cmp r1,#0x12; bls` → **跳表 @ 0x07FCBEEA**(19 项,target=0x07FCBEEE+entry×2,表体文件 0x00BF2C):
|
||
|
||
| opcode | target | 语义(与 web 对照) |
|
||
|---|---|---|
|
||
| `DD` | 0x07FCBF12 | 设时间:LE 4 字节 unix → state[0x78],并换算;只用前 4 字节(web 的年月日周字节被忽略)✓ |
|
||
| `E1` | 0x07FCBF78 | 模式:[7]==0→图模式(0x07FCBF8C,state[2]=0+刷新);==1→日历(0x07FCC10A,循环/可指定,state[0x14]=0);==2→时钟(0x07FCC12E,state[0x14]=1)✓ |
|
||
| `E2` | 0x07FCBF64 | 提交:查显示状态后 → 0x07FCC0D0 → `bl 0x07FCA880(1)` 刷新 ✓ |
|
||
| `E3` | 0x07FCC0D0 | 反色 → `bl 0x07FCA880(0)` ✓ |
|
||
| `E4` | 0x07FCBF98 | 时钟字体 state[0x25] 0/1 循环 ✓ |
|
||
| `E5` | 0x07FCBF58 | 旋转 180°:state[0x11] 翻转 ✓ |
|
||
| `E6` | 0x07FCBF70 | LUT/VCOM 校准字节 → 显示参数结构 0x07FD09D0+6,然后刷新。平面写函数 0x07FC8648 @0x07FC86EA 读该字节并按 **0x10 分界**(<0x10 红平面 / ≥0x10 黑平面)——与 web 文档"01–0f 设红、10–f0 设黑"精确一致 ✓ |
|
||
| `EF` | 0x07FCBFAA | 激活/取设备 ID,见 §4 |
|
||
| DE–E0, E7–EE | 0x07FCC0D6 | **空操作**(含 web 在用的 `E9` 轮播间隔、`EA` 槽位——本固件忽略)✗差异 |
|
||
|
||
跳表外直比链(0x07FCBE54–0x07FCBE88):
|
||
|
||
| opcode | target | 语义 |
|
||
|---|---|---|
|
||
| `14` | 0x07FCC004 | 12/24h:state[0x23] 翻转 ✓ |
|
||
| `15` | 0x07FCC0A0 | 时钟颜色:state[0x19]^=1 ✓ |
|
||
| `23` | 0x07FCC058 | 三色/黑白:state[0x18]=[7]&1;并写参数[6]=0x0C/0x80 ✓ |
|
||
| `88` | 0x07FCC092 | 置标志位 0x8000(web 未用) |
|
||
| `99` | 0x07FCC068 | 日历倒计时文字:len≥0x1F 时按 [7]×0x48 拷贝 **72 字节/字符** 到 0x07FD18BD 基缓冲,[7]+1 记字符数 ✓(与 web `990{j}{72B}` 一致) |
|
||
| `CC` | 0x07FCBFEE | 参数[5]:>0xE0 或 ≤0x47 时钳到 0x48(web 未用) |
|
||
| `FA` | 0x07FCC04A | 关闭倒计时:state[0x24]=1,参数[2]=2 ✓ |
|
||
| `FB` | 0x07FCC010 | 休眠时段:BCD 解析 [7]=开关、[8]=HH、[9]=MM → state[0x13]/参数+3/+4 ✓ |
|
||
| `FF` | 0x07FCBE8A | len==6 时:`FF 00`→0x07FCC152 时钟倒计时日期(BCD 年×100+月+日 → 结构+0x10/14/18,state[0xD]=1);`FF FF`→0x07FCBEA0 日历倒计时日期(→ +0x1C/20/24)✓ |
|
||
|
||
**web 有而固件无**:`E9`/`EA`(no-op)、ASCII `WIFI_SSID:...`(固件无此字符串、无解析路径,直接忽略)——本固件为纯 BLE 版,WiFi/天气属其他 SKU 或云端能力。
|
||
|
||
## 4. 激活验证逻辑(任务6)——可离线绕过
|
||
|
||
### 4.1 EF 处理路径(0x07FCBFAA)
|
||
|
||
```
|
||
[r4,#7]==0xEF 且 len==2 → "EFEF":bl 0x07FCA22C 生成设备ID,
|
||
循环 r5=0x14..0x21 把 14 字节经 ke_msg 发回(notify 应答)✓ 与 web "14B 设备ID"一致
|
||
否则 → 比较循环 @0x07FCC0AA:r4[7..12](收的 6 字节) vs state[0x44..0x49]
|
||
全部相等 → 0x07FCC0DE:state+0x4A(6B)写 Flash[state[0x40]]、state+0x44(6B)写 Flash[state[0x3C]]
|
||
(写函数 0x07FCAE4C,与图像写 Flash 同一函数,证实为 SPI Flash 写)
|
||
不等 → 0x07FCC0D6 直接返回(无任何惩罚/锁定)
|
||
```
|
||
|
||
### 4.2 比较目标 state[0x44] 的来源 = MAC 哈希(关键发现)
|
||
|
||
启动初始化函数 **0x07FC23D0**(被 0x07FC7C30/0x07FC877E 调用)尾部 0x07FC24C8–0x07FC24F4,对 i=0..5 循环:
|
||
|
||
```
|
||
t = ((MAC[i]<<1) & 0xFF) ^ 0xEF ; ldrb→lsls#1→eors ~0x10→uxtb
|
||
code1[i] = ((t<<6)+(t>>2)) & 0xFF % 101 ; = rol2(t) % 0x65,经 __aeabi_uidivmod(0x07F1DFB8)
|
||
→ 存入 state[0x44+i]
|
||
```
|
||
|
||
- MAC = state[0x4A..0x4F] = 设备 BD 地址,由工厂函数 0x07FC7B94 经 NVDS/TLV 读取(0x07FCA2DC,tag 1 = Dialog NVDS BD_ADDRESS;缺省记录 @0x07FD04BA:`14 00 06 00 70 ca ea 80 d0 07…`)
|
||
- 设备 ID(EFEF 应答)生成 @ 0x07FCA22C:`snprintf(state+0x14, "%02X"*7 @0x07FCA298, |MAC4-0x99|, |MAC5-0x99|, |MAC3-0x99|, |MAC2-0x99|, |MAC1-0x99|, |MAC0-0x99|, flags)`;flags=state[0x10] = 各 MAC 字节 ≥0x9A 的位掩码(0x07FC23D4–0x07FC23F4 计算)——**14 个十六进制字符 + 掩码可无损还原 6 字节 MAC**
|
||
- state[0x3C]/[0x40](激活码 Flash 写地址)= `0x3F0EF + MAC[0]+MAC[1]+MAC[2]` 与 `0x3F1DE + sum(MAC[0..5])`(0x07FC7C0C–0x07FC7C2C,常数 literal @0x07FC7C58 = 0x0003F0EF)——按 MAC 求和混淆存放
|
||
- 全镜像**不存在从 Flash 读回激活码的代码**(Flash 读函数 0x07FC5AC4/0x07FC5A2C 仅 OTA 路径调用);0x07FC4CDC 每次刷新都会把这两个槽**清零**并按 RAM 码非零置 state[0xE]/[0xF](显示合成开关,非门锁)
|
||
|
||
### 4.3 绕过结论
|
||
|
||
1. 激活码是纯本地函数:`code[i] = rol2(((MAC[i]<<1)&0xFF)^0xEF) % 101`(i=0..5),**无需厂商服务器**。
|
||
2. MAC 获取:BLE 广播地址直接可见;或发 `EFEF` 收 14 字符 ID 按上式反解。
|
||
3. 固件侧 EF 成功/失败均不门禁任何后续命令(03/04 图传、E1/E2 刷新等在未激活状态同样解析)——**激活仅是厂商云端商业模式,本地使用可直接无视**;如需让屏幕不再显示激活页,发送一次正确 EF 即可(或直接 patch §8 所述字节)。
|
||
|
||
## 5. OTA / SUOTA(任务3+可行性)
|
||
|
||
证据链:
|
||
|
||
1. **任务 0xFC 四消息**(表 @0x07FCFB50):FC00=MEM_DEV(0x07FCB6F8)、FC01=GPIO_MAP(0x07FCAEED)、FC02=MEM_INFO(0x07FCB6B8)、FC03=PATCH_DATA(0x07FCB3F0)——与 Dialog SPOTA 语义一一对应。
|
||
2. **写转发器 0x07FC8340**:按服务内 handle 偏移(`[r4,#6]`=起始 handle,偏移 2–13 跳表 @0x07FC8392,12 项=6 特征×2)把特征写打包成 0xFC00–0xFC03 消息(0x07FC83CC:`movs r0,#0x3f;lsls r0,#0xa`=0xFC00;literal 池 @0x07FC8520–0x07FC8528 = FC02/FC03/FC01)。6 特征 = SPOTA 标准集(mem_dev/gpio_map/mem_info/patch_len/patch_data/serv_status)。
|
||
3. **接收写盘 0x07FCB3F0**:state[0x1C] 状态机(0x10–0x13);0x200 字节块缓冲(0x07FCB424 `lsls r1,#9`);XOR 校验和累计(0x07FCB448–0x07FCB458,存 state[0x24]);收满后校验缓冲头 `70 51`(0x07FCB486–0x07FCB492)→ 写 Flash;并回读 0x38000 校验产品头 `70 52`(0x07FCB4BC/0x07FCB4C4)与镜像头 `70 51 AA`(0x07FCB4F2–0x07FCB502)。
|
||
4. 广播数据声明 SPOTA 0xFEF5(0x07FD094A)。
|
||
|
||
**OTA 实施建议**:按本镜像格式(64B 'pQ' 头 + zlib CRC32)打包 → 连接后走 SUOTA 服务(web 端声明但未用的 **0x221F**,待实机确认句柄;可先 `btgatttool` 枚举含 6 特征的服务)→ MEM_DEV 写 SPI flash 基址、PATCH_DATA 分块(块内无需应用层 ACK,结束由接收方校验头+长度+XOR)→ 完成后设备复位,boot ROM 按产品头切换 bank。**风险**:bank 切换依赖 boot ROM 读 0x38000 产品头,首次实机前建议先用一份仅改版本字符串的镜像验证。
|
||
|
||
## 6. 墨水屏驱动(任务5)
|
||
|
||
低层原语:发命令 **0x07FC3646**(CS/DC=cmd)、发数据 **0x07FC33D0**、SPI 读 **0x07FC31B4**、GPIO 配置 0x07FC3658(P0/P1 基 0x50003000,literal @0x07FC3694)、SPI1 基 0x50001200(literal @0x07FC32B8 等)、延时 0x07FCB8EC。
|
||
|
||
### 6.1 驱动 IC 识别 —— 双面板支持,state[0x1C] 选择
|
||
|
||
**主路径 state[0x1C]==0:SSD1683 兼容**(面板初始化 0x07FC3440,证据 @0x07FC34C8–0x07FC3562):
|
||
|
||
```
|
||
12 ; SWRESET,延时 200ms(0x07FC34CE bl 0x07FC3154, r0=0xC8)
|
||
74 / 54 ; 模拟块控制
|
||
7E / 3B ; 数字块控制
|
||
2B / 04 63 ; VCOM/ACVCOM
|
||
0C / 8B 9C 96 0F ; Booster soft start(GDEY042 系列特征序列)
|
||
11 / 01 ; data entry mode
|
||
44 / 00 31 ; RAM X: 0–49 → 50 字节 = 400 列 ✓
|
||
45 / 2C 01 00 00 ; RAM Y: start 0x012C=300, end 0(反向寻址) ✓ 300 行
|
||
3C / 01 ; border
|
||
22 / B1, 20 ; 装载温度+主激活
|
||
4E / 00, 4F / 2C 01 ; RAM 计数器
|
||
```
|
||
|
||
另有 0x07FC3344 发 `01 / 2B 01 / (1-state[0x20])` = Driver Output Control,mux 0x012B=299 → **300 行**(400×300 三色 4.2" 实锤)。温度读取 @0x07FC32BC:`18/80`、`22/B1`、`20`、`1B` 读 2 字节 >>4 带符号(bit 0x800)→ state[0x28]。
|
||
|
||
**备选路径 state[0x1C]!=0:UC8151/IL0373 兼容**(0x07FC3476 起):
|
||
|
||
```
|
||
01 / 03 00 26 26 (0F|03) ; Power Setting(VGH/VSH/VSL/VDHR)
|
||
06 / 17 17 17 ; Booster Soft Start
|
||
50 / (97|51) 60 ; VCOM & Data Interval
|
||
22 / 04, 延时 200
|
||
```
|
||
|
||
面板类型 state[0x1C] 由 TLV 记录(tag 0x40–0x44,读取器 0x07FCA2DC 跳表 @0x07FCA2F4)配置。
|
||
|
||
### 6.2 刷新编排 0x07FCA880
|
||
|
||
读温度→选波形参数(0x07FC3440)→ 平面写 **0x07FC8648** 两次:`(0x24|0x10, 0)` 与 `(0x26|0x13, 2)`——0x24/0x26 = SSD168x 写黑/红 RAM;0x10/0x13 = UC8151 写 RAM1/RAM2,按面板标志 state[0x1E]/[0x1F] 选择 → ADC 读电池(0x07FC6374,state[0x2C]=百分比)→ 计数 state[0x2B]。
|
||
|
||
### 6.3 LUT
|
||
|
||
**固件内无 LUT 表**:全程未发 `0x32`(Write LUT),波形用驱动 IC 内部 OTP LUT;`E6` 命令仅存校准字节到 0x07FD09D0+6,平面写时按 <0x10/≥0x10 分红/黑平面生效(0x07FC86EA)。两段"LUT 候选"(0x07FD06F8/0x07FD187D)实为清零/0xFF 填充的间隙区,非 LUT。
|
||
|
||
## 7. 字符串交叉引用(任务7)
|
||
|
||
| 字符串 | 位置 | 引用点 | 用途 |
|
||
|---|---|---|---|
|
||
| `TEW MI YAO:` | 0x07FC2508 (f0x002548) | `adr` @0x07FC2414 | 开机/未激活屏第一行标题(经 0x07FCC1C4 snprintf 到显存,随 0x07FC23D0 绘制) |
|
||
| `H:mspppclock.tech` | 0x07FC251C | `adr` @0x07FC244A | 激活屏:厂商主机名(仅显示用,固件无联网代码) |
|
||
| `V:PP_da14585_4.2` | 0x07FC2530 | `adr` @0x07FC2464 | 激活屏:固件版本 |
|
||
| `WX:2549294317` | 0x07FC2544 | `adr` @0x07FC247C | 激活屏:微信联系方式 |
|
||
| `MAC:%02X%02X…` | 0x07FC2554 | `adr` @0x07FC24A0 | 激活屏:显示 BD 地址 |
|
||
| `%02X%02X%02X%02X%02X%02X%02X` | 0x07FCA298 | `adr` @0x07FCA286 | 设备 ID(14 hex)格式串,0x07FCA22C |
|
||
| `%d %02d` / `%d %02d %02d` / `%s %s` 等 | 0x07FC2D88/90/58/60 | `adr` @0x07FC2D1E/22/C4/C8 | 时钟/日历屏文本排版 |
|
||
| `Happiness`…`Motive`(22 词) | 0x07FD034C–0x07FD04B8 | 指针表 @0x07FC9708 | 日历模式每日一词 |
|
||
| `DA14585` / `PP_da14585_4.2` / `1.0.0.0-LE` / `Dialog Semi` | 0x07FD02C4/0x07FD08B9/0x07FD08D0/0x07FD08F6 | DIS 表 | DIS 0x2A24/0x2A26/0x2A27/0x2A29 值 |
|
||
| `NRF-XXXXXX` | 0x07FD0956 | 0x07FCA210、0x07FCBC4C | 广播名模板(X 由 MAC 填充;web 端 `namePrefix:'NRF-'` ✓) |
|
||
| `0123456789abcdef`/`ABCDEF` | 0x07FCC638/0x07FCC64C | hex 工具 | 通用 |
|
||
|
||
`Sun/Mon/Tues/Wednes/Thurs/Fri/Satu`(0x07FD0482 起,定长 8B)与 `中华人民共和国`(0x07FD0920,UTF-8)为日历显示素材。
|
||
|
||
## 8. 固件修改/重打包建议
|
||
|
||
1. **重打包**:改完代码区后用 `fw_parse.py` 同算法重算 zlib CRC32 写回头 0x08,长度不变则无需改 0x04;经 §5 SUOTA 通道或 UART boot 烧录。
|
||
2. **免激活 patch**:将 0x07FCC0AA 比较循环的首分支 `beq`(0x07FCC0BC 处 `beq #0x7fcc0ac` 的 fall-through `b #0x7fcc0d6`)改为直接跳成功分支,或把 EF 处理改成总写 Flash——但更简单的做法仍是按 §4.3 公式算码发送。
|
||
3. **去激活开机屏**:0x07FC23D0 的 r0 判分支(0x07FC23F6 `cmp r0,#0; beq`)强制走 0x07FC24C4 即可跳过 TEW MI YAO/MAC/WX 屏。
|
||
4. **RAM 无边界写注意**:cmd 04 的 0xFF 平面分支(0x07FCBD48)无长度检查,自研上位机时不要越界(会踩 0x07FD4B18 之后的 BSS)。
|
||
5. **手柄速查**:EPD 数据 handle 2;命令 handle 7 与 0x0B(同一解析器);SUOTA 服务=含 6 特征(12 句柄)的服务(枚举确认)。
|
||
6. **排产注意**:固件忽略 E9/EA/WIFI 命令——自研上位机不必实现;倒计时文字位图经 opcode 0–8 数据通道(len≥0x1F)而非 0x99 之外的格式。
|
||
|
||
## 附:关键地址速查
|
||
|
||
| 名称 | 映射地址 | 文件偏移 |
|
||
|---|---|---|
|
||
| 镜像头 | - | 0x000000 |
|
||
| Reset handler | 0x07FC0525 | 0x0004E5 |
|
||
| GATT 写总入口 | 0x07FCBC64 | 0x00BC24 |
|
||
| RXTX 命令分发器 | 0x07FCBDE4 | 0x00BDA4 |
|
||
| 0xDD–0xEF 跳表 | 0x07FCBEEA(表体) | 0x00BF2C |
|
||
| EF 激活处理 | 0x07FCBFAA | 0x00BF6A |
|
||
| 激活码 keygen(boot) | 0x07FC24C8 | 0x002488 |
|
||
| 设备 ID 生成 | 0x07FCA22C | 0x00A1EC |
|
||
| SUOTA PATCH_DATA 接收 | 0x07FCB3F0 | 0x00B3B0 |
|
||
| SUOTA 写转发器 | 0x07FC8340 | 0x008300 |
|
||
| 面板初始化(SSD1683/UC8151) | 0x07FC3440 | 0x003400 |
|
||
| 刷新编排 | 0x07FCA880 | 0x00A840 |
|
||
| 平面写(0x24/0x26/0x10/0x13) | 0x07FC8648 | 0x008608 |
|
||
| Flash 写(页) | 0x07FCAE4C | 0x00AE0C |
|
||
| Flash 读 | 0x07FC5AC4 / 0x07FC5A2C | 0x005A84 / 0x0059EC |
|
||
| Flash sector 擦除 | 0x07FC58E0 / 0x07FCAE8C | 0x0058A0 / 0x00AE4C |
|
||
| 全局状态 state | 0x07FD19E8(BSS) | - |
|
||
| 显示参数结构(E6 字节 +6) | 0x07FD09D0 | 0x010990 |
|
||
| cmd04 RAM 缓冲 0xFF/0x00 | 0x07FD4B18 / 0x07FD0A0A | - |
|
||
| 文字位图缓冲(op0–8/99) | 0x07FD17BD / 0x07FD183D / 0x07FD18BD | - |
|