8.4 KiB
RS232 — Serial Port Library for DJGPP
ISR-driven UART communication library supporting up to 4 simultaneous COM ports with ring buffers and hardware/software flow control.
Ported from the DOS Serial Library 1.4 by Karl Stenerud (MIT License), stripped to DJGPP-only codepaths and restyled.
Features
- ISR-driven receive and transmit with 2048-byte ring buffers
- Auto-detected IRQ from BIOS data area
- UART type detection (8250, 16450, 16550, 16550A)
- 16550 FIFO detection and configurable trigger threshold
- XON/XOFF, RTS/CTS, and DTR/DSR flow control
- DPMI memory locking for ISR safety
- Speeds from 50 to 115200 bps
- 5-8 data bits, N/O/E/M/S parity, 1-2 stop bits
API Reference
Types
All functions take a COM port index (int com) as their first argument:
| Constant | Value | Description |
|---|---|---|
RS232_COM1 |
0 | COM1 |
RS232_COM2 |
1 | COM2 |
RS232_COM3 |
2 | COM3 |
RS232_COM4 |
3 | COM4 |
UART Types
| Constant | Value | Description |
|---|---|---|
RS232_UART_UNKNOWN |
0 | Unknown or undetected |
RS232_UART_8250 |
1 | 8250 — no FIFO, no scratch register |
RS232_UART_16450 |
2 | 16450 — scratch register, no FIFO |
RS232_UART_16550 |
3 | 16550 — broken FIFO (unusable) |
RS232_UART_16550A |
4 | 16550A — working 16-byte FIFO |
Handshaking Modes
| Constant | Value | Description |
|---|---|---|
RS232_HANDSHAKE_NONE |
0 | No flow control |
RS232_HANDSHAKE_XONXOFF |
1 | Software (XON/XOFF) |
RS232_HANDSHAKE_RTSCTS |
2 | Hardware (RTS/CTS) |
RS232_HANDSHAKE_DTRDSR |
3 | Hardware (DTR/DSR) |
Error Codes
| Constant | Value | Description |
|---|---|---|
RS232_SUCCESS |
0 | Success |
RS232_ERR_UNKNOWN |
-1 | Unknown error |
RS232_ERR_NOT_OPEN |
-2 | Port not open |
RS232_ERR_ALREADY_OPEN |
-3 | Port already open |
RS232_ERR_NO_UART |
-4 | No UART detected |
RS232_ERR_INVALID_PORT |
-5 | Bad port index |
RS232_ERR_INVALID_BASE |
-6 | Bad I/O base address |
RS232_ERR_INVALID_IRQ |
-7 | Bad IRQ number |
RS232_ERR_INVALID_BPS |
-8 | Unsupported baud rate |
RS232_ERR_INVALID_DATA |
-9 | Bad data bits (not 5-8) |
RS232_ERR_INVALID_PARITY |
-10 | Bad parity character |
RS232_ERR_INVALID_STOP |
-11 | Bad stop bits (not 1-2) |
RS232_ERR_INVALID_HANDSHAKE |
-12 | Bad handshaking mode |
RS232_ERR_INVALID_FIFO |
-13 | Bad FIFO threshold |
RS232_ERR_NULL_PTR |
-14 | NULL pointer argument |
RS232_ERR_IRQ_NOT_FOUND |
-15 | Could not detect IRQ |
RS232_ERR_LOCK_MEM |
-16 | DPMI memory lock failed |
Functions
Open / Close
int rs232Open(int com, int32_t bps, int dataBits, char parity,
int stopBits, int handshake);
Opens a COM port. Detects the UART base address from the BIOS data area, auto-detects the IRQ, installs the ISR, and configures the port.
bps— baud rate (50, 75, 110, 150, 300, 600, 1200, 1800, 2400, 3800, 4800, 7200, 9600, 19200, 38400, 57600, 115200)dataBits— 5, 6, 7, or 8parity—'N'(none),'O'(odd),'E'(even),'M'(mark),'S'(space)stopBits— 1 or 2handshake—RS232_HANDSHAKE_*constant
int rs232Close(int com);
Closes the port, removes the ISR, and restores the original interrupt vector.
Read / Write
int rs232Read(int com, char *data, int len);
Reads up to len bytes from the receive buffer. Returns the number of
bytes actually read (0 if the buffer is empty).
int rs232Write(int com, const char *data, int len);
Blocking write. Sends len bytes, waiting for transmit buffer space
as needed. Returns RS232_SUCCESS or an error code.
int rs232WriteBuf(int com, const char *data, int len);
Non-blocking write. Copies as many bytes as will fit into the transmit buffer. Returns the number of bytes actually queued.
Buffer Management
int rs232ClearRxBuffer(int com);
int rs232ClearTxBuffer(int com);
Discard all data in the receive or transmit ring buffer.
Getters
int rs232GetBase(int com); // UART I/O base address
int32_t rs232GetBps(int com); // Current baud rate
int rs232GetCts(int com); // CTS line state (0 or 1)
int rs232GetData(int com); // Data bits setting
int rs232GetDsr(int com); // DSR line state (0 or 1)
int rs232GetDtr(int com); // DTR line state (0 or 1)
int rs232GetHandshake(int com); // Handshaking mode
int rs232GetIrq(int com); // IRQ number
int rs232GetLsr(int com); // Line status register
int rs232GetMcr(int com); // Modem control register
int rs232GetMsr(int com); // Modem status register
char rs232GetParity(int com); // Parity setting ('N','O','E','M','S')
int rs232GetRts(int com); // RTS line state (0 or 1)
int rs232GetRxBuffered(int com); // Bytes in receive buffer
int rs232GetStop(int com); // Stop bits setting
int rs232GetTxBuffered(int com); // Bytes in transmit buffer
int rs232GetUartType(int com); // UART type (RS232_UART_* constant)
rs232GetUartType probes the UART hardware to identify the chip:
- Scratch register test — writes two values to register 7 and reads them back. The 8250 lacks this register, so readback fails.
- FIFO test — enables the FIFO via the FCR, then reads IIR bits
7:6.
0b11= 16550A (working FIFO),0b10= 16550 (broken FIFO),0b00= 16450 (no FIFO). The original FCR value is restored after probing.
Setters
int rs232Set(int com, int32_t bps, int dataBits, char parity,
int stopBits, int handshake);
Reconfigure all port parameters at once (port must be open).
int rs232SetBase(int com, int base); // Override I/O base address
int rs232SetBps(int com, int32_t bps); // Change baud rate
int rs232SetData(int com, int dataBits); // Change data bits
int rs232SetDtr(int com, bool dtr); // Assert/deassert DTR
int rs232SetFifoThreshold(int com, int thr); // FIFO trigger level (1,4,8,14)
int rs232SetHandshake(int com, int handshake); // Change flow control mode
int rs232SetIrq(int com, int irq); // Override IRQ (before Open)
int rs232SetMcr(int com, int mcr); // Write modem control register
int rs232SetParity(int com, char parity); // Change parity
int rs232SetRts(int com, bool rts); // Assert/deassert RTS
int rs232SetStop(int com, int stopBits); // Change stop bits
Example
#include "rs232.h"
int main(void) {
// Open COM1 at 115200 8N1, no flow control
int rc = rs232Open(RS232_COM1, 115200, 8, 'N', 1, RS232_HANDSHAKE_NONE);
if (rc != RS232_SUCCESS) {
return 1;
}
// Identify UART chip
int uartType = rs232GetUartType(RS232_COM1);
// uartType == RS232_UART_16550A on most systems
// Blocking send
rs232Write(RS232_COM1, "Hello\r\n", 7);
// Non-blocking receive
char buf[128];
int n;
while ((n = rs232Read(RS232_COM1, buf, sizeof(buf))) > 0) {
// process buf[0..n-1]
}
rs232Close(RS232_COM1);
return 0;
}
Implementation Notes
- The ISR handles all four COM ports from a single shared handler. On entry it disables UART interrupts for all open ports, then re-enables CPU interrupts so higher-priority devices are serviced.
- Ring buffers use power-of-2 sizes (2048 bytes) with bitmask indexing for zero-branch wraparound.
- Flow control watermarks are at 80% (assert) and 20% (deassert) of buffer capacity.
- DPMI
__dpmi_lock_linear_regionis used to pin the ISR, ring buffers, and port state in physical memory.
Building
make # builds ../lib/librs232.a
make clean # removes objects and library
Target: DJGPP cross-compiler, 486+ CPU.