00001 #!/usr/local/bin/python 00002 # 00003 # Copyright 2004 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__ = "Example CAL test application" 00012 __author__ = "R. Claus <Claus@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online" 00013 __date__ = ("$Date: 2005/03/21 17:58:12 $").split(' ')[1] 00014 __version__ = "$Revision: 1.7 $" 00015 __release__ = "$Name: R04-12-00 $" 00016 __credits__ = "SLAC" 00017 00018 import LATTE.copyright_SLAC 00019 00020 import threading 00021 import logging as log 00022 import time 00023 00024 from LATTE.runcontrol.rcTransitions import rcTransitions 00025 from LATTE.runcontrol.ArgumentImpl import ArgumentImpl 00026 #from rcHouseKeeping import rcHouseKeeping 00027 00028 from support.SimpleGasuExample import * 00029 from support.MiniGLTExample import * 00030 00031 import LDF 00032 import Numeric 00033 00034 00035 OneDgContrib = True # Select between two custom LATcontribution methods 00036 00037 class CAL_LATcontribution(object): 00038 def __init__(self, buf): 00039 # For application level contributions, offset the typeID value from the 00040 # subsystem base values defined in LDF/include/LATidentity.h. 00041 # The primary value identifies the structure of the contribution. 00042 # The secondary value identifies the version of that structure. 00043 primary = LDF.LATprimaryId().Base_CAL + 0 00044 secondary = LDF.LATsecondaryId().Base_CAL + 0 00045 00046 # Pad the contributions with zeros to force it to be an integer number of 00047 # longwords in length 00048 remainder = len(buf) & 0x3 00049 if remainder: buf += "\x00\x00\x00"[0:4-remainder] 00050 00051 typeId = LDF.LATtypeId(primary, secondary) 00052 length = len(buf) # 16 bit contribution length in bytes 00053 opaque = 0 # User defined 16 bit quantity 00054 00055 assert (length < 0x10000), "LATcontribution length is > 64K: %d" % (length) 00056 00057 # Need to prepend some space for the LATcontribution header items 00058 # I would prefer to hide this in the LDF package, but don't know how, now 00059 buf = (len(LDF.LATcontribution()) * " ") + buf 00060 00061 # The following may byteswap 00062 self.__contrib = LDF.LATcontribution.create(typeId, length, opaque, buf) 00063 00064 def __str__(self): 00065 """Helper python method so that we can take the str() of this object""" 00066 return self.__contrib.string() 00067 00068 def __len__(self): 00069 """Helper python method so that we can take the len() of this object""" 00070 return self.__contrib.length() 00071 00072 00073 # This class puts up a GUI for inputting a value of some sort. It is used by 00074 # the userApplication example to get the number of self triggers to take. 00075 class userArgument(ArgumentImpl): 00076 "GUI for getting the user to input some sort of value." 00077 def __init__(self, parent = None, name = None, modal = 0, fl = 0): 00078 ArgumentImpl.__init__(self, parent, name, modal, fl) 00079 self.__value = 0 00080 self.setCaption("Hello world!") 00081 00082 def OKButtonClicked(self): 00083 self.__value = int(self.ArgumentList.text().latin1()) 00084 self.close() 00085 00086 def CancelButtonClicked(self): 00087 self.__value = None 00088 self.close() 00089 00090 def getValue(self, caption): 00091 self.setCaption(caption) 00092 self.show() 00093 self.exec_loop() 00094 return self.__value 00095 00096 class userArgText(object): 00097 "Text user interface for getting the user to input some sort of value" 00098 def __init__(self): 00099 pass 00100 00101 def getValue(self, caption): 00102 return int(raw_input("%s: " % (caption))) 00103 00104 00105 # Example application implementation. 00106 # Note that the name of the class must be userApplication. 00107 # Look at rcTransitions for names of other transition methods that can be used. 00108 class userApplication(rcTransitions): 00109 "Implmentation class for a user application" 00110 def __init__(self, rc, userId, debug): 00111 rcTransitions.__init__(self, rc, userId, debug) 00112 log.debug("userApplication.__init__()") 00113 self.__eventSem = threading.Semaphore(0) 00114 self.__cmdSynchSem = threading.Semaphore(0) 00115 00116 def getName(self): 00117 return __name__ 00118 00119 def setup(self): 00120 log.debug("userApplication.setup()") 00121 00122 if self.rc is None: 00123 self.__arg = userArgText() 00124 else: 00125 self.__arg = self.rc.createGUI(userArgument, self.rc, 'test1', 1) 00126 00127 # Get a TEM instance 00128 if self.lat.TEMcnt() == 1: 00129 tem = self.lat.TEM[self.lat.TEM.keys()[0]] 00130 elif self.lat.TEMcnt() > 1: 00131 tem = self.lat.TEM.all() 00132 else: 00133 log.fatal("No TEM(s) found in the schema") 00134 return -1 00135 00136 #----- The following RESETs and other system register manipulation is 00137 #----- commented out as it is handled by RunControl. Other register 00138 #----- setup should be taken care of in the schema/configuration file. 00139 # reset the TEM since we are going to modify DATA_MASKS 00140 #tem.CMD_RESET = 1 00141 00142 # clear TEM stats reg 00143 tem.COMMAND_RESPONSE = 0 00144 00145 # clear TEM status reg 00146 tem.STATUS = 0 00147 00148 # enable CAL, disable TKR, no diag # 0x10FF for diag 00149 #tem.DATA_MASKS = 0x10FF 00150 00151 # TEM config reg # set TEM timeout 00152 #tem.CONFIGURATION = 0 00153 00154 #status = gTEMread( __GT, temId, TEM_REG_CONFIGURATION, &payload); 00155 #printf("tem config reg = 0x%08x\n", payload); 00156 00157 # enable output in our GCCCs 00158 # broadcast load of GCCC_REG_CONFIGURATION 00159 00160 #bcast_ccc = tem.allCCC() 00161 #bcast_ccc.CONFIGURATION = 0x80000000L 00162 00163 # disable all GCRCs in all GCCCs via broadcast # GCCC_REG_LAYER_MASK_0, GCCC_REG_LAYER_MASK_1 00164 #bcast_ccc.LAYER_MASK_0 = 0xFFFFFFFFL 00165 #bcast_ccc.LAYER_MASK_1 = 0xFFFFFFFFL 00166 #ccc0 = tem.downCCC(0) # O$GCCC_00 00167 #ccc0.LAYER_MASK_0 = 0xFFFF0000L 00168 #ccc0.LAYER_MASK_1 = 0xFFFF000FL 00169 #ccc2 = tem.downCCC(2) # O$GCCC_02 00170 #ccc2.LAYER_MASK_0 = 0xFFFF0000L 00171 #ccc2.LAYER_MASK_1 = 0xFFFF0000L 00172 00173 # config GCFE for calibration -- range 0 first 00174 #bcast_cfe = tem.allCCC().allCRC().allCFE() 00175 #bcast_cfe.CONFIG_0 = 0x00 00176 #bcast_cfe.CONFIG_1 = 0x36 00177 #bcast_cfe.FLE_DAC = 0x55 00178 #bcast_cfe.FHE_DAC = 0x55 00179 #bcast_cfe.LOG_ACPT = 0x10 00180 #bcast_cfe.RNG_ULD_DAC = 0x7F 00181 #bcast_cfe.REF_DAC = 0x7f 00182 00183 # config GCRC for calibration 00184 #bcast_crc = tem.allCCC().allCRC() 00185 #bcast_crc.DELAY_1 = 0xFF 00186 #bcast_crc.DELAY_2 = 0xFF 00187 #bcast_crc.DELAY_3 = 0xFF 00188 #bcast_crc.DAC = 0x42FE 00189 #bcast_crc.DAC = 0x42FE 00190 00191 # large timeouts for all GCCCs 00192 # broadcast load of GCCC_REG_EVENT_TIMEOUTS 00193 #bcast_ccc.EVENT_TIMEOUTS = 0x0 00194 #status = gGCCCread( __GT, temId, 1, GCCC_REG_EVENT_TIMEOUTS, &payload); 00195 #printf("gccc register event timeouts = 0x%08x\n", payload); 00196 00197 # Register environment variables for housekeeping 00198 #hsk = self.getHSK() 00199 #regs = [tem.regs['data_masks'], ccc2.regs['layer_mask_1']] 00200 #hsk.addEnvRegs(regs) 00201 #hsk.setUpdateInterval(1) 00202 00203 # Two choices for the trigger, GEM and MiniGLT 00204 if self.lat.existsGEM(): 00205 self.trigger( SimpleGasuExample() ) 00206 else: 00207 self.trigger( MiniGLTExample() ) 00208 00209 # Override the default event handler 00210 self.selectEventHandler(rcTransitions.EVENT_HANDLER_LEAN_AND_MEAN) 00211 00212 # A state transition can be rejected by not returning None 00213 return None 00214 00215 def startRun(self): 00216 log.debug("userApplication.startRun()") 00217 00218 caption = "Enter number of triggers to take" 00219 if self.rc is None: 00220 cnt = self.__arg.getValue(caption) 00221 else: 00222 cnt = self.rc.execGUImethod(self.__arg.getValue, caption) 00223 00224 # The user pressed 'Cancel' 00225 if cnt is None: return -1 00226 self.__cnt = cnt 00227 00228 self.getParameterVerifier().add(caption, cnt) 00229 00230 calHdr = "HDR:" 00231 calHdr += "LEN=%d:" % (9999) 00232 calHdr += "VERSION=%2d:" % (6) 00233 calHdr += "USERSEGMENT:" 00234 calHdr += "{'comment':" 00235 calHdr += " 'Comprehensive Functional Test (CPT) on CAL FM101 at 20.0 MHz and 3.3 volts', " 00236 calHdr += "'tackdelay': %d, " % (70) 00237 calHdr += "'leGain': %d, " % (5) 00238 calHdr += "'heGain': %d, " % (0) 00239 calHdr += "'app': '%s', " % (self.getName()) #'calf_mu_optical') 00240 calHdr += "'feconfig_0': %d, " % (517) 00241 00242 array = Numeric.array_str(2*Numeric.ones((4,4,12))) 00243 calHdr += "'feconfig_1list': array(%s), " % (array) 00244 00245 calHdr += "'fourRngFlag': %s, " % ('True') 00246 calHdr += "'suppression': %s" % ('False') 00247 calHdr += "}" 00248 00249 if OneDgContrib: 00250 # Two methods to add a LATcontribution to the data stream: 00251 # 1) Build a datagram containing the CAL_LATcontribution 00252 archiver = self.getArchiverInstance() 00253 if archiver is not None and not archiver.isClosed(): 00254 import struct 00255 lc = CAL_LATcontribution(calHdr) 00256 dg = LDF.LATdatagram() 00257 dg = struct.pack('>2L', dg.ID, len(dg) + len(lc)) 00258 archiver.writeTuple((dg, str(lc))) 00259 else: 00260 # 2) Prebuild the CAL_LATcontribution and prepend it to the first event 00261 # in process(), below. 00262 self.__latCon = str(CAL_LATcontribution(calHdr)) 00263 00264 # Spawn a thread to synchronize commands with events 00265 self.__cmdSynchQuit = False 00266 00267 # A state transition can be rejected by not returning None 00268 return None 00269 00270 def stopRun(self): 00271 log.debug("userApplication.stopRun()") 00272 00273 if self.getBadEvents() == 0 and self.getErrorEvents() == 0: 00274 self.setCompletionStatus(self.COMPL_STATUS_PASSED) 00275 else: 00276 self.setCompletionStatus(self.COMPL_STATUS_FAILED) 00277 00278 self.__cmdSynchQuit = True 00279 self.__eventSem.release() 00280 00281 # The STOP_RUN transition can not be rejected 00282 00283 def resume(self): 00284 log.debug("userApplication.resume()") 00285 00286 # Issue self trigger to make up for the one that was lost during PAUSE 00287 self.trigger().solicit() 00288 00289 return None 00290 00291 def stop(self): 00292 log.debug("userApplication.stop()") 00293 00294 return self.stopRun() 00295 00296 def teardown(self): 00297 log.debug("userApplication.teardown()") 00298 # Allow the C++ object to be deleted 00299 if self.rc is not None and self.__arg is not None: 00300 self.__arg.deleteLater() 00301 00302 def process(self, (status, latDatagram)): 00303 "Method called back for each data event taken" 00304 #log.debug("userApplication.process()") 00305 00306 #evtCli = self.evtCli 00307 00308 if status != 0: 00309 #if evtCli.isGGLTStatus(): 00310 log.error("%s.process(): GGLT_STATUS = 0x%08x = %d", self.getName(), status, status) 00311 #log.error("GGLT_STATUS=%d %s" % (evtCli.getGGLTStatus(), evtCli.getGGLTStatusStr())) 00312 #elif not evtCli.checkOnlineStatus(status, self.evtCli.PLAYBACK_ERROR): 00313 # log.error("EVENT ERROR= 0x%x %s" % (status, evtCli.getOnlineStatusStr())) 00314 #try: 00315 # # In the future this event may contain additional data 00316 # if evtCli.isSweepEvent(): return 00317 #except: 00318 # # Event summary word inaccessible, handle the bad event here 00319 # log.exception() 00320 # return 00321 00322 # Get next event triggered 00323 #self.__eventSem.release() 00324 00325 if not OneDgContrib: 00326 if self.__latCon is None: return 00327 00328 latCon = self.__latCon 00329 self.__latCon = None 00330 return latCon, latDatagram[8:] 00331 00332 def commandSynch(self): 00333 "Method called by the command synchronization task" 00334 import time 00335 trigger = self.trigger() 00336 eventSem = self.__eventSem 00337 00338 # Drain the semaphore release count 00339 # Handles the case when the stop run release collided with a trigger release 00340 while eventSem.acquire(0): pass 00341 00342 t0 = time.time() 00343 00344 # Compensate for the extra CMD_SELF_TRIGGER below 00345 cnt = 1 00346 count = self.__cnt 00347 00348 # Wait for START_RUN to enable triggers 00349 trigger.waitForMaskEnable() 00350 00351 trigger.solicit() # Issue an internal trigger 00352 #eventSem.acquire() # Wait for the event to be processed 00353 00354 t1 = trigger.getEnableTime() # get the last trigger enable time from GLT 00355 while cnt < count and not self.__cmdSynchQuit: 00356 cnt += 1 00357 trigger.solicit() # Issue an internal trigger 00358 time.sleep(.0001) 00359 #eventSem.acquire() # Wait for the event to be processed 00360 #trigger.disable() # Disable triggers 00361 # Do stuff 00362 #trigger.enable() # Enable triggers 00363 00364 t2 = trigger.getTimeStamp() # Get the last trigger timestamp 00365 00366 if t1 is None: 00367 t1 = t0 00368 if t2 is None: 00369 t2 = time.time() 00370 dT = t2 - t1 00371 if dT == 0.0: dT = 0.000001 00372 log.info("%s processed %d events in %.3f seconds = %.1f events/second" % \ 00373 (self.getName(), self.evtCnt, dT, self.evtCnt/dT)) 00374 00375 # Get out of waiting when in suite or standalone mode 00376 self.sync() 00377 00378 # execute the GUI functions for stopRun, just in case 00379 if not self.__cmdSynchQuit and not self.isRunFromSuite(): 00380 if self.rc is not None: 00381 self.rc.doStop() 00382 00383 def wait(self): 00384 self.__cmdSynchSem.acquire() 00385 00386 def sync(self): 00387 if __name__ == "__main__" or self.isRunFromSuite(): 00388 self.__cmdSynchSem.release() 00389 00390 00391 # Standalone mode: 00392 if __name__ == "__main__": 00393 import os 00394 log.basicConfig() 00395 log.getLogger("").setLevel(log.DEBUG) 00396 ua = userApplication(None, 321, 0) 00397 prefs = {'datasave': 1, 'datadir':os.path.join(os.environ['ONLINE_ROOT'],'temp')} 00398 ua.setPrefs(prefs) 00399 ua.rcSetup(os.path.join(os.environ['ONLINE_ROOT'], 'repos/simpleTemSchema.xml')) 00400 ua.rcStartRun() 00401 ua.wait() 00402 ua.rcStopRun() 00403 ua.rcTeardown() 00404 00405 # History: 00406 # $Log: testAppCal_dg.py,v $ 00407 # Revision 1.7 2005/03/21 17:58:12 claus 00408 # Modified to use the first TEM found in the schema, if only one is there, or 00409 # broadcast to all TEMs if there are multiple. 00410 # 00411 # Revision 1.6 2004/11/01 23:09:39 claus 00412 # Added a comment. 00413 # 00414 # Revision 1.5 2004/10/30 01:52:20 stuvi 00415 # Check if the archiver is None before accessing it. 00416 # 00417 # Revision 1.4 2004/10/25 02:44:43 panetta 00418 # Fixes regarding byteswapping and error contribution 00419 # 00420 # Revision 1.3 2004/10/23 23:50:33 claus 00421 # Added completionStatus logic. 00422 # 00423 # Revision 1.2 2004/10/18 01:00:19 claus 00424 # Provided switch between 2 examples of adding custom LATcontributions. 00425 # 00426 # Revision 1.4 2004/08/31 03:13:38 stuvi 00427 # Integrated the parameter verifier with Run Control 00428 # 00429 # Revision 1.3 2004/08/18 18:00:15 stuvi 00430 # Updated for LATTE 4. 00431 # All hippo functions go through the Qt GUI bridge now. 00432 # 00433 # Revision 1.2 2004/08/13 04:46:22 claus 00434 # Got rid of obsolete TRUE and FALSE declarations. 00435 # 00436 # Revision 1.1 2004/07/28 21:24:00 stuvi 00437 # Added testAppCal and its supporting classes. 00438 # 00439 # Revision 1.28 2004/07/09 23:14:17 stuvi 00440 # Added "operatorobj" preference that contains the rcUser object and left the "operator" preference to contain the user name. 00441 # 00442 # Revision 1.27 2004/05/03 22:49:36 stuvi 00443 # Added commented out code example that demonstrates how to access the CAL and TKR diagnostics contributions. 00444 # 00445 # Revision 1.26 2004/05/03 21:19:47 stuvi 00446 # Moved non-Runcontrol scripts to the support directory and modified imports accordingly. 00447 # 00448 # Revision 1.25 2004/04/21 21:05:29 stuvi 00449 # Added an example of how to pass the preferences using the setPrefs method when running in standalone mode. 00450 # 00451 # Revision 1.24 2004/04/17 02:23:48 stuvi 00452 # Added teardown() to delete the C++ object for the userArgument 00453 # Fixed LogData parsing based on the evtCli changes 00454 # 00455 # Revision 1.23 2004/03/31 01:01:19 stuvi 00456 # Added commented code on how to parse the error contribution. 00457 # 00458 # Revision 1.22 2004/03/10 22:24:51 panetta 00459 # Upgraded trigger interface. 00460 # Removed dependencies on self.glt. 00461 # 00462 # Revision 1.21 2004/03/04 23:08:47 stuvi 00463 # Removed glt.destination assignment 00464 # 00465 # Revision 1.20 2004/02/20 03:20:23 stuvi 00466 # Added handling of the sweep events and error checking to the process() method, 00467 # 00468 # Revision 1.19 2004/02/13 03:13:25 stuvi 00469 # Sweep events are also sent to user script's process event now, so added code to handle the case. 00470 # 00471 # Revision 1.18 2004/02/02 23:14:00 stuvi 00472 # Changes required to make the scripts work with the new FSM engine. 00473 # 00474 # Revision 1.17 2004/01/30 04:33:44 claus 00475 # Updated for transitions not running in the GUI thread. 00476 # New commandSynch handling. 00477 # 00478 # Revision 1.16 2003/12/19 02:05:26 stuvi 00479 # Added support for creating and updating GUIs from a suite 00480 # 00481 # Revision 1.15 2003/12/11 02:22:35 stuvi 00482 # Suite and standalone mode modifications 00483 # 00484 # Revision 1.14 2003/12/11 01:53:16 stuvi 00485 # Modified code to support suites. 00486 # 00487 # Revision 1.13 2003/11/25 02:16:12 stuvi 00488 # Modified according to the current test setup to generate some results 00489 # 00490 # Revision 1.12 2003/11/04 04:25:11 stuvi 00491 # Changed the commandSynch logic so that the enableMask() call would not pose a threat to snapshot taking. 00492 # 00493 # Revision 1.11 2003/10/31 01:09:37 panetta 00494 # 1) Moved register writes from startRun to setup 00495 # 2) Added GLT enabling logic to __commandSynch 00496 # 3) Gave example of getting the start/stop time from the hardware/event stream 00497 # 00498 # Revision 1.10 2003/10/28 03:17:34 stuvi 00499 # Added support for calculating the event rate correctly using the new GLT behaviour. 00500 # 00501 # Revision 1.9 2003/08/21 21:13:38 stuvi 00502 # no message 00503 # 00504 # Revision 1.8 2003/07/17 00:01:35 stuvi 00505 # no message 00506 # 00507 # Revision 1.7 2003/06/13 23:26:24 stuvi 00508 # Added TEM reset 00509 # 00510 # Revision 1.6 2003/04/12 02:38:34 stuvi 00511 # Added Cancel button handler to argument class 00512 # 00513 # Revision 1.5 2003/04/09 00:45:15 stuvi 00514 # Commented out references to DATA_MASKS register which should not be touched during script execution. 00515 # 00516 # Revision 1.4 2003/04/01 21:04:59 stuvi 00517 # Fixed event count discrepancy when the run is stopped in the middle. 00518 # 00519 # Revision 1.3 2003/03/31 19:23:44 stuvi 00520 # Fixed name 00521 # 00522 # Revision 1.2 2003/03/26 21:59:36 stuvi 00523 # Fixed standalone mode 00524 # 00525 # Revision 1.1 2003/03/11 21:20:55 stuvi 00526 # Moved from RunControl directory 00527 # 00528 # Revision 1.8 2003/02/06 05:19:38 claus 00529 # Added resume; StopRun bug fix 00530 # 00531 # Revision 1.7 2003/02/06 04:14:35 claus 00532 # Fixed StopRun bug 00533 # 00534 # Revision 1.6 2002/12/11 21:18:07 stuvi 00535 # Changed glt register assignments to bit field assignments 00536 # 00537 # Revision 1.5 2002/12/10 01:09:58 claus 00538 # Added path and changed schema/config file for stand-alone mode 00539 # 00540 # Revision 1.4 2002/12/04 01:59:23 claus 00541 # Added message logging 00542 # 00543 # Revision 1.3 2002/12/02 17:17:09 claus 00544 # Added provision to allow application to run stand-alone 00545 # 00546 # Revision 1.2 2002/11/28 02:02:04 claus 00547 # Shuffled constructor arguments 00548 # 00549 # Revision 1.1 2002/11/27 05:02:48 claus 00550 # Initial version of Run Control 00551 #