TANGO training
How to develop
a TANGO device
Preamble
Ambition
– Approaching different steps of a device
development
– Handling the tools
Collective approach
– Operating concepts of session I
– A C++ example
Individual approach
– Read the documentation !
• Tutorial C++ & Java
• Many implementation details
The example
Servers…
– device BeamImage
• Beam image (made in the plan of 1 screen)
• Supposed to be linked to a camera (with on/off ctrl )
• Params : size (pixels) , scaling (mm/pixel)
– device BeamDim
•
•
•
•
Profiles and size of beam
Logical device (SC service)
Analysis of the image produced by BeamImage
Params : image source (device)
The client(s)…
– Matlab and/or Igor Pro and/or DeviceTree
E1 : Definition of interfaces
Preliminary essential step
– Led by the clients’ need
– Functionalities and/or datas to «export» ?
Contract with the clients
– Attractive choice
– Strong link with non generic clients
Elementary choices
– Commands, Attributes, Ownerships
– Command or Attribute ?
• command ~ action
• attribute ~ physical size «monitorable»
E1 : BeamImage : interface
6 Commands
–
–
–
–
–
–
void SetImageSize(long)
long GetImageSize(void)
void SetImageScaling(double)
double GetImageScaling(void)
void SwitchOn (void)
void SwitchOff (void)
size pixels
size pixels
(size * scaling) mm
(size * scaling) mm
E1 : BeamImage : interface
3 Attributes
– size
• WRITE, SCALAR, LONG
– scaling
• READ_WRITE, SCALAR, DOUBLE
– bimage
• READ, IMAGE, LONG
size pixels
size pixels
(size * scaling) mm
(size * scaling) mm
E1 : BeamImage : interface
2 States
– ON
• Camera ON
• All commands authorized except SwitchOn
• Reading image authorized
– OFF
• Camera OFF
• No authorized command except SwitchOn
• Reading image forbidden
– TANGO
• State management -> command execution
• No state management -> reading/writing attribute
E1 : BeamDim : interface
2 Commands
• string GetImageSource(void)
• void SetImageSource(string)
E1 : BeamDim : interface
4 Attributes
– x_profil & y_profil
• READ, SPECTRUM, LONG
– x_dim & y_dim
• READ, SCALAR, DOUBLE
x_profil
x_dim
E2 : Code generation
POGO
– The Program Obviously used to Generate Tango
Objects
– Java Application
• Win32, Linux, Sun-Solaris
– Code generator
• C++ or Java
– Devices skeleton
• Commands, Attributes, Ownerships, States
– To launch POGO under Windows…
• %SOLEIL_ROOT%\tango\win32\script\start-pogo.bat
E2 : POGO : Prog. Language
E2 : POGO : New Project
E2 : POGO : New Project
Classe du device
E2 : POGO : New Project
E2 : POGO : States
class BeamImage interface : états
-ON : Camera on
-OFF : Camera off
E2 : POGO : Commands
class BeamImage interface : commands
Tango::DEV_VOID SetImageSize(Tango::DEV_LONG)
- allowed for states: ON
Tango::DEV_LONG GetImageSize(Tango::DEV_VOID)
- allowed for states: ON
Tango::DEV_VOID SetImageScaling(Tango::DEV_DOUBLE)
- allowed for states: ON,OFF
Tango::DEV_DOUBLE GetImageScaling(Tango::DEV_VOID)
- allowed for states: ON,OFF
Tango::DEV_VOID SwitchOn(Tango::DEV_VOID)
– allowed for states: OFF
Tango::DEV_VOID SwitchOff(Tango::DEV_VOID)
– allowed for states: ON
E2 : POGO : Attributes
class BeamImage interface : attributes
–size
•WRITE, SCALAR, LONG
•Val_Min = 100, Val_Max = 500, Unit = pixels
•Write allowed for states : ON
–scaling
•READ_WRITE, SCALAR, DOUBLE
•Val_Min = 0.001, Val_Max = 10, Unit = mm/pixel
•Read/Write allowed for states : ON, OFF
–image
•READ, IMAGE, LONG
•Read allowed for states : ON
E2 : POGO : Code generation
E2 : POGO : Doc generation
E3 : Compilation
Creating the working environment
– Positioning the variables of environnement
• %SOLEIL_ROOT%\env\win32\envSOLEIL.bat
• executing this script in a console
– Copying and modifying the Makefile
• %SOLEIL_ROOT%\env\win32\Makefile.VC
• copying to the directory of the device
• editing : device_server = BeamImage
Compiler
– nmake –f MakeFile.VC all
– nmake –f MakeFile.VC clean
E3 : Compilation
Where is the result of the
compilation ?
– Intermediate files
• C:\TEMP\{USER NAME}\{DEVICE NAME}
– Executable
• C:\DeviceServers\ds_{DEVICE NAME}.exe
E4 : Execution
Syntax
– {EXEC NAME} {INSTANCE NAME} [-v{VERBOSE LEVEL}]
• {EXEC NAME} = name of the binary
• {INSTANCE NAME} = name of the device instance
– C:\DeviceServers\ds_BeamImage 1 –v4
E4 : Execution
Syntax
– {EXEC NAME} {INSTANCE NAME} [-v {VERBOSE LEVEL}]
• {EXEC NAME} = name of the binary
• {INSTANCE NAME} = instance name of the device
– C:\ds_BeamImage 1 –v4
Oups!
– The device server ds_BeamImage/1 is not defined in
database. Exiting!
– Save the server in the TANGO database
• Jive : %SOLEIL_ROOT%\win32\script\start-jive.bat
– Option –nodb (cf. TANGO programmer’s manual)
E4 : Execution (recording)
E4 : Execution (recording)
E4 : Execution
Second attempt
– {EXEC NAME} {INSTANCE NAME} [-v {VERBOSE
LEVEL}]
• {EXEC NAME} = name of the binary
• {INSTANCE NAME} = instance name of the device
– C:\ds_BeamImage 1 –v4
E4 : Execution
Second attempt
– {EXEC NAME} {INSTANCE NAME} [-v {VERBOSE
LEVEL}]
• {EXEC NAME} = name of the binary
• {INSTANCE NAME} = instance name of the device
– C:\ds_BeamImage 1 –v4
This time …
– Ready to accept request
– Device waiting for external requests
– Integrated into the control system
• Appreciate what is done for you !
E4 : Execution
Test
– Generic client : DeviceTree, Igor Pro, Matlab
At this stage …
– The device runs but does nothing
– The interface remains to be implemented
• Do what you declare doing !
E5 : Implementation
What is POGO ?
– Basic code of the device : 6 files
• main.cpp
– initialisation of the process and activation of the device
• ClassFactory.cpp
– Internal cooking of TANGO (extra load via linker)
Free !
• {BeamImage}Class.h
• {BeamImage}Class.cpp
– header and impl. of the class (in the TANGO sense) of BeamImage
devices.
– Implement a « BeamImage factory »
– Instanciation of devices , commands, attributes
– States management (for the execution of commands only!)
– Reading/writing of «class properties» in the TANGO database
Not expensive !
• {BeamImage}.h
• {BeamImage}.cpp
– «Implementation class» of BeamImage devices
– Implementation of the interface : role of the developer !
E4 : Implementation
What is POGO generating (continuation) ?
– The « glue» allowing to integrate the device to SC
– An «empty» implementation of the device !
Developer role
– Implementing the specific code (acquisition, calculation,
simulation, …)
– Linking this code to the TANGO interface (generated by
POGO)
E5 : Implementation
S
C
SOLEIL Control
system
(applications network)
S
C
S
C
S
C
client application.
S
Server application.
POGO
TANGO
Developer
Application logic
Material
Supplier
(driver, lib, …)
E5 : Implementation
To do …
–
–
–
–
Implementing the commands
Implementing reading/writing of attributes
Managing the states
Taking into account the ownerships (stored in
the database)
Where to intervene?
– {DeviceClassName}.h
et {DeviceClassName}.cpp
– Here : BeamImage.h et BeamImage.cpp
E5 : Implementation : command
Execution command :
– Tango::DEV_LONG SetImageSize(Tango::DEV_LONG)
BeamImage
(CORBA Obj.)
BeamImageClass
(Device Class)
SetImageSize
(Command)
BeamImage
(Device Impl.)
command_inout
CORBA::Any
command_handler
CORBA::Any
always_executed_hook
is_allowed
execute
CORBA::Any
CORBA::Any
CORBA::Any
CORBA::Any
set_image_size
Tango::DevLong
Tango::DevLong
E5 : Implementation : command
BeamImage.h
/**
* Turns the camera on
* @exception DevFailed
*/
void switch_on();
BeamImage.cpp
//------------------------------------------------------------// method: BeamImage::switch_on
// description: method to execute "SwitchOn"
//
Turns the camera on
//------------------------------------------------------------void BeamImage::switch_on()
{
cout2 << "BeamImage::switch_on(): entering... !" << endl;
// Add your own code to control device here
}
E5 : Implementation : command
BeamImage.h
/**
* Turns the camera on
* @exception DevFailed
*/
void switch_on();
BeamImage.cpp
//------------------------------------------------------------// method: BeamImage::switch_on
// description: method to execute "SwitchOn"
//
Turns the camera on
//------------------------------------------------------------void BeamImage::switch_on()
{
cout2 << "BeamImage::switch_on(): entering... !" << endl;
// Add your own code to control device here
set_state(Tango::ON);
set_status(‘Device up and ready (camera is on)’);
}
The TANGO command «SwitchOn» is implemented !
E5 : Implementation : command
Main difficulties
– Client/server exchange
• Device client of a device (cf. BeamDim)
– Rules of management of the memory in C++
• Allocation/De-allocation (Ownership)
– CORBA (for certain types)
• Strings, Sequences, Any (insertion/extraction)
– Section 7.2 of the Tango programmer’s guide
• Read this or die !
– An example (a model)
• Device TangoTest
• An ex. of command for each TANGO type
E5 : Implementation : command
Management of
– C++ Exceptions
errors
• spread towards the client (CORBA)
– Generic exception
• Tango: DevFailed
• Reason, Description, Origin, Severity
– Other exceptions (more semantic)
• ConnectionFailed, CommunicationFailed, …
– Section 7.2.4 of the programmer’s guide
E5 : Implementation : command
Management of errors (example)
// Allocate image buffer
image_buffer = new Tango::DevLong[new_size];
// Check allocation
if (image_buffer == 0) {
TangoSys_OMemStream o;
o << "Failed to allocate beam image buffer" << ends;
LOG_ERROR((o.str()));
Tango::Except::throw_exception(
(const char *)"Out of memory error",
o.str(),
(const char *)"BeamImage::set_image_size");
}
E5 : Implementation : command
Management of errors (example)
Tango::DeviceProxy *isource = …
try {
Tango::DeviceData dd;
dd = isource->command_inout(“GetImageScaling”);
}
cacth (Tango::DevFailed& ex) {
TangoSys_OMemStream o;
o << "Failed to execute GetImageScaling" << ends;
LOG_ERROR((o.str()));
Tango::Except::re_throw_exception(
ex,
(const char *)"Tango command failed",
o.str(),
(const char *)"BeamDim::read_attr_hardware");
}
E5 : Implementation : command
E5 : Implementation : attributes
Tricks to know…
– The developer «handles» data associated to the
attribute, not the attribute itself !
– Variables member of the implementation class with the
type of the attribute (and not instances of the Tango
class :Attribute)
– For a READ attribute, the associated variable member
represents the current value of the attribute (i.e. last
value read on the hardware)
– For a WRITE attribute, it represents the value of the
instruction (i.e. value to «write» on the hardware)
– Current implementation of TANGO
• item being discussed
• re-implementation considered
E5 : Implementation : attributes
READ attribute
–
–
–
–
1 variable member of the implementation class
name : attr_{ATTR NAME}_read
type : pointer on the attribute type
Ex : image attribute of a BeamImage device
• BeamImage.h (header of the BeamImage class )
– POGO code : Tango::DevLong *attr_image_read;
• BeamImage.cpp (impl. de la classe BeamImage)
– POGO code : Nothing !
– Data associated to the attribute must be instanced
– attr_image_read = new Tango::DevLong[size*size];
– Beware of memory leaks (init_device vs delete_device) !
E5 : Implementation : attributes
Reading mecanism
BeamImage
(Device Impl.)
BeamImage
(CORBA Obj.)
read_attributes(Attr1, Attr2)
always_executed_hook
read_attr_hardware (Attr1, Attr2)
read_attr (Attr1)
read_attr (Attr2)
E5 : Implementation : attributes
Reading mecanism
– About read_attribut_hardware…
• 1 call for the n attributes to read
• object : reading the hardware only once
• update of variable members of the type <…_read>
– About read_attr…
• 1 call per attribute to read
• object : affected a value to the attribute
• associating the attribute and the variable member
which represents it
– attr.set_value(attr_image_read, size, size)
E5 : Implementation : attributes
WRITE attribute
– 1 variable member of the implementation class
– name : attr_{ATTR NAME}_write
• POGO 1.33 imperfection : also generates
attr_{ATTR NAME}_read (do not take into account)
– type : attribute type
– Ex : attribute size of a BeamImage device
• BeamImage.h (header of the BeamImage class )
– POGO code : Tango::DevLong attr_size_write;
• BeamImage.cpp (impl. of the BeamImage class )
– POGO code : Nothing !
– attr_size_write = initialSize;
E5 : Implementation : attributes
Writing mecanism
BeamImage
(Device Impl.)
BeamImage
(CORBA Obj.)
write_attributes(Attr1, Attr2)
always_executed_hook
write_attr_hardware (Attr1, Attr2)
E5 : Implementation : attributes
Writing mecanism
– About write_attribut_hardware…
• 1 call for n attributes to write
• object : «writing» on the hardware (instruction)
• update of variable members of type <…_write>
– attr.get_write_value(attr_size_write)
• exception removed beforehand (by TANGO) if …
– val_min > valeur_utilisateur
• or
– Valeur_utilisateur > val_max
• In that case …
– no call to write_attribut_hardware !
– for no attribute !
E5 : Implementation : attributes
READ_WRITE attribute
– READ_WRITE = READ + WRITE
• 2 variables member of the implementation class
• instruction vs real value
• <read part>
– name : attr_{ATTR NAME}_read
– type : pointer on the attribute type
• <write part>
– name : attr_{ATTR NAME}_write
– type : attribute type
– Ex : attribute scaling of a BeamImage device
• BeamImage.h (header of the BeamImage class)
– Tango::DevDouble *attr_scaling_read;
– Tango::DevDouble attr_scaling_write;
• BeamImage.cpp (impl. of the BeamImage class )
– POGO code : Nothing !
– attr_scaling_read = new Tango::DevDouble;
– attr_scaling_write = initialScaling;
E5 : Implementation : attributes
E5 : Implementation :
miscellaneous
About the init_device…
– Method linked to the initialisation of a device
– Contents
• Everything in line with the device init
– Instanciations and memory allocations
– Reading of the properties from the TANGO database
– A constraint …
• The exec of the TANGO Init commands (on the
DServer and/or the device) causes the one of
<init_device>
• Memory leaks !
– A reflex …
• Overload delete_device
• De-allott everyting (re)allotted by init_device
E5 : Implementation :
miscellaneous
Case of a «device-client»
– A device client of another device
– Use API C++
• Class Tango: DeviceProxy
• Cf. Section 5 of the programmer’s guide
– An exemple : the BeamDim device
•
•
•
•
•
•
•
•
•
•
std::string source_name(“formation-tango/beamimage/user0”);
Tango::DeviceProxy *image_source;
//connect to source
image_source = new Tango::DeviceProxy(source_name);
Tango::DeviceAttribute result;
//read image attribut
result = image_source->read_attribute(“image”);
//extract image from generic container into a std::vector
std::vector<Tango::DevLong> image;
result >> image;
© Copyright 2026 Paperzz