summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Kuethe <chris.kuethe@gmail.com>2009-01-26 19:12:34 +0000
committerChris Kuethe <chris.kuethe@gmail.com>2009-01-26 19:12:34 +0000
commite7cb7b8215724420420929bdb66f0d45b8b41387 (patch)
tree011fabfdec436e379a036ca692160905d2732abc
parent1553411a7ab0ed044cb4e1d2349684b7559cf549 (diff)
downloadgpsd-e7cb7b8215724420420929bdb66f0d45b8b41387.tar.gz
driver for novatel superstar2.
not enabled by default yet; i still need to get mode switching working. kinda funny - i bought the superstar last july, and it's taken me nearly six months to even take it out of the antistatic bag. at least the driver isn't vaporware any more (and the only copy of it isn't on my laptop).
-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_ */