def test_emptyish_char_waveform_monitor(): '''a test of a char waveform of length 1 (NORD=1): value "\0" with using auto_monitor ''' with no_simulator_updates(): zerostr = PV(pvnames.char_arr_pv, auto_monitor=True) zerostr.wait_for_connection() zerostr.put([0], wait=True) time.sleep(0.2) assert zerostr.get(as_string=True) == '' numpy.testing.assert_array_equal(zerostr.get(as_string=False), [0]) assert zerostr.get(as_string=True, as_numpy=False) == '' numpy.testing.assert_array_equal( zerostr.get(as_string=False, as_numpy=False), [0]) zerostr.put([0, 0], wait=True) time.sleep(0.2) assert zerostr.get(as_string=True) == '' numpy.testing.assert_array_equal(zerostr.get(as_string=False), [0, 0]) assert zerostr.get(as_string=True, as_numpy=False) == '' numpy.testing.assert_array_equal( zerostr.get(as_string=False, as_numpy=False), [0, 0]) zerostr.disconnect()
def test_with_PV_and_getPV(): # create 2 PV objects connecting to the same PV signal, one using PV class and the other one using get_pv() pv1 = PV(mypv, auto_monitor=True, callback=lambda **args:...) pv2 = get_pv(mypv) pv1.wait_for_connection() pv2.wait_for_connection() # check that both PVs are connected assert pv1.connected is True assert pv2.connected is True # check that data is received assert pv1.get() is not None assert pv2.get() is not None # disconnect 1 PV pv1.disconnect() time.sleep(1) # check that the first PV is disconnected and doesn't receive data assert pv1.connected is False assert pv1.get() is None # check that the other PV is connected and still receives data assert pv2.connected is True assert pv2.get() is not None
def test_emptyish_char_waveform_no_monitor(self): '''a test of a char waveform of length 1 (NORD=1): value "\0" without using auto_monitor ''' with no_simulator_updates(): zerostr = PV(pvnames.char_arr_pv, auto_monitor=False) zerostr.wait_for_connection() # elem_count = 128, requested count = None, libca returns count = 1 zerostr.put([0], wait=True) self.assertEquals(zerostr.get(as_string=True), '') numpy.testing.assert_array_equal(zerostr.get(as_string=False), [0]) self.assertEquals(zerostr.get(as_string=True, as_numpy=False), '') numpy.testing.assert_array_equal( zerostr.get(as_string=False, as_numpy=False), [0]) # elem_count = 128, requested count = None, libca returns count = 2 zerostr.put([0, 0], wait=True) self.assertEquals(zerostr.get(as_string=True), '') numpy.testing.assert_array_equal(zerostr.get(as_string=False), [0, 0]) self.assertEquals(zerostr.get(as_string=True, as_numpy=False), '') numpy.testing.assert_array_equal( zerostr.get(as_string=False, as_numpy=False), [0, 0]) zerostr.disconnect()
def test_force_connect(): pv = PV(pvnames.double_arrays[0], auto_monitor=True) print("Connecting") assert pv.wait_for_connection(5.0) print("SUM", pv.get().sum()) time.sleep(3) print("Disconnecting") pv.disconnect() print("Reconnecting") pv.force_connect() assert pv.wait_for_connection(5.0) called = {'called': False} def callback(value=None, **kwargs): called['called'] = True print("update", value.sum()) pv.add_callback(callback) time.sleep(1) assert pv.get() is not None assert called['called']
def test_memleak_disconnect(): # try to connect multiple times to the same PV mem = [] for i in range(int(2)): for j in range(int(1000)): pv = PV(mypv, auto_monitor=True, callback=lambda **args:...) pv.disconnect() process = psutil.Process(os.getpid()) mem.append(process.memory_info().rss) # check used memory by the process didn't increase by more than 1% assert mem[1] / mem[0] < 1.01
def post(self, message): stationStr = self._BL msg = message date_formatted = datetime.datetime.strftime(datetime.datetime.now(), "%a %d-%b-%Y %H:%M:%S") mscroll = PV("SF-OP:" + str(stationStr) + "-MSG:OP-MSCROLL.PROC") mscroll.value = 1 msg1 = PV("SF-OP:" + str(stationStr) + "-MSG:OP-MSG1") msg1.value = msg.encode() date1 = PV("SF-OP:" + str(stationStr) + "-MSG:OP-DATE1") date1.value = date_formatted.encode() msg1.disconnect() date1.disconnect()
def test_reconnect(): # connect and disconnect pv = PV(mypv, auto_monitor=True, callback=lambda **args:...) pv.wait_for_connection() pv.disconnect() # try to reconnect to the same PV connected = pv.reconnect() # check that PV is connected assert connected is True # check that data is received value = pv.get() assert value is not None
def release(self): if (self.app == None): return False release_pv = PV('{}:THR_LOADED'.format(self.app.get_pv_name())) if (self.verbose): sys.stdout.write('Releasing IOC (setting {})...'.format( release_pv.pvname)) # do release if (release_pv.host == None): print('ERROR: Failed to read release PV {}'.format( release_pv.pvname)) return False try: release_pv.put(1) except epics.ca.CASeverityException: print('ERROR: Tried to write to a read-only PV ({}=1)'.\ format(release_pv.pvname)) return False release_pv.disconnect() enable_pv = PV('{}:MPS_EN'.format(self.app.get_pv_name())) if (self.verbose): sys.stdout.write('Releasing IOC (setting {})...'.format( enable_pv.pvname)) # do release if (enable_pv.host == None): print('ERROR: Failed to read release PV {}'.format( enable_pv.pvname)) return False try: enable_pv.put(1) except epics.ca.CASeverityException: print('ERROR: Tried to write to a read-only PV ({}=1)'.\ format(enable_pv.pvname)) return False enable_pv.disconnect() if (self.verbose): print(' done.')
def test_with_caget_nomonitor(): pv = PV(mypv, auto_monitor=True, callback=lambda **args:...) pv.wait_for_connection() # check that the PV is connected and data is received assert pv.connected is True assert pv.get() is not None # use caget to get data from the same PV assert caget(mypv, use_monitor=False) is not None # disconnect PV object pv.disconnect() # check that the PV is disconnected and doesn't receive data assert pv.connected is False assert pv.get() is None # check that you can still use caget to get data from the same PV assert caget(mypv, use_monitor=False) is not None
def test_connect_disconnect(): pv = PV(mypv, auto_monitor=True, callback=lambda **args:...) pv.wait_for_connection() # check that PV is connected assert pv.connected is True # check that data is received value = pv.get() assert value is not None pv.disconnect() # check that PV is disconnected assert pv.connected is False # check that no data is received after disconnect value = pv.get() assert value is None
def test_with_camonitor(): pv = PV(mypv, auto_monitor=True, callback=lambda **args:...) pv.wait_for_connection() # check that the PV is connected and data is received assert pv.connected is True assert pv.get() is not None # use camonitor received = {'flag': False} def callback(**args): received['flag'] = True camonitor(mypv, callback=callback) time.sleep(1) # check that the monitor receives data assert received['flag'] is True # disconnect PV object pv.disconnect() time.sleep(1) # check that the PV is disconnected and doesn't receive data assert pv.connected is False assert pv.get() is None # reset the flag to check that new data is received by camonitor received['flag'] = False time.sleep(1) assert received['flag'] is True # clear the monitor camonitor_clear(mypv) time.sleep(1) # reset the flag to check that no new data is received by camonitor received['flag'] = False time.sleep(1) assert received['flag'] is False
class PCO2000(StandardDevice): TYPE_TIFF = "TIFF" TYPE_HDF = "HDF" #CALLBACK FUNCTION FOR THE CCD ACQUIRE STATUS PV def onAcquireChange(self, value, **kw): self._doneRecord = (value == 0) def onAcquireRBVChange(self, value, **kw): self._doneReadOut = (value == 0) def onDataChange(self, value, **kw): if(self.initCamera): self.initCamera = False return self.imageBufferQueue.put(value) self.NData = self.NData + 1 def onNELMChange(self, value, **kw): if(self.initNELM): self.initNELM = False return self.NCount = self.NCount + 1 #CONSTRUCTOR OF CCD CLASS def __init__(self, pvName, mnemonic, imageBufferQueue=None, processName=""): StandardDevice.__init__(self, mnemonic) self.processName = processName self.initCamera = True self.initNELM = True self.NCount = 0 self.NData = 0 self.imageBufferQueue = imageBufferQueue self.pvData = PV(pvName+":Data", auto_monitor=True) self.pvData.add_callback(self.onDataChange) self.pvAcquire = PV(pvName+":Acquire", callback=self.onAcquireChange, auto_monitor=True) self.pvAcquireRBV = PV(pvName+":Acquire_RBV", callback=self.onAcquireRBVChange, auto_monitor=True) self.pvNELM = PV(pvName+":Data.NELM", callback=self.onNELMChange) self._done = self.isDone() self.pvPixelSize = PV(pvName + ":PixelSize") self.pvCheckImage = PV(pvName + ":CheckImage") self.pvMinX = PV(pvName + ":MinX") self.pvMinY = PV(pvName + ":MinY") self.pvSizeX = PV(pvName + ":SizeX") self.pvSizeY = PV(pvName + ":SizeY") self.pvAcquireTime = PV(pvName+":AcquireTime") self.pvAcquireTimeBase = PV(pvName+":AcquireTimeBase") self.pvDelayTime = PV(pvName + ":DelayTime") self.pvDelayTimeBase = PV(pvName + ":DelayTimeBase") self.pvFileFormat = PV(pvName + ":FileFormat") self.pvFileName = PV(pvName + ":FileName") self.pvFileNumber = PV(pvName + ":FileNumber") self.pvFilePath = PV(pvName + ":FilePath") # #### PVS Bellow are used only for information display, no need to be here in the Python Class # #### If needed just uncomment and create the proper methods for GET and SET values. # self.pvADC = PV(pvName+":ADC") # self.pvAutoIncrement = PV(pvName+":AutoIncrement") # self.pvBinHorz = PV(pvName + ":BinHorz") # self.pvBinVert = PV(pvName + ":BinVert") # self.pvBoolTest = PV(pvName + ":BoolTest") # self.pvCamTemp = PV(pvName + ":CamTemp") # self.pvCCDTemp = PV(pvName + ":CCDTemp") # self.pvDoubleImage = PV(pvName + ":DoubleImage") # self.pvHotPixelCorrection = PV(pvName + ":HotPixelCorrection") # self.pvHotPixelX = PV(pvName + ":HotPixelX") # self.pvHotPixelY = PV(pvName + ":HotPixelY") # self.pvNoiseFiltering = PV(pvName + ":NoiseFiltering") # self.pvPixelRate = PV(pvName + ":PixelRate") # self.pvPixelSize = PV(pvName + ":PixelSize") # self.pvPowTemp = PV(pvName + ":PowTemp") # self.pvTimestamp = PV(pvName + ":Timestamp") # self.pvStatus = PV(pvName + ":Status") def getPixelSize(self): return self.pvPixelSize.get() def getCheckImage(self): return self.pvCheckImage.get() def setCheckImage(self, v): self.pvCheckImage.put(v) def getMinX(self): return self.pvMinX.get() def setMinX(self, v): self.pvMinX.put(v) def getMinY(self): return self.pvMinY.get() def setMinY(self, v): self.pvMinY.put(v) def getSizeX(self): return self.pvSizeX.get() def setSizeX(self, v): self.pvSizeX.put(v) def getSizeY(self): return self.pvSizeY.get() def setSizeY(self, v): self.pvSizeY.put(v) def getAcquireTime(self): return self.pvAcquireTime.get() def setAcquireTime(self, v): self.pvAcquireTime.put(v) def getAcquireTimeBase(self): return self.pvAcquireTimeBase.get() def setAcquireTimeBase(self, v): self.pvAcquireTimeBase.put(v) def getDelayTime(self): return self.pvDelayTime.get() def setDelayTime(self, v): self.pvDelayTime.put(v) def getDelayTimeBase(self): return self.pvDelayTimeBase.get() def setDelaytimeBase(self, v): self.pvDelayTimeBase.put(v) def getFileFormat(self): return self.pvFileFormat.get() def setFileFormat(self, v): if(v in [self.TYPE_HDF, self.TYPE_TIFF]): self.pvFileFormat.put(v) else: msg = 'File format "' + v + '" not supported. Only supported are: ' raise Exception('Error: ',msg) def getFileName(self): return self.pvFileName.get() def setFileName(self, v): self.pvFileName.put(v) def getFileNumber(self): return self.pvFileNumber.get() def setFuleNumber(self, v): self.pvFileNumber.put(v) def getFilePath(self): return self.pvFilePath.get() def setFilePath(self, v): self.pvFilePath.put(v) def getCompleteFilePath(self): if(self.getFileFormat() == self.TYPE_TIFF): ext = ".tif" elif(self.getFileFormat() == self.TYPE_HDF): ext = ".h5" else: ext = "" return self.getFilePath()+"/"+self.getFileName()+ext def getNELMChangeCount(self): return self.NCount def getData(self): self._newData = False return self.pvData.get() def isDone(self): return (self.pvAcquireRBV.get() == 0) def isRecordDone(self): return (self.pvAcquire.get() == 0) def isReadOutDone(self): return (self.pvAcquireRBV.get() == 0) def getIntensity(self): return self.scaler.getIntensity() def acquire(self, waitRecord=False, waitReadOut=False): #self.scaler.setCountTime(self.time) #self.scaler.setCountStart() self.pvAcquire.put(1) self._doneRecord = False self._doneReadOut = False self._newData = False if(waitRecord): self.waitRecord() if(waitReadOut): self.waitReadOut() #self.scaler.setCountStop() def waitConfig(self): self._doneConfig = False while(not self._doneConfig): sleep(0.001) def waitRecord(self): while(not self._doneRecord): sleep(0.001) def waitReadOut(self): while(not self._doneReadOut): sleep(0.001) def destroy(self): self.pvData.disconnect() self.pvAcquire.disconnect() self.pvAcquireRBV.disconnect() self.pvNELM.disconnect() self.imageBufferQueue = None
class Feed(object): """ This class reads frames in a real time using pyepics, and delivers to consuming process. """ def __init__(self, config, app): """ Constructor """ self.app = app self.eventq = tqueue.Queue() self.detector = config['detector'] with open(config['pvs']) as file: self.pvs = json.loads(file.read()) self.sizex = 0 self.sizey = 0 self.index = 0 self.current_counter = None def event(self, event_str): # we will find out later how to handle the events pass def deliver_data(self, data): # process data in the same thread as the callback self.app.process_data(data) def handle_event(self): """ This function receives data, processes it, and delivers to consuming process. This function is invoked at the beginning of the feed as a distinct thread. It reads data from a thread_dataq inside a loop that delivers current counter value on change. If the counter is not a consecutive number to the previous reading a 'missing' string is enqueued into process_dataq in place of the data to mark the missing frames. For every received frame data, it reads a data type from PV, and the two elements are delivered to a consuming process via process_dataq as Data instance. If a sequence is defined, then the data type for this frame determined from sequence is compared with the data type read from PV. If they are different, a warning log is recorded. On the loop exit an 'all_data' string is enqueud into the inter-process queue, and 'exit' string is enqueued into the inter-thread queue, to notify the main thread of the exit event. Parameters ---------- data_pv : str a PV string for the area detector data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger Returns ------- None """ self.done = False while not self.done: try: callback_item = self.eventq.get(timeout=1) if callback_item == 'finish': print('done') self.done = True else: current_ctr = callback_item if current_ctr > self.current_counter + 1: self.event('missing frames') self.current_counter = current_ctr + 1 try: print('current cntr', self.current_counter) pv_pairs = {} slice = np.array(caget(self.get_data_pv_name())) print('pvname', self.get_data_pv_name()) # read other pvs for pv in self.pvs: pv_pairs[pv] = (self.pvs[pv], caget(self.pvs[pv])) print('pv pairs', pv_pairs) if slice is None: self.done = True self.event( 'reading image times out, possibly the detector exposure time is too small' ) else: slice.resize(self.sizex, self.sizey) data = ut.Data(slice, pv_pairs) # deliver data to monitor self.deliver_data(data) except: self.done = True self.event( 'reading image raises exception, possibly the detector exposure time is too small' ) except tqueue.Empty: continue self.finish() def acq_done(self, pvname=None, **kws): """ A callback method that activates when pv acquire switches to off. If the value is 0, the function enqueues key word 'finish' into event queue that will be dequeued by the 'handle_event' function. Parameters ---------- pvname : str a PV string for acquire Returns ------- None """ if kws['value'] == 0: self.eventq.put('finish') def on_change(self, pvname=None, **kws): """ A callback method that activates when a frame counter of area detector changes. This method reads the counter value and enqueues it into event queue that will be dequeued by the 'handle_event' function. If it is a first read, the function adjusts counter data in the self object. Parameters ---------- pvname : str a PV string for the area detector frame counter Returns ------- None """ current_ctr = kws['value'] # init on first read if self.current_counter is None: self.current_counter = current_ctr - 1 # the self.current_counter holds previous self.eventq.put(current_ctr) def start_processes(self): """ This function starts processes and callbacks. This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- none Returns ------- nothing """ data_thread = CAThread(target=self.handle_event, args=()) data_thread.start() self.counter_pv = PV(self.get_counter_pv_name()) self.counter_pv.add_callback(self.on_change, index=1) self.acq_pv = PV(self.get_acquire_pv_name()) self.acq_pv.add_callback(self.acq_done, index=2) def get_acquire_pv_name(self): return self.detector + ':cam1:Acquire' def get_counter_pv_name(self): return self.detector + ':cam1:ArrayCounter_RBV' def get_data_pv_name(self): return self.detector + ':image1:ArrayData' def feed_data(self): """ This function is called by a client to start the process. After all initial settings are completed, the method awaits for the area detector to start acquireing by polling the PV. When the area detective is active it starts processing. Parameters ---------- none Returns ------- nothing """ test = True sizex_pv = self.detector + ':image1:ArraySize0_RBV' sizey_pv = self.detector + ':image1:ArraySize1_RBV' acquire_pv_name = self.get_acquire_pv_name() while test: self.sizex = caget(sizex_pv) self.sizey = caget(sizey_pv) ack = caget(acquire_pv_name) if ack == 1: test = False self.start_processes() else: time.sleep(.005) # # start the infinit loop so the feed does not stop after this init # if True: # time.sleep(10) # return caget(acquire_pv_name) def finish(self): try: self.counter_pv.disconnect() except: pass try: self.acq_pv.disconnect() except: pass
class PCO2000(StandardDevice): TYPE_TIFF = "TIFF" TYPE_HDF = "HDF" #CALLBACK FUNCTION FOR THE CCD ACQUIRE STATUS PV def onAcquireChange(self, value, **kw): self._doneRecord = (value == 0) def onAcquireRBVChange(self, value, **kw): self._doneReadOut = (value == 0) def onDataChange(self, value, **kw): if (self.initCamera): self.initCamera = False return self.imageBufferQueue.put(value) self.NData = self.NData + 1 def onNELMChange(self, value, **kw): if (self.initNELM): self.initNELM = False return self.NCount = self.NCount + 1 #CONSTRUCTOR OF CCD CLASS def __init__(self, pvName, mnemonic, imageBufferQueue=None, processName=""): StandardDevice.__init__(self, mnemonic) self.processName = processName self.initCamera = True self.initNELM = True self.NCount = 0 self.NData = 0 self.imageBufferQueue = imageBufferQueue self.pvData = PV(pvName + ":Data", auto_monitor=True) self.pvData.add_callback(self.onDataChange) self.pvAcquire = PV(pvName + ":Acquire", callback=self.onAcquireChange, auto_monitor=True) self.pvAcquireRBV = PV(pvName + ":Acquire_RBV", callback=self.onAcquireRBVChange, auto_monitor=True) self.pvNELM = PV(pvName + ":Data.NELM", callback=self.onNELMChange) self._done = self.isDone() self.pvPixelSize = PV(pvName + ":PixelSize") self.pvCheckImage = PV(pvName + ":CheckImage") self.pvMinX = PV(pvName + ":MinX") self.pvMinY = PV(pvName + ":MinY") self.pvSizeX = PV(pvName + ":SizeX") self.pvSizeY = PV(pvName + ":SizeY") self.pvAcquireTime = PV(pvName + ":AcquireTime") self.pvAcquireTimeBase = PV(pvName + ":AcquireTimeBase") self.pvDelayTime = PV(pvName + ":DelayTime") self.pvDelayTimeBase = PV(pvName + ":DelayTimeBase") self.pvFileFormat = PV(pvName + ":FileFormat") self.pvFileName = PV(pvName + ":FileName") self.pvFileNumber = PV(pvName + ":FileNumber") self.pvFilePath = PV(pvName + ":FilePath") # #### PVS Bellow are used only for information display, no need to be here in the Python Class # #### If needed just uncomment and create the proper methods for GET and SET values. # self.pvADC = PV(pvName+":ADC") # self.pvAutoIncrement = PV(pvName+":AutoIncrement") # self.pvBinHorz = PV(pvName + ":BinHorz") # self.pvBinVert = PV(pvName + ":BinVert") # self.pvBoolTest = PV(pvName + ":BoolTest") # self.pvCamTemp = PV(pvName + ":CamTemp") # self.pvCCDTemp = PV(pvName + ":CCDTemp") # self.pvDoubleImage = PV(pvName + ":DoubleImage") # self.pvHotPixelCorrection = PV(pvName + ":HotPixelCorrection") # self.pvHotPixelX = PV(pvName + ":HotPixelX") # self.pvHotPixelY = PV(pvName + ":HotPixelY") # self.pvNoiseFiltering = PV(pvName + ":NoiseFiltering") # self.pvPixelRate = PV(pvName + ":PixelRate") # self.pvPixelSize = PV(pvName + ":PixelSize") # self.pvPowTemp = PV(pvName + ":PowTemp") # self.pvTimestamp = PV(pvName + ":Timestamp") # self.pvStatus = PV(pvName + ":Status") def getPixelSize(self): return self.pvPixelSize.get() def getCheckImage(self): return self.pvCheckImage.get() def setCheckImage(self, v): self.pvCheckImage.put(v) def getMinX(self): return self.pvMinX.get() def setMinX(self, v): self.pvMinX.put(v) def getMinY(self): return self.pvMinY.get() def setMinY(self, v): self.pvMinY.put(v) def getSizeX(self): return self.pvSizeX.get() def setSizeX(self, v): self.pvSizeX.put(v) def getSizeY(self): return self.pvSizeY.get() def setSizeY(self, v): self.pvSizeY.put(v) def getAcquireTime(self): return self.pvAcquireTime.get() def setAcquireTime(self, v): self.pvAcquireTime.put(v) def getAcquireTimeBase(self): return self.pvAcquireTimeBase.get() def setAcquireTimeBase(self, v): self.pvAcquireTimeBase.put(v) def getDelayTime(self): return self.pvDelayTime.get() def setDelayTime(self, v): self.pvDelayTime.put(v) def getDelayTimeBase(self): return self.pvDelayTimeBase.get() def setDelaytimeBase(self, v): self.pvDelayTimeBase.put(v) def getFileFormat(self): return self.pvFileFormat.get() def setFileFormat(self, v): if (v in [self.TYPE_HDF, self.TYPE_TIFF]): self.pvFileFormat.put(v) else: msg = 'File format "' + v + '" not supported. Only supported are: ' raise Exception('Error: ', msg) def getFileName(self): return self.pvFileName.get() def setFileName(self, v): self.pvFileName.put(v) def getFileNumber(self): return self.pvFileNumber.get() def setFuleNumber(self, v): self.pvFileNumber.put(v) def getFilePath(self): return self.pvFilePath.get() def setFilePath(self, v): self.pvFilePath.put(v) def getCompleteFilePath(self): if (self.getFileFormat() == self.TYPE_TIFF): ext = ".tif" elif (self.getFileFormat() == self.TYPE_HDF): ext = ".h5" else: ext = "" return self.getFilePath() + "/" + self.getFileName() + ext def getNELMChangeCount(self): return self.NCount def getData(self): self._newData = False return self.pvData.get() def isDone(self): return (self.pvAcquireRBV.get() == 0) def isRecordDone(self): return (self.pvAcquire.get() == 0) def isReadOutDone(self): return (self.pvAcquireRBV.get() == 0) def getIntensity(self): return self.scaler.getIntensity() def acquire(self, waitRecord=False, waitReadOut=False): #self.scaler.setCountTime(self.time) #self.scaler.setCountStart() self.pvAcquire.put(1) self._doneRecord = False self._doneReadOut = False self._newData = False if (waitRecord): self.waitRecord() if (waitReadOut): self.waitReadOut() #self.scaler.setCountStop() def waitConfig(self): self._doneConfig = False while (not self._doneConfig): sleep(0.001) def waitRecord(self): while (not self._doneRecord): sleep(0.001) def waitReadOut(self): while (not self._doneReadOut): sleep(0.001) def destroy(self): self.pvData.disconnect() self.pvAcquire.disconnect() self.pvAcquireRBV.disconnect() self.pvNELM.disconnect() self.imageBufferQueue = None
class XAFSviewerFrame(wx.Frame): def __init__(self, parent=None, *args, **kwds): kwds["style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL wx.Frame.__init__(self, parent, wx.NewId(), '', wx.DefaultPosition, wx.Size(-1, -1), **kwds) self.SetTitle(" WXMPlot Plotting Demo") self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False)) menu = wx.Menu() ID_EXIT = wx.NewId() ID_TIMER = wx.NewId() menu.Append(ID_EXIT, "E&xit", "Terminate the program") menuBar = wx.MenuBar() menuBar.Append(menu, "&File") self.SetMenuBar(menuBar) wx.EVT_MENU(self, ID_EXIT, self.OnExit) self.Bind(wx.EVT_CLOSE, self.OnExit) self.plotframe = None framesizer = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(self, -1, size=(-1, -1)) panelsizer = wx.BoxSizer(wx.VERTICAL) panelsizer.Add(wx.StaticText(panel, -1, 'XAFS Spectra viewer '), 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT | wx.EXPAND, 10) b40 = wx.Button(panel, -1, 'Start Timed Plot', size=(-1, -1)) #b40.Bind(wx.EVT_BUTTON,self.onStartTimer) panelsizer.Add(b40, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5) panel.SetSizer(panelsizer) panelsizer.Fit(panel) framesizer.Add(panel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.EXPAND, 2) self.SetSizer(framesizer) framesizer.Fit(self) #----------- added by LWW ----------------------------- self.ShowPlotFrame(do_raise=False, clear=False) self.plotYdata = [] self.plotXdata = [] # ----------epics PVs----------------------- self.i0 = PV('BL10C:scaler1_calc2.VAL') self.it = PV('BL10C:scaler1_calc3.VAL') self.iF = PV('BL10C:scaler1_calc4.VAL') self.trans = PV('BL10C:scaler1_calc8.VAL') self.motorPos = PV('mobiis:m2.RBV') self.scanStart = PV('BL10C:scan2.EXSC.VAL', callback=self.scanStartCALLBACK) while self.motorPos.get() is None: print self.motorPos.get() self.countDonePV = PV('BL10C:scaler1.CNT', callback=self.countDoneCALLBACK) self.time0 = time.time() self.datrange = None #----------- end of add by LWW ----------------------- #wx.EVT_TIMER(self, ID_TIMER, self.onTimer) #self.timer = wx.Timer(self, ID_TIMER) self.Refresh() # --------------epics callback method--------------------- def scanStartCALLBACK(self, **kwargs): if kwargs['value'] is 1: # 0:Done, 1: scanning self.ShowPlotFrame(do_raise=True, clear=True) print 'New Scan Started!!!' else: print 'scan stopped!!!' return def countDoneCALLBACK(self, **kwargs): if kwargs['value'] is 1: # 0:Done, 1:Counting return ## self._flag = True self.plotYdata.append(self.trans.get()) self.plotXdata.append(self.motorPos.get()) ## self._flag = False print 'X:%s, Y:%s' % (len(self.plotXdata), len(self.plotYdata)) # Todo: we need new scan start sequence. # new list, graph clear, data save..., # print 'timer ', self.count, time.time() ## self.count += 1 #self.ShowPlotFrame(do_raise=False, clear=False) ## n = self.count if len(self.plotXdata) < 2: return # Todo: implementation of scan finish sequence. ''' if n >= self.npts: self.timer.Stop() self.timer_results() elif n <= 3: ''' if len(self.plotXdata) <= 3: self.plotframe.plot(self.plotXdata, self.plotYdata, linewidth=0.5, marker='o', markersize=6, xlabel='energy[eV]', ylabel='[count]') # , grid=False) else: xx = np.array(self.plotXdata) yy = np.array(self.plotYdata) self.plotframe.update_line(0, xx, yy, update_limits=len(xx) < 10, draw=True) etime = time.time() - self.time0 s = " %i / %i points in %8.4f s" % (len(self.plotXdata), len(self.plotYdata), etime) self.plotframe.write_message(s) if self.datrange is None: self.datrange = [min(self.plotXdata), max(self.plotXdata), min(self.plotYdata), max(self.plotYdata)] dr = [min(self.plotXdata), max(self.plotXdata), min(self.plotYdata), max(self.plotYdata)] lims = self.plotframe.panel.get_viewlimits() if dr[0] < lims[0] or dr[1] > lims[1] or dr[2] < lims[2] or dr[3] > lims[3]: self.datrange = dr ## if len(self.plotXdata) < len(self.x): ## nmax = min(int(n*1.6), len(self.x)-1) ## self.datrange[1] = self.x[nmax] self.plotframe.panel.set_xylims(self.datrange) def ShowPlotFrame(self, do_raise=True, clear=True): """make sure plot frame is enabled, and visible""" if self.plotframe is None: self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92]) # self.has_plot = False try: self.plotframe.Show() except wx.PyDeadObjectError: self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92]) self.plotframe.Show() if do_raise: self.plotframe.Raise() if clear: self.plotframe.panel.clear() self.plotframe.reset_config() self.plotYdata = [] self.plotXdata = [] ''' def onStartTimer(self,event=None): self.count = 0 self.up_count = 0 self.n_update = 1 self.datrange = None self.time0 = time.time() ### LWW self.start_mem= self.report_memory() self.timer.Start(10) # self.timer.Start(500) def timer_results(self): if (self.count < 2): return etime = time.time() - self.time0 tpp = etime/max(1,self.count) s = "drew %i points in %8.3f s: time/point= %8.4f s" % (self.count,etime,tpp) self.plotframe.write_message(s) self.time0 = 0 self.count = 0 self.datrange = None ''' ''' def onTimer(self, event): # print 'timer ', self.count, time.time() self.count += 1 self.ShowPlotFrame(do_raise=False, clear=False) n = self.count if n < 2: return if n >= self.npts: self.timer.Stop() self.timer_results() elif n <= 3: self.plotframe.plot(self.x[:n], self.y1[:n])# , grid=False) else: self.plotframe.update_line(0, self.x[:n], self.y1[:n], update_limits=n<10, draw=True) etime = time.time() - self.time0 s = " %i / %i points in %8.4f s" % (n,self.npts,etime) self.plotframe.write_message(s) if self.datrange is None: self.datrange = [min(self.x[:n]), max(self.x[:n]), min(self.y1[:n]),max(self.y1[:n])] dr = [min(self.x[:n]), max(self.x[:n]), min(self.y1[:n]), max(self.y1[:n])] lims = self.plotframe.panel.get_viewlimits() if dr[0] < lims[0] or dr[1] > lims[1] or dr[2] < lims[2] or dr[3] > lims[3]: self.datrange = dr if n < len(self.x): nmax = min(int(n*1.6), len(self.x)-1) self.datrange[1] = self.x[nmax] self.plotframe.panel.set_xylims(self.datrange) ''' def OnAbout(self, event): dlg = wx.MessageDialog(self, "This program shows MCA Spectra\n" "message dialog.", "About MPlot test", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def OnExit(self, event): # 1st. disconnect PV(s) self.countDonePV.clear_callbacks() self.i0.disconnect() self.it.disconnect() self.iF.disconnect() self.trans.disconnect() self.motorPos.disconnect() try: if self.plotframe is not None: self.plotframe.onExit() except: pass self.Destroy()