Beispiel #1
0
class ALBAPilatus(AbstractDetector, HardwareObject):
    """Detector class. Contains all information about detector
       - states are 'OK', and 'BAD'
       - status is busy, exposing, ready, etc.
       - physical property is RH for pilatus, P for rayonix
    """
    def __init__(self, name):
        AbstractDetector.__init__(self)
        HardwareObject.__init__(self, name)

        self.distance_motor_hwobj = None
        self.default_distance = None
        self.default_distance_limits = None

        self.default_latency_time = 0.003

        self.exp_time_limits = None

        self.headers = {}

    def init(self):
        self.distance_motor_hwobj = self.getObjectByRole("distance_motor")
        self.devname = self.getProperty("tangoname")

        try:
            self.latency_time = float(self.getProperty("latency_time"))
        except Exception:
            self.latency_time = None

        if self.latency_time is None:
            logging.getLogger("HWR").debug(
                "Cannot obtain latency time from Pilatus XML. Using %s" %
                self.default_latency_time)
            self.latency_time = self.default_latency_time

        self.devspecific = self.getProperty("device_specific")

        exp_time_limits = self.getProperty("exposure_limits")
        self.exp_time_limits = map(float, exp_time_limits.strip().split(","))

        self.device = DeviceProxy(self.devname)
        self.device_specific = DeviceProxy(self.devspecific)
        self.device.set_timeout_millis(30000)

        self.beamx_chan = self.get_channel_object("beamx")
        self.beamy_chan = self.get_channel_object("beamy")

    def start_acquisition(self):
        self.device.startAcq()

    def stop_acquisition(self):
        self.device.abortAcq()

    def wait_move_distance_done(self):
        self.distance_motor_hwobj.wait_end_of_move()

    def get_threshold(self):
        return self.device_specific.threshold

    def get_threshold_gain(self):
        return self.device_specific.threshold_gain

    def has_shutterless(self):
        """Return True if has shutterless mode"""
        return True

    def get_beam_centre(self):
        """Returns beam center coordinates"""
        beam_x = 0
        beam_y = 0
        try:
            beam_x = self.beamx_chan.getValue()
            beam_y = self.beamy_chan.getValue()
        except Exception:
            pass
        return beam_x, beam_y

    def get_manufacturer(self):
        return self.getProperty("manufacturer")
        return "Dectris"

    def get_model(self):
        return self.getProperty("model")

    def get_detector_type(self):
        return self.getProperty("type")

    def get_default_exposure_time(self):
        return self.getProperty("default_exposure_time")

    def get_minimum_exposure_time(self):
        return self.getProperty("minimum_exposure_time")

    def get_exposure_time_limits(self):
        """Returns exposure time limits as list with two floats"""
        return self.exp_time_limits

    def get_file_suffix(self):
        return self.getProperty("file_suffix")

    def get_pixel_size(self):
        return self.getProperty("px"), self.getProperty("py")

    # methods for data collection
    def set_energy_threshold(self):
        eugap_ch = self.get_channel_object("eugap")

        try:
            currentenergy = eugap_ch.getValue()
        except Exception:
            currentenergy = 12.6

        det_energy = self.get_threshold()

        # threshold = det_energy  / 2.
        # limitenergy = threshold / 0.8

        if round(currentenergy, 6) < 7.538:
            currentenergy = 7.538

        kev_diff = abs(det_energy - currentenergy)

        if kev_diff > 1.2:
            logging.getLogger("HWR").debug(
                "programming energy_threshold on pilatus to: %s" %
                currentenergy)
            # if self.wait_standby():
            # self.device_specific.energy_threshold = currentenergy

    def get_latency_time(self):
        return self.latency_time

    def wait_standby(self, timeout=300):
        t0 = time.time()
        while self.device_specific.cam_state == "STANDBY":
            if time.time() - t0 > timeout:
                print("timeout waiting for Pilatus to be on STANDBY")
                return False
            time.sleep(0.1)
        return True

    def prepare_acquisition(self, dcpars):

        self.set_energy_threshold()
        # self.wait_standby()

        osc_seq = dcpars["oscillation_sequence"][0]
        file_pars = dcpars["fileinfo"]

        basedir = file_pars["directory"]
        prefix = "%s_%s_" % (file_pars["prefix"], file_pars["run_number"])

        first_img_no = osc_seq["start_image_number"]
        nb_frames = osc_seq["number_of_images"]
        exp_time = osc_seq["exposure_time"]

        fileformat = "CBF"
        trig_mode = "EXTERNAL_TRIGGER"
        # latency_time = 0.003

        logging.getLogger("HWR").debug(
            " Preparing detector (dev=%s) for data collection" % self.devname)

        logging.getLogger("HWR").debug("    /saving directory: %s" % basedir)
        logging.getLogger("HWR").debug("    /prefix          : %s" % prefix)
        logging.getLogger("HWR").debug("    /saving_format   : %s" %
                                       fileformat)
        logging.getLogger("HWR").debug("    /trigger_mode    : %s" % trig_mode)
        logging.getLogger("HWR").debug("    /acq_nb_frames   : %s" % nb_frames)
        logging.getLogger("HWR").debug("    /acq_expo_time   : %s" %
                                       str(exp_time - self.latency_time))
        logging.getLogger("HWR").debug("    /latency_time    : %s" %
                                       self.latency_time)

        self.device.write_attribute("saving_mode", "AUTO_FRAME")
        self.device.write_attribute("saving_directory", basedir)
        self.device.write_attribute("saving_prefix", prefix)
        self.device.write_attribute("saving_format", fileformat)

        # set ROI and header in limaserver
        #  TODO

        TrigList = [
            "INTERNAL_TRIGGER",
            "EXTERNAL_TRIGGER",
            "EXTERNAL_TRIGGER_MULTI",
            "EXTERNAL_GATE",
            "EXTERNAL_START_STOP",
        ]

        self.device.write_attribute("acq_trigger_mode", trig_mode)
        self.device.write_attribute("acq_expo_time",
                                    exp_time - self.latency_time)
        self.device.write_attribute("latency_time", self.latency_time)

        return True

    def prepare_collection(self, nb_frames, first_img_no):
        logging.getLogger("HWR").debug(
            "ALBAPilatus. preparing collection. nb_images: %s, first_no: %s" %
            (nb_frames, first_img_no))
        self.device.write_attribute("acq_nb_frames", nb_frames)
        self.device.write_attribute("saving_next_number", first_img_no)
        self.device.prepareAcq()
        return True

    def start_collection(self):
        self.start_acquisition()

    def stop_collection(self):
        self.stop_acquisition()

    def set_image_headers(self, image_headers, angle_info):

        nb_images = image_headers["nb_images"]
        angle_inc = image_headers["Angle_increment"]
        start_angle = image_headers["Start_angle"]

        startangles_list = list()
        ang_start, ang_inc, spacing = angle_info
        for i in range(nb_images):
            startangles_list.append("%0.4f deg." % (ang_start + spacing * i))

        headers = list()
        for i, sa in enumerate(startangles_list):
            header = ("_array_data.header_convention PILATUS_1.2\n"
                      "# Detector: PILATUS 6M, S/N 60-0108, Alba\n"
                      "# %s\n"
                      "# Pixel_size 172e-6 m x 172e-6 m\n"
                      "# Silicon sensor, thickness 0.000320 m\n" %
                      time.strftime("%Y/%b/%d %T"))

            # Acquisition values (headers dictionary) but overwrites start angle
            image_headers["Start_angle"] = sa
            for key, value in image_headers.items():
                if key == "nb_images":
                    continue
                header += "# %s %s\n" % (key, value)
            headers.append("%d : array_data/header_contents|%s;" % (i, header))

        self.device.write_attribute("saving_header_delimiter", ["|", ";", ":"])
        self.device.resetCommonHeader()
        self.device.resetFrameHeaders()
        self.device.setImageHeader(headers)
Beispiel #2
0
class TangoChannel(ChannelObject):
    _tangoEventsQueue = queue.Queue()
    _eventReceivers = {}
    _tangoEventsProcessingTimer = gevent.get_hub().loop. async ()

    # start Tango events processing timer
    _tangoEventsProcessingTimer.start(processTangoEvents)

    def __init__(self,
                 name,
                 attribute_name,
                 tangoname=None,
                 username=None,
                 polling=None,
                 timeout=10000,
                 **kwargs):
        ChannelObject.__init__(self, name, username, **kwargs)

        self.attributeName = attribute_name
        self.deviceName = tangoname
        self.device = None
        self.value = Poller.NotInitializedValue
        self.polling = polling
        self.pollingTimer = None
        self.pollingEvents = False
        self.timeout = int(timeout)
        self.read_as_str = kwargs.get("read_as_str", False)
        self._device_initialized = gevent.event.Event()

        logging.getLogger("HWR").debug(
            "creating Tango attribute %s/%s, polling=%s, timeout=%d",
            self.deviceName, self.attributeName, polling, self.timeout)
        self.init_poller = Poller.poll(
            self.init_device,
            polling_period=3000,
            value_changed_callback=self.continue_init,
            error_callback=self.init_poll_failed,
            start_delay=100)

    def init_poll_failed(self, e, poller_id):
        self._device_initialized.clear()
        logging.warning(
            "%s/%s (%s): could not complete init. (hint: device server is not running, or has to be restarted)",
            self.deviceName, self.attributeName, self.name())
        self.init_poller = self.init_poller.restart(3000)

    def continue_init(self, _):
        self.init_poller.stop()

        if type(self.polling) == int:
            Poller.poll(self.poll,
                        polling_period=self.polling,
                        value_changed_callback=self.update,
                        error_callback=self.pollFailed)
        else:
            if self.polling == "events":
                # try to register event
                try:
                    self.pollingEvents = True
                    #logging.getLogger("HWR").debug("subscribing to CHANGE event for %s", self.attributeName)
                    self.device.subscribe_event(self.attributeName,
                                                PyTango.EventType.CHANGE_EVENT,
                                                self, [], True)
                    #except PyTango.EventSystemFailed:
                    #   pass
                except:
                    logging.getLogger("HWR").exception(
                        "could not subscribe event")
        self._device_initialized.set()

    def init_device(self):
        try:
            self.device = DeviceProxy(self.deviceName)
        except PyTango.DevFailed as traceback:
            self.imported = False
            last_error = traceback[-1]
            logging.getLogger('HWR').error("%s: %s", str(self.name()),
                                           last_error['desc'])
        else:
            self.imported = True
            try:
                self.device.ping()
            except PyTango.ConnectionFailed:
                self.device = None
                raise ConnectionError
            else:
                self.device.set_timeout_millis(self.timeout)

                # check that the attribute exists (to avoid Abort in PyTango grrr)
                if not self.attributeName.lower() in [
                        attr.name.lower()
                        for attr in self.device.attribute_list_query()
                ]:
                    logging.getLogger("HWR").error(
                        "no attribute %s in Tango device %s",
                        self.attributeName, self.deviceName)
                    self.device = None

    def push_event(self, event):
        #logging.getLogger("HWR").debug("%s | attr_value=%s, event.errors=%s, quality=%s", self.name(), event.attr_value, event.errors,event.attr_value is None and "N/A" or event.attr_value.quality)
        if event.attr_value is None or event.err or event.attr_value.quality != PyTango.AttrQuality.ATTR_VALID:
            #logging.getLogger("HWR").debug("%s, receving BAD event... attr_value=%s, event.errors=%s, quality=%s", self.name(), event.attr_value, event.errors, event.attr_value is None and "N/A" or event.attr_value.quality)
            return
        else:
            pass
            #logging.getLogger("HWR").debug("%s, receiving good event", self.name())
        ev = E(event)
        TangoChannel._eventReceivers[id(ev)] = saferef.safe_ref(self.update)
        TangoChannel._tangoEventsQueue.put(ev)
        TangoChannel._tangoEventsProcessingTimer.send()

    def poll(self):
        if self.read_as_str:
            value = self.device.read_attribute(
                self.attributeName,
                PyTango.DeviceAttribute.ExtractAs.String).value
            #value = self.device.read_attribute_as_str(self.attributeName).value
        else:
            value = self.device.read_attribute(self.attributeName).value

        return value

    def pollFailed(self, e, poller_id):
        emit_update = True
        if self.value is None:
            emit_update = False
        else:
            self.value = None

        try:
            self.init_device()
        except:
            pass

        poller = Poller.get_poller(poller_id)
        if poller is not None:
            poller.restart(1000)

        try:
            raise e
        except:
            logging.exception("%s: Exception happened while polling %s",
                              self.name(), self.attributeName)

        if emit_update:
            # emit at the end => can raise exceptions in callbacks
            self.emit('update', None)

    def getInfo(self):
        self._device_initialized.wait(timeout=3)
        return self.device.get_attribute_config(self.attributeName)

    def update(self, value=Poller.NotInitializedValue):
        if value == Poller.NotInitializedValue:
            value = self.getValue()
        if type(value) == tuple:
            value = list(value)

        self.value = value
        self.emit('update', value)

    def getValue(self):
        self._device_initialized.wait(timeout=3)

        if self.read_as_str:
            value = self.device.read_attribute(
                self.attributeName,
                PyTango.DeviceAttribute.ExtractAs.String).value
        else:
            value = self.device.read_attribute(self.attributeName).value

        return value

    def setValue(self, newValue, wait=False):
        self.device.write_attribute(self.attributeName, newValue)
        #attr = PyTango.AttributeProxy(self.deviceName + "/" + self.attributeName)
        #a = attr.read()
        #a.value = newValue
        #attr.write(a)

    def isConnected(self):
        return self.device is not None
Beispiel #3
0
class TangoChannel(ChannelObject):
    _tangoEventsQueue = Queue.Queue()
    _eventReceivers = {}
    _tangoEventsProcessingTimer = gevent.get_hub().loop.async()

    # start Tango events processing timer
    _tangoEventsProcessingTimer.start(processTangoEvents)

    def __init__(
        self,
        name,
        attribute_name,
        tangoname=None,
        username=None,
        polling=None,
        timeout=10000,
        **kwargs
    ):
        ChannelObject.__init__(self, name, username, **kwargs)

        self.attributeName = attribute_name
        self.deviceName = tangoname
        self.device = None
        self.value = Poller.NotInitializedValue
        self.polling = polling
        self.pollingTimer = None
        self.pollingEvents = False
        self.timeout = int(timeout)
        self.read_as_str = kwargs.get("read_as_str", False)
        self._device_initialized = gevent.event.Event()
        logging.getLogger("HWR").debug(
            "creating Tango attribute %s/%s, polling=%s, timeout=%d",
            self.deviceName,
            self.attributeName,
            polling,
            self.timeout,
        )
        self.init_device()
        self.continue_init(None)
        """
        self.init_poller = Poller.poll(self.init_device,
                                       polling_period = 3000,
                                       value_changed_callback = self.continue_init,
                                       error_callback = self.init_poll_failed,
                                       start_delay=100)
        """

    def init_poll_failed(self, e, poller_id):
        self._device_initialized.clear()
        logging.warning(
            "%s/%s (%s): could not complete init. (hint: device server is not running, or has to be restarted)",
            self.deviceName,
            self.attributeName,
            self.name(),
        )
        self.init_poller = self.init_poller.restart(3000)

    def continue_init(self, _):
        # self.init_poller.stop()

        if isinstance(self.polling, types.IntType):
            self.raw_device = RawDeviceProxy(self.deviceName)
            Poller.poll(
                self.poll,
                polling_period=self.polling,
                value_changed_callback=self.update,
                error_callback=self.pollFailed,
            )
        else:
            if self.polling == "events":
                # try to register event
                try:
                    self.pollingEvents = True
                    # logging.getLogger("HWR").debug("subscribing to CHANGE event for %s", self.attributeName)
                    self.device.subscribe_event(
                        self.attributeName,
                        PyTango.EventType.CHANGE_EVENT,
                        self,
                        [],
                        True,
                    )
                    # except PyTango.EventSystemFailed:
                    #   pass
                except BaseException:
                    logging.getLogger("HWR").exception("could not subscribe event")
        self._device_initialized.set()

    def init_device(self):
        try:
            self.device = DeviceProxy(self.deviceName)
        except PyTango.DevFailed as traceback:
            self.imported = False
            last_error = traceback[-1]
            logging.getLogger("HWR").error(
                "%s: %s", str(self.name()), last_error["desc"]
            )
        else:
            self.imported = True
            try:
                self.device.ping()
            except PyTango.ConnectionFailed:
                self.device = None
                raise ConnectionError
            else:
                self.device.set_timeout_millis(self.timeout)

                # check that the attribute exists (to avoid Abort in PyTango grrr)
                if not self.attributeName.lower() in [
                    attr.name.lower() for attr in self.device.attribute_list_query()
                ]:
                    logging.getLogger("HWR").error(
                        "no attribute %s in Tango device %s",
                        self.attributeName,
                        self.deviceName,
                    )
                    self.device = None

    def push_event(self, event):
        # logging.getLogger("HWR").debug("%s | attr_value=%s, event.errors=%s, quality=%s", self.name(), event.attr_value, event.errors,event.attr_value is None and "N/A" or event.attr_value.quality)
        if (
            event.attr_value is None
            or event.err
            or event.attr_value.quality != PyTango.AttrQuality.ATTR_VALID
        ):
            # logging.getLogger("HWR").debug("%s, receving BAD event... attr_value=%s, event.errors=%s, quality=%s", self.name(), event.attr_value, event.errors, event.attr_value is None and "N/A" or event.attr_value.quality)
            return
        else:
            pass
            # logging.getLogger("HWR").debug("%s, receiving good event", self.name())
        ev = E(event)
        TangoChannel._eventReceivers[id(ev)] = saferef.safe_ref(self.update)
        TangoChannel._tangoEventsQueue.put(ev)
        TangoChannel._tangoEventsProcessingTimer.send()

    def poll(self):
        if self.read_as_str:
            value = self.raw_device.read_attribute(
                self.attributeName, PyTango.DeviceAttribute.ExtractAs.String
            ).value
            # value = self.device.read_attribute_as_str(self.attributeName).value
        else:
            value = self.raw_device.read_attribute(self.attributeName).value

        return value

    def pollFailed(self, e, poller_id):
        self.emit("update", None)
        """
        emit_update = True
        if self.value is None:
          emit_update = False
        else:
          self.value = None

        try:
            self.init_device()
        except:
            pass

        poller = Poller.get_poller(poller_id)
        if poller is not None:
            poller.restart(1000)

        try:
          raise e
        except:
          logging.exception("%s: Exception happened while polling %s", self.name(), self.attributeName)

        if emit_update:
          # emit at the end => can raise exceptions in callbacks
          self.emit('update', None)
        """

    def getInfo(self):
        self._device_initialized.wait(timeout=3)
        return self.device.get_attribute_config(self.attributeName)

    def update(self, value=Poller.NotInitializedValue):
        if value == Poller.NotInitializedValue:
            value = self.getValue()
        if isinstance(value, types.TupleType):
            value = list(value)

        self.value = value
        self.emit("update", value)

    def getValue(self):
        self._device_initialized.wait(timeout=3)

        if self.read_as_str:
            value = self.device.read_attribute(
                self.attributeName, PyTango.DeviceAttribute.ExtractAs.String
            ).value
        else:
            value = self.device.read_attribute(self.attributeName).value

        return value

    def setValue(self, newValue):
        self.device.write_attribute(self.attributeName, newValue)
        # attr = PyTango.AttributeProxy(self.deviceName + "/" + self.attributeName)
        # a = attr.read()
        # a.value = newValue
        # attr.write(a)

    def isConnected(self):
        return self.device is not None
Beispiel #4
0
class TangoCommand(CommandObject):
    def __init__(self, name, command, tangoname=None, username=None, **kwargs):
        CommandObject.__init__(self, name, username, **kwargs)

        self.command = command
        self.deviceName = tangoname
        self.device = None

    def init_device(self):
        try:
            self.device = DeviceProxy(self.deviceName)
        except PyTango.DevFailed as traceback:
            last_error = traceback[-1]
            logging.getLogger("HWR").error(
                "%s: %s", str(self.name()), last_error["desc"]
            )
            self.device = None
        else:
            try:
                self.device.ping()
            except PyTango.ConnectionFailed:
                self.device = None
                raise ConnectionError

    def __call__(self, *args, **kwargs):
        self.emit("commandBeginWaitReply", (str(self.name()),))
        if self.device is None:
            # TODO: emit commandFailed
            # beware of infinite recursion with Sample Changer
            # (because of procedure exception cleanup...)
            self.init_device()

        try:
            tangoCmdObject = getattr(self.device, self.command)
            ret = tangoCmdObject(
                *args
            )  # eval('self.device.%s(*%s)' % (self.command, args))
        except PyTango.DevFailed as error_dict:
            logging.getLogger("HWR").error(
                "%s: Tango, %s", str(self.name()), error_dict
            )
        except BaseException:
            logging.getLogger("HWR").exception(
                "%s: an error occured when calling Tango command %s",
                str(self.name()),
                self.command,
            )
        else:
            self.emit("commandReplyArrived", (ret, str(self.name())))
            return ret
        self.emit("commandFailed", (-1, self.name()))

    def abort(self):
        pass

    def setDeviceTimeout(self, timeout):
        if self.device is None:
            self.init_device()
        self.device.set_timeout_millis(timeout)

    def isConnected(self):
        return self.device is not None
class ALBAPilatus(AbstractDetector, HardwareObject):
    """Detector class. Contains all information about detector
       - states are 'OK', and 'BAD'
       - status is busy, exposing, ready, etc.
       - physical property is RH for pilatus, P for rayonix
    """

    def __init__(self, name):
        AbstractDetector.__init__(self)
        HardwareObject.__init__(self, name)

        self.distance_motor_hwobj = None
        self.default_distance = None
        self.default_distance_limits = None

        self.default_latency_time = 0.003

        self.exp_time_limits = None

        self.headers = {}

    def init(self):
        self.distance_motor_hwobj = self.getObjectByRole("distance_motor")
        self.devname = self.getProperty("tangoname")

        try:
            self.latency_time = float(self.getProperty("latency_time"))
        except BaseException:
            self.latency_time = None

        if self.latency_time is None:
            logging.getLogger("HWR").debug(
                "Cannot obtain latency time from Pilatus XML. Using %s"
                % self.default_latency_time
            )
            self.latency_time = self.default_latency_time

        self.devspecific = self.getProperty("device_specific")

        exp_time_limits = self.getProperty("exposure_limits")
        self.exp_time_limits = map(float, exp_time_limits.strip().split(","))

        self.device = DeviceProxy(self.devname)
        self.device_specific = DeviceProxy(self.devspecific)
        self.device.set_timeout_millis(30000)

        self.beamx_chan = self.getChannelObject("beamx")
        self.beamy_chan = self.getChannelObject("beamy")

    def start_acquisition(self):
        self.device.startAcq()

    def stop_acquisition(self):
        self.device.abortAcq()

    def get_distance(self):
        """Returns detector distance in mm"""
        if self.distance_motor_hwobj is not None:
            return float(self.distance_motor_hwobj.getPosition())
        else:
            return self.default_distance

    def move_distance(self, value):
        if self.distance_motor_hwobj is not None:
            self.distance_motor_hwobj.move(value)

    def wait_move_distance_done(self):
        self.distance_motor_hwobj.wait_end_of_move()

    def get_distance_limits(self):
        """Returns detector distance limits"""
        if self.distance_motor_hwobj is not None:
            return self.distance_motor_hwobj.getLimits()
        else:
            return self.default_distance_limits

    def get_threshold(self):
        return self.device_specific.threshold

    def get_threshold_gain(self):
        return self.device_specific.threshold_gain

    def has_shutterless(self):
        """Return True if has shutterless mode"""
        return True

    def get_beam_centre(self):
        """Returns beam center coordinates"""
        beam_x = 0
        beam_y = 0
        try:
            beam_x = self.beamx_chan.getValue()
            beam_y = self.beamy_chan.getValue()
        except BaseException:
            pass
        return beam_x, beam_y

    def get_manufacturer(self):
        return self.getProperty("manufacturer")
        return "Dectris"

    def get_model(self):
        return self.getProperty("model")

    def get_detector_type(self):
        return self.getProperty("type")

    def get_default_exposure_time(self):
        return self.getProperty("default_exposure_time")

    def get_minimum_exposure_time(self):
        return self.getProperty("minimum_exposure_time")

    def get_exposure_time_limits(self):
        """Returns exposure time limits as list with two floats"""
        return self.exp_time_limits

    def get_file_suffix(self):
        return self.getProperty("file_suffix")

    def get_pixel_size(self):
        return self.getProperty("px"), self.getProperty("py")

    # methods for data collection
    def set_energy_threshold(self):
        eugap_ch = self.getChannelObject("eugap")

        try:
            currentenergy = eugap_ch.getValue()
        except BaseException:
            currentenergy = 12.6

        det_energy = self.get_threshold()

        # threshold = det_energy  / 2.
        # limitenergy = threshold / 0.8

        if round(currentenergy, 6) < 7.538:
            currentenergy = 7.538

        kev_diff = abs(det_energy - currentenergy)

        if kev_diff > 1.2:
            logging.getLogger("HWR").debug(
                "programming energy_threshold on pilatus to: %s" % currentenergy
            )
            # if self.wait_standby():
            # self.device_specific.energy_threshold = currentenergy

    def get_latency_time(self):
        return self.latency_time

    def wait_standby(self, timeout=300):
        t0 = time.time()
        while self.device_specific.cam_state == "STANDBY":
            if time.time() - t0 > timeout:
                print("timeout waiting for Pilatus to be on STANDBY")
                return False
            time.sleep(0.1)
        return True

    def prepare_acquisition(self, dcpars):

        self.set_energy_threshold()
        # self.wait_standby()

        osc_seq = dcpars["oscillation_sequence"][0]
        file_pars = dcpars["fileinfo"]

        basedir = file_pars["directory"]
        prefix = "%s_%s_" % (file_pars["prefix"], file_pars["run_number"])

        first_img_no = osc_seq["start_image_number"]
        nb_frames = osc_seq["number_of_images"]
        exp_time = osc_seq["exposure_time"]

        fileformat = "CBF"
        trig_mode = "EXTERNAL_TRIGGER"
        # latency_time = 0.003

        logging.getLogger("HWR").debug(
            " Preparing detector (dev=%s) for data collection" % self.devname
        )

        logging.getLogger("HWR").debug("    /saving directory: %s" % basedir)
        logging.getLogger("HWR").debug("    /prefix          : %s" % prefix)
        logging.getLogger("HWR").debug("    /saving_format   : %s" % fileformat)
        logging.getLogger("HWR").debug("    /trigger_mode    : %s" % trig_mode)
        logging.getLogger("HWR").debug("    /acq_nb_frames   : %s" % nb_frames)
        logging.getLogger("HWR").debug(
            "    /acq_expo_time   : %s" % str(exp_time - self.latency_time)
        )
        logging.getLogger("HWR").debug("    /latency_time    : %s" % self.latency_time)

        self.device.write_attribute("saving_mode", "AUTO_FRAME")
        self.device.write_attribute("saving_directory", basedir)
        self.device.write_attribute("saving_prefix", prefix)
        self.device.write_attribute("saving_format", fileformat)

        # set ROI and header in limaserver
        #  TODO

        TrigList = [
            "INTERNAL_TRIGGER",
            "EXTERNAL_TRIGGER",
            "EXTERNAL_TRIGGER_MULTI",
            "EXTERNAL_GATE",
            "EXTERNAL_START_STOP",
        ]

        self.device.write_attribute("acq_trigger_mode", trig_mode)
        self.device.write_attribute("acq_expo_time", exp_time - self.latency_time)
        self.device.write_attribute("latency_time", self.latency_time)

        return True

    def prepare_collection(self, nb_frames, first_img_no):
        logging.getLogger("HWR").debug(
            "ALBAPilatus. preparing collection. nb_images: %s, first_no: %s"
            % (nb_frames, first_img_no)
        )
        self.device.write_attribute("acq_nb_frames", nb_frames)
        self.device.write_attribute("saving_next_number", first_img_no)
        self.device.prepareAcq()
        return True

    def start_collection(self):
        self.start_acquisition()

    def stop_collection(self):
        self.stop_acquisition()

    def set_image_headers(self, image_headers, angle_info):

        nb_images = image_headers["nb_images"]
        angle_inc = image_headers["Angle_increment"]
        start_angle = image_headers["Start_angle"]

        startangles_list = list()
        ang_start, ang_inc, spacing = angle_info
        for i in range(nb_images):
            startangles_list.append("%0.4f deg." % (ang_start + spacing * i))

        headers = list()
        for i, sa in enumerate(startangles_list):
            header = (
                "_array_data.header_convention PILATUS_1.2\n"
                "# Detector: PILATUS 6M, S/N 60-0108, Alba\n"
                "# %s\n"
                "# Pixel_size 172e-6 m x 172e-6 m\n"
                "# Silicon sensor, thickness 0.000320 m\n"
                % time.strftime("%Y/%b/%d %T")
            )

            # Acquisition values (headers dictionary) but overwrites start angle
            image_headers["Start_angle"] = sa
            for key, value in image_headers.iteritems():
                if key == "nb_images":
                    continue
                header += "# %s %s\n" % (key, value)
            headers.append("%d : array_data/header_contents|%s;" % (i, header))

        self.device.write_attribute("saving_header_delimiter", ["|", ";", ":"])
        self.device.resetCommonHeader()
        self.device.resetFrameHeaders()
        self.device.setImageHeader(headers)