예제 #1
0
파일: psp.c 프로젝트: alexbirkett/GPSBabel
static void
psp_read(void)
{
	char buff[MAXPSPSTRINGSIZE + 1];
	double radians;
	double lat, lon;
	waypoint *wpt_tmp;
	short int pincount;
	short int pindex;
        char gridbyte = 0x00;
	char *tmp;

        /* 32 bytes - file header */
        psp_fread(&buff[0], 1, 32, psp_file_in);

        if (valid_psp_header(buff) != 0) {
            fatal(MYNAME ": input file does not appear to be a valid .PSP file.\n");
        }

	pincount = le_read16(&buff[12]);

	while (pincount--) {
	    wpt_tmp = waypt_new();

            wpt_tmp->altitude = unknown_alt;
            
            /* offset 0x20 - 0x21 pin index */
    	    psp_fread(&pindex, 1, 2, psp_file_in);

            /* offset 0x22 - 0x23 */
    	    psp_fread(&buff[0], 1, 2, psp_file_in);

            /* offset 0x24 */
            /* 1 byte, the grid byte - needed for sign corrections later*/
            psp_fread(&gridbyte, 1, 1, psp_file_in);

            /* 8 bytes - latitude in radians */
	    radians = psp_fread_double(psp_file_in);
            lat = DEG(radians);

            /* 8 bytes - longitude in radians */
	    radians = psp_fread_double(psp_file_in);
            lon = DEG(radians);

            /* since we don't know the origin of this PSP file, we use  */
            /* the grid byte adjust longitude, if necessary, mimicing   */
            /* the behavior of pocketstreets correcting the data.  This */
            /* does not correct the fact that points in eastern US are  */
            /* written with the wrong coordinates by S&T. (MS bug)      */

            decode_psp_coordinates(&lat, &lon, gridbyte);

            wpt_tmp->latitude = lat;
            wpt_tmp->longitude = lon;
           
            /* 1 byte - pin display properties */
            psp_fread(&buff[0], 1, 1, psp_file_in);

	    /* 3 bytes - unknown */
            psp_fread(&buff[0], 1, 3, psp_file_in);

            /* 1 bytes - icon (values: 0x00 - 0x27) */
            psp_fread(&buff[0], 1, 1, psp_file_in);

	    /* 3 bytes - unknown */
    	    psp_fread(&buff[0], 1, 3, psp_file_in);

	    wpt_tmp->shortname = psp_read_str(psp_file_in);
	    wpt_tmp->description = psp_read_str(psp_file_in);
	    tmp = psp_read_str(psp_file_in); /* (address?) */
	    if (tmp) xfree(tmp);

	    waypt_add(wpt_tmp);
	}
}
예제 #2
0
int
gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz)
{
	int rv = 0;
	unsigned char *buf = (unsigned char *) &ibuf->dbuf;
	int orig_receive_state;
	unsigned short pkt_id;
top:
	orig_receive_state = receive_state;
	switch (receive_state) {
	case rs_fromintr:
		rv = gusb_llops->llop_get_intr(ibuf, sz);
		break;
	case rs_frombulk:
		rv = gusb_llops->llop_get_bulk(ibuf, sz);
		break;
	default:
		fatal("Unknown receiver state %d\n", receive_state);
	}

	pkt_id = le_read16(&ibuf->gusb_pkt.pkt_id);
	if (gps_show_bytes) {
		int i;
		const char *m1, *m2;
		unsigned short pkttype = le_read16(&ibuf->gusb_pkt.databuf[0]);

		GPS_Diag("RX (%s) [%d]:",
			receive_state == rs_fromintr ? "intr" : "bulk", rv);

		for(i=0;i<rv;i++) {
/*dsr
			if (DEBUG_THRESH) {
				GPS_Diag("[...]");
				break;
			}
*/
			GPS_Diag("%02x ", buf[i]);
		}

		for(i=0;i<rv;i++) {
/*dsr
			if (DEBUG_THRESH) {
				GPS_Diag("[...]");
				break;
			}
*/
			GPS_Diag("%c", isalnum(buf[i])? buf[i] : '.');
		}

		m1 = Get_Pkt_Type(pkt_id, pkttype, &m2);
if ((rv == 0)  &&  (receive_state == rs_frombulk) ) {m1= "RET2INTR";m2=NULL;};
		GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
	}

	/* Adjust internal state and retry the read */
	if ((rv > 0) && (pkt_id == GUSB_REQUEST_BULK)) {
		receive_state = rs_frombulk;
		goto top;
	}
	/*
	 * If we were reading from the bulk pipe and we just got
	 * a zero request, adjust our internal state.
	 * It's tempting to retry the read here to hide this "stray"
	 * packet from our callers, but that only works when you know
	 * there's another packet coming.   That works in every case
	 * except the A000 discovery sequence.
	*/
	if ((receive_state == rs_frombulk) && (rv <= 0)) {
		receive_state = rs_fromintr;
	}

	return rv;
}
예제 #3
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;
}
예제 #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;
	}
	
	/* 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;
}