home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / hf / dsp / source / serial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-31  |  4.2 KB  |  206 lines

  1. /*  SERIAL.C -- IBM Serial Port handler (with interrupts)
  2.  *
  3.  *  Copyright (C) 1989,1990,1991 by Alef Null. All rights reserved.
  4.  *  Author(s): J Vuori, E Torsti
  5.  *  Modification(s):
  6.  *    1989-Sep: COM1, COM2 and baud rate selection with
  7.  *          OpenSerial(int port, int baud)
  8.  *    1991-Apr: DTR line control function added
  9.  */
  10.  
  11.  
  12. #define BUFLEN    2048    // buffer lenght
  13.  
  14.  
  15. #include <dos.h>
  16. #include <conio.h>
  17. #include <stdlib.h>
  18. #include <malloc.h>
  19. #include "serial.h"
  20.  
  21.  
  22. /* ring buffer definitions */
  23. #define NEXT(p) if (++(p) >= &buffer[BUFLEN]) (p) = buffer
  24. static volatile unsigned char *head, *tail;
  25. static        unsigned char *buffer;
  26.  
  27.  
  28. /* i/o-port definitions */
  29. #define PIC_MASK  0x21    // 8259 mask register
  30. #define PIC_EOI   0x20    // 8259 EOI command
  31. static const struct {
  32.     int data,        // 8250 data register
  33.     ier,        //    interrupt enable register
  34.     lcr,        //    line control register
  35.     mcr,        //    modem control register
  36.     stat;        //    status register
  37.     int intno;        // interrupt number
  38.     int mask;        // PIC mask
  39. } *comport, comports[2] = {
  40.     /* COM1 */
  41.     0x3f8, 0x3f9, 0x3fb, 0x3fc, 0x3fd,
  42.     0x0c,
  43.     0x10,
  44.  
  45.     /* COM2 */
  46.     0x2f8, 0x2f9, 0x2fb, 0x2fc, 0x2fd,
  47.     0x0b,
  48.     0x08,
  49. };
  50.  
  51.  
  52. /* store for old interrupt vector */
  53. static void (interrupt far cdecl *OldHandler)(void);
  54.  
  55. #pragma intrinsic(inp, outp)    // produces more beautiful code with this
  56.  
  57. /*
  58.  * 8250 UART Interrupt server routine
  59.  */
  60. #pragma check_stack(off)    // because stack check is not allowed in interrupt service routine
  61. static void cdecl interrupt far ReadChr(void) {
  62.     *head = (unsigned char)inp(comport->data);
  63.     NEXT(head);
  64.  
  65.     outp(PIC_EOI, 0x20);
  66. }
  67. #pragma check_stack()
  68.  
  69. /*
  70.  * Initializes serial communication
  71.  *
  72.  * enter with:
  73.  *  port - 1 = COM1, 2 = COM2
  74.  *
  75.  * returns:
  76.  *  NULL if failed
  77.  */
  78. int OpenSerial(int port, int baud) {
  79.     comport = &comports[port-1];
  80.  
  81.     /* allocate receiving buffer */
  82.     if (buffer = (unsigned char *)malloc(BUFLEN)) {
  83.     /* reset buffer */
  84.     head = tail = buffer;
  85.  
  86.     /* set interrupt vector */
  87.     OldHandler = _dos_getvect(comport->intno);
  88.     _dos_setvect(comport->intno, ReadChr);
  89.  
  90.     /* set 8250 UART chip */
  91.     SetBaudRate(baud);
  92.     SetDTR(0);
  93.     outp(comport->ier, 0x01);            // enable rec interrupt
  94.  
  95.     inp(comport->data);                // make UART happy
  96.  
  97.     /* set 8259 PIC chip */
  98.     outp(PIC_MASK, inp(PIC_MASK) & ~comport->mask); // remove interrupt mask
  99.  
  100.     return(-1);
  101.     } else
  102.     return(0);
  103. }
  104.  
  105.  
  106. /*
  107.  * Terminates serial communication
  108.  */
  109. void CloseSerial(void) {
  110.     /* set 8259 PIC chip */
  111.     outp(PIC_MASK, inp(PIC_MASK) | comport->mask);  // set mask
  112.  
  113.     /* reset interrupt vector */
  114.     _dos_setvect(comport->intno, OldHandler);
  115.  
  116.     free(buffer);
  117. }
  118.  
  119.  
  120. /*
  121.  * Reads one character from serial port,
  122.  * returns -1 if there are no characters waiting
  123.  */
  124. int ReadSerial(void) {
  125.     register int c;
  126.  
  127.     if (head != tail) {
  128.     c = *tail;
  129.     NEXT(tail);
  130.     return(c);
  131.     } else
  132.     return(-1);
  133. }
  134.  
  135.  
  136. /*
  137.  * Writes one character to serial port
  138.  */
  139. int WriteSerial(int c) {
  140.     while(!(inp(comport->stat) & 0x20));    // wait TBE status
  141.  
  142.     return(outp(comport->data, c));
  143. }
  144.  
  145.  
  146. /*
  147.  * Controls DTR-line
  148.  */
  149. void SetDTR(int state) {
  150.     outp(comport->mcr, state ? 0x0f : 0x0e);
  151. }
  152.  
  153.  
  154. /*
  155.  * Controls baud rate
  156.  */
  157. void SetBaudRate(int baud) {
  158.     outp(comport->lcr, 0x83);
  159.     outp(comport->data, (12L*9600L/(long)baud) & 0xff);
  160.     outp(comport->ier,    (12L*9600L/(long)baud) >> 8);
  161.     outp(comport->lcr, 0x03);                // 8, n, 1
  162. }
  163.  
  164.  
  165. #if defined(DEBUG)
  166.     #include <stdio.h>
  167.     #include <signal.h>
  168.  
  169.     #define PORT    1
  170.     #define BAUD    9600
  171.  
  172.     /*
  173.      * CTRL-C handler
  174.      */
  175.     void handler(void) {
  176.     CloseSerial();
  177.     printf("disconnected\n");
  178.     exit(-1);
  179.     }
  180.  
  181.  
  182.     int main(void) {
  183.     int c;
  184.  
  185.     signal(SIGINT, handler);
  186.     if (!OpenSerial(PORT, BAUD)) {
  187.         fprintf(stderr, "Can't open serial port COM%d\n", PORT);
  188.         return(-1);
  189.     }
  190.  
  191.     printf("Simple serial port terminal [COM%1d, %4d] (%s)\n", PORT, BAUD, __DATE__);
  192.     printf("Press CTRL-C to exit\n\n");
  193.  
  194.     while (1) {
  195.         while ((c = ReadSerial()) == -1)
  196.         if (kbhit())
  197.             WriteSerial(getch());
  198.  
  199.         putchar(c & 0x7f);
  200.     }
  201.  
  202.     CloseSerial();
  203.     return(0);
  204.     }
  205. #endif
  206.