home *** CD-ROM | disk | FTP | other *** search
/ Hall of Fame / HallofFameCDROM.cdr / proglc / serialm5.lzh / SERIAL.C < prev    next >
Text File  |  1989-03-07  |  8KB  |  334 lines

  1. /*
  2.         S E R I A L . C
  3.  
  4.         Copyright (c) 1988, 1989 by Oklahoma Software Systems
  5.  
  6.         This code was written to allow a good set of interrupt driven
  7.         serial routines to be available for Microsoft C 5.x under MS/PC-DOS
  8.         3.x or higher.  These routines are nothing fancy; but they will
  9.         support X and Ymodem transfer algorithms (I have them here) using
  10.         either Checksum or CRC-16 error-checking.
  11.  
  12.         If you have any questions you can contact me via EchoMAIL at 147/30
  13.         where I operate as a Point-mail system.
  14.  
  15.         Ron Merts
  16.  
  17.  
  18. */
  19.  
  20. #include        "serial.h"
  21. #include        <dos.h>
  22. #include        <stdio.h>
  23. #include        <conio.h>
  24. #include        <bios.h>
  25. #include        <process.h>
  26.  
  27. int SError;
  28. int portbase=0;
  29. void (interrupt far *oldvects[3])();
  30. char ccbuf[SBUFSIZ];
  31. int startbuf=0;
  32. int endbuf=0;
  33.  
  34. /*      this does the hard work (handling interrupts)           */
  35.  
  36. void far interrupt com_int (void)
  37.  
  38. {
  39.     _disable ();
  40.     if ((inp (portbase+IIR) & RX_MASK)==RX_ID) {
  41.         if (((endbuf+1) & 0x1fff)==startbuf)
  42.             SError=BUFOVFL;
  43.         ccbuf[endbuf++]=inp (portbase+RX);
  44.         endbuf&=0x1fff;
  45.         };
  46.     outp (ICR,EOI);
  47.     _enable ();
  48. }
  49.  
  50. /* this routine returns the currently value in the buffer */
  51.  
  52. int getccb(void)
  53.  
  54. {
  55.     int res;
  56.     if (endbuf==startbuf) return (-1);
  57.     res=(int) ccbuf[startbuf];
  58.     startbuf=(startbuf+1) % SBUFSIZ;
  59.     return (res);
  60. }
  61.  
  62. void setvects (void)
  63.  
  64. {
  65.     oldvects[0]= _dos_getvect(0x0b);
  66.     oldvects[1]=  _dos_getvect(0x0c);
  67.     _dos_setvect(0x0b,com_int);
  68.     _dos_setvect(0x0c,com_int);
  69. }
  70.  
  71. void resvects (void)
  72.  
  73. {
  74.     _dos_setvect(0x0b,oldvects[0]);
  75.     _dos_setvect(0x0c,oldvects[1]);
  76. }
  77.  
  78. void i_enable (int pnum)
  79.  
  80. {
  81.     int c;
  82.     _disable();
  83.     c = inp (portbase+MCR) | MC_INT;
  84.     outp (portbase+MCR,c);
  85.     outp (portbase+IER,RX_INT);
  86.     c = inp (IMR) & (pnum==2 ? IRQ3 : IRQ4);
  87.     outp (IMR,c);
  88.     _enable();
  89. }
  90.  
  91. void i_disable (void)
  92.  
  93. {
  94.     int c;
  95.     _disable ();
  96.     c=inp (IMR) | ~IRQ3 | ~IRQ4;
  97.     outp (IMR,c);
  98.     outp (portbase + IER,0);
  99.     c=inp (portbase+MCR) & ~MC_INT;
  100.     outp (portbase+MCR,c);
  101.     _enable ();
  102. }
  103.  
  104. void comon (void)
  105.  
  106. {
  107.     int c,pnum;
  108.     pnum = portbase == COM1BASE ? 1 : 2;
  109.     i_enable (pnum);
  110.     c=inp (portbase + MCR) | DTR | RTS;
  111.     outp (portbase + MCR,c);
  112. }
  113.  
  114. void initserial (void)
  115.  
  116. {
  117.     endbuf=startbuf=0;
  118.     setvects();
  119.     comon();
  120. };
  121.  
  122. void comoff (void)
  123.  
  124. {
  125.     i_disable ();
  126.     outp (portbase+MCR,0);
  127. }
  128.  
  129. void closeserial(void)
  130.  
  131. {
  132.     comoff();
  133.     resvects();
  134. };
  135.  
  136. /* this outputs a serial character              */
  137.  
  138. int SerialOut (char x)
  139.  
  140. {
  141.     long timeout = 0x0000ffff;
  142.     outp (portbase+MCR,OUT2|DTR|RTS);
  143.  
  144.     /* wait for clear to send     */
  145.     while ((inp(portbase + MSR) & CTS)==0)
  146.         if ((--timeout)==0) return (-1);
  147.     timeout=0x0000ffff;
  148.  
  149.     /* wait for outport register to clear         */
  150.     while ((inp(portbase+LSR) & DSR)==0)
  151.         if ((--timeout)==0) return (-1);
  152.             _disable ();
  153.     outp (portbase+TX,x);
  154.     _enable ();
  155.     return (0);
  156. }
  157.  
  158. /* this routine sets which port we are working with     */
  159.  
  160. int SetPort (int Port)
  161.  
  162. {
  163.     char far * RS232_Addr;
  164.     int Offset;
  165.  
  166.     switch (Port) {                      /* sort out the base address    */
  167.         case 1 :
  168.              Offset=0x0000;
  169.              break;                         /* only ports one & two allowed */
  170.          case 2 :
  171.              Offset=0x0002;
  172.              break;
  173.          default :
  174.              return (-1);
  175.          };
  176.     FP_OFF(RS232_Addr) = Offset;          /* find out where the port is   */
  177.     FP_SEG(RS232_Addr) = 0x0040;
  178.     if (*RS232_Addr==0)
  179.         return (-1);      /* if it ain't there return (-1)*/
  180.     switch (Port) {
  181.         case 1:
  182.             portbase=0x03F8;
  183.             break;
  184.         case 2:
  185.             portbase=0x02F8;
  186.             break;
  187.         };
  188.     return (0);
  189. }
  190.  
  191. /* this routine sets the speed; will accept funny baud rates   */
  192.  
  193. int SetSpeed (int Speed)
  194.  
  195. {
  196.     char c;
  197.     int divisor;
  198.     if (Speed==0)
  199.         return (-1);            /* avoid divide by zero */
  200.     else
  201.         divisor=(int)(115200L/Speed);
  202.     if (portbase==0)
  203.         return (-11);
  204.     _disable ();
  205.     c=inp (portbase+LCR);
  206.     outp (portbase+LCR,(c|0x80));                     /* set DLAB     */
  207.     outp (portbase+DLL,(divisor & 0x00ff));   /* set divisor  */
  208.     outp (portbase+DLH,((divisor>>8)&0x00ff));
  209.     outp (portbase+LCR,c);
  210.     _enable();
  211.     return (0);
  212. }
  213.  
  214. /*      This routine set the LCR                */
  215.  
  216. int SetOthers (int Parity,int Bits,int StopBit)
  217.  
  218. {
  219.     int temp;
  220.     if (portbase==0)
  221.         return (-1);
  222.     if ((Parity<NO_PAR) || (Parity>OD_PAR))
  223.         return (-1);
  224.     if ((Bits<5) || (Bits>8))
  225.         return (-1);
  226.     if ((StopBit<1) || (StopBit>2))
  227.         return (-1);
  228.     temp=Bits-5;
  229.     temp|=((StopBit==1) ? 0x00 : 0x04);
  230.     switch (Parity) {
  231.         case NO_PAR:
  232.             temp |= 0x00;
  233.             break;
  234.         case OD_PAR:
  235.             temp |= 0x08;
  236.             break;
  237.         case EV_PAR:
  238.             temp |= 0x18;
  239.             break;
  240.         }
  241.     _disable();            /* turn off interrupts */
  242.     outp (portbase+LCR,temp);
  243.     _enable();             /* turn em back on */
  244.     return (0);
  245. }
  246.  
  247. /*      This routine sets the ports                     */
  248.  
  249. int setserial (int Port,int Speed,int Parity,int Bits,int StopBit)
  250.  
  251. {
  252.     if (SetPort(Port)==-1)
  253.         return(-1);
  254.     if (SetSpeed(Speed)==-1)
  255.         return(-1);
  256.     if (SetOthers(Parity,Bits,StopBit)==-1)
  257.         return(-1);
  258.     return(0);
  259. }
  260.  
  261. /*      This routine check for Carrier Detect,
  262.           returns 1 if CD present or
  263.           returns 0 if CD not present
  264. */
  265.  
  266. int checkCD()
  267. {
  268.     int c;
  269.     _disable();    /* disable Interrupts */
  270.     c = inp(portbase+MSR) & CD;
  271.     if (c == 128)
  272.         c = 1;
  273.     _enable();     /* Enable Interrupts again */
  274.     return(c);
  275. }
  276.  
  277.  
  278.  
  279. /* short demo                                           */
  280. /* this opens the ports and echos to screen until       */
  281. /* Ctrl-Z received                                      */
  282.  
  283. main (argc, argv)
  284. int argc;
  285. char **argv;
  286.  
  287. {
  288.     int c, c_m, bd_rate, com_port_num;
  289.  
  290.     if (argc != 3) {
  291.         printf("USAGE:  serial <1 | 2> <Baud-rate>\n\n\n");
  292.         printf("serial 2 2400    - Sets COM2 to 2400 Baud\n");
  293.         printf("serial 1 1200    - Sets COM1 to 1200 Baud\n");
  294.         exit(1);
  295.         }
  296.     com_port_num = atoi(argv[1]);
  297.     if (com_port_num != 1 && com_port_num != 2) {
  298.         printf("Give me a break, 1 or 2 only please!\n\n");
  299.         exit(1);
  300.         }
  301.     bd_rate = atoi(argv[2]);
  302.     switch (bd_rate) {
  303.         case  300:
  304.         case 1200:
  305.         case 2400:
  306.         case 4800:
  307.         case 9600:
  308.             break;
  309.         default:
  310.             printf("Are you trying to be difficult????\n");
  311.             printf(" Valid baud rates are 300,1200,2400,4800 and 9600\n\n");
  312.             exit(1);
  313.         }
  314.     if (setserial (com_port_num,bd_rate,NO_PAR,8,1) ==-1)
  315.         exit(1);
  316.     initserial();
  317.     printf("You're now in terminal mode.  Press ESC to quit the program.\n\n");
  318.  
  319.     do {
  320.         if (kbhit()) {         /* Check local keyboard */
  321.             c = getch();       /* If we got something */
  322.             if (c==27)
  323.                 break;
  324.             SerialOut(c);      /* Send it to the COM port */
  325.             }
  326.  
  327.         if ((c_m=getccb())!=-1)  /* Check the COM port, -1 means nothing there */
  328.             putchar (c_m);       /* If we got something, print it */
  329.  
  330.         } while (c!=27);
  331.  
  332.     closeserial();
  333. }
  334.