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.

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()?

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

[quote=“jade”]
Do you have any suggestions to set spectrum attributes in init_device()?[/quote]

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

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.

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:

Kind regards,
Reynald