Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

testAppCal_dg.py

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 #

Generated on Fri Jul 21 13:26:33 2006 for LATTE R04-12-00 by doxygen 1.4.3