Flow Control
Flow control prevents data loss when one side of a serial connection sends data faster than the other side can process it. Without flow control, the receiver’s buffer fills up, and incoming bytes are silently dropped.
There are two approaches: software flow control using in-band control characters, and hardware flow control using dedicated signal lines. mcserial provides tools for enabling and managing both types — your MCP assistant configures flow control when opening a port or via configure_serial on an already-open port.
Software flow control (XON/XOFF)
Section titled “Software flow control (XON/XOFF)”Software flow control uses two special byte values embedded in the data stream:
| Character | Hex | ASCII | Meaning |
|---|---|---|---|
| XON | 0x11 | Ctrl-Q | ”Resume sending — I can accept data” |
| XOFF | 0x13 | Ctrl-S | ”Stop sending — my buffer is full” |
When the receiver’s buffer fills up, it sends XOFF to the sender. The sender pauses until it receives XON, then resumes transmission.
Enabling XON/XOFF
Section titled “Enabling XON/XOFF”Enable it when opening a port:
// open_serial_port(port="/dev/ttyUSB0", baudrate=9600, xonxoff=true)Or toggle it on an open port:
// configure_serial(port="/dev/ttyUSB0", xonxoff=true){ "success": true, "port": "/dev/ttyUSB0", "xonxoff": true, "rtscts": false, "dsrdtr": false}Manual flow gating
Section titled “Manual flow gating”The set_flow_control tool lets you manually send XON/XOFF signals or pause/resume your own output:
// Tell the remote device to stop sending// set_flow_control(port="/dev/ttyUSB0", input_flow=false){ "success": true, "port": "/dev/ttyUSB0", "changes": {"input_flow": false}, "flow_control_enabled": {"xonxoff": true, "rtscts": false}}
// Tell the remote device to resume sending// set_flow_control(port="/dev/ttyUSB0", input_flow=true)input_flow=truesends XON (allow the remote device to send to us)input_flow=falsesends XOFF (tell the remote device to pause)output_flow=trueresumes our outgoing dataoutput_flow=falsepauses our outgoing data
Flow control must already be enabled (via xonxoff=true or rtscts=true) for these signals to have effect.
Advantages and limitations
Section titled “Advantages and limitations”Advantages:
- Works on any serial connection, including 3-wire (TX, RX, GND) cables with no additional signal lines
- Works over network serial connections (
socket://,rfc2217://) - No extra hardware required
Hardware flow control (RTS/CTS)
Section titled “Hardware flow control (RTS/CTS)”Hardware flow control uses dedicated signal lines rather than in-band bytes. The most common pair is RTS (Request To Send) and CTS (Clear To Send).
When the receiver’s buffer is getting full, it deasserts CTS. The sender watches CTS and pauses transmission until CTS is asserted again. Because the signaling happens on separate wires, it works with any data content — there are no reserved byte values.
Enabling RTS/CTS
Section titled “Enabling RTS/CTS”Enable it when opening a port:
// open_serial_port(port="/dev/ttyUSB0", baudrate=115200, rtscts=true)Or toggle it on an open port:
// configure_serial(port="/dev/ttyUSB0", rtscts=true){ "success": true, "port": "/dev/ttyUSB0", "xonxoff": false, "rtscts": true, "dsrdtr": false}Advantages and limitations
Section titled “Advantages and limitations”Advantages:
- Works with binary data — no reserved byte values
- Faster response than XON/XOFF (hardware signal vs. byte transmission delay)
- Handled by the UART hardware, not software
Limitations:
- Requires a cable with RTS and CTS lines connected (some cheap cables omit them)
- Not available on 3-wire serial connections
- Not meaningful on
socket://network connections (no physical lines to assert)
Hardware flow control (DSR/DTR)
Section titled “Hardware flow control (DSR/DTR)”An alternative hardware flow control pair. DSR (Data Set Ready) and DTR (Data Terminal Ready) can serve as flow control signals when RTS/CTS is unavailable or already used for another purpose.
// open_serial_port(port="/dev/ttyUSB0", baudrate=9600, dsrdtr=true)DSR/DTR flow control is less common than RTS/CTS. Most devices that support hardware flow control use RTS/CTS.
Choosing the right flow control
Section titled “Choosing the right flow control”| Scenario | Recommended | Reason |
|---|---|---|
| Text/ASCII protocols (AT commands, console) | XON/XOFF | Simple, no extra wires needed |
| Binary protocols (Modbus RTU, firmware transfer) | RTS/CTS | No byte value conflicts |
Network serial (socket://) | None | TCP handles flow control at the transport layer |
| High-speed transfers (115200+) | RTS/CTS | Faster response, less latency than XON/XOFF |
| 3-wire cable (TX, RX, GND only) | XON/XOFF | RTS/CTS lines not available |
| RS-485 bus | XON/XOFF or None | RTS is used for direction control |
| Unknown device | Start with None | Add flow control if you see buffer overruns |
Flow control in mcserial
Section titled “Flow control in mcserial”All flow control options are available in two places:
At open time:
// open_serial_port(// port="/dev/ttyUSB0",// baudrate=9600,// xonxoff=false,// rtscts=false,// dsrdtr=false// )On an already-open port:
// configure_serial(// port="/dev/ttyUSB0",// xonxoff=true,// rtscts=false,// dsrdtr=false// )You can enable multiple flow control methods simultaneously, though this is unusual. The most common configurations are:
- No flow control (all false) — suitable when you control the data rate, or when using protocols that handle their own flow management
- XON/XOFF only — text terminals, console access, simple ASCII protocols
- RTS/CTS only — binary transfers, high-speed communication, GPS receivers
Detecting flow control problems
Section titled “Detecting flow control problems”If you suspect flow control issues, look for these symptoms:
- Missing data in the middle of a transfer: the receiver’s buffer overflowed and bytes were dropped. Enable flow control.
- Data stops flowing and never resumes: the sender received XOFF but never got XON (or CTS was deasserted and never reasserted). Check cable connections and remote device state.
- Corrupted binary data with 0x11 or 0x13 bytes missing: XON/XOFF is enabled on a binary stream. Switch to RTS/CTS or disable flow control.
Use get_connection_status to check the current flow control configuration and modem line states for all open ports.
USB Adapter Compatibility
Section titled “USB Adapter Compatibility”Not all USB-to-serial adapters support all flow control features. The chipset determines what’s available:
| Chipset | RTS/CTS | DSR/DTR | XON/XOFF | Notes |
|---|---|---|---|---|
| FTDI FT232R | ✅ | ✅ | ✅ | Full support, reliable |
| FTDI FT2232H | ✅ | ✅ | ✅ | Dual port, same quality |
| CP2102 | ✅ | ⚠️ | ✅ | DTR may need jumper |
| CP2104 | ✅ | ✅ | ✅ | Full support |
| CH340/CH341 | ⚠️ | ❌ | ✅ | RTS timing may be poor |
| PL2303 | ⚠️ | ⚠️ | ✅ | Varies by clone quality |
Legend: ✅ = reliable, ⚠️ = works but may have issues, ❌ = not supported or unreliable
Debugging with modem lines
Section titled “Debugging with modem lines”Use get_modem_lines to verify flow control lines are behaving as expected:
// get_modem_lines(port="/dev/ttyUSB0"){ "success": true, "input_lines": { "cts": false, "dsr": false, "ri": false, "cd": false }, "output_lines": { "rts": true, "dtr": true }}If CTS is always false when you expect it to be asserted:
- Check the cable — CTS may not be wired through
- Check the remote device — it may not be asserting CTS
- Check the adapter — cheap adapters may not report CTS accurately
Deadlock scenarios
Section titled “Deadlock scenarios”Flow control can cause communication to stall if both ends wait on each other:
XON/XOFF deadlock:
- You send XOFF (buffer full)
- Remote stops sending
- Your code processes data and clears buffer
- You forget to send XON
- Remote waits forever
RTS/CTS deadlock:
- You deassert RTS (not ready to receive)
- Remote stops sending and waits for RTS
- Your code waits for data
- Nothing happens
Prevention:
- Always re-enable flow after processing (XON or reassert RTS)
- Use timeouts to detect stalls
- Check
get_modem_linesto diagnose which side is blocking
// If data stops flowing, check line states// get_modem_lines(port="/dev/ttyUSB0")
// If CTS is false, the remote is blocking our sends// If we've deasserted RTS, the remote is waiting for us