Ejemplo n.º 1
0
int
gusb_close(gpsdevh *dh)
{
	garmin_usb_packet scratch;

	memset(&scratch, 0, sizeof(scratch));

	switch (receive_state) {
	case rs_frombulk:
		gusb_cmd_get(&scratch, sizeof(scratch));
		break;
	default:
		break;
	}

	gusb_llops->llop_close(dh);
	return 1;

#if BOOGER
	garmin_usb_packet scratch = {0};
abort();
	switch (receive_state) {
	case rs_frombulk:
		gusb_cmd_get(dh, &scratch, sizeof(scratch));
		break;
	}

	return 1;
#endif
}
Ejemplo n.º 2
0
void
gusb_syncup(void)
{
	static int unit_number;
	static const char  oinit[12] =
		{0, 0, 0, 0, GUSB_SESSION_START, 0, 0, 0, 0, 0, 0, 0};
	garmin_usb_packet iresp;
	int i;

	/*
	 * This is our first communication with the unit.
	 */
	receive_state = rs_fromintr;

	for(i = 0; i < 25; i++) {
		le_write16(&iresp.gusb_pkt.pkt_id, 0);
		le_write32(&iresp.gusb_pkt.datasz, 0);
		le_write32(&iresp.gusb_pkt.databuf, 0);

		gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));
		gusb_cmd_get(&iresp, sizeof(iresp));

		if ((le_read16(iresp.gusb_pkt.pkt_id) == GUSB_SESSION_ACK) &&
			(le_read32(iresp.gusb_pkt.datasz) == 4)) {
			unsigned serial_number = le_read32(iresp.gusb_pkt.databuf);
			garmin_unit_info[unit_number].serial_number = serial_number;
			gusb_id_unit(&garmin_unit_info[unit_number]);

			unit_number++;

			return;
		}
	}
	fatal("Unable to establish USB syncup\n");
}
Ejemplo n.º 3
0
void
gusb_id_unit(struct garmin_unit_info *gu)
{
	static const char  oid[12] =
		{20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0};
	garmin_usb_packet iresp;
	int i;

	gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid));

	for (i = 0; i < 25; i++) {
		iresp.gusb_pkt.type = 0;
		if (gusb_cmd_get(&iresp, sizeof(iresp)) < 0) {
			return;
		}
		if (le_read16(iresp.gusb_pkt.pkt_id) == 0xff) {
			gu->product_identifier = xstrdup((char *) iresp.gusb_pkt.databuf+4);
			gu->unit_id = le_read16(iresp.gusb_pkt.databuf+0);
			gu->unit_version = le_read16(iresp.gusb_pkt.databuf+2);
		}
		/*
		 * My goodnesss, this is fragile.  During command syncup,
		 * we need to know if we're at the end.  The 0xfd packet
		 * is promised by Garmin engineering to be the last.
		 */
		if (le_read16(iresp.gusb_pkt.pkt_id) == 0xfd) return;
	}
	fatal("Unable to sync with Garmin USB device in %d attempts.", i);
}
Ejemplo n.º 4
0
/*
 * Return values are:
 * Negative on error.
 * 1 if read success - even if empty packet.
 */
int32 GPS_Packet_Read_usb(gpsdevh *dh, GPS_PPacket *packet, int eat_bulk)
{
	int32  n;
	int32 payload_size;

	garmin_usb_packet pkt;

	memset(&pkt, 0, sizeof(pkt));
do_over:
	n = gusb_cmd_get(&pkt, sizeof(pkt));

	if ( n < 0 ) {
		/*
		 * We (probably) used to have a GPS and it went away 
	 	 * while we were speaking with it.  Perhaps batteries 
		 * died or it was unplugged or something.
		 */
		gps_errno = PROTOCOL_ERROR;
		return n;
	}

	/*
	 * This is a horrible hack for 276/296.   This family sometimes 
	 * switches between bulk and interrupt on EVERY packet.   Rather 
	 * than bother all the callers with that bit of unpleasantness, 
	 * silently consume zero byte "switch back to intr"  packets here.
	 *
	 * The one caller that doesn't want this hidden is device discovery
	 * in the A000 handler.
	 */
	if ((n == 0) && eat_bulk)  {
		goto do_over;
	}
	
	/* 
	 * Populate members of serial packet from USB packet.   The
	 * copy here seems wasteful, but teaching all the callers about
	 * a structure with the "data" member being in a different place 
	 * (Since the protocol packets was badly exposed in the core
	 * design of jeeps) is even more painful.
	 */
	(*packet)->type = le_read16(&pkt.gusb_pkt.pkt_id);
	payload_size = le_read32(&pkt.gusb_pkt.datasz);
	if (payload_size<0 || payload_size>MAX_GPS_PACKET_SIZE)
	{
		GPS_Error("GPS_Packet_Read_usb: Bad payload size %d", payload_size);
		gps_errno = FRAMING_ERROR;
		return 0;
	}
	(*packet)->n = payload_size;
	memcpy((*packet)->data, &pkt.gusb_pkt.databuf, payload_size);
	
	return 1;
}
Ejemplo n.º 5
0
/*
 * This was a function of great joy to discover...and even greater to maintain.
 *
 * It turns out that as of 5/2006, every Garmin USB product has a problem
 * where the device does not reset the data toggles after a configuration
 * set.   After a reset, the toggles both match.  So we tear through the
 * conversation and life is good.  Unfortunately, the second time through,
 * if we had an odd number of transactions in the previous conversation,
 * we send a configuration set and reset the toggle on the HCI but the 
 * toggle on the device's end of the pipe is now out of whack which means
 * that the subsequent transaction will hang.
 * 
 * This isn't a problem in Windows since the configuration set is done only
 * once there.
 * 
 * This code has been tested in loops of 1000 cycles on Linux and OS/X and
 * it seems to cure this at a mere cost of complexity and startup time.  I'll
 * be delighted when all the firmware gets revved and updated and we can
 * remove this.
 *
 * 9/2008 But wait, there's more.   The very toggle reset that we *had* to 
 * implement in 2006 to make non-Windows OSes work actually locks up verion
 * 2.70 of the Venture HC.   On that model, the second product request 
 * (you know, the one that we *use*, locks that device's protocol stack
 * after the RET2INTR that immediately follows the REQBLK (and why is it
 * telling us to go into bulk mode followed by an immeidate EOF, anyway?)
 * that follows the request for product ID.   100% reproducible on Mac and
 * Linux.    Of course, we don't see this on the Windows system becuase
 * we don't have to jump through hooops to clear the spec-violating out
 * of state toggles there becuase those systems see only one configuration
 * set ever.
 *
 * Grrrr!
 */
unsigned 
gusb_reset_toggles(void)
{
	static const char  oinit[12] = 
		{0, 0, 0, 0, GUSB_SESSION_START, 0, 0, 0, 0, 0, 0, 0};
	static const char  oid[12] = 
		{20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0};
	garmin_usb_packet iresp;
	int t;
	unsigned rv = 0;

	/* Start off with three session starts.
	 * #1 resets the bulk out toggle.  It may not make it to the device.
	 * #2 resets the the intr in toggle.  It will make it to the device
	 *	since #1 reset the the bulk out toggle.   The device will
	 *      respond on the intr in pipe which will clear its toggle.
	 * #3 actually starts the session now that the above are both clear.
 	 */

	gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));
	gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));
	gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));

	t = 10;
	while(1) {
		le_write16(&iresp.gusb_pkt.pkt_id, 0);
		le_write32(&iresp.gusb_pkt.datasz, 0);
		le_write32(&iresp.gusb_pkt.databuf, 0);

		gusb_cmd_get(&iresp, sizeof(iresp));

		if ((le_read16(iresp.gusb_pkt.pkt_id) == GUSB_SESSION_ACK) &&
                        (le_read32(iresp.gusb_pkt.datasz) == 4)) {
				break;
		}
		if (t-- <= 0) {
			fatal("Could not start session in a reasonable number of tries.\n");
		}
	}

	/*
	 * Now that the bulk out and intr in packets are good, we send
	 * a product ID.    On devices that respond totally on the intr
	 * pipe, this does nothing interesting, but on devices that respon
	 * on the bulk pipe this will reset the toggles on the bulk in.
 	 */

	t = 10;
	gusb_cmd_send((const garmin_usb_packet *) oid, sizeof(oid));
	while(1) {
		le_write16(&iresp.gusb_pkt.pkt_id, 0);
		le_write32(&iresp.gusb_pkt.datasz, 0);
		le_write32(&iresp.gusb_pkt.databuf, 0);

		gusb_cmd_get(&iresp, sizeof(iresp));

		if (le_read16(iresp.gusb_pkt.pkt_id) == 0xff) {
			rv = le_read16(iresp.gusb_pkt.databuf+0);
		}

		if (le_read16(iresp.gusb_pkt.pkt_id) == 0xfd) return rv;
		if (t-- <= 0) {
			fatal("Could not start session in a reasonable number of tries.\n");
		}
	}
	return 0;
}
Ejemplo n.º 6
0
/*
 * Return values are:
 * Negative on error.
 * 1 if read success - even if empty packet.
 */
int32 GPS_Packet_Read_usb(gpsdevh *dh, GPS_PPacket *packet, int eat_bulk)
{
	int32  n;
	int32 payload_size;

	garmin_usb_packet pkt;

	memset(&pkt, 0, sizeof(pkt));
do_over:
	n = gusb_cmd_get(&pkt, sizeof(pkt));

	if ( n < 0 ) {
		/*
		 * We (probably) used to have a GPS and it went away 
	 	 * while we were speaking with it.  Perhaps batteries 
		 * died or it was unplugged or something.
		 */
		gps_errno = PROTOCOL_ERROR;
		return n;
	}

	/*
	 * This is a horrible hack for 276/296.   This family sometimes 
	 * switches between bulk and interrupt on EVERY packet.   Rather 
	 * than bother all the callers with that bit of unpleasantness, 
	 * silently consume zero byte "switch back to intr"  packets here.
	 *
	 * The one caller that doesn't want this hidden is device discovery
	 * in the A000 handler.
	 */
	if ((n == 0) && eat_bulk)  {
		goto do_over;
	}
	
	/* We sometimes get corrupted packets during a track log transfer
	 * where the first byte in a packet is lost, causing all remaining
	 * bytes in this packet to be shifted. So far, this has only been
	 * observed on a Forerunner 305 (both on Linux and Windows). The
	 * cause is unknown, but it seems to be timing dependent.
	 * We try to detect the corruption mainly by checking reserved bytes
	 * 3 and 7 which normally should be 0, the remaining comparisons are
	 * only sanity checks and they alone could also trigger in case of
	 * valid packets. Note: We can't detect corrupted packets with an ID
	 * or length that's a multiple of 256, but such corrupted packets
	 * haven't been observed so far.
	 */
	if (gps_save_id == 484
	    && pkt.gusb_pkt.type == 0 && pkt.gusb_pkt.reserved1 == 0
	    && pkt.gusb_pkt.reserved2 == 0 && pkt.gusb_pkt.reserved3 != 0
	    && pkt.gusb_pkt.pkt_id[0] <= 4 && pkt.gusb_pkt.pkt_id[1] == 0
	    && pkt.gusb_pkt.reserved6 == 0 && pkt.gusb_pkt.reserved7 != 0) {
		memmove(&pkt.dbuf[1], &pkt.dbuf[0], sizeof(pkt) - 1);
		pkt.gusb_pkt.type = 20;
	}
	
	/* 
	 * Populate members of serial packet from USB packet.   The
	 * copy here seems wasteful, but teaching all the callers about
	 * a structure with the "data" member being in a different place 
	 * (Since the protocol packets was badly exposed in the core
	 * design of jeeps) is even more painful.
	 */
	(*packet)->type = le_read16(&pkt.gusb_pkt.pkt_id);
	payload_size = le_read32(&pkt.gusb_pkt.datasz);
	if (payload_size<0 || payload_size>MAX_GPS_PACKET_SIZE)
	{
		/* If you get this, the packet might have been corrupted
		 * by the unit. Have a look at the corruption detection
		 * code above.
		 */
		GPS_Error("GPS_Packet_Read_usb: Bad payload size %d", payload_size);
		gps_errno = FRAMING_ERROR;
		return 0;
	}
	(*packet)->n = payload_size;
	memcpy((*packet)->data, &pkt.gusb_pkt.databuf, payload_size);
	
	return 1;
}