summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--driver_rtcm2.c156
-rw-r--r--gpsd.xml121
-rw-r--r--gpsd_json.c17
-rw-r--r--rtcm2_json.c22
-rw-r--r--test/daemon/naujoks-ntrip.log.chk10
5 files changed, 295 insertions, 31 deletions
diff --git a/driver_rtcm2.c b/driver_rtcm2.c
index d272e7c0..af68c549 100644
--- a/driver_rtcm2.c
+++ b/driver_rtcm2.c
@@ -94,6 +94,10 @@ BSD terms apply: see the file COPYING in the distribution root for details.
#pragma pack(1)
+/*
+ * Reminder: Emacs reverse-region is useful...
+ */
+
#ifndef WORDS_BIGENDIAN /* little-endian, like x86 */
struct rtcm2_msg_t {
@@ -320,6 +324,58 @@ struct rtcm2_msg_t {
} txt[RTCM2_WORDS_MAX-2];
} type16;
+ /* msg 31 - differential GLONASS corrections */
+ struct rtcm2_msg31 {
+ struct glonass_correction_t {
+ struct { /* msg 1 word 3 */
+ uint parity:6;
+ int prc1:16;
+ uint satident1:5; /* satellite ID */
+ uint udre1:2;
+ uint scale1:1;
+ uint _pad:2;
+ } w3;
+
+ struct { /* msg 1 word 4 */
+ uint parity:6;
+ uint satident2:5; /* satellite ID */
+ uint udre2:2;
+ uint scale2:1;
+ uint tod1:7;
+ uint change1:1;
+ int rrc1:8;
+ uint _pad:2;
+ } w4;
+
+ struct { /* msg 1 word 5 */
+ uint parity:6;
+ int rrc2:8;
+ int prc2:16;
+ uint _pad:2;
+ } w5;
+
+ struct { /* msg 1 word 6 */
+ uint parity:6;
+ int prc3_h:8;
+ uint satident3:5; /* satellite ID */
+ uint udre3:2;
+ uint scale3:1;
+ uint tod2:7;
+ uint change2:1;
+ uint _pad:2;
+ } w6;
+
+ struct { /* msg 1 word 7 */
+ uint parity:6;
+ uint tod3:7;
+ uint change3:1;
+ int rrc3:8;
+ uint prc3_l:8; /* NOTE: uint for low byte */
+ uint _pad:2;
+ } w7;
+ } corrections[(RTCM2_WORDS_MAX - 2) / 5];
+ } type31;
+
/* unknown message */
isgps30bits_t rtcm2_msgunk[RTCM2_WORDS_MAX-2];
} msg_type;
@@ -548,6 +604,58 @@ struct rtcm2_msg_t {
} txt[RTCM2_WORDS_MAX-2];
} type16;
+ /* msg 31 - differential GLONASS corrections */
+ struct rtcm2_msg31 {
+ struct glonass_correction_t {
+ struct { /* msg 1 word 3 */
+ uint _pad:2;
+ uint scale1:1;
+ uint udre1:2;
+ uint satident1:5; /* satellite ID */
+ int prc1:16;
+ uint parity:6;
+ } w3;
+
+ struct { /* msg 1 word 4 */
+ uint _pad:2;
+ int rrc1:8;
+ uint change1:1;
+ uint tod1:7;
+ uint scale2:1;
+ uint udre2:2;
+ uint satident2:5; /* satellite ID */
+ uint parity:6;
+ } w4;
+
+ struct { /* msg 1 word 5 */
+ uint _pad:2;
+ int prc2:16;
+ int rrc2:8;
+ uint parity:6;
+ } w5;
+
+ struct { /* msg 1 word 6 */
+ uint _pad:2;
+ uint change2:1;
+ uint tod2:7;
+ uint scale3:1;
+ uint udre3:2;
+ uint satident3:5; /* satellite ID */
+ int prc3_h:8;
+ uint parity:6;
+ } w6;
+
+ struct { /* msg 1 word 7 */
+ uint _pad:2;
+ uint prc3_l:8; /* NOTE: uint for low byte */
+ int rrc3:8;
+ uint change3:1;
+ uint tod3:7;
+ uint parity:6;
+ } w7;
+ } corrections[(RTCM2_WORDS_MAX - 2) / 5];
+ } type31;
+
/* unknown message */
isgps30bits_t rtcm2_msgunk[RTCM2_WORDS_MAX-2];
} msg_type;
@@ -743,6 +851,54 @@ void rtcm2_unpack( /*@out@*/ struct rtcm2_t *tp, char *buf)
tp->message[n++] = '\0';
break;
+ case 31:
+ {
+ struct glonass_correction_t *m = &msg->msg_type.type31.corrections[0];
+
+ while (len >= 0) {
+ if (len >= 2) {
+ tp->glonass_ranges.sat[n].ident = m->w3.satident1;
+ tp->glonass_ranges.sat[n].udre = m->w3.udre1;
+ tp->glonass_ranges.sat[n].change = m->w4.change1;
+ tp->glonass_ranges.sat[n].tod = m->w4.tod1;
+ tp->glonass_ranges.sat[n].prc = m->w3.prc1 *
+ (m->w3.scale1 ? PRCLARGE : PRCSMALL);
+ tp->glonass_ranges.sat[n].rrc = m->w4.rrc1 *
+ (m->w3.scale1 ? RRLARGE : RRSMALL);
+ n++;
+ }
+ if (len >= 4) {
+ tp->glonass_ranges.sat[n].ident = m->w4.satident2;
+ tp->glonass_ranges.sat[n].udre = m->w4.udre2;
+ tp->glonass_ranges.sat[n].change = m->w6.change2;
+ tp->glonass_ranges.sat[n].tod = m->w6.tod2;
+ tp->glonass_ranges.sat[n].prc = m->w5.prc2 *
+ (m->w4.scale2 ? PRCLARGE : PRCSMALL);
+ tp->glonass_ranges.sat[n].rrc = m->w5.rrc2 *
+ (m->w4.scale2 ? RRLARGE : RRSMALL);
+ n++;
+ }
+ if (len >= 5) {
+ tp->glonass_ranges.sat[n].ident = m->w6.satident3;
+ tp->glonass_ranges.sat[n].udre = m->w6.udre3;
+ tp->glonass_ranges.sat[n].change = m->w7.change3;
+ tp->glonass_ranges.sat[n].tod = m->w7.tod3;
+ /*@ -shiftimplementation @*/
+ tp->glonass_ranges.sat[n].prc =
+ ((m->w6.prc3_h << 8) | (m->w7.prc3_l)) *
+ (m->w6.scale3 ? PRCLARGE : PRCSMALL);
+ tp->glonass_ranges.sat[n].rrc =
+ m->w7.rrc3 * (m->w6.scale3 ? RRLARGE : RRSMALL);
+ /*@ +shiftimplementation @*/
+ n++;
+ }
+ len -= 5;
+ m++;
+ }
+ tp->glonass_ranges.nentries = n;
+ }
+ break;
+
default:
memcpy(tp->words, msg->msg_type.rtcm2_msgunk,
(RTCM2_WORDS_MAX - 2) * sizeof(isgps30bits_t));
diff --git a/gpsd.xml b/gpsd.xml
index b280ef94..2ff33229 100644
--- a/gpsd.xml
+++ b/gpsd.xml
@@ -1775,7 +1775,7 @@ field containing the pathname of the originating device.</para>
<varlistentry>
<term>1</term>
<listitem><para>full corrections - one message containing corrections for
-all satellites in view. This is not common.</para></listitem>
+all GPS satellites in view. This is not common.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1809,7 +1809,7 @@ satellites the beacon can see.</para></listitem>
<varlistentry>
<term>9</term>
<listitem><para>subset corrections &mdash; a message containing corrections
-for only a subset of the satellites in view.</para></listitem>
+for only a subset of the GPS satellites in view.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1817,6 +1817,15 @@ for only a subset of the satellites in view.</para></listitem>
<listitem><para>special message &mdash; a text message from the beacon
operator.</para></listitem>
</varlistentry>
+
+<varlistentry>
+<term>31</term>
+<listitem><para>GLONASS subset corrections &mdash; a message
+containing corrections for a set of the GLONASS satellites in
+view.</para></listitem>
+</varlistentry>
+
+
</variablelist>
</refsect3>
@@ -2072,6 +2081,42 @@ for each satellite.</para>
</table>
</refsect3>
+<refsect3><title>Type 6: Null</title>
+
+<para>This just indicates a null message. There are no payload fields.</para>
+</refsect3>
+
+<refsect3><title>Unknown message</title>
+
+<para>This format is used to dump message words in hexadecimal when the
+message type field doesn't match any of the known ones.</para>
+
+<para>Here is the format:</para>
+
+<table frame="all" pgwide="0"><title>Unknown Message</title>
+<tgroup cols="3" align="left" colsep="1" rowsep="1">
+<thead>
+<row>
+ <entry>Name</entry>
+ <entry>Type</entry>
+ <entry><para>Description</para></entry>
+</row>
+</thead>
+<tbody>
+<row>
+ <entry>data</entry>
+ <entry>list</entry>
+ <entry><para>A list of strings.</para></entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<para>Each string in the array is a hex literal representing 30 bits
+of information, after parity checks and inversion. The high two bits
+should be ignored.</para>
+
+</refsect3>
<refsect3><title>Type 7: Radio Beacon Almanac</title>
<para>Here is the format:</para>
@@ -2265,19 +2310,12 @@ message:</para>
</table>
</refsect3>
-<refsect3><title>Type 6: Null</title>
-
-<para>This just indicates a null message. There are no payload fields.</para>
-</refsect3>
-
-<refsect3><title>Unknown message</title>
+<refsect3><title>Type 31: Correction data</title>
-<para>This format is used to dump message words in hexadecimal when the
-message type field doesn't match any of the known ones.</para>
-
-<para>Here is the format:</para>
+<para>One or more GLONASS satellite objects follow the header for type
+1 or type 9 messages. Here is the format:</para>
-<table frame="all" pgwide="0"><title>Unknown Message</title>
+<table frame="all" pgwide="0"><title>Satellite object</title>
<tgroup cols="3" align="left" colsep="1" rowsep="1">
<thead>
<row>
@@ -2288,18 +2326,49 @@ message type field doesn't match any of the known ones.</para>
</thead>
<tbody>
<row>
- <entry>data</entry>
- <entry>list</entry>
- <entry><para>A list of strings.</para></entry>
+ <entry>ident</entry>
+ <entry>integer</entry>
+ <entry><para>The PRN number of the satellite for which this is
+ correction data.</para></entry>
+</row>
+<row>
+ <entry>udre</entry>
+ <entry>integer</entry>
+ <entry><para>User Differential Range Error (0-3). See the
+ table following for values.</para></entry>
+</row>
+<row>
+ <entry>change</entry>
+ <entry>boolean</entry>
+ <entry><para>Change-of-ephemeris bit.</para></entry>
+</row>
+<row>
+ <entry>tod</entry>
+ <entry>uinteger</entry>
+ <entry><para>Count of 30-second periods since the top of the
+ hour.</para></entry>
+</row>
+<row>
+ <entry>prc</entry>
+ <entry>real</entry>
+ <entry><para>The pseudorange error in meters for this
+ satellite as measured by the beacon reference receiver at the
+ epoch indicated by the z_count in the parent
+ record.</para></entry>
+</row>
+<row>
+ <entry>rrc</entry>
+ <entry>real</entry>
+ <entry><para>The rate of change of pseudorange error in
+ meters/sec for this satellite as measured by the beacon
+ reference receiver at the epoch indicated by the z_count field
+ in the parent record. This is used to calculate pseudorange
+ errors at other epochs, if required by the GPS
+ receiver.</para></entry>
</row>
</tbody>
</tgroup>
</table>
-
-<para>Each string in the array is a hex literal representing 30 bits
-of information, after parity checks and inversion. The high two bits
-should be ignored.</para>
-
</refsect3>
</refsect2>
<refsect2 id='dump-format3'><title>RTCM3 DUMP FORMAT</title>
@@ -2681,9 +2750,9 @@ past and problems may still lurk there.</para>
<para>AIDVM decoding of types 16-17, 22-23, and 25-26 is unverified.</para>
-<para>The RTCM2 decoder logic is sufficiently convoluted to confuse some
-compiler optimizers, notably in GCC 3.x at -O2, into generating bad
-code.</para>
+<para>The ISGPS used for RTCM2 and subframes decoder logic is
+sufficiently convoluted to confuse some compiler optimizers, notably
+in GCC 3.x at -O2, into generating bad code.</para>
</refsect1>
<refsect1 id='files'><title>FILES</title>
@@ -2758,8 +2827,8 @@ Version 3</citetitle> RTCM Paper 177-2006-SC104-STD.</para>
<para>Note that GPSD presently fully recognizes only the 2.1 level of RTCM;
the protocol was revised up to a version 2.3 including additional
messages relating to GLONASS and real-time kinematics before being
-deprecated in favor of V3. The 2.3 message types 13 and 14 are, however,
-recognized and reported.</para>
+deprecated in favor of V3. The 2.3 message types 13, 14, and 31 are
+recognized and reported, but not types 10-12, 15-30, or 35-63.</para>
<para>Ordering instructions for the RTCM standards are accessible from
the website of the <ulink url='http://www.rtcm.org/'>Radio Technical
diff --git a/gpsd_json.c b/gpsd_json.c
index 8b4942f2..d30da9a8 100644
--- a/gpsd_json.c
+++ b/gpsd_json.c
@@ -843,6 +843,23 @@ void json_rtcm2_dump(const struct rtcm2_t *rtcm,
rtcm->message));
break;
+ case 31:
+ (void)strlcat(buf, "\"satellites\":[", buflen);
+ for (n = 0; n < rtcm->glonass_ranges.nentries; n++) {
+ const struct glonass_rangesat_t *rsp = &rtcm->glonass_ranges.sat[n];
+ (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
+ "{\"ident\":%u,\"udre\":%u,\"change\":%s,\"tod\":%u,\"prc\":%0.3f,\"rrc\":%0.3f},",
+ rsp->ident,
+ rsp->udre,
+ JSON_BOOL(rsp->change),
+ rsp->tod,
+ rsp->prc, rsp->rrc);
+ }
+ if (buf[strlen(buf) - 1] == ',')
+ buf[strlen(buf) - 1] = '\0';
+ (void)strlcat(buf, "]", buflen);
+ break;
+
default:
(void)strlcat(buf, "\"data\":[", buflen);
for (n = 0; n < rtcm->length; n++)
diff --git a/rtcm2_json.c b/rtcm2_json.c
index 68b98533..549a59c4 100644
--- a/rtcm2_json.c
+++ b/rtcm2_json.c
@@ -174,6 +174,24 @@ int json_rtcm2_read(const char *buf,
{NULL},
};
+ const struct json_attr_t rtcm31_satellite[] = {
+ {"ident", t_uinteger, STRUCTOBJECT(struct glonass_rangesat_t, ident)},
+ {"udre", t_uinteger, STRUCTOBJECT(struct glonass_rangesat_t, udre)},
+ {"change", t_boolean, STRUCTOBJECT(struct glonass_rangesat_t, change)},
+ {"tod", t_uinteger, STRUCTOBJECT(struct glonass_rangesat_t, tod)},
+ {"prc", t_real, STRUCTOBJECT(struct glonass_rangesat_t, prc)},
+ {"rrc", t_real, STRUCTOBJECT(struct glonass_rangesat_t, rrc)},
+ {NULL},
+ };
+ /*@-type@*//* STRUCTARRAY confuses splint */
+ const struct json_attr_t json_rtcm31[] = {
+ RTCM2_HEADER
+ {"satellites", t_array, STRUCTARRAY(rtcm2->glonass_ranges.sat,
+ rtcm31_satellite, &satcount)},
+ {NULL},
+ };
+ /*@+type@*/
+
/*@-type@*//* complex union array initislizations confuses splint */
const struct json_attr_t json_rtcm2_fallback[] = {
RTCM2_HEADER
@@ -226,6 +244,10 @@ int json_rtcm2_read(const char *buf,
status = json_read_object(buf, json_rtcm14, endptr);
} else if (strstr(buf, "\"type\":16,") != NULL) {
status = json_read_object(buf, json_rtcm16, endptr);
+ } else if (strstr(buf, "\"type\":31,") != NULL) {
+ status = json_read_object(buf, json_rtcm31, endptr);
+ if (status == 0)
+ rtcm2->glonass_ranges.nentries = (unsigned)satcount;
} else {
int n;
status = json_read_object(buf, json_rtcm2_fallback, endptr);
diff --git a/test/daemon/naujoks-ntrip.log.chk b/test/daemon/naujoks-ntrip.log.chk
index 2f5280a6..77cb333b 100644
--- a/test/daemon/naujoks-ntrip.log.chk
+++ b/test/daemon/naujoks-ntrip.log.chk
@@ -1,11 +1,11 @@
{"class":"RTCM2","type":14,"station_id":688,"zcount":841.8,"seqnum":3,"length":1,"station_health":6,"week":600,"hour":63,"leapsecs":15}
-{"class":"RTCM2","type":31,"station_id":688,"zcount":828.0,"seqnum":4,"length":14,"station_health":6,"data":["0x0386f0f4","0x00000158","0x06c10049","0x4003c69b","0xe9800003","0xc54641bc","0x0000034e","0x8686801a","0x800185d9","0x71010001","0x4586266d","0x4080052b","0xc56ebe02","0x800282b8"]}
+{"class":"RTCM2","type":31,"station_id":688,"zcount":828.0,"seqnum":4,"length":14,"station_health":6,"satellites":[{"ident":14,"udre":0,"change":false,"tod":0,"prc":142.140,"rrc":0.000},{"ident":5,"udre":0,"change":false,"tod":0,"prc":138.320,"rrc":0.002},{"ident":15,"udre":0,"change":false,"tod":0,"prc":136.440,"rrc":0.000},{"ident":21,"udre":0,"change":false,"tod":0,"prc":128.120,"rrc":0.000},{"ident":13,"udre":0,"change":false,"tod":0,"prc":133.640,"rrc":0.000},{"ident":6,"udre":0,"change":false,"tod":0,"prc":121.680,"rrc":0.008},{"ident":22,"udre":0,"change":false,"tod":0,"prc":125.940,"rrc":0.004},{"ident":20,"udre":0,"change":false,"tod":0,"prc":111.240,"rrc":-0.016}]}
{"class":"RTCM2","type":1,"station_id":688,"zcount":843.0,"seqnum":5,"length":19,"station_health":6,"satellites":[{"ident":10,"udre":0,"iod":46,"prc":-2.400,"rrc":0.000},{"ident":13,"udre":0,"iod":94,"prc":-4.420,"rrc":0.000},{"ident":7,"udre":0,"iod":22,"prc":-5.160,"rrc":0.002},{"ident":2,"udre":0,"iod":34,"prc":-6.480,"rrc":0.000},{"ident":4,"udre":0,"iod":47,"prc":-8.860,"rrc":0.000},{"ident":8,"udre":0,"iod":76,"prc":-7.980,"rrc":0.002},{"ident":5,"udre":0,"iod":99,"prc":-8.260,"rrc":0.002},{"ident":23,"udre":0,"iod":81,"prc":-8.060,"rrc":0.000},{"ident":16,"udre":0,"iod":70,"prc":-11.740,"rrc":0.000},{"ident":30,"udre":0,"iod":4,"prc":-18.960,"rrc":-0.006},{"ident":29,"udre":0,"iod":101,"prc":-24.960,"rrc":-0.002}]}
-{"class":"RTCM2","type":31,"station_id":688,"zcount":829.2,"seqnum":6,"length":14,"station_health":6,"data":["0x8386f0dd","0x4000014e","0x86c10060","0x0003c68d","0x69804024","0x05464183","0xc0000371","0x46864034","0x000185f0","0x31010017","0xc5862644","0x0080053d","0x456e7e3a","0x800282b8"]}
+{"class":"RTCM2","type":31,"station_id":688,"zcount":829.2,"seqnum":6,"length":14,"station_health":6,"satellites":[{"ident":14,"udre":0,"change":false,"tod":0,"prc":142.140,"rrc":0.000},{"ident":5,"udre":0,"change":false,"tod":0,"prc":138.320,"rrc":0.002},{"ident":15,"udre":0,"change":false,"tod":0,"prc":136.440,"rrc":0.002},{"ident":21,"udre":0,"change":false,"tod":0,"prc":128.120,"rrc":0.000},{"ident":13,"udre":0,"change":false,"tod":0,"prc":133.620,"rrc":0.000},{"ident":6,"udre":0,"change":false,"tod":0,"prc":121.680,"rrc":0.008},{"ident":22,"udre":0,"change":false,"tod":0,"prc":125.940,"rrc":0.004},{"ident":20,"udre":0,"change":false,"tod":0,"prc":111.220,"rrc":-0.016}]}
{"class":"RTCM2","type":1,"station_id":688,"zcount":844.2,"seqnum":7,"length":19,"station_health":6,"satellites":[{"ident":10,"udre":0,"iod":46,"prc":-2.400,"rrc":0.000},{"ident":13,"udre":0,"iod":94,"prc":-4.420,"rrc":0.000},{"ident":7,"udre":0,"iod":22,"prc":-5.160,"rrc":0.002},{"ident":2,"udre":0,"iod":34,"prc":-6.480,"rrc":0.000},{"ident":4,"udre":0,"iod":47,"prc":-8.860,"rrc":0.000},{"ident":8,"udre":0,"iod":76,"prc":-7.980,"rrc":0.002},{"ident":5,"udre":0,"iod":99,"prc":-8.260,"rrc":0.002},{"ident":23,"udre":0,"iod":81,"prc":-8.080,"rrc":0.000},{"ident":16,"udre":0,"iod":70,"prc":-11.740,"rrc":0.000},{"ident":30,"udre":0,"iod":4,"prc":-18.960,"rrc":-0.006},{"ident":29,"udre":0,"iod":101,"prc":-24.960,"rrc":-0.002}]}
-{"class":"RTCM2","type":31,"station_id":688,"zcount":829.8,"seqnum":0,"length":14,"station_health":6,"data":["0xc386f0cb","0xc0000167","0xc6c10076","0x8003c6a4","0x29804032","0x854641aa","0x80000367","0xc686401d","0x400185e6","0xb101003e","0x85862652","0x80800514","0x056e3e22","0x800282b8"]}
+{"class":"RTCM2","type":31,"station_id":688,"zcount":829.8,"seqnum":0,"length":14,"station_health":6,"satellites":[{"ident":14,"udre":0,"change":false,"tod":0,"prc":142.140,"rrc":0.000},{"ident":5,"udre":0,"change":false,"tod":0,"prc":138.320,"rrc":0.002},{"ident":15,"udre":0,"change":false,"tod":0,"prc":136.440,"rrc":0.002},{"ident":21,"udre":0,"change":false,"tod":0,"prc":128.120,"rrc":0.000},{"ident":13,"udre":0,"change":false,"tod":0,"prc":133.620,"rrc":0.000},{"ident":6,"udre":0,"change":false,"tod":0,"prc":121.680,"rrc":0.008},{"ident":22,"udre":0,"change":false,"tod":0,"prc":125.940,"rrc":0.004},{"ident":20,"udre":0,"change":false,"tod":0,"prc":111.200,"rrc":-0.016}]}
{"class":"RTCM2","type":1,"station_id":688,"zcount":844.8,"seqnum":1,"length":19,"station_health":6,"satellites":[{"ident":10,"udre":0,"iod":46,"prc":-2.400,"rrc":0.000},{"ident":13,"udre":0,"iod":94,"prc":-4.440,"rrc":0.000},{"ident":7,"udre":0,"iod":22,"prc":-5.160,"rrc":0.002},{"ident":2,"udre":0,"iod":34,"prc":-6.480,"rrc":0.000},{"ident":8,"udre":0,"iod":76,"prc":-7.980,"rrc":0.002},{"ident":4,"udre":0,"iod":47,"prc":-8.860,"rrc":0.000},{"ident":5,"udre":0,"iod":99,"prc":-8.260,"rrc":0.002},{"ident":23,"udre":0,"iod":81,"prc":-8.080,"rrc":0.000},{"ident":16,"udre":0,"iod":70,"prc":-11.740,"rrc":0.000},{"ident":30,"udre":0,"iod":4,"prc":-18.940,"rrc":-0.006},{"ident":29,"udre":0,"iod":101,"prc":-24.960,"rrc":-0.002}]}
-{"class":"RTCM2","type":31,"station_id":688,"zcount":831.0,"seqnum":2,"length":14,"station_health":6,"data":["0x0386f0f4","0x00000158","0x06c10049","0x4003c69b","0xe980400d","0x45464163","0xc0000371","0x46864034","0x000185f0","0x3141001a","0x85862652","0x80800514","0x056dbe3e","0x800282b8"]}
+{"class":"RTCM2","type":31,"station_id":688,"zcount":831.0,"seqnum":2,"length":14,"station_health":6,"satellites":[{"ident":14,"udre":0,"change":false,"tod":0,"prc":142.140,"rrc":0.000},{"ident":5,"udre":0,"change":false,"tod":0,"prc":138.320,"rrc":0.002},{"ident":15,"udre":0,"change":false,"tod":0,"prc":136.440,"rrc":0.002},{"ident":21,"udre":0,"change":false,"tod":0,"prc":128.100,"rrc":0.000},{"ident":13,"udre":0,"change":false,"tod":0,"prc":133.620,"rrc":0.000},{"ident":6,"udre":0,"change":false,"tod":0,"prc":121.700,"rrc":0.008},{"ident":22,"udre":0,"change":false,"tod":0,"prc":125.940,"rrc":0.004},{"ident":20,"udre":0,"change":false,"tod":0,"prc":111.160,"rrc":-0.016}]}
{"class":"RTCM2","type":1,"station_id":688,"zcount":846.0,"seqnum":3,"length":19,"station_health":6,"satellites":[{"ident":10,"udre":0,"iod":46,"prc":-2.400,"rrc":0.000},{"ident":13,"udre":0,"iod":94,"prc":-4.440,"rrc":0.000},{"ident":7,"udre":0,"iod":22,"prc":-5.160,"rrc":0.002},{"ident":2,"udre":0,"iod":34,"prc":-6.480,"rrc":0.000},{"ident":8,"udre":0,"iod":76,"prc":-7.980,"rrc":0.002},{"ident":4,"udre":0,"iod":47,"prc":-8.880,"rrc":0.000},{"ident":5,"udre":0,"iod":99,"prc":-8.240,"rrc":0.002},{"ident":23,"udre":0,"iod":81,"prc":-8.080,"rrc":0.000},{"ident":16,"udre":0,"iod":70,"prc":-11.740,"rrc":0.000},{"ident":30,"udre":0,"iod":4,"prc":-18.960,"rrc":-0.006},{"ident":29,"udre":0,"iod":101,"prc":-24.960,"rrc":-0.002}]}
-{"class":"RTCM2","type":31,"station_id":688,"zcount":832.2,"seqnum":4,"length":14,"station_health":6,"data":["0x8386f120","0x00400155","0x46c1005f","0xc003c6b2","0xa980401b","0xc546414a","0x80000367","0xc686401d","0x400185e6","0xb1810024","0x0586267b","0xc0800502","0x856d3e08","0x00028291"]}
+{"class":"RTCM2","type":31,"station_id":688,"zcount":832.2,"seqnum":4,"length":14,"station_health":6,"satellites":[{"ident":14,"udre":0,"change":false,"tod":0,"prc":142.160,"rrc":0.002},{"ident":5,"udre":0,"change":false,"tod":0,"prc":138.320,"rrc":0.002},{"ident":15,"udre":0,"change":false,"tod":0,"prc":136.440,"rrc":0.002},{"ident":21,"udre":0,"change":false,"tod":0,"prc":128.100,"rrc":0.000},{"ident":13,"udre":0,"change":false,"tod":0,"prc":133.620,"rrc":0.000},{"ident":6,"udre":0,"change":false,"tod":0,"prc":121.720,"rrc":0.008},{"ident":22,"udre":0,"change":false,"tod":0,"prc":125.940,"rrc":0.004},{"ident":20,"udre":0,"change":false,"tod":0,"prc":111.120,"rrc":-0.016}]}
{"class":"RTCM2","type":1,"station_id":688,"zcount":847.2,"seqnum":5,"length":19,"station_health":6,"satellites":[{"ident":10,"udre":0,"iod":46,"prc":-2.400,"rrc":0.000},{"ident":13,"udre":0,"iod":94,"prc":-4.440,"rrc":0.000},{"ident":7,"udre":0,"iod":22,"prc":-5.160,"rrc":0.002},{"ident":2,"udre":0,"iod":34,"prc":-6.480,"rrc":0.000},{"ident":8,"udre":0,"iod":76,"prc":-7.980,"rrc":0.002},{"ident":4,"udre":0,"iod":47,"prc":-8.860,"rrc":0.002},{"ident":5,"udre":0,"iod":99,"prc":-8.240,"rrc":0.002},{"ident":23,"udre":0,"iod":81,"prc":-8.080,"rrc":0.000},{"ident":16,"udre":0,"iod":70,"prc":-11.760,"rrc":0.000},{"ident":30,"udre":0,"iod":4,"prc":-18.980,"rrc":-0.006},{"ident":29,"udre":0,"iod":101,"prc":-24.980,"rrc":-0.002}]}