2019-08-09 07:58:52 -06:00
# include <stdio.h>
# include <string>
# include <iostream>
# include <arpa/inet.h>
# include "fmt/format.h"
# include "fmt/printf.h"
# include <fstream>
# include <map>
# include <bitset>
# include <vector>
# include <thread>
# include <signal.h>
2019-09-09 12:49:31 -06:00
# include <mutex>
2019-08-09 07:58:52 -06:00
# include "ext/powerblog/h2o-pp.hh"
# include "minicurl.hh"
# include <time.h>
# include "ubx.hh"
# include "bits.hh"
# include "minivec.hh"
# include "navmon.pb.h"
2019-08-12 07:54:16 -06:00
# include "ephemeris.hh"
# include "gps.hh"
2019-08-26 07:58:01 -06:00
# include "glonass.hh"
# include "beidou.hh"
2019-08-30 09:56:41 -06:00
# include "galileo.hh"
2019-09-02 08:13:49 -06:00
# include "tle.hh"
2019-08-12 17:15:25 -06:00
# include <optional>
2019-09-03 12:05:40 -06:00
# include "navmon.hh"
2019-09-02 08:13:49 -06:00
# include <Tle.h>
2019-10-12 06:57:44 -06:00
# include "navparse.hh"
2019-10-23 02:31:32 -06:00
# include <fenv.h>
2020-01-11 12:33:30 -07:00
# include "influxpush.hh"
2020-02-25 04:12:35 -07:00
# include "sbas.hh"
2020-07-03 15:08:52 -06:00
# include <sys/resource.h>
2020-02-11 08:54:41 -07:00
2020-01-21 11:13:29 -07:00
# include "CLI/CLI.hpp"
2020-02-11 08:39:29 -07:00
# include "gpscnav.hh"
2020-02-29 06:28:36 -07:00
# include "rtcm.hh"
2020-01-21 11:13:29 -07:00
# include "version.hh"
2020-11-11 08:45:25 -07:00
//#include "nequick.hh"
2020-02-29 06:28:36 -07:00
2020-01-21 11:13:29 -07:00
static char program [ ] = " navparse " ;
2019-10-23 02:31:32 -06:00
2019-08-09 07:58:52 -06:00
using namespace std ;
2020-01-21 11:13:29 -07:00
extern const char * g_gitHash ;
2020-07-29 11:46:51 -06:00
struct ObserverFacts
2019-09-16 06:33:06 -06:00
{
Point pos ;
2019-11-26 11:12:37 -07:00
double groundSpeed { - 1 } ;
2020-01-09 06:33:02 -07:00
double accuracy { - 1.0 } ;
string serialno ;
string hwversion ;
string swversion ;
string mods ;
string vendor ;
double clockOffsetNS { - 1 } ;
double clockOffsetDriftNS { - 1 } ;
double clockAccuracyNS { - 1 } ;
double freqAccuracyPS { - 1 } ;
time_t uptime ;
string githash ;
string owner ;
string remark ;
2019-09-16 06:33:06 -06:00
time_t lastSeen { 0 } ;
} ;
2020-07-29 11:46:51 -06:00
std : : map < int , ObserverFacts > g_srcpos ;
2019-08-09 07:58:52 -06:00
2020-02-25 04:12:35 -07:00
struct SBASAndReceiverStatus
2020-02-11 08:39:29 -07:00
{
2020-02-25 04:12:35 -07:00
SBASState status ;
2020-02-11 08:39:29 -07:00
struct PerRecv
{
time_t last_seen { 0 } ;
} ;
map < int , PerRecv > perrecv ;
} ;
2020-02-25 04:12:35 -07:00
typedef map < int , SBASAndReceiverStatus > sbas_t ;
2020-02-11 08:39:29 -07:00
sbas_t g_sbas ;
GetterSetter < sbas_t > g_sbaskeeper ;
2019-09-03 12:05:40 -06:00
map < int , BeidouAlmanacEntry > g_beidoualma ;
map < int , pair < GlonassMessage , GlonassMessage > > g_glonassalma ;
2019-09-05 01:35:13 -06:00
map < int , GalileoMessage : : Almanac > g_galileoalma ;
2019-09-09 12:49:31 -06:00
map < int , GPSAlmanac > g_gpsalma ;
GetterSetter < map < int , BeidouAlmanacEntry > > g_beidoualmakeeper ;
GetterSetter < map < int , pair < GlonassMessage , GlonassMessage > > > g_glonassalmakeeper ;
GetterSetter < map < int , GalileoMessage : : Almanac > > g_galileoalmakeeper ;
GetterSetter < map < int , GPSAlmanac > > g_gpsalmakeeper ;
2019-09-02 08:13:49 -06:00
TLERepo g_tles ;
2019-08-09 16:54:35 -06:00
struct GNSSReceiver
{
Point position ;
} ;
2020-02-25 04:12:35 -07:00
double g_GSTUTCOffset , g_GSTGPSOffset , g_GPSUTCOffset , g_BeiDouUTCOffset , g_GlonassUTCOffset , g_GlonassGPSOffset ;
/*
The situation . We have a single ephemeris function that is able to operate on
Galileo , GPS1 and Beidou structs . It does so using functions like getT0e ( ) .
This ephemeris function also does speed and doppler .
We have structs for all four GNSS .
All GNSS have ephemerides that are spread out over multiple messages .
Because of that , we have to do some kind of atomic update .
We also have an SVStat that has some knowledge about IODs .
It would be great is we could ask the svstat about " the latest ephemeris "
and get a useful answer .
More concretely , we could ask the svstat about the latest * position * or * speed * .
It would be easier to do that . There is no unified " ephemeris object " between all the GNSS .
2019-08-09 16:54:35 -06:00
2020-02-25 04:12:35 -07:00
We do need a unified " do we have a complete ephemeris method " .
2019-08-30 09:56:41 -06:00
2020-02-25 04:12:35 -07:00
For Galileo this is messages 1 , 2 , 3 and 4
For GPS it is 2 and 3
For BeiDou it is message 2 and message 3 in succession ( ? )
sow is in each message , forms a link
For GLONASS I don ' t really know
2019-08-30 09:56:41 -06:00
2020-02-25 04:12:35 -07:00
We also care about ephemeris discontinuities .
2019-08-09 07:58:52 -06:00
2020-02-25 04:12:35 -07:00
Idea is that SVStat has four structs around , one for each GNSS , each containing " the lastest complete ephemeris " .
ephglomsg etc
It also has infrastructure for storing the ephemerides as they are being assembled .
Open question :
*/
// XXX conversion glonass??
int SVStat : : wn ( ) const
2019-08-09 07:58:52 -06:00
{
2020-02-25 04:12:35 -07:00
if ( gnss = = 0 )
return gpsmsg . wn ;
else if ( gnss = = 2 )
return galmsg . wn ;
else if ( gnss = = 3 )
return beidoumsg . wn ;
else if ( gnss = = 6 ) {
uint32_t glotime = glonassMessage . getGloTime ( ) ; // this starts GLONASS time at 31st of december 1995, 00:00 UTC
return glotime / ( 7 * 86400 ) ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
return 0 ;
}
int SVStat : : tow ( ) const
{
if ( gnss = = 0 )
return gpsmsg . tow ;
else if ( gnss = = 2 )
return galmsg . tow ;
else if ( gnss = = 3 )
return beidoumsg . sow ;
else if ( gnss = = 6 ) {
uint32_t glotime = glonassMessage . getGloTime ( ) ; // this starts GLONASS time at 31st of december 1995, 00:00 UTC
return glotime % ( 7 * 86400 ) ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
return 0 ;
}
2019-08-09 07:58:52 -06:00
2020-02-25 04:12:35 -07:00
const GPSLikeEphemeris & SVStat : : liveIOD ( ) const
{
if ( gnss = = 0 )
return ephgpsmsg ;
else if ( gnss = = 2 )
return ephgalmsg ;
else if ( gnss = = 3 )
return ephBeidoumsg ;
throw std : : runtime_error ( " Asked for GPS like ephemeris for gnss " + to_string ( gnss ) ) ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
const GPSLikeEphemeris & SVStat : : prevIOD ( ) const
{
if ( gnss = = 0 )
return oldephgpsmsg ;
else if ( gnss = = 2 )
return oldephgalmsg ;
else if ( gnss = = 3 )
return oldephBeidoumsg ;
throw std : : runtime_error ( " Asked for old-GPS like ephemeris for gnss " + to_string ( gnss ) ) ;
}
2019-08-09 07:58:52 -06:00
bool SVStat : : completeIOD ( ) const
{
2020-02-25 04:12:35 -07:00
if ( gnss = = 6 )
return false ;
// yeah now what
return true ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
double SVStat : : getCoordinates ( double tow , Point * p , bool quiet ) const
2019-08-09 07:58:52 -06:00
{
2020-02-25 04:12:35 -07:00
if ( gnss = = 6 )
return : : getCoordinates ( tow , ephglomsg , p ) ;
// getCoordinates needs to be overloaded for GLONASS
return : : getCoordinates ( tow , liveIOD ( ) , p , quiet ) ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
double SVStat : : getOldEphCoordinates ( double tow , Point * p , bool quiet ) const
2019-08-09 07:58:52 -06:00
{
2020-02-25 04:12:35 -07:00
if ( gnss = = 6 )
return : : getCoordinates ( tow , oldephglomsg , p ) ;
// getCoordinates needs to be overloaded for GLONASS
return : : getCoordinates ( tow , prevIOD ( ) , p , quiet ) ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
void SVStat : : getSpeed ( double tow , Vector * v ) const
2019-08-09 07:58:52 -06:00
{
2020-02-25 04:12:35 -07:00
return : : getSpeed ( tow , liveIOD ( ) , v ) ;
}
DopplerData SVStat : : doDoppler ( double tow , const Point & us , double freq ) const
{
if ( gnss = = 6 )
return : : doDoppler ( tow , us , ephglomsg , freq ) ;
else
return : : doDoppler ( tow , us , liveIOD ( ) , freq ) ;
2019-08-12 07:54:16 -06:00
}
2019-08-09 07:58:52 -06:00
2020-02-25 04:12:35 -07:00
double satUTCTime ( const SatID & id ) ;
void SVStat : : reportNewEphemeris ( const SatID & id , InfluxPusher & idb )
2019-08-12 07:54:16 -06:00
{
2020-02-25 04:12:35 -07:00
int ephage ;
if ( gnss = = 6 )
ephage = ephAge ( ephglomsg . getT0e ( ) , oldephglomsg . getT0e ( ) ) ;
else
ephage = ephAge ( liveIOD ( ) . getT0e ( ) , prevIOD ( ) . getT0e ( ) ) ;
Point p , oldp ;
getCoordinates ( tow ( ) , & p ) ;
getOldEphCoordinates ( tow ( ) , & oldp ) ;
2019-08-11 02:43:29 -06:00
2020-02-25 04:12:35 -07:00
double hours = ephage / 3600 ;
double disco = Vector ( p , oldp ) . length ( ) ;
// cout<<id.first<<","<<id.second<<" discontinuity after "<< hours<<" hours: "<< disco <<endl;
if ( hours < 4 ) {
latestDisco = disco ;
latestDiscoAge = ephage ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
else
latestDisco = - 1 ;
2020-07-03 15:00:55 -06:00
if ( gnss = = 0 ) { // GPS
const auto & eg = ephgpsmsg ;
idb . addValue ( id , " ephemeris-actual " , {
{ " iod " , eg . getIOD ( ) } ,
{ " t0e " , eg . t0e } ,
{ " sqrta " , eg . sqrtA } ,
{ " e " , eg . e } ,
{ " cuc " , eg . cuc } ,
{ " cus " , eg . cus } ,
{ " crc " , eg . crc } ,
{ " crs " , eg . crs } ,
{ " m0 " , eg . m0 } ,
{ " deltan " , eg . deltan } ,
{ " i0 " , eg . i0 } ,
{ " cic " , eg . cic } ,
{ " cis " , eg . cis } ,
{ " omegadot " , eg . omegadot } ,
{ " omega0 " , eg . omega0 } ,
{ " idot " , eg . idot } ,
{ " af0 " , eg . af0 } ,
{ " af1 " , eg . af1 } ,
{ " af2 " , eg . af2 } ,
{ " t0c " , eg . t0c } ,
{ " omega " , eg . omega } } , satUTCTime ( id ) ) ;
}
2020-06-17 12:49:34 -06:00
if ( gnss = = 2 ) {
const auto & eg = ephgalmsg ;
idb . addValue ( id , " ephemeris-actual " , {
{ " iod " , eg . getIOD ( ) } ,
{ " t0e " , eg . t0e } ,
{ " sqrta " , eg . sqrtA } ,
{ " e " , eg . e } ,
{ " cuc " , eg . cuc } ,
{ " cus " , eg . cus } ,
{ " crc " , eg . crc } ,
{ " crs " , eg . crs } ,
{ " m0 " , eg . m0 } ,
{ " deltan " , eg . deltan } ,
{ " i0 " , eg . i0 } ,
{ " cic " , eg . cic } ,
{ " cis " , eg . cis } ,
{ " omegadot " , eg . omegadot } ,
{ " omega0 " , eg . omega0 } ,
{ " idot " , eg . idot } ,
2020-07-03 15:00:55 -06:00
{ " af0 " , eg . af0 } ,
{ " af1 " , eg . af1 } ,
{ " af2 " , eg . af2 } ,
{ " t0c " , eg . t0c } ,
2020-06-17 12:49:34 -06:00
{ " omega " , eg . omega } } , satUTCTime ( id ) ) ;
}
2020-02-25 04:12:35 -07:00
if ( hours < 24 ) {
idb . addValue ( id , " eph-disco " ,
{ { " meters " , disco } ,
{ " seconds " , hours * 3600.0 } ,
{ " oldx " , oldp . x } ,
{ " oldy " , oldp . y } ,
{ " oldz " , oldp . z } ,
{ " x " , p . x } ,
{ " y " , p . y } ,
{ " z " , p . z } ,
{ " iod " , gnss = = 6 ? - 1.0 : 1.0 * liveIOD ( ) . getIOD ( ) } ,
{ " oldiod " , gnss = = 6 ? - 1.0 : 1.0 * prevIOD ( ) . getIOD ( ) } } , satUTCTime ( id ) ) ;
2019-08-09 07:58:52 -06:00
}
2019-09-09 12:49:31 -06:00
2020-02-25 04:12:35 -07:00
2019-08-09 07:58:52 -06:00
}
2019-09-16 06:33:06 -06:00
2020-02-25 04:12:35 -07:00
2019-09-09 12:49:31 -06:00
svstats_t g_svstats ;
2019-08-09 07:58:52 -06:00
2019-09-16 06:33:06 -06:00
GetterSetter < svstats_t > g_statskeeper ;
2019-08-09 07:58:52 -06:00
2019-09-09 12:49:31 -06:00
int latestWN ( int gnssid , const svstats_t & stats )
2019-08-09 07:58:52 -06:00
{
2019-09-16 06:33:06 -06:00
map < int , SatID > ages ;
2019-09-09 12:49:31 -06:00
for ( const auto & s : stats )
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = ( unsigned int ) gnssid )
2020-02-25 04:12:35 -07:00
ages [ 7 * s . second . wn ( ) * 86400 + s . second . tow ( ) ] = s . first ;
2019-08-09 07:58:52 -06:00
if ( ages . empty ( ) )
2020-02-25 04:12:35 -07:00
throw runtime_error ( " Asked for latest WN for " + to_string ( gnssid ) + " : we don't know it yet ( " + to_string ( stats . size ( ) ) + " ) " ) ;
2019-09-09 12:49:31 -06:00
2020-02-25 04:12:35 -07:00
return stats . find ( ages . rbegin ( ) - > second ) - > second . wn ( ) ;
2019-08-09 07:58:52 -06:00
}
2019-09-09 12:49:31 -06:00
int latestTow ( int gnssid , const svstats_t & stats )
2019-08-09 07:58:52 -06:00
{
2019-09-16 06:33:06 -06:00
map < int , SatID > ages ;
2019-09-09 12:49:31 -06:00
for ( const auto & s : stats )
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = ( unsigned int ) gnssid )
2020-02-25 04:12:35 -07:00
ages [ 7 * s . second . wn ( ) * 86400 + s . second . tow ( ) ] = s . first ;
2019-08-09 07:58:52 -06:00
if ( ages . empty ( ) )
2020-02-25 04:12:35 -07:00
throw runtime_error ( " Asked for latest TOW for " + to_string ( gnssid ) + " : we don't know it yet ( " + to_string ( stats . size ( ) ) + " ) " ) ;
return stats . find ( ages . rbegin ( ) - > second ) - > second . tow ( ) ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
// nanoseconds posix time from that gnss WN and TOW
2019-09-16 06:33:06 -06:00
int64_t nanoTime ( int gnssid , int wn , double tow )
2019-08-09 07:58:52 -06:00
{
2019-08-29 04:45:37 -06:00
int offset ;
if ( gnssid = = 0 ) // GPS
offset = 315964800 ;
if ( gnssid = = 2 ) // Galileo, 22-08-1999
offset = 935280000 ;
2019-09-02 08:13:49 -06:00
if ( gnssid = = 3 ) { // Beidou, 01-01-2006 - I think leap seconds count differently in Beidou!! XXX
2019-08-29 04:45:37 -06:00
offset = 1136073600 ;
2019-09-02 08:13:49 -06:00
return 1000000000ULL * ( offset + wn * 7 * 86400 + tow - g_dtLSBeidou ) ;
}
2019-08-30 09:56:41 -06:00
if ( gnssid = = 6 ) { // GLONASS
offset = 820368000 ;
return 1000000000ULL * ( offset + wn * 7 * 86400 + tow ) ; // no leap seconds in glonass
}
2019-08-12 17:15:25 -06:00
2019-08-30 09:56:41 -06:00
return 1000000000ULL * ( offset + wn * 7 * 86400 + tow - g_dtLS ) ;
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
// same in seconds
2020-01-11 12:33:30 -07:00
double satUTCTime ( const SatID & id )
2019-08-09 07:58:52 -06:00
{
2020-02-25 04:12:35 -07:00
return nanoTime ( id . gnss , g_svstats [ id ] . wn ( ) , g_svstats [ id ] . tow ( ) ) / 1000000000.0 ;
2020-01-11 12:33:30 -07:00
}
2019-08-09 07:58:52 -06:00
/* The GST start epoch is defined as 13 seconds before midnight between 21st August and
22 nd August 1999 , i . e . GST was equal to 13 seconds at 22 nd August 1999 00 : 00 : 00 UTC . */
2019-09-09 12:49:31 -06:00
std : : string humanTime ( int gnssid , int wn , int tow )
2019-08-09 07:58:52 -06:00
{
2019-09-09 12:49:31 -06:00
time_t t = nanoTime ( gnssid , wn , tow ) / 1000000000 ;
2019-08-09 07:58:52 -06:00
struct tm tm ;
gmtime_r ( & t , & tm ) ;
char buffer [ 80 ] ;
strftime ( buffer , sizeof ( buffer ) , " %a, %d %b %Y %T %z " , & tm ) ;
return buffer ;
}
2019-12-26 14:01:54 -07:00
std : : optional < double > getHzCorrection ( time_t now , int src , unsigned int gnssid , unsigned int sigid , const svstats_t & svstats )
2019-08-12 17:15:25 -06:00
{
2019-09-18 06:17:41 -06:00
2019-09-16 09:21:53 -06:00
std : : optional < double > allHzCorr ;
double alltot = 0 ;
int allcount = 0 ;
2019-09-18 06:17:41 -06:00
// cout<<"getHzCorrection called for src "<<src<<" gnss "<<gnssid <<" sigid "<< sigid <<endl;
2019-09-09 12:49:31 -06:00
for ( const auto & s : svstats ) {
2019-09-16 09:21:53 -06:00
if ( s . first . gnss ! = gnssid )
continue ;
if ( s . first . sigid ! = sigid )
continue ;
2019-09-18 06:17:41 -06:00
if ( auto iter = s . second . perrecv . find ( src ) ; iter ! = s . second . perrecv . end ( ) & & now - iter - > second . deltaHzTime < 60 ) {
// cout<<" Found entry for SV "<<s.first.gnss<<","<<s.first.sv<<","<<s.first.sigid<<" from src "<<iter->first<<", deltaHz: "<<iter->second.deltaHz<< " age " << now - iter->second.deltaHzTime<<" db "<<iter->second.db<<endl;
2019-09-16 09:21:53 -06:00
alltot + = iter - > second . deltaHz ;
2019-08-12 17:15:25 -06:00
allcount + + ;
}
}
2019-09-18 06:17:41 -06:00
if ( allcount > 3 ) {
2019-08-12 17:15:25 -06:00
allHzCorr = alltot / allcount ;
2019-09-18 06:17:41 -06:00
// cout<<"Returning "<<*allHzCorr<<endl;
}
else
; // cout<<"Not enough data"<<endl;
2019-08-12 17:15:25 -06:00
return allHzCorr ;
}
2019-08-26 07:58:01 -06:00
2019-09-09 12:49:31 -06:00
std : : string humanBhs ( int bhs )
{
static vector < string > options { " ok " , " out of service " , " will be out of service " , " test " } ;
2019-10-12 06:57:44 -06:00
if ( bhs > = ( int ) options . size ( ) ) {
2019-10-01 07:03:30 -06:00
cerr < < " Asked for humanBHS " < < bhs < < endl ;
return " ?? " ;
}
2019-09-09 12:49:31 -06:00
return options . at ( bhs ) ;
}
2019-11-02 14:25:07 -06:00
void addHeaders ( h2o_req_t * req )
{
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_CACHE_CONTROL ,
NULL , H2O_STRLIT ( " max-age=3 " ) ) ;
// Access-Control-Allow-Origin
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN ,
NULL , H2O_STRLIT ( " * " ) ) ;
}
2020-07-03 15:08:52 -06:00
time_t getSatelliteUTC ( svstats_t & svstats )
{
time_t ret ;
try {
ret = utcFromGST ( latestWN ( 2 , svstats ) , latestTow ( 2 , svstats ) ) ;
}
catch ( . . . )
{
ret = utcFromGPS ( latestWN ( 0 , svstats ) , latestTow ( 0 , svstats ) ) ;
// if this throws, we are done
}
return ret ;
}
static double get_cpu_seconds_total ( )
{
struct rusage usage ;
getrusage ( RUSAGE_SELF , & usage ) ;
return usage . ru_utime . tv_sec + usage . ru_utime . tv_usec / 1000000.0 + usage . ru_stime . tv_sec + usage . ru_stime . tv_usec / 1000000.0 ;
}
void storeSelfStats ( InfluxPusher & idb , time_t t )
{
map < int , int > receivers ;
time_t now ;
try {
now = getSatelliteUTC ( g_svstats ) ;
}
catch ( . . . ) {
return ;
}
map < SatID , int > svcount , sigcount ;
map < int , int > siggnsscount , svgnsscount ;
for ( const auto & sv : g_svstats ) {
bool fresh = false ;
for ( const auto & pr : sv . second . perrecv ) {
int age = now - pr . second . t ;
if ( age < 30 ) {
fresh = true ;
receivers [ pr . first ] + + ;
}
}
if ( fresh ) {
sigcount [ sv . first ] + + ;
siggnsscount [ sv . first . gnss ] + + ;
SatID id = sv . first ;
id . sigid = 0 ;
svcount [ id ] + + ;
}
}
for ( const auto & sv : svcount )
svgnsscount [ sv . first . gnss ] + + ;
vector < pair < string , InfluxPusher : : var_t > > tags ;
idb . addValue ( tags , " self " , {
{ " measurements " , idb . d_nummsmts } ,
{ " dedup-msmts " , idb . d_numdedupmsmts } ,
{ " values " , idb . d_numvalues } ,
{ " total-live-svs " , ( int64_t ) svcount . size ( ) } ,
{ " total-live-signals " , ( int64_t ) sigcount . size ( ) } ,
{ " gps-svs " , svgnsscount [ 0 ] } ,
{ " galileo-svs " , svgnsscount [ 2 ] } ,
{ " beidou-svs " , svgnsscount [ 3 ] } ,
{ " glonass-svs " , svgnsscount [ 6 ] } ,
{ " gps-sigs " , siggnsscount [ 0 ] } ,
{ " galileo-sigs " , siggnsscount [ 2 ] } ,
{ " beidou-sigs " , siggnsscount [ 3 ] } ,
{ " glonass-sigs " , siggnsscount [ 6 ] } ,
{ " total-cpu-msec " , 1000.0 * get_cpu_seconds_total ( ) } ,
{ " total-live-receivers " , ( int64_t ) receivers . size ( ) }
} , t ) ;
for ( const auto & p : idb . d_msmtmap ) {
idb . addValue ( { { " metric " , p . first } } , " msmts " , { { " value " , p . second } } , t ) ;
}
}
// GALILEO ONLY FOR NOW
void storeCoverageStats ( InfluxPusher & idb , time_t t )
try {
int tow ;
tow = latestTow ( 2 , g_svstats ) ;
vector < Point > sats ;
for ( const auto & g : g_galileoalma ) {
Point sat ;
getCoordinates ( tow , g . second , & sat ) ;
if ( g . first < 0 )
continue ;
SatID id { 2 , ( uint32_t ) g . first , 1 } ;
const auto & svstat = g_svstats [ id ] ;
if ( svstat . completeIOD ( ) & & svstat . galmsg . sisa = = 255 ) {
continue ;
}
if ( svstat . galmsg . e1bhs | | svstat . galmsg . e1bdvs ) {
continue ;
}
sats . push_back ( sat ) ;
}
2020-12-06 06:29:32 -07:00
vector < SatID > aux { { 2 , 14 , 1 } , { 2 , 18 , 1 } } ;
for ( const auto & id : aux ) {
if ( ! g_svstats . count ( id ) )
continue ;
const auto & svstat = g_svstats [ id ] ;
if ( svstat . completeIOD ( ) & & svstat . galmsg . sisa = = 255 ) {
continue ;
}
if ( svstat . galmsg . e1bhs | | svstat . galmsg . e1bdvs ) {
continue ;
}
Point sat ;
getCoordinates ( tow , svstat . galmsg , & sat ) ;
sats . push_back ( sat ) ;
}
2020-07-03 15:08:52 -06:00
// cout<<endl;
auto cov = emitCoverage ( sats ) ;
int cells = 0 ;
int pdopexceeds5 = 0 , pdopexceeds10 = 0 , pdopexceeds20 = 0 ;
int covlow5 = 0 , covlow10 = 0 , covlow20 = 0 ;
for ( const auto & latvect : cov ) {
for ( const auto & longpair : latvect . second ) {
cells + + ;
if ( get < 4 > ( longpair ) > = 6.0 | | get < 4 > ( longpair ) < 0.0 )
pdopexceeds5 + + ;
if ( get < 5 > ( longpair ) > = 6.0 | | get < 5 > ( longpair ) < 0.0 )
pdopexceeds10 + + ;
if ( get < 6 > ( longpair ) > = 6.0 | | get < 6 > ( longpair ) < 0.0 )
pdopexceeds20 + + ;
if ( get < 1 > ( longpair ) < 4 )
covlow5 + + ;
if ( get < 2 > ( longpair ) < 4 )
covlow10 + + ;
if ( get < 3 > ( longpair ) < 4 )
covlow20 + + ;
// else
//cout<<get<6>(longpair) << endl;
}
}
/*
fmt : : printf ( " At %s, %.2f%% (%d) of %d cells exceeded PDOP 6 for 5 degrees horizon (%d sats) \n " , humanTime ( t ) , 100.0 * pdopexceeds5 / cells , pdopexceeds5 , cells , sats . size ( ) ) ;
fmt : : printf ( " At %s, %.2f%% (%d) of %d cells exceeded PDOP 6 for 10 degrees horizon (%d sats) \n " , humanTime ( t ) , 100.0 * pdopexceeds10 / cells , pdopexceeds10 , cells , sats . size ( ) ) ;
fmt : : printf ( " At %s, %.2f%% (%d) of %d cells exceeded PDOP 6 for 20 degrees horizon (%d sats) \n " , humanTime ( t ) , 100.0 * pdopexceeds20 / cells , pdopexceeds20 , cells , sats . size ( ) ) ;
fmt : : printf ( " At %s, %.2f%% (%d) of %d cells have less than 4 sats in view for 5 degrees horizon (%d sats) \n " , humanTime ( t ) , 100.0 * covlow5 / cells , covlow5 , cells , sats . size ( ) ) ;
fmt : : printf ( " At %s, %.2f%% (%d) of %d cells have less than 4 sats in view for 10 degrees horizon (%d sats) \n " , humanTime ( t ) , 100.0 * covlow10 / cells , covlow10 , cells , sats . size ( ) ) ;
fmt : : printf ( " At %s, %.2f%% (%d) of %d cells have less than 4 sats in view for 20 degrees horizon (%d sats) \n " , humanTime ( t ) , 100.0 * covlow20 / cells , covlow20 , cells , sats . size ( ) ) ;
*/
idb . addValue ( { { " sigid " , 1 } , { " gnss " , 2 } } , " quality " , {
{ " pdop5perc " , 100.0 * pdopexceeds5 / cells } ,
{ " pdop10perc " , 100.0 * pdopexceeds10 / cells } ,
{ " pdop20perc " , 100.0 * pdopexceeds20 / cells } ,
{ " covlow5 " , 100.0 * covlow5 / cells } ,
{ " covlow10 " , 100.0 * covlow10 / cells } ,
{ " covlow20 " , 100.0 * covlow20 / cells } ,
{ " sats " , ( int ) sats . size ( ) }
} , t ) ;
}
catch ( std : : exception & e ) {
cout < < " Error with coverage: " < < e . what ( ) < < endl ;
}
2019-08-09 07:58:52 -06:00
int main ( int argc , char * * argv )
try
{
2020-01-21 11:13:29 -07:00
bool doVERSION { false } ;
CLI : : App app ( program ) ;
2020-01-26 05:20:20 -07:00
string localAddress ( " 127.0.0.1:29599 " ) ;
string htmlDir ( " ./html " ) ;
string influxDBName ( " null " ) ;
2020-07-29 03:38:32 -06:00
bool doGalileoReportSpeedup { false } ;
2020-07-03 15:08:52 -06:00
bool doLogRFData { false } ;
2020-01-21 11:13:29 -07:00
app . add_flag ( " --version " , doVERSION , " show program version and copyright " ) ;
2020-07-03 15:08:52 -06:00
app . add_flag ( " --log-rf-data " , doLogRFData , " store per station RF/correlator data " ) ;
2020-07-29 03:38:32 -06:00
app . add_flag ( " --gal-report-speedup " , doGalileoReportSpeedup , " skip debugging data, glonass, beidou, SBAS " ) ;
2020-01-26 05:20:20 -07:00
app . add_option ( " --bind,-b " , localAddress , " Address to bind to " ) ;
app . add_option ( " --html " , htmlDir , " Where to source the HTML & JavaScript " ) ;
2020-01-26 07:58:26 -07:00
app . add_option ( " --influxdb " , influxDBName , " Name of influxdb database " ) ;
2020-01-26 05:20:20 -07:00
2020-01-21 11:13:29 -07:00
try {
app . parse ( argc , argv ) ;
} catch ( const CLI : : Error & e ) {
return app . exit ( e ) ;
}
if ( doVERSION ) {
2020-01-22 15:45:29 -07:00
showVersion ( program , g_gitHash ) ;
2020-01-21 11:13:29 -07:00
exit ( 0 ) ;
}
2019-11-26 11:12:37 -07:00
// feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );
2019-10-23 02:31:32 -06:00
2020-07-29 03:38:32 -06:00
// g_tles.parseFile("active.txt");
2019-09-03 12:05:40 -06:00
2019-09-02 08:13:49 -06:00
g_tles . parseFile ( " galileo.txt " ) ;
g_tles . parseFile ( " glo-ops.txt " ) ;
g_tles . parseFile ( " gps-ops.txt " ) ;
g_tles . parseFile ( " beidou.txt " ) ;
2019-09-09 12:49:31 -06:00
2019-09-03 12:05:40 -06:00
2019-08-09 07:58:52 -06:00
signal ( SIGPIPE , SIG_IGN ) ;
2020-01-26 05:20:20 -07:00
InfluxPusher idb ( influxDBName ) ;
2019-08-09 07:58:52 -06:00
MiniCurl : : init ( ) ;
H2OWebserver h2s ( " galmon " ) ;
2019-08-09 08:50:26 -06:00
2019-09-22 08:42:23 -06:00
h2s . addHandler ( " /global.json " , [ ] ( auto handler , auto req ) {
2019-11-02 14:25:07 -06:00
addHeaders ( req ) ;
2019-08-09 07:58:52 -06:00
nlohmann : : json ret = nlohmann : : json : : object ( ) ;
2019-09-09 12:49:31 -06:00
auto svstats = g_statskeeper . get ( ) ;
2019-08-09 07:58:52 -06:00
ret [ " leap-seconds " ] = g_dtLS ;
2019-08-12 07:54:16 -06:00
try {
2020-02-25 04:12:35 -07:00
// if we haven't seen galileo, we have no idea
2019-09-09 12:49:31 -06:00
ret [ " last-seen " ] = utcFromGST ( latestWN ( 2 , svstats ) , latestTow ( 2 , svstats ) ) ;
2019-08-12 07:54:16 -06:00
}
catch ( . . . )
2020-05-14 01:44:26 -06:00
{
try {
ret [ " last-seen " ] = utcFromGPS ( latestWN ( 0 , svstats ) , latestTow ( 0 , svstats ) ) ;
}
catch ( . . . )
{ }
}
2019-08-12 07:54:16 -06:00
2020-02-25 04:12:35 -07:00
ret [ " gst-utc-offset-ns " ] = g_GSTUTCOffset ;
ret [ " gst-gps-offset-ns " ] = g_GSTGPSOffset ;
ret [ " gps-utc-offset-ns " ] = g_GPSUTCOffset ;
ret [ " beidou-utc-offset-ns " ] = g_BeiDouUTCOffset ;
ret [ " glonass-utc-offset-ns " ] = g_GlonassUTCOffset ;
ret [ " glonass-gps-offset-ns " ] = g_GlonassGPSOffset ;
map < int , int > siggnsscount , svgnsscount ;
map < SatID , int > svcount , sigcount ;
map < int , int > receivers ;
time_t now = time ( 0 ) ;
for ( const auto & sv : svstats ) {
bool fresh = false ;
for ( const auto & pr : sv . second . perrecv ) {
int age = now - pr . second . t ;
if ( age < 30 ) {
fresh = true ;
receivers [ pr . first ] + + ;
}
2019-08-18 02:56:22 -06:00
}
2020-02-25 04:12:35 -07:00
if ( fresh ) {
2019-08-18 02:56:22 -06:00
2020-02-25 04:12:35 -07:00
sigcount [ sv . first ] + + ;
siggnsscount [ sv . first . gnss ] + + ;
SatID id = sv . first ;
id . sigid = 0 ;
svcount [ id ] + + ;
}
2019-08-18 02:56:22 -06:00
}
2020-02-25 04:12:35 -07:00
for ( const auto & sv : svcount )
svgnsscount [ sv . first . gnss ] + + ;
ret [ " total-live-receivers " ] = receivers . size ( ) ;
ret [ " total-live-svs " ] = svcount . size ( ) ;
ret [ " total-live-signals " ] = sigcount . size ( ) ;
ret [ " gps-svs " ] = svgnsscount [ 0 ] ;
ret [ " galileo-svs " ] = svgnsscount [ 2 ] ;
ret [ " beidou-svs " ] = svgnsscount [ 3 ] ;
ret [ " glonass-svs " ] = svgnsscount [ 6 ] ;
ret [ " gps-sigs " ] = siggnsscount [ 0 ] ;
ret [ " galileo-sigs " ] = siggnsscount [ 2 ] ;
ret [ " beidou-sigs " ] = siggnsscount [ 3 ] ;
ret [ " glonass-sigs " ] = siggnsscount [ 6 ] ;
2019-08-18 02:56:22 -06:00
2019-09-03 12:05:40 -06:00
return ret ;
} ) ;
2019-09-22 08:42:23 -06:00
h2s . addHandler ( " /almanac.json " , [ ] ( auto handler , auto req ) {
2019-11-02 14:25:07 -06:00
addHeaders ( req ) ;
2019-09-09 12:49:31 -06:00
auto beidoualma = g_beidoualmakeeper . get ( ) ;
auto svstats = g_statskeeper . get ( ) ;
2019-09-03 12:05:40 -06:00
nlohmann : : json ret = nlohmann : : json : : object ( ) ;
2019-09-09 12:49:31 -06:00
for ( const auto & ae : beidoualma ) {
2019-09-03 12:05:40 -06:00
nlohmann : : json item = nlohmann : : json : : object ( ) ;
2019-09-09 12:49:31 -06:00
item [ " gnssid " ] = 3 ;
2019-09-03 12:05:40 -06:00
if ( ae . second . alma . getT0e ( ) > 7 * 86400 )
continue ;
Point sat ;
2019-09-16 06:33:06 -06:00
getCoordinates ( latestTow ( 3 , svstats ) , ae . second . alma , & sat ) ;
2019-09-03 12:05:40 -06:00
item [ " eph-ecefX " ] = sat . x / 1000 ;
item [ " eph-ecefY " ] = sat . y / 1000 ;
item [ " eph-ecefZ " ] = sat . z / 1000 ;
auto longlat = getLongLat ( sat . x , sat . y , sat . z ) ;
item [ " eph-longitude " ] = 180 * longlat . first / M_PI ;
item [ " eph-latitude " ] = 180 * longlat . second / M_PI ;
item [ " t0e " ] = ae . second . alma . getT0e ( ) ;
2019-09-09 12:49:31 -06:00
item [ " t " ] = ephAge ( ae . second . alma . getT0e ( ) , latestTow ( 3 , svstats ) ) / 86400.0 ;
item [ " inclination " ] = 180 * ae . second . alma . getI0 ( ) / M_PI ;
2019-09-16 06:33:06 -06:00
item [ " observed " ] = false ;
if ( auto iter = svstats . find ( { 3 , ( uint32_t ) ae . first , 0 } ) ; iter ! = svstats . end ( ) ) {
2020-02-25 04:12:35 -07:00
if ( time ( 0 ) - nanoTime ( 3 , iter - > second . wn ( ) , iter - > second . tow ( ) ) / 1000000000 < 300 )
2019-09-16 06:33:06 -06:00
item [ " observed " ] = true ;
}
2019-09-09 12:49:31 -06:00
if ( ephAge ( ae . second . alma . getT0e ( ) , latestTow ( 3 , svstats ) ) < 0 ) {
auto match = g_tles . getBestMatch ( nanoTime ( 3 , latestWN ( 3 , svstats ) , latestTow ( 3 , svstats ) ) / 1000000000.0 ,
2019-09-03 12:05:40 -06:00
sat . x , sat . y , sat . z ) ;
if ( match . distance < 200000 ) {
item [ " best-tle " ] = match . name ;
item [ " best-tle-norad " ] = match . norad ;
item [ " best-tle-int-desig " ] = match . internat ;
item [ " best-tle-dist " ] = match . distance / 1000.0 ;
item [ " tle-ecefX " ] = match . ecefX / 1000 ;
item [ " tle-ecefY " ] = match . ecefY / 1000 ;
item [ " tle-ecefZ " ] = match . ecefZ / 1000 ;
item [ " tle-eciX " ] = match . eciX / 1000 ;
item [ " tle-eciY " ] = match . eciY / 1000 ;
item [ " tle-eciZ " ] = match . eciZ / 1000 ;
item [ " tle-latitude " ] = 180 * match . latitude / M_PI ;
item [ " tle-longitude " ] = 180 * match . longitude / M_PI ;
item [ " tle-altitude " ] = match . altitude ;
}
}
2019-09-24 13:18:35 -06:00
auto name = fmt : : sprintf ( " C%02d " , ae . first ) ;
item [ " name " ] = name ;
ret [ name ] = item ;
2019-09-03 12:05:40 -06:00
}
2019-09-09 12:49:31 -06:00
auto glonassalma = g_glonassalmakeeper . get ( ) ;
for ( const auto & ae : glonassalma ) {
2019-09-03 12:05:40 -06:00
nlohmann : : json item = nlohmann : : json : : object ( ) ;
// ae.second.first -> even ae.second.sceond -> odd
2019-09-09 12:49:31 -06:00
item [ " gnssid " ] = 6 ;
2019-09-03 12:05:40 -06:00
item [ " e " ] = ae . second . first . getE ( ) ;
item [ " inclination " ] = 180 * ae . second . first . getI0 ( ) / M_PI ;
item [ " health " ] = ae . second . first . CnA ;
item [ " tlambdana " ] = ae . second . second . gettLambdaNa ( ) ;
item [ " lambdana " ] = ae . second . second . getLambdaNaDeg ( ) ;
item [ " hna " ] = ae . second . second . hna ;
2019-09-16 06:33:06 -06:00
item [ " observed " ] = false ;
for ( uint32_t sigid : { 0 , 1 , 2 } ) { // XXX SIGIDS
if ( auto iter = svstats . find ( { 6 , ( uint32_t ) ae . first , sigid } ) ; iter ! = svstats . end ( ) ) {
2020-02-25 04:12:35 -07:00
if ( time ( 0 ) - nanoTime ( 6 , iter - > second . wn ( ) , iter - > second . tow ( ) ) / 1000000000 < 300 ) {
2019-09-16 06:33:06 -06:00
item [ " observed " ] = true ;
auto longlat = getLongLat ( iter - > second . glonassMessage . x , iter - > second . glonassMessage . y , iter - > second . glonassMessage . z ) ;
item [ " eph-longitude " ] = 180 * longlat . first / M_PI ;
item [ " eph-latitude " ] = 180 * longlat . second / M_PI ;
break ;
}
}
}
2019-09-24 13:18:35 -06:00
auto name = fmt : : sprintf ( " R%02d " , ae . first ) ;
item [ " name " ] = name ;
ret [ name ] = item ;
2019-09-03 12:05:40 -06:00
}
2019-09-05 01:35:13 -06:00
2019-09-09 12:49:31 -06:00
auto galileoalma = g_galileoalmakeeper . get ( ) ;
for ( const auto & ae : galileoalma ) {
2019-09-05 01:35:13 -06:00
nlohmann : : json item = nlohmann : : json : : object ( ) ;
2019-09-09 12:49:31 -06:00
item [ " gnssid " ] = 2 ;
2019-09-05 01:35:13 -06:00
item [ " e " ] = ae . second . getE ( ) ;
item [ " e1bhs " ] = ae . second . e1bhs ;
item [ " e5bhs " ] = ae . second . e5bhs ;
item [ " t0e " ] = ae . second . getT0e ( ) ;
2019-09-09 12:49:31 -06:00
item [ " t " ] = ephAge ( ae . second . getT0e ( ) , latestTow ( 2 , svstats ) ) / 86400.0 ;
item [ " eph-age " ] = ephAge ( latestTow ( 2 , svstats ) , ae . second . getT0e ( ) ) ;
2019-09-05 01:35:13 -06:00
item [ " i0 " ] = 180.0 * ae . second . getI0 ( ) / M_PI ;
2019-09-09 12:49:31 -06:00
item [ " inclination " ] = 180 * ae . second . getI0 ( ) / M_PI ;
2020-01-09 06:33:02 -07:00
item [ " omega " ] = ae . second . getOmega ( ) ;
item [ " sqrtA " ] = ae . second . getSqrtA ( ) ;
item [ " M0 " ] = ae . second . getM0 ( ) ;
item [ " delta-n " ] = ae . second . getDeltan ( ) ;
item [ " omega-dot " ] = ae . second . getOmegadot ( ) ;
item [ " omega0 " ] = ae . second . getOmega0 ( ) ;
item [ " idot " ] = ae . second . getIdot ( ) ;
item [ " t0e " ] = ae . second . getT0e ( ) ;
2019-09-05 01:35:13 -06:00
Point sat ;
2020-01-09 06:33:02 -07:00
double E = getCoordinates ( latestTow ( 2 , svstats ) , ae . second , & sat ) ;
item [ " E " ] = E ;
2019-09-05 01:35:13 -06:00
item [ " eph-ecefX " ] = sat . x / 1000 ;
item [ " eph-ecefY " ] = sat . y / 1000 ;
item [ " eph-ecefZ " ] = sat . z / 1000 ;
auto longlat = getLongLat ( sat . x , sat . y , sat . z ) ;
item [ " eph-longitude " ] = 180 * longlat . first / M_PI ;
item [ " eph-latitude " ] = 180 * longlat . second / M_PI ;
2019-09-16 06:33:06 -06:00
item [ " observed " ] = false ;
2022-06-16 11:31:05 -06:00
for ( uint32_t sigid : { 0 , 1 , 5 , 6 } ) {
2019-09-16 06:33:06 -06:00
if ( auto iter = svstats . find ( { 2 , ( uint32_t ) ae . first , sigid } ) ; iter ! = svstats . end ( ) ) {
2019-10-15 10:01:22 -06:00
if ( iter - > second . completeIOD ( ) ) {
2020-02-25 04:12:35 -07:00
item [ " sisa " ] = iter - > second . galmsg . sisa ;
2019-10-15 10:01:22 -06:00
}
// if we hit an 'observed', stop trying sigids
2020-02-25 04:12:35 -07:00
if ( time ( 0 ) - nanoTime ( 2 , iter - > second . wn ( ) , iter - > second . tow ( ) ) / 1000000000 < 300 ) {
2019-09-16 06:33:06 -06:00
item [ " observed " ] = true ;
2019-10-15 10:01:22 -06:00
break ;
}
2019-09-16 06:33:06 -06:00
}
}
2019-09-09 12:49:31 -06:00
auto match = g_tles . getBestMatch ( nanoTime ( 2 , latestWN ( 2 , svstats ) , latestTow ( 2 , svstats ) ) / 1000000000.0 ,
2019-09-05 01:35:13 -06:00
sat . x , sat . y , sat . z ) ;
if ( match . distance < 200000 ) {
item [ " best-tle " ] = match . name ;
item [ " best-tle-norad " ] = match . norad ;
item [ " best-tle-int-desig " ] = match . internat ;
item [ " best-tle-dist " ] = match . distance / 1000.0 ;
item [ " tle-ecefX " ] = match . ecefX / 1000 ;
item [ " tle-ecefY " ] = match . ecefY / 1000 ;
item [ " tle-ecefZ " ] = match . ecefZ / 1000 ;
item [ " tle-eciX " ] = match . eciX / 1000 ;
item [ " tle-eciY " ] = match . eciY / 1000 ;
item [ " tle-eciZ " ] = match . eciZ / 1000 ;
item [ " tle-latitude " ] = 180 * match . latitude / M_PI ;
item [ " tle-longitude " ] = 180 * match . longitude / M_PI ;
item [ " tle-altitude " ] = match . altitude ;
}
2019-09-24 13:18:35 -06:00
auto name = fmt : : sprintf ( " E%02d " , ae . first ) ;
item [ " name " ] = name ;
ret [ name ] = item ;
2019-09-05 01:35:13 -06:00
}
2019-09-09 12:49:31 -06:00
auto gpsalma = g_gpsalmakeeper . get ( ) ;
for ( const auto & ae : gpsalma ) {
nlohmann : : json item = nlohmann : : json : : object ( ) ;
item [ " gnssid " ] = 0 ;
item [ " e " ] = ae . second . getE ( ) ;
item [ " health " ] = ae . second . health ;
item [ " t0e " ] = ae . second . getT0e ( ) ;
2020-02-25 04:12:35 -07:00
item [ " t " ] = ephAge ( ae . second . getT0e ( ) , latestTow ( 0 , svstats ) ) / 86400.0 ;
item [ " eph-age " ] = ephAge ( latestTow ( 0 , svstats ) , ae . second . getT0e ( ) ) ;
2019-09-09 12:49:31 -06:00
item [ " i0 " ] = 180.0 * ae . second . getI0 ( ) / M_PI ;
item [ " inclination " ] = 180 * ae . second . getI0 ( ) / M_PI ;
Point sat ;
2019-09-16 06:33:06 -06:00
getCoordinates ( latestTow ( 0 , svstats ) , ae . second , & sat ) ;
2019-09-09 12:49:31 -06:00
item [ " eph-ecefX " ] = sat . x / 1000 ;
item [ " eph-ecefY " ] = sat . y / 1000 ;
item [ " eph-ecefZ " ] = sat . z / 1000 ;
auto longlat = getLongLat ( sat . x , sat . y , sat . z ) ;
item [ " eph-longitude " ] = 180 * longlat . first / M_PI ;
item [ " eph-latitude " ] = 180 * longlat . second / M_PI ;
2019-09-16 06:33:06 -06:00
item [ " observed " ] = false ;
2022-06-16 11:31:05 -06:00
for ( uint32_t sigid : { 0 , 1 , 4 , 6 } ) {
2019-09-16 06:33:06 -06:00
if ( auto iter = svstats . find ( { 0 , ( uint32_t ) ae . first , sigid } ) ; iter ! = svstats . end ( ) ) {
2020-02-25 04:12:35 -07:00
if ( time ( 0 ) - nanoTime ( 0 , iter - > second . wn ( ) , iter - > second . tow ( ) ) / 1000000000 < 300 )
2019-09-16 06:33:06 -06:00
item [ " observed " ] = true ;
}
}
2019-09-09 12:49:31 -06:00
auto match = g_tles . getBestMatch ( nanoTime ( 0 , latestWN ( 0 , svstats ) , latestTow ( 0 , svstats ) ) / 1000000000.0 ,
sat . x , sat . y , sat . z ) ;
if ( match . distance < 200000 ) {
item [ " best-tle " ] = match . name ;
item [ " best-tle-norad " ] = match . norad ;
item [ " best-tle-int-desig " ] = match . internat ;
item [ " best-tle-dist " ] = match . distance / 1000.0 ;
item [ " tle-ecefX " ] = match . ecefX / 1000 ;
item [ " tle-ecefY " ] = match . ecefY / 1000 ;
item [ " tle-ecefZ " ] = match . ecefZ / 1000 ;
item [ " tle-eciX " ] = match . eciX / 1000 ;
item [ " tle-eciY " ] = match . eciY / 1000 ;
item [ " tle-eciZ " ] = match . eciZ / 1000 ;
item [ " tle-latitude " ] = 180 * match . latitude / M_PI ;
item [ " tle-longitude " ] = 180 * match . longitude / M_PI ;
item [ " tle-altitude " ] = match . altitude ;
}
2019-09-24 13:18:35 -06:00
auto name = fmt : : sprintf ( " G%02d " , ae . first ) ;
item [ " name " ] = name ;
ret [ name ] = item ;
2019-09-09 12:49:31 -06:00
}
2019-09-03 12:05:40 -06:00
2019-08-09 07:58:52 -06:00
return ret ;
} ) ;
2019-09-09 12:49:31 -06:00
2019-09-22 08:42:23 -06:00
h2s . addHandler ( " /observers.json " , [ ] ( auto handler , auto req ) {
2019-11-02 14:25:07 -06:00
addHeaders ( req ) ;
2019-09-09 12:49:31 -06:00
nlohmann : : json ret = nlohmann : : json : : array ( ) ;
for ( const auto & src : g_srcpos ) {
nlohmann : : json obj ;
obj [ " id " ] = src . first ;
2020-01-09 06:33:02 -07:00
auto latlonh = ecefToWGS84 ( src . second . pos . x , src . second . pos . y , src . second . pos . z ) ;
get < 0 > ( latlonh ) * = 180.0 / M_PI ;
get < 1 > ( latlonh ) * = 180.0 / M_PI ;
get < 0 > ( latlonh ) = ( ( int ) ( 10 * get < 0 > ( latlonh ) ) ) / 10.0 ;
get < 1 > ( latlonh ) = ( ( int ) ( 10 * get < 1 > ( latlonh ) ) ) / 10.0 ;
get < 2 > ( latlonh ) = ( ( int ) ( 10 * get < 2 > ( latlonh ) ) ) / 10.0 ;
obj [ " latitude " ] = get < 0 > ( latlonh ) ;
obj [ " longitude " ] = get < 1 > ( latlonh ) ;
2019-09-16 06:33:06 -06:00
obj [ " last-seen " ] = src . second . lastSeen ;
2019-11-26 11:12:37 -07:00
obj [ " ground-speed " ] = src . second . groundSpeed ;
2020-01-09 06:33:02 -07:00
obj [ " swversion " ] = src . second . swversion ;
obj [ " hwversion " ] = src . second . hwversion ;
obj [ " mods " ] = src . second . mods ;
obj [ " serialno " ] = src . second . serialno ;
obj [ " clockoffsetns " ] = src . second . clockOffsetNS ;
obj [ " clockdriftns " ] = src . second . clockOffsetDriftNS ;
obj [ " clockacc " ] = src . second . clockAccuracyNS ;
obj [ " freqacc " ] = src . second . freqAccuracyPS ;
obj [ " uptime " ] = src . second . uptime ;
obj [ " githash " ] = src . second . githash ;
obj [ " owner " ] = src . second . owner ;
obj [ " vendor " ] = src . second . vendor ;
obj [ " remark " ] = src . second . remark ;
obj [ " acc " ] = src . second . accuracy ;
obj [ " h " ] = get < 2 > ( latlonh ) ;
2019-09-22 08:42:23 -06:00
auto svstats = g_statskeeper . get ( ) ;
nlohmann : : json svs = nlohmann : : json : : object ( ) ;
for ( const auto & sv : svstats ) {
if ( auto iter = sv . second . perrecv . find ( src . first ) ; iter ! = sv . second . perrecv . end ( ) ) {
2019-11-26 11:12:37 -07:00
if ( iter - > second . db > 0 & & time ( 0 ) - iter - > second . t < 120 ) {
2019-09-22 08:42:23 -06:00
nlohmann : : json svo = nlohmann : : json : : object ( ) ;
svo [ " db " ] = iter - > second . db ;
2019-12-10 16:11:16 -07:00
svo [ " elev " ] = roundf ( 10.0 * iter - > second . el ) / 10.0 ;
svo [ " azi " ] = roundf ( 10.0 * iter - > second . azi ) / 10.0 ;
2019-09-22 08:42:23 -06:00
Point sat ;
2020-01-09 06:33:02 -07:00
if ( ( sv . first . gnss = = 0 | | sv . first . gnss = = 2 ) & & sv . second . completeIOD ( ) ) {
2020-01-18 08:48:22 -07:00
svo [ " delta_hz " ] = truncPrec ( iter - > second . deltaHz , 2 ) ;
2020-01-09 06:33:02 -07:00
auto hzCorrection = getHzCorrection ( time ( 0 ) , src . first , sv . first . gnss , sv . first . sigid , svstats ) ;
if ( hzCorrection )
2020-01-18 08:48:22 -07:00
svo [ " delta_hz_corr " ] = truncPrec ( iter - > second . deltaHz - * hzCorrection , 2 ) ;
2020-01-09 06:33:02 -07:00
2020-02-25 04:12:35 -07:00
sv . second . getCoordinates ( latestTow ( sv . first . gnss , svstats ) , & sat ) ;
2020-01-09 06:33:02 -07:00
}
2020-02-25 04:12:35 -07:00
if ( sv . first . gnss = = 3 & & sv . second . ephBeidoumsg . sow > = 0 & & sv . second . ephBeidoumsg . sqrtA ! = 0 ) {
getCoordinates ( latestTow ( sv . first . gnss , svstats ) , sv . second . ephBeidoumsg , & sat ) ;
2019-09-22 08:42:23 -06:00
}
2020-02-25 04:12:35 -07:00
if ( sv . first . gnss = = 6 & & sv . second . wn ( ) > 0 ) {
2020-01-12 11:32:07 -07:00
getCoordinates ( latestTow ( 6 , svstats ) , sv . second . glonassMessage , & sat ) ;
2019-09-22 08:42:23 -06:00
}
if ( sat . x ) {
Point our = g_srcpos [ iter - > first ] . pos ;
2019-12-10 16:11:16 -07:00
svo [ " elev " ] = roundf ( 10.0 * getElevationDeg ( sat , our ) ) / 10.0 ;
svo [ " azi " ] = roundf ( 10.0 * getAzimuthDeg ( sat , our ) ) / 10.0 ;
2019-09-22 08:42:23 -06:00
}
2020-01-18 08:48:22 -07:00
svo [ " prres " ] = truncPrec ( iter - > second . prres , 2 ) ;
2020-01-09 06:33:02 -07:00
svo [ " qi " ] = iter - > second . qi ;
svo [ " used " ] = iter - > second . used ;
2019-09-22 08:42:23 -06:00
svo [ " age-s " ] = time ( 0 ) - iter - > second . t ;
svo [ " last-seen " ] = iter - > second . t ;
svo [ " gnss " ] = sv . first . gnss ;
svo [ " sv " ] = sv . first . sv ;
svo [ " sigid " ] = sv . first . sigid ;
2019-09-24 13:18:35 -06:00
svo [ " fullName " ] = makeSatIDName ( sv . first ) ;
svo [ " name " ] = makeSatPartialName ( sv . first ) ;
2019-09-22 08:42:23 -06:00
svs [ makeSatIDName ( sv . first ) ] = svo ;
}
}
}
obj [ " svs " ] = svs ;
2019-09-09 12:49:31 -06:00
ret . push_back ( obj ) ;
}
return ret ;
} ) ;
2019-09-22 08:42:23 -06:00
h2s . addHandler ( " /sv.json " , [ ] ( auto handler , auto req ) {
2019-11-02 14:25:07 -06:00
addHeaders ( req ) ;
2019-09-22 08:42:23 -06:00
string_view path = convert ( req - > path ) ;
nlohmann : : json ret = nlohmann : : json : : object ( ) ;
SatID id ;
auto pos = path . find ( " sv= " ) ;
if ( pos = = string : : npos ) {
return ret ;
}
id . sv = atoi ( & path [ 0 ] + pos + 3 ) ;
pos = path . find ( " gnssid= " ) ;
if ( pos = = string : : npos ) {
return ret ;
}
id . gnss = atoi ( & path [ 0 ] + pos + 7 ) ;
2019-09-24 13:18:35 -06:00
2019-09-22 08:42:23 -06:00
id . sigid = 1 ;
pos = path . find ( " sigid= " ) ;
if ( pos ! = string : : npos ) {
2019-09-24 13:18:35 -06:00
id . sigid = atoi ( & path [ 0 ] + pos + 6 ) ;
2019-09-22 08:42:23 -06:00
}
auto svstats = g_statskeeper . get ( ) ;
ret [ " sv " ] = id . sv ;
ret [ " gnssid " ] = id . gnss ;
ret [ " sigid " ] = id . sigid ;
auto iter = svstats . find ( id ) ;
if ( iter = = svstats . end ( ) )
return ret ;
const auto & s = iter - > second ;
2020-02-25 04:12:35 -07:00
// XXX CONVERSION
/*
2019-09-22 08:42:23 -06:00
ret [ " a0 " ] = s . a0 ;
ret [ " a1 " ] = s . a1 ;
ret [ " a0g " ] = s . a0g ;
ret [ " a1g " ] = s . a1g ;
2020-02-25 04:12:35 -07:00
*/
2019-10-20 12:34:06 -06:00
if ( id . gnss = = 2 ) {
2020-02-25 04:12:35 -07:00
ret [ " sf1 " ] = s . galmsg . sf1 ;
ret [ " sf2 " ] = s . galmsg . sf2 ;
ret [ " sf3 " ] = s . galmsg . sf3 ;
ret [ " sf4 " ] = s . galmsg . sf4 ;
ret [ " sf5 " ] = s . galmsg . sf5 ;
ret [ " BGDE1E5a " ] = s . galmsg . BGDE1E5a ;
ret [ " BGDE1E5b " ] = s . galmsg . BGDE1E5b ;
ret [ " e5bdvs " ] = s . galmsg . e5bdvs ;
ret [ " e1bdvs " ] = s . galmsg . e1bdvs ;
ret [ " e5bhs " ] = s . galmsg . e5bhs ;
ret [ " e1bhs " ] = s . galmsg . e1bhs ;
2019-10-20 12:34:06 -06:00
}
2020-02-25 04:12:35 -07:00
// XXX CONVERSION
/*
2019-09-22 08:42:23 -06:00
ret [ " ai0 " ] = s . ai0 ;
ret [ " ai1 " ] = s . ai1 ;
ret [ " ai2 " ] = s . ai2 ;
2020-02-25 04:12:35 -07:00
*/
ret [ " wn " ] = s . wn ( ) ;
ret [ " tow " ] = s . tow ( ) ;
// XXX CONVERSION
/*
2019-09-22 08:42:23 -06:00
ret [ " dtLS " ] = s . dtLS ;
ret [ " dtLSF " ] = s . dtLSF ;
ret [ " wnLSF " ] = s . wnLSF ;
ret [ " dn " ] = s . dn ;
2020-02-25 04:12:35 -07:00
*/
2019-09-22 08:42:23 -06:00
2020-02-25 04:12:35 -07:00
if ( id . gnss = = 3 & & svstats [ id ] . ephBeidoumsg . sow > = 0 & & svstats [ id ] . ephBeidoumsg . sqrtA ! = 0 ) {
const auto & iod = svstats [ id ] . ephBeidoumsg ;
2019-10-20 12:34:06 -06:00
ret [ " e " ] = iod . getE ( ) ;
ret [ " omega " ] = iod . getOmega ( ) ;
ret [ " sqrtA " ] = iod . getSqrtA ( ) ;
ret [ " M0 " ] = iod . getM0 ( ) ;
ret [ " i0 " ] = iod . getI0 ( ) ;
ret [ " delta-n " ] = iod . getDeltan ( ) ;
ret [ " omega-dot " ] = iod . getOmegadot ( ) ;
ret [ " omega0 " ] = iod . getOmega0 ( ) ;
ret [ " idot " ] = iod . getIdot ( ) ;
ret [ " t0e " ] = iod . getT0e ( ) ;
ret [ " t0c " ] = iod . getT0c ( ) ;
ret [ " cuc " ] = iod . getCuc ( ) ;
ret [ " cus " ] = iod . getCus ( ) ;
ret [ " crc " ] = iod . getCrc ( ) ;
ret [ " crs " ] = iod . getCrs ( ) ;
ret [ " cic " ] = iod . getCic ( ) ;
ret [ " cis " ] = iod . getCis ( ) ;
// ret["sisa"] = iod.sisa;
ret [ " af0 " ] = iod . a0 ;
ret [ " af1 " ] = iod . a1 ;
ret [ " af2 " ] = iod . a2 ;
Point p ;
2020-02-25 04:12:35 -07:00
s . getCoordinates ( s . tow ( ) , & p ) ;
2019-10-20 12:34:06 -06:00
ret [ " x " ] = p . x ;
ret [ " y " ] = p . y ;
ret [ " z " ] = p . z ;
auto longlat = getLongLat ( p . x , p . y , p . z ) ;
ret [ " longitude " ] = 180.0 * longlat . first / M_PI ;
ret [ " latitude " ] = 180.0 * longlat . second / M_PI ;
}
else if ( svstats [ id ] . completeIOD ( ) ) {
2019-09-22 08:42:23 -06:00
const auto & iod = svstats [ id ] . liveIOD ( ) ;
2020-02-25 04:12:35 -07:00
ret [ " iod " ] = svstats [ id ] . liveIOD ( ) . getIOD ( ) ;
2019-09-22 08:42:23 -06:00
ret [ " e " ] = iod . getE ( ) ;
ret [ " omega " ] = iod . getOmega ( ) ;
ret [ " sqrtA " ] = iod . getSqrtA ( ) ;
ret [ " M0 " ] = iod . getM0 ( ) ;
ret [ " i0 " ] = iod . getI0 ( ) ;
ret [ " delta-n " ] = iod . getDeltan ( ) ;
ret [ " omega-dot " ] = iod . getOmegadot ( ) ;
ret [ " omega0 " ] = iod . getOmega0 ( ) ;
ret [ " idot " ] = iod . getIdot ( ) ;
ret [ " t0e " ] = iod . getT0e ( ) ;
2020-02-25 04:12:35 -07:00
// XXX conversion
// ret["t0c"] = iod.getT0c();
2019-09-22 08:42:23 -06:00
ret [ " cuc " ] = iod . getCuc ( ) ;
ret [ " cus " ] = iod . getCus ( ) ;
ret [ " crc " ] = iod . getCrc ( ) ;
ret [ " crs " ] = iod . getCrs ( ) ;
ret [ " cic " ] = iod . getCic ( ) ;
ret [ " cis " ] = iod . getCis ( ) ;
2020-02-25 04:12:35 -07:00
// XXX conversion
/*
2019-09-22 08:42:23 -06:00
ret [ " sisa " ] = iod . sisa ;
ret [ " af0 " ] = iod . af0 ;
ret [ " af1 " ] = iod . af1 ;
ret [ " af2 " ] = iod . af2 ;
2020-02-25 04:12:35 -07:00
*/
2019-09-22 08:42:23 -06:00
Point p ;
2020-02-25 04:12:35 -07:00
s . getCoordinates ( s . tow ( ) , & p ) ;
2019-09-22 08:42:23 -06:00
ret [ " x " ] = p . x ;
ret [ " y " ] = p . y ;
ret [ " z " ] = p . z ;
auto longlat = getLongLat ( p . x , p . y , p . z ) ;
ret [ " longitude " ] = 180.0 * longlat . first / M_PI ;
ret [ " latitude " ] = 180.0 * longlat . second / M_PI ;
}
2020-01-09 06:33:02 -07:00
nlohmann : : json recvs = nlohmann : : json : : object ( ) ;
for ( const auto & perrecv : s . perrecv ) {
nlohmann : : json recv = nlohmann : : json : : object ( ) ;
recv [ " db " ] = perrecv . second . db ;
recv [ " qi " ] = perrecv . second . qi ;
recv [ " used " ] = perrecv . second . used ;
2020-01-18 08:48:22 -07:00
recv [ " prres " ] = truncPrec ( perrecv . second . prres , 2 ) ;
2020-01-09 06:33:02 -07:00
recv [ " elev " ] = perrecv . second . el ;
recv [ " last-seen-s " ] = time ( 0 ) - perrecv . second . t ;
recvs [ std : : to_string ( perrecv . first ) ] = recv ;
}
ret [ " recvs " ] = recvs ;
2019-09-22 08:42:23 -06:00
return ret ;
}
) ;
2019-10-12 06:57:44 -06:00
2019-10-23 02:33:13 -06:00
h2s . addHandler ( " /cov.json " , [ ] ( auto handler , auto req ) {
2019-11-02 14:25:07 -06:00
addHeaders ( req ) ;
2019-10-23 02:33:13 -06:00
vector < Point > sats ;
auto galileoalma = g_galileoalmakeeper . get ( ) ;
auto gpsalma = g_gpsalmakeeper . get ( ) ;
auto beidoualma = g_beidoualmakeeper . get ( ) ;
auto svstats = g_statskeeper . get ( ) ;
// cout<<"pseudoTow "<<pseudoTow<<endl;
string_view path = convert ( req - > path ) ;
2020-01-12 11:32:07 -07:00
bool doGalileo { true } , doGPS { false } , doBeidou { false } , doGlonass { false } ;
2019-10-23 02:33:13 -06:00
auto pos = path . find ( " gps= " ) ;
if ( pos ! = string : : npos ) {
doGPS = ( path [ pos + 4 ] = = ' 1 ' ) ;
}
pos = path . find ( " galileo= " ) ;
if ( pos ! = string : : npos ) {
doGalileo = ( path [ pos + 8 ] = = ' 1 ' ) ;
}
pos = path . find ( " beidou= " ) ;
if ( pos ! = string : : npos ) {
doBeidou = ( path [ pos + 7 ] = = ' 1 ' ) ;
}
2020-01-12 11:32:07 -07:00
pos = path . find ( " glonass= " ) ;
if ( pos ! = string : : npos ) {
doGlonass = ( path [ pos + 8 ] = = ' 1 ' ) ;
}
2019-10-23 02:33:13 -06:00
if ( doGalileo )
for ( const auto & g : galileoalma ) {
Point sat ;
getCoordinates ( latestTow ( 2 , svstats ) , g . second , & sat ) ;
if ( g . first < 0 )
continue ;
SatID id { 2 , ( uint32_t ) g . first , 1 } ;
2020-02-25 04:12:35 -07:00
if ( svstats [ id ] . completeIOD ( ) & & svstats [ id ] . galmsg . sisa = = 255 ) {
2019-10-23 02:33:13 -06:00
continue ;
}
2020-02-25 04:12:35 -07:00
if ( svstats [ id ] . galmsg . e1bhs | | svstats [ id ] . galmsg . e1bdvs )
2019-10-23 02:33:13 -06:00
continue ;
sats . push_back ( sat ) ;
}
if ( doGPS )
for ( const auto & g : gpsalma ) {
Point sat ;
getCoordinates ( latestTow ( 0 , svstats ) , g . second , & sat ) ;
if ( g . first < 0 )
continue ;
SatID id { 0 , ( uint32_t ) g . first , 0 } ;
2020-02-25 04:12:35 -07:00
if ( svstats [ id ] . completeIOD ( ) & & svstats [ id ] . gpsmsg . ura = = 16 ) {
2019-10-23 02:33:13 -06:00
// cout<<"Skipping G"<<id.sv<<" because of URA"<<endl;
continue ;
}
2020-02-25 04:12:35 -07:00
if ( svstats [ id ] . gpsmsg . gpshealth ) {
2019-10-23 02:33:13 -06:00
// cout<<"Skipping G"<<id.sv<<" because of health"<<endl;
continue ;
}
sats . push_back ( sat ) ;
}
if ( doBeidou )
for ( const auto & g : beidoualma ) {
Point sat ;
getCoordinates ( latestTow ( 3 , svstats ) , g . second . alma , & sat ) ;
if ( g . first < 0 )
continue ;
SatID id { 3 , ( uint32_t ) g . first , 0 } ;
/*
if ( svstats [ id ] . completeIOD ( ) & & svstats [ id ] . ura = = 16 ) {
cout < < " Skipping G " < < id . sv < < " because of URA " < < endl ;
continue ;
}
*/
2020-02-25 04:12:35 -07:00
if ( svstats [ id ] . gpsmsg . gpshealth ) {
2019-10-23 02:33:13 -06:00
// cout<<"Skipping C"<<id.sv<<" because of health"<<endl;
continue ;
}
sats . push_back ( sat ) ;
}
2020-01-12 11:32:07 -07:00
// fake almanac from svstats -- to avoid ejecting Glonasses to another galaxy due
// to excessive extrapolation, they freeze where they were last seen.
if ( doGlonass )
for ( const auto & s : svstats ) {
2020-02-25 04:12:35 -07:00
if ( s . first . gnss = = 6 & & s . second . wn ( ) > 0 ) {
2020-01-12 11:32:07 -07:00
Point sat ;
2020-02-25 04:12:35 -07:00
getCoordinates ( s . second . tow ( ) , s . second . glonassMessage , & sat ) ;
2020-01-12 11:32:07 -07:00
if ( svstats [ s . first ] . glonassMessage . Bn & 7 ) {
continue ;
}
sats . push_back ( sat ) ;
}
}
2019-10-23 02:33:13 -06:00
auto cov = emitCoverage ( sats ) ;
2019-10-12 06:57:44 -06:00
auto ret = nlohmann : : json : : array ( ) ;
// ret =
2019-10-15 10:01:22 -06:00
// [ [90, [[-180, 3,2,1], [-179, 3,2,1], ... [180,3,2,1] ]]
2019-10-12 06:57:44 -06:00
// [89, [[-180, 4], [-179, 4], ... [180,2] ]]
// ]
for ( const auto & latvect : cov ) {
auto jslatvect = nlohmann : : json : : array ( ) ;
auto jslongvect = nlohmann : : json : : array ( ) ;
for ( const auto & longpair : latvect . second ) {
auto jsdatum = nlohmann : : json : : array ( ) ;
2019-10-15 10:01:22 -06:00
jsdatum . push_back ( ( int ) get < 0 > ( longpair ) ) ;
jsdatum . push_back ( get < 1 > ( longpair ) ) ;
jsdatum . push_back ( get < 2 > ( longpair ) ) ;
jsdatum . push_back ( get < 3 > ( longpair ) ) ;
2019-10-19 16:53:33 -06:00
jsdatum . push_back ( ( int ) ( 10 * get < 4 > ( longpair ) ) ) ;
jsdatum . push_back ( ( int ) ( 10 * get < 5 > ( longpair ) ) ) ;
jsdatum . push_back ( ( int ) ( 10 * get < 6 > ( longpair ) ) ) ;
2019-10-23 02:33:13 -06:00
jsdatum . push_back ( ( int ) ( 10 * get < 7 > ( longpair ) ) ) ;
jsdatum . push_back ( ( int ) ( 10 * get < 8 > ( longpair ) ) ) ;
jsdatum . push_back ( ( int ) ( 10 * get < 9 > ( longpair ) ) ) ;
jsdatum . push_back ( ( int ) ( 10 * get < 10 > ( longpair ) ) ) ;
jsdatum . push_back ( ( int ) ( 10 * get < 11 > ( longpair ) ) ) ;
jsdatum . push_back ( ( int ) ( 10 * get < 12 > ( longpair ) ) ) ;
2019-10-12 06:57:44 -06:00
jslongvect . push_back ( jsdatum ) ;
}
jslatvect . push_back ( latvect . first ) ;
jslatvect . push_back ( jslongvect ) ;
ret . push_back ( jslatvect ) ;
}
return ret ;
} ) ;
2020-02-11 08:39:29 -07:00
h2s . addHandler ( " /sbas.json " , [ ] ( auto handler , auto req ) {
addHeaders ( req ) ;
auto svstats = g_statskeeper . get ( ) ;
auto sbas = g_sbaskeeper . get ( ) ;
nlohmann : : json ret = nlohmann : : json : : object ( ) ;
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_CACHE_CONTROL ,
NULL , H2O_STRLIT ( " max-age=3 " ) ) ;
// Access-Control-Allow-Origin
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN ,
NULL , H2O_STRLIT ( " * " ) ) ;
for ( const auto & s : sbas ) {
nlohmann : : json item = nlohmann : : json : : object ( ) ;
2020-02-25 04:12:35 -07:00
item [ " last-seen " ] = s . second . status . d_lastSeen ;
item [ " last-seen-s " ] = time ( 0 ) - s . second . status . d_lastSeen ;
2020-02-11 08:39:29 -07:00
2020-02-25 04:12:35 -07:00
item [ " last-type-0 " ] = s . second . status . d_lastDNU ;
item [ " last-type-0-s " ] = time ( 0 ) - s . second . status . d_lastDNU ;
2020-02-11 08:39:29 -07:00
2020-02-25 04:12:35 -07:00
// this 59 is to make sure galmonmon doesn't trigger on a single message
if ( s . second . status . d_lastSeen - s . second . status . d_lastDNU < 59 )
2020-02-11 08:39:29 -07:00
item [ " health " ] = " DON'T USE " ;
else
item [ " health " ] = " OK " ;
nlohmann : : json perrecv = nlohmann : : json : : object ( ) ;
for ( const auto & recv : s . second . perrecv ) {
perrecv [ to_string ( recv . first ) ] [ " last-seen " ] = recv . second . last_seen ;
perrecv [ to_string ( recv . first ) ] [ " last-seen-s " ] = time ( 0 ) - recv . second . last_seen ;
}
item [ " perrecv " ] = perrecv ;
ret [ to_string ( s . first ) ] = item ;
}
return ret ;
} ) ;
2019-08-09 07:58:52 -06:00
2019-09-22 08:42:23 -06:00
h2s . addHandler ( " /svs.json " , [ ] ( auto handler , auto req ) {
2019-11-02 14:25:07 -06:00
addHeaders ( req ) ;
2019-09-09 12:49:31 -06:00
auto svstats = g_statskeeper . get ( ) ;
2019-08-09 07:58:52 -06:00
nlohmann : : json ret = nlohmann : : json : : object ( ) ;
2019-10-01 07:03:30 -06:00
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_CACHE_CONTROL ,
NULL , H2O_STRLIT ( " max-age=3 " ) ) ;
2019-08-12 17:15:25 -06:00
2019-11-02 14:25:07 -06:00
// Access-Control-Allow-Origin
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN ,
NULL , H2O_STRLIT ( " * " ) ) ;
2019-09-09 12:49:31 -06:00
for ( const auto & s : svstats ) {
2019-08-12 07:54:16 -06:00
nlohmann : : json item = nlohmann : : json : : object ( ) ;
2020-02-25 04:12:35 -07:00
if ( ! s . second . tow ( ) ) // I know, I know, will suck briefly
2019-08-12 07:54:16 -06:00
continue ;
2019-08-26 07:58:01 -06:00
2019-09-16 06:33:06 -06:00
item [ " gnssid " ] = s . first . gnss ;
item [ " svid " ] = s . first . sv ;
item [ " sigid " ] = s . first . sigid ;
2020-02-25 04:12:35 -07:00
// perhaps check ephBeidoumsg for sow >=0 as 'completeIOD'?
2019-08-30 09:56:41 -06:00
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 3 ) { // beidou
2020-02-25 04:12:35 -07:00
item [ " sisa " ] = humanUra ( s . second . ephBeidoumsg . urai ) ;
item [ " sisa-m " ] = numUra ( s . second . ephBeidoumsg . urai ) ;
if ( s . second . completeIOD ( ) ) {
item [ " eph-age-m " ] = ephAge ( s . second . tow ( ) , s . second . ephBeidoumsg . getT0e ( ) ) / 60.0 ;
2019-09-09 12:49:31 -06:00
}
2020-02-25 04:12:35 -07:00
2019-09-09 12:49:31 -06:00
Point p ;
2020-02-25 04:12:35 -07:00
if ( s . second . ephBeidoumsg . sqrtA ! = 0 ) {
getCoordinates ( s . second . tow ( ) , s . second . ephBeidoumsg , & p ) ;
2019-10-23 02:32:47 -06:00
auto beidoualma = g_beidoualmakeeper . get ( ) ;
if ( auto iter = beidoualma . find ( s . first . sv ) ; iter ! = beidoualma . end ( ) ) {
Point almapos ;
2020-02-25 04:12:35 -07:00
getCoordinates ( s . second . tow ( ) , iter - > second . alma , & almapos ) ;
2020-01-18 08:48:22 -07:00
item [ " alma-dist " ] = truncPrec ( Vector ( almapos , p ) . length ( ) / 1000.0 , 1 ) ;
2019-10-23 02:32:47 -06:00
}
2019-09-02 08:13:49 -06:00
}
2019-08-30 09:56:41 -06:00
}
2019-09-16 06:33:06 -06:00
else if ( s . first . gnss = = 6 ) { // glonass
2020-01-26 05:20:20 -07:00
if ( s . second . glonassMessage . FT < 16 ) {
2019-08-30 09:56:41 -06:00
item [ " sisa " ] = humanFt ( s . second . glonassMessage . FT ) ;
2020-01-26 05:20:20 -07:00
item [ " sisa-m " ] = numFt ( s . second . glonassMessage . FT ) ;
}
2020-02-25 04:12:35 -07:00
item [ " aode " ] = s . second . ephglomsg . En * 24 ;
item [ " iod " ] = s . second . ephglomsg . Tb ;
2019-09-09 12:49:31 -06:00
2020-02-25 04:12:35 -07:00
time_t glonow = nanoTime ( 6 , s . second . wn ( ) , s . second . tow ( ) ) / 1000000000.0 ;
2019-09-09 12:49:31 -06:00
// the 820368000 stuff is to rebase to 'day 1' so the % works
auto pseudoTow = ( getGlonassT0e ( glonow , s . second . glonassMessage . Tb ) - 820368000 ) % ( 7 * 86400 ) ;
2020-02-25 04:12:35 -07:00
// cout<<std::fixed<<"wn: "<<s.second.wn() <<" tow "<<s.second.tow() <<" " << (int) s.second.glonassMessage.Tb << " " << glonow <<" " << humanTime(glonow) <<" ";
// cout<< pseudoTow <<" " << ephAge(s.second.tow(), getGlonassT0e(pseudoTow, s.second.glonassMessage.Tb))/60.0<<endl;
item [ " eph-age-m " ] = ephAge ( s . second . tow ( ) , getGlonassT0e ( pseudoTow , s . second . glonassMessage . Tb ) ) / 60.0 ;
2019-09-02 08:13:49 -06:00
2020-02-25 04:12:35 -07:00
// this should actually use local time!
Point p ;
s . second . getCoordinates ( s . second . tow ( ) , & p ) ;
auto match = g_tles . getBestMatch ( nanoTime ( s . first . gnss , s . second . wn ( ) , s . second . tow ( ) ) / 1000000000.0 ,
p . x , p . y , p . z ) ;
item [ " best-tle " ] = match . name ;
item [ " best-tle-norad " ] = match . norad ;
item [ " best-tle-int-desig " ] = match . internat ;
item [ " best-tle-dist " ] = match . distance / 1000.0 ;
2019-08-26 07:58:01 -06:00
}
2019-08-09 07:58:52 -06:00
if ( s . second . completeIOD ( ) ) {
2020-02-25 04:12:35 -07:00
item [ " iod " ] = s . second . liveIOD ( ) . getIOD ( ) ;
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 0 | | s . first . gnss = = 3 ) {
2020-02-25 04:12:35 -07:00
item [ " sisa " ] = humanUra ( s . second . gpsmsg . ura ) ;
item [ " sisa-m " ] = truncPrec ( numUra ( s . second . gpsmsg . ura ) , 3 ) ;
2019-08-13 12:44:23 -06:00
// cout<<"Asked to convert "<<s.second.ura<<" for sv "<<s.first.first<<","<<s.first.second<<endl;
}
2020-01-26 05:20:20 -07:00
else {
2020-02-25 04:12:35 -07:00
item [ " sisa " ] = humanSisa ( s . second . galmsg . sisa ) ;
item [ " sisa-m " ] = numSisa ( s . second . galmsg . sisa ) ;
2020-01-26 05:20:20 -07:00
}
2020-02-25 04:12:35 -07:00
item [ " eph-age-m " ] = ephAge ( s . second . tow ( ) , s . second . liveIOD ( ) . getT0e ( ) ) / 60 ;
// CONVERSION
item [ " af0 " ] = 0 ; // s.second.liveIOD().af0;
item [ " af1 " ] = 0 ; //s.second.liveIOD().af1;
item [ " af2 " ] = 0 ; // (int)s.second.liveIOD().af2;
// XXX conversion
// item["t0c"] = s.second.liveIOD().getT0c();
2019-08-12 07:54:16 -06:00
2019-09-05 01:35:13 -06:00
2020-04-25 03:43:25 -06:00
if ( s . second . rtcmEphDelta . id . gnss = = s . first . gnss & & s . second . rtcmEphDelta . id . sv = = s . first . sv & & s . second . rtcmEphDelta . iod = = s . second . liveIOD ( ) . getIOD ( )
& & abs ( s . second . rtcmEphDelta . sow - s . second . tow ( ) ) < 60 ) {
const auto & ed = s . second . rtcmEphDelta ;
item [ " rtcm-eph-delta-cm " ] = truncPrec ( sqrt ( ed . radial * ed . radial + ed . along * ed . along + ed . cross * ed . cross ) / 10.0 , 2 ) ;
item [ " rtcm-eph-radial-cm " ] = truncPrec ( ed . radial / 10.0 , 2 ) ;
item [ " rtcm-eph-along-cm " ] = truncPrec ( ed . along / 10.0 , 2 ) ;
item [ " rtcm-eph-cross-cm " ] = truncPrec ( ed . cross / 10.0 , 2 ) ;
item [ " rtcm-eph-dradial-cm " ] = truncPrec ( ed . dradial / 10.0 , 2 ) ;
item [ " rtcm-eph-dalong-cm " ] = truncPrec ( ed . dalong / 10.0 , 2 ) ;
item [ " rtcm-eph-dcross-cm " ] = truncPrec ( ed . dcross / 10.0 , 2 ) ;
2020-07-03 15:08:52 -06:00
const auto & cd = s . second . rtcmClockDelta ;
// so.. the clock delta message has no iod. It relates to "the previous ephemeris message" it seems
if ( cd . id . gnss = = s . first . gnss & & cd . id . sv = = s . first . sv & & abs ( s . second . rtcmClockDelta . sow - s . second . tow ( ) ) < 60 ) {
auto corrclock = cd . dclock0 - 3e8 * ldexp ( s . second . galmsg . BGDE1E5a - s . second . galmsg . BGDE1E5b , - 32 ) ;
item [ " rtcm-clock-dclock0 " ] = truncPrec ( corrclock * 100 , 2 ) ; // we turn this into centimeters
item [ " rtcm-clock-dclock1 " ] = truncPrec ( cd . dclock1 * 100 , 2 ) ; // we turn this into centimeters
item [ " rtcm-clock-dclock2 " ] = truncPrec ( cd . dclock2 * 100 , 2 ) ; // we turn this into centimeters
}
2020-04-25 03:43:25 -06:00
}
2019-08-09 07:58:52 -06:00
Point p ;
Point core ;
2019-08-12 07:54:16 -06:00
2019-08-09 07:58:52 -06:00
// this should actually use local time!
2020-02-25 04:12:35 -07:00
s . second . getCoordinates ( s . second . tow ( ) , & p ) ;
auto match = g_tles . getBestMatch ( nanoTime ( s . first . gnss , s . second . wn ( ) , s . second . tow ( ) ) / 1000000000.0 ,
2019-09-02 08:13:49 -06:00
p . x , p . y , p . z ) ;
item [ " best-tle " ] = match . name ;
item [ " best-tle-norad " ] = match . norad ;
item [ " best-tle-int-desig " ] = match . internat ;
item [ " best-tle-dist " ] = match . distance / 1000.0 ;
2019-09-05 01:35:13 -06:00
2019-08-12 07:54:16 -06:00
2019-08-09 07:58:52 -06:00
item [ " x " ] = p . x ;
item [ " y " ] = p . y ;
item [ " z " ] = p . z ;
2019-08-12 17:15:25 -06:00
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 0 ) {
2019-09-09 12:49:31 -06:00
auto gpsalma = g_gpsalmakeeper . get ( ) ;
2019-09-16 06:33:06 -06:00
if ( auto iter = gpsalma . find ( s . first . sv ) ; iter ! = gpsalma . end ( ) ) {
2019-09-09 12:49:31 -06:00
Point almapos ;
2020-02-25 04:12:35 -07:00
getCoordinates ( s . second . tow ( ) , iter - > second , & almapos ) ;
2019-09-09 12:49:31 -06:00
item [ " alma-dist " ] = Vector ( almapos , p ) . length ( ) / 1000.0 ;
}
}
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 2 ) {
2020-11-11 08:47:19 -07:00
if ( s . second . osnmaTime > = 0 & & ephAge ( s . second . galmsg . tow , s . second . osnmaTime ) < 60 )
item [ " osnma " ] = s . second . osnma ;
2019-09-09 12:49:31 -06:00
auto galileoalma = g_galileoalmakeeper . get ( ) ;
2019-09-16 06:33:06 -06:00
if ( auto iter = galileoalma . find ( s . first . sv ) ; iter ! = galileoalma . end ( ) ) {
2019-09-09 12:49:31 -06:00
Point almapos ;
2020-02-25 04:12:35 -07:00
getCoordinates ( s . second . tow ( ) , iter - > second , & almapos ) ;
2019-09-09 12:49:31 -06:00
item [ " alma-dist " ] = Vector ( almapos , p ) . length ( ) / 1000.0 ;
}
}
2019-08-09 07:58:52 -06:00
}
2020-02-25 04:12:35 -07:00
// XX conversion
/*
2019-08-12 07:54:16 -06:00
item [ " a0 " ] = s . second . a0 ;
item [ " a1 " ] = s . second . a1 ;
2020-02-25 04:12:35 -07:00
*/
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 0 ) { // GPS
2020-02-25 04:12:35 -07:00
auto deltaUTC = getGPSUTCOffset ( s . second . tow ( ) , s . second . wn ( ) , s . second . gpsmsg ) ;
2019-09-09 12:49:31 -06:00
item [ " delta-utc " ] = fmt : : sprintf ( " %.1f %+.1f/d " , deltaUTC . first , deltaUTC . second * 86400 ) ;
2020-02-25 04:12:35 -07:00
// CONVERSION
// item["t0t"] = s.second.gpsmsg.t0t;
// item["wn0t"] = s.second.gpsmsg.wn0t;
2019-09-09 12:49:31 -06:00
}
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 2 ) {
2020-02-25 04:12:35 -07:00
auto deltaUTC = s . second . galmsg . getUTCOffset ( s . second . tow ( ) , s . second . wn ( ) ) ;
2019-09-09 12:49:31 -06:00
item [ " delta-utc " ] = fmt : : sprintf ( " %.1f %+.1f/d " , deltaUTC . first , deltaUTC . second * 86400 ) ;
2020-02-25 04:12:35 -07:00
auto deltaGPS = s . second . galmsg . getGPSOffset ( s . second . tow ( ) , s . second . wn ( ) ) ;
2019-09-09 12:49:31 -06:00
item [ " delta-gps " ] = fmt : : sprintf ( " %.1f %+.1f/d " , deltaGPS . first , deltaGPS . second * 86400 ) ;
item [ " t0t " ] = s . second . galmsg . t0t ;
item [ " wn0t " ] = s . second . galmsg . wn0t ;
}
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 3 ) {
2020-02-25 04:12:35 -07:00
auto deltaUTC = s . second . ephBeidoumsg . getUTCOffset ( s . second . ephBeidoumsg . sow ) ;
2019-09-09 12:49:31 -06:00
item [ " delta-utc " ] = fmt : : sprintf ( " %.1f %+.1f/d " , deltaUTC . first , deltaUTC . second * 86400 ) ;
2020-02-25 04:12:35 -07:00
auto deltaGPS = s . second . ephBeidoumsg . getGPSOffset ( s . second . ephBeidoumsg . sow ) ;
2019-09-09 12:49:31 -06:00
item [ " delta-gps " ] = fmt : : sprintf ( " %.1f %+.1f/d " , deltaGPS . first , deltaGPS . second * 86400 ) ;
item [ " t0g " ] = 0 ;
item [ " wn0g " ] = 0 ;
item [ " t0t " ] = 0 ;
item [ " wn0t " ] = 0 ;
}
2020-02-25 04:12:35 -07:00
// XXX conversion
// item["dtLS"]=s.second.dtLS;
2019-08-26 07:58:01 -06:00
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 3 ) { // beidou
2020-02-25 04:12:35 -07:00
item [ " a0g " ] = s . second . ephBeidoumsg . a0gps ;
item [ " a1g " ] = s . second . ephBeidoumsg . a1gps ;
if ( s . second . ephBeidoumsg . aode > = 0 )
item [ " aode " ] = s . second . ephBeidoumsg . aode ;
if ( s . second . ephBeidoumsg . aodc > = 0 )
item [ " aodc " ] = s . second . ephBeidoumsg . aodc ;
item [ " health " ] = s . second . beidoumsg . sath1 ? " NOT OK " : " OK " ;
item [ " healthissue " ] = ! ! s . second . beidoumsg . sath1 ;
2019-08-26 07:58:01 -06:00
}
2020-02-25 04:12:35 -07:00
if ( s . first . gnss = = 6 ) { // GLONASS
auto deltaUTC = s . second . glonassMessage . getUTCOffset ( 0 ) ;
item [ " delta-utc " ] = fmt : : sprintf ( " %.1f %+.1f/d " , deltaUTC . first , deltaUTC . second * 86400 ) ;
auto deltaGPS = s . second . glonassMessage . getGPSOffset ( 0 ) ;
item [ " delta-gps " ] = fmt : : sprintf ( " %.1f %+.1f/d " , deltaGPS . first , deltaGPS . second * 86400 ) ;
}
2019-08-26 07:58:01 -06:00
2019-09-16 06:33:06 -06:00
if ( s . first . gnss = = 2 ) { // galileo
2020-02-25 04:12:35 -07:00
item [ " a0g " ] = s . second . galmsg . a0g ;
item [ " a1g " ] = s . second . galmsg . a1g ;
item [ " t0g " ] = s . second . galmsg . t0g ;
item [ " wn0g " ] = s . second . galmsg . wn0g ;
2019-09-09 12:49:31 -06:00
2019-08-26 07:58:01 -06:00
item [ " health " ] =
2020-02-25 04:12:35 -07:00
humanBhs ( s . second . galmsg . e1bhs ) + " / " +
humanBhs ( s . second . galmsg . e5bhs ) + " / " +
( s . second . galmsg . e1bdvs ? " NG " : " val " ) + " / " +
( s . second . galmsg . e5bdvs ? " NG " : " val " ) ;
item [ " e5bdvs " ] = s . second . galmsg . e5bdvs ;
item [ " e1bdvs " ] = s . second . galmsg . e1bdvs ;
item [ " e5bhs " ] = s . second . galmsg . e5bhs ;
item [ " e1bhs " ] = s . second . galmsg . e1bhs ;
2019-08-26 07:58:01 -06:00
item [ " healthissue " ] = 0 ;
2020-02-25 04:12:35 -07:00
if ( s . second . galmsg . e1bhs = = 2 | | s . second . galmsg . e5bhs = = 2 )
2019-08-26 07:58:01 -06:00
item [ " healthissue " ] = 1 ;
2020-02-25 04:12:35 -07:00
if ( s . second . galmsg . e1bhs = = 3 | | s . second . galmsg . e5bhs = = 3 )
2019-08-26 07:58:01 -06:00
item [ " healthissue " ] = 1 ;
2020-02-25 04:12:35 -07:00
if ( s . second . galmsg . e1bdvs | | s . second . galmsg . e5bdvs | | s . second . galmsg . e1bhs = = 1 | | s . second . galmsg . e5bhs = = 1 )
2019-08-26 07:58:01 -06:00
item [ " healthissue " ] = 2 ;
}
2020-02-25 04:12:35 -07:00
else if ( s . first . gnss = = 0 ) {
item [ " health " ] = s . second . gpsmsg . gpshealth ? ( " NOT OK: " + to_string ( s . second . gpsmsg . gpshealth ) ) : string ( " OK " ) ;
item [ " healthissue " ] = 2 * ! ! s . second . gpsmsg . gpshealth ;
}
else if ( s . first . gnss = = 6 ) { // GLONASS
item [ " health " ] = s . second . glonassMessage . Bn ? ( " NOT OK: " + to_string ( s . second . glonassMessage . Bn ) ) : string ( " OK " ) ;
item [ " healthissue " ] = 2 * ! ! s . second . glonassMessage . Bn ;
2019-08-12 17:15:25 -06:00
}
2019-08-12 07:54:16 -06:00
nlohmann : : json perrecv = nlohmann : : json : : object ( ) ;
for ( const auto & pr : s . second . perrecv ) {
2020-01-11 12:33:30 -07:00
if ( pr . second . db > 0 | | ( time ( 0 ) - pr . second . t < 1800 ) ) {
2019-08-30 09:56:41 -06:00
nlohmann : : json det = nlohmann : : json : : object ( ) ;
det [ " elev " ] = pr . second . el ;
2019-09-05 01:35:13 -06:00
Point sat ;
2020-02-25 04:12:35 -07:00
if ( s . second . completeIOD ( ) )
s . second . getCoordinates ( latestTow ( s . first . gnss , svstats ) , & sat ) ;
2019-09-05 01:35:13 -06:00
if ( sat . x ) {
2019-09-16 06:33:06 -06:00
Point our = g_srcpos [ pr . first ] . pos ;
2019-12-10 16:11:16 -07:00
det [ " elev " ] = roundf ( 10.0 * getElevationDeg ( sat , our ) ) / 10.0 ;
det [ " azi " ] = roundf ( 10.0 * getAzimuthDeg ( sat , our ) ) / 10.0 ;
2019-09-05 01:35:13 -06:00
}
else
det [ " elev " ] = pr . second . el ;
2019-08-30 09:56:41 -06:00
det [ " db " ] = pr . second . db ;
det [ " last-seen-s " ] = time ( 0 ) - pr . second . t ;
2020-01-18 08:48:22 -07:00
det [ " prres " ] = truncPrec ( pr . second . prres , 2 ) ;
2020-01-09 06:33:02 -07:00
det [ " qi " ] = pr . second . qi ;
det [ " used " ] = pr . second . used ;
2019-09-16 09:21:53 -06:00
if ( time ( 0 ) - pr . second . deltaHzTime < 60 ) {
det [ " delta_hz " ] = pr . second . deltaHz ;
auto hzCorrection = getHzCorrection ( time ( 0 ) , pr . first , s . first . gnss , s . first . sigid , svstats ) ;
if ( hzCorrection )
det [ " delta_hz_corr " ] = pr . second . deltaHz - * hzCorrection ;
}
2019-08-30 09:56:41 -06:00
perrecv [ to_string ( pr . first ) ] = det ;
}
2019-08-12 07:54:16 -06:00
}
item [ " perrecv " ] = perrecv ;
2020-02-25 04:12:35 -07:00
item [ " last-seen-s " ] = time ( 0 ) - nanoTime ( s . first . gnss , s . second . wn ( ) , s . second . tow ( ) ) / 1000000000 ;
2019-09-16 06:33:06 -06:00
2019-08-12 07:54:16 -06:00
if ( s . second . latestDisco > = 0 ) {
2020-01-18 08:48:22 -07:00
item [ " latest-disco " ] = truncPrec ( s . second . latestDisco , 3 ) ;
2019-09-18 06:17:41 -06:00
item [ " latest-disco-age " ] = s . second . latestDiscoAge ;
2019-08-12 07:54:16 -06:00
}
2019-08-30 09:56:41 -06:00
if ( s . second . timeDisco > - 100 & & s . second . timeDisco < 100 ) {
2020-01-18 08:48:22 -07:00
item [ " time-disco " ] = truncPrec ( s . second . timeDisco , 1 ) ;
2019-08-30 09:56:41 -06:00
}
2019-08-12 07:54:16 -06:00
2020-02-25 04:12:35 -07:00
item [ " wn " ] = s . second . wn ( ) ;
item [ " tow " ] = s . second . tow ( ) ;
2019-09-24 13:18:35 -06:00
item [ " fullName " ] = makeSatIDName ( s . first ) ;
item [ " name " ] = makeSatPartialName ( s . first ) ;
2019-09-22 08:42:23 -06:00
ret [ makeSatIDName ( s . first ) ] = item ;
2019-08-12 07:54:16 -06:00
}
2019-08-09 07:58:52 -06:00
return ret ;
} ) ;
2020-02-25 04:12:35 -07:00
h2s . addHandler ( " /sbstatus.json " , [ ] ( auto handler , auto req ) {
addHeaders ( req ) ;
auto svstats = g_statskeeper . get ( ) ;
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_CACHE_CONTROL ,
NULL , H2O_STRLIT ( " max-age=3 " ) ) ;
// Access-Control-Allow-Origin
h2o_add_header ( & req - > pool , & req - > res . headers , H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN ,
NULL , H2O_STRLIT ( " * " ) ) ;
auto ret = nlohmann : : json : : array ( ) ;
time_t now = time ( 0 ) ;
for ( const auto & s : svstats ) {
for ( const auto & sb : s . second . sbas ) {
if ( now - sb . second . longterm . lastUpdate > 120 )
continue ;
if ( now - sb . second . fast . lastUpdate > 120 )
continue ;
if ( sb . second . fast . udrei = = 14 )
continue ;
auto obj = nlohmann : : json : : object ( ) ;
obj [ " name " ] = makeSatPartialName ( s . first ) ;
obj [ " sbasprn " ] = sb . first ;
obj [ " dx " ] = sb . second . longterm . dx ;
obj [ " dy " ] = sb . second . longterm . dy ;
obj [ " dz " ] = sb . second . longterm . dz ;
obj [ " dai " ] = sb . second . longterm . dai ;
obj [ " iod8 " ] = sb . second . longterm . iod8 ;
obj [ " velocity " ] = sb . second . longterm . velocity ;
obj [ " last-longterm-update-s " ] = now - sb . second . longterm . lastUpdate ;
obj [ " last-fast-update-s " ] = now - sb . second . fast . lastUpdate ;
if ( sb . second . longterm . velocity ) {
obj [ " toa " ] = sb . second . longterm . toa ;
int toadelta = ( now % 86400 ) - sb . second . longterm . toa ;
obj [ " toa-delta " ] = toadelta ;
obj [ " ddx " ] = sb . second . longterm . ddx ;
obj [ " ddy " ] = sb . second . longterm . ddy ;
obj [ " ddz " ] = sb . second . longterm . ddz ;
obj [ " ddai " ] = sb . second . longterm . ddai ;
obj [ " adx " ] = sb . second . longterm . dx + toadelta * sb . second . longterm . ddx ;
obj [ " ady " ] = sb . second . longterm . dy + toadelta * sb . second . longterm . ddy ;
obj [ " adz " ] = sb . second . longterm . dz + toadelta * sb . second . longterm . ddz ;
obj [ " adai " ] = sb . second . longterm . dai + toadelta * sb . second . longterm . ddai ;
}
obj [ " correction " ] = sb . second . fast . correction ;
obj [ " udrei " ] = sb . second . fast . udrei ;
if ( s . second . completeIOD ( ) & & ( s . second . liveIOD ( ) . getIOD ( ) & 0xff ) = = sb . second . longterm . iod8 ) {
Point sat ;
s . second . getCoordinates ( s . second . tow ( ) , & sat ) ;
Point adjsat = sat ;
adjsat . x + = sb . second . longterm . dx ;
adjsat . y + = sb . second . longterm . dy ;
adjsat . z + = sb . second . longterm . dz ;
Point sbasCenter ;
int prn = sb . first ;
if ( prn = = 126 | | prn = = 136 | | prn = = 123 )
sbasCenter = c_egnosCenter ;
else if ( prn = = 138 | | prn = = 131 | | prn = = 133 )
sbasCenter = c_waasCenter ;
else
sbasCenter = Point { 0 , 0 , 0 } ;
double dist = Vector ( sbasCenter , adjsat ) . length ( ) - Vector ( sbasCenter , sat ) . length ( ) ;
obj [ " space-shift " ] = dist ;
dist - = sb . second . longterm . dai / 3 ;
obj [ " eph-shift " ] = dist ;
obj [ " range-shift " ] = dist - sb . second . fast . correction ;
}
ret . push_back ( obj ) ;
}
}
return ret ;
} ) ;
2020-01-26 05:20:20 -07:00
h2s . addDirectory ( " / " , htmlDir ) ;
2019-08-09 07:58:52 -06:00
2020-01-26 05:20:20 -07:00
const char * address = localAddress . c_str ( ) ;
2019-08-16 03:25:28 -06:00
std : : thread ws ( [ & h2s , address ] ( ) {
2019-08-09 07:58:52 -06:00
auto actx = h2s . addContext ( ) ;
2019-09-09 12:49:31 -06:00
ComboAddress listenOn ( address ) ;
h2s . addListener ( listenOn , actx ) ;
cout < < " Listening on " < < listenOn . toStringWithPort ( ) < < endl ;
2019-08-09 07:58:52 -06:00
h2s . runLoop ( ) ;
} ) ;
ws . detach ( ) ;
try {
for ( ; ; ) {
2019-09-09 12:49:31 -06:00
static time_t lastWebSync ;
if ( lastWebSync ! = time ( 0 ) ) {
g_statskeeper . set ( g_svstats ) ;
2020-02-11 08:39:29 -07:00
g_sbaskeeper . set ( g_sbas ) ;
2019-09-09 12:49:31 -06:00
g_galileoalmakeeper . set ( g_galileoalma ) ;
g_glonassalmakeeper . set ( g_glonassalma ) ;
g_beidoualmakeeper . set ( g_beidoualma ) ;
g_gpsalmakeeper . set ( g_gpsalma ) ;
lastWebSync = time ( 0 ) ;
}
2020-02-04 13:25:20 -07:00
2019-09-05 01:35:13 -06:00
char bert [ 6 ] ;
2020-02-25 15:17:55 -07:00
// I apologise deeply
2020-07-03 15:08:52 -06:00
if ( fread ( bert , 1 , sizeof ( bert ) , stdin ) ! = sizeof ( bert ) | | bert [ 0 ] ! = ' b ' | | bert [ 1 ] ! = ' e ' | | bert [ 2 ] ! = ' r ' | | bert [ 3 ] ! = ' t ' ) {
2019-08-09 08:50:26 -06:00
cerr < < " EOF or bad magic " < < endl ;
2019-08-09 07:58:52 -06:00
break ;
2019-08-09 08:50:26 -06:00
}
2019-08-09 07:58:52 -06:00
uint16_t len ;
2019-09-05 01:35:13 -06:00
memcpy ( & len , bert + 4 , 2 ) ;
2019-08-09 07:58:52 -06:00
len = htons ( len ) ;
char buffer [ len ] ;
2019-09-05 01:35:13 -06:00
if ( fread ( buffer , 1 , len , stdin ) ! = len )
2019-08-09 07:58:52 -06:00
break ;
2019-09-05 01:35:13 -06:00
2019-08-09 07:58:52 -06:00
NavMonMessage nmm ;
2020-07-03 15:08:52 -06:00
try {
if ( ! nmm . ParseFromString ( string ( buffer , len ) ) ) {
cerr < < " Parsing error nmm " < < endl ;
continue ;
2020-02-04 13:25:20 -07:00
}
2020-07-03 15:08:52 -06:00
}
catch ( std : : exception & e ) {
cerr < < " nmm exception: " < < e . what ( ) ;
continue ;
}
catch ( . . . ) {
cerr < < " nmm exception " < < endl ;
continue ;
}
constexpr auto lastCovInterval = 300 ;
static time_t lastCovSyncPoint ;
static time_t holdOffTime ;
if ( nmm . localutcseconds ( ) / lastCovInterval > ( unsigned int ) lastCovSyncPoint ) {
if ( ! lastCovSyncPoint )
holdOffTime = nmm . localutcseconds ( ) + 600 ;
2020-12-06 06:29:32 -07:00
if ( ( time_t ) nmm . localutcseconds ( ) > holdOffTime )
2020-07-03 15:08:52 -06:00
storeCoverageStats ( idb , nmm . localutcseconds ( ) ) ;
lastCovSyncPoint = nmm . localutcseconds ( ) / lastCovInterval ;
}
constexpr auto lastSelfstatInterval = 60 ;
static time_t lastSelfstatSyncPoint ;
if ( nmm . localutcseconds ( ) / lastSelfstatInterval > ( unsigned int ) lastSelfstatSyncPoint ) {
storeSelfStats ( idb , nmm . localutcseconds ( ) ) ;
lastSelfstatSyncPoint = nmm . localutcseconds ( ) / lastSelfstatInterval ;
2020-02-04 13:25:20 -07:00
}
2020-11-11 08:45:25 -07:00
2020-12-06 06:29:32 -07:00
#if 0
2020-11-11 08:45:25 -07:00
constexpr auto lastIonoInterval = 3600 ;
static time_t lastIonoSyncPoint ;
if ( nmm . localutcseconds ( ) / lastIonoInterval > ( unsigned int ) lastIonoSyncPoint ) {
// go over all satellites
NeQuickInst nqi ;
// cerr<<"Looking at all sats"<<endl;
for ( const auto & s : g_svstats ) {
if ( s . first . gnss ! = 2 | | ! s . second . completeIOD ( ) )
continue ;
Point sat ;
s . second . getCoordinates ( s . second . tow ( ) , & sat ) ;
for ( const auto & pr : s . second . perrecv ) {
// cerr<<"Looking at "<<s.first.sv<<", "<<pr.second.db<<" "<<nmm.localutcseconds()<<", "<<pr.second.t<<" perrecv "<<pr.first<<" count " << g_srcpos.count(pr.first)<<endl;
if ( g_srcpos . count ( pr . first ) & & ( pr . second . db > 0 | | ( nmm . localutcseconds ( ) - pr . second . t < 120 ) ) ) {
// cerr<<"Doing it -> "<< s.second.galmsg.ai0 <<" " <<s.second.galmsg.ai1<<" " << s.second.galmsg.ai2<< endl;
const auto & sp = g_srcpos [ pr . first ] ;
try {
// cerr<<"Obs "<<pr.first<<" pos: "<<sp.pos.x<<", "<<sp.pos.y<<", "<<sp.pos.z<<endl;
// cerr<<"Sat " <<s.first.sv<<" pos: "<<sat.x<<", "<<sat.y<<", "<<sat.z<<endl;
// auto obs = ecefToWGS84Deg(sp.pos.x, sp.pos.y, sp.pos.z);
// cerr<<"Observer height: "<<get<2>(obs)<<" meters, long "<<get<0>(obs)<<", lat "<<get<1>(obs)<<endl;
// auto satdegs = ecefToWGS84Deg(sat.x, sat.y, sat.z);
// cerr<<"Satellite height: "<<get<2>(satdegs)<<" meters, long "<<get<0>(satdegs)<<", lat "<<get<1>(satdegs)<< " -> elevation "<<getElevationDeg(sat, sp.pos)<<" deg"<<endl;
if ( getElevationDeg ( sat , sp . pos ) < 0 ) // below the horizon
continue ;
if ( sp . pos . x = = 0 | | isnan ( sat . x ) ) {
// cerr<<"Fake position, skipping"<<endl;
continue ;
}
double meters = ( 40.3e16 / ( 1575420000.0 * 1575420000.0 ) ) *
nqi . getTecu ( nmm . localutcseconds ( ) ,
s . second . galmsg . ai0 ,
s . second . galmsg . ai1 ,
s . second . galmsg . ai2 , sp . pos , sat ) ;
idb . addValue ( s . first , " nequick " ,
{
{ " meters " , meters }
} , nmm . localutcseconds ( ) + nmm . localutcnanoseconds ( ) / 1000000000.0 , pr . first ) ;
// cerr<<"Meters: "<<meters<<endl;
}
catch ( std : : exception & e ) {
cerr < < " Exception during NeQuick: " < < e . what ( ) < < endl ;
}
}
}
}
// cerr<<"Done"<<endl;
lastIonoSyncPoint = nmm . localutcseconds ( ) / lastIonoInterval ;
}
# endif
2020-02-04 13:25:20 -07:00
2019-08-09 07:58:52 -06:00
if ( nmm . type ( ) = = NavMonMessage : : ReceptionDataType ) {
2019-08-12 07:54:16 -06:00
int gnssid = nmm . rd ( ) . gnssid ( ) ;
2019-08-09 07:58:52 -06:00
int sv = nmm . rd ( ) . gnsssv ( ) ;
2019-09-16 06:33:06 -06:00
int sigid = nmm . rd ( ) . sigid ( ) ;
if ( gnssid = = 2 & & sigid = = 0 )
sigid = 1 ;
2022-06-16 11:31:05 -06:00
if ( gnssid = = 2 & & sigid = = 4 )
sigid = 3 ;
2019-09-16 06:33:06 -06:00
SatID id { ( uint32_t ) gnssid , ( uint32_t ) sv , ( uint32_t ) sigid } ;
2020-01-09 06:33:02 -07:00
auto & perrecv = g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] ;
perrecv . db = nmm . rd ( ) . db ( ) ;
perrecv . el = nmm . rd ( ) . el ( ) ;
perrecv . azi = nmm . rd ( ) . azi ( ) ;
perrecv . prres = nmm . rd ( ) . prres ( ) ;
if ( nmm . rd ( ) . has_qi ( ) )
perrecv . qi = nmm . rd ( ) . qi ( ) ;
else
perrecv . qi = - 1 ;
2019-08-12 17:15:25 -06:00
2020-01-09 06:33:02 -07:00
if ( nmm . rd ( ) . has_used ( ) )
perrecv . used = nmm . rd ( ) . used ( ) ;
else
perrecv . used = - 1 ;
2019-09-16 06:33:06 -06:00
Point sat { 0 , 0 , 0 } ;
//cout<<"Got recdata for "<<id.gnss<<","<<id.sv<<","<<id.sigid<<": count="<<g_svstats.count(id)<<endl;
2020-09-27 08:49:59 -06:00
if ( g_svstats [ id ] . completeIOD ( ) & & ! ( random ( ) % 16 ) ) {
2020-02-25 04:12:35 -07:00
g_svstats [ id ] . getCoordinates ( g_svstats [ id ] . tow ( ) , & sat ) ;
2019-09-16 06:33:06 -06:00
}
2020-01-09 06:33:02 -07:00
2019-10-23 02:32:47 -06:00
if ( sat . x ! = 0 & & g_srcpos [ nmm . sourceid ( ) ] . pos . x ! = 0 ) {
2020-09-27 08:49:59 -06:00
if ( doLogRFData & & ! ( random ( ) % 16 ) )
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " recdata " ,
2019-09-16 06:33:06 -06:00
{
{ " db " , nmm . rd ( ) . db ( ) } ,
{ " azi " , getAzimuthDeg ( sat , g_srcpos [ nmm . sourceid ( ) ] . pos ) } ,
{ " ele " , getElevationDeg ( sat , g_srcpos [ nmm . sourceid ( ) ] . pos ) } ,
2020-01-09 06:33:02 -07:00
{ " prres " , nmm . rd ( ) . prres ( ) } ,
{ " qi " , perrecv . qi } ,
{ " used " , perrecv . used }
2020-01-11 12:33:30 -07:00
} , nmm . localutcseconds ( ) + nmm . localutcnanoseconds ( ) / 1000000000.0 , nmm . sourceid ( ) ) ;
2019-09-16 06:33:06 -06:00
}
2019-08-09 07:58:52 -06:00
}
else if ( nmm . type ( ) = = NavMonMessage : : GalileoInavType ) {
basic_string < uint8_t > inav ( ( uint8_t * ) nmm . gi ( ) . contents ( ) . c_str ( ) , nmm . gi ( ) . contents ( ) . size ( ) ) ;
int sv = nmm . gi ( ) . gnsssv ( ) ;
2019-09-16 06:33:06 -06:00
int sigid ;
if ( nmm . gi ( ) . has_sigid ( ) )
sigid = nmm . gi ( ) . sigid ( ) ;
else
sigid = 1 ; // default to E1B
SatID id = { 2 , ( uint32_t ) sv , ( uint32_t ) sigid } ;
2020-02-25 04:12:35 -07:00
2019-08-30 09:56:41 -06:00
auto & svstat = g_svstats [ id ] ;
2020-02-25 04:12:35 -07:00
svstat . gnss = id . gnss ;
2019-08-30 09:56:41 -06:00
auto oldgm = svstat . galmsg ;
2019-09-05 01:35:13 -06:00
auto & gm = svstat . galmsg ;
unsigned int wtype = gm . parse ( inav ) ;
2019-11-02 14:25:07 -06:00
2019-09-09 12:49:31 -06:00
if ( wtype = = 5 & & svstat . galmsgTyped . count ( 5 ) ) {
const auto & old5gm = svstat . galmsgTyped [ 5 ] ;
if ( make_tuple ( old5gm . e5bhs , old5gm . e1bhs , old5gm . e5bdvs , old5gm . e1bdvs ) ! =
make_tuple ( gm . e5bhs , gm . e1bhs , gm . e5bdvs , gm . e1bdvs ) ) {
2020-02-25 04:12:35 -07:00
cout < < humanTime ( id . gnss , svstat . wn ( ) , svstat . tow ( ) ) < < " src " < < nmm . sourceid ( ) < < " Galileo " < < id . sv < < " sigid " < < id . sigid < < " change in health: [ " < < humanBhs ( old5gm . e5bhs ) < < " , " < < humanBhs ( old5gm . e1bhs ) < < " , " < < ( int ) old5gm . e5bdvs < < " , " < < ( int ) old5gm . e1bdvs < < " ] -> [ " < < humanBhs ( gm . e5bhs ) < < " , " < < humanBhs ( gm . e1bhs ) < < " , " < < ( int ) gm . e5bdvs < < " , " < < ( int ) gm . e1bdvs < < " ], lastseen " < < ephAge ( old5gm . tow , gm . tow ) / 3600.0 < < " hours " < < endl ;
2019-09-09 12:49:31 -06:00
}
}
2019-11-02 14:25:07 -06:00
svstat . galmsgTyped [ wtype ] = gm ;
2020-02-25 04:12:35 -07:00
if ( wtype = = 1 | | wtype = = 2 | | wtype = = 3 | | wtype = = 4 ) {
2020-11-11 08:47:19 -07:00
if ( nmm . gi ( ) . has_reserved1 ( ) ) {
static string off ;
if ( off . empty ( ) )
off . append ( 5 , ( char ) 0 ) ;
svstat . osnma = nmm . gi ( ) . reserved1 ( ) ! = off ;
if ( svstat . osnma ) // eventually this will become too much but ok for now
2020-12-06 06:29:32 -07:00
idb . addValue ( id , " osnma " , { { " wtype " , wtype } , { " field " , makeHexDump ( nmm . gi ( ) . reserved1 ( ) ) } } , satUTCTime ( id ) ) ;
2020-11-11 08:47:19 -07:00
svstat . osnmaTime = gm . tow ;
}
2020-02-25 04:12:35 -07:00
idb . addValue ( id , " ephemeris " , { { " iod-live " , svstat . galmsg . iodnav } ,
{ " eph-age " , ephAge ( gm . tow , gm . getT0e ( ) ) } } , satUTCTime ( id ) ) ;
int w = 1 ;
for ( ; w < 5 ; + + w ) {
if ( ! svstat . galmsgTyped . count ( w ) )
break ;
if ( w > 1 & & svstat . galmsgTyped [ w - 1 ] . iodnav ! = svstat . galmsgTyped [ w ] . iodnav )
break ;
}
2020-07-29 11:46:51 -06:00
if ( w = = 5 ) { // have complete new ephemeris
2020-02-25 04:12:35 -07:00
if ( svstat . ephgalmsg . iodnav ! = svstat . galmsgTyped [ 1 ] . iodnav ) {
svstat . oldephgalmsg = svstat . ephgalmsg ;
svstat . ephgalmsg = svstat . galmsgTyped [ wtype ] ;
svstat . reportNewEphemeris ( id , idb ) ;
}
}
}
2020-09-27 08:49:59 -06:00
svstat . perrecv [ nmm . sourceid ( ) ] . t = nmm . localutcseconds ( ) ;
2020-02-25 04:12:35 -07:00
if ( wtype > = 1 & & wtype < = 4 ) { // ephemeris
if ( wtype = = 3 ) {
2020-09-27 08:49:59 -06:00
idb . addValue ( id , " sisa " , { { " value " , svstat . galmsg . sisa } } , satUTCTime ( id ) ) ;
2020-02-25 04:12:35 -07:00
}
else if ( wtype = = 4 ) {
idb . addValue ( id , " clock " , { { " offset_ns " , svstat . galmsg . getAtomicOffset ( svstat . tow ( ) ) . first } ,
2020-09-27 08:49:59 -06:00
{ " t0c " , svstat . galmsg . t0c * 60 } , // getT0c()??
{ " af0 " , svstat . galmsg . af0 } ,
{ " af1 " , svstat . galmsg . af1 } ,
{ " af2 " , svstat . galmsg . af2 } } , satUTCTime ( id ) ) ;
2020-01-11 12:33:30 -07:00
2019-08-30 09:56:41 -06:00
if ( oldgm . af0 & & oldgm . t0c ! = svstat . galmsg . t0c ) {
2020-02-25 04:12:35 -07:00
auto oldOffset = oldgm . getAtomicOffset ( svstat . tow ( ) ) ;
auto newOffset = svstat . galmsg . getAtomicOffset ( svstat . tow ( ) ) ;
2019-08-30 09:56:41 -06:00
svstat . timeDisco = oldOffset . first - newOffset . first ;
2020-01-12 13:42:36 -07:00
if ( fabs ( svstat . timeDisco ) < 10000 )
2020-07-29 03:38:32 -06:00
idb . addValue ( id , " clock_jump_ns " , {
{ " jump " , svstat . timeDisco } ,
{ " duration " , ephAge ( svstat . galmsg . t0c * 60 , oldgm . t0c * 60 ) } ,
{ " old-af0 " , oldgm . af0 } ,
{ " old-af1 " , oldgm . af1 } ,
{ " old-af2 " , oldgm . af2 } ,
{ " old-t0c " , oldgm . t0c * 60 } ,
{ " new-af0 " , svstat . galmsg . af0 } ,
{ " new-af1 " , svstat . galmsg . af1 } ,
{ " new-af2 " , svstat . galmsg . af2 } ,
{ " new-t0c " , svstat . galmsg . t0c * 60 }
} , satUTCTime ( id ) ) ;
2019-08-30 09:56:41 -06:00
}
2019-08-09 07:58:52 -06:00
}
}
else if ( wtype = = 5 ) {
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " iono " , {
2020-09-27 08:49:59 -06:00
{ " ai0 " , svstat . galmsg . ai0 } ,
{ " ai1 " , svstat . galmsg . ai1 } ,
{ " ai2 " , svstat . galmsg . ai2 } ,
{ " sf1 " , svstat . galmsg . sf1 } ,
{ " sf2 " , svstat . galmsg . sf2 } ,
{ " sf3 " , svstat . galmsg . sf3 } ,
{ " sf4 " , svstat . galmsg . sf4 } ,
{ " sf5 " , svstat . galmsg . sf5 } } , satUTCTime ( id ) ) ;
2020-01-11 12:33:30 -07:00
2019-08-09 07:58:52 -06:00
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " galbgd " , {
2020-09-27 08:49:59 -06:00
{ " BGDE1E5a " , svstat . galmsg . BGDE1E5a } ,
{ " BGDE1E5b " , svstat . galmsg . BGDE1E5b } } , satUTCTime ( id ) ) ;
2020-01-11 12:33:30 -07:00
2019-08-09 07:58:52 -06:00
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " galhealth " , {
2020-09-27 08:49:59 -06:00
{ " e1bhs " , svstat . galmsg . e1bhs } ,
{ " e5bhs " , svstat . galmsg . e5bhs } ,
{ " e5bdvs " , svstat . galmsg . e5bdvs } ,
{ " e1bdvs " , svstat . galmsg . e1bdvs } } , satUTCTime ( id ) ) ;
2019-08-09 07:58:52 -06:00
}
else if ( wtype = = 6 ) { // GST-UTC
2020-09-27 08:49:59 -06:00
const auto & sv = svstat ;
2020-02-25 04:12:35 -07:00
g_GSTUTCOffset = sv . galmsg . getUTCOffset ( sv . tow ( ) , sv . wn ( ) ) . first ;
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " utcoffset " , {
2020-02-25 04:12:35 -07:00
{ " a0 " , sv . galmsg . a0 } ,
{ " a1 " , sv . galmsg . a1 } ,
{ " t0t " , sv . galmsg . t0t } ,
{ " delta " , g_GSTUTCOffset }
2020-01-11 12:33:30 -07:00
} ,
satUTCTime ( id ) ) ;
2019-08-09 07:58:52 -06:00
2020-02-25 04:12:35 -07:00
g_dtLS = sv . galmsg . dtLS ;
2019-08-09 07:58:52 -06:00
}
2019-09-05 01:35:13 -06:00
else if ( wtype = = 7 ) {
// this contains first part of alma1
}
else if ( wtype = = 8 ) {
if ( gm . tow - svstat . galmsgTyped [ 7 ] . tow < 5 & &
svstat . galmsgTyped [ 7 ] . alma1 . svid & & gm . iodalmanac = = svstat . galmsgTyped [ 7 ] . iodalmanac ) {
// cout<<(int)wtype<<" alma-sv "<<gm.alma1.svid<< " "<<gm.alma1.deltaSqrtA<<" " <<gm.alma1.t0almanac << endl;
g_galileoalma [ gm . alma1 . svid ] = gm . alma1 ;
}
}
else if ( wtype = = 9 ) {
if ( gm . tow - svstat . galmsgTyped [ 8 ] . tow < = 30 & &
svstat . galmsgTyped [ 8 ] . alma2 . svid & & gm . iodalmanac = = svstat . galmsgTyped [ 8 ] . iodalmanac ) {
// cout<<(int)wtype<<" alma-sv "<<gm.alma2.svid<< " "<<gm.alma2.deltaSqrtA<<" " <<gm.alma2.t0almanac << endl;
g_galileoalma [ gm . alma2 . svid ] = gm . alma2 ;
}
}
2019-08-09 07:58:52 -06:00
else if ( wtype = = 10 ) { // GSTT GPS
2019-09-05 01:35:13 -06:00
if ( gm . tow - svstat . galmsgTyped [ 9 ] . tow < 5 & &
svstat . galmsgTyped [ 9 ] . alma3 . svid & & gm . iodalmanac = = svstat . galmsgTyped [ 9 ] . iodalmanac ) {
// cout<<(int)wtype<<" alma-sv "<<gm.alma3.svid<< " "<<gm.alma3.deltaSqrtA<<" " <<gm.alma3.t0almanac << endl;
// cout<<(int)wtype<<"b alma-sv "<<svstat.galmsgTyped[9].alma3.svid<< " "<<svstat.galmsgTyped[9].alma3.deltaSqrtA<<" " <<svstat.galmsgTyped[9].alma3.t0almanac << endl;
g_galileoalma [ gm . alma3 . svid ] = gm . alma3 ;
}
2020-02-25 04:12:35 -07:00
g_GSTGPSOffset = gm . getGPSOffset ( gm . tow , gm . wn ) . first ;
2020-09-27 08:49:59 -06:00
idb . addValue ( id , " gpsoffset " , { { " a0g " , svstat . galmsg . a0g } ,
{ " a1g " , svstat . galmsg . a1g } ,
{ " t0g " , svstat . galmsg . t0g } ,
{ " wn0g " , svstat . galmsg . wn0g } ,
2020-07-06 01:50:53 -06:00
{ " delta " , g_GSTGPSOffset }
2020-01-11 12:33:30 -07:00
} , satUTCTime ( id ) ) ;
2019-08-12 07:54:16 -06:00
2019-08-09 07:58:52 -06:00
}
2020-07-29 11:46:51 -06:00
}
2020-08-01 13:19:16 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : GalileoCnavType ) {
2020-09-27 08:49:59 -06:00
SatID id = { 2 , ( uint32_t ) nmm . gc ( ) . gnsssv ( ) , 8 } ; // E6
idb . addValue ( id , " galcnav " , { { " msg " , makeHexDump ( nmm . gc ( ) . contents ( ) ) } } ,
nmm . localutcseconds ( ) ) ;
2020-08-01 13:19:16 -06:00
// ... no idea what this contains
}
2020-07-29 11:46:51 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : GalileoFnavType ) {
basic_string < uint8_t > fnav ( ( uint8_t * ) nmm . gf ( ) . contents ( ) . c_str ( ) , nmm . gf ( ) . contents ( ) . size ( ) ) ;
int sv = nmm . gf ( ) . gnsssv ( ) ;
SatID id = { 2 , ( uint32_t ) sv , 6 } ; // E5a
auto & svstat = g_svstats [ id ] ;
svstat . gnss = id . gnss ;
auto oldgm = svstat . galmsg ;
2019-08-09 07:58:52 -06:00
2020-07-29 11:46:51 -06:00
auto & gm = svstat . galmsg ;
unsigned int wtype = gm . parseFnav ( fnav ) ;
2019-08-12 07:54:16 -06:00
2020-07-29 11:46:51 -06:00
if ( wtype = = 1 & & svstat . galmsgTyped . count ( 1 ) ) {
const auto & old5gm = svstat . galmsgTyped [ 1 ] ;
if ( make_tuple ( old5gm . e5ahs , old5gm . e1bhs , old5gm . e5advs , old5gm . e1bdvs ) ! =
make_tuple ( gm . e5ahs , gm . e1bhs , gm . e5advs , gm . e1bdvs ) ) {
cout < < humanTime ( id . gnss , svstat . wn ( ) , svstat . tow ( ) ) < < " src " < < nmm . sourceid ( ) < < " Galileo " < < id . sv < < " sigid " < < id . sigid < < " change in health: [ " < < humanBhs ( old5gm . e5ahs ) < < " , " < < humanBhs ( old5gm . e1bhs ) < < " , " < < ( int ) old5gm . e5advs < < " , " < < ( int ) old5gm . e1bdvs < < " ] -> [ " < < humanBhs ( gm . e5ahs ) < < " , " < < humanBhs ( gm . e1bhs ) < < " , " < < ( int ) gm . e5advs < < " , " < < ( int ) gm . e1bdvs < < " ], lastseen " < < ephAge ( old5gm . tow , gm . tow ) / 3600.0 < < " hours " < < endl ;
}
}
svstat . galmsgTyped [ wtype ] = gm ;
if ( wtype = = 1 | | wtype = = 2 | | wtype = = 3 | | wtype = = 4 ) {
idb . addValue ( id , " ephemeris " , { { " iod-live " , svstat . galmsg . iodnav } ,
{ " eph-age " , ephAge ( gm . tow , gm . getT0e ( ) ) } } , satUTCTime ( id ) ) ;
2020-09-27 08:49:59 -06:00
int w = 1 ;
2020-07-29 11:46:51 -06:00
for ( ; w < 5 ; + + w ) {
if ( ! svstat . galmsgTyped . count ( w ) )
break ;
2020-09-27 08:49:59 -06:00
if ( w > 1 & & svstat . galmsgTyped [ w - 1 ] . iodnav ! = svstat . galmsgTyped [ w ] . iodnav )
2020-07-29 11:46:51 -06:00
break ;
}
if ( w = = 5 ) { // have complete new ephemeris
if ( svstat . ephgalmsg . iodnav ! = svstat . galmsgTyped [ 2 ] . iodnav ) {
2020-09-27 08:49:59 -06:00
// cout<<"New F/NAV ephemeris for "<<makeSatIDName(id)<<" iod " << svstat.galmsgTyped[1].iodnav << " t0e " << svstat.galmsgTyped[3].t0e << " af0 "<< gm.af0 <<" iod1 "<<svstat.galmsgTyped[1].iodnav;
/*
cout < < " iod2 " < < svstat . galmsgTyped [ 2 ] . iodnav ;
cout < < " iod3 " < < svstat . galmsgTyped [ 3 ] . iodnav ;
cout < < " iod4 " < < svstat . galmsgTyped [ 4 ] . iodnav < < endl ;
*/
2020-07-29 11:46:51 -06:00
svstat . oldephgalmsg = svstat . ephgalmsg ;
2020-09-27 08:49:59 -06:00
svstat . ephgalmsg = svstat . galmsg ;
2020-07-29 11:46:51 -06:00
svstat . reportNewEphemeris ( id , idb ) ;
2019-08-09 07:58:52 -06:00
}
}
2020-07-29 11:46:51 -06:00
}
2020-09-27 08:49:59 -06:00
svstat . perrecv [ nmm . sourceid ( ) ] . t = nmm . localutcseconds ( ) ;
2020-07-29 11:46:51 -06:00
if ( wtype > = 1 & & wtype < = 4 ) { // ephemeris
if ( wtype = = 1 ) {
2020-09-27 08:49:59 -06:00
idb . addValue ( id , " sisa " , { { " value " , svstat . galmsg . sisa } } , satUTCTime ( id ) ) ;
2020-07-29 11:46:51 -06:00
idb . addValue ( id , " galbgd " , {
2020-09-27 08:49:59 -06:00
{ " BGDE1E5a " , svstat . galmsg . BGDE1E5a } ,
2020-07-29 11:46:51 -06:00
} , satUTCTime ( id ) ) ;
idb . addValue ( id , " galhealth " , {
2020-09-27 08:49:59 -06:00
{ " e5ahs " , svstat . galmsg . e5bhs } ,
{ " e5advs " , svstat . galmsg . e5bdvs }
2020-07-29 11:46:51 -06:00
} , satUTCTime ( id ) ) ;
idb . addValue ( id , " clock " , { { " offset_ns " , svstat . galmsg . getAtomicOffset ( svstat . tow ( ) ) . first } ,
2020-09-27 08:49:59 -06:00
{ " t0c " , svstat . galmsg . t0c * 60 } , // getT0c()??
{ " af0 " , svstat . galmsg . af0 } ,
{ " af1 " , svstat . galmsg . af1 } ,
{ " af2 " , svstat . galmsg . af2 } } , satUTCTime ( id ) ) ;
2020-07-29 11:46:51 -06:00
if ( oldgm . af0 & & oldgm . t0c ! = svstat . galmsg . t0c ) {
auto oldOffset = oldgm . getAtomicOffset ( svstat . tow ( ) ) ;
auto newOffset = svstat . galmsg . getAtomicOffset ( svstat . tow ( ) ) ;
svstat . timeDisco = oldOffset . first - newOffset . first ;
if ( fabs ( svstat . timeDisco ) < 10000 )
idb . addValue ( id , " clock_jump_ns " , {
{ " jump " , svstat . timeDisco } ,
{ " duration " , ephAge ( svstat . galmsg . t0c * 60 , oldgm . t0c * 60 ) } ,
{ " old-af0 " , oldgm . af0 } ,
{ " old-af1 " , oldgm . af1 } ,
{ " old-af2 " , oldgm . af2 } ,
{ " old-t0c " , oldgm . t0c * 60 } ,
{ " new-af0 " , svstat . galmsg . af0 } ,
{ " new-af1 " , svstat . galmsg . af1 } ,
{ " new-af2 " , svstat . galmsg . af2 } ,
{ " new-t0c " , svstat . galmsg . t0c * 60 }
} , satUTCTime ( id ) ) ;
}
idb . addValue ( id , " iono " , {
2020-09-27 08:49:59 -06:00
{ " ai0 " , svstat . galmsg . ai0 } ,
{ " ai1 " , svstat . galmsg . ai1 } ,
{ " ai2 " , svstat . galmsg . ai2 } ,
{ " sf1 " , svstat . galmsg . sf1 } ,
{ " sf2 " , svstat . galmsg . sf2 } ,
{ " sf3 " , svstat . galmsg . sf3 } ,
{ " sf4 " , svstat . galmsg . sf4 } ,
{ " sf5 " , svstat . galmsg . sf5 } } , satUTCTime ( id ) ) ;
2020-07-29 11:46:51 -06:00
}
}
else if ( wtype = = 4 ) {
const auto & sv = g_svstats [ id ] ;
g_GSTUTCOffset = sv . galmsg . getUTCOffset ( sv . tow ( ) , sv . wn ( ) ) . first ;
idb . addValue ( id , " utcoffset " , {
{ " a0 " , sv . galmsg . a0 } ,
{ " a1 " , sv . galmsg . a1 } ,
{ " t0t " , sv . galmsg . t0t } ,
{ " delta " , g_GSTUTCOffset }
} ,
satUTCTime ( id ) ) ;
g_dtLS = sv . galmsg . dtLS ;
g_GSTGPSOffset = gm . getGPSOffset ( gm . tow , gm . wn ) . first ;
2020-09-27 08:49:59 -06:00
idb . addValue ( id , " gpsoffset " , { { " a0g " , svstat . galmsg . a0g } ,
{ " a1g " , svstat . galmsg . a1g } ,
{ " t0g " , svstat . galmsg . t0g } ,
{ " wn0g " , svstat . galmsg . wn0g } ,
2020-07-29 11:46:51 -06:00
{ " delta " , g_GSTGPSOffset }
} , satUTCTime ( id ) ) ;
}
2019-08-09 07:58:52 -06:00
}
2019-08-09 08:50:26 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : ObserverPositionType ) {
2019-09-16 06:33:06 -06:00
g_srcpos [ nmm . sourceid ( ) ] . lastSeen = nmm . localutcseconds ( ) ;
g_srcpos [ nmm . sourceid ( ) ] . pos . x = nmm . op ( ) . x ( ) ;
g_srcpos [ nmm . sourceid ( ) ] . pos . y = nmm . op ( ) . y ( ) ;
g_srcpos [ nmm . sourceid ( ) ] . pos . z = nmm . op ( ) . z ( ) ;
2019-11-26 11:12:37 -07:00
if ( nmm . op ( ) . has_groundspeed ( ) ) {
g_srcpos [ nmm . sourceid ( ) ] . groundSpeed = nmm . op ( ) . groundspeed ( ) ;
}
2020-01-09 06:33:02 -07:00
g_srcpos [ nmm . sourceid ( ) ] . accuracy = nmm . op ( ) . acc ( ) ;
2019-11-26 11:12:37 -07:00
// idb.addValueObserver(nmm.sourceid(), "accfix", nmm.op().acc(), nmm.localutcseconds());
auto latlonh = ecefToWGS84 ( nmm . op ( ) . x ( ) , nmm . op ( ) . y ( ) , nmm . op ( ) . z ( ) ) ;
idb . addValueObserver ( nmm . sourceid ( ) , " fix " , {
{ " x " , nmm . op ( ) . x ( ) } ,
{ " y " , nmm . op ( ) . y ( ) } ,
{ " z " , nmm . op ( ) . z ( ) } ,
{ " lat " , 180.0 * std : : get < 0 > ( latlonh ) / M_PI } ,
{ " lon " , 180.0 * std : : get < 1 > ( latlonh ) / M_PI } ,
{ " h " , std : : get < 2 > ( latlonh ) } ,
{ " acc " , nmm . op ( ) . acc ( ) } ,
{ " groundspeed " , nmm . op ( ) . has_groundspeed ( ) ? nmm . op ( ) . groundspeed ( ) : - 1.0 }
} ,
nmm . localutcseconds ( ) ) ;
2019-08-09 07:58:52 -06:00
}
2019-08-09 08:50:26 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : RFDataType ) {
2019-09-16 06:33:06 -06:00
SatID id { nmm . rfd ( ) . gnssid ( ) , nmm . rfd ( ) . gnsssv ( ) , nmm . rfd ( ) . sigid ( ) } ;
2019-09-22 08:42:23 -06:00
2019-11-26 11:12:37 -07:00
2019-09-22 08:42:23 -06:00
if ( id . gnss = = 2 & & id . sigid = = 0 ) // old ubxtool output gets this wrong
id . sigid = 1 ;
2019-11-26 11:12:37 -07:00
// some sources ONLY have RFDatatype & not ReceptionDataType
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . db = nmm . rfd ( ) . cno ( ) ;
2020-07-03 15:08:52 -06:00
if ( doLogRFData )
idb . addValueObserver ( nmm . sourceid ( ) , " rfdata " ,
2019-09-16 06:33:06 -06:00
{ { " carrierphase " , nmm . rfd ( ) . carrierphase ( ) } ,
{ " doppler " , nmm . rfd ( ) . doppler ( ) } ,
{ " locktime " , nmm . rfd ( ) . locktimems ( ) } ,
2020-01-09 06:33:02 -07:00
{ " pseudorange " , nmm . rfd ( ) . pseudorange ( ) } ,
{ " prstd " , nmm . rfd ( ) . prstd ( ) } ,
{ " cpstd " , nmm . rfd ( ) . cpstd ( ) } ,
{ " dostd " , nmm . rfd ( ) . dostd ( ) }
2020-01-11 12:33:30 -07:00
} , nanoTime ( 0 , nmm . rfd ( ) . rcvwn ( ) , nmm . rfd ( ) . rcvtow ( ) ) / 1000000000.0 , id ) ;
2020-02-25 04:12:35 -07:00
if ( id . gnss = = 3 & & g_svstats [ id ] . ephBeidoumsg . sow > = 0 & & g_svstats [ id ] . ephBeidoumsg . sqrtA ! = 0 ) {
2019-09-16 09:21:53 -06:00
double freq = 1561.098 ;
if ( nmm . rfd ( ) . sigid ( ) ! = 0 )
freq = 1207.140 ;
2020-01-09 06:33:02 -07:00
// the magic 14 is because 'rcvtow()' is in GPS/Galileo TOW
// but BeiDou operates with 14 leap seconds less than GPS/Galileo
2020-02-25 04:12:35 -07:00
auto res = doDoppler ( nmm . rfd ( ) . rcvtow ( ) - 14 , g_srcpos [ nmm . sourceid ( ) ] . pos , g_svstats [ id ] . ephBeidoumsg , freq * 1000000 ) ;
2019-08-30 09:56:41 -06:00
if ( isnan ( res . preddop ) ) {
2019-09-16 06:33:06 -06:00
cerr < < " Problem with doppler calculation for C " < < id . sv < < " : " < < endl ;
2019-08-30 09:56:41 -06:00
exit ( 1 ) ;
}
2019-08-10 08:03:45 -06:00
2019-08-30 09:56:41 -06:00
time_t t = utcFromGPS ( nmm . rfd ( ) . rcvwn ( ) , nmm . rfd ( ) . rcvtow ( ) ) ;
2019-09-16 09:21:53 -06:00
if ( t - g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHzTime > 10 ) {
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHz = nmm . rfd ( ) . doppler ( ) - res . preddop ;
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHzTime = t ;
2019-08-30 09:56:41 -06:00
2020-01-11 12:33:30 -07:00
// idb.addValue(id, "delta_hz", nmm.rfd().doppler() - res.preddop);
2019-09-16 09:21:53 -06:00
auto corr = getHzCorrection ( t , nmm . sourceid ( ) , id . gnss , id . sigid , g_svstats ) ;
2019-08-30 09:56:41 -06:00
if ( corr ) {
2020-01-11 12:33:30 -07:00
// idb.addValue(id, "delta_hz_cor", nmm.rfd().doppler() - res.preddop - (*corr));
2020-01-09 06:33:02 -07:00
Point sat ;
2020-02-25 04:12:35 -07:00
getCoordinates ( nmm . rfd ( ) . rcvtow ( ) , g_svstats [ id ] . ephBeidoumsg , & sat ) ;
2020-01-09 06:33:02 -07:00
2020-07-03 15:08:52 -06:00
if ( doLogRFData )
idb . addValue ( id , " correlator " ,
2020-01-09 06:33:02 -07:00
{ { " delta_hz_cor " , nmm . rfd ( ) . doppler ( ) - res . preddop - ( * corr ) } ,
{ " delta_hz " , nmm . rfd ( ) . doppler ( ) - res . preddop } ,
{ " elevation " , getElevationDeg ( sat , g_srcpos [ nmm . sourceid ( ) ] . pos ) } ,
2020-01-12 13:42:36 -07:00
{ " hz " , nmm . rfd ( ) . doppler ( ) } ,
2020-01-09 06:33:02 -07:00
{ " prres " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . prres } ,
2020-01-12 13:42:36 -07:00
{ " qi " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . qi } ,
{ " used " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . used } ,
{ " db " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . db }
2020-01-11 12:33:30 -07:00
} , nanoTime ( 0 , nmm . rfd ( ) . rcvwn ( ) , nmm . rfd ( ) . rcvtow ( ) ) / 1000000000.0 , nmm . sourceid ( ) ) ; //this time is supplied in GPS timeframe
2020-01-09 06:33:02 -07:00
2019-08-30 09:56:41 -06:00
}
}
}
2020-02-25 04:12:35 -07:00
else if ( g_svstats [ id ] . completeIOD ( ) & &
( id . gnss ! = 6 | | ! ( random ( ) % 16 ) ) ) { // GLONASS is too slow
2019-09-16 06:33:06 -06:00
double freqMHZ = 1575.42 ;
2019-09-16 09:21:53 -06:00
if ( id . gnss = = 2 & & id . sigid = = 5 ) // this is exactly the beidou b2i freq?
2019-09-16 06:33:06 -06:00
freqMHZ = 1207.140 ;
2020-02-25 04:12:35 -07:00
auto res = g_svstats [ id ] . doDoppler ( nmm . rfd ( ) . rcvtow ( ) , g_srcpos [ nmm . sourceid ( ) ] . pos , freqMHZ * 1000000 ) ;
2019-09-16 06:33:06 -06:00
2020-01-09 06:33:02 -07:00
Point sat ;
2020-02-25 04:12:35 -07:00
g_svstats [ id ] . getCoordinates ( nmm . rfd ( ) . rcvtow ( ) , & sat ) ;
2019-09-16 06:33:06 -06:00
2019-08-12 17:15:25 -06:00
time_t t = utcFromGPS ( nmm . rfd ( ) . rcvwn ( ) , nmm . rfd ( ) . rcvtow ( ) ) ;
2020-01-09 06:33:02 -07:00
// idb.addValueObserver((int)nmm.sourceid(), "orbit",
// {{"preddop", res.preddop},
// {"radvel", res.radvel}}, t, id);
2019-08-12 17:15:25 -06:00
2020-01-09 06:33:02 -07:00
if ( t - g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHzTime > 10 ) { // only replace after 5 seconds
2019-09-16 09:21:53 -06:00
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHz = nmm . rfd ( ) . doppler ( ) - res . preddop ;
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHzTime = t ;
2020-01-11 12:33:30 -07:00
// idb.addValue(id, "delta_hz", nmm.rfd().doppler() - res.preddop);
2019-09-16 09:21:53 -06:00
auto corr = getHzCorrection ( t , nmm . sourceid ( ) , id . gnss , id . sigid , g_svstats ) ;
2019-08-12 17:15:25 -06:00
if ( corr ) {
2020-01-11 12:33:30 -07:00
// idb.addValue(id, "delta_hz_cor", nmm.rfd().doppler() - res.preddop - *corr, nmm.sourceid());
2020-07-03 15:08:52 -06:00
if ( doLogRFData )
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " correlator " ,
2020-01-09 06:33:02 -07:00
{ { " delta_hz_cor " , nmm . rfd ( ) . doppler ( ) - res . preddop - ( * corr ) } ,
{ " delta_hz " , nmm . rfd ( ) . doppler ( ) - res . preddop } ,
{ " hz " , nmm . rfd ( ) . doppler ( ) } ,
{ " elevation " , getElevationDeg ( sat , g_srcpos [ nmm . sourceid ( ) ] . pos ) } ,
{ " prres " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . prres } ,
2020-01-12 13:42:36 -07:00
{ " qi " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . qi } ,
{ " used " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . used } ,
{ " db " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . db }
2020-01-11 12:33:30 -07:00
} , t , nmm . sourceid ( ) ) ;
2020-01-09 06:33:02 -07:00
2019-08-12 17:15:25 -06:00
}
}
2019-08-10 08:03:45 -06:00
}
2019-08-12 07:54:16 -06:00
}
2020-01-09 06:33:02 -07:00
else if ( nmm . type ( ) = = NavMonMessage : : ObserverDetailsType ) {
auto & o = g_srcpos [ nmm . sourceid ( ) ] ;
o . serialno = nmm . od ( ) . serialno ( ) ;
o . swversion = nmm . od ( ) . swversion ( ) ;
o . hwversion = nmm . od ( ) . hwversion ( ) ;
o . mods = nmm . od ( ) . modules ( ) ;
if ( nmm . od ( ) . has_clockoffsetns ( ) )
o . clockOffsetNS = nmm . od ( ) . clockoffsetns ( ) ;
else
o . clockOffsetNS = - 1 ;
if ( nmm . od ( ) . has_clockoffsetdriftns ( ) )
o . clockOffsetDriftNS = nmm . od ( ) . clockoffsetdriftns ( ) ;
else
o . clockOffsetDriftNS = - 1 ;
if ( nmm . od ( ) . has_clockaccuracyns ( ) )
o . clockAccuracyNS = nmm . od ( ) . clockaccuracyns ( ) ;
else
o . clockAccuracyNS = - 1 ;
if ( nmm . od ( ) . has_freqaccuracyps ( ) )
o . freqAccuracyPS = nmm . od ( ) . freqaccuracyps ( ) ;
else
o . freqAccuracyPS = - 1 ;
if ( nmm . od ( ) . has_uptime ( ) )
o . uptime = nmm . od ( ) . uptime ( ) ;
else
o . uptime = - 1 ;
if ( nmm . od ( ) . has_recvgithash ( ) )
o . githash = nmm . od ( ) . recvgithash ( ) ;
else
o . githash . clear ( ) ;
o . vendor = nmm . od ( ) . vendor ( ) ;
o . owner = nmm . od ( ) . owner ( ) ;
o . remark = nmm . od ( ) . remark ( ) ;
idb . addValueObserver ( nmm . sourceid ( ) , " observer_details " , {
{ " clock_offset_ns " , o . clockOffsetNS } ,
{ " clock_drift_ns " , o . clockOffsetDriftNS } ,
{ " clock_acc_ns " , o . clockAccuracyNS } ,
{ " freq_acc_ps " , o . freqAccuracyPS } ,
{ " uptime " , o . uptime }
} ,
nmm . localutcseconds ( ) ) ;
}
2020-01-29 10:06:23 -07:00
else if ( nmm . type ( ) = = NavMonMessage : : UbloxJammingStatsType ) {
/*
cout < < " noisePerMS " < < nmm . ujs ( ) . noiseperms ( ) < < " agcCnt " < <
nmm . ujs ( ) . agccnt ( ) < < " flags " < < nmm . ujs ( ) . flags ( ) < < " jamind " < <
nmm . ujs ( ) . jamind ( ) < < endl ;
*/
idb . addValueObserver ( nmm . sourceid ( ) , " ubx_jamming " , {
{ " noise_per_ms " , nmm . ujs ( ) . noiseperms ( ) } ,
{ " agccnt " , nmm . ujs ( ) . agccnt ( ) } ,
{ " jamind " , nmm . ujs ( ) . jamind ( ) } ,
{ " flags " , nmm . ujs ( ) . flags ( ) }
} ,
nmm . localutcseconds ( ) ) ;
}
2020-01-09 06:33:02 -07:00
else if ( nmm . type ( ) = = NavMonMessage : : DebuggingType ) {
2020-07-29 03:38:32 -06:00
if ( doGalileoReportSpeedup )
continue ; // speedup
2020-07-03 15:08:52 -06:00
2020-01-09 06:33:02 -07:00
auto ret = parseTrkMeas ( basic_string < uint8_t > ( ( const uint8_t * ) nmm . dm ( ) . payload ( ) . c_str ( ) , nmm . dm ( ) . payload ( ) . size ( ) ) ) ;
for ( const auto & tss : ret ) {
2020-01-09 07:23:58 -07:00
SatID id { static_cast < uint32_t > ( tss . gnss ) , static_cast < uint32_t > ( tss . sv ) , tss . gnss = = 2 ? 1u : 0u } ;
2020-01-09 06:33:02 -07:00
if ( g_svstats [ id ] . completeIOD ( ) ) {
double freqMHZ = 1575.42 ;
double tsat = ldexp ( 1.0 * tss . tr , - 32 ) / 1000.0 ;
2020-02-25 04:12:35 -07:00
auto res = g_svstats [ id ] . doDoppler ( tsat , g_srcpos [ nmm . sourceid ( ) ] . pos , freqMHZ * 1000000 ) ;
2020-01-09 06:33:02 -07:00
2020-01-11 12:33:30 -07:00
// idb.addValueObserver((int)nmm.sourceid(), "orbit",
// {{"preddop", res.preddop},
// {"radvel", res.radvel}}, (time_t)nmm.localutcseconds(), id);
2020-01-09 06:33:02 -07:00
// cout << " preddop "<<res.preddop <<" meas "<<tss.dopplerHz <<" delta " << (tss.dopplerHz - res.preddop);
double t = utcFromGPS ( latestWN ( 0 , g_svstats ) , tsat ) ;
if ( t - g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHzTime > 5 ) { // only replace after 5 seconds
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHz = tss . dopplerHz - res . preddop ;
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . deltaHzTime = t ;
2020-01-11 12:33:30 -07:00
// idb.addValue(id, "delta_hz", tss.dopplerHz - res.preddop);
2020-01-09 06:33:02 -07:00
auto corr = getHzCorrection ( t , nmm . sourceid ( ) , id . gnss , id . sigid , g_svstats ) ;
if ( corr ) {
Point sat ;
2020-02-25 04:12:35 -07:00
g_svstats [ id ] . getCoordinates ( tsat , & sat ) ;
2020-01-09 06:33:02 -07:00
2020-01-11 12:33:30 -07:00
// idb.addValue(id, "delta_hz_cor", tss.dopplerHz - res.preddop - *corr, nmm.sourceid());
2020-01-09 06:33:02 -07:00
2020-07-03 15:08:52 -06:00
if ( doLogRFData )
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " correlator " ,
2020-01-09 06:33:02 -07:00
{ { " delta_hz_cor " , tss . dopplerHz - res . preddop - * corr } ,
{ " delta_hz " , tss . dopplerHz - res . preddop } ,
{ " hz " , tss . dopplerHz } ,
{ " elevation " , getElevationDeg ( sat , g_srcpos [ nmm . sourceid ( ) ] . pos ) } ,
{ " prres " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . prres } ,
2020-01-12 13:42:36 -07:00
{ " qi " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . qi } ,
{ " used " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . used } ,
{ " db " , g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . db }
2020-01-11 12:33:30 -07:00
} , t , nmm . sourceid ( ) ) ;
2020-01-09 06:33:02 -07:00
}
}
}
// cout<<endl;
}
}
2019-08-12 07:54:16 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : GPSInavType ) {
2020-07-03 15:08:52 -06:00
2019-09-16 06:33:06 -06:00
if ( nmm . gpsi ( ) . sigid ( ) ) {
2020-02-25 04:12:35 -07:00
cout < < " ignoring sigid " < < nmm . gpsi ( ) . sigid ( ) < < " for legacy GPS " < < nmm . gpsi ( ) . gnsssv ( ) < < endl ;
2019-09-16 06:33:06 -06:00
continue ;
}
2019-08-12 07:54:16 -06:00
auto cond = getCondensedGPSMessage ( std : : basic_string < uint8_t > ( ( uint8_t * ) nmm . gpsi ( ) . contents ( ) . c_str ( ) , nmm . gpsi ( ) . contents ( ) . size ( ) ) ) ;
2019-09-16 06:33:06 -06:00
SatID id { nmm . gpsi ( ) . gnssid ( ) , nmm . gpsi ( ) . gnsssv ( ) , nmm . gpsi ( ) . sigid ( ) } ;
2019-08-12 17:15:25 -06:00
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . t = nmm . localutcseconds ( ) ;
2019-08-12 07:54:16 -06:00
auto & svstat = g_svstats [ id ] ;
2020-02-25 04:12:35 -07:00
svstat . gnss = id . gnss ;
2019-08-30 09:56:41 -06:00
auto oldsvstat = svstat ;
2019-08-12 17:15:25 -06:00
uint8_t page ;
2020-02-25 04:12:35 -07:00
auto & gm = svstat . gpsmsg ;
auto oldgm = gm ;
int frame = gm . parseGPSMessage ( cond , & page ) ;
2019-08-12 17:15:25 -06:00
if ( frame = = 1 ) {
2020-01-11 12:33:30 -07:00
2020-02-25 04:12:35 -07:00
idb . addValue ( id , " clock " , { { " offset_ns " , getGPSAtomicOffset ( svstat . tow ( ) , svstat . gpsmsg ) . first } ,
2020-06-17 12:49:34 -06:00
{ " t0c " , 16 * gm . t0c } ,
{ " af0 " , 8 * gm . af0 } ,
{ " af1 " , 8 * gm . af1 } ,
{ " af2 " , 16 * gm . af2 } } , satUTCTime ( id ) ) ;
2020-01-11 12:33:30 -07:00
2020-02-25 04:12:35 -07:00
// cout<<"Got ura "<<gm.ura<<" for sv "<<id.first<<","<<id.second<<endl;
idb . addValue ( id , " gpsura " , { { " value " , gm . ura } } , satUTCTime ( id ) ) ;
2019-08-12 17:15:25 -06:00
2020-02-25 04:12:35 -07:00
if ( oldgm . af0 & & oldgm . ura ! = gm . ura ) { // XX find better way to check
cout < < humanTime ( id . gnss , gm . wn , gm . tow ) < < " src " < < nmm . sourceid ( ) < < " wn " < < gm . wn < < " GPS " < < id . sv < < " @ " < < id . sigid < < " change in URA [ " < < humanUra ( oldgm . ura ) < < " ] -> [ " < < humanUra ( gm . ura ) < < " ] " < < ( int ) gm . ura < < " , lastseen " < < ephAge ( oldgm . tow , gm . tow ) / 3600.0 < < " hours " < < endl ;
2019-09-09 12:49:31 -06:00
}
2020-02-25 04:12:35 -07:00
if ( oldgm . af0 & & oldgm . gpshealth ! = gm . gpshealth ) { // XX find better way to check
cout < < humanTime ( id . gnss , gm . wn , gm . tow ) < < " src " < < nmm . sourceid ( ) < < " wn " < < gm . wn < < " GPS " < < id . sv < < " @ " < < id . sigid < < " change in health [ " < < ( int ) oldgm . gpshealth < < " ] -> [ " < < ( int ) gm . gpshealth < < " ], lastseen " < < ephAge ( oldgm . tow , gm . tow ) / 3600.0 < < " hours " < < endl ;
2019-09-09 12:49:31 -06:00
}
2020-01-11 12:33:30 -07:00
// double age = ephAge(g_svstats[id].tow, g_svstats[id].t0c * 16);
2019-08-30 09:56:41 -06:00
2020-02-25 04:12:35 -07:00
if ( oldgm . af0 & & oldgm . t0c ! = gm . t0c ) {
auto oldOffset = getGPSAtomicOffset ( gm . tow , oldgm ) ;
auto newOffset = getGPSAtomicOffset ( gm . tow , gm ) ;
2019-08-30 09:56:41 -06:00
svstat . timeDisco = oldOffset . first - newOffset . first ;
2020-07-29 03:38:32 -06:00
if ( fabs ( svstat . timeDisco ) < 10000 ) {
idb . addValue ( id , " clock_jump_ns " , {
{ " jump " , svstat . timeDisco } ,
{ " duration " , ephAge ( gm . t0c * 16 , oldgm . t0c * 16 ) } ,
{ " old-af0 " , oldgm . af0 } ,
{ " old-af1 " , oldgm . af1 } ,
{ " old-af2 " , oldgm . af2 } ,
{ " old-t0c " , oldgm . t0c * 16 } ,
{ " new-af0 " , gm . af0 } ,
{ " new-af1 " , gm . af1 } ,
{ " new-af2 " , gm . af2 } ,
{ " new-t0c " , gm . t0c * 16 }
} , satUTCTime ( id ) ) ;
}
2019-08-30 09:56:41 -06:00
}
2019-08-12 17:15:25 -06:00
}
2019-08-13 12:44:23 -06:00
else if ( frame = = 2 ) {
2020-02-25 04:12:35 -07:00
if ( oldgm . gpshealth ! = gm . gpshealth ) {
cout < < humanTime ( id . gnss , gm . wn , gm . tow ) < < " src " < < nmm . sourceid ( ) < < " GPS " < < id . sv < < " @ " < < id . sigid < < " change in health: [ " < < ( int ) oldgm . gpshealth < < " ] -> [ " < < ( int ) gm . gpshealth < < " ] , lastseen " < < ephAge ( oldgm . tow , gm . tow ) / 3600.0 < < " hours " < < endl ;
}
svstat . gpsmsg2 = gm ;
idb . addValue ( id , " gpshealth " , { { " value " , g_svstats [ id ] . gpsmsg . gpshealth } } , satUTCTime ( id ) ) ;
if ( svstat . gpsmsg2 . gpsiod = = svstat . gpsmsg3 . gpsiod & & gm . gpsiod ! = svstat . ephgpsmsg . gpsiod ) {
svstat . oldephgpsmsg = svstat . ephgpsmsg ;
svstat . ephgpsmsg = gm ;
svstat . reportNewEphemeris ( id , idb ) ;
}
}
else if ( frame = = 3 ) {
svstat . gpsmsg3 = gm ;
if ( svstat . gpsmsg2 . gpsiod = = svstat . gpsmsg3 . gpsiod & & gm . gpsiod ! = svstat . ephgpsmsg . gpsiod ) {
svstat . oldephgpsmsg = svstat . ephgpsmsg ;
svstat . ephgpsmsg = gm ;
svstat . reportNewEphemeris ( id , idb ) ;
2019-09-09 12:49:31 -06:00
}
2019-08-13 12:44:23 -06:00
}
2019-08-12 17:15:25 -06:00
else if ( frame = = 4 & & page = = 18 ) {
2020-02-25 04:12:35 -07:00
const auto & sv = g_svstats [ id ] ;
2020-01-11 12:33:30 -07:00
2020-02-25 04:12:35 -07:00
g_GPSUTCOffset = getGPSUTCOffset ( sv . tow ( ) , sv . wn ( ) , gm ) . first ;
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " utcoffset " , {
2020-02-25 04:12:35 -07:00
{ " a0 " , gm . a0 } ,
{ " a1 " , gm . a1 } ,
{ " delta " , g_GPSUTCOffset }
2020-01-11 12:33:30 -07:00
} ,
satUTCTime ( id ) ) ;
2019-08-12 17:15:25 -06:00
}
2019-09-09 12:49:31 -06:00
else if ( ( frame = = 5 & & page < = 24 ) | | ( frame = = 4 & & page > = 25 & & page < = 32 ) ) {
2020-02-25 04:12:35 -07:00
g_gpsalma [ gm . gpsalma . sv ] = gm . gpsalma ;
2019-09-09 12:49:31 -06:00
}
2019-08-12 07:54:16 -06:00
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . t = nmm . localutcseconds ( ) ;
2020-02-25 04:12:35 -07:00
// XXX conversion possibly vital
// g_svstats[id].tow = nmm.gpsi().gnsstow();
// g_svstats[id].wn = nmm.gpsi().gnsswn();
// if(g_svstats[id].wn < 512) // XXX ROLLOVER
// g_svstats[id].wn += 2048;
2019-08-09 08:50:26 -06:00
}
2020-02-29 06:28:36 -07:00
else if ( nmm . type ( ) = = NavMonMessage : : RTCMMessageType ) {
RTCMMessage rm ;
rm . parse ( nmm . rm ( ) . contents ( ) ) ;
if ( rm . type = = 1057 | | rm . type = = 1240 ) {
for ( const auto & ed : rm . d_ephs ) {
2020-04-25 03:43:25 -06:00
auto iter = g_svstats . find ( ed . id ) ;
2020-07-29 03:38:32 -06:00
// XXX NAVCAST ONLY
2021-09-21 09:30:57 -06:00
if ( iter ! = g_svstats . end ( ) & & iter - > second . completeIOD ( ) & & iter - > second . liveIOD ( ) . getIOD ( ) = = ed . iod & & nmm . sourceid ( ) = = 302 )
2020-04-25 03:43:25 -06:00
iter - > second . rtcmEphDelta = ed ;
2020-02-29 06:28:36 -07:00
idb . addValue ( ed . id , " rtcm-eph-correction " , {
{ " iod " , ed . iod } ,
{ " radial " , ed . radial } ,
{ " along " , ed . along } ,
{ " cross " , ed . cross } ,
{ " dradial " , ed . dradial } ,
{ " dalong " , ed . dalong } ,
{ " dcross " , ed . dcross } ,
{ " ssr-iod " , rm . ssrIOD } ,
{ " ssr-provider " , rm . ssrProvider } ,
{ " ssr-solution " , rm . ssrSolution } ,
{ " tow " , rm . sow } ,
2020-06-10 01:28:42 -06:00
{ " udi " , rm . udi } ,
{ " total-dist " , sqrt ( ed . radial * ed . radial + ed . along * ed . along + ed . cross * ed . cross ) } } ,
2020-02-29 06:28:36 -07:00
nmm . localutcseconds ( ) ,
nmm . sourceid ( ) ) ;
}
}
else if ( rm . type = = 1058 | | rm . type = = 1241 ) {
2020-07-03 15:08:52 -06:00
2020-02-29 06:28:36 -07:00
for ( const auto & cd : rm . d_clocks ) {
2020-07-03 15:08:52 -06:00
auto iter = g_svstats . find ( cd . id ) ;
2021-09-21 09:30:57 -06:00
if ( iter ! = g_svstats . end ( ) & & nmm . sourceid ( ) = = 302 ) /// XXX wrong
2020-07-03 15:08:52 -06:00
iter - > second . rtcmClockDelta = cd ;
2020-02-29 06:28:36 -07:00
idb . addValue ( cd . id , " rtcm-clock-correction " , {
{ " dclock0 " , cd . dclock0 } ,
{ " dclock1 " , cd . dclock1 } ,
{ " dclock2 " , cd . dclock2 } ,
{ " ssr-iod " , rm . ssrIOD } ,
{ " ssr-provider " , rm . ssrProvider } ,
{ " ssr-solution " , rm . ssrSolution } ,
{ " tow " , rm . sow } ,
{ " udi " , rm . udi } } ,
nmm . localutcseconds ( ) ,
nmm . sourceid ( ) ) ;
}
}
2020-11-11 08:44:32 -07:00
else if ( rm . type = = 1059 | | rm . type = = 1242 ) {
for ( const auto & dcb : rm . d_dcbs ) {
idb . addValue ( dcb . first , " rtcm-dcb " , {
{ " value " , dcb . second } } ,
nmm . localutcseconds ( ) ,
nmm . sourceid ( ) ) ;
}
}
2020-07-03 15:08:52 -06:00
else if ( rm . type = = 1060 | | rm . type = = 1243 ) {
for ( const auto & ed : rm . d_ephs ) {
auto iter = g_svstats . find ( ed . id ) ;
2021-09-21 09:30:57 -06:00
if ( iter ! = g_svstats . end ( ) & & iter - > second . completeIOD ( ) & & iter - > second . liveIOD ( ) . getIOD ( ) = = ed . iod & & nmm . sourceid ( ) = = 302 )
2020-07-03 15:08:52 -06:00
iter - > second . rtcmEphDelta = ed ;
idb . addValue ( ed . id , " rtcm-eph-correction " , {
{ " iod " , ed . iod } ,
{ " radial " , ed . radial } ,
{ " along " , ed . along } ,
{ " cross " , ed . cross } ,
{ " dradial " , ed . dradial } ,
{ " dalong " , ed . dalong } ,
{ " dcross " , ed . dcross } ,
{ " ssr-iod " , rm . ssrIOD } ,
{ " ssr-provider " , rm . ssrProvider } ,
{ " ssr-solution " , rm . ssrSolution } ,
{ " tow " , rm . sow } ,
{ " udi " , rm . udi } ,
{ " total-dist " , sqrt ( ed . radial * ed . radial + ed . along * ed . along + ed . cross * ed . cross ) } } ,
nmm . localutcseconds ( ) ,
nmm . sourceid ( ) ) ;
}
}
2020-07-21 10:14:06 -06:00
else if ( rm . type = = 1045 | | rm . type = = 1046 ) { // Galileo Ephemeris
// rm.d_gm will now contain an at least partially filled out Galileo ephemeris
// 1045 is F/NAV, 1046 is I/NAV
// we have no real need for the I/NAV since we have that in spades
if ( rm . type = = 1045 ) {
const auto & eg = rm . d_gm ;
SatID id ;
id . gnss = 2 ;
id . sv = rm . d_sv ;
id . sigid = 6 ; // seems reasonable for E5a
2020-12-06 06:29:32 -07:00
static map < pair < int , int > , unsigned int > lastT0e ;
2020-07-21 10:14:06 -06:00
pair < int , int > key ( nmm . sourceid ( ) , rm . d_sv ) ;
if ( ! lastT0e . count ( key ) | | lastT0e [ key ] ! = eg . t0e ) {
idb . addValue ( id , " ephemeris-actual " , {
{ " iod " , eg . getIOD ( ) } ,
{ " t0e " , eg . t0e } ,
{ " sqrta " , eg . sqrtA } ,
{ " e " , eg . e } ,
{ " cuc " , eg . cuc } ,
{ " cus " , eg . cus } ,
{ " crc " , eg . crc } ,
{ " crs " , eg . crs } ,
{ " m0 " , eg . m0 } ,
{ " deltan " , eg . deltan } ,
{ " i0 " , eg . i0 } ,
{ " cic " , eg . cic } ,
{ " cis " , eg . cis } ,
{ " omegadot " , eg . omegadot } ,
{ " omega0 " , eg . omega0 } ,
{ " idot " , eg . idot } ,
{ " af0 " , eg . af0 } ,
{ " af1 " , eg . af1 } ,
{ " af2 " , eg . af2 } ,
{ " t0c " , eg . t0c } ,
{ " omega " , eg . omega } } , nmm . localutcseconds ( ) , nmm . sourceid ( ) ) ;
}
lastT0e [ key ] = eg . t0e ;
}
}
2020-07-03 15:08:52 -06:00
for ( const auto & cd : rm . d_clocks ) {
auto iter = g_svstats . find ( cd . id ) ;
2021-09-21 09:30:57 -06:00
if ( iter ! = g_svstats . end ( ) & & nmm . sourceid ( ) = = 302 )
2020-07-03 15:08:52 -06:00
iter - > second . rtcmClockDelta = cd ;
idb . addValue ( cd . id , " rtcm-clock-correction " , {
{ " dclock0 " , cd . dclock0 } ,
{ " dclock1 " , cd . dclock1 } ,
{ " dclock2 " , cd . dclock2 } ,
{ " ssr-iod " , rm . ssrIOD } ,
{ " ssr-provider " , rm . ssrProvider } ,
{ " ssr-solution " , rm . ssrSolution } ,
{ " tow " , rm . sow } ,
{ " iod " , cd . iod } ,
{ " udi " , rm . udi } } ,
nmm . localutcseconds ( ) ,
nmm . sourceid ( ) ) ;
}
2020-02-29 06:28:36 -07:00
}
2020-02-11 08:39:29 -07:00
else if ( nmm . type ( ) = = NavMonMessage : : GPSCnavType ) {
SatID id { nmm . gpsc ( ) . gnssid ( ) , nmm . gpsc ( ) . gnsssv ( ) , nmm . gpsc ( ) . sigid ( ) } ;
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . t = nmm . localutcseconds ( ) ;
auto & svstat = g_svstats [ id ] ;
2020-02-25 04:12:35 -07:00
svstat . gnss = id . gnss ;
2020-02-11 08:39:29 -07:00
GPSCNavState gcns ;
parseGPSCNavMessage (
std : : basic_string < uint8_t > ( ( uint8_t * ) nmm . gpsc ( ) . contents ( ) . c_str ( ) ,
nmm . gpsc ( ) . contents ( ) . size ( ) ) ,
gcns ) ;
2020-02-11 08:45:35 -07:00
// cout<<"Got a message from "<<makeSatIDName(id)<<endl;
2020-02-25 04:12:35 -07:00
// XXX conversion possibly vital
// svstat.tow = nmm.gpsc().gnsstow();
// svstat.wn = nmm.gpsc().gnsswn();
2020-02-11 08:39:29 -07:00
}
2019-08-30 09:56:41 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : BeidouInavTypeD1 ) {
2020-09-27 08:49:59 -06:00
if ( doGalileoReportSpeedup )
continue ; // speedup
2020-07-29 03:38:32 -06:00
2020-01-09 06:33:02 -07:00
try {
2019-09-16 06:33:06 -06:00
SatID id { nmm . bid1 ( ) . gnssid ( ) , nmm . bid1 ( ) . gnsssv ( ) , nmm . bid1 ( ) . sigid ( ) } ;
2019-08-26 07:58:01 -06:00
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . t = nmm . localutcseconds ( ) ;
auto & svstat = g_svstats [ id ] ;
2020-02-25 04:12:35 -07:00
svstat . gnss = id . gnss ;
2019-08-26 07:58:01 -06:00
uint8_t pageno ;
2019-08-30 09:56:41 -06:00
auto cond = getCondensedBeidouMessage ( std : : basic_string < uint8_t > ( ( uint8_t * ) nmm . bid1 ( ) . contents ( ) . c_str ( ) , nmm . bid1 ( ) . contents ( ) . size ( ) ) ) ;
2020-02-25 04:12:35 -07:00
auto & bm = svstat . beidoumsg ;
2019-09-09 12:49:31 -06:00
auto oldbm = bm ;
2019-08-26 07:58:01 -06:00
int fraid = bm . parse ( cond , & pageno ) ;
2020-02-25 04:12:35 -07:00
// XXX conversion possibly vital
// svstat.tow = nmm.bid1().gnsstow();
// svstat.wn = nmm.bid1().gnsswn();
2019-08-26 07:58:01 -06:00
if ( fraid = = 1 ) {
2019-09-09 12:49:31 -06:00
if ( oldbm . sath1 ! = bm . sath1 ) {
2020-02-25 04:12:35 -07:00
cout < < humanTime ( id . gnss , svstat . wn ( ) , svstat . tow ( ) ) < < " wn " < < bm . wn < < " sow " < < bm . sow < < " BeiDou C " < < id . sv < < " @ " < < id . sigid < < " health changed from " < < ( int ) oldbm . sath1 < < " to " < < ( int ) bm . sath1 < < " , lastseen " < < ephAge ( oldbm . sow , bm . sow ) / 3600.0 < < " hours " < < endl ;
2019-09-09 12:49:31 -06:00
}
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " clock " , { { " offset_ns " , 1000000.0 * bm . getAtomicOffset ( ) . first } ,
{ " t0c " , bm . getT0c ( ) } ,
{ " af0 " , bm . a0 * 2 } ,
{ " af1 " , bm . a1 / 16 } ,
{ " af2 " , bm . a2 / 128 } } , satUTCTime ( id ) ) ; // scaled to galileo units
idb . addValue ( id , " beidouhealth " , { { " sath1 " , bm . sath1 } } , satUTCTime ( id ) ) ;
2020-01-12 13:42:36 -07:00
idb . addValue ( id , " beidouurai " , { { " value " , bm . urai } } , satUTCTime ( id ) ) ;
2019-08-30 09:56:41 -06:00
if ( svstat . lastBeidouMessage1 . wn > = 0 & & svstat . lastBeidouMessage1 . t0c ! = bm . t0c ) {
auto oldOffset = svstat . lastBeidouMessage1 . getAtomicOffset ( bm . sow ) ;
auto newOffset = bm . getAtomicOffset ( bm . sow ) ;
svstat . timeDisco = oldOffset . first - newOffset . first ;
2020-01-12 13:42:36 -07:00
if ( fabs ( svstat . timeDisco ) < 10000 )
2020-09-27 08:49:59 -06:00
idb . addValue ( id , " clock_jump_ns " , { { " jump " , svstat . timeDisco } } , satUTCTime ( id ) ) ;
2019-08-30 09:56:41 -06:00
}
svstat . lastBeidouMessage1 = bm ;
2019-08-26 07:58:01 -06:00
}
if ( fraid = = 2 ) {
svstat . lastBeidouMessage2 = bm ;
}
if ( fraid = = 3 ) {
Point oldpoint , newpoint ;
2020-02-25 04:12:35 -07:00
if ( bm . sow - svstat . lastBeidouMessage2 . sow = = 6 ) {
if ( svstat . ephBeidoumsg . getT0e ( ) ! = svstat . beidoumsg . getT0e ( ) & & bm . sqrtA ) {
svstat . oldephBeidoumsg = svstat . ephBeidoumsg ;
svstat . ephBeidoumsg = bm ;
svstat . reportNewEphemeris ( id , idb ) ;
}
2019-08-26 07:58:01 -06:00
}
}
2019-09-03 12:05:40 -06:00
else if ( ( fraid = = 4 & & 1 < = pageno & & pageno < = 24 ) | |
( fraid = = 5 & & 1 < = pageno & & pageno < = 6 ) | |
( fraid = = 5 & & 11 < = pageno & & pageno < = 23 ) ) {
struct BeidouAlmanacEntry bae ;
2020-02-25 04:12:35 -07:00
// bm.alma.AmEpID = svstat.ephBeidoumsg.alma.AmEpID; // this comes from older messages
2019-09-03 12:05:40 -06:00
if ( processBeidouAlmanac ( bm , bae ) ) {
g_beidoualma [ bae . sv ] = bae ;
}
}
2019-08-26 07:58:01 -06:00
if ( fraid = = 5 & & pageno = = 9 ) {
2020-02-25 04:12:35 -07:00
/*
2019-08-26 07:58:01 -06:00
svstat . a0g = bm . a0gps ;
svstat . a1g = bm . a1gps ;
2020-02-25 04:12:35 -07:00
*/
2019-08-26 07:58:01 -06:00
}
if ( fraid = = 5 & & pageno = = 10 ) {
2020-02-25 04:12:35 -07:00
/*
2019-08-26 07:58:01 -06:00
svstat . a0 = bm . a0utc ;
2019-09-02 08:13:49 -06:00
svstat . a1 = bm . a1utc ;
2020-02-25 04:12:35 -07:00
*/
2019-09-02 08:13:49 -06:00
g_dtLSBeidou = bm . deltaTLS ;
2020-02-25 04:12:35 -07:00
g_BeiDouUTCOffset = bm . getUTCOffset ( bm . sow ) . first ;
2019-09-02 08:13:49 -06:00
// cout<<"Beidou leap seconds: "<<g_dtLSBeidou<<endl;
2019-08-26 07:58:01 -06:00
}
2020-01-09 06:33:02 -07:00
} catch ( std : : exception & e ) {
cerr < < " Beidou: " < < e . what ( ) < < endl ;
}
2019-08-30 09:56:41 -06:00
}
else if ( nmm . type ( ) = = NavMonMessage : : BeidouInavTypeD2 ) {
auto cond = getCondensedBeidouMessage ( std : : basic_string < uint8_t > ( ( uint8_t * ) nmm . bid2 ( ) . contents ( ) . c_str ( ) , nmm . bid2 ( ) . contents ( ) . size ( ) ) ) ;
2019-09-02 08:13:49 -06:00
/*
2019-08-30 09:56:41 -06:00
int fraid = getbitu ( & cond [ 0 ] , beidouBitconv ( 16 ) , 3 ) ;
int sow = getbitu ( & cond [ 0 ] , beidouBitconv ( 19 ) , 20 ) ;
int pnum = getbitu ( & cond [ 0 ] , beidouBitconv ( 43 ) , 4 ) ;
int pre = getbitu ( & cond [ 0 ] , beidouBitconv ( 1 ) , 11 ) ;
2019-09-02 08:13:49 -06:00
2019-08-30 09:56:41 -06:00
// cout<<"C"<< nmm.bid2().gnsssv() << " sent D2 message, pre "<<pre<<" sow "<<sow<<", FraID "<<fraid;
// if(fraid == 1)
// cout <<" pnum "<<pnum;
// cout<<endl;
2019-09-02 08:13:49 -06:00
*/
2019-08-30 09:56:41 -06:00
}
else if ( nmm . type ( ) = = NavMonMessage : : GlonassInavType ) {
2020-09-27 08:49:59 -06:00
if ( doGalileoReportSpeedup )
continue ; // speedup
2020-07-29 03:38:32 -06:00
2019-09-16 06:33:06 -06:00
SatID id { nmm . gloi ( ) . gnssid ( ) , nmm . gloi ( ) . gnsssv ( ) , nmm . gloi ( ) . sigid ( ) } ;
2019-08-30 09:56:41 -06:00
auto & svstat = g_svstats [ id ] ;
2020-02-25 04:12:35 -07:00
svstat . gnss = id . gnss ;
2019-08-30 09:56:41 -06:00
auto & gm = svstat . glonassMessage ;
2019-08-30 17:08:56 -06:00
auto oldgm = gm ;
2019-08-30 09:56:41 -06:00
int strno = gm . parse ( std : : basic_string < uint8_t > ( ( uint8_t * ) nmm . gloi ( ) . contents ( ) . c_str ( ) , nmm . gloi ( ) . contents ( ) . size ( ) ) ) ;
g_svstats [ id ] . perrecv [ nmm . sourceid ( ) ] . t = nmm . localutcseconds ( ) ;
2019-08-30 17:08:56 -06:00
if ( strno = = 1 & & gm . n4 ! = 0 & & gm . NT ! = 0 ) {
2020-04-25 03:43:25 -06:00
// uint32_t glotime = gm.getGloTime(); // this starts GLONASS time at 31st of december 1995, 00:00 UTC
2020-02-25 04:12:35 -07:00
// CONVERSION, possibly vital
// svstat.wn = glotime / (7*86400);
// svstat.tow = glotime % (7*86400);
2019-09-09 12:49:31 -06:00
// cout<<"Glonass now: "<<humanTime(glotime + 820368000) << " n4 "<<(int)gm.n4<<" NT "<<(int)gm.NT<< " wn "<<svstat.wn <<" tow " <<svstat.tow<<endl;
2019-08-30 09:56:41 -06:00
}
2019-09-03 12:05:40 -06:00
else if ( strno = = 2 ) {
2020-02-25 04:12:35 -07:00
if ( svstat . wn ( ) > 0 )
2020-01-11 12:33:30 -07:00
idb . addValue ( id , " glohealth " , { { " Bn " , gm . Bn } } , satUTCTime ( id ) ) ;
2019-09-09 12:49:31 -06:00
if ( oldgm . Bn ! = gm . Bn ) {
2020-02-25 04:12:35 -07:00
cout < < humanTime ( id . gnss , svstat . wn ( ) , svstat . tow ( ) ) < < " n4 " < < ( int ) gm . n4 < < " NT " < < ( int ) gm . NT < < " GLONASS R " < < id . sv < < " @ " < < id . sigid < < " health changed from " < < ( int ) oldgm . Bn < < " to " < < ( int ) gm . Bn < < endl ;
2019-09-09 12:49:31 -06:00
}
2019-08-30 09:56:41 -06:00
}
2019-09-03 12:05:40 -06:00
else if ( strno = = 4 ) {
2020-02-25 04:12:35 -07:00
// svstat.aode = gm.En * 24;
if ( svstat . wn ( ) > 0 ) {
2020-01-26 05:20:20 -07:00
idb . addValue ( id , " glo_taun_ns " , { { " value " , gm . getTaunNS ( ) } } , satUTCTime ( id ) ) ;
idb . addValue ( id , " ft " , { { " value " , gm . FT } } , satUTCTime ( id ) ) ;
if ( oldgm . taun & & oldgm . taun ! = gm . taun ) {
if ( gm . getGloTime ( ) - oldgm . getGloTime ( ) < 300 ) {
svstat . timeDisco = gm . getTaunNS ( ) - oldgm . getTaunNS ( ) ;
2020-09-27 08:49:59 -06:00
idb . addValue ( id , " clock_jump_ns " , { { " jump " , svstat . timeDisco } } , satUTCTime ( id ) ) ;
2020-01-26 05:20:20 -07:00
}
2019-08-30 17:08:56 -06:00
}
}
2019-09-02 08:13:49 -06:00
if ( gm . x & & gm . y & & gm . z ) {
2020-02-25 04:12:35 -07:00
if ( svstat . ephglomsg . x ! = gm . x & &
svstat . ephglomsg . y ! = gm . y & &
svstat . ephglomsg . z ! = gm . z ) {
svstat . oldephglomsg = svstat . ephglomsg ;
svstat . ephglomsg = gm ;
svstat . reportNewEphemeris ( id , idb ) ;
2019-09-05 01:35:13 -06:00
}
2019-09-02 08:13:49 -06:00
}
2019-08-30 09:56:41 -06:00
}
2020-02-25 04:12:35 -07:00
else if ( strno = = 5 ) {
g_GlonassUTCOffset = gm . getUTCOffset ( 0 ) . first ;
g_GlonassGPSOffset = gm . getGPSOffset ( 0 ) . first ;
idb . addValue ( id , " utcoffset " , {
{ " tauc " , gm . tauc } ,
{ " delta " , g_GlonassUTCOffset }
} ,
satUTCTime ( id ) ) ;
}
2019-09-03 12:05:40 -06:00
else if ( strno = = 6 | | strno = = 8 | | strno = = 10 | | strno = = 12 | | strno = = 14 ) {
svstat . glonassAlmaEven = { nmm . localutcseconds ( ) , gm } ;
}
else if ( strno = = 7 | | strno = = 9 | | strno = = 11 | | strno = = 13 | | strno = = 15 ) {
if ( nmm . localutcseconds ( ) - svstat . glonassAlmaEven . first < 4 & & svstat . glonassAlmaEven . second . strtype = = gm . strtype - 1 ) {
g_glonassalma [ svstat . glonassAlmaEven . second . nA ] = make_pair ( svstat . glonassAlmaEven . second , gm ) ;
}
}
2019-09-02 08:13:49 -06:00
// cout<<"GLONASS R"<<id.second<<" str "<<strno<<endl;
2019-08-26 07:58:01 -06:00
}
2020-02-11 08:39:29 -07:00
else if ( nmm . type ( ) = = NavMonMessage : : SBASMessageType ) {
2020-07-29 03:38:32 -06:00
if ( doGalileoReportSpeedup )
continue ; // speedup
2020-02-11 08:39:29 -07:00
auto & sb = g_sbas [ nmm . sbm ( ) . gnsssv ( ) ] ;
2020-02-25 04:12:35 -07:00
2020-02-11 08:39:29 -07:00
sb . perrecv [ nmm . sourceid ( ) ] . last_seen = nmm . localutcseconds ( ) ;
basic_string < uint8_t > sbas ( ( uint8_t * ) nmm . sbm ( ) . contents ( ) . c_str ( ) , nmm . sbm ( ) . contents ( ) . length ( ) ) ;
2020-02-25 15:17:55 -07:00
auto delta = sb . status . parse ( sbas , nmm . localutcseconds ( ) ) ;
2020-07-03 15:08:52 -06:00
// fast correction - clogs the database, so dropping that for now
/*
2020-02-25 15:17:55 -07:00
for ( const auto & f : delta . first ) {
idb . addValue ( f . id , " sbas_fast " ,
{ { " correction " , f . correction } ,
{ " udrei " , f . udrei } } , nmm . localutcseconds ( ) ,
nmm . sbm ( ) . gnsssv ( ) , " sbas " ) ;
}
2020-07-03 15:08:52 -06:00
*/
2020-02-25 15:17:55 -07:00
for ( const auto & lt : delta . second ) {
2020-02-26 13:25:18 -07:00
auto iter = g_svstats . find ( lt . id ) ;
if ( iter = = g_svstats . end ( ) )
continue ;
const auto & s = * iter ;
bool haveEphemeris = false ;
double spaceShift = 0 , ephShift = 0 , rangeShift = 0 ;
if ( s . second . completeIOD ( ) & & ( s . second . liveIOD ( ) . getIOD ( ) & 0xff ) = = lt . iod8 ) {
Point sat ;
s . second . getCoordinates ( s . second . tow ( ) , & sat ) ;
Point adjsat = sat ;
adjsat . x + = lt . dx ;
adjsat . y + = lt . dy ;
adjsat . z + = lt . dz ;
Point sbasCenter ;
int prn = nmm . sbm ( ) . gnsssv ( ) ;
if ( prn = = 126 | | prn = = 136 | | prn = = 123 )
sbasCenter = c_egnosCenter ;
else if ( prn = = 138 | | prn = = 131 | | prn = = 133 )
sbasCenter = c_waasCenter ;
else
sbasCenter = Point { 0 , 0 , 0 } ;
double dist = Vector ( sbasCenter , adjsat ) . length ( ) - Vector ( sbasCenter , sat ) . length ( ) ;
spaceShift = dist ;
dist - = lt . dai / 3 ;
ephShift = dist ;
rangeShift = dist - g_svstats [ lt . id ] . sbas [ nmm . sbm ( ) . gnsssv ( ) ] . fast . correction ;
haveEphemeris = true ;
}
2020-02-25 15:17:55 -07:00
idb . addValue ( lt . id , " sbas_lterm " ,
{
{ " iod8 " , lt . iod8 } ,
{ " toa " , lt . toa } ,
{ " iodp " , lt . iodp } ,
{ " dx " , lt . dx } ,
{ " dy " , lt . dy } ,
{ " dz " , lt . dz } ,
{ " dai " , lt . dai } ,
{ " ddx " , lt . ddx } ,
{ " ddy " , lt . ddy } ,
{ " ddz " , lt . ddz } ,
2020-02-26 13:25:18 -07:00
{ " ddai " , lt . ddai } ,
{ " ephemeris " , 1.0 * haveEphemeris } ,
{ " space_shift " , spaceShift } ,
{ " eph_shift " , ephShift } ,
{ " range_shift " , rangeShift }
2020-02-25 15:17:55 -07:00
} , nmm . localutcseconds ( ) , nmm . sbm ( ) . gnsssv ( ) , " sbas " ) ;
}
2020-02-25 04:12:35 -07:00
if ( nmm . localutcseconds ( ) - sb . status . d_lastDNU > 120 ) {
for ( const auto & c : sb . status . d_fast ) {
g_svstats [ c . first ] . sbas [ nmm . sbm ( ) . gnsssv ( ) ] . fast = c . second ;
}
for ( const auto & c : sb . status . d_longterm ) {
g_svstats [ c . first ] . sbas [ nmm . sbm ( ) . gnsssv ( ) ] . longterm = c . second ;
}
2020-02-11 08:39:29 -07:00
}
}
2020-07-03 15:00:55 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : SARResponseType ) {
SatID id ;
id . gnss = 2 ;
id . sv = nmm . sr ( ) . gnsssv ( ) ;
id . sigid = nmm . sr ( ) . sigid ( ) ;
string hexid = nmm . sr ( ) . identifier ( ) ;
string hexstring ;
for ( int n = 0 ; n < 15 ; + + n )
hexstring + = fmt : : sprintf ( " %x " , ( int ) getbitu ( ( unsigned char * ) hexid . c_str ( ) , 4 + 4 * n , 4 ) ) ;
idb . addValue ( id , " galsar " , { { " mtype " , ( int ) nmm . sr ( ) . type ( ) } ,
{ " midentifier " , hexstring } ,
{ " mcode " , nmm . sr ( ) . code ( ) } ,
{ " mparams " , makeHexDump ( nmm . sr ( ) . params ( ) ) } } , satUTCTime ( id ) , nmm . sourceid ( ) ) ;
}
2020-07-09 09:18:35 -06:00
else if ( nmm . type ( ) = = NavMonMessage : : TimeOffsetType ) {
struct gnsstimeoffset
{
2020-07-09 13:48:30 -06:00
double offset { 0 } ;
double accuracy { - 1 } ; // this is how we detect 'unset'
2020-07-09 09:18:35 -06:00
} gps , gal , glo , bds ;
for ( const auto & o : nmm . to ( ) . offsets ( ) ) {
if ( o . gnssid ( ) = = 0 ) {
gps . offset = o . offsetns ( ) ;
gps . accuracy = o . tacc ( ) ;
} else if ( o . gnssid ( ) = = 2 ) {
gal . offset = o . offsetns ( ) ;
gal . accuracy = o . tacc ( ) ;
} else if ( o . gnssid ( ) = = 3 ) {
bds . offset = o . offsetns ( ) ;
bds . accuracy = o . tacc ( ) ;
} else if ( o . gnssid ( ) = = 6 ) {
glo . offset = o . offsetns ( ) ;
glo . accuracy = o . tacc ( ) ;
}
}
idb . addValueObserver ( nmm . sourceid ( ) , " timeoffset " ,
{ { " itow " , nmm . to ( ) . itow ( ) } ,
2020-07-09 13:48:30 -06:00
{ gps . accuracy > = 0 ? " gps-offset " : nullptr , gps . offset } ,
{ gal . accuracy > = 0 ? " gal-offset " : nullptr , gal . offset } ,
{ glo . accuracy > = 0 ? " glo-offset " : nullptr , glo . offset } ,
{ bds . accuracy > = 0 ? " bds-offset " : nullptr , bds . offset } ,
{ " gps-tacc " , gps . accuracy } ,
{ " gal-tacc " , gal . accuracy } ,
{ " glo-tacc " , glo . accuracy } ,
{ " bds-tacc " , bds . accuracy } ,
{ ( gal . accuracy > = 0 & & gps . accuracy > = 0 ) ? " gal-gps-offset " : nullptr , gal . offset - gps . offset } ,
{ ( gal . accuracy > = 0 & & bds . accuracy > = 0 ) ? " gal-bds-offset " : nullptr , gal . offset - bds . offset } ,
{ ( gal . accuracy > = 0 & & glo . accuracy > = 0 ) ? " gal-glo-offset " : nullptr , gal . offset - glo . offset } ,
{ ( gps . accuracy > = 0 & & bds . accuracy > = 0 ) ? " gps-bds-offset " : nullptr , gps . offset - bds . offset } ,
{ ( gps . accuracy > = 0 & & glo . accuracy > = 0 ) ? " gps-glo-offset " : nullptr , gps . offset - glo . offset } ,
{ ( bds . accuracy > = 0 & & glo . accuracy > = 0 ) ? " bds-glo-offset " : nullptr , bds . offset - glo . offset } } ,
2020-07-09 09:18:35 -06:00
nmm . localutcseconds ( ) ) ;
}
2019-08-09 08:50:26 -06:00
else {
cout < < " Unknown type " < < ( int ) nmm . type ( ) < < endl ;
2019-08-09 07:58:52 -06:00
}
}
}
catch ( EofException & e )
{ }
}
catch ( std : : exception & e )
{
cerr < < " Exiting because of fatal error " < < e . what ( ) < < endl ;
}
2020-07-29 11:46:51 -06:00
// dedup techniques
#if 0
/*
struct DedupKey
{
SatID id ;
int wn ;
int tow ;
basic_string < uint8_t > contents ;
bool operator < ( const DedupKey & rhs ) const
{
return tie ( id , wn , tow , contents ) <
tie ( rhs . id , rhs . wn , rhs . tow , rhs . contents ) ;
}
} ;
static set < DedupKey > s_dedup ;
DedupKey dk { id , ( int ) nmm . gf ( ) . gnsswn ( ) , ( int ) nmm . gf ( ) . gnsstow ( ) , inav } ;
if ( s_dedup . insert ( dk ) . second = = false ) {
// cout<<"Dedup"<<endl;
continue ;
}
if ( s_dedup . size ( ) > 10000 )
s_dedup . clear ( ) ;
*/
// XXX conversion, may be vital
// g_svstats[id].wn = nmm.gf().gnsswn();
# endif