Annotation of embedaddon/ntp/libparse/clk_meinberg.c, revision 1.1.1.1
1.1 misho 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-2005 by Frank Kardel <kardel <AT> ntp.org>
9: * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, 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' alternate antenna
109: *
110: * Meinberg GPS166 receiver
111: *
112: * You must get the Uni-Erlangen firmware for the GPS receiver support
113: * to work to full satisfaction !
114: *
115: * <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
116: *
117: * 000000000111111111122222222223333333333444444444455555555556666666
118: * 123456789012345678901234567890123456789012345678901234567890123456
119: * \x0209.07.93; 5; 08:48:26; +00:00; #*S!A L; 49.5736N 11.0280E 373m\x03
120: *
121: *
122: * <STX> = '\002' ASCII start of text
123: * <ETX> = '\003' ASCII end of text
124: * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
125: * <w> = day of week (sunday= 0)
126: * <hh>,<mm>,<ss> = hour, minute, second
127: * <+/->,<00:00> = offset to UTC
128: * <S> = '#' if never synced since powerup else ' '
129: * <F> = '*' if position is not confirmed else ' '
130: * <D> = 'S' if daylight saving time is active else ' '
131: * <A> = '!' during the hour preceeding an daylight saving time
132: * start/end change
133: * <L> = 'A' LEAP second announcement
134: * <R> = 'R' alternate antenna (reminiscent of PZF535) usually ' '
135: * <L> = 'L' on 23:59:60
136: *
137: * Binary messages have a lead in for a fixed header of SOH
138: */
139:
140: /*--------------------------------------------------------------*/
141: /* Name: csum() */
142: /* */
143: /* Purpose: Compute a checksum about a number of bytes */
144: /* */
145: /* Input: uchar *p address of the first byte */
146: /* short n the number of bytes */
147: /* */
148: /* Output: -- */
149: /* */
150: /* Ret val: the checksum */
151: /*+-------------------------------------------------------------*/
152:
153: unsigned long
154: mbg_csum(
155: unsigned char *p,
156: unsigned int n
157: )
158: {
159: unsigned long sum = 0;
160: short i;
161:
162: for ( i = 0; i < n; i++ )
163: sum += *p++;
164:
165: return( sum );
166: } /* csum */
167:
168: void
169: get_mbg_header(
170: unsigned char **bufpp,
171: GPS_MSG_HDR *headerp
172: )
173: {
174: headerp->gps_cmd = get_lsb_short(bufpp);
175: headerp->gps_len = get_lsb_short(bufpp);
176: headerp->gps_data_csum = get_lsb_short(bufpp);
177: headerp->gps_hdr_csum = get_lsb_short(bufpp);
178: }
179:
180: static struct format meinberg_fmt[] =
181: {
182: {
183: {
184: { 3, 2}, { 6, 2}, { 9, 2},
185: { 18, 2}, { 21, 2}, { 24, 2},
186: { 14, 1}, { 27, 4}, { 29, 1},
187: },
188: (const unsigned char *)"\2D: . . ;T: ;U: . . ; \3",
189: 0
190: },
191: { /* special extended FAU Erlangen extended format */
192: {
193: { 1, 2}, { 4, 2}, { 7, 2},
194: { 14, 2}, { 17, 2}, { 20, 2},
195: { 11, 1}, { 25, 4}, { 27, 1},
196: },
197: (const unsigned char *)"\2 . . ; ; : : ; \3",
198: MBG_EXTENDED
199: },
200: { /* special extended FAU Erlangen GPS format */
201: {
202: { 1, 2}, { 4, 2}, { 7, 2},
203: { 14, 2}, { 17, 2}, { 20, 2},
204: { 11, 1}, { 32, 7}, { 35, 1},
205: { 25, 2}, { 28, 2}, { 24, 1}
206: },
207: (const unsigned char *)"\2 . . ; ; : : ; : ; ; . . ",
208: 0
209: }
210: };
211:
212: static u_long cvt_meinberg (unsigned char *, int, struct format *, clocktime_t *, void *);
213: static u_long cvt_mgps (unsigned char *, int, struct format *, clocktime_t *, void *);
214: static u_long mbg_input (parse_t *, unsigned int, timestamp_t *);
215: static u_long gps_input (parse_t *, unsigned int, timestamp_t *);
216:
217: struct msg_buf
218: {
219: unsigned short len; /* len to fill */
220: unsigned short phase; /* current input phase */
221: };
222:
223: #define MBG_NONE 0 /* no data input */
224: #define MBG_HEADER 1 /* receiving header */
225: #define MBG_DATA 2 /* receiving data */
226: #define MBG_STRING 3 /* receiving standard data message */
227:
228: clockformat_t clock_meinberg[] =
229: {
230: {
231: mbg_input, /* normal input handling */
232: cvt_meinberg, /* Meinberg conversion */
233: pps_one, /* easy PPS monitoring */
234: 0, /* conversion configuration */
235: "Meinberg Standard", /* Meinberg simple format - beware */
236: 32, /* string buffer */
237: 0 /* no private data (complete pakets) */
238: },
239: {
240: mbg_input, /* normal input handling */
241: cvt_meinberg, /* Meinberg conversion */
242: pps_one, /* easy PPS monitoring */
243: 0, /* conversion configuration */
244: "Meinberg Extended", /* Meinberg enhanced format */
245: 32, /* string buffer */
246: 0 /* no private data (complete pakets) */
247: },
248: {
249: gps_input, /* no input handling */
250: cvt_mgps, /* Meinberg GPS166 conversion */
251: pps_one, /* easy PPS monitoring */
252: (void *)&meinberg_fmt[2], /* conversion configuration */
253: "Meinberg GPS Extended", /* Meinberg FAU GPS format */
254: 512, /* string buffer */
255: sizeof(struct msg_buf) /* no private data (complete pakets) */
256: }
257: };
258:
259: /*
260: * cvt_meinberg
261: *
262: * convert simple type format
263: */
264: static u_long
265: cvt_meinberg(
266: unsigned char *buffer,
267: int size,
268: struct format *unused,
269: clocktime_t *clock_time,
270: void *local
271: )
272: {
273: struct format *format;
274:
275: /*
276: * select automagically correct data format
277: */
278: if (Strok(buffer, meinberg_fmt[0].fixed_string))
279: {
280: format = &meinberg_fmt[0];
281: }
282: else
283: {
284: if (Strok(buffer, meinberg_fmt[1].fixed_string))
285: {
286: format = &meinberg_fmt[1];
287: }
288: else
289: {
290: return CVT_FAIL|CVT_BADFMT;
291: }
292: }
293:
294: /*
295: * collect data
296: */
297: if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
298: format->field_offsets[O_DAY].length) ||
299: Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
300: format->field_offsets[O_MONTH].length) ||
301: Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
302: format->field_offsets[O_YEAR].length) ||
303: Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
304: format->field_offsets[O_HOUR].length) ||
305: Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
306: format->field_offsets[O_MIN].length) ||
307: Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
308: format->field_offsets[O_SEC].length))
309: {
310: return CVT_FAIL|CVT_BADFMT;
311: }
312: else
313: {
314: unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
315:
316: clock_time->usecond = 0;
317: clock_time->flags = PARSEB_S_LEAP;
318:
319: if (clock_time->second == 60)
320: clock_time->flags |= PARSEB_LEAPSECOND;
321:
322: /*
323: * in the extended timecode format we have also the
324: * indication that the timecode is in UTC
325: * for compatibilty reasons we start at the USUAL
326: * offset (POWERUP flag) and know that the UTC indication
327: * is the character before the powerup flag
328: */
329: if ((format->flags & MBG_EXTENDED) && (f[-1] == 'U'))
330: {
331: /*
332: * timecode is in UTC
333: */
334: clock_time->utcoffset = 0; /* UTC */
335: clock_time->flags |= PARSEB_UTC;
336: }
337: else
338: {
339: /*
340: * only calculate UTC offset if MET/MED is in time code
341: * or we have the old time code format, where we do not
342: * know whether it is UTC time or MET/MED
343: * pray that nobody switches to UTC in the *old* standard time code
344: * ROMS !!!! The new ROMS have 'U' at the ZONE field - good.
345: */
346: switch (buffer[format->field_offsets[O_ZONE].offset])
347: {
348: case ' ':
349: clock_time->utcoffset = -1*60*60; /* MET */
350: break;
351:
352: case 'S':
353: clock_time->utcoffset = -2*60*60; /* MED */
354: break;
355:
356: case 'U':
357: /*
358: * timecode is in UTC
359: */
360: clock_time->utcoffset = 0; /* UTC */
361: clock_time->flags |= PARSEB_UTC;
362: break;
363:
364: default:
365: return CVT_FAIL|CVT_BADFMT;
366: }
367: }
368:
369: /*
370: * gather status flags
371: */
372: if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
373: clock_time->flags |= PARSEB_DST;
374:
375: if (f[0] == '#')
376: clock_time->flags |= PARSEB_POWERUP;
377:
378: if (f[1] == '*')
379: clock_time->flags |= PARSEB_NOSYNC;
380:
381: if (f[3] == '!')
382: clock_time->flags |= PARSEB_ANNOUNCE;
383:
384: /*
385: * oncoming leap second
386: * 'a' code not confirmed - earth is not
387: * expected to speed up
388: */
389: if (f[3] == 'A')
390: clock_time->flags |= PARSEB_LEAPADD;
391:
392: if (f[3] == 'a')
393: clock_time->flags |= PARSEB_LEAPDEL;
394:
395:
396: if (format->flags & MBG_EXTENDED)
397: {
398: clock_time->flags |= PARSEB_S_ANTENNA;
399:
400: /*
401: * DCF77 does not encode the direction -
402: * so we take the current default -
403: * earth slowing down
404: */
405: clock_time->flags &= ~PARSEB_LEAPDEL;
406:
407: if (f[4] == 'A')
408: clock_time->flags |= PARSEB_LEAPADD;
409:
410: if (f[5] == 'R')
411: clock_time->flags |= PARSEB_ALTERNATE;
412: }
413: return CVT_OK;
414: }
415: }
416:
417:
418: /*
419: * mbg_input
420: *
421: * grep data from input stream
422: */
423: static u_long
424: mbg_input(
425: parse_t *parseio,
426: unsigned int ch,
427: timestamp_t *tstamp
428: )
429: {
430: unsigned int rtc;
431:
432: parseprintf(DD_PARSE, ("mbg_input(0x%lx, 0x%x, ...)\n", (long)parseio, ch));
433:
434: switch (ch)
435: {
436: case STX:
437: parseprintf(DD_PARSE, ("mbg_input: STX seen\n"));
438:
439: parseio->parse_index = 1;
440: parseio->parse_data[0] = ch;
441: parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
442: return PARSE_INP_SKIP;
443:
444: case ETX:
445: parseprintf(DD_PARSE, ("mbg_input: ETX seen\n"));
446: if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP)
447: return parse_end(parseio);
448: else
449: return rtc;
450:
451: default:
452: return parse_addchar(parseio, ch);
453: }
454: }
455:
456:
457: /*
458: * cvt_mgps
459: *
460: * convert Meinberg GPS format
461: */
462: static u_long
463: cvt_mgps(
464: unsigned char *buffer,
465: int size,
466: struct format *format,
467: clocktime_t *clock_time,
468: void *local
469: )
470: {
471: if (!Strok(buffer, format->fixed_string))
472: {
473: return cvt_meinberg(buffer, size, format, clock_time, local);
474: }
475: else
476: {
477: if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day,
478: format->field_offsets[O_DAY].length) ||
479: Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month,
480: format->field_offsets[O_MONTH].length) ||
481: Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year,
482: format->field_offsets[O_YEAR].length) ||
483: Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour,
484: format->field_offsets[O_HOUR].length) ||
485: Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute,
486: format->field_offsets[O_MIN].length) ||
487: Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second,
488: format->field_offsets[O_SEC].length))
489: {
490: return CVT_FAIL|CVT_BADFMT;
491: }
492: else
493: {
494: long h;
495: unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset];
496:
497: clock_time->flags = PARSEB_S_LEAP|PARSEB_S_POSITION;
498:
499: clock_time->usecond = 0;
500:
501: /*
502: * calculate UTC offset
503: */
504: if (Stoi(&buffer[format->field_offsets[O_UTCHOFFSET].offset], &h,
505: format->field_offsets[O_UTCHOFFSET].length))
506: {
507: return CVT_FAIL|CVT_BADFMT;
508: }
509: else
510: {
511: if (Stoi(&buffer[format->field_offsets[O_UTCMOFFSET].offset], &clock_time->utcoffset,
512: format->field_offsets[O_UTCMOFFSET].length))
513: {
514: return CVT_FAIL|CVT_BADFMT;
515: }
516:
517: clock_time->utcoffset += TIMES60(h);
518: clock_time->utcoffset = TIMES60(clock_time->utcoffset);
519:
520: if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-')
521: {
522: clock_time->utcoffset = -clock_time->utcoffset;
523: }
524: }
525:
526: /*
527: * gather status flags
528: */
529: if (buffer[format->field_offsets[O_ZONE].offset] == 'S')
530: clock_time->flags |= PARSEB_DST;
531:
532: if (clock_time->utcoffset == 0)
533: clock_time->flags |= PARSEB_UTC;
534:
535: /*
536: * no sv's seen - no time & position
537: */
538: if (f[0] == '#')
539: clock_time->flags |= PARSEB_POWERUP;
540:
541: /*
542: * at least one sv seen - time (for last position)
543: */
544: if (f[1] == '*')
545: clock_time->flags |= PARSEB_NOSYNC;
546: else
547: if (!(clock_time->flags & PARSEB_POWERUP))
548: clock_time->flags |= PARSEB_POSITION;
549:
550: /*
551: * oncoming zone switch
552: */
553: if (f[3] == '!')
554: clock_time->flags |= PARSEB_ANNOUNCE;
555:
556: /*
557: * oncoming leap second
558: * 'a' code not confirmed - earth is not
559: * expected to speed up
560: */
561: if (f[4] == 'A')
562: clock_time->flags |= PARSEB_LEAPADD;
563:
564: if (f[4] == 'a')
565: clock_time->flags |= PARSEB_LEAPDEL;
566:
567: /*
568: * f[5] == ' '
569: */
570:
571: /*
572: * this is the leap second
573: */
574: if ((f[6] == 'L') || (clock_time->second == 60))
575: clock_time->flags |= PARSEB_LEAPSECOND;
576:
577: return CVT_OK;
578: }
579: }
580: }
581:
582: /*
583: * gps_input
584: *
585: * grep binary data from input stream
586: */
587: static u_long
588: gps_input(
589: parse_t *parseio,
590: unsigned int ch,
591: timestamp_t *tstamp
592: )
593: {
594: CSUM calc_csum; /* used to compare the incoming csums */
595: GPS_MSG_HDR header;
596: struct msg_buf *msg_buf;
597:
598: msg_buf = (struct msg_buf *)parseio->parse_pdata;
599:
600: parseprintf(DD_PARSE, ("gps_input(0x%lx, 0x%x, ...)\n", (long)parseio, ch));
601:
602: if (!msg_buf)
603: return PARSE_INP_SKIP;
604:
605: if ( msg_buf->phase == MBG_NONE )
606: { /* not receiving yet */
607: switch (ch)
608: {
609: case SOH:
610: parseprintf(DD_PARSE, ("gps_input: SOH seen\n"));
611:
612: msg_buf->len = sizeof( header ); /* prepare to receive msg header */
613: msg_buf->phase = MBG_HEADER; /* receiving header */
614: break;
615:
616: case STX:
617: parseprintf(DD_PARSE, ("gps_input: STX seen\n"));
618:
619: msg_buf->len = 0;
620: msg_buf->phase = MBG_STRING; /* prepare to receive ASCII ETX delimited message */
621: parseio->parse_index = 1;
622: parseio->parse_data[0] = ch;
623: break;
624:
625: default:
626: return PARSE_INP_SKIP; /* keep searching */
627: }
628:
629: parseio->parse_dtime.parse_msglen = 1; /* reset buffer pointer */
630: parseio->parse_dtime.parse_msg[0] = ch; /* fill in first character */
631: parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
632: return PARSE_INP_SKIP;
633: }
634:
635: /* SOH/STX has already been received */
636:
637: /* save incoming character in both buffers if needbe */
638: if ((msg_buf->phase == MBG_STRING) &&
639: (parseio->parse_index < parseio->parse_dsize))
640: parseio->parse_data[parseio->parse_index++] = ch;
641:
642: parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch;
643:
644: if (parseio->parse_dtime.parse_msglen > sizeof(parseio->parse_dtime.parse_msg))
645: {
646: msg_buf->phase = MBG_NONE; /* buffer overflow - discard */
647: parseio->parse_data[parseio->parse_index] = '\0';
648: memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
649: parseio->parse_ldsize = parseio->parse_index;
650: return PARSE_INP_DATA;
651: }
652:
653: switch (msg_buf->phase)
654: {
655: case MBG_HEADER:
656: case MBG_DATA:
657: msg_buf->len--;
658:
659: if ( msg_buf->len ) /* transfer not complete */
660: return PARSE_INP_SKIP;
661:
662: parseprintf(DD_PARSE, ("gps_input: %s complete\n", (msg_buf->phase == MBG_DATA) ? "data" : "header"));
663:
664: break;
665:
666: case MBG_STRING:
667: if ((ch == ETX) || (parseio->parse_index >= parseio->parse_dsize))
668: {
669: msg_buf->phase = MBG_NONE;
670: parseprintf(DD_PARSE, ("gps_input: string complete\n"));
671: parseio->parse_data[parseio->parse_index] = '\0';
672: memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
673: parseio->parse_ldsize = parseio->parse_index;
674: parseio->parse_index = 0;
675: return PARSE_INP_TIME;
676: }
677: else
678: {
679: return PARSE_INP_SKIP;
680: }
681: }
682:
683: /* cnt == 0, so the header or the whole message is complete */
684:
685: if ( msg_buf->phase == MBG_HEADER )
686: { /* header complete now */
687: unsigned char *datap = parseio->parse_dtime.parse_msg + 1;
688:
689: get_mbg_header(&datap, &header);
690:
691: parseprintf(DD_PARSE, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n",
692: (int)header.gps_cmd, (int)header.gps_len, (int)header.gps_data_csum,
693: (int)header.gps_hdr_csum));
694:
695:
696: calc_csum = mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg + 1, (unsigned short)6 );
697:
698: if ( calc_csum != header.gps_hdr_csum )
699: {
700: parseprintf(DD_PARSE, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n",
701: (int)calc_csum, (int)mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg, (unsigned short)6 )));
702:
703: msg_buf->phase = MBG_NONE; /* back to hunting mode */
704: return PARSE_INP_DATA; /* invalid header checksum received - pass up for detection */
705: }
706:
707: if ((header.gps_len == 0) || /* no data to wait for */
708: (header.gps_len >= (sizeof (parseio->parse_dtime.parse_msg) - sizeof(header) - 1))) /* blows anything we have space for */
709: {
710: msg_buf->phase = MBG_NONE; /* back to hunting mode */
711: return (header.gps_len == 0) ? PARSE_INP_DATA : PARSE_INP_SKIP; /* message complete/throwaway */
712: }
713:
714: parseprintf(DD_PARSE, ("gps_input: expecting %d bytes of data message\n", (int)header.gps_len));
715:
716: msg_buf->len = header.gps_len;/* save number of bytes to wait for */
717: msg_buf->phase = MBG_DATA; /* flag header already complete */
718: return PARSE_INP_SKIP;
719: }
720:
721: parseprintf(DD_PARSE, ("gps_input: message data complete\n"));
722:
723: /* Header and data have been received. The header checksum has been */
724: /* checked */
725:
726: msg_buf->phase = MBG_NONE; /* back to hunting mode */
727: return PARSE_INP_DATA; /* message complete, must be evaluated */
728: }
729:
730: #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
731: int clk_meinberg_bs;
732: #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */
733:
734: /*
735: * History:
736: *
737: * clk_meinberg.c,v
738: * Revision 4.12.2.1 2005/09/25 10:22:35 kardel
739: * cleanup buffer bounds
740: *
741: * Revision 4.12 2005/04/16 17:32:10 kardel
742: * update copyright
743: *
744: * Revision 4.11 2004/11/14 15:29:41 kardel
745: * support PPSAPI, upgrade Copyright to Berkeley style
746: *
747: * Revision 4.8 1999/11/28 09:13:50 kardel
748: * RECON_4_0_98F
749: *
750: * Revision 4.7 1999/02/21 11:09:14 kardel
751: * cleanup
752: *
753: * Revision 4.6 1998/06/14 21:09:36 kardel
754: * Sun acc cleanup
755: *
756: * Revision 4.5 1998/06/13 15:18:54 kardel
757: * fix mem*() to b*() function macro emulation
758: *
759: * Revision 4.4 1998/06/13 12:03:23 kardel
760: * fix SYSV clock name clash
761: *
762: * Revision 4.3 1998/06/12 15:22:28 kardel
763: * fix prototypes
764: *
765: * Revision 4.2 1998/05/24 16:14:42 kardel
766: * support current Meinberg standard data formats
767: *
768: * Revision 4.1 1998/05/24 09:39:52 kardel
769: * implementation of the new IO handling model
770: *
771: * Revision 4.0 1998/04/10 19:45:29 kardel
772: * Start 4.0 release version numbering
773: *
774: * from V3 3.23 - log info deleted 1998/04/11 kardel
775: *
776: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>