Not in Kansas anymore

Out of almost pure gadgetitis, I bought a Garmin Forerunner 205 this weekend. I am getting ready to do Wildflower in May, but I don’t think that justifies needing a GPS trainer. Still, what a cool little tool. Yesterday, I ran from my house in Noe Valley, out to Glen Park, through the Sunnyside, around through St. Francis Wood, over Portola, and back down into Noe - it didn’t lose the signal once. Unfortunately, although Garmin has promised Mac support sometime in the next couple months, their current software does not run on the Mac, nor will it run in VirtualPC. Bollocks.

So, I did what any development-minded individual would do: I plugged it into my Mac and tried to get at it using IOKit.

I read through all Apple’s USB documentation, Garmin’s protocol docs, and Apple’s “Accessing Hardware From Applications” documentation. It all makes pretty good sense, but it also makes me feel like Cocoa’s back in Kansas while I’m wandering in IOKit OZ. For the most part, it’s gone smoothly - I can see the device, the inteface, and the pipes that I should use for reading and writing. But I must be doing something wrong with the Garmin protocol. I send the “Start Session” packet, which should tell the unit that I’m ready to start. It should reply with a “Session Started” packet. However, I put async reads on both the interrupt and bulk in ports, and I never get any reply. I’ve tried bypassing “Start Session” and trying some application-level packets but also without any success.

Frustrating. But, being able to at least get at the Forerunner data so I can copy it to MotionBased or to Garmin’s TrainingCenter application in VirtualPC would be SO worth the effort. I think my brain is too fried to keep going right now, but hopefully I can play with it some more this week and figure it out.

10 Responses to “Not in Kansas anymore”


  1. 1 Daniel Jalkut Feb 27th, 2006 at 9:46 am

    I have been dealing with a USB device lately, and it’s been a bit persnickety. The problem is we don’t have USB bus analyzers, which is what any pro will tell you to use to get to the bottom of these types of problems quickly.

    Is it possible that you’re sending the session started packet to the wrong pipe?

    Another thing is make sure you’re not asking for more bytes from your Async read than the device is prepared to give. I believe it will wait patiently for the requested number of bytes to appear. So you might need to ask for a shorter number of bytes and see if anything at all is coming back.

  2. 2 blake Feb 27th, 2006 at 10:24 am

    Being able to see the actual communications would be awesome!

    The gps only provides three pipes: Interrupt in, bulk in, and bulk out. I’m writing to the bulk out pipe - which the docs say all host->device communications should occur on. I even tried switching over to Apple’s USBSimpleExample example code - it picks out the pipes - and replacing their transfer data code with code to send the packet.

    I’ve double-checked my data structure, and I *think* I’m sending the right structure. (As far as I can tell, there isn’t much error handling on the device, which may be contributing to the problem :)

    I’ve tried reading just one byte and I still get nothing. Frustrating.

  3. 3 Daniel Jalkut Feb 27th, 2006 at 3:45 pm

    How complicated is the packet? Is it several bytes or just a single byte? Consider the possibility that maybe the bits should go in the opposite order. I don’t think I mean exactly byte-swapped, but outright opposite. I had some confusing experiences with my device where what I expected to be the most significant end of a value was actually least.

  4. 4 Jonathan Wight Feb 27th, 2006 at 3:46 pm

    Hey Blake, what data are you trying to get from the unit? I have an app I am about to release that will download waypoints and/or tracks from any Garmin device (serial devices included) and output the data as a GPX file. i’m looking for testers for it now (developer testers are great).

  5. 5 Greg Hulands Feb 27th, 2006 at 3:53 pm

    I have experienced the exact same problem as you… I still have resolved it either. The async call back just never gets called. And if I do a sync read it just sits waiting deep in IOKit. For me doing async or sync is no problem as it runs in a background thread and doesn’t block.

  6. 6 Jonathan Wight Feb 27th, 2006 at 4:01 pm

    Ooh so my code is the only one that works? I ought to auction it off… Starting big (pinky on lips): one MILLION dollars!

  7. 7 blake Feb 27th, 2006 at 4:05 pm

    I will definitely give your app a test, Jonathan.

    I’m trying to get the historical data from the Forerunner. I think the Forerunner series keeps running data somewhat differently than a standard GPS would keep waypoints, tracks, etc. But I don’t know this for sure. I tried GarminUSBTool1.0b5 - based on gpsbabel - that pulled Tracks, Waypoints, etc - but all the GPX files I got from it were empty. This made me think that the Forerunner is keeping data that doesn’t show as waypoints or tracks.

    But I’d still love to give your app a try just to see if it can get inside the data.

    -Blake

  8. 8 blake Feb 27th, 2006 at 4:08 pm

    Daniel,

    Hmmm, you might have something there. I was under the impression that USB was little-endian and that IOKit would handle whatever swapping was necessary to do this… but now that I go back through my notes and some of the docs, I don’t know what made me think that.

    Garmin’s sample code for windows (a *very* short program that simply sends a “start session” and reads the “session started” declares the struct basically the same as I do - but maybe I need to do some byte-swapping on my own to make sure it goes across the bus right?

    The struct I’m using looks like this:

    typedef struct Garmin_USB_Packet {
    	uint8_t packet_type;
    	uint8_t reserved1_1;
    	uint16_t reserved1_2;
    	uint16_t packet_id;
    	uint16_t reserved2;
    	uint32_t data_size;
    } Garmin_USB_Packet_t;
    

    There’s technically more that I would pack int the same buffer that contains any actual data payload - although I haven’t even gone that far yet.

  9. 9 Jonathan Wight Feb 27th, 2006 at 4:42 pm

    Here’s my code:

    struct Packet {
    UInt8 layer;
    UInt8 reserved0[3];
    UInt16 packetId;
    UInt8 reserved1[2];
    UInt32 dataLength;
    UInt8 data[];
    } __attribute__ ((packed));

    Have fun. Feel free to bug me on aim (schwatoo).

  10. 10 Clark Weber Mar 8th, 2006 at 9:49 am

    MotionBased just launched basic support for the Mac.

    http://wiki.motionbased.com/mb/Mac

Comments are currently closed.