diff --git a/tomcat_bec/devices/gigafrost/gigafrostcamera.py b/tomcat_bec/devices/gigafrost/gigafrostcamera.py index bc5a5a7..909f539 100644 --- a/tomcat_bec/devices/gigafrost/gigafrostcamera.py +++ b/tomcat_bec/devices/gigafrost/gigafrostcamera.py @@ -268,50 +268,41 @@ class GigaFrostCamera(PSIDetectorBase): EpicsSignal, "SOFT_TRIG.PROC", put_complete=True, kind=Kind.omitted) cmdSoftExposure = Component(EpicsSignal, "SOFT_EXP", put_complete=True) - # Trigger configuration PVs - cfgCntStartBit = Component( - EpicsSignal, - "CNT_STARTBIT_RBV", - write_pv="CNT_STARTBIT", + + ############################################################################################### + # Enable schemes + # NOTE: 0 physical, 1 virtual (i.e. always running, but logs enable signal) + cfgEnableScheme = Component( + EpicsSignal, + "MODE_ENBL_EXP_RBV", + write_pv="MODE_ENBL_EXP", put_complete=True, kind=Kind.config, ) - cfgCntEndBit = Component( - EpicsSignal, - "CNT_ENDBIT_RBV", - write_pv="CNT_ENDBIT", - put_complete=True, - kind=Kind.config - ) - # Enable modes - cfgTrigEnableExt = Component( + # Enable signals (combined by OR gate) + cfgEnableExt = Component( EpicsSignal, "MODE_ENBL_EXT_RBV", write_pv="MODE_ENBL_EXT", put_complete=True, kind=Kind.config, ) - cfgTrigEnableSoft = Component( + cfgEnableSoft = Component( EpicsSignal, "MODE_ENBL_SOFT_RBV", write_pv="MODE_ENBL_SOFT", put_complete=True, kind=Kind.config, ) - cfgTrigEnableAuto = Component( + cfgEnableAlways = Component( EpicsSignal, "MODE_ENBL_AUTO_RBV", write_pv="MODE_ENBL_AUTO", put_complete=True, kind=Kind.config, ) - cfgTrigVirtEnable = Component( - EpicsSignal, - "MODE_ENBL_EXP_RBV", - write_pv="MODE_ENBL_EXP", - put_complete=True, - kind=Kind.config, - ) + + ############################################################################################### # Trigger modes cfgTrigExt = Component( EpicsSignal, @@ -341,22 +332,25 @@ class GigaFrostCamera(PSIDetectorBase): put_complete=True, kind=Kind.config, ) + + ############################################################################################### # Exposure modes - cfgTrigExpExt = Component( + # NOTE: I.e.exposure time control, usually TIMER + cfgExpExt = Component( EpicsSignal, "MODE_EXP_EXT_RBV", write_pv="MODE_EXP_EXT", put_complete=True, kind=Kind.config, ) - cfgTrigExpSoft = Component( + cfgExpSoft = Component( EpicsSignal, "MODE_EXP_SOFT_RBV", write_pv="MODE_EXP_SOFT", put_complete=True, kind=Kind.config, ) - cfgTrigExpTimer = Component( + cfgExpTimer = Component( EpicsSignal, "MODE_EXP_TIMER_RBV", write_pv="MODE_EXP_TIMER", @@ -364,6 +358,24 @@ class GigaFrostCamera(PSIDetectorBase): kind=Kind.config, ) + ############################################################################################### + # Trigger configuration PVs + # NOTE: Theese PVs set the behavior on posedge and negedge of the trigger signal + cfgCntStartBit = Component( + EpicsSignal, + "CNT_STARTBIT_RBV", + write_pv="CNT_STARTBIT", + put_complete=True, + kind=Kind.config, + ) + cfgCntEndBit = Component( + EpicsSignal, + "CNT_ENDBIT_RBV", + write_pv="CNT_ENDBIT", + put_complete=True, + kind=Kind.config + ) + # Line swap selection cfgLineSwapSW = Component(EpicsSignal, "LS_SW", put_complete=True, kind=Kind.config) cfgLineSwapNW = Component(EpicsSignal, "LS_NW", put_complete=True, kind=Kind.config) @@ -453,6 +465,9 @@ class GigaFrostCamera(PSIDetectorBase): scanid : int, optional Scan identification number to be associated with the scan data (default = 0) + trigger_mode : str, optional + Trigger mode of the gifafrost + (default = unchanged) correction_mode : int, optional The correction to be applied to the imaging data. The following modes are available (default = 5): @@ -481,6 +496,7 @@ class GigaFrostCamera(PSIDetectorBase): pixel_width = d.get('roix', pixel_width) pixel_height = d.get('roiy', pixel_height) scanid = d.get('scanid', 0) + trigger_mode = d.get('trigger_mode', None) correction_mode = d.get('correction_mode', 5) # change settings @@ -492,9 +508,55 @@ class GigaFrostCamera(PSIDetectorBase): self.cfgCntNum.set(nimages).wait() self.cfgCorrMode.set(correction_mode).wait() + # if trigger_mode is not None: + # self.set_trigger_mode(str(trigger_mode)) + # Commit parameter self.cmdSetParam.set(1).wait() + def set_trigger_mode(self, trigger_mode): + if trigger_mode=="soft": + # Switch to physical enable signal + self.cfgEnableScheme.set(0).wait() + # Set enable signal to always + self.cfgEnableExt.set(0).wait() + self.cfgEnableSoft.set(1).wait() + self.cfgEnableAlways.set(1).wait() + # Set trigger mode to software + self.cfgTrigExt.set(0).wait() + self.cfgTrigSoft.set(1).wait() + self.cfgTrigTimer.set(1).wait() + self.cfgTrigAuto.set(0).wait() + # Set exposure mode to timer + self.cfgExpExt.set(0).wait() + self.cfgExpSoft.set(0).wait() + self.cfgExpTimer.set(1).wait() + # Set trigger edge to fixed frames on posedge + self.cfgCntStartBit.set(1).wait() + self.cfgCntEndBit.set(0).wait() + elif trigger_mode in ["ext", "external"]: + # Switch to physical enable signal + self.cfgEnableScheme.set(0).wait() + # Set enable signal to always + self.cfgEnableExt.set(0).wait() + self.cfgEnableSoft.set(0).wait() + self.cfgEnableAlways.set(1).wait() + # Set trigger mode to external + self.cfgTrigExt.set(1).wait() + self.cfgTrigSoft.set(0).wait() + self.cfgTrigTimer.set(0).wait() + self.cfgTrigAuto.set(0).wait() + # Set exposure mode to timer + self.cfgExpExt.set(0).wait() + self.cfgExpSoft.set(0).wait() + self.cfgExpTimer.set(1).wait() + # Set trigger edge to fixed frames on posedge + self.cfgCntStartBit.set(1).wait() + self.cfgCntEndBit.set(0).wait() + else: + raise RuntimeError(f"Unsupported trigger mode: {trigger_mode}") + + def stage(self): """ Standard stage command""" if not self._initialized: @@ -514,9 +576,9 @@ class GigaFrostCamera(PSIDetectorBase): The camera's active exposure mode. If more than one mode is active at the same time, it returns None. """ - mode_soft = self.cfgTrigExpSoft.get() - mode_timer = self.cfgTrigExpTimer.get() - mode_external = self.cfgTrigExpExt.get() + mode_soft = self.cfgExpSoft.get() + mode_timer = self.cfgExpTimer.get() + mode_external = self.cfgExpExt.get() if mode_soft and not mode_timer and not mode_external: return "soft" if not mode_soft and mode_timer and not mode_external: @@ -536,17 +598,17 @@ class GigaFrostCamera(PSIDetectorBase): The exposure mode to be set. """ if exp_mode == "external": - self.cfgTrigExpExt.set(1).wait() - self.cfgTrigExpSoft.set(0).wait() - self.cfgTrigExpTimer.set(0).wait() + self.cfgExpExt.set(1).wait() + self.cfgExpSoft.set(0).wait() + self.cfgExpTimer.set(0).wait() elif exp_mode == "timer": - self.cfgTrigExpExt.set(0).wait() - self.cfgTrigExpSoft.set(0).wait() - self.cfgTrigExpTimer.set(1).wait() + self.cfgExpExt.set(0).wait() + self.cfgExpSoft.set(0).wait() + self.cfgExpTimer.set(1).wait() elif exp_mode == "soft": - self.cfgTrigExpExt.set(0).wait() - self.cfgTrigExpSoft.set(1).wait() - self.cfgTrigExpTimer.set(0).wait() + self.cfgExpExt.set(0).wait() + self.cfgExpSoft.set(1).wait() + self.cfgExpTimer.set(0).wait() else: raise ValueError( f"Invalid exposure mode! Valid modes are:\n{const.gf_valid_exposure_modes}" @@ -679,22 +741,26 @@ class GigaFrostCamera(PSIDetectorBase): enable_mode: {'soft', 'external', 'soft+ext', 'always'} The camera's active enable mode. """ - mode_soft = self.cfgTrigEnableSoft.get() - mode_external = self.cfgTrigEnableExt.get() - mode_auto = self.cfgTrigEnableAuto.get() - if mode_soft and not mode_auto: - return "soft+ext" if mode_external else "soft" - if mode_auto and not mode_soft and not mode_external: + mode_soft = self.cfgEnableSoft.get() + mode_external = self.cfgEnableExt.get() + mode_always = self.cfgEnableAlways.get() + if mode_always: return "always" - if mode_external and not mode_soft and not mode_auto: + elif mode_soft and mode_external: + return "soft+ext" + elif mode_soft and not mode_external: + return "soft" + elif mode_external and not mode_soft: return "external" - - return None + else: + return None @enable_mode.setter def enable_mode(self, mode): """Apply the enable mode for the GigaFRoST camera. + NOTE: Always does not seem to work and Enablesoft works like a trigger + Parameters ---------- mode : {'soft', 'external', 'soft+ext', 'always'} @@ -706,21 +772,21 @@ class GigaFrostCamera(PSIDetectorBase): ) if mode == "soft": - self.cfgTrigEnableExt.set(0).wait() - self.cfgTrigEnableSoft.set(1).wait() - self.cfgTrigEnableAuto.set(0).wait() + self.cfgEnableExt.set(0).wait() + self.cfgEnableSoft.set(1).wait() + self.cfgEnableAlways.set(0).wait() elif mode == "external": - self.cfgTrigEnableExt.set(1).wait() - self.cfgTrigEnableSoft.set(0).wait() - self.cfgTrigEnableAuto.set(0).wait() + self.cfgEnableExt.set(1).wait() + self.cfgEnableSoft.set(0).wait() + self.cfgEnableAlways.set(0).wait() elif mode == "soft+ext": - self.cfgTrigEnableExt.set(1).wait() - self.cfgTrigEnableSoft.set(1).wait() - self.cfgTrigEnableAuto.set(0).wait() + self.cfgEnableExt.set(1).wait() + self.cfgEnableSoft.set(1).wait() + self.cfgEnableAlways.set(0).wait() elif mode == "always": - self.cfgTrigEnableExt.set(0).wait() - self.cfgTrigEnableSoft.set(0).wait() - self.cfgTrigEnableAuto.set(1).wait() + self.cfgEnableExt.set(0).wait() + self.cfgEnableSoft.set(0).wait() + self.cfgEnableAlways.set(1).wait() # Commit parameters self.cmdSetParam.set(1).wait() diff --git a/tomcat_bec/scans/tomcat_scanbase.py b/tomcat_bec/scans/tomcat_scanbase.py index 6b917d8..0de5bd7 100644 --- a/tomcat_bec/scans/tomcat_scanbase.py +++ b/tomcat_bec/scans/tomcat_scanbase.py @@ -289,7 +289,8 @@ class GigaStepScanBase(ScanBase): "ntotal": self.scan_ntotal, "nimages": burst_at_each_point, "exposure": 1000*exp_time, - "period": 2000*exp_time, + "period": 2000*exp_time, + "trigger_mode": "soft", "pixel_width": self.scan_roix, "pixel_height": self.scan_roiy } @@ -393,7 +394,8 @@ class SnapAndStepScanBase(TemplatedScanBase): "ntotal": self.scan_ntotal, "nimages": burst_at_each_point, "exposure": 1000 * exp_time, - "period": 2000*exp_time, + "period": 2000*exp_time, + "trigger_mode": "eternal", "pixel_width": roix, "pixel_height": roiy } diff --git a/tomcat_bec/scripts/demoscans.py b/tomcat_bec/scripts/demoscans.py index 46988a1..4a2e139 100644 --- a/tomcat_bec/scripts/demoscans.py +++ b/tomcat_bec/scripts/demoscans.py @@ -9,7 +9,7 @@ def bl_check_beam(): -def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, roix=2016, roiy=2016, sync='event'): +def demostepscan(scan_start, scan_end, steps, exp_time=0.005, exp_burst=1, settling_time=0, roix=2016, roiy=2016, sync='event'): """ Demo step scan with GigaFrost This is a small BEC user-space demo step scan at the microXAS testbench @@ -18,33 +18,34 @@ def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_poin Example: -------- - demostepscan(scan_start=-32, scan_end=148, steps=180, exp_time=0.005, burst_at_each_point=5) + demostepscan(scan_start=-32, scan_end=148, steps=180, exp_time=0.005, exp_burst=5) """ if not bl_check_beam(): raise RuntimeError("Beamline is not in ready state") - scan_ntotal = burst_at_each_point * (steps + 1) + scan_ntotal = exp_burst * (steps + 1) # Move to start position t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4} - cfg = {'ntotal': scan_ntotal, 'trigger': t_modes[sync]} + cfg = {'ntotal': scan_ntotal*10, 'trigger': t_modes[sync]} dev.es1_ddaq.configure(d=cfg) # Configure gigafrost cfg = { - "ntotal": scan_ntotal, "nimages": burst_at_each_point, + "ntotal": scan_ntotal, "nimages": exp_burst, "exposure": 1000*exp_time, "period": 2000*exp_time, - "pixel_width": roix, "pixel_height": roiy + "pixel_width": roix, "pixel_height": roiy, "trigger_mode": "soft" } dev.gfclient.configure(d=cfg) # Configure PSO trigger (trigger is normally disabled in fly mode) - dev.es1_psod.configure(d={}) - dev.es1_psod.software_trigger = True + # dev.es1_psod.configure(d={}) + # dev.es1_psod.software_trigger = True # Explicitly arm trigger (and detector in future) - dev.es1_psod.prepare() + # dev.es1_psod.prepare() + # dev.es1_roty.move(scan_start).wait() print("Handing over to 'scans.line_scan'") - wait_time = 0.1 + 2*exp_time * burst_at_each_point + wait_time = 2*exp_time * exp_burst scans.line_scan( dev.es1_roty, scan_start, scan_end, steps=steps, exp_time=wait_time, relative=False, settling_time=settling_time)