Fix DE-9 logo accuracy and reframe docs for MCP client perspective

Logo/favicon: Replace crude rectangle with proper DE-9 connector geometry
derived from EIA/TIA-574 specs (D-shaped shell, 5-over-4 pin layout,
hex standoff mounting posts).

Documentation: Rewrite all code examples from the MCP client perspective.
Remove Python syntax highlighting, use JSON boolean conventions
(true/false instead of True/False), and add framing notes explaining
tool-call notation. Tutorials now guide users through natural language
interaction with the assistant rather than direct function calls.
This commit is contained in:
Ryan Malloy 2026-02-02 22:42:48 -07:00
parent dc8caddb8f
commit 38a33e38b1
16 changed files with 171 additions and 109 deletions

View File

@ -1,12 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
<rect x="3" y="8" width="26" height="16" rx="3" stroke="#0d9488" stroke-width="2" fill="none"/> <!-- DE-9 connector favicon -->
<circle cx="9" cy="14" r="1.5" fill="#0d9488"/> <circle cx="3" cy="16" r="2" stroke="#0d9488" stroke-width="1" fill="none"/>
<circle cx="13" cy="14" r="1.5" fill="#0d9488"/> <circle cx="29" cy="16" r="2" stroke="#0d9488" stroke-width="1" fill="none"/>
<circle cx="17" cy="14" r="1.5" fill="#0d9488"/> <path d="M 7,10 L 25,10 A 3,6 0 0 1 23,22 L 9,22 A 3,6 0 0 1 7,10 Z"
<circle cx="21" cy="14" r="1.5" fill="#0d9488"/> stroke="#0d9488" stroke-width="1.5" fill="none"/>
<circle cx="25" cy="14" r="1.5" fill="#0d9488"/> <circle cx="10" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="11" cy="19" r="1.5" fill="#0d9488"/> <circle cx="13" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="15" cy="19" r="1.5" fill="#0d9488"/> <circle cx="16" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="19" cy="19" r="1.5" fill="#0d9488"/> <circle cx="19" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="23" cy="19" r="1.5" fill="#0d9488"/> <circle cx="22" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="11.5" cy="18" r="1.1" fill="#0d9488"/>
<circle cx="14.5" cy="18" r="1.1" fill="#0d9488"/>
<circle cx="17.5" cy="18" r="1.1" fill="#0d9488"/>
<circle cx="20.5" cy="18" r="1.1" fill="#0d9488"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 636 B

After

Width:  |  Height:  |  Size: 869 B

View File

@ -1,17 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
<!-- DB-9 connector outline --> <!-- DE-9 (D-subminiature 9-pin) connector, face-on view -->
<rect x="3" y="8" width="26" height="16" rx="3" stroke="#0d9488" stroke-width="2" fill="none"/> <!-- Proportions derived from EIA/TIA-574 specifications -->
<!-- Trapezoidal shape suggestion -->
<path d="M6 10 L26 10 L24 22 L8 22 Z" stroke="#0d9488" stroke-width="1.5" fill="none" opacity="0.4"/> <!-- Hex standoff mounting posts (4-40 UNC) -->
<!-- Pin row 1 (5 pins) --> <circle cx="3" cy="16" r="2" stroke="#0d9488" stroke-width="1" fill="none"/>
<circle cx="9" cy="14" r="1.5" fill="#0d9488"/> <circle cx="29" cy="16" r="2" stroke="#0d9488" stroke-width="1" fill="none"/>
<circle cx="13" cy="14" r="1.5" fill="#0d9488"/>
<circle cx="17" cy="14" r="1.5" fill="#0d9488"/> <!-- D-shaped connector shell -->
<circle cx="21" cy="14" r="1.5" fill="#0d9488"/> <!-- Top edge wider (18 units), bottom edge narrower (14 units) = 22% reduction -->
<circle cx="25" cy="14" r="1.5" fill="#0d9488"/> <!-- Rounded end caps connect the two edges, forming the characteristic D shape -->
<!-- Pin row 2 (4 pins) --> <path d="M 7,10 L 25,10 A 3,6 0 0 1 23,22 L 9,22 A 3,6 0 0 1 7,10 Z"
<circle cx="11" cy="19" r="1.5" fill="#0d9488"/> stroke="#0d9488" stroke-width="1.5" fill="none"/>
<circle cx="15" cy="19" r="1.5" fill="#0d9488"/>
<circle cx="19" cy="19" r="1.5" fill="#0d9488"/> <!-- Pin row 1: 5 pins at 3-unit pitch, centered at x=16 -->
<circle cx="23" cy="19" r="1.5" fill="#0d9488"/> <circle cx="10" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="13" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="16" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="19" cy="14" r="1.1" fill="#0d9488"/>
<circle cx="22" cy="14" r="1.1" fill="#0d9488"/>
<!-- Pin row 2: 4 pins offset by half pitch (1.5 units), 4-unit row spacing -->
<circle cx="11.5" cy="18" r="1.1" fill="#0d9488"/>
<circle cx="14.5" cy="18" r="1.1" fill="#0d9488"/>
<circle cx="17.5" cy="18" r="1.1" fill="#0d9488"/>
<circle cx="20.5" cy="18" r="1.1" fill="#0d9488"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 874 B

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -7,7 +7,7 @@ import { Aside } from '@astrojs/starlight/components';
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. 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. 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) ## Software flow control (XON/XOFF)

View File

@ -5,7 +5,7 @@ description: Understanding the differences between RS-232 and RS-485 serial comm
import { Aside } from '@astrojs/starlight/components'; import { Aside } from '@astrojs/starlight/components';
RS-232 and RS-485 are two serial communication standards that solve different problems. RS-232 connects one device to another over short distances. RS-485 connects many devices on a shared bus over long distances. Understanding when to use each one determines which mcserial tools you reach for. RS-232 and RS-485 are two serial communication standards that solve different problems. RS-232 connects one device to another over short distances. RS-485 connects many devices on a shared bus over long distances. Understanding when to use each one determines which mcserial tools your MCP assistant will reach for.
## Physical layer ## Physical layer
@ -71,7 +71,7 @@ RS-485 is the right choice when:
## How mcserial handles the difference ## How mcserial handles the difference
mcserial tracks which mode each port is in and restricts tools accordingly. This prevents accidentally sending RS-232 modem control commands on an RS-485 bus (which would disrupt communication by toggling the direction control line). mcserial tracks which mode each port is in and restricts tools accordingly. This prevents accidentally sending RS-232 modem control commands on an RS-485 bus (which would disrupt communication by toggling the direction control line). Your MCP assistant uses the `set_port_mode` tool to switch between modes on an open port.
### Default: RS-232 mode ### Default: RS-232 mode
@ -85,7 +85,7 @@ Every port opens in RS-232 mode. The following tools are available:
### After switching: RS-485 mode ### After switching: RS-485 mode
Call `set_port_mode(port, "rs485")` to switch. The RS-232 tools become unavailable and these tools become available: Ask the assistant to call `set_port_mode` with `mode="rs485"` to switch. The RS-232 tools become unavailable and these tools become available:
- `set_rs485_mode` -- configure hardware DE/RE direction control - `set_rs485_mode` -- configure hardware DE/RE direction control
- `rs485_transact` -- send data and receive response with automatic turnaround - `rs485_transact` -- send data and receive response with automatic turnaround

View File

@ -7,6 +7,8 @@ import { Steps, Aside } from '@astrojs/starlight/components';
Serial file transfers are useful when you need to move files to or from devices that lack network connectivity: embedded systems running a bootloader, legacy industrial equipment, air-gapped machines, or remote hardware accessed through a serial console. Serial file transfers are useful when you need to move files to or from devices that lack network connectivity: embedded systems running a bootloader, legacy industrial equipment, air-gapped machines, or remote hardware accessed through a serial console.
All of the operations described in this guide are performed through your MCP client. Ask the assistant to send or receive files, and it will call the appropriate mcserial transfer tools on your behalf. The tool call notation below shows exactly what the assistant invokes.
mcserial implements four protocol variants, all built in without external dependencies. mcserial implements four protocol variants, all built in without external dependencies.
## Protocol comparison ## Protocol comparison

View File

@ -7,6 +7,8 @@ import { Tabs, TabItem, Aside } from '@astrojs/starlight/components';
Serial devices are not always physically attached to the machine running mcserial. Serial device servers, terminal servers, and networked test equipment expose serial ports over TCP. mcserial supports these through URL schemes passed to `open_serial_port` -- the same read, write, configure, and file transfer tools work regardless of how the port is connected. Serial devices are not always physically attached to the machine running mcserial. Serial device servers, terminal servers, and networked test equipment expose serial ports over TCP. mcserial supports these through URL schemes passed to `open_serial_port` -- the same read, write, configure, and file transfer tools work regardless of how the port is connected.
All of the operations described in this guide are performed through your MCP client. Ask the assistant to open a network serial port by providing the URL scheme, and all subsequent tool calls work identically to a local port.
## Why network serial ## Why network serial
- **Serial device servers** (Digi, Moxa, Lantronix) bridge RS-232/RS-485 ports to your LAN - **Serial device servers** (Digi, Moxa, Lantronix) bridge RS-232/RS-485 ports to your LAN

View File

@ -7,6 +7,8 @@ import { Steps, Aside } from '@astrojs/starlight/components';
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. 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. Every port opens in RS-232 mode automatically. No additional configuration is needed unless you want to switch to RS-485.
## Modem control lines ## Modem control lines

View File

@ -7,6 +7,8 @@ import { Steps, Aside } from '@astrojs/starlight/components';
RS-485 uses a shared differential bus where multiple devices communicate over two wires. Unlike RS-232's point-to-point model, RS-485 is half-duplex -- only one device transmits at a time while all others listen. This makes it the standard for industrial protocols like Modbus RTU. RS-485 uses a shared differential bus where multiple devices communicate over two wires. Unlike RS-232's point-to-point model, RS-485 is half-duplex -- only one device transmits at a time while all others listen. This makes it the standard for industrial protocols like Modbus RTU.
All of the operations described in this guide are performed through your MCP client. Ask the assistant to open ports, switch modes, scan for devices, and transact on the bus. The tool call notation below shows exactly what the assistant calls on your behalf.
## Switching to RS-485 mode ## Switching to RS-485 mode
Ports open in RS-232 mode by default. Switch to RS-485 mode before using any RS-485 tools. Ports open in RS-232 mode by default. Switch to RS-485 mode before using any RS-485 tools.

View File

@ -37,12 +37,14 @@ import { Card, CardGrid, Aside } from '@astrojs/starlight/components';
## Quick start ## Quick start
Install mcserial and register it with your MCP client:
```bash ```bash
# Add to Claude Code # Add to Claude Code (one-time setup)
claude mcp add mcserial -- uvx mcserial claude mcp add mcserial -- uvx mcserial
``` ```
Then use the tools in a natural sequence -- discover, open, read/write, close: Then ask your assistant to work with serial ports. It calls the tools behind the scenes:
``` ```
list_serial_ports() # find available ports list_serial_ports() # find available ports
@ -52,7 +54,7 @@ read_serial(port="loop://") # read response
close_serial_port(port="loop://") # release the port close_serial_port(port="loop://") # release the port
``` ```
See the [Getting Started tutorial](/tutorials/getting-started/) for the full walkthrough with example responses. You interact in natural language -- "list my serial ports," "open the loopback port at 9600 baud," "send hello." See the [Getting Started tutorial](/tutorials/getting-started/) for the full walkthrough with example responses.
## Supported URL schemes ## Supported URL schemes

View File

@ -9,6 +9,10 @@ import { Aside } from '@astrojs/starlight/components';
These 18 tools work in both RS-232 and RS-485 modes. They cover port discovery, connection management, reading and writing data, configuration, flow control, and diagnostics. These 18 tools work in both RS-232 and RS-485 modes. They cover port discovery, connection management, reading and writing data, configuration, flow control, and diagnostics.
<Aside type="note">
Examples use tool-call notation: `tool_name(param=value)`. These are MCP tool calls made by the assistant, not code you write directly. Boolean values use JSON convention (`true`/`false`).
</Aside>
--- ---
## Port Discovery ## Port Discovery
@ -24,12 +28,12 @@ List available serial ports on the system. Call this first to discover what port
**Returns:** List of port objects with `device`, `description`, `hwid`, `manufacturer`, `product`, `serial_number`, and `is_open` fields. Sorted with USB ports (ttyUSB, ttyACM) first. **Returns:** List of port objects with `device`, `description`, `hwid`, `manufacturer`, `product`, `serial_number`, and `is_open` fields. Sorted with USB ports (ttyUSB, ttyACM) first.
```python ```
# List all USB serial devices # List all USB serial devices
list_serial_ports() list_serial_ports()
# Include legacy ttyS ports # Include legacy ttyS ports
list_serial_ports(usb_only=False) list_serial_ports(usb_only=false)
# Find FTDI adapters # Find FTDI adapters
list_serial_ports(grep="FTDI") list_serial_ports(grep="FTDI")
@ -69,7 +73,7 @@ Open a serial port connection with optional auto-baud detection. If `baudrate` i
When `baudrate` is `None` and the port is a local device (not a URL scheme), auto-baud detection runs automatically. For best results with devices that only respond to input, pass an `autobaud_probe` string like `"UUUUU"` or `"AT\r\n"`. When `baudrate` is `None` and the port is a local device (not a URL scheme), auto-baud detection runs automatically. For best results with devices that only respond to input, pass an `autobaud_probe` string like `"UUUUU"` or `"AT\r\n"`.
</Aside> </Aside>
```python ```
# Auto-detect baud rate # Auto-detect baud rate
open_serial_port(port="/dev/ttyUSB0") open_serial_port(port="/dev/ttyUSB0")
@ -77,10 +81,10 @@ open_serial_port(port="/dev/ttyUSB0")
open_serial_port(port="/dev/ttyUSB0", baudrate=115200) open_serial_port(port="/dev/ttyUSB0", baudrate=115200)
# RS-232 with hardware flow control # RS-232 with hardware flow control
open_serial_port(port="/dev/ttyUSB0", baudrate=9600, rtscts=True) open_serial_port(port="/dev/ttyUSB0", baudrate=9600, rtscts=true)
# Exclusive access prevents other processes from using the port # Exclusive access prevents other processes from using the port
open_serial_port(port="/dev/ttyUSB0", baudrate=9600, exclusive=True) open_serial_port(port="/dev/ttyUSB0", baudrate=9600, exclusive=true)
# Auto-detect with sync probe # Auto-detect with sync probe
open_serial_port(port="/dev/ttyUSB0", autobaud_probe="UUUUU") open_serial_port(port="/dev/ttyUSB0", autobaud_probe="UUUUU")
@ -106,7 +110,7 @@ Close an open serial port connection and release it for other processes.
**Returns:** Status dict with `success`, `port`, and `message` fields. **Returns:** Status dict with `success`, `port`, and `message` fields.
```python ```
close_serial_port(port="/dev/ttyUSB0") close_serial_port(port="/dev/ttyUSB0")
``` ```
@ -121,7 +125,7 @@ Switch a serial port between RS-232 and RS-485 modes. Mode determines which mode
**Returns:** Status dict with `success`, `previous_mode`, `current_mode`, and `mode_tools` (list of tools available in the new mode). **Returns:** Status dict with `success`, `previous_mode`, `current_mode`, and `mode_tools` (list of tools available in the new mode).
```python ```
# Switch to RS-485 mode for Modbus communication # Switch to RS-485 mode for Modbus communication
set_port_mode(port="/dev/ttyUSB0", mode="rs485") set_port_mode(port="/dev/ttyUSB0", mode="rs485")
@ -139,7 +143,7 @@ Get status of all open serial connections. Takes no parameters.
**Returns:** Dict with `connections` (map of port to status details) and `count`. Each connection includes `is_open`, `mode`, `baudrate`, `bytesize`, `parity`, `stopbits`, `timeout`, `write_timeout`, `inter_byte_timeout`, flow control flags, buffer counts (`in_waiting`, `out_waiting`), modem line states (`cts`, `dsr`, `ri`, `cd`, `rts`, `dtr`), and `resource_uri`. **Returns:** Dict with `connections` (map of port to status details) and `count`. Each connection includes `is_open`, `mode`, `baudrate`, `bytesize`, `parity`, `stopbits`, `timeout`, `write_timeout`, `inter_byte_timeout`, flow control flags, buffer counts (`in_waiting`, `out_waiting`), modem line states (`cts`, `dsr`, `ri`, `cd`, `rts`, `dtr`), and `resource_uri`.
```python ```
get_connection_status() get_connection_status()
``` ```
@ -159,7 +163,7 @@ Write string data to an open serial port. Data is encoded using the specified en
**Returns:** Dict with `success`, `bytes_written`, and `port`. **Returns:** Dict with `success`, `bytes_written`, and `port`.
```python ```
# Send an AT command # Send an AT command
write_serial(port="/dev/ttyUSB0", data="AT\r\n") write_serial(port="/dev/ttyUSB0", data="AT\r\n")
@ -178,7 +182,7 @@ Write raw bytes to an open serial port. Use this when you need to send binary da
**Returns:** Dict with `success`, `bytes_written`, and `port`. **Returns:** Dict with `success`, `bytes_written`, and `port`.
```python ```
# Send AT\r\n as raw bytes # Send AT\r\n as raw bytes
write_serial_bytes(port="/dev/ttyUSB0", data=[65, 84, 13, 10]) write_serial_bytes(port="/dev/ttyUSB0", data=[65, 84, 13, 10])
@ -207,7 +211,7 @@ Read data from an open serial port. Returns both decoded text and raw hex repres
**Returns:** Dict with `success`, `data` (decoded string), `bytes_read`, `raw_hex`, and `port`. Decoding errors are replaced rather than raising exceptions. **Returns:** Dict with `success`, `data` (decoded string), `bytes_read`, `raw_hex`, and `port`. Decoding errors are replaced rather than raising exceptions.
```python ```
# Read all available data # Read all available data
read_serial(port="/dev/ttyUSB0") read_serial(port="/dev/ttyUSB0")
@ -229,7 +233,7 @@ Read a single line (until newline character) from an open serial port.
**Returns:** Dict with `success`, `line` (decoded string with trailing CR/LF stripped), `bytes_read`, and `port`. **Returns:** Dict with `success`, `line` (decoded string with trailing CR/LF stripped), `bytes_read`, and `port`.
```python ```
read_serial_line(port="/dev/ttyUSB0") read_serial_line(port="/dev/ttyUSB0")
``` ```
@ -245,7 +249,7 @@ Read multiple lines from an open serial port. Reads up to `max_lines`, stopping
**Returns:** Dict with `success`, `lines` (list of decoded strings), `count`, `bytes_read`, and `port`. **Returns:** Dict with `success`, `lines` (list of decoded strings), `count`, `bytes_read`, and `port`.
```python ```
# Read up to 10 lines (default) # Read up to 10 lines (default)
read_serial_lines(port="/dev/ttyUSB0") read_serial_lines(port="/dev/ttyUSB0")
@ -266,7 +270,7 @@ Read data until a specific terminator sequence is received. More flexible than `
**Returns:** Dict with `success`, `data` (decoded string), `bytes_read`, `raw_hex`, `port`, and `terminator_found` (bool indicating whether the terminator was actually found or the read timed out). **Returns:** Dict with `success`, `data` (decoded string), `bytes_read`, `raw_hex`, `port`, and `terminator_found` (bool indicating whether the terminator was actually found or the read timed out).
```python ```
# Read until "OK\r\n" # Read until "OK\r\n"
read_until(port="/dev/ttyUSB0", terminator="OK\r\n") read_until(port="/dev/ttyUSB0", terminator="OK\r\n")
@ -300,7 +304,7 @@ Modify settings on an already-open serial port. Only the parameters you provide
**Returns:** Dict with `success`, `port`, and all current settings (`baudrate`, `timeout`, `write_timeout`, `inter_byte_timeout`, `xonxoff`, `rtscts`, `dsrdtr`, `rts`, `dtr`). **Returns:** Dict with `success`, `port`, and all current settings (`baudrate`, `timeout`, `write_timeout`, `inter_byte_timeout`, `xonxoff`, `rtscts`, `dsrdtr`, `rts`, `dtr`).
```python ```
# Change baud rate on the fly # Change baud rate on the fly
configure_serial(port="/dev/ttyUSB0", baudrate=115200) configure_serial(port="/dev/ttyUSB0", baudrate=115200)
@ -308,10 +312,10 @@ configure_serial(port="/dev/ttyUSB0", baudrate=115200)
configure_serial(port="/dev/ttyUSB0", timeout=5.0) configure_serial(port="/dev/ttyUSB0", timeout=5.0)
# Enable hardware flow control # Enable hardware flow control
configure_serial(port="/dev/ttyUSB0", rtscts=True) configure_serial(port="/dev/ttyUSB0", rtscts=true)
# Set DTR low (useful for reset sequences) # Set DTR low (useful for reset sequences)
configure_serial(port="/dev/ttyUSB0", dtr=False) configure_serial(port="/dev/ttyUSB0", dtr=false)
``` ```
### flush_serial ### flush_serial
@ -326,12 +330,12 @@ Clear serial port input and/or output buffers. Discards any pending data.
**Returns:** Dict with `success`, `port`, `flushed_input`, and `flushed_output`. **Returns:** Dict with `success`, `port`, `flushed_input`, and `flushed_output`.
```python ```
# Flush both buffers (default) # Flush both buffers (default)
flush_serial(port="/dev/ttyUSB0") flush_serial(port="/dev/ttyUSB0")
# Flush only the input buffer # Flush only the input buffer
flush_serial(port="/dev/ttyUSB0", input_buffer=True, output_buffer=False) flush_serial(port="/dev/ttyUSB0", input_buffer=true, output_buffer=false)
``` ```
--- ---
@ -354,12 +358,12 @@ Manually gate input/output flow control signals on a serial port. Flow control m
This function is not portable across all platforms. Behavior depends on the OS and driver support. This function is not portable across all platforms. Behavior depends on the OS and driver support.
</Aside> </Aside>
```python ```
# Pause incoming data (send XOFF) # Pause incoming data (send XOFF)
set_flow_control(port="/dev/ttyUSB0", input_flow=False) set_flow_control(port="/dev/ttyUSB0", input_flow=false)
# Resume incoming data (send XON) # Resume incoming data (send XON)
set_flow_control(port="/dev/ttyUSB0", input_flow=True) set_flow_control(port="/dev/ttyUSB0", input_flow=true)
``` ```
### cancel_read ### cancel_read
@ -376,7 +380,7 @@ Cancel any pending read operation on a serial port. Interrupts a blocking read b
Only effective on platforms that support it (POSIX with select-based reads). Only effective on platforms that support it (POSIX with select-based reads).
</Aside> </Aside>
```python ```
cancel_read(port="/dev/ttyUSB0") cancel_read(port="/dev/ttyUSB0")
``` ```
@ -394,7 +398,7 @@ Cancel any pending write operation on a serial port. Interrupts a blocking write
Only effective on platforms that support it (POSIX with select-based writes). Only effective on platforms that support it (POSIX with select-based writes).
</Aside> </Aside>
```python ```
cancel_write(port="/dev/ttyUSB0") cancel_write(port="/dev/ttyUSB0")
``` ```
@ -417,9 +421,9 @@ Enable or disable low-latency mode on a serial port. Reduces latency by changing
This is a Linux-specific feature. It may not be available on all hardware or kernel versions. Returns an error on unsupported systems rather than silently failing. This is a Linux-specific feature. It may not be available on all hardware or kernel versions. Returns an error on unsupported systems rather than silently failing.
</Aside> </Aside>
```python ```
# Enable low latency for time-critical communication # Enable low latency for time-critical communication
set_low_latency_mode(port="/dev/ttyUSB0", enabled=True) set_low_latency_mode(port="/dev/ttyUSB0", enabled=true)
``` ```
### detect_baud_rate ### detect_baud_rate
@ -440,7 +444,7 @@ Auto-detect baud rate using multiple heuristics: 0x55 sync pattern analysis, byt
Detection works best when the remote device is actively sending data. For devices that only respond to input, use the `probe` parameter to send a string that triggers a response at each candidate baud rate. Detection works best when the remote device is actively sending data. For devices that only respond to input, use the `probe` parameter to send a string that triggers a response at each candidate baud rate.
</Aside> </Aside>
```python ```
# Detect baud rate on an active device # Detect baud rate on an active device
detect_baud_rate(port="/dev/ttyUSB0") detect_baud_rate(port="/dev/ttyUSB0")

View File

@ -9,6 +9,10 @@ import { Aside } from '@astrojs/starlight/components';
Transfer files over serial connections using classic X/Y/ZMODEM protocols. These tools work in both RS-232 and RS-485 modes. Transfer files over serial connections using classic X/Y/ZMODEM protocols. These tools work in both RS-232 and RS-485 modes.
<Aside type="note">
Examples use tool-call notation: `tool_name(param=value)`. These are MCP tool calls made by the assistant, not code you write directly. Boolean values use JSON convention (`true`/`false`).
</Aside>
## Protocol Comparison ## Protocol Comparison
| Protocol | Block Size | Batch | Resume | Error Correction | Recommended | | Protocol | Block Size | Batch | Resume | Error Correction | Recommended |
@ -36,7 +40,7 @@ Send a single file over serial using a selected protocol. The receiver must be w
**Returns:** Transfer statistics dict with protocol-specific details including bytes sent and any errors. The dict also includes `protocol` and `file` fields. **Returns:** Transfer statistics dict with protocol-specific details including bytes sent and any errors. The dict also includes `protocol` and `file` fields.
```python ```
# Send a firmware file using ZMODEM (default) # Send a firmware file using ZMODEM (default)
file_transfer_send(port="/dev/ttyUSB0", file_path="/home/user/firmware.bin") file_transfer_send(port="/dev/ttyUSB0", file_path="/home/user/firmware.bin")
@ -85,7 +89,7 @@ Receive a file over serial using a selected protocol. The behavior of `save_path
XMODEM does not transmit the filename -- the sender and receiver must agree on it beforehand. Pass the full destination file path as `save_path`. YMODEM and ZMODEM carry the filename in the protocol, so `save_path` should be a directory. XMODEM does not transmit the filename -- the sender and receiver must agree on it beforehand. Pass the full destination file path as `save_path`. YMODEM and ZMODEM carry the filename in the protocol, so `save_path` should be a directory.
</Aside> </Aside>
```python ```
# Receive via ZMODEM into a directory # Receive via ZMODEM into a directory
file_transfer_receive( file_transfer_receive(
port="/dev/ttyUSB0", port="/dev/ttyUSB0",
@ -104,7 +108,7 @@ file_transfer_receive(
port="/dev/ttyUSB0", port="/dev/ttyUSB0",
save_path="/home/user/downloads/", save_path="/home/user/downloads/",
protocol="ymodem", protocol="ymodem",
overwrite=True, overwrite=true,
) )
``` ```
@ -130,7 +134,7 @@ Send multiple files in a single batch transfer. Only YMODEM and ZMODEM support b
All files are validated before the transfer begins. If any file in the list does not exist, the entire batch is rejected with an error identifying the missing file. All files are validated before the transfer begins. If any file in the list does not exist, the entire batch is rejected with an error identifying the missing file.
</Aside> </Aside>
```python ```
# Batch send with ZMODEM (default) # Batch send with ZMODEM (default)
file_transfer_send_batch( file_transfer_send_batch(
port="/dev/ttyUSB0", port="/dev/ttyUSB0",
@ -155,7 +159,7 @@ file_transfer_send_batch(
A complete file transfer session looks like this: A complete file transfer session looks like this:
```python ```
# 1. Open the port at a suitable baud rate # 1. Open the port at a suitable baud rate
open_serial_port(port="/dev/ttyUSB0", baudrate=115200) open_serial_port(port="/dev/ttyUSB0", baudrate=115200)

View File

@ -9,6 +9,10 @@ import { Aside } from '@astrojs/starlight/components';
RS-232 is the default mode for all newly opened ports. These five tools provide control over modem signal lines and break conditions -- the hardware handshaking and signaling layer of point-to-point serial communication. RS-232 is the default mode for all newly opened ports. These five tools provide control over modem signal lines and break conditions -- the hardware handshaking and signaling layer of point-to-point serial communication.
<Aside type="note">
Examples use tool-call notation: `tool_name(param=value)`. These are MCP tool calls made by the assistant, not code you write directly. Boolean values use JSON convention (`true`/`false`).
</Aside>
<Aside type="note" title="RS-232 mode required"> <Aside type="note" title="RS-232 mode required">
All tools on this page require the port to be in RS-232 mode. Since RS-232 is the default mode when a port is opened, no extra setup is needed unless you previously switched to RS-485 mode. To switch back, call `set_port_mode(port, "rs232")`. All tools on this page require the port to be in RS-232 mode. Since RS-232 is the default mode when a port is opened, no extra setup is needed unless you previously switched to RS-485 mode. To switch back, call `set_port_mode(port, "rs232")`.
</Aside> </Aside>
@ -41,7 +45,7 @@ Read all RS-232 modem control and status line states, including the current brea
**Returns:** Dict with `success`, `port`, `input_lines` (object with `cts`, `dsr`, `ri`, `cd`), `output_lines` (object with `rts`, `dtr`), and `break_condition` (bool). **Returns:** Dict with `success`, `port`, `input_lines` (object with `cts`, `dsr`, `ri`, `cd`), `output_lines` (object with `rts`, `dtr`), and `break_condition` (bool).
```python ```
get_modem_lines(port="/dev/ttyUSB0") get_modem_lines(port="/dev/ttyUSB0")
# Example response: # Example response:
@ -74,15 +78,15 @@ These lines are commonly used for:
- Power control on some devices - Power control on some devices
- Custom signaling protocols - Custom signaling protocols
```python ```
# Assert DTR to signal "terminal ready" # Assert DTR to signal "terminal ready"
set_modem_lines(port="/dev/ttyUSB0", dtr=True) set_modem_lines(port="/dev/ttyUSB0", dtr=true)
# Drop RTS to signal "stop sending" # Drop RTS to signal "stop sending"
set_modem_lines(port="/dev/ttyUSB0", rts=False) set_modem_lines(port="/dev/ttyUSB0", rts=false)
# Set both lines at once # Set both lines at once
set_modem_lines(port="/dev/ttyUSB0", rts=True, dtr=True) set_modem_lines(port="/dev/ttyUSB0", rts=true, dtr=true)
``` ```
--- ---
@ -107,12 +111,12 @@ Typical reset sequences:
- **ESP32/ESP8266**: DTR + RTS sequence enters bootloader - **ESP32/ESP8266**: DTR + RTS sequence enters bootloader
- **Custom hardware**: Various reset/trigger signals - **Custom hardware**: Various reset/trigger signals
```python ```
# Arduino-style reset (DTR pulse, active low) # Arduino-style reset (DTR pulse, active low)
pulse_line(port="/dev/ttyUSB0", line="dtr", duration_ms=100) pulse_line(port="/dev/ttyUSB0", line="dtr", duration_ms=100)
# Active-high pulse on RTS # Active-high pulse on RTS
pulse_line(port="/dev/ttyUSB0", line="rts", duration_ms=200, active_low=False) pulse_line(port="/dev/ttyUSB0", line="rts", duration_ms=200, active_low=false)
# Short trigger pulse # Short trigger pulse
pulse_line(port="/dev/ttyUSB0", line="dtr", duration_ms=10) pulse_line(port="/dev/ttyUSB0", line="dtr", duration_ms=10)
@ -131,7 +135,7 @@ Send a timed serial break signal -- a sustained low state on the TX line longer
**Returns:** Dict with `success`, `port`, and `duration_ms`. **Returns:** Dict with `success`, `port`, and `duration_ms`.
```python ```
# Standard break signal # Standard break signal
send_break(port="/dev/ttyUSB0") send_break(port="/dev/ttyUSB0")
@ -159,12 +163,12 @@ Set or clear the break condition on a serial port. Unlike `send_break()` which s
The break condition holds the TX line low continuously. The remote device will not receive valid data while break is asserted. Always clear the condition with `enabled=False` when done. The break condition holds the TX line low continuously. The remote device will not receive valid data while break is asserted. Always clear the condition with `enabled=False` when done.
</Aside> </Aside>
```python ```
# Assert break condition # Assert break condition
set_break_condition(port="/dev/ttyUSB0", enabled=True) set_break_condition(port="/dev/ttyUSB0", enabled=true)
# ... wait for device to respond ... # ... wait for device to respond ...
# Release break # Release break
set_break_condition(port="/dev/ttyUSB0", enabled=False) set_break_condition(port="/dev/ttyUSB0", enabled=false)
``` ```

View File

@ -9,10 +9,14 @@ import { Aside } from '@astrojs/starlight/components';
RS-485 enables half-duplex multi-drop bus communication where multiple devices share a single pair of wires. These tools handle direction control, request/response transactions, and bus scanning. RS-485 enables half-duplex multi-drop bus communication where multiple devices share a single pair of wires. These tools handle direction control, request/response transactions, and bus scanning.
<Aside type="note">
Examples use tool-call notation: `tool_name(param=value)`. These are MCP tool calls made by the assistant, not code you write directly. Boolean values use JSON convention (`true`/`false`).
</Aside>
<Aside type="caution" title="Switch to RS-485 mode first"> <Aside type="caution" title="Switch to RS-485 mode first">
Ports open in RS-232 mode by default. Before using any tool on this page, switch the port to RS-485 mode: Ports open in RS-232 mode by default. Before using any tool on this page, switch the port to RS-485 mode:
```python ```
open_serial_port(port="/dev/ttyUSB0", baudrate=9600) open_serial_port(port="/dev/ttyUSB0", baudrate=9600)
set_port_mode(port="/dev/ttyUSB0", mode="rs485") set_port_mode(port="/dev/ttyUSB0", mode="rs485")
``` ```
@ -40,7 +44,7 @@ Configure the hardware RS-485 settings for half-duplex communication. This sets
The `rts_level_for_tx` and `rts_level_for_rx` parameters control the polarity of the DE/RE enable pin. Most RS-485 transceivers use active-high for TX enable and active-low for RX enable, which is the default configuration. The `rts_level_for_tx` and `rts_level_for_rx` parameters control the polarity of the DE/RE enable pin. Most RS-485 transceivers use active-high for TX enable and active-low for RX enable, which is the default configuration.
</Aside> </Aside>
```python ```
# Enable hardware RS-485 with defaults # Enable hardware RS-485 with defaults
set_rs485_mode(port="/dev/ttyUSB0") set_rs485_mode(port="/dev/ttyUSB0")
@ -54,12 +58,12 @@ set_rs485_mode(
# Inverted RTS polarity # Inverted RTS polarity
set_rs485_mode( set_rs485_mode(
port="/dev/ttyUSB0", port="/dev/ttyUSB0",
rts_level_for_tx=False, rts_level_for_tx=false,
rts_level_for_rx=True, rts_level_for_rx=true,
) )
# Disable hardware RS-485 (revert to software control) # Disable hardware RS-485 (revert to software control)
set_rs485_mode(port="/dev/ttyUSB0", enabled=False) set_rs485_mode(port="/dev/ttyUSB0", enabled=false)
``` ```
--- ---
@ -85,7 +89,7 @@ Known hardware support:
| `pl2303` | PL2303 | No -- use software RTS control | | `pl2303` | PL2303 | No -- use software RTS control |
| native | ttyS, ttyAMA | Yes -- check transceiver wiring | | native | ttyS, ttyAMA | Yes -- check transceiver wiring |
```python ```
check_rs485_support(port="/dev/ttyUSB0") check_rs485_support(port="/dev/ttyUSB0")
# Example response: # Example response:
@ -132,7 +136,7 @@ The transaction flow:
5. De-assert RTS for RX (if no hardware RS-485) 5. De-assert RTS for RX (if no hardware RS-485)
6. Read response using terminator, length, or timeout 6. Read response using terminator, length, or timeout
```python ```
# Simple query with timeout-based response # Simple query with timeout-based response
rs485_transact(port="/dev/ttyUSB0", data="?ID\r\n") rs485_transact(port="/dev/ttyUSB0", data="?ID\r\n")
@ -185,7 +189,7 @@ Scan the RS-485 bus for responding devices by sending a probe message to each ad
Scanning 247 addresses at 0.1s per address takes approximately 25 seconds. Narrow the address range when possible, or reduce `response_timeout` for faster scans on responsive buses. Scanning 247 addresses at 0.1s per address takes approximately 25 seconds. Narrow the address range when possible, or reduce `response_timeout` for faster scans on responsive buses.
</Aside> </Aside>
```python ```
# Scan the full Modbus range # Scan the full Modbus range
rs485_scan_addresses(port="/dev/ttyUSB0") rs485_scan_addresses(port="/dev/ttyUSB0")

View File

@ -39,7 +39,7 @@ COM12 -- Higher-numbered ports
/dev/tty.usbmodem14201 -- USB CDC ACM device /dev/tty.usbmodem14201 -- USB CDC ACM device
``` ```
```python ```
open_serial_port(port="/dev/ttyUSB0", baudrate=115200) open_serial_port(port="/dev/ttyUSB0", baudrate=115200)
``` ```
@ -55,7 +55,7 @@ Data sent to the socket appears on the remote serial port and vice versa. No pro
**When to use:** Serial-to-Ethernet bridges (Moxa, Digi, Lantronix), ESP32/ESP8266 with TCP server firmware, or any device that bridges serial to a TCP socket. **When to use:** Serial-to-Ethernet bridges (Moxa, Digi, Lantronix), ESP32/ESP8266 with TCP server firmware, or any device that bridges serial to a TCP socket.
```python ```
open_serial_port(port="socket://192.168.1.100:4001", baudrate=115200) open_serial_port(port="socket://192.168.1.100:4001", baudrate=115200)
``` ```
@ -75,7 +75,7 @@ Unlike `socket://`, this scheme negotiates serial parameters with the remote dev
**When to use:** Remote serial port servers that implement RFC 2217, such as ser2net, or commercial terminal servers with Telnet COM Port support. **When to use:** Remote serial port servers that implement RFC 2217, such as ser2net, or commercial terminal servers with Telnet COM Port support.
```python ```
# Remote serial with full parameter control # Remote serial with full parameter control
open_serial_port(port="rfc2217://192.168.1.100:2217", baudrate=115200) open_serial_port(port="rfc2217://192.168.1.100:2217", baudrate=115200)
``` ```
@ -94,7 +94,7 @@ Loopback virtual port. Everything written is echoed back as readable data. No ha
**When to use:** Testing, development, CI/CD pipelines, or verifying tool behavior without physical serial hardware. **When to use:** Testing, development, CI/CD pipelines, or verifying tool behavior without physical serial hardware.
```python ```
open_serial_port(port="loop://", baudrate=9600) open_serial_port(port="loop://", baudrate=9600)
write_serial(port="loop://", data="hello") write_serial(port="loop://", data="hello")
read_serial(port="loop://") # Returns "hello" read_serial(port="loop://") # Returns "hello"
@ -113,7 +113,7 @@ All bytes read and written are printed to stderr in a human-readable format. The
**When to use:** Debugging communication issues, reverse-engineering protocols, or logging traffic for analysis. **When to use:** Debugging communication issues, reverse-engineering protocols, or logging traffic for analysis.
```python ```
# Wraps /dev/ttyUSB0 with traffic logging # Wraps /dev/ttyUSB0 with traffic logging
open_serial_port(port="spy:///dev/ttyUSB0", baudrate=9600) open_serial_port(port="spy:///dev/ttyUSB0", baudrate=9600)
``` ```
@ -142,7 +142,7 @@ uv pip install mcserial[cp2110]
Without this extra, opening a `cp2110://` URL returns an error explaining the missing dependency. Without this extra, opening a `cp2110://` URL returns an error explaining the missing dependency.
</Aside> </Aside>
```python ```
open_serial_port(port="cp2110://", baudrate=9600) open_serial_port(port="cp2110://", baudrate=9600)
``` ```
@ -156,7 +156,7 @@ Hardware grep -- opens the first serial port matching a hardware description pat
**When to use:** When you know the type of device but not the exact port assignment. Useful for scripts that need to find a specific adapter regardless of which USB port it is plugged into. **When to use:** When you know the type of device but not the exact port assignment. Useful for scripts that need to find a specific adapter regardless of which USB port it is plugged into.
```python ```
# Open the first FTDI adapter found # Open the first FTDI adapter found
open_serial_port(port="hwgrep://FTDI", baudrate=115200) open_serial_port(port="hwgrep://FTDI", baudrate=115200)

View File

@ -5,7 +5,11 @@ description: Install mcserial and make your first serial connection.
import { Steps, Tabs, TabItem, Aside, Card, CardGrid } from '@astrojs/starlight/components'; import { Steps, Tabs, TabItem, Aside, Card, CardGrid } from '@astrojs/starlight/components';
mcserial is a FastMCP server that gives MCP clients full serial port access -- discovery, configuration, read/write, modem control, and file transfers. This tutorial walks you through installation and your first connection. mcserial is a FastMCP server that gives MCP clients full serial port access -- discovery, configuration, read/write, modem control, and file transfers. You use it through your MCP client (Claude Code, Claude Desktop, or any other MCP-compatible client) by talking to your assistant in natural language. This tutorial walks you through installation, client configuration, and your first serial connection.
<Aside type="note" title="How to read tool calls in this guide">
The `tool_name(param=value)` blocks below show what the assistant executes behind the scenes. You don't type these yourself -- instead, ask the assistant in plain English, like "list my serial ports" or "open /dev/ttyUSB0 at 115200 baud." The assistant translates your request into the appropriate tool call.
</Aside>
## Prerequisites ## Prerequisites
@ -82,18 +86,18 @@ mcserial runs over stdio, so you register it with your MCP client and the client
## Your first connection ## Your first connection
The natural workflow is: **discover** available ports, **open** one, **read/write** data, then **close** when done. The natural workflow is: **discover** available ports, **open** one, **read/write** data, then **close** when done. You ask the assistant to do each step, and it calls the appropriate mcserial tools.
This walkthrough uses `loop://` so you can follow along without any hardware. Everything written to a loopback port is immediately available to read back. This walkthrough uses `loop://` so you can follow along without any hardware. Everything written to a loopback port is immediately available to read back.
<Steps> <Steps>
1. **Discover available ports** 1. **Ask the assistant to list available ports**
Call `list_serial_ports` to see what's connected: The assistant calls `list_serial_ports` to see what's connected:
``` ```
list_serial_ports(usb_only=False) list_serial_ports(usb_only=false)
``` ```
Response: Response:
@ -112,7 +116,7 @@ This walkthrough uses `loop://` so you can follow along without any hardware. Ev
] ]
``` ```
Set `usb_only=False` to include built-in serial ports. Use `grep` to filter by hardware: `list_serial_ports(grep="FTDI")`. Set `usb_only=false` to include built-in serial ports. Use `grep` to filter by hardware: `list_serial_ports(grep="FTDI")`.
<Aside type="note"> <Aside type="note">
If you have no hardware, skip this step and go straight to opening `loop://` in the next step. If you have no hardware, skip this step and go straight to opening `loop://` in the next step.
@ -120,7 +124,7 @@ This walkthrough uses `loop://` so you can follow along without any hardware. Ev
2. **Open a connection** 2. **Open a connection**
Open the loopback port (or a real device path from step 1): Ask the assistant to open the loopback port (or a real device path from step 1). The assistant calls:
``` ```
open_serial_port(port="loop://", baudrate=9600) open_serial_port(port="loop://", baudrate=9600)
@ -150,7 +154,7 @@ This walkthrough uses `loop://` so you can follow along without any hardware. Ev
3. **Write data** 3. **Write data**
Send a string to the port: Tell the assistant to send a message. It calls:
``` ```
write_serial(port="loop://", data="Hello, serial world!\n") write_serial(port="loop://", data="Hello, serial world!\n")
@ -168,7 +172,7 @@ This walkthrough uses `loop://` so you can follow along without any hardware. Ev
4. **Read data back** 4. **Read data back**
Read whatever is waiting in the receive buffer: Ask the assistant to read from the port. It reads whatever is waiting in the receive buffer:
``` ```
read_serial(port="loop://") read_serial(port="loop://")
@ -190,7 +194,7 @@ This walkthrough uses `loop://` so you can follow along without any hardware. Ev
5. **Close the connection** 5. **Close the connection**
Always close ports when you're done to release the resource: When you're done, ask the assistant to close the port to release the resource:
``` ```
close_serial_port(port="loop://") close_serial_port(port="loop://")

View File

@ -5,7 +5,11 @@ description: Test serial communication without any hardware using loop:// virtua
import { Steps, Tabs, TabItem, Aside } from '@astrojs/starlight/components'; import { Steps, Tabs, TabItem, Aside } from '@astrojs/starlight/components';
pyserial provides a built-in `loop://` URL scheme that creates a virtual serial port. Everything written to it is immediately available to read back -- no cables, no adapters, no hardware at all. This makes it ideal for testing tool workflows, validating encodings, and running automated checks in CI/CD. pyserial provides a built-in `loop://` URL scheme that creates a virtual serial port. Everything written to it is immediately available to read back -- no cables, no adapters, no hardware at all. This makes it a great way to verify that mcserial is working in your MCP client, practice serial workflows, validate encodings, and run automated checks in CI/CD.
<Aside type="note" title="MCP tool calls">
The tool calls shown below are what the assistant executes when you ask it to perform serial operations. You interact in natural language -- for example, "open a loopback port" or "write AT+VERSION to the serial port."
</Aside>
## Why use loopback ## Why use loopback
@ -16,11 +20,11 @@ pyserial provides a built-in `loop://` URL scheme that creates a virtual serial
## Basic round-trip ## Basic round-trip
The simplest test: write a string and read it back. The simplest test: ask the assistant to write a string and read it back.
<Steps> <Steps>
1. **Open the loopback port** 1. **Ask the assistant to open the loopback port**
``` ```
open_serial_port(port="loop://", baudrate=9600) open_serial_port(port="loop://", baudrate=9600)
@ -42,7 +46,9 @@ The simplest test: write a string and read it back.
The `baudrate` parameter is accepted but has no effect on loopback -- data moves at memory speed regardless of the value. Setting it still validates that the parameter is handled correctly throughout the tool chain. The `baudrate` parameter is accepted but has no effect on loopback -- data moves at memory speed regardless of the value. Setting it still validates that the parameter is handled correctly throughout the tool chain.
2. **Write a message** 2. **Send a message**
The assistant writes your data to the port:
``` ```
write_serial(port="loop://", data="AT+VERSION\r\n") write_serial(port="loop://", data="AT+VERSION\r\n")
@ -58,6 +64,8 @@ The simplest test: write a string and read it back.
3. **Read it back** 3. **Read it back**
Ask the assistant to read from the port:
``` ```
read_serial(port="loop://") read_serial(port="loop://")
``` ```
@ -90,6 +98,8 @@ Many serial devices send responses as lines terminated with `\r\n` or `\n`. Use
1. **Open and write multi-line data** 1. **Open and write multi-line data**
Ask the assistant to open a loopback port and send multi-line data:
``` ```
open_serial_port(port="loop://", baudrate=115200) open_serial_port(port="loop://", baudrate=115200)
``` ```
@ -100,6 +110,8 @@ Many serial devices send responses as lines terminated with `\r\n` or `\n`. Use
2. **Read one line at a time** 2. **Read one line at a time**
The assistant calls `read_serial_line` to get a single line:
``` ```
read_serial_line(port="loop://") read_serial_line(port="loop://")
``` ```
@ -117,6 +129,8 @@ Many serial devices send responses as lines terminated with `\r\n` or `\n`. Use
3. **Drain remaining lines in one call** 3. **Drain remaining lines in one call**
Ask the assistant to read all remaining lines:
``` ```
read_serial_lines(port="loop://", max_lines=10) read_serial_lines(port="loop://", max_lines=10)
``` ```
@ -149,6 +163,8 @@ Not every protocol uses newlines. Some devices use `>` as a prompt, `\x00` as a
1. **Open and write prompt-terminated data** 1. **Open and write prompt-terminated data**
Ask the assistant to open a loopback port and write data with a `>` prompt at the end:
``` ```
open_serial_port(port="loop://", baudrate=9600) open_serial_port(port="loop://", baudrate=9600)
``` ```
@ -159,6 +175,8 @@ Not every protocol uses newlines. Some devices use `>` as a prompt, `\x00` as a
2. **Read until the `>` prompt** 2. **Read until the `>` prompt**
The assistant calls `read_until` with a custom terminator:
``` ```
read_until(port="loop://", terminator=">") read_until(port="loop://", terminator=">")
``` ```
@ -186,7 +204,7 @@ Not every protocol uses newlines. Some devices use `>` as a prompt, `\x00` as a
## Testing encodings ## Testing encodings
Serial devices don't always speak UTF-8. Industrial equipment, legacy systems, and some sensors use Latin-1 or other single-byte encodings. mcserial's `encoding` parameter handles the translation. Serial devices don't always speak UTF-8. Industrial equipment, legacy systems, and some sensors use Latin-1 or other single-byte encodings. mcserial's `encoding` parameter handles the translation. Tell the assistant which encoding to use, and it passes the value through to the read/write calls.
<Steps> <Steps>
@ -198,7 +216,7 @@ Serial devices don't always speak UTF-8. Industrial equipment, legacy systems, a
2. **Write with Latin-1 encoding** 2. **Write with Latin-1 encoding**
Latin-1 maps bytes 0x00--0xFF directly, which makes it useful for binary-safe text: Latin-1 maps bytes 0x00--0xFF directly, which makes it useful for binary-safe text. The assistant calls:
``` ```
write_serial(port="loop://", data="Temp: 23\xb0C", encoding="latin-1") write_serial(port="loop://", data="Temp: 23\xb0C", encoding="latin-1")
@ -238,7 +256,7 @@ Serial devices don't always speak UTF-8. Industrial equipment, legacy systems, a
## Testing raw byte writes ## Testing raw byte writes
For binary protocols (Modbus RTU, custom framing, firmware uploads), use `write_serial_bytes` to send exact byte sequences: For binary protocols (Modbus RTU, custom framing, firmware uploads), the assistant uses `write_serial_bytes` to send exact byte sequences:
<Steps> <Steps>
@ -292,7 +310,7 @@ For binary protocols (Modbus RTU, custom framing, firmware uploads), use `write_
## Testing port configuration changes ## Testing port configuration changes
You can reconfigure an open port without closing and reopening it. This is useful for testing parameter changes or simulating baud rate switching: The assistant can reconfigure an open port without closing and reopening it. This is useful for testing parameter changes or simulating baud rate switching:
<Steps> <Steps>
@ -344,7 +362,7 @@ You can reconfigure an open port without closing and reopening it. This is usefu
## Testing buffer management ## Testing buffer management
When building protocol handlers, you sometimes need to clear stale data before sending a new command. Use `flush_serial` to reset the buffers: When working with protocol handlers, you sometimes need to clear stale data before sending a new command. Ask the assistant to flush the buffers:
``` ```
flush_serial(port="loop://", input_buffer=true, output_buffer=true) flush_serial(port="loop://", input_buffer=true, output_buffer=true)