📄 refclock_nmea.c
字号:
if (pps_info.clear_sequence == up->pps_info.clear_sequence) return (0); ts = up->pps_info.clear_timestamp; } else { return (0); } if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec)) return (0); up->ts = ts; tstmp.l_ui = ts.tv_sec + JAN_1970; dtemp = ts.tv_nsec * FRAC / 1e9; tstmp.l_uf = (u_int32)dtemp; *tsptr = tstmp; return (1);}#endif /* HAVE_PPSAPI *//* * nmea_receive - receive data from the serial interface */static voidnmea_receive( struct recvbuf *rbufp ){ register struct nmeaunit *up; struct refclockproc *pp; struct peer *peer; int month, day; int i; char *cp, *dp; int cmdtype; /* Use these variables to hold data until we decide its worth keeping */ char rd_lastcode[BMAX]; l_fp rd_tmp; u_short rd_lencode; /* * Initialize pointers and read the timecode and timestamp */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct nmeaunit *)pp->unitptr; rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); /* * There is a case that a <CR><LF> gives back a "blank" line */ if (rd_lencode == 0) return;#ifdef DEBUG if (debug) printf("nmea: gpsread %d %s\n", rd_lencode, rd_lastcode);#endif /* * We check the timecode format and decode its contents. The * we only care about a few of them. The most important being * the $GPRMC format * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC * For Magellan (ColorTrak) GLL probably datum (order of sentences) * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F * $GPRMB,... * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77 * $GPAPB,... * $GPGSA,... * $GPGSV,... * $GPGSV,... */#define GPXXX 0#define GPRMC 1#define GPGGA 2#define GPGLL 4 cp = rd_lastcode; cmdtype=0; if(strncmp(cp,"$GPRMC",6)==0) { cmdtype=GPRMC; } else if(strncmp(cp,"$GPGGA",6)==0) { cmdtype=GPGGA; } else if(strncmp(cp,"$GPGLL",6)==0) { cmdtype=GPGLL; } else if(strncmp(cp,"$GPXXX",6)==0) { cmdtype=GPXXX; } else return; /* See if I want to process this message type */ if ( ((peer->ttl == 0) && (cmdtype != GPRMC)) || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) ) return; pp->lencode = rd_lencode; strcpy(pp->a_lastcode,rd_lastcode); cp = pp->a_lastcode; pp->lastrec = up->tstamp = rd_tmp; up->pollcnt = 2;#ifdef DEBUG if (debug) printf("nmea: timecode %d %s\n", pp->lencode, pp->a_lastcode);#endif /* Grab field depending on clock string type */ switch( cmdtype ) { case GPRMC: /* * Test for synchronization. Check for quality byte. */ dp = field_parse(cp,2); if( dp[0] != 'A') pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; /* Now point at the time field */ dp = field_parse(cp,1); break; case GPGGA: /* * Test for synchronization. Check for quality byte. */ dp = field_parse(cp,6); if( dp[0] == '0') pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; /* Now point at the time field */ dp = field_parse(cp,1); break; case GPGLL: /* * Test for synchronization. Check for quality byte. */ dp = field_parse(cp,6); if( dp[0] != 'A') pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; /* Now point at the time field */ dp = field_parse(cp,5); break; case GPXXX: return; default: return; } /* * Check time code format of NMEA */ if( !isdigit((int)dp[0]) || !isdigit((int)dp[1]) || !isdigit((int)dp[2]) || !isdigit((int)dp[3]) || !isdigit((int)dp[4]) || !isdigit((int)dp[5]) ) { refclock_report(peer, CEVNT_BADREPLY); return; } /* * Convert time and check values. */ pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; /* Default to 0 milliseconds, if decimal convert milliseconds in one, two or three digits */ pp->nsec = 0; if (dp[6] == '.') { if (isdigit((int)dp[7])) { pp->nsec = (dp[7] - '0') * 100000000; if (isdigit((int)dp[8])) { pp->nsec += (dp[8] - '0') * 10000000; if (isdigit((int)dp[9])) { pp->nsec += (dp[9] - '0') * 1000000; } } } } if (pp->hour > 23 || pp->minute > 59 || pp->second > 59 || pp->nsec > 1000000000) { refclock_report(peer, CEVNT_BADTIME); return; } /* * Convert date and check values. */ if (cmdtype==GPRMC) { dp = field_parse(cp,9); day = dp[0] - '0'; day = (day * 10) + dp[1] - '0'; month = dp[2] - '0'; month = (month * 10) + dp[3] - '0'; pp->year = dp[4] - '0'; pp->year = (pp->year * 10) + dp[5] - '0'; } else { /* only time */ time_t tt = time(NULL); struct tm * t = gmtime(&tt); day = t->tm_mday; month = t->tm_mon + 1; pp->year= t->tm_year; } if (month < 1 || month > 12 || day < 1) { refclock_report(peer, CEVNT_BADTIME); return; } /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */ /* good thing that 2000 is a leap year */ /* pp->year will be 00-99 if read from GPS, 00-> (years since 1900) from tm_year */ if (pp->year % 4) { if (day > day1tab[month - 1]) { refclock_report(peer, CEVNT_BADTIME); return; } for (i = 0; i < month - 1; i++) day += day1tab[i]; } else { if (day > day2tab[month - 1]) { refclock_report(peer, CEVNT_BADTIME); return; } for (i = 0; i < month - 1; i++) day += day2tab[i]; } pp->day = day;#ifdef HAVE_PPSAPI /* * If the PPSAPI is working, rather use its timestamps. * assume that the PPS occurs on the second so blow any msec */ if (nmea_pps(up, &rd_tmp) == 1) { pp->lastrec = up->tstamp = rd_tmp; pp->nsec = 0; }#endif /* HAVE_PPSAPI */ /* * Process the new sample in the median filter and determine the * reference clock offset and dispersion. We use lastrec as both * the reference time and receive time, in order to avoid being * cute, like setting the reference time later than the receive * time, which may cause a paranoid protocol module to chuck out * the data. */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } /* * Only go on if we had been polled. */ if (!up->polled) return; up->polled = 0; pp->lastref = pp->lastrec; refclock_receive(peer); /* If we get here - what we got from the clock is OK, so say so */ refclock_report(peer, CEVNT_NOMINAL); record_clock_stats(&peer->srcadr, pp->a_lastcode);}/* * nmea_poll - called by the transmit procedure * * We go to great pains to avoid changing state here, since there may be * more than one eavesdropper receiving the same timecode. */static voidnmea_poll( int unit, struct peer *peer ){ register struct nmeaunit *up; struct refclockproc *pp; pp = peer->procptr; up = (struct nmeaunit *)pp->unitptr; if (up->pollcnt == 0) refclock_report(peer, CEVNT_TIMEOUT); else up->pollcnt--; pp->polls++; up->polled = 1; /* * usually nmea_receive can get a timestamp every second */ gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);}/* * * gps_send(fd,cmd, peer) Sends a command to the GPS receiver. * as gps_send(fd,"rqts,u\r", peer); * * We don't currently send any data, but would like to send * RTCM SC104 messages for differential positioning. It should * also give us better time. Without a PPS output, we're * Just fooling ourselves because of the serial code paths * */static voidgps_send( int fd, const char *cmd, struct peer *peer ){ if (write(fd, cmd, strlen(cmd)) == -1) { refclock_report(peer, CEVNT_FAULT); }}static char *field_parse( char *cp, int fn ){ char *tp; int i = fn; for (tp = cp; *tp != '\0'; tp++) { if (*tp == ',') i--; if (i == 0) break; } return (++tp);}#elseint refclock_nmea_bs;#endif /* REFCLOCK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -