Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Garmin GPS/Bulk Reads



(I shortened the subject line a bit)

At 12:39 PM -0600 2/10/05, Robert Lipe wrote:
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

This email sent to email@hidden
References: 
 >Re: Does Mac OS X 10.3.8 update include USB stack update which may help Mac OS X communicate with Ga (From: Robert Lipe <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.