AttributeCombiner.cpp 65 KB
Newer Older
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*----- PROTECTED REGION ID(AttributeCombiner.cpp) ENABLED START -----*/
//=============================================================================
//
// file :        AttributeCombiner.cpp
//
// description : C++ source for the AttributeCombiner class and its commands.
//               The class is derived from Device. It represents the
//               CORBA servant object which will be accessed from the
//               network. All commands which can be executed on the
//               AttributeCombiner are implemented in this file.
//
// project :     AttributeCombiner
//
// This file is part of Tango device class.
// 
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
// 
//
// Copyright (C): 2018
//                European Synchrotron Radiation Facility
//                BP 220, Grenoble 38043
//                France
//
//=============================================================================
//                This file is generated by POGO
//        (Program Obviously used to Generate tango Object)
//=============================================================================


#include <AttributeCombiner.h>
#include <AttributeCombinerClass.h>


/*----- PROTECTED REGION END -----*/	//	AttributeCombiner.cpp

/**
 *  AttributeCombiner class description:
 *    A class to combine attributes coming from several devices
 */

//================================================================
//  The following table gives the correspondence
//  between command and method names.
//
56
//  Command name       |  Method name
Jean-Luc Pons's avatar
Jean-Luc Pons committed
57
//================================================================
58
59
60
61
62
63
64
65
//  State              |  Inherited (no method)
//  Status             |  Inherited (no method)
//  ResetError         |  reset_error
//  UpdateSetpoint     |  update_setpoint
//  EnableDevice       |  enable_device
//  DisableDevice      |  disable_device
//  Indice2Devicename  |  indice2_devicename
//  Devicename2Indice  |  devicename2_indice
66
67
//  DisableAll         |  disable_all
//  EnableAll          |  enable_all
68
//  saveAttribute      |  save_attribute
Jean-Luc Pons's avatar
Jean-Luc Pons committed
69
70
71
//================================================================

//================================================================
72
//  Attributes managed are:
Jean-Luc Pons's avatar
Jean-Luc Pons committed
73
//================================================================
74
75
//  Errors      |  Tango::DevString	Spectrum  ( max = 2048)
//  DeviceList  |  Tango::DevString	Spectrum  ( max = 4096)
Jean-Luc Pons's avatar
Jean-Luc Pons committed
76
77
78
79
80
81
//================================================================

namespace AttributeCombiner_ns
{
/*----- PROTECTED REGION ID(AttributeCombiner::namespace_starting) ENABLED START -----*/

82
    //	static initializations
Jean-Luc Pons's avatar
Jean-Luc Pons committed
83

84
    /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::namespace_starting
Jean-Luc Pons's avatar
Jean-Luc Pons committed
85
86
87
88
89
90
91
92
93
94
95
96

//--------------------------------------------------------
/**
 *	Method      : AttributeCombiner::AttributeCombiner()
 *	Description : Constructors for a Tango device
 *                implementing the classAttributeCombiner
 */
//--------------------------------------------------------
AttributeCombiner::AttributeCombiner(Tango::DeviceClass *cl, string &s)
 : TANGO_BASE_CLASS(cl, s.c_str())
{
	/*----- PROTECTED REGION ID(AttributeCombiner::constructor_1) ENABLED START -----*/
97
98
99
        init_device();

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::constructor_1
Jean-Luc Pons's avatar
Jean-Luc Pons committed
100
101
102
103
104
105
}
//--------------------------------------------------------
AttributeCombiner::AttributeCombiner(Tango::DeviceClass *cl, const char *s)
 : TANGO_BASE_CLASS(cl, s)
{
	/*----- PROTECTED REGION ID(AttributeCombiner::constructor_2) ENABLED START -----*/
106
107
108
        init_device();

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::constructor_2
Jean-Luc Pons's avatar
Jean-Luc Pons committed
109
110
111
112
113
114
}
//--------------------------------------------------------
AttributeCombiner::AttributeCombiner(Tango::DeviceClass *cl, const char *s, const char *d)
 : TANGO_BASE_CLASS(cl, s, d)
{
	/*----- PROTECTED REGION ID(AttributeCombiner::constructor_3) ENABLED START -----*/
115
116
117
        init_device();

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::constructor_3
Jean-Luc Pons's avatar
Jean-Luc Pons committed
118
119
120
121
122
123
124
125
126
127
128
129
}

//--------------------------------------------------------
/**
 *	Method      : AttributeCombiner::delete_device()
 *	Description : will be called at device destruction or at init command
 */
//--------------------------------------------------------
void AttributeCombiner::delete_device()
{
	DEBUG_STREAM << "AttributeCombiner::delete_device() " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::delete_device) ENABLED START -----*/
130
        delete deviceGroup;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
131

132
133
134
135
136
137
138
139
140
141
        if (Tango::Util::instance()->is_svr_shutting_down() ||
                Tango::Util::instance()->is_device_restarting(get_name())) {
            attMap.clear();
        }

        delete self;

        for (int i = 0; i < (int) deviceList.size(); i++) {
            Tango::string_free(attr_DeviceList_read[i]);
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
142

143
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::delete_device
144
	delete[] attr_DeviceList_read;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
145
146
147
148
149
150
151
152
153
154
155
156
}

//--------------------------------------------------------
/**
 *	Method      : AttributeCombiner::init_device()
 *	Description : will be called at device initialization.
 */
//--------------------------------------------------------
void AttributeCombiner::init_device()
{
	DEBUG_STREAM << "AttributeCombiner::init_device() create device " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::init_device_before) ENABLED START -----*/
157
158
159
160

        //	Initialization before get_device_property() call

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::init_device_before
Jean-Luc Pons's avatar
Jean-Luc Pons committed
161
162
163
164
165
	

	//	Get the device properties from database
	get_device_property();
	
166
	attr_DeviceList_read = new Tango::DevString[4096];
Jean-Luc Pons's avatar
Jean-Luc Pons committed
167
168
	/*----- PROTECTED REGION ID(AttributeCombiner::init_device) ENABLED START -----*/

169
170
171
        set_state(Tango::ON);
        set_status("ON");

Nicolas Tappret's avatar
Nicolas Tappret committed
172
        // Create devices group
173
174
175
176
177
178
179
180
181
182
183
184
185
186
        deviceGroup = new Tango::Group("DEVGROUP");

        errorStack.clear();
        for (int i = 0; i < (int) deviceList.size(); i++) {
            // Populate error vector
            ERRITEM it;
            errorStack.push_back(it);
        }
        deviceGroup->add(deviceList);
        deviceGroup->set_timeout_millis(timeout);

        Tango::GroupReply::enable_exception(false);
        self = new Tango::DeviceProxy(device_name);

Nicolas Tappret's avatar
Nicolas Tappret committed
187
        // Read disabled Devices
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
        Tango::DbData dbd;
        dbd.push_back(Tango::DbDatum("DisabledDevices"));
        get_db_device()->get_property(dbd);
        vector<string> values;
        dbd[0] >> values;
        for (int i = 0; i < (int) values.size(); i++) {
            cout << "Disable: " << values[i] << endl;
            deviceGroup->disable(values[i]);
        }

        for (int i = 0; i < (int) deviceList.size(); i++) {
            attr_DeviceList_read[i] = Tango::string_dup(deviceList[i].c_str());
        }

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::init_device
Jean-Luc Pons's avatar
Jean-Luc Pons committed
203
204
205
206
207
208
209
210
211
212
213
214
}

//--------------------------------------------------------
/**
 *	Method      : AttributeCombiner::get_device_property()
 *	Description : Read database to initialize property data members.
 */
//--------------------------------------------------------
void AttributeCombiner::get_device_property()
{
	/*----- PROTECTED REGION ID(AttributeCombiner::get_device_property_before) ENABLED START -----*/

215
216
217
218
219
220
        //	Initialize property data members
        deviceList.clear();
        attributeList.clear();
        attributeRefList.clear();

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::get_device_property_before
Jean-Luc Pons's avatar
Jean-Luc Pons committed
221
222
223
224
225
226
227


	//	Read device properties from database.
	Tango::DbData	dev_prop;
	dev_prop.push_back(Tango::DbDatum("AttributeList"));
	dev_prop.push_back(Tango::DbDatum("AttributeRefList"));
	dev_prop.push_back(Tango::DbDatum("DeviceList"));
228
	dev_prop.push_back(Tango::DbDatum("CommandList"));
229
	dev_prop.push_back(Tango::DbDatum("Timeout"));
230
	dev_prop.push_back(Tango::DbDatum("refreshTime"));
Jean-Luc Pons's avatar
Jean-Luc Pons committed
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

	//	is there at least one property to be read ?
	if (dev_prop.size()>0)
	{
		//	Call database and extract values
		if (Tango::Util::instance()->_UseDb==true)
			get_db_device()->get_property(dev_prop);
	
		//	get instance on AttributeCombinerClass to get class property
		Tango::DbDatum	def_prop, cl_prop;
		AttributeCombinerClass	*ds_class =
			(static_cast<AttributeCombinerClass *>(get_device_class()));
		int	i = -1;

		//	Try to initialize AttributeList from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  attributeList;
		else {
			//	Try to initialize AttributeList from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  attributeList;
		}
		//	And try to extract AttributeList value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  attributeList;

		//	Try to initialize AttributeRefList from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  attributeRefList;
		else {
			//	Try to initialize AttributeRefList from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  attributeRefList;
		}
		//	And try to extract AttributeRefList value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  attributeRefList;

		//	Try to initialize DeviceList from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  deviceList;
		else {
			//	Try to initialize DeviceList from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  deviceList;
		}
		//	And try to extract DeviceList value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  deviceList;

278
279
280
281
282
283
284
285
286
287
288
		//	Try to initialize CommandList from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  commandList;
		else {
			//	Try to initialize CommandList from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  commandList;
		}
		//	And try to extract CommandList value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  commandList;

289
290
291
292
293
294
295
296
297
298
299
		//	Try to initialize Timeout from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  timeout;
		else {
			//	Try to initialize Timeout from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  timeout;
		}
		//	And try to extract Timeout value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  timeout;

300
301
302
303
304
305
306
307
308
309
310
		//	Try to initialize refreshTime from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  refreshTime;
		else {
			//	Try to initialize refreshTime from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  refreshTime;
		}
		//	And try to extract refreshTime value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  refreshTime;

Jean-Luc Pons's avatar
Jean-Luc Pons committed
311
312
313
	}

	/*----- PROTECTED REGION ID(AttributeCombiner::get_device_property_after) ENABLED START -----*/
314
315
316
317

        //	Check device property data members init

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::get_device_property_after
Jean-Luc Pons's avatar
Jean-Luc Pons committed
318
319
320
321
322
323
324
325
326
327
328
329
}

//--------------------------------------------------------
/**
 *	Method      : AttributeCombiner::always_executed_hook()
 *	Description : method always executed before any command is executed
 */
//--------------------------------------------------------
void AttributeCombiner::always_executed_hook()
{
	DEBUG_STREAM << "AttributeCombiner::always_executed_hook()  " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::always_executed_hook) ENABLED START -----*/
330
331
332
333

        //	code always executed before all requests

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::always_executed_hook
Jean-Luc Pons's avatar
Jean-Luc Pons committed
334
335
336
337
338
339
340
341
342
343
344
345
}

//--------------------------------------------------------
/**
 *	Method      : AttributeCombiner::read_attr_hardware()
 *	Description : Hardware acquisition for attributes
 */
//--------------------------------------------------------
void AttributeCombiner::read_attr_hardware(TANGO_UNUSED(vector<long> &attr_list))
{
	DEBUG_STREAM << "AttributeCombiner::read_attr_hardware(vector<long> &attr_list) entering... " << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::read_attr_hardware) ENABLED START -----*/
346
347
348
349

        //	Add your own code

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::read_attr_hardware
Jean-Luc Pons's avatar
Jean-Luc Pons committed
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
}

//--------------------------------------------------------
/**
 *	Read attribute Errors related method
 *	Description: 
 *
 *	Data type:	Tango::DevString
 *	Attr type:	Spectrum max = 2048
 */
//--------------------------------------------------------
void AttributeCombiner::read_Errors(Tango::Attribute &attr)
{
	DEBUG_STREAM << "AttributeCombiner::read_Errors(Tango::Attribute &attr) entering... " << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::read_Errors) ENABLED START -----*/

366
367
368
369
370
371
372
        int nbError = 0;
        attr_Errors_read = new Tango::DevString[MAXERROR * deviceList.size()];
        for (int i = 0; i < (int) errorStack.size(); i++) {
            for (int j = 0; j < (int) errorStack[i].errList.size(); j++)
                attr_Errors_read[nbError++] = Tango::string_dup(errorStack[i].errList[j].c_str());
        }
        attr.set_value(attr_Errors_read, nbError, 0, true);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
373

374
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::read_Errors
Jean-Luc Pons's avatar
Jean-Luc Pons committed
375
}
376
377
378
379
380
381
382
383
384
385
386
387
388
389
//--------------------------------------------------------
/**
 *	Read attribute DeviceList related method
 *	Description: 
 *
 *	Data type:	Tango::DevString
 *	Attr type:	Spectrum max = 4096
 */
//--------------------------------------------------------
void AttributeCombiner::read_DeviceList(Tango::Attribute &attr)
{
	DEBUG_STREAM << "AttributeCombiner::read_DeviceList(Tango::Attribute &attr) entering... " << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::read_DeviceList) ENABLED START -----*/

390
        attr.set_value(attr_DeviceList_read, deviceList.size());
391

392
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::read_DeviceList
393
}
Jean-Luc Pons's avatar
Jean-Luc Pons committed
394
395
396
397
398
399
400
401
402
403
404
405

//--------------------------------------------------------
/**
 *	Method      : AttributeCombiner::add_dynamic_attributes()
 *	Description : Create the dynamic attributes if any
 *                for specified device.
 */
//--------------------------------------------------------
void AttributeCombiner::add_dynamic_attributes()
{
	/*----- PROTECTED REGION ID(AttributeCombiner::add_dynamic_attributes) ENABLED START -----*/

406
407
        // Attribute List
        string usage = "9 fields expected name;attName list;type;readwrite;spectrum;grouped;lengthattname;expert;alarm";
Jean-Luc Pons's avatar
Jean-Luc Pons committed
408

409
        for (int i = 0; i < (int) attributeList.size(); i++) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
410

411
412
413
414
415
416
417
            vector<string> fields;
            split(fields, attributeList[i], ';');
            if (fields.size() != 9) {
                cerr << "ERROR: Wrong attribute configuration property for " << attributeList[i] << endl;
                cerr << "ERROR: " << usage << endl;
                exit(0);
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
418

419
420
421
            string name = fields[0];
            vector<string> attNames;
            split(attNames, fields[1], ',');
Jean-Luc Pons's avatar
Jean-Luc Pons committed
422

423
424
425
426
427
            if (attNames.size() == 0) {
                cerr << "ERROR: Empty attribute list for " << attributeList[i] << endl;
                cerr << "ERROR: " << usage << endl;
                exit(0);
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
428

429
430
431
432
            if (attNames.size() > MAXATTRIBUTE) {
                cerr << "ERROR: Attribute list too long for " << attributeList[i] << endl;
                exit(0);
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
433

434
            int type = ToTangoType(name, fields[2]);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
435

436
437
438
439
440
441
442
            tolower(fields[3]);
            Tango::AttrWriteType rwType;
            if (fields[3].compare("true") == 0) {
                rwType = Tango::READ_WRITE;
            } else {
                rwType = Tango::READ;
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
443

444
445
            tolower(fields[4]);
            bool isSpectrum = fields[4].compare("true") == 0;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
446

447
448
            tolower(fields[5]);
            bool grouped = fields[5].compare("true") == 0;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
449

450
            string lengthAttName = fields[6];
Jean-Luc Pons's avatar
Jean-Luc Pons committed
451

452
453
            tolower(fields[7]);
            bool expert = fields[7].compare("true") == 0;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
454

455
456
            tolower(fields[8]);
            bool alarm = fields[8].compare("true") == 0;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
457

458
            if (grouped) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
459

460
461
462
463
464
                if (isSpectrum) {
                    cerr << "ERROR: Wrong attribute configuration property for " << attributeList[i] << endl;
                    cerr << "ERROR: Cannot group spectrum attribute" << endl;
                    exit(0);
                }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
465

Nicolas Tappret's avatar
Nicolas Tappret committed
466
                // We group all Devices attribute in only one (for scalar only)
467
468
                DynAttribute *att = new DynAttribute(name.c_str(), type, rwType, expert);
                add_attribute(att);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
469

470
                if (type == Tango::DEV_ENUM) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
471

472
473
474
475
476
477
478
479
480
                    // Retrieve the enum list from the first attribute
                    // All grouped attributes must have the same list
                    // Use the first enabled device
                    int i = 0;
                    bool found = false;
                    while (!found && i < (int) deviceList.size()) {
                        found = !isDisabled(i);
                        if (!found) i++;
                    }
481

482
483
484
485
486
487
488
489
                    if (found) {
                        Tango::AttributeInfoEx ae = deviceGroup->get_device(deviceList[i])->get_attribute_config(attNames[0]);
                        Tango::Attribute &eAtt = get_device_attr()->get_attr_by_name(name.c_str());
                        Tango::MultiAttrProp<Tango::DevEnum> presetProps;
                        eAtt.get_properties(presetProps);
                        presetProps.enum_labels = ae.enum_labels;
                        eAtt.set_properties(presetProps);
                    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
490

491
                }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
492

Jean-Luc Pons's avatar
Jean-Luc Pons committed
493

494
            } else {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
495

496
                DynSpectrumAttribute *att;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
497

498
                if (!isSpectrum) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
499

500
501
502
503
504
                    // Map scalar attritbute to spectrum (convert all type to double except state)
                    if (type != Tango::DEV_STATE)
                        att = new DynSpectrumAttribute(name.c_str(), Tango::DEV_DOUBLE, deviceList.size() * attNames.size(), rwType, expert);
                    else
                        att = new DynSpectrumAttribute(name.c_str(), Tango::DEV_STATE, deviceList.size() * attNames.size(), rwType, expert);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
505

506
                } else {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
507

508
509
510
511
512
513
                    // Map spectrum attritbute to mulitple spectrum
                    if (rwType == Tango::READ_WRITE) {
                        cerr << "ERROR: Wrong attribute configuration property for " << attributeList[i] << endl;
                        cerr << "ERROR: ReadWrite mode not supported for multiple spectrum" << endl;
                        exit(0);
                    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
514

515
                    att = new DynSpectrumAttribute(name.c_str(), Tango::DEV_DOUBLE, deviceList.size() * attNames.size() * MAXVALUELENGTH, rwType, expert);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
516

517
                }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
518

519
                add_attribute(att);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
520

521
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
522

523
            attMap.add(name, attNames, grouped, type, rwType, isSpectrum, lengthAttName, alarm);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
524
525


526
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
527

528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
        // Attribute ref diff list
        string usageRef = "3 fields expected (name Ref attribute;Live attribute Name For Difference;name of difference attribute) or 1 fields  name Ref attribute";

        for (int i = 0; i < (int) attributeRefList.size(); i++) {
            vector<string> fields;
            split(fields, attributeRefList[i], ';');
            int nbParam = fields.size();
            if (nbParam != 3 && nbParam != 1) {
                cerr << "ERROR: Wrong attribute configuration property for " << attributeRefList[i] << endl;
                cerr << "ERROR: " << usageRef << endl;
                exit(0);
            }

            string name = fields[0];

            DynSpectrumAttribute *att;
            att = new DynSpectrumAttribute(name.c_str(), Tango::DEV_DOUBLE, MAXVALUELENGTH, Tango::READ_WRITE, true);
            add_attribute(att);
            attMap.addRef(name);
            
            try {
                ATTITEM * item = attMap.get(name);
                string memoriedString = readAttributeProperty(name, "__value");
                vector<string> splited;
                split(splited, memoriedString, ',');
                int size = splited.size();

                item->refSize = size;
                item->refData = (Tango::DevDouble *)malloc(size * sizeof(Tango::DevDouble));
                stringstream ss;

                for (int i = 0; i < size; i++) {
                    ss.clear();
                    ss << splited[i];
                    ss >> item->refData[i];
                }
                this->get_device_attr()->get_w_attr_by_name(name.c_str()).set_write_value(item->refData, size);

            } catch (Tango::DevFailed &ex) {
                Tango::Except::print_exception(ex);
            }
            

            if (nbParam == 3) {
                string attrDiffrenceName = fields[2];
                string attrLiveName = fields[1];

                ATTITEM * refItem = attMap.get(name);
                ATTITEM * liveItem = attMap.get(attrLiveName);
                
                //add pointer to ref attribute for save attribute
                liveItem->refItem = refItem;
                refItem->liveItem = liveItem;

                if (refItem == nullptr || liveItem == nullptr) {
                    cerr << "ERROR: Wrong attribute configuration property for " << attributeRefList[i] << endl;
                    cerr << "ERROR: Live attribute Name not Found" << endl;
                    exit(0);
                }

                DynSpectrumAttribute *attDiff;
                attDiff = new DynSpectrumAttribute(attrDiffrenceName.c_str(), Tango::DEV_DOUBLE, MAXVALUELENGTH, Tango::READ, true);
                add_attribute(attDiff);
                attMap.addDifferenceRef(attrDiffrenceName, refItem, liveItem);
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
593

594
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
595

596
597
598
599
600
601
602
603
        // States attribute
        if (deviceList.size() > 0) {
            vector<string> stateName;
            stateName.push_back("State");
            DynSpectrumAttribute *stateAtt = new DynSpectrumAttribute("States", Tango::DEV_STATE, deviceList.size(), Tango::READ, false);
            add_attribute(stateAtt);
            attMap.add("States", stateName, false, Tango::DEV_STATE, Tango::READ, false, "None", false);
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
604

605
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::add_dynamic_attributes
Jean-Luc Pons's avatar
Jean-Luc Pons committed
606
607
608
609
610
611
612
613
614
615
616
617
618
619
}

//--------------------------------------------------------
/**
 *	Command ResetError related method
 *	Description: Reset Error stack
 *
 */
//--------------------------------------------------------
void AttributeCombiner::reset_error()
{
	DEBUG_STREAM << "AttributeCombiner::ResetError()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::reset_error) ENABLED START -----*/

620
621
622
623
        for (int i = 0; i < (int) errorStack.size(); i++)
            errorStack[i].errList.clear();

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::reset_error
Jean-Luc Pons's avatar
Jean-Luc Pons committed
624
625
626
627
628
629
630
631
632
633
634
635
636
}
//--------------------------------------------------------
/**
 *	Command UpdateSetpoint related method
 *	Description: Update local setpoints from device setpoints
 *
 */
//--------------------------------------------------------
void AttributeCombiner::update_setpoint()
{
	DEBUG_STREAM << "AttributeCombiner::UpdateSetpoint()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::update_setpoint) ENABLED START -----*/

637
638
639
640
641
642
643
        // Force update of setpoints at the next reading
        for (int i = 0; i < (int) attMap.size(); i++) {
            ATTITEM *item = attMap.get(i);
            item->setInit = false;
        }

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::update_setpoint
Jean-Luc Pons's avatar
Jean-Luc Pons committed
644
645
646
647
648
649
650
651
652
653
654
655
656
657
}
//--------------------------------------------------------
/**
 *	Command EnableDevice related method
 *	Description: Enable device
 *
 *	@param argin Enable device #i
 */
//--------------------------------------------------------
void AttributeCombiner::enable_device(Tango::DevShort argin)
{
	DEBUG_STREAM << "AttributeCombiner::EnableDevice()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::enable_device) ENABLED START -----*/

658
659
660
661
662
663
        if (argin < 0 || argin >= (short) deviceList.size()) {
            Tango::Except::throw_exception(
                    (const char *) "AttributeCombiner::error_write",
                    (const char *) "Invalid device index",
                    (const char *) "AttributeCombiner::disable_device");
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
664

665
        deviceGroup->enable(deviceList[argin]);
Nicolas Tappret's avatar
Nicolas Tappret committed
666
        saveDisabled();
Jean-Luc Pons's avatar
Jean-Luc Pons committed
667

668
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::enable_device
Jean-Luc Pons's avatar
Jean-Luc Pons committed
669
670
671
672
673
674
675
676
677
678
679
680
681
682
}
//--------------------------------------------------------
/**
 *	Command DisableDevice related method
 *	Description: Disable device
 *
 *	@param argin Disable device #i
 */
//--------------------------------------------------------
void AttributeCombiner::disable_device(Tango::DevShort argin)
{
	DEBUG_STREAM << "AttributeCombiner::DisableDevice()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::disable_device) ENABLED START -----*/

683
684
685
686
687
688
        if (argin < 0 || argin >= (short) deviceList.size()) {
            Tango::Except::throw_exception(
                    (const char *) "AttributeCombiner::error_write",
                    (const char *) "Invalid device index",
                    (const char *) "AttributeCombiner::disable_device");
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
689

690
        deviceGroup->disable(deviceList[argin]);
Nicolas Tappret's avatar
Nicolas Tappret committed
691
        saveDisabled();
Jean-Luc Pons's avatar
Jean-Luc Pons committed
692

693
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::disable_device
Jean-Luc Pons's avatar
Jean-Luc Pons committed
694
695
}
//--------------------------------------------------------
696
697
698
699
700
701
702
703
704
705
706
707
708
709
/**
 *	Command Indice2Devicename related method
 *	Description: Return the devicename associated to the input indice
 *
 *	@param argin indice of device (from 0)
 *	@returns 
 */
//--------------------------------------------------------
Tango::DevString AttributeCombiner::indice2_devicename(Tango::DevShort argin)
{
	Tango::DevString argout;
	DEBUG_STREAM << "AttributeCombiner::Indice2Devicename()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::indice2_devicename) ENABLED START -----*/

710
711
712
713
714
715
716
717
        if (argin < 0 || argin >= (short) deviceList.size()) {
            Tango::Except::throw_exception(
                    (const char *) "AttributeCombiner::error_write",
                    (const char *) "Invalid device index",
                    (const char *) "AttributeCombiner::indice2_devicename");
        }

        argout = Tango::string_dup(deviceList[argin].c_str());
718
719


720
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::indice2_devicename
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
	return argout;
}
//--------------------------------------------------------
/**
 *	Command Devicename2Indice related method
 *	Description: 
 *
 *	@param argin Devicename
 *	@returns indice of device (from 0) if the devicename is found. -1 otherwise
 */
//--------------------------------------------------------
Tango::DevShort AttributeCombiner::devicename2_indice(Tango::DevString argin)
{
	Tango::DevShort argout;
	DEBUG_STREAM << "AttributeCombiner::Devicename2Indice()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::devicename2_indice) ENABLED START -----*/

738
739
740
741
742
743
744
745
746
747
        string devicename = argin;
        for (argout = 0; argout < (short) deviceList.size(); argout++) {
            if (deviceList[argout] == devicename) return argout;
        }

        argout = -1;
        Tango::Except::throw_exception(
                (const char *) "AttributeCombiner::error_write",
                (const char *) "devicename not found",
                (const char *) "AttributeCombiner::disable_device");
748
749


750
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::devicename2_indice
751
752
753
	return argout;
}
//--------------------------------------------------------
754
755
756
757
758
759
760
761
762
763
764
765
/**
 *	Command DisableAll related method
 *	Description: 
 *
 */
//--------------------------------------------------------
void AttributeCombiner::disable_all()
{
	DEBUG_STREAM << "AttributeCombiner::DisableAll()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::disable_all) ENABLED START -----*/


766
767
        for (int i = 0; i < (int) deviceList.size(); i++)
            deviceGroup->disable(deviceList[i]);
Nicolas Tappret's avatar
Nicolas Tappret committed
768
        saveDisabled();
769
770


771
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::disable_all
772
773
774
775
776
777
778
779
780
781
782
783
784
}
//--------------------------------------------------------
/**
 *	Command EnableAll related method
 *	Description: 
 *
 */
//--------------------------------------------------------
void AttributeCombiner::enable_all()
{
	DEBUG_STREAM << "AttributeCombiner::EnableAll()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::enable_all) ENABLED START -----*/

785
786
        for (int i = 0; i < (int) deviceList.size(); i++)
            deviceGroup->enable(deviceList[i]);
Nicolas Tappret's avatar
Nicolas Tappret committed
787
        saveDisabled();
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860

        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::enable_all
}
//--------------------------------------------------------
/**
 *	Command saveAttribute related method
 *	Description: save attribute in reference attribute. Pass only the name of the attribute you want saved
 *
 *	@param argin name of the attribute than you wand saved
 */
//--------------------------------------------------------
void AttributeCombiner::save_attribute(Tango::DevString argin)
{
	DEBUG_STREAM << "AttributeCombiner::saveAttribute()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AttributeCombiner::save_attribute) ENABLED START -----*/
	string attrName = argin;
        
        ATTITEM * attrToSave = attMap.get(attrName);
        if(attrToSave == nullptr){
            Tango::Except::throw_exception(
                    "Attribute Not Found",
                    "Attribute to Save Not Found",
                    "AttributeCombiner::save_attribute");
        }
        if(attrToSave->refItem == nullptr){
            Tango::Except::throw_exception(
                    "Attribute Found But it don't have reference Attribute",
                    "Attribute Found But it don't have reference Attribute",
                    "AttributeCombiner::save_attribute");
        }
        
        switch (attrToSave->type) {

            case Tango::DEV_BOOLEAN:
                saveAttribute<Tango::DevBoolean>(attrToSave);
                break;

            case Tango::DEV_USHORT:
                saveAttribute<Tango::DevUShort>(attrToSave);
                break;

            case Tango::DEV_SHORT:
                saveAttribute<Tango::DevShort>(attrToSave);
                break;

            case Tango::DEV_ENUM:
                saveAttribute<Tango::DevEnum>(attrToSave);
                break;

            case Tango::DEV_LONG:
                saveAttribute<Tango::DevLong>(attrToSave);
                break;

            case Tango::DEV_LONG64:
                saveAttribute<Tango::DevLong64>(attrToSave);
                break;

            case Tango::DEV_ULONG:
                saveAttribute<Tango::DevULong>(attrToSave);
                break;

            case Tango::DEV_ULONG64:
                saveAttribute<Tango::DevULong64>(attrToSave);
                break;

            case Tango::DEV_DOUBLE:
                saveAttribute<Tango::DevDouble>(attrToSave);
                break;

        }
	//	Add your own code
	
	/*----- PROTECTED REGION END -----*/	//	AttributeCombiner::save_attribute
861
862
}
//--------------------------------------------------------
Jean-Luc Pons's avatar
Jean-Luc Pons committed
863
864
865
866
867
868
869
870
871
/**
 *	Method      : AttributeCombiner::add_dynamic_commands()
 *	Description : Create the dynamic commands if any
 *                for specified device.
 */
//--------------------------------------------------------
void AttributeCombiner::add_dynamic_commands()
{
	/*----- PROTECTED REGION ID(AttributeCombiner::add_dynamic_commands) ENABLED START -----*/
872

873
        for (int i = 0; i < (int) commandList.size(); i++) {
874

875
876
877
            // Create command
            DynCommandClass *cmd = new DynCommandClass(commandList[i].c_str(), Tango::DEV_VOID, Tango::DEV_VOID);
            add_command(cmd);
878

879
880
881
        }
        
        /*----- PROTECTED REGION END -----*/	//	AttributeCombiner::add_dynamic_commands
Jean-Luc Pons's avatar
Jean-Luc Pons committed
882
883
884
885
}

/*----- PROTECTED REGION ID(AttributeCombiner::namespace_ending) ENABLED START -----*/

886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
    template<typename inType>
    void AttributeCombiner::READG(Tango::Attribute &attr, inType &value, ATTITEM *item, Tango::GroupAttrReplyList arl[]) {

        // READ grouped attribute
        // Set to alarm if not all value are equal

        string &attName = attr.get_name();
        bool allEqual = true;
        bool firstValue = true;
        int nbAtt = (int) item->attNames.size();
        int nbDev = (int) deviceGroup->get_size();

        for (int i = 0; i < nbDev; i++) {
            for (int j = 0; j < nbAtt; j++) {
                if (!arl[j][i].has_failed() && arl[j][i].group_element_enabled()) {
                    inType val;
                    arl[j][i] >> val;
                    if (firstValue) {
                        value = val;
                        firstValue = false;
                    } else {
                        allEqual = allEqual && (val == value);
                    }
                } else {
                    if (arl[j][i].group_element_enabled()) {
                        addError(i, arl[j][i]);
                        allEqual = false;
                    }
                }
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
916
917
        }

918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
        if (firstValue) {
            /* All reading failed */
            attr.set_quality(Tango::ATTR_INVALID);
        } else {
            attr.set_value(&value);
            if (!allEqual && item->manageAlarm)
                attr.set_quality(Tango::ATTR_ALARM);

            if (!item->setInit &&
                    item->rwType == Tango::READ_WRITE) {
                Tango::WAttribute &att = getAtt(attName);
                att.set_write_value(value);
                item->setInit = true;
            }
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
933

934
    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
935

936
    /* ------------------------------------------------------------------------------- */
Jean-Luc Pons's avatar
Jean-Luc Pons committed
937

938
    void AttributeCombiner::read_dyn_attributes(Tango::Attribute &attr, DynAttribute *src) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
939

940
941
942
943
        string &attName = attr.get_name();
        ATTITEM *item = attMap.get(attName);
        if (item == NULL) {
            Tango::Except::throw_exception(
Nicolas Tappret's avatar
Nicolas Tappret committed
944
                    (const char *) "AttributeCombiner::error_read",
945
                    (const char *) "Unknown attribute",
Nicolas Tappret's avatar
Nicolas Tappret committed
946
                    (const char *) "AttributeCombiner::read_dyn_attributes");
947
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
948

949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
        // Read all values

        Tango::GroupAttrReplyList arl[MAXATTRIBUTE];
        int nbAtt = (int) item->attNames.size();
        for (int i = 0; i < nbAtt; i++)
            arl[i] = deviceGroup->read_attribute(item->attNames[i]);

        switch (item->type) {
            case Tango::DEV_BOOLEAN:
                READG(attr, item->bVal, item, arl);
                break;
            case Tango::DEV_USHORT:
                READG(attr, item->usVal, item, arl);
                break;
            case Tango::DEV_SHORT:
                READG(attr, item->sVal, item, arl);
                break;
            case Tango::DEV_ULONG:
                READG(attr, item->ulVal, item, arl);
                break;
            case Tango::DEV_LONG:
                READG(attr, item->lVal, item, arl);
                break;
            case Tango::DEV_LONG64:
                READG(attr, item->lVal64, item, arl);
                break;
            case Tango::DEV_ULONG64:
                READG(attr, item->ulVal64, item, arl);
                break;
            case Tango::DEV_DOUBLE:
                READG(attr, item->dVal, item, arl);
                break;
            case Tango::DEV_ENUM:
                READG(attr, item->eVal, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
984

985
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
986

987
    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
988

989
    /* ------------------------------------------------------------------------------- */
Jean-Luc Pons's avatar
Jean-Luc Pons committed
990

991
992
    template <typename T>
    void AttributeCombiner::WRITEG(Tango::WAttribute &attr, ATTITEM *item, Tango::GroupReplyList arl[]) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
993

994
995
        // WRITE grouped attribute
        T w_val;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
996

997
        attr.get_write_value(w_val);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
998

999
1000
1001
1002
1003
        int nbAtt = (int) item->attNames.size();
        for (int i = 0; i < nbAtt; i++) {
            Tango::DeviceAttribute da(item->attNames[i], w_val);
            arl[i] = deviceGroup->write_attribute(da);
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1004

1005
    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1006

1007
    void AttributeCombiner::write_dyn_attributes(Tango::WAttribute &attr, DynAttribute *src) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1008
1009


1010
1011
1012
1013
1014
1015
1016
        ATTITEM *item = attMap.get(attr.get_name());
        if (item == NULL) {
            Tango::Except::throw_exception(
                    (const char *) "AttributeCombiner::error_write",
                    (const char *) "Unknown attribute",
                    (const char *) "AttributeCombiner::write_dyn_attributes");
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1017

1018
1019
1020
        Tango::GroupReplyList arl[MAXATTRIBUTE];
        int nbAtt = (int) item->attNames.size();
        int nbDev = (int) deviceGroup->get_size();
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1021

1022
        switch (item->type) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1023

1024
1025
1026
            case Tango::DEV_BOOLEAN:
                WRITEG<Tango::DevBoolean>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1027

1028
1029
1030
            case Tango::DEV_USHORT:
                WRITEG<Tango::DevUShort>(attr, item, arl);
                break;
1031

1032
1033
1034
            case Tango::DEV_SHORT:
                WRITEG<Tango::DevShort>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1035

1036
1037
1038
            case Tango::DEV_ENUM:
                WRITEG<Tango::DevEnum>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1039

1040
1041
1042
            case Tango::DEV_LONG:
                WRITEG<Tango::DevLong>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1043

1044
1045
1046
            case Tango::DEV_LONG64:
                WRITEG<Tango::DevLong64>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1047

1048
1049
1050
            case Tango::DEV_ULONG:
                WRITEG<Tango::DevULong>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1051

1052
1053
1054
            case Tango::DEV_ULONG64:
                WRITEG<Tango::DevULong64>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1055

1056
1057
1058
            case Tango::DEV_DOUBLE:
                WRITEG<Tango::DevDouble>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1059

1060
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1061

1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
        // Check results
        for (int j = 0; j < nbAtt; j++) {
            for (int i = 0; i < nbDev; i++) {
                if (arl[j][i].has_failed() && arl[j][i].group_element_enabled()) {
                    char errStr[512];
                    sprintf(errStr, "Failed to write %s/%s\n%s",
                            arl[j][i].dev_name().c_str(), item->attNames[0].c_str(),
                            (const char *) arl[j][i].get_err_stack().get_buffer()[0].desc);
                    Tango::Except::throw_exception(
                            (const char *) "AttributeCombiner::error_write",
                            (const char *) errStr,
                            (const char *) "AttributeCombiner::write_dyn_attributes");
                }
            }
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1077

1078
    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1079

1080
    /* ------------------------------------------------------------------------------- */
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1081

1082
1083
    template <typename inType, typename outType>
    void AttributeCombiner::READSCALAR(Tango::Attribute &attr, ATTITEM *item, Tango::GroupAttrReplyList arl[], outType invalid, outType disableValue) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1084

1085
1086
1087
1088
        string& attName = attr.get_name();
        int nbAtt = (int) item->attNames.size();
        int nbDev = deviceGroup->get_size();
        int size = nbDev * nbAtt;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1089

1090
1091
        // Read scalar attribute and combime them to spectrum
        outType *result = new outType[size];
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1092

1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
        for (int i = 0; i < nbDev; i++) {

            for (int j = 0; j < nbAtt; j++) {
                if (arl[j][i].has_failed()) {
                    result[i * nbAtt + j] = invalid;
                    addError(i, arl[j][i]);
                } else {
                    if (arl[j][i].group_element_enabled()) {
                        inType v;
                        arl[j][i] >> v;
                        result[i * nbAtt + j] = (outType) v;
                    } else {
                        result[i * nbAtt + j] = disableValue;
                    }
                }
            }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1109
1110
1111

        }

1112
1113
1114
1115
1116
1117
        if (!item->setInit &&
                item->rwType == Tango::READ_WRITE) {
            Tango::WAttribute &att = getAtt(attName);
            att.set_write_value(result, size);
            item->setInit = true;
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1118

1119
1120
        //Update cache
        item->lastUpdate = timeMS();
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1121

1122
1123
1124
        if (size != item->cacheSize && item->cacheData != nullptr) {
            SAFE_FREE(item->cacheData);
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1125

1126
1127
1128
        if (item->cacheData == nullptr) {
            item->cacheData = (void *) malloc(size * sizeof (outType));
            item->cacheSize = size;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1129
1130
        }

1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
        memcpy(item->cacheData, result, size * sizeof (outType));

        attr.set_value(result, size, 0, true);

    }

    /* ------------------------------------------------------------------------------- */

    template <typename inType>
    void AttributeCombiner::READSPECTRUM(Tango::Attribute &attr, ATTITEM *item, Tango::GroupAttrReplyList arl[]) {

        // Read spectrum attribute and combime them to multiple spectrum
        Tango::DevULong length;

        int nbAtt = (int) item->attNames.size();
        int nbDev = deviceGroup->get_size();
        int size = nbDev * nbAtt;


        if (isNumber(item->lengthAttName))
            length = atol(item->lengthAttName.c_str());
        else
            self->read_attribute(item->lengthAttName) >> length;

        int blockSize = length * nbAtt;
        Tango::DevDouble *result = new Tango::DevDouble[length * size];
        for (int i = 0; i < nbDev; i++) {

            for (int j = 0; j < nbAtt; j++) {
                if (arl[j][i].has_failed()) {
                    for (int k = 0; k < (int) length; k++)
                        result[i * blockSize + j * length + k] = NAN;
                    addError(i, arl[j][i]);
                } else {
                    if (arl[j][i].group_element_enabled()) {
                        int k = 0;
                        vector<inType> v;
                        arl[j][i] >> v;
                        for (k = 0; k < (int) length && k < (int) v.size(); k++)
                            result[i * blockSize + j * length + k] = (Tango::DevDouble) v[k];
                        for (; k < (int) length; k++)
                            result[i * length * nbAtt + j * length + k] = NAN;
                    } else {
                        // Disabled device
                        for (int k = 0; k < (int) length; k++)
                            result[i * blockSize + j * length + k] = NAN;
                    }
                }
            }
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1181
1182
1183



1184
        attr.set_value(result, length * size, 0, true);
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1185

1186
    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1187

1188
    /* ------------------------------------------------------------------------------- */
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1189

1190
    void AttributeCombiner::read_dynspec_attributes(Tango::Attribute &attr, DynSpectrumAttribute *src) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1191

1192
1193
1194
1195
1196
1197
1198
1199
        string& attName = attr.get_name();
        ATTITEM *item = attMap.get(attName);
        if (item == NULL) {
            Tango::Except::throw_exception(
                    (const char *) "AttributeCombiner::error_read",
                    (const char *) "Unknown attribute",
                    (const char *) "AttributeCombiner::read_dynspec_attributes");
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1200

1201
1202
1203
1204
1205
1206
        // Attribute ref
        if (item->isRef) {
            if (item->refData != NULL)
                attr.set_value(item->refData, item->refSize);
            return;
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1207

1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
        if (item->isDiff) {
            bool needLiveAttributeCacheUpdate = (item->liveItem->lastUpdate + refreshTime) < timeMS() || item->liveItem->cacheData == nullptr;
            //Launch update cache for liveAttribute. A simple reading is enough
            if (needLiveAttributeCacheUpdate) {
                self->read_attribute(item->liveItem->attName);
            }

            //find minimum length
            int diffLength;
            if (item->liveItem->cacheSize > item->refItem->refSize) {
                diffLength = item->refItem->refSize;
            } else {
                diffLength = item->liveItem->cacheSize;
            }

            bool needCacheUpdate = (item->lastUpdate + refreshTime) < timeMS() || item->cacheData == nullptr;

            if (!needCacheUpdate) {
                attr.set_value((Tango::DevDouble *)item->cacheData, item->cacheSize);
                return;
            }

            //Update cache
            item->lastUpdate = timeMS();

            if (diffLength != item->cacheSize && item->cacheData != nullptr) {
                SAFE_FREE(item->cacheData);
            }

            if (item->cacheData == nullptr) {
                if (diffLength > 0) {
                    item->cacheData = (void *) malloc(diffLength * sizeof (Tango::DevDouble));
                }
                item->cacheSize = diffLength;
            }

            Tango::DevDouble * liveCacheData = new Tango::DevDouble[diffLength];

            ATTITEM * itemLive = item->liveItem;

            switch (item->type) {

                case Tango::DEV_BOOLEAN:
                    convertTypePtrToDoublePtr((Tango::DevBoolean *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_ENUM:
                    convertTypePtrToDoublePtr((Tango::DevEnum *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_USHORT:
                    convertTypePtrToDoublePtr((Tango::DevUShort *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_SHORT:
                    convertTypePtrToDoublePtr((Tango::DevShort *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_LONG:
                    convertTypePtrToDoublePtr((Tango::DevLong *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_ULONG:
                    convertTypePtrToDoublePtr((Tango::DevULong *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_LONG64:
                    convertTypePtrToDoublePtr((Tango::DevLong64 *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_ULONG64:
                    convertTypePtrToDoublePtr((Tango::DevLong64 *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_STATE:
                    convertTypePtrToDoublePtr((Tango::DevState *)itemLive->cacheData, liveCacheData, diffLength);
                    break;

                case Tango::DEV_DOUBLE:
                    liveCacheData = (Tango::DevDouble *)itemLive->cacheData;
                    break;

            }

            Tango::DevDouble * cacheDataPtr = (Tango::DevDouble *)item->cacheData;
            for (int i = 0; i < diffLength; i++) {
                cacheDataPtr[i] = liveCacheData[i] - item->refItem->refData[i];
            }

            if (diffLength == 0) {
                attr.set_quality(Tango::ATTR_INVALID);
            } else {
                attr.set_value((Tango::DevDouble *)item->cacheData, item->cacheSize);
            }
            return;
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1304
1305


1306
        bool needCacheUpdate = (item->lastUpdate + refreshTime) < timeMS() || item->cacheData == nullptr;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1307

1308
1309
1310
1311
        if (!needCacheUpdate) {
            setValueGoodCacheType(attr, item);
            return;
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1312

1313
        Tango::GroupAttrReplyList arl[MAXATTRIBUTE];
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1314

1315
1316
        // Read all attribute
        int nbAtt = (int) item->attNames.size();
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1317

1318
1319
1320
        for (int i = 0; i < nbAtt; i++) {
            arl[i] = deviceGroup->read_attribute(item->attNames[i]);
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1321

1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
        switch (item->type) {

            case Tango::DEV_BOOLEAN:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevBoolean>(attr, item, arl);
                else
                    READSCALAR<Tango::DevBoolean, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_ENUM:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevEnum>(attr, item, arl);
                else
                    READSCALAR<Tango::DevEnum, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_USHORT:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevUShort>(attr, item, arl);
                else
                    READSCALAR<Tango::DevUShort, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_SHORT:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevShort>(attr, item, arl);
                else
                    READSCALAR<Tango::DevShort, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_LONG:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevLong>(attr, item, arl);
                else
                    READSCALAR<Tango::DevLong, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_ULONG:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevULong>(attr, item, arl);
                else
                    READSCALAR<Tango::DevULong, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_LONG64:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevLong64>(attr, item, arl);
                else
                    READSCALAR<Tango::DevLong64, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_ULONG64:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevULong64>(attr, item, arl);
                else
                    READSCALAR<Tango::DevULong64, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;

            case Tango::DEV_STATE:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevState>(attr, item, arl);
                else {
                    if (attName == "States") {
                        READSCALAR<Tango::DevState, Tango::DevState>(attr, item, arl, Tango::UNKNOWN, Tango::DISABLE);
                    } else {
                        READSCALAR<Tango::DevState, Tango::DevState>(attr, item, arl, Tango::UNKNOWN, Tango::UNKNOWN);
                    }
                }
                break;

            case Tango::DEV_DOUBLE:
                if (item->isSpectrum)
                    READSPECTRUM<Tango::DevDouble>(attr, item, arl);
                else
                    READSCALAR<Tango::DevDouble, Tango::DevDouble>(attr, item, arl, NAN, NAN);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1398

1399
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1400

1401
    }
1402

1403
    /* ------------------------------------------------------------------------------- */
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1404

1405
1406
    template <typename inType, typename outType>
    void AttributeCombiner::WRITES(Tango::WAttribute &attr, ATTITEM *item, Tango::GroupReplyList arl[]) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1407

1408
1409
1410
1411
        // Write scalar attributes from combined spectrum
        int nbAtt = (int) item->attNames.size();
        int nbDev = deviceGroup->get_size();
        int size = nbAtt*nbDev;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1412

1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
        const inType *w_val;
        attr.get_write_value(w_val);
        int length = attr.get_write_value_length();
        if (length != size) {
            char errStr[256];
            sprintf(errStr, "Invalid argument size (%d expected)", size);
            Tango::Except::throw_exception(
                    (const char *) "AttributeCombiner::error_write",
                    (const char *) errStr,
                    (const char *) "AttributeCombiner::write_dynspec_attributes");
        }
        for (int k = 0; k < nbAtt; k++) {
            vector<outType> cw_val;
            for (int i = 0; i < nbDev; i++)
                cw_val.push_back((outType) w_val[i * nbAtt + k]);
            arl[k] = deviceGroup->write_attribute(item->attNames[k], cw_val);
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1430

1431
    }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1432

1433
    void AttributeCombiner::write_dynspec_attributes(Tango::WAttribute &attr, DynSpectrumAttribute *src) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1434
1435


1436
1437
1438
1439
1440
1441
1442
        ATTITEM *item = attMap.get(attr.get_name());
        if (item == NULL) {
            Tango::Except::throw_exception(
                    (const char *) "AttributeCombiner::error_read",
                    (const char *) "Unknown attribute",
                    (const char *) "AttributeCombiner::read_dynspec_attributes");
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1443

1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
        // Attribute ref
        if (item->isRef) {
            const Tango::DevDouble *w_val;
            attr.get_write_value(w_val);
            int length = attr.get_write_value_length();
            SAFE_FREE(item->refData);
            item->refData = (double *) malloc(length * sizeof (double));
            memcpy(item->refData, w_val, length * sizeof (double));
            item->refSize = length;
            
            stringstream ss;
            ss << std::fixed;
            for(int i = 0 ; i < length ; i++){
                ss << item->refData[i] << ",";
            }
            string contents = ss.str();
            contents = contents.substr(0,contents.size()-1);
            writeAttributeProperty(item->attName,"__value",contents);
            return;
        }
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1464

1465
        Tango::GroupReplyList arl[MAXATTRIBUTE];
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1466

1467
        // Read all attributes
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1468

1469
        switch (item->type) {
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1470

1471
1472
1473
            case Tango::DEV_USHORT:
                WRITES<Tango::DevDouble, Tango::DevUShort>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1474

1475
1476
1477
            case Tango::DEV_SHORT:
                WRITES<Tango::DevDouble, Tango::DevShort>(attr, item, arl);
                break;
Jean-Luc Pons's avatar
Jean-Luc Pons committed
1478

1479
</