00001 #!/usr/local/bin/python 00002 # 00003 # Copyright 2003 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 distribution polling class" 00012 __author__ = "R. Claus <Claus@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online" 00013 __date__ = ("$Date: 2005/06/28 17:38:56 $").split(' ')[1] 00014 __version__ = "$Revision: 2.3 $" 00015 __release__ = "$Name: R04-12-00 $" 00016 __credits__ = "SLAC" 00017 00018 import LATTE.copyright_SLAC 00019 00020 00021 import DataDistributor as DD 00022 import threading 00023 import copy 00024 import time 00025 00026 00027 class DataDistributorPoll(DD.DataDistributorClient): 00028 """\brief Data distributor client that polls for samples of data. 00029 00030 Use of this class involves the starting of a thread that constantly receives 00031 the data arriving in the base class's socket. Keeping the socket drained of 00032 data allows the user of this class to get the most recent data received, thus 00033 avoiding getting data with a bursty time structure. Whenever the application 00034 calls the receive() method, it gets the most recent data sample. Because of 00035 the reference counting method used by Python objects, no copy of the data 00036 needs to be made to avoid the data changing from underneath the application. 00037 The application can hold onto the data reference as long as it likes. 00038 Whenever new data appears a new reference is created, and is possibly deleted 00039 before the application gets access to it, leaving any existing reference 00040 alone. When the application tries to get access to the latest data, it gets 00041 a copy of the most recent reference, and the previous reference is deleted, 00042 if it has gone out of scope. 00043 """ 00044 def __init__(self, name, length = 64*1024): 00045 """DataDistributorPoll constructor. 00046 00047 \param name The name of the type of data that the client wants to receive. 00048 See the DataDistributorAddress class. 00049 \param length The size in bytes of the buffer to allocate for receiving the 00050 data. Defaults to 64 KB. 00051 """ 00052 DD.DataDistributorClient.__init__(self, name, length) 00053 self.__pollTaskQuit = False 00054 self.__pollTask = None 00055 self.__data = None 00056 self.__dataCopy = None 00057 self.__sender = None 00058 00059 def start(self): 00060 """Start the polling thread.""" 00061 self.__pollTask = threading.Thread(None, self.__poll, 'DataDistributorPoll') 00062 if self.__pollTask is not None: 00063 self.__pollTask.start() 00064 00065 def stop(self): 00066 """Stop the polling thread.""" 00067 self.returnNone() # Force the base class receiver loop to break out 00068 self.__pollTaskQuit = True 00069 self.__pollTask.join() 00070 00071 def __poll(self): 00072 """Internal routine to drain the data distributor client socket.""" 00073 while not self.__pollTaskQuit: 00074 self.__data, self.__sender = DD.DataDistributorClient.receive(self) 00075 time.sleep(.001) # Let another thread have some CPU time 00076 00077 def receive(self): 00078 """Receive a sampled value of the data and sender information. 00079 00080 \return A list of the sampled data and sender's identification string. 00081 If the data buffer has not been refreshed since the last call, 00082 return None, None. 00083 """ 00084 # Avoid returning the same data more than once by keeping a reference to 00085 # the last-returned data. When there is a new data buffer the references 00086 # won't match. 00087 if self.__data is not self.__dataCopy: 00088 self.__dataCopy = self.__data 00089 return self.__dataCopy, self.__sender 00090 else: 00091 return None, None