1 /* $OpenBSD: gpiodcf.c,v 1.1 2008/11/28 17:42:43 mbalmer Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/kernel.h> 22 #include <sys/conf.h> 23 #include <sys/file.h> 24 #include <sys/select.h> 25 #include <sys/proc.h> 26 #include <sys/vnode.h> 27 #include <sys/device.h> 28 #include <sys/poll.h> 29 #include <sys/time.h> 30 #include <sys/sensors.h> 31 #include <sys/gpio.h> 32 33 #include <dev/gpio/gpiovar.h> 34 35 #ifdef GPIODCF_DEBUG 36 #define DPRINTFN(n, x) do { if (gpiodcfdebug > (n)) printf x; } while (0) 37 int gpiodcfdebug = 0; 38 #else 39 #define DPRINTFN(n, x) 40 #endif 41 #define DPRINTF(x) DPRINTFN(0, x) 42 43 #define DPERIOD1 ((long) 5 * 60) /* degrade OK -> WARN */ 44 #define DPERIOD2 ((long) 15 * 60) /* degrade WARN -> CRIT */ 45 46 /* max. skew of received time diff vs. measured time diff in percent. */ 47 #define MAX_SKEW 5 48 49 #define CLOCK_DCF77 0 50 #define CLOCK_HBG 1 51 52 #define GPIODCF_NPINS 1 53 #define GPIODCF_PIN_DATA 0 54 55 static const char *clockname[2] = { 56 "DCF77", 57 "HBG" }; 58 59 struct gpiodcf_softc { 60 struct device sc_dev; /* base device */ 61 void *sc_gpio; 62 struct gpio_pinmap sc_map; 63 int __map[GPIODCF_NPINS]; 64 u_char sc_dying; /* disconnecting */ 65 int sc_data; 66 67 struct timeout sc_to; 68 69 struct timeout sc_bv_to; /* bit-value detect */ 70 struct timeout sc_db_to; /* debounce */ 71 struct timeout sc_mg_to; /* minute-gap detect */ 72 struct timeout sc_sl_to; /* signal-loss detect */ 73 struct timeout sc_it_to; /* invalidate time */ 74 struct timeout sc_ct_to; /* detect clock type */ 75 76 int sc_detect_ct; /* != 0: autodetect type */ 77 int sc_clocktype; /* DCF77 or HBG */ 78 int sc_sync; /* 1 during sync */ 79 u_int64_t sc_mask; /* 64 bit mask */ 80 u_int64_t sc_tbits; /* Time bits */ 81 int sc_minute; 82 int sc_level; 83 time_t sc_last_mg; 84 time_t sc_current; /* current time */ 85 time_t sc_next; /* time to become valid next */ 86 time_t sc_last; 87 int sc_nrecv; /* consecutive valid times */ 88 struct timeval sc_last_tv; /* uptime of last valid time */ 89 struct ksensor sc_sensor; 90 #ifdef GPIODCF_DEBUG 91 struct ksensor sc_skew; /* recv vs local skew */ 92 #endif 93 struct ksensordev sc_sensordev; 94 }; 95 96 /* 97 * timeouts being used in hz: 98 * t_bv bit value detection (150ms) 99 * t_ct detect clocktype (250ms) 100 * t_sync sync (950ms) 101 * t_mg minute gap detection (1500ms) 102 * t_mgsync resync after a minute gap (450ms) 103 * t_sl detect signal loss (3sec) 104 * t_wait wait (5sec) 105 * t_warn degrade sensor status to warning (5min) 106 * t_crit degrade sensor status to critical (15min) 107 */ 108 static int t_bv, t_ct, t_sync, t_mg, t_sl, t_mgsync, t_wait, t_warn, t_crit; 109 110 void gpiodcf_intr(void *); 111 void gpiodcf_probe(void *); 112 void gpiodcf_bv_probe(void *); 113 void gpiodcf_mg_probe(void *); 114 void gpiodcf_sl_probe(void *); 115 void gpiodcf_ct_probe(void *); 116 void gpiodcf_invalidate(void *); 117 118 int gpiodcf_match(struct device *, void *, void *); 119 void gpiodcf_attach(struct device *, struct device *, void *); 120 int gpiodcf_detach(struct device *, int); 121 int gpiodcf_activate(struct device *, enum devact); 122 123 int gpiodcf_signal(struct gpiodcf_softc *); 124 125 struct cfdriver gpiodcf_cd = { 126 NULL, "gpiodcf", DV_DULL 127 }; 128 129 const struct cfattach gpiodcf_ca = { 130 sizeof(struct gpiodcf_softc), 131 gpiodcf_match, 132 gpiodcf_attach, 133 gpiodcf_detach, 134 gpiodcf_activate 135 }; 136 137 int 138 gpiodcf_match(struct device *parent, void *match, void *aux) 139 { 140 struct cfdata *cf = match; 141 struct gpio_attach_args *ga = aux; 142 143 if (ga->ga_offset == -1) 144 return 0; 145 146 return (strcmp(cf->cf_driver->cd_name, "gpiodcf") == 0); 147 } 148 149 void 150 gpiodcf_attach(struct device *parent, struct device *self, void *aux) 151 { 152 struct gpiodcf_softc *sc = (struct gpiodcf_softc *)self; 153 struct gpio_attach_args *ga = aux; 154 struct timeval t; 155 int caps; 156 157 if (gpio_npins(ga->ga_mask) != GPIODCF_NPINS) { 158 printf(": invalid pin mask\n"); 159 return; 160 } 161 sc->sc_gpio = ga->ga_gpio; 162 sc->sc_map.pm_map = sc->__map; 163 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 164 &sc->sc_map)) { 165 printf(": can't map pins\n"); 166 return; 167 } 168 169 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIODCF_PIN_DATA); 170 if (!(caps & GPIO_PIN_INPUT)) { 171 printf(": data pin is unable to receive input\n"); 172 goto fishy; 173 } 174 printf(": DATA[%d]", sc->sc_map.pm_map[GPIODCF_PIN_DATA]); 175 sc->sc_data = GPIO_PIN_INPUT; 176 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIODCF_PIN_DATA, sc->sc_data); 177 printf("\n"); 178 179 sc->sc_detect_ct = 1; 180 strlcpy(sc->sc_sensor.desc, "Unknown", 181 sizeof(sc->sc_sensor.desc)); 182 183 timeout_set(&sc->sc_to, gpiodcf_probe, sc); 184 timeout_set(&sc->sc_bv_to, gpiodcf_bv_probe, sc); 185 timeout_set(&sc->sc_mg_to, gpiodcf_mg_probe, sc); 186 timeout_set(&sc->sc_sl_to, gpiodcf_sl_probe, sc); 187 timeout_set(&sc->sc_it_to, gpiodcf_invalidate, sc); 188 timeout_set(&sc->sc_ct_to, gpiodcf_ct_probe, sc); 189 190 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 191 sizeof(sc->sc_sensordev.xname)); 192 193 sc->sc_sensor.type = SENSOR_TIMEDELTA; 194 sc->sc_sensor.status = SENSOR_S_UNKNOWN; 195 sc->sc_sensor.value = 0LL; 196 sc->sc_sensor.flags = 0; 197 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 198 199 #ifdef GPIODCF_DEBUG 200 sc->sc_skew.type = SENSOR_TIMEDELTA; 201 sc->sc_skew.status = SENSOR_S_UNKNOWN; 202 sc->sc_skew.value = 0LL; 203 sc->sc_skew.flags = 0; 204 strlcpy(sc->sc_skew.desc, "local clock skew", 205 sizeof(sc->sc_skew.desc)); 206 sensor_attach(&sc->sc_sensordev, &sc->sc_skew); 207 #endif 208 sensordev_install(&sc->sc_sensordev); 209 210 sc->sc_clocktype = -1; 211 sc->sc_level = 0; 212 sc->sc_minute = 0; 213 sc->sc_last_mg = 0L; 214 215 sc->sc_sync = 1; 216 217 sc->sc_current = 0L; 218 sc->sc_next = 0L; 219 sc->sc_nrecv = 0; 220 sc->sc_last = 0L; 221 sc->sc_last_tv.tv_sec = 0L; 222 223 /* convert timevals to hz */ 224 t.tv_sec = 0L; 225 t.tv_usec = 150000L; 226 t_bv = tvtohz(&t); 227 228 t.tv_usec = 450000L; 229 t_mgsync = tvtohz(&t); 230 231 t.tv_usec = 950000L; 232 t_sync = tvtohz(&t); 233 234 t.tv_sec = 1L; 235 t.tv_usec = 500000L; 236 t_mg = tvtohz(&t); 237 238 t.tv_sec = 3L; 239 t.tv_usec = 0L; 240 t_sl = tvtohz(&t); 241 242 t.tv_sec = 5L; 243 t_wait = tvtohz(&t); 244 245 t.tv_sec = DPERIOD1; 246 t_warn = tvtohz(&t); 247 248 t.tv_sec = DPERIOD2; 249 t_crit = tvtohz(&t); 250 251 if (sc->sc_detect_ct) { 252 t.tv_sec = 0L; 253 t.tv_usec = 250000L; 254 t_ct = tvtohz(&t); 255 } 256 257 /* Give the receiver some slack to stabilize */ 258 timeout_add(&sc->sc_to, t_wait); 259 260 /* Detect signal loss */ 261 timeout_add(&sc->sc_sl_to, t_wait + t_sl); 262 263 DPRINTF(("synchronizing\n")); 264 return; 265 266 fishy: 267 DPRINTF(("gpiodcf_attach failed\n")); 268 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 269 sc->sc_dying = 1; 270 } 271 272 int 273 gpiodcf_detach(struct device *self, int flags) 274 { 275 struct gpiodcf_softc *sc = (struct gpiodcf_softc *)self; 276 277 sc->sc_dying = 1; 278 279 timeout_del(&sc->sc_to); 280 timeout_del(&sc->sc_bv_to); 281 timeout_del(&sc->sc_mg_to); 282 timeout_del(&sc->sc_sl_to); 283 timeout_del(&sc->sc_it_to); 284 timeout_del(&sc->sc_ct_to); 285 286 /* Unregister the clock with the kernel */ 287 sensordev_deinstall(&sc->sc_sensordev); 288 289 /* Finally unmap the GPIO pin */ 290 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 291 292 return 0; 293 } 294 295 /* 296 * return 1 during high-power-, 0 during low-power-emission 297 * If bit 0 is set, the transmitter emits at full power. 298 * During the low-power emission we decode a zero bit. 299 */ 300 int 301 gpiodcf_signal(struct gpiodcf_softc *sc) 302 { 303 return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIODCF_PIN_DATA) == 304 GPIO_PIN_HIGH ? 1 : 0); 305 } 306 307 /* gpiodcf_probe runs in a process context. */ 308 void 309 gpiodcf_probe(void *xsc) 310 { 311 struct gpiodcf_softc *sc = xsc; 312 struct timespec now; 313 int data; 314 315 if (sc->sc_dying) 316 return; 317 318 data = gpiodcf_signal(sc); 319 if (data == -1) 320 return; 321 322 if (data) { 323 sc->sc_level = 1; 324 timeout_add(&sc->sc_to, 1); 325 return; 326 } 327 328 if (sc->sc_level == 0) 329 return; 330 331 /* the beginning of a second */ 332 sc->sc_level = 0; 333 if (sc->sc_minute == 1) { 334 if (sc->sc_sync) { 335 DPRINTF(("start collecting bits\n")); 336 sc->sc_sync = 0; 337 if (sc->sc_sensor.status == SENSOR_S_UNKNOWN && 338 sc->sc_detect_ct) 339 sc->sc_clocktype = -1; 340 } else { 341 /* provide the timedelta */ 342 microtime(&sc->sc_sensor.tv); 343 nanotime(&now); 344 sc->sc_current = sc->sc_next; 345 sc->sc_sensor.value = (int64_t)(now.tv_sec - 346 sc->sc_current) * 1000000000LL + now.tv_nsec; 347 348 /* set the clocktype and make sensor valid */ 349 if (sc->sc_sensor.status == SENSOR_S_UNKNOWN && 350 sc->sc_detect_ct) { 351 strlcpy(sc->sc_sensor.desc, sc->sc_clocktype ? 352 clockname[CLOCK_HBG] : 353 clockname[CLOCK_DCF77], 354 sizeof(sc->sc_sensor.desc)); 355 } 356 sc->sc_sensor.status = SENSOR_S_OK; 357 358 /* 359 * if no valid time information is received 360 * during the next 5 minutes, the sensor state 361 * will be degraded to SENSOR_S_WARN 362 */ 363 timeout_add(&sc->sc_it_to, t_warn); 364 } 365 sc->sc_minute = 0; 366 } 367 368 timeout_add(&sc->sc_to, t_sync); /* resync in 950 ms */ 369 370 /* no clock and bit detection during sync */ 371 if (!sc->sc_sync) { 372 /* detect bit value */ 373 timeout_add(&sc->sc_bv_to, t_bv); 374 375 /* detect clocktype */ 376 if (sc->sc_detect_ct && sc->sc_clocktype == -1) 377 timeout_add(&sc->sc_ct_to, t_ct); 378 } 379 timeout_add(&sc->sc_mg_to, t_mg); /* detect minute gap */ 380 timeout_add(&sc->sc_sl_to, t_sl); /* detect signal loss */ 381 } 382 383 /* detect the bit value */ 384 void 385 gpiodcf_bv_probe(void *xsc) 386 { 387 struct gpiodcf_softc *sc = xsc; 388 int data; 389 390 if (sc->sc_dying) 391 return; 392 393 data = gpiodcf_signal(sc); 394 if (data == -1) { 395 DPRINTF(("bit detection failed\n")); 396 return; 397 } 398 399 DPRINTFN(1, (data ? "0" : "1")); 400 if (!(data)) 401 sc->sc_tbits |= sc->sc_mask; 402 sc->sc_mask <<= 1; 403 } 404 405 /* detect the minute gap */ 406 void 407 gpiodcf_mg_probe(void *xsc) 408 { 409 struct gpiodcf_softc *sc = xsc; 410 struct clock_ymdhms ymdhm; 411 struct timeval monotime; 412 int tdiff_recv, tdiff_local; 413 int skew; 414 int minute_bits, hour_bits, day_bits; 415 int month_bits, year_bits, wday; 416 int p1, p2, p3; 417 int p1_bit, p2_bit, p3_bit; 418 int r_bit, a1_bit, a2_bit, z1_bit, z2_bit; 419 int s_bit, m_bit; 420 u_int32_t parity = 0x6996; 421 422 if (sc->sc_sync) { 423 sc->sc_minute = 1; 424 goto cleanbits; 425 } 426 427 if (time_second - sc->sc_last_mg < 57) { 428 DPRINTF(("\nunexpected gap, resync\n")); 429 sc->sc_sync = sc->sc_minute = 1; 430 goto cleanbits; 431 } 432 433 /* extract bits w/o parity */ 434 m_bit = sc->sc_tbits & 1; 435 r_bit = sc->sc_tbits >> 15 & 1; 436 a1_bit = sc->sc_tbits >> 16 & 1; 437 z1_bit = sc->sc_tbits >> 17 & 1; 438 z2_bit = sc->sc_tbits >> 18 & 1; 439 a2_bit = sc->sc_tbits >> 19 & 1; 440 s_bit = sc->sc_tbits >> 20 & 1; 441 p1_bit = sc->sc_tbits >> 28 & 1; 442 p2_bit = sc->sc_tbits >> 35 & 1; 443 p3_bit = sc->sc_tbits >> 58 & 1; 444 445 minute_bits = sc->sc_tbits >> 21 & 0x7f; 446 hour_bits = sc->sc_tbits >> 29 & 0x3f; 447 day_bits = sc->sc_tbits >> 36 & 0x3f; 448 wday = (sc->sc_tbits >> 42) & 0x07; 449 month_bits = sc->sc_tbits >> 45 & 0x1f; 450 year_bits = sc->sc_tbits >> 50 & 0xff; 451 452 /* validate time information */ 453 p1 = (parity >> (minute_bits & 0x0f) & 1) ^ 454 (parity >> (minute_bits >> 4) & 1); 455 456 p2 = (parity >> (hour_bits & 0x0f) & 1) ^ 457 (parity >> (hour_bits >> 4) & 1); 458 459 p3 = (parity >> (day_bits & 0x0f) & 1) ^ 460 (parity >> (day_bits >> 4) & 1) ^ 461 ((parity >> wday) & 1) ^ (parity >> (month_bits & 0x0f) & 1) ^ 462 (parity >> (month_bits >> 4) & 1) ^ 463 (parity >> (year_bits & 0x0f) & 1) ^ 464 (parity >> (year_bits >> 4) & 1); 465 466 if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit && 467 p3 == p3_bit && (z1_bit ^ z2_bit)) { 468 469 /* Decode time */ 470 if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)) > 2037) { 471 DPRINTF(("year out of range, resync\n")); 472 sc->sc_sync = 1; 473 goto cleanbits; 474 } 475 ymdhm.dt_min = FROMBCD(minute_bits); 476 ymdhm.dt_hour = FROMBCD(hour_bits); 477 ymdhm.dt_day = FROMBCD(day_bits); 478 ymdhm.dt_mon = FROMBCD(month_bits); 479 ymdhm.dt_sec = 0; 480 481 sc->sc_next = clock_ymdhms_to_secs(&ymdhm); 482 getmicrouptime(&monotime); 483 484 /* convert to coordinated universal time */ 485 sc->sc_next -= z1_bit ? 7200 : 3600; 486 487 DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s", 488 ymdhm.dt_day, ymdhm.dt_mon, ymdhm.dt_year, 489 ymdhm.dt_hour, ymdhm.dt_min, z1_bit ? "CEST" : "CET")); 490 DPRINTF((r_bit ? ", call bit" : "")); 491 DPRINTF((a1_bit ? ", dst chg ann." : "")); 492 DPRINTF((a2_bit ? ", leap sec ann." : "")); 493 DPRINTF(("\n")); 494 495 if (sc->sc_last) { 496 tdiff_recv = sc->sc_next - sc->sc_last; 497 tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec; 498 skew = abs(tdiff_local - tdiff_recv); 499 #ifdef GPIODCF_DEBUG 500 if (sc->sc_skew.status == SENSOR_S_UNKNOWN) 501 sc->sc_skew.status = SENSOR_S_CRIT; 502 sc->sc_skew.value = skew * 1000000000LL; 503 getmicrotime(&sc->sc_skew.tv); 504 #endif 505 DPRINTF(("local = %d, recv = %d, skew = %d\n", 506 tdiff_local, tdiff_recv, skew)); 507 508 if (skew && skew * 100LL / tdiff_local > MAX_SKEW) { 509 DPRINTF(("skew out of tolerated range\n")); 510 goto cleanbits; 511 } else { 512 if (sc->sc_nrecv < 2) { 513 sc->sc_nrecv++; 514 DPRINTF(("got frame %d\n", 515 sc->sc_nrecv)); 516 } else { 517 DPRINTF(("data is valid\n")); 518 sc->sc_minute = 1; 519 } 520 } 521 } else { 522 DPRINTF(("received the first frame\n")); 523 sc->sc_nrecv = 1; 524 } 525 526 /* record the time received and when it was received */ 527 sc->sc_last = sc->sc_next; 528 sc->sc_last_tv.tv_sec = monotime.tv_sec; 529 } else { 530 DPRINTF(("\nparity error, resync\n")); 531 sc->sc_sync = sc->sc_minute = 1; 532 } 533 534 cleanbits: 535 timeout_add(&sc->sc_to, t_mgsync); /* re-sync in 450 ms */ 536 sc->sc_last_mg = time_second; 537 sc->sc_tbits = 0LL; 538 sc->sc_mask = 1LL; 539 } 540 541 /* detect signal loss */ 542 void 543 gpiodcf_sl_probe(void *xsc) 544 { 545 struct gpiodcf_softc *sc = xsc; 546 547 if (sc->sc_dying) 548 return; 549 550 DPRINTF(("no signal\n")); 551 sc->sc_sync = 1; 552 timeout_add(&sc->sc_to, t_wait); 553 timeout_add(&sc->sc_sl_to, t_wait + t_sl); 554 } 555 556 /* invalidate timedelta (called in an interrupt context) */ 557 void 558 gpiodcf_invalidate(void *xsc) 559 { 560 struct gpiodcf_softc *sc = xsc; 561 562 if (sc->sc_dying) 563 return; 564 565 if (sc->sc_sensor.status == SENSOR_S_OK) { 566 sc->sc_sensor.status = SENSOR_S_WARN; 567 /* 568 * further degrade in 15 minutes if we dont receive any new 569 * time information 570 */ 571 timeout_add(&sc->sc_it_to, t_crit); 572 } else { 573 sc->sc_sensor.status = SENSOR_S_CRIT; 574 sc->sc_nrecv = 0; 575 } 576 } 577 578 /* detect clock type. used for older devices only. */ 579 void 580 gpiodcf_ct_probe(void *xsc) 581 { 582 struct gpiodcf_softc *sc = xsc; 583 int data; 584 585 if (sc->sc_dying) 586 return; 587 588 data = gpiodcf_signal(sc); 589 if (data == -1) { 590 DPRINTF(("clocktype detection failed\n")); 591 return; 592 } 593 594 sc->sc_clocktype = data ? 0 : 1; 595 DPRINTF(("\nclocktype is %s\n", sc->sc_clocktype ? 596 clockname[CLOCK_HBG] : clockname[CLOCK_DCF77])); 597 } 598 599 int 600 gpiodcf_activate(struct device *self, enum devact act) 601 { 602 struct gpiodcf_softc *sc = (struct gpiodcf_softc *)self; 603 604 switch (act) { 605 case DVACT_ACTIVATE: 606 break; 607 case DVACT_DEACTIVATE: 608 sc->sc_dying = 1; 609 break; 610 } 611 return 0; 612 } 613