home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / comsrc.zip / COMSRC.C
C/C++ Source or Header  |  1994-12-18  |  25KB  |  798 lines

  1. /*******************************************************************************
  2. *
  3. *       Copyright (c) 1988-91 OS/tools Incorporated -- All rights reserved
  4. *
  5. *       This code is supplied on an As-is basis.  No guarantees, no promises,
  6. *       no licenses.  Use as you see fit!
  7. *
  8. *   Some of this code was written for an OS/2 1.x program and some of the VIO
  9. *   may not be done the way code written for OS/2 2.x would be done.
  10. *
  11. *   You must have the OS/2 Developers Tool Kit to compile this code.
  12. *
  13. *   This code has been successfully compiled with Microsoft's "C" 6.0 compiler,
  14. *   but why bother?
  15. *
  16. *   All current development is done using Borland's OS/2 C++ compiler.
  17. *
  18. *   If you are interested, we have a complete Presentation Manager VIO application
  19. *   we use for in-house testing that is available as source code.  All you need
  20. *   to do is ask for it.
  21. *
  22. *   For questions, comments, or any other communication, contact us on the OS2AVEN
  23. *   forum, Section One, or send mail to CompuServe address 70314,3235.
  24. *
  25. *  All trademarks herin are trademarks, or registered trademarks, of their respective
  26. *  owners.
  27. *
  28. *******************************************************************************/
  29. #define INCL_DEV
  30. #define INCL_DOS
  31. #define INCL_DOSERRORS
  32. #define INCL_VIO
  33. #include <os2.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36.  
  37. /*
  38. **  Atom constants - use your imagination.
  39. */
  40. #define ATM_LINEWRT      3609
  41. #define ATM_LINERD       3608
  42. #define ATM_DCBWRT       3607
  43. #define ATM_DCBRD        3606
  44. #define ATM_BAUDWRT      3605
  45. #define ATM_BAUDRD       3604
  46. #define ATM_FXOFF        3603
  47. #define ATM_FXON         3602
  48. #define ATM_MDMGET       3601
  49. #define ATM_MDMSET       3600
  50. #define ATM_FLUSH        5034
  51. #define ATM_COMEVENTS    5035
  52. #define ATM_COMEVENT     5036
  53. #define ATM_COMERROR     5037
  54. #define ATM_XMITSTAT     5038
  55. #define ATM_COMSTAT      5039
  56. #define ATM_BRKON        5040
  57. #define ATM_BRKOFF       5041
  58. #define ATM_RCVQLEN      5042
  59. #define ATM_TXQLEN       5043
  60. #define ATM_IMMBYTE      5044
  61. #define ATM_MDMGET_OUT1  5045
  62. #define ATM_MDMSET_OUT1  5046
  63. #define EATM_DOSOPEN     6001
  64. #define EATM_ERRORCD     6002
  65. #define EATM_FUNCTION    6003
  66. #define EATM_IOCTL       6004
  67.  
  68. /*
  69. ** constants used by FlushBuffers function
  70. */
  71. #define INPUT         1
  72. #define OUTPUT        2
  73.  
  74. /*
  75. ** constants used by SendXonXoff function
  76. */
  77. #define SEND_XON      0
  78. #define SEND_XOFF     1
  79.  
  80. /*
  81. **  User Message Constants
  82. */
  83. #define UM_KILLTHREAD 30000
  84.  
  85. typedef unsigned char BYTE;
  86. typedef unsigned short WORD;
  87.  
  88. /*
  89. ** used by function 46h
  90. */
  91. typedef struct
  92.     {
  93.     BYTE byModemSigOn;   // activate signal if bit is a one
  94.     BYTE byModemSigOff;  // de-activate signal if bit is zero
  95.     }MDMSSIG;
  96. /*
  97. **  ON bits take presedent over OFF bits.  Bit one is DTR, bit two is RTS.
  98. **  If you are using COMi and modem signal extensions are enabled, then bit three
  99. **  controls OUT1 and bit six controls LOOP.  Any other bits on, or off, will
  100. **  cause the command to be ignored and an error will be returned.
  101. */
  102. /*
  103. ** used by functions 42h and 62h
  104. */
  105. typedef struct
  106.     {
  107.     BYTE byDataBits;          // number of data bits
  108.     BYTE byParity;            // 0 = none; 1 = odd, 2 = even, 3 = mark, 4 = space
  109.     BYTE byStopBits;          // 0 = one stop bit, 1 = 1.5 stop bits (5 bit data word only),
  110.                               // 2 = two stop bits (not valid for 5 bit data word)
  111.     BOOL bTransmittingBreak;  // return only, with "get line"
  112.     }LINECHAR;
  113.  
  114. /*
  115. ** used by function 43h
  116. */
  117. typedef struct
  118.   {
  119.   LONG lBaudRate;
  120.   BYTE byFraction;    // not used by COMi
  121.   }BAUDRT;
  122.  
  123. /*
  124. ** used by function 43h
  125. */
  126. typedef struct
  127.   {
  128.   BAUDRT stCurrentBaud;
  129.   BAUDRT stHighestBaud;
  130.   BAUDRT stLowestBaud;
  131.   }BAUDST;
  132.  
  133. /*
  134. ** DCB used by functions 53h and 73h
  135. */
  136. typedef struct
  137.     {
  138.     WORD wWrtTimeout;  // 1/10 second increments - zero = wait 1/10 second
  139.     WORD wReadTimeout; //  ditto
  140.     BYTE byFlags1;
  141.     BYTE byFlags2;
  142.     BYTE byFlags3;
  143.     BYTE byErrorReplacementChar;
  144.     BYTE byBreakReplacementChar;
  145.     BYTE byXonChar;
  146.     BYTE byXoffChar;
  147.    }DCB;
  148. /*
  149. **  Constants for DCB flags
  150. **
  151. **  See the "Physical Device Driver" technical reference under "Category One,
  152. **  Asynchronous Serial Device Drivers" for more detail.
  153. */
  154. #define F1_ENABLE_DTR                   '\x01'
  155. #define F1_ENABLE_DTR_INPUT_HS          '\x02'
  156. #define F1_DTR_MASK                     '\x03'
  157. #define F1_ENABLE_DSR_INPUT_SENSE       '\x40'
  158. #define F1_ENABLE_DCD_OUTPUT_HS         '\x20'
  159. #define F1_ENABLE_DSR_OUTPUT_HS         '\x10'
  160. #define F1_ENABLE_CTS_OUTPUT_HS         '\x08'
  161.  
  162. #define F2_ENABLE_RTS                   '\x40'
  163. #define F2_ENABLE_RTS_INPUT_HS          '\x80'
  164. #define F2_ENABLE_RTS_TOG_ON_XMIT       '\xc0'
  165. #define F2_RTS_MASK                     '\xc0'
  166.  
  167. #define F2_ENABLE_BREAK_REPL            '\x10'
  168. #define F2_ENABLE_NULL_STRIP            '\x08'
  169. #define F2_ENABLE_ERROR_REPL            '\x04'
  170.  
  171. #define F2_ENABLE_RCV_XON_XOFF_FLOW     '\x02'
  172. #define F2_ENABLE_XMIT_XON_XOFF_FLOW    '\x01'
  173. #define F2_ENABLE_FULL_DUPLEX           '\x20'
  174.  
  175. #define F3_USE_TX_FIFO                  '\x80'
  176. #define F3_4_CHARACTER_FIFO             '\x20'
  177. #define F3_8_CHARACTER_FIFO             '\x40'
  178. #define F3_14_CHARACTER_FIFO            '\x60'
  179. #define F3_FIFO_DISABLE                 '\x08'
  180. #define F3_FIFO_ENABLE                  '\x10'
  181. #define F3_FIFO_APO                     '\x18'
  182. #define F3_FIFO_MASK                    '\xf8'
  183. #define F3_RTO_WAIT_NORM                '\x02' // Read Time-Out
  184. #define F3_RTO_WAIT_NONE                '\x06'
  185. #define F3_RTO_WAIT_SOMETHING           '\x04'
  186. #define F3_RTO_MASK                     '\x06'
  187. #define F3_INFINITE_WTO                 '\x01' // Write Time-Out
  188.  
  189. /*
  190. **  Function prototypes
  191. */
  192. void SendXonXoff(HFILE hCom,WORD wSignal);
  193. void FlushComBuffer(HFILE hCom,ULONG ulDirection);
  194. APIRET ForceXoff(HFILE hCom);
  195. APIRET ForceXon(HFILE hCom);
  196. APIRET GetBaudRate(HFILE hCom,LONG *plBaud);
  197. APIRET SetBaudRate(HFILE hCom,LONG lBaud);
  198. APIRET GetLineCharacteristics(HFILE hCom,LINECHAR *pstLineChar);
  199. APIRET SetLineCharacteristics(HFILE hCom,LINECHAR *pstLineChar);
  200. APIRET SetModemSignals(HFILE hCom,BYTE byOnByte,BYTE byOffByte,WORD *pwCOMerror);
  201. APIRET GetModemOutputSignals(HFILE hCom,BYTE *pbySignals);
  202. BOOL ToggleOUT1(HFILE hCom,BOOL bToggle,BOOL *pActive);
  203. APIRET GetModemInputSignals(HFILE hCom,BYTE *pbySignals);
  204. APIRET GetTransmitQueueLen(HFILE hCom,WORD *pwQueueLen,WORD *pwByteCount);
  205. APIRET GetReceiveQueueLen(HFILE hCom,WORD *pwQueueLen,WORD *pwByteCount);
  206. APIRET BreakOff(HFILE hCom,WORD *pwCOMerror);
  207. APIRET BreakOn(HFILE hCom,WORD *pwCOMerror);
  208. APIRET GetCOMerror(HFILE hCom,WORD *pwCOMerror);
  209. APIRET GetCOMevent(HFILE hCom,WORD *pwCOMevent);
  210. APIRET GetCOMstatus(HFILE hCom,BYTE *pbyCOMstatus);
  211. APIRET GetXmitStatus(HFILE hCom,BYTE *pbyCOMstatus);
  212. APIRET SendDCB(HFILE hCom,DCB *pstComDCB);
  213. APIRET GetDCB(HFILE hCom,DCB *pstComDCB);
  214.  
  215. extern HEV hevKillThreadSem;
  216. extern BOOL bStopThread = TRUE;
  217. extern BOOL bInputLF = FALSE;
  218. extern BOOL bRemoteEcho = FALSE;
  219.  
  220. extern HPS hpsVio;
  221.  
  222. extern HAB habAnchorBlock;
  223. extern char szPortName[];
  224. extern HWND hwndFrame;
  225. extern HWND hwndClient;
  226. extern HFILE hCom;
  227. extern char abyInString[100];
  228.  
  229. /*****************************************************************************
  230. ** Keyboard input
  231. **
  232. **  This is a code fargment that demonstrates how to "grab" a keystroke.  This
  233. **  fragment would be placed in the main window procedure (hwndClient) message (msg)
  234. **  case statement.  The WM_CHAR message is sent to the client window procedure
  235. **  of the process that has keyboard focus, usually the foreground process, whenever
  236. **  the user presses a key.
  237.  
  238.     case WM_CHAR:
  239.       if (fProcessType == TERMINAL)
  240.         {
  241.         if (SHORT1FROMMP(mp1) & KC_CHAR)
  242.           {
  243.           chKey = SHORT1FROMMP(mp2);
  244.           if ((rc = DosWrite(hCom,(PVOID)&chKey,1,&ulCount)) != NO_ERROR)
  245.             {
  246.             sprintf(szMessage,"Error Writing to Port - Error = %u",wError);
  247.             ErrorNotify(szMessage);
  248.             }
  249.           if (bLocalEcho == TRUE)
  250.             VioWrtTTY(&chKey,1,hpsVio);
  251.           if (chKey == '\x0d')
  252.             {
  253.             chKey = '\x0a';
  254.             if (bLocalEcho == TRUE)
  255.               VioWrtTTY(&chKey,1,hpsVio);
  256.             if (bOutputLF)
  257.               {
  258.               if ((rc = DosWrite(hCom,(PVOID)&chKey,1,&ulCount)) != NO_ERROR)
  259.                 {
  260.                 sprintf(szMessage,"Error Writing to Port - Error = %u",rc);
  261.                 ErrorNotify(szMessage);
  262.                 }
  263.               }
  264.             }
  265.           }
  266.         }
  267.       else
  268.         return(WinDefWindowProc(hwnd,msg,mp1,mp2));
  269.       break;
  270. *******************************************************************************/
  271.  
  272. /********************************************************************************
  273. **
  274. **  OpenPort
  275. **
  276. **********************************************************************************/
  277. BOOL OpenPort(HWND hwnd,HFILE *phCom,char szPortName[])
  278.   {
  279.   ULONG ulAction;
  280.   APIRET rc;
  281.   CHAR szMsgString[100];
  282.   CHAR szCaption[80];
  283.  
  284.   if ((rc = DosOpen(szPortName,phCom,&ulAction,0L,0,0x0001,0x21c2,0L)) != NO_ERROR)
  285.     {
  286.     WinQueryWindowText(hwndFrame,sizeof(szCaption),szCaption);
  287.     WinLoadString(habAnchorBlock,(HMODULE)0,EATM_DOSOPEN,sizeof(szMsgString),szMsgString);
  288.     sprintf(&szMsgString[strlen(szMsgString)],"%s\nError Code = %04X",szPortName,rc);
  289.     WinMessageBox(HWND_DESKTOP,
  290.                   hwnd,
  291.              (PSZ)szMsgString,
  292.              (PSZ)szCaption,
  293.                   0,
  294.                  (MB_MOVEABLE | MB_OK | MB_CUAWARNING));
  295.     return(FALSE);
  296.     }
  297.   return(TRUE);
  298.   }
  299.  
  300. void ErrorNotify(char szMessage[])
  301.   {
  302.   WinMessageBox( HWND_DESKTOP,
  303.                  hwndFrame,
  304.                  (PSZ)szMessage,
  305.                  0,
  306.                  0,
  307.                  MB_MOVEABLE | MB_OK | MB_CUAWARNING );
  308.   }
  309.  
  310. /***************************************************************************************************
  311. **  DosDevIOCtl functions for serial devices
  312. **
  313. **
  314. ****************************************************************************************************/
  315.  
  316. VOID IOctlErrorMessageBox(ULONG idErrMsg,WORD wFunction,WORD wError)
  317.   {
  318.   CHAR szErrMsg[80];
  319.   CHAR szMsgString[200];
  320.   LONG lLength;
  321.  
  322.   lLength = WinLoadString(habAnchorBlock,NULLHANDLE,idErrMsg,sizeof(szMsgString),szMsgString);
  323.   WinLoadString(habAnchorBlock,NULLHANDLE,EATM_FUNCTION,sizeof(szErrMsg),szErrMsg);
  324.   lLength += sprintf(&szMsgString[lLength],"\n\n%s 0x%02X",szErrMsg,wFunction);
  325.   WinLoadString(habAnchorBlock,NULLHANDLE,EATM_ERRORCD,sizeof(szErrMsg),szErrMsg);
  326.   sprintf(&szMsgString[lLength],"\n%s 0x%04X",szErrMsg,wError);
  327.   lLength = WinLoadString(habAnchorBlock,NULLHANDLE,EATM_IOCTL,sizeof(szErrMsg),szErrMsg);
  328.   sprintf(&szErrMsg[lLength]," %s",szPortName);
  329.   WinMessageBox(HWND_DESKTOP,
  330.                 hwndFrame,
  331.            (PSZ)szMsgString,
  332.            (PSZ)szErrMsg,
  333.                 0,
  334.                (MB_MOVEABLE | MB_OK | MB_CUAWARNING));
  335.   }
  336.  
  337. APIRET GetDCB(HFILE hCom,DCB *pstComDCB)
  338.   {
  339.   ULONG ulDataLen = sizeof(DCB);
  340.   ULONG ulParmLen = 0L;
  341.   APIRET rc;
  342.  
  343.   if ((rc = DosDevIOCtl(hCom,0x01,0x73,0L,0L,&ulParmLen,(PVOID)pstComDCB,sizeof(DCB),&ulDataLen)) != NO_ERROR)
  344.     IOctlErrorMessageBox(ATM_DCBRD,0x73,rc);
  345.   return(rc);
  346.   }
  347.  
  348. APIRET SendDCB(HFILE hCom,DCB *pstComDCB)
  349.   {
  350.   ULONG ulDataLen = 0L;
  351.   ULONG ulParmLen = sizeof(DCB);
  352.   APIRET rc;
  353.  
  354.   if ((rc = DosDevIOCtl(hCom,0x01,0x53,(PVOID)pstComDCB,sizeof(DCB),&ulParmLen,0L,0L,&ulDataLen)) != NO_ERROR)
  355.     IOctlErrorMessageBox(ATM_DCBWRT,0x53,rc);
  356.   return(rc);
  357.   }
  358.  
  359. APIRET SendByteImmediate(HFILE hCom,BYTE bySendByte)
  360.   {
  361.   ULONG ulDataLen = 0L;
  362.   ULONG ulParmLen = 1L;
  363.   USHORT rc;
  364.  
  365.   if ((rc = DosDevIOCtl(hCom,0x01,0x44,(PVOID)&bySendByte,1L,&ulParmLen,0L,0L,&ulDataLen)) != NO_ERROR)
  366.     IOctlErrorMessageBox(ATM_IMMBYTE,0x44,rc);
  367.   return(rc);
  368.   }
  369.  
  370. APIRET GetXmitStatus(HFILE hCom,BYTE *pbyCOMstatus)
  371.   {
  372.   ULONG ulDataLen = 1l;
  373.   ULONG ulParmLen = 0l;
  374.   APIRET rc;
  375.  
  376.   if ((rc = DosDevIOCtl(hCom,0x01,0x65,0L,0L,&ulParmLen,(PVOID)pbyCOMstatus,1L,&ulDataLen)) != NO_ERROR)
  377.     IOctlErrorMessageBox(ATM_XMITSTAT,0x65,rc);
  378.   return(rc);
  379.   }
  380.  
  381. APIRET GetCOMstatus(HFILE hCom,BYTE *pbyCOMstatus)
  382.   {
  383.   ULONG ulDataLen = 1L;
  384.   ULONG ulParmLen = 0L;
  385.   APIRET rc;
  386.  
  387.   if ((rc = DosDevIOCtl(hCom,0x01,0x64,0L,0L,&ulParmLen,pbyCOMstatus,1L,&ulDataLen)) != NO_ERROR)
  388.     IOctlErrorMessageBox(ATM_COMSTAT,0x64,rc);
  389.   return(rc);
  390.   }
  391.  
  392. APIRET GetCOMevent(HFILE hCom,WORD *pwCOMevent)
  393.   {
  394.   ULONG ulDataLen = 2L;
  395.   ULONG ulParmLen = 0L;
  396.   APIRET rc;
  397.  
  398.   if ((rc = DosDevIOCtl(hCom,0x01,0x72,0L,0L,&ulParmLen,pwCOMevent,2L,&ulDataLen)) != NO_ERROR)
  399.       IOctlErrorMessageBox(ATM_COMEVENT,0x72,rc);
  400.   return(rc);
  401.   }
  402.  
  403. APIRET GetCOMerror(HFILE hCom,WORD *pwCOMerror)
  404.   {
  405.   ULONG ulDataLen = 2L;
  406.   ULONG ulParmLen = 0L;
  407.   APIRET rc;
  408.  
  409.   if ((rc = DosDevIOCtl(hCom,0x01,0x6d,0L,0L,&ulParmLen,pwCOMerror,2L,&ulDataLen)) != NO_ERROR)
  410.     IOctlErrorMessageBox(ATM_COMERROR,0x6d,rc);
  411.   return(rc);
  412.   }
  413.  
  414. APIRET BreakOn(HFILE hCom,WORD *pwCOMerror)
  415.   {
  416.   ULONG ulDataLen = 2L;
  417.   ULONG ulParmLen = 0L;
  418.   APIRET rc;
  419.  
  420.   if ((rc = DosDevIOCtl(hCom,0x01,0x4b,0L,0L,&ulParmLen,pwCOMerror,2L,&ulDataLen)) != NO_ERROR)
  421.     IOctlErrorMessageBox(ATM_BRKON,0x4b,rc);
  422.   return(rc);
  423.   }
  424.  
  425. APIRET BreakOff(HFILE hCom,WORD *pwCOMerror)
  426.   {
  427.   ULONG ulDataLen = 2L;
  428.   ULONG ulParmLen = 0L;
  429.   APIRET rc;
  430.  
  431.   if ((rc = DosDevIOCtl(hCom,0x01,0x45,0L,0L,&ulParmLen,pwCOMerror,2L,&ulDataLen)) != NO_ERROR)
  432.     IOctlErrorMessageBox(ATM_BRKOFF,0x45,rc);
  433.   return(rc);
  434.   }
  435.  
  436. APIRET GetReceiveQueueLen(HFILE hCom,WORD *pwQueueLen,WORD *pwByteCount)
  437.   {
  438.   ULONG ulDataLen = 4L;
  439.   ULONG ulParmLen = 0L;
  440.   APIRET rc;
  441.   struct
  442.     {
  443.     WORD wByteCount;
  444.     WORD wQueueLen;
  445.     }stWordPair;
  446.  
  447.   if ((rc = DosDevIOCtl(hCom,0x01,0x68,0L,0L,&ulParmLen,&stWordPair,4L,&ulDataLen)) != NO_ERROR)
  448.     IOctlErrorMessageBox(ATM_RCVQLEN,0x68,rc);
  449.   *pwQueueLen = stWordPair.wQueueLen;
  450.   *pwByteCount = stWordPair.wByteCount;
  451.   return(rc);
  452.   }
  453.  
  454. APIRET GetTransmitQueueLen(HFILE hCom,WORD *pwQueueLen,WORD *pwByteCount)
  455.   {
  456.   ULONG ulDataLen = 4L;
  457.   ULONG ulParmLen = 0L;
  458.   APIRET rc;
  459.   struct
  460.     {
  461.     WORD wByteCount;
  462.     WORD wQueueLen;
  463.     }stWordPair;
  464.  
  465.   if ((rc = DosDevIOCtl(hCom,0x01,0x69,0L,0L,&ulParmLen,&stWordPair,4L,&ulDataLen)) != NO_ERROR)
  466.     IOctlErrorMessageBox(ATM_TXQLEN,0x69,rc);
  467.   *pwQueueLen = stWordPair.wQueueLen;
  468.   *pwByteCount = stWordPair.wByteCount;
  469.   return(rc);
  470.   }
  471.  
  472. APIRET GetModemInputSignals(HFILE hCom,BYTE *pbySignals)
  473.   {
  474.   ULONG ulDataLen = 1L;
  475.   ULONG ulParmLen = 0L;
  476.   APIRET rc;
  477.  
  478.   if ((rc = DosDevIOCtl(hCom,0x01,0x67,0L,0L,&ulParmLen,pbySignals,1L,&ulDataLen)) != NO_ERROR)
  479.     IOctlErrorMessageBox(ATM_MDMSET,0x67,rc);
  480.   return(rc);
  481.   }
  482. /*
  483. **  Toggle the OUT1 modem signal; returns resultant OUT1 state in the "*pActivate"
  484. **  variable, or FALSE if the device driver is not capable of performing this function.
  485. **
  486. **  This function will only work with the COMi device driver, when the "Extended
  487. **  Modem Signals" extension has been enabled.
  488. */
  489. BOOL ToggleOUT1(HFILE hCom,BOOL bToggle,BOOL *pActive)
  490.   {
  491.   ULONG ulDataLen = 1L;
  492.   ULONG ulParmLen = 0L;
  493.   MDMSSIG stModemSetSignals;
  494.   BYTE byState;
  495.   WORD wCOMerror;
  496.   APIRET rc;
  497.  
  498.   if ((rc = DosDevIOCtl(hCom,0x01,0x66,0L,0L,&ulParmLen,&byState,1L,&ulDataLen)) != NO_ERROR)
  499.     {
  500.     IOctlErrorMessageBox(ATM_MDMGET_OUT1,0x69,rc);
  501.     return(FALSE);
  502.     }
  503.   byState &= '\x04';
  504.   stModemSetSignals.byModemSigOff = ~byState;
  505.  
  506.   byState ^= '\x04';
  507.   if ((byState & '\x04') != 0)
  508.     *pActive = TRUE;
  509.   else
  510.     *pActive = FALSE;
  511.   stModemSetSignals.byModemSigOn = byState;
  512.  
  513.   ulDataLen = 2L;
  514.   ulParmLen = 2L;
  515.   if ((rc = DosDevIOCtl(hCom,0x01,0x46,&stModemSetSignals,2L,&ulParmLen,&wCOMerror,2L,&ulDataLen)) != NO_ERROR)
  516.     {
  517.     IOctlErrorMessageBox(ATM_MDMSET_OUT1,0x69,rc);
  518.     return(FALSE);
  519.     }
  520.   if (!bToggle)
  521.     {
  522.     stModemSetSignals.byModemSigOff = ~byState;
  523.  
  524.     if ((byState ^= '\x04') != 0)
  525.       *pActive = TRUE;
  526.     else
  527.       *pActive = FALSE;
  528.     stModemSetSignals.byModemSigOn = byState;
  529.     if ((rc = DosDevIOCtl(hCom,0x01,0x46,&stModemSetSignals,2L,&ulParmLen,&wCOMerror,2L,&ulDataLen)) != NO_ERROR)
  530.       {
  531.       IOctlErrorMessageBox(ATM_MDMSET_OUT1,0x69,rc);
  532.       return(FALSE);
  533.       }
  534.     }
  535.   return(TRUE);
  536.   }
  537.  
  538. APIRET GetModemOutputSignals(HFILE hCom,BYTE *pbySignals)
  539.   {
  540.   ULONG ulDataLen = 1L;
  541.   ULONG ulParmLen = 0L;
  542.   APIRET rc;
  543.  
  544.   if ((rc = DosDevIOCtl(hCom,0x01,0x66,0L,0L,&ulParmLen,pbySignals,1L,&ulDataLen)) != NO_ERROR)
  545.     IOctlErrorMessageBox(ATM_MDMGET,0x66,rc);
  546.   return(rc);
  547.   }
  548.  
  549. APIRET SetModemSignals(HFILE hCom,BYTE byOnByte,BYTE byOffByte,WORD *pwCOMerror)
  550.   {
  551.   ULONG ulDataLen = 2L;
  552.   ULONG ulParmLen = 2L;
  553.   APIRET rc;
  554.   MDMSSIG stModemSetSignals;
  555.  
  556.   stModemSetSignals.byModemSigOn = byOnByte;
  557.   stModemSetSignals.byModemSigOff = byOffByte;
  558.  
  559.   if ((rc = DosDevIOCtl(hCom,0x01,0x46,&stModemSetSignals,2L,&ulParmLen,pwCOMerror,2L,&ulDataLen)) != NO_ERROR)
  560.     IOctlErrorMessageBox(ATM_MDMSET,0x46,rc);
  561.   return(rc);
  562.   }
  563.  
  564. APIRET SetLineCharacteristics(HFILE hCom,LINECHAR *pstLineChar)
  565.   {
  566.   ULONG ulDataLen = 0L;
  567.   ULONG ulParmLen = sizeof(LINECHAR);
  568.   APIRET rc;
  569.  
  570.   if ((rc = DosDevIOCtl(hCom,0x01,0x42,pstLineChar,sizeof(LINECHAR),&ulParmLen,0L,0L,&ulDataLen)) != NO_ERROR)
  571.     IOctlErrorMessageBox(ATM_LINERD,0x42,rc);
  572.   return(rc);
  573.   }
  574.  
  575. APIRET GetLineCharacteristics(HFILE hCom,LINECHAR *pstLineChar)
  576.   {
  577.   ULONG ulDataLen = sizeof(LINECHAR);
  578.   ULONG ulParmLen = 0L;
  579.   APIRET rc;
  580.  
  581.   if ((rc = DosDevIOCtl(hCom,0x01,0x62,0L,0L,&ulParmLen,pstLineChar,sizeof(LINECHAR),&ulDataLen)) != NO_ERROR)
  582.     IOctlErrorMessageBox(ATM_LINERD,0x62,rc);
  583.   return(rc);
  584.   }
  585.  
  586. APIRET SetBaudRate(HFILE hCom,LONG lBaud)
  587.   {
  588.   ULONG ulDataLen = 0l;
  589.   ULONG ulParmLen = sizeof(BAUDRT);
  590.   APIRET rc;
  591.   WORD wFunction = 0x0041;
  592.   BAUDRT stBaudRate;
  593.  
  594.   stBaudRate.lBaudRate = lBaud;
  595.   stBaudRate.byFraction = 0;
  596.   if (stBaudRate.lBaudRate > 0xffff)
  597.   wFunction = 0x0043;
  598.   if ((rc = DosDevIOCtl(hCom,0x01,wFunction,&stBaudRate,sizeof(BAUDRT),&ulParmLen,0L,0L,&ulDataLen)) != NO_ERROR)
  599.     IOctlErrorMessageBox(ATM_BAUDWRT,wFunction,rc);
  600.   return(rc);
  601.   }
  602.  
  603. APIRET GetBaudRate(HFILE hCom,LONG *plBaud)
  604.   {
  605.   ULONG ulDataLen = sizeof(BAUDRT);
  606.   ULONG ulParmLen = 0L;
  607.   APIRET rc;
  608.   BAUDST stBaudRate;
  609.  
  610.   *plBaud = 0;
  611.   if ((rc = DosDevIOCtl(hCom,0x01,0x63,0L,0L,&ulParmLen,&stBaudRate,sizeof(BAUDRT),&ulDataLen)) != NO_ERROR)
  612.     rc = DosDevIOCtl(hCom,0x01,0x61,0L,0L,&ulParmLen,&stBaudRate,sizeof(BAUDRT),&ulDataLen);
  613.   if (rc != NO_ERROR)
  614.     IOctlErrorMessageBox(ATM_BAUDRD,0x63,rc);
  615.   *plBaud = stBaudRate.stCurrentBaud.lBaudRate;
  616.   return(rc);
  617.   }
  618.  
  619. APIRET ForceXon(HFILE hCom)
  620.   {
  621.   ULONG ulDataLen = 0L;
  622.   ULONG ulParmLen = 0L;
  623.   APIRET rc;
  624.  
  625.   if ((rc = DosDevIOCtl(hCom,0x01,0x48,0L,0L,&ulParmLen,0L,0L,&ulDataLen)) != NO_ERROR)
  626.     IOctlErrorMessageBox(ATM_FXON,0x48,rc);
  627.   return(rc);
  628.   }
  629.  
  630. APIRET ForceXoff(HFILE hCom)
  631.   {
  632.   ULONG ulDataLen = 0L;
  633.   ULONG ulParmLen = 0L;
  634.   APIRET rc;
  635.  
  636.   if ((rc = DosDevIOCtl(hCom,0x01,0x47,0L,0L,&ulParmLen,0L,0L,&ulDataLen)) != NO_ERROR)
  637.     IOctlErrorMessageBox(ATM_FXOFF,0x47,rc);
  638.   return(rc);
  639.   }
  640.  
  641. void FlushComBuffer(HFILE hCom,ULONG ulDirection)
  642.   {
  643.   ULONG cbDataLen = 0;
  644.   ULONG cbParmLen = 1;
  645.   WORD Error;
  646.   BYTE byParam = 0;
  647.  
  648.   if ((Error = DosDevIOCtl(hCom,0x0b,ulDirection,&byParam,1L,&cbParmLen,0L,0L,&cbDataLen)) != NO_ERROR)
  649.     IOctlErrorMessageBox(ATM_FLUSH,0x0b,Error);
  650.   }
  651.  
  652. void SendXonXoff(HFILE hCom,WORD wSignal)
  653.   {
  654.   DCB stComDCB;
  655.   BYTE byTemp;
  656.  
  657.   GetDCB(hCom,&stComDCB);
  658.   if (wSignal == SEND_XON)
  659.     byTemp = stComDCB.byXonChar;
  660.   else
  661.     byTemp = stComDCB.byXoffChar;
  662.  
  663.   SendByteImmediate(hCom,byTemp);
  664.   }
  665.  
  666. /********************************************************************************
  667. **  Terminal Tread
  668. **
  669. **  This code is launched via the DosCreateThread API function.
  670. **
  671. **  It continues to loop until the "bStopThread" variable is TRUE.  As this thread
  672. **  ends it sets a semphore so that the main process will know it is finisned.  This
  673. **  is used to "synchronize" the thread exit to the main thread.  See function
  674. **  "KillThread" for more information.
  675. **
  676. **  Note that all variables defined externally are accessable by both this thread
  677. **  and the main thread.
  678. **
  679. **  A call to DosOpen must have been called to open the port and initialize the
  680. **  "hCom" variable before calling DosCreateThread.
  681. **
  682. **********************************************************************************/
  683.  
  684. void APIENTRY TerminalThread(HFILE hCom)
  685.   {
  686.   APIRET rc;
  687.   ULONG ulCount;
  688.   BYTE byTemp;
  689.  
  690.   while (!bStopThread)
  691.     {
  692.     if (!bInputLF)
  693.       {
  694.       if ((rc = DosRead(hCom,(PVOID)abyInString,80,&ulCount)) != NO_ERROR)
  695.         {
  696.         sprintf(abyInString,"Error Reading Port - Error = %u",rc);
  697.         ErrorNotify(abyInString);
  698.         break;
  699.         }
  700.       else
  701.         if (ulCount != 0)
  702.           {
  703.           if (bRemoteEcho == TRUE)
  704.             if ((rc = DosWrite(hCom,(PVOID)abyInString,ulCount,&ulCount)) != NO_ERROR)
  705.               {
  706.               sprintf(abyInString,"Error Writing Echo to Port - Error = %u",rc);
  707.               ErrorNotify(abyInString);
  708.               break;
  709.               }
  710.           abyInString[ulCount] = 0;
  711.           VioWrtTTY(abyInString,strlen(abyInString),hpsVio);
  712.           }
  713.       }
  714.     else
  715.       {
  716.       if ((rc = DosRead(hCom,(PVOID)&byTemp,1,&ulCount)) != NO_ERROR)
  717.         {
  718.         sprintf(abyInString,"Error Reading Port - Error = %u",rc);
  719.         ErrorNotify(abyInString);
  720.         break;
  721.         }
  722.       else
  723.         if (ulCount != 0)
  724.           {
  725.           if (bRemoteEcho == TRUE)
  726.             if ((rc = DosWrite(hCom,(PVOID)&byTemp,1,&ulCount)) != NO_ERROR)
  727.               {
  728.               sprintf(abyInString,"Error Writing Echo to Port - Error = %u",rc);
  729.               ErrorNotify(abyInString);
  730.               break;
  731.               }
  732.           VioWrtTTY(&byTemp,1,hpsVio);
  733.           if (byTemp == '\x0d')
  734.             VioWrtTTY("\x0a",1,hpsVio);
  735.           }
  736.       }
  737.     }
  738.   WinSendMsg(hwndClient,UM_KILLTHREAD,0L,0L);
  739.   DosPostEventSem(hevKillThreadSem);
  740.   }
  741.  
  742. /*
  743. **  CreateThread
  744. **
  745. **  Creates COM port thread
  746. **
  747. **  Since serial devices must sometimes wait for data to be received (and sometimes
  748. **  transmitted), it makes sense to read from, and write to, a serial device from
  749. **  some thread other than the thread that is executing the main window thread.
  750. **
  751. **  If you do a DosRead to the serial device driver (COMx) the device driver will
  752. **  not return to the calling thread until either all of the characters requested
  753. **  are received or until the read time-out period has passed.  If you DosRead from
  754. **  the main window thread, no other window thread can run until the device driver
  755. **  has returned control to its calling thread and that thread has returned control
  756. **  the the window queue.
  757. */
  758. VOID CreateThread(TID *ptidThread)
  759.   {
  760.   bStopThread = FALSE;
  761.   DosCreateThread(ptidThread,(PFNTHREAD)TerminalThread,0L,0L,4096);
  762.   }
  763.  
  764. /*
  765. **  Killing the COM thread is only made complicated by the desire to have the main
  766. **  window thread not return control to the user until the COM thread has been killed
  767. **  and is no longer blocked in the device driver.
  768. **
  769. **  This could cause a problem if the read (or write) time-out is relatively long
  770. **  and the thread is blocked in the device driver when "KillThread" is called.  It
  771. **  would be a good idea to either flush the buffers (see "FlushComBuffer" function),
  772. **  or cause the read time-out to be shortened (see "SetDCB" function) as part of the
  773. **  "KillThread" processing.
  774. */
  775. VOID KillThread(void)
  776.   {
  777.   APIRET rc;
  778.   ULONG ulPostCount;
  779.  
  780.   DosResetEventSem(hevKillThreadSem,&ulPostCount);
  781.   bStopThread = TRUE;
  782.   /*
  783.   ** Flush buffers or lower time-out values, if necessary.
  784.   **
  785.   ** GetDCB
  786.   ** set time-outs to zero
  787.   ** SetDCB
  788.   */
  789.   DosWaitEventSem(hevKillThreadSem,10000);  // 10000 (ten seconds) is arbitrary
  790.                                             // and should probably be -1, once
  791.                                             // code is debugged
  792.   /*
  793.   ** reset time-outs to required values
  794.   ** SetDCB
  795.   */
  796.   }
  797.  
  798.