123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852 |
- /* subframe.c -- interpret satellite subframe data.
- *
- * This file is Copyright (c) 2010-2018 by the GPSD project
- * SPDX-License-Identifier: BSD-2-clause
- */
- #include "gpsd_config.h" /* must be before all includes */
- #include <math.h>
- #include "gpsd.h"
- /* convert unsigned to signed */
- #define uint2int( u, bit) ( (u & (1<<(bit-1))) ? u - (1<<bit) : u)
- gps_mask_t gpsd_interpret_subframe_raw(struct gps_device_t *session,
- unsigned int tSVID, uint32_t words[])
- {
- unsigned int i;
- uint8_t preamble;
- if (session->subframe_count++ == 0) {
- speed_t speed = gpsd_get_speed(session);
- if (speed < 38400)
- GPSD_LOG(LOG_WARN, &session->context->errout,
- "speed less than 38,400 may cause data lag and loss of functionality\n");
- }
- /*
- * This function assumes an array of 10 ints, each of which carries
- * a raw 30-bit GPS word use your favorite search engine to find the
- * latest version of the specification: IS-GPS-200.
- *
- * Each raw 30-bit word is made of 24 data bits and 6 parity bits. The
- * raw word and transport word are emitted from the GPS MSB-first and
- * right justified. In other words, masking the raw word against 0x3f
- * will return just the parity bits. Masking with 0x3fffffff and shifting
- * 6 bits to the right returns just the 24 data bits. The top two bits
- * (b31 and b30) are undefined; chipset designers may store copies of
- * the bits D29* and D30* here to aid parity checking.
- *
- * Since bits D29* and D30* are not available in word 0, it is tested for
- * a known preamble to help check its validity and determine whether the
- * word is inverted.
- *
- */
- GPSD_LOG(LOG_DATA, &session->context->errout,
- "50B: gpsd_interpret_subframe_raw: "
- "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
- words[0], words[1], words[2], words[3], words[4],
- words[5], words[6], words[7], words[8], words[9]);
- preamble = (uint8_t)((words[0] >> 22) & 0xFF);
- if (preamble == 0x8b) { /* preamble is inverted */
- words[0] ^= 0x3fffffc0; /* invert */
- } else if (preamble != 0x74) {
- /* strangely this is very common, so don't log it */
- GPSD_LOG(LOG_DATA, &session->context->errout,
- "50B: gpsd_interpret_subframe_raw: bad preamble 0x%x\n",
- preamble);
- return 0;
- }
- words[0] = (words[0] >> 6) & 0xffffff;
- for (i = 1; i < 10; i++) {
- int invert;
- uint32_t parity;
- /* D30* says invert */
- invert = (words[i] & 0x40000000) ? 1 : 0;
- /* inverted data, invert it back */
- if (invert) {
- words[i] ^= 0x3fffffc0;
- }
- parity = (uint32_t)isgps_parity((isgps30bits_t)words[i]);
- if (parity != (words[i] & 0x3f)) {
- GPSD_LOG(LOG_DATA, &session->context->errout,
- "50B: gpsd_interpret_subframe_raw parity fail words[%d] 0x%x != 0x%x\n",
- i, parity, (words[i] & 0x1));
- return 0;
- }
- words[i] = (words[i] >> 6) & 0xffffff;
- }
- return gpsd_interpret_subframe(session, tSVID, words);
- }
- /* you can find up to date almanac data for comparision here:
- * https://gps.afspc.af.mil/gps/Current/current.alm
- */
- static void subframe_almanac(const struct gpsd_errout_t *errout,
- uint8_t tSVID, uint32_t words[],
- uint8_t subframe, uint8_t sv,
- uint8_t data_id,
- struct almanac_t *almp)
- {
- almp->sv = sv; /* ignore the 0 sv problem for now */
- almp->e = ( words[2] & 0x00FFFF);
- almp->d_eccentricity = pow(2.0,-21) * almp->e;
- /* carefull, each SV can have more than 2 toa's active at the same time
- * you can not just store one or two almanacs for each sat */
- almp->toa = ((words[3] >> 16) & 0x0000FF);
- almp->l_toa = almp->toa << 12;
- almp->deltai = ( words[3] & 0x00FFFF);
- almp->d_deltai = pow(2.0, -19) * almp->deltai;
- almp->Omegad = ((words[4] >> 8) & 0x00FFFF);
- almp->d_Omegad = pow(2.0, -38) * almp->Omegad;
- almp->svh = ( words[4] & 0x0000FF);
- almp->sqrtA = ( words[5] & 0xFFFFFF);
- almp->d_sqrtA = pow(2.0,-11) * almp->sqrtA;
- almp->Omega0 = ( words[6] & 0xFFFFFF);
- almp->Omega0 = uint2int(almp->Omega0, 24);
- almp->d_Omega0 = pow(2.0, -23) * almp->Omega0;
- almp->omega = ( words[7] & 0xFFFFFF);
- almp->omega = uint2int(almp->omega, 24);
- almp->d_omega = pow(2.0, -23) * almp->omega;
- almp->M0 = ( words[8] & 0x00FFFFFF);
- almp->M0 = uint2int(almp->M0, 24);
- /* if you want radians, multiply by GPS_PI, but we do semi-circles
- * to match IS-GPS-200E */
- almp->d_M0 = pow(2.0,-23) * almp->M0;
- almp->af1 = ((words[9] >> 5) & 0x0007FF);
- almp->af1 = (short)uint2int(almp->af1, 11);
- almp->d_af1 = pow(2.0,-38) * almp->af1;
- almp->af0 = ((words[9] >> 16) & 0x0000FF);
- almp->af0 <<= 3;
- almp->af0 |= ((words[9] >> 2) & 0x000007);
- almp->af0 = (short)uint2int(almp->af0, 11);
- almp->d_af0 = pow(2.0,-20) * almp->af0;
- GPSD_LOG(LOG_PROG, errout,
- "50B: SF:%d SV:%2u TSV:%2u data_id %d e:%g toa:%lu "
- "deltai:%.10e Omegad:%.5e svh:%u sqrtA:%.10g Omega0:%.10e "
- "omega:%.10e M0:%.11e af0:%.5e af1:%.5e\n",
- subframe, almp->sv, tSVID, data_id,
- almp->d_eccentricity,
- almp->l_toa,
- almp->d_deltai,
- almp->d_Omegad,
- almp->svh,
- almp->d_sqrtA,
- almp->d_Omega0,
- almp->d_omega,
- almp->d_M0,
- almp->d_af0,
- almp->d_af1);
- }
- gps_mask_t gpsd_interpret_subframe(struct gps_device_t *session,
- unsigned int tSVID, uint32_t words[])
- {
- /*
- * Heavy black magic begins here!
- *
- * A description of how to decode these bits is at
- * <http://home-2.worldonline.nl/~samsvl/nav2eu.htm>
- *
- * We're mostly looking for subframe 4 page 18 word 9, the leap second
- * correction. This functions assumes an array of words without parity
- * or inversion (inverted word 0 is OK). It may be called directly by a
- * driver if the chipset emits acceptable data.
- *
- * To date this code has been tested on iTrax, SiRF and ublox.
- */
- /* FIXME!! I really doubt this is Big Endian compatible */
- uint8_t preamble;
- struct subframe_t *subp = &session->gpsdata.subframe;
- GPSD_LOG(LOG_DATA, &session->context->errout,
- "50B: gpsd_interpret_subframe: (%d) "
- "%06x %06x %06x %06x %06x %06x %06x %06x %06x %06x\n",
- tSVID, words[0], words[1], words[2], words[3], words[4],
- words[5], words[6], words[7], words[8], words[9]);
- preamble = (uint8_t)((words[0] >> 16) & 0x0FF);
- if (preamble == 0x8b) {
- /* somehow missed an inversion */
- preamble ^= 0xff;
- words[0] ^= 0xffffff;
- }
- if (preamble != 0x74) {
- GPSD_LOG(LOG_WARN, &session->context->errout,
- "50B: gpsd_interpret_subframe bad preamble: 0x%x header 0x%x\n",
- preamble, words[0]);
- return 0;
- }
- subp->integrity = (bool)((words[0] >> 1) & 0x01);
- /* The subframe ID is in the Hand Over Word (page 80) */
- subp->TOW17 = ((words[1] >> 7) & 0x01FFFF);
- subp->l_TOW17 = (long)(subp->TOW17 * 6);
- subp->tSVID = (uint8_t)tSVID;
- subp->subframe_num = ((words[1] >> 2) & 0x07);
- subp->alert = (bool)((words[1] >> 6) & 0x01);
- subp->antispoof = (bool)((words[1] >> 6) & 0x01);
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:%d SV:%2u TOW17:%7lu Alert:%u AS:%u IF:%d\n",
- subp->subframe_num, subp->tSVID, subp->l_TOW17,
- (unsigned)subp->alert, (unsigned)subp->antispoof,
- (unsigned)subp->integrity);
- /*
- * Consult the latest revision of IS-GPS-200 for the mapping
- * between magic SVIDs and pages.
- */
- subp->pageid = (words[2] >> 16) & 0x00003F; /* only in frames 4 & 5 */
- subp->data_id = (words[2] >> 22) & 0x3; /* only in frames 4 & 5 */
- subp->is_almanac = 0;
- switch (subp->subframe_num) {
- case 1:
- /* subframe 1: clock parameters for transmitting SV */
- /* get Week Number (WN) from subframe 1 */
- /*
- * This only extracts 10 bits of GPS week.
- * 13 bits are available in the extension CNAV message,
- * which we don't decode yet because we don't know
- * of any receiver that reports it.
- */
- session->context->gps_week =
- (unsigned short)((words[2] >> 14) & 0x03ff);
- subp->sub1.WN = (uint16_t)session->context->gps_week;
- subp->sub1.l2 = (uint8_t)((words[2] >> 12) & 0x000003); /* L2 Code */
- subp->sub1.ura = (unsigned int)((words[2] >> 8) & 0x00000F); /* URA Index */
- subp->sub1.hlth = (unsigned int)((words[2] >> 2) & 0x00003F); /* SV health */
- subp->sub1.IODC = (words[2] & 0x000003); /* IODC 2 MSB */
- subp->sub1.l2p = ((words[3] >> 23) & 0x000001); /* L2 P flag */
- subp->sub1.Tgd = (int8_t)( words[6] & 0x0000FF);
- subp->sub1.d_Tgd = pow(2.0, -31) * (int)subp->sub1.Tgd;
- subp->sub1.toc = ( words[7] & 0x00FFFF);
- subp->sub1.l_toc = (long)subp->sub1.toc << 4;
- subp->sub1.af2 = (int8_t)((words[8] >> 16) & 0x0FF);
- subp->sub1.d_af2 = pow(2.0, -55) * (int)subp->sub1.af2;
- subp->sub1.af1 = (int16_t)( words[8] & 0x00FFFF);
- subp->sub1.d_af1 = pow(2.0, -43) * subp->sub1.af1;
- subp->sub1.af0 = (int32_t)((words[9] >> 2) & 0x03FFFFF);
- subp->sub1.af0 = uint2int(subp->sub1.af0, 22);
- subp->sub1.d_af0 = pow(2.0, -31) * subp->sub1.af0;
- subp->sub1.IODC <<= 8;
- subp->sub1.IODC |= ((words[7] >> 16) & 0x00FF);
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:1 SV:%2u WN:%4u IODC:%4u"
- " L2:%u ura:%u hlth:%u L2P:%u Tgd:%g toc:%lu af2:%.4g"
- " af1:%.6e af0:%.7e\n",
- subp->tSVID,
- subp->sub1.WN,
- subp->sub1.IODC,
- subp->sub1.l2,
- subp->sub1.ura,
- subp->sub1.hlth,
- subp->sub1.l2p,
- subp->sub1.d_Tgd,
- subp->sub1.l_toc,
- subp->sub1.d_af2,
- subp->sub1.d_af1,
- subp->sub1.d_af0);
- break;
- case 2:
- /* subframe 2: ephemeris for transmitting SV */
- subp->sub2.IODE = ((words[2] >> 16) & 0x00FF);
- subp->sub2.Crs = (int16_t)( words[2] & 0x00FFFF);
- subp->sub2.d_Crs = pow(2.0,-5) * subp->sub2.Crs;
- subp->sub2.deltan = (int16_t)((words[3] >> 8) & 0x00FFFF);
- subp->sub2.d_deltan = pow(2.0,-43) * subp->sub2.deltan;
- subp->sub2.M0 = (int32_t)( words[3] & 0x0000FF);
- subp->sub2.M0 <<= 24;
- subp->sub2.M0 |= ( words[4] & 0x00FFFFFF);
- subp->sub2.d_M0 = pow(2.0,-31) * subp->sub2.M0 * GPS_PI;
- subp->sub2.Cuc = (int16_t)((words[5] >> 8) & 0x00FFFF);
- subp->sub2.d_Cuc = pow(2.0,-29) * subp->sub2.Cuc;
- subp->sub2.e = ( words[5] & 0x0000FF);
- subp->sub2.e <<= 24;
- subp->sub2.e |= ( words[6] & 0x00FFFFFF);
- subp->sub2.d_eccentricity = pow(2.0,-33) * subp->sub2.e;
- subp->sub2.Cus = (int16_t)((words[7] >> 8) & 0x00FFFF);
- subp->sub2.d_Cus = pow(2.0,-29) * subp->sub2.Cus;
- subp->sub2.sqrtA = ( words[7] & 0x0000FF);
- subp->sub2.sqrtA <<= 24;
- subp->sub2.sqrtA |= ( words[8] & 0x00FFFFFF);
- subp->sub2.d_sqrtA = pow(2.0, -19) * subp->sub2.sqrtA;
- subp->sub2.toe = ((words[9] >> 8) & 0x00FFFF);
- subp->sub2.l_toe = (long)(subp->sub2.toe << 4);
- subp->sub2.fit = ((words[9] >> 7) & 0x000001);
- subp->sub2.AODO = ((words[9] >> 2) & 0x00001F);
- subp->sub2.u_AODO = subp->sub2.AODO * 900;
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:2 SV:%2u IODE:%3u Crs:%.6e deltan:%.6e "
- "M0:%.11e Cuc:%.6e e:%f Cus:%.6e sqrtA:%.11g "
- "toe:%lu FIT:%u AODO:%5u\n",
- subp->tSVID,
- subp->sub2.IODE,
- subp->sub2.d_Crs,
- subp->sub2.d_deltan,
- subp->sub2.d_M0,
- subp->sub2.d_Cuc,
- subp->sub2.d_eccentricity,
- subp->sub2.d_Cus,
- subp->sub2.d_sqrtA,
- subp->sub2.l_toe,
- subp->sub2.fit,
- subp->sub2.u_AODO);
- break;
- case 3:
- /* subframe 3: ephemeris for transmitting SV */
- subp->sub3.Cic = (int16_t)((words[2] >> 8) & 0x00FFFF);
- subp->sub3.d_Cic = pow(2.0, -29) * subp->sub3.Cic;
- subp->sub3.Omega0 = (int32_t)(words[2] & 0x0000FF);
- subp->sub3.Omega0 <<= 24;
- subp->sub3.Omega0 |= ( words[3] & 0x00FFFFFF);
- subp->sub3.d_Omega0 = pow(2.0, -31) * subp->sub3.Omega0;
- subp->sub3.Cis = (int16_t)((words[4] >> 8) & 0x00FFFF);
- subp->sub3.d_Cis = pow(2.0, -29) * subp->sub3.Cis;
- subp->sub3.i0 = (int32_t)(words[4] & 0x0000FF);
- subp->sub3.i0 <<= 24;
- subp->sub3.i0 |= ( words[5] & 0x00FFFFFF);
- subp->sub3.d_i0 = pow(2.0, -31) * subp->sub3.i0;
- subp->sub3.Crc = (int16_t)((words[6] >> 8) & 0x00FFFF);
- subp->sub3.d_Crc = pow(2.0, -5) * subp->sub3.Crc;
- subp->sub3.omega = (int32_t)(words[6] & 0x0000FF);
- subp->sub3.omega <<= 24;
- subp->sub3.omega |= ( words[7] & 0x00FFFFFF);
- subp->sub3.d_omega = pow(2.0, -31) * subp->sub3.omega;
- subp->sub3.Omegad = (int32_t)(words[8] & 0x00FFFFFF);
- subp->sub3.Omegad = uint2int(subp->sub3.Omegad, 24);
- subp->sub3.d_Omegad = pow(2.0, -43) * subp->sub3.Omegad;
- subp->sub3.IODE = ((words[9] >> 16) & 0x0000FF);
- subp->sub3.IDOT = (int16_t)((words[9] >> 2) & 0x003FFF);
- subp->sub3.IDOT = uint2int(subp->sub3.IDOT, 14);
- subp->sub3.d_IDOT = pow(2.0, -43) * subp->sub3.IDOT;
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:3 SV:%2u IODE:%3u I IDOT:%.6g Cic:%.6e Omega0:%.11e "
- " Cis:%.7g i0:%.11e Crc:%.7g omega:%.11e Omegad:%.6e\n",
- subp->tSVID, subp->sub3.IODE, subp->sub3.d_IDOT,
- subp->sub3.d_Cic, subp->sub3.d_Omega0, subp->sub3.d_Cis,
- subp->sub3.d_i0, subp->sub3.d_Crc, subp->sub3.d_omega,
- subp->sub3.d_Omegad );
- break;
- case 4:
- {
- int i = 0; /* handy loop counter */
- int sv = -2;
- switch (subp->pageid) {
- case 0:
- /* almanac for dummy sat 0, which is same as transmitting sat */
- sv = 0;
- break;
- case 1:
- case 6:
- case 11:
- case 16:
- case 21:
- case 57:
- /* for some inscutable reason these pages are all sent
- * as page 57, IS-GPS-200E Table 20-V */
- break;
- case 12:
- case 24:
- case 62:
- /* for some inscrutable reason these pages are all sent
- * as page 62, IS-GPS-200E Table 20-V */
- break;
- case 14:
- case 53:
- /* for some inscrutable reason page 14 is sent
- * as page 53, IS-GPS-200E Table 20-V */
- break;
- case 15:
- case 54:
- /* for some inscrutable reason page 15 is sent
- * as page 54, IS-GPS-200E Table 20-V */
- break;
- case 19:
- /* for some inscrutable reason page 20 is sent
- * as page 58, IS-GPS-200E Table 20-V */
- /* reserved page */
- break;
- case 20:
- /* for some inscrutable reason page 20 is sent
- * as page 59, IS-GPS-200E Table 20-V */
- /* reserved page */
- break;
- case 22:
- case 60:
- /* for some inscrutable reason page 22 is sent
- * as page 60, IS-GPS-200E Table 20-V */
- /* reserved page */
- break;
- case 23:
- case 61:
- /* for some inscrutable reason page 23 is sent
- * as page 61, IS-GPS-200E Table 20-V */
- /* reserved page */
- break;
- /* almanac data for SV 25 through 32 respectively; */
- case 2:
- sv = 25;
- break;
- case 3:
- sv = 26;
- break;
- case 4:
- sv = 27;
- break;
- case 5:
- sv = 28;
- break;
- case 7:
- sv = 29;
- break;
- case 8:
- sv = 30;
- break;
- case 9:
- sv = 31;
- break;
- case 10:
- sv = 32;
- break;
- case 13:
- case 52:
- /* NMCT */
- sv = -1;
- subp->sub4_13.ai = (unsigned char)((words[2] >> 22) & 0x000003);
- subp->sub4_13.ERD[1] = (char)((words[2] >> 8) & 0x00003F);
- subp->sub4_13.ERD[2] = (char)((words[2] >> 2) & 0x00003F);
- subp->sub4_13.ERD[3] = (char)((words[2] >> 0) & 0x000003);
- subp->sub4_13.ERD[3] <<= 2;
- subp->sub4_13.ERD[3] |= (char)((words[3] >> 20) & 0x00000F);
- subp->sub4_13.ERD[4] = (char)((words[3] >> 14) & 0x00003F);
- subp->sub4_13.ERD[5] = (char)((words[3] >> 8) & 0x00003F);
- subp->sub4_13.ERD[6] = (char)((words[3] >> 2) & 0x00003F);
- subp->sub4_13.ERD[7] = (char)((words[3] >> 0) & 0x000003);
- subp->sub4_13.ERD[7] <<= 2;
- subp->sub4_13.ERD[7] |= (char)((words[4] >> 20) & 0x00000F);
- subp->sub4_13.ERD[8] = (char)((words[4] >> 14) & 0x00003F);
- subp->sub4_13.ERD[9] = (char)((words[4] >> 8) & 0x00003F);
- subp->sub4_13.ERD[10] = (char)((words[4] >> 2) & 0x00003F);
- subp->sub4_13.ERD[11] = (char)((words[4] >> 0) & 0x00000F);
- subp->sub4_13.ERD[11] <<= 2;
- subp->sub4_13.ERD[11] |= (char)((words[5] >> 20) & 0x00000F);
- subp->sub4_13.ERD[12] = (char)((words[5] >> 14) & 0x00003F);
- subp->sub4_13.ERD[13] = (char)((words[5] >> 8) & 0x00003F);
- subp->sub4_13.ERD[14] = (char)((words[5] >> 2) & 0x00003F);
- subp->sub4_13.ERD[15] = (char)((words[5] >> 0) & 0x000003);
- subp->sub4_13.ERD[15] <<= 2;
- subp->sub4_13.ERD[15] |= (char)((words[6] >> 20) & 0x00000F);
- subp->sub4_13.ERD[16] = (char)((words[6] >> 14) & 0x00003F);
- subp->sub4_13.ERD[17] = (char)((words[6] >> 8) & 0x00003F);
- subp->sub4_13.ERD[18] = (char)((words[6] >> 2) & 0x00003F);
- subp->sub4_13.ERD[19] = (char)((words[6] >> 0) & 0x000003);
- subp->sub4_13.ERD[19] <<= 2;
- subp->sub4_13.ERD[19] |= (char)((words[7] >> 20) & 0x00000F);
- subp->sub4_13.ERD[20] = (char)((words[7] >> 14) & 0x00003F);
- subp->sub4_13.ERD[21] = (char)((words[7] >> 8) & 0x00003F);
- subp->sub4_13.ERD[22] = (char)((words[7] >> 2) & 0x00003F);
- subp->sub4_13.ERD[23] = (char)((words[7] >> 0) & 0x000003);
- subp->sub4_13.ERD[23] <<= 2;
- subp->sub4_13.ERD[23] |= (char)((words[8] >> 20) & 0x00000F);
- subp->sub4_13.ERD[24] = (char)((words[8] >> 14) & 0x00003F);
- subp->sub4_13.ERD[25] = (char)((words[8] >> 8) & 0x00003F);
- subp->sub4_13.ERD[26] = (char)((words[8] >> 2) & 0x00003F);
- subp->sub4_13.ERD[27] = (char)((words[8] >> 0) & 0x000003);
- subp->sub4_13.ERD[27] <<= 2;
- subp->sub4_13.ERD[27] |= (char)((words[9] >> 20) & 0x00000F);
- subp->sub4_13.ERD[28] = (char)((words[9] >> 14) & 0x00003F);
- subp->sub4_13.ERD[29] = (char)((words[9] >> 8) & 0x00003F);
- subp->sub4_13.ERD[30] = (char)((words[9] >> 2) & 0x00003F);
- for ( i = 1; i < 31; i++ ) {
- subp->sub4_13.ERD[i] = uint2int(subp->sub4_13.ERD[i], 6);
- }
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:4-13 data_id %d ai:%u "
- "ERD1:%d ERD2:%d ERD3:%d ERD4:%d "
- "ERD5:%d ERD6:%d ERD7:%d ERD8:%d "
- "ERD9:%d ERD10:%d ERD11:%d ERD12:%d "
- "ERD13:%d ERD14:%d ERD15:%d ERD16:%d "
- "ERD17:%d ERD18:%d ERD19:%d ERD20:%d "
- "ERD21:%d ERD22:%d ERD23:%d ERD24:%d "
- "ERD25:%d ERD26:%d ERD27:%d ERD28:%d "
- "ERD29:%d ERD30:%d\n",
- subp->data_id, subp->sub4_13.ai,
- subp->sub4_13.ERD[1], subp->sub4_13.ERD[2],
- subp->sub4_13.ERD[3], subp->sub4_13.ERD[4],
- subp->sub4_13.ERD[5], subp->sub4_13.ERD[6],
- subp->sub4_13.ERD[7], subp->sub4_13.ERD[8],
- subp->sub4_13.ERD[9], subp->sub4_13.ERD[10],
- subp->sub4_13.ERD[11], subp->sub4_13.ERD[12],
- subp->sub4_13.ERD[13], subp->sub4_13.ERD[14],
- subp->sub4_13.ERD[15], subp->sub4_13.ERD[16],
- subp->sub4_13.ERD[17], subp->sub4_13.ERD[18],
- subp->sub4_13.ERD[19], subp->sub4_13.ERD[20],
- subp->sub4_13.ERD[21], subp->sub4_13.ERD[22],
- subp->sub4_13.ERD[23], subp->sub4_13.ERD[24],
- subp->sub4_13.ERD[25], subp->sub4_13.ERD[26],
- subp->sub4_13.ERD[27], subp->sub4_13.ERD[28],
- subp->sub4_13.ERD[29], subp->sub4_13.ERD[30]);
- break;
- case 25:
- case 63:
- /* for some inscrutable reason page 25 is sent
- * as page 63, IS-GPS-200E Table 20-V */
- /* A-S flags/SV configurations for 32 SVs,
- * plus SV health for SV 25 through 32
- */
- sv = -1;
- subp->sub4_25.svf[1] = (unsigned char)((words[2] >> 12) & 0x0F);
- subp->sub4_25.svf[2] = (unsigned char)((words[2] >> 8) & 0x0F);
- subp->sub4_25.svf[3] = (unsigned char)((words[2] >> 4) & 0x0F);
- subp->sub4_25.svf[4] = (unsigned char)((words[2] >> 0) & 0x0F);
- subp->sub4_25.svf[5] = (unsigned char)((words[3] >> 20) & 0x0F);
- subp->sub4_25.svf[6] = (unsigned char)((words[3] >> 16) & 0x0F);
- subp->sub4_25.svf[7] = (unsigned char)((words[3] >> 12) & 0x0F);
- subp->sub4_25.svf[8] = (unsigned char)((words[3] >> 8) & 0x0F);
- subp->sub4_25.svf[9] = (unsigned char)((words[3] >> 4) & 0x0F);
- subp->sub4_25.svf[10] = (unsigned char)((words[3] >> 0) & 0x0F);
- subp->sub4_25.svf[11] = (unsigned char)((words[4] >> 20) & 0x0F);
- subp->sub4_25.svf[12] = (unsigned char)((words[4] >> 16) & 0x0F);
- subp->sub4_25.svf[13] = (unsigned char)((words[4] >> 12) & 0x0F);
- subp->sub4_25.svf[14] = (unsigned char)((words[4] >> 8) & 0x0F);
- subp->sub4_25.svf[15] = (unsigned char)((words[4] >> 4) & 0x0F);
- subp->sub4_25.svf[16] = (unsigned char)((words[4] >> 0) & 0x0F);
- subp->sub4_25.svf[17] = (unsigned char)((words[5] >> 20) & 0x0F);
- subp->sub4_25.svf[18] = (unsigned char)((words[5] >> 16) & 0x0F);
- subp->sub4_25.svf[19] = (unsigned char)((words[5] >> 12) & 0x0F);
- subp->sub4_25.svf[20] = (unsigned char)((words[5] >> 8) & 0x0F);
- subp->sub4_25.svf[21] = (unsigned char)((words[5] >> 4) & 0x0F);
- subp->sub4_25.svf[22] = (unsigned char)((words[5] >> 0) & 0x0F);
- subp->sub4_25.svf[23] = (unsigned char)((words[6] >> 20) & 0x0F);
- subp->sub4_25.svf[24] = (unsigned char)((words[6] >> 16) & 0x0F);
- subp->sub4_25.svf[25] = (unsigned char)((words[6] >> 12) & 0x0F);
- subp->sub4_25.svf[26] = (unsigned char)((words[6] >> 8) & 0x0F);
- subp->sub4_25.svf[27] = (unsigned char)((words[6] >> 4) & 0x0F);
- subp->sub4_25.svf[28] = (unsigned char)((words[6] >> 0) & 0x0F);
- subp->sub4_25.svf[29] = (unsigned char)((words[7] >> 20) & 0x0F);
- subp->sub4_25.svf[30] = (unsigned char)((words[7] >> 16) & 0x0F);
- subp->sub4_25.svf[31] = (unsigned char)((words[7] >> 12) & 0x0F);
- subp->sub4_25.svf[32] = (unsigned char)((words[7] >> 8) & 0x0F);
- subp->sub4_25.svhx[0] = ((words[7] >> 0) & 0x00003F);
- subp->sub4_25.svhx[1] = ((words[8] >> 18) & 0x00003F);
- subp->sub4_25.svhx[2] = ((words[8] >> 12) & 0x00003F);
- subp->sub4_25.svhx[3] = ((words[8] >> 6) & 0x00003F);
- subp->sub4_25.svhx[4] = ((words[8] >> 0) & 0x00003F);
- subp->sub4_25.svhx[5] = ((words[9] >> 18) & 0x00003F);
- subp->sub4_25.svhx[6] = ((words[9] >> 12) & 0x00003F);
- subp->sub4_25.svhx[7] = ((words[9] >> 6) & 0x00003F);
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:4-25 data_id %d "
- "SV1:%u SV2:%u SV3:%u SV4:%u "
- "SV5:%u SV6:%u SV7:%u SV8:%u "
- "SV9:%u SV10:%u SV11:%u SV12:%u "
- "SV13:%u SV14:%u SV15:%u SV16:%u "
- "SV17:%u SV18:%u SV19:%u SV20:%u "
- "SV21:%u SV22:%u SV23:%u SV24:%u "
- "SV25:%u SV26:%u SV27:%u SV28:%u "
- "SV29:%u SV30:%u SV31:%u SV32:%u "
- "SVH25:%u SVH26:%u SVH27:%u SVH28:%u "
- "SVH29:%u SVH30:%u SVH31:%u SVH32:%u\n",
- subp->data_id,
- subp->sub4_25.svf[1], subp->sub4_25.svf[2],
- subp->sub4_25.svf[3], subp->sub4_25.svf[4],
- subp->sub4_25.svf[5], subp->sub4_25.svf[6],
- subp->sub4_25.svf[7], subp->sub4_25.svf[8],
- subp->sub4_25.svf[9], subp->sub4_25.svf[10],
- subp->sub4_25.svf[11], subp->sub4_25.svf[12],
- subp->sub4_25.svf[13], subp->sub4_25.svf[14],
- subp->sub4_25.svf[15], subp->sub4_25.svf[16],
- subp->sub4_25.svf[17], subp->sub4_25.svf[18],
- subp->sub4_25.svf[19], subp->sub4_25.svf[20],
- subp->sub4_25.svf[21], subp->sub4_25.svf[22],
- subp->sub4_25.svf[23], subp->sub4_25.svf[24],
- subp->sub4_25.svf[25], subp->sub4_25.svf[26],
- subp->sub4_25.svf[27], subp->sub4_25.svf[28],
- subp->sub4_25.svf[29], subp->sub4_25.svf[30],
- subp->sub4_25.svf[31], subp->sub4_25.svf[32],
- subp->sub4_25.svhx[0], subp->sub4_25.svhx[1],
- subp->sub4_25.svhx[2], subp->sub4_25.svhx[3],
- subp->sub4_25.svhx[4], subp->sub4_25.svhx[5],
- subp->sub4_25.svhx[6], subp->sub4_25.svhx[7]);
- break;
- case 33:
- case 34:
- case 35:
- case 36:
- case 37:
- case 38:
- case 39:
- case 40:
- case 41:
- case 42:
- case 43:
- case 44:
- case 45:
- case 46:
- case 47:
- case 48:
- case 49:
- case 50:
- /* unassigned */
- break;
- case 51:
- /* unknown */
- break;
- case 17:
- case 55:
- /* for some inscrutable reason page 17 is sent
- * as page 55, IS-GPS-200E Table 20-V */
- sv = -1;
- /*
- * "The requisite 176 bits shall occupy bits 9 through 24
- * of word TWO, the 24 MSBs of words THREE through EIGHT,
- * plus the 16 MSBs of word NINE." (word numbers changed
- * to account for zero-indexing)
- * Since we've already stripped the low six parity bits,
- * and shifted the data to a byte boundary, we can just
- * copy it out. */
- i = 0;
- subp->sub4_17.str[i++] = (words[2] >> 8) & 0xff;
- subp->sub4_17.str[i++] = (words[2]) & 0xff;
- subp->sub4_17.str[i++] = (words[3] >> 16) & 0xff;
- subp->sub4_17.str[i++] = (words[3] >> 8) & 0xff;
- subp->sub4_17.str[i++] = (words[3]) & 0xff;
- subp->sub4_17.str[i++] = (words[4] >> 16) & 0xff;
- subp->sub4_17.str[i++] = (words[4] >> 8) & 0xff;
- subp->sub4_17.str[i++] = (words[4]) & 0xff;
- subp->sub4_17.str[i++] = (words[5] >> 16) & 0xff;
- subp->sub4_17.str[i++] = (words[5] >> 8) & 0xff;
- subp->sub4_17.str[i++] = (words[5]) & 0xff;
- subp->sub4_17.str[i++] = (words[6] >> 16) & 0xff;
- subp->sub4_17.str[i++] = (words[6] >> 8) & 0xff;
- subp->sub4_17.str[i++] = (words[6]) & 0xff;
- subp->sub4_17.str[i++] = (words[7] >> 16) & 0xff;
- subp->sub4_17.str[i++] = (words[7] >> 8) & 0xff;
- subp->sub4_17.str[i++] = (words[7]) & 0xff;
- subp->sub4_17.str[i++] = (words[8] >> 16) & 0xff;
- subp->sub4_17.str[i++] = (words[8] >> 8) & 0xff;
- subp->sub4_17.str[i++] = (words[8]) & 0xff;
- subp->sub4_17.str[i++] = (words[9] >> 16) & 0xff;
- subp->sub4_17.str[i++] = (words[9] >> 8) & 0xff;
- subp->sub4_17.str[i] = '\0';
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:4-17 system message: %.24s\n",
- subp->sub4_17.str);
- break;
- case 18:
- case 56:
- /* for some inscrutable reason page 18 is sent
- * as page 56, IS-GPS-200E Table 20-V */
- /* ionospheric and UTC data */
- sv = -1;
- /* current leap seconds */
- subp->sub4_18.alpha0 = (int8_t)((words[2] >> 8) & 0x0000FF);
- subp->sub4_18.d_alpha0 = pow(2.0, -30) * (int)subp->sub4_18.alpha0;
- subp->sub4_18.alpha1 = (int8_t)((words[2] >> 0) & 0x0000FF);
- subp->sub4_18.d_alpha1 = pow(2.0, -27) * (int)subp->sub4_18.alpha1;
- subp->sub4_18.alpha2 = (int8_t)((words[3] >> 16) & 0x0000FF);
- subp->sub4_18.d_alpha2 = pow(2.0, -24) * (int)subp->sub4_18.alpha2;
- subp->sub4_18.alpha3 = (int8_t)((words[3] >> 8) & 0x0000FF);
- subp->sub4_18.d_alpha3 = pow(2.0, -24) * (int)subp->sub4_18.alpha3;
- subp->sub4_18.beta0 = (int8_t)((words[3] >> 0) & 0x0000FF);
- subp->sub4_18.d_beta0 = pow(2.0, 11) * (int)subp->sub4_18.beta0;
- subp->sub4_18.beta1 = (int8_t)((words[4] >> 16) & 0x0000FF);
- subp->sub4_18.d_beta1 = pow(2.0, 14) * (int)subp->sub4_18.beta1;
- subp->sub4_18.beta2 = (int8_t)((words[4] >> 8) & 0x0000FF);
- subp->sub4_18.d_beta2 = pow(2.0, 16) * (int)subp->sub4_18.beta2;
- subp->sub4_18.beta3 = (int8_t)((words[4] >> 0) & 0x0000FF);
- subp->sub4_18.d_beta3 = pow(2.0, 16) * (int)subp->sub4_18.beta3;
- subp->sub4_18.A1 = (int32_t)((words[5] >> 0) & 0xFFFFFF);
- subp->sub4_18.A1 = uint2int(subp->sub4_18.A1, 24);
- subp->sub4_18.d_A1 = pow(2.0,-50) * subp->sub4_18.A1;
- subp->sub4_18.A0 = (int32_t)((words[6] >> 0) & 0xFFFFFF);
- subp->sub4_18.A0 <<= 8;
- subp->sub4_18.A0 |= ((words[7] >> 16) & 0x0000FF);
- subp->sub4_18.d_A0 = pow(2.0,-30) * subp->sub4_18.A0;
- /* careful WN is 10 bits, but WNt is 8 bits! */
- /* WNt (Week Number of LSF) */
- subp->sub4_18.tot = ((words[7] >> 8) & 0x0000FF);
- subp->sub4_18.t_tot = 2e12 * subp->sub4_18.tot;
- subp->sub4_18.WNt = ((words[7] >> 0) & 0x0000FF);
- subp->sub4_18.leap = (int8_t)((words[8] >> 16) & 0x0000FF);
- subp->sub4_18.WNlsf = ((words[8] >> 8) & 0x0000FF);
- /* DN (Day Number of LSF) */
- subp->sub4_18.DN = (words[8] & 0x0000FF);
- /* leap second future */
- subp->sub4_18.lsf = (int8_t)((words[9] >> 16) & 0x0000FF);
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:4-18 a0:%.5g a1:%.5g a2:%.5g a3:%.5g "
- "b0:%.5g b1:%.5g b2:%.5g b3:%.5g "
- "A1:%.11e A0:%.11e tot:%lld WNt:%u "
- "ls: %d WNlsf:%u DN:%u, lsf:%d\n",
- subp->sub4_18.d_alpha0, subp->sub4_18.d_alpha1,
- subp->sub4_18.d_alpha2, subp->sub4_18.d_alpha3,
- subp->sub4_18.d_beta0, subp->sub4_18.d_beta1,
- subp->sub4_18.d_beta2, subp->sub4_18.d_beta3,
- subp->sub4_18.d_A1, subp->sub4_18.d_A0,
- (long long)subp->sub4_18.t_tot, subp->sub4_18.WNt,
- subp->sub4_18.leap, subp->sub4_18.WNlsf,
- subp->sub4_18.DN, subp->sub4_18.lsf);
- /* notify the leap seconds correction in the end
- * of current day */
- /* IS-GPS-200 Revision E, paragraph 20.3.3.5.2.4 */
- /* FIXME: only allow LEAPs in June and December */
- // only need to check whole seconds
- if (((session->context->gps_week % 256) ==
- (unsigned short)subp->sub4_18.WNlsf) &&
- (((subp->sub4_18.DN - 1) * SECS_PER_DAY) <
- session->context->gps_tow.tv_sec) &&
- ((subp->sub4_18.DN * SECS_PER_DAY) >
- session->context->gps_tow.tv_sec)) {
- if (subp->sub4_18.leap < subp->sub4_18.lsf) {
- session->context->leap_notify = LEAP_ADDSECOND;
- } else if (subp->sub4_18.leap > subp->sub4_18.lsf) {
- session->context->leap_notify = LEAP_DELSECOND;
- } else {
- session->context->leap_notify = LEAP_NOWARNING;
- }
- } else {
- session->context->leap_notify = LEAP_NOWARNING;
- }
- session->context->leap_seconds = (int)subp->sub4_18.leap;
- session->context->valid |= LEAP_SECOND_VALID;
- break;
- default:
- ; /* no op */
- }
- if ( -1 < sv ) {
- subp->is_almanac = 1;
- subframe_almanac(&session->context->errout,
- subp->tSVID, words, subp->subframe_num,
- (uint8_t)sv, subp->data_id,
- &subp->sub4.almanac);
- } else if ( -2 == sv ) {
- /* unknown or secret page */
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:4-%d data_id %d\n",
- subp->pageid, subp->data_id);
- return 0;
- }
- /* else, already handled */
- }
- break;
- case 5:
- /* Pages 0, dummy almanac for dummy SV 0
- * Pages 1 through 24: almanac data for SV 1 through 24
- * Page 25: SV health data for SV 1 through 24, the almanac
- * reference time, the almanac reference week number.
- */
- if ( 25 > subp->pageid ) {
- subp->is_almanac = 1;
- subframe_almanac(&session->context->errout,
- subp->tSVID, words, subp->subframe_num,
- subp->pageid, subp->data_id, &subp->sub5.almanac);
- } else if ( 51 == subp->pageid ) {
- /* for some inscrutable reason page 25 is sent as page 51
- * IS-GPS-200E Table 20-V */
- subp->sub5_25.toa = ((words[2] >> 8) & 0x0000FF);
- subp->sub5_25.l_toa <<= 12;
- subp->sub5_25.WNa = ( words[2] & 0x0000FF);
- subp->sub5_25.sv[1] = ((words[2] >> 18) & 0x00003F);
- subp->sub5_25.sv[2] = ((words[2] >> 12) & 0x00003F);
- subp->sub5_25.sv[3] = ((words[2] >> 6) & 0x00003F);
- subp->sub5_25.sv[4] = ((words[2] >> 0) & 0x00003F);
- subp->sub5_25.sv[5] = ((words[3] >> 18) & 0x00003F);
- subp->sub5_25.sv[6] = ((words[3] >> 12) & 0x00003F);
- subp->sub5_25.sv[7] = ((words[3] >> 6) & 0x00003F);
- subp->sub5_25.sv[8] = ((words[3] >> 0) & 0x00003F);
- subp->sub5_25.sv[9] = ((words[4] >> 18) & 0x00003F);
- subp->sub5_25.sv[10] = ((words[4] >> 12) & 0x00003F);
- subp->sub5_25.sv[11] = ((words[4] >> 6) & 0x00003F);
- subp->sub5_25.sv[12] = ((words[4] >> 0) & 0x00003F);
- subp->sub5_25.sv[13] = ((words[5] >> 18) & 0x00003F);
- subp->sub5_25.sv[14] = ((words[5] >> 12) & 0x00003F);
- subp->sub5_25.sv[15] = ((words[5] >> 6) & 0x00003F);
- subp->sub5_25.sv[16] = ((words[5] >> 0) & 0x00003F);
- subp->sub5_25.sv[17] = ((words[6] >> 18) & 0x00003F);
- subp->sub5_25.sv[18] = ((words[6] >> 12) & 0x00003F);
- subp->sub5_25.sv[19] = ((words[6] >> 6) & 0x00003F);
- subp->sub5_25.sv[20] = ((words[6] >> 0) & 0x00003F);
- subp->sub5_25.sv[21] = ((words[7] >> 18) & 0x00003F);
- subp->sub5_25.sv[22] = ((words[7] >> 12) & 0x00003F);
- subp->sub5_25.sv[23] = ((words[7] >> 6) & 0x00003F);
- subp->sub5_25.sv[24] = ((words[7] >> 0) & 0x00003F);
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:5-25 SV:%2u ID:%u toa:%lu WNa:%u "
- "SV1:%u SV2:%u SV3:%u SV4:%u "
- "SV5:%u SV6:%u SV7:%u SV8:%u "
- "SV9:%u SV10:%u SV11:%u SV12:%u "
- "SV13:%u SV14:%u SV15:%u SV16:%u "
- "SV17:%u SV18:%u SV19:%u SV20:%u "
- "SV21:%u SV22:%u SV23:%u SV24:%u\n",
- subp->tSVID, subp->data_id,
- subp->sub5_25.l_toa, subp->sub5_25.WNa,
- subp->sub5_25.sv[1], subp->sub5_25.sv[2],
- subp->sub5_25.sv[3], subp->sub5_25.sv[4],
- subp->sub5_25.sv[5], subp->sub5_25.sv[6],
- subp->sub5_25.sv[7], subp->sub5_25.sv[8],
- subp->sub5_25.sv[9], subp->sub5_25.sv[10],
- subp->sub5_25.sv[11], subp->sub5_25.sv[12],
- subp->sub5_25.sv[13], subp->sub5_25.sv[14],
- subp->sub5_25.sv[15], subp->sub5_25.sv[16],
- subp->sub5_25.sv[17], subp->sub5_25.sv[18],
- subp->sub5_25.sv[19], subp->sub5_25.sv[20],
- subp->sub5_25.sv[21], subp->sub5_25.sv[22],
- subp->sub5_25.sv[23], subp->sub5_25.sv[24]);
- } else {
- /* unknown page */
- GPSD_LOG(LOG_PROG, &session->context->errout,
- "50B: SF:5-%d data_id %d uknown page\n",
- subp->pageid, subp->data_id);
- return 0;
- }
- break;
- default:
- /* unknown/illegal subframe */
- return 0;
- }
- return SUBFRAME_SET;
- }
|