diff options
author | Marc Balmer <mbalmer@cvs.openbsd.org> | 2006-12-05 15:23:17 +0000 |
---|---|---|
committer | Marc Balmer <mbalmer@cvs.openbsd.org> | 2006-12-05 15:23:17 +0000 |
commit | b54934720012c4f065af94644f14dda05804a447 (patch) | |
tree | 4be0b5310bfd36fb81c3f04c2636b070d55b8415 | |
parent | 4908fe2c7e4a596aa9c53fa806fe7b1f7695990d (diff) |
Add code to detect (and eliminate) statistical outliers. Tested by me and
naddy; many thanks to naddy for continous testing and feedback during the
last weeks.
ok naddy
-rw-r--r-- | sys/dev/usb/udcf.c | 105 |
1 files changed, 87 insertions, 18 deletions
diff --git a/sys/dev/usb/udcf.c b/sys/dev/usb/udcf.c index 6c1431d64fc..68c43152e48 100644 --- a/sys/dev/usb/udcf.c +++ b/sys/dev/usb/udcf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udcf.c,v 1.21 2006/11/15 07:10:14 mbalmer Exp $ */ +/* $OpenBSD: udcf.c,v 1.22 2006/12/05 15:23:16 mbalmer Exp $ */ /* * Copyright (c) 2006 Marc Balmer <mbalmer@openbsd.org> @@ -52,6 +52,9 @@ int udcfdebug = 0; #define DPERIOD1 ((long) 5 * 60) /* degrade OK -> WARN */ #define DPERIOD2 ((long) 15 * 60) /* degrade WARN -> CRIT */ +/* skew tolerance of received time diff vs. measured time diff in percent. */ +#define SKEW_TOLERANCE 5 + #define CLOCK_DCF77 0 #define CLOCK_HBG 1 @@ -90,10 +93,15 @@ struct udcf_softc { int sc_level; time_t sc_last_mg; - time_t sc_current; /* current time information */ + time_t sc_current; /* current time */ time_t sc_next; /* time to become valid next */ - + time_t sc_last; + int sc_nrecv; /* consecutive valid times */ + struct timeval sc_last_tv; /* uptime of last valid time */ struct sensor sc_sensor; +#ifdef UDCF_DEBUG + struct sensor sc_skew; /* recv vs local skew */ +#endif }; /* @@ -182,6 +190,9 @@ USB_ATTACH(udcf) sc->sc_current = 0L; sc->sc_next = 0L; + sc->sc_nrecv = 0; + sc->sc_last = 0L; + sc->sc_last_tv.tv_sec = 0L; strlcpy(sc->sc_sensor.device, USBDEVNAME(sc->sc_dev), sizeof(sc->sc_sensor.device)); @@ -191,7 +202,17 @@ USB_ATTACH(udcf) sc->sc_sensor.flags = 0; strlcpy(sc->sc_sensor.desc, "Unknown", sizeof(sc->sc_sensor.desc)); sensor_add(&sc->sc_sensor); - +#ifdef UDCF_DEBUG + strlcpy(sc->sc_skew.device, USBDEVNAME(sc->sc_dev), + sizeof(sc->sc_skew.device)); + sc->sc_skew.type = SENSOR_TIMEDELTA; + sc->sc_skew.status = SENSOR_S_UNKNOWN; + sc->sc_skew.value = 0LL; + sc->sc_skew.flags = 0; + strlcpy(sc->sc_skew.desc, "local clock skew", + sizeof(sc->sc_skew.desc)); + sensor_add(&sc->sc_skew); +#endif /* Prepare the USB request to probe the value */ sc->sc_req.bmRequestType = UDCF_READ_REQ; sc->sc_req.bRequest = 1; @@ -300,7 +321,9 @@ USB_DETACH(udcf) /* Unregister the clock with the kernel */ sensor_del(&sc->sc_sensor); - +#ifdef UDCF_DEBUG + sensor_del(&sc->sc_skew); +#endif usb_rem_task(sc->sc_udev, &sc->sc_task); usb_rem_task(sc->sc_udev, &sc->sc_bv_task); usb_rem_task(sc->sc_udev, &sc->sc_mg_task); @@ -422,8 +445,6 @@ udcf_probe(void *xsc) */ timeout_add(&sc->sc_it_to, t_warn); } - sc->sc_tbits = 0LL; - sc->sc_mask = 1LL; sc->sc_minute = 0; } @@ -473,6 +494,9 @@ udcf_mg_probe(void *xsc) struct udcf_softc *sc = xsc; struct clock_ymdhms ymdhm; + struct timeval monotime; + int tdiff_recv, tdiff_local; + int skew; int minute_bits, hour_bits, day_bits; int month_bits, year_bits, wday; int p1, p2, p3; @@ -483,19 +507,19 @@ udcf_mg_probe(void *xsc) u_int32_t parity = 0x6996; if (sc->sc_sync) { - timeout_add(&sc->sc_to, t_mgsync); /* re-sync in 450 ms */ sc->sc_minute = 1; - sc->sc_last_mg = time_second; - return; + goto cleanbits; } if (time_second - sc->sc_last_mg < 57) { - DPRINTF(("unexpected gap, resync\n")); + DPRINTF(("\nunexpected gap, resync\n")); sc->sc_sync = 1; +#if 0 timeout_add(&sc->sc_to, t_wait); timeout_add(&sc->sc_sl_to, t_wait + t_sl); sc->sc_last_mg = 0; - return; +#endif + goto cleanbits; } /* Extract bits w/o parity */ @@ -534,33 +558,76 @@ udcf_mg_probe(void *xsc) if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit && p3 == p3_bit && (z1_bit ^ z2_bit)) { - /* Decode valid time */ + /* Decode time */ + if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)) > 2037) { + DPRINTF(("year out of range, resync\n")); + sc->sc_sync = 1; + goto cleanbits; + } ymdhm.dt_min = FROMBCD(minute_bits); ymdhm.dt_hour = FROMBCD(hour_bits); ymdhm.dt_day = FROMBCD(day_bits); ymdhm.dt_mon = FROMBCD(month_bits); - ymdhm.dt_year = 2000 + FROMBCD(year_bits); ymdhm.dt_sec = 0; sc->sc_next = clock_ymdhms_to_secs(&ymdhm); + getmicrouptime(&monotime); /* convert to coordinated universal time */ sc->sc_next -= z1_bit ? 7200 : 3600; DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s", - ymdhm.dt_day, ymdhm.dt_mon + 1, ymdhm.dt_year, + ymdhm.dt_day, ymdhm.dt_mon, ymdhm.dt_year, ymdhm.dt_hour, ymdhm.dt_min, z1_bit ? "CEST" : "CET")); DPRINTF((r_bit ? ", reserve antenna" : "")); DPRINTF((a1_bit ? ", dst chg ann." : "")); DPRINTF((a2_bit ? ", leap sec ann." : "")); DPRINTF(("\n")); + + if (sc->sc_last) { + tdiff_recv = sc->sc_next - sc->sc_last; + tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec; + skew = abs(tdiff_local - tdiff_recv); +#ifdef UDCF_DEBUG + if (sc->sc_skew.status == SENSOR_S_UNKNOWN) + sc->sc_skew.status = SENSOR_S_CRIT; + sc->sc_skew.value = skew * 1000000000LL; + getmicrotime(&sc->sc_skew.tv); +#endif + DPRINTF(("local = %d, recv = %d, skew = %d\n", + tdiff_local, tdiff_recv, skew)); + + if (skew * 100LL / tdiff_local > SKEW_TOLERANCE) { + DPRINTF(("skew out of tolerated range\n")); + goto cleanbits; + } else { + if (sc->sc_nrecv < 2) { + sc->sc_nrecv++; + DPRINTF(("got frame %d\n", + sc->sc_nrecv)); + } else { + DPRINTF(("data is valid\n")); + sc->sc_minute = 1; + } + } + } else { + DPRINTF(("received the first frame\n")); + sc->sc_nrecv = 1; + } + + /* record the time received and when it was received */ + sc->sc_last = sc->sc_next; + sc->sc_last_tv.tv_sec = monotime.tv_sec; } else { - DPRINTF(("parity error, resync\n")); + DPRINTF(("\nparity error, resync\n")); sc->sc_sync = 1; } + +cleanbits: timeout_add(&sc->sc_to, t_mgsync); /* re-sync in 450 ms */ - sc->sc_minute = 1; sc->sc_last_mg = time_second; + sc->sc_tbits = 0LL; + sc->sc_mask = 1LL; } /* detect signal loss */ @@ -596,8 +663,10 @@ udcf_it_probe(void *xsc) * time information */ timeout_add(&sc->sc_it_to, t_crit); - } else + } else { sc->sc_sensor.status = SENSOR_S_CRIT; + sc->sc_nrecv = 0; + } } /* detect clock type */ |