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