winusb driver - isochronous endpoint not working

%3CLINGO-SUB%20id%3D%22lingo-sub-3004392%22%20slang%3D%22en-US%22%3Ewinusb%20driver%20-%20isochronous%20endpoint%20not%20working%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-3004392%22%20slang%3D%22en-US%22%3E%3CP%3EHi%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20have%20a%20usb%20device%20that%20working%20with%20our%20WDM%20driver%20written%20about%2015%20years%20ago%20.%3C%2FP%3E%3CP%3EIt%20works%20on%20Windows%20XP%20to%20Windows%2010%2032%20and%2064%20bit.%3C%2FP%3E%3CP%3EDevice%20sends%20analog%20data%20of%202%20bytes%20every%201ms%20to%20PC%20(%20Data%20sample%20rate%20%3D%201000)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI%20tried%20to%20switch%20working%20with%20Microsoft%20winusb%20driver%20in%20Windows%2010.%3C%2FP%3E%3CP%3EDriver%20installed%20OK%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI%20write%20some%20wrapper%20code%20(So%20my%20Application%20will%20work%20as%20is)%20to%20use%20winusb%20driver%20on%3C%2FP%3E%3CP%3Eisochronous%20pipe%20streaming%20and%20get%20very%20strange%20behave%20...%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI%20am%20missing%20packets%20%2C%20on%20All%20empty%20packets%20i%20get%20Status%20of%26nbsp%3BUSBD_STATUS_ISO_NOT_ACCESSED_BY_HW%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EUSBD_STATUS_ISO_NOT_ACCESSED_BY_HW%3C%2FP%3E%3CP%3EExtended%20isochronous%20error%20codes%20returned%20by%20USBD.%3CBR%20%2F%3EThese%20errors%20appear%20in%20the%20packet%20status%20field%20of%20an%20isochronous%20transfer.%20%5B0xC0020000%5D%3CBR%20%2F%3EFor%20some%20reason%20the%20controller%20did%20not%20access%20the%20TD%20associated%20with%20this%20packet%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-applescript%22%3E%3CCODE%3E%2F*%20-----%20%20%20%20%20%20%20IF%20Using%20WinUSB.sys%20driver%20%20%20---------------%20*%2F%0A%23ifdef%20USE_WINUSB_DRIVER%0A%0A%23include%20%3CTCHAR.H%3E%0A%23include%20%3CSTRSAFE.H%3E%0A%23include%20%3CWINUSB.H%3E%0A%23include%20%3CUSB.H%3E%0A%23include%20%3CCSTDLIB%3E%0A%23include%20%3CINITGUID.H%3E%0A%23include%20%3CCFGMGR32.H%3E%0A%23include%20%3CCOMBASEAPI.H%3E%0A%0A%2F%2F%0A%2F%2F%20Device%20Interface%20GUID.%0A%2F%2F%20Used%20by%20all%20WinUsb%20devices%20that%20this%20application%20talks%20to.%0A%2F%2F%20Must%20match%20%22DeviceInterfaceGUIDs%22%20registry%20value%20specified%20in%20the%20INF%20file.%0A%2F%2F%20yyyyyy-yyyy-yyyy-xxxx-yyyyyyyy%0A%2F%2F%0ADEFINE_GUID(GUID_DEVINTERFACE_ECGUSB1%2C%200xyyyyyyyy%2C%200xyyyy%2C%200xyyy%2C%200xxx%2C%200xxx%2C%200xyy%2C%200xyy%2C%200xyy%2C%200xyy%2C%200xyy%2C%200xyy)%3B%0A%0A%0A%0A%23define%20ISOCH_DATA_SIZE_MS%2010%0A%23define%20ISOCH_TRANSFER_COUNT%202%20%20%2F%2Fwill%20need%20to%20be%20at%20least%202%0A%0A%2F*%0A*%20%20My%20device%20sends%20one%20sample%20of%202%20bytes%20every%201ms%20..%20%3D%26gt%3B%20data%20sample%20rate%20%3D%201000s%2Fs%0A*%20%0A*%20%20Problem%20!!%0A*%20%20Only%20Transfer%201%20has%20the%20data%20all%20next%20(ISOCH_TRANSFER_COUNT)%20are%20empty%0A*%20%20As%20a%20result%20i%20see%20data%20arriving%20at%20sample%20rate%20of%201000%20%2F%20ISOCH_TRANSFER_COUNT%20%20in%20Read%20application%0A*%20%0A*%20%20Why%20%3F%3F%3F%3F%3F%0A*%20%0AnvUSB.lib%3A%20Current%20Frame%20number%3D261744397%0AnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%0AnvUSB.lib%3A%20bRead()%20Transfer%201%20completed.%20Read%20100%20bytes.%0AnvUSB.lib%3A%20Current%20Frame%20number%3D261744447%0AnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%0AnvUSB.lib%3A%20bRead()%20Transfer%202%20completed.%20Read%200%20bytes.%20%20%20%20%20%26lt%3B--%20%3F%3F%0AnvUSB.lib%3A%20Current%20Frame%20number%3D261744497%0AnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%0AnvUSB.lib%3A%20bRead()%20Transfer%201%20completed.%20Read%20100%20bytes.%0AnvUSB.lib%3A%20Current%20Frame%20number%3D261744547%0AnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%0AnvUSB.lib%3A%20bRead()%20Transfer%202%20completed.%20Read%200%20bytes.%20%20%20%20%20%26lt%3B---%20%3F%3F%0AnvUSB.lib%3A%20Current%20Frame%20number%3D261744597%0AnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%0AnvUSB.lib%3A%20bRead()%20Transfer%201%20completed.%20Read%20100%20bytes.%0AnvUSB.lib%3A%20Current%20Frame%20number%3D261744647%0AnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%0AnvUSB.lib%3A%20bRead()%20Transfer%202%20completed.%20Read%200%20bytes.%0AnvUSB.lib%3A%20Current%20Frame%20number%3D261744697%0A%0A%0A*%2F%0A%0A%0A%0A%0A%0Atypedef%20struct%20_PCECG_PIPE_INFORMATION_EX%20%7B%0A%20USBD_PIPE_TYPE%20PipeType%3B%0A%20UCHAR%20%20%20%20%20%20%20%20%20%20PipeId%3B%0A%20USHORT%20%20%20%20%20%20%20%20%20MaximumPacketSize%3B%0A%20UCHAR%20%20%20%20%20%20%20%20%20%20Interval%3B%0A%20ULONG%20%20%20%20%20%20%20%20%20%20MaximumBytesPerInterval%3B%0A%20int%20%20%20%20%20%20index%3B%0A%7D%20PCECG_PIPE_INFORMATION_EX%2C%20*%20PPCECG_PIPE_INFORMATION_EX%3B%0A%0A%0Astruct%20PIPE_ID%0A%7B%0A%20%2F%2F%20Note%3A%0A%20%2F%2F%20Each%20USB%20device%20can%20define%20up%20to%2032%20endpoints(16%20inputs%20and%2016%20outputs%20though%20one%20must%20be%20a%20control%20endpoint)%0A%20%2F%2F%20Here%20i%20assume%20that%20we%20will%20use%20maximum%202%20for%20each%20type..%0A%20PCECG_PIPE_INFORMATION_EX%20%20Bulk_Pipe%5B2%5D%3B%20%2F%2F%20%5B0%5D%20-for%20IN%20type%20%3B%20%5B1%5D%20-for%20OUT%20type%20%0A%20PCECG_PIPE_INFORMATION_EX%20%20Int_Pipe%5B2%5D%3B%0A%20PCECG_PIPE_INFORMATION_EX%20%20Iso_Pipe%5B2%5D%3B%0A%7D%3B%0A%0A%0Atypedef%20struct%20_RING_BUFFER%0A%7B%0A%20PUCHAR%20%20%20%20%20%20buffer%3B%0A%20PUCHAR%20%20%20%20%20%20inPtr%3B%0A%20PUCHAR%20%20%20%20%20%20outPtr%3B%0A%20SIZE_T%20%20%20%20%20%20totalSize%3B%0A%20SIZE_T%20%20%20%20%20%20currentSize%3B%0A%20KSPIN_LOCK%20spinLock%3B%0A%0A%20SIZE_T%20%20%20%20%20%20Size%3B%0A%20PUCHAR%20%20%20%20%20%20Base%3B%0A%20PUCHAR%20%20%20%20%20%20End%3B%0A%20PUCHAR%20%20%20%20%20%20Head%3B%0A%20PUCHAR%20%20%20%20%20%20Tail%3B%0A%0A%7D%20RING_BUFFER%2C%20*%20PRING_BUFFER%3B%0A%0A%0A%0Aclass%20CUsbPCECGHelper%0A%7B%0Apublic%3A%0A%20%2F%2F%20%20constructor%0A%20CUsbPCECGHelper()%3B%0A%20%2F%2F%20destructor%0A%20virtual%20~CUsbPCECGHelper()%3B%0A%0A%20BOOL%20GetDeviceHandle(GUID%20guidDeviceInterface%2C%20PHANDLE%20hDeviceHandle)%3B%0A%20BOOL%20GetWinUSBHandle(HANDLE%20hDeviceHandle%2C%20PWINUSB_INTERFACE_HANDLE%20phWinUSBHandle)%3B%0A%20BOOL%20GetUSBDeviceSpeed(WINUSB_INTERFACE_HANDLE%20hDeviceHandle%2C%20UCHAR*%20pDeviceSpeed)%3B%0A%20BOOL%20QueryDeviceEndpoints(WINUSB_INTERFACE_HANDLE%20hDeviceHandle%2C%20PIPE_ID*%20pipeid)%3B%0A%0A%20void%20ClearIsobuffers(void)%3B%0A%20void%20ClearDeviceHandles(void)%3B%0A%20void%20ClearThreadHandles(void)%3B%0A%20DWORD%20StartThreadHandles(void)%3B%0A%0A%20HANDLE%20%20%20%20%20%20m_hDeviceHandle%20%3B%0A%20WINUSB_INTERFACE_HANDLE%20%20m_hWinUSBHandle%5B2%5D%3B%0A%20PIPE_ID%20%20%20%20%20%20PipeID%3B%0A%20DRIVER_VERSION%20%20%20%20drvver%3B%0A%20BOOL%20%20%20%20%20%20RealTimeInProgress%3B%0A%0A%20ULONG%20%20%20%20%20%20IsochInTransferSize%3B%0A%20ULONG%20%20%20%20%20%20IsochInPacketCount%3B%0A%20PUCHAR%20%20%20%20%20%20readBuffer%3B%0A%20LPOVERLAPPED%20%20%20%20overlapped%3B%0A%20WINUSB_ISOCH_BUFFER_HANDLE%20isochReadBufferHandle%3B%0A%20PUSBD_ISO_PACKET_DESCRIPTOR%20isochPacketDescriptors%3B%0A%0A%0A%20%2F%2Freading%20execution%20thread%20handle%0A%20HANDLE%20%20%20%20%20%20m_hEventThread%3B%0A%20%2F%2Fevent%20handle%20to%20close%20execution%20thread%0A%20HANDLE%20%20%20%20%20%20m_hCloseThread%3B%0A%20%2F%2Fevent%20handle%20for%20read%20%0A%20HANDLE%20%20%20%20%20%20m_hReadAsync%5BISOCH_TRANSFER_COUNT%5D%3B%0A%20DWORD%20%20%20%20%20%20m_dwInterval%3B%0A%20BOOL%20%20%20%20%20%20m_bResult%3B%0A%0A%20DWORD%20ReadIsoBuffer(DWORD%20eventIndex)%3B%0A%0A%20%2F%2F%20Data%20Event%20thread%20procedure.%0A%20static%20DWORD%20WINAPI%20AsyncReadThreadProc(__in%20LPVOID%20pvData)%3B%0A%0A%0A%20PRING_BUFFER%20m_DataRingBuffer%3B%0A%0A%20PRING_BUFFER%20AllocRingBuffer(%20SIZE_T%20%20%20%20Size%20)%3B%0A%20VOID%20%20%20FreeRingBuffer(%20PRING_BUFFER%20%20%20ringBuffer)%3B%0A%20SIZE_T%20%20%20ReadRingBuffer(%20PRING_BUFFER%20%20%20ringBuffer%2C%20PUCHAR%20%20%20%20readBuffer%2C%20SIZE_T%20%20%20numberOfBytesToRead%20)%3B%0A%20SIZE_T%20%20%20WriteRingBuffer(PRING_BUFFER%20%20%20ringBuffer%2C%20PUCHAR%20%20%20%20writeBuffer%2C%20SIZE_T%20%20%20numberOfBytesToWrite)%3B%0A%20VOID%20%20%20RingBufferGetAvailableSpace(PRING_BUFFER%20%20%20%20%20%20ringBuffer%2C%20SIZE_T*%20AvailableSpace%20)%3B%0A%20VOID%20%20%20RingBufferGetAvailableData(%20PRING_BUFFER%20%20%20%20%20%20ringBuffer%2C%20SIZE_T*%20AvailableData%20)%3B%0A%0A%7D%3B%0A%0A%0ACUsbPCECGHelper%20%20helperfunctionsc_class%3B%0A%0A%0A%23endif%0A%0A%23ifdef%20USE_WINUSB_DRIVER%0A%0ACUsbPCECGHelper%3A%3ACUsbPCECGHelper()%0A%7B%0A%20m_hDeviceHandle%20%20%20%20%3D%20INVALID_HANDLE_VALUE%3B%0A%20m_hWinUSBHandle%5B0%5D%20%3D%20INVALID_HANDLE_VALUE%3B%0A%20m_hWinUSBHandle%5B1%5D%20%3D%20INVALID_HANDLE_VALUE%3B%0A%0A%20drvver.MajorVersion%20%3D%200%3B%0A%20drvver.MinorVersion%20%3D%200%3B%0A%20drvver.BuildVersion%20%3D%200%3B%0A%0A%20PipeID.Bulk_Pipe%5B0%5D.index%20%3D%20-1%3B%0A%20PipeID.Int_Pipe%20%5B0%5D.index%20%3D%20-1%3B%0A%20PipeID.Iso_Pipe%20%5B0%5D.index%20%3D%20-1%3B%0A%0A%20PipeID.Bulk_Pipe%5B1%5D.index%20%3D%20-1%3B%0A%20PipeID.Int_Pipe%20%5B1%5D.index%20%3D%20-1%3B%0A%20PipeID.Iso_Pipe%20%5B1%5D.index%20%3D%20-1%3B%0A%0A%20RealTimeInProgress%20%3D%20FALSE%3B%0A%0A%20readBuffer%20%3D%20NULL%3B%0A%20isochPacketDescriptors%20%3D%20NULL%3B%0A%20overlapped%20%3D%20NULL%3B%0A%20isochReadBufferHandle%20%3D%20INVALID_HANDLE_VALUE%3B%0A%0A%20m_hEventThread%20%3D%20NULL%3B%0A%20m_hCloseThread%20%3D%20NULL%3B%0A%20m_bResult%20%3D%20FALSE%3B%0A%0A%0A%20m_DataRingBuffer%20%3D%20NULL%3B%0A%20m_DataRingBuffer%20%3D%20AllocRingBuffer(64%20*%201024)%3B%0A%7D%0A%0ACUsbPCECGHelper%3A%3A~CUsbPCECGHelper()%0A%7B%0A%20ClearThreadHandles()%3B%0A%20ClearIsobuffers()%3B%0A%20ClearDeviceHandles()%3B%0A%0A%20FreeRingBuffer(m_DataRingBuffer)%3B%0A%7D%0A%0A%0Avoid%20%20CUsbPCECGHelper%3A%3AClearThreadHandles(void)%0A%7B%0A%20if%20(NULL%20!%3D%20m_hCloseThread)%0A%20%7B%0A%20%20%2F%2F%20Stop%20the%20event%20thread.%0A%20%20%3A%3ASetEvent(m_hCloseThread)%3B%0A%0A%20%20%2F%2F%20Wait%20for%20the%20thread%20to%20end.%0A%20%20%3A%3AWaitForSingleObject(m_hEventThread%2C%20INFINITE)%3B%0A%0A%20%20if%20(NULL%20!%3D%20m_hEventThread)%0A%20%20%7B%0A%20%20%20CloseHandle(m_hEventThread)%3B%0A%20%20%20m_hEventThread%20%3D%20NULL%3B%0A%20%20%7D%0A%0A%20%20CloseHandle(m_hCloseThread)%3B%0A%20%20m_hCloseThread%20%3D%20NULL%3B%0A%20%7D%0A%7D%0A%0Avoid%20CUsbPCECGHelper%3A%3AClearIsobuffers(void)%0A%7B%0A%20%2F%2FULONG%20i%3B%0A%0A%20if%20(isochReadBufferHandle%20!%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20WinUsb_UnregisterIsochBuffer(isochReadBufferHandle)%3B%0A%20%20isochReadBufferHandle%20%3D%20INVALID_HANDLE_VALUE%3B%0A%20%7D%0A%0A%20if%20(readBuffer%20!%3D%20NULL)%0A%20%7B%0A%20%20delete%5B%5D%20readBuffer%3B%0A%20%20readBuffer%20%3D%20NULL%3B%0A%20%7D%0A%0A%20if%20(isochPacketDescriptors%20!%3D%20NULL)%0A%20%7B%0A%20%20delete%5B%5D%20isochPacketDescriptors%3B%0A%20%20isochPacketDescriptors%20%3D%20NULL%3B%0A%20%7D%0A%0A%2F*%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%7B%0A%20%20if%20(overlapped%5Bi%5D.hEvent%20!%3D%20NULL)%0A%20%20%7B%0A%20%20%20CloseHandle(overlapped%5Bi%5D.hEvent)%3B%0A%20%20%20overlapped%5Bi%5D.hEvent%20%3D%20NULL%3B%0A%20%20%7D%0A%20%7D*%2F%0A%0A%20if%20(overlapped%20!%3D%20NULL)%0A%20%7B%0A%20%20delete%5B%5D%20overlapped%3B%0A%20%20overlapped%20%3D%20NULL%3B%0A%20%7D%0A%7D%0A%0Avoid%20CUsbPCECGHelper%3A%3AClearDeviceHandles(void)%0A%7B%0A%20if%20(m_hWinUSBHandle%5B0%5D%20!%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20WinUsb_Free(m_hWinUSBHandle%5B0%5D)%3B%0A%20%20m_hWinUSBHandle%5B0%5D%20%3D%20INVALID_HANDLE_VALUE%3B%0A%20%7D%0A%0A%20if%20(m_hWinUSBHandle%5B1%5D%20!%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20WinUsb_Free(m_hWinUSBHandle%5B1%5D)%3B%0A%20%20m_hWinUSBHandle%5B1%5D%20%3D%20INVALID_HANDLE_VALUE%3B%0A%20%7D%0A%0A%20if%20(m_hDeviceHandle%20!%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20CloseHandle(m_hDeviceHandle)%3B%0A%20%20m_hDeviceHandle%20%3D%20INVALID_HANDLE_VALUE%3B%0A%20%7D%0A%0A%7D%0A%0ADWORD%20CUsbPCECGHelper%3A%3AStartThreadHandles(void)%0A%7B%0A%20DWORD%20result%20%3D%20S_OK%3B%0A%0A%20if%20(m_hWinUSBHandle%5B0%5D%20%3D%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20return%20E_HANDLE%3B%0A%20%7D%0A%0A%0A%20%2F%2F%20Create%20the%20event%20used%20to%20close%20the%20thread.%0A%20if%20(NULL%20%3D%3D%20m_hCloseThread)%0A%20%7B%0A%20%20m_hCloseThread%20%3D%20%3A%3ACreateEvent(NULL%2C%20FALSE%2C%20FALSE%2C%20TEXT(%22CloseThreadEvent%22))%3B%0A%20%7D%0A%20if%20(NULL%20%3D%3D%20m_hCloseThread)%0A%20%7B%0A%20%20result%3DE_UNEXPECTED%3B%0A%20%7D%0A%0A%20if%20(SUCCEEDED(result)%20%26amp%3B%26amp%3B%20(m_hEventThread%20%3D%3D%20NULL))%0A%20%7B%0A%20%20m_hEventThread%20%3D%20%3A%3ACreateThread(NULL%2C%20%20%20%20%20%20%20%20%2F%2F%20Cannot%20be%20inherited%20by%20child%20process%0A%20%20%200%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Default%20stack%20size%0A%20%20%20%26amp%3BCUsbPCECGHelper%3A%3AAsyncReadThreadProc%2C%20%20%2F%2F%20Thread%20proc%0A%20%20%20(LPVOID)this%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Thread%20proc%20argument%0A%20%20%200%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Starting%20state%20%3D%20running%0A%20%20%20NULL)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20No%20thread%20identifier%0A%0A%20%20if%20(NULL%20%3D%3D%20m_hEventThread)%0A%20%20%7B%0A%20%20%20result%20%3D%20E_UNEXPECTED%3B%0A%20%20%7D%0A%20%20else%0A%20%20%7B%0A%20%20%20%2F%2FDWORD%20dwError%2C%20dwThreadPri%3B%0A%20%20%20if%20(!SetThreadPriority(m_hEventThread%2C%20THREAD_PRIORITY_HIGHEST))%0A%20%20%20%7B%0A%20%20%20%20%2F%2FdwError%20%3D%20GetLastError()%3B%0A%20%20%20%20result%20%3D%20E_UNEXPECTED%3B%0A%20%20%20%7D%0A%20%20%20%2F%2FdwThreadPri%20%3D%20GetThreadPriority(m_hEventThread)%3B%0A%20%20%7D%0A%20%7D%0A%0A%20return%20result%3B%0A%7D%0A%0A%0ADWORD%20WINAPI%20CUsbPCECGHelper%3A%3AAsyncReadThreadProc(__in%20LPVOID%20pvData)%0A%7B%0A%0A%23if(1)%0A%0A%20%2F%2F--------------%0A%0A%20HANDLE%20hEvents%5BISOCH_TRANSFER_COUNT%2B1%5D%3B%0A%20DWORD%20dwWait%20%3D%200%3B%0A%20DWORD%20dwNum%20%3D%200%3B%0A%20USHORT%20headerSize%20%3D%203%3B%0A%20ULONG%20bytesRead%20%3D%200%3B%0A%20BOOL%20b%20%3D%20FALSE%3B%0A%20ULONG%20i%3B%0A%20BOOL%20result%20%3D%20FALSE%3B%0A%0A%20%2F%2F%20Cast%20the%20argument%20to%20the%20correct%20type%0A%20CUsbPCECGHelper*%20pThis%20%3D%20static_cast%3CCUSBPCECGHELPER%3E(pvData)%3B%0A%0A%20%2F%2F%20New%20threads%20must%20always%20CoInitialize%0A%20HRESULT%20hr%20%3D%20CoInitializeEx(NULL%2C%20COINIT_MULTITHREADED)%3B%0A%0A%20ULONG%20totalTransferSize%20%3D%20pThis-%26gt%3BIsochInTransferSize%20*%20ISOCH_TRANSFER_COUNT%3B%0A%0A%20pThis-%26gt%3BreadBuffer%20%3D%20new%20UCHAR%5BtotalTransferSize%5D%3B%0A%20if%20(pThis-%26gt%3BreadBuffer%20%3D%3D%20NULL)%0A%20%7B%0A%20%20%2F%2Fsprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bStart()%20Unable%20to%20allocate%20memory%5Cn%22)%3B%0A%20%20%2F%2FOutputDebugString((LPCSTR)s)%3B%0A%20%20hr%20%3D%20E_UNEXPECTED%3B%0A%20%7D%0A%20else%0A%20%7B%0A%20%20ZeroMemory(pThis-%26gt%3BreadBuffer%2C%20totalTransferSize)%3B%0A%20%7D%0A%0A%20hEvents%5B0%5D%20%3D%20pThis-%26gt%3Bm_hCloseThread%3B%0A%0A%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%7B%0A%20%20pThis-%26gt%3Bm_hReadAsync%5Bi%5D%20%3D%20CreateEvent(%0A%20%20%20NULL%2C%20%20%20%20%2F%2F%20default%20security%20attribute%0A%20%20%20TRUE%2C%20%20%20%20%2F%2F%20manual-reset%20event%0A%20%20%20FALSE%2C%20%20%20%2F%2F%20initial%20state%20%3D%20not%20signaled%0A%20%20%20NULL)%3B%20%20%20%2F%2F%20unnamed%20event%20object%0A%20%7D%0A%0A%20for%20(i%20%3D%201%3B%20i%20%26lt%3B%20(ISOCH_TRANSFER_COUNT%2B1)%3B%20i%2B%2B)%0A%20%20hEvents%5Bi%5D%20%3D%20pThis-%26gt%3Bm_hReadAsync%5Bi-1%5D%3B%0A%0A%20if%20(SUCCEEDED(hr))%0A%20%7B%0A%20%20pThis-%26gt%3Boverlapped%20%3D%20new%20OVERLAPPED%5BISOCH_TRANSFER_COUNT%5D%3B%0A%20%20ZeroMemory(pThis-%26gt%3Boverlapped%2C%20(sizeof(OVERLAPPED)%20*%20ISOCH_TRANSFER_COUNT))%3B%0A%20%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%20%7B%0A%2F%2F%20%20%20pThis-%26gt%3Boverlapped%5Bi%5D.hEvent%20%3D%20CreateEvent(NULL%2C%20TRUE%2C%20FALSE%2C%20NULL)%3B%0A%0A%20%20%20pThis-%26gt%3Boverlapped%5Bi%5D.hEvent%20%3D%20pThis-%26gt%3Bm_hReadAsync%5Bi%5D%3B%0A%20%20%20%2F%2F%20Initialize%20the%20rest%20of%20the%20OVERLAPPED%20structure%20to%20zero.%0A%20%20%20pThis-%26gt%3Boverlapped%5Bi%5D.Internal%20%3D%200%3B%0A%20%20%20pThis-%26gt%3Boverlapped%5Bi%5D.InternalHigh%20%3D%200%3B%0A%20%20%20pThis-%26gt%3Boverlapped%5Bi%5D.Offset%20%3D%200%3B%0A%20%20%20pThis-%26gt%3Boverlapped%5Bi%5D.OffsetHigh%20%3D%200%3B%0A%0A%20%20%20if%20(pThis-%26gt%3Boverlapped%5Bi%5D.hEvent%20%3D%3D%20NULL)%0A%20%20%20%7B%0A%20%20%20%20%2F%2Fsprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bStart()%20Unable%20to%20set%20event%20for%20overlapped%20operation%5Cn%22)%3B%0A%20%20%20%20%2F%2FOutputDebugString((LPCSTR)s)%3B%0A%20%20%20%20hr%20%3D%20E_UNEXPECTED%3B%0A%20%20%20%7D%0A%20%20%7D%0A%20%7D%0A%0A%20if%20(SUCCEEDED(hr))%0A%20%7B%0A%20%20result%20%3D%20WinUsb_RegisterIsochBuffer(%0A%20%20%20pThis-%26gt%3Bm_hWinUSBHandle%5B0%5D%2C%20%20%20%2F%2F%20An%20opaque%20handle%20to%20an%20interface%20in%20the%20selected%20configuration.%20That%20handle%20must%20be%20created%20by%20a%20previous%20call%20to%20WinUsb_Initialize%20or%20WinUsb_GetAssociatedInterface.%0A%20%20%20pThis-%26gt%3BPipeID.Iso_Pipe%5B0%5D.PipeId%2C%20%2F%2F%20Derived%20from%20Bit%203...0%20of%20the%20bEndpointAddress%20field%20in%20the%20endpoint%20descriptor.%0A%20%20%20pThis-%26gt%3BreadBuffer%2C%20%20%20%20%20%2F%2F%20Pointer%20to%20the%20transfer%20buffer%20to%20be%20registered.%0A%20%20%20totalTransferSize%2C%20%20%20%20%20%2F%2F%20Length%2C%20in%20bytes%2C%20of%20the%20transfer%20buffer%20pointed%20to%20by%20Buffer.%0A%20%20%20%26amp%3BpThis-%26gt%3BisochReadBufferHandle)%3B%20%20%2F%2F%20Receives%20an%20opaque%20handle%20to%20the%20registered%20buffer.%20This%20handle%20is%20required%20by%20other%20WinUSB%20functions%20that%20perform%20isochronous%20transfers.%20To%20release%20the%20handle%2C%20call%20the%20WinUsb_UnregisterIsochBuffer%20function.%0A%0A%20%20if%20(!result)%0A%20%20%7B%0A%20%20%20%2F%2Fsprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bStart()%20Isoch%20buffer%20registration%20failed.%5Cn%22)%3B%0A%20%20%20%2F%2FOutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20hr%20%3D%20E_UNEXPECTED%3B%0A%20%20%7D%0A%20%7D%0A%0A%20if%20(SUCCEEDED(hr))%0A%20%7B%0A%20%20pThis-%26gt%3BisochPacketDescriptors%20%3D%20new%20USBD_ISO_PACKET_DESCRIPTOR%5BpThis-%26gt%3BIsochInPacketCount%20*%20ISOCH_TRANSFER_COUNT%5D%3B%0A%20%20ZeroMemory(pThis-%26gt%3BisochPacketDescriptors%2C%20pThis-%26gt%3BIsochInPacketCount%20*%20ISOCH_TRANSFER_COUNT)%3B%0A%0A%0A%20%20%2F%2Ffor%20iso%20endpoints%20read%20this%0A%20%20%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fwindows-hardware%2Fdrivers%2Fusbcon%2Fgetting-set-up-to-use-windows-devices-usb%0A%20%20%2F%2F%0A%0A%20%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%20%7B%0A%20%20%20result%20%3D%20WinUsb_ReadIsochPipeAsap(%0A%20%20%20%20pThis-%26gt%3BisochReadBufferHandle%2C%20%20%20%2F%2F%20An%20opaque%20handle%20to%20the%20transfer%20buffer%20that%20was%20registered%20by%20a%20previous%20call%20to%20WinUsb_RegisterIsochBuffer.%0A%20%20%20%20pThis-%26gt%3BIsochInTransferSize%20*%20i%2C%20%20%20%2F%2F%20Offset%20into%20the%20buffer%20relative%20to%20the%20start%20the%20transfer.%0A%20%20%20%20pThis-%26gt%3BIsochInTransferSize%2C%20%20%20%20%2F%2F%20Length%20in%20bytes%20of%20the%20transfer%20buffer.%0A%20%20%20%20(i%20%3D%3D%200)%20%3F%20FALSE%20%3A%20TRUE%2C%20%20%20%20%2F%2F%20Indicates%20that%20the%20transfer%20should%20only%20be%20submitted%20if%20it%20can%20be%20scheduled%20in%20the%20first%20frame%20after%20the%20last%20pending%20transfer.%0A%20%20%20%20pThis-%26gt%3BIsochInPacketCount%2C%20%20%20%20%2F%2F%20Total%20number%20of%20isochronous%20packets%20required%20to%20hold%20the%20transfer%20buffer.Also%20indicates%20the%20number%20of%20elements%20in%20the%20array%20pointed%20to%20by%20IsoPacketDescriptors.%0A%20%20%20%20%26amp%3BpThis-%26gt%3BisochPacketDescriptors%5Bi%20*%20pThis-%26gt%3BIsochInPacketCount%5D%2C%20%2F%2FAn%20array%20of%20USBD_ISO_PACKET_DESCRIPTOR%20that%20receives%20the%20details%20of%20each%20isochronous%20packet%20in%20the%20transfer.%0A%20%20%20%20%26amp%3BpThis-%26gt%3Boverlapped%5Bi%5D)%3B%20%20%20%20%20%2F%2F%20Pointer%20to%20an%20OVERLAPPED%20structure%20used%20for%20asynchronous%20operations.%0A%0A%20%20%20if%20(!result)%0A%20%20%20%7B%0A%20%20%20%20DWORD%20%20lastError%20%3D%20GetLastError()%3B%0A%0A%20%20%20%20if%20(lastError%20!%3D%20ERROR_IO_PENDING)%0A%20%20%20%20%7B%0A%20%20%20%20%20%2F%2Fsprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bStart()%20Failed%20to%20start%20a%20read%20operation%20with%20error%20%25x%5Cn%22%2C%20lastError)%3B%0A%20%20%20%20%20%2F%2FOutputDebugString((LPCSTR)s)%3B%0A%20%20%20%20%20hr%20%3D%20E_UNEXPECTED%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%7D%0A%20%7D%0A%20%2F%2F--------------%0A%0A%0A%20if%20(SUCCEEDED(hr))%0A%20%7B%0A%20%20while%20(true)%0A%20%20%7B%20%0A%20%20%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%20%20%20pThis-%26gt%3Bm_bResult%20%3D%20ResetEvent(pThis-%26gt%3Bm_hReadAsync%5Bi%5D)%3B%0A%0A%20%20%20dwWait%20%3D%20WaitForMultipleObjects(ISOCH_TRANSFER_COUNT%2B1%2C%20%20%20%20%20%20%2F%2F%20number%20of%20event%20objects%20%0A%20%20%20%20hEvents%2C%20%20%20%20%20%20%2F%2F%20array%20of%20event%20objects%20%0A%20%20%20%20FALSE%2C%20%20%20%20%20%20%20%20%2F%2F%20does%20not%20wait%20for%20all%20%0A%20%20%20%20INFINITE%20%20%20%20%2F%2F%20waits%20indefinitely%20%0A%20%20%20)%3B%0A%20%0A%0A%20%20%20if%20(dwWait%20%3D%3D%20WAIT_OBJECT_0)%20%2F%2FSTOP_THREAD%0A%20%20%20%7B%0A%20%20%20%20CoUninitialize()%3B%0A%0A%20%20%20%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%20%20%20%20CloseHandle(pThis-%26gt%3Bm_hReadAsync%5Bi%5D)%3B%0A%0A%20%20%20%20return%200%3B%0A%20%20%20%7D%0A%20%20%20else%0A%20%20%20%7B%0A%20%20%20%20for%20(i%20%3D%201%3B%20i%20%26lt%3B%20(ISOCH_TRANSFER_COUNT%20%2B%201)%3B%20i%2B%2B)%0A%20%20%20%20%7B%0A%20%20%20%20%20if%20(dwWait%20%3D%3D%20(WAIT_OBJECT_0%20%2B%20i))%0A%20%20%20%20%20%7B%0A%20%20%20%20%20%20pThis-%26gt%3BReadIsoBuffer((i-1))%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%7D%0A%20%7D%0A%0A%23endif%0A%0A%0A%23if(0)%0A%0A%20OVERLAPPED%20oOverlap%3B%0A%20HANDLE%20hEvents%5B2%5D%3B%0A%20DWORD%20dwWait%20%3D%200%3B%0A%20DWORD%20dwNum%20%3D%200%3B%0A%20const%20DWORD%20STOP_THREAD%20%3D%20WAIT_OBJECT_0%3B%0A%20const%20DWORD%20READ_EVENT%20%20%3D%20WAIT_OBJECT_0%20%2B%201%3B%0A%20USHORT%20headerSize%20%3D%203%3B%0A%20UCHAR%20buffer%5B3%5D%3B%0A%20ULONG%20bytesRead%20%3D%200%3B%0A%20BOOL%20b%20%3D%20FALSE%3B%0A%20%0A%0A%0A%20%2F%2F%20Cast%20the%20argument%20to%20the%20correct%20type%0A%20CUsbPCECGHelper*%20pThis%20%3D%20static_cast%3CCUSBPCECGHELPER%3E(pvData)%3B%0A%0A%20%2F%2F%20New%20threads%20must%20always%20CoInitialize%0A%20HRESULT%20hr%20%3D%20CoInitializeEx(NULL%2C%20COINIT_MULTITHREADED)%3B%0A%0A%20%0A%20hEvents%5B0%5D%20%3D%20pThis-%26gt%3Bm_hCloseThread%3B%0A%0A%20pThis-%26gt%3Bm_hReadAsync%20%3D%20CreateEvent(%0A%20%20NULL%2C%20%20%20%20%2F%2F%20default%20security%20attribute%0A%20%20TRUE%2C%20%20%20%20%2F%2F%20manual-reset%20event%0A%20%20FALSE%2C%20%20%20%2F%2F%20initial%20state%20%3D%20not%20signaled%0A%20%20NULL)%3B%20%20%20%2F%2F%20unnamed%20event%20object%0A%0A%0A%20hEvents%5B1%5D%20%3D%20pThis-%26gt%3Bm_hReadAsync%3B%0A%0A%2F*%0A%20oOverlap.hEvent%20%3D%20pThis-%26gt%3Bm_hReadAsync%3B%0A%20%2F%2F%20Initialize%20the%20rest%20of%20the%20OVERLAPPED%20structure%20to%20zero.%0A%20oOverlap.Internal%20%3D%200%3B%0A%20oOverlap.InternalHigh%20%3D%200%3B%0A%20oOverlap.Offset%20%3D%200%3B%0A%20oOverlap.OffsetHigh%20%3D%200%3B%0A*%2F%0A%0A%20%0A%0A%20if%20(SUCCEEDED(hr))%0A%20%7B%0A%20%20while%20(true)%0A%20%20%7B%0A%20%20%20%2F*%0A%20%20%20pThis-%26gt%3Bm_bResult%20%3D%20ResetEvent(pThis-%26gt%3Bm_hReadAsync)%3B%0A%20%20%20pThis-%26gt%3BReadHeader(buffer%2C%20headerSize%2C%20%26amp%3BbytesRead%2C%20%26amp%3BoOverlap)%3B%0A%20%20%20dwWait%20%3D%20WaitForMultipleObjects(2%2C%20%20%20%20%20%20%2F%2F%20number%20of%20event%20objects%20%0A%20%20%20%20hEvents%2C%20%20%20%20%20%20%2F%2F%20array%20of%20event%20objects%20%0A%20%20%20%20FALSE%2C%20%20%20%20%20%20%20%20%2F%2F%20does%20not%20wait%20for%20all%20%0A%20%20%20%20INFINITE%20%20%20%20%2F%2F%20waits%20indefinitely%20%0A%20%20%20)%3B%0A%20%20%20b%20%3D%20WinUsb_GetOverlappedResult(pThis-%26gt%3Bm_UsbHandle%5B1%5D%2C%20%26amp%3BoOverlap%2C%20%26amp%3BdwNum%2C%20FALSE)%3B%0A%20%20%20*%2F%0A%0A%20%20%20pThis-%26gt%3Bm_bResult%20%3D%20ResetEvent(pThis-%26gt%3Bm_hReadAsync)%3B%0A%20%20%20dwWait%20%3D%20WaitForMultipleObjects(2%2C%20%20%20%20%20%20%2F%2F%20number%20of%20event%20objects%20%0A%20%20%20%20hEvents%2C%20%20%20%20%20%20%2F%2F%20array%20of%20event%20objects%20%0A%20%20%20%20FALSE%2C%20%20%20%20%20%20%20%20%2F%2F%20does%20not%20wait%20for%20all%20%0A%20%20%20%20INFINITE%20%20%20%20%2F%2F%20waits%20indefinitely%20%0A%20%20%20)%3B%0A%0A%20%20%20switch%20(dwWait)%0A%20%20%20%7B%0A%20%20%20case%20STOP_THREAD%3A%0A%20%20%20%20CoUninitialize()%3B%0A%20%20%20%20CloseHandle(pThis-%26gt%3Bm_hReadAsync)%3B%0A%20%20%20%20return%200%3B%0A%20%20%20%20%2F%2Fbreak%3B%0A%20%20%20case%20READ_EVENT%3A%0A%20%20%20%20%2F*%0A%20%20%20%20%2F%2Freads%20the%20rest%20of%20the%20message%20if%20exist%2C%20throws%20events%20if%20needed%0A%20%20%20%20if%20(b)%0A%20%20%20%20%7B%0A%20%20%20%20%20pThis-%26gt%3BParseDataMessage(buffer)%3B%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%2F%2Ferror%0A%20%20%20%20%20WinUsb_FlushPipe(pThis-%26gt%3Bm_UsbHandle%5B1%5D%2C%20pThis-%26gt%3Bm_bulkInPipe)%3B%0A%20%20%20%20%7D%0A%20%20%20%20break%3B%0A%20%20%20%20*%2F%0A%20%20%20default%3A%0A%20%20%20%20break%3B%0A%20%20%20%7D%0A%20%20%7D%0A%20%7D%0A%0A%23endif%0A%0A%20%2F%2Fcode%20not%20reached%0A%20return%201%3B%0A%7D%0A%0A%0ADWORD%20CUsbPCECGHelper%3A%3AReadIsoBuffer(DWORD%20eventIndex)%0A%7B%0A%23if(1)%0A%0A%20%2F*%0A%20%20%2F%2Ffor%20iso%20endpoints%20read%20this%0A%20%20%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fwindows-hardware%2Fdrivers%2Fusbcon%2Fgetting-set-up-to-use-windows-devices-usb%0A%20%20%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fwindows-hardware%2Fdrivers%2Fusbcon%2Ftransfer-data-to-isochronous-endpoints%0A%20%20%2F%2F%0A%20*%2F%0A%0A%0A%20char%20s%5B256%5D%3B%0A%20DWORD%20Status%20%3D%20UsbPCECG_ERR_SUCCESS%3B%0A%20ULONG%20i%2C%20j%3B%0A%20BOOL%20result%3B%0A%20DWORD%20lastError%3B%0A%20ULONG%20numBytes%20%3D%200%3B%0A%20BOOL%20%20%20%20ContinueStream%20%3D%20TRUE%3B%0A%0A%20ULONG%20%20%20%20frameNumber%3B%0A%20ULONG%20%20%20%20startFrame%3B%0A%20LARGE_INTEGER%20%20timeStamp%3B%0A%0A%20if%20(helperfunctionsc_class.m_hWinUSBHandle%5B0%5D%20%3D%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%7D%0A%0A%0A%20result%20%3D%20WinUsb_GetCurrentFrameNumber(%0A%20%20helperfunctionsc_class.m_hWinUSBHandle%5B0%5D%2C%0A%20%20%26amp%3BframeNumber%2C%0A%20%20%26amp%3BtimeStamp)%3B%0A%0A%20if%20(!result)%0A%20%7B%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20WinUsb_GetCurrentFrameNumber%20failed.%20%5Cn%22)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%7D%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Current%20Frame%20number%3D%25d%5Cn%22%2C%20frameNumber)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0A%0A%0A%20startFrame%20%3D%20frameNumber%20%2B%2010%3B%0A%0A%20i%20%3D%20eventIndex%3B%0A%2F%2F%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%7B%0A%20%20if%20(helperfunctionsc_class.RealTimeInProgress%20%3D%3D%20FALSE)%0A%20%20%7B%0A%20%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%20%7D%0A%0A%20%20result%20%3D%20WinUsb_GetOverlappedResult(%0A%20%20%20helperfunctionsc_class.m_hWinUSBHandle%5B0%5D%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.overlapped%5Bi%5D%2C%0A%20%20%20%26amp%3BnumBytes%2C%0A%20%20%20TRUE)%3B%0A%0A%20%20if%20(!result%20%7C%7C%20numBytes%20%3D%3D%200)%0A%20%20%7B%0A%20%20%20%2F%2F0x1F%20%20%3D%20ERROR_GEN_FAILURE%20%20%20%20A%20device%20attached%20to%20the%20system%20is%20not%20functioning.%0A%20%20%20%2F%2F0x7A%20%20%3D%20ERROR_INSUFFICIENT_BUFFER%20%20%20%20%20The%20data%20area%20passed%20to%20a%20system%20call%20is%20too%20small.%0A%20%20%20%2F%2F0x57%20%20%3D%20ERROR_INVALID_PARAMETER%20%20%20%20%20%20%20The%20parameter%20is%20incorrect.%0A%20%20%20%2F%2F0x3E5%20%3D%20ERROR_IO_PENDING%20%20%20%20%20%20%20%20%20%20%20%20%20%20Overlapped%20I%2FO%20operation%20is%20in%20progress.%0A%0A%20%20%20lastError%20%3D%20GetLastError()%3B%0A%0A%20%20%20if%20(lastError%20%3D%3D%20ERROR_IO_PENDING)%20%2F%2FThe%20transfer%20is%20pending..%0A%20%20%20%7B%0A%20%20%20%20%2F%2F%20try%20again..%0A%20%20%20%20if%20(i%20%26gt%3B%200)%20i--%3B%0A%2F%2F%20%20%20%20continue%3B%0A%20%20%20%7D%0A%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Failed%20to%20read%20with%20error%20%25x%20%5Cn%22%2C%20lastError)%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%20%7D%0A%20%20else%0A%20%20%7B%0A%20%20%20numBytes%20%3D%200%3B%0A%20%20%20for%20(j%20%3D%200%3B%20j%20%26lt%3B%20helperfunctionsc_class.IsochInPacketCount%3B%20j%2B%2B)%0A%20%20%20%7B%0A%20%20%20%20numBytes%20%2B%3D%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%3B%0A%0A%20%20%20%20%2F%2Fsprintf_s(s%2C%20sizeof(s)%2C%20%22%25d-%25d-%25d%5Cn%22%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%2C%20helperfunctionsc_class.isochPackets%5Bj%5D.Offset%2C%20helperfunctionsc_class.isochPackets%5Bj%5D.Status)%3B%0A%20%20%20%20%2F%2FOutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%2F*%0A%20%20%20%20if%20(helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%20!%3D%200%20%26amp%3B%26amp%3B%20helperfunctionsc_class.isochPackets%5Bj%5D.Status%20%3D%3D%200)%0A%20%20%20%20%7B%0A%20%20%20%20%20memcpy(inBuffer%2C%20helperfunctionsc_class.readBuffer%20%2B%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Offset%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length)%3B%0A%20%20%20%20%20*nWriten%20%2B%3D%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%3B%0A%20%20%20%20%20inBuffer%20%2B%3D%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%3B%0A%20%20%20%20%7D%0A%20%20%20%20*%2F%0A%0A%20%20%20%20%2F*%0A%0A%20%20%20%20!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%0A%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20desc.lenght%3D%25d%20bytes%20descr.status%3D%25x%5Cn%22%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Status)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20for%20ECGUSB1D-EX%20get%0A%20%20%20%20nvUSB.lib%3A%20desc.lenght%3D2%20bytes%20descr.status%3D0%20%20%20%20%20%20%20%20%20%20%20if%20OK%0A%20%20%20%20nvUSB.lib%3A%20desc.lenght%3D0%20bytes%20descr.status%3Dc0020000%20%20%20%20if%20empty%20packet%0A%0A%20%20%20%20WD_USBD_STATUS_ISO_NOT_ACCESSED_BY_HW%0A%0A%20%20%20%20Extended%20isochronous%20error%20codes%20returned%20by%20USBD.%0A%20%20%20%20These%20errors%20appear%20in%20the%20packet%20status%20field%20of%20an%20isochronous%20transfer.%20%5B0xC0020000%5D%0A%20%20%20%20For%20some%20reason%20the%20controller%20did%20not%20access%20the%20TD%20associated%20with%20this%20packet%3A%0A%0A%0A%20%20%20%20!%0A%20%20%20%20When%20the%20USB%20driver%20stack%20processes%20the%20URB%2C%20the%20driver%20discards%20all%20isochronous%20packets%20in%20the%20URB%20whose%20frame%20numbers%20are%20lower%20than%20the%20current%20frame%20number.%0A%20%20%20%20The%20driver%20stack%20sets%20the%20Status%20member%20of%20the%20packet%20descriptor%20for%20each%20discarded%20packet%20to%20USBD_STATUS_ISO_NA_LATE_USBPORT%2C%20USBD_STATUS_ISO_NOT_ACCESSED_BY_HW%2C%0A%20%20%20%20or%20USBD_STATUS_ISO_NOT_ACCESSED_LATE.%20Even%20though%20some%20packets%20in%20the%20URB%20are%20discarded%2C%20the%20driver%20stack%20attempts%20to%20transmit%20only%20those%20packets%20whose%20frame%20numbers%0A%20%20%20%20are%20higher%20than%20the%20current%20frame%20number.%0A%20%20%20%20!!%0A%0A%20%20%20%20*%2F%0A%20%20%20%20%2F*%0A%20%20%20%20if%20(helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%20%3D%3D%200%20%26amp%3B%26amp%3B%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Status%20%3D%3D%20USBD_STATUS_ISO_NOT_ACCESSED_BY_HW)%0A%20%20%20%20%7B%0A%20%20%20%20%20if%20(!(WinUsb_FlushPipe(helperfunctionsc_class.m_hWinUSBHandle%5B0%5D%2C%20helperfunctionsc_class.PipeID.Iso_Pipe%5B0%5D.PipeId)))%0A%20%20%20%20%20%7B%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20error%20flush%20pipe%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20return%20UsbPCECG_ERR_RESETPIPE%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20*%2F%0A%0A%20%20%20%20if%20(helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%20!%3D%200%20%26amp%3B%26amp%3B%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Status%20%3D%3D%200)%0A%20%20%20%20%7B%0A%20%20%20%20%20WriteRingBuffer(%0A%20%20%20%20%20%20helperfunctionsc_class.m_DataRingBuffer%2C%0A%20%20%20%20%20%20(helperfunctionsc_class.readBuffer%20%2B%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Offset)%2C%0A%20%20%20%20%20%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%0A%20%20%20%20%20)%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Requested%20%25d%20bytes%20in%20%25d%20packets%20per%20transfer.%5Cn%22%2C%20helperfunctionsc_class.IsochInTransferSize%2C%20helperfunctionsc_class.IsochInPacketCount)%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20%7D%0A%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Transfer%20%25d%20completed.%20Read%20%25d%20bytes.%20%5Cn%22%2C%20i%20%2B%201%2C%20numBytes)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%0A%20%20result%20%3D%20WinUsb_ReadIsochPipeAsap(%0A%20%20%20helperfunctionsc_class.isochReadBufferHandle%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%20*%20i%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%2C%0A%20%20%20ContinueStream%2C%0A%20%20%20helperfunctionsc_class.IsochInPacketCount%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.isochPacketDescriptors%5Bi%20*%20helperfunctionsc_class.IsochInPacketCount%5D%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.overlapped%5Bi%5D)%3B%0A%0A%0A%20%20%2F*%0A%20%20%2F%2F%20not%20working%0A%20%20%2F%2F%20return%20with%20nvUSB.lib%3A%20bRead()%20Failed%20to%20read%20with%20error%201f%20%20after%20first%20time..%0A%20%20result%20%3D%20WinUsb_ReadIsochPipe(%0A%20%20%20helperfunctionsc_class.isochReadBufferHandle%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%20*%20i%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%2C%0A%20%20%20%26amp%3BstartFrame%2C%0A%20%20%20helperfunctionsc_class.IsochInPacketCount%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.isochPacketDescriptors%5Bi%20*%20helperfunctionsc_class.IsochInPacketCount%5D%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.overlapped%5Bi%5D)%3B%0A%20%20*%2F%0A%0A%20%20if%20(!result)%0A%20%20%7B%0A%20%20%20lastError%20%3D%20GetLastError()%3B%0A%0A%20%20%20if%20(lastError%20%3D%3D%20ERROR_INVALID_PARAMETER%20%26amp%3B%26amp%3B%20ContinueStream)%0A%20%20%20%7B%0A%20%20%20%20ContinueStream%20%3D%20FALSE%3B%0A%2F%2F%20%20%20%20continue%3B%0A%20%20%20%7D%0A%0A%20%20%20if%20(lastError%20!%3D%20ERROR_IO_PENDING)%0A%20%20%20%7B%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Failed%20to%20start%20a%20read%20operation%20with%20error%20%25x%5Cn%22%2C%20lastError)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%20%20%7D%0A%0A%20%20%20ContinueStream%20%3D%20TRUE%3B%0A%20%20%7D%0A%0A%20%7D%0A%0A%20return(Status)%3B%0A%0A%23endif%0A%0A%0A%23if(0)%0A%0A%20%2F*%0A%20%20%2F%2Ffor%20iso%20endpoints%20read%20this%0A%20%20%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fwindows-hardware%2Fdrivers%2Fusbcon%2Fgetting-set-up-to-use-windows-devices-usb%0A%20%20%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fwindows-hardware%2Fdrivers%2Fusbcon%2Ftransfer-data-to-isochronous-endpoints%0A%20%20%2F%2F%0A%20*%2F%0A%0A%0A%20char%20s%5B256%5D%3B%0A%20DWORD%20Status%20%3D%20UsbPCECG_ERR_SUCCESS%3B%0A%20ULONG%20i%2C%20j%3B%0A%20BOOL%20result%3B%0A%20DWORD%20lastError%3B%0A%20ULONG%20numBytes%3D0%3B%0A%20BOOL%20%20%20%20ContinueStream%20%3D%20TRUE%3B%0A%0A%20ULONG%20%20%20%20frameNumber%3B%0A%20ULONG%20%20%20%20startFrame%3B%0A%20LARGE_INTEGER%20%20timeStamp%3B%0A%0A%20if%20(helperfunctionsc_class.m_hWinUSBHandle%5B0%5D%20%3D%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%7D%0A%0A%0A%20result%20%3D%20WinUsb_GetCurrentFrameNumber(%0A%20%20helperfunctionsc_class.m_hWinUSBHandle%5B0%5D%2C%0A%20%20%26amp%3BframeNumber%2C%0A%20%20%26amp%3BtimeStamp)%3B%0A%0A%20if%20(!result)%0A%20%7B%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20WinUsb_GetCurrentFrameNumber%20failed.%20%5Cn%22)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%7D%0A%0A%20startFrame%20%3D%20frameNumber%20%2B%2010%3B%0A%0A%0A%20for%20(i%20%3D%200%3B%20i%20%26lt%3B%20ISOCH_TRANSFER_COUNT%3B%20i%2B%2B)%0A%20%7B%0A%20%20if%20(helperfunctionsc_class.RealTimeInProgress%20%3D%3D%20FALSE)%0A%20%20%7B%0A%20%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%20%7D%0A%0A%20%20result%20%3D%20WinUsb_GetOverlappedResult(%0A%20%20%20helperfunctionsc_class.m_hWinUSBHandle%5B0%5D%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.overlapped%5Bi%5D%2C%0A%20%20%20%26amp%3BnumBytes%2C%0A%20%20%20TRUE)%3B%0A%0A%20%20if%20(!result%20%7C%7C%20numBytes%3D%3D0)%0A%20%20%7B%0A%20%20%20%2F%2F0x1F%20%20%3D%20ERROR_GEN_FAILURE%20%20%20%20A%20device%20attached%20to%20the%20system%20is%20not%20functioning.%0A%20%20%20%2F%2F0x7A%20%20%3D%20ERROR_INSUFFICIENT_BUFFER%20%20%20%20%20The%20data%20area%20passed%20to%20a%20system%20call%20is%20too%20small.%0A%20%20%20%2F%2F0x57%20%20%3D%20ERROR_INVALID_PARAMETER%20%20%20%20%20%20%20The%20parameter%20is%20incorrect.%0A%20%20%20%2F%2F0x3E5%20%3D%20ERROR_IO_PENDING%20%20%20%20%20%20%20%20%20%20%20%20%20%20Overlapped%20I%2FO%20operation%20is%20in%20progress.%0A%0A%20%20%20lastError%20%3D%20GetLastError()%3B%0A%0A%20%20%20if%20(lastError%20%3D%3D%20ERROR_IO_PENDING)%20%2F%2FThe%20transfer%20is%20pending..%0A%20%20%20%7B%0A%20%20%20%20%2F%2F%20try%20again..%0A%20%20%20%20if%20(i%20%26gt%3B%200)%20i--%3B%20%0A%20%20%20%20continue%3B%0A%20%20%20%7D%0A%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Failed%20to%20read%20with%20error%20%25x%20%5Cn%22%2C%20lastError)%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%20%7D%0A%20%20else%0A%20%20%7B%0A%20%20%20numBytes%20%3D%200%3B%0A%20%20%20for%20(j%20%3D%200%3B%20j%20%26lt%3B%20helperfunctionsc_class.IsochInPacketCount%3B%20j%2B%2B)%0A%20%20%20%7B%0A%20%20%20%20numBytes%20%2B%3D%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%3B%0A%0A%20%20%20%20%2F%2Fsprintf_s(s%2C%20sizeof(s)%2C%20%22%25d-%25d-%25d%5Cn%22%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%2C%20helperfunctionsc_class.isochPackets%5Bj%5D.Offset%2C%20helperfunctionsc_class.isochPackets%5Bj%5D.Status)%3B%0A%20%20%20%20%2F%2FOutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%2F*%0A%20%20%20%20if%20(helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%20!%3D%200%20%26amp%3B%26amp%3B%20helperfunctionsc_class.isochPackets%5Bj%5D.Status%20%3D%3D%200)%0A%20%20%20%20%7B%0A%20%20%20%20%20memcpy(inBuffer%2C%20helperfunctionsc_class.readBuffer%20%2B%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Offset%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length)%3B%0A%20%20%20%20%20*nWriten%20%2B%3D%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%3B%0A%20%20%20%20%20inBuffer%20%2B%3D%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%3B%0A%20%20%20%20%7D%0A%20%20%20%20*%2F%0A%0A%20%20%20%20%2F*%0A%20%20%20%20%20%0A%20%20%20%20!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%20%0A%20%20%20%20%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20desc.lenght%3D%25d%20bytes%20descr.status%3D%25x%5Cn%22%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%2C%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Status)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20for%20ECGUSB1D-EX%20get%0A%20%20%20%20nvUSB.lib%3A%20desc.lenght%3D2%20bytes%20descr.status%3D0%20%20%20%20%20%20%20%20%20%20%20if%20OK%0A%20%20%20%20nvUSB.lib%3A%20desc.lenght%3D0%20bytes%20descr.status%3Dc0020000%20%20%20%20if%20empty%20packet%0A%0A%20%20%20%20WD_USBD_STATUS_ISO_NOT_ACCESSED_BY_HW%0A%0A%20%20%20%20Extended%20isochronous%20error%20codes%20returned%20by%20USBD.%0A%20%20%20%20These%20errors%20appear%20in%20the%20packet%20status%20field%20of%20an%20isochronous%20transfer.%20%5B0xC0020000%5D%20%0A%20%20%20%20For%20some%20reason%20the%20controller%20did%20not%20access%20the%20TD%20associated%20with%20this%20packet%3A%0A%0A%0A%20%20%20%20!%0A%20%20%20%20When%20the%20USB%20driver%20stack%20processes%20the%20URB%2C%20the%20driver%20discards%20all%20isochronous%20packets%20in%20the%20URB%20whose%20frame%20numbers%20are%20lower%20than%20the%20current%20frame%20number.%20%0A%20%20%20%20The%20driver%20stack%20sets%20the%20Status%20member%20of%20the%20packet%20descriptor%20for%20each%20discarded%20packet%20to%20USBD_STATUS_ISO_NA_LATE_USBPORT%2C%20USBD_STATUS_ISO_NOT_ACCESSED_BY_HW%2C%20%0A%20%20%20%20or%20USBD_STATUS_ISO_NOT_ACCESSED_LATE.%20Even%20though%20some%20packets%20in%20the%20URB%20are%20discarded%2C%20the%20driver%20stack%20attempts%20to%20transmit%20only%20those%20packets%20whose%20frame%20numbers%20%0A%20%20%20%20are%20higher%20than%20the%20current%20frame%20number.%0A%20%20%20%20!!%0A%0A%20%20%20%20*%2F%0A%0A%20%20%20%20if%20(helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%20!%3D%200%20%26amp%3B%26amp%3B%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Status%20%3D%3D%200)%0A%20%20%20%20%7B%0A%20%20%20%20%20WriteRingBuffer(%0A%20%20%20%20%20%20helperfunctionsc_class.m_DataRingBuffer%2C%0A%20%20%20%20%20%20(helperfunctionsc_class.readBuffer%20%2B%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Offset)%2C%0A%20%20%20%20%20%20helperfunctionsc_class.isochPacketDescriptors%5Bj%5D.Length%0A%20%20%20%20%20)%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Requested%20%25d%20bytes%20in%20%25d%20packets%20per%20transfer.%5Cn%22%2C%20helperfunctionsc_class.IsochInTransferSize%2C%20helperfunctionsc_class.IsochInPacketCount)%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20%7D%0A%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Transfer%20%25d%20completed.%20Read%20%25d%20bytes.%20%5Cn%22%2C%20i%20%2B%201%2C%20numBytes)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%0A%20%20result%20%3D%20WinUsb_ReadIsochPipeAsap(%0A%20%20%20helperfunctionsc_class.isochReadBufferHandle%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%20*%20i%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%2C%0A%20%20%20ContinueStream%2C%0A%20%20%20helperfunctionsc_class.IsochInPacketCount%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.isochPacketDescriptors%5Bi%20*%20helperfunctionsc_class.IsochInPacketCount%5D%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.overlapped%5Bi%5D)%3B%0A%20%20%0A%0A%20%20%2F*%0A%20%20%2F%2F%20not%20working%20%0A%20%20%2F%2F%20return%20with%20nvUSB.lib%3A%20bRead()%20Failed%20to%20read%20with%20error%201f%20%20after%20first%20time..%0A%20%20result%20%3D%20WinUsb_ReadIsochPipe(%0A%20%20%20helperfunctionsc_class.isochReadBufferHandle%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%20*%20i%2C%0A%20%20%20helperfunctionsc_class.IsochInTransferSize%2C%0A%20%20%20%26amp%3BstartFrame%2C%0A%20%20%20helperfunctionsc_class.IsochInPacketCount%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.isochPacketDescriptors%5Bi%20*%20helperfunctionsc_class.IsochInPacketCount%5D%2C%0A%20%20%20%26amp%3Bhelperfunctionsc_class.overlapped%5Bi%5D)%3B%0A%20%20*%2F%0A%0A%20%20if%20(!result)%0A%20%20%7B%0A%20%20%20lastError%20%3D%20GetLastError()%3B%0A%0A%20%20%20if%20(lastError%20%3D%3D%20ERROR_INVALID_PARAMETER%20%26amp%3B%26amp%3B%20ContinueStream)%0A%20%20%20%7B%0A%20%20%20%20ContinueStream%20%3D%20FALSE%3B%0A%20%20%20%20continue%3B%0A%20%20%20%7D%0A%0A%20%20%20if%20(lastError%20!%3D%20ERROR_IO_PENDING)%0A%20%20%20%7B%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20bRead()%20Failed%20to%20start%20a%20read%20operation%20with%20error%20%25x%5Cn%22%2C%20lastError)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20return%20UsbPCECG_ERR_READISOBUFF%3B%0A%20%20%20%7D%0A%0A%20%20%20ContinueStream%20%3D%20TRUE%3B%0A%20%20%7D%0A%0A%20%7D%0A%0A%20return(Status)%3B%0A%0A%23endif%0A%0A%7D%0A%0A%0A%2F*%0A%2F%2F-----------------------------------------------------------------------------%0A%2F%2F%20GetDeviceHandle()%0A%2F%2F%0A%2F%2F%20Parameters%3A%0A%2F%2F%20%20%20%20%20%20%20%20guidDeviceInterface%3A%20DEVICE%20GUID%20defined%20in%20WinUSB%20inf%20file%0A%2F%2F%20%20%20%20%20%20%20%20hDeviceHandle%20%20%20%3A%20device%20handle%20returned%0A%2F%2F%0A%2F%2F%20Return%20Values%3A%0A%2F%2F%20%20%20%20%20%20%20%20true%20%3A%20success%0A%2F%2F%20%20%20%20%20%20%20%20false%3A%20fail%0A%2F%2F%0A%2F%2F%20Remarks%3A%0A%2F%2F%20%20%20%20%20%20%20%20Function%20to%20create%20file%20handle%20for%20USB%20device%0A%2F%2F-----------------------------------------------------------------------------%0A*%2F%0A%0ABOOL%20CUsbPCECGHelper%3A%3AGetDeviceHandle(GUID%20guidDeviceInterface%2C%20PHANDLE%20hDeviceHandle)%0A%7B%0A%20char%20s%5B256%5D%3B%0A%0A%23if(1)%0A%20HRESULT%20%20%20%20%20%20%20%20result%3B%0A%20HDEVINFO%20%20%20%20%20%20%20deviceInfo%3B%0A%20SP_DEVINFO_DATA%20%20%20%20%20%20deviceInfoData%3B%0A%20SP_DEVICE_INTERFACE_DATA%20%20%20deviceInterfaceData%3B%0A%20SP_DRVINFO_DATA_A%20%20%20%20%20DriverInfo%3B%0A%20PSP_DEVICE_INTERFACE_DETAIL_DATA%20interfaceDetailData%3B%0A%20ULONG%20%20%20%20%20%20%20%20requiredLength%3B%0A%20LPTSTR%20%20%20%20%20%20%20%20devicePath%3B%0A%20size_t%20%20%20%20%20%20%20%20length%3B%0A%20BOOL%20%20%20%20%20%20%20%20ret%20%3D%20FALSE%3B%0A%0A%20result%20%3D%20S_OK%3B%0A%20interfaceDetailData%20%3D%20NULL%3B%0A%20requiredLength%20%3D%200%3B%0A%20devicePath%20%3D%20NULL%3B%0A%0A%20deviceInfo%20%3D%20SetupDiGetClassDevs(%0A%20%20%26amp%3BguidDeviceInterface%2C%0A%20%20NULL%2C%0A%20%20NULL%2C%20%0A%20%20DIGCF_PRESENT%20%7C%20DIGCF_DEVICEINTERFACE%0A%20)%3B%0A%0A%20if%20(deviceInfo%20%3D%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20result%20%3D%20E_HANDLE%3B%0A%20%7D%0A%0A%20if%20(SUCCEEDED(result))%0A%20%7B%0A%20%20%2F%2F%20Check%20that%20a%20query%20for%20a%20second%20interface%20fails%2C%20but%20that%20the%0A%20%20%2F%2F%20first%20interface%20succeeds%0A%20%20deviceInfoData.cbSize%20%3D%20sizeof(SP_DEVINFO_DATA)%3B%0A%20%20if%20(%20%20!SetupDiEnumDeviceInfo(deviceInfo%2C%201%2C%20%26amp%3BdeviceInfoData)%20%0A%20%20%20%26amp%3B%26amp%3B%20SetupDiEnumDeviceInfo(deviceInfo%2C%200%2C%20%26amp%3BdeviceInfoData))%0A%20%20%7B%0A%0A%20%20%20%2F%2F%20Get%20the%20specific%20device%20interface%0A%20%20%20deviceInterfaceData.cbSize%20%3D%20sizeof(SP_INTERFACE_DEVICE_DATA)%3B%0A%20%20%20if%20(!SetupDiEnumDeviceInterfaces(deviceInfo%2C%20%26amp%3BdeviceInfoData%2C%26amp%3BguidDeviceInterface%2C%200%2C%20%26amp%3BdeviceInterfaceData)%20)%0A%20%20%20%7B%0A%20%20%20%20result%20%3D%20HRESULT_FROM_WIN32(GetLastError())%3B%0A%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20SetupDiEnumDeviceInterfaces%20failed%20%25d.%5Cn%22%2C%20result)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20%20%7D%0A%0A%20%20%20%2F%2F%20Check%20the%20size%20needed%20for%20the%20device%20interface%20details%20and%20%0A%20%20%20%2F%2F%20allocate%20the%20data%20needed%20to%20get%20the%20details%0A%20%20%20if%20(%20%20%20SUCCEEDED(result)%20%0A%20%20%20%20%26amp%3B%26amp%3B%20!SetupDiGetDeviceInterfaceDetail(deviceInfo%2C%26amp%3BdeviceInterfaceData%2C%20NULL%2C%200%2C%20%26amp%3BrequiredLength%2C%20NULL))%0A%20%20%20%7B%0A%20%20%20%20if%20%20%20%20%20(GetLastError()%20%3D%3D%20ERROR_INSUFFICIENT_BUFFER%20%0A%20%20%20%20%20%26amp%3B%26amp%3B%20requiredLength%20%26gt%3B%200)%0A%20%20%20%20%7B%0A%20%20%20%20%20interfaceDetailData%20%3D(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR%2C%20(SIZE_T)requiredLength)%3B%0A%20%20%20%20%20if%20(interfaceDetailData%20%3D%3D%20NULL)%0A%20%20%20%20%20%7B%0A%20%20%20%20%20%20result%20%3D%20E_OUTOFMEMORY%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%20else%0A%20%20%20%20%20%7B%0A%20%20%20%20%20%20result%20%3D%20S_OK%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20result%20%3D%20HRESULT_FROM_WIN32(GetLastError())%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20%2F%2F%20Get%20the%20device%20interface%20details%0A%20%20%20if%20(SUCCEEDED(result)%20%26amp%3B%26amp%3B%20interfaceDetailData%20!%3D%20NULL)%0A%20%20%20%7B%0A%20%20%20%20interfaceDetailData-%26gt%3BcbSize%20%3D%20sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)%3B%0A%20%20%20%20if%20(!SetupDiGetDeviceInterfaceDetail(deviceInfo%2C%26amp%3BdeviceInterfaceData%2C%20interfaceDetailData%2CrequiredLength%2C%20NULL%2C%20%26amp%3BdeviceInfoData))%0A%20%20%20%20%7B%0A%20%20%20%20%20result%20%3D%20HRESULT_FROM_WIN32(GetLastError())%3B%0A%0A%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20SetupDiGetDeviceInterfaceDetail%20failed%20%25d.%5Cn%22%2C%20result)%3B%0A%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20if%20(SUCCEEDED(result)%20%26amp%3B%26amp%3B%20interfaceDetailData%20!%3D%20NULL)%0A%20%20%20%7B%0A%20%20%20%20%2F%2F%20Build%20the%20null%20terminated%20device%20path%20for%20the%20device%0A%20%20%20%20length%20%3D%20_tcslen(interfaceDetailData-%26gt%3BDevicePath)%20%2B%201%3B%0A%20%20%20%20devicePath%20%3D%20(TCHAR*)LocalAlloc(LPTR%2C%20length%20*%20sizeof(TCHAR))%3B%0A%20%20%20%20if%20(devicePath%20!%3D%20NULL)%0A%20%20%20%20%7B%0A%20%20%20%20%20StringCchCopy(devicePath%2C%20length%2CinterfaceDetailData-%26gt%3BDevicePath)%3B%0A%20%20%20%20%20devicePath%5Blength%20-%201%5D%20%3D%200%3B%0A%0A%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Device%20path%3A%20%20%25s%5Cn%22%2C%20devicePath)%3B%0A%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%2F%2FThis%20what%20i%20get%20on%20Windows%2010%20as%20output%3A%0A%20%20%20%20%20%2F%2F%20nvUSB.lib%3A%20Device%20path%3A%20%20%5C%5C%3F%5Cusb%23vid_10c4%26amp%3Bpid_825f%237%26amp%3B1b060a7f%26amp%3B0%26amp%3B3%23%7B93bd88a4-eb10-4706-8304-c512f18b8e42%7D%0A%0A%20%20%20%20%20%2F%2F------------------%20Get%20winusb%20driver%20version%20-----------------------------------------------------------%0A%20%20%20%20%20if%20(!SetupDiBuildDriverInfoList(deviceInfo%2C%20%26amp%3BdeviceInfoData%2C%20SPDIT_COMPATDRIVER))%0A%20%20%20%20%20%7B%0A%20%20%20%20%20%20result%20%3D%20HRESULT_FROM_WIN32(GetLastError())%3B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20%20SetupDiBuildDriverInfoList%20failed%20%25d.%5Cn%22%2C%20result)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%7D%0A%20%20%20%20%20else%0A%20%20%20%20%20%7B%0A%20%20%20%20%20%20DriverInfo.cbSize%20%3D%20sizeof(SP_DRVINFO_DATA_A)%3B%0A%20%20%20%20%20%20if%20((SetupDiEnumDriverInfoA(deviceInfo%2C%20%26amp%3BdeviceInfoData%2C%20SPDIT_COMPATDRIVER%2C%200%2C%20%26amp%3BDriverInfo)))%0A%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20SetupDiEnumDriverInfoA%20%5Cn%22)%3B%0A%20%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20winusb%20driver%20version%20%25s%20v.%25u.%25u.%25u.%25u%5Cn%22%2C%0A%20%20%20%20%20%20%20%20DriverInfo.Description%2C%0A%20%20%20%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2048)%20%26amp%3B%200xFFFF%2C%0A%20%20%20%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2032)%20%26amp%3B%200xFFFF%2C%0A%20%20%20%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2016)%20%26amp%3B%200xFFFF%2C%0A%20%20%20%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%200)%20%26amp%3B%200xFFFF%0A%0A%20%20%20%20%20%20%20)%3B%0A%20%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20%20drvver.MajorVersion%20%3D%20(WORD)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2048)%20%26amp%3B%200xFFFF%3B%0A%20%20%20%20%20%20%20drvver.MinorVersion%20%3D%20(WORD)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2032)%20%26amp%3B%200xFFFF%3B%0A%20%20%20%20%20%20%20drvver.BuildVersion%20%3D%20(WORD)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2016)%20%26amp%3B%200xFFFF%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20else%0A%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20result%20%3D%20HRESULT_FROM_WIN32(GetLastError())%3B%0A%0A%20%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20SetupDiEnumDriverInfoA%20failed%20%25d.%5Cn%22%2C%20result)%3B%0A%20%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%7D%0A%20%20%20%20%20%2F%2F-------------------------------------------------------------------------------------------------------------%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20result%20%3D%20E_OUTOFMEMORY%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%7D%0A%20%7D%0A%0A%20if%20(SUCCEEDED(result)%20%26amp%3B%26amp%3B%20devicePath%20!%3D%20NULL)%0A%20%7B%0A%20%20ret%20%3D%20TRUE%3B%0A%0A%20%20%2F%2F%20Open%20the%20device%20handle%0A%20%20*hDeviceHandle%20%3D%20CreateFile(%0A%20%20%20devicePath%2C%20%0A%20%20%20GENERIC_READ%20%7C%20GENERIC_WRITE%2C%0A%20%20%20FILE_SHARE_READ%20%7C%20FILE_SHARE_WRITE%2C%20NULL%2C%0A%20%20%20OPEN_EXISTING%2C%20%0A%20%20%20FILE_FLAG_OVERLAPPED%2C%20%0A%20%20%20NULL%0A%20%20)%3B%0A%20%20if%20(*hDeviceHandle%20%3D%3D%20INVALID_HANDLE_VALUE)%0A%20%20%7B%0A%20%20%20result%20%3D%20HRESULT_FROM_WIN32(GetLastError())%3B%0A%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20CreateFile%20failed%20%25d.%5Cn%22%2C%20result)%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20ret%20%3D%20FALSE%3B%0A%20%20%7D%0A%20%7D%0A%0A%20%2F%2F%20Perform%20cleanup%20of%20the%20allocated%20data%0A%20if%20(devicePath%20!%3D%20NULL)%0A%20%7B%0A%20%20LocalFree(devicePath)%3B%0A%20%7D%0A%20if%20(interfaceDetailData%20!%3D%20NULL)%0A%20%7B%0A%20%20LocalFree(interfaceDetailData)%3B%0A%20%7D%0A%20if%20(deviceInfo%20!%3D%20INVALID_HANDLE_VALUE)%0A%20%7B%0A%20%20(void)SetupDiDestroyDeviceInfoList(deviceInfo)%3B%0A%20%7D%0A%0A%20%0A%20return%20ret%3B%0A%0A%23endif%0A%0A%23if(0)%0A%20%0A%20BOOL%20bResult%20%3D%20TRUE%3B%0A%20HDEVINFO%20hDeviceInfo%3B%0A%20SP_DEVINFO_DATA%20DeviceInfoData%3B%0A%20SP_DRVINFO_DATA_A%20DriverInfo%3B%0A%20DriverInfo.cbSize%20%3D%20sizeof(SP_DRVINFO_DATA_A)%3B%0A%0A%20SP_DEVICE_INTERFACE_DATA%20deviceInterfaceData%3B%0A%20PSP_DEVICE_INTERFACE_DETAIL_DATA%20pInterfaceDetailData%20%3D%20NULL%3B%0A%0A%20ULONG%20requiredLength%20%3D%200%3B%0A%0A%20LPTSTR%20lpDevicePath%20%3D%20NULL%3B%0A%0A%20DWORD%20index%20%3D%200%3B%0A%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Enter%20to%20GetDeviceHandle%5Cn%22)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0A%0A%2F%2F%20if%20(guidDeviceInterface%20%3D%3D%20GUID_NULL)%20%7B%0A%2F%2F%20%20return%20FALSE%3B%0A%2F%2F%20%7D%0A%0A%0A%20%2F%2F%20Get%20information%20about%20all%20the%20installed%20devices%20for%20the%20specified%0A%20%2F%2F%20device%20interface%20class.%0A%20hDeviceInfo%20%3D%20SetupDiGetClassDevs(%0A%20%20%26amp%3BguidDeviceInterface%2C%0A%20%20NULL%2C%0A%20%20NULL%2C%0A%20%20DIGCF_PRESENT%20%7C%20DIGCF_DEVICEINTERFACE)%3B%0A%0A%20if%20(hDeviceInfo%20%3D%3D%20INVALID_HANDLE_VALUE)%20%7B%0A%20%20%2F%2F%20ERROR%20%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Error%20SetupDiGetClassDevs%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20bResult%20%3D%20FALSE%3B%0A%20%20goto%20done%3B%0A%20%7D%0A%0A%20%2F%2FEnumerate%20all%20the%20device%20interfaces%20in%20the%20device%20information%20set.%0A%20DeviceInfoData.cbSize%20%3D%20sizeof(SP_DEVINFO_DATA)%3B%0A%0A%0A%0A%20for%20(index%20%3D%200%3B%20SetupDiEnumDeviceInfo(hDeviceInfo%2C%20index%2C%20%26amp%3BDeviceInfoData)%3B%20index%2B%2B)%20%7B%0A%20%20%0A%20%20%2F%2FReset%20for%20this%20iteration%0A%20%20if%20(lpDevicePath)%20%0A%20%20%7B%0A%20%20%20LocalFree(lpDevicePath)%3B%0A%20%20%20lpDevicePath%20%3D%20NULL%3B%0A%20%20%7D%0A%0A%20%20if%20(pInterfaceDetailData)%20%0A%20%20%7B%0A%20%20%20LocalFree(pInterfaceDetailData)%3B%0A%20%20%20pInterfaceDetailData%20%3D%20NULL%3B%0A%20%20%7D%0A%0A%20%20%2F%2F%20Check%20if%20last%20item%0A%20%20if%20(GetLastError()%20%3D%3D%20ERROR_NO_MORE_ITEMS)%20%0A%20%20%7B%0A%20%20%20break%3B%0A%20%20%7D%0A%0A%20%20deviceInterfaceData.cbSize%20%3D%20sizeof(SP_INTERFACE_DEVICE_DATA)%3B%0A%0A%20%20%2F%2FGet%20information%20about%20the%20device%20interface.%0A%20%20bResult%20%3D%20SetupDiEnumDeviceInterfaces(%0A%20%20%20hDeviceInfo%2C%0A%20%20%20%26amp%3BDeviceInfoData%2C%0A%20%20%20%26amp%3BguidDeviceInterface%2C%0A%20%20%20index%2C%0A%20%20%20%26amp%3BdeviceInterfaceData)%3B%0A%0A%20%20bResult%20%3D%20SetupDiEnumDeviceInterfaces(%0A%20%20%20hDeviceInfo%2C%0A%20%20%20%26amp%3BDeviceInfoData%2C%0A%20%20%20%26amp%3BguidDeviceInterface%2C%0A%20%20%20index%2C%0A%20%20%20%26amp%3BdeviceInterfaceData)%3B%0A%0A%0A%20%20%2F%2F%20Check%20if%20last%20item%0A%20%20if%20(GetLastError()%20%3D%3D%20ERROR_NO_MORE_ITEMS)%20%0A%20%20%7B%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20SetupDiEnumDeviceInterfaces%20ERROR_NO_MORE_ITEMS%20(%25d)%20%5Cn%22%2C%20index)%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20break%3B%0A%20%20%7D%0A%0A%20%20%2F%2FCheck%20for%20some%20other%20error%0A%20%20if%20(!bResult)%20%7B%0A%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Error%20SetupDiEnumDeviceInterfaces%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20bResult%20%3D%20FALSE%3B%0A%20%20%20goto%20done%3B%0A%20%20%7D%0A%0A%20%20%2F%2FInterface%20data%20is%20returned%20in%20SP_DEVICE_INTERFACE_DETAIL_DATA%0A%20%20%2F%2Fwhich%20we%20need%20to%20allocate%2C%20so%20we%20have%20to%20call%20this%20function%20twice.%0A%20%20%2F%2FFirst%20to%20get%20the%20size%20so%20that%20we%20know%20how%20much%20to%20allocate%0A%20%20%2F%2FSecond%2C%20the%20actual%20call%20with%20the%20allocated%20buffer%0A%0A%20%20bResult%20%3D%20SetupDiGetDeviceInterfaceDetail(%0A%20%20%20hDeviceInfo%2C%0A%20%20%20%26amp%3BdeviceInterfaceData%2C%0A%20%20%20NULL%2C%200%2C%0A%20%20%20%26amp%3BrequiredLength%2C%0A%20%20%20NULL)%3B%0A%0A%0A%20%20%2F%2FCheck%20for%20some%20other%20error%0A%20%20if%20(!bResult)%20%7B%0A%20%20%20if%20((ERROR_INSUFFICIENT_BUFFER%20%3D%3D%20GetLastError())%20%26amp%3B%26amp%3B%20(requiredLength%20%26gt%3B%200))%20%7B%0A%20%20%20%20%2F%2Fwe%20got%20the%20size%2C%20allocate%20buffer%0A%20%20%20%20pInterfaceDetailData%20%3D%20(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR%2C%20requiredLength)%3B%0A%0A%20%20%20%20if%20(!pInterfaceDetailData)%20%7B%0A%20%20%20%20%20%2F%2F%20ERROR%20%0A%20%20%20%20%20%2F%2Fprintf(%22Error%20allocating%20memory%20for%20the%20device%20detail%20buffer.%5Cn%22)%3B%0A%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Error%20allocating%20memory%20for%20the%20device%20detail%20buffer.%5Cn%22)%3B%0A%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20bResult%20%3D%20FALSE%3B%0A%20%20%20%20%20goto%20done%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20else%20%7B%0A%20%20%20%20%2F%2Fprintf(%22Error%20SetupDiEnumDeviceInterfaces%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Error%20SetupDiEnumDeviceInterfaces%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20bResult%20%3D%20FALSE%3B%0A%20%20%20%20goto%20done%3B%0A%20%20%20%7D%0A%20%20%7D%0A%0A%20%20%2F%2Fget%20the%20interface%20detailed%20data%0A%20%20pInterfaceDetailData-%26gt%3BcbSize%20%3D%20sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)%3B%0A%0A%20%20%2F%2FNow%20call%20it%20with%20the%20correct%20size%20and%20allocated%20buffer%0A%20%20bResult%20%3D%20SetupDiGetDeviceInterfaceDetail(%0A%20%20%20hDeviceInfo%2C%0A%20%20%20%26amp%3BdeviceInterfaceData%2C%0A%20%20%20pInterfaceDetailData%2C%0A%20%20%20requiredLength%2C%0A%20%20%20NULL%2C%0A%20%20%20%26amp%3BDeviceInfoData)%3B%0A%0A%0A%20%20%2F%2FCheck%20for%20some%20other%20error%0A%20%20if%20(!bResult)%20%7B%0A%20%20%20%2F%2Fprintf(%22Error%20SetupDiGetDeviceInterfaceDetail%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Error%20SetupDiGetDeviceInterfaceDetail%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20bResult%20%3D%20FALSE%3B%0A%20%20%20goto%20done%3B%0A%20%20%7D%0A%0A%20%20if%20(!SetupDiBuildDriverInfoList(hDeviceInfo%2C%20%26amp%3BDeviceInfoData%2C%20SPDIT_COMPATDRIVER))%0A%20%20%7B%0A%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Error%20SetupDiBuildDriverInfoList%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%7D%0A%20%20else%0A%20%20%7B%0A%20%20%20if%20((SetupDiEnumDriverInfoA(hDeviceInfo%2C%20%26amp%3BDeviceInfoData%2C%20SPDIT_COMPATDRIVER%2C%20index%2C%20%26amp%3BDriverInfo))%20!%3D%20FALSE)%0A%20%20%20%7B%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20SetupDiEnumDriverInfoA%20%5Cn%22)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20winusb%20driver%20version%20%25s%20v.%25u.%25u.%25u.%25u%5Cn%22%2C%0A%20%20%20%20%20DriverInfo.Description%2C%0A%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2048)%20%26amp%3B%200xFFFF%2C%0A%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2032)%20%26amp%3B%200xFFFF%2C%0A%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2016)%20%26amp%3B%200xFFFF%2C%0A%20%20%20%20%20(DWORD32)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%200)%20%26amp%3B%200xFFFF%0A%0A%20%20%20%20)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20drvver.MajorVersion%20%3D%20(WORD)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2048)%20%26amp%3B%200xFFFF%3B%0A%20%20%20%20drvver.MinorVersion%20%3D%20(WORD)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2032)%20%26amp%3B%200xFFFF%3B%0A%20%20%20%20drvver.BuildVersion%20%3D%20(WORD)(DriverInfo.DriverVersion%20%26gt%3B%26gt%3B%2016)%20%26amp%3B%200xFFFF%3B%0A%0A%20%20%20%20%2F%2Fcopy%20device%20path%0A%20%20%20%20size_t%20nLength%20%3D%20_tcslen(pInterfaceDetailData-%26gt%3BDevicePath)%20%2B%201%3B%0A%20%20%20%20lpDevicePath%20%3D%20(TCHAR*)LocalAlloc(LPTR%2C%20nLength%20*%20sizeof(TCHAR))%3B%0A%20%20%20%20StringCchCopy(lpDevicePath%2C%20nLength%2C%20pInterfaceDetailData-%26gt%3BDevicePath)%3B%0A%20%20%20%20lpDevicePath%5BnLength%20-%201%5D%20%3D%200%3B%0A%0A%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Device%20path%3A%20%20%25s%5Cn%22%2C%20lpDevicePath)%3B%0A%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20%20%20%0A%20%20%20%20%2F%2FThis%20what%20i%20get%20on%20Windows%2010%20as%20output%3A%0A%20%20%20%20%2F%2F%20nvUSB.lib%3A%20Device%20path%3A%20%20%5C%5C%3F%5Cusb%23vid_10c4%26amp%3Bpid_825f%237%26amp%3B1b060a7f%26amp%3B0%26amp%3B3%23%7B93bd88a4-eb10-4706-8304-c512f18b8e42%7D%0A%0A%0A%20%20%20%20break%3B%20%2F%2Fconnect%20to%20to%20only%20one%20device%0A%20%20%20%7D%0A%20%20%7D%0A%0A%20%7D%2F%2Ffor%20(index%20%3D%200%3B%20SetupDiEnumDeviceInfo(hDeviceInfo%2C%20index%2C%20%26amp%3BDeviceInfoData)%3B%20index%2B%2B)%0A%0A%20if%20(!lpDevicePath)%20%7B%0A%20%20%2F%2FError.%0A%20%20%2F%2Fprintf(%22Error%20%25d.%22%2C%20GetLastError())%3B%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20lpDevicePath%20Error%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20bResult%20%3D%20FALSE%3B%0A%20%20goto%20done%3B%0A%20%7D%0A%0A%20%2F%2FOpen%20the%20device%0A%20*hDeviceHandle%20%3D%20CreateFile(%0A%20%20lpDevicePath%2C%0A%20%20GENERIC_READ%20%7C%20GENERIC_WRITE%2C%0A%20%20FILE_SHARE_READ%20%7C%20FILE_SHARE_WRITE%2C%0A%20%20NULL%2C%0A%20%20OPEN_EXISTING%2C%0A%20%20FILE_FLAG_OVERLAPPED%2C%0A%20%20NULL)%3B%0A%0A%20if%20(*hDeviceHandle%20%3D%3D%20INVALID_HANDLE_VALUE)%20%7B%0A%20%20%2F%2FError.%0A%20%20%2F%2Fprintf(%22Error%20%25d.%22%2C%20GetLastError())%3B%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20CreateFile%20Error%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20bResult%20%3D%20FALSE%3B%0A%20%20goto%20done%3B%0A%20%7D%0A%0A%0A%0Adone%3A%0A%0A%20if%20(lpDevicePath)%20%7B%0A%20%20LocalFree(lpDevicePath)%3B%0A%20%7D%0A%0A%20if%20(pInterfaceDetailData)%20%7B%0A%20%20LocalFree(pInterfaceDetailData)%3B%0A%20%7D%0A%0A%0A%20if%20(!bResult)%0A%20%7B%0A%20%20if%20(hDeviceInfo%20!%3D%20INVALID_HANDLE_VALUE)%0A%20%20%20SetupDiDestroyDeviceInfoList(hDeviceInfo)%3B%0A%20%7D%0A%20else%0A%20%7B%0A%20%20if%20(hDeviceInfo%20!%3D%20INVALID_HANDLE_VALUE)%0A%20%20%20bResult%20%3D%20SetupDiDestroyDeviceInfoList(hDeviceInfo)%3B%0A%20%7D%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Exit%20from%20GetDeviceHandle%5Cn%22)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20return%20bResult%3B%0A%0A%23endif%0A%0A%7D%20%2F%2F%20End%20of%20GetDeviceHandle()%0A%0A%0A%2F*%0A%2F%2F-----------------------------------------------------------------------------%0A%2F%2F%20GetWinUSBHandle()%0A%2F%2F%0A%2F%2F%20Parameters%3A%0A%2F%2F%20%20%20%20%20%20%20%20hDeviceHandle%20%20%3A%20device%20handle%20created%20for%20the%20USB%20device%0A%2F%2F%20%20%20%20%20%20%20%20phWinUSBHandle%20%3A%20WinUSB%20Interface%20handle%20returned%0A%2F%2F%0A%2F%2F%20Return%20Values%3A%0A%2F%2F%20%20%20%20%20%20%20%20true%20%3A%20success%0A%2F%2F%20%20%20%20%20%20%20%20false%3A%20fail%0A%2F%2F%0A%2F%2F%20Remarks%3A%0A%2F%2F%20%20%20%20%20%20%20%20Function%20to%20get%20WinUSB%20Interface%20Handle%20for%20the%20device%0A%2F%2F-----------------------------------------------------------------------------%0A*%2F%0A%0ABOOL%20CUsbPCECGHelper%3A%3AGetWinUSBHandle(HANDLE%20hDeviceHandle%2C%20PWINUSB_INTERFACE_HANDLE%20phWinUSBHandle)%0A%7B%0A%20char%20s%5B256%5D%3B%0A%20BOOL%20bResult%20%3D%20FALSE%3B%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Enter%20to%20GetWinUSBHandle%5Cn%22)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20if%20(hDeviceHandle%20%3D%3D%20INVALID_HANDLE_VALUE)%20%0A%20%7B%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Exit%20from%20GetWinUSBHandle%20(hDeviceHandle%20not%20valid)%20%5Cn%22)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20return%20FALSE%3B%0A%20%7D%0A%0A%20%2F*%0A%20%5Bin%5D%20DeviceHandle%0A%20The%20handle%20to%20the%20device%20that%20CreateFile%20returned.WinUSB%20uses%20overlapped%20I%20%2F%20O%2C%20so%20FILE_FLAG_OVERLAPPED%20must%20be%20specified%20in%20%0A%20the%20dwFlagsAndAttributes%20parameter%20of%20CreateFile%20call%20for%20DeviceHandle%20to%20have%20the%20characteristics%20necessary%20for%20%0A%20WinUsb_Initialize%20to%20function%20properly.%0A%0A%20%5Bout%5D%20InterfaceHandle%0A%20Receives%20an%20opaque%20handle%20to%20the%20first(default)%20interface%20on%20the%20device.This%20handle%20is%20required%20by%20other%20WinUSB%20routines%20that%20%0A%20perform%20operations%20on%20the%20default%20interface.To%20release%20the%20handle%2C%20call%20the%20WinUSB_Free%20function.%0A%0A%20WinUsb_Initialize%20returns%20TRUE%20if%20the%20operation%20succeeds.%20Otherwise%2C%20this%20routine%20returns%20FALSE%2C%20and%20the%20caller%20can%20retrieve%20the%20logged%20%0A%20error%20by%20calling%20GetLastError.%0A%20*%2F%0A%0A%20bResult%20%3D%20WinUsb_Initialize(hDeviceHandle%2C%20phWinUSBHandle)%3B%0A%20if%20(!bResult)%20%0A%20%7B%0A%20%20%2F%2FError.%0A%20%20%2F%2Fprintf(%22WinUsb_Initialize%20Error%20%25d.%22%2C%20GetLastError())%3B%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20WinUsb_Initialize%20Error%20%25d.%22%2C%20GetLastError())%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%20%20return%20FALSE%3B%0A%20%7D%0A%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Exit%20from%20GetWinUSBHandle%20%5Cn%22)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20return%20bResult%3B%0A%7D%20%2F%2F%20End%20of%20GetWinUSBHandle()%0A%0A%0A%0A%2F*%0A%2F%2F-----------------------------------------------------------------------------%0A%2F%2F%20GetUSBDeviceSpeed()%0A%2F%2F%0A%2F%2F%20Parameters%3A%0A%2F%2F%20%20%20%20%20%20%20%20hDeviceHandle%20%20%3A%20WinUSB%20Interface%20Handle%0A%2F%2F%20%20%20%20%20%20%20%20pDeviceSpeed%20%20%20%3A%20Device%20Speed%20returned%0A%2F%2F%0A%2F%2F%20Return%20Values%3A%0A%2F%2F%20%20%20%20%20%20%20%20true%20%3A%20success%0A%2F%2F%20%20%20%20%20%20%20%20false%3A%20fail%0A%2F%2F%0A%2F%2F%20Remarks%3A%0A%2F%2F%20%20%20%20%20%20%20%20Function%20to%20get%20device%20speed%0A%2F%2F-----------------------------------------------------------------------------%0A*%2F%0A%0ABOOL%20CUsbPCECGHelper%3A%3AGetUSBDeviceSpeed(WINUSB_INTERFACE_HANDLE%20hDeviceHandle%2C%20UCHAR*%20pDeviceSpeed)%0A%7B%0A%20char%20s%5B256%5D%3B%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Enter%20to%20GetUSBDeviceSpeed()%20%5Cn%22)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20if%20(!pDeviceSpeed%20%7C%7C%20hDeviceHandle%20%3D%3D%20INVALID_HANDLE_VALUE)%20%7B%0A%20%20return%20FALSE%3B%0A%20%7D%0A%0A%20BOOL%20bResult%20%3D%20TRUE%3B%0A%0A%20ULONG%20length%20%3D%20sizeof(UCHAR)%3B%0A%0A%20bResult%20%3D%20WinUsb_QueryDeviceInformation(hDeviceHandle%2C%20DEVICE_SPEED%2C%20%26amp%3Blength%2C%20pDeviceSpeed)%3B%0A%20if%20(!bResult)%20%7B%0A%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Error%20getting%20device%20speed%3A%20%25d.%5Cn%22%2C%20GetLastError())%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20goto%20done%3B%0A%20%7D%0A%0A%20%2F*%0A%20if%20(*pDeviceSpeed%20%3D%3D%20LowSpeed)%20%7B%0A%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Device%20speed%3A%20%25d%20(Low%20speed).%5Cn%22%2C%20*pDeviceSpeed)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20goto%20done%3B%0A%20%7D%0A%0A%20if%20(*pDeviceSpeed%20%3D%3D%20FullSpeed)%20%7B%0A%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Device%20speed%3A%20%25d%20(Full%20speed).%5Cn%22%2C%20*pDeviceSpeed)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20goto%20done%3B%0A%20%7D%0A%20*%2F%0A%0A%20if%20(*pDeviceSpeed%20%3D%3D%201)%20%7B%0A%0A%20%20%2F%2F---!!%20printf(%22Device%20speed%3A%20%25d%20-%20Full%20speed%20or%20lower%20(initial%20documentation%20on%20MSDN%20was%20wrong).%5Cn%22%2C%20*pDeviceSpeed)%3B%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Device%20speed%3A%20%25d%20(Full%20speed%20or%20lower).%5Cn%22%2C%20*pDeviceSpeed)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20goto%20done%3B%0A%20%7D%0A%0A%20if%20(*pDeviceSpeed%20%3D%3D%20HighSpeed)%20%7B%0A%0A%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Device%20speed%3A%20%25d%20(High%20speed).%5Cn%22%2C%20*pDeviceSpeed)%3B%0A%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20goto%20done%3B%0A%20%7D%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Exit%20from%20GetUSBDeviceSpeed()%20%5Cn%22)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0Adone%3A%0A%20return%20bResult%3B%0A%7D%20%2F%2F%20End%20of%20GetUSBDeviceSpeed()%0A%0A%0A%0A%2F*%0A%2F%2F-----------------------------------------------------------------------------%0A%2F%2F%20QueryDeviceEndpoints()%0A%2F%2F%0A%2F%2F%20Parameters%3A%0A%2F%2F%20%20%20%20%20%20%20%20hDeviceHandle%20%20%3A%20WinUSB%20Interface%20Handle%0A%2F%2F%20%20%20%20%20%20%20%20pipeid%20%20%20%3A%20Pipe%20ID%20returned%0A%2F%2F%0A%2F%2F%20Return%20Values%3A%0A%2F%2F%20%20%20%20%20%20%20%20true%20%3A%20success%0A%2F%2F%20%20%20%20%20%20%20%20false%3A%20fail%0A%2F%2F%0A%2F%2F%20Remarks%3A%0A%2F%2F%20%20%20%20%20%20%20%20Function%20to%20check%20end%20points%20and%20get%20pipe%20ID%0A%2F%2F-----------------------------------------------------------------------------%0A*%2F%0A%0ABOOL%20CUsbPCECGHelper%3A%3AQueryDeviceEndpoints(WINUSB_INTERFACE_HANDLE%20hDeviceHandle%2C%20PIPE_ID*%20pipeid)%0A%7B%0A%20char%20s%5B256%5D%3B%0A%0A%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Enter%20to%20QueryDeviceEndpoints()%20%5Cn%22)%3B%0A%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20if%20(hDeviceHandle%20%3D%3D%20INVALID_HANDLE_VALUE)%20%7B%0A%20%20return%20FALSE%3B%0A%20%7D%0A%0A%20BOOL%20bResult%20%3D%20TRUE%3B%0A%0A%20USB_INTERFACE_DESCRIPTOR%20InterfaceDescriptor%3B%0A%20ZeroMemory(%26amp%3BInterfaceDescriptor%2C%20sizeof(USB_INTERFACE_DESCRIPTOR))%3B%0A%0A%20WINUSB_PIPE_INFORMATION_EX%20Pipe%3B%20ZeroMemory(%26amp%3BPipe%2C%20sizeof(WINUSB_PIPE_INFORMATION_EX))%3B%0A%20%2F%2FWINUSB_PIPE_INFORMATION%20%20Pipe%3B%20%20ZeroMemory(%26amp%3BPipe%2C%20sizeof(WINUSB_PIPE_INFORMATION))%3B%0A%20%0A%20bResult%20%3D%20WinUsb_QueryInterfaceSettings(hDeviceHandle%2C%200%2C%20%26amp%3BInterfaceDescriptor)%3B%0A%0A%20if%20(bResult)%20%7B%0A%20%20for%20(int%20index%20%3D%200%3B%20index%20%26lt%3B%20InterfaceDescriptor.bNumEndpoints%3B%20index%2B%2B)%20%7B%0A%20%20%20bResult%20%3D%20WinUsb_QueryPipeEx(hDeviceHandle%2C%200%2C%20index%2C%20%26amp%3BPipe)%3B%0A%20%20%20%2F%2FbResult%20%3D%20WinUsb_QueryPipe(hDeviceHandle%2C%200%2C%20index%2C%20%26amp%3BPipe)%3B%0A%0A%20%20%20if%20(bResult)%20%7B%0A%20%20%20%20if%20(Pipe.PipeType%20%3D%3D%20UsbdPipeTypeControl)%20%7B%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Control%20IN%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20%0A%20%20%20%20%20%7D%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Control%20OUT%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20%0A%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(Pipe.PipeType%20%3D%3D%20UsbdPipeTypeIsochronous)%20%7B%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20%2F%2FPrintout%20for%20ECGUSB1D-EX%20%3A%0A%20%20%20%20%20%20%2F%2FnvUSB.lib%3A%20Endpoint%20index%3A%200%20Pipe%20type%3A%20Isochronous%20IN%20Pipe%20ID%3A%20129.%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Isochronous%20IN%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B0%5D.PipeType%20%3D%20Pipe.PipeType%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B0%5D.PipeId%20%3D%20Pipe.PipeId%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B0%5D.Interval%20%3D%20Pipe.Interval%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B0%5D.MaximumPacketSize%20%3D%20Pipe.MaximumPacketSize%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B0%5D.index%20%3D%20index%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B0%5D.MaximumBytesPerInterval%20%3D%20Pipe.MaximumBytesPerInterval%3B%0A%0A%20%20%20%20%20%20%2F%2FPrintout%20for%20ECGUSB1D-EX%20%3A%0A%20%20%20%20%20%20%2F%2FnvUSB.lib%3A%20Type%3D1%20%2C%20Interval%3D1%20%2C%20MaximumPacketSize%3D24%20%2CMaximumBytesPerInterval%3D24%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Type%3D%25d%20%2C%20Interval%3D%25d%20%2C%20MaximumPacketSize%3D%25d%20%2CMaximumBytesPerInterval%3D%25d%5Cn%22%2C%20%0A%20%20%20%20%20%20Pipe.PipeType%2C%0A%20%20%20%20%20%20Pipe.Interval%2C%0A%20%20%20%20%20%20Pipe.MaximumPacketSize%2C%0A%20%20%20%20%20%20Pipe.MaximumBytesPerInterval%0A%20%20%20%20%20%20)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20%2F*%0A%20%20%20%20%20%20MaximumPacketSize%0A%20%20%20%20%20%20The%20maximum%20size%2C%20in%20bytes%2C%20of%20the%20packets%20that%20are%20transmitted%20on%20the%20pipe.%0A%0A%20%20%20%20%20%20MaximumBytesPerInterval%0A%20%20%20%20%20%20The%20maximum%20number%20of%20bytes%20that%20can%20be%20transmitted%20in%20single%20interval.%20This%20value%20may%20be%20a%20larger%20than%20%0A%20%20%20%20%20%20the%20MaximumPacketSize%20value%20on%20high-bandwidth%2C%20high-speed%20periodic%20endpoints%20and%20SuperSpeed%20periodic%20endpoints%2C%20%0A%20%20%20%20%20%20such%20as%20isochronous%20endpoints.%0A%20%20%20%20%20%20*%2F%0A%0A%20%20%20%20%20%7D%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Isochronous%20OUT%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B1%5D.PipeType%20%3D%20Pipe.PipeType%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B1%5D.PipeId%20%3D%20Pipe.PipeId%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B1%5D.Interval%20%3D%20Pipe.Interval%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B1%5D.MaximumPacketSize%20%3D%20Pipe.MaximumPacketSize%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B1%5D.index%20%3D%20index%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BIso_Pipe%5B1%5D.MaximumBytesPerInterval%20%3D%20Pipe.MaximumBytesPerInterval%3B%0A%20%20%20%20%20%7D%0A%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(Pipe.PipeType%20%3D%3D%20UsbdPipeTypeBulk)%20%7B%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Bulk%20IN%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B0%5D.PipeType%20%3D%20Pipe.PipeType%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B0%5D.PipeId%20%3D%20Pipe.PipeId%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B0%5D.Interval%20%3D%20Pipe.Interval%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B0%5D.MaximumPacketSize%20%3D%20Pipe.MaximumPacketSize%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B0%5D.index%20%3D%20index%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B0%5D.MaximumBytesPerInterval%20%3D%20Pipe.MaximumBytesPerInterval%3B%0A%20%20%20%20%20%7D%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Bulk%20OUT%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B1%5D.PipeType%20%3D%20Pipe.PipeType%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B1%5D.PipeId%20%3D%20Pipe.PipeId%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B1%5D.Interval%20%3D%20Pipe.Interval%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B1%5D.MaximumPacketSize%20%3D%20Pipe.MaximumPacketSize%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B1%5D.index%20%3D%20index%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BBulk_Pipe%5B1%5D.MaximumBytesPerInterval%20%3D%20Pipe.MaximumBytesPerInterval%3B%0A%20%20%20%20%20%7D%0A%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(Pipe.PipeType%20%3D%3D%20UsbdPipeTypeInterrupt)%20%7B%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Int%20IN%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B0%5D.PipeType%20%3D%20Pipe.PipeType%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B0%5D.PipeId%20%3D%20Pipe.PipeId%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B0%5D.Interval%20%3D%20Pipe.Interval%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B0%5D.MaximumPacketSize%20%3D%20Pipe.MaximumPacketSize%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B0%5D.index%20%3D%20index%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B0%5D.MaximumBytesPerInterval%20%3D%20Pipe.MaximumBytesPerInterval%3B%0A%20%20%20%20%20%7D%0A%0A%20%20%20%20%20if%20(USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId))%20%7B%0A%0A%20%20%20%20%20%20sprintf_s(s%2C%20sizeof(s)%2C%20%22nvUSB.lib%3A%20Endpoint%20index%3A%20%25d%20Pipe%20type%3A%20Int%20OUT%20Pipe%20ID%3A%20%25d.%5Cn%22%2C%20index%2C%20%20Pipe.PipeId)%3B%0A%20%20%20%20%20%20OutputDebugString((LPCSTR)s)%3B%0A%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B1%5D.PipeType%20%3D%20Pipe.PipeType%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B1%5D.PipeId%20%3D%20Pipe.PipeId%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B1%5D.Interval%20%3D%20Pipe.Interval%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B1%5D.MaximumPacketSize%20%3D%20Pipe.MaximumPacketSize%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B1%5D.index%20%3D%20index%3B%0A%20%20%20%20%20%20pipeid-%26gt%3BInt_Pipe%5B1%5D.MaximumBytesPerInterval%20%3D%20Pipe.MaximumBytesPerInterval%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20else%20%7B%0A%20%20%20%20continue%3B%0A%20%20%20%7D%0A%20%20%7D%0A%20%7D%0A%0A%20%2F%2Fdone%3A%0A%20return%20bResult%3B%0A%7D%20%2F%2F%20End%20of%20QueryDeviceEndpoints()%0A%0A%0A%0APRING_BUFFER%0ACUsbPCECGHelper%3A%3AAllocRingBuffer(%0A%20SIZE_T%20%20%20%20Size%0A)%0A%7B%0A%20PRING_BUFFER%20%20%20ringBuffer%20%3D%20NULL%3B%0A%0A%0A%20ringBuffer%20%3D%20new%20RING_BUFFER%5Bsizeof(RING_BUFFER)%5D%3B%0A%0A%20if%20(!ringBuffer)%0A%20%20return%20NULL%3B%0A%0A%20ringBuffer-%26gt%3Bbuffer%20%3D%20new%20UCHAR%5BSize%5D%3B%0A%0A%20if%20(!ringBuffer-%26gt%3Bbuffer)%0A%20%7B%0A%20%20free(ringBuffer)%3B%0A%20%20return%20NULL%3B%0A%20%7D%0A%0A%0A%20ringBuffer-%26gt%3BSize%20%3D%20Size%3B%0A%20ringBuffer-%26gt%3BBase%20%3D%20ringBuffer-%26gt%3Bbuffer%3B%0A%20ringBuffer-%26gt%3BEnd%20%3D%20ringBuffer-%26gt%3Bbuffer%20%2B%20Size%3B%0A%20ringBuffer-%26gt%3BHead%20%3D%20ringBuffer-%26gt%3Bbuffer%3B%0A%20ringBuffer-%26gt%3BTail%20%3D%20ringBuffer-%26gt%3Bbuffer%3B%0A%0A%20ringBuffer-%26gt%3BinPtr%20%3D%20ringBuffer-%26gt%3Bbuffer%3B%0A%20ringBuffer-%26gt%3BoutPtr%20%3D%20ringBuffer-%26gt%3Bbuffer%3B%0A%20ringBuffer-%26gt%3BtotalSize%20%3D%20Size%3B%0A%20ringBuffer-%26gt%3BcurrentSize%20%3D%200%3B%0A%0A%2F%2F%20KeInitializeSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock)%3B%0A%0A%20return%20ringBuffer%3B%0A%7D%0A%0AVOID%0ACUsbPCECGHelper%3A%3AFreeRingBuffer(%0A%20PRING_BUFFER%20%20%20ringBuffer%0A)%0A%7B%0A%20free(ringBuffer-%26gt%3Bbuffer)%3B%0A%20free(ringBuffer)%3B%0A%7D%0A%0A%0AVOID%0ACUsbPCECGHelper%3A%3ARingBufferGetAvailableSpace(%0A%20PRING_BUFFER%20%20%20%20%20%20ringBuffer%2C%0A%20SIZE_T*%20AvailableSpace%0A)%0A%7B%0A%20PUCHAR%20headSnapshot%20%3D%20NULL%3B%0A%20PUCHAR%20tailSnapshot%20%3D%20NULL%3B%0A%20PUCHAR%20tailPlusOne%20%3D%20NULL%3B%0A%0A%20if%20(!AvailableSpace)%20%20%20return%3B%0A%20%2F%2F%20%20%20ASSERT(AvailableSpace)%3B%0A%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20Take%20a%20snapshot%20of%20the%20head%20and%20tail%20pointers.%20We%20will%20compute%20the%0A%20%20%20%20%2F%2F%20available%20space%20based%20on%20this%20snapshot.%20This%20is%20safe%20to%20do%20in%20a%0A%20%20%20%20%2F%2F%20single-producer%2C%20single-consumer%20model%2C%20because%20-%0A%20%20%20%20%2F%2F%20%20%20%20%20*%20A%20producer%20will%20call%20GetAvailableSpace()%20to%20determine%20whether%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20there%20is%20enough%20space%20to%20write%20the%20data%20it%20is%20trying%20to%20write.%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20The%20only%20other%20thread%20that%20could%20modify%20the%20amount%20of%20space%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20available%20is%20the%20consumer%20thread%2C%20which%20can%20only%20increase%20the%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20amount%20of%20space%20available.%20Hence%20it%20is%20safe%20for%20the%20producer%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20to%20write%20based%20on%20this%20snapshot.%0A%20%20%20%20%2F%2F%20%20%20%20%20*%20A%20consumer%20thread%20will%20call%20GetAvailableSpace()%20to%20determine%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20whether%20there%20is%20enough%20data%20in%20the%20buffer%20for%20it%20to%20read.%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20(Available%20data%20%3D%20Buffer%20size%20-%20Available%20space).%20The%20only%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20other%20thread%20that%20could%20modify%20the%20amount%20of%20space%20available%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20is%20the%20producer%20thread%2C%20which%20can%20only%20decrease%20the%20amount%20of%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20space%20available%20(thereby%20increasing%20the%20amount%20of%20data%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20available.%20Hence%20it%20is%20safe%20for%20the%20consumer%20to%20read%20based%20on%0A%20%20%20%20%2F%2F%20%20%20%20%20%20%20this%20snapshot.%0A%20%20%20%20%2F%2F%0A%20headSnapshot%20%3D%20ringBuffer-%26gt%3BHead%3B%0A%20tailSnapshot%20%3D%20ringBuffer-%26gt%3BTail%3B%0A%0A%20%2F%2F%0A%20%2F%2F%20In%20order%20to%20distinguish%20between%20a%20full%20buffer%20and%20an%20empty%20buffer%2C%0A%20%2F%2F%20we%20always%20leave%20the%20last%20byte%20of%20the%20buffer%20unused.%20So%2C%20an%20empty%0A%20%2F%2F%20buffer%20is%20denoted%20by%20-%0A%20%2F%2F%20%20%20%20%20%20tail%20%3D%3D%20head%0A%20%2F%2F%20...%20and%20a%20full%20buffer%20is%20denoted%20by%20-%0A%20%2F%2F%20%20%20%20%20%20(tail%2B1)%20%3D%3D%20head%0A%20%2F%2F%0A%20tailPlusOne%20%3D%20((tailSnapshot%20%2B%201)%20%3D%3D%20ringBuffer-%26gt%3BEnd)%20%3F%20ringBuffer-%26gt%3BBase%20%3A%20(tailSnapshot%20%2B%201)%3B%0A%0A%20if%20(tailPlusOne%20%3D%3D%20headSnapshot)%0A%20%7B%0A%20%20%2F%2F%0A%20%20%2F%2F%20Buffer%20full%0A%20%20%2F%2F%0A%20%20*AvailableSpace%20%3D%200%3B%0A%20%7D%0A%20else%20if%20(tailSnapshot%20%3D%3D%20headSnapshot)%0A%20%7B%0A%20%20%2F%2F%0A%20%20%2F%2F%20Buffer%20empty%0A%20%20%2F%2F%20The%20-1%20in%20the%20computation%20below%20is%20to%20account%20for%20the%20fact%20that%0A%20%20%2F%2F%20we%20always%20leave%20the%20last%20byte%20of%20the%20ring%20buffer%20unused%20in%20order%0A%20%20%2F%2F%20to%20distinguish%20between%20an%20empty%20buffer%20and%20a%20full%20buffer.%0A%20%20%2F%2F%0A%20%20*AvailableSpace%20%3D%20ringBuffer-%26gt%3BSize%20-%201%3B%0A%20%7D%0A%20else%0A%20%7B%0A%20%20if%20(tailSnapshot%20%26gt%3B%20headSnapshot)%0A%20%20%7B%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20Data%20has%20not%20wrapped%20around%20the%20end%20of%20the%20buffer%0A%20%20%20%2F%2F%20The%20-1%20in%20the%20computation%20below%20is%20to%20account%20for%20the%20fact%0A%20%20%20%2F%2F%20that%20we%20always%20leave%20the%20last%20byte%20of%20the%20ring%20buffer%20unused%0A%20%20%20%2F%2F%20in%20order%20to%20distinguish%20between%20an%20empty%20buffer%20and%20a%20full%0A%20%20%20%2F%2F%20buffer.%0A%20%20%20%2F%2F%0A%20%20%20*AvailableSpace%20%3D%20ringBuffer-%26gt%3BSize%20-%20(tailSnapshot%20-%20headSnapshot)%20-%201%3B%0A%20%20%7D%0A%20%20else%0A%20%20%7B%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20Data%20has%20wrapped%20around%20the%20end%20of%20the%20buffer%0A%20%20%20%2F%2F%20The%20-1%20in%20the%20computation%20below%20is%20to%20account%20for%20the%20fact%0A%20%20%20%2F%2F%20that%20we%20always%20leave%20the%20last%20byte%20of%20the%20ring%20buffer%20unused%0A%20%20%20%2F%2F%20in%20order%20to%20distinguish%20between%20an%20empty%20buffer%20and%20a%20full%0A%20%20%20%2F%2F%20buffer.%0A%20%20%20%2F%2F%0A%20%20%20*AvailableSpace%20%3D%20(headSnapshot%20-%20tailSnapshot)%20-%201%3B%0A%20%20%7D%0A%20%7D%0A%7D%0A%0A%0AVOID%0ACUsbPCECGHelper%3A%3ARingBufferGetAvailableData(%0A%20PRING_BUFFER%20%20%20%20%20%20ringBuffer%2C%0A%20SIZE_T*%20AvailableData%0A)%0A%7B%0A%20SIZE_T%20%20%20availableSpace%3B%0A%2F%2F%20KIRQL%20%20%20%20oldIrql%3B%0A%0A%20if%20(!AvailableData)%20%20%20return%3B%0A%20%2F%2FASSERT(AvailableData)%3B%0A%0A%2F%2F%20KeAcquireSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20%26amp%3BoldIrql)%3B%0A%20RingBufferGetAvailableSpace(ringBuffer%2C%20%26amp%3BavailableSpace)%3B%0A%2F%2F%20KeReleaseSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20oldIrql)%3B%0A%0A%20%2F%2F%0A%20%2F%2F%20The%20-1%20in%20the%20arithmetic%20below%20accounts%20for%20the%20fact%20that%20we%20always%0A%20%2F%2F%20keep%201%20byte%20of%20the%20ring%20buffer%20unused%20in%20order%20to%20distinguish%0A%20%2F%2F%20between%20a%20full%20buffer%20and%20an%20empty%20buffer.%0A%20%2F%2F%0A%20*AvailableData%20%3D%20ringBuffer-%26gt%3BSize%20-%20availableSpace%20-%201%3B%0A%7D%0A%0A%0A%0A%0A%0A%0A%0A%0ASIZE_T%0ACUsbPCECGHelper%3A%3AReadRingBuffer(%0A%20PRING_BUFFER%20%20%20ringBuffer%2C%0A%20PUCHAR%20%20%20%20%20%20%20%20%20readBuffer%2C%0A%20SIZE_T%20%20%20%20%20%20%20%20numberOfBytesToRead%0A)%0A%2F*%0A%20%20%20Routine%20Description%3A%0A%20%20%20This%20routine%20reads%20data%20from%20a%20ring%20buffer.%0A%0A%20%20%20Arguments%3A%0A%20%20%20ringBuffer%20-%20pointer%20to%20a%20ring%20buffer%20structure%0A%20%20%20readBuffer%20-%20pointer%20to%20a%20user%20supplied%20buffer%20to%20transfer%20data%20into%0A%20%20%20numberOfBytesToRead%20-%20number%20of%20bytes%20to%20read%20from%20the%20ring%20buffer%0A%0A%20%20%20Return%20Value%3A%0A%20%20%20ULONG%20-%20number%20of%20bytes%20read.%20%20May%20be%20smaller%20than%20requested%20number%20of%20bytes.%0A*%2F%0A%7B%0A%0A%20SIZE_T%20%20%20byteCount%3B%0A%2F%2F%20KIRQL%20%20%20%20oldIrql%3B%0A%20SIZE_T%20%20%20l_currentsize%3B%0A%0A%2F%2F%20KeAcquireSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20%26amp%3BoldIrql)%3B%0A%20l_currentsize%20%3D%20ringBuffer-%26gt%3BcurrentSize%3B%0A%2F%2F%20KeReleaseSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20oldIrql)%3B%0A%0A%2F%2F%20MarlinUSB_DbgPrint(1%2C%20(%22Marlin.sys%3A%20ReadRingBuffer()%20enter%5Cn%22))%3B%0A%0A%20if%20(numberOfBytesToRead%20%26gt%3B%20ringBuffer-%26gt%3BtotalSize)%0A%20%20return%200%3B%0A%0A%20if%20(l_currentsize%20%3D%3D%200)%0A%20%20return%200%3B%0A%0A%20if%20(numberOfBytesToRead%20%26gt%3B%20l_currentsize)%0A%20%20byteCount%20%3D%20l_currentsize%3B%0A%20else%0A%20%20byteCount%20%3D%20numberOfBytesToRead%3B%0A%0A%20%2F%2F%0A%20%2F%2F%20two%20cases.%20%20Read%20either%20wraps%20or%20it%20doesn't.%0A%20%2F%2F%20Handle%20the%20non-wrapped%20case%20first%0A%20%2F%2F%0A%20if%20((ringBuffer-%26gt%3BoutPtr%20%2B%20byteCount%20-%201)%20%26lt%3B%20(ringBuffer-%26gt%3Bbuffer%20%2B%20ringBuffer-%26gt%3BtotalSize))%0A%20%7B%0A%2F%2F%20%20MarlinUSB_DbgPrint(1%2C%20(%22Marlin.sys%3A%20ReadRingBuffer()%20about%20to%20copy%20a%5Cn%22))%3B%0A%20%20RtlCopyMemory(readBuffer%2C%20ringBuffer-%26gt%3BoutPtr%2C%20byteCount)%3B%0A%20%20ringBuffer-%26gt%3BoutPtr%20%2B%3D%20byteCount%3B%0A%20%20if%20(ringBuffer-%26gt%3BoutPtr%20%3D%3D%20ringBuffer-%26gt%3Bbuffer%20%2B%20ringBuffer-%26gt%3BtotalSize)%0A%20%20%20ringBuffer-%26gt%3BoutPtr%20%3D%20ringBuffer-%26gt%3Bbuffer%3B%0A%20%7D%0A%20%2F%2F%20now%20handle%20the%20wrapped%20case%0A%20else%0A%20%7B%0A%20%20%2F%2FULONG%20%20%20%20fragSize%3B%0A%20%20%20%2F%2FBoris%2C%2018.04.2021%20(Get%20error%3A%20conversion%20from%20'__int64'%20to%20'ULONG'%2C%20possible%20loss%20of%20data)%0A%20%20SIZE_T%20%20%20%20fragSize%3B%0A%0A%2F%2F%20%20MarlinUSB_DbgPrint(1%2C%20(%22Marlin.sys%3A%20ReadRingBuffer()%20about%20to%20copy%20b%5Cn%22))%3B%0A%0A%20%20%2F%2F%20get%20the%20first%20half%20of%20the%20read%0A%20%20%2F%2FBoris%2C%2016.02.2009%20%2CWDK%206001.18002%20build%0A%20%20%2F%2FfragSize%20%3D%20ringBuffer-%26gt%3Bbuffer%20%2B%20ringBuffer-%26gt%3BtotalSize%20-%20ringBuffer-%26gt%3BoutPtr%3B%0A%20%20%2F%2FfragSize%20%3D%20ringBuffer-%26gt%3BtotalSize%20%2B%20(ULONG)(ringBuffer-%26gt%3Bbuffer%20-%20ringBuffer-%26gt%3BoutPtr)%3B%0A%20%20%2F%2FBoris%2C%2018.04.2021%20%0A%20%20fragSize%20%3D%20(ringBuffer-%26gt%3BtotalSize%20%2B%20ringBuffer-%26gt%3Bbuffer)%20-%20ringBuffer-%26gt%3BoutPtr%3B%0A%0A%20%20RtlCopyMemory(readBuffer%2C%20ringBuffer-%26gt%3BoutPtr%2C%20fragSize)%3B%0A%0A%20%20%2F%2F%20now%20get%20the%20rest%0A%20%20RtlCopyMemory(readBuffer%20%2B%20fragSize%2C%20ringBuffer-%26gt%3Bbuffer%2C%20byteCount%20-%20fragSize)%3B%0A%0A%20%20ringBuffer-%26gt%3BoutPtr%20%3D%20ringBuffer-%26gt%3Bbuffer%20%2B%20byteCount%20-%20fragSize%3B%0A%20%7D%0A%0A%20%2F%2F%0A%20%2F%2F%20update%20the%20current%20size%20of%20the%20ring%20buffer.%20%20Use%20spinlock%20to%20insure%0A%20%2F%2F%20atomic%20operation.%0A%20%2F%2F%0A%2F%2F%20KeAcquireSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20%26amp%3BoldIrql)%3B%0A%20ringBuffer-%26gt%3BcurrentSize%20-%3D%20byteCount%3B%0A%2F%2F%20KeReleaseSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20oldIrql)%3B%0A%0A%2F%2F%20MarlinUSB_DbgPrint(1%2C%20(%22Marlin.sys%3A%20ReadRingBuffer()%20exit%5Cn%22))%3B%0A%0A%20return%20byteCount%3B%0A%0A%0A%20%2F*%0A%20%20SIZE_T%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20availableData%3D0%3B%0A%20%20SIZE_T%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dataFromCurrToEnd%3B%0A%20%20SIZE_T%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20DataSize%3D0%3B%0A%20%20SIZE_T%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20BytesCopied%20%3D%200%3B%0A%0A%20%20if(!readBuffer)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%20%20if%20(numberOfBytesToRead%20%3D%3D%200)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%20%20if%20(ringBuffer-%26gt%3BHead%20%26gt%3B%3D%20ringBuffer-%26gt%3BEnd)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%0A%20%20%2F%2F%0A%20%20%2F%2F%20Get%20the%20amount%20of%20data%20available%20in%20the%20buffer%0A%20%20%2F%2F%0A%20%20RingBufferGetAvailableData(ringBuffer%2C%20%26amp%3BavailableData)%3B%0A%0A%20%20if%20(availableData%20%3D%3D%200)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%0A%20%20DataSize%20%3D%20numberOfBytesToRead%3B%0A%0A%20%20if%20(DataSize%20%26gt%3B%20availableData)%0A%20%20%7B%0A%20%20%20DataSize%20%3D%20availableData%3B%0A%20%20%7D%0A%0A%20%20BytesCopied%20%3D%20DataSize%3B%0A%0A%20%20if%20((ringBuffer-%26gt%3BHead%20%2B%20DataSize)%20%26gt%3B%20ringBuffer-%26gt%3BEnd)%0A%20%20%7B%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20The%20data%20requested%20by%20the%20caller%20is%20wrapped%20around%20the%20end%20of%20the%0A%20%20%20%2F%2F%20buffer.%20So%20we'll%20do%20the%20copy%20in%20two%20steps%20-%0A%20%20%20%2F%2F%20%20%20%20*%20Copy%20X%20bytes%20from%20the%20current%20position%20to%20the%20end%20buffer%20into%0A%20%20%20%2F%2F%20%20%20%20%20%20the%20caller's%20buffer%0A%20%20%20%2F%2F%20%20%20%20*%20Copy%20(DataSize%20-%20X)%20bytes%20from%20the%20beginning%20to%20the%20buffer%20into%0A%20%20%20%2F%2F%20%20%20%20%20%20the%20caller's%20buffer%0A%20%20%20%2F%2F%0A%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20The%20first%20step%20of%20the%20copy%20...%0A%20%20%20%2F%2F%0A%20%20%20dataFromCurrToEnd%20%3D%20ringBuffer-%26gt%3BEnd%20-%20ringBuffer-%26gt%3BHead%3B%0A%20%20%20RtlCopyMemory(readBuffer%2C%20ringBuffer-%26gt%3BHead%2C%20dataFromCurrToEnd)%3B%0A%20%20%20readBuffer%20%2B%3D%20dataFromCurrToEnd%3B%0A%20%20%20DataSize%20%20%20-%3D%20dataFromCurrToEnd%3B%0A%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20The%20second%20step%20of%20the%20copy%20...%0A%20%20%20%2F%2F%0A%20%20%20RtlCopyMemory(readBuffer%2C%20ringBuffer-%26gt%3BBase%2C%20DataSize)%3B%0A%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20Advance%20the%20head%20pointer%0A%20%20%20%2F%2F%0A%20%20%20ringBuffer-%26gt%3BHead%20%3D%20ringBuffer-%26gt%3BBase%20%2B%20DataSize%3B%0A%20%20%7D%0A%20%20else%0A%20%20%7B%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20The%20data%20in%20the%20buffer%20is%20NOT%20wrapped%20around%20the%20end%20of%20the%20buffer.%0A%20%20%20%2F%2F%20Simply%20copy%20the%20data%20over%20to%20the%20caller's%20buffer%20in%20a%20single%20step.%0A%20%20%20%2F%2F%0A%20%20%20RtlCopyMemory(readBuffer%2C%20ringBuffer-%26gt%3BHead%2C%20DataSize)%3B%0A%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20Advance%20the%20head%20pointer%0A%20%20%20%2F%2F%0A%20%20%20ringBuffer-%26gt%3BHead%20%2B%3D%20DataSize%3B%0A%20%20%20if%20(ringBuffer-%26gt%3BHead%20%3D%3D%20ringBuffer-%26gt%3BEnd)%0A%20%20%20%7B%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20We%20have%20exactly%20reached%20the%20end%20of%20the%20buffer.%20The%20next%0A%20%20%20%20%2F%2F%20read%20should%20wrap%20around%20and%20start%20from%20the%20beginning.%0A%20%20%20%20%2F%2F%0A%20%20%20%20ringBuffer-%26gt%3BHead%20%3D%20ringBuffer-%26gt%3BBase%3B%0A%20%20%20%7D%0A%20%20%7D%0A%0A%20%20if%20(!(ringBuffer-%26gt%3BHead%20%26lt%3B%20ringBuffer-%26gt%3BEnd))%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%0A%20%20return%20BytesCopied%3B%0A%0A%20*%2F%0A%7D%0A%0ASIZE_T%0ACUsbPCECGHelper%3A%3AWriteRingBuffer(%0A%20PRING_BUFFER%20%20%20ringBuffer%2C%0A%20PUCHAR%20%20%20%20%20%20%20%20%20writeBuffer%2C%0A%20SIZE_T%20%20%20%20%20%20%20%20%20numberOfBytesToWrite%0A)%0A%2F*%0A%20%20%20Routine%20Description%3A%0A%20%20%20This%20routine%20writes%20data%20to%20a%20ring%20buffer.%20%20If%20the%20requested%20write%20size%20exceeds%0A%20%20%20available%20space%20in%20the%20ring%20buffer%2C%20then%20the%20write%20is%20rejected.%0A%0A%20%20%20Arguments%3A%0A%20%20%20ringBuffer%20-%20pointer%20to%20a%20ring%20buffer%20structure%0A%20%20%20readBuffer%20-%20pointer%20to%20a%20user%20supplied%20buffer%20of%20data%20to%20copy%20to%20the%20ring%20buffer%0A%20%20%20numberOfBytesToRead%20-%20number%20of%20bytes%20to%20write%20to%20the%20ring%20buffer%0A%0A%20%20%20Return%20Value%3A%0A%20%20%20ULONG%20-%20number%20of%20bytes%20written.%0A*%2F%0A%7B%0A%20SIZE_T%20%20%20byteCount%3B%0A%2F%2F%20KIRQL%20%20%20%20oldIrql%3B%0A%20SIZE_T%20%20%20l_currentsize%3B%0A%0A%2F%2F%20KeAcquireSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20%26amp%3BoldIrql)%3B%0A%20l_currentsize%20%3D%20ringBuffer-%26gt%3BcurrentSize%3B%0A%2F%2F%20KeReleaseSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20oldIrql)%3B%0A%0A%0A%20if%20(numberOfBytesToWrite%20%26gt%3B%20(ringBuffer-%26gt%3BtotalSize%20-%20l_currentsize))%0A%20%7B%0A%20%20%2F%2FMarlinUSB_DbgPrint(1%2C%20(%22Marlin.sys%3A%20WriteRingBuffer()%20OVERFLOW%5Cn%22))%3B%0A%20%20return%200%3B%0A%20%7D%0A%0A%20byteCount%20%3D%20numberOfBytesToWrite%3B%0A%0A%20%2F%2F%0A%20%2F%2F%20two%20cases.%20%20Write%20either%20wraps%20or%20it%20doesn't.%0A%20%2F%2F%20Handle%20the%20non-wrapped%20case%20first%0A%20%2F%2F%0A%20if%20((ringBuffer-%26gt%3BinPtr%20%2B%20byteCount%20-%201)%20%26lt%3B%20(ringBuffer-%26gt%3Bbuffer%20%2B%20ringBuffer-%26gt%3BtotalSize))%0A%20%7B%0A%20%20RtlCopyMemory(ringBuffer-%26gt%3BinPtr%2C%20writeBuffer%2C%20byteCount)%3B%0A%20%20ringBuffer-%26gt%3BinPtr%20%2B%3D%20byteCount%3B%0A%20%20if%20(ringBuffer-%26gt%3BinPtr%20%3D%3D%20ringBuffer-%26gt%3Bbuffer%20%2B%20ringBuffer-%26gt%3BtotalSize)%0A%20%20%20ringBuffer-%26gt%3BinPtr%20%3D%20ringBuffer-%26gt%3Bbuffer%3B%0A%20%7D%0A%20%2F%2F%20now%20handle%20the%20wrapped%20case%0A%20else%0A%20%7B%0A%20%20%2F%2FULONG%20%20%20%20fragSize%3B%0A%20%20%2F%2FBoris%2C%2018.04.2021%20(Get%20error%3A%20conversion%20from%20'__int64'%20to%20'ULONG'%2C%20possible%20loss%20of%20data)%0A%20%20SIZE_T%20%20%20%20fragSize%3B%0A%0A%20%20%2F%2F%20write%20the%20first%20fragment%0A%20%20%2F%2FBoris%2C%2016.02.2009%20%2CWDK%206001.18002%20build%0A%20%20%2F%2FfragSize%20%3D%20ringBuffer-%26gt%3Bbuffer%20%2B%20ringBuffer-%26gt%3BtotalSize%20-%20ringBuffer-%26gt%3BinPtr%3B%0A%20%20%2F%2FfragSize%20%3D%20ringBuffer-%26gt%3BtotalSize%20%2B%20(ULONG)(ringBuffer-%26gt%3Bbuffer%20-%20ringBuffer-%26gt%3BinPtr)%3B%0A%0A%20%20%2F%2FBoris%2C%2018.04.2021%20(Get%20error%3A%20conversion%20from%20'__int64'%20to%20'ULONG'%2C%20possible%20loss%20of%20data)%0A%20%20fragSize%20%3D%20(ringBuffer-%26gt%3BtotalSize%20%2B%20ringBuffer-%26gt%3Bbuffer)%20-%20ringBuffer-%26gt%3BinPtr%3B%0A%0A%20%20RtlCopyMemory(ringBuffer-%26gt%3BinPtr%2C%20writeBuffer%2C%20fragSize)%3B%0A%0A%20%20%2F%2F%20now%20write%20the%20rest%0A%20%20RtlCopyMemory(ringBuffer-%26gt%3Bbuffer%2C%20writeBuffer%20%2B%20fragSize%2C%20byteCount%20-%20fragSize)%3B%0A%0A%20%20ringBuffer-%26gt%3BinPtr%20%3D%20ringBuffer-%26gt%3Bbuffer%20%2B%20byteCount%20-%20fragSize%3B%0A%0A%20%7D%0A%0A%20%2F%2F%0A%20%2F%2F%20update%20the%20current%20size%20of%20the%20ring%20buffer.%20%20Use%20spinlock%20to%20insure%0A%20%2F%2F%20atomic%20operation.%0A%20%2F%2F%0A%2F%2F%20KeAcquireSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20%26amp%3BoldIrql)%3B%0A%20ringBuffer-%26gt%3BcurrentSize%20%2B%3D%20byteCount%3B%0A%2F%2F%20KeReleaseSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20oldIrql)%3B%0A%0A%20%2F%2FMarlinUSB_DbgPrint(1%2C%20(%22Marlin.sys%3A%20WriteRingBuffer()%20%25d%20bytes%5Cn%22%2C%20byteCount))%3B%0A%0A%20return%20byteCount%3B%0A%0A%0A%0A%20%2F*%0A%20%20SIZE_T%20%20%20availableSpace%20%3D%200%3B%0A%20%20SIZE_T%20%20%20spaceFromCurrToEnd%3B%0A%20%20SIZE_T%20%20%20bytesToCopy%3B%0A%20%20SIZE_T%20%20%20bytesCopied%3D0%3B%0A%20%20KIRQL%20%20%20%20oldIrql%3B%0A%0A%20%20if%20(!writeBuffer)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%20%20if%20(numberOfBytesToWrite%20%3D%3D%200)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%20%20if%20(ringBuffer-%26gt%3BTail%20%26gt%3B%3D%20ringBuffer-%26gt%3BEnd)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%0A%20%20%2F%2F%0A%20%20%2F%2F%20Get%20the%20amount%20of%20space%20available%20in%20the%20buffer%0A%20%20%2F%2F%0A%20%20KeAcquireSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20%26amp%3BoldIrql)%3B%0A%20%20RingBufferGetAvailableSpace(ringBuffer%2C%20%26amp%3BavailableSpace)%3B%0A%20%20KeReleaseSpinLock(%26amp%3BringBuffer-%26gt%3BspinLock%2C%20oldIrql)%3B%0A%0A%20%20%2F%2F%0A%20%20%2F%2F%20If%20there%20is%20not%20enough%20space%20to%20fit%20in%20all%20the%20data%20passed%20in%20by%20the%0A%20%20%2F%2F%20caller%20then%20copy%20as%20much%20as%20possible%20and%20throw%20away%20the%20rest%0A%20%20%2F%2F%0A%20%20if%20(availableSpace%20%26lt%3B%20numberOfBytesToWrite)%0A%20%20%7B%0A%20%20%20bytesToCopy%20%3D%20availableSpace%3B%0A%20%20%7D%0A%20%20else%0A%20%20%7B%0A%20%20%20bytesToCopy%20%3D%20numberOfBytesToWrite%3B%0A%20%20%7D%0A%0A%20%20bytesCopied%20%3D%20bytesToCopy%3B%0A%0A%20%20if%20(bytesToCopy)%0A%20%20%7B%0A%20%20%20%2F%2F%0A%20%20%20%2F%2F%20The%20buffer%20has%20some%20space%20at%20least%0A%20%20%20%2F%2F%0A%20%20%20if%20((ringBuffer-%26gt%3BTail%20%2B%20bytesToCopy)%20%26gt%3B%20ringBuffer-%26gt%3BEnd)%0A%20%20%20%7B%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20The%20data%20being%20written%20will%20wrap%20around%20the%20end%20of%20the%20buffer.%0A%20%20%20%20%2F%2F%20So%20the%20copy%20has%20to%20be%20done%20in%20two%20steps%20-%0A%20%20%20%20%2F%2F%20*%20X%20bytes%20from%20current%20position%20to%20end%20of%20the%20buffer%0A%20%20%20%20%2F%2F%20*%20the%20remaining%20(bytesToCopy%20-%20X)%20from%20the%20start%20of%20the%20buffer%0A%20%20%20%20%2F%2F%0A%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20The%20first%20step%20of%20the%20copy%20...%0A%20%20%20%20%2F%2F%0A%20%20%20%20spaceFromCurrToEnd%20%3D%20ringBuffer-%26gt%3BEnd%20-%20ringBuffer-%26gt%3BTail%3B%0A%0A%20%20%20%20RtlCopyMemory(ringBuffer-%26gt%3BTail%2C%20writeBuffer%2C%20spaceFromCurrToEnd)%3B%0A%0A%20%20%20%20writeBuffer%20%2B%3D%20spaceFromCurrToEnd%3B%0A%0A%20%20%20%20bytesToCopy%20-%3D%20spaceFromCurrToEnd%3B%0A%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20The%20second%20step%20of%20the%20copy%20...%0A%20%20%20%20%2F%2F%0A%20%20%20%20RtlCopyMemory(ringBuffer-%26gt%3BBase%2C%20writeBuffer%2C%20bytesToCopy)%3B%0A%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20Advance%20the%20tail%20pointer%0A%20%20%20%20%2F%2F%0A%20%20%20%20ringBuffer-%26gt%3BTail%20%3D%20ringBuffer-%26gt%3BBase%20%2B%20bytesToCopy%3B%0A%20%20%20%7D%0A%20%20%20else%0A%20%20%20%7B%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20Data%20does%20NOT%20wrap%20around%20the%20end%20of%20the%20buffer.%20Just%20copy%20it%0A%20%20%20%20%2F%2F%20over%20in%20a%20single%20step%0A%20%20%20%20%2F%2F%0A%20%20%20%20RtlCopyMemory(ringBuffer-%26gt%3BTail%2C%20writeBuffer%2C%20bytesToCopy)%3B%0A%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20Advance%20the%20tail%20pointer%0A%20%20%20%20%2F%2F%0A%20%20%20%20ringBuffer-%26gt%3BTail%20%2B%3D%20bytesToCopy%3B%0A%20%20%20%20if%20(ringBuffer-%26gt%3BTail%20%3D%3D%20ringBuffer-%26gt%3BEnd)%0A%20%20%20%20%7B%0A%20%20%20%20%20%2F%2F%0A%20%20%20%20%20%2F%2F%20We%20have%20exactly%20reached%20the%20end%20of%20the%20buffer.%20The%20next%0A%20%20%20%20%20%2F%2F%20write%20should%20wrap%20around%20and%20start%20from%20the%20beginning.%0A%20%20%20%20%20%2F%2F%0A%20%20%20%20%20ringBuffer-%26gt%3BTail%20%3D%20ringBuffer-%26gt%3BBase%3B%0A%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20%20%20if%20(!(ringBuffer-%26gt%3BTail%20%26lt%3B%20ringBuffer-%26gt%3BEnd))%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%0A%20%20%7D%0A%0A%20%20return%20bytesCopied%3B%0A%0A%20%20*%2F%0A%7D%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%2F%2F%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A%3C%2FCUSBPCECGHELPER%3E%3C%2FCUSBPCECGHELPER%3E%3C%2FCOMBASEAPI.H%3E%3C%2FCFGMGR32.H%3E%3C%2FINITGUID.H%3E%3C%2FCSTDLIB%3E%3C%2FUSB.H%3E%3C%2FWINUSB.H%3E%3C%2FSTRSAFE.H%3E%3C%2FTCHAR.H%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%23define%20ISOCH_DATA_SIZE_MS%2010%3CBR%20%2F%3E%23define%20ISOCH_TRANSFER_COUNT%202%26nbsp%3B%20%26nbsp%3B%20%2F%2Fwill%20need%20to%20be%20at%20least%202%3C%2FP%3E%3CP%3E%2F*%3CBR%20%2F%3E*%20My%20device%20sends%20one%20sample%20of%202%20bytes%20every%201ms%20..%20%3D%26gt%3B%20data%20sample%20rate%20%3D%201000s%2Fs%3CBR%20%2F%3E*%3CBR%20%2F%3E*%20Problem%20!!%3CBR%20%2F%3E*%20Only%20Transfer%201%20has%20the%20data%20all%20next%20(ISOCH_TRANSFER_COUNT)%20are%20empty%3CBR%20%2F%3E*%20As%20a%20result%20i%20see%20data%20arriving%20at%20sample%20rate%20of%201000%20%2F%20ISOCH_TRANSFER_COUNT%20in%20Read%20application%3CBR%20%2F%3E*%3CBR%20%2F%3E*%20Why%20%3F%3F%3F%3F%3F%3CBR%20%2F%3E*%3CBR%20%2F%3EnvUSB.lib%3A%20Current%20Frame%20number%3D261744397%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Transfer%201%20completed.%20Read%20100%20bytes.%3CBR%20%2F%3EnvUSB.lib%3A%20Current%20Frame%20number%3D261744447%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Transfer%202%20completed.%20Read%200%20bytes.%20%26lt%3B--%20%3F%3F%3CBR%20%2F%3EnvUSB.lib%3A%20Current%20Frame%20number%3D261744497%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Transfer%201%20completed.%20Read%20100%20bytes.%3CBR%20%2F%3EnvUSB.lib%3A%20Current%20Frame%20number%3D261744547%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Transfer%202%20completed.%20Read%200%20bytes.%20%26lt%3B---%20%3F%3F%3CBR%20%2F%3EnvUSB.lib%3A%20Current%20Frame%20number%3D261744597%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Transfer%201%20completed.%20Read%20100%20bytes.%3CBR%20%2F%3EnvUSB.lib%3A%20Current%20Frame%20number%3D261744647%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Requested%201200%20bytes%20in%2050%20packets%20per%20transfer.%3CBR%20%2F%3EnvUSB.lib%3A%20bRead()%20Transfer%202%20completed.%20Read%200%20bytes.%3CBR%20%2F%3EnvUSB.lib%3A%20Current%20Frame%20number%3D261744697%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E
Visitor

Hi

 

We have a usb device that working with our WDM driver written about 15 years ago .

It works on Windows XP to Windows 10 32 and 64 bit.

Device sends analog data of 2 bytes every 1ms to PC ( Data sample rate = 1000)

 

I tried to switch working with Microsoft winusb driver in Windows 10.

Driver installed OK;

 

I write some wrapper code (So my Application will work as is) to use winusb driver on

isochronous pipe streaming and get very strange behave ...

 

I am missing packets , on All empty packets i get Status of USBD_STATUS_ISO_NOT_ACCESSED_BY_HW

 

USBD_STATUS_ISO_NOT_ACCESSED_BY_HW

Extended isochronous error codes returned by USBD.
These errors appear in the packet status field of an isochronous transfer. [0xC0020000]
For some reason the controller did not access the TD associated with this packet:

 

/* -----       IF Using WinUSB.sys driver   --------------- */
#ifdef USE_WINUSB_DRIVER

#include <tchar.h>
#include <strsafe.h>
#include <winusb.h>
#include <usb.h>
#include <cstdlib>
#include <initguid.h>
#include <cfgmgr32.h>
#include <combaseapi.h>

//
// Device Interface GUID.
// Used by all WinUsb devices that this application talks to.
// Must match "DeviceInterfaceGUIDs" registry value specified in the INF file.
// yyyyyy-yyyy-yyyy-xxxx-yyyyyyyy
//
DEFINE_GUID(GUID_DEVINTERFACE_ECGUSB1, 0xyyyyyyyy, 0xyyyy, 0xyyy, 0xxx, 0xxx, 0xyy, 0xyy, 0xyy, 0xyy, 0xyy, 0xyy);



#define ISOCH_DATA_SIZE_MS	10
#define ISOCH_TRANSFER_COUNT	2		//will need to be at least 2

/*
*  My device sends one sample of 2 bytes every 1ms .. => data sample rate = 1000s/s
* 
*  Problem !!
*  Only Transfer 1 has the data all next (ISOCH_TRANSFER_COUNT) are empty
*  As a result i see data arriving at sample rate of 1000 / ISOCH_TRANSFER_COUNT  in Read application
* 
*  Why ?????
* 
nvUSB.lib: Current Frame number=261744397
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes.
nvUSB.lib: Current Frame number=261744447
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes.					<-- ??
nvUSB.lib: Current Frame number=261744497
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes.
nvUSB.lib: Current Frame number=261744547
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes.					<--- ??
nvUSB.lib: Current Frame number=261744597
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes.
nvUSB.lib: Current Frame number=261744647
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes.
nvUSB.lib: Current Frame number=261744697


*/





typedef struct _PCECG_PIPE_INFORMATION_EX {
	USBD_PIPE_TYPE PipeType;
	UCHAR          PipeId;
	USHORT         MaximumPacketSize;
	UCHAR          Interval;
	ULONG          MaximumBytesPerInterval;
	int			   index;
} PCECG_PIPE_INFORMATION_EX, * PPCECG_PIPE_INFORMATION_EX;


struct PIPE_ID
{
	// Note:
	// Each USB device can define up to 32 endpoints(16 inputs and 16 outputs though one must be a control endpoint)
	// Here i assume that we will use maximum 2 for each type..
	PCECG_PIPE_INFORMATION_EX  Bulk_Pipe[2]; // [0] -for IN type ; [1] -for OUT type 
	PCECG_PIPE_INFORMATION_EX  Int_Pipe[2];
	PCECG_PIPE_INFORMATION_EX  Iso_Pipe[2];
};


typedef struct _RING_BUFFER
{
	PUCHAR      buffer;
	PUCHAR      inPtr;
	PUCHAR      outPtr;
	SIZE_T      totalSize;
	SIZE_T      currentSize;
	KSPIN_LOCK	spinLock;

	SIZE_T      Size;
	PUCHAR      Base;
	PUCHAR      End;
	PUCHAR      Head;
	PUCHAR      Tail;

} RING_BUFFER, * PRING_BUFFER;



class CUsbPCECGHelper
{
public:
	//  constructor
	CUsbPCECGHelper();
	// destructor
	virtual ~CUsbPCECGHelper();

	BOOL GetDeviceHandle(GUID guidDeviceInterface, PHANDLE hDeviceHandle);
	BOOL GetWinUSBHandle(HANDLE hDeviceHandle, PWINUSB_INTERFACE_HANDLE phWinUSBHandle);
	BOOL GetUSBDeviceSpeed(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pDeviceSpeed);
	BOOL QueryDeviceEndpoints(WINUSB_INTERFACE_HANDLE hDeviceHandle, PIPE_ID* pipeid);

	void ClearIsobuffers(void);
	void ClearDeviceHandles(void);
	void ClearThreadHandles(void);
	DWORD StartThreadHandles(void);

	HANDLE						m_hDeviceHandle ;
	WINUSB_INTERFACE_HANDLE		m_hWinUSBHandle[2];
	PIPE_ID						PipeID;
	DRIVER_VERSION				drvver;
	BOOL						RealTimeInProgress;

	ULONG						IsochInTransferSize;
	ULONG						IsochInPacketCount;
	PUCHAR						readBuffer;
	LPOVERLAPPED				overlapped;
	WINUSB_ISOCH_BUFFER_HANDLE	isochReadBufferHandle;
	PUSBD_ISO_PACKET_DESCRIPTOR isochPacketDescriptors;


	//reading execution thread handle
	HANDLE						m_hEventThread;
	//event handle to close execution thread
	HANDLE						m_hCloseThread;
	//event handle for read 
	HANDLE						m_hReadAsync[ISOCH_TRANSFER_COUNT];
	DWORD						m_dwInterval;
	BOOL						m_bResult;

	DWORD ReadIsoBuffer(DWORD eventIndex);

	// Data Event thread procedure.
	static DWORD WINAPI AsyncReadThreadProc(__in LPVOID pvData);


	PRING_BUFFER	m_DataRingBuffer;

	PRING_BUFFER	AllocRingBuffer( SIZE_T    Size	);
	VOID			FreeRingBuffer(	PRING_BUFFER   ringBuffer);
	SIZE_T			ReadRingBuffer(	PRING_BUFFER   ringBuffer,	PUCHAR    readBuffer,	SIZE_T   numberOfBytesToRead );
	SIZE_T			WriteRingBuffer(PRING_BUFFER   ringBuffer,	PUCHAR    writeBuffer,	SIZE_T   numberOfBytesToWrite);
	VOID			RingBufferGetAvailableSpace(PRING_BUFFER      ringBuffer,	SIZE_T* AvailableSpace );
	VOID			RingBufferGetAvailableData(	PRING_BUFFER      ringBuffer,	SIZE_T* AvailableData	);

};


CUsbPCECGHelper		helperfunctionsc_class;


#endif

#ifdef USE_WINUSB_DRIVER

CUsbPCECGHelper::CUsbPCECGHelper()
{
	m_hDeviceHandle	   = INVALID_HANDLE_VALUE;
	m_hWinUSBHandle[0] = INVALID_HANDLE_VALUE;
	m_hWinUSBHandle[1] = INVALID_HANDLE_VALUE;

	drvver.MajorVersion = 0;
	drvver.MinorVersion = 0;
	drvver.BuildVersion = 0;

	PipeID.Bulk_Pipe[0].index = -1;
	PipeID.Int_Pipe [0].index = -1;
	PipeID.Iso_Pipe [0].index = -1;

	PipeID.Bulk_Pipe[1].index = -1;
	PipeID.Int_Pipe [1].index = -1;
	PipeID.Iso_Pipe [1].index = -1;

	RealTimeInProgress = FALSE;

	readBuffer = NULL;
	isochPacketDescriptors = NULL;
	overlapped = NULL;
	isochReadBufferHandle = INVALID_HANDLE_VALUE;

	m_hEventThread = NULL;
	m_hCloseThread = NULL;
	m_bResult = FALSE;


	m_DataRingBuffer = NULL;
	m_DataRingBuffer = AllocRingBuffer(64 * 1024);
}

CUsbPCECGHelper::~CUsbPCECGHelper()
{
	ClearThreadHandles();
	ClearIsobuffers();
	ClearDeviceHandles();

	FreeRingBuffer(m_DataRingBuffer);
}


void  CUsbPCECGHelper::ClearThreadHandles(void)
{
	if (NULL != m_hCloseThread)
	{
		// Stop the event thread.
		::SetEvent(m_hCloseThread);

		// Wait for the thread to end.
		::WaitForSingleObject(m_hEventThread, INFINITE);

		if (NULL != m_hEventThread)
		{
			CloseHandle(m_hEventThread);
			m_hEventThread = NULL;
		}

		CloseHandle(m_hCloseThread);
		m_hCloseThread = NULL;
	}
}

void CUsbPCECGHelper::ClearIsobuffers(void)
{
	//ULONG i;

	if (isochReadBufferHandle != INVALID_HANDLE_VALUE)
	{
		WinUsb_UnregisterIsochBuffer(isochReadBufferHandle);
		isochReadBufferHandle = INVALID_HANDLE_VALUE;
	}

	if (readBuffer != NULL)
	{
		delete[] readBuffer;
		readBuffer = NULL;
	}

	if (isochPacketDescriptors != NULL)
	{
		delete[] isochPacketDescriptors;
		isochPacketDescriptors = NULL;
	}

/*	for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
	{
		if (overlapped[i].hEvent != NULL)
		{
			CloseHandle(overlapped[i].hEvent);
			overlapped[i].hEvent = NULL;
		}
	}*/

	if (overlapped != NULL)
	{
		delete[] overlapped;
		overlapped = NULL;
	}
}

void CUsbPCECGHelper::ClearDeviceHandles(void)
{
	if (m_hWinUSBHandle[0] != INVALID_HANDLE_VALUE)
	{
		WinUsb_Free(m_hWinUSBHandle[0]);
		m_hWinUSBHandle[0] = INVALID_HANDLE_VALUE;
	}

	if (m_hWinUSBHandle[1] != INVALID_HANDLE_VALUE)
	{
		WinUsb_Free(m_hWinUSBHandle[1]);
		m_hWinUSBHandle[1] = INVALID_HANDLE_VALUE;
	}

	if (m_hDeviceHandle != INVALID_HANDLE_VALUE)
	{
		CloseHandle(m_hDeviceHandle);
		m_hDeviceHandle = INVALID_HANDLE_VALUE;
	}

}

DWORD CUsbPCECGHelper::StartThreadHandles(void)
{
	DWORD result = S_OK;

	if (m_hWinUSBHandle[0] == INVALID_HANDLE_VALUE)
	{
		return E_HANDLE;
	}


	// Create the event used to close the thread.
	if (NULL == m_hCloseThread)
	{
		m_hCloseThread = ::CreateEvent(NULL, FALSE, FALSE, TEXT("CloseThreadEvent"));
	}
	if (NULL == m_hCloseThread)
	{
		result=E_UNEXPECTED;
	}

	if (SUCCEEDED(result) && (m_hEventThread == NULL))
	{
		m_hEventThread = ::CreateThread(NULL,        // Cannot be inherited by child process
			0,                                       // Default stack size
			&CUsbPCECGHelper::AsyncReadThreadProc,	 // Thread proc
			(LPVOID)this,                            // Thread proc argument
			0,                                       // Starting state = running
			NULL);                                   // No thread identifier

		if (NULL == m_hEventThread)
		{
			result = E_UNEXPECTED;
		}
		else
		{
			//DWORD dwError, dwThreadPri;
			if (!SetThreadPriority(m_hEventThread, THREAD_PRIORITY_HIGHEST))
			{
				//dwError = GetLastError();
				result = E_UNEXPECTED;
			}
			//dwThreadPri = GetThreadPriority(m_hEventThread);
		}
	}

	return result;
}


DWORD WINAPI CUsbPCECGHelper::AsyncReadThreadProc(__in LPVOID pvData)
{

#if(1)

	//--------------

	HANDLE hEvents[ISOCH_TRANSFER_COUNT+1];
	DWORD dwWait = 0;
	DWORD dwNum = 0;
	USHORT headerSize = 3;
	ULONG bytesRead = 0;
	BOOL b = FALSE;
	ULONG i;
	BOOL result = FALSE;

	// Cast the argument to the correct type
	CUsbPCECGHelper* pThis = static_cast<CUsbPCECGHelper*>(pvData);

	// New threads must always CoInitialize
	HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

	ULONG totalTransferSize = pThis->IsochInTransferSize * ISOCH_TRANSFER_COUNT;

	pThis->readBuffer = new UCHAR[totalTransferSize];
	if (pThis->readBuffer == NULL)
	{
		//sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Unable to allocate memory\n");
		//OutputDebugString((LPCSTR)s);
		hr = E_UNEXPECTED;
	}
	else
	{
		ZeroMemory(pThis->readBuffer, totalTransferSize);
	}

	hEvents[0] = pThis->m_hCloseThread;

	for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
	{
		pThis->m_hReadAsync[i] = CreateEvent(
			NULL,    // default security attribute
			TRUE,    // manual-reset event
			FALSE,   // initial state = not signaled
			NULL);   // unnamed event object
	}

	for (i = 1; i < (ISOCH_TRANSFER_COUNT+1); i++)
		hEvents[i] = pThis->m_hReadAsync[i-1];

	if (SUCCEEDED(hr))
	{
		pThis->overlapped = new OVERLAPPED[ISOCH_TRANSFER_COUNT];
		ZeroMemory(pThis->overlapped, (sizeof(OVERLAPPED) * ISOCH_TRANSFER_COUNT));
		for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
		{
//			pThis->overlapped[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

			pThis->overlapped[i].hEvent = pThis->m_hReadAsync[i];
			// Initialize the rest of the OVERLAPPED structure to zero.
			pThis->overlapped[i].Internal = 0;
			pThis->overlapped[i].InternalHigh = 0;
			pThis->overlapped[i].Offset = 0;
			pThis->overlapped[i].OffsetHigh = 0;

			if (pThis->overlapped[i].hEvent == NULL)
			{
				//sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Unable to set event for overlapped operation\n");
				//OutputDebugString((LPCSTR)s);
				hr = E_UNEXPECTED;
			}
		}
	}

	if (SUCCEEDED(hr))
	{
		result = WinUsb_RegisterIsochBuffer(
			pThis->m_hWinUSBHandle[0],			// An opaque handle to an interface in the selected configuration. That handle must be created by a previous call to WinUsb_Initialize or WinUsb_GetAssociatedInterface.
			pThis->PipeID.Iso_Pipe[0].PipeId,	// Derived from Bit 3...0 of the bEndpointAddress field in the endpoint descriptor.
			pThis->readBuffer,					// Pointer to the transfer buffer to be registered.
			totalTransferSize,					// Length, in bytes, of the transfer buffer pointed to by Buffer.
			&pThis->isochReadBufferHandle);		// Receives an opaque handle to the registered buffer. This handle is required by other WinUSB functions that perform isochronous transfers. To release the handle, call the WinUsb_UnregisterIsochBuffer function.

		if (!result)
		{
			//sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Isoch buffer registration failed.\n");
			//OutputDebugString((LPCSTR)s);

			hr = E_UNEXPECTED;
		}
	}

	if (SUCCEEDED(hr))
	{
		pThis->isochPacketDescriptors = new USBD_ISO_PACKET_DESCRIPTOR[pThis->IsochInPacketCount * ISOCH_TRANSFER_COUNT];
		ZeroMemory(pThis->isochPacketDescriptors, pThis->IsochInPacketCount * ISOCH_TRANSFER_COUNT);


		//for iso endpoints read this
		//https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/getting-set-up-to-use-windows-devices-usb
		//

		for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
		{
			result = WinUsb_ReadIsochPipeAsap(
				pThis->isochReadBufferHandle,			// An opaque handle to the transfer buffer that was registered by a previous call to WinUsb_RegisterIsochBuffer.
				pThis->IsochInTransferSize * i,			// Offset into the buffer relative to the start the transfer.
				pThis->IsochInTransferSize,				// Length in bytes of the transfer buffer.
				(i == 0) ? FALSE : TRUE,				// Indicates that the transfer should only be submitted if it can be scheduled in the first frame after the last pending transfer.
				pThis->IsochInPacketCount,				// Total number of isochronous packets required to hold the transfer buffer.Also indicates the number of elements in the array pointed to by IsoPacketDescriptors.
				&pThis->isochPacketDescriptors[i * pThis->IsochInPacketCount], //An array of USBD_ISO_PACKET_DESCRIPTOR that receives the details of each isochronous packet in the transfer.
				&pThis->overlapped[i]);					// Pointer to an OVERLAPPED structure used for asynchronous operations.

			if (!result)
			{
				DWORD  lastError = GetLastError();

				if (lastError != ERROR_IO_PENDING)
				{
					//sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Failed to start a read operation with error %x\n", lastError);
					//OutputDebugString((LPCSTR)s);
					hr = E_UNEXPECTED;
				}
			}
		}
	}
	//--------------


	if (SUCCEEDED(hr))
	{
		while (true)
		{	
			for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
				pThis->m_bResult = ResetEvent(pThis->m_hReadAsync[i]);

			dwWait = WaitForMultipleObjects(ISOCH_TRANSFER_COUNT+1,			   // number of event objects 
				hEvents,      // array of event objects 
				FALSE,        // does not wait for all 
				INFINITE	   // waits indefinitely 
			);
	

			if (dwWait == WAIT_OBJECT_0) //STOP_THREAD
			{
				CoUninitialize();

				for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
					CloseHandle(pThis->m_hReadAsync[i]);

				return 0;
			}
			else
			{
				for (i = 1; i < (ISOCH_TRANSFER_COUNT + 1); i++)
				{
					if (dwWait == (WAIT_OBJECT_0 + i))
					{
						pThis->ReadIsoBuffer((i-1));
					}
				}
			}
		}
	}

#endif


#if(0)

	OVERLAPPED oOverlap;
	HANDLE hEvents[2];
	DWORD dwWait = 0;
	DWORD dwNum = 0;
	const DWORD STOP_THREAD = WAIT_OBJECT_0;
	const DWORD READ_EVENT  = WAIT_OBJECT_0 + 1;
	USHORT headerSize = 3;
	UCHAR buffer[3];
	ULONG bytesRead = 0;
	BOOL b = FALSE;
	


	// Cast the argument to the correct type
	CUsbPCECGHelper* pThis = static_cast<CUsbPCECGHelper*>(pvData);

	// New threads must always CoInitialize
	HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

	
	hEvents[0] = pThis->m_hCloseThread;

	pThis->m_hReadAsync = CreateEvent(
		NULL,    // default security attribute
		TRUE,    // manual-reset event
		FALSE,   // initial state = not signaled
		NULL);   // unnamed event object


	hEvents[1] = pThis->m_hReadAsync;

/*
	oOverlap.hEvent = pThis->m_hReadAsync;
	// Initialize the rest of the OVERLAPPED structure to zero.
	oOverlap.Internal = 0;
	oOverlap.InternalHigh = 0;
	oOverlap.Offset = 0;
	oOverlap.OffsetHigh = 0;
*/

	

	if (SUCCEEDED(hr))
	{
		while (true)
		{
			/*
			pThis->m_bResult = ResetEvent(pThis->m_hReadAsync);
			pThis->ReadHeader(buffer, headerSize, &bytesRead, &oOverlap);
			dwWait = WaitForMultipleObjects(2,			   // number of event objects 
				hEvents,      // array of event objects 
				FALSE,        // does not wait for all 
				INFINITE	   // waits indefinitely 
			);
			b = WinUsb_GetOverlappedResult(pThis->m_UsbHandle[1], &oOverlap, &dwNum, FALSE);
			*/

			pThis->m_bResult = ResetEvent(pThis->m_hReadAsync);
			dwWait = WaitForMultipleObjects(2,			   // number of event objects 
				hEvents,      // array of event objects 
				FALSE,        // does not wait for all 
				INFINITE	   // waits indefinitely 
			);

			switch (dwWait)
			{
			case STOP_THREAD:
				CoUninitialize();
				CloseHandle(pThis->m_hReadAsync);
				return 0;
				//break;
			case READ_EVENT:
				/*
				//reads the rest of the message if exist, throws events if needed
				if (b)
				{
					pThis->ParseDataMessage(buffer);
				}
				else
				{
					//error
					WinUsb_FlushPipe(pThis->m_UsbHandle[1], pThis->m_bulkInPipe);
				}
				break;
				*/
			default:
				break;
			}
		}
	}

#endif

	//code not reached
	return 1;
}


DWORD CUsbPCECGHelper::ReadIsoBuffer(DWORD eventIndex)
{
#if(1)

	/*
		//for iso endpoints read this
		//https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/getting-set-up-to-use-windows-devices-usb
		//https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/transfer-data-to-isochronous-endpoints
		//
	*/


	char	s[256];
	DWORD	Status = UsbPCECG_ERR_SUCCESS;
	ULONG	i, j;
	BOOL	result;
	DWORD	lastError;
	ULONG	numBytes = 0;
	BOOL    ContinueStream = TRUE;

	ULONG				frameNumber;
	ULONG				startFrame;
	LARGE_INTEGER		timeStamp;

	if (helperfunctionsc_class.m_hWinUSBHandle[0] == INVALID_HANDLE_VALUE)
	{
		return UsbPCECG_ERR_READISOBUFF;
	}


	result = WinUsb_GetCurrentFrameNumber(
		helperfunctionsc_class.m_hWinUSBHandle[0],
		&frameNumber,
		&timeStamp);

	if (!result)
	{
		sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() WinUsb_GetCurrentFrameNumber failed. \n");
		OutputDebugString((LPCSTR)s);

		return UsbPCECG_ERR_READISOBUFF;
	}

	sprintf_s(s, sizeof(s), "nvUSB.lib: Current Frame number=%d\n", frameNumber);
	OutputDebugString((LPCSTR)s);


	startFrame = frameNumber + 10;

	i = eventIndex;
//	for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
	{
		if (helperfunctionsc_class.RealTimeInProgress == FALSE)
		{
			return UsbPCECG_ERR_READISOBUFF;
		}

		result = WinUsb_GetOverlappedResult(
			helperfunctionsc_class.m_hWinUSBHandle[0],
			&helperfunctionsc_class.overlapped[i],
			&numBytes,
			TRUE);

		if (!result || numBytes == 0)
		{
			//0x1F  = ERROR_GEN_FAILURE				A device attached to the system is not functioning.
			//0x7A  = ERROR_INSUFFICIENT_BUFFER     The data area passed to a system call is too small.
			//0x57  = ERROR_INVALID_PARAMETER       The parameter is incorrect.
			//0x3E5 = ERROR_IO_PENDING              Overlapped I/O operation is in progress.

			lastError = GetLastError();

			if (lastError == ERROR_IO_PENDING) //The transfer is pending..
			{
				// try again..
				if (i > 0) i--;
//				continue;
			}

			sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to read with error %x \n", lastError);
			OutputDebugString((LPCSTR)s);

			return UsbPCECG_ERR_READISOBUFF;
		}
		else
		{
			numBytes = 0;
			for (j = 0; j < helperfunctionsc_class.IsochInPacketCount; j++)
			{
				numBytes += helperfunctionsc_class.isochPacketDescriptors[j].Length;

				//sprintf_s(s, sizeof(s), "%d-%d-%d\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPackets[j].Offset, helperfunctionsc_class.isochPackets[j].Status);
				//OutputDebugString((LPCSTR)s);

				/*
				if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPackets[j].Status == 0)
				{
					memcpy(inBuffer, helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset, helperfunctionsc_class.isochPacketDescriptors[j].Length);
					*nWriten += helperfunctionsc_class.isochPacketDescriptors[j].Length;
					inBuffer += helperfunctionsc_class.isochPacketDescriptors[j].Length;
				}
				*/

				/*

				!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

				sprintf_s(s, sizeof(s), "nvUSB.lib: desc.lenght=%d bytes descr.status=%x\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPacketDescriptors[j].Status);
				OutputDebugString((LPCSTR)s);

				for ECGUSB1D-EX get
				nvUSB.lib: desc.lenght=2 bytes descr.status=0           if OK
				nvUSB.lib: desc.lenght=0 bytes descr.status=c0020000    if empty packet

				WD_USBD_STATUS_ISO_NOT_ACCESSED_BY_HW

				Extended isochronous error codes returned by USBD.
				These errors appear in the packet status field of an isochronous transfer. [0xC0020000]
				For some reason the controller did not access the TD associated with this packet:


				!
				When the USB driver stack processes the URB, the driver discards all isochronous packets in the URB whose frame numbers are lower than the current frame number.
				The driver stack sets the Status member of the packet descriptor for each discarded packet to USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW,
				or USBD_STATUS_ISO_NOT_ACCESSED_LATE. Even though some packets in the URB are discarded, the driver stack attempts to transmit only those packets whose frame numbers
				are higher than the current frame number.
				!!

				*/
				/*
				if (helperfunctionsc_class.isochPacketDescriptors[j].Length == 0 && helperfunctionsc_class.isochPacketDescriptors[j].Status == USBD_STATUS_ISO_NOT_ACCESSED_BY_HW)
				{
					if (!(WinUsb_FlushPipe(helperfunctionsc_class.m_hWinUSBHandle[0], helperfunctionsc_class.PipeID.Iso_Pipe[0].PipeId)))
					{
						sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() error flush pipe %d.\n", GetLastError());
						OutputDebugString((LPCSTR)s);

						return	UsbPCECG_ERR_RESETPIPE;
					}
				}
				*/

				if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPacketDescriptors[j].Status == 0)
				{
					WriteRingBuffer(
						helperfunctionsc_class.m_DataRingBuffer,
						(helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset),
						helperfunctionsc_class.isochPacketDescriptors[j].Length
					);
				}
			}

			sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Requested %d bytes in %d packets per transfer.\n", helperfunctionsc_class.IsochInTransferSize, helperfunctionsc_class.IsochInPacketCount);
			OutputDebugString((LPCSTR)s);
		}

		sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Transfer %d completed. Read %d bytes. \n", i + 1, numBytes);
		OutputDebugString((LPCSTR)s);


		result = WinUsb_ReadIsochPipeAsap(
			helperfunctionsc_class.isochReadBufferHandle,
			helperfunctionsc_class.IsochInTransferSize * i,
			helperfunctionsc_class.IsochInTransferSize,
			ContinueStream,
			helperfunctionsc_class.IsochInPacketCount,
			&helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount],
			&helperfunctionsc_class.overlapped[i]);


		/*
		// not working
		// return with nvUSB.lib: bRead() Failed to read with error 1f  after first time..
		result = WinUsb_ReadIsochPipe(
			helperfunctionsc_class.isochReadBufferHandle,
			helperfunctionsc_class.IsochInTransferSize * i,
			helperfunctionsc_class.IsochInTransferSize,
			&startFrame,
			helperfunctionsc_class.IsochInPacketCount,
			&helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount],
			&helperfunctionsc_class.overlapped[i]);
		*/

		if (!result)
		{
			lastError = GetLastError();

			if (lastError == ERROR_INVALID_PARAMETER && ContinueStream)
			{
				ContinueStream = FALSE;
//				continue;
			}

			if (lastError != ERROR_IO_PENDING)
			{
				sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to start a read operation with error %x\n", lastError);
				OutputDebugString((LPCSTR)s);

				return UsbPCECG_ERR_READISOBUFF;
			}

			ContinueStream = TRUE;
		}

	}

	return(Status);

#endif


#if(0)

	/*
		//for iso endpoints read this
		//https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/getting-set-up-to-use-windows-devices-usb
		//https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/transfer-data-to-isochronous-endpoints
		//
	*/


	char	s[256];
	DWORD	Status = UsbPCECG_ERR_SUCCESS;
	ULONG	i, j;
	BOOL	result;
	DWORD	lastError;
	ULONG	numBytes=0;
	BOOL    ContinueStream = TRUE;

	ULONG				frameNumber;
	ULONG				startFrame;
	LARGE_INTEGER		timeStamp;

	if (helperfunctionsc_class.m_hWinUSBHandle[0] == INVALID_HANDLE_VALUE)
	{
		return UsbPCECG_ERR_READISOBUFF;
	}


	result = WinUsb_GetCurrentFrameNumber(
		helperfunctionsc_class.m_hWinUSBHandle[0],
		&frameNumber,
		&timeStamp);

	if (!result)
	{
		sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() WinUsb_GetCurrentFrameNumber failed. \n");
		OutputDebugString((LPCSTR)s);

		return UsbPCECG_ERR_READISOBUFF;
	}

	startFrame = frameNumber + 10;


	for (i = 0; i < ISOCH_TRANSFER_COUNT; i++)
	{
		if (helperfunctionsc_class.RealTimeInProgress == FALSE)
		{
			return UsbPCECG_ERR_READISOBUFF;
		}

		result = WinUsb_GetOverlappedResult(
			helperfunctionsc_class.m_hWinUSBHandle[0],
			&helperfunctionsc_class.overlapped[i],
			&numBytes,
			TRUE);

		if (!result || numBytes==0)
		{
			//0x1F  = ERROR_GEN_FAILURE				A device attached to the system is not functioning.
			//0x7A  = ERROR_INSUFFICIENT_BUFFER     The data area passed to a system call is too small.
			//0x57  = ERROR_INVALID_PARAMETER       The parameter is incorrect.
			//0x3E5 = ERROR_IO_PENDING              Overlapped I/O operation is in progress.

			lastError = GetLastError();

			if (lastError == ERROR_IO_PENDING) //The transfer is pending..
			{
				// try again..
				if (i > 0) i--; 
				continue;
			}

			sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to read with error %x \n", lastError);
			OutputDebugString((LPCSTR)s);

			return UsbPCECG_ERR_READISOBUFF;
		}
		else
		{
			numBytes = 0;
			for (j = 0; j < helperfunctionsc_class.IsochInPacketCount; j++)
			{
				numBytes += helperfunctionsc_class.isochPacketDescriptors[j].Length;

				//sprintf_s(s, sizeof(s), "%d-%d-%d\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPackets[j].Offset, helperfunctionsc_class.isochPackets[j].Status);
				//OutputDebugString((LPCSTR)s);

				/*
				if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPackets[j].Status == 0)
				{
					memcpy(inBuffer, helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset, helperfunctionsc_class.isochPacketDescriptors[j].Length);
					*nWriten += helperfunctionsc_class.isochPacketDescriptors[j].Length;
					inBuffer += helperfunctionsc_class.isochPacketDescriptors[j].Length;
				}
				*/

				/*
				 
				!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
				
				sprintf_s(s, sizeof(s), "nvUSB.lib: desc.lenght=%d bytes descr.status=%x\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPacketDescriptors[j].Status);
				OutputDebugString((LPCSTR)s);

				for ECGUSB1D-EX get
				nvUSB.lib: desc.lenght=2 bytes descr.status=0           if OK
				nvUSB.lib: desc.lenght=0 bytes descr.status=c0020000    if empty packet

				WD_USBD_STATUS_ISO_NOT_ACCESSED_BY_HW

				Extended isochronous error codes returned by USBD.
				These errors appear in the packet status field of an isochronous transfer. [0xC0020000] 
				For some reason the controller did not access the TD associated with this packet:


				!
				When the USB driver stack processes the URB, the driver discards all isochronous packets in the URB whose frame numbers are lower than the current frame number. 
				The driver stack sets the Status member of the packet descriptor for each discarded packet to USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW, 
				or USBD_STATUS_ISO_NOT_ACCESSED_LATE. Even though some packets in the URB are discarded, the driver stack attempts to transmit only those packets whose frame numbers 
				are higher than the current frame number.
				!!

				*/

				if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPacketDescriptors[j].Status == 0)
				{
					WriteRingBuffer(
						helperfunctionsc_class.m_DataRingBuffer,
						(helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset),
						helperfunctionsc_class.isochPacketDescriptors[j].Length
					);
				}
			}

			sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Requested %d bytes in %d packets per transfer.\n", helperfunctionsc_class.IsochInTransferSize, helperfunctionsc_class.IsochInPacketCount);
			OutputDebugString((LPCSTR)s);
		}

		sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Transfer %d completed. Read %d bytes. \n", i + 1, numBytes);
		OutputDebugString((LPCSTR)s);

		
		result = WinUsb_ReadIsochPipeAsap(
			helperfunctionsc_class.isochReadBufferHandle,
			helperfunctionsc_class.IsochInTransferSize * i,
			helperfunctionsc_class.IsochInTransferSize,
			ContinueStream,
			helperfunctionsc_class.IsochInPacketCount,
			&helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount],
			&helperfunctionsc_class.overlapped[i]);
		

		/*
		// not working 
		// return with nvUSB.lib: bRead() Failed to read with error 1f  after first time..
		result = WinUsb_ReadIsochPipe(
			helperfunctionsc_class.isochReadBufferHandle,
			helperfunctionsc_class.IsochInTransferSize * i,
			helperfunctionsc_class.IsochInTransferSize,
			&startFrame,
			helperfunctionsc_class.IsochInPacketCount,
			&helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount],
			&helperfunctionsc_class.overlapped[i]);
		*/

		if (!result)
		{
			lastError = GetLastError();

			if (lastError == ERROR_INVALID_PARAMETER && ContinueStream)
			{
				ContinueStream = FALSE;
				continue;
			}

			if (lastError != ERROR_IO_PENDING)
			{
				sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to start a read operation with error %x\n", lastError);
				OutputDebugString((LPCSTR)s);

				return UsbPCECG_ERR_READISOBUFF;
			}

			ContinueStream = TRUE;
		}

	}

	return(Status);

#endif

}


/*
//-----------------------------------------------------------------------------
// GetDeviceHandle()
//
// Parameters:
//        guidDeviceInterface: DEVICE GUID defined in WinUSB inf file
//        hDeviceHandle		 : device handle returned
//
// Return Values:
//        true : success
//        false: fail
//
// Remarks:
//        Function to create file handle for USB device
//-----------------------------------------------------------------------------
*/

BOOL CUsbPCECGHelper::GetDeviceHandle(GUID guidDeviceInterface, PHANDLE hDeviceHandle)
{
	char s[256];

#if(1)
	HRESULT								result;
	HDEVINFO							deviceInfo;
	SP_DEVINFO_DATA						deviceInfoData;
	SP_DEVICE_INTERFACE_DATA			deviceInterfaceData;
	SP_DRVINFO_DATA_A					DriverInfo;
	PSP_DEVICE_INTERFACE_DETAIL_DATA	interfaceDetailData;
	ULONG								requiredLength;
	LPTSTR								devicePath;
	size_t								length;
	BOOL								ret = FALSE;

	result = S_OK;
	interfaceDetailData = NULL;
	requiredLength = 0;
	devicePath = NULL;

	deviceInfo = SetupDiGetClassDevs(
		&guidDeviceInterface,
		NULL,
		NULL, 
		DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
	);

	if (deviceInfo == INVALID_HANDLE_VALUE)
	{
		result = E_HANDLE;
	}

	if (SUCCEEDED(result))
	{
		// Check that a query for a second interface fails, but that the
		// first interface succeeds
		deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
		if (  !SetupDiEnumDeviceInfo(deviceInfo, 1, &deviceInfoData) 
			&& SetupDiEnumDeviceInfo(deviceInfo, 0, &deviceInfoData))
		{

			// Get the specific device interface
			deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
			if (!SetupDiEnumDeviceInterfaces(deviceInfo, &deviceInfoData,&guidDeviceInterface, 0, &deviceInterfaceData) )
			{
				result = HRESULT_FROM_WIN32(GetLastError());

				sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDeviceInterfaces failed %d.\n", result);
				OutputDebugString((LPCSTR)s);
			}

			// Check the size needed for the device interface details and 
			// allocate the data needed to get the details
			if (   SUCCEEDED(result) 
				&& !SetupDiGetDeviceInterfaceDetail(deviceInfo,&deviceInterfaceData, NULL, 0, &requiredLength, NULL))
			{
				if     (GetLastError() == ERROR_INSUFFICIENT_BUFFER 
					&& requiredLength > 0)
				{
					interfaceDetailData =(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, (SIZE_T)requiredLength);
					if (interfaceDetailData == NULL)
					{
						result = E_OUTOFMEMORY;
					}
					else
					{
						result = S_OK;
					}
				}
				else
				{
					result = HRESULT_FROM_WIN32(GetLastError());
				}
			}

			// Get the device interface details
			if (SUCCEEDED(result) && interfaceDetailData != NULL)
			{
				interfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
				if (!SetupDiGetDeviceInterfaceDetail(deviceInfo,&deviceInterfaceData, interfaceDetailData,requiredLength, NULL, &deviceInfoData))
				{
					result = HRESULT_FROM_WIN32(GetLastError());

					sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiGetDeviceInterfaceDetail failed %d.\n", result);
					OutputDebugString((LPCSTR)s);
				}
			}
			if (SUCCEEDED(result) && interfaceDetailData != NULL)
			{
				// Build the null terminated device path for the device
				length = _tcslen(interfaceDetailData->DevicePath) + 1;
				devicePath = (TCHAR*)LocalAlloc(LPTR, length * sizeof(TCHAR));
				if (devicePath != NULL)
				{
					StringCchCopy(devicePath, length,interfaceDetailData->DevicePath);
					devicePath[length - 1] = 0;

					sprintf_s(s, sizeof(s), "nvUSB.lib: Device path:  %s\n", devicePath);
					OutputDebugString((LPCSTR)s);

					//This what i get on Windows 10 as output:
					// nvUSB.lib: Device path:  \\?\usb#vid_10c4&pid_825f#7&1b060a7f&0&3#{93bd88a4-eb10-4706-8304-c512f18b8e42}

					//------------------ Get winusb driver version -----------------------------------------------------------
					if (!SetupDiBuildDriverInfoList(deviceInfo, &deviceInfoData, SPDIT_COMPATDRIVER))
					{
						result = HRESULT_FROM_WIN32(GetLastError());

						sprintf_s(s, sizeof(s), "nvUSB.lib:  SetupDiBuildDriverInfoList failed %d.\n", result);
						OutputDebugString((LPCSTR)s);

					}
					else
					{
						DriverInfo.cbSize = sizeof(SP_DRVINFO_DATA_A);
						if ((SetupDiEnumDriverInfoA(deviceInfo, &deviceInfoData, SPDIT_COMPATDRIVER, 0, &DriverInfo)))
						{
							sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDriverInfoA \n");
							OutputDebugString((LPCSTR)s);

							sprintf_s(s, sizeof(s), "nvUSB.lib: winusb driver version %s v.%u.%u.%u.%u\n",
								DriverInfo.Description,
								(DWORD32)(DriverInfo.DriverVersion >> 48) & 0xFFFF,
								(DWORD32)(DriverInfo.DriverVersion >> 32) & 0xFFFF,
								(DWORD32)(DriverInfo.DriverVersion >> 16) & 0xFFFF,
								(DWORD32)(DriverInfo.DriverVersion >> 0) & 0xFFFF

							);
							OutputDebugString((LPCSTR)s);

							drvver.MajorVersion = (WORD)(DriverInfo.DriverVersion >> 48) & 0xFFFF;
							drvver.MinorVersion = (WORD)(DriverInfo.DriverVersion >> 32) & 0xFFFF;
							drvver.BuildVersion = (WORD)(DriverInfo.DriverVersion >> 16) & 0xFFFF;
						}
						else
						{
							result = HRESULT_FROM_WIN32(GetLastError());

							sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDriverInfoA failed %d.\n", result);
							OutputDebugString((LPCSTR)s);
						}
					}
					//-------------------------------------------------------------------------------------------------------------
				}
				else
				{
					result = E_OUTOFMEMORY;
				}
			}
		}
	}

	if (SUCCEEDED(result) && devicePath != NULL)
	{
		ret = TRUE;

		// Open the device handle
		*hDeviceHandle = CreateFile(
			devicePath, 
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
			OPEN_EXISTING, 
			FILE_FLAG_OVERLAPPED, 
			NULL
		);
		if (*hDeviceHandle == INVALID_HANDLE_VALUE)
		{
			result = HRESULT_FROM_WIN32(GetLastError());

			sprintf_s(s, sizeof(s), "nvUSB.lib: CreateFile failed %d.\n", result);
			OutputDebugString((LPCSTR)s);

			ret = FALSE;
		}
	}

	// Perform cleanup of the allocated data
	if (devicePath != NULL)
	{
		LocalFree(devicePath);
	}
	if (interfaceDetailData != NULL)
	{
		LocalFree(interfaceDetailData);
	}
	if (deviceInfo != INVALID_HANDLE_VALUE)
	{
		(void)SetupDiDestroyDeviceInfoList(deviceInfo);
	}

	
	return ret;

#endif

#if(0)
	
	BOOL bResult = TRUE;
	HDEVINFO hDeviceInfo;
	SP_DEVINFO_DATA DeviceInfoData;
	SP_DRVINFO_DATA_A DriverInfo;
	DriverInfo.cbSize = sizeof(SP_DRVINFO_DATA_A);

	SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
	PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;

	ULONG requiredLength = 0;

	LPTSTR lpDevicePath = NULL;

	DWORD index = 0;


	sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to GetDeviceHandle\n");
	OutputDebugString((LPCSTR)s);

//	if (guidDeviceInterface == GUID_NULL) {
//		return FALSE;
//	}


	// Get information about all the installed devices for the specified
	// device interface class.
	hDeviceInfo = SetupDiGetClassDevs(
		&guidDeviceInterface,
		NULL,
		NULL,
		DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

	if (hDeviceInfo == INVALID_HANDLE_VALUE) {
		// ERROR 
		sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiGetClassDevs: %d.\n", GetLastError());
		OutputDebugString((LPCSTR)s);

		bResult = FALSE;
		goto done;
	}

	//Enumerate all the device interfaces in the device information set.
	DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);



	for (index = 0; SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData); index++) {
		
		//Reset for this iteration
		if (lpDevicePath) 
		{
			LocalFree(lpDevicePath);
			lpDevicePath = NULL;
		}

		if (pInterfaceDetailData) 
		{
			LocalFree(pInterfaceDetailData);
			pInterfaceDetailData = NULL;
		}

		// Check if last item
		if (GetLastError() == ERROR_NO_MORE_ITEMS) 
		{
			break;
		}

		deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);

		//Get information about the device interface.
		bResult = SetupDiEnumDeviceInterfaces(
			hDeviceInfo,
			&DeviceInfoData,
			&guidDeviceInterface,
			index,
			&deviceInterfaceData);

		bResult = SetupDiEnumDeviceInterfaces(
			hDeviceInfo,
			&DeviceInfoData,
			&guidDeviceInterface,
			index,
			&deviceInterfaceData);


		// Check if last item
		if (GetLastError() == ERROR_NO_MORE_ITEMS) 
		{
			sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDeviceInterfaces ERROR_NO_MORE_ITEMS (%d) \n", index);
			OutputDebugString((LPCSTR)s);

			break;
		}

		//Check for some other error
		if (!bResult) {

			sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
			OutputDebugString((LPCSTR)s);

			bResult = FALSE;
			goto done;
		}

		//Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA
		//which we need to allocate, so we have to call this function twice.
		//First to get the size so that we know how much to allocate
		//Second, the actual call with the allocated buffer

		bResult = SetupDiGetDeviceInterfaceDetail(
			hDeviceInfo,
			&deviceInterfaceData,
			NULL, 0,
			&requiredLength,
			NULL);


		//Check for some other error
		if (!bResult) {
			if ((ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (requiredLength > 0)) {
				//we got the size, allocate buffer
				pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredLength);

				if (!pInterfaceDetailData) {
					// ERROR 
					//printf("Error allocating memory for the device detail buffer.\n");
					sprintf_s(s, sizeof(s), "nvUSB.lib: Error allocating memory for the device detail buffer.\n");
					OutputDebugString((LPCSTR)s);

					bResult = FALSE;
					goto done;
				}
			}
			else {
				//printf("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
				sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
				OutputDebugString((LPCSTR)s);

				bResult = FALSE;
				goto done;
			}
		}

		//get the interface detailed data
		pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

		//Now call it with the correct size and allocated buffer
		bResult = SetupDiGetDeviceInterfaceDetail(
			hDeviceInfo,
			&deviceInterfaceData,
			pInterfaceDetailData,
			requiredLength,
			NULL,
			&DeviceInfoData);


		//Check for some other error
		if (!bResult) {
			//printf("Error SetupDiGetDeviceInterfaceDetail: %d.\n", GetLastError());
			sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiGetDeviceInterfaceDetail: %d.\n", GetLastError());
			OutputDebugString((LPCSTR)s);

			bResult = FALSE;
			goto done;
		}

		if (!SetupDiBuildDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_COMPATDRIVER))
		{
			sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiBuildDriverInfoList: %d.\n", GetLastError());
			OutputDebugString((LPCSTR)s);

		}
		else
		{
			if ((SetupDiEnumDriverInfoA(hDeviceInfo, &DeviceInfoData, SPDIT_COMPATDRIVER, index, &DriverInfo)) != FALSE)
			{
				sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDriverInfoA \n");
				OutputDebugString((LPCSTR)s);

				sprintf_s(s, sizeof(s), "nvUSB.lib: winusb driver version %s v.%u.%u.%u.%u\n",
					DriverInfo.Description,
					(DWORD32)(DriverInfo.DriverVersion >> 48) & 0xFFFF,
					(DWORD32)(DriverInfo.DriverVersion >> 32) & 0xFFFF,
					(DWORD32)(DriverInfo.DriverVersion >> 16) & 0xFFFF,
					(DWORD32)(DriverInfo.DriverVersion >> 0) & 0xFFFF

				);
				OutputDebugString((LPCSTR)s);

				drvver.MajorVersion = (WORD)(DriverInfo.DriverVersion >> 48) & 0xFFFF;
				drvver.MinorVersion = (WORD)(DriverInfo.DriverVersion >> 32) & 0xFFFF;
				drvver.BuildVersion = (WORD)(DriverInfo.DriverVersion >> 16) & 0xFFFF;

				//copy device path
				size_t nLength = _tcslen(pInterfaceDetailData->DevicePath) + 1;
				lpDevicePath = (TCHAR*)LocalAlloc(LPTR, nLength * sizeof(TCHAR));
				StringCchCopy(lpDevicePath, nLength, pInterfaceDetailData->DevicePath);
				lpDevicePath[nLength - 1] = 0;

				sprintf_s(s, sizeof(s), "nvUSB.lib: Device path:  %s\n", lpDevicePath);
				OutputDebugString((LPCSTR)s);
				
				//This what i get on Windows 10 as output:
				// nvUSB.lib: Device path:  \\?\usb#vid_10c4&pid_825f#7&1b060a7f&0&3#{93bd88a4-eb10-4706-8304-c512f18b8e42}


				break; //connect to to only one device
			}
		}

	}//for (index = 0; SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData); index++)

	if (!lpDevicePath) {
		//Error.
		//printf("Error %d.", GetLastError());
		sprintf_s(s, sizeof(s), "nvUSB.lib: lpDevicePath Error %d.\n", GetLastError());
		OutputDebugString((LPCSTR)s);

		bResult = FALSE;
		goto done;
	}

	//Open the device
	*hDeviceHandle = CreateFile(
		lpDevicePath,
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_OVERLAPPED,
		NULL);

	if (*hDeviceHandle == INVALID_HANDLE_VALUE) {
		//Error.
		//printf("Error %d.", GetLastError());
		sprintf_s(s, sizeof(s), "nvUSB.lib: CreateFile Error %d.\n", GetLastError());
		OutputDebugString((LPCSTR)s);

		bResult = FALSE;
		goto done;
	}



done:

	if (lpDevicePath) {
		LocalFree(lpDevicePath);
	}

	if (pInterfaceDetailData) {
		LocalFree(pInterfaceDetailData);
	}


	if (!bResult)
	{
		if (hDeviceInfo != INVALID_HANDLE_VALUE)
			SetupDiDestroyDeviceInfoList(hDeviceInfo);
	}
	else
	{
		if (hDeviceInfo != INVALID_HANDLE_VALUE)
			bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo);
	}

	sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetDeviceHandle\n");
	OutputDebugString((LPCSTR)s);

	return bResult;

#endif

} // End of GetDeviceHandle()


/*
//-----------------------------------------------------------------------------
// GetWinUSBHandle()
//
// Parameters:
//        hDeviceHandle  : device handle created for the USB device
//        phWinUSBHandle : WinUSB Interface handle returned
//
// Return Values:
//        true : success
//        false: fail
//
// Remarks:
//        Function to get WinUSB Interface Handle for the device
//-----------------------------------------------------------------------------
*/

BOOL CUsbPCECGHelper::GetWinUSBHandle(HANDLE hDeviceHandle, PWINUSB_INTERFACE_HANDLE phWinUSBHandle)
{
	char s[256];
	BOOL bResult = FALSE;

	sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to GetWinUSBHandle\n");
	OutputDebugString((LPCSTR)s);

	if (hDeviceHandle == INVALID_HANDLE_VALUE) 
	{
		sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetWinUSBHandle (hDeviceHandle not valid) \n");
		OutputDebugString((LPCSTR)s);
		return FALSE;
	}

	/*
	[in] DeviceHandle
	The handle to the device that CreateFile returned.WinUSB uses overlapped I / O, so FILE_FLAG_OVERLAPPED must be specified in 
	the dwFlagsAndAttributes parameter of CreateFile call for DeviceHandle to have the characteristics necessary for 
	WinUsb_Initialize to function properly.

	[out] InterfaceHandle
	Receives an opaque handle to the first(default) interface on the device.This handle is required by other WinUSB routines that 
	perform operations on the default interface.To release the handle, call the WinUSB_Free function.

	WinUsb_Initialize returns TRUE if the operation succeeds. Otherwise, this routine returns FALSE, and the caller can retrieve the logged 
	error by calling GetLastError.
	*/

	bResult = WinUsb_Initialize(hDeviceHandle, phWinUSBHandle);
	if (!bResult) 
	{
		//Error.
		//printf("WinUsb_Initialize Error %d.", GetLastError());
		sprintf_s(s, sizeof(s), "nvUSB.lib: WinUsb_Initialize Error %d.", GetLastError());
		OutputDebugString((LPCSTR)s);
		return FALSE;
	}


	sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetWinUSBHandle \n");
	OutputDebugString((LPCSTR)s);

	return bResult;
} // End of GetWinUSBHandle()



/*
//-----------------------------------------------------------------------------
// GetUSBDeviceSpeed()
//
// Parameters:
//        hDeviceHandle  : WinUSB Interface Handle
//        pDeviceSpeed   : Device Speed returned
//
// Return Values:
//        true : success
//        false: fail
//
// Remarks:
//        Function to get device speed
//-----------------------------------------------------------------------------
*/

BOOL CUsbPCECGHelper::GetUSBDeviceSpeed(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pDeviceSpeed)
{
	char s[256];

	sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to GetUSBDeviceSpeed() \n");
	OutputDebugString((LPCSTR)s);

	if (!pDeviceSpeed || hDeviceHandle == INVALID_HANDLE_VALUE) {
		return FALSE;
	}

	BOOL bResult = TRUE;

	ULONG length = sizeof(UCHAR);

	bResult = WinUsb_QueryDeviceInformation(hDeviceHandle, DEVICE_SPEED, &length, pDeviceSpeed);
	if (!bResult) {

		sprintf_s(s, sizeof(s), "nvUSB.lib: Error getting device speed: %d.\n", GetLastError());
		OutputDebugString((LPCSTR)s);

		goto done;
	}

	/*
	if (*pDeviceSpeed == LowSpeed) {

		sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (Low speed).\n", *pDeviceSpeed);
		OutputDebugString((LPCSTR)s);

		goto done;
	}

	if (*pDeviceSpeed == FullSpeed) {

		sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (Full speed).\n", *pDeviceSpeed);
		OutputDebugString((LPCSTR)s);

		goto done;
	}
	*/

	if (*pDeviceSpeed == 1) {

		//---!! printf("Device speed: %d - Full speed or lower (initial documentation on MSDN was wrong).\n", *pDeviceSpeed);
		sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (Full speed or lower).\n", *pDeviceSpeed);
		OutputDebugString((LPCSTR)s);

		goto done;
	}

	if (*pDeviceSpeed == HighSpeed) {

		sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (High speed).\n", *pDeviceSpeed);
		OutputDebugString((LPCSTR)s);

		goto done;
	}

	sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetUSBDeviceSpeed() \n");
	OutputDebugString((LPCSTR)s);
done:
	return bResult;
} // End of GetUSBDeviceSpeed()



/*
//-----------------------------------------------------------------------------
// QueryDeviceEndpoints()
//
// Parameters:
//        hDeviceHandle  : WinUSB Interface Handle
//        pipeid		 : Pipe ID returned
//
// Return Values:
//        true : success
//        false: fail
//
// Remarks:
//        Function to check end points and get pipe ID
//-----------------------------------------------------------------------------
*/

BOOL CUsbPCECGHelper::QueryDeviceEndpoints(WINUSB_INTERFACE_HANDLE hDeviceHandle, PIPE_ID* pipeid)
{
	char s[256];

	sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to QueryDeviceEndpoints() \n");
	OutputDebugString((LPCSTR)s);

	if (hDeviceHandle == INVALID_HANDLE_VALUE) {
		return FALSE;
	}

	BOOL bResult = TRUE;

	USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
	ZeroMemory(&InterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR));

	WINUSB_PIPE_INFORMATION_EX Pipe; ZeroMemory(&Pipe, sizeof(WINUSB_PIPE_INFORMATION_EX));
	//WINUSB_PIPE_INFORMATION  Pipe;	 ZeroMemory(&Pipe, sizeof(WINUSB_PIPE_INFORMATION));
	
	bResult = WinUsb_QueryInterfaceSettings(hDeviceHandle, 0, &InterfaceDescriptor);

	if (bResult) {
		for (int index = 0; index < InterfaceDescriptor.bNumEndpoints; index++) {
			bResult = WinUsb_QueryPipeEx(hDeviceHandle, 0, index, &Pipe);
			//bResult = WinUsb_QueryPipe(hDeviceHandle, 0, index, &Pipe);

			if (bResult) {
				if (Pipe.PipeType == UsbdPipeTypeControl) {

					if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) {

						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Control IN Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						
					}

					if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) {

						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Control OUT Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						
					}
				}

				if (Pipe.PipeType == UsbdPipeTypeIsochronous) {

					if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) {

						//Printout for ECGUSB1D-EX :
						//nvUSB.lib: Endpoint index: 0 Pipe type: Isochronous IN Pipe ID: 129.
						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Isochronous IN Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						pipeid->Iso_Pipe[0].PipeType = Pipe.PipeType;
						pipeid->Iso_Pipe[0].PipeId = Pipe.PipeId;
						pipeid->Iso_Pipe[0].Interval = Pipe.Interval;
						pipeid->Iso_Pipe[0].MaximumPacketSize = Pipe.MaximumPacketSize;
						pipeid->Iso_Pipe[0].index = index;
						pipeid->Iso_Pipe[0].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval;

						//Printout for ECGUSB1D-EX :
						//nvUSB.lib: Type=1 , Interval=1 , MaximumPacketSize=24 ,MaximumBytesPerInterval=24
						sprintf_s(s, sizeof(s), "nvUSB.lib: Type=%d , Interval=%d , MaximumPacketSize=%d ,MaximumBytesPerInterval=%d\n", 
						Pipe.PipeType,
						Pipe.Interval,
						Pipe.MaximumPacketSize,
						Pipe.MaximumBytesPerInterval
						);
						OutputDebugString((LPCSTR)s);

						/*
						MaximumPacketSize
						The maximum size, in bytes, of the packets that are transmitted on the pipe.

						MaximumBytesPerInterval
						The maximum number of bytes that can be transmitted in single interval. This value may be a larger than 
						the MaximumPacketSize value on high-bandwidth, high-speed periodic endpoints and SuperSpeed periodic endpoints, 
						such as isochronous endpoints.
						*/

					}

					if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) {

						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Isochronous OUT Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						pipeid->Iso_Pipe[1].PipeType = Pipe.PipeType;
						pipeid->Iso_Pipe[1].PipeId = Pipe.PipeId;
						pipeid->Iso_Pipe[1].Interval = Pipe.Interval;
						pipeid->Iso_Pipe[1].MaximumPacketSize = Pipe.MaximumPacketSize;
						pipeid->Iso_Pipe[1].index = index;
						pipeid->Iso_Pipe[1].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval;
					}

				}

				if (Pipe.PipeType == UsbdPipeTypeBulk) {

					if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) {

						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Bulk IN Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						pipeid->Bulk_Pipe[0].PipeType = Pipe.PipeType;
						pipeid->Bulk_Pipe[0].PipeId = Pipe.PipeId;
						pipeid->Bulk_Pipe[0].Interval = Pipe.Interval;
						pipeid->Bulk_Pipe[0].MaximumPacketSize = Pipe.MaximumPacketSize;
						pipeid->Bulk_Pipe[0].index = index;
						pipeid->Bulk_Pipe[0].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval;
					}

					if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) {

						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Bulk OUT Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						pipeid->Bulk_Pipe[1].PipeType = Pipe.PipeType;
						pipeid->Bulk_Pipe[1].PipeId = Pipe.PipeId;
						pipeid->Bulk_Pipe[1].Interval = Pipe.Interval;
						pipeid->Bulk_Pipe[1].MaximumPacketSize = Pipe.MaximumPacketSize;
						pipeid->Bulk_Pipe[1].index = index;
						pipeid->Bulk_Pipe[1].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval;
					}

				}

				if (Pipe.PipeType == UsbdPipeTypeInterrupt) {

					if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) {

						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Int IN Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						pipeid->Int_Pipe[0].PipeType = Pipe.PipeType;
						pipeid->Int_Pipe[0].PipeId = Pipe.PipeId;
						pipeid->Int_Pipe[0].Interval = Pipe.Interval;
						pipeid->Int_Pipe[0].MaximumPacketSize = Pipe.MaximumPacketSize;
						pipeid->Int_Pipe[0].index = index;
						pipeid->Int_Pipe[0].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval;
					}

					if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) {

						sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Int OUT Pipe ID: %d.\n", index,  Pipe.PipeId);
						OutputDebugString((LPCSTR)s);

						pipeid->Int_Pipe[1].PipeType = Pipe.PipeType;
						pipeid->Int_Pipe[1].PipeId = Pipe.PipeId;
						pipeid->Int_Pipe[1].Interval = Pipe.Interval;
						pipeid->Int_Pipe[1].MaximumPacketSize = Pipe.MaximumPacketSize;
						pipeid->Int_Pipe[1].index = index;
						pipeid->Int_Pipe[1].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval;
					}
				}
			}
			else {
				continue;
			}
		}
	}

	//done:
	return bResult;
} // End of QueryDeviceEndpoints()



PRING_BUFFER
CUsbPCECGHelper::AllocRingBuffer(
	SIZE_T    Size
)
{
	PRING_BUFFER   ringBuffer = NULL;


	ringBuffer = new RING_BUFFER[sizeof(RING_BUFFER)];

	if (!ringBuffer)
		return NULL;

	ringBuffer->buffer = new UCHAR[Size];

	if (!ringBuffer->buffer)
	{
		free(ringBuffer);
		return NULL;
	}


	ringBuffer->Size = Size;
	ringBuffer->Base = ringBuffer->buffer;
	ringBuffer->End = ringBuffer->buffer + Size;
	ringBuffer->Head = ringBuffer->buffer;
	ringBuffer->Tail = ringBuffer->buffer;

	ringBuffer->inPtr = ringBuffer->buffer;
	ringBuffer->outPtr = ringBuffer->buffer;
	ringBuffer->totalSize = Size;
	ringBuffer->currentSize = 0;

//	KeInitializeSpinLock(&ringBuffer->spinLock);

	return ringBuffer;
}

VOID
CUsbPCECGHelper::FreeRingBuffer(
	PRING_BUFFER   ringBuffer
)
{
	free(ringBuffer->buffer);
	free(ringBuffer);
}


VOID
CUsbPCECGHelper::RingBufferGetAvailableSpace(
	PRING_BUFFER      ringBuffer,
	SIZE_T* AvailableSpace
)
{
	PUCHAR headSnapshot = NULL;
	PUCHAR tailSnapshot = NULL;
	PUCHAR tailPlusOne = NULL;

	if (!AvailableSpace)   return;
	//   ASSERT(AvailableSpace);

	   //
	   // Take a snapshot of the head and tail pointers. We will compute the
	   // available space based on this snapshot. This is safe to do in a
	   // single-producer, single-consumer model, because -
	   //     * A producer will call GetAvailableSpace() to determine whether
	   //       there is enough space to write the data it is trying to write.
	   //       The only other thread that could modify the amount of space
	   //       available is the consumer thread, which can only increase the
	   //       amount of space available. Hence it is safe for the producer
	   //       to write based on this snapshot.
	   //     * A consumer thread will call GetAvailableSpace() to determine
	   //       whether there is enough data in the buffer for it to read.
	   //       (Available data = Buffer size - Available space). The only
	   //       other thread that could modify the amount of space available
	   //       is the producer thread, which can only decrease the amount of
	   //       space available (thereby increasing the amount of data
	   //       available. Hence it is safe for the consumer to read based on
	   //       this snapshot.
	   //
	headSnapshot = ringBuffer->Head;
	tailSnapshot = ringBuffer->Tail;

	//
	// In order to distinguish between a full buffer and an empty buffer,
	// we always leave the last byte of the buffer unused. So, an empty
	// buffer is denoted by -
	//      tail == head
	// ... and a full buffer is denoted by -
	//      (tail+1) == head
	//
	tailPlusOne = ((tailSnapshot + 1) == ringBuffer->End) ? ringBuffer->Base : (tailSnapshot + 1);

	if (tailPlusOne == headSnapshot)
	{
		//
		// Buffer full
		//
		*AvailableSpace = 0;
	}
	else if (tailSnapshot == headSnapshot)
	{
		//
		// Buffer empty
		// The -1 in the computation below is to account for the fact that
		// we always leave the last byte of the ring buffer unused in order
		// to distinguish between an empty buffer and a full buffer.
		//
		*AvailableSpace = ringBuffer->Size - 1;
	}
	else
	{
		if (tailSnapshot > headSnapshot)
		{
			//
			// Data has not wrapped around the end of the buffer
			// The -1 in the computation below is to account for the fact
			// that we always leave the last byte of the ring buffer unused
			// in order to distinguish between an empty buffer and a full
			// buffer.
			//
			*AvailableSpace = ringBuffer->Size - (tailSnapshot - headSnapshot) - 1;
		}
		else
		{
			//
			// Data has wrapped around the end of the buffer
			// The -1 in the computation below is to account for the fact
			// that we always leave the last byte of the ring buffer unused
			// in order to distinguish between an empty buffer and a full
			// buffer.
			//
			*AvailableSpace = (headSnapshot - tailSnapshot) - 1;
		}
	}
}


VOID
CUsbPCECGHelper::RingBufferGetAvailableData(
	PRING_BUFFER      ringBuffer,
	SIZE_T* AvailableData
)
{
	SIZE_T   availableSpace;
//	KIRQL    oldIrql;

	if (!AvailableData)   return;
	//ASSERT(AvailableData);

//	KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
	RingBufferGetAvailableSpace(ringBuffer, &availableSpace);
//	KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);

	//
	// The -1 in the arithmetic below accounts for the fact that we always
	// keep 1 byte of the ring buffer unused in order to distinguish
	// between a full buffer and an empty buffer.
	//
	*AvailableData = ringBuffer->Size - availableSpace - 1;
}








SIZE_T
CUsbPCECGHelper::ReadRingBuffer(
	PRING_BUFFER   ringBuffer,
	PUCHAR         readBuffer,
	SIZE_T        numberOfBytesToRead
)
/*
   Routine Description:
   This routine reads data from a ring buffer.

   Arguments:
   ringBuffer - pointer to a ring buffer structure
   readBuffer - pointer to a user supplied buffer to transfer data into
   numberOfBytesToRead - number of bytes to read from the ring buffer

   Return Value:
   ULONG - number of bytes read.  May be smaller than requested number of bytes.
*/
{

	SIZE_T   byteCount;
//	KIRQL    oldIrql;
	SIZE_T   l_currentsize;

//	KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
	l_currentsize = ringBuffer->currentSize;
//	KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);

//	MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() enter\n"));

	if (numberOfBytesToRead > ringBuffer->totalSize)
		return 0;

	if (l_currentsize == 0)
		return 0;

	if (numberOfBytesToRead > l_currentsize)
		byteCount = l_currentsize;
	else
		byteCount = numberOfBytesToRead;

	//
	// two cases.  Read either wraps or it doesn't.
	// Handle the non-wrapped case first
	//
	if ((ringBuffer->outPtr + byteCount - 1) < (ringBuffer->buffer + ringBuffer->totalSize))
	{
//		MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() about to copy a\n"));
		RtlCopyMemory(readBuffer, ringBuffer->outPtr, byteCount);
		ringBuffer->outPtr += byteCount;
		if (ringBuffer->outPtr == ringBuffer->buffer + ringBuffer->totalSize)
			ringBuffer->outPtr = ringBuffer->buffer;
	}
	// now handle the wrapped case
	else
	{
		//ULONG    fragSize;
		 //Boris, 18.04.2021 (Get error: conversion from '__int64' to 'ULONG', possible loss of data)
		SIZE_T    fragSize;

//		MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() about to copy b\n"));

		// get the first half of the read
		//Boris, 16.02.2009 ,WDK 6001.18002 build
		//fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->outPtr;
		//fragSize = ringBuffer->totalSize + (ULONG)(ringBuffer->buffer - ringBuffer->outPtr);
		//Boris, 18.04.2021 
		fragSize = (ringBuffer->totalSize + ringBuffer->buffer) - ringBuffer->outPtr;

		RtlCopyMemory(readBuffer, ringBuffer->outPtr, fragSize);

		// now get the rest
		RtlCopyMemory(readBuffer + fragSize, ringBuffer->buffer, byteCount - fragSize);

		ringBuffer->outPtr = ringBuffer->buffer + byteCount - fragSize;
	}

	//
	// update the current size of the ring buffer.  Use spinlock to insure
	// atomic operation.
	//
//	KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
	ringBuffer->currentSize -= byteCount;
//	KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);

//	MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() exit\n"));

	return byteCount;


	/*
		SIZE_T                  availableData=0;
		SIZE_T                  dataFromCurrToEnd;
		SIZE_T                  DataSize=0;
		SIZE_T                  BytesCopied = 0;

		if(!readBuffer)                                             return 0;
		if (numberOfBytesToRead == 0)                               return 0;
		if (ringBuffer->Head >= ringBuffer->End)                    return 0;

		//
		// Get the amount of data available in the buffer
		//
		RingBufferGetAvailableData(ringBuffer, &availableData);

		if (availableData == 0)                                    return 0;

		DataSize = numberOfBytesToRead;

		if (DataSize > availableData)
		{
			DataSize = availableData;
		}

		BytesCopied = DataSize;

		if ((ringBuffer->Head + DataSize) > ringBuffer->End)
		{
			//
			// The data requested by the caller is wrapped around the end of the
			// buffer. So we'll do the copy in two steps -
			//    * Copy X bytes from the current position to the end buffer into
			//      the caller's buffer
			//    * Copy (DataSize - X) bytes from the beginning to the buffer into
			//      the caller's buffer
			//

			//
			// The first step of the copy ...
			//
			dataFromCurrToEnd = ringBuffer->End - ringBuffer->Head;
			RtlCopyMemory(readBuffer, ringBuffer->Head, dataFromCurrToEnd);
			readBuffer += dataFromCurrToEnd;
			DataSize   -= dataFromCurrToEnd;

			//
			// The second step of the copy ...
			//
			RtlCopyMemory(readBuffer, ringBuffer->Base, DataSize);

			//
			// Advance the head pointer
			//
			ringBuffer->Head = ringBuffer->Base + DataSize;
		}
		else
		{
			//
			// The data in the buffer is NOT wrapped around the end of the buffer.
			// Simply copy the data over to the caller's buffer in a single step.
			//
			RtlCopyMemory(readBuffer, ringBuffer->Head, DataSize);

			//
			// Advance the head pointer
			//
			ringBuffer->Head += DataSize;
			if (ringBuffer->Head == ringBuffer->End)
			{
				//
				// We have exactly reached the end of the buffer. The next
				// read should wrap around and start from the beginning.
				//
				ringBuffer->Head = ringBuffer->Base;
			}
		}

		if (!(ringBuffer->Head < ringBuffer->End))                  return 0;

		return BytesCopied;

	*/
}

SIZE_T
CUsbPCECGHelper::WriteRingBuffer(
	PRING_BUFFER   ringBuffer,
	PUCHAR         writeBuffer,
	SIZE_T         numberOfBytesToWrite
)
/*
   Routine Description:
   This routine writes data to a ring buffer.  If the requested write size exceeds
   available space in the ring buffer, then the write is rejected.

   Arguments:
   ringBuffer - pointer to a ring buffer structure
   readBuffer - pointer to a user supplied buffer of data to copy to the ring buffer
   numberOfBytesToRead - number of bytes to write to the ring buffer

   Return Value:
   ULONG - number of bytes written.
*/
{
	SIZE_T   byteCount;
//	KIRQL    oldIrql;
	SIZE_T   l_currentsize;

//	KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
	l_currentsize = ringBuffer->currentSize;
//	KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);


	if (numberOfBytesToWrite > (ringBuffer->totalSize - l_currentsize))
	{
		//MarlinUSB_DbgPrint(1, ("Marlin.sys: WriteRingBuffer() OVERFLOW\n"));
		return 0;
	}

	byteCount = numberOfBytesToWrite;

	//
	// two cases.  Write either wraps or it doesn't.
	// Handle the non-wrapped case first
	//
	if ((ringBuffer->inPtr + byteCount - 1) < (ringBuffer->buffer + ringBuffer->totalSize))
	{
		RtlCopyMemory(ringBuffer->inPtr, writeBuffer, byteCount);
		ringBuffer->inPtr += byteCount;
		if (ringBuffer->inPtr == ringBuffer->buffer + ringBuffer->totalSize)
			ringBuffer->inPtr = ringBuffer->buffer;
	}
	// now handle the wrapped case
	else
	{
		//ULONG    fragSize;
		//Boris, 18.04.2021 (Get error: conversion from '__int64' to 'ULONG', possible loss of data)
		SIZE_T    fragSize;

		// write the first fragment
		//Boris, 16.02.2009 ,WDK 6001.18002 build
		//fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->inPtr;
		//fragSize = ringBuffer->totalSize + (ULONG)(ringBuffer->buffer - ringBuffer->inPtr);

		//Boris, 18.04.2021 (Get error: conversion from '__int64' to 'ULONG', possible loss of data)
		fragSize = (ringBuffer->totalSize + ringBuffer->buffer) - ringBuffer->inPtr;

		RtlCopyMemory(ringBuffer->inPtr, writeBuffer, fragSize);

		// now write the rest
		RtlCopyMemory(ringBuffer->buffer, writeBuffer + fragSize, byteCount - fragSize);

		ringBuffer->inPtr = ringBuffer->buffer + byteCount - fragSize;

	}

	//
	// update the current size of the ring buffer.  Use spinlock to insure
	// atomic operation.
	//
//	KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
	ringBuffer->currentSize += byteCount;
//	KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);

	//MarlinUSB_DbgPrint(1, ("Marlin.sys: WriteRingBuffer() %d bytes\n", byteCount));

	return byteCount;



	/*
		SIZE_T   availableSpace = 0;
		SIZE_T   spaceFromCurrToEnd;
		SIZE_T   bytesToCopy;
		SIZE_T   bytesCopied=0;
		KIRQL    oldIrql;

		if (!writeBuffer)                                           return 0;
		if (numberOfBytesToWrite == 0)                              return 0;
		if (ringBuffer->Tail >= ringBuffer->End)                    return 0;

		//
		// Get the amount of space available in the buffer
		//
		KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
		RingBufferGetAvailableSpace(ringBuffer, &availableSpace);
		KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);

		//
		// If there is not enough space to fit in all the data passed in by the
		// caller then copy as much as possible and throw away the rest
		//
		if (availableSpace < numberOfBytesToWrite)
		{
			bytesToCopy = availableSpace;
		}
		else
		{
			bytesToCopy = numberOfBytesToWrite;
		}

		bytesCopied = bytesToCopy;

		if (bytesToCopy)
		{
			//
			// The buffer has some space at least
			//
			if ((ringBuffer->Tail + bytesToCopy) > ringBuffer->End)
			{
				//
				// The data being written will wrap around the end of the buffer.
				// So the copy has to be done in two steps -
				// * X bytes from current position to end of the buffer
				// * the remaining (bytesToCopy - X) from the start of the buffer
				//

				//
				// The first step of the copy ...
				//
				spaceFromCurrToEnd = ringBuffer->End - ringBuffer->Tail;

				RtlCopyMemory(ringBuffer->Tail, writeBuffer, spaceFromCurrToEnd);

				writeBuffer += spaceFromCurrToEnd;

				bytesToCopy -= spaceFromCurrToEnd;

				//
				// The second step of the copy ...
				//
				RtlCopyMemory(ringBuffer->Base, writeBuffer, bytesToCopy);

				//
				// Advance the tail pointer
				//
				ringBuffer->Tail = ringBuffer->Base + bytesToCopy;
			}
			else
			{
				//
				// Data does NOT wrap around the end of the buffer. Just copy it
				// over in a single step
				//
				RtlCopyMemory(ringBuffer->Tail, writeBuffer, bytesToCopy);

				//
				// Advance the tail pointer
				//
				ringBuffer->Tail += bytesToCopy;
				if (ringBuffer->Tail == ringBuffer->End)
				{
					//
					// We have exactly reached the end of the buffer. The next
					// write should wrap around and start from the beginning.
					//
					ringBuffer->Tail = ringBuffer->Base;
				}
			}

		   if (!(ringBuffer->Tail < ringBuffer->End))                  return 0;

		}

		return bytesCopied;

		*/
}














//==========================================================================================================================================================

#define ISOCH_DATA_SIZE_MS 10
#define ISOCH_TRANSFER_COUNT 2    //will need to be at least 2

/*
* My device sends one sample of 2 bytes every 1ms .. => data sample rate = 1000s/s
*
* Problem !!
* Only Transfer 1 has the data all next (ISOCH_TRANSFER_COUNT) are empty
* As a result i see data arriving at sample rate of 1000 / ISOCH_TRANSFER_COUNT in Read application
*
* Why ?????
*
nvUSB.lib: Current Frame number=261744397
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes.
nvUSB.lib: Current Frame number=261744447
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. <-- ??
nvUSB.lib: Current Frame number=261744497
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes.
nvUSB.lib: Current Frame number=261744547
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. <--- ??
nvUSB.lib: Current Frame number=261744597
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes.
nvUSB.lib: Current Frame number=261744647
nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer.
nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes.
nvUSB.lib: Current Frame number=261744697

 

 

 

 

 

 

 

 

0 Replies