How to create inheritance link between Tango classes#
This howto explains how to create a new Tango device class which inherits from an already existing one.
We use the usual definition of inheritance from object oriented programming:
The high level class supports all the commands/attributes defined in the low level class on top of its own (if any),
The device(s) available for the external world are an instances of the high level class.
Warning
Once modified, Pogo will not be able to understand the high level Tango class and therefore can’t be used for further changes in this class
The example case#
Let’s say that we already have a Tango class called LowLevel
with
one command called LowLevelCmd
and one attribute called
LowLevelAttr
. We want to create a new Tango class called HighLevel
with its own command called HighLevelCmd
and its own attribute called
HighLevelAttr
. Both classes have been generated using Pogo. The
following is a description of what has to be modified in the code
generated by Pogo for the HighLevel
Tango class in order to create the
inheritance link.
The HighLevelClass.h file#
In this file, we will modify the HighLevelClass
declaration in order to inherit from the LowLevelClass
class instead of TANGO_BASE_CLASS
but we first need to add an extra include file at the file beginning:
1#ifndef _HIGHLEVELCLASS_H
2#define _HIGHLEVELCLASS_H
3
4#include <tango.h>
5#include <HighLevel.h>
6
7#include <LowLevelClass.h>
Then, we change the HighLevelClass inheritance declaration:
1//
2// The HighLevelClass singleton definition
3//
4
5class
6#ifdef WIN32
7 __declspec(dllexport)
8#endif
9HighLevelClass : public LowLevel_ns::LowLevelClass
10{
11public:
12// properties member data
13
14// add your own data members here
15//------------------------------------
The HighLevelClass.cpp file#
In this file, we have to modify:
The HighLevelClass constructor
The HighLevelClass command_factory() method
The HighLevelClass attribute_factory() method
1//+----------------------------------------------------------------------------
2//
3// method : HighLevelClass::HighLevelClass(std::string &s)
4//
5// description : constructor for the HighLevelClass
6//
7// in : - s : The class name
8//
9//-----------------------------------------------------------------------------
10HighLevelClass::HighLevelClass(std::string &s)
11: LowLevel_ns::LowLevelClass(s)
12{
13 TANGO_LOG_INFO << "Entering HighLevelClass constructor" << std::endl;
14 set_default_property();
15 get_class_property();
16 write_class_property();
17
18 TANGO_LOG_INFO << "Leaving HighLevelClass constructor" << std::endl;
19}
Then, the changes in the command_factory() method which needs to call the LowLevelClass command_factory() method:
1//+----------------------------------------------------------------------------
2//
3// method : HighLevelClass::command_factory
4//
5// description : Create the command object(s) and store them in the
6// command list
7//
8//-----------------------------------------------------------------------------
9void HighLevelClass::command_factory()
10{
11 LowLevel_ns::LowLevelClass::command_factory();
12
13 command_list.push_back(new HighLevelCmdClass("HighLevelCmd",
14 Tango::DEV_VOID, Tango::DEV_VOID,
15 "",
16 "",
17 Tango::OPERATOR));
18
19 // add polling if any
20 for(size_t i = 0 ; i < command_list.size(); i++)
21 {
22 // ...
23 }
24}
Finally, the changes in the attribute_factory() method which needs to call the LowLevelClass attribute_factory() method:
1//+----------------------------------------------------------------------------
2// Method: HighLevelClass::attribute_factory(std::vector<Tango::Attr *> &att_list)
3//-----------------------------------------------------------------------------
4void HighLevelClass::attribute_factory(std::vector<Tango::Attr *> &att_list)
5{
6 LowLevel_ns::LowLevelClass::attribute_factory(att_list);
7
8 // Attribute : HighLevelAttr
9 HighLevelAttrAttrib *high_level_attr = new HighLevelAttrAttrib();
10 // ...
11 att_list.push_back(high_level_attr);
12}
The HighLevel.h file#
This file has to be modified in order to:
Change the
HighLevel
class inheritance fromTANGO_BASE_CLASS
toLowLevel_ns::LowLevel
Add a new data member in the
HighLevel
class in order to correctly implement the deviceInit
command (a boolean is enough)Modify the class destructor for a correct management of the device
Init
command
First, we have to add a new include file:
1#ifndef _HIGHLEVEL_H
2#define _HIGHLEVEL_H
3
4#include <tango.h>
5#include <LowLevel.h>
Then, the change in the HighLevel class inheritance:
1class HighLevel: public LowLevel_ns::LowLevel
2{
3public :
4 // Add your own data members here
5 //-----------------------------------------
The addition of the new data member at the end of the HighLevel class declaration:
1protected :
2 // Add your own data members here
3 //-----------------------------------------
4 bool device_constructed{false};
5}
And finally, the change in the HighLevel class destructor:
1/**
2 * The object desctructor.
3 */
4 ~HighLevel()
5 {
6 delete_device();
7 }
The HighLevel.cpp file#
In this file, we have to modify
The HighLevel class constructors to reflect the change in its inheritance and to initialize the new data member
device_constructed
The HighLevel class
delete_device()
andinit_device()
to correctly handle the deviceInit
commandThe HighLevel class
always_executed_hook()
andread_attr_hardware()
methods in order that they call the correspondingLowLevel
class method
Let’s start with the changes in the HighLevel class constructors:
1//+----------------------------------------------------------------------------
2//
3// method : HighLevel::HighLevel(string &s)
4//
5// description : constructor for HighLevel
6//
7// in : - cl : Pointer to the DeviceClass object
8// - s : Device name
9// - d : Description
10//
11//-----------------------------------------------------------------------------
12HighLevel::HighLevel(Tango::DeviceClass *cl, std::string &s)
13 :LowLevel_ns::LowLevel(cl, s.c_str())
14{
15 init_device();
16 device_constructed = true;
17}
18
19HighLevel::HighLevel(Tango::DeviceClass *cl, const char *s)
20 :LowLevel_ns::LowLevel(cl, s)
21{
22 init_device();
23 device_constructed = true;
24}
25
26HighLevel::HighLevel(Tango::DeviceClass *cl, const char *s, const char *d)
27 :LowLevel_ns::LowLevel(cl, s, d)
28{
29 init_device();
30 device_constructed = true;
31}
Now, the modified HighLevel class init_device()
and delete_device()
methods:
1//+----------------------------------------------------------------------------
2//
3// method : HighLevel::delete_device()
4//
5// description : will be called at device destruction or at init command.
6//
7//-----------------------------------------------------------------------------
8void HighLevel::delete_device()
9{
10 TANGO_LOG_INFO << "HighLevel::delete_device()" << std::endl;
11
12 // Delete device's allocated object
13
14 if(device_constructed)
15 {
16 LowLevel_ns::LowLevel::delete_device();
17 }
18}
19
20//+----------------------------------------------------------------------------
21//
22// method : HighLevel::init_device()
23//
24// description : will be called at device initialization.
25//
26//-----------------------------------------------------------------------------
27void HighLevel::init_device()
28{
29 if(device_constructed)
30 {
31 LowLevel_ns::LowLevel::init_device();
32 }
33
34 TANGO_LOG_INFO << "HighLevel::HighLevel() create device " << device_name << std::endl;
35 // ...
And finally, the HighLevel class always_executed_hook()
and read_attr_hardware()
methods:
1//+----------------------------------------------------------------------------
2//
3// method : HighLevel::always_executed_hook()
4//
5// description : method always executed before any command is executed
6//
7//-----------------------------------------------------------------------------
8void HighLevel::always_executed_hook()
9{
10 LowLevel_ns::LowLevel::always_executed_hook();
11 TANGO_LOG_INFO << "HighLevel::always_executed_hook()" << std::endl;
12 // ...
13}
14
15//+----------------------------------------------------------------------------
16//
17// method : HighLevel::read_attr_hardware
18//
19// description : Hardware acquisition for attributes.
20//
21//-----------------------------------------------------------------------------
22void HighLevel::read_attr_hardware(std::vector<long> &attr_list)
23{
24 LowLevel_ns::LowLevel::read_attr_hardware(attr_list);
25 TANGO_DEBUG_LOG << "HighLevel::read_attr_hardware(std::vector<long> &attr_list) entering... " << std::endl;
26 // ...
27}
Don’t forget to also modify CMakeLists.txt
in order to link the three
LowLevel Tango class object files (Lowlevel.o, LowLevelClass.o and
LowLevelStateMachine.o) to your executable.
The HighLevel
class can be registered and started with the usual approach by
Jive or tango_admin.
Conclusion#
With these relatively simple changes in the HighLevel class, we now have a device instance of a Tango class which “inherits” from another Tango class. The drawback of this method is that once the file has been modified, Pogo will not be able to understand the HighLevel class any more and should not be used for further changes in this class!
With a couple of virtual
methods, it is also possible in the HighLevel
class to overwrite a command or an attribute defined in the Lowlevel class.