home *** CD-ROM | disk | FTP | other *** search
/ BBS 1 / BBS#1.iso / for-dos / turboc.arj / SERIAL.C < prev    next >
C/C++ Source or Header  |  1991-08-20  |  8KB  |  332 lines

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