gd2/gd2.c100644 645 645 107477 6423241554 12026 0ustar bentsonbentsonstatic char *rcsid ="$Revision: 2.7 $$Date: 1997/10/22 00:03:34 $"; /* This program is based on protocol description by * william.soley@sun.com, werme@zk3.dec.com * http://playground.sun.com/pub/soley/garmin.txt * and was inspired by M.J.Montgomery's GarDown program. * * Thanks to correspondence with, and hints and code from, * Thomas Dean * Paul A. Edwards * Cliff Olling * David Woolley * * It is designed to extract most conventional information, * such as tracks, routes, waypoints, position, clock, and * almanac. Since Soley's report does not describe all * messages, this program does not interpret those additional * messages. These messages are suspected to include more * status on signals and such. * * This version can also upload routes and waypoints. * The best way to use this feature is to download * routes and waypoints to determine the file format, * then upload an file with additional entries. * * It is distrubuted under the GNU Public License. * * Randolph Bentson * bentson@grieg.seaslug.org * *$Log: gd2.c,v $ *Revision 2.7 1997/10/22 00:03:34 bentson *change some floats to doubles; changes to support FreeBSD; *strip unused date code; * *Revision 2.6 1997/10/15 05:42:42 bentson *add a "listen only" command to catch-up with async reports * *Revision 2.5 1997/10/01 00:43:57 bentson *add cfg and all flags; use ISO 8601 std; upload track; *better support for STDIN; * *Revision 2.4 1997/09/30 18:16:08 bentson *sort of works to upload/download proximity points * *Revision 2.3djw1 1997/10/18 David Woolley *wrong location for NUL test in memcpyset/const violation *sscanf %c doesn't store NUL; lost precision on waypoint upload * *Revision 2.3 1997/09/20 22:14:57 bentson *update argument checks and error reporting * *Revision 2.2 1997/09/20 21:53:18 bentson *don't wait for EOT for IdData, Posn and UTC records; *get UTC option parsed correctly * *Revision 2.1 1997/09/04 18:59:42 bentson *shuffle for cosmetic purposes * *Revision 2.0 1997/09/04 06:50:07 bentson *added support to upload waypoints and routes * *Revision 1.1 1996/11/30 01:02:34 bentson *Initial revision * */ #include #include #include #include #include #include #include #include #include #include /* for BSD systems, termios does not include some definitions */ #ifndef OLCUC #define OLCUC 0000002 #endif #ifndef OCRNL #define OCRNL 0000010 #endif #ifndef IUCLC #define IUCLC 0001000 #endif #ifndef CBAUD #define CBAUD 0010017 #endif #ifndef XCASE #define XCASE 0000004 #endif /* Define the following if you have a Garmin 45 or Garmin 12xl */ #define GRMN45 #define MyPI 3.1415926535 #define EPOCH_DIFF 631065600L /* delta from Unix epoch to Garmin epoch */ #define GRMN_CLOCK 255750.0 /* rate of Garmin internal clock */ #define DEFAULT_PORT "/dev/gps0" /* Where the device is attached */ #define MsgSigAmp 0x01 #define MsgACK 0x06 #define MsgRequest 0x0a #define MsgEOT 0x0c #define MsgEvent 0x0d #define MsgUTC 0x0e #define MsgPosn 0x11 #define Msg12 0x12 #define MsgProx 0x13 #define Msg14 0x14 #define MsgNAK 0x15 #define Msg16 0x16 #define Msg17 0x17 #define Msg19 0x19 #define MsgSatStat 0x1a #define MsgBOT 0x1b #define MsgAsync 0x1c #define MsgRoute 0x1d #define MsgRteWpt 0x1e #define MsgAlmanac 0x1f #define MsgVersion 0x20 #define MsgTrack 0x22 #define MsgWayPt 0x23 #define Msg27 0x27 #define Msg28 0x28 #define Msg29 0x29 #define MsgSatSel 0x2a #define MsgIdReq 0xfe #define MsgIdData 0xff #define ReqAlmanac 0x1 #define ReqPosn 0x2 #define ReqProx 0x3 #define ReqRoute 0x4 #define ReqUTC 0x5 #define ReqTrack 0x6 #define ReqWayPt 0x7 #define ReqPowerOff 0x8 #define ReqAll 0x17 #define ReqCfg 0x18 struct ProximityData{ char name[6] __attribute__ ((packed)); long latitude __attribute__ ((packed)); long longitude __attribute__ ((packed)); long time_date __attribute__ ((packed)); char comment[40] __attribute__ ((packed)); char fill[2] __attribute__ ((packed)); float alarm_radius __attribute__ ((packed)); }ProximityData; struct RouteData { char number[1] __attribute__ ((packed)); char comment[20] __attribute__ ((packed)); }RouteData; struct RouteWaypointData{ char name[6] __attribute__ ((packed)); long latitude __attribute__ ((packed)); long longitude __attribute__ ((packed)); long time_date __attribute__ ((packed)); char comment[40] __attribute__ ((packed)); }RouteWaypointData; struct AlmanacData{ short week __attribute__ ((packed)); float ToA __attribute__ ((packed)); float Af0 __attribute__ ((packed)); float Af1 __attribute__ ((packed)); float Ecc __attribute__ ((packed)); float SqrtA __attribute__ ((packed)); float Anom __attribute__ ((packed)); float Perigree __attribute__ ((packed)); float RtAscen __attribute__ ((packed)); float Rate_of_RtAscen __attribute__ ((packed)); float OrbitIncline __attribute__ ((packed)); }AlmanacData; struct WaypointData{ char name[6] __attribute__ ((packed)); long latitude __attribute__ ((packed)); long longitude __attribute__ ((packed)); long time_date __attribute__ ((packed)); char comment[40] __attribute__ ((packed)); }WaypointData; struct TrackData{ long latitude __attribute__ ((packed)); long longitude __attribute__ ((packed)); long time_date __attribute__ ((packed)); char flag __attribute__ ((packed)); }TrackData; #define BUFSIZE 1024 extern char *optarg; int power=0, async=-1, format=0, debug_flags=0; int position=0, utc=0, ident = 0, listen=0; int get_almanac=0, get_waypoint=0, get_route=0, get_track=0; int set_almanac=0, set_waypoint=0, set_route=0, set_track=0; char *fn_almanac, *fn_waypoint, *fn_route, *fn_track; #ifdef GRMN45 int get_proximity=0, set_proximity=0, get_all=0, get_cfg=0; char *fn_proximity; #endif void usage(){ printf ("-a get almanac\n"); printf ("-f formatting options\n"); if (format){ printf(" 0x1 -> track as Deg instead of Deg Min\n"); } printf ("-h help -- show this\n"); printf ("-i query unit ident\n"); printf ("-p query position\n"); printf ("-r get routes\n"); printf ("-t get tracks\n"); printf ("-u request UTC time\n"); printf ("-w get waypoints\n"); #ifdef GRMN45 printf ("-x get proximity points\n"); #endif printf ("-A set almanac\n"); printf ("-D debug operation\n"); if (debug_flags){ printf(" 0x1 -> record assembly\n"); printf(" 0x2 -> binary record display\n"); printf(" 0x4 -> command issue/completion\n"); printf(" 0x10 -> display chars as transmitted\n"); printf(" 0x20 -> display outbound source record\n"); } printf ("-P specify port %s\n", DEFAULT_PORT); printf ("-R set routes\n"); printf ("-T set tracks\n"); printf ("-V display version\n"); printf ("-W set waypoints\n"); #ifdef GRMN45 printf ("-X set proximity points\n"); #endif printf ("-Y enable async\n"); if (async != -1){ printf(" 0x0 = disable all (no bits set)\n"); printf(" 0x1 = enables RecordType=00,01,02\n"); printf(" 0x2 = enables RecordType=0d\n"); printf(" 0x4 = enables RecordType=14,27,28\n"); printf(" 0x8 = enables RecordType=16\n"); printf(" 0x10 = enables RecordType=17\n"); printf(" 0x20 = enables RecordType=07,12,19\n"); printf(" 0x40 = enables RecordType=07,12\n"); printf(" 0x80 = enables RecordType=1a\n"); printf("0x100 = enables RecordType=29,2a\n"); printf("0xffff = enables all (all bits set)\n"); printf(" 00 - filler?, 01 - SigAmp, 02 - ?, 07 - ?\n"); printf(" 0d - Event (SatAcq, NavQual,etc.), 12 - ?, 14 - ?\n"); printf(" 16 - comes in groups, one for each sat tracked\n"); printf(" 17 - ?, 19 - ?, 1A - SatStat, 27 - ?, 28 - ?\n"); printf(" 29 - cames with 2A, 2A - SatSel\n"); } printf ("-Z power off\n"); printf ("missing filename or '-' refers to STDIN\n"); printf ("\n"); }/* usage */ void notyet(){ fprintf(stdout,"This option may not yet be operational\n"); fprintf(stdout,"If you wish to experiment, remove the\n"); fprintf(stdout,"appropriate call to 'notyet' in the source\n"); fprintf(stdout,"and report the results.\n"); }/* notyet */ void disp_msg(char *buffer, int size, char *suffix){ int index; for (index = 0; index < size; index++){ printf("%2.2x ", 0xff & buffer[index]); } printf("%s\n", suffix); fflush(stdout); }/* disp_msg */ void memcpyset(void *dest, const void *src, size_t n, char fill){ while(n--){ if (*(char *)src == '\n'){ *(char *)dest++ = '\0'; break; } *(char *)dest++ = *(char *)src++; if (*(char *)src == '\0'){ break; } } while(n--){ *(char *)dest++ = fill; } }/* memcpyset */ char checksum(char *string, int count){ int retval = 0; while (count--){ retval += *string++; } return (retval & 0xff); }/* checksum */ /* compare records for qsort routine */ int mss_cmp(const char *one, const char *two){ return(*one - *two); }/* mss_cmp */ char * iso_time(const time_t *timep){ static char now[40]; struct tm *time_parts; time_parts = gmtime(timep); sprintf(now,"%4.4d/%2.2d/%2.2d-%2.2d:%2.2d:%2.2d", time_parts->tm_year+1900, time_parts->tm_mon+1, time_parts->tm_mday, time_parts->tm_hour, time_parts->tm_min, time_parts->tm_sec); return now; }/* iso_time */ /* 1997/09/30-11:43:44 */ long iso2time(char *now){ struct tm tp; int retval; now[4] = now[7] = now[10] = now[13] = now[16] = ' '; tp.tm_sec = 0; tp.tm_wday = 0; tp.tm_yday = 0; tp.tm_isdst = 0; retval = sscanf(now, "%d %d %d %d %d %d", &tp.tm_year, &tp.tm_mon, &tp.tm_mday, &tp.tm_hour, &tp.tm_min, &tp.tm_sec); if(retval != 6) { return EPOCH_DIFF ; } tp.tm_year -= 1900; tp.tm_mon -= 1; return mktime(&tp); }/* iso2time */ void send_ack(int grmn_fd, int type){ static char msg[] = "\x10\x06\x02\x00\x00\x00\x10\x03"; msg[3] = type; msg[5] = 0xF8 - type; if (write(grmn_fd, msg, 8) != 8){ fprintf(stderr, "couldn't write ack\n"); exit(1); } }/* send_ack */ void send_nak(int grmn_fd, int type){ static char msg[] = "\x10\x15\x02\x00\x00\x00\x10\x03"; msg[3] = type; msg[5] = 0xE9 - type; if (write(grmn_fd, msg, 8) != 8){ fprintf(stderr, "couldn't write nak\n"); exit(1); } }/* send_nak */ void send_cmd(int grmn_fd, int type){ static char msg[] = "\x10\x0A\x02\x00\x00\x00\x10\x03"; msg[3] = type; msg[5] = 0xF4 - type; /* checksum */ if (write(grmn_fd, msg, 8) != 8){ fprintf(stderr, "couldn't write command\n"); exit(1); } }/* send_cmd */ void send_cmd2(int grmn_fd, int type){ static char msg[] = "\x10\x1C\x02\x00\x00\x00\x10\x03"; msg[3] = type; msg[4] = type>>8; msg[5] = 0xE2 - (0xff & type) - (type>>8); /* checksum */ if (write(grmn_fd, msg, 8) != 8){ fprintf(stderr, "couldn't write command\n"); exit(1); } }/* send_cmd2 */ void send_msg0(int grmn_fd, int type){ static char msg[] = "\x10\x00\x00\x02\x10\x03"; msg[1] = type; msg[3] = 0 - type; /* checksum */ if (write(grmn_fd, msg, 6) != 6){ fprintf(stderr, "couldn't write command\n"); exit(1); } }/* send_msg0 */ /* Write one record to character stream. */ int writerec(int grmn_fd, char buffer[], int size, int type){ char *bufp; int checksum = 0; if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0x10); write(grmn_fd,"\x10",1); /* DLE */ if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0xff & type); write(grmn_fd,&type,1); /* record type */ checksum += type; if(size == '\x10'){ if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0xff & size); write(grmn_fd,"\x10",1); } if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", size); write(grmn_fd,&size,1); /* record size */ checksum += size; bufp = buffer; while(size--){ if(*bufp == '\x10'){ if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0x10); write(grmn_fd,"\x10",1); } if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0xff & *bufp); write(grmn_fd,bufp,1); /* message byte */ checksum += *bufp++; } checksum = -checksum; if((checksum & 0xff) == '\x10'){ if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0x10); write(grmn_fd,"\x10",1); } if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0xff & checksum); write(grmn_fd,&checksum,1); /* checksum */ if (0x10 & debug_flags) fprintf(stderr, "%2.2x ", 0x10); write(grmn_fd,"\x10",1); /* DLE */ if (0x10 & debug_flags) fprintf(stderr, "%2.2x \n", 0x03); write(grmn_fd,"\x03",1); /* EOT */ }/* writerec */ /* Read one record from character stream. Returns (-1 on error) or (number of characters read at end of record or when nothing seen for 15 seconds). */ int readrec(int grmn_fd, char buffer[], int size){ int retval, count; struct timeval delay; fd_set readfds; char *charp = buffer; int ccount = 0; int rec_len; int state = 0; if (size == 0) return (-1); FD_ZERO(&readfds); FD_SET(grmn_fd, &readfds); delay.tv_usec = 0; delay.tv_sec = 15; while ((retval = select(grmn_fd+1, &readfds, 0, 0, &delay)) > 0){ if((retval = read(grmn_fd, charp, 1))>0){ if (0x1 & debug_flags) fprintf(stderr, "%2.2x<%d> ", 0xff & *charp, state); switch (state){ case 0: /* 1st DLE */ if (*charp == '\x10'){ state++; } break; case 1: /* command */ if (*charp == '\x3'){ goto reset; } if (*charp == '\x10'){ goto reset; } state++; goto keep; case 2: /* rec length */ if (*charp == '\x10'){ state++; break; } state++; case 3: /* rec length may have been escaped */ rec_len = 1 + *charp; state++; goto keep; case 4: /* is message body escaped? */ state++; if (*charp == '\x10'){ break; } case 5: /* message body */ state = 4; keep: charp++; ccount++; if (--rec_len == 0){ state = 6; break; } if (size-- == 0){ return (-1); } break; case 6: /* is checksum escaped? */ state++; if (*charp == '\x10'){ break; } case 7: /* checksum */ if (0x1 & debug_flags) fprintf(stderr, "[%x %x] ", 0xff & checksum(&buffer[0], buffer[1]+2), 0xff & *charp); if (0xff & (checksum(&buffer[0], buffer[1]+2) + *charp)){ goto reset; } state++; break; case 8: /* 2nd DLE */ if (*charp != '\x10'){ goto reset; } state++; break; case 9: /* EOF */ if (*charp != '\x3'){ goto reset; } if (0x1 & debug_flags) fprintf(stderr, "\n"); return(ccount); reset: state = 0; charp = buffer; ccount = 0; } }else if(retval == -1){ fprintf(stderr, "error during read from port\n"); exit(1); } } /* should add checksum validation at this point!!! */ if (retval == -1){ fprintf(stderr, "couldn't read from port\n"); exit(1); }else if (retval == 0){ fprintf(stderr, "timeout\n"); return(ccount); }else{ fprintf(stderr, "don't know what happened\n"); return(-1); } }/* readrec */ /* process one record--generate ack if appropriate */ int inrec(int grmn_fd, unsigned char buffer[], int size){ int index; char tmp_s[256], tmp_s2[256]; long tmp_l; float radius; double latitude_d, longitude_d; long grmn_time; if (size == -1){ disp_msg(buffer, size, " ERROR"); send_nak(grmn_fd, 0); /****** control messages *********/ }else if(buffer[0] == MsgACK){ if (0x2 & debug_flags) disp_msg(buffer, size, " ACK"); return MsgACK; }else if(buffer[0] == MsgNAK){ if (0x2 & debug_flags) disp_msg(buffer, size, " NAK"); return MsgNAK; }else if(buffer[0] == MsgEOT){ if (0x2 & debug_flags) disp_msg(buffer, size, " EOT"); send_ack(grmn_fd, MsgEOT); return MsgEOT; }else if(buffer[0] == MsgBOT){ if (0x2 & debug_flags) disp_msg(buffer, size, " BOT"); send_ack(grmn_fd, MsgBOT); return MsgBOT; /****** data messages *********/ }else if(buffer[0] == MsgPosn){ if (0x2 & debug_flags){ disp_msg(buffer, size, " POS"); }else { latitude_d = (180/MyPI) * *(double *)(&buffer[2]); longitude_d = (180/MyPI) * *(double *)(&buffer[10]); printf("POS %lf %lf\n", latitude_d, longitude_d); } send_ack(grmn_fd, MsgPosn); return MsgPosn; }else if(buffer[0] == MsgRoute){ if (0x2 & debug_flags){ disp_msg(buffer, size, " RTE"); }else{ strncpy(tmp_s, &buffer[3], 20); tmp_s[20] = '\0'; printf("RTE %d %s\n", buffer[2], tmp_s); } send_ack(grmn_fd, MsgRoute); return MsgRoute; }else if(buffer[0] == MsgRteWpt){ if (0x2 & debug_flags){ disp_msg(buffer, size, " RTW"); }else{ tmp_l = *(long *)(&buffer[8]); latitude_d = tmp_l/((1L<<30)/90.0); tmp_l = *(long *)(&buffer[12]); longitude_d = tmp_l/((1L<<30)/90.0); grmn_time = *(long *)(&buffer[16]); grmn_time += EPOCH_DIFF; strncpy(tmp_s, &buffer[2], 6); tmp_s[6] = '\0'; strncpy(tmp_s2, &buffer[20], 40); tmp_s2[40] = '\0'; printf(" %s %.8lf %.8lf %s %s\n", tmp_s, latitude_d, longitude_d, iso_time(&grmn_time), tmp_s2); } send_ack(grmn_fd, MsgRteWpt); return MsgRteWpt; }else if(buffer[0] == MsgAlmanac){ if (0x2 & debug_flags){ disp_msg(buffer, size, " ALC"); }else{ if (0xffff == *(unsigned short *)(&buffer[2])){ printf("ALC %2.2x %4.4x %4.4x %4.4x %4.4x %4.4x\n\t%4.4x %4.4x %4.4x %4.4x %4.4x\n", *(unsigned short *)(&buffer[2]), *(long *)(&buffer[4]), *(long *)(&buffer[8]), *(long *)(&buffer[12]), *(long *)(&buffer[16]), *(long *)(&buffer[20]), *(long *)(&buffer[24]), *(long *)(&buffer[28]), *(long *)(&buffer[32]), *(long *)(&buffer[36]), *(long *)(&buffer[40]) ); }else{ printf("ALC %d %8.0f %f %f %f %f\n\t %f %f %f %f %f\n", *(unsigned short *)(&buffer[2]), *(float *)(&buffer[4]), *(float *)(&buffer[8]), *(float *)(&buffer[12]), *(float *)(&buffer[16]), *(float *)(&buffer[20]), *(float *)(&buffer[24]), *(float *)(&buffer[28]), *(float *)(&buffer[32]), *(float *)(&buffer[36]), *(float *)(&buffer[40]) ); } } send_ack(grmn_fd, MsgAlmanac); return MsgAlmanac; }else if(buffer[0] == MsgTrack){ if (0x2 & debug_flags){ disp_msg(buffer, size, " TRK"); }else{ tmp_l = *(long *)(&buffer[2]); latitude_d = tmp_l/((1L<<30)/90.0); tmp_l = *(long *)(&buffer[6]); longitude_d = tmp_l/((1L<<30)/90.0); grmn_time = *(long *)(&buffer[10]); grmn_time += EPOCH_DIFF; if (format & 0x1){ printf("TRK %.10lf %.10lf %s %c\n", latitude_d, longitude_d, iso_time(&grmn_time), (buffer[14]==0)?'0':'1'); }else{ printf("TRK %c%d %lf %c%d %lf %s %c\n", latitude_d<0?'S':'N', abs((int)latitude_d), 60.0*(fabs(latitude_d) - abs((int)latitude_d)), longitude_d<0?'W':'E', abs((int)longitude_d), 60.0*(fabs(longitude_d) - abs((int)longitude_d)), iso_time(&grmn_time), (buffer[14]==0)?'0':'1'); } } send_ack(grmn_fd, MsgTrack); return MsgTrack; }else if(buffer[0] == MsgWayPt){ if (0x2 & debug_flags){ disp_msg(buffer, size, " WPT"); }else{ tmp_l = *(long *)(&buffer[8]); latitude_d = tmp_l/((1L<<30)/90.0); tmp_l = *(long *)(&buffer[12]); longitude_d = tmp_l/((1L<<30)/90.0); grmn_time = *(long *)(&buffer[16]); grmn_time += EPOCH_DIFF; strncpy(tmp_s, &buffer[2], 6); tmp_s[6] = '\0'; strncpy(tmp_s2, &buffer[20], 40); tmp_s2[40] = '\0'; printf("WPT %s %6s %lf %lf %s %s\n", buffer[20]?"":" ", tmp_s, latitude_d, longitude_d, iso_time(&grmn_time), tmp_s2); } send_ack(grmn_fd, MsgWayPt); return MsgWayPt; /******************************/ }else if(buffer[0] == MsgProx){ if (0x2 & debug_flags){ disp_msg(buffer, size, " PRX"); }else{ tmp_l = *(long *)(&buffer[8]); latitude_d = tmp_l/((1L<<30)/90.0); tmp_l = *(long *)(&buffer[12]); longitude_d = tmp_l/((1L<<30)/90.0); grmn_time = *(long *)(&buffer[16]); grmn_time += EPOCH_DIFF; strncpy(tmp_s, &buffer[2], 6); tmp_s[6] = '\0'; strncpy(tmp_s2, &buffer[20], 40); tmp_s2[40] = '\0'; radius = *(float *)(&buffer[62]); printf("PRX %s %6s %lf %lf %f %s %s\n", buffer[20]?"":" ", tmp_s, latitude_d, longitude_d, radius, iso_time(&grmn_time), tmp_s2); } send_ack(grmn_fd, MsgProx); return MsgProx; /******************************/ }else if(buffer[0] == MsgIdData){ if (0x2 & debug_flags){ disp_msg(buffer, size, " IDx"); }else{ printf("ID %s\n", &buffer[6]); } send_ack(grmn_fd, MsgIdData); return MsgIdData; }else if(buffer[0] == MsgUTC){ if (0x2 & debug_flags){ disp_msg(buffer, size, " UTC"); }else{ tmp_l = *(long *)(&buffer[10]); printf("UTC %d/%d/%d %2.2d:%2.2d:%2.2d %f\n", *(short *)(&buffer[4]), buffer[3], buffer[2], buffer[6], buffer[8], buffer[9], tmp_l/GRMN_CLOCK); } send_ack(grmn_fd, MsgUTC); return MsgUTC; /****** async messages *********/ }else if(buffer[0] == MsgSatSel){ if (0x2 & debug_flags){ disp_msg(buffer, size, " MSL"); }else{ printf("MSL %d\n", *(short *)(&buffer[2])); } return MsgSatSel; }else if(buffer[0] == MsgSatStat){ if (0x2 & debug_flags){ disp_msg(buffer, size, " MSS"); }else{ printf("MSS"); /* qsort(&buffer[2], 8, 7, mss_cmp); */ for(index = 0; index < 8; index++){ printf("\t%2d %3d %4x %d %2x\n", 0xff & buffer[2+7*index], 0xff & buffer[3+7*index], *(short *)(&buffer[4+7*index]), 0xff & buffer[6+7*index], 0xff & buffer[7+7*index], 0xff & buffer[8+7*index]); } fflush(stdout); } return MsgSatStat; }else if(buffer[0] == MsgSigAmp){ if (0x2 & debug_flags){ disp_msg(buffer, size, " SIG"); }else{ printf("SIG %d %x\n", *(short *)(&buffer[2]), *(short *)(&buffer[2]) ); } return MsgSigAmp; }else if(buffer[0] == MsgVersion){ if (0x2 & debug_flags){ disp_msg(buffer, size, " VER"); }else{ strncpy(tmp_s, &buffer[2], 7); tmp_s[7] = '\0'; printf("VER %s\n", tmp_s); } return MsgVersion; /****** command messages *********/ }else if(buffer[0] == MsgRequest){ disp_msg(buffer, size, " Req"); send_nak(grmn_fd, MsgRequest); return MsgRequest; }else{ disp_msg(buffer, size, " unknown"); send_ack(grmn_fd, buffer[0]); return 0; } }/* inrec */ /* Process block of data, one record after another; return when empty */ void readblock(int grmn_fd, unsigned char *buffer, int bufsize){ int retval, retval2; while ((retval = readrec(grmn_fd, buffer, BUFSIZE))>0){ retval2 = inrec(grmn_fd, buffer, retval); if (retval2 == MsgEOT || retval2 == MsgIdData || retval2 == MsgPosn || retval2 == MsgUTC ){ break; } } }/* readblock */ int get_ack(int grmn_fd, unsigned char buffer[]){ int retval, retval2; while ((retval = readrec(grmn_fd, buffer, BUFSIZE))>0){ retval2 = inrec(grmn_fd, buffer, retval); if (retval2 == MsgACK){ return 1; } } return 0; }/* get_ack */ /* send one record--look for ack */ int outrec(int grmn_fd, unsigned char buffer[], int type){ int retval; char name[256], comment[256], time[256]; char flag1, flag2, flag3; long tmp_l, latdeg, londeg; float radius; double latitude_d, longitude_d; long grmn_time; if(0x20 & debug_flags) fprintf(stderr, "send %s\n", buffer); if(strncmp(buffer,"RTE",3) == 0 && type == MsgRoute){ retval = sscanf(&buffer[4], "%d %128c", &tmp_l, comment); RouteData.number[0] = (char)(0x1f & tmp_l); memcpyset(RouteData.comment, comment, 20, ' '); do{ writerec(grmn_fd, (char *)&RouteData, sizeof(RouteData), MsgRoute); }while(!get_ack(grmn_fd, buffer)); }else if(buffer[0] == ' ' && type == MsgRoute){ retval = sscanf(&buffer[1], "%6c %lf %lf %19c %[^\n]", name, &latitude_d, &longitude_d, time, comment); memcpyset(RouteWaypointData.name, name, 6, ' '); tmp_l = latitude_d * ((1L<<30)/90.0); RouteWaypointData.latitude = tmp_l; tmp_l = longitude_d * ((1L<<30)/90.0); RouteWaypointData.longitude = tmp_l; grmn_time = iso2time(time); grmn_time -= EPOCH_DIFF; RouteWaypointData.time_date = grmn_time; memcpyset(RouteWaypointData.comment, comment, 40, ' '); do{ writerec(grmn_fd, (char *)&RouteWaypointData, sizeof(RouteWaypointData), MsgRteWpt); }while(!get_ack(grmn_fd, buffer)); }else if(strncmp(buffer,"WPT",3) == 0 && type == MsgWayPt){ retval = sscanf(&buffer[5], "%6c %lf %lf %19c %[^\n]", name, &latitude_d, &longitude_d, time, comment); memcpyset(WaypointData.name, name, 6, ' '); tmp_l = latitude_d * ((1L<<30)/90.0); WaypointData.latitude = tmp_l; tmp_l = longitude_d * ((1L<<30)/90.0); WaypointData.longitude = tmp_l; grmn_time = iso2time(time); grmn_time -= EPOCH_DIFF; WaypointData.time_date = grmn_time; memcpyset(WaypointData.comment, comment, 40, ' '); do{ writerec(grmn_fd, (char *)&WaypointData, sizeof(WaypointData), MsgWayPt); }while(!get_ack(grmn_fd, buffer)); }else if(strncmp(buffer,"ALC",3) == 0){ }else if(strncmp(buffer,"TRK",3) == 0 && type == MsgTrack){ retval = sscanf(&buffer[4], "%c%d %lf %c%d %lf %19c %1c", &flag1, &latdeg, &latitude_d, &flag2, &londeg, &longitude_d, &time, &flag3); latitude_d = latdeg + latitude_d/60.0; if (flag1 == 'S') latitude_d = -latitude_d; tmp_l = latitude_d * ((1L<<30)/90.0); TrackData.latitude = tmp_l; longitude_d = londeg + longitude_d/60.0; if (flag2 == 'W') longitude_d = -longitude_d; tmp_l = longitude_d * ((1L<<30)/90.0); TrackData.longitude = tmp_l; grmn_time = iso2time(time); grmn_time -= EPOCH_DIFF; TrackData.time_date = grmn_time; TrackData.flag = flag3; do{ writerec(grmn_fd, (char *)&TrackData, sizeof(TrackData), MsgTrack); }while(!get_ack(grmn_fd, buffer)); }else if(strncmp(buffer,"PRX",3) == 0 && type == MsgProx){ retval = sscanf(&buffer[5], "%6c %lf %lf %lf %19c %128c", name, &latitude_d, &longitude_d, &radius, time, comment); memcpyset(ProximityData.name, name, 6, ' '); tmp_l = latitude_d * ((1L<<30)/90.0); ProximityData.latitude = tmp_l; tmp_l = longitude_d * ((1L<<30)/90.0); ProximityData.longitude = tmp_l; grmn_time = iso2time(time); grmn_time -= EPOCH_DIFF; ProximityData.time_date = grmn_time; memcpyset(ProximityData.comment, comment, 40, ' '); ProximityData.alarm_radius = radius; do{ writerec(grmn_fd, (char *)&ProximityData, sizeof(ProximityData), MsgProx); }while(!get_ack(grmn_fd, buffer)); }else if(buffer[0] == '\t'){ }else{ /* ignore this file record */ } }/* outrec */ /* write data from named file to GARMIN, performing conversions as appropriate */ void writeblock(int grmn_fd, unsigned char *buffer, int bufsize, char *fname, int type){ FILE *data_fd; if(fname && strcmp(fname,"-")){ data_fd = fopen(fname, "r"); if (data_fd == NULL){ fprintf(stderr, "cannot open data file: %s\n", fname); exit(1); } }else{ data_fd = stdin; } while(fgets(buffer, BUFSIZE, data_fd) != NULL){ outrec(grmn_fd, buffer, type); } if(fname){ fclose(data_fd); } }/* writeblock */ int main(int argc, char *argv[]){ int arg; char port[1024]; int grmn_fd; struct termios termios; int retval, length; unsigned char buffer[BUFSIZE]; strcpy(port,DEFAULT_PORT); /* Specify what is desired, or induce a usage hint */ while ((arg=getopt(argc,argv, #ifdef GRMN45 "D:acf:hilprtu:wx!A:P:R:T:VW:X:Y:Z" #else "D:acf:hilprtu:w!A:P:R:T:VW:Y:Z" #endif ))>0){ switch (arg){ #ifdef GRMN45 case '!': /* get all */ get_all++; break; #endif case 'a': /* get almanac */ get_almanac++; break; #ifdef GRMN45 case 'c': /* get configuration */ get_cfg++; break; #endif case 'f': /* format */ sscanf(optarg, "%d", &format); break; case 'h': /* help */ default: usage(); exit(0); case 'i': /* unit id */ ident++; break; case 'l': /* listen w/o command */ listen++; break; case 'p': /* position */ position++; break; case 'r': /* get route */ get_route++; break; case 't': /* get track */ get_track++; break; case 'u': /* UTC */ sscanf(optarg, "%d", &utc); break; case 'w': /* get waypoint */ get_waypoint++; break; #ifdef GRMN45 case 'x': /* get proximity */ get_proximity++; break; #endif case 'A': /* set almanac */ set_almanac++; fn_almanac = optarg; break; case 'D': /* debug operation */ sscanf(optarg, "%x", &debug_flags); break; case 'P': /* port */ strncpy(port,optarg,1023); port[1023] = '\0'; break; case 'R': /* set routes */ set_route++; fn_route = optarg; break; case 'T': /* set track */ set_track++; fn_track = optarg; break; case 'V': /* display version */ printf("Garmin up/down load: %s\n", rcsid); printf(" built %s %s\n", __DATE__, __TIME__); /******************************************************************** printf("size of ProximityData is %d\n", sizeof(struct ProximityData)); printf("size of RouteData is %d\n", sizeof(struct RouteData)); printf("size of RouteWaypointData is %d\n", sizeof(struct RouteWaypointData)); printf("size of AlmanacData is %d\n", sizeof(struct AlmanacData)); printf("size of WaypointData is %d\n", sizeof(struct WaypointData)); ********************************************************************/ break; case 'W': /* set waypoints */ set_waypoint++; fn_waypoint = optarg; break; #ifdef GRMN45 case 'X': /* set proximity */ set_proximity++; fn_proximity = optarg; break; #endif case 'Y': /* async */ sscanf(optarg, "%x", &async); break; case 'Z': /* power */ power++; break; } } /****************************************************************************/ /** initialize the serial port **/ /****************************************************************************/ grmn_fd = open(port, O_RDWR|O_NOCTTY|O_NONBLOCK|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (grmn_fd == -1){ fprintf(stderr, "cannot open control port\n"); exit(1); } if (isatty(grmn_fd)){ if (tcgetattr(grmn_fd, &termios) == -1){ fprintf(stderr, "couldn't get port status\n"); exit(1); } termios.c_oflag = termios.c_oflag & ~(OPOST|OLCUC|OCRNL|ONLCR); termios.c_iflag = termios.c_iflag & ~(IGNPAR|INPCK|ISTRIP|INLCR|IGNCR|ICRNL| IXON|IXOFF|IUCLC|IXANY|IMAXBEL); termios.c_cflag = termios.c_cflag & ~CBAUD | B9600 | CLOCAL; termios.c_lflag = termios.c_lflag & ~(ISIG|ICANON|XCASE|ECHO); if (tcsetattr(grmn_fd, TCSANOW, &termios) == -1){ fprintf(stderr, "couldn't set port status\n"); exit(1); } } /****************************************************************************/ /** Implement the options, one after another, in mostly alphabetical order **/ /****************************************************************************/ if(get_almanac){ if (0x4 & debug_flags) fprintf(stderr, "ask for almanac\n"); send_cmd(grmn_fd, ReqAlmanac); readblock(grmn_fd, buffer, BUFSIZE); } #ifdef GRMN45 if(get_all){ if (0x4 & debug_flags) fprintf(stderr, "ask for all user info\n"); send_cmd(grmn_fd, ReqAll); readblock(grmn_fd, buffer, BUFSIZE); } #endif if(set_almanac){ notyet(); if (0x4 & debug_flags) fprintf(stderr, "send almanac from %s\n", fn_almanac); if(fn_almanac == 0){ fprintf(stderr, "No file given for almanac, using STDIN.\n"); fn_almanac = "-"; } writeblock(grmn_fd, buffer, BUFSIZE, fn_almanac, MsgAlmanac); } #ifdef GRMN45 if(get_cfg){ if (0x4 & debug_flags) fprintf(stderr, "ask for configuration info\n"); send_cmd(grmn_fd, ReqCfg); readblock(grmn_fd, buffer, BUFSIZE); } #endif if(ident){ if (0x4 & debug_flags) fprintf(stderr, "ask for unit ident\n"); send_msg0(grmn_fd, MsgIdReq); readblock(grmn_fd, buffer, BUFSIZE); } if(listen){ if (0x4 & debug_flags) fprintf(stderr, "listen for messages\n"); readblock(grmn_fd, buffer, BUFSIZE); } if(position){ if (0x4 & debug_flags) fprintf(stderr, "ask for position\n"); send_cmd(grmn_fd, ReqPosn); readblock(grmn_fd, buffer, BUFSIZE); } #ifdef GRMN45 if(get_proximity){ if (0x4 & debug_flags) fprintf(stderr, "ask for proximity\n"); send_cmd(grmn_fd, ReqProx); readblock(grmn_fd, buffer, BUFSIZE); } if(set_proximity){ if (0x4 & debug_flags) fprintf(stderr, "send proximity from %s\n", fn_proximity); if(fn_proximity == 0){ fprintf(stderr, "No file given for proximity, using STDIN.\n"); fn_proximity = "-"; } writeblock(grmn_fd, buffer, BUFSIZE, fn_proximity, MsgProx); } #endif if(get_route){ if (0x4 & debug_flags) fprintf(stderr, "ask for routes\n"); send_cmd(grmn_fd, ReqRoute); readblock(grmn_fd, buffer, BUFSIZE); } if(set_route){ if (0x4 & debug_flags) fprintf(stderr, "send routes from %s\n", fn_route); if(fn_route == 0){ fprintf(stderr, "No file given for routes, using STDIN\n"); fn_route = "-"; } writeblock(grmn_fd, buffer, BUFSIZE, fn_route, MsgRoute); } if(get_track){ if (0x4 & debug_flags) fprintf(stderr, "ask for track\n"); send_cmd(grmn_fd, ReqTrack); readblock(grmn_fd, buffer, BUFSIZE); } if(set_track){ if (0x4 & debug_flags) fprintf(stderr, "send track from %s\n", fn_route); if(fn_track == 0){ fprintf(stderr, "No file given for track, using STDIN\n"); fn_track = "-"; } writeblock(grmn_fd, buffer, BUFSIZE, fn_track, MsgTrack); } while(utc--){ if (0x4 & debug_flags) fprintf(stderr, "ask for UTC\n"); send_cmd(grmn_fd, ReqUTC); readblock(grmn_fd, buffer, BUFSIZE); } if(get_waypoint){ if (0x4 & debug_flags) fprintf(stderr, "ask for waypoint\n"); send_cmd(grmn_fd, ReqWayPt); readblock(grmn_fd, buffer, BUFSIZE); } if(set_waypoint){ if (0x4 & debug_flags) fprintf(stderr, "send waypoints from %s\n", fn_waypoint); if(fn_waypoint == 0){ fprintf(stderr, "No file given for waypoints, using STDIN.\n"); fn_waypoint = "-"; } writeblock(grmn_fd, buffer, BUFSIZE, fn_waypoint, MsgWayPt); } if(async != -1){ if (0x4 & debug_flags) fprintf(stderr, "enable async\n"); send_cmd2(grmn_fd, async); readblock(grmn_fd, buffer, BUFSIZE); } if(power){ if (0x4 & debug_flags) fprintf(stderr, "turn off unit\n"); send_cmd(grmn_fd, ReqPowerOff); } if (0x4 & debug_flags) printf("all done\n"); }/* main */ gd2/gd2.1100644 645 645 6764 6423242522 11675 0ustar bentsonbentson.TH gd2 1 "5 September 1997" .IX gd2 .\" $Header$ .TH PSPLIT 1 "" "" LOCAL .SH NAME gd2 \- Garmin Download version 2 (for POSIX systems) .SH SYNOPSIS .B gd2 .RB [ -options ] .SH DESCRIPTION This program was inspired by M.J.Montgomery's GarDown program and is based on protocol description by william.soley@sun.com, werme@zk3.dec.com http://playground.sun.com/pub/soley/garmin.txt. It is designed to extract most conventional information, such as tracks, routes, waypoints, position, clock, and almanac. Since Soley's report does not describe all messages, this program does not interpret those additional messages. These messages are suspected to include more status on signals and such. This program can also upload routes and waypoints. .SH OPTIONS .TP .B -! get all information (you may have to escape the exclamation character from the shell) .TP .B -a get almanac .TP .B -c get configuration (not currently interpreted) .TP .B -f "" formatting options .TP .B -h help -- show command summary .TP .B -i query unit ident .TP .B -l just "listen" for reports .TP .B -p query position .TP .B -r get routes .TP .B -t get tracks .TP .B -u "" request UTC time -- as fast as possible for .B count times. .TP .B -w get waypoints .TP .B -x get proximity waypoints .TP .B -A "" set almanac (Not currently supported.) .TP .B -D "" debug operation .TP .B -P "" specify port (default is /dev/gps0) .TP .B -R "" set routes .TP .B -T "" set track .TP .B -V display gd2 software version .TP .B -W "" set waypoints .TP .B -X "" set proximity waypoints .TP .B -Y "" enable async .TP .B -Z power off .SH NOTES When file names are missing, or when they are given as "-", STDIN is used as source. The .B -h option will show the mask values if masked options are first set to non-zero values. .SH EXAMPLES .nf gd2 -t >trk.todaysdate gd2 -Wwaypointfile -P/dev/gps0 gd2 -i -p -w -r -t > full.dump.file gd2 -i -p -! > full.dump.file gd2 -Y1 -D1 -f1 -h .fi .SH BUGS The Garmin 12xl and 38 don't properly convert lower case characters found in uploads. The Garmin 12xl and 38 store and display only the first 16 characters of the comment field. They ignore extra characters in upload. The Garmin 12xl and 38 ignore the date/time creation field in upload and return 0 in download. When a waypoint is entered by hand, the creation date/time are placed in the comment field. .SH FILES The best way to use the 'set' features is to download routes, waypoints, tracks, and proximity waypoints to determine the file format, then upload a file with additional entries in that format. .SH CONFIGURATION FILES All data can be put in a single file, but if that data are passed via STDIN, data from only one command are extracted from the data stream. .nf WPT FACTRY 24.974150 121.549652 1989/12/31-00:00:00 TAIWAN FACTORY WPT GARMIN 38.950050 -94.746117 1989/12/31-00:00:00 OLATHE KS WPT RETAIL 47.674606 -122.405876 1989/12/31-00:00:00 WEST MARINE RTE 1 TRACBACK T003 47.67460632 -122.40587616 1989/12/31-00:00:00 29-SEP-97 00:56 T002 38.85544968 -94.80039978 1989/12/31-00:00:00 29-SEP-97 00:56 T001 24.97414970 121.54987335 1989/12/31-00:00:00 29-SEP-97 00:56 PRX GARMIN 38.950050 -94.746117 16093.471680 1989/12/31-00:00:00 OLATHE KS .fi .SH ENVIRONMENT .SH INSTALLATION You may wish to use the SED.fix.time script to convert files written by earlier versions of gd2. .SH AUTHOR Copyright (c) 1996,1997 by Randolph Bentson Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.