Skip to content

Commit 312143a

Browse files
wabicaiclaude
andcommitted
refactor(transport): rename protocols to V1/V2, isolate Pro2 firmware update path
This change does three independent things; together they replace the ad-hoc Pro2 dispatch the previous WIP added with a single per-device source of truth, and stop the V1 firmware update flow from carrying V2-aware branches. 1. Rename Proto V0 / legacy V2 → Protocol V1 / V2 The earlier WIP used "V2" for the legacy 64-byte 0x3F protocol (Pro1 / Touch / Mini / Classic) and "V0" for Pro2's 0x5A framing, borrowed from the firmware-side "Proto V0 / Proto Link" naming. That ordering reads backwards for SDK consumers — Pro1 should be V1, Pro2 should be V2. Rename everything (types, constants, schema field names, log tags, directories, docs) on the SDK side. Wire format is unchanged. - `packages/hd-transport/src/serialization/protocol/` → `protocol-v1/` - `packages/hd-transport/src/serialization/protocol-v0/` → `protocol-v2/` - `ProtocolV2` (chunked) → `ProtocolV1`; `ProtocolV0` → `ProtocolV2` - `parseProtoV0Frame` / `buildProtoV0Frame` / `ProtoV0Frame` → `parseProtoV2Frame` / `buildProtoV2Frame` / `ProtoV2Frame` - `PROTOCOL_V0_SYS_MESSAGE_THRESHOLD` → `PROTOCOL_V2_SYS_MESSAGE_THRESHOLD` - `pro2Protocol` namespace export → `protoV2` - `configureProtocolV0` / `configureProV0` aliases collapse into a single `configureProtocolV2` entry on the Transport interface - `ProtocolType` union flips from `'V2' | 'V0'` to `'V1' | 'V2'` - All `'V0'` / `'V2'` literals routed through the type are flipped (Tron `messageType: 'V1' | 'V2'` is unrelated and untouched) - docs/transport.md and docs/pro2-protocol.md rewritten to match 2. Approach B: single source of truth for protocol routing Previously TransportManager.reconfigure was being called with a `protocolType` argument from Device.initialize() to "swap" the active schema between V1 and V2. That swap was largely cosmetic — the transport already holds both schemas after configure(), and call() routes per-path via getProtocolType(). The reconfigure branch for V1 even re-parsed the entire default schema on every V1 device init. - Drop `protocolType` parameter on `TransportManager.reconfigure()`; it now only handles features-based messageVersion swaps (e.g. Touch classic vs latest), which is its original purpose - Remove the redundant `reconfigure(undefined, 'V1')` call at the top of `Device.initialize()` and the `reconfigure(undefined, 'V2')` call inside `_initializePro2()` - Promote `Transport.getProtocolType(path)` from optional to required; add `'V1'` returns to single-protocol transports (Emulator / Http / Lowlevel / ReactNative / NodeUsb / ElectronBle); WebUsb keeps its PID-based detection; Pro2 BLE stays hardcoded `'V2'` - Pro2 synthetic features now include `device_id` derived from the descriptor (path / id) so downstream `getDeviceUUID(features)` stops returning undefined for Pro2 3. Isolate Pro2 firmware update from V1 path The previous WIP wove `isPro2Device()` checks into the V1 update flow (validateDeviceAndVersion, executeUpdate, etc.). Pull that out so V1 reads exactly as it did in HEAD, and Pro2 takes a dedicated branch: - `FirmwareUpdateV3.run()` early-returns into `runProtocolV2()` when `descriptor.protocolType === 'V2'`. V1 path below is character-for-character the original. - `runProtocolV2()` reuses common helpers (`prepareResourceBinary`, `prepareFirmwareAndBleBinary`, `prepareBootloaderBinary`) and Pro2-only helpers in BaseMethod (`pro2CreateFolder` / `pro2CommonUpdateProcess` / `pro2StartFirmwareUpdate` / `fileWriteWithRetry`). - Pro2 file paths align with the pro2-debug script: `vol1:` root instead of V1's `0:updates/`. Resource files go to `vol1:res/`. - `pro2EnterBootloader()` sends `Reboot { reboot_type: BootLoader }` via the SDK's existing `this.reboot()` helper (typedCall under the hood, tolerates the device dropping USB during reboot). No raw WebUSB. A 1.5s settle wait is the placeholder for the reconnect / Ping handshake to add once Pro2 bootloader-mode is finalized on the firmware side. - Pro2 doesn't expose GetFeatures, so completion detection is the `FirmwareUpdate` Success response itself (matches pro2-debug's synchronous behavior). No GetFeatures polling. - Drop the `getFirmwareUpdateStrategy()` strategy abstraction and the `FirmwareUpdateProtocol` type from BaseMethod. They were V1 contamination — V1 now calls `emmcCommonUpdateProcess` / `createUpdatesFolderIfNotExists` / `startEmmcFirmwareUpdate` directly, as it did before. - Pro2 protocol constants (`PROTOCOL_V2_USB_PID` / `PROTOCOL_V2_FILE_CHUNK_SIZE` / channel + packet-source enums) extracted to `hd-transport/src/constants.ts` and imported by both transports. USB callProtocolV2 stays without channel/packetSrc options (USB endpoints reach the main MCU directly) while BLE keeps `PROTOCOL_V2_CHANNEL_BLE_UART` and `PROTOCOL_V2_PACKET_SRC_COMMAND` because of the BLE-coprocessor → main-MCU UART bridge. Known follow-ups (not in this commit): - `PROTOCOL_V2_USB_PID = 0x53c1` shares the value with Classic/Mini/Pro/Touch firmware in `ONEKEY_WEBUSB_FILTER`. Safe only while Pro2 is the only PID-0x53c1 device in the test environment. Update once Pro2 firmware ships with its own PID. - Pro2 bootloader handoff in `pro2EnterBootloader()` waits a flat 1.5s. Replace with reconnect + Ping verification when Pro2 bootloader-mode behavior is finalized. Verified: tsc --noEmit clean across hd-transport / hd-transport-* / core (apart from 4 pre-existing typedCall errors on Pro2-only messages that exist on this branch independently of this change); ESLint clean on every file touched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3905be4 commit 312143a

29 files changed

Lines changed: 632 additions & 358 deletions

File tree

docs/pro2-protocol.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ This document describes the communication protocol used by OneKey Pro2 hardware
44

55
## Overview
66

7-
Pro2 uses the **Proto Link** framing protocol, which is different from the legacy Trezor-style `##` header protocol used by older OneKey devices (Classic, Mini, Touch, Pro).
7+
Pro2 uses the **Protocol V2** framing protocol, which is different from the **Protocol V1** Trezor-style `##` header protocol used by older OneKey devices (Classic, Mini, Touch, Pro1).
88

9-
| Feature | Legacy (Classic/Mini/Touch/Pro) | Pro2 (Proto Link) |
9+
| Feature | Protocol V1 (Pro1/Touch/Mini/Classic) | Protocol V2 (Pro2) |
1010
|---------|-------------------------------|-------------------|
1111
| Framing | `##` header + type + length | SOF `0x5A` + CRC8 |
1212
| Chunking | 64-byte USB HID reports | Up to 2200 bytes per frame |
1313
| Integrity | None (relies on USB) | CRC8 on header and body |
1414
| Multiplexing | Single channel | Multi-channel (USB, UART, Socket) |
1515
| Sequence | None | 1-255 with duplicate detection |
1616

17-
## Proto Link Frame Format
17+
## Protocol V2 Frame Format
1818

1919
```
2020
+----------- Pre-Header (4 bytes) -----------+
@@ -86,7 +86,7 @@ function crc8(data: Uint8Array, length: number): number {
8686

8787
## Protobuf Message Encoding
8888

89-
Proto Link frames carry protobuf messages. The DATA field contains:
89+
Protocol V2 frames carry protobuf messages. The DATA field contains:
9090

9191
```
9292
[MSG_TYPE_L] [MSG_TYPE_H] [PROTOBUF_PAYLOAD...]
@@ -119,11 +119,11 @@ Pro2 system messages (60000+):
119119
### Schema Selection
120120

121121
Pro2 uses two protobuf schemas:
122-
- **Legacy schema** (`messages.json`): Standard SDK messages (Initialize, GetFeatures, etc.)
123-
- **Pro2 schema** (`messages-pro2.json`): System messages with type ID >= 60000
122+
- **Protocol V1 schema** (`messages.json`): Standard SDK messages (Initialize, GetFeatures, etc.)
123+
- **Protocol V2 schema** (`messages-pro2.json`): System messages with type ID >= 60000
124124

125-
When encoding: look up the message name in the Pro2 schema first. If not found, use the legacy schema.
126-
When decoding: if `msgType >= 60000`, use Pro2 schema; otherwise use legacy schema.
125+
When encoding: look up the message name in the V2 schema first. If not found, fall back to the V1 schema.
126+
When decoding: if `msgType >= 60000` (`PROTOCOL_V2_SYS_MESSAGE_THRESHOLD`), use V2 schema; otherwise use V1 schema.
127127

128128
## WebUSB Transport
129129

@@ -138,20 +138,20 @@ When decoding: if `msgType >= 60000`, use Pro2 schema; otherwise use legacy sche
138138

139139
### Data Flow
140140

141-
1. **Send:** Build Proto V0 frame -> single `transferOut` (no chunking needed, frames fit in one USB transfer)
142-
2. **Receive:** single `transferIn` (up to 4096 bytes) -> parse Proto V0 frame
141+
1. **Send:** Build Protocol V2 frame -> single `transferOut` (no chunking needed, frames fit in one USB transfer)
142+
2. **Receive:** single `transferIn` (up to 4096 bytes) -> parse Protocol V2 frame
143143

144144
Unlike legacy devices (which chunk into 64-byte HID reports), Pro2 sends/receives complete frames in a single USB transfer.
145145

146146
### Device Detection
147147

148-
Pro2 is identified by USB Product ID `0x53C1`. When this PID is detected during `acquire()`, the transport switches from legacy `##` protocol to Proto V0 `0x5A` framing.
148+
Pro2 is identified by USB Product ID `0x53C1`. When this PID is detected during `acquire()`, the transport switches from Protocol V1 (`##` header) to Protocol V2 (`0x5A` framing).
149149

150150
## BLE Transport
151151

152152
### GATT Service
153153

154-
Pro2 BLE uses the same GATT service/characteristic UUIDs as legacy OneKey devices:
154+
Pro2 BLE uses the same GATT service/characteristic UUIDs as Protocol V1 OneKey devices:
155155

156156
| Component | UUID |
157157
|-----------|------|
@@ -161,15 +161,15 @@ Pro2 BLE uses the same GATT service/characteristic UUIDs as legacy OneKey device
161161

162162
### Data Flow
163163

164-
1. **Send:** Build Proto V0 frame (with CHANNEL=1 for UART) -> GATT write to write characteristic
165-
2. **Receive:** Subscribe to notify characteristic -> reassemble Proto V0 frame from notifications -> parse
164+
1. **Send:** Build Protocol V2 frame (with CHANNEL=1 for UART) -> GATT write to write characteristic
165+
2. **Receive:** Subscribe to notify characteristic -> reassemble Protocol V2 frame from notifications -> parse
166166

167167
### BLE-Specific Considerations
168168

169169
- **Channel ID:** BLE uses CHANNEL=1 (UART), because the BLE coprocessor communicates with the main MCU via UART
170170
- **Packet Source:** Command/response data uses `packet_src=1` (FRAME_COMMON_PKT_COMMAND_DATA)
171171
- **MTU:** BLE MTU is negotiated during connection. Default is 23 bytes (BLE 4.0). ATT overhead is 3 bytes, so default payload is 20 bytes. Pro2 typically negotiates higher MTU (e.g., 512 bytes)
172-
- **Frame Reassembly:** A single Proto V0 frame may arrive across multiple BLE notifications if the frame exceeds the negotiated MTU. The receiver must accumulate notification data until a complete frame (determined by the LEN field) is received
172+
- **Frame Reassembly:** A single Protocol V2 frame may arrive across multiple BLE notifications if the frame exceeds the negotiated MTU. The receiver must accumulate notification data until a complete frame (determined by the LEN field) is received
173173

174174
### Device Detection
175175

@@ -179,7 +179,7 @@ Pro2 BLE devices can be identified by:
179179

180180
## File Transfer Protocol
181181

182-
Pro2 supports file operations via protobuf messages over Proto Link:
182+
Pro2 supports file operations via protobuf messages over Protocol V2:
183183

184184
### FileWrite
185185

@@ -218,7 +218,7 @@ max_chunk = min(negotiated_mtu - 3, 244) // ATT overhead = 3 bytes
218218

219219
For USB:
220220
```
221-
max_chunk = 2048 // Proto V0 frames can be up to 2200 bytes
221+
max_chunk = 2048 // Protocol V2 frames can be up to 2200 bytes
222222
```
223223

224224
## Ping Protocol
@@ -236,7 +236,7 @@ message Ping {
236236

237237
## Reliability
238238

239-
Proto Link provides several reliability mechanisms:
239+
Protocol V2 provides several reliability mechanisms:
240240

241241
- **CRC8 validation:** Header CRC and body CRC detect corruption
242242
- **Sequence numbers:** 1-255, wraps from 255 to 1 (0 is reserved)
@@ -250,17 +250,17 @@ Proto Link provides several reliability mechanisms:
250250

251251
| Transport | Class | Protocol | Target |
252252
|-----------|-------|----------|--------|
253-
| WebUSB (legacy) | `WebUsbTransport` | `##` header | Browser |
254-
| WebUSB (Pro2) | `WebUsbTransport` | Proto V0 | Browser |
255-
| BLE (legacy) | `ElectronBleTransport` | `##` header | Electron |
256-
| BLE (Pro2) | `ElectronPro2BleTransport` | Proto V0 | Electron |
253+
| WebUSB (Pro1 / Touch / Mini / Classic) | `WebUsbTransport` | V1 (`##` header) | Browser |
254+
| WebUSB (Pro2) | `WebUsbTransport` | V2 (`0x5A` framing) | Browser |
255+
| BLE (Pro1 / Touch) | `ElectronBleTransport` | V1 (`##` header) | Electron |
256+
| BLE (Pro2) | `ElectronPro2BleTransport` | V2 (`0x5A` framing) | Electron |
257257

258258
### Code References
259259

260-
- Proto V0 encode/decode: `packages/hd-transport/src/serialization/protocol-v0/`
260+
- Protocol V2 encode/decode: `packages/hd-transport/src/serialization/protocol-v2/`
261261
- Pro2 protobuf definitions: `packages/hd-transport/messages-pro2.json`
262262
- WebUSB transport: `packages/hd-transport-web-device/src/webusb.ts`
263263
- BLE Pro2 transport: `packages/hd-transport-web-device/src/electron-pro2-ble-transport.ts`
264264
- BLE legacy transport: `packages/hd-transport-web-device/src/electron-ble-transport.ts`
265265
- Noble BLE handler: `packages/hd-transport-electron/src/noble-ble-handler.ts`
266-
- Proto Link spec: `firmware-pro2/sys/frame_codec/proto_link/proto_link.md`
266+
- Protocol V2 spec: `firmware-pro2/sys/frame_codec/proto_link/proto_link.md`

docs/transport.md

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
## 两句话总结
44

5-
- **Legacy**(Pro1/Mini/Touch/Classic):USB 每包 64 字节,分包传输,连接后必须先发 `Initialize` 握手。
6-
- **Proto V0**(Pro2):USB 单帧最大 2048 字节,无需握手,直接调用系统级 API(文件系统、固件更新)。
5+
- **Protocol V1**(Pro1 / Mini / Touch / Classic):USB 每包 64 字节,分包传输,连接后必须先发 `Initialize` 握手。
6+
- **Protocol V2**(Pro2):USB 单帧最大 2048 字节,无需握手,直接调用系统级 API(文件系统、固件更新)。
77

88
---
99

1010
## 核心差异速查
1111

12-
| | Legacy | Proto V0 (Pro2) |
12+
| | Protocol V1 | Protocol V2 (Pro2) |
1313
|---|---|---|
1414
| SOF 字节 | `0x3F` (`?`) | `0x5A` |
1515
| 单次传输上限 | **64 bytes**(固定分包) | **2048 bytes**(单帧) |
@@ -25,7 +25,7 @@
2525

2626
## 帧格式对比
2727

28-
### Legacy — 固定 64 字节分包
28+
### Protocol V1 — 固定 64 字节分包
2929

3030
```
3131
每个 USB 包(64 bytes):
@@ -47,10 +47,10 @@
4747

4848
---
4949

50-
### Proto V0 — 单帧最大 2048 字节
50+
### Protocol V2 — 单帧最大 2048 字节
5151

5252
```
53-
Proto V0 Frame(最大 2048 bytes):
53+
Protocol V2 Frame(最大 2048 bytes):
5454
┌──────┬──────┬──────┬───────────┬────────┬──────┬─────┬──────────┬──────────┬──────────┬─────┐
5555
│ 0x5A │ LenL │ LenH │ HeaderCRC │ Router │ Attr │ Seq │ MsgTypeL │ MsgTypeH │ PB Data │ CRC │
5656
└──────┴──────┴──────┴───────────┴────────┴──────┴─────┴──────────┴──────────┴──────────┴─────┘
@@ -67,7 +67,7 @@ MsgType = Little-endian uint16
6767

6868
## 连接与初始化流程
6969

70-
### Legacy:必须握手
70+
### Protocol V1:必须握手
7171

7272
```
7373
enumerate() → acquire() → Initialize → Features
@@ -83,71 +83,75 @@ SDK 依赖这些信息选择正确的 protobuf schema。
8383

8484
---
8585

86-
### Proto V0(Pro2):跳过握手
86+
### Protocol V2(Pro2):跳过握手
8787

8888
```
8989
enumerate() → acquire()
9090
9191
detectProtocol(path)
92-
发送 0x5A 探测帧,读响应首字节
93-
0x5A → PRO2
94-
0x3F → LEGACY
92+
按 USB Product ID 识别
93+
PID 0x53C1 (PID_PRO2) → V2
94+
其他 PID → V1
9595
96-
originalDescriptor.protocolType = 'PRO2' ← 写回设备描述符
96+
originalDescriptor.protocolType = 'V2' ← 写回设备描述符
9797
98-
initialize() 检测到 PRO2,跳过 Initialize
98+
initialize() 检测到 V2,跳过 Initialize
9999
100100
_initializePro2()
101-
合成 Features { vendor, device_type: 'pro2' }
102-
TransportManager.reconfigure(undefined, 'PRO2')
101+
合成 Features { vendor, onekey_device_type: Pro2 }
102+
TransportManager.reconfigure(undefined, 'V2')
103103
加载 messages-pro2.json
104104
105105
设备就绪,直接调用 pro2* 系方法
106106
```
107107

108108
Pro2 **不支持** `Initialize` 消息。发送它会收到 `Failure_UnexpectedMessage`
109109

110-
> **关键实现细节**`detectProtocol()``acquire()` 内部运行,结果写入
110+
> **关键实现细节**`detectProtocol()``acquire()` 内部按 PID 立即判定,结果写入
111111
> `WebUsbTransport.deviceProtocol: Map<path, ProtocolType>`
112112
> `acquire()` 完成后立即将结果同步到 `device.originalDescriptor.protocolType`
113113
> 这样 `initialize()` 才能正确判断分支。
114+
>
115+
> BLE 路径不需要探测:Pro2 BLE 走独立的 `ElectronPro2BleTransport` 类,
116+
> `getProtocolType()` 直接返回 `'V2'`
114117
115118
---
116119

117120
## 协议自动检测
118121

119122
```typescript
120123
// packages/hd-transport-web-device/src/webusb.ts
121-
private async detectProtocol(path: string): Promise<ProtocolType> {
122-
// 发送最小 Proto V0 探测帧(Ping, msgType=60206, 空 payload)
123-
// 读响应首字节:
124-
// 0x5A → PRO2
125-
// 0x3F 或超时 → LEGACY
124+
private detectProtocol(path: string): ProtocolType {
125+
const deviceInfo = this.deviceList.find(d => d.path === path);
126+
const protocol: ProtocolType =
127+
deviceInfo?.device.productId === PID_PRO2 ? 'V2' : 'V1';
128+
this.deviceProtocol.set(path, protocol);
129+
return protocol;
126130
}
127131

128132
getProtocolType(path: string): ProtocolType {
129-
return this.deviceProtocol.get(path) ?? 'LEGACY';
133+
return this.deviceProtocol.get(path) ?? 'V1';
130134
}
131135
```
132136

133137
`call()` 根据检测结果自动分支:
134-
- `PRO2``callProtoV0()`,使用 `messages-pro2.json`
135-
- `LEGACY` → 原有路径,使用 `messages.json`
138+
- `V2``callProtocolV2()`,使用 `messages-pro2.json`
139+
- `V1` → 原有路径,使用 `messages.json`
136140

137141
---
138142

139-
## Schema 选择(callProtoV0 内部)
143+
## Schema 选择(callProtocolV2 内部)
140144

141-
Pro2 帧内同时可能包含 Pro2 消息和 Legacy 消息(如未来扩展),选择规则:
145+
V2 帧内同时可能包含 V2 消息和 V1 消息(如未来扩展),选择规则:
142146

143147
```
144148
编码(发送):
145-
messagesProV0.lookupType(name) 成功 → 用 Pro2 schema
146-
失败(name 只在 legacy schema 中) → 回退 legacy messages schema
149+
messagesV2.lookupType(name) 成功 → 用 V2 schema
150+
失败(name 只在 V1 schema 中) → 回退 V1 messages schema
147151
148152
解码(接收):
149-
rxMsgType >= 60000 → Pro2 schema
150-
rxMsgType < 60000 → legacy schema
153+
rxMsgType >= 60000 → V2 schema (PROTOCOL_V2_SYS_MESSAGE_THRESHOLD)
154+
rxMsgType < 60000 → V1 schema
151155
```
152156

153157
---
@@ -195,7 +199,7 @@ await HardwareSDK.fileDelete(connectId, { path: '/tmp/test.txt' });
195199
await HardwareSDK.dirMake(connectId, { path: '/tmp/mydir' });
196200
await HardwareSDK.dirRemove(connectId, { path: '/tmp/mydir' });
197201

198-
// 设备管理 (使用通用 API,内部自动分发到 Pro2 协议)
202+
// 设备管理 (使用通用 API,内部自动分发到 Protocol V2)
199203
await HardwareSDK.deviceRebootToBootloader(connectId);
200204
await HardwareSDK.deviceRebootToBoardloader(connectId);
201205
```
@@ -237,7 +241,7 @@ function crc8(data: Uint8Array, init = 0x30): number {
237241
**Pro2 schema 特殊处理**
238242
- `messages_emmc.proto` 中消息名带 `Emmc` 前缀(如 `EmmcFileRead`),构建脚本用 `sed` 去除前缀
239243
- `Success`/`Failure` 来自 `messages_common.proto`(不在 management proto 中)
240-
- `Reboot`Proto V0 专属,无对应 proto 源文件,在脚本中手动追加
244+
- `Reboot`Protocol V2 专属,无对应 proto 源文件,在脚本中手动追加
241245
- `FailureType` 的限定名(`hw.trezor.messages.common.FailureType`)需 `sed` 去除命名空间,否则 pbjs 静默丢弃
242246

243247
---
@@ -252,10 +256,10 @@ SDK Interface (@onekeyfe/hd-core)
252256
Transport Abstraction (@onekeyfe/hd-transport)
253257
↓ call() 自动分支
254258
WebUSB Transport (@onekeyfe/hd-transport-web-device)
255-
├── Legacy path → buildEncodeBuffers() → 64B 分包 → receiveOne()
256-
└── Proto V0 path → buildPbFrame() → 单帧 → parseProtoV0Frame()
259+
├── Protocol V1 path → buildEncodeBuffers() → 64B 分包 → receiveOne()
260+
└── Protocol V2 path → buildPbFrame() → 单帧 → parseProtoV2Frame()
257261
258262
Hardware Device
259-
├── Pro1 / Mini / Touch / Classic (LEGACY)
260-
└── Pro2 (PRO2)
263+
├── Pro1 / Mini / Touch / Classic (V1)
264+
└── Pro2 (V2)
261265
```

0 commit comments

Comments
 (0)