static char *rcsid ="$Revision: 2.9.1.3 $$Date: 2000/05/03 00:31:18 $"; /* 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 * Marc Blanchet * G. Frank Paynter * Bert Driehuis * * 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.holmsjoen.com * *$Log: gd2.c,v $ *Revision 2.9.1.3 2000/05/03 00:31:18 bentson *added BSD patch * *Revision 2.9.1.2 2000/03/07 02:26:42 bentson *add support for non-native mode representation in routes and waypoints * *Revision 2.9.1.1 2000/03/07 01:45:37 bentson *fix problem with loop counter exit value * *Revision 2.9 1998/08/14 00:49:03 bentson *fix holes in time display and show enough digits *in location that waypoints won't drift when uploaded *and downloaded * *Revision 2.8 1997/10/26 04:08:46 bentson *add flexible output format for lat/long * *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 double rint(double); /* 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 -- symlink it to the port of your choice*/ #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 Msg3d 0x3d #define MsgSatSel 0x2a #define MsgProto 0xfd #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 -> lat/long as Deg instead of Deg Min\n"); printf(" 0x2 -> lat/long in base format\n"); printf(" (integer biased degrees or floating radians\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"); printf ("-c get configuration\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 */ /* given longs representing (2**30/90) times latitude and longitude * return string as floating point degrees ddd.ddddddddddddd, * base units ddddddddddd, or * NSEW degrees and floating point minutes C ddd mm.mmmmmm */ char * lat_long(long latitude, long longitude){ static char dest[1024]; double latitude_d, longitude_d; if (format & 0x1){ /* double deg */ latitude_d = latitude/((1L<<30)/90.0); longitude_d = longitude/((1L<<30)/90.0); sprintf(dest, "%.13lf %.13lf", latitude_d, longitude_d); }else if (format & 0x2){ /* long deg */ sprintf(dest, "%.11ld %.11ld", latitude, longitude); }else{ /* deg/min */ latitude_d = latitude/((1L<<30)/90.0); longitude_d = longitude/((1L<<30)/90.0); sprintf(dest, "%c%d %.9lf %c%d %.9lf", 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))); } return((char *)dest); }/* lat_long */ /* given doubles representing latitude and longitude in radians, * return string as floating point degrees ddd.ddddddddddddd, * base units ddddddddddd, or * NSEW degrees and floating point minutes C ddd mm.mmmmmm */ char * lat_long_D(double latitude_d, double longitude_d){ static char dest[1024]; long tmp_l, tmp_l2; if (format & 0x1){ /* double deg */ sprintf(dest, "%.13lf %.13lf", (180/MyPI) * latitude_d, (180/MyPI) * longitude_d); }else if (format & 0x2){ /* long deg */ tmp_l = rint(683565275.576431632 * latitude_d); tmp_l2 = rint(683565275.576431632 * longitude_d); sprintf(dest, "%.11ld %.11ld", tmp_l, tmp_l2); }else{ /* deg/min */ latitude_d *= (180/MyPI); longitude_d *= (180/MyPI); sprintf(dest, "%c%d %lf %c%d %lf", 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))); } return((char *)dest); }/* lat_long_D */ void memcpyset(void *dest, const void *src, size_t n, char fill){ while(n){ n--; /* Mike Porter pointed out that n could leave this loop with negative value if it entered with zero value. Disaster followed in loop below. This new code avoids the problem. */ 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; 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 { printf("POS %s\n", lat_long_D(*(double *)(&buffer[2]), *(double *)(&buffer[10]))); } 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{ 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 %s %s %s\n", tmp_s, lat_long(*(long *)(&buffer[8]), *(long *)(&buffer[12])), 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{ grmn_time = *(long *)(&buffer[10]); grmn_time += EPOCH_DIFF; printf("TRK %s %s %c\n", lat_long(*(long *)(&buffer[2]), *(long *)(&buffer[6])), 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{ 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 %s %s %s\n", buffer[20]?"":" ", tmp_s, lat_long( *(long *)(&buffer[8]), *(long *)(&buffer[12])), 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{ 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 %s %f %s %s\n", buffer[20]?"":" ", tmp_s, lat_long(*(long *)(&buffer[8]), *(long *)(&buffer[12])), 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/%2.2d/%2.2d %2.2d:%2.2d:%2.2d %f\n", *(short *)(&buffer[4]), buffer[2], buffer[3], 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; double latitude_m, longitude_m; char latitude_s, longitude_s; 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 && (buffer[8] == 'N' || buffer[8] == 'S')){ retval = sscanf(&buffer[1], "%6c %1c%lf %lf %1c%lf %lf %19c %[^\n]", name, &latitude_s, &latitude_d, &latitude_m, &longitude_s, &longitude_d, &longitude_m, time, comment); memcpyset(RouteWaypointData.name, name, 6, ' '); tmp_l = (latitude_d + latitude_m/60) * ((1L<<30)/90.0); if (latitude_s == 'S'){ tmp_l = -tmp_l; } RouteWaypointData.latitude = tmp_l; tmp_l = (longitude_d + longitude_m/60) * ((1L<<30)/90.0); if (longitude_s == 'W'){ tmp_l = -tmp_l; } 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(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 && (buffer[12] == 'N' || buffer[12] == 'S')){ retval = sscanf(&buffer[5], "%6c %c%lf %lf %c%lf %lf %19c %[^\n]", name, &latitude_s, &latitude_d, &latitude_m, &longitude_s, &longitude_d, &longitude_m, time, comment); memcpyset(WaypointData.name, name, 6, ' '); tmp_l = (latitude_d + latitude_m/60) * ((1L<<30)/90.0); if (latitude_s == 'S'){ tmp_l = -tmp_l; } WaypointData.latitude = tmp_l; tmp_l = (longitude_d + longitude_m/60) * ((1L<<30)/90.0); if (longitude_s == 'W'){ tmp_l = -tmp_l; } 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,"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); } #ifdef __bsdi__ /* This may well be right for FreeBSD and NetBSD as well */ cfmakeraw(&termios); termios.c_ispeed = termios.c_ospeed = 9600; #else 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); #endif 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 */