Subsections
The quickest way of getting started is by studying this example:
-
- /*
* Example of a client using the TANGO Api
*/
import fr.esrf.Tango.*;
import fr.esrf.TangoDs.*;
import fr.esrf.TangoApi.*;
public class TestDevice
{
public static void main (String args[])
{
try
{
// Connect to the device.
DeviceProxy dev = new DeviceProxy(my/serial/device);
// Send a write command to the device
DeviceData argin = new DeviceData();
argin.insert(Hello World !);
dev.command_inout(DevWriteMessage, argin);
// Send a read command to the device
DeviceData argout = dev.command_inout(DevReadMessage);
String received = argout.extractString();
System.out.println(received);
// Read a device attribute (double data type)
DeviceAttribute da = dev.read_attribute(TheAttr);
System.out.println(\nRead + da.extractDouble() + on + dev.getName());
}
catch (DevFailed e)
{
Except.print_exception(e);
}
}
}
Modify this example to fit your device server or client's needs, compile
it.
Do not forget when you start it to set the parameter TANGO_HOST with
<host_name>:<port_number>
(i.e. java -DTANGO_HOST=tango:20000 TestDevice).
And forget about those painful early Tango days when you had to learn
CORBA and manipulate Any's.
Life is going to easy and fun from now on.
The quickest way of getting started is by studying this
example :
-
- /*
* example of a client using the TANGO C++ api.
*/
#include <tango.h>
using namespace Tango;
int main(unsigned int argc, char **argv)
{
try
{
//
// create a connection to a TANGO device
//
DeviceProxy *device = new DeviceProxy(``sys/database/2'');
//
// Ping the device
//
device->ping();
//
// Execute a command on the device and extract the reply as a string
//
string db_info;
DeviceData cmd_reply;
cmd_reply = device->command_inout(``DbInfo'');
cmd_reply >> db_info;
cout << ``Command reply `` << db_info << endl;
//
// Read a device attribute (string data type)
//
string spr;
DeviceAttribute att_reply;
att_reply = device->read_attribute(``StoredProcedureRelease'');
att_reply >> spr;
cout << ``Database device stored procedure release: `` << spr << endl;
}
catch (DevFailed &e)
{
Except::print_exception(e);
exit(-1);
}
}
Modify this example to fit your device server or client's
needs, compile it and link with the library -ltango. Forget about
those painful early TANGO days when you had to learn CORBA and manipulate
Any's. Life's going to easy and fun from now on !
The code given in this chapter as example has been generated using
POGO. Pogo is a code generator for Tango device server.
See [15] for more information about POGO. The following
examples briefly describe how to write device class with commands
which receives and return different kind of Tango data types and also
how to write device attributes The device class
implements 5 commands and 3 attributes. The commands are :
- The command DevSimple deals with simple Tango data type
- The command DevString deals with Tango strings
- DevArray receive and return an array of simple Tango data
type
- DevStrArray which does not receive any data but which returns
an array of strings
- DevStruct which also does not receive data but which returns
one of the two Tango composed types (DevVarDoubleStringArray)
For all these commands, the default behavior of the state machine
(command always allowed) is acceptable. The attributes are :
- A spectrum type attribute of the Tango string type called StrAttr
- A readable attribute of the Tango::DevLong type called LongRdAttr.
This attribute is linked with the following writable attribute
- A writable attribute also of the Tango::DevLong type called LongWrAttr.
For each command called DevXxxx, pogo generates in the device class
a method named dev_xxx which will be executed when the command is
requested by a client. In this chapter, the name of the device class
is DocDs
This method receives a Tango::DevFloat type
and also returns a data of the Tango::DevFloat type which is simply
the double of the input value. The code for the method executed by
this command is the following:
-
- 1 Tango::DevFloat DocDs::dev_simple(Tango::DevFloat argin)
2 {
3 Tango::DevFloat argout ;
4 DEBUG_STREAM << DocDs::dev_simple(): entering... ! << endl;
5
6 // Add your own code to control device here
7
8 argout = argin * 2;
9 return argout;
10 }
This method is fairly simple. The received data is passed to the method
as its argument. It is
doubled at line 8 and the method simply returns the result.
This method receives a data of the Tango::DevVarLongArray
type and also returns a data of the Tango::DevVarLongArray type. Each
element of the array is doubled. The code for the method executed
by the command is the following :
-
- 1 Tango::DevVarLongArray *DocDs::dev_array(const Tango::DevVarLongArray *argin)
2 {
3 // POGO has generated a method core with argout allocation.
4 // If you would like to use a static reference without copying,
5 // See TANGO Device Server Programmer's Manual
6 // (chapter x.x)
7 //------------------------------
8 Tango::DevVarLongArray *argout = new Tango::DevVarLongArray();
9
10 DEBUG_STREAM << DocDs::dev_array(): entering... ! << endl;
11
12 // Add your own code to control device here
13
14 long argin_length = argin->length();
15 argout->length(argin_length);
16 for (int i = 0;i < argin_length;i++)
17 (*argout)[i] = (*argin)[i] * 2;
18
19 return argout;
20 }
The argout data array is created at line 8. Its length is set at line
15 from the input argument length. The array is populated at line
16,17 and returned. This method allocates memory for
the argout array. This memory is freed by the Tango core classes after
the data have been sent to the caller (no delete is needed). It is
also possible to return data from a statically allocated array without
copying. Look at chapter for all the details.
This method receives a data of the Tango::DevString
type and also returns a data of the Tango::DevString type. The command
simply displays the content of the input string and returns a hard-coded
string. The code for the method executed by the command is the following
:
-
- 1 Tango::DevString DocDs::dev_string(Tango::DevString argin)
2 {
3 // POGO has generated a method core with argout allocation.
4 // If you would like to use a static reference without copying,
5 // See TANGO Device Server Programmer's Manual
6 // (chapter x.x)
7 //------------------------------
8 Tango::DevString argout;
9 DEBUG_STREAM << DocDs::dev_string(): entering... ! << endl;
10
11 // Add your own code to control device here
12
13 cout << the received string is << argin << endl;
14
15 string str(Am I a good Tango dancer ?);
16 argout = new char[str.size() + 1];
17 strcpy(argout,str.c_str());
18
19 return argout;
20 }
The argout string is created at line 8. Internally, this method is
using a standard C++ string. Memory for the returned data is allocated
at line 16 and is initialized at line 17. This method allocates memory
for the argout string. This memory is freed by the Tango core classes
after the data have been sent to the caller (no delete is needed).
It is also possible to return data from a statically allocated string
without copying. Look at chapter for all the
details.
This method does not receive input data but returns an array of strings
(Tango::DevVarStringArray type).
The code for the method executed by this command is the following:
-
- 1 Tango::DevVarStringArray *DocDs::dev_str_array()
2 {
3 // POGO has generated a method core with argout allocation.
4 // If you would like to use a static reference without copying,
5 // See TANGO Device Server Programmer's Manual
6 // (chapter x.x)
7 //------------------------------
8 Tango::DevVarStringArray *argout = new Tango::DevVarStringArray();
9
10 DEBUG_STREAM << DocDs::dev_str_array(): entering... ! << endl;
11
12 // Add your own code to control device here
13
14 argout->length(3);
15 (*argout)[0] = CORBA::string_dup(Rumba);
16 (*argout)[1] = CORBA::string_dup(Waltz);
17 string str(Jerck);
18 (*argout)[2] = CORBA::string_dup(str.c_str());
19 return argout;
20 }
The argout data array is created at line 8. Its length is set at line
14. The array is populated at line 15,16 and 18. The last array element
is initialized from a standard C++ string created at line 17. Note
the usage of the string_dup function of
the CORBA namespace. This is necessary for strings array due to the
CORBA memory allocation schema.
This method does not receive input data but returns a structure of
the Tango::DevVarDoubleStringArray
type. This type is a composed type with an array of double and an
array of strings. The code for the method executed by this command
is the following:
-
- 1 Tango::DevVarDoubleStringArray *DocDs::dev_struct()
2 {
3 // POGO has generated a method core with argout allocation.
4 // If you would like to use a static reference without copying,
5 // See TANGO Device Server Programmer's Manual
6 // (chapter x.x)
7 //------------------------------
8 Tango::DevVarDoubleStringArray *argout = new Tango::DevVarDoubleStringArray();
9
10 DEBUG_STREAM << DocDs::dev_struct(): entering... ! << endl;
11
12 // Add your own code to control device here
13
14 argout->dvalue.length(3);
15 argout->dvalue[0] = 0.0;
16 argout->dvalue[1] = 11.11;
17 argout->dvalue[2] = 22.22;
18
19 argout->svalue.length(2);
20 argout->svalue[0] = CORBA::string_dup(Be Bop);
21 string str(Smurf);
22 argout->svalue[1] = CORBA::string_dup(str.c_str());
23
24 return argout;
25 }
The argout data structure is created at line 8. The length of the
double array in the output structure is set at line 14. The array
is populated between lines 15 and 17. The length of the string array
in the output structure is set at line 19. This string array is populated
between lines 20 an 22 from a hard-coded string and from a standard
C++ string. This method allocates memory for the argout
data. This memory is freed by the Tango core classes after the data
have been sent to the caller (no delete is needed). Note the usage
of the string_dup function of the CORBA
namespace. This is necessary for strings array due to the CORBA memory
allocation schema.
6 The three attributes
Some data have been added to the definition of the device class in
order to store attributes value. These data are (part of the class
definition) :
-
- 1
2
3 protected :
4 // Add your own data members here
5 //---------------------
6 Tango::DevString attr_str_array[5];
7 Tango::DevLong attr_rd;
8 Tango::DevLong attr_wr;
One data has been created for each attribute. As the StrAttr attribute
is of type spectrum with a maximum X dimension of 5, an array of length
5 has been reserved.
Several methods are necessary to implement these attributes. One method
to read the hardware which is common to all readable
attributes plus one read method for
each readable attribute and one write
method for each writable attribute. The code for these methods is
the following :
-
- 1 void DocDs::read_attr_hardware(vector<long> &attr_list)
2 {
3 DEBUG_STREAM << DocDs::read_attr_hardware(vector<long> &attr_list) entering... << endl;
4 // Add your own code here
5
6 string att_name;
7 for (long i = 0;i < attr_list.size();i++)
8 {
9 att_name = dev_attr->get_attr_by_ind(attr_list[i]).get_name();
10
11 if (att_name == LongRdAttr)
12 {
13 attr_rd = 5;
14 }
15 }
16 }
17
18 void DocDs::read_LongRdAttr(Tango::Attribute &attr)
19 {
20 DEBUG_STREAM << DocDs::read_LongRdAttr(Tango::Attribute &attr) entering... << endl;
21
22 attr.set_value(&attr_rd);
23 }
24
25 void DocDs::read_LongWrAttr(Tango::Attribute &attr)
26 {
27 DEBUG_STREAM << DocDs::read_LongWrAttr(Tango::Attribute &attr) entering... << endl;
28
29 attr.set_value(&attr_wr);
30 }
31
32 void DocDs::write_LongWrAttr(Tango::WAttribute &attr)
33 {
34 DEBUG_STREAM << DocDs::write_LongWrAttr(Tango::WAttribute &attr) entering... << endl;
35
36 attr.get_write_value(attr_wr);
37 DEBUG_STREAM << Value to be written = << attr_wr << endl;
38 }
39
40 void DocDs::read_StrAttr(Tango::Attribute &attr)
41 {
42 DEBUG_STREAM << DocDs::read_StrAttr(Tango::Attribute &attr) entering... << endl;
43
44 attr_str_array[0] = CORBA::string_dup(Rock);
45 attr_str_array[1] = CORBA::string_dup(Samba);
46
47 attr_set_value(attr_str_array, 2);
48 }
The read_attr_hardware() method
is executed once when a client execute the read_attributes
CORBA request whatever the number of attribute to be read is. The
rule of this method is to read the hardware and to store the read
values somewhere in the device object. In our example, only the LongRdAttr
attribute internal value is set by this method at line 13. The method
read_LongRdAttr() is executed by the read_attributes
CORBA call when the LongRdAttr attribute is read but after the read_attr_hardware()
method has been executed. Its rule is to set the attribute value in
the TANGO core classes object representing the attribute. This is
done at line 22. The method read_LongWrAttr() will be executed
when the LongWrAttr attribute is read (after the read_attr_hardware()
method). The attribute value is set at line 29. In the same manner,
the method called read_StrAttr() will be executed when the
attribute StrAttr is read. Its value is initialized in this method
at line 44 and 45 with the string_dup CORBA
function. The write_LongWrAttr() method is executed when the
LongWrAttr attribute value is set by a client. The
new attribute value coming from the client is stored in the object
data at line 36.
Pogo also generates a file called DocDsStateMachine.cpp
(for a Tango device server class called DocDs). This file is used
to store methods coding the device state machine. By default a allways
allowed state machine is provided. For more information about coding
the state machine, refer to the chapter Writing a device
server.
For each command called DevXxxx, pogo generates in the device class
a method named dev_xxx which will be executed when the command is
requested by a client. In this chapter, the name of the device class
is DocDs
This method receives a Tango DevFloat type and also
returns a data of the Tango DevFloat type which is simply the double
of the input value. Using java, the Tango::DevFloat type is mapped
to classical java float type. The code for the method executed by
this command is the following:
-
- 1 public float dev_simple(float argin) throws DevFailed
2 {
3 float argout = (float)0;
4
5 Util.out2.println(Entering dev_simple());
6
7 // --Add your Own code to control device here --
8
9 argout = argin * 2;
10 return argout;
11 }
This method is fairly simple. The received data is passed to the method
as its argument. It is
doubled at line 9 and the method simply returns the result.
This method receives a data of the Tango::DevVarLongArray
type and also returns a data of the Tango::DevVarLongArray type. Each
element of the array is doubled. Using java, the Tango DevVarLongArray
type is mapped to an array of java long. The code for the method executed
by the command is the following :
-
- 1 public int[] dev_array(int[] argin) throws DevFailed
2 {
3 int[] argout = new int[argin.length];
4
5 Util.out2.println(Entering dev_array());
6
7 // --Add your Own code to control device here --
8
9 for (int i = 0;i < argin.length;i++)
10 argout[i] = argin[i] * 2;
11 return argout;
12 }
The argout data array is created at line 3. The array is populated
at line 9,10 and returned.
This method receives a data of the Tango DevString
type and also returns a data of the Tango DevString type. The command
simply displays the content of the input string and returns a hard-coded
string. Using java, the Tango DevString type simply maps to java String.The
code for the method executed by the command is the following :
-
- 1 public String dev_string(String argin) throws DevFailed
2 {
3 Util.out2.println(Entering dev_string());
4
5 // --Add your Own code to control device here --
6
7 System.out.println(the received string is +argin);
8
9 String argout = new String(Am I a good Tango dancer ?);
10 return argout;
11 }
The argout string is created at line 9.
This method does not receive input data but returns an array of strings
(Tango DevVarStringArray type). Using java,
the Tango DevVarStringArray type maps to an array of java String.
The code for the method executed by this command is the following:
-
- 1 public String[] dev_str_array() throws DevFailed
2 {
3
4 Util.out2.println(Entering dev_str_array());
5
6 // --Add your Own code to control device here --
7
8 String[] argout = new String[3];
9 argout[0] = new String(Rumba);
10 argout[1] = new String(Waltz);
11 argout[2] = new String(Jerck);
12 return argout;
13 }
The argout data array is created at line 8. The array is populated
at line 9,10 and 11.
This method does not receive input data but returns a structure of
the Tango DevVarDoubleStringArray
type. This type is a composed type with an array of double and an
array of strings. This is mapped to a specific java class called DevVarDoubleStringArray.
The code for the method executed by this command is the following:
-
- 1 public DevVarDoubleStringArray dev_struct() throws DevFailed
2 {
3 DevVarDoubleStringArray argout = new DevVarDoubleStringArray();
4
5 Util.out2.println(Entering dev_struct());
6
7 // --Add your Own code to control device here --
8
9 argout.dvalue = new double[3];
10 argout.dvalue[0] = 0.0;
11 argout.dvalue[1] = 11.11;
12 argout.dvalue[2] = 22.22;
13
14 argout.svalue = new String[2];
15 argout.svalue[0] = new String(Be Bop);
16 argout.svalue[1] = new String(Smurf);
17
18 return argout;
19 }
The argout data structure is created at line 3. The double array in
the output structure is created at line 9. The array is populated
between lines 10 and 12. The string array in the output structure
is created at line 14. This string array is populated between lines
15 and 16 from hard-coded strings.
6 The three attributes
Some data have been added to the definition of the device class in
order to store attributes value. These data are (part of the class
definition) :
-
- 1 protected String[] attr_str_array = new String[5];
2 protected int attr_rd;
3 protected int attr_wr;
One data has been created for each attribute. As the StrAttr attribute
is of type spectrum with a maximum X dimension of 5, an array of length
5 has been reserved.
Unfortunately, Java Tango device server are not at the same level
of development than C++ device servers. This is why they are not written
exactly the same way than C++ device servers. Three methods are necessary
to implement these attributes. The code for these methods is the following
:
-
- 1 public void write_attr_hardware(Vector attr_list)
2 {
3 Util.out2.println(In write_attr_hardware for +attr_list.size()+ attribute(s));
4
5 for (int i=0 ; i<attr_list.size() ; i++)
6 {
7 int ind = ((Integer)(attr_list.elementAt(i))).intValue();
8 WAttribute att = dev_attr.get_w_attr_by_ind(ind);
9 String attr_name = att.get_name();
10
11 // Switch on attribute name
12 //-----------------
13 if (attr_name.equals(LongWrAttr) == true)
14 {
15 // Add your own code here
16 attr_wr = att.get_lg_write_value();
17 System.out.println(Value to be written = +attr_wr);
18 }
19 }
20 }
21
22
23 public void read_attr_hardware(Vector attr_list)
24 {
25 Util.out2.println(In read_attr_hardware for +attr_list.size()+ attribute(s));
26
27 // Add you own code here
28 //-----------------
29
30 for (int i=0; i<attr_list.size() ; i++)
31 {
32 int ind = ((Integer)(attr_list.elementAt(i))).intValue();
33 Attribute att = dev_attr.get_attr_by_ind(ind);
34 String attr_name = attr_list.elementAt(i);
35
36 if (attr_name.equals(LongRdAttr) == true)
37 {
38 attr_rd = 5;
39 }
40 else if (attr_name.equals(StrAttr) == true)
41 {
42 attr_str_array[0] = new String(Rock);
43 attr_str_array[1] = new String(Samba);
44 }
45 }
46 }
47
48
49 public void read_attr(Attribute attr) throws DevFailed
50 {
51 String attr_name = attr.get_name();
52 Util.out2.println(In read_attr for attribute +attr_name);
53
54 // Switch on attribute name
55 //-----------------
56 if (attr_name.equals(LongWrAttr) == true)
57 {
58 // Add your own code here
59 attr.set_value(attr_wr);
60 }
61 if (attr_name.equals(LongRdAttr) == true)
62 {
63 // Add your own code here
64 attr.set_value(attr_rd);
65 }
66 if (attr_name.equals(StrAttr) == true)
67 {
68 // Add your own code here
69 attr.set_value(attr_str_array);
70 }
71 }
The write_attr_hardware() method
is executed when an attribute value is set by a
client. In our example only one attribute is writable (the LongWrAttr
attribute). The new attribute value coming from the client is stored
in the object data at line 16. The read_attr_hardware()
method is executed once when a client execute the read_attributes
CORBA request. The rule of this method is to read the hardware and
to store the read values somewhere in the device object. In our example,
the LongRdAttr attribute internal value is set by this method at line
38 at the StrAttr attribute internal value is set at lines 42 and
43. The method read_attr() is executed for
each attribute to be read by the read_attributes
CORBA call. Its rule is to set the attribute value in the TANGO core
classes object representing the attribute. This is done at line 64
for the LongRdAttr attribute, at line 59 for the LongWrAttr attribute
and at line 69 for the StrAttr attribute
Emmanuel Taurel
2012-06-06