r4638 - developers/werner/ahrt/host/tmc/lib

werner at docs.openmoko.org werner at docs.openmoko.org
Wed Sep 10 01:15:53 CEST 2008


Author: werner
Date: 2008-09-10 01:15:52 +0200 (Wed, 10 Sep 2008)
New Revision: 4638

Modified:
   developers/werner/ahrt/host/tmc/lib/function.py
   developers/werner/ahrt/host/tmc/lib/instrument.py
   developers/werner/ahrt/host/tmc/lib/meter.py
   developers/werner/ahrt/host/tmc/lib/power.py
   developers/werner/ahrt/host/tmc/lib/scope.py
   developers/werner/ahrt/host/tmc/lib/shape.py
   developers/werner/ahrt/host/tmc/lib/trigger.py
   developers/werner/ahrt/host/tmc/lib/wave.py
Log:
Highlights:
- debugged the trigger/horizontal system setup (many small bugs)
- classes with settable attributes can now be locked, so that typos like
  "s.hor.pod = 0" don't cause silent failure

Details:
- lib/instrument.py (settable), lib/*.py all classes derived from "settable":
  added ability to lock the attributes of a "settable" class, such that new
  attributes can't be added by accident
- lib/scope.py (channel.name): name was incorrectly set to CHn instead of
  CHANn, causing setting the trigger source to fail
- lib/scope.py (horizontal.state_map): has to be a list to have an "index"
  method
- lib/scope.py (horizontal): new experimental methods "run" and "stop" to
  run/stop the scope
- lib/scope.py (wave): call self.wave, not self.download
- lib/shape.py (__shape_with_duty): seems that a class name can't begin with
  two underscores. Renamed to shape_with_duty.
- lib/wave.py (analog.digitize): reject inverted thresholds
- lib/trigger.py: the logic for updating settings after attaching a trigger was
  busted. Need to explicitly clear and re-set the attributes.
- lib/trigger.py (trigger.set_sweep): don't try to set if we don't have a value
- lib/trigger.py (trigger.get_sweep): query needs a question mark
- lib/wave.py: use iter(obj), not obj.__iter__()



Modified: developers/werner/ahrt/host/tmc/lib/function.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/function.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/function.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -16,6 +16,7 @@
 
 
 class function(instrument):
+    # Warning: "function" doesn't lock itself !
     pass
 
 
@@ -27,6 +28,7 @@
 	      "vendor=0x164e", "product=0x13ec")
 	else:
 	    function.__init__(self, "telnet", "tries=3", "nl", name, "5025")
+	self.lock_attr()
 
     def read(self):
 	return function.read(self).rstrip('\n')

Modified: developers/werner/ahrt/host/tmc/lib/instrument.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/instrument.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/instrument.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -81,12 +81,39 @@
 	      " "+self.args+str(value))
 
 
+#
+# The attributes of a "settable" object can be locked. This means that any
+# attempt to create a new attribute will cause an AttributeError. This is to
+# protect against accidently adding new attributes, which would otherwise cause
+# a silent failure.
+#
+# In order to avoid having to call settable.__init__ in the __init__ methods of
+# all subclasses, attr_is_locked also considers the absence of the
+# "attr_locked" attribute to mean that the class is not (yet) locked.
+#
+
 class settable(object):
 
     def set(self, **list):
 	for key in list.keys():
 	    self.__setattr__(key, list[key])
 
+    def attr_is_locked(self):
+	try:
+	    return super(settable, self).__getattribute__("attr_locked")
+	except AttributeError:
+	    return False
+
+    def lock_attr(self):
+	if self.attr_is_locked():
+	    raise hell
+	object.__setattr__(self, "attr_locked", True)
+
+    def unlock_attr(self):
+	if not self.attr_is_locked():
+	    raise hell
+	object.__setattr__(self, "attr_locked", False)
+
     def __getattribute__(self, name):
 	ret = super(settable, self).__getattribute__(name)
 	if isinstance(ret, settings):
@@ -97,6 +124,8 @@
 	attr = self.__dict__.get(name)
 	if isinstance(attr, settings):
 	    return attr.set(value)
+	if self.attr_is_locked():
+	    super(settable, self).__getattribute__(name)
 	return super(settable, self).__setattr__(name, value)
 
 
@@ -109,6 +138,7 @@
 
     def __init__(self, *args):
 	self.__tmc = _tmc.Instr(*args)
+	# Warning: "instrument" doesn't lock itself !
 
     def send(self, s):
 	print "SEND", s

Modified: developers/werner/ahrt/host/tmc/lib/meter.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/meter.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/meter.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -16,6 +16,7 @@
 
 
 class meter(instrument):
+    # Warning: "meter" doesn't lock itself !
     pass
 
 
@@ -23,6 +24,7 @@
 
     def __init__(self, name):
 	meter.__init__(self, "telnet", "tries=3", name)
+	self.lock_attr()
 
 
 class picotest_m3500a(meter):
@@ -30,3 +32,4 @@
     def __init__(self):
 	meter.__init__(self, "usbtmc", "timeout=2", "retry", "vendor=0x164e",
 	  "product=0x0dad")
+	self.lock_attr()

Modified: developers/werner/ahrt/host/tmc/lib/power.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/power.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/power.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -17,10 +17,12 @@
 #
 #
 
-from tmc.instrument import settable, setting, instrument
+from tmc.instrument import setting, instrument
 
+
 class power(instrument):
-	pass
+    # Warning: "power" doesn't lock itself !
+    pass
 
 
 #
@@ -67,6 +69,8 @@
 	self.mode = setting(self, ":SYS:STATUS",
 	  lambda s: self.mode_map.get(s, None))
 
+	self.lock_attr()
+
     def send(self, s):
 	power.send(self, s)
 	last_read = power.read(self)

Modified: developers/werner/ahrt/host/tmc/lib/scope.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/scope.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/scope.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -87,7 +87,7 @@
 
 	self.scope = scope
 	self.number = number
-	self.name = "CH"+str(number)
+	self.name = "CHAN"+str(number)
 
 	self.on = setting(scope, ":CHAN"+str(number)+":DISP",
 	  lambda on: on == "ON",
@@ -108,6 +108,7 @@
 	self.bwlimit = setting(scope, ":CHAN"+str(self.number)+":BWL",
 	  out_convert = self.scope.bwlimit_translate)
 
+	self.lock_attr()
 	self.forget()
 
     def forget(self):
@@ -158,7 +159,7 @@
 	
 class horizontal(settable):
 
-    state_map = ( "RUN", "STOP", "T'D", "WAIT", "SCAN", "AUTO" )
+    state_map = [ "RUN", "STOP", "T'D", "WAIT", "SCAN", "AUTO" ]
 
     def __init__(self, scope):
 	self.scope = scope
@@ -170,6 +171,7 @@
 	  lambda x: "%.9f" % x)
 	self.sweep = horizontal_trigger_setting(scope,
 	  trigger.set_sweep, trigger.get_sweep)
+	self.lock_attr()
 	self.forget()
 
     def forget(self):
@@ -177,6 +179,16 @@
 	self.scale = None
 	self.sweep = None
 
+    # "run" and "stop" are experimental: should we instead just have a common
+    # attribute "state" that then automatically determines what to do ? Also,
+    # should "run" send a ":STOP" first ?
+
+    def run(self):
+	self.scope.send(":RUN")
+
+    def stop(self):
+	self.scope.send(":STOP")
+
     def force(self):
 	self.scope.send(":FORC")
 
@@ -188,6 +200,7 @@
 
 
 class scope(instrument):
+    # Warning: "scope" doesn't lock itself !
     pass
 
 
@@ -308,6 +321,7 @@
 	    self.ch.append(channel(self, n))
 	self.trigger = None
 	self.hor = horizontal(self)
+	self.lock_attr()
 
     def forget(self):
 	for ch in self.ch:
@@ -353,7 +367,7 @@
 
     def wave(self, channels, start = None, end = None, step = None):
 	if not isinstance(channels, list):
-	    return self.download([channels], start, end, step)[0]
+	    return self.wave([channels], start, end, step)[0]
 	la = None
 	res = waves()
 	for ch in channels:

Modified: developers/werner/ahrt/host/tmc/lib/shape.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/shape.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/shape.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -54,6 +54,7 @@
 	self.freq = shape_setting(self, 0, self.__set_freq)
 	self.period = shape_setting(self, None, self.__set_period)
 
+	self.lock_attr()
 	self.set(**list)
 
     def __set_low(self, y):
@@ -106,7 +107,7 @@
 	return sin(2*pi*t*self.freq)*self.peak/2.0+self.offset
 
 
-class __shape_with_duty(shape):
+class shape_with_duty(shape):
 
     def __init__(self, init, **list):
 	self.duty = shape_setting(self, init, self.__set_duty)
@@ -122,20 +123,20 @@
 	self.duty = self.freq*n
 
 
-class square(__shape_with_duty):
+class square(shape_with_duty):
 
     def __init__(self, **list):
-	__shape_with_duty(self, 0.5, **list)
+	shape_with_duty.__init__(self, 0.5, **list)
 
     def get(self, t):
 	p = t*self.freq
 	return (self.low, self.high)[p-floor(p) < self.duty]
 
 
-class ramp(__shape_with_duty):
+class ramp(shape_with_duty):
 
     def __init__(self, **list):
-	__shape_with_duty(self, 1, **list)
+	shape_with_duty.__init__(self, 1, **list)
 
     def get(self, t):
 	p = t*self.freq

Modified: developers/werner/ahrt/host/tmc/lib/trigger.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/trigger.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/trigger.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -31,6 +31,7 @@
     def __init__(self):
 	self.channel = None
 	self.scope = None
+	# Warning: "trigger" doesn't lock itself !
 
     def source(self, channel, coupling = None):
 	if self.scope is not None:
@@ -46,7 +47,9 @@
 	    if coupling is not None:
 		self.scope.send(
 		  ":TRIG:"+self.mode+":COUP "+self.coupling_map[coupling])
-	    self.scope.send(":TRIG:"+self.mode+":SWE "+scope.sweep)
+	    old = self.scope.hor.sweep
+	    self.scope.hor.sweep = None
+	    self.scope.hor.sweep = old
 	    self.update()
 
     def send(self, *args):
@@ -59,11 +62,14 @@
 	return self.scope.query(*args)
 	
     def set_sweep(self, value):
-	self.scope.send(":TRIG:"+self.mode+":SWE "+self.sweep_map[value])
+	if value is not None:
+	    self.scope.send(":TRIG:"+self.mode+":SWE "+self.sweep_map[value])
 
     def get_sweep(self):
-	return self.sweep_map.index(self.scope.query(":TRIG:"+self.mode+":SWE"))
+	return self.sweep_map.index(
+	  self.scope.query(":TRIG:"+self.mode+":SWE?"))
 
+
 class slope:
     Rising, Falling, Both = range(3)
 
@@ -81,6 +87,7 @@
 	  lambda x: self.slope_map.index(x),
 	  lambda x: self.slope_map[x])
 	self.forget()
+	self.lock_attr()
 	self.set(**list)
 
     def forget(self):
@@ -88,8 +95,12 @@
 	self.slope = None
 
     def update(self):
-	self.level = self.level
-	self.slope = self.slope
+	old = self.level
+	self.level = None
+	self.level = old
+	old = self.slope
+	self.slope = None
+	self.slope = old
 
     def apply(self, wave):
 	# @@@ only digital waves for now

Modified: developers/werner/ahrt/host/tmc/lib/wave.py
===================================================================
--- developers/werner/ahrt/host/tmc/lib/wave.py	2008-09-08 22:40:16 UTC (rev 4637)
+++ developers/werner/ahrt/host/tmc/lib/wave.py	2008-09-09 23:15:52 UTC (rev 4638)
@@ -184,7 +184,7 @@
 	self.nxt = []
 	self.t = None
 	for w in waves:
-	    i = w.__iter__()
+	    i = iter(w)
 	    v = next_or_none(i)
 	    self.iter.append(i)
 	    self.nxt.append(v)
@@ -358,6 +358,8 @@
     def digitize(self, low, high = None):
 	if high is None:
 	    high = low
+	if high < low:
+	    raise hell
 	res = digital()
 	state = None
 	for p in self.data:




More information about the commitlog mailing list