home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / c / cuj9301.zip / 1101057A < prev    next >
Text File  |  1992-11-09  |  6KB  |  240 lines

  1. #include <iostream.h>
  2. #include "tserial.h"
  3. #include <string.h>
  4. #include <dos.h>
  5. #include <bios.h>
  6. #include <conio.h>
  7.  
  8. // interrupt functions. 
  9. typedef void interrupt far intFunc(...);
  10.  
  11. // Programmed Interrupt Controller constants.
  12. const PIC0 = 0x20;
  13. const PIC1 = 0x21;
  14. const EOI = 0x20;
  15.  
  16. // Offsets from port address.
  17. const InterruptEnable = 1, 
  18.       InterruptIdent = 2,
  19.       ModemControl = 4,
  20.       LineStatus = 5,
  21.       ModemStatus = 6;
  22.       
  23. // Value for the modem control register.
  24. const ModemControlValue = 11;
  25.  
  26. // A serial port circular buffer class.  There
  27. // are only two instances of this class, one
  28. // for each port COM1, and COM2.  They are
  29. // static globals, and are initailized before
  30. // main().  They contain a circular buffer,
  31. // the port number and port address, and the
  32. // interrupt vector they replace, so that 
  33. // they can be restored at destruction.  This
  34. // is not a complete or robust class, and is
  35. // private to this module.  It is intended
  36. // only for use by SerialStream.
  37. class ComBuffer {
  38. public:
  39. // Size of circular buffer
  40.     enum { BufSize = 0x100 };
  41. // Default constructor.  
  42.     ComBuffer();
  43.     ~ComBuffer();
  44. // Set up vector, and enables interrupts
  45.     void hookInterrupt();
  46. // Get a single character from the buffer
  47.     int getc();
  48. // Send a single character to the port
  49.     void putc(int c);
  50. // Read the line status register.
  51.     int status() const
  52.     { 
  53.         return ::inp(portAddr+LineStatus); 
  54.     }
  55. // Check if characters are available
  56.     int avail() const
  57.     { 
  58.         return in != out; 
  59.     }
  60. // Receive a character from port.  This function
  61. // is called by the interrupt routine.
  62.     void receive();
  63. private:
  64. // The mask needed for setting the PIC.
  65.     int interruptMask(int port) const
  66.     { 
  67.         return 1 << (4 - port); 
  68.     }
  69. // The interrupt number for each port.
  70.     int interruptVec(int port) const
  71.     { 
  72.         return 12 - port; 
  73.     }
  74.     char *in, *out, *buff;    // The circular buffer
  75.     int port;            // The port number 0-1
  76.     int portAddr;        // The port address
  77.     intFunc *oldVector;        // The previos vector
  78.     static int initPort;    
  79. };
  80.  
  81. // initPort is used by the constructor to initialize
  82. // the ports in sequence.
  83. int ComBuffer::initPort = 0;
  84. // Only two ports are set up here.  If you add more
  85. // you need to identify the port addresses and 
  86. // interrupt vectors.
  87. static ComBuffer CommPorts[2];
  88.  
  89. // Initialize the buffers.  Allocate the circular
  90. // buffer, set the in/out pointers, set the port
  91. // and port address values, and clear the old
  92. // vector value.
  93. ComBuffer::ComBuffer()
  94.     : buff(new char[BufSize]), port(initPort++), 
  95.                oldVector(0)
  96. {
  97. // this line is for sceptics to see initializing.
  98.     cout << "initializing port #" << port << endl;
  99.     portAddr = port ? 0x2f8 : 0x3f8;
  100.     in = out = buff;
  101. }
  102.  
  103. // Delete the circular buffer.  If the old vector
  104. // is a valid address, restore it.
  105. ComBuffer::~ComBuffer()
  106. {
  107. // another line for sceptics.
  108.     cout << "de-initializing port #" << port << endl;
  109.     if(oldVector)
  110.         ::setvect(interruptVec(port),oldVector);
  111.     delete[] buff;
  112. }
  113.  
  114. // These two routines reset to PIC, and put
  115. // the new character in the buffer
  116. void interrupt far comInterrupt0(...)
  117. {
  118.     ::outp(PIC0,EOI);
  119.     CommPorts[0].receive();
  120. }
  121.  
  122. void interrupt far comInterrupt1(...)
  123. {
  124.     ::outp(PIC0,EOI);
  125.     CommPorts[1].receive();
  126. }
  127.  
  128. // This function sets up the interrupts, and
  129. // enables the PIC
  130. void
  131. ComBuffer::hookInterrupt()
  132. {
  133.     if(oldVector == 0)
  134.         oldVector = ::getvect(interruptVec(port));
  135.     switch(port)
  136.     {
  137.     case 0:
  138.         ::setvect(interruptVec(port),comInterrupt0);
  139.         break;
  140.     case 1:
  141.         ::setvect(interruptVec(port),comInterrupt1);
  142.         break;
  143.     default:
  144.         return;
  145.     }
  146.     ::outp(portAddr+ModemControl,
  147.       ::inp(portAddr+ModemControl)|ModemControlValue);
  148.     ::outp(PIC1,::inp(PIC1) & ~interruptMask(port)); 
  149.     ::outp(portAddr+InterruptEnable,1);
  150.     ::outp(PIC0, EOI);
  151.     ::inp(portAddr);
  152.     ::inp(portAddr+InterruptIdent);
  153.     ::inp(portAddr+ModemStatus);
  154.     status();            // clear status reg.
  155. }
  156.  
  157. // Receive a byte from the port and place in the 
  158. // circular buffer, called from the interrupt
  159. // handler.
  160. void
  161. ComBuffer::receive()
  162. {
  163.     if(in == buff + BufSize)
  164.         in = buff;        // circular buffer
  165.     *in++ = ::inp(portAddr);
  166. }
  167.  
  168. // Get a character from the circular buffer.
  169. int
  170. ComBuffer::getc()
  171. {
  172.     while(!avail())
  173.         if(::kbhit())
  174.            return -1;
  175.     if(out == buff + BufSize)
  176.         out = buff;        // circular buffer
  177.     return  *out++;
  178. }
  179.  
  180. // Send a character directly to the port
  181. void
  182. ComBuffer::putc(int c)
  183. {
  184.     while((status() & 0x20) == 0)
  185.         if(::kbhit())
  186.             return;
  187.     ::outp(portAddr, c);
  188. }
  189.  
  190. const default_init = _COM_1200|_COM_CHR8|
  191.                      _COM_STOP1|_COM_NOPARITY;
  192.  
  193. // The open function needs to translate the name
  194. // to the port number, initialize the port, and
  195. // enable interrupts.
  196. int SerialStream::open(const char *name, int, int)
  197. {
  198.     if(::stricmp(name,"COM1") == 0)
  199.         port = 0;
  200.     else if(::stricmp(name, "COM2") == 0)
  201.         port = 1;
  202.     else
  203.         return -1;
  204.     unsigned int stat = ::_bios_serialcom(
  205.                      _COM_INIT,port,default_init);
  206.     buffPtr = CommPorts+port;
  207.     buffPtr->hookInterrupt();
  208.     if(stat & 0xFF00)
  209.         return -1;
  210.     return 0;
  211. }
  212.  
  213. // The close routine sets the port number to -1
  214. // to indicate it's closed
  215. int
  216. SerialStream::close()
  217. {
  218.     port = -1;
  219.     return 0;
  220. }
  221.  
  222. // The read routine repeatedly calls ComBuffer::getc
  223. // to fill it's buffer.  len should always be 1.
  224. int SerialStream::read(char *b, size_t len)
  225. {
  226.     for(int i = 0; i < len; i++)
  227.         b[i] = buffPtr->getc();
  228.     return i;
  229. }
  230.  
  231. // The write routine repeatedly calls ComBuffer::putc
  232. // to empty it's buffer.  len should alway be 1.
  233. int SerialStream::write(char *b, size_t len)
  234. {
  235.     for(int i = 0; i < len; i++)
  236.         buffPtr->putc(b[i]);
  237.     return i;
  238. }
  239.  
  240.