⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asynch.cpp

📁 异步处理类, C++代码
💻 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 + -