winusb driver - isochronous stream transmission get USBD_STATUS_ISO_NOT_ACCESSED_BY_HW from WinUsb_GetOverlappedResult() on all transmitions exept the first one
Hi,
We are using our own usb driver for our device transmitting analog data 2bytes per 1ms via iso pipe.
Driver written 15 years ago and in some PC's do not work properly.
I wanted to check possibility to work with winusb.sys driver.
I installed it OK, Can send commands via control pipes but when i start isochronous pipe stream i get USBD_STATUS_ISO_NOT_ACCESSED_BY_HW
error in "isochPacketDescriptors[j].Status" for all transfers exept the first one..
Here is a code
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
*/
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://learn.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
DWORD CUsbPCECGHelper::ReadIsoBuffer(DWORD eventIndex)
{
if(1)
/*
//for iso endpoints read this
//https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/getting-set-up-to-use-windows-devices-usb
//https://learn.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);