diff --git a/phoenix_bec/bec_ipython_client/startup/post_startup.py b/phoenix_bec/bec_ipython_client/startup/post_startup.py index 17bba61..a5ffa50 100644 --- a/phoenix_bec/bec_ipython_client/startup/post_startup.py +++ b/phoenix_bec/bec_ipython_client/startup/post_startup.py @@ -43,9 +43,9 @@ from IPython.core.magic import register_line_magic from bec_lib.logger import bec_logger logger = bec_logger.logger -#logger = bec_logger.LOGLEVEL.TRACE +# logger = bec_logger.LOGLEVEL.TRACE -#pylint: disable=invald-name, unused-import, import-error, undefined-variable, unused-variable, unused-argument, no-name-in-module +# pylint: disable=invald-name, unused-import, import-error, undefined-variable, unused-variable, unused-argument, no-name-in-module _session_name = "session_phoenix" # SETUP PROMPTS @@ -54,23 +54,21 @@ bec._ip.prompts.status = 1 # make sure that edited modules are reloaded when changed -print('phoenix_bec/bec_iphyon_client/startup/post_startup.py') -print('... set autoreload of modules') -bec._ip.run_line_magic("reload_ext","autoreload") +print("phoenix_bec/bec_iphyon_client/startup/post_startup.py") +print("... set autoreload of modules") +bec._ip.run_line_magic("reload_ext", "autoreload") bec._ip.run_line_magic("autoreload", "2") -print('autoreload loaded ') - +print("autoreload loaded ") ############################################################################# # -#... register BL specific magic commands +# ... register BL specific magic commands # ############################################################################## - @register_line_magic def ph_reload(line): @@ -85,62 +83,76 @@ def ph_reload(line): ###################################################################W##### from phoenix_bec.scripts import phoenix as PH - print('reload phoenix_bec.scripts.phoenix to iphyhton console') - print('to update version server restart server ') + + print("reload phoenix_bec.scripts.phoenix to iphyhton console") + print("to update version server restart server ") # need to use global statement here, as I like to reload into space on # iphyton consoel - global PH,phoenix - print('from phoenix_bec.scripts import phoenix as PH') - print('phoenix = PH.PhoenixBL()') + global PH, phoenix + print("from phoenix_bec.scripts import phoenix as PH") + print("phoenix = PH.PhoenixBL()") phoenix = PH.PhoenixBL() - #ph_config=PH.PhoenixConfighelper() -#enddef + # ph_config=PH.PhoenixConfighelper() -print('##################################################################') -print('register magic') -print('...... %ph_load_xmap ... to reload xmap configuration') +# enddef + +print("##################################################################") +print("register magic") +print("...... %ph_load_xmap ... to reload xmap configuration") @register_line_magic def ph_load_xmap(line): ### - #magic for loading xmap + # magic for loading xmap ### - t0=tt.time() + t0 = tt.time() phoenix_server.add_xmap() - print('elapsed time:', tt.time()-t0) -#enddef + print("elapsed time:", tt.time() - t0) + + +# enddef + +print("...... %ph_load_falcon ... to reload falcon configuration") + -print('...... %ph_load_falcon ... to reload falcon configuration') @register_line_magic def ph_load_falcon(line): # magic to load falcon - t0=tt.time() + t0 = tt.time() phoenix_server.add_falcon() - print('elapsed time:', tt.time()-t0) -#enddef + print("elapsed time:", tt.time() - t0) + + +# enddef + +print("...... %ph_load_config ... to reload phoenix default configuration") + -print('...... %ph_load_config ... to reload phoenix default configuration') @register_line_magic def ph_load_config(line): - t0=tt.time() + t0 = tt.time() phoenix_server.add_phoenix_config() - print('elapsed time:', tt.time()-t0) -#enddef + print("elapsed time:", tt.time() - t0) + + +# enddef + @register_line_magic def ph_restart_bec_server(line): - os.system('bec-server restart') + os.system("bec-server restart") os.system('gnome-terminal --geometry 120X50 -- bash -c "bec-server attach; exec bash"') + ##@register_line_magic -#def ph_post_startup(line): +# def ph_post_startup(line): # print('import phoenix_bec.bec_ipython_client.startup.post_startup does not work caused loop ') # #import phoenix_bec.bec_ipython_client.startup.post_startup # does not work seems to build a infinite stack... @@ -154,21 +166,20 @@ def ph_restart_bec_server(line): ## ##################################################################################### -print('###############################################################') -print('init phoenix_bec/scripts/phoenix.py in two different ways') -print(' 1) phoenix_server = PhoenixBL() ... takes code from server version ') -print('SERBVR VERSION DOES NOT WORK ANYMORE ') -print('FOLDER SCRUIPT SEEMS TO BE NON_STANDARD!!!!!!! ') +print("###############################################################") +print("init phoenix_bec/scripts/phoenix.py in two different ways") +print(" 1) phoenix_server = PhoenixBL() ... takes code from server version ") +print("SERBVR VERSION DOES NOT WORK ANYMORE ") +print("FOLDER SCRUIPT SEEMS TO BE NON_STANDARD!!!!!!! ") -phoenix_server=PhoenixBL() +phoenix_server = PhoenixBL() -print(' 2) phoenix=PH.PhoenixBL() ... on inpython shell only! (for debugging)') +print(" 2) phoenix=PH.PhoenixBL() ... on inpython shell only! (for debugging)") from phoenix_bec.scripts import phoenix as PH + phoenix = PH.PhoenixBL() - -#from phoenix_bec.bec_ipython_client.plugins.phoenix import Phoenix -#from phoenix_bec.devices.falcon_phoenix_no_hdf5 import FalconHDF5Plugins - +# from phoenix_bec.bec_ipython_client.plugins.phoenix import Phoenix +# from phoenix_bec.devices.falcon_phoenix_no_hdf5 import FalconHDF5Plugins diff --git a/phoenix_bec/device_configs/phoenix_devices.yaml b/phoenix_bec/device_configs/phoenix_devices.yaml index e2a52dd..52dac00 100644 --- a/phoenix_bec/device_configs/phoenix_devices.yaml +++ b/phoenix_bec/device_configs/phoenix_devices.yaml @@ -1,26 +1,4 @@ -falcon_nohdf5: - description: Falcon detector x-ray fluoresence II - deviceClass: phoenix_bec.devices.falcon_phoenix_no_hdf5.FalconPhoenix - deviceConfig: - prefix: 'X07MB-SITORO:' - deviceTags: - - phoenix - - falcon - - no hdf5 - - phoenix_devices.yaml - onFailure: buffer - enabled: true - readoutPriority: async - softwareTrigger: false - - -################################################### -# -# phoenix standard devices (motors) -# -# -####################################################: PH_TTL: description: PHOENIX TTL trigger deviceClass: phoenix_bec.devices.phoenix_trigger.PhoenixTrigger @@ -36,6 +14,13 @@ PH_TTL: softwareTrigger: true +################################################### +# +# phoenix standard devices (motors) +# +# +####################################################: + PH_Dummy: description: PHOENIX DUMMY DET deviceClass: phoenix_bec.devices.dummy_devices.Dummy_PSIDetector diff --git a/phoenix_bec/devices/phoenix_trigger.py b/phoenix_bec/devices/phoenix_trigger.py index d4fe1c7..9b05cf2 100644 --- a/phoenix_bec/devices/phoenix_trigger.py +++ b/phoenix_bec/devices/phoenix_trigger.py @@ -1,5 +1,17 @@ -""" Module for the PhoenixTrigger class to connect to the ADC card -that creates TTL signals to trigger cameras and detectors at Phoenix. """ +""" +Module for the PhoenixTrigger class to connect to the ADC card +that creates TTL signals to trigger cameras and detectors at Phoenix. + +TO Do + +-- allow for variable dwell times +-- add erase/Start for XMAP and FALCON +-- check values for time.sleep() +-- check in on_triggerthe status check for Falcon +-- rework togther with Xiaoquiang the functionality of involved EPICS channels + (Callbacks etc.) to minimize the need of sleeping times. + +""" import enum import time @@ -23,10 +35,16 @@ class PhoenixTriggerError(Exception): class SAMPLING(int, enum.Enum): - """Sampling Done PV""" + """Sampling Done PV - RUNNING = 0 - DONE = 1 + This class serves redabilty of missinx class and ensure correct setting of + certain conditions. + defiend preset values for certain states to be called in the + mixing class, where we for example check whether the sampling is done of not + by comparing with SAMPLING.DONE + xxx==SAMPLING.DONE + + """ class PhoenixTriggerSetup(CustomDetectorMixin): @@ -35,13 +53,26 @@ class PhoenixTriggerSetup(CustomDetectorMixin): """ def on_stage(self) -> None: - """On stage actions which are executed upon staging the device""" - if self.parent.scaninfo.scan_type == "step": + """ + + On stage actions which are executed upon staging the device + + + """ + if self.parent.scaninfo.scan_type == "step": # check whether we use step scanning + ############### + # next lines ensure that TTL trigger is on single sampling mode (posible ) + ############## self.parent.start_csmpl.set(0) + time.sleep(0.1) self.parent.total_cycles.set(1) self.parent.smpl.put(1) time.sleep(0.5) + ##### + # set sampling to dwell time of scan + ###### self.parent.total_cycles.set(np.ceil(self.parent.scaninfo.exp_time * 5)) + logger.info(f"Device {self.parent.name} was staged for step scan") def on_unstage(self) -> None: @@ -50,21 +81,26 @@ class PhoenixTriggerSetup(CustomDetectorMixin): def on_trigger(self) -> DeviceStatus: """On trigger actions which are executed upon triggering the device""" + # TODO Test the proper check for the falcon state # Check first that falcon is set to acquiring - falcon = self.parent.device_manager.devices.get("falcon_nohdf5", None) + falcon = self.parent.device_manager.devices.get("falcon_nohdf5", None) # get device timeout = 1 if falcon is not None: # TODO Check that falcon.state.get() == 1 is the correct check. --> When is the falcon acquiring, this assumes 1? + if not self.wait_for_signals([(falcon.state.get, 1)], timeout=timeout): raise PhoenixTriggerError( f"Device {self.parent.name} is not ready to take trigger, timeout due to waiting for Falcon to get ready. Timeout after {timeout}s" ) + if self.parent.scaninfo.scan_type == "step": time.sleep(0.2) self.parent.smpl.put(1) # Minimum of 1 cycle has to be waited. Cycle == 0.2s + time.sleep(0.2) + # Trigger function from ophyd.Device returns a DeviceStatus. This function # starts a process that creates a DeviceStatus, and waits for the signal_conditions # self.parent.smpl_done.get to change to the value SAMPLING.DONE @@ -74,18 +110,30 @@ class PhoenixTriggerSetup(CustomDetectorMixin): # In ScanBase, the _at_each_point function calls # self.stubs.wait(wait_type="trigger", group="trigger", wait_time=self.exp_time) # which ensures that the DeviceStatus object resolves before continuing, i.e. DeviceStatus.done = True + status = self.wait_with_status( signal_conditions=[(self.parent.smpl_done.get, SAMPLING.DONE)], timeout=5 * self.parent.scaninfo.exp_time, # Check if timeout is appropriate check_stopped=True, ) - return status + + # explanation of last line (self.parent.smpl_done.get, SAMPLINGDONE.DONE) creates a tuple which defines a + # condition, which is tested in self.wait_with_status, here it tests for : + # (self.parent.smpl_done.get() == SAMPLINGDONE.DONE), where SAMPLINGDONE.DONE =1, as set in code above + # As this is in mixing class (PhoenixtriggerSetup), parent.sample_done is defined in + # main class as smpl_done = Cpt(EpicsSignalRO, "SMPL-DONE", kind=Kind.config) + + return status # should this be in if clause level or outside? + # endif def on_stop(self) -> None: - """Actions to stop the Device""" - # Put the Device again in continous acquisition mode - self.parent.total_cycles.set(5) + """ + Actions to stop the Device + Here the device is switched back to continuous sampling. + + """ self.parent.start_csmpl.set(1) + time.sleep(0.5) self.parent.smpl.put(1) time.sleep(0.5) self.parent.smpl.put(1) @@ -102,8 +150,51 @@ class PhoenixTrigger(PSIDetectorBase): This device is used to trigger communicate with an ADC card that creates TTL signals to trigger cameras and detectors at Phoenix. """ + ################################################################## + # + # The Variable USER_ACCESS contains an ascii list of functions which will be + # visible in dev.TTL. Here, this list is empty. + # note that components are alway public + # + ################################################################## + + USER_ACCESS = [] + + ##################################################################### + # specify Setup class into variable custom_prepare_cls + # in __init__ of PSIDetectorBase will the initialzed by + # self.custom_prepare = self.custom_prepare_cls(parent=self, **kwargs) + # making the instance of PSIDetectorBase availble to functions + # in PhoenixTriggerSetup. + ###################################################################### + custom_prepare_cls = PhoenixTriggerSetup + ############################################################# + # + # Now use Component=Cpt to provide channel access + # when PhoenixTrigger is initialized, the parameters of the base class are + # inherited, most notable prefix, which is here 'X07MB-OP2:' + # + # The input of Component=Cpt is Cpt(deviceClass,suffix) + # if Cpt is used in a class, which has interited Device, here via: + # + # (Here PhoenixTrigger <-- PSIDetectorBase <- Device + # + # then Cpt will construct - magically- the + # Epics channel name = prefix+suffix, + # + # for example + # 'X07MB-OP2:' + 'START-CSMPL' -> 'X07MB-OP2:' + 'START-CSMPL' + # + # to construct names, for now we keep the convention to derive + # them from the EPICS NAMES (such as ) X07MB-OP2:SMPL-DONE --> smpl_done + # + # this mean access to channel using dev.PH_TTL.smpl_done.get() + # + # + ################################################################### + start_csmpl = Cpt( EpicsSignal, "START-CSMPL", kind=Kind.config, put_complete=True ) # cont on / off diff --git a/phoenix_bec/scripts/phoenix.py b/phoenix_bec/scripts/phoenix.py index 76bc6ea..1037419 100644 --- a/phoenix_bec/scripts/phoenix.py +++ b/phoenix_bec/scripts/phoenix.py @@ -55,21 +55,29 @@ class PhoenixBL: self.path_scripts_local = ( "/data/test/x07mb-test-bec/bec_deployment/phoenix_bec/phoenix_bec/local_scripts/" ) + self.path_config_local = ( self.path_scripts_local + "TEST_ConfigPhoenix/" ) # base dir for local configurations + self.path_devices_local = ( self.path_config_local + "Local_device_config/" ) # local yamal file + self.file_devices_file_local = self.path_devices_local + "phoenix_devices.yaml" self.path_phoenix_bec = "/data/test/x07mb-test-bec/bec_deployment/phoenix_bec/" - self.path_devices = ( - self.path_phoenix_bec + "phoenix_bec/device_configs/" - ) # local yamal file + self.path_devices = self.path_phoenix_bec + "phoenix_bec/device_configs/" + # yamal file for default configuration + self.file_devices_file = ( self.path_phoenix_bec + "phoenix_bec/device_configs/phoenix_devices.yaml" ) # local yamal file + + self.file_devices_tmp = ( + self.path_phoenix_bec + "phoenix_bec/device_configs/current_devices_tmp.yaml" + ) # tmp configuration file. Will be electronicall created and appended if needed + self.t0 = time.time() def read_local_phoenix_config(self): @@ -77,24 +85,30 @@ class PhoenixBL: print(self.file_phoenix_devices_file) bec.config.update_session_with_file(self.file_devices_file_local) + def create_base_config(self): + # create a yaml file from standard configuration + os.system("cat " + self.file_devices_file + " > " + self.file_devices_tmp) + # os.system("ls -altr" + self.path_phoenix_bec + "phoenix_bec/devices") + bec.config.update_session_with_file(self.file_devices_tmp) + def add_phoenix_config(self): print("add_phoenix_config ") print("self.file_devices_file") - bec.config.update_session_with_file(self.file_devices_file) + bec.config.update_session_with_file(self.tmp.file_devices_file) def add_xmap(self): print("add xmap ") - print(self.path_devices + "phoenix_xmap.yaml") - bec.config.update_session_with_file( - self.path_devices + "phoenix_xmap.yaml" - ) # ,timeout=100) + os.system("cat " + self.path_devices + "phoenix_xmap.yaml" + " >> " + self.file_devices_tmp) + bec.config.update_session_with_file(self.file_devices_tmp) def add_falcon(self): - print("add_xmap") - print(self.path_devices + "/phoenix_falcon.yaml") - # bec.config.wait_for_config_reply() - bec.config.update_session_with_file(self.path_devices + "/phoenix_falcon.yaml") + print("add_falcon") + + os.system( + "cat " + self.path_devices + "phoenix_falcon.yaml" + " >> " + self.file_devices_tmp + ) + bec.config.update_session_with_file(self.file_devices_tmp) def show_phoenix_setup(self): print(self.path_phoenix_bec)