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