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__ = "GLAST LAT data export routines" 00012 __author__ = "J. Panetta <panetta@slac.stanford.edu> SLAC - GLAST LAT I&T/Online" 00013 __date__ = ("$Date: 2004/11/08 21:03:12 $").split(' ')[1] 00014 __version__ = "$Revision: 2.2 $" 00015 __release__ = "$Name: R04-12-00 $" 00016 __credits__ = "SLAC" 00017 00018 import LATTE.copyright_SLAC 00019 00020 import time 00021 from Numeric import array, zeros 00022 00023 from LATTE.tools.taskEngine import TaskEngine 00024 from LATTE.database.gLAT import * 00025 from LATTE.trigger.TrgObject import TrgObject 00026 from thread import allocate_lock 00027 00028 class AcdHWMultiplexer(object): 00029 """\brief AcdHWMultiplexer class 00030 00031 A class to multiplex the two ACD hardware scalers defined in 00032 section 2.6.2 of the GEM document, LAT-TD-01545 into up to 108 00033 separate counters. 00034 00035 """ 00036 __DEFAULT_DWELL_TIME = 1 # Default to 1 second 00037 00038 def __init__(self, GEM): 00039 """\brief AcdHWMultiplexer constructor 00040 00041 \param GEM a GEM object 00042 """ 00043 self.__gemst = GEM.downGEMST() 00044 self.__gemie = GEM.downGEMIE() 00045 00046 self.__dwell = None 00047 self.__tList = None 00048 self.__stats = None 00049 00050 self.__accumEngine = TaskEngine("AcdHWMultiplexer") 00051 self.__accumEngine.start() 00052 00053 self.__statsLock = allocate_lock() 00054 00055 self.__setupDone = False 00056 self.__stopAccum = False 00057 self.__abortAccum = False 00058 00059 self.__sortIEregs() 00060 00061 def start(self): 00062 """\brief Method for starting the accumulation of ACD hardware scalers 00063 00064 Start the integration of the hardware counters. 00065 At the start of integration, the counters are all reset to zero (0). 00066 """ 00067 # invalidate setup to reset stats, etc. 00068 self.__setupDone = False 00069 # spawn the accumulate engine 00070 self.__accumEngine.spawn(self.__accumulate) 00071 00072 def stop(self): 00073 """\brief Method for stopping the accumulation of ACD hardware scalers 00074 00075 Stop the integration of the hardware counters. 00076 The stop occurs at the end of the current cycle, and 00077 the counts from the current cycle are integrated into the count 00078 statistics 00079 """ 00080 self.__stopAccum = True 00081 00082 def resume(self): 00083 """\brief Method for resuming the accumulation of ACD hardware scalers after a stop 00084 00085 Resume the integration of the hardware counters after a stop() 00086 call. At resume of integration, the internal counters are not reset, but 00087 continue from their previous values. 00088 """ 00089 # spawn the accumulate engine 00090 self.__stopAccum = False 00091 self.__accumEngine.spawn(self.__accumulate) 00092 00093 def abort(self): 00094 """\brief Method for aborting the accumulation of ACD hardware scalers 00095 00096 Abort the integration of the hardware counters. The cycle 00097 stops immediately, and the set of counts from the current cycle 00098 is discarded. 00099 """ 00100 self.__abortAccum = True 00101 00102 def shutdown(self): 00103 """\brief Method for shutting down the Multiplexer. 00104 00105 Shut down the thread the multiplexer is running in. Should be 00106 called during endRun. 00107 """ 00108 self.__accumEngine.shutdown() 00109 00110 def dwell(self, d=None): 00111 """\brief Method to set the dwell time for scaler integration 00112 00113 Set the dwell time (in seconds) for integration. 00114 Total time in a cycle through the scalers will be dwell * nTiles. 00115 Minimum dwell time is 0.1 seconds. Default is 1 second. 00116 \param dwell Dwell time in seconds, default = 1 second 00117 """ 00118 if d is not None: 00119 if d < 0.1: 00120 d = 0.1 00121 self.__dwell = d 00122 self.__setupDone = False # invalidate setup, need to recompute stuff 00123 return self.__dwell 00124 00125 def tileList(self, tList=None): 00126 """\brief Method to set which tiles are integrated 00127 00128 Defines the list of tiles which are being integrated. 00129 Ex: range(108); [0,2,4,6] 00130 00131 \param tList The list of tiles to be integrated. 00132 \return The list of tiles that are being integrated 00133 """ 00134 if tList is not None: 00135 self.__tList = tList 00136 self.__setupDone = False # invalidate setup, need to recompute stuff 00137 return self.__tList 00138 00139 def stats(self): 00140 """\brief Method to access the counter statistics 00141 00142 Provides the user with the a list containing the counter statistics. 00143 This list corresponds to the tiles in tileList. 00144 00145 \return The list of the tile statistics. 00146 """ 00147 # Prevent multithread access to self.__stats with a lock 00148 self.__statsLock.acquire() 00149 s = self.__stats.tolist() 00150 self.__statsLock.release() 00151 return s 00152 00153 00154 # private: 00155 def __setup(self): 00156 """Set up the system 00157 """ 00158 # Make sure we're able to run. 00159 self.__stopAccum = False 00160 self.__abortAccum = False 00161 self.__setupDone = True 00162 00163 # error checking 00164 if self.__tList is None: 00165 msg = "No list of tiles defined for the multiplexer." 00166 raise Exception, msg 00167 00168 # No dwell time specified? 00169 if self.__dwell is None: 00170 self.__dwell = AcdHWMultiplexer.__DEFAULT_DWELL_TIME 00171 00172 # Check integrity of tile list 00173 for tile in self.__tList: 00174 if tile < TrgObject.TILE_NUMBER_MIN or \ 00175 tile > TrgObject.TILE_NUMBER_MAX: 00176 msg = "Tile number %d is out of range [%d, %d]" % \ 00177 ( tile, TrgObject.TILE_NUMBER_MIN, TrgObject.TILE_NUMBER_MAX ) 00178 raise IndexError, msg 00179 00180 # set up internal array structure 00181 self.__tListInt = array( self.__tList ) 00182 00183 # create our internal and external stats arrays 00184 self.__statsInt = zeros( self.__tListInt.shape ) 00185 self.__stats = zeros( self.__tListInt.shape ) 00186 00187 def __accumulate(self): 00188 """ This is where the work is really done. 00189 """ 00190 if not self.__setupDone: 00191 self.__setup() 00192 00193 sweepSize = len(self.__tListInt) 00194 00195 while ( not self.__stopAccum ): 00196 for tileSet in range(0,sweepSize,2): 00197 # Check for abort here 00198 if self.__abortAccum: 00199 print "abort" 00200 return 00201 00202 tile_0 = self.__tListInt[tileSet] 00203 if tileSet+1 < sweepSize: 00204 tile_1 = self.__tListInt[tileSet+1] 00205 else: 00206 tile_1 = None 00207 00208 # cache input enables 00209 regList = self.__gemie.regs.values() 00210 self.__regCache = zeros( (len(regList)) ) 00211 for reg in regList: 00212 if reg.size() > 0: 00213 self.__regCache[reg.id()] = reg.get() 00214 00215 # set up counters 00216 self.__gemst.TILE_0 = tile_0 00217 if tile_1 is not None: 00218 self.__gemst.TILE_1 = tile_1 00219 00220 # enable the proper tiles 00221 self.__setIE(tile_0) 00222 if tile_1 is not None: 00223 self.__setIE(tile_1) 00224 00225 self.__gemst.TILE_COUNTERS = 0 00226 # Accumulate 00227 time.sleep(self.__dwell) 00228 count = self.__gemst.TILE_COUNTERS 00229 00230 # reset the input enables 00231 self.__resetIE(tile_0) 00232 if tile_1 is not None: 00233 self.__resetIE(tile_1) 00234 00235 # pull counters 00236 self.__statsInt[tileSet] = ( count >> 0 ) & 0xffff 00237 if tile_1 is not None: 00238 self.__statsInt[tileSet+1] = ( count >> 16 ) & 0xffff 00239 00240 # Send internal stats into external stats 00241 # Prevent multithread access to self.__stats with a lock 00242 self.__statsLock.acquire() 00243 self.__stats += self.__statsInt 00244 self.__statsLock.release() 00245 print "stopped" 00246 00247 def __setIE(self,tile): 00248 # set the corresponding bits in the IE on for a tile 00249 00250 reg,bit = divmod(tile,9) 00251 value = ( 1 << bit ) + ( 1 << bit+9 ) # two nine bit fields 00252 self.__gemieDict[reg+5].set( self.__gemieDict[reg+5].get() | value ) # tile enables start at 5 00253 00254 def __resetIE(self,tile): 00255 # reset the changed input enables to their cached values 00256 reg,bit = divmod(tile,9) 00257 self.__gemieDict[reg+5].set( self.__regCache[reg+5] ) 00258 00259 def __sortIEregs(self): 00260 # create a lookup table based on register number 00261 regList = self.__gemie.regs.values() 00262 self.__gemieDict = {} 00263 for reg in regList: 00264 if reg.size() > 0: 00265 self.__gemieDict[reg.id()] = reg 00266