# Send SCPI and G-code From Your Dashboard

> How SCPI and G-code work on the wire, why sending commands is harder than reading data, and how dashboard controls format outbound messages safely.
>
> Control · July 5, 2026 · by Alex Spataru · https://serial-studio.com/blog/control-devices-scpi-gcode

Reading data from a device is passive. Whatever arrives, you parse it, plot it, and nothing bad happens if you get it slightly wrong. Sending a command is a transaction: it has to be formatted exactly the way the device expects, terminated correctly, and acknowledged. That asymmetry is why so many home-grown dashboards are read-only. This post looks at the two command languages you are most likely to meet, SCPI on the bench and G-code on a machine, and at what it takes to wire a slider or a switch to them.

## SCPI, the language of bench instruments

SCPI (Standard Commands for Programmable Instruments) is an ASCII command language layered on IEEE 488.2, and nearly every modern bench instrument speaks it: Keysight, Rigol, Siglent, Rohde & Schwarz, Tektronix. Commands form a tree with colon-separated keywords, and each keyword has a long and a short form, so these two lines are the same command:

```
MEASURE:VOLTAGE:DC?
MEAS:VOLT:DC?
```

A trailing `?` makes a command a query that returns data. Commands starting with `*` are IEEE 488.2 common commands every compliant instrument must implement: `*IDN?` returns the identification string, `*RST` resets, `*OPC?` blocks until pending operations finish. A real session with a Rigol DP832 power supply looks like this:

```
*IDN?           → RIGOL TECHNOLOGIES,DP832,...
:INST CH1         select channel 1
:VOLT 3.3         set 3.3 V
:CURR 1           set the current limit
:OUTP CH1,ON      enable the output
:MEAS:VOLT? CH1   read back what actually happened
```

The transport varies (USB-TMC, a raw TCP socket on port 5025 for LAN instruments, plain serial on older gear) but the framing convention is stable: one command per line, terminated with `\n`. Two habits keep sessions healthy. Set limits before you enable an output, and read values back instead of trusting the setpoint you sent.

## G-code, the language of motion

CNC controllers and 3D printers speak G-code, and the most common open firmware dialect is Grbl (and its actively developed successor, grblHAL). The protocol is strict and simple: you send one ASCII line, the controller answers every line with exactly `ok` or `error:N`, and you do not send the next line until you hear back. A handful of single-character realtime commands bypass the line buffer entirely and get no reply: `?` requests a status report, `!` is feed hold, `~` resumes, and Ctrl-X soft-resets.

For a dashboard, the most useful part of Grbl 1.1 is the jogging interface:

```
$J=G91 X10.00 F500
```

That jogs the X axis 10 mm at 500 mm/min. Jog commands are checked against soft limits before they execute, they do not disturb the G-code parser's modal state, and an in-flight jog can be cancelled instantly. Those properties exist precisely so that a hold-a-button UI can be safe.

## Why the write path is harder than the read path

Three things make control messier than monitoring. First, formatting: `VOLT 3.3` and `$J=G91 X3.30 F500` encode the same user intent for different devices, and the device rejects anything else. Second, interleaving: command replies arrive on the same line as streaming telemetry, so the reader has to tell `ok` apart from data. Grbl helps by making status reports syntactically distinct (`<Idle|MPos:...>`); SCPI does not, which is why an unread query reply desynchronizes every read that follows. Third, state: the UI's belief and the device's truth drift apart, so a good dashboard displays what the device reports, not what the user last asked for.

## Wiring a slider to the wire

Serial Studio's approach is to keep the widget generic and put the device-specific part in a small script. The [output widgets](https://serial-studio.com/help/output-controls) (buttons, toggles, sliders, knobs, text fields) each carry a `transmit(value)` function that turns the widget's value into the exact bytes to send. The bundled SCPI template is short enough to read in full:

```js
function transmit(value) {
  if (typeof value === "string")
    return value + "\n";
  if (value === 0 || value === 1)
    return "OUTP1 " + (value ? "ON" : "OFF") + "\n";
  return "SOUR1:VOLT " + Number(value).toFixed(3) + "\n";
}
```

A toggle sends `OUTP1 ON`, a slider sends `SOUR1:VOLT 3.300`, and a text field passes raw SCPI through. The G-code and Grbl templates have the same shape: a switch maps to `M3`/`M5` for the spindle, a slider maps to a `$J=` jog, a text field sends `$H` or `$$` verbatim. Because the formatting lives in an editable script rather than in application code, adapting it to your instrument means changing one line, and a transmit test dialog shows the exact bytes a value will produce before anything reaches the port. Output widgets are part of [Serial Studio Pro](https://serial-studio.com/help/pro-vs-free).

## Keep the safety rails physical

One convention matters more than all the others: an emergency stop must not depend on software. A dashboard button is a convenience, not a safety device, because it sits behind an operating system, a serial driver, and a cable. Real machine safety lives in hardware power cutoff, in controller-side soft limits, and in instrument-side protection like over-voltage and over-current clamps that fire no matter what the host sends. Configure those first, then enjoy the slider.

If the vocabulary of downlink and telecommand is new, [What Is Telemetry?](https://serial-studio.com/blog/what-is-telemetry) covers the read path this post writes back against, and [Serial Studio Isn't Just for Serial Ports](https://serial-studio.com/blog/not-just-serial-ports) tours the transports these commands travel over.
