]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/ntp/ntpd/refclock_nmea.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / ntp / ntpd / refclock_nmea.c
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(SYS_WINNT)
11 #undef close
12 #define close closesocket
13 #endif
14
15 #if defined(REFCLOCK) && defined(CLOCK_NMEA)
16
17 #include <stdio.h>
18 #include <ctype.h>
19
20 #include "ntpd.h"
21 #include "ntp_io.h"
22 #include "ntp_unixtime.h"
23 #include "ntp_refclock.h"
24 #include "ntp_stdlib.h"
25
26 #ifdef HAVE_PPSAPI
27 # include "ppsapi_timepps.h"
28 #endif /* HAVE_PPSAPI */
29
30 /*
31  * This driver supports the NMEA GPS Receiver with
32  *
33  * Protype was refclock_trak.c, Thanks a lot.
34  *
35  * The receiver used spits out the NMEA sentences for boat navigation.
36  * And you thought it was an information superhighway.  Try a raging river
37  * filled with rapids and whirlpools that rip away your data and warp time.
38  *
39  * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in.
40  * On startup if initialization of the PPSAPI fails, it will fall back
41  * to the "normal" timestamps.
42  *
43  * The PPSAPI part of the driver understands fudge flag2 and flag3. If
44  * flag2 is set, it will use the clear edge of the pulse. If flag3 is
45  * set, kernel hardpps is enabled.
46  *
47  * GPS sentences other than RMC (the default) may be enabled by setting
48  * the relevent bits of 'mode' in the server configuration line
49  * server 127.127.20.x mode X
50  * 
51  * bit 0 - enables RMC (1)
52  * bit 1 - enables GGA (2)
53  * bit 2 - enables GLL (4)
54  * multiple sentences may be selected
55  */
56
57 /*
58  * Definitions
59  */
60 #ifdef SYS_WINNT
61 # define DEVICE "COM%d:"        /* COM 1 - 3 supported */
62 #else
63 # define DEVICE "/dev/gps%d"    /* name of radio device */
64 #endif
65 #define SPEED232        B4800   /* uart speed (4800 bps) */
66 #define PRECISION       (-9)    /* precision assumed (about 2 ms) */
67 #define PPS_PRECISION   (-20)   /* precision assumed (about 1 us) */
68 #define REFID           "GPS\0" /* reference id */
69 #define DESCRIPTION     "NMEA GPS Clock" /* who we are */
70 #define NANOSECOND      1000000000 /* one second (ns) */
71 #define RANGEGATE       500000  /* range gate (ns) */
72
73 #define LENNMEA         75      /* min timecode length */
74
75 /*
76  * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
77  * leap.
78  */
79 static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
80 static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
81
82 /*
83  * Unit control structure
84  */
85 struct nmeaunit {
86         int     pollcnt;        /* poll message counter */
87         int     polled;         /* Hand in a sample? */
88         l_fp    tstamp;         /* timestamp of last poll */
89 #ifdef HAVE_PPSAPI
90         struct timespec ts;     /* last timestamp */
91         pps_params_t pps_params; /* pps parameters */
92         pps_info_t pps_info;    /* last pps data */
93         pps_handle_t handle;    /* pps handlebars */
94 #endif /* HAVE_PPSAPI */
95 };
96
97 /*
98  * Function prototypes
99  */
100 static  int     nmea_start      P((int, struct peer *));
101 static  void    nmea_shutdown   P((int, struct peer *));
102 #ifdef HAVE_PPSAPI
103 static  void    nmea_control    P((int, struct refclockstat *, struct
104                                     refclockstat *, struct peer *));
105 static  int     nmea_ppsapi     P((struct peer *, int, int));
106 static  int     nmea_pps        P((struct nmeaunit *, l_fp *));
107 #endif /* HAVE_PPSAPI */
108 static  void    nmea_receive    P((struct recvbuf *));
109 static  void    nmea_poll       P((int, struct peer *));
110 static  void    gps_send        P((int, const char *, struct peer *));
111 static  char    *field_parse    P((char *, int));
112
113 /*
114  * Transfer vector
115  */
116 struct  refclock refclock_nmea = {
117         nmea_start,             /* start up driver */
118         nmea_shutdown,  /* shut down driver */
119         nmea_poll,              /* transmit poll message */
120 #ifdef HAVE_PPSAPI
121         nmea_control,           /* fudge control */
122 #else
123         noentry,                /* fudge control */
124 #endif /* HAVE_PPSAPI */
125         noentry,                /* initialize driver */
126         noentry,                /* buginfo */
127         NOFLAGS                 /* not used */
128 };
129
130 /*
131  * nmea_start - open the GPS devices and initialize data for processing
132  */
133 static int
134 nmea_start(
135         int unit,
136         struct peer *peer
137         )
138 {
139         register struct nmeaunit *up;
140         struct refclockproc *pp;
141         int fd;
142         char device[20];
143
144         /*
145          * Open serial port. Use CLK line discipline, if available.
146          */
147         (void)sprintf(device, DEVICE, unit);
148
149         fd = refclock_open(device, SPEED232, LDISC_CLK);
150         if (fd <= 0) {
151 #ifdef HAVE_READLINK
152           /* nmead support added by Jon Miner (cp_n18@yahoo.com)
153            *
154            * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
155            * for information about nmead
156            *
157            * To use this, you need to create a link from /dev/gpsX to
158            * the server:port where nmead is running.  Something like this:
159            *
160            * ln -s server:port /dev/gps1
161            */
162           char buffer[80];
163           char *nmea_host;
164           int   nmea_port;
165           int   len;
166           struct hostent *he;
167           struct protoent *p;
168           struct sockaddr_in so_addr;
169
170           if ((len = readlink(device,buffer,sizeof(buffer))) == -1)
171             return(0);
172           buffer[len] = 0;
173
174           if ((nmea_host = strtok(buffer,":")) == NULL)
175             return(0);
176          
177           nmea_port = atoi(strtok(NULL,":"));
178
179           if ((he = gethostbyname(nmea_host)) == NULL)
180             return(0);
181           if ((p = getprotobyname("ip")) == NULL)
182             return(0);
183           so_addr.sin_family = AF_INET;
184           so_addr.sin_port = htons(nmea_port);
185           so_addr.sin_addr = *((struct in_addr *) he->h_addr);
186
187           if ((fd = socket(PF_INET,SOCK_STREAM,p->p_proto)) == -1)
188             return(0);
189           if (connect(fd,(struct sockaddr *)&so_addr,SOCKLEN(&so_addr)) == -1) {
190             close(fd);
191             return (0);
192           }
193 #else
194             return (0);
195 #endif
196         }
197
198         /*
199          * Allocate and initialize unit structure
200          */
201         up = (struct nmeaunit *)emalloc(sizeof(struct nmeaunit));
202         if (up == NULL) {
203                 (void) close(fd);
204                 return (0);
205         }
206         memset((char *)up, 0, sizeof(struct nmeaunit));
207         pp = peer->procptr;
208         pp->io.clock_recv = nmea_receive;
209         pp->io.srcclock = (caddr_t)peer;
210         pp->io.datalen = 0;
211         pp->io.fd = fd;
212         if (!io_addclock(&pp->io)) {
213                 (void) close(fd);
214                 free(up);
215                 return (0);
216         }
217         pp->unitptr = (caddr_t)up;
218
219         /*
220          * Initialize miscellaneous variables
221          */
222         peer->precision = PRECISION;
223         pp->clockdesc = DESCRIPTION;
224         memcpy((char *)&pp->refid, REFID, 4);
225         up->pollcnt = 2;
226         gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
227
228 #ifdef HAVE_PPSAPI
229         /*
230          * Start the PPSAPI interface if it is there. Default to use
231          * the assert edge and do not enable the kernel hardpps.
232          */
233         if (time_pps_create(fd, &up->handle) < 0) {
234                 up->handle = 0;
235                 msyslog(LOG_ERR,
236                     "refclock_nmea: time_pps_create failed: %m");
237                 return (1);
238         }
239         return(nmea_ppsapi(peer, 0, 0));
240 #else
241         return (1);
242 #endif /* HAVE_PPSAPI */
243 }
244
245 /*
246  * nmea_shutdown - shut down a GPS clock
247  */
248 static void
249 nmea_shutdown(
250         int unit,
251         struct peer *peer
252         )
253 {
254         register struct nmeaunit *up;
255         struct refclockproc *pp;
256
257         pp = peer->procptr;
258         up = (struct nmeaunit *)pp->unitptr;
259 #ifdef HAVE_PPSAPI
260         if (up->handle != 0)
261                 time_pps_destroy(up->handle);
262 #endif /* HAVE_PPSAPI */
263         io_closeclock(&pp->io);
264         free(up);
265 }
266
267 #ifdef HAVE_PPSAPI
268 /*
269  * nmea_control - fudge control
270  */
271 static void
272 nmea_control(
273         int unit,               /* unit (not used */
274         struct refclockstat *in, /* input parameters (not uded) */
275         struct refclockstat *out, /* output parameters (not used) */
276         struct peer *peer       /* peer structure pointer */
277         )
278 {
279         struct refclockproc *pp;
280
281         pp = peer->procptr;
282         nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
283             pp->sloppyclockflag & CLK_FLAG3);
284 }
285
286
287 /*
288  * Initialize PPSAPI
289  */
290 int
291 nmea_ppsapi(
292         struct peer *peer,      /* peer structure pointer */
293         int enb_clear,          /* clear enable */
294         int enb_hardpps         /* hardpps enable */
295         )
296 {
297         struct refclockproc *pp;
298         struct nmeaunit *up;
299         int capability;
300
301         pp = peer->procptr;
302         up = (struct nmeaunit *)pp->unitptr;
303         if (time_pps_getcap(up->handle, &capability) < 0) {
304                 msyslog(LOG_ERR,
305                     "refclock_nmea: time_pps_getcap failed: %m");
306                 return (0);
307         }
308         memset(&up->pps_params, 0, sizeof(pps_params_t));
309         if (enb_clear)
310                 up->pps_params.mode = capability & PPS_CAPTURECLEAR;
311         else
312                 up->pps_params.mode = capability & PPS_CAPTUREASSERT;
313         if (!up->pps_params.mode) {
314                 msyslog(LOG_ERR,
315                     "refclock_nmea: invalid capture edge %d",
316                     !enb_clear);
317                 return (0);
318         }
319         up->pps_params.mode |= PPS_TSFMT_TSPEC;
320         if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
321                 msyslog(LOG_ERR,
322                     "refclock_nmea: time_pps_setparams failed: %m");
323                 return (0);
324         }
325         if (enb_hardpps) {
326                 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
327                                     up->pps_params.mode & ~PPS_TSFMT_TSPEC,
328                                     PPS_TSFMT_TSPEC) < 0) {
329                         msyslog(LOG_ERR,
330                             "refclock_nmea: time_pps_kcbind failed: %m");
331                         return (0);
332                 }
333                 pps_enable = 1;
334         }
335         peer->precision = PPS_PRECISION;
336
337 #if DEBUG
338         if (debug) {
339                 time_pps_getparams(up->handle, &up->pps_params);
340                 printf(
341                     "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n",
342                     capability, up->pps_params.api_version,
343                     up->pps_params.mode, enb_hardpps);
344         }
345 #endif
346
347         return (1);
348 }
349
350 /*
351  * Get PPSAPI timestamps.
352  *
353  * Return 0 on failure and 1 on success.
354  */
355 static int
356 nmea_pps(
357         struct nmeaunit *up,
358         l_fp *tsptr
359         )
360 {
361         pps_info_t pps_info;
362         struct timespec timeout, ts;
363         double dtemp;
364         l_fp tstmp;
365
366         /*
367          * Convert the timespec nanoseconds field to ntp l_fp units.
368          */ 
369         if (up->handle == 0)
370                 return (0);
371         timeout.tv_sec = 0;
372         timeout.tv_nsec = 0;
373         memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
374         if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
375             &timeout) < 0)
376                 return (0);
377         if (up->pps_params.mode & PPS_CAPTUREASSERT) {
378                 if (pps_info.assert_sequence ==
379                     up->pps_info.assert_sequence)
380                         return (0);
381                 ts = up->pps_info.assert_timestamp;
382         } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
383                 if (pps_info.clear_sequence ==
384                     up->pps_info.clear_sequence)
385                         return (0);
386                 ts = up->pps_info.clear_timestamp;
387         } else {
388                 return (0);
389         }
390         if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
391                 return (0);
392         up->ts = ts;
393
394         tstmp.l_ui = ts.tv_sec + JAN_1970;
395         dtemp = ts.tv_nsec * FRAC / 1e9;
396         tstmp.l_uf = (u_int32)dtemp;
397         *tsptr = tstmp;
398         return (1);
399 }
400 #endif /* HAVE_PPSAPI */
401
402 /*
403  * nmea_receive - receive data from the serial interface
404  */
405 static void
406 nmea_receive(
407         struct recvbuf *rbufp
408         )
409 {
410         register struct nmeaunit *up;
411         struct refclockproc *pp;
412         struct peer *peer;
413         int month, day;
414         int i;
415         char *cp, *dp;
416         int cmdtype;
417         /* Use these variables to hold data until we decide its worth keeping */
418         char    rd_lastcode[BMAX];
419         l_fp    rd_tmp;
420         u_short rd_lencode;
421
422         /*
423          * Initialize pointers and read the timecode and timestamp
424          */
425         peer = (struct peer *)rbufp->recv_srcclock;
426         pp = peer->procptr;
427         up = (struct nmeaunit *)pp->unitptr;
428         rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
429
430         /*
431          * There is a case that a <CR><LF> gives back a "blank" line
432          */
433         if (rd_lencode == 0)
434             return;
435
436 #ifdef DEBUG
437         if (debug)
438             printf("nmea: gpsread %d %s\n", rd_lencode,
439                    rd_lastcode);
440 #endif
441
442         /*
443          * We check the timecode format and decode its contents. The
444          * we only care about a few of them.  The most important being
445          * the $GPRMC format
446          * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
447          * For Magellan (ColorTrak) GLL probably datum (order of sentences)
448          * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL
449          * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
450          * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
451          * $GPRMB,...
452          * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
453          * $GPAPB,...
454          * $GPGSA,...
455          * $GPGSV,...
456          * $GPGSV,...
457          */
458 #define GPXXX   0
459 #define GPRMC   1
460 #define GPGGA   2
461 #define GPGLL   4
462         cp = rd_lastcode;
463         cmdtype=0;
464         if(strncmp(cp,"$GPRMC",6)==0) {
465                 cmdtype=GPRMC;
466         }
467         else if(strncmp(cp,"$GPGGA",6)==0) {
468                 cmdtype=GPGGA;
469         }
470         else if(strncmp(cp,"$GPGLL",6)==0) {
471                 cmdtype=GPGLL;
472         }
473         else if(strncmp(cp,"$GPXXX",6)==0) {
474                 cmdtype=GPXXX;
475         }
476         else
477             return;
478
479
480         /* See if I want to process this message type */
481         if ( ((peer->ttl == 0) && (cmdtype != GPRMC))
482            || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) )
483                 return;
484
485         pp->lencode = rd_lencode;
486         strcpy(pp->a_lastcode,rd_lastcode);
487         cp = pp->a_lastcode;
488
489         pp->lastrec = up->tstamp = rd_tmp;
490         up->pollcnt = 2;
491
492 #ifdef DEBUG
493         if (debug)
494             printf("nmea: timecode %d %s\n", pp->lencode,
495                    pp->a_lastcode);
496 #endif
497
498
499         /* Grab field depending on clock string type */
500         switch( cmdtype ) {
501             case GPRMC:
502                 /*
503                  * Test for synchronization.  Check for quality byte.
504                  */
505                 dp = field_parse(cp,2);
506                 if( dp[0] != 'A')
507                         pp->leap = LEAP_NOTINSYNC;
508                 else
509                         pp->leap = LEAP_NOWARNING;
510
511                 /* Now point at the time field */
512                 dp = field_parse(cp,1);
513                 break;
514
515
516             case GPGGA:
517                 /*
518                  * Test for synchronization.  Check for quality byte.
519                  */
520                 dp = field_parse(cp,6);
521                 if( dp[0] == '0')
522                         pp->leap = LEAP_NOTINSYNC;
523                 else
524                         pp->leap = LEAP_NOWARNING;
525
526                 /* Now point at the time field */
527                 dp = field_parse(cp,1);
528                 break;
529
530
531             case GPGLL:
532                 /*
533                  * Test for synchronization.  Check for quality byte.
534                  */
535                 dp = field_parse(cp,6);
536                 if( dp[0] != 'A')
537                         pp->leap = LEAP_NOTINSYNC;
538                 else
539                         pp->leap = LEAP_NOWARNING;
540
541                 /* Now point at the time field */
542                 dp = field_parse(cp,5);
543                 break;
544
545
546             case GPXXX:
547                 return;
548             default:
549                 return;
550
551         }
552
553                 /*
554                  *      Check time code format of NMEA
555                  */
556
557                 if( !isdigit((int)dp[0]) ||
558                     !isdigit((int)dp[1]) ||
559                     !isdigit((int)dp[2]) ||
560                     !isdigit((int)dp[3]) ||
561                     !isdigit((int)dp[4]) ||
562                     !isdigit((int)dp[5])        
563                     ) {
564                         refclock_report(peer, CEVNT_BADREPLY);
565                         return;
566                 }
567
568
569         /*
570          * Convert time and check values.
571          */
572         pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0';
573         pp->minute = ((dp[2] - '0') * 10) + dp[3] -  '0';
574         pp->second = ((dp[4] - '0') * 10) + dp[5] - '0';
575         /* Default to 0 milliseconds, if decimal convert milliseconds in
576            one, two or three digits
577         */
578         pp->nsec = 0; 
579         if (dp[6] == '.') {
580                 if (isdigit((int)dp[7])) {
581                         pp->nsec = (dp[7] - '0') * 100000000;
582                         if (isdigit((int)dp[8])) {
583                                 pp->nsec += (dp[8] - '0') * 10000000;
584                                 if (isdigit((int)dp[9])) {
585                                         pp->nsec += (dp[9] - '0') * 1000000;
586                                 }
587                         }
588                 }
589         }
590
591         if (pp->hour > 23 || pp->minute > 59 || pp->second > 59
592           || pp->nsec > 1000000000) {
593                 refclock_report(peer, CEVNT_BADTIME);
594                 return;
595         }
596
597
598         /*
599          * Convert date and check values.
600          */
601         if (cmdtype==GPRMC) {
602             dp = field_parse(cp,9);
603             day = dp[0] - '0';
604             day = (day * 10) + dp[1] - '0';
605             month = dp[2] - '0';
606             month = (month * 10) + dp[3] - '0';
607             pp->year = dp[4] - '0';
608             pp->year = (pp->year * 10) + dp[5] - '0';
609         }
610         else {
611         /* only time */
612             time_t tt = time(NULL);
613             struct tm * t = gmtime(&tt);
614             day = t->tm_mday;
615             month = t->tm_mon + 1;
616             pp->year= t->tm_year;
617         }
618
619         if (month < 1 || month > 12 || day < 1) {
620                 refclock_report(peer, CEVNT_BADTIME);
621                 return;
622         }
623
624         /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */
625         /* good thing that 2000 is a leap year */
626         /* pp->year will be 00-99 if read from GPS, 00->  (years since 1900) from tm_year */
627         if (pp->year % 4) {
628                 if (day > day1tab[month - 1]) {
629                         refclock_report(peer, CEVNT_BADTIME);
630                         return;
631                 }
632                 for (i = 0; i < month - 1; i++)
633                     day += day1tab[i];
634         } else {
635                 if (day > day2tab[month - 1]) {
636                         refclock_report(peer, CEVNT_BADTIME);
637                         return;
638                 }
639                 for (i = 0; i < month - 1; i++)
640                     day += day2tab[i];
641         }
642         pp->day = day;
643
644
645 #ifdef HAVE_PPSAPI
646         /*
647          * If the PPSAPI is working, rather use its timestamps.
648          * assume that the PPS occurs on the second so blow any msec
649          */
650         if (nmea_pps(up, &rd_tmp) == 1) {
651                 pp->lastrec = up->tstamp = rd_tmp;
652                 pp->nsec = 0;
653         }
654 #endif /* HAVE_PPSAPI */
655
656         /*
657          * Process the new sample in the median filter and determine the
658          * reference clock offset and dispersion. We use lastrec as both
659          * the reference time and receive time, in order to avoid being
660          * cute, like setting the reference time later than the receive
661          * time, which may cause a paranoid protocol module to chuck out
662          * the data.
663          */
664
665         if (!refclock_process(pp)) {
666                 refclock_report(peer, CEVNT_BADTIME);
667                 return;
668         }
669
670
671
672         /*
673          * Only go on if we had been polled.
674          */
675         if (!up->polled)
676             return;
677         up->polled = 0;
678         pp->lastref = pp->lastrec;
679         refclock_receive(peer);
680
681         /* If we get here - what we got from the clock is OK, so say so */
682          refclock_report(peer, CEVNT_NOMINAL);
683
684         record_clock_stats(&peer->srcadr, pp->a_lastcode);
685
686 }
687
688 /*
689  * nmea_poll - called by the transmit procedure
690  *
691  * We go to great pains to avoid changing state here, since there may be
692  * more than one eavesdropper receiving the same timecode.
693  */
694 static void
695 nmea_poll(
696         int unit,
697         struct peer *peer
698         )
699 {
700         register struct nmeaunit *up;
701         struct refclockproc *pp;
702
703         pp = peer->procptr;
704         up = (struct nmeaunit *)pp->unitptr;
705         if (up->pollcnt == 0)
706             refclock_report(peer, CEVNT_TIMEOUT);
707         else
708             up->pollcnt--;
709         pp->polls++;
710         up->polled = 1;
711
712         /*
713          * usually nmea_receive can get a timestamp every second
714          */
715
716         gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
717 }
718
719 /*
720  *
721  *      gps_send(fd,cmd, peer)  Sends a command to the GPS receiver.
722  *       as     gps_send(fd,"rqts,u\r", peer);
723  *
724  *      We don't currently send any data, but would like to send
725  *      RTCM SC104 messages for differential positioning. It should
726  *      also give us better time. Without a PPS output, we're
727  *      Just fooling ourselves because of the serial code paths
728  *
729  */
730 static void
731 gps_send(
732         int fd,
733         const char *cmd,
734         struct peer *peer
735         )
736 {
737
738         if (write(fd, cmd, strlen(cmd)) == -1) {
739                 refclock_report(peer, CEVNT_FAULT);
740         }
741 }
742
743 static char *
744 field_parse(
745         char *cp,
746         int fn
747         )
748 {
749         char *tp;
750         int i = fn;
751
752         for (tp = cp; *tp != '\0'; tp++) {
753                 if (*tp == ',')
754                     i--;
755                 if (i == 0)
756                     break;
757         }
758         return (++tp);
759 }
760 #else
761 int refclock_nmea_bs;
762 #endif /* REFCLOCK */