summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--NEWS17
-rw-r--r--configure.ac21
-rw-r--r--drivers.c5
-rw-r--r--gpsd.h-tail6
-rw-r--r--libgpsd_core.c5
-rw-r--r--packet.c64
-rw-r--r--packet_states.h10
-rw-r--r--superstar2.c526
-rw-r--r--superstar2.h59
10 files changed, 702 insertions, 12 deletions
diff --git a/Makefile.am b/Makefile.am
index f76fed46..196d6d66 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -134,6 +134,7 @@ libgpsd_c_sources = \
dgpsip.c \
ntrip.c \
sirf.c \
+ superstar2.c \
report.c \
isgps.c \
rtcm2.c \
diff --git a/NEWS b/NEWS
index 4e21c040..4bd99548 100644
--- a/NEWS
+++ b/NEWS
@@ -1,15 +1,16 @@
-* Fri Jan 02 2009 Chris Kuethe <ckuethe@mail.berlios.de> - 2.38
- Regression test load for RoyalTek RGM3800 and Blumax GPS-009
- added. Scaling on E error-estimate fields fixed to match O. Listen
- on localhost only by default to avoid security problems; this can be
+* Mon Jan 26 2009 Chris Kuethe <ckuethe@mail.berlios.de> - 2.38
+ Regression test load for RoyalTek RGM3800 and Blumax GPS-009 added.
+ Scaling on E error-estimate fields fixed to match O. Listen on
+ localhost only by default to avoid security problems; this can be
overridden with the -G command-line option. The packet-state machine
can now recognize RTCM3 packets, though support is not yet complete.
Added support for ublox5 and mkt-3301 devices. Add a wrapper around
gpsd_hexdump to save CPU. Lots of little fixes to various packet
- parsers. Always keep the device open: "-n" is not optional any
- more. xgpsspeed no longer depends on Motif. gpsctl can now ship
- arbitrary payloads to a device. It's possible to send binary through the
- control channel with the new & command.
+ parsers. Always keep the device open: "-n" is not optional any more.
+ xgpsspeed no longer depends on Motif. gpsctl can now ship arbitrary
+ payloads to a device. It's possible to send binary through the
+ control channel with the new "&" command. Experimental new driver
+ for Novatel SuperStarII.
* Sun Feb 17 2008 Chris Kuethe <ckuethe@mail.berlios.de> - 2.37
The C++ bindings, Garmin USB support, and multiple instances of ntp
diff --git a/configure.ac b/configure.ac
index 2c358ae2..fddd19dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -201,8 +201,8 @@ if test x"$with_x" != "xno" -a x"$have_x" != "xdisabled"
dnl traditional way) by hand.
AC_CHECK_LIB(Xaw8, XawInitializeWidgetSet, XAW_LIBS="-lXaw8",
AC_CHECK_LIB(Xaw7, XawInitializeWidgetSet, XAW_LIBS="-lXaw7",
- AC_CHECK_LIB(Xaw, XawInitializeWidgetSet, XAW_LIBS="-lXaw",
- ,${X_PRE_LIBS} ${X11_LIBS}),
+ AC_CHECK_LIB(Xaw, XawInitializeWidgetSet, XAW_LIBS="-lXaw",
+ ,${X_PRE_LIBS} ${X11_LIBS}),
${X_PRE_LIBS} ${X11_LIBS}),
${X_PRE_LIBS} ${X11_LIBS})
AC_SUBST(XAW_LIBS)
@@ -298,6 +298,19 @@ else
AC_MSG_RESULT([no])
fi
+dnl check for Novatel SuperStarII support
+AC_ARG_ENABLE(superstar2,
+ AC_HELP_STRING([--enable-superstar2],
+ [enable SuperStarII chipset support]),
+ [ac_superstar2=$enableval], [ac_superstar2=no])
+AC_MSG_CHECKING([for SuperStarII support])
+if test x"$ac_superstar2" = "xyes"; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([SUPERSTAR2_ENABLE], 1, [SuperStarII chipset support])
+else
+ AC_MSG_RESULT([no])
+fi
+
dnl check for Trimble TSIP support
AC_ARG_ENABLE(tsip,
AC_HELP_STRING([--disable-tsip],
@@ -507,7 +520,7 @@ AC_ARG_ENABLE(rtcm104v2,
[disable rtcm104v2 support]),
[ac_rtcm104v2=$enableval], [ac_rtcm104v2=yes])
AC_MSG_CHECKING([for rtcm104v2 support])
-if test x"$ac_earthmate" = "xno" -a x"$ac_evermore" = "xno" -a x"$ac_garmin" = "xno" -a x"$ac_itrax" = "xno" -a x"$ac_sirf" = "xno" -a x"$ac_tsip" = "xno" -a x"$ac_navcom" = "xno"; then
+if test x"$ac_earthmate" = "xno" -a x"$ac_evermore" = "xno" -a x"$ac_garmin" = "xno" -a x"$ac_itrax" = "xno" -a x"$ac_sirf" = "xno" -a x"$ac_superstar2" = "xno" -a x"$ac_tsip" = "xno" -a x"$ac_navcom" = "xno"; then
ac_rtcm104v2=no
fi
if test x"$ac_rtcm104v2" = "xyes"; then
@@ -809,6 +822,7 @@ echo "Navcom : $ac_navcom"
echo "RTCM104V2 : $ac_rtcm104v2"
echo "RTCM104V3 : $ac_rtcm104v3"
echo "SiRF : $ac_sirf"
+echo "SuperStarII : $ac_superstar2"
echo "Trimble TSIP : $ac_tsip"
echo "Tripmate : $ac_tripmate"
echo "True North : $ac_tnt"
@@ -847,6 +861,7 @@ if test "xdummy" = "xdummy" -a \
x"$ac_ntrip" = "xno" -a \
x"$ac_rtcm104v2" = "xno" -a \
x"$ac_sirf" = "xno" -a \
+ x"$ac_superstar2" = "xno" -a \
x"$ac_tnt" = "xno" -a \
x"$ac_oceanserver" = "xno" -a \
x"$ac_tripmate" = "xno" -a \
diff --git a/drivers.c b/drivers.c
index c9d5c845..03025799 100644
--- a/drivers.c
+++ b/drivers.c
@@ -1081,7 +1081,7 @@ static struct gps_type_t mkt3301 = {
extern struct gps_type_t garmin_usb_binary, garmin_ser_binary;
extern struct gps_type_t sirf_binary, tsip_binary;
extern struct gps_type_t evermore_binary, italk_binary;
-extern struct gps_type_t navcom_binary;
+extern struct gps_type_t navcom_binary, superstar2_binary;
/*@ -nullassign @*/
/* the point of this rigamarole is to not have to export a table size */
@@ -1134,6 +1134,9 @@ static struct gps_type_t *gpsd_driver_array[] = {
#ifdef SIRF_ENABLE
&sirf_binary,
#endif /* SIRF_ENABLE */
+#ifdef SUPERSTAR2_ENABLE
+ &superstar2_binary,
+#endif /* SIRF_ENABLE */
#ifdef TSIP_ENABLE
&tsip_binary,
#endif /* TSIP_ENABLE */
diff --git a/gpsd.h-tail b/gpsd.h-tail
index a17da58b..69f2e44e 100644
--- a/gpsd.h-tail
+++ b/gpsd.h-tail
@@ -66,6 +66,7 @@ struct gps_packet_t {
#define RTCM3_PACKET 10
#define UBX_PACKET 11
#define GARMINTXT_PACKET 12
+#define SUPERSTAR2_PACKET 13
unsigned int state;
size_t length;
unsigned char inbuffer[MAX_PACKET_LENGTH*2+1];
@@ -276,6 +277,11 @@ struct gps_device_t {
#endif /* ALLOW_RECONFIGURE */
} sirf;
#endif /* SIRF_ENABLE */
+#ifdef SUPERSTAR2_ENABLE
+ struct {
+ unsigned short gps_week;
+ } superstar2;
+#endif /* SUPERSTAR2_ENABLE */
#ifdef TSIP_ENABLE
struct {
int16_t gps_week; /* Current GPS week number */
diff --git a/libgpsd_core.c b/libgpsd_core.c
index 49df4780..b89bd21d 100644
--- a/libgpsd_core.c
+++ b/libgpsd_core.c
@@ -706,6 +706,11 @@ gps_mask_t gpsd_poll(struct gps_device_t *session)
(void)gpsd_switch_driver(session, "SiRF binary");
break;
#endif /* SIRF_ENABLE */
+#ifdef SUPERSTAR2_ENABLE
+ case SUPERSTAR2_PACKET:
+ (void)gpsd_switch_driver(session, "SuperStarII binary");
+ break;
+#endif /* SUPERSTAR2_ENABLE */
#ifdef TSIP_ENABLE
case TSIP_PACKET:
(void)gpsd_switch_driver(session, "Trimble TSIP");
diff --git a/packet.c b/packet.c
index c1976068..fe93432e 100644
--- a/packet.c
+++ b/packet.c
@@ -31,6 +31,7 @@ others apart and distinguish them from baud barf.
#include <string.h>
#include <errno.h>
#include "gpsd_config.h"
+#include "bits.h"
#include "gpsd.h"
#include "crc24q.h"
@@ -85,10 +86,12 @@ enum {
#include "packet_states.h"
};
+#define SOH 0x01
#define DLE 0x10
#define STX 0x02
#define ETX 0x03
+static unsigned char ctmp;
static void nextstate(struct gps_packet_t *lexer,
unsigned char c)
{
@@ -125,6 +128,12 @@ static void nextstate(struct gps_packet_t *lexer,
break;
}
#endif /* SIRF_ENABLE */
+#ifdef SUPERSTAR2_ENABLE
+ if (c == SOH) {
+ lexer->state = SUPERSTAR2_LEADER;
+ break;
+ }
+#endif /* SUPERSTAR2_ENABLE */
#if defined(TSIP_ENABLE) || defined(EVERMORE_ENABLE) || defined(GARMIN_ENABLE)
if (c == DLE) {
lexer->state = DLE_LEADER;
@@ -469,6 +478,38 @@ static void nextstate(struct gps_packet_t *lexer,
lexer->state = GROUND_STATE;
break;
#endif /* SIRF_ENABLE */
+#ifdef SUPERSTAR2_ENABLE
+ case SUPERSTAR2_LEADER:
+ ctmp = c;
+ lexer->state = SUPERSTAR2_ID1;
+ break;
+ case SUPERSTAR2_ID1:
+ if ((ctmp ^ 0xff) == c)
+ lexer->state = SUPERSTAR2_ID2;
+ else
+ lexer->state = GROUND_STATE;
+ break;
+ case SUPERSTAR2_ID2:
+ lexer->length = c + 4;
+ if (lexer->length <= MAX_PACKET_LENGTH)
+ lexer->state = SUPERSTAR2_PAYLOAD;
+ else
+ lexer->state = GROUND_STATE;
+ break;
+ case SUPERSTAR2_PAYLOAD:
+ if (--lexer->length == 0)
+ lexer->state = SUPERSTAR2_CKSUM1;
+ break;
+ case SUPERSTAR2_CKSUM1:
+ lexer->state = SUPERSTAR2_RECOGNIZED;
+ break;
+ case SUPERSTAR2_RECOGNIZED:
+ if (c == SOH)
+ lexer->state = SUPERSTAR2_LEADER;
+ else
+ lexer->state = GROUND_STATE;
+ break;
+#endif /* SUPERSTAR2_ENABLE */
#if defined(TSIP_ENABLE) || defined(EVERMORE_ENABLE) || defined(GARMIN_ENABLE)
case DLE_LEADER:
#ifdef EVERMORE_ENABLE
@@ -939,6 +980,29 @@ void packet_parse(struct gps_packet_t *lexer)
break;
}
#endif /* SIRF_ENABLE */
+#ifdef SUPERSTAR2_ENABLE
+ else if (lexer->state == SUPERSTAR2_RECOGNIZED) {
+ unsigned short a = 0, b, n;
+ lexer->length = 4 + lexer->inbuffer[3] + 2;
+ for(n = 0; n < lexer->length - 2; n++)
+ a += lexer->inbuffer[n];
+ a = htons(a);
+ b = getbeuw(lexer->inbuffer, lexer->length - 2);
+ gpsd_report(LOG_IO, "SuperStarII pkt dump: type %u len %u: %s\n",
+ lexer->inbuffer[1], (unsigned int)lexer->length,
+ gpsd_hexdump_wrapper(lexer->inbuffer, lexer->length, LOG_RAW));
+ if (a != b) {
+ gpsd_report(LOG_IO, "REJECT SuperStarII packet type 0x%02x"
+ "%zd bad checksum 0x%04x, expecting 0x%04x\n",
+ lexer->inbuffer[1], lexer->length, a, b);
+ lexer->state = GROUND_STATE;
+ } else {
+ packet_accept(lexer, SUPERSTAR2_PACKET);
+ }
+ packet_discard(lexer);
+ break;
+ }
+#endif /* SUPERSTAR2_ENABLE */
#if defined(TSIP_ENABLE) || defined(GARMIN_ENABLE)
else if (lexer->state == TSIP_RECOGNIZED) {
size_t packetlen = lexer->inbufptr - lexer->inbuffer;
diff --git a/packet_states.h b/packet_states.h
index ff65e1ee..c718ef7c 100644
--- a/packet_states.h
+++ b/packet_states.h
@@ -127,6 +127,16 @@
GARMIN_RECOGNIZED, /* found end of Garmin packet */
#endif /* TSIP_ENABLE GARMIN_ENABLE */
+#ifdef SUPERSTAR2_ENABLE
+ SUPERSTAR2_LEADER, /* leading SOH */
+ SUPERSTAR2_ID1, /* message type */
+ SUPERSTAR2_ID2, /* message type xor 0xff */
+ SUPERSTAR2_PAYLOAD, /* length of the actual packet data */
+ SUPERSTAR2_CKSUM1,
+ SUPERSTAR2_CKSUM2,
+ SUPERSTAR2_RECOGNIZED,
+#endif
+
#ifdef RTCM104V2_ENABLE
RTCM2_SYNC_STATE, /* we have sync lock */
RTCM2_SKIP_STATE, /* we have sync lock, but this character is bad */
diff --git a/superstar2.c b/superstar2.c
new file mode 100644
index 00000000..b9d46a90
--- /dev/null
+++ b/superstar2.c
@@ -0,0 +1,526 @@
+/* $Id$ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+
+#include "gpsd_config.h"
+#include "gpsd.h"
+
+#if defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE)
+#include "bits.h"
+#include "superstar2.h"
+
+/*
+ * These routines are specific to this driver
+ */
+
+static gps_mask_t superstar2_parse_input(struct gps_device_t *);
+static gps_mask_t superstar2_dispatch(struct gps_device_t *,
+ unsigned char *, size_t );
+static gps_mask_t superstar2_msg_ack(struct gps_device_t *,
+ unsigned char *, size_t );
+static gps_mask_t superstar2_msg_navsol_lla(struct gps_device_t *,
+ unsigned char *, size_t );
+static gps_mask_t superstar2_msg_navsol_ecef(struct gps_device_t *,
+ unsigned char *, size_t );
+static gps_mask_t superstar2_msg_timing(struct gps_device_t *,
+ unsigned char *, size_t );
+static gps_mask_t superstar2_msg_svinfo(struct gps_device_t *,
+ unsigned char *, size_t );
+
+/*
+ * These methods may be called elsewhere in gpsd
+ */
+static ssize_t superstar2_write(struct gps_device_t *, char *, size_t );
+static void superstar2_probe_wakeup(struct gps_device_t *);
+static void superstar2_configurator(struct gps_device_t *, unsigned int );
+static bool superstar2_set_speed(struct gps_device_t *, speed_t );
+static void superstar2_set_mode(struct gps_device_t *, int );
+static void superstar2_probe_wakeup(struct gps_device_t *);
+static void superstar2_probe_subtype(struct gps_device_t *, unsigned int );
+
+/*
+ * Decode the message ACK message
+ */
+static gps_mask_t
+superstar2_msg_ack(struct gps_device_t *session UNUSED,
+ unsigned char *buf, size_t data_len)
+{
+ if (data_len == 11)
+ gpsd_report(LOG_PROG,
+ "superstar2 #126 - "
+ "ACK 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ buf[5], buf[6], buf[7], buf[8], buf[9]);
+ return ONLINE_SET; /* always returns ONLINE_SET, but avoid runt packets */
+}
+
+/*
+ * Decode the navigation solution message
+ */
+static gps_mask_t
+superstar2_msg_navsol_lla(struct gps_device_t *session,
+ unsigned char *buf, size_t data_len)
+{
+ gps_mask_t mask;
+ unsigned char flags;
+ union int_float i_f;
+ union long_double l_d;
+ double d;
+ struct tm tm;
+
+ if (data_len != 77)
+ return 0;
+
+ gpsd_report(LOG_PROG, "superstar2 #20 - user navigation data\n");
+ mask = ONLINE_SET;
+
+ flags = getub(buf, 72);
+ if ((flags & 0x0f) != 3) /* mode 3 is navigation */
+ return mask;
+
+ /* extract time data */
+ bzero(&tm, sizeof(tm));
+ tm.tm_hour = getub(buf, 4) & 0x1f;
+ tm.tm_min = getub(buf, 5);
+ d = getled(buf, 6);
+ tm.tm_sec = (int)d;
+ tm.tm_mday = getub(buf, 14);
+ tm.tm_mon = getub(buf, 15) - 1;
+ tm.tm_year = getleuw(buf, 16) - 1900;
+ session->gpsdata.fix.time = session->gpsdata.sentence_time =
+ timegm(&tm) + (d - tm.tm_sec);
+ mask |= TIME_SET;
+
+ /* extract the local tangential plane (ENU) solution */
+ session->gpsdata.fix.latitude = getled(buf,18) * RAD_2_DEG;
+ session->gpsdata.fix.longitude = getled(buf,26) * RAD_2_DEG;
+ session->gpsdata.fix.altitude = getlef(buf,34);
+ session->gpsdata.fix.speed = getlef(buf,38);
+ session->gpsdata.fix.track = getlef(buf,42) * RAD_2_DEG;
+ session->gpsdata.fix.climb = getlef(buf,54);
+ mask |= LATLON_SET | ALTITUDE_SET | SPEED_SET | TRACK_SET | CLIMB_SET ;
+
+ session->gpsdata.satellites_used = getub(buf,71) & 0x0f;
+ session->gpsdata.hdop = getleuw(buf,66) * 0.1;
+ session->gpsdata.vdop = getleuw(buf,68) * 0.1;
+ /* other DOP if available */
+ mask |= HDOP_SET | VDOP_SET | USED_SET;
+
+ flags = getub(buf,70);
+ switch (flags & 0x1f) {
+ case 2:
+ session->gpsdata.fix.mode = MODE_3D;
+ session->gpsdata.status = STATUS_FIX;
+ break;
+ case 4:
+ session->gpsdata.fix.mode = MODE_3D;
+ session->gpsdata.status = STATUS_DGPS_FIX;
+ break;
+ case 5:
+ session->gpsdata.fix.mode = MODE_2D;
+ session->gpsdata.status = STATUS_DGPS_FIX;
+ break;
+ case 3:
+ case 6:
+ session->gpsdata.fix.mode = MODE_2D;
+ session->gpsdata.status = STATUS_FIX;
+ break;
+ default:
+ session->gpsdata.status = STATUS_NO_FIX;
+ session->gpsdata.fix.mode = MODE_NO_FIX;
+ }
+
+ /* CYCLE_START_SET if this message starts a reporting period */
+ mask |= MODE_SET | STATUS_SET | CYCLE_START_SET ;
+
+ return mask;
+}
+
+static gps_mask_t
+superstar2_msg_navsol_ecef(struct gps_device_t *session,
+ unsigned char *buf, size_t data_len)
+{
+ gps_mask_t mask;
+ unsigned char flags;
+ union int_float i_f;
+ union long_double l_d;
+ double tm, tow;
+
+ if (data_len != 85)
+ return 0;
+
+ gpsd_report(LOG_PROG, "superstar2 #21 - ecef navigation data\n");
+ mask = ONLINE_SET;
+
+ flags = getub(buf, 79) & 0x1f;
+ if ((flags < 2) || (flags > 5))
+ return mask;
+
+ /* extract time data */
+ tow = getled(buf, 4);
+ session->driver.superstar2.gps_week = getleuw(buf, 12);
+ tm = gpstime_to_unix((int)session->driver.superstar2.gps_week, tow) -
+ session->context->leap_seconds;
+ session->gpsdata.fix.time = session->gpsdata.sentence_time = tm;
+ mask |= TIME_SET;
+
+ /* extract the earth-centered, earth-fixed (ECEF) solution */
+ ecef_to_wgs84fix(&session->gpsdata,
+ getled(buf, 14), getled(buf, 22), getled(buf, 30),
+ getlef(buf, 38), getlef(buf, 42), getlef(buf, 46));
+ mask |= LATLON_SET | ALTITUDE_SET | SPEED_SET | TRACK_SET | CLIMB_SET ;
+
+ session->gpsdata.satellites_used = getub(buf, 79) & 0x0f;
+ session->gpsdata.hdop = getleuw(buf, 74) * 0.1;
+ session->gpsdata.vdop = getleuw(buf, 76) * 0.1;
+ /* other DOP if available */
+ mask |= HDOP_SET | VDOP_SET | USED_SET;
+
+ flags = getub(buf,70);
+ switch (flags & 0x1f) {
+ case 2:
+ session->gpsdata.fix.mode = MODE_3D;
+ session->gpsdata.status = STATUS_FIX;
+ break;
+ case 4:
+ session->gpsdata.fix.mode = MODE_3D;
+ session->gpsdata.status = STATUS_DGPS_FIX;
+ break;
+ case 5:
+ session->gpsdata.fix.mode = MODE_2D;
+ session->gpsdata.status = STATUS_DGPS_FIX;
+ break;
+ case 3:
+ case 6:
+ session->gpsdata.fix.mode = MODE_2D;
+ session->gpsdata.status = STATUS_FIX;
+ break;
+ default:
+ session->gpsdata.status = STATUS_NO_FIX;
+ session->gpsdata.fix.mode = MODE_NO_FIX;
+ }
+
+ /* CYCLE_START_SET if this message starts a reporting period */
+ mask |= MODE_SET | STATUS_SET | CYCLE_START_SET;
+
+ return mask;
+}
+
+/**
+ * GPS Satellite Info
+ */
+static gps_mask_t
+superstar2_msg_svinfo(struct gps_device_t *session,
+ unsigned char *buf, size_t data_len)
+{
+ unsigned char i, st, nchan, nsv;
+
+ if (data_len != 67)
+ return 0;
+
+ gpsd_report(LOG_PROG, "superstar2 #33 - satellite data");
+
+ nchan = 12;
+ gpsd_zero_satellites(&session->gpsdata);
+ nsv = 0; /* number of actually used satellites */
+ for (i = st = 0; i < nchan; i++) {
+ /* get info for one channel/satellite */
+ int off = i*5 + 5;
+ int porn;
+ if ((porn = getub(buf, off) & 0x1f) == 0)
+ porn = (getub(buf, off+3) >> 1) + 87;
+
+ session->gpsdata.PRN[i] = porn;
+ session->gpsdata.ss[i] = getub(buf, off+4);
+ session->gpsdata.elevation[i] = getsb(buf, off+1);
+ session->gpsdata.azimuth[i] = (unsigned short)getub(buf, off+2) + ((unsigned short)(getub(buf, off+3) & 0x1) << 1);
+
+ if ((getub(buf, off) & 0x60) == 0x60)
+ session->gpsdata.used[nsv++] = session->gpsdata.PRN[i];
+
+ if(session->gpsdata.PRN[i])
+ st++;
+ }
+ session->gpsdata.satellites_used = nsv;
+ session->gpsdata.satellites = st;
+ return SATELLITE_SET | USED_SET | ONLINE_SET;
+}
+
+static gps_mask_t
+superstar2_msg_version(struct gps_device_t *session,
+ unsigned char *buf, size_t data_len)
+{
+#define SZ 16
+ char main_sw[SZ], hw_part[SZ], boot_sw[SZ], ser_num[SZ];
+
+ /* byte 98 is device type, value = 3 means superstar2 */
+ if ((data_len != 101) || ((getub(buf,98) & 0x0f) != 3))
+ return 0;
+
+ snprintf(main_sw, 15, "%s", buf+4);
+ snprintf(hw_part, 15, "%s", buf+18);
+ snprintf(boot_sw, 15, "%s", buf+36);
+ snprintf(ser_num, 14, "%s", buf+73);
+
+ gpsd_report(LOG_PROG,
+ "superstar2 #45 - "
+ "hw part %s boot sw %s main sw %s ser num %s\n",
+ hw_part, boot_sw, main_sw, ser_num);
+ strlcpy(session->subtype, main_sw, sizeof(session->subtype));
+ return DEVICEID_SET | ONLINE_SET;
+}
+
+/**
+ * GPS Leap Seconds
+ */
+static gps_mask_t
+superstar2_msg_timing(struct gps_device_t *session, unsigned char *buf, size_t data_len)
+{
+ union long_double l_d;
+ double d;
+ struct tm tm;
+
+ if (data_len != 65)
+ return 0;
+
+ gpsd_report(LOG_PROG, "superstar2 #113 - timing status\n");
+ if ((getub(buf, 55) & 0x30) != 0)
+ return ONLINE_SET;
+
+ /* extract time data */
+ bzero(&tm, sizeof(tm));
+ tm.tm_mday = getsb(buf, 37);
+ tm.tm_mon = getsb(buf, 38) - 1;
+ tm.tm_year = getlesw(buf, 39) - 1900;
+
+ tm.tm_hour = getsb(buf, 41);
+ tm.tm_min = getsb(buf, 42);
+ d = getled(buf, 43);
+ tm.tm_sec = (int)d;
+ session->gpsdata.sentence_time = session->gpsdata.fix.time = timegm(&tm);
+ session->context->leap_seconds = getsb(buf,20);
+
+ return TIME_SET | ONLINE_SET;
+}
+
+
+/**
+ * Write data to the device, doing any required padding or checksumming
+ */
+static ssize_t
+superstar2_write(struct gps_device_t *session, char *msg, size_t msglen)
+{
+ unsigned short c = 0;
+ size_t i;
+
+ for (i = 0; i < msglen - 2; i++)
+ c += (unsigned char)msg[i];
+// c = htons(c); // XXX is this needed on big-endian machines?
+ memcpy(msg + msg[3] + 4, &c, 2);
+ gpsd_report(LOG_IO, "writing superstar2 control type %02x len %zu:%s\n",
+ (unsigned char)msg[1], msglen,
+ gpsd_hexdump_wrapper(msg, msglen, LOG_IO));
+ return gpsd_write(session, msg, msglen);
+}
+
+/**
+ * Parse the data from the device
+ */
+gps_mask_t
+superstar2_dispatch(struct gps_device_t *session, unsigned char *buf,
+ size_t len)
+{
+ int type;
+
+ if (len == 0)
+ return 0;
+
+ type = buf[SUPERSTAR2_TYPE_OFFSET];
+ (void)snprintf(session->gpsdata.tag,
+ sizeof(session->gpsdata.tag), "SS2-%u", (int)type);
+
+ switch (type)
+ {
+ case SUPERSTAR2_ACK: /* Message Acknowledgement */
+ return superstar2_msg_ack(session, buf, len);
+ case SUPERSTAR2_SVINFO: /* Satellite Visibility Data */
+ return superstar2_msg_svinfo(session, buf, len);
+ case SUPERSTAR2_NAVSOL_LLA: /* Navigation Data */
+ return superstar2_msg_navsol_lla(session, buf, len);
+ case SUPERSTAR2_NAVSOL_ECEF: /* Navigation Data */
+ return superstar2_msg_navsol_ecef(session, buf, len);
+ case SUPERSTAR2_VERSION: /* Hardware/Software Version */
+ return superstar2_msg_version(session, buf, len);
+ case SUPERSTAR2_TIMING: /* Timing Parameters */
+ return superstar2_msg_timing(session, buf, len);
+
+ default:
+ /* XXX This gets noisy in a hurry. */
+ gpsd_report(LOG_WARN,
+ "unknown superstar2 packet id 0x%02x length %zd: %s\n",
+ type, len, gpsd_hexdump_wrapper(buf, len, LOG_WARN));
+ return 0;
+ }
+}
+
+/**********************************************************
+ *
+ * Externally called routines below here
+ *
+ **********************************************************/
+/* canned config messages */
+/* Initiate Link ID# 63 */
+static unsigned char link_msg[] = {0x01, 0x3f, 0xc0, 0x08,
+ 0x55, 0x47, 0x50, 0x53, 0x2d, 0x30, 0x30, 0x30,
+ 0x00, 0x00};
+
+/* Request Hardware/Software Identification ID# 45 */
+static unsigned char version_msg[] = {0x01, 0x2d, 0xd2, 0x00, 0x00, 0x01};
+
+static void
+superstar2_probe_wakeup(struct gps_device_t *session)
+{
+ superstar2_write(session, link_msg, sizeof(link_msg));
+ usleep(300000);
+ superstar2_write(session, version_msg, sizeof(version_msg));
+ return;
+}
+
+static void
+superstar2_probe_subtype(struct gps_device_t *session,
+ unsigned int seq)
+{
+ if (seq == 0){
+ superstar2_write(session, link_msg, sizeof(link_msg));
+ usleep(300000);
+ superstar2_write(session, version_msg, sizeof(version_msg));
+ }
+ return;
+}
+
+static void superstar2_configurator(struct gps_device_t *session,
+ unsigned int seq UNUSED)
+{
+ unsigned char a;
+ unsigned char message_list[] = {
+ SUPERSTAR2_NAVSOL_LLA,
+ SUPERSTAR2_SVINFO,
+ SUPERSTAR2_TIMING,
+ SUPERSTAR2_NAVSOL_ECEF,
+ SUPERSTAR2_DUMMY};
+ unsigned char message2_list[] = {
+ SUPERSTAR2_MEASUREMENT,
+ SUPERSTAR2_DUMMY};
+ unsigned char tmpl_msg[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned char tmpl2_msg[] = { 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
+
+ for(a = 0; message_list[a] != 0; a++){
+ /* set high bit to enable continuous output */
+ tmpl_msg[1] = (unsigned char)(message_list[a] | 0x80);
+ tmpl_msg[2] = (unsigned char)(tmpl_msg[1] ^ 0xff);
+ superstar2_write(session, tmpl_msg, sizeof(tmpl_msg));
+ usleep(20000);
+ }
+ for(a = 0; message2_list[a] != 0; a++){
+ /* set high bit to enable continuous output */
+ tmpl2_msg[1] = (unsigned char)(message2_list[a] | 0x80);
+ tmpl2_msg[2] = (unsigned char)(tmpl2_msg[1] ^ 0xff);
+ superstar2_write(session, tmpl2_msg, sizeof(tmpl2_msg));
+ usleep(20000);
+ }
+ superstar2_write(session, version_msg, sizeof(version_msg));
+}
+
+/*
+ * This is the entry point to the driver. When the packet sniffer recognizes
+ * a packet for this driver, it calls this method which passes the packet to
+ * the binary processor or the nmea processor, depending on the session type.
+ */
+static gps_mask_t superstar2_parse_input(struct gps_device_t *session)
+{
+ gps_mask_t st;
+
+ if (session->packet.type == SUPERSTAR2_PACKET){
+ st = superstar2_dispatch(session, session->packet.outbuffer,
+ session->packet.length);
+ session->gpsdata.driver_mode = 1;
+ return st;
+#ifdef NMEA_ENABLE
+ } else if (session->packet.type == NMEA_PACKET) {
+ st = nmea_parse((char *)session->packet.outbuffer, session);
+ session->gpsdata.driver_mode = 0;
+ return st;
+#endif /* NMEA_ENABLE */
+ } else
+ return 0;
+}
+
+static bool superstar2_set_speed(struct gps_device_t *session, speed_t speed)
+{
+ /* set port operating mode, speed, bits etc. here */
+ return 0;
+}
+
+/*
+ * Switch between NMEA and binary mode, if supported
+ */
+static void superstar2_set_mode(struct gps_device_t *session, int mode)
+{
+ if (mode == MODE_NMEA) {
+ // superstar2_to_nmea(session->gpsdata.gps_fd,session->gpsdata.baudrate); /* send the mode switch control string */
+ session->gpsdata.driver_mode = 0; /* NMEA */
+ (void)gpsd_switch_driver(session, "Generic NMEA");
+ } else {
+ session->back_to_nmea = false;
+ session->gpsdata.driver_mode = 1; /* binary */
+ }
+}
+struct gps_type_t superstar2_binary = {
+ /* Full name of type */
+ .type_name = "SuperStarII binary",
+ /* Response string that identifies device (not active) */
+ .trigger = NULL,
+ /* Number of satellite channels supported by the device */
+ .channels = 12,
+ /* Control string sender - should provide checksum and trailer */
+ .control_send = superstar2_write,
+ /* Startup-time device detector */
+ .probe_detect = NULL,
+ /* Wakeup to be done before each baud hunt */
+ .probe_wakeup = superstar2_probe_wakeup,
+ /* Initialize the device and get subtype */
+ .probe_subtype = superstar2_probe_subtype,
+#ifdef ALLOW_RECONFIGURE
+ /* Enable what reports we need */
+ .configurator = superstar2_configurator,
+#endif /* ALLOW_RECONFIGURE */
+ /* Packet getter (using default routine) */
+ .get_packet = generic_get,
+ /* Parse message packets */
+ .parse_packet = superstar2_parse_input,
+ /* RTCM handler (using default routine) */
+ .rtcm_writer = pass_rtcm,
+ /* Speed (baudrate) switch */
+ .speed_switcher = superstar2_set_speed,
+ /* Switch to NMEA mode */
+ .mode_switcher = superstar2_set_mode,
+ /* Message delivery rate switcher (not active) */
+ .rate_switcher = NULL,
+ /* Number of chars per report cycle (not active) */
+ .cycle_chars = -1,
+#ifdef ALLOW_RECONFIGURE
+ /* Undo the actions of .configurator */
+ .revert = NULL,
+#endif /* ALLOW_RECONFIGURE */
+ /* Puts device back to original settings */
+ .wrapup = NULL,
+ /* Number of updates per second */
+ .cycle = 1
+};
+#endif /* defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE) */
diff --git a/superstar2.h b/superstar2.h
new file mode 100644
index 00000000..8b1529ca
--- /dev/null
+++ b/superstar2.h
@@ -0,0 +1,59 @@
+/* $Id$ */
+#ifndef _GPSD_SUPERSTAR2_H_
+#define _GPSD_SUPERSTAR2_H_
+
+#define SUPERSTAR2_BASE_SIZE 4
+#define SUPERSTAR2_TYPE_OFFSET 1
+
+/* input-only */
+#define SUPERSTAR2_RESET 2
+#define SUPERSTAR2_LINKUP 63
+#define SUPERSTAR2_CHANNEL_INHIBIT 64
+#define SUPERSTAR2_TIME_PARAMS 69
+#define SUPERSTAR2_ALMANAC_INCREMENT 77
+#define SUPERSTAR2_ALMANAC_UPLOAD 79
+#define SUPERSTAR2_SET_OPMODE 80
+#define SUPERSTAR2_SET_MASK 81
+#define SUPERSTAR2_SET_DGPS 83
+#define SUPERSTAR2_SET_IONOMODEL 84
+#define SUPERSTAR2_SET_MSLMODEL 86
+#define SUPERSTAR2_SET_HEIGHT_MODE 87
+#define SUPERSTAR2_SET_DATUM 88
+#define SUPERSTAR2_SATELLITE_INHIBIT 90
+#define SUPERSTAR2_BASE_CONFIG 91
+#define SUPERSTAR2_SATELLITE_TRACK 95
+#define SUPERSTAR2_NVM_ERASE 99
+#define SUPERSTAR2_SET_TIME 103
+#define SUPERSTAR2_MESSAGE_CONFIG 105
+#define SUPERSTAR2_SERIAL_CONFIG 110
+
+/* output-only */
+#define SUPERSTAR2_CHANINF2 7
+#define SUPERSTAR2_LINKERR 125
+#define SUPERSTAR2_ACK 126
+
+/* bidirectional */
+#define SUPERSTAR2_DUMMY 0
+#define SUPERSTAR2_CHANINF 6
+#define SUPERSTAR2_NAVSOL_LLA 20
+#define SUPERSTAR2_NAVSOL_ECEF 21
+#define SUPERSTAR2_EPHEMERIS 22
+#define SUPERSTAR2_MEASUREMENT 23
+#define SUPERSTAR2_RECV_CONFIG 30
+#define SUPERSTAR2_SVINFO 33
+#define SUPERSTAR2_DGPSCONFIG 43
+#define SUPERSTAR2_VERSION 45
+#define SUPERSTAR2_BASE_STATUS 47
+#define SUPERSTAR2_DGPS_STATUS 48
+#define SUPERSTAR2_RECV_STATUS 49
+#define SUPERSTAR2_SAT_HEALTH 50
+#define SUPERSTAR2_SELFTEST 51
+#define SUPERSTAR2_RTCM_DATA 65
+#define SUPERSTAR2_SBAS_DATA 67
+#define SUPERSTAR2_SBAS_STATUS 68
+#define SUPERSTAR2_IONO_UTC 75
+#define SUPERSTAR2_ALMANAC_DATA 76
+#define SUPERSTAR2_ALMANAC_STATUS 78
+#define SUPERSTAR2_TIMING 113
+
+#endif /* _GPSD_SUPERSTAR2_H_ */