From 5fbba2a5853d7498424c2e9cde72e3f217c65e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20K=C3=B6gl?= Date: Thu, 22 Nov 2012 07:22:33 +0100 Subject: [PATCH] logging, more events, some bugs/regressions fixed --- reflowctl/reflowctl_gui.py | 168 ++++++++++++++++++++++++++++++++----- 1 file changed, 149 insertions(+), 19 deletions(-) diff --git a/reflowctl/reflowctl_gui.py b/reflowctl/reflowctl_gui.py index 5f83d39..3c6a97a 100755 --- a/reflowctl/reflowctl_gui.py +++ b/reflowctl/reflowctl_gui.py @@ -9,6 +9,7 @@ from operator import attrgetter import xml.etree.ElementTree as etree import pylab +import numpy from PyQt4 import QtGui, QtCore from numpy import arange, sin, pi, array, linspace, arange @@ -96,7 +97,7 @@ def getTemperature(): return 20. -class TempLevel(object): +class TempLevel(QtCore.QObject): def __init__(self, name, temp, is_env=False): self.name = name self.temp = temp @@ -104,9 +105,12 @@ class TempLevel(object): self.color = None -class Solder(object): +class Solder(QtCore.QObject): - def __init__(self, name=str(), description=str()): + log_message = QtCore.pyqtSignal(str) + + def __init__(self, name=str(), description=str(), parent=None): + super(Solder, self).__init__(parent) self.name = name self.description = description self.temp_levels = list() @@ -142,8 +146,96 @@ class Solder(object): assert isinstance(ix, int) return self.temp_levels[ix] + def calc_rate(self, x1, y1, x2, y2): + return (y2 - y1) / (x2 - x1) + + def check_duration_constraints(self, temp_level, used): + + x = list() + y = list() + temp_levels = None + value = None + for temp_levels, value in self.durations: + tl_len = len(temp_levels) + if temp_levels and temp_levels[0] == temp_level and tl_len > 1: + if temp_level not in used: + used.add(temp_level) + x.append(self.time) + y.append(temp_level.temp) + + if tl_len == 2: + y.append(temp_levels[1].temp) + used.add(temp_levels[1]) + self.time += value + x.append(self.time) + elif tl_len >= 3: + part = value / (tl_len - 1) + for tl in temp_levels[1:]: + used.add(tl) + + self.time += part + x.append(self.time) + y.append(tl.temp) + + self.log.append("* Duration connection: TempLevel %r connected to TempLevels %r" % (temp_level.name, [tl.name for tl in temp_levels[1:]])) + + return x, y + + def check_rate_constraints(self, temp_level, used): + x = list() + y = list() + for temp_levels, value in self.rates: + tl_len = len(temp_levels) + if temp_levels and temp_levels[0] == temp_level and tl_len > 1: + if temp_level not in used: + used.add(temp_level) + x.append(self.time) + y.append(temp_level.temp) + + self.time += (temp_levels[1].temp - temp_level.temp) / value + used.add(temp_levels[1]) + x.append(self.time) + y.append(temp_levels[1].temp) + + self.log.append("* Rate connection: TempLevel %r connected to TempLevels %r" % (temp_level.name, [tl.name for tl in temp_levels[1:]])) + + return x, y + def calc_profile(self): + self.log = list() + x = list() + y = list() + duration_points = dict() + rate_points = dict() + self.time = 0 + used = set() + unused = list() + for temp_level in self.temp_levels: + dur_x, dur_y = self.check_duration_constraints(temp_level, used) + rate_x, rate_y = self.check_rate_constraints(temp_level, used) + + print dur_x, dur_y + print rate_x, rate_y + print + if len(dur_x) > 0: + x.extend(dur_x) + y.extend(dur_y) + elif len(rate_x) > 0: + x.extend(rate_x) + y.extend(rate_y) + else: + if temp_level not in used: + unused.append(temp_level) + + self.log.append("") + map(self.log.append, ["* Missing Connection: %r" % tl.name for tl in unused]) + self.log_message.emit("\n".join(self.log)) + del self.log + return array(map(float, x)), array(map(float, y)), max(x), max(y), used, unused + + def calc_profile_old(self): + x = list() y = list() duration_points = dict() @@ -202,11 +294,11 @@ class Solder(object): @staticmethod - def unpack(filename): + def unpack(filename, parent): xmltree = etree.parse(filename) root = xmltree.getroot() solder_node = root[0] - s = Solder(solder_node.attrib["name"], solder_node.attrib["description"]) + s = Solder(solder_node.attrib["name"], solder_node.attrib["description"], parent) env_count = 0 for temp_level in solder_node.findall("state"): tstr = temp_level.attrib["temperature"] @@ -276,7 +368,7 @@ class SolderListModel(QtCore.QAbstractListModel): dirlisting = filter(lambda x: os.path.splitext(x)[1] == ".xml", os.listdir(dirname)) self.listdata = [] for p in dirlisting: - self.listdata.append(Solder.unpack(os.path.join(dirname, p))) + self.listdata.append(Solder.unpack(os.path.join(dirname, p), self)) self.listdata.sort(key=lambda x: x.name) self.reset() @@ -390,6 +482,7 @@ class TempLevelModel(QtCore.QAbstractTableModel): assert isinstance(temp_levels, list) self.temp_levels = temp_levels self.reset() + print self.setTempLevels def clear(self): @@ -404,6 +497,14 @@ class Plotter(FigureCanvas): self.fig = Figure(figsize=(width, height), dpi=dpi) super(Plotter, self).__init__(self.fig) self.axes = self.fig.add_subplot(111) + #self.fig.subplots_adjust( + #left=0.1, + #bottom=0.05, + #right=0.9, + #top=0.95, + #wspace=0, + #hspace=0 + #) self.axes.set_axis_bgcolor('white') self.axes.set_title(u'reflow profile', size=12) @@ -432,20 +533,19 @@ class Plotter(FigureCanvas): def update_figure(self): if self.updated: - updated = False + self.updated = False self.axes.patches = list() self.axes.texts = list() self.x = list() self.y = list() - try: - self.x, self.y, self.xmax, self.ymax, self.duration_points, self.rate_points = self.solder.calc_profile() + self.x, self.y, self.xmax, self.ymax, self.used, self.unused = self.solder.calc_profile() - for ix, (a, b) in enumerate(zip(self.x[:-1], self.y[:-1])): - annotation.slope_marker((a + 10, b), (self.y[ix+1] - b) / (self.x[ix+1] - a), ax=self.axes) - except Exception, e: - self.xmax = 500 - self.ymax = 300 + for ix, (a, b) in enumerate(zip(self.x[:-1], self.y[:-1])): + slope = (self.y[ix+1] - b) / (self.x[ix+1] - a) + if not (numpy.isnan(slope) or numpy.isinf(slope)): + origin = (a + 10, b) + annotation.slope_marker(origin, slope, ax=self.axes) self.plot_data.set_xdata(self.x) self.plot_data.set_ydata(self.y) @@ -453,7 +553,7 @@ class Plotter(FigureCanvas): self.axes.set_xbound(lower=0, upper=self.xmax + 20) self.axes.set_ybound(lower=0, upper=self.ymax + 20) - self.axes.set_yticks([state.temp for state in self.solder.temp_levels]) + self.axes.set_yticks(self.y) self.axes.set_xticks(self.x) #duration_widget = self.myapp.duration_widget @@ -468,11 +568,12 @@ class Plotter(FigureCanvas): transform=self.axes.transData, figure=self.fig, color=str(temp_level.color.name()), label="name", zorder=1) lines.append(line) - self.axes.legend(("Estimated profile",)) + self.axes.legend(("Estimated profile",), loc=2) self.draw() def solder_changed(self): self.solder.changed = True + self.updated = True def setData(self, solder): self.solder = solder @@ -731,9 +832,11 @@ class DurationConstraintWidget(ConstraintWidget): def _set_data(self, solder): self.spinbox_block = True self.constraint_model.constraint_list = solder.durations + self.constraint_model.reset() ix = self.constraint_model.index(0, 0) self._constraint_selected(ix) self.constraint_view.setCurrentIndex(ix) + print self._set_data def _constraint_selected(self, index): if index.isValid(): @@ -743,8 +846,9 @@ class DurationConstraintWidget(ConstraintWidget): self.controls.value.setValue(value) else: self.spinbox_block = True - self.selected_temp_levels.setTempLevels([]) + self.selected_temp_levels.setTempLevels(list()) self.controls.value.setValue(0) + print self._constraint_selected class OvenControlsWidget(QtGui.QWidget): @@ -812,7 +916,7 @@ class RateConstraintWidget(ConstraintWidget): def _set_data(self, solder): self.spinbox_block = True self.constraint_model.constraint_list = solder.rates - + self.constraint_model.reset() ix = self.constraint_model.index(0, 0) self._constraint_selected(ix) self.constraint_view.setCurrentIndex(ix) @@ -948,6 +1052,12 @@ class TempLevelWidget(QtGui.QWidget): #self.controls.add_button.setEnabled(not is_end) self.controls.remove_button.setEnabled(not is_env) + +class Report(QtGui.QWidget): + def __init__(self, parent=None): + super(Report, self).__init__(parent) + + class ApplicationWindow(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) @@ -1033,6 +1143,16 @@ class ApplicationWindow(QtGui.QMainWindow): QtCore.SIGNAL("solder_changed()"), self.plotter.solder_changed) + self.connect( + self.duration_widget, + QtCore.SIGNAL("solder_changed()"), + self.plotter.solder_changed) + + self.connect( + self.rate_widget, + QtCore.SIGNAL("solder_changed()"), + self.plotter.solder_changed) + self.solder_widget = SolderWidget(self) self.connect( @@ -1048,11 +1168,18 @@ class ApplicationWindow(QtGui.QMainWindow): self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical, self) + self.plotter_splitter = QtGui.QSplitter(self) + self.profile_log = QtGui.QTextEdit(self) + self.solder_selected(self.solder_widget.solder_model.index(0,0)) + + self.plotter_splitter.addWidget(self.plotter) + self.plotter_splitter.addWidget(self.profile_log) + self.splitter.addWidget(self.settings_widget) self.splitter.addWidget(self.controls_widget) - self.splitter.addWidget(self.plotter) + self.splitter.addWidget(self.plotter_splitter) self.splitter.setStretchFactor(0, 2) self.splitter.setStretchFactor(1, 2) self.splitter.setStretchFactor(2, 8) @@ -1082,10 +1209,13 @@ class ApplicationWindow(QtGui.QMainWindow): if index.isValid(): solder = self.solder_widget.solder_model.listdata[index.row()] self.temp_level_widget.setData(solder) + print "pre duration" self.duration_widget.setData(solder) + print "post duration" self.rate_widget.setData(solder) self.plotter.setData(solder) self.controls_widget.temp_level_widget.setData(solder) + solder.log_message.connect(self.profile_log.setPlainText) def open_controls_view(self): print self.open_controls_view