Raw
Verbatim bytes on a cloned endpointRAW places one packet or bulk transfer, byte for byte, on an endpoint named by number and direction: IN to the game PC, OUT to the real device. It enters the path after every stage that reads or rewrites a packet.
IN native report --> rewrite --> lock, render, inject --> rewrite ---+
HID_IN EMIT |
v
RAW(ep, 1) ------> [ IN queue ] --> game PC
OUT game PC --------> rewrite ----------------------------------------+
HID_OUT, VEND_INTR, VEND_BULK |
v
RAW(ep, 2) ------> [ OUT relay ] --> real device
rewrite = the rewrite rules and the clip packet triggers on that surfaceStandard inputs belong in INJECT and MOVE, which the box renders into a faithful report; RAW is for bytes no semantic field describes.
RAW runs only under OPTION(IMPERFECT). Otherwise the box discards the frame with no reply, and discards a clip raw item, counted in gated.
RAW
One packet or bulk transfer on one endpointRAW carries an endpoint address and the bytes to put there. Opcode 0x19.
RAW 0x19 · payload 2 + n bytes
Fire-and-forget
| Offset | Field | Type | Notes |
|---|---|---|---|
| 0 | ep_num | u8 | endpoint number; low four bits used |
| 1 | dir | u8 | 1 IN, 2 OUT (the LOCK direction byte) |
| 2 | bytes | u8[] | packet, verbatim; delimited by the frame LEN, so at most 510 bytes |
| Value | Name | Effect |
|---|---|---|
1 | IN | queued on the clone's IN endpoint ep_num (HID interrupt, vendor interrupt or bulk) for the game PC to read |
2 | OUT | relayed through the host chip to OUT endpoint ep_num (HID interrupt, vendor interrupt or bulk) on the real device |
| Refused when | Why |
|---|---|
| payload under 2 bytes | no endpoint address |
| clone not yet configured by the game PC | clone endpoints are unarmed until the PC's SET_CONFIGURATION |
dir is not 1 or 2 | only 1 (IN) and 2 (OUT) name an address |
IN: no cloned HID or vendor IN endpoint ep_num | the box writes only IN endpoints it cloned |
OUT: no real-device OUT endpoint ep_num | the host chip drops it, with no endpoint to submit to |
| an interrupt packet past its limit | an interrupt transfer is one packet, so a split would reach the PC as two reports |
The bytes reach the endpoint as given. RAW has no reply; an EMIT subscription shows an IN packet as the game PC reads it.
Left button down on HID interrupt IN endpoint 1: ep_num = 1, dir = 1, a 4-byte report:
+--------+--------+--------+--------+--------+--------+-------------+--------+ | A5 | 19 | 00 | 06 00 | 01 | 01 | 01 00 00 00 | lo hi | +--------+--------+--------+--------+--------+--------+-------------+--------+ | SOF | TYPE | SEQ | LEN | ep_num | dir | bytes | CRC16 | +--------+--------+--------+--------+--------+--------+-------------+--------+
The release, button bit clear:
+--------+--------+--------+--------+--------+--------+-------------+--------+ | A5 | 19 | 01 | 06 00 | 01 | 01 | 00 00 00 00 | lo hi | +--------+--------+--------+--------+--------+--------+-------------+--------+ | SOF | TYPE | SEQ | LEN | ep_num | dir | bytes | CRC16 | +--------+--------+--------+--------+--------+--------+-------------+--------+
A keyboard LED report, Caps Lock on, to interrupt OUT endpoint 2: ep_num = 2, dir = 2, one byte:
+--------+--------+--------+--------+--------+--------+--------+--------+ | A5 | 19 | 02 | 03 00 | 02 | 02 | 02 | lo hi | +--------+--------+--------+--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | ep_num | dir | bytes | CRC16 | +--------+--------+--------+--------+--------+--------+--------+--------+
Packet size
Per transfer typeAn OUT packet is the endpoint's wMaxPacketSize on the wire, as IN; the inter-chip relay carries a bulk payload in pieces of at most 64 bytes.
| Aspect | dir = 1, IN | dir = 2, OUT |
|---|---|---|
| Interrupt | one packet, at most the endpoint's wMaxPacketSize and at most 64 bytes | one packet, at most the endpoint's wMaxPacketSize |
| Bulk | split at wMaxPacketSize | |
| Bulk end | a short packet, or a zero-length packet (ZLP) when the payload is an exact multiple of wMaxPacketSize; an empty bytes sends one ZLP | |
bulk, wMaxPacketSize = 64 bytes = 130 --> [ 64 ] [ 64 ] [ 2 ] the 2-byte packet ends the transfer bytes = 128 --> [ 64 ] [ 64 ] [ ZLP ] an exact multiple ends on a ZLP bytes = 0 --> [ ZLP ]
| Name | Behaviour |
|---|---|
| HID IN, 8 reports | drops the oldest native report when full, else the oldest RAW one, counted in tx_drops |
| vendor interrupt IN, 8 packets | drops the oldest packet when full, counted in relay_drops |
| vendor bulk IN, 8 packets | drops the new packet when full, counted in relay_drops; at 6 queued it pauses the native bulk stream until the queue drains to 2 |
| OUT relay, 8 packets | drops the new packet when full, counted in relay_drops |
A bulk IN transfer longer than the queue's free slots reaches the game PC truncated. At wMaxPacketSize = 64, 510 bytes is 8 packets, the whole queue.
Lifetime
Held until the next native reportA RAW IN report is the last state the game PC read on that endpoint until the next native report replaces it.
A RAW report takes a poll of its own; no native report carries it. On an endpoint the device reports on every poll, it goes after at most two native reports.
native report [ btn 0 ] [ btn 0 ]
RAW, dir = 1 [ btn 1 ]
on the wire [ btn 0 ] [ btn 1 ] [ btn 0 ]
|<- last report read ->|A RAW packet goes straight to the endpoint, past every rewrite rule, clip packet trigger, LOCK, TRANSFORM, rendering and injection.
| Mechanism | Effect |
|---|---|
| report merging | sums motion between other queued reports and keeps each RAW report whole, byte for byte |
| change suppression | records a RAW report shaped like the mouse, keyboard or media report the box injects into as the last report emitted, the baseline for injected frames |
A clip raw item is the same packet on a clip tick, with its own release rule.
Catch taps
Traffic classes a RAW packet raisesA RAW IN packet raises TRAFFIC_EVENTs on the taps it passes. The HID_IN and OUT taps sit upstream of RAW's entry point.
| When | Raises |
|---|---|
the game PC reads a non-empty RAW report off a HID IN endpoint | EMIT (9), dir = 1 |
a RAW packet enters a vendor IN queue | VEND_INTR (6) or VEND_BULK (7), dir = 1, stamped clk = 1 by the device chip; bulk carries the end-of-transfer and ZLP flags |
the game PC reads a non-empty RAW packet off a vendor IN endpoint | EMIT (9), dir = 1 |