Skip to content

RS-232 Communication

RS-232 is the default mode when you open a port with mcserial. It provides point-to-point serial communication with modem control lines — the signals that let you detect device presence, manage hardware flow control, and trigger resets.

All of the operations described in this guide are performed through your MCP client — ask the assistant to open ports, read modem lines, pulse reset signals, and so on. The tool call notation below shows exactly what the assistant calls on your behalf.

Every port opens in RS-232 mode automatically. No additional configuration is needed unless you want to switch to RS-485.

RS-232 defines six modem control lines. Four are inputs (read from the remote device) and two are outputs (set by you).

These reflect the state of the remote device. Read them with get_modem_lines:

LineFull NameWhat it means
CTSClear To SendRemote device is ready to receive data
DSRData Set ReadyRemote device is powered and present
RIRing IndicatorIncoming call (modems) or attention signal
CDCarrier DetectActive connection established
// get_modem_lines(port="/dev/ttyUSB0")
{
"success": true,
"port": "/dev/ttyUSB0",
"input_lines": {
"cts": true,
"dsr": true,
"ri": false,
"cd": false
},
"output_lines": {
"rts": true,
"dtr": true
},
"break_condition": false
}

These are signals you send to the remote device. Set them with set_modem_lines:

LineFull NameCommon uses
RTSRequest To SendHardware flow control, TX enable for RS-485 converters
DTRData Terminal ReadySignal our presence, trigger device reset
// set_modem_lines(port="/dev/ttyUSB0", rts=true, dtr=true)
{
"success": true,
"port": "/dev/ttyUSB0",
"rts": true,
"dtr": true
}

You can set one or both lines in a single call. Pass null (omit the parameter) to leave a line unchanged.

Many development boards use DTR or RTS to trigger a hardware reset. The pulse_line tool handles the timing for you.

Arduino boards use DTR to reset the microcontroller. When DTR goes low, the reset capacitor pulls the RESET pin low briefly, rebooting the chip.

// pulse_line(port="/dev/ttyUSB0", line="dtr", duration_ms=100, active_low=true)
{
"success": true,
"port": "/dev/ttyUSB0",
"line": "dtr",
"duration_ms": 100,
"active_low": true
}

The active_low=true parameter (the default) means the line pulses LOW then returns HIGH — exactly what Arduino expects.

Practical example: connect to Arduino, reset, read boot output

Section titled “Practical example: connect to Arduino, reset, read boot output”
  1. Open the serial port

    Open the port at 115200 baud (common for Arduino). If you are unsure of the baud rate, omit it and mcserial will attempt auto-detection.

    // open_serial_port(port="/dev/ttyACM0", baudrate=115200)
    {
    "success": true,
    "port": "/dev/ttyACM0",
    "mode": "rs232",
    "baudrate": 115200,
    "resource_uri": "serial:///dev/ttyACM0/data"
    }
  2. Flush any stale data in the buffer

    Clear out anything sitting in the receive buffer from before the reset.

    // flush_serial(port="/dev/ttyACM0")
    {
    "success": true,
    "port": "/dev/ttyACM0",
    "flushed_input": true,
    "flushed_output": true
    }
  3. Pulse DTR to reset the Arduino

    A 100ms DTR pulse is enough for any Arduino board.

    // pulse_line(port="/dev/ttyACM0", line="dtr", duration_ms=100, active_low=true)
    {
    "success": true,
    "port": "/dev/ttyACM0",
    "line": "dtr",
    "duration_ms": 100,
    "active_low": true
    }
  4. Read the bootloader and startup output

    After reset, the Arduino bootloader prints a brief message, then your sketch starts. Read multiple lines to capture everything.

    // read_serial_lines(port="/dev/ttyACM0", max_lines=20)
    {
    "success": true,
    "lines": [
    "",
    "Sketch starting...",
    "Initializing sensors...",
    "Ready."
    ],
    "count": 4,
    "bytes_read": 52,
    "port": "/dev/ttyACM0"
    }
  5. Interact with the running sketch

    Send commands and read responses as needed.

    // write_serial(port="/dev/ttyACM0", data="STATUS\r\n")
    {
    "success": true,
    "bytes_written": 8,
    "port": "/dev/ttyACM0"
    }

A break signal is a sustained LOW state on the TX line that lasts longer than a normal character frame. Some devices use break signals to enter configuration mode, trigger a reset, or synchronize communication.

mcserial provides two ways to send breaks:

send_break holds the line LOW for a fixed duration, then releases it. This is the most common usage.

// send_break(port="/dev/ttyUSB0", duration_ms=250)
{
"success": true,
"port": "/dev/ttyUSB0",
"duration_ms": 250
}

The default duration is 250ms, which is long enough for most devices. The valid range is 1ms to 5000ms.

set_break_condition holds the TX line LOW indefinitely until you explicitly release it. Use this when a protocol requires a sustained break state.

// Assert break (hold TX low)
// set_break_condition(port="/dev/ttyUSB0", enabled=true)
{
"success": true,
"port": "/dev/ttyUSB0",
"break_condition": true
}
// Release break (return to normal)
// set_break_condition(port="/dev/ttyUSB0", enabled=false)
{
"success": true,
"port": "/dev/ttyUSB0",
"break_condition": false
}

The current break state is also reported in the get_modem_lines response under break_condition.

You can verify the state of all modem lines at any time with get_modem_lines. This is useful for:

  • Detecting device presence — check DSR before attempting communication
  • Debugging connections — verify CTS is asserted if hardware flow control is in use
  • Monitoring — poll RI or CD for incoming events on modem-style devices
// get_modem_lines(port="/dev/ttyUSB0")
{
"success": true,
"port": "/dev/ttyUSB0",
"input_lines": {
"cts": true,
"dsr": false,
"ri": false,
"cd": false
},
"output_lines": {
"rts": true,
"dtr": true
},
"break_condition": false
}

In this example, CTS is asserted (the device can receive data) but DSR is low (the device may not be powered or connected). This is a common state for USB-serial adapters that loop CTS back internally but do not connect DSR.