/*------------------------------------------------------------------------------ -- FUNCTION: PortIOThreadProc -- -- DATE: Oct 13, 2010 -- -- REVISIONS: Nov 05, 2010 -- Modified the function to also listen for a "disconnect" event, -- and to break in that case. ProcessRead() is now called once a -- complete packet is confirmed (as opposed to sending the -- contents of the buffer to ProcessRead() as soon as they arrive). -- -- Nov 29, 2010 -- Renamed function from ReadThreadProc(). The event handling is -- from the original function, but the response to each event has -- changed. -- -- DESIGNER: Dean Morin -- -- PROGRAMMER: Dean Morin, Daniel Wright -- -- INTERFACE: DWORD WINAPI PortIOThreadProc(HWND hWnd) -- hWnd - the handle to the window -- -- RETURNS: 0 because threads are required to return a DWORD. -- -- NOTES: -- While connected, this thread will loop and wait for characters -- to arrive at the port, or for a timeout to occur, then call the -- appropriate function. This function uses overlapped I/O. ------------------------------------------------------------------------------*/ DWORD WINAPI PortIOThreadProc(HWND hWnd) { OVERLAPPED ol = {0}; DWORD dwEvent = 0; DWORD dwError = 0; COMSTAT cs = {0}; HANDLE* hEvents = NULL; PSTATEINFO psi = NULL; PWNDDATA pwd = (PWNDDATA) GetWindowLongPtr(hWnd, 0); if ((ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { DISPLAY_ERROR("Error creating event in read thread"); } hEvents = (HANDLE*) malloc(sizeof(HANDLE) * PORT_IO_EVENTS); hEvents[0] = CreateEvent(NULL, FALSE, FALSE, TEXT("disconnected")); hEvents[1] = ol.hEvent; psi = (PSTATEINFO) malloc(sizeof(STATEINFO)); InitStateInfo(psi); DL_STATE = psi->iState; while (pwd->bConnected) { SetCommMask(pwd->hPort, EV_RXCHAR); if (!WaitCommEvent(pwd->hPort, &dwEvent, &ol)) { ProcessCommError(pwd->hPort); } dwEvent = WaitForMultipleObjects(PORT_IO_EVENTS, hEvents, FALSE, psi->dwTimeout); ClearCommError(pwd->hPort, &dwError, &cs); if (dwEvent == WAIT_OBJECT_0) { // the connection was severed break; } else if (dwEvent == WAIT_OBJECT_0 + 1 && cs.cbInQue) { // data arrived at the port ReadFromPort(hWnd, psi, ol, cs.cbInQue); } else if (dwEvent == WAIT_TIMEOUT) { // a timeout occured ProcessTimeout(hWnd, psi); } else if (dwEvent == WAIT_FAILED) { DISPLAY_ERROR("Invalid event occured in the Port I/O thread"); } ResetEvent(ol.hEvent); } if (!PurgeComm(pwd->hPort, PURGE_RXCLEAR)) { DISPLAY_ERROR("Error purging read buffer"); } CloseHandle(ol.hEvent); CloseHandle(hEvents[0]); free(hEvents); return 0; }
status_t LinkReceiver::GetNextMessage(int32 &code, bigtime_t timeout) { fReadError = B_OK; int32 remaining = fDataSize - (fRecvStart + fReplySize); STRACE(("info: LinkReceiver GetNextReply() reports %ld bytes remaining in buffer.\n", remaining)); // find the position of the next message header in the buffer message_header *header; if (remaining <= 0) { status_t err = ReadFromPort(timeout); if (err < B_OK) return err; remaining = fDataSize; header = (message_header *)fRecvBuffer; } else { fRecvStart += fReplySize; // start of the next message fRecvPosition = fRecvStart; header = (message_header *)(fRecvBuffer + fRecvStart); } // check we have a well-formed message if (remaining < (int32)sizeof(message_header)) { // we don't have enough data for a complete header STRACE(("error info: LinkReceiver remaining %ld bytes is less than header size.\n", remaining)); ResetBuffer(); return B_ERROR; } fReplySize = header->size; if (fReplySize > remaining || fReplySize < (int32)sizeof(message_header)) { STRACE(("error info: LinkReceiver message size of %ld bytes smaller than header size.\n", fReplySize)); ResetBuffer(); return B_ERROR; } code = header->code; fRecvPosition += sizeof(message_header); STRACE(("info: LinkReceiver got header %ld [%ld %ld %ld] from port %ld.\n", header->code, fReplySize, header->code, header->flags, fReceivePort)); return B_OK; }