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 00011 __facility__ = "Online" 00012 __abstract__ = "OCS node" 00013 __author__ = "Amedeo Perazzo <perazzo@slac.stanford.edu> SLAC - GLAST I&T/Online" 00014 __date__ = ("$Date: 2005/06/23 23:54:48 $").split(' ')[1] 00015 __version__ = "$Revision: 2.29 $" 00016 __release__ = "$Name: R04-12-00 $" 00017 __credits__ = "SLAC" 00018 00019 import LATTE.copyright_SLAC 00020 00021 import logging 00022 import time 00023 import math 00024 import struct 00025 import gDb 00026 import gAttr 00027 00028 import LATTE.client.gException as gException 00029 00030 class GOCS(gDb.Gdb): 00031 """\brief OCS node. 00032 00033 Has OCS specific registers and methods. 00034 00035 Valid Registers: 00036 - \c stats_failed_events 00037 - \c stats_failed_event_sends 00038 - \c stats_valid_events 00039 - \c stats_discarded_event_sends 00040 - \c stats_length_mismatch_count 00041 - \c stats_events_not_sent 00042 - \c stats_filter_pkt_errors 00043 - \c stats_filter_src_errors 00044 - \c stats_filter_passes 00045 - \c stats_filter_fails 00046 - \c stats_handled_events 00047 00048 Event statistics: 00049 00050 The following statistics registers are initialized 00051 at the start of each RunControl run: 00052 00053 - \c stats_failed_events -- Counts events where 00054 the eventHandler receives a bad status for the event. 00055 00056 - \c stats_failed_event_sends -- Counts events where 00057 the socket send failed with an error other than 00058 EWOULDBLOCK. 00059 00060 - \c stats_valid_events -- Counts when a valid event 00061 has been successfully sent to the client. 00062 00063 - \c stats_discarded_event_sends -- Counts cases when an 00064 event send failed due to the fact that the send 00065 returned an EWOULDBLOCK error. 00066 00067 - \c stats_length_mismatch_count -- Counts cases when 00068 the length argument passed to the event handler did 00069 not match the length provided in the event header. 00070 00071 - \c stats_events_not_sent -- Counts when an event is 00072 not sent over the socket due a filter or a scaler. 00073 00074 - \c stats_filter_pkt_errors -- Counts when the filtered 00075 event has a packet error in its contribution. 00076 00077 - \c stats_filter_src_errors -- Counts when the filtered 00078 event has a source error in its contribution. 00079 00080 - \c stats_filter_passes -- Counts when the event goes through the filter. 00081 00082 - \c stats_filter_fails -- Counts when the event fails the filter. 00083 00084 - \c stats_handled_events -- Counts when the event is received by the SBC event handler. 00085 00086 """ 00087 ProtocolVersion = 2 00088 ProtocolRevision = 1 00089 00090 __attrs = [ 00091 # Registers; IDs kept for backward compatibility with GLAT 00092 gAttr.GattrReg('stats_failed_events', 8, 4), 00093 gAttr.GattrReg('stats_failed_event_sends', 9, 4), 00094 gAttr.GattrReg('stats_valid_events', 10, 4), 00095 gAttr.GattrReg('stats_discarded_event_sends', 11, 4), 00096 gAttr.GattrReg('stats_length_mismatch_count', 12, 4), 00097 gAttr.GattrReg('stats_events_not_sent', 13, 4), 00098 gAttr.GattrReg('stats_filter_pkt_errors', 14, 4), 00099 gAttr.GattrReg('stats_filter_src_errors', 15, 4), 00100 gAttr.GattrReg('stats_filter_passes', 16, 4), 00101 gAttr.GattrReg('stats_filter_fails', 17, 4), 00102 gAttr.GattrReg('stats_handled_events', 18, 4), 00103 ] 00104 00105 def __init__(self, client): 00106 self.__cbDict = {} # dictionary of callback parameters 00107 gDb.Gdb.__init__(self, client, None, 0, self.__attrs) 00108 00109 def read(self, reg): 00110 return self.cmdrsp('ggLATread', reg, '!I') 00111 00112 def load(self, reg, value): 00113 return self.cmdrsp('ggLATload', reg, value) 00114 00115 def evtHandlerSendAll(self): 00116 """\brief Sets the current event mode to send all events to the client. 00117 """ 00118 name = 'evtHandlerSendAll' 00119 self.__cbDict.clear() 00120 self.__cbDict['name'] = name 00121 response = self.cmdrsp(name) 00122 return response.status() 00123 00124 def evtHandlerSendNothing(self): 00125 """\brief Sets the current event mode to send no data events to the client. 00126 """ 00127 name = 'evtHandlerSendNothing' 00128 self.__cbDict.clear() 00129 self.__cbDict['name'] = name 00130 response = self.cmdrsp(name) 00131 return response.status() 00132 00133 def evtHandlerSendErrorsOnly(self): 00134 """\brief Sets the current event mode to send only error events to the client. 00135 """ 00136 name = 'evtHandlerSendErrorsOnly' 00137 self.__cbDict.clear() 00138 self.__cbDict['name'] = name 00139 response = self.cmdrsp(name) 00140 return response.status() 00141 00142 def evtHandlerSendAcdScalers(self, marker, prescale=0): 00143 """\brief Sets the current event mode to send only events containing the 00144 ACD software scalers to the client upon recept of the given marker. All 00145 marker zero events are accumulated by the scaler code. If an event is 00146 triggered with the specified marker, the scaler data will be delivered with 00147 that event. Thus, if the specified marker is zero, then all data events 00148 will be accompanied by the scaler data. In addition, marker zero events can 00149 be prescaled before delivery to the client. A \a prescale value of zero 00150 (the default) delivers every marker zero event. A \a prescale value of 00151 0xffffffffL disables prescaling and delivers no events. 00152 00153 \param marker - Marker to value to use 00154 \param prescale - Prescale value to use 00155 """ 00156 name = 'evtHandlerSendAcdScalers' 00157 self.__cbDict.clear() 00158 self.__cbDict['name'] = name 00159 self.__cbDict['marker'] = marker 00160 self.__cbDict['prescale'] = prescale 00161 response = self.cmdrsp(name, marker, prescale) 00162 return response.status() 00163 00164 def evtHandlerSendPrescaled(self, prescale): 00165 """\brief Sets the current event mode to send prescaled events to the client. 00166 A \a prescale value of zero delivers every event. A \a prescale value of 00167 0xffffffffL disables prescaling and delivers no events. 00168 00169 \param prescale - Prescale value to use 00170 """ 00171 name = 'evtHandlerSendPrescaled' 00172 self.__cbDict.clear() 00173 self.__cbDict['name'] = name 00174 self.__cbDict['prescale'] = prescale 00175 response = self.cmdrsp(name, prescale) 00176 return response.status() 00177 00178 def evtHandlerPrescaleExternal(self, prescale): 00179 """\brief Sets the current event mode to prescale externally triggered events. 00180 Only events with only the external trigger firing will be prescaled. 00181 A \a prescale value of zero delivers every event. A \a prescale value of 00182 0xffffffffL disables prescaling and delivers no events. 00183 \param prescale - Prescale value to use 00184 """ 00185 name = 'evtHandlerPrescaleExternal' 00186 self.__cbDict.clear() 00187 self.__cbDict['name'] = name 00188 self.__cbDict['prescale'] = prescale 00189 response = self.cmdrsp(name, prescale) 00190 return response.status() 00191 00192 def evtHandlerFilterTkrHits(self, lowThreshold = 0, towerMask = 0xffff, highThreshold = 0xffffffffL, prescale = 0xffffffffL): 00193 """\brief Sets the current event mode to the Tracker Hit Filter 00194 00195 The Tracker Hit Filter filters events based on the number of hits in the 00196 tracker. Only events with no errors will be filtered. 00197 00198 The filter algorithm sums up the number of hits found in the tracker 00199 contributions of the towers given in the \a towerMask and requires this 00200 total number of hits to be greater than or equal to the \a lowThreshold 00201 value and less than or equal to the \a highThreshold value in order to 00202 send the event downstream. The default threshold values allow all events 00203 to pass the filter, i.e., the default low threshold is zero, and the default 00204 high threshold is larger than the full LAT can generate. 00205 00206 The \a towerMask value is constructed by setting the bit at the position 00207 corresponding to the tower address of the tower to be included. Bit zero 00208 is the least significant, right-most bit and corresponds to the tower with 00209 LATp address zero. By default, all 16 towers are included in the filter 00210 calculation. 00211 00212 A \a prescale can be applied to allow a fraction of the events that don't 00213 pass the TKR hit filter through. If the \a prescale value is zero, the TKR 00214 hit filter is ignored. If the \a prescale value is 0xffffffffL (the 00215 default), prescaling is disabled and filtering is determined by the TKR hit 00216 filter. If prescaling is enabled, every event is considered for prescaling, 00217 not just the events that fail the TKR hit filter. 00218 00219 \param lowThreshold - Minimum number of TKR hits needed to pass the event downstream 00220 \param towerMask - Mask of the towers participating in the filter 00221 \param highThreshold - Maximum number of TKR hits allowed to pass the event downstream 00222 \param prescale - Prescale value to use 00223 """ 00224 name = 'evtHandlerFilterTkrHits' 00225 self.__cbDict.clear() 00226 self.__cbDict['name'] = name 00227 self.__cbDict['lowThreshold'] = lowThreshold 00228 self.__cbDict['towerMask'] = towerMask 00229 self.__cbDict['highThreshold'] = highThreshold 00230 self.__cbDict['prescale'] = prescale 00231 response = self.cmdrsp(name, lowThreshold, towerMask, highThreshold, prescale) 00232 return response.status() 00233 00234 def evtHandlerSetVerbosity(self, verbosity): 00235 """\brief Sets the event server verbosity. 00236 00237 \param verbosity - Verbosity value to use 00238 """ 00239 response = self.cmdrsp('evtHandlerSetVerbosity', verbosity) 00240 return response.status() 00241 00242 def evtClearEvtSeqMSW(self): 00243 """\brief Clears the event sequence counter. 00244 00245 """ 00246 response = self.cmdrsp('evtClearEvtSeqMSW') 00247 return response.status() 00248 00249 def synchronize(self): 00250 """\brief Synchronize the SBC's clock with the host's clock. 00251 """ 00252 (fraction, integer) = math.modf(time.time()) 00253 seconds = int(integer) 00254 nanoseconds = int(fraction*1000000000) 00255 return self.cmdrsp('ocsSetTime', seconds, nanoseconds) 00256 00257 def getCallbackParams(self): 00258 """\brief Return a dictionary of the parameters used in the active OES callback 00259 """ 00260 return self.__cbDict 00261 00262 def getVersion(self): 00263 """\brief Get the protocol versions of code running on the SBC. 00264 """ 00265 response = self.cmdrsp('ocsVersion', '!H', '!H') 00266 return (response.payloads()[0], response.payloads()[1]) 00267 00268 def getStartupScriptInfo(self): 00269 """\brief Retrieve CVS $Id: gOCS.py,v 2.29 2005/06/23 23:54:48 perazzo Exp $ info for the startup script. 00270 00271 \return A list of CVS related info in the form: [filename, version, date, time, user] 00272 """ 00273 format = '!128s' 00274 size = struct.calcsize(format) 00275 strng = self.cmdrsp('ocsstrncpy', format, "startupScriptInfo", size).payloads() 00276 value = ''.join(strng).rstrip('\x00') 00277 sValue = value.split(" ") 00278 if len(sValue) != 8: 00279 logging.error("*** Unable to retrieve startup script info") 00280 return None 00281 else: 00282 return [sValue[1].split(',')[0]] + sValue[2:6] 00283 00284 def verifyVersion(self): 00285 """\brief Verify that the protocol version of the code running on the SBC 00286 is one the host code is expected to support. 00287 """ 00288 (version, revision) = self.getVersion() 00289 if version != GOCS.ProtocolVersion or revision < GOCS.ProtocolRevision: 00290 logging.error("gOCS: server protocol version is %d.%d expected %d.%d" 00291 %(version, revision, 00292 GOCS.ProtocolVersion, GOCS.ProtocolRevision)) 00293 status = gException.LATInterfaceStatus.status('OCS_BDVER') 00294 raise gException.LATInterfaceException(status) 00295 00296 def cmxAsBuilt(self): 00297 asbuilt = {} 00298 format = '!32s' 00299 idptr = self.cmdrsp('CMX_asBuiltScan', 0).status() 00300 while idptr: 00301 version = self.__getVersion(idptr) 00302 time = self.__getTime(idptr) 00303 name = self.__getString(idptr, 'CMX_asBuiltGetConstit', format) 00304 package = self.__getString(idptr, 'CMX_asBuiltGetPackage', format) 00305 user = self.__getString(idptr, 'CMX_asBuiltGetUser', format) 00306 idptr = self.cmdrsp('CMX_asBuiltScan', idptr).status() 00307 asbuilt[name] = [package, version, user, time] 00308 return asbuilt 00309 00310 def __getString(self, constituent, function, format): 00311 size = struct.calcsize(format) 00312 ptr = self.cmdrsp(function, constituent).status() 00313 string = self.cmdrsp('strncpy', format, ptr, size).payloads() 00314 return ''.join(string).rstrip('\x00') 00315 00316 def __getVersion(self, constituent): 00317 response = self.cmdrsp('CMX_asBuiltGetVersion', 00318 constituent,'!c','!H','!H','!H') 00319 ver = str(response.payloads()[0]) 00320 if ver == 'U': 00321 return '<unknown>' 00322 elif ver == 'T': 00323 return '<test>' 00324 elif ver == 'D': 00325 return '<dev>' 00326 else: 00327 maj = str(response.payloads()[1]) 00328 min = str(response.payloads()[2]) 00329 rev = str(response.payloads()[3]) 00330 return ''.join(['V',maj,'-',min,'-',rev]) 00331 00332 def __getTime(self, constituent): 00333 GLATEPOCH = 0x3a4fc880 00334 buildtime = self.cmdrsp('CMX_asBuiltGetTime', constituent).status() 00335 return time.strftime('%Y-%02m-%02d %H:%02M:%02S', 00336 time.gmtime(buildtime+GLATEPOCH))