00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 __facility__ = "Online"
00012 __abstract__ = "Classes for determining alarm states"
00013 __author__ = "J. Panetta <panetta@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00014 __date__ = "12/29/2005"
00015 __updated__ = ("$Date: 2006/04/28 01:20:18 $").split(' ')[1]
00016 __version__ = "$Revision: 1.6 $"
00017 __release__ = "$Name: HEAD $"
00018 __credits__ = "SLAC"
00019
00020 import LICOS.copyright_SLAC
00021
00022 import threading
00023 import sys, os, asyncore
00024 from ConfigParser import ConfigParser
00025
00026 from qt import QApplication, QMainWindow, QObject
00027 from qt import QPopupMenu, QString, Qt, QColor, QTimer
00028 from qt import SIGNAL, SLOT
00029
00030
00031
00032 mainApp = QApplication(sys.argv)
00033 killEvent = threading.Event()
00034 killEvent.clear()
00035
00036 from LICOS.core.thread.guiBridges import GUIbridge
00037 from LICOS.tools.alarm.AlarmWindow import AlarmWindow
00038 from LICOS.tools.alarm.AlarmObjects import QLV_AlarmedItem, AlarmClient
00039 from LICOS.tools.alarm.AlarmStates import AlarmState
00040 from LICOS.tools.proxy.VscProxyPorts import VscProxyPorts
00041 from ISOC.TlmUtils.TlmRdbInterface import TlmRdbDb
00042
00043
00044 lightGray = QColor(0xd0,0xd0,0xd0)
00045 UPDATE_CHECK_TIME = 20
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 def asyncore_loop(timeout=1.0, use_poll=False, map=None):
00061 """replace the asyncore central loop and run it its own thread.
00062 Valid for Python 2.3.x
00063 Python 2.4 has an extra agument for loop, count.
00064 """
00065 if map is None:
00066 map = asyncore.socket_map
00067
00068 if use_poll:
00069 if hasattr(select, 'poll'):
00070 poll_fun = asyncore.poll3
00071 else:
00072 poll_fun = asyncore.poll2
00073 else:
00074 poll_fun = asyncore.poll
00075
00076 while map and not killEvent.isSet():
00077 poll_fun(timeout, map)
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 class AlarmHandler(AlarmWindow):
00092 def __init__(self, config, vscConfig, cvtHost,
00093 popAlarmSwitch = True,
00094 parent=None, name = None, fl = 0,):
00095 AlarmWindow.__init__(self, parent, name, fl)
00096
00097 self.MainAlarmListView.addColumn('Item')
00098 self.MainAlarmListView.addColumn('Raw Value')
00099 self.MainAlarmListView.addColumn('Eng Value')
00100 self.MainAlarmListView.addColumn('Description')
00101 self.MainAlarmListView.setSorting(0)
00102 self.MainAlarmListView.setPaletteBackgroundColor(lightGray)
00103
00104 self.__guiBridge = GUIbridge(threading.currentThread())
00105
00106 self.__configuration = config
00107 self.__vscConfig = vscConfig
00108 self.__cvtHost = cvtHost
00109
00110 self.__alarmItems = {}
00111 self.__source = None
00112 self.__tlmDb = None
00113 self.__cvc = None
00114
00115 self.__popAlarmSwitch = popAlarmSwitch
00116 self.__prevUpdateCounter = -1
00117
00118 self.connect(self.MainAlarmListView,
00119 SIGNAL("contextMenuRequested(QListViewItem *, const QPoint &, int)"),
00120 self.contextMenuShow)
00121
00122 self.buildContextMenu()
00123 self.__tlmDb, self.__source = self.__initDatabase()
00124
00125
00126 try:
00127 caption = config.get("GUI","caption")
00128 except:
00129 caption = 'Alarm Window'
00130 self.setCaption(QString(caption))
00131
00132 self.configure()
00133
00134
00135 try:
00136 delay = int(config.get("timer","delay"))*1000
00137 except:
00138 delay = UPDATE_CHECK_TIME * 1000
00139 self.__timer = QTimer()
00140 self.__timer.connect(self.__timer, SIGNAL("timeout()"), self.__timerEvent)
00141 self.__timer.start(delay, False)
00142
00143 def fileExit(self):
00144 self.close()
00145
00146 def close(self, qParam = False):
00147 self.__guiBridge.shutdown()
00148 return QMainWindow.close(self, qParam)
00149
00150 def configuration(self):
00151 return self.__configuration
00152
00153 def configure(self):
00154
00155
00156 config = self.configuration()
00157 if not config.has_section('top_level'):
00158 msg = "Configuration lacks 'top_level' section. Cannot configure AlarmHandler"
00159 raise RuntimeError(msg)
00160
00161
00162 self.__alarmItems['top_level'] = self.MainAlarmListView
00163 for tlItem in self.__getMembers('top_level'):
00164 self.addItem(tlItem, 'top_level')
00165
00166
00167 validMnems = []
00168 for mnem in self.__alarmItems.keys():
00169 if mnem not in validMnems and self.__tlmDb.mnem(mnem) is not None:
00170 validMnems.append(mnem)
00171 self.__alarmItems[mnem].setDescription(self.__tlmDb.mnem(mnem).desc())
00172
00173
00174 ports = VscProxyPorts(self.__vscConfig.getint('vsc', 'proxyPortBase'))
00175 self.__cvc = AlarmClient( host = self.__cvtHost,
00176 port = ports.cvtOut(),
00177 gui = self,
00178 mnemList = validMnems)
00179
00180 self.optionsAlarm_PopupsAction.setOn(self.__popAlarmSwitch)
00181 self.__cvc.registerAll()
00182
00183 def addItem(self, itemName, parentName):
00184 """!\brief Add an item to the alarm handler. Recursive.
00185
00186 \param Name of the item to be added
00187 """
00188 config = self.configuration()
00189
00190 parent = self.__alarmItems[parentName]
00191 thisItem = QLV_AlarmedItem(self, parent, str(itemName), AlarmState.NoLimit)
00192 self.__alarmItems[itemName] = thisItem
00193
00194 if itemName in config.sections():
00195 if config.has_option(itemName, 'expanded'):
00196 expanded = config.getboolean(itemName, 'expanded')
00197 thisItem.setOpen( expanded )
00198 if config.has_option(itemName, 'description'):
00199 thisItem.setDescription( config.get(itemName, 'description').strip() )
00200 thisItem.setRawValue()
00201
00202 for member in self.__getMembers(itemName):
00203 self.addItem(member, itemName)
00204 thisItem.sortChildItems(0, True)
00205
00206
00207 def __getMembers(self, itemName):
00208 """!\brief retrieve a list of members of an alarmed hierarchy entry
00209
00210 """
00211 config = self.configuration()
00212 if config.has_option(itemName, 'members'):
00213 mStr = config.get(itemName, 'members')
00214 mList = [ a.strip() for a in mStr.split(',') ]
00215 else:
00216 mList = []
00217
00218 return mList
00219
00220 def alarmItems(self):
00221 return self.__alarmItems
00222
00223 def tlmDb(self):
00224 return self.__tlmDb
00225
00226 def guiBridge(self):
00227 return self.__guiBridge
00228
00229 def contextMenuShow(self, item, pos, col ):
00230 self.__contextMenu.exec_loop(pos)
00231
00232 def buildContextMenu(self):
00233 self.__contextMenu = QPopupMenu(self)
00234 self.__contextMenu.insertItem("Show Data", self.showData)
00235
00236
00237 self.__contextMenu.insertItem("Show Limits",self.showLimits)
00238 self.__contextMenu.insertItem("Acknowledge Alarms", self.acknowledge)
00239 self.__contextMenu.insertItem("Disable", self.disableAlarm)
00240 self.__contextMenu.insertItem("Enable", self.enableAlarm)
00241
00242 def showData(self):
00243
00244 selItem = self.MainAlarmListView.selectedItem()
00245 if selItem is not None:
00246 selItem.showInfo()
00247
00248 def showLimits(self):
00249
00250 selItem = self.MainAlarmListView.selectedItem()
00251 if selItem is not None:
00252 selItem.showLimits()
00253
00254 def expandChildren(self):
00255
00256 selItem = self.MainAlarmListView.selectedItem()
00257 if selItem is not None:
00258 selItem.expandChildren(True)
00259
00260 def collapseChildren(self):
00261
00262 selItem = self.MainAlarmListView.selectedItem()
00263 if selItem is not None:
00264 selItem.expandChildren(False)
00265
00266 def acknowledge(self):
00267
00268 selItem = self.MainAlarmListView.selectedItem()
00269 if selItem is not None:
00270 selItem.recalculate()
00271
00272 def disableAlarm(self):
00273 selItem = self.MainAlarmListView.selectedItem()
00274 selItem.disable()
00275
00276 selItem.setState(selItem.state(),forceUpdate=True)
00277
00278 def enableAlarm(self):
00279 selItem = self.MainAlarmListView.selectedItem()
00280 selItem.enable()
00281
00282 selItem.setState(selItem.state(),forceUpdate=True)
00283
00284 def customEvent(self, e):
00285 self.__guiBridge.handleCustomEvent(e)
00286
00287 def __cfgDb(self, config):
00288 import psycopg
00289 dsn = config.get('postgres', 'dsn')
00290 db = psycopg.connect(dsn)
00291
00292 return db
00293
00294 def __initDatabase(self):
00295 config = self.__vscConfig
00296
00297 csect = config.sections()
00298 sect = "tlmdb"
00299 if sect not in csect:
00300 msg = "Config file %s is missing required section: %s" % (config, sect)
00301 raise KeyError, msg
00302
00303 source = int(config.get("tlmdb", "source"))
00304 build = config.get("tlmdb", "build")
00305
00306 db = self.__cfgDb(config)
00307 cur = db.cursor()
00308
00309 tlmDb = TlmRdbDb(cur)
00310
00311 tlmDb.populate(source=source, build=build)
00312
00313 return (tlmDb, source)
00314
00315 def __timerEvent(self):
00316 val = self.__cvc.getUpdateCount()
00317 if val == self.__prevUpdateCounter:
00318 self.leUpdateCounter.setPaletteBackgroundColor(Qt.red)
00319 else:
00320 self.leUpdateCounter.setPaletteBackgroundColor(lightGray)
00321 self.__prevUpdateCounter = val
00322 self.leUpdateCounter.setText(QString(str(val)))
00323 x = self.MainAlarmListView.sizeHint()
00324
00325 def optionsAlarmPopups(self, state):
00326 if state:
00327 self.__popAlarmSwitch = True
00328 else:
00329 self.__popAlarmSwitch = False
00330
00331 def popAlarms(self):
00332
00333 return self.__popAlarmSwitch
00334
00335
00336 def main(options):
00337
00338
00339 config = ConfigParser()
00340 config.read(options.config)
00341
00342 vscConfig = ConfigParser()
00343 vscConfig.read(options.vscConfig)
00344
00345 cvtHost = options.cvtHost
00346
00347
00348 if options.noPopAlarm is None:
00349 popAlarmSwitch = True
00350 else:
00351 popAlarmSwitch = False
00352
00353 p = AlarmHandler(config, vscConfig, cvtHost, popAlarmSwitch)
00354 mainApp.setMainWidget(p)
00355
00356 p.show()
00357 QObject.connect(mainApp, SIGNAL("lastWindowClosed()"), mainApp, SLOT("quit()"))
00358
00359 threading.Thread(target=asyncore_loop).start()
00360
00361 mainApp.exec_loop()
00362 killEvent.set()
00363
00364 def usage():
00365 s = '/'
00366 if os.name == 'nt': s = '\\'
00367 name = sys.argv[0].split('.')[-2].split(s)[-1]
00368 return "%s is used to display telemetry data from a database." % (name)
00369
00370
00371
00372 if __name__ == '__main__':
00373
00374 from LICOS.util.gOptions import Options
00375
00376 options = Options(['config', 'vscConfig', 'cvtHost'],switches = ['noPopAlarm'])
00377 try:
00378 options.parse()
00379 except Exception, msg:
00380 options.usage(usage())
00381 raise Exception, msg
00382 x = options.noPopAlarm
00383
00384 main(options)
00385