Add firmware for the ATUSB IEEE 802.15.4 USB Adapter
[linux-libre-firmware.git] / atusb / an / dec.py
diff --git a/atusb/an/dec.py b/atusb/an/dec.py
new file mode 100755 (executable)
index 0000000..8534857
--- /dev/null
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+
+from tmc.wave import *
+from tmc.dxplore import dxplore
+from tmc.decode import d_usb_stream
+
+
+#
+# Clock recovery: we assume that each change in the wave is triggered by a
+# clock edge. We know the clock's nominal period and resynchronize on each
+# edge. Additionally, we can obtain a list of times when a timing violation
+# has occurred.
+#
+# Note that the timing violations logic doesn't make much sense in its present
+# form, since it mainly measures noise (particularly if we're digitizing slow
+# edges) and not clock drift.
+#
+# A more useful metric would be accumulated error from some point of reference
+# or at least the timing of same edges, to eliminate (generally harmless) time
+# offsets introduced by digitizing.
+#
+# So it would probably make more sense for "recover" not to check for timing
+# violations at all, and leave this to more specialized functions.
+#
+def recover(self, period, min = None, max = None, t0 = None):
+    if t0 is None:
+       t0 = self.data[0]
+    v = not self.initial
+    res = []
+    violations = []
+    for t in self.data:
+       v = not v
+       if t <= t0:
+           continue
+       n = 0
+       while t0 < t-period/2:
+           res.append(t0)
+           t0 += period
+           n += 1
+       if min is not None:
+           if t0-t > n*min:
+               violations.append(t)
+       if max is not None:
+           if t-t0 > n*max:
+               violations.append(t)
+       t0 = t
+    return res, violations
+
+
+#
+# Load the analog waves saved by get.py
+#
+wv = waves()
+wv.load("_wv")
+
+#
+# Digitize the waves and save the result.
+#
+dp = wv[0].digitize(1.5, 1.8)
+dm = wv[1].digitize(1.5, 1.8)
+wv = waves(dp, dm, dp-dm)
+wv.save("_dig")
+
+#
+# Also record the differential signal.
+#
+wd = wv[1]-wv[0]
+dd = wd.digitize(-0.5, 0.5)
+wd.save("_diff")
+
+#
+# Run clock recovery on D+/D-. We only need one, but check both to be sure.
+#
+#p = 1/1.5e6
+p = 1/12e6
+dp_t, viol = recover(dp, p, p*0.9, p*1.1)
+print viol
+dm_t, viol = recover(dm, p, p*.9, p*1.1, t0 = dp.data[0])
+print viol
+
+#
+# Shift the clock by half a period, add a few periods to get steady state and
+# SE0s (if any), and then sample the data lines.
+#
+clk = map(lambda t: t+p/2, dp_t)
+clk.extend((clk[-1]+p, clk[-1]+2*p, clk[-1]+3*p))
+dp_bv = dp.get(clk)
+dm_bv = dm.get(clk)
+
+#
+# Save a wave with the recovered clock to make it easier to find the bits in
+# analog graphs.
+#
+dd.data = dp_t;
+dd.save("_clk")
+
+#
+# For decoding, we need a fake bit clock. We generate it by doubling each data
+# bit and generating a L->H transition during this bit.
+#
+dpd = []
+dmd = []
+dck = []
+
+# err, silly, seems that we've mixed up D+ and D- all over the place :-)
+print d_usb_stream(dm_bv[:], dp_bv[:])
+
+for v in dp_bv:
+    dpd.append(v)
+    dpd.append(v)
+    dck.append(0)
+    dck.append(1)
+
+for v in dm_bv:
+    dmd.append(v)
+    dmd.append(v)
+
+#
+# Display the reconstructed digital signal. Note that the absolute time is only
+# correct at the beginning and that relative time is only accurate over
+# intervals in which no significant clock resynchronization has occurred.
+#
+# In fact, dxplore should probably have an option to either turn off time
+# entirely or to display a user-provided time axis. The latter may be a bit
+# tricky to implement.
+#
+dxplore((dmd, dpd, dck), 0, p/2, labels = ("D+", "D-", "CLK"))