How to init spectrum attributes ?

Hi
I need to initialise small size spectrum attributes in init_device() but there is sommething wrong with the manual writing. After a set_write_value(), I call get_write_value() to check but it returns garbage values. Can you tell me how to fix it? Thanks


void TestSpectrumWriting::init_device()
{

attr_RWDoubleSpectrum_read = new Tango::DevDouble[10];
attr_RWFloatSpectrum_read = new Tango::DevFloat[10];

// Initialize RWFloatSpectrum
int w_length ;
Tango::WAttribute &RWFloatAttr = dev_attr->get_w_attr_by_name( "RWFloatSpectrum" );
std::vector<float> float_input={1,2,3};
RWFloatAttr.set_write_value(float_input.data(),3,1);
w_length = RWFloatAttr.get_write_value_length();
const Tango::DevFloat *rb_farray;
RWFloatAttr.get_write_value(rb_farray);
std::cout<<"input float array "<<w_length<<" : ";
for(auto elem : float_input)
{
std::cout<<elem<< " ";
}
std::cout<<std::endl;

std::cout<<"Readback float array "<<w_length<<" :"<<std::endl;
for (int j=0;j<w_length;j++)
std::cout<<"RWFloatAttr["<<j<<"] = "<<rb_farray[j]<<" ";
std::cout<<std::endl<<std::endl;
write_RWFloatSpectrum(RWFloatAttr);

// Initialize RWDoubleSpectrum
Tango::WAttribute &RWDoubleAttr = dev_attr->get_w_attr_by_name( "RWDoubleSpectrum" );
std::vector<double> double_input={1,2,3};
RWDoubleAttr.set_write_value(double_input,3,1);
w_length = RWDoubleAttr.get_write_value_length();
const Tango::DevDouble *rb_darray;
RWDoubleAttr.get_write_value(rb_darray);
std::cout<<"\ninput double array "<<w_length<<" : ";
for(auto elem : double_input)
{
std::cout<<elem<< " ";
}
std::cout<<std::endl;
std::cout<<"Readback double array "<<w_length<<" :"<<std::endl;
for (int j=0;j<w_length;j++)
std::cout<<"RWDoubleAttr["<<j<<"] = "<<rb_darray[j]<<" ";
std::cout<<std::endl<<std::endl;
write_RWDoubleSpectrum(RWDoubleAttr);
/*—– PROTECTED REGION END —–*/ // TestSpectrumWriting::init_device
}

void TestSpectrumWriting::write_RWDoubleSpectrum(Tango::WAttribute &attr)
{
// Retrieve number of write values
int w_length = attr.get_write_value_length();

// Retrieve pointer on write values (Do not delete !)
const Tango::DevDouble *w_val;
attr.get_write_value(w_val);
std::cout<<"In write_RWDoubleSpectrum:"<<std::endl;
for (int j=0;j<attr.get_write_value_length();j++){
std::cout<<"w_val["<<j<<"] = "<<w_val[j]<<" ";
attr_RWDoubleSpectrum_read[j] = w_val[j];
}
}
//——————————————————–

void TestSpectrumWriting::write_RWFloatSpectrum(Tango::WAttribute &attr)
{
// Retrieve number of write values
int w_length = attr.get_write_value_length();

// Retrieve pointer on write values (Do not delete !)
const Tango::DevFloat *w_val;
attr.get_write_value(w_val);
std::cout<<"In write_RWFloatSpectrum:"<<std::endl;
for (int j=0;j<attr.get_write_value_length();j++){
std::cout<<"w_val["<<j<<"] = "<<w_val[j]<<" ";
attr_RWFloatSpectrum_read[j] = w_val[j];
}

}


Output tested with Tango 9.3.5 (same results with other types of spectrum attributes):
input float array 3 : 1 2 3
Readback float array 3 :
RWFloatAttr[0] = -691.754 RWFloatAttr[1] = 3.06744e-41 RWFloatAttr[2] = -665.501

In write_RWFloatSpectrum:
w_val[0] = -691.754 w_val[1] = 3.06744e-41 w_val[2] = -665.501
input double array 3 : 1 2 3
Readback double array 3 :
RWDoubleAttr[0] = 4.64521e-310 RWDoubleAttr[1] = 4.64521e-310 RWDoubleAttr[2] = 3

In write_RWDoubleSpectrum:
w_val[0] = 4.64521e-310 w_val[1] = 4.64521e-310 w_val[2] = 3
Hi Jade,

get_write_value() method is not doing what you think it does.
get_write_value() method should be used only in write_MyAttr() methods.
It is used to retrieve the input data from the client which currently tries to write MyAttr attribute.
It makes sense only when a client is currently trying to write MyAttr attribute.

So you should not use get_write_value() method in init_device(). It is returning garbage because no client is currently writing this attribute.
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
Thank Reynald for your reply.

I used get_write_value() inside init_device() to verify after receiving garbage value inside write_MyAttr().
You can see that write_MyAttr is called in init_device(). The get_write_value() called inside this method gives the same garbage values as it is called in init_device().

I don't have the same issue while using the same way to initialise scalar attributes.

Do you have any suggestions to set spectrum attributes in init_device()?
jade
I used get_write_value() inside init_device() to verify after receiving garbage value inside write_MyAttr().
You can see that write_MyAttr is called in init_device(). The get_write_value() called inside this method gives the same garbage values as it is called in init_device().

Yes. This is expected.
It might not be intuitive but you should not call write_MyAttr() method directly from your code.
This method should be called only by the cppTango layer when a Tango CORBA client is trying to write the attribute using the write_attribute/write_attributes methods.
Only in this situation get_write_value() will return what the client provided as input argument to write_attribute method.
In other situations it will return garbage because the data structure used to store what is returned by get_write_value() won't be initialized before the call.
get_write_value() is initialized only when a Tango CORBA client is invoking write_attribute()/write_attributes() methods.

set_write_value() is not doing what you think it does.
set_write_value() is not setting the same data structure as the one retrieved by get_write_value().
set_write_value() is a method you can use to set the set point (only set point) of a given writable attribute.
It is indeed interesting to use it in init_device() in some situations to set an initial set point for a given RW attribute.
If you read the attribute immediately after the device initialization and no client wrote this attribute with write_attribute() before the read_attribute(), you will get the value which was set with set_write_value as set point of this attribute (reminder: read_attribute returns a read value and a set value).

jade
Do you have any suggestions to set spectrum attributes in init_device()?

What I would do is something like what is provided in the attached code (only done with the RWFloatSpectrum Attribute in the example).

Hoping this helps.
Reynald
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
Edited 1 month ago
Thank Reynald, I understand now.

The issue is that I want to call some write_MyAttr() methods to init some hardware values . So it is impossible to init the spectrum attributes in init_device()
What I would suggest is simply to define a method which will be used to initialize the hardware values related to MyAttr attribute.
You can then call this method in your write_MyAttr() method as well as in init_device() method.
You might need to call explicitly always_executed_hook() if your always_executed_hook() method is doing some important stuff that must be done before.
You might need to execute what is in the write_attr_hardware() too after in case you have some important code there too to apply some settings to the hardware.
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
I see. Thank you Reynald
Hi Reynald
I found the issue in Tango source code.
While the method get_write_value() of WAttribute returns the garbage value in manual writing case, the method get_last_written_fl() returns the good value.


Tango::DevVarFloatArray *get_last_written_fl() {return &float_array_val;}
void get_write_value(const Tango::DevFloat *&ptr) {ptr = float_ptr;}


For Tango 9.3 , we only need to add a line to method copy_data: float_ptr = float_array_val.get_buffer(); (same thing for other types )


void WAttribute::copy_data(const CORBA::Any &any)
{
switch (data_type)
{

case Tango::DEV_FLOAT :
const Tango::DevVarFloatArray *fl_ptr;
any >>= fl_ptr;
float_array_val = *fl_ptr;
float_ptr = float_array_val.get_buffer();

break;
}
}



I need this correction for a project in collaboration with another institute who uses Tango 9.4. I cannot suggest a corrrection as I don't know how to find code of the method
 template void WAttribute::_copy_any_data(const CORBA::Any&);


Do you think that this error could be corrected for Tango9
Hi Jade,

The place to contribute and to report issues in the Tango C++ Library is here:
https://gitlab.com/tango-controls/cppTango/

Kind regards,
Reynald
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
 
Register or login to create to post a reply.