Part 5 — Control
How a product's settings are seen and changed from outside it. CTRL-USB (8.1) is a feature: a USB 2.0 service port behind the panel through which a case host, or MIDI 2.0 software on a computer, lists and sets a product's parameters with the MIDI-CI Property Exchange standards. The host bridge protocol (8.2) is what a case host offers a computer so that the computer reaches each product's console, and updates its firmware, through the host. This part is a protocol specification; nothing in it changes whether a product fits a row or patches to another.
Contents
- 8.1 USB service port and parameter interface (CTRL-USB): Feature CTRL-USB: the USB service port and the MIDI 2.0 parameter interface
- 8.2 Host bridge protocol: The host bridge protocol a case host offers a computer
8.1 USB service port and parameter interface (CTRL-USB)
CTRL-USB is an optional feature in two roles: a CTRL-USB device, a module, supply, converter, bus board, or enclosure whose settings are seen and changed through a CTRL-USB port behind its panel; and a case host, a module or a bus board that connects to those ports and edits them. The leads between them are cables of the feature; a claim file gives the role. The port is a USB 2.0 device; its parameters follow the MIDI 2.0 standards of the MIDI Association and AMEI, so any conforming host, and any MIDI 2.0 software on a computer, can list and set them without knowing the product. EIS adds what those standards leave open: the connector, the read-back of current values, and an optional description of units. The figures are in data/ctrl_usb.json; the units schema is data/ctrl-units-v1.schema.json.
The port
A CTRL-USB device shall have a USB 2.0 full-speed device port on a USB-PH4 connector with the pin functions tabulated below (USB-001). The port shall be marked USB beside it and shall withstand 5.25 V or 0 V on any of its pins without damage (USB-002): a lead made for another purpose with the same housing can be fitted to it. A product shall draw no more than 100 mA from VBUS at its CTRL-USB port and shall not drive VBUS (USB-003). In a row it runs from its power entries (6.1); VBUS may power it on a bench.
| Variant | Header (reference) | Mating housing (reference) | Rated per circuit (A) |
|---|---|---|---|
| USB-PH4 | JST B4B-PH-K-S (top entry) or S4B-PH-K-S (side entry) | JST PHR-4 with SPH-002T-P0.5S crimp terminals | 2 |
USB-PH4 pins
| Pin | Function |
|---|---|
| 1 | VBUS |
| 2 | D− |
| 3 | D+ |
| 4 | 0 V (GND) |
| Figure | Value |
|---|---|
| Signalling | USB 2.0 full speed, 12 Mbit/s |
| VBUS drawn by a device | at most 100 mA; never driven |
| Withstood on any pin | 5.25 V or 0 V |
| Lead | at most 300 mm, D+ and D− twisted, at least 28 AWG |
| Case host port | current limit at most 500 mA, switched per port |
A CTRL-USB lead shall connect each pin to the same pin at both ends, be no longer than 300 mm, and twist the D+ and D− conductors as a pair (USB-004). The CTRL-USB lead joins the 0 V of the two products it connects, like a patch cable (6.3).
Identity
A CTRL-USB device's iProduct string shall be the product name its claim gives, and its iSerial string shall be unique to the unit and the same at every enumeration (USB-005). A host tells two units of one product apart by iSerial, and finds a unit again after it moves to another port. Products of one maker may share a USB product ID; iProduct names the product.
A CTRL-USB device shall use its maker's own System Exclusive manufacturer ID in MIDI-CI, never the non-commercial ID 7D (USB-006). A manufacturer ID is a paid, one-time registration with the MIDI Association; it is the one cost this feature puts on a maker.
Parameter interface
A CTRL-USB device shall present a USB-MIDI 2.0 function with alternate setting 1 carrying one Universal MIDI Packet endpoint pair, and alternate setting 0 carrying USB-MIDI 1.0 (USB-007). It shall answer MIDI-CI discovery and Property Exchange with the resources ResourceList, DeviceInfo, and AllCtrlList, and CtrlMapList when any control is a toggle or a list (USB-008). Each AllCtrlList entry shall give a CtrlMapList for a toggle or a list and a stepCount for a control that moves in steps, and shall be set by a 32-bit Control Change, RPN, or NRPN message (USB-009).
The standards give a host no way to read a control's current value. On a Property Exchange subscription to AllCtrlList, a CTRL-USB device shall send the current value of every control whose transmit is not false as its controller message, and send it again whenever it changes (USB-010). A CTRL-USB device shall keep working when a host closes its MIDI endpoints and opens them again (USB-011); a host with few endpoints parks the devices it is not showing.
Units
A control's 32-bit value says nothing of its engineering units. A device that gives an x-units object on a controller entry shall serve the ctrl-units-v1 schema as the JSONSchema resource with resId ctrl-units-v1 and follow it (USB-012): the engineering values at the two ends of the entry's range, mapped linearly, with a unit, decimals, a fine and a coarse step, and the origin of a bipolar bar.
| Field | Meaning | |
|---|---|---|
min |
required | Engineering value at minMax[0] |
max |
required | Engineering value at minMax[1] |
unit |
optional | Shown after the value: an SI symbol (ns, kHz, ms, V), %, °, or a short word |
decimals |
optional | |
step |
optional | Fine step in engineering units; values are rounded to it. Default 10^-decimals |
coarse |
optional | Normal (coarse) step; default = step |
zero |
optional | Bar origin for bipolar controls; default 0 when min < 0 < max, else min |
Mapping: v = min + (raw − minMax[0]) / (minMax[1] − minMax[0]) × (max − min); a value outside minMax is clamped.
EIS recommends x-units on every continuous control: "+2000 ns" tells the user more than "53.1 %". A host that finds no ctrl-units-v1 resource ignores every x-units the device sends and shows the standard fields.
Case host
A case host is a module or a bus board in the host role: it claims module (CTRL-USB-HOST) or bus board (CTRL-USB-HOST), meets every requirement of its own role, and these as well. A case host shall give each downstream port its own current limit of at most 500 mA and a switch that power-cycles that port alone (USB-013), and shall mark each downstream port with the number it shows for that port (USB-014). It shall find and edit the controls of any CTRL-USB device with the interfaces of this clause alone, showing a control without x-units by its standard fields: a percentage of its range, its step, or its map's titles (USB-015). A case host that closes a device's endpoints shall subscribe to AllCtrlList again when it opens them (USB-016).
A case host that offers a computer a link to the products behind it, for their consoles or their firmware, shall implement the host bridge protocol of 8.2 (USB-017). The products' own console commands and firmware formats stay their makers'.
tools/pe_check.py checks a device's Property Exchange resources, saved as JSON, against USB-008, USB-009, and USB-012; data/examples/pe-video-reference-generator.json is a worked example.
8.2 Host bridge protocol
A case host that offers a computer a link to the products behind it implements this protocol (USB-017, 8.1). The computer then reaches each product's console through the host, and updates a product's firmware through the host, without the product ever appearing on the computer's own USB. The machine-readable form is data/bridge_v1.json.
8.2.1 The link
The host is a USB device on the computer with one CDC interface. In console mode the interface carries the host's own text console, whose commands are the host maker's. The console command bridge switches it to bridge mode: framed binary, until a CLOSE frame on channel 0 or until the computer drops DTR. One interface for both keeps the computer from having to tell two interfaces apart.
8.2.2 Frames
Each frame is COBS-encoded and ends with one 0x00 byte; multi-byte fields are little-endian. CRC: CRC-16/CCITT-FALSE (poly 0x1021, init 0xFFFF, no reflection, no final XOR) over every field before it.
| Field | Bytes | |
|---|---|---|
ver |
1 | Protocol version, 1 |
chan |
1 | 0 is the control channel; 1 to 255 are assigned by open or update |
type |
1 | Frame type, below |
seq |
2 | Per channel; a reply echoes the request's seq |
len |
2 | Payload length, at most max_payload |
payload |
len | JSON for CTRL and EVENT; bytes for DATA; a u32 byte count for CREDIT |
crc |
2 | CRC over the fields above |
| Type | Code | |
|---|---|---|
CTRL |
1 | A request, or the reply to one |
EVENT |
2 | Something changed; no reply |
DATA |
3 | Bytes for a tunnel or an update |
CREDIT |
4 | The receiver grants more bytes on the channel |
CLOSE |
5 | The channel ends; on channel 0, bridge mode ends |
A frame with a bad CRC or a bad COBS encoding is dropped. The sender of a request retries it after a timeout. Flow control is by credit, per channel: the receiver grants bytes with CREDIT, and the sender never has more than that in flight. A host grants no more than the buffer it has for the channel.
8.2.3 Control channel
Requests and replies are CTRL frames on channel 0 with JSON payloads. hello is the first frame of a session.
Each request is a JSON object whose cmd names the command; its other fields and the reply's are below.
cmd |
Request fields | Reply fields | |
|---|---|---|---|
hello |
proto | proto, host (fw, serial), ports, maxPayload | The first frame of a session; versions and limits |
ports |
— | for each port: port, power, mode (app, update, empty), usb (vid, pid, manufacturer, product, serial, classes), last | Each downstream port; last is the product that was on it before it entered update mode |
open |
port | chan | A tunnel: a byte pipe to the product's console interface |
close |
chan | — | Ends a tunnel or an update |
update |
port, method, size, sha256, product, and the method's own | chan, credit | Streams a firmware image on DATA frames; the method names how the host writes it |
power_cycle |
port | — | Switches the port's power off and on (USB-013) |
| Event | Payload fields | |
|---|---|---|
attach |
the port's ports entry | A product appeared on a port |
detach |
port | A product left a port |
state |
port, mode | A port's mode changed |
update |
chan, stage, pct; or stage error with code and message | Progress of an update |
A product's identity in ports is its iSerial (USB-005), which survives the product's reboots and a move to another port. last is the identity a port had before it entered update mode, when a boot loader answers there in the product's place; it lets the computer recover a product that stopped in its boot loader.
8.2.4 Updates
update names a method, and the host runs that method's stages, reporting each in an update event. The host streams the image: it holds no copy, writes each block as it arrives, and checks the SHA-256 of the whole stream before the last block. One update runs at a time; tunnels to other products stay open. An abort before the write leaves the product running; an abort during the write leaves it in its boot loader, from which the same update recovers it. The one method defined suits any product whose boot loader presents a UF2 mass-storage volume; the boot ROMs of the RP2040 and RP2350 microcontrollers are two such loaders, and a product names its UF2 family in the update request.
| Method | For | Stages | |
|---|---|---|---|
uf2-msc |
Any product whose boot loader presents a UF2 mass-storage volume | PREFLIGHT, ENTER, WAIT_LOADER, CHECK, WRITE, WAIT_APP, VERIFY, DONE | The host asks the product to enter its boot loader, waits for the mass-storage volume on the same port, checks the first UF2 block's family and size, writes each 512-byte block as it arrives, and waits for the product to return with the same iSerial |
| Error | |
|---|---|
no_module |
Nothing in app mode on the port |
product_mismatch |
The port's iProduct is not the update's product |
no_loader |
The product did not enter its boot loader |
loader_timeout |
No boot loader appeared on the port |
bad_image |
The image's format, family, or size is wrong |
write_failed |
The host could not write a block |
hash_mismatch |
The streamed image's SHA-256 is not the one announced |
no_app |
The product did not return after the write; the port stays in update mode, recoverable |
A host that updates a product whose outputs a row depends on, such as a video reference generator, asks the user before it starts: the row loses them until the product returns.