1 /* 2 * refclock_nmea.c - clock driver for an NMEA GPS CLOCK 3 * Michael Petry Jun 20, 1994 4 * based on refclock_heathn.c 5 */ 6 #ifdef HAVE_CONFIG_H 7 #include <config.h> 8 #endif 9 10 #if defined(REFCLOCK) && defined(CLOCK_NMEA) 11 12 #include <stdio.h> 13 #include <ctype.h> 14 #include <sys/time.h> 15 #include <time.h> 16 17 #include "ntpd.h" 18 #include "ntp_io.h" 19 #include "ntp_refclock.h" 20 #include "ntp_stdlib.h" 21 22 /* 23 * This driver supports the NMEA GPS Receiver with 24 * 25 * Protype was refclock_trak.c, Thanks a lot. 26 * 27 * The receiver used spits out the NMEA sentences for boat navigation. 28 * And you thought it was an information superhighway. Try a raging river 29 * filled with rapids and whirlpools that rip away your data and warp time. 30 */ 31 32 /* 33 * Definitions 34 */ 35 #define DEVICE "/dev/gps%d" /* name of radio device */ 36 #define SPEED232 B4800 /* uart speed (4800 bps) */ 37 #define PRECISION (-9) /* precision assumed (about 2 ms) */ 38 #define DCD_PRECISION (-20) /* precision assumed (about 1 us) */ 39 #define REFID "GPS\0" /* reference id */ 40 #define DESCRIPTION "NMEA GPS Clock" /* who we are */ 41 42 #define LENNMEA 75 /* min timecode length */ 43 44 /* 45 * Tables to compute the ddd of year form icky dd/mm timecode. Viva la 46 * leap. 47 */ 48 static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 49 static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 50 51 /* 52 * Unit control structure 53 */ 54 struct nmeaunit { 55 int pollcnt; /* poll message counter */ 56 int polled; /* Hand in a sample? */ 57 l_fp tstamp; /* timestamp of last poll */ 58 }; 59 60 /* 61 * Function prototypes 62 */ 63 static int nmea_start P((int, struct peer *)); 64 static void nmea_shutdown P((int, struct peer *)); 65 static void nmea_receive P((struct recvbuf *)); 66 static void nmea_poll P((int, struct peer *)); 67 static void gps_send P((int, const char *, struct peer *)); 68 static char *field_parse P((char *, int)); 69 70 /* 71 * Transfer vector 72 */ 73 struct refclock refclock_nmea = { 74 nmea_start, /* start up driver */ 75 nmea_shutdown, /* shut down driver */ 76 nmea_poll, /* transmit poll message */ 77 noentry, /* handle control */ 78 noentry, /* initialize driver */ 79 noentry, /* buginfo */ 80 NOFLAGS /* not used */ 81 }; 82 83 /* 84 * nmea_start - open the GPS devices and initialize data for processing 85 */ 86 static int 87 nmea_start( 88 int unit, 89 struct peer *peer 90 ) 91 { 92 register struct nmeaunit *up; 93 struct refclockproc *pp; 94 int fd; 95 char device[20]; 96 97 /* 98 * Open serial port. Use CLK line discipline, if available. 99 */ 100 (void)sprintf(device, DEVICE, unit); 101 if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) 102 return (0); 103 104 /* 105 * Allocate and initialize unit structure 106 */ 107 if (!(up = (struct nmeaunit *) 108 emalloc(sizeof(struct nmeaunit)))) { 109 (void) close(fd); 110 return (0); 111 } 112 memset((char *)up, 0, sizeof(struct nmeaunit)); 113 pp = peer->procptr; 114 pp->io.clock_recv = nmea_receive; 115 pp->io.srcclock = (caddr_t)peer; 116 pp->io.datalen = 0; 117 pp->io.fd = fd; 118 if (!io_addclock(&pp->io)) { 119 (void) close(fd); 120 free(up); 121 return (0); 122 } 123 pp->unitptr = (caddr_t)up; 124 125 /* 126 * Initialize miscellaneous variables 127 */ 128 peer->precision = DCD_PRECISION; 129 pp->clockdesc = DESCRIPTION; 130 memcpy((char *)&pp->refid, REFID, 4); 131 up->pollcnt = 2; 132 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); 133 134 return (1); 135 } 136 137 /* 138 * nmea_shutdown - shut down a GPS clock 139 */ 140 static void 141 nmea_shutdown( 142 int unit, 143 struct peer *peer 144 ) 145 { 146 register struct nmeaunit *up; 147 struct refclockproc *pp; 148 149 pp = peer->procptr; 150 up = (struct nmeaunit *)pp->unitptr; 151 io_closeclock(&pp->io); 152 free(up); 153 } 154 155 /* 156 * nmea_receive - receive data from the serial interface 157 */ 158 static void 159 nmea_receive( 160 struct recvbuf *rbufp 161 ) 162 { 163 register struct nmeaunit *up; 164 struct refclockproc *pp; 165 struct peer *peer; 166 l_fp trtmp; 167 int month, day; 168 int i; 169 char *cp, *dp; 170 int cmdtype; 171 172 /* 173 * Initialize pointers and read the timecode and timestamp 174 */ 175 peer = (struct peer *)rbufp->recv_srcclock; 176 pp = peer->procptr; 177 up = (struct nmeaunit *)pp->unitptr; 178 pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); 179 180 /* 181 * There is a case that a <CR><LF> gives back a "blank" line 182 */ 183 if (pp->lencode == 0) 184 return; 185 186 /* 187 * We get a buffer and timestamp for each <cr>. 188 */ 189 pp->lastrec = up->tstamp = trtmp; 190 up->pollcnt = 2; 191 #ifdef DEBUG 192 if (debug) 193 printf("nmea: timecode %d %s\n", pp->lencode, 194 pp->a_lastcode); 195 #endif 196 197 /* 198 * We check the timecode format and decode its contents. The 199 * we only care about a few of them. The most important being 200 * the $GPRMC format 201 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC 202 * $GPGGA,162617.0,4548.339,N,00837.719,E,1,07,0.97,00262,M,048,M,,*5D 203 */ 204 #define GPRMC 0 205 #define GPXXX 1 206 #define GPGCA 2 207 cp = pp->a_lastcode; 208 cmdtype=0; 209 if(strncmp(cp,"$GPRMC",6)==0) { 210 cmdtype=GPRMC; 211 } 212 else if(strncmp(cp,"$GPGGA",6)==0) { 213 cmdtype=GPGCA; 214 } 215 else if(strncmp(cp,"$GPXXX",6)==0) { 216 cmdtype=GPXXX; 217 } 218 else 219 return; 220 221 switch( cmdtype ) { 222 case GPRMC: 223 case GPGCA: 224 /* 225 * Check time code format of NMEA 226 */ 227 228 dp = field_parse(cp,1); 229 if( !isdigit((int)dp[0]) || 230 !isdigit((int)dp[1]) || 231 !isdigit((int)dp[2]) || 232 !isdigit((int)dp[3]) || 233 !isdigit((int)dp[4]) || 234 !isdigit((int)dp[5]) 235 ) { 236 refclock_report(peer, CEVNT_BADREPLY); 237 return; 238 } 239 240 /* 241 * Test for synchronization. Check for quality byte. 242 */ 243 dp = field_parse(cp,2); 244 if( dp[0] != 'A') { 245 refclock_report(peer, CEVNT_BADREPLY); 246 return; 247 } 248 break; 249 case GPXXX: 250 return; 251 default: 252 return; 253 254 } 255 256 if (cmdtype ==GPGCA) { 257 /* only time */ 258 time_t tt = time(NULL); 259 struct tm * t = gmtime(&tt); 260 day = t->tm_mday; 261 month = t->tm_mon + 1; 262 pp->year= t->tm_year; 263 } else { 264 dp = field_parse(cp,9); 265 /* 266 * Convert date and check values. 267 */ 268 day = dp[0] - '0'; 269 day = (day * 10) + dp[1] - '0'; 270 month = dp[2] - '0'; 271 month = (month * 10) + dp[3] - '0'; 272 pp->year = dp[4] - '0'; 273 pp->year = (pp->year * 10) + dp[5] - '0'; 274 } 275 276 if (month < 1 || month > 12 || day < 1) { 277 refclock_report(peer, CEVNT_BADTIME); 278 return; 279 } 280 281 if (pp->year % 4) { 282 if (day > day1tab[month - 1]) { 283 refclock_report(peer, CEVNT_BADTIME); 284 return; 285 } 286 for (i = 0; i < month - 1; i++) 287 day += day1tab[i]; 288 } else { 289 if (day > day2tab[month - 1]) { 290 refclock_report(peer, CEVNT_BADTIME); 291 return; 292 } 293 for (i = 0; i < month - 1; i++) 294 day += day2tab[i]; 295 } 296 pp->day = day; 297 298 dp = field_parse(cp,1); 299 /* 300 * Convert time and check values. 301 */ 302 pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; 303 pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; 304 pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; 305 pp->msec = 0; 306 307 if (pp->hour > 23 || pp->minute > 59 || pp->second > 59) { 308 refclock_report(peer, CEVNT_BADTIME); 309 return; 310 } 311 312 /* 313 * Process the new sample in the median filter and determine the 314 * reference clock offset and dispersion. We use lastrec as both 315 * the reference time and receive time, in order to avoid being 316 * cute, like setting the reference time later than the receive 317 * time, which may cause a paranoid protocol module to chuck out 318 * the data. 319 */ 320 if (!refclock_process(pp)) { 321 refclock_report(peer, CEVNT_BADTIME); 322 return; 323 } 324 325 /* 326 * Only go on if we had been polled. 327 */ 328 if (!up->polled) 329 return; 330 up->polled = 0; 331 332 refclock_receive(peer); 333 334 record_clock_stats(&peer->srcadr, pp->a_lastcode); 335 } 336 337 /* 338 * nmea_poll - called by the transmit procedure 339 * 340 * We go to great pains to avoid changing state here, since there may be 341 * more than one eavesdropper receiving the same timecode. 342 */ 343 static void 344 nmea_poll( 345 int unit, 346 struct peer *peer 347 ) 348 { 349 register struct nmeaunit *up; 350 struct refclockproc *pp; 351 352 pp = peer->procptr; 353 up = (struct nmeaunit *)pp->unitptr; 354 if (up->pollcnt == 0) 355 refclock_report(peer, CEVNT_TIMEOUT); 356 else 357 up->pollcnt--; 358 pp->polls++; 359 up->polled = 1; 360 361 /* 362 * usually nmea_receive can get a timestamp every second 363 */ 364 365 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); 366 } 367 368 /* 369 * 370 * gps_send(fd,cmd, peer) Sends a command to the GPS receiver. 371 * as gps_send(fd,"rqts,u\r", peer); 372 * 373 * We don't currently send any data, but would like to send 374 * RTCM SC104 messages for differential positioning. It should 375 * also give us better time. Without a PPS output, we're 376 * Just fooling ourselves because of the serial code paths 377 * 378 */ 379 static void 380 gps_send( 381 int fd, 382 const char *cmd, 383 struct peer *peer 384 ) 385 { 386 387 if (write(fd, cmd, strlen(cmd)) == -1) { 388 refclock_report(peer, CEVNT_FAULT); 389 } 390 } 391 392 static char * 393 field_parse( 394 char *cp, 395 int fn 396 ) 397 { 398 char *tp; 399 int i = fn; 400 401 for (tp = cp; *tp != '\0'; tp++) { 402 if (*tp == ',') 403 i--; 404 if (i == 0) 405 break; 406 } 407 return (++tp); 408 } 409 #else 410 int refclock_nmea_bs; 411 #endif /* REFCLOCK */ 412