1 /* 2 * /src/NTP/ntp-4/libparse/clk_rawdcf.c,v 4.6 1998/06/14 21:09:37 kardel RELEASE_19990228_A 3 * 4 * clk_rawdcf.c,v 4.6 1998/06/14 21:09:37 kardel RELEASE_19990228_A 5 * 6 * Raw DCF77 pulse clock support 7 * 8 * Copyright (C) 1992-1998 by Frank Kardel 9 * Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 * 15 */ 16 17 #ifdef HAVE_CONFIG_H 18 # include <config.h> 19 #endif 20 21 #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_RAWDCF) 22 23 #include <sys/types.h> 24 #include <sys/time.h> 25 26 #include "ntp_fp.h" 27 #include "ntp_unixtime.h" 28 #include "ntp_calendar.h" 29 30 #include "parse.h" 31 #ifdef PARSESTREAM 32 # include <sys/parsestreams.h> 33 #endif 34 35 #ifndef PARSEKERNEL 36 # include "ntp_stdlib.h" 37 #endif 38 39 /* 40 * DCF77 raw time code 41 * 42 * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig 43 * und Berlin, Maerz 1989 44 * 45 * Timecode transmission: 46 * AM: 47 * time marks are send every second except for the second before the 48 * next minute mark 49 * time marks consist of a reduction of transmitter power to 25% 50 * of the nominal level 51 * the falling edge is the time indication (on time) 52 * time marks of a 100ms duration constitute a logical 0 53 * time marks of a 200ms duration constitute a logical 1 54 * FM: 55 * see the spec. (basically a (non-)inverted psuedo random phase shift) 56 * 57 * Encoding: 58 * Second Contents 59 * 0 - 10 AM: free, FM: 0 60 * 11 - 14 free 61 * 15 R - alternate antenna 62 * 16 A1 - expect zone change (1 hour before) 63 * 17 - 18 Z1,Z2 - time zone 64 * 0 0 illegal 65 * 0 1 MEZ (MET) 66 * 1 0 MESZ (MED, MET DST) 67 * 1 1 illegal 68 * 19 A2 - expect leap insertion/deletion (1 hour before) 69 * 20 S - start of time code (1) 70 * 21 - 24 M1 - BCD (lsb first) Minutes 71 * 25 - 27 M10 - BCD (lsb first) 10 Minutes 72 * 28 P1 - Minute Parity (even) 73 * 29 - 32 H1 - BCD (lsb first) Hours 74 * 33 - 34 H10 - BCD (lsb first) 10 Hours 75 * 35 P2 - Hour Parity (even) 76 * 36 - 39 D1 - BCD (lsb first) Days 77 * 40 - 41 D10 - BCD (lsb first) 10 Days 78 * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday) 79 * 45 - 49 MO - BCD (lsb first) Month 80 * 50 MO0 - 10 Months 81 * 51 - 53 Y1 - BCD (lsb first) Years 82 * 54 - 57 Y10 - BCD (lsb first) 10 Years 83 * 58 P3 - Date Parity (even) 84 * 59 - usually missing (minute indication), except for leap insertion 85 */ 86 87 static u_long pps_rawdcf P((parse_t *, int, timestamp_t *)); 88 static u_long cvt_rawdcf P((unsigned char *, int, struct format *, clocktime_t *, void *)); 89 static u_long inp_rawdcf P((parse_t *, unsigned int, timestamp_t *)); 90 91 clockformat_t clock_rawdcf = 92 { 93 inp_rawdcf, /* DCF77 input handling */ 94 cvt_rawdcf, /* raw dcf input conversion */ 95 pps_rawdcf, /* examining PPS information */ 96 0, /* no private configuration data */ 97 "RAW DCF77 Timecode", /* direct decoding / time synthesis */ 98 99 61, /* bit buffer */ 100 0 /* no private data (currently in input buffer) */ 101 }; 102 103 static struct dcfparam 104 { 105 unsigned char onebits[60]; 106 unsigned char zerobits[60]; 107 } dcfparameter = 108 { 109 "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */ 110 "--------------------s-------p------p----------------------p" /* 'ZERO' representation */ 111 }; 112 113 static struct rawdcfcode 114 { 115 char offset; /* start bit */ 116 } rawdcfcode[] = 117 { 118 { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 }, 119 { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 } 120 }; 121 122 #define DCF_M 0 123 #define DCF_R 1 124 #define DCF_A1 2 125 #define DCF_Z 3 126 #define DCF_A2 4 127 #define DCF_S 5 128 #define DCF_M1 6 129 #define DCF_M10 7 130 #define DCF_P1 8 131 #define DCF_H1 9 132 #define DCF_H10 10 133 #define DCF_P2 11 134 #define DCF_D1 12 135 #define DCF_D10 13 136 #define DCF_DW 14 137 #define DCF_MO 15 138 #define DCF_MO0 16 139 #define DCF_Y1 17 140 #define DCF_Y10 18 141 #define DCF_P3 19 142 143 static struct partab 144 { 145 char offset; /* start bit of parity field */ 146 } partab[] = 147 { 148 { 21 }, { 29 }, { 36 }, { 59 } 149 }; 150 151 #define DCF_P_P1 0 152 #define DCF_P_P2 1 153 #define DCF_P_P3 2 154 155 #define DCF_Z_MET 0x2 156 #define DCF_Z_MED 0x1 157 158 static u_long 159 ext_bf( 160 register unsigned char *buf, 161 register int idx, 162 register unsigned char *zero 163 ) 164 { 165 register u_long sum = 0; 166 register int i, first; 167 168 first = rawdcfcode[idx].offset; 169 170 for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--) 171 { 172 sum <<= 1; 173 sum |= (buf[i] != zero[i]); 174 } 175 return sum; 176 } 177 178 static unsigned 179 pcheck( 180 unsigned char *buf, 181 int idx, 182 unsigned char *zero 183 ) 184 { 185 int i,last; 186 unsigned psum = 1; 187 188 last = partab[idx+1].offset; 189 190 for (i = partab[idx].offset; i < last; i++) 191 psum ^= (buf[i] != zero[i]); 192 193 return psum; 194 } 195 196 static u_long 197 convert_rawdcf( 198 unsigned char *buffer, 199 int size, 200 struct dcfparam *dcfprm, 201 clocktime_t *clock_time 202 ) 203 { 204 register unsigned char *s = buffer; 205 register unsigned char *b = dcfprm->onebits; 206 register unsigned char *c = dcfprm->zerobits; 207 register int i; 208 209 parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer)); 210 211 if (size < 57) 212 { 213 #ifndef PARSEKERNEL 214 msyslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits\n", size); 215 #endif 216 return CVT_NONE; 217 } 218 219 for (i = 0; i < 58; i++) 220 { 221 if ((*s != *b) && (*s != *c)) 222 { 223 /* 224 * we only have two types of bytes (ones and zeros) 225 */ 226 #ifndef PARSEKERNEL 227 msyslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion for \"%s\"\n", buffer); 228 #endif 229 return CVT_NONE; 230 } 231 b++; 232 c++; 233 s++; 234 } 235 236 /* 237 * check Start and Parity bits 238 */ 239 if ((ext_bf(buffer, DCF_S, dcfprm->zerobits) == 1) && 240 pcheck(buffer, DCF_P_P1, dcfprm->zerobits) && 241 pcheck(buffer, DCF_P_P2, dcfprm->zerobits) && 242 pcheck(buffer, DCF_P_P3, dcfprm->zerobits)) 243 { 244 /* 245 * buffer OK 246 */ 247 parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n")); 248 249 clock_time->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP; 250 clock_time->utctime= 0; 251 clock_time->usecond= 0; 252 clock_time->second = 0; 253 clock_time->minute = ext_bf(buffer, DCF_M10, dcfprm->zerobits); 254 clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1, dcfprm->zerobits); 255 clock_time->hour = ext_bf(buffer, DCF_H10, dcfprm->zerobits); 256 clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1, dcfprm->zerobits); 257 clock_time->day = ext_bf(buffer, DCF_D10, dcfprm->zerobits); 258 clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1, dcfprm->zerobits); 259 clock_time->month = ext_bf(buffer, DCF_MO0, dcfprm->zerobits); 260 clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO, dcfprm->zerobits); 261 clock_time->year = ext_bf(buffer, DCF_Y10, dcfprm->zerobits); 262 clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1, dcfprm->zerobits); 263 264 switch (ext_bf(buffer, DCF_Z, dcfprm->zerobits)) 265 { 266 case DCF_Z_MET: 267 clock_time->utcoffset = -1*60*60; 268 break; 269 270 case DCF_Z_MED: 271 clock_time->flags |= PARSEB_DST; 272 clock_time->utcoffset = -2*60*60; 273 break; 274 275 default: 276 parseprintf(DD_RAWDCF,("parse: convert_rawdcf: BAD TIME ZONE\n")); 277 return CVT_FAIL|CVT_BADFMT; 278 } 279 280 if (ext_bf(buffer, DCF_A1, dcfprm->zerobits)) 281 clock_time->flags |= PARSEB_ANNOUNCE; 282 283 if (ext_bf(buffer, DCF_A2, dcfprm->zerobits)) 284 clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */ 285 286 if (ext_bf(buffer, DCF_R, dcfprm->zerobits)) 287 clock_time->flags |= PARSEB_ALTERNATE; 288 289 parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%lx\n", 290 (int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year, 291 (u_long)clock_time->flags)); 292 return CVT_OK; 293 } 294 else 295 { 296 /* 297 * bad format - not for us 298 */ 299 #ifndef PARSEKERNEL 300 msyslog(LOG_ERR, "parse: convert_rawdcf: parity check FAILED for \"%s\"\n", buffer); 301 #endif 302 return CVT_FAIL|CVT_BADFMT; 303 } 304 } 305 306 /* 307 * raw dcf input routine - needs to fix up 50 baud 308 * characters for 1/0 decision 309 */ 310 static u_long 311 cvt_rawdcf( 312 unsigned char *buffer, 313 int size, 314 struct format *param, 315 clocktime_t *clock_time, 316 void *local 317 ) 318 { 319 register unsigned char *s = (unsigned char *)buffer; 320 register unsigned char *e = s + size; 321 register unsigned char *b = dcfparameter.onebits; 322 register unsigned char *c = dcfparameter.zerobits; 323 register unsigned rtc = CVT_NONE; 324 register unsigned int i, lowmax, highmax, cutoff, span; 325 #define BITS 9 326 unsigned char histbuf[BITS]; 327 /* 328 * the input buffer contains characters with runs of consecutive 329 * bits set. These set bits are an indication of the DCF77 pulse 330 * length. We assume that we receive the pulse at 50 Baud. Thus 331 * a 100ms pulse would generate a 4 bit train (20ms per bit and 332 * start bit) 333 * a 200ms pulse would create all zeroes (and probably a frame error) 334 */ 335 336 for (i = 0; i < BITS; i++) 337 { 338 histbuf[i] = 0; 339 } 340 341 cutoff = 0; 342 lowmax = 0; 343 344 while (s < e) 345 { 346 register unsigned int ch = *s ^ 0xFF; 347 /* 348 * these lines are left as an excercise to the reader 8-) 349 */ 350 if (!((ch+1) & ch) || !*s) 351 { 352 353 for (i = 0; ch; i++) 354 { 355 ch >>= 1; 356 } 357 358 *s = i; 359 histbuf[i]++; 360 cutoff += i; 361 lowmax++; 362 } 363 else 364 { 365 parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, (int)(s - (unsigned char *)buffer))); 366 *s = (unsigned char)~0; 367 rtc = CVT_FAIL|CVT_BADFMT; 368 } 369 s++; 370 } 371 372 if (lowmax) 373 { 374 cutoff /= lowmax; 375 } 376 else 377 { 378 cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */ 379 } 380 381 parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: average bit count: %d\n", cutoff)); 382 383 lowmax = 0; 384 highmax = 0; 385 386 parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: histogram:")); 387 for (i = 0; i <= cutoff; i++) 388 { 389 lowmax+=histbuf[i] * i; 390 highmax += histbuf[i]; 391 parseprintf(DD_RAWDCF,(" %d", histbuf[i])); 392 } 393 parseprintf(DD_RAWDCF, (" <M>")); 394 395 lowmax += highmax / 2; 396 397 if (highmax) 398 { 399 lowmax /= highmax; 400 } 401 else 402 { 403 lowmax = 0; 404 } 405 406 highmax = 0; 407 cutoff = 0; 408 409 for (; i < BITS; i++) 410 { 411 highmax+=histbuf[i] * i; 412 cutoff +=histbuf[i]; 413 parseprintf(DD_RAWDCF,(" %d", histbuf[i])); 414 } 415 parseprintf(DD_RAWDCF,("\n")); 416 417 if (cutoff) 418 { 419 highmax /= cutoff; 420 } 421 else 422 { 423 highmax = BITS-1; 424 } 425 426 span = cutoff = lowmax; 427 for (i = lowmax; i <= highmax; i++) 428 { 429 if (histbuf[cutoff] > histbuf[i]) 430 { 431 cutoff = i; 432 span = i; 433 } 434 else 435 if (histbuf[cutoff] == histbuf[i]) 436 { 437 span = i; 438 } 439 } 440 441 cutoff = (cutoff + span) / 2; 442 443 parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff)); 444 445 s = (unsigned char *)buffer; 446 while ((s < e) && *c && *b) 447 { 448 if (*s == (unsigned char)~0) 449 { 450 *s = '?'; 451 } 452 else 453 { 454 *s = (*s >= cutoff) ? *b : *c; 455 } 456 s++; 457 b++; 458 c++; 459 } 460 461 return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, &dcfparameter, clock_time) : rtc; 462 } 463 464 /* 465 * pps_rawdcf 466 * 467 * currently a very stupid version - should be extended to decode 468 * also ones and zeros (which is easy) 469 */ 470 /*ARGSUSED*/ 471 static u_long 472 pps_rawdcf( 473 register parse_t *parseio, 474 register int status, 475 register timestamp_t *ptime 476 ) 477 { 478 if (!status) /* negative edge for simpler wiring (Rx->DCD) */ 479 { 480 parseio->parse_dtime.parse_ptime = *ptime; 481 parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 482 } 483 484 return CVT_NONE; 485 } 486 487 static u_long 488 snt_rawdcf( 489 register parse_t *parseio, 490 register timestamp_t *ptime 491 ) 492 { 493 if ((parseio->parse_dtime.parse_status & CVT_MASK) == CVT_OK) 494 { 495 parseio->parse_dtime.parse_stime = *ptime; 496 497 #ifdef PARSEKERNEL 498 parseio->parse_dtime.parse_time.tv.tv_sec++; 499 #else 500 parseio->parse_dtime.parse_time.fp.l_ui++; 501 #endif 502 503 parseprintf(DD_RAWDCF,("parse: snt_rawdcf: time stamp synthesized offset %d seconds\n", parseio->parse_index - 1)); 504 505 return updatetimeinfo(parseio, parseio->parse_lstate); 506 } 507 return CVT_NONE; 508 } 509 510 /* 511 * inp_rawdcf 512 * 513 * grep DCF77 data from input stream 514 */ 515 static u_long 516 inp_rawdcf( 517 parse_t *parseio, 518 unsigned int ch, 519 timestamp_t *tstamp 520 ) 521 { 522 static struct timeval timeout = { 1, 500000 }; /* 1.5 secongs denote second #60 */ 523 524 parseprintf(DD_PARSE, ("inp_rawdcf(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); 525 526 parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ 527 528 if (parse_timedout(parseio, tstamp, &timeout)) 529 { 530 parseprintf(DD_PARSE, ("inp_rawdcf: time out seen\n")); 531 532 (void) parse_end(parseio); 533 (void) parse_addchar(parseio, ch); 534 return PARSE_INP_TIME; 535 } 536 else 537 { 538 unsigned int rtc; 539 540 rtc = parse_addchar(parseio, ch); 541 if (rtc == PARSE_INP_SKIP) 542 { 543 if (snt_rawdcf(parseio, tstamp) == CVT_OK) 544 return PARSE_INP_SYNTH; 545 } 546 return rtc; 547 } 548 } 549 550 #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RAWDCF) */ 551 int clk_rawdcf_bs; 552 #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RAWDCF) */ 553 554 /* 555 * History: 556 * 557 * clk_rawdcf.c,v 558 * Revision 4.6 1998/06/14 21:09:37 kardel 559 * Sun acc cleanup 560 * 561 * Revision 4.5 1998/06/13 12:04:16 kardel 562 * fix SYSV clock name clash 563 * 564 * Revision 4.4 1998/06/12 15:22:28 kardel 565 * fix prototypes 566 * 567 * Revision 4.3 1998/06/06 18:33:36 kardel 568 * simplified condidional compile expression 569 * 570 * Revision 4.2 1998/05/24 11:04:18 kardel 571 * triggering PPS on negative edge for simpler wiring (Rx->DCD) 572 * 573 * Revision 4.1 1998/05/24 09:39:53 kardel 574 * implementation of the new IO handling model 575 * 576 * Revision 4.0 1998/04/10 19:45:30 kardel 577 * Start 4.0 release version numbering 578 * 579 * from V3 3.24 log info deleted 1998/04/11 kardel 580 * 581 */ 582