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 2002 additions and 1351 deletions
/*
* 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 "log_thread.h"
#include "cmd_thread.h"
#include <regex>
static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $";
......@@ -26,13 +19,6 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $";
/*
* alarm_t class methods
*/
alarm_t::alarm_t()
{
grp=0;
counter=0;
stat = S_NORMAL;
ack = ACK;
}
bool alarm_t::operator==(const alarm_t &that)
{
......@@ -51,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 >> 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);
......@@ -61,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" << counter << "\t" << lev << "\t" << silent_time << "\t" << grp2str() << "\t" << msg << ends;
<< stat << "\t" << ack << "\t" << on_counter << "\t" << lev << "\t" << silent_time << "\t" << grp2str() << "\t" << msg << ends;
#endif
return(os.str());
}
......@@ -168,6 +165,26 @@ void alarm_t::clear()
// ts = 0;
}
void alarm_t::confstr(string &s)
{
ostringstream conf;
conf <<
KEY(NAME_KEY)<<name << SEP <<
KEY(FORMULA_KEY)<<formula << SEP <<
KEY(ONDELAY_KEY)<<on_delay << SEP <<
KEY(OFFDELAY_KEY)<<off_delay << SEP <<
KEY(LEVEL_KEY)<< lev << SEP <<
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();
}
/*
* alarm_table class methods
*/
......@@ -229,27 +246,15 @@ void alarm_table::init(vector<string>& avs, vector<string> &evn, map< string,vec
void alarm_table::push_back(alarm_t &a)
{
#ifndef _RW_LOCK
this->lock();
#else
vlock->writerIn();
#endif
//v_alarm.push_back(a);
v_alarm.insert(make_pair(a.name,a));
#ifndef _RW_LOCK
this->unlock();
#else
vlock->writerOut();
#endif
}
void alarm_table::show(vector<string> &al_table_string)
{
#ifndef _RW_LOCK
this->lock();
#else
vlock->readerIn();
#endif
ostringstream log_msg;
string log_str;
if (v_alarm.empty() == false) {
......@@ -284,11 +289,7 @@ void alarm_table::show(vector<string> &al_table_string)
j++;
}
}
#ifndef _RW_LOCK
this->unlock();
#else
vlock->readerOut();
#endif
}
unsigned int alarm_table::size(void)
......@@ -303,11 +304,7 @@ alarm_container_t& alarm_table::get(void)
void alarm_table::stored(vector<alarm_t>& a)
{
#ifndef _RW_LOCK
this->lock();
#else
vlock->readerIn();
#endif
if (a.empty() == false) {
for (vector<alarm_t>::iterator i = a.begin(); i != a.end(); i++)
{
......@@ -327,24 +324,15 @@ void alarm_table::stored(vector<alarm_t>& a)
}
} /* for */
} /* if */
#ifndef _RW_LOCK
this->unlock();
#else
vlock->readerOut();
#endif
}
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;
alm_log_t a;
#ifndef _RW_LOCK
this->lock();
#else
vlock->readerIn();
#endif
alarm_container_t::iterator found = v_alarm.find(alm_name);
if (found != v_alarm.end())
{
......@@ -355,41 +343,58 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
double dsilent = found->second.ts_time_silenced.tv_sec + ((double)found->second.ts_time_silenced.tv_usec) / 1000000;
double dminutes = (dnow - dsilent)/60;
if(dminutes < found->second.silent_time)
{
found->second.silenced = found->second.silent_time - floor(dminutes);
}
else
{
found->second.silenced = 0;
found->second.shelved = false;
found->second.is_new = 0;
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;
bool status_time_threshold;
if(found->second.time_threshold > 0) //if enabled time threshold
status_time_threshold = ((int)(res.value)) && (found->second.counter >= 1) && ((ts.tv_sec - found->second.time_threshold) > found->second.ts_time_threshold.tv_sec); //formula gives true and time threshold is passed
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.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.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.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_time_threshold = (int)(res.value);
status_off_delay = !(bool)(!res.value.empty() && res.value[0] != 0);
//if status changed:
// - from S_NORMAL to S_ALARM considering also time threshold
// - from S_NORMAL to S_ALARM considering also on delay
//or
// - from S_ALARM to S_NORMAL
if((status_time_threshold && (found->second.stat == S_NORMAL)) || (!(int)(res.value) && (found->second.stat == S_ALARM)))
// - from S_ALARM to S_NORMAL considering also off delay
if((status_on_delay && (found->second.stat == S_NORMAL)) || (status_off_delay && (found->second.stat == S_ALARM)))
{
ret_changed=true;
a.type_log = TYPE_LOG_STATUS;
a.name = alm_name;
a.time_s = ts.tv_sec;
a.time_us = ts.tv_usec;
a.status = (int)(res.value) ? S_ALARM : S_NORMAL;
//a.level = found->second.lev;
if((int)(res.value))
if((bool)(!res.value.empty() && res.value[0] != 0))
found->second.ack = NOT_ACK; //if changing from NORMAL to ALARM -> NACK
a.ack = found->second.ack;
a.values = attr_values;
//a.grp = found->second.grp2str();
//a.msg = (int)(res.value) ? found->second.msg : "";
logloop->log_alarm_db(a);
//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((int)(res.value))
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;
......@@ -483,21 +500,56 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
}
}
}
if (status_time_threshold) {
if (status_on_delay) {
found->second.stat = S_ALARM;
//found->second.ack = NOT_ACK;
}
if((int)(res.value)) {
found->second.counter++;
} else {
else if (status_off_delay) {
found->second.stat = S_NORMAL;
found->second.counter = 0;
}
if(found->second.counter == 1)
found->second.ts_time_threshold = gettime(); //first occurrance of this alarm, now begin to wait for time threshold
if(found->second.counter >= 1)
found->second.attr_values_time_threshold = attr_values; //save last attr_values to be used in timer_update if this alarm pass over time threshold
//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.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
if(found->second.on_counter == 1)
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 {
/*
......@@ -506,11 +558,7 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
out_stream << "couldn't find alarm '" << alm_name << "' in 'alarms' table" << ends;
LOG_STREAM << gettime().tv_sec << " alarm_table::update(): " << out_stream.str() << endl;
}
#ifndef _RW_LOCK
this->unlock();
#else
vlock->readerOut();
#endif
if(out_stream.str().length() > 0)
throw out_stream.str();
return ret_changed;
......@@ -521,101 +569,216 @@ bool alarm_table::timer_update()
bool ret_changed=false;
Tango::TimeVal ts = gettime();
TangoSys_MemStream out_stream;
alm_log_t a;
#ifndef _RW_LOCK
this->lock();
#else
vlock->readerIn();
#endif
for(alarm_container_t::iterator i = v_alarm.begin(); i != v_alarm.end(); i++)
{
bool status_time_threshold;
if(i->second.time_threshold > 0) //if enabled time threshold
status_time_threshold = (i->second.counter >= 1) && ((ts.tv_sec - i->second.time_threshold) > i->second.ts_time_threshold.tv_sec); //waiting for threshold and time threshold is passed
else
continue; //if not enabled time threshold, nothing to do in timer
bool status_on_delay=false;
bool status_off_delay=false;
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
status_off_delay = (i->second.off_counter >= 1) && ((ts.tv_sec - i->second.off_delay) > i->second.ts_off_delay.tv_sec); //waiting for off delay has passed
//if status changed from S_NORMAL to S_ALARM considering also time threshold
if(status_time_threshold && (i->second.stat == S_NORMAL))
//look here also if shelved time ended
bool old_shelved = i->second.shelved;
int old_silenced = i->second.silenced;
if(i->second.silenced > 0)
{
Tango::TimeVal now = gettime();
double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000;
double dsilent = i->second.ts_time_silenced.tv_sec + ((double)i->second.ts_time_silenced.tv_usec) / 1000000;
double dminutes = (dnow - dsilent)/60;
if(dminutes < i->second.silent_time)
{
i->second.silenced = i->second.silent_time - floor(dminutes);
}
else
{
i->second.silenced = 0;
i->second.shelved = false;
i->second.is_new = 0;
i->second.ack = ACK;
}
}
//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) || (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(i->second.silenced > 0)
if(status_err_delay)
{
Tango::TimeVal now = gettime();
double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000;
double dsilent = i->second.ts_time_silenced.tv_sec + ((double)i->second.ts_time_silenced.tv_usec) / 1000000;
double dminutes = (dnow - dsilent)/60;
if(dminutes < i->second.silent_time)
i->second.silenced = i->second.silent_time - floor(dminutes);
else
i->second.silenced = 0;
if(!i->second.error)
{
i->second.is_new = 1;
i->second.ack = NOT_ACK;
}
i->second.error = true;
}
a.type_log = TYPE_LOG_STATUS;
a.name = i->second.name;
a.time_s = ts.tv_sec;
a.time_us = ts.tv_usec;
a.status = S_ALARM;
//a.level = found->second.lev;
i->second.ack = NOT_ACK; //if changing from NORMAL to ALARM -> NACK
a.ack = i->second.ack;
a.values = i->second.attr_values_time_threshold;
logloop->log_alarm_db(a);
if(status_on_delay)
i->second.ack = NOT_ACK; //if changing from NORMAL to ALARM but not ended shelved time -> NACK
i->second.ts = ts; /* store event timestamp into alarm timestamp */ //here update ts only if status changed
i->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(i->second.dp_a && ((ts.tv_sec - startup_complete.tv_sec) > 10))
if(status_on_delay)
{
/*try {
long call_id;
i->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(i->second.dp_a && ((ts.tv_sec - startup_complete.tv_sec) > 10))
{
/*try {
long call_id;
ostringstream tmp;
tmp << i->second.name << ";" << i->second.attr_values_on_delay;
Tango::DevString str = CORBA::string_dup(tmp.str().c_str());
Tango::DeviceData Din;
Din << str;
CORBA::string_free(str);
//i->second.dp_a->ping();
cmdloop->mutex_dp->lock();
//call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din, true); //true -> "fire and forget" mode: client do not care at all about the server answer
call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din);
cmdloop->mutex_dp->unlock();
LOG_STREAM << gettime().tv_sec << " alarm_table::timer_update() executed action: " << i->second.cmd_name_a << " !!!" << endl;
cmd_t arg;
arg.cmd_id = call_id;
arg.dp_add = (long)i->second.dp_a;
arg.arg_s = i->second.cmd_name_a;
cmdloop->list.push_back(arg);
} catch(Tango::DevFailed e)
{
string err(e.errors[0].desc);
if(err.find("is not yet arrived") == string::npos) //TODO: change this!!
out_stream << "Failed to execute action " << i->second.cmd_name_a << ", err=" << e.errors[0].desc << ends;
//LOG_STREAM << "alarm_table::timer_update() ERROR: " << out_stream.str() << endl;
}*/
ostringstream tmp;
tmp << i->second.name << ";" << i->second.attr_values_time_threshold;
Tango::DevString str = CORBA::string_dup(tmp.str().c_str());
Tango::DeviceData Din;
Din << str;
CORBA::string_free(str);
//i->second.dp_a->ping();
cmdloop->mutex_dp->lock();
//call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din, true); //true -> "fire and forget" mode: client do not care at all about the server answer
call_id = i->second.dp_a->command_inout_asynch(i->second.cmd_action_a, Din);
cmdloop->mutex_dp->unlock();
LOG_STREAM << gettime().tv_sec << " alarm_table::timer_update() executed action: " << i->second.cmd_name_a << " !!!" << endl;
string tmp_attr_val = i->second.attr_values_delay;
replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
string tmp_msg = i->second.msg;
replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
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 = call_id;
arg.cmd_id = CMD_COMMAND;
arg.dp_add = (long)i->second.dp_a;
arg.arg_s = i->second.cmd_name_a;
cmdloop->list.push_back(arg);
} catch(Tango::DevFailed e)
arg.arg_s1 = tmp.str();
arg.arg_s2 = i->second.cmd_action_a;
arg.arg_s3 = i->second.cmd_name_a;
arg.arg_b = i->second.send_arg_a;
cmdloop->list.push_back(arg);
}
}
else if(status_off_delay && (i->second.stat == S_ALARM))
{
if(i->second.dp_n && ((ts.tv_sec - startup_complete.tv_sec) > 10))
{
string err(e.errors[0].desc);
if(err.find("is not yet arrived") == string::npos) //TODO: change this!!
out_stream << "Failed to execute action " << i->second.cmd_name_a << ", err=" << e.errors[0].desc << ends;
//LOG_STREAM << "alarm_table::timer_update() ERROR: " << out_stream.str() << endl;
}*/
ostringstream tmp;
string tmp_attr_val = i->second.attr_values_time_threshold;
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;
cmd_t arg;
arg.cmd_id = CMD_COMMAND;
arg.dp_add = (long)i->second.dp_a;
arg.arg_s1 = tmp.str();
arg.arg_s2 = i->second.cmd_action_a;
arg.arg_s3 = i->second.cmd_name_a;
arg.arg_b = i->second.send_arg_a;
cmdloop->list.push_back(arg);
/*try {
long call_id;
ostringstream tmp;
tmp << i->second.name << ";" << i->second.attr_values_off_delay;
Tango::DevString str = CORBA::string_dup(tmp.str().c_str());
Tango::DeviceData Din;
Din << str;
CORBA::string_free(str);
//i->second.dp_n->ping();
cmdloop->mutex_dp->lock();
//call_id = i->second.dp_n->command_inout_asynch(i->second.cmd_action_n, Din, true); //true -> "fire and forget" mode: client do not care at all about the server answer
call_id = i->second.dp_n->command_inout_asynch(i->second.cmd_action_n, Din);
cmdloop->mutex_dp->unlock();
LOG_STREAM << gettime().tv_sec << " alarm_table::timer_update() executed action: " << i->second.cmd_name_n << " !!!" << endl;
cmd_t arg;
arg.cmd_id = call_id;
arg.dp_add = (long)i->second.dp_n;
arg.arg_s = i->second.cmd_name_n;
cmdloop->list.push_back(arg);
} catch(Tango::DevFailed e)
{
string err(e.errors[0].desc);
if(err.find("is not yet arrived") == string::npos) //TODO: change this!!
out_stream << "Failed to execute action " << i->second.cmd_name_n << ", err=" << e.errors[0].desc << ends;
//LOG_STREAM << "alarm_table::timer_update() ERROR: " << out_stream.str() << endl;
}*/
ostringstream tmp;
string tmp_attr_val = i->second.attr_values_delay;
replace(tmp_attr_val.begin(), tmp_attr_val.end(), ';' , ',');
string tmp_msg = i->second.msg;
replace(tmp_msg.begin(), tmp_msg.end(), ';' , ',');
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;
arg.arg_s1 = tmp.str();
arg.arg_s2 = i->second.cmd_action_n;
arg.arg_s3 = i->second.cmd_name_n;
arg.arg_b = i->second.send_arg_n;
cmdloop->list.push_back(arg);
}
}
if((int)(status_on_delay)) {
i->second.off_counter = 0;
} else if(status_off_delay) {
i->second.on_counter = 0;
}
*(i->second.attr_value) = true;
if(!i->second.enabled)
*(i->second.attr_value) = _OOSRV;
else if(i->second.shelved && i->second.silenced > 0)
*(i->second.attr_value) = _SHLVD;
else if((status_off_delay) && i->second.ack == ACK)
*(i->second.attr_value) = _NORM;
else if((status_on_delay) && i->second.ack == NOT_ACK)
*(i->second.attr_value) = _UNACK;
else if((status_on_delay) && i->second.ack == ACK)
*(i->second.attr_value) = _ACKED;
else if((status_off_delay) && i->second.ack == NOT_ACK)
*(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::DevBoolean *)i->second.attr_value,now,(Tango::AttrQuality)i->second.quality, 1/*size*/, 0, false);
mydev->push_archive_event(i->second.attr_name,(Tango::DevBoolean *)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
{
......@@ -632,17 +795,16 @@ bool alarm_table::timer_update()
} catch(Tango::DevFailed &e)
{}
}
if (status_time_threshold) {
if (status_on_delay) {
i->second.stat = S_ALARM;
//found->second.ack = NOT_ACK;
}
else if (status_off_delay) {
i->second.stat = S_NORMAL;
}
//found->second.ts = ts; /* store event timestamp into alarm timestamp */ //here update ts everytime
}
#ifndef _RW_LOCK
this->unlock();
#else
vlock->readerOut();
#endif
if(out_stream.str().length() > 0)
throw out_stream.str();
return ret_changed;
......@@ -650,17 +812,9 @@ bool alarm_table::timer_update()
void alarm_table::erase(alarm_container_t::iterator i)
{
#ifndef _RW_LOCK
this->lock();
#else
vlock->writerIn();
#endif
v_alarm.erase(i);
#ifndef _RW_LOCK
this->unlock();
#else
vlock->writerOut();
#endif
}
bool alarm_table::exist(string& s)
......@@ -675,73 +829,42 @@ bool alarm_table::exist(string& s)
unsigned int alarm_table::to_be_evaluated_num()
{
unsigned int ret=0;
#ifndef _RW_LOCK
this->lock();
#else
vlock->readerIn();
#endif
for(alarm_container_t::iterator i = v_alarm.begin(); i != v_alarm.end(); i++)
{
if(i->second.to_be_evaluated == true)
ret++;
}
#ifndef _RW_LOCK
this->unlock();
#else
vlock->readerOut();
#endif
return ret;
}
vector<string> alarm_table::to_be_evaluated_list()
{
vector<string> ret;
#ifndef _RW_LOCK
this->lock();
#else
vlock->readerIn();
#endif
for(alarm_container_t::iterator i = v_alarm.begin(); i != v_alarm.end(); i++)
{
if(i->second.to_be_evaluated == true)
ret.push_back(i->first);
}
#ifndef _RW_LOCK
this->unlock();
#else
vlock->readerOut();
#endif
return ret;
}
#ifdef _RW_LOCK
void alarm_table::new_rwlock()
{
#ifndef _USE_BOOST_LOCK
vlock = new(ReadersWritersLock);
#else
vlock = new rwlock_t("VLOCK");
#endif
}
void alarm_table::del_rwlock()
{
delete vlock;
}
#endif
void alarm_table::init_logdb(string dbhost, string dbuser, string dbpw, string dbname, int dbport, string instance_name)
{
logloop = new log_thread(dbhost, dbuser, dbpw, dbname, dbport, instance_name);
logloop->start();
}
void alarm_table::stop_logdb()
{
alm_log_t a;
a.name = LOG_THREAD_EXIT;
a.time_s = LOG_THREAD_EXIT_TIME;
logloop->log_alarm_db(a);
//sleep(1);
//delete logloop;
}
void alarm_table::init_cmdthread()
{
......@@ -757,80 +880,120 @@ void alarm_table::stop_cmdthread()
cmdloop->list.push_back(arg);
}
void alarm_table::log_alarm_db(unsigned int type, Tango::TimeVal ts, string name, string status, string ack,
string formula, unsigned int time_threshold, string grp, string lev, string msg, string action, 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)
{
alm_log_t a;
a.type_log = type;
a.name = name;
a.time_s = ts.tv_sec;
a.time_us = ts.tv_usec;
a.time_threshold = time_threshold;
a.status = status;
a.level = lev;
a.ack = ack;
a.grp = grp;
a.msg = msg;
a.action = action;
a.formula = formula;
a.alm_list = alm_list;
a.silent_time = silent_time;
logloop->log_alarm_db(a);
// We want to put properties for attribute "att_name"
Tango::DbDatum dbd_att_name(att_name);
Tango::DbDatum dbd_name(NAME_KEY);
Tango::DbDatum dbd_formula(FORMULA_KEY);
Tango::DbDatum dbd_on_delay(ONDELAY_KEY);
Tango::DbDatum dbd_off_delay(OFFDELAY_KEY);
Tango::DbDatum dbd_level(LEVEL_KEY);
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)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.c_str();
dbd_silence_time << (Tango::DevLong)silent_time;
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);
db_data.push_back(dbd_name);
db_data.push_back(dbd_formula);
db_data.push_back(dbd_on_delay);
db_data.push_back(dbd_off_delay);
db_data.push_back(dbd_level);
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());
try
{
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)
{
TANGO_LOG << __func__ << ": Exception saving configuration = " << e.errors[0].desc<<endl;
}
}
void alarm_table::save_alarm_conf_db(string att_name, Tango::TimeVal ts, string name, string status, string ack,
string formula, unsigned int time_threshold, string grp, string lev, string msg, string action, int silent_time, vector<string> alm_list)
void alarm_table::delete_alarm_conf_db(string att_name)
{
// We want to put properties for attribute "att_name"
Tango::DbDatum dbd_att_name(att_name);
Tango::DbDatum dbd_name("name");
Tango::DbDatum dbd_formula("formula");
Tango::DbDatum dbd_time_threshold("time_threshold");
Tango::DbDatum dbd_level("level");
Tango::DbDatum dbd_silence_time("silence_time"); //TODO: silent_time
Tango::DbDatum dbd_group("group");
Tango::DbDatum dbd_message("message");
Tango::DbDatum dbd_command("command"); //TODO: action
Tango::DbDatum dbd_name(NAME_KEY);
Tango::DbDatum dbd_formula(FORMULA_KEY);
Tango::DbDatum dbd_on_delay(ONDELAY_KEY);
Tango::DbDatum dbd_off_delay(OFFDELAY_KEY);
Tango::DbDatum dbd_level(LEVEL_KEY);
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 << 8; // Eigth properties for attribute "att_name"
dbd_name << name;
dbd_formula << formula;
dbd_time_threshold << time_threshold;
dbd_level << lev;
dbd_silence_time << silent_time;
dbd_group << grp;
dbd_message << msg;
dbd_command << action;
db_data.push_back(dbd_att_name);
db_data.push_back(dbd_name);
db_data.push_back(dbd_formula);
db_data.push_back(dbd_time_threshold);
db_data.push_back(dbd_on_delay);
db_data.push_back(dbd_off_delay);
db_data.push_back(dbd_level);
db_data.push_back(dbd_silence_time);
db_data.push_back(dbd_group);
db_data.push_back(dbd_message);
db_data.push_back(dbd_command);
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());
Tango::DbDevice *db_dev = mydev->get_db_device();
db_dev->get_dbase()->put_device_attribute_property(dev_name,db_data);
try
{
Tango::DbDevice *db_dev = mydev->get_db_device();
db_dev->get_dbase()->delete_device_attribute_property(dev_name,db_data);
}
catch(Tango::DevFailed &e)
{
TANGO_LOG << __func__ << ": Exception deleting " << att_name << " = " << e.errors[0].desc<<endl;
}
}
void alarm_table::get_alarm_list_db(vector<string> &al_list)
void alarm_table::get_alarm_list_db(vector<string> &al_list, map<string, string> &saved_alarms, ReadersWritersLock *savedlock)
{
//logloop->get_alarm_list(al_list);
/*
* " CONCAT('\t', " << DESC_COL_NAME << ",'\t'," << DESC_COL_FORMULA <<
",'\t'," << "IFNULL(" << DESC_COL_TIME_THRESHOLD << ",0)" << ",'\t'," << DESC_COL_LEVEL <<
",'\t'," << "IFNULL(" << DESC_COL_SILENT_TIME << ",-1)" <<
",'\t'," << DESC_COL_GRP << ",'\t','\"'," << "IFNULL(" << DESC_COL_MSG << ",'')" <<
",'\"','\t'," << "IFNULL(" << DESC_COL_ACTION << ",';')" << ")" <<
*/
string dev_name(mydev->get_name());
vector<string> att_list;
......@@ -843,8 +1006,16 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list)
db_data.push_back(Tango::DbDatum(*it));
}
db_dev->get_attribute_property(db_data);
try
{
db_dev->get_attribute_property(db_data);
}
catch(Tango::DevFailed &e)
{
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;
......@@ -853,45 +1024,81 @@ void alarm_table::get_alarm_list_db(vector<string> &al_list)
i++;
string alm_name;
string alm_formula;
string alm_time_threshold("0");
string alm_on_delay("0");
string alm_off_delay("0");
string alm_level;
string alm_silence_time("-1");
string alm_group;
string alm_message;
string alm_command(";");
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;
if (prop_name == "name")
if (prop_name == NAME_KEY)
db_data[i] >> alm_name;
else if (prop_name == "formula")
else if (prop_name == FORMULA_KEY)
db_data[i] >> alm_formula;
else if (prop_name == "time_threshold")
db_data[i] >> alm_time_threshold;
else if (prop_name == "level")
else if (prop_name == ONDELAY_KEY)
db_data[i] >> alm_on_delay;
else if (prop_name == OFFDELAY_KEY)
db_data[i] >> alm_off_delay;
else if (prop_name == LEVEL_KEY)
db_data[i] >> alm_level;
else if (prop_name == "silence_time")
else if (prop_name == SILENT_TIME_KEY)
db_data[i] >> alm_silence_time;
else if (prop_name == "group")
else if (prop_name == GROUP_KEY)
db_data[i] >> alm_group;
else if (prop_name == "message")
else if (prop_name == MESSAGE_KEY)
db_data[i] >> alm_message;
else if (prop_name == "command")
db_data[i] >> alm_command;
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 << alm_name << "\t" << alm_formula << "\t" << alm_time_threshold << "\t" << alm_level <<
"\t" << alm_silence_time << "\t" << alm_group << "\t\"" << alm_message << "\"\t" << alm_command;
alm << KEY(NAME_KEY)<<alm_name << SEP <<
KEY(FORMULA_KEY)<<alm_formula << SEP <<
KEY(ONDELAY_KEY)<<alm_on_delay << SEP <<
KEY(OFFDELAY_KEY)<<alm_off_delay << SEP <<
KEY(LEVEL_KEY)<< alm_level << SEP <<
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
{
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)
......@@ -258,15 +511,29 @@ class alarm_t {
string name,
formula;
string attr_name;
Tango::DevBoolean *attr_value;
string attr_name_formula;
Tango::DevEnum *attr_value;
Tango::DevString *attr_value_formula;
int quality;
string ex_reason;
string ex_desc;
string ex_origin;
Tango::TimeVal ts;
string stat,
ack;
unsigned int 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;
......@@ -275,23 +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_time_threshold; //says when it has gone in alarm status for the first time
unsigned int time_threshold; //TODO: seconds, is it enough precision?
Tango::TimeVal ts_on_delay; //says when it has gone in alarm status for the first time
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{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_time_threshold; //attr_values of first occurrence of alarm waiting for time threshold
string cmd_name_a; //action to execute: when NORMAL -> ALARM, cmd_name = cmd_dp_a/cmd_action_a
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_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
......@@ -299,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);
......@@ -310,6 +587,7 @@ class alarm_t {
void str2grp(string &s);
void insert(const string& s);
void clear();
void confstr(string &s);
protected:
private:
......@@ -317,15 +595,13 @@ class alarm_t {
};
typedef map<string,alarm_t> alarm_container_t;
#ifndef _RW_LOCK
class alarm_table : public omni_mutex {
#else
class alarm_table {
#endif
public:
alarm_table() {}
~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);
......@@ -342,29 +618,30 @@ class alarm_table {
vector<string> to_be_evaluated_list();
//vector<alarm_t> v_alarm;
alarm_container_t v_alarm;
#ifdef _RW_LOCK
#ifndef _USE_BOOST_LOCK
ReadersWritersLock *vlock;
#else
rwlock_t *vlock;
#endif
void new_rwlock();
void del_rwlock();
#endif
void init_logdb(string dbhost, string dbuser, string dbpw, string dbname, int dbport, string instance_name);
void stop_logdb();
void log_alarm_db(unsigned int type, Tango::TimeVal ts, string name, string status, string ack,
string formula, unsigned int time_threshold, string grp, string lev, string msg, string action, int silent_time, vector<string> alm_list=vector<string>());
void save_alarm_conf_db(string att_name, Tango::TimeVal ts, string name, string status, string ack,
string formula, unsigned int time_threshold, string grp, string lev, string msg, string action, int silent_time, vector<string> alm_list=vector<string>());
void get_alarm_list_db(vector<string> &al_list);
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, 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;
};
......
/*
* cmd_thread.cpp
*
* $Author: claudio $
*
* $Revision: 1.3 $
*
* $Log: cmd_thread.cpp,v $
* Revision 1.3 2015-07-21 13:40:59 claudio
* minor cleanups
*
* Revision 1.2 2008-11-17 13:13:21 graziano
* command action can be: without arguments or with string argument
*
* Revision 1.1 2008/11/10 10:53:31 graziano
* thread for execution of commands
*
*
*
*
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
* 34012 Basovizza, Trieste ITALY
......@@ -32,8 +14,8 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.3 $";
*/
cmd_thread::cmd_thread()
{
cout << __FILE__rev << endl;
cout << gettime().tv_sec << " cmd_thread::cmd_thread(): constructor... !" << endl;
TANGO_LOG << __FILE__rev << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::cmd_thread(): constructor... !" << endl;
//mutex_dp = new omni_mutex::omni_mutex();
}
......@@ -42,7 +24,7 @@ cmd_thread::cmd_thread()
*/
cmd_thread::~cmd_thread()
{
cout << gettime().tv_sec << " cmd_thread::~cmd_thread(): delete device entering..." << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::~cmd_thread(): delete device entering..." << endl;
//delete mutex_dp;
}
......@@ -62,13 +44,13 @@ void cmd_thread::run(void *)
switch(cmd.cmd_id)
{
case CMD_THREAD_EXIT:
cout << gettime().tv_sec << " cmd_thread::run(): received command THREAD_EXIT -> exiting..." << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run(): received command THREAD_EXIT -> exiting..." << endl;
return;
case CMD_COMMAND:
{
try {
cout << gettime().tv_sec << " cmd_thread::run(): COMMAND ... action=" << cmd.arg_s3 << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run(): COMMAND ... action=" << cmd.arg_s3 << endl;
dp = (Tango::DeviceProxy *)cmd.dp_add;
if(cmd.arg_b)
{
......@@ -82,7 +64,7 @@ void cmd_thread::run(void *)
}
else
call_id = dp->command_inout_asynch(cmd.arg_s2);
cout << gettime().tv_sec << " cmd_thread::run() executed action: " << cmd.arg_s3 << " !!! call_id=" << call_id << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run() executed action: " << cmd.arg_s3 << " !!! call_id=" << call_id << endl;
/*cmd_t arg;
arg.cmd_id = CMD_RESPONSE;
arg.call_id = call_id;
......@@ -94,18 +76,18 @@ void cmd_thread::run(void *)
cmd.cmd_id = CMD_RESPONSE; //if no exception till now push in list request of response
cmd.call_id = call_id; //if no exception till now push in list request of response
list.push_back(cmd); //if no exception till now push in list request of response
} catch(Tango::DevFailed e)
} catch(Tango::DevFailed &e)
{
TangoSys_MemStream out_stream;
string err(e.errors[0].desc);
if(err.find("is not yet arrived") == string::npos) //TODO: change this!!
{
out_stream << "Failed to execute action " << cmd.arg_s3 << ", err=" << e.errors[0].desc << ends;
cout << gettime().tv_sec << " cmd_thread::run() ERROR: " << out_stream.str() << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run() ERROR: " << out_stream.str() << endl;
}
else
{
cout << gettime().tv_sec << " cmd_thread::run() exception 'is not yet arrived': pushing request of response, call_id=" << call_id << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run() exception 'is not yet arrived': pushing request of response, call_id=" << call_id << endl;
cmd.cmd_id = CMD_RESPONSE; //if no exception till now push in list request of response
cmd.call_id = call_id; //if no exception till now push in list request of response
list.push_back(cmd); //if no exception till now push in list request of response
......@@ -117,13 +99,13 @@ void cmd_thread::run(void *)
case CMD_RESPONSE:
{
//cout << gettime().tv_sec << " cmd_thread::run(): RESPONSE WAKE UP... action=" << cmd.arg_s3 << " call_id=" << cmd.call_id << endl;
//TANGO_LOG << gettime().tv_sec << " cmd_thread::run(): RESPONSE WAKE UP... action=" << cmd.arg_s3 << " call_id=" << cmd.call_id << endl;
Tango::DeviceData resp;
dp = (Tango::DeviceProxy *)cmd.dp_add;
try {
resp = dp->command_inout_reply(cmd.call_id);
cout << gettime().tv_sec << " cmd_thread::run() RECEIVED response to action " << cmd.arg_s3 << endl;
} catch(Tango::DevFailed e)
TANGO_LOG << gettime().tv_sec << " cmd_thread::run() RECEIVED response to action " << cmd.arg_s3 << endl;
} catch(Tango::DevFailed &e)
{
TangoSys_MemStream out_stream;
out_stream << "EXCEPTION executing action " << cmd.arg_s3 << ", err=" << e.errors[0].desc << ends;
......@@ -136,7 +118,7 @@ void cmd_thread::run(void *)
}
else
{
cout << gettime().tv_sec << " cmd_thread::run() " << out_stream.str() << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run() " << out_stream.str() << endl;
Tango::Except::print_exception(e);
}
}
......@@ -145,20 +127,20 @@ void cmd_thread::run(void *)
}
/* if(cmd.arg_s == CMD_THREAD_EXIT)
{
cout << gettime().tv_sec << " cmd_thread::run(): received command THREAD_EXIT -> exiting..." << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run(): received command THREAD_EXIT -> exiting..." << endl;
return;
}
else
{
cout << gettime().tv_sec << " cmd_thread::run(): WAKE UP... action=" << cmd.arg_s << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run(): WAKE UP... action=" << cmd.arg_s << endl;
Tango::DeviceData resp;
dp = (Tango::DeviceProxy *)cmd.dp_add;
try {
mutex_dp->lock();
resp = dp->command_inout_reply(cmd.cmd_id);
mutex_dp->unlock();
cout << gettime().tv_sec << " cmd_thread::run() received response to action " << cmd.arg_s << endl;
} catch(Tango::DevFailed e)
TANGO_LOG << gettime().tv_sec << " cmd_thread::run() received response to action " << cmd.arg_s << endl;
} catch(Tango::DevFailed &e)
{
TangoSys_MemStream out_stream;
out_stream << "EXCEPTION executing action " << cmd.arg_s << ", err=" << e.errors[0].desc << ends;
......@@ -170,7 +152,7 @@ void cmd_thread::run(void *)
omni_thread::sleep(0,300000000); //0.2 s
}
else
cout << gettime().tv_sec << " cmd_thread::run() " << out_stream.str() << endl;
TANGO_LOG << gettime().tv_sec << " cmd_thread::run() " << out_stream.str() << endl;
}
}*/
......@@ -196,7 +178,7 @@ void cmd_thread::run(void *)
printf("cmd_thread::run(): catched unknown exception!!");
}
}
//cout << "alarm_thread::run(): returning" << endl;
//TANGO_LOG << "alarm_thread::run(): returning" << endl;
} /* cmd_thread::run() */
/*
......@@ -206,7 +188,7 @@ void cmd_list::push_back(cmd_t& cmd)
{
this->lock();
//cout << "event_list::push_back: " << e.name << " value=" << e.value[0] << endl;
//TANGO_LOG << "cmd_list::push_back: cmd_id=" << cmd.cmd_id << " call_id=" << cmd.call_id << endl;
try{
l_cmd.push_back(cmd);
empty.signal();
......@@ -222,7 +204,7 @@ void cmd_list::push_back(cmd_t& cmd)
{
ostringstream err;
err << "exception signaling omni_condition: '" << ex.errors[0].desc << "'" << ends;
//WARN_STREAM << "event_list::push_back(): " << err.str() << endl;
//WARN_STREAM << "cmd_list::push_back(): " << err.str() << endl;
printf("cmd_list::push_back: %s", err.str().c_str());
Tango::Except::print_exception(ex);
}
......@@ -273,7 +255,7 @@ const cmd_t cmd_list::pop_front(void)
/*const*/ cmd_t cmd;
cmd = *(l_cmd.begin());
//cout << "event_list::pop_front: " << e.name << " value=" << e.value[0] << endl;
//TANGO_LOG << "cmd_list::pop_front: " << e.name << " value=" << e.value[0] << endl;
l_cmd.pop_front();
this->unlock();
......
/*
*cmd_thread.h
*
* $Author: graziano $
*
* $Revision: 1.2 $
*
* $Log: cmd_thread.h,v $
* Revision 1.2 2008-11-17 13:10:36 graziano
* command action can be: without arguments or with string argument
*
* Revision 1.1 2008/11/10 10:53:31 graziano
* thread for execution of commands
*
* Revision 1.2 2008/10/07 14:03:07 graziano
* added handling of multi axis groups and spindle groups
*
* Revision 1.1 2008/09/30 09:46:32 graziano
* first version
*
* Revision 1.3 2008/04/23 15:00:57 graziano
* small code cleanings
*
*
* cmd_thread.h
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
......@@ -41,8 +19,8 @@
#define CMD_THREAD_EXIT 3
#include <omnithread.h>
#include <tango.h>
#include "Alarm.h"
#include <tango/tango.h>
#include "AlarmHandler.h"
struct cmd_t
{
......
/*
* event_table.cpp
*
* $Author: graziano $
*
* $Revision: 1.5 $
*
* $Log: event_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 "event_table.h"
#include "Alarm.h"
#include "AlarmHandler.h"
#include "alarm_grammar.h"
//for get_event_system_for_event_id, to know if ZMQ
#include <eventconsumer.h>
#include <regex>
static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $";
......@@ -37,17 +30,17 @@ void event_list::push_back(bei_t& e)
catch(omni_thread_fatal& ex)
{
ostringstream err;
err << "omni_thread_fatal exception signaling omni_condition, err=" << ex.error << ends;
err << "omni_thread_fatal exception signaling omni_condition, err=" << ex.error;
//WARN_STREAM << "event_list::push_back(): " << err.str() << endl;
printf("event_list::push_back(): %s", err.str().c_str());
}
catch(Tango::DevFailed& ex)
{
ostringstream err;
err << "exception signaling omni_condition: '" << ex.errors[0].desc << "'" << ends;
err << "exception signaling omni_condition: '" << ex.errors[0].desc << "'";
//WARN_STREAM << "event_list::push_back(): " << err.str() << endl;
printf("event_list::push_back: %s", err.str().c_str());
Tango::Except::print_exception(ex);
//printf("event_list::push_back: %s", err.str().c_str());
//Tango::Except::print_exception(ex);
}
catch(...)
{
......@@ -68,7 +61,7 @@ const bei_t event_list::pop_front(void)
catch(omni_thread_fatal& ex)
{
ostringstream err;
err << "omni_thread_fatal exception waiting on omni_condition, err=" << ex.error << ends;
err << "omni_thread_fatal exception waiting on omni_condition, err=" << ex.error;
//WARN_STREAM << "event_list::pop_front(): " << err.str() << endl;
printf("event_list::pop_front(): %s", err.str().c_str());
bei_t e;
......@@ -79,10 +72,10 @@ const bei_t event_list::pop_front(void)
catch(Tango::DevFailed& ex)
{
ostringstream err;
err << "exception waiting on omni_condition: '" << ex.errors[0].desc << "'" << ends;
err << "exception waiting on omni_condition: '" << ex.errors[0].desc << "'";
//WARN_STREAM << "event_list::pop_front(): " << err.str() << endl;
printf("event_list::pop_front: %s", err.str().c_str());
Tango::Except::print_exception(ex);
//printf("event_list::pop_front: %s", err.str().c_str());
//Tango::Except::print_exception(ex);
bei_t e;
this->unlock();
sleep(1);
......@@ -124,6 +117,65 @@ list<bei_t> event_list::show(void)
return(el);
}
size_t event_list::size(void)
{
size_t res;
this->lock();
res = l_event.size();
this->unlock();
return(res);
}
/*
* alarm_list class methods
*/
void alarm_list::push(string& a)
{
l.lock();
l_alarm.push_back(a);
l.unlock();
}
void alarm_list::pop(const string& a)
{
l.lock();
list<string>::iterator it = find(l_alarm.begin(), l_alarm.end(), a);
if(it != l_alarm.end())
l_alarm.erase(it);
else
TANGO_LOG << "alarm_list::"<<__func__<< ": ALARM '"<< a << "' NOT FOUND!"<< endl;
l.unlock();
return;
}
void alarm_list::clear(void)
{
l.lock();
l_alarm.clear();
l.unlock();
}
list<string> alarm_list::show(void)
{
list<string> al;
l.lock();
al = l_alarm;
l.unlock();
return(al);
}
bool alarm_list::empty(void)
{
bool res;
l.lock();
res = l_alarm.empty();
l.unlock();
return(res);
}
/*
* event class methods
......@@ -149,6 +201,8 @@ event::event(string& s, value_t& v, Tango::TimeVal& t) : \
event_id = SUB_ERR;
err_counter = 0;
valid = false;
dim_x=0;
dim_y=0;
}
event::event(string& s) : name(s)
......@@ -170,22 +224,9 @@ event::event(string& s) : name(s)
type = -1;
event_id = SUB_ERR;
err_counter = 0;
valid = false;
}
void event::push_alarm(string& n)
{
m_alarm.push_back(n);
}
void event::pop_alarm(string& n)
{
vector<string>::iterator it = find(m_alarm.begin(), m_alarm.end(), n);
if(it != m_alarm.end())
m_alarm.erase(it);
else
cout << "event::"<<__func__<< ": event="<<name<<" ALARM '"<< n << "' NOT FOUND!"<< endl;
valid = false;
dim_x=0;
dim_y=0;
}
bool event::operator==(const event& e)
......@@ -206,13 +247,73 @@ bool event::operator==(const string& s)
// v_event.push_back(e);//TODO: replaced with add
}*/
void event_table::show(void)
void event_table::show(list<string> &evl)
{
DEBUG_STREAM << "events found:" << endl;
if (v_event.empty() == false) {
evl.clear();
ReaderLock lock(veclock);
if (v_event.empty() == false)
{
vector<event>::iterator i = v_event.begin();
while (i != v_event.end()) {
DEBUG_STREAM << "\t" << i->name << endl;
while (i != v_event.end())
{
//DEBUG_STREAM << "\t" << i->name << endl;
evl.push_back(i->name);
i++;
}
}
}
void event_table::summary(list<string> &evs)
{
evs.clear();
ReaderLock lock(veclock);
if (v_event.empty() == false)
{
vector<event>::iterator i = v_event.begin();
while (i != v_event.end())
{
ostringstream ev_summary;
ev_summary << KEY(EVENT_KEY) << i->name << SEP;
tm time_tm;
time_t time_sec;
if(i->valid)
{
time_sec= i->ts.tv_sec;
}
else
{
timeval now;
gettimeofday(&now, NULL);
time_sec = now.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);
ev_summary << KEY(EVENT_TIME_KEY) << time_buf << SEP;
ostringstream tmp_val;
if(i->type != Tango::DEV_STRING)
tmp_val << print_array(i->value,i->dim_x,i->dim_y);
else
tmp_val << "[\""<<i->value_string<<"\"]";
ev_summary << KEY(ATTR_VALUES_KEY) << tmp_val.str() << SEP;
ostringstream tmp_ex;
//tmp_ex.str("");
if(!i->ex_reason.empty() || !i->ex_desc.empty() || !i->ex_origin.empty())
{
tmp_ex << "{\"Reason\":\"" << i->ex_reason << "\",\"Desc\":\"" << i->ex_desc << "\",\"Origin\":\"" << i->ex_origin << "\"}";
}
ev_summary << KEY(EXCEPTION_KEY) << tmp_ex.str() << SEP;
ev_summary << KEY(QUALITY_KEY);
try
{
ev_summary << quality_labels.at(i->quality) << SEP;
} catch(std::out_of_range& ex)
{
ev_summary << i->quality << SEP;
}
evs.push_back(ev_summary.str());
i++;
}
}
......@@ -222,11 +323,12 @@ event_table::event_table(Tango::DeviceImpl *s):Tango::LogAdapter(s)
{
mydev = s;
stop_it = false;
action = NOTHING;
action.store(NOTHING);
}
unsigned int event_table::size(void)
{
ReaderLock lock(veclock); //TODO: necessary?
return(v_event.size());
}
#if 0
......@@ -243,7 +345,7 @@ void event_table::init_proxy(void) throw(vector<string> &)
{
ostringstream o;
o << "new DeviceProxy() failed for " \
<< i->device << ends;
<< i->device;
ERROR_STREAM << o.str() << endl;
//throw o.str();
proxy_error.push_back(o.str());
......@@ -270,7 +372,7 @@ void event_table::free_proxy(void)
}
}
void event_table::subscribe(EventCallBack& ecb) throw(vector<string> &)//throw(string&)
void event_table::subscribe(EventCallBack& ecb)
{
vector<string> subscribe_error;
if (v_event.empty() == false) {
......@@ -283,7 +385,7 @@ void event_table::subscribe(EventCallBack& ecb) throw(vector<string> &)//throw(s
} catch (...) {
ostringstream o;
o << "subscribe_event() failed for " \
<< i->name << ends;
<< i->name;
ERROR_STREAM << o.str() << endl;
//throw o.str();
subscribe_error.push_back(o.str());
......@@ -294,7 +396,7 @@ void event_table::subscribe(EventCallBack& ecb) throw(vector<string> &)//throw(s
throw subscribe_error;
}
void event_table::unsubscribe(void) throw(string&)
void event_table::unsubscribe(void)
{
ostringstream o;
if (v_event.empty() == false) {
......@@ -336,13 +438,12 @@ event *event_table::get_signal(string signame)
for (unsigned int i=0 ; i<v_event.size() ; i++)
{
event *sig = &v_event[i];
if (static_cast<Alarm_ns::Alarm *>(mydev)->compare_without_domain(sig->name,signame))
if (static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_without_domain(sig->name,signame))
return sig;
}
return NULL;
}
//=============================================================================
/**
* Stop saving on DB a signal.
......@@ -360,10 +461,8 @@ void event_table::stop(string &signame)
if(!v_event[i].stopped)
{
v_event[i].stopped=true;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read++;
if(v_event[i].running)
{
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStartedNumber_read--;
try
{
remove(signame, true);
......@@ -376,7 +475,6 @@ void event_table::stop(string &signame)
}
if(v_event[i].paused)
{
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributePausedNumber_read--;
try
{
remove(signame, true);
......@@ -397,19 +495,17 @@ void event_table::stop(string &signame)
for (unsigned int i=0 ; i<v_event.size() ; i++)
{
#ifndef _MULTI_TANGO_HOST
if (static_cast<Alarm_ns::Alarm *>(mydev)->compare_without_domain(v_event[i].name,signame))
if (static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_without_domain(v_event[i].name,signame))
#else
if (!static_cast<Alarm_ns::Alarm *>(mydev)->compare_tango_names(v_event[i].name,signame))
if (!static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_tango_names(v_event[i].name,signame))
#endif
{
v_event[i].siglock->writerIn();
if(!v_event[i].stopped)
{
v_event[i].stopped=true;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read++;
if(v_event[i].running)
{
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStartedNumber_read--;
try
{
remove(signame, true);
......@@ -422,7 +518,6 @@ void event_table::stop(string &signame)
}
if(v_event[i].paused)
{
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributePausedNumber_read--;
try
{
remove(signame, true);
......@@ -448,7 +543,6 @@ void event_table::stop(string &signame)
(const char *)"event_table::stop()");
}
//=============================================================================
/**
* Remove a signal in the list.
......@@ -524,13 +618,7 @@ void event_table::remove(string &signame, bool stop)
}
if(!stop)
{
if(sig->running)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStartedNumber_read--;
if(sig->paused)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributePausedNumber_read--;
if(sig->stopped)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read--;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeNumber_read--;
static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->attr_AttributeNumber_read--;
delete sig->siglock;
v_event.erase(pos);
DEBUG_STREAM <<"event_table::"<< __func__<<": removed " << signame << endl;
......@@ -545,9 +633,9 @@ void event_table::remove(string &signame, bool stop)
{
event *sig = &v_event[i];
#ifndef _MULTI_TANGO_HOST
if (static_cast<Alarm_ns::Alarm *>(mydev)->compare_without_domain(sig->name,signame))
if (static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_without_domain(sig->name,signame))
#else
if (!static_cast<Alarm_ns::Alarm *>(mydev)->compare_tango_names(sig->name,signame))
if (!static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_tango_names(sig->name,signame))
#endif
{
found = true;
......@@ -575,13 +663,8 @@ void event_table::remove(string &signame, bool stop)
}
if(!stop)
{
if(sig->running)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStartedNumber_read--;
if(sig->paused)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributePausedNumber_read--;
if(sig->stopped)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read--;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeNumber_read--;
static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->attr_AttributeNumber_read--;
delete sig->siglock;
v_event.erase(pos);
DEBUG_STREAM <<"event_table::"<< __func__<<": removed " << signame << endl;
......@@ -610,10 +693,9 @@ void event_table::remove(string &signame, bool stop)
}
void event_table::update_property()
{
DEBUG_STREAM <<"event_table::"<< __func__<<": going to increase action... action="<<action<<"++" << endl;
if(action <= UPDATE_PROP)
action++;
//put_signal_property(); //TODO: wakeup thread and let it do it? -> signal()
DEBUG_STREAM <<"event_table::"<< __func__<<": going to increase action... action="<<action.load()<<"++" << endl;
int expected=NOTHING;
action.compare_exchange_strong(expected, UPDATE_PROP); //if it is NOTHING, then change to UPDATE_PROP
signal();
}
//=============================================================================
......@@ -709,7 +791,7 @@ void event_table::add(string &signame, vector<string> contexts, int to_do, bool
for (unsigned int i=0 ; i<v_event.size() && !found ; i++)
{
sig = &v_event[i];
found = static_cast<Alarm_ns::Alarm *>(mydev)->compare_without_domain(sig->name,signame);
found = static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_without_domain(sig->name,signame);
}
veclock.readerOut();
//DEBUG_STREAM << "event_table::"<<__func__<<": signame="<<signame<<" found="<<(found ? "Y" : "N") << " start="<<(start ? "Y" : "N")<< endl;
......@@ -743,20 +825,25 @@ void event_table::add(string &signame, vector<string> contexts, int to_do, bool
signal->running = false;
signal->stopped = true;
signal->paused = false;
signal->valid = false;
signal->dim_x=0;
signal->dim_y=0;
//DEBUG_STREAM << "event_table::"<<__func__<<": signame="<<signame<<" created signal"<< endl;
}
else if(found && start)
{
signal = sig;
#if 0
signal->siglock->writerIn();
signal->ex_reason = "NOT_connected";
signal->ex_desc = "Attribute not subscribed";
signal->ex_origin = "...";
signal->siglock->writerOut();
#endif
//DEBUG_STREAM << "created proxy to " << signame << endl;
// create Attribute proxy
signal->attr = new Tango::AttributeProxy(signal->name); //TODO: OK out of siglock? accessed only inside the same thread?
DEBUG_STREAM << "event_table::"<<__func__<<": signame="<<signame<<" created proxy"<< endl;
DEBUG_STREAM << "event_table::"<<__func__<<": signame="<<signame<<" created proxy"<< endl;
}
signal->event_id = SUB_ERR;
signal->evstate = Tango::ALARM;
......@@ -781,8 +868,8 @@ void event_table::add(string &signame, vector<string> contexts, int to_do, bool
// Add in vector
v_event.push_back(*signal);
delete signal;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeNumber_read++;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read++;
static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->attr_AttributeNumber_read++;
//static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->attr_AttributeStoppedNumber_read++;
veclock.writerOut();
//DEBUG_STREAM << "event_table::"<<__func__<<": signame="<<signame<<" push_back signal"<< endl;
}
......@@ -790,9 +877,10 @@ void event_table::add(string &signame, vector<string> contexts, int to_do, bool
{
}
DEBUG_STREAM <<"event_table::"<< __func__<<": going to increase action... action="<<action<<" += " << to_do << endl;
if(action <= UPDATE_PROP)
action += to_do;
int act=action.load();
DEBUG_STREAM <<"event_table::"<< __func__<<": going to increase action... action="<<act<<" += " << to_do << endl;
int expected=NOTHING;
action.compare_exchange_strong(expected, UPDATE_PROP); //if it is NOTHING, then change to UPDATE_PROP
}
DEBUG_STREAM <<"event_table::"<< __func__<<": exiting... " << signame << endl;
signal();
......@@ -813,11 +901,15 @@ void event_table::subscribe_events()
if(ret == 0) pthread_rwlock_unlock(&sig2->siglock);
}*/
//omni_mutex_lock sync(*this);
veclock.readerIn();
for (unsigned int i=0 ; i<v_event.size() ; i++)
list<string> l_events;
show(l_events);
DEBUG_STREAM << "event_table::" << __func__ << ": going to subscribe " << v_event.size() << " attributes" << endl;
for (auto it : l_events)
{
event *sig = &v_event[i];
sig->siglock->writerIn();
veclock.readerIn();
event *sig = get_signal(it);
sig->siglock->readerIn();
string sig_name(sig->name);
if (sig->event_id==SUB_ERR && !sig->stopped)
{
if(!sig->attr)
......@@ -829,20 +921,44 @@ void event_table::subscribe_events()
}
catch (Tango::DevFailed &e)
{
//Tango::Except::print_exception(e);
INFO_STREAM << "event_table::subscribe_events: error adding " << sig->name <<" err="<< e.errors[0].desc << endl;
v_event[i].ex_reason = e.errors[0].reason;
v_event[i].ex_desc = e.errors[0].desc;
v_event[i].ex_origin = e.errors[0].origin;
v_event[i].siglock->writerOut();
string ex_reason(e.errors[0].reason);
ex_reason = std::regex_replace(ex_reason, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
string ex_desc(e.errors[0].desc);
ex_desc = std::regex_replace(ex_desc, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
string ex_origin(e.errors[0].origin);
ex_origin = std::regex_replace(ex_origin, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
bei_t ex;
ostringstream o;
o << "Error adding'" \
<< sig->name << "' error=" << ex_desc;
INFO_STREAM << "event_table::subscribe_events: " << o.str() << endl;
sig->ex_reason = ex.ex_reason = ex_reason;
sig->ex_desc = ex.ex_desc = ex_desc;
// sig->ex_desc.erase(std::remove(sig->ex_desc.begin(), sig->ex_desc.end(), '\n'), sig->ex_desc.end());
sig->ex_origin = ex.ex_origin = ex_origin;
sig->ts = ex.ts = gettime();
sig->quality = ex.quality = Tango::ATTR_INVALID;
ex.ev_name = sig->name;
sig->siglock->readerOut();
veclock.readerOut();
//TODO: since event callback not called for this attribute, need to manually trigger do_alarm to update internal structures ?
ex.type = TYPE_TANGO_ERR;
ex.msg=o.str();
try
{//DevFailed for push events
static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->do_alarm(ex);
} catch(Tango::DevFailed & ee)
{
WARN_STREAM << "event_table::"<<__func__<<": " << sig_name << " - EXCEPTION PUSHING EVENTS: " << ee.errors[0].desc << endl;
}
continue;
}
}
sig->event_cb = new EventCallBack(static_cast<Alarm_ns::Alarm *>(mydev));
sig->event_cb = new EventCallBack(static_cast<AlarmHandler_ns::AlarmHandler *>(mydev));
sig->first = true;
sig->first_err = true;
DEBUG_STREAM << "event_table::"<<__func__<<":Subscribing for " << sig->name << " " << (sig->first ? "FIRST" : "NOT FIRST") << endl;
sig->siglock->writerOut();
DEBUG_STREAM << "event_table::"<<__func__<<":Subscribing for " << sig_name << " " << (sig->first ? "FIRST" : "NOT FIRST") << endl;
sig->siglock->readerOut();
int event_id = SUB_ERR;
bool isZMQ = true;
bool err = false;
......@@ -860,39 +976,64 @@ void event_table::subscribe_events()
DEBUG_STREAM << sig->name << " Subscribed" << endl;*/
// Check event source ZMQ/Notifd ?
Tango::ZmqEventConsumer *consumer =
Tango::ApiUtil::instance()->get_zmq_event_consumer();
isZMQ = (consumer->get_event_system_for_event_id(event_id) == Tango::ZMQ);
/*Tango::ZmqEventConsumer *consumer =
Tango::ApiUtil::instance()->get_zmq_event_consumer();*/
isZMQ = true;//(consumer->get_event_system_for_event_id(event_id) == Tango::ZMQ);//TODO: remove
DEBUG_STREAM << sig->name << "(id="<< event_id <<"): Subscribed " << ((isZMQ)? "ZMQ Event" : "NOTIFD Event") << endl;
DEBUG_STREAM << sig_name << "(id="<< event_id <<"): Subscribed " << ((isZMQ)? "ZMQ Event" : "NOTIFD Event") << endl;
}
catch (Tango::DevFailed &e)
{
INFO_STREAM <<"event_table::"<<__func__<<": sig->attr->subscribe_event EXCEPTION:" << endl;
string ex_reason(e.errors[0].reason);
ex_reason = std::regex_replace(ex_reason, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
string ex_desc(e.errors[0].desc);
ex_desc = std::regex_replace(ex_desc, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
string ex_origin(e.errors[0].origin);
ex_origin = std::regex_replace(ex_origin, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
bei_t ex;
ostringstream o;
o << "Event exception for'" \
<< sig_name << "' error=" << ex_desc;
INFO_STREAM <<"event_table::"<<__func__<<": sig->attr->subscribe_event: " << o.str() << endl;
err = true;
Tango::Except::print_exception(e);
sig->siglock->writerIn();
sig->ex_reason = e.errors[0].reason;
sig->ex_desc = e.errors[0].desc;
sig->ex_origin = e.errors[0].origin;
//Tango::Except::print_exception(e);
//sig->siglock->writerIn(); //not yet subscribed, no one can modify
sig->ex_reason = ex.ex_reason = ex_reason;
sig->ex_desc = ex.ex_desc = ex_desc;
sig->ex_origin = ex.ex_origin = ex_origin;
sig->event_id = SUB_ERR;
delete sig->event_cb;
sig->siglock->writerOut();
sig->ts = ex.ts = gettime();
sig->quality = ex.quality = Tango::ATTR_INVALID;
ex.ev_name = sig->name;
//sig->siglock->writerOut();//not yet subscribed, no one can modify
veclock.readerOut();
//since event callback not called for this attribute, need to manually trigger do_alarm to update interlan structures
ex.type = TYPE_TANGO_ERR;
ex.msg=o.str();
try
{//DevFailed for push events
static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->do_alarm(ex);
} catch(Tango::DevFailed & ee)
{
WARN_STREAM << "event_table::"<<__func__<<": " << ex.ev_name << " - EXCEPTION PUSHING EVENTS: " << ee.errors[0].desc << endl;
}
continue;
}
if(!err)
{
sig->siglock->writerIn();
//sig->siglock->writerIn(); //nobody else write event_id and isZMQ
sig->event_id = event_id;
sig->isZMQ = isZMQ;
sig->siglock->writerOut();
//sig->siglock->writerOut();//nobody else write event_id and isZMQ
}
}
else
{
sig->siglock->writerOut();
sig->siglock->readerOut();
}
veclock.readerOut();
}
veclock.readerOut();
initialized = true;
}
......@@ -910,7 +1051,6 @@ void event_table::start(string &signame)
{
if(v_event[i].stopped)
{
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read--;
try
{
add(signame, contexts, NOTHING, true);
......@@ -927,9 +1067,6 @@ void event_table::start(string &signame)
}
}
v_event[i].running=true;
if(v_event[i].paused)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributePausedNumber_read--;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStartedNumber_read++;
v_event[i].paused=false;
v_event[i].stopped=false;
}
......@@ -940,9 +1077,9 @@ void event_table::start(string &signame)
for (unsigned int i=0 ; i<v_event.size() ; i++)
{
#ifndef _MULTI_TANGO_HOST
if (static_cast<Alarm_ns::Alarm *>(mydev)->compare_without_domain(v_event[i].name,signame))
if (static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_without_domain(v_event[i].name,signame))
#else
if (!static_cast<Alarm_ns::Alarm *>(mydev)->compare_tango_names(v_event[i].name,signame))
if (!static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->compare_tango_names(v_event[i].name,signame))
#endif
{
v_event[i].siglock->writerIn();
......@@ -950,7 +1087,6 @@ void event_table::start(string &signame)
{
if(v_event[i].stopped)
{
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read--;
try
{
add(signame, contexts, NOTHING, true);
......@@ -967,9 +1103,6 @@ void event_table::start(string &signame)
}
}
v_event[i].running=true;
if(v_event[i].paused)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributePausedNumber_read--;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStartedNumber_read++;
v_event[i].paused=false;
v_event[i].stopped=false;
}
......@@ -997,7 +1130,6 @@ void event_table::start_all()
if(v_event[i].stopped)
{
string signame = v_event[i].name;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStoppedNumber_read--;
try
{
add(signame, contexts, NOTHING, true);
......@@ -1014,9 +1146,6 @@ void event_table::start_all()
}
}
v_event[i].running=true;
if(v_event[i].paused)
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributePausedNumber_read--;
static_cast<Alarm_ns::Alarm *>(mydev)->attr_AttributeStartedNumber_read++;
v_event[i].paused=false;
v_event[i].stopped=false;
}
......@@ -1024,7 +1153,6 @@ void event_table::start_all()
}
}
//=============================================================================
//=============================================================================
bool event_table::get_if_stop()
......@@ -1069,15 +1197,34 @@ int event_table::nb_sig_to_subscribe()
//=============================================================================
void event_table::put_signal_property()
{
DEBUG_STREAM << "event_table::"<<__func__<<": put_signal_property entering action=" << action << endl;
//ReaderLock lock(veclock);
if (action>NOTHING)
int act=action.load();
DEBUG_STREAM << "event_table::"<<__func__<<": entering action=" << act << endl;
if (act>NOTHING)
{
static_cast<Alarm_ns::Alarm *>(mydev)->put_signal_property();
if(action >= UPDATE_PROP)
action--;
static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->put_signal_property();
int expected=UPDATE_PROP;
action.compare_exchange_strong(expected, NOTHING); //if it is UPDATE_PROP, then change to NOTHING
}
DEBUG_STREAM << "event_table::"<<__func__<<": put_signal_property exiting action=" << action << endl;
DEBUG_STREAM << "event_table::"<<__func__<<": exiting action=" << action.load() << endl;
}
//=============================================================================
/**
* build a list of signal to set HDB device property
*/
//=============================================================================
void event_table::check_signal_property()
{
int act=action.load();
DEBUG_STREAM << "event_table::"<<__func__<<": entering action=" << act << endl;
if (act>NOTHING)
return;
if (static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->check_signal_property())
{
int expected=NOTHING;
action.compare_exchange_strong(expected, UPDATE_PROP); //if it is NOTHING, then change to UPDATE_PROP
}
DEBUG_STREAM << "event_table::"<<__func__<<": exiting action=" << action.load() << endl;
}
......@@ -1105,7 +1252,7 @@ void EventCallBack::push_event(Tango::EventData* ev)
try {
//e.errors = ev->errors;
e.quality = Tango::ATTR_VALID;
//cout << "EVENT="<<ev->attr_name<<" quality="<<e.quality<<endl;
//TANGO_LOG << "EVENT="<<ev->attr_name<<" quality="<<e.quality<<endl;
if (!ev->err) {
e.quality = (int)ev->attr_value->get_quality();
#if 0//TANGO_VER >= 711
......@@ -1121,8 +1268,9 @@ void EventCallBack::push_event(Tango::EventData* ev)
e.ev_name = ev->attr_name;
#endif
e.ts = ev->attr_value->time;
extract_values(ev->attr_value, e.value, e.value_string, e.type);
extract_values(ev->attr_value, e.value, e.value_string, e.type, e.read_size, e.dim_x, e.dim_y);
} else {
e.quality = Tango::ATTR_INVALID;
#if 0//TANGO_VER >= 711
string ev_name_str(ev->attr_name);
string::size_type pos = ev_name_str.find("tango://");
......@@ -1141,12 +1289,13 @@ void EventCallBack::push_event(Tango::EventData* ev)
temp_name = temp_name.substr(0,pos_change);
}
ostringstream o;
o << "Tango error for '" << temp_name << "'=" << ev->errors[0].desc.in() << ends;
o << "Tango error for " << temp_name << ": " << ev->errors[0].desc.in();
e.ev_name = temp_name;
e.type = TYPE_TANGO_ERR;
//e.ev_name = INTERNAL_ERROR;
//e.type = -1;
e.msg = o.str();
e.msg = std::regex_replace(e.msg, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
}
}
catch (string &err) {
......@@ -1160,18 +1309,18 @@ void EventCallBack::push_event(Tango::EventData* ev)
{
ostringstream o;
o << "Event exception for'" \
<< ev->attr_name << "' error=" << Terr.errors[0].desc << ends;
<< ev->attr_name << "' error=" << Terr.errors[0].desc;
e.ev_name = ev->attr_name;
e.type = TYPE_GENERIC_ERR;
//e.value.i = 0;
e.ts = gettime();
e.msg = o.str();
//cerr << o.str() << endl;
e.msg = std::regex_replace(e.msg, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
}
catch (...) {
ostringstream o;
o << "Generic Event exception for'" \
<< ev->attr_name << "'" << ends;
<< ev->attr_name << "'";
e.ev_name = ev->attr_name;
e.type = TYPE_GENERIC_ERR;
//e.value.i = 0;
......@@ -1179,10 +1328,10 @@ void EventCallBack::push_event(Tango::EventData* ev)
e.msg = o.str();
//cerr << o.str() << endl;
}
static_cast<Alarm_ns::Alarm *>(mydev)->evlist.push_back(e);
static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->evlist.push_back(e);
} /* push_event() */
void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type)
void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size, long &dim_x, long &dim_y)
{
Tango::DevState stval;
vector<Tango::DevState> v_st;
......@@ -1196,78 +1345,107 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
vector<Tango::DevBoolean> v_bo;
vector<Tango::DevLong64> v_lo64;
vector<Tango::DevULong64> v_ulo64;
vector<Tango::DevEnum> v_enum;
vector<string> v_string;
val_string = string("");
//Tango::AttributeDimension attr_w_dim;
Tango::AttributeDimension attr_r_dim;
//attr_value->reset_exceptions(Tango::DeviceAttribute::isempty_flag); //disable is_empty exception //commented to throw exceptions if empty
if(!attr_value->is_empty())
{
//attr_w_dim = data->attr_value->get_w_dimension();
attr_r_dim = attr_value->get_r_dimension();
}
else
{
attr_r_dim.dim_x = 0;
//attr_w_dim.dim_x = 0;
attr_r_dim.dim_y = 0;
//attr_w_dim.dim_y = 0;
}
dim_x = attr_r_dim.dim_x;
dim_y = attr_r_dim.dim_y;
read_size = attr_r_dim.dim_x;
if(attr_r_dim.dim_y > 1)
read_size *= attr_r_dim.dim_y;
if (attr_value->get_type() == Tango::DEV_UCHAR) {
*(attr_value) >> v_uch;
attr_value->extract_read(v_uch);
for(vector<Tango::DevUChar>::iterator it = v_uch.begin(); it != v_uch.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_UCHAR;
} else if (attr_value->get_type() == Tango::DEV_SHORT) {
*(attr_value) >> v_sh;
attr_value->extract_read(v_sh);
for(vector<Tango::DevShort>::iterator it = v_sh.begin(); it != v_sh.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_SHORT;
} else if (attr_value->get_type() == Tango::DEV_USHORT) {
*(attr_value) >> v_ush;
attr_value->extract_read(v_ush);
for(vector<Tango::DevUShort>::iterator it = v_ush.begin(); it != v_ush.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_USHORT;
} else if (attr_value->get_type() == Tango::DEV_LONG) {
*(attr_value) >> v_lo;
attr_value->extract_read(v_lo);
for(vector<Tango::DevLong>::iterator it = v_lo.begin(); it != v_lo.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_LONG;
} else if (attr_value->get_type() == Tango::DEV_STATE) {
//*(attr_value) >> v_st; //doesn't work in tango 5
*(attr_value) >> stval;
v_st.push_back(stval);
for(vector<Tango::DevState>::iterator it = v_st.begin(); it != v_st.end(); it++)
val.push_back((double)(*it)); //convert all to double
//v_st.push_back(stval);
//attr_value->extract_read(stval);
//for(vector<Tango::DevState>::iterator it = v_st.begin(); it != v_st.end(); it++)
val.push_back((double)(stval)); //convert all to double
type = Tango::DEV_STATE;
#if 1//TANGO_VER >= 600
} else if (attr_value->get_type() == Tango::DEV_ULONG) {
*(attr_value) >> v_ulo;
attr_value->extract_read(v_ulo);
for(vector<Tango::DevULong>::iterator it = v_ulo.begin(); it != v_ulo.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_ULONG;
#endif //TANGO_VER >= 600
} else if (attr_value->get_type() == Tango::DEV_DOUBLE) {
*(attr_value) >> v_do;
attr_value->extract_read(v_do);
for(vector<Tango::DevDouble>::iterator it = v_do.begin(); it != v_do.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_DOUBLE;
} else if (attr_value->get_type() == Tango::DEV_FLOAT) {
*(attr_value) >> v_fl;
attr_value->extract_read(v_fl);
for(vector<Tango::DevFloat>::iterator it = v_fl.begin(); it != v_fl.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_FLOAT;
} else if (attr_value->get_type() == Tango::DEV_BOOLEAN) {
*(attr_value) >> v_bo;
attr_value->extract_read(v_bo);
for(vector<Tango::DevBoolean>::iterator it = v_bo.begin(); it != v_bo.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_BOOLEAN;
} else if (attr_value->get_type() == Tango::DEV_LONG64) {
*(attr_value) >> v_lo64;
attr_value->extract_read(v_lo64);
for(vector<Tango::DevLong64>::iterator it = v_lo64.begin(); it != v_lo64.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_LONG64;
} else if (attr_value->get_type() == Tango::DEV_ULONG64) {
*(attr_value) >> v_ulo64;
attr_value->extract_read(v_ulo64);
for(vector<Tango::DevULong64>::iterator it = v_ulo64.begin(); it != v_ulo64.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_ULONG64;
} else if (attr_value->get_type() == Tango::DEV_ENUM) {
attr_value->extract_read(v_enum);
for(vector<Tango::DevEnum>::iterator it = v_enum.begin(); it != v_enum.end(); it++)
val.push_back((double)(*it)); //convert all to double
type = Tango::DEV_ENUM;
} else if (attr_value->get_type() == Tango::DEV_STRING) {
*(attr_value) >> v_string;
attr_value->extract_read(v_string);
val_string = *(v_string.begin()); //TODO: support string spectrum attrbutes
type = Tango::DEV_STRING;
}
else {
ostringstream o;
o << "unknown type" << ends;
o << "unknown type";
throw o.str();
}
}
}
/*void EventCallBack::init(event_list* e)
......
/*
* event_table.h
*
* $Author: graziano $
*
* $Revision: 1.2 $
*
* $Log: event_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
......@@ -19,8 +12,8 @@
#include <iostream>
#include <string>
#include <map>
#include <tango.h>
#include <atomic>
#include <tango/tango.h>
using namespace std;
......@@ -28,10 +21,25 @@ using namespace std;
#define INTERNAL_ERROR "internal_error"
#define TYPE_TANGO_ERR -2
#define TYPE_GENERIC_ERR -3
#define SUB_ERR -1
#define NOTHING 0
#define UPDATE_PROP 1
constexpr int NOTHING = 0;
constexpr int UPDATE_PROP = 1;
class alarm_list {
public:
alarm_list(void) {}
alarm_list(const alarm_list& la) {l_alarm = la.l_alarm;}
~alarm_list(void) {}
void push(string& a);
void pop(const string &a);
void clear(void);
list<string> show(void);
bool empty();
alarm_list& operator=(const alarm_list& other) {if (this != &other) {l_alarm = other.l_alarm;} return *this;}
protected:
list<string> l_alarm;
omni_mutex l;
};
class event;
class event_list;
......@@ -50,21 +58,20 @@ class event {
string attname;
value_t value; /* event value */
string value_string; //added for DevString attributes
int quality;
//Tango::DevErrorList errors;
int quality{Tango::ATTR_INVALID};
string ex_reason;
string ex_desc;
string ex_origin;
Tango::TimeVal ts; /* event timestamp */
int type, /* attribute data type */
read_size, /* attribute size of read part */
counter, /* molteplicita' */
err_counter; /* molteplicita' errore */
//map<string, string> m_alarm;
vector<string> m_alarm;
err_counter; /* molteplicita' errore */
long dim_x, dim_y;
alarm_list m_alarm;
bool valid; //TODO: old
bool first;//TODO: new
bool first_err;//TODO: new
//Tango::DeviceProxy *dp;
Tango::AttributeProxy *attr;
Tango::DevState evstate;
unsigned int event_id;
......@@ -88,8 +95,8 @@ class event {
event(string& s);
event() {}
~event() {}
void push_alarm(string& n);
void pop_alarm(string& n);
//void push_alarm(string& n);
//void pop_alarm(string& n);
// bool event::operator==(const event& e); //TODO: gcc 4 problem??
bool operator==(const event& e);
// bool event::operator==(const string& s); //TODO: gcc 4 problem??
......@@ -109,6 +116,9 @@ typedef struct basic_event_info_s {
string ex_desc;
string ex_origin;
int type;
int read_size;
long dim_x;
long dim_y;
Tango::TimeVal ts;
string msg;
} bei_t;
......@@ -126,6 +136,7 @@ class event_list : public omni_mutex {
const bei_t pop_front(void);
void clear(void);
list<bei_t> show(void);
size_t size();
protected:
list<bei_t> l_event;
private:
......@@ -138,15 +149,16 @@ class event_list : public omni_mutex {
class event_table : public Tango::TangoMonitor, public Tango::LogAdapter {
public:
event_table(Tango::DeviceImpl *s);//:Tango::LogAdapter(s) {mydev = s;}
~event_table(void) {}
~event_table(void) {stop_thread();}
//void push_back(event e);
void show(void);
void show(list<string> &evl);
void summary(list<string> &evs);
unsigned int size(void);
#if 0
void init_proxy(void) throw(vector<string> &);
void free_proxy(void);
void subscribe(EventCallBack& ecb) throw(vector<string> &);//throw(string&);
void unsubscribe(void) throw(string&);
void subscribe(EventCallBack& ecb);
void unsubscribe(void);
#endif
/**
* Add a new signal.
......@@ -169,6 +181,7 @@ class event_table : public Tango::TangoMonitor, public Tango::LogAdapter {
* build a list of signal to set HDB device property
*/
void put_signal_property();
void check_signal_property();
bool is_initialized();
bool get_if_stop();
void stop_thread();
......@@ -176,7 +189,7 @@ class event_table : public Tango::TangoMonitor, public Tango::LogAdapter {
ReadersWritersLock veclock;
bool stop_it;
bool initialized;
int action;
atomic_int action;
private:
Tango::DeviceImpl *mydev;
}; /* class event_table */
......@@ -192,7 +205,7 @@ class EventCallBack : public Tango::CallBack, public Tango::LogAdapter
~EventCallBack(void);
void push_event(Tango::EventData* ev);
//void init(event_list* e);
void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type);
void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size, long &dim_x, long &dim_y);
private:
//event_list* e_ptr;
Tango::DeviceImpl *mydev;
......
/*
* formula_grammar.h
*
* $Author: graziano $
*
* $Revision: 1.5 $
*
* $Log: formula_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
......@@ -80,6 +73,20 @@ struct Assign_Stat
}
};
//TODO: duplicated from alarm.h
enum _AlarmStateEnum {
_NORM,
_UNACK,
_ACKED,
_RTNUN,
_SHLVD,
_DSUPR,
_OOSRV,
_ERROR
} ;
static vector<string> quality_labels = {"ATTR_VALID","ATTR_INVALID","ATTR_ALARM","ATTR_CHANGING","ATTR_WARNING"};
struct formula_grammar : public grammar<formula_grammar>
{
......@@ -116,10 +123,17 @@ struct formula_grammar : public grammar<formula_grammar>
static const int exprID = 21;
static const int nonempty_exprID = 22;
static const int val_qualityID = 23;
static const int val_alarm_enum_stID = 24;
static const int propertyID = 25;
static const int index_rangeID = 26;
static const int index_listID = 27;
symbols<unsigned int> tango_states;
symbols<unsigned int> attr_quality;
symbols<unsigned int> alarm_enum_states;
formula_grammar()
{
tango_states.add("ON", (unsigned int)Tango::ON);
......@@ -142,6 +156,16 @@ struct formula_grammar : public grammar<formula_grammar>
attr_quality.add("ATTR_ALARM", (unsigned int)Tango::ATTR_ALARM);
attr_quality.add("ATTR_CHANGING", (unsigned int)Tango::ATTR_CHANGING);
attr_quality.add("ATTR_WARNING", (unsigned int)Tango::ATTR_WARNING);
alarm_enum_states.add("NORM", (unsigned int)_NORM);
alarm_enum_states.add("UNACK", (unsigned int)_UNACK);
alarm_enum_states.add("ACKED", (unsigned int)_ACKED);
alarm_enum_states.add("RTNUN", (unsigned int)_RTNUN);
alarm_enum_states.add("SHLVD", (unsigned int)_SHLVD);
alarm_enum_states.add("DSUPR", (unsigned int)_DSUPR);
alarm_enum_states.add("OOSRV", (unsigned int)_OOSRV);
alarm_enum_states.add("ERROR", (unsigned int)_ERROR);
}
template <typename ScannerT>
......@@ -169,7 +193,7 @@ struct formula_grammar : public grammar<formula_grammar>
= (alnum_p | '.' | '_' | '-' | '+') //any alpha numeric char plus '.', '_', '-'
;
symbol_attr
= (alnum_p | '_' ) //any alpha numeric char plus '_' for attribute names
= (alnum_p | '_' | '.') - str_p(".normal") - str_p(".alarm") - str_p(".quality") //any alpha numeric char plus '_', '.' for attribute names
;
//------------------------------ALARM NAME--------------------------------------
name
......@@ -185,9 +209,23 @@ struct formula_grammar : public grammar<formula_grammar>
]
]
// = repeat_p(3)[(+symbol) >> ch_p('/')] >> (+symbol)
;
;
index_range
=
( uint_p >> !(discard_node_d[ch_p('-')] >> uint_p)) // n or n-m
;
index_list
= (index_range >> *(discard_node_d[ch_p(',')] >> index_range)) // n-m,k,s-t,..
;
index
= inner_node_d[ch_p('[') >> uint_p >> ch_p(']')]
= discard_node_d[ch_p('[')] >>
(str_p("-1") | index_list) >>
discard_node_d[ch_p(']')]
;
property
= str_p(".quality")
| str_p(".alarm")
| str_p(".normal")
;
//------------------------------FORMULA--------------------------------------
val_r
......@@ -211,8 +249,13 @@ struct formula_grammar : public grammar<formula_grammar>
;
val_quality
=
//access_node_d[self.tango_states[&Save_Stat]][&Assign_Stat] //save Tango::state value in node
//access_node_d[self.attr_quality[&Save_Stat]][&Assign_Stat] //save Tango::state value in node
access_node_d[self.attr_quality[Save_Stat()]][Assign_Stat()] //save Tango::state value in node
;
val_alarm_enum_st
=
//access_node_d[self.alarm_enum_states[&Save_Stat]][&Assign_Stat] //save Tango::state value in node
access_node_d[self.alarm_enum_states[Save_Stat()]][Assign_Stat()] //save Tango::state value in node
;
val_string
#if BOOST_VERSION < 103600
......@@ -231,8 +274,8 @@ struct formula_grammar : public grammar<formula_grammar>
event_
= name
>> !( (index)
| (".quality")
>> ( *(index)//0 or more indexex
>> !(property) //followed by 0 or 1 property
)
;
......@@ -309,18 +352,20 @@ struct formula_grammar : public grammar<formula_grammar>
;
function
= ( root_node_d[str_p("abs")] >> (inner_node_d[ch_p('(') >> cond_expr >> ')']) //TODO: ? not expr_atom ?
| root_node_d[str_p("cos")] >> (inner_node_d[ch_p('(') >> cond_expr >> ')']) //TODO: ? not expr_atom ?
| root_node_d[str_p("sin")] >> (inner_node_d[ch_p('(') >> cond_expr >> ')']) //TODO: ? not expr_atom ?
| root_node_d[str_p("quality")] >> (inner_node_d[ch_p('(') >> cond_expr >> ')']) //TODO: ? not expr_atom ?
= ( root_node_d[str_p("abs")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')]) //TODO: ? not expr_atom ?
| root_node_d[str_p("cos")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')]) //TODO: ? not expr_atom ?
| root_node_d[str_p("sin")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')]) //TODO: ? not expr_atom ?
| root_node_d[str_p("quality")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')]) //TODO: ? not expr_atom ?
| root_node_d[str_p("AND")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')]) //TODO: ? not expr_atom ?
| root_node_d[str_p("OR")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(')')]) //TODO: ? not expr_atom ?
)
;
function_dual
= ( (root_node_d[str_p("max")] >> (inner_node_d[ch_p('(') >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> ')']))
= ( (root_node_d[str_p("max")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> discard_node_d[ch_p(')')]))
//| (root_node_d[str_p("max")] >> (inner_node_d[ch_p('(') >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> discard_node_d[ch_p(',')] >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> ')']))
| (root_node_d[str_p("min")] >> (inner_node_d[ch_p('(') >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> ')']))
| (root_node_d[str_p("min")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> discard_node_d[ch_p(')')]))
//| (root_node_d[str_p("min")] >> (inner_node_d[ch_p('(') >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> discard_node_d[ch_p(',')] >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> ')']))
| (root_node_d[str_p("pow")] >> (inner_node_d[ch_p('(') >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> ')']))
| (root_node_d[str_p("pow")] >> (discard_node_d[ch_p('(')] >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> discard_node_d[ch_p(')')]))
)
//= *( (root_node_d[str_p("max")] >> (inner_node_d[ch_p('(') >> logical_expr_paren >> discard_node_d[ch_p(',')] >> logical_expr_paren >> ')']))
// | (root_node_d[str_p("min")] >> (inner_node_d[ch_p('(') >> logical_expr_paren >> discard_node_d[ch_p(',')] >> logical_expr_paren >> ')']))
......@@ -336,7 +381,7 @@ struct formula_grammar : public grammar<formula_grammar>
expr_atom
= //val_h | val_r
event_
| val_h | val_r | val_st | val_quality | val_string
| val_h | val_r | val_st | val_quality | val_alarm_enum_st | val_string
//| (inner_node_d[ch_p('(') >> non_empty_expression >> ')'])
| (discard_node_d[ch_p('(')] >> non_empty_expression >> discard_node_d[ch_p(')')])
;
......@@ -365,6 +410,8 @@ struct formula_grammar : public grammar<formula_grammar>
rule<ScannerT, parser_context<>, parser_tag<expr_atomID> > expr_atom;
rule<ScannerT, parser_context<>, parser_tag<funcID> > function;
rule<ScannerT, parser_context<>, parser_tag<nameID> > name;
rule<ScannerT, parser_context<>, parser_tag<index_rangeID> > index_range;
rule<ScannerT, parser_context<>, parser_tag<index_listID> > index_list;
rule<ScannerT, parser_context<>, parser_tag<indexID> > index;
rule<ScannerT, parser_context<>, parser_tag<val_stringID> > val_string;
rule<ScannerT, parser_context<>, parser_tag<func_dualID> > function_dual;
......@@ -373,6 +420,9 @@ struct formula_grammar : public grammar<formula_grammar>
rule<ScannerT, parser_context<>, parser_tag<nonempty_exprID> > non_empty_expression;
rule<ScannerT, parser_context<>, parser_tag<exprID> > expression;
rule<ScannerT, parser_context<>, parser_tag<val_qualityID> > val_quality;
rule<ScannerT, parser_context<>, parser_tag<val_alarm_enum_stID> > val_alarm_enum_st;
rule<ScannerT, parser_context<>, parser_tag<propertyID> > property;
rule<ScannerT> const&
start() const { return top; }
......
/*
* log_thread.cpp
*
* $Author: graziano $
*
* $Revision: 1.7 $
*
* $Log: log_thread.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 "log_thread.h"
//#define _DEBUG_LOG_THREAD 0
//#define _DEBUG_LOG_THREAD 1
static const char __FILE__rev[] = __FILE__ " $Revision: 1.7 $";
/*
* log_thread::log_thread()
*/
log_thread::log_thread(string dbhost, string dbuser, string dbpw, string dbname, int dbport, string instance_name/*, Alarm_ns::Alarm *p*/)/*: Tango::LogAdapter(p)*/
{
//p_Alarm = p;
m_dbhost = dbhost;
m_dbuser = dbuser;
m_dbpw = dbpw;
m_dbname = dbname;
m_dbport = dbport;
m_instance_name = instance_name;
//cout << __FILE__rev << endl;
ostringstream err;
if(!mysql_init(&log_db))
{
err << "mysql_init failed for log DB" << ends;
throw err.str();
}
my_bool my_auto_reconnect=1;
if(mysql_options(&log_db,MYSQL_OPT_RECONNECT,&my_auto_reconnect) !=0)
{
err << "mysql auto reconnection error for log DB: " << mysql_error(&log_db) << ends;;
throw err.str();
}
if(!mysql_real_connect(&log_db, m_dbhost.c_str(), m_dbuser.c_str(), m_dbpw.c_str(), m_dbname.c_str(), m_dbport, NULL, 0))
{
err << "mysql_real_connect failed for log DB" << ends;
throw err.str();
}
}
/*
* log_thread::~log_thread()
*/
log_thread::~log_thread()
{
//p_Alarm = NULL;
mysql_close(&log_db);
}
/*
* log_thread::run()
*/
void log_thread::run(void *)
{
while (true) {
/*
* pop_front() will wait() on condition variable
*/
try
{
alm_log_t a = al_list.pop_front();
if ((a.name == LOG_THREAD_EXIT) && \
(a.time_s == LOG_THREAD_EXIT_TIME))
break;
write_db(a);
}
catch(omni_thread_fatal& ex)
{
ostringstream err;
err << "omni_thread_fatal exception running log thread, err=" << ex.error << ends;
//WARN_STREAM << "alarm_thread::run(): " << err.str() << endl;
printf("log_thread::run(): %s", err.str().c_str());
}
catch(Tango::DevFailed& ex)
{
ostringstream err;
err << "exception running log thread: '" << ex.errors[0].desc << "'" << ends;
//WARN_STREAM << "alarm_thread::run(): " << err.str() << endl;
printf("log_thread::run(): %s", err.str().c_str());
Tango::Except::print_exception(ex);
}
catch(...)
{
//WARN_STREAM << "alarm_thread::run(): catched unknown exception!!" << endl;
printf("log_thread::run(): catched unknown exception!!");
}
}
} /* alarm_thread::run() */
void log_thread::log_alarm_db(alm_log_t& a)
{
al_list.push_back(a);
}
void log_thread::write_db(alm_log_t& a)
{
ostringstream query_str;
ostringstream err_msg;
char *values_escaped = new char [2 * a.values.length() + 1];
char *name_escaped = new char [2 * a.name.length() + 1];
char *formula_escaped = new char [2 * a.formula.length() + 1];
char *grp_escaped = new char [2 * a.grp.length() + 1];
char *msg_escaped = new char [2 * a.msg.length() + 1];
char *level_escaped = new char [2 * a.level.length() + 1];
char *action_escaped = new char [2 * a.action.length() + 1];
char *instance_escaped = new char [2 * m_instance_name.length() + 1];
mysql_real_escape_string(&log_db, values_escaped, a.values.c_str(), a.values.length());
mysql_real_escape_string(&log_db, name_escaped, a.name.c_str(), a.name.length());
mysql_real_escape_string(&log_db, formula_escaped, a.formula.c_str(), a.formula.length());
mysql_real_escape_string(&log_db, grp_escaped, a.grp.c_str(), a.grp.length());
mysql_real_escape_string(&log_db, msg_escaped, a.msg.c_str(), a.msg.length());
mysql_real_escape_string(&log_db, level_escaped, a.level.c_str(), a.level.length());
mysql_real_escape_string(&log_db, action_escaped, a.action.c_str(), a.action.length());
mysql_real_escape_string(&log_db, instance_escaped, m_instance_name.c_str(), m_instance_name.length());
char *tmp_name_escaped;
ostringstream tmp_names;
for(vector<string>::iterator it=a.alm_list.begin(); it!=a.alm_list.end(); it++)
{
tmp_name_escaped = new char [2 * it->length() + 1];
mysql_real_escape_string(&log_db, tmp_name_escaped, it->c_str(), it->length());
tmp_names << " AND " << DESC_COL_NAME << "!='" << tmp_name_escaped << "'";
delete [] tmp_name_escaped;
}
switch (a.type_log)
{
case TYPE_LOG_STATUS:
//example:
//INSERT INTO alarms
// (time_sec, time_usec, status, ack, id_description, attr_values)
// SELECT 1234567890, 123456, 'ALARM', 'NACK', id_description, 'ev/ev/ev/ev2=1.;' //take id_description
// FROM description //from description
// WHERE name='al/al/al/al' AND active=1 AND instance='alarm_1'; //where this alarm is active
if((a.status.size() == 0) || (a.ack.size() == 0) || (strlen(name_escaped) == 0))
{
err_msg << "log_thread::write_db(): ERROR some mandatory values adding alarm status are empty: status=" <<
a.status << " ack=" << a.ack << " name=" << name_escaped << ends;
break;
}
query_str <<
"INSERT INTO " << m_dbname << "." << STAT_TABLE_NAME <<
" (" << STAT_COL_TIME_S << "," << STAT_COL_TIME_U << "," <<
STAT_COL_STATUS << "," << STAT_COL_ACK << "," <<
STAT_COL_DESC_ID << "," << STAT_COL_VALUES <<
") SELECT " << a.time_s << "," << a.time_us << ",'" <<
a.status << "','" << a.ack << "'," <<
DESC_COL_ID << ",'" << values_escaped << "'" <<
" FROM " << DESC_TABLE_NAME <<
" WHERE " << DESC_COL_NAME << "='" << name_escaped << "'" <<
" AND " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
ends;
break;
case TYPE_LOG_DESC_ADD:
//example:
//INSERT INTO description
// (name, active, time_sec, formula, time_threashold, level, grp, msg, action, instance)
// SELECT 'al/al/al/al', 'alarm_1', 1, 1234567890, '(ev/ev/ev/evn < 1.2)', 'log', 'gr_none', 'msg'
// FROM description
// WHERE name='al/al/al/al' AND active=1 AND instance='alarm_1' //look if exists an alarm with the same name and active
// HAVING count(*) = 0; //insert only if it does not exist
if((strlen(name_escaped) == 0) || (strlen(instance_escaped) == 0) || (strlen(formula_escaped) == 0) || (strlen(level_escaped) == 0) ||
(strlen(grp_escaped) == 0) || (strlen(msg_escaped) == 0))
{
err_msg << "log_thread::write_db(): ERROR some mandatory values adding alarm description are empty: name=" <<
name_escaped << " instance=" << instance_escaped << " formula=" << formula_escaped << " level=" << level_escaped << " grp=" << grp_escaped <<
" msg=" << msg_escaped << ends;
break;
}
query_str <<
"INSERT INTO " << m_dbname << "." << DESC_TABLE_NAME <<
" (" << DESC_COL_NAME << "," << DESC_COL_ACTIVE << "," <<
DESC_COL_TIME_S << "," << DESC_COL_FORMULA << "," <<
DESC_COL_TIME_THRESHOLD << "," << DESC_COL_LEVEL << "," <<
DESC_COL_GRP << "," << DESC_COL_MSG << "," <<
DESC_COL_ACTION << "," << DESC_COL_INSTANCE << "," <<
DESC_COL_SILENT_TIME <<
") SELECT '" << name_escaped << "'," << ALARM_ACTIVE << "," <<
a.time_s << ",'" << formula_escaped << "','" <<
a.time_threshold << "','" << level_escaped << "','" <<
grp_escaped << "','" << msg_escaped << "','" <<
action_escaped << "','" <<instance_escaped << "','" <<
a.silent_time << "'" <<
" FROM " << DESC_TABLE_NAME <<
" WHERE " << DESC_COL_NAME << "='" << name_escaped << "'" <<
" AND " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
" HAVING COUNT(*) = 0" <<
ends;
break;
case TYPE_LOG_DESC_DIS:
//example:
//UPDATE description
// SET active=0 //set active to 0
// WHERE name='al/al/al/al' AND active=1 AND instance='alarm_1'; //in alarm specified that is active
if(strlen(name_escaped) == 0 || strlen(instance_escaped) == 0)
{
err_msg << "log_thread::write_db(): ERROR some mandatory values setting non-active alarm are empty: name=" <<
name_escaped << " instance=" << instance_escaped << ends;
break;
}
query_str <<
"UPDATE " << m_dbname << "." << DESC_TABLE_NAME <<
" SET " << DESC_COL_ACTIVE << "=" << ALARM_REMOVED <<
" WHERE " << DESC_COL_NAME << "='" << name_escaped << "'" <<
" AND " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
ends;
break;
case TYPE_LOG_DESC_REM:
//example:
//DELETE FROM description
// WHERE name='al/al/al/al' AND active=1 AND instance='alarm_1'; //in alarm specified that is active
if(strlen(name_escaped) == 0 || strlen(instance_escaped) == 0)
{
err_msg << "log_thread::write_db(): ERROR some mandatory values removing alarm are empty: name=" <<
name_escaped << " instance=" << instance_escaped<< ends;
break;
}
query_str <<
"DELETE FROM " << m_dbname << "." << DESC_TABLE_NAME <<
" WHERE " << DESC_COL_NAME << "='" << name_escaped << "'" <<
" AND " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
ends;
break;
case TYPE_LOG_DESC_SYNC:
//example:
//UPDATE description
// SET active=0
// WHERE name='al/al/al/al' //disable this alarm
// AND active=1 //if it is active and
// AND instance='alarm_1' //for this alarm instance and
// AND (formula!='(ev/ev/ev/ev > 1)' //or formula is changed
// OR time_threashold!=5 //or time_threshold is changed
// OR level!='log' //or level is changed
// OR grp!='gr_none' //or grp is changed
// OR msg!='message'); //or msg is changed
// OR action!='act/act/act/act'); //or action is changed
query_str <<
"UPDATE " << m_dbname << "." << DESC_TABLE_NAME <<
" SET " << DESC_COL_ACTIVE << "=" << ALARM_REMOVED <<
" WHERE " << DESC_COL_NAME << "='" << name_escaped << "'" <<
" AND " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
" AND (" << DESC_COL_FORMULA << "!='" << formula_escaped << "'" <<
" OR " << DESC_COL_TIME_THRESHOLD << "!='" << a.time_threshold << "'" <<
" OR " << DESC_COL_LEVEL << "!='" << level_escaped << "'" <<
" OR " << DESC_COL_GRP << "!='" << grp_escaped << "'" <<
" OR " << DESC_COL_MSG << "!='" << msg_escaped << "'" <<
" OR " << DESC_COL_ACTION << "!='" << action_escaped << "'" <<
")" <<
ends;
break;
case TYPE_LOG_DESC_UPD_OLD:
//example:
//UPDATE description
// SET active=0
// WHERE name!='al1/al1/al1/al1' //disable every alarm not in this list
// AND name !='al2/al2/al2/al2'
// AND name !=...
// AND active=1 //if it is active
// AND instance='alarm_1'
query_str <<
"UPDATE " << m_dbname << "." << DESC_TABLE_NAME <<
" SET " << DESC_COL_ACTIVE << "=" << ALARM_REMOVED <<
" WHERE " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
tmp_names.str() <<
ends;
break;
case TYPE_LOG_DESC_UPDATE:
//example:
//UPDATE description
// SET time_sec=1234567890, time_threashold=1, level='log', grp='gr_none', msg='msg'
// WHERE name='al1/al1/al1/al1' //
// AND active=1 //
// AND instance='alarm_1'
query_str <<
"UPDATE " << m_dbname << "." << DESC_TABLE_NAME <<
" SET " << DESC_COL_TIME_S << "=" << a.time_s <<
" , " << DESC_COL_TIME_THRESHOLD << "=" << a.time_threshold <<
" , " << DESC_COL_LEVEL << "='" << level_escaped << "'" <<
" , " << DESC_COL_GRP << "='" << grp_escaped << "'" <<
" , " << DESC_COL_MSG << "='" << msg_escaped << "'" <<
" , " << DESC_COL_ACTION << "='" << action_escaped << "'" <<
" , " << DESC_COL_SILENT_TIME << "='" << a.silent_time << "'" <<
" WHERE " << DESC_COL_NAME << "='" << name_escaped << "'" <<
" AND " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
ends;
break;
}
delete [] values_escaped;
delete [] name_escaped;
delete [] formula_escaped;
delete [] grp_escaped;
delete [] msg_escaped;
delete [] level_escaped;
delete [] action_escaped;
delete [] instance_escaped;
if(err_msg.str().size() != 0)
{
cout << err_msg.str();
return;
}
if(mysql_query(&log_db, query_str.str().c_str()))
{
err_msg << " log_thread::write_db(): ERROR in query=" << query_str.str() << endl;
//cout << err_msg.str();
//throw err_msg.str();
}
if(err_msg.str().size() != 0)
{
cout << gettime().tv_sec << err_msg.str();
return;
}
int num_rows = mysql_affected_rows(&log_db);
#ifdef _DEBUG_LOG_THREAD
cout << gettime().tv_sec << " log_thread::write_db(): Affected rows=" << num_rows << " in query=" << query_str.str() << endl;
#else
if(((a.type_log == TYPE_LOG_STATUS) || (a.type_log == TYPE_LOG_DESC_DIS)) && (num_rows != 1))
cout << gettime().tv_sec << " log_thread::write_db(): Error num_rows=" << num_rows << " in query=" << query_str.str() << endl;
#endif
}
void log_thread::get_alarm_list(vector<string> &al_list)
{
ostringstream query_str;
ostringstream err_msg;
MYSQL_RES *res;
MYSQL_ROW row;
char *instance_escaped = new char [2 * m_instance_name.length() + 1];
mysql_real_escape_string(&log_db, instance_escaped, m_instance_name.c_str(), m_instance_name.length());
// unsigned int num_fields;
// unsigned int i;
//example:
//SELECT description
// CONCAT('\t',name,'\t',formula,
// '\t',IFNULL(time_threshold,0),'\t',level,
// '\t',grp,'\t','\"',IFNULL(msg,''),'\"',
// '\t',IFNULL(action,''))
// FROM alarm.description
// WHERE active=1
// AND instance='alarm_1'
query_str <<
"SELECT" <<
" CONCAT('\t', " << DESC_COL_NAME << ",'\t'," << DESC_COL_FORMULA <<
",'\t'," << "IFNULL(" << DESC_COL_TIME_THRESHOLD << ",0)" << ",'\t'," << DESC_COL_LEVEL <<
",'\t'," << "IFNULL(" << DESC_COL_SILENT_TIME << ",-1)" <<
",'\t'," << DESC_COL_GRP << ",'\t','\"'," << "IFNULL(" << DESC_COL_MSG << ",'')" <<
",'\"','\t'," << "IFNULL(" << DESC_COL_ACTION << ",';')" << ")" <<
" FROM " << m_dbname << "." << DESC_TABLE_NAME <<
" WHERE " << DESC_COL_ACTIVE << "=" << ALARM_ACTIVE <<
" AND " << DESC_COL_INSTANCE << "='" << instance_escaped << "'" <<
ends;
delete [] instance_escaped;
if(mysql_query(&log_db, query_str.str().c_str()))
{
err_msg << "log_thread::get_alarm_list(): ERROR in query=" << query_str.str() << endl;
//cout << err_msg.str();
throw err_msg.str();
}
//#define _DEBUG_LOG_THREAD 1
#ifdef _DEBUG_LOG_THREAD
else
cout << gettime().tv_sec << " log_thread::get_alarm_list(): Success with query=" << query_str.str() << endl;
#endif //_DEBUG_LOG_THREAD
res = mysql_use_result(&log_db);
if(res == NULL)
{
if(*mysql_error(&log_db))
err_msg << "log_thread::get_alarm_list(): ERROR while retrieving result, err=" << mysql_error(&log_db) << endl;
else
err_msg << "log_thread::get_alarm_list(): ERROR while retrieving result" << endl;
//cout << err_msg.str();
throw err_msg.str();
}
//num_fields = mysql_num_fields(res);
while ((row = mysql_fetch_row(res)))
{
al_list.push_back(row[0]);
#ifdef _DEBUG_LOG_THREAD
cout << gettime().tv_sec << " log_thread::get_alarm_list(): Retrieved line: " << row[0] << endl;
#endif //_DEBUG_LOG_THREAD
}
mysql_free_result(res);
}
/*
* alarm_list class methods
*/
void alarm_list::push_back(alm_log_t& a)
{
this->lock();
try{
l_alarm.push_back(a);
empty.signal();
}
catch(omni_thread_fatal& ex)
{
ostringstream err;
err << "omni_thread_fatal exception signaling omni_condition, err=" << ex.error << ends;
//WARN_STREAM << "alarm_list::push_back(): " << err.str() << endl;
printf("alarm_list::push_back(): %s", err.str().c_str());
}
catch(Tango::DevFailed& ex)
{
ostringstream err;
err << "exception signaling omni_condition: '" << ex.errors[0].desc << "'" << ends;
//WARN_STREAM << "alarm_list::push_back(): " << err.str() << endl;
printf("alarm_list::push_back: %s", err.str().c_str());
Tango::Except::print_exception(ex);
}
catch(...)
{
//WARN_STREAM << "alarm_list::push_back(): catched unknown exception!!" << endl;
printf("alarm_list::push_back(): catched unknown exception signaling omni_condition!!");
}
this->unlock();
}
const alm_log_t alarm_list::pop_front(void)
{
this->lock();
//omni_mutex_lock l((omni_mutex)this); //call automatically unlock on destructor and on exception
try{
while (l_alarm.empty() == true)
empty.wait(); //wait release mutex while is waiting, then reacquire when signaled
}
catch(omni_thread_fatal& ex)
{
ostringstream err;
err << "omni_thread_fatal exception waiting on omni_condition, err=" << ex.error << ends;
//WARN_STREAM << "alarm_list::pop_front(): " << err.str() << endl;
printf("alarm_list::pop_front(): %s", err.str().c_str());
alm_log_t a;
this->unlock();
sleep(1);
return(a);
}
catch(Tango::DevFailed& ex)
{
ostringstream err;
err << "exception waiting on omni_condition: '" << ex.errors[0].desc << "'" << ends;
//WARN_STREAM << "alarm_list::pop_front(): " << err.str() << endl;
printf("alarm_list::pop_front: %s", err.str().c_str());
Tango::Except::print_exception(ex);
alm_log_t a;
this->unlock();
sleep(1);
return(a);
}
catch(...)
{
//WARN_STREAM << "alarm_list::pop_front(): catched unknown exception!!" << endl;
printf("alarm_list::pop_front(): catched unknown exception waiting on omni_condition!!");
alm_log_t a;
this->unlock();
sleep(1);
return(a);
}
/*const*/ alm_log_t a;
a = *(l_alarm.begin());
l_alarm.pop_front();
this->unlock();
return(a);
}
void alarm_list::clear(void)
{
//this->lock();
l_alarm.clear();
//this->unlock();
}
list<alm_log_t> alarm_list::show(void)
{
list<alm_log_t> al;
this->lock();
al = l_alarm;
this->unlock();
return(al);
}
/*
* log_thread.h
*
* $Author: graziano $
*
* $Revision: 1.4 $
*
* $Log: log_thread.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
*/
#ifndef LOG_THREAD_H
#define LOG_THREAD_H
#include <omnithread.h>
#include <tango.h>
#include <Alarm.h>
#include <mysql.h>
#define LOG_THREAD_EXIT "log_thread_exit"
#define LOG_THREAD_EXIT_TIME 1
//############# DB ############
//#define LOG_DB_NAME "alarm"
//######## ALARM_DESC ########
#define DESC_TABLE_NAME "description"
#define DESC_COL_ID "id_description"
#define DESC_COL_NAME "name"
#define DESC_COL_INSTANCE "instance"
#define DESC_COL_ACTIVE "active"
#define DESC_COL_TIME_S "time_sec"
#define DESC_COL_FORMULA "formula"
#define DESC_COL_SILENT_TIME "silent_time"
#define DESC_COL_TIME_THRESHOLD "time_threshold"
#define DESC_COL_LEVEL "level"
#define DESC_COL_GRP "grp"
#define DESC_COL_MSG "msg"
#define DESC_COL_ACTION "action"
//######## ALARM_STATUS #######
#define STAT_TABLE_NAME "alarms"
#define STAT_COL_ID "id_alarms"
#define STAT_COL_TIME_S "time_sec"
#define STAT_COL_TIME_U "time_usec"
#define STAT_COL_STATUS "status"
#define STAT_COL_ACK "ack"
#define STAT_COL_DESC_ID DESC_COL_ID
#define STAT_COL_VALUES "attr_values"
#define TYPE_LOG_STATUS 1
#define TYPE_LOG_DESC_ADD 2
#define TYPE_LOG_DESC_DIS 3
#define TYPE_LOG_DESC_REM 4
#define TYPE_LOG_DESC_SYNC 5
#define TYPE_LOG_DESC_UPD_OLD 6
#define TYPE_LOG_DESC_UPDATE 7
#define ALARM_ACTIVE 1
#define ALARM_REMOVED 0
typedef struct {
unsigned int type_log;
unsigned int time_s;
unsigned int time_us;
unsigned int time_threshold;
int silent_time;
string name;
string status;
string ack;
string level;
string grp;
string msg;
string formula;
string action;
string values;
vector<string> alm_list;
} alm_log_t;
/*
* here Alarm insert data to log, log_thread process data
* and store in db
*/
class alarm_list : public omni_mutex {
public:
alarm_list(void): full(this), empty(this) {}
~alarm_list(void) {}
void push_back(alm_log_t& a);
const alm_log_t pop_front(void);
void clear(void);
list<alm_log_t> show(void);
protected:
list<alm_log_t> l_alarm;
private:
omni_condition full,
empty;
};
class log_thread : public omni_thread/*, public Tango::LogAdapter*/
{
public:
log_thread(string dbhost, string dbuser, string dbpw, string dbname, int dbport, string instance_name/*, Alarm_ns::Alarm *p*/);
~log_thread();
void log_alarm_db(alm_log_t& a);
void get_alarm_list(vector<string> &al_list);
protected:
void run(void *);
private:
//Alarm_ns::Alarm *p_Alarm;
MYSQL log_db;
alarm_list al_list;
string m_dbhost;
string m_dbuser;
string m_dbpw;
string m_dbname;
int m_dbport;
string m_instance_name;
void write_db(alm_log_t& a);
};
#endif /* LOG_THREAD_H */
/* EOF */
/*----- PROTECTED REGION ID(Alarm::main.cpp) ENABLED START -----*/
static const char *RcsId = "$Id: $";
/*----- PROTECTED REGION ID(AlarmHandler::main.cpp) ENABLED START -----*/
//=============================================================================
//
// file : main.cpp
//
// description : C++ source for the Alarm device server main.
// description : C++ source for the AlarmHandler device server main.
// The main rule is to initialise (and create) the Tango
// system and to create the DServerClass singleton.
// The main should be the same for every Tango device server.
//
// project : alarm
// project : Elettra alarm handler device server
//
// This file is part of Tango device class.
//
......@@ -26,38 +25,40 @@ static const char *RcsId = "$Id: $";
// You should have received a copy of the GNU General Public License
// along with Tango. If not, see <http://www.gnu.org/licenses/>.
//
// $Author: $
//
// $Revision: $
// $Date: $
//
// $HeadURL: $
//
//=============================================================================
// This file is generated by POGO
// (Program Obviously used to Generate tango Object)
//=============================================================================
#include <tango/tango.h>
// Check if crash reporting is used.
#if defined(ENABLE_CRASH_REPORT)
# include <crashreporting/crash_report.h>
#else
# define DECLARE_CRASH_HANDLER
# define INSTALL_CRASH_HANDLER
#endif
DECLARE_CRASH_HANDLER;
#include <tango.h>
#ifndef TANGO_LOG
#define TANGO_LOG cout
#endif
int main(int argc,char *argv[])
{
Tango::Util *tg;
using std::endl;
using std::bad_alloc;
INSTALL_CRASH_HANDLER
try
{
// Initialise the device server
//----------------------------------------
tg = Tango::Util::init(argc,argv);
Tango::Util *tg = Tango::Util::init(argc,argv);
/*
* serialize all calls
* BY_DEVICE, BY_CLASS, BY_PROCESS
*/
//tg->set_serial_model(Tango::BY_PROCESS);
// Create the device server singleton
// which will create everything
//----------------------------------------
......@@ -65,24 +66,23 @@ int main(int argc,char *argv[])
// Run the endless loop
//----------------------------------------
cout << "Ready to accept request" << endl;
TANGO_LOG << "Ready to accept request" << endl;
tg->server_run();
}
catch (bad_alloc)
catch (bad_alloc &)
{
cout << "Can't allocate memory to store device object !!!" << endl;
cout << "Exiting" << endl;
TANGO_LOG << "Can't allocate memory to store device object !!!" << endl;
TANGO_LOG << "Exiting" << endl;
}
catch (CORBA::Exception &e)
{
Tango::Except::print_exception(e);
cout << "Received a CORBA_Exception" << endl;
cout << "Exiting" << endl;
TANGO_LOG << "Received a CORBA_Exception" << endl;
TANGO_LOG << "Exiting" << endl;
}
tg->server_cleanup();
Tango::Util::instance()->server_cleanup();
return(0);
}
/*----- PROTECTED REGION END -----*/ // Alarm::main.cpp
/*----- PROTECTED REGION END -----*/ // AlarmHandler::main.cpp
/*
* update-thread.cpp
*
* $Author: claudio $
*
* $Revision: 1.2 $
*
* $Log: update-thread.cpp,v $
* Revision 1.2 2013-03-06 10:38:43 claudio
* commented out debug print statements
*
* Revision 1.1 2008-11-10 10:54:09 graziano
* thread for update of alarms with time threshold > 0
*
*
*
*
* 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 "update-thread.h"
......@@ -26,9 +8,9 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.2 $";
/*
* alarm_thread::alarm_thread()
*/
update_thread::update_thread(Alarm_ns::Alarm *p) : p_Alarm(p)
update_thread::update_thread(AlarmHandler_ns::AlarmHandler *p) : p_Alarm(p),Tango::LogAdapter(p)
{
//cout << __FILE__rev << endl;
//TANGO_LOG << __FILE__rev << endl;
}
/*
......@@ -36,6 +18,7 @@ update_thread::update_thread(Alarm_ns::Alarm *p) : p_Alarm(p)
*/
update_thread::~update_thread()
{
DEBUG_STREAM << __func__ << "update_thread::~update_thread(): entering!" << endl;
p_Alarm = NULL;
}
......@@ -44,6 +27,7 @@ update_thread::~update_thread()
*/
void update_thread::run(void *)
{
DEBUG_STREAM << __func__ << "update_thread::run(): entering!" << endl;
//printf("update_thread::run(): running...\n");
unsigned int pausasec, pausanano;
pausasec=1;
......@@ -52,14 +36,23 @@ void update_thread::run(void *)
while (!p_Alarm->abortflag) {
try
{
omni_thread::sleep(pausasec,pausanano);
p_Alarm->timer_update();
//omni_thread::sleep(pausasec,pausanano);
abort_sleep(pausasec+(double)pausanano/1000000000);
if(!p_Alarm->abortflag)
p_Alarm->timer_update();
//printf("update_thread::run(): TIMER!!\n");
}
catch(...)
{
printf("update_thread::run(): catched unknown exception!!\n");
INFO_STREAM << "update_thread::run(): catched unknown exception!!";
}
}
//cout << "update_thread::run(): exiting!" << endl;
DEBUG_STREAM << "update_thread::run(): exiting!" << endl;
} /* update_thread::run() */
void update_thread::abort_sleep(double time)
{
omni_mutex_lock sync(*this);
long time_millis = (long)(time*1000);
int res = wait(time_millis);
}
/*
* alarm-thread.h
*
* $Author: graziano $
*
* $Revision: 1.1 $
*
* $Log: update-thread.h,v $
* Revision 1.1 2008-11-10 10:54:09 graziano
* thread for update of alarms with time threshold > 0
*
*
*
*
* copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale
* Strada Statale 14 - km 163,5 in AREA Science Park
* 34012 Basovizza, Trieste ITALY
* update-thread.h
*/
#ifndef UPDATE_THREAD_H
#define UPDATE_THREAD_H
#include <omnithread.h>
#include <tango.h>
#include <Alarm.h>
#include <tango/tango.h>
#include <AlarmHandler.h>
class update_thread : public omni_thread {
class update_thread : public omni_thread, public Tango::TangoMonitor, public Tango::LogAdapter {
public:
update_thread(Alarm_ns::Alarm *p);
update_thread(AlarmHandler_ns::AlarmHandler *p);
~update_thread();
protected:
void run(void *);
private:
Alarm_ns::Alarm *p_Alarm;
void abort_sleep(double time);
AlarmHandler_ns::AlarmHandler *p_Alarm;
};
#endif /* UPDATE_THREAD_H */
......
cmake_minimum_required(VERSION 3.2)
project(test NONE)
include(ExternalProject)
ExternalProject_Add(testdevice
SOURCE_DIR ${CMAKE_SOURCE_DIR}/test/testdevice
# PREFIX ${CMAKE_BINARY_DIR}
CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}"
# INSTALL_DIR ${CMAKE_BINARY_DIR}
# BINARY_DIR ${CMAKE_BINARY_DIR}
# STEP_TARGETS build
# EXCLUDE_FROM_ALL TRUE
)
ExternalProject_Get_property(testdevice SOURCE_DIR)
message("Source dir of testdevice = ${SOURCE_DIR}")
ExternalProject_Get_property(testdevice INSTALL_DIR)
message("Install dir of testdevice = ${INSTALL_DIR}")
ExternalProject_Get_property(testdevice BINARY_DIR)
message("Binary dir of testdevice = ${BINARY_DIR}")
ExternalProject_Get_property(testdevice CMAKE_ARGS)
message("CMqke args for testdevice = ${CMAKE_ARGS}")
#ExternalProject_Get_property(testdevice PREFIX)
#message("Prefix dir of testdevice = ${PREFIX}")
{
"_version": 1,
"_source": "ConfigInjectorDiag.xls",
"_title": "hdbpp mysql innodb test",
"_date": "2020-07-07 14:45:04",
"servers": {
"alarm-handler-srv/01": {
"AlarmHandler": {
"alarm/handler/01": {
"properties": {
},
"attribute_properties": {
}
}
}
},
"testdevice-srv/01": {
"TestDevice": {
"alarm/test/01": {
"properties": {
"Attr_config": [
"condition:bool:0:0.0"
]
},
"attribute_properties": {
}
}
}
}
},
"classes": {
"AlarmHandler": {
"properties": {
"GroupNames": ["gr_none","gr_test"],
"StatisticsTimeWindow": ["60"],
"SubscribeRetryPeriod": ["30"]
}
},
"TestDevice": {
"properties": {
}
}
}
}
#!/usr/bin/python
#
import sys,re
#import PyTango
from PyTango import *
import time
import string
if __name__ == "__main__":
Device = False
Conf = False
File = False
conflist = []
#PrepareState = False
for arg in sys.argv:
word = '([a-z0-9._\-\*]*)'
wordpath = '([a-z0-9._\-\*/]*)'
m = re.compile("--device=" + word + "/{0,1}" + word + "/{0,1}" + word).match(arg.lower())
if m is not None:
#print m.groups()
domain = m.groups()[0]
family = m.groups()[1]
member = m.groups()[2]
if domain == '':
domain = '*'
if family == '':
family = '*'
if member == '':
member = '*'
Device = True
#formula = '([a-z0-9._,\*,\-,\|,\/,\",\s,\t]*)'
formula = '(.*)'
m = re.compile("--conf=" + formula).match(arg)
if m is not None:
#print m.groups()
alarm_rule = m.groups()[0]
Conf = True
#m = re.compile("--prepare_state").match(arg.lower())
#if m is not None:
# PrepareState = True
m = re.compile("--file=" + wordpath).match(arg)
if m is not None:
#print m.groups()
file_name = m.groups()[0]
File = True
tagchars = '([a-zA-Z0-9._-]*)'
tag=''
if Device:
if Conf or File:
dev_name = domain + '/' + family + '/' + member
try:
dev = DeviceProxy(dev_name)
except (DevFailed,ConnectionFailed,EventSystemFailed) as e:
print ('ERROR connecting proxy(',dev_name,'): ',e[0].desc)
sys.exit(-1)
if Conf:
m = re.compile("tag=" + tagchars + ";(.*)").match(alarm_rule)
if m is not None:
try:
tag = m.groups()[0]
conflist = dev.command_inout('SearchAlarm',tag)
except (DevFailed,ConnectionFailed,EventSystemFailed) as e:
print (' ---> ERROR: ', e[0].desc)
sys.exit(1)
for co in conflist:
if co == alarm_rule:
print ('Found matching alarm: ', co)
sys.exit(0)
print ('Not found conf for alarm ', tag)
sys.exit(1)
elif File:
for line in open(file_name):
line = line[0:-1]
m = re.compile("tag=" + tagchars + ";(.*)").match(line)
conf_found = False
if m is not None:
try:
tag = m.groups()[0]
conflist = dev.command_inout('SearchAlarm',tag)
except (DevFailed,ConnectionFailed,EventSystemFailed) as e:
print (' ---> ERROR: ', e[0].desc)
sys.exit(1)
for co in conflist:
if co == alarm_rule:
conf_found = True
if not conf_found:
print ('Not found conf for alarm ', tag)
sys.exit(1)
sys.exit(0)
if len(sys.argv) < 3:
print ('Usage:', sys.argv[0], ' --device=alarm_device --conf=alarm_rule | --file=filename')
print ()
print ('Examples:')
print ('\tcheck one alarm_rule in alarm/handler/01:', sys.argv[0], '--device=alarm/handler/01 --conf=\"tag=test0;formula=(alarm/test/01/condition == 1);on_delay=0;off_delay=0;priority=high;shlvd_time=0;group=gr_test;message=Test alarm;url=;on_command=;off_command=;enabled=1\"')
print ('\tcheck alarm rules from filename in alarm/handler/01:', sys.argv[0], '--device=alarm/handler/01 --file=alarms.txt')
sys.exit(-1)
# EOF
#!/usr/bin/python
#
import sys,re
#import PyTango
from PyTango import *
import time
import string
if __name__ == "__main__":
Device = False
Conf = False
File = False
#PrepareState = False
for arg in sys.argv:
word = '([a-z0-9._\-\*]*)'
wordpath = '([a-z0-9._\-\*/]*)'
m = re.compile("--device=" + word + "/{0,1}" + word + "/{0,1}" + word).match(arg.lower())
if m is not None:
domain = m.groups()[0]
family = m.groups()[1]
member = m.groups()[2]
if domain == '':
domain = '*'
if family == '':
family = '*'
if member == '':
member = '*'
Device = True
#formula = '([a-z0-9._,\*,\-,\|,\/,\",\s,\t]*)'
formula = '(.*)'
m = re.compile("--conf=" + formula).match(arg)
if m is not None:
alarm_rule = m.groups()[0]
Conf = True
#m = re.compile("--prepare_state").match(arg.lower())
#if m is not None:
# PrepareState = True
m = re.compile("--file=" + wordpath).match(arg)
if m is not None:
file_name = m.groups()[0]
File = True
if Device:
if Conf or File:
dev_name = domain + '/' + family + '/' + member
try:
dev = DeviceProxy(dev_name)
except (DevFailed,ConnectionFailed,EventSystemFailed) as e:
print ('ERROR connecting proxy(',dev_name,'): ',e[0].desc)
sys.exit(-1)
if Conf:
print ('Loading: ', alarm_rule)
try:
dev.command_inout('Load',alarm_rule)
print ('.............OK!')
except (DevFailed,ConnectionFailed,EventSystemFailed) as e:
print ('...........ERROR!')
print (' ---> ERROR: ', e[0].desc)
continue
sys.exit(0)
elif File:
for line in open(file_name):
line = line[0:-1]
try:
dev.command_inout('Load',line)
time.sleep(0.1)
except (DevFailed,ConnectionFailed,EventSystemFailed) as e:
print (' ---> ERROR: ', e[0].desc)
time.sleep(2)
sys.exit(1)
sys.exit(0)
#dev = DeviceProxy("alarm/alarm/1")
#dev.command_inout('Load', sys.argv[1])
if len(sys.argv) < 3:
print ('Usage:', sys.argv[0], ' --device=alarm_device --conf=alarm_rule | --file=filename')
print ()
print ('Examples:')
print ('\tload one alarm_rule in alarm/handler/01:', sys.argv[0], '--device=alarm/handler/01 --conf=\"tag=test0;formula=(alarm/test/01/condition == 1);on_delay=0;off_delay=0;priority=high;shlvd_time=0;group=gr_test;message=Test alarm;url=;on_command=;off_command=;enabled=1\"')
print ('\tload alarm rules from filename in alarm/handler/01:', sys.argv[0], '--device=alarm/handler/01 --file=alarms.txt')
sys.exit(-1)
# EOF
# Functions and Pre-build -----------------------------------
# Stop messy in source builds
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES OFF)
if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt." )
endif()
# Start Build Config -----------------------------------
cmake_minimum_required(VERSION 3.8)
set(CMAKE_SKIP_RPATH true)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Output name for the final binary
set(DEV_NAME "testdevice-srv")
# Versioning
set(VERSION_MAJOR "1")
set(VERSION_MINOR "0")
set(VERSION_PATCH "0")
set(VERSION_METADATA "")
set(VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
# Add any include paths from the command line
list(APPEND INCLUDE_PATHS ${CMAKE_INCLUDE_PATH})
list(APPEND INCLUDE_PATHS ${CMAKE_SOURCE_DIR})
list(APPEND LIBRARY_PATHS ${CMAKE_LIBRARY_PATH})
# Start the project
project(testdevice VERSION ${VERSION_STRING} LANGUAGES CXX)
# Build options
# arch install definitions
include(GNUInstallDirs)
message(STATUS "Searching for libraries...")
# Variable to contain a list of all the libs we depend on
set(AH_LIBRARIES)
# allow pkg-config to search the CMAKE_PREFIX_PATH
set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH ON)
list(APPEND CMAKE_PREFIX_PATH "/usr")
# Find Dependencies -----------------------------------
# Find tango if it has not already been found. Returns an interface library
# called TangoInterfaceLibrary
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(Tango)
# Source -----------------------------------
add_subdirectory(src)
# Build Targets -----------------------------------
# Executable --------
add_executable(testdevice ${SRC_FILES})
target_link_libraries(testdevice
PRIVATE
TangoInterfaceLibrary
)
target_include_directories(testdevice
PRIVATE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
${INCLUDE_PATHS}
"${PROJECT_BINARY_DIR}"
)
if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
set_target_properties(testdevice
PROPERTIES
OUTPUT_NAME ${DEV_NAME}
LINK_FLAGS "-Wl,--no-undefined"
CXX_STANDARD 17)
else()
set_target_properties(testdevice
PROPERTIES
OUTPUT_NAME ${DEV_NAME}
LINK_FLAGS ""
CXX_STANDARD 17)
endif()
target_compile_options(testdevice
PRIVATE "$<$<CONFIG:DEBUG>:-g>")
# Install Config -----------------------------------
install(
TARGETS testdevice
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
message(STATUS "Configured testdevice project")
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
GCCMAJOR := $(shell ${CXX} -dumpversion | cut -d"." -f1)
GCCMINOR := $(shell ${CXX} -dumpversion | cut -d"." -f2)
MACHINE := $(shell ${CXX} -dumpmachine)
TANGO_DIR := /usr/local/tango-9.3.4
OMNIORB_DIR := /usr/local/omniorb-4.2.3
ZMQ_DIR := /usr/local/zeromq-4.0.8
RUNTIME_DIR := /runtime
TANGO_INC := ${TANGO_DIR}/include/tango
LOG4TANGO_INC := ${TANGO_DIR}/include
OMNIORB_INC := ${OMNIORB_DIR}/include
ZMQ_INC := ${ZMQ_DIR}/include
RUNTIME_INC := ${RUNTIME_DIR}/include
TANGO_LIB = ${TANGO_DIR}/lib
OMNIORB_LIB = ${OMNIORB_DIR}/lib
ZMQ_LIB = ${ZMQ_DIR}/lib
RUNTIME_LIB = ${RUNTIME_DIR}/lib
ifeq ($(SDKTARGETSYSROOT),)
ifeq ($(GCCMAJOR),4)
ifeq ($(shell test $(GCCMINOR) -lt 4; echo $$?),0)
CXXFLAGS += -std=gnu++98
else
CXXFLAGS += -std=c++0x
endif
else
CXXFLAGS += -std=c++11
endif
INC_DIR = -I${TANGO_INC} -I${LOG4TANGO_INC} -I${OMNIORB_INC} -I${ZMQ_INC} -I${RUNTIME_INC}
LIB_DIR = -L${TANGO_LIB} -L${OMNIORB_LIB} -L${ZMQ_LIB} -L${RUNTIME_LIB} -L/usr/local/lib
else
CXXFLAGS += -std=gnu++11
INC_DIR = -I${SDKTARGETSYSROOT}/usr/include/tango
endif
#-----------------------------------------
# Default make entry
#-----------------------------------------
default: release
release debug: bin/$(NAME_SRV)
all: default
#-----------------------------------------
# Set CXXFLAGS and LDFLAGS
#-----------------------------------------
CXXFLAGS += -D__linux__ -D__OSVERSION__=2 -Wall -pedantic \
-Wno-non-virtual-dtor -Wno-long-long -DOMNI_UNLOADABLE_STUBS \
$(INC_DIR) -Isrc
ifeq ($(GCCMAJOR),4)
CXXFLAGS += -Wextra
endif
ifeq ($(GCCMAJOR),5)
CXXFLAGS += -Wextra
endif
LDFLAGS += $(LIB_DIR) -ltango -lomniORB4 -lomniDynamic4 \
-lCOS4 -lomnithread -lzmq
#-----------------------------------------
# Set dependencies
#-----------------------------------------
SRC_FILES += $(wildcard src/*.cpp)
OBJ_FILES += $(addprefix obj/,$(notdir $(SRC_FILES:.cpp=.o)))
obj/%.o: $(SRC_FILES:%.cpp)
$(CXX) $(CXXFLAGS) -c -o $@ $<
.nse_depinfo: $(SRC_FILES)
@$(CXX) $(CXXFLAGS) -M -MM $^ | sed 's/\(.*\)\.o/obj\/\1.o/g' > $@
-include .nse_depinfo
#-----------------------------------------
# Main make entries
#-----------------------------------------
bin/$(NAME_SRV): bin obj $(OBJ_FILES)
$(CXX) $(CXXFLAGS) $(OBJ_FILES) -o bin/$(NAME_SRV) $(LDFLAGS)
clean:
@rm -fr obj/ bin/ core* .nse_depinfo src/*~
bin obj:
@ test -d $@ || mkdir $@
#-----------------------------------------
# Target specific options
#-----------------------------------------
release: CXXFLAGS += -O2 -DNDEBUG
release: LDFLAGS += -s
debug: CXXFLAGS += -ggdb3
.PHONY: clean
NAME_SRV = testdevice-srv
CXXFLAGS =
LDFLAGS =
include ./Make-9.3.4.in