From 92b68f9cf4bca092dca8fc578e09558e96a19e92 Mon Sep 17 00:00:00 2001
From: gscalamera <graziano.scalamera@elettra.eu>
Date: Fri, 19 Aug 2016 11:53:04 +0200
Subject: [PATCH] added dynamic attributes for alarms with quality and
 exceptions

---
 src/Alarm.cpp             | 448 ++++++++++++++++++++++++++++++++------
 src/Alarm.h               |  20 +-
 src/Alarm.xmi             |  10 +-
 src/AlarmClass.h          |  17 ++
 src/AlarmDynAttrUtils.cpp | 158 ++++++++++++++
 src/AlarmStateMachine.cpp |  16 ++
 src/alarm_table.cpp       |  47 +++-
 src/alarm_table.h         | 171 ++++++++++++++-
 src/event_table.cpp       |   9 +-
 src/event_table.h         |  10 +
 10 files changed, 821 insertions(+), 85 deletions(-)
 create mode 100644 src/AlarmDynAttrUtils.cpp

diff --git a/src/Alarm.cpp b/src/Alarm.cpp
index 6a4648d..2d7c109 100644
--- a/src/Alarm.cpp
+++ b/src/Alarm.cpp
@@ -302,7 +302,7 @@ void Alarm::init_device()
 	alarmedlock = new(ReadersWritersLock);
 	internallock = new(ReadersWritersLock);
 	dslock = new(ReadersWritersLock);
-
+	alarms.set_dev(this);
 
 	/*----- PROTECTED REGION END -----*/	//	Alarm::init_device_before
 	
@@ -1086,6 +1086,72 @@ void Alarm::read_alarm(Tango::Attribute &attr)
 	/*----- PROTECTED REGION END -----*/	//	Alarm::read_alarm
 }
 
+//--------------------------------------------------------
+/**
+ *	Read attribute AlarmState related method
+ *	Description: 
+ *
+ *	Data type:	Tango::DevBoolean
+ *	Attr type:	Scalar
+ */
+//--------------------------------------------------------
+void Alarm::read_AlarmState(Tango::Attribute &attr)
+{
+	DEBUG_STREAM << "Alarm::read_AlarmState(Tango::Attribute &attr) entering... " << endl;
+	Tango::DevBoolean	*att_value = get_AlarmState_data_ptr(attr.get_name());
+	/*----- PROTECTED REGION ID(Alarm::read_AlarmState) ENABLED START -----*/
+	string reason("");
+	string desc("");
+	string origin("");
+	int quality = Tango::ATTR_VALID;
+#ifndef _RW_LOCK
+	alarms.lock();
+#else
+	alarms.vlock->readerIn();
+#endif
+	alarm_container_t::iterator it;
+	for(it = alarms.v_alarm.begin(); it != alarms.v_alarm.end(); it++)
+	{
+		if(it->second.attr_name == attr.get_name())
+		{
+
+			break;
+		}
+	}
+	if(it != alarms.v_alarm.end())
+	{
+		reason = it->second.ex_reason;
+		desc = it->second.ex_desc;
+		origin = it->second.ex_origin;
+		quality = it->second.quality;
+	}
+	DEBUG_STREAM << "Alarm::read_AlarmState: " << attr.get_name() << " desc=" << desc << endl;
+#ifndef _RW_LOCK
+	alarms.unlock();
+#else
+	alarms.vlock->readerOut();
+#endif
+	if(desc.length() > 0)
+	{
+		Tango::Except::throw_exception(
+				reason,
+				desc,
+				origin, Tango::ERR);
+	}
+	//	Set the attribute value
+	if(quality != Tango::ATTR_VALID)
+	{
+		timeval now;
+		gettimeofday(&now, NULL);
+		attr.set_value_date_quality(att_value, now/*TODO timestamp*/, (Tango::AttrQuality)quality);
+	}
+	else
+	{
+		attr.set_value(att_value);
+	}
+	
+	/*----- PROTECTED REGION END -----*/	//	Alarm::read_AlarmState
+}
 //--------------------------------------------------------
 /**
  *	Method      : Alarm::add_dynamic_attributes()
@@ -1095,9 +1161,34 @@ void Alarm::read_alarm(Tango::Attribute &attr)
 //--------------------------------------------------------
 void Alarm::add_dynamic_attributes()
 {
+	//	Example to add dynamic attribute:
+	//	Copy inside the following protected area to create instance(s) at startup.
+	//	add_AlarmState_dynamic_attribute("MyAlarmStateAttribute");
+	
 	/*----- PROTECTED REGION ID(Alarm::add_dynamic_attributes) ENABLED START -----*/
 	
 	//	Add your own code to create and add dynamic attributes if any
+#ifndef _RW_LOCK
+	alarms.lock();
+#else
+	alarms.vlock->readerIn();
+#endif
+	if (alarms.v_alarm.empty() == false)
+	{
+		for (alarm_container_t::iterator i = alarms.v_alarm.begin(); \
+			i != alarms.v_alarm.end(); i++)
+		{
+			add_AlarmState_dynamic_attribute(i->second.attr_name);
+			Tango::DevBoolean *attr_value = get_AlarmState_data_ptr(i->second.attr_name);
+			i->second.attr_value = attr_value;
+		}
+	}
+#ifndef _RW_LOCK
+	alarms.unlock();
+#else
+	alarms.vlock->readerOut();
+#endif
+
 	
 	/*----- PROTECTED REGION END -----*/	//	Alarm::add_dynamic_attributes
 }
@@ -1427,12 +1518,12 @@ void Alarm::load(Tango::DevString argin)
 	if(alm.to_be_evaluated)							//TODO: remove this evaluation of the formula that is not necessary
 	{
 		DEBUG_STREAM << "Alarm::load(): Evaluating formula=" << alm.formula << endl;
-		try {    	
-    		double res;
+		try {
+			struct formula_res_t res;
     		string attr_values;
     		res = eval_formula(alm.formula_tree, attr_values);
-          	DEBUG_STREAM << "Parsing succeeded of "<< alm.formula << "; result=" << res << endl;
-        	alarms.update(alm.name, gettime(), (int)res, attr_values, alm.grp2str(), alm.msg, alm.formula);		//pass "now" as timestamp in this case
+          	DEBUG_STREAM << "Parsing succeeded of "<< alm.formula << "; result=" << res.value << " quality=" << res.quality << endl;
+        	alarms.update(alm.name, gettime(), res, attr_values, alm.grp2str(), alm.msg, alm.formula);		//pass "now" as timestamp in this case
 
 		} catch(std::out_of_range& e)
 		{
@@ -1839,6 +1930,11 @@ void Alarm::modify(Tango::DevString argin)
 	alarm_t alm;
 	alarm_parse al_gr(alm);    //  Construct Spirit grammar
 	alm.name.clear();
+	alm.attr_name.clear();
+	alm.quality = Tango::ATTR_VALID;
+	alm.ex_reason.clear();
+	alm.ex_desc.clear();
+	alm.ex_origin.clear();
 	alm.formula.clear();
 	alm.msg.clear();
 	alm.lev.clear();
@@ -2130,6 +2226,11 @@ void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
 	DEBUG_STREAM << "Alarm::load_alarm(): Creating Spirit Parser..." << endl;
 	alarm_parse al_gr(alm);    //  Construct Spirit grammar		
 	alm.name.clear();
+	alm.attr_name.clear();
+	alm.quality = Tango::ATTR_VALID;
+	alm.ex_reason.clear();
+	alm.ex_desc.clear();
+	alm.ex_origin.clear();
 	alm.formula.clear();
 	alm.msg.clear();
 	alm.lev.clear();
@@ -2160,6 +2261,19 @@ void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
 	if (alm.formula_tree.full)
 	{
     	std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower);		//transform to lowercase
+    	//replace / with __
+    	if(!alm.name.empty())
+    	{
+    		alm.attr_name = alm.name;
+			size_t start_pos = 0;
+			string from("/");
+			string to("__");
+			while((start_pos = alm.attr_name.find(from, start_pos)) != std::string::npos)
+			{
+				alm.attr_name.replace(start_pos, from.length(), to);
+				start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
+			}
+    	}
     	//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower);		//transform to lowercase: incorrect, state has to be written uppercase
     	std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower);		//transform to lowercase
     	
@@ -2219,6 +2333,7 @@ void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
     }	
 	alm.ts = gettime();
 	DEBUG_STREAM << "Alarm::load_alarm(): name     = '" << alm.name << "'" << endl;
+	DEBUG_STREAM << "               attr_name     = '" << alm.attr_name << "'" << endl;
 	DEBUG_STREAM << "               formula        = '" << alm.formula << "'" << endl;
 	DEBUG_STREAM << "               time_threshold = '" << alm.time_threshold << "'" << endl;	
 	DEBUG_STREAM << "               msg            = '" << alm.msg << "'" << endl;
@@ -2247,7 +2362,9 @@ void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
 				(const char*)"", \
 				(const char*)"Alarm::load_alarm()", Tango::ERR);
 	}
-
+	add_AlarmState_dynamic_attribute(alm.attr_name);
+	Tango::DevBoolean *attr_value = get_AlarmState_data_ptr(alm.attr_name);
+	alm.attr_value = attr_value;
 	if (alarms.exist(alm.name)) {
 		ostringstream o;
 		o << "Alarm::load_alarm(): alarm '" << alm.name << "' already exist" << ends;
@@ -2500,8 +2617,10 @@ void Alarm::subscribe_event(alarm_t& a, EventCallBack& ecb, vector<string> &evn)
 void Alarm::do_alarm(bei_t& e)
 {
 	bool changed=true;
+	int num_changed=0;
 	//if (e.name == INTERNAL_ERROR) {
-	if(e.type == TYPE_TANGO_ERR) {	
+	if(e.type == TYPE_TANGO_ERR || e.type == TYPE_GENERIC_ERR)
+	{
 		ostringstream o;
 		o << e.msg << endl;
 		WARN_STREAM << "Alarm::do_alarm(): " <<  o.str() << endl;
@@ -2550,20 +2669,61 @@ void Alarm::do_alarm(bei_t& e)
 		{
 			found_ev->err_counter++;
 			if(found_ev->err_counter >= errThreshold)
-				set_internal_alarm(e.ev_name, gettime(), o.str(), errThreshold);			
+			{
+				set_internal_alarm(e.ev_name, gettime(), o.str(), errThreshold);
+			}
+			if(e.type == TYPE_TANGO_ERR)
+				found_ev->ex_reason = string("Event_ERROR");
+			else
+				found_ev->ex_reason = string("Alarm_ERROR");
+			found_ev->ex_desc = o.str();
+			found_ev->ex_origin = e.ev_name;
+			//LOOP ALARMS IN WHICH THIS EVENT IS USED
+			vector<string>::iterator j = found_ev->m_alarm.begin();
+			while (j != found_ev->m_alarm.end())
+			{
+#ifndef _RW_LOCK
+				alarms.lock();
+#else
+				alarms.vlock->readerIn();
+#endif
+				alarm_container_t::iterator it = alarms.v_alarm.find(*j);
+				if(it != alarms.v_alarm.end())
+				{
+					try
+					{
+						if(e.type == TYPE_TANGO_ERR)
+							it->second.ex_reason = found_ev->ex_reason;
+						else
+							it->second.ex_reason = found_ev->ex_reason;
+						it->second.ex_desc = found_ev->ex_desc;
+						it->second.ex_origin = found_ev->ex_origin;
+						Tango::DevErrorList errors(1);
+						errors.length(1);
+						errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
+						errors[0].severity = Tango::ERR;
+						errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
+						errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
+						Tango::DevFailed except(errors);
+						DEBUG_STREAM << "PUSHING EXCEPTION FOR " << it->second.attr_name << " " << it->second.ex_desc << "-" << it->second.ex_reason << "-" << it->second.ex_origin << endl;
+						push_change_event(it->second.attr_name, &except);
+						push_archive_event(it->second.attr_name, &except);
+					}catch(Tango::DevFailed &ex)
+					{}
+				}
+#ifndef _RW_LOCK
+          		alarms.unlock();
+#else
+          		alarms.vlock->readerOut();
+#endif
+          		j++;
+			}
 		}
 		return;
-	}
-	else if(e.type == TYPE_GENERIC_ERR) {	
-		ostringstream o;
-		o << e.msg << endl;
-		WARN_STREAM << "Alarm::do_alarm(): " <<  o.str() << endl;
-		set_internal_alarm(e.ev_name, gettime(), o.str());
-		return;
 	}	
 	DEBUG_STREAM << "Alarm::do_alarm(): arrived event=" << e.ev_name << endl;
 	
-	double res;
+	formula_res_t res;
 	vector<event>::iterator found = \
 			find(events->v_event.begin(), events->v_event.end(), e.ev_name);
 	if (found == events->v_event.end())
@@ -2608,6 +2768,11 @@ void Alarm::do_alarm(bei_t& e)
 	if (found != events->v_event.end())
 	{	
 		found->value = e.value;
+		found->quality = e.quality;
+		//found->errors = e.errors;
+		found->ex_reason = e.ex_reason;
+		found->ex_desc = e.ex_desc;
+		found->ex_origin = e.ex_origin;
 		found->valid = true;
 		found->ts = e.ts;
 		found->type = e.type;
@@ -2628,14 +2793,43 @@ void Alarm::do_alarm(bei_t& e)
 				try {   	
     				string attr_values;
     				res = eval_formula(it->second.formula_tree, attr_values);
-          			DEBUG_STREAM << "Alarm::do_alarm(): Evaluation of " << it->second.formula << "; result=" << res << endl;
+          			DEBUG_STREAM << "Alarm::do_alarm(): Evaluation of " << it->second.formula << "; result=" << res.value << " quality=" << res.quality << endl;
 #ifndef _RW_LOCK
           			alarms.unlock();
 #else
           			alarms.vlock->readerOut();
 #endif
-          			changed = alarms.update(tmpname, found->ts, (int)res, attr_values, it->second.grp2str(), it->second.msg, it->second.formula); 		//update internal structure and log to db
-				} catch(std::out_of_range& e)
+          			changed = alarms.update(tmpname, found->ts, res, attr_values, it->second.grp2str(), it->second.msg, it->second.formula); 		//update internal structure and log to db
+          			if(changed)
+          				num_changed++;
+          			Tango::DevBoolean *attr_value = get_AlarmState_data_ptr(it->second.attr_name);
+          			*attr_value = (it->second.stat == S_ALARM);
+    				try
+    				{	//DevFailed for push events
+    					if(it->second.ex_reason.length() == 0)
+    					{
+    						timeval now;
+    						gettimeofday(&now, NULL);
+    						push_change_event(it->second.attr_name,(Tango::DevBoolean *)attr_value,now,(Tango::AttrQuality)it->second.quality, 1/*size*/, 0, false);
+    						push_archive_event(it->second.attr_name,(Tango::DevBoolean *)attr_value,now,(Tango::AttrQuality)it->second.quality, 1/*size*/, 0, false);
+    					}
+    					else
+    					{
+    						Tango::DevErrorList errors(1);
+    						errors.length(1);
+    						errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
+    						errors[0].severity = Tango::ERR;
+    						errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
+    						errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
+    						Tango::DevFailed except(errors);
+        					push_change_event(it->second.attr_name, &except);
+        					push_archive_event(it->second.attr_name, &except);
+    					}
+    				} catch(Tango::DevFailed & ex)
+    				{
+    					WARN_STREAM << "Alarm::do_alarm(): EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
+    				}
+				} catch(std::out_of_range& ex)
 				{
 #ifndef _RW_LOCK
           			alarms.unlock();
@@ -2645,8 +2839,26 @@ void Alarm::do_alarm(bei_t& e)
 					ostringstream o;
 					o << tmpname << ": in formula array index out of range!" << ends;
 					WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
-					set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());				
-				} catch(string & e)
+					set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
+    				try
+    				{	//DevFailed for push events
+						Tango::DevErrorList errors(1);
+						errors.length(1);
+						it->second.ex_reason = string("OUT_OF_RANGE");
+						it->second.ex_desc = e.ev_name + ": " + o.str();
+						it->second.ex_origin = e.ev_name;
+						errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
+						errors[0].severity = Tango::ERR;
+						errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
+						errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
+						Tango::DevFailed except(errors);
+    					push_change_event(it->second.attr_name, &except);
+    					push_archive_event(it->second.attr_name, &except);
+    				} catch(Tango::DevFailed & ex)
+    				{
+    					WARN_STREAM << "Alarm::do_alarm(): EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
+    				}
+				} catch(string & ex)
 				{
 #ifndef _RW_LOCK
           			alarms.unlock();
@@ -2654,9 +2866,27 @@ void Alarm::do_alarm(bei_t& e)
           			alarms.vlock->readerOut();
 #endif
 					ostringstream o;
-					o << tmpname << ": in formula err=" << e << ends;
+					o << tmpname << ": in formula err=" << ex << ends;
 					WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
-					set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());				
+					set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
+    				try
+    				{	//DevFailed for push events
+						Tango::DevErrorList errors(1);
+						errors.length(1);
+						it->second.ex_reason = string("FORMULA_ERROR");
+						it->second.ex_desc = e.ev_name + ": " + o.str();
+						it->second.ex_origin = e.ev_name;
+						errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
+						errors[0].severity = Tango::ERR;
+						errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
+						errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
+						Tango::DevFailed except(errors);
+    					push_change_event(it->second.attr_name, &except);
+    					push_archive_event(it->second.attr_name, &except);
+    				} catch(Tango::DevFailed & ex)
+    				{
+    					WARN_STREAM << "Alarm::do_alarm(): EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
+    				}
 				}
 			}
 			else
@@ -2670,14 +2900,31 @@ void Alarm::do_alarm(bei_t& e)
 				//o << j->first << ": not found formula in alarm table" << ends;
 				o << (*j) << ": not found formula in alarm table" << ends;
 				WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
-				set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());				
+				set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
+				try
+				{	//DevFailed for push events
+					Tango::DevErrorList errors(1);
+					errors.length(1);
+					it->second.ex_reason = string("NOT_FOUND");
+					it->second.ex_desc = e.ev_name + ": " + o.str();
+					it->second.ex_origin = e.ev_name;
+					errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
+					errors[0].severity = Tango::ERR;
+					errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
+					errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
+					Tango::DevFailed except(errors);
+					push_change_event(it->second.attr_name, &except);
+					push_archive_event(it->second.attr_name, &except);
+				} catch(Tango::DevFailed & ex)
+				{
+					WARN_STREAM << "Alarm::do_alarm(): EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
+				}
 			}
 			j++;
 		}
 
-		//TODO: push_change_event HERE!
 		prepare_alarm_attr();
-		if(!changed)
+		if(num_changed==0)
 			return;
 		if(ds_num == 0)
 		{
@@ -2704,7 +2951,19 @@ void Alarm::timer_update()
 		ostringstream o;
 		o << "Error checking time thresholds and updating alarm status=" << e << ends;
 		WARN_STREAM << "Alarm::timer_update(): " << o.str() << endl;
-		set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());				
+		set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
+/*		Tango::DevErrorList errors(1);
+		errors.length(1);
+		it->second.ex_reason = string("INTERNAL_ERROR");
+		it->second.ex_desc = o.str();
+		it->second.ex_origin = string("Alarm::timer_update");
+		errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
+		errors[0].severity = Tango::ERR;
+		errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
+		errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
+		Tango::DevFailed except(errors);
+		push_change_event(it->second.attr_name, &except);
+		push_archive_event(it->second.attr_name, &except);*/
 	}
 
 	prepare_alarm_attr();
@@ -2805,13 +3064,14 @@ bool Alarm::remove_alarm(string& s) throw(string&)
 		i->second.dp_n = NULL;		
 		/*
 		 * remove this alarm from alarm table
-		 */			
+		 */
+		remove_AlarmState_dynamic_attribute(i->second.attr_name);
+		alarms.erase(i);
 #ifndef _RW_LOCK
 		alarms.unlock();
 #else
 		alarms.vlock->writerOut();
 #endif
-		alarms.erase(i);
 		return true;
 	}
 #ifndef _RW_LOCK
@@ -2949,12 +3209,12 @@ void Alarm::set_internal_alarm(string name, Tango::TimeVal t, string msg, unsign
 //==============================================================
 //------------------- AST evaluation methods -------------------
 //==============================================================
-double Alarm::eval_formula(tree_parse_info_t tree, string &attr_values)
+formula_res_t Alarm::eval_formula(tree_parse_info_t tree, string &attr_values)
 {
     return eval_expression(tree.trees.begin(), attr_values);
 }
 
-double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind) //throw (string &), std::out_of_range
+formula_res_t Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind) //throw (string &), std::out_of_range
 {
 
     ostringstream err;
@@ -2969,8 +3229,10 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         	throw err.str(); 
         }
         string val_d(i->value.begin(), i->value.end());
-		DEBUG_STREAM << "		node value real = " << val_d << endl;
-        return strtod(val_d.c_str(), 0);
+		formula_res_t res;
+		res.value = strtod(val_d.c_str(), 0);
+		DEBUG_STREAM << "		node value real = " << val_d << "(value="<<res.value<<" quality="<<res.quality<<")" << endl;
+        return res;
     }
     else if (i->value.id() == formula_grammar::val_hID)
     {
@@ -2981,7 +3243,9 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         }        		
         string val_d(i->value.begin(), i->value.end());
 		DEBUG_STREAM << "		node value hex = " << val_d << endl;
-        return strtod(val_d.c_str(), 0);
+		formula_res_t res;
+		res.value = strtod(val_d.c_str(), 0);
+        return res;
     } 
     else if (i->value.id() == formula_grammar::val_stID)
     {
@@ -3025,7 +3289,9 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         double st =  i->value.value();			//get value directly from node saved with access_node_d
 #endif //_ACCESS_NODE_D    	        	        	      	        	        	        	        	        	        	        	        	
 		DEBUG_STREAM << "		node value state : " << val_st << "=" << st << endl;
-        return st;
+		formula_res_t res;
+		res.value = st;
+        return res;
     }       
     else if (i->value.id() == formula_grammar::unary_exprID)
     {
@@ -3035,12 +3301,15 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         	err <<  "in node unary_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
         	throw err.str(); 
         }
+		formula_res_t res;
+		res = eval_expression(i->children.begin(), attr_values);
         if (*i->value.begin() == '+')
-        	return + eval_expression(i->children.begin(), attr_values);
+        	res.value = + res.value;
         if (*i->value.begin() == '-')
-        	return - eval_expression(i->children.begin(), attr_values);
+        	res.value = - res.value;
         if (*i->value.begin() == '!')
-        	return ! eval_expression(i->children.begin(), attr_values);        	        	
+        	res.value = ! res.value;
+        return res;
     }
     else if (i->value.id() == formula_grammar::mult_exprID)
     {
@@ -3093,20 +3362,20 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
     else if (i->value.id() == formula_grammar::event_ID)
     {
 		DEBUG_STREAM << "		node event" << string(i->value.begin(), i->value.end()) << endl;
-		int ind;
+		formula_res_t ind;
 		if(i->children.size() != 2)		
 		{
         	err <<  "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;;
         	throw err.str(); 
-        }		
+        }
 		if((i->children.begin()+1)->value.id() == formula_grammar::indexID)
-			ind = (int)eval_expression(i->children.begin()+1, attr_values);		//array index
+			ind = eval_expression(i->children.begin()+1, attr_values);		//array index
 		else
 		{
         	err <<  "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children2 is not an index ->" << string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) << ends;;
         	throw err.str(); 
-        }	
-		return eval_expression(i->children.begin(), attr_values ,ind);
+        }
+		return eval_expression(i->children.begin(), attr_values, (int)ind.value);
     }    
     else if (i->value.id() == formula_grammar::nameID)
     {
@@ -3135,8 +3404,14 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
 			ostringstream temp_attr_val;
 			temp_attr_val << it->name << "[" << ev_ind << "]=" <<it->value.at(ev_ind) << ";";
 			attr_values += temp_attr_val.str();
-			DEBUG_STREAM << "		node name -> " << temp_attr_val.str() << endl;
-			return it->value.at(ev_ind);		//throw  std::out_of_range		
+			formula_res_t res;
+			res.quality = it->quality;
+			res.ex_reason = it->ex_reason;
+			res.ex_desc = it->ex_desc;
+			res.ex_origin = it->ex_origin;
+			DEBUG_STREAM << "		node name -> " << temp_attr_val.str() << " quality=" << res.quality << endl;
+			res.value = it->value.at(ev_ind);		//throw  std::out_of_range
+			return 	res;
 		}
 		else
 		{
@@ -3153,7 +3428,9 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         }			
         string val_d(i->value.begin(), i->value.end());
      	DEBUG_STREAM << "		node index = " << val_d << endl;
-        return strtod(val_d.c_str(), 0);
+     	formula_res_t res;
+     	res.value = strtod(val_d.c_str(), 0);
+        return res;
     }   
     else if (i->value.id() == formula_grammar::logical_exprID)
     {
@@ -3187,28 +3464,46 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         	err <<  "in node bitwise_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
         	throw err.str(); 
         }	 		
-        double val_d1=eval_expression(i->children.begin(), attr_values),
-           	val_d2=eval_expression(i->children.begin()+1, attr_values);
+		formula_res_t res_1=eval_expression(i->children.begin(), attr_values),
+           	res_2=eval_expression(i->children.begin()+1, attr_values);
         long val_l1,val_l2;
             
     	string err2("ERROR: non-int value in bitwise operation!");
-    	val_l1 = (long)trunc(val_d1);		//transform to long
-    	val_l2 = (long)trunc(val_d2);		//transform to long
+    	val_l1 = (long)trunc(res_1.value);		//transform to long
+    	val_l2 = (long)trunc(res_2.value);		//transform to long
 
-	    if((val_l1 != val_d1) || (val_l2 != val_d2))	//if different, lost something with truncf
+	    if((val_l1 != res_1.value) || (val_l2 != res_2.value))	//if different, lost something with truncf
     		throw err2;
     		  
         if (*i->value.begin() == '&')
-        {          
-            return (double)(val_l1 & val_l2);
+        {
+        	formula_res_t res;
+        	res.value = (double)(val_l1 & val_l2);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
         }
         else if (*i->value.begin() == '|')
         {      
-            return (double)(val_l1 | val_l2);
+        	formula_res_t res;
+        	res.value = (double)(val_l1 | val_l2);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
         }  
         else if (*i->value.begin() == '^')
-        {         
-            return (double)(val_l1 ^ val_l2);
+        {
+        	formula_res_t res;
+        	res.value = (double)(val_l1 ^ val_l2);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
         }  
         else
         {
@@ -3224,24 +3519,36 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         	err <<  "in node shift_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
         	throw err.str(); 
         }			
-        double val_d1=eval_expression(i->children.begin(), attr_values),
-           	val_d2=eval_expression(i->children.begin()+1, attr_values);
+		formula_res_t res_1=eval_expression(i->children.begin(), attr_values),
+           	res_2=eval_expression(i->children.begin()+1, attr_values);
         long val_l1,val_l2;
             
     	string err2("ERROR: non-int value in bitwise operation!");
-    	val_l1 = (long)trunc(val_d1);		//transform to long
-    	val_l2 = (long)trunc(val_d2);		//transform to long
+    	val_l1 = (long)trunc(res_1.value);		//transform to long
+    	val_l2 = (long)trunc(res_2.value);		//transform to long
 
-	    if((val_l1 != val_d1) || (val_l2 != val_d2))	//if different, lost something with truncf
+	    if((val_l1 != res_1.value) || (val_l2 != res_2.value))	//if different, lost something with truncf
     		throw err2;
     		  
         if (string(i->value.begin(), i->value.end()) == string("<<"))
-        {          
-            return (double)(val_l1 << val_l2);
+        {
+        	formula_res_t res;
+        	res.value = (double)(val_l1 << val_l2);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
         }
         else if (string(i->value.begin(), i->value.end()) == string(">>"))
-        {      
-            return (double)(val_l1 >> val_l2);
+        {
+        	formula_res_t res;
+        	res.value = (double)(val_l1 >> val_l2);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
         }  
         else
         {
@@ -3314,8 +3621,11 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
 		{
         	err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
         	throw err.str(); 
-        }	
-		return fabs(eval_expression(i->children.begin(), attr_values));			//now handled only abs as function
+        }
+		formula_res_t res;
+		res = eval_expression(i->children.begin(), attr_values);
+		res.value = fabs(res.value);
+		return res;			//now handled only abs as function
     }  
     else
     {
@@ -3325,7 +3635,9 @@ double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind)
         	throw err.str(); 
         }	
     }
-    return 0;
+    formula_res_t res;
+    res.value = 0;
+    return res;
 }
 
 void Alarm::find_event_formula(tree_parse_info_t tree, vector<string> & ev)
diff --git a/src/Alarm.h b/src/Alarm.h
index dd9c4d7..681eb2d 100644
--- a/src/Alarm.h
+++ b/src/Alarm.h
@@ -183,6 +183,22 @@ public:
 	virtual void read_alarm(Tango::Attribute &attr);
 	virtual bool is_alarm_allowed(Tango::AttReqType type);
 
+//	Dynamic attribute methods
+public:
+
+	/**
+	 *	Attribute AlarmState related methods
+	 *	Description: 
+	 *
+	 *	Data type:	Tango::DevBoolean
+	 *	Attr type:	Scalar
+	 */
+	virtual void read_AlarmState(Tango::Attribute &attr);
+	virtual bool is_AlarmState_allowed(Tango::AttReqType type);
+	void add_AlarmState_dynamic_attribute(string attname);
+	void remove_AlarmState_dynamic_attribute(string attname);
+	Tango::DevBoolean *get_AlarmState_data_ptr(string &name);
+	map<string,Tango::DevBoolean>	   AlarmState_data;
 
 	//--------------------------------------------------------
 	/**
@@ -303,10 +319,10 @@ private:
 	
 	void load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn);
 
-	double eval_formula(tree_parse_info_t tree, string &attr_values);
+	formula_res_t eval_formula(tree_parse_info_t tree, string &attr_values);
 	void find_event_formula(tree_parse_info_t tree, vector<string> &);
 	
-	double eval_expression(iter_t const& i, string &attr_values, int ev_ind=0);			//recursive tree node evaluation	
+	formula_res_t eval_expression(iter_t const& i, string &attr_values, int ev_ind=0);			//recursive tree node evaluation
 	void eval_node_event(iter_t const& i, vector<string> & ev);		//recursive tree node evaluation		
 
 	void prepare_alarm_attr();	//for read attribute alarm and push_change_event
diff --git a/src/Alarm.xmi b/src/Alarm.xmi
index e7e5428..1623e05 100644
--- a/src/Alarm.xmi
+++ b/src/Alarm.xmi
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="ASCII"?>
 <pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://www.esrf.fr/tango/pogo/PogoDsl">
   <classes name="Alarm" pogoRevision="9.1">
-    <description description="Elettra alarm device server" title="Elettra alarm device server" sourcePath="/home/graziano/workspace/git/alarm/src" language="Cpp" filestogenerate="XMI   file,Code files,Protected Regions" license="GPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false">
+    <description description="Elettra alarm device server" title="Elettra alarm device server" sourcePath="/home/graziano/workspace/git/alarm/src" language="Cpp" filestogenerate="XMI   file,Code files,Protected Regions,Eclipse Project" license="GPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false">
       <inheritances classname="Device_4Impl" sourcePath=""/>
       <identification contact="at elettra.eu - graziano.scalamera" author="graziano.scalamera" emailDomain="elettra.eu" classFamily="SoftwareSystem" siteSpecific="" platform="Unix Like" bus="Not Applicable" manufacturer="" reference=""/>
     </description>
@@ -129,6 +129,14 @@
       <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
       <properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
     </attributes>
+    <dynamicAttributes name="AlarmState" attType="Scalar" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="" maxY="" allocReadMember="true" isDynamic="true">
+      <dataType xsi:type="pogoDsl:BooleanType"/>
+      <changeEvent fire="true" libCheckCriteria="true"/>
+      <archiveEvent fire="true" libCheckCriteria="true"/>
+      <dataReadyEvent fire="false" libCheckCriteria="true"/>
+      <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
+      <properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
+    </dynamicAttributes>
     <preferences docHome="./doc_html" makefileHome="/usr/local/tango-8.1.2.c/share/pogo/preferences"/>
   </classes>
 </pogoDsl:PogoSystem>
diff --git a/src/AlarmClass.h b/src/AlarmClass.h
index df66071..e215eb1 100644
--- a/src/AlarmClass.h
+++ b/src/AlarmClass.h
@@ -72,6 +72,23 @@ public:
 };
 
 
+//=========================================
+//	Define classes for dynamic attributes
+//=========================================
+//	Attribute AlarmState class definition
+class AlarmStateAttrib: public Tango::Attr
+{
+public:
+	AlarmStateAttrib(const string &att_name):Attr(att_name.c_str(), 
+			Tango::DEV_BOOLEAN, Tango::READ) {};
+	~AlarmStateAttrib() {};
+	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
+		{(static_cast<Alarm *>(dev))->read_AlarmState(att);}
+	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
+		{return (static_cast<Alarm *>(dev))->is_AlarmState_allowed(ty);}
+};
+
+
 //=========================================
 //	Define classes for commands
 //=========================================
diff --git a/src/AlarmDynAttrUtils.cpp b/src/AlarmDynAttrUtils.cpp
new file mode 100644
index 0000000..122abfe
--- /dev/null
+++ b/src/AlarmDynAttrUtils.cpp
@@ -0,0 +1,158 @@
+/*----- PROTECTED REGION ID(Alarm::DynAttrUtils.cpp) ENABLED START -----*/
+static const char *RcsId = "$Id:  $";
+//=============================================================================
+//
+// file :        AlarmDynAttrUtils.cpp
+//
+// description : Dynamic attributes utilities file for the Alarm class
+//
+// project :     Elettra alarm device server
+//
+// 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/>.
+// 
+// $Author:  $
+//
+// $Revision:  $
+// $Date:  $
+//
+// $HeadURL:  $
+//
+//=============================================================================
+//                This file is generated by POGO
+//        (Program Obviously used to Generate tango Object)
+//=============================================================================
+
+
+#include <Alarm.h>
+#include <AlarmClass.h>
+
+/*----- PROTECTED REGION END -----*/	//	Alarm::DynAttrUtils.cpp
+
+//================================================================
+//  Attributes managed is:
+//================================================================
+//  AlarmState  |  Tango::DevBoolean	Scalar
+//================================================================
+
+//	For compatibility reason, this file (AlarmDynAttrUtils)
+//	manage also the dynamic command utilities.
+//================================================================
+//  The following table gives the correspondence
+//  between command and method names.
+//
+//  Command name  |  Method name
+//================================================================
+//================================================================
+
+namespace Alarm_ns
+{
+//=============================================================
+//	Add/Remove dynamic attribute methods
+//=============================================================
+
+//--------------------------------------------------------
+/**
+ *	Add a AlarmState dynamic attribute.
+ *
+ *  parameter attname: attribute name to be cretated and added.
+ */
+//--------------------------------------------------------
+void Alarm::add_AlarmState_dynamic_attribute(string attname)
+{
+	//	Attribute : AlarmState
+	AlarmStateAttrib	*alarmstate = new AlarmStateAttrib(attname);
+	Tango::UserDefaultAttrProp	alarmstate_prop;
+	//	description	not set for AlarmState
+	//	label	not set for AlarmState
+	//	unit	not set for AlarmState
+	//	standard_unit	not set for AlarmState
+	//	display_unit	not set for AlarmState
+	//	format	not set for AlarmState
+	//	max_value	not set for AlarmState
+	//	min_value	not set for AlarmState
+	//	max_alarm	not set for AlarmState
+	//	min_alarm	not set for AlarmState
+	//	max_warning	not set for AlarmState
+	//	min_warning	not set for AlarmState
+	//	delta_t	not set for AlarmState
+	//	delta_val	not set for AlarmState
+	
+	/*----- PROTECTED REGION ID(Alarm::att_AlarmState_dynamic_attribute) ENABLED START -----*/
+	DEBUG_STREAM << __func__<<": entering name="<<attname;
+	
+	/*----- PROTECTED REGION END -----*/	//	Alarm::att_AlarmState_dynamic_attribute
+	alarmstate->set_default_properties(alarmstate_prop);
+	//	Not Polled
+	alarmstate->set_disp_level(Tango::OPERATOR);
+	//	Not Memorized
+	alarmstate->set_change_event(true, true);
+	alarmstate->set_archive_event(true, true);
+	AlarmState_data.insert(make_pair(attname, false));
+	add_attribute(alarmstate);
+}
+//--------------------------------------------------------
+/**
+ *	remove a AlarmState dynamic attribute.
+ *
+ *  parameter attname: attribute name to be removed.
+ */
+//--------------------------------------------------------
+void Alarm::remove_AlarmState_dynamic_attribute(string attname)
+{
+	remove_attribute(attname, true);
+	map<string,Tango::DevBoolean>::iterator ite;
+    if ((ite=AlarmState_data.find(attname))!=AlarmState_data.end())
+    {
+    	/*----- PROTECTED REGION ID(Alarm::remove_AlarmState_dynamic_attribute) ENABLED START -----*/
+    	DEBUG_STREAM << __func__<<": entering name="<<attname;
+    	/*----- PROTECTED REGION END -----*/	//	Alarm::remove_AlarmState_dynamic_attribute
+		AlarmState_data.erase(ite);
+	}
+}
+
+
+//============================================================
+//	Tool methods to get pointer on attribute data buffer 
+//============================================================
+//--------------------------------------------------------
+/**
+ *	Return a pointer on AlarmState data.
+ *
+ *  parameter attname: the specified attribute name.
+ */
+//--------------------------------------------------------
+Tango::DevBoolean *Alarm::get_AlarmState_data_ptr(string &name)
+{
+	map<string,Tango::DevBoolean>::iterator ite;
+    if ((ite=AlarmState_data.find(name))==AlarmState_data.end())
+    {
+		TangoSys_OMemStream	tms;
+		tms << "Dynamic attribute " << name << " has not been created";
+		Tango::Except::throw_exception(
+					(const char *)"ATTRIBUTE_NOT_FOUND",
+					tms.str().c_str(),
+					(const char *)"Alarm::get_AlarmState_data_ptr()");
+    }
+	return  &(ite->second);
+}
+
+
+//=============================================================
+//	Add/Remove dynamic command methods
+//=============================================================
+
+
+} //	namespace
diff --git a/src/AlarmStateMachine.cpp b/src/AlarmStateMachine.cpp
index 5f703cc..558ee6f 100644
--- a/src/AlarmStateMachine.cpp
+++ b/src/AlarmStateMachine.cpp
@@ -66,6 +66,22 @@ bool Alarm::is_alarm_allowed(TANGO_UNUSED(Tango::AttReqType type))
 	return true;
 }
 
+//--------------------------------------------------------
+/**
+ *	Method      : Alarm::is_AlarmState_allowed()
+ *	Description : Execution allowed for AlarmState attribute
+ */
+//--------------------------------------------------------
+bool Alarm::is_AlarmState_allowed(TANGO_UNUSED(Tango::AttReqType type))
+{
+
+	//	Not any excluded states for AlarmState attribute in read access.
+	/*----- PROTECTED REGION ID(Alarm::AlarmStateStateAllowed_READ) ENABLED START -----*/
+	
+	/*----- PROTECTED REGION END -----*/	//	Alarm::AlarmStateStateAllowed_READ
+	return true;
+}
+
 
 //=================================================
 //		Commands Allowed Methods
diff --git a/src/alarm_table.cpp b/src/alarm_table.cpp
index fa6b4ce..d017c15 100644
--- a/src/alarm_table.cpp
+++ b/src/alarm_table.cpp
@@ -341,7 +341,7 @@ void alarm_table::stored(vector<alarm_t>& a)
 #endif
 }
 
-bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, int res, string &attr_values, string grp, string msg, string formula)
+bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_t res, string &attr_values, string grp, string msg, string formula)
 {
 	bool ret_changed=false;
 	//Tango::TimeVal now = gettime();
@@ -366,34 +366,37 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, int res, str
 			else
 				found->second.silenced = 0;
 		}
-
+		found->second.quality = res.quality;
+		found->second.ex_reason = res.ex_reason;
+		found->second.ex_desc = res.ex_desc;
+		found->second.ex_origin = res.ex_origin;
 		bool status_time_threshold;
 		if(found->second.time_threshold > 0)		//if enabled time threshold
-			status_time_threshold = (res) && (found->second.counter >= 1) && ((ts.tv_sec - found->second.time_threshold) > found->second.ts_time_threshold.tv_sec);	//formula gives true and time threshold is passed
+			status_time_threshold = ((int)res.value) && (found->second.counter >= 1) && ((ts.tv_sec - found->second.time_threshold) > found->second.ts_time_threshold.tv_sec);	//formula gives true and time threshold is passed
 		else
-			status_time_threshold = res;	
+			status_time_threshold = (int)res.value;
 		//if status changed:
 		// - from S_NORMAL to S_ALARM considering also time threshold
 		//or
 		// - from S_ALARM to S_NORMAL		
-		if((status_time_threshold && (found->second.stat == S_NORMAL)) || (!res && (found->second.stat == S_ALARM)))
+		if((status_time_threshold && (found->second.stat == S_NORMAL)) || (!(int)res.value && (found->second.stat == S_ALARM)))
 		{
 			ret_changed=true;
 			a.type_log = TYPE_LOG_STATUS;
 			a.name = alm_name;
 			a.time_s = ts.tv_sec;		
 			a.time_us = ts.tv_usec;
-			a.status = res ? S_ALARM : S_NORMAL;
+			a.status = (int)res.value ? S_ALARM : S_NORMAL;
 			//a.level = found->second.lev;
-			if(res)
+			if((int)res.value)
 				found->second.ack = NOT_ACK;	//if changing from NORMAL to ALARM -> NACK
 			a.ack = found->second.ack;
 			a.values = attr_values;
 			//a.grp = found->second.grp2str();
-			//a.msg = res ? found->second.msg : "";
+			//a.msg = (int)res.value ? found->second.msg : "";
 			logloop->log_alarm_db(a);
 			found->second.ts = ts;	/* store event timestamp into alarm timestamp */ //here update ts only if status changed
-			if(res)
+			if((int)res.value)
 			{
 				found->second.is_new = 1;		//here set this alarm as new, read attribute set it to 0	//12-06-08: StopNew command set it to 0
 				if(found->second.dp_a && ((ts.tv_sec - startup_complete.tv_sec) > 10))		//action from S_NORMAL to S_ALARM
@@ -491,7 +494,7 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, int res, str
 			found->second.stat = S_ALARM;
 			//found->second.ack = NOT_ACK;
 		}
-		if(res) {
+		if((int)res.value) {
 			found->second.counter++;
 		} else {
 			found->second.stat = S_NORMAL;
@@ -611,6 +614,30 @@ bool alarm_table::timer_update()
 				arg.arg_b = i->second.send_arg_a;	
 				cmdloop->list.push_back(arg);
 			}
+			*(i->second.attr_value) = true;
+			try
+			{
+				if(i->second.ex_reason.length() == 0)
+				{
+					timeval now;
+					gettimeofday(&now, NULL);
+					mydev->push_change_event(i->second.attr_name,(Tango::DevBoolean *)i->second.attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
+					mydev->push_archive_event(i->second.attr_name,(Tango::DevBoolean *)i->second.attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
+				}
+				else
+				{
+					Tango::DevErrorList errors(1);
+					errors.length(1);
+					errors[0].desc = CORBA::string_dup(i->second.ex_desc.c_str());
+					errors[0].severity = Tango::ERR;
+					errors[0].reason = CORBA::string_dup(i->second.ex_reason.c_str());
+					errors[0].origin = CORBA::string_dup(i->second.ex_origin.c_str());
+					Tango::DevFailed except(errors);
+					mydev->push_change_event(i->second.attr_name, &except);
+					mydev->push_archive_event(i->second.attr_name, &except);
+				}
+			} catch(Tango::DevFailed &e)
+			{}
 		}
 		if (status_time_threshold) {
 			i->second.stat = S_ALARM;
diff --git a/src/alarm_table.h b/src/alarm_table.h
index ee82694..818a7e4 100644
--- a/src/alarm_table.h
+++ b/src/alarm_table.h
@@ -102,6 +102,166 @@ class alarm_table;
 class log_thread;
 class cmd_thread;
 
+
+struct formula_res_t
+{
+	formula_res_t(){value=0;quality=Tango::ATTR_VALID;ex_reason=string("");ex_desc=string("");ex_origin=string("");}
+	double value;
+	int quality;
+	Tango::DevErrorList 	errors;	//TODO: error stack
+	string ex_reason;
+	string ex_desc;
+	string ex_origin;
+	int combine_quality(int quality1, int quality2)
+	{
+		int res;
+		if(quality1 == Tango::ATTR_INVALID ||  quality2 == Tango::ATTR_INVALID)
+			res = Tango::ATTR_INVALID;
+		else if(quality1 == Tango::ATTR_ALARM ||  quality2 == Tango::ATTR_ALARM)
+			res = Tango::ATTR_ALARM;
+		else if(quality1 == Tango::ATTR_WARNING ||  quality2 == Tango::ATTR_WARNING)
+			res = Tango::ATTR_WARNING;
+		else if(quality1 == Tango::ATTR_CHANGING ||  quality2 == Tango::ATTR_CHANGING)
+			res = Tango::ATTR_CHANGING;
+		else
+			res = (quality1 > quality2) ? quality1 : quality2;	//TODO: decide priority in enum AttrQuality { ATTR_VALID, ATTR_INVALID, ATTR_ALARM, ATTR_CHANGING, ATTR_WARNING /*, __max_AttrQuality=0xffffffff */ };
+		return res;
+	}
+	string combine_exception(string ex_1, string ex_2)
+	{
+		if(ex_1.length() > 0)
+			return ex_1;
+		else
+			return ex_2;
+	}
+	formula_res_t operator==(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value == e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator!=(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value != e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator<=(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value <= e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator>=(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value >= e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator<(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value < e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator>(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value > e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator||(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value || e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator&&(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value && e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator+(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value + e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator-(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value - e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator*(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value * e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	formula_res_t operator/(const formula_res_t& e)
+		{
+			formula_res_t res;
+			res.value = value / e.value;
+			res.quality = combine_quality(quality, e.quality);
+			res.ex_reason = combine_exception(ex_reason, e.ex_reason);
+			res.ex_desc = combine_exception(ex_desc, e.ex_desc);
+			res.ex_origin = combine_exception(ex_origin, e.ex_origin);
+			return res;
+		}
+	/*string operator<<(const formula_res_t& e)
+		{
+			stringstream res;
+			res << "value="<<e.value<<" quality="<<e.quality<<" EX reason="<<e.ex_reason<<" desc="<<e.ex_desc<<" origin="<<e.ex_origin;
+			return res.str();
+		}*/
+};
+
 /*
  * store the alarm-name/alarm-formula pair
  */
@@ -109,6 +269,12 @@ class alarm_t {
 	public:
 		string name,
 					 formula;
+		string attr_name;
+		Tango::DevBoolean *attr_value;
+		int quality;
+		string ex_reason;
+		string ex_desc;
+		string ex_origin;
 		Tango::TimeVal ts;
 		string stat,
 					 ack;
@@ -171,6 +337,7 @@ class alarm_table {
 	public:
 		alarm_table() {}
 		~alarm_table() {}
+		void set_dev(Tango::DeviceImpl* devImpl) {mydev=devImpl;}
 
 		//void init(vector<string>& avs);
 		//void init(vector<string>& avs, vector<string> &evn, map< string,vector<string> > &alarm_event);		
@@ -179,7 +346,7 @@ class alarm_table {
 		unsigned int size(void);
 		alarm_container_t& get(void);
 		void stored(vector<alarm_t>& a);
-		bool update(const string& alm_name, Tango::TimeVal ts, int res, string &attr_values, string grp, string msg, string formula);
+		bool update(const string& alm_name, Tango::TimeVal ts, formula_res_t res, string &attr_values, string grp, string msg, string formula);
 		bool timer_update();
 		void erase(alarm_container_t::iterator i);
 		bool exist(string& s);
@@ -203,7 +370,7 @@ class alarm_table {
 	
 	protected:
 	private:
-		
+		Tango::DeviceImpl* mydev;
 		log_thread *logloop;
 		cmd_thread *cmdloop;		
 };
diff --git a/src/event_table.cpp b/src/event_table.cpp
index 846e5cb..da0c2cc 100644
--- a/src/event_table.cpp
+++ b/src/event_table.cpp
@@ -377,10 +377,15 @@ void EventCallBack::push_event(Tango::EventData* ev)
 {
 	string temp_name;	
 	bei_t e;
-	
+	e.ex_reason = string("");
+	e.ex_desc = string("");
+	e.ex_origin = string("");
 	try {
+		//e.errors = ev->errors;
+		e.quality = Tango::ATTR_VALID;
+		//cout << "EVENT="<<ev->attr_name<<" quality="<<e.quality<<endl;
 		if (!ev->err) {
-			
+			e.quality = (int)ev->attr_value->get_quality();
 #if 0//TANGO_VER >= 711
  			string ev_name_str(ev->attr_name);
  			string::size_type pos = ev_name_str.find("tango://");
diff --git a/src/event_table.h b/src/event_table.h
index 395c9ec..8e2b5cb 100644
--- a/src/event_table.h
+++ b/src/event_table.h
@@ -45,6 +45,11 @@ class event {
 					 device,				/* device name */
 					 attribute;			/* attribute name */
 		value_t value;				/* event value */
+		int quality;
+		//Tango::DevErrorList 	errors;
+		string ex_reason;
+		string ex_desc;
+		string ex_origin;
 		Tango::TimeVal ts;		/* event timestamp */
 		int type,							/* attribute data type */
 				counter,					/* molteplicita' */
@@ -76,6 +81,11 @@ class event {
 typedef struct basic_event_info_s {
 	string ev_name;
 	value_t value;
+	int quality;
+	//Tango::DevErrorList 	errors;
+	string ex_reason;
+	string ex_desc;
+	string ex_origin;
 	int type;
 	Tango::TimeVal ts;
 	string msg;
-- 
GitLab