summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Balmer <mbalmer@cvs.openbsd.org>2006-12-05 15:23:17 +0000
committerMarc Balmer <mbalmer@cvs.openbsd.org>2006-12-05 15:23:17 +0000
commitb54934720012c4f065af94644f14dda05804a447 (patch)
tree4be0b5310bfd36fb81c3f04c2636b070d55b8415
parent4908fe2c7e4a596aa9c53fa806fe7b1f7695990d (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.c105
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 */