home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / diverses / tctnt / serial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-27  |  9.2 KB  |  375 lines

  1. /* SERIAL.C: An interrupt driven serial port buffer
  2.  
  3.             The following code shows how to take advantage of some of
  4.             the Turbo C extensions to the C language to do asynchronous
  5.             communications without having to write supporting assembly-
  6.             language routines.
  7.  
  8.             This program bypasses the less-than-adequate PC BIOS
  9.             communications routines and installs a serial interrupt
  10.             handler. Direct access to PC hardware allows the program to
  11.             run at faster baud rates and eliminates the need for
  12.             the main program to continuously poll the serial port for
  13.             data; thus implementing background communications. Data that
  14.             enters the serial port is stored in a circular buffer.
  15.  
  16.             * Compile this program with Test Stack Overflow OFF.
  17. */
  18.  
  19. #include <dos.h>
  20. #include <conio.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include "serial.h"
  24.  
  25. #define VERSION 0x0101
  26.  
  27. #define FALSE           0
  28. #define TRUE           (!FALSE)
  29.  
  30. #define NOERROR         0       // No error
  31. #define BUFOVFL         1       // Buffer overflowed
  32.  
  33. #define ESC             0x1B    // ASCII Escape character
  34. #define ASCII           0x007F  // Mask ASCII characters
  35. #define SBUFSIZ         0x4000  // Serial buffer size
  36.  
  37. int            SError          = NOERROR;
  38. int            portbase        = 0;
  39.  
  40. // A user defined type for use with getvect() & setvect()
  41. typedef void interrupt far (*intvect)(...);
  42.  
  43. intvect              oldvects[2];
  44.  
  45. static   char  ccbuf[SBUFSIZ];
  46. unsigned int   startbuf        = 0;
  47. unsigned int   endbuf          = 0;
  48.  
  49. /*-------------------------------------------------------------------
  50.      com_int - Handle communications interrupts and put them in ccbuf
  51. */
  52.  
  53. void interrupt com_int(void) {
  54.     disable();
  55.     if ((inportb(portbase + IIR) & RX_MASK) == RX_ID) {
  56.         if (((endbuf + 1) & SBUFSIZ - 1) == startbuf)
  57.             SError = BUFOVFL;
  58.  
  59.             ccbuf[endbuf++] = inportb(portbase + RXR);
  60.             endbuf &= SBUFSIZ - 1;
  61.     }
  62.  
  63.     // Signal end of hardware interrupt
  64.     outportb(ICR, EOI);
  65.     enable();
  66. } // end of com_int()
  67.  
  68. /*-------------------------------------------------------------------
  69.     SerialOut - Output a character to the serial port
  70. */
  71.  
  72. int SerialOut(char x) {
  73.     long int timeout = 0x0000FFFFL;
  74.  
  75.     outportb(portbase + MCR,  MC_INT | DTR | RTS);
  76.  
  77.     // Wait for Clear To Send from modem
  78.     while ((inportb(portbase + MSR) & CTS) == 0)
  79.         if (!(--timeout))
  80.             return (-1);
  81.  
  82.         timeout = 0x0000FFFFL;
  83.  
  84.         // Wait for transmitter to clear
  85.         while ((inportb(portbase + LSR) & XMTRDY) == 0)
  86.             if (!(--timeout))
  87.                 return (-1);
  88.  
  89.         disable();
  90.         outportb(portbase + TXR, x);
  91.         enable();
  92.  
  93.         return (0);
  94. } // end of serialOut()
  95.  
  96. /*-------------------------------------------------------------------
  97.      SerialString - Output a string to the serial port
  98. */
  99.  
  100. void SerialString(char *string) {
  101.     while (*string)
  102.         SerialOut(*string++);
  103. } // end of SerailString()
  104.  
  105. /*-------------------------------------------------------------------
  106.      getccb - This routine returns the current value in the buffer
  107. */
  108.  
  109. int getccb(void) {
  110.     int res;
  111.  
  112.     if (endbuf == startbuf)
  113.         return (-1);
  114.  
  115.     res = (int) ccbuf[startbuf++];
  116.     startbuf %= SBUFSIZ;
  117.     return (res);
  118. } // end of getccb()
  119.  
  120. /*-------------------------------------------------------------------
  121.      setvects - Install our functions to handle communications
  122. */
  123.  
  124. void setvects(void) {
  125.     oldvects[0] = (intvect) getvect(0x0B);
  126.     oldvects[1] = (intvect) getvect(0x0C);
  127.     setvect(0x0B, (intvect)com_int);
  128.     setvect(0x0C, (intvect)com_int);
  129. } // end of setvects()
  130.  
  131. /*-------------------------------------------------------------------
  132.      resvects - Uninstall our vectors before exiting the program
  133. */
  134.  
  135. void resvects(void) {
  136.     setvect(0x0B, (intvect)oldvects[0]);
  137.     setvect(0x0C, (intvect)oldvects[1]);
  138. } // end of resvects()
  139.  
  140. /*-------------------------------------------------------------------
  141.      i_enable - Turn on communications interrupts
  142. */
  143.  
  144. void i_enable(int pnum) {
  145.     int c;
  146.  
  147.     disable();
  148.     c = inportb(portbase + MCR) | MC_INT;
  149.     outportb(portbase + MCR, c);
  150.     outportb(portbase + IER, RX_INT);
  151.     c = inportb(IMR) & (pnum == COM1 ? IRQ4 : IRQ3);
  152.     outportb(IMR, c);
  153.     enable();
  154. } // end of i_enable()
  155.  
  156. /*-------------------------------------------------------------------
  157.         i_disable - Turn off communications interrupts
  158. */
  159.  
  160. void i_disable(void) {
  161.     int c;
  162.  
  163.     disable();
  164.     c = inportb(IMR) | ~IRQ3 | ~IRQ4;
  165.     outportb(IMR, c);
  166.     outportb(portbase + IER, 0);
  167.     c = inportb(portbase + MCR) & ~MC_INT;
  168.     outportb(portbase + MCR, c);
  169.     enable();
  170. } // end of i_disable()
  171.  
  172. /*-------------------------------------------------------------------
  173.      comm_on - Tell modem that we're ready to go
  174. */
  175.  
  176. void comm_on(void) {
  177.     int c, pnum;
  178.  
  179.     pnum = (portbase == COM1BASE ? COM1 : COM2);
  180.     i_enable(pnum);
  181.     c = inportb(portbase + MCR) | DTR | RTS;
  182.     outportb(portbase + MCR, c);
  183. } // end of comm_on()
  184.  
  185. /*-------------------------------------------------------------------
  186.      comm_off - Go off-line
  187. */
  188.  
  189. void comm_off(void) {
  190.     i_disable();
  191.     outportb(portbase + MCR, 0);
  192. } // end of comm_off()
  193.  
  194. /*-------------------------------------------------------------------
  195.      initserial -
  196. */
  197.  
  198. void initserial(void) {
  199.     endbuf = startbuf = 0;
  200.     setvects();
  201.     comm_on();
  202. } // end of initserial()
  203.  
  204. /*-------------------------------------------------------------------
  205.      closeserial -
  206. */
  207.  
  208. void closeserial(void) {
  209.     comm_off();
  210.     resvects();
  211. } // end of closerial()
  212.  
  213. /*-------------------------------------------------------------------
  214.      SetPort - Set the port number to use
  215. */
  216.  
  217. int SetPort(int Port) {
  218.     int Offset, far *RS232_Addr;
  219.  
  220.     switch (Port) { // Sort out the base address
  221.         case COM1 : Offset = 0x0000;
  222.                                 break;
  223.         case COM2 : Offset = 0x0002;
  224.                                 break;
  225.         default   : return (-1);
  226.     }
  227.  
  228.     // Find out where the port is.
  229.     RS232_Addr = (int far*) MK_FP(0x0040, Offset);
  230.     if (*RS232_Addr == NULL)
  231.         return (-1);                                             // If NULL then port not used.
  232.     portbase = *RS232_Addr;              // Otherwise set portbase
  233.  
  234.     return (0);
  235. } // end of SetPort()
  236.  
  237. /*-------------------------------------------------------------------
  238.      SetSpeed - This routine sets the speed; will accept funny baud
  239.                             rates. Setting the speed requires that the DLAB be set
  240.                             on.
  241. */
  242.  
  243. int SetSpeed(int Speed) {
  244.     char c;
  245.     int divisor;
  246.  
  247.     if (Speed == 0)            // Avoid divide by zero
  248.         return (-1);
  249.     else
  250.         divisor = (int) (115200L/Speed);
  251.  
  252.     if (portbase == 0)
  253.         return (-1);
  254.  
  255.     disable();
  256.     c = inportb(portbase + LCR);
  257.     outportb(portbase + LCR, (c | 0x80)); // Set DLAB
  258.     outportb(portbase + DLL, (divisor & 0x00FF));
  259.     outportb(portbase + DLH, ((divisor >> 8) & 0x00FF));
  260.     outportb(portbase + LCR, c);          // Reset DLAB
  261.     enable();
  262.     return (0);
  263. } // end of SetSpeed()
  264.  
  265. /*-------------------------------------------------------------------
  266.      SetOthers - Set other communications parameters
  267. */
  268.  
  269. int SetOthers(int Parity, int Bits, int StopBit) {
  270.     int setting;
  271.  
  272.     if (portbase == 0)
  273.         return (-1);
  274.     if (Bits < 5 || Bits > 8)
  275.         return (-1);
  276.     if (StopBit != 1 && StopBit != 2)
  277.         return (-1);
  278.     if (Parity != NO_PARITY && Parity != ODD_PARITY && Parity != EVEN_PARITY)
  279.         return (-1);
  280.  
  281.     setting = Bits-5;
  282.     setting |= ((StopBit == 1) ? 0x00 : 0x04);
  283.     setting |= Parity;
  284.  
  285.     disable();
  286.     outportb(portbase + LCR, setting);
  287.     enable();
  288.     return (0);
  289. } // end of SetOthers()
  290.  
  291. /*-------------------------------------------------------------------
  292.      SetSerial - Set up the port
  293. */
  294.  
  295. int SetSerial(int Port, int Speed, int Parity, int Bits, int StopBit) {
  296.     if (SetPort(Port))                    return (-1);
  297.     if (SetSpeed(Speed))                  return (-1);
  298.     if (SetOthers(Parity, Bits, StopBit)) return (-1);
  299.     return 0;
  300. } // end of SetSerial()
  301.  
  302. /*
  303.      c_break - Control-Break interrupt handler
  304. */
  305.  
  306. int c_break(void) {
  307.     i_disable();
  308.     fprintf(stderr, "\nStill online.\n");
  309.     return 0;
  310. } // end of c_bresk()
  311.  
  312. //*******************************************************************
  313. main()
  314. {
  315.     // Communications parameters
  316.     int        port     = COM1;
  317.     int        speed    = 1200;
  318.     int        parity   = NO_PARITY;
  319.     int        bits     = 7;
  320.     int        stopbits = 1;
  321.  
  322.     int        c, done  = FALSE;
  323.  
  324.     if (SetSerial(port, speed, parity, bits, stopbits) != 0) {
  325.         fprintf(stderr, "Serial Port setup error.\n");
  326.         return (99);
  327.     }
  328.  
  329.     initserial();
  330.     ctrlbrk(c_break);
  331.  
  332.     fprintf(stdout, "TURBO C TERMINAL\n"
  333.                                     "...You're now in terminal mode, "
  334.                                     "press [ESC] to quit...\n\n");
  335.  
  336.     /* The main loop acts as a dumb terminal. We repeatedly
  337.          check the keyboard buffer, and communications buffer. */
  338.     do {
  339.         if (kbhit()) {
  340.             // Look for an Escape key
  341.             switch (c=getch()) {
  342.                 case ESC:
  343.                     done = TRUE;  // Exit program
  344.                     break;
  345.  
  346.                     //* You may want to handle other keys here...
  347.             }
  348.  
  349.             if (!done)
  350.                 SerialOut(c);
  351.         }
  352.         if ((c=getccb()) != -1)
  353.             fputc(c & ASCII, stdout);
  354.  
  355.     } while (!done && !SError);
  356.  
  357.     // Check for errors
  358.     switch (SError) {
  359.         case NOERROR:
  360.             fprintf(stderr, "\nbye.\n");
  361.             closeserial();
  362.             return 0;
  363.  
  364.         case BUFOVFL:
  365.             fprintf(stderr, "\nBuffer Overflow.\n");
  366.             closeserial();
  367.             return (99);
  368.  
  369.         default:
  370.             fprintf(stderr, "\nUnknown Error, SError = %d\n", SError);
  371.             closeserial();
  372.          return (99);
  373.     }
  374. } // end of main()
  375.