class EigerBase(AreaDetector, HxnModalTrigger):
    """
    Eiger, sans any triggering behavior.

    Use EigerSingleTrigger or EigerFastTrigger below.
    """
    num_triggers = ADComponent(EpicsSignalWithRBV, 'cam1:NumTriggers')
    file = Cpt(EigerSimulatedFilePlugin, suffix='cam1:',
               # write_path_template='/XF11ID/data/%Y/%m/%d/',
               # write_path_template='/data/eiger_tests/',
               write_path_template='/data/eiger1m/%Y/%m/%d/',
               #root='/XF11ID/',
               root='/data')
    beam_center_x = ADComponent(EpicsSignalWithRBV, 'cam1:BeamX')
    beam_center_y = ADComponent(EpicsSignalWithRBV, 'cam1:BeamY')
    wavelength = ADComponent(EpicsSignalWithRBV, 'cam1:Wavelength')
    det_distance = ADComponent(EpicsSignalWithRBV, 'cam1:DetDist')
    threshold_energy = ADComponent(EpicsSignalWithRBV, 'cam1:ThresholdEnergy')
    photon_energy = ADComponent(EpicsSignalWithRBV, 'cam1:PhotonEnergy')
    manual_trigger = ADComponent(EpicsSignalWithRBV, 'cam1:ManualTrigger')  # the checkbox
    special_trigger_button = ADComponent(EpicsSignal, 'cam1:Trigger')  # the button next to 'Start' and 'Stop'
    image = Cpt(ImagePlugin, 'image1:')
    stats1 = Cpt(StatsPlugin, 'Stats1:')
    stats2 = Cpt(StatsPlugin, 'Stats2:')
    stats3 = Cpt(StatsPlugin, 'Stats3:')
    stats4 = Cpt(StatsPlugin, 'Stats4:')
    stats5 = Cpt(StatsPlugin, 'Stats5:')
    roi1 = Cpt(ROIPlugin, 'ROI1:')
    roi2 = Cpt(ROIPlugin, 'ROI2:')
    roi3 = Cpt(ROIPlugin, 'ROI3:')
    roi4 = Cpt(ROIPlugin, 'ROI4:')
    proc1 = Cpt(ProcessPlugin, 'Proc1:')

    shutter_mode = ADComponent(EpicsSignalWithRBV, 'cam1:ShutterMode')

    # hotfix: shadow non-existant PV
    size_link = None

    def stage(self, *args, **kwargs):
        # before parent
        ret = super().stage(*args, **kwargs)
        # after parent
        set_and_wait(self.manual_trigger, 1)
        return ret

    def unstage(self):
        set_and_wait(self.manual_trigger, 0)
        super().unstage()

    @property
    def hints(self):
        return {'fields': [self.stats1.total.name]}

    def mode_internal(self):
        # super().mode_internal()

        count_time = self.count_time.get()
        if count_time is not None:
            self.cam.stage_sigs[self.cam.acquire_time] = count_time
            self.cam.stage_sigs[self.cam.acquire_period] = count_time + 0.020
class EigerSimulatedFilePlugin(Device, FileStoreBase):
    sequence_id = ADComponent(EpicsSignalRO, 'SequenceId')
    file_path = ADComponent(EpicsSignalWithRBV, 'FilePath', string=True)
    file_write_name_pattern = ADComponent(EpicsSignalWithRBV, 'FWNamePattern',
                                          string=True)
    file_write_images_per_file = ADComponent(EpicsSignalWithRBV,
                                             'FWNImagesPerFile')
    current_run_start_uid = Cpt(Signal, value='', add_prefix=())
    enable = SimpleNamespace(get=lambda: True)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._datum_kwargs_map = dict()  # store kwargs for each uid
        self.filestore_spec = 'AD_EIGER2'

    def stage(self):
        res_uid = new_short_uid()
        write_path = datetime.now().strftime(self.write_path_template)
        set_and_wait(self.file_path, write_path)
        set_and_wait(self.file_write_name_pattern, '{}_$id'.format(res_uid))
        super().stage()
        fn = (PurePath(self.file_path.get()) / res_uid)
        ipf = int(self.file_write_images_per_file.get())
        # logger.debug("Inserting resource with filename %s", fn)
        self._fn = fn
        res_kwargs = {'images_per_file': ipf}
        self._generate_resource(res_kwargs)

    def generate_datum(self, key, timestamp, datum_kwargs):
        # The detector keeps its own counter which is uses label HDF5
        # sub-files.  We access that counter via the sequence_id
        # signal and stash it in the datum.
        seq_id = 1 + int(self.sequence_id.get())  # det writes to the NEXT one
        datum_kwargs.update({'seq_id': seq_id})
        return super().generate_datum(key, timestamp, datum_kwargs)
class EigerBase(AreaDetector):
    """
    Eiger, sans any triggering behavior.

    Use EigerSingleTrigger or EigerFastTrigger below.
    """
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('labels', ['detectors', 'cameras'])
        super().__init__(*args, **kwargs)


    num_triggers = ADComponent(EpicsSignalWithRBV, 'cam1:NumTriggers')
    file = Cpt(EigerSimulatedFilePlugin, suffix='cam1:',
               write_path_template='/GPFS/xf04id/DATA/Eiger1M/%Y/%m/%d/',
               root='/GPFS/xf04id/')

    beam_center_x = ADComponent(EpicsSignalWithRBV, 'cam1:BeamX')
    beam_center_y = ADComponent(EpicsSignalWithRBV, 'cam1:BeamY')
    wavelength = ADComponent(EpicsSignalWithRBV, 'cam1:Wavelength')
    det_distance = ADComponent(EpicsSignalWithRBV, 'cam1:DetDist')
    threshold_energy = ADComponent(EpicsSignalWithRBV, 'cam1:ThresholdEnergy')
    photon_energy = ADComponent(EpicsSignalWithRBV, 'cam1:PhotonEnergy')
    # the checkbox
    manual_trigger = ADComponent(EpicsSignalWithRBV, 'cam1:ManualTrigger')
    # the button next to 'Start' and 'Stop'
    special_trigger_button = ADComponent(EpicsSignal, 'cam1:Trigger')
    image = Cpt(ImagePlugin, 'image1:')
    stats1 = Cpt(StatsPlugin, 'Stats1:')
    stats2 = Cpt(StatsPlugin, 'Stats2:')
    stats3 = Cpt(StatsPlugin, 'Stats3:')
    stats4 = Cpt(StatsPlugin, 'Stats4:')
    stats5 = Cpt(StatsPlugin, 'Stats5:')
    roi1 = Cpt(ROIPlugin, 'ROI1:')
    roi2 = Cpt(ROIPlugin, 'ROI2:')
    roi3 = Cpt(ROIPlugin, 'ROI3:')
    roi4 = Cpt(ROIPlugin, 'ROI4:')
    proc1 = Cpt(ProcessPlugin, 'Proc1:')

    shutter_mode = ADComponent(EpicsSignalWithRBV, 'cam1:ShutterMode')

    # hotfix: shadow non-existant PV
    size_link = None

    def stage(self):
        # before parent
        super().stage()
        # after parent
        set_and_wait(self.manual_trigger, 1)

    def unstage(self):
        set_and_wait(self.manual_trigger, 0)
        super().unstage()
class EigerSimulatedFilePlugin(Device, FileStoreBase):
    sequence_id = ADComponent(EpicsSignalRO, 'SequenceId')
    file_path = ADComponent(EpicsSignalWithRBV, 'FilePath', string=True)
    file_write_name_pattern = ADComponent(EpicsSignalWithRBV, 'FWNamePattern',
                                          string=True)
    file_write_images_per_file = ADComponent(EpicsSignalWithRBV,
                                             'FWNImagesPerFile')
    current_run_start_uid = Cpt(Signal, value='', add_prefix=())
    enable = SimpleNamespace(get=lambda: True)

    def __init__(self, *args, **kwargs):
        self.sequence_id_offset = 1
        # This is changed for when a datum is a slice
        # also used by ophyd
        self.filestore_spec = "AD_EIGER2"
        self.frame_num = None
        super().__init__(*args, **kwargs)
        self._datum_kwargs_map = dict()  # store kwargs for each uid

    def stage(self):
        res_uid = new_short_uid()
        write_path = datetime.now().strftime(self.write_path_template)
        set_and_wait(self.file_path, write_path + '/')
        set_and_wait(self.file_write_name_pattern, '{}_$id'.format(res_uid))
        super().stage()
        fn = (PurePath(self.file_path.get()) / res_uid)
        ipf = int(self.file_write_images_per_file.get())
        # logger.debug("Inserting resource with filename %s", fn)
        self._fn = fn
        res_kwargs = {'images_per_file' : ipf}
        self._generate_resource(res_kwargs)

    def generate_datum(self, key, timestamp, datum_kwargs):
        # The detector keeps its own counter which is uses label HDF5
        # sub-files.  We access that counter via the sequence_id
        # signal and stash it in the datum.
        seq_id = int(self.sequence_id_offset) + int(self.sequence_id.get())  # det writes to the NEXT one
        datum_kwargs.update({'seq_id': seq_id})
        if self.frame_num is not None:
            datum_kwargs.update({'frame_num': self.frame_num})
        return super().generate_datum(key, timestamp, datum_kwargs)

    def describe(self,):
        ret = super().describe()
        if hasattr(self.parent.cam, 'bit_depth'):
            cur_bits = self.parent.cam.bit_depth.get()
            dtype_str_map = {8: '|u1', 16: '<u2', 32:'<u4'}
            ret[self.parent._image_name]['dtype_str'] = dtype_str_map[cur_bits]
        return ret
예제 #5
0
class PCDSAreaDetectorBase(DetectorBase):
    """Standard area detector with no plugins."""
    cam = ADComponent(cam.CamBase, '')

    def get_plugin_graph_edges(self, *, use_names=True, include_cam=False):
        """
        Get a list of (source, destination) ports for all plugin chains.

        Parameters
        ----------
        use_names : bool, optional
            By default, the ophyd names for each plugin are used. Set this to
            False to instead get the AreaDetector port names.
        include_cam : bool, optional
            Include plugins with 'CAM' as the source.  As it is easy to assume
            that a camera without an explicit source is CAM, by default this
            method does not include it in the list.
        """

        cam_port = self.cam.port_name.get()
        graph, port_map = self.get_asyn_digraph()
        port_edges = [(src, dest) for src, dest in graph.edges
                      if src != cam_port or include_cam]
        if use_names:
            port_edges = [(port_map[src].name, port_map[dest].name)
                          for src, dest in port_edges]
        return port_edges
예제 #6
0
class PCDSAreaDetectorBase(DetectorBase):
    """Standard area detector with no plugins."""
    cam = ADComponent(cam.CamBase, '')

    def get_plugin_graph_edges(self, *, use_names=True, include_cam=False):
        """
        Get a list of (source, destination) ports for all plugin chains.

        Parameters
        ----------
        use_names : bool, optional
            By default, the ophyd names for each plugin are used. Set this to
            False to instead get the AreaDetector port names.
        include_cam : bool, optional
            Include plugins with 'CAM' as the source.  As it is easy to assume
            that a camera without an explicit source is CAM, by default this
            method does not include it in the list.
        """

        cam_port = self.cam.port_name.get()
        graph, port_map = self.get_asyn_digraph()
        port_edges = [(src, dest) for src, dest in graph.edges
                      if src != cam_port or include_cam]
        if use_names:
            port_edges = [(port_map[src].name, port_map[dest].name)
                          for src, dest in port_edges]
        return port_edges

    def screen(self, main: bool = False) -> None:
        """
        Open camViewer screen for camera.

        Parameters
        ----------
        main : bool, optional
            Set to True to bring up 'main' edm config screen.
            Defaults to False, which opens python viewer.
        """
        if not shutil.which('camViewer'):
            logger.error('no camViewer available')
            return

        arglist = [
            'camViewer', '-H',
            str(get_hutch_name()).lower(), '-c', self.name
        ]
        if main:
            arglist.append('-m')

        logger.info('starting camviewer')
        subprocess.run(arglist, check=False)
예제 #7
0
class FeeOpalCam(cam.CamBase):
    """Opal camera used in the FEE for the PIMs."""
    # enums?
    # trigger_modes = enum("Internal", "External", start=0)
    # exposure_modes = enum("Full Frame", "HW ROI", start=0)
    # acquire_enum = enum("Done", "Acquire", start=0)
    # test_patterns = enum("Off", "On", start=0)
    # trigger_line_enum = enum("CC1", "CC2", "CC3", "CC4", start=0)
    # polarity_enum = enum("Normal", "Inverted", start=0)
    # prescale_enum = enum("119 : 1 us", "1 : 1/119 us", start=0)
    # pack_enum = enum("24", "16", start=0)
    # video_out_enum = enum("Top Down", "Top & Bottom", start=0)
    # baud_rates = enum("9600", "19200", "38400", "57600", "115200", start=0)

    # Signals with RBV
    min_callback_time = ADComponent(EpicsSignalWithRBV, 'MinCallbackTime')
    blocking_callbacks = ADComponent(EpicsSignalWithRBV, 'BlockingCallbacks')
    enable_callbacks = ADComponent(EpicsSignalWithRBV, 'EnableCallbacks')
    dropped_arrays = ADComponent(EpicsSignalWithRBV, 'DroppedArrays')
    nd_array_address = ADComponent(EpicsSignalWithRBV, 'NDArrayAddress')
    queue_size = ADComponent(EpicsSignalWithRBV, 'QueueSize')
    nd_array_port = ADComponent(EpicsSignalWithRBV, 'NDArrayPort', string=True)

    # Signals
    pixel_size = ADComponent(EpicsSignal, 'PixelSize')
    exposure_mode = ADComponent(EpicsSignal, 'ExposureMode')
    test_pattern = ADComponent(EpicsSignal, 'TestPattern')
    trg_polarity = ADComponent(EpicsSignal, 'TrgPolarity')
    queue_use = ADComponent(EpicsSignal, 'QueueUse')
    queue_free_low = ADComponent(EpicsSignal, 'QueueFreeLow')
    queue_use_high = ADComponent(EpicsSignal, 'QueueUseHIGH')
    queue_use_hihi = ADComponent(EpicsSignal, 'QueueUseHIHI')
    num_col = ADComponent(EpicsSignal, 'NumCol')
    num_cycles = ADComponent(EpicsSignal, 'NumCycles')
    num_row = ADComponent(EpicsSignal, 'NumRow')
    num_trains = ADComponent(EpicsSignal, 'NumTrains')
    queue_free = ADComponent(EpicsSignal, 'QueueFree')
    status_word = ADComponent(EpicsSignal, 'StatusWord')
    trg2_frame = ADComponent(EpicsSignal, 'Trg2Frame')
    bl_set = ADComponent(EpicsSignal, 'BL_SET')
    fp_set = ADComponent(EpicsSignal, 'FP_SET')
    full_col = ADComponent(EpicsSignal, 'FullCol')
    full_row = ADComponent(EpicsSignal, 'FullRow')
    ga_set = ADComponent(EpicsSignal, 'GA_SET')
    it_set = ADComponent(EpicsSignal, 'IT_SET')
    ssus = ADComponent(EpicsSignal, 'SSUS')
    skip_col = ADComponent(EpicsSignal, 'SkipCol')
    skip_row = ADComponent(EpicsSignal, 'SkipRow')
    trg_code = ADComponent(EpicsSignal, 'TrgCode')
    trg_delay = ADComponent(EpicsSignal, 'TrgDelay')
    trg_width = ADComponent(EpicsSignal, 'TrgWidth')
    baud = ADComponent(EpicsSignal, 'Baud')
    evr_prescale = ADComponent(EpicsSignal, 'EvrPrescale')
    v_out = ADComponent(EpicsSignal, 'VOut')
    resp = ADComponent(EpicsSignal, 'Resp', string=True)
    cmd = ADComponent(EpicsSignal, 'CMD', string=True)
    cmd_evr = ADComponent(EpicsSignal, 'CmdEVR', string=True)
    cmd_free = ADComponent(EpicsSignal, 'CmdFree', string=True)
    cmd_full = ADComponent(EpicsSignal, 'CmdFull', string=True)
    cmd_init = ADComponent(EpicsSignal, 'CmdInit', string=True)
    cmd_roi = ADComponent(EpicsSignal, 'CmdROI', string=True)
    cmd_t_ptn = ADComponent(EpicsSignal, 'CmdTPtn', string=True)

    # Read Only Signals
    array_data = ADComponent(EpicsSignalRO, 'ArrayData')
    execution_time = ADComponent(EpicsSignalRO, 'ExecutionTime_RBV')
    temp_f = ADComponent(EpicsSignalRO, 'TempF_RBV')
    bl = ADComponent(EpicsSignalRO, 'BL_RBV')
    bits_per_pixel = ADComponent(EpicsSignalRO, 'BitsPerPixel_RBV')
    fp = ADComponent(EpicsSignalRO, 'FP_RBV')
    ga = ADComponent(EpicsSignalRO, 'GA_RBV')
    err = ADComponent(EpicsSignalRO, 'ERR_RBV')
    mid = ADComponent(EpicsSignalRO, 'MID_RBV')
    plugin_type = ADComponent(EpicsSignalRO, 'PluginType_RBV', string=True)
    sdk_version = ADComponent(EpicsSignalRO, 'SDKVersion_RBV', string=True)
    ufdt = ADComponent(EpicsSignalRO, 'UFDT_RBV', string=True)

    # Overridden Components
    # array_rate = Component(Signal)
    array_rate = Component(EpicsSignalRO, 'FrameRate')
    acquire = Component(EpicsSignal, 'Acquire')

    # Attrs that arent in the fee opal
    array_counter = Component(SynSignal)  # C(SignalWithRBV, 'ArrayCounter')
    nd_attributes_file = Component(
        SynSignal)  # C(EpicsSignal, 'NDAttributesFile', string=True)
    pool_alloc_buffers = Component(
        SynSignal)  # C(EpicsSignalRO, 'PoolAllocBuffers')
    pool_free_buffers = Component(
        SynSignal)  # C(EpicsSignalRO, 'PoolFreeBuffers')
    pool_max_buffers = Component(
        SynSignal)  # C(EpicsSignalRO, 'PoolMaxBuffers')
    pool_max_mem = Component(SynSignal)  # C(EpicsSignalRO, 'PoolMaxMem')
    pool_used_buffers = Component(
        SynSignal)  # C(EpicsSignalRO, 'PoolUsedBuffers')
    pool_used_mem = Component(SynSignal)  # C(EpicsSignalRO, 'PoolUsedMem')
    port_name = Component(
        SynSignal)  # C(EpicsSignalRO, 'PortName_RBV', string=True)
    array_callbacks = Component(
        SynSignal)  # C(SignalWithRBV, 'ArrayCallbacks')
    array_size = Component(SynSignal)  # DDC(ad_group(EpicsSignalRO,
    #              (('array_size_x', 'ArraySizeX_RBV'),
    #               ('array_size_y', 'ArraySizeY_RBV'),
    #               ('array_size_z', 'ArraySizeZ_RBV'))),
    #     doc='Size of the array in the XYZ dimensions')
    color_mode = Component(SynSignal)  # C(SignalWithRBV, 'ColorMode')
    data_type = Component(SynSignal)  # C(SignalWithRBV, 'DataType')
    array_size_bytes = Component(
        SynSignal)  # C(EpicsSignalRO, 'ArraySize_RBV')
예제 #8
0
class PCDSDetectorBase(DetectorBase):
    """
    Standard area detector with no plugins.
    """
    cam = ADComponent(cam.CamBase, ":")
예제 #9
0
class PCDSHDF5BlueskyTriggerable(SingleTrigger, PCDSAreaDetectorBase):
    """
    Saves an HDF5 file in a bluesky plan.

    This class takes care of all the standard setup for saving the files
    using the HDF5 plugin for our area detector setups at LCLS during
    bluesky scans, including configuration of the stage signals
    and various site-specific settings.

    You can decide how many images we'll take at each point by setting
    the `num_images_per_point` attribute.

    There are two modes provided: "always aquire" and "aquire at points"
    with key differences in the behavior. You can select which one
    to use using the ``always_acquire`` keyword argument, which
    defaults to True.

    With always_aquire=True (default):
    - Viewers will remain updated throughout the scan, even between
      scan points.
    - The camera will be set to ``acquire`` at ``stage``, if needed, which
      begins taking images. This happens early in the scan.
    - At each point, the ``capture`` feature of the HDF5 plugin will be
      toggled on until we've saved an image count equal to the
      `num_images_per_point` attribute. The counting is handled by the
      plugin.
    - If the camera or server lags during the aquisition, the scan will
      patiently wait for the correct number of images to be saved.
    - There is no guarantee that the images are sequential, there can be
      gaps, but each image that does get saved will be trigger-synchronized.
      (And therefore, beam-synchronized with beam-synchronized triggers).
    - Each point in the scan will have its own associate hdf5 file.
    - If the camera needed to be set to ``acquire`` at ``stage``,
      it will revert to ``stop`` at ``unstage``.

    With always_acquire=False:
    - Viewers will only be updated at the specific scan points.
    - The HDF5 plugin will be set to ``capture`` at stage, and the camera
      will be configured to take a fixed number of images per acquisition
      cycle.
    - At each point, the ``acquire`` bit will be turned on, which causes
      `num_images_per_point` images to be acquired.
    - If the camera or server lags during the acquisition, it will be
      unable to complete it cleanly.
    - There is a guarantee that the images are sequential.
    - All the points in the scan will be grouped into one larger hdf5 file.

    This class can be also be used interactively via the ``save_images``
    function.

    Parameters
    ----------
    prefix : ``str``
        The PV prefix that leads us to this camera's PVs.
    write_path : ``str``
        The directory to drop our hdf5 files into.
    always_acquire : ``bool``, optional
        Determines which mode we use to collect images as described above.
    name : ``str``, keyword-only
        A name to associate with the camera for bluesky.
    """
    hdf51 = ADComponent(HDF5FileStore,
                        'HDF51:',
                        write_path_template='/dev/null',
                        kind='normal',
                        doc='Save output as an HDF5 file')

    def __init__(
        self,
        *args,
        write_path: str,
        always_acquire: bool = True,
        **kwargs,
    ):
        super().__init__(*args, **kwargs)
        self.hutch_name = get_hutch_name()
        self.always_acquire = always_acquire
        self.num_images_per_point = 1
        self.hdf51.write_path_template = write_path
        self.hdf51.stage_sigs['file_template'] = '%s%s_%03d.h5'
        self.hdf51.stage_sigs['file_write_mode'] = 'Stream'
        del self.hdf51.stage_sigs["capture"]
        if always_acquire:
            # This mode is "acquire always, capture on trigger"
            # Override the default to Continuous, always go
            self.stage_sigs['cam.acquire'] = 1
            self.stage_sigs['cam.image_mode'] = 2
            # Make sure we toggle capture for trigger
            self._acquisition_signal = self.hdf51.capture
        else:
            # This mode is "acquire on trigger, capture always"
            # Confirm default of Multiple, start off
            # Redundantly set these here for code clarity
            self.stage_sigs['cam.acquire'] = 0
            self.stage_sigs['cam.image_mode'] = 1
            # If we include capture in stage, it must be last
            self.hdf51.stage_sigs["capture"] = 1
            # Ensure we use the cam acquire as the trigger
            self._acquisition_signal = self.cam.acquire

    def stage(self) -> list[OphydObject]:
        """
        Bluesky interface for setting up the plan.

        This will unpack all of our stage_sigs like normal, but also
        add a small delay to avoid a race condition in the IOC.
        """
        rval = super().stage()
        # It takes a moment for the IOC to be ready sometimes
        time.sleep(0.1)
        return rval

    @property
    def num_images_per_point(self) -> int:
        """
        The number of images to save at each point in the scan.
        """
        if self.always_acquire:
            return self.cam.stage_sigs['num_images']
        return self.hdf51.stage_sigs['num_capture']

    @num_images_per_point.setter
    def num_images_per_point(self, num_images: int):
        if self.always_acquire:
            self.hdf51.stage_sigs['num_capture'] = num_images
            self.cam.stage_sigs['num_images'] = 1
        else:
            self.hdf51.stage_sigs['num_capture'] = 0
            self.cam.stage_sigs['num_images'] = num_images

    def save_images(self) -> None:
        """
        Save images interactively as if we were currently at a scan point.
        """
        self.stage()
        self.trigger().wait()
        self.unstage()
class SpecsDetector(SpecsSingleTrigger, DetectorBase):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.stage_sigs.update({self.cam.safe_state: 0})
        self.stage_sigs.update({self.count_enable: 1})
        self.stage_sigs.update({self.cam.data_type: 9})

        self.count.kind = Kind.hinted

    cam = ADComponent(SpecsDetectorCam, 'cam1:')
    #    hdf1 = ADComponent(SpecsHDF5Plugin,
    #                       name='hdf1',suffix='HDF1:',
    #                       write_path_template='/GPFS/xf23id/xf23id2/data/specs/%Y/%m/%d/',
    # write_path_template='/nsls2/xf23id1/xf23id2/data/specs/%Y/%m/%d/',
    #read_path_template='/nsls2/xf23id1/xf23id2/data/specs/%Y/%m/%d/',
    #write_path_template='X:\xf23id2\data\specs\\%Y\\%m\\%d\\',
    #                       root='/GPFS/xf23id/xf23id2/')
    #root='/nsls2/xf23id1/xf23id2/')

    count = ADComponent(EpicsSignalRO,
                        'Stats5:Total_RBV',
                        kind=Kind.hinted,
                        name='count')
    count_enable = ADComponent(EpicsSignal,
                               'Stats5:EnableCallbacks',
                               kind=Kind.omitted,
                               name='count_enable')
    # I need to find the actual PV for above

    acquisition_mode = None

    def set_mode(self, mode):
        '''This method returns a plan that swaps between 'single_count' mode and 'spectrum' mode.

        This method sets a range of parameters in order to run the detector in either 'single_count'
        mode, where a single value is read at each trigger, and 'spectrum' mode, where a spectrum is
        read at each trigger.

        Parameters
        ----------
        mode : str or SPECSmode enum
            The mode to use for the data acquisition, the options are 'single_point' and 'spectrum'.
        '''

        if type(mode) == str:
            try:
                mode = SPECSmode(mode)
            except ValueError:
                raise ValueError(
                    f'The value provided via `mode` in {self.name}.set_mode does not have'
                    f' the correct value type (should be "single_count", "spectrum", '
                    f'SPECSmode.single_count or SPECSmode.spectrum')
        elif type(mode) is not SPECSmode:
            raise TypeError(
                f'the mode supplied in {self.name}.set_mode is not of type `string` or'
                f' type SPECSmode, set was not performed')

        if mode is SPECSmode.single_count:
            yield from mv(self.cam.acquire_mode, 3)
            #,self.hdf1.enable, 0)
        elif mode == SPECSmode.spectrum:
            yield from mv(self.cam.acquire_mode, 0, self.hdf1.enable, 1)
            self.hdf1.kind = Kind.normal
        else:
            raise ValueError(
                f'The value provided via `mode` in {self.name}.set_mode does not have'
                f' the correct value type (should be "single_count", "spectrum", '
                f'SPECSmode.single_count or SPECSmode.spectrum')
        self.acquisition_mode = mode
class SpecsDetectorCam(CamBase):
    '''This is a class that defines the cam class for a SPECS detector
    '''

    # Controls
    connect = ADComponent(EpicsSignal,
                          'CONNECTED_RBV',
                          write_pv='CONNECT',
                          kind=Kind.omitted,
                          name='connect')
    status_message = ADComponent(EpicsSignalRO,
                                 'StatusMessage_RBV',
                                 string=True,
                                 kind=Kind.omitted,
                                 name='status_message')
    server_name = ADComponent(EpicsSignalRO,
                              'SERVER_NAME_RBV',
                              string=True,
                              kind=Kind.omitted,
                              name='server_name')
    protocol_version = ADComponent(EpicsSignalRO,
                                   'PROTOCOL_VERSION_RBV',
                                   string=True,
                                   kind=Kind.omitted,
                                   name='protocol_version')

    # Energy Controls
    pass_energy = ADComponent(EpicsSignalWithRBV,
                              'PASS_ENERGY',
                              name='pass_energy')
    low_energy = ADComponent(EpicsSignalWithRBV,
                             'LOW_ENERGY',
                             name='low_energy')
    high_energy = ADComponent(EpicsSignalWithRBV,
                              'HIGH_ENERGY',
                              name='high_energy')
    energy_width = ADComponent(EpicsSignalRO,
                               'ENERGY_WIDTH_RBV',
                               name='energy_width')
    kinetic_energy = ADComponent(EpicsSignalWithRBV,
                                 'KINETIC_ENERGY',
                                 name='kinetic_energy')
    retarding_ratio = ADComponent(EpicsSignalWithRBV,
                                  'RETARDING_RATIO',
                                  name='retarding_ratio')
    step_size = ADComponent(EpicsSignalWithRBV, 'STEP_SIZE', name='step_size')
    fat_values = ADComponent(EpicsSignalWithRBV, 'VALUES', name='fat_values')
    samples = ADComponent(EpicsSignalWithRBV, 'SAMPLES', name='samples')
    lens_mode = ADComponent(EpicsSignalWithRBV, 'LENS_MODE', name='lens_mode')

    # Configuration
    scan_range = ADComponent(EpicsSignalWithRBV,
                             'SCAN_RANGE',
                             kind=Kind.config,
                             name='scan_range')
    acquire_mode = ADComponent(EpicsSignalWithRBV,
                               'ACQ_MODE',
                               kind=Kind.config,
                               name='acquire_mode')
    define_spectrum = ADComponent(EpicsSignalWithRBV,
                                  'DEFINE_SPECTRUM',
                                  kind=Kind.config,
                                  name='define_spectrum')
    validate_spectrum = ADComponent(EpicsSignalWithRBV,
                                    'VALIDATE_SPECTRUM',
                                    kind=Kind.config,
                                    name='validate_spectrum')
    safe_state = ADComponent(EpicsSignalWithRBV,
                             'SAFE_STATE',
                             kind=Kind.config,
                             name='safe_state')
    pause_acq = ADComponent(EpicsSignalWithRBV,
                            'PAUSE_RBV',
                            kind=Kind.config,
                            name='pause_acq')

    #Data Progress
    current_point = ADComponent(EpicsSignalRO,
                                'CURRENT_POINT_RBV',
                                kind=Kind.omitted,
                                name='current_point')
    current_channel = ADComponent(EpicsSignalRO,
                                  'CURRENT_CHANNEL_RBV',
                                  kind=Kind.omitted,
                                  name='current_channel')
    region_time_left = ADComponent(EpicsSignalRO,
                                   'REGION_TIME_LEFT_RBV',
                                   kind=Kind.omitted,
                                   name='region_time_left')
    region_progress = ADComponent(EpicsSignalRO,
                                  'REGION_PROGRESS_RBV',
                                  kind=Kind.omitted,
                                  name='region_progress')
    total_time_left = ADComponent(EpicsSignalRO,
                                  'TOTAL_TIME_LEFT_RBV',
                                  kind=Kind.omitted,
                                  name='total_tiem_left')
    progress = ADComponent(EpicsSignalRO,
                           'PROGRESS_RBV',
                           kind=Kind.omitted,
                           name='progress')
    total_points_iteration = ADComponent(EpicsSignalRO,
                                         'TOTAL_POINTS_ITERTION_RBV',
                                         kind=Kind.omitted,
                                         name='total_points_iteration')
    total_points = ADComponent(EpicsSignalRO,
                               'TOTAL_POINTS_RBV',
                               kind=Kind.omitted,
                               name='total_points')
예제 #12
0
class FeeOpalDetector(DetectorBase):
    """
    Opal detector that in the FEE running using Dehong's IOC.
    """
    cam = ADComponent(FeeOpalCam, ":")
예제 #13
0
class PulnixDetector(DetectorBase):
    """
    Standard pulnix detector.
    """
    cam = ADComponent(cam.CamBase, ":")