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