diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | NEWS | 17 | ||||
-rw-r--r-- | configure.ac | 21 | ||||
-rw-r--r-- | drivers.c | 5 | ||||
-rw-r--r-- | gpsd.h-tail | 6 | ||||
-rw-r--r-- | libgpsd_core.c | 5 | ||||
-rw-r--r-- | packet.c | 64 | ||||
-rw-r--r-- | packet_states.h | 10 | ||||
-rw-r--r-- | superstar2.c | 526 | ||||
-rw-r--r-- | superstar2.h | 59 |
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 \ @@ -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 \ @@ -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"); @@ -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_ */ |