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