diff --git a/src/AlarmHandler.cpp b/src/AlarmHandler.cpp index da9930afb992626a481c80294bd83cd456eb85f0..61b88fb07bcdc8ca8cb32730064160f5bb01ce3d 100644 --- a/src/AlarmHandler.cpp +++ b/src/AlarmHandler.cpp @@ -367,6 +367,7 @@ void AlarmHandler::init_device() internallock = new(ReadersWritersLock); dslock = new(ReadersWritersLock); alarms.set_dev(this); + alarms.set_err_delay(30); //TODO: device property /*----- PROTECTED REGION END -----*/ // AlarmHandler::init_device_before @@ -953,161 +954,6 @@ void AlarmHandler::read_alarm(Tango::Attribute &attr) //DEBUG_STREAM << "AlarmHandler::read_alarm(Tango::Attribute &attr) entering... " << endl; /*----- PROTECTED REGION ID(AlarmHandler::read_alarm) ENABLED START -----*/ // Add your own code here -#if 0 - alarm_container_t::iterator ai; - vector<alarm_t>::iterator aid; - for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) { - if (ai->second.stat == S_ALARM) { - /* - * alarm status is S_ALARM - */ - aid = find(alarmed.begin(), alarmed.end(),ai->second.name); - if (aid != alarmed.end()) { - /* - * found, change stat only if switching from - * S_NORMAL to S_ALARM status - */ - //cout << "read_attr(): S_ALARM: found: " << aid->name << endl; - if (aid->stat == S_NORMAL) { - aid->stat = S_ALARM; - aid->ack = NOT_ACK; - aid->ts = ai->second.ts; - aid->msg = ai->second.msg; - } - aid->grp = ai->second.grp; - aid->lev = ai->second.lev; - aid->is_new = ai->second.is_new; //copy is_new state - //ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0 - aid->counter = ai->second.counter; - aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset - aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary) - aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update - } else { - /* - * not found: new "alarmed" item - */ - DEBUG_STREAM << "read_attr(): S_ALARM: pushing new alarm: " \ - << ai->second.name << "\t" << ai->second.stat << endl; - alarmed.push_back(ai->second); - //ai->second.is_new = 0; //set state as not more new //12-06-08: StopNew command set it to 0 - } - } else if (ai->second.stat == S_NORMAL) { - /* - * alarm status is S_NORMAL - */ - aid = find(alarmed.begin(), alarmed.end(), ai->second.name); - if (aid != alarmed.end()) { - /* - * found, as it should; - * switching from S_ALARM to S_NORMAL - */ - aid->stat = S_NORMAL; - aid->ts = ai->second.ts; - //aid->msg = " "; /* no message again */ - aid->msg =ai->second.msg; - aid->grp = ai->second.grp; - aid->lev = ai->second.lev; - aid->counter = ai->second.counter; - aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset - aid->is_new = ai->second.is_new; //copy is_new state - aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary) - aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update - //ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0 - if (aid->ack == ACK) { - if (aid->done) { - /* - * if already ACKnowledged and visualized - * remove from "alarmed" list - */ - DEBUG_STREAM << "read_attr(): S_NORMAL: " << aid->name \ - << " ACKnowledged: removing" << endl; - alarmed.erase(aid); - } else { - aid->done = true; - } - } /* if */ - } /* if */ - } /* if else if */ - } /* for */ - - vector<string> tmp_alarm_table; - string is_new; - ostringstream os1; - /*os1.clear(); - os1 << header << "\t" << alarmed.size() << ends;*/ - //tmp_alarm_table.push_back(os1.str()); - if (alarmed.empty() == false) { - for (aid = alarmed.begin(); aid != alarmed.end(); aid++) { - if(aid->silenced > 0) - { - Tango::TimeVal now = gettime(); - double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000; - double dsilent = aid->ts_time_silenced.tv_sec + ((double)aid->ts_time_silenced.tv_usec) / 1000000; - double dminutes = (dnow - dsilent)/60; - //silenced already calculated in alarm_table::update, but here updated for panel also if state not changed: - //to see minutes countdown - if(dminutes < aid->silent_time) - aid->silenced = aid->silent_time - floor(dminutes); - else - aid->silenced = 0; - } - ostringstream os; - os.clear(); - is_new.clear(); - is_new = (aid->is_new && aid->silenced <= 0) ? "NEW" : " "; - os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \ - << aid->name << "\t" << aid->stat << "\t" << aid->ack \ - << "\t" << aid->counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new << ends; - tmp_alarm_table.push_back(os.str()); - } - } - if (internal.empty() == false) { - for (aid = internal.begin(); aid != internal.end(); aid++) { - -/* size_t index; - int count = 1; - index = aid->stat.find("*"); - if((index != std::string::npos) && (index+1 != std::string::npos)) - { - - size_t last = aid->stat.size(); - string str_count= aid->stat.substr(index+1, last - index+1); - count = strtol(str_count.c_str(), 0,10); - } - //do not show internal alarms that have a molteplicity less then errThreshold - if((aid->msg.find()) && (count < errThreshold)) - continue;*/ - - ostringstream os; - os.clear(); - os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \ - << aid->name << "\t" << aid->stat << "\t" << aid->ack \ - << "\t" << aid->counter << "\t" << aid->lev << "\t"<< -1/*silenced*/ <<"\t" << aid->grp2str() << "\t" << aid->msg << "\t "<< ends; //TODO: silenced for internal errors? - tmp_alarm_table.push_back(os.str()); - } - } - int i; - for (i = ds_num - 1; i >= 0; i--) { - CORBA::string_free(ds[i]); - } - ds_num = tmp_alarm_table.size(); - if(ds_num > MAX_ALARMS) - ds_num = MAX_ALARMS; - for (i = 0; i < ds_num; i++) { - ds[i] = CORBA::string_dup(tmp_alarm_table[i].c_str()); - } - if(ds_num == 0) - { - ostringstream os1; - ds_num++; - os1.clear(); - os1 << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << -1 << "\t" << 0 << "\t" << 0 << "\t "<< ends; - ds[0] = CORBA::string_dup(os1.str().c_str()); - } -#else - //bool changed; - //prepare_alarm_attr(changed);//moved in do_alarm; -#endif if(ds_num == 0) { attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); @@ -1325,16 +1171,19 @@ void AlarmHandler::read_AlarmState(Tango::Attribute &attr) break; } } + bool error; if(it != alarms.v_alarm.end()) { reason = it->second.ex_reason; desc = it->second.ex_desc; origin = it->second.ex_origin; quality = it->second.quality; + error = it->second.error; } DEBUG_STREAM << "AlarmHandler::read_AlarmState: " << attr.get_name() << " desc=" << desc << endl; alarms.vlock->readerOut(); - if(desc.length() > 0) + if(error) //TODO: if needs to be considered err_delay also in single alarm attributes, error must be used + //if(desc.length() > 0) { Tango::Except::throw_exception( reason, @@ -1485,7 +1334,7 @@ void AlarmHandler::ack(const Tango::DevVarStringArray *argin) *attr_value = _RTNUN; try { //DevFailed for push events - if(localv_alarm.ex_reason.length() == 0) + if(localv_alarm.ex_reason.empty()) { timeval now; gettimeofday(&now, NULL); @@ -2534,7 +2383,7 @@ void AlarmHandler::shelve(const Tango::DevVarStringArray *argin) *attr_value = _SHLVD; try { //DevFailed for push events - if(alm.ex_reason.length() == 0) + if(alm.ex_reason.empty()) { timeval now; gettimeofday(&now, NULL); @@ -2649,7 +2498,7 @@ void AlarmHandler::enable(Tango::DevString argin) *attr_value = _RTNUN; try { //DevFailed for push events - if(alm.ex_reason.length() == 0) + if(alm.ex_reason.empty()) { timeval now; gettimeofday(&now, NULL); @@ -2756,7 +2605,7 @@ void AlarmHandler::disable(Tango::DevString argin) *attr_value = _OOSRV; try { //DevFailed for push events - if(alm.ex_reason.length() == 0) + if(alm.ex_reason.empty()) { timeval now; gettimeofday(&now, NULL); @@ -2995,7 +2844,7 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString ostringstream tmp_ex; tmp_ex.str(""); - if(it->second.ex_reason.length() > 0 || it->second.ex_desc.length() > 0 || it->second.ex_origin.length() > 0) + if(it->second.error) { tmp_ex << "{\"Reason\":\"" << it->second.ex_reason << "\",\"Desc\":\"" << it->second.ex_desc << "\",\"Origin\":\"" << it->second.ex_origin << "\"}"; info.insert(make_pair(VALUE_KEY,string("ERROR"))); @@ -3195,6 +3044,8 @@ void AlarmHandler::load_alarm(string alarm_string, alarm_t &alm, vector<string> alm.ex_reason=string("NOT_SUBSCRIBED"); alm.ex_desc=string("One or more events not subscribed"); alm.ex_origin.clear(); + alm.error = false; + alm.err_counter = 0; alm.formula.clear(); alm.msg.clear(); alm.lev.clear(); @@ -3611,10 +3462,12 @@ void AlarmHandler::do_alarm(bei_t& e) alarm_container_t::iterator it = alarms.v_alarm.find(*j); if(it != alarms.v_alarm.end()) { + it->second.err_counter++; //if first error, reset ACK - if(it->second.ex_reason.empty() && it->second.ex_desc.empty() || it->second.ex_origin.empty()) + if(it->second.ex_reason.empty() && it->second.ex_desc.empty() && it->second.ex_origin.empty()) { it->second.ack = NOT_ACK; + it->second.ts_err_delay = gettime(); //first occurrance of this error, now begin to wait for err delay } if(e.type == TYPE_TANGO_ERR) it->second.ex_reason = found_ev->ex_reason; @@ -3622,6 +3475,15 @@ void AlarmHandler::do_alarm(bei_t& e) it->second.ex_reason = found_ev->ex_reason; it->second.ex_desc = found_ev->ex_desc; it->second.ex_origin = found_ev->ex_origin; + if(alarms.err_delay > 0) + { + if((it->second.ts.tv_sec - alarms.err_delay) > it->second.ts_err_delay.tv_sec) //error is present and err delay has passed + it->second.error = true; + } + else + { + it->second.error = true; + } alarm_t alm = it->second; alarms.vlock->readerOut(); try @@ -3834,7 +3696,8 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal string ex_reason = it->second.ex_reason; string ex_desc = it->second.ex_desc; string ex_origin = it->second.ex_origin; - if(ex_reason.length() > 0 || ex_desc.length() > 0 || ex_origin.length() > 0) + prev_error = it->second.error; + if(prev_error) { prev_error = true; DEBUG_STREAM << "AlarmHandler::"<<__func__<<": before evaluating exception {"<<ex_reason<<","<<ex_desc.length()<<","<<ex_origin<<"}"<<endl; @@ -3869,7 +3732,7 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal alarms.vlock->readerOut(); //Don't hold alarms lock while pushing events to prevent deadlocks try { //DevFailed for push events - if(ex_reason.length() == 0) + if(!it->second.error) { timeval now; gettimeofday(&now, NULL); @@ -5137,7 +5000,7 @@ void AlarmHandler::prepare_alarm_attr() ostringstream tmp_ex; //tmp_ex.str(""); - if(ai->second.ex_reason.length() > 0 || ai->second.ex_desc.length() > 0 || ai->second.ex_origin.length() > 0) + if(ai->second.error) { tmp_ex << "{\"Reason\":\"" << ai->second.ex_reason << "\",\"Desc\":\"" << ai->second.ex_desc << "\",\"Origin\":\"" << ai->second.ex_origin << "\"}"; DEBUG_STREAM << __func__ << ": " << ai->first << " -> " << tmp_ex.str(); @@ -5291,7 +5154,7 @@ void AlarmHandler::prepare_alarm_attr() * S_NORMAL to S_ALARM status */ //cout << "read_attr(): S_ALARM: found: " << aid->name << endl; - if (aid->stat == S_NORMAL) { + if (aid->stat == S_NORMAL || aid->stat == S_ERROR) { aid->stat = S_ALARM; aid->ack = NOT_ACK; aid->ts = ai->second.ts; @@ -5389,7 +5252,7 @@ void AlarmHandler::prepare_alarm_attr() os1 << header << "\t" << alarmed.size() << ends;*/ //tmp_alarm_table.push_back(os1.str()); alarmedlock->readerIn(); - if (alarmed.empty() == false) { + if (!alarmed.empty()) { for (aid = alarmed.begin(); aid != alarmed.end(); aid++) { if(aid->silenced > 0) { diff --git a/src/alarm_table.cpp b/src/alarm_table.cpp index fc57f582431d4a419990b16f4cd685e127c5ce28..65322f6ae8f70b39e5d1d94ccd8332e8f3d54ffc 100644 --- a/src/alarm_table.cpp +++ b/src/alarm_table.cpp @@ -363,6 +363,11 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_ found->second.ack = ACK; } } + bool status_err_delay; + if(err_delay > 0) + status_err_delay = (!res.ex_reason.empty() || !res.ex_desc.empty() || !res.ex_origin.empty()) && (found->second.err_counter >= 1) && ((ts.tv_sec - err_delay) > found->second.ts_err_delay.tv_sec); //error is present and err delay has passed + else + status_err_delay = (!res.ex_reason.empty() || !res.ex_desc.empty() || !res.ex_origin.empty()); found->second.quality = res.quality; found->second.ex_reason = res.ex_reason; found->second.ex_desc = res.ex_desc; @@ -490,6 +495,16 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_ else if (status_off_delay) { found->second.stat = S_NORMAL; } + //if error changed: + // - from false to true considering also err delay + //or + // - from true to false + if((status_err_delay && !found->second.error) || (!status_err_delay)) + { + ret_changed=true; + } + if(status_err_delay) + found->second.error = true; if((bool)(res.value != 0)) { found->second.on_counter++; @@ -498,6 +513,15 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_ found->second.on_counter = 0; found->second.off_counter++; } + if(!found->second.ex_reason.empty() || !found->second.ex_desc.empty() || !found->second.ex_origin.empty()) + { + found->second.err_counter++; + } + else + { + found->second.err_counter = 0; + found->second.error = false; + } found->second.attr_values_delay = attr_values; //save last attr_values to be used in timer_update if this alarm pass over on or off delay @@ -505,7 +529,8 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_ found->second.ts_on_delay = gettime(); //first occurrance of this alarm, now begin to wait for on delay if(found->second.off_counter == 1) found->second.ts_off_delay = gettime(); //first occurrance of back to normal, now begin to wait for off delay - + if(found->second.err_counter == 1) + found->second.ts_err_delay = gettime(); //first occurrance of this error, now begin to wait for err delay //found->second.ts = ts; /* store event timestamp into alarm timestamp */ //here update ts everytime } else { /* @@ -530,7 +555,11 @@ bool alarm_table::timer_update() { bool status_on_delay=false; bool status_off_delay=false; - if(i->second.on_delay == 0 && i->second.off_delay == 0 && !i->second.shelved && i->second.silenced <=0) + bool status_err_delay=false; + if(err_delay > 0) //if enabled off delay + status_err_delay = (i->second.err_counter >= 1) && ((ts.tv_sec - err_delay) > i->second.ts_err_delay.tv_sec); //waiting for err delay has passed + + if(i->second.on_delay == 0 && i->second.off_delay == 0 && err_delay == 0 && !i->second.shelved && i->second.silenced <=0) continue; //if not enabled on or off delay or not shelved, nothing to do in timer if(i->second.on_delay > 0) //if enabled on delay status_on_delay = (i->second.on_counter >= 1) && ((ts.tv_sec - i->second.on_delay) > i->second.ts_on_delay.tv_sec); //waiting for on delay has passed @@ -563,7 +592,6 @@ bool alarm_table::timer_update() if(old_silenced>0 && i->second.silenced == 0) { ret_changed = true; - } //if status changed: // - from S_NORMAL to S_ALARM considering also on delay @@ -571,7 +599,7 @@ bool alarm_table::timer_update() // - from S_ALARM to S_NORMAL considering also off delay //or // - from shelved to not shelved - if((status_on_delay && (i->second.stat == S_NORMAL)) || (status_off_delay && (i->second.stat == S_ALARM)) || (old_shelved && !i->second.shelved)) + if((status_on_delay && (i->second.stat == S_NORMAL)) || (status_off_delay && (i->second.stat == S_ALARM)) || (old_shelved && !i->second.shelved) || (status_err_delay && !i->second.error)) { if(old_shelved && !i->second.shelved) //TODO: ok to execute on command and off command after shelving ends? { @@ -579,6 +607,10 @@ bool alarm_table::timer_update() status_off_delay = i->second.stat == S_NORMAL; } ret_changed = true; + if(status_err_delay) + { + i->second.error = true; + } if(status_on_delay) i->second.ack = NOT_ACK; //if changing from NORMAL to ALARM but not ended shelved time -> NACK @@ -697,7 +729,7 @@ bool alarm_table::timer_update() *(i->second.attr_value) = _RTNUN; try { - if(i->second.ex_reason.length() == 0) + if(!i->second.error) { timeval now; gettimeofday(&now, NULL); diff --git a/src/alarm_table.h b/src/alarm_table.h index 5cdf5514bbe729bad8b7146b5c53fb9469a6ca3b..46dddf5e6fbc4ac0d9d0165700e03acb9264bd5f 100644 --- a/src/alarm_table.h +++ b/src/alarm_table.h @@ -276,10 +276,12 @@ class alarm_t { Tango::TimeVal ts; string stat, ack; + bool error; bool enabled; bool shelved; unsigned int on_counter; unsigned int off_counter; + unsigned int err_counter; unsigned int freq_counter; tree_parse_info_t formula_tree; @@ -297,6 +299,7 @@ class alarm_t { unsigned int on_delay; //TODO: seconds, is it enough precision? Tango::TimeVal ts_off_delay; //says when it returned normal status unsigned int off_delay; //TODO: seconds, is it enough precision? + Tango::TimeVal ts_err_delay; //says when it has gone in error status for the first time Tango::TimeVal ts_time_silenced; //says when it has been silenced int silent_time; //minutes max to be silent @@ -366,10 +369,12 @@ class alarm_table { void get_alarm_list_db(vector<string> &al_list, map<string, string> &saved_alarms); void init_cmdthread(); void stop_cmdthread(); - Tango::TimeVal startup_complete; //to disable action execution at startup - + Tango::TimeVal startup_complete; //to disable action execution at startup + void set_err_delay(unsigned int delay){err_delay=delay;}; + unsigned int err_delay; //TODO: private protected: private: + Tango::DeviceImpl* mydev; log_thread *logloop; cmd_thread *cmdloop;