Skip to main content
Ctrl+K
Tango Controls documentation - Home Tango Controls documentation - Home
  • Explanation
    • Overview of Tango Controls
    • Device
    • Command
    • Attribute
    • Property
    • Events
    • Device polling
    • Tango object naming (device, attribute and property)
    • Tango Data Model
    • Tango Database
    • Attribute alarms
    • Archiving
      • HDB++
      • SNAP
    • Pipe
    • Threading
    • Communication paradigms
    • The Tango device server model
    • Long Term Support
    • History
  • Tutorials
    • Getting started
      • Coffee Crisis!
      • First steps
      • State and Status
      • Init and Delete Device
      • About and version info
      • Commands
      • Attributes
      • Device properties
      • Running a Tango Database
      • Adding a new server to the Tango Database
    • Example deployment of a Tango Controls System
    • ATKPanel
    • Developing clients with the TangoATK
    • Guidelines for developing a Tango Device Server
    • Developing a Tango device server
  • How-Tos
    • Installation
      • Conda Packages
      • Debian
      • Red Hat based
      • Windows
      • macOS
      • Virtual Machine
      • TangoBox 9.3
      • SNAPshot (Archiving) installation and configuration
    • Getting Started
      • How to try Tango Controls
      • Use the end-user applications
      • Start a device server
      • Configure properties on a new device
    • Deployment
      • Transfer events using the multicast protocol
      • Use multiple database servers within a Tango control system
      • Use the property file
      • Use the Starter device
      • Run a device server with the File Database
      • Starting a Tango control system
      • Run a device server without a database
      • Use the Tango controlled access system
      • Import multiple device classes to the Catalogue
      • Use Tango with systemd integration
      • Run a device server with an active Windows firewall
    • Development
      • Create your first Device class
      • Write your first Tango client
      • Generate events in a device server
      • Tune polling from inside device classes
      • Telemetry with Tango
      • Transfer images
      • Get started with cppTango
        • Quick start: create and start a device
        • Write your first C++ TANGO device class
        • Device server with user defined event loop
        • How to create inheritance link between Tango classes
        • Use C++ std::vector to set attributes
        • How to add dynamic attributes to a device class
        • Handle Tango string attributes in C++
        • How to reconnect to the Tango HOST at device server startup time
        • How to use an enumerated attribute
        • How to use a forwarded attribute
        • How to use a memorized attribute
        • How to work with device and attribute aliases
        • Writing a TANGO client using TANGO C++ APIs
      • Getting started with JTango (Java implementation of Tango-Controls)
        • Developing your first Java TANGO client
        • Developing your first Java TANGO device class
        • Integrate Java Tango servers with Astor
      • Getting started with PyTango (Python implementation of Tango-Controls)
        • Developing Python TANGO device class
        • How to PyTango
        • PyTangoArchiving Recipes
    • Debugging and Testing
      • Using Tango docker containers
      • JUNIT helper classes for device server testing
    • Contributing
      • Tango IDL
      • cppTango
      • PyTango
      • JTango
      • Tango Documentation
      • How to add a subproject to the readthedocs tango-controls documentation
  • Tools
    • Developer’s Toolkit
    • Tango Application Toolkit “ATK”
    • Astor
    • Jive
    • Starter
    • LogViewer
      • LogViewer
    • Tango Admin utility
    • JDraw
    • ITango
    • Taurus (Python GUI library)
    • PANIC Alarm System
    • POGO
    • Bensikin User Manual
    • Taranta
    • Tango REST API
  • Reference
    • RFC
    • Ecosystem
    • Tango Core: C++
    • Tango Core: Python
    • Tango Core: Java
    • Bindings
      • C Language
      • Igor Pro
      • LabVIEW
      • Matlab & Octave
      • REST API
    • ATK Java documentation
    • Glossary
    • Reference part
    • CORBA
    • HDB++ Design and implementation
    • Legacy HDB tables structure
    • schema CQL source (Cassandra)
    • Configuration Manager interface
    • Event Subscriber interface
    • schema SQL source (MySQL)
    • schema SQL source (TimescaleDb)
    • Old Presentations
      • Scada introduction with TANGO examples
      • General TANGO training for C++
      • General TANGO training for Python
  • Authors
  • Show source
  • Suggest edit
  • .md

How to create inheritance link between Tango classes

Contents

  • The example case
  • The HighLevelClass.h file
  • The HighLevelClass.cpp file
  • The HighLevel.h file
  • The HighLevel.cpp file
  • Conclusion

How to create inheritance link between Tango classes#

audience:developers lang:c++

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:

  1. The high level class supports all the commands/attributes defined in the low level class on top of its own (if any),

  2. 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:

  1. The HighLevelClass constructor

  2. The HighLevelClass command_factory() method

  3. 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:

  1. Change the HighLevel class inheritance from TANGO_BASE_CLASS to LowLevel_ns::LowLevel

  2. Add a new data member in the HighLevel class in order to correctly implement the device Init command (a boolean is enough)

  3. 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

  1. The HighLevel class constructors to reflect the change in its inheritance and to initialize the new data member device_constructed

  2. The HighLevel class delete_device() and init_device() to correctly handle the device Init command

  3. The HighLevel class always_executed_hook() and read_attr_hardware() methods in order that they call the corresponding LowLevel 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.

previous

Device server with user defined event loop

next

Use C++ std::vector to set attributes

Contents
  • The example case
  • The HighLevelClass.h file
  • The HighLevelClass.cpp file
  • The HighLevel.h file
  • The HighLevel.cpp file
  • Conclusion
© Copyright 2017-2025, Tango Controls Community, under Creative Commons Attribution 4.0 International (CC BY 4.0), except where otherwise noted.