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

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