DVX_GUI/rs232/README.md

212 lines
7.2 KiB
Markdown

# 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.