home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / RIO / RIOLIB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-13  |  21.4 KB  |  966 lines

  1. /* RIOLIB.C */
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. /* Remote communications Input/Output Library for OS/2 and Win32 */
  6.  
  7. #define RIOLIB_VER    100
  8.  
  9. #ifdef __OS2__
  10.     #define INCL_DOSDEVICES
  11.     #define INCL_DOSDEVIOCTL
  12.     #define INCL_DOS
  13.     #include <os2.h>
  14.  
  15. #else    // Win32
  16.  
  17.     #include <windows.h>
  18. #endif
  19.  
  20. #include <time.h>
  21. #include <stdio.h>
  22. #include <fcntl.h>
  23. #include <string.h>
  24. #include <process.h>
  25. #include "riolib.h"
  26. #include "riodefs.h"
  27.  
  28. int rio_handle=-1;
  29.  
  30. int rio_abort=0,rio_aborted=0;
  31. int inbufbot,inbuftop;
  32. int outbufbot,outbuftop;
  33. char inbuf[RIO_INCOM_BUFLEN];
  34. char outbuf[RIO_OUTCOM_BUFLEN];
  35.  
  36. /****************************************************************************/
  37. /* OS/2 Specific                                                            */
  38. /****************************************************************************/
  39.  
  40. #ifdef __OS2__
  41.  
  42. HEV rio_sem;
  43.  
  44. typedef struct {    /* Packet for Get/Set Device Control Block Parms */
  45.  
  46.     ushort    wr_timeout;
  47.     ushort    rd_timeout;
  48.     uchar    flags1;
  49.     uchar    flags2;
  50.     uchar    flags3;
  51.     uchar    err_char;
  52.     uchar    brk_char;
  53.     uchar    xon_char;
  54.     uchar    xoff_char;
  55.  
  56.     } async_dcb_t;
  57.  
  58. typedef struct {    /* Parameter Packet for Extended Set Bit Rate */
  59.  
  60.     ulong rate;
  61.     uchar frac;
  62.  
  63.     } setrate_t;
  64.  
  65. typedef struct {    /* Data Packet for Extended Query Bit Rate */
  66.  
  67.     ulong cur_rate;
  68.     uchar cur_rate_frac;
  69.     ulong min_rate;
  70.     uchar min_rate_frac;
  71.     ulong max_rate;
  72.     uchar max_rate_frac;
  73.  
  74.     } getrate_t;
  75.  
  76. typedef struct {    /* Data Packet for Query Number of Chars Queue */
  77.  
  78.     ushort    cur,
  79.             max;
  80.  
  81.     } getqueue_t;
  82.  
  83. typedef struct {    /* Parameter Packet for Set Modem Control Signals */
  84.  
  85.     uchar    on;
  86.     uchar    off;
  87.  
  88.     } setmdmctrl_t;
  89.  
  90. typedef struct {    /* Parameter Packet for Set Line Characteristics */
  91.  
  92.     uchar    data;
  93.     uchar    parity;
  94.     uchar    stop;
  95.  
  96.     } setline_t;
  97.  
  98. #else
  99.  
  100. /****************************************************************************/
  101. /* Win32 Specific                                                            */
  102. /****************************************************************************/
  103.  
  104. HANDLE    rio_event;
  105.  
  106. #endif
  107.  
  108. /************************************************************************/
  109. /* Opens COM port, ignoring IRQ argument                                */
  110. /* Returns 0 on no error                                                */
  111. /************************************************************************/
  112. int rioini(int com, int unused)
  113. {
  114.     char        str[64];
  115. #ifdef __OS2__
  116.     async_dcb_t async_dcb;
  117. #else // Win32
  118.     DCB         dcb;
  119.     COMMTIMEOUTS timeouts;
  120. #endif
  121.  
  122. #ifdef __WATOMC__
  123.     char        *stack;
  124. #endif
  125.  
  126. inbufbot=inbuftop=outbufbot=outbuftop=0;    /* clear our i/o buffers */
  127.  
  128. if(!com) { /* Close port */
  129.     if(rio_handle>=0) {
  130. #ifdef __OS2__
  131.         close(rio_handle);
  132.         rio_handle=-1;     /* signal outcom_thread() to end */
  133.         DosPostEventSem(rio_sem);
  134. #else // Win32
  135.         CloseHandle((HANDLE)rio_handle);
  136.         rio_handle=-1;
  137.         SetEvent(rio_event);
  138. #endif
  139.         return(0); }
  140.     return(-2); }
  141.  
  142. sprintf(str,"COM%u",com);
  143. #ifdef __OS2__
  144. if(rio_handle==-1) {    /* Not already opened */
  145.     if((rio_handle=open(str,O_RDWR|O_BINARY,0))==-1)
  146.         return(-1); }
  147. #else // Win32
  148. if(rio_handle==-1) {    /* Not already opened */
  149.     if((rio_handle=(int)CreateFile(str
  150.         ,GENERIC_READ|GENERIC_WRITE     /* Access */
  151.         ,0                                /* Share mode */
  152.         ,NULL                            /* Security attributes */
  153.         ,OPEN_EXISTING                    /* Create access */
  154.         ,FILE_ATTRIBUTE_NORMAL            /* File attributes */
  155.         ,NULL                            /* Template */
  156.         ))==(int)INVALID_HANDLE_VALUE)
  157.         return(-1); }
  158. #endif
  159.  
  160. #ifdef __OS2__
  161.  
  162. if(DosDevIOCtl(rio_handle
  163.     ,IOCTL_ASYNC, 0x73    /* Query Device Control Block (DCB) Parms */
  164.     ,NULL
  165.     ,0
  166.     ,NULL
  167.     ,&async_dcb
  168.     ,sizeof(async_dcb)
  169.     ,NULL))
  170.     return(-6);
  171.  
  172. async_dcb.flags2&=~(1<<1);    /* Disable Automatic Recv XON/XOFF flow ctrl */
  173. /* Extended Hardware Buffering (16550 FIFO) */
  174. if(async_dcb.flags3&((1<<4)|(1<<3))) {            /* Supported */
  175.     async_dcb.flags3&=~((1<<3)|(1<<6)|(1<<5));    /* Set to 1 char trgr lvl */
  176.     async_dcb.flags3|=((1<<4)|(1<<7)); }        /* Set to 16 char tx buf */
  177. async_dcb.flags3|=((1<<2)|(1<<1));                /* No-Wait read timeout */
  178. async_dcb.flags3&=~(1<<0);                        /* Normal write timeout */
  179. async_dcb.wr_timeout=499;                        /* 5 seconds? */
  180. DosDevIOCtl(rio_handle
  181.     ,IOCTL_ASYNC, 0x53    /* Set Device Control Block (DCB) Parms */
  182.     ,(void *)&async_dcb
  183.     ,sizeof(async_dcb)
  184.     ,NULL
  185.     ,NULL
  186.     ,0
  187.     ,NULL);
  188.  
  189. if(DosCreateEventSem(NULL,&rio_sem,0,0))
  190.     return(-5);
  191.  
  192. #else // Win32
  193.  
  194. if(GetCommState((HANDLE)rio_handle,&dcb)!=TRUE)
  195.     return(-6);
  196.  
  197. dcb.fBinary=1;            // No EOF check
  198. dcb.fDtrControl=DTR_CONTROL_ENABLE;
  199. dcb.fDsrSensitivity=FALSE;
  200. dcb.fOutX=0;            // No Xon/Xoff out
  201. dcb.fInX=0;             // No Xon/Xoff in
  202. dcb.fErrorChar=FALSE;    // No character replacement
  203. dcb.fNull=0;            // No null stripping
  204. dcb.fAbortOnError=0;    // Continue to communicate even if error detected
  205.  
  206. SetCommState((HANDLE)rio_handle,&dcb);
  207.  
  208. if(GetCommTimeouts((HANDLE)rio_handle,&timeouts)!=TRUE)
  209.     return(-7);
  210.  
  211. timeouts.ReadIntervalTimeout=MAXDWORD;
  212. timeouts.ReadTotalTimeoutMultiplier=0;
  213. timeouts.ReadTotalTimeoutConstant=0;        // No-wait read timeout
  214. timeouts.WriteTotalTimeoutMultiplier=0;
  215. timeouts.WriteTotalTimeoutConstant=5000;    // 5 seconds
  216. SetCommTimeouts((HANDLE)rio_handle,&timeouts);
  217.  
  218. SetupComm((HANDLE)rio_handle,4096,4096);    /* Init Rx and Tx buffer sizes */
  219.  
  220. if((rio_event=CreateEvent(NULL            /* Security attributes */
  221.     ,TRUE                                /* Manual reset */
  222.     ,FALSE                                /* Non-signaled by default */
  223.     ,NULL                                /* Event name */
  224.     ))==NULL)
  225.     return(-5);
  226.  
  227. #endif
  228.  
  229. #ifdef __WATCOMC__
  230. stack=malloc(RIO_OUTCOM_STACK);
  231. if(stack==NULL)
  232.     return(-4);
  233. if(_beginthread(outcom_thread,stack,RIO_OUTCOM_STKLEN,NULL)==-1)
  234.     return(-3);
  235. #else
  236. if(_beginthread(outcom_thread,RIO_OUTCOM_STKLEN,NULL)==(ulong)-1)
  237.     return(-3);
  238. #endif
  239.  
  240.  
  241. return(0);
  242. }
  243.  
  244. /************************************************************************/
  245. /* Raise or lower DTR                                                    */
  246. /* If onoff is 0, drop and exit, 1 raise and exit, >1 drop and wait     */
  247. /* up to x seconds for DCD to drop, return 0 on success, 1 on failure    */
  248. /************************************************************************/
  249. int dtr(char onoff)
  250. {
  251. #ifdef __OS2__
  252.     setmdmctrl_t setmdmctrl;
  253.     ulong start;
  254.     ushort w;
  255.     uchar c;
  256.  
  257. if(onoff==1) {
  258.     setmdmctrl.on=1;
  259.     setmdmctrl.off=0xff; }
  260. else {
  261.     setmdmctrl.on=0;
  262.     setmdmctrl.off=0xfe; }
  263.  
  264. DosDevIOCtl(rio_handle, IOCTL_ASYNC, 0x46    /* Set Modem Ctrl Signals */
  265.     ,&setmdmctrl
  266.     ,sizeof(setmdmctrl)
  267.     ,NULL
  268.     ,&w
  269.     ,sizeof(short)
  270.     ,NULL);
  271.  
  272. if(onoff<=1)
  273.     return(0);
  274.  
  275. start=time(NULL);
  276. while(time(NULL)-start<=onoff) {
  277.     DosDevIOCtl(rio_handle
  278.         ,IOCTL_ASYNC, 0x67                    /* Get Modem Input Signals */
  279.         ,NULL
  280.         ,0
  281.         ,NULL
  282.         ,&c
  283.         ,1
  284.         ,NULL);
  285.     if(!(c&DCD))    /* DCD is low */
  286.         return(0);
  287.     DosSleep(1); }
  288.  
  289. #else // Win32
  290.  
  291.     ulong l,start;
  292.  
  293. if(onoff==1)
  294.     EscapeCommFunction((HANDLE)rio_handle,SETDTR);
  295. else
  296.     EscapeCommFunction((HANDLE)rio_handle,CLRDTR);
  297.  
  298. if(onoff<=1)
  299.     return(0);
  300.  
  301. start=time(NULL);
  302. while(time(NULL)-start<=onoff) {
  303.     GetCommModemStatus((HANDLE)rio_handle,&l);
  304.     if(!(l&MS_RLSD_ON)) // DCD is low
  305.         return(0);
  306.     Sleep(1000); }
  307.  
  308. #endif
  309.  
  310. return(1); /* Dropping DTR failed to lower DCD */
  311. }
  312.  
  313.  
  314.  
  315. /************************************************************************/
  316. /* Returns the current DTE rate of the currently open COM port            */
  317. /************************************************************************/
  318. long rio_getbaud(void)
  319. {
  320. #ifdef __OS2__
  321.     getrate_t getrate;
  322.  
  323. if(DosDevIOCtl(rio_handle, IOCTL_ASYNC, 0x63 /* Extended Query Bit Rate */
  324.     ,NULL
  325.     ,0
  326.     ,NULL
  327.     ,&getrate
  328.     ,sizeof(getrate)
  329.     ,NULL)==0)
  330.     return(getrate.cur_rate);
  331.  
  332. #else // Win32
  333.  
  334.     DCB dcb;
  335.  
  336. if(GetCommState((HANDLE)rio_handle,&dcb)==TRUE) {
  337.     switch(dcb.BaudRate) {
  338.         case CBR_110:
  339.             return(110);
  340.         case CBR_300:
  341.             return(300);
  342.         case CBR_600:
  343.             return(600);
  344.         case CBR_1200:
  345.             return(1200);
  346.         case CBR_2400:
  347.             return(2400);
  348.         case CBR_4800:
  349.             return(4800);
  350.         case CBR_9600:
  351.             return(9600);
  352.         case CBR_14400:
  353.             return(14400);
  354.         case CBR_19200:
  355.             return(19200);
  356.         case CBR_38400:
  357.             return(38400);
  358.         case CBR_56000:
  359.             return(56000);
  360.         case CBR_57600:
  361.             return(57600);
  362.         case CBR_115200:
  363.             return(115200);
  364.         case CBR_128000:
  365.             return(128000);
  366.         case CBR_256000:
  367.             return(256000);
  368.         default:
  369.             return(dcb.BaudRate); } }
  370.  
  371. #endif
  372.  
  373. return(-1); // Error
  374. }
  375.  
  376.  
  377. /************************************************************************/
  378. /* Sets the current DTE rate                                            */
  379. /* Returns 0 on success                                                 */
  380. /************************************************************************/
  381. int setbaud(int rate)
  382. {
  383. #ifdef __OS2__
  384.     setrate_t setrate;
  385.     APIRET    ret;
  386.  
  387. setrate.rate=rate;
  388. setrate.frac=0;
  389.  
  390. ret=DosDevIOCtl(rio_handle, IOCTL_ASYNC, 0x43    /* Extended Set Bit Rate */
  391.     ,&setrate
  392.     ,sizeof(setrate)
  393.     ,NULL
  394.     ,NULL
  395.     ,0
  396.     ,NULL);
  397.  
  398. if(ret)
  399.     return(ret);
  400.  
  401. if(rio_getbaud()!=rate)     /* Make sure it actually changed rates */
  402.     return(-1);
  403.  
  404. #else // Win32
  405.  
  406.     DCB dcb;
  407.  
  408. if(GetCommState((HANDLE)rio_handle,&dcb)!=TRUE)
  409.     return(-1);
  410. dcb.BaudRate=rate;
  411. if(SetCommState((HANDLE)rio_handle,&dcb)!=TRUE)
  412.     return(-1);
  413.  
  414. #endif
  415.  
  416. return(0);
  417. }
  418.  
  419. /************************************************************************/
  420. /* Return next incoming character from COM port, NOINP if none avail.    */
  421. /* Uses a linear buffer.                                                */
  422. /************************************************************************/
  423. int incom(void)
  424. {
  425.     char c;
  426.  
  427. if(inbufbot!=inbuftop) {
  428.     c=inbuf[inbufbot];
  429.     inbufbot++;
  430.     if(inbufbot==inbuftop)
  431.         inbufbot=inbuftop=0;
  432.     if(rio_abort && c==3) {         /* Ctrl-C */
  433.         rio_aborted=1;
  434.         rioctl(IOFO);
  435.         return(NOINP); }
  436.     return(c); }
  437.  
  438. inbufbot=0;
  439. #ifdef __OS2__
  440. inbuftop=read(rio_handle,inbuf,RIO_INCOM_BUFLEN);
  441. #else // Win32
  442. ReadFile((HANDLE)rio_handle,inbuf,RIO_INCOM_BUFLEN,(DWORD *)&inbuftop,NULL);
  443. #endif
  444. if(inbuftop<=0 || inbuftop>RIO_INCOM_BUFLEN) {
  445.     inbuftop=0;
  446.     return(NOINP); }
  447. else
  448.     return(inbuf[inbufbot++]);
  449. }
  450.  
  451. /************************************************************************/
  452. /* Return number of chars in our input buffer                            */
  453. /************************************************************************/
  454. int inbufcnt(void)
  455. {
  456. return(inbuftop-inbufbot);
  457. }
  458.  
  459. /************************************************************************/
  460. /* Place a character into outbound buffer, return TXBOF on buffer        */
  461. /* overflow, 0 on success.                                                */
  462. /************************************************************************/
  463. int outcom(int ch)
  464. {
  465.     int i=outbuftop+1;
  466.  
  467. if(i==RIO_OUTCOM_BUFLEN)
  468.     i=0;
  469. if(i==outbufbot)
  470.     return(TXBOF);
  471. outbuf[outbuftop++]=ch;
  472. if(outbuftop==RIO_OUTCOM_BUFLEN)
  473.     outbuftop=0;
  474. #ifdef __OS2__
  475. DosPostEventSem(rio_sem);     // Enable output
  476. #else // Win32
  477. SetEvent(rio_event);
  478. #endif
  479. return(0);
  480. }
  481.  
  482. /************************************************************************/
  483. /************************************************************************/
  484. void outcom_thread(void *unused)
  485. {
  486.     int i,top;
  487.     ulong l;
  488.  
  489. while(rio_handle>=0) {
  490.     if(outbufbot==outbuftop) {
  491. #ifdef __OS2__
  492.         DosResetEventSem(rio_sem,&l);
  493.         DosWaitEventSem(rio_sem,10000);  /* every 10 seconds */
  494. #else // Win32
  495.         ResetEvent(rio_event);
  496.         WaitForSingleObject(rio_event,10000);
  497. #endif
  498.         continue; }
  499.     top=outbuftop;
  500.     if(top<outbufbot)
  501.         i=RIO_OUTCOM_BUFLEN-outbufbot;
  502.     else
  503.         i=top-outbufbot;
  504. #ifdef __OS2__
  505.     i=write(rio_handle,outbuf+outbufbot,i);
  506. #else // Win32
  507.     WriteFile((HANDLE)rio_handle,outbuf+outbufbot,i,(DWORD *)&i,NULL);
  508. #endif
  509.     if(i>0 && i<=RIO_OUTCOM_BUFLEN-outbufbot)
  510.         outbufbot+=i;
  511.     if(outbufbot==RIO_OUTCOM_BUFLEN)
  512.         outbufbot=0; }
  513. _endthread();
  514. }
  515.  
  516. /************************************************************************/
  517. /* Return number of chars in our output buffer                            */
  518. /************************************************************************/
  519. int outbufcnt(void)
  520. {
  521. if(outbuftop>=outbufbot)
  522.     return(outbuftop-outbufbot);
  523. return(outbuftop+(RIO_OUTCOM_BUFLEN-outbufbot));
  524. }
  525.  
  526. /************************************************************************/
  527. /************************************************************************/
  528. int rio_getstate(void)
  529. {
  530. #ifdef __OS2__
  531.     uchar c;
  532.     ushort state=0,w;
  533.     getqueue_t getqueue;
  534.  
  535. if(rio_abort && !rio_aborted) {
  536.     DosDevIOCtl(rio_handle
  537.         ,IOCTL_ASYNC, 0x68 /* Query # of chars in rx queue */
  538.         ,NULL
  539.         ,0
  540.         ,NULL
  541.         ,&getqueue
  542.         ,sizeof(getqueue)
  543.         ,NULL);
  544.     if(getqueue.cur && read(rio_handle,&c,1)==1) {
  545.         if(c==3) { /* ctrl-c */
  546.             rio_aborted=1;
  547.             rioctl(IOFO); }
  548.         else
  549.             if(inbuftop<RIO_INCOM_BUFLEN)  /* don't overflow input buffer */
  550.                 inbuf[inbuftop++]=c; } }
  551.  
  552. if(rio_aborted)
  553.     state|=ABORT;
  554.  
  555. #if 0    // just to see if things speed up
  556. DosDevIOCtl(rio_handle
  557.     ,IOCTL_ASYNC, 0x6D    /* Query COM Error */
  558.     ,NULL
  559.     ,0
  560.     ,NULL
  561.     ,&w
  562.     ,sizeof(short)
  563.     ,NULL);
  564. state|=w&0xf;    /* FERR|PERR|OVRR|RXLOST */
  565. #endif
  566.  
  567. DosDevIOCtl(rio_handle
  568.     ,IOCTL_ASYNC, 0x67    /* Query Modem Input Signals */
  569.     ,NULL
  570.     ,0
  571.     ,NULL
  572.     ,&c
  573.     ,sizeof(char)
  574.     ,NULL);
  575. state|=c&0xf0;    /* DCD|RI|DSR|CTS */
  576.  
  577. #else // Win32
  578.  
  579.     uchar c;
  580.     ushort state=0;
  581.     int i;
  582.     ulong l;
  583.     COMSTAT comstat;
  584.  
  585. if(rio_abort && !rio_aborted) {
  586.     ClearCommError((HANDLE)rio_handle,&l,&comstat);
  587.     if(comstat.cbInQue) {
  588.         ReadFile((HANDLE)rio_handle,&c,1,(DWORD *)&i,NULL);
  589.         if(i==1) {
  590.             if(c==3) { /* Ctrl-C */
  591.                 rio_aborted=1;
  592.                 rioctl(IOFO); }
  593.             else
  594.                 if(inbuftop<RIO_INCOM_BUFLEN)  /* don't overflow input buffer */
  595.                     inbuf[inbuftop++]=c; } } }
  596.  
  597. GetCommModemStatus((HANDLE)rio_handle,(DWORD *)&state);  /* DCD|RI|DSR|CTS */
  598. if(rio_aborted)
  599.     state|=ABORT;
  600.  
  601. #endif
  602.  
  603. return(state);
  604. }
  605.  
  606.  
  607. /************************************************************************/
  608. /************************************************************************/
  609. int rioctl(ushort action)
  610. {
  611. #ifdef __OS2__
  612.     async_dcb_t     async_dcb;
  613.     getqueue_t        getqueue;
  614.     setline_t        setline;
  615. #else // Win32
  616.     COMMPROP        commprop;
  617.     COMSTAT         comstat;
  618.     DCB             dcb;
  619.     ulong            l;
  620. #endif
  621.     uchar c;
  622.     ushort mode,w;
  623.     clock_t start;
  624.  
  625. switch(action) {
  626.     case GVERS:     /* Get version */
  627.         return(RIOLIB_VER);
  628.     case GUART:     /* Get UART I/O address, not available */
  629.         return(0xffff);
  630.     case GIRQN:     /* Get IRQ number, not available */
  631.         return((int)rio_handle);
  632.     case GBAUD:     /* Get current bit rate */
  633.         return(rio_getbaud());
  634.     case RXBC:        /* Get receive buffer count */
  635. #ifndef __OS2__ // Win32
  636.         ClearCommError((HANDLE)rio_handle,&l,&comstat);
  637.         return(comstat.cbInQue+inbufcnt());
  638. #endif
  639.         /* Fall-through if OS/2 */
  640.     case RXBS:        /* Get receive buffer size */
  641. #ifdef __OS2__
  642.         DosDevIOCtl(rio_handle
  643.             ,IOCTL_ASYNC, 0x68 /* Query # of chars in rx queue */
  644.             ,NULL
  645.             ,0
  646.             ,NULL
  647.             ,&getqueue
  648.             ,sizeof(getqueue)
  649.             ,NULL);
  650.         if(action==RXBC)
  651.             return(getqueue.cur+inbufcnt());
  652.         /* RXBS */
  653.         return(getqueue.max+RIO_INCOM_BUFLEN);
  654. #else
  655.         GetCommProperties((HANDLE)rio_handle,&commprop);
  656.         return(commprop.dwCurrentRxQueue+RIO_INCOM_BUFLEN);
  657. #endif
  658.     case TXBC:        /* Get transmit buffer count */
  659. #ifndef __OS2__ // Win32
  660.         ClearCommError((HANDLE)rio_handle,&l,&comstat);
  661.         return(comstat.cbOutQue+outbufcnt());
  662. #endif
  663.         /* Fall-through if OS/2 */
  664.     case TXBS:        /* Get transmit buffer size */
  665.     case TXBF:        /* Get transmit buffer free space */
  666. #ifdef __OS2__
  667.         DosDevIOCtl(rio_handle
  668.             ,IOCTL_ASYNC, 0x69    /* Query # of chars in tx queue */
  669.             ,NULL
  670.             ,0
  671.             ,NULL
  672.             ,&getqueue
  673.             ,sizeof(getqueue)
  674.             ,NULL);
  675.         if(action==TXBC)
  676.             return(getqueue.cur+outbufcnt());
  677.         else if(action==TXBS)
  678.             return(getqueue.max+RIO_OUTCOM_BUFLEN);
  679.         /* TXBF */
  680.         return((getqueue.max-getqueue.cur)+(RIO_OUTCOM_BUFLEN-outbufcnt()));
  681. #else
  682.         GetCommProperties((HANDLE)rio_handle,&commprop);
  683.         if(action==TXBS)
  684.             return(commprop.dwCurrentTxQueue+RIO_OUTCOM_BUFLEN);
  685.         /* TXBF */
  686.         ClearCommError((HANDLE)rio_handle,&l,&comstat);
  687.         return((commprop.dwCurrentTxQueue-comstat.cbOutQue)
  688.             +(RIO_OUTCOM_BUFLEN-outbufcnt()));
  689. #endif
  690.     case IOSTATE:
  691.         return(rio_getstate());
  692.     case IOFI:        /* Flush input buffer */
  693.     case IOFO:        /* Flush output buffer */
  694.     case IOFB:        /* Flush both buffers */
  695. #ifdef __OS2__
  696.         c=0;
  697.         if((action&IOFI)==IOFI) {
  698.             DosDevIOCtl(rio_handle
  699.                 ,IOCTL_GENERAL, DEV_FLUSHINPUT
  700.                 ,&c
  701.                 ,sizeof(char)
  702.                 ,NULL
  703.                 ,&w
  704.                 ,sizeof(short)
  705.                 ,NULL);
  706.             inbufbot=inbuftop=0;
  707.             }       /* Clear our input buffer too */
  708.         c=0;
  709.         if((action&IOFO)==IOFO) {
  710.             DosDevIOCtl(rio_handle
  711.                 ,IOCTL_GENERAL, DEV_FLUSHOUTPUT
  712.                 ,&c
  713.                 ,sizeof(char)
  714.                 ,NULL
  715.                 ,&w
  716.                 ,sizeof(short)
  717.                 ,NULL);
  718.             outbufbot=outbuftop=0;
  719.             }     /* Clear our output buffer too */
  720. #else // Win32
  721.         l=0;
  722.         if((action&IOFI)==IOFI)
  723.             l|=(PURGE_RXABORT|PURGE_RXCLEAR);
  724.         if((action&IOFO)==IOFO)
  725.             l|=(PURGE_TXABORT|PURGE_TXCLEAR);
  726.         PurgeComm((HANDLE)rio_handle,l);
  727. #endif
  728.         return(rio_getstate());
  729.     case LFN81:
  730.     case LFE71:
  731. #ifdef __OS2__
  732.         setline.stop=0; /* 1 stop bit */
  733.         if(action==LFN81) {
  734.             setline.data=8;
  735.             setline.parity=0; } /* No parity */
  736.         else {
  737.             setline.data=7;
  738.             setline.parity=2; } /* Even parity */
  739.         DosDevIOCtl(rio_handle
  740.             ,IOCTL_ASYNC, 0x42    /* Set Line Characteristics */
  741.             ,&setline
  742.             ,sizeof(setline)
  743.             ,NULL
  744.             ,NULL
  745.             ,0
  746.             ,NULL);
  747. #else // Win32
  748.         GetCommState((HANDLE)rio_handle,&dcb);
  749.         if(action==LFN81) {
  750.             dcb.Parity=NOPARITY;
  751.             dcb.ByteSize=8;
  752.             dcb.StopBits=ONESTOPBIT; }
  753.         else {
  754.             dcb.Parity=EVENPARITY;
  755.             dcb.ByteSize=7;
  756.             dcb.StopBits=ONESTOPBIT; }
  757.         SetCommState((HANDLE)rio_handle,&dcb);
  758. #endif
  759.         return(0);
  760.     case FIFOCTL:
  761. #ifdef __OS2__
  762.         DosDevIOCtl(rio_handle
  763.             ,IOCTL_ASYNC, 0x73    /* Query Device Control Block (DCB) Parms */
  764.             ,NULL
  765.             ,0
  766.             ,NULL
  767.             ,&async_dcb
  768.             ,sizeof(async_dcb)
  769.             ,NULL);
  770.  
  771.         /* Extended Hardware Buffering (16550 FIFO) */
  772.         if(async_dcb.flags3&(1<<4)) {                    /* Supported */
  773.             c=0xc0;
  774.             if(async_dcb.flags3&(1<<7))
  775.                 c|=0x0c;
  776.             return(c); }
  777. #else // Win32
  778.         // Not supported under Win32?
  779. #endif
  780.         return(0);
  781.     }
  782.  
  783. if((action&0xff)<=IOCM) {    /* Get/Set/Clear mode */
  784.     mode=0;
  785.  
  786. #ifdef __OS2__
  787.     DosDevIOCtl(rio_handle
  788.         ,IOCTL_ASYNC, 0x73    /* Query Device Control Block (DCB) Parms */
  789.         ,NULL
  790.         ,0
  791.         ,NULL
  792.         ,&async_dcb
  793.         ,sizeof(async_dcb)
  794.         ,NULL);
  795.     if(async_dcb.flags1&(1<<3)) /* Output CTS handshaking */
  796.         mode|=CTSCK;
  797.     if(async_dcb.flags2&(1<<0)) /* Automatic Xmit Control Flow Xon/Xoff */
  798.         mode|=PAUSE;
  799.     if(async_dcb.flags2&(1<<7)    /* RTS Input handshaking */
  800.         && !(async_dcb.flags2&(1<<6)))
  801.         mode|=RTSCK;
  802.     if(rio_abort)
  803.         mode|=ABORT;
  804.  
  805.     if(action==IOMODE)
  806.         return(mode);
  807.  
  808.     if((action&0xff)==IOCM)     /* Clear mode */
  809.         mode&=~(action&0xff00);
  810.     else                        /* Set mode */
  811.         mode|=(action&0xff00);
  812.  
  813.     if(mode&CTSCK)
  814.         async_dcb.flags1|=(1<<3);
  815.     else
  816.         async_dcb.flags1&=~(1<<3);
  817.     if(mode&PAUSE) {
  818.         async_dcb.flags2|=(1<<0);    /* xmit flow control */
  819.         async_dcb.xon_char=17;        /* Ctrl-Q */
  820.         async_dcb.xoff_char=19; }    /* Ctrl-S */
  821.     else
  822.         async_dcb.flags2&=~(1<<0);
  823.     if(mode&RTSCK) {
  824.         async_dcb.flags2|=(1<<7);
  825.         async_dcb.flags2&=~(1<<6); }
  826.     else
  827.         async_dcb.flags2&=~((1<<7)|(1<<6));
  828.     if(mode&ABORT)
  829.         rio_abort=1;
  830.     else
  831.         rio_abort=0;
  832.  
  833.     DosDevIOCtl(rio_handle
  834.         ,IOCTL_ASYNC, 0x53    /* Set Device Control Block (DCB) Parms */
  835.         ,&async_dcb
  836.         ,sizeof(async_dcb)
  837.         ,NULL
  838.         ,NULL
  839.         ,0
  840.         ,NULL);
  841.  
  842. #else // Win32
  843.  
  844.     GetCommState((HANDLE)rio_handle,&dcb);
  845.     if(dcb.fOutxCtsFlow)
  846.         mode|=CTSCK;
  847.     if(dcb.fOutX)
  848.         mode|=PAUSE;
  849.     if(dcb.fRtsControl==RTS_CONTROL_HANDSHAKE)
  850.         mode|=RTSCK;
  851.  
  852.     if(rio_abort)
  853.         mode|=ABORT;
  854.  
  855.     if(action==IOMODE)
  856.         return(mode);
  857.  
  858.     if((action&0xff)==IOCM)     /* Clear mode */
  859.         mode&=~(action&0xff00);
  860.     else                        /* Set mode */
  861.         mode|=(action&0xff00);
  862.  
  863.     if(mode&CTSCK)
  864.         dcb.fOutxCtsFlow=1;
  865.     else
  866.         dcb.fOutxCtsFlow=0;
  867.     if(mode&PAUSE) {
  868.         dcb.fOutX=1;
  869.         dcb.XonChar=17;     /* Ctrl-Q */
  870.         dcb.XoffChar=19; }    /* Ctrl-S */
  871.     else
  872.         dcb.fOutX=0;
  873.     if(mode&RTSCK)
  874.         dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
  875.     else
  876.         dcb.fRtsControl=RTS_CONTROL_ENABLE;
  877.     if(mode&ABORT)
  878.         rio_abort=1;
  879.     else
  880.         rio_abort=0;
  881.  
  882.     SetCommState((HANDLE)rio_handle,&dcb);
  883.  
  884. #endif
  885.  
  886.     return(mode); }
  887.  
  888. if((action&0xff)==IOSS) {    /* Set state */
  889.  
  890.     if(action&ABORT)
  891.         rio_aborted=1;
  892.  
  893. #ifdef __OS2__
  894.     if(action&PAUSE)
  895.         DosDevIOCtl(rio_handle
  896.             ,IOCTL_ASYNC, 0x47    /* Behave as if XOFF Received */
  897.             ,NULL
  898.             ,0
  899.             ,NULL
  900.             ,&w
  901.             ,sizeof(short)
  902.             ,NULL);
  903. #else // Win32
  904.     if(action&PAUSE)
  905.         EscapeCommFunction((HANDLE)rio_handle,SETXOFF);
  906. #endif
  907.  
  908.     return(rio_getstate()); }
  909.  
  910. if((action&0xff)==IOCS) {    /* Clear state */
  911.  
  912.     if(action&ABORT)
  913.         rio_aborted=0;
  914.  
  915. #ifdef __OS2__
  916.     if(action&PAUSE)
  917.         DosDevIOCtl(rio_handle
  918.             ,IOCTL_ASYNC, 0x48    /* Behave as if XON Received */
  919.             ,NULL
  920.             ,0
  921.             ,NULL
  922.             ,&w
  923.             ,sizeof(short)
  924.             ,NULL);
  925. #else // Win32
  926.     if(action&PAUSE)
  927.         EscapeCommFunction((HANDLE)rio_handle,SETXON);
  928. #endif
  929.     return(rio_getstate()); }
  930.  
  931. if((action&0xff)==TXSYNC) { /* Synchronize transmition */
  932.     c=action>>8;            /* Number of seconds */
  933.     w=110+(c*1000);         /* Number of milliseconds */
  934.     start=clock();
  935.     while(clock()-start<w) {
  936.         if(!outbufcnt()) {
  937. #ifdef __OS2__
  938.             DosDevIOCtl(rio_handle
  939.                 ,IOCTL_ASYNC, 0x69    /* Query # of chars in tx queue */
  940.                 ,NULL
  941.                 ,0
  942.                 ,NULL
  943.                 ,&getqueue
  944.                 ,sizeof(getqueue)
  945.                 ,NULL);
  946.             if(getqueue.cur==0)     /* Empty outbound queue */
  947.                 return(0);
  948. #else // Win32
  949.             ClearCommError((HANDLE)rio_handle,&l,&comstat);
  950.             if(comstat.cbOutQue==0) /* Empty outbound queue */
  951.                 return(0);
  952. #endif
  953.             }
  954. #ifdef __OS2__
  955.         DosSleep(1);
  956. #else // Win32
  957.         Sleep(1);
  958. #endif
  959.         }
  960.     return(1); }
  961.  
  962. return(0);
  963. }
  964.  
  965. /* End of file */
  966.