r4646 - in developers/werner/ahrt/host/tmc: . demo lib
werner at docs.openmoko.org
werner at docs.openmoko.org
Tue Sep 16 02:11:18 CEST 2008
Author: werner
Date: 2008-09-16 02:11:17 +0200 (Tue, 16 Sep 2008)
New Revision: 4646
Added:
developers/werner/ahrt/host/tmc/lib/decode.py
developers/werner/ahrt/host/tmc/lib/dplore.py
Modified:
developers/werner/ahrt/host/tmc/README
developers/werner/ahrt/host/tmc/demo/dplore.py
developers/werner/ahrt/host/tmc/lib/trigger.py
developers/werner/ahrt/host/tmc/lib/wave.py
developers/werner/ahrt/host/tmc/setup.py
Log:
Mainly dplore restructuring and making it useful in real life.
Highlights:
- fixed a few stupid bugs that made dplore painfully slow
- split dplore.py into components and prepared the SDIO command decoder for
batch processing
- added measurements and zoom
- lots of digitizing and sampling fixes
Details:
- demo/dplore.py (channel.__init__): draw waveforms as single polyline and
omit redundant segments
- demo/dplore.py (d_sdio_cmd): fixed handling of CRC containing invalid bits
- demo/dplore.py (main_window.move): fixed index overrun as lower end of
window
- demo/dplore.py (main_window.move): deselect/select only if selection
changed, not on every movement
- demo/dplore.py (main_window): cleaned up creating of the various windows
- demo/dplore.py (main_window, measurement): added a measurement window
measuring selection width, current position, and current interval
- demo/dplore.py (dplore.quit): do actually call it and exit more gracefully
- demo/dplore.py (control_window): added a "quit" button
- demo/dplore.py, lib/dplore.py, lib/decode.py: split dplore into its
components and fixed bugs concealed by having everything in a single file
- lib/decode.py (d_sdio_cmd): new option "stop" to stop processing at the end
of the command or at the first error
- README: added install instructions
- lib/wave.py (digital.sample): add samples for constant tails
- lib/wave.py (digital.sample): make sure to return numeric values if constant
- lib/wave.py (digital.sample): use list multiplication instead of map+range
- lib/wave.py (analog.digitize): don't try to optimize calls to res.append, or
constant tails will get truncated
Modified: developers/werner/ahrt/host/tmc/README
===================================================================
--- developers/werner/ahrt/host/tmc/README 2008-09-16 00:08:57 UTC (rev 4645)
+++ developers/werner/ahrt/host/tmc/README 2008-09-16 00:11:17 UTC (rev 4646)
@@ -40,13 +40,49 @@
annotated examples in the demo/ directory.
-System setup
+Installation
============
+Prerequisites
+-------------
+
+To build TMC, development libraries for libc, Python, and libusb are
+required. On Ubuntu, one would install them with:
+
+# apt-get install libc6-dev python-dev libusb-dev
+
+At run time, some parts of TMC use NumPy, Tkinter, and ImageMagick.
+On Ubuntu, one would install them with:
+
+# apt-get install python-numpy python-tk imagemagick
+
+Waveforms are saved in a format compatible with gnuplot.
+On Ubuntu, one would install gnuplot with:
+
+# apt-get install gnuplot
+
+
+Building and installing TMC
+---------------------------
+
+TMC is built by simply running "make":
+
+% cd tmc
+% make
+
+To install TMC on the local machine, run the following command as root:
+
+# make install
+
+
+System setup
+------------
+
Access to USB TMC devices requires that the user running TMC has write
-access to the corresponding device files. This is accomplished by
-making all these device files belong to a group "usbtmc" and making
-TMC users members of this group.
+access to the corresponding device files. This is accomplished either
+by using TMC from a privileged account (i.e., root), which is generally
+considered unsafe practice, or by making all these device files belong
+to a group "usbtmc" and making TMC users members of this group.
The instructions below apply to Ubuntu 8.04. The procedure may differ
slightly for other systems, and it will differ a lot for systems not
Modified: developers/werner/ahrt/host/tmc/demo/dplore.py
===================================================================
--- developers/werner/ahrt/host/tmc/demo/dplore.py 2008-09-16 00:08:57 UTC (rev 4645)
+++ developers/werner/ahrt/host/tmc/demo/dplore.py 2008-09-16 00:11:17 UTC (rev 4646)
@@ -4,403 +4,44 @@
# WORK IN PROGRESS !
#
# TODO:
-# - zoom
-# - pan
-# - resize
-# - auto-scale
-# - turn this into a module
-# - clean up
#
+# - just taking the minimum of all sample steps does not guarantee that the
+# true sample rate is used (e.g., two symmetrical square waves with a period
+# of 4 and a phase offset of 1 each have a sample step of 2. This could be
+# solved by using the same zero reference for all waves.
+#
+# - make sure all waves start at the same time
+#
+# - pad or truncate all waves to the same length
+#
+# - all the conditioning and conversion into bit arrays is complex enough to
+# justify putting it into the library
+#
-# apt-get install python-tk
-
-from Tkinter import *
+from tmc.dplore import dplore
from tmc.wave import waves
-import sys
+from sys import argv
-def d_bits(bits):
- s = ""
- for b in bits:
- s += str(b)
- return s
+w = waves()
+w.load(argv[1])
-def d_byte(bit_pos, bits):
- s = ""
+dig = []
+for wv in w:
+ dig.append(wv.digitize(0.5))
- for i in range(0, len(bits)-7, 8):
- if len(s):
- s += "."
- v = 0
- for j in range(0, 8):
- if bits[i+j] == "X":
- s += "??"
- break
- v |= bits[i+j] << bit_pos(j)
- else:
- s += "%02X" % v
-
- if len(bits) & 7:
- s += "|"+d_bits(bits[len(bits) & ~7:len(bits)])
- return s
-
-def d_byte_lsb(bits):
- return d_byte(lambda p: p, bits)
-
-def d_byte_msb(bits):
- return d_byte(lambda p: 7-p, bits)
-
-def d_counter(bits):
- return "%d" % len(bits)
-
-def d_msb(bits):
- v = 0
- pos = len(bits)-1
- for b in bits:
- if b == "X":
- return None
- v |= b << pos
- pos -= 1
- return v
-
-def decode_address(addr):
- if addr < 0x14:
- return (
- "Rev", "SDR", "IOE", "IOR",
- "IEN", "INT", "Abr", "Bus",
- "Cap", "CIS", "Sus", "Sel",
- "EXF", "RDY", "BSZ", "BSZ",
- "PWR", "HSp")[addr]
- return None
-
-def decode_arg(cmd, arg):
- if cmd == 52:
- write = (arg >> 31) & 1
- s = ("R", "W")[write]
- s += str((arg >> 28) & 7)
- s += (" ", "W")[(arg >> 27) & 1]
- addr = (arg >> 9) & 0x1ffff
- name = decode_address(addr)
- if name is None:
- s += "0x%X" % addr
- else:
- s += name+("(0x%X)" % addr)
- if not write:
- return s
- return s+",0x%X" % (arg & 0xff)
- if cmd == 53:
- write = (arg >> 31) & 1
- s = ("R", "W")[write]
- s += str((arg >> 28) & 7)
- s += ("b", "B")[(arg >> 27) & 1]
- s += ("=", "+")[(arg >> 26) & 1]
- addr = (arg >> 9) & 0x1ffff
- name = decode_address(addr)
- if name is None:
- s += "0x%X" % addr
- else:
- s += name+("(0x%X)" % addr)
- if not write:
- return s
- return s+"*%d" % (arg & 0x1ff)
- return None
-
-def d_sdio_cmd(bits):
- if bits[0]:
- s = "~"
- else:
- s = ""
-
- while len(bits) and bits[0]:
- del bits[0]
-
- if len(bits) == 0:
- return s
- s += "["
- del bits[0]
-
- if len(bits) == 0:
- return s
- s += ("?", ">")[bits[0]]
- del bits[0]
-
- if len(bits) == 0:
- return s
- if len(bits) < 6:
- return s+"|"+d_bits(bits)
- cmd = d_msb(bits[0:6])
- if cmd is None:
- s += "CMD??"
- else:
- s += "CMD%d" % cmd
- del bits[0:6]
-
- if len(bits) == 0:
- return s
- if len(bits) < 32:
- return s+"("+d_byte_msb(bits)
- arg = d_msb(bits[0:32])
- if cmd is None or arg is None:
- arg = None
- else:
- arg = decode_arg(cmd, arg)
- if arg is None:
- s += "("+d_byte_msb(bits)+")"
- else:
- s += "("+arg+")"
- del bits[0:32]
-
- if len(bits) == 0:
- return s
- if len(bits) < 7:
- return s+"|"+d_bits(bits)
- crc = d_msb(bits[0:7])
- s += "CRC%02x" % crc
- del bits[0:7]
-
- if len(bits) == 0:
- return s
- s += ("?", "]")[bits[0]]
- del bits[0]
-
- if len(bits):
- s += "|"+d_bits(bits)
-
- return s
-
-def d_sdio_resp(bits):
- return "SDIO"
-
-decoders = [
- ( "LSB->MSB", d_byte_lsb ),
- ( "MSB->LSB", d_byte_msb ),
- ( "SDIO CMD", d_sdio_cmd ),
- ( "SDIO RESP", d_sdio_resp )
-]
-
-class channel:
-
- color_normal = "green"
- color_selected = "yellow"
- decode_color = "white"
- decode_bg_color = "#4040ff"
-
- def __init__(self, main, number, data):
- self.main = main
- self.number = number
- self.tag = "ch%d" % number
- self.d = data
-
- last = data[0]
- for i in range(0, len(data)):
- if data[i] != last:
- main.w.create_line(self.x(i), self.y(0), self.x(i),
- self.y(1), fill = self.color_normal, tags = self.tag)
- main.w.create_line(self.x(i), self.y(data[i]),
- self.x(i+1), self.y(data[i]),
- fill = self.color_normal, tags = self.tag)
-# main.w.create_line(self.x(i), self.y(last),
-# self.x(i+1), self.y(data[i]),
-# fill = self.color_normal, tags = self.tag)
- last = data[i]
-
- def x(self, sample):
- return sample*self.main.mag
-
- def y(self, value):
- return self.number*50-value*20+25
-
- def select(self):
- self.main.w.itemconfig(self.tag, fill = self.color_selected)
-
- def deselect(self):
- self.main.w.itemconfig(self.tag, fill = self.color_normal)
-
- def set_decoder(self, decoder):
- self.decoder = decoder
-
- def begin_decode(self, pos):
- x0 = self.x(pos)
- x1 = x0+self.main.mag
- y = self.y(0)
- self.main.w.create_text(x0+5, y+6,
- fill = self.decode_color, anchor = "nw", tags = "d_fg_"+self.tag)
- rect = self.main.w.create_rectangle(x0, y+5, x1, y+20,
- fill = self.decode_bg_color, outline = self.decode_bg_color,
- tags = "d_bg_"+self.tag)
- self.main.w.tag_raise("d_bg_"+self.tag)
- self.main.w.tag_raise("d_fg_"+self.tag)
-
- def decode(self, selected, bits):
- y = self.y(0)
- x0 = self.x(self.main.decode_from)
- x1 = self.x(self.main.cur.pos+1)
- if selected:
- text = d_counter(bits)
- else:
- text = self.decoder(bits)
- self.main.w.itemconfig("d_fg_"+self.tag, text = text)
- self.main.w.coords("d_bg_"+self.tag, x0, y+5, x1, y+20)
-
- def end_decode(self):
- self.main.w.delete("d_fg_"+self.tag)
- self.main.w.delete("d_bg_"+self.tag)
-
-
-class cursor:
-
- color = "white"
-
- def __init__(self, main):
- self.main = main
- self.tag = main.w.create_line(0, 0, 0, 0, fill = self.color, width = 1)
- self.pos = 0
-
- def set(self):
- x = self.main.ch[0].x(self.pos)
- self.main.w.coords(self.tag, x, 0, x, self.main.yres)
- self.main.w.tag_raise(self.tag)
-
- def move(self, x):
- s = (x+self.main.mag/2)/self.main.mag
- if s >= len(self.main.ch[0].d):
- return
- if s != self.pos:
- self.pos = s
- self.set()
-
-
-class main_window:
-
- background_color = "black"
- selection_color = "#808080"
-
- def __init__(self, master, d):
- channels = len(d)
- samples = len(d[0])
- self.mag = 1
- self.yres = channels*50
- self.w3 = Frame(master, width = 100, bg = 'black')
- self.w3.pack(side = LEFT, fill = BOTH, expand = 1)
- self.w = Canvas(master,
- width = samples*self.mag,
- height = self.yres, bg = self.background_color)
- self.w.pack(expand = 1, fill = "x")
- self.w2 = Canvas(master, width = samples*self.mag, height = 20,
- bg = 'black')
- self.w2.pack(expand = 1, fill = "x")
- self.w.bind("<Motion>", self.move)
- self.w.bind("<Button-1>", self.button)
- self.decode_from = None
- self.ch = []
- self.cur = cursor(self)
- for ch in range(0, channels):
- self.ch.append(channel(self, ch, d[ch]))
- self.decoder_menu(self.w3, self.ch[-1], ch)
- self.selected = None
-
- def decoder_menu(self, master, ch, n):
- mb = Menubutton(master, direction = RIGHT, text = decoders[0][0],
- relief = FLAT, width = 10)
- mb.place(x = 3, y = 50*n+3)
- mb.menu = Menu(mb, tearoff = 0)
- mb["menu"] = mb.menu
-
- for dec in decoders:
- def handler(ch = ch, decoder = dec[1], button = mb, label = dec[0]):
- ch.set_decoder(decoder)
- mb.config(text = label)
- mb.menu.add_command(label = dec[0], command = handler)
- ch.set_decoder(decoders[0][1])
-
- def move(self, event):
- self.cur.move(event.x)
- y = event.y
- ny = (event.y+0)/50
- if self.decode_from is not None:
- self.decode()
- return
- if self.selected is not None:
- self.selected.deselect()
- self.selected = self.ch[ny]
- self.selected.select()
-
- def button(self, event):
- if self.decode_from is None:
- self.begin_decode()
- else:
- self.end_decode()
-
- def begin_decode(self):
- pos = self.cur.pos
- if pos == 0:
- return
- if self.selected.d[pos-1] == self.selected.d[pos]:
- return
- self.decode_from = pos
- for ch in self.ch:
- ch.begin_decode(pos)
- x0 = self.ch[0].x(pos)
- x1 = x0+self.mag
- rect = self.w.create_rectangle(x0, 0, x1, self.yres,
- fill = self.selection_color, outline = self.selection_color,
- tags = "selection")
- self.w.tag_lower(rect)
- self.w.tag_raise(self.cur)
- self.decode()
-
- def decode(self):
- if self.cur.pos < self.decode_from:
- return
- x0 = self.ch[0].x(self.decode_from)
- x1 = self.ch[0].x(self.cur.pos+1)
- self.w.coords("selection", x0, 0, x1, self.yres)
- for ch in self.ch:
- bits = []
- i = self.decode_from
- while i <= self.cur.pos:
- if self.selected.d[i-1] != self.selected.d[i] and \
- self.selected.d[i] == self.selected.d[self.decode_from]:
- if ch.d[i-1] == ch.d[i]:
- bits.append(ch.d[i])
- else:
- bits.append("X")
- i += 1
- ch.decode(ch is self.selected, bits)
-
- def end_decode(self):
- for ch in self.ch:
- ch.end_decode()
- self.w.delete("selection")
- self.decode_from = None
-
-
-class dplore:
-
- def __init__(self, channels):
- self.master = Tk()
- self.master.resizable(1, 0)
- self.main = main_window(self.master, d)
- self.master.bind("q", quit)
- mainloop()
-
- def quit(event):
- sys.exit(0)
-
-
-w = waves()
-w.load(sys.argv[1])
-min = w[1].digitize(0.5).sample_step()
-for wv in w[2:]:
- step = wv.digitize(0.5).sample_step()
+min = dig[1].sample_step()
+for d in dig[2:]:
+ step = d.sample_step()
if step is not None and step < min:
min = step
-d = []
-for wv in w[1:]:
- a = wv.digitize(0.5).sample(min)
+
+da = []
+for d in dig[1:]:
+ a = d.sample(min)
# print len(a)
if len(a) >= 1500:
- d.append(a[0:1500])
-dplore(d.reverse())
+ da.append(a)
-# 1, 2, 3, 5, 10
+da.reverse()
+dplore(da, dig[1].start(), min, argv[1])
Added: developers/werner/ahrt/host/tmc/lib/decode.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/decode.py (rev 0)
+++ developers/werner/ahrt/host/tmc/lib/decode.py 2008-09-16 00:11:17 UTC (rev 4646)
@@ -0,0 +1,194 @@
+#!/usr/bin/python
+
+
+def d_bits(bits):
+ s = ""
+ for b in bits:
+ s += str(b)
+ return s
+
+
+def d_byte(bit_pos, bits):
+ s = ""
+
+ for i in range(0, len(bits)-7, 8):
+ if len(s):
+ s += "."
+ v = 0
+ for j in range(0, 8):
+ if bits[i+j] == "X":
+ s += "??"
+ break
+ v |= bits[i+j] << bit_pos(j)
+ else:
+ s += "%02X" % v
+
+ if len(bits) & 7:
+ s += "|"+d_bits(bits[len(bits) & ~7:len(bits)])
+ return s
+
+
+def d_byte_lsb(bits):
+ return d_byte(lambda p: p, bits)
+
+
+def d_byte_msb(bits):
+ return d_byte(lambda p: 7-p, bits)
+
+
+def d_counter(bits):
+ return "%d" % len(bits)
+
+
+def d_msb(bits):
+ v = 0
+ pos = len(bits)-1
+ for b in bits:
+ if b == "X":
+ return None
+ v |= b << pos
+ pos -= 1
+ return v
+
+
+def decode_address(addr):
+ if addr < 0x14:
+ return (
+ "Rev", "SDR", "IOE", "IOR",
+ "IEN", "INT", "Abr", "Bus",
+ "Cap", "CIS", "Sus", "Sel",
+ "EXF", "RDY", "BSZ", "BSZ",
+ "PWR", "HSp")[addr]
+ return None
+
+
+def decode_arg(cmd, arg):
+ if cmd == 52:
+ write = (arg >> 31) & 1
+ s = ("R", "W")[write]
+ s += str((arg >> 28) & 7)
+ s += (" ", "W")[(arg >> 27) & 1]
+ addr = (arg >> 9) & 0x1ffff
+ name = decode_address(addr)
+ if name is None:
+ s += "0x%X" % addr
+ else:
+ s += name+("(0x%X)" % addr)
+ if not write:
+ return s
+ return s+",0x%X" % (arg & 0xff)
+ if cmd == 53:
+ write = (arg >> 31) & 1
+ s = ("R", "W")[write]
+ s += str((arg >> 28) & 7)
+ s += ("b", "B")[(arg >> 27) & 1]
+ s += ("=", "+")[(arg >> 26) & 1]
+ addr = (arg >> 9) & 0x1ffff
+ name = decode_address(addr)
+ if name is None:
+ s += "0x%X" % addr
+ else:
+ s += name+("(0x%X)" % addr)
+ if not write:
+ return s
+ return s+"*%d" % (arg & 0x1ff)
+ return None
+
+
+def d_sdio_cmd(bits, stop = False):
+ if bits[0]:
+ s = "~"
+ else:
+ s = ""
+
+ while len(bits) and bits[0]:
+ del bits[0]
+
+ if len(bits) == 0:
+ return s
+ s += "["
+ del bits[0]
+
+ if len(bits) == 0:
+ return s
+ if bits[0]:
+ s += ">"
+ else:
+ s += "?"
+ if stop:
+ return s
+ del bits[0]
+
+ if len(bits) == 0:
+ return s
+ if len(bits) < 6:
+ return s+"|"+d_bits(bits)
+ cmd = d_msb(bits[0:6])
+ if cmd is None:
+ s += "CMD??"
+ if stop:
+ return s
+ else:
+ s += "CMD%d" % cmd
+ del bits[0:6]
+
+ if len(bits) == 0:
+ return s
+ if len(bits) < 32:
+ return s+"("+d_byte_msb(bits)
+ arg = d_msb(bits[0:32])
+ if cmd is None or arg is None:
+ arg = None
+ else:
+ arg = decode_arg(cmd, arg)
+ if arg is None:
+ s += "("+d_byte_msb(bits)+")"
+ if stop:
+ return s
+ else:
+ s += "("+arg+")"
+ del bits[0:32]
+
+ if len(bits) == 0:
+ return s
+ if len(bits) < 7:
+ return s+"|"+d_bits(bits)
+ crc = d_msb(bits[0:7])
+ if crc is None:
+ s += "CRC??"
+ if stop:
+ return s
+ else:
+ s += "CRC%02x" % crc
+ del bits[0:7]
+
+ if len(bits) == 0:
+ return s
+ s += ("?", "]")[bits[0]]
+ del bits[0]
+
+ if stop:
+ return s
+
+ if len(bits):
+ s += "|"+d_bits(bits)
+
+ return s
+
+
+def d_sdio_resp_spi(bits):
+ return "SDIO"
+
+
+def d_sdio_resp_sd(bits):
+ return "SDIO"
+
+
+decoders = [
+ # 0123456789abcdef -- maximum length is 16 characters
+ ( "LSB->MSB", d_byte_lsb ),
+ ( "MSB->LSB", d_byte_msb ),
+ ( "SDIO CMD", d_sdio_cmd ),
+ ( "SDIO RESP (SD)", d_sdio_resp_sd ),
+ ( "SDIO RESP (SPI)", d_sdio_resp_spi ),
+]
Property changes on: developers/werner/ahrt/host/tmc/lib/decode.py
___________________________________________________________________
Name: svn:executable
+ *
Added: developers/werner/ahrt/host/tmc/lib/dplore.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/dplore.py (rev 0)
+++ developers/werner/ahrt/host/tmc/lib/dplore.py 2008-09-16 00:11:17 UTC (rev 4646)
@@ -0,0 +1,584 @@
+#!/usr/bin/python
+
+#
+# WORK IN PROGRESS !
+#
+# TODO:
+# - zoom
+# - pan
+# - resize
+# - auto-scale
+# - clean up
+#
+
+# apt-get install python-tk
+
+from Tkinter import *
+from tmc.decode import *
+from math import ceil, floor
+
+
+class channel:
+
+ color_normal = "green"
+ color_selected = "yellow"
+ decode_color = "white"
+ decode_bg_color = "#4040ff"
+ decode_font = "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*"
+
+ def __init__(self, main, number, data):
+ self.main = main
+ self.number = number
+ self.tag = "d_%d" % number
+ self.zoom_tag = "d_z_%d" % number
+ self.d = data
+ self.draw()
+
+ def draw(self):
+ if self.main.pos0 > len(self.d):
+ return
+ pos0 = max(0, self.main.pos0)
+ last = self.d[pos0]
+ line = [ self.x(pos0), self.y(last) ]
+ for i in range(pos0, len(self.d)):
+ if self.d[i] != last:
+ line.extend((self.x(i), self.y(self.d[i])))
+ x1 = self.x(i+1)
+ if x1 > self.main.xres:
+ break
+ if self.d[i] == last and i != pos0:
+ line.pop()
+ line.pop()
+ line.extend((x1, self.y(self.d[i])))
+ last = self.d[i]
+ self.main.w.create_line(
+ fill = self.color_normal, tags = self.tag, *line)
+
+ def draw_zoom(self):
+ mag = float(self.main.xres)/self.main.samples
+ last = self.d[0]
+ line = [ 0, self.zoom_y(last) ]
+ for i in range(0, len(self.d)):
+ if self.d[i] != last:
+ line.extend((i*mag, self.zoom_y(self.d[i])))
+ elif i:
+ line.pop()
+ line.pop()
+ line.extend(((i+1)*mag, self.zoom_y(self.d[i])))
+ last = self.d[i]
+ self.main.wz.create_line(
+ fill = self.color_normal, tags = self.zoom_tag, *line)
+
+ def redraw_zoom(self):
+ self.main.w.delete(self.zoom_tag)
+ self.draw_zoom()
+
+ def redraw(self):
+ self.main.w.delete(self.tag)
+ self.draw()
+
+ def x(self, sample):
+ return int(round(self.main.x0+(sample-self.main.pos0)*self.main.mag))
+
+ def y(self, value):
+ return self.number*50-value*20+25
+
+ def zoom_y(self, value):
+ return self.number*6-value*2+5
+
+ def select(self):
+ self.main.w.itemconfig(self.tag, fill = self.color_selected)
+
+ def deselect(self):
+ self.main.w.itemconfig(self.tag, fill = self.color_normal)
+
+ def set_decoder(self, decoder):
+ self.decoder = decoder
+
+ def begin_decode(self, pos):
+ x0 = self.x(pos)
+ x1 = x0+self.main.mag
+ y = self.y(0)
+ self.main.w.create_text(x0+5, y+6,
+ fill = self.decode_color, anchor = "nw", tags = "d_fg_"+self.tag,
+ font = self.decode_font)
+ rect = self.main.w.create_rectangle(x0, y+5, x1, y+20,
+ fill = self.decode_bg_color, outline = self.decode_bg_color,
+ tags = "d_bg_"+self.tag)
+ self.main.w.tag_raise("d_bg_"+self.tag)
+ self.main.w.tag_raise("d_fg_"+self.tag)
+
+ def decode(self, selected, bits):
+ y = self.y(0)
+ x0 = self.x(self.main.decode_from)
+ x1 = self.x(self.main.cur.pos+1)
+ if selected:
+ text = d_counter(bits)
+ else:
+ text = self.decoder(bits)
+ self.main.w.itemconfig("d_fg_"+self.tag, text = text)
+ self.main.w.coords("d_bg_"+self.tag, x0, y+5, x1, y+20)
+
+ def end_decode(self):
+ self.main.w.delete("d_fg_"+self.tag)
+ self.main.w.delete("d_bg_"+self.tag)
+
+
+class measurement:
+
+ background_color = "black"
+ color = "white"
+ font = "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*"
+ # sigh, where's a mono-spaced font with a sans-serif "1" when you need
+ # one ...
+ font = "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-iso8859-*"
+
+ def __init__(self, master, t0, dt, prefix = ""):
+ self.fn = (
+ ( self.show_samples, "Sa" ),
+ ( self.show_time, "s" ),
+ ( self.show_frequency, "Hz" ))
+
+ self.t0 = t0
+ self.dt = dt
+ self.prefix = prefix
+ self.last_prefix = None
+ self.var = StringVar()
+ self.button = Button(master, textvariable = self.var, width = 12,
+ relief = FLAT, borderwidth = 0, font = self.font,
+ fg = self.color, bg = self.background_color,
+ activeforeground = self.color,
+ activebackground = self.background_color,
+ command = self.button)
+ self.button.pack(side = LEFT)
+ self.index = 0
+ self.last = None
+ self.hide()
+
+ def button(self):
+ self.index += 1
+ self.index %= len(self.fn)
+ self.__show(self.last)
+
+ def pretty_float(self, f):
+ if f < 0:
+ sign = True
+ f = -f
+ else:
+ sign = False
+
+ if f < 1e-6:
+ unit = "n"
+ f *= 1e9
+ elif f < 1e-3:
+ unit = "u"
+ f *= 1e6
+ elif f < 1:
+ unit = "m"
+ f *= 1e3
+ elif f < 1e3:
+ unit = " "
+ elif f < 1e6:
+ unit = "k"
+ f *= 1e-3
+ elif f < 1e9:
+ unit = "M"
+ f *= 1e-6
+ elif f < 1e12:
+ unit = "G"
+ f *= 1e-9
+ elif f < 1e15:
+ unit = "T"
+ f *= 1e-12
+ else:
+ print f
+ raise hell
+
+ return "%s%7.3f%s" % ((" ", "-")[sign], f, unit)
+
+ # Comment out the line above to remove trailing zeroes, e.g.,
+ # 5.100 becomes 5.1. While this looks like a nice idea, I found the
+ # constantly changing format somewhat irritating. It's also inaccurate
+ # in the sense that these numbers represent physical units well above
+ # quantum level and therefore cannot be exact.
+
+ if round(f*1000) == round(f)*1000:
+ dec = 0
+ elif round(f*1000) == round(f*10)*100:
+ dec = 1
+ elif round(f*1000) == round(f*100)*10:
+ dec = 2
+ else:
+ dec = 3
+
+ fract = (0, 1+dec)[dec > 0]
+
+ return "%s%*.*f%*s%s" % (
+ (" ", "-")[sign],
+ fract+3, dec, f,
+ 4-fract, "",
+ unit)
+
+ def show_samples(self, samples):
+ self.var.set(self.prefix+"%8d Sa" % samples)
+
+ def show_time(self, samples):
+ t = samples*self.dt+self.t0
+ self.var.set(self.prefix+self.pretty_float(float(t))+"s")
+
+ def show_frequency(self, samples):
+ t = samples*self.dt+self.t0
+ if abs(t) < 1e-12:
+ self.hide()
+ else:
+ self.var.set(self.prefix+self.pretty_float(1.0/t)+"Hz")
+
+ def __show(self, samples):
+ if samples is None:
+ self.hide()
+ else:
+ self.fn[self.index][0](samples)
+
+ def show(self, samples):
+ if samples != self.last or self.prefix != self.last_prefix:
+ self.__show(samples)
+ self.last = samples
+ self.last_prefix = self.prefix
+
+ def hide(self):
+ self.var.set(" "*9+self.fn[self.index][1])
+ self.last = None
+
+ def remove(self):
+ self.button(delete)
+
+
+class cursor:
+
+ color = "white"
+
+ def __init__(self, main):
+ self.main = main
+ self.tag = main.w.create_line(0, 0, 0, 0, fill = self.color, width = 1)
+ self.zoom_tag = \
+ main.wz.create_line(0, 0, 0, 0, fill = self.color, width = 1)
+ self.x = 0
+ self.pos = 0
+
+ def set(self):
+ x = self.main.ch[0].x(self.pos)
+ self.main.w.coords(self.tag, x, 0, x, self.main.yres)
+ self.main.w.tag_raise(self.tag)
+ x = int(float(self.pos)/self.main.samples*self.main.xres)
+ self.main.wz.coords(self.zoom_tag, x, 0, x, self.main.zres)
+ self.main.wz.tag_raise(self.zoom_tag)
+ self.main.meas_pos.show(self.pos)
+
+ def x_to_pos(self, x):
+ s = self.main.pos0+int(round((x-self.main.x0)/self.main.mag))
+ if s < 0:
+ return 0
+ if s >= self.main.samples:
+ return self.main.samples-1
+ return s
+
+ def move(self, x):
+ s = self.x_to_pos(x)
+ self.x = x
+ if s != self.pos:
+ self.pos = s
+ self.set()
+
+
+class main_window:
+
+ background_color = "black"
+ selection_color = "#808080"
+ data_color = "white"
+ zoom_color = "#808080"
+
+ def __init__(self, master, d, t0, sample_step):
+ channels = len(d)
+ self.samples = len(d[0])
+ self.xres = self.samples
+ self.yres = channels*50
+ self.zres = channels*6+2
+ self.geometry()
+ self.w3 = self.control_window(master)
+ self.wz = self.zoom_window(master)
+ self.w = self.main_window(master)
+ self.wt = self.tick_window(master)
+ self.wd = self.meas_window(master, t0, sample_step)
+ self.setup_events(master)
+ self.decode_from = None
+ self.ch = []
+ self.cur = cursor(self)
+ for ch in range(0, channels):
+ self.ch.append(channel(self, ch, d[ch]))
+ self.decoder_menu(self.w3, self.ch[-1], ch)
+ self.selected = None
+ self.update_zoom_area()
+
+ def geometry(self):
+ self.x0 = 0
+ self.pos0 = 0
+ self.mag = 1.0
+
+ def main_window(self, master):
+ w = Canvas(master,
+ width = self.xres,
+ height = self.yres, bg = self.background_color)
+ w.pack(expand = 1, fill = "x")
+ return w
+
+ def zoom_window(self, master):
+ w = Canvas(master,
+ width = self.xres,
+ height = self.zres, bg = self.zoom_color)
+ w.pack(expand = 1, fill = "x")
+ self.zoom_area = w.create_rectangle(0, 0, 0, 0,
+ fill = self.background_color, width = 0)
+ return w
+
+ def meas_window(self, master, t0, sample_step):
+ w = Frame(master, width = self.xres, height = 20,
+ bg = self.background_color)
+ w.pack(expand = 1, fill = "x")
+
+ self.meas_start = measurement(w, 0, sample_step)
+ self.meas_pos = measurement(w, t0, sample_step)
+ self.meas_width = measurement(w, 0, sample_step)
+
+ def tick_window(self, master):
+ w = Canvas(master, width = self.xres, height = 20,
+ bg = self.background_color)
+ w.pack(expand = 1, fill = "x")
+
+ def control_window(self, master):
+ w = Frame(master, width = 135, bg = self.background_color)
+ w.pack(side = LEFT, fill = BOTH, expand = 1)
+ b = Button(master, text = "Quit", relief = FLAT, command = master.quit)
+ b.place(x = 3, y = self.yres+16+self.zres+2)
+
+ def setup_events(self, master):
+ self.w.bind("<Motion>", self.move)
+ self.w.bind("<Button-1>", self.button)
+ self.w.bind("<Button-3>", self.center)
+ self.w.bind("<Button-4>", self.zoom_in)
+ self.w.bind("<Button-5>", self.zoom_out)
+ self.w.bind("<Configure>", self.resize)
+
+ self.wz.bind("<Button-1>", self.zoom_button)
+ self.wz.bind("<Button-3>", self.zoom_button)
+ self.wz.bind("<Button-4>", self.zoom_in)
+ self.wz.bind("<Button-5>", self.zoom_out)
+
+ master.bind("+", self.zoom_in)
+ master.bind("=", self.zoom_in)
+ master.bind("-", self.zoom_out)
+ master.bind(".", self.center)
+ master.bind("c", self.center)
+
+ def decoder_menu(self, master, ch, n):
+ mb = Menubutton(master, direction = RIGHT, text = decoders[0][0],
+ relief = FLAT, width = 16)
+ mb.place(x = 3, y = 50*n+3+self.zres+2)
+ mb.menu = Menu(mb, tearoff = 0)
+ mb["menu"] = mb.menu
+
+ for dec in decoders:
+
+ # Brilliant hack. Found it described here:
+ # http://infohost.nmt.edu/tcc/help/pubs/tkinter/extra-args.html
+
+ def handler(ch = ch, decoder = dec[1], button = mb, label = dec[0]):
+ ch.set_decoder(decoder)
+ button.config(text = label)
+
+ mb.menu.add_command(label = dec[0], command = handler)
+ ch.set_decoder(decoders[0][1])
+
+ def move(self, event):
+ self.cur.move(event.x)
+ if self.decode_from is not None:
+ self.decode()
+ else:
+ self.move_y(event.y)
+ self.measure_width()
+
+ def move_y(self, y):
+ ny = y/50
+ if ny >= len(self.ch):
+ return
+ if self.selected is not None:
+ if self.selected.number == ny:
+ return
+ self.selected.deselect()
+ self.selected = self.ch[ny]
+ self.selected.select()
+
+ def measure_width(self):
+ if self.selected is None:
+ self.meas_width.hide()
+ return
+ val = self.selected.d[self.cur.pos]
+ pos = self.cur.pos
+ i = pos-1
+ while i >= 0 and self.selected.d[i] == val:
+ i -= 1
+ width = pos-i-1
+ i = pos+1
+ while i < self.samples and self.selected.d[i] == val:
+ i += 1
+ width += i-pos-1+1 # remove last sample, add center
+ self.meas_width.prefix = ("L ", "H ")[val]
+ self.meas_width.show(width)
+
+ def zoom(self):
+ self.pos0 = self.cur.pos-int(self.cur.x/self.mag)
+ self.x0 = self.cur.x-int(self.mag*(self.cur.pos-self.pos0-0.5))
+ self.redraw()
+
+ def zoom_in(self, event):
+ if self.decode_from is not None:
+ return
+ if self.mag > 10:
+ return
+ self.mag *= 2.0
+ self.zoom()
+
+ def zoom_out(self, event):
+ if self.decode_from is not None:
+ return
+ if self.xres > self.samples*self.mag:
+ if self.reset():
+ self.zoom()
+ else:
+ self.mag /= 2.0
+ self.zoom()
+
+ def center(self, event):
+ if self.decode_from is not None:
+ return
+ x = self.cur.x
+ self.cur.x = self.xres/2
+ self.zoom()
+ self.cur.move(x)
+
+ def zoom_button(self, event):
+ if self.decode_from is not None:
+ return
+ self.cur.pos = int(float(event.x)/self.xres*self.samples+0.49)
+ if self.cur.pos >= self.samples:
+ self.cur.pos = self.samples-1
+ self.center(event)
+
+ def reset(self):
+ end = (self.samples-self.pos0)*self.mag
+ # Entire waveform is on screen
+ if self.pos0 <= 0 and (self.samples-self.pos0)*self.mag <= self.xres:
+ return False
+
+ # No unused space surrounde waveform
+ if self.pos0 >= 0 and end >= self.xres:
+ return False
+
+ pos = self.samples-int(self.xres/self.mag)
+ if abs(pos-self.pos0) > abs(self.pos0):
+ self.pos0 = 0
+ else:
+ self.pos0 = pos
+ self.cur.move(self.cur.x)
+ return True
+
+ def resize(self, event):
+ if self.decode_from is not None:
+ self.end_decode()
+ self.xres = event.width
+ for ch in self.ch:
+ ch.redraw_zoom()
+ self.reset()
+ self.zoom()
+
+ def redraw(self):
+ for ch in self.ch:
+ ch.redraw()
+ self.cur.move(self.cur.x)
+ self.update_zoom_area()
+
+ def update_zoom_area(self):
+ self.wz.coords(self.zoom_area,
+ int(float(self.pos0)/self.samples*self.xres), 0,
+ int(ceil((self.pos0+self.xres/self.mag)/self.samples*self.xres)),
+ self.zres)
+
+ def button(self, event):
+ if self.decode_from is None:
+ self.begin_decode()
+ else:
+ self.end_decode()
+
+ def begin_decode(self):
+ # @@@FIXME: at mag < 1, this we're usually off by a pixel
+ x0 = max(1, self.pos0+int((self.cur.x-self.x0)/self.mag))
+ x1 = min(self.samples,
+ self.pos0+int((self.cur.x-self.x0+1)/self.mag)+1)
+ # print self.cur.pos, x0, x1
+ for pos in range(x0, x1):
+ if self.selected.d[pos-1] != self.selected.d[pos]:
+ break
+ else:
+ return
+ self.decode_from = pos
+ for ch in self.ch:
+ ch.begin_decode(pos)
+ x0 = self.ch[0].x(pos)
+ x1 = x0+self.mag
+ rect = self.w.create_rectangle(x0, 0, x1, self.yres,
+ fill = self.selection_color, outline = self.selection_color,
+ tags = "selection")
+ self.w.tag_lower(rect)
+ self.w.tag_raise(self.cur)
+ self.decode()
+
+ def decode(self):
+ self.meas_start.show(self.cur.pos-self.decode_from)
+ if self.cur.pos < self.decode_from:
+ return
+ x0 = self.ch[0].x(self.decode_from)
+ x1 = self.ch[0].x(self.cur.pos+1)
+ self.w.coords("selection", x0, 0, x1, self.yres)
+ for ch in self.ch:
+ bits = []
+ i = self.decode_from
+ while i <= self.cur.pos:
+ if self.selected.d[i-1] != self.selected.d[i] and \
+ self.selected.d[i] == self.selected.d[self.decode_from]:
+ if ch.d[i-1] == ch.d[i]:
+ bits.append(ch.d[i])
+ else:
+ bits.append("X")
+ i += 1
+ ch.decode(ch is self.selected, bits)
+
+ def end_decode(self):
+ for ch in self.ch:
+ ch.end_decode()
+ self.w.delete("selection")
+ self.decode_from = None
+ self.meas_start.hide()
+
+
+class dplore:
+
+ def __init__(self, channels, t0, sample_step, title = None):
+ self.master = Tk()
+ if title is not None:
+ self.master.title(title)
+ self.master.resizable(1, 0)
+ self.main = main_window(self.master, channels, t0, sample_step)
+ self.master.bind("q", self.quit)
+ mainloop()
+
+ def quit(self, event):
+ self.master.quit()
Property changes on: developers/werner/ahrt/host/tmc/lib/dplore.py
___________________________________________________________________
Name: svn:executable
+ *
Modified: developers/werner/ahrt/host/tmc/lib/trigger.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/trigger.py 2008-09-16 00:08:57 UTC (rev 4645)
+++ developers/werner/ahrt/host/tmc/lib/trigger.py 2008-09-16 00:11:17 UTC (rev 4646)
@@ -80,6 +80,7 @@
def __init__(self, **list):
trigger.__init__(self)
+ # @@@WARNING: Agilent use divs as the trigger level unit, not V.
self.level = setting(self, ":TRIG:"+self.mode+":LEV",
lambda x: float(x),
lambda x: "%.9f" % x)
Modified: developers/werner/ahrt/host/tmc/lib/wave.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/wave.py 2008-09-16 00:08:57 UTC (rev 4645)
+++ developers/werner/ahrt/host/tmc/lib/wave.py 2008-09-16 00:11:17 UTC (rev 4646)
@@ -361,16 +361,11 @@
if high < low:
raise hell
res = digital()
- state = None
for p in self.data:
if p[1] >= high:
- if state is None or not state:
- res.append(p[0], 1)
- state = True
+ res.append(p[0], 1)
elif p[1] <= low:
- if state is None or state:
- res.append(p[0], 0)
- state = False
+ res.append(p[0], 0)
return res
@@ -474,9 +469,9 @@
return []
if len(self.data) == 1:
if step is None:
- return [self.initial]
- return map(lambda x: self.initial,
- range(0, int(round((self.t_end-self.data[0])/float(step)))))
+ return [int(self.initial)]
+ return [int(self.initial)]* \
+ int(round((self.t_end-self.data[0])/float(step)))
if step is None:
step = self.sample_step()
value = int(self.initial)
@@ -486,9 +481,10 @@
n = round((t-last)/step)
if abs(n*step-(t-last)) > step*tolerance:
raise hell
- res.extend(map(lambda x: value, range(0, int(n))))
+ res.extend([value]*int(n))
last = t
value = 1-value
+ res.extend([value]*int((self.end()-t)/step+0.5))
return res
def __iter__(self):
Modified: developers/werner/ahrt/host/tmc/setup.py
===================================================================
--- developers/werner/ahrt/host/tmc/setup.py 2008-09-16 00:08:57 UTC (rev 4645)
+++ developers/werner/ahrt/host/tmc/setup.py 2008-09-16 00:11:17 UTC (rev 4646)
@@ -5,6 +5,7 @@
description = "Test and Measurement Control",
py_modules = [ "tmc.instrument",
"tmc.wave", "tmc.trigger", "tmc.shape",
+ "tmc.decode", "tmc.dplore",
"tmc.meter", "tmc.scope", "tmc.power", "tmc.function" ],
package_dir = { "tmc": "lib" },
ext_modules = [
More information about the commitlog
mailing list