00001 #!/usr/local/bin/python 00002 # 00003 # sweepRejectTest.py 00004 # Test code to test what happens when sweeps never appear in RC. 00005 # Sweeps are disabled by reimplementing the shut() method. 00006 # DO NOT use this code as a basis for any user code. --Jim 00007 # 00008 # 00009 # 00010 # Copyright 2004 00011 # by 00012 # The Board of Trustees of the 00013 # Leland Stanford Junior University. 00014 # All rights reserved. 00015 # 00016 00017 00018 00019 00020 __facility__ = "Online" 00021 __abstract__ = "Application to test Bad or Timed out SWEEP events." 00022 __author__ = "J. Panetta <panetta@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online" 00023 __date__ = ("$Date: 2005/03/21 17:58:11 $").split(' ')[1] 00024 __version__ = "$Revision: 1.2 $" 00025 __release__ = "$Name: R04-12-00 $" 00026 __credits__ = "SLAC" 00027 00028 import LATTE.copyright_SLAC 00029 00030 import threading 00031 import logging as log 00032 import time 00033 00034 from LATTE.runcontrol.rcTransitions import rcTransitions 00035 from LATTE.runcontrol.ArgumentImpl import ArgumentImpl 00036 00037 from support.SimpleGasuExample import * 00038 from support.MiniGLTExample import * 00039 00040 00041 # This class puts up a GUI for inputting a value of some sort. It is used by 00042 # the userApplication example to get the number of self triggers to take. 00043 class userArgument(ArgumentImpl): 00044 "GUI for getting the user to input some sort of value." 00045 def __init__(self, parent = None, name = None, modal = 0, fl = 0): 00046 ArgumentImpl.__init__(self, parent, name, modal, fl) 00047 self.__value = 0 00048 self.setCaption("Hello world!") 00049 00050 def OKButtonClicked(self): 00051 self.__value = int(self.ArgumentList.text().latin1()) 00052 self.close() 00053 00054 def CancelButtonClicked(self): 00055 self.__value = None 00056 self.close() 00057 00058 def getValue(self, caption): 00059 self.setCaption(caption) 00060 self.show() 00061 self.exec_loop() 00062 return self.__value 00063 00064 class userArgText(object): 00065 "Text user interface for getting the user to input some sort of value" 00066 def __init__(self): 00067 pass 00068 00069 def getValue(self, caption): 00070 return int(raw_input("%s: " % (caption))) 00071 00072 00073 # Example application implementation. 00074 # Note that the name of the class must be userApplication. 00075 # Look at rcTransitions for names of other transition methods that can be used. 00076 class userApplication(rcTransitions): 00077 "Implmentation class for a user application" 00078 def __init__(self, rc, userId, debug): 00079 rcTransitions.__init__(self, rc, userId, debug) 00080 log.debug("userApplication.__init__()") 00081 self.__eventSem = threading.Semaphore(0) 00082 self.__cmdSynchSem = threading.Semaphore(0) 00083 00084 def getName(self): 00085 return __name__ 00086 00087 def setup(self): 00088 log.debug("userApplication.setup()") 00089 00090 if self.rc is None: 00091 self.__arg = userArgText() 00092 else: 00093 self.__arg = self.rc.createGUI(userArgument, self.rc, 'test1', 1) 00094 00095 # Get a TEM instance 00096 if self.lat.TEMcnt() == 1: 00097 tem = self.lat.TEM[self.lat.TEM.keys()[0]] 00098 elif self.lat.TEMcnt() > 1: 00099 tem = self.lat.TEM.all() 00100 else: 00101 log.fatal("No TEM(s) found in the schema") 00102 return -1 00103 00104 # clear TEM stats reg 00105 tem.COMMAND_RESPONSE = 0 00106 00107 # clear TEM status reg 00108 tem.STATUS = 0 00109 00110 # enable output in our GCCCs 00111 # broadcast load of GCCC_REG_CONFIGURATION 00112 00113 bcast_ccc = tem.allCCC() 00114 bcast_ccc.CONFIGURATION = 0x80000000L 00115 00116 # disable all GCRCs in all GCCCs via broadcast # GCCC_REG_LAYER_MASK_0, GCCC_REG_LAYER_MASK_1 00117 bcast_ccc.LAYER_MASK_0 = 0xFFFFFFFFL 00118 bcast_ccc.LAYER_MASK_1 = 0xFFFFFFFFL 00119 ccc0 = tem.downCCC(0) # O$GCCC_00 00120 ccc0.LAYER_MASK_0 = 0xFFFF0000L 00121 ccc0.LAYER_MASK_1 = 0xFFFF000FL 00122 ccc2 = tem.downCCC(2) # O$GCCC_02 00123 ccc2.LAYER_MASK_0 = 0xFFFF0000L 00124 ccc2.LAYER_MASK_1 = 0xFFFF0000L 00125 00126 # large timeouts for all GCCCs 00127 # broadcast load of GCCC_REG_EVENT_TIMEOUTS 00128 bcast_ccc.EVENT_TIMEOUTS = 0x0 00129 00130 # Two choices for the trigger, GEM and MiniGLT 00131 if self.lat.existsGEM(): 00132 self.trigger( BadGasuExample() ) 00133 else: 00134 self.trigger( BadGLTExample() ) 00135 00136 # A state transition can be rejected by not returning None 00137 return None 00138 00139 def startRun(self): 00140 log.debug("userApplication.startRun()") 00141 00142 caption = "Enter number of triggers to take" 00143 if self.rc is None: 00144 cnt = self.__arg.getValue(caption) 00145 else: 00146 cnt = self.rc.execGUImethod(self.__arg.getValue, caption) 00147 00148 # The user pressed 'Cancel' 00149 if cnt is None: return -1 00150 self.__cnt = cnt 00151 00152 if self.rc is not None: 00153 self.getParameterVerifier().add(caption, cnt) 00154 00155 # Spawn a thread to synchronize commands with events 00156 self.__cmdSynchQuit = False 00157 00158 # A state transition can be rejected by not returning None 00159 return None 00160 00161 def stopRun(self): 00162 log.debug("userApplication.stopRun()") 00163 00164 if self.getBadEvents() == 0 and self.getErrorEvents() == 0: 00165 self.setCompletionStatus(self.COMPL_STATUS_PASSED) 00166 else: 00167 self.setCompletionStatus(self.COMPL_STATUS_FAILED) 00168 00169 self.__cmdSynchQuit = True 00170 self.__eventSem.release() 00171 00172 # The STOP_RUN transition can not be rejected 00173 00174 def resume(self): 00175 log.debug("userApplication.resume()") 00176 00177 # Issue self trigger to make up for the one that was lost during PAUSE 00178 self.trigger().solicit() 00179 00180 return None 00181 00182 def stop(self): 00183 log.debug("userApplication.stop()") 00184 00185 return self.stopRun() 00186 00187 def teardown(self): 00188 log.debug("userApplication.teardown()") 00189 # Allow the C++ object to be deleted 00190 if self.rc is not None and self.__arg is not None: 00191 self.__arg.deleteLater() 00192 00193 def process(self, (status, buffer)): 00194 "Method called back for each data event taken" 00195 #log.debug("userApplication.process()") 00196 00197 evtCli = self.evtCli 00198 00199 if status != 0: 00200 if evtCli.isGGLTStatus(): 00201 log.error("GGLT_STATUS=%d %s" % (evtCli.getGGLTStatus(), evtCli.getGGLTStatusStr())) 00202 elif not evtCli.checkOnlineStatus(status, self.evtCli.PLAYBACK_ERROR): 00203 log.error("EVENT ERROR= 0x%x %s" % (status, evtCli.getOnlineStatusStr())) 00204 self.__eventSem.release() 00205 return 00206 try: 00207 # In the future this event may contain additional data 00208 if evtCli.isSweepEvent(): return 00209 except: 00210 # Event summary word inaccessible, handle the bad event here 00211 log.exception("") 00212 return 00213 00214 00215 # Get next event triggered 00216 self.__eventSem.release() 00217 00218 00219 def commandSynch(self): 00220 "Method called by the command synchronization task" 00221 import time 00222 trigger = self.trigger() 00223 eventSem = self.__eventSem 00224 00225 # Drain the semaphore release count 00226 # Handles the case when the stop run release collided with a trigger release 00227 while eventSem.acquire(0): pass 00228 00229 t0 = time.time() 00230 00231 # Compensate for the extra CMD_SELF_TRIGGER below 00232 cnt = 1 00233 count = self.__cnt 00234 00235 # Wait for START_RUN to enable triggers 00236 trigger.waitForMaskEnable() 00237 00238 trigger.solicit() # Issue an internal trigger 00239 eventSem.acquire() # Wait for the event to be processed 00240 00241 t1 = trigger.getEnableTime() # get the last trigger enable time from GLT 00242 while cnt < count and not self.__cmdSynchQuit: 00243 cnt += 1 00244 trigger.solicit() # Issue an internal trigger 00245 time.sleep(.0001) 00246 eventSem.acquire() # Wait for the event to be processed 00247 00248 t2 = trigger.getTimeStamp() # Get the last trigger timestamp 00249 00250 if t1 is None: 00251 t1 = t0 00252 if t2 is None: 00253 t2 = time.time() 00254 dT = t2 - t1 00255 if dT == 0.0: dT = 0.000001 00256 log.info("%s processed %d events in %.3f seconds = %.1f events/second" % \ 00257 (self.getName(), self.evtCnt, dT, self.evtCnt/dT)) 00258 00259 # Get out of waiting when in suite or standalone mode 00260 self.sync() 00261 00262 # execute the GUI functions for stopRun, just in case 00263 if not self.__cmdSynchQuit and not self.isRunFromSuite(): 00264 if self.rc is not None: 00265 self.rc.doStop() 00266 00267 def wait(self): 00268 self.__cmdSynchSem.acquire() 00269 00270 def sync(self): 00271 if __name__ == "__main__" or self.isRunFromSuite(): 00272 self.__cmdSynchSem.release() 00273 00274 from LATTE.trigger.rcTrgGem import * 00275 from LATTE.trigger.rcTrgMiniGLT import * 00276 class BadGasuExample(SimpleGasuExample): 00277 """\brief BadGasuExample 00278 """ 00279 def __init__(self): 00280 """\brief BadGasuExample constructor 00281 """ 00282 SimpleGasuExample.__init__(self) 00283 def shut(self, sweepEvent, progress = None): 00284 """Re-implementation of the shut function to NEVER send a sweep 00285 00286 NEVER EVER EVER use this code in a real trigger system. --Jim Panetta 00287 This code is only to test a particular bug in sweep timeouts. 00288 """ 00289 00290 gemw = self.GEM().GEMW 00291 gemsc = self.GEM().GEMSC 00292 00293 #0) determine whether we are enabled or not 00294 if gemw.WINDOW_OPEN_MASK != 0: 00295 enabled = True 00296 else: 00297 enabled = False 00298 00299 #1) disable triggers 00300 goodSolicit = self.solicit 00301 # self.solicit = self.__falseSolicit 00302 self.disable() 00303 sweepEvent.clear() 00304 00305 #2) Replace contents of all schedulers with solicited with (Engine) f 00306 # Doing it by hand 00307 oldSched = [ gemsc.CONDITIONS_40_47, 00308 gemsc.CONDITIONS_48_4F, 00309 gemsc.CONDITIONS_50_57, 00310 gemsc.CONDITIONS_58_5F, 00311 gemsc.CONDITIONS_60_67, 00312 gemsc.CONDITIONS_68_6F, 00313 gemsc.CONDITIONS_70_77, 00314 gemsc.CONDITIONS_78_7F ] 00315 scheduler = ( 0xffffffffL ) # Everything's f! 00316 gemsc.CONDITIONS_40_47 = scheduler 00317 gemsc.CONDITIONS_48_4F = scheduler 00318 gemsc.CONDITIONS_50_57 = scheduler 00319 gemsc.CONDITIONS_58_5F = scheduler 00320 gemsc.CONDITIONS_60_67 = scheduler 00321 gemsc.CONDITIONS_68_6F = scheduler 00322 gemsc.CONDITIONS_70_77 = scheduler 00323 gemsc.CONDITIONS_78_7F = scheduler 00324 00325 #2.5) Wait until we don't have progress 00326 if progress is not None: 00327 while True: 00328 if progress() == 0: 00329 break 00330 time.sleep(.5) 00331 # print "waiting for progress" 00332 00333 #3) Change conditions to be solicit only, solicit a trigger 00334 gemw.WINDOW_OPEN_MASK = TrgGem._TrgGem__SOLICIT_MASK 00335 # self.GEM().downGEMC().CMD_TRIGGER = 1 00336 00337 #4) Block until the sweep is detected by rcTransitions then disable triggers 00338 tmo = self._rcTrgGem__SWEEP_TMO 00339 while (tmo > 0.0): 00340 if sweepEvent.isSet(): break 00341 sweepEvent.wait(0.50) 00342 if progress is not None: 00343 if progress() != 0: 00344 tmo = self._rcTrgGem__SWEEP_TMO 00345 continue 00346 tmo -= 0.50 00347 if tmo <= 0: 00348 sweepEvent.set() 00349 logging.fatal("Trigger sweep timed out before all events were drained") 00350 return False 00351 00352 self.disable() 00353 00354 #5) Put the original contents of schedulers back 00355 gemsc.CONDITIONS_40_47 = oldSched[0] 00356 gemsc.CONDITIONS_48_4F = oldSched[1] 00357 gemsc.CONDITIONS_50_57 = oldSched[2] 00358 gemsc.CONDITIONS_58_5F = oldSched[3] 00359 gemsc.CONDITIONS_60_67 = oldSched[4] 00360 gemsc.CONDITIONS_68_6F = oldSched[5] 00361 gemsc.CONDITIONS_70_77 = oldSched[6] 00362 gemsc.CONDITIONS_78_7F = oldSched[7] 00363 00364 #6) Put the trigger conditions back. 00365 if enabled: 00366 self.enable() 00367 self.solicit = goodSolicit 00368 00369 return True 00370 00371 00372 class BadGLTExample(MiniGLTExample): 00373 """\brief MiniTower example interface to MiniGLT 00374 """ 00375 def __init__(self): 00376 """\brief AcdTriggerExample constructor 00377 """ 00378 MiniGLTExample.__init__(self) 00379 def shut(self, sweepEvent, progress = None): 00380 """Re-implementation of the shut function to NEVER send a sweep 00381 00382 NEVER EVER EVER use this code in a real trigger system. --Jim Panetta 00383 This code is only to test a particular bug in sweep timeouts. 00384 """ 00385 00386 glt = self.GLT() 00387 00388 #0) disable triggers 00389 if not glt.triggersDisabled(): 00390 enabled = True 00391 else: 00392 enabled = False 00393 goodSolicit = self.solicit 00394 # self.solicit = self.__falseSolicit 00395 00396 self.disable() 00397 sweepEvent.clear() 00398 00399 #1) Set up marker logic 00400 mask = glt.MASK # Cache Mask, CalStrobe and Tack 00401 calStrobe = glt.CAL_STROBE 00402 tack = glt.TACK 00403 zeroSuppress = glt.ZERO_SUPPRESS 00404 fourRange = glt.FOUR_RANGE_READOUT 00405 marker = glt.MARKER 00406 00407 glt.MASK = TrgMiniGLT._TrgMiniGLT__SOLICIT_MASK # Enable internal trigger only 00408 glt.MARKER = rcTrgMiniGLT._rcTrgMiniGLT__SWEEP_MARKER # Signal that we're sweeping 00409 glt.CAL_STROBE = 0 # Don't inject charge 00410 glt.TACK = 1 # Force a readout 00411 glt.ZERO_SUPPRESS = 1 # Yes to zero suppression 00412 glt.FOUR_RANGE_READOUT = 0 # No to four range readout 00413 00414 #2) enable and solicit 00415 glt.enableMask() 00416 self.waitForMaskEnable() 00417 # self.GLT().CMD_SELF_TRIGGER = 1 # Solicit a trigger 00418 00419 #3) Block until the sweep is detected by rcTransitions then disable triggers 00420 tmo = self._rcTrgMiniGLT__SWEEP_TMO 00421 while (tmo > 0.0): 00422 if sweepEvent.isSet(): break 00423 sweepEvent.wait(0.5) 00424 if progress is not None: 00425 if progress() != 0: 00426 tmo = self._rcTrgMiniGLT__SWEEP_TMO 00427 continue 00428 tmo -= 0.5 00429 if tmo <= 0: 00430 sweepEvent.set() 00431 logging.fatal("Trigger sweep timed out before all events were drained") 00432 return False 00433 self.disable() 00434 00435 #4) Put the original contents of scheduler 0x40 back, and put the TAM back 00436 glt.CAL_STROBE = calStrobe 00437 glt.TACK = tack 00438 glt.MARKER = marker 00439 glt.ZERO_SUPPRESS = zeroSuppress 00440 glt.FOUR_RANGE_READOUT = fourRange 00441 glt.MASK = mask 00442 00443 #5) Put the trigger conditions back 00444 if enabled: 00445 glt.enableMask() 00446 self.solicit = goodSolicit 00447 00448 return True