1 | /* |
---|
2 | * refclock_hpgps - clock driver for HP 58503A GPS receiver |
---|
3 | */ |
---|
4 | #ifdef HAVE_CONFIG_H |
---|
5 | #include <config.h> |
---|
6 | #endif |
---|
7 | |
---|
8 | #if defined(REFCLOCK) && defined(HPGPS) |
---|
9 | |
---|
10 | #include <stdio.h> |
---|
11 | #include <ctype.h> |
---|
12 | #include <sys/time.h> |
---|
13 | |
---|
14 | #include "ntpd.h" |
---|
15 | #include "ntp_io.h" |
---|
16 | #include "ntp_refclock.h" |
---|
17 | #include "ntp_stdlib.h" |
---|
18 | |
---|
19 | /* Version 0.1 April 1, 1995 |
---|
20 | * 0.2 April 25, 1995 |
---|
21 | * tolerant of missing timecode response prompt and sends |
---|
22 | * clear status if prompt indicates error; |
---|
23 | * can use either local time or UTC from receiver; |
---|
24 | * can get receiver status screen via flag4 |
---|
25 | * |
---|
26 | * WARNING!: This driver is UNDER CONSTRUCTION |
---|
27 | * Everything in here should be treated with suspicion. |
---|
28 | * If it looks wrong, it probably is. |
---|
29 | * |
---|
30 | * Comments and/or questions to: Dave Vitanye |
---|
31 | * Hewlett Packard Company |
---|
32 | * dave@scd.hp.com |
---|
33 | * (408) 553-2856 |
---|
34 | * |
---|
35 | * Thanks to the author of the PST driver, which was the starting point for |
---|
36 | * this one. |
---|
37 | * |
---|
38 | * This driver supports the HP 58503A Time and Frequency Reference Receiver. |
---|
39 | * This receiver uses HP SmartClock (TM) to implement an Enhanced GPS receiver. |
---|
40 | * The receiver accuracy when locked to GPS in normal operation is better |
---|
41 | * than 1 usec. The accuracy when operating in holdover is typically better |
---|
42 | * than 10 usec. per day. |
---|
43 | * |
---|
44 | * The receiver should be operated with factory default settings. |
---|
45 | * Initial driver operation: expects the receiver to be already locked |
---|
46 | * to GPS, configured and able to output timecode format 2 messages. |
---|
47 | * |
---|
48 | * The driver uses the poll sequence :PTIME:TCODE? to get a response from |
---|
49 | * the receiver. The receiver responds with a timecode string of ASCII |
---|
50 | * printing characters, followed by a <cr><lf>, followed by a prompt string |
---|
51 | * issued by the receiver, in the following format: |
---|
52 | * T#yyyymmddhhmmssMFLRVcc<cr><lf>scpi > |
---|
53 | * |
---|
54 | * The driver processes the response at the <cr> and <lf>, so what the |
---|
55 | * driver sees is the prompt from the previous poll, followed by this |
---|
56 | * timecode. The prompt from the current poll is (usually) left unread until |
---|
57 | * the next poll. So (except on the very first poll) the driver sees this: |
---|
58 | * |
---|
59 | * scpi > T#yyyymmddhhmmssMFLRVcc<cr><lf> |
---|
60 | * |
---|
61 | * The T is the on-time character, at 980 msec. before the next 1PPS edge. |
---|
62 | * The # is the timecode format type. We look for format 2. |
---|
63 | * Without any of the CLK or PPS stuff, then, the receiver buffer timestamp |
---|
64 | * at the <cr> is 24 characters later, which is about 25 msec. at 9600 bps, |
---|
65 | * so the first approximation for fudge time1 is nominally -0.955 seconds. |
---|
66 | * This number probably needs adjusting for each machine / OS type, so far: |
---|
67 | * -0.955000 on an HP 9000 Model 712/80 HP-UX 9.05 |
---|
68 | * -0.953175 on an HP 9000 Model 370 HP-UX 9.10 |
---|
69 | * |
---|
70 | * This receiver also provides a 1PPS signal, but I haven't figured out |
---|
71 | * how to deal with any of the CLK or PPS stuff yet. Stay tuned. |
---|
72 | * |
---|
73 | */ |
---|
74 | |
---|
75 | /* |
---|
76 | * Fudge Factors |
---|
77 | * |
---|
78 | * Fudge time1 is used to accomodate the timecode serial interface adjustment. |
---|
79 | * Fudge flag4 can be set to request a receiver status screen summary, which |
---|
80 | * is recorded in the clockstats file. |
---|
81 | */ |
---|
82 | |
---|
83 | /* |
---|
84 | * Interface definitions |
---|
85 | */ |
---|
86 | #define DEVICE "/dev/hpgps%d" /* device name and unit */ |
---|
87 | #define SPEED232 B9600 /* uart speed (9600 baud) */ |
---|
88 | #define PRECISION (-10) /* precision assumed (about 1 ms) */ |
---|
89 | #define REFID "GPS\0" /* reference ID */ |
---|
90 | #define DESCRIPTION "HP 58503A GPS Time and Frequency Reference Receiver" |
---|
91 | |
---|
92 | #define NSAMPLES 3 /* stages of median filter */ |
---|
93 | #define SMAX 23*80+1 /* for :SYSTEM:PRINT? status screen response */ |
---|
94 | |
---|
95 | #define MTZONE 2 /* number of fields in timezone reply */ |
---|
96 | #define MTCODET2 12 /* number of fields in timecode format T2 */ |
---|
97 | #define NTCODET2 21 /* number of chars to checksum in format T2 */ |
---|
98 | |
---|
99 | /* |
---|
100 | * Imported from ntp_timer module |
---|
101 | */ |
---|
102 | extern u_long current_time; /* current time (s) */ |
---|
103 | |
---|
104 | /* |
---|
105 | * Imported from ntpd module |
---|
106 | */ |
---|
107 | extern int debug; /* global debug flag */ |
---|
108 | |
---|
109 | /* |
---|
110 | * Tables to compute the day of year from yyyymmdd timecode. |
---|
111 | * Viva la leap. |
---|
112 | */ |
---|
113 | static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
---|
114 | static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
---|
115 | |
---|
116 | /* |
---|
117 | * Unit control structure |
---|
118 | */ |
---|
119 | struct hpgpsunit { |
---|
120 | int pollcnt; /* poll message counter */ |
---|
121 | int tzhour; /* timezone offset, hours */ |
---|
122 | int tzminute; /* timezone offset, minutes */ |
---|
123 | int linecnt; /* set for expected multiple line responses */ |
---|
124 | char *lastptr; /* pointer to receiver response data */ |
---|
125 | char statscrn[SMAX]; /* receiver status screen buffer */ |
---|
126 | }; |
---|
127 | |
---|
128 | /* |
---|
129 | * Function prototypes |
---|
130 | */ |
---|
131 | static int hpgps_start P((int, struct peer *)); |
---|
132 | static void hpgps_shutdown P((int, struct peer *)); |
---|
133 | static void hpgps_receive P((struct recvbuf *)); |
---|
134 | static void hpgps_poll P((int, struct peer *)); |
---|
135 | |
---|
136 | /* |
---|
137 | * Transfer vector |
---|
138 | */ |
---|
139 | struct refclock refclock_hpgps = { |
---|
140 | hpgps_start, /* start up driver */ |
---|
141 | hpgps_shutdown, /* shut down driver */ |
---|
142 | hpgps_poll, /* transmit poll message */ |
---|
143 | noentry, /* not used (old hpgps_control) */ |
---|
144 | noentry, /* initialize driver */ |
---|
145 | noentry, /* not used (old hpgps_buginfo) */ |
---|
146 | NOFLAGS /* not used */ |
---|
147 | }; |
---|
148 | |
---|
149 | |
---|
150 | /* |
---|
151 | * hpgps_start - open the devices and initialize data for processing |
---|
152 | */ |
---|
153 | static int |
---|
154 | hpgps_start(unit, peer) |
---|
155 | int unit; |
---|
156 | struct peer *peer; |
---|
157 | { |
---|
158 | register struct hpgpsunit *up; |
---|
159 | struct refclockproc *pp; |
---|
160 | int fd; |
---|
161 | char device[20]; |
---|
162 | |
---|
163 | /* |
---|
164 | * Open serial port. Use CLK line discipline, if available. |
---|
165 | */ |
---|
166 | (void)sprintf(device, DEVICE, unit); |
---|
167 | #ifdef TTYCLK |
---|
168 | if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) |
---|
169 | #else |
---|
170 | if (!(fd = refclock_open(device, SPEED232, 0))) |
---|
171 | #endif /* TTYCLK */ |
---|
172 | return (0); |
---|
173 | |
---|
174 | /* |
---|
175 | * Allocate and initialize unit structure |
---|
176 | */ |
---|
177 | if (!(up = (struct hpgpsunit *) |
---|
178 | emalloc(sizeof(struct hpgpsunit)))) { |
---|
179 | (void) close(fd); |
---|
180 | return (0); |
---|
181 | } |
---|
182 | memset((char *)up, 0, sizeof(struct hpgpsunit)); |
---|
183 | pp = peer->procptr; |
---|
184 | pp->io.clock_recv = hpgps_receive; |
---|
185 | pp->io.srcclock = (caddr_t)peer; |
---|
186 | pp->io.datalen = 0; |
---|
187 | pp->io.fd = fd; |
---|
188 | if (!io_addclock(&pp->io)) { |
---|
189 | (void) close(fd); |
---|
190 | free(up); |
---|
191 | return (0); |
---|
192 | } |
---|
193 | pp->unitptr = (caddr_t)up; |
---|
194 | |
---|
195 | /* |
---|
196 | * Initialize miscellaneous variables |
---|
197 | */ |
---|
198 | peer->precision = PRECISION; |
---|
199 | pp->clockdesc = DESCRIPTION; |
---|
200 | memcpy((char *)&pp->refid, REFID, 4); |
---|
201 | up->tzhour = 0; |
---|
202 | up->tzminute = 0; |
---|
203 | |
---|
204 | *up->statscrn = '\0'; |
---|
205 | up->lastptr = up->statscrn; |
---|
206 | up->pollcnt = 2; |
---|
207 | |
---|
208 | /* |
---|
209 | * Get the identifier string, which is logged but otherwise ignored, |
---|
210 | * and get the local timezone information |
---|
211 | */ |
---|
212 | up->linecnt = 1; |
---|
213 | if (write(pp->io.fd, "*IDN?\r:PTIME:TZONE?\r", 20) != 20) |
---|
214 | refclock_report(peer, CEVNT_FAULT); |
---|
215 | |
---|
216 | return (1); |
---|
217 | } |
---|
218 | |
---|
219 | |
---|
220 | /* |
---|
221 | * hpgps_shutdown - shut down the clock |
---|
222 | */ |
---|
223 | static void |
---|
224 | hpgps_shutdown(unit, peer) |
---|
225 | int unit; |
---|
226 | struct peer *peer; |
---|
227 | { |
---|
228 | register struct hpgpsunit *up; |
---|
229 | struct refclockproc *pp; |
---|
230 | |
---|
231 | pp = peer->procptr; |
---|
232 | up = (struct hpgpsunit *)pp->unitptr; |
---|
233 | io_closeclock(&pp->io); |
---|
234 | free(up); |
---|
235 | } |
---|
236 | |
---|
237 | |
---|
238 | /* |
---|
239 | * hpgps_receive - receive data from the serial interface |
---|
240 | */ |
---|
241 | static void |
---|
242 | hpgps_receive(rbufp) |
---|
243 | struct recvbuf *rbufp; |
---|
244 | { |
---|
245 | register struct hpgpsunit *up; |
---|
246 | struct refclockproc *pp; |
---|
247 | struct peer *peer; |
---|
248 | l_fp trtmp; |
---|
249 | char tcodechar1; /* identifies timecode format */ |
---|
250 | char tcodechar2; /* identifies timecode format */ |
---|
251 | char timequal; /* time figure of merit: 0-9 */ |
---|
252 | char freqqual; /* frequency figure of merit: 0-3 */ |
---|
253 | char leapchar; /* leapsecond: + or 0 or - */ |
---|
254 | char servchar; /* request for service: 0 = no, 1 = yes */ |
---|
255 | char syncchar; /* time info is invalid: 0 = no, 1 = yes */ |
---|
256 | short expectedsm; /* expected timecode byte checksum */ |
---|
257 | short tcodechksm; /* computed timecode byte checksum */ |
---|
258 | int i,m,n; |
---|
259 | int month, day, lastday; |
---|
260 | char *tcp; /* timecode pointer (skips over the prompt) */ |
---|
261 | char prompt[BMAX]; /* prompt in response from receiver */ |
---|
262 | |
---|
263 | /* |
---|
264 | * Initialize pointers and read the receiver response |
---|
265 | */ |
---|
266 | peer = (struct peer *)rbufp->recv_srcclock; |
---|
267 | pp = peer->procptr; |
---|
268 | up = (struct hpgpsunit *)pp->unitptr; |
---|
269 | *pp->a_lastcode = '\0'; |
---|
270 | pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); |
---|
271 | |
---|
272 | #ifdef DEBUG |
---|
273 | if (debug) |
---|
274 | printf("hpgps: lencode: %d timecode:%s\n", |
---|
275 | pp->lencode, pp->a_lastcode); |
---|
276 | #endif |
---|
277 | |
---|
278 | /* |
---|
279 | * If there's no characters in the reply, we can quit now |
---|
280 | */ |
---|
281 | if (pp->lencode == 0) |
---|
282 | return; |
---|
283 | |
---|
284 | /* |
---|
285 | * If linecnt is greater than zero, we are getting information only, |
---|
286 | * such as the receiver identification string or the receiver status |
---|
287 | * screen, so put the receiver response at the end of the status |
---|
288 | * screen buffer. When we have the last line, write the buffer to |
---|
289 | * the clockstats file and return without further processing. |
---|
290 | * |
---|
291 | * If linecnt is zero, we are expecting either the timezone |
---|
292 | * or a timecode. At this point, also write the response |
---|
293 | * to the clockstats file, and go on to process the prompt (if any), |
---|
294 | * timezone, or timecode and timestamp. |
---|
295 | */ |
---|
296 | |
---|
297 | |
---|
298 | if (up->linecnt-- > 0) { |
---|
299 | if ((int)(pp->lencode + 2) <= (SMAX - (up->lastptr - up->statscrn))) { |
---|
300 | *up->lastptr++ = '\n'; |
---|
301 | (void)strcpy(up->lastptr, pp->a_lastcode); |
---|
302 | up->lastptr += pp->lencode; |
---|
303 | } |
---|
304 | if (up->linecnt == 0) |
---|
305 | record_clock_stats(&peer->srcadr, up->statscrn); |
---|
306 | |
---|
307 | return; |
---|
308 | } |
---|
309 | |
---|
310 | record_clock_stats(&peer->srcadr, pp->a_lastcode); |
---|
311 | pp->lastrec = trtmp; |
---|
312 | |
---|
313 | up->lastptr = up->statscrn; |
---|
314 | *up->lastptr = '\0'; |
---|
315 | up->pollcnt = 2; |
---|
316 | |
---|
317 | /* |
---|
318 | * We get down to business: get a prompt if one is there, issue |
---|
319 | * a clear status command if it contains an error indication. |
---|
320 | * Next, check for either the timezone reply or the timecode reply |
---|
321 | * and decode it. If we don't recognize the reply, or don't get the |
---|
322 | * proper number of decoded fields, or get an out of range timezone, |
---|
323 | * or if the timecode checksum is bad, then we declare bad format |
---|
324 | * and exit. |
---|
325 | * |
---|
326 | * Timezone format (including nominal prompt): |
---|
327 | * scpi > -H,-M<cr><lf> |
---|
328 | * |
---|
329 | * Timecode format (including nominal prompt): |
---|
330 | * scpi > T2yyyymmddhhmmssMFLRVcc<cr><lf> |
---|
331 | * |
---|
332 | */ |
---|
333 | |
---|
334 | (void)strcpy(prompt,pp->a_lastcode); |
---|
335 | tcp = strrchr(pp->a_lastcode,'>'); |
---|
336 | if (tcp == NULL) |
---|
337 | tcp = pp->a_lastcode; |
---|
338 | else |
---|
339 | tcp++; |
---|
340 | prompt[tcp - pp->a_lastcode] = '\0'; |
---|
341 | while ((*tcp == ' ') || (*tcp == '\t')) tcp++; |
---|
342 | |
---|
343 | /* |
---|
344 | * deal with an error indication in the prompt here |
---|
345 | */ |
---|
346 | if (strrchr(prompt,'E') > strrchr(prompt,'s')){ |
---|
347 | #ifdef DEBUG |
---|
348 | if (debug) |
---|
349 | printf("hpgps: error indicated in prompt: %s\n", prompt); |
---|
350 | #endif |
---|
351 | if (write(pp->io.fd, "*CLS\r\r", 6) != 6) |
---|
352 | refclock_report(peer, CEVNT_FAULT); |
---|
353 | } |
---|
354 | |
---|
355 | /* |
---|
356 | * make sure we got a timezone or timecode format and |
---|
357 | * then process accordingly |
---|
358 | */ |
---|
359 | m = sscanf(tcp,"%c%c", &tcodechar1, &tcodechar2); |
---|
360 | |
---|
361 | if (m != 2){ |
---|
362 | #ifdef DEBUG |
---|
363 | if (debug) |
---|
364 | printf("hpgps: no format indicator\n"); |
---|
365 | #endif |
---|
366 | refclock_report(peer, CEVNT_BADREPLY); |
---|
367 | return; |
---|
368 | } |
---|
369 | |
---|
370 | switch (tcodechar1) { |
---|
371 | |
---|
372 | case '+': |
---|
373 | case '-': |
---|
374 | m = sscanf(tcp,"%d,%d", &up->tzhour, &up->tzminute); |
---|
375 | if (m != MTZONE) { |
---|
376 | #ifdef DEBUG |
---|
377 | if (debug) |
---|
378 | printf("hpgps: only %d fields recognized in timezone\n", m); |
---|
379 | #endif |
---|
380 | refclock_report(peer, CEVNT_BADREPLY); |
---|
381 | return; |
---|
382 | } |
---|
383 | if ((up->tzhour < -12) || (up->tzhour > 13) || |
---|
384 | (up->tzminute < -59) || (up->tzminute > 59)){ |
---|
385 | #ifdef DEBUG |
---|
386 | if (debug) |
---|
387 | printf("hpgps: timezone %d, %d out of range\n", |
---|
388 | up->tzhour, up->tzminute); |
---|
389 | #endif |
---|
390 | refclock_report(peer, CEVNT_BADREPLY); |
---|
391 | return; |
---|
392 | } |
---|
393 | return; |
---|
394 | |
---|
395 | case 'T': |
---|
396 | break; |
---|
397 | |
---|
398 | default: |
---|
399 | #ifdef DEBUG |
---|
400 | if (debug) |
---|
401 | printf("hpgps: unrecognized reply format %c%c\n", |
---|
402 | tcodechar1, tcodechar2); |
---|
403 | #endif |
---|
404 | refclock_report(peer, CEVNT_BADREPLY); |
---|
405 | return; |
---|
406 | } /* end of tcodechar1 switch */ |
---|
407 | |
---|
408 | |
---|
409 | switch (tcodechar2) { |
---|
410 | |
---|
411 | case '2': |
---|
412 | m = sscanf(tcp,"%*c%*c%4d%2d%2d%2d%2d%2d%c%c%c%c%c%2hx", |
---|
413 | &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second, |
---|
414 | &timequal, &freqqual, &leapchar, &servchar, &syncchar, |
---|
415 | &expectedsm); |
---|
416 | n = NTCODET2; |
---|
417 | |
---|
418 | if (m != MTCODET2){ |
---|
419 | #ifdef DEBUG |
---|
420 | if (debug) |
---|
421 | printf("hpgps: only %d fields recognized in timecode\n", m); |
---|
422 | #endif |
---|
423 | refclock_report(peer, CEVNT_BADREPLY); |
---|
424 | return; |
---|
425 | } |
---|
426 | break; |
---|
427 | |
---|
428 | default: |
---|
429 | #ifdef DEBUG |
---|
430 | if (debug) |
---|
431 | printf("hpgps: unrecognized timecode format %c%c\n", |
---|
432 | tcodechar1, tcodechar2); |
---|
433 | #endif |
---|
434 | refclock_report(peer, CEVNT_BADREPLY); |
---|
435 | return; |
---|
436 | } /* end of tcodechar2 format switch */ |
---|
437 | |
---|
438 | /* |
---|
439 | * Compute and verify the checksum. |
---|
440 | * Characters are summed starting at tcodechar1, ending at just |
---|
441 | * before the expected checksum. Bail out if incorrect. |
---|
442 | */ |
---|
443 | tcodechksm = 0; |
---|
444 | while (n-- > 0) tcodechksm += *tcp++; |
---|
445 | tcodechksm &= 0x00ff; |
---|
446 | |
---|
447 | if (tcodechksm != expectedsm) { |
---|
448 | #ifdef DEBUG |
---|
449 | if (debug) |
---|
450 | printf("hpgps: checksum %2hX doesn't match %2hX expected\n", |
---|
451 | tcodechksm, expectedsm); |
---|
452 | #endif |
---|
453 | refclock_report(peer, CEVNT_BADREPLY); |
---|
454 | return; |
---|
455 | } |
---|
456 | |
---|
457 | /* |
---|
458 | * Compute the day of year from the yyyymmdd format. |
---|
459 | * Exception noted for year 2000. |
---|
460 | */ |
---|
461 | if (month < 1 || month > 12 || day < 1) { |
---|
462 | refclock_report(peer, CEVNT_BADTIME); |
---|
463 | return; |
---|
464 | } |
---|
465 | if ((pp->year % 4) || (pp->year == 2000)) { |
---|
466 | /* not a leap year */ |
---|
467 | if (day > day1tab[month - 1]) { |
---|
468 | refclock_report(peer, CEVNT_BADTIME); |
---|
469 | return; |
---|
470 | } |
---|
471 | for (i = 0; i < month - 1; i++) day += day1tab[i]; |
---|
472 | lastday = 365; |
---|
473 | } else { |
---|
474 | /* a leap year */ |
---|
475 | if (day > day2tab[month - 1]) { |
---|
476 | refclock_report(peer, CEVNT_BADTIME); |
---|
477 | return; |
---|
478 | } |
---|
479 | for (i = 0; i < month - 1; i++) day += day2tab[i]; |
---|
480 | lastday = 366; |
---|
481 | } |
---|
482 | |
---|
483 | /* |
---|
484 | * Deal with the timezone offset here. The receiver timecode is in |
---|
485 | * local time = UTC + :PTIME:TZONE, so SUBTRACT the timezone values. |
---|
486 | * For example, Pacific Standard Time is -8 hours , 0 minutes. |
---|
487 | * Deal with the underflows and overflows. |
---|
488 | */ |
---|
489 | pp->minute -= up->tzminute; |
---|
490 | pp->hour -= up->tzhour; |
---|
491 | |
---|
492 | if (pp->minute < 0) { |
---|
493 | pp->minute += 60; |
---|
494 | pp->hour--; |
---|
495 | } |
---|
496 | if (pp->minute > 59) { |
---|
497 | pp->minute -= 60; |
---|
498 | pp->hour++; |
---|
499 | } |
---|
500 | if (pp->hour < 0) { |
---|
501 | pp->hour += 24; |
---|
502 | day--; |
---|
503 | if (day < 1) { |
---|
504 | pp->year--; |
---|
505 | if ((pp->year % 4) || (pp->year % 400)) |
---|
506 | day = 365; |
---|
507 | else |
---|
508 | day = 366; |
---|
509 | } |
---|
510 | } |
---|
511 | |
---|
512 | if (pp->hour > 23) { |
---|
513 | pp->hour -= 24; |
---|
514 | day++; |
---|
515 | if (day > lastday) { |
---|
516 | pp->year++; |
---|
517 | day = 1; |
---|
518 | } |
---|
519 | } |
---|
520 | |
---|
521 | pp->day = day; |
---|
522 | |
---|
523 | /* |
---|
524 | * Decode the MFLRV indicators. |
---|
525 | * NEED TO FIGURE OUT how to deal with the request for service, |
---|
526 | * time quality, and frequency quality indicators some day. |
---|
527 | */ |
---|
528 | if (syncchar != '0') { |
---|
529 | pp->leap = LEAP_NOTINSYNC; |
---|
530 | } |
---|
531 | else { |
---|
532 | switch (leapchar) { |
---|
533 | |
---|
534 | case '+': |
---|
535 | pp->leap = LEAP_ADDSECOND; |
---|
536 | break; |
---|
537 | |
---|
538 | case '0': |
---|
539 | pp->leap = LEAP_NOWARNING; |
---|
540 | break; |
---|
541 | |
---|
542 | case '-': |
---|
543 | pp->leap = LEAP_DELSECOND; |
---|
544 | break; |
---|
545 | |
---|
546 | default: |
---|
547 | #ifdef DEBUG |
---|
548 | if (debug) |
---|
549 | printf("hpgps: unrecognized leap indicator: %c\n", |
---|
550 | leapchar); |
---|
551 | #endif |
---|
552 | refclock_report(peer, CEVNT_BADTIME); |
---|
553 | return; |
---|
554 | } /* end of leapchar switch */ |
---|
555 | |
---|
556 | pp->lasttime = current_time; |
---|
557 | } |
---|
558 | |
---|
559 | /* |
---|
560 | * Process the new sample in the median filter and determine the |
---|
561 | * reference clock offset and dispersion. We use lastrec as both |
---|
562 | * the reference time and receive time in order to avoid being |
---|
563 | * cute, like setting the reference time later than the receive |
---|
564 | * time, which may cause a paranoid protocol module to chuck out |
---|
565 | * the data. |
---|
566 | */ |
---|
567 | if (!refclock_process(pp, NSAMPLES, NSAMPLES)) { |
---|
568 | refclock_report(peer, CEVNT_BADTIME); |
---|
569 | return; |
---|
570 | } |
---|
571 | trtmp = pp->lastrec; |
---|
572 | |
---|
573 | #ifdef DEBUG |
---|
574 | if (debug) |
---|
575 | printf("hpgps: refclock_rcv: off: %s, disp: %s, tref: %s, trec: %s, lp: %hd\n", |
---|
576 | lfptoa(&pp->offset,6), |
---|
577 | ufptoa(pp->dispersion,6), |
---|
578 | ulfptoa(&trtmp,6), |
---|
579 | ulfptoa(&pp->lastrec,6), |
---|
580 | pp->leap); |
---|
581 | #endif |
---|
582 | |
---|
583 | refclock_receive(peer, &pp->offset, 0, pp->dispersion, &trtmp, |
---|
584 | &pp->lastrec, pp->leap); |
---|
585 | |
---|
586 | /* |
---|
587 | * If CLK_FLAG4 is set, ask for the status screen response. |
---|
588 | */ |
---|
589 | if (pp->sloppyclockflag & CLK_FLAG4){ |
---|
590 | up->linecnt = 22; |
---|
591 | if (write(pp->io.fd, ":SYSTEM:PRINT?\r", 15) != 15) |
---|
592 | refclock_report(peer, CEVNT_FAULT); |
---|
593 | } |
---|
594 | } |
---|
595 | |
---|
596 | |
---|
597 | /* |
---|
598 | * hpgps_poll - called by the transmit procedure |
---|
599 | */ |
---|
600 | static void |
---|
601 | hpgps_poll(unit, peer) |
---|
602 | int unit; |
---|
603 | struct peer *peer; |
---|
604 | { |
---|
605 | register struct hpgpsunit *up; |
---|
606 | struct refclockproc *pp; |
---|
607 | |
---|
608 | /* |
---|
609 | * Time to poll the clock. The HP 58503A responds to a |
---|
610 | * ":PTIME:TCODE?" by returning a timecode in the format specified |
---|
611 | * above. If nothing is heard from the clock for two polls, |
---|
612 | * declare a timeout and keep going. |
---|
613 | */ |
---|
614 | pp = peer->procptr; |
---|
615 | up = (struct hpgpsunit *)pp->unitptr; |
---|
616 | if (up->pollcnt == 0) |
---|
617 | refclock_report(peer, CEVNT_TIMEOUT); |
---|
618 | else |
---|
619 | up->pollcnt--; |
---|
620 | if (write(pp->io.fd, ":PTIME:TCODE?\r", 14) != 14) { |
---|
621 | refclock_report(peer, CEVNT_FAULT); |
---|
622 | } |
---|
623 | else |
---|
624 | pp->polls++; |
---|
625 | } |
---|
626 | |
---|
627 | #endif |
---|