From bafb045bdd4be7cb8870e8ade523d39bbd1d2923 Mon Sep 17 00:00:00 2001 From: Mike Furlotti <7596301+mfurlotti@users.noreply.github.com> Date: Sun, 2 Dec 2018 21:41:27 -0800 Subject: [PATCH 1/5] add devices to read slider position so these four values can be plotted and exported to csv, add signal to catch ctrl-c from command line, and move the slider stylesheet to an imported file to make using an alternate style easier --- src/artisanlib/main.py | 94 ++++++++++------------------------- src/artisanlib/sliderStyle.py | 51 +++++++++++++++++++ 2 files changed, 78 insertions(+), 67 deletions(-) create mode 100644 src/artisanlib/sliderStyle.py diff --git a/src/artisanlib/main.py b/src/artisanlib/main.py index 14252dd9c..428a56a30 100644 --- a/src/artisanlib/main.py +++ b/src/artisanlib/main.py @@ -53,6 +53,8 @@ import uuid import threading import multiprocessing +import signal +signal.signal(signal.SIGINT, signal.SIG_DFL) import urllib.parse as urlparse # @Reimport import urllib.request as urllib # @Reimport @@ -173,69 +175,7 @@ from artisanlib.modbusport import modbusport from artisanlib.qtsingleapplication import QtSingleApplication -artisan_slider_style = """ - QSlider::groove:vertical:focus {{ - background: #888; - border: 0.5px solid #666; - width: 3px; - border-radius: 5px; - }} - QSlider::sub-page:vertical:focus {{ - background: 888; - border: 0.5px solid #666; - width: 85px; - border-radius: 5px; - }} - - QSlider::groove:vertical {{ - background: #ddd; - border: 0.5px solid #aaa; - width: 3px; - border-radius: 5px; - }} - QSlider::sub-page:vertical {{ - background: #ddd; - border: 0.5px solid #aaa; - width: 85px; - border-radius: 5px; - }} - QSlider::add-page:vertical {{ - background: {color}; - border: 1px solid {color}; - width: 5px; - border-radius: 2px; - }} - QSlider::handle:vertical {{ - background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #fff, stop:1 #eee); - border: 0.5px solid #ddd; - height: 8px; - margin-top: -1px; - margin-bottom: -1px; - margin-left: -10px; - margin-right: -10px; - border-radius: 5px; - }} - QSlider::handle:vertical:hover {{ - background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc); - border: 1px solid #ccc; - border-radius: 5px; - }} - QSlider::sub-page:vertical:disabled {{ - background: #bbb; - border-color: #999; - }} - QSlider::add-page:vertical:disabled {{ - background: #eee; - border-color: #999; - }} - QSlider::handle:vertical:disabled {{ - background: #eee; - border: 1px solid #aaa; - border-radius: 5px; - }} -""" - - +from artisanlib.sliderStyle import * # maps Artisan thermocouple types (order as listed in the menu; see phidget1048_types) to Phdiget thermocouple types @@ -997,6 +937,8 @@ def __init__(self,parent,dpi): "+Aillio Bullet R1 State/Fan RPM", #87 "+Program 78", #88 "+Program 910", #89 + "+Slider 01", #90 + "+Slider 23", #91 ] @@ -1025,6 +967,8 @@ def __init__(self,parent,dpi): 76, # +Phidget HUB0000 IO Digital 45 84, # +Aillio Bullet R1 Heater/Fan 87, # +Aillio Bullet R1 State + 90, # +Slider 01 + 91, # +Slider 23 ] #extra devices @@ -36167,6 +36111,8 @@ def __init__(self): self.R1_RPM_STATE, #87 self.callprogram_78, #88 self.callprogram_910, #89 + self.slider_01, #90 + self.slider_23, #91 ] #string with the name of the program for device #27 self.externalprogram = "test.py" @@ -36461,6 +36407,18 @@ def callprogram_910(self): t2 = aw.qmc.program_t10 return tx,t2,t1 + def slider_01(self): + tx = aw.qmc.timeclock.elapsed()/1000. + t1 = aw.slider1.value() + t2 = aw.slider2.value() + return tx,t2,t1 + + def slider_23(self): + tx = aw.qmc.timeclock.elapsed()/1000. + t1 = aw.slider3.value() + t2 = aw.slider4.value() + return tx,t2,t1 + def virtual(self): tx = aw.qmc.timeclock.elapsed()/1000. return tx,1.,1. @@ -41035,7 +40993,7 @@ def __init__(self, parent = None): tab1Layout.addWidget(etbt_help_label) devid = aw.qmc.device # "ADD DEVICE:" - if not(devid in [27,29,33,34,37,40,41,45,46,47,48,49,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89]) and not(devid == 0 and aw.ser.useModbusPort): # hide serial confs for MODBUS, Phidget and Yocto devices + if not(devid in [27,29,33,34,37,40,41,45,46,47,48,49,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89,90,91]) and not(devid == 0 and aw.ser.useModbusPort): # hide serial confs for MODBUS, Phidget and Yocto devices tab1Layout.addLayout(gridBoxLayout) tab1Layout.addStretch() #LAYOUT TAB 2 @@ -41563,7 +41521,7 @@ def createserialTable(self): device = QTableWidgetItem(devname) #type identification of the device. Non editable self.serialtable.setItem(i,0,device) # "ADD DEVICE:" - if not (devid in [27,29,33,34,37,40,41,45,46,47,48,49,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89]) and devicename[0] != "+": # hide serial confs for MODBUS, Phidgets and "+X" extra devices + if not (devid in [27,29,33,34,37,40,41,45,46,47,48,49,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89,90,91]) and devicename[0] != "+": # hide serial confs for MODBUS, Phidgets and "+X" extra devices comportComboBox = PortComboBox(selection = aw.extracomport[i]) comportComboBox.activated.connect(lambda i=0:self.portComboBoxIndexChanged(comportComboBox,i)) comportComboBox.setFixedWidth(200) @@ -41655,7 +41613,7 @@ class timeoutError(Exception): pass #save extra serial ports by reading the serial extra table self.saveserialtable() # "ADD DEVICE:" - if not(aw.qmc.device in [27,29,33,34,37,40,41,45,46,47,48,49,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89]) and not(aw.qmc.device == 0 and aw.ser.useModbusPort): # only if serial conf is not hidden + if not(aw.qmc.device in [27,29,33,34,37,40,41,45,46,47,48,49,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89,90,91]) and not(aw.qmc.device == 0 and aw.ser.useModbusPort): # only if serial conf is not hidden try: #check here comport errors if not comport: @@ -43866,6 +43824,8 @@ def okEvent(self): 1, # 87 1, # 88 1, # 89 + 1, # 90 + 1, # 91 ] #init serial settings of extra devices for i in range(len(aw.qmc.extradevices)): @@ -43982,7 +43942,7 @@ def okEvent(self): self.accept() #if device is not None or not external-program (don't need serial settings config) # "ADD DEVICE:" - if not(aw.qmc.device in [18,27,34,37,40,41,45,46,47,48,49,50,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89]): + if not(aw.qmc.device in [18,27,34,37,40,41,45,46,47,48,49,50,51,52,55,58,59,60,61,62,63,64,65,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,88,89,90,91]): aw.setcommport() #self.close() except Exception as e: diff --git a/src/artisanlib/sliderStyle.py b/src/artisanlib/sliderStyle.py new file mode 100644 index 000000000..8ad2353ce --- /dev/null +++ b/src/artisanlib/sliderStyle.py @@ -0,0 +1,51 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +artisan_slider_style = """ + QSlider::groove:vertical {{ + background: #ddd; + border: 0.5px solid #aaa; + width: 3px; + border-radius: 5px; + }} + QSlider::sub-page:vertical {{ + background: #ddd; + border: 0.5px solid #aaa; + width: 85px; + border-radius: 5px; + }} + QSlider::add-page:vertical {{ + background: {color}; + border: 1px solid {color}; + width: 5px; + border-radius: 2px; + }} + QSlider::handle:vertical {{ + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #fff, stop:1 #eee); + border: 0.5px solid #ddd; + height: 8px; + margin-top: -1px; + margin-bottom: -1px; + margin-left: -10px; + margin-right: -10px; + border-radius: 5px; + }} + QSlider::handle:vertical:hover {{ + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc); + border: 1px solid #ccc; + border-radius: 5px; + }} + QSlider::sub-page:vertical:disabled {{ + background: #bbb; + border-color: #999; + }} + QSlider::add-page:vertical:disabled {{ + background: #eee; + border-color: #999; + }} + QSlider::handle:vertical:disabled {{ + background: #eee; + border: 1px solid #aaa; + border-radius: 5px; + }} +""" From 907abd22586e09fe5db038acd73319865f672422 Mon Sep 17 00:00:00 2001 From: Mike Furlotti <7596301+mfurlotti@users.noreply.github.com> Date: Sun, 2 Dec 2018 22:21:45 -0800 Subject: [PATCH 2/5] Enable IO COMMANDs to feedback state in the GUI 1) Add analog output out(c,v), duplicating the function from VOUT COMMAND. Now the command list of IO COMMAND can contain both analog and digital output commands. 2) Update the command parsing to use regular expressions. This makes it easier to validate the user input and improve error handling. 3) Update the toggle(c) command so it causes the style of the button that was clicked to toggle. 4) Add a new command button(b,c,v). This sets the button number (b) to style (v) and also the output of channel (c) to (v). 5) Add a new command slider(c,v). This updates the position of slider (c) to value (v) --- src/artisanlib/main.py | 94 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/src/artisanlib/main.py b/src/artisanlib/main.py index 428a56a30..ae01c2dda 100644 --- a/src/artisanlib/main.py +++ b/src/artisanlib/main.py @@ -53,6 +53,7 @@ import uuid import threading import multiprocessing +import re import signal signal.signal(signal.SIGINT, signal.SIG_DFL) @@ -15068,19 +15069,57 @@ def eventaction_internal(self,action,cmd): if cmd_str: cmds = filter(None, cmd_str.split(";")) # allows for sequences of commands like in ";;...;" for c in cmds: - cs = c.strip() - try: - if cs.startswith('set(') and len(cs)>7: - c,v = cs[4:-1].split(',') - aw.ser.phidgetBinaryOUTset(int(c),bool(int(v))) - elif cs.startswith('toggle(') and len(cs)>8: - c = int(cs[7:-1]) - aw.ser.phidgetBinaryOUTtoggle(c) - elif cs.startswith('pulse(') and len(cs)>9 and len(cs)<14: - c,t = cs[6:-1].split(',') - aw.ser.phidgetBinaryOUTpulse(int(c),int(t)) - except Exception: - pass + cs_a = re.findall("[0-9a-zA-Z-\.]+", c) + cs_len = len(cs_a) + + if cs_a[0] == "set" and cs_len == 3: + aw.ser.phidgetBinaryOUTset(toInt(cs_a[1]), bool(toInt(cs_a[2]))) + + elif cs_a[0] == "toggle" and cs_len == 2: + c = toInt(cs_a[1]) + #keep state of this gpio, rather than rely on phidget and use non-zero value to set button color + self.buttonStates[self.lastbuttonpressed] = (self.buttonStates[self.lastbuttonpressed] + 1) & 0x1 + aw.ser.phidgetBinaryOUTset(c, (self.buttonStates[self.lastbuttonpressed])) + #block resetting style of last button + self.lastbuttonpressed = -1 + #aw.sendmessage(QApplication.translate("Message", "toggle(%d)" % (toInt(cs_a[1])), None)) + + elif cs_a[0] == "pulse" and cs_len == 3: #len(cs)>9 and len(cs)<14: + c = toInt(cs_a[1]) + t = toInt(cs_a[2]) + #print("pulse(%d, %d)" % (c, t)) + if t>= 0.0 and t <= 1000: + aw.ser.phidgetBinaryOUTpulse(c, t) + else: + aw.sendmessage(QApplication.translate("Message", "Pulse out of range (%d)" % (t), None)) + + elif cs_a[0] == "out" and cs_len == 3: + aw.ser.phidgetVOUTsetVOUT(toInt(cs_a[1]), toFloat(cs_a[2])) + + elif cs_a[0] == "slider" and cs_len == 3: + v = toFloat(cs_a[2]) + if v >= 0.0 and v <= 100.0: + aw.moveslider(toInt(cs_a[1]), v) + else: + aw.sendmessage(QApplication.translate("Message", "Slider out of range (%f)" % (f), None)) + + elif cs_a[0] == "button" and cs_len == 4: + b = toInt(cs_a[1]) - 1 # gui button list is indexed from 1 + c = toInt(cs_a[2]) + v = toInt(cs_a[3]) + self.buttonStates[b] = v & 0x1 + aw.ser.phidgetBinaryOUTset(c, bool(self.buttonStates[b])) + #print("button(%d, %d, %d) self.buttonStates: %s" % (b, c, v, self.buttonStates)) + + if self.buttonStates[b] != 0: + self.setExtraEventButtonStyle(b, style="pressed") + else: + self.setExtraEventButtonStyle(b, style="normal") + + else: + #print("no match for command [%s], continue" % (cs_a[0])) + aw.sendmessage(QApplication.translate("Message","No match for command [%s], continuing" % (cs_a[0]), None)) + elif action == 7: # slider call-program action try: self.call_prog_with_args(cmd_str) @@ -15385,6 +15424,19 @@ def moveslider(self,n,v,forceLCDupdate=False): elif n == 3 and self.slider4.value() != v: self.slider4.setValue(v) + def setExtraEventButtonStyle(self, tee, style="normal"): + if style=="normal": + # set color of this button to "normal" + normalstyle = "QPushButton {font-size: 10pt; font-weight: bold; color: %s; background-color: %s}" % ( + self.extraeventbuttontextcolor[tee],self.extraeventbuttoncolor[tee]) + self.buttonlist[tee].setStyleSheet(normalstyle) + + if style=="pressed": + # set color of this button to "pressed" + pressedstyle = "QPushButton {font-size: 10pt; font-weight: bold; color: %s; background-color: %s}" % ( + self.extraeventbuttoncolor[tee],self.extraeventbuttontextcolor[tee]) + self.buttonlist[tee].setStyleSheet(pressedstyle) + #called from user configured event buttons def recordextraevent(self,ee): eventtype = self.extraeventstypes[ee] @@ -15392,13 +15444,17 @@ def recordextraevent(self,ee): aw.qmc.eventactionsemaphore.acquire(1) # reset color of last pressed button if self.lastbuttonpressed != -1 and len(self.buttonlist)>self.lastbuttonpressed: - normalstyle = "QPushButton {font-size: 10pt; font-weight: bold; color: %s; background-color: %s}"%(self.extraeventbuttontextcolor[self.lastbuttonpressed],self.extraeventbuttoncolor[self.lastbuttonpressed]) - self.buttonlist[self.lastbuttonpressed].setStyleSheet(normalstyle) - # set color of this button to "pressed" - pressedstyle = "QPushButton {font-size: 10pt; font-weight: bold; color: %s; background-color: %s}"%(self.extraeventbuttoncolor[ee],self.extraeventbuttontextcolor[ee]) - self.buttonlist[ee].setStyleSheet(pressedstyle) + self.setExtraEventButtonStyle(self.lastbuttonpressed, style="normal") + + #toggle button if it has nonzero state prior to toggling + if self.buttonStates[ee] != 0: + self.setExtraEventButtonStyle(ee, style="normal") + else: + self.setExtraEventButtonStyle(ee, style="pressed") + # reset lastbuttonpressed self.lastbuttonpressed = ee + except Exception: pass finally: @@ -25417,6 +25473,7 @@ def realignbuttons(self): self.e3buttondialog.clear() self.e4buttondialog.clear() self.buttonlist = [] + self.buttonStates = [] #hide all extra button rows self.e1buttondialog.setVisible(False) self.e2buttondialog.setVisible(False) @@ -25438,6 +25495,7 @@ def realignbuttons(self): p.setFocusPolicy(Qt.NoFocus) p.clicked.connect(lambda _,x=i:self.recordextraevent(x)) self.buttonlist.append(p) + self.buttonStates.append(0) #add button to row (CHANGED: now never add extra buttons to default button set) if False: #lowerbuttonvisiblebuttons < self.buttonlistmaxlen: self.lowerbuttondialog.addButton(self.buttonlist[i],QDialogButtonBox.ActionRole) From 27672aaff07ce44595a5036c96a816712959586b Mon Sep 17 00:00:00 2001 From: Mike Furlotti <7596301+mfurlotti@users.noreply.github.com> Date: Thu, 6 Dec 2018 15:49:38 -0800 Subject: [PATCH 3/5] Add axis=0 since this argument is required in numpy version 1.14.5. Ubuntu is shipping with numpy 1.14.5, so this change is for backwards compatibility. --- src/artisanlib/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/artisanlib/main.py b/src/artisanlib/main.py index ae01c2dda..b8b6ab892 100644 --- a/src/artisanlib/main.py +++ b/src/artisanlib/main.py @@ -10267,7 +10267,7 @@ def decay_average(self,tx,temp,decay_weights): d = aw.qmc.delay / 1000. tx_org = tx[-l:] # as len(tx)=len(temp) here, it is guranteed that len(tx_org)=l # we create a linearly spaced time array starting from the newest timestamp in sampling interval distance - tx_lin = numpy.flip(numpy.arange(tx_org[-1],tx_org[-1]-l*d,-d)) # by contruction, len(tx_lin)=len(tx_org)=l + tx_lin = numpy.flip(numpy.arange(tx_org[-1],tx_org[-1]-l*d,-d), axis=0) # by contruction, len(tx_lin)=len(tx_org)=l temp_trail = temp[-l:] # by construction, len(temp_trail)=len(tx_lin)=len(tx_org)=l temp_trail_re = numpy.interp(tx_lin, tx_org, temp_trail) # resample data into that linear spaced time return numpy.average(temp_trail_re[-len(decay_weights):],weights=decay_weights[-l:]) # len(decay_weights)>len(temp_trail_re)=l is possible From 5c6332b204cdcf5990a55ca3db262159b789f034 Mon Sep 17 00:00:00 2001 From: Mike Furlotti <7596301+mfurlotti@users.noreply.github.com> Date: Mon, 10 Dec 2018 23:43:13 -0800 Subject: [PATCH 4/5] add slider style that is slightly wider --- src/artisanlib/sliderStyle-wide.py | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/artisanlib/sliderStyle-wide.py diff --git a/src/artisanlib/sliderStyle-wide.py b/src/artisanlib/sliderStyle-wide.py new file mode 100644 index 000000000..621b0ea43 --- /dev/null +++ b/src/artisanlib/sliderStyle-wide.py @@ -0,0 +1,52 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +artisan_slider_style = """ + QSlider::groove:vertical {{ + background: #ddd; + border: 0.5px solid #aaa; + width: 10px; + border-radius: 5px; + }} + QSlider::sub-page:vertical {{ + background: #ddd; + border: 0.5px solid #aaa; + width: 85px; + border-radius: 5px; + }} + QSlider::add-page:vertical {{ + background: {color}; + border: 1px solid {color}; + width: 5px; + border-radius: 2px; + }} + QSlider::handle:vertical {{ + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #fff, stop:1 #eee); + border: 0.5px solid #ddd; + height: 10px; + margin-top: -1px; + margin-bottom: -1px; + margin-left: -15px; + margin-right: -15px; + border-radius: 5px; + }} + QSlider::handle:vertical:hover {{ + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc); + border: 1px solid #ccc; + border-radius: 5px; + }} + QSlider::sub-page:vertical:disabled {{ + background: #bbb; + border-color: #999; + }} + QSlider::add-page:vertical:disabled {{ + background: #eee; + border-color: #999; + }} + QSlider::handle:vertical:disabled {{ + background: #eee; + border: 1px solid #aaa; + border-radius: 5px; + }} +""" + From e5c9d44e826c6557180254d23ce11c89830ee72f Mon Sep 17 00:00:00 2001 From: Mike Furlotti <7596301+mfurlotti@users.noreply.github.com> Date: Mon, 10 Dec 2018 23:44:02 -0800 Subject: [PATCH 5/5] add return value indicating status of phidgetBinaryOUTset and phidgetVOUTsetVOUT, update button style only if phidget update is successful. --- src/artisanlib/main.py | 52 +++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/src/artisanlib/main.py b/src/artisanlib/main.py index b8b6ab892..c4080292d 100644 --- a/src/artisanlib/main.py +++ b/src/artisanlib/main.py @@ -10271,7 +10271,7 @@ def decay_average(self,tx,temp,decay_weights): temp_trail = temp[-l:] # by construction, len(temp_trail)=len(tx_lin)=len(tx_org)=l temp_trail_re = numpy.interp(tx_lin, tx_org, temp_trail) # resample data into that linear spaced time return numpy.average(temp_trail_re[-len(decay_weights):],weights=decay_weights[-l:]) # len(decay_weights)>len(temp_trail_re)=l is possible - + # sample devices at interval self.delay miliseconds. # we can assume within the processing of sample() that flagon=True def sample(self): @@ -15073,16 +15073,24 @@ def eventaction_internal(self,action,cmd): cs_len = len(cs_a) if cs_a[0] == "set" and cs_len == 3: - aw.ser.phidgetBinaryOUTset(toInt(cs_a[1]), bool(toInt(cs_a[2]))) + if not aw.ser.phidgetBinaryOUTset(toInt(cs_a[1]), bool(toInt(cs_a[2]))): + aw.sendmessage(QApplication.translate("Message", "Failed to set(%s, %s)" % (cs_a[1], cs_a[2] ), None)) elif cs_a[0] == "toggle" and cs_len == 2: c = toInt(cs_a[1]) #keep state of this gpio, rather than rely on phidget and use non-zero value to set button color - self.buttonStates[self.lastbuttonpressed] = (self.buttonStates[self.lastbuttonpressed] + 1) & 0x1 - aw.ser.phidgetBinaryOUTset(c, (self.buttonStates[self.lastbuttonpressed])) + newValue = (self.buttonStates[self.lastbuttonpressed] + 1) & 0x1 + if aw.ser.phidgetBinaryOUTset(c, bool(newValue)): + self.buttonStates[self.lastbuttonpressed] = newValue + else: + aw.sendmessage(QApplication.translate("Message", "Failed to toggle(%s)" % (cs_a[1]), None)) + #clear style that got set in button press event handler + if 0 != self.buttonStates[self.lastbuttonpressed]: + self.setExtraEventButtonStyle(self.lastbuttonpressed, style="pressed") + else: + self.setExtraEventButtonStyle(self.lastbuttonpressed, style="normal") #block resetting style of last button self.lastbuttonpressed = -1 - #aw.sendmessage(QApplication.translate("Message", "toggle(%d)" % (toInt(cs_a[1])), None)) elif cs_a[0] == "pulse" and cs_len == 3: #len(cs)>9 and len(cs)<14: c = toInt(cs_a[1]) @@ -15094,7 +15102,8 @@ def eventaction_internal(self,action,cmd): aw.sendmessage(QApplication.translate("Message", "Pulse out of range (%d)" % (t), None)) elif cs_a[0] == "out" and cs_len == 3: - aw.ser.phidgetVOUTsetVOUT(toInt(cs_a[1]), toFloat(cs_a[2])) + if not aw.ser.phidgetVOUTsetVOUT(toInt(cs_a[1]), toFloat(cs_a[2])): + aw.sendmessage(QApplication.translate("Message", "Failed to set VOUT(%s, %s)" % (cs_a[1], cs_a[2] ), None)) elif cs_a[0] == "slider" and cs_len == 3: v = toFloat(cs_a[2]) @@ -15107,9 +15116,10 @@ def eventaction_internal(self,action,cmd): b = toInt(cs_a[1]) - 1 # gui button list is indexed from 1 c = toInt(cs_a[2]) v = toInt(cs_a[3]) - self.buttonStates[b] = v & 0x1 - aw.ser.phidgetBinaryOUTset(c, bool(self.buttonStates[b])) - #print("button(%d, %d, %d) self.buttonStates: %s" % (b, c, v, self.buttonStates)) + if aw.ser.phidgetBinaryOUTset(c, bool(v & 0x1)): + self.buttonStates[b] = v & 0x1 + else: + aw.sendmessage(QApplication.translate("Message", "Failed to set button(%s, %s, %s)" % (cs_a[1], cs_a[2], cs_a[3] ), None)) if self.buttonStates[b] != 0: self.setExtraEventButtonStyle(b, style="pressed") @@ -38634,29 +38644,32 @@ def phidgetBinaryOUTattach(self,channel): aw.ser.PhidgetBinaryOut[channel].openWaitForAttachment(1000) except: pass - + def phidgetBinaryOUTpulse(self,channel,millis): self.phidgetBinaryOUTset(channel,1) -# QTimer.singleShot(millis,lambda : self.phidgetBinaryOUTset(channel,0)) +# QTimer.singleShot(millis,lambda : self.phidgetBinaryOUTset(channel,0)) # QTimer (which does not work being called from a QThread) call replaced by the next 2 lines (event actions are now started in an extra thread) # the following solution has the drawback to block the eventaction thread # libtime.sleep(millis/1000.) # self.phidgetBinaryOUTset(channel,0) # so we use a QTimer.singleShot running in the main thread aw.singleShotPhidgetsPulseOFF.emit(channel,millis,"BinaryOUTset") - + # channel: 0-8 # value: True or False def phidgetBinaryOUTset(self,channel,value): + res = False self.phidgetBinaryOUTattach(channel) if aw.ser.PhidgetBinaryOut: # set state of the given channel try: if len(aw.ser.PhidgetBinaryOut) > channel and aw.ser.PhidgetBinaryOut[channel] and aw.ser.PhidgetBinaryOut[channel].getAttached(): aw.ser.PhidgetBinaryOut[channel].setState(value) + res = True except Exception: - pass - + res = False + return res + # channel: 0-8 # returns: True or False (default) def phidgetBinaryOUTget(self,channel): @@ -38866,11 +38879,12 @@ def phidgetVOUTattach(self,channel): if not aw.ser.PhidgetAnalogOut[channel].getAttached(): aw.ser.PhidgetAnalogOut[channel].openWaitForAttachment(1000) except: - pass - + pass # value: float + # returns True or False indicating set status def phidgetVOUTsetVOUT(self,channel,value): + res = False self.phidgetVOUTattach(channel) if aw.ser.PhidgetAnalogOut: # set voltage output @@ -38882,9 +38896,11 @@ def phidgetVOUTsetVOUT(self,channel,value): else: aw.ser.PhidgetAnalogOut[channel].setVoltage(value) aw.ser.PhidgetAnalogOut[channel].setEnabled(True) + res = True except Exception: - pass - + res = False + return res + def phidgetVOUTclose(self): if aw.ser.PhidgetAnalogOut: for i in range(4):