diff --git a/docs/Formula.md b/docs/Formula.md index d731f5159bd748c10e2d7ffac72ad3c08b6f48ff..a7311769106974f61d41630ec5cd8ab4e8b5808d 100644 --- a/docs/Formula.md +++ b/docs/Formula.md @@ -105,8 +105,20 @@ The read part of every attribute is internally extracted in a vector of double w - 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]```). +## Lists and ranges of indexes to slice arrays +Indexes can be specified as a comma separated list and/or hyphen-separated range (e.g. ```[i0,i1-i2,...]```). +In this way: +- A slice can be extracted from a one-dimensional array with a list and/or range of indexes between square brackets (e.g. ```name/of/dev/1Dattr[i0,i1-i2,...]```). +- A subset of rows can be extracted from a two-dimensional array with a list and/or range of indexes for the first dimension (e.g. ```name/of/dev/2Dattr[i0,i1-i2,...]```). +- A single column slice can be extracted from a two-dimensional array with a list and/or range of indexes for the first dimension and a single index for the second dimension (e.g. ```name/of/dev/2Dattr[i0,i1-i2,...][i3]```). +- A single row slice can be extracted from a two-dimensional array with a single index for the first dimension and list/range of indexes for the second dimension (e.g. ```name/of/dev/2Dattr[i0][i1-i2,i3,...]```). +- An array slice can be extracted from a two-dimensional array with a list and/or range of indexes for both the first and second dimensions (e.g. ```name/of/dev/2Dattr[i0-i1,...][i2,i3,...]```). +- To specify all elements of one dimension index -1 can be used (e.g. Column 3 of all rows of 2D array ```name/of/dev/2Dattr[-1][3]```). + If any index exceeds actual dimensions of the array, the formula is evaluated to ERROR with an out of bounds exception. +No check is done on the order and uniqueness of indexes, so it is allowed to concatenate duplicated and out of order elements/rows/columns (e.g. ```name/of/dev/2Dattr[0-2,1,0,..]``` evaluates to an array with rows 0,1,2,1,0 of 2Dattr) + ## Limitations - It is not possible to specify array constants (e.g. ```name/of/dev/attr > [val1,val2]```). diff --git a/src/AlarmHandler.cpp b/src/AlarmHandler.cpp index 8b50b963bef78486307cf490100500ef302cbc0e..4d6b8d5d4f86405d8a1522e2aeb13b97c5c82517 100644 --- a/src/AlarmHandler.cpp +++ b/src/AlarmHandler.cpp @@ -491,6 +491,8 @@ void AlarmHandler::init_device() rule_names[formula_grammar::val_qualityID] = "ValQuality"; rule_names[formula_grammar::val_alarm_enum_stID] = "ValAlarmEnumStatus"; rule_names[formula_grammar::propertyID] = "EventProperty"; + rule_names[formula_grammar::index_rangeID] = "RangeIndex"; + rule_names[formula_grammar::index_listID] = "ListIndex"; /* * get device attribute properties and initialize internal @@ -3813,6 +3815,10 @@ void AlarmHandler::do_alarm(bei_t& e) push_archive_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz); push_archive_event("alarmDisabled",attr_alarmDisabled_read, alarmDisabled_sz); } + else + { + events->veclock.readerOut(); + } return; } //here not event error @@ -3948,6 +3954,7 @@ void AlarmHandler::do_alarm(bei_t& e) } else { + events->veclock.readerOut(); DEBUG_STREAM << "AlarmHandler::"<<__func__<<": event=" << e.ev_name << "NOT FOUND IN EVENT TABLE" << endl; } } /* do_alarm() */ @@ -3987,7 +3994,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=" << print_vector(res.value) << " quality=" << res.quality << " valid=" << (int)res.valid << endl; + DEBUG_STREAM << "AlarmHandler::"<<__func__<<": Evaluation of " << it->second.formula << "; result=" << print_array(res.value,res.dim_x,res.dim_y) << " 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; @@ -4168,6 +4175,7 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal } else { + alarms.vlock->readerOut(); ostringstream o; //o << j->first << ": not found formula in alarm table" << ends; o << (alm_name) << ": not found formula in alarm table"; @@ -4516,7 +4524,7 @@ formula_res_t AlarmHandler::eval_formula(tree_parse_info_t tree, string &attr_va 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=" << print_vector(res.value) << " valid=" << (int)res.valid << " error='" << res.error << "' ex_desc='" << res.ex_desc<<"' quality=" << res.quality << endl; + DEBUG_STREAM << __func__ << ": finally value=" << print_array(res.value,res.dim_x,res.dim_y) << " valid=" << (int)res.valid << " error='" << res.error << "' ex_desc='" << res.ex_desc<<"' quality=" << res.quality << endl; #endif if(res.valid) { @@ -4528,7 +4536,40 @@ 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, vector<double> ev_ind) +void AlarmHandler::eval_index_range(iter_t const& i, string &attr_values, vector<double> & ind) +{ + if(i->value.id() == formula_grammar::index_rangeID || i->value.id() == formula_grammar::indexID) + { + if(i->children.size() == 0) + { + std::string val_s(i->value.begin(), i->value.end()); + long value = strtol(val_s.c_str(), NULL, 10); + if(value>=0) + { + ind.push_back(value); + } + else if(value == -1) + { + ind = {(double)(value)}; + } + } + else if(i->children.size() == 2) + { + iter_t child = i->children.begin(); + string val_s1(child->value.begin(), child->value.end()); + long ind_start = strtol(val_s1.c_str(), NULL, 10); + string val_s2((child+1)->value.begin(), (child+1)->value.end()); + long ind_end = strtol(val_s2.c_str(), NULL, 10); + if(ind_start>=0 && ind_end>=ind_start) + { + for(int ind_range=ind_start; ind_range<=ind_end; ind_range++) + ind.push_back((double)ind_range); + } + } + } +} + +formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values, vector< vector<double> > ev_ind) { ostringstream err; @@ -4545,9 +4586,11 @@ 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.dim_x=1; + res.dim_y=0; res.valid = true; #ifdef _DEBUG_FORMULA - DEBUG_STREAM << " node value real = " << val_d << "(value="<<print_vector(res.value)<<" quality="<<res.quality<<")" << endl; + DEBUG_STREAM << " node value real = " << val_d << "(value="<<print_array(res.value,res.dim_x,res.dim_y)<<" quality="<<res.quality<<")" << endl; #endif return res; } @@ -4564,6 +4607,8 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values #endif formula_res_t res; res.value = {(strtod(val_d.c_str(), 0))}; + res.dim_x=1; + res.dim_y=0; res.valid = true; return res; } @@ -4581,6 +4626,8 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values #endif formula_res_t res; res.value = {(double)st}; + res.dim_x=1; + res.dim_y=0; res.valid = true; return res; } @@ -4598,6 +4645,8 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values #endif formula_res_t res; res.value = {(double)st}; + res.dim_x=1; + res.dim_y=0; res.valid = true; return res; } @@ -4616,6 +4665,8 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values #endif formula_res_t res; res.value = {(double)quality}; + res.dim_x=1; + res.dim_y=0; res.valid = true; return res; } @@ -4710,74 +4761,97 @@ 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()) << ") children=" << i->children.size();; throw err.str(); } - size_t child_ind=0; - while((child_ind < i->children.size() -1) && ((i->children.begin()+child_ind+1)->value.id() == formula_grammar::indexID)) + vector<vector<double> > indexes; + iter_t child = i->children.begin(); + if(child->value.id() != formula_grammar::nameID) + { + err << "in node "<< rule_names[i->value.id()]<<"(" << string(i->value.begin(), i->value.end()) << ") expecting " << rule_names[formula_grammar::nameID] << " as first child"; + throw err.str(); + } + child++; + while(child != i->children.end() && child->value.id() != formula_grammar::propertyID) //eval indexes { - 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) + if(child->value.id() == formula_grammar::index_rangeID || child->value.id() == formula_grammar::indexID) { - ind.value.push_back(ind_tmp.value[0]); + vector<double> ind_range; + eval_index_range(child, attr_values, ind_range); + if(!ind_range.empty()) + indexes.push_back(ind_range); } - child_ind++; + else if(child->value.id() == formula_grammar::index_listID) + { + vector<double> ind_list; + iter_t granchild = child->children.begin(); + while(granchild != child->children.end() && granchild->value.id() == formula_grammar::index_rangeID) //eval indexes + { + eval_index_range(granchild, attr_values, ind_list); + granchild++; + } + if(!ind_list.empty()) + indexes.push_back(ind_list); + } + child++; } - if(child_ind+1 == i->children.size() -1 && (i->children.begin()+child_ind+1)->value.id() == formula_grammar::propertyID) + + if(child - i->children.begin() == (long int)i->children.size() -1 && child->value.id() == formula_grammar::propertyID) { - if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) == ".quality") + if(string(child->value.begin(), child->value.end()) == ".quality") { formula_res_t res; res = eval_expression(i->children.begin(), attr_values); res.value = {(double)res.quality}; + res.dim_x=1; + res.dim_y=0; 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) << "],"; + temp_attr_val << "\"" << res.attr_name << string(child->value.begin(), child->value.end()) << "\":" <<print_array(res.value,res.dim_x,res.dim_y) << ","; attr_values += temp_attr_val.str(); #ifdef _DEBUG_FORMULA - DEBUG_STREAM << " node event.quality -> " << print_vector(res.value) << endl; + DEBUG_STREAM << " node event.quality -> " << print_array(res.value,res.dim_x,res.dim_y) << endl; #endif return res; } - else if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) == ".alarm") + else if(string(child->value.begin(), child->value.end()) == ".alarm") { formula_res_t res; - if(!ind.value.empty()) - res = eval_expression(i->children.begin(), attr_values, ind.value); + if(!indexes.empty()) + res = eval_expression(i->children.begin(), attr_values, indexes); 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) << "],"; + temp_attr_val << "\"" << res.attr_name << string(child->value.begin(), child->value.end()) << "\":" <<print_array(res.value,res.dim_x,res.dim_y) << ","; attr_values += temp_attr_val.str(); #ifdef _DEBUG_FORMULA - DEBUG_STREAM << " node event.alarm -> " << print_vector(res.value)<< endl; + DEBUG_STREAM << " node event.alarm -> " << print_array(res.value,res.dim_x,res.dim_y)<< endl; #endif return res; } - else if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) == ".normal") + else if(string(child->value.begin(), child->value.end()) == ".normal") { formula_res_t res; - if(!ind.value.empty()) - res = eval_expression(i->children.begin(), attr_values, ind.value); + if(!indexes.empty()) + res = eval_expression(i->children.begin(), attr_values, indexes); 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) << "],"; + temp_attr_val << "\"" << res.attr_name << string(child->value.begin(), child->value.end()) << "\":" <<print_array(res.value,res.dim_x,res.dim_y) << ","; attr_values += temp_attr_val.str(); #ifdef _DEBUG_FORMULA - DEBUG_STREAM << " node event.normal -> " << print_vector(res.value) << endl; + DEBUG_STREAM << " node event.normal -> " << print_array(res.value,res.dim_x,res.dim_y) << endl; #endif return res; } } - else if(child_ind+1 < i->children.size() -1)//unsupported more indexes/qualities + else if(child - i->children.begin() < (long int)i->children.size() -1)//unsupported more indexes/qualities { - 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()); + err << "expecting indexes or properties after attribute name, found instead: "<< string(child->value.begin(), child->value.end()); throw err.str(); } - if(!ind.value.empty()) - return eval_expression(i->children.begin(), attr_values, ind.value); + if(!indexes.empty()) + return eval_expression(i->children.begin(), attr_values, indexes); else return eval_expression(i->children.begin(), attr_values); } @@ -4862,76 +4936,327 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values { if(!ev_ind.empty()) { - size_t ev_ind_1d = ev_ind[0]; temp_attr_val << "\"" << it->name; - for(auto ei : ev_ind) + for(auto vei : ev_ind) { - temp_attr_val << "[" << ei << "]"; + if(!vei.empty()) + { + temp_attr_val << "[" << print_vector(vei) << "]"; + } } temp_attr_val << "\":"; - if(ev_ind.size() ==1 && it->dim_y <=1)//single element of 1D array + if(it->dim_y <=1)//1D array { - res.dim_x = 1; - res.dim_y = 0; - if(ev_ind[0] >= it->value.size()) + if(ev_ind.size() ==1 && ev_ind[0].size() == 1 && ev_ind[0][0] != -1)//single element of 1D array (e.g. [0]) { - 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.dim_x = 1; + res.dim_y = 0; + if(ev_ind[0][0] >= it->value.size()) + { + err << "Requested element " << ev_ind[0][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][0])};//throw std::out_of_range + temp_attr_val << "[" << res.value[0] << "],"; } - 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) + else if(ev_ind.size() ==1 && ev_ind[0].size() > 1)//multiple elements of 1D array (e.g. [0,1,2]) { - err << "Requested row " << ev_ind[0] << " is out of bounds with dim_y=" << it->dim_y; - events->veclock.readerOut(); + res.dim_y = 0; + for(auto ei0 : ev_ind[0]) + { + if(ei0 < 0 || ei0 >= it->value.size()) + { + err << "Requested element " << ei0 << " is out of bounds with dim=" << it->value.size(); + temp_attr_val << "[]"; + 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); + } + else + { + res.value.push_back(it->value.at(ei0));//throw std::out_of_range + } + } + res.dim_x = res.value.size(); + temp_attr_val << print_array(res.value, res.dim_x, res.dim_y) << ","; + } + else if(ev_ind.size() ==1 && ev_ind[0].size() == 1 && ev_ind[0][0]==-1)//all elements of 1D array (e.g. [-1]) + { + res.dim_y = 0; + res.value = it->value; + res.dim_x = it->dim_x; + temp_attr_val << print_array(res.value, res.dim_x, res.dim_y) <<","; + } + else + { + err << "UNSUPPORTED additional indexes in 1D array: " << ev_ind.size() << " indexes given, dim_x=" << it->dim_x << " dim_y=" << it->dim_y; 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); + events->veclock.readerOut(); + throw err.str(); } - 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 + else if(it->dim_y > 1)//2D array { - res.dim_x = 1; - res.dim_y = 0; - if(ev_ind[0] >= it->dim_y) + //single row of 2D array (e.g. [0] or [0][-1]) + if((ev_ind.size() == 1 || //only first index + (ev_ind.size() == 2 && ev_ind[1].size() == 1 && ev_ind[1][0] == -1)) //or also second index = -1 + && ev_ind[0].size() == 1 && ev_ind[0][0] != -1) // and first index not -1 { - 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); + res.dim_y = 0; + if(ev_ind[0][0] >= it->dim_y) + { + err << "Requested row " << ev_ind[0][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();//start iterator of a row in a vector containing a 2D array + auto vend = it->value.begin();//end iterator of a row in a vector containing a 2D array + advance(vstart,(int)(ev_ind[0][0] * (it->dim_x))); + advance(vend,(int)(ev_ind[0][0]+1) * it->dim_x); + res.value = value_t(vstart,vend); + temp_attr_val << "" << print_array(res.value,res.dim_x,res.dim_y) << ","; } - if(ev_ind[1] >= it->dim_x) + else if((ev_ind.size() == 1 || //only first index + (ev_ind.size() == 2 && ev_ind[1].size() == 1 && ev_ind[1][0] == -1)) //or also second index = -1 + && ev_ind[0].size() > 1)//multiple rows of 2D array (e.g. [0,1,2] or [0,1,2][-1]) { - err << "Requested column " << ev_ind[1] << " is out of bounds with dim_x=" << it->dim_x; - events->veclock.readerOut(); + res.dim_x = it->dim_x; + res.dim_y = ev_ind[0].size(); + + for(auto ei0 : ev_ind[0]) + { + if(ei0 < 0 || ei0 >= it->value.size()) + { + err << "Requested element " << ei0 << " is out of bounds with dim=" << it->value.size(); + temp_attr_val << "[]"; + 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); + } + else + { + auto vstart = it->value.begin();//start iterator of a row in a vector containing a 2D array + auto vend = it->value.begin();//end iterator of a row in a vector containing a 2D array + advance(vstart,(int)(ei0 * (it->dim_x))); + advance(vend,(int)(ei0+1) * it->dim_x); + value_t row = value_t(vstart,vend); + res.value.insert( + res.value.end(), + std::make_move_iterator(row.begin()), + std::make_move_iterator(row.end()) + ); + + } + } + temp_attr_val << print_array(res.value,res.dim_x,res.dim_y) << ","; + } + else if((ev_ind.size() == 1 || //only first index + (ev_ind.size() == 2 && ev_ind[1].size() == 1 && ev_ind[1][0] == -1)) //or also second index = -1 + && ev_ind[0].size() == 1 && ev_ind[0][0] == -1)//all rows of 2D array (e.g. [-1] or [-1][-1]) + { + res.dim_x = it->dim_x; + res.dim_y = it->dim_y; + res.value = it->value; + temp_attr_val << print_array(res.value,res.dim_x,res.dim_y) << ","; + } + else if(ev_ind.size() == 2 && ev_ind[0].size() == 1 && ev_ind[0][0] != -1 && ev_ind[1].size() == 1 && ev_ind[1][0] != -1)//single element of 2D array (e.g. [0][1]) + { + res.dim_x = 1; + res.dim_y = 0; + if(ev_ind[0][0] >= it->dim_y) + { + err << "Requested row " << ev_ind[0][0] << " is out of bounds with dim_y=" << it->dim_y; + temp_attr_val << "[]"; + 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][0] >= it->dim_x) + { + err << "Requested column " << ev_ind[1][0] << " is out of bounds with dim_x=" << it->dim_x; + temp_attr_val << "[]"; + 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][0]*it->dim_x + ev_ind[1][0])};//throw std::out_of_range + temp_attr_val << "[" <<res.value[0] << "],";//throw std::out_of_range + } + else if(ev_ind.size() == 2 && ev_ind[0].size() > 1 && ev_ind[1].size() == 1 && ev_ind[1][0] != -1)//single column slice of 2D array (e.g. [0,1,2][3]) + { + res.dim_x = 1; + long ei1 = ev_ind[1][0]; + if(ei1 >= it->dim_x) + { + err << "Requested column " << ei1 << " is out of bounds with dim_x=" << it->dim_x; + temp_attr_val << "[]"; + 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); + } + for(auto ei0 : ev_ind[0]) + { + if(ei0 < 0 || ei0 >= it->dim_y) + { + err << "Requested row " << ei0 << " is out of bounds with dim_y=" << it->dim_y; + temp_attr_val << "[]"; + 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.push_back(it->value.at(ei0*it->dim_x + ei1));//throw std::out_of_range + } + res.dim_y = ev_ind[0].size(); + temp_attr_val <<print_array(res.value,res.dim_x,res.dim_y) <<","; + } + else if(ev_ind.size() == 2 && ev_ind[0].size() == 1 && ev_ind[0][0] == -1 && ev_ind[1].size() == 1 && ev_ind[1][0] != -1)//single column of 2D array (e.g. [-1][3]) + { + res.dim_x = 1; + long ei1 = ev_ind[1][0]; + if(ei1 >= it->dim_x) + { + err << "Requested column " << ei1 << " is out of bounds with dim_x=" << it->dim_x; + temp_attr_val << "[]"; + 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); + } + for(long ei0 = 0; ei0 < it->dim_y; ei0++) + { + res.value.push_back(it->value.at(ei0*it->dim_x + ei1));//throw std::out_of_range + } + res.dim_y = it->dim_y; + temp_attr_val <<print_array(res.value,res.dim_x,res.dim_y) <<","; + } + else if(ev_ind.size() == 2 && ev_ind[0].size() == 1 && ev_ind[0][0] != -1 && ev_ind[1].size() > 1)//single row slice of 2D array (e.g. [0][1,2,3]) + { + res.dim_y = 0; + long ei0 = ev_ind[0][0]; + if(ei0 >= it->dim_y) + { + err << "Requested row " << ei0 << " is out of bounds with dim_y=" << it->dim_y; + temp_attr_val << "[]"; + 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); + } + for(auto ei1 : ev_ind[1]) + { + if(ei1 < 0 || ei1 >= it->dim_x) + { + err << "Requested column " << ei1 << " is out of bounds with dim_x=" << it->dim_x; + temp_attr_val << "[]"; + 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.push_back(it->value.at(ei0*it->dim_x + ei1));//throw std::out_of_range + } + res.dim_x = ev_ind[1].size(); + temp_attr_val <<print_array(res.value,res.dim_x,res.dim_y) <<","; + } + else if(ev_ind.size() == 2 && ev_ind[0].size() > 1 && ev_ind[1].size() > 1)//subarray of 2D array (e.g. [0,1][2,3]) + { + for(auto ei0 : ev_ind[0]) + { + if(ei0 < 0 || ei0 >= it->dim_y) + { + err << "Requested row " << ei0 << " is out of bounds with dim_y=" << it->dim_y; + temp_attr_val << "[]"; + 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); + } + for(auto ei1 : ev_ind[1]) + { + if(ei1 < 0 || ei1 >= it->dim_x) + { + err << "Requested column " << ei1 << " is out of bounds with dim_x=" << it->dim_x; + temp_attr_val << "[]"; + 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.push_back(it->value.at(ei0*it->dim_x + ei1));//throw std::out_of_range + } + } + res.dim_x = ev_ind[1].size(); + res.dim_y = ev_ind[0].size(); + temp_attr_val <<print_array(res.value,res.dim_x,res.dim_y) <<","; + } + else if(ev_ind.size() == 2 && ev_ind[0].size() == 1 && ev_ind[0][0] == -1 && ev_ind[1].size() > 1)//subarray of 2D array (e.g. [-1][2,3]) + { + for(long ei0 = 0; ei0 < it->dim_y; ei0++) + { + for(auto ei1 : ev_ind[1]) + { + if(ei1 < 0 || ei1 >= it->dim_x) + { + err << "Requested column " << ei1 << " is out of bounds with dim_x=" << it->dim_x; + temp_attr_val << "[]"; + 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.push_back(it->value.at(ei0*it->dim_x + ei1));//throw std::out_of_range + } + } + res.dim_x = ev_ind[1].size(); + res.dim_y = it->dim_y; + temp_attr_val <<print_array(res.value,res.dim_x,res.dim_y) <<","; + } + else //ev_ind.size() > 2 + { + err << "UNSUPPORTED additional indexes in 2D array: " << ev_ind.size() << " indexes given, dim_x=" << it->dim_x << " dim_y=" << it->dim_y; 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); + events->veclock.readerOut(); + throw err.str(); } - 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 { @@ -4944,7 +5269,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values else { res.value = it->value; - temp_attr_val << "\"" << it->name << "\":[" <<print_vector(res.value) << "],"; + temp_attr_val << "\"" << it->name << "\":" <<print_array(res.value,res.dim_x,res.dim_y) << ","; } } else @@ -4977,6 +5302,8 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values formula_res_t res; res.valid = true; res.value = {(strtod(val_d.c_str(), 0))}; + res.dim_x=1; + res.dim_y=0; return res; } else if (i->value.id() == formula_grammar::logical_exprID) @@ -5263,11 +5590,15 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values if (string(i->value.begin(), i->value.end()) == string("!=")) { res.value = {(double)(attr_val != val_string)}; + res.dim_x=1; + res.dim_y=0; return res; } else if (string(i->value.begin(), i->value.end()) == string("==")) { res.value = {(double)(attr_val == val_string)}; + res.dim_x=1; + res.dim_y=0; return res; } else @@ -5369,11 +5700,15 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values { res = eval_expression(i->children.begin(), attr_values); res.value = {(double)res.quality};//ignore values and keep quality as result + res.dim_x=1; + res.dim_y=0; return res; } else if ((string(i->value.begin(), i->value.end()) == string("AND") || string(i->value.begin(), i->value.end()) == string("OR"))) { res = eval_expression(i->children.begin(), attr_values); + res.dim_x=1; + res.dim_y=0; if(string(i->value.begin(), i->value.end()) == string("AND")) { res.value = {(double)std::accumulate(res.value.begin(), res.value.end(), (bool)true, [](bool acc, double n) { return (bool)(acc && (bool)(n));})}; @@ -5383,7 +5718,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values 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; + DEBUG_STREAM << " node funcID("<<string(i->value.begin(), i->value.end())<<") value="<<print_array(res.value,res.dim_x,res.dim_y)<<" quality="<<res.quality<< endl; #endif return res; } @@ -5496,6 +5831,8 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values } formula_res_t res; res.value = {(double)0.0}; + res.dim_x=1; + res.dim_y=0; res.valid = false; return res; } @@ -5686,7 +6023,6 @@ void AlarmHandler::prepare_alarm_attr() time_sec= ai->second.ts.tv_sec; //gmtime_r(&time_sec,&time_tm); //-> UTC localtime_r(&time_sec,&time_tm); - time_buf[64]; strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm); #ifndef ALM_SUM_STR diff --git a/src/AlarmHandler.h b/src/AlarmHandler.h index d8b6007263cb8a37dda7660794787613ea49b381..617337276dec25530ff8cb234b9a25189045cf34 100644 --- a/src/AlarmHandler.h +++ b/src/AlarmHandler.h @@ -607,7 +607,8 @@ 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, vector<double> ev_ind={}); //recursive tree node evaluation + formula_res_t eval_expression(iter_t const& i, string &attr_values, vector< vector<double> > ev_ind={}); //recursive tree node evaluation + void eval_index_range(iter_t const& i, string &attr_values, vector<double> & ind); 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_table.cpp b/src/alarm_table.cpp index 6c1932c1f8cc225a4ce0655b16fee3b6493ea87b..f1a6d45f90f36898b7b65d759eb7f40e227260f2 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] != 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.empty() && 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] != 0); + status_on_delay = (bool)(!res.value.empty() && 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] != 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.empty() && 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] != 0); + status_off_delay = !(bool)(!res.value.empty() && 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] != 0)) + if((bool)(!res.value.empty() && 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[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] != 0)) + if((bool)(!res.value.empty() && 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] != 0)) { + if((bool)(!res.value.empty() && 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 d3701ec44af780ad8a29fb7d9b9f41cdced421a2..7db0b96d43042c2e61482e5013bb82b570c8daba 100644 --- a/src/alarm_table.h +++ b/src/alarm_table.h @@ -45,7 +45,7 @@ #endif //#include "log_thread.h" - +#define MAX_ARRAY_PRINTED_CHARS 1000 #define LOG_STREAM TANGO_LOG using namespace std; @@ -119,12 +119,59 @@ string print_vector(const std::vector<T>& v, const char * const separator = ",") { std::copy(v.begin(), --v.end(), - std::ostream_iterator<T>(out/*std::cout*/, separator)); + std::ostream_iterator<T>(out, separator)); out << v.back(); } return out.str(); } +template <typename T> +string print_array(const std::vector<T>& v, long dim_x, long dim_y, const char * const separator = ",") +{ + ostringstream out; + if(dim_y <1) + { + out <<"["<< print_vector(v); + out.seekp(0, ios::end); + stringstream::pos_type offset = out.tellp(); + if(offset > MAX_ARRAY_PRINTED_CHARS) + { + out.seekp(MAX_ARRAY_PRINTED_CHARS, ios::beg);//limit size + out << "...]" << ends; + } + else + out << "]"; + return out.str(); + } + out << "["; + for(long i=0; i<dim_y; i++) + { + auto vstart = v.begin();//start iterator of a row in a vector containing a 2D array + auto vend = v.begin();//end iterator of a row in a vector containing a 2D array + advance(vstart,(int)(i * (dim_x))); + advance(vend,(int)((i+1) * dim_x)); + value_t row = value_t(vstart,vend); + out <<"["<< print_vector(row); + out.seekp(0, ios::end); + stringstream::pos_type offset = out.tellp(); + if(offset > MAX_ARRAY_PRINTED_CHARS) + { + out.seekp(MAX_ARRAY_PRINTED_CHARS, ios::beg);//limit size + out << "...]]" << ends; + break; + } + else + out << "]"; + if(i < dim_y-1) + { + out << ","; + } + } + + out << "]"; + return out.str(); +} + struct vectorUtils { static double fBitAnd(long a, long b){ return (double)(a & b);} @@ -236,7 +283,12 @@ struct formula_res_t } void extract_result() { - value = {(double)std::accumulate(value.begin(), value.end(), (bool)false, [](bool a, double b) { return (bool)(a || (bool)b); })}; + if(!value.empty()) + { + value = {(double)std::accumulate(value.begin(), value.end(), (bool)false, [](bool a, double b) { return (bool)(a || (bool)b); })}; + dim_x=1; + dim_y=0; + } } formula_res_t operator==(const formula_res_t& e) diff --git a/src/event_table.cpp b/src/event_table.cpp index 2f9f97731dc9670edbc4d958c0c03b45d69ff65b..af8cf4fa6683eb1ae2595bc61028db505e48e8b0 100644 --- a/src/event_table.cpp +++ b/src/event_table.cpp @@ -201,6 +201,8 @@ event::event(string& s, value_t& v, Tango::TimeVal& t) : \ event_id = SUB_ERR; err_counter = 0; valid = false; + dim_x=0; + dim_y=0; } event::event(string& s) : name(s) @@ -222,7 +224,9 @@ event::event(string& s) : name(s) type = -1; event_id = SUB_ERR; err_counter = 0; - valid = false; + valid = false; + dim_x=0; + dim_y=0; } bool event::operator==(const event& e) @@ -289,27 +293,10 @@ void event_table::summary(list<string> &evs) ev_summary << KEY(EVENT_TIME_KEY) << time_buf << SEP; ostringstream tmp_val; - //if(i->valid) - { - tmp_val << "[" ; - if(i->type != Tango::DEV_STRING) - { - if(i->read_size > 0 && i->value.size() > 0) - { - for(size_t k=0; k<i->read_size && k<i->value.size(); k++) - { - tmp_val << i->value[k]; - if(k < i->read_size-1 && k<i->value.size()-1) - tmp_val << ","; - } - } - } - else - { - tmp_val << "\""<<i->value_string<<"\""; - } - tmp_val << "]"; - } + if(i->type != Tango::DEV_STRING) + tmp_val << print_array(i->value,i->dim_x,i->dim_y); + else + tmp_val << "[\""<<i->value_string<<"\"]"; ev_summary << KEY(ATTR_VALUES_KEY) << tmp_val.str() << SEP; ostringstream tmp_ex; //tmp_ex.str(""); @@ -838,6 +825,9 @@ void event_table::add(string &signame, vector<string> contexts, int to_do, bool signal->running = false; signal->stopped = true; signal->paused = false; + signal->valid = false; + signal->dim_x=0; + signal->dim_y=0; //DEBUG_STREAM << "event_table::"<<__func__<<": signame="<<signame<<" created signal"<< endl; } else if(found && start) diff --git a/src/formula_grammar.h b/src/formula_grammar.h index 8a83118f0c19bcd2401af1cfa6fb68bd76fd90c9..54aca74707d3f67681c8ceb6bbffe035e84e1bd3 100644 --- a/src/formula_grammar.h +++ b/src/formula_grammar.h @@ -125,6 +125,8 @@ struct formula_grammar : public grammar<formula_grammar> static const int val_qualityID = 23; static const int val_alarm_enum_stID = 24; static const int propertyID = 25; + static const int index_rangeID = 26; + static const int index_listID = 27; symbols<unsigned int> tango_states; @@ -207,9 +209,18 @@ struct formula_grammar : public grammar<formula_grammar> ] ] // = repeat_p(3)[(+symbol) >> ch_p('/')] >> (+symbol) - ; + ; + index_range + = + ( uint_p >> !(discard_node_d[ch_p('-')] >> uint_p)) // n or n-m + ; + index_list + = (index_range >> *(discard_node_d[ch_p(',')] >> index_range)) // n-m,k,s-t,.. + ; index - = inner_node_d[ch_p('[') >> uint_p >> ch_p(']')] + = discard_node_d[ch_p('[')] >> + (str_p("-1") | index_list) >> + discard_node_d[ch_p(']')] ; property = str_p(".quality") @@ -399,6 +410,8 @@ struct formula_grammar : public grammar<formula_grammar> rule<ScannerT, parser_context<>, parser_tag<expr_atomID> > expr_atom; rule<ScannerT, parser_context<>, parser_tag<funcID> > function; rule<ScannerT, parser_context<>, parser_tag<nameID> > name; + rule<ScannerT, parser_context<>, parser_tag<index_rangeID> > index_range; + rule<ScannerT, parser_context<>, parser_tag<index_listID> > index_list; rule<ScannerT, parser_context<>, parser_tag<indexID> > index; rule<ScannerT, parser_context<>, parser_tag<val_stringID> > val_string; rule<ScannerT, parser_context<>, parser_tag<func_dualID> > function_dual;