📄 asynch.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
//
// Asynchronous Class for C++
// Copyright (C) 1991 by Jui-Lin Hung and SPD!
//
// You may freely use or incorporate these routines into your own programs
// without royalty to me, as I believe this is beneficial to programmers.
// However, I would like to request that if you distribute the source code,
// you would include this header in the source file and not remove it.
// Thank you, and I hope these routines are useful.
//
// April, 1991 - Version 1.1
//
/////////////////////////////////////////////////////////////////////////////
#include <dos.h>
#include <stdarg.h>
#include <stdio.h>
#include "asynch.h" // Asynch class definitions
/////////////////////////////////////////////////////////////////////////////
_ainfo_t _ainfo; // Global asynchronous info variable
/////////////////////////////////////////////////////////////////////////////
void far interrupt (*OldVect)(...);
void far interrupt asynch_irq(...)
// Asynchronous port interrupt handler. This is the new interrupt which
// we will swap with the old one to handle all asynchronous i/o
// This interrupt handler was apparently ripped off of Rob Raper's
// buffered NEWCOM routines for the WWIV bulletin board software.
// Original credit goes to him.
{
static int temp;
enable(); // enable interrupts
for (;;)
{
temp = inportb(_ainfo.base+IIR); // why interrupt was called
if (temp & 0x01) // Nothing else to do
{
outportb(ICR,EOI); // reset interrupt
return; // return to program
}
switch(temp)
{
case 0x00: // modem status changed
inportb(_ainfo.base+MSR); // read in useless char
break;
case 0x02: // Request To Send char
if (_ainfo.outhead != _ainfo.outtail) // there's a char to send
{
// send the character
outportb(_ainfo.base+TXR,_ainfo.outbuf[_ainfo.outhead++]);
// if at end of buffer, reset pointer
if (_ainfo.outhead == OBUF_LEN) _ainfo.outhead=0;
}
break;
case 0x04: // character ready to be read in
// read character into inbuffer
_ainfo.inbuf[_ainfo.inhead++] = inportb(_ainfo.base+RXR);
if (_ainfo.inhead == IBUF_LEN) // if at end of buffer
_ainfo.inhead=0; // reset pointer
break;
case 0x06: // line status has changed
inportb(_ainfo.base+LSR); // read in useless char
break;
default:
break;
}
}
}
void Asynch::asynchInit()
// Initializes variables, saves old interrupt vectors and sets the new
// interrupts. Initializes the asynchronous port too.
{
OldVect = getvect(_ainfo.irq+MCI); // Save old interrupt vector
setvect(_ainfo.irq+MCI,asynch_irq); // Set up serial int handler
outportb(_ainfo.base+LCR, 0x03); // Turn DTR and RTS on
disable(); // disable ints during init
int temp = inportb(_ainfo.base+LSR); // read serial port line status
temp = inportb(_ainfo.base+RXR); // read char
temp = inportb(IMR); // get interrupt settings
temp = temp & ((IER<<_ainfo.irq)^0xff); // turn on serial interrupt
outportb(IMR, temp); // send out new int settings
outportb(_ainfo.base+IER, IER); // turn on all IRQ events
outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) | 0x0a);
enable(); // re-enable all interrupts
_ainfo.inhead=_ainfo.intail=0; // reset in buffer pointers
_ainfo.outhead=_ainfo.outtail=0; // reset out buffer pointers
_ainfo.flow = 0; // Default flow control is off
_ainfo.nohangup = 0; // hangup when done
}
Asynch::Asynch(unsigned char p)
// Class constructor - set base address and irq number.
{
switch(p) // set up correct base address and irq for this port
{
case COM1: // serial port 1
_ainfo.base = 0x03f8; // base address for port 1
_ainfo.irq = 4; // interrupt number for port 1
break;
case COM2: // serial port 2
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
case COM3: // serial port 3
_ainfo.base = 0x03e8; // base address for port 3
_ainfo.irq = 4; // interrupt number for port 3
break;
case COM4: // serial port 4
_ainfo.base = 0x02e8; // base address for port 4
_ainfo.irq = 3; // interrupt number for port 4
break;
default: // defaults to com2, cuz that's what I have!
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
}
_ainfo.baud = 2400; // Default baud rate is 2400
asynchInit(); // call interrupt initialization
setBaud(_ainfo.baud); // set to default baud rate
}
Asynch::Asynch(unsigned char p,unsigned int b)
// Class constructor - set base address and irq number.
// This particular constructor also sets the baud rate to the
// specified speed
{
switch(p) // set up correct base address and irq for this port
{
case COM1: // serial port 1
_ainfo.base = 0x03f8; // base address for port 1
_ainfo.irq = 4; // interrupt number for port 1
break;
case COM2: // serial port 2
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
case COM3: // serial port 3
_ainfo.base = 0x03e8; // base address for port 3
_ainfo.irq = 4; // interrupt number for port 3
break;
case COM4: // serial port 4
_ainfo.base = 0x02e8; // base address for port 4
_ainfo.irq = 3; // interrupt number for port 4
break;
default: // defaults to com2
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
}
_ainfo.baud = b; // Default baud rate is 2400
asynchInit(); // call interrupt initialization
setBaud(_ainfo.baud); // set to default baud rate
}
Asynch::~Asynch()
// Class destructor - de-initializes the asynchronous port, and restores
// the old interrupts
{
disable(); // disable interrupts
int temp = inportb(IMR);
temp = temp | (IER << _ainfo.irq);
outportb(IMR, temp | CTS);
outportb(_ainfo.base+IIR, 0x00);
outportb(_ainfo.base+MCR, IER);
enable(); // enable interrupts
setvect(_ainfo.irq+MCI,OldVect); // reinstate old vector
}
void Asynch::setBaud(unsigned int b)
// Sets the baud rate to the specified speed
{
if (b > 49 && (long)b < 57601L)
{
float rate = 115200.0 / ((float)b);
_ainfo.baud = (unsigned int)rate;
outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) | 0x80);
outportb(_ainfo.base, (_ainfo.baud & 0x00ff));
outportb(_ainfo.base+IER, ((_ainfo.baud >> MCI) & 0x00ff));
outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) & 0x7f);
}
}
int Asynch::dtr()
// Returns 1 if the DTR is high, or if DTR remains low, returns a 0
{
int addr;
switch(_ainfo.port)
{
case COM1: addr = 0x03fe; break;
case COM2: addr = 0x02fe; break;
case COM3: addr = 0x03ee; break;
case COM4: addr = 0x02ee; break;
}
if (inportb(addr) & 128)
return(1);
delay(500);
return(inportb(addr) & 128);
}
void Asynch::setDtr()
// This function basically sets the DTR to high.
{
outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) & 0x00fe);
}
void Asynch::dropDtr()
// This function basically sets the DTR to low (i.e. hangs up the phone)
{
int addr;
if (!_ainfo.nohangup)
{
switch(_ainfo.port)
{
case COM1: addr = 0x03fc; break;
case COM2: addr = 0x02fc; break;
case COM3: addr = 0x03ec; break;
case COM4: addr = 0x02ec; break;
}
outportb(addr, inportb(addr) & 0xfe);
delay(500);
}
}
/////////////////////////////////////////////////////////////////////////////
Asynch &Asynch::operator<<(char ch)
// Inserts the character to be outputted into the output buffer, checking
// for an open slot in the output buffer array. If there is, insert
// the character, or if there isn't, wait until a slot opens up.
{
if (ch) // If this is a valid char
{
enable(); // turn on irqs to ensure data output
// check buffer, and if full, wait for an available opening
while((_ainfo.outhead-1==_ainfo.outtail) ||
(_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
;
disable(); // make sure nothing happens while changing buffer
_ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
if (_ainfo.outtail == OBUF_LEN) // if at end of out buffer
_ainfo.outtail = 0; // reset pointer
enable(); // re-enable interrupts
outportb(_ainfo.base+DTR,0x0f);
}
return(*this);
}
Asynch &Asynch::operator<<(char *str)
// Outputs a string to the serial port
{
while (*str)
{
if (*str=='\n')
(*this) << '\r', (*this) << '\n';
else
(*this) << (*str);
str++;
}
return(*this);
}
Asynch &Asynch::operator>>(char &ch)
// Returns either the character to be received from modem if there is one
// waiting in the buffer, or returns a 0 if there is no character waiting.
{
if (_ainfo.inhead != _ainfo.intail) // there is a character
{
disable(); // disable irqs while getting char
ch = _ainfo.inbuf[_ainfo.intail++]; // get character from buffer
if (_ainfo.intail == IBUF_LEN) // if at end of in buffer
_ainfo.intail=0; // reset pointer
enable(); // re-enable interrupt
return(*this); // return the char
}
ch = 0;
return(*this); // return nothing
}
/////////////////////////////////////////////////////////////////////////////
// C type functions for asynchronous i/o
char Asynch::ainkey()
// Returns 0 if no character waiting, or the character itself if there
// is a character waiting in the buffer
{
if (_ainfo.inhead != _ainfo.intail) // there is a character
{
disable(); // disable irqs while getting char
// get character from buffer
unsigned char ch = _ainfo.inbuf[_ainfo.intail++];
if (_ainfo.intail == IBUF_LEN) // if at end of in buffer
_ainfo.intail=0; // reset pointer
enable(); // re-enable interrupt
return(ch); // return the char
}
return(0); // return nothing
}
void Asynch::aputch(char ch)
// Inserts the character to be outputted into output buffer. If there is
// an open slot in the output buffer array, insert character there, or
// wait for a slot to open.
// This output character function apparently ripped off of Rob Raper's
// buffered NEWCOM routines for the WWIV bulletin board software.
// Original credit goes to him.
{
if (ch) // If this is a valid char
{
enable(); // turn on irqs to ensure data output
// check buffer, and if full, wait for an available opening
while((_ainfo.outhead-1==_ainfo.outtail) ||
(_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
;
disable(); // make sure nothing happens while changing buffer
_ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
if (_ainfo.outtail == OBUF_LEN) // if at end of out buffer
_ainfo.outtail = 0; // reset pointer
enable(); // re-enable interrupts
outportb(_ainfo.base+DTR,0x0f);
}
}
void Asynch::aputs(char *str)
// Outputs a string through the serial port
{
while (*str)
{
if (*str=='\n')
aputch('\r'), aputch('\n');
else
aputch(*str);
str++;
}
}
void Asynch::aprintf(char *format, ...)
// Outputs a formatted string through the serial port
{
#define MAXLEN 256
va_list argptr;
char str[256];
va_start(argptr,format); // access argument list
vsprintf(str,format,argptr); // create string using argument list
va_end(argptr); // end access of argument list
aputs(str); // output the formatted string
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -