winusb driver - isochronous stream transmission get USBD_STATUS_ISO_NOT_ACCESSED_BY_HW from WinUsb_GetOverlappedResult() on all transmitions exept the first one

Boris Wainshtein 1 Reputation point
2021-11-28T08:37:47.46+00:00

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);  

endif

Windows Hardware Performance
Windows Hardware Performance
Windows: A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.Hardware Performance: Delivering / providing hardware or hardware systems or adjusting / adapting hardware or hardware systems.
1,546 questions
0 comments No comments
{count} votes