// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// RS-232 Serial Port Library for DJGPP
// Ported from DOS Serial Library 1.4 by Karl Stenerud (MIT License)
//
// ISR-driven UART communication with ring buffers and flow control.
// Supports up to 4 simultaneous COM ports with auto-detected IRQ.
//
// Architecture:
//   A single ISR (comGeneralIsr) handles all open COM ports. When any
//   UART interrupts, the ISR loops over all open ports draining their
//   FIFOs into per-port ring buffers. The application reads from these
//   buffers at its leisure. This decouples the UART's byte-at-a-time
//   pace from application-level processing.
//
//   Ring buffers are power-of-2 sized (2048 bytes) so head/tail index
//   wrapping is a single AND, not a modulo  -- critical for ISR speed.
//
//   Flow control (XON/XOFF, RTS/CTS, DTR/DSR) operates entirely within
//   the ISR using watermark thresholds. When the RX buffer is 80% full,
//   we signal the remote to stop; at 20%, we allow it to resume. This
//   prevents buffer overflow without application involvement.
//
//   The ISR and its data structures are locked in memory via DPMI to
//   prevent page faults during interrupt handling  -- a requirement for
//   any ISR running under a DPMI host (DOS extender, Windows, etc.).

#ifndef RS232_H
#define RS232_H

#include <stdint.h>
#include <stdbool.h>

// COM Ports
#define RS232_COM1                      0
#define RS232_COM2                      1
#define RS232_COM3                      2
#define RS232_COM4                      3
#define RS232_NUM_PORTS                 4

// Handshaking Modes
#define RS232_HANDSHAKE_NONE            0
#define RS232_HANDSHAKE_XONXOFF         1
#define RS232_HANDSHAKE_RTSCTS          2
#define RS232_HANDSHAKE_DTRDSR          3

// UART Types (detected by probing scratch register and FIFO capability)
// 8250:   No scratch register, no FIFO (original IBM PC)
// 16450:  Has scratch register, no FIFO
// 16550:  Has FIFO but it's buggy (rare)
// 16550A: Has working 16-byte FIFO (most common in 486+ era hardware)
#define RS232_UART_UNKNOWN              0
#define RS232_UART_8250                 1
#define RS232_UART_16450                2
#define RS232_UART_16550                3
#define RS232_UART_16550A               4

// Error Codes
#define RS232_SUCCESS                   0
#define RS232_ERR_UNKNOWN              -1
#define RS232_ERR_NOT_OPEN             -2
#define RS232_ERR_ALREADY_OPEN         -3
#define RS232_ERR_NO_UART              -4
#define RS232_ERR_INVALID_PORT         -5
#define RS232_ERR_INVALID_BASE         -6
#define RS232_ERR_INVALID_IRQ          -7
#define RS232_ERR_INVALID_BPS          -8
#define RS232_ERR_INVALID_DATA         -9
#define RS232_ERR_INVALID_PARITY      -10
#define RS232_ERR_INVALID_STOP        -11
#define RS232_ERR_INVALID_HANDSHAKE   -12
#define RS232_ERR_INVALID_FIFO        -13
#define RS232_ERR_NULL_PTR            -14
#define RS232_ERR_IRQ_NOT_FOUND       -15
#define RS232_ERR_LOCK_MEM            -16


// Buffer management
int rs232ClearRxBuffer(int com);
int rs232ClearTxBuffer(int com);

// Open/close
int rs232Close(int com);
int rs232Open(int com, int32_t bps, int dataBits, char parity, int stopBits, int handshake);

// Getters
int     rs232GetBase(int com);
int32_t rs232GetBps(int com);
int     rs232GetCts(int com);
int     rs232GetData(int com);
int     rs232GetDsr(int com);
int     rs232GetDtr(int com);
int     rs232GetHandshake(int com);
int     rs232GetIrq(int com);
int     rs232GetLsr(int com);
int     rs232GetMcr(int com);
int     rs232GetMsr(int com);
char    rs232GetParity(int com);
int     rs232GetRts(int com);
int     rs232GetRxBuffered(int com);
int     rs232GetStop(int com);
int     rs232GetTxBuffered(int com);
int     rs232GetUartType(int com);

// Read/write
// rs232Read: non-blocking drain from RX ring buffer, returns bytes read
// rs232Write: blocking polled write directly to UART THR (bypasses TX buffer)
// rs232WriteBuf: non-blocking write to TX ring buffer, ISR drains to UART
int rs232Read(int com, char *data, int len);
int rs232Write(int com, const char *data, int len);
int rs232WriteBuf(int com, const char *data, int len);

// Setters
int rs232Set(int com, int32_t bps, int dataBits, char parity, int stopBits, int handshake);
int rs232SetBase(int com, int base);
int rs232SetBps(int com, int32_t bps);
int rs232SetData(int com, int dataBits);
int rs232SetDtr(int com, bool dtr);
int rs232SetFifoThreshold(int com, int threshold);
int rs232SetHandshake(int com, int handshake);
int rs232SetIrq(int com, int irq);
int rs232SetMcr(int com, int mcr);
int rs232SetParity(int com, char parity);
int rs232SetRts(int com, bool rts);
int rs232SetStop(int com, int stopBits);

#endif
