[Gpsbabel-code] USB/Garmin fix committed
Brought to you by:
robertl
From: Robert L. <rob...@us...> - 2006-07-23 19:41:15
|
Twice within the last week, I noticed that I'd have a geocache that was present on my dashtop but not my handheld or vice versa. It just happened to catch my attention when driving by a geocache that I *knew* was there and yet was missing from one of my handhelds, but present in the other that were loaded from the same GPX file. Why did the handheld and the dashtop have different failure cases? It's intuitively obvious to even the most casual observer: they have different waypoint name lengths. Why did the 60cs and the 60csx have different failure cases? They speak different waypoint types. If the length of the waypoint name plus the length of the comment was 48 characters on the 60CSX (or any unit with D110's) or 38 on the 60CS (or any unit with D109's) the waypoint AFTER that one would be silently eaten by a grue. In my tests, about .4% of the waypoints are affected. Different patterns of names will generate different failure rates - that's just what MY tests yielded. The Garmin protocol spec actually says that packets that are an exact multiple fo the max frame size must be followed by a zero byte packet. When I first reverse engineered the protocol, this wasn't something that I ever noticed. When I did the rewrite this spring, I noticed it in the spec and then implemented it incorrectly (sigh) in the Windows layer. This fix commonizes it. Finding this stuff will make you prematurely old. RJL Index: jeeps/gpslibusb.c =================================================================== RCS file: /cvsroot/gpsbabel/gpsbabel/jeeps/gpslibusb.c,v retrieving revision 1.27 diff -p -u -r1.27 gpslibusb.c --- jeeps/gpslibusb.c 13 Jul 2006 03:27:53 -0000 1.27 +++ jeeps/gpslibusb.c 23 Jul 2006 19:26:09 -0000 @@ -54,6 +54,7 @@ typedef struct { static int gusb_intr_in_ep; static int gusb_bulk_out_ep; static int gusb_bulk_in_ep; +static gusb_llops_t libusb_llops; static usb_dev_handle *udev; static void garmin_usb_scan(libusb_unit_data *, int); @@ -71,6 +72,7 @@ gusb_libusb_send(const garmin_usb_packet usb_strerror()); } } + return r; } @@ -214,10 +216,12 @@ garmin_usb_start(struct usb_device *dev) fatal("Claim interfaced failed: %s\n", usb_strerror()); } + libusb_llops.max_tx_size = dev->descriptor.bMaxPacketSize0; for (i = 0; i < dev->config->interface->altsetting->bNumEndpoints; i++) { struct usb_endpoint_descriptor * ep; ep = &dev->config->interface->altsetting->endpoint[i]; + switch (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) { #define EA(x) x & USB_ENDPOINT_ADDRESS_MASK case USB_ENDPOINT_TYPE_BULK: Index: jeeps/gpsusbcommon.c =================================================================== RCS file: /cvsroot/gpsbabel/gpsbabel/jeeps/gpsusbcommon.c,v retrieving revision 1.5 diff -p -u -r1.5 gpsusbcommon.c --- jeeps/gpsusbcommon.c 24 May 2006 15:31:21 -0000 1.5 +++ jeeps/gpsusbcommon.c 23 Jul 2006 19:26:09 -0000 @@ -170,6 +170,19 @@ gusb_cmd_send(const garmin_usb_packet *o GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); } + /* + * Recursion, when used in a disciplined way, can be our friend. + * + * The Garmin protocol requires that packets that are exactly + * a multiple of the max tx size be followed by a zero length + * packet. Do that here so we can see it in debugging traces. + */ + + if (sz && !(sz % gusb_llops->max_tx_size)) { + gusb_cmd_send(opkt, 0); + } + return (rv); } Index: jeeps/gpsusbcommon.h =================================================================== RCS file: /cvsroot/gpsbabel/gpsbabel/jeeps/gpsusbcommon.h,v retrieving revision 1.2 diff -p -u -r1.2 gpsusbcommon.h --- jeeps/gpsusbcommon.h 24 May 2006 15:31:21 -0000 1.2 +++ jeeps/gpsusbcommon.h 23 Jul 2006 19:26:09 -0000 @@ -32,6 +32,7 @@ typedef struct gusb_llops { gusb_llop_get llop_get_bulk; gusb_llop_send llop_send; gusb_llop_close llop_close; + int max_tx_size; } gusb_llops_t; /* Provided by the common code. */ Index: jeeps/gpsusbwin.c =================================================================== RCS file: /cvsroot/gpsbabel/gpsbabel/jeeps/gpsusbwin.c,v retrieving revision 1.14 diff -p -u -r1.14 gpsusbwin.c --- jeeps/gpsusbwin.c 24 May 2006 15:31:21 -0000 1.14 +++ jeeps/gpsusbwin.c 23 Jul 2006 19:26:09 -0000 @@ -72,7 +72,6 @@ gusb_win_get(garmin_usb_packet *ibuf, si DWORD rxed = GARMIN_USB_INTERRUPT_DATA_SIZE; unsigned char *buf = (unsigned char *) &ibuf->dbuf; int tsz=0; - unsigned char *obuf = buf; while (sz) { /* The driver wrongly (IMO) rejects reads smaller than @@ -118,13 +117,7 @@ gusb_win_send(const garmin_usb_packet *o WriteFile(usb_handle, obuf, sz, &rsz, NULL); if (rsz != sz) { - fatal ("Error sending %d bytes. Successfully sent %d\n", sz, rsz); - } - - if (0 == sz % usb_tx_packet_size) { - DWORD sz2; - GPS_Diag("Writing padding buffer.\n"); - WriteFile(usb_handle, 0, 0, &sz2, NULL); + fatal ("Error sending %d bytes. Successfully sent %ld\n", sz, rsz); } return rsz; @@ -177,6 +170,7 @@ HANDLE * garmin_usb_start(HDEVINFO* hdev &size, NULL)) { fatal("Couldn't get USB packet size.\n"); } + win_llops.max_tx_size = usb_tx_packet_size; gusb_syncup(); |