Medius - Native APITransfer

Transfer

One control request on the real device

TRANSFER runs one USB control transfer on the real device from the control PC; TRANSFER_RESP returns the result: a descriptor, a string, a vendor value, or the handshake that ended it.

  control PC           DEVICE chip            HOST chip            real device
      |                     |                      |                     |
      |-- TRANSFER, SEQ n ->|                      |                     |
      |                     |-- link request ----->|                     |
      |                     |                      |-- SETUP, OUT data ->|
      |                     |                      |<-- IN data, status -|
      |                     |<-- link answer ------|                     |
      |<- TRANSFER_RESP, n -|                      |                     |

The request crosses the inter-chip link on its own messages and joins the game PC's control requests in the host chip's control queue.

TRANSFER is advanced control and runs only under the imperfect-clone opt-in. Otherwise a request with a full setup packet gets 0xFC and never reaches the device.

TRANSFER

One request, one reply

TRANSFER carries a target endpoint, an eight-byte setup packet, and any OUT data stage. Opcode 0x1A.

TRANSFER 0x1A · payload 9..512 bytes

Reply

PAYLOAD
OffsetFieldTypeNotes
0epu80 = EP0, else a control endpoint the real device declares, matched on bits 0-3
1bmRequestTypeu8bit 7 is direction: 1 IN, 0 OUT
2bRequestu8request code
3wValueu16little-endian
5wIndexu16little-endian
7wLengthu16data stage length, little-endian, at most 504
9..datau8[]OUT only: the first wLength bytes are the data stage

Offsets 1 to 8 are the setup packet exactly as the device receives it, never rewritten or retried.

DATA STAGE
ValueEffect
bit 7 = 1, INbytes after offset 8 ignored; the reply carries what the device sent, up to wLength
bit 7 = 0, OUTthe first wLength bytes sent, the rest ignored; fewer is refused

An OUT stage tops out at 503 bytes, what a 512-byte payload leaves after ep and the setup packet.

A SET_CONFIGURATION or SET_INTERFACE sent here changes only the real device; the clone and the endpoints the host chip polls stay as the game PC set them.

REFUSALS
WhenSends
payload under 9 bytesnothing; frame discarded
opt-in off0xFC
wLength above 5040xFC
OUT request with fewer than wLength data bytes0xFC
host chip control queue full, from any user0xFC
nonzero ep naming no declared control endpoint0xFE, or 0xFF with no device attached
EXAMPLE

GET_DESCRIPTOR(device) on EP0, 18 bytes: setup 80 06 00 01 00 00 12 00.

+--------+--------+--------+--------+--------+
| A5     | 1A     | 07     | 09 00  | 00     |
+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | ep     |
+--------+--------+--------+--------+--------+

+---------------+----------+--------+--------+--------+--------+
| 80            | 06       | 00 01  | 00 00  | 12 00  | lo hi  |
+---------------+----------+--------+--------+--------+--------+
| bmRequestType | bRequest | wValue | wIndex | wLength| CRC16  |
+---------------+----------+--------+--------+--------+--------+

An OUT request: SET_REPORT(Output) on interface 0 with one data byte, 02, a boot keyboard's Caps Lock LED.

+--------+--------+--------+--------+--------+
| A5     | 1A     | 08     | 0A 00  | 00     |
+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | ep     |
+--------+--------+--------+--------+--------+

+---------------+----------+--------+--------+--------+--------+--------+
| 21            | 09       | 00 02  | 00 00  | 01 00  | 02     | lo hi  |
+---------------+----------+--------+--------+--------+--------+--------+
| bmRequestType | bRequest | wValue | wIndex | wLength| data   | CRC16  |
+---------------+----------+--------+--------+--------+--------+--------+

Library bindings: transfer, transfer_timeout, and the AsyncDevice forms.

TRANSFER_RESP

Result of one TRANSFER

One reply per TRANSFER with a full setup packet, its SEQ echoing the command's. Opcode 0x1B.

TRANSFER_RESP 0x1B · payload 2..506 bytes

Reply

PAYLOAD
OffsetFieldTypeNotes
0epu8echoes the command's ep byte
1statusu8how the transfer ended, as below
2..datau8[]IN data stage, only on an IN request with status = 0; length from the frame LEN
STATUS
ValueStateMeans
0x00completedthe device finished the status stage; an IN request's data follows
0xFCrefusedstopped before the device, per the refusals
0xFDSTALLthe device STALLed the request
0xFEno answerdevice didn't finish within 500 ms, the transfer failed on the bus, the endpoint is undeclared, or no reply crossed the link within 800 ms
0xFFno devicenothing attached on the host chip, or the host chip is re-enumerating it

The same codes flag a CLIP_XFER event, the transfer a clip runs.

EXAMPLE

The device descriptor for SEQ 07 (18 data bytes, so LEN = 20):

+--------+--------+--------+--------+--------+--------+
| A5     | 1B     | 07     | 14 00  | 00     | 00     |
+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | ep     | status |
+--------+--------+--------+--------+--------+--------+

+--------------------------------------------+--------+
| 12 01 00 02 00 00 00 40 ...  (18 bytes)    | lo hi  |
+--------------------------------------------+--------+
| IN data: the device descriptor             | CRC16  |
+--------------------------------------------+--------+

A device that STALLs SEQ 08's request (no data):

+--------+--------+--------+--------+--------+--------+--------+
| A5     | 1B     | 08     | 02 00  | 00     | FD     | lo hi  |
+--------+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | ep     | status | CRC16  |
+--------+--------+--------+--------+--------+--------+--------+

One at a time

A TRANSFER holds the control port until its reply

The box runs a TRANSFER to completion before reading the next control frame, so replies arrive in command order.

  TRANSFER A --> [ runs, up to 800 ms ] --> TRANSFER_RESP A
  TRANSFER B --> waits on the box -------------------------> [ runs ] --> TRANSFER_RESP B
  MOVE, ...  --> waits on the box -------------------------> applied in arrival order
TIMING
QuantityValue
Device reply, host chip500 ms, then 0xFE.
Link reply, device chip800 ms, then 0xFE.
Frames held while one runs63 frames, the running one included, or just under 16 KiB of payload; a frame past either is dropped.
Injection silence timerRestarts when the frame is read and again when a reply arrives; an 800 ms timeout leaves it counting from the frame.

Every other command waits behind a running TRANSFER, including MOVE and INJECT; keep transfers out of time-critical streams.

An 0xFE from the 800 ms window leaves the request queued on the host chip; it can still reach the device after the reply, and its late result is dropped.

One control queue

Requests to the real device take turns

The host chip feeds the real device one control request at a time from one six-deep queue, shared by TRANSFER, the game PC's requests, clip transfers, and the box's own.

  game PC ------EP0------> clone -----------------+
                                                  |
  clip transfer items ---> DEVICE chip -----------+
                                                  |
  control PC --TRANSFER--> DEVICE chip -----------+--> HOST chip queue --> real device
                                                  |    six deep            one at a time
  halt clears, baseline reads (HOST chip) --------+

A queue filled by any of them refuses a TRANSFER with 0xFC.

TAPS

A TRANSFER runs outside every tap, rule and trigger: CATCH CONTROL, REWRITE on CONTROL, and clip packet triggers cover the game PC's traffic only.

A slow request holds the device's EP0 for up to 500 ms, and a game PC request queued behind it waits that long.