static BOOL WaitComReady(HANDLE hC0C, BOOL ignoreDSR, const BYTE *pAwakSeq) { BOOL waitAwakSeq = (pAwakSeq && *pAwakSeq); BOOL waitDSR = (!ignoreDSR && !waitAwakSeq); if (!waitAwakSeq && !waitDSR) return TRUE; enum { EVENT_READ, EVENT_STAT, EVENT_NUM }; HANDLE hEvents[EVENT_NUM]; OVERLAPPED overlaps[EVENT_NUM]; if (!PrepareEvents(EVENT_NUM, hEvents, overlaps)) return FALSE; BOOL fault = FALSE; if (!SetCommMask(hC0C, EV_DSR)) { TraceLastError("WaitComReady(): SetCommMask()"); fault = TRUE; } DWORD not_used; const BYTE *pAwakSeqNext = pAwakSeq; BYTE cbufRead[1]; BOOL waitingRead = !waitAwakSeq; BOOL waitingStat = !waitDSR; while (!fault) { if (!waitingRead) { if (!pAwakSeqNext || !*pAwakSeqNext) break; if (!ReadFile(hC0C, cbufRead, sizeof(cbufRead), ¬_used, &overlaps[EVENT_READ])) { if (::GetLastError() != ERROR_IO_PENDING) { TraceLastError("WaitComReady(): ReadFile()"); break; } } waitingRead = TRUE; } if (!waitingStat) { if (!WaitCommEvent(hC0C, ¬_used, &overlaps[EVENT_STAT])) { if (::GetLastError() != ERROR_IO_PENDING) { TraceLastError("WaitComReady(): WaitCommEvent()"); fault = TRUE; break; } } waitingStat = TRUE; DWORD stat; if (!GetCommModemStatus(hC0C, &stat)) { TraceLastError("WaitComReady(): GetCommModemStatus()"); fault = TRUE; break; } if (stat & MS_DSR_ON) { printf("DSR is ON\n"); Sleep(1000); if (!GetCommModemStatus(hC0C, &stat)) { TraceLastError("WaitComReady(): GetCommModemStatus()"); fault = TRUE; break; } if (stat & MS_DSR_ON) break; // OK if DSR is still ON printf("DSR is OFF\n"); } } if (waitingRead && waitingStat) { DWORD done; switch (WaitForMultipleObjects(EVENT_NUM, hEvents, FALSE, 5000)) { case WAIT_OBJECT_0 + EVENT_READ: if (!GetOverlappedResult(hC0C, &overlaps[EVENT_READ], &done, FALSE)) { TraceLastError("WaitComReady(): GetOverlappedResult(EVENT_READ)"); fault = TRUE; } ResetEvent(hEvents[EVENT_READ]); if (done && pAwakSeqNext) { if (*pAwakSeqNext == *cbufRead) { pAwakSeqNext++; } else { pAwakSeqNext = pAwakSeq; if (*pAwakSeqNext == *cbufRead) pAwakSeqNext++; } printf("Skipped character 0x%02.2X\n", (int)*cbufRead); } waitingRead = FALSE; break; case WAIT_OBJECT_0 + EVENT_STAT: if (!GetOverlappedResult(hC0C, &overlaps[EVENT_STAT], ¬_used, FALSE)) { TraceLastError("WaitComReady(): GetOverlappedResult(EVENT_STAT)"); fault = TRUE; } waitingStat = FALSE; break; case WAIT_TIMEOUT: break; default: TraceLastError("WaitComReady(): WaitForMultipleObjects()"); fault = TRUE; } } } CancelIo(hC0C); CloseEvents(EVENT_NUM, hEvents); printf("WaitComReady() - %s\n", fault ? "FAIL" : "OK"); return !fault; }
static BOOL PrepareEvents(int num, HANDLE *hEvents, OVERLAPPED *overlaps) { memset(hEvents, 0, num * sizeof(HANDLE)); memset(overlaps, 0, num * sizeof(OVERLAPPED)); for (int i = 0 ; i < num ; i++) { overlaps[i].hEvent = hEvents[i] = ::CreateEvent(NULL, TRUE, FALSE, NULL); if (!hEvents[i]) { TraceLastError("PrepareEvents(): CreateEvent()"); CloseEvents(i, hEvents); return FALSE; } } return TRUE; }
int main( void ) { DWORD dwWaitResult; // TODO: Create the shared buffer // Create events and THREADCOUNT threads to read from the buffer CreateEventsAndThreads(); // At this point, the reader threads have started and are most // likely waiting for the global event to be signaled. However, // it is safe to write to the buffer because the event is a // manual-reset event. WriteToBuffer(); printf("Main thread waiting for threads to exit...\n"); // The handle for each thread is signaled when the thread is // terminated. dwWaitResult = WaitForMultipleObjects( THREADCOUNT, // number of handles in array ghThreads, // array of thread handles TRUE, // wait until all are signaled INFINITE); switch (dwWaitResult) { // All thread objects were signaled case WAIT_OBJECT_0: printf("All threads ended, cleaning up for application exit...\n"); break; // An error occurred default: printf("WaitForMultipleObjects failed (%d)\n", GetLastError()); return 1; } // Close the events to clean up CloseEvents(); return 0; }
static void InOut( HANDLE hC0C, SOCKET hSock, Protocol &protocol, BOOL ignoreDSR, SOCKET hSockListen = INVALID_SOCKET) { printf("InOut() START\n"); protocol.Clean(); BOOL stop = FALSE; enum { EVENT_READ, EVENT_SENT, EVENT_RECEIVED, EVENT_WRITTEN, EVENT_STAT, EVENT_CLOSE, EVENT_ACCEPT, EVENT_NUM }; HANDLE hEvents[EVENT_NUM]; OVERLAPPED overlaps[EVENT_NUM]; if (!PrepareEvents(EVENT_NUM, hEvents, overlaps)) stop = TRUE; if (!SetCommMask(hC0C, EV_DSR)) { TraceLastError("InOut(): SetCommMask()"); stop = TRUE; } WSAEventSelect(hSock, hEvents[EVENT_CLOSE], FD_CLOSE); if (hSockListen != INVALID_SOCKET) WSAEventSelect(hSockListen, hEvents[EVENT_ACCEPT], FD_ACCEPT); DWORD not_used; BYTE cbufRead[64]; BOOL waitingRead = FALSE; BYTE cbufSend[64]; int cbufSendSize = 0; int cbufSendDone = 0; BOOL waitingSend = FALSE; BYTE cbufRecv[64]; BOOL waitingRecv = FALSE; BYTE cbufWrite[64]; int cbufWriteSize = 0; int cbufWriteDone = 0; BOOL waitingWrite = FALSE; BOOL waitingStat = FALSE; int DSR = -1; while (!stop) { if (!waitingSend) { if (!cbufSendSize) { cbufSendSize = protocol.Read(cbufSend, sizeof(cbufSend)); if (cbufSendSize < 0) break; } DWORD num = cbufSendSize - cbufSendDone; if (num) { if (!WriteFile((HANDLE)hSock, cbufSend + cbufSendDone, num, ¬_used, &overlaps[EVENT_SENT])) { if (::GetLastError() != ERROR_IO_PENDING) { TraceLastError("InOut(): WriteFile(hSock)"); break; } } waitingSend = TRUE; } } if (!waitingRead && !protocol.isSendFull()) { if (!ReadFile(hC0C, cbufRead, sizeof(cbufRead), ¬_used, &overlaps[EVENT_READ])) { if (::GetLastError() != ERROR_IO_PENDING) { TraceLastError("InOut(): ReadFile(hC0C)"); break; } } waitingRead = TRUE; } if (!waitingWrite) { if (!cbufWriteSize) { cbufWriteSize = protocol.Recv(cbufWrite, sizeof(cbufWrite)); if (cbufWriteSize < 0) break; } DWORD num = cbufWriteSize - cbufWriteDone; if (num) { if (!WriteFile(hC0C, cbufWrite + cbufWriteDone, num, ¬_used, &overlaps[EVENT_WRITTEN])) { if (::GetLastError() != ERROR_IO_PENDING) { TraceLastError("InOut(): WriteFile(hC0C)"); break; } } waitingWrite = TRUE; } } if (!waitingRecv && !protocol.isWriteFull()) { if (!ReadFile((HANDLE)hSock, cbufRecv, sizeof(cbufRecv), ¬_used, &overlaps[EVENT_RECEIVED])) { if (::GetLastError() != ERROR_IO_PENDING) { TraceLastError("InOut(): ReadFile(hSock)"); break; } } waitingRecv = TRUE; } if (!waitingStat) { if (!WaitCommEvent(hC0C, ¬_used, &overlaps[EVENT_STAT])) { if (::GetLastError() != ERROR_IO_PENDING) { TraceLastError("InOut(): WaitCommEvent()"); break; } } waitingStat = TRUE; DWORD stat; if (!GetCommModemStatus(hC0C, &stat)) { TraceLastError("InOut(): GetCommModemStatus()"); break; } if (!(stat & MS_DSR_ON)) { if (DSR != 0) { printf("DSR is OFF\n"); DSR = 0; } if (!ignoreDSR) { if (waitingSend) Sleep(1000); break; } } else { if (DSR != 1) { printf("DSR is ON\n"); DSR = 1; } } } if ((waitingRead || waitingSend) && (waitingRecv || waitingWrite) && waitingStat) { DWORD done; switch (WaitForMultipleObjects(EVENT_NUM, hEvents, FALSE, 5000)) { case WAIT_OBJECT_0 + EVENT_READ: if (!GetOverlappedResult(hC0C, &overlaps[EVENT_READ], &done, FALSE)) { if (::GetLastError() != ERROR_OPERATION_ABORTED) { TraceLastError("InOut(): GetOverlappedResult(EVENT_READ)"); stop = TRUE; break; } } ResetEvent(hEvents[EVENT_READ]); waitingRead = FALSE; protocol.Send(cbufRead, done); break; case WAIT_OBJECT_0 + EVENT_SENT: if (!GetOverlappedResult((HANDLE)hSock, &overlaps[EVENT_SENT], &done, FALSE)) { if (::GetLastError() != ERROR_OPERATION_ABORTED) { TraceLastError("InOut(): GetOverlappedResult(EVENT_SENT)"); stop = TRUE; break; } done = 0; } ResetEvent(hEvents[EVENT_SENT]); cbufSendDone += done; if (cbufSendDone >= cbufSendSize) cbufSendDone = cbufSendSize = 0; waitingSend = FALSE; break; case WAIT_OBJECT_0 + EVENT_RECEIVED: if (!GetOverlappedResult((HANDLE)hSock, &overlaps[EVENT_RECEIVED], &done, FALSE)) { if (::GetLastError() != ERROR_OPERATION_ABORTED) { TraceLastError("InOut(): GetOverlappedResult(EVENT_RECEIVED)"); stop = TRUE; break; } done = 0; } else if (!done) { ResetEvent(hEvents[EVENT_RECEIVED]); printf("Received EOF\n"); break; } ResetEvent(hEvents[EVENT_RECEIVED]); waitingRecv = FALSE; protocol.Write(cbufRecv, done); break; case WAIT_OBJECT_0 + EVENT_WRITTEN: if (!GetOverlappedResult(hC0C, &overlaps[EVENT_WRITTEN], &done, FALSE)) { if (::GetLastError() != ERROR_OPERATION_ABORTED) { TraceLastError("InOut(): GetOverlappedResult(EVENT_WRITTEN)"); stop = TRUE; break; } done = 0; } ResetEvent(hEvents[EVENT_WRITTEN]); cbufWriteDone += done; if (cbufWriteDone >= cbufWriteSize) cbufWriteDone = cbufWriteSize = 0; waitingWrite = FALSE; break; case WAIT_OBJECT_0 + EVENT_STAT: if (!GetOverlappedResult(hC0C, &overlaps[EVENT_STAT], &done, FALSE)) { if (::GetLastError() != ERROR_OPERATION_ABORTED) { TraceLastError("InOut(): GetOverlappedResult(EVENT_STAT)"); stop = TRUE; break; } } waitingStat = FALSE; break; case WAIT_OBJECT_0 + EVENT_CLOSE: ResetEvent(hEvents[EVENT_CLOSE]); printf("EVENT_CLOSE\n"); if (waitingWrite) Sleep(1000); stop = TRUE; break; case WAIT_OBJECT_0 + EVENT_ACCEPT: { ResetEvent(hEvents[EVENT_ACCEPT]); printf("EVENT_ACCEPT\n"); SOCKET hSockTmp = Accept(hSockListen); if (hSockTmp != INVALID_SOCKET) { char msg[] = "*** Serial port is busy ***\n"; send(hSockTmp, msg, strlen(msg), 0); Disconnect(hSockTmp); } break; } case WAIT_TIMEOUT: break; default: TraceLastError("InOut(): WaitForMultipleObjects()"); stop = TRUE; } } } CancelIo(hC0C); CancelIo((HANDLE)hSock); if (hSockListen != INVALID_SOCKET) { WSAEventSelect(hSockListen, hEvents[EVENT_ACCEPT], 0); u_long blocking = 0; ioctlsocket(hSockListen, FIONBIO, &blocking); } CloseEvents(EVENT_NUM, hEvents); printf("InOut() - STOP\n"); }