wxThread::ExitCode ReceiveFromDevice::Entry() { bool error = false;//Indicates last state while(!TestDestroy()) { DWORD read = 0; UCHAR buff[256]= {0}; if(device->WinUSBHandle == INVALID_HANDLE_VALUE || !device->GetState()) { Reset(); if(error) Sleep(errSleep); error = true; continue; } OVERLAPPED overlapped; ZeroMemory(&overlapped, sizeof(overlapped)); overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);//(NULL, TRUE, FALSE, NULL); if(!WinUsb_ReadPipe(device->WinUSBHandle, IN_EP, data + received, IN_EP_PACKET, &read, &overlapped)) { if(GetLastError() != ERROR_IO_PENDING) { Reset(); if(error) Sleep(errSleep); error = true; continue; } } while(WaitForSingleObject(overlapped.hEvent, 100) == WAIT_TIMEOUT) { if(TestDestroy())//Check whether the thread should be destroyed { CloseHandle(overlapped.hEvent); return 0; } } //Complete transfer - get received bytes WinUsb_GetOverlappedResult(device->WinUSBHandle, &overlapped, &read, FALSE); CloseHandle(overlapped.hEvent);//Clear event //Process data if(read == 0) { //Error occur, reset state Reset(); if(error) Sleep(errSleep); error = true; continue; } error = false; //Increase counters received += read; receivedPackets++; //Check if we read entire message if(data[0] == receivedPackets) { ProcessMessage(); Reset(); } } return 0; }
bool AdbWinUsbIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data, ULONG* bytes_transferred, bool wait) { if (NULL != bytes_transferred) { *bytes_transferred = 0; } if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false; } ULONG transfer; bool ret = WinUsb_GetOverlappedResult( parent_winusb_io_object()->winusb_handle(), overlapped(), &transfer, wait ? TRUE : FALSE) ? true : false; // TODO: This is bizzare but I've seen it happening // that GetOverlappedResult with wait set to true returns "prematurely", // with wrong transferred bytes value and GetLastError reporting // ERROR_IO_PENDING. So, lets give it an up to a 20 ms loop! ULONG error = GetLastError(); if (wait && ret && (0 == transfer) && (0 != expected_transfer_size_) && ((ERROR_IO_INCOMPLETE == error) || (ERROR_IO_PENDING == error))) { for (int trying = 0; trying < 10; trying++) { Sleep(2); ret = WinUsb_GetOverlappedResult( parent_winusb_io_object()->winusb_handle(), overlapped(), &transfer, wait ? TRUE : FALSE) ? true : false; error = GetLastError(); if (!ret || (0 != transfer) || ((ERROR_IO_INCOMPLETE != error) && (ERROR_IO_PENDING != error))) { break; } } } if (NULL != ovl_data) { CopyMemory(ovl_data, overlapped(), sizeof(OVERLAPPED)); } if (NULL != bytes_transferred) { *bytes_transferred = transfer; } return ret; }
void UsbInterfacePrivate::threadFunc() { HANDLE handles[1+m_oCount]; handles[0] = m_quitEvent; handles[m_oCount] = m_waitEvents[m_oCount-1]; //= { m_quitEvent, m_waitEvents[0], m_waitEvents[1] }; // start first read operation for (m_readIdx = 0 ; m_readIdx < (m_oCount-1); ++m_readIdx) { handles[m_readIdx+1] = m_waitEvents[m_readIdx]; //m_readIdx = 0; m_overlapped[m_readIdx] = OVERLAPPED(); ::ResetEvent(m_waitEvents[m_readIdx]); //lint !e534 m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx]; WinUsb_ReadPipe(m_usbHandle[1], m_bulkInPipe, m_fixedBuffer[m_readIdx], (ULONG)m_fixedBufferSize, 0, &m_overlapped[m_readIdx]); //lint !e534 } int fastCount = 0; //m_readIdx = 1; bool policyFast = false; bool run = true; while (run) { // start follow-up read operation m_overlapped[m_readIdx] = OVERLAPPED(); ::ResetEvent(m_waitEvents[m_readIdx]); //lint !e534 m_overlapped[m_readIdx].hEvent = m_waitEvents[m_readIdx]; WinUsb_ReadPipe(m_usbHandle[1], m_bulkInPipe, m_fixedBuffer[m_readIdx], (ULONG)m_fixedBufferSize, 0, &m_overlapped[m_readIdx]); //lint !e534 m_readIdx = (m_readIdx + 1) % m_oCount; int64_t tBegin = XsTime_timeStampNow(0); DWORD waitResult = ::WaitForMultipleObjects(1+m_oCount, handles, FALSE, INFINITE); #if 1 // not sure if this causes problems, but it should help in catching up int64_t tEnd = XsTime_timeStampNow(0); switch (tEnd - tBegin) { case 0: if (++fastCount > 3 && !policyFast) { policyFast = true; // set fast policy UCHAR enable = TRUE; WinUsb_SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS, sizeof(UCHAR), &enable); //lint !e534 } break; case 1: if (fastCount) --fastCount; if (policyFast && fastCount <= 3) { // reset policy policyFast = false; UCHAR enable = FALSE; WinUsb_SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS, sizeof(UCHAR), &enable); //lint !e534 } break; default: fastCount = 0; if (policyFast) { // reset policy policyFast = false; UCHAR enable = FALSE; WinUsb_SetPipePolicy(m_usbHandle[1], m_bulkInPipe, IGNORE_SHORT_PACKETS, sizeof(UCHAR), &enable); //lint !e534 } break; } #endif // handle data switch (waitResult) { case WAIT_TIMEOUT: case WAIT_FAILED: case WAIT_OBJECT_0: run = false; break; default: if (waitResult >= WAIT_ABANDONED_0) { JLDEBUG(gJournal, "WFMO abandoned: " << (waitResult - WAIT_OBJECT_0)); break; } #ifndef XSENS_RELEASE JLDEBUG(gJournal, "WFMO trigger: " << (waitResult - WAIT_OBJECT_0)); #endif { // put data into buffer int idx = m_readIdx; DWORD dataRead = 0; if (!WinUsb_GetOverlappedResult(m_usbHandle[0], &m_overlapped[idx], &dataRead, FALSE)) { // error DWORD err = ::GetLastError(); switch (err) { case ERROR_SEM_TIMEOUT: case ERROR_IO_INCOMPLETE: //JLDEBUG(gJournal, "WinUsb_GetOverlappedResult resulted in acceptable windows error " << err); break; default: JLALERT(gJournal, "WinUsb_GetOverlappedResult resulted in windows error " << err); run = false; break; } //assert (err == ERROR_IO_INCOMPLETE); } else { // append unread data to var buffer JLTRACE(gJournal, "WinUsb_GetOverlappedResult resulted in " << dataRead << " bytes being read"); XsByteArray ref(&m_fixedBuffer[idx][0], dataRead, XSDF_None); ::EnterCriticalSection(&m_mutex); m_varBuffer.append(ref); ::LeaveCriticalSection(&m_mutex); } } break; } } }