diff --git a/docs/Formula.md b/docs/Formula.md
new file mode 100644
index 0000000000000000000000000000000000000000..69515cf86b426acfaff256415ed626040206a5f1
--- /dev/null
+++ b/docs/Formula.md
@@ -0,0 +1,131 @@
+# Formula syntax
+The formula is an expression with operators, operands and functions. Operands can be variables, constant values, or other expression optionally enclosed by parentheses.
+
+## Operands
+
+### Variables
+
+- Attributes names with or without fqdn (e.g. ```tango://host:port/name/of/dev/attr```, ```name/of/dev/attr```)
+- attribute properties ```.quality```, ```.alarm```, ```.normal``` so that
+  - ```name/of/dev/attr.quality``` returns the Tango quality (the integer value) of the attribute
+  - ```name/of/dev/attr.alarm``` returns true if the attribute ==UNACK or ==ACK
+  - ```name/of/dev/attr.normal``` returns true if the attribute ==NORM or ==RTNUN
+
+### Constants
+
+- Real numbers (e.g. ```name/of/dev/attr >= 35```, ```name/of/dev/attr < -23.5```)
+- Hexadecimal numbers (e.g. ```name/of/dev/attr != 0xaf```, ```name/of/dev/attr & 0x1A```)
+- Strings as any character between an opening and a closing ' (e.g. ```name/of/dev/status == 'The device is in ON state.'```)
+- Tango states enum labels (*ON, OFF, CLOSE, OPEN, INSERT, EXTRACT, MOVING, STANDBY, FAULT, INIT, RUNNING, ALARM, DISABLE, UNKNOWN*) (e.g. ```name/of/dev/state == FAULT```)
+- Tango quality enum labels (*ATTR_VALID, ATTR_INVALID, ATTR_WARNING, ATTR_ALARM, ATTR_CHANGING*) (e.g. ```name/of/dev/attr.quality == ATTR_ALARM```)
+- Alarm state enum labels (*NORM, UNACK, ACKED, RTNUN, SHLVD, DSUPR, OOSRV*) (e.g. ```name/of/dev/alarm_attr != NORM```)
+
+### Expressions
+
+- A combination of operands and operators enclosed by parentheses
+
+## Operators
+
+### Binary Math
+- Multiplication ```*```
+- Division ```/```
+- Addition ```+```
+- Subtraction ```-```
+### Binary Comparison
+- Equal ```==```
+- Not equal ```!=```
+- Greater than ```>```
+- Greater than or equal to  ```>=```
+- Less than ```<```
+- Less than or equal to  ```<=```
+### Binary Logical
+- Logical AND ```&&```
+- Logical OR ```||```
+### Binary Bitwise
+- Left shift ```<<```
+- Right shift ```>>```
+- Bitwise AND ```&```
+- Bitwise OR ```|```
+- Bitwise XOR ```^```
+### Unary Math
+- Minus ```-```
+### Unary Logical
+- Logical NOT ```!```
+
+### Binary operators order of precedence
+
+```
+*, /, +, -, <<, >>, <=, >=, >, <, ==, !=, &, |, ^, &&, ||
+```
+
+## Functions
+
+### Unary Functions
+- Absolute value of X ```abs(X)```
+- Sine of X ```sin(X)```
+- Cosine of X ```cos(X)```
+
+### Binary Functions
+- Minimum between two values X and Y ```min(X,Y)```
+- Maximum between two values X and Y ```max(X,Y)```
+- Power: X raised to the power of Y ```pow(X,Y)```
+
+### Ternary Functions
+- Conditional operator: if X then Y else Z ```X ? Y : Z```
+
+### Reduce Functions
+- Reduce OR: reduce array X applying logical OR to each element ```OR(X)```
+- Reduce AND: reduce array X applying logical AND to each element ```OR(X)```
+
+# Attributes types
+
+The following types of attribute are supported:
+
+```
+Scalar, Spectrum, Image
+```
+
+with data types:
+
+```
+DevBoolean, DevUChar, DevShort, DevUShort, DevLong, DevULong, DevLong64, DevULong64, DevFloat, DevDouble, DevString, DevState, DevEnum
+```
+
+```DevEncoded``` is not supported.
+
+The read part of every attribute is internally extracted in a vector of double with the ```extract_read``` method of the ```DeviceAttribute``` class. In this ways operations between attribute with different data types and sizes can be performed with the following constraints:
+- DevString attributes can only be compared with 'equal' or 'not equal' operators to DevString attributes or string constants
+- Binary operators can operate on arrays if both operands have the same size, or one of the two has size equal to one.
+
+# Operation on arrays
+
+## Index to access single element
+
+A single element of an array attribute (Spectrum, Image) can be extracted with a single index between square brackets (e.g. ```name/of/dev/attr[ind]```). Since Image attributes are extracted to vectors as well, the single index can access every element as long as the size of rows is known. Accessing an *Image* element using two indexes for the two dimensions is not supported at the moment.
+
+## Unary operators and functions
+
+Unary operators and functions are applied to every element of the array
+
+## Binary operators and functions
+
+- If both operands have the same size, operators are applied element by element. Result is an array with the same size.
+- If one operand has size one, operators apply it to every element of the other operand. Result is an array with the same size.
+- Otherwise an exception is raised and the formula is evaluated to the *ERROR* state with the Reason, Descrption and Origin DevFailed fields properly filled.
+
+## Ternary Function
+- Conditional operator: if X then Y else Z. X is implicitly reduced with *OR* to have a boolean value, then Y or Z are evaluated depending on the result
+
+# Formula result
+Every formula produce a boolean result in the following way:
+1. each element of the array is tested as not equal to zero in order to have an array of booleans
+2. the array of boolean is reduced with OR (i.e. if at least one element of the array is TRUE, the result is TRUE) 
+
+# Errors
+
+If a formula cannot be evaluated, the corresponding alarm is set to the *ERROR* value with the Reason, Description and Origin DevFailed fields properly filled.
+Possible errors are:
+- Errors coming from the event system for one or more attributes involved in the formula
+- Errors coming from evaluation of array with different sizes
+- Errors coming from indexes out of bound while extracting elements from arrays
+- Unexpected errors while evaluating formulas
diff --git a/src/AlarmHandler.cpp b/src/AlarmHandler.cpp
index 274f4b5cd06127a060fbfbd9f8baf716b4079a2c..927e4da845a71c63f69245705638948a574763f0 100644
--- a/src/AlarmHandler.cpp
+++ b/src/AlarmHandler.cpp
@@ -37,6 +37,7 @@
 #include <AlarmHandler.h>
 #include <AlarmHandlerClass.h>
 #include <ctype.h>		//for tolower
+#include <numeric>		//for std::accumulate
 
 #include "alarm-thread.h"
 #include "alarm_grammar.h"
@@ -2354,7 +2355,7 @@ void AlarmHandler::modify(Tango::DevString argin)
 	//4: load modified alarm
 	//------------------------------
 	load(argin);
-
+	usleep(150000);//wait some time before updating attributes with prepare_alarm_attr so that event are subscribed and first evaluation done
 	prepare_alarm_attr();
 	try
 	{
@@ -3859,7 +3860,7 @@ void AlarmHandler::do_alarm(bei_t& e)
 		}
 	}
 	if (found != events->v_event.end())
-	{	
+	{
 		found->value = e.value;
 		found->value_string = e.value_string;
 		found->quality = e.quality;
@@ -3983,7 +3984,7 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 			it->second.to_be_evaluated = false;
 			it->second.attr_values.erase(it->second.attr_values.size()-1);
 			it->second.attr_values += string("}");
-			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": Evaluation of " << it->second.formula << "; result=" << res.value << " quality=" << res.quality << " valid=" << (int)res.valid << endl;
+			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": Evaluation of " << it->second.formula << "; result=" << print_vector(res.value) << " quality=" << res.quality << " valid=" << (int)res.valid << endl;
 			changed = alarms.update(tmpname, ts, res, it->second.attr_values, it->second.grp2str(), it->second.msg, it->second.formula); 		//update internal structure and log to db
 			changed = changed || (prev_error && res.valid);
 			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": changed=" << (int)changed << " error=" << (int)it->second.error << endl;
@@ -4040,7 +4041,8 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 			}
 		} catch(std::out_of_range& ex)
 		{
-			changed = !prev_error;
+			events->veclock.readerOut(); //readerIn called in eval_expression
+			changed = true;//force update attributes in case of modify/load alarm with out_of_range exception
 			it->second.to_be_evaluated = true;
 			ostringstream o;
 			o << tmpname << ": in formula array index out of range!";
@@ -4051,7 +4053,7 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 				Tango::DevErrorList errors(1);
 				errors.length(1);
 				it->second.ex_reason = string("OUT_OF_RANGE");
-				it->second.ex_desc = ev_name + ": " + o.str();
+				it->second.ex_desc = o.str();
 				it->second.ex_origin = ev_name;
 				errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
 				errors[0].severity = Tango::ERR;
@@ -4061,6 +4063,13 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 				bool enabled=it->second.enabled;
 				bool shelved=it->second.shelved;
 				int silenced=it->second.silenced;
+				Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
+				it->second.error=true;
+				it->second.quality = Tango::ATTR_INVALID;
+				if(enabled && !(shelved && silenced >0))
+				{
+					*attr_value = _ERROR;
+				}
 				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
 				if(enabled && !(shelved && silenced >0))
 				{
@@ -4094,6 +4103,54 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 				bool enabled=it->second.enabled;
 				bool shelved=it->second.shelved;
 				int silenced=it->second.silenced;
+				Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
+				it->second.error=true;
+				it->second.quality = Tango::ATTR_INVALID;
+				if(enabled && !(shelved && silenced >0))
+				{
+					*attr_value = _ERROR;
+				}
+				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
+				if(enabled && !(shelved && silenced >0))
+				{
+					push_change_event(attr_name, &except);
+					push_archive_event(attr_name, &except);
+				}
+			} catch(Tango::DevFailed & ex)
+			{
+				WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
+			}
+		}
+		catch(Tango::DevFailed & ex)
+		{
+			changed = !prev_error;
+			it->second.to_be_evaluated = true;
+			ostringstream o;
+			o << ex.errors[0].desc;
+			WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
+			set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
+			try
+			{	//DevFailed for push events
+				Tango::DevErrorList errors(1);
+				errors.length(1);
+				it->second.ex_reason = ex.errors[0].reason;
+				it->second.ex_desc = ex.errors[0].desc;
+				it->second.ex_origin = ex.errors[0].origin;
+				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);
+				bool enabled=it->second.enabled;
+				bool shelved=it->second.shelved;
+				int silenced=it->second.silenced;
+				Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
+				it->second.error=true;
+				it->second.quality = Tango::ATTR_INVALID;
+				if(enabled && !(shelved && silenced >0))
+				{
+					*attr_value = _ERROR;
+				}
 				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
 				if(enabled && !(shelved && silenced >0))
 				{
@@ -4168,6 +4225,7 @@ void AlarmHandler::timer_update()
 	{
 		return;
 	}
+	DEBUG_STREAM << "AlarmHandler::timer_update(): changed -> prepare_alarm_attr" << endl;
 	prepare_alarm_attr();//TODO: frequencyAlarm should be updated anyway
 	try
 	{
@@ -4453,8 +4511,9 @@ void AlarmHandler::set_internal_alarm(string name, Tango::TimeVal t, string msg,
 formula_res_t AlarmHandler::eval_formula(tree_parse_info_t tree, string &attr_values)
 {
 	formula_res_t res = eval_expression(tree.trees.begin(), attr_values);
+	res.extract_result(); //from Array res.value to Scalar res.value
 #ifdef _DEBUG_FORMULA
-	DEBUG_STREAM << __func__ << ": 		 finally value=" << res.value << " valid=" << (int)res.valid << " error='" << res.error << "' ex_desc='" << res.ex_desc<<"' quality=" << res.quality << endl;
+	DEBUG_STREAM << __func__ << ": 		 finally value=" << print_vector(res.value) << " valid=" << (int)res.valid << " error='" << res.error << "' ex_desc='" << res.ex_desc<<"' quality=" << res.quality << endl;
 #endif
 	if(res.valid)
 	{
@@ -4482,10 +4541,10 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }
         string val_d(i->value.begin(), i->value.end());
 		formula_res_t res;
-		res.value = strtod(val_d.c_str(), 0);
+		res.value = {(strtod(val_d.c_str(), 0))};
 		res.valid = true;
 #ifdef _DEBUG_FORMULA
-		DEBUG_STREAM << "		node value real = " << val_d << "(value="<<res.value<<" quality="<<res.quality<<")" << endl;
+		DEBUG_STREAM << "		node value real = " << val_d << "(value="<<print_vector(res.value)<<" quality="<<res.quality<<")" << endl;
 #endif
 		return res;
     }
@@ -4501,7 +4560,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value hex = " << val_d << endl;
 #endif
 		formula_res_t res;
-		res.value = strtod(val_d.c_str(), 0);
+		res.value = {(strtod(val_d.c_str(), 0))};
 		res.valid = true;
         return res;
     } 
@@ -4518,7 +4577,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value state : " << val_st << "=" << st << endl;
 #endif
 		formula_res_t res;
-		res.value = st;
+		res.value = {(double)st};
 		res.valid = true;
         return res;
     }
@@ -4535,7 +4594,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value alarm enum state : " << val_st << "=" << st << endl;
 #endif
 		formula_res_t res;
-		res.value = st;
+		res.value = {(double)st};
 		res.valid = true;
         return res;
     }
@@ -4553,7 +4612,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value quality : " << val_quality << "=" << quality << endl;
 #endif
 		formula_res_t res;
-		res.value = quality;
+		res.value = {(double)quality};
 		res.valid = true;
         return res;
 	}
@@ -4567,26 +4626,23 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         	err <<  "in node unary_exprID(" << 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 (*i->value.begin() == '+')
         {
-        	res.value = + res.value;
+			return eval_expression(i->children.begin(), attr_values);
         }
         else if (*i->value.begin() == '-')
         {
-        	res.value = - res.value;
+			return -eval_expression(i->children.begin(), attr_values);
         }
         else if (*i->value.begin() == '!')
         {
-        	res.value = ! res.value;
+			return !eval_expression(i->children.begin(), attr_values);
         }
         else
         {
         	err <<  "in node unary_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
         	throw err.str();
         }
-        return res;
     }
     else if (i->value.id() == formula_grammar::mult_exprID)
     {
@@ -4657,28 +4713,48 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		{
 			if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".quality")
 			{
-				formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value);
-				res.value = res.quality;
+				formula_res_t res;
+				res = eval_expression(i->children.begin(), attr_values);
+				res.value = {(double)res.quality};
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  res.attr_name << string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) << "\":[" <<print_vector(res.value) << "],";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "		node event.quality -> " << res.value << endl;
+				DEBUG_STREAM << "		node event.quality -> " << print_vector(res.value) << endl;
 #endif
 				return res;
 			}
 			else if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".alarm")
 			{
-				formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value);
-				res.value = (res.value == _UNACK) || (res.value == _ACKED);
+				formula_res_t res;
+				if(!ind.value.empty())
+					res = eval_expression(i->children.begin(), attr_values, (int)ind.value[0]);
+				else
+					res = eval_expression(i->children.begin(), attr_values);
+				std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+								[](double n) { return (double)((n == _UNACK) || (n == _ACKED)); });
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  res.attr_name << string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) << "\":[" <<print_vector(res.value) << "],";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "		node event.alarm -> " << res.value << endl;
+				DEBUG_STREAM << "		node event.alarm -> " << print_vector(res.value)<< endl;
 #endif
 				return res;
 			}
 			else if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".normal")
 			{
-				formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value);
-				res.value = (res.value == _NORM) || (res.value == _RTNUN);
+				formula_res_t res;
+				if(!ind.value.empty())
+					res = eval_expression(i->children.begin(), attr_values, (int)ind.value[0]);
+				else
+					res = eval_expression(i->children.begin(), attr_values);
+				std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+								[](double n) { return (double)((n == _NORM) || (n == _RTNUN)); });
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  res.attr_name << string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) << "\":[" <<print_vector(res.value) << "],";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "		node event.normal -> " << res.value << endl;
+				DEBUG_STREAM << "		node event.normal -> " << print_vector(res.value) << endl;
 #endif
 				return res;
 			}
@@ -4688,7 +4764,10 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         	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());
         	throw err.str(); 
         }
-		return eval_expression(i->children.begin(), attr_values, (int)ind.value);
+		if(!ind.value.empty())
+			return eval_expression(i->children.begin(), attr_values, (int)ind.value[0]);
+		else
+			return eval_expression(i->children.begin(), attr_values);
     }    
     else if (i->value.id() == formula_grammar::nameID)
     {
@@ -4718,6 +4797,10 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 				res.ex_desc = it->ex_desc;
 				res.ex_origin = it->ex_origin;
 				res.error = err.str();
+				res.attr_name = it->name;
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  it->name << "\":{\"Reason\":\"" << res.ex_reason << "\",\"Desc\":\"" << res.ex_desc << "\",\"Origin\":\"" << res.ex_origin << "\"},";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
 				DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value not valid, desc=" << res.ex_desc << " quality=" << res.quality << endl;
 #endif
@@ -4738,6 +4821,10 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 				res.ex_desc = it->ex_desc;
 				res.ex_origin = it->ex_origin;
 				res.error = err.str();
+				res.attr_name = it->name;
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  it->name << "\":{\"Reason\":\"" << res.ex_reason << "\",\"Desc\":\"" << res.ex_desc << "\",\"Origin\":\"" << res.ex_origin << "\"},";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
 				DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value empty, desc=" << res.ex_desc << " quality=" << res.quality << endl;
 #endif
@@ -4746,10 +4833,15 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 				return res;
         	}        	
 			ostringstream temp_attr_val;
-			if(it->value.size() > 1)
-				temp_attr_val << "\"" <<  it->name << "[" << ev_ind << "]\":" <<it->value.at(ev_ind) << ",";//throw  std::out_of_range
+			if(it->value.size() > 0)
+			{
+				if(ev_ind > 0)
+					temp_attr_val << "\"" <<  it->name << "[" << ev_ind << "]\":[" <<it->value.at(ev_ind) << "],";//throw  std::out_of_range
+				else
+					temp_attr_val << "\"" <<  it->name << "\":[" <<print_vector(it->value) << "],";
+			}
 			else
-				temp_attr_val << "\"" <<  it->name << "\":" <<it->value.at(ev_ind) << ",";//throw  std::out_of_range
+				temp_attr_val << "\"" <<  it->name << "\":[],";
 			attr_values += temp_attr_val.str();
 			formula_res_t res;
 			res.valid = true;
@@ -4757,10 +4849,14 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 			res.ex_reason = it->ex_reason;
 			res.ex_desc = it->ex_desc;
 			res.ex_origin = it->ex_origin;
+			res.attr_name = it->name;
 #ifdef _DEBUG_FORMULA
 			DEBUG_STREAM << "		node name -> " << temp_attr_val.str() << " quality=" << res.quality << endl;
 #endif
-			res.value = it->value.at(ev_ind);		//throw  std::out_of_range
+			if(ev_ind >=0)
+				res.value = {(it->value.at(ev_ind))};		//throw  std::out_of_range
+			else
+				res.value = it->value;
 			events->veclock.readerOut();
 			return 	res;
 		}
@@ -4784,7 +4880,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 #endif
      	formula_res_t res;
 		res.valid = true;
-     	res.value = strtod(val_d.c_str(), 0);
+     	res.value = {(strtod(val_d.c_str(), 0))};
         return res;
     }   
     else if (i->value.id() == formula_grammar::logical_exprID)
@@ -4825,56 +4921,72 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &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;
+        vector<long> val_l1(res_1.value.size()),val_l2(res_2.value.size());
 		bool valid = res_1.valid && res_2.valid;
             
-    	string err2("ERROR: non-int value in bitwise operation!");
-    	val_l1 = (long)trunc(res_1.value);		//transform to long
-    	val_l2 = (long)trunc(res_2.value);		//transform to long
-
-	    if((val_l1 != res_1.value) || (val_l2 != res_2.value))	//if different, lost something with truncf
-    		throw err2;
+    	string err2("Non int value in bitwise operation");
+		std::transform(res_1.value.begin(), res_1.value.end(), val_l1.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		std::transform(res_2.value.begin(), res_2.value.end(), val_l2.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		size_t ii;
+		for(ii=0; ii<res_1.value.size(); ii++)
+		{
+			if(val_l1[ii] != res_1.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception(	//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
+		for(ii=0; ii<res_2.value.size(); ii++)
+		{
+			if(val_l2[ii] != res_2.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception( //throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
     		  
         if (*i->value.begin() == '&')
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 & val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				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);
 			}
+			vectorUtils::applyVectorFunc(val_l1, val_l2,res.value, "Bitwise &", vectorUtils::fBitAnd);
             return res;
         }
         else if (*i->value.begin() == '|')
         {      
         	formula_res_t res;
-        	res.value = (double)(val_l1 | val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				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);
 			}
+			vectorUtils::applyVectorFunc(val_l1, val_l2,res.value, "Bitwise |", vectorUtils::fBitOr);
             return res;
         }  
         else if (*i->value.begin() == '^')
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 ^ val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				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);
 			}
+			vectorUtils::applyVectorFunc(val_l1, val_l2,res.value, "Bitwise ^", vectorUtils::fBitXor);
             return res;
         }  
         else
@@ -4895,42 +5007,59 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &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;
+        vector<long> val_l1(res_1.value.size()),val_l2(res_2.value.size());
 		bool valid = res_1.valid && res_2.valid;
             
-    	string err2("ERROR: non-int value in bitwise operation!");
-    	val_l1 = (long)trunc(res_1.value);		//transform to long
-    	val_l2 = (long)trunc(res_2.value);		//transform to long
-
-	    if((val_l1 != res_1.value) || (val_l2 != res_2.value))	//if different, lost something with truncf
-    		throw err2;
+    	string err2("Non int value in bitwise operation");
+		std::transform(res_1.value.begin(), res_1.value.end(), val_l1.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		std::transform(res_2.value.begin(), res_2.value.end(), val_l2.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		bool non_int_error=false;
+		size_t ii;
+		for(ii=0; ii<res_1.value.size(); ii++)
+		{
+			if(val_l1[ii] != res_1.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception(//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
+		for(ii=0; ii<res_2.value.size(); ii++)
+		{
+			if(val_l2[ii] != res_2.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception(//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
     		  
         if (string(i->value.begin(), i->value.end()) == string("<<"))
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 << val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				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);
 			}
+			vectorUtils::applyVectorFunc(val_l1, val_l2,res.value, "Bitwise <<", vectorUtils::fBitShiftL);
             return res;
         }
         else if (string(i->value.begin(), i->value.end()) == string(">>"))
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 >> val_l2);
-			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+			res.valid = valid;
 			if(!res.valid)
 			{
 				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);
 			}
+			vectorUtils::applyVectorFunc(val_l1, val_l2,res.value, "Bitwise >>", vectorUtils::fBitShiftR);
             return res;
         }  
         else
@@ -4976,16 +5105,34 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 						err <<  "in node equality_exprID -> nameID(" << string(i2_1->value.begin(), i2_1->value.end()) << ") value not valid!";
 						if(it->ex_desc.length() > 0)
 							err << " EX: '" << it->ex_desc << "'";
+						res.valid = false;
+						res.quality = it->quality;
+						res.ex_reason = it->ex_reason;
+						res.ex_desc = it->ex_desc;
+						res.ex_origin = it->ex_origin;
 						events->veclock.readerOut();
-						throw err.str();
+						/*Tango::Except::throw_exception( //throw exception to have error not delayed
+							it->ex_reason,//or Event_ERROR
+							it->ex_desc,
+							it->ex_origin);*/
+						return res;
 					}
 					else if(it->type != Tango::DEV_STRING && it->value.empty())
 					{
 						err <<  "in node nameID(" << string(i2_1->value.begin(), i2_1->value.end()) << ") value not initialized!!";
 						if(it->ex_desc.length() > 0)
 							err << " EX: '" << it->ex_desc << "'";
+						res.valid = false;
+						res.quality = it->quality;
+						res.ex_reason = it->ex_reason;
+						res.ex_desc = it->ex_desc;
+						res.ex_origin = it->ex_origin;
 						events->veclock.readerOut();
-						throw err.str();
+						/*Tango::Except::throw_exception( //throw exception to have error not delayed
+							it->ex_reason,//or Event_ERROR
+							it->ex_desc,
+							it->ex_origin);*/
+						return res;
 					}
 					ostringstream temp_attr_val;
 					temp_attr_val << "\"" << it->name << "\":\"" <<it->value_string << "\",";
@@ -5013,12 +5160,12 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 
 				if (string(i->value.begin(), i->value.end()) == string("!="))
 				{
-					res.value = attr_val != val_string;
+					res.value = {(double)(attr_val != val_string)};
 					return res;
 				}
 				else if (string(i->value.begin(), i->value.end()) == string("=="))
 				{
-					res.value = attr_val == val_string;
+					res.value = {(double)(attr_val == val_string)};
 					return res;
 				}
 				else
@@ -5079,7 +5226,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }        
         else
         {
-        	err <<  "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
+        	err <<  "in node compare_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
         	throw err.str(); 
         }	
     }   
@@ -5098,132 +5245,45 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &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);
+			std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+							[](double n) { return fabs(n); });
 			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);
+			std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+							[](double n) { return cos(n); });
 			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);
+			std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+							[](double n) { return sin(n); });
 			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;
+			res.value = {(double)res.quality};//ignore values and keep quality as result
 			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)
+		else if ((string(i->value.begin(), i->value.end()) == string("AND") || string(i->value.begin(), i->value.end()) == string("OR")))
 		{
-			events->veclock.readerIn();
-			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
-#ifdef _DEBUG_FORMULA
-			DEBUG_STREAM << "                       -> " << string(i->value.begin(), i->value.end()) << "(" << s << ")" << endl;
-#endif
-			while ((it != events->v_event.end()) && (it->name != s))
-				it++;
-			if (it != events->v_event.end())
+			res = eval_expression(i->children.begin(), attr_values);
+			if(string(i->value.begin(), i->value.end()) == string("AND"))
 			{
-				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 << it->ex_desc << "";
-					else
-						err <<  "attribute " << string(i->value.begin(), i->value.end()) << " value not valid while evaluating formula";
-					formula_res_t res;
-					res.valid = false;
-					res.quality = it->quality;
-					res.ex_reason = it->ex_reason;
-					res.ex_desc = it->ex_desc;
-					res.ex_origin = it->ex_origin;
-					res.error = err.str();
-#ifdef _DEBUG_FORMULA
-					DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value not valid, desc=" << res.ex_desc << endl;
-#endif
-					events->veclock.readerOut();
-					//throw err.str();
-					return res;
-				}
-				else if(it->type != Tango::DEV_STRING && it->value.empty())
-				{
-					if(it->ex_desc.length() > 0)
-						err << it->ex_desc << "";
-					else
-						err <<  "attribute " << string(i->value.begin(), i->value.end()) << " value not initialized while evaluating formula";
-					formula_res_t res;
-					res.valid = false;
-					res.quality = it->quality;
-					res.ex_reason = it->ex_reason;
-					res.ex_desc = it->ex_desc;
-					res.ex_origin = it->ex_origin;
-					res.error = err.str();
-#ifdef _DEBUG_FORMULA
-					DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value empty, desc=" << res.ex_desc << endl;
-#endif
-					events->veclock.readerOut();
-					//throw err.str();
-					return res;
-				}     
-
-				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;
-				res.valid = true;
-#ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "               node name -> " << temp_attr_val.str() << " quality=" << res.quality << endl;
-#endif
-				res.value = result;
-				events->veclock.readerOut();
-				return res;    
+				res.value = {(double)std::accumulate(res.value.begin(), res.value.end(), (bool)true, [](bool acc, double n) { return (bool)(acc && (bool)(n));})};
 			}
-			else
+			else if(string(i->value.begin(), i->value.end()) == string("OR"))
 			{
-				events->veclock.readerOut();
-				err <<  "in function " << string(i->value.begin(), i->value.end()) << " event (" << s << ") not found in event table" << ends;
-				throw err.str();
+				res.value = {(double)std::accumulate(res.value.begin(), res.value.end(), (bool)false, [](bool acc, double n) { return (bool)(acc || (bool)(n));})};
 			}
+#ifdef _DEBUG_FORMULA
+			DEBUG_STREAM << "		node funcID("<<string(i->value.begin(), i->value.end())<<") value="<<print_vector(res.value)<<" quality="<<res.quality<< endl;
+#endif
+			return res;
 		}
 		else
 		{
@@ -5247,7 +5307,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		if (string(i->value.begin(), i->value.end()) == string("min"))
 		{
         	formula_res_t res;
-        	res.value = min(res_1.value, res_2.value);
+			vectorUtils::applyVectorFunc(res_1.value, res_2.value, res.value, string(i->value.begin(), i->value.end()), vectorUtils::fMin);
 			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
@@ -5261,7 +5321,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		else if (string(i->value.begin(), i->value.end()) == string("max"))
 		{
         	formula_res_t res;
-        	res.value = max(res_1.value, res_2.value);
+			vectorUtils::applyVectorFunc(res_1.value, res_2.value, res.value, string(i->value.begin(), i->value.end()), vectorUtils::fMax);
 			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
@@ -5275,7 +5335,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		else if (string(i->value.begin(), i->value.end()) == string("pow"))
 		{
         	formula_res_t res;
-        	res.value = pow(res_1.value, res_2.value);
+			vectorUtils::applyVectorFunc(res_1.value, res_2.value, res.value, string(i->value.begin(), i->value.end()), vectorUtils::fPow);
 			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
@@ -5303,7 +5363,15 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 			throw err.str();
 		}
 		formula_res_t res_1=eval_expression(i->children.begin(), attr_values);
-		if(res_1.value)
+		if(!res_1.valid || res_1.value.empty())
+		{
+#ifdef _DEBUG_FORMULA
+			DEBUG_STREAM << "		node ternary_if expression: returning Error=" << res_1.ex_desc << endl;
+#endif
+			return res_1;
+		}
+		res_1.extract_result();
+		if(res_1.value[0])
 		{
         	formula_res_t res = eval_expression(i->children.begin()+1, attr_values);
             return res;
@@ -5325,7 +5393,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }	
     }
     formula_res_t res;
-    res.value = 0;
+    res.value = {(double)0.0};
 	res.valid = false;
     return res;
 }
diff --git a/src/AlarmHandler.h b/src/AlarmHandler.h
index 1f0fe2e80cc8152fd09e99e2842a7de2cf20acd7..de47f24cd779b9a5a13411a81178bdcbc5cf868d 100644
--- a/src/AlarmHandler.h
+++ b/src/AlarmHandler.h
@@ -607,7 +607,7 @@ private:
 	formula_res_t eval_formula(tree_parse_info_t tree, string &attr_values);
 	void find_event_formula(tree_parse_info_t tree, vector<string> &);
 	
-	formula_res_t 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=-1);			//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-thread.cpp b/src/alarm-thread.cpp
index 9a9874420fdf7d6f48c13f4feece634bd5f4b92e..a3a9c8b7ad467f4d2d545168578a3cd8948f1289 100644
--- a/src/alarm-thread.cpp
+++ b/src/alarm-thread.cpp
@@ -120,20 +120,20 @@ void alarm_thread::run(void *)
 			ostringstream err;
 			err << "omni_thread_fatal exception running alarm thread, err=" << ex.error << ends;
 			//WARN_STREAM << "alarm_thread::run(): " << err.str() << endl;	
-			printf("alarm_thread::run(): %s", err.str().c_str());
+			printf("alarm_thread::run(): %s\n", err.str().c_str());
 		}			
 		catch(Tango::DevFailed& ex)
 		{
 			ostringstream err;
 			err << "exception running alarm thread: '" << ex.errors[0].desc << "'" << ends;
 			//WARN_STREAM << "alarm_thread::run(): " << err.str() << endl;	
-			printf("alarm_thread::run(): %s", err.str().c_str());
+			printf("alarm_thread::run(): %s\n", err.str().c_str());
 			//Tango::Except::print_exception(ex);
 		}		
 		catch(...)
 		{
 			//WARN_STREAM << "alarm_thread::run(): catched unknown exception!!" << endl;
-			printf("alarm_thread::run(): catched unknown exception!!");
+			printf("alarm_thread::run(): catched unknown exception!!\n");
 		}		
 	}
 	//TANGO_LOG << "alarm_thread::run(): returning" << endl;
diff --git a/src/alarm_table.cpp b/src/alarm_table.cpp
index 1783cdaa8c6ffee21f6b29da5e990c23d5b112f5..6c1932c1f8cc225a4ce0655b16fee3b6493ea87b 100644
--- a/src/alarm_table.cpp
+++ b/src/alarm_table.cpp
@@ -374,14 +374,14 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 		found->second.quality = res.quality;
 		bool status_on_delay;
 		if(found->second.on_delay > 0)		//if enabled on delay
-			status_on_delay = ((bool)(res.value != 0)) && (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
+			status_on_delay = ((bool)(res.value[0] != 0)) && (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 = (bool)(res.value != 0);
+			status_on_delay = (bool)(res.value[0] != 0);
 		bool status_off_delay;
 		if(found->second.off_delay > 0)		//if enabled off delay
-			status_off_delay = (!(bool)(res.value != 0)) && (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
+			status_off_delay = (!(bool)(res.value[0] != 0)) && (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_off_delay = !(bool)(res.value != 0);
+			status_off_delay = !(bool)(res.value[0] != 0);
 		//if status changed:
 		// - from S_NORMAL to S_ALARM considering also on delay
 		//or
@@ -389,12 +389,12 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 		if((status_on_delay && (found->second.stat == S_NORMAL)) || (status_off_delay && (found->second.stat == S_ALARM)))
 		{
 			ret_changed=true;
-			if((bool)(res.value != 0))
+			if((bool)(res.value[0] != 0))
 				found->second.ack = NOT_ACK;	//if changing from NORMAL to ALARM -> NACK
 			//a.grp = found->second.grp2str();
-			//a.msg = (int)(res.value) ? found->second.msg : "";
+			//a.msg = (int)(res.value[0]) ? found->second.msg : "";
 			found->second.ts = ts;	/* store event timestamp into alarm timestamp */ //here update ts only if status changed
-			if((bool)(res.value != 0))
+			if((bool)(res.value[0] != 0))
 			{
 				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
@@ -525,7 +525,7 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 			found->second.error = true;
 		}
 
-		if((bool)(res.value != 0)) {
+		if((bool)(res.value[0] != 0)) {
 			found->second.on_counter++;
 			found->second.off_counter = 0;
 		} else {
diff --git a/src/alarm_table.h b/src/alarm_table.h
index 8155101a0710e39a645ae3d81b77fdc61a46ca86..5d396bd81d6ed94d37d47b73ca3eee4d22cd9aac 100644
--- a/src/alarm_table.h
+++ b/src/alarm_table.h
@@ -14,6 +14,7 @@
 #include <iostream>
 #include <string>
 #include <map>
+#include <numeric>		//for std::accumulate
 
 #include <tango/tango.h>
 
@@ -49,6 +50,7 @@
 
 using namespace std;
 
+typedef vector<Tango::DevDouble> value_t;
 
 #if BOOST_VERSION  < 103600
 typedef std::string::iterator  iterator_t;
@@ -109,11 +111,82 @@ struct rwlock_t
 };
 #endif
 
+template <typename T>
+string print_vector(const std::vector<T>& v, const char * const separator = ",")
+{
+	ostringstream out;
+    if(!v.empty())
+    {
+        std::copy(v.begin(),
+                  --v.end(),
+                  std::ostream_iterator<T>(out/*std::cout*/, separator));
+        out << v.back();
+    }
+	return out.str();
+}
+
+struct vectorUtils
+{
+static double fBitAnd(long a, long b){	return (double)(a & b);}
+static double fBitOr(long a, long b){	return (double)(a | b);}
+static double fBitXor(long a, long b){	return (double)(a ^ b);}
+static double fBitShiftL(long a, long b){	return (double)(a << b);}
+static double fBitShiftR(long a, long b){	return (double)(a >> b);}
+static double fMin(double a, double b){	return (double)min(a, b);}
+static double fMax(double a, double b){	return (double)max(a, b);}
+static double fPow(double a, double b){	return (double)pow(a, b);}
+static double fEqual(double a, double b){	return (double)(a == b);}
+static double fDifferent(double a, double b){	return (double)(a != b);}
+static double fGreaterEqual(double a, double b){	return (double)(a >= b);}
+static double fGreater(double a, double b){	return (double)(a > b);}
+static double fLessEqual(double a, double b){	return (double)(a <= b);}
+static double fLess(double a, double b){	return (double)(a < b);}
+static double fPlus(double a, double b){	return (double)(a + b);}
+static double fMinus(double a, double b){	return (double)(a - b);}
+static double fMult(double a, double b){	return (double)(a * b);}
+static double fDiv(double a, double b){	return (double)(a / b);}
+static double fAnd(double a, double b){	return (double)((bool)a && (bool)b);}
+static double fOr(double a, double b){	return (double)((bool)a || (bool)b);}
+
+template<class T >
+static void applyVectorFunc(const vector<T> & v1, const vector<T> & v2, value_t &res, const string& origin, double (*func)(T, T))
+{
+	if(v1.size() > 0 && v2.size() > 0 && (v1.size() == v2.size()))
+	{
+		res.resize(v1.size());
+		std::transform(v1.begin(), v1.end(), v2.begin(),res.begin(),
+					[func](T a, T b) { return func(a, b); });				
+	}
+	else if(v2.size() == 1)
+	{
+		T b = v2[0];
+		res.resize(v1.size());
+		std::transform(v1.begin(), v1.end(), res.begin(),
+					[b,func](T a) { return func(a, b); });
+	}
+	else if(v1.size() == 1)
+	{
+		T a = v1[0];
+		res.resize(v2.size());
+		std::transform(v2.begin(), v2.end(), res.begin(),
+					[a,func](T b) { return func(a, b); });
+	}
+	else if(v1.size() > 0 && v2.size() > 0)
+	{
+		ostringstream o;
+		o << "Array sizes do not match: " << v1.size() << "!=" <<v2.size();
+		Tango::Except::throw_exception( //throw exception to have error not delayed
+			"FORMULA_ERROR",
+			o.str(),
+			origin);
+	}
+}
+};
 
 struct formula_res_t
 {
-	formula_res_t(){value=0;valid=false;quality=Tango::ATTR_VALID;ex_reason=string("");ex_desc=string("");ex_origin=string("");}
-	double value;
+	formula_res_t(){valid=false;quality=Tango::ATTR_VALID;ex_reason=string("");ex_desc=string("");ex_origin=string("");}
+	value_t value;
 	int quality;
 	bool valid;
 	string error;
@@ -121,6 +194,7 @@ struct formula_res_t
 	string ex_reason;
 	string ex_desc;
 	string ex_origin;
+	string attr_name; //last evaluated attr name
 	int combine_quality(int quality1, int quality2)
 	{
 		int res;
@@ -143,10 +217,14 @@ struct formula_res_t
 		else
 			return ex_2;
 	}
+	void extract_result()
+	{
+		value = {(double)std::accumulate(value.begin(), value.end(), (bool)false, [](bool a, double b) { return (bool)(a || (bool)b); })};
+	}
+
 	formula_res_t operator==(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value == e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -155,12 +233,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fEqual);
 			return res;
 		}
 	formula_res_t operator!=(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value != e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -169,12 +247,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fDifferent);
 			return res;
 		}
 	formula_res_t operator<=(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value <= e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -183,12 +261,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fLessEqual);
 			return res;
 		}
 	formula_res_t operator>=(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value >= e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -197,12 +275,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fGreaterEqual);
 			return res;
 		}
 	formula_res_t operator<(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value < e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -211,12 +289,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fLess);
 			return res;
 		}
 	formula_res_t operator>(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value > e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -225,13 +303,19 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fGreater);
 			return res;
 		}
 	formula_res_t operator||(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = (valid && value) || (e.valid && e.value);
-			res.valid = (valid && value) || (e.valid && e.value) || (valid && e.valid);
+			if(value.size() <= 1 && e.value.size() <= 1) //apply special logic ov validity only if comparing scalars. Being careful that if valid=false, then size could be 0
+			{
+				res.value = {(double)((valid && value[0]) || (e.valid && e.value[0]))}; //in OR one operand TRUE and valid is enough
+				res.valid = (valid && value[0]) || (e.valid && e.value[0]) || (valid && e.valid); //in OR one operand TRUE and valid is enough, otherwise both valid as usual 
+			}
+			else
+				res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
 			{
@@ -239,13 +323,22 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			if(!(value.size() <= 1 && e.value.size() <= 1))
+			{
+				vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fOr);
+			}
 			return res;
 		}
 	formula_res_t operator&&(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = !((valid && !value) || (e.valid && !e.value)) || (valid && value && e.valid && e.value);
-			res.valid = (valid && !value) || (e.valid && !e.value) || (valid && e.valid);
+			if(value.size() <= 1 && e.value.size() <= 1) //apply special logic ov validity only if comparing scalars
+			{
+				res.value = {(double)(!((valid && !value[0]) || (e.valid && !e.value[0])) || (valid && value[0] && e.valid && e.value[0]))}; //if at least one operand is FALSE and valid, result is FALSE for sure (and valid)
+				res.valid = (valid && !value[0]) || (e.valid && !e.value[0]) || (valid && e.valid);
+			}
+			else
+				res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
 			{
@@ -253,12 +346,15 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			if(!(value.size() <= 1 && e.value.size() <= 1))
+			{
+				vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fAnd);
+			}
 			return res;
 		}
 	formula_res_t operator+(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value + e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -267,12 +363,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fPlus);
 			return res;
 		}
 	formula_res_t operator-(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value - e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -281,12 +377,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fMinus);
 			return res;
 		}
 	formula_res_t operator*(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value * e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -295,12 +391,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fMult);
 			return res;
 		}
 	formula_res_t operator/(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value / e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -309,6 +405,25 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,e.value,res.value,__func__,vectorUtils::fDiv);
+			return res;
+		}
+	formula_res_t operator!()
+		{
+			formula_res_t res;
+			for(size_t ii=0; ii < value.size(); ii++)
+			{
+				res.value.push_back(!value[ii]);
+			}
+			return res;
+		}
+	formula_res_t operator-()
+		{
+			formula_res_t res;
+			for(size_t ii=0; ii < value.size(); ii++)
+			{
+				res.value.push_back(-value[ii]);
+			}
 			return res;
 		}
 	/*string operator<<(const formula_res_t& e)
diff --git a/src/event_table.cpp b/src/event_table.cpp
index 2a19323790c259bafcf4d3554e605ffce2fb07ee..f52d904c94a65590fec8addd79e1cc2e7be29c2f 100644
--- a/src/event_table.cpp
+++ b/src/event_table.cpp
@@ -1380,71 +1380,72 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
                 read_size *= attr_r_dim.dim_y;
 
 	if (attr_value->get_type() == Tango::DEV_UCHAR) {
-		*(attr_value) >> v_uch;
+		attr_value->extract_read(v_uch);
 		for(vector<Tango::DevUChar>::iterator it = v_uch.begin(); it != v_uch.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_UCHAR;		
 	} else if (attr_value->get_type() == Tango::DEV_SHORT) {
-		*(attr_value) >> v_sh;
+		attr_value->extract_read(v_sh);
 		for(vector<Tango::DevShort>::iterator  it = v_sh.begin(); it != v_sh.end(); it++)
 			val.push_back((double)(*it));		//convert all to double				
 		type = Tango::DEV_SHORT;
 	} else if (attr_value->get_type() == Tango::DEV_USHORT) {
-		*(attr_value) >> v_ush;
+		attr_value->extract_read(v_ush);
 		for(vector<Tango::DevUShort>::iterator  it = v_ush.begin(); it != v_ush.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_USHORT;			
 	} else if (attr_value->get_type() == Tango::DEV_LONG) {
-		*(attr_value) >> v_lo;
+		attr_value->extract_read(v_lo);
 		for(vector<Tango::DevLong>::iterator  it = v_lo.begin(); it != v_lo.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_LONG;
 	} else if (attr_value->get_type() == Tango::DEV_STATE) {
 		//*(attr_value) >> v_st;		//doesn't work in tango 5
 		*(attr_value) >> stval;
-		v_st.push_back(stval);
-		for(vector<Tango::DevState>::iterator it = v_st.begin(); it != v_st.end(); it++)
-			val.push_back((double)(*it));		//convert all to double
+		//v_st.push_back(stval);
+		//attr_value->extract_read(stval);
+		//for(vector<Tango::DevState>::iterator it = v_st.begin(); it != v_st.end(); it++)
+		val.push_back((double)(stval));		//convert all to double
 		type = Tango::DEV_STATE;
 #if 1//TANGO_VER >= 600
 	} else if (attr_value->get_type() == Tango::DEV_ULONG) {
-		*(attr_value) >> v_ulo;
+		attr_value->extract_read(v_ulo);
 		for(vector<Tango::DevULong>::iterator  it = v_ulo.begin(); it != v_ulo.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_ULONG;
 #endif  //TANGO_VER >= 600								
 	} else if (attr_value->get_type() == Tango::DEV_DOUBLE) {
-		*(attr_value) >> v_do;
+		attr_value->extract_read(v_do);
 		for(vector<Tango::DevDouble>::iterator  it = v_do.begin(); it != v_do.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_DOUBLE;
 	} else if (attr_value->get_type() == Tango::DEV_FLOAT) {
-		*(attr_value) >> v_fl;
+		attr_value->extract_read(v_fl);
 		for(vector<Tango::DevFloat>::iterator  it = v_fl.begin(); it != v_fl.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_FLOAT;
 	} else if (attr_value->get_type() == Tango::DEV_BOOLEAN) {
-		*(attr_value) >> v_bo;
+		attr_value->extract_read(v_bo);
 		for(vector<Tango::DevBoolean>::iterator  it = v_bo.begin(); it != v_bo.end(); it++)
 			val.push_back((double)(*it));		//convert all to double		
 		type = Tango::DEV_BOOLEAN;
 	} else if (attr_value->get_type() == Tango::DEV_LONG64) {
-		*(attr_value) >> v_lo64;
+		attr_value->extract_read(v_lo64);
 		for(vector<Tango::DevLong64>::iterator  it = v_lo64.begin(); it != v_lo64.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_LONG64;
 	} else if (attr_value->get_type() == Tango::DEV_ULONG64) {
-		*(attr_value) >> v_ulo64;
+		attr_value->extract_read(v_ulo64);
 		for(vector<Tango::DevULong64>::iterator  it = v_ulo64.begin(); it != v_ulo64.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_ULONG64;
 	} else if (attr_value->get_type() == Tango::DEV_ENUM) {
-		*(attr_value) >> v_enum;
+		attr_value->extract_read(v_enum);
 		for(vector<Tango::DevEnum>::iterator  it = v_enum.begin(); it != v_enum.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_ENUM;
 	} else if (attr_value->get_type() == Tango::DEV_STRING) {
-		*(attr_value) >> v_string;
+		attr_value->extract_read(v_string);
 		val_string = *(v_string.begin());	//TODO: support string spectrum attrbutes
 		type = Tango::DEV_STRING;
 	}
@@ -1452,7 +1453,7 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
 		ostringstream o;
 		o << "unknown type";
 		throw o.str();
-	}	
+	}
 }
 
 /*void EventCallBack::init(event_list* e)