HP3562A/q3562A.py

changeset 40
1bbea188a7e5
parent 39
8becd52c2171
child 41
9a453b2479c5
equal deleted inserted replaced
39:8becd52c2171 40:1bbea188a7e5
1 #
2
3 import os, sys
4 import time
5 import glob
6
7 from PyQt4 import QtGui, QtCore, uic
8 from PyQt4.QtCore import SIGNAL, Qt
9
10 if "-m" in sys.argv:
11 from dump_datablock_mockup import HP3562dumper
12 else:
13 from dump_datablock import HP3562dumper
14 import q3562A_rc
15
16 ldir = os.path.abspath(os.path.dirname(__file__))
17 sys.path.append(ldir)
18 form_class, base_class = uic.loadUiType(os.path.join(ldir, "q3562A.ui"))
19
20 from qpreferences import BaseItem, IntItem, UnicodeItem, ColorItem
21 from qpreferences import PointItem, SizeItem, ByteArrayItem
22 from qpreferences import AbstractPreferences
23 from qpreferenceseditor import PreferencesEditor
24
25 from tools import str_num_cmp
26
27 class Preferences(AbstractPreferences):
28 ORGANISATION="Logilab"
29 APPLICATION="qgpib_plotter"
30
31 _pos = PointItem()
32 _size = SizeItem()
33 _appState = ByteArrayItem()
34
35 device = UnicodeItem(default='/dev/ttyUSB0',
36 name=u'device',
37 description=u'GPIB device',
38 group="GPIB settings")
39 address = IntItem(default=5, min=0, max=16,
40 name=u'GPIB address',
41 group="GPIB settings")
42
43 background = ColorItem(default=QtGui.QColor("white"),
44 name="Background",
45 group="Colors")
46 color0 = ColorItem(default=QtGui.QColor("black"),
47 name="Pen #0",
48 group="Colors")
49 color1 = ColorItem(default=QtGui.QColor("green"),
50 name="Pen #1",
51 group="Colors")
52 color2 = ColorItem(default=QtGui.QColor("red"),
53 name="Pen #2",
54 group="Colors")
55 color3 = ColorItem(default=QtGui.QColor("blue"),
56 name="Pen #3",
57 group="Colors")
58 color4 = ColorItem(default=QtGui.QColor("yellow"),
59 name="Pen #4",
60 group="Colors")
61 color5 = ColorItem(default=QtGui.QColor("cyan"),
62 name="Pen #5",
63 group="Colors")
64 color6 = ColorItem(default=QtGui.QColor("magenta"),
65 name="Pen #6",
66 group="Colors")
67 color7 = ColorItem(default=QtGui.QColor("darkred"),
68 name="Pen #7",
69 group="Colors")
70
71 class QtHPGLPlotter(QtGui.QMainWindow, form_class):
72 def __init__(self, parent=None):
73 QtGui.QMainWindow.__init__(self, parent)
74 self._plots = {}
75 self._prefs = Preferences()
76 self.setupUi()
77 self.initializeGPIB()
78 if self._prefs._pos:
79 self.move(self._prefs._pos)
80 if self._prefs._size:
81 self.resize(self._prefs._size)
82 if self._prefs._appState:
83 self.restoreState(self._prefs._appState)
84 self.readPreferences()
85
86 def readPreferences(self):
87 bg = self._prefs.background
88 if bg and bg.isValid():
89 self.plotterWidget.qview.setBackgroundBrush(QtGui.QBrush(bg))
90 pen_colors = [self._prefs["color%d"%i] for i in range(8)]
91 self.plotterWidget.pen_colors = pen_colors
92
93 def replotCurrent(self):
94 self.currentPlotChanged(self.plotsView.currentIndex())
95
96 def setupUi(self):
97 form_class.setupUi(self, self) # call qtdesigner generated form creation
98 # actions defined in designer
99 self.connect(self.actionPreferences, SIGNAL('triggered(bool)'),
100 self.preferencesTriggered)
101 self.connect(self.actionQuit, SIGNAL('triggered(bool)'),
102 self.quitTriggered)
103 self.actionQuit.setShortcut(QtGui.QKeySequence(u'Ctrl+Q'))
104 self.connect(self.actionOpen, SIGNAL('triggered(bool)'),
105 self.openTriggered)
106 self.actionOpen.setShortcut(QtGui.QKeySequence(u'Ctrl+O'))
107 self.connect(self.actionSave, SIGNAL('triggered(bool)'),
108 self.saveTriggered)
109 self.actionSave.setShortcut(QtGui.QKeySequence(u'Ctrl+S'))
110 self.connect(self.actionSaveAs, SIGNAL('triggered(bool)'),
111 self.saveAsTriggered)
112
113 self.plotterWidget = QHPGLPlotterWidget(self)
114 self.setCentralWidget(self.plotterWidget)
115
116 self.connect(self.captureButton, SIGNAL("toggled(bool)"),
117 self.captureToggled)
118
119 self._plots_list = QtGui.QStringListModel()
120 self.plotsView.setModel(self._plots_list)
121 self.connect(self.plotsView, SIGNAL('activated(const QModelIndex&)'),
122 self.currentPlotChanged)
123 self.connect(self.plotsView.selectionModel(),
124 SIGNAL('currentChanged(const QModelIndex&, const QModelIndex&)'),
125 self.currentPlotChanged)
126
127 def currentPlotChanged(self, index, old_index=None):
128 if index.isValid():
129 value = unicode(self.plotsView.model().data(index, Qt.DisplayRole).toString())
130
131 self.plotterWidget.clear()
132 self.plotterWidget.parse(self._plots[value])
133
134 def preferencesTriggered(self, checked=False):
135 PreferencesEditor(self._prefs, self).exec_()
136 self.readPreferences()
137 self.replotCurrent()
138
139 def quitTriggered(self, checked=False):
140 self.close()
141
142 def closeEvent(self, event):
143 if 1:
144 #if self.promptForSave():
145 self._prefs._pos = self.pos()
146 self._prefs._size = self.size()
147 self._prefs._appState = self.saveState()
148 event.accept()
149 else:
150 event.ignore()
151
152 def openTriggered(self, checked=False):
153 filenames = QtGui.QFileDialog.getOpenFileNames(self, "Open a HPGL file to display", '.', 'HPGL files (*.plt)\nAll files (*)')
154 self.openFiles(filenames)
155 self.displayFirst()
156
157 def displayFirst(self):
158 if not self.plotsView.currentIndex().isValid():
159 self.plotsView.setCurrentIndex(self.plotsView.model().index(0, 0))
160
161 def openFiles(self, filenames):
162 ok = False
163 for filename in filenames:
164 filename = str(filename)
165 if os.path.exists(filename):
166 data = open(filename).read()
167 name = os.path.basename(filename)
168 name = os.path.splitext(name)[0]
169 lst = self.plotsView.model().stringList()
170 lst.append(name)
171 self._plots[name] = data
172 self.plotsView.model().setStringList(lst)
173 ok = True
174 return ok
175
176 def plotReceived(self, num):
177 self._receiving = False
178 self.setReceivingLed()
179 plot, timestamp = self.captureThread.getPlot(num)
180 name = "plot_%s"%(num)
181 lst = self.plotsView.model().stringList()
182 lst.append(name)
183 self._plots[name] = plot
184 self.plotsView.model().setStringList(lst)
185
186 def plotStarted(self):
187 self._receiving = True
188 self.setReceivingLed()
189
190 def saveTriggered(self, checked=False):
191 print "save"
192
193 def saveAsTriggered(self, checked=False):
194 index = self.plotsView.selectionModel().currentIndex()
195 if index.isValid():
196 filename = QtGui.QFileDialog.getSaveFileName(self, "Selecte a file name to save HPGL file", '.', 'HPGL files (*.plt)\nAll files (*)')
197 n = index.row()
198 value = unicode(self.plotsView.model().data(index, Qt.DisplayRole).toString())
199 open(filename, 'w').write(self._plots[value])
200
201
202 def initializeGPIB(self):
203 self._online = False
204 try:
205 self.gpib_plotter = QGPIBplotter(device=self._prefs.device,
206 address=self._prefs.address,
207 )
208 self.captureThread = GPIBReceiver(self.gpib_plotter)
209 self.connect(self.captureThread, SIGNAL('plotReceived(int)'),
210 self.plotReceived)
211 self.connect(self.captureThread, SIGNAL('plotStarted()'),
212 self.plotStarted)
213 self.captureThread.start()
214 except Exception, e:
215 #print e
216 self.gpib_plotter = None
217 self.setCaptureLed()
218
219 def captureToggled(self, state):
220 if state:
221 if self.gpib_plotter is None:
222 self.initializeGPIB()
223 if self.gpib_plotter is None:
224 QtGui.QMessageBox.critical(self, self.tr("GPIB error"),
225 self.tr("<b>Unable to initialize GPIB connection</b>.<br>Please check your GPIB dongle and settings."))
226 self._online = False
227 self.setCaptureLed()
228 return
229 self._online = True
230 self.captureThread.startCapture()
231 else:
232 if self.captureThread:
233 self.captureThread.stopCapture()
234 self._online = False
235 self.setCaptureLed()
236
237 def setCaptureLed(self):
238 if self._online:
239 icn = QtGui.QIcon(':/icons/led_green.svg')
240 else:
241 icn = QtGui.QIcon(':/icons/led_green_off.svg')
242 self.captureButton.setIcon(icn)
243 self.captureButton.setChecked(self._online)
244
245 def setReceivingLed(self):
246 if self._receiving:
247 icn = QtGui.QIcon(':/icons/led_red.svg')
248 else:
249 icn = QtGui.QIcon(':/icons/led_red_off.svg')
250 self.receivingButton.setIcon(icn)
251
252 class QGPIBplotter(GPIBplotter):
253 def __init__(self, device="/dev/ttyUSB0", baudrate=115200, timeout=0.1,
254 address=5):
255 GPIBplotter.__init__(self, device, baudrate, timeout, address)
256 self.emitter = None
257
258 def plotStarted(self):
259 if self.emitter:
260 self.emitter.emit(SIGNAL('plotStarted()'))
261 #self.emitter.msleep(1)
262
263 class GPIBReceiver(QtCore.QThread):
264 def __init__(self, cnx):
265 QtCore.QThread.__init__(self)
266 self.gpibplotter = cnx
267 self.gpibplotter.emitter = self
268
269 self._cancelmutex = QtCore.QMutex()
270 self._cancel = False
271 #self._nreceived = 0
272 self._plotsmutex = QtCore.QMutex()
273 self._plots = []
274 self._startstopmutex = QtCore.QMutex()
275 self._startstop = QtCore.QWaitCondition()
276 self._capturing = False
277
278 def cancel(self):
279 self._cancelmutex.lock()
280 self._cancel = True
281 self._cancelmutex.unlock()
282
283 def startCapture(self):
284 self._startstop.wakeOne()
285
286 def stopCapture(self):
287 self._startstopmutex.lock()
288 self._capturing = False
289 self._startstopmutex.unlock()
290
291 def run(self):
292 while 1:
293 self._cancelmutex.lock()
294 if self._cancel:
295 return
296 self._cancelmutex.unlock()
297 self._startstopmutex.lock()
298 if not self._capturing:
299 self._startstop.wait(self._startstopmutex)
300 self._capturing = True
301 self._startstopmutex.unlock()
302
303 plot = self.gpibplotter.load_plot(wait_timeout=0.1)
304 timestamp = time.time()
305 if plot:
306 self._plotsmutex.lock()
307 self._plots.append((plot, timestamp))
308 n = len(self._plots)
309 self._plotsmutex.unlock()
310 self.emit(SIGNAL('plotReceived(int)'), n-1)
311 self.msleep(10)
312
313 def getPlot(self, num):
314 self._plotsmutex.lock()
315 try:
316 return self._plots[num]
317 finally:
318 self._plotsmutex.unlock()
319
320 def main():
321 import optparse
322 opt = optparse.OptionParser('A simple PyQt4 HP7470A GPIB plotter emulator for USB-GPIB bundle (ProLogix)')
323 opt.add_option('-m', '--mockup', default=False,
324 action="store_true",
325 dest='mockup',
326 help='Use a pseudo GPIB connection (for test purpose)',
327 )
328 opt.add_option('-v', '--verbose', default=False,
329 action="store_true",
330 dest="verbose",
331 help="Verbose mode",)
332
333 options, argv = opt.parse_args(sys.argv)
334
335 a = QtGui.QApplication(argv)
336 w = QtHPGLPlotter()
337 files = [f for f in argv[1:] if os.path.isfile(f)]
338 files.sort(cmp=str_num_cmp)
339 if w.openFiles(files):
340 w.displayFirst()
341
342 w.show()
343 a.exec_()
344
345 if __name__ == '__main__':
346 main()

mercurial