I have a device that attaches using the WinUSB driver and exposes a 16 byte Bulk in and a 16 byte Bulk out endpoint. The size of the messages, sent or received could be any arbitrary length (up to 64 bytes), but I don’t have enough RAM on my ?C to build to 64 byte buffers, consequently I have exchange all messages in 16 byte increments. This was first coded as:
success = WinUsb_ReadPipe(myDevInfo.winUsbHandle, _
pipeID, _
buffer, _
bytesToRead, _
bytesRead, _
IntPtr.Zero)
Where buffer is a byte array of size 64, and bytesToRead is ‘64’. Read pipe policies are set to IGNORE_SHORT_PACKETS = False, and Timeout = 2000 (2s). Attempting to receiving a 16 byte message resulted in an error 121=semaphore timeout. Using Don Miller’s WinUSB trace provider I generated the following trace:
[1]0F80.0CDC::06/09/2010-16:04:33.296 - IOCTL_WINUSB_WRITE_PIPE
[1]0F80.0CDC::06/09/2010-16:04:33.296 - PIPE1: (00000010) The write has been added to the write queue
[1]0F80.0CDC::06/09/2010-16:04:33.296 - PIPE1: (00000010) The write is being handled
[1]0F80.0CDC::06/09/2010-16:04:33.296 - PIPE1: (00000010) Writing 5 bytes to the device
[1]0F80.04F0::06/09/2010-16:04:33.296 - IOCTL_WINUSB_READ_PIPE
[1]0F80.04F0::06/09/2010-16:04:33.296 - PIPE129: (00000011) The read has been added to the read queue
[1]0F80.04F0::06/09/2010-16:04:33.296 - PIPE129: (00000011) The read for 64 bytes is being handled
[1]0F80.04F0::06/09/2010-16:04:33.296 - PIPE129: (00000011) Reading 64 bytes from the device
[1]0F80.0CDC::06/09/2010-16:04:43.780 - IOCTL_WINUSB_WRITE_PIPE
[1]0F80.0CDC::06/09/2010-16:04:43.780 - PIPE1: (00000012) The write has been added to the write queue
[1]0F80.0CDC::06/09/2010-16:04:43.780 - PIPE1: (00000012) The write is being handled
[1]0F80.0CDC::06/09/2010-16:04:43.780 - PIPE1: (00000012) Writing 15 bytes to the device
[1]0F80.0CDC::06/09/2010-16:04:48.061 - IOCTL_WINUSB_WRITE_PIPE
[1]0F80.0CDC::06/09/2010-16:04:48.061 - PIPE1: (00000014) The write has been added to the write queue
[1]0F80.0CDC::06/09/2010-16:04:48.061 - PIPE1: (00000014) The write is being handled
[1]0F80.0CDC::06/09/2010-16:04:48.061 - PIPE1: (00000014) Writing 16 bytes to the device
[1]0004.0180::06/09/2010-16:04:50.061 - PIPE129: (00000015) Request failed with status 0xc00000b5(STATUS_IO_TIMEOUT)
[1]0004.0180::06/09/2010-16:04:50.061 - PIPE129: (00000015) Read request for 64 bytes has completed with 16 bytes
[0]0000.0000::06/09/2010-16:04:33.296 - PIPE1: (00000010) Write request for 5 bytes has completed
[0]0F80.0CDC::06/09/2010-16:04:33.311 - PIPE129: (00000011) Transfer was terminated by a short packet
[0]0F80.0CDC::06/09/2010-16:04:33.311 - PIPE129: (00000011) Read request for 64 bytes has completed with 5 bytes
[0]0000.0000::06/09/2010-16:04:43.780 - PIPE1: (00000012) Write request for 15 bytes has completed
[0]0F80.04F0::06/09/2010-16:04:43.780 - IOCTL_WINUSB_READ_PIPE
[0]0F80.04F0::06/09/2010-16:04:43.780 - PIPE129: (00000013) The read has been added to the read queue
[0]0F80.04F0::06/09/2010-16:04:43.780 - PIPE129: (00000013) The read for 64 bytes is being handled
[0]0F80.04F0::06/09/2010-16:04:43.780 - PIPE129: (00000013) Reading 64 bytes from the device
[0]0F80.0CDC::06/09/2010-16:04:43.780 - PIPE129: (00000013) Transfer was terminated by a short packet
[0]0F80.0CDC::06/09/2010-16:04:43.780 - PIPE129: (00000013) Read request for 64 bytes has completed with 15 bytes
[0]0000.0000::06/09/2010-16:04:48.061 - PIPE1: (00000014) Sending a zero length packet to terminate the transfer
[0]0000.0000::06/09/2010-16:04:48.061 - PIPE1: (00000014) Writing 0 bytes to the device
[0]0000.0000::06/09/2010-16:04:48.061 - PIPE1: (00000014) Write request for 16 bytes has completed
[0]0F80.04F0::06/09/2010-16:04:48.061 - IOCTL_WINUSB_READ_PIPE
[0]0F80.04F0::06/09/2010-16:04:48.061 - PIPE129: (00000015) The read has been added to the read queue
[0]0F80.04F0::06/09/2010-16:04:48.061 - PIPE129: (00000015) The read for 64 bytes is being handled
[0]0F80.04F0::06/09/2010-16:04:48.061 - PIPE129: (00000015) Reading 64 bytes from the device
[0]0F80.04F0::06/09/2010-16:04:51.343 - Purging pipe: x85677110 pipe queue: x7ACB9FE8
[0]0F80.04F0::06/09/2010-16:04:51.343 - Purging pipe: x856BDD48 pipe queue: x7A914BA8
[0]0F80.04F0::06/09/2010-16:04:51.358 - Enter: WinUSB_InitControlPipe
[0]0F80.04F0::06/09/2010-16:04:51.358 - Exit: WinUSB_InitControlPipe (STATUS_SUCCESS)
Transaction 15 ends in a timout error, but 16 bytes were recieved. Clearly WinUSB_readpipe cannot handle a message that is shorter than the requested number of bytes *and* equal to the endpoint size. Whether or not a 0 byte frame is sent after the endpoint sized message.
So, I recoded to break the message up into endpoint sized message, *or smaller*:
If bytesToRead > myDevInfo.bulkInPipeSize Then
For i As UInt32 = 0 To bytesToRead Step myDevInfo.bulkInPipeSize
success = WinUsb_ReadPipe(myDevInfo.winUsbHandle, _
pipeID, _
FractionalBuffer, _
myDevInfo.bulkInPipeSize, _
BytesReadNow, _
IntPtr.Zero)
If success Then
System.Buffer.BlockCopy(FractionalBuffer, 0, buffer, CType(i, Integer), CType(BytesReadNow, Integer))
bytesRead = bytesRead + BytesReadNow
If BytesReadNow < myDevInfo.bulkInPipeSize Then
Exit For
End If
Else
Exit For
End If
Next
End If
The endpoint policies are the same, and FractionalBuffer is defined as myDevInfo.bulkInPipeSize (16). The fact that the Visual Studio 2008 doesn’t provide a way to append arrays was a shock, but I was able to make the buffer.blockmove work.
This also fails a 16 byte message with an error 121=semaphore timeout. The WinUSB trace provider produced the following file:
1]17C4.1160::06/11/2010-09:33:23.611 - Create succeeded
[1]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_GET_DESCRIPTOR
[1]17C4.1160::06/11/2010-09:33:23.627 - IOCTL_WINUSB_GET_DESCRIPTOR
[1]17C4.1160::06/11/2010-09:33:23.627 - IOCTL_WINUSB_QUERY_DEVICE_INFORMATION
[1]17C4.1160::06/11/2010-09:33:33.064 - IOCTL_WINUSB_WRITE_PIPE
[1]17C4.1160::06/11/2010-09:33:33.064 - PIPE1: (0000000f) The write has been added to the write queue
[1]17C4.1160::06/11/2010-09:33:33.064 - PIPE1: (0000000f) The write is being handled
[1]17C4.1160::06/11/2010-09:33:33.064 - PIPE1: (0000000f) Writing 16 bytes to the device
[1]17C4.07D4::06/11/2010-09:33:33.080 - IOCTL_WINUSB_READ_PIPE
[1]17C4.07D4::06/11/2010-09:33:33.080 - PIPE129: (00000010) The read has been added to the read queue
[1]17C4.07D4::06/11/2010-09:33:33.080 - PIPE129: (00000010) The read for 16 bytes is being handled
[1]17C4.07D4::06/11/2010-09:33:33.080 - PIPE129: (00000010) Reading 16 bytes from the device
[1]17C4.07D4::06/11/2010-09:33:33.080 - IOCTL_WINUSB_READ_PIPE
[1]17C4.07D4::06/11/2010-09:33:33.080 - PIPE129: (00000011) The read has been added to the read queue
[1]17C4.07D4::06/11/2010-09:33:33.080 - PIPE129: (00000011) The read for 16 bytes is being handled
[1]17C4.07D4::06/11/2010-09:33:33.080 - PIPE129: (00000011) Reading 16 bytes from the device
[1]0004.0188::06/11/2010-09:33:35.080 - PIPE129: (00000011) Request failed with status 0xc00000b5(STATUS_IO_TIMEOUT)
[1]0004.0188::06/11/2010-09:33:35.080 - PIPE129: (00000011) Read request for 16 bytes has completed with 0 bytes
[1]17C4.07D4::06/11/2010-09:33:36.018 - Purging pipe: x853807E8 pipe queue: x7AC4DB48
[1]17C4.07D4::06/11/2010-09:33:36.018 - Purging pipe: x851B8230 pipe queue: x7AC43FE8
[1]17C4.07D4::06/11/2010-09:33:36.018 - Enter: WinUSB_InitControlPipe
[1]17C4.07D4::06/11/2010-09:33:36.018 - Exit: WinUSB_InitControlPipe (STATUS_SUCCESS)
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_VERSION_EXCHANGE
[0]17C4.1160::06/11/2010-09:33:23.611 - Enter: WinUSB_ExchangeVersion
[0]17C4.1160::06/11/2010-09:33:23.611 - Exit: WinUSB_ExchangeVersion (STATUS_SUCCESS)
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_GET_DESCRIPTOR
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_GET_DESCRIPTOR
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_GET_DESCRIPTOR
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_RESET_DEFAULTS
[0]17C4.1160::06/11/2010-09:33:23.611 - Enter: WinUSB_InitControlPipe
[0]17C4.1160::06/11/2010-09:33:23.611 - Exit: WinUSB_InitControlPipe (STATUS_SUCCESS)
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_SET_PIPE_POLICY
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_SET_PIPE_POLICY
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_SET_PIPE_POLICY
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_SET_PIPE_POLICY
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_GET_DESCRIPTOR
[0]17C4.1160::06/11/2010-09:33:23.611 - IOCTL_WINUSB_GET_DESCRIPTOR
[0]0000.0000::06/11/2010-09:33:33.064 - PIPE1: (0000000f) Sending a zero length packet to terminate the transfer
[0]0000.0000::06/11/2010-09:33:33.064 - PIPE1: (0000000f) Writing 0 bytes to the device
[0]0000.0000::06/11/2010-09:33:33.064 - PIPE1: (0000000f) Write request for 16 bytes has completed
[0]17C4.1160::06/11/2010-09:33:33.080 - PIPE129: (00000010) Read request for 16 bytes has completed with 16 bytes
Transaction 11 fails due to a timeout, but the bytes received was 0. Since my code is looking for a *succesful* message size of < 16 to terminate assembling the complete message, my code fails.
This appears to be a bug in WinUSB (?), whereby a 0 length message is *not* recognized as a short packet (1- 15 is however), and so WinUSB_readpipe returns a fail, when it should return a success?
Actually, WinUSB_readpipe should implement the algorithm in my second set of code, and automagically assemble the message from 16 byte or less pieces. But, I’ve coded around that in my application (Whither array.append??). However, I cannot code around the fact that a legitimate 0 lenght packet read causes WinUSB_readpipe to fail???
There will be those here who ask why not just request the number of bytes that equals the message size? As I explained the message size can be any arbitrary size up to 64 bytes, which I don’t know, a priori. There will those who ask why not make the endpoint size 64 bytes? As I explained my device doesn’t have those kind of resources.
So, either I’ve missed something in the pipe policies, or returning ‘fail’ for a legitimate 0 packet transaction is a bug. I’m open to being wrong (it wouldn’t be the first time. Today even), but I honestly don’t see how make this happen if WinUSB_readpipe is going to call this a failure?