gpstrans-0.41/ 0000755 0001750 0001750 00000000000 11037770611 010303 5 0000000 0000000 gpstrans-0.41/doc/ 0000755 0001750 0001750 00000000000 11037770611 011050 5 0000000 0000000 gpstrans-0.41/doc/gpstrans-old.html 0000644 0001750 0001750 00000004673 10225356640 014305 0000000 0000000
GPStrans - Transfer between Garmin GPS and UNIX Workstation
GPStrans -
Transfer data between Garmin GPS and UNIX Workstations
What is GPStrans?
GPStrans is a program which allows to up- and download waypoints, route,
almanac and trackroutes from you Garmin GPS. There is a ASCII-Version
wish will allow to use the basic up-/download features of the program without
having access to a graphic screen. The X11-Verion will soon allow to view
the track-log and waypoints, also allow the edit data.
Software-Requirements
To successfully compile GPStrans you'll need 'gcc' or another ansi-C compatible
Compiler. For the X11-Version you also need the xview-package distributed by
Sun Microsystems as source-code. Be sure to use Version 3.2 or later because I
take use of the new feature like filechooser.
Installation of GPStrans
GPStrans was developed using a Sun Workstation with SunOS 4.1.3. If you're
using a SUN-Workstation you should only need to check the paths in the
Makefile to point to the new xview-libraries.
I've successfully compiled GPStrans on a HP Workstation, but couldn't try
the serial communication, because I don't have direct access to the
workstation.
GPStrans Licensing Information
GPStrans is FreeWare. I'm releasing this source code to the public domain.
You can redistribute it as often as you want as long as you let the original
copyright notice in. If you like to do changes to GPStrans, please contact
me before so that we can coordinate the work.
GPStrans is Copyright 1995 by Carsten tschach (tschach@zedat.fu-berlin.de).
The datum translation-routines are based on the program MacGPS from John F.
Waers (jfwaers@csn.net). You can copy it as long as you let the original
copyright notice in.
How to get GPStrans
GPStrans is available via anonymous ftp from
ftp.fu-berlin.de.
The current version is 0.2beta - it's still a beta-test-version, so feel
free to test it, but don't expect that it is error-free. If you discovered
any errors, please email them to me at
tschach@zedat.fu-berlin.de.
- Source code:
- gpstrans-0.3b.tar.gz
gpstrans-0.41/doc/gpstrans.1 0000644 0001750 0001750 00000014143 10427451722 012717 0000000 0000000 .TH "GPSTRANS" "1" "2006 May 7" "-" "GPS Utility"
.SH "NAME"
gpstrans \- communicate with Garmin GPS receiver
.SH "SYNOPOSIS"
.BR gpstrans " [ "
.IR options " ] [ " "file " ]
.SH "DESCRIPTION"
.PP
\fBgpstrans\fP allows the user with a Garmin GPS receiver to upload
and download waypoints, routes, almanacs (satellite orbital elements)
and trackroutes. If \fIfile\fP is not supplied, data will be read
from stdin (\fB\-u\fP\fIx\fP switch) or written to stdout
(\fB\-d\fP\fIx\fP switch).
.SH "OPTIONS"
.TP
.BI \-p "port"
set serial I/O device
.TP
.B \-s
set datum, format, offset, and device interactively, and save them in
\fI$HOME/.gpstrans\fP.
.TP
.B \-i
identify connected GPS
.TP
.B \-o
turn off GPS device
.TP
.B \-t
get time from GPS
.TP
.B \-ts
get time from GPS and set system time on host
.TP
.BI \-d x
download data indicated by \fIx\fP: \fBr\fP=route, \fBt\fP=track,
\fBw\fP=waypoint, \fBa\fP=almanac
.TP
.B \-m
With \fB\-dt\fP, downloads track data in the format which can be
displayed by Mayko mXmap(1). With \fB\-dr\fP or \fB\-ur\fP, downloads or
uploads route data in a format compatible with Mayko mXmap.
.TP
.BI \-u x
upload data indicated by \fIx\fP: \fBr\fP=route, \fBt\fP=track,
\fBw\fP=waypoint, \fBa\fP=almanac
.TP
.B \-v
print program version.
.TP
.BI \-\-verbose
Increase verbosity.
.TP
.BI \-\-debug
Add debug printouts.
.TP
.BI \-\-help
Print help text.
.SH "CONNECTION"
For a DB\-25 connector, you may need to connect pin 4, 5 and 6, 8, 20
together. This sets handshake signals so that your workstation can use
the serial port to communicate with the GPS.
.nf
.sp
1 ### #####
o o o # # # o # o o o o o
o o o o o o # o o o o o
.fi
Connect the Garmin cable as follows:
.nf
.sp
2 3 7
o o o o o o o o o o o o o
o o o o o o o o o o o o
Pin 2 goes to DATA IN (White)
Pin 3 goes to DATA OUT (Brown)
Pin 7 goes to GROUND (Black)
.fi
If it doesn't work in this way, try exchanging pins 2 and 3 at the connector.
The circular connector on a Garmin GPS II receiver can be wired to a DB\-9
connector as follows:
.nf
.sp
_____ _____,\-\-\-\-\-,
3 / \\ 4 | | |
| o o | | | |_____
| < <\- groove \-> |=====| |\-\-\-\-,|
| o o | | | | ||
2 \\ _____ / 1 |_____| | ||
`\-\-\-\-\-' ||
||
views are looking ||
into connector ||
at each end of cable ||
||
||
5 3 2 ________ ||
o o o o o | \\___________||
o o o o |_________,\-\-\-\-\-\-\-\-\-\-\-\-'
DB\-9 pin 2 goes to circular connector pin 2
DB\-9 pin 3 goes to circular connector pin 4
DB\-9 pin 5 goes to circular connector pin 3
other pins are not connected
(Note: the pin numbers for the circular connector are
arbitrary, and may not match the `official' numbers.)
.fi
If your plug is more recent than the one above (ex: etrex) then you need DB\-9 or DB\-25 to be connected to your Garmin GPS like this:
.BR
_____,\-\-\-\-\-,
POWER(+) | | |
groove \-\-> |=====| |_____
DATA IN | | |\-\-\-\-,|
DATA OUT | | | ||
GROUND(\-) |_____| | ||
`\-\-\-\-\-' ||
||
||
||
||
||
||
________ ||
| \\___________||
|_________,\-\-\-\-\-\-\-\-\-\-\-\-'
DB\-25 :
2 3 7
o o o o o o o o o o o o o
o o o o o o o o o o o o
Pin 2 goes to DATA IN (White)
Pin 3 goes to DATA OUT (Brown)
Pin 7 goes to GROUND (Black)
DB\-9:
5 3 2
o o o o o
o o o o
pin 2 goes to DATA IN (White)
pin 3 goes to DATA OUT (Brown)
pin 5 goes to GROUND (Black)
other pins are not connected
For testing, you might try setting the GPS to NMEA\-Output and using a
terminal emulator program like Kermit. The GPS will send a data record
every 2 seconds. As long as you don't see any data on your computer,
\fBgpstrans\fP won't work.
After finishing the test, be sure to set your GPS receiver to
GRMN/GRMN.
.SH "ENVIRONMENT"
.TP
.B GPSDEV
Serial I/O device (overrides contents of \fI$HOME/.gpstrans\fP, and is
overridden by \fB\-p\fP switch).
.SH "FILES"
.TP
.I $HOME/.gpstrans
Has user preferences for datum, format, offset, and serial I/O device
(see \fB\-s\fP switch, above).
.SH "AUTHOR"
GPStrans is Copyright 1995 by Carsten Tschach
. The datum translation routines are
based on the program MacGPS from John F. Waers .
Mayko mXmap output format by Matthias Kattanek .
German Grid by Andreas Lange .
etrex support by Joao Seabra CT2GNL \- .
Other Garmin formats added by Jim Van Zandt .
.SH "SEE ALSO"
.BR mxmap (1),
.BR GPSMan
gpstrans-0.41/src/ 0000755 0001750 0001750 00000000000 11037770611 011072 5 0000000 0000000 gpstrans-0.41/src/gps/ 0000755 0001750 0001750 00000000000 11037770611 011663 5 0000000 0000000 gpstrans-0.41/src/gps/Makefile 0000644 0001750 0001750 00000001416 10231323522 013233 0000000 0000000 ##############################################################################
#
# Makefile for GPStrans - subdirectory ./gps/
#
##############################################################################
#
# You don't need to change anything here. Do every change in ./Makefile
#
##############################################################################
CC = gcc
INCLUDES=-I../include
CFLAGS = -g -D__LINUX__ -DDEBUG
OFILES = sendgpsinfo.o dms.o datum.o calendar.o gpsmessage.o garmincomm.o \
garminserial.o getgpsinfo.o latlong.o
HFILES = ../include/defs.h ../include/Prefs.h ../include/Garmin.h ../include/protocols.h
.c.o: $(HFILES)
$(CC) -c $(CFLAGS) $(INCLUDES) $<
all: $(OFILES) $(HFILES)
clean:
@rm -f core gpstrans *.o *.bak *~ #*#
gpstrans-0.41/src/gps/calendar.c 0000644 0001750 0001750 00000012370 10225356640 013523 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/calendar.c - Procedures to convert time and datum */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
#include "Prefs.h"
/* define constants */
#define START 2447892L /* Julian date for 00:00 12/31/89 */
/* prototype functions */
static long date2days (short mm, short dd, short yy);
static void days2date (long julian, short *mm, short *dd, short *yy);
/****************************************************************************/
/* dt is the date and time in the format "mm/dd/yyyy hh:mm:ss" and secs */
/* is the number of seconds since 12/31/1989 00:00:00, as defined by the */
/* #define START */
/****************************************************************************/
/****************************************************************************/
/* Convert seconds since 01/01/90 00:00:00 in date. */
/****************************************************************************/
char *
secs2dt (long secs, short offset)
{
static char dt[30];
short mm, dd, yy, h, m, s;
long days, rest;
days = (long) ((secs + (long) (offset * 3600.0)) / (24L * 3600L));
rest = (secs + (long) (offset * 3600.0)) - (long) (days * 24L * 3600L);
days2date (days, &mm, &dd, &yy);
h = rest / 3600L;
m = (rest - (long) h * 3600L) / 60L;
s = (rest - (long) h * 3600L) - ((long) m * 60L);
sprintf (dt, "%02d/%02d/%04d %02d:%02d:%02d", mm, dd, yy, h, m, s);
return dt;
}
/****************************************************************************/
/* Convert dat in seconds since 01/01/90 00:00:00 */
/****************************************************************************/
long
dt2secs (char *dt, int offset)
{
int mm, dd, yy, h, m, s;
sscanf (dt, "%d/%d/%d %d:%d:%d", &mm, &dd, &yy, &h, &m, &s);
return 24L * 3600L * date2days (mm, dd, yy)
+ 3600L * h + 60L * m + s - (long) (offset * 3600.0);
}
/****************************************************************************/
/* Convert date in days since 01/01/90 00:00:00 */
/****************************************************************************/
static long
date2days (short mm, short dd, short yy)
{
long jul;
short ja, jy, jm;
if (yy < 0)
++yy;
if (mm > 2)
{
jy = yy;
jm = mm + 1;
}
else
{
jy = yy - 1;
jm = mm + 13;
}
ja = 0.01 * jy;
jul = (long) ((long) (365.25 * jy) + (long) (30.6001 * jm) +
dd + 1720997 - ja + (long) (0.25 * ja));
return jul - START;
}
/****************************************************************************/
/* Convert days since 01/01/90 00:00:00 in date. */
/****************************************************************************/
static void
days2date (long days, short *mm, short *dd, short *yy)
{
long ja, jalpha, jb, jc, jd, je;
jalpha = (long) (((float) (days + START - 1867216) - 0.25) / 36524.25);
ja = days + START + 1 + jalpha - (long) (0.25 * jalpha);
jb = ja + 1524L;
jc = 6680.0 + (long) (((double) (jb - 2439870) - 122.1) / 365.25);
jd = (long) (365.25 * jc);
je = (long) ((jb - jd) / 30.6001);
*dd = jb - jd - (short) (30.6001 * je);
*mm = je - 1;
if (*mm > 12)
*mm -= 12;
*yy = jc - 4715;
if (*mm > 2)
--(*yy);
if (*yy <= 0)
--(*yy);
}
gpstrans-0.41/src/gps/datum.c 0000644 0001750 0001750 00000021435 10225356640 013066 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/datum.c - Definition of Datum and Ellipsoid */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
/****************************************************************************/
/* */
/* ellipsoid: index into the gEllipsoid[] array, in which */
/* */
/* a: ellipsoid semimajor axis */
/* invf: inverse of the ellipsoid flattening f */
/* dx, dy, dz: ellipsoid center with respect to WGS84 ellipsoid center */
/* */
/* x axis is the prime meridian */
/* y axis is 90 degrees east longitude */
/* z axis is the axis of rotation of the ellipsoid */
/* */
/* The following values for dx, dy and dz were extracted from the output of */
/* the GARMIN PCX5 program. The output also includes values for da and df, */
/* the difference between the reference ellipsoid and the WGS84 ellipsoid */
/* semi-major axis and flattening, respectively. These are replaced by the */
/* data contained in the structure array gEllipsoid[], which was obtained */
/* from the Defence Mapping Agency document number TR8350.2, "Department of */
/* Defense World Geodetic System 1984." */
/* */
/****************************************************************************/
/* Number of gDatum entries */
short nDatums = 102;
struct DATUM const gDatum[] = {
{"Adindan", 5, -162, -12, 206},
{"Afgooye", 15, -43, -163, 45},
{"Ain el Abd 1970", 14, -150, -251, -2},
{"Anna 1 Astro 1965", 2, -491, -22, 435},
{"Arc 1950", 5, -143, -90, -294},
{"Arc 1960", 5, -160, -8, -300},
{"Ascension Island `58", 14, -207, 107, 52},
{"Astro B4 Sorol Atoll", 14, 114, -116, -333},
{"Astro Beacon \"E\"", 14, 145, 75, -272},
{"Astro DOS 71/4", 14, -320, 550, -494},
{"Astronomic Stn `52", 14, 124, -234, -25},
{"Australian Geod `66", 2, -133, -48, 148},
{"Australian Geod `84", 2, -134, -48, 149},
{"Bellevue (IGN)", 14, -127, -769, 472},
{"Bermuda 1957", 4, -73, 213, 296},
{"Bogota Observatory", 14, 307, 304, -318},
{"Campo Inchauspe", 14, -148, 136, 90},
{"Canton Astro 1966", 14, 298, -304, -375},
{"Cape", 5, -136, -108, -292},
{"Cape Canaveral", 4, -2, 150, 181},
{"Carthage", 5, -263, 6, 431},
{"CH-1903", 3, 674, 15, 405},
{"Chatham 1971", 14, 175, -38, 113},
{"Chua Astro", 14, -134, 229, -29},
{"Corrego Alegre", 14, -206, 172, -6},
{"Djakarta (Batavia)", 3, -377, 681, -50},
{"DOS 1968", 14, 230, -199, -752},
{"Easter Island 1967", 14, 211, 147, 111},
{"European 1950", 14, -87, -98, -121},
{"European 1979", 14, -86, -98, -119},
{"Finland Hayford", 14, -78, -231, -97},
{"Gandajika Base", 14, -133, -321, 50},
{"Geodetic Datum `49", 14, 84, -22, 209},
{"Guam 1963", 4, -100, -248, 259},
{"GUX 1 Astro", 14, 252, -209, -751},
{"Hjorsey 1955", 14, -73, 46, -86},
{"Hong Kong 1963", 14, -156, -271, -189},
{"Indian Bangladesh", 6, 289, 734, 257},
{"Indian Thailand", 6, 214, 836, 303},
{"Ireland 1965", 1, 506, -122, 611},
{"ISTS 073 Astro `69", 14, 208, -435, -229},
{"Johnston Island", 14, 191, -77, -204},
{"Kandawala", 6, -97, 787, 86},
{"Kerguelen Island", 14, 145, -187, 103},
{"Kertau 1948", 7, -11, 851, 5},
{"L.C. 5 Astro", 4, 42, 124, 147},
{"Liberia 1964", 5, -90, 40, 88},
{"Luzon Mindanao", 4, -133, -79, -72},
{"Luzon Philippines", 4, -133, -77, -51},
{"Mahe 1971", 5, 41, -220, -134},
{"Marco Astro", 14, -289, -124, 60},
{"Massawa", 3, 639, 405, 60},
{"Merchich", 5, 31, 146, 47},
{"Midway Astro 1961", 14, 912, -58, 1227},
{"Minna", 5, -92, -93, 122},
{"NAD27 Alaska", 4, -5, 135, 172},
{"NAD27 Bahamas", 4, -4, 154, 178},
{"NAD27 Canada", 4, -10, 158, 187},
{"NAD27 Canal Zone", 4, 0, 125, 201},
{"NAD27 Caribbean", 4, -7, 152, 178},
{"NAD27 Central", 4, 0, 125, 194},
{"NAD27 CONUS", 4, -8, 160, 176},
{"NAD27 Cuba", 4, -9, 152, 178},
{"NAD27 Greenland", 4, 11, 114, 195},
{"NAD27 Mexico", 4, -12, 130, 190},
{"NAD27 San Salvador", 4, 1, 140, 165},
{"NAD83", 11, 0, 0, 0},
{"Nahrwn Masirah Ilnd", 5, -247, -148, 369},
{"Nahrwn Saudi Arbia", 5, -231, -196, 482},
{"Nahrwn United Arab", 5, -249, -156, 381},
{"Naparima BWI", 14, -2, 374, 172},
{"Observatorio 1966", 14, -425, -169, 81},
{"Old Egyptian", 12, -130, 110, -13},
{"Old Hawaiian", 4, 61, -285, -181},
{"Oman", 5, -346, -1, 224},
{"Ord Srvy Grt Britn", 0, 375, -111, 431},
{"Pico De Las Nieves", 14, -307, -92, 127},
{"Pitcairn Astro 1967", 14, 185, 165, 42},
{"Prov So Amrican `56", 14, -288, 175, -376},
{"Prov So Chilean `63", 14, 16, 196, 93},
{"Puerto Rico", 4, 11, 72, -101},
{"Qatar National", 14, -128, -283, 22},
{"Qornoq", 14, 164, 138, -189},
{"Reunion", 14, 94, -948, -1262},
{"Rome 1940", 14, -225, -65, 9},
{"RT 90", 3, 498, -36, 568},
{"Santo (DOS)", 14, 170, 42, 84},
{"Sao Braz", 14, -203, 141, 53},
{"Sapper Hill 1943", 14, -355, 16, 74},
{"Schwarzeck", 21, 616, 97, -251},
{"South American `69", 16, -57, 1, -41},
{"South Asia", 8, 7, -10, -26},
{"Southeast Base", 14, -499, -249, 314},
{"Southwest Base", 14, -104, 167, -38},
{"Timbalai 1948", 6, -689, 691, -46},
{"Tokyo", 3, -128, 481, 664},
{"Tristan Astro 1968", 14, -632, 438, -609},
{"Viti Levu 1916", 5, 51, 391, -36},
{"Wake-Eniwetok `60", 13, 101, 52, -39},
{"WGS 72", 19, 0, 0, 5},
{"WGS 84", 20, 0, 0, 0},
{"Zanderij", 14, -265, 120, -358},
{"Potsdam", 3, 606, 23, 413}
};
struct ELLIPSOID const gEllipsoid[] = {
{"Airy 1830", 6377563.396, 299.3249646},
{"Modified Airy", 6377340.189, 299.3249646},
{"Australian National", 6378160.0, 298.25},
{"Bessel 1841", 6377397.155, 299.1528128},
{"Clarke 1866", 6378206.4, 294.9786982},
{"Clarke 1880", 6378249.145, 293.465},
{"Everest (India 1830)", 6377276.345, 300.8017},
{"Everest (1948)", 6377304.063, 300.8017},
{"Modified Fischer 1960", 6378155.0, 298.3},
{"Everest (Pakistan)", 6377309.613, 300.8017},
{"Indonesian 1974", 6378160.0, 298.247},
{"GRS 80", 6378137.0, 298.257222101},
{"Helmert 1906", 6378200.0, 298.3},
{"Hough 1960", 6378270.0, 297.0},
{"International 1924", 6378388.0, 297.0},
{"Krassovsky 1940", 6378245.0, 298.3},
{"South American 1969", 6378160.0, 298.25},
{"Everest (Malaysia 1969)", 6377295.664, 300.8017},
{"Everest (Sabah Sarawak)", 6377298.556, 300.8017},
{"WGS 72", 6378135.0, 298.26},
{"WGS 84", 6378137.0, 298.257223563},
{"Bessel 1841 (Namibia)", 6377483.865, 299.1528128},
{"Everest (India 1956)", 6377301.243, 300.8017}
};
gpstrans-0.41/src/gps/dms.c 0000644 0001750 0001750 00000010156 10225356640 012535 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/dms.c - Convert to various position formats */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
/****************************************************************************/
/* Convert degrees to dd mm'ss.s" (DMS-Format) */
/****************************************************************************/
char *
toDMS (double a)
{
short neg = 0;
double d, m, s;
static char dms[20];
if (a < 0.0)
{
a = -a;
neg = 1;
}
d = (double) ((int) a);
a = (a - d) * 60.0;
m = (double) ((int) a);
s = (a - m) * 60.0;
if (s > 59.5)
{
s = 0.0;
m += 1.0;
}
if (m > 59.5)
{
m = 0.0;
d += 1.0;
}
if (neg)
d = -d;
sprintf (dms, "%.0f°%02.0f'%04.1f\"", d, m, s);
return dms;
}
/****************************************************************************/
/* Convert dd mm'ss.s" (DMS-Format) to degrees. */
/****************************************************************************/
double
DMStoDegrees (char *dms)
{
int d, m;
double s;
sscanf (dms, "%d%d%lf", &d, &m, &s);
s = (double) (abs (d)) + ((double) m + s / 60.0) / 60.0;
if (d >= 0)
return s;
else
return -s;
}
/****************************************************************************/
/* Convert degrees to dd mm.mmm' (DMM-Format) */
/****************************************************************************/
char *
toDM (double a)
{
short neg = 0;
double d, m;
static char dm[13];
if (a < 0.0)
{
a = -a;
neg = 1;
}
d = (double) ((int) a);
m = (a - d) * 60.0;
if (m > 59.5)
{
m = 0.0;
d += 1.0;
}
if (neg)
d = -d;
sprintf (dm, "%.0f°%06.3f'", d, m);
return dm;
}
/****************************************************************************/
/* Convert dd mm.mmm' (DMM-Format) to degree. */
/****************************************************************************/
double
DMtoDegrees (char *dms)
{
int d;
double m;
sscanf (dms, "%d%lf", &d, &m);
m = (double) (abs (d)) + m / 60.0;
if (d >= 0)
return m;
else
return -m;
}
gpstrans-0.41/src/gps/garmincomm.c 0000644 0001750 0001750 00000020257 10236024453 014102 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/garmincomm.c - Basic communication procedures between gps and */
/* unix host. */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* Copyright (c) 2001 by Joao Seabra - CT2GNL (seabra@ci.aac.uc.pt) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
#include "Prefs.h"
#include "util.h"
#include
/* declare external variables */
extern int ttyfp;
/* define global variables */
BYTE gGarminMessage[MAX_LENGTH];
int naks;
/* define static variables */
static unsigned char checksum;
/****************************************************************************/
/* Prepare package and send to GPS. */
/* */
/* A Garmin packet has six bytes of overhead. The caller includes two */
/* bytes of the packet header (ID and data byte count) in the message. */
/* This routine prepends the DLE and appends the trailer (checksum, DLE, */
/* and ETX). */
/****************************************************************************/
void
sendGPSMessage (BYTE * message, short bytes)
{
short i;
long n;
BYTE gGarminMessage[MAX_LENGTH];
BYTE *p = gGarminMessage;
checksum=0;
*p++ = 0x10; /* Define start of message */
for (i = 0; i < bytes; i++)
{
*p++ = message[i];
checksum -= message[i];
if (message[i] == 0x10)
*p++ = 0x10;
}
*p++ = checksum;
if (checksum == 0x10)
*p++ = 0x10;
*p++ = 0x10;
*p++ = 0x03;
n = (long) (p - gGarminMessage);
if (debugging>1)
{
printf (" Sending : ");
for (i = 0; i < n; i++)
printf ("%02X ", *(gGarminMessage + i));
printf ("\n");
if ((bytes != (message[1]+2)) || (bytes > 254))
Error("sendGPSMessage: invalid byte count\n");
}
write (ttyfp, gGarminMessage, n);
}
/****************************************************************************/
/* Sent a "are-you-ready" message to GPS - return TRUE if GPS responds or */
/* FALSE if GPS did not respond (GPS off? / incorrect format?) */
/****************************************************************************/
int
CheckGPS ()
{
extern struct PREFS gPrefs;
extern char gMessageStr[];
BYTE *p = gGarminMessage;
BYTE last = 0;
BYTE c;
short err;
int igot;
short length = 0;
long tttime = TickCount ();
/* Open device, FALSE if unable to open device */
if ((err = serialOpen (GARMIN)) != noErr)
{
sprintf (gMessageStr, "The initialization of port %s has failed.",
gPrefs.Device);
Error (gMessageStr);
serialClose ();
return (1 == 0);
}
if (debugging)
fprintf(stderr, "CheckGPS: sending test packet\n");
sendGPSMessage (test, 4);
/* The "test" message has packet ID 0x1c=28, which is not listed
in Garmin's ICD. Apparently it is an invalid ID, so the device
will reply with an ACK but discard the packet. */
/* wait for response */
for (;;)
{
/* timeout exceeded */
if (TickCount () > (tttime + (long) TIMEOUT))
{
serialClose ();
return (1 == 0);
}
while (serialCharsAvail ())
{
igot = read (ttyfp, &c, 1);
if (c == 0x10 && last == 0x10)
last = 0;
else
{
assert(p < gGarminMessage + MAX_LENGTH);
last = *p++ = c;
++length;
}
/* received valid response package */
if (*(p - 1) == 0x03 && *(p - 2) == 0x10)
{
if (debugging>1)
{
int i;
printf (" Receiving: ");
for (i = 0; i < length; i++)
printf ("%02X ", *(gGarminMessage + i));
printf ("\n");
}
serialClose ();
return (1 == 1);
}
}
}
}
/****************************************************************************/
/* Get response from GPS - returns number of bytes received, 0 if timeout */
/* period elapsed without completing a package. */
/****************************************************************************/
short
getGPSMessage ()
{
extern enum PROTOCOL mode;
BYTE *p = gGarminMessage;
BYTE last = 0;
BYTE c;
short length = 0;
int igot;
long tttime = TickCount ();
checksum = -(0x10 + 0x03 + 0x10); /* with this starting value, the
sum over the entire packet
should be zero */
for (;;)
{
/* exit if timeout exceeded */
if (TickCount () > (tttime + (long) TIMEOUT))
{
CloseBarGraph ();
Error ("The GPS receiver is not responding.");
mode = NONE;
return 0;
}
while (serialCharsAvail ())
{
if (length >= MAX_LENGTH - 1)
{
Error ("GPS receiver communication protocol error.");
mode = NONE;
return 0;
}
igot = read (ttyfp, &c, 1);
if (c == 0x10 && last == 0x10)
last = 0;
else
{
assert(p < gGarminMessage + MAX_LENGTH);
last = *p++ = c;
checksum += c;
++length;
}
/* return when package complete */
if (*(p - 1) == 0x03 && *(p - 2) == 0x10)
{
if (debugging>1)
{
int i;
printf (" Receiving: ");
for (i = 0; i < length; i++)
printf ("%02X ", *(gGarminMessage + i));
printf ("\n");
if (debugging && checksum)
printf("getGPSMessage: ######## checksum=%d is nonzero #########\n",
checksum);
}
return length;
}
}
}
}
/* Read the ACK packet from the GPS. Sometimes we get an invalid
packet "00 F5 10 03" instead, which we ignore. Return number of
bytes in the valid ACK packet, or zero on failure. */
int
getGPSack ()
{
int n, trial;
for (trial=0; trial<3; trial++)
{
n = getGPSMessage();
if ((n<8) ||
(gGarminMessage[0]!=0x10) ||
(gGarminMessage[2]!=n-6) ||
checksum ||
(gGarminMessage[n-2]!=0x10) ||
(gGarminMessage[n-1]!=0x03)
)
{
if (debugging)
fprintf(stderr, "GPSack: discarding invalid packet\n");
continue;
}
if (gGarminMessage[1]==0x06) /* is the packet an ACK? */
return n;
if (gGarminMessage[1]==21) /* is the packet a NAK? */
{
naks++;
return 0;
}
if (debugging)
fprintf(stderr, "GPSack: discarding packet type 0x%02X=%d, "
"neither ACK nor NAK\n",
gGarminMessage[1], gGarminMessage[1]);
}
return 0;
}
gpstrans-0.41/src/gps/garminserial.c 0000644 0001750 0001750 00000010123 10225356640 014421 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/garminserial.c - Procedure to talk with serial device */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* Copyright (c) 2001 by Joao Seabra - CT2GNL (seabra@ci.aac.uc.pt) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Prefs.h"
#include "Garmin.h"
#include
#include
#include
#include
#ifdef SUNOS41
#include
#endif
/* define external variables */
extern struct PREFS gPrefs;
/* define global variables */
int ttyfp;
struct termio ttyset;
/****************************************************************************/
/* Open serial device for requested protocol - only GARMIN supported now. */
/****************************************************************************/
int
serialOpen (enum PROTOCOL p)
{
ttyfp = open (gPrefs.Device, O_RDWR);
/* return when error opening device */
if (ttyfp < 0)
return (-1);
if (ioctl (ttyfp, TCGETA, &ttyset) < 0)
return (-1);
/* set baud rate for device */
switch (p)
{
case GARMIN:
ttyset.c_cflag = CBAUD & B9600;
ttyset.c_cflag |= CLOCAL;
break;
case NMEA:
ttyset.c_cflag = CBAUD & B4800;
break;
default:
return -1;
}
/* set character size and allow to read data */
#ifdef SUNOS41
ttyset.c_cflag |= (CSIZE & CS8) | CRTSCTS | CREAD;
#else
ttyset.c_cflag |= (CSIZE & CS8) | CREAD;
#endif
ttyset.c_iflag = ttyset.c_oflag = ttyset.c_lflag = (ushort) 0;
ttyset.c_oflag = (ONLRET);
/* return if unable to set communication parameters */
if (ioctl (ttyfp, TCSETAF, &ttyset) < 0)
return (-1);
return 0;
}
/****************************************************************************/
/* Get number of serial characters available. */
/****************************************************************************/
long
serialCharsAvail ()
{
int count;
ioctl (ttyfp, FIONREAD, &count);
return (long) count;
}
/****************************************************************************/
/* Close serial device. */
/****************************************************************************/
void
serialClose ()
{
close (ttyfp);
}
gpstrans-0.41/src/gps/getgpsinfo.c 0000644 0001750 0001750 00000147301 11037513456 014124 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/getgpsinfo.c - Receive data from GPS */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* Copyright (c) 1998 by Matthias Kattanek (mattes@ugraf.com) */
/* */
/* Copyright (c) 2001 by Joćo Seabra (seabra@ci.aac.uc.pt) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
#include "Prefs.h"
#include "graph.h"
#include "util.h"
#include
#include "protocols.h"
#include
#include
#include
/* define external variables */
extern BYTE gGarminMessage[MAX_LENGTH];
extern char *protocols;
/* define global variables */
static short records;
static FILE *FileRefNum;
static char fileData[2*MAX_LINE];
static int AlmanacSat = 0;
char GPSVersionStr[255];
/* function prototypes */
static int xmap_route_nr = 0;
static long xmap_time = 0;
static double xmap_lat = 0;
static double xmap_lon = 0;
static float xmap_speed = 0;
static char *colorCodeToName (int code);
static void doTrackHeader ();
#ifdef OLDCODE
static void doTrack_xmap (void);
static void doTrack (void);
#endif
static void doWaypoint_xmap (void);
static double distance (double lata, double lona, double latb, double lonb);
static void parseGPS (void);
static void doWaypoint (void);
static void doRouteName (void);
static void doAlmanac (void);
static long number (BYTE * p);
static char *string (short n, BYTE * p);
static void FileWrite (char *data);
static float tofloat (unsigned char *p);
static short toshort (unsigned char *p);
/****************************************************************************/
/* Write format information to output file. */
/****************************************************************************/
void
saveFormat (char *fileData, short type)
{
extern struct PREFS gPrefs;
extern struct DATUM const gDatum[];
char format[4];
time_t thistime;
switch (gPrefs.format)
{
case DMS:
strcpy (format, "DMS");
break;
case DMM:
strcpy (format, "DMM");
break;
default:
fprintf(stderr, "format code not recognized - using DDD instead\n");
gPrefs.format = DDD;
case DDD:
strcpy (format, "DDD");
break;
case UTM:
strcpy (format, "UTM");
break;
case KKJ:
strcpy (format, "KKJ");
break;
case BNG:
strcpy (format, "BNG");
break;
case ITM:
strcpy (format, "ITM");
break;
case SEG:
strcpy (format, "SEG");
break;
case GKK:
strcpy (format, "GKK");
break; /* Gauss Krueger Grid = German Grid */
}
switch(file_format)
{
case MAYKO:
case MAYKO2:
time (&thistime);
if (type == TRACK)
sprintf (fileData, "xmaplog 1.0 %s", ctime (&thistime));
else if (type == ROUTE)
sprintf (fileData, "xmaproute 1.0 %s", ctime (&thistime));
else
sprintf (fileData, "unknown xmap format %s", ctime (&thistime));
break;
case TSV:
/****************************************************************************/
/* The following header is used to save information about the data */
/* in the TSV data files. If changed, the function getFileData() in */
/* SendGPSInfo.c must also be changed. */
/* */
/* Format: DDD UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* ||| |||||| ||| */
/* 0 1 2 3 4 5 6 */
/* 0123456789012345678901234567890123456789012345678901234567890123456789 */
/****************************************************************************/
sprintf (fileData, "Format: %s UTC Offset: %6.2f hrs Datum[%03d]: %s\n",
format, gPrefs.offset, gPrefs.datum, gDatum[gPrefs.datum].name);
switch (type)
{
case ROUTE:
case WAYPOINT:
if (strstr(protocols, "A100 D100"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D101"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D102"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D103"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D104"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D105"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D106"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D107"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t");
else if (strstr(protocols, "A100 D108"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t"
"Altitude\t");
else if (strstr(protocols, "A100 D109"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t"
"Date \t"
"Altitude\t");
else if (strstr(protocols, "A100 D110"))
strcat(fileData,
"Type\t"
"Name\t"
"Comment \t"
"Date \t"
"Altitude\t");
break;
case TRACK:
if (strstr(protocols, "D300"))
strcat(fileData,
"Type\t"
"Date \t");
else if (strstr(protocols, "D301"))
strcat(fileData,
"Type\t"
"Date \t"
"Altitude\t");
else if (strstr(protocols, "D302"))
strcat(fileData,
"Type\t"
"Date \t"
"Altitude\t");
}
switch (gPrefs.format)
{
case DMS:
case DMM:
case DDD: strcat(fileData, "Latitude\tLongitude\t\n"); break;
case UTM: strcat(fileData, "ZE\tZN\tEasting\tNorthing\t\n"); break;
case BNG:
case ITM:
case KKJ: strcat(fileData, "Zone\tEasting\tNorthing\t\n"); break;
/* case SUI: appears in sendgpsinfo.c comment but not implemented */
case SEG:
case GKK: strcat(fileData, "Easting\tNorthing\t\n"); break;
default: ;
}
break;
}
}
/****************************************************************************/
/* Query GPS for its model and software version. Set string to point
to a text string. Return nonzero status if error. */
/****************************************************************************/
int getGPSVersion (char **string)
{
extern struct PREFS gPrefs;
extern char gMessageStr[];
char temp[255];
short err;
int last = 0, i;
BYTE *data=gGarminMessage+3;
extern unsigned short product_ID, software_version;
*string=gMessageStr;
SetFrameBusy (1);
/* First check if GPS responds to the "are-you-ready" package */
if (CheckGPS ())
{
usleep (10000); /* a fast computer requires this - jrv */
if ((err = serialOpen (GARMIN)) != noErr)
{
sprintf (gMessageStr, "The port initialization of %s has failed.",
gPrefs.Device);
Error (gMessageStr);
return 1; /* FAIL */
}
if (debugging)
fprintf(stderr, "getGPSVersion: sending product data request\n");
/* send request and receive version package */
sendGPSMessage (gid4, 2); /* protocol A000, Pid_Product_Rqst */
getGPSack (); /* presumably the GPS's ACK packet */
getGPSMessage (); /* get the GPS Pid_Product_Data */
sendGPSMessage (gid5, 4); /* send ACK packet for GPS response */
/*
data returned has this format:
typedef struct {
uint16 product_ID;
sint16 software_version;
char product_description[]; // null-terminated string
} Product_Data_Type;
*/
product_ID=toshort(data);
software_version=toshort(data+2);
/* extract model name and software version */
sprintf (GPSVersionStr, "Garmin %s", gGarminMessage + 7);
GPSVersionStr[strlen (GPSVersionStr) - 1] = '\0';
for (i = 0; i <= strlen (GPSVersionStr); i++)
{
if (GPSVersionStr[i] == ' ')
last = i;
}
sprintf (temp, " - V%s", &GPSVersionStr[last + 1]);
GPSVersionStr[last] = '\0';
while ((i > 0) && (GPSVersionStr[strlen (GPSVersionStr) - 1] == ' '))
GPSVersionStr[strlen (GPSVersionStr) - 1] = '\0';
sprintf (GPSVersionStr, "%s%s", GPSVersionStr, temp);
usleep (10000); /* wait 1/10 sec for device to send a
protocol string */
if (serialCharsAvail())
{ /* the device apparently implements
the protocol capability protocol */
char *p;
BYTE *s=data;
BYTE tag;
unsigned short udata;
int n;
getGPSMessage();
n=data[-1];
if (n<0)
n=0;
p=protocols=xmalloc(5*n/3+1);
for ( ; n>0; n-=3)
{
tag=*s; udata=toshort(s+1);
/* translate each protocol tag and data to the string used in the docs */
sprintf(p, " %c%03d", tag, udata);
s+=3; p+=5;
}
*p=0;
/*
A100 - waypoint transfer
A20x - route transfer
A30x - track log transfer
A400 - proximity waypoint transfer
A500 - almanac transfer
A600 - Date and time initialization
A700 - Position initialization
A800 - PVT protocol
A906 - lap transfer
For an etrex legend:
P000 L001
A010
A100 D108
A201 D202 D108 D210
A301 D310 D301
A500 D501
A600 D600
A700 D700
A800 D800
A900
A902
A903
*/
}
else
{ /* Look up the protocols using the
product ID and software version */
typedef struct
{
uint16 product_ID; /* product ID */
sint16 software_version; /* the earliest software version
implementing this list of
protocols */
char *protocol; /* list of protocols and their data
types */
} protocol_t;
/* These are protocol capabilities of "many" devices that do not
implement the Protocol Capability Protocol, from Table 28 in the
interface specification */
static protocol_t historic_protocols[] = {
{7, 000, "L001 A010 A100 D100 A200 D200 D100 A500 D500 A600 D600 A700 D700"},
/* waypoints routes tracks prox wpt almanac */
{25, 000, "L001 A010 A100 D100 A200 D200 D100 A300 D300 A400 D400 A500 D500 A600 D600 A700 D700"},
{13, 000, "L001 A010 A100 D100 A200 D200 D100 A300 D300 A400 D400 A500 D500 A600 D600 A700 D700"},
{14, 000, "L001 A010 A100 D100 A200 D200 D100 A400 D400 A500 D500 A600 D600 A700 D700"},
{15, 000, "L001 A010 A100 D151 A200 D200 D151 A400 D151 A500 D500 A600 D600 A700 D700"},
{18, 000, "L001 A010 A100 D100 A200 D200 D100 A300 D300 A400 D400 A500 D500 A600 D600 A700 D700"},
{20, 000, "L002 A011 A100 D150 A200 D201 D150 A400 D450 A500 D550 A600 D600 A700 D700"},
{22, 000, "L001 A010 A100 D152 A200 D200 D152 A300 D300 A400 D152 A500 D500 A600 D600 A700 D700"},
{23, 000, "L001 A010 A100 D100 A200 D200 D100 A300 D300 A400 D400 A500 D500 A600 D600 A700 D700"},
{24, 000, "L001 A010 A100 D100 A200 D200 D100 A300 D300 A400 D400 A500 D500 A600 D600 A700 D700"},
{29, 000, "L001 A010 A100 D101 A200 D201 D101 A300 D300 A400 D101 A500 D500 A600 D600 A700 D700"},
{29, 400, "L001 A010 A100 D102 A200 D201 D102 A300 D300 A400 D102 A500 D500 A600 D600 A700 D700"},
{31, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{33, 000, "L002 A011 A100 D150 A200 D201 D150 A400 D450 A500 D550 A600 D600 A700 D700"},
{34, 000, "L002 A011 A100 D150 A200 D201 D150 A400 D450 A500 D550 A600 D600 A700 D700"},
{35, 000, "L001 A010 A100 D100 A200 D200 D100 A300 D300 A400 D400 A500 D500 A600 D600 A700 D700"},
{36, 000, "L001 A010 A100 D152 A200 D200 D152 A300 D300 A400 D152 A500 D500 A600 D600 A700 D700"},
{36, 300, "L001 A010 A100 D152 A200 D200 D152 A300 D300 A500 D500 A600 D600 A700 D700"},
{39, 000, "L001 A010 A100 D151 A200 D201 D151 A300 D300 A500 D500 A600 D600 A700 D700"},
{41, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{42, 000, "L001 A010 A100 D100 A200 D200 D100 A300 D300 A400 D400 A500 D500 A600 D600 A700 D700"},
{44, 000, "L001 A010 A100 D101 A200 D201 D101 A300 D300 A400 D101 A500 D500 A600 D600 A700 D700"},
{45, 000, "L001 A010 A100 D152 A200 D201 D152 A300 D300 A500 D500 A600 D600 A700 D700"},
{47, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{48, 000, "L001 A010 A100 D154 A200 D201 D154 A300 D300 A500 D501 A600 D600 A700 D700"},
{49, 000, "L001 A010 A100 D102 A200 D201 D102 A300 D300 A400 D102 A500 D501 A600 D600 A700 D700"},
{50, 000, "L001 A010 A100 D152 A200 D201 D152 A300 D300 A500 D501 A600 D600 A700 D700"},
{52, 000, "L002 A011 A100 D150 A200 D201 D150 A400 D450 A500 D550 A600 D600 A700 D700"},
{53, 000, "L001 A010 A100 D152 A200 D201 D152 A300 D300 A500 D501 A600 D600 A700 D700"},
{55, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{56, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{59, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{61, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{62, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{64, 000, "L002 A011 A100 D150 A200 D201 D150 A400 D450 A500 D551 A600 D600 A700 D700"},
{71, 000, "L001 A010 A100 D155 A200 D201 D155 A300 D300 A500 D501 A600 D600 A700 D700"},
{72, 000, "L001 A010 A100 D104 A200 D201 D104 A300 D300 A500 D501 A600 D600 A700 D700"},
{73, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A500 D501 A600 D600 A700 D700"},
{74, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A500 D500 A600 D600 A700 D700"},
{76, 000, "L001 A010 A100 D102 A200 D201 D102 A300 D300 A400 D102 A500 D501 A600 D600 A700 D700"},
{77, 000, "L001 A010 A100 D100 A200 D201 D100 A300 D300 A400 D400 A500 D501 A600 D600 A700 D700"},
{77, 301, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{77, 350, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A500 D501 A600 D600 A700 D700"},
{77, 361, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{87, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{88, 000, "L001 A010 A100 D102 A200 D201 D102 A300 D300 A400 D102 A500 D501 A600 D600 A700 D700"},
{95, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{96, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{97, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A500 D501 A600 D600 A700 D700"},
{98, 000, "L002 A011 A100 D150 A200 D201 D150 A400 D450 A500 D551 A600 D600 A700 D700"},
{100, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{105, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{106, 000, "L001 A010 A100 D103 A200 D201 D103 A300 D300 A400 D403 A500 D501 A600 D600 A700 D700"},
{112, 000, "L001 A010 A100 D152 A200 D201 D152 A300 D300 A500 D501 A600 D600 A700 D700"},
/* 179 is the etrex Legend, which *usually* follows the
protocol protocol, but is included here because it
sometimes doesn't */
{179, 000, "L001 A010 A100 D108 A201 D202 D108 D210 A301 D310 D301 A500 D501 A600 D600 A700 D700 A800 D800 A900 A902 A903"},
{0}
};
protocol_t *p=historic_protocols, *next;
if (verbose)
printf("checking historic protocols for product ID %d\n", product_ID);
while(p->product_ID)
{
if (p->product_ID == product_ID)
while(1)
{
next = p+1;
if ((next->product_ID != product_ID) ||
(software_version < next->software_version))
goto found_protocol;
p++;
}
p++;
}
printf ("Warning: device with product ID %d is unknown"
" - assuming it's like a GPS II.\n", product_ID);
p=historic_protocols+31;
found_protocol:
protocols = p->protocol;
}
usleep (60000); /* 5000 < needed < 6000 */
if (debugging)
printf("product ID 0x%02x=%d, software version 0x%04x=%d, protocol string: \n%s\n",
product_ID, product_ID, software_version, software_version, protocols);
serialClose ();
SetFrameBusy (0);
}
else
{
sprintf (GPSVersionStr, "");
SetFrameBusy (0);
*string=GPSVersionStr;
return 1; /* FAIL */
}
*string=GPSVersionStr;
return 0; /* normal return */
}
/****************************************************************************/
/* Query GPS for current GPS time (in GMT/UTC). */
/****************************************************************************/
long
getGPSTime (int var)
{
extern struct PREFS gPrefs;
extern char gMessageStr[];
short err;
struct tm *txx;
time_t clock;
/* Check if GPS responds to the "are-you-ready" package */
if (!CheckGPS ())
NotResponding ();
/* open serial device */
if ((err = serialOpen (GARMIN)) != noErr)
{
sprintf (gMessageStr, "The port initialization of %s has failed.",
gPrefs.Device);
Error (gMessageStr);
return (0);
}
if ((gPrefs.model == 'y'))
{
/* send command and receive package */
sendGPSMessage (tim1, 4);
getGPSack ();
getGPSMessage ();
}
else
{
/* send command and receive package */
sendGPSMessage (tim1, 4);
getGPSack (); /* this is the ACK-package */
getGPSMessage (); /* This is of the unknown type 09: leap seconds ? */
getGPSack (); /* This is ACK again */
getGPSMessage (); /* Stuff */
}
/* close serial device */
serialClose ();
/* exit if not a valid time package */
if (*(gGarminMessage + 1) != 0x0e)
return (-1);
/* convert UTC time to localtime using the unix timezone */
time (&clock);
txx = gmtime (&clock);
txx->tm_sec = *(gGarminMessage + 10);
txx->tm_min = *(gGarminMessage + 9);
txx->tm_hour = *(gGarminMessage + 7);
txx->tm_year = (toshort (gGarminMessage + 5) - 1900);
txx->tm_mday = *(gGarminMessage + 4);
txx->tm_mon = (*(gGarminMessage + 3)) - 1;
clock = timegm (txx);
return (clock);
}
/****************************************************************************/
/* Get multiple line packages from GPS (route, waypoint, track) */
/****************************************************************************/
void
getGPSInfo (FILE * refNum, short type)
{
extern struct PREFS gPrefs;
extern char gMessageStr[];
short total;
short done = 0;
BYTE *init, *req;
short err;
char *rType;
int junk;
char *junk_str;
/* First check if GPS responds to the "are-you-ready" package */
if (!CheckGPS ())
NotResponding ();
junk=getGPSVersion(&junk_str); /* load the "protocols" array */
/* open serial device */
if ((err = serialOpen (GARMIN)) != noErr)
{
sprintf (gMessageStr, "The port initialization of %s has failed.",
gPrefs.Device);
Error (gMessageStr);
return;
}
FileRefNum = refNum;
records = 0;
/* Save output format if not Almanac-Data */
saveFormat (fileData, type);
if (type != ALMANAC)
FileWrite (fileData);
/* process different requests */
switch (type)
{
default:
case ALMANAC: init = alm1; req = alm2; rType = "almanac"; break;
case ROUTE: init = rte1; req = rte2; rType = "routes"; break;
case TRACK: init = trk1; req = trk2; rType = "track"; break;
case WAYPOINT: init = wpt1; req = wpt2; rType = "waypoint"; break;
}
AlmanacSat = 0;
/* open BarGraph window */
InitBarGraph ();
/* send init package */
sendGPSMessage (init, 4);
getGPSack();
/* exit if no package received from GPS */
if (getGPSMessage () == 0)
{
CloseBarGraph ();
serialClose ();
return;
}
total = toshort(gGarminMessage+3); /* get number of records to
transfer */
if (verbose)
{
sprintf(gMessageStr, "GPS receiver will send %d packets.",
total);
Message (gMessageStr);
}
if (total < 1)
total = 1; /* prevent divide by zero or negative
length progress bar */
/* repeat until all packages received */
while (!done)
{
sendGPSMessage (req, 4);
if (getGPSMessage () == 0)
break;
done = (gGarminMessage[1] == 0x0c);
if (!done)
{
parseGPS ();
SetBarGraph ((double) (records) / (double) total);
}
}
/* close BarGraph and serial device */
CloseBarGraph ();
serialClose ();
if (verbose || debugging)
{
sprintf (gMessageStr,
"%d %s packets were transferred from the GPS receiver.",
records, rType);
Message (gMessageStr);
if (debugging && total && (records != total))
{
sprintf(gMessageStr, " (%d were expected.)", total);
Message (gMessageStr);
}
}
}
/****************************************************************************/
/* Parse messages received from GPS. */
/****************************************************************************/
static void
parseGPS ()
{
switch (gGarminMessage[1])
{
case RTE_NAM: /* Route name record */
doRouteName ();
break;
case RTE_WPT: /* Route waypoint record */
if (file_format == MAYKO)
doWaypoint_xmap ();
else
doWaypoint ();
break;
case ALM: /* Almanac record */
doAlmanac ();
break;
case Pid_Trk_Hdr:
doTrackHeader ();
break;
case TRK: /* Track record */
if (file_format == MAYKO)
// doTrack_xmap ();
doWaypoint ();
else
// doTrack ();
doWaypoint ();
break;
case WPT: /* Waypoint record */
doWaypoint ();
break;
default:
if (debugging)
printf("parseGPS: unexpected package, packet ID 0x%02X=%d\n",
gGarminMessage[1], gGarminMessage[1]);
return;
}
records++;
}
/****************************************************************************/
/* Process RouteName package (data type D200, D201, or D202) and write
to output file\. */
/****************************************************************************/
static void
doRouteName ()
{
typedef struct
{
unsigned int nmbr;
char *cmnt;
} route_name_type;
route_name_type rte;
rte.cmnt=0;
rte.nmbr=~1;
if (strstr(protocols, "D200"))
{
char *d=(char *)(gGarminMessage+3);
rte.nmbr=d[0];
/* no string field */
}
else if (strstr(protocols, "D201"))
{
D201_Rte_Hdr_Type *d=(D201_Rte_Hdr_Type *)(gGarminMessage+3);
rte.nmbr=d->nmbr;
rte.cmnt=(char *)(&d->cmnt);
}
else if (strstr(protocols, "D202"))
{
D202_Rte_Hdr_Type *d=(D202_Rte_Hdr_Type *)(gGarminMessage+3);
/* no route number */
rte.cmnt=(char *)(&d->rte_ident);
}
if (file_format == MAYKO)
{
if (rte.nmbr != ~1)
xmap_route_nr = rte.nmbr;
else
xmap_route_nr = 0; /* punt */
}
else
{
sprintf (fileData, "R\t");
FileWrite (fileData);
if (rte.nmbr != ~1)
{
sprintf (fileData, "%d\t", rte.nmbr);
FileWrite (fileData);
}
if (rte.cmnt)
{
sprintf (fileData, "%s\n", rte.cmnt);
FileWrite (fileData);
}
}
}
static void
doTrackHeader ()
{
struct
{
unsigned char dspl;
unsigned char color;
char *ident;
int index;
struct {
unsigned dspl:1;
unsigned color:1;
unsigned ident:1;
unsigned index:1;
} has;
} hdr;
hdr.has.dspl =
hdr.has.color =
hdr.has.ident =
hdr.has.index = 0;
if (strstr(protocols, "D310"))
{
D310_Trk_Hdr_Type *d=(D310_Trk_Hdr_Type *)(gGarminMessage+3);
hdr.dspl = d->dspl;
hdr.color = d->color; /* same as in D108 */
hdr.ident = (char *)(&d->trk_ident);
hdr.has.dspl = hdr.has.color = hdr.has.ident = 1;
}
if (strstr(protocols, "D311"))
{
D311_Trk_Hdr_Type *d=(D311_Trk_Hdr_Type *)(gGarminMessage+3);
hdr.index = toshort ((BYTE *)(&d->index));
hdr.has.index = 1;
}
if (strstr(protocols, "D312"))
{
D312_Trk_Hdr_Type *d=(D312_Trk_Hdr_Type *)(gGarminMessage+3);
hdr.dspl = d->dspl;
hdr.color = d->color; /* same as in D110 */
hdr.ident = (char *)(&d->trk_ident);
hdr.has.dspl = hdr.has.color = hdr.has.ident = 1;
}
switch(file_format)
{
case MAYKO:
case MAYKO2:
break;
case TSV:
if (hdr.has.dspl)
printf("H\t%s\t%s\t%.51s\n",
hdr.dspl?"display":"hide",
colorCodeToName(hdr.color),
hdr.ident);
else
printf("H\t%d\n", hdr.index);
break;
}
}
/* return a pointer to a static string with the name of the color
corresponding to CODE. */
static char *
colorCodeToName (int code)
{
char *color_name[18]={
"black",
"dark red",
"dark green",
"dark yellow",
"dark blue",
"dark magenta",
"dark cyan",
"light gray",
"dark gray",
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
"white",
"transparent",
"default"
};
if (code == 0x1f || code == 255)
return color_name[17];
if (code < 0 || code > 16)
{
if (debugging)
printf("colorCodeToName: unexpected color code 0x%02X=%d, "
"assuming black\n", code, code);
code = 0;
}
return color_name[code];
}
#ifdef OLDCODE
/****************************************************************************/
/* Process Track package and write to output file\. */
/****************************************************************************/
static void
doTrack ()
{
extern struct PREFS gPrefs;
double latitude, longitude, x, y;
char zone[6];
if (*(gGarminMessage + 15) == '\x01') /* New track, create blank record */
if (records != 0)
FileWrite ("\n");
/* convert bytes to latitude / longitude */
latitude = int2deg (number (gGarminMessage + 3));
longitude = int2deg (number (gGarminMessage + 7));
/* translate to selected datum */
translate (1, &latitude, &longitude, gPrefs.datum);
/* Write track time to file */
sprintf (fileData, "T\t%s\t", secs2dt (number (gGarminMessage + 11),
gPrefs.offset));
FileWrite (fileData);
/* convert to selected position format */
switch (gPrefs.format)
{
case DMS:
sprintf (fileData, "%s\t", toDMS (latitude));
FileWrite (fileData);
sprintf (fileData, "%s\n", toDMS (longitude));
FileWrite (fileData);
break;
case DMM:
sprintf (fileData, "%s\t", toDM (latitude));
FileWrite (fileData);
sprintf (fileData, "%s\n", toDM (longitude));
FileWrite (fileData);
break;
case DDD:
sprintf (fileData, "%03.7f\t%04.7f\n", latitude, longitude);
FileWrite (fileData);
break;
case UTM: /* Convert to UTM grid */
DegToUTM (latitude, longitude, zone, &x, &y);
sprintf (fileData, "%s\t%07.0f\t%07.0f\n", zone, x, y);
FileWrite (fileData);
break;
case KKJ: /* Convert to KKJ grid */
DegToKKJ (latitude, longitude, zone, &x, &y);
sprintf (fileData, "%s\t%07.0f\t%07.0f\n", zone, x, y);
FileWrite (fileData);
break;
case BNG: /* Convert to British grid */
DegToBNG (latitude, longitude, zone, &x, &y);
sprintf (fileData, "%s\t%05.0f\t%05.0f\n", zone, x, y);
FileWrite (fileData);
break;
case ITM: /* Convert to Irish grid */
DegToITM (latitude, longitude, zone, &x, &y);
sprintf (fileData, "%s\t%05.0f\t%05.0f\n", zone, x, y);
FileWrite (fileData);
break;
case SEG: /* Convert to Swedish grid */
DegToSEG (latitude, longitude, &x, &y);
sprintf (fileData, "%07.0f\t%07.0f\n", x, y);
FileWrite (fileData);
break;
case GKK:
DegToGKK (latitude, longitude, &x, &y);
sprintf (fileData, "%07.0f\t%07.0f\n", x, y);
FileWrite (fileData);
break;
default:
break;
}
}
/****************************************************************************/
/* convert Track package and write to Mayko xmap log */
/****************************************************************************/
static void
doTrack_xmap ()
{
extern struct PREFS gPrefs;
double latitude, longitude;
int altitude = 0;
long t_diff = 0;
double x_dist = 0;
float x_speed = 0;
if (*(gGarminMessage + 15) == '\x01')
{ /* New track, create blank record */
xmap_lat = 0; // reset xmap lat + lon
xmap_lon = 0;
xmap_time = 0;
if (records != 0)
FileWrite ("\n");
}
/* convert bytes to latitude / longitude */
latitude = int2deg (number (gGarminMessage + 3));
longitude = int2deg (number (gGarminMessage + 7));
/* translate to selected datum */
translate (1, &latitude, &longitude, gPrefs.datum);
/*
* --- calculate speed
*/
if (xmap_lat)
{
x_dist = distance (latitude, longitude, xmap_lat, xmap_lon);
t_diff = number (gGarminMessage + 11) - xmap_time;
if (t_diff)
x_speed = (float) ((x_dist / (double) t_diff) * 3600 / 1.852);
else
x_speed = xmap_speed;
}
/*
* --- write mayko xmap format
*/
sprintf (fileData, "1 %03.7f %04.7f ", latitude, longitude);
FileWrite (fileData);
sprintf (fileData, "%.1f %d ", x_speed, altitude);
FileWrite (fileData);
sprintf (fileData, "%s", secs2dt (number (gGarminMessage + 11),
gPrefs.offset));
FileWrite (fileData);
if (xmap_lat)
{
if (file_format == MAYKO)
{
sprintf (fileData, " x%03.7f %04.7f", xmap_lat, xmap_lon);
FileWrite (fileData);
sprintf (fileData, " %06.7f", x_dist);
FileWrite (fileData);
sprintf (fileData, " -%d-", (int) t_diff);
FileWrite (fileData);
sprintf (fileData, " %.3f", x_speed);
FileWrite (fileData);
}
}
FileWrite ("\n");
xmap_lat = latitude; //save lat + lon for next round
xmap_lon = longitude;
xmap_time = number (gGarminMessage + 11);
xmap_speed = x_speed;
}
#endif /* OLDCODE */
/****************************************************************************/
/* convert Track package and write to Mayko xmap log */
/****************************************************************************/
static void
doWaypoint_xmap ()
{
extern struct PREFS gPrefs;
double latitude, longitude;
printf ("route number %d\n", xmap_route_nr);
if (xmap_route_nr) // save only "active" route 0
return;
/* convert bytes to latitude / longitude */
latitude = int2deg (number (gGarminMessage + 9));
longitude = int2deg (number (gGarminMessage + 13));
/* translate to selected datum */
translate (1, &latitude, &longitude, gPrefs.datum);
/*
* --- write mayko xmap route format
*/
sprintf (fileData, "%s,", string (6, gGarminMessage + 3));
FileWrite (fileData);
sprintf (fileData, "%03.6f,%04.6f,0,,\n", latitude, longitude);
FileWrite (fileData);
}
/* return distance in km from (lata,lona) to (latb,lonb), where the
latter are in degrees. Uses spherical earth approximation. */
double
distance (double lata, double lona, double latb, double lonb)
{
#define DEG2RAD (3.14159265358979323846E0/180.0)
double l0 = lona * DEG2RAD;
double l1 = lonb * DEG2RAD;
double b0 = lata * DEG2RAD;
double b1 = latb * DEG2RAD;
return (6371*2*asin(sqrt(cos(b1)*cos(b0)*sin(0.5*(l1 - l0))*sin(0.5*(l1 - l0))
+ sin(0.5*(b1 - b0))*sin(0.5*(b1 - b0)))));
}
/****************************************************************************/
/* Process Waypoint packet (D1xx), Route packet (D2xx), or Track packet (D3xx)
and write to output file. */
/****************************************************************************/
static void
doWaypoint ()
{
extern struct PREFS gPrefs;
char zone[6], *s;
double x,y;
double x_dist=0, t_diff=0, x_speed=0;
/* We extract these from the packet if available */
struct
{
double latitude, longitude;
double altitude;
double seconds;
char name[16];
char *comment;
char new_trk;
struct {
/* latitude and longitude are always present */
unsigned altitude:1;
unsigned seconds:1;
unsigned name:1;
unsigned comment:1;
} has;
} pkt;
char flag;
char Pid;
pkt.new_trk =
pkt.has.altitude =
pkt.has.seconds =
pkt.has.name =
pkt.has.comment = 0;
Pid = gGarminMessage[1];
switch(Pid)
{
case Pid_Rte_Wpt_Data:
case Pid_Wpt_Data:
flag='W';
/* all the devices seem to use the same packet type for
waypoints and routes, but something else for tracks */
if (strstr(protocols, "D100"))
{
D100_Wpt_Type *d=(D100_Wpt_Type *)(gGarminMessage+3);
/* D100_Wpt_Type:
struct {
char ident[6]; // identifier
position_type posn; // position
uint32 unused; // should be set to zero
char cmnt[40]; // comment
}
*/
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-6.6s",(char *)(&d->ident));
pkt.comment=(char *)(&d->cmnt);
pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D101"))
{
D101_Wpt_Type *d=(D101_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-6.6s",(char *)(&d->ident));
pkt.comment=(char *)(&d->cmnt);
pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D102"))
{
D102_Wpt_Type *d=(D102_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-6.6s",(char *)(&d->ident));
pkt.comment=(char *)(&d->cmnt);
pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D103"))
{
D103_Wpt_Type *d=(D103_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-6.6s",(char *)(&d->ident));
pkt.comment=(char *)(&d->cmnt);
pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D104"))
{
D104_Wpt_Type *d=(D104_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-6.6s",(char *)(&d->ident));
pkt.comment=(char *)(&d->cmnt);
pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D105"))
{
D105_Wpt_Type *d=(D105_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-15.15s",(char *)(&d->ident));
/* no comment */
pkt.has.name=1;
}
else if (strstr(protocols, "D106"))
{
D106_Wpt_Type *d=(D106_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-15.15s",(char *)(&d->ident));
/* no comment */
pkt.has.name=1;
}
else if (strstr(protocols, "D107"))
{
D107_Wpt_Type *d=(D107_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
sprintf(pkt.name, "%-6.6s",(char *)(&d->ident));
pkt.comment=(char *)(&d->cmnt);
pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D108"))
{
D108_Wpt_Type *d=(D108_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
pkt.altitude = tofloat ((BYTE *)(&d->alt));
s=(char *)(char *)(&d->ident);
sprintf(pkt.name, "%-15.15s",s);
s+=strlen(s)+1;
pkt.comment=s;
pkt.has.altitude=pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D109"))
{
D109_Wpt_Type *d=(D109_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
pkt.altitude = tofloat ((BYTE *)(&d->alt));
s=(char *)(char *)(&d->ident);
sprintf(pkt.name, "%-15.15s",s);
s+=strlen(s)+1;
pkt.comment=s;
pkt.has.altitude=pkt.has.name=pkt.has.comment=1;
}
else if (strstr(protocols, "D110"))
{
D110_Wpt_Type *d=(D110_Wpt_Type *)(gGarminMessage+3);
/* convert bytes to latitude/longitude */
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
pkt.altitude = tofloat ((BYTE *)(&d->alt));
s=(char *)(&d->ident);
sprintf(pkt.name, "%-15.15s",s);
s+=strlen(s)+1;
pkt.comment=s;
pkt.seconds=number((BYTE *)(&d->time));
pkt.has.altitude=pkt.has.name=pkt.has.comment=pkt.has.seconds=1;
}
break;
case Pid_Trk_Data:
flag='T';
if (strstr(protocols, "D300"))
{
D300_Trk_Point_Type *d=(D300_Trk_Point_Type *)(gGarminMessage+3);
pkt.seconds = number((BYTE *)(&d->time));
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
pkt.new_trk = d->new_trk;
pkt.has.seconds=1;
}
if (strstr(protocols, "D301"))
{
D301_Trk_Point_Type *d=(D301_Trk_Point_Type *)(gGarminMessage+3);
pkt.seconds = number((BYTE *)(&d->time));
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
pkt.altitude = tofloat ((BYTE *)(&d->alt));
pkt.new_trk = d->new_trk;
pkt.has.seconds=pkt.has.altitude=1;
}
if (strstr(protocols, "D302"))
{
D302_Trk_Point_Type *d=(D302_Trk_Point_Type *)(gGarminMessage+3);
pkt.seconds = number((BYTE *)(&d->time));
pkt.latitude = int2deg (number ((BYTE *)(&d->posn.lat)));
pkt.longitude = int2deg (number ((BYTE *)(&d->posn.lon)));
pkt.altitude = tofloat ((BYTE *)(&d->alt));
pkt.new_trk = d->new_trk;
pkt.has.seconds=pkt.has.altitude=1;
}
break;
}
/* translate position selected datum */
translate (1, &pkt.latitude, &pkt.longitude, gPrefs.datum);
switch(file_format)
{
case MAYKO:
case MAYKO2:
switch(Pid)
{
case Pid_Rte_Wpt_Data:
sprintf (fileData, "%s,", pkt.name);
FileWrite (fileData);
sprintf (fileData, "%03.6f,%04.6f,0,,\n", pkt.latitude, pkt.longitude);
FileWrite (fileData);
break;
case Pid_Trk_Data:
if (pkt.new_trk)
{ /* New track, create blank record */
xmap_lat = 0; /* reset xmap lat + lon */
xmap_lon = 0;
xmap_time = 0;
if (records != 0)
FileWrite ("\n");
}
/* calculate speed */
if (xmap_lat)
{
x_dist = distance (pkt.latitude, pkt.longitude, xmap_lat, xmap_lon);
t_diff = pkt.seconds - xmap_time;
if (t_diff)
x_speed = (float)((x_dist/(double)t_diff)*3600/1.852);
else
x_speed = xmap_speed;
}
/* write mayko xmap format */
sprintf (fileData, "1 %03.7f %04.7f ", pkt.latitude, pkt.longitude);
FileWrite (fileData);
sprintf (fileData, "%.1f %1.0f ", x_speed, pkt.altitude);
FileWrite (fileData);
sprintf (fileData, "%s", secs2dt (pkt.seconds, gPrefs.offset));
FileWrite (fileData);
if (xmap_lat && (file_format == MAYKO2))
{
sprintf (fileData, " x%03.7f %04.7f", xmap_lat, xmap_lon);
FileWrite (fileData);
sprintf (fileData, " %06.7f", x_dist);
FileWrite (fileData);
sprintf (fileData, " -%d-", (int) t_diff);
FileWrite (fileData);
sprintf (fileData, " %.3f", x_speed);
FileWrite (fileData);
}
FileWrite ("\n");
xmap_lat = pkt.latitude; //save lat + lon for next round
xmap_lon = pkt.longitude;
xmap_time = number (gGarminMessage + 11);
xmap_speed = x_speed;
break;
}
break;
case TSV:
/* write record type flag */
sprintf (fileData, "%c\t", flag);
FileWrite (fileData);
/* write waypoint name */
if (pkt.has.name)
{
sprintf (fileData, "%s\t", pkt.name);
FileWrite (fileData);
}
/* write comment - up to 40 characters */
if (pkt.has.comment)
{
sprintf (fileData, "%-40s\t", pkt.comment);
FileWrite (fileData);
}
/* write date/time */
if (pkt.has.seconds)
{
sprintf (fileData, "%s\t", secs2dt (pkt.seconds, gPrefs.offset));
FileWrite (fileData);
}
/* write altitude */
if (pkt.has.altitude) /* does the packet accommodate altitude? */
{
if (pkt.altitude < 1.e24) /* is the altitude valid? */
if (gPrefs.feet)
sprintf (fileData, "%9.2f ft\t", pkt.altitude/.3048);
else
sprintf (fileData, "%9.2f m\t", pkt.altitude);
else
sprintf (fileData, "unknown \t");
FileWrite (fileData);
}
switch (gPrefs.format)
{
case DMS:
sprintf (fileData, "%s\t", toDMS (pkt.latitude));
FileWrite (fileData);
sprintf (fileData, "%s\n", toDMS (pkt.longitude));
FileWrite (fileData);
break;
case DMM:
sprintf (fileData, "%s\t", toDM (pkt.latitude));
FileWrite (fileData);
sprintf (fileData, "%s\n", toDM (pkt.longitude));
FileWrite (fileData);
break;
case DDD:
sprintf (fileData, "%03.7f\t%04.7f\n", pkt.latitude, pkt.longitude);
FileWrite (fileData);
break;
case UTM: /* convert to UTM grid */
DegToUTM (pkt.latitude, pkt.longitude, zone, &x, &y);
sprintf (fileData, "%s\t%07.0f\t%07.0f\n", zone, x, y);
FileWrite (fileData);
break;
case KKJ: /* convert to KKJ grid */
DegToKKJ (pkt.latitude, pkt.longitude, zone, &x, &y);
sprintf (fileData, "%s\t%07.0f\t%07.0f\n", zone, x, y);
FileWrite (fileData);
break;
case BNG: /* convert to British grid */
DegToBNG (pkt.latitude, pkt.longitude, zone, &x, &y);
sprintf (fileData, "%s\t%05.0f\t%05.0f\n", zone, x, y);
FileWrite (fileData);
break;
case ITM: /* convert to irish grid */
DegToITM (pkt.latitude, pkt.longitude, zone, &x, &y);
sprintf (fileData, "%s\t%05.0f\t%05.0f\n", zone, x, y);
FileWrite (fileData);
break;
case SEG: /* convert to Swedish grid */
DegToSEG (pkt.latitude, pkt.longitude, &x, &y);
sprintf (fileData, "%07.0f\t%07.0f\n", x, y);
FileWrite (fileData);
break;
case GKK: /* convert to German Grid */
DegToGKK (pkt.latitude, pkt.longitude, &x, &y);
sprintf (fileData, "%07.0f\t%07.0f\n", x, y);
FileWrite (fileData);
break;
default:
break;
}
break;
}
}
/****************************************************************************/
/* Process Almanac package (D500, D501, D550, or D551) and write to
output file\. */
/****************************************************************************/
static void
doAlmanac ()
{
char temp[255];
typedef struct
{
int svid;
short wn;
double toa, af0, af1, e, sqrta, m0, w, omg0, odot, i;
int hlth;
} almanac_type;
almanac_type pkt;
pkt.svid = pkt.hlth = ~1;
if (strstr(protocols, "D500"))
{
D500_Almanac_Type *d=(D500_Almanac_Type *)(gGarminMessage+3);
/* no satellite ID */
pkt.wn = toshort ((BYTE *)(&d->wn ));
pkt.toa = tofloat ((BYTE *)(&d->toa ));
pkt.af0 = tofloat ((BYTE *)(&d->af0 ));
pkt.af1 = tofloat ((BYTE *)(&d->af1 ));
pkt.e = tofloat ((BYTE *)(&d->e ));
pkt.sqrta = tofloat ((BYTE *)(&d->sqrta));
pkt.m0 = tofloat ((BYTE *)(&d->m0 ));
pkt.w = tofloat ((BYTE *)(&d->w ));
pkt.omg0 = tofloat ((BYTE *)(&d->omg0 ));
pkt.odot = tofloat ((BYTE *)(&d->odot ));
pkt.i = tofloat ((BYTE *)(&d->i ));
/* no hlth */
}
else if (strstr(protocols, "D501"))
{
D501_Almanac_Type *d=(D501_Almanac_Type *)(gGarminMessage+3);
/* no satellite ID */
pkt.wn = toshort ((BYTE *)(&d->wn ));
pkt.toa = tofloat ((BYTE *)(&d->toa ));
pkt.af0 = tofloat ((BYTE *)(&d->af0 ));
pkt.af1 = tofloat ((BYTE *)(&d->af1 ));
pkt.e = tofloat ((BYTE *)(&d->e ));
pkt.sqrta = tofloat ((BYTE *)(&d->sqrta));
pkt.m0 = tofloat ((BYTE *)(&d->m0 ));
pkt.w = tofloat ((BYTE *)(&d->w ));
pkt.omg0 = tofloat ((BYTE *)(&d->omg0 ));
pkt.odot = tofloat ((BYTE *)(&d->odot ));
pkt.i = tofloat ((BYTE *)(&d->i ));
pkt.hlth = d->hlth;
}
else if (strstr(protocols, "D550"))
{
D550_Almanac_Type *d=(D550_Almanac_Type *)(gGarminMessage+3);
pkt.svid = d->svid;
pkt.wn = toshort ((BYTE *)(&d->wn ));
pkt.toa = tofloat ((BYTE *)(&d->toa ));
pkt.af0 = tofloat ((BYTE *)(&d->af0 ));
pkt.af1 = tofloat ((BYTE *)(&d->af1 ));
pkt.e = tofloat ((BYTE *)(&d->e ));
pkt.sqrta = tofloat ((BYTE *)(&d->sqrta));
pkt.m0 = tofloat ((BYTE *)(&d->m0 ));
pkt.w = tofloat ((BYTE *)(&d->w ));
pkt.omg0 = tofloat ((BYTE *)(&d->omg0 ));
pkt.odot = tofloat ((BYTE *)(&d->odot ));
pkt.i = tofloat ((BYTE *)(&d->i ));
/* no hlth */
}
else if (strstr(protocols, "D551"))
{
D551_Almanac_Type *d=(D551_Almanac_Type *)(gGarminMessage+3);
pkt.svid = d->svid;
pkt.wn = toshort ((BYTE *)(&d->wn ));
pkt.toa = tofloat ((BYTE *)(&d->toa ));
pkt.af0 = tofloat ((BYTE *)(&d->af0 ));
pkt.af1 = tofloat ((BYTE *)(&d->af1 ));
pkt.e = tofloat ((BYTE *)(&d->e ));
pkt.sqrta = tofloat ((BYTE *)(&d->sqrta));
pkt.m0 = tofloat ((BYTE *)(&d->m0 ));
pkt.w = tofloat ((BYTE *)(&d->w ));
pkt.omg0 = tofloat ((BYTE *)(&d->omg0 ));
pkt.odot = tofloat ((BYTE *)(&d->odot ));
pkt.i = tofloat ((BYTE *)(&d->i ));
pkt.hlth = d->hlth;
}
if (pkt.svid == ~1)
pkt.svid = ++AlmanacSat; /* next satellite */
/* don't handle if satellite not active
"If the data for a particular satellite is missing or if the
satellite is non-existent, then the week number for that satellite
must be set to a negative number to indicate that the data is
invalid." */
if (pkt.wn < 0)
return;
/* print almanac data in yuma-format */
sprintf (temp, "******** Week %d almanac for PRN-%02d ********\n",
pkt.wn, pkt.svid);
FileWrite (temp);
sprintf (temp, "ID: %02d\n", pkt.svid);
FileWrite (temp);
sprintf (temp, "Health: %03d\n", pkt.hlth);
FileWrite (temp);
sprintf (temp, "Eccentricity: % 1.10E\n", pkt.e);
FileWrite (temp);
sprintf (temp, "Time of Applicability(x): %10.2f\n", pkt.toa);
FileWrite (temp);
sprintf (temp, "Orbital Inclination(rad): % 1.10f\n", pkt.i);
FileWrite (temp);
sprintf (temp, "Rate of Right Ascen(r/s): % 1.10E\n", pkt.odot);
FileWrite (temp);
sprintf (temp, "SQRT(A) (m^1/2): % 1.10f\n", pkt.sqrta);
FileWrite (temp);
sprintf (temp, "Right Ascen at TOA(rad): % 1.10E\n", pkt.omg0);
FileWrite (temp);
sprintf (temp, "Argument of Perigee(rad): % 1.10f\n", pkt.w);
FileWrite (temp);
sprintf (temp, "Mean Anom(rad): % 1.10E\n", pkt.m0);
FileWrite (temp);
sprintf (temp, "Af0(s): % 1.10E\n", pkt.af0);
FileWrite (temp);
sprintf (temp, "Af1(s/s): % 1.10E\n", pkt.af1);
FileWrite (temp);
sprintf (temp, "week: %d\n", pkt.wn);
FileWrite (temp);
sprintf (temp, "\n");
FileWrite (temp);
}
/****************************************************************************/
/* Convert bytes to string. */
/****************************************************************************/
static char *
string (short n, BYTE * p)
{
static char s[50];
short i;
for (i = 0; i < n; i++)
s[i] = *p++;
s[n] = '\0';
return s;
}
/****************************************************************************/
/* Convert bytes to long number. */
/****************************************************************************/
static long
number (BYTE * p)
{
long n;
/* LSB is first */
n = ((((((long) p[3] << 8) + p[2]) << 8) + p[1]) << 8) + p[0];
return n;
}
/****************************************************************************/
/* Convert bytes to float number. */
/****************************************************************************/
static float
tofloat (BYTE * p)
{
float n;
long *lp = (long *) &n;
/* LSB is first */
*lp = ((((((long) p[3] << 8) + p[2]) << 8) + p[1]) << 8) + p[0];
return n;
}
/****************************************************************************/
/* Convert bytes to short number. */
/****************************************************************************/
static short
toshort (BYTE * p)
{
short n;
n = ((short) p[1] << 8) + p[0];
return n;
}
/****************************************************************************/
/* Write string to output file\. */
/****************************************************************************/
static void
FileWrite (char *data)
{
fputs (data, FileRefNum);
}
gpstrans-0.41/src/gps/gpsmessage.c 0000644 0001750 0001750 00000007026 10235233252 014104 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/gpsmessage.c - Define GPS commands */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
/****************************************************************************/
/* Define Garmin-Protocol commands. */
/****************************************************************************/
BYTE m1[] = "\xfe\x01\x20"; /* Get the model and version number */
BYTE m2[] = "\x06\x02\xff\x00"; /* unknown */
BYTE p1[] = "\x06\x02\x1b\x00"; /* Get 1st packet */
BYTE p2[] = "\x06\x02\x0c\x00"; /* Get last packet */
BYTE alm1[] = "\x0a\x02\x01\x00"; /* Send almanac command */
BYTE alm2[] = "\x06\x02\x1f\x00"; /* Acknowlege almanac packet */
BYTE trk1[] = "\x0a\x02\x06\x00"; /* Get track command */
BYTE trk2[] = "\x06\x02\x22\x00"; /* Acknowlege track packet */
BYTE wpt1[] = "\x0A\x02\x07\x00"; /* Get waypoint command */
BYTE wpt2[] = "\x06\x02\x23\x00"; /* Acknowlege waypoint packet */
BYTE rte1[] = "\x0a\x02\x04\x00"; /* Get route command */
BYTE rte2[] = "\x06\x02\x1d\x00"; /* Acknowlege route packet */
BYTE test[] = "\x1c\x02\x00\x00"; /* Get response from Garmin */
BYTE gid4[] = "\xfe\x00"; /* Get Garmin model & Software rev */
BYTE gid5[] = "\x06\x02\xff\x00";
BYTE off1[] = "\x0a\x02\x08\x00"; /* Turn Garmin Off */
BYTE tim1[] = "\x0a\x02\x05\x00"; /* Get UTC Time */
BYTE almt[] = "\x0c\x02\x01\x00"; /* Almanac data base terminator */
BYTE rtet[] = "\x0c\x02\x04\x00"; /* Route data base terminator */
BYTE trkt[] = "\x0c\x02\x06\x00"; /* Track data base terminator */
BYTE wptt[] = "\x0c\x02\x07\x00"; /* Waypoint data base terminator */
gpstrans-0.41/src/gps/latlong.c 0000644 0001750 0001750 00000015110 10225356640 013405 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/latlong.c - Convert latitude and longitude */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
#include
/* define constants */
static const double CONVERT = 11930464.7111111111111; /* 2^31 / 180 */
#ifndef PI
static const double PI = 3.14159265358979323846; /* PI */
#endif
static const double WGSa = 6378137.0; /* WGS84 semimajor axis */
static const double WGSinvf = 298.257223563; /* WGS84 1/f */
static const short WGS84ID = 100; /* ID of WGS84 datum */
/****************************************************************************/
/* Converts latitude and longitude in decimal degrees from WGS84 to another */
/* datum or from another datum to WGS84. The arguments to this function */
/* include a direction flag 'fromWGS84', pointers to double precision */
/* latitude and longitude, and an index to the gDatum[] array. */
/****************************************************************************/
void
translate (short fromWGS84, double *latitude, double *longitude,
short datumID)
{
extern struct DATUM const gDatum[];
extern struct ELLIPSOID const gEllipsoid[];
double dx = gDatum[datumID].dx;
double dy = gDatum[datumID].dy;
double dz = gDatum[datumID].dz;
double phi = *latitude * PI / 180.0;
double lambda = *longitude * PI / 180.0;
double a0, b0, es0, f0; /* Reference ellipsoid of input data */
double a1, b1, es1, f1; /* Reference ellipsoid of output data */
double psi; /* geocentric latitude */
double x, y, z; /* 3D coordinates with respect to original datum */
double psi1; /* transformed geocentric latitude */
if (datumID == WGS84ID) /* do nothing if current datum is WGS84 */
return;
if (fromWGS84)
{ /* convert from WGS84 to new datum */
a0 = WGSa; /* WGS84 semimajor axis */
f0 = 1.0 / WGSinvf; /* WGS84 flattening */
a1 = gEllipsoid[gDatum[datumID].ellipsoid].a;
f1 = 1.0 / gEllipsoid[gDatum[datumID].ellipsoid].invf;
}
else
{ /* convert from datum to WGS84 */
a0 = gEllipsoid[gDatum[datumID].ellipsoid].a; /* semimajor axis */
f0 = 1.0 / gEllipsoid[gDatum[datumID].ellipsoid].invf; /* flattening */
a1 = WGSa; /* WGS84 semimajor axis */
f1 = 1 / WGSinvf; /* WGS84 flattening */
dx = -dx;
dy = -dy;
dz = -dz;
}
b0 = a0 * (1 - f0); /* semiminor axis for input datum */
es0 = 2 * f0 - f0 * f0; /* eccentricity^2 */
b1 = a1 * (1 - f1); /* semiminor axis for output datum */
es1 = 2 * f1 - f1 * f1; /* eccentricity^2 */
/* Convert geodedic latitude to geocentric latitude, psi */
if (*latitude == 0.0 || *latitude == 90.0 || *latitude == -90.0)
psi = phi;
else
psi = atan ((1 - es0) * tan (phi));
/* Calc x and y axis coordinates with respect to original ellipsoid */
if (*longitude == 90.0 || *longitude == -90.0)
{
x = 0.0;
y = fabs (a0 * b0 / sqrt (b0 * b0 + a0 * a0 * pow (tan (psi), 2.0)));
}
else
{
x = fabs ((a0 * b0) /
sqrt ((1 + pow (tan (lambda), 2.0)) *
(b0 * b0 + a0 * a0 * pow (tan (psi), 2.0))));
y = fabs (x * tan (lambda));
}
if (*longitude < -90.0 || *longitude > 90.0)
x = -x;
if (*longitude < 0.0)
y = -y;
/* Calculate z axis coordinate with respect to the original ellipsoid */
if (*latitude == 90.0)
z = b0;
else if (*latitude == -90.0)
z = -b0;
else
z =
tan (psi) * sqrt ((a0 * a0 * b0 * b0) /
(b0 * b0 + a0 * a0 * pow (tan (psi), 2.0)));
/* Calculate the geocentric latitude with respect to the new ellipsoid */
psi1 = atan ((z - dz) / sqrt ((x - dx) * (x - dx) + (y - dy) * (y - dy)));
/* Convert to geodetic latitude and save return value */
*latitude = atan (tan (psi1) / (1 - es1)) * 180.0 / PI;
/* Calculate the longitude with respect to the new ellipsoid */
*longitude = atan ((y - dy) / (x - dx)) * 180.0 / PI;
/* Correct the resultant for negative x values */
if (x - dx < 0.0)
{
if (y - dy > 0.0)
*longitude = 180.0 + *longitude;
else
*longitude = -180.0 + *longitude;
}
}
/****************************************************************************/
/* Converts Garmin integer format to double precision decimal degrees. */
/****************************************************************************/
double
int2deg (long n)
{
double res;
res = (double) (n / CONVERT);
return (res);
}
/****************************************************************************/
/* Converts double precision decimal degrees to Garmin integer format. */
/****************************************************************************/
long
deg2int (double x)
{
long res;
res = (long) (x * CONVERT);
return (res);
}
gpstrans-0.41/src/gps/sendgpsinfo.c 0000644 0001750 0001750 00000141145 10427450423 014272 0000000 0000000 /****************************************************************************/
/* */
/* ./gps/sendgpsinfo.c - Send data to GPS */
/* */
/* This file is part of gpstrans - a program to communicate with garmin gps */
/* Parts are taken from John F. Waers (jfwaers@csn.net) program MacGPS. */
/* */
/* */
/* Copyright (c) 1995 by Carsten Tschach (tschach@zedat.fu-berlin.de) */
/* */
/* Copyright (c) 1998 by Matthias Kattanek (mattes@ugraf.com) */
/* 980802 sscanf modification %d -> %hd */
/* in sendGPSInfo() send one record too much */
/* */
/* */
/* */
/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, */
/* USA. */
/****************************************************************************/
#include "defs.h"
#include "Garmin.h"
#include "Prefs.h"
#include "protocols.h"
#include
#include
#include
/* define external variables */
extern BYTE gGarminMessage[MAX_LENGTH];
extern struct PREFS gPrefs;
extern char *protocols;
/* define global variables */
static char fileData[MAX_LINE];
static BYTE newTrack;
static int track_count;
static BYTE message[520]; /* allow for many 0x10 bytes which must be doubled */
struct PREFS gFilePrefs;
/* additions for mXmap */
void mxmap_route (char *, int);
char *mystrsep2 (char **stringp, char *delim);
void strconvert (char *);
/* prototype functions */
static short records (FILE *ifile, short type);
static short doWaypoint (short type);
static short doTrack (void);
static short doRoute (void);
static short doAlmanac (void);
static short sendRecords (short);
static void copyNumber (BYTE * p, long n);
static void copyFloat (BYTE * p, double d);
static char *field (char *a, short n);
static void cpystr (BYTE * p, char *q, short n);
static short getFileFormat (char *, char*);
static void cleanupDMS (char *s);
struct
{
int count;
int type;
int name;
int comment;
int date;
int altitude;
int position; /* first column of position data */
} column;
/****************************************************************************/
/* Send "commit-suicide-command" to GPS. */
/****************************************************************************/
long
sendGPSOff ()
{
extern struct PREFS gPrefs;
extern char gMessageStr[];
short err;
/* First check if GPS responds to the "are-you-ready" package */
if (!CheckGPS ())
NotResponding ();
/* open serial device */
if ((err = serialOpen (GARMIN)) != noErr)
{
sprintf (gMessageStr, "The port initialization of %s has failed.",
gPrefs.Device);
Error (gMessageStr);
return 99; /* Currently Error never returns.
Allow for another
implementation? */
}
/* send command - no respond is send from GPS */
sendGPSMessage (off1, 4);
/* close serial device */
serialClose ();
printf ("GPS turned off successfully\n");
return 0;
}
/****************************************************************************/
/* Send multiple line packages to GPS (route, waypoint, track) */
/****************************************************************************/
void
sendGPSInfo (FILE *ifile, short type)
{
extern char gMessageStr[];
short recs, processed = 0;
short err, result = 1;
char *rType;
BYTE *term;
char secondLine[MAX_LINE];
int junk;
char *junk_str;
/* First check it GPS responds to the "are-you-ready" package */
if (!CheckGPS ())
NotResponding ();
junk=getGPSVersion(&junk_str); /* load the "protocols" array */
/* open serial device */
if ((err = serialOpen (GARMIN)) != noErr)
{
sprintf (gMessageStr, "The port initialization of %s has failed.",
gPrefs.Device);
Error (gMessageStr);
return;
}
recs = records (ifile, type);
recs--; /* before vers0.34 sent one record too many*/
/* Continue only if GPS responds to the send-request package */
if (sendRecords (recs) == 0)
{
Error ("GPS did not respond to send-request packet.\n");
return;
}
/* return to beginning of file and read first lines */
rewind (ifile);
GetLine (ifile, fileData, 1);
GetLine (ifile, secondLine, 1); /* some files have two header lines */
rewind (ifile); /* reading header lines again is harmless */
if (!getFileFormat (fileData, secondLine))
{
Error ("The file header format is incorrect.");
return;
}
naks = 0;
InitBarGraph ();
/* process different requests */
switch (type)
{
default:
case ALMANAC:
rType = "almanac";
term = almt;
while (GetLine (ifile, fileData, 0) &&
processed < recs && result)
{
if (fileData[0] == 'A')
{
result = doAlmanac ();
SetBarGraph ((double) (++processed) / (double) recs);
}
}
break;
case ROUTE:
rType = "routes";
term = rtet;
if (file_format != MAYKO)
{
while (GetLine (ifile, fileData, 0) &&
processed < recs && result)
{
if (fileData[0] == 'R')
{
result = doRoute (); /* send route header */
++processed;
}
if (fileData[0] == 'W')
{
result = doWaypoint (ROUTE);
++processed;
}
SetBarGraph ((double) (processed) / (double) recs);
}
break;
}
else
{ // manage Mayko mXmap format
// case MXMAP_ROUTE:
sprintf (fileData, "R\t0\tMAYKO MXMAP\n");
result = doRoute ();
while (GetLine (ifile, fileData, 0) && result)
{
if (*fileData == '\0')
break;
mxmap_route (fileData, processed);
// printf("mxmap-wp %s-\n", fileData );
// printf("%s-\n", fileData );
if (fileData[0] == 'W')
{
result = doWaypoint (ROUTE);
++processed;
}
*fileData = '\0';
SetBarGraph ((double) (processed) / (double) recs);
}
recs = processed;
break;
}
case TRACK:
rType = "track";
term = trkt;
track_count = newTrack = 1;
while (GetLine (ifile, fileData, 0) &&
processed < recs && result)
{
if (fileData[0] == 'T')
{
result = doTrack ();
SetBarGraph ((double) (++processed) / (double) recs);
}
else
{
newTrack = 1;
track_count++;
}
}
break;
case WAYPOINT:
rType = "waypoint";
term = wptt;
while (GetLine (ifile, fileData, 0) &&
(processed < recs) && result)
{
if (fileData[0] == 'W')
{
result = doWaypoint (WAYPOINT);
SetBarGraph ((double) (++processed) / (double) recs);
}
}
break;
}
/* close BarGraph window */
CloseBarGraph ();
/* send terminator message to tell GPS - its over */
if (result)
{
sendGPSMessage (term, 4);
/* get final response but ignore it */
getGPSMessage ();
/* print number of packages transferred */
sprintf (gMessageStr,
"%d %s packets were successfully transferred to the GPS receiver.",
recs-naks, rType);
Message (gMessageStr);
if (naks)
{
sprintf (gMessageStr,
"%d packets were rejected.\n", naks);
Error (gMessageStr);
}
if (verbose && track_count)
printf("%d tracks were transferred.\n", track_count);
}
/* close serial device */
serialClose ();
}
/*
* Take mXmap route records and changes it back into the format
* that gpstrans is using. Not the ideal solution,
* actually pretty nasty hack, but works though.
*/
void
mxmap_route (char *Datastring, int mrec)
{
static char *month[12] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
};
int i;
char *p, *r;
char xname[80];
char xlat[10], xlon[10];
time_t t;
struct tm *ts;
time (&t);
ts = localtime (&t);
sprintf (xname, "MX%02d", mrec + 1); // set dummy name
p = Datastring;
r = mystrsep2 (&p, ",\n");
if (r != NULL)
{
strcpy (xname, r);
strconvert (xname); // convert to upper, strip spaces
}
r = mystrsep2 (&p, ",\n");
strcpy (xlat, r);
r = mystrsep2 (&p, ",\n");
strcpy (xlon, r);
// this is how a gpstrans route record looks like
//printf("W\t123456\t123456789012345678901234527-JUL-98 23:56\t12/31/1989 -8:00:00\t42.3753083\t-71.0194016\n");
sprintf (Datastring, "W\t%s\t", xname);
// this seems not to be necessary to have doRoute() understand the record
// i = strlen( Datastring );
// p = Datastring + i;
// i = 32 - i;
// while ( i-- )
// *p++ = '.';
i = strlen (Datastring);
sprintf (Datastring + i, "%2d-%s-%02d %02d:%02d\t",
ts->tm_mday,
month[ts->tm_mon], ts->tm_year, ts->tm_hour, ts->tm_min);
i = strlen (Datastring);
sprintf (Datastring + i, "12/31/1989 -8:00:00\t%s\t%s\n", xlat, xlon);
}
char *
mystrsep2 (char **stringp, char *delim)
{
char *begin, *end;
begin = *stringp + strspn (*stringp, delim);
end = *stringp + strcspn (*stringp, delim);
if (end == *stringp)
begin = NULL;
if (*end != '\0')
*end++ = '\0';
*stringp = end;
return begin;
}
void
strconvert (char *p)
{
char *dest;
dest = p;
while (*p)
{
if (!isspace (*p))
{
if (islower (*p))
*dest = toupper (*p);
else
*dest = *p;
dest++;
}
p++;
}
*dest = '\0';
}
/****************************************************************************/
/* Waypoint file format: */
/* */
/* */
/* Format: DDD UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W HOME 123 SNOWMASS 07/28/1994 20:12:54 40.1777471 -105.0892654 */
/* 0 1 2 3 4 5 */
/* TYPE NAME COMMENT DATE LATITUDE LONGITUDE */
/* */
/* */
/* Format: DMM UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W HOME 123 SNOWMASS 07/28/1994 20:12:54 40 10.665' -105 05.356' */
/* 0 1 2 3 4 5 */
/* TYPE NAME COMMENT DATE LATITUDE LONGITUDE */
/* */
/* */
/* Format: DMS UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W HOME 123 SNOWMASS 07/28/1994 20:12:54 40 10'39.9" -105 05'21.4" */
/* 0 1 2 3 4 5 */
/* TYPE NAME COMMENT DATE LATITUDE LONGITUDE */
/* */
/* */
/* Format: UTM UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W HOME 123 SNOWMASS 07/28/1994 20:12:54 13 T 0492400 4447279 */
/* 0 1 2 3 4 5 6 7 */
/* TYPE NAME COMMENT DATE ZE ZN EASTING NORTHING */
/* */
/* */
/* Format: BNG UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W EXAMPL BRITISH GRD 07/28/1994 20:12:54 SE 12345 67890 */
/* 0 1 2 3 4 5 6 */
/* TYPE NAME COMMENT DATE ZONE EASTING NORTHING */
/* */
/* */
/* Format: ITM UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W EXAMPL IRISH GRID 07/28/1994 20:12:54 IN 12345 67890 */
/* 0 1 2 3 4 5 6 */
/* TYPE NAME COMMENT DATE ZONE EASTING NORTHING */
/* */
/* */
/* Format: FIN UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W EXAMPL SWISS GRID 07/28/1994 20:12:54 27E 012345 067890 */
/* 0 1 2 3 4 5 6 */
/* TYPE NAME COMMENT DATE ZE EASTING NORTHING */
/* */
/* */
/* Format: SUI UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* W EXAMPL SWISS GRID 07/28/1994 20:12:54 012345 067890 */
/* 0 1 2 3 5 6 */
/* TYPE NAME COMMENT DATE EASTING NORTHING */
/* */
/* */
/* Format: SEG UTC Offset: 1.00 hrs Datum[085]: RT 90 */
/* W EXAMPL SWEDISH GRID 07/28/1994 20:12:54 012345 067890 */
/* 0 1 2 3 4 5 */
/* TYPE NAME COMMENT DATE EASTING NORTHING */
/* */
/* */
/* Format: GKK UTC Offset: 1.00 hrs Datum[102]: Potsdam */
/* W EXAMPL GERMAN GRID 07/28/1994 20:12:54 0123456 0678901 */
/* 0 1 2 3 4 5 */
/* TYPE NAME COMMENT DATE EASTING NORTHING */
/* */
/* */
/****************************************************************************/
/****************************************************************************/
/* Process Waypoint package - return 0 if GPS does not respond. */
/****************************************************************************/
static short
doWaypoint (short type)
{
double x, y;
short zone;
char finzone[5]; /* Currently always 27E, i.e. not used */
char bgzone[5];
char nsZone;
int pos;
char *s;
enum { LAT, LON };
enum { ZE, ZN, EASTING, NORTHING }; /* UTM Grid */
enum { BGZ, BGEAST, BGNORTH }; /* British, Irish Grid */
enum { SEAST, SNORTH }; /* Swiss Grid */
enum { SEGEAST, SEGNORTH }; /* Swedish Grid */
/* same format for German Grid */
struct
{
char type;
char *comment, *name;
long seconds;
double latitude, longitude;
double altitude;
struct {
/* latitude and longitude are always present */
unsigned altitude:1;
unsigned seconds:1;
unsigned name:1;
unsigned comment:1;
} has;
} pkt;
char empty[]="";
pkt.has.altitude =
pkt.has.seconds =
pkt.has.name =
pkt.has.comment = 0;
pkt.altitude = 1.01e24;
pkt.seconds = ~0;
pkt.comment = pkt.name = empty;
if (column.type >= 0)
pkt.type = *field(fileData, column.type);
if (column.date >= 0)
{
char date[20];
strncpy (date, field (fileData, column.date), 19);
date[19] = 0;
pkt.seconds = dt2secs (date, gFilePrefs.offset);
pkt.has.seconds = 1;
}
if ((column.altitude >= 0) &&
(!strstr(field(fileData, column.altitude), "unknown")))
{
pkt.altitude = atof (field (fileData, column.altitude));
pkt.has.altitude = 1;
}
if (column.name >= 0)
{
pkt.name = field(fileData, column.name);
pkt.has.name = 1;
}
if (column.comment >= 0)
{
pkt.comment = field(fileData, column.comment);
pkt.has.comment = 1;
}
pos=column.position;
/* handle various grids */
switch (gFilePrefs.format)
{
case DMS:
cleanupDMS (fileData);
pkt.latitude = DMStoDegrees (field (fileData, pos+LAT));
pkt.longitude = DMStoDegrees (field (fileData, pos+LON));
break;
case DMM:
cleanupDMS (fileData);
pkt.latitude = DMtoDegrees (field (fileData, pos+LAT));
pkt.longitude = DMtoDegrees (field (fileData, pos+LON));
break;
case DDD:
sscanf (field (fileData, pos+LAT), "%lf %lf", &pkt.latitude, &pkt.longitude);
break;
case UTM: /* UTM Grid */
sscanf (field (fileData, pos+ZE), "%hd", &zone);
sscanf (field (fileData, pos+ZN), "%c", &nsZone);
sscanf (field (fileData, pos+EASTING), "%lf %lf", &x, &y);
UTMtoDeg (zone, nsZone <= 'M', x, y, &pkt.latitude, &pkt.longitude);
break;
case KKJ: /* KKJ Grid */
sscanf (field (fileData, pos+ZE), "%s", finzone);
sscanf (field (fileData, pos+EASTING), "%lf %lf", &x, &y);
KKJtoDeg (2, 0, x, y, &pkt.latitude, &pkt.longitude); /* 2 is 27E, not used currently */
break;
case BNG: /* British Grid */
sscanf (field (fileData, pos+BGZ), "%s", bgzone);
sscanf (field (fileData, pos+BGEAST), "%lf %lf", &x, &y);
BNGtoDeg (bgzone, x, y, &pkt.latitude, &pkt.longitude);
break;
case ITM: /* Irish Grid */
sscanf (field (fileData, pos+BGZ), "%s", bgzone);
sscanf (field (fileData, pos+BGEAST), "%lf %lf", &x, &y);
ITMtoDeg (bgzone, x, y, &pkt.latitude, &pkt.longitude);
break;
case SEG: /* Swedish Grid */
sscanf (field (fileData, pos+SEGEAST), "%lf %lf", &x, &y);
SEGtoDeg (x, y, &pkt.latitude, &pkt.longitude);
break;
case GKK: /* German Grid */
sscanf (field (fileData, pos+SEGEAST), "%lf %lf", &x, &y);
GKKtoDeg (x, y, &pkt.latitude, &pkt.longitude);
break;
default:
break;
}
/* translate to selected datum */
translate (0, &pkt.latitude, &pkt.longitude, gFilePrefs.datum);
if (column.name >= 0)
{ /* eliminate trailing tab and spaces
(destructive, so must follow last
use of "field" function */
if ((s = strstr(pkt.name, "\t")))
*s = 0; /* replace tab with null */
s = pkt.name;
s += strlen(s);
if (*s == '\n')
*s = 0; /* replace newline with null */
for ( ; (--s > pkt.name) && (*s == ' '); )
*s = 0; /* eliminate trailing blanks */
}
if (column.comment >= 0)
{ /* eliminate trailing tab and spaces
(destructive, so must follow last
use of "field" function */
if ((s = strstr(pkt.comment, "\t")))
*s = 0; /* replace tab with null */
s = pkt.comment;
s += strlen(s);
if (*s == '\n')
*s = 0; /* replace newline with null */
for ( ; (--s > pkt.comment) && (*s == ' '); )
*s = 0; /* eliminate trailing blanks */
}
if (debugging>1)
{
printf("pkt: name=\"%s\" comment=\"%s\"\n", pkt.name, pkt.comment);
if(pkt.has.seconds) printf("%s", ctime(&pkt.seconds));
printf("latitude=%9.6f longitude=%9.6f altitude=%5.0f\n",
pkt.latitude, pkt.longitude, pkt.altitude);
}
/* now create the appropriate kind of packet for this device */
/* create package header */
if (type == WAYPOINT)
message[0] = Pid_Wpt_Data;
else /* type == ROUTE */
message[0] = Pid_Rte_Wpt_Data;
if (strstr(protocols, "D100"))
{
D100_Wpt_Type *d=(D100_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
/* copy position and time to GPS package */
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
copyNumber ((BYTE *)&d->unused, pkt.seconds);
cpystr ((unsigned char *)&d->ident, pkt.name, 6);
cpystr ((unsigned char *)&d->cmnt, pkt.comment, 40);
}
else if (strstr(protocols, "D101"))
{
D101_Wpt_Type *d=(D101_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
copyNumber ((BYTE *)&d->unused, pkt.seconds);
cpystr ((unsigned char *)&d->ident, pkt.name, 6);
cpystr ((unsigned char *)&d->cmnt, pkt.comment, 40);
}
else if (strstr(protocols, "D102"))
{
D102_Wpt_Type *d=(D102_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
copyNumber ((BYTE *)&d->unused, pkt.seconds);
cpystr ((unsigned char *)&d->ident, pkt.name, 6);
cpystr ((unsigned char *)&d->cmnt, pkt.comment, 40);
}
else if (strstr(protocols, "D103"))
{
D103_Wpt_Type *d=(D103_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
copyNumber ((BYTE *)&d->unused, pkt.seconds);
cpystr ((unsigned char *)&d->ident, pkt.name, 6);
cpystr ((unsigned char *)&d->cmnt, pkt.comment, 40);
}
else if (strstr(protocols, "D104"))
{
D104_Wpt_Type *d=(D104_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
copyNumber ((BYTE *)&d->unused, pkt.seconds);
cpystr ((unsigned char *)&d->ident, pkt.name, 6);
cpystr ((unsigned char *)&d->cmnt, pkt.comment, 40);
}
else if (strstr(protocols, "D105"))
{
D105_Wpt_Type *d=(D105_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
/* no date field */
cpystr ((unsigned char *)&d->ident, pkt.name, 15);
/* no comment field */
}
else if (strstr(protocols, "D106"))
{
D106_Wpt_Type *d=(D106_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
/* no date field */
cpystr ((unsigned char *)&d->ident, pkt.name, 15);
/* no comment field */
}
else if (strstr(protocols, "D107"))
{
D107_Wpt_Type *d=(D107_Wpt_Type *)(message+2);
/* number of message bytes to follow */
message[1] = sizeof(*d);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
copyNumber ((BYTE *)&d->unused, pkt.seconds);
cpystr ((unsigned char *)&d->ident, pkt.name, 6);
cpystr ((unsigned char *)&d->cmnt, pkt.comment, 40);
}
else if (strstr(protocols, "D108"))
{
D108_Wpt_Type *d=(D108_Wpt_Type *)(message+2);
copyFloat ((BYTE *)&d->alt, pkt.altitude);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
/* no date field */
s = (char *)&d->ident;
strcpy (s, pkt.name);
s += strlen(s)+1;
strcpy (s, pkt.comment);
s += strlen(s)+1;
message[1] = s- (char *)d; /* number of message bytes */
}
else if (strstr(protocols, "D109"))
{
D109_Wpt_Type *d=(D109_Wpt_Type *)(message+2);
copyFloat ((BYTE *)&d->alt, pkt.altitude);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
/* no date field */
s = (char *)&d->ident;
strcpy (s, pkt.name);
s += strlen(s)+1;
strcpy (s, pkt.comment);
s += strlen(s)+1;
message[1] = s- (char *)d; /* number of message bytes */
}
else if (strstr(protocols, "D110"))
{
D110_Wpt_Type *d=(D110_Wpt_Type *)(message+2);
copyFloat ((BYTE *)&d->alt, pkt.altitude);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
copyNumber ((BYTE *)&d->time, pkt.seconds);
s = (char *)&d->ident;
strcpy (s, pkt.name);
s += strlen(s)+1;
strcpy (s, pkt.comment);
s += strlen(s)+1;
message[1] = s- (char *)d; /* number of message bytes */
}
/* send package to GPS */
sendGPSMessage (message, message[1]+2);
/* make sure GPS responds */
return getGPSack ();
}
static int
colorNameToCode (char *name, char *protocol)
{
char *color_name[18]={
"black",
"dark red",
"dark green",
"dark yellow",
"dark blue",
"dark magenta",
"dark cyan",
"light gray",
"dark gray",
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
"white",
"transparent",
"default"
};
int i;
for (i=0; i<18; i++)
if (strcasecmp(name, color_name[i]) == 0)
break;
if (i == 18)
i = 0; /* unrecognized color name */
if (i == 17)
{
if ((strcasecmp(protocol,"D108")==0) ||
(strcasecmp(protocol,"D310")==0))
i = 255;
else
i = 0x1f; /* D109 */
}
return i;
}
/****************************************************************************/
/* Track file format: */
/* */
/* */
/* T 08/29/1994 13:32:01 40.146967 -105.125464 13 T 489391 4443614 */
/* 0 1 2 3 4 5 6 7 */
/* TYPE DATE LAT LON ZONE ZN EASTING NORTHING */
/* */
/* */
/* Format: DDD UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* T 09/09/1994 20:03:49 40.1780207 -105.0901666 */
/* 0 1 2 3 */
/* TYPE DATE/TIME LATITUDE LONGITUDE */
/* */
/* */
/* Format: DMM UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* T 09/09/1994 20:03:49 40 10.681' -105 05.410' */
/* 0 1 2 3 */
/* TYPE DATE/TIME LATITUDE LONGITUDE */
/* */
/* */
/* Format: DMS UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* T 09/09/1994 20:03:49 40 10'40.9" -105 05'24.6" */
/* 0 1 2 3 */
/* TYPE DATE/TIME LATITUDE LONGITUDE */
/* */
/* */
/* Format: UTM UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* T 09/09/1994 20:03:49 13 T 0492323 4447310 */
/* 0 1 2 3 4 5 */
/* TYPE DATE/TIME ZE ZN EASTING NORTHING */
/* */
/* */
/* Format: BNG UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* T 09/09/1994 20:03:49 SE 12345 67890 */
/* 0 1 2 3 4 */
/* TYPE DATE/TIME ZONE EASTING NORTHING */
/* */
/* */
/* Format: ITM UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* T 09/09/1994 20:03:49 IN 12345 67890 */
/* 0 1 2 3 4 */
/* TYPE DATE/TIME ZONE EASTING NORTHING */
/* */
/* */
/* Format: SUI UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* T 09/09/1994 20:03:49 012345 067890 */
/* 0 1 3 4 */
/* TYPE DATE/TIME EASTING NORTHING */
/* */
/* Format: SEG UTC Offset: 1.00h Datum[085]: RT90 */
/* T 09/09/1994 20:03:49 012345 067890 */
/* 0 1 2 3 */
/* TYPE DATE/TIME EASTING NORTHING */
/* */
/* */
/* Format: GKK UTC Offset: 1.00 hrs Datum[102]: Potsdam */
/* T 07/28/1994 20:12:54 0123456 0678901 */
/* 0 1 2 3 */
/* TYPE DATE/TIME EASTING NORTHING */
/* */
/* */
/* Note: Even though the date/time is included in the protocol, the GPS 45 */
/* appears to ignore this field. The only track data that is time stamped */
/* is that actually generated by the GPS 45; actual track data uploaded */
/* from the GPS 45 has correct time stamps. */
/* */
/****************************************************************************/
/****************************************************************************/
/* Process Track package - return 0 if GPS does not respond. */
/****************************************************************************/
static short
doTrack ()
{
double latitude, longitude, x, y;
long lat, lon;
short zone;
char nsZone, bgzone[3], finzone[5];
int pos;
enum { LAT, LON };
enum { ZE, ZN, EASTING, NORTHING }; /* UTM Grid */
enum { BGZ, BGEAST, BGNORTH }; /* British, Irish Grid */
enum { SEAST, SNORTH }; /* Swiss Grid */
enum { SEGEAST, SEGNORTH }; /* Swedish Grid */
/* same format for German Grid */
struct
{
char type;
char *comment, *name;
long seconds;
double latitude, longitude;
double altitude;
struct {
/* latitude and longitude are always present */
unsigned altitude:1;
unsigned seconds:1;
unsigned name:1;
unsigned comment:1;
} has;
} pkt;
char empty[]="";
pkt.has.altitude =
pkt.has.seconds =
pkt.has.name =
pkt.has.comment = 0;
pkt.altitude = 1.01e24;
pkt.seconds = ~0;
pkt.comment = pkt.name = empty;
if (column.date >= 0)
{
char date[20];
strncpy (date, field (fileData, column.date), 19);
date[19] = 0;
pkt.seconds = dt2secs (date, gFilePrefs.offset);
pkt.has.seconds = 1;
}
if ((column.altitude >= 0) &&
(!strstr(field(fileData, column.altitude), "unknown")))
{
pkt.altitude = atof (field (fileData, column.altitude));
pkt.has.altitude = 1;
}
pos=column.position;
/* handle various grids */
switch (gFilePrefs.format)
{
case DMS:
cleanupDMS (fileData);
latitude = DMStoDegrees (field (fileData, pos+LAT));
longitude = DMStoDegrees (field (fileData, pos+LON));
break;
case DMM:
cleanupDMS (fileData);
latitude = DMtoDegrees (field (fileData, pos+LAT));
longitude = DMtoDegrees (field (fileData, pos+LON));
break;
case DDD:
sscanf (field (fileData, pos+LAT), "%lf %lf", &latitude, &longitude);
break;
case UTM: /* UTM Grid */
sscanf (field (fileData, pos+ZE), "%hd", &zone);
sscanf (field (fileData, pos+ZN), "%c", &nsZone);
sscanf (field (fileData, pos+EASTING), "%lf %lf", &x, &y);
UTMtoDeg (zone, nsZone <= 'M', x, y, &latitude, &longitude);
break;
case KKJ: /* KKJ Grid */
sscanf (field (fileData, pos+ZE), "%s", finzone);
sscanf (field (fileData, pos+EASTING), "%lf %lf", &x, &y);
KKJtoDeg (2, 0, x, y, &latitude, &longitude); /* 2 is 27E, not used currently */
break;
case BNG: /* British Grid */
sscanf (field (fileData, pos+BGZ), "%s", bgzone);
sscanf (field (fileData, pos+BGEAST), "%lf %lf", &x, &y);
BNGtoDeg (bgzone, x, y, &latitude, &longitude);
break;
case ITM: /* Irish Grid */
sscanf (field (fileData, pos+BGZ), "%s", bgzone);
sscanf (field (fileData, pos+BGEAST), "%lf %lf", &x, &y);
ITMtoDeg (bgzone, x, y, &latitude, &longitude);
break;
case SEG: /* Swedish Grid */
sscanf (field (fileData, pos+SEGEAST), "%lf %lf", &x, &y);
SEGtoDeg (x, y, &latitude, &longitude);
break;
case GKK: /* German Grid */
sscanf (field (fileData, pos+SEGEAST), "%lf %lf", &x, &y);
GKKtoDeg (x, y, &latitude, &longitude);
break;
default:
break;
}
/* translate to selected datum */
translate (0, &latitude, &longitude, gFilePrefs.datum);
pkt.latitude = latitude;
pkt.longitude = longitude;
/* convert numbers to GPS bytes */
lat = deg2int (latitude);
lon = deg2int (longitude);
/* create package header */
message[0] = Pid_Trk_Data;
#ifdef OLD
/* number of message bytes to follow */
message[1] = 13;
/* copy position and time to GPS package */
copyNumber (message + 2, lat);
copyNumber (message + 6, lon);
copyNumber (message + 10, dat);
/* set "new track flag" */
#endif
if (strstr(protocols, "D300"))
{
D300_Trk_Point_Type *d=(D300_Trk_Point_Type *)(message+2);
copyNumber ((BYTE *)&d->time, pkt.seconds);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
d->new_trk = newTrack;
message[1] = sizeof(*d);
}
if (strstr(protocols, "D301"))
{
D301_Trk_Point_Type *d=(D301_Trk_Point_Type *)(message+2);
copyNumber ((BYTE *)&d->time, pkt.seconds);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
if (pkt.has.altitude)
copyFloat ((BYTE *)&d->alt, pkt.altitude);
d->new_trk = newTrack;
message[1] = sizeof(*d);
}
if (strstr(protocols, "D302"))
{
D302_Trk_Point_Type *d=(D302_Trk_Point_Type *)(message+2);
copyNumber ((BYTE *)&d->time, pkt.seconds);
copyNumber ((BYTE *)&d->posn.lat, deg2int (pkt.latitude));
copyNumber ((BYTE *)&d->posn.lon, deg2int (pkt.longitude));
if (pkt.has.altitude)
copyFloat ((BYTE *)&d->alt, pkt.altitude);
d->new_trk = newTrack;
message[1] = sizeof(*d);
}
newTrack = 0;
/* send package to GPS */
sendGPSMessage (message, message[1]+2);
/* make sure GPS responds */
return getGPSMessage ();
}
/****************************************************************************/
/* Route file format: */
/* */
/* */
/* R 1 BOGUS 1 */
/* 0 1 2 */
/* */
/****************************************************************************/
/****************************************************************************/
/* Process Route package - return 0 if GPS does not respond. */
/****************************************************************************/
static short
doRoute ()
{
short route;
/* create package header */
message[0] = '\x1d';
/* number of message bytes to follow */
message[1] = 21;
/* copy route data to GPS package */
sscanf (field (fileData, 1), "%hd", &route);
// route = (short) strtol(field(fileData, 1), (char **)NULL, 10);
message[2] = route;
cpystr (message + 3, field (fileData, 2), 20);
/* send package to GPS */
sendGPSMessage (message, 23);
/* make sure GPS responds */
return getGPSMessage ();
}
/****************************************************************************/
/* Process Almanac package - uploading almanac data is no longer supported. */
/****************************************************************************/
#define ALM_BYTES 42
static short
doAlmanac ()
{
short i;
unsigned short x;
/* Print error message and return */
fprintf (stderr,
"Error: Uploading of almanac data is no longer supported.\n");
return (0);
/* create package header */
message[0] = '\x1f';
/* number of message bytes to follow */
message[1] = ALM_BYTES;
/* copy almanac bytes to GPS package */
for (i = 0; i < ALM_BYTES; i++)
{
sscanf (fileData + 2 + 3 * i, "%02hX", &x);
message[i + 2] = (BYTE) x;
}
/* send package to GPS */
sendGPSMessage (message, ALM_BYTES + 2);
/* make sure GPS respond */
return getGPSMessage ();
}
/****************************************************************************/
/* Return number of records in input-file. */
/****************************************************************************/
static short
records (FILE *ifile, short type)
{
short n = 0;
/* Get line from input file */
GetLine (ifile, fileData, 1);
/* Parse package type until end-of-file */
while (GetLine (ifile, fileData, 0))
{
if (strncasecmp(fileData, "Type", 4))
{
/* process different types */
switch (type)
{
case ALMANAC:
if (fileData[0] == 'A')
++n;
break;
case ROUTE:
if (fileData[0] == 'R' || fileData[0] == 'W')
++n;
break;
case TRACK:
if (fileData[0] == 'T')
++n;
break;
case WAYPOINT:
if (fileData[0] == 'W')
++n;
break;
default:
/* ignore blank lines, comments, etc. */
break;
}
}
}
/* return number of records */
return n;
}
/****************************************************************************/
/* Send a message containing the number of records to follow. Returns a */
/* result code - zero if GPS did not respond. */
/****************************************************************************/
static short
sendRecords (short recs)
{
short result;
/* create package header */
message[0] = '\x1b';
/* number of message bytes to follow */
message[1] = '\x02';
/* convert number of records to GPS bytes */
message[2] = recs % 256; /* LSB of number of records */
message[3] = recs / 256; /* MSB */
/* send package to GPS */
sendGPSMessage (message, 4);
/* make sure GPS responded */
result = getGPSMessage ();
return result;
}
/****************************************************************************/
/* Convert long number to bytes. */
/****************************************************************************/
static void
copyNumber (BYTE * p, long n)
{
*p++ = n & 0xff; /* LSB first */
n >>= 8;
*p++ = n & 0xff;
n >>= 8;
*p++ = n & 0xff;
n >>= 8;
*p = n & 0xff;
}
/****************************************************************************/
/* Convert float number to bytes. */
/****************************************************************************/
static void
copyFloat (BYTE * p, double d)
{
float f = (float)d;
long *lp = (long *) &f;
long n = *lp;
*p++ = n & 0xff; /* LSB first */
n >>= 8;
*p++ = n & 0xff;
n >>= 8;
*p++ = n & 0xff;
n >>= 8;
*p = n & 0xff;
}
/****************************************************************************/
/* returns a pointer to the nth field of a tab-delimited record which */
/* starts at address a. */
/****************************************************************************/
static char *
field (char *str, short n)
{
short i = 0;
char *a = str;
while ((i++) < n)
do
{
if (!*a)
{
char buf[160];
sprintf(buf, "Input line should have at least %d tabs:\n%80s\n",
n-1, str);
Error(buf);
}
} while (*(++a) != '\t');
return (a + 1);
}
/****************************************************************************/
/* Copy a string to GPS bytes. */
/****************************************************************************/
static void
cpystr (BYTE * p, char *q, short n)
{
while ((*q != '\t') && (*q != '\n') && (*q != '\r') && (*q != 0))
{
*p++ = *q++;
--n;
}
while (n-- > 0)
*p++ = ' ';
}
/****************************************************************************/
/* */
/* The following function retrieves the file format info from the first */
/* lines of the data file. This is highly dependent upon the following */
/* format for the first line in the file -- note that there are no */
/* embedded tabs. See the file "getGPSInfo.c" for further information. */
/* */
/* Format: DDD UTC Offset: -6.00 hrs Datum[061]: NAD27 CONUS */
/* ||| |||||| ||| */
/* 0 1 2 3 4 5 6 */
/* 0123456789012345678901234567890123456789012345678901234567890123456789 */
/* */
/****************************************************************************/
/*
for Mayko track:
xmaplog 1.0 Sat Apr 9 15:37:06 2005
1 24.9745041 121.5487808 0.0 0 12/11/1996 17:20:08
1 24.9745792 121.5483677 1.7 0 12/11/1996 17:20:58
for Mayko track type 2, "-m -m". Blank lines mark breaks in the track (GPS was off)
xmaplog 1.0 Wed May 11 13:25:08 2005
1 24.9745041 121.5487808 0.0 0 12/11/1996 17:20:08
1 24.9745792 121.5483677 1.7 0 12/11/1996 17:20:58 x24.9745041 121.5487808 0.0424647 -50- 1.651
for Mayko route:
xmaproute 1.0 Sun May 8 15:31:45 2005
for Mayko waypoints:
unknown xmap format Sun May 8 15:30:53 2005
W 001 67.657959 meters 12/31/1989 -5:00:00 42.9273394 -71.4672483
*/
/****************************************************************************/
/* Get data format from the first two lines of the input file. Return
nonzero on success. */
/****************************************************************************/
static short
getFileFormat (char *first, char *second)
{
extern short nDatums;
char fmt[10];
if (strstr(first, "xmap"))
{ // manage Mayko mXmap format
file_format = MAYKO;
gFilePrefs.format = DDD;
gFilePrefs.offset = 0;
gFilePrefs.datum = 100;
if (verbose)
printf("Input file is in Mayko mXmap format.\n");
}
else
{
sscanf (first, "%7s", fmt);
if (strcmp (fmt, "Format:") != 0)
return 0;
/* Get position format */
sscanf (first + 8, "%3s", fmt);
if (strcmp (fmt, "DMS") == 0)
gFilePrefs.format = DMS;
else if (strcmp (fmt, "DMM") == 0)
gFilePrefs.format = DMM;
else if (strcmp (fmt, "DDD") == 0)
gFilePrefs.format = DDD;
else if (strcmp (fmt, "UTM") == 0)
gFilePrefs.format = UTM;
else if (strcmp (fmt, "BNG") == 0)
gFilePrefs.format = BNG;
else if (strcmp (fmt, "ITM") == 0)
gFilePrefs.format = ITM;
else if (strcmp (fmt, "KKJ") == 0)
gFilePrefs.format = KKJ;
else if (strcmp (fmt, "SEG") == 0)
gFilePrefs.format = SEG;
else if (strcmp (fmt, "GKK") == 0)
gFilePrefs.format = GKK;
else
return 0;
/* Get time offset */
sscanf (first + 25, "%lf", &gFilePrefs.offset);
if (gFilePrefs.offset < -24.0 || gFilePrefs.offset > 24.0)
return 0;
/* Get datum format */
sscanf (first + 43, "%3hd", &gFilePrefs.datum);
/* nDatums - 1 was wrong, as Datums count from 0 to 102, that are 103 Datums,
but nDatums was set to 102 */
if (gFilePrefs.datum < 0 || gFilePrefs.datum > nDatums)
return 0;
if (!*second)
return 0;
{
int i;
char *s;
column.count=0;
/* count the column labels. Labels are separated by tabs. A
tab is optional after the last label. */
for (s=second; *s; s++)
if ((*s == '\t') && s[1])
column.count++;
s=second;
for (i=0; i