home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / comos2.zip / COMM16.C < prev    next >
C/C++ Source or Header  |  1993-02-21  |  30KB  |  1,158 lines

  1. /**************************************************************************
  2.  *
  3.  *  COMM16.C
  4.  *
  5.  *  This file contains the 16-bit routines which provide the basic
  6.  *  serial support.
  7.  *
  8.  *  This file was compiled with the MicroSoft C6.00AX compiler using the
  9.  *  following flags:
  10.  *
  11.  *    To produce a multi-thread version of the library
  12.  *      /MT /W3 /Alfu /Gt64 /G2s /FPi87 /c
  13.  *
  14.  *    To produce a single-thread version of the library
  15.  *      /W3 /Alfu /Gt64 /G2s /FPi87 /c
  16.  *_________________________________________________________________________
  17.  *
  18.  *  Copyright (c) 1992 by ASH Software, Inc.
  19.  *
  20.  *  Update History
  21.  *
  22.  *    11/28/1992 - Module created
  23.  *
  24.  **************************************************************************/
  25.  
  26. #define INCL_COMMOS2_16BIT
  27. #include "COMM.H"
  28.  
  29. /*------------------------------------------------------------------------*
  30.  *  CommStartSystem
  31.  *
  32.  *  This routine initializes the comm library.  This routine must be
  33.  *  called before other routines in the comm library and must specify the
  34.  *  maximum number of ports to be handled by the library.
  35.  *------------------------------------------------------------------------*/
  36.  
  37. ULONG CommStartSystem(int iCommPorts)
  38. {
  39. ULONG
  40.   ulRC;
  41.  
  42. int
  43.   iLoop;
  44.  
  45. PCOMMOS2_STRUCT
  46.   pCommStruct;
  47.  
  48. if (iCommPorts <= 0)
  49.   return COMM_ERROR_INVALIDMAXPORTS;      // Invalid number of ports
  50.  
  51. iLoop=TRUE;
  52.  
  53. hCommSem.cb     = sizeof(DOSFSRSEM);
  54. hCommSem.pid    = 0;
  55. hCommSem.tid    = 0;
  56. hCommSem.cUsage = 0;
  57. hCommSem.client = 0;
  58. hCommSem.sem    = 0;
  59.  
  60. ulRC=(ULONG)DosFSRamSemRequest(&hCommSem,COMMOS2_RESOURCE_SEM_WAIT);
  61. if (ulRC)
  62.   return COMM_ERROR_SEMAPHOREFAILED;
  63.  
  64. if (iMaxNumberCommPorts > 0)
  65.   iLoop=FALSE;
  66. else
  67.   iMaxNumberCommPorts = iCommPorts;
  68.  
  69. if (!iLoop)
  70.   {
  71.   DosFSRamSemClear(&hCommSem);
  72.   return COMM_ERROR_ALREADYINITIALIZED;   // System already initialized
  73.   }
  74.  
  75. pCommOS2Struct=malloc(iCommPorts*sizeof(COMMOS2_STRUCT));
  76. if (pCommOS2Struct == NULL)
  77.   {
  78.   DosFSRamSemClear(&hCommSem);
  79.   return COMM_ERROR_SYSINITFAILED;        // Unable to allocate resources
  80.   }
  81.  
  82. //
  83. // Initialize the COMM structure
  84. //
  85.  
  86. for (iLoop=0; iLoop<iCommPorts; iLoop++)
  87.   {
  88.   pCommStruct                       = &pCommOS2Struct[iLoop];
  89.   pCommStruct->ulCommErrorCode      = COMM_ERROR_NOERROR;
  90.   pCommStruct->ulDosErrorCode       = NO_ERROR;
  91.   pCommStruct->hCommPortFile        = 0;
  92.   pCommStruct->ulCommMode           = COMM_MODE_NOTSTARTED;
  93.   pCommStruct->fPortOpen            = FALSE;
  94.   pCommStruct->fPortOpened          = FALSE;
  95.   pCommStruct->hCommWriteSem.cb     = sizeof(DOSFSRSEM);
  96.   pCommStruct->hCommWriteSem.pid    = 0;
  97.   pCommStruct->hCommWriteSem.tid    = 0;
  98.   pCommStruct->hCommWriteSem.cUsage = 0;
  99.   pCommStruct->hCommWriteSem.client = 0;
  100.   pCommStruct->hCommWriteSem.sem    = 0;
  101.   pCommStruct->hCommReadSem.cb      = sizeof(DOSFSRSEM);
  102.   pCommStruct->hCommReadSem.pid     = 0;
  103.   pCommStruct->hCommReadSem.tid     = 0;
  104.   pCommStruct->hCommReadSem.cUsage  = 0;
  105.   pCommStruct->hCommReadSem.client  = 0;
  106.   pCommStruct->hCommReadSem.sem     = 0;
  107.   }
  108.  
  109. DosFSRamSemClear(&hCommSem);
  110. return COMM_ERROR_NOERROR;
  111. }
  112.  
  113. /*------------------------------------------------------------------------*
  114.  *  CommStopSystem
  115.  *
  116.  *  This system frees the resources used when initializing the comm
  117.  *  library and closes any open ports.  This should be called when the 
  118.  *  comm library is no longer needed or during program termination.
  119.  *------------------------------------------------------------------------*/
  120.  
  121. ULONG CommStopSystem(void)
  122. {
  123. int
  124.   iLoop;
  125.  
  126. if (pCommOS2Struct != NULL)
  127.   {
  128.   for (iLoop=0; iLoop<iMaxNumberCommPorts; iLoop++)
  129.     CommClose(iLoop);
  130.  
  131.   free(pCommOS2Struct);
  132.   }
  133. iMaxNumberCommPorts = 0;
  134.  
  135. return COMM_ERROR_NOERROR;
  136. }
  137.  
  138. /*------------------------------------------------------------------------*
  139.  *  CommGetLastError
  140.  *
  141.  *  This routine returns information concerning the last error for the
  142.  *  requested comm port.
  143.  *------------------------------------------------------------------------*/
  144.  
  145. ULONG CommGetLastError(HCOMMPORT hCommPort,ULONG *ulCommError,
  146.   ULONG *ulDosError,ULONG *ulCommMode)
  147. {
  148. PCOMMOS2_STRUCT
  149.   pCommStruct;
  150.  
  151. pCommStruct=CommGetStruct(hCommPort);
  152.  
  153. if (pCommStruct == NULL)
  154.   return COMM_ERROR_PORTNOTFOUND;   // Unable to locate comm port
  155.  
  156. (*ulCommError) = pCommStruct->ulCommErrorCode;
  157. (*ulDosError)  = pCommStruct->ulDosErrorCode;
  158. (*ulCommMode)  = pCommStruct->ulCommMode;
  159.  
  160. return COMM_ERROR_NOERROR;
  161. }
  162.  
  163. /*------------------------------------------------------------------------*
  164.  *  CommOpen
  165.  *
  166.  *  This routine invokes DosOpen to open the specified serial comm port.
  167.  *  The error return is the same as for DosOpen.
  168.  *------------------------------------------------------------------------*/
  169.  
  170. ULONG CommOpen(int iCommPort,PHCOMMPORT phCommPort)
  171. {
  172. int
  173.   iLoop,
  174.   fKeepLooping;
  175.  
  176. USHORT
  177.   usAction;
  178.  
  179. ULONG
  180.   ulRC;
  181.  
  182. char
  183.   cPortName[21];
  184.  
  185. PCOMMOS2_STRUCT
  186.   pCommStruct;
  187.  
  188. LINECONTROL
  189.   COMParams;
  190.  
  191. //
  192. // Find an empty location in the static structure.
  193. // Use a Fast Safe Ram semaphore to serialize access.
  194. //
  195.  
  196. ulRC=(ULONG)DosFSRamSemRequest(&hCommSem,COMMOS2_RESOURCE_SEM_WAIT);
  197. if (ulRC)
  198.   {
  199.   return COMM_ERROR_SEMAPHOREFAILED;
  200.   }
  201.  
  202. fKeepLooping=TRUE;
  203. iLoop=0;
  204. pCommStruct=NULL;
  205. while(fKeepLooping)
  206.   {
  207.   if (pCommOS2Struct[iLoop].fPortOpened)
  208.     {
  209.     iLoop++;
  210.     if (iLoop == iMaxNumberCommPorts)
  211.       fKeepLooping=FALSE;
  212.     }
  213.   else
  214.     {
  215.     pCommStruct=&pCommOS2Struct[iLoop];
  216.     fKeepLooping=FALSE;
  217.     pCommStruct->fPortOpened=TRUE;
  218.     *phCommPort=iLoop;
  219.     }
  220.   }
  221. DosFSRamSemClear(&hCommSem);
  222.  
  223. if (pCommStruct == NULL)
  224.   return COMM_ERROR_MAXPORTSEXCEEDED;  // Max number of comm ports exceeded
  225.  
  226. sprintf(cPortName,"COM%d",iCommPort);
  227. ulRC=(ULONG)DosOpen(cPortName,&(pCommStruct->hCommPortFile),&usAction,0L,
  228.        FILE_NORMAL,FILE_OPEN,
  229.        OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE,
  230.        0L);
  231.  
  232. if (ulRC)
  233.   {
  234.   pCommStruct->ulCommErrorCode = COMM_ERROR_OPENFAILED;
  235.   pCommStruct->ulDosErrorCode  = ulRC;
  236.   pCommStruct->hCommPortFile   = -1;
  237.   pCommStruct->ulCommMode      = COMM_MODE_OPEN;
  238.   return COMM_ERROR_OPENFAILED;
  239.   }
  240. else
  241.   {
  242.   pCommStruct->ulCommErrorCode = COMM_ERROR_NOERROR;
  243.   pCommStruct->ulDosErrorCode  = NO_ERROR;
  244.   pCommStruct->ulCommMode      = COMM_MODE_OPEN;
  245.   pCommStruct->fPortOpen       = TRUE;
  246.   }
  247.  
  248. //
  249. // Initialize the DCB structure
  250. //
  251.  
  252. ulRC=CommGetDCBInfo(*phCommPort);
  253. if (ulRC)
  254.   return COMM_ERROR_DCBINFOFAILED;
  255. pCommStruct->DCBOriginal=pCommStruct->DCBInfo;
  256.  
  257. //
  258. // Initialize other parameters
  259. //
  260.  
  261. ulRC=(ULONG)DosDevIOCtl(&COMParams,NULL,
  262.        ASYNC_GETLINECTRL,IOCTL_ASYNC,pCommStruct->hCommPortFile);
  263. pCommStruct->usDataBits = COMParams.bDataBits;
  264. pCommStruct->usParity   = COMParams.bParity;
  265. pCommStruct->usStopBits = COMParams.bStopBits;
  266. pCommStruct->usTxBreak  = COMParams.fTransBreak;
  267. if (ulRC)
  268.   return COMM_ERROR_BAUDFAILED;
  269.  
  270. ulRC=(ULONG)DosDevIOCtl(&(pCommStruct->usBaudRate),NULL,
  271.        ASYNC_GETBAUDRATE,IOCTL_ASYNC,pCommStruct->hCommPortFile);
  272. if (ulRC)
  273.   return COMM_ERROR_BAUDFAILED;
  274.  
  275. return COMM_ERROR_NOERROR;
  276. }
  277.  
  278. /*------------------------------------------------------------------------*
  279.  *  CommInit
  280.  *
  281.  *  This routine initializes a serial comm port by calling the
  282.  *  DosDevIOCtl routine with the proper parameters.
  283.  *------------------------------------------------------------------------*/
  284.  
  285. ULONG CommInit(HCOMMPORT hCommPort,USHORT usBaudRate,
  286.          USHORT usParity,USHORT usDataBits,
  287.          USHORT usStopBits,USHORT usTxBreak)
  288. {
  289. ULONG
  290.   ulParmLength,
  291.   ulRC;
  292.  
  293. LINECONTROL
  294.   COMParams;
  295.  
  296. PCOMMOS2_STRUCT
  297.   pCommStruct;
  298.  
  299. //
  300. // Set the baud rate
  301. //
  302.  
  303. pCommStruct=CommGetStruct(hCommPort);
  304. ulRC=(ULONG)DosDevIOCtl(NULL,&usBaudRate,
  305.        ASYNC_SETBAUDRATE,IOCTL_ASYNC,pCommStruct->hCommPortFile);
  306. if (ulRC)
  307.   {
  308.   pCommStruct->ulCommErrorCode = COMM_ERROR_BAUDFAILED;
  309.   pCommStruct->ulDosErrorCode  = ulRC;
  310.   pCommStruct->ulCommMode      = COMM_MODE_SETBAUD;
  311.   return COMM_ERROR_BAUDFAILED;
  312.   }
  313.  
  314. //
  315. // Set the number of bits, parity, stop bits, and Transmit break
  316. //
  317.  
  318. COMParams.bDataBits  =(UCHAR)usDataBits;  // Set data bits
  319. COMParams.bParity    =(UCHAR)usParity;    // Set parity
  320. COMParams.bStopBits  =(UCHAR)usStopBits;  // Set stop bits
  321. COMParams.fTransBreak=(UCHAR)usTxBreak;   // Set Transmit break
  322. ulParmLength=sizeof(LINECONTROL);
  323.  
  324. ulRC=(ULONG)DosDevIOCtl(NULL,&COMParams,
  325.        ASYNC_SETLINECTRL,IOCTL_ASYNC,pCommStruct->hCommPortFile);
  326. if (ulRC)
  327.   {
  328.   pCommStruct->ulCommErrorCode = COMM_ERROR_LINECNTRLFAILED;
  329.   pCommStruct->ulDosErrorCode  = ulRC;
  330.   pCommStruct->ulCommMode      = COMM_MODE_SETLINECNTRL;
  331.   return COMM_ERROR_LINECNTRLFAILED;
  332.   }
  333.  
  334. return COMM_ERROR_NOERROR;
  335. }
  336.  
  337. /*------------------------------------------------------------------------*
  338.  *  CommClear
  339.  *
  340.  *  This routine clears both the transmit and receive buffers for the
  341.  *  com port
  342.  *------------------------------------------------------------------------*/
  343.  
  344. ULONG CommClear(HCOMMPORT hCommPort)
  345. {
  346. ULONG
  347.   ulRC;
  348.  
  349. ulRC=CommClearTxBuffer(hCommPort);
  350. if (!ulRC)
  351.   ulRC=CommClearRxBuffer(hCommPort);
  352.  
  353. return ulRC;
  354. }
  355.  
  356. /*------------------------------------------------------------------------*
  357.  *  CommClearTxBuffer
  358.  *
  359.  *  This routine clears the transmit buffer for the com port
  360.  *------------------------------------------------------------------------*/
  361.  
  362. ULONG CommClearTxBuffer(HCOMMPORT hCommPort)
  363. {
  364. UCHAR
  365.   ucZero;
  366.  
  367. ULONG
  368.   ulRC;
  369.  
  370. PCOMMOS2_STRUCT
  371.   pCommStruct;
  372.  
  373. ucZero=0;
  374.  
  375. pCommStruct=CommGetStruct(hCommPort);
  376. ulRC=(ULONG)DosDevIOCtl(NULL,&ucZero,
  377.        DEV_FLUSHOUTPUT,IOCTL_GENERAL,pCommStruct->hCommPortFile);
  378. if (ulRC)
  379.   {
  380.   pCommStruct->ulCommErrorCode = COMM_ERROR_CLEARBUFFERFAILED;
  381.   pCommStruct->ulDosErrorCode  = ulRC;
  382.   pCommStruct->ulCommMode      = COMM_MODE_CLEARTXBUFFER;
  383.   return COMM_ERROR_CLEARBUFFERFAILED;
  384.   }
  385.  
  386. return COMM_ERROR_NOERROR;
  387. }
  388.  
  389. /*------------------------------------------------------------------------*
  390.  *  CommClearRxBuffer
  391.  *
  392.  *  This routine clears receive buffer for the com port
  393.  *------------------------------------------------------------------------*/
  394.  
  395. ULONG CommClearRxBuffer(HCOMMPORT hCommPort)
  396. {
  397. UCHAR
  398.   ucZero;
  399.  
  400. ULONG
  401.   ulRC;
  402.  
  403. PCOMMOS2_STRUCT
  404.   pCommStruct;
  405.  
  406. ucZero=0;
  407.  
  408. pCommStruct=CommGetStruct(hCommPort);
  409. ulRC=(ULONG)DosDevIOCtl(NULL,&ucZero,
  410.        DEV_FLUSHINPUT,IOCTL_GENERAL,pCommStruct->hCommPortFile);
  411. if (ulRC)
  412.   {
  413.   pCommStruct->ulCommErrorCode = COMM_ERROR_CLEARBUFFERFAILED;
  414.   pCommStruct->ulDosErrorCode  = ulRC;
  415.   pCommStruct->ulCommMode      = COMM_MODE_CLEARRXBUFFER;
  416.   return COMM_ERROR_CLEARBUFFERFAILED;
  417.   }
  418.  
  419. return COMM_ERROR_NOERROR;
  420. }
  421.  
  422. /*------------------------------------------------------------------------*
  423.  *  CommClose
  424.  *
  425.  *  This routine invokes DosClose to close a serial comm port.
  426.  *------------------------------------------------------------------------*/
  427.  
  428. ULONG CommClose(HCOMMPORT hCommPort)
  429. {
  430. ULONG
  431.   ulDCBSize;
  432.  
  433. PCOMMOS2_STRUCT
  434.   pCommStruct;
  435.  
  436. pCommStruct=CommGetStruct(hCommPort);
  437.  
  438. if (pCommStruct == NULL)
  439.   return COMM_ERROR_PORTNOTFOUND;   // Unable to locate comm port
  440.  
  441. if (pCommStruct->fPortOpen)
  442.   {  
  443.   ulDCBSize=sizeof(DCBINFO);
  444.   DosDevIOCtl(NULL,&(pCommStruct->DCBOriginal),ASYNC_SETDCBINFO,
  445.     IOCTL_ASYNC,pCommStruct->hCommPortFile);
  446.   CommInit(hCommPort,pCommStruct->usBaudRate,
  447.     pCommStruct->usParity,pCommStruct->usDataBits,
  448.     pCommStruct->usStopBits,pCommStruct->usTxBreak);
  449.   DosClose(pCommStruct->hCommPortFile);
  450.   }
  451.  
  452. pCommStruct->ulCommErrorCode = COMM_ERROR_NOERROR;
  453. pCommStruct->ulDosErrorCode  = NO_ERROR;
  454. pCommStruct->hCommPortFile   = 0;
  455. pCommStruct->ulCommMode      = COMM_MODE_NOTSTARTED;
  456. pCommStruct->fPortOpen       = FALSE;
  457. pCommStruct->fPortOpened     = FALSE;
  458.  
  459. return COMM_ERROR_NOERROR;
  460. }
  461.  
  462. /*------------------------------------------------------------------------*
  463.  *  CommWrite
  464.  *
  465.  *  This routine invokes DosWrite to write the data to the serial comm
  466.  *  port.
  467.  *------------------------------------------------------------------------*/
  468.  
  469. ULONG CommWrite(HCOMMPORT hCommPort,UCHAR *pucDataArea,
  470.          USHORT usDataAreaSize,ULONG *pulWritten)
  471. {
  472. USHORT
  473.   usWritten;
  474.  
  475. ULONG
  476.   ulRC;
  477.  
  478. PCOMMOS2_STRUCT
  479.   pCommStruct;
  480.  
  481. pCommStruct=CommGetStruct(hCommPort);
  482. ulRC=(ULONG)DosFSRamSemRequest(&(pCommStruct->hCommWriteSem),
  483.   COMMOS2_RESOURCE_SEM_WAIT);
  484. if (ulRC)
  485.   {
  486.   pCommStruct->ulCommErrorCode = COMM_ERROR_SEMAPHOREFAILED;
  487.   pCommStruct->ulDosErrorCode  = ulRC;
  488.   pCommStruct->ulCommMode      = COMM_MODE_WRITE;
  489.   return COMM_ERROR_SEMAPHOREFAILED;
  490.   }
  491.  
  492. ulRC=(ULONG)DosWrite(pCommStruct->hCommPortFile,pucDataArea,
  493.      usDataAreaSize,&usWritten);
  494. (*pulWritten)=(ULONG)usWritten;
  495.  
  496. DosFSRamSemClear(&(pCommStruct->hCommWriteSem));
  497.  
  498. if (ulRC)
  499.   {
  500.   pCommStruct->ulCommErrorCode = COMM_ERROR_WRITEFAILED;
  501.   pCommStruct->ulDosErrorCode  = ulRC;
  502.   pCommStruct->ulCommMode      = COMM_MODE_WRITE;
  503.   return COMM_ERROR_WRITEFAILED;
  504.   }
  505.  
  506. return COMM_ERROR_NOERROR;
  507. }
  508.  
  509. /*------------------------------------------------------------------------*
  510.  *  CommRead
  511.  *
  512.  *  This routine invokes DosRead to read the data from the serial comm
  513.  *  port.  This routine reads whatever data is currently available from
  514.  *  the port buffer.  It does not wait for information to arrive.
  515.  *------------------------------------------------------------------------*/
  516.  
  517. ULONG CommRead(HCOMMPORT hCommPort,UCHAR *pucDataArea,
  518.          USHORT usDataAreaSize,ULONG *pulRead)
  519. {
  520. USHORT
  521.   usRead;
  522.  
  523. ULONG
  524.   ulRC;
  525.  
  526. PCOMMOS2_STRUCT
  527.   pCommStruct;
  528.  
  529. pCommStruct=CommGetStruct(hCommPort);
  530. ulRC=(ULONG)DosFSRamSemRequest(&(pCommStruct->hCommReadSem),
  531.   COMMOS2_RESOURCE_SEM_WAIT);
  532. if (ulRC)
  533.   {
  534.   pCommStruct->ulCommErrorCode = COMM_ERROR_SEMAPHOREFAILED;
  535.   pCommStruct->ulDosErrorCode  = ulRC;
  536.   pCommStruct->ulCommMode      = COMM_MODE_READ;
  537.   return COMM_ERROR_SEMAPHOREFAILED;
  538.   }
  539.  
  540. ulRC=(ULONG)DosRead(pCommStruct->hCommPortFile,pucDataArea,
  541.        usDataAreaSize,&usRead);
  542. (*pulRead)=(ULONG)usRead;
  543.  
  544. DosFSRamSemClear(&(pCommStruct->hCommReadSem));
  545.  
  546. if (ulRC)
  547.   {
  548.   pCommStruct->ulCommErrorCode = COMM_ERROR_READFAILED;
  549.   pCommStruct->ulDosErrorCode  = ulRC;
  550.   pCommStruct->ulCommMode      = COMM_MODE_READ;
  551.   return COMM_ERROR_READFAILED;
  552.   }
  553.  
  554. return COMM_ERROR_NOERROR;
  555. }
  556.  
  557. /*------------------------------------------------------------------------*
  558.  *  CommReadTimeOut
  559.  *
  560.  *  This routine invokes DosRead and DosDevIOCtl to either read the
  561.  *  specified number of characters or to return once the timeout specified
  562.  *  has elapsed.
  563.  *------------------------------------------------------------------------*/
  564.  
  565. ULONG CommReadTimeOut(HCOMMPORT hCommPort,
  566.          UCHAR *pucDataArea,USHORT usDataAreaSize,
  567.          ULONG *pulRead,long lTimeOutmSec)
  568. {
  569. int
  570.   fCheck,
  571.   fKeepWaiting;
  572.  
  573. ULONG
  574.   ulStartTime,
  575.   ulTimeOut,
  576.   ulSleepTime,
  577.   ulCharCount,
  578.   ulReadRC,
  579.   ulRC;
  580.  
  581. PCOMMOS2_STRUCT
  582.   pCommStruct;
  583.  
  584. pCommStruct=CommGetStruct(hCommPort);
  585. ulRC=(ULONG)DosFSRamSemRequest(&(pCommStruct->hCommReadSem),
  586.   COMMOS2_RESOURCE_SEM_WAIT);
  587. if (ulRC)
  588.   {
  589.   pCommStruct->ulCommErrorCode = COMM_ERROR_SEMAPHOREFAILED;
  590.   pCommStruct->ulDosErrorCode  = ulRC;
  591.   pCommStruct->ulCommMode      = COMM_MODE_READTIMEOUT;
  592.   return COMM_ERROR_SEMAPHOREFAILED;
  593.   }
  594.  
  595. ulStartTime=TimerValue();
  596. ulTimeOut=lTimeOutmSec/10L;
  597. ulSleepTime=1L;
  598. fKeepWaiting=TRUE;
  599. if (lTimeOutmSec == TIMEOUT_INDEFINITE)
  600.   fCheck=FALSE;
  601. else
  602.   fCheck=TRUE;
  603. ulReadRC=COMM_ERROR_NOERROR;
  604. do
  605.   {
  606.   ulRC=CommQueryQueue(hCommPort,COMM_QUERY_RXCOUNT,&ulCharCount);
  607.   if (ulRC)
  608.     {
  609.     pCommStruct->ulCommErrorCode = COMM_ERROR_IOCTLFAILED;
  610.     pCommStruct->ulDosErrorCode  = ulRC;
  611.     pCommStruct->ulCommMode      = COMM_MODE_READTIMEOUT;
  612.     DosFSRamSemClear(&(pCommStruct->hCommReadSem));
  613.     return COMM_ERROR_IOCTLFAILED;
  614.     }
  615.  
  616.   if (ulCharCount >= usDataAreaSize) 
  617.     {
  618.  
  619.     //
  620.     // The number of characters requested are available.  Read the data
  621.     // and return to the calling program.
  622.     //
  623.  
  624.     fKeepWaiting=FALSE;
  625.     ulReadRC=CommRead(hCommPort,pucDataArea,usDataAreaSize,pulRead);
  626.     }
  627.   else
  628.     {
  629.  
  630.     //
  631.     // The requested number of characters are not available at this
  632.     // time.  Test to see if the specified time has elapsed and return
  633.     // to the calling program if it has.
  634.     //
  635.  
  636.     if (fCheck && (TimerDifference(ulStartTime) > ulTimeOut))
  637.       {
  638.       fKeepWaiting=FALSE;
  639.       (*pulRead)=0;
  640.       pCommStruct->ulCommErrorCode = COMM_ERROR_TIMEOUTEXCEEDED;
  641.       pCommStruct->ulDosErrorCode  = NO_ERROR;
  642.       pCommStruct->ulCommMode      = COMM_MODE_READTIMEOUT;
  643.       ulReadRC=COMM_ERROR_TIMEOUTEXCEEDED;
  644.       }
  645.     }
  646.   if (fKeepWaiting)
  647.     {
  648.     DosSleep(ulSleepTime);
  649.  
  650.     //
  651.     // If port is not responding, slowly increase sleep interval.  Do
  652.     // not exceed 256 (approximately 1/4 second).
  653.     //
  654.  
  655.     if (ulSleepTime < 256L)
  656.       ulSleepTime *= 2L;
  657.     }
  658.   } while (fKeepWaiting);
  659.  
  660. DosFSRamSemClear(&(pCommStruct->hCommReadSem));
  661. return ulReadRC;
  662. }
  663.  
  664. /*------------------------------------------------------------------------*
  665.  *  CommReadUntilByte
  666.  *
  667.  *  This routine invokes DosRead and DosDevIOCtl to either read either the
  668.  *  specified number of characters or to return once the character
  669.  *  specified has been read.  The routine will also return if the timeout
  670.  *  specified has elapsed.
  671.  *------------------------------------------------------------------------*/
  672.  
  673. ULONG CommReadUntilByte(HCOMMPORT hCommPort,
  674.          UCHAR *pucDataArea,USHORT usDataAreaSize,
  675.          ULONG *pulRead,UCHAR ucWaitByte,
  676.          long lTimeOutmSec)
  677. {
  678. USHORT
  679.   usDataPosition;
  680.  
  681. UCHAR
  682.   ucNextChar;
  683.  
  684. int
  685.   fCheck,
  686.   fKeepWaiting;
  687.  
  688. ULONG
  689.   ulStartTime,
  690.   ulTimeOut,
  691.   ulSleepTime,
  692.   ulRead,
  693.   ulReadRC,
  694.   ulCharCount,
  695.   ulRC;
  696.  
  697. PCOMMOS2_STRUCT
  698.   pCommStruct;
  699.  
  700. pCommStruct=CommGetStruct(hCommPort);
  701. ulRC=(ULONG)DosFSRamSemRequest(&(pCommStruct->hCommReadSem),
  702.   COMMOS2_RESOURCE_SEM_WAIT);
  703. if (ulRC)
  704.   {
  705.   pCommStruct->ulCommErrorCode = COMM_ERROR_SEMAPHOREFAILED;
  706.   pCommStruct->ulDosErrorCode  = ulRC;
  707.   pCommStruct->ulCommMode      = COMM_MODE_READUNTILBYTE;
  708.   return COMM_ERROR_SEMAPHOREFAILED;
  709.   }
  710.  
  711. ulStartTime=TimerValue();
  712. ulTimeOut=lTimeOutmSec/10L;
  713. ulSleepTime=1L;
  714. fKeepWaiting=TRUE;
  715. if (lTimeOutmSec == TIMEOUT_INDEFINITE)
  716.   fCheck=FALSE;
  717. else
  718.   fCheck=TRUE;
  719. ulReadRC=COMM_ERROR_NOERROR;
  720. usDataPosition=0;
  721. (*pulRead)=0;
  722. do
  723.   {
  724.   ulRC=CommQueryQueue(hCommPort,COMM_QUERY_RXCOUNT,&ulCharCount);
  725.   if (ulRC)
  726.     {
  727.     pCommStruct->ulCommErrorCode = COMM_ERROR_IOCTLFAILED;
  728.     pCommStruct->ulDosErrorCode  = ulRC;
  729.     pCommStruct->ulCommMode      = COMM_MODE_READUNTILBYTE;
  730.     DosFSRamSemClear(&(pCommStruct->hCommReadSem));
  731.     return COMM_ERROR_IOCTLFAILED;
  732.     }
  733.  
  734.   if (ulCharCount > 0) 
  735.     {
  736.  
  737.     //
  738.     // Some characters are available.  Read them one by one checking
  739.     // to see if the termination character is present or the maximum
  740.     // number of characters have been read.
  741.     //
  742.  
  743.     do
  744.       {
  745.       ulReadRC=CommRead(hCommPort,&ucNextChar,1,&ulRead);
  746.       if (ulReadRC)
  747.         fKeepWaiting=FALSE;
  748.       if (fKeepWaiting)
  749.         {
  750.         pucDataArea[usDataPosition]=ucNextChar;
  751.         usDataPosition++;
  752.         ulCharCount--;
  753.         if (ucNextChar == ucWaitByte)
  754.           fKeepWaiting=FALSE;
  755.         if (usDataPosition >= usDataAreaSize)
  756.           fKeepWaiting=FALSE;
  757.         }
  758.       } while (fKeepWaiting && (ulCharCount > 0));
  759.     (*pulRead)=(ULONG)usDataPosition;
  760.     }
  761.   else
  762.     {
  763.  
  764.     //
  765.     // The requested number of characters are not available at this
  766.     // time.  Test to see if the specified time has elapsed and return
  767.     // to the calling program if it has.
  768.     //
  769.  
  770.     if (fCheck && (TimerDifference(ulStartTime) > ulTimeOut))
  771.       {
  772.       fKeepWaiting=FALSE;
  773.       pCommStruct->ulCommErrorCode = COMM_ERROR_TIMEOUTEXCEEDED;
  774.       pCommStruct->ulDosErrorCode  = NO_ERROR;
  775.       pCommStruct->ulCommMode      = COMM_MODE_READUNTILBYTE;
  776.       ulReadRC=COMM_ERROR_TIMEOUTEXCEEDED;
  777.       }
  778.     }
  779.   if (fKeepWaiting)
  780.     {
  781.     DosSleep(ulSleepTime);
  782.  
  783.     //
  784.     // If port is not responding, slowly increase sleep interval.  Do
  785.     // not exceed 256 (approximately 1/4 second).
  786.     //
  787.  
  788.     if (ulSleepTime < 256L)
  789.       ulSleepTime *= 2L;
  790.     }
  791.   } while (fKeepWaiting);
  792.  
  793. DosFSRamSemClear(&(pCommStruct->hCommReadSem));
  794. return ulReadRC;
  795. }
  796.  
  797. /*------------------------------------------------------------------------*
  798.  *  TimerValue
  799.  *
  800.  *  This routine returns a timer value in hundredths of seconds.  This
  801.  *  routine does not return a value which can be used for the current time,
  802.  *  but it does return a value useful for use as a timer.  If the value
  803.  *  returned is less than a previous value, you should add 8,640,000 which
  804.  *  is equivalent to one day in hundredths of seconds.
  805.  *------------------------------------------------------------------------*/
  806.  
  807. static ULONG TimerValue()
  808. {
  809. DATETIME
  810.   CurrentTime;
  811.  
  812. DosGetDateTime(&CurrentTime);
  813.  
  814. return 360000L*(ULONG)CurrentTime.hours+
  815.          6000L*(ULONG)CurrentTime.minutes+
  816.           100L*(ULONG)CurrentTime.seconds+
  817.                (ULONG)CurrentTime.hundredths;
  818. }
  819.  
  820. /*------------------------------------------------------------------------*
  821.  *  TimerDifference
  822.  *
  823.  *  This routine uses a base value obtained from TimerValue and calls 
  824.  *  TimerValue itself to return the difference in hundreths of seconds.
  825.  *------------------------------------------------------------------------*/
  826.  
  827. static ULONG TimerDifference(ULONG ulBaseTimerValue)
  828. {
  829. ULONG
  830.   ulCurrentTime;
  831.  
  832. ulCurrentTime=TimerValue();
  833. if (ulCurrentTime < ulBaseTimerValue)
  834.   ulCurrentTime += 8640000L;
  835.  
  836. return ulCurrentTime-ulBaseTimerValue;
  837. }                              
  838.  
  839. /*------------------------------------------------------------------------*
  840.  *  CommGetStruct
  841.  *
  842.  *  This is an internal routine which returns the address of the error
  843.  *  structure for the requested comm port.
  844.  *------------------------------------------------------------------------*/
  845.  
  846. static PCOMMOS2_STRUCT CommGetStruct(HCOMMPORT hCommPort)
  847. {
  848. PCOMMOS2_STRUCT
  849.   pCommStruct;
  850.  
  851. pCommStruct=NULL;
  852. if (pCommOS2Struct[hCommPort].fPortOpened)
  853.   pCommStruct=&pCommOS2Struct[hCommPort];
  854.  
  855. return pCommStruct;
  856. }
  857.  
  858. /*------------------------------------------------------------------------*
  859.  *  CommQueryQueue
  860.  *
  861.  *  This routine queries the values of count and size for both the
  862.  *  receive and transmit buffers.
  863.  *------------------------------------------------------------------------*/
  864.  
  865. static ULONG CommQueryQueue(HCOMMPORT hCommPort,short sMode,
  866.   ULONG *ulValue)
  867. {
  868. USHORT
  869.   usFunction;
  870.  
  871. RXQUEUE
  872.   RxQueue;
  873.  
  874. ULONG
  875.   ulRC,
  876.   ulRxQueue;
  877.  
  878. PCOMMOS2_STRUCT
  879.   pCommStruct;
  880.  
  881. switch (sMode)
  882.   {
  883.   case COMM_QUERY_RXCOUNT:  // Query Rx character count
  884.   case COMM_QUERY_RXBUFFER: // Query Rx buffer size
  885.     usFunction=ASYNC_GETINQUECOUNT;
  886.     break;
  887.  
  888.   case COMM_QUERY_TXCOUNT:  // Query Tx character count
  889.   case COMM_QUERY_TXBUFFER: // Query Tx buffer size
  890.     usFunction=ASYNC_GETOUTQUECOUNT;
  891.     break;
  892.   }
  893.  
  894. pCommStruct=CommGetStruct(hCommPort);
  895. ulRxQueue=sizeof(RXQUEUE);
  896. (*ulValue)=0;
  897. ulRC=(ULONG)DosDevIOCtl(&RxQueue,NULL,
  898.        usFunction,IOCTL_ASYNC,pCommStruct->hCommPortFile);
  899.  
  900. if (ulRC)
  901.   {  
  902.   pCommStruct->ulCommErrorCode = COMM_ERROR_IOCTLFAILED;
  903.   pCommStruct->ulDosErrorCode  = ulRC;
  904.   return COMM_ERROR_IOCTLFAILED;
  905.   }
  906.  
  907. switch (sMode)
  908.   {
  909.   case COMM_QUERY_RXCOUNT:  // Return Rx buffer count
  910.   case COMM_QUERY_TXCOUNT:  // Return Tx buffer count
  911.     (*ulValue)=RxQueue.cch;
  912.     break;
  913.  
  914.   case COMM_QUERY_RXBUFFER: // Return Rx buffer size
  915.   case COMM_QUERY_TXBUFFER: // Return Tx buffer size
  916.     (*ulValue)=RxQueue.cb;
  917.     break;
  918.   }
  919.  
  920. return COMM_ERROR_NOERROR;
  921. }
  922.  
  923. /*------------------------------------------------------------------------*
  924.  *  CommQueryRxCount
  925.  *
  926.  *  This routine returns the number of characters in the receiver buffer.
  927.  *------------------------------------------------------------------------*/
  928.  
  929. ULONG CommQueryRxCount(HCOMMPORT hCommPort,ULONG *ulCount)
  930. {
  931. ULONG
  932.   ulRC;
  933.  
  934. PCOMMOS2_STRUCT
  935.   pCommStruct;
  936.  
  937. ulRC=CommQueryQueue(hCommPort,COMM_QUERY_RXCOUNT,ulCount);
  938. if (ulRC)
  939.   {
  940.   pCommStruct=CommGetStruct(hCommPort);
  941.   pCommStruct->ulCommMode      = COMM_MODE_QUERYRXCOUNT;
  942.   }
  943.  
  944. return ulRC;
  945. }
  946.  
  947. /*------------------------------------------------------------------------*
  948.  *  CommQueryRxBufSize
  949.  *
  950.  *  This routine returns the size of the receiver buffer.
  951.  *------------------------------------------------------------------------*/
  952.  
  953. ULONG CommQueryRxBufSize(HCOMMPORT hCommPort,ULONG *ulSize)
  954. {
  955. ULONG
  956.   ulRC;
  957.  
  958. PCOMMOS2_STRUCT
  959.   pCommStruct;
  960.  
  961. ulRC=CommQueryQueue(hCommPort,COMM_QUERY_RXBUFFER,ulSize);
  962. if (ulRC)
  963.   {
  964.   pCommStruct=CommGetStruct(hCommPort);
  965.   pCommStruct->ulCommMode      = COMM_MODE_QUERYRXBUFSIZE;
  966.   }
  967.  
  968. return ulRC;
  969. }
  970.  
  971. /*------------------------------------------------------------------------*
  972.  *  CommQueryTxCount
  973.  *
  974.  *  This routine returns the number of characters in the transmit buffer.
  975.  *------------------------------------------------------------------------*/
  976.  
  977. ULONG CommQueryTxCount(HCOMMPORT hCommPort,ULONG *ulCount)
  978. {
  979. ULONG
  980.   ulRC;
  981.  
  982. PCOMMOS2_STRUCT
  983.   pCommStruct;
  984.  
  985. ulRC=CommQueryQueue(hCommPort,COMM_QUERY_TXCOUNT,ulCount);
  986. if (ulRC)
  987.   {
  988.   pCommStruct=CommGetStruct(hCommPort);
  989.   pCommStruct->ulCommMode      = COMM_MODE_QUERYTXCOUNT;
  990.   }
  991.  
  992. return ulRC;
  993. }
  994.  
  995. /*------------------------------------------------------------------------*
  996.  *  CommQueryTxBufSize
  997.  *
  998.  *  This routine returns the size of the transmit buffer.
  999.  *------------------------------------------------------------------------*/
  1000.  
  1001. ULONG CommQueryTxBufSize(HCOMMPORT hCommPort,ULONG *ulSize)
  1002. {
  1003. ULONG
  1004.   ulRC;
  1005.  
  1006. PCOMMOS2_STRUCT
  1007.   pCommStruct;
  1008.  
  1009. ulRC=CommQueryQueue(hCommPort,COMM_QUERY_TXBUFFER,ulSize);
  1010. if (ulRC)
  1011.   {
  1012.   pCommStruct=CommGetStruct(hCommPort);
  1013.   pCommStruct->ulCommMode      = COMM_MODE_QUERYTXBUFSIZE;
  1014.   }
  1015.  
  1016. return ulRC;
  1017. }
  1018.  
  1019. /*------------------------------------------------------------------------*
  1020.  *  CommGetDCBInfo
  1021.  *
  1022.  *  This routine gets the DCB information for the comm port.
  1023.  *------------------------------------------------------------------------*/
  1024.  
  1025. ULONG CommGetDCBInfo(HCOMMPORT hCommPort)
  1026. {
  1027. ULONG
  1028.   ulRC,
  1029.   ulDCBSize;
  1030.  
  1031. PCOMMOS2_STRUCT
  1032.   pCommStruct;
  1033.  
  1034. pCommStruct=CommGetStruct(hCommPort);
  1035. ulDCBSize=sizeof(DCBINFO);
  1036. ulRC=(ULONG)DosDevIOCtl(&(pCommStruct->DCBInfo),NULL,
  1037.        ASYNC_GETDCBINFO,IOCTL_ASYNC,pCommStruct->hCommPortFile);
  1038.  
  1039. if (ulRC)
  1040.   {
  1041.   pCommStruct->ulCommErrorCode = COMM_ERROR_DCBINFOFAILED;
  1042.   pCommStruct->ulDosErrorCode  = ulRC;
  1043.   pCommStruct->ulCommMode      = COMM_MODE_GETDCBINFO;
  1044.   return COMM_ERROR_DCBINFOFAILED;
  1045.   }
  1046.  
  1047. return COMM_ERROR_NOERROR;
  1048. }
  1049.  
  1050. /*------------------------------------------------------------------------*
  1051.  *  CommSetDCBInfo
  1052.  *
  1053.  *  This routine sets the DCB information for the comm port.
  1054.  *------------------------------------------------------------------------*/
  1055.  
  1056. ULONG CommSetDCBInfo(HCOMMPORT hCommPort)
  1057. {
  1058. ULONG
  1059.   ulRC,
  1060.   ulDCBSize;
  1061.  
  1062. PCOMMOS2_STRUCT
  1063.   pCommStruct;
  1064.  
  1065. pCommStruct=CommGetStruct(hCommPort);
  1066. ulDCBSize=sizeof(DCBINFO);
  1067. ulRC=(ULONG)DosDevIOCtl(NULL,&(pCommStruct->DCBInfo),
  1068.        ASYNC_SETDCBINFO,IOCTL_ASYNC,pCommStruct->hCommPortFile);
  1069.  
  1070. if (ulRC)
  1071.   {
  1072.   pCommStruct->ulCommErrorCode = COMM_ERROR_DCBINFOFAILED;
  1073.   pCommStruct->ulDosErrorCode  = ulRC;
  1074.   pCommStruct->ulCommMode      = COMM_MODE_SETDCBINFO;
  1075.   return COMM_ERROR_DCBINFOFAILED;
  1076.   }
  1077.  
  1078. return COMM_ERROR_NOERROR;
  1079. }
  1080.  
  1081. /*------------------------------------------------------------------------*
  1082.  *  CommSetReadTimeOut
  1083.  *
  1084.  *  This routine sets the read timeout for the comm port.
  1085.  *------------------------------------------------------------------------*/
  1086.  
  1087. ULONG CommSetReadTimeOut(HCOMMPORT hCommPort,ULONG ulTimeMsec)
  1088. {
  1089. USHORT
  1090.   usTimeOut;
  1091.  
  1092. PCOMMOS2_STRUCT
  1093.   pCommStruct;
  1094.  
  1095. pCommStruct=CommGetStruct(hCommPort);
  1096.  
  1097. if (ulTimeMsec == TIMEOUT_INDEFINITE) // Make wait as large as possible!
  1098.   ulTimeMsec=64000;
  1099.  
  1100. if (ulTimeMsec > 64000)
  1101.   ulTimeMsec=64000;
  1102. usTimeOut=(USHORT)ulTimeMsec/10;
  1103. pCommStruct->DCBInfo.usReadTimeout = usTimeOut;
  1104.  
  1105. //
  1106. // Clear MODE_NOWAIT_READ_TIMEOUT bits and then
  1107. // set MODE_WAIT_READ_TIMEOUT bits
  1108. //
  1109.  
  1110. pCommStruct->DCBInfo.fbTimeout &= (~(BYTE)(MODE_NOWAIT_READ_TIMEOUT));
  1111. pCommStruct->DCBInfo.fbTimeout |= MODE_WAIT_READ_TIMEOUT;
  1112.  
  1113. return CommSetDCBInfo(hCommPort);
  1114. }
  1115.  
  1116. /*------------------------------------------------------------------------*
  1117.  *  CommSetWriteTimeOut
  1118.  *
  1119.  *  This routine sets the write timeout for the comm port.
  1120.  *------------------------------------------------------------------------*/
  1121.  
  1122. ULONG CommSetWriteTimeOut(HCOMMPORT hCommPort,ULONG ulTimeMsec)
  1123. {
  1124. USHORT
  1125.   usTimeOut;
  1126.  
  1127. PCOMMOS2_STRUCT
  1128.   pCommStruct;
  1129.  
  1130. pCommStruct=CommGetStruct(hCommPort);
  1131. if (ulTimeMsec == TIMEOUT_INDEFINITE)
  1132.   {
  1133.   pCommStruct->DCBInfo.usWriteTimeout = 0;
  1134.   
  1135.   //
  1136.   // Set MODE_NO_WRITE_TIMEOUT bit
  1137.   //
  1138.  
  1139.   pCommStruct->DCBInfo.fbTimeout |= MODE_NO_WRITE_TIMEOUT;
  1140.   }
  1141. else
  1142.   {
  1143.   if (ulTimeMsec > 64000)
  1144.     ulTimeMsec=64000;
  1145.   usTimeOut=(USHORT)ulTimeMsec/10;
  1146.   pCommStruct->DCBInfo.usWriteTimeout = usTimeOut;
  1147.  
  1148.   //
  1149.   // Clear MODE_NO_WRITE_TIMEOUT bit
  1150.   //
  1151.  
  1152.   pCommStruct->DCBInfo.fbTimeout &= (~(BYTE)(MODE_NO_WRITE_TIMEOUT));
  1153.   }
  1154. return CommSetDCBInfo(hCommPort);
  1155. }
  1156.  
  1157.  
  1158.