Skip to content
Snippets Groups Projects
Commit 99e3d081 authored by Taya Snijder's avatar Taya Snijder
Browse files

fixed 'illegal state transition' bug and off->initialise state bug

parent dde30236
No related branches found
No related tags found
2 merge requests!18Resolve #2021 "04 16 branched from master state bug fix",!17Resolve #2021 "04 16 branched from master state bug fix"
...@@ -17,9 +17,9 @@ from tango.server import run ...@@ -17,9 +17,9 @@ from tango.server import run
from src.hardware_device import * from src.hardware_device import *
__all__ = ["HW_dev"] __all__ = ["HW_dev"]
class HW_dev(hardware_device): class HW_dev(hardware_device):
""" """
This class is the minimal (read empty) implementation of a class using 'hardware_device' This class is the minimal (read empty) implementation of a class using 'hardware_device'
...@@ -76,6 +76,7 @@ class HW_dev(hardware_device): ...@@ -76,6 +76,7 @@ class HW_dev(hardware_device):
""" user code here. is called when the sate is set to INIT """ """ user code here. is called when the sate is set to INIT """
pass pass
# ---------- # ----------
# Run server # Run server
# ---------- # ----------
...@@ -86,4 +87,3 @@ def main(args=None, **kwargs): ...@@ -86,4 +87,3 @@ def main(args=None, **kwargs):
if __name__ == '__main__': if __name__ == '__main__':
main() main()
...@@ -15,21 +15,33 @@ ...@@ -15,21 +15,33 @@
from tango import DebugIt from tango import DebugIt
from tango.server import run, command from tango.server import run, command
from tango.server import device_property from tango.server import device_property
# Additional import # Additional import
from clients.opcua_connection import OPCUAConnection from clients.opcua_connection import OPCUAConnection
from src.attribute_wrapper import * from src.attribute_wrapper import *
from src.hardware_device import * from src.hardware_device import *
from src.lofar_logging import device_logging_to_python
__all__ = ["PCC", "main"] __all__ = ["PCC", "main"]
@device_logging_to_python({"device": "PCC"})
class PCC(hardware_device): class PCC(hardware_device):
"""
**Properties:**
- Device Property
OPC_Server_Name
- Type:'DevString'
OPC_Server_Port
- Type:'DevULong'
OPC_Time_Out
- Type:'DevDouble'
"""
# ----------------- # -----------------
# Device Properties # Device Properties
# ----------------- # -----------------
OPC_Server_Name = device_property( OPC_Server_Name = device_property(
dtype='DevString', dtype='DevString',
mandatory=True mandatory=True
...@@ -44,8 +56,7 @@ class PCC(hardware_device): ...@@ -44,8 +56,7 @@ class PCC(hardware_device):
dtype='DevDouble', dtype='DevDouble',
mandatory=True mandatory=True
) )
OPC_namespace = device_property(
OPC_Namespace = device_property(
dtype='DevString', dtype='DevString',
mandatory=False mandatory=False
) )
...@@ -53,56 +64,36 @@ class PCC(hardware_device): ...@@ -53,56 +64,36 @@ class PCC(hardware_device):
# ---------- # ----------
# Attributes # Attributes
# ---------- # ----------
RCU_state_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_state_R"], datatype=numpy.str_, access=AttrWriteType.READ_WRITE)
RCU_mask_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_mask_RW"], datatype=numpy.bool_, dims=(32,), access=AttrWriteType.READ_WRITE) RCU_mask_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_mask_RW"], datatype=numpy.bool_, dims=(32,), access=AttrWriteType.READ_WRITE)
Ant_mask_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:Ant_mask_RW"], datatype=numpy.bool_, dims=(3, 32), access=AttrWriteType.READ_WRITE) Ant_mask_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:Ant_mask_RW"], datatype=numpy.bool_, dims=(3, 32), access=AttrWriteType.READ_WRITE)
RCU_attenuator_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_attenuator_R"], datatype=numpy.int64, dims=(3, 32)) RCU_attenuator_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_attenuator_R"], datatype=numpy.int64, dims=(3, 32))
RCU_attenuator_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_attenuator_RW"], datatype=numpy.int64, dims=(3, 32),
RCU_attenuator_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_attenuator_RW"], datatype=numpy.int64, dims=(3, 32), access=AttrWriteType.READ_WRITE) access=AttrWriteType.READ_WRITE)
RCU_band_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_band_R"], datatype=numpy.int64, dims=(3, 32)) RCU_band_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_band_R"], datatype=numpy.int64, dims=(3, 32))
RCU_band_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_band_RW"], datatype=numpy.int64, dims=(3, 32), access=AttrWriteType.READ_WRITE) RCU_band_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_band_RW"], datatype=numpy.int64, dims=(3, 32), access=AttrWriteType.READ_WRITE)
RCU_temperature_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_temperature_R"], datatype=numpy.float64, dims=(32,)) RCU_temperature_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_temperature_R"], datatype=numpy.float64, dims=(32,))
RCU_Pwr_dig_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_Pwr_dig_R"], datatype=numpy.int64, dims=(32,)) RCU_Pwr_dig_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_Pwr_dig_R"], datatype=numpy.int64, dims=(32,))
RCU_LED0_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_LED0_R"], datatype=numpy.int64, dims=(32,)) RCU_LED0_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_LED0_R"], datatype=numpy.int64, dims=(32,))
RCU_LED0_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_LED0_RW"], datatype=numpy.int64, dims=(32,), access=AttrWriteType.READ_WRITE) RCU_LED0_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_LED0_RW"], datatype=numpy.int64, dims=(32,), access=AttrWriteType.READ_WRITE)
RCU_ADC_lock_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_lock_R"], datatype=numpy.int64, dims=(3, 32)) RCU_ADC_lock_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_lock_R"], datatype=numpy.int64, dims=(3, 32))
RCU_ADC_SYNC_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_SYNC_R"], datatype=numpy.int64, dims=(3, 32)) RCU_ADC_SYNC_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_SYNC_R"], datatype=numpy.int64, dims=(3, 32))
RCU_ADC_JESD_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_JESD_R"], datatype=numpy.int64, dims=(3, 32)) RCU_ADC_JESD_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_JESD_R"], datatype=numpy.int64, dims=(3, 32))
RCU_ADC_CML_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_CML_R"], datatype=numpy.int64, dims=(3, 32)) RCU_ADC_CML_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ADC_CML_R"], datatype=numpy.int64, dims=(3, 32))
RCU_OUT1_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_OUT1_R"], datatype=numpy.int64, dims=(3, 32)) RCU_OUT1_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_OUT1_R"], datatype=numpy.int64, dims=(3, 32))
RCU_OUT2_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_OUT2_R"], datatype=numpy.int64, dims=(3, 32)) RCU_OUT2_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_OUT2_R"], datatype=numpy.int64, dims=(3, 32))
RCU_ID_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ID_R"], datatype=numpy.int64, dims=(32,)) RCU_ID_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_ID_R"], datatype=numpy.int64, dims=(32,))
RCU_version_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_version_R"], datatype=numpy.str_, dims=(32,)) RCU_version_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_version_R"], datatype=numpy.str_, dims=(32,))
HBA_element_beamformer_delays_R = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_beamformer_delays_R"], datatype=numpy.int64, dims=(32, 96)) HBA_element_beamformer_delays_R = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_beamformer_delays_R"], datatype=numpy.int64,
dims=(32, 96))
HBA_element_beamformer_delays_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_beamformer_delays_RW"], datatype=numpy.int64, dims=(32, 96), access=AttrWriteType.READ_WRITE) HBA_element_beamformer_delays_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_beamformer_delays_RW"], datatype=numpy.int64,
dims=(32, 96), access=AttrWriteType.READ_WRITE)
HBA_element_pwr_R = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_pwr_R"], datatype=numpy.int64, dims=(32, 96)) HBA_element_pwr_R = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_pwr_R"], datatype=numpy.int64, dims=(32, 96))
HBA_element_pwr_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_pwr_RW"], datatype=numpy.int64, dims=(32, 96),
access=AttrWriteType.READ_WRITE)
HBA_element_pwr_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:HBA_element_pwr_RW"], datatype=numpy.int64, dims=(32, 96), access=AttrWriteType.READ_WRITE) RCU_monitor_rate_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_monitor_rate_RW"], datatype=numpy.float64,
access=AttrWriteType.READ_WRITE)
uC_ID_R = attribute_wrapper(comms_annotation=["2:PCC", "2:uC_ID_R"], datatype=numpy.int64, dims=(32,))
RCU_monitor_rate_RW = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_monitor_rate_RW"], datatype=numpy.float64, access=AttrWriteType.READ_WRITE)
def delete_device(self): def delete_device(self):
"""Hook to delete resources allocated in init_device. """Hook to delete resources allocated in init_device.
...@@ -112,6 +103,7 @@ class PCC(hardware_device): ...@@ -112,6 +103,7 @@ class PCC(hardware_device):
destructor and by the device Init command (a Tango built-in). destructor and by the device Init command (a Tango built-in).
""" """
self.debug_stream("Shutting down...") self.debug_stream("Shutting down...")
self.Off() self.Off()
self.debug_stream("Shut down. Good bye.") self.debug_stream("Shut down. Good bye.")
...@@ -122,17 +114,24 @@ class PCC(hardware_device): ...@@ -122,17 +114,24 @@ class PCC(hardware_device):
""" user code here. is called when the state is set to OFF """ """ user code here. is called when the state is set to OFF """
# Stop keep-alive # Stop keep-alive
self.OPCua_client.disconnect() self.OPCua_client.stop()
def initialise(self): def initialise(self):
""" user code here. is called when the state is set to INIT """ """ user code here. is called when the state is set to INIT """
#set up the OPC ua client # Init the dict that contains function to OPC-UA function mappings.
namespace = "http://lofar.eu" self.function_mapping = {}
if self.OPC_Namespace is not None: self.function_mapping["RCU_on"] = {}
namespace = self.OPC_Namespace self.function_mapping["RCU_off"] = {}
self.function_mapping["ADC_on"] = {}
self.function_mapping["RCU_update"] = {}
self.function_mapping["CLK_on"] = {}
self.function_mapping["CLK_off"] = {}
self.function_mapping["CLK_PLL_setup"] = {}
self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), namespace, self.OPC_Time_Out, self.Standby, self.Fault, self) # set up the OPC ua client
self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu",
self.OPC_Time_Out, self.Fault, self)
# map the attributes to the OPC ua comm client # map the attributes to the OPC ua comm client
for i in self.attr_list(): for i in self.attr_list():
...@@ -141,16 +140,6 @@ class PCC(hardware_device): ...@@ -141,16 +140,6 @@ class PCC(hardware_device):
except: except:
pass pass
# Init the dict that contains function to OPC-UA function mappings.
self.function_mapping = {}
self.function_mapping["RCU_off"] = self.OPCua_client._setup_annotation(["2:PCC", "2:RCU_off"])
self.function_mapping["RCU_on"] = self.OPCua_client._setup_annotation(["2:PCC", "2:RCU_on"])
self.function_mapping["ADC_on"] = self.OPCua_client._setup_annotation(["2:PCC", "2:ADC_on"])
self.function_mapping["RCU_update"] = self.OPCua_client._setup_annotation(["2:PCC", "2:RCU_update"])
self.function_mapping["CLK_off"] = self.OPCua_client._setup_annotation(["2:PCC", "2:CLK_off"])
self.function_mapping["CLK_on"] = self.OPCua_client._setup_annotation(["2:PCC", "2:CLK_on"])
self.function_mapping["CLK_PLL_setup"] = self.OPCua_client._setup_annotation(["2:PCC", "2:CLK_PLL_setup"])
self.OPCua_client.start() self.OPCua_client.start()
# -------- # --------
...@@ -244,4 +233,3 @@ def main(args=None, **kwargs): ...@@ -244,4 +233,3 @@ def main(args=None, **kwargs):
if __name__ == '__main__': if __name__ == '__main__':
main() main()
...@@ -19,12 +19,10 @@ from tango.server import device_property ...@@ -19,12 +19,10 @@ from tango.server import device_property
from clients.opcua_connection import OPCUAConnection from clients.opcua_connection import OPCUAConnection
from src.attribute_wrapper import * from src.attribute_wrapper import *
from src.hardware_device import * from src.hardware_device import *
from src.lofar_logging import device_logging_to_python
__all__ = ["SDP", "main"] __all__ = ["SDP", "main"]
@device_logging_to_python({"device": "SDP"})
class SDP(hardware_device): class SDP(hardware_device):
""" """
...@@ -105,10 +103,7 @@ class SDP(hardware_device): ...@@ -105,10 +103,7 @@ class SDP(hardware_device):
"""Initialises the attributes and properties of the PCC.""" """Initialises the attributes and properties of the PCC."""
# set up the OPC ua client # set up the OPC ua client
self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu", self.OPC_Time_Out, self.Standby, self.Fault, self) self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu", self.OPC_Time_Out, self.Fault, self)
# will contain all the values for this object
self.setup_value_dict()
# map an access helper class # map an access helper class
for i in self.attr_list(): for i in self.attr_list():
......
from src.comms_client import * from src.comms_client import *
import opcua
__all__ = ["OPCUAConnection"] __all__ = ["OPCUAConnection"]
...@@ -33,13 +33,13 @@ class OPCUAConnection(CommClient): ...@@ -33,13 +33,13 @@ class OPCUAConnection(CommClient):
def start(self): def start(self):
super().start() super().start()
def __init__(self, address, namespace, timeout, on_func, fault_func, streams, try_interval=2): def __init__(self, address, namespace, timeout, fault_func, streams, try_interval=2):
""" """
Create the OPC ua client and connect() to it and get the object node Create the OPC ua client and connect() to it and get the object node
""" """
super().__init__(on_func, fault_func, streams, try_interval) super().__init__(fault_func, streams, try_interval)
self.client = opcua.Client(address, timeout) self.client = Client(address, timeout)
# Explicitly connect # Explicitly connect
if not self.connect(): if not self.connect():
...@@ -77,7 +77,7 @@ class OPCUAConnection(CommClient): ...@@ -77,7 +77,7 @@ class OPCUAConnection(CommClient):
return True return True
except socket.error as e: except socket.error as e:
self.streams.error_stream("Could not connect to server %s: %s", self._servername(), e) self.streams.error_stream("Could not connect to server %s: %s", self._servername(), e)
raise Exception("") from e raise Exception("Could not connect to server %s", self._servername()) from e
def disconnect(self): def disconnect(self):
...@@ -89,19 +89,16 @@ class OPCUAConnection(CommClient): ...@@ -89,19 +89,16 @@ class OPCUAConnection(CommClient):
try: try:
self.client.disconnect() self.client.disconnect()
except Exception as e: except Exception as e:
self.streams.error_stream("Disconnect from OPC-UA server {} failed: {}".format(self._servername(), e)) self.streams.error_stream("Disconnect from OPC-UA server %s failed: %s", self._servername(), e)
def ping(self): def ping(self):
""" """
ping the client to make sure the connection with the client is still functional. ping the client to make sure the connection with the client is still functional.
""" """
try: try:
if self.connected is True:
self.client.send_hello() self.client.send_hello()
else:
self.streams.debug_stream("Will not ping OPC-UA server {} because the connection is inactive.".format(self._servername()))
except Exception as e: except Exception as e:
raise Exception("Lost connection to server {}.".format(self._servername())) from e raise Exception("Lost connection to server %s: %s", self._servername(), e)
def _setup_annotation(self, annotation): def _setup_annotation(self, annotation):
""" """
...@@ -117,12 +114,13 @@ class OPCUAConnection(CommClient): ...@@ -117,12 +114,13 @@ class OPCUAConnection(CommClient):
elif isinstance(annotation, list): elif isinstance(annotation, list):
path = annotation path = annotation
else: else:
raise Exception("OPC-ua mapping requires either a list of the path or dict with the path. Was given {} type containing: {}".format(type(annotation), annotation)) raise Exception("OPC-ua mapping requires either a list of the path or dict with the path. Was given %s type containing: %s", type(annotation), annotation)
try: try:
node = self.obj.get_child(path) node = self.obj.get_child(path)
except Exception as e: except Exception as e:
raise Exception("Could not get node: {} on server {}".format(path, self._servername())) from e self.streams.error_stream("Could not get node: %s on server %s: %s", path, self._servername(), e)
raise Exception("Could not get node: %s on server %s", path, self._servername()) from e
return node return node
......
from src.comms_client import * from src.comms_client import *
# <class 'numpy.bool_'> # <class 'numpy.bool_'>
class example_client(CommClient): class example_client(CommClient):
...@@ -11,11 +12,11 @@ class example_client(CommClient): ...@@ -11,11 +12,11 @@ class example_client(CommClient):
def start(self): def start(self):
super().start() super().start()
def __init__(self, standby_func, fault_func, streams, try_interval=2): def __init__(self, fault_func, streams, try_interval=2):
""" """
initialises the class and tries to connect to the client. initialises the class and tries to connect to the client.
""" """
super().__init__(standby_func, fault_func, streams, try_interval) super().__init__(fault_func, streams, try_interval)
# Explicitly connect # Explicitly connect
if not self.connect(): if not self.connect():
...@@ -66,7 +67,6 @@ class example_client(CommClient): ...@@ -66,7 +67,6 @@ class example_client(CommClient):
return dims, dtype return dims, dtype
def _setup_mapping(self, dims, dtype): def _setup_mapping(self, dims, dtype):
""" """
takes all gathered data to configure and return the correct read and write functions takes all gathered data to configure and return the correct read and write functions
...@@ -85,7 +85,6 @@ class example_client(CommClient): ...@@ -85,7 +85,6 @@ class example_client(CommClient):
self.streams.debug_stream("created and bound example_client read/write functions to attribute_wrapper object") self.streams.debug_stream("created and bound example_client read/write functions to attribute_wrapper object")
return read_function, write_function return read_function, write_function
def setup_attribute(self, annotation=None, attribute=None): def setup_attribute(self, annotation=None, attribute=None):
""" """
MANDATORY function: is used by the attribute wrapper to get read/write functions. MANDATORY function: is used by the attribute wrapper to get read/write functions.
...@@ -103,4 +102,3 @@ class example_client(CommClient): ...@@ -103,4 +102,3 @@ class example_client(CommClient):
# return the read/write functions # return the read/write functions
return read_function, write_function return read_function, write_function
#! /usr/bin/env python3
import logging
def configure_logging():
# Always also log the hostname because it makes the origin of the log clear.
import socket
hostname = socket.gethostname()
# Set up logging in a way that it can be understood by a human reader, be
# easily grep'ed, be parsed with a couple of shell commands and
# easily fed into an Kibana/Elastic search system.
logging.basicConfig(format = '%(asctime)s.%(msecs)d %(levelname)s - HOST="{}" PID="%(process)d" TNAME="%(threadName)s" TID="%(thread)d" FILE="%(pathname)s" LINE="%(lineno)d" FUNC="%(funcName)s" MSG="%(message)s"'.format(hostname), datefmt = '%Y-%m-%dT%H:%M:%S', level = logging.INFO, Force = True)
...@@ -5,6 +5,7 @@ import numpy ...@@ -5,6 +5,7 @@ import numpy
from src.wrappers import only_when_on, fault_on_error from src.wrappers import only_when_on, fault_on_error
import logging import logging
logger = logging.getLogger() logger = logging.getLogger()
...@@ -23,8 +24,6 @@ class attribute_wrapper(attribute): ...@@ -23,8 +24,6 @@ class attribute_wrapper(attribute):
if "numpy" not in str(datatype) and type(datatype) != str: if "numpy" not in str(datatype) and type(datatype) != str:
raise TypeError("Attribute needs to be a Tango-supported numpy or str type, but has type \"%s\"" % (datatype,)) raise TypeError("Attribute needs to be a Tango-supported numpy or str type, but has type \"%s\"" % (datatype,))
self.comms_annotation = comms_annotation # store data that can be used by the comms interface. not used by the wrapper itself self.comms_annotation = comms_annotation # store data that can be used by the comms interface. not used by the wrapper itself
self.numpy_type = datatype # tango changes our attribute to their representation (E.g numpy.int64 becomes "DevLong64") self.numpy_type = datatype # tango changes our attribute to their representation (E.g numpy.int64 becomes "DevLong64")
...@@ -54,7 +53,6 @@ class attribute_wrapper(attribute): ...@@ -54,7 +53,6 @@ class attribute_wrapper(attribute):
# scalar, just set the single dimension # scalar, just set the single dimension
max_dim_x = 1 max_dim_x = 1
if access == AttrWriteType.READ_WRITE: if access == AttrWriteType.READ_WRITE:
""" if the attribute is of READ_WRITE type, assign the RW and write function to it""" """ if the attribute is of READ_WRITE type, assign the RW and write function to it"""
...@@ -68,8 +66,8 @@ class attribute_wrapper(attribute): ...@@ -68,8 +66,8 @@ class attribute_wrapper(attribute):
try: try:
return device.value_dict[self] return device.value_dict[self]
except Exception as e: except Exception as e:
raise Exception("Attribute read_RW function error, attempted to read value_dict with key: `%s`, are you sure this exists?", self) from e raise Exception("Attribute read_RW function error, attempted to read value_dict with key: `%s`, are you sure this exists?",
self) from e
@only_when_on @only_when_on
@fault_on_error @fault_on_error
...@@ -77,8 +75,11 @@ class attribute_wrapper(attribute): ...@@ -77,8 +75,11 @@ class attribute_wrapper(attribute):
""" """
_write_RW writes a value to this attribute _write_RW writes a value to this attribute
""" """
try:
self.write_function(value) self.write_function(value)
device.value_dict[self] = value device.value_dict[self] = value
except Exception as e:
raise e
self.fget = read_RW self.fget = read_RW
self.fset = write_RW self.fset = write_RW
...@@ -133,6 +134,7 @@ class attribute_wrapper(attribute): ...@@ -133,6 +134,7 @@ class attribute_wrapper(attribute):
except Exception as e: except Exception as e:
def pass_func(value=None): def pass_func(value=None):
pass pass
logger.error("setting comm_client failed. using pass function instead") logger.error("setting comm_client failed. using pass function instead")
self.read_function = pass_func self.read_function = pass_func
......
...@@ -3,6 +3,9 @@ import socket ...@@ -3,6 +3,9 @@ import socket
import time import time
import numpy import numpy
import opcua
from opcua import Client
from tango import DevState from tango import DevState
...@@ -11,11 +14,10 @@ class CommClient(Thread): ...@@ -11,11 +14,10 @@ class CommClient(Thread):
The ProtocolHandler class is the generic interface class between the tango attribute_wrapper and the outside world The ProtocolHandler class is the generic interface class between the tango attribute_wrapper and the outside world
""" """
def __init__(self, standby_func, fault_func, streams, try_interval=2): def __init__(self, fault_func, streams, try_interval=2):
""" """
""" """
self.standby_func = standby_func
self.fault_func = fault_func self.fault_func = fault_func
self.try_interval = try_interval self.try_interval = try_interval
self.streams = streams self.streams = streams
...@@ -45,14 +47,13 @@ class CommClient(Thread): ...@@ -45,14 +47,13 @@ class CommClient(Thread):
self.fault_func() self.fault_func()
return return
self.standby_func()
self.stopping = False self.stopping = False
while not self.stopping: while not self.stopping:
# keep trying to connect # keep trying to connect
if not self.connected: if not self.connected:
if self.connect(): if self.connect():
self.standby_func() # self.standby_func()
pass
else: else:
# we retry only once, to catch exotic network issues. if the infra or hardware is down, # we retry only once, to catch exotic network issues. if the infra or hardware is down,
# our device cannot help, and must be reinitialised after the infra or hardware is fixed. # our device cannot help, and must be reinitialised after the infra or hardware is fixed.
......
...@@ -17,7 +17,6 @@ from tango import DevState, DebugIt ...@@ -17,7 +17,6 @@ from tango import DevState, DebugIt
# Additional import # Additional import
from src.attribute_wrapper import * from src.attribute_wrapper import *
from src.lofar_logging import log_exceptions
__all__ = ["hardware_device"] __all__ = ["hardware_device"]
...@@ -60,7 +59,6 @@ class hardware_device(Device): ...@@ -60,7 +59,6 @@ class hardware_device(Device):
self.value_dict = {i: i.initial_value() for i in self.attr_list()} self.value_dict = {i: i.initial_value() for i in self.attr_list()}
@log_exceptions()
def init_device(self): def init_device(self):
""" Instantiates the device in the OFF state. """ """ Instantiates the device in the OFF state. """
...@@ -84,21 +82,22 @@ class hardware_device(Device): ...@@ -84,21 +82,22 @@ class hardware_device(Device):
""" """
self.set_state(DevState.INIT) self.set_state(DevState.INIT)
self.setup_value_dict() self.setup_value_dict()
self.initialise()
self.standby()
self.set_state(DevState.STANDBY)
@only_in_states([DevState.INIT])
def Standby(self):
"""
Command to ask for initialisation of this device. Can only be called in FAULT or OFF state.
:return:None self.initialise()
"""
self.standby()
self.set_state(DevState.STANDBY) self.set_state(DevState.STANDBY)
# @only_in_states([DevState.INIT])
# def Standby(self):
# """
# Command to ask for initialisation of this device. Can only be called in FAULT or OFF state.
#
# :return:None
# """
#
# self.standby()
# self.set_state(DevState.STANDBY)
@command() @command()
@only_in_states([DevState.STANDBY]) @only_in_states([DevState.STANDBY])
@DebugIt() @DebugIt()
...@@ -164,7 +163,6 @@ class hardware_device(Device): ...@@ -164,7 +163,6 @@ class hardware_device(Device):
"""Method always executed before any TANGO command is executed.""" """Method always executed before any TANGO command is executed."""
pass pass
@log_exceptions()
def delete_device(self): def delete_device(self):
"""Hook to delete resources allocated in init_device. """Hook to delete resources allocated in init_device.
......
#! /usr/bin/env python3
def startup(device: str, force_restart: bool):
'''
Start a LOFAR Tango device:
pcc = startup(device = 'LTS/PCC/1', force_restart = False)
'''
import tango
proxy = tango.DeviceProxy(device)
state = proxy.state()
if force_restart is True:
print("Forcing device {} restart.".format(device))
proxy.off()
state = proxy.state()
if state is not tango._tango.DevState.OFF:
print("Device {} cannot perform off although restart has been enforced, state = {}. Please investigate.".format(device, state))
return proxy
if state is not tango._tango.DevState.OFF:
print("Device {} is not in OFF state, cannot start it. state = {}".format(device, state))
return proxy
print("Device {} is in OFF, performing initialisation.".format(device))
proxy.initialise()
state = proxy.state()
if state is not tango._tango.DevState.STANDBY:
print("Device {} cannot perform initialise, state = {}. Please investigate.".format(device, state))
return proxy
print("Device {} is in STANDBY, performing on.".format(device))
proxy.on()
state = proxy.state()
if state is not tango._tango.DevState.ON:
print("Device {} cannot perform on, state = {}. Please investigate.".format(device, state))
else:
print("Device {} has successfully reached ON state.".format(device))
return proxy
...@@ -25,7 +25,6 @@ __all__ = ["test_device", "main"] ...@@ -25,7 +25,6 @@ __all__ = ["test_device", "main"]
class test_device(hardware_device): class test_device(hardware_device):
# ----------------- # -----------------
# Device Properties # Device Properties
# ----------------- # -----------------
...@@ -48,16 +47,20 @@ class test_device(hardware_device): ...@@ -48,16 +47,20 @@ class test_device(hardware_device):
bool_scalar_R = attribute_wrapper(comms_annotation="numpy.bool_ type read scalar", datatype=numpy.bool_) bool_scalar_R = attribute_wrapper(comms_annotation="numpy.bool_ type read scalar", datatype=numpy.bool_)
bool_scalar_RW = attribute_wrapper(comms_annotation="numpy.bool_ type read/write scalar", datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) bool_scalar_RW = attribute_wrapper(comms_annotation="numpy.bool_ type read/write scalar", datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
int64_spectrum_R = attribute_wrapper(comms_annotation="numpy.int64 type read spectrum (len = 8)", datatype=numpy.int64, dims=(8,)) int32_spectrum_R = attribute_wrapper(comms_annotation="numpy.int32 type read spectrum (len = 8)", datatype=numpy.int32, dims=(8,))
str_spectrum_RW = attribute_wrapper(comms_annotation="numpy.str type read/write spectrum (len = 8)", datatype=numpy.str_, dims=(8,), access=AttrWriteType.READ_WRITE) int32_spectrum_RW = attribute_wrapper(comms_annotation="numpy.int32 type read spectrum (len = 8)", datatype=numpy.int32, dims=(8,),
access=AttrWriteType.READ_WRITE)
double_image_R = attribute_wrapper(comms_annotation="numpy.double type read image (dims = 2x8)", datatype=numpy.double, dims=(2, 8)) double_image_R = attribute_wrapper(comms_annotation="numpy.double type read image (dims = 2x8)", datatype=numpy.double, dims=(2, 8))
double_image_RW = attribute_wrapper(comms_annotation="numpy.double type read/write image (dims = 8x2)", datatype=numpy.double, dims=(8, 2), access=AttrWriteType.READ_WRITE) double_image_RW = attribute_wrapper(comms_annotation="numpy.double type read/write image (dims = 8x2)", datatype=numpy.double, dims=(8, 2),
access=AttrWriteType.READ_WRITE)
int32_scalar_R = attribute_wrapper(comms_annotation="numpy.int32 type read scalar", datatype=numpy.int32) int32_scalar_R = attribute_wrapper(comms_annotation="numpy.int32 type read scalar", datatype=numpy.int32)
uint16_spectrum_RW = attribute_wrapper(comms_annotation="numpy.uint16 type read/write spectrum (len = 8)", datatype=numpy.uint16, dims=(8,), access=AttrWriteType.READ_WRITE) uint16_spectrum_RW = attribute_wrapper(comms_annotation="numpy.uint16 type read/write spectrum (len = 8)", datatype=numpy.uint16, dims=(8,),
access=AttrWriteType.READ_WRITE)
float32_image_R = attribute_wrapper(comms_annotation="numpy.float32 type read image (dims = 8x2)", datatype=numpy.float32, dims=(8, 2)) float32_image_R = attribute_wrapper(comms_annotation="numpy.float32 type read image (dims = 8x2)", datatype=numpy.float32, dims=(8, 2))
uint8_image_RW = attribute_wrapper(comms_annotation="numpy.uint8 type read/write image (dims = 2x8)", datatype=numpy.uint8, dims=(2, 8), access=AttrWriteType.READ_WRITE) uint8_image_RW = attribute_wrapper(comms_annotation="numpy.uint8 type read/write image (dims = 2x8)", datatype=numpy.uint8, dims=(2, 8),
access=AttrWriteType.READ_WRITE)
# -------- # --------
# overloaded functions # overloaded functions
...@@ -68,17 +71,16 @@ class test_device(hardware_device): ...@@ -68,17 +71,16 @@ class test_device(hardware_device):
self.set_state(DevState.INIT) self.set_state(DevState.INIT)
# set up the OPC ua client # set up the OPC ua client
self.example_client = example_client(self.Standby, self.Fault, self) self.example_client = example_client(self.Fault, self)
# map an access helper class # map an access helper class
for i in self.attr_list(): for i in self.attr_list():
i.set_comm_client(self.example_client) i.set_comm_client(self.example_client)
self.example_client.start() self.example_client.start()
# ---------- # ----------
# Run server # Run server
# ---------- # ----------
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment