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__ = "Housekeeping handler client" 00013 __author__ = "Jim Panetta SLAC - GLAST I&T/Online" 00014 __date__ = ("$Date: 2005/01/26 23:35:26 $").split(' ')[1] 00015 __created__ = "2004/08/27" 00016 __version__ = "$Revision: 1.3 $" 00017 __release__ = "$Name: R04-12-00 $" 00018 __credits__ = "SLAC" 00019 00020 import LATTE.copyright_SLAC 00021 import logging as log 00022 import select 00023 import struct 00024 import threading 00025 import time 00026 00027 import LATTE.client.gCommand as gCommand 00028 import LATTE.client.gSocket as gSocket 00029 import LATTE.client.gException as gException 00030 00031 00032 CMD_RX_PORT = 8000 00033 CMD_TX_PORT = 8001 00034 TELEM_PORT = 8002 00035 00036 CMD_RX_SIZE = 62 00037 CMD_TX_SIZE = 62 00038 TELEM_SIZE = 842 00039 HSK_SIZE = 116 00040 00041 00042 class HskCli(object): 00043 """\brief Housekeeping client input/output class 00044 00045 This class instantiates and controls the sockets for the housekeeping process. 00046 """ 00047 def __init__(self, handler=None): 00048 self.__cmdRx = HskCmdRxSocket(handler) 00049 self.__cmdTx = HskCmdTxSocket(handler) 00050 self.__telem = HskTelemSocket(handler) 00051 self.readCmdRx = self.__cmdRx.read 00052 self.readCmdTx = self.__cmdTx.read 00053 self.readTelem = self.__telem.read 00054 00055 def connect(self, server): 00056 """\brief connect method 00057 00058 \param server the hostname where the housekeeping server process runs 00059 connect the housekeeping system to the housekeeping server 00060 """ 00061 self.__cmdRx.connect(server) 00062 self.__cmdTx.connect(server) 00063 self.__telem.connect(server) 00064 self.readCmdRx = self.__cmdRx.read 00065 self.readCmdTx = self.__cmdTx.read 00066 self.readTelem = self.__telem.read 00067 00068 def disconnect(self): 00069 """\brief disconnect method 00070 00071 disconnect the housekeeping system from housekeeping server 00072 """ 00073 self.__cmdRx.disconnect() 00074 self.__cmdTx.disconnect() 00075 self.__telem.disconnect() 00076 00077 def handler(self, newhandler): 00078 self.__cmdRx.handler(newhandler) 00079 self.__cmdTx.handler(newhandler) 00080 self.__telem.handler(newhandler) 00081 00082 class ccsdsSocket(gSocket.Socket): 00083 UNPACK_ERROR = -1001 00084 00085 def __init__(self, handler=None, debug=0, port=0): 00086 gSocket.Socket.__init__(self, port) 00087 self.__handler = handler 00088 00089 self.__timeout = 30 00090 self.__timeoutEnabled = False 00091 self.read = None 00092 00093 def connect(self, host): 00094 gSocket.Socket.connect(self, host) 00095 self.read = self.readCCSDS 00096 00097 def disconnect(self): 00098 gSocket.Socket.disconnect(self) 00099 self.read = None 00100 00101 def handler(self, newhandler): 00102 self.__handler = newhandler 00103 00104 def readCCSDS(self): 00105 """\brief CCSDS read routine. 00106 00107 This routine does the minimal work of reading the raw CCSDS 00108 data from a socket. 00109 00110 \return socket buffer read 00111 """ 00112 self.lock() 00113 try: 00114 # read CCSDS primary header... 00115 dat = self.recvall(6) 00116 h = struct.unpack('!HHH',dat) 00117 # CCSDS packet length encoding: 00118 # h[2] = 2ndary hdr (8) + payload (102) - 1 00119 # total bytes left = h[2] + 1 00120 numLeft = h[2] + 1 00121 dat += self.recvall(numLeft) 00122 self.release() 00123 except: 00124 self.release() 00125 if self.__handler is not None: 00126 self.__handler.timedout() 00127 status = gException.LATInterfaceStatus.status('OCS_TMO') 00128 raise gException.LATInterfaceException(status) 00129 00130 if len(dat) == 0: 00131 if self.__handler is not None: 00132 self.__handler.disconnected() 00133 status = gException.LATInterfaceStatus.status('OCS_NOSRV') 00134 raise gException.LATInterfaceException(status) 00135 00136 return (0, dat) 00137 00138 def setTimeoutEnabled(self, flag): 00139 """\brief Enable or disable event timeout 00140 00141 \param flag 1 = Enable event timeout 00142 0 = Disable event timeout (default) 00143 """ 00144 self.__timeoutEnabled = flag; 00145 00146 def isTimeoutEnabled(self): 00147 """\brief Checks the event timeout state 00148 00149 \return 1 = If event timeout is enabled 00150 0 = If event timeout is disabled 00151 """ 00152 return self.__timeoutEnabled 00153 00154 def setTimeout(self, timeout): 00155 """\brief Set the timeout value. 00156 00157 \param timeout Event timeout value as a floating point number in seconds. 00158 Default is 1 second. 00159 """ 00160 self.__timeout = timeout 00161 00162 def getTimeout(self): 00163 """\brief Query the current timeout value. 00164 00165 \return Current event timeout value as a floating point number in seconds 00166 """ 00167 return self.__timeout 00168 00169 class HskCmdRxSocket(ccsdsSocket): 00170 def __init__(self, handler=None, debug=0, port=CMD_RX_PORT): 00171 ccsdsSocket.__init__(self, handler, debug, port) 00172 00173 class HskCmdTxSocket(ccsdsSocket): 00174 def __init__(self, handler=None, debug=0, port=CMD_TX_PORT): 00175 ccsdsSocket.__init__(self, handler, debug, port) 00176 00177 class HskTelemSocket(ccsdsSocket): 00178 def __init__(self, handler=None, debug=0, port=TELEM_PORT): 00179 ccsdsSocket.__init__(self, handler, debug, port) 00180 00181 00182 class ConnectState: 00183 Disconnected = 0 00184 Waiting = 1 00185 Connected = 2 00186 00187 class HskHandler(object): 00188 """\brief HskHandler class 00189 00190 Defines connection protocol to hsk server. 00191 This class needs to define two calls: disconnected and timeout. 00192 00193 Inherit from this to create GUI versions of HskSvr 00194 """ 00195 def __init__(self, server, host): 00196 self.__server = server 00197 self.__host = host 00198 server.handler(self) 00199 self.__connection_state = ConnectState.Disconnected # disconnected at startup 00200 self.connect() 00201 00202 def connect(self): 00203 """\brief connect 00204 00205 Connect to the command/hsk server 00206 """ 00207 self.__connection_state = ConnectState.Waiting 00208 self.__tries = 0 00209 self.__connect() 00210 00211 def disconnected(self): 00212 """\brief disconnected 00213 00214 """ 00215 self.__disconnect() 00216 00217 def timedout(self): 00218 """\brief timedout 00219 """ 00220 self.__disconnect() 00221 00222 def __disconnect(self): 00223 # disconnect from the server 00224 self.__server.disconnect() 00225 # deal with the outcome of disconnecting 00226 self.__connection_notthere() 00227 00228 def __connect(self): 00229 # spawn the connecting thread in the background 00230 connecthdlr = threading.Thread(None, self.__connection_handler, 'ConnectHandler',()) 00231 connecthdlr.setDaemon(True) 00232 connecthdlr.start() 00233 00234 def __connection_handler(self): 00235 while (True): 00236 try: 00237 self.__server.connect(self.__host) 00238 log.info("HSK server is now connected") 00239 self.__connection_state = ConnectState.Connected 00240 self.__tries = 0 00241 break 00242 except RuntimeError, msg: 00243 if self.__tries == 0: 00244 log.error(msg) 00245 self.__tries += 1 00246 state = self.__connection_state 00247 if state == ConnectState.Disconnected: break 00248 time.sleep(3) 00249 00250 def __connection_notthere(self): 00251 # Do this once... 00252 if self.__connection_state == ConnectState.Connected: 00253 log.error("HSK server disconnected, trying to reconnect") 00254 self.__connection_state = ConnectState.Waiting 00255 self.__connect() 00256 00257