home *** CD-ROM | disk | FTP | other *** search
-
- /*------------------------------------------------------------------*
- SERIAL.CPP
-
- The following code shows how to take advantage of some of
- the Turbo C++ extensions to the C++ language to do asynchronous
- communications without having to write supporting assembly-
- language routines.
-
- This program bypasses the less-than-adequate PC BIOS
- communications routines and installs a serial interrupt
- handler. Direct access to PC hardware allows the program to
- run at faster baud rates and eliminates the need for
- the main program to continuously poll the serial port for
- data; thus implementing background communications. Data that
- enters the serial port is stored in a circular buffer.
-
- * Compile this program with Test Stack Overflow OFF.
-
- *------------------------------------------------------------------*/
-
- #include <dos.h>
- #include <conio.h>
- #include <stdio.h>
- #include <string.h>
- #include "serial.h"
-
- #define VERSION 0x0101
-
- #define FALSE 0
- #define TRUE (!FALSE)
-
- #define NOERROR 0 /* No error */
- #define BUFOVFL 1 /* Buffer overflowed */
-
- #define ESC 0x1B /* ASCII Escape character */
- #define ASCII 0x007F /* Mask ASCII characters */
- #define SBUFSIZ 0x4000 /* Serial buffer size */
-
- int SError = NOERROR;
- int portbase = 0;
- void interrupt(*oldvects[2])(...);
-
- static char ccbuf[SBUFSIZ];
- unsigned int startbuf = 0;
- unsigned int endbuf = 0;
-
-
- /* Handle communications interrupts and put them in ccbuf */
- void interrupt com_int(...)
- {
- disable();
- if ((inportb(portbase + IIR) & RX_MASK) == RX_ID)
- {
- if (((endbuf + 1) & SBUFSIZ - 1) == startbuf)
- SError = BUFOVFL;
-
- ccbuf[endbuf++] = inportb(portbase + RXR);
- endbuf &= SBUFSIZ - 1;
- }
-
- /* Signal end of hardware interrupt */
- outportb(ICR, EOI);
- enable();
- }
-
- /* Output a character to the serial port */
- serial& serial::operator<<( char x )
- {
- long int timeout = 0x0000FFFFL;
-
- outportb(portbase + MCR, MC_INT | DTR | RTS);
-
- /* Wait for Clear To Send from modem */
- while ((inportb(portbase + MSR) & CTS) == 0)
- if (!(--timeout))
- return *this;
-
- timeout = 0x0000FFFFL;
-
- /* Wait for transmitter to clear */
- while ((inportb(portbase + LSR) & XMTRDY) == 0)
- if (!(--timeout))
- return *this;
-
- disable();
- outportb(portbase + TXR, x);
- enable();
-
- return *this;
- }
-
- /* Output a string to the serial port */
- serial& serial::operator<<( char *string )
- {
- while (*string)
- {
- (*this) << *string;
- string++;
- }
- return *this;
- }
-
- /* This routine returns the current value in the buffer */
- serial &serial::operator>>( char &ch )
- {
- if (endbuf == startbuf)
- {
- ch = -1;
- return *this;
- }
-
- ch = ccbuf[startbuf];
- startbuf++;
- startbuf %= SBUFSIZ;
- return *this;
- }
-
- /* Install our functions to handle communications */
- void setvects(void)
- {
- oldvects[0] = getvect(0x0B);
- oldvects[1] = getvect(0x0C);
- setvect(0x0B, com_int);
- setvect(0x0C, com_int);
- }
-
- /* Uninstall our vectors before exiting the program */
- void resvects(void)
- {
- setvect(0x0B, oldvects[0]);
- setvect(0x0C, oldvects[1]);
- }
-
- /* Turn on communications interrupts */
- void i_enable(int pnum)
- {
- int c;
-
- disable();
- c = inportb(portbase + MCR) | MC_INT;
- outportb(portbase + MCR, c);
- outportb(portbase + IER, RX_INT);
- c = inportb(IMR) & (pnum == COM1 ? IRQ4 : IRQ3);
- outportb(IMR, c);
- enable();
- }
-
- /* Turn off communications interrupts */
- void i_disable(void)
- {
- int c;
-
- disable();
- c = inportb(IMR) | ~IRQ3 | ~IRQ4;
- outportb(IMR, c);
- outportb(portbase + IER, 0);
- c = inportb(portbase + MCR) & ~MC_INT;
- outportb(portbase + MCR, c);
- enable();
- }
-
- /* Tell modem that we're ready to go */
- void comm_on(void)
- {
- int c, pnum;
-
- pnum = (portbase == COM1BASE ? COM1 : COM2);
- i_enable(pnum);
- c = inportb(portbase + MCR) | DTR | RTS;
- outportb(portbase + MCR, c);
- }
-
- /* Go off-line */
- void serial::comm_off(void)
- {
- i_disable();
- outportb(portbase + MCR, 0);
- }
-
- void serial::init_serial(void)
- {
- endbuf = startbuf = 0;
- setvects();
- comm_on();
- }
-
- serial::~serial()
- {
- comm_off();
- resvects();
- }
-
- /* Set the port number to use */
- int serial::SetPort(int Port)
- {
- int Offset, far *RS232_Addr;
-
- switch (Port)
- { /* Sort out the base address */
- case COM1 : Offset = 0x0000;
- break;
- case COM2 : Offset = 0x0002;
- break;
- default : return (-1);
- }
-
- RS232_Addr = (int far *)MK_FP(0x0040, Offset); /* Find out where the port is. */
- if (*RS232_Addr == NULL) return (-1);/* If NULL then port not used. */
- portbase = *RS232_Addr; /* Otherwise set portbase */
-
- return (0);
- }
-
- /* This routine sets the speed; will accept funny baud rates. */
- /* Setting the speed requires that the DLAB be set on. */
- int serial::SetSpeed(int Speed)
- {
- char c;
- int divisor;
-
- if (Speed == 0) /* Avoid divide by zero */
- return (-1);
- else
- divisor = (int) (115200L/Speed);
-
- if (portbase == 0)
- return (-1);
-
- disable();
- c = inportb(portbase + LCR);
- outportb(portbase + LCR, (c | 0x80)); /* Set DLAB */
- outportb(portbase + DLL, (divisor & 0x00FF));
- outportb(portbase + DLH, ((divisor >> 8) & 0x00FF));
- outportb(portbase + LCR, c); /* Reset DLAB */
- enable();
-
- return (0);
- }
-
- /* Set other communications parameters */
- int serial::SetOthers(int Parity, int Bits, int StopBit)
- {
- int setting;
-
- if (portbase == 0) return (-1);
- if (Bits < 5 || Bits > 8) return (-1);
- if (StopBit != 1 && StopBit != 2) return (-1);
- if (Parity != NO_PARITY && Parity != ODD_PARITY && Parity != EVEN_PARITY)
- return (-1);
-
- setting = Bits-5;
- setting |= ((StopBit == 1) ? 0x00 : 0x04);
- setting |= Parity;
-
- disable();
- outportb(portbase + LCR, setting);
- enable();
-
- return (0);
- }
-
- /* Set up the port */
- serial::serial(int Port, int Speed, int Parity, int Bits, int StopBit)
- {
- flag = 0;
- if (SetPort(Port))
- flag = -1;
- if (SetSpeed(Speed))
- flag = -1;
- if (SetOthers(Parity, Bits, StopBit))
- flag = -1;
-
- if (!flag)
- init_serial();
- }
-
- /* Control-Break interrupt handler */
- int c_break(void)
- {
- i_disable();
- fprintf(stderr, "\nStill online.\n");
-
- return(0);
- }
-
- main()
- {
- /* Communications parameters */
- int port = COM2;
- int speed = 2400;
- int parity = NO_PARITY;
- int bits = 8;
- int stopbits = 1;
-
- int done = FALSE;
- char c;
-
- serial comport(port, speed, parity, bits, stopbits);
-
- ctrlbrk(c_break);
-
- fprintf(stdout, "TURBO C TERMINAL\n"
- "...You're now in terminal mode, "
- "press [ESC] to quit...\n\n");
-
- /*
- The main loop acts as a dumb terminal. We repeatedly
- check the keyboard buffer, and communications buffer.
- */
- do {
- if (kbhit())
- {
- /* Look for an Escape key */
- switch (c=getch())
- {
- case ESC: done = TRUE; /* Exit program */
- break;
-
- /* You may want to handle other keys here... */
- }
- if (!done)
- comport << c;
- }
- comport >> c;
- if (c != -1)
- fputc(c & ASCII, stdout);
-
- } while (!done && !SError);
-
- /* Check for errors */
- switch (SError)
- {
- case NOERROR: fprintf(stderr, "\nbye.\n");
- return (0);
-
- case BUFOVFL: fprintf(stderr, "\nBuffer Overflow.\n");
- return (99);
-
- default: fprintf(stderr, "\nUnknown Error, SError = %d\n",
- SError);
- return (99);
- }
- }
-
-
-