diff --git a/docs/Formula.md b/docs/Formula.md new file mode 100644 index 0000000000000000000000000000000000000000..d731f5159bd748c10e2d7ffac72ad3c08b6f48ff --- /dev/null +++ b/docs/Formula.md @@ -0,0 +1,140 @@ +# 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 + +## Indexes to access elements + +- A single element of a one-dimensional array attribute (Spectrum) can be extracted with a single index between square brackets (e.g. ```name/of/dev/attr[ind]```). +- A single element of a two-dimensional array attribute (Image) can be extracted with two indexes between square brackets (e.g. ```name/of/dev/attr[ind_row][ind_column]```). +- A one-dimensional array can be extracted from a two-dimensional array attribute (Image) with a single index between square brackets (e.g. ```name/of/dev/attr[ind_row]```). + +If any index exceeds actual dimensions of the array, the formula is evaluated to ERROR with an out of bounds exception. + +## Limitations + +- It is not possible to specify array constants (e.g. ```name/of/dev/attr > [val1,val2]```). +- It is not possible to use indexes on expressions (e.g. ```(any_expression)[ind]```). + +## 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..8b50b963bef78486307cf490100500ef302cbc0e 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,9 +3860,12 @@ void AlarmHandler::do_alarm(bei_t& e) } } if (found != events->v_event.end()) - { + { found->value = e.value; found->value_string = e.value_string; + found->read_size = e.read_size; + found->dim_x = e.dim_x; + found->dim_y = e.dim_y; found->quality = e.quality; //found->errors = e.errors; found->ex_reason = e.ex_reason; @@ -3983,7 +3987,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 +4044,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 +4056,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 +4066,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 +4106,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 +4228,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 +4514,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) { @@ -4466,7 +4528,7 @@ formula_res_t AlarmHandler::eval_formula(tree_parse_info_t tree, string &attr_va return res; } -formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values, int ev_ind) //throw (string &), std::out_of_range +formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values, vector<double> ev_ind) { ostringstream err; @@ -4482,10 +4544,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 +4563,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 +4580,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 +4597,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 +4615,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 +4629,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) { @@ -4646,49 +4705,81 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values DEBUG_STREAM << " node event" << string(i->value.begin(), i->value.end()) << endl; #endif formula_res_t ind; - if(i->children.size() != 2) + if(i->children.size() < 2) { err << "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();; throw err.str(); } - if((i->children.begin()+1)->value.id() == formula_grammar::indexID) - ind = eval_expression(i->children.begin()+1, attr_values); //array index - else if((i->children.begin()+1)->value.id() == formula_grammar::propertyID) + size_t child_ind=0; + while((child_ind < i->children.size() -1) && ((i->children.begin()+child_ind+1)->value.id() == formula_grammar::indexID)) { - if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".quality") + formula_res_t ind_tmp; + ind_tmp = eval_expression(i->children.begin()+child_ind+1, attr_values); //array index + if(ind_tmp.value.size() == 1 && ind_tmp.value[0]>=0) { - formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value); - res.value = res.quality; + ind.value.push_back(ind_tmp.value[0]); + } + child_ind++; + } + if(child_ind+1 == i->children.size() -1 && (i->children.begin()+child_ind+1)->value.id() == formula_grammar::propertyID) + { + if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) == ".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()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+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") + else if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+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, ind.value); + 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()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+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") + else if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+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, ind.value); + 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()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+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; } } - else + else if(child_ind+1 < i->children.size() -1)//unsupported more indexes/qualities { - 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()); + err << "expecting indexes or properties after attribute name, found instead: "<< string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+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, ind.value); + else + return eval_expression(i->children.begin(), attr_values); } else if (i->value.id() == formula_grammar::nameID) { @@ -4713,11 +4804,17 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values err << "attribute " << string(i->value.begin(), i->value.end()) << " value not valid while evaluating formula"; formula_res_t res; res.valid = false; + res.dim_x = it->dim_x; + res.dim_y = it->dim_y; 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(); + 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 @@ -4733,35 +4830,130 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values err << "attribute " << string(i->value.begin(), i->value.end()) << " value not initialized while evaluating formula"; formula_res_t res; res.valid = false; + res.dim_x = it->dim_x; + res.dim_y = it->dim_y; 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(); + 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 events->veclock.readerOut(); //throw err.str(); 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 - else - temp_attr_val << "\"" << it->name << "\":" <<it->value.at(ev_ind) << ",";//throw std::out_of_range - attr_values += temp_attr_val.str(); + } formula_res_t res; res.valid = true; + res.dim_x = it->dim_x; + res.dim_y = it->dim_y; res.quality = it->quality; res.ex_reason = it->ex_reason; res.ex_desc = it->ex_desc; res.ex_origin = it->ex_origin; + res.attr_name = it->name; + ostringstream temp_attr_val; + if(it->value.size() > 0) + { + if(!ev_ind.empty()) + { + size_t ev_ind_1d = ev_ind[0]; + temp_attr_val << "\"" << it->name; + for(auto ei : ev_ind) + { + temp_attr_val << "[" << ei << "]"; + } + temp_attr_val << "\":"; + if(ev_ind.size() ==1 && it->dim_y <=1)//single element of 1D array + { + res.dim_x = 1; + res.dim_y = 0; + if(ev_ind[0] >= it->value.size()) + { + err << "Requested element " << ev_ind[0] << " is out of bounds with dim=" << it->value.size(); + events->veclock.readerOut(); + DEBUG_STREAM << __func__ << ": " << err.str() << endl; + Tango::Except::throw_exception( //throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification) + (const char *)"OUT_OF_RANGE", + err.str(), + it->name); + } + res.value = {it->value.at(ev_ind[0])};//throw std::out_of_range + temp_attr_val << "[" << res.value[0] << "],"; + } + else if(ev_ind.size() == 1 && it->dim_y > 1)//single row of 2D array + { + res.dim_y = 0; + if(ev_ind[0] >= it->dim_y) + { + err << "Requested row " << ev_ind[0] << " is out of bounds with dim_y=" << it->dim_y; + events->veclock.readerOut(); + DEBUG_STREAM << __func__ << ": " << err.str() << endl; + Tango::Except::throw_exception( //throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification) + (const char *)"OUT_OF_RANGE", + err.str(), + it->name); + } + auto vstart = it->value.begin(); + auto vend = it->value.begin(); + advance(vstart,(int)(ev_ind[0] * (it->dim_x))); + advance(vend,(int)(ev_ind[0]+1)*it->dim_x); + res.value = value_t(vstart,vend); + temp_attr_val << "[" << print_vector(res.value) << "],"; + } + else if(ev_ind.size() == 2 && it->dim_y > 1)//single element of 2D array + { + res.dim_x = 1; + res.dim_y = 0; + if(ev_ind[0] >= it->dim_y) + { + err << "Requested row " << ev_ind[0] << " is out of bounds with dim_y=" << it->dim_y; + events->veclock.readerOut(); + DEBUG_STREAM << __func__ << ": " << err.str() << endl; + Tango::Except::throw_exception( //throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification) + (const char *)"OUT_OF_RANGE", + err.str(), + it->name); + } + if(ev_ind[1] >= it->dim_x) + { + err << "Requested column " << ev_ind[1] << " is out of bounds with dim_x=" << it->dim_x; + events->veclock.readerOut(); + DEBUG_STREAM << __func__ << ": " << err.str() << endl; + Tango::Except::throw_exception( //throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification) + (const char *)"OUT_OF_RANGE", + err.str(), + it->name); + } + res.value = {it->value.at(ev_ind[0]*it->dim_x + ev_ind[1])};//throw std::out_of_range + temp_attr_val << "[" <<res.value[0] << "],";//throw std::out_of_range + } + else //TODO N-DIMENSIONAL arrays + { + err << "UNSUPPORTED array indexes: " << ev_ind.size() << " indexes given, dim_x=" << it->dim_x << " dim_y=" << it->dim_y; + DEBUG_STREAM << __func__ << ": " << err.str() << endl; + events->veclock.readerOut(); + throw err.str(); + } + } + else + { + res.value = it->value; + temp_attr_val << "\"" << it->name << "\":[" <<print_vector(res.value) << "],"; + } + } + else + temp_attr_val << "\"" << it->name << "\":[],"; + attr_values += temp_attr_val.str(); + events->veclock.readerOut(); #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 - events->veclock.readerOut(); +#endif return res; } else @@ -4784,7 +4976,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 +5017,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, res_1.dim_x,res_1.dim_y,val_l2,res_2.dim_x,res_2.dim_y,res.value,res.dim_x,res.dim_y, "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, res_1.dim_x,res_1.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "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, res_1.dim_x,res_1.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "Bitwise ^", vectorUtils::fBitXor); return res; } else @@ -4895,42 +5103,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, res_2.dim_x,res_2.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "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, res_1.dim_x,res_1.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "Bitwise >>", vectorUtils::fBitShiftR); return res; } else @@ -4976,21 +5201,45 @@ 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.dim_x = it->dim_x; + res.dim_y = it->dim_y; + 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.dim_x = it->dim_x; + res.dim_y = it->dim_y; + 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 << "\","; attr_values += temp_attr_val.str(); res.valid = true; + res.dim_x = it->dim_x; + res.dim_y = it->dim_y; res.quality = it->quality; res.ex_reason = it->ex_reason; res.ex_desc = it->ex_desc; @@ -5013,12 +5262,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 +5328,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 +5347,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 +5409,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_1.dim_x,res_1.dim_y, res_2.value, res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, 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 +5423,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_1.dim_x,res_1.dim_y, res_2.value, res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, 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 +5437,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_1.dim_x,res_1.dim_y, res_2.value, res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, 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 +5465,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 +5495,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..d8b6007263cb8a37dda7660794787613ea49b381 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, vector<double> ev_ind={}); //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..d3701ec44af780ad8a29fb7d9b9f41cdced421a2 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,99 @@ 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, long v1_x, long v1_y, const vector<T> & v2, long v2_x, long v2_y, value_t &res, long &res_x, long &res_y, const string& origin, double (*func)(T, T)) +{ + if(v1.size() > 0 && v2.size() > 0 && (v1.size() == v2.size())) + { + res_x = v1_x; + res_y = v1_y; + if(v1_x != v2_x || (v1_y != v2_y && (v1_y > 1 || v2_y > 1)))//dim_y 0 and 1 are the same + { + ostringstream o; + o << "Array sizes do not match: " << (v1_y ? v1_y : 1) << "x" << v1_x << " != " << (v2_y ? v2_y : 1) << "x" << v2_x; + Tango::Except::throw_exception( //throw exception to have error not delayed + "FORMULA_ERROR", + o.str(), + origin); + } + 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) + { + res_x = v1_x; + res_y = v1_y; + 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) + { + res_x = v2_x; + res_y = v2_y; + 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_y ? v1_y : 1) << "x" << v1_x << " != " << (v2_y ? v2_y : 1) << "x" << v2_x; + 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("");dim_x=0;dim_y=0;} + value_t value; + long dim_x; + long dim_y; int quality; bool valid; string error; @@ -121,6 +211,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 +234,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 +250,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +264,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +278,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +292,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +306,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +320,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +340,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +363,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +380,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +394,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +408,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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 +422,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,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__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..2f9f97731dc9670edbc4d958c0c03b45d69ff65b 100644 --- a/src/event_table.cpp +++ b/src/event_table.cpp @@ -1278,7 +1278,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, e.read_size); + extract_values(ev->attr_value, e.value, e.value_string, e.type, e.read_size, e.dim_x, e.dim_y); } else { e.quality = Tango::ATTR_INVALID; #if 0//TANGO_VER >= 711 @@ -1341,7 +1341,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, int &read_size) +void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size, long &dim_x, long &dim_y) { Tango::DevState stval; vector<Tango::DevState> v_st; @@ -1375,76 +1375,79 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do attr_r_dim.dim_y = 0; //attr_w_dim.dim_y = 0; } + dim_x = attr_r_dim.dim_x; + dim_y = attr_r_dim.dim_y; 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; + 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 +1455,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) diff --git a/src/event_table.h b/src/event_table.h index 764369b3feed7d55fac9eff7f8d1a3e1fee08ad3..21758e040c3f4b637cc30124484da301e03f0564 100644 --- a/src/event_table.h +++ b/src/event_table.h @@ -66,7 +66,8 @@ class event { int type, /* attribute data type */ read_size, /* attribute size of read part */ counter, /* molteplicita' */ - err_counter; /* molteplicita' errore */ + err_counter; /* molteplicita' errore */ + long dim_x, dim_y; alarm_list m_alarm; bool valid; //TODO: old bool first;//TODO: new @@ -116,6 +117,8 @@ typedef struct basic_event_info_s { string ex_origin; int type; int read_size; + long dim_x; + long dim_y; Tango::TimeVal ts; string msg; } bei_t; @@ -202,7 +205,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, int &read_size); + void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size, long &dim_x, long &dim_y); private: //event_list* e_ptr; Tango::DeviceImpl *mydev; diff --git a/src/formula_grammar.h b/src/formula_grammar.h index 0aba5d0664c363d02eeb24ca3630e8b5269dc8db..8a83118f0c19bcd2401af1cfa6fb68bd76fd90c9 100644 --- a/src/formula_grammar.h +++ b/src/formula_grammar.h @@ -263,8 +263,8 @@ struct formula_grammar : public grammar<formula_grammar> event_ = name - >> !( (index) - | (property) + >> ( *(index)//0 or more indexex + >> !(property) //followed by 0 or 1 property ) ;