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 P((unsigned char *, int, struct format *, clocktime_t *, void *)); 213 static u_long cvt_mgps P((unsigned char *, int, struct format *, clocktime_t *, void *)); 214 static u_long mbg_input P((parse_t *, unsigned int, timestamp_t *)); 215 static u_long gps_input P((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 */ 777