Annotation of embedaddon/ntp/libparse/clk_meinberg.c, revision 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>