With GPSBabel exactly as it's checked into the tree, it starts to get off the
ground, succeeding in one write, one read, one write, and then hangs on the
second read:
<snip>
Synced in 0
Converting ep address to pipeRef.
ep_to_pipeRef: Pipe 1: DIR: 1 number: 1
ep_to_pipeRef: Pipe 2: DIR: 0 number: 2
ep_to_pipeRef: pipeRef for ep address 0x02 found: 0x02
usb_bulk_write: endpoint=0x02 size=12 TO=64
write completed
Sent: 12
14 00 00 00 fe 00 00 00 00 00 00 00
............
usb_bulk_read: ep addr = 0x01
Converting ep address to pipeRef.
ep_to_pipeRef: Pipe 1: DIR: 1 number: 1
ep_to_pipeRef: pipeRef for ep address 0x81 found: 0x01
usb_bulk_read: endpoint=0x81 size=1024 timeout=0.064000sec
usb_bulk_read: interrupt pipe
^C^C^C^C^Z
Suspended
[host242-231-65-207:~/src/gpsbabel] bradsimm% kill -9 %1
OK, I think I can see your problem here.
It looks like you are attempting to read an unknown quantity of data
into a 1024 byte buffer with a short (64ms) timeout to cause the read
to return if the device responds with less data.
This is a logical approach and you would think that would work as
described -- however that's not the case on Mac OS X.
First, USB timeouts on Mac OS X don't work the way -- despite being
able to specify them to millisecond resolution, the actual
implementation has a resolution measured in seconds -- meaning that
they are suitable for detecting a hung device but not for
implementing a communication protocol.
(Nano, Barry, jump in if I'm remembering incorrectly)
Second, bulk reads don't work quite the way you would think, either.
There are 3 things that (should) cause BulkRead() to return:
1) the buffer is filled
2) the device sends a short (< maxPacketSize) packet
3) the timeout expires
As mentioned above, 3) isn't going to help you.
It's important to remember that USB bulk transfers are packet
oriented -- you need to read and be aware of a bulk endpoint's
maximum packet size.
(For a high speed device, maxPacketSize is almost always going to be
64 bytes, so for the rest of this conversation, assume that "64"
means "the endpoint's maximum packet size" -- similarly, 1024 means
the size of your buffer)
If the device sends more that 1024 bytes BulkRead() will return
because of condition 1)
If the device sends any quantity of data that is not a multiple of 64
bytes, BulkRead() will return because of condition 2)
If the device sends less than 1024 bytes but a multiple of 64 bytes,
BulkRead() will hang until the transfer is aborted by the USB stack
which, IIRC, is something like 3 seconds, and therefore not useful.
A well designed protocol dealing with sending arbitrarily sized
transactions over bulk USB will require that the packet of the
transaction be followed by a zero byte packet to signal that it has
sent all of its data. This will cause BulkRead() to return because of
condition 2)
PTP/USB Still Imaging Class does this -- I suspect that Garmin does not.
(Although whoever decided to save a couple bytes in the PTP protocol
by giving it a 12-byte header instead of a full packet should be
publicly flogged as it means you have to copy a 1MB image to prepend
a 12 byte header to it -- or do a huge misaligned transaction --
because you can't use a separate buffer for the header and data w/o
terminating the transaction)
So, the simplest thing is to reduce your buffer size to 64 bytes -- I
suspect that the GPS is sending so little data that this will work
fine and the lost performance will not be an issue.
If the Garmin protocol has a data size in the beginning of the reply
or a minimum size reply, make your first read the minimum reply size
rounded up to the next multiple of 64 bytes and then read the rest of
the transaction.
When doing bulk reads, you always want to round your buffer size up
to the next multiple of maxPacketSize. The reason for this it that
the device does not know how big your buffer is -- it will send
full-size packets until it runs out of data, meaning that if the last
packet sent before your buffer fills won't fit, you will have an
overrun error, lose whatever didn't fit in your buffer, and have to
clear an endpoint stall.
If you round up the request size, BulkRead() will return either
because the buffer was full or there was a short packet and you can
just check the actual size returned to find out how much data was
transferred, handling any overflow yourself.
Hope this helps,
-Steve
P.S. Sorry this was long, but this seems to be almost an FAQ and I
haven't seen a clear answer posted in a long time.
--
_________________________________________________________________________
Steve Sisak, CTO email@hidden
IOXperts, Inc. voice: +1 617 876-2572
87 Bristol St #3A fax: +1 617 876-2337
Cambridge, MA 02139 mobile: +1 617 388-6476
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Usb mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/usb/email@hidden