// // GPS Daemon // Neal Probert // #include #include #include #include #include #include #include #include #include #include #include #include "UriParse.h" #include "GpsDaemon.h" #include "NmeaParser.h" #include "ApplanixParser.h" #include "FastraxParser.h" #include "GarminParser.h" #include "SirfParser.h" #include "UbloxParser.h" #include "netlib.h" //**************************************************************************** // defines //***************************************************************************/ //**************************************************************************** // macros //***************************************************************************/ //**************************************************************************** // structs & typedefs //***************************************************************************/ //**************************************************************************** // global constants //***************************************************************************/ //**************************************************************************** // global variables //***************************************************************************/ //**************************************************************************** // static constants //***************************************************************************/ //**************************************************************************** // static variables //***************************************************************************/ //**************************************************************************** // static functions //***************************************************************************/ //**************************************************************************** // C++ functions //***************************************************************************/ GpsDaemon::GpsDaemon() { log_open( GPSD_NAME ); clockset = 0; msgcount = 0; dgps_corr = true; SourceIn = CorrIn = -1; strcpy( Uri, "" ); nClients = 0; SetClientTimeout(false); // don't reset timeout on client activity } GpsDaemon::~GpsDaemon() { Gps.GpsClose(); Log.LogClose(); } /* NMEA **********************************************************************/ void GpsDaemon::PositionListener( const GpsPoint &Pos, const ErrorInfo &Err ) { } void GpsDaemon::TimeListener( const struct timeval &tv ) { // good fix and time if ( clockset && tv.tv_sec ) { if ( getuid() == 0 ) settimeofday( &tv, NULL ); clockset = 0; } } /* TCP ***********************************************************************/ int GpsDaemon::ServerTimeout(void) { // timeout (a bad thing) DgpsReconnect(); return 0; } int GpsDaemon::ServerSocket(void) { char buf[2048]; int n = 0; if ( IsSet( CorrIn ) ) { // corrections if ( dgps_corr ) // from RTCM server (once a minute) n = Dgps.DgpsRead( buf, sizeof(buf) ); else // from NTRIP server (once a minute) n = Ntrip.NtripRead( (unsigned char *)buf, sizeof(buf) ); // xmit if ( n > 0 ) Gps.GpsWrite( buf, n ); else if ( n == 0 ) { if ( dgps_corr ) log_error( "Remote RTCM server closed!" ); else log_error( "Remote NTRIP server closed!" ); DgpsReconnect(); } ResetServerTimeout(); } else if ( IsSet( SourceIn ) ) { if ( gps_source ) // packet from GPS device n = Gps.GpsRead( buf, sizeof(buf) ); else // remote gpsd/glty n = Gpsd.Recv( buf, sizeof(buf) ); if ( n > 0 && Parser && Parser->GpsParse(buf, n) > 0 ) { msgcount++; // 'cast ClientCast( buf, n ); } } return n; } int GpsDaemon::ClientIn( int sock, const char *buf, int n ) { // allows for NMEA playback via netcat if ( *buf == '$' ) { // broadcast it Bcast.SendTo( buf, n ); // send to clients TcpServer::ClientCast( buf, n ); } else { // parse for commands? // just log it log_write( buf ); } return n; } int GpsDaemon::ClientUp( int sock ) { if ( nClients++ == 0 ) ; return 1; } void GpsDaemon::ClientDown( int sock ) { // disconnect source if ( --nClients <= 0 ) nClients = 0; } void GpsDaemon::ClientCast( const char *buf, int n ) { // broadcast it Bcast.SendTo( buf, n ); // send to clients TcpServer::ClientCast( buf, n ); // log NMEA data with time stamp Log.LogWrite( buf, n ); } /* GPS ***********************************************************************/ int GpsDaemon::GpsOpen( const char *device, int baud ) { UriParse parsed; parsed.setRate( baud ); parsed.setUri( device ); const char *proto = parsed.getProto(); SourceIn = -1; if ( !proto ) proto = "nmea"; // connect to gpsd? if ( strcmp( proto, "gpsd" ) == 0 ) { // does r mode for NMEA SourceIn = Gpsd.GpsdConnect( parsed.getHost() ); proto = "nmea"; } else if ( strcmp( proto, "glty" ) == 0 ) { // put in NMEA mode SourceIn = Gpsd.GpsdConnect( parsed.getHost() ); Gpsd.Send( "$PGLTY,NMEA\n", 12 ); proto = "pvii"; } else { // open device SourceIn = Gps.GpsOpen( parsed.getPath(), parsed.getRate() ); gps_source = true; } // check if ( SourceIn < 0 ) return SourceIn; bool binary = false; // attach parser (should probably use a table) if ( strcasecmp( proto, "nmea") == 0 ) { // ascii NmeaParser *parser = new NmeaParser(); Parser = (GpsParser *)parser; } else if ( strcasecmp( proto, "applanix") == 0 ) { // binary binary = true; ApplanixParser *parser = new ApplanixParser(); Parser = (GpsParser *)parser; } else if ( strcasecmp( proto, "fastrax") == 0 ) { // ascii FastraxParser *parser = new FastraxParser(); Parser = (GpsParser *)parser; } else if ( strcasecmp( proto, "garmin") == 0 ) { // ascii/binary GarminParser *parser = new GarminParser(); Parser = (GpsParser *)parser; } else if ( strcasecmp( proto, "sirf") == 0 ) { // binary SirfParser *parser = new SirfParser(); Parser = (GpsParser *)parser; } else if ( strcasecmp( proto, "ublox") == 0 ) { // ascii/binary UbloxParser *parser = new UbloxParser(); Parser = (GpsParser *)parser; } else { // ascii NmeaParser *parser = new NmeaParser(); Parser = (GpsParser *)parser; } // set mode if ( binary ) Gps.SetCanonical( false, 0, 0 ); // subscribe Parser->Subscribe( (GpsListener*)this ); // add listener AddFd( SourceIn ); return SourceIn; } int GpsDaemon::DgpsConnect( const char *uri ) { if ( !uri ) return -1; // already connected? if ( CorrIn >= 0 ) return CorrIn; UriParse parsed; parsed.setService( "2101" ); parsed.setUri( uri ); const char *proto = parsed.getProto(); if ( strcmp( proto, "dgps" ) == 0 || strcmp( proto, "dgpsip" ) == 0 || strcmp( proto, "rtcmd" ) == 0 ) { // RTCM server (dgpsip) CorrIn = Dgps.DgpsConnect( parsed.getHost(), parsed.getService() ); dgps_corr = true; } else if ( strcmp( proto, "ntrip" ) == 0 ) { // NTRIP caster CorrIn = Ntrip.NtripConnect( uri ); dgps_corr = false; } // add listener if ( CorrIn >= 0 ) { strcpy( Uri, uri ); AddFd( CorrIn ); } return CorrIn; } void GpsDaemon::DgpsDisconnect( void ) { if ( CorrIn >= 0 ) ; else return; Dgps.DgpsClose(); Ntrip.NtripClose(); DelFd( CorrIn ); CorrIn = -1; } void GpsDaemon::DgpsReconnect( void ) { if ( nClients == 0 || strlen(Uri) == 0 ) return; log_printf( "Remote RTCM/NTRIP timed out, reconnecting" ); Dgps.DgpsClose(); Ntrip.NtripClose(); DelFd( CorrIn ); CorrIn = -1; DgpsConnect( Uri ); } int GpsDaemon::GpsBroadcast( const char *host ) { const char *port = GPSD_SERVICE; int sock = Bcast.Caster( host, port ); return sock; }