libserialport clib Hardware / I/O

Minimal cross-platform serial port library by the sigrok project. One API for Windows, Linux, and macOS — no platform #ifdef needed.

ppm install libserialport

What is libserialport?

libserialport is a minimal, cross-platform C library created by the sigrok project — the same team behind PulseView and sigrok-cli. It provides a single, clean API for serial port communication that works on all major platforms without any platform-specific code in your application.

Under the hood it uses the Win32 API on Windows, termios on Linux, and IOKit on macOS. You write your code once and it runs everywhere.

CLib package — system library required

Ubuntu/Debian: sudo apt install libserialport-dev  •  macOS: brew install libserialport  •  Windows: download from sigrok.org or use vcpkg.

Common Serial Port Settings

Every serial connection is defined by five parameters. Both ends must use identical settings or communication will fail.

ParameterTypical valuesNotes
Baud rate9600, 115200, 9216009600 is universal default; 115200 for most modern devices; 921600 for high-throughput sensors
Data bits8 (almost always)5, 6, 7 exist for legacy equipment; 8 is the standard for modern use
ParityNone (most common)Odd/Even add a parity bit for error detection; None is standard for USB-serial adapters
Stop bits1 (most common)2 stop bits used with slow baud rates or older hardware; 1.5 is rare
Flow controlNone or RTS/CTSNone for simple adapters; RTS/CTS (hardware) for reliable high-speed transfers; XON/XOFF (software) for text-based protocols

Use Cases

What connects over serial?

Microcontrollers — Arduino, ESP32, STM32 via USB-serial adapters (CP2102, CH340, FTDI FT232).
Industrial protocols — Modbus RTU over RS-485 two-wire buses; SCADA field devices.
GPS receivers — NMEA 0183 sentences at 4800 or 9600 baud; u-blox modules at 115200.
Legacy lab instruments — oscilloscopes, signal generators, multimeters with RS-232 ports.
Industrial sensors — barcode scanners, weight scales, temperature controllers, PLCs.

Types

type
  TSPPort   = Integer;  { serial port handle }
  TSPConfig = Integer;  { port configuration handle }

  TSPParity = (
    spParNone  = 0,  { no parity (most common) }
    spParOdd   = 1,  { odd parity }
    spParEven  = 2,  { even parity }
    spParMark  = 3,  { mark parity }
    spParSpace = 4   { space parity }
  );

  TSPFlow = (
    spFlowNone    = 0,  { no flow control }
    spFlowXonXoff = 1,  { software: XON/XOFF }
    spFlowRtsCts  = 2,  { hardware: RTS/CTS }
    spFlowDtrDsr  = 3   { hardware: DTR/DSR }
  );

  TSPMode = (
    spRead      = 1,
    spWrite     = 2,
    spReadWrite = 3
  );

  TSPSignal = (
    spCTS = 1,  { Clear To Send }
    spDSR = 2,  { Data Set Ready }
    spDCD = 4,  { Data Carrier Detect }
    spRI  = 8   { Ring Indicator }
  );

  TSPPortInfo = record
    Name         : string;  { e.g. '/dev/ttyUSB0', 'COM3' }
    Description  : string;  { human-readable device description }
    Transport    : string;  { 'native', 'usb', 'bluetooth' }
    USBVendorID  : Integer;
    USBProductID : Integer;
    USBSerial    : string;
    USBBus       : Integer;
    USBAddress   : Integer;
  end;

API Reference

Enumeration

{ List all available serial port names. }
function ListPorts: array of string;

{ List ports with full info (description, USB IDs, transport). }
function ListPortsInfo: array of TSPPortInfo;

Open / Close

{ Open a serial port by name. Mode: spRead, spWrite, spReadWrite. }
function OpenPort(const Name: string; Mode: TSPMode): TSPPort;

{ Close port and release all resources. }
procedure ClosePort(Port: TSPPort);

{ Get port info (description, USB IDs) for an open port. }
function GetPortInfo(Port: TSPPort): TSPPortInfo;

Configuration

{ Configure port with all settings at once (most common approach). }
procedure Configure(Port: TSPPort; BaudRate, DataBits: Integer;
                    Parity: TSPParity; StopBits: Integer; Flow: TSPFlow);

{ Set individual parameters. }
procedure SetBaudRate(Port: TSPPort; BaudRate: Integer);
procedure SetDataBits(Port: TSPPort; Bits: Integer);
procedure SetParity(Port: TSPPort; Parity: TSPParity);
procedure SetStopBits(Port: TSPPort; Bits: Integer);
procedure SetFlowControl(Port: TSPPort; Flow: TSPFlow);

{ Get current configuration as human-readable string. }
function GetConfig(Port: TSPPort): string;

I/O

{ Write data to port. Returns bytes written. }
function WritePort(Port: TSPPort; const Data: string): Integer;

{ Write with timeout in ms. 0 = non-blocking. }
function WriteTimeout(Port: TSPPort; const Data: string; TimeoutMs: Integer): Integer;

{ Read up to MaxBytes. Returns data read (may be less than MaxBytes). }
function ReadPort(Port: TSPPort; MaxBytes: Integer): string;

{ Read with timeout in ms. -1 = block until data available. }
function ReadTimeout(Port: TSPPort; MaxBytes, TimeoutMs: Integer): string;

{ Read a newline-terminated line. TimeoutMs: max wait in ms. }
function ReadLine(Port: TSPPort; TimeoutMs: Integer): string;

{ Number of bytes waiting in input buffer. }
function InputWaiting(Port: TSPPort): Integer;

{ Number of bytes in output buffer not yet sent. }
function OutputWaiting(Port: TSPPort): Integer;

{ Discard all pending input and output buffers. }
procedure Flush(Port: TSPPort);

{ Drain — block until all output bytes have been transmitted. }
procedure Drain(Port: TSPPort);

Control Lines

{ Set RTS (Request To Send) line state. }
procedure SetRTS(Port: TSPPort; Value: Boolean);

{ Set DTR (Data Terminal Ready) line state. }
procedure SetDTR(Port: TSPPort; Value: Boolean);

{ Read CTS/DSR/DCD/RI signal states as a bitmask (use TSPSignal enum). }
function GetSignals(Port: TSPPort): Integer;

{ Send a break signal for DurationMs milliseconds. }
procedure SendBreak(Port: TSPPort; DurationMs: Integer);

Error Handling

{ Get last error message from the library. }
function GetLastError: string;

{ Get the underlying libserialport version string. }
function LibSerialPortVersion: string;

Code Example — Arduino Communication

uses libserialport;

var
  Port  : TSPPort;
  Resp  : string;
  Ports : array of string;
  I     : Integer;

begin
  { List available ports }
  Ports := ListPorts;
  WriteLn('Available serial ports:');
  for I := 0 to High(Ports) do
    WriteLn('  ', Ports[I]);

  { Open and configure for Arduino at 9600 baud }
  Port := OpenPort('/dev/ttyUSB0', spReadWrite);
  Configure(Port, 9600, 8, spParNone, 1, spFlowNone);
  WriteLn('Config: ', GetConfig(Port));

  { Send command to Arduino }
  WritePort(Port, 'LED_ON' + #13 + #10);

  { Wait for response, 2 second timeout }
  Resp := ReadLine(Port, 2000);
  WriteLn('Arduino says: ', Resp);

  ClosePort(Port);
end.

Port Name Reference

How to find the right port name

Linux: /dev/ttyUSB0 (USB-serial adapter: CP2102, CH340, FTDI), /dev/ttyACM0 (Arduino CDC / composite), /dev/ttyS0 (hardware RS-232 COM port).
Windows: COM3, COM4, etc. Check Device Manager under “Ports (COM & LPT)”. High-numbered COM ports (COM10+) also work.
macOS: /dev/tty.usbserial-* (FTDI / prolific adapters), /dev/tty.usbmodem* (Arduino CDC). Use ls /dev/tty.* to list.
Tip: call ListPorts at runtime to enumerate all ports without hardcoding a name.

Package Info

Version1.0.0
Typeclib
C Librarylibserialport
Authorgustavo

Install

ppm install libserialport
Requireslibserialport-dev

Note

By the sigrok project — same team as PulseView logic analyzer and sigrok-cli.

Functions

  • ListPorts
  • ListPortsInfo
  • OpenPort
  • ClosePort
  • GetPortInfo
  • Configure
  • SetBaudRate
  • SetDataBits
  • SetParity
  • SetStopBits
  • SetFlowControl
  • GetConfig
  • WritePort
  • WriteTimeout
  • ReadPort
  • ReadTimeout
  • ReadLine
  • InputWaiting
  • OutputWaiting
  • Flush / Drain
  • SetRTS / SetDTR
  • GetSignals
  • SendBreak
  • GetLastError
  • LibSerialPortVersion

See Also