1 /* $OpenBSD: gpiodcf.c,v 1.2 2009/04/26 02:20:58 cnst 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 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 196 197 #ifdef GPIODCF_DEBUG 198 sc->sc_skew.type = SENSOR_TIMEDELTA; 199 sc->sc_skew.status = SENSOR_S_UNKNOWN; 200 strlcpy(sc->sc_skew.desc, "local clock skew", 201 sizeof(sc->sc_skew.desc)); 202 sensor_attach(&sc->sc_sensordev, &sc->sc_skew); 203 #endif 204 sensordev_install(&sc->sc_sensordev); 205 206 sc->sc_clocktype = -1; 207 sc->sc_level = 0; 208 sc->sc_minute = 0; 209 sc->sc_last_mg = 0L; 210 211 sc->sc_sync = 1; 212 213 sc->sc_current = 0L; 214 sc->sc_next = 0L; 215 sc->sc_nrecv = 0; 216 sc->sc_last = 0L; 217 sc->sc_last_tv.tv_sec = 0L; 218 219 /* convert timevals to hz */ 220 t.tv_sec = 0L; 221 t.tv_usec = 150000L; 222 t_bv = tvtohz(&t); 223 224 t.tv_usec = 450000L; 225 t_mgsync = tvtohz(&t); 226 227 t.tv_usec = 950000L; 228 t_sync = tvtohz(&t); 229 230 t.tv_sec = 1L; 231 t.tv_usec = 500000L; 232 t_mg = tvtohz(&t); 233 234 t.tv_sec = 3L; 235 t.tv_usec = 0L; 236 t_sl = tvtohz(&t); 237 238 t.tv_sec = 5L; 239 t_wait = tvtohz(&t); 240 241 t.tv_sec = DPERIOD1; 242 t_warn = tvtohz(&t); 243 244 t.tv_sec = DPERIOD2; 245 t_crit = tvtohz(&t); 246 247 if (sc->sc_detect_ct) { 248 t.tv_sec = 0L; 249 t.tv_usec = 250000L; 250 t_ct = tvtohz(&t); 251 } 252 253 /* Give the receiver some slack to stabilize */ 254 timeout_add(&sc->sc_to, t_wait); 255 256 /* Detect signal loss */ 257 timeout_add(&sc->sc_sl_to, t_wait + t_sl); 258 259 DPRINTF(("synchronizing\n")); 260 return; 261 262 fishy: 263 DPRINTF(("gpiodcf_attach failed\n")); 264 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 265 sc->sc_dying = 1; 266 } 267 268 int 269 gpiodcf_detach(struct device *self, int flags) 270 { 271 struct gpiodcf_softc *sc = (struct gpiodcf_softc *)self; 272 273 sc->sc_dying = 1; 274 275 timeout_del(&sc->sc_to); 276 timeout_del(&sc->sc_bv_to); 277 timeout_del(&sc->sc_mg_to); 278 timeout_del(&sc->sc_sl_to); 279 timeout_del(&sc->sc_it_to); 280 timeout_del(&sc->sc_ct_to); 281 282 /* Unregister the clock with the kernel */ 283 sensordev_deinstall(&sc->sc_sensordev); 284 285 /* Finally unmap the GPIO pin */ 286 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 287 288 return 0; 289 } 290 291 /* 292 * return 1 during high-power-, 0 during low-power-emission 293 * If bit 0 is set, the transmitter emits at full power. 294 * During the low-power emission we decode a zero bit. 295 */ 296 int 297 gpiodcf_signal(struct gpiodcf_softc *sc) 298 { 299 return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIODCF_PIN_DATA) == 300 GPIO_PIN_HIGH ? 1 : 0); 301 } 302 303 /* gpiodcf_probe runs in a process context. */ 304 void 305 gpiodcf_probe(void *xsc) 306 { 307 struct gpiodcf_softc *sc = xsc; 308 struct timespec now; 309 int data; 310 311 if (sc->sc_dying) 312 return; 313 314 data = gpiodcf_signal(sc); 315 if (data == -1) 316 return; 317 318 if (data) { 319 sc->sc_level = 1; 320 timeout_add(&sc->sc_to, 1); 321 return; 322 } 323 324 if (sc->sc_level == 0) 325 return; 326 327 /* the beginning of a second */ 328 sc->sc_level = 0; 329 if (sc->sc_minute == 1) { 330 if (sc->sc_sync) { 331 DPRINTF(("start collecting bits\n")); 332 sc->sc_sync = 0; 333 if (sc->sc_sensor.status == SENSOR_S_UNKNOWN && 334 sc->sc_detect_ct) 335 sc->sc_clocktype = -1; 336 } else { 337 /* provide the timedelta */ 338 microtime(&sc->sc_sensor.tv); 339 nanotime(&now); 340 sc->sc_current = sc->sc_next; 341 sc->sc_sensor.value = (int64_t)(now.tv_sec - 342 sc->sc_current) * 1000000000LL + now.tv_nsec; 343 344 /* set the clocktype and make sensor valid */ 345 if (sc->sc_sensor.status == SENSOR_S_UNKNOWN && 346 sc->sc_detect_ct) { 347 strlcpy(sc->sc_sensor.desc, sc->sc_clocktype ? 348 clockname[CLOCK_HBG] : 349 clockname[CLOCK_DCF77], 350 sizeof(sc->sc_sensor.desc)); 351 } 352 sc->sc_sensor.status = SENSOR_S_OK; 353 354 /* 355 * if no valid time information is received 356 * during the next 5 minutes, the sensor state 357 * will be degraded to SENSOR_S_WARN 358 */ 359 timeout_add(&sc->sc_it_to, t_warn); 360 } 361 sc->sc_minute = 0; 362 } 363 364 timeout_add(&sc->sc_to, t_sync); /* resync in 950 ms */ 365 366 /* no clock and bit detection during sync */ 367 if (!sc->sc_sync) { 368 /* detect bit value */ 369 timeout_add(&sc->sc_bv_to, t_bv); 370 371 /* detect clocktype */ 372 if (sc->sc_detect_ct && sc->sc_clocktype == -1) 373 timeout_add(&sc->sc_ct_to, t_ct); 374 } 375 timeout_add(&sc->sc_mg_to, t_mg); /* detect minute gap */ 376 timeout_add(&sc->sc_sl_to, t_sl); /* detect signal loss */ 377 } 378 379 /* detect the bit value */ 380 void 381 gpiodcf_bv_probe(void *xsc) 382 { 383 struct gpiodcf_softc *sc = xsc; 384 int data; 385 386 if (sc->sc_dying) 387 return; 388 389 data = gpiodcf_signal(sc); 390 if (data == -1) { 391 DPRINTF(("bit detection failed\n")); 392 return; 393 } 394 395 DPRINTFN(1, (data ? "0" : "1")); 396 if (!(data)) 397 sc->sc_tbits |= sc->sc_mask; 398 sc->sc_mask <<= 1; 399 } 400 401 /* detect the minute gap */ 402 void 403 gpiodcf_mg_probe(void *xsc) 404 { 405 struct gpiodcf_softc *sc = xsc; 406 struct clock_ymdhms ymdhm; 407 struct timeval monotime; 408 int tdiff_recv, tdiff_local; 409 int skew; 410 int minute_bits, hour_bits, day_bits; 411 int month_bits, year_bits, wday; 412 int p1, p2, p3; 413 int p1_bit, p2_bit, p3_bit; 414 int r_bit, a1_bit, a2_bit, z1_bit, z2_bit; 415 int s_bit, m_bit; 416 u_int32_t parity = 0x6996; 417 418 if (sc->sc_sync) { 419 sc->sc_minute = 1; 420 goto cleanbits; 421 } 422 423 if (time_second - sc->sc_last_mg < 57) { 424 DPRINTF(("\nunexpected gap, resync\n")); 425 sc->sc_sync = sc->sc_minute = 1; 426 goto cleanbits; 427 } 428 429 /* extract bits w/o parity */ 430 m_bit = sc->sc_tbits & 1; 431 r_bit = sc->sc_tbits >> 15 & 1; 432 a1_bit = sc->sc_tbits >> 16 & 1; 433 z1_bit = sc->sc_tbits >> 17 & 1; 434 z2_bit = sc->sc_tbits >> 18 & 1; 435 a2_bit = sc->sc_tbits >> 19 & 1; 436 s_bit = sc->sc_tbits >> 20 & 1; 437 p1_bit = sc->sc_tbits >> 28 & 1; 438 p2_bit = sc->sc_tbits >> 35 & 1; 439 p3_bit = sc->sc_tbits >> 58 & 1; 440 441 minute_bits = sc->sc_tbits >> 21 & 0x7f; 442 hour_bits = sc->sc_tbits >> 29 & 0x3f; 443 day_bits = sc->sc_tbits >> 36 & 0x3f; 444 wday = (sc->sc_tbits >> 42) & 0x07; 445 month_bits = sc->sc_tbits >> 45 & 0x1f; 446 year_bits = sc->sc_tbits >> 50 & 0xff; 447 448 /* validate time information */ 449 p1 = (parity >> (minute_bits & 0x0f) & 1) ^ 450 (parity >> (minute_bits >> 4) & 1); 451 452 p2 = (parity >> (hour_bits & 0x0f) & 1) ^ 453 (parity >> (hour_bits >> 4) & 1); 454 455 p3 = (parity >> (day_bits & 0x0f) & 1) ^ 456 (parity >> (day_bits >> 4) & 1) ^ 457 ((parity >> wday) & 1) ^ (parity >> (month_bits & 0x0f) & 1) ^ 458 (parity >> (month_bits >> 4) & 1) ^ 459 (parity >> (year_bits & 0x0f) & 1) ^ 460 (parity >> (year_bits >> 4) & 1); 461 462 if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit && 463 p3 == p3_bit && (z1_bit ^ z2_bit)) { 464 465 /* Decode time */ 466 if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)) > 2037) { 467 DPRINTF(("year out of range, resync\n")); 468 sc->sc_sync = 1; 469 goto cleanbits; 470 } 471 ymdhm.dt_min = FROMBCD(minute_bits); 472 ymdhm.dt_hour = FROMBCD(hour_bits); 473 ymdhm.dt_day = FROMBCD(day_bits); 474 ymdhm.dt_mon = FROMBCD(month_bits); 475 ymdhm.dt_sec = 0; 476 477 sc->sc_next = clock_ymdhms_to_secs(&ymdhm); 478 getmicrouptime(&monotime); 479 480 /* convert to coordinated universal time */ 481 sc->sc_next -= z1_bit ? 7200 : 3600; 482 483 DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s", 484 ymdhm.dt_day, ymdhm.dt_mon, ymdhm.dt_year, 485 ymdhm.dt_hour, ymdhm.dt_min, z1_bit ? "CEST" : "CET")); 486 DPRINTF((r_bit ? ", call bit" : "")); 487 DPRINTF((a1_bit ? ", dst chg ann." : "")); 488 DPRINTF((a2_bit ? ", leap sec ann." : "")); 489 DPRINTF(("\n")); 490 491 if (sc->sc_last) { 492 tdiff_recv = sc->sc_next - sc->sc_last; 493 tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec; 494 skew = abs(tdiff_local - tdiff_recv); 495 #ifdef GPIODCF_DEBUG 496 if (sc->sc_skew.status == SENSOR_S_UNKNOWN) 497 sc->sc_skew.status = SENSOR_S_CRIT; 498 sc->sc_skew.value = skew * 1000000000LL; 499 getmicrotime(&sc->sc_skew.tv); 500 #endif 501 DPRINTF(("local = %d, recv = %d, skew = %d\n", 502 tdiff_local, tdiff_recv, skew)); 503 504 if (skew && skew * 100LL / tdiff_local > MAX_SKEW) { 505 DPRINTF(("skew out of tolerated range\n")); 506 goto cleanbits; 507 } else { 508 if (sc->sc_nrecv < 2) { 509 sc->sc_nrecv++; 510 DPRINTF(("got frame %d\n", 511 sc->sc_nrecv)); 512 } else { 513 DPRINTF(("data is valid\n")); 514 sc->sc_minute = 1; 515 } 516 } 517 } else { 518 DPRINTF(("received the first frame\n")); 519 sc->sc_nrecv = 1; 520 } 521 522 /* record the time received and when it was received */ 523 sc->sc_last = sc->sc_next; 524 sc->sc_last_tv.tv_sec = monotime.tv_sec; 525 } else { 526 DPRINTF(("\nparity error, resync\n")); 527 sc->sc_sync = sc->sc_minute = 1; 528 } 529 530 cleanbits: 531 timeout_add(&sc->sc_to, t_mgsync); /* re-sync in 450 ms */ 532 sc->sc_last_mg = time_second; 533 sc->sc_tbits = 0LL; 534 sc->sc_mask = 1LL; 535 } 536 537 /* detect signal loss */ 538 void 539 gpiodcf_sl_probe(void *xsc) 540 { 541 struct gpiodcf_softc *sc = xsc; 542 543 if (sc->sc_dying) 544 return; 545 546 DPRINTF(("no signal\n")); 547 sc->sc_sync = 1; 548 timeout_add(&sc->sc_to, t_wait); 549 timeout_add(&sc->sc_sl_to, t_wait + t_sl); 550 } 551 552 /* invalidate timedelta (called in an interrupt context) */ 553 void 554 gpiodcf_invalidate(void *xsc) 555 { 556 struct gpiodcf_softc *sc = xsc; 557 558 if (sc->sc_dying) 559 return; 560 561 if (sc->sc_sensor.status == SENSOR_S_OK) { 562 sc->sc_sensor.status = SENSOR_S_WARN; 563 /* 564 * further degrade in 15 minutes if we dont receive any new 565 * time information 566 */ 567 timeout_add(&sc->sc_it_to, t_crit); 568 } else { 569 sc->sc_sensor.status = SENSOR_S_CRIT; 570 sc->sc_nrecv = 0; 571 } 572 } 573 574 /* detect clock type. used for older devices only. */ 575 void 576 gpiodcf_ct_probe(void *xsc) 577 { 578 struct gpiodcf_softc *sc = xsc; 579 int data; 580 581 if (sc->sc_dying) 582 return; 583 584 data = gpiodcf_signal(sc); 585 if (data == -1) { 586 DPRINTF(("clocktype detection failed\n")); 587 return; 588 } 589 590 sc->sc_clocktype = data ? 0 : 1; 591 DPRINTF(("\nclocktype is %s\n", sc->sc_clocktype ? 592 clockname[CLOCK_HBG] : clockname[CLOCK_DCF77])); 593 } 594 595 int 596 gpiodcf_activate(struct device *self, enum devact act) 597 { 598 struct gpiodcf_softc *sc = (struct gpiodcf_softc *)self; 599 600 switch (act) { 601 case DVACT_ACTIVATE: 602 break; 603 case DVACT_DEACTIVATE: 604 sc->sc_dying = 1; 605 break; 606 } 607 return 0; 608 } 609