From c541de6aae977c0b6175b468787b2debf26276be Mon Sep 17 00:00:00 2001
From: gscalamera <graziano.scalamera@elettra.eu>
Date: Thu, 16 Mar 2017 17:07:00 +0100
Subject: [PATCH] Removed time_threshold and added on_delay and off_delay

---
 src/Alarm.cpp       |  40 ++++---
 src/alarm_grammar.h |  25 +++--
 src/alarm_table.cpp | 259 ++++++++++++++++++++++++++++++--------------
 src/alarm_table.h   |  13 ++-
 4 files changed, 229 insertions(+), 108 deletions(-)

diff --git a/src/Alarm.cpp b/src/Alarm.cpp
index 6823e91..5d4a9ac 100644
--- a/src/Alarm.cpp
+++ b/src/Alarm.cpp
@@ -1476,10 +1476,10 @@ void Alarm::load(Tango::DevString argin)
 #endif
 	string cmd_name_full = alm.cmd_name_a + string(";") + alm.cmd_name_n;
 	alarms.log_alarm_db(TYPE_LOG_DESC_ADD, ts, alm.name, "", "", 		//add new alarm on log before subscribe event
-			alm.formula, alm.time_threshold, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time);	//but if it fails remove it from table
+			alm.formula, alm.on_delay, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time);	//but if it fails remove it from table
 
 	alarms.save_alarm_conf_db(alm.attr_name, ts, alm.name, "", "", 		//add new alarm on log before subscribe event
-			alm.formula, alm.time_threshold, alm.grp2str(), alm.lev, alm.msg, alm.cmd_name_a, alm.cmd_name_n, alm.silent_time);	//but if it fails remove it from table
+			alm.formula, alm.on_delay, alm.off_delay, alm.grp2str(), alm.lev, alm.msg, alm.cmd_name_a, alm.cmd_name_n, alm.silent_time);	//but if it fails remove it from table
 
 
 
@@ -1762,7 +1762,7 @@ Tango::DevVarStringArray *Alarm::configured(Tango::DevString argin)
 		{
 			ostringstream os;
 			os.clear();
-			os << ai->second.ts.tv_sec << "\t" << ai->second.name << "\t" /*TODO<< KEY(FORMULA_KEY)*/ << ai->second.formula << "\t" << KEY(DELAY_KEY) << ai->second.time_threshold <<
+			os << ai->second.ts.tv_sec << "\t" << ai->second.name << "\t" /*TODO<< KEY(FORMULA_KEY)*/ << ai->second.formula << "\t" << KEY(ONDELAY_KEY) << ai->second.on_delay << "\t" << KEY(OFFDELAY_KEY) << ai->second.off_delay <<
 			"\t" << KEY(LEVEL_KEY) << ai->second.lev << "\t" << KEY(SILENT_TIME_KEY) << ai->second.silent_time << "\t" << KEY(GROUP_KEY) << ai->second.grp2str() << "\t" << KEY(MESSAGE_KEY) << ai->second.msg << "\t" <<
 			KEY(ON_COMMAND_KEY) << ai->second.cmd_name_a << "\t" << KEY(OFF_COMMAND_KEY) << ai->second.cmd_name_n << ends;
 			alarm_filtered.push_back(os.str());
@@ -1996,7 +1996,8 @@ void Alarm::modify(Tango::DevString argin)
 	alm.lev.clear();
 	alm.grp=0;
 	alm.to_be_evaluated = false;
-	alm.time_threshold = 0;
+	alm.on_delay = 0;
+	alm.off_delay = 0;
 	alm.silent_time = -1;
 	alm.silenced = -1;
 	alm.cmd_name_a.clear();
@@ -2090,7 +2091,8 @@ void Alarm::modify(Tango::DevString argin)
 				i->second.lev = alm.lev;
 				i->second.grp = alm.grp;
 				//i->second.to_be_evaluated = alm.to_be_evaluated;
-				i->second.time_threshold = alm.time_threshold;
+				i->second.on_delay = alm.on_delay;
+				i->second.off_delay = alm.off_delay;
 				i->second.silent_time = alm.silent_time;
 				i->second.silenced = alm.silenced;
 				i->second.cmd_name_a = alm.cmd_name_a;
@@ -2119,7 +2121,7 @@ void Alarm::modify(Tango::DevString argin)
 
 
 			alarms.log_alarm_db(TYPE_LOG_DESC_UPDATE, ts, alm.name, "", "",
-					alm.formula, alm.time_threshold, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time);
+					alm.formula, alm.on_delay, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time);
 
 			//delete proxy for actions
 			if(i->second.dp_a)
@@ -2285,7 +2287,8 @@ void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
 	alm.lev.clear();
 	alm.grp=0;
 	alm.to_be_evaluated = false;
-	alm.time_threshold = 0;
+	alm.on_delay = 0;
+	alm.off_delay = 0;
 	alm.silent_time = -1;
 	alm.silenced = -1;
 	alm.cmd_name_a.clear();
@@ -2376,9 +2379,10 @@ 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 << "               attr_name      = '" << alm.attr_name << "'" << endl;
 	DEBUG_STREAM << "               formula        = '" << alm.formula << "'" << endl;
-	DEBUG_STREAM << "               time_threshold = '" << alm.time_threshold << "'" << endl;	
+	DEBUG_STREAM << "               on_delay       = '" << alm.on_delay << "'" << endl;
+	DEBUG_STREAM << "               off_delay      = '" << alm.off_delay << "'" << endl;
 	DEBUG_STREAM << "               msg            = '" << alm.msg << "'" << endl;
 	DEBUG_STREAM << "               grp            = '" << showbase << hex << alm.grp << "'=" << alm.grp2str() << endl;
 	DEBUG_STREAM << "               silent_time    = '" << alm.silent_time << "'" << endl;
@@ -3196,8 +3200,8 @@ void Alarm::set_internal_alarm(string name, Tango::TimeVal t, string msg, unsign
 			if(it->msg.find(name) != string::npos)		
 			{
 				existing=true;
-				if(it->counter < count)
-					it->counter = count;
+				if(it->on_counter < count)
+					it->on_counter = count;
 				break;
 			}
 		}			
@@ -3220,7 +3224,7 @@ void Alarm::set_internal_alarm(string name, Tango::TimeVal t, string msg, unsign
 		}	
 		else
 			it->stat += "*2";*/
-		it->counter++;
+		it->on_counter++;
 		it->msg = msg;		//update with the last message
 	}
 	else
@@ -3233,7 +3237,7 @@ void Alarm::set_internal_alarm(string name, Tango::TimeVal t, string msg, unsign
 			stat << S_ALARM;
 		else
 			stat << S_ALARM << "*" << count;*/
-		alm.counter = count;
+		alm.on_counter = count;
 		//alm.stat = stat.str();
 		alm.stat = S_ALARM;
 		alm.ack = NOT_ACK;
@@ -3914,7 +3918,8 @@ void Alarm::prepare_alarm_attr()
 				aid->lev = ai->second.lev;
 				aid->is_new = ai->second.is_new;			//copy is_new state
 				//ai->second.is_new = 0;						//and set state as not more new //12-06-08: StopNew command set it to 0
-				aid->counter = ai->second.counter;
+				aid->on_counter = ai->second.on_counter;
+				aid->off_counter = ai->second.off_counter;
 				aid->ack = ai->second.ack;					//if already acknowledged but has arrived new alarm ack is reset
 				aid->silenced = ai->second.silenced;		//update silenced from alarm table (maybe not necessary)
 				aid->silent_time = ai->second.silent_time;	//if already alarmed and not saved correctly in properties needed to update
@@ -3949,7 +3954,8 @@ void Alarm::prepare_alarm_attr()
 				aid->msg =ai->second.msg;
 				aid->grp = ai->second.grp;
 				aid->lev = ai->second.lev;
-				aid->counter = ai->second.counter;
+				aid->on_counter = ai->second.on_counter;
+				aid->off_counter = ai->second.off_counter;
 				aid->ack = ai->second.ack;					//if already acknowledged but has arrived new alarm ack is reset
 				aid->is_new = ai->second.is_new;			//copy is_new state
 				aid->silenced = ai->second.silenced;		//update silenced from alarm table (maybe not necessary)
@@ -4010,7 +4016,7 @@ void Alarm::prepare_alarm_attr()
 			is_new = (aid->is_new && aid->silenced <= 0) ? "NEW" : " ";
 			os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \
 			 	 << aid->name << "\t" << aid->stat << "\t" << aid->ack \
-				 << "\t" << aid->counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new << ends;
+				 << "\t" << aid->on_counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new << ends;
 			tmp_alarm_table.push_back(os.str());
 		}
 	}
@@ -4037,7 +4043,7 @@ void Alarm::prepare_alarm_attr()
 			os.clear();
 			os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \
 			 	 << aid->name << "\t" << aid->stat << "\t" << aid->ack \
-				 << "\t" << aid->counter << "\t" << aid->lev << "\t"<< -1/*silenced*/ <<"\t" << aid->grp2str() << "\t" << aid->msg << "\t "<< ends; //TODO: silenced for internal errors?
+				 << "\t" << aid->on_counter << "\t" << aid->lev << "\t"<< -1/*silenced*/ <<"\t" << aid->grp2str() << "\t" << aid->msg << "\t "<< ends; //TODO: silenced for internal errors?
 			tmp_alarm_table.push_back(os.str());
 		}
 	}
diff --git a/src/alarm_grammar.h b/src/alarm_grammar.h
index fd9806c..32810b1 100644
--- a/src/alarm_grammar.h
+++ b/src/alarm_grammar.h
@@ -69,7 +69,8 @@
 
 #define NAME_KEY			"name"
 #define FORMULA_KEY			"formula"
-#define DELAY_KEY			"time_threshold"
+#define ONDELAY_KEY			"on_delay"
+#define OFFDELAY_KEY		"off_delay"
 #define LEVEL_KEY			"level"
 #define SILENT_TIME_KEY		"silent_time"
 #define GROUP_KEY			"group"
@@ -194,7 +195,8 @@ struct alarm_parse : public grammar<alarm_parse>
 			;
 
             option
-				=	discard_node_d[time_threshold] |
+				=	discard_node_d[on_delay] |
+					discard_node_d[off_delay] |
 					discard_node_d[level] |
 					discard_node_d[silent_time] |
 					discard_node_d[group] |
@@ -252,12 +254,21 @@ struct alarm_parse : public grammar<alarm_parse>
 							]					
 					>> '"'
 				;
-			//---------------------------TIME THRESHOLD----------------------------------	
-			time_threshold 
-				=	discard_node_d[str_p(KEY(DELAY_KEY))] >>
+			//---------------------------ON DELAY----------------------------------------
+			on_delay
+				=	discard_node_d[str_p(KEY(ONDELAY_KEY))] >>
 					(uint_p
 					[
-						assign_a(self.m_alarm.time_threshold)
+						assign_a(self.m_alarm.on_delay)
+					]
+					| epsilon_p)
+				;
+			//---------------------------OFF DELAY---------------------------------------
+			off_delay
+				=	discard_node_d[str_p(KEY(OFFDELAY_KEY))] >>
+					(uint_p
+					[
+						assign_a(self.m_alarm.off_delay)
 					]
 					| epsilon_p)
 				;
@@ -300,7 +311,7 @@ struct alarm_parse : public grammar<alarm_parse>
 		rule_t expression, event, option;
         rule<typename lexeme_scanner<ScannerT>::type> symbol;					//needed to use lexeme_d in rule name
         rule<typename lexeme_scanner<ScannerT>::type> symbol_attr_name;		//needed to use lexeme_d in rule name
-        rule_t name, name_alm, val, token, oper, msg, group, level, time_threshold, silent_time, on_command, off_command;
+        rule_t name, name_alm, val, token, oper, msg, group, level, on_delay, off_delay, silent_time, on_command, off_command;
 		formula_grammar formula;
 		
 		rule_t const&					
diff --git a/src/alarm_table.cpp b/src/alarm_table.cpp
index 5798630..dd8ddf5 100644
--- a/src/alarm_table.cpp
+++ b/src/alarm_table.cpp
@@ -23,16 +23,29 @@
 
 static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $";
 
+//TODO: duplicated from alarm.h
+enum _AlarmStateEnum {
+	_NORM,
+	_UNACK,
+	_ACKED,
+	_RTNUN,
+	_SHLVD,
+	_DSUPR,
+	_OOSRV,
+} ;
+
 /*
  * alarm_t class methods
  */
 alarm_t::alarm_t()
 {
 	grp=0;
-	counter=0;
+	on_counter=0;
+	off_counter=0;
 	stat = S_NORMAL;
 	ack = ACK;
-	time_threshold = 0;
+	on_delay = 0;
+	off_delay = 0;
 	silent_time = -1;
 	cmd_name_a=string("");
 	cmd_name_n=string("");
@@ -55,7 +68,7 @@ void alarm_t::str2alm(const string &s)
 	istringstream is(s);
 	ostringstream temp_msg;
 	string temp_grp;
-	is >> ts.tv_sec >> ts.tv_usec >> name >> stat >> ack >> counter >> lev >> silent_time >> temp_grp >> msg;		//stop at first white space in msg
+	is >> ts.tv_sec >> ts.tv_usec >> name >> stat >> ack >> on_counter >> lev >> silent_time >> temp_grp >> msg;		//stop at first white space in msg
 	temp_msg << is.rdbuf();		//read all remaining characters as msg
 	msg += temp_msg.str();
 	str2grp(temp_grp);
@@ -66,7 +79,7 @@ string alarm_t::alm2str(void)
 	ostringstream os;
 	os.clear();
 	os << ts.tv_sec << "\t" << ts.tv_usec << "\t" << name << "\t" \
-		 << stat << "\t" << ack << "\t" << counter << "\t" << lev << "\t" << silent_time << "\t" << grp2str() << "\t" << msg << ends;
+		 << stat << "\t" << ack << "\t" << on_counter << "\t" << lev << "\t" << silent_time << "\t" << grp2str() << "\t" << msg << ends;
 	return(os.str());
 }
 
@@ -367,16 +380,22 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 		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 = ((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
+		bool status_on_delay;
+		if(found->second.on_delay > 0)		//if enabled on delay
+			status_on_delay = ((int)(res.value)) && (found->second.on_counter >= 1) && ((ts.tv_sec - found->second.on_delay) > found->second.ts_on_delay.tv_sec);	//formula gives true and on delay has passed
+		else
+			status_on_delay = (int)(res.value);
+		bool status_off_delay;
+		if(found->second.off_delay > 0)		//if enabled off delay
+			status_off_delay = (!(int)(res.value)) && (found->second.off_counter >= 1) && ((ts.tv_sec - found->second.off_delay) > found->second.ts_off_delay.tv_sec);	//formula gives false and off delay has passed
 		else
-			status_time_threshold = (int)(res.value);
+			status_off_delay = !(int)(res.value);
+
 		//if status changed:
-		// - from S_NORMAL to S_ALARM considering also time threshold
+		// - from S_NORMAL to S_ALARM considering also on delay
 		//or
-		// - from S_ALARM to S_NORMAL		
-		if((status_time_threshold && (found->second.stat == S_NORMAL)) || (!(int)(res.value) && (found->second.stat == S_ALARM)))
+		// - from S_ALARM to S_NORMAL considering also off delay
+		if((status_on_delay && (found->second.stat == S_NORMAL)) || (status_off_delay && (found->second.stat == S_ALARM)))
 		{
 			ret_changed=true;
 			a.type_log = TYPE_LOG_STATUS;
@@ -487,20 +506,28 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 				}
 			}
 		}
-		if (status_time_threshold) {
+		if (status_on_delay) {
 			found->second.stat = S_ALARM;
 			//found->second.ack = NOT_ACK;
 		}
+		else if (status_off_delay) {
+			found->second.stat = S_NORMAL;
+		}
+
 		if((int)(res.value)) {
-			found->second.counter++;
+			found->second.on_counter++;
+			found->second.off_counter = 0;
 		} else {
-			found->second.stat = S_NORMAL;
-			found->second.counter = 0;
+			found->second.on_counter = 0;
+			found->second.off_counter++;
 		}
-		if(found->second.counter == 1)
-			found->second.ts_time_threshold = gettime();		//first occurrance of this alarm, now begin to wait for time threshold
-		if(found->second.counter >= 1)
-			found->second.attr_values_time_threshold = attr_values;		//save last attr_values to be used in timer_update if this alarm pass over time threshold
+
+		found->second.attr_values_delay = attr_values;		//save last attr_values to be used in timer_update if this alarm pass over on or off delay
+
+		if(found->second.on_counter == 1)
+			found->second.ts_on_delay = gettime();		//first occurrance of this alarm, now begin to wait for on delay
+		if(found->second.off_counter == 1)
+			found->second.ts_off_delay = gettime();		//first occurrance of back to normal, now begin to wait for off delay
 
 		//found->second.ts = ts;	/* store event timestamp into alarm timestamp */ //here update ts everytime
 	} else {
@@ -533,14 +560,20 @@ bool alarm_table::timer_update()
 #endif
 	for(alarm_container_t::iterator i = v_alarm.begin(); i != v_alarm.end(); i++)
 	{		
-		bool status_time_threshold;
-		if(i->second.time_threshold > 0)		//if enabled time threshold
-			status_time_threshold = (i->second.counter >= 1) && ((ts.tv_sec - i->second.time_threshold) > i->second.ts_time_threshold.tv_sec);	//waiting for threshold and time threshold is passed
-		else
-			continue;			//if not enabled time threshold, nothing to do in timer	
+		bool status_on_delay;
+		bool status_off_delay;
+		if(i->second.on_delay == 0 && i->second.off_delay == 0)
+			continue;	//if not enabled on or off delay, nothing to do in timer
+		if(i->second.on_delay > 0)		//if enabled on delay
+			status_on_delay = (i->second.on_counter >= 1) && ((ts.tv_sec - i->second.on_delay) > i->second.ts_on_delay.tv_sec);	//waiting for on delay has passed
+		if(i->second.off_delay > 0)		//if enabled off delay
+			status_off_delay = (i->second.off_counter >= 1) && ((ts.tv_sec - i->second.off_delay) > i->second.ts_off_delay.tv_sec);	//waiting for off delay has passed
 
-		//if status changed from S_NORMAL to S_ALARM considering also time threshold	
-		if(status_time_threshold && (i->second.stat == S_NORMAL))
+		//if status changed:
+		// - from S_NORMAL to S_ALARM considering also on delay
+		//or
+		// - from S_ALARM to S_NORMAL considering also off delay
+		if(status_on_delay && (i->second.stat == S_NORMAL) || (status_off_delay && (i->second.stat == S_ALARM)))
 		{
 			ret_changed = true;
 			if(i->second.silenced > 0)
@@ -559,59 +592,117 @@ bool alarm_table::timer_update()
 			a.name = i->second.name;
 			a.time_s = ts.tv_sec;		
 			a.time_us = ts.tv_usec;
-			a.status = S_ALARM;
+			a.status = (status_on_delay) ? S_ALARM : S_NORMAL;
 			//a.level = found->second.lev;
-			i->second.ack = NOT_ACK;	//if changing from NORMAL to ALARM -> NACK
+			if(status_on_delay)
+				i->second.ack = NOT_ACK;	//if changing from NORMAL to ALARM -> NACK
 			a.ack = i->second.ack;
-			a.values = i->second.attr_values_time_threshold;
+			a.values = i->second.attr_values_delay;
 			logloop->log_alarm_db(a);
 			i->second.ts = ts;	/* store event timestamp into alarm timestamp */ //here update ts only if status changed
-
-			i->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(i->second.dp_a && ((ts.tv_sec - startup_complete.tv_sec) > 10))
+			if(status_on_delay)
 			{
-				/*try {
-					long call_id;
+				i->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(i->second.dp_a && ((ts.tv_sec - startup_complete.tv_sec) > 10))
+				{
+					/*try {
+						long call_id;
+						ostringstream tmp;
+						tmp << i->second.name << ";" << i->second.attr_values_on_delay;
+						Tango::DevString str = CORBA::string_dup(tmp.str().c_str());
+						Tango::DeviceData Din;
+						Din << str;
+						CORBA::string_free(str);
+						//i->second.dp_a->ping();
+						cmdloop->mutex_dp->lock();
+						//call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din, true);		//true -> "fire and forget" mode: client do not care at all about the server answer
+						call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din);
+						cmdloop->mutex_dp->unlock();
+						LOG_STREAM << gettime().tv_sec << " alarm_table::timer_update() executed action: " << i->second.cmd_name_a << " !!!" << endl;
+						cmd_t arg;
+						arg.cmd_id = call_id;
+						arg.dp_add = (long)i->second.dp_a;
+						arg.arg_s = i->second.cmd_name_a;
+						cmdloop->list.push_back(arg);
+					} catch(Tango::DevFailed e)
+					{
+						string err(e.errors[0].desc);
+						if(err.find("is not yet arrived") == string::npos)			//TODO: change this!!
+							out_stream << "Failed to execute action " << i->second.cmd_name_a << ", err=" << e.errors[0].desc << ends;
+						//LOG_STREAM << "alarm_table::timer_update() ERROR: " << out_stream.str() << endl;
+					}*/
 					ostringstream tmp;
-					tmp << i->second.name << ";" << i->second.attr_values_time_threshold;
-					Tango::DevString str = CORBA::string_dup(tmp.str().c_str());
-					Tango::DeviceData Din;
-					Din << str;
-					CORBA::string_free(str);
-					//i->second.dp_a->ping();		
-					cmdloop->mutex_dp->lock();			
-					//call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din, true);		//true -> "fire and forget" mode: client do not care at all about the server answer
-					call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din);		
-					cmdloop->mutex_dp->unlock();
-					LOG_STREAM << gettime().tv_sec << " alarm_table::timer_update() executed action: " << i->second.cmd_name_a << " !!!" << endl;
+					string tmp_attr_val = i->second.attr_values_delay;
+					replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
+					string tmp_msg = i->second.msg;
+					replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
+					tmp << "name=" << i->second.name << ";groups=" << i->second.grp2str() << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<i->second.formula;
 					cmd_t arg;
-					arg.cmd_id = call_id;
+					arg.cmd_id = CMD_COMMAND;
 					arg.dp_add = (long)i->second.dp_a;
-					arg.arg_s = i->second.cmd_name_a;	
-					cmdloop->list.push_back(arg);					
-				} catch(Tango::DevFailed e) 
+					arg.arg_s1 = tmp.str();
+					arg.arg_s2 = i->second.cmd_action_a;
+					arg.arg_s3 = i->second.cmd_name_a;
+					arg.arg_b = i->second.send_arg_a;
+					cmdloop->list.push_back(arg);
+				}
+			}
+			else if(status_off_delay)
+			{
+				if(i->second.dp_a && ((ts.tv_sec - startup_complete.tv_sec) > 10))
 				{
-					string err(e.errors[0].desc);
-					if(err.find("is not yet arrived") == string::npos)			//TODO: change this!!			
-						out_stream << "Failed to execute action " << i->second.cmd_name_a << ", err=" << e.errors[0].desc << ends;
-					//LOG_STREAM << "alarm_table::timer_update() ERROR: " << out_stream.str() << endl;
-				}*/
-				ostringstream tmp;
-				string tmp_attr_val = i->second.attr_values_time_threshold;
-				replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
-				string tmp_msg = i->second.msg;
-				replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
-				tmp << "name=" << i->second.name << ";groups=" << i->second.grp2str() << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<i->second.formula;
-				cmd_t arg;
-				arg.cmd_id = CMD_COMMAND;
-				arg.dp_add = (long)i->second.dp_a;
-				arg.arg_s1 = tmp.str();
-				arg.arg_s2 = i->second.cmd_action_a;
-				arg.arg_s3 = i->second.cmd_name_a;
-				arg.arg_b = i->second.send_arg_a;	
-				cmdloop->list.push_back(arg);
+					/*try {
+						long call_id;
+						ostringstream tmp;
+						tmp << i->second.name << ";" << i->second.attr_values_off_delay;
+						Tango::DevString str = CORBA::string_dup(tmp.str().c_str());
+						Tango::DeviceData Din;
+						Din << str;
+						CORBA::string_free(str);
+						//i->second.dp_n->ping();
+						cmdloop->mutex_dp->lock();
+						//call_id = i->second.dp_n->command_inout_asynch(i->second.cmd_action_n, Din, true);		//true -> "fire and forget" mode: client do not care at all about the server answer
+						call_id = i->second.dp_n->command_inout_asynch(i->second.cmd_action_n, Din);
+						cmdloop->mutex_dp->unlock();
+						LOG_STREAM << gettime().tv_sec << " alarm_table::timer_update() executed action: " << i->second.cmd_name_n << " !!!" << endl;
+						cmd_t arg;
+						arg.cmd_id = call_id;
+						arg.dp_add = (long)i->second.dp_n;
+						arg.arg_s = i->second.cmd_name_n;
+						cmdloop->list.push_back(arg);
+					} catch(Tango::DevFailed e)
+					{
+						string err(e.errors[0].desc);
+						if(err.find("is not yet arrived") == string::npos)			//TODO: change this!!
+							out_stream << "Failed to execute action " << i->second.cmd_name_n << ", err=" << e.errors[0].desc << ends;
+						//LOG_STREAM << "alarm_table::timer_update() ERROR: " << out_stream.str() << endl;
+					}*/
+					ostringstream tmp;
+					string tmp_attr_val = i->second.attr_values_delay;
+					replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
+					string tmp_msg = i->second.msg;
+					replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
+					tmp << "name=" << i->second.name << ";groups=" << i->second.grp2str() << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<i->second.formula;
+					cmd_t arg;
+					arg.cmd_id = CMD_COMMAND;
+					arg.dp_add = (long)i->second.dp_n;
+					arg.arg_s1 = tmp.str();
+					arg.arg_s2 = i->second.cmd_action_n;
+					arg.arg_s3 = i->second.cmd_name_n;
+					arg.arg_b = i->second.send_arg_n;
+					cmdloop->list.push_back(arg);
+				}
 			}
-			*(i->second.attr_value) = true;
+
+			//TODO: if not _SHLVD, _DSUPR, _OOSRV
+			if((status_off_delay) && i->second.ack == ACK)
+				*(i->second.attr_value) = _NORM;
+			else if((status_on_delay) && i->second.ack == NOT_ACK)
+				*(i->second.attr_value) = _UNACK;
+			else if((status_on_delay) && i->second.ack == ACK)
+				*(i->second.attr_value) = _ACKED;
+			else if((status_off_delay) && i->second.ack == NOT_ACK)
+				*(i->second.attr_value) = _RTNUN;
 			try
 			{
 				if(i->second.ex_reason.length() == 0)
@@ -636,9 +727,12 @@ bool alarm_table::timer_update()
 			} catch(Tango::DevFailed &e)
 			{}
 		}
-		if (status_time_threshold) {
+
+		if (status_on_delay) {
 			i->second.stat = S_ALARM;
-			//found->second.ack = NOT_ACK;
+		}
+		else if (status_off_delay) {
+			i->second.stat = S_NORMAL;
 		}
 		//found->second.ts = ts;	/* store event timestamp into alarm timestamp */ //here update ts everytime
 	}
@@ -783,13 +877,14 @@ void alarm_table::log_alarm_db(unsigned int type, Tango::TimeVal ts, string name
 }
 
 void alarm_table::save_alarm_conf_db(string att_name, Tango::TimeVal ts, string name, string status, string ack,
-		string formula, unsigned int time_threshold, string grp, string lev, string msg, string cmd_a, string cmd_n, int silent_time, vector<string> alm_list)
+		string formula, unsigned int on_delay, unsigned int off_delay, string grp, string lev, string msg, string cmd_a, string cmd_n, int silent_time, vector<string> alm_list)
 {
 	// We want to put properties for attribute "att_name"
 	Tango::DbDatum dbd_att_name(att_name);
 	Tango::DbDatum dbd_name(NAME_KEY);
 	Tango::DbDatum dbd_formula(FORMULA_KEY);
-	Tango::DbDatum dbd_time_threshold(DELAY_KEY);
+	Tango::DbDatum dbd_on_delay(ONDELAY_KEY);
+	Tango::DbDatum dbd_off_delay(OFFDELAY_KEY);
 	Tango::DbDatum dbd_level(LEVEL_KEY);
 	Tango::DbDatum dbd_silence_time(SILENT_TIME_KEY);	//TODO: silent_time
 	Tango::DbDatum dbd_group(GROUP_KEY);
@@ -801,7 +896,8 @@ void alarm_table::save_alarm_conf_db(string att_name, Tango::TimeVal ts, string
 	dbd_att_name << 9;                               // Eigth properties for attribute "att_name"
 	dbd_name << name;
 	dbd_formula << formula;
-	dbd_time_threshold << time_threshold;
+	dbd_on_delay << on_delay;
+	dbd_off_delay << off_delay;
 	dbd_level << lev;
 	dbd_silence_time << silent_time;
 	dbd_group << grp;
@@ -812,7 +908,8 @@ void alarm_table::save_alarm_conf_db(string att_name, Tango::TimeVal ts, string
 	db_data.push_back(dbd_att_name);
 	db_data.push_back(dbd_name);
 	db_data.push_back(dbd_formula);
-	db_data.push_back(dbd_time_threshold);
+	db_data.push_back(dbd_on_delay);
+	db_data.push_back(dbd_off_delay);
 	db_data.push_back(dbd_level);
 	db_data.push_back(dbd_silence_time);
 	db_data.push_back(dbd_group);
@@ -860,7 +957,8 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list)
 		i++;
 		string alm_name;
 		string alm_formula;
-		string alm_time_threshold("0");
+		string alm_on_delay("0");
+		string alm_off_delay("0");
 		string alm_level;
 		string alm_silence_time("-1");
 		string alm_group;
@@ -875,8 +973,10 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list)
 				db_data[i] >> alm_name;
 			else if (prop_name == FORMULA_KEY)
 				db_data[i] >> alm_formula;
-			else if (prop_name == DELAY_KEY)
-				db_data[i] >> alm_time_threshold;
+			else if (prop_name == ONDELAY_KEY)
+				db_data[i] >> alm_on_delay;
+			else if (prop_name == OFFDELAY_KEY)
+				db_data[i] >> alm_off_delay;
 			else if (prop_name == LEVEL_KEY)
 				db_data[i] >> alm_level;
 			else if (prop_name == SILENT_TIME_KEY)
@@ -900,7 +1000,8 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list)
 		stringstream alm;
 		alm << alm_name << "\t" <<
 				/*TODO: KEY(FORMULA_KEY)<<*/alm_formula << "\t" <<
-				KEY(DELAY_KEY)<<alm_time_threshold << "\t" <<
+				KEY(ONDELAY_KEY)<<alm_on_delay << "\t" <<
+				KEY(OFFDELAY_KEY)<<alm_off_delay << "\t" <<
 				KEY(LEVEL_KEY)<< alm_level << "\t" <<
 				KEY(SILENT_TIME_KEY)<<alm_silence_time << "\t" <<
 				KEY(GROUP_KEY)<< alm_group << "\t" <<
diff --git a/src/alarm_table.h b/src/alarm_table.h
index 062648d..3383184 100644
--- a/src/alarm_table.h
+++ b/src/alarm_table.h
@@ -268,7 +268,8 @@ class alarm_t {
 		Tango::TimeVal ts;
 		string stat,
 					 ack;
-		unsigned int counter;
+		unsigned int on_counter;
+		unsigned int off_counter;
 		
 		tree_parse_info_t formula_tree;
 					 
@@ -281,13 +282,15 @@ class alarm_t {
 		string lev;
 		set<string> s_event;
 		int is_new;
-		Tango::TimeVal ts_time_threshold;	//says when it has gone in alarm status for the first time
-		unsigned int time_threshold;		//TODO: seconds, is it enough precision?
+		Tango::TimeVal ts_on_delay;	//says when it has gone in alarm status for the first time
+		unsigned int on_delay;		//TODO: seconds, is it enough precision?
+		Tango::TimeVal ts_off_delay;	//says when it returned normal status
+		unsigned int off_delay;		//TODO: seconds, is it enough precision?
 
 		Tango::TimeVal ts_time_silenced;	//says when it has been silenced
 		int silent_time;			//minutes max to be silent
 		int silenced;				//minutes still to be silent
-		string attr_values_time_threshold;	//attr_values of first occurrence of alarm waiting for time threshold
+		string attr_values_delay;	//attr_values of first occurrence of alarm waiting for on or off delay
 		string cmd_name_a;					//action to execute: when NORMAL -> ALARM, cmd_name = cmd_dp_a/cmd_action_a
 		string cmd_dp_a;						//device proxy part of cmd_name_a
 		string cmd_action_a;					//action part of cmd_name_a
@@ -356,7 +359,7 @@ class alarm_table {
 		void log_alarm_db(unsigned int type, Tango::TimeVal ts, string name, string status, string ack,
 				 string formula, unsigned int time_threshold, string grp, string lev, string msg, string action, int silent_time, vector<string> alm_list=vector<string>());
 		void save_alarm_conf_db(string att_name, Tango::TimeVal ts, string name, string status, string ack,
-				 string formula, unsigned int time_threshold, string grp, string lev, string msg, string cmd_a, string cmd_n, int silent_time, vector<string> alm_list=vector<string>());
+				 string formula, unsigned int on_delay, unsigned int off_delay, string grp, string lev, string msg, string cmd_a, string cmd_n, int silent_time, vector<string> alm_list=vector<string>());
 		void get_alarm_list_db(vector<string> &al_list);
 		void init_cmdthread();
 		void stop_cmdthread();
-- 
GitLab