00001 #!/usr/local/bin/python 00002 # 00003 # Copyright 2002 00004 # by 00005 # The Board of Trustees of the 00006 # Leland Stanford Junior University. 00007 # All rights reserved. 00008 # 00009 00010 __facility__ = "Online" 00011 __abstract__ = "Environmental Monitoring implementation GUI class" 00012 __author__ = "S. Tuvi <stuvi@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online" 00013 __date__ = ("$Date: 2005/05/25 01:48:20 $").split(' ')[1] 00014 __version__ = "$Revision: 1.2 $" 00015 __release__ = "$Name: R04-12-00 $" 00016 __credits__ = "SLAC" 00017 00018 import LATTE.copyright_SLAC 00019 from LATTE.runcontrol.RunControlMainGUIImpl import rcFileSelector 00020 00021 from GpibPwrCtrl import GpibPwrCtrl 00022 from qt import * 00023 00024 import sys 00025 from ConfigParser import ConfigParser 00026 import logging as log 00027 import atexit 00028 00029 class GpibPwrCtrlImpl(GpibPwrCtrl): 00030 def __init__(self, gpib, parent = None, name = None, fl = 0): 00031 GpibPwrCtrl.__init__(self, None, name, fl) 00032 self.connect(self.buttonSelectConfig,SIGNAL("clicked()"),self.readPowerConfig) 00033 self.connect(self.buttonReset,SIGNAL("clicked()"),self.resetDevice) 00034 self.connect(self.buttonEnableOut,SIGNAL("clicked()"),self.enableOutput) 00035 self.connect(self.buttonDisableOut,SIGNAL("clicked()"),self.disableOutput) 00036 self.connect(self.buttonRelease,SIGNAL("clicked()"),self.releaseGpib) 00037 self.connect(self.comboConfig,SIGNAL("activated(const QString &)"),self.loadConfig) 00038 atexit.register(self.shutdown) 00039 self.__address = None 00040 self.__input = {'vmax':None, 'vset':None, 'imax':None, 'iset':None} 00041 self.__cmdWrite = {'vmax':'VMAX %2.3fV', 00042 'vset':'VSET %2.3fV', 00043 'imax':'IMAX %2.3fA', 00044 'iset':'ISET %2.3fA' 00045 } 00046 self.__cmdRead = {'ovp' : 'OVP?', 00047 'vmax':'VMAX?', 00048 'vset':'VSET?', 00049 'imax':'IMAX?', 00050 'iset':'ISET?' 00051 } 00052 00053 self.__labelRead = {'ovp' : self.labelOVP, 00054 'vmax': self.labelVMAX, 00055 'vset': self.labelVSET, 00056 'imax': self.labelIMAX, 00057 'iset': self.labelISET 00058 } 00059 00060 self.__txtWrite = {'vmax': self.txtVMAX, 00061 'vset': self.txtVSET, 00062 'imax': self.txtIMAX, 00063 'iset': self.txtISET 00064 } 00065 00066 self.__funcApply = {'vmax': lambda: self.applyData('vmax'), 00067 'vset': lambda: self.applyData('vset'), 00068 'imax': lambda: self.applyData('imax'), 00069 'iset': lambda: self.applyData('iset') 00070 } 00071 self.connect(self.buttonApplyVMAX,SIGNAL("clicked()"),self.__funcApply['vmax']) 00072 self.connect(self.buttonApplyVSET,SIGNAL("clicked()"),self.__funcApply['vset']) 00073 self.connect(self.buttonApplyIMAX,SIGNAL("clicked()"),self.__funcApply['imax']) 00074 self.connect(self.buttonApplyISET,SIGNAL("clicked()"),self.__funcApply['iset']) 00075 00076 self.__currentCfg = '' 00077 self.__init = False 00078 self.buttonRelease.setEnabled(0) 00079 self.__power = gpib.Power() 00080 self.__timer = QTimer(self) 00081 self.__interval = 5000 00082 self.connect(self.__timer, SIGNAL("timeout()"), self.updateReadout) 00083 00084 def readPowerConfig(self): 00085 self.stopTimer() 00086 self.txtError.setText('') 00087 self.labelStatus.setText('') 00088 cfgSel = rcFileSelector(self.__currentCfg, "(*.cfg)", self, "Select Power Configuration") 00089 cfgFilename = cfgSel.getValue() 00090 # Allow the C++ object to be deleted 00091 cfgSel.deleteLater() 00092 if cfgFilename is None: return 00093 self.__currentCfg = cfgFilename 00094 if self.comboConfig.listBox().findItem(cfgFilename) is None: 00095 self.comboConfig.insertItem(cfgFilename) 00096 self.comboConfig.clearEdit() 00097 self.comboConfig.setCurrentText(cfgFilename) 00098 self.loadConfig(cfgFilename) 00099 00100 def loadConfig(self, cfgFilename): 00101 self.waitCursor() 00102 qApp.processEvents() 00103 confParser = ConfigParser() 00104 confParser.read(str(cfgFilename)) 00105 self.__address = None 00106 parseError = self.parserToScreen(confParser) 00107 if parseError: 00108 self.txtError.setPaletteForegroundColor(Qt.red) 00109 self.txtError.setText("Error in reading configuration file") 00110 elif self.__address is not None: 00111 if self.initGPIB() is not None: 00112 status = self.checkOutputEnable() 00113 self.startTimer() 00114 self.normalCursor() 00115 00116 def initGPIB(self): 00117 if self.__init: 00118 self.__power.unlock() 00119 self.__power.close() 00120 self.__init = False 00121 self.buttonRelease.setEnabled(0) 00122 status = self.__power.open(self.__address) 00123 if status == 0: 00124 status = self.__power.lock() 00125 if status != 0: 00126 self.updateError() 00127 return None 00128 else: 00129 self.__power.causeError(0) 00130 self.__init = True 00131 self.buttonRelease.setEnabled(1) 00132 return 0 00133 else: 00134 return None 00135 00136 def checkOutputEnable(self): 00137 self.__power.write("OUT?") 00138 data = self.__power.read() 00139 status = self.updateError() 00140 if status != 0: 00141 return status 00142 if data.strip(' \n\r') == "OUT 1": 00143 self.buttonEnableOut.setOn(1) 00144 else: 00145 self.buttonDisableOut.setOn(1) 00146 return 0 00147 00148 def applyData(self, type): 00149 self.__power.write(self.__cmdWrite[type] % float(str(self.__txtWrite[type].text()))) 00150 status = self.updateError() 00151 if status == 0: 00152 self.__labelRead[type].setText(self.readData(type)) 00153 00154 def readData(self, type): 00155 self.__power.write(self.__cmdRead[type]) 00156 data = self.__power.read() 00157 status = self.updateError() 00158 if status != 0: 00159 return None 00160 if data is not None: 00161 data = data.strip(" \n\r") 00162 typeValue = data.split() 00163 if typeValue[0].lower() == type: 00164 data = typeValue[1] 00165 return data 00166 00167 def resetDevice(self): 00168 self.__power.write("RST") 00169 self.updateError() 00170 00171 def enableOutput(self): 00172 self.__power.write("OUT 1") 00173 self.updateError() 00174 00175 def disableOutput(self): 00176 self.__power.write("OUT 0") 00177 self.updateError() 00178 00179 def updateError(self): 00180 errorStr = self.__power.getErrorStr() 00181 if errorStr == 'No error': 00182 self.txtError.unsetPalette() 00183 self.txtError.setText(errorStr) 00184 self.labelStatus.unsetPalette() 00185 self.labelStatus.setText('READY') 00186 return 0 00187 else: 00188 self.txtError.setPaletteForegroundColor(Qt.red) 00189 self.txtError.setText(errorStr) 00190 errorNo = self.__power.getErrorNo() 00191 if errorNo == 11: # Locked 00192 self.labelStatus.setPaletteForegroundColor(Qt.red) 00193 self.labelStatus.setText('LOCKED') 00194 else: 00195 self.labelStatus.unsetPalette() 00196 self.labelStatus.setText('READY') 00197 return errorNo 00198 00199 def clearReadout(self): 00200 for label in self.__labelRead.values(): 00201 label.setText('') 00202 00203 def clearSettings(self): 00204 for text in self.__txtWrite.values(): 00205 text.setText('') 00206 00207 def updateReadout(self): 00208 self.clearReadout() 00209 for type in self.__cmdRead.keys(): 00210 data = self.readData(type) 00211 status = self.updateError() 00212 if status == 11: # Locked 00213 self.labelStatus.setText('LOCKED') 00214 return 00215 elif status != 0: 00216 return 00217 else: 00218 self.labelStatus.setText('READY') 00219 self.__labelRead[type].setText(data) 00220 00221 def parserToScreen(self, confParser): 00222 error = False 00223 self.clearSettings() 00224 sections = confParser.sections() 00225 for section in sections: 00226 if section == 'device': 00227 for option in confParser.options(section): 00228 if option == 'address': 00229 self.__address = confParser.get(section, option) 00230 self.labelDevice.setText(self.__address.split(':')[1]) 00231 00232 if section == 'input': 00233 for option in confParser.options(section): 00234 if option == 'vmax': 00235 self.__input['vmax'] = confParser.get(section, option) 00236 self.txtVMAX.setText(self.__input['vmax']) 00237 elif option == 'vset': 00238 self.__input['vset'] = confParser.get(section, option) 00239 self.txtVSET.setText(self.__input['vset']) 00240 elif option == 'imax': 00241 self.__input['imax'] = confParser.get(section, option) 00242 self.txtIMAX.setText(self.__input['imax']) 00243 elif option == 'iset': 00244 self.__input['iset'] = confParser.get(section, option) 00245 self.txtISET.setText(self.__input['iset']) 00246 00247 if self.__address is None: 00248 error = True 00249 log.error("'%s' option missing from section '%s'" % ('device', 'address')) 00250 00251 for inp in self.__input: 00252 if self.__input[inp] is None: 00253 error = True 00254 log.error("'%s' option missing from section '%s'" % (inp, 'input')) 00255 00256 return error 00257 00258 def releaseGpib(self): 00259 self.clearReadout() 00260 self.clearSettings() 00261 self.labelStatus.unsetPalette() 00262 self.labelStatus.setText('') 00263 self.txtError.unsetPalette() 00264 self.txtError.setText('') 00265 self.stopTimer() 00266 self.__power.unlock() 00267 self.__power.close() 00268 self.__init = False 00269 self.buttonRelease.setEnabled(0) 00270 00271 def startTimer(self): 00272 self.updateReadout() 00273 self.__timer.start(self.__interval) 00274 00275 def stopTimer(self): 00276 self.__timer.stop() 00277 00278 def showEvent(self, e): 00279 if self.__init: 00280 self.startTimer() 00281 00282 def closeEvent(self, e): 00283 self.stopTimer() 00284 e.accept() 00285 00286 def shutdown(self): 00287 self.unregisterExitHandler() 00288 self.stopTimer() 00289 self.__power.unlock() 00290 self.__power.close() 00291 00292 def unregisterExitHandler(self): 00293 for i in range(len(atexit._exithandlers)): 00294 if atexit._exithandlers[i][0] == self.shutdown: 00295 del atexit._exithandlers[i] 00296 break 00297 00298 def normalCursor(self): 00299 self.setCursor(QCursor(Qt.ArrowCursor)) 00300 00301 def waitCursor(self): 00302 self.setCursor(QCursor(Qt.WaitCursor)) 00303 00304 if __name__ == "__main__": 00305 import gpibCtrl 00306 a = QApplication(sys.argv) 00307 gpc = GpibPwrCtrlImpl(gpibCtrl) 00308 QObject.connect(a,SIGNAL("lastWindowClosed()"), a, SLOT("quit()")) 00309 a.setMainWidget(gpc) 00310 gpc.show() 00311 a.exec_loop() 00312