From 1ba7f19990852126ebb9a0a39ff8539eabe061c7 Mon Sep 17 00:00:00 2001
From: gscalamera <graziano.scalamera@elettra.eu>
Date: Tue, 17 Mar 2020 22:14:46 +0100
Subject: [PATCH] Support AND and OR formula for spectrum arrays

---
 src/AlarmHandler.cpp  | 92 +++++++++++++++++++++++++++++++++++++++----
 src/event_table.cpp   | 24 ++++++++++-
 src/event_table.h     |  4 +-
 src/formula_grammar.h |  4 +-
 4 files changed, 113 insertions(+), 11 deletions(-)

diff --git a/src/AlarmHandler.cpp b/src/AlarmHandler.cpp
index 49fd770..7bdad9d 100644
--- a/src/AlarmHandler.cpp
+++ b/src/AlarmHandler.cpp
@@ -3512,7 +3512,7 @@ void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
 				try {
 					Tango::DeviceAttribute attr_value;
 					attr_value = k->dp->read_attribute(k->attribute);
-					ecb.extract_values(&attr_value, k->value, k->type);
+					ecb.extract_values(&attr_value, k->value, k->type, k->read_size);
 					k->valid = true;
 					ostringstream msg;
 					msg << "AlarmHandler::add_event(): initial values of " << k->name << " = ";
@@ -3521,7 +3521,7 @@ void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
 					msg << ", valid=" << k->valid << ends;
 					DEBUG_STREAM << msg.str() << endl;
 					//delete attr_value;
-				} catch(Tango::DevFailed& e)
+				} catch(Tango::DevFailed& e
 				{
 					TangoSys_MemStream out_stream;
 					out_stream << "Failed to read initial value of " << k->name << " = " << e.errors[0].desc << ends;
@@ -3715,6 +3715,7 @@ void AlarmHandler::do_alarm(bei_t& e)
 		found->valid = true;
 		found->ts = e.ts;
 		found->type = e.type;
+		found->read_size = e.read_size;
 		found->err_counter = 0;
 		vector<string>::iterator j = found->m_alarm.begin();
 		while (j != found->m_alarm.end()) 
@@ -4769,38 +4770,115 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node function: " << string(i->value.begin(), i->value.end()) << endl;
 		if(i->children.size() != 1)		
 		{
-        	err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
-        	throw err.str(); 
-        }
+			err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
+			throw err.str(); 
+		}
 		formula_res_t res;
-		res = eval_expression(i->children.begin(), attr_values);
 
 		if (string(i->value.begin(), i->value.end()) == string("abs"))
 		{
+			res = eval_expression(i->children.begin(), attr_values);
 			res.value = fabs(res.value);
 			return res;
 		}
 		else if (string(i->value.begin(), i->value.end()) == string("cos"))
 		{
+			res = eval_expression(i->children.begin(), attr_values);
 			res.value = cos(res.value);
 			return res;
 		}
 		else if (string(i->value.begin(), i->value.end()) == string("sin"))
 		{
+			res = eval_expression(i->children.begin(), attr_values);
 			res.value = sin(res.value);
 			return res;
 		}
 		else if (string(i->value.begin(), i->value.end()) == string("quality"))
 		{
+			res = eval_expression(i->children.begin(), attr_values);
 			res.value = res.quality;
 			return res;
 		}
+		else if ((string(i->value.begin(), i->value.end()) == string("AND") || string(i->value.begin(), i->value.end()) == string("OR")) && i->children.begin()->value.id() == formula_grammar::nameID)
+		{
+			vector<event>::iterator it = events->v_event.begin();
+			string s(i->children.begin()->value.begin(), i->children.begin()->value.end());
+			std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower);            //transform to lowercase
+			DEBUG_STREAM << "                       -> " << string(i->value.begin(), i->value.end()) << "(" << s << ")" << endl;
+			while ((it != events->v_event.end()) && (it->name != s))
+				it++;
+			if (it != events->v_event.end())
+			{
+				if(!it->valid)
+				{
+					err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << "), (" << s << ") value not valid!" << ends;
+					if(it->ex_desc.length() > 0)
+						err <<  "attribute '" << string(i->value.begin(), i->value.end()) << "' exception: '" << it->ex_desc << "'";
+					else
+						err <<  "attribute '" << string(i->value.begin(), i->value.end()) << "' value not valid!";
+					throw err.str();
+				}
+				else if(it->type != Tango::DEV_STRING && it->value.empty())
+				{
+					if(it->ex_desc.length() > 0)
+						err <<  "attribute '" << string(i->value.begin(), i->value.end()) << "' exception: '" << it->ex_desc << "'";
+					else
+						err <<  "attribute '" << string(i->value.begin(), i->value.end()) << "' value not initialized!!";
+					throw err.str();
+				}     
+
+				ostringstream temp_attr_val;
+				bool result;
+				if (string(i->value.begin(), i->value.end()) == string("AND"))
+					result = true;
+				else if (string(i->value.begin(), i->value.end()) == string("OR"))
+					result = false;
+
+				temp_attr_val << "\"" << it->name << "\":";
+				if(it->read_size > 1)
+					temp_attr_val << "[";
+				for(int att_ind = 0; att_ind < it->read_size && att_ind < it->value.size(); att_ind++)
+				{
+					temp_attr_val << it->value.at(att_ind);
+					if (string(i->value.begin(), i->value.end()) == string("AND"))
+					{
+						result = result && (bool)it->value.at(att_ind);
+						if(!result)     //comment to have all array values in attr_values
+							break;  //comment to have all array values in attr_values
+					}
+					else if (string(i->value.begin(), i->value.end()) == string("OR"))
+					{
+						result = result || (bool)it->value.at(att_ind);
+						if(result)      //comment to have all array values in attr_values
+							break;  //comment to have all array values in attr_values
+					}
+					if(att_ind < it->read_size-1 && att_ind < it->value.size()-1)
+						temp_attr_val << ",";
+				}
+				if(it->read_size > 1)
+					temp_attr_val << "]";
+				temp_attr_val << ",";
+				attr_values += temp_attr_val.str();
+				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 = result;
+				return res;    
+			}
+			else
+			{
+				err <<  "in function " << string(i->value.begin(), i->value.end()) << " event (" << s << ") not found in event table" << ends;
+				throw err.str();
+			}
+		}
 		else
 		{
 			err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
 			throw err.str();
 		}
-    }  
+	}
 	else if (i->value.id() == formula_grammar::func_dualID)
 	{
 		DEBUG_STREAM << "		node function dual: " << string(i->value.begin(), i->value.end()) << endl;
diff --git a/src/event_table.cpp b/src/event_table.cpp
index 1c7a602..70f52bd 100644
--- a/src/event_table.cpp
+++ b/src/event_table.cpp
@@ -1134,7 +1134,7 @@ void EventCallBack::push_event(Tango::EventData* ev)
 			e.ev_name = ev->attr_name;
 #endif
 			e.ts = ev->attr_value->time;
-			extract_values(ev->attr_value, e.value, e.value_string, e.type);
+			extract_values(ev->attr_value, e.value, e.value_string, e.type, e.read_size);
 		} else {
 #if 0//TANGO_VER >= 711
  			string ev_name_str(ev->attr_name);
@@ -1195,7 +1195,7 @@ void EventCallBack::push_event(Tango::EventData* ev)
 	static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->evlist.push_back(e);
 }  /* push_event() */
 
-void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type)
+void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size)
 {
 	Tango::DevState stval;
 	vector<Tango::DevState> v_st;
@@ -1212,6 +1212,26 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
 	vector<string> v_string;
 	val_string = string("");
 
+	//Tango::AttributeDimension attr_w_dim;
+	Tango::AttributeDimension attr_r_dim;
+
+        //attr_value->reset_exceptions(Tango::DeviceAttribute::isempty_flag); //disable is_empty exception //commented to throw exceptions if empty
+        if(!attr_value->is_empty())
+        {
+                //attr_w_dim = data->attr_value->get_w_dimension();
+                attr_r_dim = attr_value->get_r_dimension();
+        }
+        else
+        {
+                attr_r_dim.dim_x = 0;
+                //attr_w_dim.dim_x = 0;
+                attr_r_dim.dim_y = 0;
+                //attr_w_dim.dim_y = 0;
+        }
+        read_size = attr_r_dim.dim_x;
+        if(attr_r_dim.dim_y > 1)
+                read_size *= attr_r_dim.dim_y;
+
 	if (attr_value->get_type() == Tango::DEV_UCHAR) {
 		*(attr_value) >> v_uch;
 		for(vector<Tango::DevUChar>::iterator it = v_uch.begin(); it != v_uch.end(); it++)
diff --git a/src/event_table.h b/src/event_table.h
index 576f2fe..8a8935b 100644
--- a/src/event_table.h
+++ b/src/event_table.h
@@ -57,6 +57,7 @@ class event {
 		string ex_origin;
 		Tango::TimeVal ts;		/* event timestamp */
 		int type,							/* attribute data type */
+				read_size,                                      /* attribute size of read part */
 				counter,					/* molteplicita' */
 				err_counter;					/* molteplicita' errore */				
 		//map<string, string> m_alarm;
@@ -109,6 +110,7 @@ typedef struct basic_event_info_s {
 	string ex_desc;
 	string ex_origin;
 	int type;
+	int read_size;
 	Tango::TimeVal ts;
 	string msg;
 } bei_t;
@@ -193,7 +195,7 @@ class EventCallBack : public Tango::CallBack, public Tango::LogAdapter
 		~EventCallBack(void);
 		void push_event(Tango::EventData* ev);
 		//void init(event_list* e);
-		void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type);
+		void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size);
 	private:
 		//event_list* e_ptr;
 		Tango::DeviceImpl *mydev;
diff --git a/src/formula_grammar.h b/src/formula_grammar.h
index 2dc2940..f2a6bad 100644
--- a/src/formula_grammar.h
+++ b/src/formula_grammar.h
@@ -356,7 +356,9 @@ struct formula_grammar : public grammar<formula_grammar>
             	=	( root_node_d[str_p("abs")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')])	//TODO: ? not expr_atom ?
             		| root_node_d[str_p("cos")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')])	//TODO: ? not expr_atom ?
             		| root_node_d[str_p("sin")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')])	//TODO: ? not expr_atom ?
-					| root_node_d[str_p("quality")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')])	//TODO: ? not expr_atom ?
+            		| root_node_d[str_p("quality")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')])	//TODO: ? not expr_atom ?
+            		| root_node_d[str_p("AND")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')])	//TODO: ? not expr_atom ?
+            		| root_node_d[str_p("OR")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')])	//TODO: ? not expr_atom ?
             		)
             	;
             function_dual
-- 
GitLab