def __init__(self, parent, opts, locale="fr_FR"): """ Le constructeur @param parent un QWidget @param opts une liste d'options extraite à l'aide de getopts @param locale la langue de l'application """ QMainWindow.__init__(self) QWidget.__init__(self, parent) self.locale = locale from Ui_main import Ui_Dialog self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.graphWidget.setWorld(0, -5, 1, 5) # begins with A0 checked self.ui.A0Check.setCheckState(Qt.Checked) # connects the panel's great button self.connect(self.ui.panelButton, SIGNAL("clicked()"), self.panelHelp) # clears the text browser self.showhelp("") # initialize self.tw: table of widgets which are on the panel self.NSIG = 1 + 32 # number of signals; zeroth element is unused self.tw = [None] * self.NSIG # left entry widgets: 6, 7, 10 self.setTwDisplay(1, self.ui.ID0_display) self.setTwDisplay(2, self.ui.ID0_display) self.setTwEdit(6, self.ui.SQR1_edit) self.setTwEdit(7, self.ui.SQR2_edit) self.setTwDisplay(8, self.ui.SQR2_display) self.setTwEdit(10, self.ui.PULSE_edit) self.setTwDisplay(15, self.ui.FREQ_display) self.setTwDisplay(22, self.ui.SEN_display_2) self.setTwDisplay(23, self.ui.SEN_display) self.setTwDisplay(24, self.ui.A2_display) self.setTwDisplay(25, self.ui.A1_display) self.setTwDisplay(26, self.ui.A0_display) self.setTwDisplay(27, self.ui.CS_display) self.setTwEdit(28, self.ui.CS_edit) self.setTwEdit(30, self.ui.BPV_edit) self.setTwEdit(31, self.ui.UPV_edit) self.connect(self.ui.OD0_check, SIGNAL("stateChanged(int)"), self.OD0toggle) self.connect(self.ui.OD1_check, SIGNAL("stateChanged(int)"), self.OD1toggle) self.connect(self.ui.ID0_button_F, SIGNAL("clicked()"), self.freq_id0) self.connect(self.ui.AMPLI_button_F, SIGNAL("clicked()"), self.freq_ampin) self.connect(self.ui.SEN_button_F, SIGNAL("clicked()"), self.freq_sen) self.connect(self.ui.ID0_button_pcent, SIGNAL("clicked()"), self.pcent_id0) self.connect(self.ui.horizontalSlider, SIGNAL("valueChanged(int)"), self.set_timebase) self.connect(self.ui.A0Check, SIGNAL("stateChanged(int)"), self.toggleA0) self.connect(self.ui.A1Check, SIGNAL("stateChanged(int)"), self.toggleA1) self.connect(self.ui.fitCheck, SIGNAL("stateChanged(int)"), self.toggleFit) self.connect(self.ui.lisCheck, SIGNAL("stateChanged(int)"), self.toggleLis) self.connect(self.ui.saveButton, SIGNAL("clicked()"), self.save) self.connect(self.ui.xmButton, SIGNAL("clicked()"), self.xmgrace) self.connect(self.ui.ftButton, SIGNAL("clicked()"), self.do_fft) self.connect(self.ui.quitButton, SIGNAL("clicked()"), self.close) # other intializations self.VPERDIV = 1.0 # Volts per division, vertical scale self.delay = 10 # Time interval between samples self.np = 100 # Number of samples self.nc = 1 # Number of channels self.lissa = False # drawing lissajous-type plots self.chanmask = 1 # byte to store the mask for active analogic channels. self.np = 100 # number of points to plot (and samples to get) self.delay = 10 # delay for measurements (µs between two samples) self.measure = 0 # boolean to toggle data fitting self.NOSQR2 = True # SQR2 is not set self.NOSF = True # No frequency on SENSOR input self.NOAF = True # No frequency on Amplifier input, T15 self.NODF = True # No frequency on Digital input 0 self.OUTMASK = 0 # Digital outputs to LOW # connect to the eyes box self.eye = eyes.open() # Try several times to make a connection # starts the timer for refresh loop if self.eye == None: self.setWindowTitle("EYES Hardware NOT found.") self.showhelp("EYES Hardware Not Found.<br/>Re-Connect USB cable and restart the program.", "red") else: self.setWindowTitle(("EYES Hardware found on " + str(self.eye.device))) self.eye.write_outputs(0) self.eye.disable_actions() self.eye.loadall_calib() self.timer = QTimer(self) self.connect(self.timer, SIGNAL("timeout()"), self.update) self.timer.start(500) # refresh twice per second if possible
def __init__(self, parent, opts, locale="fr_FR"): """ Le constructeur @param parent un QWidget @param opts une liste d'options extraite à l'aide de getopts @param locale la langue de l'application """ QMainWindow.__init__(self) QWidget.__init__(self, parent) self.locale = locale from Ui_main import Ui_Dialog self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.graphWidget.setWorld(0, -5, 1, 5) # begins with A0 checked self.ui.A0Check.setCheckState(Qt.Checked) # connects the panel's great button self.connect(self.ui.panelButton, SIGNAL("clicked()"), self.panelHelp) # clears the text browser self.showhelp('') # initialize self.tw: table of widgets which are on the panel self.NSIG = 1 + 32 # number of signals; zeroth element is unused self.tw = [None] * self.NSIG # left entry widgets: 6, 7, 10 self.setTwDisplay(1, self.ui.ID0_display) self.setTwDisplay(2, self.ui.ID0_display) self.setTwEdit(6, self.ui.SQR1_edit) self.setTwEdit(7, self.ui.SQR2_edit) self.setTwDisplay(8, self.ui.SQR2_display) self.setTwEdit(10, self.ui.PULSE_edit) self.setTwDisplay(15, self.ui.FREQ_display) self.setTwDisplay(22, self.ui.SEN_display_2) self.setTwDisplay(23, self.ui.SEN_display) self.setTwDisplay(24, self.ui.A2_display) self.setTwDisplay(25, self.ui.A1_display) self.setTwDisplay(26, self.ui.A0_display) self.setTwDisplay(27, self.ui.CS_display) self.setTwEdit(28, self.ui.CS_edit) self.setTwEdit(30, self.ui.BPV_edit) self.setTwEdit(31, self.ui.UPV_edit) self.connect(self.ui.OD0_check, SIGNAL("stateChanged(int)"), self.OD0toggle) self.connect(self.ui.OD1_check, SIGNAL("stateChanged(int)"), self.OD1toggle) self.connect(self.ui.ID0_button_F, SIGNAL("clicked()"), self.freq_id0) self.connect(self.ui.AMPLI_button_F, SIGNAL("clicked()"), self.freq_ampin) self.connect(self.ui.SEN_button_F, SIGNAL("clicked()"), self.freq_sen) self.connect(self.ui.ID0_button_pcent, SIGNAL("clicked()"), self.pcent_id0) self.connect(self.ui.horizontalSlider, SIGNAL("valueChanged(int)"), self.set_timebase) self.connect(self.ui.A0Check, SIGNAL("stateChanged(int)"), self.toggleA0) self.connect(self.ui.A1Check, SIGNAL("stateChanged(int)"), self.toggleA1) self.connect(self.ui.fitCheck, SIGNAL("stateChanged(int)"), self.toggleFit) self.connect(self.ui.lisCheck, SIGNAL("stateChanged(int)"), self.toggleLis) self.connect(self.ui.saveButton, SIGNAL("clicked()"), self.save) self.connect(self.ui.xmButton, SIGNAL("clicked()"), self.xmgrace) self.connect(self.ui.ftButton, SIGNAL("clicked()"), self.do_fft) self.connect(self.ui.quitButton, SIGNAL("clicked()"), self.close) # other intializations self.VPERDIV = 1.0 # Volts per division, vertical scale self.delay = 10 # Time interval between samples self.np = 100 # Number of samples self.nc = 1 # Number of channels self.lissa = False # drawing lissajous-type plots self.chanmask = 1 # byte to store the mask for active analogic channels. self.np = 100 # number of points to plot (and samples to get) self.delay = 10 # delay for measurements (µs between two samples) self.measure = 0 # boolean to toggle data fitting self.NOSQR2 = True # SQR2 is not set self.NOSF = True # No frequency on SENSOR input self.NOAF = True # No frequency on Amplifier input, T15 self.NODF = True # No frequency on Digital input 0 self.OUTMASK = 0 # Digital outputs to LOW # connect to the eyes box self.eye = eyes.open() # Try several times to make a connection # starts the timer for refresh loop if self.eye == None: self.setWindowTitle('EYES Hardware NOT found.') self.showhelp( 'EYES Hardware Not Found.<br/>Re-Connect USB cable and restart the program.', 'red') else: self.setWindowTitle( ('EYES Hardware found on ' + str(self.eye.device))) self.eye.write_outputs(0) self.eye.disable_actions() self.eye.loadall_calib() self.timer = QTimer(self) self.connect(self.timer, SIGNAL("timeout()"), self.update) self.timer.start(500) # refresh twice per second if possible
class mainWindow(QMainWindow): def __init__(self, parent, opts, locale="fr_FR"): """ Le constructeur @param parent un QWidget @param opts une liste d'options extraite à l'aide de getopts @param locale la langue de l'application """ QMainWindow.__init__(self) QWidget.__init__(self, parent) self.locale = locale from Ui_main import Ui_Dialog self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.graphWidget.setWorld(0, -5, 1, 5) # begins with A0 checked self.ui.A0Check.setCheckState(Qt.Checked) # connects the panel's great button self.connect(self.ui.panelButton, SIGNAL("clicked()"), self.panelHelp) # clears the text browser self.showhelp("") # initialize self.tw: table of widgets which are on the panel self.NSIG = 1 + 32 # number of signals; zeroth element is unused self.tw = [None] * self.NSIG # left entry widgets: 6, 7, 10 self.setTwDisplay(1, self.ui.ID0_display) self.setTwDisplay(2, self.ui.ID0_display) self.setTwEdit(6, self.ui.SQR1_edit) self.setTwEdit(7, self.ui.SQR2_edit) self.setTwDisplay(8, self.ui.SQR2_display) self.setTwEdit(10, self.ui.PULSE_edit) self.setTwDisplay(15, self.ui.FREQ_display) self.setTwDisplay(22, self.ui.SEN_display_2) self.setTwDisplay(23, self.ui.SEN_display) self.setTwDisplay(24, self.ui.A2_display) self.setTwDisplay(25, self.ui.A1_display) self.setTwDisplay(26, self.ui.A0_display) self.setTwDisplay(27, self.ui.CS_display) self.setTwEdit(28, self.ui.CS_edit) self.setTwEdit(30, self.ui.BPV_edit) self.setTwEdit(31, self.ui.UPV_edit) self.connect(self.ui.OD0_check, SIGNAL("stateChanged(int)"), self.OD0toggle) self.connect(self.ui.OD1_check, SIGNAL("stateChanged(int)"), self.OD1toggle) self.connect(self.ui.ID0_button_F, SIGNAL("clicked()"), self.freq_id0) self.connect(self.ui.AMPLI_button_F, SIGNAL("clicked()"), self.freq_ampin) self.connect(self.ui.SEN_button_F, SIGNAL("clicked()"), self.freq_sen) self.connect(self.ui.ID0_button_pcent, SIGNAL("clicked()"), self.pcent_id0) self.connect(self.ui.horizontalSlider, SIGNAL("valueChanged(int)"), self.set_timebase) self.connect(self.ui.A0Check, SIGNAL("stateChanged(int)"), self.toggleA0) self.connect(self.ui.A1Check, SIGNAL("stateChanged(int)"), self.toggleA1) self.connect(self.ui.fitCheck, SIGNAL("stateChanged(int)"), self.toggleFit) self.connect(self.ui.lisCheck, SIGNAL("stateChanged(int)"), self.toggleLis) self.connect(self.ui.saveButton, SIGNAL("clicked()"), self.save) self.connect(self.ui.xmButton, SIGNAL("clicked()"), self.xmgrace) self.connect(self.ui.ftButton, SIGNAL("clicked()"), self.do_fft) self.connect(self.ui.quitButton, SIGNAL("clicked()"), self.close) # other intializations self.VPERDIV = 1.0 # Volts per division, vertical scale self.delay = 10 # Time interval between samples self.np = 100 # Number of samples self.nc = 1 # Number of channels self.lissa = False # drawing lissajous-type plots self.chanmask = 1 # byte to store the mask for active analogic channels. self.np = 100 # number of points to plot (and samples to get) self.delay = 10 # delay for measurements (µs between two samples) self.measure = 0 # boolean to toggle data fitting self.NOSQR2 = True # SQR2 is not set self.NOSF = True # No frequency on SENSOR input self.NOAF = True # No frequency on Amplifier input, T15 self.NODF = True # No frequency on Digital input 0 self.OUTMASK = 0 # Digital outputs to LOW # connect to the eyes box self.eye = eyes.open() # Try several times to make a connection # starts the timer for refresh loop if self.eye == None: self.setWindowTitle("EYES Hardware NOT found.") self.showhelp("EYES Hardware Not Found.<br/>Re-Connect USB cable and restart the program.", "red") else: self.setWindowTitle(("EYES Hardware found on " + str(self.eye.device))) self.eye.write_outputs(0) self.eye.disable_actions() self.eye.loadall_calib() self.timer = QTimer(self) self.connect(self.timer, SIGNAL("timeout()"), self.update) self.timer.start(500) # refresh twice per second if possible def save(self, filename="measures.dat"): """ save current data to a file @param filename the name of the file """ self.eye.save(self.trace, filename) self.showhelp("Traces saved to %s" % filename) def xmgrace(self): """ opens xmgrage with current data in a plot """ if self.eye.grace(self.trace) == False: self.showhelp("Could not find Xmgrace or Pygrace. Install them", "red") def do_fft(self, filename="measureFFT.dat"): """ opens xmgrage with current data in a FFT plot @param filename the name of the file """ if EYEMATH == False: self.showhelp("Could not find scipy package. Install it", "red") return if self.trace == None: return transform = [] for xy in self.trace: fr, tr = eyemath.fft(xy[1], self.delay * self.nc * 0.001) transform.append([fr, tr]) self.eye.save(transform, filename) self.eye.grace(transform, "freq", "power") self.showhelp("Fourier transform Saved to %s" % filename) def toggleA0(self, state): """ callback function for the A0 check box @param state state of the checkbox """ if state == Qt.Checked: self.chanmask = self.chanmask | 1 else: self.chanmask = self.chanmask & 254 self.adjustChannels() def toggleA1(self, state): """ callback function for the A1 check box @param state state of the checkbox """ if state == Qt.Checked: self.chanmask = self.chanmask | 2 else: self.chanmask = self.chanmask & 253 self.adjustChannels() def adjustChannels(self): """ adjust channel flags when some has been toggled """ if self.chanmask == 3: self.nc = 2 else: self.nc = 1 if self.chanmask == 0: self.ui.graphWidget.delete_lines() self.ui.graphWidget.update() def toggleFit(self, state): """ callback function for the Fit check box @param state state of the checkbox """ if state == Qt.Checked: self.measure = 1 else: self.measure = 0 self.showhelp("") # to erase previous fittings if any def toggleLis(self, state): """ callback function for the Lis check box @param state state of the checkbox """ if state == Qt.Checked: self.lissa = 1 else: self.lissa = 0 def freq_id0(self): """ force the display of the frequency at ID0 """ fr = self.eye.digin_frequency(0) if fr < 0: self.labset(1, "0 Hz") else: self.labset(1, "%5.2f Hz" % fr) def freq_ampin(self): fr = self.eye.ampin_frequency() if fr < 0: self.labset(15, "0 Hz") self.NOAF = True else: self.labset(15, "%5.2f Hz" % (fr)) self.NOAF = False def freq_sen(self): fr = self.eye.sensor_frequency() if fr < 0: self.labset(22, "0 Hz") self.NOSF = True else: self.labset(22, "%5.2f Hz" % (fr)) self.NOSF = False def pcent_id0(self): """ force the display of the duty cycle at ID0 """ hi = self.eye.r2ftime(0, 0) if hi > 0: lo = self.eye.f2rtime(0, 0) ds = 100 * hi / (hi + lo) self.labset(1, "%5.2f %%" % (ds)) else: self.labset(1, "0 Hz") def set_timebase(self, value): """ callback for the horizontal slider @param value: the position of the cursor in range(10) """ assert value in range(10) divs = [0.050, 0.100, 0.200, 0.500, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0] msperdiv = divs[value] self.np = 200 self.delay = msperdiv * 100 if self.delay < 10: # for value==0 # self.delay == 5 is too short; increase the delay, get less measurements self.np = 20 * self.delay * self.nc self.delay = 10 elif self.delay > 1000: # for value in [8,9] # self.delay in [2000, 5000] is too long; get more measurements, decrease the delay self.np = self.delay / 5 / self.nc self.delay = 1000 # don't allow float values self.delay = int(self.delay) self.np = int(self.np) self.setTimeVoltageWorld() def setTimeVoltageWorld(self): """ ensures the right viewport for ordinary oscillogramme """ self.ui.graphWidget.setWorld( 0, -5 * self.VPERDIV, self.np * self.delay * 0.001, 5 * self.VPERDIV, xUnit="ms", yUnit="V" ) def OD0toggle(self, state): """ Callback for the check box OD0 @param state the state of the check box """ if state == Qt.Checked: self.ui.OD0_check.setStyleSheet(bgreen) self.ui.OD0_check.setText(_("HI")) self.OUTMASK |= 1 << 0 else: self.ui.OD0_check.setStyleSheet(bgray) self.ui.OD0_check.setText(_("LO")) self.OUTMASK &= ~(1 << 0) self.eye.write_outputs(self.OUTMASK & 3) def OD1toggle(self, state): """ Callback for the check box OD1 @param state the state of the check box """ if state == Qt.Checked: self.ui.OD1_check.setStyleSheet(bgreen) self.ui.OD1_check.setText(_("HI")) self.OUTMASK |= 1 << 1 else: self.ui.OD1_check.setStyleSheet(bgray) self.ui.OD1_check.setText(_("LO")) self.OUTMASK &= ~(1 << 1) self.eye.write_outputs(self.OUTMASK & 3) def setTwDisplay(self, i, w): """ affects a widget to the table, when it is used to display values @param i the index in the table @param w the widget """ self.tw[i] = w w.setReadOnly(True) return def panelHelp(self): """ callback used when one clicks over the panel """ wpos = self.geometry().topLeft() pos = QCursor.pos() x = pos.x() - wpos.x() y = pos.y() - wpos.y() plug = int(1.0 + (y - 12) / (550 - 12) * 16) if x in range(11, 72): self.showhelp(help[plug]) elif x in range(394, 455): plug = 33 - plug self.showhelp(help[plug]) else: self.showhelp(help[0]) def setTwEdit(self, i, w): """ affects a widget to the table, when it is used to enter values @param i the index in the table @param w the widget """ self.tw[i] = w self.connect(w, SIGNAL("editingFinished ()"), self.make_process(w)) return def make_process(self, w): """ function factory to make callbacks for line editors on the Panel @param w a widget which will send a signal """ # begin of definition of a process which will use w as a local variable def process(): """ callback for line editors on the Panel """ for i in range(self.NSIG): if self.tw[i] == w: # Look for the widget where Enter is pressed fld = i break msg = "" try: val = float(w.text()) # Get the value entered by the user except: return if fld == 6: # Set SQR1 freq = self.eye.set_sqr1(val) self.twset(fld, "%5.1f" % freq) elif fld == 7: # Set SQR2 self.eye.set_sqr2(val) freq = self.eye.get_sqr2() if freq > 0: self.labset(8, "%5.1f Hz" % freq) self.NOSQR2 = False else: self.labset(8, "0 Hz") self.NOSQR2 = True elif fld == 10: # Set Pulse duty cycle ds = self.eye.set_pulse(val) self.twset(fld, "%5.1f" % ds) elif fld == 28: # Set Current self.eye.set_current(val) self.twset(fld, "%5.3f" % val) elif fld == 30: self.eye.set_voltage(0, val) self.twset(i, "%5.3f" % val) elif fld == 31: self.eye.set_voltage(1, val) self.twset(fld, "%5.3f" % val) # end of definition of the process with w as a local variable return process def update(self, debug=True): """ the routine for the periodic timer; reports an error when something goes wrong @param debug setting it to True escapes the try/except clause, so errors can be raised """ if debug: self.routine_work() return try: self.routine_work() except: self.showhelp("Transaction Error.", "red") def routine_work(self): """ sequence of actions to be done at each timer's tick """ self.trace = [] # a pair of vectors which remains local to mainWindow g = self.ui.graphWidget tt, vv = None, None if self.lissa == True: t, v, tt, vv = self.eye.capture01(self.np, self.delay) g.delete_lines() g.setWorld(-5, -5, 5, 5, xUnit="V", yUnit="V") g.polyline(v, vv) self.trace.append([v, vv]) elif self.chanmask == 1 or self.chanmask == 2: # Waveform display code t, v = self.eye.capture(self.chanmask - 1, self.np, self.delay) g.delete_lines() g.polyline(t, v, self.chanmask - 1) self.trace.append([t, v]) elif self.chanmask == 3: t, v, tt, vv = self.eye.capture01(self.np, self.delay) g.delete_lines() g.polyline(t, v) g.polyline(tt, vv, 1) self.trace.append([t, v]) self.trace.append([tt, vv]) self.curveFit(t, v, tt, vv) # fits the curves v = self.eye.get_voltage(6) # CS voltage self.labset(27, "%5.3f V" % v) v = self.eye.get_voltage(0) # A0 self.labset(26, "%5.3f V" % v) v = self.eye.get_voltage(1) # A1 self.labset(25, "%5.3f V" % v) v = self.eye.get_voltage(2) # A2 self.labset(24, "%5.3f V" % v) v = self.eye.get_voltage(4) # SENSOR self.labset(23, "%5.3f V" % v) res = self.eye.read_inputs() # Set the color based on Input Levels if res & 1: # ID0 self.ui.ID0_display.setStyleSheet(bgreen) else: self.ui.ID0_display.setStyleSheet(bgray) if res & 2: # ID1 self.ui.ID1_display.setStyleSheet(bgreen) else: self.ui.ID1_display.setStyleSheet(bgray) if res & 4: # T15 input self.ui.FREQ_display.setStyleSheet(bgreen) else: self.ui.FREQ_display.setStyleSheet(bgray) if res & 8: # Sensor Input self.ui.SEN_display_2.setStyleSheet(bgreen) else: self.ui.SEN_display_2.setStyleSheet(bgray) if self.NOSQR2 == False: freq = self.eye.get_sqr2() if freq > 0: self.labset(8, "%5.1f Hz" % freq) else: self.labset(8, "0 Hz") self.NOSQR2 = True if self.NOSF == False: freq = self.eye.sensor_frequency() if freq > 0: self.labset(22, "%5.1f Hz" % freq) else: self.labset(22, "0 Hz") self.NOSF = True def curveFit(self, t, v, tt=None, vv=None): """ Curve fitting routine @param t : abscissa vector @param v : ordinate vector @param tt: abscissa vector @param vv: ordinate vector """ if not self.measure: return if not EYEMATH: self.showhelp("python-scipy not installed. Required for data fitting", "red") return s = "" if self.chanmask in (1, 2): fa = eyemath.fit_sine(t, v) if fa != None: rms = self.eye.rms(v) f0 = fa[1][1] * 1000 s = "CH%d: %5.2f V, F= %5.2f Hz" % (self.chanmask >> 1, rms, f0) else: s = "CH%d: nosig " % (self.chanmask >> 1) elif self.chanmask == 3: fa = eyemath.fit_sine(t, v) if fa != None: rms = self.eye.rms(v) f0 = fa[1][1] * 1000 ph0 = fa[1][2] s += "CH0: %5.2f V, F= %5.2f Hz" % (rms, f0) else: s += "CH0: no signal" fb = eyemath.fit_sine(tt, vv) if fb != None: rms = self.eye.rms(vv) f1 = fb[1][1] * 1000 ph1 = fb[1][2] s = s + "<br/>CH1: %5.2f V, F= %5.2f Hz" % (rms, f1) if fa != None and abs(f0 - f1) < f0 * 0.1: s = s + "<br/>dphi= %5.1f" % ((ph1 - ph0) * 180.0 / math.pi) else: s += "<br/>CH1:no signal" self.showhelp(s, "blue") return def showhelp(self, s, color="black"): """ displays a new text in the text browser @param s a plain or html text @param color a color to span over it """ self.ui.helpBrowser.clear() self.ui.helpBrowser.setAcceptRichText(True) t = QTextDocument() t.setHtml("<span style='color:%s;font-family:monospace;font-size:11px;'>%s</span>" % (color, s)) self.ui.helpBrowser.setDocument(t) def labset(self, i, s): self.tw[i].setText(s) def twset(self, i, s): self.tw[i].setText(s)
class mainWindow(QMainWindow): def __init__(self, parent, opts, locale="fr_FR"): """ Le constructeur @param parent un QWidget @param opts une liste d'options extraite à l'aide de getopts @param locale la langue de l'application """ QMainWindow.__init__(self) QWidget.__init__(self, parent) self.locale = locale from Ui_main import Ui_Dialog self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.graphWidget.setWorld(0, -5, 1, 5) # begins with A0 checked self.ui.A0Check.setCheckState(Qt.Checked) # connects the panel's great button self.connect(self.ui.panelButton, SIGNAL("clicked()"), self.panelHelp) # clears the text browser self.showhelp('') # initialize self.tw: table of widgets which are on the panel self.NSIG = 1 + 32 # number of signals; zeroth element is unused self.tw = [None] * self.NSIG # left entry widgets: 6, 7, 10 self.setTwDisplay(1, self.ui.ID0_display) self.setTwDisplay(2, self.ui.ID0_display) self.setTwEdit(6, self.ui.SQR1_edit) self.setTwEdit(7, self.ui.SQR2_edit) self.setTwDisplay(8, self.ui.SQR2_display) self.setTwEdit(10, self.ui.PULSE_edit) self.setTwDisplay(15, self.ui.FREQ_display) self.setTwDisplay(22, self.ui.SEN_display_2) self.setTwDisplay(23, self.ui.SEN_display) self.setTwDisplay(24, self.ui.A2_display) self.setTwDisplay(25, self.ui.A1_display) self.setTwDisplay(26, self.ui.A0_display) self.setTwDisplay(27, self.ui.CS_display) self.setTwEdit(28, self.ui.CS_edit) self.setTwEdit(30, self.ui.BPV_edit) self.setTwEdit(31, self.ui.UPV_edit) self.connect(self.ui.OD0_check, SIGNAL("stateChanged(int)"), self.OD0toggle) self.connect(self.ui.OD1_check, SIGNAL("stateChanged(int)"), self.OD1toggle) self.connect(self.ui.ID0_button_F, SIGNAL("clicked()"), self.freq_id0) self.connect(self.ui.AMPLI_button_F, SIGNAL("clicked()"), self.freq_ampin) self.connect(self.ui.SEN_button_F, SIGNAL("clicked()"), self.freq_sen) self.connect(self.ui.ID0_button_pcent, SIGNAL("clicked()"), self.pcent_id0) self.connect(self.ui.horizontalSlider, SIGNAL("valueChanged(int)"), self.set_timebase) self.connect(self.ui.A0Check, SIGNAL("stateChanged(int)"), self.toggleA0) self.connect(self.ui.A1Check, SIGNAL("stateChanged(int)"), self.toggleA1) self.connect(self.ui.fitCheck, SIGNAL("stateChanged(int)"), self.toggleFit) self.connect(self.ui.lisCheck, SIGNAL("stateChanged(int)"), self.toggleLis) self.connect(self.ui.saveButton, SIGNAL("clicked()"), self.save) self.connect(self.ui.xmButton, SIGNAL("clicked()"), self.xmgrace) self.connect(self.ui.ftButton, SIGNAL("clicked()"), self.do_fft) self.connect(self.ui.quitButton, SIGNAL("clicked()"), self.close) # other intializations self.VPERDIV = 1.0 # Volts per division, vertical scale self.delay = 10 # Time interval between samples self.np = 100 # Number of samples self.nc = 1 # Number of channels self.lissa = False # drawing lissajous-type plots self.chanmask = 1 # byte to store the mask for active analogic channels. self.np = 100 # number of points to plot (and samples to get) self.delay = 10 # delay for measurements (µs between two samples) self.measure = 0 # boolean to toggle data fitting self.NOSQR2 = True # SQR2 is not set self.NOSF = True # No frequency on SENSOR input self.NOAF = True # No frequency on Amplifier input, T15 self.NODF = True # No frequency on Digital input 0 self.OUTMASK = 0 # Digital outputs to LOW # connect to the eyes box self.eye = eyes.open() # Try several times to make a connection # starts the timer for refresh loop if self.eye == None: self.setWindowTitle('EYES Hardware NOT found.') self.showhelp( 'EYES Hardware Not Found.<br/>Re-Connect USB cable and restart the program.', 'red') else: self.setWindowTitle( ('EYES Hardware found on ' + str(self.eye.device))) self.eye.write_outputs(0) self.eye.disable_actions() self.eye.loadall_calib() self.timer = QTimer(self) self.connect(self.timer, SIGNAL("timeout()"), self.update) self.timer.start(500) # refresh twice per second if possible def save(self, filename='measures.dat'): """ save current data to a file @param filename the name of the file """ self.eye.save(self.trace, filename) self.showhelp('Traces saved to %s' % filename) def xmgrace(self): """ opens xmgrage with current data in a plot """ if self.eye.grace(self.trace) == False: self.showhelp('Could not find Xmgrace or Pygrace. Install them', 'red') def do_fft(self, filename='measureFFT.dat'): """ opens xmgrage with current data in a FFT plot @param filename the name of the file """ if EYEMATH == False: self.showhelp('Could not find scipy package. Install it', 'red') return if self.trace == None: return transform = [] for xy in self.trace: fr, tr = eyemath.fft(xy[1], self.delay * self.nc * 0.001) transform.append([fr, tr]) self.eye.save(transform, filename) self.eye.grace(transform, 'freq', 'power') self.showhelp('Fourier transform Saved to %s' % filename) def toggleA0(self, state): """ callback function for the A0 check box @param state state of the checkbox """ if state == Qt.Checked: self.chanmask = self.chanmask | 1 else: self.chanmask = self.chanmask & 254 self.adjustChannels() def toggleA1(self, state): """ callback function for the A1 check box @param state state of the checkbox """ if state == Qt.Checked: self.chanmask = self.chanmask | 2 else: self.chanmask = self.chanmask & 253 self.adjustChannels() def adjustChannels(self): """ adjust channel flags when some has been toggled """ if self.chanmask == 3: self.nc = 2 else: self.nc = 1 if self.chanmask == 0: self.ui.graphWidget.delete_lines() self.ui.graphWidget.update() def toggleFit(self, state): """ callback function for the Fit check box @param state state of the checkbox """ if state == Qt.Checked: self.measure = 1 else: self.measure = 0 self.showhelp('') # to erase previous fittings if any def toggleLis(self, state): """ callback function for the Lis check box @param state state of the checkbox """ if state == Qt.Checked: self.lissa = 1 else: self.lissa = 0 def freq_id0(self): """ force the display of the frequency at ID0 """ fr = self.eye.digin_frequency(0) if fr < 0: self.labset(1, '0 Hz') else: self.labset(1, '%5.2f Hz' % fr) def freq_ampin(self): fr = self.eye.ampin_frequency() if fr < 0: self.labset(15, '0 Hz') self.NOAF = True else: self.labset(15, '%5.2f Hz' % (fr)) self.NOAF = False def freq_sen(self): fr = self.eye.sensor_frequency() if fr < 0: self.labset(22, '0 Hz') self.NOSF = True else: self.labset(22, '%5.2f Hz' % (fr)) self.NOSF = False def pcent_id0(self): """ force the display of the duty cycle at ID0 """ hi = self.eye.r2ftime(0, 0) if hi > 0: lo = self.eye.f2rtime(0, 0) ds = 100 * hi / (hi + lo) self.labset(1, '%5.2f %%' % (ds)) else: self.labset(1, '0 Hz') def set_timebase(self, value): """ callback for the horizontal slider @param value: the position of the cursor in range(10) """ assert value in range(10) divs = [0.050, 0.100, 0.200, 0.500, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0] msperdiv = divs[value] self.np = 200 self.delay = msperdiv * 100 if self.delay < 10: # for value==0 # self.delay == 5 is too short; increase the delay, get less measurements self.np = 20 * self.delay * self.nc self.delay = 10 elif self.delay > 1000: # for value in [8,9] # self.delay in [2000, 5000] is too long; get more measurements, decrease the delay self.np = self.delay / 5 / self.nc self.delay = 1000 # don't allow float values self.delay = int(self.delay) self.np = int(self.np) self.setTimeVoltageWorld() def setTimeVoltageWorld(self): """ ensures the right viewport for ordinary oscillogramme """ self.ui.graphWidget.setWorld(0, -5 * self.VPERDIV, self.np * self.delay * 0.001, 5 * self.VPERDIV, xUnit='ms', yUnit='V') def OD0toggle(self, state): """ Callback for the check box OD0 @param state the state of the check box """ if state == Qt.Checked: self.ui.OD0_check.setStyleSheet(bgreen) self.ui.OD0_check.setText(_("HI")) self.OUTMASK |= (1 << 0) else: self.ui.OD0_check.setStyleSheet(bgray) self.ui.OD0_check.setText(_("LO")) self.OUTMASK &= ~(1 << 0) self.eye.write_outputs(self.OUTMASK & 3) def OD1toggle(self, state): """ Callback for the check box OD1 @param state the state of the check box """ if state == Qt.Checked: self.ui.OD1_check.setStyleSheet(bgreen) self.ui.OD1_check.setText(_("HI")) self.OUTMASK |= (1 << 1) else: self.ui.OD1_check.setStyleSheet(bgray) self.ui.OD1_check.setText(_("LO")) self.OUTMASK &= ~(1 << 1) self.eye.write_outputs(self.OUTMASK & 3) def setTwDisplay(self, i, w): """ affects a widget to the table, when it is used to display values @param i the index in the table @param w the widget """ self.tw[i] = w w.setReadOnly(True) return def panelHelp(self): """ callback used when one clicks over the panel """ wpos = self.geometry().topLeft() pos = QCursor.pos() x = pos.x() - wpos.x() y = pos.y() - wpos.y() plug = int(1.0 + (y - 12) / (550 - 12) * 16) if x in range(11, 72): self.showhelp(help[plug]) elif x in range(394, 455): plug = 33 - plug self.showhelp(help[plug]) else: self.showhelp(help[0]) def setTwEdit(self, i, w): """ affects a widget to the table, when it is used to enter values @param i the index in the table @param w the widget """ self.tw[i] = w self.connect(w, SIGNAL("editingFinished ()"), self.make_process(w)) return def make_process(self, w): """ function factory to make callbacks for line editors on the Panel @param w a widget which will send a signal """ # begin of definition of a process which will use w as a local variable def process(): """ callback for line editors on the Panel """ for i in range(self.NSIG): if self.tw[ i] == w: # Look for the widget where Enter is pressed fld = i break msg = '' try: val = float(w.text()) # Get the value entered by the user except: return if fld == 6: # Set SQR1 freq = self.eye.set_sqr1(val) self.twset(fld, '%5.1f' % freq) elif fld == 7: # Set SQR2 self.eye.set_sqr2(val) freq = self.eye.get_sqr2() if freq > 0: self.labset(8, '%5.1f Hz' % freq) self.NOSQR2 = False else: self.labset(8, '0 Hz') self.NOSQR2 = True elif fld == 10: # Set Pulse duty cycle ds = self.eye.set_pulse(val) self.twset(fld, '%5.1f' % ds) elif fld == 28: # Set Current self.eye.set_current(val) self.twset(fld, '%5.3f' % val) elif fld == 30: self.eye.set_voltage(0, val) self.twset(i, '%5.3f' % val) elif fld == 31: self.eye.set_voltage(1, val) self.twset(fld, '%5.3f' % val) # end of definition of the process with w as a local variable return process def update(self, debug=True): """ the routine for the periodic timer; reports an error when something goes wrong @param debug setting it to True escapes the try/except clause, so errors can be raised """ if debug: self.routine_work() return try: self.routine_work() except: self.showhelp('Transaction Error.', 'red') def routine_work(self): """ sequence of actions to be done at each timer's tick """ self.trace = [] # a pair of vectors which remains local to mainWindow g = self.ui.graphWidget tt, vv = None, None if self.lissa == True: t, v, tt, vv = self.eye.capture01(self.np, self.delay) g.delete_lines() g.setWorld(-5, -5, 5, 5, xUnit='V', yUnit='V') g.polyline(v, vv) self.trace.append([v, vv]) elif self.chanmask == 1 or self.chanmask == 2: # Waveform display code t, v = self.eye.capture(self.chanmask - 1, self.np, self.delay) g.delete_lines() g.polyline(t, v, self.chanmask - 1) self.trace.append([t, v]) elif self.chanmask == 3: t, v, tt, vv = self.eye.capture01(self.np, self.delay) g.delete_lines() g.polyline(t, v) g.polyline(tt, vv, 1) self.trace.append([t, v]) self.trace.append([tt, vv]) self.curveFit(t, v, tt, vv) # fits the curves v = self.eye.get_voltage(6) # CS voltage self.labset(27, '%5.3f V' % v) v = self.eye.get_voltage(0) # A0 self.labset(26, '%5.3f V' % v) v = self.eye.get_voltage(1) # A1 self.labset(25, '%5.3f V' % v) v = self.eye.get_voltage(2) # A2 self.labset(24, '%5.3f V' % v) v = self.eye.get_voltage(4) # SENSOR self.labset(23, '%5.3f V' % v) res = self.eye.read_inputs() # Set the color based on Input Levels if res & 1: # ID0 self.ui.ID0_display.setStyleSheet(bgreen) else: self.ui.ID0_display.setStyleSheet(bgray) if res & 2: # ID1 self.ui.ID1_display.setStyleSheet(bgreen) else: self.ui.ID1_display.setStyleSheet(bgray) if res & 4: # T15 input self.ui.FREQ_display.setStyleSheet(bgreen) else: self.ui.FREQ_display.setStyleSheet(bgray) if res & 8: # Sensor Input self.ui.SEN_display_2.setStyleSheet(bgreen) else: self.ui.SEN_display_2.setStyleSheet(bgray) if self.NOSQR2 == False: freq = self.eye.get_sqr2() if freq > 0: self.labset(8, '%5.1f Hz' % freq) else: self.labset(8, '0 Hz') self.NOSQR2 = True if self.NOSF == False: freq = self.eye.sensor_frequency() if freq > 0: self.labset(22, '%5.1f Hz' % freq) else: self.labset(22, '0 Hz') self.NOSF = True def curveFit(self, t, v, tt=None, vv=None): """ Curve fitting routine @param t : abscissa vector @param v : ordinate vector @param tt: abscissa vector @param vv: ordinate vector """ if not self.measure: return if not EYEMATH: self.showhelp( 'python-scipy not installed. Required for data fitting', 'red') return s = '' if self.chanmask in (1, 2): fa = eyemath.fit_sine(t, v) if fa != None: rms = self.eye.rms(v) f0 = fa[1][1] * 1000 s = 'CH%d: %5.2f V, F= %5.2f Hz' % (self.chanmask >> 1, rms, f0) else: s = 'CH%d: nosig ' % (self.chanmask >> 1) elif self.chanmask == 3: fa = eyemath.fit_sine(t, v) if fa != None: rms = self.eye.rms(v) f0 = fa[1][1] * 1000 ph0 = fa[1][2] s += 'CH0: %5.2f V, F= %5.2f Hz' % (rms, f0) else: s += 'CH0: no signal' fb = eyemath.fit_sine(tt, vv) if fb != None: rms = self.eye.rms(vv) f1 = fb[1][1] * 1000 ph1 = fb[1][2] s = s + '<br/>CH1: %5.2f V, F= %5.2f Hz' % (rms, f1) if fa != None and abs(f0 - f1) < f0 * 0.1: s = s + '<br/>dphi= %5.1f' % ( (ph1 - ph0) * 180.0 / math.pi) else: s += '<br/>CH1:no signal' self.showhelp(s, 'blue') return def showhelp(self, s, color='black'): """ displays a new text in the text browser @param s a plain or html text @param color a color to span over it """ self.ui.helpBrowser.clear() self.ui.helpBrowser.setAcceptRichText(True) t = QTextDocument() t.setHtml( "<span style='color:%s;font-family:monospace;font-size:11px;'>%s</span>" % (color, s)) self.ui.helpBrowser.setDocument(t) def labset(self, i, s): self.tw[i].setText(s) def twset(self, i, s): self.tw[i].setText(s)