Initialising your SKA Tango device
Prefer init_device to __init__
Note
SKABaseDevice provides a
deprecated mechanism to provide device initialisation by overriding an
InitCommand
object.
In order to use init_device as described here you must set
InitCommand to None to acknowledge the deprecation.
See SKA command objects deprecated for more details.
In general, initialisation of a Tango device should be done in the init_device()
method as this allows clients to “re-initialise” the device via the built-in
Init() command. For example, the following device starts a background thread
and opens a socket connect
class MyDevice(LRCMixin, SKADevice):
HardwareHost = device_property(dtype=str, mandatory=True)
HardwarePort = device_property(dtype=int, mandatory=True)
def init_device(self) -> None:
# device properties are read from the Tango database here:
super().init_device()
# TODO: Handle connection failure
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((self.HardwareHost, self.HardwarePort))
self.stop_event = threading.Event # To signal to the background thread to stop
self.background_thread = threading.Thread(target=self._run_background_thread)
self.background_thread.start()
def _run_background_thread(self) -> None:
# All threads should be made an omnithread:
with tango.EnsureOmniThread():
...
Tip
Don’t forget to call super().init_device()! Typically, this should
be done before your code.
Clean up resources in delete_device
All resources allocated during :py:func`!init_device` should be reclaimed during the
delete_device() method. In other words, all threads must be
joined, files/sockets closed etc.
As we are using python, we don’t have to worry about the python objects themselves being reclaimed as this will be handled by the python interpreter automatically.
For the example device above, we need to join the thread and close the socket:
class MyDevice(LRCMixin, SKADevice):
...
def delete_device(self) -> None:
self.stop_event.set()
with self.allow_internal_threads():
self.background_thread.join()
self.socket.close()
super().delete_device()
Tip
Don’t forget to call super().delete_device()! Typically, this should
be done after your code.
Tip
When joining a thread that needs to interact with the Tango device, use
allow_internal_threads()
to avoid a deadlock. This will release the Tango device monitor lock,
allowing the thread being joined to acquire the monitor lock, but it
will not allow new client requests to start.
Call init_completed when inheriting from SKABaseDevice
When inheriting from SKABaseDevice,
the super().init_device() will set the device state to INIT.
You are then responsible for calling
init_completed() once
initialisation has finished. This will then transition the device state
according to the operational state model.
It is possible to call
init_completed() some
time later if your device has a long running initialisation process.
For example, the following device calls
init_completed()
immediately from its init_device():
class MyDevice(SKABaseDevice[MyComponentManager]):
InitCommand = None
def init_device(self) -> None:
super().init_device()
self.init_completed()