# 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 - 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 | ### 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 ```c 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 8 - `parity` — `'N'` (none), `'O'` (odd), `'E'` (even), `'M'` (mark), `'S'` (space) - `stopBits` — 1 or 2 - `handshake` — `RS232_HANDSHAKE_*` constant ```c int rs232Close(int com); ``` Closes the port, removes the ISR, and restores the original interrupt vector. #### Read / Write ```c 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). ```c 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. ```c 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 ```c int rs232ClearRxBuffer(int com); int rs232ClearTxBuffer(int com); ``` Discard all data in the receive or transmit ring buffer. #### Getters ```c 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 ``` #### Setters ```c 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). ```c 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 ```c #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; } // 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_region` is 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.