Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1439 lines
47 KiB

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  7. //
  8. // MODULE: CommCode.c
  9. //
  10. // PURPOSE: Handles all the COMM routines for TapiComm.
  11. //
  12. // EXPORTED FUNCTIONS: These functions are for use by other modules.
  13. // StartComm - Start communications.
  14. // StopComm - Stop Communications.
  15. // WriteCommString - Write a string to the Comm port.
  16. //
  17. // INTERNAL FUNCTION: These functions are for this module only.
  18. // CloseReadThread - Close the Read Thread.
  19. // CloseWriteThread - Close the Write Thread.
  20. //
  21. // StartReadThreadProc - Starting function for the Read Thread.
  22. // StartWriteThreadProc - Starting function for the Write Thread.
  23. //
  24. // - Write Thread helper function
  25. // HandleWriteData - Actually does the work of writing a string to comm.
  26. //
  27. // - Read Thread helper functions
  28. // SetupReadEvent - Sets up the overlapped ReadFile
  29. // HandleReadEvent - Gets the results from the overlapped ReadFile
  30. // HandleReadData - Handles data returned from the ReadFile
  31. //
  32. // HandleCommEvent - Sets up the CommEvent event.
  33. // SetupCommEvent - Handles CommEvent events (if they occur).
  34. //
  35. #include <windows.h>
  36. #include <string.h>
  37. #include "TapiCode.h"
  38. #include "CommCode.h"
  39. #include "globals.h"
  40. #include "TapiInfo.h"
  41. #include "dpspimp.h"
  42. #include "logit.h"
  43. // This is the message posted to the WriteThread
  44. // When we have something to write.
  45. // Default size of the Input Buffer used by this code.
  46. #define INPUTBUFFERSIZE 2048
  47. //*****************************************
  48. // Global variables.
  49. //*****************************************
  50. volatile BOOL g_bIgnoreReads = FALSE;
  51. volatile BOOL g_bRecovery = FALSE;
  52. HANDLE g_hCommFile = NULL;
  53. DWORD g_dwIOThreadID = 0;
  54. HANDLE g_hIOThread = NULL;
  55. HANDLE g_hCloseEvent = NULL;
  56. HANDLE g_hDummyEvent1 = NULL;
  57. HANDLE g_hDummyEvent2 = NULL;
  58. HANDLE g_hReadEvent = NULL;
  59. HANDLE g_hWriteEvent1 = NULL;
  60. HANDLE g_hWriteEvent0 = NULL;
  61. HANDLE g_hCommEvent = NULL;
  62. CImpIDP_SP *g_IDP = NULL;
  63. DWORD dwMsgs = 0;
  64. typedef struct
  65. {
  66. BOOL bValid;
  67. LPVOID lpv;
  68. DWORD dwSize;
  69. } WRITE_WAIT;
  70. WRITE_WAIT writewait[2];
  71. MSG_BUILDER msg_Building;
  72. //*****************************************
  73. // CommCode internal Function Prototypes
  74. //*****************************************
  75. void CloseReadThread();
  76. void CloseWriteThread();
  77. DWORD WINAPI StartIOThreadProc(LPVOID lpvParam);
  78. BOOL HandleWriteData(LPOVERLAPPED lpOverlappedWrite,
  79. LPCSTR lpszStringToWrite, DWORD dwNumberOfBytesToWrite);
  80. BOOL SetupReadEvent(LPOVERLAPPED lpOverlappedRead,
  81. LPSTR lpszInputBuffer, DWORD dwSizeofBuffer,
  82. LPDWORD lpnNumberOfBytesRead);
  83. BOOL HandleReadEvent(LPOVERLAPPED lpOverlappedRead,
  84. LPSTR lpszInputBuffer, DWORD dwSizeofBuffer,
  85. LPDWORD lpnNumberOfBytesRead);
  86. BOOL HandleReadData(LPCSTR lpszInputBuffer, DWORD dwSizeofBuffer);
  87. BOOL HandleCommEvent(LPOVERLAPPED lpOverlappedCommEvent,
  88. LPDWORD lpfdwEvtMask, BOOL fRetrieveEvent);
  89. BOOL SetupCommEvent(LPOVERLAPPED lpOverlappedCommEvent,
  90. LPDWORD lpfdwEvtMask);
  91. #define WAIT_OBJECT_1 (WAIT_OBJECT_0 + 1)
  92. #define WAIT_OBJECT_2 (WAIT_OBJECT_0 + 2)
  93. #define WAIT_OBJECT_3 (WAIT_OBJECT_0 + 3)
  94. #define WAIT_OBJECT_4 (WAIT_OBJECT_0 + 4)
  95. #define WAIT_OBJECT_5 (WAIT_OBJECT_0 + 5)
  96. volatile BOOL g_bCommStarted = FALSE;
  97. //*****************************************
  98. // Functions exported for use by other modules
  99. //*****************************************
  100. //
  101. // FUNCTION: StartComm(HANDLE)
  102. //
  103. // PURPOSE: Starts communications over the comm port.
  104. //
  105. // PARAMETERS:
  106. // hNewCommFile - This is the COMM File handle to communicate with.
  107. // This handle is obtained from TAPI.
  108. //
  109. // RETURN VALUE:
  110. // TRUE if able to setup the communications.
  111. //
  112. // COMMENTS:
  113. //
  114. // StartComm makes sure there isn't communication in progress already,
  115. // the hNewCommFile is valid, and all the threads can be created. It
  116. // also configures the hNewCommFile for the appropriate COMM settings.
  117. //
  118. // If StartComm fails for any reason, it's up to the calling application
  119. // to close the Comm file handle.
  120. //
  121. //
  122. extern BOOL CreateQueue(DWORD dwElements, DWORD dwmaxMsg, DWORD dwmaxPlayers);
  123. extern BOOL DeleteQueue();
  124. BOOL _cdecl StartComm(HANDLE hNewCommFile, HANDLE hEvent)
  125. {
  126. // Is this a valid comm handle?
  127. if (GetFileType(hNewCommFile) != FILE_TYPE_CHAR)
  128. {
  129. TSHELL_INFO(TEXT("File handle is not a comm handle."));
  130. return FALSE;
  131. }
  132. // Are we already doing comm?
  133. if (g_hCommFile != NULL)
  134. {
  135. TSHELL_INFO(TEXT("Already have a comm file open"));
  136. return FALSE;
  137. }
  138. // Its ok to continue.
  139. g_hCommFile = hNewCommFile;
  140. // Setting and querying the comm port configurations.
  141. { // Configure the comm settings.
  142. COMMTIMEOUTS commtimeouts;
  143. DCB dcb;
  144. COMMPROP commprop;
  145. DWORD fdwEvtMask;
  146. // These are here just so you can set a breakpoint
  147. // and see what the comm settings are. Most Comm settings
  148. // are already set through TAPI.
  149. GetCommState(hNewCommFile, &dcb);
  150. GetCommProperties(hNewCommFile, &commprop);
  151. GetCommMask(g_hCommFile, &fdwEvtMask);
  152. GetCommTimeouts(g_hCommFile, &commtimeouts);
  153. // The CommTimeout numbers will very likely change if you are
  154. // coding to meet some kind of specification where
  155. // you need to reply within a certain amount of time after
  156. // recieving the last byte. However, If 1/4th of a second
  157. // goes by between recieving two characters, its a good
  158. // indication that the transmitting end has finished, even
  159. // assuming a 1200 baud modem.
  160. commtimeouts.ReadIntervalTimeout = 250;
  161. commtimeouts.ReadTotalTimeoutMultiplier = 0;
  162. commtimeouts.ReadTotalTimeoutConstant = 0;
  163. commtimeouts.WriteTotalTimeoutMultiplier = 0;
  164. commtimeouts.WriteTotalTimeoutConstant = 0;
  165. SetCommTimeouts(g_hCommFile, &commtimeouts);
  166. // fAbortOnError is the only DCB dependancy in TapiComm.
  167. // Can't guarentee that the SP will set this to what we expect.
  168. dcb.fAbortOnError = FALSE;
  169. SetCommState(hNewCommFile, &dcb);
  170. }
  171. // Create the events we need.
  172. g_hCloseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  173. g_hReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  174. g_hDummyEvent1 = CreateEvent(NULL, TRUE, FALSE, NULL);
  175. g_hDummyEvent2 = CreateEvent(NULL, TRUE, FALSE, NULL);
  176. g_hWriteEvent1 = CreateEvent(NULL, TRUE, FALSE, NULL);
  177. g_hWriteEvent0 = CreateEvent(NULL, TRUE, FALSE, NULL);
  178. g_hCommEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  179. if ( !g_hCloseEvent
  180. || !g_hDummyEvent1
  181. || !g_hReadEvent
  182. || !g_hDummyEvent2
  183. || !g_hWriteEvent1
  184. || !g_hWriteEvent0
  185. || !g_hCommEvent)
  186. {
  187. DBG_INFO((DBGARG, TEXT("Unable to CreateEvent: %d"), GetLastError()));
  188. g_hCommFile = NULL;
  189. return FALSE;
  190. }
  191. // Create the Read thread.
  192. g_hIOThread =
  193. CreateThread(NULL, 0, StartIOThreadProc, 0, 0, &g_dwIOThreadID);
  194. if (g_hIOThread == NULL)
  195. {
  196. DBG_INFO((DBGARG, TEXT("Unable to create IO thread: %d"), GetLastError()));
  197. g_dwIOThreadID = 0;
  198. g_hCommFile = 0;
  199. if (g_hCloseEvent ) CloseHandle(g_hCloseEvent );
  200. if (g_hReadEvent ) CloseHandle(g_hReadEvent );
  201. if (g_hDummyEvent1) CloseHandle(g_hDummyEvent1);
  202. if (g_hDummyEvent2) CloseHandle(g_hDummyEvent2);
  203. if (g_hWriteEvent1) CloseHandle(g_hWriteEvent1);
  204. if (g_hWriteEvent0) CloseHandle(g_hWriteEvent0);
  205. if (g_hCommEvent ) CloseHandle(g_hCommEvent );
  206. g_hCloseEvent = NULL;
  207. g_hReadEvent = NULL;
  208. g_hDummyEvent1 = NULL;
  209. g_hDummyEvent2 = NULL;
  210. g_hWriteEvent1 = NULL;
  211. g_hWriteEvent0 = NULL;
  212. g_hCommEvent = NULL;
  213. return FALSE;
  214. }
  215. // Comm threads should to have a higher base priority than the UI thread.
  216. // If they don't, then any temporary priority boost the UI thread gains
  217. // could cause the COMM threads to loose data.
  218. SetThreadPriority(g_hIOThread, THREAD_PRIORITY_HIGHEST);
  219. g_bCommStarted = TRUE;
  220. // Everything was created ok. Ready to go!
  221. if (hEvent)
  222. SetEvent(hEvent);
  223. return TRUE;
  224. }
  225. //
  226. // FUNCTION: StopComm
  227. //
  228. // PURPOSE: Stop and end all communication threads.
  229. //
  230. // PARAMETERS:
  231. // none
  232. //
  233. // RETURN VALUE:
  234. // none
  235. //
  236. // COMMENTS:
  237. //
  238. // Tries to gracefully signal all communication threads to
  239. // close, but terminates them if it has to.
  240. //
  241. //
  242. void _cdecl StopComm(HANDLE hEvent)
  243. {
  244. g_bCommStarted = FALSE;
  245. // No need to continue if we're not communicating.
  246. if (g_hCommFile == NULL)
  247. return;
  248. TSHELL_INFO(TEXT("Stopping the Comm."));
  249. if (g_hIOThread)
  250. {
  251. TSHELL_INFO(TEXT("Closing Read Thread"));
  252. // Signal the event to close the worker threads.
  253. SetEvent(g_hCloseEvent);
  254. // Purge all outstanding reads
  255. PurgeComm(g_hCommFile, PURGE_RXABORT | PURGE_RXCLEAR
  256. | PURGE_TXABORT | PURGE_TXCLEAR);
  257. // Wait 10 seconds for it to exit. Shouldn't happen.
  258. if (WaitForSingleObject(g_hIOThread, 10000) == WAIT_TIMEOUT)
  259. {
  260. TSHELL_INFO(TEXT("IO thread not exiting. Terminating it."));
  261. TerminateThread(g_hIOThread, 0);
  262. // The ReadThread cleans up these itself if it terminates
  263. // normally.
  264. CloseHandle(g_hIOThread);
  265. g_hIOThread = 0;
  266. g_dwIOThreadID = 0;
  267. }
  268. }
  269. CloseHandle(g_hCloseEvent );
  270. CloseHandle(g_hDummyEvent1);
  271. CloseHandle(g_hDummyEvent2);
  272. CloseHandle(g_hWriteEvent1);
  273. CloseHandle(g_hWriteEvent0);
  274. CloseHandle(g_hCommEvent );
  275. g_hCloseEvent = NULL;
  276. g_hDummyEvent1 = NULL;
  277. g_hDummyEvent2 = NULL;
  278. g_hWriteEvent1 = NULL;
  279. g_hWriteEvent0 = NULL;
  280. g_hCommEvent = NULL;
  281. // Now close the comm port handle.
  282. CloseHandle(g_hCommFile);
  283. g_hCommFile = NULL;
  284. if (hEvent)
  285. SetEvent(hEvent);
  286. }
  287. //
  288. // FUNCTION: WriteCommString(LPCSTR, DWORD)
  289. //
  290. // PURPOSE: Send a String to the Write Thread to be written to the Comm.
  291. //
  292. // PARAMETERS:
  293. // pszStringToWrite - String to Write to Comm port.
  294. // nSizeofStringToWrite - length of pszStringToWrite.
  295. //
  296. // RETURN VALUE:
  297. // Returns TRUE if the PostMessage is successful.
  298. // Returns FALSE if PostMessage fails or Write thread doesn't exist.
  299. //
  300. // COMMENTS:
  301. //
  302. // This is a wrapper function so that other modules don't care that
  303. // Comm writing is done via PostMessage to a Write thread. Note that
  304. // using PostMessage speeds up response to the UI (very little delay to
  305. // 'write' a string) and provides a natural buffer if the comm is slow
  306. // (ie: the messages just pile up in the message queue).
  307. //
  308. // Note that it is assumed that pszStringToWrite is allocated with
  309. // LocalAlloc, and that if WriteCommString succeeds, its the job of the
  310. // Write thread to LocalFree it. If WriteCommString fails, then its
  311. // the job of the calling function to free the string.
  312. //
  313. //
  314. BOOL WriteCommString(LPVOID lpszStringToWrite, DWORD dwSizeofStringToWrite)
  315. {
  316. if (g_hIOThread)
  317. {
  318. if (PostThreadMessage(g_dwIOThreadID, PWM_COMMWRITE,
  319. (WPARAM) dwSizeofStringToWrite, (LPARAM) lpszStringToWrite))
  320. {
  321. if (g_IDP)
  322. InterlockedIncrement((LPLONG) &g_IDP->m_dwPendingWrites);
  323. return TRUE;
  324. }
  325. else
  326. TSHELL_INFO(TEXT("Failed to Post to Write thread."));
  327. }
  328. else
  329. TSHELL_INFO(TEXT("Write thread not created."));
  330. return FALSE;
  331. }
  332. //*****************************************
  333. // The rest of the functions are intended for use
  334. // only within the CommCode module.
  335. //*****************************************
  336. //
  337. // FUNCTION: StartIOThreadProc(LPVOID)
  338. //
  339. // PURPOSE: The starting point for the Write thread.
  340. //
  341. // PARAMETERS:
  342. // lpvParam - unused.
  343. //
  344. // RETURN VALUE:
  345. // DWORD - unused.
  346. //
  347. // COMMENTS:
  348. //
  349. // The Write thread uses a PeekMessage loop to wait for a string to write,
  350. // and when it gets one, it writes it to the Comm port. If the CloseEvent
  351. // object is signaled, then it exits. The use of messages to tell the
  352. // Write thread what to write provides a natural desynchronization between
  353. // the UI and the Write thread.
  354. //
  355. //
  356. typedef enum
  357. {
  358. READ_HDR,
  359. READ_MSG,
  360. READ_RECOVER_K,
  361. READ_RECOVER_J,
  362. READ_RECOVER_y,
  363. READ_RECOVER_o,
  364. READ_RECOVER_r,
  365. READ_RECOVER_h,
  366. READ_RECOVER_a,
  367. READ_RECOVER_n,
  368. READ_RECOVER_H,
  369. READ_RECOVER_a2,
  370. READ_RECOVER_l1,
  371. READ_RECOVER_l2,
  372. READ_GOOD_CONNECT_1,
  373. RG2,
  374. RG3,
  375. RG4,
  376. RG5,
  377. RG6,
  378. RG7,
  379. RG8,
  380. RG9,
  381. RG10,
  382. RG11,
  383. RG12,
  384. RG13,
  385. RG14,
  386. RG15,
  387. RG16
  388. } READ_STATE;
  389. typedef enum
  390. {
  391. ZERO_PENDING,
  392. ONE_PENDING,
  393. TWO_PENDING
  394. } WRITE_STATE;
  395. #ifdef DEBUG
  396. #define WAIT_ZERO_PENDING INFINITE
  397. #else
  398. #define WAIT_ZERO_PENDING 5000
  399. #endif
  400. DWORD WINAPI StartIOThreadProc(LPVOID lpvParam)
  401. {
  402. MSG msg;
  403. DWORD dwHandleSignaled;
  404. READ_STATE rState = READ_HDR;
  405. WRITE_STATE wState = ZERO_PENDING;
  406. HANDLE HandlesToWaitFor[5];
  407. OVERLAPPED overlappedWrite0 = {0, 0, 0, 0, NULL};
  408. OVERLAPPED overlappedWrite1 = {0, 0, 0, 0, NULL};
  409. OVERLAPPED overlappedCommEvent = {0, 0, 0, 0, NULL};
  410. OVERLAPPED overlappedRead = {0, 0, 0, 0, NULL};
  411. DWORD dwCount;
  412. DWORD dwReadCountExpected;
  413. DWORD fdwEvtMask;
  414. BOOL bb;
  415. BOOL bFirst = TRUE;
  416. DWORD dwTimeBegin = 0;
  417. DWORD dwBadBegin = 0;
  418. HandlesToWaitFor[0] = g_hCloseEvent;
  419. HandlesToWaitFor[1] = g_hCommEvent;
  420. HandlesToWaitFor[2] = g_hReadEvent;
  421. overlappedRead.hEvent = g_hReadEvent;
  422. overlappedCommEvent.hEvent = g_hCommEvent;
  423. overlappedWrite0.hEvent = g_hWriteEvent0;
  424. overlappedWrite1.hEvent = g_hWriteEvent1;
  425. writewait[0].bValid = FALSE;
  426. writewait[0].lpv = NULL;
  427. writewait[0].dwSize = 0;
  428. writewait[1].bValid = FALSE;
  429. writewait[1].lpv = NULL;
  430. writewait[1].dwSize = 0;
  431. // Setup CommEvent handling.
  432. // Set the comm mask so we receive error signals.
  433. if (!SetCommMask(g_hCommFile, EV_ERR))
  434. {
  435. DBG_INFO((DBGARG, TEXT("Unable to SetCommMask: %d"), GetLastError()));
  436. PostHangupCall();
  437. return(0);
  438. }
  439. // Start waiting for CommEvents (Errors)
  440. if (!SetupCommEvent(&overlappedCommEvent, &fdwEvtMask))
  441. {
  442. PostHangupCall();
  443. return(0);
  444. }
  445. dwCount = sizeof(DPHDR);
  446. dwReadCountExpected = dwCount;
  447. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  448. TSHELL_INFO(TEXT("Comm started so release waiting operations."));
  449. g_IDP->SetBlock();
  450. while (TRUE)
  451. {
  452. switch(wState)
  453. {
  454. case ZERO_PENDING:
  455. {
  456. HandlesToWaitFor[3] = g_hDummyEvent1;
  457. HandlesToWaitFor[4] = g_hWriteEvent1;
  458. // TSHELL_INFO(TEXT("Wait with 0 Pending."));
  459. dwHandleSignaled =
  460. MsgWaitForMultipleObjects(5, HandlesToWaitFor, FALSE,
  461. WAIT_ZERO_PENDING, QS_ALLINPUT);
  462. }
  463. break;
  464. case ONE_PENDING:
  465. {
  466. // TSHELL_INFO(TEXT("Wait with 1 Pending."));
  467. if (writewait[0].bValid)
  468. {
  469. HandlesToWaitFor[3] = g_hWriteEvent0;
  470. HandlesToWaitFor[4] = g_hDummyEvent2;
  471. }
  472. else
  473. {
  474. HandlesToWaitFor[3] = g_hDummyEvent1;
  475. HandlesToWaitFor[4] = g_hWriteEvent1;
  476. }
  477. dwHandleSignaled =
  478. MsgWaitForMultipleObjects(5, HandlesToWaitFor, FALSE,
  479. INFINITE, QS_ALLINPUT);
  480. }
  481. break;
  482. case TWO_PENDING:
  483. {
  484. // TSHELL_INFO(TEXT("Wait with 2 Pending."));
  485. HandlesToWaitFor[3] = g_hWriteEvent0;
  486. HandlesToWaitFor[4] = g_hWriteEvent1;
  487. dwHandleSignaled =
  488. WaitForMultipleObjects(5, HandlesToWaitFor, FALSE,
  489. INFINITE);
  490. }
  491. break;
  492. default:
  493. TSHELL_INFO(TEXT("Invalid Write State"));
  494. }
  495. // DBG_INFO((DBGARG, TEXT("IO Thread Woken up. %8x"), dwHandleSignaled));
  496. switch (dwHandleSignaled)
  497. {
  498. case WAIT_TIMEOUT:
  499. //
  500. // Do to what I believe are problems with MsgWait() we will
  501. // time out MsgWait() at 1000msec if in the zero pending state.
  502. //
  503. break;
  504. case WAIT_OBJECT_0: // CloseEvent
  505. {
  506. TSHELL_INFO(TEXT("Close Event recieved."));
  507. //
  508. // Cleanup and Exit
  509. //
  510. return(0);
  511. }
  512. break;
  513. case WAIT_OBJECT_1: // CommEvent
  514. {
  515. TSHELL_INFO(TEXT("CommEvent Recieved."));
  516. // Handle the CommEvent.
  517. if (!HandleCommEvent(&overlappedCommEvent, &fdwEvtMask, TRUE))
  518. {
  519. PostHangupCall();
  520. return(0);
  521. }
  522. // Start waiting for the next CommEvent.
  523. if (!SetupCommEvent(&overlappedCommEvent, &fdwEvtMask))
  524. {
  525. PostHangupCall();
  526. return(0);
  527. }
  528. }
  529. break;
  530. case WAIT_OBJECT_2: // ReadEvent
  531. {
  532. // TSHELL_INFO(TEXT("ReadEvent Recieved."));
  533. bb = GetOverlappedResult(g_hCommFile, &overlappedRead, &dwCount, FALSE);
  534. DBG_INFO((DBGARG, TEXT("Read expected %d and got %d on result %d"),
  535. dwReadCountExpected, dwCount, bb));
  536. if (dwCount == dwReadCountExpected)
  537. {
  538. if (rState == READ_HDR)
  539. {
  540. DBG_INFO((DBGARG, TEXT("Read Hdr to(%d) from(%d) count (%d) cookie(%d) All(%8x)"),
  541. msg_Building.dpHdr.to,
  542. msg_Building.dpHdr.from,
  543. msg_Building.dpHdr.usCount,
  544. msg_Building.dpHdr.usCookie,
  545. msg_Building.dpHdr.dwConnect1));
  546. if ( msg_Building.dpHdr.usCookie == SPSYS_USER
  547. || msg_Building.dpHdr.usCookie == SPSYS_SYS
  548. || msg_Building.dpHdr.usCookie == SPSYS_HIGH
  549. || msg_Building.dpHdr.usCookie == SPSYS_CONNECT)
  550. {
  551. // TSHELL_INFO(TEXT("Got a valid msg header, look for body."));
  552. rState = READ_MSG;
  553. dwReadCountExpected = msg_Building.dpHdr.usCount;
  554. ResetEvent(g_hReadEvent);
  555. ReadFile(g_hCommFile, msg_Building.chMsgCompose,
  556. dwReadCountExpected, &dwCount, &overlappedRead);
  557. }
  558. else if ( msg_Building.dpHdr.dwConnect1 == DPSYS_JOHN)
  559. {
  560. SPMSG_CONNECT *pMsg;
  561. TSHELL_INFO(TEXT("Other end needs recover ssync."));
  562. pMsg = (SPMSG_CONNECT *) LocalAlloc(LMEM_FIXED, sizeof(SPMSG_CONNECT));
  563. if (pMsg)
  564. {
  565. pMsg->dpHdr.to = 0;
  566. pMsg->dpHdr.from = 0;
  567. pMsg->dpHdr.usCount = sizeof(SPMSG_CONNECT) - sizeof(DPHDR);
  568. pMsg->dpHdr.usCookie = SPSYS_CONNECT;
  569. pMsg->usVerMajor = DPVERSION_MAJOR;
  570. pMsg->usVerMinor = DPVERSION_MINOR;
  571. pMsg->dwConnect1 = DPSYS_KYRA;
  572. pMsg->dwConnect2 = DPSYS_HALL;
  573. WriteCommString(pMsg, sizeof(SPMSG_CONNECT));
  574. dwCount = sizeof(DPHDR);
  575. dwReadCountExpected = dwCount;
  576. ResetEvent(g_hReadEvent);
  577. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  578. }
  579. else
  580. {
  581. PostHangupCall();
  582. return(0);
  583. }
  584. }
  585. else
  586. {
  587. DPHDR *pRecover;
  588. TSHELL_INFO(TEXT("Bad header type. Enter recover state."));
  589. if (bFirst)
  590. {
  591. PurgeComm(g_hCommFile, PURGE_RXCLEAR);
  592. rState = READ_GOOD_CONNECT_1;
  593. dwCount = 1;
  594. dwReadCountExpected = dwCount;
  595. ResetEvent(g_hReadEvent);
  596. dwTimeBegin = GetTickCount();
  597. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  598. }
  599. else
  600. {
  601. pRecover = (DPHDR *) LocalAlloc(LMEM_FIXED, sizeof(DPHDR));
  602. if (pRecover)
  603. {
  604. g_bRecovery = TRUE;
  605. pRecover->dwConnect1 = DPSYS_JOHN;
  606. DBG_INFO((DBGARG, TEXT("Send John 1 %8x"), pRecover));
  607. WriteCommString(pRecover, sizeof(DPHDR));
  608. PurgeComm(g_hCommFile, PURGE_RXCLEAR);
  609. rState = READ_RECOVER_K;
  610. dwCount = 1;
  611. dwReadCountExpected = dwCount;
  612. ResetEvent(g_hReadEvent);
  613. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  614. }
  615. else
  616. {
  617. PostHangupCall();
  618. return(0);
  619. }
  620. }
  621. }
  622. }
  623. else if (rState == READ_MSG)
  624. {
  625. bFirst = FALSE;
  626. g_IDP->HandleMessage((LPVOID) &msg_Building, dwReadCountExpected);
  627. rState = READ_HDR;
  628. dwCount = sizeof(DPHDR);
  629. dwReadCountExpected = dwCount;
  630. ResetEvent(g_hReadEvent);
  631. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  632. }
  633. else if (rState >= READ_GOOD_CONNECT_1)
  634. {
  635. char ch = *((CHAR *) (&msg_Building.dpHdr));
  636. BOOL bSuccess = FALSE;
  637. DBG_INFO((DBGARG, TEXT("First Connect state loop. %x, State %d"), 0x000000ff & ch, rState));
  638. switch( rState)
  639. {
  640. case READ_GOOD_CONNECT_1:
  641. rState = (ch == 0x00) ? RG2 : READ_GOOD_CONNECT_1;
  642. break;
  643. case RG2:
  644. rState = (ch == 0x00) ? RG3 : READ_GOOD_CONNECT_1;
  645. break;
  646. case RG3 :
  647. if (ch == 0x0c)
  648. rState = RG4;
  649. else if (ch == 0x00)
  650. rState = RG3;
  651. else
  652. rState = READ_GOOD_CONNECT_1;
  653. break;
  654. case RG4 :
  655. rState = (ch == 0x3c) ? RG5 : READ_GOOD_CONNECT_1;
  656. break;
  657. case RG5 :
  658. rState = (ch == 0x01) ? RG6 : READ_GOOD_CONNECT_1;
  659. break;
  660. case RG6 :
  661. rState = (ch == 0x00) ? RG7 : READ_GOOD_CONNECT_1;
  662. break;
  663. case RG7 :
  664. rState = (ch == 0x01) ? RG8 : READ_GOOD_CONNECT_1;
  665. break;
  666. case RG8 :
  667. rState = (ch == 0x00) ? RG9 : READ_GOOD_CONNECT_1;
  668. break;
  669. case RG9 :
  670. rState = (ch == 0x4b) ? RG10 : READ_GOOD_CONNECT_1;
  671. break;
  672. case RG10:
  673. rState = (ch == 0x79) ? RG11 : READ_GOOD_CONNECT_1;
  674. break;
  675. case RG11:
  676. rState = (ch == 0x72) ? RG12 : READ_GOOD_CONNECT_1;
  677. break;
  678. case RG12:
  679. rState = (ch == 0x61) ? RG13 : READ_GOOD_CONNECT_1;
  680. break;
  681. case RG13:
  682. rState = (ch == 0x48) ? RG14 : READ_GOOD_CONNECT_1;
  683. break;
  684. case RG14:
  685. rState = (ch == 0x61) ? RG15 : READ_GOOD_CONNECT_1;
  686. break;
  687. case RG15:
  688. rState = (ch == 0x6c) ? RG16 : READ_GOOD_CONNECT_1;
  689. break;
  690. case RG16:
  691. rState = (ch == 0x6c) ? READ_HDR : READ_GOOD_CONNECT_1;
  692. break;
  693. default:
  694. rState = READ_GOOD_CONNECT_1;
  695. }
  696. ResetEvent(g_hReadEvent);
  697. if (rState == READ_HDR)
  698. {
  699. SPMSG_CONNECT *pConnect;
  700. pConnect = (SPMSG_CONNECT *) &msg_Building;
  701. pConnect->dpHdr.to = 0;
  702. pConnect->dpHdr.from = 0;
  703. pConnect->dpHdr.usCount = sizeof(SPMSG_CONNECT) - sizeof(DPHDR);
  704. pConnect->dpHdr.usCookie = SPSYS_CONNECT;
  705. pConnect->usVerMajor = DPVERSION_MAJOR;
  706. pConnect->usVerMinor = DPVERSION_MINOR;
  707. pConnect->dwConnect1 = DPSYS_KYRA;
  708. pConnect->dwConnect2 = DPSYS_HALL;
  709. g_IDP->HandleMessage((LPVOID) &msg_Building, sizeof(SPMSG_CONNECT));
  710. dwCount = sizeof(READ_HDR);
  711. dwReadCountExpected = dwCount;
  712. TSHELL_INFO(TEXT("Sweet recovery, I hope."));
  713. DBG_INFO(( DBGARG, TEXT("Garbage process %d ticks"),
  714. GetTickCount() - dwTimeBegin));
  715. }
  716. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  717. }
  718. else
  719. {
  720. char ch = *((CHAR *) (&msg_Building.dpHdr));
  721. BOOL bSuccess = FALSE;
  722. DBG_INFO((DBGARG, TEXT("Recover state loop. %x"), 0x000000ff & ch));
  723. switch (ch)
  724. {
  725. case 'K':
  726. if (rState == READ_RECOVER_K)
  727. rState = READ_RECOVER_y;
  728. else
  729. rState = READ_RECOVER_K;
  730. break;
  731. case 'y':
  732. if (rState == READ_RECOVER_y)
  733. rState = READ_RECOVER_r;
  734. else
  735. rState = READ_RECOVER_K;
  736. break;
  737. case 'r':
  738. if (rState == READ_RECOVER_r)
  739. rState = READ_RECOVER_a;
  740. else
  741. rState = READ_RECOVER_K;
  742. break;
  743. case 'a':
  744. if (rState == READ_RECOVER_a)
  745. rState = READ_RECOVER_H;
  746. else if (rState == READ_RECOVER_a2)
  747. rState = READ_RECOVER_l1;
  748. else
  749. rState = READ_RECOVER_K;
  750. break;
  751. case 'H':
  752. if (rState == READ_RECOVER_H)
  753. rState = READ_RECOVER_a2;
  754. else
  755. rState = READ_RECOVER_K;
  756. break;
  757. case 'l':
  758. if (rState == READ_RECOVER_l1)
  759. rState = READ_RECOVER_l2;
  760. else if (rState == READ_RECOVER_l2)
  761. {
  762. SPMSG_CONNECT *pMsg;
  763. pMsg = (SPMSG_CONNECT *) LocalAlloc(LMEM_FIXED, sizeof(SPMSG_CONNECT));
  764. if (pMsg)
  765. {
  766. pMsg->dpHdr.to = 0;
  767. pMsg->dpHdr.from = 0;
  768. pMsg->dpHdr.usCount = sizeof(SPMSG_CONNECT) - sizeof(DPHDR);
  769. pMsg->dpHdr.usCookie = SPSYS_CONNECT;
  770. pMsg->usVerMajor = DPVERSION_MAJOR;
  771. pMsg->usVerMinor = DPVERSION_MINOR;
  772. pMsg->dwConnect1 = DPSYS_KYRA;
  773. pMsg->dwConnect2 = DPSYS_HALL;
  774. WriteCommString(pMsg, sizeof(SPMSG_CONNECT));
  775. bSuccess = TRUE;
  776. g_bRecovery = FALSE;
  777. }
  778. else
  779. {
  780. PostHangupCall();
  781. return(0);
  782. }
  783. }
  784. else
  785. rState = READ_RECOVER_K;
  786. break;
  787. case 'J':
  788. if (rState == READ_RECOVER_J)
  789. rState = READ_RECOVER_o;
  790. else
  791. rState = READ_RECOVER_K;
  792. break;
  793. case 'o':
  794. if (rState == READ_RECOVER_o)
  795. rState = READ_RECOVER_h;
  796. else
  797. rState = READ_RECOVER_K;
  798. break;
  799. case 'h':
  800. if (rState == READ_RECOVER_h)
  801. rState = READ_RECOVER_n;
  802. else
  803. rState = READ_RECOVER_K;
  804. break;
  805. case 'n':
  806. if (rState == READ_RECOVER_n)
  807. bSuccess = TRUE;
  808. else
  809. rState = READ_RECOVER_K;
  810. break;
  811. default:
  812. rState = READ_RECOVER_K;
  813. break;
  814. }
  815. if (bSuccess)
  816. {
  817. rState = READ_HDR;
  818. dwCount = sizeof(DPHDR);
  819. }
  820. else
  821. {
  822. dwCount = 1;
  823. }
  824. dwReadCountExpected = dwCount;
  825. ResetEvent(g_hReadEvent);
  826. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  827. }
  828. }
  829. else
  830. {
  831. DPHDR *pRecover;
  832. if (g_bIgnoreReads)
  833. {
  834. TSHELL_INFO(TEXT("Ignore extraneous reads before we send something."));
  835. dwBadBegin++;
  836. if (dwBadBegin % 10)
  837. {
  838. TSHELL_INFO(TEXT("Bad Byte again."));
  839. }
  840. dwCount = sizeof(DPHDR);
  841. dwReadCountExpected = dwCount;
  842. ResetEvent(g_hReadEvent);
  843. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  844. break;
  845. }
  846. if (bFirst)
  847. {
  848. TSHELL_INFO(TEXT("Got bad data before we read anything. Look for Good Connect."));
  849. PurgeComm(g_hCommFile, PURGE_RXCLEAR);
  850. rState = READ_GOOD_CONNECT_1;
  851. dwTimeBegin = GetTickCount();
  852. dwCount = 1;
  853. dwReadCountExpected = dwCount;
  854. ResetEvent(g_hReadEvent);
  855. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  856. break;
  857. }
  858. TSHELL_INFO(TEXT("Recover from bad read count."));
  859. DBG_INFO((DBGARG, TEXT("Bad Packet Begins %8x, Read %d Expected %d State %d"),
  860. &msg_Building, dwCount, dwReadCountExpected, rState));
  861. DBG_INFO((DBGARG, TEXT("Read Bad Hdr to(%d) from(%d) count (%d) cookie(%d) All(%8x)"),
  862. msg_Building.dpHdr.to,
  863. msg_Building.dpHdr.from,
  864. msg_Building.dpHdr.usCount,
  865. msg_Building.dpHdr.usCookie,
  866. msg_Building.dpHdr.dwConnect1));
  867. pRecover = (DPHDR *) LocalAlloc(LMEM_FIXED, sizeof(DPHDR));
  868. if (pRecover)
  869. {
  870. g_bRecovery = TRUE;
  871. pRecover->dwConnect1 = DPSYS_JOHN;
  872. DBG_INFO((DBGARG, TEXT("Send John 1 %8x"), pRecover));
  873. WriteCommString(pRecover, sizeof(DPHDR));
  874. PurgeComm(g_hCommFile, PURGE_RXCLEAR);
  875. rState = READ_RECOVER_K;
  876. dwCount = 1;
  877. dwReadCountExpected = dwCount;
  878. ResetEvent(g_hReadEvent);
  879. ReadFile(g_hCommFile, &msg_Building.dpHdr, dwCount, &dwCount, &overlappedRead);
  880. }
  881. else
  882. {
  883. PostHangupCall();
  884. return(0);
  885. }
  886. }
  887. }
  888. break;
  889. case WAIT_OBJECT_3: // Write Buffer 1 completion.
  890. {
  891. // TSHELL_INFO(TEXT("Write Buffer1 received."));
  892. if (writewait[0].bValid == TRUE)
  893. {
  894. GetOverlappedResult(g_hCommFile, &overlappedWrite0, &dwCount, FALSE);
  895. if (writewait[0].dwSize == dwCount)
  896. {
  897. //
  898. // Success.
  899. //
  900. writewait[0].bValid = FALSE;
  901. DBG_INFO((DBGARG, TEXT("Free 0 %8x"), writewait[0].lpv));
  902. LocalFree((HLOCAL) writewait[0].lpv);
  903. if (wState == TWO_PENDING)
  904. {
  905. wState = ONE_PENDING;
  906. }
  907. else if (wState == ONE_PENDING)
  908. {
  909. wState = ZERO_PENDING;
  910. }
  911. //
  912. // state of zero pending would be a fatal error. BUGBUG;
  913. //
  914. }
  915. else
  916. {
  917. writewait[0].bValid = FALSE;
  918. writewait[0].bValid = FALSE;
  919. DBG_INFO((DBGARG, TEXT("Free Err 0 %8x"), writewait[0].lpv));
  920. LocalFree((HLOCAL) writewait[0].lpv);
  921. if (wState == TWO_PENDING)
  922. {
  923. wState = ONE_PENDING;
  924. }
  925. else if (wState == ONE_PENDING)
  926. {
  927. wState = ZERO_PENDING;
  928. }
  929. DBG_INFO((DBGARG, TEXT("Write Error Tried %d Wrote %d"),
  930. writewait[0].dwSize, dwCount));
  931. }
  932. }
  933. //
  934. // if bValid not TRUE error. BUGBUG.
  935. //
  936. ResetEvent(g_hWriteEvent0);
  937. }
  938. break;
  939. case WAIT_OBJECT_4: // Write Buffer 2 completion.
  940. {
  941. // TSHELL_INFO(TEXT("Write Buffer2 received."));
  942. if (writewait[1].bValid == TRUE)
  943. {
  944. GetOverlappedResult(g_hCommFile, &overlappedWrite1, &dwCount, FALSE);
  945. if (writewait[1].dwSize == dwCount)
  946. {
  947. //
  948. // Success.
  949. //
  950. writewait[1].bValid = FALSE;
  951. DBG_INFO((DBGARG, TEXT("Free 1 %8x"), writewait[1].lpv));
  952. LocalFree((HLOCAL) writewait[1].lpv);
  953. if (wState == TWO_PENDING)
  954. {
  955. wState = ONE_PENDING;
  956. }
  957. else if (wState == ONE_PENDING)
  958. {
  959. wState = ZERO_PENDING;
  960. }
  961. //
  962. // state of zero pending would be a fatal error. BUGBUG;
  963. //
  964. }
  965. else
  966. {
  967. writewait[1].bValid = FALSE;
  968. DBG_INFO((DBGARG, TEXT("Free Err 1 %8x"), writewait[1].lpv));
  969. LocalFree((HLOCAL) writewait[1].lpv);
  970. if (wState == TWO_PENDING)
  971. {
  972. wState = ONE_PENDING;
  973. }
  974. else if (wState == ONE_PENDING)
  975. {
  976. wState = ZERO_PENDING;
  977. }
  978. DBG_INFO((DBGARG, TEXT("Write Error Tried %d Wrote %d"),
  979. writewait[0].dwSize, dwCount));
  980. }
  981. }
  982. //
  983. // if bValid not TRUE error. BUGBUG.
  984. //
  985. ResetEvent(g_hWriteEvent1);
  986. }
  987. break;
  988. case WAIT_OBJECT_5: // More Write Requests.
  989. //
  990. // It turns out that out MsgWait function won't return
  991. // if we have a current message in the loop, only if
  992. // we get a new one.
  993. //
  994. // That has to be wrong, since we have a window
  995. // of opportunity after we do our peek's manually and
  996. // before we do a MsgWait().
  997. //
  998. break;
  999. }
  1000. //
  1001. // Remember that loop conditional doesn't execute PeekMessage()
  1002. // if the state is already TWO_PENDING. Don't change it or
  1003. // you'll lose a message.
  1004. //
  1005. while (wState != TWO_PENDING && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
  1006. {
  1007. if (msg.hwnd != NULL || msg.message != PWM_COMMWRITE)
  1008. {
  1009. TranslateMessage(&msg);
  1010. DispatchMessage(&msg);
  1011. }
  1012. else
  1013. {
  1014. if (g_IDP)
  1015. InterlockedDecrement((LPLONG) &g_IDP->m_dwPendingWrites);
  1016. DBG_INFO((DBGARG, TEXT("Write Hdr to(%d) from(%d) count (%d) cookie(%d): %8x %d"),
  1017. ((DPHDR *)msg.lParam)->to,
  1018. ((DPHDR *)msg.lParam)->from,
  1019. ((DPHDR *)msg.lParam)->usCount,
  1020. ((DPHDR *)msg.lParam)->usCookie,
  1021. ((DPHDR *)msg.lParam)->dwConnect1,
  1022. rState));
  1023. if (writewait[0].bValid == FALSE)
  1024. {
  1025. writewait[0].bValid = TRUE;
  1026. writewait[0].lpv = (LPVOID) msg.lParam;
  1027. DBG_INFO((DBGARG, TEXT("Set 0 %8x"), writewait[0].lpv));
  1028. writewait[0].dwSize = (DWORD)msg.wParam;
  1029. WriteFile( g_hCommFile, (LPVOID) msg.lParam, (DWORD)msg.wParam,
  1030. &dwCount, &overlappedWrite0);
  1031. }
  1032. else
  1033. {
  1034. writewait[1].bValid = TRUE;
  1035. writewait[1].lpv = (LPVOID) msg.lParam;
  1036. DBG_INFO((DBGARG, TEXT("Set 1 %8x"), writewait[1].lpv));
  1037. writewait[1].dwSize = (DWORD)msg.wParam;
  1038. WriteFile( g_hCommFile, (LPVOID) msg.lParam, (DWORD)msg.wParam,
  1039. &dwCount, &overlappedWrite1);
  1040. }
  1041. }
  1042. if (wState == ZERO_PENDING)
  1043. {
  1044. wState = ONE_PENDING;
  1045. }
  1046. else if (wState == ONE_PENDING)
  1047. {
  1048. wState = TWO_PENDING;
  1049. }
  1050. //
  1051. // BUGBUG state two_pending is illegal.
  1052. //
  1053. }
  1054. }
  1055. return 0;
  1056. }
  1057. // FUNCTION: SetupCommEvent(LPOVERLAPPED, LPDWORD)
  1058. //
  1059. // PURPOSE: Sets up the overlapped WaitCommEvent call.
  1060. //
  1061. // PARAMETERS:
  1062. // lpOverlappedCommEvent - Pointer to the overlapped structure to use.
  1063. // lpfdwEvtMask - Pointer to DWORD to received Event data.
  1064. //
  1065. // RETURN VALUE:
  1066. // TRUE if able to successfully setup the WaitCommEvent.
  1067. // FALSE if unable to setup WaitCommEvent, unable to handle
  1068. // an existing outstanding event or if the CloseEvent has been signaled.
  1069. //
  1070. // COMMENTS:
  1071. //
  1072. // This function is a helper function for the Read Thread that sets up
  1073. // the WaitCommEvent so we can deal with comm events (like Comm errors)
  1074. // if they occur.
  1075. //
  1076. //
  1077. BOOL SetupCommEvent(LPOVERLAPPED lpOverlappedCommEvent,
  1078. LPDWORD lpfdwEvtMask)
  1079. {
  1080. DWORD dwLastError;
  1081. StartSetupCommEvent:
  1082. // Make sure the CloseEvent hasn't been signaled yet.
  1083. // Check is needed because this function is potentially recursive.
  1084. if (WAIT_TIMEOUT != WaitForSingleObject(g_hCloseEvent,0))
  1085. return FALSE;
  1086. // Start waiting for Comm Errors.
  1087. if (WaitCommEvent(g_hCommFile, lpfdwEvtMask, lpOverlappedCommEvent))
  1088. {
  1089. // This could happen if there was an error waiting on the
  1090. // comm port. Lets try and handle it.
  1091. TSHELL_INFO(TEXT("Event (Error) waiting before WaitCommEvent."));
  1092. if (!HandleCommEvent(NULL, lpfdwEvtMask, FALSE))
  1093. return FALSE;
  1094. // What could cause infinite recursion at this point?
  1095. goto StartSetupCommEvent;
  1096. }
  1097. // We expect ERROR_IO_PENDING returned from WaitCommEvent
  1098. // because we are waiting with an overlapped structure.
  1099. dwLastError = GetLastError();
  1100. // LastError was ERROR_IO_PENDING, as expected.
  1101. if (dwLastError == ERROR_IO_PENDING)
  1102. {
  1103. TSHELL_INFO(TEXT("Waiting for a CommEvent (Error) to occur."));
  1104. return TRUE;
  1105. }
  1106. // Its possible for this error to occur if the
  1107. // service provider has closed the port. Time to end.
  1108. if (dwLastError == ERROR_INVALID_HANDLE)
  1109. {
  1110. TSHELL_INFO(TEXT("ERROR_INVALID_HANDLE, Likely that the Service Provider has closed the port."));
  1111. return FALSE;
  1112. }
  1113. // Unexpected error. No idea what could cause this to happen.
  1114. TSHELL_INFO(TEXT("Unexpected WaitCommEvent error: "));
  1115. return FALSE;
  1116. }
  1117. //
  1118. // FUNCTION: HandleCommEvent(LPOVERLAPPED, LPDWORD, BOOL)
  1119. //
  1120. // PURPOSE: Handle an outstanding Comm Event.
  1121. //
  1122. // PARAMETERS:
  1123. // lpOverlappedCommEvent - Pointer to the overlapped structure to use.
  1124. // lpfdwEvtMask - Pointer to DWORD to received Event data.
  1125. // fRetrieveEvent - Flag to signal if the event needs to be
  1126. // retrieved, or has already been retrieved.
  1127. //
  1128. // RETURN VALUE:
  1129. // TRUE if able to handle a Comm Event.
  1130. // FALSE if unable to setup WaitCommEvent, unable to handle
  1131. // an existing outstanding event or if the CloseEvent has been signaled.
  1132. //
  1133. // COMMENTS:
  1134. //
  1135. // This function is a helper function for the Read Thread that (if
  1136. // fRetrieveEvent == TRUE) retrieves an outstanding CommEvent and
  1137. // deals with it. The only event that should occur is an EV_ERR event,
  1138. // signalling that there has been an error on the comm port.
  1139. //
  1140. // Normally, comm errors would not be put into the normal data stream
  1141. // as this sample is demonstrating. Putting it in a status bar would
  1142. // be more appropriate for a real application.
  1143. //
  1144. //
  1145. BOOL HandleCommEvent(LPOVERLAPPED lpOverlappedCommEvent,
  1146. LPDWORD lpfdwEvtMask, BOOL fRetrieveEvent)
  1147. {
  1148. DWORD dwDummy;
  1149. LPSTR lpszOutput;
  1150. char szError[128] = "";
  1151. DWORD dwErrors;
  1152. DWORD dwLastError;
  1153. lpszOutput = (char *) LocalAlloc(LPTR,256);
  1154. if (lpszOutput == NULL)
  1155. {
  1156. DBG_INFO((DBGARG, TEXT("LocalAlloc: %d"), GetLastError()));
  1157. return FALSE;
  1158. }
  1159. // If this fails, it could be because the file was closed (and I/O is
  1160. // finished) or because the overlapped I/O is still in progress. In
  1161. // either case (or any others) its a bug and return FALSE.
  1162. if (fRetrieveEvent)
  1163. if (!GetOverlappedResult(g_hCommFile,
  1164. lpOverlappedCommEvent, &dwDummy, FALSE))
  1165. {
  1166. dwLastError = GetLastError();
  1167. // Its possible for this error to occur if the
  1168. // service provider has closed the port. Time to end.
  1169. if (dwLastError == ERROR_INVALID_HANDLE)
  1170. {
  1171. TSHELL_INFO(TEXT("ERROR_INVALID_HANDLE, Likely that the Service Provider has closed the port."));
  1172. return FALSE;
  1173. }
  1174. DBG_INFO((DBGARG, TEXT("Unexpected GetOverlappedResult for WaitCommEvent: %x"),
  1175. dwLastError));
  1176. return FALSE;
  1177. }
  1178. // Was the event an error?
  1179. if (*lpfdwEvtMask & EV_ERR)
  1180. {
  1181. // Which error was it?
  1182. if (!ClearCommError(g_hCommFile, &dwErrors, NULL))
  1183. {
  1184. dwLastError = GetLastError();
  1185. // Its possible for this error to occur if the
  1186. // service provider has closed the port. Time to end.
  1187. if (dwLastError == ERROR_INVALID_HANDLE)
  1188. {
  1189. TSHELL_INFO(TEXT("ERROR_INVALID_HANDLE, Likely that the Service Provider has closed the port."));
  1190. return FALSE;
  1191. }
  1192. DBG_INFO((DBGARG, TEXT("ClearCommError: %x"), GetLastError()));
  1193. return FALSE;
  1194. }
  1195. // Its possible that multiple errors occured and were handled
  1196. // in the last ClearCommError. Because all errors were signaled
  1197. // individually, but cleared all at once, pending comm events
  1198. // can yield EV_ERR while dwErrors equals 0. Ignore this event.
  1199. if (dwErrors == 0)
  1200. {
  1201. lstrcat(szError, TEXT("NULL Error"));
  1202. }
  1203. if (dwErrors & CE_FRAME)
  1204. {
  1205. if (szError[0])
  1206. lstrcat(szError,TEXT(" and "));
  1207. lstrcat(szError,TEXT("CE_FRAME"));
  1208. }
  1209. if (dwErrors & CE_OVERRUN)
  1210. {
  1211. if (szError[0])
  1212. lstrcat(szError,TEXT(" and "));
  1213. lstrcat(szError,TEXT("CE_OVERRUN"));
  1214. }
  1215. if (dwErrors & CE_RXPARITY)
  1216. {
  1217. if (szError[0])
  1218. lstrcat(szError,TEXT(" and "));
  1219. lstrcat(szError,TEXT("CE_RXPARITY"));
  1220. }
  1221. if (dwErrors & ~ (CE_FRAME | CE_OVERRUN | CE_RXPARITY))
  1222. {
  1223. if (szError[0])
  1224. lstrcat(szError,TEXT(" and "));
  1225. lstrcat(szError,TEXT("EV_ERR Unknown EvtMask"));
  1226. }
  1227. DBG_INFO((DBGARG, TEXT("Comm Event: '%s', EvtMask = '%lx' %s %d"),
  1228. szError, dwErrors));
  1229. return TRUE;
  1230. }
  1231. // Should not have gotten here. Only interested in ERR conditions.
  1232. DBG_INFO((DBGARG, TEXT("Unexpected comm event %lx"),*lpfdwEvtMask));
  1233. return FALSE;
  1234. }
  1235.