AR488 Protocol
The AR488 firmware on the ESP32 acts as a bridge between a serial/TCP text interface and the GPIB bus. All communication between mcgpib and the bridge uses a simple line-oriented ASCII protocol where commands to the bridge are prefixed with ++ and everything else is sent directly to the GPIB bus.
Prologix heritage
Section titled “Prologix heritage”The AR488 command set is based on the Prologix GPIB-USB adapter, a commercial product that established the ++ prefix convention for GPIB controller commands. Prologix adapters have been widely used since the mid-2000s, and many GPIB software tools support the protocol.
AR488 implements the full Prologix command set and extends it with additional features. This means software written for Prologix adapters generally works with AR488, and vice versa.
Command vs data mode
Section titled “Command vs data mode”The protocol has a simple rule: lines starting with ++ are commands to the bridge itself. Everything else is data that gets sent to the currently addressed instrument on the GPIB bus.
++addr 5 ← Command: set current GPIB address to 5MEAS:VOLT:DC? ← Data: sent to instrument at address 5++read eoi ← Command: read from instrument until EOIThere is no escape mechanism. If you need to send data to an instrument that literally starts with ++, you are out of luck (though no known instrument uses such a protocol).
How mcgpib uses the protocol
Section titled “How mcgpib uses the protocol”Every mcgpib tool call translates into a sequence of ++ commands and data strings. Here is what happens when the LLM calls instrument_query("bench-a", 22, "MEAS:VOLT:DC?"):
sequenceDiagram
participant M as mcgpib
participant AR as AR488 Bridge
participant BUS as GPIB Bus
participant I as Instrument<br/>(addr 22)
M->>AR: ++addr 22
Note over M,AR: 10ms delay
M->>AR: MEAS:VOLT:DC?
AR->>BUS: ATN + address 22
AR->>BUS: Send query string
Note over M,AR: 10ms delay
M->>AR: ++read eoi
AR->>BUS: Request data (NRFD/NDAC handshake)
I-->>BUS: +4.23451E+00 [EOI]
AR-->>M: +4.23451E+00
The bridge responds with the instrument’s data, which mcgpib reads as a line of ASCII text.
For instrument_write (no response expected), steps 5 is omitted — mcgpib sends the command but does not issue ++read.
The init sequence explained
Section titled “The init sequence explained”When mcgpib connects to a bridge, it sends a carefully ordered series of ++ commands to put the bridge in a known state. Each command addresses a specific requirement:
graph TD
START(["Connect transport"])
DRAIN1["Drain buffer<br/>(clear macro 0 output)"]
VERBOSE["++verbose 0"]
DRAIN2["Drain buffer<br/>(clear verbose response)"]
PROMPT["++prompt 0"]
AUTO["++auto 0"]
MODE["++mode 1"]
EOI["++eoi 1"]
EOS["++eos 0"]
TMO["++read_tmo_ms N"]
VER["++ver"]
CHECK{"Valid firmware<br/>version?"}
OK(["Bridge ready"])
FAIL(["BridgeInitError"])
START --> DRAIN1
DRAIN1 --> VERBOSE
VERBOSE --> DRAIN2
DRAIN2 --> PROMPT
PROMPT --> AUTO
AUTO --> MODE
MODE --> EOI
EOI --> EOS
EOS --> TMO
TMO --> VER
VER --> CHECK
CHECK -- "Yes" --> OK
CHECK -- "Timeout" --> FAIL
style START fill:#78350f,stroke:#d97706,color:#fde68a
style OK fill:#166534,stroke:#22c55e,color:#dcfce7
style FAIL fill:#7f1d1d,stroke:#ef4444,color:#fecaca
style CHECK fill:#78350f,stroke:#d97706,color:#fde68a
style DRAIN1 fill:#334155,stroke:#94a3b8,color:#e2e8f0
style VERBOSE fill:#334155,stroke:#94a3b8,color:#e2e8f0
style DRAIN2 fill:#334155,stroke:#94a3b8,color:#e2e8f0
style PROMPT fill:#334155,stroke:#94a3b8,color:#e2e8f0
style AUTO fill:#334155,stroke:#94a3b8,color:#e2e8f0
style MODE fill:#334155,stroke:#94a3b8,color:#e2e8f0
style EOI fill:#334155,stroke:#94a3b8,color:#e2e8f0
style EOS fill:#334155,stroke:#94a3b8,color:#e2e8f0
style TMO fill:#334155,stroke:#94a3b8,color:#e2e8f0
style VER fill:#334155,stroke:#94a3b8,color:#e2e8f0
++verbose 0
Section titled “++verbose 0”Purpose: Machine-parseable output.
With verbose mode on, the bridge returns human-readable strings like Current address: 5. With verbose off, it returns just 5. mcgpib needs to parse responses programmatically, so verbose must be off.
After sending this command, mcgpib drains the buffer because the ++verbose command itself might produce output in the old (verbose) format.
++prompt 0
Section titled “++prompt 0”Purpose: Clean response lines.
When the prompt is enabled, the bridge prepends a prompt character to its output, which would corrupt parsed responses. Disabling it ensures responses contain only data.
++auto 0
Section titled “++auto 0”Purpose: Explicit read control.
This is the most important setting. Auto mode controls whether the bridge automatically reads from the GPIB bus after sending data:
| Mode | Behavior |
|---|---|
auto 0 | Manual — read only when ++read is sent |
auto 1 | Prologix compatible — read after every data send |
auto 2 | On query — read after commands ending with ? |
auto 3 | Continuous — read repeatedly |
mcgpib uses auto 0 because:
- Write commands produce no response. In auto mode, the bridge would wait for a response that never comes, causing a timeout on every
instrument_writecall. - Timing control. mcgpib needs to decide exactly when to read, especially when inserting inter-command delays or handling slow instruments.
- Multi-step operations. Sequences like “address, send, delay, read” require fine-grained control that auto mode does not provide.
++mode 1
Section titled “++mode 1”Purpose: Controller mode.
Mode 1 sets the AR488 as a GPIB controller (as opposed to mode 0, which makes it act as a GPIB device). As controller, the AR488 can address instruments, initiate data transfers, and assert bus management signals like IFC and REN.
++eoi 1
Section titled “++eoi 1”Purpose: Proper message termination.
EOI (End Or Identify) is asserted on the last byte of every GPIB message. This tells the receiving device “this is the end of my message.” Without EOI, the receiver has to guess when a message ends based on a termination character — which is unreliable for binary data and can cause problems with instruments that embed newlines in their responses.
++eos 0
Section titled “++eos 0”Purpose: Consistent line endings.
EOS (End Of Send) controls what termination characters the bridge appends when sending data to the GPIB bus. Setting 0 appends CR+LF, which is the most commonly expected termination across instruments.
| Value | Termination |
|---|---|
| 0 | CR+LF |
| 1 | CR only |
| 2 | LF only |
| 3 | None (EOI only) |
++read_tmo_ms N
Section titled “++read_tmo_ms N”Purpose: Read timeout.
Sets how long the bridge waits for data when ++read is issued. If the instrument does not respond within this time, the bridge returns nothing and mcgpib raises a TimeoutError. The value comes from the bridge’s read_timeout_ms config setting.
Purpose: Communication verification.
After all settings are applied, mcgpib sends ++ver and reads the response. A valid firmware version string confirms that the bridge is communicating and processing commands correctly. If this step times out, the init fails — something is wrong with the connection.
Read modes in detail
Section titled “Read modes in detail”The ++read command has several forms:
| Syntax | Behavior |
|---|---|
++read eoi | Read until EOI is asserted (most reliable) |
++read 10 | Read until character 10 (LF) is received |
++read | Read until timeout |
mcgpib always uses ++read eoi because EOI provides an unambiguous end-of-message signal. Relying on character matching can fail when instrument data contains the termination character.
Key gotchas
Section titled “Key gotchas”Brownout detector
Section titled “Brownout detector”The ESP32’s brownout detector is disabled in the AR488 firmware (RTC_CNTL_BROWN_OUT_REG is cleared in setup()). GPIB bus activity causes current spikes through the SN75160/SN75161 transceiver ICs, which can dip the ESP32’s supply voltage below the brownout threshold. With the detector enabled, these dips would cause spontaneous resets.
This means the ESP32 will not self-protect against severe undervoltage. If powered from a weak USB source, it may silently corrupt data or lock up instead of cleanly resetting. Use a reliable power source.
Macro 0 auto-execution
Section titled “Macro 0 auto-execution”AR488 supports up to 10 macros (0—9) stored in NVS flash. Macro 0 executes automatically at startup. This is useful for instrument initialization (e.g., setting up a multimeter for a default measurement mode), but it can cause problems:
- If macro 0 sends output, it fills the receive buffer before mcgpib connects. mcgpib’s init sequence drains this buffer, but unexpected data can still cause timing issues.
- If macro 0 contains commands that change the bridge’s mode or settings, the init sequence may conflict with them.
- If macro 0 sends commands that hang (e.g.,
++readwith no talker), the bridge becomes unresponsive.
To clear macro 0: ++macro 0 clear (or ++macro 0 del).
++savecfg persistence
Section titled “++savecfg persistence”The ++savecfg command writes the current bridge configuration (mode, auto, eoi, eos, address, timeout, etc.) to the ESP32’s NVS flash. This survives power cycles.
The risk: if mcgpib’s init sequence changes a setting (which it always does), and someone sends ++savecfg, the bridge’s power-on defaults will reflect mcgpib’s settings — which may not be what you want for manual use with a serial terminal.
mcgpib never sends ++savecfg automatically. If you use the raw_command tool to send it, be aware that you are changing the bridge’s power-on behavior.
Verbose mode changes output format
Section titled “Verbose mode changes output format”When ++verbose 1 is set, commands like ++addr return Current address: 5 instead of 5. If verbose mode is accidentally enabled (e.g., by macro 0 or a previous session), mcgpib’s response parser will fail because it expects numeric values.
The init sequence sets ++verbose 0 first, then drains the buffer, specifically to handle this case.
AR488 extensions beyond Prologix
Section titled “AR488 extensions beyond Prologix”AR488 adds several commands that the original Prologix adapter does not support:
| Command | Purpose |
|---|---|
++findlstn | Find all listeners on the bus (returns space-separated addresses) |
++findrqs addr [addr ...] | Find which device is requesting service |
++allspoll addr [addr ...] | Serial poll multiple addresses in one operation |
++dcl | Send Universal Device Clear to all devices |
++ppoll | Conduct a parallel poll |
++xdiag mode byte | Bus diagnostics — write a byte directly to data or control bus |
++macro N [set|del] | Manage stored macros (0—9, 128 bytes each) |
++default | Reset to factory default configuration |
++id name [S] | Set/get the interface name |
++id serial [N] | Set/get the interface serial number |
++id verstr [S] | Set/get a custom version string |
++prompt [0|1] | Show/hide the command prompt |
++ren [0|1] | Assert/deassert Remote Enable |
mcgpib uses several of these extensions:
++findlstnforbus_scan— much more efficient than polling each address individually++allspollfor polling all instruments in a single command++findrqsfor identifying the SRQ source++dclfor universal device clear++ppollfor parallel poll operations++xdiagfor hardware-level bus diagnostics