/src/ntp-dev/ntpd/refclock_leitch.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock |
3 | | */ |
4 | | |
5 | | #ifdef HAVE_CONFIG_H |
6 | | # include <config.h> |
7 | | #endif |
8 | | |
9 | | #include "ntp_types.h" |
10 | | |
11 | | #if defined(REFCLOCK) && defined(CLOCK_LEITCH) |
12 | | |
13 | | #include <stdio.h> |
14 | | #include <ctype.h> |
15 | | |
16 | | #include "ntpd.h" |
17 | | #include "ntp_io.h" |
18 | | #include "ntp_refclock.h" |
19 | | #include "timevalops.h" |
20 | | #include "ntp_stdlib.h" |
21 | | |
22 | | |
23 | | /* |
24 | | * Driver for Leitch CSD-5300 Master Clock System |
25 | | * |
26 | | * COMMANDS: |
27 | | * DATE: D <CR> |
28 | | * TIME: T <CR> |
29 | | * STATUS: S <CR> |
30 | | * LOOP: L <CR> |
31 | | * |
32 | | * FORMAT: |
33 | | * DATE: YYMMDD<CR> |
34 | | * TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/ |
35 | | * second bondaried on the stop bit of the <CR> |
36 | | * second boundaries at '/' above. |
37 | | * STATUS: G (good), D (diag fail), T (time not provided) or |
38 | | * P (last phone update failed) |
39 | | */ |
40 | 0 | #define PRECISION (-20) /* 1x10-8 */ |
41 | 0 | #define MAXUNITS 1 /* max number of LEITCH units */ |
42 | 0 | #define LEITCHREFID "ATOM" /* reference id */ |
43 | 0 | #define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver" |
44 | | #define LEITCH232 "/dev/leitch%d" /* name of radio device */ |
45 | 0 | #define SPEED232 B300 /* uart speed (300 baud) */ |
46 | | #ifdef DEBUG |
47 | 0 | #define leitch_send(A,M) \ |
48 | 0 | if (debug) fprintf(stderr,"write leitch %s\n",M); \ |
49 | 0 | if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\ |
50 | 0 | if (debug) \ |
51 | 0 | fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \ |
52 | 0 | else \ |
53 | 0 | msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);} |
54 | | #else |
55 | | #define leitch_send(A,M) \ |
56 | | if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\ |
57 | | msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);} |
58 | | #endif |
59 | | |
60 | 0 | #define STATE_IDLE 0 |
61 | 0 | #define STATE_DATE 1 |
62 | 0 | #define STATE_TIME1 2 |
63 | 0 | #define STATE_TIME2 3 |
64 | 0 | #define STATE_TIME3 4 |
65 | | |
66 | | /* |
67 | | * LEITCH unit control structure |
68 | | */ |
69 | | struct leitchunit { |
70 | | struct peer *peer; |
71 | | struct refclockio leitchio; |
72 | | u_char unit; |
73 | | short year; |
74 | | short yearday; |
75 | | short month; |
76 | | short day; |
77 | | short hour; |
78 | | short second; |
79 | | short minute; |
80 | | short state; |
81 | | u_short fudge1; |
82 | | l_fp reftime1; |
83 | | l_fp reftime2; |
84 | | l_fp reftime3; |
85 | | l_fp codetime1; |
86 | | l_fp codetime2; |
87 | | l_fp codetime3; |
88 | | u_long yearstart; |
89 | | }; |
90 | | |
91 | | /* |
92 | | * Function prototypes |
93 | | */ |
94 | | static void leitch_init (void); |
95 | | static int leitch_start (int, struct peer *); |
96 | | static void leitch_shutdown (int, struct peer *); |
97 | | static void leitch_poll (int, struct peer *); |
98 | | static void leitch_control (int, const struct refclockstat *, struct refclockstat *, struct peer *); |
99 | | #define leitch_buginfo noentry |
100 | | static void leitch_receive (struct recvbuf *); |
101 | | static void leitch_process (struct leitchunit *); |
102 | | #if 0 |
103 | | static void leitch_timeout (struct peer *); |
104 | | #endif |
105 | | static int leitch_get_date (struct recvbuf *, struct leitchunit *); |
106 | | static int leitch_get_time (struct recvbuf *, struct leitchunit *, int); |
107 | | static int days_per_year (int); |
108 | | |
109 | | static struct leitchunit leitchunits[MAXUNITS]; |
110 | | static u_char unitinuse[MAXUNITS]; |
111 | | static u_char stratumtouse[MAXUNITS]; |
112 | | static u_int32 refid[MAXUNITS]; |
113 | | |
114 | | static char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
115 | | |
116 | | /* |
117 | | * Transfer vector |
118 | | */ |
119 | | struct refclock refclock_leitch = { |
120 | | leitch_start, leitch_shutdown, leitch_poll, |
121 | | leitch_control, leitch_init, leitch_buginfo, NOFLAGS |
122 | | }; |
123 | | |
124 | | /* |
125 | | * leitch_init - initialize internal leitch driver data |
126 | | */ |
127 | | static void |
128 | | leitch_init(void) |
129 | 0 | { |
130 | 0 | int i; |
131 | |
|
132 | 0 | memset((char*)leitchunits, 0, sizeof(leitchunits)); |
133 | 0 | memset((char*)unitinuse, 0, sizeof(unitinuse)); |
134 | 0 | for (i = 0; i < MAXUNITS; i++) |
135 | 0 | memcpy((char *)&refid[i], LEITCHREFID, 4); |
136 | 0 | } |
137 | | |
138 | | /* |
139 | | * leitch_shutdown - shut down a LEITCH clock |
140 | | */ |
141 | | static void |
142 | | leitch_shutdown( |
143 | | int unit, |
144 | | struct peer *peer |
145 | | ) |
146 | 0 | { |
147 | 0 | struct leitchunit *leitch; |
148 | |
|
149 | 0 | if (unit >= MAXUNITS) { |
150 | 0 | return; |
151 | 0 | } |
152 | 0 | leitch = &leitchunits[unit]; |
153 | 0 | if (-1 != leitch->leitchio.fd) |
154 | 0 | io_closeclock(&leitch->leitchio); |
155 | 0 | #ifdef DEBUG |
156 | 0 | if (debug) |
157 | 0 | fprintf(stderr, "leitch_shutdown()\n"); |
158 | 0 | #endif |
159 | 0 | } |
160 | | |
161 | | /* |
162 | | * leitch_poll - called by the transmit procedure |
163 | | */ |
164 | | static void |
165 | | leitch_poll( |
166 | | int unit, |
167 | | struct peer *peer |
168 | | ) |
169 | 0 | { |
170 | 0 | struct leitchunit *leitch; |
171 | | |
172 | | /* start the state machine rolling */ |
173 | |
|
174 | 0 | #ifdef DEBUG |
175 | 0 | if (debug) |
176 | 0 | fprintf(stderr, "leitch_poll()\n"); |
177 | 0 | #endif |
178 | 0 | if (unit >= MAXUNITS) { |
179 | | /* XXXX syslog it */ |
180 | 0 | return; |
181 | 0 | } |
182 | | |
183 | 0 | leitch = &leitchunits[unit]; |
184 | |
|
185 | 0 | if (leitch->state != STATE_IDLE) { |
186 | | /* reset and wait for next poll */ |
187 | | /* XXXX syslog it */ |
188 | 0 | leitch->state = STATE_IDLE; |
189 | 0 | } else { |
190 | 0 | leitch_send(leitch,"D\r"); |
191 | 0 | leitch->state = STATE_DATE; |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | static void |
196 | | leitch_control( |
197 | | int unit, |
198 | | const struct refclockstat *in, |
199 | | struct refclockstat *out, |
200 | | struct peer *passed_peer |
201 | | ) |
202 | 0 | { |
203 | 0 | if (unit >= MAXUNITS) { |
204 | 0 | msyslog(LOG_ERR, |
205 | 0 | "leitch_control: unit %d invalid", unit); |
206 | 0 | return; |
207 | 0 | } |
208 | | |
209 | 0 | if (in) { |
210 | 0 | if (in->haveflags & CLK_HAVEVAL1) |
211 | 0 | stratumtouse[unit] = (u_char)(in->fudgeval1); |
212 | 0 | if (in->haveflags & CLK_HAVEVAL2) |
213 | 0 | refid[unit] = in->fudgeval2; |
214 | 0 | if (unitinuse[unit]) { |
215 | 0 | struct peer *peer; |
216 | |
|
217 | 0 | peer = (&leitchunits[unit])->peer; |
218 | 0 | peer->stratum = stratumtouse[unit]; |
219 | 0 | peer->refid = refid[unit]; |
220 | 0 | } |
221 | 0 | } |
222 | |
|
223 | 0 | if (out) { |
224 | 0 | memset((char *)out, 0, sizeof (struct refclockstat)); |
225 | 0 | out->type = REFCLK_ATOM_LEITCH; |
226 | 0 | out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; |
227 | 0 | out->fudgeval1 = (int32)stratumtouse[unit]; |
228 | 0 | out->fudgeval2 = refid[unit]; |
229 | 0 | out->p_lastcode = ""; |
230 | 0 | out->clockdesc = LEITCH_DESCRIPTION; |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | | /* |
235 | | * leitch_start - open the LEITCH devices and initialize data for processing |
236 | | */ |
237 | | static int |
238 | | leitch_start( |
239 | | int unit, |
240 | | struct peer *peer |
241 | | ) |
242 | 0 | { |
243 | 0 | struct leitchunit *leitch; |
244 | 0 | int fd232; |
245 | 0 | char leitchdev[20]; |
246 | | |
247 | | /* |
248 | | * Check configuration info. |
249 | | */ |
250 | 0 | if (unit >= MAXUNITS) { |
251 | 0 | msyslog(LOG_ERR, "leitch_start: unit %d invalid", unit); |
252 | 0 | return (0); |
253 | 0 | } |
254 | | |
255 | 0 | if (unitinuse[unit]) { |
256 | 0 | msyslog(LOG_ERR, "leitch_start: unit %d in use", unit); |
257 | 0 | return (0); |
258 | 0 | } |
259 | | |
260 | | /* |
261 | | * Open serial port. |
262 | | */ |
263 | 0 | snprintf(leitchdev, sizeof(leitchdev), LEITCH232, unit); |
264 | 0 | fd232 = open(leitchdev, O_RDWR, 0777); |
265 | 0 | if (fd232 == -1) { |
266 | 0 | msyslog(LOG_ERR, |
267 | 0 | "leitch_start: open of %s: %m", leitchdev); |
268 | 0 | return (0); |
269 | 0 | } |
270 | | |
271 | 0 | leitch = &leitchunits[unit]; |
272 | 0 | memset(leitch, 0, sizeof(*leitch)); |
273 | |
|
274 | | #if defined(HAVE_SYSV_TTYS) |
275 | | /* |
276 | | * System V serial line parameters (termio interface) |
277 | | * |
278 | | */ |
279 | | { struct termio ttyb; |
280 | | if (ioctl(fd232, TCGETA, &ttyb) < 0) { |
281 | | msyslog(LOG_ERR, |
282 | | "leitch_start: ioctl(%s, TCGETA): %m", leitchdev); |
283 | | goto screwed; |
284 | | } |
285 | | ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL; |
286 | | ttyb.c_oflag = 0; |
287 | | ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD; |
288 | | ttyb.c_lflag = ICANON; |
289 | | ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0'; |
290 | | if (ioctl(fd232, TCSETA, &ttyb) < 0) { |
291 | | msyslog(LOG_ERR, |
292 | | "leitch_start: ioctl(%s, TCSETA): %m", leitchdev); |
293 | | goto screwed; |
294 | | } |
295 | | } |
296 | | #endif /* HAVE_SYSV_TTYS */ |
297 | 0 | #if defined(HAVE_TERMIOS) |
298 | | /* |
299 | | * POSIX serial line parameters (termios interface) |
300 | | */ |
301 | 0 | { struct termios ttyb, *ttyp; |
302 | |
|
303 | 0 | ttyp = &ttyb; |
304 | 0 | if (tcgetattr(fd232, ttyp) < 0) { |
305 | 0 | msyslog(LOG_ERR, |
306 | 0 | "leitch_start: tcgetattr(%s): %m", leitchdev); |
307 | 0 | goto screwed; |
308 | 0 | } |
309 | 0 | ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL; |
310 | 0 | ttyp->c_oflag = 0; |
311 | 0 | ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD; |
312 | 0 | ttyp->c_lflag = ICANON; |
313 | 0 | ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; |
314 | 0 | if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { |
315 | 0 | msyslog(LOG_ERR, |
316 | 0 | "leitch_start: tcsetattr(%s): %m", leitchdev); |
317 | 0 | goto screwed; |
318 | 0 | } |
319 | 0 | if (tcflush(fd232, TCIOFLUSH) < 0) { |
320 | 0 | msyslog(LOG_ERR, |
321 | 0 | "leitch_start: tcflush(%s): %m", leitchdev); |
322 | 0 | goto screwed; |
323 | 0 | } |
324 | 0 | } |
325 | 0 | #endif /* HAVE_TERMIOS */ |
326 | | #if defined(HAVE_BSD_TTYS) |
327 | | /* |
328 | | * 4.3bsd serial line parameters (sgttyb interface) |
329 | | */ |
330 | | { |
331 | | struct sgttyb ttyb; |
332 | | |
333 | | if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { |
334 | | msyslog(LOG_ERR, |
335 | | "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev); |
336 | | goto screwed; |
337 | | } |
338 | | ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; |
339 | | ttyb.sg_erase = ttyb.sg_kill = '\0'; |
340 | | ttyb.sg_flags = EVENP|ODDP|CRMOD; |
341 | | if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { |
342 | | msyslog(LOG_ERR, |
343 | | "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev); |
344 | | goto screwed; |
345 | | } |
346 | | } |
347 | | #endif /* HAVE_BSD_TTYS */ |
348 | | |
349 | | /* |
350 | | * Set up the structures |
351 | | */ |
352 | 0 | leitch->peer = peer; |
353 | 0 | leitch->unit = unit; |
354 | 0 | leitch->state = STATE_IDLE; |
355 | 0 | leitch->fudge1 = 15; /* 15ms */ |
356 | |
|
357 | 0 | leitch->leitchio.clock_recv = leitch_receive; |
358 | 0 | leitch->leitchio.srcclock = peer; |
359 | 0 | leitch->leitchio.datalen = 0; |
360 | 0 | leitch->leitchio.fd = fd232; |
361 | 0 | if (!io_addclock(&leitch->leitchio)) { |
362 | 0 | leitch->leitchio.fd = -1; |
363 | 0 | goto screwed; |
364 | 0 | } |
365 | | |
366 | | /* |
367 | | * All done. Initialize a few random peer variables, then |
368 | | * return success. |
369 | | */ |
370 | 0 | peer->precision = PRECISION; |
371 | 0 | peer->stratum = stratumtouse[unit]; |
372 | 0 | peer->refid = refid[unit]; |
373 | 0 | unitinuse[unit] = 1; |
374 | 0 | return(1); |
375 | | |
376 | | /* |
377 | | * Something broke; abandon ship. |
378 | | */ |
379 | 0 | screwed: |
380 | 0 | close(fd232); |
381 | 0 | return(0); |
382 | 0 | } |
383 | | |
384 | | /* |
385 | | * leitch_receive - receive data from the serial interface on a leitch |
386 | | * clock |
387 | | */ |
388 | | static void |
389 | | leitch_receive( |
390 | | struct recvbuf *rbufp |
391 | | ) |
392 | 0 | { |
393 | 0 | struct leitchunit *leitch = rbufp->recv_peer->procptr->unitptr; |
394 | |
|
395 | 0 | #ifdef DEBUG |
396 | 0 | if (debug) |
397 | 0 | fprintf(stderr, "leitch_recieve(%*.*s)\n", |
398 | 0 | rbufp->recv_length, rbufp->recv_length, |
399 | 0 | rbufp->recv_buffer); |
400 | 0 | #endif |
401 | 0 | if (rbufp->recv_length != 7) |
402 | 0 | return; /* The date is return with a trailing newline, |
403 | | discard it. */ |
404 | | |
405 | 0 | switch (leitch->state) { |
406 | 0 | case STATE_IDLE: /* unexpected, discard and resync */ |
407 | 0 | return; |
408 | 0 | case STATE_DATE: |
409 | 0 | if (!leitch_get_date(rbufp,leitch)) { |
410 | 0 | leitch->state = STATE_IDLE; |
411 | 0 | break; |
412 | 0 | } |
413 | 0 | leitch_send(leitch,"T\r"); |
414 | 0 | #ifdef DEBUG |
415 | 0 | if (debug) |
416 | 0 | fprintf(stderr, "%u\n",leitch->yearday); |
417 | 0 | #endif |
418 | 0 | leitch->state = STATE_TIME1; |
419 | 0 | break; |
420 | 0 | case STATE_TIME1: |
421 | 0 | if (!leitch_get_time(rbufp,leitch,1)) { |
422 | 0 | } |
423 | 0 | if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, |
424 | 0 | leitch->second, 1, rbufp->recv_time.l_ui, |
425 | 0 | &leitch->yearstart, &leitch->reftime1.l_ui)) { |
426 | 0 | leitch->state = STATE_IDLE; |
427 | 0 | break; |
428 | 0 | } |
429 | 0 | leitch->reftime1.l_uf = 0; |
430 | 0 | #ifdef DEBUG |
431 | 0 | if (debug) |
432 | 0 | fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui); |
433 | 0 | #endif |
434 | 0 | MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf); |
435 | 0 | leitch->codetime1 = rbufp->recv_time; |
436 | 0 | leitch->state = STATE_TIME2; |
437 | 0 | break; |
438 | 0 | case STATE_TIME2: |
439 | 0 | if (!leitch_get_time(rbufp,leitch,2)) { |
440 | 0 | } |
441 | 0 | if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, |
442 | 0 | leitch->second, 1, rbufp->recv_time.l_ui, |
443 | 0 | &leitch->yearstart, &leitch->reftime2.l_ui)) { |
444 | 0 | leitch->state = STATE_IDLE; |
445 | 0 | break; |
446 | 0 | } |
447 | 0 | #ifdef DEBUG |
448 | 0 | if (debug) |
449 | 0 | fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui); |
450 | 0 | #endif |
451 | 0 | MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf); |
452 | 0 | leitch->codetime2 = rbufp->recv_time; |
453 | 0 | leitch->state = STATE_TIME3; |
454 | 0 | break; |
455 | 0 | case STATE_TIME3: |
456 | 0 | if (!leitch_get_time(rbufp,leitch,3)) { |
457 | 0 | } |
458 | 0 | if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, |
459 | 0 | leitch->second, GMT, rbufp->recv_time.l_ui, |
460 | 0 | &leitch->yearstart, &leitch->reftime3.l_ui)) { |
461 | 0 | leitch->state = STATE_IDLE; |
462 | 0 | break; |
463 | 0 | } |
464 | 0 | #ifdef DEBUG |
465 | 0 | if (debug) |
466 | 0 | fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui); |
467 | 0 | #endif |
468 | 0 | MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf); |
469 | 0 | leitch->codetime3 = rbufp->recv_time; |
470 | 0 | leitch_process(leitch); |
471 | 0 | leitch->state = STATE_IDLE; |
472 | 0 | break; |
473 | 0 | default: |
474 | 0 | msyslog(LOG_ERR, |
475 | 0 | "leitech_receive: invalid state %d unit %d", |
476 | 0 | leitch->state, leitch->unit); |
477 | 0 | } |
478 | 0 | } |
479 | | |
480 | | /* |
481 | | * leitch_process - process a pile of samples from the clock |
482 | | * |
483 | | * This routine uses a three-stage median filter to calculate offset and |
484 | | * dispersion. reduce jitter. The dispersion is calculated as the span |
485 | | * of the filter (max - min), unless the quality character (format 2) is |
486 | | * non-blank, in which case the dispersion is calculated on the basis of |
487 | | * the inherent tolerance of the internal radio oscillator, which is |
488 | | * +-2e-5 according to the radio specifications. |
489 | | */ |
490 | | static void |
491 | | leitch_process( |
492 | | struct leitchunit *leitch |
493 | | ) |
494 | 0 | { |
495 | 0 | l_fp off; |
496 | 0 | l_fp tmp_fp; |
497 | | /*double doffset;*/ |
498 | |
|
499 | 0 | off = leitch->reftime1; |
500 | 0 | L_SUB(&off,&leitch->codetime1); |
501 | 0 | tmp_fp = leitch->reftime2; |
502 | 0 | L_SUB(&tmp_fp,&leitch->codetime2); |
503 | 0 | if (L_ISGEQ(&off,&tmp_fp)) |
504 | 0 | off = tmp_fp; |
505 | 0 | tmp_fp = leitch->reftime3; |
506 | 0 | L_SUB(&tmp_fp,&leitch->codetime3); |
507 | |
|
508 | 0 | if (L_ISGEQ(&off,&tmp_fp)) |
509 | 0 | off = tmp_fp; |
510 | | /*LFPTOD(&off, doffset);*/ |
511 | 0 | refclock_receive(leitch->peer); |
512 | 0 | } |
513 | | |
514 | | /* |
515 | | * days_per_year |
516 | | */ |
517 | | static int |
518 | | days_per_year( |
519 | | int year |
520 | | ) |
521 | 0 | { |
522 | 0 | if (year%4) { /* not a potential leap year */ |
523 | 0 | return (365); |
524 | 0 | } else { |
525 | 0 | if (year % 100) { /* is a leap year */ |
526 | 0 | return (366); |
527 | 0 | } else { |
528 | 0 | if (year % 400) { |
529 | 0 | return (365); |
530 | 0 | } else { |
531 | 0 | return (366); |
532 | 0 | } |
533 | 0 | } |
534 | 0 | } |
535 | 0 | } |
536 | | |
537 | | static int |
538 | | leitch_get_date( |
539 | | struct recvbuf *rbufp, |
540 | | struct leitchunit *leitch |
541 | | ) |
542 | 0 | { |
543 | 0 | int i; |
544 | |
|
545 | 0 | if (rbufp->recv_length < 6) |
546 | 0 | return(0); |
547 | 0 | #undef BAD /* confict: defined as (-1) in AIX sys/param.h */ |
548 | 0 | #define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9') |
549 | 0 | if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) |
550 | 0 | return(0); |
551 | 0 | #define ATOB(A) ((rbufp->recv_buffer[A])-'0') |
552 | 0 | leitch->year = ATOB(0)*10 + ATOB(1); |
553 | 0 | leitch->month = ATOB(2)*10 + ATOB(3); |
554 | 0 | leitch->day = ATOB(4)*10 + ATOB(5); |
555 | | |
556 | | /* sanity checks */ |
557 | 0 | if (leitch->month > 12) |
558 | 0 | return(0); |
559 | 0 | if (leitch->day > days_in_month[leitch->month-1]) |
560 | 0 | return(0); |
561 | | |
562 | | /* calculate yearday */ |
563 | 0 | i = 0; |
564 | 0 | leitch->yearday = leitch->day; |
565 | |
|
566 | 0 | while ( i < (leitch->month-1) ) |
567 | 0 | leitch->yearday += days_in_month[i++]; |
568 | |
|
569 | 0 | if ((days_per_year((leitch->year>90?1900:2000)+leitch->year)==365) && |
570 | 0 | leitch->month > 2) |
571 | 0 | leitch->yearday--; |
572 | |
|
573 | 0 | return(1); |
574 | 0 | } |
575 | | |
576 | | /* |
577 | | * leitch_get_time |
578 | | */ |
579 | | static int |
580 | | leitch_get_time( |
581 | | struct recvbuf *rbufp, |
582 | | struct leitchunit *leitch, |
583 | | int which |
584 | | ) |
585 | 0 | { |
586 | 0 | if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) |
587 | 0 | return(0); |
588 | 0 | leitch->hour = ATOB(0)*10 +ATOB(1); |
589 | 0 | leitch->minute = ATOB(2)*10 +ATOB(3); |
590 | 0 | leitch->second = ATOB(4)*10 +ATOB(5); |
591 | |
|
592 | 0 | if ((leitch->hour > 23) || (leitch->minute > 60) || |
593 | 0 | (leitch->second > 60)) |
594 | 0 | return(0); |
595 | 0 | return(1); |
596 | 0 | } |
597 | | |
598 | | #else |
599 | | NONEMPTY_TRANSLATION_UNIT |
600 | | #endif /* REFCLOCK */ |