Skip to content

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.

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.

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 5
MEAS:VOLT:DC? ← Data: sent to instrument at address 5
++read eoi ← Command: read from instrument until EOI

There 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).

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.

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

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.

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.

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:

ModeBehavior
auto 0Manual — read only when ++read is sent
auto 1Prologix compatible — read after every data send
auto 2On query — read after commands ending with ?
auto 3Continuous — 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_write call.
  • 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.

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.

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.

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.

ValueTermination
0CR+LF
1CR only
2LF only
3None (EOI only)

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.

The ++read command has several forms:

SyntaxBehavior
++read eoiRead until EOI is asserted (most reliable)
++read 10Read until character 10 (LF) is received
++readRead 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.

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.

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., ++read with no talker), the bridge becomes unresponsive.

To clear macro 0: ++macro 0 clear (or ++macro 0 del).

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.

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 adds several commands that the original Prologix adapter does not support:

CommandPurpose
++findlstnFind 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
++dclSend Universal Device Clear to all devices
++ppollConduct a parallel poll
++xdiag mode byteBus diagnostics — write a byte directly to data or control bus
++macro N [set|del]Manage stored macros (0—9, 128 bytes each)
++defaultReset 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:

  • ++findlstn for bus_scan — much more efficient than polling each address individually
  • ++allspoll for polling all instruments in a single command
  • ++findrqs for identifying the SRQ source
  • ++dcl for universal device clear
  • ++ppoll for parallel poll operations
  • ++xdiag for hardware-level bus diagnostics