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