Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Frame Format

Every command exchange uses the command endpoints (0x01 OUT / 0x81 IN). The data endpoints are a separate, unframed stream.

Source: Command::to_raw and Response::from_raw in src/commands/mod.rs, and WchLink::send_command in src/probe.rs.

Request

Byte 0Byte 1Byte 2Bytes 3 … n
0x81CMDLENPAYLOAD
#![allow(unused)]
fn main() {
let mut bytes = vec![0x81, Self::COMMAND_ID, 0x00];
bytes.extend(self.payload());
bytes[2] = bytes.len() as u8 - 3;   // LEN = PAYLOAD.len()
}

LEN is a single byte holding the payload length, so the format allows up to 255 payload bytes. In practice wlink reads responses into a 64-byte buffer, which caps a response payload at 61 bytes; all implemented commands use far smaller payloads.

Example — GetProbeInfo (0x0d, subcommand 0x01):

81 0d 01 01
^^ ^^ ^^ ^^
|  |  |  └─ PAYLOAD[0] = 0x01 (GetProbeInfo)
|  |  └──── LEN = 1
|  └─────── CMD = 0x0d (Control)
└────────── request marker

Success response

Byte 0Byte 1Byte 2Bytes 3 … n
0x82CMDLENPAYLOAD

The parser checks resp[0] == 0x82, verifies LEN == resp[3..].len(), then hands resp[3..] to the response type. It does not verify that CMD matches the request.

Example — GetProbeInfo responding with firmware 2.15 on a WCH-LinkE:

82 0d 03 02 0f 02
         ^^^^^^^^^^ PAYLOAD = [0x02, 0x0f, 0x02]

Error response

Byte 0Byte 1Byte 2Bytes 3 … n
0x81REASONLENPAYLOAD

An 0x81 first byte means failure regardless of CMD. wlink validates the length and surfaces Error::Protocol(reason, response_bytes).

REASONMeaning
0x55Failed to connect to the target RISC-V chip
otherOpaque; the full frame is preserved in the error

Response decoding by type

Rust typeRule
()Payload ignored, success is enough
u8Payload must be exactly 1 byte
boolPayload must be 1 byte; 0x01 means success (SetSpeed)
Vec<u8>Raw payload returned
AttachChipResponseExactly 5 bytes: family u8 + ChipID u32_be
DmiOpResponseExactly 6 bytes: addr u8 + data u32_be + op u8
ProbeInfoAt least 3 bytes: major, minor, optional variant
ESignatureNon-standard 20-byte raw response, see Chip Info
invalid markerError::InvalidPayload
length mismatchError::InvalidPayloadLength

Data endpoint stream

The data endpoints carry no 81/82 header. Two shapes occur:

  • Bulk output: the flash algorithm blob for the chip family, then firmware data split into write_pack_size chunks, each padded with 0xff to data_packet_size (see WchLink::write_data_with_progress).
  • Bulk input: read_data(n) accumulates 64-byte bulk reads until n bytes are collected. During a fast-program cycle, each written chunk is followed by a 4-byte acknowledgement on 0x82; wlink checks that the last byte is 0x04 (observed 41 01 01 04).

ProbeSession::read_memory reverses each 4-byte word of the returned memory buffer to compensate for the probe’s word order.