Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • cs/ds/alarm-handler
  • francesco.tripaldi/alarm-handler
2 results
Show changes
Showing
with 3132 additions and 1015 deletions
docs/images/alarm_ng.png

206 KiB

docs/images/alarm_ng_history.png

78.6 KiB

docs/images/alarm_notify_properties.png

11.7 KiB

docs/images/free_properties.png

68.8 KiB

......@@ -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"
......@@ -68,6 +69,7 @@ using namespace boost::spirit::classic;
#include <cassert>
#endif //_DUMP_TREE_XML
#include <sstream>
#include <regex>
std::map<parser_id, std::string> rule_names; //only for log messages
......@@ -108,6 +110,7 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.29 $";
// ResetStatistics | reset_statistics
// StopNew | stop_new
// GetAlarmInfo | get_alarm_info
// ReLoadAll | re_load_all
//================================================================
//================================================================
......@@ -126,6 +129,9 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.29 $";
// alarmList | Tango::DevString Spectrum ( max = 10000)
// alarmFrequency | Tango::DevDouble Spectrum ( max = 10000)
// alarmSummary | Tango::DevString Spectrum ( max = 10000)
// eventList | Tango::DevString Spectrum ( max = 10000)
// eventSummary | Tango::DevString Spectrum ( max = 10000)
// alarmDisabled | Tango::DevString Spectrum ( max = 10000)
//================================================================
namespace AlarmHandler_ns
......@@ -191,6 +197,7 @@ void AlarmHandler::delete_device()
DEBUG_STREAM << __func__ << " starting="<<(int)starting << " shutting_down="<<(int)shutting_down<<" restarting="<<(int)restarting;
abortflag = true;
updateloop->signal();
DEBUG_STREAM << "AlarmHandler::delete_device(): after abortflag=true..." << endl;
try {
events->unsubscribe_events();
......@@ -209,10 +216,15 @@ void AlarmHandler::delete_device()
if(!shutting_down && !restarting)
alarms.del_rwlock(); //otherwise moved in alarm_table destructor
alarms.stop_cmdthread();
sleep(1); //wait for alarm_thread and log_thread to exit
//delete almloop;
events->stop_thread();
usleep(50000);
DEBUG_STREAM << "AlarmHandler::delete_device(): stopped alarm and log threads!" << endl;
delete events;
thread->join(nullptr);
sleep(1); //wait for alarm_thread, update_thread and log_thread to exit
//delete almloop;
DEBUG_STREAM << "AlarmHandler::delete_device(): deleted events" << endl;
//delete proxy for actions
for(alarm_container_t::iterator i = alarms.v_alarm.begin(); i!=alarms.v_alarm.end(); i++)
......@@ -254,7 +266,6 @@ void AlarmHandler::delete_device()
* clear all data structures
*/
alarms.v_alarm.clear();
events->v_event.clear();
evlist.clear();
/* for (int i = ds_num - 1; i >= 0; i--) {
CORBA::string_free(ds[i]);
......@@ -311,10 +322,10 @@ void AlarmHandler::delete_device()
*/
alarmed.clear();
delete alarmedlock;
delete savedlock;
delete internallock;
delete dslock;
delete events;
instanceCounter--;
//Tango::leavefunc();
delete prepare_alm_mtx;
......@@ -331,6 +342,9 @@ void AlarmHandler::delete_device()
delete[] attr_alarmList_read;
delete[] attr_alarmFrequency_read;
delete[] attr_alarmSummary_read;
delete[] attr_eventList_read;
delete[] attr_eventSummary_read;
delete[] attr_alarmDisabled_read;
}
//--------------------------------------------------------
......@@ -359,12 +373,13 @@ void AlarmHandler::init_device()
if(instanceCounter > 1)
{
ERROR_STREAM << "More than one instance in the same executable of Alarm Server is not allowed!!" << endl;
cout << "ERROR: second instance of Alarm Server, exiting..." << endl;
TANGO_LOG << "ERROR: second instance of Alarm Server, exiting..." << endl;
exit(-1);
} //-------------------------------------------
alarmedlock = new(ReadersWritersLock);
internallock = new(ReadersWritersLock);
dslock = new(ReadersWritersLock);
savedlock = new(ReadersWritersLock);
alarms.set_dev(this);
/*----- PROTECTED REGION END -----*/ // AlarmHandler::init_device_before
......@@ -385,6 +400,9 @@ void AlarmHandler::init_device()
attr_alarmList_read = new Tango::DevString[10000];
attr_alarmFrequency_read = new Tango::DevDouble[10000];
attr_alarmSummary_read = new Tango::DevString[10000];
attr_eventList_read = new Tango::DevString[10000];
attr_eventSummary_read = new Tango::DevString[10000];
attr_alarmDisabled_read = new Tango::DevString[10000];
/*----- PROTECTED REGION ID(AlarmHandler::init_device) ENABLED START -----*/
/* for(size_t i=0; i<MAX_ALARMS; i++)
{
......@@ -398,6 +416,8 @@ void AlarmHandler::init_device()
alarmSummary_read[i].resize(MAX_ATTR_SUMMARY);
}*/
// Initialize device
alarms.set_al_qual(setAlarmQuality);
alarms.set_err_delay(errorDelay);
thread->period = subscribeRetryPeriod;
#ifdef _USE_ELETTRA_DB_RW
......@@ -471,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
......@@ -501,11 +523,11 @@ void AlarmHandler::init_device()
}
}*/
try {
alarms.get_alarm_list_db(tmp_alm_vec, saved_alarms);
alarms.get_alarm_list_db(tmp_alm_vec, saved_alarms, savedlock);//holds write locks savedlock
} catch(string & e)
{
ERROR_STREAM << "AlarmHandler::init_device(): " << e << endl;
cout << "Error: " << e << ". Exiting..." << endl;
TANGO_LOG << "Error: " << e << ". Exiting..." << endl;
exit(-4);
}
......@@ -614,6 +636,8 @@ void AlarmHandler::init_device()
for(alarm_container_t::iterator i = alarms.v_alarm.begin(); \
i!=alarms.v_alarm.end(); i++)
{
if(!i->second.enabled)
i->second.ts_time_silenced = gettime(); //TODO: save time when alarm was disabled
if(i->second.cmd_name_a.length() > 0)
{
try {
......@@ -705,7 +729,7 @@ void AlarmHandler::init_device()
find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end())
{
k->pop_alarm(i->second.name); //remove alarm/formula just added to event
k->m_alarm.pop(i->second.name); //remove alarm/formula just added to event
DEBUG_STREAM << "AlarmHandler::init_device(): Removed!!!! alarm=" << i->second.name << " from event=" << *j << endl;
if(k->m_alarm.empty())
{
......@@ -733,7 +757,7 @@ void AlarmHandler::init_device()
}
}
set_change_event("alarm",true,false);
set_change_event("alarm",true,true);
/*
* create alarm processing thread
*/
......@@ -805,6 +829,8 @@ void AlarmHandler::get_device_property()
dev_prop.push_back(Tango::DbDatum("GroupNames"));
dev_prop.push_back(Tango::DbDatum("SubscribeRetryPeriod"));
dev_prop.push_back(Tango::DbDatum("StatisticsTimeWindow"));
dev_prop.push_back(Tango::DbDatum("ErrorDelay"));
dev_prop.push_back(Tango::DbDatum("SetAlarmQuality"));
// is there at least one property to be read ?
if (dev_prop.size()>0)
......@@ -852,6 +878,28 @@ void AlarmHandler::get_device_property()
// And try to extract StatisticsTimeWindow value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> statisticsTimeWindow;
// Try to initialize ErrorDelay from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> errorDelay;
else {
// Try to initialize ErrorDelay from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> errorDelay;
}
// And try to extract ErrorDelay value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> errorDelay;
// Try to initialize SetAlarmQuality from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> setAlarmQuality;
else {
// Try to initialize SetAlarmQuality from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> setAlarmQuality;
}
// And try to extract SetAlarmQuality value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> setAlarmQuality;
}
/*----- PROTECTED REGION ID(AlarmHandler::get_device_property_after) ENABLED START -----*/
......@@ -927,7 +975,7 @@ void AlarmHandler::read_alarmAudible(Tango::Attribute &attr)
//--------------------------------------------------------
void AlarmHandler::read_StatisticsResetTime(Tango::Attribute &attr)
{
DEBUG_STREAM << "AlarmHandler::read_StatisticsResetTime(Tango::Attribute &attr) entering... " << endl;
//DEBUG_STREAM << "AlarmHandler::read_StatisticsResetTime(Tango::Attribute &attr) entering... " << endl;
/*----- PROTECTED REGION ID(AlarmHandler::read_StatisticsResetTime) ENABLED START -----*/
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
......@@ -949,169 +997,16 @@ void AlarmHandler::read_StatisticsResetTime(Tango::Attribute &attr)
//--------------------------------------------------------
void AlarmHandler::read_alarm(Tango::Attribute &attr)
{
DEBUG_STREAM << "AlarmHandler::read_alarm(Tango::Attribute &attr) entering... " << endl;
//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
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
attr.set_value(ds, ds_num, 0, false);
/*----- PROTECTED REGION END -----*/ // AlarmHandler::read_alarm
......@@ -1289,13 +1184,69 @@ void AlarmHandler::read_alarmFrequency(Tango::Attribute &attr)
//--------------------------------------------------------
void AlarmHandler::read_alarmSummary(Tango::Attribute &attr)
{
DEBUG_STREAM << "AlarmHandler::read_alarmSummary(Tango::Attribute &attr) entering... " << endl;
//DEBUG_STREAM << "AlarmHandler::read_alarmSummary(Tango::Attribute &attr) entering... " << endl;
/*----- PROTECTED REGION ID(AlarmHandler::read_alarmSummary) ENABLED START -----*/
// Set the attribute value
attr.set_value(attr_alarmSummary_read, alarmSummary_sz);
/*----- PROTECTED REGION END -----*/ // AlarmHandler::read_alarmSummary
}
//--------------------------------------------------------
/**
* Read attribute eventList related method
* Description: List of all subscribed attributes
*
* Data type: Tango::DevString
* Attr type: Spectrum max = 10000
*/
//--------------------------------------------------------
void AlarmHandler::read_eventList(Tango::Attribute &attr)
{
//DEBUG_STREAM << "AlarmHandler::read_eventList(Tango::Attribute &attr) entering... " << endl;
/*----- PROTECTED REGION ID(AlarmHandler::read_eventList) ENABLED START -----*/
prepare_event_list();
// Set the attribute value
attr.set_value(attr_eventList_read, eventList_sz);
/*----- PROTECTED REGION END -----*/ // AlarmHandler::read_eventList
}
//--------------------------------------------------------
/**
* Read attribute eventSummary related method
* Description:
*
* Data type: Tango::DevString
* Attr type: Spectrum max = 10000
*/
//--------------------------------------------------------
void AlarmHandler::read_eventSummary(Tango::Attribute &attr)
{
//DEBUG_STREAM << "AlarmHandler::read_eventSummary(Tango::Attribute &attr) entering... " << endl;
/*----- PROTECTED REGION ID(AlarmHandler::read_eventSummary) ENABLED START -----*/
prepare_event_summary();
// Set the attribute value
attr.set_value(attr_eventSummary_read, eventSummary_sz);
/*----- PROTECTED REGION END -----*/ // AlarmHandler::read_eventSummary
}
//--------------------------------------------------------
/**
* Read attribute alarmDisabled related method
* Description: List of alarms in out of service or shelved state
*
* Data type: Tango::DevString
* Attr type: Spectrum max = 10000
*/
//--------------------------------------------------------
void AlarmHandler::read_alarmDisabled(Tango::Attribute &attr)
{
//DEBUG_STREAM << "AlarmHandler::read_alarmDisabled(Tango::Attribute &attr) entering... " << endl;
/*----- PROTECTED REGION ID(AlarmHandler::read_alarmDisabled) ENABLED START -----*/
// Set the attribute value
attr.set_value(attr_alarmDisabled_read, alarmDisabled_sz);
/*----- PROTECTED REGION END -----*/ // AlarmHandler::read_alarmDisabled
}
//--------------------------------------------------------
/**
......@@ -1308,7 +1259,7 @@ void AlarmHandler::read_alarmSummary(Tango::Attribute &attr)
//--------------------------------------------------------
void AlarmHandler::read_AlarmState(Tango::Attribute &attr)
{
DEBUG_STREAM << "AlarmHandler::read_AlarmState(Tango::Attribute &attr) entering... " << endl;
//DEBUG_STREAM << "AlarmHandler::read_AlarmState(Tango::Attribute &attr) entering... " << endl;
Tango::DevEnum *att_value = get_AlarmState_data_ptr(attr.get_name());
/*----- PROTECTED REGION ID(AlarmHandler::read_AlarmState) ENABLED START -----*/
string reason("");
......@@ -1324,16 +1275,25 @@ void AlarmHandler::read_AlarmState(Tango::Attribute &attr)
break;
}
}
bool error=false;
bool enabled=true;
bool shelved=false;
int silenced=0;
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;
enabled = it->second.enabled;
shelved = it->second.shelved;
silenced = it->second.silenced;
}
DEBUG_STREAM << "AlarmHandler::read_AlarmState: " << attr.get_name() << " desc=" << desc << endl;
alarms.vlock->readerOut();
if(desc.length() > 0)
if(error && enabled && !(shelved && silenced >0)) //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,
......@@ -1341,7 +1301,7 @@ void AlarmHandler::read_AlarmState(Tango::Attribute &attr)
origin, Tango::ERR);
}
// Set the attribute value
if(quality != Tango::ATTR_VALID)
if(quality != Tango::ATTR_VALID && setAlarmQuality)
{
timeval now;
gettimeofday(&now, NULL);
......@@ -1365,7 +1325,7 @@ void AlarmHandler::read_AlarmState(Tango::Attribute &attr)
//--------------------------------------------------------
void AlarmHandler::read_AlarmFormula(Tango::Attribute &attr)
{
DEBUG_STREAM << "AlarmHandler::read_AlarmFormula(Tango::Attribute &attr) entering... " << endl;
//DEBUG_STREAM << "AlarmHandler::read_AlarmFormula(Tango::Attribute &attr) entering... " << endl;
Tango::DevString *att_value = get_AlarmFormula_data_ptr(attr.get_name());
/*----- PROTECTED REGION ID(AlarmHandler::read_AlarmFormula) ENABLED START -----*/
// Set the attribute value
......@@ -1430,6 +1390,7 @@ void AlarmHandler::ack(const Tango::DevVarStringArray *argin)
vector<string> str;
str << (*argin);
vector<string>::iterator si;
alarm_t localalarmed, localv_alarm;
for (si = str.begin(); si != str.end(); si++) {
alarms.vlock->readerIn();
......@@ -1454,57 +1415,73 @@ void AlarmHandler::ack(const Tango::DevVarStringArray *argin)
alarms.vlock->readerOut();
continue;
}
//update alarm ack in alarm table
i->second.ack = ACK;
//update alarm status from alarm table
found->stat = i->second.stat;
if(found->ack == NOT_ACK)
localalarmed = *found; //NOTE: copy before updating ack
localv_alarm = i->second;
//update alarm ack in alarmed table
found->ack = ACK;
alarmedlock->readerOut();
alarms.vlock->readerOut();
if(localalarmed.ack == NOT_ACK)
{
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(i->second.attr_name);
if(!i->second.enabled)
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(localv_alarm.attr_name);
if(!localv_alarm.enabled)
*attr_value = _OOSRV;
else if(i->second.shelved && i->second.silenced > 0)
else if(localv_alarm.shelved && localv_alarm.silenced > 0)
*attr_value = _SHLVD;
else if((i->second.stat == S_NORMAL) && i->second.ack == ACK)
else if((localv_alarm.stat == S_NORMAL) && localv_alarm.ack == ACK)
*attr_value = _NORM;
else if((i->second.stat == S_ALARM) && i->second.ack == NOT_ACK)
else if((localv_alarm.stat == S_ALARM) && localv_alarm.ack == NOT_ACK)
*attr_value = _UNACK;
else if((i->second.stat == S_ALARM) && i->second.ack == ACK)
else if((localv_alarm.stat == S_ALARM) && localv_alarm.ack == ACK)
*attr_value = _ACKED;
else if((i->second.stat == S_NORMAL) && i->second.ack == NOT_ACK)
else if((localv_alarm.stat == S_NORMAL) && localv_alarm.ack == NOT_ACK)
*attr_value = _RTNUN;
try
{ //DevFailed for push events
if(i->second.ex_reason.length() == 0)
if(!localv_alarm.error || !localv_alarm.enabled || (localv_alarm.shelved && localv_alarm.silenced > 0))
{
timeval now;
gettimeofday(&now, NULL);
push_change_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
push_archive_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
if(setAlarmQuality)
{
push_change_event(localv_alarm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)localv_alarm.quality, 1/*size*/, 0, false);
push_archive_event(localv_alarm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)localv_alarm.quality, 1/*size*/, 0, false);
}
else
{
push_change_event(localv_alarm.attr_name,(Tango::DevEnum *)attr_value);
push_archive_event(localv_alarm.attr_name,(Tango::DevEnum *)attr_value);
}
}
else
{
Tango::DevErrorList errors(1);
errors.length(1);
errors[0].desc = CORBA::string_dup(i->second.ex_desc.c_str());
errors[0].desc = CORBA::string_dup(localv_alarm.ex_desc.c_str());
errors[0].severity = Tango::ERR;
errors[0].reason = CORBA::string_dup(i->second.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(i->second.ex_origin.c_str());
errors[0].reason = CORBA::string_dup(localv_alarm.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(localv_alarm.ex_origin.c_str());
Tango::DevFailed except(errors);
push_change_event(i->second.attr_name, &except);
push_archive_event(i->second.attr_name, &except);
push_change_event(localv_alarm.attr_name, &except);
push_archive_event(localv_alarm.attr_name, &except);
}
} catch(Tango::DevFailed & ex)
{
WARN_STREAM << "AlarmHandler::"<<__func__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
}
}
found->ack = ACK;
}
alarmedlock->readerOut();
alarms.vlock->readerOut();
else //not found in alarmed
{
alarmedlock->readerOut();
alarms.vlock->readerOut();
}
}
/*
* remove S_NORMAL status ACKnowledged alarms
......@@ -1532,6 +1509,7 @@ void AlarmHandler::ack(const Tango::DevVarStringArray *argin)
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -1540,6 +1518,7 @@ void AlarmHandler::ack(const Tango::DevVarStringArray *argin)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -1554,7 +1533,8 @@ void AlarmHandler::ack(const Tango::DevVarStringArray *argin)
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -1565,7 +1545,8 @@ void AlarmHandler::ack(const Tango::DevVarStringArray *argin)
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0],alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
......@@ -1589,6 +1570,7 @@ void AlarmHandler::load(Tango::DevString argin)
DEBUG_STREAM << "AlarmHandler::Load() - " << device_name << endl;
/*----- PROTECTED REGION ID(AlarmHandler::load) ENABLED START -----*/
// Add your own code
DEBUG_STREAM << "AlarmHandler::LOAD ENTERING alm=" << argin << endl;
string s;
alarm_t alm;
vector<string> evn;
......@@ -1597,7 +1579,7 @@ void AlarmHandler::load(Tango::DevString argin)
//std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase
Tango::TimeVal ts = gettime();
try {
load_alarm(s, alm, evn);
load_alarm(s, alm, evn);//doesn't hold locks
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -1610,8 +1592,8 @@ void AlarmHandler::load(Tango::DevString argin)
}
try {
add_alarm(alm);
} catch (string& err) {
add_alarm(alm);//holds alarm writer lock + reader lock
} catch (string& err) { //TODO: not throwing string exception
WARN_STREAM << "AlarmHandler::load(): " << err << endl;
Tango::Except::throw_exception( \
(const char*)"AlarmHandler::load()", \
......@@ -1647,18 +1629,23 @@ void AlarmHandler::load(Tango::DevString argin)
(const char*)"AlarmHandler::load()", Tango::ERR);
}
#endif
#if 0//already saved attribute property by subscribe thread
alarms.save_alarm_conf_db(alm.attr_name, alm.name, "", "", alm.enabled, //add new alarm on log before subscribe event
alm.formula, alm.on_delay, alm.off_delay, alm.grp2str(), alm.lev, alm.msg, alm.cmd_name_a, alm.cmd_name_n, alm.silent_time); //but if it fails remove it from table
alm.formula, alm.on_delay, alm.off_delay, alm.grp2str(), alm.lev, alm.msg, alm.url, alm.cmd_name_a, alm.cmd_name_n, alm.silent_time); //but if it fails remove it from table
DEBUG_STREAM << "AlarmHandler::LOAD save_alarm_conf_db-" << alm.attr_name << endl;
string conf_str;
alm.confstr(conf_str);
savedlock->writerIn();
saved_alarms.insert(make_pair(alm.attr_name,conf_str));
savedlock->writerOut();
#endif
alarms.vlock->readerIn();
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name);
if(i != alarms.v_alarm.end())
{
try {
add_event(i->second, evn);//moved after events->add
add_event(i->second, evn);//moved after events->add //holds alarm reader lock
} catch (string& err) {
WARN_STREAM << "AlarmHandler::"<<__func__<<": string exception=" << err << endl;
//TODO: handle error
......@@ -1670,7 +1657,7 @@ void AlarmHandler::load(Tango::DevString argin)
find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end())
{
k->pop_alarm(i->second.name); //remove alarm/formula just added to event
k->m_alarm.pop(i->second.name); //remove alarm/formula just added to event
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": Removed!!!! alarm=" << i->second.name << " from event=" << *j << endl;
if(k->m_alarm.empty())
{
......@@ -1762,7 +1749,7 @@ void AlarmHandler::load(Tango::DevString argin)
alarms.vlock->readerOut();
#if 0//TODO
#if 1//TODO
prepare_alarm_attr();
try
{
......@@ -1783,7 +1770,7 @@ void AlarmHandler::load(Tango::DevString argin)
INFO_STREAM << __func__<<": " << err.str() << endl;
}
#endif
DEBUG_STREAM << "AlarmHandler::LOAD EXITING alm=" << argin << endl;
/*----- PROTECTED REGION END -----*/ // AlarmHandler::load
}
//--------------------------------------------------------
......@@ -1850,6 +1837,7 @@ void AlarmHandler::remove(Tango::DevString argin)
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -1858,6 +1846,7 @@ void AlarmHandler::remove(Tango::DevString argin)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -1872,7 +1861,8 @@ void AlarmHandler::remove(Tango::DevString argin)
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -1883,7 +1873,8 @@ void AlarmHandler::remove(Tango::DevString argin)
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -1934,13 +1925,13 @@ Tango::DevVarStringArray *AlarmHandler::search_alarm(Tango::DevString argin)
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}*/
start_pos = filter.find("*", start_pos);
if(start_pos != std::string::npos && start_pos == filter.size()-1) //* is the only character or at the end of the filter
if(start_pos != std::string::npos && start_pos == filter.size()-1) // * is the only character or at the end of the filter
{
filter.replace(start_pos, 1, "");
filter_begin = filter;
DEBUG_STREAM << __func__ << ": updated filter to: " << filter_begin;
}
/*else if(start_pos != std::string::npos) //* is in the middle of the filter
/*else if(start_pos != std::string::npos) // * is in the middle of the filter
{
string filter_begin=filter.substr(0,start_pos);
string filter_end=filter.substr(start_pos+1);
......@@ -1968,9 +1959,9 @@ Tango::DevVarStringArray *AlarmHandler::search_alarm(Tango::DevString argin)
{
ostringstream os;
os.clear();
os << ai->second.ts.tv_sec << SEP << KEY(NAME_KEY) << ai->second.name << SEP << KEY(FORMULA_KEY) << ai->second.formula << SEP << KEY(ONDELAY_KEY) << ai->second.on_delay << SEP << KEY(OFFDELAY_KEY) << ai->second.off_delay <<
SEP << KEY(LEVEL_KEY) << ai->second.lev << SEP << KEY(SILENT_TIME_KEY) << ai->second.silent_time << SEP << KEY(GROUP_KEY) << ai->second.grp2str() << SEP << KEY(MESSAGE_KEY) << ai->second.msg <<
SEP << KEY(ON_COMMAND_KEY) << ai->second.cmd_name_a << SEP << KEY(OFF_COMMAND_KEY) << ai->second.cmd_name_n << SEP << KEY(ENABLED_KEY) << (ai->second.enabled ? "1" : "0");
os << KEY(NAME_KEY) << ai->second.name << SEP << KEY(FORMULA_KEY) << ai->second.formula << SEP << KEY(ONDELAY_KEY) << ai->second.on_delay << SEP << KEY(OFFDELAY_KEY) << ai->second.off_delay <<
SEP << KEY(LEVEL_KEY) << ai->second.lev << SEP << KEY(SILENT_TIME_KEY) << ai->second.silent_time << SEP << KEY(GROUP_KEY) << ai->second.grp2str() << SEP << KEY(MESSAGE_KEY) << ai->second.msg << SEP << KEY(URL_KEY) << ai->second.url <<
SEP << KEY(ON_COMMAND_KEY) << ai->second.cmd_name_a << SEP << KEY(OFF_COMMAND_KEY) << ai->second.cmd_name_n << SEP << KEY(RECEIVERS_KEY) << ai->second.receivers << SEP << KEY(ENABLED_KEY) << (ai->second.enabled ? "1" : "0");
alarm_filtered.push_back(os.str());
}
} /* for */
......@@ -2011,6 +2002,7 @@ void AlarmHandler::stop_audible()
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -2019,6 +2011,7 @@ void AlarmHandler::stop_audible()
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -2033,7 +2026,8 @@ void AlarmHandler::stop_audible()
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -2044,7 +2038,8 @@ void AlarmHandler::stop_audible()
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -2078,6 +2073,16 @@ void AlarmHandler::silence(const Tango::DevVarStringArray *argin)
alarm_container_t::iterator i = alarms.v_alarm.find(*si);
if(i != alarms.v_alarm.end())
{
if(!i->second.enabled)
{
ostringstream err;
err << *si << " is not enabled";
alarms.vlock->readerOut();
Tango::Except::throw_exception( \
(const char*)"NOT_ENABLED", \
(const char*)err.str().c_str(), \
(const char*)__func__, Tango::ERR);
}
if(i->second.silenced > 0)
{
Tango::TimeVal now = gettime();
......@@ -2149,6 +2154,7 @@ void AlarmHandler::silence(const Tango::DevVarStringArray *argin)
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -2157,6 +2163,7 @@ void AlarmHandler::silence(const Tango::DevVarStringArray *argin)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -2171,7 +2178,8 @@ void AlarmHandler::silence(const Tango::DevVarStringArray *argin)
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -2182,7 +2190,8 @@ void AlarmHandler::silence(const Tango::DevVarStringArray *argin)
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -2213,135 +2222,45 @@ void AlarmHandler::modify(Tango::DevString argin)
//------------------------------
string alarm_string(argin);
alarm_t alm;
alarm_parse al_gr(alm); // Construct Spirit grammar
alm.name.clear();
alm.attr_name.clear();
alm.quality = Tango::ATTR_VALID;
alm.ex_reason.clear();
alm.ex_desc.clear();
alm.ex_origin.clear();
alm.formula.clear();
alm.msg.clear();
alm.lev.clear();
alm.grp=0;
alm.to_be_evaluated = false;
alm.on_delay = 0;
alm.off_delay = 0;
alm.silent_time = -1;
alm.silenced = -1;
alm.cmd_name_a.clear();
alm.cmd_dp_a.clear();
alm.cmd_action_a.clear();
alm.send_arg_a = false;
alm.dp_a = NULL;
alm.cmd_name_n.clear();
alm.cmd_dp_n.clear();
alm.cmd_action_n.clear();
alm.send_arg_n = false;
alm.dp_n = NULL;
alm.enabled=true;
alm.shelved=false;
parse_alarm(alarm_string, alm);
alm.formula_tree =
//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces
if (alm.formula_tree.full)
DEBUG_STREAM << "AlarmHandler::Modify: parsing ended: alm name=" << alm.name << endl;
//------------------------------
//2: if alarm already exist and
// formula is not changed
//------------------------------
alarms.vlock->writerIn(); //TODO: use readerIn instead?
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name);
if (i != alarms.v_alarm.end())
{
std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower); //transform to lowercase
//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower); //transform to lowercase: incorrect, state has to be written upercase
std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower); //transform to lowercase
if(i->second.formula == alm.formula)
{
Tango::TimeVal ts = gettime();
string cmd_name_full = alm.cmd_name_a + string(";") + alm.cmd_name_n;
if(alm.cmd_name_a.length() > 0)
{
const char *c = alm.cmd_name_a.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_a.push_back(*c);
else if (*c != '/')
alm.cmd_action_a.push_back(*c);
c++;
}
}
if(alm.cmd_name_n.length() > 0)
{
const char *c = alm.cmd_name_n.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_n.push_back(*c);
else if (*c != '/')
alm.cmd_action_n.push_back(*c);
c++;
}
}
}
else
{
ostringstream o;
o << __func__<<": Parsing Failed, parsed up to '" << string(alarm_string.begin(), alm.formula_tree.stop) << "' not parsed '" << string(alm.formula_tree.stop, alarm_string.end()) << "'"; //TODO
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Parsing Failed!", \
(const char*)o.str().c_str(), \
(const char*)__func__, Tango::ERR);
}
DEBUG_STREAM << "AlarmHandler::Modify: parsing ended: alm name=" << alm.name << endl;
//------------------------------
//2: if alarm already exist and
// formula is not changed
//------------------------------
alarms.vlock->writerIn();
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name);
if (i != alarms.v_alarm.end())
{
if(i->second.formula == alm.formula)
{
Tango::TimeVal ts = gettime();
string cmd_name_full = alm.cmd_name_a + string(";") + alm.cmd_name_n;
if ((alm.name.empty() == false) && \
(alm.formula.empty() == false) && \
((alm.lev==LEV_LOG)||(alm.lev==LEV_WARNING)|| \
(alm.lev==LEV_FAULT)||(alm.lev.empty() == true))) {
i->second.stat = S_NORMAL;
i->second.ack = ACK;
i->second.done = false;
i->second.msg = alm.msg;
i->second.lev = alm.lev;
i->second.grp = alm.grp;
//i->second.to_be_evaluated = alm.to_be_evaluated;
i->second.on_delay = alm.on_delay;
i->second.off_delay = alm.off_delay;
i->second.silent_time = alm.silent_time;
i->second.silenced = (i->second.silent_time > 0) ? 0 : -1; //0: can be silenced, -1: cannot be silencedd;
i->second.cmd_name_a = alm.cmd_name_a;
i->second.cmd_dp_a = alm.cmd_dp_a;
i->second.cmd_action_a = alm.cmd_action_a;
//i->second.send_arg_a = alm.send_arg_a;
i->second.cmd_name_n = alm.cmd_name_n;
i->second.cmd_dp_n = alm.cmd_dp_n;
i->second.cmd_action_n = alm.cmd_action_n;
//i->second.send_arg_n = alm.send_arg_n;
i->second.enabled = alm.enabled;
} else {
ostringstream o;
o << __func__<<": syntax error in '" << alarm_string << "'";
WARN_STREAM << o.str() << endl;
alarms.vlock->writerOut();
Tango::Except::throw_exception( \
(const char*)o.str().c_str(), \
(const char*)"", \
(const char*)__func__, Tango::ERR);
}
i->second.stat = S_NORMAL;
i->second.ack = ACK;
i->second.done = false;
i->second.msg = alm.msg;
i->second.url = alm.url;
i->second.lev = alm.lev;
i->second.grp = alm.grp;
//i->second.to_be_evaluated = alm.to_be_evaluated;
i->second.on_delay = alm.on_delay;
i->second.off_delay = alm.off_delay;
i->second.silent_time = alm.silent_time;
i->second.silenced = (i->second.silent_time > 0) ? 0 : -1; //0: can be silenced, -1: cannot be silencedd;
i->second.cmd_name_a = alm.cmd_name_a;
i->second.cmd_dp_a = alm.cmd_dp_a;
i->second.cmd_action_a = alm.cmd_action_a;
//i->second.send_arg_a = alm.send_arg_a;
i->second.cmd_name_n = alm.cmd_name_n;
i->second.cmd_dp_n = alm.cmd_dp_n;
i->second.cmd_action_n = alm.cmd_action_n;
//i->second.send_arg_n = alm.send_arg_n;
i->second.receivers = alm.receivers;
i->second.enabled = alm.enabled;
//update attribute properties
events->update_property();
......@@ -2419,10 +2338,10 @@ void AlarmHandler::modify(Tango::DevString argin)
else
{
alarms.vlock->writerOut();
ostringstream o;
o << "Alarm '"<<alm.name<<"' not found";
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
ostringstream o;
o << "Alarm '"<<alm.name<<"' not found";
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Not found", \
(const char*)o.str().c_str(), \
(const char*)__func__, Tango::ERR);
......@@ -2438,10 +2357,11 @@ 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
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -2450,6 +2370,7 @@ void AlarmHandler::modify(Tango::DevString argin)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -2464,7 +2385,8 @@ void AlarmHandler::modify(Tango::DevString argin)
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -2475,7 +2397,8 @@ void AlarmHandler::modify(Tango::DevString argin)
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -2573,7 +2496,10 @@ void AlarmHandler::shelve(const Tango::DevVarStringArray *argin)
alarms.vlock->readerIn();
alarm_container_t::iterator i = alarms.v_alarm.find(*si);
if(i == alarms.v_alarm.end())
{
alarms.vlock->readerOut();
continue;
}
i->second.shelved = true;
//load silent time
......@@ -2588,42 +2514,55 @@ void AlarmHandler::shelve(const Tango::DevVarStringArray *argin)
alarmed.erase(found);
}
alarmedlock->writerOut();
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(i->second.attr_name);
alarm_t alm = i->second;
alarms.vlock->readerOut();
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(alm.attr_name);
*attr_value = _SHLVD;
try
{ //DevFailed for push events
if(i->second.ex_reason.length() == 0)
#if 0//do not store errors for disabled alarms
if(!alm.error)
#endif
{
timeval now;
gettimeofday(&now, NULL);
push_change_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
push_archive_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
if(setAlarmQuality)
{
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)alm.quality, 1/*size*/, 0, false);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)alm.quality, 1/*size*/, 0, false);
}
else
{
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value);
}
}
#if 0//do not store errors for disabled alarms
else
{
Tango::DevErrorList errors(1);
errors.length(1);
errors[0].desc = CORBA::string_dup(i->second.ex_desc.c_str());
errors[0].desc = CORBA::string_dup(alm.ex_desc.c_str());
errors[0].severity = Tango::ERR;
errors[0].reason = CORBA::string_dup(i->second.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(i->second.ex_origin.c_str());
errors[0].reason = CORBA::string_dup(alm.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(alm.ex_origin.c_str());
Tango::DevFailed except(errors);
push_change_event(i->second.attr_name, &except);
push_archive_event(i->second.attr_name, &except);
push_change_event(alm.attr_name, &except);
push_archive_event(alm.attr_name, &except);
}
#endif
} catch(Tango::DevFailed & ex)
{
WARN_STREAM << "AlarmHandler::"<<__func__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
}
alarms.vlock->readerOut();
}
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -2632,6 +2571,7 @@ void AlarmHandler::shelve(const Tango::DevVarStringArray *argin)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -2644,7 +2584,8 @@ void AlarmHandler::shelve(const Tango::DevVarStringArray *argin)
push_change_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
push_change_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -2653,7 +2594,8 @@ void AlarmHandler::shelve(const Tango::DevVarStringArray *argin)
push_archive_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
push_archive_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -2696,48 +2638,56 @@ void AlarmHandler::enable(Tango::DevString argin)
i->second.silenced = (i->second.silent_time > 0) ? 0 : -1; //0: can be silenced, -1: cannot be silenced
i->second.shelved = false;
alarm_t alm = i->second;
alarms.vlock->readerOut();
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(alm.attr_name);
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(i->second.attr_name);
if((i->second.stat == S_NORMAL) && i->second.ack == ACK)
if((alm.stat == S_NORMAL) && alm.ack == ACK)
*attr_value = _NORM;
else if((i->second.stat == S_ALARM) && i->second.ack == NOT_ACK)
else if((alm.stat == S_ALARM) && alm.ack == NOT_ACK)
*attr_value = _UNACK;
else if((i->second.stat == S_ALARM) && i->second.ack == ACK)
else if((alm.stat == S_ALARM) && alm.ack == ACK)
*attr_value = _ACKED;
else if((i->second.stat == S_NORMAL) && i->second.ack == NOT_ACK)
else if((alm.stat == S_NORMAL) && alm.ack == NOT_ACK)
*attr_value = _RTNUN;
try
{ //DevFailed for push events
if(i->second.ex_reason.length() == 0)
if(!alm.error)
{
timeval now;
gettimeofday(&now, NULL);
push_change_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
push_archive_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
if(setAlarmQuality)
{
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)alm.quality, 1/*size*/, 0, false);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)alm.quality, 1/*size*/, 0, false);
}
else
{
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value);
}
}
else
{
Tango::DevErrorList errors(1);
errors.length(1);
errors[0].desc = CORBA::string_dup(i->second.ex_desc.c_str());
errors[0].desc = CORBA::string_dup(alm.ex_desc.c_str());
errors[0].severity = Tango::ERR;
errors[0].reason = CORBA::string_dup(i->second.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(i->second.ex_origin.c_str());
errors[0].reason = CORBA::string_dup(alm.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(alm.ex_origin.c_str());
Tango::DevFailed except(errors);
push_change_event(i->second.attr_name, &except);
push_archive_event(i->second.attr_name, &except);
push_change_event(alm.attr_name, &except);
push_archive_event(alm.attr_name, &except);
}
} catch(Tango::DevFailed & ex)
{
WARN_STREAM << "AlarmHandler::"<<__func__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
}
alarms.vlock->readerOut();
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -2746,6 +2696,7 @@ void AlarmHandler::enable(Tango::DevString argin)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -2758,7 +2709,8 @@ void AlarmHandler::enable(Tango::DevString argin)
push_change_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
push_change_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -2767,7 +2719,8 @@ void AlarmHandler::enable(Tango::DevString argin)
push_archive_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
push_archive_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -2809,40 +2762,52 @@ void AlarmHandler::disable(Tango::DevString argin)
i->second.enabled = false;
i->second.ts_time_silenced = gettime();
i->second.silenced = (i->second.silent_time > 0) ? 0 : -1; //0: can be silenced, -1: cannot be silenced
i->second.shelved = false;
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(i->second.attr_name);
alarm_t alm = i->second;
alarms.vlock->readerOut();
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(alm.attr_name);
*attr_value = _OOSRV;
try
{ //DevFailed for push events
if(i->second.ex_reason.length() == 0)
#if 0 //do not store errors for disabled alarms
if(!alm.error)
#endif
{
timeval now;
gettimeofday(&now, NULL);
push_change_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
push_archive_event(i->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
if(setAlarmQuality)
{
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)alm.quality, 1/*size*/, 0, false);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)alm.quality, 1/*size*/, 0, false);
}
else
{
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value);
}
}
#if 0 //do not store errors for disabled alarms
else
{
Tango::DevErrorList errors(1);
errors.length(1);
errors[0].desc = CORBA::string_dup(i->second.ex_desc.c_str());
errors[0].desc = CORBA::string_dup(alm.ex_desc.c_str());
errors[0].severity = Tango::ERR;
errors[0].reason = CORBA::string_dup(i->second.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(i->second.ex_origin.c_str());
errors[0].reason = CORBA::string_dup(alm.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(alm.ex_origin.c_str());
Tango::DevFailed except(errors);
push_change_event(i->second.attr_name, &except);
push_archive_event(i->second.attr_name, &except);
push_change_event(alm.attr_name, &except);
push_archive_event(alm.attr_name, &except);
}
#endif
} catch(Tango::DevFailed & ex)
{
WARN_STREAM << "AlarmHandler::"<<__func__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
}
alarms.vlock->readerOut();
/*
* remove from alarmed
*/
......@@ -2864,6 +2829,7 @@ void AlarmHandler::disable(Tango::DevString argin)
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -2872,6 +2838,7 @@ void AlarmHandler::disable(Tango::DevString argin)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -2886,7 +2853,8 @@ void AlarmHandler::disable(Tango::DevString argin)
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -2897,7 +2865,8 @@ void AlarmHandler::disable(Tango::DevString argin)
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -2926,11 +2895,11 @@ void AlarmHandler::reset_statistics()
{
i->second.freq_counter = 0;
}
alarms.vlock->readerOut();
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
double dnow = (now.tv_sec) + ((double)(now.tv_nsec))/1000000000;
last_statistics_reset_time = dnow;
alarms.vlock->readerOut();
/*----- PROTECTED REGION END -----*/ // AlarmHandler::reset_statistics
}
//--------------------------------------------------------
......@@ -2958,6 +2927,7 @@ void AlarmHandler::stop_new()
prepare_alarm_attr();
try
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -2966,6 +2936,7 @@ void AlarmHandler::stop_new()
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -2980,7 +2951,8 @@ void AlarmHandler::stop_new()
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read);
push_change_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_change_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -2991,7 +2963,8 @@ void AlarmHandler::stop_new()
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read);
push_archive_event("alarmSummary",&attr_alarmSummary_read[0],alarmSummary_sz);
push_archive_event("alarmDisabled",&attr_alarmDisabled_read[0], alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -3034,7 +3007,7 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString
{
alarms.vlock->readerOut();
ostringstream o;
o << "Alarm '" << argin << "' not found";
o << "Alarm '" << string((*argin)[0]) << "' not found";
DEBUG_STREAM <<__func__ << ": " << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"NOT FOUND", \
......@@ -3058,11 +3031,23 @@ 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)
ostringstream tmp;
tmp.str("");
tmp << "\"" << it->second.msg << "\"";
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")));
complete.push_back(KEY(VALUE_KEY)+string("ERROR"));
string almstate(tmp_val.str());
if(almstate != "SHLVD" && almstate != "OOSRV")
{
almstate = S_ERROR;
}
info.insert(make_pair(VALUE_KEY,almstate));
complete.push_back(KEY(VALUE_KEY)+almstate);
info.insert(make_pair(MESSAGE_KEY,tmp.str()));
complete.push_back(KEY(MESSAGE_KEY)+tmp.str());
info.insert(make_pair(URL_KEY,it->second.url));
complete.push_back(KEY(URL_KEY)+it->second.url);
info.insert(make_pair(FORMULA_KEY,it->second.formula));
complete.push_back(KEY(FORMULA_KEY)+it->second.formula);
info.insert(make_pair(ATTR_VALUES_KEY,tmp_ex.str()));
......@@ -3072,13 +3057,26 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString
{
info.insert(make_pair(VALUE_KEY,tmp_val.str()));
complete.push_back(KEY(VALUE_KEY)+tmp_val.str());
info.insert(make_pair(MESSAGE_KEY,tmp.str()));
complete.push_back(KEY(MESSAGE_KEY)+tmp.str());
info.insert(make_pair(URL_KEY,it->second.url));
complete.push_back(KEY(URL_KEY)+it->second.url);
info.insert(make_pair(FORMULA_KEY,it->second.formula));
complete.push_back(KEY(FORMULA_KEY)+it->second.formula);
info.insert(make_pair(ATTR_VALUES_KEY,it->second.attr_values));
complete.push_back(KEY(ATTR_VALUES_KEY)+it->second.attr_values);
}
tm time_tm;
time_t time_sec= it->second.ts.tv_sec;
//gmtime_r(&time_sec,&time_tm); //-> UTC
localtime_r(&time_sec,&time_tm);
char time_buf[64];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
ostringstream time_s;
time_s << time_buf << "." << it->second.ts.tv_usec;
info.insert(make_pair(ALARM_TIME_KEY,time_s.str()));
complete.push_back(KEY(ALARM_TIME_KEY)+time_s.str());
ostringstream tmp_qual;
try
......@@ -3090,7 +3088,7 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString
}
info.insert(make_pair(QUALITY_KEY,tmp_qual.str()));
complete.push_back(KEY(QUALITY_KEY)+tmp_qual.str());
ostringstream tmp;
//#if 0
tmp.str("");
tmp << (it->second.enabled ? "1" : "0");
......@@ -3105,6 +3103,7 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString
info.insert(make_pair(ACKNOWLEDGED_KEY,tmp.str())); //TODO: redundant, information already in attr_value
complete.push_back(KEY(ACKNOWLEDGED_KEY)+tmp.str()); //TODO: redundant, information already in attr_value
//#endif
tmp.str("");
tmp << (it->second.is_new ? "1" : "0");
info.insert(make_pair(AUDIBLE_KEY,tmp.str()));
......@@ -3130,7 +3129,7 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString
info.insert(make_pair(ONDELAY_KEY,tmp.str()));
complete.push_back(KEY(ONDELAY_KEY)+tmp.str());
tmp.str("");
tmp << (it->second.on_delay);
tmp << (it->second.off_delay);
info.insert(make_pair(OFFDELAY_KEY,tmp.str()));
complete.push_back(KEY(OFFDELAY_KEY)+tmp.str());
info.insert(make_pair(LEVEL_KEY,it->second.lev));
......@@ -3145,15 +3144,12 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString
complete.push_back(KEY(SILENT_TIME_REMAINING_KEY)+tmp.str());
info.insert(make_pair(GROUP_KEY,it->second.grp2str()));
complete.push_back(KEY(GROUP_KEY)+it->second.grp2str());
tmp.str("");
tmp << "\"" << it->second.msg << "\"";
info.insert(make_pair(MESSAGE_KEY,tmp.str()));
complete.push_back(KEY(MESSAGE_KEY)+tmp.str());
info.insert(make_pair(ON_COMMAND_KEY,it->second.cmd_name_a));
complete.push_back(KEY(ON_COMMAND_KEY)+it->second.cmd_name_a);
info.insert(make_pair(OFF_COMMAND_KEY,it->second.cmd_name_n));
complete.push_back(KEY(OFF_COMMAND_KEY)+it->second.cmd_name_n);
info.insert(make_pair(RECEIVERS_KEY,it->second.receivers));
complete.push_back(KEY(RECEIVERS_KEY)+it->second.receivers);
alarms.vlock->readerOut();
argout = new Tango::DevVarStringArray();
if(argin->length() == 1)
......@@ -3187,6 +3183,46 @@ Tango::DevVarStringArray *AlarmHandler::get_alarm_info(const Tango::DevVarString
return argout;
}
//--------------------------------------------------------
/**
* Command ReLoadAll related method
* Description: Re Load all alarms.
*
*/
//--------------------------------------------------------
void AlarmHandler::re_load_all()
{
DEBUG_STREAM << "AlarmHandler::ReLoadAll() - " << device_name << endl;
/*----- PROTECTED REGION ID(AlarmHandler::re_load_all) ENABLED START -----*/
// Add your own code
vector<string> tmp_alm_vec;
alarms.get_alarm_list_db(tmp_alm_vec, saved_alarms, savedlock);//holds write locks savedlock
for(const auto &it_al : tmp_alm_vec)
{
bool modify_err=false;
try
{
modify((Tango::DevString)it_al.c_str());
}
catch(Tango::DevFailed &e)
{
INFO_STREAM << __func__ << ": error modifying '" << it_al << "' err='" << e.errors[0].desc << "'";
modify_err=true;
}
if(modify_err)
{
try
{
load((Tango::DevString)it_al.c_str());
}
catch(Tango::DevFailed &e)
{
INFO_STREAM << __func__ << ": error loading '" << it_al << "' err='" << e.errors[0].desc << "'";
}
}
}
/*----- PROTECTED REGION END -----*/ // AlarmHandler::re_load_all
}
//--------------------------------------------------------
/**
* Method : AlarmHandler::add_dynamic_commands()
* Description : Create the dynamic commands if any
......@@ -3218,8 +3254,13 @@ 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.ts_err_delay = gettime();
alm.ts_err_delay.tv_sec -= errorDelay;
alm.err_counter = 0;
alm.formula.clear();
alm.msg.clear();
alm.url.clear();
alm.lev.clear();
alm.grp=0;
alm.to_be_evaluated = false;
......@@ -3238,6 +3279,7 @@ void AlarmHandler::load_alarm(string alarm_string, alarm_t &alm, vector<string>
alm.send_arg_n = false;
alm.dp_n = NULL;
alm.enabled = 1;
alm.receivers.clear();
evn.clear();
alm.formula_tree =
......@@ -3251,19 +3293,14 @@ void AlarmHandler::load_alarm(string alarm_string, alarm_t &alm, vector<string>
{
alm.attr_name = alm.name;
#if 0
size_t start_pos = 0;
string from("/");
string to("__");
while((start_pos = alm.attr_name.find(from, start_pos)) != std::string::npos)
{
alm.attr_name.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
alm.attr_name = std::regex_replace(alm.attr_name, std::regex("/"), "_");
#endif
}
//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower); //transform to lowercase: incorrect, state has to be written uppercase
std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower); //transform to lowercase
alm.msg = std::regex_replace(alm.msg, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
alm.url = std::regex_replace(alm.url, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
alm.receivers = std::regex_replace(alm.receivers, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
if(alm.cmd_name_a.length() > 0)
{
const char *c = alm.cmd_name_a.c_str();
......@@ -3304,16 +3341,16 @@ void AlarmHandler::load_alarm(string alarm_string, alarm_t &alm, vector<string>
dbg_msg;
DEBUG_STREAM << dbg_msg.str() << endl;
}
else
{
ostringstream o;
else
{
ostringstream o;
o << "AlarmHandler::load_alarm(): Parsing Failed, '" << string(alarm_string.begin(), alm.formula_tree.stop) << "' parsed ok, BUT '" << string(alm.formula_tree.stop, alarm_string.end()) << "' not parsed"; //TODO
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Parsing Failed!", \
(const char*)o.str().c_str(), \
(const char*)"AlarmHandler::load_alarm()", Tango::ERR);
}
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Parsing Failed!", \
(const char*)o.str().c_str(), \
(const char*)"AlarmHandler::load_alarm()", Tango::ERR);
}
alm.ts = gettime();
DEBUG_STREAM << "AlarmHandler::load_alarm(): name = '" << alm.name << "'" << endl;
DEBUG_STREAM << " attr_name = '" << alm.attr_name << "'" << endl;
......@@ -3321,17 +3358,21 @@ void AlarmHandler::load_alarm(string alarm_string, alarm_t &alm, vector<string>
DEBUG_STREAM << " on_delay = '" << alm.on_delay << "'" << endl;
DEBUG_STREAM << " off_delay = '" << alm.off_delay << "'" << endl;
DEBUG_STREAM << " msg = '" << alm.msg << "'" << endl;
DEBUG_STREAM << " url = '" << alm.url << "'" << endl;
DEBUG_STREAM << " grp = '" << showbase << hex << alm.grp << "'=" << alm.grp2str() << endl;
DEBUG_STREAM << " silent_time = '" << alm.silent_time << "'" << endl;
DEBUG_STREAM << " silenced = '" << alm.silenced << "'" << endl;
DEBUG_STREAM << " lev = '" << alm.lev << "'" << endl;
DEBUG_STREAM << " action_a = '" << alm.cmd_name_a << "'" << endl;
DEBUG_STREAM << " action_n = '" << alm.cmd_name_n << "'" << endl;
DEBUG_STREAM << " receivers = '" << alm.receivers << "'" << endl;
DEBUG_STREAM << " enabled = '" << (alm.enabled ? "1" : "0") << "'" << endl;
if ((alm.name.empty() == false) && \
(alm.formula.empty() == false) && \
(alm.msg.empty() == false) && \
((alm.lev==LEV_LOG)||(alm.lev==LEV_WARNING)|| \
(alm.lev==LEV_FAULT)||(alm.lev.empty() == true))) {
(alm.lev==LEV_FAULT)||(alm.lev==LEV_LOWEST)||(alm.lev==LEV_LOW)|| \
(alm.lev==LEV_MEDIUM)||(alm.lev==LEV_HIGH)||(alm.lev==LEV_HIGHEST)||(alm.lev.empty() == true))) {
alm.stat = S_NORMAL;
alm.ack = ACK;
alm.done = false;
......@@ -3381,7 +3422,7 @@ void AlarmHandler::init_alarms(map< string,vector<string> > &alarm_events)
if (found != events->v_event.end())
{
i->second.insert(found->name);
found->push_alarm(i->second.name);
found->m_alarm.push(i->second.name);
DEBUG_STREAM << "AlarmHandler::init_alarms(): found Event= " << found->name << " <- Alarm= " << i->second.name << endl;
//break; ???
} /* if */
......@@ -3407,13 +3448,14 @@ void AlarmHandler::init_events(vector<string> &evn)
}
} /* if */
}
void AlarmHandler::add_alarm(alarm_t& a, bool starting) throw(string&)
void AlarmHandler::add_alarm(alarm_t& a, bool starting)
{
alarms.push_back(a);
alarms.push_back(a); //take and release writer vlock
DEBUG_STREAM << "AlarmHandler::add_alarm(): added alarm '" \
<< a.name << "'" << endl;
<< a.name << "' starting=" << (int)starting << endl;
if(!starting)
{
alarms.vlock->readerIn();
alarm_container_t::iterator italm = alarms.v_alarm.find(a.name);
add_AlarmState_dynamic_attribute(italm->second.attr_name);
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(italm->second.attr_name);
......@@ -3426,10 +3468,11 @@ void AlarmHandler::add_alarm(alarm_t& a, bool starting) throw(string&)
*attr_value_formula = Tango::string_dup(italm->second.formula.c_str());
italm->second.attr_value_formula = attr_value_formula;
#endif
alarms.vlock->readerOut();
}
}
void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
void AlarmHandler::add_event(alarm_t& a, vector<string> &evn)
{
DEBUG_STREAM << "AlarmHandler::add_event(): formula '" << a.formula << "' found " << evn.size() << " events" << endl;
/*
......@@ -3457,7 +3500,7 @@ void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
* the event already exist; push alarm name
* into the per-event alarm list
*/
k->push_alarm(a.name);
k->m_alarm.push(a.name);
a.to_be_evaluated = true;
DEBUG_STREAM << "AlarmHandler::add_event(): '" << *j << "' found, added " \
<< " alarm '" << a.name << "' to list, valid=" << k->valid << endl;
......@@ -3504,13 +3547,13 @@ void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
k = find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end())
{
k->push_alarm(a.name);
k->m_alarm.push(a.name);
#if 0
//now initialize value of this attribute
try {
Tango::DeviceAttribute attr_value;
attr_value = k->dp->read_attribute(k->attribute);
ecb.extract_values(&attr_value, k->value, k->type);
ecb.extract_values(&attr_value, k->value, k->type, k->read_size);
k->valid = true;
ostringstream msg;
msg << "AlarmHandler::add_event(): initial values of " << k->name << " = ";
......@@ -3519,13 +3562,13 @@ void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
msg << ", valid=" << k->valid << ends;
DEBUG_STREAM << msg.str() << endl;
//delete attr_value;
} catch(Tango::DevFailed& e)
} catch(Tango::DevFailed& e
{
TangoSys_MemStream out_stream;
out_stream << "Failed to read initial value of " << k->name << " = " << e.errors[0].desc << ends;
k->valid = false;
#if TANGO_VER < 611 //if using subscribe stateless, alarm is not removed if it fails the subscription
k->pop_alarm(a.name); //remove alarm/formula just added to event
k->m_alarm.pop(a.name); //remove alarm/formula just added to event
//events->v_event.pop_back();
events->v_event.erase(k); //remove event just added to event_table
//delete attr_value;
......@@ -3535,7 +3578,7 @@ void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
{
TangoSys_MemStream out_stream;
out_stream << "Error reading initial value of " << k->name << " = " << e << ends;
k->pop_alarm(a.name); //remove alarm/formula just added to event
k->m_alarm.pop(a.name); //remove alarm/formula just added to event
//events->v_event.pop_back();
events->v_event.erase(k); //remove event just added to event_table
//delete attr_value;
......@@ -3545,6 +3588,7 @@ void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
}
}
} //for (vector<string>::iterator j = evn.begin(); ...
thread->signal(); //wake up subscibe thread if not waked by events->add
for(vector<string>::iterator j = evn.begin(); j != evn.end(); j++)
{
......@@ -3570,8 +3614,9 @@ void AlarmHandler::do_alarm(bei_t& e)
if(e.type == TYPE_TANGO_ERR || e.type == TYPE_GENERIC_ERR)
{
ostringstream o;
o << e.msg << endl;
WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
o << e.msg;
WARN_STREAM << "AlarmHandler::"<<__func__<<": " << e.ev_name << ": " << o.str() << endl;
events->veclock.readerIn();
vector<event>::iterator found_ev = \
find(events->v_event.begin(), events->v_event.end(), e.ev_name);
if (found_ev == events->v_event.end())
......@@ -3615,6 +3660,8 @@ void AlarmHandler::do_alarm(bei_t& e)
}
if(found_ev != events->v_event.end())
{
found_ev->valid = false;
Tango::TimeVal ts = gettime();
found_ev->err_counter++;
if(e.type == TYPE_TANGO_ERR)
found_ev->ex_reason = string("Event_ERROR");
......@@ -3622,44 +3669,161 @@ void AlarmHandler::do_alarm(bei_t& e)
found_ev->ex_reason = string("Alarm_ERROR");
found_ev->ex_desc = o.str();
found_ev->ex_origin = e.ev_name;
found_ev->quality = e.quality;
//LOOP ALARMS IN WHICH THIS EVENT IS USED
vector<string>::iterator j = found_ev->m_alarm.begin();
while (j != found_ev->m_alarm.end())
list<string> m_alarm=found_ev->m_alarm.show();
string found_ev_ex_reason = found_ev->ex_reason;
string found_ev_ex_desc = found_ev->ex_desc;
string found_ev_ex_origin = found_ev->ex_origin;
events->veclock.readerOut();
list<string>::iterator j = m_alarm.begin();
while (j != m_alarm.end())
{
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": before do_alarm_eval name=" << *j << " ev=" << e.ev_name << " err=" << found_ev_ex_desc << endl;
changed = do_alarm_eval(*j, e.ev_name, ts);
//if(!changed)
// continue; //TODO: check if OK
alarms.vlock->readerIn();
alarm_container_t::iterator it = alarms.v_alarm.find(*j);
if(it != alarms.v_alarm.end())
{
try
#if 0 //already done in alarm_table::update called by do_alarm_eval
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())
{
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;
else
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(errorDelay > 0)
{
if((ts.tv_sec - errorDelay) > it->second.ts_err_delay.tv_sec) //error is present and err delay has passed
{
if(!it->second.error)
{
it->second.is_new = 1;
it->second.ack = NOT_ACK;//if first error, reset ACK
}
it->second.error = true;
}
}
else
{
if(!it->second.error)
{
it->second.is_new = 1;
it->second.ack = NOT_ACK;//if first error, reset ACK
}
it->second.error = true;
}
#endif
alarm_t alm = it->second;
alarms.vlock->readerOut();
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": after do_alarm_eval name=" << *j << " error=" << (int)alm.error << " enabled=" << alm.enabled << endl;
#if 0 //TODO: already pushed in do_alarm_eval, not necessary here ?
if(alm.error && alm.enabled && !(alm.shelved && alm.silenced > 0))
{
try
{
Tango::DevErrorList errors(1);
errors.length(1);
errors[0].desc = CORBA::string_dup(alm.ex_desc.c_str());
errors[0].severity = Tango::ERR;
errors[0].reason = CORBA::string_dup(alm.ex_reason.c_str());
errors[0].origin = CORBA::string_dup(alm.ex_origin.c_str());
Tango::DevFailed except(errors);
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": PUSHING EXCEPTION FOR " << alm.attr_name << " " << alm.ex_desc << "-" << alm.ex_reason << "-" << alm.ex_origin << endl;
push_change_event(alm.attr_name, &except);
push_archive_event(alm.attr_name, &except);
}catch(Tango::DevFailed &ex)
{}
}
else if(alm.error) //TODO: or if(changed) ?
{
if(e.type == TYPE_TANGO_ERR)
it->second.ex_reason = found_ev->ex_reason;
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(alm.attr_name);
if(!alm.enabled)
{
*attr_value = _OOSRV;
}
else if(alm.shelved && alm.silenced > 0)
{
*attr_value = _SHLVD;
}
if(setAlarmQuality)
{
timeval now;
gettimeofday(&now, NULL);
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,static_cast<Tango::AttrQuality>(alm.quality), 1/*size*/, 0, false);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value,now,static_cast<Tango::AttrQuality>(alm.quality), 1/*size*/, 0, false);
}
else
it->second.ex_reason = found_ev->ex_reason;
it->second.ex_desc = found_ev->ex_desc;
it->second.ex_origin = found_ev->ex_origin;
Tango::DevErrorList errors(1);
errors.length(1);
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);
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": PUSHING EXCEPTION FOR " << it->second.attr_name << " " << it->second.ex_desc << "-" << it->second.ex_reason << "-" << it->second.ex_origin << endl;
push_change_event(it->second.attr_name, &except);
push_archive_event(it->second.attr_name, &except);
}catch(Tango::DevFailed &ex)
{}
{
push_change_event(alm.attr_name,(Tango::DevEnum *)attr_value);
push_archive_event(alm.attr_name,(Tango::DevEnum *)attr_value);
}
}
#endif
}
alarms.vlock->readerOut();
j++;
else
{
alarms.vlock->readerOut();
}
j++;
}
prepare_alarm_attr();//TODO: frequencyAlarm should be updated anyway
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
}
push_change_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_change_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_change_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
push_change_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
push_change_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
push_change_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
push_change_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
push_change_event("alarmDisabled",attr_alarmDisabled_read, alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
push_archive_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
push_archive_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
push_archive_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
push_archive_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
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
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": arrived event=" << e.ev_name << endl;
formula_res_t res;
events->veclock.readerIn();
vector<event>::iterator found = \
find(events->v_event.begin(), events->v_event.end(), e.ev_name);
if (found == events->v_event.end())
......@@ -3702,9 +3866,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;
......@@ -3713,12 +3880,16 @@ void AlarmHandler::do_alarm(bei_t& e)
found->valid = true;
found->ts = e.ts;
found->type = e.type;
found->read_size = e.read_size;
found->err_counter = 0;
vector<string>::iterator j = found->m_alarm.begin();
while (j != found->m_alarm.end())
list<string> m_alarm=found->m_alarm.show();
Tango::TimeVal ts = found->ts;
events->veclock.readerOut(); //do not hold events->veclock in do_alarm_eval which push events
list<string>::iterator j = m_alarm.begin();
while (j != m_alarm.end())
{
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": before do_alarm_eval name=" << *j << " ev=" << e.ev_name << endl;
changed = do_alarm_eval(*j, e.ev_name, found->ts);
changed = do_alarm_eval(*j, e.ev_name, ts);
if(changed)
num_changed++;
j++;
......@@ -3726,8 +3897,8 @@ void AlarmHandler::do_alarm(bei_t& e)
if(num_changed==0)
{
prepare_alm_mtx->lock();
alarms.vlock->readerIn();
prepare_alm_mtx->lock();
alarm_container_t::iterator ai;
size_t freq_ind = 0;
for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++)
......@@ -3735,13 +3906,14 @@ void AlarmHandler::do_alarm(bei_t& e)
attr_alarmFrequency_read[freq_ind] = ai->second.freq_counter;
freq_ind++;
}
alarms.vlock->readerOut();
prepare_alm_mtx->unlock();
alarms.vlock->readerOut();
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
return;
}
prepare_alarm_attr();//TODO: frequencyAlarm should be updated anyway
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -3750,6 +3922,7 @@ void AlarmHandler::do_alarm(bei_t& e)
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -3765,6 +3938,7 @@ void AlarmHandler::do_alarm(bei_t& e)
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
push_change_event("alarmDisabled",attr_alarmDisabled_read, alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -3776,9 +3950,11 @@ void AlarmHandler::do_alarm(bei_t& e)
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
push_archive_event("alarmDisabled",attr_alarmDisabled_read, alarmDisabled_sz);
}
else
{
events->veclock.readerOut();
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": event=" << e.ev_name << "NOT FOUND IN EVENT TABLE" << endl;
}
} /* do_alarm() */
......@@ -3786,31 +3962,43 @@ void AlarmHandler::do_alarm(bei_t& e)
bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal ts)
{
bool changed = true;
bool eval_err = false;
bool prev_error = false;
formula_res_t res;
//alarm_container_t::iterator it = alarms.v_alarm.find(j->first);
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": before lock name=" << alm_name<< " ev=" << ev_name << endl;
alarms.vlock->readerIn();
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": after lock name=" << alm_name<< " ev=" << ev_name << endl;
alarm_container_t::iterator it = alarms.v_alarm.find(alm_name);
if(it != alarms.v_alarm.end())
{
string attr_name = it->second.attr_name;
if(ev_name == "FORCED_EVAL" && !it->second.to_be_evaluated)
{
DEBUG_STREAM << __func__ << ": ev_name=" << ev_name << " -> FORCED_EVAL && !it->second.to_be_evaluated -> changed=false" << endl;
alarms.vlock->readerOut();
return false;
}
if(ev_name != "FORCED_EVAL")
it->second.freq_counter++;
string tmpname=it->first;
string ex_reason = it->second.ex_reason;
string ex_desc = it->second.ex_desc;
string ex_origin = it->second.ex_origin;
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;
}
try {
it->second.attr_values = string("{");
res = eval_formula(it->second.formula_tree, it->second.attr_values);
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 << 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
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(it->second.attr_name);
changed = changed || (prev_error && res.valid);
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": changed=" << (int)changed << " error=" << (int)it->second.error << endl;
Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
if(!it->second.enabled)
*attr_value = _OOSRV;
else if(it->second.shelved && it->second.silenced > 0)
......@@ -3823,34 +4011,49 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
*attr_value = _ACKED;
else if((it->second.stat == S_NORMAL) && it->second.ack == NOT_ACK)
*attr_value = _RTNUN;
Tango::AttrQuality quality = (Tango::AttrQuality)it->second.quality;
ex_reason = it->second.ex_reason; //copying again because updated with formula result res.ex_reason in alarms.update
ex_desc = it->second.ex_desc;
ex_origin = it->second.ex_origin;
alarms.vlock->readerOut(); //Don't hold alarms lock while pushing events to prevent deadlocks
try
{ //DevFailed for push events
if(it->second.ex_reason.length() == 0)
if(!it->second.error || !it->second.enabled || (it->second.shelved && it->second.silenced > 0))
{
timeval now;
gettimeofday(&now, NULL);
push_change_event(it->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)it->second.quality, 1/*size*/, 0, false);
push_archive_event(it->second.attr_name,(Tango::DevEnum *)attr_value,now,(Tango::AttrQuality)it->second.quality, 1/*size*/, 0, false);
if(setAlarmQuality)
{
push_change_event(attr_name,(Tango::DevEnum *)attr_value,now,quality, 1/*size*/, 0, false);
push_archive_event(attr_name,(Tango::DevEnum *)attr_value,now,quality, 1/*size*/, 0, false);
}
else
{
push_change_event(attr_name,(Tango::DevEnum *)attr_value);
push_archive_event(attr_name,(Tango::DevEnum *)attr_value);
}
}
else
{
Tango::DevErrorList errors(1);
errors.length(1);
errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
errors[0].desc = CORBA::string_dup(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());
errors[0].reason = CORBA::string_dup(ex_reason.c_str());
errors[0].origin = CORBA::string_dup(ex_origin.c_str());
Tango::DevFailed except(errors);
push_change_event(it->second.attr_name, &except);
push_archive_event(it->second.attr_name, &except);
push_change_event(attr_name, &except);
push_archive_event(attr_name, &except);
}
} catch(Tango::DevFailed & ex)
{
WARN_STREAM << "AlarmHandler::"<<__func__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
}
} catch(std::out_of_range& ex)
{
eval_err = true;
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!";
WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
......@@ -3860,24 +4063,39 @@ 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;
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);
push_change_event(it->second.attr_name, &except);
push_archive_event(it->second.attr_name, &except);
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__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
}
} catch(string & ex)
{
eval_err = true;
changed = !prev_error;
it->second.to_be_evaluated = true;
ostringstream o;
o << tmpname << ": in formula err=" << ex;
o << ex;
WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
try
......@@ -3885,27 +4103,79 @@ 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("FORMULA_ERROR");
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;
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);
push_change_event(it->second.attr_name, &except);
push_archive_event(it->second.attr_name, &except);
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__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
}
}
if(!eval_err)
catch(Tango::DevFailed & ex)
{
it->second.to_be_evaluated = false;
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))
{
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;
}
}
}
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";
......@@ -3932,7 +4202,7 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
}
#endif
}
alarms.vlock->readerOut();
//alarms.vlock->readerOut();
return changed;
}
......@@ -3966,9 +4236,11 @@ 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
{
#ifdef _ZEROS_ALARM_EMPTY
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
......@@ -3977,6 +4249,7 @@ void AlarmHandler::timer_update()
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
#endif
{
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
......@@ -3992,6 +4265,7 @@ void AlarmHandler::timer_update()
push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_change_event("alarmAudible",attr_alarmAudible_read);
push_change_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
push_change_event("alarmDisabled",attr_alarmDisabled_read, alarmDisabled_sz);
push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
......@@ -4003,6 +4277,7 @@ void AlarmHandler::timer_update()
push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
push_archive_event("alarmAudible",attr_alarmAudible_read);
push_archive_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
push_archive_event("alarmDisabled",attr_alarmDisabled_read, alarmDisabled_sz);
} catch(Tango::DevFailed& e)
{
ostringstream err;
......@@ -4011,7 +4286,7 @@ void AlarmHandler::timer_update()
}
}
bool AlarmHandler::remove_alarm(string& s) throw(string&)
bool AlarmHandler::remove_alarm(string& s)
{
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": entering alm name=" << s << endl;
alarms.vlock->writerIn();
......@@ -4033,8 +4308,8 @@ bool AlarmHandler::remove_alarm(string& s) throw(string&)
/*
* remove alarm
*/
k->pop_alarm(i->second.name);
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": after pop_alarm" << endl;
k->m_alarm.pop(i->second.name);
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": after m_alarm.pop" << endl;
if (k->m_alarm.empty()) {
/*
* no more alarms associated to this event, unsubscribe
......@@ -4103,8 +4378,8 @@ bool AlarmHandler::remove_alarm(string& s) throw(string&)
/*
* remove this alarm from alarm table
*/
alarms.erase(i);
alarms.vlock->writerOut();
alarms.erase(i); //takes vlock writer lock
return true;
}
else
......@@ -4121,7 +4396,7 @@ bool AlarmHandler::remove_alarm(string& s) throw(string&)
} /* remove_alarm() */
/*void AlarmHandler::add_to_database(alarm_t& a) throw(string&)
/*void AlarmHandler::add_to_database(alarm_t& a)
{
Tango::DbDatum alarm("alarm");
Tango::DbData db_data;
......@@ -4160,6 +4435,7 @@ bool AlarmHandler::remove_alarm(string& s) throw(string&)
void AlarmHandler::set_internal_alarm(string name, Tango::TimeVal t, string msg, unsigned int count)
{
#if 0
alarm_t alm;
bool existing=false;
ostringstream o;
......@@ -4233,10 +4509,11 @@ void AlarmHandler::set_internal_alarm(string name, Tango::TimeVal t, string msg,
else
alm.grp = GR_DEFAULT;
//alm.lev = LEV_DEFAULT;
alm.lev = LEV_LOG;
alm.lev = LEV_LOWEST;
internal.push_back(alm);
}
internallock->writerOut();
#endif
}
//==============================================================
......@@ -4244,14 +4521,59 @@ 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)
{
return eval_expression(tree.trees.begin(), attr_values);
}
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 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_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)
{
res.ex_reason.clear();
res.ex_desc.clear();
res.ex_origin.clear();
res.error.clear();
}
return res;
}
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;
err << "Evaluating formula: ";
err << "";
//iter_t it = i->children.begin();
if (i->value.id() == formula_grammar::val_rID)
......@@ -4263,9 +4585,14 @@ 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);
DEBUG_STREAM << " node value real = " << val_d << "(value="<<res.value<<" quality="<<res.quality<<")" << endl;
return 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_array(res.value,res.dim_x,res.dim_y)<<" quality="<<res.quality<<")" << endl;
#endif
return res;
}
else if (i->value.id() == formula_grammar::val_hID)
{
......@@ -4275,9 +4602,14 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
throw err.str();
}
string val_d(i->value.begin(), i->value.end());
#ifdef _DEBUG_FORMULA
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.dim_x=1;
res.dim_y=0;
res.valid = true;
return res;
}
else if (i->value.id() == formula_grammar::val_stID)
......@@ -4289,9 +4621,14 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
string val_st(i->value.begin(), i->value.end());
double st = i->value.value(); //get value directly from node saved with access_node_d
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node value state : " << val_st << "=" << st << endl;
#endif
formula_res_t res;
res.value = st;
res.value = {(double)st};
res.dim_x=1;
res.dim_y=0;
res.valid = true;
return res;
}
else if (i->value.id() == formula_grammar::val_alarm_enum_stID)
......@@ -4303,9 +4640,14 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
string val_st(i->value.begin(), i->value.end());
double st = i->value.value(); //get value directly from node saved with access_node_d
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node value alarm enum state : " << val_st << "=" << st << endl;
#endif
formula_res_t res;
res.value = st;
res.value = {(double)st};
res.dim_x=1;
res.dim_y=0;
res.valid = true;
return res;
}
else if (i->value.id() == formula_grammar::val_qualityID)
......@@ -4318,43 +4660,49 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
string val_quality(i->value.begin(), i->value.end());
double quality = i->value.value(); //get value directly from node saved with access_node_d
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node value quality : " << val_quality << "=" << quality << endl;
#endif
formula_res_t res;
res.value = quality;
res.value = {(double)quality};
res.dim_x=1;
res.dim_y=0;
res.valid = true;
return res;
}
else if (i->value.id() == formula_grammar::unary_exprID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node unary expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 1)
{
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)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node mult expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node mult_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4378,7 +4726,9 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else if (i->value.id() == formula_grammar::add_exprID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node add expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node add_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4402,93 +4752,538 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else if (i->value.id() == formula_grammar::event_ID)
{
#ifdef _DEBUG_FORMULA
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)
vector<vector<double> > indexes;
iter_t child = i->children.begin();
if(child->value.id() != formula_grammar::nameID)
{
if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".quality")
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
{
if(child->value.id() == formula_grammar::index_rangeID || child->value.id() == formula_grammar::indexID)
{
formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value);
res.value = res.quality;
DEBUG_STREAM << " node event.quality -> " << res.value << endl;
vector<double> ind_range;
eval_index_range(child, attr_values, ind_range);
if(!ind_range.empty())
indexes.push_back(ind_range);
}
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 - i->children.begin() == (long int)i->children.size() -1 && child->value.id() == formula_grammar::propertyID)
{
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(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_array(res.value,res.dim_x,res.dim_y) << endl;
#endif
return res;
}
else if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".alarm")
else if(string(child->value.begin(), child->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);
DEBUG_STREAM << " node event.alarm -> " << res.value << endl;
formula_res_t res;
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(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_array(res.value,res.dim_x,res.dim_y)<< endl;
#endif
return res;
}
else if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".normal")
else if(string(child->value.begin(), child->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);
DEBUG_STREAM << " node event.normal -> " << res.value << endl;
formula_res_t res;
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(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_array(res.value,res.dim_x,res.dim_y) << endl;
#endif
return res;
}
}
else
else if(child - i->children.begin() < (long int)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(child->value.begin(), child->value.end());
throw err.str();
}
return eval_expression(i->children.begin(), attr_values, (int)ind.value);
if(!indexes.empty())
return eval_expression(i->children.begin(), attr_values, indexes);
else
return eval_expression(i->children.begin(), attr_values);
}
else if (i->value.id() == formula_grammar::nameID)
{
if(i->children.size() != 0)
{
err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
throw err.str();
}
vector<event>::iterator it = events->v_event.begin();
string s(i->value.begin(), i->value.end());
std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase
while ((it != events->v_event.end()) && (it->name != s))
it++;
err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
throw err.str();
}
events->veclock.readerIn();
vector<event>::iterator it = events->v_event.begin();
string s(i->value.begin(), i->value.end());
std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase
while ((it != events->v_event.end()) && (it->name != s))
it++;
if (it != events->v_event.end())
{
if(!it->valid)
{
if(it->ex_desc.length() > 0)
err << "attribute '" << string(i->value.begin(), i->value.end()) << "' exception: '" << it->ex_desc << "'";
err << it->ex_desc << "";
else
err << "attribute '" << string(i->value.begin(), i->value.end()) << "' value not valid!";
throw err.str();
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
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 << "attribute '" << string(i->value.begin(), i->value.end()) << "' exception: '" << it->ex_desc << "'";
err << it->ex_desc << "";
else
err << "attribute '" << string(i->value.begin(), i->value.end()) << "' value not initialized!!";
throw err.str();
}
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();
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;
}
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())
{
temp_attr_val << "\"" << it->name;
for(auto vei : ev_ind)
{
if(!vei.empty())
{
temp_attr_val << "[" << print_vector(vei) << "]";
}
}
temp_attr_val << "\":";
if(it->dim_y <=1)//1D array
{
if(ev_ind.size() ==1 && ev_ind[0].size() == 1 && ev_ind[0][0] != -1)//single element of 1D array (e.g. [0])
{
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] << "],";
}
else if(ev_ind.size() ==1 && ev_ind[0].size() > 1)//multiple elements of 1D array (e.g. [0,1,2])
{
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;
events->veclock.readerOut();
throw err.str();
}
}
else if(it->dim_y > 1)//2D array
{
//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
{
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) << ",";
}
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])
{
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;
events->veclock.readerOut();
throw err.str();
}
}
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_array(res.value,res.dim_x,res.dim_y) << ",";
}
}
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;
res.value = it->value.at(ev_ind); //throw std::out_of_range
#endif
return res;
}
else
{
events->veclock.readerOut();
err << "in event: (" << string(i->value.begin(), i->value.end()) << ") not found in event table";
throw err.str();
}
......@@ -4501,14 +5296,21 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
throw err.str();
}
string val_d(i->value.begin(), i->value.end());
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node index = " << val_d << endl;
#endif
formula_res_t res;
res.value = strtod(val_d.c_str(), 0);
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)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node logical expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node logical_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4532,7 +5334,9 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else if (i->value.id() == formula_grammar::bitwise_exprID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node bitwise expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node bitwise_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4540,43 +5344,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.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);
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::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.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);
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::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.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);
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::fBitXor);
return res;
}
else
......@@ -4587,7 +5420,9 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else if (i->value.id() == formula_grammar::shift_exprID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node shift expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node shift_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4595,33 +5430,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.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);
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_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.quality = res.combine_quality(res_1.quality, res_2.quality);
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);
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
......@@ -4632,7 +5493,9 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else if (i->value.id() == formula_grammar::equality_exprID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node equality expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4653,6 +5516,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
string name_id(i2_1->value.begin(), i2_1->value.end());
std::transform(name_id.begin(), name_id.end(), name_id.begin(), (int(*)(int))tolower); //transform to lowercase
formula_res_t res;
events->veclock.readerIn();
vector<event>::iterator it = events->v_event.begin();
while ((it != events->v_event.end()) && (it->name != name_id))
......@@ -4664,27 +5528,58 @@ 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 << "'";
throw err.str();
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();
/*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 << "'";
throw err.str();
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();
/*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;
res.ex_origin = it->ex_origin;
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node name -> " << temp_attr_val.str() << " quality=" << res.quality << endl;
#endif
attr_val = string("'") + it->value_string + string("'");
events->veclock.readerOut();
}
else
{
events->veclock.readerOut();
err << "in event: (" << string(i->value.begin(), i->value.end()) << ") not found in event table";
throw err.str();
}
......@@ -4694,12 +5589,16 @@ 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)};
res.dim_x=1;
res.dim_y=0;
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)};
res.dim_x=1;
res.dim_y=0;
return res;
}
else
......@@ -4730,7 +5629,9 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else if (i->value.id() == formula_grammar::compare_exprID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node compare expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node compare_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4758,39 +5659,67 @@ 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();
}
}
else if (i->value.id() == formula_grammar::funcID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node function: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 1)
{
err << "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
throw err.str();
}
err << "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
throw err.str();
}
formula_res_t res;
res = eval_expression(i->children.begin(), attr_values);
if (string(i->value.begin(), i->value.end()) == string("abs"))
{
res.value = fabs(res.value);
res = eval_expression(i->children.begin(), attr_values);
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.value = cos(res.value);
res = eval_expression(i->children.begin(), attr_values);
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.value = sin(res.value);
res = eval_expression(i->children.begin(), attr_values);
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.value = res.quality;
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));})};
}
else if(string(i->value.begin(), i->value.end()) == string("OR"))
{
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_array(res.value,res.dim_x,res.dim_y)<<" quality="<<res.quality<< endl;
#endif
return res;
}
else
......@@ -4798,10 +5727,12 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
err << "in node funcID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
throw err.str();
}
}
}
else if (i->value.id() == formula_grammar::func_dualID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node function dual: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 2)
{
err << "in node func_dualID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4809,34 +5740,47 @@ 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);
bool valid = res_1.valid && res_2.valid;
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);
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);
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);
}
return res;
}
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);
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);
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);
}
return res;
}
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);
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);
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);
}
return res;
}
else
......@@ -4847,14 +5791,24 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else if (i->value.id() == formula_grammar::cond_exprID)
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node ternary_if expression: " << string(i->value.begin(), i->value.end()) << endl;
#endif
if(i->children.size() != 3)
{
err << "in node ternary_ifID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
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;
......@@ -4867,14 +5821,19 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
}
else
{
#ifdef _DEBUG_FORMULA
DEBUG_STREAM << " node unknown id: " << string(i->value.begin(), i->value.end()) << endl;
#endif
{
err << "node unknown!! value=" << string(i->value.begin(), i->value.end());
throw err.str();
}
}
formula_res_t res;
res.value = 0;
res.value = {(double)0.0};
res.dim_x=1;
res.dim_y=0;
res.valid = false;
return res;
}
......@@ -4886,9 +5845,9 @@ void AlarmHandler::find_event_formula(tree_parse_info_t tree, vector<string> & e
void AlarmHandler::eval_node_event(iter_t const& i, vector<string> & ev)
{
DEBUG_STREAM << "In eval_node_event. i->value = '" <<
string(i->value.begin(), i->value.end()) <<
"' i->children.size() = " << i->children.size() << " NODE=" << rule_names[i->value.id()] << endl;
//DEBUG_STREAM << "In eval_node_event. i->value = '" <<
// string(i->value.begin(), i->value.end()) <<
// "' i->children.size() = " << i->children.size() << " NODE=" << rule_names[i->value.id()] << endl;
ostringstream err;
err << "Looking for event in formula tree: ";
/*if (i->value.id() == formula_grammar::event_ID)
......@@ -4897,7 +5856,7 @@ void AlarmHandler::eval_node_event(iter_t const& i, vector<string> & ev)
}
else*/ if (i->value.id() == formula_grammar::nameID)
{
DEBUG_STREAM << "eval_node_event(): find event name=" << string(i->value.begin(), i->value.end()) << endl;
//DEBUG_STREAM << "eval_node_event(): find event name=" << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 0)
{
err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
......@@ -4907,7 +5866,7 @@ void AlarmHandler::eval_node_event(iter_t const& i, vector<string> & ev)
std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase
ev.push_back(s);
}
//cout << endl;
//TANGO_LOG << endl;
//iter_t it = i->children.begin();
for(iter_t it = i->children.begin(); it != i->children.end(); it++)
eval_node_event(it, ev);
......@@ -4917,11 +5876,11 @@ void AlarmHandler::eval_node_event(iter_t const& i, vector<string> & ev)
void AlarmHandler::prepare_alarm_attr()
{
prepare_alm_mtx->lock();
alarm_container_t::iterator ai;
vector<alarm_t>::iterator aid;
bool is_audible=false;
alarms.vlock->readerIn();
prepare_alm_mtx->lock();
outOfServiceAlarms_sz=0;
shelvedAlarms_sz=0;
acknowledgedAlarms_sz=0;
......@@ -4931,9 +5890,11 @@ void AlarmHandler::prepare_alarm_attr()
silencedAlarms_sz=0;
listAlarms_sz=0;
alarmSummary_sz=0;
alarmDisabled_sz=0;
string almstate;
for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) {
//DEBUG_STREAM << __func__<<": looping v_alarm.size="<<alarms.v_alarm.size()<<", listAlarms_sz="<<listAlarms_sz<<" : "<<ai->second.name<<endl;
#ifndef ALM_SUM_STR
stringstream alm_summary;
alm_summary << KEY(NAME_KEY) << ai->first << SEP;
......@@ -4941,6 +5902,7 @@ void AlarmHandler::prepare_alarm_attr()
string alm_summary;
alm_summary += KEY(NAME_KEY) + ai->first + SEP;
#endif
stringstream alm_disabled;
if(ai->second.enabled == false)
{
outOfServiceAlarms_read[outOfServiceAlarms_sz] = ai->second.name;
......@@ -4963,7 +5925,7 @@ void AlarmHandler::prepare_alarm_attr()
}
else
{
if(ai->second.stat == S_ALARM && ai->second.ack == ACK)
if(ai->second.stat == S_ALARM && ai->second.ack == ACK && !ai->second.error)
{
acknowledgedAlarms_read[acknowledgedAlarms_sz] = ai->second.name;
attr_alarmAcknowledged_read[acknowledgedAlarms_sz] = const_cast<char*>(acknowledgedAlarms_read[acknowledgedAlarms_sz].c_str());
......@@ -4973,7 +5935,7 @@ void AlarmHandler::prepare_alarm_attr()
acknowledgedAlarms_sz++;
almstate = "ACKED";
}
else if(ai->second.stat == S_ALARM && ai->second.ack == NOT_ACK)
else if(ai->second.stat == S_ALARM && ai->second.ack == NOT_ACK && !ai->second.error)
{
unacknowledgedAlarms_read[unacknowledgedAlarms_sz] = ai->second.name;
attr_alarmUnacknowledged_read[unacknowledgedAlarms_sz] = const_cast<char*>(unacknowledgedAlarms_read[unacknowledgedAlarms_sz].c_str());
......@@ -4983,7 +5945,7 @@ void AlarmHandler::prepare_alarm_attr()
unacknowledgedAlarms_sz++;
almstate = "UNACK";
}
else if(ai->second.stat == S_NORMAL && ai->second.ack == NOT_ACK)
else if(ai->second.stat == S_NORMAL && ai->second.ack == NOT_ACK && !ai->second.error)
{
unacknowledgedNormalAlarms_read[unacknowledgedNormalAlarms_sz] = ai->second.name;
attr_alarmUnacknowledgedNormal_read[unacknowledgedNormalAlarms_sz] = const_cast<char*>(unacknowledgedNormalAlarms_read[unacknowledgedNormalAlarms_sz].c_str());
......@@ -4993,7 +5955,7 @@ void AlarmHandler::prepare_alarm_attr()
unacknowledgedNormalAlarms_sz++;
almstate = "RTNUN";
}
else if(ai->second.stat == S_NORMAL && ai->second.ack == ACK)
else if(ai->second.stat == S_NORMAL && ai->second.ack == ACK && !ai->second.error)
{
normalAlarms_read[normalAlarms_sz] = ai->second.name;
attr_alarmNormal_read[normalAlarms_sz] = const_cast<char*>(normalAlarms_read[normalAlarms_sz].c_str());
......@@ -5014,23 +5976,53 @@ void AlarmHandler::prepare_alarm_attr()
}
}
tm time_tm;
time_t time_sec= ai->second.ts_time_silenced.tv_sec;
//gmtime_r(&time_sec,&time_tm); //-> UTC
localtime_r(&time_sec,&time_tm);
char time_buf[64];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
if(almstate == "OOSRV" || almstate == "SHLVD")
{
//TANGO_LOG << __func__ << ": " << ai->first << " silenced="<< ai->second.silenced << endl;
#if 0
alm_disabled << KEY(ALARM_TIME_KEY) << time_buf << "." << ai->second.ts.tv_usec << SEP;
alm_disabled << KEY(NAME_KEY) << ai->first << SEP;
alm_disabled << KEY(VALUE_KEY) << almstate << SEP; //TODO: string or enum value?
alm_disabled << KEY(SILENT_TIME_REMAINING_KEY) << ai->second.silenced << SEP;
alm_disabled << KEY(MESSAGE_KEY) << ai->second.msg; //TODO: escape ';'
#else
alm_disabled << ai->second.ts.tv_sec << "\t";
alm_disabled << ai->second.ts.tv_usec << "\t";
alm_disabled << ai->first << "\t";
alm_disabled << almstate << "\t"; //TODO: string or enum value?
alm_disabled << ai->second.ack << "\t";
alm_disabled << ai->second.lev << "\t";
alm_disabled << ai->second.silenced << "\t";
alm_disabled << ai->second.grp2str() << "\t";
alm_disabled << ai->second.msg << "\t"; //TODO: escape ';'
#endif
alarmDisabled_read[alarmDisabled_sz] = alm_disabled.str();
attr_alarmDisabled_read[alarmDisabled_sz] = const_cast<char*>(alarmDisabled_read[alarmDisabled_sz].c_str());
alarmDisabled_sz++;
}
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__ << ": " << tmp_ex.str();
DEBUG_STREAM << __func__ << ": " << ai->first << " -> " << tmp_ex.str();
if(almstate != "SHLVD" && almstate != "OOSRV")
{
almstate = "ERROR";
almstate = S_ERROR;
}
}
tm time_tm;
time_t time_sec= ai->second.ts.tv_sec;
time_sec= ai->second.ts.tv_sec;
//gmtime_r(&time_sec,&time_tm); //-> UTC
localtime_r(&time_sec,&time_tm);
char time_buf[64];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
#ifndef ALM_SUM_STR
......@@ -5039,6 +6031,7 @@ void AlarmHandler::prepare_alarm_attr()
alm_summary << KEY(ALARM_TIME_KEY) << time_buf << "." << ai->second.ts.tv_usec << SEP;
alm_summary << KEY(FORMULA_KEY) << ai->second.formula << SEP;
alm_summary << KEY(MESSAGE_KEY) << ai->second.msg; //TODO: escape ';'
//alm_summary << KEY(URL_KEY) << ai->second.url; //TODO: escape ';' TODO: add to alarmSummary?
#else
alm_summary += string(KEY(VALUE_KEY)) + almstate + SEP; //TODO: string or enum value?
alm_summary += KEY(LEVEL_KEY) + ai->second.lev + SEP;
......@@ -5047,6 +6040,7 @@ void AlarmHandler::prepare_alarm_attr()
alm_summary += KEY(ALARM_TIME_KEY) + sval.str() + SEP;
alm_summary += KEY(FORMULA_KEY) + ai->second.formula + SEP;
alm_summary += KEY(MESSAGE_KEY) + ai->second.msg; //TODO: escape ';'
//alm_summary += KEY(URL_KEY) + ai->second.url; //TODO: escape ';' TODO: add to alarmSummary?
#endif
......@@ -5115,7 +6109,58 @@ void AlarmHandler::prepare_alarm_attr()
alm_summary += KEY(ATTR_VALUES_KEY) + ai->second.attr_values + SEP;
#endif
#endif
if (ai->second.stat == S_ALARM && ai->second.enabled && !ai->second.shelved) {
if (almstate == S_ERROR) {
/*
* alarm status is S_ERROR
*/
alarmedlock->readerIn();
aid = find(alarmed.begin(), alarmed.end(),ai->second.name);
if (aid != alarmed.end()) {
/*
* found, change stat only if switching from
* S_NORMAL or S_ALARM status to S_ERROR
*/
//TANGO_LOG << "read_attr(): S_ERROR: found: " << aid->name << endl;
if (aid->stat != S_ERROR) {
aid->stat = S_ERROR;
aid->ack = NOT_ACK;
aid->ts = ai->second.ts;
aid->msg = ai->second.ex_desc;//tmp_ex.str();//ai->second.msg;
aid->url = ai->second.url;
}
aid->grp = ai->second.grp;
aid->lev = ai->second.lev;
aid->is_new = ai->second.is_new; //copy is_new state
aid->receivers = ai->second.receivers;
//ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0
#ifdef _CNT_ATOMIC
aid->on_counter.store(ai->second.on_counter);
aid->off_counter.store(ai->second.off_counter);
#else
aid->on_counter = ai->second.on_counter;
aid->off_counter = ai->second.off_counter;
#endif
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 {
alarm_t at = ai->second;
at.stat = S_ERROR;
at.msg = ai->second.ex_desc;//tmp_ex.str();//ai->second.msg;
/*
* not found: new "alarmed" item
*/
DEBUG_STREAM << __func__<<": S_ERROR: pushing new alarm: " \
<< ai->second.name << "\t" << ai->second.stat << endl;
alarmedlock->readerOut();
alarmedlock->writerIn();
alarmed.push_back(at);
//ai->second.is_new = 0; //set state as not more new //12-06-08: StopNew command set it to 0
alarmedlock->writerOut();
alarmedlock->readerIn();
}
alarmedlock->readerOut();
} else if (ai->second.stat == S_ALARM && ai->second.enabled && !ai->second.shelved) {
/*
* alarm status is S_ALARM
*/
......@@ -5126,19 +6171,26 @@ void AlarmHandler::prepare_alarm_attr()
* 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) {
//TANGO_LOG << "read_attr(): S_ALARM: found: " << aid->name << endl;
if (aid->stat == S_NORMAL || aid->stat == S_ERROR) {
aid->stat = S_ALARM;
aid->ack = NOT_ACK;
aid->ts = ai->second.ts;
aid->msg = ai->second.msg;
aid->url = ai->second.url;
}
aid->grp = ai->second.grp;
aid->lev = ai->second.lev;
aid->is_new = ai->second.is_new; //copy is_new state
aid->receivers = ai->second.receivers;
//ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0
#ifdef _CNT_ATOMIC
aid->on_counter.store(ai->second.on_counter);
aid->off_counter.store(ai->second.off_counter);
#else
aid->on_counter = ai->second.on_counter;
aid->off_counter = ai->second.off_counter;
#endif
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
......@@ -5171,17 +6223,25 @@ void AlarmHandler::prepare_alarm_attr()
aid->ts = ai->second.ts;
//aid->msg = " "; /* no message again */
aid->msg =ai->second.msg;
aid->url = ai->second.url;
aid->grp = ai->second.grp;
aid->lev = ai->second.lev;
#ifdef _CNT_ATOMIC
aid->on_counter.store(ai->second.on_counter);
aid->off_counter.store(ai->second.off_counter);
#else
aid->on_counter = ai->second.on_counter;
aid->off_counter = ai->second.off_counter;
#endif
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
aid->receivers = ai->second.receivers;
//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 (aid->done) //TODO: done seems useless
{
/*
* if already ACKnowledged and visualized
* remove from "alarmed" list
......@@ -5193,9 +6253,11 @@ void AlarmHandler::prepare_alarm_attr()
alarmed.erase(aid);
alarmedlock->writerOut();
alarmedlock->readerIn();
} else {
aid->done = true;
}
//else
//{
// aid->done = true;
//}
} /* if */
} /* if */
alarmedlock->readerOut();
......@@ -5213,8 +6275,8 @@ void AlarmHandler::prepare_alarm_attr()
alarmSummary_sz++;
} /* for */
*attr_alarmAudible_read = is_audible;
alarms.vlock->readerOut();
prepare_alm_mtx->unlock();
alarms.vlock->readerOut();
vector<string> tmp_alarm_table;
string is_new;
ostringstream os1;
......@@ -5222,7 +6284,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)
{
......@@ -5248,7 +6310,7 @@ void AlarmHandler::prepare_alarm_attr()
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->on_counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new;
<< "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new;
tmp_alarm_table.push_back(os.str());
}
}
......@@ -5275,21 +6337,49 @@ void AlarmHandler::prepare_alarm_attr()
strncpy(dss[i],tmp_alarm_table[i].c_str(), len);
dss[i][len]=0;
}
#ifdef _ZEROS_ALARM_EMPTY
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 ";
os1 << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << -1 << "\t" << 0 << "\t" << 0 << "\t ";
//ds[0] = CORBA::string_dup(os1.str().c_str());
size_t len=os1.str().length();
if(len >= 10124) len = 10124-1;
strncpy(dss[i],os1.str().c_str(), len);
dss[i][len]=0;
}
#endif
dslock->writerOut();
}
void AlarmHandler::prepare_event_list()
{
eventList_sz=0;
list<string> evl;
events->show(evl);
for(auto &ev : evl)
{
eventList_read[eventList_sz] = ev;
attr_eventList_read[eventList_sz] = const_cast<char*>(eventList_read[eventList_sz].c_str());
eventList_sz++;
}
}
void AlarmHandler::prepare_event_summary()
{
eventSummary_sz=0;
list<string> evs;
events->summary(evs);
for(auto &ev : evs)
{
eventSummary_read[eventSummary_sz] = ev;
attr_eventSummary_read[eventSummary_sz] = const_cast<char*>(eventSummary_read[eventSummary_sz].c_str());
eventSummary_sz++;
}
}
//=============================================================================
string AlarmHandler::remove_domain(string str)
{
......@@ -5334,51 +6424,94 @@ void AlarmHandler::put_signal_property()
{
vector<string> prop;
alarms.vlock->readerIn();
alarm_container_t::iterator it;
for(it = alarms.v_alarm.begin(); it != alarms.v_alarm.end(); it++)
auto local_alarms(alarms.v_alarm);
alarms.vlock->readerOut();
for(auto &it:local_alarms)
{
prop.push_back(it->first);
prop.push_back(it.first);
string conf_str;
it->second.confstr(conf_str);
map<string,string>::iterator itmap = saved_alarms.find(it->first);
it.second.confstr(conf_str);
savedlock->readerIn();
auto itmap = saved_alarms.find(it.first);
if(itmap == saved_alarms.end())
{
DEBUG_STREAM << __func__<<": SAVING " << it->first << endl;
alarms.save_alarm_conf_db(it->second.attr_name, it->second.name, it->second.stat, it->second.ack, it->second.enabled,
it->second.formula, it->second.on_delay, it->second.off_delay, it->second.grp2str(), it->second.lev, it->second.msg, it->second.cmd_name_a, it->second.cmd_name_n, it->second.silent_time);
saved_alarms.insert(make_pair(it->first,conf_str));
savedlock->readerOut();
DEBUG_STREAM << __func__<<": SAVING '" <<it.first << "'" << endl;
DECLARE_TIME_VAR t0, t1;
GET_TIME(t0);
alarms.save_alarm_conf_db(it.second.attr_name,it.second.name,it.second.stat,it.second.ack,it.second.enabled,
it.second.formula,it.second.on_delay,it.second.off_delay,it.second.grp2str(),it.second.lev,it.second.msg,it.second.url,it.second.cmd_name_a,it.second.cmd_name_n,it.second.receivers,it.second.silent_time);
GET_TIME(t1);
DEBUG_STREAM << __func__ << ": SAVED '" <<it.first << "' in " << ELAPSED(t0, t1) << " ms" << endl;
//alarms.vlock->readerOut();//TODO: avoid keeping lock
savedlock->writerIn();
saved_alarms.insert(make_pair(it.first,conf_str));
savedlock->writerOut();
//alarms.vlock->readerIn();//TODO: avoid keeping lock
}
else
{
string conf_string;
it->second.confstr(conf_string);
it.second.confstr(conf_string);
//alarm found but configuration changed
if(conf_string != itmap->second)
{
DEBUG_STREAM << __func__<<": UPDATING " << it->first << endl;
alarms.save_alarm_conf_db(it->second.attr_name, it->second.name, it->second.stat, it->second.ack, it->second.enabled,
it->second.formula, it->second.on_delay, it->second.off_delay, it->second.grp2str(), it->second.lev, it->second.msg, it->second.cmd_name_a, it->second.cmd_name_n, it->second.silent_time);
DEBUG_STREAM << __func__<<": UPDATING " <<it.first << " because conf changed: \""<<conf_string<<"\"<<---"<< itmap->second << endl;
DECLARE_TIME_VAR t0, t1;
GET_TIME(t0);
itmap->second = conf_string;
savedlock->readerOut();
alarms.save_alarm_conf_db(it.second.attr_name,it.second.name,it.second.stat,it.second.ack,it.second.enabled,
it.second.formula,it.second.on_delay,it.second.off_delay,it.second.grp2str(),it.second.lev,it.second.msg,it.second.url,it.second.cmd_name_a,it.second.cmd_name_n,it.second.receivers,it.second.silent_time);
GET_TIME(t1);
DEBUG_STREAM << __func__ << ": UPDATED '" <<it.first << "' in " << ELAPSED(t0, t1) << " ms" << endl;
}
else
{
savedlock->readerOut();
}
}
}
// Identify the alarms that need to be removed.
// The alarms that have been identified to be removed have their tag
// stored in a std::vector. The vector is later iterated over in a second
// step when the alarms get removed.
savedlock->readerIn();
map<string, string>::iterator it2=saved_alarms.begin();
vector< string > alarms_to_be_erased;
while(it2 != saved_alarms.end())
{
alarm_container_t::iterator found = alarms.v_alarm.find(it2->first);
if (found == alarms.v_alarm.end())
if(!it2->first.empty())//TODO: should not be needed, bug if it happens
{
DEBUG_STREAM << __func__<<": DELETING " << it2->first << endl;
alarms.delete_alarm_conf_db(it2->first);
saved_alarms.erase(it2);
auto found = local_alarms.find(it2->first);
if (found == local_alarms.end())
{
alarms_to_be_erased.push_back(it2->first);
}
}
if(it2 != saved_alarms.end())
it2++;
}
alarms.vlock->readerOut();
savedlock->readerOut();
// Now remove the alarms from the property in the TangoDB and saved_alarms.
if(!alarms_to_be_erased.empty())
{
savedlock->writerIn();
for(auto iter{alarms_to_be_erased.begin()}; iter != alarms_to_be_erased.end(); ++iter)
{
DEBUG_STREAM << __func__<<": DELETING '" << *iter << "' saved_alarms.size=" << saved_alarms.size() << endl;
DECLARE_TIME_VAR t0, t1;
GET_TIME(t0);
alarms.delete_alarm_conf_db(*iter);
GET_TIME(t1);
DEBUG_STREAM << __func__ << ": DELETED '" << *iter << "' in " << ELAPSED(t0, t1) << " ms saved_alarms.size=" << saved_alarms.size() << endl;
saved_alarms.erase(saved_alarms.find(*iter));
}
savedlock->writerOut();
}
Tango::DbData data;
data.push_back(Tango::DbDatum("AlarmList"));
......@@ -5421,6 +6554,24 @@ void AlarmHandler::put_signal_property()
}
delete db;
}
//=============================================================================
//=============================================================================
bool AlarmHandler::check_signal_property()
{
savedlock->readerIn();
size_t saved_size=saved_alarms.size();
savedlock->readerOut();
alarms.vlock->readerIn();
size_t alarm_size=alarms.v_alarm.size();
alarms.vlock->readerOut();
if (saved_size<alarm_size)
{
DEBUG_STREAM << "AlarmHandler::"<<__func__<<": saved_size="<<saved_size<<" alarm_size="<< alarm_size << endl;
return true;
}
return false;
}
//--------------------------------------------------------
/**
* remove a AlarmState dynamic attribute without cleaning DB.
......@@ -5440,5 +6591,104 @@ void AlarmHandler::remove_AlarmState_dynamic_attribute_no_clean_db(string attnam
}
void AlarmHandler::parse_alarm(string &alarm_string, alarm_t &alm)
{
alarm_parse al_gr(alm); // Construct Spirit grammar
alm.name.clear();
alm.attr_name.clear();
alm.quality = Tango::ATTR_VALID;
alm.ex_reason.clear();
alm.ex_desc.clear();
alm.ex_origin.clear();
alm.formula.clear();
alm.msg.clear();
alm.url.clear();
alm.lev.clear();
alm.grp=0;
alm.to_be_evaluated = false;
alm.on_delay = 0;
alm.off_delay = 0;
alm.silent_time = -1;
alm.silenced = -1;
alm.cmd_name_a.clear();
alm.cmd_dp_a.clear();
alm.cmd_action_a.clear();
alm.send_arg_a = false;
alm.dp_a = NULL;
alm.cmd_name_n.clear();
alm.cmd_dp_n.clear();
alm.cmd_action_n.clear();
alm.send_arg_n = false;
alm.dp_n = NULL;
alm.enabled=true;
alm.shelved=false;
alm.receivers.clear();
alm.formula_tree =
//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces
if (alm.formula_tree.full)
{
if (alm.name.empty() || alm.formula.empty() || alm.msg.empty() ||
((alm.lev!=LEV_LOG)&&(alm.lev!=LEV_WARNING)&&(alm.lev!=LEV_FAULT)&&(alm.lev!=LEV_LOWEST)&&
(alm.lev!=LEV_LOW)&&(alm.lev!=LEV_MEDIUM)&&(alm.lev!=LEV_HIGH)&&(alm.lev!=LEV_HIGHEST)&&(!alm.lev.empty())))
{
ostringstream o;
o << __func__<<": Parsing Failed, at least "<<NAME_KEY<<","<<FORMULA_KEY<<","<<LEVEL_KEY<<","<<MESSAGE_KEY<<" must be specified"; //TODO
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Parsing Failed!", \
(const char*)o.str().c_str(), \
(const char*)__func__, Tango::ERR);
}
std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower); //transform to lowercase
//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower); //transform to lowercase: incorrect, state has to be written upercase
std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower); //transform to lowercase
alm.msg = std::regex_replace(alm.msg, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
alm.url = std::regex_replace(alm.url, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
alm.receivers = std::regex_replace(alm.receivers, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
if(alm.cmd_name_a.length() > 0)
{
const char *c = alm.cmd_name_a.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_a.push_back(*c);
else if (*c != '/')
alm.cmd_action_a.push_back(*c);
c++;
}
}
if(alm.cmd_name_n.length() > 0)
{
const char *c = alm.cmd_name_n.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_n.push_back(*c);
else if (*c != '/')
alm.cmd_action_n.push_back(*c);
c++;
}
}
}
else
{
ostringstream o;
o << __func__<<": Parsing Failed, parsed up to '" << string(alarm_string.begin(), alm.formula_tree.stop) << "' not parsed '" << string(alm.formula_tree.stop, alarm_string.end()) << "'"; //TODO
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Parsing Failed!", \
(const char*)o.str().c_str(), \
(const char*)__func__, Tango::ERR);
}
}
/*----- PROTECTED REGION END -----*/ // AlarmHandler::namespace_ending
} // namespace
......@@ -33,8 +33,7 @@
#ifndef AlarmHandler_H
#define AlarmHandler_H
#include <tango.h>
#include <mysql.h>
#include <tango/tango.h>
#include <boost/version.hpp>
#if BOOST_VERSION >= 103600
......@@ -62,7 +61,15 @@ class update_thread;
# define ELAPSED(before, after) \
1000.0*(after.tv_sec-before.tv_sec) + \
((double)after.tv_usec-before.tv_usec) / 1000
#ifndef TANGO_LOG
#define TANGO_LOG cout
#endif
#ifndef TANGO_LOG_INFO
#define TANGO_LOG_INFO cout2
#endif
#ifndef TANGO_LOG_DEBUG
#define TANGO_LOG_DEBUG cout4
#endif
/*----- PROTECTED REGION END -----*/ // AlarmHandler.h
......@@ -101,10 +108,6 @@ class AlarmHandler : public TANGO_BASE_CLASS
public:
bool compare_without_domain(string str1, string str2);
string remove_domain(string str);
//TODO: real attributes
Tango::DevLong attr_AttributeStartedNumber_read;
Tango::DevLong attr_AttributePausedNumber_read;
Tango::DevLong attr_AttributeStoppedNumber_read;
Tango::DevLong attr_AttributeNumber_read;
string normalAlarms_read[MAX_ALARMS];
......@@ -116,6 +119,9 @@ public:
string silencedAlarms_read[MAX_ALARMS];
string listAlarms_read[MAX_ALARMS];
string alarmSummary_read[MAX_ALARMS];
string eventList_read[MAX_ATTR_SUMMARY];
string eventSummary_read[MAX_ATTR_SUMMARY];
string alarmDisabled_read[MAX_ALARMS];
/* char c_normalAlarms_read[MAX_ALARMS][MAX_ATTR_NAME];
char c_unacknowledgedAlarms_read[MAX_ALARMS][MAX_ATTR_NAME];
......@@ -137,6 +143,9 @@ public:
size_t silencedAlarms_sz;
size_t listAlarms_sz;
size_t alarmSummary_sz;
size_t eventList_sz;
size_t eventSummary_sz;
size_t alarmDisabled_sz;
double last_statistics_reset_time;
......@@ -152,6 +161,10 @@ public:
Tango::DevLong subscribeRetryPeriod;
// StatisticsTimeWindow: Time window to compute statistics in seconds
vector<Tango::DevLong> statisticsTimeWindow;
// ErrorDelay: Delay in seconds before changing to ERROR state after an exception is received.
Tango::DevULong errorDelay;
// SetAlarmQuality: Set alarm attribute quality as computed using quality of attributes in the formula
Tango::DevBoolean setAlarmQuality;
// Attribute data members
public:
......@@ -168,6 +181,9 @@ public:
Tango::DevString *attr_alarmList_read;
Tango::DevDouble *attr_alarmFrequency_read;
Tango::DevString *attr_alarmSummary_read;
Tango::DevString *attr_eventList_read;
Tango::DevString *attr_eventSummary_read;
Tango::DevString *attr_alarmDisabled_read;
// Constructors and destructors
public:
......@@ -346,6 +362,33 @@ public:
*/
virtual void read_alarmSummary(Tango::Attribute &attr);
virtual bool is_alarmSummary_allowed(Tango::AttReqType type);
/**
* Attribute eventList related methods
* Description: List of all subscribed attributes
*
* Data type: Tango::DevString
* Attr type: Spectrum max = 10000
*/
virtual void read_eventList(Tango::Attribute &attr);
virtual bool is_eventList_allowed(Tango::AttReqType type);
/**
* Attribute eventSummary related methods
* Description:
*
* Data type: Tango::DevString
* Attr type: Spectrum max = 10000
*/
virtual void read_eventSummary(Tango::Attribute &attr);
virtual bool is_eventSummary_allowed(Tango::AttReqType type);
/**
* Attribute alarmDisabled related methods
* Description: List of alarms in out of service or shelved state
*
* Data type: Tango::DevString
* Attr type: Spectrum max = 10000
*/
virtual void read_alarmDisabled(Tango::Attribute &attr);
virtual bool is_alarmDisabled_allowed(Tango::AttReqType type);
// Dynamic attribute methods
public:
......@@ -494,6 +537,13 @@ public:
*/
virtual Tango::DevVarStringArray *get_alarm_info(const Tango::DevVarStringArray *argin);
virtual bool is_GetAlarmInfo_allowed(const CORBA::Any &any);
/**
* Command ReLoadAll related method
* Description: Re Load all alarms.
*
*/
virtual void re_load_all();
virtual bool is_ReLoadAll_allowed(const CORBA::Any &any);
//--------------------------------------------------------
......@@ -529,6 +579,7 @@ private:
ReadersWritersLock *dslock;
int period; //subscribe thread period
map<string, string> saved_alarms;
ReadersWritersLock *savedlock;
static int instanceCounter;
......@@ -541,14 +592,14 @@ private:
#if 0
void init_alarms(map< string,vector<string> > &alarm_events);
#endif
void add_alarm(alarm_t& a, bool starting=false) throw(string&);
void add_event(alarm_t& a, vector<string> &evn) throw(string&);
void add_alarm(alarm_t& a, bool starting=false);
void add_event(alarm_t& a, vector<string> &evn);
#if 0
void subscribe_event(alarm_t& a, EventCallBack& ecb, vector<string> &evn) throw(string&);
void subscribe_event(alarm_t& a, EventCallBack& ecb, vector<string> &evn);
#endif
// void do_alarm(bei_t& e); //gcc 4 problem??
bool remove_alarm(string& s) throw(string&);
//void add_to_database(alarm_t& a) throw(string&);
bool remove_alarm(string& s);
//void add_to_database(alarm_t& a);
void set_internal_alarm(string name, Tango::TimeVal t, string msg, unsigned int count=1);
void load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn);
......@@ -556,17 +607,24 @@ 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< 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
void prepare_event_list();
void prepare_event_summary();
void remove_AlarmState_dynamic_attribute_no_clean_db(string attname);
void parse_alarm(string &alarm_string, alarm_t &alm);
SubscribeThread *thread;
public:
void put_signal_property();
bool check_signal_property();
void do_alarm(bei_t& e); //public instead of protected for gcc 4 problem??
bool do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal ts);
void timer_update(); //public instead of protected for gcc 4 problem??
......
<?xml version="1.0" encoding="ASCII"?>
<pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://www.esrf.fr/tango/pogo/PogoDsl">
<classes name="AlarmHandler" pogoRevision="9.4">
<description description="Elettra alarm handler device server" title="Elettra alarm handler device server" sourcePath="/home/graziano/ws/alarmhandler/src" language="Cpp" filestogenerate="XMI file,Code files,Protected Regions" license="GPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false">
<classes name="AlarmHandler" pogoRevision="9.6">
<description description="Elettra alarm handler device server" title="Elettra alarm handler device server" sourcePath="/home/graziano/ws/alarm-handler/src" language="Cpp" filestogenerate="XMI file,Code files,Protected Regions" license="GPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false">
<inheritances classname="Device_4Impl" sourcePath=""/>
<identification contact="at elettra.eu - graziano.scalamera" author="graziano.scalamera" emailDomain="elettra.eu" classFamily="SoftwareSystem" siteSpecific="" platform="Unix Like" bus="Not Applicable" manufacturer="" reference=""/>
</description>
<classProperties name="GroupNames" description="Labels for Group mask, first is for mask 0x00">
<type xsi:type="pogoDsl:StringVectorType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</classProperties>
<classProperties name="SubscribeRetryPeriod" description="Retry subscription period in seconds">
<type xsi:type="pogoDsl:IntType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<DefaultPropValue>30</DefaultPropValue>
</classProperties>
<classProperties name="StatisticsTimeWindow" description="Time window to compute statistics in seconds">
<type xsi:type="pogoDsl:IntVectorType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<DefaultPropValue>60</DefaultPropValue>
</classProperties>
<classProperties name="ErrorDelay" description="Delay in seconds before changing to ERROR state after an exception is received.">
<type xsi:type="pogoDsl:UIntType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<DefaultPropValue>30</DefaultPropValue>
</classProperties>
<classProperties name="SetAlarmQuality" description="Set alarm attribute quality as computed using quality of attributes in the formula">
<type xsi:type="pogoDsl:BooleanType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<DefaultPropValue>false</DefaultPropValue>
</classProperties>
<deviceProperties name="GroupNames" description="Labels for Group mask, first is for mask 0x00">
<type xsi:type="pogoDsl:StringVectorType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
......@@ -19,6 +43,16 @@
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<DefaultPropValue>60</DefaultPropValue>
</deviceProperties>
<deviceProperties name="ErrorDelay" description="Delay in seconds before changing to ERROR state after an exception is received.">
<type xsi:type="pogoDsl:UIntType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<DefaultPropValue>30</DefaultPropValue>
</deviceProperties>
<deviceProperties name="SetAlarmQuality" description="Set alarm attribute quality as computed using quality of attributes in the formula">
<type xsi:type="pogoDsl:BooleanType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<DefaultPropValue>false</DefaultPropValue>
</deviceProperties>
<commands name="State" description="This command gets the device state (stored in its &lt;i>device_state&lt;/i> data member) and returns it to the caller." execMethod="dev_state" displayLevel="OPERATOR" polledPeriod="0">
<argin description="none.">
<type xsi:type="pogoDsl:VoidType"/>
......@@ -154,10 +188,19 @@
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="ReLoadAll" description="Re Load all alarms." execMethod="re_load_all" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<attributes name="alarmAudible" attType="Scalar" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="" maxY="" allocReadMember="true" isDynamic="false">
<dataType xsi:type="pogoDsl:BooleanType"/>
<changeEvent fire="true" libCheckCriteria="false"/>
<archiveEvent fire="true" libCheckCriteria="false"/>
<changeEvent fire="true" libCheckCriteria="true"/>
<archiveEvent fire="true" libCheckCriteria="true"/>
<dataReadyEvent fire="false" libCheckCriteria="true"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="True if there is at least one alarm that needs audible indication on the GUI" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
......@@ -257,6 +300,30 @@
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
</attributes>
<attributes name="eventList" attType="Spectrum" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="10000" maxY="" allocReadMember="true" isDynamic="false">
<dataType xsi:type="pogoDsl:StringType"/>
<changeEvent fire="false" libCheckCriteria="true"/>
<archiveEvent fire="false" libCheckCriteria="true"/>
<dataReadyEvent fire="false" libCheckCriteria="true"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="List of all subscribed attributes" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
</attributes>
<attributes name="eventSummary" attType="Spectrum" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="10000" maxY="" allocReadMember="true" isDynamic="false">
<dataType xsi:type="pogoDsl:StringType"/>
<changeEvent fire="false" libCheckCriteria="true"/>
<archiveEvent fire="false" libCheckCriteria="true"/>
<dataReadyEvent fire="false" libCheckCriteria="true"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
</attributes>
<attributes name="alarmDisabled" attType="Spectrum" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="10000" maxY="" allocReadMember="true" isDynamic="false">
<dataType xsi:type="pogoDsl:StringType"/>
<changeEvent fire="true" libCheckCriteria="true"/>
<archiveEvent fire="true" libCheckCriteria="true"/>
<dataReadyEvent fire="false" libCheckCriteria="true"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="List of alarms in out of service or shelved state" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
</attributes>
<dynamicAttributes name="AlarmState" attType="Scalar" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="" maxY="" allocReadMember="true" isDynamic="true">
<dataType xsi:type="pogoDsl:EnumType"/>
<changeEvent fire="true" libCheckCriteria="true"/>
......@@ -275,12 +342,12 @@
</dynamicAttributes>
<dynamicAttributes name="AlarmFormula" attType="Scalar" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="" maxY="" allocReadMember="true" isDynamic="true">
<dataType xsi:type="pogoDsl:StringType"/>
<changeEvent fire="true" libCheckCriteria="false"/>
<archiveEvent fire="true" libCheckCriteria="false"/>
<changeEvent fire="true" libCheckCriteria="true"/>
<archiveEvent fire="true" libCheckCriteria="true"/>
<dataReadyEvent fire="false" libCheckCriteria="true"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
</dynamicAttributes>
<preferences docHome="./doc_html" makefileHome="/usr/local/tango-9.2.5a/share/pogo/preferences"/>
<preferences docHome="./doc_html" makefileHome="/usr/local/tango-9.3.3/share/pogo/preferences"/>
</classes>
</pogoDsl:PogoSystem>
/*----- PROTECTED REGION ID(AlarmHandlerClass.cpp) ENABLED START -----*/
static const char *RcsId = "$Id: $";
static const char *TagName = "$Name: $";
static const char *CvsPath = "$Source: $";
static const char *SvnPath = "$HeadURL: $";
static const char *HttpServer = "http://www.esrf.eu/computing/cs/tango/tango_doc/ds_doc/";
//=============================================================================
//
// file : AlarmHandlerClass.cpp
......@@ -78,15 +73,16 @@ AlarmHandlerClass *AlarmHandlerClass::_instance = NULL;
//--------------------------------------------------------
AlarmHandlerClass::AlarmHandlerClass(string &s):Tango::DeviceClass(s)
{
cout2 << "Entering AlarmHandlerClass constructor" << endl;
TANGO_LOG_INFO << "Entering AlarmHandlerClass constructor" << endl;
set_default_property();
get_class_property();
write_class_property();
/*----- PROTECTED REGION ID(AlarmHandlerClass::constructor) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // AlarmHandlerClass::constructor
cout2 << "Leaving AlarmHandlerClass constructor" << endl;
TANGO_LOG_INFO << "Leaving AlarmHandlerClass constructor" << endl;
}
//--------------------------------------------------------
......@@ -166,7 +162,7 @@ AlarmHandlerClass *AlarmHandlerClass::instance()
//--------------------------------------------------------
CORBA::Any *AckClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "AckClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "AckClass::execute(): arrived" << endl;
const Tango::DevVarStringArray *argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->ack(argin));
......@@ -186,7 +182,7 @@ CORBA::Any *AckClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_an
//--------------------------------------------------------
CORBA::Any *LoadClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "LoadClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "LoadClass::execute(): arrived" << endl;
Tango::DevString argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->load(argin));
......@@ -206,7 +202,7 @@ CORBA::Any *LoadClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_a
//--------------------------------------------------------
CORBA::Any *RemoveClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "RemoveClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "RemoveClass::execute(): arrived" << endl;
Tango::DevString argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->remove(argin));
......@@ -226,7 +222,7 @@ CORBA::Any *RemoveClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in
//--------------------------------------------------------
CORBA::Any *SearchAlarmClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "SearchAlarmClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "SearchAlarmClass::execute(): arrived" << endl;
Tango::DevString argin;
extract(in_any, argin);
return insert((static_cast<AlarmHandler *>(device))->search_alarm(argin));
......@@ -245,7 +241,7 @@ CORBA::Any *SearchAlarmClass::execute(Tango::DeviceImpl *device, const CORBA::An
//--------------------------------------------------------
CORBA::Any *StopAudibleClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const CORBA::Any &in_any))
{
cout2 << "StopAudibleClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "StopAudibleClass::execute(): arrived" << endl;
((static_cast<AlarmHandler *>(device))->stop_audible());
return new CORBA::Any();
}
......@@ -263,7 +259,7 @@ CORBA::Any *StopAudibleClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(co
//--------------------------------------------------------
CORBA::Any *SilenceClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "SilenceClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "SilenceClass::execute(): arrived" << endl;
const Tango::DevVarStringArray *argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->silence(argin));
......@@ -283,7 +279,7 @@ CORBA::Any *SilenceClass::execute(Tango::DeviceImpl *device, const CORBA::Any &i
//--------------------------------------------------------
CORBA::Any *ModifyClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "ModifyClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "ModifyClass::execute(): arrived" << endl;
Tango::DevString argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->modify(argin));
......@@ -303,7 +299,7 @@ CORBA::Any *ModifyClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in
//--------------------------------------------------------
CORBA::Any *ShelveClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "ShelveClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "ShelveClass::execute(): arrived" << endl;
const Tango::DevVarStringArray *argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->shelve(argin));
......@@ -323,7 +319,7 @@ CORBA::Any *ShelveClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in
//--------------------------------------------------------
CORBA::Any *EnableClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "EnableClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "EnableClass::execute(): arrived" << endl;
Tango::DevString argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->enable(argin));
......@@ -343,7 +339,7 @@ CORBA::Any *EnableClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in
//--------------------------------------------------------
CORBA::Any *DisableClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "DisableClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "DisableClass::execute(): arrived" << endl;
Tango::DevString argin;
extract(in_any, argin);
((static_cast<AlarmHandler *>(device))->disable(argin));
......@@ -363,7 +359,7 @@ CORBA::Any *DisableClass::execute(Tango::DeviceImpl *device, const CORBA::Any &i
//--------------------------------------------------------
CORBA::Any *ResetStatisticsClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const CORBA::Any &in_any))
{
cout2 << "ResetStatisticsClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "ResetStatisticsClass::execute(): arrived" << endl;
((static_cast<AlarmHandler *>(device))->reset_statistics());
return new CORBA::Any();
}
......@@ -381,7 +377,7 @@ CORBA::Any *ResetStatisticsClass::execute(Tango::DeviceImpl *device, TANGO_UNUSE
//--------------------------------------------------------
CORBA::Any *StopNewClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const CORBA::Any &in_any))
{
cout2 << "StopNewClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "StopNewClass::execute(): arrived" << endl;
((static_cast<AlarmHandler *>(device))->stop_new());
return new CORBA::Any();
}
......@@ -399,12 +395,30 @@ CORBA::Any *StopNewClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const
//--------------------------------------------------------
CORBA::Any *GetAlarmInfoClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
cout2 << "GetAlarmInfoClass::execute(): arrived" << endl;
TANGO_LOG_INFO << "GetAlarmInfoClass::execute(): arrived" << endl;
const Tango::DevVarStringArray *argin;
extract(in_any, argin);
return insert((static_cast<AlarmHandler *>(device))->get_alarm_info(argin));
}
//--------------------------------------------------------
/**
* method : ReLoadAllClass::execute()
* description : method to trigger the execution of the command.
*
* @param device The device on which the command must be executed
* @param in_any The command input data
*
* returns The command output data (packed in the Any object)
*/
//--------------------------------------------------------
CORBA::Any *ReLoadAllClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const CORBA::Any &in_any))
{
TANGO_LOG_INFO << "ReLoadAllClass::execute(): arrived" << endl;
((static_cast<AlarmHandler *>(device))->re_load_all());
return new CORBA::Any();
}
//===================================================================
// Properties management
......@@ -454,6 +468,99 @@ Tango::DbDatum AlarmHandlerClass::get_default_class_property(string &prop_name)
return Tango::DbDatum(prop_name);
}
//--------------------------------------------------------
/**
* Method : AlarmHandlerClass::get_class_property()
* Description : Read database to initialize class property data members.
*/
//--------------------------------------------------------
void AlarmHandlerClass::get_class_property()
{
/*----- PROTECTED REGION ID(AlarmHandlerClass::get_class_property_before) ENABLED START -----*/
// Initialize class property data members
/*----- PROTECTED REGION END -----*/ // AlarmHandlerClass::get_class_property_before
// Read class properties from database.
cl_prop.push_back(Tango::DbDatum("GroupNames"));
cl_prop.push_back(Tango::DbDatum("SubscribeRetryPeriod"));
cl_prop.push_back(Tango::DbDatum("StatisticsTimeWindow"));
cl_prop.push_back(Tango::DbDatum("ErrorDelay"));
cl_prop.push_back(Tango::DbDatum("SetAlarmQuality"));
// Call database and extract values
if (Tango::Util::instance()->_UseDb==true)
get_db_class()->get_property(cl_prop);
Tango::DbDatum def_prop;
int i = -1;
// Try to extract GroupNames value
if (cl_prop[++i].is_empty()==false) cl_prop[i] >> groupNames;
else
{
// Check default value for GroupNames
def_prop = get_default_class_property(cl_prop[i].name);
if (def_prop.is_empty()==false)
{
def_prop >> groupNames;
cl_prop[i] << groupNames;
}
}
// Try to extract SubscribeRetryPeriod value
if (cl_prop[++i].is_empty()==false) cl_prop[i] >> subscribeRetryPeriod;
else
{
// Check default value for SubscribeRetryPeriod
def_prop = get_default_class_property(cl_prop[i].name);
if (def_prop.is_empty()==false)
{
def_prop >> subscribeRetryPeriod;
cl_prop[i] << subscribeRetryPeriod;
}
}
// Try to extract StatisticsTimeWindow value
if (cl_prop[++i].is_empty()==false) cl_prop[i] >> statisticsTimeWindow;
else
{
// Check default value for StatisticsTimeWindow
def_prop = get_default_class_property(cl_prop[i].name);
if (def_prop.is_empty()==false)
{
def_prop >> statisticsTimeWindow;
cl_prop[i] << statisticsTimeWindow;
}
}
// Try to extract ErrorDelay value
if (cl_prop[++i].is_empty()==false) cl_prop[i] >> errorDelay;
else
{
// Check default value for ErrorDelay
def_prop = get_default_class_property(cl_prop[i].name);
if (def_prop.is_empty()==false)
{
def_prop >> errorDelay;
cl_prop[i] << errorDelay;
}
}
// Try to extract SetAlarmQuality value
if (cl_prop[++i].is_empty()==false) cl_prop[i] >> setAlarmQuality;
else
{
// Check default value for SetAlarmQuality
def_prop = get_default_class_property(cl_prop[i].name);
if (def_prop.is_empty()==false)
{
def_prop >> setAlarmQuality;
cl_prop[i] << setAlarmQuality;
}
}
/*----- PROTECTED REGION ID(AlarmHandlerClass::get_class_property_after) ENABLED START -----*/
// Check class property data members init
/*----- PROTECTED REGION END -----*/ // AlarmHandlerClass::get_class_property_after
}
//--------------------------------------------------------
/**
......@@ -472,6 +579,75 @@ void AlarmHandlerClass::set_default_property()
vector<string> vect_data;
// Set Default Class Properties
prop_name = "GroupNames";
prop_desc = "Labels for Group mask, first is for mask 0x00";
prop_def = "";
vect_data.clear();
if (prop_def.length()>0)
{
Tango::DbDatum data(prop_name);
data << vect_data ;
cl_def_prop.push_back(data);
add_wiz_class_prop(prop_name, prop_desc, prop_def);
}
else
add_wiz_class_prop(prop_name, prop_desc);
prop_name = "SubscribeRetryPeriod";
prop_desc = "Retry subscription period in seconds";
prop_def = "30";
vect_data.clear();
vect_data.push_back("30");
if (prop_def.length()>0)
{
Tango::DbDatum data(prop_name);
data << vect_data ;
cl_def_prop.push_back(data);
add_wiz_class_prop(prop_name, prop_desc, prop_def);
}
else
add_wiz_class_prop(prop_name, prop_desc);
prop_name = "StatisticsTimeWindow";
prop_desc = "Time window to compute statistics in seconds";
prop_def = "60";
vect_data.clear();
vect_data.push_back("60");
if (prop_def.length()>0)
{
Tango::DbDatum data(prop_name);
data << vect_data ;
cl_def_prop.push_back(data);
add_wiz_class_prop(prop_name, prop_desc, prop_def);
}
else
add_wiz_class_prop(prop_name, prop_desc);
prop_name = "ErrorDelay";
prop_desc = "Delay in seconds before changing to ERROR state after an exception is received.";
prop_def = "30";
vect_data.clear();
vect_data.push_back("30");
if (prop_def.length()>0)
{
Tango::DbDatum data(prop_name);
data << vect_data ;
cl_def_prop.push_back(data);
add_wiz_class_prop(prop_name, prop_desc, prop_def);
}
else
add_wiz_class_prop(prop_name, prop_desc);
prop_name = "SetAlarmQuality";
prop_desc = "Set alarm attribute quality as computed using quality of attributes in the formula";
prop_def = "false";
vect_data.clear();
vect_data.push_back("false");
if (prop_def.length()>0)
{
Tango::DbDatum data(prop_name);
data << vect_data ;
cl_def_prop.push_back(data);
add_wiz_class_prop(prop_name, prop_desc, prop_def);
}
else
add_wiz_class_prop(prop_name, prop_desc);
// Set Default device Properties
prop_name = "GroupNames";
......@@ -515,6 +691,34 @@ void AlarmHandlerClass::set_default_property()
}
else
add_wiz_dev_prop(prop_name, prop_desc);
prop_name = "ErrorDelay";
prop_desc = "Delay in seconds before changing to ERROR state after an exception is received.";
prop_def = "30";
vect_data.clear();
vect_data.push_back("30");
if (prop_def.length()>0)
{
Tango::DbDatum data(prop_name);
data << vect_data ;
dev_def_prop.push_back(data);
add_wiz_dev_prop(prop_name, prop_desc, prop_def);
}
else
add_wiz_dev_prop(prop_name, prop_desc);
prop_name = "SetAlarmQuality";
prop_desc = "Set alarm attribute quality as computed using quality of attributes in the formula";
prop_def = "false";
vect_data.clear();
vect_data.push_back("false");
if (prop_def.length()>0)
{
Tango::DbDatum data(prop_name);
data << vect_data ;
dev_def_prop.push_back(data);
add_wiz_dev_prop(prop_name, prop_desc, prop_def);
}
else
add_wiz_dev_prop(prop_name, prop_desc);
}
//--------------------------------------------------------
......@@ -580,7 +784,7 @@ void AlarmHandlerClass::device_factory(const Tango::DevVarStringArray *devlist_p
// Create devices and add it into the device list
for (unsigned long i=0 ; i<devlist_ptr->length() ; i++)
{
cout4 << "Device name : " << (*devlist_ptr)[i].in() << endl;
TANGO_LOG_DEBUG << "Device name : " << (*devlist_ptr)[i].in() << endl;
device_list.push_back(new AlarmHandler(this, (*devlist_ptr)[i]));
}
......@@ -643,8 +847,8 @@ void AlarmHandlerClass::attribute_factory(vector<Tango::Attr *> &att_list)
// Not Polled
alarmaudible->set_disp_level(Tango::OPERATOR);
// Not Memorized
alarmaudible->set_change_event(true, false);
alarmaudible->set_archive_event(true, false);
alarmaudible->set_change_event(true, true);
alarmaudible->set_archive_event(true, true);
att_list.push_back(alarmaudible);
// Attribute : StatisticsResetTime
......@@ -955,6 +1159,80 @@ void AlarmHandlerClass::attribute_factory(vector<Tango::Attr *> &att_list)
alarmsummary->set_archive_event(true, true);
att_list.push_back(alarmsummary);
// Attribute : eventList
eventListAttrib *eventlist = new eventListAttrib();
Tango::UserDefaultAttrProp eventlist_prop;
eventlist_prop.set_description("List of all subscribed attributes");
// label not set for eventList
// unit not set for eventList
// standard_unit not set for eventList
// display_unit not set for eventList
// format not set for eventList
// max_value not set for eventList
// min_value not set for eventList
// max_alarm not set for eventList
// min_alarm not set for eventList
// max_warning not set for eventList
// min_warning not set for eventList
// delta_t not set for eventList
// delta_val not set for eventList
eventlist->set_default_properties(eventlist_prop);
// Not Polled
eventlist->set_disp_level(Tango::OPERATOR);
// Not Memorized
att_list.push_back(eventlist);
// Attribute : eventSummary
eventSummaryAttrib *eventsummary = new eventSummaryAttrib();
Tango::UserDefaultAttrProp eventsummary_prop;
// description not set for eventSummary
// label not set for eventSummary
// unit not set for eventSummary
// standard_unit not set for eventSummary
// display_unit not set for eventSummary
// format not set for eventSummary
// max_value not set for eventSummary
// min_value not set for eventSummary
// max_alarm not set for eventSummary
// min_alarm not set for eventSummary
// max_warning not set for eventSummary
// min_warning not set for eventSummary
// delta_t not set for eventSummary
// delta_val not set for eventSummary
eventsummary->set_default_properties(eventsummary_prop);
// Not Polled
eventsummary->set_disp_level(Tango::OPERATOR);
// Not Memorized
att_list.push_back(eventsummary);
// Attribute : alarmDisabled
alarmDisabledAttrib *alarmdisabled = new alarmDisabledAttrib();
Tango::UserDefaultAttrProp alarmdisabled_prop;
alarmdisabled_prop.set_description("List of alarms in out of service or shelved state");
// label not set for alarmDisabled
// unit not set for alarmDisabled
// standard_unit not set for alarmDisabled
// display_unit not set for alarmDisabled
// format not set for alarmDisabled
// max_value not set for alarmDisabled
// min_value not set for alarmDisabled
// max_alarm not set for alarmDisabled
// min_alarm not set for alarmDisabled
// max_warning not set for alarmDisabled
// min_warning not set for alarmDisabled
// delta_t not set for alarmDisabled
// delta_val not set for alarmDisabled
alarmdisabled->set_default_properties(alarmdisabled_prop);
// Not Polled
alarmdisabled->set_disp_level(Tango::OPERATOR);
// Not Memorized
alarmdisabled->set_change_event(true, true);
alarmdisabled->set_archive_event(true, true);
att_list.push_back(alarmdisabled);
// Create a list of static attributes
create_static_attribute_list(get_class_attr()->get_attr_list());
......@@ -1117,6 +1395,15 @@ void AlarmHandlerClass::command_factory()
Tango::OPERATOR);
command_list.push_back(pGetAlarmInfoCmd);
// Command ReLoadAll
ReLoadAllClass *pReLoadAllCmd =
new ReLoadAllClass("ReLoadAll",
Tango::DEV_VOID, Tango::DEV_VOID,
"",
"",
Tango::OPERATOR);
command_list.push_back(pReLoadAllCmd);
/*----- PROTECTED REGION ID(AlarmHandlerClass::command_factory_after) ENABLED START -----*/
// Add your own code
......@@ -1145,7 +1432,7 @@ void AlarmHandlerClass::create_static_attribute_list(vector<Tango::Attr *> &att_
defaultAttList.push_back(att_name);
}
cout2 << defaultAttList.size() << " attributes in default list" << endl;
TANGO_LOG_INFO << defaultAttList.size() << " attributes in default list" << endl;
/*----- PROTECTED REGION ID(AlarmHandlerClass::create_static_att_list) ENABLED START -----*/
......@@ -1181,7 +1468,7 @@ void AlarmHandlerClass::erase_dynamic_attributes(const Tango::DevVarStringArray
vector<string>::iterator ite_str = find(defaultAttList.begin(), defaultAttList.end(), att_name);
if (ite_str == defaultAttList.end())
{
cout2 << att_name << " is a UNWANTED dynamic attribute for device " << (*devlist_ptr)[i] << endl;
TANGO_LOG_INFO << att_name << " is a UNWANTED dynamic attribute for device " << (*devlist_ptr)[i] << endl;
Tango::Attribute &att = dev->get_device_attr()->get_attr_by_name(att_name.c_str());
dev->remove_attribute(att_list[att.get_attr_idx()], true, false);
--ite_att;
......@@ -1195,7 +1482,7 @@ void AlarmHandlerClass::erase_dynamic_attributes(const Tango::DevVarStringArray
//--------------------------------------------------------
/**
* Method : AlarmHandlerClass::get_attr_by_name()
* Method : AlarmHandlerClass::get_attr_object_by_name()
* Description : returns Tango::Attr * object found by name
*/
//--------------------------------------------------------
......
......@@ -37,7 +37,7 @@
#ifndef AlarmHandlerClass_H
#define AlarmHandlerClass_H
#include <tango.h>
#include <tango/tango.h>
#include <AlarmHandler.h>
......@@ -223,6 +223,45 @@ public:
{return (static_cast<AlarmHandler *>(dev))->is_alarmSummary_allowed(ty);}
};
// Attribute eventList class definition
class eventListAttrib: public Tango::SpectrumAttr
{
public:
eventListAttrib():SpectrumAttr("eventList",
Tango::DEV_STRING, Tango::READ, 10000) {};
~eventListAttrib() {};
virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
{(static_cast<AlarmHandler *>(dev))->read_eventList(att);}
virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
{return (static_cast<AlarmHandler *>(dev))->is_eventList_allowed(ty);}
};
// Attribute eventSummary class definition
class eventSummaryAttrib: public Tango::SpectrumAttr
{
public:
eventSummaryAttrib():SpectrumAttr("eventSummary",
Tango::DEV_STRING, Tango::READ, 10000) {};
~eventSummaryAttrib() {};
virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
{(static_cast<AlarmHandler *>(dev))->read_eventSummary(att);}
virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
{return (static_cast<AlarmHandler *>(dev))->is_eventSummary_allowed(ty);}
};
// Attribute alarmDisabled class definition
class alarmDisabledAttrib: public Tango::SpectrumAttr
{
public:
alarmDisabledAttrib():SpectrumAttr("alarmDisabled",
Tango::DEV_STRING, Tango::READ, 10000) {};
~alarmDisabledAttrib() {};
virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
{(static_cast<AlarmHandler *>(dev))->read_alarmDisabled(att);}
virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
{return (static_cast<AlarmHandler *>(dev))->is_alarmDisabled_allowed(ty);}
};
//=========================================
// Define classes for dynamic attributes
......@@ -558,6 +597,29 @@ public:
{return (static_cast<AlarmHandler *>(dev))->is_GetAlarmInfo_allowed(any);}
};
// Command ReLoadAll class definition
class ReLoadAllClass : public Tango::Command
{
public:
ReLoadAllClass(const char *name,
Tango::CmdArgType in,
Tango::CmdArgType out,
const char *in_desc,
const char *out_desc,
Tango::DispLevel level)
:Command(name,in,out,in_desc,out_desc, level) {};
ReLoadAllClass(const char *name,
Tango::CmdArgType in,
Tango::CmdArgType out)
:Command(name,in,out) {};
~ReLoadAllClass() {};
virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any);
virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any)
{return (static_cast<AlarmHandler *>(dev))->is_ReLoadAll_allowed(any);}
};
/**
* The AlarmHandlerClass singleton definition
......@@ -574,6 +636,18 @@ class AlarmHandlerClass : public Tango::DeviceClass
/*----- PROTECTED REGION END -----*/ // AlarmHandlerClass::Additionnal DServer data members
// Class properties data members
public:
// GroupNames: Labels for Group mask, first is for mask 0x00
vector<string> groupNames;
// SubscribeRetryPeriod: Retry subscription period in seconds
Tango::DevLong subscribeRetryPeriod;
// StatisticsTimeWindow: Time window to compute statistics in seconds
vector<Tango::DevLong> statisticsTimeWindow;
// ErrorDelay: Delay in seconds before changing to ERROR state after an exception is received.
Tango::DevULong errorDelay;
// SetAlarmQuality: Set alarm attribute quality as computed using quality of attributes in the formula
Tango::DevBoolean setAlarmQuality;
public:
// write class properties data members
Tango::DbData cl_prop;
......
......@@ -128,7 +128,7 @@ void AlarmHandler::add_AlarmState_dynamic_attribute(string attname)
//--------------------------------------------------------
void AlarmHandler::remove_AlarmState_dynamic_attribute(string attname)
{
remove_attribute(attname, true);
remove_attribute(attname, true, Tango::Util::instance()->_UseDb);
map<string,Tango::DevEnum>::iterator ite;
if ((ite=AlarmState_data.find(attname))!=AlarmState_data.end())
{
......@@ -173,8 +173,8 @@ void AlarmHandler::add_AlarmFormula_dynamic_attribute(string attname)
// Not Polled
alarmformula->set_disp_level(Tango::OPERATOR);
// Not Memorized
alarmformula->set_change_event(true, false);
alarmformula->set_archive_event(true, false);
alarmformula->set_change_event(true, true);
alarmformula->set_archive_event(true, true);
char array[1];
array[0] = '\0';
AlarmFormula_data.insert(make_pair(attname, array));
......@@ -189,7 +189,7 @@ void AlarmHandler::add_AlarmFormula_dynamic_attribute(string attname)
//--------------------------------------------------------
void AlarmHandler::remove_AlarmFormula_dynamic_attribute(string attname)
{
remove_attribute(attname, true);
remove_attribute(attname, true, Tango::Util::instance()->_UseDb);
map<string,Tango::DevString>::iterator ite;
if ((ite=AlarmFormula_data.find(attname))!=AlarmFormula_data.end())
{
......
......@@ -252,6 +252,54 @@ bool AlarmHandler::is_alarmSummary_allowed(TANGO_UNUSED(Tango::AttReqType type))
return true;
}
//--------------------------------------------------------
/**
* Method : AlarmHandler::is_eventList_allowed()
* Description : Execution allowed for eventList attribute
*/
//--------------------------------------------------------
bool AlarmHandler::is_eventList_allowed(TANGO_UNUSED(Tango::AttReqType type))
{
// Not any excluded states for eventList attribute in read access.
/*----- PROTECTED REGION ID(AlarmHandler::eventListStateAllowed_READ) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // AlarmHandler::eventListStateAllowed_READ
return true;
}
//--------------------------------------------------------
/**
* Method : AlarmHandler::is_eventSummary_allowed()
* Description : Execution allowed for eventSummary attribute
*/
//--------------------------------------------------------
bool AlarmHandler::is_eventSummary_allowed(TANGO_UNUSED(Tango::AttReqType type))
{
// Not any excluded states for eventSummary attribute in read access.
/*----- PROTECTED REGION ID(AlarmHandler::eventSummaryStateAllowed_READ) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // AlarmHandler::eventSummaryStateAllowed_READ
return true;
}
//--------------------------------------------------------
/**
* Method : AlarmHandler::is_alarmDisabled_allowed()
* Description : Execution allowed for alarmDisabled attribute
*/
//--------------------------------------------------------
bool AlarmHandler::is_alarmDisabled_allowed(TANGO_UNUSED(Tango::AttReqType type))
{
// Not any excluded states for alarmDisabled attribute in read access.
/*----- PROTECTED REGION ID(AlarmHandler::alarmDisabledStateAllowed_READ) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // AlarmHandler::alarmDisabledStateAllowed_READ
return true;
}
//--------------------------------------------------------
/**
* Method : AlarmHandler::is_AlarmState_allowed()
......@@ -484,6 +532,21 @@ bool AlarmHandler::is_GetAlarmInfo_allowed(TANGO_UNUSED(const CORBA::Any &any))
return true;
}
//--------------------------------------------------------
/**
* Method : AlarmHandler::is_ReLoadAll_allowed()
* Description : Execution allowed for ReLoadAll attribute
*/
//--------------------------------------------------------
bool AlarmHandler::is_ReLoadAll_allowed(TANGO_UNUSED(const CORBA::Any &any))
{
// Not any excluded states for ReLoadAll command.
/*----- PROTECTED REGION ID(AlarmHandler::ReLoadAllStateAllowed) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // AlarmHandler::ReLoadAllStateAllowed
return true;
}
/*----- PROTECTED REGION ID(AlarmHandler::AlarmHandlerStateAllowed.AdditionalMethods) ENABLED START -----*/
......
cmake_minimum_required(VERSION 3.2)
# source files
set(SRC_FILES ${SRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/AlarmHandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/AlarmHandlerClass.cpp
${CMAKE_CURRENT_SOURCE_DIR}/AlarmHandlerDynAttrUtils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/AlarmHandlerStateMachine.cpp
${CMAKE_CURRENT_SOURCE_DIR}/alarm_table.cpp
${CMAKE_CURRENT_SOURCE_DIR}/alarm-thread.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ClassFactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cmd_thread.cpp
${CMAKE_CURRENT_SOURCE_DIR}/event_table.cpp
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SubscribeThread.cpp
${CMAKE_CURRENT_SOURCE_DIR}/update-thread.cpp
PARENT_SCOPE)
......@@ -32,7 +32,7 @@
// (Program Obviously used to Generate tango Object)
//=============================================================================
#include <tango.h>
#include <tango/tango.h>
#include <AlarmHandlerClass.h>
// Add class header files if needed
......
static const char *RcsId = "$Header: /home/cvsadm/cvsroot/fermi/servers/hdb++/hdb++es/src/SubscribeThread.cpp,v 1.6 2014-03-06 15:21:43 graziano Exp $";
//+=============================================================================
//
// file : HdbEventHandler.cpp
//
// description : C++ source for thread management
// project : TANGO Device Server
//
// $Author: graziano $
//
// $Revision: 1.6 $
//
// $Log: SubscribeThread.cpp,v $
// Revision 1.6 2014-03-06 15:21:43 graziano
// StartArchivingAtStartup,
// start_all and stop_all,
// archiving of first event received at subscribe
//
// Revision 1.5 2014-02-20 14:59:02 graziano
// name and path fixing
// removed start acquisition from add
//
// Revision 1.4 2013-09-24 08:42:21 graziano
// bug fixing
//
// Revision 1.3 2013-09-02 12:13:22 graziano
// cleaned
//
// Revision 1.2 2013-08-23 10:04:53 graziano
// development
//
// Revision 1.1 2013-07-17 13:37:43 graziano
// *** empty log message ***
//
//
//
// copyleft : European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// FRANCE
//
//-=============================================================================
#include "AlarmHandler.h"
#include "event_table.h"
......@@ -64,6 +21,12 @@ void SubscribeThread::updateProperty()
}
//=============================================================================
//=============================================================================
void SubscribeThread::signal()
{
shared->signal();
}
//=============================================================================
//=============================================================================
void *SubscribeThread::run_undetached(void *ptr)
{
INFO_STREAM << "SubscribeThread id="<<omni_thread::self()->id()<<endl;
......@@ -71,16 +34,20 @@ void *SubscribeThread::run_undetached(void *ptr)
{
// Try to subscribe
usleep(500000); //TODO: try to delay a bit subscribe_events
if(shared->get_if_stop())
break;
DEBUG_STREAM << "SubscribeThread::"<<__func__<<": AWAKE"<<endl;
updateProperty();
alarm_dev->events->subscribe_events();
int nb_to_subscribe = shared->nb_sig_to_subscribe();
shared->check_signal_property(); //check if, while subscribing, new alarms to be saved in properties where added (update action)
// And wait a bit before next time or
// wait a long time if all signals subscribed
{
omni_mutex_lock sync(*shared);
//shared->lock();
if (nb_to_subscribe==0 && shared->action == NOTHING)
int act=shared->action.load();
if (nb_to_subscribe==0 && act == NOTHING)
{
DEBUG_STREAM << "SubscribeThread::"<<__func__<<": going to wait nb_to_subscribe=0"<<endl;
//shared->condition.wait();
......@@ -98,7 +65,7 @@ void *SubscribeThread::run_undetached(void *ptr)
//shared->unlock();
}
}
shared->unsubscribe_events();
//shared->unsubscribe_events();
INFO_STREAM <<"SubscribeThread::"<< __func__<<": exiting..."<<endl;
return NULL;
}
......
//=============================================================================
//
// file : HdbEventHandler.h
//
// description : Include for the HDbDevice class.
//
// project : Tango Device Server
//
// $Author: graziano $
//
// $Revision: 1.5 $
//
// $Log: SubscribeThread.h,v $
// Revision 1.5 2014-03-06 15:21:43 graziano
// StartArchivingAtStartup,
// start_all and stop_all,
// archiving of first event received at subscribe
//
// Revision 1.4 2013-09-24 08:42:21 graziano
// bug fixing
//
// Revision 1.3 2013-09-02 12:11:32 graziano
// cleaned
//
// Revision 1.2 2013-08-23 10:04:53 graziano
// development
//
// Revision 1.1 2013-07-17 13:37:43 graziano
// *** empty log message ***
//
//
//
// copyleft : European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// FRANCE
//
//=============================================================================
#ifndef _SUBSCRIBE_THREAD_H
#define _SUBSCRIBE_THREAD_H
#include <tango.h>
#include <eventconsumer.h>
#include <tango/tango.h>
#include <stdint.h>
#include "event_table.h"
/**
* @author $Author: graziano $
* @version $Revision: 1.5 $
*/
// constants definitions here.
//-----------------------------------------------
// constants definitions here.
//-----------------------------------------------
namespace AlarmHandler_ns
{
......@@ -82,6 +38,7 @@ public:
int period;
SubscribeThread(AlarmHandler *dev);
void updateProperty();
void signal();
/**
* Execute the thread loop.
* This thread is awaken when a command has been received
......
/*
* alarm-thread.cpp
*
* $Author: claudio $
*
* $Revision: 1.7 $
*
* $Log: alarm-thread.cpp,v $
* Revision 1.7 2015-07-21 13:40:59 claudio
* minor cleanups
*
* Revision 1.6 2013-03-06 10:41:11 claudio
* commented out debug print statements
*
* Revision 1.5 2008-07-08 12:11:39 graziano
* omni_thread_fatal exception handling
*
* Revision 1.4 2008/07/07 09:13:12 graziano
* omni_thread_fatal exception handling
*
* Revision 1.3 2008/04/24 06:51:34 graziano
* small code cleanings
*
*
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
* 34012 Basovizza, Trieste ITALY
......@@ -36,7 +14,7 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.7 $";
*/
alarm_thread::alarm_thread(AlarmHandler_ns::AlarmHandler *p) : p_Alarm(p)
{
//cout << __FILE__rev << endl;
//TANGO_LOG << __FILE__rev << endl;
}
/*
......@@ -142,21 +120,21 @@ 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());
Tango::Except::print_exception(ex);
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");
}
}
//cout << "alarm_thread::run(): returning" << endl;
//TANGO_LOG << "alarm_thread::run(): returning" << endl;
} /* alarm_thread::run() */
/*
* alarm-thread.h
*
* $Author: graziano $
*
* $Revision: 1.3 $
*
* $Log: alarm-thread.h,v $
* Revision 1.3 2008-04-23 15:00:57 graziano
* small code cleanings
*
*
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
* 34012 Basovizza, Trieste ITALY
......@@ -20,7 +10,7 @@
#define ALARM_THREAD_H
#include <omnithread.h>
#include <tango.h>
#include <tango/tango.h>
#include <AlarmHandler.h>
#define ALARM_THREAD_EXIT "alarm_thread_exit"
......
/*
* alarm_grammar.h
*
* $Author: $
*
* $Revision: $
*
* $Log: alarm_grammar.h,v $
*
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
* 34012 Basovizza, Trieste ITALY
......@@ -75,15 +68,17 @@
#define SILENT_TIME_KEY "shlvd_time"
#define GROUP_KEY "group"
#define MESSAGE_KEY "message"
#define URL_KEY "url"
#define ON_COMMAND_KEY "on_command"
#define OFF_COMMAND_KEY "off_command"
#define RECEIVERS_KEY "receivers"
#define ENABLED_KEY "enabled"
#define SILENT_TIME_REMAINING_KEY "shlvd_end"
#define SHELVED_KEY "shelved"
#define ACKNOWLEDGED_KEY "ack"
#define ATTR_VALUES_KEY "values"
#define VALUE_KEY "state"
#define VALUE_KEY "state"
#define ON_COUNTER_KEY "on_counter"
#define OFF_COUNTER_KEY "off_counter"
#define COUNTER_KEY "counter"
......@@ -92,6 +87,8 @@
#define AUDIBLE_KEY "audible"
#define FREQ_COUNTER_KEY "freq_counter"
#define ALARM_TIME_KEY "time"
#define EVENT_KEY "event"
#define EVENT_TIME_KEY ALARM_TIME_KEY
#define KEY(S_VAL) S_VAL "="
#define SEP ";"
......@@ -222,8 +219,10 @@ struct alarm_parse : public grammar<alarm_parse>
no_node_d[separator] >> no_node_d[silent_time] |
no_node_d[separator] >> no_node_d[group] |
no_node_d[separator] >> no_node_d[msg] |
no_node_d[separator] >> no_node_d[url] |
no_node_d[separator] >> no_node_d[on_command] |
no_node_d[separator] >> no_node_d[off_command] |
no_node_d[separator] >> no_node_d[receivers] |
no_node_d[separator] >> no_node_d[enabled]
;
......@@ -246,7 +245,7 @@ struct alarm_parse : public grammar<alarm_parse>
= discard_node_d[str_p(KEY(LEVEL_KEY))] >>
//lexeme_d[(+alnum_p)] //match only possible levels?? (fault, log, ...)
//(+(alnum_p-'\t'))
(str_p("fault") | str_p("warning") | str_p("log"))
(str_p("highest") | str_p("high") | str_p("medium") | str_p("lowest") | str_p("low") | str_p("fault") | str_p("warning") | str_p("log"))//TODO
[
assign_a(self.m_alarm.lev) //save level in alarm_t
]
......@@ -267,15 +266,26 @@ struct alarm_parse : public grammar<alarm_parse>
)
;
//------------------------------MESSAGE--------------------------------------
escChar = (ch_p('\\') | ch_p(';')) >> ch_p(';'); //escaped semicolon: "\;" or ";;"
msg
= discard_node_d[str_p(KEY(MESSAGE_KEY))]
//>> ch_p('"')
>> (+(anychar_p - ';')) //one ore more char except ';'
>> (+(escChar | (anychar_p - ';'))) //one ore more char except ';'
[
assign_a(self.m_alarm.msg)
]
//>> '"'
;
//------------------------------URL--------------------------------------
url
= discard_node_d[str_p(KEY(URL_KEY))]
//>> ch_p('"')
>> (*(escChar | (anychar_p - ';'))) //zero ore more char except ';'
[
assign_a(self.m_alarm.url)
]
//>> '"'
;
//---------------------------ON DELAY----------------------------------------
on_delay
= discard_node_d[str_p(KEY(ONDELAY_KEY))] >>
......@@ -327,6 +337,16 @@ struct alarm_parse : public grammar<alarm_parse>
] //discard_node_d
| epsilon_p)
;
//------------------------------RECEIVERS------------------------------------
receivers
= discard_node_d[str_p(KEY(RECEIVERS_KEY))]
//>> ch_p('"')
>> (*(escChar | (anychar_p - ';'))) //zero ore more char except ';'
[
assign_a(self.m_alarm.receivers)
]
//>> '"'
;
//------------------------------ENABLED----------------------------------------
enabled
= discard_node_d[str_p(KEY(ENABLED_KEY))] >>
......@@ -346,7 +366,7 @@ struct alarm_parse : public grammar<alarm_parse>
rule_t expression, event, option;
rule<typename lexeme_scanner<ScannerT>::type> symbol; //needed to use lexeme_d in rule name
rule<typename lexeme_scanner<ScannerT>::type> symbol_attr_name; //needed to use lexeme_d in rule name
rule_t name, name_alm, val, token, oper, msg, group, level, on_delay, off_delay, silent_time, on_command, off_command, enabled, separator;
rule_t name, name_alm, val, token, oper, msg, url, group, level, on_delay, off_delay, silent_time, on_command, off_command, receivers, enabled, separator,escChar;
formula_grammar formula;
rule_t const&
......
/*
* alarm_table.cpp
*
* $Author: graziano $
*
* $Revision: 1.5 $
*
* $Log: alarm_table.cpp,v $
*
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
* 34012 Basovizza, Trieste ITALY
*/
#include <sys/time.h>
#include <tango.h>
#include <tango/tango.h>
#include "alarm_table.h"
#include "alarm_grammar.h"
#include "cmd_thread.h"
#include <regex>
static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $";
......@@ -25,22 +19,6 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $";
/*
* alarm_t class methods
*/
alarm_t::alarm_t()
{
grp=0;
on_counter=0;
off_counter=0;
freq_counter=0;
stat = S_NORMAL;
ack = ACK;
on_delay = 0;
off_delay = 0;
silent_time = -1;
cmd_name_a=string("");
cmd_name_n=string("");
enabled=true;
shelved=false;
}
bool alarm_t::operator==(const alarm_t &that)
{
......@@ -59,7 +37,13 @@ void alarm_t::str2alm(const string &s)
istringstream is(s);
ostringstream temp_msg;
string temp_grp;
is >> ts.tv_sec >> ts.tv_usec >> name >> stat >> ack >> on_counter >> lev >> silent_time >> temp_grp >> msg; //stop at first white space in msg
unsigned int on_cnt;
is >> ts.tv_sec >> ts.tv_usec >> name >> stat >> ack >> on_cnt >> lev >> silent_time >> temp_grp >> msg; //stop at first white space in msg
#ifdef _CNT_ATOMIC
on_counter.store(on_cnt);
#else
on_counter = on_cnt;
#endif
temp_msg << is.rdbuf(); //read all remaining characters as msg
msg += temp_msg.str();
str2grp(temp_grp);
......@@ -69,8 +53,13 @@ string alarm_t::alm2str(void)
{
ostringstream os;
os.clear();
#ifdef _CNT_ATOMIC
os << ts.tv_sec << "\t" << ts.tv_usec << "\t" << name << "\t" \
<< stat << "\t" << ack << "\t" << on_counter.load() << "\t" << lev << "\t" << silent_time << "\t" << grp2str() << "\t" << msg << ends;
#else
os << ts.tv_sec << "\t" << ts.tv_usec << "\t" << name << "\t" \
<< stat << "\t" << ack << "\t" << on_counter << "\t" << lev << "\t" << silent_time << "\t" << grp2str() << "\t" << msg << ends;
#endif
return(os.str());
}
......@@ -188,8 +177,10 @@ void alarm_t::confstr(string &s)
KEY(SILENT_TIME_KEY)<<silent_time << SEP <<
KEY(GROUP_KEY)<< grp2str() << SEP <<
KEY(MESSAGE_KEY)<< msg << SEP <<
KEY(URL_KEY)<< url << SEP <<
KEY(ON_COMMAND_KEY)<< cmd_name_a << SEP <<
KEY(OFF_COMMAND_KEY)<< cmd_name_n << SEP <<
KEY(RECEIVERS_KEY)<< receivers << SEP <<
KEY(ENABLED_KEY)<< (enabled ? "1" : "0");
s = conf.str();
}
......@@ -339,7 +330,7 @@ void alarm_table::stored(vector<alarm_t>& a)
bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_t res, string &attr_values, string grp, string msg, string formula)
{
bool ret_changed=false;
//Tango::TimeVal now = gettime();
Tango::TimeVal now = gettime();
TangoSys_MemStream out_stream;
vlock->readerIn();
alarm_container_t::iterator found = v_alarm.find(alm_name);
......@@ -363,20 +354,34 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
found->second.ack = ACK;
}
}
found->second.quality = res.quality;
bool status_err_delay;
if(err_delay > 0)
status_err_delay = (!res.valid) && (found->second.err_counter >= 1) && ((now.tv_sec - err_delay) > found->second.ts_err_delay.tv_sec); //error is present and err delay has passed
else
status_err_delay = (!res.valid);
found->second.ex_reason = res.ex_reason;
found->second.ex_desc = res.ex_desc;
found->second.ex_origin = res.ex_origin;
if(!status_err_delay && !res.valid) //formula result not valid, waiting for err_delay
{
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
found->second.err_counter++;
if(found->second.err_counter == 1)
found->second.ts_err_delay = gettime(); //first occurrance of this error, now begin to wait for err delay
vlock->readerOut();
return ret_changed;
}
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.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);
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)) && (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);
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
......@@ -384,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.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) ? 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.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
......@@ -425,7 +430,13 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
string tmp_msg = msg;
replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
tmp << "name=" << alm_name << ";groups=" << grp << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<formula;
tm time_tm;
time_t time_sec= found->second.ts.tv_sec;
//gmtime_r(&time_sec,&time_tm); //-> UTC
localtime_r(&time_sec,&time_tm);
char time_buf[64];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
tmp << "name=" << alm_name << ";groups=" << grp << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<formula<<";time="<<time_buf << "." << found->second.ts.tv_usec<<";url="<<found->second.url;
cmd_t arg;
arg.cmd_id = CMD_COMMAND;
arg.dp_add = (long)found->second.dp_a;
......@@ -471,7 +482,13 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
string tmp_msg = msg;
replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
tmp << "name=" << alm_name << ";groups=" << grp << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<formula;
tm time_tm;
time_t time_sec= found->second.ts.tv_sec;
//gmtime_r(&time_sec,&time_tm); //-> UTC
localtime_r(&time_sec,&time_tm);
char time_buf[64];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
tmp << "name=" << alm_name << ";groups=" << grp << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<formula<<";time="<<time_buf << "." << found->second.ts.tv_usec;
cmd_t arg;
arg.cmd_id = CMD_COMMAND;
arg.dp_add = (long)found->second.dp_n;
......@@ -490,14 +507,40 @@ 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)
{
if(!found->second.error)
{
found->second.is_new = 1;
found->second.ack = NOT_ACK;
}
found->second.error = true;
}
if((bool)(res.value != 0)) {
if((bool)(!res.value.empty() && res.value[0] != 0)) {
found->second.on_counter++;
found->second.off_counter = 0;
} else {
found->second.on_counter = 0;
found->second.off_counter++;
}
if(!res.valid)
{
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 +548,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,8 +574,12 @@ 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)
continue; //if not enabled on or off delay, nothing to do in timer
bool status_err_delay=false;
if(err_delay > 0) //if enabled err 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
if(i->second.off_delay > 0) //if enabled off delay
......@@ -561,16 +609,32 @@ bool alarm_table::timer_update()
//if just ended silence time, set ret_changed to true so to push events
//TODO: not interested in executing commands?
if(old_silenced>0 && i->second.silenced == 0)
{
ret_changed = true;
}
//if status changed:
// - from S_NORMAL to S_ALARM considering also on delay
//or
// - 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?
{
status_on_delay = i->second.stat == S_ALARM;
status_off_delay = i->second.stat == S_NORMAL;
}
ret_changed = true;
if(status_err_delay)
{
if(!i->second.error)
{
i->second.is_new = 1;
i->second.ack = NOT_ACK;
}
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
......@@ -611,7 +675,13 @@ bool alarm_table::timer_update()
replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
string tmp_msg = i->second.msg;
replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
tmp << "name=" << i->second.name << ";groups=" << i->second.grp2str() << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<i->second.formula;
tm time_tm;
time_t time_sec= i->second.ts.tv_sec;
//gmtime_r(&time_sec,&time_tm); //-> UTC
localtime_r(&time_sec,&time_tm);
char time_buf[64];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
tmp << "name=" << i->second.name << ";groups=" << i->second.grp2str() << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<i->second.formula<<";time="<<time_buf << "." << i->second.ts.tv_usec<<";url="<<i->second.url;
cmd_t arg;
arg.cmd_id = CMD_COMMAND;
arg.dp_add = (long)i->second.dp_a;
......@@ -657,7 +727,13 @@ bool alarm_table::timer_update()
replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
string tmp_msg = i->second.msg;
replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
tmp << "name=" << i->second.name << ";groups=" << i->second.grp2str() << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<i->second.formula;
tm time_tm;
time_t time_sec= i->second.ts.tv_sec;
//gmtime_r(&time_sec,&time_tm); //-> UTC
localtime_r(&time_sec,&time_tm);
char time_buf[64];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
tmp << "name=" << i->second.name << ";groups=" << i->second.grp2str() << ";msg="<<tmp_msg<<";values="<<tmp_attr_val<<";formula="<<i->second.formula<<";time="<<time_buf << "." << i->second.ts.tv_usec<<";url="<<i->second.url;
cmd_t arg;
arg.cmd_id = CMD_COMMAND;
arg.dp_add = (long)i->second.dp_n;
......@@ -689,12 +765,20 @@ bool alarm_table::timer_update()
*(i->second.attr_value) = _RTNUN;
try
{
if(i->second.ex_reason.length() == 0)
if(!i->second.error || !i->second.enabled || (i->second.shelved && i->second.silenced > 0))
{
timeval now;
gettimeofday(&now, NULL);
mydev->push_change_event(i->second.attr_name,(Tango::DevEnum *)i->second.attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
mydev->push_archive_event(i->second.attr_name,(Tango::DevEnum *)i->second.attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
if(setAlarmQuality)
{
mydev->push_change_event(i->second.attr_name,(Tango::DevEnum *)i->second.attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
mydev->push_archive_event(i->second.attr_name,(Tango::DevEnum *)i->second.attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
}
else
{
mydev->push_change_event(i->second.attr_name,(Tango::DevEnum *)i->second.attr_value);
mydev->push_archive_event(i->second.attr_name,(Tango::DevEnum *)i->second.attr_value);
}
}
else
{
......@@ -771,7 +855,11 @@ vector<string> alarm_table::to_be_evaluated_list()
void alarm_table::new_rwlock()
{
#ifndef _USE_BOOST_LOCK
vlock = new(ReadersWritersLock);
#else
vlock = new rwlock_t("VLOCK");
#endif
}
void alarm_table::del_rwlock()
{
......@@ -792,8 +880,8 @@ void alarm_table::stop_cmdthread()
cmdloop->list.push_back(arg);
}
void alarm_table::save_alarm_conf_db(string att_name, string name, string status, string ack, bool enabled,
string formula, unsigned int on_delay, unsigned int off_delay, string grp, string lev, string msg, string cmd_a, string cmd_n, int silent_time, vector<string> alm_list)
void alarm_table::save_alarm_conf_db(const string &att_name, const string &name, const string &status, const string &ack, bool enabled,
const string &formula, unsigned int on_delay, unsigned int off_delay, const string &grp, const string &lev, const string &msg, const string &url, const string &cmd_a, const string &cmd_n, const string &receivers, int silent_time)
{
// We want to put properties for attribute "att_name"
Tango::DbDatum dbd_att_name(att_name);
......@@ -805,22 +893,26 @@ void alarm_table::save_alarm_conf_db(string att_name, string name, string status
Tango::DbDatum dbd_silence_time(SILENT_TIME_KEY); //TODO: silent_time
Tango::DbDatum dbd_group(GROUP_KEY);
Tango::DbDatum dbd_message(MESSAGE_KEY);
Tango::DbDatum dbd_url(URL_KEY);
Tango::DbDatum dbd_oncommand(ON_COMMAND_KEY);
Tango::DbDatum dbd_offcommand(OFF_COMMAND_KEY);
Tango::DbDatum dbd_enabled(ENABLED_KEY);
Tango::DbDatum dbd_receivers(RECEIVERS_KEY);
Tango::DbData db_data;
dbd_att_name << (short int)11; // Eleven properties for attribute "att_name"
dbd_name << name;
dbd_formula << formula;
dbd_att_name << (short int)13; // Thirteen properties for attribute "att_name"
dbd_name << name.c_str();
dbd_formula << formula.c_str();
dbd_on_delay << (Tango::DevLong)on_delay;
dbd_off_delay << (Tango::DevLong)off_delay;
dbd_level << lev;
dbd_level << lev.c_str();
dbd_silence_time << (Tango::DevLong)silent_time;
dbd_group << grp;
dbd_message << msg;
dbd_oncommand << cmd_a;
dbd_offcommand << cmd_n;
dbd_group << grp.c_str();
dbd_message << msg.c_str();
dbd_url << url.c_str();
dbd_oncommand << cmd_a.c_str();
dbd_offcommand << cmd_n.c_str();
dbd_receivers << receivers.c_str();
dbd_enabled << (enabled ? (short int)1 : (short int)0);
db_data.push_back(dbd_att_name);
......@@ -832,9 +924,11 @@ void alarm_table::save_alarm_conf_db(string att_name, string name, string status
db_data.push_back(dbd_silence_time);
db_data.push_back(dbd_group);
db_data.push_back(dbd_message);
db_data.push_back(dbd_url);
db_data.push_back(dbd_oncommand);
db_data.push_back(dbd_offcommand);
db_data.push_back(dbd_enabled);
db_data.push_back(dbd_receivers);
string dev_name(mydev->get_name());
......@@ -842,10 +936,11 @@ void alarm_table::save_alarm_conf_db(string att_name, string name, string status
{
Tango::DbDevice *db_dev = mydev->get_db_device();
db_dev->get_dbase()->put_device_attribute_property(dev_name,db_data);
//Tango::Util::instance()->get_database()->put_device_attribute_property(dev_name,db_data);
}
catch(Tango::DevFailed &e)
{
cout << __func__ << ": Exception saving configuration = " << e.errors[0].desc<<endl;
TANGO_LOG << __func__ << ": Exception saving configuration = " << e.errors[0].desc<<endl;
}
}
......@@ -861,9 +956,11 @@ void alarm_table::delete_alarm_conf_db(string att_name)
Tango::DbDatum dbd_silence_time(SILENT_TIME_KEY); //TODO: silent_time
Tango::DbDatum dbd_group(GROUP_KEY);
Tango::DbDatum dbd_message(MESSAGE_KEY);
Tango::DbDatum dbd_url(URL_KEY);
Tango::DbDatum dbd_oncommand(ON_COMMAND_KEY);
Tango::DbDatum dbd_offcommand(OFF_COMMAND_KEY);
Tango::DbDatum dbd_enabled(ENABLED_KEY);
Tango::DbDatum dbd_receivers(RECEIVERS_KEY);
Tango::DbData db_data;
......@@ -876,9 +973,11 @@ void alarm_table::delete_alarm_conf_db(string att_name)
db_data.push_back(dbd_silence_time);
db_data.push_back(dbd_group);
db_data.push_back(dbd_message);
db_data.push_back(dbd_url);
db_data.push_back(dbd_oncommand);
db_data.push_back(dbd_offcommand);
db_data.push_back(dbd_enabled);
db_data.push_back(dbd_receivers);
string dev_name(mydev->get_name());
......@@ -889,13 +988,12 @@ void alarm_table::delete_alarm_conf_db(string att_name)
}
catch(Tango::DevFailed &e)
{
cout << __func__ << ": Exception deleting " << att_name << " = " << e.errors[0].desc<<endl;
TANGO_LOG << __func__ << ": Exception deleting " << att_name << " = " << e.errors[0].desc<<endl;
}
}
void alarm_table::get_alarm_list_db(vector<string> &al_list, map<string, string> &saved_alarms)
void alarm_table::get_alarm_list_db(vector<string> &al_list, map<string, string> &saved_alarms, ReadersWritersLock *savedlock)
{
saved_alarms.clear();
string dev_name(mydev->get_name());
vector<string> att_list;
......@@ -914,8 +1012,10 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list, map<string, string>
}
catch(Tango::DevFailed &e)
{
cout << __func__ << ": Exception reading configuration = " << e.errors[0].desc<<endl;
TANGO_LOG << __func__ << ": Exception reading configuration = " << e.errors[0].desc<<endl;
}
savedlock->writerIn();
saved_alarms.clear();
for (size_t i=0;i < db_data.size();/*i++*/)
{
Tango::DevLong64 nb_prop;
......@@ -930,9 +1030,11 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list, map<string, string>
string alm_silence_time("-1");
string alm_group;
string alm_message;
string alm_url;
string alm_on_command("");
string alm_off_command("");
string alm_enabled("1");
string alm_receivers("");
for (long k=0;k < nb_prop;k++)
{
string &prop_name = db_data[i].name;
......@@ -953,20 +1055,27 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list, map<string, string>
db_data[i] >> alm_group;
else if (prop_name == MESSAGE_KEY)
db_data[i] >> alm_message;
else if (prop_name == URL_KEY)
db_data[i] >> alm_url;
else if (prop_name == ON_COMMAND_KEY)
db_data[i] >> alm_on_command;
else if (prop_name == OFF_COMMAND_KEY)
db_data[i] >> alm_off_command;
else if (prop_name == ENABLED_KEY)
db_data[i] >> alm_enabled;
else if (prop_name == RECEIVERS_KEY)
db_data[i] >> alm_receivers;
else
{
cout << "att_name="<<att_name<<" UNKWNOWN prop_name="<<prop_name<<endl;
TANGO_LOG << "att_name="<<att_name<<" UNKWNOWN prop_name="<<prop_name<<endl;
i++;
continue;
}
i++;
}
alm_message = std::regex_replace(alm_message, std::regex(";"), "\\;");
alm_url = std::regex_replace(alm_url, std::regex(";"), "\\;");
alm_receivers = std::regex_replace(alm_receivers, std::regex(";"), "\\;");
stringstream alm;
alm << KEY(NAME_KEY)<<alm_name << SEP <<
KEY(FORMULA_KEY)<<alm_formula << SEP <<
......@@ -976,17 +1085,20 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list, map<string, string>
KEY(SILENT_TIME_KEY)<<alm_silence_time << SEP <<
KEY(GROUP_KEY)<< alm_group << SEP <<
KEY(MESSAGE_KEY)<< alm_message << SEP <<
KEY(URL_KEY)<< alm_url << SEP <<
KEY(ON_COMMAND_KEY)<< alm_on_command << SEP <<
KEY(OFF_COMMAND_KEY)<< alm_off_command << SEP <<
KEY(RECEIVERS_KEY)<< alm_receivers << SEP <<
KEY(ENABLED_KEY)<< alm_enabled;
if(alm_name.empty() || alm_formula.empty() || alm_level.empty() || alm_group.empty() || alm_message.empty()) //TODO: decide if all mandatory
{
cout << __func__ << ": skipped '" << alm.str() << "'" << endl;
TANGO_LOG << __func__ << ": skipped '" << alm.str() << "'" << endl;
continue;
}
al_list.push_back(alm.str());
saved_alarms.insert(make_pair(alm_name,alm.str()));
}
savedlock->writerOut();
#if 0
......
/*
* alarm_table.h
*
* $Author: graziano $
*
* $Revision: 1.5 $
*
* $Log: alarm_table.h,v $
*
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
* 34012 Basovizza, Trieste ITALY
......@@ -21,8 +14,9 @@
#include <iostream>
#include <string>
#include <map>
#include <numeric> //for std::accumulate
#include <tango.h>
#include <tango/tango.h>
//spirit defines have to be put befor first inclusion of spirit headers
#ifndef BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT
......@@ -45,13 +39,18 @@
#else
#include <boost/spirit/include/classic_ast.hpp> //for ast parse trees (in tree_formula)
#endif
//#define _USE_BOOST_LOCK
#ifdef _USE_BOOST_LOCK
#include <boost/thread/shared_mutex.hpp>
#endif
//#include "log_thread.h"
#define LOG_STREAM cout
#define MAX_ARRAY_PRINTED_CHARS 1000
#define LOG_STREAM TANGO_LOG
using namespace std;
typedef vector<Tango::DevDouble> value_t;
#if BOOST_VERSION < 103600
typedef std::string::iterator iterator_t;
......@@ -69,6 +68,7 @@ typedef parse_tree_match_t::tree_iterator iter_t;
#define S_NORMAL "NORMAL"
#define S_ALARM "ALARM"
#define S_ERROR "ERROR"
#define NOT_ACK "NACK"
#define ACK "ACK"
......@@ -83,23 +83,182 @@ typedef parse_tree_match_t::tree_iterator iter_t;
#define LEV_LOG "log"
#define LEV_WARNING "warning"
#define LEV_FAULT "fault"
#define LEV_DEFAULT LEV_FAULT
//#define LEV_DEFAULT LEV_FAULT
#define LEV_LOWEST "lowest"
#define LEV_LOW "low"
#define LEV_MEDIUM "medium"
#define LEV_HIGH "high"
#define LEV_HIGHEST "highest"
#define LEV_DEFAULT LEV_HIGH
class alarm_t;
class alarm_table;
class log_thread;
class cmd_thread;
#ifdef _USE_BOOST_LOCK
struct rwlock_t
{
string name;
rwlock_t(string n){name=n;};
rwlock_t(){name=string("RWLOCK");};
boost::shared_mutex mut;
void readerIn(){TANGO_LOG<<name<<": " << __func__<<endl;mut.lock_shared();}
void readerOut(){TANGO_LOG<<name<<": " << __func__<<endl;mut.unlock_shared();}
void writerIn(){TANGO_LOG<<name<<": " << __func__<<endl;mut.lock();}
void writerOut(){TANGO_LOG<<name<<": " << __func__<<endl;mut.unlock();}
};
#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, 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);}
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;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;
Tango::DevErrorList errors; //TODO: error stack
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;
......@@ -122,124 +281,218 @@ struct formula_res_t
else
return ex_2;
}
void extract_result()
{
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)
{
formula_res_t res;
res.value = value == e.value;
res.valid = valid && e.valid;
res.quality = combine_quality(quality, e.quality);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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 = value || e.value;
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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 = value && e.value;
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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);
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
res.ex_desc = combine_exception(ex_desc, e.ex_desc);
res.ex_origin = combine_exception(ex_origin, e.ex_origin);
if(!res.valid)
{
res.ex_reason = combine_exception(ex_reason, e.ex_reason);
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)
......@@ -266,13 +519,21 @@ class alarm_t {
string ex_desc;
string ex_origin;
Tango::TimeVal ts;
string stat,
ack;
bool enabled;
bool shelved;
unsigned int on_counter;
unsigned int off_counter;
unsigned int freq_counter;
string stat{S_NORMAL},
ack{ACK};
bool error;
bool enabled{true};
bool shelved{false};
#ifdef _CNT_ATOMIC
atomic_uint on_counter= {0};
atomic_uint off_counter= {0};
atomic_uint err_counter= {0};
#else
unsigned int on_counter= {0};
unsigned int off_counter= {0};
unsigned int err_counter= {0};
#endif
unsigned int freq_counter{0};
tree_parse_info_t formula_tree;
......@@ -281,26 +542,29 @@ class alarm_t {
bool done;
bool to_be_evaluated;
string msg;
unsigned int grp;
string url;
string receivers;
unsigned int grp{0};
string lev;
set<string> s_event;
int is_new;
Tango::TimeVal ts_on_delay; //says when it has gone in alarm status for the first time
unsigned int on_delay; //TODO: seconds, is it enough precision?
unsigned int on_delay{0}; //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?
unsigned int off_delay{0}; //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
int silent_time{-1}; //minutes max to be silent
int silenced; //minutes still to be silent
string attr_values; //attr_values
string attr_values_delay; //attr_values of first occurrence of alarm waiting for on or off delay
string cmd_name_a; //action to execute: when NORMAL -> ALARM, cmd_name = cmd_dp_a/cmd_action_a
string cmd_name_a{""}; //action to execute: when NORMAL -> ALARM, cmd_name = cmd_dp_a/cmd_action_a
string cmd_dp_a; //device proxy part of cmd_name_a
string cmd_action_a; //action part of cmd_name_a
bool send_arg_a; //send as string argument alarm name and attr values
Tango::DeviceProxy *dp_a;
string cmd_name_n; //action to execute: when ALARM -> NORMAL, cmd_name_n = cmd_dp_n/cmd_action_n
string cmd_name_n{""}; //action to execute: when ALARM -> NORMAL, cmd_name_n = cmd_dp_n/cmd_action_n
string cmd_dp_n; //device proxy part of cmd_name_n
string cmd_action_n; //action part of cmd_name_n
bool send_arg_n; //send as string argument alarm name and attr values
......@@ -308,7 +572,11 @@ class alarm_t {
/*
* methods
*/
alarm_t(); //constructor
alarm_t() noexcept {}; //constructor
#ifdef _CNT_ATOMIC
alarm_t& operator=(const alarm_t& rhs) { on_counter = rhs.on_counter.load(); off_counter = rhs.off_counter.load(); err_counter = rhs.err_counter.load(); return *this; }
alarm_t(const alarm_t& rhs) { on_counter = rhs.on_counter.load(); off_counter = rhs.off_counter.load(); err_counter = rhs.err_counter.load();}
#endif
void init_static_map(vector<string> &group_names);
bool operator==(const alarm_t& that);
bool operator==(const string& n);
......@@ -331,7 +599,9 @@ class alarm_table {
public:
alarm_table() {}
~alarm_table() {del_rwlock();}
bool setAlarmQuality {false};
void set_dev(Tango::DeviceImpl* devImpl) {mydev=devImpl;}
void set_al_qual(bool set_al_qual) {setAlarmQuality=set_al_qual;}
//void init(vector<string>& avs);
//void init(vector<string>& avs, vector<string> &evn, map< string,vector<string> > &alarm_event);
......@@ -348,23 +618,30 @@ class alarm_table {
vector<string> to_be_evaluated_list();
//vector<alarm_t> v_alarm;
alarm_container_t v_alarm;
#ifndef _USE_BOOST_LOCK
ReadersWritersLock *vlock;
#else
rwlock_t *vlock;
#endif
void new_rwlock();
void del_rwlock();
void save_alarm_conf_db(string att_name, string name, string status, string ack, bool enabled,
string formula, unsigned int on_delay, unsigned int off_delay, string grp, string lev, string msg, string cmd_a, string cmd_n, int silent_time, vector<string> alm_list=vector<string>());
void save_alarm_conf_db(const string &att_name, const string &name, const string &status, const string &ack, bool enabled,
const string &formula, unsigned int on_delay, unsigned int off_delay, const string &grp, const string &url, const string &lev, const string &msg, const string &cmd_a, const string &cmd_n, const string &receivers, int silent_time);
void delete_alarm_conf_db(string att_name);
void get_alarm_list_db(vector<string> &al_list, map<string, string> &saved_alarms);
void get_alarm_list_db(vector<string> &al_list, map<string, string> &saved_alarms, ReadersWritersLock *savedlock);
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;};
protected:
private:
Tango::DeviceImpl* mydev;
log_thread *logloop;
cmd_thread *cmdloop;
cmd_thread *cmdloop;
unsigned int err_delay;
};
......