class ForAttrTabata(Device):
    """
    Demonstrate the use of the forwarded attribute
    """

    # PROTECTED REGION ID(ForAttrTabata.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  ForAttrTabata.class_variable

    prepare = attribute(name="prepare", label="prepare", forwarded=True)
    work = attribute(name="work", label="work", forwarded=True)
    rest = attribute(name="rest", label="rest", forwarded=True)
    cycle = attribute(name="cycle", label="cycle", forwarded=True)
    tabata = attribute(name="tabata", label="tabata", forwarded=True)

    # ---------------
    # General methods
    # ---------------

    def init_device(self):
        """Initialises the attributes and properties of the ForAttrTabata."""
        Device.init_device(self)
        # PROTECTED REGION ID(ForAttrTabata.init_device) ENABLED START #
        # PROTECTED REGION END #    //  ForAttrTabata.init_device

    def always_executed_hook(self):
        """Method always executed before any TANGO command is executed."""
        # PROTECTED REGION ID(ForAttrTabata.always_executed_hook) ENABLED START # noqa E501
        # PROTECTED REGION END #    //  ForAttrTabata.always_executed_hook

    def delete_device(self):
        """Hook to delete resources allocated in init_device.
Exemple #2
0
class TempHumid(Device):

    temperature = attribute(name='Temperature',
                            access=AttrWriteType.READ,
                            dtype=float,
                            fget='get_temperature',
                            format='.2f',
                            min_value=-273.15,
                            doc='the measured temperature',
                            unit='C')

    humidity = attribute(name='Humidity',
                         access=AttrWriteType.READ,
                         dtype=float,
                         fget='get_humidity',
                         format='.2f',
                         doc='the measured humidity',
                         unit='%')

    def init_device(self):
        self.info_stream('Trying to connect device to server.')
        try:
            Device.init_device(self)
            self.am2315 = am_driver.AM2315()
            self.set_state(DevState.ON)
            self.temp = 0
            self.humid = 0
            self.info_stream("Connection established.")
        except:
            self.error_stream('Connection could not be established.')

    @DebugIt()
    @command()
    def get_data(self):
        try:
            #_read_data measures both humidity and temperature
            self.am2315._read_data()
            self.temp = self.am2315.temperature
            self.humid = self.am2315.humidity
        except:
            self.error_stream('Data could not be read')

    @InfoIt(show_ret=True)
    def get_temperature(self):
        return self.temp

    @InfoIt(show_ret=True)
    def get_humidity(self):
        return self.humid

    @ErrorIt()
    @command()
    def error_func(self):
        print('You have made an error.')
        return None

    def read_state(self):
        return self.state()
Exemple #3
0
def attr(**kwargs):
    name = kwargs['name'].lower()
    func = ATTR_MAP[name]
    dtype = kwargs.setdefault('dtype', float)

    def get(self):
        value = self.last_values[name]
        if isinstance(value, Exception):
            raise value
        value = self.last_values[name]
        if value is None:
            value = float('nan') if dtype == float else ''
            return value, time.time(), AttrQuality.ATTR_INVALID
        return value

    attr = attribute(get, **kwargs)

    sig = inspect.signature(func)
    if len(sig.parameters) > 1:

        @attr.setter
        def fset(self, value):
            func(self.cryocon, value)

        fset.__name__ = 'write_' + name
        kwargs['fset'] = fset

    return attr
Exemple #4
0
class DeviceMemLeak(Device):

    attr1 = attribute(dtype=tango.CmdArgType.DevEncoded)

    def init_device(self):
        self.info_stream('In Python init_device method')
        self.set_state(tango.DevState.ON)
        self.set_change_event("attr1", True, False)
        self._stopped = False
        self._value = pickle.dumps(dict(index=0, value=1.23))
        self._fmt = "pickle"

    def read_attr1(self):
        return self._fmt, self._value

    @command
    def Start(self):
        self.info_stream('Starting...')
        self._stopped = False
        self._job_thread = JobThread(self)
        self._job_thread.start()

    @command
    def Stop(self):
        self.info_stream('Stopping...')
        self._stopped = True
        self._job_thread.join()
Exemple #5
0
 def initialize_dynamic_attributes(self):
     # TODO: setup polling and event filter
     for d in self.DYN_ATTRS:
         new_attr = attribute(fget=self.read_general,
                              fset=self.write_general,
                              **d)
         self.add_attribute(new_attr)
Exemple #6
0
class Clock(Device):
    @attribute(dtype=float)
    def time(self):
        return time.time()

    gmtime = attribute(dtype=(int, ), max_dim_x=9)

    def read_gmtime(self):
        return time.gmtime()

    @attribute(dtype=Noon)
    def noon(self):
        time_struct = time.gmtime(time.time())
        return Noon.AM if time_struct.tm_hour < 12 else Noon.PM

    @command(dtype_in=float, dtype_out=str)
    def ctime(self, seconds):
        """
        Convert a time in seconds since the Epoch to a string in local time.
        This is equivalent to asctime(localtime(seconds)). When the time tuple
        is not present, current time as returned by localtime() is used.
        """
        return time.ctime(seconds)

    @command(dtype_in=(int, ), dtype_out=float)
    def mktime(self, tupl):
        return time.mktime(tupl)
Exemple #7
0
 def add_dyn_attr_new(self):
     attr = attribute(
         name="dyn_attr",
         dtype=GoodEnum,
         access=AttrWriteType.READ_WRITE,
         fget=self.read,
         fset=self.write)
     self.add_attribute(attr)
Exemple #8
0
class Device2(Device):

    attr1 = attribute()
    attr2 = attribute()

    def init_device(self):
        Device.init_device(self)
        self.set_change_event("attr1", True, False)
        self.set_change_event("attr2", True, False)
        self._attr1 = 0
        self._attr2 = 0

    def read_attr1(self):
        return self._attr1

    def read_attr2(self):
        return self._attr2
Exemple #9
0
 def add_dyn_attr(self):
     attr = attribute(
         name="dyn_attr",
         dtype=dtype,
         max_dim_x=10,
         access=AttrWriteType.READ_WRITE,
         fget=self.read,
         fset=self.write)
     self.add_attribute(attr)
class Worker(Device):
    def init_device(self):
        super(Worker, self).init_device()
        self._is_on = False

    is_on = attribute(
        dtype=tango.DevBoolean,
        access=tango.AttrWriteType.READ_WRITE,
    )

    def read_is_on(self):
        return self._is_on

    def write_is_on(self, value):
        self._is_on = value
Exemple #11
0
class FwdServer(Device):
    """
    Start this server: python FwdServer.py myFwdServer
    Start the server containing the root attribute.
    Then using jive select the Attribute properties from myFwdServer
    Select you forwarded attribute and add the value to __root_att
    e.g. __root_att   ->  x/y/z/root_attribute_name
    Now restart the FwdServer
    """
    def init_device(self):
        Device.init_device(self)
        self._current = 0.0
        self.set_state(tango.DevState.ON)

    voltage = attribute(name="voltage", label='Voltage', forwarded=True)

    @attribute(label='Current', dtype='float')
    def current(self):
        return self._current
Exemple #12
0
class Device2(Device):

    attr2 = attribute()

    def init_device(self):
        self.set_state(tango.DevState.ON)

    def read_attr2(self):
        return create_device_proxy()

    def is_cmd2_allowed(self):
        return self.get_state() == tango.DevState.ON

    @command()
    def cmd2(self):
        self.set_state(tango.DevState.MOVING)

        def job(device):
            with tango.EnsureOmniThread():
                create_device_proxy()
                device.set_state(tango.DevState.ON)

        threading.Thread(target=job, args=(self, )).start()
Exemple #13
0
class Device1(Device):

    attr1 = attribute()

    def init_device(self):
        self.set_state(tango.DevState.ON)

    def read_attr1(self):
        return read_double_scalar()

    def is_cmd1_allowed(self):
        return self.get_state() == tango.DevState.ON

    @command()
    def cmd1(self):
        self.set_state(tango.DevState.MOVING)

        def job(device):
            with tango.EnsureOmniThread():
                read_double_scalar()
                device.set_state(tango.DevState.ON)

        threading.Thread(target=job, args=(self, )).start()
Exemple #14
0
class DeviceEventGenerator(Device):

    attr_with_events = attribute()

    def init_device(self):
        self.set_change_event("attr_with_events", True, False)
        self.set_state(tango.DevState.ON)
        self.emit_events = False
        self.job_thread = None
        self.info_stream("DeviceEventGenerator.init_device")

    def read_attr_with_events(self):
        return 0.0

    def is_Start_allowed(self):
        return self.get_state() == tango.DevState.ON

    @command()
    def Start(self):
        self.emit_events = True
        self.set_state(tango.DevState.MOVING)

        def job(device):
            while device.emit_events:
                self.info_stream("Running job")
                device.push_change_event("attr_with_events", 0.0)
                time.sleep(0.01)

        self.job_thread = threading.Thread(target=job, args=(self, ))
        self.job_thread.start()

    @command()
    def Stop(self):
        self.emit_events = False
        self.job_thread.join()
        self.set_state(tango.DevState.ON)
class CspMasterLeafNode(SKABaseDevice):
    """
    The primary responsibility of the CSP Master Leaf node is to monitor the CSP Master and issue control
    actions during an observation.

    :Device Properties:

        CspMasterFQDN:
            Property to provide FQDN of CSP Master Device

    :Device Attributes:

        cspHealthState:
            Forwarded attribute to provide CSP Master Health State

        activityMessage:
            Attribute to provide activity message

    """
    # -----------------
    # Device Properties
    # -----------------
    CspMasterFQDN = device_property(dtype="str")

    # ----------
    # Attributes
    # ----------

    activityMessage = attribute(
        dtype="str",
        access=AttrWriteType.READ_WRITE,
        doc="Activity Message",
    )

    cspHealthState = attribute(name="cspHealthState",
                               label="cspHealthState",
                               forwarded=True)

    # ---------------
    # General methods
    # ---------------

    class InitCommand(SKABaseDevice.InitCommand):
        """
        A class for the TMC CSP Master Leaf Node's init_device() method.
        """
        def do(self):
            """
            Initializes the attributes and properties of the CspMasterLeafNode.

            :return: A tuple containing a return code and a string message indicating status.
             The message is for information purpose only.

            :rtype: (ResultCode, str)

            :raises: DevFailed if error occurs while creating the device proxy for CSP Master or
                    subscribing the evennts.
            """
            super().do()
            device = self.target
            device.attr_map = {}

            this_device = TangoServerHelper.get_instance()
            this_device.set_tango_class(device)
            this_device.write_attr("activityMessage",
                                   const.STR_CSP_INIT_LEAF_NODE, False)

            ApiUtil.instance().set_asynch_cb_sub_model(
                tango.cb_sub_model.PUSH_CALLBACK)
            log_msg = f"{const.STR_SETTING_CB_MODEL}{ApiUtil.instance().get_asynch_cb_sub_model()}"
            self.logger.debug(log_msg)

            this_device.write_attr("activityMessage", const.STR_INIT_SUCCESS,
                                   False)
            self.logger.info(const.STR_INIT_SUCCESS)
            return (ResultCode.OK, const.STR_INIT_SUCCESS)

    def always_executed_hook(self):
        # PROTECTED REGION ID(CspMasterLeafNode.always_executed_hook) ENABLED START #
        """ Internal construct of TANGO. """
        # PROTECTED REGION END #    //  CspMasterLeafNode.always_executed_hook

    def delete_device(self):
        # PROTECTED REGION ID(CspMasterLeafNode.delete_device) ENABLED START #
        """ Internal construct of TANGO. """
        # PROTECTED REGION END #    //  CspMasterLeafNode.delete_device

    # ------------------
    # Attributes methods
    # ------------------

    def read_activityMessage(self):
        # PROTECTED REGION ID(CspMasterLeafNode.activityMessage_read) ENABLED START #
        """ Internal construct of TANGO. Returns the activityMessage. """
        return self.attr_map["activityMessage"]
        # PROTECTED REGION END #    //  CspMasterLeafNode.activityMessage_read

    def write_activityMessage(self, value):
        # PROTECTED REGION ID(CspMasterLeafNode.activityMessage_write) ENABLED START #
        """Internal construct of TANGO. Sets the activityMessage. """
        self.attr_map["activityMessage"] = value
        # PROTECTED REGION END #    //  CspMasterLeafNode.activityMessage_write

    def is_Standby_allowed(self):
        """
        Checks whether this command is allowed to be run in current device state

        :return: True if this command is allowed to be run in current device state

        :rtype: boolean

        :raises: DevFailed if this command is not allowed to be run in current device state

        """
        handler = self.get_command_object("Standby")
        return handler.check_allowed()

    @command(
        dtype_in=("str", ),
        doc_in=
        "If the array length is 0, the command applies to the whole\nCSP Element.\nIf the array "
        "length is > 1, each array element specifies the FQDN of the\nCSP SubElement to put in "
        "STANDBY mode.",
    )
    @DebugIt()
    def Standby(self, argin):
        """ Sets Standby Mode on the CSP Element. """
        handler = self.get_command_object("Standby")
        handler(argin)

    def init_command_objects(self):
        """
        Initialises the command handlers for commands supported by this device.
        """
        device_data = DeviceData.get_instance()
        super().init_command_objects()
        args = (device_data, self.state_model, self.logger)
        self.register_command_object("Off", Off(*args))
        self.register_command_object("On", On(*args))
        self.register_command_object("Standby", Standby(*args))
class SKACapability(with_metaclass(DeviceMeta, SKAObsDevice)):
    """
    A Subarray handling device. It exposes the instances of configured capabilities.
    """
    # PROTECTED REGION ID(SKACapability.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  SKACapability.class_variable

    # -----------------
    # Device Properties
    # -----------------

    CapType = device_property(dtype='str', )

    CapID = device_property(dtype='str', )

    subID = device_property(dtype='str', )

    # ----------
    # Attributes
    # ----------

    activationTime = attribute(
        dtype='double',
        unit="s",
        standard_unit="s",
        display_unit="s",
        doc="Time of activation in seconds since Unix epoch.",
    )

    configuredInstances = attribute(
        dtype='uint16',
        doc=
        "Number of instances of this Capability Type currently in use on this subarray.",
    )

    usedComponents = attribute(
        dtype=('str', ),
        max_dim_x=100,
        doc=
        "A list of components with no. of instances in use on this Capability.",
    )

    # ---------------
    # General methods
    # ---------------

    def init_device(self):
        SKAObsDevice.init_device(self)
        self._build_state = '{}, {}, {}'.format(release.name, release.version,
                                                release.description)
        self._version_id = release.version
        # PROTECTED REGION ID(SKACapability.init_device) ENABLED START #
        self._activation_time = 0.0
        self._configured_instances = 0
        self._used_components = [""]
        # PROTECTED REGION END #    //  SKACapability.init_device

    def always_executed_hook(self):
        # PROTECTED REGION ID(SKACapability.always_executed_hook) ENABLED START #
        pass
        # PROTECTED REGION END #    //  SKACapability.always_executed_hook

    def delete_device(self):
        # PROTECTED REGION ID(SKACapability.delete_device) ENABLED START #
        pass
        # PROTECTED REGION END #    //  SKACapability.delete_device

    # ------------------
    # Attributes methods
    # ------------------

    def read_activationTime(self):
        # PROTECTED REGION ID(SKACapability.activationTime_read) ENABLED START #
        """
        Reads time of activation since Unix epoch.
        :return: Activation time in seconds
        """
        return self._activation_time
        # PROTECTED REGION END #    //  SKACapability.activationTime_read

    def read_configuredInstances(self):
        # PROTECTED REGION ID(SKACapability.configuredInstances_read) ENABLED START #
        """
        Reads the number of instances of a capability in the subarray
        :return: The number of configured instances of a capability in a subarray
        """
        return self._configured_instances
        # PROTECTED REGION END #    //  SKACapability.configuredInstances_read

    def read_usedComponents(self):
        # PROTECTED REGION ID(SKACapability.usedComponents_read) ENABLED START #
        """
        Reads the list of components with no. of instances in use on this Capability
        :return: The number of components currently in use.
        """
        return self._used_components
        # PROTECTED REGION END #    //  SKACapability.usedComponents_read

    # --------
    # Commands
    # --------

    @command(
        dtype_in='uint16',
        doc_in="The number of instances to configure for this Capability.",
    )
    @DebugIt()
    def ConfigureInstances(self, argin):
        # PROTECTED REGION ID(SKACapability.ConfigureInstances) ENABLED START #
        """
        This function indicates how many number of instances of the current capacity
        should to be configured.
        :param argin: Number of instances to configure
        :return: None.
        """
        self._configured_instances = argin
class SKAMaster(with_metaclass(DeviceMeta, SKABaseDevice)):
    """
    A master test
    """
    # PROTECTED REGION ID(SKAMaster.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  SKAMaster.class_variable

    # -----------------
    # Device Properties
    # -----------------

    # List of maximum number of instances per capability type provided by this Element;
    # CORRELATOR=512, PSS-BEAMS=4, PST-BEAMS=6, VLBI-BEAMS=4  or for DSH it can be:
    # BAND-1=1, BAND-2=1, BAND3=0, BAND-4=0, BAND-5=0 (if only bands 1&amp;2 is installed)
    MaxCapabilities = device_property(dtype=('str', ), )

    # ----------
    # Attributes
    # ----------

    elementLoggerAddress = attribute(
        dtype='str',
        doc="FQDN of Element Logger",
    )

    elementAlarmAddress = attribute(
        dtype='str',
        doc="FQDN of Element Alarm Handlers",
    )

    elementTelStateAddress = attribute(
        dtype='str',
        doc="FQDN of Element TelState device",
    )

    elementDatabaseAddress = attribute(
        dtype='str',
        doc="FQDN of Element Database device",
    )

    maxCapabilities = attribute(
        dtype=('str', ),
        max_dim_x=20,
        doc=
        "Maximum number of instances of each capability type, e.g. 'CORRELATOR:512', 'PSS-BEAMS:4'.",
    )

    availableCapabilities = attribute(
        dtype=('str', ),
        max_dim_x=20,
        doc="A list of available number of instances of each capability type, "
        "e.g. 'CORRELATOR:512', 'PSS-BEAMS:4'.",
    )

    # ---------------
    # General methods
    # ---------------

    def init_device(self):
        SKABaseDevice.init_device(self)
        # PROTECTED REGION ID(SKAMaster.init_device) ENABLED START #
        self._build_state = '{}, {}, {}'.format(release.name, release.version,
                                                release.description)
        self._version_id = release.version
        # Initialize attribute values.
        self._element_logger_address = ""
        self._element_alarm_address = ""
        self._element_tel_state_address = ""
        self._element_database_address = ""
        self._element_alarm_device = ""
        self._element_tel_state_device = ""
        self._element_database_device = ""
        self._max_capabilities = {}
        if self.MaxCapabilities:
            for max_capability in self.MaxCapabilities:
                capability_type, max_capability_instances = max_capability.split(
                    ":")
                self._max_capabilities[capability_type] = int(
                    max_capability_instances)
        self._available_capabilities = self._max_capabilities.copy()
        # PROTECTED REGION END #    //  SKAMaster.init_device

    def always_executed_hook(self):
        # PROTECTED REGION ID(SKAMaster.always_executed_hook) ENABLED START #
        pass
        # PROTECTED REGION END #    //  SKAMaster.always_executed_hook

    def delete_device(self):
        # PROTECTED REGION ID(SKAMaster.delete_device) ENABLED START #
        pass
        # PROTECTED REGION END #    //  SKAMaster.delete_device

    # ------------------
    # Attributes methods
    # ------------------

    def read_elementLoggerAddress(self):
        # PROTECTED REGION ID(SKAMaster.elementLoggerAddress_read) ENABLED START #
        """Reads FQDN of Element Logger device"""
        return self._element_logger_address
        # PROTECTED REGION END #    //  SKAMaster.elementLoggerAddress_read

    def read_elementAlarmAddress(self):
        # PROTECTED REGION ID(SKAMaster.elementAlarmAddress_read) ENABLED START #
        """Reads FQDN of Element Alarm device"""
        return self._element_alarm_address
        # PROTECTED REGION END #    //  SKAMaster.elementAlarmAddress_read

    def read_elementTelStateAddress(self):
        # PROTECTED REGION ID(SKAMaster.elementTelStateAddress_read) ENABLED START #
        """Reads FQDN of Element TelState device"""
        return self._element_tel_state_address
        # PROTECTED REGION END #    //  SKAMaster.elementTelStateAddress_read

    def read_elementDatabaseAddress(self):
        # PROTECTED REGION ID(SKAMaster.elementDatabaseAddress_read) ENABLED START #
        """Reads FQDN of Element Database device"""
        return self._element_database_address
        # PROTECTED REGION END #    //  SKAMaster.elementDatabaseAddress_read

    def read_maxCapabilities(self):
        # PROTECTED REGION ID(SKAMaster.maxCapabilities_read) ENABLED START #
        """Reads maximum number of instances of each capability type"""
        return convert_dict_to_list(self._max_capabilities)
        # PROTECTED REGION END #    //  SKAMaster.maxCapabilities_read

    def read_availableCapabilities(self):
        # PROTECTED REGION ID(SKAMaster.availableCapabilities_read) ENABLED START #
        """Reads list of available number of instances of each capability type"""
        return convert_dict_to_list(self._available_capabilities)
        # PROTECTED REGION END #    //  SKAMaster.availableCapabilities_read

    # --------
    # Commands
    # --------

    @command(
        dtype_in='DevVarLongStringArray',
        doc_in="[nrInstances][Capability types]",
        dtype_out='bool',
    )
    @DebugIt()
    def isCapabilityAchievable(self, argin):
        # PROTECTED REGION ID(SKAMaster.isCapabilityAchievable) ENABLED START #
        """
        Checks of provided capabilities can be achieved by the resource(s).

        :param argin: DevVarLongStringArray.

            An array consisting pair of
                    [nrInstances]: DevLong. Number of instances of the capability.

                    [Capability types]: DevString. Type of capability.

        :return: DevBoolean

            True if capability can be achieved.

            False if cannot.
        """
        command_name = 'isCapabilityAchievable'
        capabilities_instances, capability_types = argin
        validate_input_sizes(command_name, argin)
        validate_capability_types(command_name, capability_types,
                                  list(self._max_capabilities.keys()))

        for capability_type, capability_instances in zip(
                capability_types, capabilities_instances):
            if not self._available_capabilities[
                    capability_type] >= capability_instances:
                return False

        return True
class FspPssSubarray(CspSubElementObsDevice):
    """
    FspPssSubarray TANGO device class for the FspPssSubarray prototype
    """
    # PROTECTED REGION ID(FspPssSubarray.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  FspPssSubarray.class_variable

    # -----------------
    # Device Properties
    # -----------------

    SubID = device_property(dtype='uint16')

    FspID = device_property(dtype='uint16')

    CbfControllerAddress = device_property(
        dtype='str',
        doc="FQDN of CBF Controller",
        default_value="mid_csp_cbf/controller/main")

    # TODO: CbfSubarrayAddress prop not being used
    CbfSubarrayAddress = device_property(dtype='str',
                                         doc="FQDN of CBF Subarray")

    VCC = device_property(dtype=('str', ))

    # ----------
    # Attributes
    # ----------

    receptors = attribute(
        dtype=('uint16', ),
        access=AttrWriteType.READ,
        max_dim_x=197,
        label="Receptors",
        doc="List of receptors assigned to subarray",
    )
    searchBeams = attribute(
        dtype=('str', ),
        access=AttrWriteType.READ,
        max_dim_x=192,
        label="SearchBeams",
        doc="List of searchBeams assigned to fspsubarray",
    )
    searchWindowID = attribute(
        dtype='uint16',
        access=AttrWriteType.READ,
        max_dim_x=2,
        label="ID for 300MHz Search Window",
        doc=
        "Identifier of the Search Window to be used as input for beamforming on this FSP.",
    )

    searchBeamID = attribute(
        dtype=('uint16', ),
        access=AttrWriteType.READ,
        max_dim_x=192,
        label="ID for 300MHz Search Window",
        doc=
        "Identifier of the Search Window to be used as input for beamforming on this FSP.",
    )

    outputEnable = attribute(
        dtype='bool',
        access=AttrWriteType.READ,
        label="Enable Output",
        doc="Enable/disable transmission of output products.",
    )

    # ---------------
    # General methods
    # ---------------

    def init_command_objects(self):
        """
        Sets up the command objects
        """
        super().init_command_objects()

        device_args = (self, self.state_model, self.logger)
        self.register_command_object("ConfigureScan",
                                     self.ConfigureScanCommand(*device_args))
        self.register_command_object("GoToIdle",
                                     self.GoToIdleCommand(*device_args))

    class InitCommand(CspSubElementObsDevice.InitCommand):
        """
        A class for the Vcc's init_device() "command".
        """
        def do(self):
            """
            Stateless hook for device initialisation.

            :return: A tuple containing a return code and a string
                message indicating status. The message is for
                information purpose only.
            :rtype: (ResultCode, str)
            """

            self.logger.debug("Entering InitCommand()")

            device = self.target

            # Make a private copy of the device properties:
            device._subarray_id = device.SubID
            device._fsp_id = device.FspID

            # initialize attribute values
            device._receptors = []
            device._search_beams = []
            device._search_window_id = 0
            device._search_beam_id = []
            device._output_enable = 0
            device._scan_id = 0
            device._config_id = ""

            # device proxy for easy reference to CBF Controller
            device._proxy_cbf_controller = tango.DeviceProxy(
                device.CbfControllerAddress)

            device._controller_max_capabilities = dict(
                pair.split(":")
                for pair in device._proxy_cbf_controller.get_property(
                    "MaxCapabilities")["MaxCapabilities"])
            device._count_vcc = int(device._controller_max_capabilities["VCC"])
            device._fqdn_vcc = list(device.VCC)[:device._count_vcc]
            device._proxies_vcc = [*map(tango.DeviceProxy, device._fqdn_vcc)]

            message = "FspPssSubarry Init command completed OK"
            self.logger.info(message)
            return (ResultCode.OK, message)

        # PROTECTED REGION END #    //  FspPssSubarray.init_device

    def always_executed_hook(self):
        # PROTECTED REGION ID(FspPssSubarray.always_executed_hook) ENABLED START #
        """hook before any commands"""
        pass
        # PROTECTED REGION END #    //  FspPssSubarray.always_executed_hook

    def delete_device(self):
        # PROTECTED REGION ID(FspPssSubarray.delete_device) ENABLED START #
        """Set Idle, remove all receptors, turn device OFF"""
        pass
        # PROTECTED REGION END #    //  FspPssSubarray.delete_device

    # ------------------
    # Attributes methods
    # ------------------

    def read_receptors(self):
        # PROTECTED REGION ID(FspPssSubarray.receptors_read) ENABLED START #
        """return receptros attribute.(array of int)"""
        return self._receptors
        # PROTECTED REGION END #    //  FspPssSubarray.receptors_read

    def read_searchBeams(self):
        # PROTECTED REGION ID(FspPssSubarray.searchBeams_read) ENABLED START #
        """Return searchBeams attribute (JSON)"""
        return self._search_beams
        # PROTECTED REGION END #    //  FspPssSubarray.searchBeams_read

    def read_searchBeamID(self):
        # PROTECTED REGION ID(FspPssSubarray.read_searchBeamID ENABLED START #
        """REturn list of SearchBeam IDs(array of int). (From searchBeams JSON)"""
        return self._search_beam_id
        # PROTECTED REGION END #    //  FspPssSubarray.read_searchBeamID

    def read_searchWindowID(self):
        # PROTECTED REGION ID(CbfSubarrayPssConfig.read_searchWindowID) ENABLED START #
        """Return searchWindowID attribtue(array of int)"""
        return self._search_window_id
        # PROTECTED REGION END #    //  CbfSubarrayPssConfig.read_searchWindowID

    def read_outputEnable(self):
        # PROTECTED REGION ID(CbfSubarrayPssConfig.read_outputEnable) ENABLED START #
        """Enable/Disable transmission of the output products"""
        return self._output_enable
        # PROTECTED REGION END #    //  CbfSubarrayPssConfig.read_outputEnable

    # --------
    # Commands
    # --------

    def _add_receptors(self, receptorIDs):
        """add specified receptors to the FSP subarray. Input is array of int."""
        self.logger.debug("_AddReceptors")
        errs = []  # list of error messages
        receptor_to_vcc = dict(
            [*map(int, pair.split(":"))]
            for pair in self._proxy_cbf_controller.receptorToVcc)
        for receptorID in receptorIDs:
            try:
                vccID = receptor_to_vcc[receptorID]
                subarrayID = self._proxies_vcc[vccID - 1].subarrayMembership

                # only add receptor if it belongs to the CBF subarray
                if subarrayID != self._subarray_id:
                    errs.append(
                        "Receptor {} does not belong to subarray {}.".format(
                            str(receptorID), str(self._subarray_id)))
                else:
                    if receptorID not in self._receptors:
                        self._receptors.append(receptorID)
                    else:
                        # TODO: this is not true if more receptors can be
                        #       specified for the same search beam
                        log_msg = "Receptor {} already assigned to current FSP subarray.".format(
                            str(receptorID))
                        self.logger.warn(log_msg)

            except KeyError:  # invalid receptor ID
                errs.append("Invalid receptor ID: {}".format(receptorID))

        if errs:
            msg = "\n".join(errs)
            self.logger.error(msg)
            tango.Except.throw_exception("Command failed", msg,
                                         "AddReceptors execution",
                                         tango.ErrSeverity.ERR)
        # PROTECTED REGION END #    //  FspPssSubarray.AddReceptors

    def _remove_receptors(self, argin):
        """Remove Receptors. Input is array of int"""
        self.logger.debug("_remove_receptors")
        for receptorID in argin:
            if receptorID in self._receptors:
                self._receptors.remove(receptorID)
            else:
                log_msg = "Receptor {} not assigned to FSP subarray. "\
                    "Skipping.".format(str(receptorID))
                self.logger.warn(log_msg)

    def _remove_all_receptors(self):
        self._remove_receptors(self._receptors[:])

    # --------
    # Commands
    # --------

    class ConfigureScanCommand(CspSubElementObsDevice.ConfigureScanCommand):
        """
        A class for the FspPssSubarray's ConfigureScan() command.
        """
        """Input a serilized JSON object. """
        def do(self, argin):
            """
            Stateless hook for ConfigureScan() command functionality.

            :param argin: The configuration as JSON formatted string
            :type argin: str

            :return: A tuple containing a return code and a string
                message indicating status. The message is for
                information purpose only.
            :rtype: (ResultCode, str)
            :raises: ``CommandError`` if the configuration data validation fails.
            """

            device = self.target

            argin = json.loads(argin)

            # Configure receptors.
            self.logger.debug("_receptors = {}".format(device._receptors))

            device._fsp_id = argin["fsp_id"]
            device._search_window_id = int(argin["search_window_id"])

            self.logger.debug("_search_window_id = {}".format(
                device._search_window_id))

            for searchBeam in argin["search_beam"]:

                if len(searchBeam["receptor_ids"]) != 1:
                    # TODO - to add support for multiple receptors
                    msg = "Currently only 1 receptor per searchBeam is supported"
                    self.logger.error(msg)
                    return (ResultCode.FAILED, msg)

                device._add_receptors(map(int, searchBeam["receptor_ids"]))
                self.logger.debug("device._receptors = {}".format(
                    device._receptors))
                device._search_beams.append(json.dumps(searchBeam))

                device._search_beam_id.append(int(
                    searchBeam["search_beam_id"]))

            # TODO: _output_enable is not currently set

            # TODO - possibly move validation of params to
            #        validate_input()
            # (result_code, msg) = self.validate_input(argin) # TODO

            result_code = ResultCode.OK  # TODO  - temp - remove
            msg = "Configure command completed OK"  # TODO temp, remove

            if result_code == ResultCode.OK:
                # store the configuration on command success
                device._last_scan_configuration = argin
                msg = "Configure command completed OK"

            return (result_code, msg)

        def validate_input(self, argin):
            """
            Validate the configuration parameters against allowed values, as needed.

            :param argin: The JSON formatted string with configuration for the device.
            :type argin: 'DevString'
            :return: A tuple containing a return code and a string message.
            :rtype: (ResultCode, str)
            """
            device = self.target
            return (ResultCode.OK,
                    "ConfigureScan arguments validation successfull")

    @command(
        dtype_in='DevString',
        doc_in="JSON formatted string with the scan configuration.",
        dtype_out='DevVarLongStringArray',
        doc_out=
        "A tuple containing a return code and a string message indicating status. "
        "The message is for information purpose only.",
    )
    @DebugIt()
    def ConfigureScan(self, argin):
        # PROTECTED REGION ID(Vcc.ConfigureScan) ENABLED START #
        """
        Configure the observing device parameters for the current scan.

        :param argin: JSON formatted string with the scan configuration.
        :type argin: 'DevString'

        :return: A tuple containing a return code and a string message indicating status.
            The message is for information purpose only.
        :rtype: (ResultCode, str)
        """
        command = self.get_command_object("ConfigureScan")
        (return_code, message) = command(argin)
        return [[return_code], [message]]

    class GoToIdleCommand(CspSubElementObsDevice.GoToIdleCommand):
        """
        A class for the FspPssSubarray's GoToIdle command.
        """
        def do(self):
            """
            Stateless hook for GoToIdle() command functionality.

            :return: A tuple containing a return code and a string
                message indicating status. The message is for
                information purpose only.
            :rtype: (ResultCode, str)
            """

            self.logger.debug("Entering GoToIdleCommand()")

            device = self.target

            # initialize attribute values
            device._search_beams = []
            device._search_window_id = 0
            device._search_beam_id = []
            device._output_enable = 0
            device._scan_id = 0
            device._config_id = ""

            device._remove_all_receptors()

            if device.state_model.obs_state == ObsState.IDLE:
                return (ResultCode.OK,
                        "GoToIdle command completed OK. Device already IDLE")

            return (ResultCode.OK, "GoToIdle command completed OK")
class  AgilisAGAP(Device):

    Address = device_property(
        dtype='int16',
    )
    Port = device_property(
        dtype='str',
    )

# some Constants
    __AXIS_X = 'U'
    __AXIS_Y = 'V'

# Errors from page 64 of the manual
    __ERROR_NEG_END_OF_RUN = 1
    __ERROR_POS_END_OF_RUN = 2
    __ERROR_OUT_OF_RANGE   = ('G', 'C')

# States from page 65 of the manual
    __STATE_READY   = ('32', '33', '34', '35', '36')
    __STATE_MOVING  = ('28', '29')
    
    position_x = attribute(
        label='Position X',
        dtype='float',
        access=AttrWriteType.READ_WRITE,
        format="%4.3f",
        doc = 'absolute position X'
    )
    position_y = attribute(
        label='Position Y',
        dtype='float',
        access=AttrWriteType.READ_WRITE,
        format="%4.3f",
        doc = 'absolute position Y'
    )

    def init_device(self):
        Device.init_device(self)

        self.set_state(DevState.INIT)
        try:
            self.info_stream("Connecting to AgilisAGAP on port: {:s} ...".format(self.Port))
            self.serial = serial.Serial(
                port = self.Port,
                baudrate = 921600,
                bytesize = 8,
                stopbits = 1,
                parity = 'N',
                xonxoff = True,
                timeout = 0.05)
            if self.serial.isOpen():
                self.serial.close()
            self.serial.open()
            self.info_stream("Success!")
            self.info_stream('Connection established:\n{:s}\n{:s}'.format(self.query('ID?'), self.query('VE?')))
        except:
            self.error_stream("Cannot connect!")
            self.set_state(DevState.OFF)
       
        self.set_state(DevState.ON)        

    def delete_device(self):
        if self.serial.isOpen():
            self.serial.close()
            self.info_stream('Connection closed for port {:s}'.format(self.Port))

    def always_executed_hook(self):
        res = self.query('TS?')
        if (res != ''):
            err = int(res[:4],16)
            state = res[4:]
            if (state in self.__STATE_MOVING):
                self.set_status('Device is MOVING')
                self.set_state(DevState.MOVING)
            elif (state in self.__STATE_READY):
                self.set_status('Device is ON')
                self.set_state(DevState.ON)
            else:
                self.set_status('Device is UNKOWN')
                self.set_state(DevState.UNKNOWN)

    def read_position_x(self):
        return float(self.query('TP' + self.__AXIS_X + '?'))

    def write_position_x(self, value):
        self.query('PA' + self.__AXIS_X + str(value))
        err = self.get_cmd_error_string()
        if err in self.__ERROR_OUT_OF_RANGE:
            Except.throw_exception('x position out of range',
                'x position out of range',
                'write_position_x')
        else:
            self.set_state(DevState.MOVING)  

    def read_position_y(self):
        return float(self.query('TP' + self.__AXIS_Y + '?'))

    def write_position_y(self, value):
        self.query('PA' + self.__AXIS_Y + str(value))
        err = self.get_cmd_error_string()
        if err in self.__ERROR_OUT_OF_RANGE:
            Except.throw_exception('y position out of range',
                'y position out of range',
                'write_position_y')
        else:
            self.set_state(DevState.MOVING)
        
    @command
    def Stop(self):
        self.query('ST')
        
    @command()    
    def Reset(self):
        self.query('RS')

    def query(self, cmd):
        prefix = str(self.Address) + cmd[:-1]
        self.send_cmd(cmd)
        answer = self.serial.readline().decode('utf-8')
        if answer.startswith(prefix):
           answer = answer[len(prefix):].strip()
        else:
           answer = ''
        return answer
    
    def send_cmd(self, cmd):
        cmd = str(self.Address) + cmd + '\r\n'
        self.serial.flushInput()
        self.serial.flushOutput()
        self.serial.write(cmd.encode('utf-8'))
        self.serial.flush()                  

    def get_cmd_error_string(self):
        error = self.query('TE?')
        return error.strip()
Exemple #20
0
class NIUSB6501(Device):

    port3 = attribute(fget='read_port3',
                      fset='write_port3',
                      name='Port_1_3',
                      access=AttrWriteType.READ_WRITE,
                      dtype=bool)

    port4 = attribute(fget='read_port4',
                      fset='write_port4',
                      name='Port_1_4',
                      access=AttrWriteType.READ_WRITE,
                      dtype=bool)

    port5 = attribute(fget='read_port5',
                      fset='write_port5',
                      name='Port_1_5',
                      access=AttrWriteType.READ_WRITE,
                      dtype=bool)

    port6 = attribute(fget='read_port6',
                      fset='write_port6',
                      name='Port_1_6',
                      access=AttrWriteType.READ_WRITE,
                      dtype=bool)

    port7 = attribute(fget='read_port7',
                      fset='write_port7',
                      name='Port_1_7',
                      access=AttrWriteType.READ_WRITE,
                      dtype=bool)

    gatetime = attribute(fget='read_gatetime',
                         fset='write_gatetime',
                         name='Gatetime',
                         access=AttrWriteType.READ_WRITE,
                         dtype=float,
                         min_value=0)

    act_port = attribute(fget='read_act_port',
                         fset='write_act_port',
                         name='ActivePort',
                         access=AttrWriteType.READ_WRITE,
                         dtype=int,
                         min_warning=2,
                         min_value=0,
                         max_value=7)

    frequency = attribute(fget='read_frequency',
                          fset='write_frequency',
                          name='Frequency',
                          access=AttrWriteType.READ_WRITE,
                          dtype=float,
                          min_value=1)

    npulses = attribute(name='npulses',
                        access=AttrWriteType.READ_WRITE,
                        dtype=int,
                        min_value=1)

    def init_device(self):
        self.info_stream('Trying to establish connection')

        try:
            Device.init_device(self)
            self.dev = ni.get_adapter()
            self.set_state(DevState.ON)
            self.dev.set_io_mode(0b00000000, 0b01111111,
                                 0b00000000)  #only ports 1.0-1.7 are writeable
            self.__ports = {3: False, 4: False, 5: False, 6: False, 7: False}
            self.__active = '0b00000000'
            self.dev.write_port(1, int(self.__active, 2))
            self.info_stream('Connection established.')

            self.__gatetime = 1
            self.__act_port = 3
            self.__freq = 1
            self.__npulses = 1
            self.__busy = False

        except:
            if not self.dev:
                self.error_stream('Connection could not be established')
                self.set_state(DevState.FAULT)
            else:
                #Connection already running (info_stream gets called in case
                #the init method is called more than once)
                self.info_stream(
                    'Connection has already been established in a prior run.')

    def read_port3(self):
        return self.__ports[3]

    def write_port3(self, state):
        self.change_port(3, state)

    def read_port4(self):
        return self.__ports[4]

    def write_port4(self, state):
        self.change_port(4, state)

    def read_port5(self):
        return self.__ports[5]

    def write_port5(self, state):
        self.change_port(5, state)

    def read_port6(self):
        return self.__ports[6]

    def write_port6(self, state):
        self.change_port(6, state)

    def read_port7(self):
        return self.__ports[7]

    def write_port7(self, state):
        self.change_port(7, state)

    def read_npulses(self):
        return self.__npulses

    def write_npulses(self, val):
        self.__npulses = val

    def read_gatetime(self):
        return self.__gatetime

    def write_gatetime(self, value):
        self.__gatetime = value

    def read_act_port(self):
        return self.__act_port

    def write_act_port(self, value):
        self.__act_port = value

    def read_frequency(self):
        return self.__freq

    def write_frequency(self, value):
        self.__freq = value

    @DebugIt(show_args=True, show_ret=True)
    def change_active(self, port, state):
        new = -1 - port
        self.__active = list(self.__active)

        if state:
            self.__active[new] = '1'
        if not state:
            self.__active[new] = '0'
        self.__active = ''.join(self.__active)
        bitmap = self.__active
        return bitmap

    @DebugIt()
    def change_port(self, port, state):
        self.change_active(port, state)
        self.dev.write_port(1, int(self.__active, 2))
        self.__ports[port] = state
        self.debug_stream('changed port' + str(port) + ' to ' + str(state))

    #using the gate_timer for longer than 3s command will create a timeout error
    #the command will still be executed as desired, but a warning will be sent
    @DebugIt()
    @command()
    def gate_timer(self):
        start = time.time()
        self.__busy = True
        self.change_port(self.__act_port, True)
        self.info_stream('Port{} active'.format(self.__act_port))
        time.sleep(self.__gatetime)
        self.change_port(self.__act_port, False)
        self.__busy = False
        self.info_stream('Port{} inactive'.format(self.__act_port))
        self.debug_stream('Actual duration of gate: ' +
                          str(time.time() - start))

    @command()
    def train_async(self):
        if not self.__busy:
            t = Thread(target=self.pulsetrain)
            t.daemon = True
            t.start()

    def pulsetrain(self):
        bitmap_on = int(self.change_active(self.__act_port, True), 2)
        bitmap_off = int(self.change_active(self.__act_port, False), 2)
        self.debug_stream(str(bitmap_on))
        self.debug_stream(str(bitmap_off))

        # start = time.time()
        # while time.time() <= start+self.__gatetime:
        #     hits += 1
        #     self.dev.write_port(1,bitmap_on)
        #     time.sleep(1/(self.__freq))
        #     self.dev.write_port(1,bitmap_off)
        #     time.sleep(1/(self.__freq))
        # act_dur = time.time()-start
        self.set_state(DevState.RUNNING)
        self.__busy = True
        t0 = time.time()
        for i in range(self.__npulses):
            self.dev.write_port(1, bitmap_on)
            time.sleep(1 / (2 * self.__freq))
            self.dev.write_port(1, bitmap_off)
            time.sleep(1 / (2 * self.__freq))
        duration = time.time() - t0
        print(f'elapsed: {duration:.2f}', file=self.log_debug)
        self.set_state(DevState.ON)
        self.__busy = False
class TemplateDeviceServer(Device):
    '''
    This docstring should describe your Tango Class and optionally
    what it depends on (drivers etc).
    '''

    # ------ Attributes ------ #

    humidity = attribute(label='Humidity',
                         dtype=float,
                         access=AttrWriteType.READ,
                         doc='Example for an attribute that can only be read.')

    # optionally use fget/fset to point to read and write functions.
    # Default is "read_temperature"/"write_temperature".
    # Added some optional attribute properties.
    temperature = attribute(label='Temperature',
                            fget='get_temperature',
                            dtype=float,
                            access=AttrWriteType.READ_WRITE,
                            display_level=DispLevel.EXPERT,
                            min_value=-273.15,
                            min_alarm=-100,
                            max_alarm=100,
                            min_warning=-50,
                            max_warning=50,
                            unit='C',
                            format="8.4f",
                            doc='Attribute that can be read/written.')

    # ------ Device Properties ------ #
    # device_properties will be set once per family-member and usually -
    # contain serial numbers or a certain port-ID that needs to be set once -
    # and will not change while the server is running.

    port = device_property(dtype=int, default_value=10000)

    # ------ default functions that are inherited from parent "Device" ------ #
    def init_device(self):
        Device.init_device(self)
        self.info_stream('Connection established')  # prints this line while -
        # in logging mode "info" or lower
        self.set_state(DevState.ON)

        # here you could initiate first contact to the hardware (driver)

        self.__temp = 0  # declaring values for the attributes if needed
        self.__humid = 0

    def delete_device(self):
        self.set_state(DevState.OFF)
        self.error_stream('A device was deleted!')  # prints this line while -
        # in logging mode "error" or lower.

    # define what is executed when Tango checks for the state.
    # Here you could inquire the state of the hardware and not just -
    # (as it is in default) of the TDS.
    # Default returns state but also sets state from ON to ALARM if -
    # some attribute alarm limits are surpassed.
    def dev_state(self):
        # possible pseudo code:
        # if hardware-state and TDS-state is ON:
        #   return DevState.ON
        # else:
        #   return DevState.FAULT
        return DevState

    def always_executed_hook(self):
        # a method that is executed continuously and by default does nothing.
        # if you want smth done polled/continuously, put it in this method.
        # check connection to hardware or whether status is acceptable etc.
        pass

# ------ Read/Write functions ------ #

    def read_humidity(self):  # this is default to read humidity
        return self.__humid  # returns the value of the "humidity" attr.

    def get_temperature(self):  # this was set by fget in attribute declaration
        return self.__temp

    def write_temperature(self, value):
        # possibly execute some function here to talk to the hardware -
        # (e.g. set temperature with a thermostat)
        self.__temp = value  # update the declared server value of the attr.

# ------ Internal Methods ------ #
# method that works with multiple input parameters only "inside" this code

    def internal_method(self, param1, param2):
        # do something with param1, param2
        pass

# ------ COMMANDS ------ #

    @DebugIt()  # let the execution of this command be logged in debugging mode
    @command()  # make method executable through the client -
    # (as opposed to just callable inside this code)
    def external_method(self, param):
        # this kind of method only allows one input parameter
        pass

    # more examples of externally executable methods
    @command()
    def turn_off(self):
        self.set_state(DevState.OFF)

    @command()
    def turn_on(self):
        self.set_state(DevState.ON)
Exemple #22
0
class Timer(Device):
    """
    A Timer countdown device composed by
    minutes and seconds.

    **Properties:**

    - Device Property
        minutesCounter
            - device name for the minutes counter
            - Type:'DevString'
        secondsCounter
            - Device name for the seconds counter
            - Type:'DevString'
        sleep_time
            - Sleep time
            - Type:'DevFloat'
    """

    # PROTECTED REGION ID(Timer.class_variable) ENABLED START #
    def event_subscription(self):
        self._dev_factory.get_device(self.secondsCounter).subscribe_event(
            "value",
            tango.EventType.CHANGE_EVENT,
            self.handle_event,
            stateless=True,
        )
        self._dev_factory.get_device(self.minutesCounter).subscribe_event(
            "value",
            tango.EventType.CHANGE_EVENT,
            self.handle_event,
            stateless=True,
        )

    def internal_reset_counters(self):
        with self._lock:
            self._dev_factory.get_device(self.minutesCounter).CounterReset(
                self._start_minutes)
            self._dev_factory.get_device(self.secondsCounter).CounterReset(
                self._start_seconds)

    def step_loop(self):
        with tango.EnsureOmniThread():
            while not self.get_state() == tango.DevState.OFF:
                # import debugpy; debugpy.debug_this_thread()
                with self._lock:
                    device = self._dev_factory.get_device(self.secondsCounter)
                    # self.logger.debug("SECONDS %s", device.value)
                    device.decrement()

                time.sleep(self.sleep_time)

    def handle_event(self, evt):
        if evt.err:
            error = evt.errors[0]
            self.logger.error("%s %s", error.reason, error.desc)
            return

        if evt.device.value <= 0 and (not self.get_state()
                                      == tango.DevState.OFF):
            self.logger.debug("HANDLE EVENT %s %s", evt.device.dev_name(),
                              evt.device.value)

            if evt.device.dev_name() == self.secondsCounter:
                if self.get_state() == DevState.ALARM:
                    with self._lock:
                        self.set_state(DevState.OFF)
                else:
                    device = self._dev_factory.get_device(self.minutesCounter)
                    with self._lock:
                        device.decrement()
                        self._dev_factory.get_device(
                            self.secondsCounter).CounterReset(59)
                    # self.logger.debug("MINUTES %s", device.value)
            else:
                with self._lock:
                    self.set_state(DevState.ALARM)

    def is_Start_allowed(self):
        return self.get_state() == tango.DevState.OFF

    def is_Stop_allowed(self):
        return not self.get_state() == tango.DevState.OFF

    def is_ResetCounters_allowed(self):
        return self.get_state() == tango.DevState.OFF

    # PROTECTED REGION END #    //  Timer.class_variable

    # -----------------
    # Device Properties
    # -----------------

    minutesCounter = device_property(dtype="DevString",
                                     default_value="test/counter/minutes")

    secondsCounter = device_property(dtype="DevString",
                                     default_value="test/counter/seconds")

    sleep_time = device_property(dtype="DevFloat", default_value=1)

    # ----------
    # Attributes
    # ----------

    start_minutes = attribute(
        dtype="DevShort",
        access=AttrWriteType.READ_WRITE,
    )

    start_seconds = attribute(
        dtype="DevShort",
        access=AttrWriteType.READ_WRITE,
    )

    # ---------------
    # General methods
    # ---------------

    def init_device(self):
        """Initialises the attributes and properties of the Timer."""
        Device.init_device(self)
        # PROTECTED REGION ID(Timer.init_device) ENABLED START #
        self.logger = logging.getLogger(__name__)
        self._lock = threading.Lock()
        self._dev_factory = DevFactory()
        self._start_minutes = 0
        self._start_seconds = 0
        self.subscribed = False
        self.set_state(DevState.OFF)
        self.worker_thread = None
        # PROTECTED REGION END #    //  Timer.init_device

    def always_executed_hook(self):
        """Method always executed before any TANGO command is executed."""
        # PROTECTED REGION ID(Timer.always_executed_hook) ENABLED START #
        if not self.subscribed:
            self.event_subscription()
            self.subscribed = True
            self.internal_reset_counters()
        # PROTECTED REGION END #    //  Timer.always_executed_hook

    def delete_device(self):
        """Hook to delete resources allocated in init_device.

        This method allows for any memory or other resources allocated in the
        init_device method to be released.  This method is called by the device
        destructor and by the device Init command.
        """
        # PROTECTED REGION ID(Timer.delete_device) ENABLED START #
        # PROTECTED REGION END #    //  Timer.delete_device

    # ------------------
    # Attributes methods
    # ------------------

    def read_start_minutes(self):
        # PROTECTED REGION ID(Timer.start_minutes_read) ENABLED START #
        """Return the start_minutes attribute."""
        return self._start_minutes
        # PROTECTED REGION END #    //  Timer.start_minutes_read

    def write_start_minutes(self, value):
        # PROTECTED REGION ID(Timer.start_minutes_write) ENABLED START #
        """Set the start_minutes attribute."""
        if value < 1:
            raise Exception("only positive values!")

        self._start_minutes = value
        # PROTECTED REGION END #    //  Timer.start_minutes_write

    def read_start_seconds(self):
        # PROTECTED REGION ID(Timer.start_seconds_read) ENABLED START #
        """Return the start_seconds attribute."""
        return self._start_seconds
        # PROTECTED REGION END #    //  Timer.start_seconds_read

    def write_start_seconds(self, value):
        # PROTECTED REGION ID(Timer.start_seconds_write) ENABLED START #
        """Set the start_seconds attribute."""
        if value < 1:
            raise Exception("only positive values!")

        self._start_seconds = value
        # PROTECTED REGION END #    //  Timer.start_seconds_write

    # --------
    # Commands
    # --------

    @command()
    @DebugIt()
    def ResetCounters(self):
        # PROTECTED REGION ID(Timer.ResetCounters) ENABLED START #
        """
        Reset the counters minutes and seconds

        :return:None
        """
        self.internal_reset_counters()
        # PROTECTED REGION END #    //  Timer.ResetCounters

    @command()
    @DebugIt()
    def Start(self):
        # PROTECTED REGION ID(Timer.Start) ENABLED START #
        """
        Set the device state to ON and start execution

        :return:None
        """
        self.set_state(tango.DevState.RUNNING)
        self.worker_thread = threading.Thread(target=self.step_loop)
        self.worker_thread.start()
        # PROTECTED REGION END #    //  Timer.Start

    @command()
    @DebugIt()
    def Stop(self):
        # PROTECTED REGION ID(Timer.Stop) ENABLED START #
        """
        set the device state to OFF and stop the execution

        :return:None
        """
        self.set_state(DevState.OFF)
        self.worker_thread.join()
Exemple #23
0
class RaspberryPiIO(Device):

    #attributes
    image = attribute(dtype=((int, ), ), max_dim_x=2000, max_dim_y=2000)

    pin3_voltage = attribute(label="PIN_3 voltage",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_3 voltage",
                             fget="get_pin3_voltage",
                             fset="set_pin3_voltage",
                             fisallowed="is_voltage_allowed")

    pin3_output = attribute(label="PIN_3 output",
                            dtype=bool,
                            display_level=DispLevel.OPERATOR,
                            access=AttrWriteType.READ_WRITE,
                            doc="PIN_3 output",
                            fget="get_pin3_output",
                            fset="set_pin3_output",
                            fisallowed="is_output_allowed")

    pin5_voltage = attribute(label="PIN_5 voltage",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_5 voltage",
                             fget="get_pin5_voltage",
                             fset="set_pin5_voltage",
                             fisallowed="is_voltage_allowed")

    pin5_output = attribute(label="PIN_5 output",
                            dtype=bool,
                            display_level=DispLevel.OPERATOR,
                            access=AttrWriteType.READ_WRITE,
                            doc="PIN_5 output",
                            fget="get_pin5_output",
                            fset="set_pin5_output",
                            fisallowed="is_output_allowed")

    pin7_voltage = attribute(label="PIN_7 voltage",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_7 voltage",
                             fget="get_pin7_voltage",
                             fset="set_pin7_voltage",
                             fisallowed="is_voltage_allowed")

    pin7_output = attribute(label="PIN_7 output",
                            dtype=bool,
                            display_level=DispLevel.OPERATOR,
                            access=AttrWriteType.READ_WRITE,
                            doc="PIN_7 output",
                            fget="get_pin7_output",
                            fset="set_pin7_output",
                            fisallowed="is_output_allowed")

    pin8_voltage = attribute(label="PIN_8 voltage",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_8 voltage",
                             fget="get_pin8_voltage",
                             fset="set_pin8_voltage",
                             fisallowed="is_voltage_allowed")

    pin8_output = attribute(label="PIN_8 output",
                            dtype=bool,
                            display_level=DispLevel.OPERATOR,
                            access=AttrWriteType.READ_WRITE,
                            doc="PIN_8 output",
                            fget="get_pin8_output",
                            fset="set_pin8_output",
                            fisallowed="is_output_allowed")

    pin10_voltage = attribute(label="PIN_10 voltage",
                              dtype=bool,
                              display_level=DispLevel.OPERATOR,
                              access=AttrWriteType.READ_WRITE,
                              doc="PIN_10 voltage",
                              fget="get_pin10_voltage",
                              fset="set_pin10_voltage",
                              fisallowed="is_voltage_allowed")

    pin10_output = attribute(label="PIN_10 output",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_10 output",
                             fget="get_pin10_output",
                             fset="set_pin10_output",
                             fisallowed="is_output_allowed")

    pin11_voltage = attribute(label="PIN_11 voltage",
                              dtype=bool,
                              display_level=DispLevel.OPERATOR,
                              access=AttrWriteType.READ_WRITE,
                              doc="PIN_11 voltage",
                              fget="get_pin11_voltage",
                              fset="set_pin11_voltage",
                              fisallowed="is_voltage_allowed")

    pin11_output = attribute(label="PIN_11 output",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_11 output",
                             fget="get_pin11_output",
                             fset="set_pin11_output",
                             fisallowed="is_output_allowed")

    pin12_voltage = attribute(label="PIN_12 voltage",
                              dtype=bool,
                              display_level=DispLevel.OPERATOR,
                              access=AttrWriteType.READ_WRITE,
                              doc="PIN_12 voltage",
                              fget="get_pin12_voltage",
                              fset="set_pin12_voltage",
                              fisallowed="is_voltage_allowed")

    pin12_output = attribute(label="PIN_12 output",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_12 output",
                             fget="get_pin12_output",
                             fset="set_pin12_output",
                             fisallowed="is_output_allowed")

    pin13_voltage = attribute(label="PIN_13 voltage",
                              dtype=bool,
                              display_level=DispLevel.OPERATOR,
                              access=AttrWriteType.READ_WRITE,
                              doc="PIN_13 voltage",
                              fget="get_pin13_voltage",
                              fset="set_pin13_voltage",
                              fisallowed="is_voltage_allowed")

    pin13_output = attribute(label="PIN_13 output",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_13 output",
                             fget="get_pin13_output",
                             fset="set_pin13_output",
                             fisallowed="is_output_allowed")

    pin15_voltage = attribute(label="PIN_15 voltage",
                              dtype=bool,
                              display_level=DispLevel.OPERATOR,
                              access=AttrWriteType.READ_WRITE,
                              doc="PIN_15 voltage",
                              fget="get_pin15_voltage",
                              fset="set_pin15_voltage",
                              fisallowed="is_voltage_allowed")

    pin15_output = attribute(label="PIN_15 output",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_15 output",
                             fget="get_pin15_output",
                             fset="set_pin15_output",
                             fisallowed="is_output_allowed")

    pin16_voltage = attribute(label="PIN_16 voltage",
                              dtype=bool,
                              display_level=DispLevel.OPERATOR,
                              access=AttrWriteType.READ_WRITE,
                              doc="PIN_16 voltage",
                              fget="get_pin16_voltage",
                              fset="set_pin16_voltage",
                              fisallowed="is_voltage_allowed")

    pin16_output = attribute(label="PIN_16 output",
                             dtype=bool,
                             display_level=DispLevel.OPERATOR,
                             access=AttrWriteType.READ_WRITE,
                             doc="PIN_16 output",
                             fget="get_pin16_output",
                             fset="set_pin16_output",
                             fisallowed="is_output_allowed")

    Host = device_property(dtype=str)
    Port = device_property(dtype=int, default_value=9788)

    def init_device(self):
        Device.init_device(self)
        self.raspberry = Raspberry(self.Host)

        #Event flags
        #self.set_change_event('pin3_voltage', True, True)
        #self.set_change_event('pin5_voltage', True, True)
        #self.set_change_event('pin7_voltage', True, True)
        #self.set_change_event('pin8_voltage', True, True)
        #self.set_change_event('pin10_voltage', True, True)
        #self.set_change_event('pin11_voltage', True, True)
        #self.set_change_event('pin12_voltage', True, True)
        #self.set_change_event('pin13_voltage', True, True)
        #self.set_change_event('pin15_voltage', True, True)
        #self.set_change_event('pin16_voltage', True, True)
        #self.set_change_event('pin3_output', True, True)
        #self.set_change_event('pin5_output', True, True)
        #self.set_change_event('pin7_output', True, True)
        #self.set_change_event('pin8_output', True, True)
        #self.set_change_event('pin10_output', True, True)
        #self.set_change_event('pin11_output', True, True)
        #self.set_change_event('pin12_output', True, True)
        #self.set_change_event('pin13_output', True, True)
        #self.set_change_event('pin15_output', True, True)
        #self.set_change_event('pin16_output', True, True)

        #No error decorator for the init function
        try:
            self.raspberry.connect_to_pi()
            url = 'http://' + self.Host + ':5000/stream'
            response = requests.get(url, stream=True)

            self.reader = Reader(response)
            self.frame = self.get_frame()
            self.set_state(DevState.ON)

        except (BrokenPipeError, ConnectionRefusedError, ConnectionError,
                socket.timeout) as connectionerror:
            self.set_state(DevState.FAULT)
            self.debug_stream('Unable to connect to Raspberry Pi TCP/IP' +
                              ' server.')

    def get_frame(self):
        for event in self.reader.events():
            try:
                event = event.strip(b'\r\n\r\n')
                decoded = np.asarray(bytearray(event), dtype=np.uint8)
                decoded = decoded.reshape(480, 640)
                yield decoded
            except Exception as e:
                #               print("Missing frame")
                #               print(e)
                pass

    def read_image(self):
        l = next(self.frame)
        return l

    def delete_device(self):
        self.raspberry.disconnect_from_pi()
        self.raspberry = None

    #Read and write states currently have the same condition
    def is_voltage_allowed(self, request):
        if request == AttReqType.READ_REQ:
            return (self.get_state() == DevState.ON)
        if request == AttReqType.WRITE_REQ:
            return (self.get_state() == DevState.ON)

    def is_output_allowed(self, request):
        return self.get_state() == DevState.ON

    def set_voltage(self, value, pin, output):
        if not output:
            raise ValueError("Pin must be setup as an output first")
        else:
            request = self.raspberry.setvoltage(pin, value)
            if not request:
                raise ValueError("Pin must be setup as an output first")

    #gpio3
    @catch_connection_error
    def get_pin3_voltage(self):
        self.__pin3_voltage = self.raspberry.readvoltage(3)
        return self.__pin3_voltage

    @catch_connection_error
    def set_pin3_voltage(self, value):
        self.set_voltage(value, 3, self.__pin3_output)

    @catch_connection_error
    def get_pin3_output(self):
        self.__pin3_output = self.raspberry.readoutput(3)
        return self.__pin3_output

    @catch_connection_error
    def set_pin3_output(self, value):
        self.raspberry.setoutput(3, value)

    #gpio5
    @catch_connection_error
    def get_pin5_voltage(self):
        self.__pin5_voltage = self.raspberry.readvoltage(5)
        return self.__pin5_voltage

    @catch_connection_error
    def set_pin5_voltage(self, value):
        self.set_voltage(value, 5, self.__pin5_output)

    @catch_connection_error
    def get_pin5_output(self):
        self.__pin5_output = self.raspberry.readoutput(5)
        return self.__pin5_output

    @catch_connection_error
    def set_pin5_output(self, value):
        self.raspberry.setoutput(5, value)

    #gpio7
    @catch_connection_error
    def get_pin7_voltage(self):
        self.__pin7_voltage = self.raspberry.readvoltage(7)
        return self.__pin7_voltage

    @catch_connection_error
    def set_pin7_voltage(self, value):
        self.set_voltage(value, 7, self.__pin7_output)

    @catch_connection_error
    def get_pin7_output(self):
        self.__pin7_output = self.raspberry.readoutput(7)
        return self.__pin7_output

    @catch_connection_error
    def set_pin7_output(self, value):
        self.raspberry.setoutput(7, value)

    #gpio8
    @catch_connection_error
    def get_pin8_voltage(self):
        self.__pin8_voltage = self.raspberry.readvoltage(8)
        return self.__pin8_voltage

    @catch_connection_error
    def set_pin8_voltage(self, value):
        self.set_voltage(value, 8, self.__pin8_output)

    @catch_connection_error
    def get_pin8_output(self):
        self.__pin8_output = self.raspberry.readoutput(8)
        return self.__pin8_output

    @catch_connection_error
    def set_pin8_output(self, value):
        self.raspberry.setoutput(8, value)

    #gpio10
    @catch_connection_error
    def get_pin10_voltage(self):
        self.__pin10_voltage = self.raspberry.readvoltage(10)
        return self.__pin10_voltage

    @catch_connection_error
    def set_pin10_voltage(self, value):
        self.set_voltage(value, 10, self.__pin10_output)

    @catch_connection_error
    def get_pin10_output(self):
        self.__pin10_output = self.raspberry.readoutput(10)
        return self.__pin10_output

    @catch_connection_error
    def set_pin10_output(self, value):
        self.raspberry.setoutput(10, value)

    #gpio11
    @catch_connection_error
    def get_pin11_voltage(self):
        self.__pin11_voltage = self.raspberry.readvoltage(11)
        return self.__pin11_voltage

    @catch_connection_error
    def set_pin11_voltage(self, value):
        self.set_voltage(value, 11, self.__pin11_output)

    @catch_connection_error
    def get_pin11_output(self):
        self.__pin11_output = self.raspberry.readoutput(11)
        return self.__pin11_output

    @catch_connection_error
    def set_pin11_output(self, value):
        self.raspberry.setoutput(11, value)

    #gpio12
    @catch_connection_error
    def get_pin12_voltage(self):
        self.__pin12_voltage = self.raspberry.readvoltage(12)
        return self.__pin12_voltage

    @catch_connection_error
    def set_pin12_voltage(self, value):
        self.set_voltage(value, 12, self.__pin12_output)

    @catch_connection_error
    def get_pin12_output(self):
        self.__pin12_output = self.raspberry.readoutput(12)
        return self.__pin12_output

    @catch_connection_error
    def set_pin12_output(self, value):
        self.raspberry.setoutput(12, value)

    #gpio13
    @catch_connection_error
    def get_pin13_voltage(self):
        self.__pin13_voltage = self.raspberry.readvoltage(13)
        return self.__pin13_voltage

    @catch_connection_error
    def set_pin13_voltage(self, value):
        self.set_voltage(value, 13, self.__pin13_output)

    @catch_connection_error
    def get_pin13_output(self):
        self.__pin13_output = self.raspberry.readoutput(13)
        return self.__pin13_output

    @catch_connection_error
    def set_pin13_output(self, value):
        self.raspberry.setoutput(13, value)

    #gpio15
    @catch_connection_error
    def get_pin15_voltage(self):
        self.__pin15_voltage = self.raspberry.readvoltage(15)
        return self.__pin15_voltage

    @catch_connection_error
    def set_pin15_voltage(self, value):
        self.set_voltage(value, 15, self.__pin15_output)

    @catch_connection_error
    def get_pin15_output(self):
        self.__pin15_output = self.raspberry.readoutput(15)
        return self.__pin15_output

    @catch_connection_error
    def set_pin15_output(self, value):
        self.raspberry.setoutput(15, value)

    #gpio16
    @catch_connection_error
    def get_pin16_voltage(self):
        self.__pin16_voltage = self.raspberry.readvoltage(16)
        return self.__pin16_voltage

    @catch_connection_error
    def set_pin16_voltage(self, value):
        self.set_voltage(value, 16, self.__pin16_output)

    @catch_connection_error
    def get_pin16_output(self):
        self.__pin16_output = self.raspberry.readoutput(16)
        return self.__pin16_output

    @catch_connection_error
    def set_pin16_output(self, value):
        self.raspberry.setoutput(16, value)

    #End of gpio's

    def is_TurnOff_allowed(self):
        return self.get_state() == DevState.ON

    @command
    def TurnOff(self):
        self.raspberry.turnoff()
        self.set_state(DevState.OFF)

    def is_ResetAll_allowed(self):
        return self.get_state() == DevState.ON

    @command
    def ResetAll(self):
        self.raspberry.resetall()
Exemple #24
0
class PowerSupply(Device):
    """
    Example power supply device from the PyTango documentation.
    """

    # green_mode = GreenMode.Asyncio

    voltage = attribute(
        label="Voltage",
        dtype=float,
        display_level=DispLevel.OPERATOR,
        access=AttrWriteType.READ,
        unit="V",
        format="8.4f",
        doc="the power supply voltage",
    )

    current = attribute(
        label="Current",
        dtype=float,
        display_level=DispLevel.EXPERT,
        access=AttrWriteType.READ_WRITE,
        unit="A",
        format="8.4f",
        min_value=0.0,
        max_value=8.5,
        min_alarm=0.1,
        max_alarm=8.4,
        min_warning=0.5,
        max_warning=8.0,
        fget="get_current",
        fset="set_current",
        doc="the power supply current",
    )

    noise = attribute(label="Noise",
                      dtype=((int, ), ),
                      max_dim_x=1024,
                      max_dim_y=1024)

    host = device_property(dtype=str)
    port = device_property(dtype=int, default_value=9788)

    def __init__(self, device_class, device_name):
        super().__init__(device_class, device_name)
        self.__current = 0.0

    def init_device(self):
        """Initialise device"""
        Device.init_device(self)
        self.set_current(0.0)
        self.set_state(DevState.STANDBY)

    def read_voltage(self):
        """Read voltage"""
        self.info_stream("read_voltage(%s, %d)", self.host, self.port)
        return 240, time.time(), AttrQuality.ATTR_VALID

    def get_current(self):
        """Get the current"""
        return self.__current

    def set_current(self, current):
        """Set the current"""
        self.__current = current

    def read_info(self):
        """Get device information"""
        return "Information", dict(manufacturer="Tango",
                                   model="PS2000",
                                   version_number=123)

    @DebugIt()
    def read_noise(self):
        """Get a matrix of random noise"""
        return numpy.random.random_integers(1000, size=(100, 100))

    @command
    def turn_on(self):
        """Turn the device on"""
        # turn on the actual power supply here
        self.set_state(DevState.ON)

    @command
    def turn_off(self):
        """Turn the device off"""
        # turn off the actual power supply here
        self.set_state(DevState.OFF)

    @command(
        dtype_in=float,
        doc_in="Ramp target current",
        dtype_out=bool,
        doc_out="True if ramping went well, "
        "False otherwise",
    )
    def ramp(self, target_current):
        """Ramp voltage to the target current"""
        # should do the ramping. This doesn't.
        self.set_current(target_current)
        return True
Exemple #25
0
class ADAM6224(Device):
    """ ADAM6224
It is a definition of a class used to control ADAM-6224 controller via
Modbus TCP.
Device contains 4-ch Isolated Analog Output and 4-ch Digital Input.
For each AO there are associated attributes:

 * AnalogOutput(double) - contains present output value of the channel (V or
    mA), it is adjustable
 * SafetyValue(double)  - contains present safety value of the channel (V or
    mA), it is adjustable
 * StartupValue(double)  - contains present startup value of the channel (V
    or mA), it is adjustable
 * Status(string)  - contains present status of the channel, available:
    Fail to provide AO Value, No Output Current, Zero/Span Calibration Error,
    DI triggered to Safety Value, DI triggered to Startup Value,
    AO triggered to Fail Safety Value
 * CodeType(string) - contains present type of output of the channel,
    available:  0-20mA, 4-20mA, 0-10V, 0-5V, +-10V, +-5V

For each DI there are associated attributes:

 * DigitalInput(bool) - contains present input value of the channel
 * EventStatus(string) - contains present status of the channel, available:
    Unreliable DI value (UART Timeout), Safety Value triggered,
     Startup Value triggered

"""
    __metaclass__ = DeviceMeta
    connected_ADAM = 0.0
    digital_input_values = [False, False, False, False]
    digital_input_events = [0, 0, 0, 0]
    analog_output_values = [0, 0, 0, 0]
    analog_output_statuses = [0, 0, 0, 0, 0, 0, 0, 0]
    analog_output_types = [0, 0, 0, 0]
    analog_output_startup_values = [0, 0, 0, 0]
    analog_output_safety_values = [0, 0, 0, 0]
    type_to_code_dict = {
        '0-20mA': int("0182", 16),
        '4-20mA': int("0180", 16),
        '0-10V': int("0148", 16),
        '0-5V': int("0147", 16),
        '+-10V': int("0143", 16),
        '+-5V': int("0142", 16)
    }
    code_to_type_dict = {v: k for k, v in type_to_code_dict.iteritems()}

    event_status_dictionary = {
        int(1): 'Unreliable DI value (UART Timeout)',
        int(2): 'Safety Value triggered',
        int(4): 'Startup Value triggered',
        int(0): ' '
    }

    status_dict_1 = {
        int(1): 'Fail to provide AO Value',
        int(8): 'No Output Current',
        int(512): 'Zero/Span Calibration Error',
        int(0): ' '
    }

    status_dict_2 = {
        int(1): 'DI triggered to Safety Value',
        int(2): 'DI triggered to Startup Value',
        int(4): 'AO triggered to Fail Safety Value',
        int(0): ' '
    }

    # ----------------
    # Class Properties
    # ----------------

    # -----------------
    # Device Properties
    # -----------------

    DeviceAddress = device_property(dtype='str',
                                    default_value="192.168.120.55",
                                    doc="An IP address of device")

    # ------------------
    # Attributes methods
    # ------------------

    # --------------------
    # DigitalInput method
    # --------------------

    def read_DigitalInput(self, channel):
        return self.digital_input_values[channel]

    # --------------------
    # EventStatus method
    # --------------------

    def read_EventStatus(self, channel):
        return self.event_status_dictionary[self.digital_input_events[channel]]

    # --------------------
    # Status method
    # --------------------

    def read_Status(self, channel):
        reg = 2 * channel
        return self.status_dict_1[self.analog_output_statuses[reg]] + \
               ' ' + \
               self.status_dict_2[self.analog_output_statuses[reg + 1]]

    # --------------------
    # AnalogOutput method
    # --------------------

    def read_AnalogOutput(self, channel):
        return self.encode_value(self.analog_output_values[channel], channel)

    def write_AnalogOutput(self, channel, value):
        self.connected_ADAM.write_register(
            channel, self.decode_value(value, channel, 0))

    # --------------------
    # SafetyValue method
    # --------------------

    def read_SafetyValue(self, channel):
        return self.encode_value(self.analog_output_safety_values[channel],
                                 channel)

    def write_SafetyValue(self, value, channel):
        reg = 410 + channel
        self.connected_ADAM.write_register(
            reg, self.decode_value(value, channel, 1))

    # --------------------
    # StartupValue method
    # --------------------

    def read_StartupValue(self, channel):
        return self.encode_value(self.analog_output_startup_values[channel],
                                 channel)

    def write_StartupValue(self, value, channel):
        reg = 400 + channel
        self.connected_ADAM.write_register(
            reg, self.decode_value(value, channel, 2))

    # --------------------
    # TypeCode method
    # --------------------

    def read_TypeCode(self, channel):
        return self.decode_type_code(channel)

    def write_TypeCode(self, value, channel):
        reg = 200 + channel
        self.connected_ADAM.write_register(reg, self.encode_type_code(value))

    # ----------
    # Attributes
    # ----------

    DigitalInput_0 = attribute(dtype='bool',
                               access=AttrWriteType.READ,
                               doc="Bool value at channel 0 of Digital Input")

    DigitalInput_1 = attribute(dtype='bool',
                               access=AttrWriteType.READ,
                               doc="Bool value at channel 1 of Digital Input")

    DigitalInput_2 = attribute(dtype='bool',
                               access=AttrWriteType.READ,
                               doc="Bool value at channel 2 of Digital Input")

    DigitalInput_3 = attribute(dtype='bool',
                               access=AttrWriteType.READ,
                               doc="Bool value at channel 3 of Digital Input")

    AnalogOutput_0 = attribute(dtype=float,
                               access=AttrWriteType.READ_WRITE,
                               format='%2.4f',
                               doc="Value at channel 0 of Analog Output")

    AnalogOutput_1 = attribute(dtype=float,
                               access=AttrWriteType.READ_WRITE,
                               format='%2.4f',
                               doc="Value at channel 1 of Analog Output")

    AnalogOutput_2 = attribute(dtype=float,
                               access=AttrWriteType.READ_WRITE,
                               format='%2.4f',
                               doc="Value at channel 2 of Analog Output")

    AnalogOutput_3 = attribute(dtype=float,
                               access=AttrWriteType.READ_WRITE,
                               format='%2.4f',
                               doc="Value at channel 3 of Analog Output")

    SafetyValue_0 = attribute(dtype=float,
                              access=AttrWriteType.READ_WRITE,
                              format='%2.4f',
                              doc="Safety Value of channel 0 of Analog Output")

    SafetyValue_1 = attribute(dtype=float,
                              access=AttrWriteType.READ_WRITE,
                              format='%2.4f',
                              doc="Safety Value of channel 1 of Analog Output")

    SafetyValue_2 = attribute(dtype=float,
                              access=AttrWriteType.READ_WRITE,
                              format='%2.4f',
                              doc="Safety Value of channel 2 of Analog Output")

    SafetyValue_3 = attribute(dtype=float,
                              access=AttrWriteType.READ_WRITE,
                              format='%2.4f',
                              doc="Safety Value of channel 3 of Analog Output")

    StartupValue_0 = attribute(
        dtype=float,
        access=AttrWriteType.READ_WRITE,
        format='%2.4f',
        doc="Startup Value of channel 0 of Analog Output")

    StartupValue_1 = attribute(
        dtype=float,
        access=AttrWriteType.READ_WRITE,
        format='%2.4f',
        doc="Startup Value of channel 1 of Analog Output")

    StartupValue_2 = attribute(
        dtype=float,
        access=AttrWriteType.READ_WRITE,
        format='%2.4f',
        doc="Startup Value of channel 2 of Analog Output")

    StartupValue_3 = attribute(
        dtype=float,
        access=AttrWriteType.READ_WRITE,
        format='%2.4f',
        doc="Startup Value of channel 3 of Analog Output")

    TypeCode_0 = attribute(dtype='str',
                           access=AttrWriteType.READ_WRITE,
                           doc="Type of output at channel 0 of Analog Output")

    TypeCode_1 = attribute(dtype='str',
                           access=AttrWriteType.READ_WRITE,
                           doc="Type of output at channel 1 of Analog Output")

    TypeCode_2 = attribute(dtype='str',
                           access=AttrWriteType.READ_WRITE,
                           doc="Type of output at channel 2 of Analog Output")

    TypeCode_3 = attribute(dtype='str',
                           access=AttrWriteType.READ_WRITE,
                           doc="Type of output at channel 3 of Analog Output")

    Status_0 = attribute(dtype='str',
                         access=AttrWriteType.READ,
                         doc="Status of channel 0 of Analog Output")

    Status_1 = attribute(dtype='str',
                         access=AttrWriteType.READ,
                         doc="Status of channel 1 of Analog Output")

    Status_2 = attribute(dtype='str',
                         access=AttrWriteType.READ,
                         doc="Status of channel 2 of Analog Output")

    Status_3 = attribute(dtype='str',
                         access=AttrWriteType.READ,
                         doc="Status of channel 3 of Analog Output")

    EventStatus_0 = attribute(dtype='str',
                              access=AttrWriteType.READ,
                              doc="Event Status of channel 0 of Digital Input")

    EventStatus_1 = attribute(dtype='str',
                              access=AttrWriteType.READ,
                              doc="Event Status of channel 1 of Digital Input")

    EventStatus_2 = attribute(dtype='str',
                              access=AttrWriteType.READ,
                              doc="Event Status of channel 2 of Digital Input")

    EventStatus_3 = attribute(dtype='str',
                              access=AttrWriteType.READ,
                              doc="Event Status of channel 3 of Digital Input")

    # ---------------
    # General methods
    # ---------------

    def init_device(self):
        """Initialise device and sets its state to STANDBY"""
        Device.init_device(self)
        self.set_state(DevState.STANDBY)
        self.set_status("ADAM-6224 in state STANDBY, ready to connect to "
                        "device")

    def delete_device(self):
        """Disconnect from physical device before deleting instance"""
        self.connected_ADAM.close()

    @command
    @DebugIt()
    def disconnect(self):
        """Disconnect from device and sets state to STANDBY """
        self.connected_ADAM.close()
        self.set_state(DevState.STANDBY)
        self.set_status(
            "Device disconnected form ADAM-6224, set state to STANDBY, "
            "ready to connect to device again")

    # --------------------
    # AnalogOutput methods
    # --------------------

    def read_AnalogOutput_0(self):
        return self.read_AnalogOutput(0)

    def write_AnalogOutput_0(self, value):
        return self.write_AnalogOutput(0, value)

    def read_AnalogOutput_1(self):
        return self.read_AnalogOutput(1)

    def write_AnalogOutput_1(self, value):
        return self.write_AnalogOutput(1, value)

    def read_AnalogOutput_2(self):
        return self.read_AnalogOutput(2)

    def write_AnalogOutput_2(self, value):
        return self.write_AnalogOutput(2, value)

    def read_AnalogOutput_3(self):
        return self.read_AnalogOutput(3)

    def write_AnalogOutput_3(self, value):
        return self.write_AnalogOutput(3, value)

    def read_AnalogOutput_4(self):
        return self.read_AnalogOutput(4)

    def write_AnalogOutput_4(self, value):
        return self.write_AnalogOutput(4, value)

    def read_AnalogOutput_5(self):
        return self.read_AnalogOutput(5)

    def write_AnalogOutput_5(self, value):
        return self.write_AnalogOutput(5, value)

    def read_AnalogOutput_6(self):
        return self.read_AnalogOutput(6)

    def write_AnalogOutput_6(self, value):
        return self.write_AnalogOutput(6, value)

    def read_AnalogOutput_7(self):
        return self.read_AnalogOutput(7)

    def write_AnalogOutput_7(self, value):
        return self.write_AnalogOutput(7, value)

    # --------------------
    # SafetyValue methods
    # --------------------

    def read_SafetyValue_0(self):
        return self.read_SafetyValue(0)

    def write_SafetyValue_0(self, value):
        self.write_SafetyValue(0, value)

    def read_SafetyValue_1(self):
        return self.read_SafetyValue(1)

    def write_SafetyValue_1(self, value):
        self.write_SafetyValue(1, value)

    def read_SafetyValue_2(self):
        return self.read_SafetyValue(2)

    def write_SafetyValue_2(self, value):
        self.write_SafetyValue(2, value)

    def read_SafetyValue_3(self):
        return self.read_SafetyValue(3)

    def write_SafetyValue_3(self, value):
        self.write_SafetyValue(3, value)

    def read_SafetyValue_4(self):
        return self.read_SafetyValue(4)

    def write_SafetyValue_4(self, value):
        self.write_SafetyValue(4, value)

    def read_SafetyValue_5(self):
        return self.read_SafetyValue(5)

    def write_SafetyValue_5(self, value):
        self.write_SafetyValue(5, value)

    def read_SafetyValue_6(self):
        return self.read_SafetyValue(6)

    def write_SafetyValue_6(self, value):
        self.write_SafetyValue(6, value)

    def read_SafetyValue_7(self):
        return self.read_SafetyValue(7)

    def write_SafetyValue_7(self, value):
        self.write_SafetyValue(7, value)

    # --------------------
    # StartupValue methods
    # --------------------

    def read_StartupValue_0(self):
        return self.read_StartupValue(0)

    def write_StartupValue_0(self, value):
        self.write_StartupValue(0, value)

    def read_StartupValue_1(self):
        return self.read_StartupValue(1)

    def write_StartupValue_1(self, value):
        self.write_StartupValue(1, value)

    def read_StartupValue_2(self):
        return self.read_StartupValue(2)

    def write_StartupValue_2(self, value):
        self.write_StartupValue(2, value)

    def read_StartupValue_3(self):
        return self.read_StartupValue(3)

    def write_StartupValue_3(self, value):
        self.write_StartupValue(3, value)

    def read_StartupValue_4(self):
        return self.read_StartupValue(4)

    def write_StartupValue_4(self, value):
        self.write_StartupValue(4, value)

    def read_StartupValue_5(self):
        return self.read_StartupValue(5)

    def write_StartupValue_5(self, value):
        self.write_StartupValue(5, value)

    def read_StartupValue_6(self):
        return self.read_StartupValue(6)

    def write_StartupValue_6(self, value):
        self.write_StartupValue(6, value)

    def read_StartupValue_7(self):
        return self.read_StartupValue(7)

    def write_StartupValue_7(self, value):
        self.write_StartupValue(7, value)

    # --------------------
    # TypeCode methods
    # --------------------

    def read_TypeCode_0(self):
        return self.read_TypeCode(0)

    def write_TypeCode_0(self, value):
        self.write_TypeCode(0, value)

    def read_TypeCode_1(self):
        return self.read_TypeCode(1)

    def write_TypeCode_1(self, value):
        self.write_TypeCode(1, value)

    def read_TypeCode_2(self):
        return self.read_TypeCode(2)

    def write_TypeCode_2(self, value):
        self.write_TypeCode(2, value)

    def read_TypeCode_3(self):
        return self.read_TypeCode(3)

    def write_TypeCode_3(self, value):
        self.write_TypeCode(3, value)

    def read_TypeCode_4(self):
        return self.read_TypeCode(4)

    def write_TypeCode_4(self, value):
        self.write_TypeCode(4, value)

    def read_TypeCode_5(self):
        return self.read_TypeCode(5)

    def write_TypeCode_5(self, value):
        self.write_TypeCode(5, value)

    def read_TypeCode_6(self):
        return self.read_TypeCode(6)

    def write_TypeCode_6(self, value):
        self.write_TypeCode(6, value)

    def read_TypeCode_7(self):
        return self.read_TypeCode(7)

    def write_TypeCode_7(self, value):
        self.write_TypeCode(7, value)

    # --------------------
    # DigitalInput methods
    # --------------------

    def read_DigitalInput_0(self):
        return self.read_DigitalInput(0)

    def read_DigitalInput_1(self):
        return self.read_DigitalInput(1)

    def read_DigitalInput_2(self):
        return self.read_DigitalInput(2)

    def read_DigitalInput_3(self):
        return self.read_DigitalInput(3)

    # --------------------
    # EventStatus methods
    # --------------------

    def read_EventStatus_0(self):
        return self.read_EventStatus(0)

    def read_EventStatus_1(self):
        return self.read_EventStatus(1)

    def read_EventStatus_2(self):
        return self.read_EventStatus(2)

    def read_EventStatus_3(self):
        return self.read_EventStatus(3)

    # --------------------
    # EventStatus methods
    # --------------------

    def read_Status_0(self):
        return self.read_Status(0)

    def read_Status_1(self):
        return self.read_Status(1)

    def read_Status_2(self):
        return self.read_Status(2)

    def read_Status_3(self):
        return self.read_Status(3)

    # --------------------
    # Additional methods
    # --------------------

    def decode_value(self, value, channel, type):
        """Decode double to 16-bit value depending on Type Code of
        channel """
        type_code = self.analog_output_types[channel]
        if ((type_code == int("0182", 16)
             and not (value >= 0 and value <= 0.02))
                or (type_code == int("0180", 16)
                    and not (value >= 0.004 and value <= 0.02)) or
            (type_code == int("0148", 16) and not (value >= 0 and value <= 10))
                or
            (type_code == int("0147", 16) and not (value >= 0 and value <= 5))
                or (type_code == int("0143", 16)
                    and not (value >= -10 and value <= 10))
                or (type_code == int("0142", 16)
                    and not (value >= -5 and value <= 5))):
            if type == 0:
                tmp = self.analog_output_values[channel]
            elif type == 1:
                tmp = self.analog_output_safety_values[channel]
            else:
                tmp = self.analog_output_statup_values[channel]
            self.error_stream('Illegal value')
            raise ValueError
        else:
            if type_code == int("0182", 16):
                tmp = int(4095 * value / 0.02)
            elif type_code == int("0180", 16):
                tmp = int(4095 * (value - 0.004) / 0.016)
            elif type_code == int("0148", 16):
                tmp = int(4095 * value / 10)
            elif type_code == int("0147", 16):
                tmp = int(4095 * value / 5)
            elif type_code == int("0143", 16):
                tmp = int(4095 * (value + 10) / 20)
            elif type_code == int("0142", 16):
                tmp = int(4095 * (value + 5) / 10)
            else:
                if type == 0:
                    tmp = self.analog_output_values[channel]
                elif type == 1:
                    tmp = self.analog_output_safety_values[channel]
                else:
                    tmp = self.analog_output_statup_values[channel]
        return tmp

    def encode_value(self, value, channel):
        """Encode 16-bit value to double depending on Type Code of
        channel """
        type_code = self.analog_output_types[channel]
        if type_code == int("0182", 16):
            tmp = 0.02 * value / 4095.0
        elif type_code == int("0180", 16):
            tmp = (0.016 * value / 4095.0) + 0.004
        elif type_code == int("0148", 16):
            tmp = 10 * value / 4095.0
        elif type_code == int("0147", 16):
            tmp = 5 * value / 4095.0
        elif type_code == int("0143", 16):
            tmp = (20 * value / 4095.0) - 10
        elif type_code == int("0142", 16):
            tmp = (10 * value / 4095.0) - 5
        else:
            tmp = self.analog_output_values[channel]
        return tmp

    def decode_type_code(self, channel):
        """Decode 16-bit number to Type Code string"""
        return self.code_to_type_dict[self.analog_output_types[channel]]

    def encode_type_code(self, value="0-20mA"):
        """Encodes Type Code string to 16-bit number"""
        return self.type_to_code_dict[value]

    # --------
    # Commands
    # --------

    @command
    @DebugIt()
    def ConnectWithDevice(self):
        """
         Connect with ADAM Module with IP address the same as DeviceAddress
         property and sets its state to ON
        """
        try:
            self.connected_ADAM = ModbusTcpClient(self.DeviceAddress,
                                                  port=int(502))
        except ModbusException as e:
            self.set_state(DevState.FAULT)
            self.set_status("Modbus exception caught while"
                            " connecting to device: \n%s" % e)
        except Exception as e:
            self.set_state(DevState.FAULT)
            self.set_status("Exception caught while connecting to device:" +
                            "\n%s" % e)
        self.set_state(DevState.ON)
        self.set_status("Connected to device with IP: " +
                        str(self.DeviceAddress))

    @command(polling_period=500)
    def read_DataFromDevice(self):
        """
          Synchronous reading data from ADAM Module registers
         """
        if self.get_state() == tango.DevState.ON:
            # read Digital Inputs
            tmp = self.connected_ADAM.read_coils(0, 4)
            self.digital_input_values = tmp.bits
            # read Analog Outputs Value
            tmp = self.connected_ADAM.read_holding_registers(0, 4)
            self.analog_output_values = tmp.registers
            # read Analog Outputs Status
            tmp = self.connected_ADAM.read_holding_registers(100, 8)
            self.analog_output_statuses = tmp.registers
            # read Digital Inputs Status
            tmp = self.connected_ADAM.read_holding_registers(110, 4)
            self.digital_input_events = tmp.registers
            # read Type Codes
            tmp = self.connected_ADAM.read_holding_registers(200, 4)
            self.analog_output_types = tmp.registers
            # read Startup Values
            tmp = self.connected_ADAM.read_holding_registers(400, 4)
            self.analog_output_startup_values = tmp.registers
            # read Safety Values
            tmp = self.connected_ADAM.read_holding_registers(410, 4)
            self.analog_output_safety_values = tmp.registers
Exemple #26
0
class P04_beamline(Device):

    DYN_ATTRS = [
        dict(name='photonenergy',
             label='photon energy',
             dtype=tango.DevFloat,
             access=READ_WRITE,
             unit='eV',
             format='%6.2f',
             min_value=240,
             max_value=2000),
        dict(name='exitslit',
             label="exit slit",
             dtype=tango.DevFloat,
             access=READ_WRITE,
             unit="um",
             format="%4.0f"),
        dict(name='helicity',
             label='helicity',
             dtype=tango.DevLong,
             access=READ_WRITE,
             min_value=-1,
             max_value=1),
        dict(name='mono',
             label="monochromator",
             dtype=tango.DevFloat,
             access=READ,
             unit="eV",
             format="%6.2f"),
        dict(name='undugap',
             label='undulator gap',
             dtype=tango.DevFloat,
             access=READ,
             unit='mm'),
        # dict(name='undufactor', label='undulator scale factor',
        #      access=READ, format='%3.2f', dtype=tango.DevFloat),
        dict(name='undushift',
             label='undulator shift',
             dtype=tango.DevFloat,
             access=READ,
             unit='mm'),
        dict(name='ringcurrent',
             label='ring current',
             dtype=tango.DevFloat,
             access=READ,
             unit='mA'),
        # dict(name='keithley1', label='beamline keithley', dtype=tango.DevFloat,
        #      access=READ),
        # dict(name='keithley2', label='user keithley', dtype=tango.DevFloat,
        #      access=READ),
        dict(name='slt2hleft',
             label='slit hor left',
             dtype=tango.DevFloat,
             access=READ),
        dict(name='slt2hright',
             label='slit hor right',
             dtype=tango.DevFloat,
             access=READ),
        dict(name='slt2vgap',
             label='slit ver gap',
             dtype=tango.DevFloat,
             access=READ),
        dict(name='slt2voffset',
             label='slit ver offset',
             dtype=tango.DevFloat,
             access=READ),
        # dict(name='exsu2bpm', label='exsu2bpm', dtype=tango.DevFloat,
        # access=READ),
        # dict(name='exsu2baffle', label='exsu2baffle', dtype=tango.DevFloat,
        #       access=READ),
        # dict(name='pressure', label='experiment pressure', access=READ,
        #       dtype=tango.DevFloat, unit='mbar', format='%.2E'),
        dict(name='screen',
             label='beamline screen',
             dtype=tango.DevLong,
             access=READ_WRITE,
             min_value=0,
             max_value=2,
             enum_labels=['closed', 'mesh', 'open'])
    ]

    ready_to_move = attribute(name='ready_to_move',
                              label='in position',
                              access=READ,
                              dtype=tango.DevBoolean,
                              polling_period=1000,
                              fread="is_movable")

    host = device_property(dtype=str, mandatory=True, update_db=True)
    port = device_property(dtype=int, default_value=3002)

    def init_device(self):
        Device.init_device(self)
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.connect((self.host, self.port))
        self.s.setblocking(True)
        self.lock = Lock()
        self.set_state(DevState.ON)
        energy = self.read_attr('photonenergy')[0]
        self._setpoint_E = [energy, energy]
        self._setpoint_helicity = self.read_attr('helicity')[0]

    def initialize_dynamic_attributes(self):
        # TODO: setup polling and event filter
        for d in self.DYN_ATTRS:
            new_attr = attribute(fget=self.read_general,
                                 fset=self.write_general,
                                 **d)
            self.add_attribute(new_attr)

    @command(dtype_in=str)
    def query(self, msg):
        '''Send a query and wait for its reply.'''
        if self.lock.acquire(timeout=0.5):
            if not msg.endswith(' eoc'):
                msg += ' eoc'
            # print('sent:', msg, file=self.log_debug)
            self.s.sendall(msg.encode())
            ans = self.s.recv(1024).decode()
            # print('received:', ans, file=self.log_debug)
            assert ans.endswith('eoa')
            self.lock.release()
            return ans[:-4]
        else:
            print(f"can't send '{msg}': socket is locked", file=self.log_error)
            return 'busy'

    def read_general(self, attr):
        key = attr.get_name()
        # print('reading', key, file=self.log_debug)
        val, time, quality = self.read_attr(key)
        attr.set_value(val)

    # def write_general(self, attr):
    #     key = attr.get_name()
    #     val = attr.get_write_value()
    #     send_attrs = ['photonenergy', 'exitslit', 'helicity', 'screen']
    #     cmd = 'send' if key in send_attrs else 'set'
    #     ntries = 0
    #     while ntries < 10:
    #         ntries += 1
    #         if self.is_movable():
    #             ans = self.query(f'{cmd} {key} {val}')
    #             print(f'setting {key}: {val} ({ntries}/10)', file=self.log_debug)
    #             if ans == 'started':
    #                 self.set_state(DevState.MOVING)
    #                 print(f'[key] moving to {val}', file=self.log_debug)
    #                 return
    #             time.sleep(1)

    #     print(f'could not send {key} to {val}', file=self.log_error)

    def write_general(self, attr):
        key = attr.get_name()
        val = attr.get_write_value()
        send_attrs = ['photonenergy', 'exitslit', 'helicity', 'screen']
        cmd = 'send' if key in send_attrs else 'set'
        if key == 'photonenergy':
            self._setpoint_E[0] = val
        if key == 'helicity':
            self._setpoint_helicity = val
        ans = self.query(f'{cmd} {key} {val}')
        print(f'setting {key}: {val}', file=self.log_debug)
        if ans == 'started':
            self._setpoint_E[1] = val
            self.set_state(DevState.MOVING)
            print(f'[key] moving to {val}', file=self.log_debug)
            return

        print(f'could not send {key} to {val}', file=self.log_error)

    def is_movable(self):
        '''Check whether undulator and monochromator are in position.'''
        in_pos = self.query('check photonenergy')
        in_pos = True if in_pos == '1' else False
        if (self._setpoint_E[0] != self._setpoint_E[1]) and in_pos:
            ans_set = self.query(f'send photonenergy {self._setpoint_E[0]}')
            if ans_set == 'started':
                self._setpoint_E[1] = self._setpoint_E[0]
        helicity = self.read_attr('helicity')[0]
        state = (helicity == self._setpoint_helicity) and in_pos
        self.set_state(DevState.ON if state else DevState.MOVING)
        return in_pos

    @command(dtype_in=str, dtype_out=str)
    def cmd_async(self, msg, test):
        '''Send a command without waiting for it to finish.

        The socket will still be blocked!
        '''
        t = Thread(target=self.query, args=(msg, ))
        t.daemon = True
        t.start()

    @command
    def closeconnection(self):
        ans = self.query('closeconnection')
        if 'bye!' in ans:
            self.s.close()
            self.set_state(DevState.OFF)

    def read_attr(self, attr):
        '''Queries the position of given attribute name.

        Returns
        -------
        val : float
        tstamp : time stamp
        quality : AttrQuality instance (ATTR_VALID, ATTR_CHANGING, ...)
        '''
        ans = self.query(f'read {attr}')
        if 'Current value' in ans:
            val = float(ans.split(':')[1])
            return val, time(), AttrQuality.ATTR_VALID
        else:
            self.error_stream('Socket busy or unexpected/incomplete answer')
            return None, time(), AttrQuality.ATTR_INVALID
class SKAAlarmHandler(with_metaclass(DeviceMeta, SKABaseDevice)):
    """
    A generic base device for Alarms for SKA.
    """
    # PROTECTED REGION ID(SKAAlarmHandler.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  SKAAlarmHandler.class_variable

    # -----------------
    # Device Properties
    # -----------------

    SubAlarmHandlers = device_property(dtype=('str', ), )

    AlarmConfigFile = device_property(dtype='str', )

    # ----------
    # Attributes
    # ----------

    statsNrAlerts = attribute(
        dtype='int',
        doc="Number of active Alerts",
    )

    statsNrAlarms = attribute(
        dtype='int',
        doc="Number of active Alarms",
    )

    statsNrNewAlarms = attribute(
        dtype='int',
        doc="Number of New active alarms",
    )

    statsNrUnackAlarms = attribute(
        dtype='double',
        doc="Number of unacknowledged alarms",
    )

    statsNrRtnAlarms = attribute(
        dtype='double',
        doc="Number of returned alarms",
    )

    activeAlerts = attribute(
        dtype=('str', ),
        max_dim_x=10000,
        doc="List of active alerts",
    )

    activeAlarms = attribute(
        dtype=('str', ),
        max_dim_x=10000,
        doc="List of active alarms",
    )

    # ---------------
    # General methods
    # ---------------

    def init_device(self):
        SKABaseDevice.init_device(self)
        self._build_state = '{}, {}, {}'.format(release.name, release.version,
                                                release.description)
        self._version_id = release.version
        # PROTECTED REGION ID(SKAAlarmHandler.init_device) ENABLED START #
        # PROTECTED REGION END #    //  SKAAlarmHandler.init_device

    def always_executed_hook(self):
        # PROTECTED REGION ID(SKAAlarmHandler.always_executed_hook) ENABLED START #
        pass
        # PROTECTED REGION END #    //  SKAAlarmHandler.always_executed_hook

    def delete_device(self):
        # PROTECTED REGION ID(SKAAlarmHandler.delete_device) ENABLED START #
        pass
        # PROTECTED REGION END #    //  SKAAlarmHandler.delete_device

    # ------------------
    # Attributes methods
    # ------------------

    def read_statsNrAlerts(self):
        # PROTECTED REGION ID(SKAAlarmHandler.statsNrAlerts_read) ENABLED START #
        """
        Reads number of active alerts.
        :return: Number of active alerts
        """
        return 0
        # PROTECTED REGION END #    //  SKAAlarmHandler.statsNrAlerts_read

    def read_statsNrAlarms(self):
        # PROTECTED REGION ID(SKAAlarmHandler.statsNrAlarms_read) ENABLED START #
        """
        Reads number of active alarms.
        :return: Number of active alarms
        """
        return 0
        # PROTECTED REGION END #    //  SKAAlarmHandler.statsNrAlarms_read

    def read_statsNrNewAlarms(self):
        # PROTECTED REGION ID(SKAAlarmHandler.statsNrNewAlarms_read) ENABLED START #
        """
        Reads number of new active alarms.
        :return: Number of new active alarms
        """
        return 0
        # PROTECTED REGION END #    //  SKAAlarmHandler.statsNrNewAlarms_read

    def read_statsNrUnackAlarms(self):
        # PROTECTED REGION ID(SKAAlarmHandler.statsNrUnackAlarms_read) ENABLED START #
        """
        Reads number of unacknowledged alarms.
        :return: Number of unacknowledged alarms.
        """
        return 0.0
        # PROTECTED REGION END #    //  SKAAlarmHandler.statsNrUnackAlarms_read

    def read_statsNrRtnAlarms(self):
        # PROTECTED REGION ID(SKAAlarmHandler.statsNrRtnAlarms_read) ENABLED START #
        """
        Reads number of returned alarms.
        :return: Number of returned alarms
        """
        return 0.0
        # PROTECTED REGION END #    //  SKAAlarmHandler.statsNrRtnAlarms_read

    def read_activeAlerts(self):
        # PROTECTED REGION ID(SKAAlarmHandler.activeAlerts_read) ENABLED START #
        """
        Reads list of active alerts.
        :return: List of active alerts
        """
        return ['']
        # PROTECTED REGION END #    //  SKAAlarmHandler.activeAlerts_read

    def read_activeAlarms(self):
        # PROTECTED REGION ID(SKAAlarmHandler.activeAlarms_read) ENABLED START #
        """
        Reads list of active alarms.
        :return: List of active alarms
        """
        return ['']
        # PROTECTED REGION END #    //  SKAAlarmHandler.activeAlarms_read

    # --------
    # Commands
    # --------

    @command(
        dtype_in='str',
        doc_in="Alarm name",
        dtype_out='str',
        doc_out="JSON string",
    )
    @DebugIt()
    def GetAlarmRule(self, argin):
        # PROTECTED REGION ID(SKAAlarmHandler.GetAlarmRule) ENABLED START #
        """
        Get all configuration info of the alarm, e.g. rule, defined action, etc.
        :param argin: Name of the alarm
        :return: JSON string containing configuration information of the alarm
        """
        return ""
        # PROTECTED REGION END #    //  SKAAlarmHandler.GetAlarmRule

    @command(
        dtype_in='str',
        doc_in="Alarm name",
        dtype_out='str',
        doc_out="JSON string",
    )
    @DebugIt()
    def GetAlarmData(self, argin):
        # PROTECTED REGION ID(SKAAlarmHandler.GetAlarmData) ENABLED START #
        """
        Get list of current value, quality factor and status of
        all attributes participating in the alarm rule.
        :param argin: Name of the alarm
        :return: JSON string containing alarm data
        """
        return ""
        # PROTECTED REGION END #    //  SKAAlarmHandler.GetAlarmData

    @command(
        dtype_in='str',
        doc_in="Alarm name",
        dtype_out='str',
        doc_out="JSON string",
    )
    @DebugIt()
    def GetAlarmAdditionalInfo(self, argin):
        # PROTECTED REGION ID(SKAAlarmHandler.GetAlarmAdditionalInfo) ENABLED START #
        """
        Get additional alarm information.
        :param argin: Name of the alarm
        :return: JSON string containing additional alarm information
        """
        return ""
        # PROTECTED REGION END #    //  SKAAlarmHandler.GetAlarmAdditionalInfo

    @command(
        dtype_out='str',
        doc_out="JSON string",
    )
    @DebugIt()
    def GetAlarmStats(self):
        # PROTECTED REGION ID(SKAAlarmHandler.GetAlarmStats) ENABLED START #
        """
        Get current alarm stats.
        :return: JSON string containing alarm statistics
        """
        return ""
        # PROTECTED REGION END #    //  SKAAlarmHandler.GetAlarmStats

    @command(
        dtype_out='str',
        doc_out="JSON string",
    )
    @DebugIt()
    def GetAlertStats(self):
        # PROTECTED REGION ID(SKAAlarmHandler.GetAlertStats) ENABLED START #
        """
        Get current alert stats.
        :return: JSON string containing alert statistics
        """
        return ""
class AndrewDev(Device):
    """
    Andrew's hack of example power supply device from the PyTango documentation.
    """
    # green_mode = GreenMode.Asyncio

    voltage = attribute(label="Voltage", dtype=float,
                        display_level=DispLevel.OPERATOR,
                        access=AttrWriteType.READ,
                        unit="V", format="%4.2f",
                        doc="output voltage")

    current = attribute(label="Current", dtype=float,
                        display_level=DispLevel.EXPERT,
                        access=AttrWriteType.READ_WRITE,
                        unit="A", format="%3.2f",
                        min_value=0.0, max_value=8.5,
                        min_alarm=0.1, max_alarm=8.4,
                        min_warning=0.5, max_warning=8.0,
                        abs_change=0.01,
                        fget="get_current",
                        fset="set_current",
                        doc="output current")

    temperature = attribute(label="Temperature", dtype=int,
                            display_level=DispLevel.EXPERT,
                            access=AttrWriteType.READ,
                            unit="degC", format="%3.1f", # '°' symbol displays strangely on GUI?
                            display_unit=0.1, # tells UI to divide by 10
                            abs_change=50,
                            doc="internal temperature")

    host = device_property(dtype=str)
    port = device_property(dtype=int, default_value=9788)

    def __init__(self, device_class, device_name):
        super().__init__(device_class, device_name)
        self.__current = 0.0
        self.__temperature = 200

    def init_device(self):
        """Initialise device"""
        Device.init_device(self)
        self.set_current(0.0)
        self.set_state(DevState.STANDBY)

    def read_voltage(self):
        """Read voltage"""
        self.info_stream("read_voltage(%s, %d)", self.host, self.port)
        return 240, time.time(), AttrQuality.ATTR_VALID

    def get_current(self):
        """Get the current"""
        if self.get_state() in (DevState.STANDBY, DevState.OFF):
            return 0
        return self.__current

    def set_current(self, current):
        """Set the current"""
        self.__current = current

    def read_temperature(self):
        """Read internal temperature"""
        # very coarse thermal loss simulation
        if self.get_state() in (DevState.STANDBY, DevState.OFF):
            self.__temperature = 200
        else:
            self.__temperature = 200 + (self.__current**2)*10
        return self.__temperature + randint(-4, 4)

    @command
    def turn_on(self):
        """Turn the device on"""
        # turn on the actual power supply here
        self.set_state(DevState.ON)
        self.push_change_event('temperature', self.__temperature)
        self.push_change_event('current', self.__current)

    @command
    def turn_off(self):
        """Turn the device off"""
        # turn off the actual power supply here
        self.set_state(DevState.OFF)
        self.push_change_event('temperature', self.__temperature)
        self.push_change_event('current', self.__current)

    @command(dtype_in=float, doc_in="Ramp target current",
             dtype_out=bool, doc_out="True if ramping went well, "
                                     "False otherwise")
    def ramp(self, target_current):
        """Ramp output to the target current"""
        # should do the ramping. This doesn't.
        self.set_current(target_current)
        return True
Exemple #29
0
 def add_dyn_attr(self, name):
     attr = attribute(name=name, dtype='float', fget=self.read)
     self.add_attribute(attr)
class Vcc(CspSubElementObsDevice):
    """
    Vcc TANGO device class for the prototype
    """

    #TODO: remove temporary manual flag for unit testing
    #set True to bypass band and search window device proxies
    TEST_CONTEXT = False

    # -----------------
    # Device Properties
    # -----------------

    VccID = device_property(
        dtype='DevUShort'
    )

    Band1And2Address = device_property(
        dtype='str'
    )

    Band3Address = device_property(
        dtype='str'
    )

    Band4Address = device_property(
        dtype='str'
    )

    Band5Address = device_property(
        dtype='str'
    )

    SW1Address = device_property(
        dtype='str'
    )

    SW2Address = device_property(
        dtype='str'
    )

    # ----------
    # Attributes
    # ----------

    receptorID = attribute(
        dtype='uint16',
        access=AttrWriteType.READ_WRITE,
        label="Receptor ID",
        doc="Receptor ID",
    )

    subarrayMembership = attribute(
        dtype='uint16',
        access=AttrWriteType.READ_WRITE,
        label="subarrayMembership",
        doc="Subarray membership",
    )

    frequencyBand = attribute(
        dtype='DevEnum',
        access=AttrWriteType.READ,
        label="Frequency band",
        doc="Frequency band; an int in the range [0, 5]",
        enum_labels=["1", "2", "3", "4", "5a", "5b", ],
    )

    band5Tuning = attribute(
        dtype=('float',),
        max_dim_x=2,
        access=AttrWriteType.READ_WRITE,
        label="Stream tuning (GHz)",
        doc="Stream tuning (GHz)"
    )

    frequencyBandOffsetStream1 = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="Frequency band offset (stream 1) (Hz)",
        doc="Frequency band offset (stream 1) (Hz)"
    )

    frequencyBandOffsetStream2 = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="Frequency band offset (stream 2) (Hz)",
        doc="Frequency band offset (stream 2) (Hz)"
    )

    dopplerPhaseCorrection = attribute(
        dtype=('float',),
        access=AttrWriteType.READ_WRITE,
        max_dim_x=4,
        label="Doppler phase correction coefficients",
        doc="Doppler phase correction coefficients"
    )

    rfiFlaggingMask = attribute(
        dtype='str',
        access=AttrWriteType.READ_WRITE,
        label="RFI Flagging Mask",
        doc="RFI Flagging Mask"
    )

    scfoBand1 = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="SCFO (band 1)",
        doc="Sample clock frequency offset for band 1",
    )

    scfoBand2 = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="SCFO (band 2)",
        doc="Sample clock frequency offset for band 2",
    )

    scfoBand3 = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="SCFO (band 3)",
        doc="Sample clock frequency offset for band 3",
    )

    scfoBand4 = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="SCFO (band 4)",
        doc="Sample clock frequency offset for band 4",
    )

    scfoBand5a = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="SCFO (band 5a)",
        doc="Sample clock frequency offset for band 5a",
    )

    scfoBand5b = attribute(
        dtype='int',
        access=AttrWriteType.READ_WRITE,
        label="SCFO (band 5b)",
        doc="Sample clock frequency offset for band 5b",
    )

    delayModel = attribute(
        dtype=(('double',),),
        max_dim_x=6,
        max_dim_y=26,
        access=AttrWriteType.READ,
        label="Delay model coefficients",
        doc="Delay model coefficients, given per frequency slice"
    )

    jonesMatrix = attribute(
        dtype=(('double',),),
        max_dim_x=16,
        max_dim_y=26,
        access=AttrWriteType.READ,
        label='Jones Matrix elements',
        doc='Jones Matrix elements, given per frequency slice'
    )

    scanID = attribute(
        dtype='DevULong',
        access=AttrWriteType.READ_WRITE,
        label="scanID",
        doc="scan ID",
    )

    configID = attribute(
        dtype='DevString',
        access=AttrWriteType.READ_WRITE,
        label="config ID",
        doc="config ID",
    )

    # ---------------
    # General methods
    # ---------------

    # PROTECTED REGION ID(Vcc.class_variable) ENABLED START #

    def init_command_objects(self):
        """
        Sets up the command objects
        """
        super().init_command_objects()

        device_args = (self, self.state_model, self.logger)
        self.register_command_object(
            "ConfigureScan", self.ConfigureScanCommand(*device_args)
        )
        self.register_command_object(
            "GoToIdle", self.GoToIdleCommand(*device_args)
        )

    # PROTECTED REGION END #    //  Vcc.class_variable

    class InitCommand(CspSubElementObsDevice.InitCommand):
        """
        A class for the Vcc's init_device() "command".
        """

        def do(self):
            """
            Stateless hook for device initialisation.

            :return: A tuple containing a return code and a string
                message indicating status. The message is for
                information purpose only.
            :rtype: (ResultCode, str)
            """

            self.logger.debug("Entering InitCommand()")

            super().do()

            device = self.target

            # Make a private copy of the device properties:
            self._vcc_id = device.VccID

            # initialize attribute values        

            device._receptor_ID = 0
            device._freq_band_name = ""
            device._frequency_band = 0
            device._subarray_membership = 0
            device._stream_tuning = (0, 0)
            device._frequency_band_offset_stream_1 = 0
            device._frequency_band_offset_stream_2 = 0
            device._doppler_phase_correction = (0, 
            0, 0, 0)
            device._rfi_flagging_mask = ""
            device._scfo_band_1 = 0
            device._scfo_band_2 = 0
            device._scfo_band_3 = 0
            device._scfo_band_4 = 0
            device._scfo_band_5a = 0
            device._scfo_band_5b = 0
            device._delay_model = [[0] * 6 for i in range(26)]
            device._jones_matrix = [[0] * 16 for i in range(26)]

            device._scan_id = ""
            device._config_id = ""

            # device._fqdns = [
            #    device.Band1And2Address,
            #    device.Band3Address,
            #    device.Band4Address,
            #    device.Band5Address,
            #    device.SW1Address,
            #    device.SW2Address 
            # ] # TODO 

            # device._func_devices = [
            #     tango.DeviceProxy(fqdn) for fqdn in device._fqdns
            # ]

            device.set_change_event("subarrayMembership", True, True)

            # TODO - create a command for the proxy connections
            #        similar to InitialSetup() in ska-low-mccs stations.py
            
            #self.__get_capability_proxies()

            # TODO - To support unit testing, use a wrapper class for the  
            # connection instead of directly DeviceProxy (see MccsDeviceProxy)
            device._dev_factory = DevFactory()
            device._proxy_band_12 = None
            device._proxy_band_3  = None
            device._proxy_band_4  = None
            device._proxy_band_5  = None
            device._proxy_sw_1    = None
            device._proxy_sw_2    = None

            message = "Vcc Init command completed OK"
            device.logger.info(message)
            return (ResultCode.OK, message)

    def always_executed_hook(self):
        """Method always executed before any TANGO command is executed."""
        # PROTECTED REGION ID(Vcc.always_executed_hook) ENABLED START #
        self.logger.info("ALWAYS EXECUTED HOOK")
        self.logger.info("%s", self._dev_factory._test_context)
        try:
            #TODO: remove temporary flag to disable Vcc proxies for unit testing
            if Vcc.TEST_CONTEXT is False:
                if self._proxy_band_12 is None:
                    self.logger.info("Connect to band proxy device")
                    self._proxy_band_12 = self._dev_factory.get_device(
                        self.Band1And2Address
                    )
                if self._proxy_band_3 is None:
                    self.logger.info("Connect to band proxy device")
                    self._proxy_band_3 = self._dev_factory.get_device(
                        self.Band3Address
                    )
                if self._proxy_band_4 is None:
                    self.logger.info("Connect to band proxy device")
                    self._proxy_band_4 = self._dev_factory.get_device(
                        self.Band4Address
                    )
                if self._proxy_band_5 is None:
                    self.logger.info("Connect to band proxy device")
                    self._proxy_band_5 = self._dev_factory.get_device(
                        self.Band5Address
                    )
                if self._proxy_sw_1 is None:
                    self.logger.info("Connect to search window proxy device")
                    self._proxy_sw_1 = self._dev_factory.get_device(
                        self.SW1Address
                    )
                if self._proxy_sw_2 is None:
                    self.logger.info("Connect to search window proxy device")
                    self._proxy_sw_2 = self._dev_factory.get_device(
                        self.SW2Address
                    )
        except Exception as ex:
            self.logger.info(
                "Unexpected error on DeviceProxy creation %s", str(ex)
            )
        # PROTECTED REGION END #    //  Vcc.always_executed_hook

    def delete_device(self):
        """
        Hook to delete resources allocated in the
        :py:meth:`~.Vcc.InitCommand.do` method of
        the nested :py:class:`~.Vcc.InitCommand`
        class.

        This method allows for any memory or other resources allocated
        in the :py:meth:`~.Vcc.InitCommand.do` method to be
        released. This method is called by the device destructor, and by
        the Init command when the Tango device server is re-initialised.
        """
        pass

    # ------------------
    # Attributes methods
    # ------------------

    def read_receptorID(self):
        # PROTECTED REGION ID(Vcc.receptorID_read) ENABLED START #
        """Return recptorID attribut(int)"""
        return self._receptor_ID
        # PROTECTED REGION END #    //  Vcc.receptorID_read

    def write_receptorID(self, value):
        # PROTECTED REGION ID(Vcc.receptorID_write) ENABLED START #
        """Set receptor ID attribute(int)"""
        self._receptor_ID = value
        # PROTECTED REGION END #    //  Vcc.receptorID_write

    def read_subarrayMembership(self):
        # PROTECTED REGION ID(Vcc.subarrayMembership_read) ENABLED START #
        """Return subarrayMembership attribute: sub-array affiliation of the VCC(0 of no affliation)"""
        self.logger.debug("Entering read_subarrayMembership(), _subarray_membership = {}".format(self._subarray_membership))
        return self._subarray_membership
        # PROTECTED REGION END #    //  Vcc.subarrayMembership_read

    def write_subarrayMembership(self, value):
        # PROTECTED REGION ID(Vcc.subarrayMembership_write) ENABLED START #
        """Set subarrayMembership attribute: sub-array affiliation of the VCC(0 of no affliation)"""
        self.logger.debug("Entering write_subarrayMembership(), value = {}".format(value))
        self._subarray_membership = value
        self.push_change_event("subarrayMembership",value)
        if not value:
            self._update_obs_state(ObsState.IDLE)
        # PROTECTED REGION END #    //  Vcc.subarrayMembership_write

    def read_frequencyBand(self):
        # PROTECTED REGION ID(Vcc.frequencyBand_read) ENABLED START #
        """Return frequencyBand attribute: frequency band being observed by the current scan (one of ["1", "2", "3", "4", "5a", "5b", ])"""
        return self._frequency_band
        # PROTECTED REGION END #    //  Vcc.frequencyBand_read

    def read_band5Tuning(self):
        # PROTECTED REGION ID(Vcc.band5Tuning_read) ENABLED START #
        """Return band5Tuning attribute: Stream tuning (GHz) in float"""
        return self._stream_tuning
        # PROTECTED REGION END #    //  Vcc.band5Tuning_read

    def write_band5Tuning(self, value):
        # PROTECTED REGION ID(Vcc.band5Tuning_write) ENABLED START #
        """Set band5Tuning attribute: Stream tuning (GHz) in float"""
        self._stream_tuning = value
        # PROTECTED REGION END #    //  Vcc.band5Tuning_write

    def read_frequencyBandOffsetStream1(self):
        # PROTECTED REGION ID(Vcc.frequencyBandOffsetStream1_read) ENABLED START #
        """Return frequecyBandOffsetStream1 attribute(int)"""
        return self._frequency_band_offset_stream_1
        # PROTECTED REGION END #    //  Vcc.frequencyBandOffsetStream1_read

    def write_frequencyBandOffsetStream1(self, value):
        # PROTECTED REGION ID(Vcc.frequencyBandOffsetStream1_write) ENABLED START #
        """Set frequecyBandOffsetStream1 attribute(int)"""
        self._frequency_band_offset_stream_1 = value
        # PROTECTED REGION END #    //  Vcc.frequencyBandOffsetStream1_write

    def read_frequencyBandOffsetStream2(self):
        # PROTECTED REGION ID(Vcc.frequencyBandOffsetStream2_read) ENABLED START #
        """Return frequecyBandOffsetStream2 attribute(int)"""
        return self._frequency_band_offset_stream_2
        # PROTECTED REGION END #    //  Vcc.frequencyBandOffsetStream2_read

    def write_frequencyBandOffsetStream2(self, value):
        # PROTECTED REGION ID(Vcc.frequencyBandOffsetStream2_write) ENABLED START #
        """Set frequecyBandOffsetStream2 attribute(int)"""
        self._frequency_band_offset_stream_2 = value
        # PROTECTED REGION END #    //  Vcc.frequencyBandOffsetStream2_write

    def read_dopplerPhaseCorrection(self):
        # PROTECTED REGION ID(Vcc.dopplerPhaseCorrection_read) ENABLED START #
        """Return dopplerPhaseCorrection attribute(float)"""
        return self._doppler_phase_correction
        # PROTECTED REGION END #    //  Vcc.dopplerPhaseCorrection_read

    def write_dopplerPhaseCorrection(self, value):
        # PROTECTED REGION ID(Vcc.dopplerPhaseCorrection_write) ENABLED START #
        """Set dopplerPhaseCorrection attribute(float)"""
        self._doppler_phase_correction = value
        # PROTECTED REGION END #    //  Vcc.dopplerPhaseCorrection_write

    def read_rfiFlaggingMask(self):
        # PROTECTED REGION ID(Vcc.rfiFlaggingMask_read) ENABLED START #
        """Return rfiFlaggingMask attribute(str/JSON)"""
        return self._rfi_flagging_mask
        # PROTECTED REGION END #    //  Vcc.rfiFlaggingMask_read

    def write_rfiFlaggingMask(self, value):
        # PROTECTED REGION ID(Vcc.rfiFlaggingMask_write) ENABLED START #
        """Set rfiFlaggingMask attribute(str/JSON)"""
        self._rfi_flagging_mask = value
        # PROTECTED REGION END #    //  Vcc.rfiFlaggingMask_write

    def read_scfoBand1(self):
        # PROTECTED REGION ID(Vcc.scfoBand1_read) ENABLED START #
        """Return scfoBand1 attribute(int): Sample clock frequency offset for band 1"""
        return self._scfo_band_1
        # PROTECTED REGION END #    //  Vcc.scfoBand1_read

    def write_scfoBand1(self, value):
        # PROTECTED REGION ID(Vcc.scfoBand1_write) ENABLED START #
        """Set scfoBand1 attribute(int): Sample clock frequency offset for band 1"""
        self._scfo_band_1 = value
        # PROTECTED REGION END #    //  Vcc.scfoBand1_write

    def read_scfoBand2(self):
        # PROTECTED REGION ID(Vcc.scfoBand2_read) ENABLED START #
        """Return scfoBand2 attribute(int): Sample clock frequency offset for band 2"""
        return self._scfo_band_2
        # PROTECTED REGION END #    //  Vcc.scfoBand2_read

    def write_scfoBand2(self, value):
        # PROTECTED REGION ID(Vcc.scfoBand2_write) ENABLED START #
        """Set scfoBand2 attribute(int): Sample clock frequency offset for band 2"""
        self._scfo_band_2 = value
        # PROTECTED REGION END #    //  Vcc.scfoBand2_write

    def read_scfoBand3(self):
        # PROTECTED REGION ID(Vcc.scfoBand3_read) ENABLED START #
        """Return scfoBand3 attribute(int): Sample clock frequency offset for band 3"""        
        return self._scfo_band_3
        # PROTECTED REGION END #    //  Vcc.scfoBand3_read

    def write_scfoBand3(self, value):
        # PROTECTED REGION ID(Vcc.scfoBand3_write) ENABLED START #
        """Set scfoBand3 attribute(int): Sample clock frequency offset for band 3"""        
        self._scfo_band_3 = value
        # PROTECTED REGION END #    //  Vcc.scfoBand3_write

    def read_scfoBand4(self):
        # PROTECTED REGION ID(Vcc.scfoBand4_read) ENABLED START #
        """Return scfoBand4 attribute(int): Sample clock frequency offset for band 4"""        
        return self._scfo_band_4
        # PROTECTED REGION END #    //  Vcc.scfoBand4_read

    def write_scfoBand4(self, value):
        # PROTECTED REGION ID(Vcc.scfoBand4_write) ENABLED START #
        """Set scfoBand4 attribute(int): Sample clock frequency offset for band 4"""        
        self._scfo_band_4 = value
        # PROTECTED REGION END #    //  Vcc.scfoBand4_write

    def read_scfoBand5a(self):
        # PROTECTED REGION ID(Vcc.scfoBand5a_read) ENABLED START #
        """Return scfoBand5a attribute(int): Sample clock frequency offset for band 5a"""        
        return self._scfo_band_5a
        # PROTECTED REGION END #    //  Vcc.scfoBand5a_read

    def write_scfoBand5a(self, value):
        # PROTECTED REGION ID(Vcc.scfoBand5a_write) ENABLED START #
        """Set scfoBand5a attribute(int): Sample clock frequency offset for band 5a"""        
        self._scfo_band_5a = value
        # PROTECTED REGION END #    //  Vcc.scfoBand5a_write

    def read_scfoBand5b(self):
        # PROTECTED REGION ID(Vcc.scfoBand5b_read) ENABLED START #
        """Return scfoBand5b attribute(int): Sample clock frequency offset for band 5b"""        
        return self._scfo_band_5b
        # PROTECTED REGION END #    //  Vcc.scfoBand5b_read

    def write_scfoBand5b(self, value):
        # PROTECTED REGION ID(Vcc.scfoBand5b_write) ENABLED START #
        """Set scfoBand5b attribute(int): Sample clock frequency offset for band 5b"""        
        self._scfo_band_5b = value
        # PROTECTED REGION END #    //  Vcc.scfoBand5b_write

    def read_delayModel(self):
        # PROTECTED REGION ID(Vcc.delayModel_read) ENABLED START #
        """Return delayModel attribute(2 dim, max=6*26 array): Delay model coefficients, given per frequency slice"""
        return self._delay_model
        # PROTECTED REGION END #    //  Vcc.delayModel_read

    def read_jonesMatrix(self):
        # PROTECTED REGION ID(Vcc.jonesMatrix_read) ENABLED START #
        """Return jonesMatrix attribute(max=16 array): Jones Matrix, given per frequency slice"""
        return self._jones_matrix
        # PROTECTED REGION END #    //  Vcc.jonesMatrix_read

    def read_scanID(self):
        # PROTECTED REGION ID(Vcc.scanID_read) ENABLED START #
        """Return the scanID attribute."""
        return self._scan_id
        # PROTECTED REGION END #    //  Vcc.scanID_read

    def write_scanID(self, value):
        # PROTECTED REGION ID(Vcc.scanID_write) ENABLED START #
        """Set the scanID attribute."""
        self._scan_id=value
        # PROTECTED REGION END #    //  Vcc.scanID_write

    def read_configID(self):
        # PROTECTED REGION ID(Vcc.configID_read) ENABLED START #
        """Return the configID attribute."""
        return self._config_id
        # PROTECTED REGION END #    //  Vcc.configID_read

    def write_configID(self, value):
        # PROTECTED REGION ID(Vcc.configID_write) ENABLED START #
        """Set the configID attribute."""
        self._config_id = value
        # PROTECTED REGION END #    //  Vcc.configID_write

    # --------
    # Commands
    # --------

    class ConfigureScanCommand(CspSubElementObsDevice.ConfigureScanCommand):
        """
        A class for the Vcc's ConfigureScan() command.
        """

        def do(self, argin):
            """
            Stateless hook for ConfigureScan() command functionality.

            :param argin: The configuration as JSON formatted string
            :type argin: str

            :return: A tuple containing a return code and a string
                message indicating status. The message is for
                information purpose only.
            :rtype: (ResultCode, str)
            :raises: ``CommandError`` if the configuration data validation fails.
            """

            self.logger.debug("Entering ConfigureScanCommand()")

            device = self.target

            # By this time, the receptor_ID should be set:
            self.logger.debug(("device._receptor_ID = {}".
            format(device._receptor_ID)))

            # validate the input args
            (result_code, msg) = self.validate_input(argin)

            if result_code == ResultCode.OK:
                # TODO: cosider to turn_on the selected band device
                #       via a separate command
                if Vcc.TEST_CONTEXT is False:
                    self.turn_on_band_device(device._freq_band_name)
                # store the configuration on command success
                device._last_scan_configuration = argin
                msg = "Configure command completed OK"

            return(result_code, msg)
            
        def validate_input(self, argin):
            """
            Validate the configuration parameters against allowed values, as needed.

            :param argin: The JSON formatted string with configuration for the device.
            :type argin: 'DevString'
            :return: A tuple containing a return code and a string message.
            :rtype: (ResultCode, str)
            """
            device = self.target

            try:
                config_dict = json.loads(argin)
                device._config_id = config_dict['config_id']

                freq_band_name = config_dict['frequency_band']
                device._freq_band_name = freq_band_name
                device._frequency_band = freq_band_dict()[freq_band_name]

                # call the method to validate the data sent with
                # the configuration, as needed.
                return (ResultCode.OK, "ConfigureScan arguments validation successfull")

            except (KeyError, json.JSONDecodeError) as err:
                msg = "Validate configuration failed with error:{}".format(err)
            except Exception as other_errs:
                msg = "Validate configuration failed with unknown error:{}".format(
                    other_errs)
                self.logger.error(msg)
            return (ResultCode.FAILED, msg)

        def turn_on_band_device(self, freq_band_name):
            """
            Constraint: Must be called AFTER validate_input()
            Set corresponding band of this VCC. # TODO - remove this
            Send ON signal to the corresponding band, and DISABLE signal 
            to all others
            """

            device = self.target

            # TODO: can be done in a more Pythonian way; broken?
            if freq_band_name in ["1", "2"]:
                device._proxy_band_12.On()
                device._proxy_band_3.Disable()
                device._proxy_band_4.Disable()
                device._proxy_band_5.Disable()
            elif freq_band_name == "3":
                device._proxy_band_12.Disable()
                device._proxy_band_3.On()
                device._proxy_band_4.Disable()
                device._proxy_band_5.Disable()
            elif freq_band_name == "4":
                device._proxy_band_12.Disable()
                device._proxy_band_3.Disable()
                device._proxy_band_4.On()
                device._proxy_band_5.Disable()
            elif freq_band_name in ["5a", "5b"]:
                device._proxy_band_12.Disable()
                device._proxy_band_3.Disable()
                device._proxy_band_4.Disable()
                device._proxy_band_5.On()
            else:
                # The frequnecy band name has been validated at this point
                # so this shouldn't happen
                pass

    @command(
        dtype_in='DevString',
        doc_in="JSON formatted string with the scan configuration.",
        dtype_out='DevVarLongStringArray',
        doc_out="A tuple containing a return code and a string message indicating status. "
                "The message is for information purpose only.",
    )
    @DebugIt()
    def ConfigureScan(self, argin):
        # PROTECTED REGION ID(Vcc.ConfigureScan) ENABLED START #
        """
        Configure the observing device parameters for the current scan.

        :param argin: JSON formatted string with the scan configuration.
        :type argin: 'DevString'

        :return: A tuple containing a return code and a string message indicating status.
            The message is for information purpose only.
        :rtype: (ResultCode, str)
        """
        command = self.get_command_object("ConfigureScan")
        (return_code, message) = command(argin)
        return [[return_code], [message]]
        # PROTECTED REGION END #    //  Vcc.ConfigureScan

    class GoToIdleCommand(CspSubElementObsDevice.GoToIdleCommand):
        """
        A class for the Vcc's GoToIdle command.
        """

        def do(self):
            """
            Stateless hook for GoToIdle() command functionality.

            :return: A tuple containing a return code and a string
                message indicating status. The message is for
                information purpose only.
            :rtype: (ResultCode, str)
            """

            self.logger.debug("Entering GoToIdleCommand()")

            device = self.target

            # Reset all values intialized in InitCommand.do():

            device._freq_band_name = ""
            device._frequency_band = 0
            
            # device._receptor_ID  - DO NOT reset!
            # _receptor_ID is set via an explicit write
            # BEFORE ConfigureScan() is executed; 

            # device._subarray_membership -  DO NOT reset! 
            
            device._stream_tuning = (0, 0)
            device._frequency_band_offset_stream_1 = 0
            device._frequency_band_offset_stream_2 = 0
            device._doppler_phase_correction = (0, 0, 0, 0)
            device._rfi_flagging_mask = ""
            device._scfo_band_1 = 0
            device._scfo_band_2 = 0
            device._scfo_band_3 = 0
            device._scfo_band_4 = 0
            device._scfo_band_5a = 0
            device._scfo_band_5b = 0
            device._delay_model = [[0] * 6 for i in range(26)]
            device._jones_matrix = [[0] * 16 for i in range(26)]

            device._scan_id = 0
            device._config_id = ""

            if device.state_model.obs_state == ObsState.IDLE:
                return (ResultCode.OK, 
                "GoToIdle command completed OK. Device already IDLE")

            return (ResultCode.OK, "GoToIdle command completed OK")

    def is_UpdateDelayModel_allowed(self):
        """allowed when Devstate is ON and ObsState is READY OR SCANNIGN"""
        self.logger.debug("Entering is_UpdateDelayModel_allowed()")
        self.logger.debug("self._obs_state = {}.format(self.dev_state())")
        if self.dev_state() == tango.DevState.ON and \
                self._obs_state in [ObsState.READY, ObsState.SCANNING]:
            return True
        return False

    @command(
        dtype_in='str',
        doc_in="Delay model, given per frequency slice"
    )
    def UpdateDelayModel(self, argin):
        # PROTECTED REGION ID(Vcc.UpdateDelayModel) ENABLED START #
        """update VCC's delay model(serialized JSON object)"""

        self.logger.debug("Entering UpdateDelayModel()")
        argin = json.loads(argin)

        self.logger.debug(("self._receptor_ID = {}".
            format(self._receptor_ID)))

        for delayDetails in argin:
            self.logger.debug(("delayDetails[receptor] = {}".
            format(delayDetails["receptor"])))

            if delayDetails["receptor"] != self._receptor_ID:
                continue
            for frequency_slice in delayDetails["receptorDelayDetails"]:
                if 1 <= frequency_slice["fsid"] <= 26:
                    if len(frequency_slice["delayCoeff"]) == 6:
                        self._delay_model[frequency_slice["fsid"] - 1] = \
                            frequency_slice["delayCoeff"]
                    else:
                        log_msg = "'delayCoeff' not valid for frequency slice {} of " \
                                    "receptor {}".format(frequency_slice["fsid"], self._receptor_ID)
                        self.logger.error(log_msg)
                else:
                    log_msg = "'fsid' {} not valid for receptor {}".format(
                        frequency_slice["fsid"], self._receptor_ID
                    )
                    self.logger.error(log_msg)
        # PROTECTED REGION END #    // Vcc.UpdateDelayModel

    def is_UpdateJonesMatrix_allowed(self):
        """allowed when Devstate is ON and ObsState is READY OR SCANNINNG"""
        if self.dev_state() == tango.DevState.ON and \
                self._obs_state in [ObsState.READY, ObsState.SCANNING]:
            return True
        return False

    @command(
        dtype_in='str',
        doc_in="Jones Matrix, given per frequency slice"
    )
    def UpdateJonesMatrix(self, argin):
        # PROTECTED REGION ID(Vcc.UpdateJonesMatrix) ENABLED START #
        self.logger.debug("Vcc.UpdateJonesMatrix")
        """update FSP's Jones matrix (serialized JSON object)"""

        argin = json.loads(argin)

        for receptor in argin:
            if receptor["receptor"] == self._receptor_ID:
                for frequency_slice in receptor["receptorMatrix"]:
                    fs_id = frequency_slice["fsid"]
                    matrix = frequency_slice["matrix"]
                    if 1 <= fs_id <= 26:
                        if len(matrix) == 16:
                            self._jones_matrix[fs_id-1] = matrix.copy()
                        else:
                            log_msg = "'matrix' not valid for frequency slice {} of " \
                                      "receptor {}".format(fs_id, self._receptor_ID)
                            self.logger.error(log_msg)
                    else:
                        log_msg = "'fsid' {} not valid for receptor {}".format(
                            fs_id, self._receptor_ID
                        )
                        self.logger.error(log_msg)
        # PROTECTED REGION END #    // Vcc.UpdateJonesMatrix

    def is_ValidateSearchWindow_allowed(self):
        # This command has no constraints:
        return True

    @command(
        dtype_in='str',
        doc_in='JSON object to configure a search window'
    )
    def ValidateSearchWindow(self, argin):
        """validate a search window configuration. The input is JSON object with the search window parameters. Called by the subarray"""
        # try to deserialize input string to a JSON object

        self.logger.debug("Entering ValidateSearchWindow()") 

        try:
            argin = json.loads(argin)
        except json.JSONDecodeError:  # argument not a valid JSON object
            msg = "Search window configuration object is not a valid JSON object."
            self.logger.error(msg)
            tango.Except.throw_exception("Command failed", msg, "ConfigureSearchWindow execution",
                                         tango.ErrSeverity.ERR)

        # Validate searchWindowID.
        if "search_window_id" in argin:
            if int(argin["search_window_id"]) in [1, 2]:
                pass
            else:  # searchWindowID not in valid range
                msg = "'searchWindowID' must be one of [1, 2] (received {}).".format(
                    str(argin["search_window_id"])
                )
                self.logger.error(msg)
                tango.Except.throw_exception("Command failed", msg,
                                             "ConfigureSearchWindow execution",
                                             tango.ErrSeverity.ERR)
        else:
            msg = "Search window specified, but 'searchWindowID' not given."
            self.logger.error(msg)
            tango.Except.throw_exception("Command failed", msg, "ConfigureSearchWindow execution",
                                         tango.ErrSeverity.ERR)

        # Validate searchWindowTuning.
        if "search_window_tuning" in argin:
            freq_band_name = argin["frequency_band"]
            if freq_band_name not in ["5a", "5b"]:  # frequency band is not band 5
                
                frequencyBand_mi = freq_band_dict()[freq_band_name]
                
                frequencyBand = ["1", "2", "3", "4", "5a", "5b"].index(argin["frequency_band"])

                assert frequencyBand_mi == frequencyBand
                
                start_freq_Hz, stop_freq_Hz = [
                    const.FREQUENCY_BAND_1_RANGE_HZ,
                    const.FREQUENCY_BAND_2_RANGE_HZ,
                    const.FREQUENCY_BAND_3_RANGE_HZ,
                    const.FREQUENCY_BAND_4_RANGE_HZ
                ][frequencyBand]

                self.logger.debug("start_freq_Hz = {}".format(start_freq_Hz)) 
                self.logger.debug("stop_freq_Hz = {}".format(stop_freq_Hz)) 

                if start_freq_Hz + argin["frequency_band_offset_stream_1"] <= \
                        int(argin["search_window_tuning"]) <= \
                        stop_freq_Hz + argin["frequency_band_offset_stream_1"]:
                    pass
                else:
                    msg = "'searchWindowTuning' must be within observed band."
                    self.logger.error(msg)
                    tango.Except.throw_exception("Command failed", msg,
                                                 "ConfigureSearchWindow execution",
                                                 tango.ErrSeverity.ERR)
            else:  # frequency band 5a or 5b (two streams with bandwidth 2.5 GHz)
                if argin["band_5_tuning"] == [0,0]: # band 5 tuning not specified in configuration
                    pass
                else:
                    frequency_band_range_1 = (
                        argin["band_5_tuning"][0] * 10 ** 9 + argin["frequency_band_offset_stream_1"] - \
                        const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2,
                        argin["band_5_tuning"][0] * 10 ** 9 + argin["frequency_band_offset_stream_1"] + \
                        const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2
                    )

                    frequency_band_range_2 = (
                        argin["band_5_tuning"][1] * 10 ** 9 + argin["frequency_band_offset_stream_2"] - \
                        const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2,
                        argin["band_5_tuning"][1] * 10 ** 9 + argin["frequency_band_offset_stream_2"] + \
                        const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2
                    )

                    if (frequency_band_range_1[0] <= \
                        int(argin["search_window_tuning"]) <= \
                        frequency_band_range_1[1]) or \
                            (frequency_band_range_2[0] <= \
                            int(argin["search_window_tuning"]) <= \
                            frequency_band_range_2[1]):
                        pass
                    else:
                        msg = "'searchWindowTuning' must be within observed band."
                        self.logger.error(msg)
                        tango.Except.throw_exception("Command failed", msg,
                                                    "ConfigureSearchWindow execution",
                                                    tango.ErrSeverity.ERR)
        else:
            msg = "Search window specified, but 'searchWindowTuning' not given."
            self.logger.error(msg)
            tango.Except.throw_exception("Command failed", msg, "ConfigureSearchWindow execution",
                                         tango.ErrSeverity.ERR)

        # Validate tdcEnable.
        if "tdc_enable" in argin:
            if argin["tdc_enable"] in [True, False]:
                pass
            else:
                msg = "Search window specified, but 'tdcEnable' not given."
                self.logger.error(msg)
                tango.Except.throw_exception("Command failed", msg,
                                             "ConfigureSearchWindow execution",
                                             tango.ErrSeverity.ERR)
        else:
            msg = "Search window specified, but 'tdcEnable' not given."
            self.logger.error(msg)
            tango.Except.throw_exception("Command failed", msg, "ConfigureSearchWindow execution",
                                         tango.ErrSeverity.ERR)

        # Validate tdcNumBits.
        if argin["tdc_enable"]:
            if "tdc_num_bits" in argin:
                if int(argin["tdc_num_bits"]) in [2, 4, 8]:
                    pass
                else:
                    msg = "'tdcNumBits' must be one of [2, 4, 8] (received {}).".format(
                        str(argin["tdc_num_bits"])
                    )
                    self.logger.error(msg)
                    tango.Except.throw_exception("Command failed", msg,
                                                 "ConfigureSearchWindow execution",
                                                 tango.ErrSeverity.ERR)
            else:
                msg = "Search window specified with TDC enabled, but 'tdcNumBits' not given."
                self.logger.error(msg)
                tango.Except.throw_exception("Command failed", msg,
                                             "ConfigureSearchWindow execution",
                                             tango.ErrSeverity.ERR)

        # Validate tdcPeriodBeforeEpoch.
        if "tdc_period_before_epoch" in argin:
            if int(argin["tdc_period_before_epoch"]) > 0:
                pass
            else:
                msg = "'tdcPeriodBeforeEpoch' must be a positive integer (received {}).".format(
                    str(argin["tdc_period_before_epoch"])
                )
                self.logger.error(msg)
                tango.Except.throw_exception("Command failed", msg,
                                             "ConfigureSearchWindow execution",
                                             tango.ErrSeverity.ERR)
        else:
            pass

        # Validate tdcPeriodAfterEpoch.
        if "tdc_period_after_epoch" in argin:
            if int(argin["tdc_period_after_epoch"]) > 0:
                pass
            else:
                msg = "'tdcPeriodAfterEpoch' must be a positive integer (received {}).".format(
                    str(argin["tdc_period_after_epoch"])
                )
                self.logger.error(msg)
                tango.Except.throw_exception("Command failed", msg,
                                             "ConfigureSearchWindow execution",
                                             tango.ErrSeverity.ERR)
        else:
            pass

        # Validate tdcDestinationAddress.
        if argin["tdc_enable"]:
            try:
                for receptor in argin["tdc_destination_address"]:
                    if int(receptor["receptor_id"]) == self._receptor_ID:
                    # TODO: validate input
                        break
                    else:  # receptorID not found
                        raise KeyError  # just handle all the errors in one place
            except KeyError:
                # tdcDestinationAddress not given or receptorID not in tdcDestinationAddress
                msg = "Search window specified with TDC enabled, but 'tdcDestinationAddress' " \
                      "not given or missing receptors."
                self.logger.error(msg)
                tango.Except.throw_exception("Command failed", msg,
                                             "ConfigureSearchWindow execution",
                                             tango.ErrSeverity.ERR)

    def is_ConfigureSearchWindow_allowed(self):
        """allowed if DevState is ON and ObsState is CONFIGURING"""
        if self.dev_state() == tango.DevState.ON and \
            (self._obs_state == ObsState.CONFIGURING or \
            self._obs_state == ObsState.READY):
            return True
        return False

    @command(
        dtype_in='str',
        doc_in='JSON object to configure a search window'
    )
    def ConfigureSearchWindow(self, argin):
        # PROTECTED REGION ID(Vcc.ConfigureSearchWindow) ENABLED START #
        # 
        """
        configure SearchWindow by sending parameters from the input(JSON) to SearchWindow device.
        This function is called by the subarray after the configuration has already been validated, so the checks here have been removed to reduce overhead.
        """

        self.logger.debug("Entering ConfigureSearchWindow()") 
        argin = json.loads(argin)

        # variable to use as SW proxy
        proxy_sw = None

        # Configure searchWindowID.
        #TODO: remove temporary flag to disable Vcc proxies for unit testing
        if Vcc.TEST_CONTEXT is False:
            if int(argin["search_window_id"]) == 1:
                proxy_sw = self._proxy_sw_1
            elif int(argin["search_window_id"]) == 2:
                proxy_sw = self._proxy_sw_2

            # Configure searchWindowTuning.
            if self._frequency_band in list(range(4)):  # frequency band is not band 5
                proxy_sw.searchWindowTuning = argin["search_window_tuning"]

                start_freq_Hz, stop_freq_Hz = [
                    const.FREQUENCY_BAND_1_RANGE_HZ,
                    const.FREQUENCY_BAND_2_RANGE_HZ,
                    const.FREQUENCY_BAND_3_RANGE_HZ,
                    const.FREQUENCY_BAND_4_RANGE_HZ
                ][self._frequency_band]

                if start_freq_Hz + self._frequency_band_offset_stream_1 + \
                        const.SEARCH_WINDOW_BW_HZ / 2 <= \
                        int(argin["search_window_tuning"]) <= \
                        stop_freq_Hz + self._frequency_band_offset_stream_1 - \
                        const.SEARCH_WINDOW_BW_HZ / 2:
                    # this is the acceptable range
                    pass
                else:
                    # log a warning message
                    log_msg = "'searchWindowTuning' partially out of observed band. " \
                            "Proceeding."
                    self.logger.warn(log_msg)
            else:  # frequency band 5a or 5b (two streams with bandwidth 2.5 GHz)
                proxy_sw.searchWindowTuning = argin["search_window_tuning"]

                frequency_band_range_1 = (
                    self._stream_tuning[0] * 10 ** 9 + self._frequency_band_offset_stream_1 - \
                    const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2,
                    self._stream_tuning[0] * 10 ** 9 + self._frequency_band_offset_stream_1 + \
                    const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2
                )

                frequency_band_range_2 = (
                    self._stream_tuning[1] * 10 ** 9 + self._frequency_band_offset_stream_2 - \
                    const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2,
                    self._stream_tuning[1] * 10 ** 9 + self._frequency_band_offset_stream_2 + \
                    const.BAND_5_STREAM_BANDWIDTH * 10 ** 9 / 2
                )

                if (frequency_band_range_1[0] + \
                    const.SEARCH_WINDOW_BW * 10 ** 6 / 2 <= \
                    int(argin["search_window_tuning"]) <= \
                    frequency_band_range_1[1] - \
                    const.SEARCH_WINDOW_BW * 10 ** 6 / 2) or \
                        (frequency_band_range_2[0] + \
                        const.SEARCH_WINDOW_BW * 10 ** 6 / 2 <= \
                        int(argin["search_window_tuning"]) <= \
                        frequency_band_range_2[1] - \
                        const.SEARCH_WINDOW_BW * 10 ** 6 / 2):
                    # this is the acceptable range
                    pass
                else:
                    # log a warning message
                    log_msg = "'searchWindowTuning' partially out of observed band. " \
                            "Proceeding."
                    self.logger.warn(log_msg)

            # Configure tdcEnable.
            proxy_sw.tdcEnable = argin["tdc_enable"]
            if argin["tdc_enable"]:
                proxy_sw.On()
            else:
                proxy_sw.Disable()

            # Configure tdcNumBits.
            if argin["tdc_enable"]:
                proxy_sw.tdcNumBits = int(argin["tdc_num_bits"])

            # Configure tdcPeriodBeforeEpoch.
            if "tdc_period_before_epoch" in argin:
                proxy_sw.tdcPeriodBeforeEpoch = int(argin["tdc_period_before_epoch"])
            else:
                proxy_sw.tdcPeriodBeforeEpoch = 2
                log_msg = "Search window specified, but 'tdcPeriodBeforeEpoch' not given. " \
                        "Defaulting to 2."
                self.logger.warn(log_msg)

            # Configure tdcPeriodAfterEpoch.
            if "tdc_period_after_epoch" in argin:
                proxy_sw.tdcPeriodAfterEpoch = int(argin["tdc_period_after_epoch"])
            else:
                proxy_sw.tdcPeriodAfterEpoch = 22
                log_msg = "Search window specified, but 'tdcPeriodAfterEpoch' not given. " \
                        "Defaulting to 22."
                self.logger.warn(log_msg)

            # Configure tdcDestinationAddress.
            if argin["tdc_enable"]:
                for receptor in argin["tdc_destination_address"]:
                    if int(receptor["receptor_id"]) == self._receptor_ID:
                        # TODO: validate input
                        proxy_sw.tdcDestinationAddress = \
                            receptor["tdc_destination_address"]
                        break