Skip to content

feat(pro2): add auto-detected Protocol V2 over WebUSB and BLE#773

Draft
wabicai wants to merge 31 commits into
onekeyfrom
feat/pro2-usb-ble
Draft

feat(pro2): add auto-detected Protocol V2 over WebUSB and BLE#773
wabicai wants to merge 31 commits into
onekeyfrom
feat/pro2-usb-ble

Conversation

@wabicai
Copy link
Copy Markdown
Member

@wabicai wabicai commented Apr 24, 2026

Summary

  • Add Pro2 Protocol V2 support for WebUSB and Electron BLE with connection-time active probing.
  • Stop using PID/productName/descriptor as the protocol switch; transports send GetProtoVersion after connect and fall back to Protocol V1 on timeout or failure.
  • Keep desktop-web-ble as the default Electron BLE entry. desktop-web-ble-pro2 is now only a compatibility alias that maps to the same auto-detect transport.
  • Update Pro2 runtime schema and generated TypeScript types from firmware-pro2 so Filesystem*, DevFirmwareUpdate, and DevReboot are available through typed calls.
  • Update Pro2 firmware update flow so resource, bootloader, and firmware files all enter DevFirmwareUpdate.targets.
  • Refresh architecture, transport, protocol, and Claude entry docs for the V1/V2 split, active probing, schema routing, and Pro2 file/update flows.

Architecture

Protocol split

  • Protocol V1: existing Classic / Mini / Touch / Pro devices; supports USB and BLE; initializes with Initialize -> Features.
  • Protocol V2: Pro2; supports USB and BLE; initializes through GetProtoVersion probing and Ping.

Transport behavior

  • TransportManager configures both messages.json and messages-pro2.json when the transport supports Protocol V2.
  • WebUSB discovers interface/endpoints from USB descriptors, but protocol selection is based only on the GetProtoVersion device response.
  • Electron BLE connects/subscribes first, then probes V2. If probing fails, it keeps the legacy V1 BLE packet flow.
  • Device.acquire() reads the detected protocol through getProtocolType() and stores it on originalDescriptor.protocolType before initialization.

Pro2 initialization and update

  • Pro2 skips legacy Initialize/GetFeatures; SDK verifies the link with Ping and synthesizes minimal Features with stable device_id, serial_no, and onekey_serial_no.
  • Pro2 file/update APIs use FilesystemDirMake, FilesystemFileWrite, DevFirmwareUpdate, and DevReboot from the generated Pro2 type surface.
  • DevFirmwareUpdate.targets includes resource, bootloader, and firmware targets explicitly.

Review Findings Addressed

  • Shared PID no longer causes V1 WebUSB devices to be forced into V2 framing.
  • Pro2 WebUSB synthetic features now preserve a stable connectId/uuid source.
  • hd-transport tests now import Protocol V1 from serialization/protocol-v1.
  • Resource and bootloader uploads are included in Pro2 firmware update targets.
  • Pro2 messages are generated into the runtime JSON and TypeScript MessageType union.

Firmware Pro2 Source

  • Submodule: submodules/firmware-pro2
  • Branch source: origin/dev_romloader_split
  • Commit: 504b8752bba68c289769c320cf27d1a7bfcbfed4
  • Commit date: 2026-04-23 14:57:42 +0800

main/dev do not currently provide the required latest Pro2 schema surface used here, especially the Filesystem* and DevFirmwareUpdate messages.

Docs

  • CLAUDE.md: Claude / Agent workflow entry, task routing, Pro2 caveats, and verification commands.
  • docs/README.md: local documentation hierarchy and maintenance rules.
  • docs/architecture.md: SDK layering, V1/V2 ownership, active protocol detection, Device/TransportManager responsibilities.
  • docs/transport.md: WebUSB/BLE probing flow, schema routing, Pro2 firmware update flow, compatibility boundaries.
  • docs/pro2-protocol.md: Protocol V2 frame format, protobuf payload, message IDs, WebUSB/BLE behavior, file write and firmware update messages.

Test Plan

  • yarn prettier --write README.md docs/README.md CLAUDE.md docs/architecture.md docs/transport.md docs/pro2-protocol.md
  • yarn --cwd packages/hd-transport-web-device build
  • yarn --cwd packages/hd-common-connect-sdk build
  • yarn --cwd packages/hd-transport test --runInBand
  • yarn --cwd packages/hd-transport build
  • yarn --cwd packages/core build
  • NODE_OPTIONS=--max-old-space-size=8192 yarn lint --quiet
  • git diff --check

Hardware Validation Still Needed

  • Real Pro2 WebUSB smoke test for GetProtoVersion, Ping, file write, and firmware update.
  • Real Pro2 Electron BLE smoke test for auto-detect V2, fallback safety, and multi-chunk file write.
  • Legacy V1 WebUSB/BLE smoke test with Mini/Touch/Pro to confirm V2 probe fallback in real hardware.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@revan-zhang
Copy link
Copy Markdown
Contributor

revan-zhang commented Apr 24, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@socket-security
Copy link
Copy Markdown

socket-security Bot commented Apr 24, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Protestware or unwanted behavior: npm es5-ext

Note: The script attempts to run a local post-install script, which could potentially contain malicious code. The error handling suggests that it is designed to fail silently, which is a common tactic in malicious scripts.

From: ?npm/es5-ext@0.10.64

ℹ Read more on: This package | This alert | What is protestware?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Consider that consuming this package may come along with functionality unrelated to its primary purpose.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/es5-ext@0.10.64. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

wabicai added a commit that referenced this pull request Apr 27, 2026
The PR #773 lint job failed in `pinentry.test.ts` with
`Cannot use import statement outside a module` because the hd-cli
package was missing jest.config.js. Other workspaces (hd-transport,
core, hwk-ledger-*) already inherit the root preset that wires up
babel-jest + @babel/preset-typescript; hd-cli was the only one
running plain Jest defaults, so any TS test file failed to parse.

Mirror the existing pattern: preset → root jest.config.js,
testEnvironment → node, ignore dist/. Local `yarn test` in hd-cli
now passes 23/23 (pinentry parser tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
wabicai and others added 7 commits April 27, 2026 15:23
…proto sources

Pro2 ships a separate set of system messages (file ops, FirmwareUpdate,
Reboot, Ping, Failure types) defined under
`submodules/firmware-pro2/sys/protobuf/onekey_protocol/legacy/`. This
adds a Pro2 branch to `protobuf-build.sh` that pulls those .proto files,
strips the `Emmc` prefix from message names, splices in
`Success`/`Failure` from messages_common.proto, appends the Pro2-only
`Reboot` message (no .proto source), and emits
`messages-pro2.json` next to the existing `messages.json`. Both the
hd-transport bundle and the core SDK get a copy.

Also adds `firmware-pro2` as a submodule so the build is reproducible
without manual cloning.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Pro2

Adds Protocol V2 (Pro2's 0x5A framing — formerly known as "Proto V0" /
"Proto Link" on the firmware side) alongside the legacy 0x3F chunked
Protocol V1, and introduces per-device protocol routing across every
transport implementation.

Wire format (`packages/hd-transport/src/serialization/protocol-v2/`):
- 0x5A SOF, 2-byte little-endian length, CRC8 over header and full
  frame (init=0x30, poly=0x07), single-frame max 2200 bytes
- Channel/packet-source bytes for the firmware's proto-link routing
- `parseProtoV2Frame` decode + `buildPbFrame` encode helpers
- Cohabits with the legacy V1 codec (renamed dir from
  `protocol/` → `protocol-v1/`); both are now siblings under
  `serialization/`. `protocols.ts` is a thin facade that picks the
  right schema (V1 default + V2 schema for sys-message IDs ≥ 60000).

Transport interface (`Transport.getProtocolType(path)`):
- Promoted from optional to required so the SDK can route per device
  without falling back to features-based heuristics.
- `WebUsbTransport` detects per-path by USB PID
  (`PROTOCOL_V2_USB_PID = 0x53c1` shared with Classic/Mini/Pro/Touch
  for now — see TODO in constants.ts; awaiting Pro2-specific PID).
- New `ElectronPro2BleTransport`: BLE GATT bridge for Pro2 over Noble,
  re-uses the V2 codec, sets `CHANNEL=BLE_UART (1)` and
  `packet_src=COMMAND (1)` because BLE goes through the BLE-coprocessor
  ↔ main-MCU UART bridge. Single Pro2 frame may arrive across multiple
  BLE notifications; reassembly is driven off the LEN field.
- Single-protocol transports (Emulator / Http / Lowlevel / ReactNative
  / NodeUsb / ElectronBle) all return `'V1'`.

Routing in `WebUsbTransport.call()`:
- Dispatches to `callProtocolV2()` for V2 devices and the legacy
  64-byte chunked path for V1 — chosen at acquire time and cached on
  the per-path `deviceProtocol` map.
- Both schemas (`messages` for V1, `messagesV2` for V2) are loaded
  once on configure(); no mid-flight schema swap.
- USB endpoints reach the main MCU directly so the V2 frame doesn't
  set channel/packet-src — only BLE does.

Constants (`packages/hd-transport/src/constants.ts`):
- `PROTOCOL_V2_USB_PID` (0x53c1, with TODO)
- `PROTOCOL_V2_FRAME_MAX_BYTES` (2200)
- `PROTOCOL_V2_FILE_CHUNK_SIZE` (2048)
- `PROTOCOL_V2_CHANNEL_USB / BLE_UART / SOCKET`
- `PROTOCOL_V2_PACKET_SRC_COMMAND`
- `PROTOCOL_V2_SYS_MESSAGE_THRESHOLD` (60000)

Auxiliary changes:
- `packages/shared/src/constants.ts`: extend ONEKEY_WEBUSB_FILTER with
  Pro Boot/Touch Boot PIDs (`0x4f4a`, `0x4f4b`) so Pro2-era hardware
  in either mode is recognized.
- `noble-ble-handler.ts`: discover all GATT services and characteristics
  without UUID filtering — needed because the Pro2 firmware-side BLE
  service UUIDs are still moving and the previous filter dropped the
  notify characteristic during scan. Scan timeouts extended for the
  Pro2 advertising interval.
- `hd-common-connect-sdk`: route `desktop-web-ble-pro2` env to
  `ElectronPro2BleTransport`.

This commit collapses 18 incremental WIP commits (initial Pro V0 framing,
schema selection fixes, descriptor.protocolType propagation, debug
logging, Initialize → Ping init flow iterations, BLE transport wiring,
BLE scan tuning, Pro2 prefix removal, V1/V2 rename, lint fixes) into a
single coherent change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…em API

Wires Pro2 (Protocol V2) into the core SDK as a first-class device
type and adds the SDK-level entry points for Pro2's filesystem and
firmware-update messages.

Device type:
- `EDeviceType.Pro2` added in `@onekeyfe/hd-shared` and recognized by
  `getDeviceType()`. New `desktop-web-ble-pro2` settings env routes to
  `ElectronPro2BleTransport`.
- `Device.initialize()` early-branches into `_initializePro2()` when
  `descriptor.protocolType === 'V2'`. Pro2 doesn't support the legacy
  `Initialize` handshake, so the SDK sends `Ping` to verify
  connectivity and synthesizes the minimum `Features` shape downstream
  code reads (vendor / onekey_device_type / device_id / unlocked /
  initialized). `device_id` derives from the descriptor (path or BLE
  UUID) so `getDeviceUUID(features)` stays defined for Pro2.

TransportManager:
- `reconfigure()` keeps only its features-based messageVersion swap
  (the legitimate V1 use case for Touch classic vs latest schema).
  The previous WIP carried a `protocolType` parameter that was being
  used for cosmetic schema swaps the transport already handles
  per-call; that's removed.
- Initial `configure()` loads V1 default schema and immediately calls
  `configureProtocolV2Messages()` so the transport holds both
  schemas; per-device routing happens at `call()` time via
  `getProtocolType(path)`.

Pro2 reboot:
- `DeviceRebootToBootloader` and `DeviceRebootToBoardloader` branch on
  Pro2 to send `Reboot { reboot_type: BootLoader (2) }` /
  `{ Boardloader (1) }` instead of the V1 `RebootToBootloader` /
  `RebootToBoardloader` messages.

Firmware update (`FirmwareUpdateV3`):
- V1 path (Pro1 / Touch / Mini / Classic) is unchanged. Same
  `validateDeviceAndVersion` gates, same `enterBootloaderMode()`
  + `executeUpdate()` flow that was on `onekey`.
- New `runProtocolV2()` is reached via early-return in `run()` when
  `descriptor.protocolType === 'V2'`. It:
    1. Reuses the common binary-prep helpers
       (`prepareResourceBinary`, `prepareFirmwareAndBleBinary`,
       `prepareBootloaderBinary`).
    2. Calls `pro2EnterBootloader()` — sends
       `Reboot { reboot_type: BootLoader }` via the SDK's existing
       `this.reboot()` helper (typedCall under the hood; the helper
       already tolerates the device dropping USB during reboot).
       1.5s settle wait is the placeholder for a reconnect/Ping
       handshake that needs to land once Pro2 bootloader-mode is
       finalized firmware-side.
    3. Runs `executeUpdateProtocolV2()` — writes resources to
       `vol1:res/`, bootloader to `vol1:bootloader.bin`, firmware
       binaries to `vol1:${name}` (matches the pro2-debug script's
       `vol1:` convention), then triggers
       `FirmwareUpdate { targets[], reboot_on_success: true }`.
    4. No GetFeatures completion polling — Pro2's V2 schema doesn't
       expose it. The `FirmwareUpdate` Success response is itself
       the install-complete signal (matches pro2-debug's synchronous
       request/response usage with a long timeout).

Pro2 filesystem API (`packages/core/src/api/{DirList,DirMake,DirRemove,
FileDelete,FileRead,FileWrite,PathInfo}.ts` + `types/api/pro2.ts`):
- One BaseMethod-derived class per Pro2 system message. Exposed via
  `inject.ts` so consumers call `HardwareSDK.dirList(connectId, ...)`
  / `fileWrite(...)` etc.
- Uses `typedCall('FileWrite' | 'DirList' | ..., 'File' | 'Dir' | 'Success' | ...)` —
  the message names are now in the V1 MessageType union (the protobuf
  build merges Pro2 system messages into the same protobuf root).

Misc:
- AlephiumSignTransaction.ts: typing tweak on the `bytecodeRequest`
  branch — unrelated cleanup that drifted in.

This commit collapses the per-iteration core SDK changes (Pro2 device
type integration, multiple Initialize/Ping init iterations, firmware
update target_id and chunk-size fixes, DeviceReboot* Pro2 branches,
file-op API additions) into one coherent change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pro2 debug page (`expo-playground/app/routes/pro2-debug.tsx`):
- Wire-level testing tool that talks to Pro2 over WebUSB directly,
  bypassing the SDK transport stack. Used to isolate protocol-frame
  / CRC / message-encoding bugs from the SDK plumbing.
- Four tabs:
    * Ping — connection sanity check
    * File System — DirList, PathInfoQuery, FileRead, FileWrite,
      FileDelete, DirMake, DirRemove, FixPermission
    * Firmware — single-target FirmwareUpdate with manual target_id /
      path / reboot_on_success controls
    * Reboot — sends Reboot { reboot_type: Normal/Boardloader/BootLoader }
- Carries its own minimal protobuf encoder/decoder for the Pro2
  message subset; deliberately does not depend on the SDK so it
  remains usable as a fault-isolation tool when the SDK is broken.

Static WebUSB test page (`expo-playground/public/webusb_test.html`):
- Single-file HTML harness for the same Pro2 protocol (predates the
  React debug page). Kept under `public/` so Vercel serves it without
  a route. Useful for cross-browser / cross-machine debugging where
  setting up the playground app is overkill.

Vercel deployment:
- `vercel.json` at repo root; root `package.json` carries the build
  glue. Lets us deploy the playground (including pro2-debug and
  webusb_test.html) under a stable preview URL for the firmware team
  to test against without local toolchain setup.

Sidebar + entry client tweaks add the pro2-debug route to the
playground navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds Pro2 connection paths and firmware-update entry to the example
app, so end-to-end Pro2 SDK flows can be exercised from a real UI
(not just the wire-level pro2-debug page).

- `deviceConnectAtoms.ts` / `hardwareInstance.ts`: track and route the
  new `desktop-web-ble-pro2` env alongside the existing webusb /
  desktop-web-ble options. Default to `desktop-web-ble-pro2` when
  running inside Electron so Pro2 BLE is the path most users land on.
- `DeviceList.tsx` / `FirmwareScreen/index.tsx`: connection-type
  picker on both home and firmware-update screens; the picker triggers
  a transport switch that requires an app restart in some envs (the
  underlying transport instance is a singleton). Firmware-update
  screen shows the V3 entry for both Pro and Pro2; Pro2 path renders
  as "Firmware Update V3 (Pro2 Protocol V2)".
- Minor cleanups in `passphraseTest/TestSessionCountView.tsx` and
  `views/SLIP39TestScreen.tsx` that drifted in alongside the Pro2
  work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `docs/transport.md`: rewritten end to end. Side-by-side comparison
  of Protocol V1 (`##` header, 64-byte chunked, requires Initialize
  handshake) vs Protocol V2 (`0x5A` framing, single-frame up to 2200
  bytes, no handshake, CRC8 validated). Wire format diagrams, schema
  selection rules, PID-based detection, architecture layers.
- `docs/pro2-protocol.md`: new deep dive on Protocol V2 framing
  (Proto Link headers, channel/attr/seq fields, CRC8 algorithm),
  Pro2 message catalog (60000-series IDs), WebUSB and BLE I/O
  specifics including BLE notification reassembly and channel routing
  through the BLE coprocessor's UART bridge.
- `OneKey_Pro2_Deep_Dive.md`: high-level Pro2 architecture notes
  (storage layout, secure-element targets, firmware partition map)
  for engineers onboarding to the Pro2 stack.
- `CLAUDE.md`: minor refresh of repo-wide instructions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `packages/hd-cli/jest.config.js`: add the workspace's missing jest
  config so unit tests can transform TypeScript. Mirrors the pattern
  used by hd-transport / core / hwk-ledger-* (preset → root
  jest.config.js, testEnvironment → node, ignore dist/). Fixes the
  PR #773 lint job, which was failing in `pinentry.test.ts` with
  `Cannot use import statement outside a module` because Jest was
  running with bare defaults.
- `pinentry.ts` / `pinentry.test.ts`: small refactor to the Assuan
  parser surface — same observable behavior, less code.
- `sdk.ts`: minor cleanup that drifted in alongside.
- `hwk-adapter-core/src/__tests__/core-types.test.ts`: keep the
  Pro2 device-type addition compiling under the existing test
  expectations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wabicai wabicai force-pushed the feat/pro2-usb-ble branch from 312143a to 90bd1bd Compare April 27, 2026 07:24
@wabicai wabicai changed the title feat(pro2): WebUSB + BLE transport with Proto Link protocol feat(pro2): add auto-detected Protocol V2 over WebUSB and BLE Apr 27, 2026
@socket-security
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants