summaryrefslogtreecommitdiff
path: root/garmin.c
diff options
context:
space:
mode:
authorGary E. Miller <gem@rellim.com>2006-10-30 02:21:11 +0000
committerGary E. Miller <gem@rellim.com>2006-10-30 02:21:11 +0000
commit1eb8ef0dbf7d746f38b1987c8a73261c7cf0912f (patch)
tree7a2816f543181983d355ffed79be59b11f77671a /garmin.c
parentbb1a554d74c9d443d085e756151f7c8a328ae6ba (diff)
downloadgpsd-1eb8ef0dbf7d746f38b1987c8a73261c7cf0912f.tar.gz
Convert garmin_usb to run in serial emulation mode...
instead of packet mode. A bit simpler than the old way and works around a kernel bug.
Diffstat (limited to 'garmin.c')
-rw-r--r--garmin.c602
1 files changed, 312 insertions, 290 deletions
diff --git a/garmin.c b/garmin.c
index bcdd5628..46284626 100644
--- a/garmin.c
+++ b/garmin.c
@@ -15,7 +15,8 @@
* modes.
*
* Protocol info from:
- * GPS18_TechnicalSpecification.pdf
+ * 425_TechnicalSpecification.pdf
+ * ( formerly GPS18_TechnicalSpecification.pdf )
* iop_spec.pdf
* http://www.garmin.com/support/commProtocol.html
*
@@ -67,6 +68,13 @@
#ifdef GARMIN_ENABLE
+#define USE_RMD 0
+
+#define ETX 0x03
+#define ACK 0x06
+#define DLE 0x10
+#define NAK 0x15
+
#define GARMIN_LAYERID_TRANSPORT (uint8_t) 0
#define GARMIN_LAYERID_APPL (uint32_t) 20
// Linux Garmin USB driver layer-id to use for some control mechanisms
@@ -89,8 +97,12 @@
#define GARMIN_PKTID_PROTOCOL_ARRAY 253
#define GARMIN_PKTID_PRODUCT_RQST 254
#define GARMIN_PKTID_PRODUCT_DATA 255
+/* 0x29 ')' */
+#define GARMIN_PKTID_RMD41_DATA 41
/* 0x33 '3' */
#define GARMIN_PKTID_PVT_DATA 51
+/* 0x33 '4' */
+#define GARMIN_PKTID_RMD_DATA 52
/* 0x72 'r' */
#define GARMIN_PKTID_SAT_DATA 114
@@ -127,8 +139,9 @@ typedef struct {
// bit 3??
} cpo_sat_data;
-/* Garmin D800_Pvt_Date_Type */
-// This is the data format of the position data from the garmin USB
+/* Garmin D800_Pvt_Datetype_Type */
+/* packet type: GARMIN_PKTID_PVT_DATA 52 */
+/* This is the data format of the position data from the garmin USB */
typedef struct {
float alt; /* altitude above WGS 84 (meters) */
float epe; /* estimated position error, 2 sigma (meters) */
@@ -147,28 +160,30 @@ typedef struct {
float lon_vel; /* velocity east (meters/second) */
float lat_vel; /* velocity north (meters/second) */
float alt_vel; /* velocity up (meters/sec) */
+ // Garmin GPS25 uses pkt_id 0x28 and does not output the
+ // next 3 items
float msl_hght; /* height of WGS 84 above MSL (meters) */
int16_t leap_sec; /* diff between GPS and UTC (seconds) */
int32_t grmn_days;
} cpo_pvt_data;
-#ifdef __UNUSED__
typedef struct {
uint32_t cycles;
double pr;
uint16_t phase;
int8_t slp_dtct;
uint8_t snr_dbhz;
- int8_t svid;
+ uint8_t svid;
int8_t valid;
} cpo_rcv_sv_data;
+/* packet type: GARMIN_PKTID_RMD_DATA 53 */
+/* seems identical to the packet id 0x29 from the Garmin GPS 25 */
typedef struct {
double rcvr_tow;
int16_t rcvr_wn;
cpo_rcv_sv_data sv[GARMIN_CHANNELS];
} cpo_rcv_data;
-#endif /* __UNUSED__ */
// This is the packet format to/from the Garmin USB
typedef struct {
@@ -223,7 +238,6 @@ static inline double radtodeg( double rad) {
static gps_mask_t PrintSERPacket(struct gps_device_t *session, unsigned char pkt_id, int pkt_len, unsigned char *buf );
static gps_mask_t PrintUSBPacket(struct gps_device_t *session, Packet_t *pkt );
-static int GetPacket (struct gps_device_t *session );
gps_mask_t PrintSERPacket(struct gps_device_t *session, unsigned char pkt_id
, int pkt_len, unsigned char *buf )
@@ -241,10 +255,17 @@ gps_mask_t PrintSERPacket(struct gps_device_t *session, unsigned char pkt_id
char *msg = NULL;
cpo_sat_data *sats = NULL;
cpo_pvt_data *pvt = NULL;
+ cpo_rcv_data *rmd = NULL;
gpsd_report(4, "PrintSERPacket(, %#02x, %#02x, )\n", pkt_id, pkt_len);
switch( pkt_id ) {
+ case ACK:
+ gpsd_report(3, "ACK\n");
+ break;
+ case NAK:
+ gpsd_report(3, "NAK\n");
+ break;
case GARMIN_PKTID_L001_COMMAND_DATA:
prod_id = get_uint16((uint8_t *)buf);
/*@ -branchstate @*/
@@ -391,15 +412,30 @@ gps_mask_t PrintSERPacket(struct gps_device_t *session, unsigned char pkt_id
mask |= TIME_SET | LATLON_SET | ALTITUDE_SET | STATUS_SET | MODE_SET | SPEED_SET | TRACK_SET | CLIMB_SET | HERR_SET | VERR_SET | PERR_SET | CYCLE_START_SET;
break;
+ case GARMIN_PKTID_RMD_DATA:
+ case GARMIN_PKTID_RMD41_DATA:
+ rmd = (cpo_rcv_data *) buf;
+ gpsd_report(4, "PVT RMD Data Sz: %d\n", pkt_len);
+ gpsd_report(3, "PVT RMD rcvr_tow: %f, rcvr_wn: %d\n"
+ , rmd->rcvr_tow, rmd->rcvr_wn);
+ for ( i = 0 ; i < GARMIN_CHANNELS ; i++ ) {
+ gpsd_report(3, "PVT RMD Sat: %3u, cycles: %9lu, pr: %16.6f, phase: %7.3f, slp_dtct: %3s, snr: %3u, Valid: %3s\n"
+ , rmd->sv[i].svid + 1, rmd->sv[i].cycles, rmd->sv[i].pr
+ , (rmd->sv[i].phase * 360.0)/2048.0
+ , rmd->sv[i].slp_dtct ? "Yes" : "No"
+ , rmd->sv[i].snr_dbhz, rmd->sv[i].valid ? "Yes" : "No");
+ }
+ break;
+
case GARMIN_PKTID_SAT_DATA:
- gpsd_report(3, "Appl, SAT Data Sz: %d\n", pkt_len);
+ gpsd_report(3, "SAT Data Sz: %d\n", pkt_len);
sats = (cpo_sat_data *)buf;
session->gpsdata.satellites_used = 0;
memset(session->gpsdata.used,0,sizeof(session->gpsdata.used));
gpsd_zero_satellites(&session->gpsdata);
for ( i = 0, j = 0 ; i < GARMIN_CHANNELS ; i++, sats++ ) {
- gpsd_report(4," Sat %d, snr: %d, elev: %d, Azmth: %d, Stat: %x\n"
+ gpsd_report(4," Sat %3d, snr: %5d, elev: %2d, Azmth: %3d, Stat: %x\n"
, sats->svid
, sats->snr
, sats->elev
@@ -439,8 +475,8 @@ gps_mask_t PrintSERPacket(struct gps_device_t *session, unsigned char pkt_id
}
break;
default:
- gpsd_report(3, "Appl, ID: %d, Sz: %d\n"
- , pkt_id, pkt_len);
+ gpsd_report(3, "Unknown packet id: %#02x, Sz: %#02x, pkt:%s\n"
+ , pkt_id, pkt_len, gpsd_hexdump(buf, pkt_len));
break;
}
gpsd_report(3, "PrintSERPacket(, %#02x, %#02x, ) = %#02x\n"
@@ -462,7 +498,17 @@ static gps_mask_t PrintUSBPacket(struct gps_device_t *session, Packet_t *pkt)
uint32_t serial;
uint32_t mDataSize = get_int32( (uint8_t*)&pkt->mDataSize);
+//
+ uint8_t *buffer = (uint8_t*)pkt;
+
gpsd_report(3, "PrintUSBPacket()\n");
+// gem
+ if ( DLE == pkt->mPacketType) {
+ gpsd_report(3, "really a SER packet!\n");
+ return PrintSERPacket ( session, buffer[1], buffer[2], buffer + 3);
+ }
+
+// gem
if ( 4096 < mDataSize) {
gpsd_report(3, "bogus packet, size too large=%d\n", mDataSize);
return 0;
@@ -542,8 +588,8 @@ static gps_mask_t PrintUSBPacket(struct gps_device_t *session, Packet_t *pkt)
/*@ +branchstate @*/
-/* build and send a packet */
-static void Build_Send_Packet( struct gps_device_t *session,
+/* build and send a packet w/ USB protocol */
+static void Build_Send_USB_Packet( struct gps_device_t *session,
uint32_t layer_id, uint32_t pkt_id, uint32_t length, uint32_t data )
{
uint8_t *buffer = (uint8_t *)session->driver.garmin.Buffer;
@@ -584,137 +630,109 @@ static void Build_Send_Packet( struct gps_device_t *session,
, &n, 0);
}
}
-
-//-----------------------------------------------------------------------------
-// Gets a single packet.
-// this is odd, the garmin usb driver will only return 64 bytes, or less
-// at a time, no matter what you ask for.
-//
-// is you ask for less than 64 bytes then the next packet will include
-// just the remaining bytes of the last 64 byte packet.
-//
-// Reading a packet of length Zero, or less than 64, signals the end of
-// the entire packet.
-//
-// The Garmin sample WinXX code also assumes the same behavior, so
-// maybe it is something in the USB protocol.
-//
-// Return: 0 = got a good packet
-// -1 = error
-// 1 = got partial packet
-static int GetPacket (struct gps_device_t *session )
+/* build and send a packet in serial protocol */
+/* layer_id unused */
+static void Build_Send_SER_Packet( struct gps_device_t *session,
+ uint32_t layer_id, uint32_t pkt_id, uint32_t length, uint32_t data )
{
- struct timespec delay, rem;
- int cnt = 0;
- // int x = 0; // for debug dump
-
- memset( session->driver.garmin.Buffer, 0, sizeof(Packet_t));
- memset( &delay, 0, sizeof(delay));
- session->driver.garmin.BufferLen = 0;
- session->outbuflen = 0;
-
- gpsd_report(4, "GetPacket()\n");
-
-//delay.tv_sec = 0;
-//delay.tv_nsec = 33300000L;
-//while (nanosleep(&delay, &rem) < 0)
-// continue;
-
- for( cnt = 0 ; cnt < 10 ; cnt++ ) {
- size_t pkt_size;
- // Read async data until the driver returns less than the
- // max async data size, which signifies the end of a packet
-
- // not optimal, but given the speed and packet nature of
- // the USB not too bad for a start
+ uint8_t *buffer = (uint8_t *)session->driver.garmin.Buffer;
+ Packet_t *thePacket = (Packet_t*)buffer;
ssize_t theBytesReturned = 0;
- uint8_t *buf = (uint8_t *)session->driver.garmin.Buffer;
- Packet_t *thePacket = (Packet_t*)buf;
-
- theBytesReturned = read(session->gpsdata.gps_fd
- , buf + session->driver.garmin.BufferLen
- , ASYNC_DATA_SIZE);
- // zero byte returned is a legal value and denotes the end of a
- // binary packet.
- if ( 0 > theBytesReturned ) {
- // read error...
- // or EAGAIN, but O_NONBLOCK is never set
- gpsd_report(0, "GetPacket() read error=%d, errno=%d\n"
- , theBytesReturned, errno);
- continue;
- }
- gpsd_report(5, "got %d bytes\n", theBytesReturned);
-
- session->driver.garmin.BufferLen += theBytesReturned;
- if ( 256 <= session->driver.garmin.BufferLen ) {
- // really bad read error...
- gpsd_report(3, "GetPacket() packet too long, %ld > 255 !\n"
- , session->driver.garmin.BufferLen);
- session->driver.garmin.BufferLen = 0;
- break;
- }
- pkt_size = 12 + get_int32((uint8_t*)&thePacket->mDataSize);
- if ( 12 <= session->driver.garmin.BufferLen) {
- // have enough data to check packet size
- if ( session->driver.garmin.BufferLen > pkt_size) {
- // wrong amount of data in buffer
- gpsd_report(3
- , "GetPacket() packet size wrong! Packet: %ld, s/b %ld\n"
- , session->driver.garmin.BufferLen
- , pkt_size);
- session->driver.garmin.BufferLen = 0;
- break;
- }
- }
- if ( 64 > theBytesReturned ) {
- // zero length, or short, read is a flag for got the whole packet
- break;
+ ssize_t theBytesToWrite = 6 + length;
+ uint8_t chksum = 0;
+
+ *buffer++ = (uint8_t)DLE;
+ *buffer++ = (uint8_t)pkt_id;
+ chksum = pkt_id;
+ *buffer++ = (uint8_t)length;
+ chksum += length;
+ if ( 2 == length ) {
+ /* carefull! no DLE stuffing here! */
+ set_int16(buffer, data);
+ chksum += buffer[0];
+ chksum += buffer[1];
+ } else if ( 4 == length ) {
+ /* carefull! no DLE stuffing here! */
+ set_int32(buffer, data);
+ chksum += buffer[0];
+ chksum += buffer[1];
+ chksum += buffer[2];
+ chksum += buffer[3];
}
-
+ buffer += length;
+
+ // Add checksum
+ *buffer++ = -chksum;
+ if ( DLE == -chksum ) {
+ /* stuff another DLE */
+ *buffer++ = (uint8_t)DLE;
+ theBytesToWrite++;
+ }
+
+ // Add DLE, ETX
+ *buffer++ = (uint8_t)DLE;
+ *buffer++ = (uint8_t)ETX;
+
+#if 1
+ gpsd_report(4, "SendPacket(), writing %d bytes: %s\n"
+ , theBytesToWrite, gpsd_hexdump(thePacket, theBytesToWrite));
+#endif
+ (void)PrintSERPacket ( session, buffer[1], buffer[2], buffer + 3);
- /*@ ignore @*/
- delay.tv_sec = 0;
- delay.tv_nsec = 3330000L;
- while (nanosleep(&delay, &rem) < 0)
- continue;
- /*@ end @*/
- }
- // dump the individual bytes, debug only
- // for ( x = 0; x < session->driver.garmin.BufferLen; x++ ) {
- // gpsd_report(6, "p[%d] = %x\n", x, session->driver.garmin.Buffer[x]);
- // }
- if ( 10 <= cnt ) {
- gpsd_report(3, "GetPacket() packet too long or too slow!\n");
- return -1;
- }
+ theBytesReturned = write( session->gpsdata.gps_fd
+ , thePacket, theBytesToWrite);
+ gpsd_report(4, "SendPacket(), wrote %d bytes\n", theBytesReturned);
- gpsd_report(5, "GotPacket() sz=%d \n", session->driver.garmin.BufferLen);
- session->outbuflen = session->driver.garmin.BufferLen;
- return 0;
}
+
/*
* garmin_probe()
*
+ * check that the garmin_gps driver is installed in the kernel
+ * and that an active USB device is using it.
+ *
+ * It does not yet check that the currect device is the one
+ * attached to the garmin. So if you have a garmin and another
+ * gps this could be a problem.
+ *
+ * this is very linux specific.
+ *
* return 1 if garmin_gps device found
* return 0 if not
+ *
*/
static bool garmin_probe(struct gps_device_t *session)
{
- Packet_t *thePacket = NULL;
- uint8_t *buffer = NULL;
- fd_set fds, rfds;
- struct timeval tv;
- int sel_ret = 0;
+ FILE *fp = NULL;
+ char buf[256];
int ok = 0;
- int i;
- /* check for USB serial drivers -- very Linux-specific */
+ /* check for garmin USB serial driver -- very Linux-specific */
if (access("/sys/module/garmin_gps", R_OK) != 0) {
gpsd_report(5, "garmin_gps not active.\n");
return false;
}
+ // check for a garmin_gps device in /proc
+ if ( !(fp = fopen( "/proc/bus/usb/devices", "r") ) ) {
+ gpsd_report(5, "Can't open /proc/bus/usb/devices\n");
+ return false;
+ }
+
+ ok = 0;
+ while ( 0 < fread( buf, sizeof(buf), 1, fp ) ) {
+ if ( strstr( buf, "garmin_gps") ) {
+ ok = 1;
+ break;
+ }
+ }
+ (void)fclose(fp);
+ if ( !ok ) {
+ // no device using garmin now
+ gpsd_report(5, "garmin_gps not in /proc/bus/usb/devices.\n");
+ return false;
+ }
/* Save original terminal parameters */
if (tcgetattr(session->gpsdata.gps_fd,&session->ttyset_old) != 0) {
@@ -732,6 +750,9 @@ static bool garmin_probe(struct gps_device_t *session)
return false;
}
+#ifdef __UNUSED
+ Packet_t *thePacket = NULL;
+ uint8_t *buffer = NULL;
/* reset the buffer and buffer length */
memset( session->driver.garmin.Buffer, 0, sizeof(session->driver.garmin.Buffer) );
session->driver.garmin.BufferLen = 0;
@@ -744,159 +765,16 @@ static bool garmin_probe(struct gps_device_t *session)
buffer = (uint8_t *)session->driver.garmin.Buffer;
thePacket = (Packet_t*)buffer;
+#endif /* __UNUSED__ */
// set Mode 1, mode 0 is broken somewhere past 2.6.14
// but how?
gpsd_report(3, "Set garmin_gps driver mode = 0\n");
- Build_Send_Packet( session, GARMIN_LAYERID_PRIVATE
- , PRIV_PKTID_SET_MODE, 4, 0);
+ Build_Send_USB_Packet( session, GARMIN_LAYERID_PRIVATE
+ , PRIV_PKTID_SET_MODE, 4, MODE_GARMIN_SERIAL);
// expect no return packet !?
- // get Version info
- gpsd_report(3, "Get garmin_gps driver version\n");
- Build_Send_Packet(session, GARMIN_LAYERID_PRIVATE, PRIV_PKTID_INFO_REQ
- , 0, 0);
-
- /* get and print the driver Version info */
-
- FD_ZERO(&fds);
- FD_SET(session->gpsdata.gps_fd, &fds);
-
- /* Wait, nicely, until the device returns the Version info
- * Toss any other packets, up to 4 */
- ok = 0;
- memset( &tv,0,sizeof(tv));
- for( i = 0 ; i < 4 ; i++ ) {
- memcpy((char *)&rfds, (char *)&fds, sizeof(rfds));
-
- tv.tv_sec = 1; tv.tv_usec = 0;
- sel_ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
- if (sel_ret < 0) {
- if (errno == EINTR)
- continue;
- gpsd_report(0, "select: %s\n", strerror(errno));
- return false;
- } else if ( sel_ret == 0 ) {
- gpsd_report(3, "garmin_probe() timeout, INFO_REQ\n");
- // restore old terminal settings
- // TCIOFLUSH here causes gpsfake to hang, so skip that
- (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW
- , &session->ttyset_old);
- return false;
- }
- if ( 0 == GetPacket( session ) ) {
- (void)PrintUSBPacket(session, thePacket);
-
- if( ( (uint8_t)75 == thePacket->mPacketType)
- && (PRIV_PKTID_INFO_RESP == thePacket->mPacketId) ) {
- ok = 1;
- break;
- }
- }
- }
-
- if ( 0 == ok ) {
- gpsd_report(2, "Garmin driver never answered to INFO_REQ.\n");
- // restore old terminal settings
- (void)tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH
- , &session->ttyset_old);
- return false;
- }
- /* depending on the GARMIN version, the device may spontaneously
- return the Product Capability here */
-
- /* Tell the device that we are starting a session. */
- gpsd_report(3, "Send Garmin Start Session\n");
-
- Build_Send_Packet(session, GARMIN_LAYERID_TRANSPORT
- , GARMIN_PKTID_TRANSPORT_START_SESSION_REQ, 0, 0);
-
- /* Wait until the device is ready to the start the session
- * Toss any other packets, up to 4 */
- ok = 0;
- for( i = 0 ; i < 4 ; i++ ) {
- memcpy((char *)&rfds, (char *)&fds, sizeof(rfds));
-
- tv.tv_sec = 1; tv.tv_usec = 0;
- sel_ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
- if (sel_ret < 0) {
- if (errno == EINTR)
- continue;
- gpsd_report(0, "select: %s\n", strerror(errno));
- return(0);
- } else if ( sel_ret == 0 ) {
- gpsd_report(3, "garmin_probe() timeout, START_SESSION\n");
- // restore old terminal settings
- (void)tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH
- , &session->ttyset_old);
- return(0);
- }
- if ( 0 == GetPacket( session ) ) {
- gpsd_report(3, "Got packet waiting for START_SESSION\n");
- (void)PrintUSBPacket(session, thePacket);
-
- if( (GARMIN_LAYERID_TRANSPORT == thePacket->mPacketType)
- && (GARMIN_PKTID_TRANSPORT_START_SESSION_RESP
- == thePacket->mPacketId) ) {
- ok = 1;
- break;
- }
- }
- }
-
- if ( 0 == ok ) {
- gpsd_report(2, "Garmin driver never answered to START_SESSION.\n");
- // restore old terminal settings
- (void)tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH
- , &session->ttyset_old);
- return false;
- }
-
- // Tell the device to send product data
- gpsd_report(3, "Get Garmin Product Data\n");
-
- Build_Send_Packet(session, GARMIN_LAYERID_APPL
- , GARMIN_PKTID_PRODUCT_RQST, 0, 0);
-
- // Get the product data packet
- // Toss any other packets, up to 4
- ok = 0;
- for( i = 0 ; i < 4 ; i++ ) {
- memcpy((char *)&rfds, (char *)&fds, sizeof(rfds));
-
- tv.tv_sec = 1; tv.tv_usec = 0;
- sel_ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
- if (sel_ret < 0) {
- if (errno == EINTR)
- continue;
- gpsd_report(0, "select: %s\n", strerror(errno));
- return false;
- } else if ( sel_ret == 0 ) {
- gpsd_report(3, "garmin_probe() timeout, PRODUCT_DATA\n");
- // restore old terminal settings
- (void)tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH
- , &session->ttyset_old);
- return false;
- }
- if ( 0 == GetPacket( session ) ) {
- (void)PrintUSBPacket(session, thePacket);
-
- if( (GARMIN_LAYERID_APPL == (uint32_t)thePacket->mPacketType)
- && ( GARMIN_PKTID_PRODUCT_DATA == thePacket->mPacketId) ) {
- ok = 1;
- break;
- }
- }
- }
-
- if ( 0 == ok ) {
- gpsd_report(2, "Garmin driver never answered to PRODUCT_DATA.\n");
- // restore old terminal settings
- (void)tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH
- , &session->ttyset_old);
- return false;
- }
- return true;
+ return 1;
}
/*
@@ -911,23 +789,23 @@ static bool garmin_probe(struct gps_device_t *session)
*/
static void garmin_init(struct gps_device_t *session)
{
- bool ret;
-
- gpsd_report(5, "to garmin_probe()\n");
- ret = garmin_probe( session );
- /* FIXME - what if return code was bad */
- /* FIXME - return code is always bad */
- gpsd_report(3, "from garmin_probe() = %d\n", (int)ret);
+ // Tell the device to send product data
+ gpsd_report(3, "Get Garmin Product Data\n");
+ Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL
+ , GARMIN_PKTID_PRODUCT_RQST, 0, 0);
// turn on PVT data 49
gpsd_report(3, "Set Garmin to send reports every 1 second\n");
- Build_Send_Packet(session, GARMIN_LAYERID_APPL
+ Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL
, GARMIN_PKTID_L001_COMMAND_DATA, 2, CMND_START_PVT_DATA);
+#if USE_RMD
// turn on RMD data 110
- // Build_Send_Packet(session, GARMIN_LAYERID_APPL
- // , GARMIN_PKTID_L001_COMMAND_DATA, 2, CMND_START_RM_DATA);
+ gpsd_report(3, "Set Garmin to send Raw sat data\n");
+ Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL
+ , GARMIN_PKTID_L001_COMMAND_DATA, 2, CMND_START_RM_DATA);
+#endif
}
static void garmin_close(struct gps_device_t *session UNUSED)
@@ -938,16 +816,8 @@ static void garmin_close(struct gps_device_t *session UNUSED)
return;
}
-static ssize_t garmin_get_packet(struct gps_device_t *session)
-{
- return (ssize_t)( 0 == GetPacket( session ) ? 1 : 0);
-}
-
-static gps_mask_t garmin_usb_parse(struct gps_device_t *session)
-{
- gpsd_report(5, "garmin_usb_parse()\n");
- return PrintUSBPacket(session, (Packet_t*)session->driver.garmin.Buffer);
-}
+#define Send_ACK() Build_Send_SER_Packet(session, 0, ACK, 0, 0)
+#define Send_NAK() Build_Send_SER_Packet(session, 0, NAK, 0, 0)
/*@ +charint @*/
gps_mask_t garmin_ser_parse(struct gps_device_t *session)
@@ -969,6 +839,7 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
if ( 6 > len ) {
/* WTF? */
/* minimum packet; <DLE> [pkt id] [length=0] [chksum] <DLE> <STX> */
+ Send_NAK();
gpsd_report(6, "Garmin serial too short: %#2x\n", len);
return 0;
}
@@ -978,6 +849,7 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
}
if ( '\x10' != buf[0] ) {
+ Send_NAK();
gpsd_report(6, "buf[0] not DLE\n", buf[0]);
return 0;
}
@@ -986,6 +858,7 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
chksum = pkt_id;
if ( '\x10' == pkt_id ) {
if ( '\x10' != buf[n++] ) {
+ Send_NAK();
gpsd_report(6, "Bad pkt_id %#02x\n", pkt_id);
return 0;
}
@@ -996,6 +869,7 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
if ( '\x10' == pkt_len ) {
if ( '\x10' != buf[n++] ) {
gpsd_report(6, "Bad pkt_len %#02x\n", pkt_len);
+ Send_NAK();
return 0;
}
}
@@ -1008,12 +882,14 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
}
if ( len < n + i ) {
gpsd_report(6, "Packet too short %#02x < %#0x\n", len, n + i);
+ Send_NAK();
return 0;
}
c = buf[n + i];
if ( got_dle ) {
got_dle = 0;
if ( '\x10' != c ) {
+ Send_NAK();
gpsd_report(6, "Bad DLE %#02x\n", c);
return 0;
}
@@ -1027,6 +903,7 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
}
/* get checksum */
if ( len < n + i ) {
+ Send_NAK();
gpsd_report(6, "No checksum, Packet too short %#02x < %#0x\n"
, len, n + i);
return 0;
@@ -1035,23 +912,27 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
chksum += c;
/* get final DLE */
if ( len < n + i ) {
+ Send_NAK();
gpsd_report(6, "No final DLE, Packet too short %#02x < %#0x\n"
, len, n + i);
return 0;
}
c = buf[n + i++];
if ( '\x10' != c ) {
+ Send_NAK();
gpsd_report(6, "Final DLE not DLE\n", c);
return 0;
}
/* get final ETX */
if ( len < n + i ) {
+ Send_NAK();
gpsd_report(6, "No final ETX, Packet too short %#02x < %#0x\n"
, len, n + i);
return 0;
}
c = buf[n + i++];
if ( '\x03' != c ) {
+ Send_NAK();
gpsd_report(6, "Final ETX not ETX\n", c);
return 0;
}
@@ -1062,6 +943,8 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
gpsd_report(6, "Char: %#02x\n", data_buf[i]);
}
+ Send_ACK();
+
gpsd_report(4
, "garmin_ser_parse() Type: %#02x, Len: %#02x, chksum: %#02x\n"
, pkt_id, pkt_len, chksum);
@@ -1073,7 +956,126 @@ gps_mask_t garmin_ser_parse(struct gps_device_t *session)
/*@ -charint @*/
/* this is everything we export */
-struct gps_type_t garmin_usb_binary =
+#ifdef __UNUSED__
+static int GetPacket (struct gps_device_t *session );
+//-----------------------------------------------------------------------------
+// Gets a single packet.
+// this is odd, the garmin usb driver will only return 64 bytes, or less
+// at a time, no matter what you ask for.
+//
+// is you ask for less than 64 bytes then the next packet will include
+// just the remaining bytes of the last 64 byte packet.
+//
+// Reading a packet of length Zero, or less than 64, signals the end of
+// the entire packet.
+//
+// The Garmin sample WinXX code also assumes the same behavior, so
+// maybe it is something in the USB protocol.
+//
+// Return: 0 = got a good packet
+// -1 = error
+// 1 = got partial packet
+static int GetPacket (struct gps_device_t *session )
+{
+ struct timespec delay, rem;
+ int cnt = 0;
+ // int x = 0; // for debug dump
+
+ memset( session->driver.garmin.Buffer, 0, sizeof(Packet_t));
+ memset( &delay, 0, sizeof(delay));
+ session->driver.garmin.BufferLen = 0;
+ session->outbuflen = 0;
+
+ gpsd_report(4, "GetPacket()\n");
+
+ for( cnt = 0 ; cnt < 10 ; cnt++ ) {
+ size_t pkt_size;
+ // Read async data until the driver returns less than the
+ // max async data size, which signifies the end of a packet
+
+ // not optimal, but given the speed and packet nature of
+ // the USB not too bad for a start
+ ssize_t theBytesReturned = 0;
+ uint8_t *buf = (uint8_t *)session->driver.garmin.Buffer;
+ Packet_t *thePacket = (Packet_t*)buf;
+
+ theBytesReturned = read(session->gpsdata.gps_fd
+ , buf + session->driver.garmin.BufferLen
+ , ASYNC_DATA_SIZE);
+ // zero byte returned is a legal value and denotes the end of a
+ // binary packet.
+ if ( 0 > theBytesReturned ) {
+ // read error...
+ // or EAGAIN, but O_NONBLOCK is never set
+ gpsd_report(0, "GetPacket() read error=%d, errno=%d\n"
+ , theBytesReturned, errno);
+ continue;
+ }
+ gpsd_report(5, "got %d bytes\n", theBytesReturned);
+#if 1
+ gpsd_report(4, "getPacket(), got %d bytes: %s\n"
+ , theBytesReturned, gpsd_hexdump(thePacket, theBytesReturned));
+#endif
+
+ session->driver.garmin.BufferLen += theBytesReturned;
+ if ( 256 <= session->driver.garmin.BufferLen ) {
+ // really bad read error...
+ gpsd_report(3, "GetPacket() packet too long, %ld > 255 !\n"
+ , session->driver.garmin.BufferLen);
+ session->driver.garmin.BufferLen = 0;
+ break;
+ }
+ pkt_size = 12 + get_int32((uint8_t*)&thePacket->mDataSize);
+ if ( 12 <= session->driver.garmin.BufferLen) {
+ // have enough data to check packet size
+ if ( session->driver.garmin.BufferLen > pkt_size) {
+ // wrong amount of data in buffer
+ gpsd_report(3
+ , "GetPacket() packet size wrong! Packet: %ld, s/b %ld\n"
+ , session->driver.garmin.BufferLen
+ , pkt_size);
+ session->driver.garmin.BufferLen = 0;
+ break;
+ }
+ }
+ if ( 64 > theBytesReturned ) {
+ // zero length, or short, read is a flag for got the whole packet
+ break;
+ }
+
+
+ /*@ ignore @*/
+ delay.tv_sec = 0;
+ delay.tv_nsec = 3330000L;
+ while (nanosleep(&delay, &rem) < 0)
+ continue;
+ /*@ end @*/
+ }
+ // dump the individual bytes, debug only
+ // for ( x = 0; x < session->driver.garmin.BufferLen; x++ ) {
+ // gpsd_report(6, "p[%d] = %x\n", x, session->driver.garmin.Buffer[x]);
+ // }
+ if ( 10 <= cnt ) {
+ gpsd_report(3, "GetPacket() packet too long or too slow!\n");
+ return -1;
+ }
+
+ gpsd_report(5, "GotPacket() sz=%d \n", session->driver.garmin.BufferLen);
+ session->outbuflen = session->driver.garmin.BufferLen;
+ return 0;
+}
+static gps_mask_t garmin_usb_parse(struct gps_device_t *session)
+{
+ gpsd_report(5, "garmin_usb_parse()\n");
+ return PrintUSBPacket(session, (Packet_t*)session->driver.garmin.Buffer);
+}
+
+static ssize_t garmin_get_packet(struct gps_device_t *session)
+{
+ return (ssize_t)( 0 == GetPacket( session ) ? 1 : 0);
+}
+
+struct gps_type_t garmin_usb_binary_old =
{
.typename = "Garmin USB binary", /* full name of type */
.trigger = NULL, /* no trigger, it has a probe */
@@ -1091,6 +1093,26 @@ struct gps_type_t garmin_usb_binary =
.wrapup = garmin_close, /* close hook */
.cycle = 1, /* updates every second */
};
+#endif /* __UNUSED__ */
+
+struct gps_type_t garmin_usb_binary =
+{
+ .typename = "Garmin USB binary", /* full name of type */
+ .trigger = NULL, /* no trigger, it has a probe */
+ .channels = GARMIN_CHANNELS, /* consumer-grade GPS */
+ .wakeup = NULL, /* no wakeup to be done before hunt */
+ .probe = garmin_probe, /* how to detect at startup time */
+ .initializer = garmin_init, /* initialize the device */
+ .get_packet = packet_get, /* how to grab a packet */
+ .parse_packet = garmin_ser_parse, /* parse message packets */
+ .rtcm_writer = NULL, /* don't send DGPS corrections */
+ .speed_switcher = NULL, /* no speed switcher */
+ .mode_switcher = NULL, /* no mode switcher */
+ .rate_switcher = NULL, /* no sample-rate switcher */
+ .cycle_chars = -1, /* not relevant, no rate switch */
+ .wrapup = garmin_close, /* close hook */
+ .cycle = 1, /* updates every second */
+};
struct gps_type_t garmin_ser_binary =
{