diff options
-rw-r--r-- | driver_rtcm2.c | 156 | ||||
-rw-r--r-- | gpsd.xml | 121 | ||||
-rw-r--r-- | gpsd_json.c | 17 | ||||
-rw-r--r-- | rtcm2_json.c | 22 | ||||
-rw-r--r-- | test/daemon/naujoks-ntrip.log.chk | 10 |
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)); @@ -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 — 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 — a text message from the beacon operator.</para></listitem> </varlistentry> + +<varlistentry> +<term>31</term> +<listitem><para>GLONASS subset corrections — 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}]}
|