---
title: Timeout Tuning
description: Configuring read timeouts, inter-byte timeouts, and handling slow devices
sidebar:
  order: 6
---

import { Aside } from '@astrojs/starlight/components';

Timeouts control how long mcserial waits for data before giving up. Too short, and you miss valid responses. Too long, and your workflow stalls waiting for devices that will never respond. This guide helps you find the right balance.

---

## Timeout Types

mcserial supports three timeout parameters, each serving a different purpose:

| Parameter | Where Set | What It Controls |
|-----------|-----------|------------------|
| `timeout` | `open_serial_port`, `configure_serial`, per-read | How long to wait for *any* data to arrive |
| `inter_byte_timeout` | `open_serial_port`, `configure_serial` | Max gap between consecutive bytes during a read |
| `write_timeout` | `open_serial_port`, `configure_serial` | How long to wait for the write buffer to drain |

---

## Read Timeout (timeout)

The read timeout is how long `read_serial`, `read_serial_line`, and similar operations wait before returning with whatever data has arrived (possibly nothing).

**Default:** 1.0 second

### Setting at open time

```json
// open_serial_port(port="/dev/ttyUSB0", baudrate=115200, timeout=5.0)
{
  "success": true,
  "timeout": 5.0
}
```

### Changing on an open port

```json
// configure_serial(port="/dev/ttyUSB0", timeout=10.0)
{
  "success": true,
  "timeout": 10.0
}
```

### Per-read override

For one-off long waits without changing the port configuration:

```json
// read_serial(port="/dev/ttyUSB0", timeout=30.0)
```

This overrides the port's timeout for this single read, then reverts.

---

## Inter-Byte Timeout (inter_byte_timeout)

Inter-byte timeout specifies the maximum allowed gap between bytes *during* a read. If data starts arriving but then pauses longer than this threshold, the read completes with what has been received so far.

**Default:** None (disabled)

This is useful for protocols where the message length is unknown but messages end with a pause:

```json
// open_serial_port(
//   port="/dev/ttyUSB0",
//   baudrate=9600,
//   timeout=5.0,           // Wait up to 5s for first byte
//   inter_byte_timeout=0.1  // Complete if 100ms gap between bytes
// )
```

**How it interacts with `timeout`:**

1. `timeout` controls waiting for the *first* byte
2. Once data starts arriving, `inter_byte_timeout` controls gaps between subsequent bytes
3. If either expires, the read returns

<Aside type="tip" title="When to use inter_byte_timeout">
Inter-byte timeout is most useful when:
- Message length varies and there's no explicit terminator
- The device sends data in bursts with gaps
- You want to capture complete responses without knowing their size

For protocols with terminators (newlines, specific byte sequences), prefer `read_until` or `read_serial_line` instead.
</Aside>

---

## Write Timeout (write_timeout)

Write timeout controls how long `write_serial` waits for data to be accepted by the OS buffer. Under normal conditions, writes complete immediately. Write timeout only matters when:

- The output buffer is full (flow control blocking)
- The driver is waiting on hardware handshaking
- The serial adapter is overwhelmed

**Default:** None (blocking — wait indefinitely)

```json
// configure_serial(port="/dev/ttyUSB0", write_timeout=2.0)
```

If a write times out, the operation returns an error and partial data may have been sent.

---

## Baud Rate and Minimum Timeout

Lower baud rates transmit bytes slower. Your timeout must account for transmission time:

| Baud Rate | Bytes/Second | Time for 100 bytes |
|-----------|--------------|-------------------|
| 9600 | ~960 | ~104ms |
| 19200 | ~1920 | ~52ms |
| 115200 | ~11520 | ~9ms |
| 1000000 | ~100000 | ~1ms |

**Rule of thumb:** Minimum timeout should be at least `(expected_bytes / bytes_per_second) * 2` to allow for processing time on the remote device.

For a 100-byte response at 9600 baud:
```
100 bytes / 960 bytes/sec = 0.104 sec
Minimum timeout = 0.104 * 2 = 0.2 sec
```

Add more margin for devices that need processing time before responding.

---

## Slow Device Patterns

### GPS Cold Start

GPS receivers can take 30–60 seconds to acquire satellites and start outputting valid NMEA sentences during a cold start:

```json
// open_serial_port(port="/dev/ttyUSB0", baudrate=9600, timeout=60.0)

// Or use a moderate default and override per-read
// open_serial_port(port="/dev/ttyUSB0", baudrate=9600, timeout=1.0)
// read_serial_line(port="/dev/ttyUSB0", timeout=60.0)
```

### Industrial Sensors with Sample Cycles

Sensors that sample on a fixed interval may not respond until the next sample:

```json
// Sensor samples every 10 seconds
// configure_serial(port="/dev/ttyUSB0", timeout=12.0)
```

### Command-Response with Processing Delay

Devices that perform computation or flash writes before responding:

```json
// Write a command that triggers firmware flash
// write_serial(port="/dev/ttyUSB0", data="FLASH 0x1000\r\n")

// Wait for completion (could take several seconds)
// read_serial_line(port="/dev/ttyUSB0", timeout=30.0)
```

---

## Long Cables and Signal Degradation

Long serial cables introduce:

- **Propagation delay** — typically negligible (nanoseconds)
- **Signal degradation** — causes bit errors, retries, and timeouts

If you experience intermittent timeouts on long cable runs:

1. **Reduce baud rate** — lower rates are more tolerant of noise
2. **Enable hardware flow control** — RTS/CTS helps with buffering
3. **Check cable quality** — use shielded cables, avoid parallel power runs
4. **Add termination** — RS-485 buses need proper termination resistors

```json
// Conservative settings for a long cable
// open_serial_port(
//   port="/dev/ttyUSB0",
//   baudrate=9600,        // Lower baud for reliability
//   timeout=5.0,          // Extra time for retries
//   rtscts=true           // Hardware flow control
// )
```

---

## Auto-Baud Timeout (autobaud_timeout)

When opening a port without specifying a baud rate, mcserial runs auto-detection. The `autobaud_timeout` parameter controls how long to wait at each candidate rate:

```json
// open_serial_port(
//   port="/dev/ttyUSB0",
//   autobaud_timeout=1.0   // Wait up to 1 second per baud rate candidate
// )
```

**Default:** 0.3 seconds

Increase this if:
- The device sends data infrequently
- You're also sending a probe string that needs time to be processed

```json
// Slow device that echoes with delay
// open_serial_port(
//   port="/dev/ttyUSB0",
//   autobaud_probe="AT\r\n",
//   autobaud_timeout=0.5
// )
```

---

## Timeout Tuning Workflow

When you're not sure what timeout to use:

1. **Start conservative** — use a long timeout (10–30 seconds)
2. **Verify communication works** — can you send and receive?
3. **Measure actual response times** — how long do real responses take?
4. **Add margin** — set timeout to 2–3× typical response time
5. **Handle timeouts gracefully** — zero bytes or timeout errors should trigger retry or user notification

**Example measurement:**

```json
// Time a typical exchange
// write_serial(port="/dev/ttyUSB0", data="STATUS\r\n")
// read_serial_line(port="/dev/ttyUSB0", timeout=30.0)

// If response arrives in 0.5 seconds, set timeout to 1.5–2.0 seconds
// configure_serial(port="/dev/ttyUSB0", timeout=2.0)
```

---

## Timeout Quick Reference

| Scenario | Recommended Timeout | Notes |
|----------|-------------------|-------|
| Fast device, known protocol | 0.5–1.0 s | Just enough for transmission + processing |
| Unknown device | 5.0 s | Conservative starting point |
| GPS cold start | 60.0 s | Satellite acquisition takes time |
| Firmware flash commands | 30.0+ s | Flash write cycles are slow |
| Modbus RTU | 0.1–0.5 s | Per-transaction, short timeout for bus response |
| Auto-baud detection | 0.3–1.0 s | Per candidate baud rate |
| Long cable (>15m) | 2× normal | Account for potential retries |

<Aside type="note" title="Timeouts and blocking">
A timeout of `0` means non-blocking — return immediately with whatever is in the buffer.
A timeout of `None` (the default for write_timeout) means blocking — wait forever.

For read operations, prefer a finite timeout to avoid hanging indefinitely if a device fails.
</Aside>

---

## Environment Variable Defaults

Set server-wide defaults via environment variables:

```bash
# Default read timeout for all new connections
export MCSERIAL_DEFAULT_TIMEOUT=5.0
```

Individual tool calls can still override these defaults. See [Environment Variables](/reference/environment/) for the complete list.
