home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / BTMTSRC3.ZIP / ASYNC.C next >
C/C++ Source or Header  |  1991-10-17  |  18KB  |  869 lines

  1. /* async.c
  2. **
  3. ** Copyright (c) 1991, Chris Laforet Software/Chris Laforet
  4. ** All Rights Reserved
  5. **
  6. ** Started: 12 August 1991
  7. ** From s_fossil.c for Simplex/2 BBS: Started: 23 November 1989
  8. **
  9. ** Revision Information: $Logfile:   H:/binkley/vcs/async.c_v  $
  10. **                       $Date:   01 Sep 1991 14:32:44  $
  11. **                       $Revision:   1.0  $
  12. **
  13. */
  14.  
  15.  
  16. #define INCL_KBD 
  17. #define INCL_DOSPROCESS
  18. #define INCL_DOSFILEMGR
  19. #define INCL_DOSDEVICES
  20. #define INCL_DOSSEMAPHORES
  21.  
  22.  
  23. #include <stdio.h>
  24. #include <string.h>        
  25. #include <process.h>
  26. #include <os2.h>
  27. #include "com.h"
  28. #include "bink.h"
  29.  
  30.  
  31.  
  32. /* ----------------------- Structures for IOCTL ------------------------
  33. **            Taken from MS's OS/2 toolkit -- missing in IBM's!
  34. */
  35.  
  36. struct _dcbinfo    
  37.     {
  38.     USHORT usWriteTimeout;
  39.     USHORT usReadTimeout;
  40.     BYTE fbCtlHndShake;
  41.     BYTE fbFlowReplace;
  42.     BYTE fbTimeout;
  43.     BYTE bErrorReplacementChar;
  44.     BYTE bBreakReplacementChar;
  45.     BYTE bXONChar;
  46.     BYTE bXOFFChar;
  47.     };
  48.  
  49.  
  50. struct _linecontrol
  51.     {
  52.     BYTE bDataBits;
  53.     BYTE bParity;
  54.     BYTE bStopBits;
  55.     BYTE fTransBreak;
  56.     };
  57.  
  58.  
  59. struct _rxqueue
  60.     {
  61.     USHORT cch;
  62.     USHORT cb;
  63.     };
  64.  
  65.  
  66. struct _modemstatus
  67.     {
  68.     BYTE fbModemOn;
  69.     BYTE fbModemOff;
  70.     };
  71.  
  72.  
  73. /* -------------------- End of Structures for IOCTL -------------------- */
  74.  
  75.  
  76. #define COM_TIMEOUT                1
  77.  
  78.  
  79. HFILE com_port = (HFILE)-1;
  80. int leave_port = 0;
  81. static struct _dcbinfo save_di;
  82.  
  83.  
  84.  
  85. /* -------------------- Start of Ring Buffer Handlers -------------------- */
  86.  
  87. #define RING_STACKSIZE            2048
  88. #define RINGBUF_SIZE            1024
  89. #define READ_AHEAD                32
  90.  
  91.  
  92. int oring_stack[RING_STACKSIZE / sizeof(int)];        /* word-align the stack */
  93. int ringthread = 1;
  94. unsigned char inoringbuf[RINGBUF_SIZE];
  95. unsigned char *inoringptr;
  96. unsigned char *outoringptr;
  97. long oring_sem = 0L;            /* controls access to our oring buffer */
  98. TID oring_tid;
  99.  
  100. int iring_stack[RING_STACKSIZE / sizeof(int)];        /* word-align the stack */
  101. unsigned char iniringbuf[RINGBUF_SIZE];
  102. unsigned char *iniringptr;
  103. unsigned char *outiringptr;
  104. long iring_sem = 0L;            /* controls access to our oring buffer */
  105. TID iring_tid;
  106.  
  107. int fossil_init = 0;
  108.  
  109.  
  110. void pascal purge_oringbuf(void)
  111.     {
  112.     DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  113.     inoringptr = outoringptr = inoringbuf;
  114.     DosSemClear(&oring_sem);
  115.     }
  116.  
  117.  
  118.  
  119. int pascal write_oringbuf(unsigned char character,int checkcd)
  120.     {
  121.     int type;
  122.     int ok;
  123.  
  124.     DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  125.     if (inoringptr != outoringptr)
  126.         {
  127.         type = 0;
  128.         if ((inoringptr < outoringptr) && ((inoringptr + 1) == outoringptr))
  129.             type = 1;
  130.         else if ((outoringptr == inoringbuf) && (inoringptr == (inoringbuf + (RINGBUF_SIZE - 1))))    /* no room in the buffer */
  131.             type = 2;
  132.  
  133.         if (type)
  134.             {
  135.             ok = 0;
  136.             do
  137.                 {
  138.                 DosSemClear(&oring_sem);
  139.                 if (checkcd && !com_online())            /* CD still there? */
  140.                     return 0;
  141.                 DosSleep(10L);
  142.                 DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  143.                 if (type == 1 && ((inoringptr + 1) != outoringptr))
  144.                     ok = 1;
  145.                 else if (type == 2 && outoringptr != inoringbuf)
  146.                     ok = 1;
  147.                 }
  148.             while (!ok);
  149.             }
  150.         }
  151.     *(unsigned char*)inoringptr = character;
  152.     ++inoringptr;
  153.     if (inoringptr >= (inoringbuf + RINGBUF_SIZE))
  154.         inoringptr = inoringbuf;
  155.     DosSemClear(&oring_sem);
  156.     return 1;
  157.     }
  158.  
  159.  
  160.  
  161. void oring_handler(void far *dummy)
  162.     {
  163.     unsigned char buffer[READ_AHEAD];
  164.     int written;
  165.     int current;
  166.     int slice = 0;
  167.     int send;
  168.     int left;
  169.  
  170.     DosSetPrty(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,PRTYD_MINIMUM,oring_tid);
  171.     while (ringthread)
  172.         {
  173.         if (com_port != (HFILE)-1)
  174.             {
  175.             if (inoringptr != outoringptr)
  176.                 {
  177.                 DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  178.  
  179.                 /* send a char */
  180.                 send = 0;
  181.                 do
  182.                     {
  183.                     buffer[send++] = (unsigned char)*outoringptr;
  184.                     ++outoringptr;
  185.                     if (outoringptr >= (inoringbuf + RINGBUF_SIZE))
  186.                         outoringptr = inoringbuf;
  187.                     }
  188.                 while (send < READ_AHEAD && inoringptr != outoringptr);
  189.                 DosSemClear(&oring_sem);
  190.  
  191.                 if (send)
  192.                     {
  193.                     current = 0;
  194.                     left = send - current;
  195.                     do
  196.                         {
  197.                         DosWrite(com_port,buffer + current,left,&written);
  198.                         if (written)
  199.                             {
  200.                             current += written;
  201.                             left = send - current;
  202.                             }
  203.                         if (written != left)
  204.                             {
  205.                             if (!ringthread)
  206.                                 break;
  207.                             if (slice >= 20)
  208.                                 {
  209.                                 DosSleep(1L);
  210.                                 slice = 0;
  211.                                 }
  212.                             else
  213.                                 ++slice;
  214.                             }
  215.                         }
  216.                     while (current < send);
  217.                     }
  218.                 }
  219.             else
  220.                 DosSleep(1L);
  221.             }
  222.         else
  223.             DosSleep(30L);
  224.         }
  225.     _endthread();
  226.     }
  227.  
  228.  
  229.  
  230. void pascal purge_iringbuf(void)
  231.     {
  232.     DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  233.     iniringptr = outiringptr = iniringbuf;
  234.     DosSemClear(&iring_sem);
  235.     }
  236.  
  237.  
  238.  
  239. int pascal peek_iringbuf(void)
  240.     {
  241.     int rtn;
  242.  
  243.     if (iniringptr == outiringptr)
  244.         rtn = -1;
  245.     else
  246.         rtn = (int)*(unsigned char *)outiringptr;
  247.     return rtn;
  248.     }
  249.  
  250.  
  251.  
  252. int pascal read_iringbuf(void)
  253.     {
  254.     int rtn = -1;
  255.  
  256.     DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  257.     if (iniringptr != outiringptr)
  258.         {
  259.         rtn = (int)*(unsigned char *)outiringptr;
  260.         ++outiringptr;
  261.         if (outiringptr >= (iniringbuf + RINGBUF_SIZE))
  262.             outiringptr = iniringbuf;
  263.         }
  264.     DosSemClear(&iring_sem);
  265.     return rtn;
  266.     }
  267.  
  268.  
  269.  
  270. void iring_handler(void far *dummy)
  271.     {
  272.     unsigned char buffer[READ_AHEAD];
  273.     int current;
  274.     int bytesread;
  275.     int type;
  276.     int ok;
  277.  
  278.     DosSetPrty(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,PRTYD_MINIMUM,iring_tid);
  279.     while (ringthread)
  280.         {
  281.         if (com_port != (HFILE)-1)
  282.             {
  283.             DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  284.             DosRead(com_port,buffer,READ_AHEAD,&bytesread);
  285.             if (bytesread)
  286.                 {
  287.                 current = 0;
  288.                 do
  289.                     {
  290.                     if (iniringptr != outiringptr)
  291.                         {
  292.                         type = 0;
  293.                         if ((iniringptr < outiringptr) && ((iniringptr + 1) == outiringptr))
  294.                             type = 1;
  295.                         else if ((outiringptr == iniringbuf) && (iniringptr == (iniringbuf + (RINGBUF_SIZE - 1))))    /* no room in the buffer */
  296.                             type = 2;
  297.  
  298.                         if (type)
  299.                             {
  300.                             ok = 0;
  301.                             do
  302.                                 {
  303.                                 DosSemClear(&iring_sem);
  304.                                 DosSleep(1L);
  305.                                 DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  306.                                 if (type == 1 && ((iniringptr + 1) != outiringptr))
  307.                                     ok = 1;
  308.                                 else if (type == 2 && outiringptr != iniringbuf)
  309.                                     ok = 1;
  310.                                 }
  311.                             while (!ok);
  312.                             }
  313.                         }
  314.                     *(unsigned char*)iniringptr = buffer[current];
  315.                     ++iniringptr;
  316.                     if (iniringptr >= (iniringbuf + RINGBUF_SIZE))
  317.                         iniringptr = iniringbuf;
  318.                     ++current;
  319.                     }
  320.                 while (current < bytesread);
  321.                 DosSemClear(&iring_sem);
  322.                 }
  323.             else
  324.                 {
  325.                 DosSemClear(&iring_sem);
  326.                 DosSleep(1L);
  327.                 }
  328.             }
  329.         else
  330.             DosSleep(30L);
  331.         }
  332.     _endthread();
  333.     }
  334.  
  335.  
  336.  
  337. int start_ringthread(void)
  338.     {
  339.     iniringptr = outiringptr = iniringbuf;        /* start input ring thread */
  340.     DosSemClear(&iring_sem);
  341.     if ((iring_tid = _beginthread(iring_handler,iring_stack,RING_STACKSIZE,NULL)) == -1)
  342.         return 0;
  343.  
  344.     inoringptr = outoringptr = inoringbuf;        /* start output ring thread */
  345.     DosSemClear(&oring_sem);
  346.     if ((oring_tid = _beginthread(oring_handler,oring_stack,RING_STACKSIZE,NULL)) == -1)
  347.         return 0;
  348.     return 1;
  349.     }
  350.  
  351.  
  352.  
  353. void hold_comthread(void)
  354.     {
  355.     DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  356.     DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  357.     }
  358.  
  359.  
  360.  
  361. void restart_comthread(void)
  362.     {
  363.     DosSemClear(&iring_sem);
  364.     DosSemClear(&oring_sem);
  365.     }
  366.  
  367.  
  368. /* -------------------- End of Ring Buffer Handlers -------------------- */
  369.  
  370.  
  371.  
  372. /* com_init() : Intialize communications port. Baud rate is preserved.
  373. **              int port    : Hardware port (0 based) to init
  374. **      -OR-    char *unc    : Full UNC \\networkId\modemId to init.
  375. **
  376. ** if unc == NULL, port is used. if unc != NULL, unc is used
  377. */
  378.  
  379. int com_init(int port,char *unc)
  380.     {
  381.     struct _dcbinfo di;
  382.     struct _modemstatus ms;
  383.     UCHAR szBuffer[5];
  384.     USHORT action;
  385.     USHORT error;
  386.  
  387.     if (com_port == -1)
  388.         {
  389.         if (!fossil_init)        /* print sign-on ONLY the first time we start up */
  390.             {
  391.             fprintf(stderr,"\n\nLow-level OS/2 communications interface routines for Binkleyterm-OS/2.\n");
  392.             fprintf(stderr,"Copyright (c) 1991, Chris Laforet and Chris Laforet Software (1:151/402).\n\n");
  393.             fossil_init = 1;
  394.             }
  395.  
  396.         DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  397.         DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  398.         if (!unc)
  399.             {
  400.             sprintf(szBuffer,"com%u",port + 1);
  401.             unc = szBuffer;
  402.             }
  403.         if (DosOpen(unc,&com_port,&action,0L,FILE_NORMAL,FILE_OPEN,OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE,0L))
  404.             {
  405.             DosSemClear(&oring_sem);
  406.             DosSemClear(&iring_sem);
  407.             return 0;                /* failed port open */
  408.             }
  409.  
  410.         DosDevIOCtl(&di,0L,0x73,1,com_port);
  411.         if (!leave_port)
  412.             {
  413.             di.fbFlowReplace = (BYTE)0x40;    /* flip RTS Control mode on */
  414.             di.fbCtlHndShake = (BYTE)0x8;    /* enable CTS control */
  415.             }
  416.         else
  417.             {
  418.                memcpy(&di,&save_di,sizeof(struct _dcbinfo));
  419.             di.fbFlowReplace &= ~0x3;        /* Turn off XON/XOFF automatic input and output flow control */
  420.             }
  421.  
  422.         di.usWriteTimeout = COM_TIMEOUT;
  423.         di.usReadTimeout = COM_TIMEOUT;
  424.         di.fbTimeout &= 0xfa;            /* kill no write timeout and wait read timeout -- LEAVE hardware buffering */
  425.         di.fbTimeout = (BYTE)2;         /* read timeout */
  426.         di.fbCtlHndShake |= (BYTE)1;      /* enable dtr control */
  427.         DosDevIOCtl(0L,&di,0x53,1,com_port);
  428.  
  429.         ms.fbModemOn = 0x2;            /* flip RTS on */
  430.         ms.fbModemOff = 0xff;
  431.         DosDevIOCtl(&error,&ms,0x46,1,com_port);        /* set modem control */
  432.  
  433.         iniringptr = outiringptr = iniringbuf;
  434.         inoringptr = outoringptr = inoringbuf;
  435.         DosSemClear(&oring_sem);
  436.         DosSemClear(&iring_sem);
  437.         return 1;
  438.         }
  439.     else
  440.         return 0;
  441.     }
  442.  
  443.  
  444.  
  445. int com_fini(void)            /* close port */
  446.     {
  447.     struct _dcbinfo di;
  448.     struct _modemstatus ms;
  449.     USHORT error;
  450.  
  451.     if (com_port != (HFILE)-1)
  452.         {
  453.         DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  454.         DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  455.  
  456.         if (com_port != -1)
  457.             {
  458.             if (!leave_port)
  459.                 {
  460.                 DosDevIOCtl(&di,0L,0x73,1,com_port);
  461.                 di.usWriteTimeout = COM_TIMEOUT;
  462.                 di.usReadTimeout = COM_TIMEOUT;
  463.                 di.fbCtlHndShake = (BYTE)8;        /* enable dtr control and CTS control mode */
  464.                 di.fbFlowReplace = (BYTE)0x40;    /* flip RTS Control mode on */
  465.                 di.fbTimeout &= 0xfa;            /* kill no write timeout and wait read timeout -- LEAVE hardware buffering */
  466.                 di.fbTimeout = (BYTE)2;         /* read timeout */
  467.                 DosDevIOCtl(0L,&di,0x53,1,com_port);
  468.                 }
  469.             else 
  470.                 DosDevIOCtl(0L,&save_di,0x53,1,com_port);
  471.             }
  472.         raise_dtr();
  473.  
  474.         ms.fbModemOn = 0x2;            /* flip RTS on */
  475.         ms.fbModemOff = 0xff;
  476.         DosDevIOCtl(&error,&ms,0x46,1,com_port);        /* set modem control */
  477.  
  478.         DosClose(com_port);
  479.         com_port = (HFILE)-1;
  480.  
  481.         iniringptr = outiringptr = iniringbuf;
  482.         inoringptr = outoringptr = inoringbuf;
  483.         DosSemClear(&oring_sem);
  484.         DosSemClear(&iring_sem);
  485.         return 1;
  486.         }
  487.     return 0;
  488.     }
  489.  
  490.  
  491.  
  492. int Cominit(int port)            /* Fitzsimmons' or Andrus' code */
  493.     {
  494.     if (com_port != (HFILE)-1)
  495.         com_fini();
  496.     if (port == 0xff || com_init(port,NULL))
  497.         return 0x1954;
  498.     return 0;
  499.     }
  500.  
  501.  
  502.  
  503. void raise_dtr(void)
  504.     {
  505.     struct _modemstatus ms;
  506.     USHORT error;
  507.  
  508.     ms.fbModemOn = 0x1;            /* DTR on */
  509.     ms.fbModemOff = 0xff;
  510.     DosDevIOCtl(&error,&ms,0x46,1,com_port);
  511.     }
  512.  
  513.  
  514.  
  515. void lower_dtr(void)
  516.     {
  517.     struct _modemstatus ms;
  518.     USHORT error;
  519.  
  520.     ms.fbModemOn = 0x0;
  521.     ms.fbModemOff = 0xfe;            /* DTR off */
  522.     DosDevIOCtl(&error,&ms,0x46,1,com_port);
  523.     }
  524.  
  525.  
  526.  
  527. int com_set_baud(unsigned int baud,char parity,int databits,int stopbits)
  528.     {
  529.     struct _linecontrol lc;
  530.     int rtn = 1;
  531.  
  532.     DosSemRequest(&iring_sem,SEM_INDEFINITE_WAIT);
  533.     DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  534.  
  535.     if (DosDevIOCtl(0L,&baud,0x41,1,com_port))
  536.         rtn = 0;
  537.     else
  538.         {
  539.         lc.bDataBits = (BYTE)databits;
  540.         switch (stopbits)
  541.             {
  542.             case 1:
  543.                 lc.bStopBits = 0;
  544.                 break;
  545.             case 2:
  546.                 lc.bStopBits = 2;
  547.                 break;
  548.             default:
  549.                 if (databits == 5)
  550.                     lc.bStopBits = 1;
  551.                 else 
  552.                     lc.bStopBits = 0;
  553.             }
  554.         lc.fTransBreak = 0;
  555.         switch (parity)
  556.             {
  557.             case 'O':
  558.             case 'o':
  559.                 lc.bParity = 1;
  560.                 break;
  561.             case 'E':
  562.             case 'e':
  563.                 lc.bParity = 2;
  564.                 break;
  565.             case 'M':
  566.             case 'm':
  567.                 lc.bParity = 3;
  568.                 break;
  569.             case 'S':
  570.             case 's':
  571.                 lc.bParity = 4;
  572.                 break;
  573.             default:            /* default to N parity */
  574.                 lc.bParity = 0;
  575.                 break;
  576.             }
  577.         if (DosDevIOCtl(0L,&lc,0x42,1,com_port))
  578.             rtn = 0;
  579.         }
  580.  
  581.     DosSemClear(&oring_sem);
  582.     DosSemClear(&iring_sem);
  583.     return rtn;
  584.     }
  585.  
  586.  
  587.  
  588. void com_XON_disable(void)
  589.     {
  590.     struct _dcbinfo di;
  591.  
  592.     DosDevIOCtl(&di,0L,0x73,1,com_port);
  593.     di.fbFlowReplace &= ~0x3;        /* Turn off XON/XOFF automatic input and output flow control */
  594.     DosDevIOCtl(0L,&di,0x53,1,com_port);
  595.     }
  596.  
  597.  
  598.  
  599. void com_XON_enable(void)
  600.     {
  601.     struct _dcbinfo di;
  602.  
  603.     DosDevIOCtl(&di,0L,0x73,1,com_port);
  604.     di.fbFlowReplace |= 0x3;        /* Turn on XON/XOFF automatic input and output flow control */
  605.     di.bXOFFChar = (char)0x13;
  606.     di.bXONChar = (char)0x11;
  607.     DosDevIOCtl(0L,&di,0x53,1,com_port);
  608.     }
  609.  
  610.  
  611.  
  612. /* com_break() : start break if on==TRUE, stop break if on==FALSE */
  613.  
  614. void com_break(int cmd)
  615.     {
  616.     USHORT err;
  617.  
  618.     if (cmd == 1)
  619.         DosDevIOCtl(&err,0L,0x4b,1,com_port);    /* setbreakon */
  620.     else 
  621.         DosDevIOCtl(&err,0L,0x45,1,com_port);    /* setbreakoff */
  622.     }
  623.  
  624.  
  625.  
  626. /* return non-0 value if carrier detected */
  627.  
  628. int pascal com_online(void)
  629.     {
  630.     USHORT flags;
  631.  
  632.     DosDevIOCtl(&flags,0L,0x67,1,com_port);        /* get modem input */
  633.     if (flags & 0x80)        /* DCD on? */
  634.         return RLSD;
  635.     return 0;
  636.     }
  637.  
  638.  
  639.  
  640. void com_clear_in(void)
  641.     {
  642.     purge_iringbuf();
  643.     DosDevIOCtl(0L,0L,0x1,0xb,com_port);        /* dev flush input */
  644.     }
  645.  
  646.  
  647.  
  648. void com_clear_out(void)
  649.     {
  650.     purge_oringbuf();
  651.     DosDevIOCtl(0L,0L,0x2,0xb,com_port);        /* dev flush output */
  652.     }
  653.  
  654.  
  655. /* com_putc_now() : disregard any buffering and send a byte now damnit!
  656. ** this function should be called only during emergencies...like when
  657. ** trying to cancel a file transfer
  658. **
  659. ** Since the equivalent is a Com_ call, which in DOS is unsigned...
  660. */
  661.  
  662. unsigned int pascal com_putc_now(unsigned char c)
  663.     {
  664.     if (DosDevIOCtl(0L,&c,0x44,0x1,com_port))        /* dev transmit immediately */
  665.         return 0;
  666.     return 1;
  667.     }
  668.  
  669.  
  670.  
  671. /* com_putc() : output to com port 
  672. ** This function is very slow..where possible, write to com port in blocks
  673. ** using com_write() instead...especially above 2400 bps -- Peter Fitzsimmons'
  674. ** comment.
  675. **
  676. ** CML - this function should not be that much slower. 
  677. */
  678.  
  679. void pascal com_putc(unsigned char c)
  680.     {
  681.     write_oringbuf(c,0);        /* stick it into out buffer */
  682.     }
  683.  
  684.  
  685.  
  686. /* CML: Only for SPECIAL occasions. */
  687.  
  688. void pascal com_direct(unsigned char c)
  689.     {
  690.     USHORT written;
  691.  
  692.     do
  693.         {
  694.         DosWrite(com_port,&c,1,&written);
  695.         if (!written)
  696.             DosSleep(0L);
  697.         }
  698.     while (!written);
  699.     }
  700.  
  701.  
  702.  
  703. /* com_write() : buffered block write */
  704.  
  705. void pascal com_write(char *buf,int num,int checkcd)
  706.     {
  707.     int count;
  708.  
  709.     for (count = 0; count < num; count++)
  710.         {
  711.         if (!write_oringbuf((unsigned char)*buf++,checkcd))
  712.             break;
  713.         }
  714.     }
  715.  
  716.  
  717.  
  718. /* com_out_empty() : return TRUE if output buffer is empty */
  719.  
  720. int pascal com_out_empty(void)
  721.     {
  722.     struct _rxqueue rq;
  723.     int empty = 0;
  724.  
  725.     DosDevIOCtl(&rq,0L,0x69,1,com_port);
  726.     if (rq.cch <= 1)
  727.         {
  728.         if (inoringptr == outoringptr)        /* check our ring buffer */
  729.             ++empty;
  730.         }
  731.     return empty;
  732.     }
  733.  
  734.  
  735.  
  736. /* com_out_full() : return TRUE if output buffer is full */
  737.  
  738. int pascal com_out_full(void)
  739.     {
  740.     int full = 0;
  741.  
  742.     DosSemRequest(&oring_sem,SEM_INDEFINITE_WAIT);
  743.     if (inoringptr != outoringptr)
  744.         {
  745.         if ((inoringptr < outoringptr) && ((inoringptr + 1) == outoringptr))
  746.             full = 1;
  747.         else if ((outoringptr == inoringbuf) && (inoringptr == (inoringbuf + (RINGBUF_SIZE - 1))))    /* no room in the buffer */
  748.             full = 1;
  749.         }
  750.     DosSemClear(&oring_sem);
  751.     return full;
  752.     }
  753.  
  754.  
  755.  
  756. /* wait for output buffer to empty */
  757.  
  758. void com_wait(void)
  759.     {
  760.     while (com_online && !com_out_empty())
  761.        DosSleep (1L);
  762.     }
  763.  
  764.  
  765.  
  766. /* com_getchar() : return negative value if error */
  767.  
  768. int pascal com_getchar(void)
  769.     {
  770.     return read_iringbuf();
  771.     }
  772.  
  773.  
  774.  
  775. /* non destructive read ahead; no wait */
  776.  
  777. int pascal com_peek(void)
  778.     {
  779.     return peek_iringbuf();
  780.     }
  781.  
  782.  
  783.  
  784. /* if RXQueue over half full, return TRUE */
  785.  
  786. int pascal com_in_check(void)
  787.     {
  788.     struct _rxqueue rq;
  789.  
  790.     DosDevIOCtl(&rq,0L,0x68,1,com_port);
  791.     if (rq.cch >= (rq.cb >> 1))
  792.         return 1;
  793.     return 0;
  794.     }
  795.  
  796.  
  797.  
  798. /* return number of chars in input buffer */
  799.  
  800. int pascal com_char_avail(void)
  801.     {
  802.     if (iniringptr != outiringptr)
  803.         return 1;            /* this might work */
  804.     return 0;
  805.     }
  806.  
  807.  
  808.  
  809. extern int port_num;
  810. extern unsigned int baud;
  811. extern unsigned int comm_bits;
  812. extern unsigned int parity;
  813. extern unsigned int stop_bits;
  814. extern struct baud_str btypes[];
  815.  
  816.  
  817. void MDM_ENABLE(unsigned int rate)        /* this is Fitzsimmons' or Andrus' code */
  818.     {
  819.     char _parity;
  820.     int databits;
  821.     int stopbits;
  822.  
  823.     com_clear_out();
  824.     com_clear_in();
  825.     databits = 7 + (comm_bits == BITS_8);
  826.     stopbits = 1 + (stop_bits == STOP_2);
  827.     switch (parity)
  828.         {
  829.         case NO_PARITY:
  830.             _parity = 'N';
  831.             break;
  832.         case ODD_PARITY:
  833.             _parity = 'O';
  834.             break;
  835.         case EVEN_PARITY:
  836.             _parity = 'E';
  837.             break;
  838.         }
  839.     com_set_baud(rate,_parity,databits,stopbits);
  840.     }
  841.  
  842.  
  843.  
  844. void MDM_DISABLE(void)        /* this is Fitzsimmons' or Andrus' code */
  845.     {
  846.     if (com_port == -1)
  847.         return;
  848.     com_clear_out();
  849.     com_clear_in();
  850.     com_fini();
  851.     }
  852.  
  853.  
  854.  
  855. void pascal BUFFER_BYTE(unsigned char ch)
  856.     {
  857.     write_oringbuf(ch,0);
  858.     }
  859.  
  860.  
  861.  
  862. void UNBUFFER_BYTES(void)
  863.     {
  864.     /* since stuff is in another thread, the writing will occur anyway! */
  865.     }
  866.  
  867.  
  868.  
  869.