Serial Communication (ltf.serial)
ltf.serial provides an interface for communicating with serial port devices (COM ports or /dev/tty*). It can list available ports, open/configure a port, and perform read/write operations.
Getting started
serial is exposed as a submodule of ltf:
local ltf = require("ltf")
local serial = ltf.serial
API reference
Device discovery
ltf.serial.list_devices()
Lists all serial ports detected on the system.
Returns:
- (
serial_port_info[]): array ofserial_port_info
Example:
local ltf = require("ltf")
local serial = ltf.serial
ltf.test({
name = "List all serial ports",
body = function()
local devices = serial.list_devices()
if #devices > 0 then
ltf.print("Found", #devices, "serial devices:")
for _, device in ipairs(devices) do
ltf.print(("- %s (%s)"):format(device.path, device.description))
end
else
ltf.log_warning("No serial devices found.")
end
end,
})
ltf.serial.get_port(path)
Gets a handle for a specific serial port by its path/name (e.g. "COM3" or "/dev/ttyUSB0"). This does not open the port.
Parameters:
path(string): port path or name
Returns:
- (
serial_port): serial port handle
The serial_port object
The serial_port handle is returned by ltf.serial.get_port(path) and provides methods for configuring and communicating with the port.
port:open(mode)
Opens the port.
Parameters:
mode(serial_mode):"r","w", or"rw"
port:close()
Closes the port. Recommended to call via ltf.defer(...).
port:read(chunk_size) -> string
Reads up to chunk_size bytes (non-blocking).
port:write(data) -> integer
Writes data (non-blocking). Returns number of bytes written.
port:read_until(opts) -> (found, read)
Reads repeatedly until the pattern appears or timeout is reached.
Parameters:
-
opts(serial_read_until_opts): -
pattern(string, optional): literal string pattern (usesstring.find(..., true)). Default:"\n". timeout(integer, optional): timeout in milliseconds. Default:200.chunk_size(integer, optional): read chunk size. Default:64.
Returns:
found(boolean):trueif pattern was found before timeout,falseotherwiseread(string): everything that was read (always returned)
Port configuration methods
These configure the communication parameters:
port:set_baudrate(baudrate)port:set_bits(bits)port:set_parity(parity)port:set_stopbits(stopbits)port:set_flowcontrol(flowctrl)port:set_rts(rts_option)port:set_dtr(dtr_option)port:set_cts(cts_option)port:set_dsr(dsr_option)port:set_xon_xoff(xonxoff_option)
Port status & control
port:flush(direction)port:drain()port:get_waiting_input() -> integerport:get_waiting_output() -> integerport:get_port_info() -> serial_port_info
Full example
local ltf = require("ltf")
local serial = ltf.serial
ltf.test({
name = "Communicate with GPS Device",
tags = { "hardware", "gps" },
body = function()
local devices = serial.list_devices()
local gps_path = nil
for _, dev in ipairs(devices) do
if dev.product and dev.product:find("GPS") then
gps_path = dev.path
break
end
end
if not gps_path then
ltf.log_critical("GPS device not found!")
end
ltf.log_info("Found GPS device at:", gps_path)
local port = serial.get_port(gps_path)
ltf.defer(port.close, port)
port:open("rw")
port:set_baudrate(9600)
port:set_bits(8)
port:set_parity("none")
port:set_stopbits(1)
ltf.print("Port configured. Waiting for NMEA sentence...")
local found, data = port:read_until({
pattern = "$GPGGA",
timeout = 5000,
chunk_size = 64,
})
if found then
ltf.log_info("Received GPGGA sentence:", data)
else
ltf.log_error("Did not receive a GPGGA sentence in time. Read:", data)
end
end,
})
Data structures & types
serial_port_info (table)
Returned by ltf.serial.list_devices() and port:get_port_info().
| Field | Type | Description |
|---|---|---|
path |
string |
Path/name of the port (e.g. COM3, /dev/ttyS0). |
type |
serial_port_type |
"native", "usb", "bluetooth", "unknown". |
description |
string |
Human-readable description. |
serial |
string? |
USB serial number (if available). |
product |
string? |
USB product string (if available). |
manufacturer |
string? |
USB manufacturer string (if available). |
vid |
number? |
USB vendor ID (if available). |
pid |
number? |
USB product ID (if available). |
usb_address |
number? |
USB port address (if available). |
usb_bus |
number? |
USB bus number (if available). |
bluetooth_address |
string? |
Bluetooth MAC address (if available). |
Type aliases
| Alias | Accepted values | Description |
|---|---|---|
serial_mode |
"r", "w", "rw" |
Read / Write / Read+Write. |
serial_flush_direction |
"i", "o", "io" |
Flush input / output / both. |
serial_data_bits |
5, 6, 7, 8 |
Data bits. |
serial_parity |
"none", "odd", "even", "mark", "space" |
Parity mode. |
serial_stop_bits |
1, 2 |
Stop bits. |
serial_flowctrl |
"dtrdsr", "rtscts", "xonxoff", "none" |
Flow control. |
serial_rts |
"off", "on", "flowctrl" |
RTS behavior. |
serial_dtr |
"off", "on", "flowctrl" |
DTR behavior. |
serial_cts |
"ignore", "flowctrl" |
CTS behavior. |
serial_dsr |
"ignore", "flowctrl" |
DSR behavior. |
serial_xonxoff |
"i", "o", "io", "disable" |
XON/XOFF mode. |
serial_port_type |
"native", "usb", "bluetooth", "unknown" |
Port connection type. |
Low-level access
ltf.serial.low
serial.low exposes the underlying low-level module (require("ltf-serial")). Most users should use the high-level API above.