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