1 /*
2 * /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
3 *
4 * clk_meinberg.c,v 4.12.2.1 2005/09/25 10:22:35 kardel RELEASE_20050925_A
5 *
6 * Meinberg clock support
7 *
8 * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
9 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the author nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37 #ifdef HAVE_CONFIG_H
38 # include <config.h>
39 #endif
40
41 #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_MEINBERG)
42
43 #include "ntp_fp.h"
44 #include "ntp_unixtime.h"
45 #include "ntp_calendar.h"
46
47 #include "ntp_machine.h"
48
49 #include "parse.h"
50
51 #ifndef PARSESTREAM
52 #include <stdio.h>
53 #else
54 #include "sys/parsestreams.h"
55 #endif
56
57 #include "ntp_stdlib.h"
58
59 #include "ntp_stdlib.h"
60
61 #include "mbg_gps166.h"
62 #include "binio.h"
63 #include "ascii.h"
64
65 /*
66 * The Meinberg receiver every second sends a datagram of the following form
67 * (Standard Format)
68 *
69 * <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
70 * pos: 0 00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2 2 3 3 3
71 * 1 23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8 9 0 1 2
72 * <STX> = '\002' ASCII start of text
73 * <ETX> = '\003' ASCII end of text
74 * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
75 * <w> = day of week (sunday= 0)
76 * <hh>,<mm>,<ss> = hour, minute, second
77 * <S> = '#' if never synced since powerup for DCF C51
78 * = '#' if not PZF sychronisation available for PZF 535/509
79 * = ' ' if ok
80 * <F> = '*' if time comes from internal quartz
81 * = ' ' if completely synched
82 * <D> = 'S' if daylight saving time is active
83 * = 'U' if time is represented in UTC
84 * = ' ' if no special condition exists
85 * <A> = '!' during the hour preceeding an daylight saving time
86 * start/end change
87 * = 'A' leap second insert warning
88 * = ' ' if no special condition exists
89 *
90 * Extended data format (PZFUERL for PZF type clocks)
91 *
92 * <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <U><S><F><D><A><L><R><ETX>
93 * pos: 0 00 0 00 0 00 11 1 11 11 1 11 2 22 22 2 2 2 2 2 3 3 3
94 * 1 23 4 56 7 89 01 2 34 56 7 89 0 12 34 5 6 7 8 9 0 1 2
95 * <STX> = '\002' ASCII start of text
96 * <ETX> = '\003' ASCII end of text
97 * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
98 * <w> = day of week (sunday= 0)
99 * <hh>,<mm>,<ss> = hour, minute, second
100 * <U> = 'U' UTC time display
101 * <S> = '#' if never synced since powerup else ' ' for DCF C51
102 * '#' if not PZF sychronisation available else ' ' for PZF 535/509
103 * <F> = '*' if time comes from internal quartz else ' '
104 * <D> = 'S' if daylight saving time is active else ' '
105 * <A> = '!' during the hour preceeding an daylight saving time
106 * start/end change
107 * <L> = 'A' LEAP second announcement
108 * <R> = 'R' "call bit" used to signalize irregularities in the control facilities,
109 * usually ' ', until 2003 indicated transmission via alternate antenna
110 *
111 * Meinberg GPS receivers
112 *
113 * For very old devices you must get the Uni-Erlangen firmware for the GPS receiver support
114 * to work to full satisfaction !
115 * With newer GPS receiver types the Uni Erlangen string format can be configured at the device.
116 *
117 * <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
118 *
119 * 000000000111111111122222222223333333333444444444455555555556666666
120 * 123456789012345678901234567890123456789012345678901234567890123456
121 * \x0209.07.93; 5; 08:48:26; +00:00; #*S!A L; 49.5736N 11.0280E 373m\x03
122 *
123 *
124 * <STX> = '\002' ASCII start of text
125 * <ETX> = '\003' ASCII end of text
126 * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
127 * <w> = day of week (sunday= 0)
128 * <hh>,<mm>,<ss> = hour, minute, second
129 * <+/->,<00:00> = offset to UTC
130 * <S> = '#' if never synced since powerup else ' '
131 * <F> = '*' if position is not confirmed else ' '
132 * <D> = 'S' if daylight saving time is active else ' '
133 * <A> = '!' during the hour preceeding an daylight saving time
134 * start/end change
135 * <L> = 'A' LEAP second announcement
136 * <R> = 'R' "call bit" used to signalize irregularities in the control facilities,
137 * usually ' ', until 2003 indicated transmission via alternate antenna
138 * (reminiscent of PZF receivers)
139 * <L> = 'L' on 23:59:60
140 *
141 * Binary messages have a lead in for a fixed header of SOH
142 */
143
144 /*--------------------------------------------------------------*/
145 /* Name: csum() */
146 /* */
147 /* Purpose: Compute a checksum about a number of bytes */
148 /* */
149 /* Input: uchar *p address of the first byte */
150 /* short n the number of bytes */
151 /* */
152 /* Output: -- */
153 /* */
154 /* Ret val: the checksum */
155 /*+-------------------------------------------------------------*/
156
157 CSUM
mbg_csum(unsigned char * p,unsigned int n)158 mbg_csum(
159 unsigned char *p,
160 unsigned int n
161 )
162 {
163 unsigned int sum = 0;
164 unsigned int i;
165
166 for ( i = 0; i < n; i++ )
167 sum += *p++;
168
169 return (CSUM) sum;
170
171 } /* csum */
172
173 void
get_mbg_header(unsigned char ** bufpp,GPS_MSG_HDR * headerp)174 get_mbg_header(
175 unsigned char **bufpp,
176 GPS_MSG_HDR *headerp
177 )
178 {
179 headerp->cmd = (GPS_CMD) get_lsb_short(bufpp);
180 headerp->len = get_lsb_uint16(bufpp);
181 headerp->data_csum = (CSUM) get_lsb_short(bufpp);
182 headerp->hdr_csum = (CSUM) get_lsb_short(bufpp);
183 }
184
185 static struct format meinberg_fmt[] =
186 {
187 {
188 {
189 { 3, 2}, { 6, 2}, { 9, 2},
190 { 18, 2}, { 21, 2}, { 24, 2},
191 { 14, 1}, { 27, 4}, { 29, 1},
192 },
193 (const unsigned char *)"\2D: . . ;T: ;U: . . ; \3",
194 0
195 },
196 { /* special extended FAU Erlangen extended format */
197 {
198 { 1, 2}, { 4, 2}, { 7, 2},
199 { 14, 2}, { 17, 2}, { 20, 2},
200 { 11, 1}, { 25, 4}, { 27, 1},
201 },
202 (const unsigned char *)"\2 . . ; ; : : ; \3",
203 MBG_EXTENDED
204 },
205 { /* special extended FAU Erlangen GPS format */
206 {
207 { 1, 2}, { 4, 2}, { 7, 2},
208 { 14, 2}, { 17, 2}, { 20, 2},
209 { 11, 1}, { 32, 7}, { 35, 1},
210 { 25, 2}, { 28, 2}, { 24, 1}
211 },
212 (const unsigned char *)"\2 . . ; ; : : ; : ; ; . . ",
213 0
214 }
215 };
216
217 static parse_cvt_fnc_t cvt_meinberg;
218 static parse_cvt_fnc_t cvt_mgps;
219 static parse_inp_fnc_t mbg_input;
220 static parse_inp_fnc_t gps_input;
221
222 struct msg_buf
223 {
224 unsigned short len; /* len to fill */
225 unsigned short phase; /* current input phase */
226 };
227
228 #define MBG_NONE 0 /* no data input */
229 #define MBG_HEADER 1 /* receiving header */
230 #define MBG_DATA 2 /* receiving data */
231 #define MBG_STRING 3 /* receiving standard data message */
232
233 clockformat_t clock_meinberg[] =
234 {
235 {
236 mbg_input, /* normal input handling */
237 cvt_meinberg, /* Meinberg conversion */
238 pps_one, /* easy PPS monitoring */
239 0, /* conversion configuration */
240 "Meinberg Standard", /* Meinberg simple format - beware */
241 32, /* string buffer */
242 0 /* no private data (complete packets) */
243 },
244 {
245 mbg_input, /* normal input handling */
246 cvt_meinberg, /* Meinberg conversion */
247 pps_one, /* easy PPS monitoring */
248 0, /* conversion configuration */
249 "Meinberg Extended", /* Meinberg enhanced format */
250 32, /* string buffer */
251 0 /* no private data (complete packets) */
252 },
253 {
254 gps_input, /* no input handling */
255 cvt_mgps, /* Meinberg GPS receiver conversion */
256 pps_one, /* easy PPS monitoring */
257 (void *)&meinberg_fmt[2], /* conversion configuration */
258 "Meinberg GPS Extended", /* Meinberg FAU GPS format */
259 512, /* string buffer */
260 sizeof(struct msg_buf) /* no private data (complete packets) */
261 }
262 };
263
264 /*
265 * parse_cvt_fnc_t cvt_meinberg
266 *
267 * convert simple type format
268 */
269 static u_long
cvt_meinberg(unsigned char * buffer,int size,struct format * unused,clocktime_t * clock_time,void * local)270 cvt_meinberg(
271 unsigned char *buffer,
272 int size,
273 struct format *unused,
274 clocktime_t *clock_time,
275 void *local
276 )
277 {
278 struct format *format;
279
280 /*
281 * select automagically correct data format
282 */
283 if (Strok(buffer, meinberg_fmt[0].fixed_string))
284 {
285 format = &meinberg_fmt[0];
286 }
287 else
288 {
289 if (Strok(buffer, meinberg_fmt[1].fixed_string))
290 {
291 format = &meinberg_fmt[1];
292 }
293 else
294 {
295 return CVT_FAIL|CVT_BADFMT;
296 }
297 }
298
299 /*
300 * collect data
301 */
302 if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
303 format->field_offsets[O_DAY].length) ||
304 Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
305 format->field_offsets[O_MONTH].length) ||
306 Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
307 format->field_offsets[O_YEAR].length) ||
308 Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
309 format->field_offsets[O_HOUR].length) ||
310 Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
311 format->field_offsets[O_MIN].length) ||
312 Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
313 format->field_offsets[O_SEC].length))
314 {
315 return CVT_FAIL|CVT_BADFMT;
316 }
317 else
318 {
319 unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
320
321 clock_time->usecond = 0;
322 clock_time->flags = PARSEB_S_LEAP;
323
324 if (clock_time->second == 60)
325 clock_time->flags |= PARSEB_LEAPSECOND;
326
327 /*
328 * in the extended timecode format we have also the
329 * indication that the timecode is in UTC
330 * for compatibilty reasons we start at the USUAL
331 * offset (POWERUP flag) and know that the UTC indication
332 * is the character before the powerup flag
333 */
334 if ((format->flags & MBG_EXTENDED) && (f[-1] == 'U'))
335 {
336 /*
337 * timecode is in UTC
338 */
339 clock_time->utcoffset = 0; /* UTC */
340 clock_time->flags |= PARSEB_UTC;
341 }
342 else
343 {
344 /*
345 * only calculate UTC offset if MET/MED is in time code
346 * or we have the old time code format, where we do not
347 * know whether it is UTC time or MET/MED
348 * pray that nobody switches to UTC in the *old* standard time code
349 * ROMS !!!! The new ROMS have 'U' at the ZONE field - good.
350 */
351 switch (buffer[format->field_offsets[O_ZONE].offset])
352 {
353 case ' ':
354 clock_time->utcoffset = -1*60*60; /* MET */
355 break;
356
357 case 'S':
358 clock_time->utcoffset = -2*60*60; /* MED */
359 break;
360
361 case 'U':
362 /*
363 * timecode is in UTC
364 */
365 clock_time->utcoffset = 0; /* UTC */
366 clock_time->flags |= PARSEB_UTC;
367 break;
368
369 default:
370 return CVT_FAIL|CVT_BADFMT;
371 }
372 }
373
374 /*
375 * gather status flags
376 */
377 if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
378 clock_time->flags |= PARSEB_DST;
379
380 if (f[0] == '#')
381 clock_time->flags |= PARSEB_POWERUP;
382
383 if (f[1] == '*')
384 clock_time->flags |= PARSEB_NOSYNC;
385
386 if (f[3] == '!')
387 clock_time->flags |= PARSEB_ANNOUNCE;
388
389 /*
390 * oncoming leap second
391 * 'a' code not confirmed - earth is not
392 * expected to speed up
393 */
394 if (f[3] == 'A')
395 clock_time->flags |= PARSEB_LEAPADD;
396
397 if (f[3] == 'a')
398 clock_time->flags |= PARSEB_LEAPDEL;
399
400
401 if (format->flags & MBG_EXTENDED)
402 {
403 clock_time->flags |= PARSEB_S_CALLBIT;
404
405 /*
406 * DCF77 does not encode the direction -
407 * so we take the current default -
408 * earth slowing down
409 */
410 clock_time->flags &= ~PARSEB_LEAPDEL;
411
412 if (f[4] == 'A')
413 clock_time->flags |= PARSEB_LEAPADD;
414
415 if (f[5] == 'R')
416 clock_time->flags |= PARSEB_CALLBIT;
417 }
418 return CVT_OK;
419 }
420 }
421
422
423 /*
424 * parse_inp_fnc_t mbg_input
425 *
426 * grab data from input stream
427 */
428 static u_long
mbg_input(parse_t * parseio,char ch,timestamp_t * tstamp)429 mbg_input(
430 parse_t *parseio,
431 char ch,
432 timestamp_t *tstamp
433 )
434 {
435 unsigned int rtc;
436
437 parseprintf(DD_PARSE, ("mbg_input(0x%p, 0x%x, ...)\n", (void*)parseio, ch));
438
439 switch (ch)
440 {
441 case STX:
442 parseprintf(DD_PARSE, ("mbg_input: STX seen\n"));
443
444 parseio->parse_index = 1;
445 parseio->parse_data[0] = ch;
446 parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
447 return PARSE_INP_SKIP;
448
449 case ETX:
450 parseprintf(DD_PARSE, ("mbg_input: ETX seen\n"));
451 if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP)
452 return parse_end(parseio);
453 else
454 return rtc;
455
456 default:
457 return parse_addchar(parseio, ch);
458 }
459 }
460
461
462 /*
463 * parse_cvt_fnc_t cvt_mgps
464 *
465 * convert Meinberg GPS format
466 */
467 static u_long
cvt_mgps(unsigned char * buffer,int size,struct format * format,clocktime_t * clock_time,void * local)468 cvt_mgps(
469 unsigned char *buffer,
470 int size,
471 struct format *format,
472 clocktime_t *clock_time,
473 void *local
474 )
475 {
476 if (!Strok(buffer, format->fixed_string))
477 {
478 return cvt_meinberg(buffer, size, format, clock_time, local);
479 }
480 else
481 {
482 if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
483 format->field_offsets[O_DAY].length) ||
484 Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
485 format->field_offsets[O_MONTH].length) ||
486 Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
487 format->field_offsets[O_YEAR].length) ||
488 Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
489 format->field_offsets[O_HOUR].length) ||
490 Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
491 format->field_offsets[O_MIN].length) ||
492 Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
493 format->field_offsets[O_SEC].length))
494 {
495 return CVT_FAIL|CVT_BADFMT;
496 }
497 else
498 {
499 long h;
500 unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
501
502 clock_time->flags = PARSEB_S_LEAP|PARSEB_S_POSITION;
503
504 clock_time->usecond = 0;
505
506 /*
507 * calculate UTC offset
508 */
509 if (Stoi(&buffer[format->field_offsets[O_UTCHOFFSET].offset], &h,
510 format->field_offsets[O_UTCHOFFSET].length))
511 {
512 return CVT_FAIL|CVT_BADFMT;
513 }
514 else
515 {
516 if (Stoi(&buffer[format->field_offsets[O_UTCMOFFSET].offset], &clock_time->utcoffset,
517 format->field_offsets[O_UTCMOFFSET].length))
518 {
519 return CVT_FAIL|CVT_BADFMT;
520 }
521
522 clock_time->utcoffset += TIMES60(h);
523 clock_time->utcoffset = TIMES60(clock_time->utcoffset);
524
525 if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-')
526 {
527 clock_time->utcoffset = -clock_time->utcoffset;
528 }
529 }
530
531 /*
532 * gather status flags
533 */
534 if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
535 clock_time->flags |= PARSEB_DST;
536
537 if (clock_time->utcoffset == 0)
538 clock_time->flags |= PARSEB_UTC;
539
540 /*
541 * no sv's seen - no time & position
542 */
543 if (f[0] == '#')
544 clock_time->flags |= PARSEB_POWERUP;
545
546 /*
547 * at least one sv seen - time (for last position)
548 */
549 if (f[1] == '*')
550 clock_time->flags |= PARSEB_NOSYNC;
551 else
552 if (!(clock_time->flags & PARSEB_POWERUP))
553 clock_time->flags |= PARSEB_POSITION;
554
555 /*
556 * oncoming zone switch
557 */
558 if (f[3] == '!')
559 clock_time->flags |= PARSEB_ANNOUNCE;
560
561 /*
562 * oncoming leap second
563 * 'a' code not confirmed - earth is not
564 * expected to speed up
565 */
566 if (f[4] == 'A')
567 clock_time->flags |= PARSEB_LEAPADD;
568
569 if (f[4] == 'a')
570 clock_time->flags |= PARSEB_LEAPDEL;
571
572 /*
573 * f[5] == ' '
574 */
575
576 /*
577 * this is the leap second
578 */
579 if ((f[6] == 'L') || (clock_time->second == 60))
580 clock_time->flags |= PARSEB_LEAPSECOND;
581
582 return CVT_OK;
583 }
584 }
585 }
586
587 /*
588 * parse_inp_fnc_t gps_input
589 *
590 * grep binary data from input stream
591 */
592 static u_long
gps_input(parse_t * parseio,char ch,timestamp_t * tstamp)593 gps_input(
594 parse_t *parseio,
595 char ch,
596 timestamp_t *tstamp
597 )
598 {
599 CSUM calc_csum; /* used to compare the incoming csums */
600 GPS_MSG_HDR header;
601 struct msg_buf *msg_buf;
602
603 msg_buf = (struct msg_buf *)parseio->parse_pdata;
604
605 parseprintf(DD_PARSE, ("gps_input(0x%p, 0x%x, ...)\n", (void*)parseio, ch));
606
607 if (!msg_buf)
608 return PARSE_INP_SKIP;
609
610 if ( msg_buf->phase == MBG_NONE )
611 { /* not receiving yet */
612 switch (ch)
613 {
614 case SOH:
615 parseprintf(DD_PARSE, ("gps_input: SOH seen\n"));
616
617 msg_buf->len = sizeof( header ); /* prepare to receive msg header */
618 msg_buf->phase = MBG_HEADER; /* receiving header */
619 break;
620
621 case STX:
622 parseprintf(DD_PARSE, ("gps_input: STX seen\n"));
623
624 msg_buf->len = 0;
625 msg_buf->phase = MBG_STRING; /* prepare to receive ASCII ETX delimited message */
626 parseio->parse_index = 1;
627 parseio->parse_data[0] = ch;
628 break;
629
630 default:
631 return PARSE_INP_SKIP; /* keep searching */
632 }
633
634 parseio->parse_dtime.parse_msglen = 1; /* reset buffer pointer */
635 parseio->parse_dtime.parse_msg[0] = ch; /* fill in first character */
636 parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
637 return PARSE_INP_SKIP;
638 }
639
640 /* SOH/STX has already been received */
641
642 /* save incoming character in both buffers if needbe */
643 if ((msg_buf->phase == MBG_STRING) &&
644 (parseio->parse_index < parseio->parse_dsize))
645 parseio->parse_data[parseio->parse_index++] = ch;
646
647 parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
648
649 if (parseio->parse_dtime.parse_msglen > sizeof(parseio->parse_dtime.parse_msg))
650 {
651 msg_buf->phase = MBG_NONE; /* buffer overflow - discard */
652 parseio->parse_data[parseio->parse_index] = '\0';
653 memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
654 parseio->parse_ldsize = parseio->parse_index;
655 return PARSE_INP_DATA;
656 }
657
658 switch (msg_buf->phase)
659 {
660 case MBG_HEADER:
661 case MBG_DATA:
662 msg_buf->len--;
663
664 if ( msg_buf->len ) /* transfer not complete */
665 return PARSE_INP_SKIP;
666
667 parseprintf(DD_PARSE, ("gps_input: %s complete\n", (msg_buf->phase == MBG_DATA) ? "data" : "header"));
668
669 break;
670
671 case MBG_STRING:
672 if ((ch == ETX) || (parseio->parse_index >= parseio->parse_dsize))
673 {
674 msg_buf->phase = MBG_NONE;
675 parseprintf(DD_PARSE, ("gps_input: string complete\n"));
676 parseio->parse_data[parseio->parse_index] = '\0';
677 memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
678 parseio->parse_ldsize = parseio->parse_index;
679 parseio->parse_index = 0;
680 return PARSE_INP_TIME;
681 }
682 else
683 {
684 return PARSE_INP_SKIP;
685 }
686 }
687
688 /* cnt == 0, so the header or the whole message is complete */
689
690 if ( msg_buf->phase == MBG_HEADER )
691 { /* header complete now */
692 unsigned char *datap = parseio->parse_dtime.parse_msg + 1;
693
694 get_mbg_header(&datap, &header);
695
696 parseprintf(DD_PARSE, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n",
697 (int)header.cmd, (int)header.len, (int)header.data_csum,
698 (int)header.hdr_csum));
699
700
701 calc_csum = mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg + 1, (unsigned short)6 );
702
703 if ( calc_csum != header.hdr_csum )
704 {
705 parseprintf(DD_PARSE, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n",
706 (int)calc_csum, (int)mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg, (unsigned short)6 )));
707
708 msg_buf->phase = MBG_NONE; /* back to hunting mode */
709 return PARSE_INP_DATA; /* invalid header checksum received - pass up for detection */
710 }
711
712 if ((header.len == 0) || /* no data to wait for */
713 (header.len >= (sizeof (parseio->parse_dtime.parse_msg) - sizeof(header) - 1))) /* blows anything we have space for */
714 {
715 msg_buf->phase = MBG_NONE; /* back to hunting mode */
716 return (header.len == 0) ? PARSE_INP_DATA : PARSE_INP_SKIP; /* message complete/throwaway */
717 }
718
719 parseprintf(DD_PARSE, ("gps_input: expecting %d bytes of data message\n", (int)header.len));
720
721 msg_buf->len = header.len;/* save number of bytes to wait for */
722 msg_buf->phase = MBG_DATA; /* flag header already complete */
723 return PARSE_INP_SKIP;
724 }
725
726 parseprintf(DD_PARSE, ("gps_input: message data complete\n"));
727
728 /* Header and data have been received. The header checksum has been */
729 /* checked */
730
731 msg_buf->phase = MBG_NONE; /* back to hunting mode */
732 return PARSE_INP_DATA; /* message complete, must be evaluated */
733 }
734
735 #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
736 NONEMPTY_TRANSLATION_UNIT
737 #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
738
739 /*
740 * History:
741 *
742 * clk_meinberg.c,v
743 * Revision 4.12.2.1 2005/09/25 10:22:35 kardel
744 * cleanup buffer bounds
745 *
746 * Revision 4.12 2005/04/16 17:32:10 kardel
747 * update copyright
748 *
749 * Revision 4.11 2004/11/14 15:29:41 kardel
750 * support PPSAPI, upgrade Copyright to Berkeley style
751 *
752 * Revision 4.8 1999/11/28 09:13:50 kardel
753 * RECON_4_0_98F
754 *
755 * Revision 4.7 1999/02/21 11:09:14 kardel
756 * cleanup
757 *
758 * Revision 4.6 1998/06/14 21:09:36 kardel
759 * Sun acc cleanup
760 *
761 * Revision 4.5 1998/06/13 15:18:54 kardel
762 * fix mem*() to b*() function macro emulation
763 *
764 * Revision 4.4 1998/06/13 12:03:23 kardel
765 * fix SYSV clock name clash
766 *
767 * Revision 4.3 1998/06/12 15:22:28 kardel
768 * fix prototypes
769 *
770 * Revision 4.2 1998/05/24 16:14:42 kardel
771 * support current Meinberg standard data formats
772 *
773 * Revision 4.1 1998/05/24 09:39:52 kardel
774 * implementation of the new IO handling model
775 *
776 * Revision 4.0 1998/04/10 19:45:29 kardel
777 * Start 4.0 release version numbering
778 *
779 * from V3 3.23 - log info deleted 1998/04/11 kardel
780 *
781 */
782