more robust implementation, prepared communication with oven, started oven controls view

This commit is contained in:
Stefan Kögl 2012-11-21 12:06:39 +01:00
parent 58d225607f
commit 81c5a17241
1 changed files with 329 additions and 93 deletions

View File

@ -1,8 +1,9 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys, os, random, copy
import sys, os, random, copy, struct
from collections import deque
from operator import attrgetter
import xml.etree.ElementTree as etree
@ -16,29 +17,80 @@ from matplotlib.figure import Figure
from matplotlib.lines import Line2D
from matplotlib.path import Path
import matplotlib.patches as patches
#from mpltools import annotation
#from mpltools import annotation-
progname = os.path.basename(sys.argv[0])
progversion = "0.1"
def calc_colors(count):
if count == 1:
return [QtGui.QColor(0, 255, 0),]
r = 0
g = 255
step = int(512. / (count-1))
colors = list()
print "step", step
for i in range(count):
colors.append(QtGui.QColor(r, g, 0))
if r < 255:
r += step
if r > 255:
g -= r - 255
g -= (r - 256)
r = 255
g = max(0, g)
else:
g -= step
g = max(0, g)
return colors
def set_colors(temp_levels):
colors = calc_colors(len(temp_levels) - 1)
ix = 0
for temp_level in temp_levels:
if not temp_level.is_env:
temp_level.color = colors[ix]
ix += 1
else:
temp_level.color = QtGui.QColor("black")
def create_profile_header(x_list, y_list):
tpl = "#ifndef _H_SOLDER_PROFILE\n" \
"#define _H_SOLDER_PROFILE\n" \
"\n" \
"%s\n" \
"\n" \
"};\n" \
"\n" \
"#endif\n"
data_tpl = "unsigned int profile_%d[%d][2] = \n%s\n" \
s = list()
ix = 0
for x, y in zip(x_list, y_list):
tmp = list()
for a, b in zip(x, y):
tmp.append("{%d, %d}" % (a, b))
s.append(data_tpl % (ix, len(x), "\n".join(tmp)))
ix += 1
open("test.h", "w").write(tpl % ("\n".join(s)))
def create_profile_packet(x, y):
# msg = [length, x_0, y_0,x_1, y_1, ..., x_length-1, y_length-1]
tmp = [len(x) * 2 * 2,]
for a, b in zip(x, y):
tmp.append(a)
tmp.append(b)
tpl = "H" + (len(x) * 2) * "H"
res = struct.pack(tpl, *tmp)
return res
def getTemperature():
return 20.
@ -60,6 +112,7 @@ class Solder(object):
self.temp_levels = list()
self.durations = list()
self.rates = list()
self.changed = False
def __unicode__(self):
return unicode(self.name)
@ -100,12 +153,12 @@ class Solder(object):
for ix, temp_level in enumerate(self.temp_levels):
if temp_level != self.temp_levels[0] and temp_level not in used_temp_levels:
ix = self.temp_levels.index(temp_level)
raise ValueError("TempLevel %r not connected to %r" % (temp_level.name[ix-1], self.temp_levels[ix].name))
raise ValueError("TempLevel %r not connected to %r" % (self.temp_levels[ix-1].name, self.temp_levels[ix].name))
temp_levels = None
duration = None
for sts, dur in self.durations:
if sts[0] == temp_level:
if sts and sts[0] == temp_level:
duration = dur
temp_levels = sts
break
@ -137,7 +190,7 @@ class Solder(object):
duration_points[ix] = (x[-2:], y[-2:])
else:
for ex, (sts, rate) in enumerate(self.rates):
if sts[0] == temp_level:
if sts and sts[0] == temp_level:
used_temp_levels.add(sts[1])
duration = (sts[1].temp - temp_level.temp) / rate
self.time += duration
@ -167,14 +220,7 @@ class Solder(object):
env_count += 1
s.add_temp_level(temp_level.attrib["name"], temp, is_env)
colors = calc_colors(len(s.temp_levels) - 1)
ix = 0
for temp_level in s.temp_levels:
if not temp_level.is_env:
temp_level.color = colors[ix]
ix += 1
else:
temp_level.color = QtGui.QColor("black")
set_colors(s.temp_levels)
for duration in solder_node.findall("duration"):
temp_levels = list()
@ -225,7 +271,9 @@ class SolderListModel(QtCore.QAbstractListModel):
def create_solder(self):
solder = Solder("new", "")
solder.add_temp_level("environment temp", getTemperature(), True)
tl = solder.add_temp_level("environment temp", getTemperature(), True)
tl.color = QtGui.QColor(0, 0, 0)
self.listdata.append(solder)
self.reset()
@ -291,9 +339,8 @@ class TempLevelModel(QtCore.QAbstractTableModel):
return tmp
def add_temp_level(self, index, temp_level):
self.beginInsertRows(QtGui.QModelIndex(), index.row(), 1)
self.temp_levels.temp_levels.insert(index.row(), temp_level)
self.endInsertRows()
self.temp_levels.insert(index.row() + 1, temp_level)
set_colors(self.temp_levels)
self.reset()
self._changed = True
@ -346,23 +393,23 @@ class Plotter(FigureCanvas):
updated = False
self.x, self.y, self.xmax, self.ymax, self.duration_points, self.rate_points = self.solder.calc_profile()
#for states, value in self.durations.iteritems():
#annotation.slope_marker((states[0])
#for states, value in self.durations.iteritems():
#annotation.slope_marker((states[0])
self.axes.set_xbound(lower=0, upper=self.xmax + 20)
self.axes.set_ybound(lower=0, upper=self.ymax + 20)
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_xticks(self.x)
self.axes.set_yticks([state.temp for state in self.solder.temp_levels])
self.axes.set_xticks(self.x)
self.plot_data.set_xdata(self.x)
self.plot_data.set_ydata(self.y)
self.plot_data.set_zorder(20)
self.plot_data.set_xdata(self.x)
self.plot_data.set_ydata(self.y)
self.plot_data.set_zorder(20)
duration_widget = self.myapp.duration_widget
duration_widget = self.myapp.duration_widget
#self.selection_data.set_xdata(array(da))
#self.selection_data.set_ydata(array(db))
#self.selection_data.set_xdata(array(da))
#self.selection_data.set_ydata(array(db))
self.fig.lines = lines = list()
for temp_level in self.solder.temp_levels:
@ -374,6 +421,10 @@ class Plotter(FigureCanvas):
self.axes.legend(("Estimated profile",))
self.draw()
def setData(self, solder):
self.solder = solder
self.updated = True
class AddRemoveWidget(QtGui.QWidget):
def __init__(self, parent, with_upown=True):
@ -395,6 +446,8 @@ class AddRemoveWidget(QtGui.QWidget):
self.down_button = QtGui.QPushButton("Down")
self._layout.addWidget(self.up_button)
self._layout.addWidget(self.down_button)
self.up_button.setStyleSheet(sh)
self.down_button.setStyleSheet(sh)
self._layout.addStretch(4)
@ -437,10 +490,10 @@ class ConstraintListModel(QtCore.QAbstractListModel):
class ConstraintWidget(QtGui.QWidget):
def __init__(self, name, solder):
def __init__(self, name):
super(ConstraintWidget, self).__init__()
self.name = name
#self.solder = solder
self.spinbox_block = False
self.constraint_model = ConstraintListModel(self) # constraint selection
@ -501,7 +554,7 @@ class ConstraintWidget(QtGui.QWidget):
self.connect(
self.constraint_controls.add_button,
QtCore.SIGNAL("clicked()"),
self.constraint_model.append_constraint)
self.add_constraint)
self.connect(
self.constraint_controls.remove_button,
@ -514,18 +567,36 @@ class ConstraintWidget(QtGui.QWidget):
self.constraint_value_changed)
def setData(self, solder):
print self.setData, 1
self.solder = solder
print self.setData, 2
self.all_temp_levels.setTempLevels(self.solder.temp_levels)
print self.setData, 3
self._set_data()
print self.setData, 4
self.all_temp_levels.setTempLevels(solder.temp_levels)
self._set_data(solder)
self.set_controls()
def set_controls(self):
if not self.constraint_model.constraint_list:
self.controls.value.setEnabled(False)
self.constraint_controls.remove_button.setEnabled(False)
self.controls.add_button.setEnabled(False)
self.controls.remove_button.setEnabled(False)
self.controls.up_button.setEnabled(False)
self.controls.down_button.setEnabled(False)
else:
self.controls.value.setEnabled(True)
self.constraint_controls.remove_button.setEnabled(True)
self.controls.add_button.setEnabled(True)
self.controls.remove_button.setEnabled(True)
self.controls.up_button.setEnabled(True)
self.controls.down_button.setEnabled(True)
def add_constraint(self):
self.constraint_model.append_constraint()
self.set_controls()
def _constraint_selected(self, index):
raise NotImplementedError()
def _set_data(self):
def _set_data(self, solder):
raise NotImplementedError()
def add_temp_level_to_constraint(self):
@ -548,21 +619,25 @@ class ConstraintWidget(QtGui.QWidget):
del self.constraint_model.constraint_list[src_row]
self.constraint_model.reset()
self.selected_temp_levels.clear()
self.set_controls()
def constraint_value_changed(self, value):
print self.constraint_value_changed
if self.spinbox_block:
self.spinbox_block = False
return
print
print
print "IIIIEK"
print
src_index = self.constraint_view.currentIndex().row()
self.constraint_model.constraint_list[src_index][1] = value
def slot_temp_level_removed(self, temp_level):
print "temp_level"
deletes = deque()
ix = 0
for temp_levels, v in self.constraint_model.constraint_list:
if temp_level in temp_levels:
deletes.appendleft(ix)
ix += 1
for i in deletes:
del self.constraint_model.constraint_list[i]
self.reset()
def temp_level_up(self):
@ -578,50 +653,116 @@ class ConstraintWidget(QtGui.QWidget):
class DurationConstraintWidget(ConstraintWidget):
def _set_data(self):
def _set_data(self, solder):
self.spinbox_block = True
print self._set_data, 1
self.constraint_model.constraint_list.extend(self.solder.durations)
print self._set_data, 2
self.constraint_model.constraint_list = solder.durations
ix = self.constraint_model.index(0, 0)
print self._set_data, 3
self.constraint_view.setCurrentIndex(ix)
print self._set_data, 4
self._constraint_selected(ix)
print self._set_data, 5
self.constraint_view.setCurrentIndex(ix)
def _constraint_selected(self, index):
print self._constraint_selected
self.spinbox_block = True
temp_levels, value = self.constraint_model.constraint_list[index.row()]
self.selected_temp_levels.setTempLevels(temp_levels)
self.controls.value.setValue(value)
if index.isValid():
self.spinbox_block = True
temp_levels, value = self.constraint_model.constraint_list[index.row()]
self.selected_temp_levels.setTempLevels(temp_levels)
self.controls.value.setValue(value)
else:
self.spinbox_block = True
self.selected_temp_levels.setTempLevels([])
self.controls.value.setValue(0)
class OvenControlsWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(OvenControlsWidget, self).__init__(parent)
self.left = QtGui.QWidget(self)
self.temp_lcd = QtGui.QLCDNumber(self)
self.time_lcd = QtGui.QLCDNumber(self)
self.time_lcd.setDigitCount(3)
self.temp_lcd.setDigitCount(3)
palette = QtGui.QPalette()
palette.setColor(QtGui.QPalette.WindowText, QtCore.Qt.black)
self.temp_lcd.setPalette(palette)
self.time_lcd.setPalette(palette)
self.time_lcd.setSmallDecimalPoint(False)
self.temp_lcd.setSmallDecimalPoint(False)
self.temp_lcd.setSegmentStyle(2)
self.time_lcd.setSegmentStyle(2)
self.time_lcd.display("000")
self.temp_lcd.display("142")
self.temp_label = QtGui.QLabel("Time", self)
self.time_label = QtGui.QLabel("Temp", self)
self.temp_label.setBuddy(self.temp_lcd)
self.time_label.setBuddy(self.time_lcd)
self.sicon = QtGui.QIcon.fromTheme("media-playback-start")
self.picon = QtGui.QIcon.fromTheme("media-playback-pause")
self.start_button = QtGui.QPushButton(self.sicon, "start")
self.start_button.setCheckable(True)
layout = QtGui.QHBoxLayout(self.left)
layout.addWidget(self.time_label)
layout.addWidget(self.time_lcd)
layout.addWidget(self.temp_label)
layout.addWidget(self.temp_lcd)
layout.addWidget(self.start_button)
layout2 = QtGui.QHBoxLayout()
self.temp_level_widget = TempLevelWidget(self, True)
layout2.addWidget(self.temp_level_widget, 2)
layout2.addWidget(self.left, 4)
self.setLayout(layout2)
self.connect(
self.start_button,
QtCore.SIGNAL("clicked()"),
self.toggle_button)
def toggle_button(self):
if self.start_button.isChecked():
self.start_button.setIcon(self.picon)
else:
self.start_button.setIcon(self.sicon)
class RateConstraintWidget(ConstraintWidget):
def _set_data(self):
print self._set_data
def _set_data(self, solder):
self.spinbox_block = True
self.constraint_model.constraint_list.extend(self.solder.rates)
self.constraint_model.constraint_list = solder.rates
ix = self.constraint_model.index(0, 0)
self.constraint_view.setCurrentIndex(ix)
self._constraint_selected(ix)
self.constraint_view.setCurrentIndex(ix)
def _constraint_selected(self, index):
print self._constraint_selected
self.spinbox_block = True
temp_levels, value = self.constraint_model.constraint_list[index.row()]
self.selected_temp_levels.setTempLevels(temp_levels)
self.controls.value.setValue(value)
if index.isValid():
self.spinbox_block = True
temp_levels, value = self.constraint_model.constraint_list[index.row()]
self.selected_temp_levels.setTempLevels(temp_levels)
self.controls.value.setValue(value)
else:
self.spinbox_block = True
self.selected_temp_levels.setTempLevels([])
self.controls.value.setValue(0)
class TempLevelWidget(QtGui.QWidget):
temp_level_removed = QtCore.pyqtSignal(TempLevel)
def __init__(self, parent, solder):
def __init__(self, parent, readonly=False):
super(TempLevelWidget, self).__init__(parent)
self.temp_level_model = TempLevelModel(self)
@ -632,11 +773,8 @@ class TempLevelWidget(QtGui.QWidget):
self.temp_level_view.horizontalHeader().setStretchLastSection(True)
self.temp_level_view.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.controls = AddRemoveWidget(self)
h = QtGui.QHBoxLayout()
h.addWidget(self.temp_level_view)
h.addWidget(self.controls)
self.setLayout(h)
self.connect(
@ -644,31 +782,69 @@ class TempLevelWidget(QtGui.QWidget):
QtCore.SIGNAL("clicked(QModelIndex)"),
self.temp_level_selected)
self.connect(
self.controls.remove_button,
QtCore.SIGNAL("clicked()"),
self.remove_temp_level)
if not readonly:
self.controls = AddRemoveWidget(self)
h.addWidget(self.controls)
self.connect(
self.controls.add_button,
QtCore.SIGNAL("clicked()"),
self.add_temp_level)
self.connect(
self.controls.remove_button,
QtCore.SIGNAL("clicked()"),
self.remove_temp_level)
self.connect(
self.controls.up_button,
QtCore.SIGNAL("clicked()"),
self.temp_level_up)
self.connect(
self.controls.down_button,
QtCore.SIGNAL("clicked()"),
self.temp_level_down)
def setData(self, solder):
self.temp_level_model.setTempLevels(solder.temp_levels)
self.temp_level_view.resizeColumnsToContents()
def add_temp_level(self):
index = self.temp_level_view.currentIndex()
self.temp_level_model.add_temp_level(index,TempLevel("new", 0))
self.temp_level_model.add_temp_level(index, TempLevel("new " + str(self.temp_level_model.rowCount(None)), 0))
self.temp_level_view.setCurrentIndex(self.temp_level_model.index(index.row() + 1, 0))
self.plotter.solder.changed = True
def remove_temp_level(self):
self.temp_level_removed.emit(
self.temp_level_model.remove_temp_level(
self.temp_level_view.currentIndex().row()))
self.plotter.solder.changed = True
def temp_level_up(self):
dst_row = self.temp_level_view.currentIndex().row()
self.temp_level_model.temp_levels[dst_row - 1], self.temp_level_model.temp_levels[dst_row] = self.temp_level_model.temp_levels[dst_row], self.temp_level_model.temp_levels[dst_row - 1]
self.temp_level_model.reset()
self.plotter.solder.changed = True
def temp_level_down(self):
dst_row = self.selected_temp_levels_view.currentIndex().row()
self.temp_level_model.temp_levels[dst_row], self.temp_level_model.temp_levels[dst_row + 1] = self.temp_level_model.temp_levels[dst_row + 1], self.temp_level_model.temp_levels[dst_row]
self.temp_level_model.reset()
self.plotter.solder.changed = True
def temp_level_selected(self, index):
if index.isValid():
row = index.row()
is_env = self.temp_level_model.temp_levels[row].is_env
is_end = row == len(self.temp_level_model.temp_levels) - 1
self.controls.add_button.setEnabled(not is_end)
#is_end = row == len(self.temp_level_model.temp_levels) - 1
#self.controls.add_button.setEnabled(not is_end)
self.controls.remove_button.setEnabled(not is_env)
print "remove_button state", self.controls.remove_button.isEnabled()
class ApplicationWindow(QtGui.QMainWindow):
def __init__(self):
@ -679,12 +855,41 @@ class ApplicationWindow(QtGui.QMainWindow):
self.setWindowTitle("application main window")
self.file_menu = QtGui.QMenu('&File', self)
self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.file_menu.addAction('&Create profile header', self.create_header,
QtCore.Qt.CTRL + QtCore.Qt.Key_C)
self.file_menu.addAction('&Save plot', self.save_plot,
QtCore.Qt.CTRL + QtCore.Qt.Key_S)
self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.menuBar().addMenu(self.file_menu)
self.view_menu = QtGui.QMenu('&View', self)
self.profile_view_action = self.view_menu.addAction("&Profile View")
self.controls_view_action = self.view_menu.addAction("&Oven Controls View")
self.view_group = QtGui.QActionGroup(self)
self.view_group.setExclusive(True)
self.view_group.addAction(self.controls_view_action)
self.view_group.addAction(self.profile_view_action)
self.profile_view_action.setCheckable(True)
self.controls_view_action.setCheckable(True)
self.connect(self.profile_view_action,
QtCore.SIGNAL("triggered()"),
self.open_profile_view)
self.connect(self.controls_view_action,
QtCore.SIGNAL("triggered()"),
self.open_controls_view)
self.profile_view_action.setChecked(True)
self.menuBar().addMenu(self.view_menu)
self.help_menu = QtGui.QMenu('&Help', self)
self.menuBar().addSeparator()
self.menuBar().addMenu(self.help_menu)
@ -698,13 +903,17 @@ class ApplicationWindow(QtGui.QMainWindow):
self.solder_controls = AddRemoveWidget(self, False)
self.tab_widget = QtGui.QTabWidget(self)
self.temp_level_widget = TempLevelWidget(self, self.solder_model.listdata[0])
self.duration_widget = DurationConstraintWidget(u"Duration (s)", self.solder_model.listdata[0])
self.rate_widget = RateConstraintWidget(u"Rate (°C/s)", self.solder_model.listdata[0])
self.temp_level_widget = TempLevelWidget(self)
self.duration_widget = DurationConstraintWidget(u"Duration (s)")
self.rate_widget = RateConstraintWidget(u"Rate (°C/s)")
self.tab_widget.addTab(self.temp_level_widget, u"Temperature Levels")
self.tab_widget.addTab(self.duration_widget, u"Duration (s)")
self.tab_widget.addTab(self.rate_widget, u"Rate (°C/s)")
self.plotter = Plotter(self, self, width=5, height=4, dpi=self.dpi)
self.controls_widget = OvenControlsWidget(self)
self.controls_widget.setVisible(False)
self.connect(
self.solder_view,
QtCore.SIGNAL("clicked(QModelIndex)"),
@ -721,16 +930,20 @@ class ApplicationWindow(QtGui.QMainWindow):
pl.addWidget(self.solder_controls, 1)
pl.addWidget(self.tab_widget, 6)
self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical, self)
self.plotter = Plotter(self, self, width=5, height=4, dpi=self.dpi)
self.solder_view.setCurrentIndex(self.solder_model.index(0,0))
self.solder_selected(self.solder_model.index(0,0))
self.splitter.addWidget(self.settings_widget)
self.splitter.addWidget(self.controls_widget)
self.splitter.addWidget(self.plotter)
self.splitter.setStretchFactor(0, 2)
self.splitter.setStretchFactor(1, 8)
self.splitter.setStretchFactor(1, 2)
self.splitter.setStretchFactor(2, 8)
self.solder_controls.hide()
self.setCentralWidget(self.splitter)
@ -739,20 +952,43 @@ class ApplicationWindow(QtGui.QMainWindow):
self.temp_level_widget.temp_level_removed.connect(self.duration_widget.slot_temp_level_removed)
self.temp_level_widget.temp_level_removed.connect(self.rate_widget.slot_temp_level_removed)
def getPlotter(self):
return self.plotter
def create_header(self):
x_list = list()
y_list = list()
for solder in self.solder_model.listdata:
x, y, xmax, ymax, duration_points, rate_points = solder.calc_profile()
x_list.append(x)
y_list.append(y)
print "packet", repr(create_profile_packet(x, y))
create_profile_header(x_list, y_list)
def solder_selected(self, index):
if index.isValid():
solder = self.plotter.solder = self.solder_model.listdata[index.row()]
self.temp_level_widget.temp_level_model.setTempLevels(solder.temp_levels)
self.temp_level_widget.temp_level_view.resizeColumnsToContents()
solder = self.solder_model.listdata[index.row()]
self.temp_level_widget.setData(solder)
self.duration_widget.setData(solder)
self.rate_widget.setData(solder)
self.plotter.updated = True
self.plotter.setData(solder)
self.controls_widget.temp_level_widget.setData(solder)
def open_controls_view(self):
print self.open_controls_view
self.controls_widget.show()
self.settings_widget.hide()
def open_profile_view(self):
print self.open_profile_view
self.controls_widget.hide()
self.settings_widget.show()
def save_plot(self):
file_choices = "PNG (*.png)|*.png"
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', 'qtplot.png')
print type(filename), dir(filename)
self.plotter.print_figure(str(filename), dpi=self.dpi)
def fileQuit(self):