home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / communic / asycls11 / asynch.cpp next >
Encoding:
C/C++ Source or Header  |  1991-04-06  |  13.7 KB  |  393 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  Asynchronous Class for C++
  4. //  Copyright (C) 1991 by Jui-Lin Hung and SPD!
  5. //
  6. //  You may freely use or incorporate these routines into your own programs
  7. //  without royalty to me, as I believe this is beneficial to programmers.
  8. //  However, I would like to request that if you distribute the source code,
  9. //  you would include this header in the source file and not remove it.
  10. //  Thank you, and I hope these routines are useful.
  11. //
  12. //  April, 1991 - Version 1.1
  13. //
  14. /////////////////////////////////////////////////////////////////////////////
  15.  
  16.  
  17. #include <dos.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20.  
  21. #include "asynch.h"     // Asynch class definitions
  22.  
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25.  
  26.  
  27. _ainfo_t _ainfo;                // Global asynchronous info variable
  28.  
  29.  
  30. /////////////////////////////////////////////////////////////////////////////
  31.  
  32.  
  33. void far interrupt (*OldVect)(...);
  34.  
  35. void far interrupt asynch_irq(...)
  36. // Asynchronous port interrupt handler.  This is the new interrupt which
  37. // we will swap with the old one to handle all asynchronous i/o
  38. // This interrupt handler was apparently ripped off of Rob Raper's
  39. // buffered NEWCOM routines for the WWIV bulletin board software.
  40. // Original credit goes to him.
  41. {
  42.     static int temp;
  43.  
  44.     enable();                               // enable interrupts
  45.     for (;;)
  46.     {
  47.         temp = inportb(_ainfo.base+IIR);    // why interrupt was called
  48.         if (temp & 0x01)                    // Nothing else to do
  49.         {
  50.             outportb(ICR,EOI);              // reset interrupt
  51.             return;                         // return to program
  52.         }
  53.         switch(temp)
  54.         {
  55.             case 0x00:  // modem status changed
  56.                 inportb(_ainfo.base+MSR);   // read in useless char
  57.                 break;
  58.             case 0x02:  // Request To Send char
  59.                 if (_ainfo.outhead != _ainfo.outtail)  // there's a char to send
  60.                 {
  61.                     // send the character
  62.                     outportb(_ainfo.base+TXR,_ainfo.outbuf[_ainfo.outhead++]);
  63.                     // if at end of buffer, reset pointer
  64.                     if (_ainfo.outhead == OBUF_LEN) _ainfo.outhead=0;
  65.                 }
  66.                 break;
  67.             case 0x04:  // character ready to be read in
  68.                 // read character into inbuffer
  69.                 _ainfo.inbuf[_ainfo.inhead++] = inportb(_ainfo.base+RXR);
  70.                 if (_ainfo.inhead == IBUF_LEN) // if at end of buffer
  71.                     _ainfo.inhead=0;           // reset pointer
  72.                 break;
  73.             case 0x06:  // line status has changed
  74.                 inportb(_ainfo.base+LSR);     // read in useless char
  75.                 break;
  76.             default:
  77.                 break;
  78.         }
  79.     }
  80. }
  81.  
  82.  
  83. void Asynch::asynchInit()
  84. // Initializes variables, saves old interrupt vectors and sets the new
  85. // interrupts.  Initializes the asynchronous port too.
  86. {
  87.     OldVect = getvect(_ainfo.irq+MCI);      // Save old interrupt vector
  88.     setvect(_ainfo.irq+MCI,asynch_irq);     // Set up serial int handler
  89.     outportb(_ainfo.base+LCR, 0x03);        // Turn DTR and RTS on
  90.     disable();                              // disable ints during init
  91.     int temp = inportb(_ainfo.base+LSR);    // read serial port line status
  92.     temp = inportb(_ainfo.base+RXR);        // read char
  93.     temp = inportb(IMR);                    // get interrupt settings
  94.     temp = temp & ((IER<<_ainfo.irq)^0xff); // turn on serial interrupt
  95.     outportb(IMR, temp);                    // send out new int settings
  96.     outportb(_ainfo.base+IER, IER);         // turn on all IRQ events
  97.     outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) | 0x0a);
  98.     enable();                               // re-enable all interrupts
  99.  
  100.     _ainfo.inhead=_ainfo.intail=0;          // reset in buffer pointers
  101.     _ainfo.outhead=_ainfo.outtail=0;        // reset out buffer pointers
  102.     _ainfo.flow = 0;                        // Default flow control is off
  103.     _ainfo.nohangup = 0;                    // hangup when done
  104. }
  105.  
  106.  
  107. Asynch::Asynch(unsigned char p)
  108. // Class constructor - set base address and irq number.
  109. {
  110.     switch(p)   // set up correct base address and irq for this port
  111.     {
  112.         case COM1:  // serial port 1
  113.             _ainfo.base = 0x03f8;   // base address for port 1
  114.             _ainfo.irq  = 4;        // interrupt number for port 1
  115.             break;
  116.         case COM2:  // serial port 2
  117.             _ainfo.base = 0x02f8;   // base address for port 2
  118.             _ainfo.irq  = 3;        // interrupt number for port 2
  119.             break;
  120.         case COM3:  // serial port 3
  121.             _ainfo.base = 0x03e8;   // base address for port 3
  122.             _ainfo.irq  = 4;        // interrupt number for port 3
  123.             break;
  124.         case COM4:  // serial port 4
  125.             _ainfo.base = 0x02e8;   // base address for port 4
  126.             _ainfo.irq  = 3;        // interrupt number for port 4
  127.             break;
  128.         default:  // defaults to com2, cuz that's what I have!
  129.             _ainfo.base = 0x02f8;   // base address for port 2
  130.             _ainfo.irq  = 3;        // interrupt number for port 2
  131.             break;
  132.     }
  133.  
  134.     _ainfo.baud = 2400;             // Default baud rate is 2400
  135.  
  136.     asynchInit();                   // call interrupt initialization
  137.     setBaud(_ainfo.baud);           // set to default baud rate
  138. }
  139.  
  140.  
  141. Asynch::Asynch(unsigned char p,unsigned int b)
  142. // Class constructor - set base address and irq number.
  143. // This particular constructor also sets the baud rate to the
  144. // specified speed
  145. {
  146.     switch(p)   // set up correct base address and irq for this port
  147.     {
  148.         case COM1:  // serial port 1
  149.             _ainfo.base = 0x03f8;   // base address for port 1
  150.             _ainfo.irq  = 4;        // interrupt number for port 1
  151.             break;
  152.         case COM2:  // serial port 2
  153.             _ainfo.base = 0x02f8;   // base address for port 2
  154.             _ainfo.irq  = 3;        // interrupt number for port 2
  155.             break;
  156.         case COM3:   // serial port 3
  157.             _ainfo.base = 0x03e8;   // base address for port 3
  158.             _ainfo.irq  = 4;        // interrupt number for port 3
  159.             break;
  160.         case COM4:  // serial port 4
  161.             _ainfo.base = 0x02e8;   // base address for port 4
  162.             _ainfo.irq  = 3;        // interrupt number for port 4
  163.             break;
  164.         default:    // defaults to com2
  165.             _ainfo.base = 0x02f8;   // base address for port 2
  166.             _ainfo.irq  = 3;        // interrupt number for port 2
  167.             break;
  168.     }
  169.  
  170.     _ainfo.baud = b;                // Default baud rate is 2400
  171.  
  172.     asynchInit();                   // call interrupt initialization
  173.     setBaud(_ainfo.baud);           // set to default baud rate
  174. }
  175.  
  176.  
  177.  
  178. Asynch::~Asynch()
  179. // Class destructor - de-initializes the asynchronous port, and restores
  180. // the old interrupts
  181. {
  182.     disable();                          // disable interrupts
  183.     int temp = inportb(IMR);
  184.     temp = temp | (IER << _ainfo.irq);
  185.     outportb(IMR, temp | CTS);
  186.     outportb(_ainfo.base+IIR, 0x00);
  187.     outportb(_ainfo.base+MCR, IER);
  188.     enable();                           // enable interrupts
  189.     setvect(_ainfo.irq+MCI,OldVect);    // reinstate old vector
  190. }
  191.  
  192.  
  193. void Asynch::setBaud(unsigned int b)
  194. // Sets the baud rate to the specified speed
  195. {
  196.     if (b > 49 && (long)b < 57601L)
  197.     {
  198.         float rate = 115200.0 / ((float)b);
  199.         _ainfo.baud = (unsigned int)rate;
  200.  
  201.         outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) | 0x80);
  202.         outportb(_ainfo.base, (_ainfo.baud & 0x00ff));
  203.         outportb(_ainfo.base+IER, ((_ainfo.baud >> MCI) & 0x00ff));
  204.         outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) & 0x7f);
  205.     }
  206. }
  207.  
  208.  
  209. int Asynch::dtr()
  210. // Returns 1 if the DTR is high, or if DTR remains low, returns a 0
  211. {
  212.     int addr;
  213.  
  214.     switch(_ainfo.port)
  215.     {
  216.         case COM1: addr = 0x03fe; break;
  217.         case COM2: addr = 0x02fe; break;
  218.         case COM3: addr = 0x03ee; break;
  219.         case COM4: addr = 0x02ee; break;
  220.     }
  221.     if (inportb(addr) & 128)
  222.         return(1);
  223.     delay(500);
  224.     return(inportb(addr) & 128);
  225. }
  226.  
  227.  
  228. void Asynch::setDtr()
  229. // This function basically sets the DTR to high.
  230. {
  231.     outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) & 0x00fe);
  232. }
  233.  
  234.  
  235. void Asynch::dropDtr()
  236. // This function basically sets the DTR to low (i.e. hangs up the phone)
  237. {
  238.     int addr;
  239.  
  240.     if (!_ainfo.nohangup)
  241.     {
  242.         switch(_ainfo.port)
  243.         {
  244.             case COM1: addr = 0x03fc; break;
  245.             case COM2: addr = 0x02fc; break;
  246.             case COM3: addr = 0x03ec; break;
  247.             case COM4: addr = 0x02ec; break;
  248.         }
  249.         outportb(addr, inportb(addr) & 0xfe);
  250.         delay(500);
  251.     }
  252. }    
  253.  
  254.  
  255. /////////////////////////////////////////////////////////////////////////////
  256.  
  257.  
  258. Asynch &Asynch::operator<<(char ch)
  259. // Inserts the character to be outputted into the output buffer, checking
  260. // for an open slot in the output buffer array.  If there is, insert
  261. // the character, or if there isn't, wait until a slot opens up.
  262. {
  263.     if (ch)                         // If this is a valid char
  264.     {
  265.         enable();                   // turn on irqs to ensure data output
  266.  
  267.         // check buffer, and if full, wait for an available opening
  268.         while((_ainfo.outhead-1==_ainfo.outtail) ||
  269.               (_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
  270.             ;
  271.         disable();  // make sure nothing happens while changing buffer
  272.         _ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
  273.         if (_ainfo.outtail == OBUF_LEN)     // if at end of out buffer
  274.             _ainfo.outtail = 0;             // reset pointer
  275.         enable();                           // re-enable interrupts
  276.         outportb(_ainfo.base+DTR,0x0f);
  277.     }
  278.     return(*this);
  279. }
  280.  
  281.  
  282. Asynch &Asynch::operator<<(char *str)
  283. // Outputs a string to the serial port
  284. {
  285.     while (*str)
  286.     {
  287.         if (*str=='\n')
  288.             (*this) << '\r', (*this) << '\n';
  289.         else
  290.             (*this) << (*str);
  291.         str++;
  292.     }
  293.     return(*this);
  294. }
  295.  
  296.  
  297. Asynch &Asynch::operator>>(char &ch)
  298. // Returns either the character to be received from modem if there is one
  299. // waiting in the buffer, or returns a 0 if there is no character waiting.
  300. {
  301.     if (_ainfo.inhead != _ainfo.intail)     // there is a character
  302.     {
  303.         disable();                          // disable irqs while getting char
  304.         ch = _ainfo.inbuf[_ainfo.intail++]; // get character from buffer
  305.         if (_ainfo.intail == IBUF_LEN)      // if at end of in buffer
  306.             _ainfo.intail=0;                // reset pointer
  307.         enable();                           // re-enable interrupt
  308.         return(*this);                      // return the char
  309.     }
  310.     ch = 0;
  311.     return(*this);                          // return nothing
  312. }
  313.  
  314.  
  315. /////////////////////////////////////////////////////////////////////////////
  316.  
  317.  
  318. // C type functions for asynchronous i/o
  319.  
  320. char Asynch::ainkey()
  321. // Returns 0 if no character waiting, or the character itself if there
  322. // is a character waiting in the buffer
  323. {
  324.     if (_ainfo.inhead != _ainfo.intail)     // there is a character
  325.     {
  326.         disable();                          // disable irqs while getting char
  327.  
  328.         // get character from buffer
  329.         unsigned char ch = _ainfo.inbuf[_ainfo.intail++];
  330.  
  331.         if (_ainfo.intail == IBUF_LEN)      // if at end of in buffer
  332.             _ainfo.intail=0;                // reset pointer
  333.         enable();                           // re-enable interrupt
  334.         return(ch);                         // return the char
  335.     }
  336.     return(0);                              // return nothing
  337. }
  338.  
  339.  
  340. void Asynch::aputch(char ch)
  341. // Inserts the character to be outputted into output buffer.  If there is
  342. // an open slot in the output buffer array, insert character there, or
  343. // wait for a slot to open.
  344. // This output character function apparently ripped off of Rob Raper's
  345. // buffered NEWCOM routines for the WWIV bulletin board software.
  346. // Original credit goes to him.
  347. {
  348.     if (ch)                         // If this is a valid char
  349.     {
  350.         enable();                   // turn on irqs to ensure data output
  351.  
  352.         // check buffer, and if full, wait for an available opening
  353.         while((_ainfo.outhead-1==_ainfo.outtail) ||
  354.               (_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
  355.             ;
  356.         disable();  // make sure nothing happens while changing buffer
  357.         _ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
  358.         if (_ainfo.outtail == OBUF_LEN)     // if at end of out buffer
  359.             _ainfo.outtail = 0;             // reset pointer
  360.         enable();                           // re-enable interrupts
  361.         outportb(_ainfo.base+DTR,0x0f);
  362.     }
  363. }
  364.  
  365.  
  366. void Asynch::aputs(char *str)
  367. // Outputs a string through the serial port
  368. {
  369.     while (*str)
  370.     {
  371.         if (*str=='\n')
  372.             aputch('\r'), aputch('\n');
  373.         else
  374.             aputch(*str);
  375.         str++;
  376.     }
  377. }
  378.  
  379.  
  380. void Asynch::aprintf(char *format, ...)
  381. // Outputs a formatted string through the serial port
  382. {
  383.     #define MAXLEN 256
  384.     va_list argptr;
  385.     char str[256];
  386.  
  387.     va_start(argptr,format);            // access argument list
  388.     vsprintf(str,format,argptr);        // create string using argument list
  389.     va_end(argptr);                     // end access of argument list
  390.  
  391.     aputs(str);                         // output the formatted string
  392. }
  393.