def configure(self): if self.configWindow: self.configWindow.closeWindow() self.configWindow = ScopeConfigWindow(self)
class Oscilloscope(): def __init__(self, geom=None): self.window = None self.configWindow = None self.canvasInited = False # add more lines by adding colors self.colors = ["blue", "green", "red", "cyan", "magenta"] self.probes = [] self.numActiveProbes = 0 # range for the data (xaxis always starts at zero) self.maxNumelems = 60 self.setTimeAxis(100) self.yrange = (None, None) self.opts = {'Title':'Untitled', 'X Label':'Cycles Past (Sample Period='+ str(self.samplesPerElem)+')', 'Y Label':'Value', 'X Scale':self.xrange, 'Y Scale':'auto'} self.ymin, self.ymax = None, None self.ybounds = None, None self.ptRadius = 2 self.legend = True # just pay attention to the position part, since the canvas is a # fixed size self.geom = None if geom: self.geom = geom[geom.find('+'):] def openWindow(self): # already open; don't open again if self.window: return self.window = Tkinter.Toplevel() self.window.wm_title("Soar Oscilloscope") self.window.protocol("WM_DELETE_WINDOW", self.closeWindow) if self.geom: self.window.geometry(self.geom) self.canvWidth, self.canvHeight = 600, 400 self.canvas = Tkinter.Canvas(self.window, width = self.canvWidth, height = self.canvHeight, background = "white") self.canvas.pack() self.button = Tkinter.Button(self.window, text="Configure Oscilloscope", command = self.configure) self.button.pack() self.makeCanvasObjects() self.canvas.wait_visibility() self.setStaticObjects() def configure(self): if self.configWindow: self.configWindow.closeWindow() self.configWindow = ScopeConfigWindow(self) def doneConfiguring(self): self.configWindow = None self.setStaticObjects() def deleteScalingCanvasObjects(self): def deleteTask(): for i in range(self.lines): for j in range(self.lines[i]): self.canvas.delete(self.lines[i][j]) for j in range(self.points[i]): self.canvas.delete(self.points[i][j]) form.main.tk_enqueue(deleteTask) def makeCanvasObjects(self): if not self.window: return if self.canvasInited: self.deleteScalingCanvasObjects() # number of text objects doesn't change with rescale else: self.canvasInited = True # clear rect comes first so everything else shows up #self.clearRect = self.canvas.create_rectangle(0,0, # self.canvWidth, # self.canvHeight, # fill="white") # outline rect needs to come first (don't draw over pts) self.outlineRect = self.canvas.create_rectangle(0,0,1,1, fill="white") self.xminText = self.canvas.create_text(0, 0, text="") self.xmaxText = self.canvas.create_text(0, 0, text="") self.yminText = self.canvas.create_text(0, 0, text="") self.ymaxText = self.canvas.create_text(0, 0, text="") self.yLabelText = self.canvas.create_text(0, 0, text="") self.xLabelText = self.canvas.create_text(0, 0, text="") self.titleText = self.canvas.create_text(0, 0, text="") if self.legend: self.legendLines = [] self.legendText = [] self.legendPoints = [] for color in self.colors: l = self.canvas.create_line(-2, -1, -1, -1, fill=color, smooth=1, width=3) self.legendLines.append(l) t = self.canvas.create_text(0, 0, text="") self.legendText.append(t) p = self.canvas.create_oval(-2, -2, -1, -1, fill=color, outline=color) self.legendPoints.append(p) self.lines = [] self.points = [] rad = self.ptRadius # make all the objects off the canvas x0,y0 = -2, -1 x1,y1 = -1, -1 for i in range(len(self.colors)): color = self.colors[i] self.lines.append([]) self.points.append([]) for j in range(self.numelems): if j < self.numelems-1: l = self.canvas.create_line(x0,y0,x1,y1, fill=color, smooth=1, width=3) self.lines[i].append(l) p = self.canvas.create_oval(x1-rad, y1-rad, x1+rad, x1+rad, fill=color, outline=color) self.points[i].append(p) def setCanvasText(self, item, x, y, **opts): self.canvas.coords(item, x, y) self.canvas.itemconfig(item, opts) def closeWindow(self): if self.window: self.geom = self.window.geometry() app.soar.scope_geom = self.geom self.window.destroy() self.window = None if self.configWindow: self.configWindow.closeWindow() self.configWindow = None def setTimeAxis(self, desiredRange=None): if not desiredRange: desiredRange = self.opts['X Scale'] if desiredRange < 1: return self.numelems = desiredRange + 1 self.samplesPerElem = 1 while self.numelems > self.maxNumelems: self.samplesPerElem += 1 self.numelems = int((desiredRange+1)/self.samplesPerElem) # TODO: put appropriate label on graph self.xrange = desiredRange for p in self.probes: if p: p.resize(self.numelems, self.samplesPerElem) self.makeCanvasObjects() self.setStaticObjects() def clearProbes(self): self.probes = [] self.ymin, self.ymax = None, None def makeFunc(self, func, i=None): if func.func_code.co_argcount == 0: if i is not None: return lambda inp: func()[i] else: return lambda inp: func() elif func.func_code.co_argcount == 1: if i is not None: return lambda inp: func(inp)[i] else: return lambda inp: func(inp) else: sys.stderr.write("Dynamic plot function takes too many arguments") return lambda inp: 0.0 def addProbeFunction(self, names, func, functext=None, initVal=0): numavail = len(self.colors) - len(self.probes) if numavail == 0: sys.stderr.write("All available probes are in use. Signal will not be plotted") return if type(names) == list or type(names) == tuple: numprobes = min(numavail, len(names)) if numprobes < len(names): sys.stderr.write("Not enough available probes for all signals. Only "+str(numprobes)+" signals will be plotted.") for i in range(numprobes): text = functext if functext else str(func) text = text+"["+str(i)+"]" self.addProbe(names[i], self.makeFunc(func, i), text, initVal) else: self.addProbe(names, self.makeFunc(func), functext if functext else str(func), initVal) self.setStaticObjects() def addProbe(self, name, functext, initVal=0): func = lambda: eval(functext) self.addProbeFunction(name, func, functext, initVal) def setProbeText(self, probeidx, name, functext): func = lambda: eval(functext) self.setProbe(probeidx, name, func, functext) def addProbe(self, name, func, functext, initVal=0): self.probes.append(Probe(name, func, functext, self.numelems, self.samplesPerElem, initVal)) self.setStaticObjects() def setExtremes(self, (minv, maxv)): self.ymin = minv if self.ymin==None else min(self.ymin, minv) self.ymax = maxv if self.ymax==None else max(self.ymax, maxv)