📄 comm.cpp
字号:
// ******************************************************************** //
// //
// COMM.CPP //
// Copyright (c) 1993, Michael Holmes and Bob Flanders //
// C++ Communication Utilities //
// //
// Chapter 7: Receiving a FAX //
// Last changed in chapter 7 //
// //
// This file contains the functions to implement the basic //
// communications class and facilities. Each instance of the //
// Comm class will control a single communications port. //
// //
// ******************************************************************** //
class Comm
{
public:
Comm(int b, // define a comm instance
int i, // base addr, interrupt
int d, // baud rate divisor
int l, // line control setting
int fc = 0, // flow control flag
UINT si = 3200, // input queue size
UINT so = 1500); // and output queue size
UINT Read(char *c, // read a character from queue
char *m, // ..and get modem status reg
char *l), // and line status register
Set8n(void), // set 8 data bits, no parity
ICount(void), // get depth of input queue
OCount(void), // ..or output queue
IFree(void), // free space in input queue
OFree(void); // ..or output queue
int Modem(void), // rtn modem status register
ModemChanged(void), // rtn TRUE if msr changed
IFlow(void), // rtn input flow ctrl status
IEmpty(void), // rtn TRUE if input queue
OEmpty(void); // ..or output queue empty
long GetSpeed(void); // rtn current speed in bps
void SetSpeed(int d), // set up port's divisor
SetBPS(long s), // set up port's speed
SetLine(int l), // ..and line control register
Write(int c), // write a character
Write(char *s), // ..or a string of characters
Write(char *s, int l), // ..or a block of characters
IClear(void), // clear input queue
OClear(void), // ..and output queue
DTR(long t = 1500L), // lower DTR temporarily
RTS(int), // RTS signal control
IntRoutine(void); // interrupt service routine
~Comm(); // destructor
private:
UINT base, // base port address
irq, // interrupt number
divisor, // baud rate divisor
line, // initial line control
i_size, // input buffer size
o_size, // output buffer size
i_start, // flow ctl restart limit
i_stop, // ..and upper stop limit
i_count, // characters in input queue
o_count, // ..and output queue
Deque(void); // deque an output queue char
char *i_buf, // input buffer
*i_get, // ..and nxt user get location
*i_put, // ..and nxt comm put location
*i_limit, // ..and last location
*i_last, // ..and last i_put location
i_of, // ..and input overflow flag
*o_buf, // output buffer
*o_get, // ..and nxt comm get location
*o_put, // ..and nxt user put location
*o_limit, // ..and last location
msr_changed, // msr changed flag
int_msr, // last interrupt msr
int_lsr, // ..and last interrupt lsr
fifo, // 16550 flag
flow, // flow control enable flag
o_flow, // output flow controlled flag
i_flow, // input flow controlled flag
empty_trans; // empty transmitter flag
void InstallInt(void), // install interrupt svc rtn
DeInstallInt(void), // de-install interrupt rtn
SetLimits(void), // set up flow ctl limits
CheckFifo(void), // set up fifo flags
Queue(int c, // queue char to input queue
int m, // saving modem status reg
int l), // and line status register
interrupt (*old_comm)(...); // old comm interrupt pointer
};
extern
Comm *comm; // current Comm instance
void interrupt far comm_int(...); // comm interrupt routine
/* ******************************************************************** *
*
* Comm -- define communications port instance
*
* ******************************************************************** */
Comm::Comm(int b, // comm port base address
int i, // interrupt number
int d, // baud rate divisor
int l, // line control setting
int fc, // flow control flag
UINT si, // input queue size
UINT so) // output queue size
{
UINT max_size = 64535U / 3; // max number of input chars
base = b; // set up instance base addr
irq = i; // ..interrupt request
o_size = so; // ..output buffer size
flow = fc; // ..flow control flag
CheckFifo(); // ..fifo flag if available
SetSpeed(d); // ..line speed
SetLine(l); // ..line format
if (si < 512) // q. less than .5k of buffer?
si = 512; // a. yes .. set to minimum
if (si > max_size) // q. greater than maximum?
si = max_size; // a. yes .. set to max size
if (so < 256) // q. really small output buf?
so = 256; // a. yes .. set to minimum
i_size = si; // save input buffer size
empty_trans = 1; // ..set empty transmitter flag
msr_changed = 1; // ..set msr changed flag
o_flow = i_flow = 0; // ..clear active flags
o_count = i_count = 0; // ..and current queue counts
i_buf = i_get = i_put = // allocate input buffer
new char[i_size * 3]; // ..for data, lsr and msr
i_limit = i_buf + (i_size - 1) * 3; // ..set limit address
memset(i_buf, 0, i_size * 3); // ..and clear area to nulls
o_buf = o_get = o_put = new char[o_size]; // allocate output buffer
o_limit = o_buf + o_size - 1; // ..set limit address
memset(o_buf, 0, o_size); // ..and clear area to nulls
SetLimits(); // set up flow ctl limits
InstallInt(); // ..and interrupt routine
int_msr = IN(MSR); // set up initial MSR
}
/* ******************************************************************** *
*
* SetLimits -- set up receive buffer flow control limits
*
* This routine sets up the flow control limits for receive
* operations. Flow control will be asserted when the buffer
* reaches a point when there is not enough room to receive
* a second worth of data in the input buffer. Flow control will
* be de-asserted when 50% of the upper limit is read by the
* application.
*
* ******************************************************************** */
void Comm::SetLimits(void)
{
i_stop = (UINT) (115200L / 10) / divisor; // get 1 second in characters
if (i_stop > i_size) // q. limit too high?
i_stop = i_size / 2; // a. yes .. set at half
else
i_stop = i_size - i_stop; // else .. set limit point
i_start = i_stop / 2; // set restart point at 50%
}
/* ******************************************************************** *
*
* CheckFifo -- if UART is a 16550, set FIFO variable to true
*
* ******************************************************************** */
void Comm::CheckFifo(void)
{
fifo = 0; // assume standard uart
OUT(FCR, 0xcf); // try to enable FIFOs
if ((IN(IIR) & 0xc0) != 0xc0) // q. FIFO bits found?
return; // a. no .. just return
OUT(FCR, 0); // turn off FIFOs
fifo = 1; // set fifo available flag
}
/* ******************************************************************** *
*
* SetSpeed -- set up port baud rate divisor
*
* ******************************************************************** */
void Comm::SetSpeed(int d) // baud rate divisor
{
divisor = d; // save divisor for later
OUT(IER, 0); // clear interrupts enable
if (fifo) // q. is UART a 16550 chip?
OUT(FCR, FCR_16550); // a. yes .. enable fifo
IN(LSR); // read/reset line status reg
IN(MSR); // ..and modem status register
IN(IIR); // ..and interrupt id register
IN(RBR); // ..and receive buffer reg
__asm cli // stop interrupts
OUT(LCR, IN(LCR) | LCR_DLAB); // set divisor latch bit
OUT(DLM, d >> 8); // out msb portion of divisor
OUT(DLL, d & 0xff); // ..then the lsb portion
OUT(LCR, IN(LCR) & ~LCR_DLAB); // clear divisor latch bit
OUT(MCR, MCR_DO); // enable DTR, OUT2 and RTS
__asm sti // ..and interrupts
OUT(IER, IER_RBF | IER_TBE | IER_MSI); // then enable UART interrupts
}
/* ******************************************************************** *
*
* SetBPS -- set port's speed
*
* ******************************************************************** */
void Comm::SetBPS(long s) // speed in BPS
{
SetSpeed((int)(115200L / s)); // calc and set divisor
}
/* ******************************************************************** *
*
* GetSpeed -- retrieve current port speed
*
* ******************************************************************** */
long Comm::GetSpeed(void)
{
return((long) (115200L / (long) divisor)); // return current speed
}
/* ******************************************************************** *
*
* SetLine -- set up port's line control register
*
* ******************************************************************** */
void Comm::SetLine(int l) // new line control setting
{
line = l & ~LCR_DLAB; // save new value in instance
OUT(LCR, line); // ..and write new LCR
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -