home *** CD-ROM | disk | FTP | other *** search
/ Boldly Go Collection / version40.iso / TS / 17A / DRWIN101.ZIP / SERUTIL.C < prev    next >
C/C++ Source or Header  |  1991-07-23  |  60KB  |  1,387 lines

  1. /****************************************************************************/
  2. /*  MODULE serutil.c                                                        */
  3. /****************************************************************************/
  4. /*-----------------------------Description----------------------------------*/
  5. /*  This module contains support files for use with RS232 serial port       */
  6. /*  communications.  Both reception and transmission are interrupt-driven,  */
  7. /*  so overhead is low.  All functions (accessible to the user) begin with  */
  8. /*  the three letters "ser".  The function prototypes are listed in the     */
  9. /*  file serutil.h, along with brief descriptions.                          */
  10. /*  An error code, sererr, is set whenever an error occurs (usually         */
  11. /*  indicated by a 0 or NULL return value from a serXXXX() function).       */
  12. /*-----------------------------Constraints/Gotchas--------------------------*/
  13. /*  These functions require the use of an 8251 or 8250B serial i/o chip.    */
  14. /*--Date--------Programmer----------Comments--------------------------------*/
  15. /*  1990.07.12  D. Rogers           initial code, version 1.00              */
  16. /****************************************************************************/
  17. #include <stdio.h>
  18. #include <dos.h>
  19. #include <ctype.h>
  20. #include <stdarg.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include "strutil.h"
  25. #include "bufutil.h"
  26. #include "serutil.h"
  27.  
  28.  
  29. void interrupt serint1(void);
  30. void interrupt serint2(void);
  31. void interrupt serint3(void);
  32. void interrupt serint4(void);
  33.  
  34. volatile PORT  serp[MAXPORTS]={
  35.   { COM1, NULL, NULL, serint1, NULL, SER_COM1INT, SER_COM1IMR },
  36.   { COM2, NULL, NULL, serint2, NULL, SER_COM2INT, SER_COM2IMR },
  37.   { COM3, NULL, NULL, serint3, NULL, SER_COM3INT, SER_COM3IMR },
  38.   { COM4, NULL, NULL, serint4, NULL, SER_COM4INT, SER_COM4IMR }
  39. };
  40. char  serstr[256];
  41. char *sercomstr[8]={ "COM1","COM2","COM3","COM4",NULL };
  42. int   sererr=SER_NONE;
  43. WORD  far *seriobase=(WORD far *)0x00000400;   /*pointer to COM port list*/
  44.  
  45.  
  46.  
  47. /****************************************************************************/
  48. /*  serintX                                                                 */
  49. /****************************************************************************/
  50. /*-----------------------------Description----------------------------------*/
  51. /*  The following functions are the interrupt drivers for each of the four  */
  52. /*  COM ports currently supported.                                          */
  53. /*-----------------------------Arguments------------------------------------*/
  54. /*-----------------------------Return value---------------------------------*/
  55. /*-----------------------------Global constants-----------------------------*/
  56. /*-------------------Mod-------Global variables-----------------------------*/
  57. /*-----------------------------Functions called-----------------------------*/
  58. /*-----------------------------Constraints/Gotchas--------------------------*/
  59. /*  Don't screw with these functions unless you know what you're doing.     */
  60. /*--Date--------Programmer----------Comments--------------------------------*/
  61. /*  1990.07.12  D. Rogers           initial code                            */
  62. /****************************************************************************/
  63. void interrupt serint1(void)
  64. {
  65.   static int c;
  66.   static int ityp;                     /*interrupt type -- RX or TX*/
  67.   static WORD iop;                     /*uart base port*/
  68.   static volatile PORT *p;             /*pointer to port record*/
  69.  
  70.   disable();                           /*turn off interrupts*/
  71.   iop=seriobase[COM1];                 /*uart chip base register i/o addr*/
  72.   p=&serp[COM1];                       /*our struct*/
  73.   ityp=inp(iop+SIO_IIR) & SIO_INTID;   /*get interrupt type*/
  74.   if (inp(iop+SIO_LSR) & SIO_DR) {     /*check data ready*/
  75.     c=inp(iop+SIO_RBR);                /*read data from rec buffer register*/
  76.     if (!bufputc(p->rx,c)) sererr=SER_RXOVER;   /*if full, note error*/
  77.   }
  78.   if (inp(iop+SIO_LSR) & SIO_THRE) {   /*check transmit holding register*/
  79.     if (!bufempty(p->tx))              /*if more chars to add..*/
  80.       outp(iop+SIO_THR,bufgetc(p->tx));  /*..add one*/
  81.   }
  82.   outp(IOP_PIC,0x20);                  /*tell PIC end of interrupt*/
  83.   enable();                            /*reinstate interrupts*/
  84. }   /*serint1*/
  85.  
  86.  
  87. void interrupt serint2(void)
  88. {
  89.   static int c;
  90.   static int ityp;                     /*interrupt type -- RX or TX*/
  91.   static WORD iop;                     /*uart base port*/
  92.   static volatile PORT *p;             /*pointer to port record*/
  93.  
  94.   disable();                           /*turn off interrupts*/
  95.   iop=seriobase[COM2];                 /*uart chip base register i/o addr*/
  96.   p=&serp[COM2];                       /*our struct*/
  97.   ityp=inp(iop+SIO_IIR) & SIO_INTID;   /*get interrupt type*/
  98.   if (inp(iop+SIO_LSR) & SIO_DR) {
  99.     c=inp(iop+SIO_RBR);
  100.     if (!bufputc(p->rx,c)) sererr=SER_RXOVER;
  101.   }
  102.   if (inp(iop+SIO_LSR) & SIO_THRE) {
  103.     if (!bufempty(p->tx))
  104.       outp(iop+SIO_THR,bufgetc(p->tx));
  105.   }
  106.   outp(IOP_PIC,0x20);                  /*tell PIC end of interrupt*/
  107.   enable();                            /*reinstate interrupts*/
  108. }   /*serint2*/
  109.  
  110.  
  111. void interrupt serint3(void)
  112. {
  113.   static int c;
  114.   static int ityp;                     /*interrupt type -- RX or TX*/
  115.   static WORD iop;                     /*uart base port*/
  116.   static volatile PORT *p;             /*pointer to port record*/
  117.  
  118.   disable();                           /*turn off interrupts*/
  119.   iop=seriobase[COM3];                 /*uart chip base register i/o addr*/
  120.   p=&serp[COM3];                       /*our struct*/
  121.   ityp=inp(iop+SIO_IIR) & SIO_INTID;   /*get interrupt type*/
  122.   if (inp(iop+SIO_LSR) & SIO_DR) {
  123.     c=inp(iop+SIO_RBR);
  124.     if (!bufputc(p->rx,c)) sererr=SER_RXOVER;
  125.   }
  126.   if (inp(iop+SIO_LSR) & SIO_THRE) {
  127.     if (!bufempty(p->tx))
  128.       outp(iop+SIO_THR,bufgetc(p->tx));
  129.   }
  130.   outp(IOP_PIC,0x20);                  /*tell PIC end of interrupt*/
  131.   enable();                            /*reinstate interrupts*/
  132. }   /*serint3*/
  133.  
  134.  
  135. void interrupt serint4(void)
  136. {
  137.   static int c;
  138.   static int ityp;                     /*interrupt type -- RX or TX*/
  139.   static WORD iop;                     /*uart base port*/
  140.   static volatile PORT *p;             /*pointer to port record*/
  141.  
  142.   disable();                           /*turn off interrupts*/
  143.   iop=seriobase[COM4];                 /*uart chip base register i/o addr*/
  144.   p=&serp[COM4];                       /*our struct*/
  145.   ityp=inp(iop+SIO_IIR) & SIO_INTID;   /*get interrupt type*/
  146.   if (inp(iop+SIO_LSR) & SIO_DR) {
  147.     c=inp(iop+SIO_RBR);
  148.     if (!bufputc(p->rx,c)) sererr=SER_RXOVER;
  149.   }
  150.   if (inp(iop+SIO_LSR) & SIO_THRE) {
  151.     if (!bufempty(p->tx))
  152.       outp(iop+SIO_THR,bufgetc(p->tx));
  153.   }
  154.   outp(IOP_PIC,0x20);                  /*tell PIC end of interrupt*/
  155.   enable();                            /*reinstate interrupts*/
  156. }   /*serint4*/
  157.  
  158.  
  159. /****************************************************************************/
  160. /*  serbad                                                                  */
  161. /****************************************************************************/
  162. /*-----------------------------Description----------------------------------*/
  163. /*  This function does a quick check of the PORT pointer parameter to see   */
  164. /*  if it really points to a PORT structure.  It sets sererr on error.      */
  165. /*-----------------------------Arguments------------------------------------*/
  166. /*  PORT *p            pointer to check                                     */
  167. /*-----------------------------Return value---------------------------------*/
  168. /*  1 if the pointer was bad, 0 if it seemed ok.                            */
  169. /*-----------------------------Global constants-----------------------------*/
  170. /*-------------------Mod-------Global variables-----------------------------*/
  171. /*-----------------------------Functions called-----------------------------*/
  172. /*-----------------------------Constraints/Gotchas--------------------------*/
  173. /*--Date--------Programmer----------Comments--------------------------------*/
  174. /*  1990.07.12  D. Rogers           initial code                            */
  175. /****************************************************************************/
  176. int  serbad(PORT *p)
  177. {
  178.   if (p==NULL) return sererr=SER_BADPORT;
  179.   if (p->rx==NULL) return sererr=SER_UNINIT;
  180.   if (p->com>=MAXPORTS) return sererr=SER_BADCOM;
  181.   return sererr=0;
  182. }   /*serbad*/
  183.  
  184.  
  185. /****************************************************************************/
  186. /*  setdtr, setrts, setbrk                                                  */
  187. /****************************************************************************/
  188. /*-----------------------------Description----------------------------------*/
  189. /*  These functions set the RS232 control lines for the given COM port.     */
  190. /*  If the value passed is 0, the RS232 control line is reset (logical 0),  */
  191. /*  but if the value passed is nonzero, the RS232 line is set to an active  */
  192. /*  state.  Note that these are logic levels, and not voltages, since some  */
  193. /*  active levels are at lower voltages.                                    */
  194. /*  The output lines are Data Terminal Ready (setdtr()), Request To Send    */
  195. /*  (setrts()) and Break (setbrk()).                                        */
  196. /*-----------------------------Arguments------------------------------------*/
  197. /*  WORD p             COM port (NOT a PORT pointer), 0=COM1, 1=COM2, etc.  */
  198. /*  int  <val>         value, 0=inactive, nonzero=active                    */
  199. /*-----------------------------Return value---------------------------------*/
  200. /*-----------------------------Global constants-----------------------------*/
  201. /*-------------------Mod-------Global variables-----------------------------*/
  202. /*-----------------------------Functions called-----------------------------*/
  203. /*-----------------------------Constraints/Gotchas--------------------------*/
  204. /*  These are low-level routines, which do NOT take PORT* arguments.  For   */
  205. /*  normal use, use the corresponding sersetXXX() functions.                */
  206. /*--Date--------Programmer----------Comments--------------------------------*/
  207. /*  1990.07.12  D. Rogers           initial code                            */
  208. /****************************************************************************/
  209. int  setdtr(WORD p,int dtr)
  210. {
  211.   p=seriobase[p];
  212.   if (!p) return 0;
  213.   if (dtr)
  214.     outp(p+SIO_MCR,inp(p+SIO_MCR) | SIO_DTR);
  215.   else
  216.     outp(p+SIO_MCR,inp(p+SIO_MCR) & ~SIO_DTR);
  217.   return 0;
  218. }   /*setdtr*/
  219.  
  220.  
  221. int  setrts(WORD p,int rts)
  222. {
  223.   p=seriobase[p];
  224.   if (!p) return 0;
  225.   if (rts)
  226.     outp(p+SIO_MCR,inp(p+SIO_MCR) | SIO_RTS);
  227.   else
  228.     outp(p+SIO_MCR,inp(p+SIO_MCR) & ~SIO_RTS);
  229.   return 0;
  230. }   /*setrts*/
  231.  
  232.  
  233. int  setbrk(WORD p,int brk)
  234. {
  235.   p=seriobase[p];
  236.   if (!p) return 0;
  237.   if (brk)
  238.     outp(p+SIO_LCR,inp(p+SIO_LCR) | SIO_SBRK);
  239.   else
  240.     outp(p+SIO_LCR,inp(p+SIO_LCR) & ~SIO_SBRK);
  241.   return 1;
  242. }   /*setbrk*/
  243.  
  244.  
  245. /****************************************************************************/
  246. /*  getdtr, getrts, getbrk, getcts, getdsr                                  */
  247. /****************************************************************************/
  248. /*-----------------------------Description----------------------------------*/
  249. /*  These functions get the current settings of the RS232 control lines.    */
  250. /*  The DTR, RTS and BRK values (returned by getdtr(), getrts() and         */
  251. /*  getbrk()) are the current values on the output of the chip (under the   */
  252. /*  user's control).  The Clear To Send (getcts()) and Data Set Ready       */
  253. /*  (getdsr()) values are those present as inputs to the chip.              */
  254. /*-----------------------------Arguments------------------------------------*/
  255. /*  WORD p             COM port (NOT a PORT pointer), 0=COM1, 1=COM2, etc.  */
  256. /*-----------------------------Return value---------------------------------*/
  257. /*  1 if value is logically set (active), 0 if reset (inactive)             */
  258. /*-----------------------------Global constants-----------------------------*/
  259. /*-------------------Mod-------Global variables-----------------------------*/
  260. /*-----------------------------Functions called-----------------------------*/
  261. /*-----------------------------Constraints/Gotchas--------------------------*/
  262. /*  These are low-level routines, which do NOT take PORT* arguments.  For   */
  263. /*  normal use, use the corresponding sergetXXX() functions.                */
  264. /*--Date--------Programmer----------Comments--------------------------------*/
  265. /*  1990.07.12  D. Rogers           initial code                            */
  266. /****************************************************************************/
  267. int  getdtr(WORD p)
  268. {
  269.   p=seriobase[p];
  270.   if (!p) return 0;
  271.   return (inp(p+SIO_MCR) & SIO_DTR)!=0;
  272. }   /*getdtr*/
  273.  
  274.  
  275. int  getrts(WORD p)
  276. {
  277.   p=seriobase[p];
  278.   if (!p) return 0;
  279.   return (inp(p+SIO_MCR) & SIO_RTS)!=0;
  280. }   /*getrts*/
  281.  
  282.  
  283. int  getbrk(WORD p)
  284. {
  285.   p=seriobase[p];
  286.   if (!p) return 0;
  287.   return (inp(p+SIO_LCR) & SIO_SBRK)!=0;
  288. }   /*getbrk*/
  289.  
  290.  
  291. int  getcts(WORD p)
  292. {
  293.   p=seriobase[p];
  294.   if (!p) return 0;
  295.   return (inp(p+SIO_MSR) & SIO_CTS)!=0;
  296. }   /*getcts*/
  297.  
  298.  
  299. int  getdsr(WORD p)
  300. {
  301.   p=seriobase[p];
  302.   if (!p) return 0;
  303.   return (inp(p+SIO_MSR) & SIO_DSR)!=0;
  304. }   /*getdsr*/
  305.  
  306.  
  307. /****************************************************************************/
  308. /*  baudofbits, paryofbits, dataofbits, stopofbits                          */
  309. /****************************************************************************/
  310. /*-----------------------------Description----------------------------------*/
  311. /*  These functions convert from the low-level register values that the     */
  312. /*  serial interface chip requires, to high-level values which are easily   */
  313. /*  recognized by the user.  These functions are not accessible to the      */
  314. /*  user, but are used but higher-level functions after reading values      */
  315. /*  from the chip's registers.                                              */
  316. /*-----------------------------Arguments------------------------------------*/
  317. /*  WORD bits          bits (value) read from the serial i/o chip           */
  318. /*-----------------------------Return value---------------------------------*/
  319. /*  for baudofbits, an unsigned int equal to the baud rate                  */
  320. /*  for paryofbits, 'N' for None, 'O' for Odd and 'E' for even parity       */
  321. /*  for dataofbits, '5', '6', '7' or '8' data bits (Word Length Setting)    */
  322. /*  for stopofbits, '1' or '2' stop bits                                    */
  323. /*-----------------------------Global constants-----------------------------*/
  324. /*-------------------Mod-------Global variables-----------------------------*/
  325. /*-----------------------------Functions called-----------------------------*/
  326. /*-----------------------------Constraints/Gotchas--------------------------*/
  327. /*--Date--------Programmer----------Comments--------------------------------*/
  328. /*  1990.07.12  D. Rogers           initial code                            */
  329. /****************************************************************************/
  330. WORD baudofbits(WORD bits)
  331. {
  332.   switch(bits) {
  333.   case SER_BAUD_300:     return 300;
  334.   case SER_BAUD_600:     return 600;
  335.   case SER_BAUD_1200:    return 1200;
  336.   case SER_BAUD_2400:    return 2400;
  337.   case SER_BAUD_4800:    return 4800;
  338.   case SER_BAUD_9600:    return 9600;
  339.   case SER_BAUD_19200:   return 19200;
  340.   default:               return 0;
  341.   }   /*switch*/
  342. }   /*baudofbits*/
  343.  
  344.  
  345. char paryofbits(WORD bits)
  346. {
  347.   switch(bits & SIO_PAR) {
  348.   case SIO_PARN: return 'N';
  349.   case SIO_PARO: return 'O';
  350.   case SIO_PARE: return 'E';
  351.   default:       return 0;
  352.   }   /*switch*/
  353. }   /*paryofbits*/
  354.  
  355.  
  356. char dataofbits(WORD bits)
  357. {
  358.   switch(bits & SIO_DAT) {
  359.   case SIO_DAT5: return '5';
  360.   case SIO_DAT6: return '6';
  361.   case SIO_DAT7: return '7';
  362.   case SIO_DAT8: return '8';
  363.   default:       return 0;
  364.   }   /*switch*/
  365. }   /*dataofbits*/
  366.  
  367.  
  368. char stopofbits(WORD bits)
  369. {
  370.   switch(bits & SIO_STB) {
  371.   case SIO_STB1: return '1';
  372.   case SIO_STB2: return '2';
  373.   default:       return 0;
  374.   }   /*switch*/
  375. }   /*stopofbits*/
  376.  
  377.  
  378. /****************************************************************************/
  379. /*  bitsofbaud, bitsofpary, bitsofdata, bitsofstop                          */
  380. /****************************************************************************/
  381. /*-----------------------------Description----------------------------------*/
  382. /*  These functions convert from high-level, easily-recognizable, values    */
  383. /*  for the given configuration elements, to low-level, register-settable   */
  384. /*  bit-values for subsequent writing (setting).                            */
  385. /*-----------------------------Arguments------------------------------------*/
  386. /*  for bitsofbaud, one of the SER_BAUD_XXXX constants below                */
  387. /*  for bitsofpary, 'N' for None, 'O' for Odd and 'E' for even parity       */
  388. /*  for bitsofdata, '5', '6', '7' or '8' data bits (Word Length Setting)    */
  389. /*  for bitsofstop, '1' or '2' stop bits                                    */
  390. /*-----------------------------Return value---------------------------------*/
  391. /*  WORD bits          bits (value) read from the serial i/o chip           */
  392. /*-----------------------------Global constants-----------------------------*/
  393. /*-------------------Mod-------Global variables-----------------------------*/
  394. /*-----------------------------Functions called-----------------------------*/
  395. /*-----------------------------Constraints/Gotchas--------------------------*/
  396. /*--Date--------Programmer----------Comments--------------------------------*/
  397. /*  1990.07.12  D. Rogers           initial code                            */
  398. /****************************************************************************/
  399. WORD bitsofbaud(WORD baud)
  400. {
  401.   switch(baud) {
  402.   case 300:     return SER_BAUD_300;
  403.   case 600:     return SER_BAUD_600;
  404.   case 1200:    return SER_BAUD_1200;
  405.   case 2400:    return SER_BAUD_2400;
  406.   case 4800:    return SER_BAUD_4800;
  407.   case 9600:    return SER_BAUD_9600;
  408.   case 19200:   return SER_BAUD_19200;
  409.   default:      return 0;
  410.   }   /*switch*/
  411. }   /*bitsofbaud*/
  412.  
  413.  
  414. WORD bitsofpary(char pary)
  415. {
  416.   switch(pary) {
  417.   case 'N':  return SIO_PARN;
  418.   case 'O':  return SIO_PARO;
  419.   case 'E':  return SIO_PARE;
  420.   default:   return SIO_PARN;
  421.   }   /*switch*/
  422. }   /*bitsofpary*/
  423.  
  424.  
  425. WORD bitsofdata(char data)
  426. {
  427.   switch(data) {
  428.   case '5':  return SIO_DAT5;
  429.   case '6':  return SIO_DAT6;
  430.   case '7':  return SIO_DAT7;
  431.   case '8':  return SIO_DAT8;
  432.   default:   return SIO_DAT8;
  433.   }   /*switch*/
  434. }   /*bitsofdata*/
  435.  
  436.  
  437. WORD bitsofstop(char stop)
  438. {
  439.   switch(stop) {
  440.   case '1':  return SIO_STB1;
  441.   case '2':  return SIO_STB2;
  442.   default:   return SIO_STB1;
  443.   }   /*switch*/
  444. }   /*bitsofstop*/
  445.  
  446.  
  447. /****************************************************************************/
  448. /*  setbaud, setpary, setdata, setstop                                      */
  449. /****************************************************************************/
  450. /*-----------------------------Description----------------------------------*/
  451. /*  These functions set various transmission parameters, using low-level    */
  452. /*  bit-masks.                                                              */
  453. /*-----------------------------Arguments------------------------------------*/
  454. /*  WORD p             COM port, 0=COM1, 1=COM2, etc.                       */
  455. /*  WORD bits          appropriate bit-mask for function                    */
  456. /*-----------------------------Return value---------------------------------*/
  457. /*-----------------------------Global constants-----------------------------*/
  458. /*-------------------Mod-------Global variables-----------------------------*/
  459. /*-----------------------------Functions called-----------------------------*/
  460. /*-----------------------------Constraints/Gotchas--------------------------*/
  461. /*  The argument p is NOT a PORT pointer, but is a COM port number.         */
  462. /*--Date--------Programmer----------Comments--------------------------------*/
  463. /*  1990.07.12  D. Rogers           initial code                            */
  464. /****************************************************************************/
  465. int  setbaud(WORD p,WORD bits)
  466. {
  467.   WORD iop;
  468.  
  469.   if (p>=MAXPORTS) return 0;
  470.   iop=seriobase[p];
  471.   if (!iop) return 0;
  472.   outp(iop+SIO_LCR,inp(iop+SIO_LCR) | SIO_DLAB);
  473.   outp(iop+SIO_DLL,(bits & 0xFF));
  474.   outp(iop+SIO_DLM,(bits >> 8));
  475.   outp(iop+SIO_LCR,inp(iop+SIO_LCR) & ~SIO_DLAB);
  476.   return 1;
  477. }   /*setbaud*/
  478.  
  479.  
  480. int  setpary(WORD p,WORD bits)
  481. {
  482.   WORD iop;
  483.  
  484.   if (p>=MAXPORTS) return 0;
  485.   iop=seriobase[p];
  486.   if (!iop) return 0;
  487.   outp(iop+SIO_LCR,MSKVAL(inp(iop+SIO_LCR),SIO_PAR,bits));
  488.   return 1;
  489. }   /*setpary*/
  490.  
  491.  
  492. int  setdata(WORD p,WORD bits)
  493. {
  494.   WORD iop;
  495.  
  496.   if (p>=MAXPORTS) return 0;
  497.   iop=seriobase[p];
  498.   if (!iop) return 0;
  499.   outp(iop+SIO_LCR,MSKVAL(inp(iop+SIO_LCR),SIO_DAT,bits));
  500.   return 1;
  501. }   /*setdata*/
  502.  
  503.  
  504. int  setstop(WORD p,WORD bits)
  505. {
  506.   WORD iop;
  507.  
  508.   if (p>=MAXPORTS) return 0;
  509.   iop=seriobase[p];
  510.   if (!iop) return 0;
  511.   outp(iop+SIO_LCR,MSKVAL(inp(iop+SIO_LCR),SIO_STB,bits));
  512.   return 1;
  513. }   /*setstop*/
  514.  
  515.  
  516. /****************************************************************************/
  517. /*  getbaud, getpary, getdata, getstop                                      */
  518. /****************************************************************************/
  519. /*-----------------------------Description----------------------------------*/
  520. /*  These functions set various transmission parameters, using low-level    */
  521. /*  bit-masks.                                                              */
  522. /*-----------------------------Arguments------------------------------------*/
  523. /*  WORD p             COM port, 0=COM1, 1=COM2, etc.                       */
  524. /*-----------------------------Return value---------------------------------*/
  525. /*  Returns the current bit-mask value from the serial interface chip for   */
  526. /*  the specified configuration element.  The return value needs to be      */
  527. /*  translated from a bit-mask into a more readable form, by way of         */
  528. /*  XXXXofbits() functions above.                                           */
  529. /*-----------------------------Global constants-----------------------------*/
  530. /*-------------------Mod-------Global variables-----------------------------*/
  531. /*-----------------------------Functions called-----------------------------*/
  532. /*-----------------------------Constraints/Gotchas--------------------------*/
  533. /*  The argument p is NOT a PORT pointer, but is a COM port number.         */
  534. /*--Date--------Programmer----------Comments--------------------------------*/
  535. /*  1990.07.12  D. Rogers           initial code                            */
  536. /****************************************************************************/
  537. WORD getbaud(WORD p)
  538. {
  539.   WORD iop;
  540.   WORD bits;
  541.  
  542.   if (p>=MAXPORTS) return 0;
  543.   iop=seriobase[p];
  544.   if (!iop) return 0;
  545.   outp(iop+SIO_LCR,inp(iop+SIO_LCR) | SIO_DLAB);
  546.   bits=(inp(iop+SIO_DLM)<<8)+inp(iop+SIO_DLL);
  547.   outp(iop+SIO_LCR,inp(iop+SIO_LCR) & ~SIO_DLAB);
  548.   return bits;
  549. }   /*getbaud*/
  550.  
  551.  
  552. WORD getpary(WORD p)
  553. {
  554.   WORD iop;
  555.  
  556.   if (p>=MAXPORTS) return 0;
  557.   iop=seriobase[p];
  558.   if (!iop) return 0;
  559.   return inp(iop+SIO_LCR) & SIO_PAR;
  560. }   /*getpary*/
  561.  
  562.  
  563. WORD getdata(WORD p)
  564. {
  565.   WORD iop;
  566.  
  567.   if (p>=MAXPORTS) return 0;
  568.   iop=seriobase[p];
  569.   if (!iop) return 0;
  570.   return inp(iop+SIO_LCR) & SIO_DAT;
  571. }   /*getdata*/
  572.  
  573.  
  574. WORD getstop(WORD p)
  575. {
  576.   WORD iop;
  577.  
  578.   if (p>=MAXPORTS) return 0;
  579.   iop=seriobase[p];
  580.   if (!iop) return 0;
  581.   return inp(iop+SIO_LCR) & SIO_STB;
  582. }   /*getstop*/
  583.  
  584.  
  585. /****************************************************************************/
  586. /*  sersetdtr, sersetrts, sersetbrk                                         */
  587. /****************************************************************************/
  588. /*-----------------------------Description----------------------------------*/
  589. /*  These functions set the RS232 control lines for the serial PORT         */
  590. /*  indicated by the argument p.  If the second argument passed is 0, the   */
  591. /*  RS232 control line is reset (logical 0), but if the value passed is     */
  592. /*  nonzero, the RS232 line is set to an active level.  Note that these     */
  593. /*  are logic levels, and not voltages, since some active levels are at     */
  594. /*  lower voltages.                                                         */
  595. /*  The output lines are Data Terminal Ready (setdtr()), Request To Send    */
  596. /*  (setrts()) and Break (setbrk()).                                        */
  597. /*-----------------------------Arguments------------------------------------*/
  598. /*  PORT *p            pointer to PORT structure, as return by seropen()    */
  599. /*  int  <val>         value, 0=inactive, nonzero=active                    */
  600. /*-----------------------------Return value---------------------------------*/
  601. /*-----------------------------Global constants-----------------------------*/
  602. /*-------------------Mod-------Global variables-----------------------------*/
  603. /*-----------------------------Functions called-----------------------------*/
  604. /*-----------------------------Constraints/Gotchas--------------------------*/
  605. /*--Date--------Programmer----------Comments--------------------------------*/
  606. /*  1990.07.12  D. Rogers           initial code                            */
  607. /****************************************************************************/
  608. int   sersetdtr(PORT *p,int dtr)
  609. {
  610.   if (serbad(p)) return 0;
  611.   setdtr(p->com,dtr);
  612.   return 1;
  613. }   /*sersetdtr*/
  614.  
  615.  
  616. int   sersetrts(PORT *p,int rts)
  617. {
  618.   if (serbad(p)) return 0;
  619.   setrts(p->com,rts);
  620.   return 1;
  621. }   /*sersetrts*/
  622.  
  623.  
  624. int   sersetbrk(PORT *p,int brk)
  625. {
  626.   if (serbad(p)) return 0;
  627.   setbrk(p->com,brk);
  628.   return 1;
  629. }   /*sersetbrk*/
  630.  
  631.  
  632. /****************************************************************************/
  633. /*  sergetdtr, sergetrts, sergetbrk, sergetrts, sergetdsr                   */
  634. /****************************************************************************/
  635. /*-----------------------------Description----------------------------------*/
  636. /*  These functions read the status of the RS232 control lines for the      */
  637. /*  serial PORT indicated by the argument p.                                */
  638. /*-----------------------------Arguments------------------------------------*/
  639. /*  PORT *p            pointer to PORT structure, as return by seropen()    */
  640. /*-----------------------------Return value---------------------------------*/
  641. /*  Values returned are logic levels: 1 for TRUE (active) and 0 for FALSE.  */
  642. /*-----------------------------Global constants-----------------------------*/
  643. /*-------------------Mod-------Global variables-----------------------------*/
  644. /*-----------------------------Functions called-----------------------------*/
  645. /*-----------------------------Constraints/Gotchas--------------------------*/
  646. /*--Date--------Programmer----------Comments--------------------------------*/
  647. /*  1990.07.12  D. Rogers           initial code                            */
  648. /****************************************************************************/
  649. int   sergetdtr(PORT *p)
  650. {
  651.   if (serbad(p)) return 0;
  652.   return getdtr(p->com);
  653. }   /*sergetdtr*/
  654.  
  655.  
  656. int   sergetrts(PORT *p)
  657. {
  658.   if (serbad(p)) return 0;
  659.   return getrts(p->com);
  660. }   /*sergetrts*/
  661.  
  662.  
  663. int   sergetbrk(PORT *p)
  664. {
  665.   if (serbad(p)) return 0;
  666.   return getbrk(p->com);
  667. }   /*sergetbrk*/
  668.  
  669.  
  670. int   sergetcts(PORT *p)
  671. {
  672.   if (serbad(p)) return 0;
  673.   return getcts(p->com);
  674. }   /*sergetcts*/
  675.  
  676.  
  677. int   sergetdsr(PORT *p)
  678. {
  679.   if (serbad(p)) return 0;
  680.   return getdsr(p->com);
  681. }   /*sergetdsr*/
  682.  
  683.  
  684. /****************************************************************************/
  685. /*  sersetbaud, sersetpary, sersetdata, sersetstop                          */
  686. /****************************************************************************/
  687. /*-----------------------------Description----------------------------------*/
  688. /*  These functions set various transmission parameters of the serial port  */
  689. /*  indicated by the PORT *p argument.                                      */
  690. /*-----------------------------Arguments------------------------------------*/
  691. /*  PORT *p            serial port pointer, returned by seropen()           */
  692. /*  The second argument depends on the element being set:                   */
  693. /*  for sersetbaud(), int val   is an int baud rate (300, 1200, 9600, etc)  */
  694. /*  for sersetpary(), char val  is 'N'=none, 'O'=odd, 'E'=even parity       */
  695. /*  for sersetdata(), char val  is '5', '6', '7' or '8' data bits           */
  696. /*  for sersetstop(), char val  is '1' or '2' stop bits                     */
  697. /*-----------------------------Return value---------------------------------*/
  698. /*-----------------------------Global constants-----------------------------*/
  699. /*-------------------Mod-------Global variables-----------------------------*/
  700. /*-----------------------------Functions called-----------------------------*/
  701. /*-----------------------------Constraints/Gotchas--------------------------*/
  702. /*--Date--------Programmer----------Comments--------------------------------*/
  703. /*  1990.07.12  D. Rogers           initial code                            */
  704. /****************************************************************************/
  705. int   sersetbaud(PORT *p,int val)
  706. {
  707.   if (serbad(p)) return 0;
  708.   setbaud(p->com,bitsofbaud(val));
  709.   return 1;
  710. }   /*sersetbaud*/
  711.  
  712.  
  713. int   sersetpary(PORT *p,char val)
  714. {
  715.   if (serbad(p)) return 0;
  716.   setpary(p->com,bitsofpary(val));
  717.   return 1;
  718. }   /*sersetpary*/
  719.  
  720.  
  721. int   sersetdata(PORT *p,char val)
  722. {
  723.   if (serbad(p)) return 0;
  724.   setdata(p->com,bitsofdata(val));
  725.   return 1;
  726. }   /*sersetdata*/
  727.  
  728.  
  729. int   sersetstop(PORT *p,char val)
  730. {
  731.   if (serbad(p)) return 0;
  732.   setstop(p->com,bitsofstop(val));
  733.   return 1;
  734. }   /*sersetstop*/
  735.  
  736.  
  737. /****************************************************************************/
  738. /*  sergetbaud, sergetpary, sergetdata, sergetstop                          */
  739. /****************************************************************************/
  740. /*-----------------------------Description----------------------------------*/
  741. /*  These functions read various transmission parameters of the serial      */
  742. /*  port indicated by the PORT *p argument.                                 */
  743. /*-----------------------------Arguments------------------------------------*/
  744. /*  PORT *p            serial port pointer, returned by seropen()           */
  745. /*-----------------------------Return value---------------------------------*/
  746. /*  The return value depends on the element being set:                      */
  747. /*  for sersetbaud(), an int baud rate (300, 1200, 9600, etc)               */
  748. /*  for sersetpary(), 'N'=none, 'O'=odd, 'E'=even parity                    */
  749. /*  for sersetdata(), '5', '6', '7' or '8' data bits                        */
  750. /*  for sersetstop(), '1' or '2' stop bits                                  */
  751. /*-----------------------------Global constants-----------------------------*/
  752. /*-------------------Mod-------Global variables-----------------------------*/
  753. /*-----------------------------Functions called-----------------------------*/
  754. /*-----------------------------Constraints/Gotchas--------------------------*/
  755. /*--Date--------Programmer----------Comments--------------------------------*/
  756. /*  1990.07.12  D. Rogers           initial code                            */
  757. /****************************************************************************/
  758. int   sergetbaud(PORT *p)
  759. {
  760.   if (serbad(p)) return 0;
  761.   return baudofbits(getbaud(p->com));
  762. }   /*sergetbaud*/
  763.  
  764.  
  765. char  sergetpary(PORT *p)
  766. {
  767.   if (serbad(p)) return 0;
  768.   return paryofbits(getpary(p->com));
  769. }   /*sergetpary*/
  770.  
  771.  
  772. char  sergetdata(PORT *p)
  773. {
  774.   if (serbad(p)) return 0;
  775.   return dataofbits(getdata(p->com));
  776. }   /*sergetdata*/
  777.  
  778.  
  779. char  sergetstop(PORT *p)
  780. {
  781.   if (serbad(p)) return 0;
  782.   return stopofbits(getstop(p->com));
  783. }   /*sergetstop*/
  784.  
  785.  
  786. /****************************************************************************/
  787. /*  serscancfg                                                              */
  788. /****************************************************************************/
  789. /*-----------------------------Description----------------------------------*/
  790. /*  This function scans its string argument, looking for configuration      */
  791. /*  switches.  The string argument must already have its values loaded via  */
  792. /*  sprintf() before serscancfg() is called (see sersetcfg() and seropen(), */
  793. /*  below).  The cfg string may contain any of the following fields, in     */
  794. /*  any order:                                                              */
  795. /*    c<com-port>       <com-port>  is 0 for COM1, 1 for COM2, etc          */
  796. /*    b<baud-rate>      <baud-rate> is 300,600,1200,2400,4800,9600,19200    */
  797. /*    p<parity>         <parity>    is N=none, O=odd or E=even parity       */
  798. /*    d<data-bits>      <data-bits> is 5, 6, 7 or 8 data bits               */
  799. /*    s<stop-bits>      <stop-bits> is 1 or 2 stop bits                     */
  800. /*    r<recv-size>      <recv-size> is the receive buffer size, in bytes    */
  801. /*    t<xmit-size>      <xmit-size> is the transmit buffer size, in bytes   */
  802. /*    D<DTR>            <DTR>       is 0=inactive, 1=active state for DTR   */
  803. /*    R<RTS>            <RTS>       is 0=inactive, 1=active for RTS         */
  804. /*    B<Break>          <Break>     is 0=inactive, 1=active for Break       */
  805. /*  serscancfg() returns the settings in the locations pointed to by its    */
  806. /*  many arguments.                                                         */
  807. /*-----------------------------Arguments------------------------------------*/
  808. /*  char *cfg          pointer to configuration string to scan              */
  809. /*  All the remaining arguments point to data values to be set, if their    */
  810. /*  corresponding switches are found in the cfg string.                     */
  811. /*  WORD *c            for COM port, 0=COM1, 1=COM2, etc.                   */
  812. /*  WORD *b            for baud rate, 300,600,1200,2400,4800,9600,19200     */
  813. /*  char *p            for parity, 'N', 'O', 'E'                            */
  814. /*  char *d            for data bits, '5', '6', '7', '8'                    */
  815. /*  char *s            for stop bits, '1', '2'                              */
  816. /*  WORD *r            for receive buffer size                              */
  817. /*  WORD *t            for transmit buffer size                             */
  818. /*  char *D            for DTR value, '0', '1'                              */
  819. /*  char *R            for RTS value, '0', '1'                              */
  820. /*  char *B            for Break value, '0', '1'                            */
  821. /*-----------------------------Return value---------------------------------*/
  822. /*  1 if scan was successful, 0 if an error was encountered                 */
  823. /*-----------------------------Global constants-----------------------------*/
  824. /*-------------------Mod-------Global variables-----------------------------*/
  825. /*-----------------------------Functions called-----------------------------*/
  826. /*-----------------------------Constraints/Gotchas--------------------------*/
  827. /*--Date--------Programmer----------Comments--------------------------------*/
  828. /*  1990.07.12  D. Rogers           initial code                            */
  829. /****************************************************************************/
  830. int   serscancfg(
  831.   char *cfg,                           /*configuration string*/
  832.   WORD *c,                             /*pointer to COM port*/
  833.   WORD *b,char *p,char *d,char *s,     /*to baud, parity, data & stop bits*/
  834.   WORD *r,WORD *t,                     /*to receive and transmit buff sizes*/
  835.   char *D,char *R,char *B              /*to DTR, RTS and Break settings*/
  836. )
  837. {
  838.   if (cfg==NULL) return 1;
  839.   while (*cfg) {
  840.     while (*cfg && isspace(*cfg)) cfg++;    /*skip white space*/
  841.     switch (*cfg++) {
  842.     case 0:   return 1;
  843.     case 'c':
  844.       switch(*cfg++) {
  845.       case '0': *c=COM1; break;
  846.       case '1': *c=COM2; break;
  847.       case '2': *c=COM3; break;
  848.       case '3': *c=COM4; break;
  849.       default:  sererr=SER_ILLEGALCOM; return 0;
  850.       }   /*switch on COM port*/
  851.       break;
  852.     case 'b':
  853.       *b=atoi(cfg);
  854.       switch(*b) {
  855.       case 300:
  856.       case 600:
  857.       case 1200:
  858.       case 2400:
  859.       case 4800:
  860.       case 9600:
  861.       case 19200:
  862.         while (*cfg && !isspace(*cfg)) cfg++;
  863.         break;
  864.       default:
  865.         sererr=SER_ILLEGALBAUD;
  866.         return 0;
  867.       }   /*switch on baud*/
  868.       break;
  869.     case 'p':
  870.       *p=*cfg++;
  871.       switch(*p) {
  872.       case 'N':
  873.       case 'E':
  874.       case 'O':
  875.         break;
  876.       default:
  877.         sererr=SER_ILLEGALPARY;
  878.         return 0;
  879.       }   /*switch on parity*/
  880.       break;
  881.     case 'd':
  882.       *d=*cfg++;
  883.       switch(*d) {
  884.       case '5':
  885.       case '6':
  886.       case '7':
  887.       case '8':
  888.         break;
  889.       default:
  890.         sererr=SER_ILLEGALDATA;
  891.         return 0;
  892.       }   /*switch on data*/
  893.       break;
  894.     case 's':
  895.       *s=*cfg++;
  896.       switch(*s) {
  897.       case '1':
  898.       case '2':
  899.         break;
  900.       default:
  901.         sererr=SER_ILLEGALSTOP;
  902.         return 0;
  903.       }   /*switch on data*/
  904.       break;
  905.     case 'r':
  906.       *r=atoi(cfg);
  907.       if (*r<=0) {
  908.         sererr=SER_ILLEGALRSIZE;
  909.         return 0;
  910.       }
  911.       while (*cfg && !isspace(*cfg)) cfg++;
  912.       break;
  913.     case 't':
  914.       *t=atoi(cfg);
  915.       if (*t<=0) {
  916.         sererr=SER_ILLEGALTSIZE;
  917.         return 0;
  918.       }
  919.       while (*cfg && !isspace(*cfg)) cfg++;
  920.       break;
  921.     case 'D':
  922.       *D=*cfg++;
  923.       switch(*D) {
  924.       case '0':
  925.       case '1':
  926.         break;
  927.       default:
  928.         *D=0;
  929.         sererr=SER_ILLEGALDTR;
  930.         return 0;
  931.       }   /*switch on baud*/
  932.       break;
  933.     case 'R':
  934.       *R=*cfg++;
  935.       switch(*R) {
  936.       case '0':
  937.       case '1':
  938.         break;
  939.       default:
  940.         *R=0;
  941.         sererr=SER_ILLEGALRTS;
  942.         return 0;
  943.       }   /*switch on baud*/
  944.       break;
  945.     case 'B':
  946.       *B=*cfg++;
  947.       switch(*B) {
  948.       case '0':
  949.       case '1':
  950.         break;
  951.       default:
  952.         *B=0;
  953.         sererr=SER_ILLEGALBRK;
  954.         return 0;
  955.       }   /*switch on baud*/
  956.       break;
  957.     default:
  958.       sererr=SER_ILLEGALSPEC;
  959.       return 0;
  960.     }   /*switch*/
  961.   }   /*while*/
  962.   return 1;
  963. }   /*serscancfg*/
  964.  
  965.  
  966. /****************************************************************************/
  967. /*  seropen                                                                 */
  968. /****************************************************************************/
  969. /*-----------------------------Description----------------------------------*/
  970. /*  This function opens (initializes) a port, returning a handle to the     */
  971. /*  calling function.  The returned handle is a pointer to a serial port    */
  972. /*  structure, PORT, which holds information about the port.  The pointer   */
  973. /*  is used on subsequent calls to the serXXXXX() functions.                */
  974. /*  A configuration may be specified:                                       */
  975. /*    c<com-port>       <com-port>  is 0 for COM1, 1 for COM2, etc          */
  976. /*    b<baud-rate>      <baud-rate> is 300,600,1200,2400,4800,9600,19200    */
  977. /*    p<parity>         <parity>    is N=none, O=odd or E=even parity       */
  978. /*    d<data-bits>      <data-bits> is 5, 6, 7 or 8 data bits               */
  979. /*    s<stop-bits>      <stop-bits> is 1 or 2 stop bits                     */
  980. /*    r<recv-size>      <recv-size> is the receive buffer size, in bytes    */
  981. /*    t<xmit-size>      <xmit-size> is the transmit buffer size, in bytes   */
  982. /*    D<DTR>            <DTR>       is 0=inactive, 1=active state for DTR   */
  983. /*    R<RTS>            <RTS>       is 0=inactive, 1=active for RTS         */
  984. /*    B<Break>          <Break>     is 0=inactive, 1=active for Break       */
  985. /*-----------------------------Arguments------------------------------------*/
  986. /*  char *cfg          configuration/format string for port                 */
  987. /*  The cfg string may contain printf()-type format specifiers, in which    */
  988. /*  case extra arguments should be provided.  For example:                  */
  989. /*    p=seropen("c%d b%d pN d8 s1",COM2,1200);                              */
  990. /*  will open the COM2 port, with 1200 baud, N81.                           */
  991. /*-----------------------------Return value---------------------------------*/
  992. /*  Returns NULL on error (check sererr), otherwise returns a PORT pointer  */
  993. /*  which is to be used on subsequent calls to the serXXXX() functions.     */
  994. /*-----------------------------Global constants-----------------------------*/
  995. /*-------------------Mod-------Global variables-----------------------------*/
  996. /*-----------------------------Functions called-----------------------------*/
  997. /*-----------------------------Constraints/Gotchas--------------------------*/
  998. /*--Date--------Programmer----------Comments--------------------------------*/
  999. /*  1990.07.12  D. Rogers           initial code                            */
  1000. /****************************************************************************/
  1001. PORT *seropen(char *cfg,...)
  1002. {
  1003.   va_list va;
  1004.   PORT *p;
  1005.   WORD baud,com;
  1006.   WORD rsiz,tsiz;
  1007.   char pary,data,stop;
  1008.   char dtr,rts,brk;
  1009.   WORD iop;
  1010.  
  1011.   va_start(va,cfg);
  1012.   if (cfg) vsprintf(serstr,cfg,va); else serstr[0]=0;
  1013.   va_end(va);
  1014.  
  1015.   baud=SER_DEF_BAUD;
  1016.   com=SER_DEF_COM;
  1017.   rsiz=SER_DEF_RSIZ;
  1018.   tsiz=SER_DEF_TSIZ;
  1019.   pary=SER_DEF_PARY;
  1020.   data=SER_DEF_DATA;
  1021.   stop=SER_DEF_STOP;
  1022.   dtr=SER_DEF_DTR;
  1023.   rts=SER_DEF_RTS;
  1024.   brk=SER_DEF_BRK;
  1025.  
  1026.   for (com=0;com<MAXPORTS;com++) {
  1027.     if (seriobase[com] && (serp[com].rx==NULL)) break;
  1028.   }   /*for*/
  1029.   if (com>=MAXPORTS) { sererr=SER_NOAVAILABLE; return NULL; }
  1030.  
  1031.   if (!serscancfg(serstr,&com,&baud,&pary,&data,&stop,&rsiz,&tsiz,
  1032.         &dtr,&rts,&brk)) return NULL;
  1033.   if (com>=MAXPORTS) return NULL;
  1034.   if ((serp[com].rx!=NULL) || !seriobase[com]) {
  1035.     sererr=SER_NOAVAILABLE;
  1036.     return 0;
  1037.   }
  1038.   p=(PORT *) &serp[com];
  1039.   p->com=com;                          /*just in case*/
  1040.   p->rx=bufopen(rsiz);
  1041.   p->tx=bufopen(tsiz);
  1042.   if ((p->rx==NULL) || (p->tx==NULL)) {
  1043.     sererr=SER_NOBUFMEM;
  1044.     bufclose(p->rx);
  1045.     bufclose(p->tx);
  1046.     p->rx=NULL;
  1047.     p->tx=NULL;
  1048.     return 0;
  1049.   }
  1050.   setbaud(p->com,bitsofbaud(baud));
  1051.   setpary(p->com,bitsofpary(pary));
  1052.   setdata(p->com,bitsofdata(data));
  1053.   setstop(p->com,bitsofstop(stop));
  1054.   if (dtr) setdtr(p->com,dtr-'0');
  1055.   if (rts) setrts(p->com,rts-'0');
  1056.   if (brk) setbrk(p->com,brk-'0');
  1057.  
  1058.   iop=seriobase[p->com];
  1059.   outp(iop+SIO_LCR,inp(iop+SIO_LCR) & ~SIO_DLAB);  /*make sure not baud*/
  1060.   outp(iop+SIO_IER,SIO_ERBFI+SIO_ETBEI);
  1061.   outp(iop+SIO_MCR,inp(iop+SIO_MCR) | SIO_EINTS);
  1062.   p->serold=getvect(p->intnum);
  1063.   setvect(p->intnum,p->serint);
  1064.   outp(IOP_IMR,(~p->intimr) & inp(IOP_IMR));         /*enable by resetting*/
  1065.   inp(iop+SIO_RBR);
  1066.   inp(iop+SIO_RBR);
  1067.   inp(iop+SIO_IIR);                    /*clear stray int id's*/
  1068.  
  1069.   return p;
  1070. }   /*seropen*/
  1071.  
  1072.  
  1073. /****************************************************************************/
  1074. /*  serclose                                                                */
  1075. /****************************************************************************/
  1076. /*-----------------------------Description----------------------------------*/
  1077. /*  This function closes a serial port and frees the memory being used by   */
  1078. /*  it.                                                                     */
  1079. /*-----------------------------Arguments------------------------------------*/
  1080. /*  PORT *p            serial port pointer returned by seropen()            */
  1081. /*-----------------------------Return value---------------------------------*/
  1082. /*  Returns 1 if successful, 0 on error.                                    */
  1083. /*-----------------------------Global constants-----------------------------*/
  1084. /*-------------------Mod-------Global variables-----------------------------*/
  1085. /*-----------------------------Functions called-----------------------------*/
  1086. /*-----------------------------Constraints/Gotchas--------------------------*/
  1087. /*--Date--------Programmer----------Comments--------------------------------*/
  1088. /*  1990.07.12  D. Rogers           initial code                            */
  1089. /****************************************************************************/
  1090. int   serclose(PORT *p)
  1091. {
  1092.   WORD iop;
  1093.  
  1094.   if (serbad(p)) return 0;
  1095.   iop=seriobase[p->com];
  1096.   outp(IOP_IMR,inp(IOP_IMR) | p->intimr);
  1097.   outp(iop+SIO_MCR,inp(iop+SIO_MCR) & (~SIO_EINTS) & (~SIO_DTR));
  1098.   outp(iop+SIO_IER,0);
  1099.   setvect(p->intnum,p->serold);
  1100.   bufclose(p->rx);  p->rx=NULL;
  1101.   bufclose(p->tx);  p->tx=NULL;
  1102.   return 1;
  1103. }   /*serclose*/
  1104.  
  1105.  
  1106. /****************************************************************************/
  1107. /*  serputc                                                                 */
  1108. /****************************************************************************/
  1109. /*-----------------------------Description----------------------------------*/
  1110. /*  This function sends a character out the specified serial port.          */
  1111. /*-----------------------------Arguments------------------------------------*/
  1112. /*  PORT *p            handle for serial port over which to send the char   */
  1113. /*  int c              character (passed as int) to send                    */
  1114. /*-----------------------------Return value---------------------------------*/
  1115. /*  Returns 1 on success, 0 on error.                                       */
  1116. /*-----------------------------Global constants-----------------------------*/
  1117. /*-------------------Mod-------Global variables-----------------------------*/
  1118. /*-----------------------------Functions called-----------------------------*/
  1119. /*-----------------------------Constraints/Gotchas--------------------------*/
  1120. /*--Date--------Programmer----------Comments--------------------------------*/
  1121. /*  1990.07.12  D. Rogers           initial code                            */
  1122. /****************************************************************************/
  1123. int   serputc(PORT *p,int c)
  1124. {
  1125.   WORD iop;
  1126.  
  1127.   if (serbad(p)) return 0;
  1128.   iop=seriobase[p->com];
  1129.   if (buffull(p->tx)) {
  1130.     sererr=SER_TXFULL;
  1131.     return 0;
  1132.   }
  1133.   bufputc(p->tx,c);
  1134.   if ((inp(iop+SIO_LSR)&SIO_THRE)!=0)  /*if not currently transmitting*/
  1135.     outp(iop+SIO_THR,bufgetc(p->tx));  /*write to transmit holding reg*/
  1136.   return 1;
  1137. }   /*serputc*/
  1138.  
  1139.  
  1140. /****************************************************************************/
  1141. /*  serputs, serputns, serprintf                                            */
  1142. /****************************************************************************/
  1143. /*-----------------------------Description----------------------------------*/
  1144. /*  This functions send string out the serial port by calling serputc()     */
  1145. /*  until all the desired characters have been placed in the output buffer. */
  1146. /*  serputs() puts each character out until a 0 is found, serputns() puts   */
  1147. /*  n characters out, and serprintf() puts printf()-type formatted output.  */
  1148. /*-----------------------------Arguments------------------------------------*/
  1149. /*  PORT *p            handle of serial port to use, returned by seropen()  */
  1150. /*  char *s            (serputs() and serputns()) pointer to string to put  */
  1151. /*  int n              (serputns()) number of bytes (chars) to output       */
  1152. /*  char *fmt          (serprintf()) format specifier for formatted output  */
  1153. /*-----------------------------Return value---------------------------------*/
  1154. /*  Returns 1 on success, 0 on error.                                       */
  1155. /*-----------------------------Global constants-----------------------------*/
  1156. /*-------------------Mod-------Global variables-----------------------------*/
  1157. /*-----------------------------Functions called-----------------------------*/
  1158. /*-----------------------------Constraints/Gotchas--------------------------*/
  1159. /*--Date--------Programmer----------Comments--------------------------------*/
  1160. /*  1990.07.12  D. Rogers           initial code                            */
  1161. /****************************************************************************/
  1162. int   serputs(PORT *p,char *s)
  1163. {
  1164.   sererr=0;
  1165.   while (*s && !sererr) serputc(p,*s++);
  1166.   return sererr==0;
  1167. }   /*serputs*/
  1168.  
  1169.  
  1170. int   serputns(PORT *p,char *s,int n)
  1171. {
  1172.   if (serbad(p)) return 0;
  1173.   while ((n-->0) && !sererr) serputc(p,*s++);
  1174.   return sererr==0;
  1175. }   /*serputns*/
  1176.  
  1177.  
  1178. int   serprintf(PORT *p,char *fmt,...)
  1179. {
  1180.   va_list va;
  1181.   int n;
  1182.  
  1183.   va_start(va,fmt);
  1184.   n=vsprintf(serstr,fmt,va);
  1185.   va_end(va);
  1186.   serputns(p,serstr,n);
  1187.   return sererr==0;
  1188. }   /*serprintf*/
  1189.  
  1190.  
  1191. /****************************************************************************/
  1192. /*  sergetc, sergets                                                        */
  1193. /****************************************************************************/
  1194. /*-----------------------------Description----------------------------------*/
  1195. /*  These functions receive characters from the serial port receive buffer. */
  1196. /*  sergetc() gets a single character, and sergets() returns an ASCII-Z     */
  1197. /*  string (0-terminated), from the first character in the buffer, up to    */
  1198. /*  the first newline character ('\n'), which is NOT included.              */
  1199. /*-----------------------------Arguments------------------------------------*/
  1200. /*  PORT *p            handle of port to use, as returned by seropen()      */
  1201. /*  char *s            (sergets()) pointer to hold received string          */
  1202. /*  int n              (sergets()) maximum chars to get, including final 0  */
  1203. /*-----------------------------Return value---------------------------------*/
  1204. /*-----------------------------Global constants-----------------------------*/
  1205. /*-------------------Mod-------Global variables-----------------------------*/
  1206. /*-----------------------------Functions called-----------------------------*/
  1207. /*-----------------------------Constraints/Gotchas--------------------------*/
  1208. /*--Date--------Programmer----------Comments--------------------------------*/
  1209. /*  1990.07.12  D. Rogers           initial code                            */
  1210. /****************************************************************************/
  1211. int   sergetc(PORT *p)
  1212. {
  1213.   if (serbad(p)) return 0;
  1214.   if (bufempty(p->rx)) {
  1215.     sererr=SER_RXEMPTY;
  1216.     return 0;
  1217.   }
  1218.   return bufgetc(p->rx);
  1219. }   /*sergetc*/
  1220.  
  1221.  
  1222. int   sergets(PORT *p,char *s,int n)
  1223. {
  1224.   sererr=0;
  1225.   while ((--n>0) && !sererr) {
  1226.     *s=sergetc(p);
  1227.     if (*s==(p->rx)->trm) { *s=0; return 1; }
  1228.     s++;
  1229.   }   /*while*/
  1230.   *s=0;
  1231.   return (sererr==0);
  1232. }   /*sergets*/
  1233.  
  1234.  
  1235. /****************************************************************************/
  1236. /*  sersetcfg                                                               */
  1237. /****************************************************************************/
  1238. /*-----------------------------Description----------------------------------*/
  1239. /*  This function reconfigures the serial port, but allowing more than one  */
  1240. /*  element to be changed in a single call (as opposed to the sersetXXX()   */
  1241. /*  functions).  The new configuration values are specified just as in      */
  1242. /*  seropen():                                                              */
  1243. /*    b<baud-rate>      <baud-rate> is 300,600,1200,2400,4800,9600,19200    */
  1244. /*    p<parity>         <parity>    is N=none, O=odd or E=even parity       */
  1245. /*    d<data-bits>      <data-bits> is 5, 6, 7 or 8 data bits               */
  1246. /*    s<stop-bits>      <stop-bits> is 1 or 2 stop bits                     */
  1247. /*    D<DTR>            <DTR>       is 0=inactive, 1=active state for DTR   */
  1248. /*    R<RTS>            <RTS>       is 0=inactive, 1=active for RTS         */
  1249. /*    B<Break>          <Break>     is 0=inactive, 1=active for Break       */
  1250. /*  Note that the receive and transmit buffer sizes cannot be changed, nor  */
  1251. /*  can the serial port (COM1, COM2, etc).                                  */
  1252. /*-----------------------------Arguments------------------------------------*/
  1253. /*  PORT *p            handle for serial port, as returned by seropen()     */
  1254. /*  char *cfg          configuration/format string for port                 */
  1255. /*  The cfg string may contain printf()-type format specifiers, in which    */
  1256. /*  case extra arguments should be provided.  For example:                  */
  1257. /*    p=sersetcfg("b%d p%c d7 s1",1200,'E');                                */
  1258. /*  will reconfigure port p, with 1200 baud, E71.                           */
  1259. /*-----------------------------Return value---------------------------------*/
  1260. /*  Returns 1 on success, 0 on error.                                       */
  1261. /*-----------------------------Global constants-----------------------------*/
  1262. /*-------------------Mod-------Global variables-----------------------------*/
  1263. /*-----------------------------Functions called-----------------------------*/
  1264. /*-----------------------------Constraints/Gotchas--------------------------*/
  1265. /*--Date--------Programmer----------Comments--------------------------------*/
  1266. /*  1990.07.12  D. Rogers           initial code                            */
  1267. /****************************************************************************/
  1268. int   sersetcfg(PORT *p,char *cfg,...)
  1269. {
  1270.   va_list va;
  1271.   WORD baud=0,com=0,rsiz=0,tsiz=0;
  1272.   char pary=0,data=0,stop=0;
  1273.   char dtr=0,rts=0,brk=0;
  1274.   WORD iop;
  1275.  
  1276.   va_start(va,cfg);
  1277.   if (cfg!=NULL) vsprintf(serstr,cfg,va); else serstr[0]=0;
  1278.   va_end(va);
  1279.   if (serbad(p)) return 0;
  1280.  
  1281.   if (!serscancfg(serstr,&com,&baud,&pary,&data,&stop,
  1282.             &rsiz,&tsiz,&dtr,&rts,&brk)) return 0;
  1283.   if (com!=p->com) { sererr=SER_NOCOMSWITCH; return 0; }
  1284.   iop=seriobase[p->com];
  1285.   if (iop==0) { sererr=SER_NOAVAILABLE; return 0; }
  1286.   if (baud) sersetbaud(p,baud);
  1287.   if (pary) sersetpary(p,pary);
  1288.   if (data) sersetdata(p,data);
  1289.   if (stop) sersetstop(p,stop);
  1290.   if (dtr)  sersetdtr(p,dtr-'0');
  1291.   if (rts)  sersetrts(p,rts-'0');
  1292.   if (brk)  sersetbrk(p,brk-'0');
  1293.   if (rsiz || tsiz) {
  1294.     sererr=SER_NOBUFCHANGE;
  1295.     return 0;
  1296.   }
  1297.   return 1;
  1298. }   /*sersetcfg*/
  1299.  
  1300.  
  1301. /****************************************************************************/
  1302. /*  sergetcfg                                                               */
  1303. /****************************************************************************/
  1304. /*-----------------------------Description----------------------------------*/
  1305. /*  This function loads a string with a displayable description of the      */
  1306. /*  given ports configuration.  Note that the string is NOT commpatible     */
  1307. /*  with setsetcfg() nor seropen().                                         */
  1308. /*-----------------------------Arguments------------------------------------*/
  1309. /*  PORT *p            handle of serial port, as returned by seropen()      */
  1310. /*  char *s            destination location for configuration description   */
  1311. /*  int n              maximum length of string, including final 0          */
  1312. /*-----------------------------Return value---------------------------------*/
  1313. /*  Returns s, as passed.  Returns NULL on error.                           */
  1314. /*-----------------------------Global constants-----------------------------*/
  1315. /*-------------------Mod-------Global variables-----------------------------*/
  1316. /*-----------------------------Functions called-----------------------------*/
  1317. /*-----------------------------Constraints/Gotchas--------------------------*/
  1318. /*  The string produced by this function is NOT compatible with those       */
  1319. /*  required by sersetcfg() and seropen().  The string is meant only to be  */
  1320. /*  displayed and easily read.                                              */
  1321. /*--Date--------Programmer----------Comments--------------------------------*/
  1322. /*  1990.07.12  D. Rogers           initial code                            */
  1323. /****************************************************************************/
  1324. char *sergetcfg(PORT *p,char *s,int n)
  1325. {
  1326.   if (serbad(p)) return NULL;
  1327.   sprintf(
  1328.     serstr,
  1329.     "%s %u %c%c%c (r%u t%u)",
  1330.     sercomstr[p->com],sergetbaud(p),
  1331.     sergetpary(p),sergetdata(p),sergetstop(p),
  1332.     (p->rx)->siz,(p->tx)->siz
  1333.   );
  1334.   strncpy(s,serstr,n-1);
  1335.   s[n-1]=0;
  1336.   return s;
  1337. }   /*sergetcfg*/
  1338.  
  1339.  
  1340. /****************************************************************************/
  1341. /*  sererrmsg                                                               */
  1342. /****************************************************************************/
  1343. /*-----------------------------Description----------------------------------*/
  1344. /*  This function returns a pointer to an error message corresponding to    */
  1345. /*  the error code passed.  The error codes are possible values held by     */
  1346. /*  the int variable sererr.                                                */
  1347. /*-----------------------------Arguments------------------------------------*/
  1348. /*  int ec             error code for which a message is desired, sererr    */
  1349. /*-----------------------------Return value---------------------------------*/
  1350. /*  Returns a pointer to a constant error message string.                   */
  1351. /*-----------------------------Global constants-----------------------------*/
  1352. /*-------------------Mod-------Global variables-----------------------------*/
  1353. /*-----------------------------Functions called-----------------------------*/
  1354. /*-----------------------------Constraints/Gotchas--------------------------*/
  1355. /*--Date--------Programmer----------Comments--------------------------------*/
  1356. /*  1990.07.12  D. Rogers           initial code                            */
  1357. /****************************************************************************/
  1358. char *sererrmsg(int ec)
  1359. {
  1360.   switch (ec) {
  1361.   case SER_NONE:           return "no error";
  1362.   case SER_BADPORT:        return "port pointer was NULL";
  1363.   case SER_UNINIT:         return "port not yet initialized";
  1364.   case SER_BADCOM:         return "port pointer way off: com field bad";
  1365.   case SER_ILLEGALSPEC:    return "bad cfg specifier";
  1366.   case SER_ILLEGALCOM:     return "bad cfg COM value, c";
  1367.   case SER_ILLEGALBAUD:    return "bad cfg baud rate value, b";
  1368.   case SER_ILLEGALPARY:    return "bad cfg parity value, p";
  1369.   case SER_ILLEGALDATA:    return "bad cfg data bits value, d";
  1370.   case SER_ILLEGALSTOP:    return "bad cfg stop bits value, s";
  1371.   case SER_ILLEGALRSIZE:   return "bad cfg rx buffer size value, r";
  1372.   case SER_ILLEGALTSIZE:   return "bad cfg tx buffer size value, t";
  1373.   case SER_ILLEGALDTR:     return "bad cfg DTR value";
  1374.   case SER_ILLEGALRTS:     return "bad cfg RTS value";
  1375.   case SER_ILLEGALBRK:     return "bad cfg Break value";
  1376.   case SER_NOAVAILABLE:    return "com port not available";
  1377.   case SER_NOBUFMEM:       return "could not allocate serial buffers";
  1378.   case SER_RXOVER:         return "receive buffer overflow";
  1379.   case SER_TXFULL:         return "transmit buffer full";
  1380.   case SER_RXEMPTY:        return "receive buffer empty";
  1381.   case SER_NOCOMSWITCH:    return "COM port switching not allowed";
  1382.   case SER_NOBUFCHANGE:    return "no buffer size changes allowed";
  1383.   default:                 return "unknown serial error";
  1384.   }   /*switch*/
  1385. }   /*sererrmsg*/
  1386.  
  1387.