| .. | ||
| Makefile | ||
| README.md | ||
| rs232.c | ||
| rs232.h | ||
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.