diff --git a/Make-8.1.2.c.in b/Make-8.1.2.c.in new file mode 100644 index 0000000000000000000000000000000000000000..cc8413e8f475b1f6f111c0bb1fc781dd1ae56ccc --- /dev/null +++ b/Make-8.1.2.c.in @@ -0,0 +1,66 @@ +CXXFLAGS += -std=gnu++98 + +TANGO_DIR ?= /usr/local/tango-8.1.2.c +OMNIORB_DIR ?= /usr/local/omniorb-4.1.6 +RUNTIME_DIR ?= /runtime + +TANGO_INC = ${TANGO_DIR}/include/tango +OMNIORB_INC = ${OMNIORB_DIR}/include +RUNTIME_INC = ${RUNTIME_DIR}/include + +INC_DIR = -I${TANGO_INC} -I${OMNIORB_INC} -I${RUNTIME_INC} + +TANGO_LIB = ${TANGO_DIR}/lib +OMNIORB_LIB = ${OMNIORB_DIR}/lib +RUNTIME_LIB = ${RUNTIME_DIR}/lib + +LIB_DIR = -L${TANGO_LIB} -L${OMNIORB_LIB} -L${RUNTIME_LIB} -L/usr/local/lib + +#----------------------------------------- +# Default make entry +#----------------------------------------- +default: release +release debug: bin/$(NAME_SRV) + +#----------------------------------------- +# Set CXXFLAGS and LDFLAGS +#----------------------------------------r +CXXFLAGS += -D__linux__ -D__OSVERSION__=2 -pedantic -Wall -Wextra \ + -Wno-non-virtual-dtor -Wno-long-long -DOMNI_UNLOADABLE_STUBS \ + $(INC_DIR) -Isrc +LDFLAGS += $(LIB_DIR) -ltango -llog4tango -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: + @mkdir $@ + +#----------------------------------------- +# Target specific options +#----------------------------------------- +release: CXXFLAGS += -O2 -DNDEBUG +release: LDFLAGS += -s +debug: CXXFLAGS += -ggdb3 + +.PHONY: clean diff --git a/Make-9.2.2.in b/Make-9.2.2.in new file mode 100644 index 0000000000000000000000000000000000000000..c261ce4b6da7b1d86f2cead3f612b400a3d321ea --- /dev/null +++ b/Make-9.2.2.in @@ -0,0 +1,89 @@ +CXXFLAGS += -std=c++0x + +GCCMAJOR := $(shell ${CXX} -dumpversion | cut -d"." -f1) +GCCMINOR := $(shell ${CXX} -dumpversion | cut -d"." -f2) +ifeq ($(GCCMAJOR),4) + ifneq ($(GCCMINOR),8) + SYSROOT := $(shell ${CXX} -print-sysroot) + endif +endif +MACHINE := $(shell ${CXX} -dumpmachine) + +TANGO_DIR := /usr/local/tango-9.2.2 +OMNIORB_DIR := /usr/local/omniorb-4.2.1 +ZMQ_DIR := /usr/local/zeromq-4.0.7 +RUNTIME_DIR := /runtime + +TANGO_INC := ${TANGO_DIR}/include/tango +OMNIORB_INC := ${OMNIORB_DIR}/include +RUNTIME_INC := ${RUNTIME_DIR}/include +ZMQ_INC := ${ZMQ_DIR}/include + +ifeq ($(SYSROOT),) + INC_DIR = -I${TANGO_INC} -I${OMNIORB_INC} -I${ZMQ_INC} -I${RUNTIME_INC} +else + INC_DIR = -I${SYSROOT}/usr/include/tango -I/srv/${MACHINE}/runtime/ +endif + +TANGO_LIB = ${TANGO_DIR}/lib +OMNIORB_LIB = ${OMNIORB_DIR}/lib +RUNTIME_LIB = ${RUNTIME_DIR}/lib +ZMQ_LIB = ${ZMQ_DIR}/lib + +ifeq ($(SYSROOT),) +LIB_DIR = -L${TANGO_LIB} -L${OMNIORB_LIB} -L${RUNTIME_LIB} -L${ZMQ_LIB} +else + LIB_DIR = -L/srv/${MACHINE}/runtime/lib +endif + +#----------------------------------------- +# Default make entry +#----------------------------------------- +default: release +release debug: bin/$(NAME_SRV) + +#----------------------------------------- +# Set CXXFLAGS and LDFLAGS +#----------------------------------------r +CXXFLAGS += -D__linux__ -D__OSVERSION__=2 -pedantic -Wall \ + -Wno-non-virtual-dtor -Wno-long-long -DOMNI_UNLOADABLE_STUBS \ + $(INC_DIR) -Isrc +ifeq ($(GCCMAJOR),4) + CXXFLAGS += -Wextra +endif +LDFLAGS += $(LIB_DIR) -ltango -llog4tango -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: + @mkdir $@ + +#----------------------------------------- +# Target specific options +#----------------------------------------- +release: CXXFLAGS += -O2 -DNDEBUG +release: LDFLAGS += -s +debug: CXXFLAGS += -ggdb3 + +.PHONY: clean diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6f580c39fe068357d0c96ce1a50ef11c31fb5aae --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +NAME_SRV = alarm-srv + + + +CXXFLAGS += `mysql_config --include` + + +LDFLAGS += `mysql_config --libs_r` -lboost_thread + +#include ./Make-8.1.2.c.in +include ./Make-9.2.2.in diff --git a/src/Alarm.cpp b/src/Alarm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a4648dad66d9b965458f570c3e09f47147b8698 --- /dev/null +++ b/src/Alarm.cpp @@ -0,0 +1,3567 @@ +/*----- PROTECTED REGION ID(Alarm.cpp) ENABLED START -----*/ +static const char *RcsId = "$Id: $"; +//============================================================================= +// +// file : Alarm.cpp +// +// description : C++ source for the Alarm class and its commands. +// The class is derived from Device. It represents the +// CORBA servant object which will be accessed from the +// network. All commands which can be executed on the +// Alarm are implemented in this file. +// +// project : alarm +// +// This file is part of Tango device class. +// +// Tango is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Tango is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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.h> +#include <Alarm.h> +#include <AlarmClass.h> +#include <ctype.h> //for tolower + +#include "alarm-thread.h" +#include "alarm_grammar.h" +#include "log_thread.h" +#include "update-thread.h" + +//#define _DUMP_TREE_XML +#ifdef _DUMP_TREE_XML +#if BOOST_VERSION < 103600 +#include <boost/spirit/iterator/fixed_size_queue.hpp> + +#include <boost/spirit/core.hpp> +#include <boost/spirit/tree/ast.hpp> +#include <boost/spirit/tree/tree_to_xml.hpp> + +using namespace boost::spirit; +#else +#include <boost/spirit/include/classic_fixed_size_queue.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_ast.hpp> +#include <boost/spirit/include/classic_tree_to_xml.hpp> + +using namespace boost::spirit::classic; +#endif +#include <iostream> +#include <stack> +#include <functional> +#include <string> +#include <cassert> +#endif //_DUMP_TREE_XML +#include <sstream> + +std::map<parser_id, std::string> rule_names; //only for log messages + +int Alarm_ns::Alarm::instanceCounter = 0; + +#ifndef ALARM_BUILDTIME +#define ALARM_BUILDTIME __DATE__ " " __TIME__ " boost=" BOOST_LIB_VERSION +#endif + +const char version_string[] = "$Build: @buildID@ " ALARM_BUILDTIME " $"; +static const char __FILE__rev[] = __FILE__ " $Revision: 1.29 $"; + +/*----- PROTECTED REGION END -----*/ // Alarm.cpp + +/** + * Alarm class description: + * Elettra alarm device server + */ + +//================================================================ +// The following table gives the correspondence +// between command and method names. +// +// Command name | Method name +//================================================================ +// State | Inherited (no method) +// Status | Inherited (no method) +// Ack | ack +// Load | load +// Remove | remove +// Configured | configured +// StopNew | stop_new +// Silence | silence +// Modify | modify +//================================================================ + +//================================================================ +// Attributes managed is: +//================================================================ +// alarm | Tango::DevString Spectrum ( max = 1024) +//================================================================ + +namespace Alarm_ns +{ +/*----- PROTECTED REGION ID(Alarm::namespace_starting) ENABLED START -----*/ + +// static initializations + +/*----- PROTECTED REGION END -----*/ // Alarm::namespace_starting + +//-------------------------------------------------------- +/** + * Method : Alarm::Alarm() + * Description : Constructors for a Tango device + * implementing the classAlarm + */ +//-------------------------------------------------------- +Alarm::Alarm(Tango::DeviceClass *cl, string &s) + : TANGO_BASE_CLASS(cl, s.c_str()) +{ + /*----- PROTECTED REGION ID(Alarm::constructor_1) ENABLED START -----*/ + init_device(); + + /*----- PROTECTED REGION END -----*/ // Alarm::constructor_1 +} +//-------------------------------------------------------- +Alarm::Alarm(Tango::DeviceClass *cl, const char *s) + : TANGO_BASE_CLASS(cl, s) +{ + /*----- PROTECTED REGION ID(Alarm::constructor_2) ENABLED START -----*/ + init_device(); + + /*----- PROTECTED REGION END -----*/ // Alarm::constructor_2 +} +//-------------------------------------------------------- +Alarm::Alarm(Tango::DeviceClass *cl, const char *s, const char *d) + : TANGO_BASE_CLASS(cl, s, d) +{ + /*----- PROTECTED REGION ID(Alarm::constructor_3) ENABLED START -----*/ + init_device(); + + /*----- PROTECTED REGION END -----*/ // Alarm::constructor_3 +} + +//-------------------------------------------------------- +/** + * Method : Alarm::delete_device() + * Description : will be called at device destruction or at init command + */ +//-------------------------------------------------------- +void Alarm::delete_device() +{ + DEBUG_STREAM << "Alarm::delete_device() " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::delete_device) ENABLED START -----*/ + + // Delete device allocated objects + // Delete device's allocated object + /* + * unsubscribe events and release memory + */ + DEBUG_STREAM << "Alarm::delete_device(): entering..." << endl; + abortflag = true; + DEBUG_STREAM << "Alarm::delete_device(): after abortflag=true..." << endl; + try { + events->unsubscribe(); + } catch (string& err) { + ERROR_STREAM << err << endl; + } + DEBUG_STREAM << "Alarm::delete_device(): events unsubscribed!" << endl; + events->free_proxy(); + DEBUG_STREAM << "Alarm::delete_device(): device proxy deleted!" << endl; + /* + * kill alarm thread + */ + bei_t e; + e.ev_name = ALARM_THREAD_EXIT; + e.value.push_back(ALARM_THREAD_EXIT_VALUE); + e.value.push_back(ALARM_THREAD_EXIT_VALUE); + evlist.push_back(e); +#ifdef _RW_LOCK + alarms.del_rwlock(); +#endif + alarms.stop_logdb(); + alarms.stop_cmdthread(); + sleep(1); //wait for alarm_thread and log_thread to exit + //delete almloop; + DEBUG_STREAM << "Alarm::delete_device(): stopped alarm and log threads!" << endl; + + + //delete proxy for actions + for(alarm_container_t::iterator i = alarms.v_alarm.begin(); i!=alarms.v_alarm.end(); i++) + { + if(i->second.dp_a) + delete i->second.dp_a; + i->second.dp_a = NULL; + if(i->second.dp_n) + delete i->second.dp_n; + i->second.dp_n = NULL; + } + /* + * clear all data structures + */ + alarms.v_alarm.clear(); + events->v_event.clear(); + evlist.clear(); +/* for (int i = ds_num - 1; i >= 0; i--) { + CORBA::string_free(ds[i]); + }*/ + ds_num = 0; + /* + * store current "alarmed" table status + */ + vector<string> vs; + for (vector<alarm_t>::iterator i = alarmed.begin(); \ + i != alarmed.end(); i++) { + vs.push_back(i->alm2str()); + } + Tango::DbDatum as("AlarmStatus"); + Tango::DbData data_del; + data_del.push_back(as); + //get_db_device()->delete_property(data_del); + as << vs; + Tango::DbData data_put; + data_put.push_back(as); +#ifndef _USE_ELETTRA_DB_RW + Tango::Database *db = new Tango::Database(); +#else + //salvataggio proprietà usando host_rw e port_rw per connettersi al database + Tango::Database *db; + if(host_rw != "") + db = new Tango::Database(host_rw,port_rw); + else + db = new Tango::Database(); +#endif + try { + + db->put_device_property(get_name(), data_put); + } + catch(Tango::DevFailed &e) + { + ERROR_STREAM << __FUNCTION__<< " error saving properties='" << e.errors[0].desc << "'"; + } + delete db; + + /* + * clear storage + */ + alarmed.clear(); + delete alarmedlock; + delete internallock; + delete dslock; + delete events; + DEBUG_STREAM << "Alarm::delete_device(): saved AlarmStatus in properties!!" << endl; + //Tango::leavefunc(); + + /*----- PROTECTED REGION END -----*/ // Alarm::delete_device +} + +//-------------------------------------------------------- +/** + * Method : Alarm::init_device() + * Description : will be called at device initialization. + */ +//-------------------------------------------------------- +void Alarm::init_device() +{ + DEBUG_STREAM << "Alarm::init_device() create device " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::init_device_before) ENABLED START -----*/ + + // Initialization before get_device_property() call + int dbPortint=0; + abortflag = false; + instanceCounter++; + events = new event_table(this); + //because of static map<string, unsigned int> grp_str and of exception while subscribing + //more than one time the same event in the same executable, control the number of instances + if(instanceCounter > 1) + { + ERROR_STREAM << "More than one instance in the same executable of Alarm Server is not allowed!!" << endl; + cout << "ERROR: second instance of Alarm Server, exiting..." << endl; + exit(-1); + } //------------------------------------------- + errThreshold = 0; + alarmedlock = new(ReadersWritersLock); + internallock = new(ReadersWritersLock); + dslock = new(ReadersWritersLock); + + + /*----- PROTECTED REGION END -----*/ // Alarm::init_device_before + + + // Get the device properties from database + get_device_property(); + + /*----- PROTECTED REGION ID(Alarm::init_device) ENABLED START -----*/ + + // Initialize device + +#ifdef _USE_ELETTRA_DB_RW + host_rw = ""; + Tango::Database *db = new Tango::Database(); + try + { + Tango::DbData db_data; + db_data.push_back((Tango::DbDatum("Host"))); + db_data.push_back((Tango::DbDatum("Port"))); + db->get_property("Database",db_data); + + db_data[0] >> host_rw; + db_data[1] >> port_rw; + }catch(Tango::DevFailed &e) + { + ERROR_STREAM << __FUNCTION__ << " Error reading Database property='" << e.errors[0].desc << "'"; + } + string server = "alarm-srv/test"; + Tango::DbServerInfo info = db->get_server_info(server); + INFO_STREAM << " INFO: host=" << info.host; + + delete db; +#endif + + dbPortint = atoi(dbPort.c_str()); + if(dbHost.empty() || dbUser.empty() || dbPasswd.empty() || dbName.empty() || (dbPortint == 0) || instanceName.empty()) + { + ERROR_STREAM << "Alarm::init_device(): not all necessary properties are defined: DbHost="<<dbHost<< + " DbUser="<<dbUser<<" DbPasswd="<<dbPasswd<<" DbName="<<dbName<<" DbPort="<<dbPortint<<" InstanceName="<<instanceName<< endl; + cout << "Error: not all necessary properties are defined. Exiting..." << endl; + exit(-2); + } + ds_num = 0; //initialize number of lines returned by read_alarm + internal_counter = 0; + + /*Tango::DbData db_data; + db_data.push_back(Tango::DbDatum("alarm")); + get_db_device()->get_attribute_property(db_data);*/ + /* + * connect to log database + */ +#ifdef _RW_LOCK + alarms.new_rwlock(); +#endif + try { + if((!dbHost.empty()) && (!dbUser.empty()) && (!dbPasswd.empty()) && (!dbName.empty()) && (dbPortint != 0) ) + //logloop = new log_thread(dbhost, dbuser, dbpw, dbname, dbportint,this); + alarms.init_logdb(dbHost, dbUser, dbPasswd, dbName, dbPortint, instanceName); + } catch(string & e) + { + ERROR_STREAM << "Alarm::init_device(): " << e << endl; + cout << "Error: " << e << ". Exiting..." << endl; + exit(-3); + } + + try { + alarms.init_cmdthread(); + } catch(...) + { + WARN_STREAM << "Alarm::init_device(): error creating cmd thread" << endl; + } + + rule_names[formula_grammar::val_rID] = "ValReal"; + rule_names[formula_grammar::val_hID] = "ValHex"; + rule_names[formula_grammar::val_stID] = "ValStatus"; + rule_names[formula_grammar::event_ID] = "EventFather"; + rule_names[formula_grammar::nameID] = "EventName"; + rule_names[formula_grammar::indexID] = "EventIndex"; + rule_names[formula_grammar::funcID] = "Function"; + rule_names[formula_grammar::logical_exprID] = "LogicalE"; + rule_names[formula_grammar::bitwise_exprID] = "BitwiseE"; + rule_names[formula_grammar::equality_exprID] = "EqualityE"; + rule_names[formula_grammar::compare_exprID] = "CompareE"; + rule_names[formula_grammar::add_exprID] = "AddE"; + rule_names[formula_grammar::mult_exprID] = "MultE"; + rule_names[formula_grammar::expr_atomID] = "AtomicE"; + rule_names[formula_grammar::shift_exprID] = "ShiftE"; + rule_names[formula_grammar::unary_exprID] = "UnaryE"; + + /* + * get device attribute properties and initialize internal + * data structures + */ +// short n_prop; + string expr; + string pr_name; + vector<string> tmp_alm_vec; +/* db_data[0] >> n_prop; + INFO_STREAM << "Number alarm to load = " << n_prop << endl; + for (int i = 1; i <= n_prop; i++) + { + pr_name = db_data[i].name; + db_data[i] >> expr; + DEBUG_STREAM << " -> attr property: " << pr_name << " = " << expr << endl; + size_t pos = pr_name.find('_'); + int count_ = 1; + while(pos != string::npos) //TODO: better this control + { + pos = pr_name.find('_', pos+1); + count_++; + if((count_ == 3) && (pos != string::npos)) //if at least 3 _ in the attr property name, expr is OK //TODO: better this control + { + tmp_alm_vec.push_back(expr); + break; + } + } + }*/ + try { + alarms.get_alarm_list_db(tmp_alm_vec); + } catch(string & e) + { + ERROR_STREAM << "Alarm::init_device(): " << e << endl; + cout << "Error: " << e << ". Exiting..." << endl; + exit(-4); + } + + + /* + * store the alarms into alarm table vector + */ + map< string,vector<string> > alarm_event; //map alarm->vector event popolated by parser + vector<string> evn; //vector with all event (possibly duplicated) popolated by parser + vector<string> temp_evn; + vector<string> tmp_alm_name_lst; + //alarms.init(tmp_alm_vec, evn, alarm_event); + alarm_t tmp_alm; + evn.clear(); + for(vector<string>::iterator it_al = tmp_alm_vec.begin(); it_al!= tmp_alm_vec.end(); it_al++) + { + tmp_alm.clear(); + temp_evn.clear(); + try { + load_alarm(*it_al, tmp_alm, temp_evn); + add_alarm(tmp_alm); + tmp_alm_name_lst.push_back(tmp_alm.name); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error loading alarm=" << tmp_alm.name << " , " << e.errors[0].desc << ends; + WARN_STREAM << "Alarm::init_device(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + continue; + } catch (string& err) { + ostringstream err_out; + err_out << "error loading alarm=" << tmp_alm.name << " , " << err << ends; + WARN_STREAM << "Alarm::init_device(): " << err_out.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err_out.str()); + continue; + } + //eliminate duplicated event + if (temp_evn.empty() == false) + { + sort(temp_evn.begin(), temp_evn.end()); + vector<string>::iterator new_end = \ + unique(temp_evn.begin(), temp_evn.end()); + while (temp_evn.end() != new_end) + temp_evn.pop_back(); + } + alarm_event.insert(make_pair(tmp_alm.name,temp_evn)); + evn.insert(evn.end(),temp_evn.begin(),temp_evn.end()); +/* alarms.log_alarm_db(TYPE_LOG_DESC_SYNC, gettime(), tmp_alm.name, "", "", //remove if alarm with the same name exist but is changed + tmp_alm.formula, tmp_alm.grp2str(), tmp_alm.lev, tmp_alm.msg); + alarms.log_alarm_db(TYPE_LOG_DESC_ADD, gettime(), tmp_alm.name, "", "", //add new alarm if there is not already one active with the same name + tmp_alm.formula, tmp_alm.grp2str(), tmp_alm.lev, tmp_alm.msg);*/ + } +/* alarms.log_alarm_db(TYPE_LOG_DESC_UPD_OLD, gettime(), "", "", "", //set as not active all alarms not present in this list + "", "", "", "", tmp_alm_name_lst);*/ + DEBUG_STREAM << "alarms table size = " << alarms.size() << endl; + + vector<string> al_table_string; + alarms.show(al_table_string); + for(vector<string>::iterator str_it=al_table_string.begin(); str_it!=al_table_string.end(); str_it++) + DEBUG_STREAM << (*str_it) << endl; + + /* + * check 'stored' alarms against current alarm table for consistency + */ + vector<string> to_remove_from_stored; + if (stored.empty() == false) { + for (vector<alarm_t>::iterator i = stored.begin(); \ + i != stored.end(); i++) { + alarm_container_t::iterator found = alarms.v_alarm.find(i->name); + if (found == alarms.v_alarm.end()) { + + to_remove_from_stored.push_back(i->name); + //stored.erase(i); + } + } + } + for(vector<string>::iterator k=to_remove_from_stored.begin(); k != to_remove_from_stored.end(); k++) + { + vector<alarm_t>::iterator rmv = find(stored.begin(),stored.end(),*k); + if(rmv != stored.end()) + { + ERROR_STREAM << "init_device(): alarm '" << *k \ + << "' NOT found in alarm table! " \ + << "Removing from 'stored' alarms" << endl; + stored.erase(rmv); + } + else + WARN_STREAM << "init_device(): alarm " << *k << " not found while removing from stored !!!" << endl; + } + /* + * update "alarm" table with "stored" alarms + */ + alarms.stored(stored); + /* + * update "alarmed" table with "stored" alarms + */ + if (stored.empty() == false) { + alarmedlock->writerIn(); + for (vector<alarm_t>::iterator i = stored.begin(); \ + i != stored.end(); i++) { + alarmed.push_back(*i); + } + alarmedlock->writerOut(); + } + + for(alarm_container_t::iterator i = alarms.v_alarm.begin(); \ + i!=alarms.v_alarm.end(); i++) + { + if(i->second.cmd_name_a.length() > 0) + { + try { + i->second.dp_a = new Tango::DeviceProxy(i->second.cmd_dp_a); + i->second.dp_a->ping(); + Tango::CommandInfo info = i->second.dp_a->command_query(i->second.cmd_action_a); + if((info.in_type != Tango::DEV_STRING) && (info.in_type != Tango::DEV_VOID)) + { + ostringstream err; + err << i->second.name << ": error, command " << i->second.cmd_name_a << " does not accept a Tango::DevString or a Tango::DevVoid as input value" << ends; + ERROR_STREAM << "Alarm::init_device(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + else + { + if(info.in_type == Tango::DEV_STRING) + i->second.send_arg_a = true; + else + i->second.send_arg_a = false; + DEBUG_STREAM << "Alarm::init_device(): " << i->second.name << ": successfully connected to proxy=" << i->second.cmd_dp_a << " for action=" << i->second.cmd_action_a << endl; + } + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << i->second.name << ": error connecting to device proxy=" << i->second.cmd_dp_a << ", err=" << e.errors[0].desc << ends; + WARN_STREAM << "Alarm::init_device(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + i->second.dp_a = NULL; + } + } + if(i->second.cmd_name_n.length() > 0) + { + try { + i->second.dp_n = new Tango::DeviceProxy(i->second.cmd_dp_n); + i->second.dp_n->ping(); + Tango::CommandInfo info = i->second.dp_n->command_query(i->second.cmd_action_n); + if((info.in_type != Tango::DEV_STRING) && (info.in_type != Tango::DEV_VOID)) + { + ostringstream err; + err << i->second.name << ": error, command " << i->second.cmd_name_n << " does not accept a Tango::DevString or a Tango::DevVoid as input value" << ends; + ERROR_STREAM << "Alarm::init_device(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + else + { + if(info.in_type == Tango::DEV_STRING) + i->second.send_arg_n = true; + else + i->second.send_arg_n = false; + DEBUG_STREAM << "Alarm::init_device(): " << i->second.name << ": successfully connected to proxy=" << i->second.cmd_dp_n << " for action=" << i->second.cmd_action_n << endl; + } + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << i->second.name << ": error connecting to device proxy=" << i->second.cmd_dp_n << ", err=" << e.errors[0].desc << ends; + WARN_STREAM << "Alarm::init_device(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + i->second.dp_n = NULL; + } + } + } + + alarms.startup_complete = gettime(); //enable actions execution in 10 seconds + + ecb.init(&evlist); + for(map<string, vector<string> >::iterator al_ev_it=alarm_event.begin(); \ + al_ev_it!=alarm_event.end(); al_ev_it++) + { + alarm_container_t::iterator i = alarms.v_alarm.find(al_ev_it->first); + if(i != alarms.v_alarm.end()) + { +#if TANGO_VER < 611 + try { + add_event(i->second, al_ev_it->second); + subscribe_event(i->second, ecb, al_ev_it->second); + } catch (string& err) { + WARN_STREAM << "Alarm::init_device(): " << err << endl; + for(vector<string>::iterator j=al_ev_it->second.begin(); j!=al_ev_it->second.end(); j++) + { + DEBUG_STREAM << "Alarm::init_device(): Removing alarm=" << i->second.name << " from event=" << *j << endl; + vector<event>::iterator k = \ + find(events->v_event.begin(), events->v_event.end(), *j); + if (k != events->v_event.end()) + { + k->pop_alarm(i->second.name); //remove alarm/formula just added to event + DEBUG_STREAM << "Alarm::init_device(): Removed!!!! alarm=" << i->second.name << " from event=" << *j << endl; + if(k->m_alarm.empty()) + { + events->v_event.erase(k); //remove event just added to event_table + DEBUG_STREAM << "Alarm::init_device(): event=" << *j << " no more used, REMOVED!!!" << endl; + } + } + } + set_internal_alarm(INTERNAL_ERROR, gettime(), err); + } +#else + try { + add_event(i->second, al_ev_it->second); + } catch (string& err) { + WARN_STREAM << "Alarm::init_device(): " << err << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err); + } + try { + subscribe_event(i->second, ecb, al_ev_it->second); + } catch (string& err) { + WARN_STREAM << "Alarm::init_device(): " << err << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err); + } +#endif + } + } + + + /* + * update event table with fresh-subscribed event[s] data + */ + + list<bei_t> el; + el = evlist.show(); + + try { + for (list<bei_t>::iterator j = el.begin(); j != el.end(); j++) + { + //cout << "name = " << j->name << "\ttype = " << j->type << endl; + events->update_events(*j); + } + } + catch (string& err) + { + WARN_STREAM << "init_device(): error updating events = " << err << endl; + } + set_change_event("alarm",true,false); + /* + * create alarm processing thread + */ + + //almloop = new alarm_thread::alarm_thread(/*this*/); + almloop = new alarm_thread(this); + almloop->start(); + + updateloop = new update_thread(this); + updateloop->start(); + + set_state(Tango::RUNNING); + set_status("Alarm server is running"); + + // + +// for (int i=0; i< MAX_ALARMS ; i++) ds[i]=0; +// ds_num = 0; + for (int i=0; i< MAX_ALARMS ; i++) + ds[i]=(char *) (dss[i]); + + /*----- PROTECTED REGION END -----*/ // Alarm::init_device +} + +//-------------------------------------------------------- +/** + * Method : Alarm::get_device_property() + * Description : Read database to initialize property data members. + */ +//-------------------------------------------------------- +void Alarm::get_device_property() +{ + /*----- PROTECTED REGION ID(Alarm::get_device_property_before) ENABLED START -----*/ + + // Initialize property data members + + + /*----- PROTECTED REGION END -----*/ // Alarm::get_device_property_before + + + // Read device properties from database. + Tango::DbData dev_prop; + dev_prop.push_back(Tango::DbDatum("AlarmStatus")); + dev_prop.push_back(Tango::DbDatum("GroupNames")); + dev_prop.push_back(Tango::DbDatum("ErrThreshold")); + dev_prop.push_back(Tango::DbDatum("DbHost")); + dev_prop.push_back(Tango::DbDatum("DbUser")); + dev_prop.push_back(Tango::DbDatum("DbPasswd")); + dev_prop.push_back(Tango::DbDatum("DbName")); + dev_prop.push_back(Tango::DbDatum("DbPort")); + dev_prop.push_back(Tango::DbDatum("InstanceName")); + + // is there at least one property to be read ? + if (dev_prop.size()>0) + { + // Call database and extract values + if (Tango::Util::instance()->_UseDb==true) + get_db_device()->get_property(dev_prop); + + // get instance on AlarmClass to get class property + Tango::DbDatum def_prop, cl_prop; + AlarmClass *ds_class = + (static_cast<AlarmClass *>(get_device_class())); + int i = -1; + + // Try to initialize AlarmStatus from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> alarmStatus; + else { + // Try to initialize AlarmStatus from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> alarmStatus; + } + // And try to extract AlarmStatus value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> alarmStatus; + + // Try to initialize GroupNames from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> groupNames; + else { + // Try to initialize GroupNames from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> groupNames; + } + // And try to extract GroupNames value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> groupNames; + + // Try to initialize ErrThreshold from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> errThreshold; + else { + // Try to initialize ErrThreshold from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> errThreshold; + } + // And try to extract ErrThreshold value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> errThreshold; + + // Try to initialize DbHost from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> dbHost; + else { + // Try to initialize DbHost from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> dbHost; + } + // And try to extract DbHost value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbHost; + + // Try to initialize DbUser from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> dbUser; + else { + // Try to initialize DbUser from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> dbUser; + } + // And try to extract DbUser value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbUser; + + // Try to initialize DbPasswd from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> dbPasswd; + else { + // Try to initialize DbPasswd from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> dbPasswd; + } + // And try to extract DbPasswd value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbPasswd; + + // Try to initialize DbName from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> dbName; + else { + // Try to initialize DbName from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> dbName; + } + // And try to extract DbName value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbName; + + // Try to initialize DbPort from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> dbPort; + else { + // Try to initialize DbPort from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> dbPort; + } + // And try to extract DbPort value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbPort; + + // Try to initialize InstanceName from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> instanceName; + else { + // Try to initialize InstanceName from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> instanceName; + } + // And try to extract InstanceName value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> instanceName; + + } + + /*----- PROTECTED REGION ID(Alarm::get_device_property_after) ENABLED START -----*/ + + // Check device property data members init + /* + * initialize groups + */ + alarm_t tmp_alm; + tmp_alm.init_static_map(groupNames); + + /* + * retrive last saved alarms status + */ + if (alarmStatus.empty() == false) { + for (vector<string>::iterator i = alarmStatus.begin(); \ + i != alarmStatus.end(); i++) { + /* + * test for string length; data[1].is_empty() will return false + * when empty string eventually initialized with jive!!!!!! + */ + if (i->length() != 0) { + alarm_t tmp_alm; + tmp_alm.str2alm(*i); + tmp_alm.is_new = /*(tmp_alm.stat == S_ALARM) ? 1 :*/ 0; //don't beep at startup on old alarms + stored.push_back(tmp_alm); + } + } + } + DEBUG_STREAM << "saved alarms table:" << endl; + if (stored.empty() == false) { + for (vector<alarm_t>::iterator a = stored.begin(); \ + a != stored.end(); a++) { + DEBUG_STREAM << "\t" << a->alm2str() << endl; + } + } + + /*----- PROTECTED REGION END -----*/ // Alarm::get_device_property_after +} + +//-------------------------------------------------------- +/** + * Method : Alarm::always_executed_hook() + * Description : method always executed before any command is executed + */ +//-------------------------------------------------------- +void Alarm::always_executed_hook() +{ + DEBUG_STREAM << "Alarm::always_executed_hook() " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::always_executed_hook) ENABLED START -----*/ + + // code always executed before all requests + + + /*----- PROTECTED REGION END -----*/ // Alarm::always_executed_hook +} + +//-------------------------------------------------------- +/** + * Method : Alarm::read_attr_hardware() + * Description : Hardware acquisition for attributes + */ +//-------------------------------------------------------- +void Alarm::read_attr_hardware(TANGO_UNUSED(vector<long> &attr_list)) +{ + DEBUG_STREAM << "Alarm::read_attr_hardware(vector<long> &attr_list) entering... " << endl; + /*----- PROTECTED REGION ID(Alarm::read_attr_hardware) ENABLED START -----*/ + + // Add your own code + //DEBUG_STREAM << "In read_attr_hardware for " << attr_list.size() << " attribute(s)" << endl; + + // Add your own code here + //--------------------------------- + + /*----- PROTECTED REGION END -----*/ // Alarm::read_attr_hardware +} + +//-------------------------------------------------------- +/** + * Read attribute alarm related method + * Description: + * + * Data type: Tango::DevString + * Attr type: Spectrum max = 1024 + */ +//-------------------------------------------------------- +void Alarm::read_alarm(Tango::Attribute &attr) +{ + DEBUG_STREAM << "Alarm::read_alarm(Tango::Attribute &attr) entering... " << endl; + /*----- PROTECTED REGION ID(Alarm::read_alarm) ENABLED START -----*/ + // Add your own code here +#if 0 + alarm_container_t::iterator ai; + vector<alarm_t>::iterator aid; + for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) { + if (ai->second.stat == S_ALARM) { + /* + * alarm status is S_ALARM + */ + aid = find(alarmed.begin(), alarmed.end(),ai->second.name); + if (aid != alarmed.end()) { + /* + * found, change stat only if switching from + * S_NORMAL to S_ALARM status + */ + //cout << "read_attr(): S_ALARM: found: " << aid->name << endl; + if (aid->stat == S_NORMAL) { + aid->stat = S_ALARM; + aid->ack = NOT_ACK; + aid->ts = ai->second.ts; + aid->msg = ai->second.msg; + } + aid->grp = ai->second.grp; + aid->lev = ai->second.lev; + aid->is_new = ai->second.is_new; //copy is_new state + //ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0 + aid->counter = ai->second.counter; + aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset + aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary) + aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update + } else { + /* + * not found: new "alarmed" item + */ + DEBUG_STREAM << "read_attr(): S_ALARM: pushing new alarm: " \ + << ai->second.name << "\t" << ai->second.stat << endl; + alarmed.push_back(ai->second); + //ai->second.is_new = 0; //set state as not more new //12-06-08: StopNew command set it to 0 + } + } else if (ai->second.stat == S_NORMAL) { + /* + * alarm status is S_NORMAL + */ + aid = find(alarmed.begin(), alarmed.end(), ai->second.name); + if (aid != alarmed.end()) { + /* + * found, as it should; + * switching from S_ALARM to S_NORMAL + */ + aid->stat = S_NORMAL; + aid->ts = ai->second.ts; + //aid->msg = " "; /* no message again */ + aid->msg =ai->second.msg; + aid->grp = ai->second.grp; + aid->lev = ai->second.lev; + aid->counter = ai->second.counter; + aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset + aid->is_new = ai->second.is_new; //copy is_new state + aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary) + aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update + //ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0 + if (aid->ack == ACK) { + if (aid->done) { + /* + * if already ACKnowledged and visualized + * remove from "alarmed" list + */ + DEBUG_STREAM << "read_attr(): S_NORMAL: " << aid->name \ + << " ACKnowledged: removing" << endl; + alarmed.erase(aid); + } else { + aid->done = true; + } + } /* if */ + } /* if */ + } /* if else if */ + } /* for */ + + vector<string> tmp_alarm_table; + string is_new; + ostringstream os1; + /*os1.clear(); + os1 << header << "\t" << alarmed.size() << ends;*/ + //tmp_alarm_table.push_back(os1.str()); + if (alarmed.empty() == false) { + for (aid = alarmed.begin(); aid != alarmed.end(); aid++) { + if(aid->silenced > 0) + { + Tango::TimeVal now = gettime(); + double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000; + double dsilent = aid->ts_time_silenced.tv_sec + ((double)aid->ts_time_silenced.tv_usec) / 1000000; + double dminutes = (dnow - dsilent)/60; + //silenced already calculated in alarm_table::update, but here updated for panel also if state not changed: + //to see minutes countdown + if(dminutes < aid->silent_time) + aid->silenced = aid->silent_time - floor(dminutes); + else + aid->silenced = 0; + } + ostringstream os; + os.clear(); + is_new.clear(); + is_new = (aid->is_new && aid->silenced <= 0) ? "NEW" : " "; + os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \ + << aid->name << "\t" << aid->stat << "\t" << aid->ack \ + << "\t" << aid->counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new << ends; + tmp_alarm_table.push_back(os.str()); + } + } + if (internal.empty() == false) { + for (aid = internal.begin(); aid != internal.end(); aid++) { + +/* size_t index; + int count = 1; + index = aid->stat.find("*"); + if((index != std::string::npos) && (index+1 != std::string::npos)) + { + + size_t last = aid->stat.size(); + string str_count= aid->stat.substr(index+1, last - index+1); + count = strtol(str_count.c_str(), 0,10); + } + //do not show internal alarms that have a molteplicity less then errThreshold + if((aid->msg.find()) && (count < errThreshold)) + continue;*/ + + ostringstream os; + os.clear(); + os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \ + << aid->name << "\t" << aid->stat << "\t" << aid->ack \ + << "\t" << aid->counter << "\t" << aid->lev << "\t"<< -1/*silenced*/ <<"\t" << aid->grp2str() << "\t" << aid->msg << "\t "<< ends; //TODO: silenced for internal errors? + tmp_alarm_table.push_back(os.str()); + } + } + int i; + for (i = ds_num - 1; i >= 0; i--) { + CORBA::string_free(ds[i]); + } + ds_num = tmp_alarm_table.size(); + if(ds_num > MAX_ALARMS) + ds_num = MAX_ALARMS; + for (i = 0; i < ds_num; i++) { + ds[i] = CORBA::string_dup(tmp_alarm_table[i].c_str()); + } + if(ds_num == 0) + { + ostringstream os1; + ds_num++; + os1.clear(); + os1 << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << -1 << "\t" << 0 << "\t" << 0 << "\t "<< ends; + ds[0] = CORBA::string_dup(os1.str().c_str()); + } +#else + //bool changed; + //prepare_alarm_attr(changed);//moved in do_alarm; +#endif + if(ds_num == 0) + { + attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + attr.set_value(ds, ds_num, 0, false); + + /*----- PROTECTED REGION END -----*/ // Alarm::read_alarm +} + +//-------------------------------------------------------- +/** + * Method : Alarm::add_dynamic_attributes() + * Description : Create the dynamic attributes if any + * for specified device. + */ +//-------------------------------------------------------- +void Alarm::add_dynamic_attributes() +{ + /*----- PROTECTED REGION ID(Alarm::add_dynamic_attributes) ENABLED START -----*/ + + // Add your own code to create and add dynamic attributes if any + + /*----- PROTECTED REGION END -----*/ // Alarm::add_dynamic_attributes +} + +//-------------------------------------------------------- +/** + * Command Ack related method + * Description: Alarm acknowledge + * + * @param argin String array containing the alarms to be acknowledged + */ +//-------------------------------------------------------- +void Alarm::ack(const Tango::DevVarStringArray *argin) +{ + DEBUG_STREAM << "Alarm::Ack() - " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::ack) ENABLED START -----*/ + + // Add your own code + vector<string> str; + str << (*argin); + vector<string>::iterator si; + + for (si = str.begin(); si != str.end(); si++) { +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + alarmedlock->readerIn(); + vector<alarm_t>::iterator found = \ + find(alarmed.begin(), alarmed.end(), *si); + if (found != alarmed.end()) + { + alarm_container_t::iterator i = alarms.v_alarm.find(*si); + if(i != alarms.v_alarm.end()) + { + //update alarm ack in alarm table + i->second.ack = ACK; + //update alarm status from alarm table + found->stat = i->second.stat; + } + if(found->ack == NOT_ACK) + { + alarms.log_alarm_db(TYPE_LOG_STATUS, gettime(), found->name, found->stat, ACK, + "", 0, "", "", "", "", -1); + } + found->ack = ACK; + } else { + internallock->readerIn(); + found = find(internal.begin(), internal.end(), *si); + if (found != internal.end()) { + found->ack = ACK; + } else { + ostringstream o; + o << "\"" << *si << "\" not in 'alarmed' or 'internal' table" << endl; + WARN_STREAM << "Alarm::ack(): " << o.str() << endl; + internallock->readerOut(); + alarmedlock->readerOut(); +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + Tango::Except::throw_exception( \ + (const char*)"Alarm not found!!", \ + o.str(), \ + (const char*)"Alarm::ack()", Tango::ERR); + + } + internallock->readerOut(); + } + alarmedlock->readerOut(); +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + } + /* + * remove S_NORMAL status ACKnowledged alarms + */ + alarm_t to_be_removed; + to_be_removed.name = ""; + to_be_removed.formula = ""; + to_be_removed.stat = S_NORMAL; + to_be_removed.ack = ACK; + bool go = true; + while (go) { + alarmedlock->writerIn(); + vector<alarm_t>::iterator found = \ + find(alarmed.begin(), alarmed.end(), to_be_removed); + if (found != alarmed.end()) { + DEBUG_STREAM << "Alarm::ack(): " << found->name \ + << " S_NORMAL and ACK, removing" << endl; + alarmed.erase(found); + } else { + go = false; + } + alarmedlock->writerOut(); + } + /* + * always remove internal ACKnowlwdged alarms as + * they'll wont switch to "NORMAL" + */ + to_be_removed.name = ""; + to_be_removed.formula = ""; + to_be_removed.stat = S_ALARM; + to_be_removed.ack = ACK; + go = true; + while (go) { + internallock->writerIn(); + vector<alarm_t>::iterator found = \ + find(internal.begin(), internal.end(), to_be_removed); + if (found != internal.end()) { + DEBUG_STREAM << "Alarm::ack(): " << found->name \ + << " ACK, removing" << endl; + internal.erase(found); + } else { + go = false; + } + internallock->writerOut(); + } + + prepare_alarm_attr(); + try + { + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error pushing alarm change event err=" << e.errors[0].desc; + INFO_STREAM << __func__<<": " << err.str() << endl; + } + + /*----- PROTECTED REGION END -----*/ // Alarm::ack +} +//-------------------------------------------------------- +/** + * Command Load related method + * Description: Load a new alarm. + * + * @param argin Alarm entry + */ +//-------------------------------------------------------- +void Alarm::load(Tango::DevString argin) +{ + DEBUG_STREAM << "Alarm::Load() - " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::load) ENABLED START -----*/ + + // Add your own code + string s; + alarm_t alm; + vector<string> evn; + + s = argin; + //std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase + Tango::TimeVal ts = gettime(); + try { + load_alarm(s, alm, evn); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error loading alarm=" << alm.name << " , " << e.errors[0].desc << ends; + WARN_STREAM << "Alarm::load(): " << err.str() << endl; + Tango::Except::throw_exception( \ + (const char*)"Alarm::load()", \ + err.str(), \ + (const char*)"Alarm::load()", Tango::ERR); + } + + try { + add_alarm(alm); + } catch (string& err) { + WARN_STREAM << "Alarm::load(): " << err << endl; + Tango::Except::throw_exception( \ + (const char*)"Alarm::load()", \ + (const char*)err.c_str(), \ + (const char*)"Alarm::load()", Tango::ERR); + } + try { + add_event(alm, evn); + } catch (string& err) { + WARN_STREAM << "Alarm::load(): " << err << endl; +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->writerIn(); +#endif + alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added + if (i != alarms.v_alarm.end()) + alarms.erase(i); //and remove from alarm_table +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + Tango::Except::throw_exception( \ + (const char*)"Alarm::load()", \ + (const char*)err.c_str(), \ + (const char*)"Alarm::load()", Tango::ERR); + } + string cmd_name_full = alm.cmd_name_a + string(";") + alm.cmd_name_n; + alarms.log_alarm_db(TYPE_LOG_DESC_ADD, ts, alm.name, "", "", //add new alarm on log before subscribe event + alm.formula, alm.time_threshold, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time); //but if it fails remove it from table + try { + subscribe_event(alm, ecb, evn); + } catch (string& err) { + WARN_STREAM << "Alarm::load(): " << err << endl; +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->writerIn(); +#endif + alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added + if (i != alarms.v_alarm.end()) + alarms.erase(i); //and remove from alarm_table +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + alarms.log_alarm_db(TYPE_LOG_DESC_REM, ts, alm.name, "", "", //remove alarm just added + "", 0, "", "", "", "", -1); + Tango::Except::throw_exception( \ + (const char*)"Alarm::load()", \ + (const char*)err.c_str(), \ + (const char*)"Alarm::load()", Tango::ERR); + } + + if(alm.cmd_name_a.length() > 0) + { +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added + if (i != alarms.v_alarm.end()) + { + try { + i->second.dp_a = new Tango::DeviceProxy(i->second.cmd_dp_a); + i->second.dp_a->ping(); + Tango::CommandInfo info = i->second.dp_a->command_query(i->second.cmd_action_a); + if(info.in_type != Tango::DEV_STRING) + { + ostringstream err; + err << "Error: command " << i->second.cmd_name_a << " does not accept a Tango::DevString as input value" << ends; + ERROR_STREAM << "Alarm::load(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + else + { + if(info.in_type == Tango::DEV_STRING) + i->second.send_arg_a = true; + else + i->second.send_arg_a = false; + DEBUG_STREAM << "Alarm::load(): successfully connected to proxy=" << i->second.cmd_dp_a << " for action=" << i->second.cmd_action_a << endl; + } + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_a << ", err=" << e.errors[0].desc << ends; + WARN_STREAM << "Alarm::load(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + } + if(alm.cmd_name_n.length() > 0) + { +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added + if (i != alarms.v_alarm.end()) + { + try { + i->second.dp_n = new Tango::DeviceProxy(i->second.cmd_dp_n); + i->second.dp_n->ping(); + Tango::CommandInfo info = i->second.dp_n->command_query(i->second.cmd_action_a); + if(info.in_type != Tango::DEV_STRING) + { + ostringstream err; + err << "Error: command " << i->second.cmd_name_n << " does not accept a Tango::DevString as input value" << ends; + ERROR_STREAM << "Alarm::load(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + else + { + if(info.in_type == Tango::DEV_STRING) + i->second.send_arg_n = true; + else + i->second.send_arg_n = false; + DEBUG_STREAM << "Alarm::load(): successfully connected to proxy=" << i->second.cmd_dp_n << " for action=" << i->second.cmd_action_n << endl; + } + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_n << ", err=" << e.errors[0].desc << ends; + WARN_STREAM << "Alarm::load(): " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + } + + //if at least one event was already existing, evaluate formula of just added alarm + if(alm.to_be_evaluated) //TODO: remove this evaluation of the formula that is not necessary + { + DEBUG_STREAM << "Alarm::load(): Evaluating formula=" << alm.formula << endl; + try { + double res; + string attr_values; + res = eval_formula(alm.formula_tree, attr_values); + DEBUG_STREAM << "Parsing succeeded of "<< alm.formula << "; result=" << res << endl; + alarms.update(alm.name, gettime(), (int)res, attr_values, alm.grp2str(), alm.msg, alm.formula); //pass "now" as timestamp in this case + + } catch(std::out_of_range& e) + { + ostringstream o; + o << alm.name << ": in formula array index out of range!" << ends; + WARN_STREAM << "Alarm::load(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } catch(string & e) + { + ostringstream o; + o << alm.name << ": in formula err=" << e << ends; + WARN_STREAM << "Alarm::load(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } catch(Tango::DevFailed& e) + { + ostringstream o; + o << alm.name << "error=" << e.errors[0].desc << ends; + WARN_STREAM << "Alarm::load(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } + } + + prepare_alarm_attr(); + try + { + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error pushing alarm change event err=" << e.errors[0].desc; + INFO_STREAM << __func__<<": " << err.str() << endl; + } + + /*----- PROTECTED REGION END -----*/ // Alarm::load +} +//-------------------------------------------------------- +/** + * Command Remove related method + * Description: Remove alarm. + * + * @param argin Alarm name + */ +//-------------------------------------------------------- +void Alarm::remove(Tango::DevString argin) +{ + DEBUG_STREAM << "Alarm::Remove() - " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::remove) ENABLED START -----*/ + + // Add your own code + string s, log_alm_name; + s = argin; + log_alm_name = argin; + bool ret = false; + + alarmedlock->readerIn(); + vector<alarm_t>::iterator found = find(alarmed.begin(), alarmed.end(), s); + if (found != alarmed.end()) + { + ostringstream err; + err << s << " is in ALARM status! Acknowledge it before removing." << ends; + if((found->stat == S_ALARM) && (found->ack == NOT_ACK)) + { + alarmedlock->readerOut(); + Tango::Except::throw_exception( \ + (const char*)"Error removing alarm", \ + (const char*)err.str().c_str(), \ + (const char*)"Alarm::remove", Tango::ERR); + } + } + alarmedlock->readerOut(); + try { + ret = remove_alarm(s); + } catch (string& err) { + Tango::Except::throw_exception( \ + (const char*)"Error removing alarm", \ + (const char*)err.c_str(), \ + (const char*)"Alarm::remove", Tango::ERR); + } + if (ret) { + DEBUG_STREAM << "Alarm::remove(): removing alarm '" \ + << s << "'" << endl; + while (true) { + string::size_type i = s.find_first_of("/."); + if (i == string::npos) + break; + s.replace(i, 1, "_"); + } + } /* end if */ + alarms.log_alarm_db(TYPE_LOG_DESC_DIS, gettime(), log_alm_name, "", "", //set active to 0 + "", 0, "", "", "", "", -1); + alarmedlock->writerIn(); + found = find(alarmed.begin(), alarmed.end(), s); //look again because in the meanwhile lock was not acquired + if (found != alarmed.end()) + { + alarmed.erase(found); //remove from alarmed table + } + alarmedlock->writerOut(); + + prepare_alarm_attr(); + try + { + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error pushing alarm change event err=" << e.errors[0].desc; + INFO_STREAM << __func__<<": " << err.str() << endl; + } + + /*----- PROTECTED REGION END -----*/ // Alarm::remove +} +//-------------------------------------------------------- +/** + * Command Configured related method + * Description: Alarms configured + * + * @param argin String containing a filter for output, if empty return all alarms + * @returns Alarms configured + */ +//-------------------------------------------------------- +Tango::DevVarStringArray *Alarm::configured(Tango::DevString argin) +{ + Tango::DevVarStringArray *argout; + DEBUG_STREAM << "Alarm::Configured() - " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::configured) ENABLED START -----*/ + + // Add your own code + // POGO has generated a method core with argout allocation. + // If you would like to use a static reference without copying, + // See "TANGO Device Server Programmer's Manual" + // (chapter : Writing a TANGO DS / Exchanging data) + //------------------------------------------------------------ + argout = new Tango::DevVarStringArray(); + //argout->length(1); + //(*argout)[0] = CORBA::string_dup("dummy"); + DEBUG_STREAM << "Alarm::configured(): entering... !" << endl; + + // Add your own code to control device here + + string filter(argin); + size_t found; + vector<string> alarm_filtered; + ostringstream os1; + os1.clear(); + /*os1 << headerConfig << "\t" << alarms.v_alarm.size() << ends; + alarm_filtered.push_back(os1.str());*/ + + alarm_container_t::iterator ai; +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) + { + found = 0; + if(filter.length() != 0) + { + found = ai->first.find(filter); + } + if((filter.length() == 0) || (found != string::npos)) + { + ostringstream os; + os.clear(); + os << ai->second.ts.tv_sec << "\t" << ai->second.name << "\t" << ai->second.formula << "\t" << ai->second.time_threshold << + "\t" << ai->second.lev << "\t" << ai->second.silent_time << "\t" << ai->second.grp2str() << "\t" << ai->second.msg << "\t" << + ai->second.cmd_name_a << ";" << ai->second.cmd_name_n << ends; + alarm_filtered.push_back(os.str()); + } + } /* for */ +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + argout->length(alarm_filtered.size()); + int i = 0; + for (vector<string>::iterator it= alarm_filtered.begin(); it != alarm_filtered.end(); it++) + { + (*argout)[i] = CORBA::string_dup(it->c_str()); + i++; + } + + /*----- PROTECTED REGION END -----*/ // Alarm::configured + return argout; +} +//-------------------------------------------------------- +/** + * Command StopNew related method + * Description: Remove "NEW" field from alarm string (so alarm panel stop sound) + * + */ +//-------------------------------------------------------- +void Alarm::stop_new() +{ + DEBUG_STREAM << "Alarm::StopNew() - " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::stop_new) ENABLED START -----*/ + + // Add your own code + //12-06-08: StopNew command set is_new to 0 + // Add your own code to control device here + alarm_container_t::iterator ai; +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) { + ai->second.is_new = 0; //set all alarm as no more new + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + + prepare_alarm_attr(); + try + { + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error pushing alarm change event err=" << e.errors[0].desc; + INFO_STREAM << __func__<<": " << err.str() << endl; + } + + /*----- PROTECTED REGION END -----*/ // Alarm::stop_new +} +//-------------------------------------------------------- +/** + * Command Silence related method + * Description: Alarm temporarily silence + * + * @param argin String array containing the alarms to be silenced + */ +//-------------------------------------------------------- +void Alarm::silence(const Tango::DevVarStringArray *argin) +{ + DEBUG_STREAM << "Alarm::Silence() - " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::silence) ENABLED START -----*/ + + // Add your own code + vector<string> str; + str << (*argin); + vector<string>::iterator si; + + for (si = str.begin(); si != str.end(); si++) + { +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + alarm_container_t::iterator i = alarms.v_alarm.find(*si); + if(i != alarms.v_alarm.end()) + { + 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; + //silenced already calculated in alarm_table::update, but here updated for panel also if state not changed: + //to see minutes countdown + if(dminutes < i->second.silent_time) + i->second.silenced = i->second.silent_time - floor(dminutes); + else + i->second.silenced = 0; + } + if(i->second.silenced > 0) + { + ostringstream err; + err << "Alarm " << *si << " already silenced for " << i->second.silenced << " more minutes" << ends; +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + Tango::Except::throw_exception( \ + (const char*)"Alarm already silenced", \ + err.str(), \ + (const char*)"Alarm::silence()", Tango::ERR); + } + if(i->second.silent_time <= 0) + { + ostringstream err; + err << "Alarm " << *si << " cannot be silenced" << ends; +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + Tango::Except::throw_exception( \ + (const char*)"Alarm cannot be silenced", \ + err.str(), \ + (const char*)"Alarm::silence()", Tango::ERR); + } + + //load silent time + i->second.ts_time_silenced = gettime(); + i->second.silenced = i->second.silent_time; + //search also in alarmed + alarmedlock->readerIn(); + vector<alarm_t>::iterator found = \ + find(alarmed.begin(), alarmed.end(), *si); + if (found != alarmed.end()) + { + //load silent time from alarm table + found->silenced = i->second.silent_time; + found->ts_time_silenced = i->second.ts_time_silenced; + } + alarmedlock->readerOut(); + } + //alarms.unlock(); + if(i == alarms.v_alarm.end()) + { +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + ostringstream err; + err << "Alarm " << *si << " not found" << ends; + Tango::Except::throw_exception( \ + (const char*)"Alarm not found!!", \ + err.str(), \ + (const char*)"Alarm::silence()", Tango::ERR); + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + } + + prepare_alarm_attr(); + try + { + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error pushing alarm change event err=" << e.errors[0].desc; + INFO_STREAM << __func__<<": " << err.str() << endl; + } + + /*----- PROTECTED REGION END -----*/ // Alarm::silence +} +//-------------------------------------------------------- +/** + * Command Modify related method + * Description: Modify an existing alarm. + * + * @param argin Alarm entry + */ +//-------------------------------------------------------- +void Alarm::modify(Tango::DevString argin) +{ + DEBUG_STREAM << "Alarm::Modify() - " << device_name << endl; + /*----- PROTECTED REGION ID(Alarm::modify) ENABLED START -----*/ + + // Add your own code + //------------------------------ + //1: parse to get alarm name + //------------------------------ + string alarm_string(argin); + alarm_t alm; + alarm_parse al_gr(alm); // Construct Spirit grammar + alm.name.clear(); + alm.formula.clear(); + alm.msg.clear(); + alm.lev.clear(); + alm.grp=0; + alm.to_be_evaluated = false; + alm.time_threshold = 0; + alm.silent_time = -1; + alm.silenced = -1; + alm.cmd_name_a.clear(); + alm.cmd_dp_a.clear(); + alm.cmd_action_a.clear(); + alm.send_arg_a = false; + alm.dp_a = NULL; + alm.cmd_name_n.clear(); + alm.cmd_dp_n.clear(); + alm.cmd_action_n.clear(); + alm.send_arg_n = false; + alm.dp_n = NULL; + +#ifndef _ACCESS_NODE_D + alm.formula_tree = ast_parse(alarm_string.c_str(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces +#else + alm.formula_tree = + //boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp = + ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces +#endif + if (alm.formula_tree.full) + { + std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower); //transform to lowercase + //std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower); //transform to lowercase: incorrect, state has to be written upercase + std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower); //transform to lowercase + + if(alm.cmd_name_a.length() > 0) + { + const char *c = alm.cmd_name_a.c_str(); + int j = 0; + while (*c) { + if (*c == '/') + j++; + if (j < 3) + alm.cmd_dp_a.push_back(*c); + else if (*c != '/') + alm.cmd_action_a.push_back(*c); + c++; + } + } + if(alm.cmd_name_n.length() > 0) + { + const char *c = alm.cmd_name_n.c_str(); + int j = 0; + while (*c) { + if (*c == '/') + j++; + if (j < 3) + alm.cmd_dp_n.push_back(*c); + else if (*c != '/') + alm.cmd_action_n.push_back(*c); + c++; + } + } + + } + else + { + ostringstream o; +#ifndef _ACCESS_NODE_D + o << __func__<<": Parsing Failed, syntax error stopped at " << alm.formula_tree.stop << ends; +#else + o << __func__<<": Parsing Failed, syntax error stopped at " << string(alm.formula_tree.stop, alarm_string.end()) << ends; //TODO +#endif + DEBUG_STREAM << o.str() << endl; + Tango::Except::throw_exception( \ + (const char*)"Parsing Failed!", \ + (const char*)o.str().c_str(), \ + (const char*)__func__, Tango::ERR); + } + + + //------------------------------ + //2: if alarm already exist and + // formula is not changed + //------------------------------ +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->writerIn(); +#endif + alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); + if (i != alarms.v_alarm.end()) + { + if(i->second.formula == alm.formula) + { + Tango::TimeVal ts = gettime(); + string cmd_name_full = alm.cmd_name_a + string(";") + alm.cmd_name_n; + + if ((alm.name.empty() == false) && \ + (alm.formula.empty() == false) && \ + ((alm.lev==LEV_LOG)||(alm.lev==LEV_WARNING)|| \ + (alm.lev==LEV_FAULT)||(alm.lev.empty() == true))) { + i->second.stat = S_NORMAL; + i->second.ack = ACK; + i->second.done = false; + + i->second.msg = alm.msg; + i->second.lev = alm.lev; + i->second.grp = alm.grp; + //i->second.to_be_evaluated = alm.to_be_evaluated; + i->second.time_threshold = alm.time_threshold; + i->second.silent_time = alm.silent_time; + i->second.silenced = alm.silenced; + i->second.cmd_name_a = alm.cmd_name_a; + i->second.cmd_dp_a = alm.cmd_dp_a; + i->second.cmd_action_a = alm.cmd_action_a; + //i->second.send_arg_a = alm.send_arg_a; + i->second.cmd_name_n = alm.cmd_name_n; + i->second.cmd_dp_n = alm.cmd_dp_n; + i->second.cmd_action_n = alm.cmd_action_n; + //i->second.send_arg_n = alm.send_arg_n; + + } else { + ostringstream o; + o << __func__<<": syntax error in '" << alarm_string << "'" << ends; + WARN_STREAM << o.str() << endl; +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + Tango::Except::throw_exception( \ + (const char*)o.str().c_str(), \ + (const char*)"", \ + (const char*)__func__, Tango::ERR); + } + + + alarms.log_alarm_db(TYPE_LOG_DESC_UPDATE, ts, alm.name, "", "", + alm.formula, alm.time_threshold, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time); + + //delete proxy for actions + if(i->second.dp_a) + delete i->second.dp_a; + i->second.dp_a = NULL; + if(i->second.dp_n) + delete i->second.dp_n; + i->second.dp_n = NULL; + + if(alm.cmd_name_a.length() > 0) + { + try { + i->second.dp_a = new Tango::DeviceProxy(i->second.cmd_dp_a); + i->second.dp_a->ping(); + Tango::CommandInfo info = i->second.dp_a->command_query(i->second.cmd_action_a); + if(info.in_type != Tango::DEV_STRING) + { + ostringstream err; + err << "Error: command " << i->second.cmd_name_a << " does not accept a Tango::DevString as input value" << ends; + ERROR_STREAM << __func__<<": " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + else + { + if(info.in_type == Tango::DEV_STRING) + i->second.send_arg_a = true; + else + i->second.send_arg_a = false; + DEBUG_STREAM << __func__<<": successfully connected to proxy=" << i->second.cmd_dp_a << " for action=" << i->second.cmd_action_a << endl; + } + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_a << ", err=" << e.errors[0].desc << ends; + WARN_STREAM << __func__<<": " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + } + if(alm.cmd_name_n.length() > 0) + { + try { + i->second.dp_n = new Tango::DeviceProxy(i->second.cmd_dp_n); + i->second.dp_n->ping(); + Tango::CommandInfo info = i->second.dp_n->command_query(i->second.cmd_action_a); + if(info.in_type != Tango::DEV_STRING) + { + ostringstream err; + err << "Error: command " << i->second.cmd_name_n << " does not accept a Tango::DevString as input value" << ends; + ERROR_STREAM << __func__<<": " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + else + { + if(info.in_type == Tango::DEV_STRING) + i->second.send_arg_n = true; + else + i->second.send_arg_n = false; + DEBUG_STREAM << __func__<<": successfully connected to proxy=" << i->second.cmd_dp_n << " for action=" << i->second.cmd_action_n << endl; + } + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_n << ", err=" << e.errors[0].desc << ends; + WARN_STREAM << __func__<<": " << err.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), err.str()); + } + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + return; + } + } + else + { +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + ostringstream o; + o << "Alarm '"<<alm.name<<"' not found" << ends; + DEBUG_STREAM << o.str() << endl; + Tango::Except::throw_exception( \ + (const char*)"Not found", \ + (const char*)o.str().c_str(), \ + (const char*)__func__, Tango::ERR); + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + + //------------------------------ + //3: remove (set active=0 on db) + //------------------------------ + remove((Tango::DevString)alm.name.c_str()); + //------------------------------ + //4: load modified alarm + //------------------------------ + load(argin); + + prepare_alarm_attr(); + try + { + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error pushing alarm change event err=" << e.errors[0].desc; + INFO_STREAM << __func__<<": " << err.str() << endl; + } + + /*----- PROTECTED REGION END -----*/ // Alarm::modify +} +//-------------------------------------------------------- +/** + * Method : Alarm::add_dynamic_commands() + * Description : Create the dynamic commands if any + * for specified device. + */ +//-------------------------------------------------------- +void Alarm::add_dynamic_commands() +{ + /*----- PROTECTED REGION ID(Alarm::add_dynamic_commands) ENABLED START -----*/ + + // Add your own code to create and add dynamic commands if any + + /*----- PROTECTED REGION END -----*/ // Alarm::add_dynamic_commands +} + +/*----- PROTECTED REGION ID(Alarm::namespace_ending) ENABLED START -----*/ + +// Additional Methods +/* + * private methods + */ +void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn) +{ + DEBUG_STREAM << "Alarm::load_alarm(): Creating Spirit Parser..." << endl; + alarm_parse al_gr(alm); // Construct Spirit grammar + alm.name.clear(); + alm.formula.clear(); + alm.msg.clear(); + alm.lev.clear(); + alm.grp=0; + alm.to_be_evaluated = false; + alm.time_threshold = 0; + alm.silent_time = -1; + alm.silenced = -1; + alm.cmd_name_a.clear(); + alm.cmd_dp_a.clear(); + alm.cmd_action_a.clear(); + alm.send_arg_a = false; + alm.dp_a = NULL; + alm.cmd_name_n.clear(); + alm.cmd_dp_n.clear(); + alm.cmd_action_n.clear(); + alm.send_arg_n = false; + alm.dp_n = NULL; + evn.clear(); + +#ifndef _ACCESS_NODE_D + alm.formula_tree = ast_parse(alarm_string.c_str(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces +#else + alm.formula_tree = + //boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp = + ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces +#endif + if (alm.formula_tree.full) + { + std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower); //transform to lowercase + //std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower); //transform to lowercase: incorrect, state has to be written uppercase + std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower); //transform to lowercase + + if(alm.cmd_name_a.length() > 0) + { + const char *c = alm.cmd_name_a.c_str(); + int j = 0; + while (*c) { + if (*c == '/') + j++; + if (j < 3) + alm.cmd_dp_a.push_back(*c); + else if (*c != '/') + alm.cmd_action_a.push_back(*c); + c++; + } + } + if(alm.cmd_name_n.length() > 0) + { + const char *c = alm.cmd_name_n.c_str(); + int j = 0; + while (*c) { + if (*c == '/') + j++; + if (j < 3) + alm.cmd_dp_n.push_back(*c); + else if (*c != '/') + alm.cmd_action_n.push_back(*c); + c++; + } + } + + alm.silenced = (alm.silent_time > 0) ? 0 : -1; //0: can be silenced, -1: cannot be silenced + + DEBUG_STREAM << "Parsing succeeded! ->" << alm.name << endl; + find_event_formula(alm.formula_tree,evn); //populate event list found in this formula + ostringstream dbg_msg; + dbg_msg << "In " << alm.name << " Event ="; + for (vector<string>::iterator i = evn.begin(); i != evn.end(); i++) + dbg_msg << *i << ", "; + dbg_msg << ends; + DEBUG_STREAM << dbg_msg.str() << endl; + } + else + { + ostringstream o; +#ifndef _ACCESS_NODE_D + o << "Alarm::load_alarm(): Parsing Failed, syntax error stopped at " << alm.formula_tree.stop << ends; +#else + o << "Alarm::load_alarm(): Parsing Failed, syntax error stopped at " << string(alm.formula_tree.stop, alarm_string.end()) << ends; //TODO +#endif + DEBUG_STREAM << o.str() << endl; + Tango::Except::throw_exception( \ + (const char*)"Parsing Failed!", \ + (const char*)o.str().c_str(), \ + (const char*)"Alarm::load()", Tango::ERR); + } + alm.ts = gettime(); + DEBUG_STREAM << "Alarm::load_alarm(): name = '" << alm.name << "'" << endl; + DEBUG_STREAM << " formula = '" << alm.formula << "'" << endl; + DEBUG_STREAM << " time_threshold = '" << alm.time_threshold << "'" << endl; + DEBUG_STREAM << " msg = '" << alm.msg << "'" << endl; + DEBUG_STREAM << " grp = '" << showbase << hex << alm.grp << "'=" << alm.grp2str() << endl; + DEBUG_STREAM << " silent_time = '" << alm.silent_time << "'" << endl; + DEBUG_STREAM << " silenced = '" << alm.silenced << "'" << endl; + DEBUG_STREAM << " lev = '" << alm.lev << "'" << endl; + DEBUG_STREAM << " action_a = '" << alm.cmd_name_a << "'" << endl; + DEBUG_STREAM << " action_n = '" << alm.cmd_name_n << "'" << endl; + if ((alm.name.empty() == false) && \ + (alm.formula.empty() == false) && \ + ((alm.lev==LEV_LOG)||(alm.lev==LEV_WARNING)|| \ + (alm.lev==LEV_FAULT)||(alm.lev.empty() == true))) { + alm.stat = S_NORMAL; + alm.ack = ACK; + alm.done = false; +// alm.grp = GR_DEFAULT; +// alm.lev = LEV_DEFAULT; + } else { + ostringstream o; + o << "Alarm::load_alarm(): syntax error in '" << alarm_string << "'" << ends; + WARN_STREAM << o.str() << endl; + + Tango::Except::throw_exception( \ + (const char*)o.str().c_str(), \ + (const char*)"", \ + (const char*)"Alarm::load_alarm()", Tango::ERR); + } + + if (alarms.exist(alm.name)) { + ostringstream o; + o << "Alarm::load_alarm(): alarm '" << alm.name << "' already exist" << ends; + WARN_STREAM << o.str() << endl; + Tango::Except::throw_exception( \ + (const char*)o.str().c_str(), \ + (const char*)o.str().c_str(), \ + (const char*)"Alarm::load_alarm()", Tango::ERR); + } +} +void Alarm::init_alarms(map< string,vector<string> > &alarm_events) +{ +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + if (alarms.v_alarm.empty() == false) + { + for (alarm_container_t::iterator i = alarms.v_alarm.begin(); \ + i != alarms.v_alarm.end(); i++) + { + map< string,vector<string> >::iterator f = //looking in map for alarm name as key +// find(alarm_events->begin(), alarm_events->end(), i->name); + alarm_events.find(i->second.name); + if(f == alarm_events.end()) + continue; //ERROR: alarm not found in alarm_event map + DEBUG_STREAM << "Alarm::init_alarms(): found Alarm= " << i->second.name << endl; + for(vector<string>::iterator j = f->second.begin(); \ + j != f->second.end(); j++) + { + vector<event>::iterator found = \ + find(events->v_event.begin(), events->v_event.end(), (*j)); + DEBUG_STREAM << "Alarm::init_alarms(): looking in events table for Event= " << (*j) << endl; + if (found != events->v_event.end()) + { + i->second.insert(found->name); + found->push_alarm(i->second.name); + DEBUG_STREAM << "Alarm::init_alarms(): found Event= " << found->name << " <- Alarm= " << i->second.name << endl; + //break; ??? + } /* if */ + } /* for */ + } + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif +} +void Alarm::init_events(vector<string> &evn) +{ + if (evn.empty() == false) { + sort(evn.begin(), evn.end()); + vector<string>::iterator new_end = \ + unique(evn.begin(), evn.end()); + while (evn.end() != new_end) { + evn.pop_back(); + } + vector<string>::iterator j = evn.begin(); + while (j != evn.end()) { + events->push_back(event(*j)); + j++; + } + } /* if */ +} +void Alarm::add_alarm(alarm_t& a) throw(string&) +{ + alarms.push_back(a); + DEBUG_STREAM << "Alarm::add_alarm(): added alarm '" \ + << a.name << "'" << endl; +} +void Alarm::add_event(alarm_t& a, vector<string> &evn) throw(string&) +{ + DEBUG_STREAM << "Alarm::add_event(): formula '" << a.formula << "'" << endl; + /* + * get the list of all the events in the formula + */ + for (vector<string>::iterator j = evn.begin(); j != evn.end(); j++) { + vector<event>::iterator k = \ + find(events->v_event.begin(), events->v_event.end(), *j); + if (k != events->v_event.end()) { + /* + * the event already exist; push alarm name + * into the per-event alarm list + */ + k->push_alarm(a.name); + a.to_be_evaluated = true; + DEBUG_STREAM << "Alarm::add_event(): '" << *j << "' found, added " \ + << " alarm '" << a.name << "' to list, valid=" << k->valid << endl; +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + alarm_container_t::iterator l = alarms.v_alarm.find(a.name); + if (l != alarms.v_alarm.end()) + { + l->second.insert(*j); //insert event name in set<string> (s_event) in alarm_t + } + else + { + WARN_STREAM << "Alarm::add_event(): error inserting event '" << *j << "' in set of alarm '" + << a.name << "'" << endl; + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + } + else + { + /* + * new event; add to event table + */ + event e(*j); + events->push_back(e); + /* + * update per-alarm event list + */ + DEBUG_STREAM << "Alarm::add_event(): adding '" << *j \ + << "' to event list of alarm '" << a.name << "'" << endl; +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + alarm_container_t::iterator l = alarms.v_alarm.find(a.name); + if (l != alarms.v_alarm.end()) + { + l->second.insert(*j); //insert event name in set<string> in alarm_t + } + else + { + WARN_STREAM << "Alarm::add_event(): error inserting event '" << *j << "' in set of alarm '" + << a.name << "'" << endl; + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + /* + * now, for the just-added event, subscribe + */ + k = find(events->v_event.begin(), events->v_event.end(), *j); + if (k != events->v_event.end()) + { + k->push_alarm(a.name); + try { + k->dp = new Tango::DeviceProxy(k->device); + } catch(Tango::DevFailed& e) + { + TangoSys_MemStream out_stream; + out_stream << "Failed to connect device proxy=" << k->device << ends; + k->pop_alarm(a.name); //remove alarm/formula just added to event + //events->v_event.pop_back(); + events->v_event.erase(k); //remove event just added to event_table + throw out_stream.str(); + /*Tango::Except::re_throw_exception(e, + (const char *) "Error writing serial", + out_stream.str(), + (const char *) "Alarm::add_event()", Tango::ERR);*/ + } + DEBUG_STREAM << "Alarm::add_event(): connected to DeviceProxy: " \ + << k->device << endl; + //now initialize value of this attribute + try { + Tango::DeviceAttribute attr_value; + attr_value = k->dp->read_attribute(k->attribute); + ecb.extract_values(&attr_value, k->value, k->type); + k->valid = true; + ostringstream msg; + msg << "Alarm::add_event(): initial values of " << k->name << " = "; + for(vector<double>::iterator dd=k->value.begin(); dd!=k->value.end(); dd++) + msg << (*dd) << " "; + msg << ", valid=" << k->valid << ends; + DEBUG_STREAM << msg.str() << endl; + //delete attr_value; + } catch(Tango::DevFailed& e) + { + TangoSys_MemStream out_stream; + out_stream << "Failed to read initial value of " << k->name << " = " << e.errors[0].desc << ends; + k->valid = false; +#if TANGO_VER < 611 //if using subscribe stateless, alarm is not removed if it fails the subscription + k->pop_alarm(a.name); //remove alarm/formula just added to event + //events->v_event.pop_back(); + events->v_event.erase(k); //remove event just added to event_table + //delete attr_value; +#endif + throw out_stream.str(); + } catch(string & e) + { + TangoSys_MemStream out_stream; + out_stream << "Error reading initial value of " << k->name << " = " << e << ends; + k->pop_alarm(a.name); //remove alarm/formula just added to event + //events->v_event.pop_back(); + events->v_event.erase(k); //remove event just added to event_table + //delete attr_value; + throw out_stream.str(); + } + } + } + } //for (vector<string>::iterator j = evn.begin(); ... +} +void Alarm::subscribe_event(alarm_t& a, EventCallBack& ecb, vector<string> &evn) throw(string&) +{ + //now subscribe all events + for (vector<string>::iterator j = evn.begin(); j != evn.end(); j++) + { + vector<event>::iterator k = \ + find(events->v_event.begin(), events->v_event.end(), *j); + if (k != events->v_event.end()) + { + if(k->eid == 0) //not subscribed yet + { + try { +#if TANGO_VER < 611 + k->eid = k->dp->subscribe_event(k->attribute, \ + Tango::CHANGE_EVENT, \ + &ecb, k->filter); +#else + k->eid = k->dp->subscribe_event(k->attribute, \ + Tango::CHANGE_EVENT, \ + &ecb, k->filter,true); //stateless subscription (doesn't fail if server not running) +#endif + DEBUG_STREAM << "Alarm::add_event(): subscribed event for '" \ + << k->attribute << "' attribute" << endl; + } catch (...) { + ostringstream o; + o << "Alarm::add_event(): subscribe_event() failed for '" \ + << *j << "'" << ends; + WARN_STREAM << o.str() << endl; + k->pop_alarm(a.name); //remove alarm/formula just added to event + //events->v_event.pop_back(); + events->v_event.erase(k); //remove event just added to event_table + delete k->dp; + k->dp = NULL; + throw o.str(); + } + } + } // if (k != events->v_event.end())/ + } // for +} +/* + * because called asynchronously by alarm evaluating thread + * will use an alarm to report errors + */ +void Alarm::do_alarm(bei_t& e) +{ + bool changed=true; + //if (e.name == INTERNAL_ERROR) { + if(e.type == TYPE_TANGO_ERR) { + ostringstream o; + o << e.msg << endl; + WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl; + vector<event>::iterator found_ev = \ + find(events->v_event.begin(), events->v_event.end(), e.ev_name); + if (found_ev == events->v_event.end()) + { + //try to remove network domain and FQDN + string ev_name_str(e.ev_name); + string::size_type pos_slash = ev_name_str.find("tango://"); + if (pos_slash != string::npos) //FQDN!! + { + //first remove network domain if any + string::size_type pos_dot = ev_name_str.find(".",8); //look for first . after tango:// + string::size_type pos_colon = ev_name_str.find(":",8); //look for first : after tango:// + pos_slash = ev_name_str.find('/',8); //look for first / after tango:// + if(pos_dot < pos_slash && pos_dot != string::npos && pos_colon != string::npos && pos_slash != string::npos) //dot is in the TANGO_HOST part + { + string ev_name_str_no_domain = ev_name_str.substr(0,pos_dot) + ev_name_str.substr(pos_colon); + DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without domain: " << ev_name_str_no_domain; + found_ev = \ + find(events->v_event.begin(), events->v_event.end(), ev_name_str_no_domain); + } + if (found_ev == events->v_event.end() && pos_slash != string::npos) + { + ev_name_str = ev_name_str.substr(pos_slash + 1);//remove FQDN + DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without fqdn: " << ev_name_str; + found_ev = \ + find(events->v_event.begin(), events->v_event.end(), ev_name_str); + } + } + + if (found_ev == events->v_event.end()) + { + /* + * shouldn't happen!!! + */ + ostringstream o; + o << "TANGO Error but event '" \ + << e.ev_name << "' not found in event table!" << ends; + WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl; + set_internal_alarm(e.ev_name, gettime(), o.str()); + } + } + if(found_ev != events->v_event.end()) + { + found_ev->err_counter++; + if(found_ev->err_counter >= errThreshold) + set_internal_alarm(e.ev_name, gettime(), o.str(), errThreshold); + } + return; + } + else if(e.type == TYPE_GENERIC_ERR) { + ostringstream o; + o << e.msg << endl; + WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl; + set_internal_alarm(e.ev_name, gettime(), o.str()); + return; + } + DEBUG_STREAM << "Alarm::do_alarm(): arrived event=" << e.ev_name << endl; + + double res; + vector<event>::iterator found = \ + find(events->v_event.begin(), events->v_event.end(), e.ev_name); + if (found == events->v_event.end()) + { + //try to remove network domain and FQDN + string ev_name_str(e.ev_name); + string::size_type pos_slash = ev_name_str.find("tango://"); + if (pos_slash != string::npos) //FQDN!! + { + //first remove network domain if any + string::size_type pos_dot = ev_name_str.find(".",8); //look for first . after tango:// + string::size_type pos_colon = ev_name_str.find(":",8); //look for first : after tango:// + pos_slash = ev_name_str.find('/',8); //look for first / after tango:// + if(pos_dot < pos_slash && pos_dot != string::npos && pos_colon != string::npos && pos_slash != string::npos) //dot is in the TANGO_HOST part + { + string ev_name_str_no_domain = ev_name_str.substr(0,pos_dot) + ev_name_str.substr(pos_colon); + DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without domain: " << ev_name_str_no_domain; + found = \ + find(events->v_event.begin(), events->v_event.end(), ev_name_str_no_domain); + } + if (found == events->v_event.end() && pos_slash != string::npos) + { + ev_name_str = ev_name_str.substr(pos_slash + 1);//remove FQDN + DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without fqdn: " << ev_name_str; + found = \ + find(events->v_event.begin(), events->v_event.end(), ev_name_str); + } + } + + if (found == events->v_event.end()) + { + /* + * shouldn't happen!!! + */ + ostringstream o; + o << "event '" \ + << e.ev_name << "' not found in event table!" << ends; + WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } + } + if (found != events->v_event.end()) + { + found->value = e.value; + found->valid = true; + found->ts = e.ts; + found->type = e.type; + found->err_counter = 0; + vector<string>::iterator j = found->m_alarm.begin(); + while (j != found->m_alarm.end()) + { + //alarm_container_t::iterator it = alarms.v_alarm.find(j->first); +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + alarm_container_t::iterator it = alarms.v_alarm.find(*j); + if(it != alarms.v_alarm.end()) + { + string tmpname=it->first; + try { + string attr_values; + res = eval_formula(it->second.formula_tree, attr_values); + DEBUG_STREAM << "Alarm::do_alarm(): Evaluation of " << it->second.formula << "; result=" << res << endl; +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + changed = alarms.update(tmpname, found->ts, (int)res, attr_values, it->second.grp2str(), it->second.msg, it->second.formula); //update internal structure and log to db + } catch(std::out_of_range& e) + { +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + ostringstream o; + o << tmpname << ": in formula array index out of range!" << ends; + WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } catch(string & e) + { +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + ostringstream o; + o << tmpname << ": in formula err=" << e << ends; + WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } + } + else + { +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + ostringstream o; + //o << j->first << ": not found formula in alarm table" << ends; + o << (*j) << ": not found formula in alarm table" << ends; + WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } + j++; + } + + //TODO: push_change_event HERE! + prepare_alarm_attr(); + if(!changed) + return; + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + + } +} /* do_alarm() */ + +void Alarm::timer_update() +{ + bool changed=true; + //DEBUG_STREAM << "Alarm::timer_update(): entering..." << endl; + try { + changed=alarms.timer_update(); + } catch(string & e) + { + ostringstream o; + o << "Error checking time thresholds and updating alarm status=" << e << ends; + WARN_STREAM << "Alarm::timer_update(): " << o.str() << endl; + set_internal_alarm(INTERNAL_ERROR, gettime(), o.str()); + } + + prepare_alarm_attr(); + if(!changed) + return; + try + { + if(ds_num == 0) + { + //attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false); + struct timeval now; + gettimeofday(&now,NULL); + push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false); + } + else + //attr.set_value(ds, ds_num, 0, false); + push_change_event("alarm",ds, ds_num, 0, false); + } catch(Tango::DevFailed& e) + { + ostringstream err; + err << "error pushing alarm change event err=" << e.errors[0].desc; + INFO_STREAM << __func__<<": " << err.str() << endl; + } +} + +bool Alarm::remove_alarm(string& s) throw(string&) +{ +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->writerIn(); +#endif + alarm_container_t::iterator i = alarms.v_alarm.find(s); + if (i != alarms.v_alarm.end()) { + for (set<string>::iterator j = i->second.s_event.begin(); \ + j != i->second.s_event.end(); j++) { + /* + * for each event into the per-alarm event list find + * the event table entry and remove this alarm from + * per-event alarm list + */ + vector<event>::iterator k = \ + find(events->v_event.begin(), events->v_event.end(), *j); + if (k != events->v_event.end()) { + /* + * remove alarm + */ + k->pop_alarm(i->second.name); + if (k->m_alarm.empty()) { + /* + * no more alarms associated to this event, unsubscribe + * and remove from event table + */ + DEBUG_STREAM << "Alarm::remove_alarm(): removing event '" \ + << k->name << "' from event table" << endl; + try { + k->dp->unsubscribe_event(k->eid); + } catch (...) { + ostringstream o; + o << "unsubscribe_event() failed for " \ + << k->name << ends; + WARN_STREAM << "Alarm::remove_alarm(): " << o.str() << endl; +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + throw o.str(); + //return false; + } + delete k->dp; + k->dp = NULL; + events->v_event.erase(k); + } + } else { + /* + * shouldn't happen!!! + */ + ostringstream o; + o << "event '" << *j \ + << "' not found in event table" << ends; + WARN_STREAM << "Alarm::remove_alarm(): " << o.str() << endl; +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + throw o.str(); + //return false; + } + } /* for */ + //delete proxy for actions + if(i->second.dp_a) + delete i->second.dp_a; + i->second.dp_a = NULL; + if(i->second.dp_n) + delete i->second.dp_n; + i->second.dp_n = NULL; + /* + * remove this alarm from alarm table + */ +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + alarms.erase(i); + return true; + } +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->writerOut(); +#endif + ostringstream o; + o << "alarm '" \ + << s << "' not found in alarm table" << ends; + WARN_STREAM << "Alarm::remove_alarm(): " << o.str() << endl; + throw o.str(); + //return false; +} /* remove_alarm() */ + + +/*void Alarm::add_to_database(alarm_t& a) throw(string&) +{ + Tango::DbDatum alarm("alarm"); + Tango::DbData db_data; + + alarm << (short)1; + db_data.push_back(alarm); + string tmpname; + tmpname = a.name; + while (true) { + string::size_type j = tmpname.find_first_of("/."); + if (j == string::npos) + break; + tmpname.replace(j, 1, "_"); + } + Tango::DbDatum property(tmpname); + ostringstream num; + num.clear(); + num << a.grp << ends; +// sprintf(buf, "%02X-", buf2[j]);//change here the format of saved data +// string pro = a.name+"\t"+"$"+a.formula+"$"+"\t"+"\""+a.msg+"\""+"\t"+num.str(); + //DEBUG_STREAM << "Alarm::add_to_database(): a.name=" << a.name << " a.formula=" << a.formula << " a.lev=" << a.lev << " a.grp=" << a.grp2str() << " a.msg=" << a.msg << endl; + string pro = a.name+"\t"+a.formula+"\t"+string(a.time_threshold)+"\t"+ a.lev+"\t"+a.grp2str()+"\t"+"\""+a.msg+"\""+"\t"+a.cmd_name+"\t"; //grp has been transformed to string + DEBUG_STREAM << "Alarm::add_to_database(): adding to database property=" << pro << endl; + property << pro; + db_data.push_back(property); + try { + get_db_device()->put_attribute_property(db_data); + } catch (...) { + ostringstream o; + o << "Alarm::add_to_database(): put_device_attribute_property()" \ + << " failed" << ends; + ERROR_STREAM << o.str() << endl; + throw o.str(); + } +}*/ + +void Alarm::set_internal_alarm(string name, Tango::TimeVal t, string msg, unsigned int count) +{ + alarm_t alm; + bool existing=false; + ostringstream o; + //o << (internal.size() + 1); + if(internal.size() == 0) + internal_counter = 0; + o << internal_counter; + internallock->writerIn(); + vector<alarm_t>::iterator it; + for(it = internal.begin(); it != internal.end(); it++) + { + if(name == INTERNAL_ERROR) + { + if(it->msg == msg) + { + existing=true; + break; + } + } + else //for tango error log only one internal error per event + { + if(it->msg.find(name) != string::npos) + { + existing=true; + if(it->counter < count) + it->counter = count; + break; + } + } + } + if(existing) + { + /*size_t index; + int count; + index = it->stat.find("*"); + ostringstream temp; + if((index != std::string::npos) && (index+1 != std::string::npos)) + { + + size_t last = it->stat.size(); + string str_count= it->stat.substr(index+1, last - index+1); + count = strtol(str_count.c_str(), 0,10); + count++; + temp << it->stat.substr(0,index+1) << count; + it->stat = temp.str(); + } + else + it->stat += "*2";*/ + it->counter++; + it->msg = msg; //update with the last message + } + else + { + alm.name = string(INTERNAL_ERROR) + "_" + o.str(); + internal_counter++; + alm.ts = t; + /*ostringstream stat; + if(count==0) + stat << S_ALARM; + else + stat << S_ALARM << "*" << count;*/ + alm.counter = count; + //alm.stat = stat.str(); + alm.stat = S_ALARM; + alm.ack = NOT_ACK; + alm.done = false; + alm.msg = msg; + //alm.grp = GR_DEFAULT; + if(!alm.grp_str.empty()) + alm.grp = (alm.grp_str.begin())->second; //set groupe 'none' to internal alarms + else + alm.grp = GR_DEFAULT; + //alm.lev = LEV_DEFAULT; + alm.lev = LEV_LOG; + internal.push_back(alm); + } + internallock->writerOut(); +} + +//============================================================== +//------------------- AST evaluation methods ------------------- +//============================================================== +double Alarm::eval_formula(tree_parse_info_t tree, string &attr_values) +{ + return eval_expression(tree.trees.begin(), attr_values); +} + +double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind) //throw (string &), std::out_of_range +{ + + ostringstream err; + err << "Evaluating formula: "; + //iter_t it = i->children.begin(); + + if (i->value.id() == formula_grammar::val_rID) + { + if(i->children.size() != 0) + { + err << "in node val_rID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + string val_d(i->value.begin(), i->value.end()); + DEBUG_STREAM << " node value real = " << val_d << endl; + return strtod(val_d.c_str(), 0); + } + else if (i->value.id() == formula_grammar::val_hID) + { + if(i->children.size() != 0) + { + err << "in node val_hID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + string val_d(i->value.begin(), i->value.end()); + DEBUG_STREAM << " node value hex = " << val_d << endl; + return strtod(val_d.c_str(), 0); + } + else if (i->value.id() == formula_grammar::val_stID) + { + if(i->children.size() != 0) + { + err << "in node val_stID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + string val_st(i->value.begin(), i->value.end()); +#ifndef _ACCESS_NODE_D + Tango::DevState st; + if(val_st == "ON") + st = Tango::ON; + else if(val_st == "OFF") + st = Tango::OFF; + else if(val_st == "CLOSE") + st = Tango::CLOSE; + else if(val_st == "OPEN") + st = Tango::OPEN; + else if(val_st == "INSERT") + st = Tango::INSERT; + else if(val_st == "EXTRACT") + st = Tango::EXTRACT; + else if(val_st == "MOVING") + st = Tango::MOVING; + else if(val_st == "STANDBY") + st = Tango::STANDBY; + else if(val_st == "FAULT") + st = Tango::FAULT; + else if(val_st == "INIT") + st = Tango::INIT; + else if(val_st == "RUNNING") + st = Tango::RUNNING; + else if(val_st == "ALARM") + st = Tango::ALARM; + else if(val_st == "DISABLE") + st = Tango::DISABLE; + else if(val_st == "UNKNOWN") + st = Tango::UNKNOWN; +#else + double st = i->value.value(); //get value directly from node saved with access_node_d +#endif //_ACCESS_NODE_D + DEBUG_STREAM << " node value state : " << val_st << "=" << st << endl; + return st; + } + else if (i->value.id() == formula_grammar::unary_exprID) + { + DEBUG_STREAM << " node unary expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 1) + { + err << "in node unary_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + if (*i->value.begin() == '+') + return + eval_expression(i->children.begin(), attr_values); + if (*i->value.begin() == '-') + return - eval_expression(i->children.begin(), attr_values); + if (*i->value.begin() == '!') + return ! eval_expression(i->children.begin(), attr_values); + } + else if (i->value.id() == formula_grammar::mult_exprID) + { + DEBUG_STREAM << " node mult expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 2) + { + err << "in node mult_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + if (*i->value.begin() == '*') + { + return eval_expression(i->children.begin(), attr_values) * + eval_expression(i->children.begin()+1, attr_values); + } + else if (*i->value.begin() == '/') + { + return eval_expression(i->children.begin(), attr_values) / + eval_expression(i->children.begin()+1, attr_values); + } + else + { + err << "in node mult_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::add_exprID) + { + DEBUG_STREAM << " node add expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 2) + { + err << "in node add_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + if (*i->value.begin() == '+') + { + return eval_expression(i->children.begin(), attr_values) + + eval_expression(i->children.begin()+1, attr_values); + } + else if (*i->value.begin() == '-') + { + return eval_expression(i->children.begin(), attr_values) - + eval_expression(i->children.begin()+1, attr_values); + } + else + { + err << "in node add_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::event_ID) + { + DEBUG_STREAM << " node event" << string(i->value.begin(), i->value.end()) << endl; + int ind; + if(i->children.size() != 2) + { + err << "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;; + throw err.str(); + } + if((i->children.begin()+1)->value.id() == formula_grammar::indexID) + ind = (int)eval_expression(i->children.begin()+1, attr_values); //array index + else + { + err << "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children2 is not an index ->" << string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) << ends;; + throw err.str(); + } + return eval_expression(i->children.begin(), attr_values ,ind); + } + else if (i->value.id() == formula_grammar::nameID) + { + if(i->children.size() != 0) + { + err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + vector<event>::iterator it = events->v_event.begin(); + string s(i->value.begin(), i->value.end()); + std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase + while ((it != events->v_event.end()) && (it->name != s)) + it++; + if (it != events->v_event.end()) + { + if(!it->valid) + { + err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") value not valid!" << ends; + throw err.str(); + } + else if(it->value.empty()) + { + err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") value not initialized!!" << ends; + throw err.str(); + } + ostringstream temp_attr_val; + temp_attr_val << it->name << "[" << ev_ind << "]=" <<it->value.at(ev_ind) << ";"; + attr_values += temp_attr_val.str(); + DEBUG_STREAM << " node name -> " << temp_attr_val.str() << endl; + return it->value.at(ev_ind); //throw std::out_of_range + } + else + { + err << "in event: (" << string(i->value.begin(), i->value.end()) << ") not found in event table" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::indexID) + { + if(i->children.size() != 0) + { + err << "in node indexID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + string val_d(i->value.begin(), i->value.end()); + DEBUG_STREAM << " node index = " << val_d << endl; + return strtod(val_d.c_str(), 0); + } + else if (i->value.id() == formula_grammar::logical_exprID) + { + DEBUG_STREAM << " node logical expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 2) + { + err << "in node logical_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + if (string(i->value.begin(), i->value.end()) == string("&&")) + { + return eval_expression(i->children.begin(), attr_values) && + eval_expression(i->children.begin()+1, attr_values); + } + else if (string(i->value.begin(), i->value.end()) == string("||")) + { + return eval_expression(i->children.begin(), attr_values) || + eval_expression(i->children.begin()+1, attr_values); + } + else + { + err << "in node logical_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::bitwise_exprID) + { + DEBUG_STREAM << " node bitwise expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 2) + { + err << "in node bitwise_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + double val_d1=eval_expression(i->children.begin(), attr_values), + val_d2=eval_expression(i->children.begin()+1, attr_values); + long val_l1,val_l2; + + string err2("ERROR: non-int value in bitwise operation!"); + val_l1 = (long)trunc(val_d1); //transform to long + val_l2 = (long)trunc(val_d2); //transform to long + + if((val_l1 != val_d1) || (val_l2 != val_d2)) //if different, lost something with truncf + throw err2; + + if (*i->value.begin() == '&') + { + return (double)(val_l1 & val_l2); + } + else if (*i->value.begin() == '|') + { + return (double)(val_l1 | val_l2); + } + else if (*i->value.begin() == '^') + { + return (double)(val_l1 ^ val_l2); + } + else + { + err << "in node bitwise_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::shift_exprID) + { + DEBUG_STREAM << " node shift expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 2) + { + err << "in node shift_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + double val_d1=eval_expression(i->children.begin(), attr_values), + val_d2=eval_expression(i->children.begin()+1, attr_values); + long val_l1,val_l2; + + string err2("ERROR: non-int value in bitwise operation!"); + val_l1 = (long)trunc(val_d1); //transform to long + val_l2 = (long)trunc(val_d2); //transform to long + + if((val_l1 != val_d1) || (val_l2 != val_d2)) //if different, lost something with truncf + throw err2; + + if (string(i->value.begin(), i->value.end()) == string("<<")) + { + return (double)(val_l1 << val_l2); + } + else if (string(i->value.begin(), i->value.end()) == string(">>")) + { + return (double)(val_l1 >> val_l2); + } + else + { + err << "in node shift_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::equality_exprID) + { + DEBUG_STREAM << " node equality expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 2) + { + err << "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + if (string(i->value.begin(), i->value.end()) == string("!=")) + { + return eval_expression(i->children.begin(), attr_values) != + eval_expression(i->children.begin()+1, attr_values); + } + else if (string(i->value.begin(), i->value.end()) == string("==")) + { + return eval_expression(i->children.begin(), attr_values) == + eval_expression(i->children.begin()+1, attr_values); + } + else + { + err << "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::compare_exprID) + { + DEBUG_STREAM << " node compare expression: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 2) + { + err << "in node compare_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + if (string(i->value.begin(), i->value.end()) == string("<=")) + { + return eval_expression(i->children.begin(), attr_values) <= + eval_expression(i->children.begin()+1, attr_values); + } + else if (string(i->value.begin(), i->value.end()) == string(">=")) + { + return eval_expression(i->children.begin(), attr_values) >= + eval_expression(i->children.begin()+1, attr_values); + } + else if (*i->value.begin() == '<') + { + return eval_expression(i->children.begin(), attr_values) < + eval_expression(i->children.begin()+1, attr_values); + } + else if (*i->value.begin() == '>') + { + return eval_expression(i->children.begin(), attr_values) > + eval_expression(i->children.begin()+1, attr_values); + } + else + { + err << "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends; + throw err.str(); + } + } + else if (i->value.id() == formula_grammar::funcID) + { + DEBUG_STREAM << " node function: " << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 1) + { + err << "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + return fabs(eval_expression(i->children.begin(), attr_values)); //now handled only abs as function + } + else + { + DEBUG_STREAM << " node unknown id: " << string(i->value.begin(), i->value.end()) << endl; + { + err << "node unknown!! value=" << string(i->value.begin(), i->value.end()) << ends; + throw err.str(); + } + } + return 0; +} + +void Alarm::find_event_formula(tree_parse_info_t tree, vector<string> & ev) +{ + eval_node_event(tree.trees.begin(), ev); + return; +} + +void Alarm::eval_node_event(iter_t const& i, vector<string> & ev) +{ +/* DEBUG_STREAM << "In eval_node_event. i->value = " << + string(i->value.begin(), i->value.end()) << + " i->children.size() = " << i->children.size() << " NODE=" << rule_names[i->value.id()] << endl;*/ + ostringstream err; + err << "Looking for event in formula tree: "; + /*if (i->value.id() == formula_grammar::event_ID) + { + DEBUG_STREAM << "eval_node_event(): in eventID!!!=" << string(i->value.begin(), i->value.end()) << endl; + } + else*/ if (i->value.id() == formula_grammar::nameID) + { + DEBUG_STREAM << "eval_node_event(): find event name=" << string(i->value.begin(), i->value.end()) << endl; + if(i->children.size() != 0) + { + err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends; + throw err.str(); + } + string s(i->value.begin(), i->value.end()); + std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase + ev.push_back(s); + } + //cout << endl; + //iter_t it = i->children.begin(); + for(iter_t it = i->children.begin(); it != i->children.end(); it++) + eval_node_event(it, ev); + return; +} + + +void Alarm::prepare_alarm_attr() +{ + alarm_container_t::iterator ai; + vector<alarm_t>::iterator aid; +#ifndef _RW_LOCK + alarms.lock(); +#else + alarms.vlock->readerIn(); +#endif + for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) { + if (ai->second.stat == S_ALARM) { + /* + * alarm status is S_ALARM + */ + alarmedlock->readerIn(); + aid = find(alarmed.begin(), alarmed.end(),ai->second.name); + if (aid != alarmed.end()) { + /* + * found, change stat only if switching from + * S_NORMAL to S_ALARM status + */ + //cout << "read_attr(): S_ALARM: found: " << aid->name << endl; + if (aid->stat == S_NORMAL) { + aid->stat = S_ALARM; + aid->ack = NOT_ACK; + aid->ts = ai->second.ts; + aid->msg = ai->second.msg; + } + aid->grp = ai->second.grp; + aid->lev = ai->second.lev; + aid->is_new = ai->second.is_new; //copy is_new state + //ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0 + aid->counter = ai->second.counter; + aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset + aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary) + aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update + } else { + /* + * not found: new "alarmed" item + */ + DEBUG_STREAM << __func__<<": S_ALARM: pushing new alarm: " \ + << ai->second.name << "\t" << ai->second.stat << endl; + alarmedlock->readerOut(); + alarmedlock->writerIn(); + alarmed.push_back(ai->second); + //ai->second.is_new = 0; //set state as not more new //12-06-08: StopNew command set it to 0 + alarmedlock->writerOut(); + alarmedlock->readerIn(); + } + alarmedlock->readerOut(); + } else if (ai->second.stat == S_NORMAL) { + /* + * alarm status is S_NORMAL + */ + alarmedlock->readerIn(); + aid = find(alarmed.begin(), alarmed.end(), ai->second.name); + if (aid != alarmed.end()) { + /* + * found, as it should; + * switching from S_ALARM to S_NORMAL + */ + aid->stat = S_NORMAL; + aid->ts = ai->second.ts; + //aid->msg = " "; /* no message again */ + aid->msg =ai->second.msg; + aid->grp = ai->second.grp; + aid->lev = ai->second.lev; + aid->counter = ai->second.counter; + aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset + aid->is_new = ai->second.is_new; //copy is_new state + aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary) + aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update + //ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0 + if (aid->ack == ACK) { + if (aid->done) { + /* + * if already ACKnowledged and visualized + * remove from "alarmed" list + */ + DEBUG_STREAM << __func__<<": S_NORMAL: " << aid->name \ + << " ACKnowledged: removing" << endl; + alarmedlock->readerOut(); + alarmedlock->writerIn(); + alarmed.erase(aid); + alarmedlock->writerOut(); + alarmedlock->readerIn(); + } else { + aid->done = true; + } + } /* if */ + } /* if */ + alarmedlock->readerOut(); + } /* if else if */ + } /* for */ +#ifndef _RW_LOCK + alarms.unlock(); +#else + alarms.vlock->readerOut(); +#endif + + vector<string> tmp_alarm_table; + string is_new; + ostringstream os1; + /*os1.clear(); + os1 << header << "\t" << alarmed.size() << ends;*/ + //tmp_alarm_table.push_back(os1.str()); + alarmedlock->readerIn(); + if (alarmed.empty() == false) { + for (aid = alarmed.begin(); aid != alarmed.end(); aid++) { + if(aid->silenced > 0) + { + Tango::TimeVal now = gettime(); + double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000; + double dsilent = aid->ts_time_silenced.tv_sec + ((double)aid->ts_time_silenced.tv_usec) / 1000000; + double dminutes = (dnow - dsilent)/60; + //silenced already calculated in alarm_table::update, but here updated for panel also if state not changed: + //to see minutes countdown + if(dminutes < aid->silent_time) + aid->silenced = aid->silent_time - floor(dminutes); + else + aid->silenced = 0; + } + ostringstream os; + os.clear(); + is_new.clear(); + is_new = (aid->is_new && aid->silenced <= 0) ? "NEW" : " "; + os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \ + << aid->name << "\t" << aid->stat << "\t" << aid->ack \ + << "\t" << aid->counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new << ends; + tmp_alarm_table.push_back(os.str()); + } + } + alarmedlock->readerOut(); + internallock->readerIn(); + if (internal.empty() == false) { + for (aid = internal.begin(); aid != internal.end(); aid++) { + +/* size_t index; + int count = 1; + index = aid->stat.find("*"); + if((index != std::string::npos) && (index+1 != std::string::npos)) + { + + size_t last = aid->stat.size(); + string str_count= aid->stat.substr(index+1, last - index+1); + count = strtol(str_count.c_str(), 0,10); + } + //do not show internal alarms that have a molteplicity less then errThreshold + if((aid->msg.find()) && (count < errThreshold)) + continue;*/ + + ostringstream os; + os.clear(); + os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \ + << aid->name << "\t" << aid->stat << "\t" << aid->ack \ + << "\t" << aid->counter << "\t" << aid->lev << "\t"<< -1/*silenced*/ <<"\t" << aid->grp2str() << "\t" << aid->msg << "\t "<< ends; //TODO: silenced for internal errors? + tmp_alarm_table.push_back(os.str()); + } + } + internallock->readerOut(); + dslock->writerIn(); + int i; +// for (i = ds_num - 1; i >= 0; i--) { +// CORBA::string_free(ds[i]); +// //ds_num--; +// } +/* for (i = 0; i < ds_num; i++) { + if (ds[i] != 0) { + CORBA::string_free(ds[i]); + ds[i] = 0; + } + }*/ + ds_num = tmp_alarm_table.size(); + if(ds_num > MAX_ALARMS) + ds_num = MAX_ALARMS; + for (i = 0; i < ds_num; i++) { + //ds[i] = CORBA::string_dup(tmp_alarm_table[i].c_str()); + size_t len=tmp_alarm_table[i].length(); + if(len >= 10124) len = 10124-1; + strncpy(dss[i],tmp_alarm_table[i].c_str(), len); + dss[i][len]=0; + } + if(ds_num == 0) + { + ostringstream os1; + ds_num++; + os1.clear(); + os1 << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << -1 << "\t" << 0 << "\t" << 0 << "\t "<< ends; + //ds[0] = CORBA::string_dup(os1.str().c_str()); + size_t len=os1.str().length(); + if(len >= 10124) len = 10124-1; + strncpy(dss[i],os1.str().c_str(), len); + dss[i][len]=0; + } + dslock->writerOut(); +} + + +/*----- PROTECTED REGION END -----*/ // Alarm::namespace_ending +} // namespace diff --git a/src/Alarm.h b/src/Alarm.h new file mode 100644 index 0000000000000000000000000000000000000000..dd9c4d73fe3a907893c8b59e783a34dc51717c0a --- /dev/null +++ b/src/Alarm.h @@ -0,0 +1,337 @@ +/*----- PROTECTED REGION ID(Alarm.h) ENABLED START -----*/ +//============================================================================= +// +// file : Alarm.h +// +// description : Include file for the Alarm class +// +// project : alarm +// +// This file is part of Tango device class. +// +// Tango is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Tango is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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) +//============================================================================= + + +#ifndef Alarm_H +#define Alarm_H + +#include <tango.h> +#include <mysql.h> + +#include <boost/version.hpp> +#define _ACCESS_NODE_D 1 +#if BOOST_VERSION >= 103600 +#define BOOST_VER_1_36_0 1 +#endif + +#include "alarm_table.h" +#include "event_table.h" + +#define MAX_ALARMS 1024 + +#define _USE_ELETTRA_DB_RW + +//using namespace Tango; + +class alarm_thread; +class log_thread; +class update_thread; + + + +/*----- PROTECTED REGION END -----*/ // Alarm.h + +/** + * Alarm class description: + * Elettra alarm device server + */ + +namespace Alarm_ns +{ +/*----- PROTECTED REGION ID(Alarm::Additional Class Declarations) ENABLED START -----*/ + +// Additional Class Declarations + +/*----- PROTECTED REGION END -----*/ // Alarm::Additional Class Declarations + +class Alarm : public TANGO_BASE_CLASS +{ + +/*----- PROTECTED REGION ID(Alarm::Data Members) ENABLED START -----*/ + +// Add your own data members +public: + + +/*----- PROTECTED REGION END -----*/ // Alarm::Data Members + +// Device property data members +public: + // AlarmStatus: Persistent storage of the alarms status + vector<string> alarmStatus; + // GroupNames: Labels for Group mask, first is for mask 0x00 + vector<string> groupNames; + // ErrThreshold: Threshold for Tango error for being internal alarms + Tango::DevLong errThreshold; + // DbHost: Host of the MySQL db + string dbHost; + // DbUser: Username for the MySQL db + string dbUser; + // DbPasswd: Password for the MySQL db + string dbPasswd; + // DbName: Db name for the MySQL db + string dbName; + // DbPort: Port of the MySQL db + string dbPort; + // InstanceName: Name used to associate configured alarm rules to this instance + string instanceName; + +// Attribute data members +public: + Tango::DevString *attr_alarm_read; + +// Constructors and destructors +public: + /** + * Constructs a newly device object. + * + * @param cl Class. + * @param s Device Name + */ + Alarm(Tango::DeviceClass *cl,string &s); + /** + * Constructs a newly device object. + * + * @param cl Class. + * @param s Device Name + */ + Alarm(Tango::DeviceClass *cl,const char *s); + /** + * Constructs a newly device object. + * + * @param cl Class. + * @param s Device name + * @param d Device description. + */ + Alarm(Tango::DeviceClass *cl,const char *s,const char *d); + /** + * The device object destructor. + */ + ~Alarm() {delete_device();}; + + +// Miscellaneous methods +public: + /* + * will be called at device destruction or at init command. + */ + void delete_device(); + /* + * Initialize the device + */ + virtual void init_device(); + /* + * Read the device properties from database + */ + void get_device_property(); + /* + * Always executed method before execution command method. + */ + virtual void always_executed_hook(); + + +// Attribute methods +public: + //-------------------------------------------------------- + /* + * Method : Alarm::read_attr_hardware() + * Description : Hardware acquisition for attributes. + */ + //-------------------------------------------------------- + virtual void read_attr_hardware(vector<long> &attr_list); + +/** + * Attribute alarm related methods + * Description: + * + * Data type: Tango::DevString + * Attr type: Spectrum max = 1024 + */ + virtual void read_alarm(Tango::Attribute &attr); + virtual bool is_alarm_allowed(Tango::AttReqType type); + + + //-------------------------------------------------------- + /** + * Method : Alarm::add_dynamic_attributes() + * Description : Add dynamic attributes if any. + */ + //-------------------------------------------------------- + void add_dynamic_attributes(); + + + + +// Command related methods +public: + /** + * Command Ack related method + * Description: Alarm acknowledge + * + * @param argin String array containing the alarms to be acknowledged + */ + virtual void ack(const Tango::DevVarStringArray *argin); + virtual bool is_Ack_allowed(const CORBA::Any &any); + /** + * Command Load related method + * Description: Load a new alarm. + * + * @param argin Alarm entry + */ + virtual void load(Tango::DevString argin); + virtual bool is_Load_allowed(const CORBA::Any &any); + /** + * Command Remove related method + * Description: Remove alarm. + * + * @param argin Alarm name + */ + virtual void remove(Tango::DevString argin); + virtual bool is_Remove_allowed(const CORBA::Any &any); + /** + * Command Configured related method + * Description: Alarms configured + * + * @param argin String containing a filter for output, if empty return all alarms + * @returns Alarms configured + */ + virtual Tango::DevVarStringArray *configured(Tango::DevString argin); + virtual bool is_Configured_allowed(const CORBA::Any &any); + /** + * Command StopNew related method + * Description: Remove "NEW" field from alarm string (so alarm panel stop sound) + * + */ + virtual void stop_new(); + virtual bool is_StopNew_allowed(const CORBA::Any &any); + /** + * Command Silence related method + * Description: Alarm temporarily silence + * + * @param argin String array containing the alarms to be silenced + */ + virtual void silence(const Tango::DevVarStringArray *argin); + virtual bool is_Silence_allowed(const CORBA::Any &any); + /** + * Command Modify related method + * Description: Modify an existing alarm. + * + * @param argin Alarm entry + */ + virtual void modify(Tango::DevString argin); + virtual bool is_Modify_allowed(const CORBA::Any &any); + + + //-------------------------------------------------------- + /** + * Method : Alarm::add_dynamic_commands() + * Description : Add dynamic commands if any. + */ + //-------------------------------------------------------- + void add_dynamic_commands(); + +/*----- PROTECTED REGION ID(Alarm::Additional Method prototypes) ENABLED START -----*/ + +// Additional Method prototypes +friend class alarm_thread; + +protected : + +private: + vector<alarm_t> stored; /* property stored alarms (on exit) */ + alarm_table alarms; + event_table* events; +// event_list evlist; /* producer/consumer events list */ //gcc 4 problem?? + EventCallBack ecb; /* callback handles */ + alarm_thread *almloop; + update_thread *updateloop; + vector<alarm_t> alarmed; + ReadersWritersLock *alarmedlock; + vector<alarm_t> internal; + ReadersWritersLock *internallock; + ReadersWritersLock *dslock; + + static int instanceCounter; + + int internal_counter; + int ds_num; + Tango::DevString ds[MAX_ALARMS]; + char dss[MAX_ALARMS][10124]; + + void init_events(vector<string> &evn); + void init_alarms(map< string,vector<string> > &alarm_events); + void add_alarm(alarm_t& a) throw(string&); + void add_event(alarm_t& a, vector<string> &evn) throw(string&); + void subscribe_event(alarm_t& a, EventCallBack& ecb, vector<string> &evn) throw(string&); +// void do_alarm(bei_t& e); //gcc 4 problem?? + bool remove_alarm(string& s) throw(string&); + //void add_to_database(alarm_t& a) throw(string&); + void set_internal_alarm(string name, Tango::TimeVal t, string msg, unsigned int count=1); + + void load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn); + + double eval_formula(tree_parse_info_t tree, string &attr_values); + void find_event_formula(tree_parse_info_t tree, vector<string> &); + + double eval_expression(iter_t const& i, string &attr_values, int ev_ind=0); //recursive tree node evaluation + void eval_node_event(iter_t const& i, vector<string> & ev); //recursive tree node evaluation + + void prepare_alarm_attr(); //for read attribute alarm and push_change_event + +public: + void do_alarm(bei_t& e); //public instead of protected for gcc 4 problem?? + void timer_update(); //public instead of protected for gcc 4 problem?? + event_list evlist; /* producer/consumer events list */ //public instead of protected for gcc 4 problem?? + bool abortflag; + +#ifdef _USE_ELETTRA_DB_RW +private: + string host_rw; + long port_rw; +#endif + +/*----- PROTECTED REGION END -----*/ // Alarm::Additional Method prototypes +}; + +/*----- PROTECTED REGION ID(Alarm::Additional Classes Definitions) ENABLED START -----*/ + +// Additional Classes Definitions + +/*----- PROTECTED REGION END -----*/ // Alarm::Additional Classes Definitions + +} // End of namespace + +#endif // Alarm_H diff --git a/src/Alarm.xmi b/src/Alarm.xmi new file mode 100644 index 0000000000000000000000000000000000000000..e7e54283ea79212f3eb65719c6f82cc5768cc872 --- /dev/null +++ b/src/Alarm.xmi @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="ASCII"?> +<pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://www.esrf.fr/tango/pogo/PogoDsl"> + <classes name="Alarm" pogoRevision="9.1"> + <description description="Elettra alarm device server" title="Elettra alarm device server" sourcePath="/home/graziano/workspace/git/alarm/src" language="Cpp" filestogenerate="XMI file,Code files,Protected Regions" license="GPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false"> + <inheritances classname="Device_4Impl" sourcePath=""/> + <identification contact="at elettra.eu - graziano.scalamera" author="graziano.scalamera" emailDomain="elettra.eu" classFamily="SoftwareSystem" siteSpecific="" platform="Unix Like" bus="Not Applicable" manufacturer="" reference=""/> + </description> + <deviceProperties name="AlarmStatus" description="Persistent storage of the alarms status"> + <type xsi:type="pogoDsl:StringVectorType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="GroupNames" description="Labels for Group mask, first is for mask 0x00"> + <type xsi:type="pogoDsl:StringVectorType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="ErrThreshold" description="Threshold for Tango error for being internal alarms"> + <type xsi:type="pogoDsl:IntType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DbHost" description="Host of the MySQL db"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DbUser" description="Username for the MySQL db"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DbPasswd" description="Password for the MySQL db"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DbName" description="Db name for the MySQL db"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DbPort" description="Port of the MySQL db"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="InstanceName" description="Name used to associate configured alarm rules to this instance"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <commands name="State" description="This command gets the device state (stored in its <i>device_state</i> data member) and returns it to the caller." execMethod="dev_state" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="none."> + <type xsi:type="pogoDsl:VoidType"/> + </argin> + <argout description="State Code"> + <type xsi:type="pogoDsl:StateType"/> + </argout> + <status abstract="true" inherited="true" concrete="true" concreteHere="false"/> + </commands> + <commands name="Status" description="This command gets the device status (stored in its <i>device_status</i> data member) and returns it to the caller." execMethod="dev_status" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="none."> + <type xsi:type="pogoDsl:VoidType"/> + </argin> + <argout description="Status description"> + <type xsi:type="pogoDsl:ConstStringType"/> + </argout> + <status abstract="true" inherited="true" concrete="true" concreteHere="false"/> + </commands> + <commands name="Ack" description="Alarm acknowledge" execMethod="ack" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="String array containing the alarms to be acknowledged"> + <type xsi:type="pogoDsl:StringArrayType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <commands name="Load" description="Load a new alarm." execMethod="load" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="Alarm entry"> + <type xsi:type="pogoDsl:StringType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <commands name="Remove" description="Remove alarm." execMethod="remove" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="Alarm name"> + <type xsi:type="pogoDsl:StringType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <commands name="Configured" description="Alarms configured" execMethod="configured" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="String containing a filter for output, if empty return all alarms"> + <type xsi:type="pogoDsl:StringType"/> + </argin> + <argout description="Alarms configured"> + <type xsi:type="pogoDsl:StringArrayType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <commands name="StopNew" description="Remove "NEW" field from alarm string (so alarm panel stop sound)" execMethod="stop_new" displayLevel="OPERATOR" polledPeriod="0"> + <argin description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <commands name="Silence" description="Alarm temporarily silence" execMethod="silence" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="String array containing the alarms to be silenced"> + <type xsi:type="pogoDsl:StringArrayType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <commands name="Modify" description="Modify an existing alarm." execMethod="modify" displayLevel="OPERATOR" polledPeriod="0"> + <argin description="Alarm entry"> + <type xsi:type="pogoDsl:StringType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <attributes name="alarm" attType="Spectrum" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="1024" maxY="0"> + <dataType xsi:type="pogoDsl:StringType"/> + <changeEvent fire="false" libCheckCriteria="false"/> + <archiveEvent fire="false" libCheckCriteria="false"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + <properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/> + </attributes> + <preferences docHome="./doc_html" makefileHome="/usr/local/tango-8.1.2.c/share/pogo/preferences"/> + </classes> +</pogoDsl:PogoSystem> diff --git a/src/AlarmClass.cpp b/src/AlarmClass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4c2fa14d61c5aa8eb0a141fe88e558e9cff5c3b --- /dev/null +++ b/src/AlarmClass.cpp @@ -0,0 +1,918 @@ +/*----- PROTECTED REGION ID(AlarmClass.cpp) ENABLED START -----*/ +static const char *RcsId = "$Id: $"; +static const char *TagName = "$Name: $"; +static const char *CvsPath = "$Source: $"; +static const char *SvnPath = "$HeadURL: $"; +static const char *HttpServer = "http://www.esrf.eu/computing/cs/tango/tango_doc/ds_doc/"; +//============================================================================= +// +// file : AlarmClass.cpp +// +// description : C++ source for the AlarmClass. +// A singleton class derived from DeviceClass. +// It implements the command and attribute list +// and all properties and methods required +// by the Alarm once per process. +// +// project : alarm +// +// This file is part of Tango device class. +// +// Tango is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Tango is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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.h> +#include <Alarm.h> +#include <AlarmClass.h> + +/*----- PROTECTED REGION END -----*/ // AlarmClass.cpp + +//------------------------------------------------------------------- +/** + * Create AlarmClass singleton and + * return it in a C function for Python usage + */ +//------------------------------------------------------------------- +extern "C" { +#ifdef _TG_WINDOWS_ + +__declspec(dllexport) + +#endif + + Tango::DeviceClass *_create_Alarm_class(const char *name) { + return Alarm_ns::AlarmClass::init(name); + } +} + +namespace Alarm_ns +{ +//=================================================================== +// Initialize pointer for singleton pattern +//=================================================================== +AlarmClass *AlarmClass::_instance = NULL; + +//-------------------------------------------------------- +/** + * method : AlarmClass::AlarmClass(string &s) + * description : constructor for the AlarmClass + * + * @param s The class name + */ +//-------------------------------------------------------- +AlarmClass::AlarmClass(string &s):Tango::DeviceClass(s) +{ + cout2 << "Entering AlarmClass constructor" << endl; + set_default_property(); + write_class_property(); + + /*----- PROTECTED REGION ID(AlarmClass::constructor) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // AlarmClass::constructor + + cout2 << "Leaving AlarmClass constructor" << endl; +} + +//-------------------------------------------------------- +/** + * method : AlarmClass::~AlarmClass() + * description : destructor for the AlarmClass + */ +//-------------------------------------------------------- +AlarmClass::~AlarmClass() +{ + /*----- PROTECTED REGION ID(AlarmClass::destructor) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // AlarmClass::destructor + + _instance = NULL; +} + + +//-------------------------------------------------------- +/** + * method : AlarmClass::init + * description : Create the object if not already done. + * Otherwise, just return a pointer to the object + * + * @param name The class name + */ +//-------------------------------------------------------- +AlarmClass *AlarmClass::init(const char *name) +{ + if (_instance == NULL) + { + try + { + string s(name); + _instance = new AlarmClass(s); + } + catch (bad_alloc &) + { + throw; + } + } + return _instance; +} + +//-------------------------------------------------------- +/** + * method : AlarmClass::instance + * description : Check if object already created, + * and return a pointer to the object + */ +//-------------------------------------------------------- +AlarmClass *AlarmClass::instance() +{ + if (_instance == NULL) + { + cerr << "Class is not initialised !!" << endl; + exit(-1); + } + return _instance; +} + + + +//=================================================================== +// Command execution method calls +//=================================================================== +//-------------------------------------------------------- +/** + * method : AckClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *AckClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any) +{ + cout2 << "AckClass::execute(): arrived" << endl; + const Tango::DevVarStringArray *argin; + extract(in_any, argin); + ((static_cast<Alarm *>(device))->ack(argin)); + return new CORBA::Any(); +} + +//-------------------------------------------------------- +/** + * method : LoadClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *LoadClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any) +{ + cout2 << "LoadClass::execute(): arrived" << endl; + Tango::DevString argin; + extract(in_any, argin); + ((static_cast<Alarm *>(device))->load(argin)); + return new CORBA::Any(); +} + +//-------------------------------------------------------- +/** + * method : RemoveClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *RemoveClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any) +{ + cout2 << "RemoveClass::execute(): arrived" << endl; + Tango::DevString argin; + extract(in_any, argin); + ((static_cast<Alarm *>(device))->remove(argin)); + return new CORBA::Any(); +} + +//-------------------------------------------------------- +/** + * method : ConfiguredClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *ConfiguredClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any) +{ + cout2 << "ConfiguredClass::execute(): arrived" << endl; + Tango::DevString argin; + extract(in_any, argin); + return insert((static_cast<Alarm *>(device))->configured(argin)); +} + +//-------------------------------------------------------- +/** + * method : StopNewClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *StopNewClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const CORBA::Any &in_any)) +{ + cout2 << "StopNewClass::execute(): arrived" << endl; + ((static_cast<Alarm *>(device))->stop_new()); + return new CORBA::Any(); +} + +//-------------------------------------------------------- +/** + * method : SilenceClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *SilenceClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any) +{ + cout2 << "SilenceClass::execute(): arrived" << endl; + const Tango::DevVarStringArray *argin; + extract(in_any, argin); + ((static_cast<Alarm *>(device))->silence(argin)); + return new CORBA::Any(); +} + +//-------------------------------------------------------- +/** + * method : ModifyClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *ModifyClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any) +{ + cout2 << "ModifyClass::execute(): arrived" << endl; + Tango::DevString argin; + extract(in_any, argin); + ((static_cast<Alarm *>(device))->modify(argin)); + return new CORBA::Any(); +} + + +//=================================================================== +// Properties management +//=================================================================== +//-------------------------------------------------------- +/** + * Method : AlarmClass::get_class_property() + * Description : Get the class property for specified name. + */ +//-------------------------------------------------------- +Tango::DbDatum AlarmClass::get_class_property(string &prop_name) +{ + for (unsigned int i=0 ; i<cl_prop.size() ; i++) + if (cl_prop[i].name == prop_name) + return cl_prop[i]; + // if not found, returns an empty DbDatum + return Tango::DbDatum(prop_name); +} + +//-------------------------------------------------------- +/** + * Method : AlarmClass::get_default_device_property() + * Description : Return the default value for device property. + */ +//-------------------------------------------------------- +Tango::DbDatum AlarmClass::get_default_device_property(string &prop_name) +{ + for (unsigned int i=0 ; i<dev_def_prop.size() ; i++) + if (dev_def_prop[i].name == prop_name) + return dev_def_prop[i]; + // if not found, return an empty DbDatum + return Tango::DbDatum(prop_name); +} + +//-------------------------------------------------------- +/** + * Method : AlarmClass::get_default_class_property() + * Description : Return the default value for class property. + */ +//-------------------------------------------------------- +Tango::DbDatum AlarmClass::get_default_class_property(string &prop_name) +{ + for (unsigned int i=0 ; i<cl_def_prop.size() ; i++) + if (cl_def_prop[i].name == prop_name) + return cl_def_prop[i]; + // if not found, return an empty DbDatum + return Tango::DbDatum(prop_name); +} + + +//-------------------------------------------------------- +/** + * Method : AlarmClass::set_default_property() + * Description : Set default property (class and device) for wizard. + * For each property, add to wizard property name and description. + * If default value has been set, add it to wizard property and + * store it in a DbDatum. + */ +//-------------------------------------------------------- +void AlarmClass::set_default_property() +{ + string prop_name; + string prop_desc; + string prop_def; + vector<string> vect_data; + + // Set Default Class Properties + + // Set Default device Properties + prop_name = "AlarmStatus"; + prop_desc = "Persistent storage of the alarms status"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "GroupNames"; + prop_desc = "Labels for Group mask, first is for mask 0x00"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "ErrThreshold"; + prop_desc = "Threshold for Tango error for being internal alarms"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DbHost"; + prop_desc = "Host of the MySQL db"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DbUser"; + prop_desc = "Username for the MySQL db"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DbPasswd"; + prop_desc = "Password for the MySQL db"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DbName"; + prop_desc = "Db name for the MySQL db"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DbPort"; + prop_desc = "Port of the MySQL db"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "InstanceName"; + prop_desc = "Name used to associate configured alarm rules to this instance"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); +} + +//-------------------------------------------------------- +/** + * Method : AlarmClass::write_class_property() + * Description : Set class description fields as property in database + */ +//-------------------------------------------------------- +void AlarmClass::write_class_property() +{ + // First time, check if database used + if (Tango::Util::_UseDb == false) + return; + + Tango::DbData data; + string classname = get_name(); + string header; + string::size_type start, end; + + // Put title + Tango::DbDatum title("ProjectTitle"); + string str_title("Elettra alarm device server"); + title << str_title; + data.push_back(title); + + // Put Description + Tango::DbDatum description("Description"); + vector<string> str_desc; + str_desc.push_back("Elettra alarm device server"); + description << str_desc; + data.push_back(description); + + // put cvs or svn location + string filename("Alarm"); + filename += "Class.cpp"; + + // check for cvs information + string src_path(CvsPath); + start = src_path.find("/"); + if (start!=string::npos) + { + end = src_path.find(filename); + if (end>start) + { + string strloc = src_path.substr(start, end-start); + // Check if specific repository + start = strloc.find("/cvsroot/"); + if (start!=string::npos && start>0) + { + string repository = strloc.substr(0, start); + if (repository.find("/segfs/")!=string::npos) + strloc = "ESRF:" + strloc.substr(start, strloc.length()-start); + } + Tango::DbDatum cvs_loc("cvs_location"); + cvs_loc << strloc; + data.push_back(cvs_loc); + } + } + + // check for svn information + else + { + string src_path(SvnPath); + start = src_path.find("://"); + if (start!=string::npos) + { + end = src_path.find(filename); + if (end>start) + { + header = "$HeadURL: "; + start = header.length(); + string strloc = src_path.substr(start, (end-start)); + + Tango::DbDatum svn_loc("svn_location"); + svn_loc << strloc; + data.push_back(svn_loc); + } + } + } + + // Get CVS or SVN revision tag + + // CVS tag + string tagname(TagName); + header = "$Name: "; + start = header.length(); + string endstr(" $"); + + end = tagname.find(endstr); + if (end!=string::npos && end>start) + { + string strtag = tagname.substr(start, end-start); + Tango::DbDatum cvs_tag("cvs_tag"); + cvs_tag << strtag; + data.push_back(cvs_tag); + } + + // SVN tag + string svnpath(SvnPath); + header = "$HeadURL: "; + start = header.length(); + + end = svnpath.find(endstr); + if (end!=string::npos && end>start) + { + string strloc = svnpath.substr(start, end-start); + + string tagstr ("/tags/"); + start = strloc.find(tagstr); + if ( start!=string::npos ) + { + start = start + tagstr.length(); + end = strloc.find(filename); + string strtag = strloc.substr(start, end-start-1); + + Tango::DbDatum svn_tag("svn_tag"); + svn_tag << strtag; + data.push_back(svn_tag); + } + } + + // Get URL location + string httpServ(HttpServer); + if (httpServ.length()>0) + { + Tango::DbDatum db_doc_url("doc_url"); + db_doc_url << httpServ; + data.push_back(db_doc_url); + } + + // Put inheritance + Tango::DbDatum inher_datum("InheritedFrom"); + vector<string> inheritance; + inheritance.push_back("TANGO_BASE_CLASS"); + inher_datum << inheritance; + data.push_back(inher_datum); + + // Call database and and values + get_db_class()->put_property(data); +} + +//=================================================================== +// Factory methods +//=================================================================== + +//-------------------------------------------------------- +/** + * Method : AlarmClass::device_factory() + * Description : Create the device object(s) + * and store them in the device list + */ +//-------------------------------------------------------- +void AlarmClass::device_factory(const Tango::DevVarStringArray *devlist_ptr) +{ + /*----- PROTECTED REGION ID(AlarmClass::device_factory_before) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::device_factory_before + + // Create devices and add it into the device list + for (unsigned long i=0 ; i<devlist_ptr->length() ; i++) + { + cout4 << "Device name : " << (*devlist_ptr)[i].in() << endl; + device_list.push_back(new Alarm(this, (*devlist_ptr)[i])); + } + + // Manage dynamic attributes if any + erase_dynamic_attributes(devlist_ptr, get_class_attr()->get_attr_list()); + + // Export devices to the outside world + for (unsigned long i=1 ; i<=devlist_ptr->length() ; i++) + { + // Add dynamic attributes if any + Alarm *dev = static_cast<Alarm *>(device_list[device_list.size()-i]); + dev->add_dynamic_attributes(); + + // Check before if database used. + if ((Tango::Util::_UseDb == true) && (Tango::Util::_FileDb == false)) + export_device(dev); + else + export_device(dev, dev->get_name().c_str()); + } + + /*----- PROTECTED REGION ID(AlarmClass::device_factory_after) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::device_factory_after +} +//-------------------------------------------------------- +/** + * Method : AlarmClass::attribute_factory() + * Description : Create the attribute object(s) + * and store them in the attribute list + */ +//-------------------------------------------------------- +void AlarmClass::attribute_factory(vector<Tango::Attr *> &att_list) +{ + /*----- PROTECTED REGION ID(AlarmClass::attribute_factory_before) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::attribute_factory_before + // Attribute : alarm + alarmAttrib *alarm = new alarmAttrib(); + Tango::UserDefaultAttrProp alarm_prop; + // description not set for alarm + // label not set for alarm + // unit not set for alarm + // standard_unit not set for alarm + // display_unit not set for alarm + // format not set for alarm + // max_value not set for alarm + // min_value not set for alarm + // max_alarm not set for alarm + // min_alarm not set for alarm + // max_warning not set for alarm + // min_warning not set for alarm + // delta_t not set for alarm + // delta_val not set for alarm + + alarm->set_default_properties(alarm_prop); + // Not Polled + alarm->set_disp_level(Tango::OPERATOR); + // Not Memorized + att_list.push_back(alarm); + + + // Create a list of static attributes + create_static_attribute_list(get_class_attr()->get_attr_list()); + /*----- PROTECTED REGION ID(AlarmClass::attribute_factory_after) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::attribute_factory_after +} +//-------------------------------------------------------- +/** + * Method : AlarmClass::pipe_factory() + * Description : Create the pipe object(s) + * and store them in the pipe list + */ +//-------------------------------------------------------- +void AlarmClass::pipe_factory() +{ + /*----- PROTECTED REGION ID(AlarmClass::pipe_factory_before) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::pipe_factory_before + /*----- PROTECTED REGION ID(AlarmClass::pipe_factory_after) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::pipe_factory_after +} +//-------------------------------------------------------- +/** + * Method : AlarmClass::command_factory() + * Description : Create the command object(s) + * and store them in the command list + */ +//-------------------------------------------------------- +void AlarmClass::command_factory() +{ + /*----- PROTECTED REGION ID(AlarmClass::command_factory_before) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::command_factory_before + + + // Command Ack + AckClass *pAckCmd = + new AckClass("Ack", + Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID, + "String array containing the alarms to be acknowledged", + "", + Tango::OPERATOR); + command_list.push_back(pAckCmd); + + // Command Load + LoadClass *pLoadCmd = + new LoadClass("Load", + Tango::DEV_STRING, Tango::DEV_VOID, + "Alarm entry", + "", + Tango::OPERATOR); + command_list.push_back(pLoadCmd); + + // Command Remove + RemoveClass *pRemoveCmd = + new RemoveClass("Remove", + Tango::DEV_STRING, Tango::DEV_VOID, + "Alarm name", + "", + Tango::OPERATOR); + command_list.push_back(pRemoveCmd); + + // Command Configured + ConfiguredClass *pConfiguredCmd = + new ConfiguredClass("Configured", + Tango::DEV_STRING, Tango::DEVVAR_STRINGARRAY, + "String containing a filter for output, if empty return all alarms", + "Alarms configured", + Tango::OPERATOR); + command_list.push_back(pConfiguredCmd); + + // Command StopNew + StopNewClass *pStopNewCmd = + new StopNewClass("StopNew", + Tango::DEV_VOID, Tango::DEV_VOID, + "", + "", + Tango::OPERATOR); + command_list.push_back(pStopNewCmd); + + // Command Silence + SilenceClass *pSilenceCmd = + new SilenceClass("Silence", + Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID, + "String array containing the alarms to be silenced", + "", + Tango::OPERATOR); + command_list.push_back(pSilenceCmd); + + // Command Modify + ModifyClass *pModifyCmd = + new ModifyClass("Modify", + Tango::DEV_STRING, Tango::DEV_VOID, + "Alarm entry", + "", + Tango::OPERATOR); + command_list.push_back(pModifyCmd); + + /*----- PROTECTED REGION ID(AlarmClass::command_factory_after) ENABLED START -----*/ + + // Add your own code + + /*----- PROTECTED REGION END -----*/ // AlarmClass::command_factory_after +} + +//=================================================================== +// Dynamic attributes related methods +//=================================================================== + +//-------------------------------------------------------- +/** + * method : AlarmClass::create_static_attribute_list + * description : Create the a list of static attributes + * + * @param att_list the ceated attribute list + */ +//-------------------------------------------------------- +void AlarmClass::create_static_attribute_list(vector<Tango::Attr *> &att_list) +{ + for (unsigned long i=0 ; i<att_list.size() ; i++) + { + string att_name(att_list[i]->get_name()); + transform(att_name.begin(), att_name.end(), att_name.begin(), ::tolower); + defaultAttList.push_back(att_name); + } + + cout2 << defaultAttList.size() << " attributes in default list" << endl; + + /*----- PROTECTED REGION ID(AlarmClass::create_static_att_list) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // AlarmClass::create_static_att_list +} + + +//-------------------------------------------------------- +/** + * method : AlarmClass::erase_dynamic_attributes + * description : delete the dynamic attributes if any. + * + * @param devlist_ptr the device list pointer + * @param list of all attributes + */ +//-------------------------------------------------------- +void AlarmClass::erase_dynamic_attributes(const Tango::DevVarStringArray *devlist_ptr, vector<Tango::Attr *> &att_list) +{ + Tango::Util *tg = Tango::Util::instance(); + + for (unsigned long i=0 ; i<devlist_ptr->length() ; i++) + { + Tango::DeviceImpl *dev_impl = tg->get_device_by_name(((string)(*devlist_ptr)[i]).c_str()); + Alarm *dev = static_cast<Alarm *> (dev_impl); + + vector<Tango::Attribute *> &dev_att_list = dev->get_device_attr()->get_attribute_list(); + vector<Tango::Attribute *>::iterator ite_att; + for (ite_att=dev_att_list.begin() ; ite_att != dev_att_list.end() ; ++ite_att) + { + string att_name((*ite_att)->get_name_lower()); + if ((att_name == "state") || (att_name == "status")) + continue; + vector<string>::iterator ite_str = find(defaultAttList.begin(), defaultAttList.end(), att_name); + if (ite_str == defaultAttList.end()) + { + cout2 << att_name << " is a UNWANTED dynamic attribute for device " << (*devlist_ptr)[i] << endl; + Tango::Attribute &att = dev->get_device_attr()->get_attr_by_name(att_name.c_str()); + dev->remove_attribute(att_list[att.get_attr_idx()], true, false); + --ite_att; + } + } + } + /*----- PROTECTED REGION ID(AlarmClass::erase_dynamic_attributes) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // AlarmClass::erase_dynamic_attributes +} + +//-------------------------------------------------------- +/** + * Method : AlarmClass::get_attr_by_name() + * Description : returns Tango::Attr * object found by name + */ +//-------------------------------------------------------- +Tango::Attr *AlarmClass::get_attr_object_by_name(vector<Tango::Attr *> &att_list, string attname) +{ + vector<Tango::Attr *>::iterator it; + for (it=att_list.begin() ; it<att_list.end() ; ++it) + if ((*it)->get_name()==attname) + return (*it); + // Attr does not exist + return NULL; +} + + +/*----- PROTECTED REGION ID(AlarmClass::Additional Methods) ENABLED START -----*/ + +/*----- PROTECTED REGION END -----*/ // AlarmClass::Additional Methods +} // namespace diff --git a/src/AlarmClass.h b/src/AlarmClass.h new file mode 100644 index 0000000000000000000000000000000000000000..df66071cef0fc817cf759c3f532e9c3c3339f770 --- /dev/null +++ b/src/AlarmClass.h @@ -0,0 +1,291 @@ +/*----- PROTECTED REGION ID(AlarmClass.h) ENABLED START -----*/ +//============================================================================= +// +// file : AlarmClass.h +// +// description : Include for the Alarm root class. +// This class is the singleton class for +// the Alarm device class. +// It contains all properties and methods which the +// Alarm requires only once e.g. the commands. +// +// project : alarm +// +// This file is part of Tango device class. +// +// Tango is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Tango is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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) +//============================================================================= + + +#ifndef AlarmClass_H +#define AlarmClass_H + +#include <tango.h> +#include <Alarm.h> + +/*----- PROTECTED REGION END -----*/ // AlarmClass.h + + +namespace Alarm_ns +{ +/*----- PROTECTED REGION ID(AlarmClass::classes for dynamic creation) ENABLED START -----*/ + + +/*----- PROTECTED REGION END -----*/ // AlarmClass::classes for dynamic creation + +//========================================= +// Define classes for attributes +//========================================= +// Attribute alarm class definition +class alarmAttrib: public Tango::SpectrumAttr +{ +public: + alarmAttrib():SpectrumAttr("alarm", + Tango::DEV_STRING, Tango::READ, 1024) {}; + ~alarmAttrib() {}; + virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att) + {(static_cast<Alarm *>(dev))->read_alarm(att);} + virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty) + {return (static_cast<Alarm *>(dev))->is_alarm_allowed(ty);} +}; + + +//========================================= +// Define classes for commands +//========================================= +// Command Ack class definition +class AckClass : public Tango::Command +{ +public: + AckClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + AckClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~AckClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<Alarm *>(dev))->is_Ack_allowed(any);} +}; + +// Command Load class definition +class LoadClass : public Tango::Command +{ +public: + LoadClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + LoadClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~LoadClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<Alarm *>(dev))->is_Load_allowed(any);} +}; + +// Command Remove class definition +class RemoveClass : public Tango::Command +{ +public: + RemoveClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + RemoveClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~RemoveClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<Alarm *>(dev))->is_Remove_allowed(any);} +}; + +// Command Configured class definition +class ConfiguredClass : public Tango::Command +{ +public: + ConfiguredClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + ConfiguredClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~ConfiguredClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<Alarm *>(dev))->is_Configured_allowed(any);} +}; + +// Command StopNew class definition +class StopNewClass : public Tango::Command +{ +public: + StopNewClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + StopNewClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~StopNewClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<Alarm *>(dev))->is_StopNew_allowed(any);} +}; + +// Command Silence class definition +class SilenceClass : public Tango::Command +{ +public: + SilenceClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + SilenceClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~SilenceClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<Alarm *>(dev))->is_Silence_allowed(any);} +}; + +// Command Modify class definition +class ModifyClass : public Tango::Command +{ +public: + ModifyClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + ModifyClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~ModifyClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<Alarm *>(dev))->is_Modify_allowed(any);} +}; + + +/** + * The AlarmClass singleton definition + */ + +#ifdef _TG_WINDOWS_ +class __declspec(dllexport) AlarmClass : public Tango::DeviceClass +#else +class AlarmClass : public Tango::DeviceClass +#endif +{ + /*----- PROTECTED REGION ID(AlarmClass::Additionnal DServer data members) ENABLED START -----*/ + + + /*----- PROTECTED REGION END -----*/ // AlarmClass::Additionnal DServer data members + + public: + // write class properties data members + Tango::DbData cl_prop; + Tango::DbData cl_def_prop; + Tango::DbData dev_def_prop; + + // Method prototypes + static AlarmClass *init(const char *); + static AlarmClass *instance(); + ~AlarmClass(); + Tango::DbDatum get_class_property(string &); + Tango::DbDatum get_default_device_property(string &); + Tango::DbDatum get_default_class_property(string &); + + protected: + AlarmClass(string &); + static AlarmClass *_instance; + void command_factory(); + void attribute_factory(vector<Tango::Attr *> &); + void pipe_factory(); + void write_class_property(); + void set_default_property(); + void get_class_property(); + string get_cvstag(); + string get_cvsroot(); + + private: + void device_factory(const Tango::DevVarStringArray *); + void create_static_attribute_list(vector<Tango::Attr *> &); + void erase_dynamic_attributes(const Tango::DevVarStringArray *,vector<Tango::Attr *> &); + vector<string> defaultAttList; + Tango::Attr *get_attr_object_by_name(vector<Tango::Attr *> &att_list, string attname); +}; + +} // End of namespace + +#endif // Alarm_H diff --git a/src/AlarmStateMachine.cpp b/src/AlarmStateMachine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f703cc4b43b26966aca1517fc3223782663637f --- /dev/null +++ b/src/AlarmStateMachine.cpp @@ -0,0 +1,186 @@ +/*----- PROTECTED REGION ID(AlarmStateMachine.cpp) ENABLED START -----*/ +static const char *RcsId = "$Id: $"; +//============================================================================= +// +// file : AlarmStateMachine.cpp +// +// description : State machine file for the Alarm class +// +// project : alarm +// +// This file is part of Tango device class. +// +// Tango is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Tango is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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 <Alarm.h> + +/*----- PROTECTED REGION END -----*/ // Alarm::AlarmStateMachine.cpp + +//================================================================ +// States | Description +//================================================================ + + +namespace Alarm_ns +{ +//================================================= +// Attributes Allowed Methods +//================================================= + +//-------------------------------------------------------- +/** + * Method : Alarm::is_alarm_allowed() + * Description : Execution allowed for alarm attribute + */ +//-------------------------------------------------------- +bool Alarm::is_alarm_allowed(TANGO_UNUSED(Tango::AttReqType type)) +{ + + // Not any excluded states for alarm attribute in read access. + /*----- PROTECTED REGION ID(Alarm::alarmStateAllowed_READ) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::alarmStateAllowed_READ + return true; +} + + +//================================================= +// Commands Allowed Methods +//================================================= + +//-------------------------------------------------------- +/** + * Method : Alarm::is_Ack_allowed() + * Description : Execution allowed for Ack attribute + */ +//-------------------------------------------------------- +bool Alarm::is_Ack_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for Ack command. + /*----- PROTECTED REGION ID(Alarm::AckStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::AckStateAllowed + return true; +} + +//-------------------------------------------------------- +/** + * Method : Alarm::is_Load_allowed() + * Description : Execution allowed for Load attribute + */ +//-------------------------------------------------------- +bool Alarm::is_Load_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for Load command. + /*----- PROTECTED REGION ID(Alarm::LoadStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::LoadStateAllowed + return true; +} + +//-------------------------------------------------------- +/** + * Method : Alarm::is_Remove_allowed() + * Description : Execution allowed for Remove attribute + */ +//-------------------------------------------------------- +bool Alarm::is_Remove_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for Remove command. + /*----- PROTECTED REGION ID(Alarm::RemoveStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::RemoveStateAllowed + return true; +} + +//-------------------------------------------------------- +/** + * Method : Alarm::is_Configured_allowed() + * Description : Execution allowed for Configured attribute + */ +//-------------------------------------------------------- +bool Alarm::is_Configured_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for Configured command. + /*----- PROTECTED REGION ID(Alarm::ConfiguredStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::ConfiguredStateAllowed + return true; +} + +//-------------------------------------------------------- +/** + * Method : Alarm::is_StopNew_allowed() + * Description : Execution allowed for StopNew attribute + */ +//-------------------------------------------------------- +bool Alarm::is_StopNew_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for StopNew command. + /*----- PROTECTED REGION ID(Alarm::StopNewStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::StopNewStateAllowed + return true; +} + +//-------------------------------------------------------- +/** + * Method : Alarm::is_Silence_allowed() + * Description : Execution allowed for Silence attribute + */ +//-------------------------------------------------------- +bool Alarm::is_Silence_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for Silence command. + /*----- PROTECTED REGION ID(Alarm::SilenceStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::SilenceStateAllowed + return true; +} + +//-------------------------------------------------------- +/** + * Method : Alarm::is_Modify_allowed() + * Description : Execution allowed for Modify attribute + */ +//-------------------------------------------------------- +bool Alarm::is_Modify_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for Modify command. + /*----- PROTECTED REGION ID(Alarm::ModifyStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // Alarm::ModifyStateAllowed + return true; +} + + +/*----- PROTECTED REGION ID(Alarm::AlarmStateAllowed.AdditionalMethods) ENABLED START -----*/ + +// Additional Methods + +/*----- PROTECTED REGION END -----*/ // Alarm::AlarmStateAllowed.AdditionalMethods + +} // End of namespace diff --git a/src/ClassFactory.cpp b/src/ClassFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..065b2f918a28230bdf255d2b5b1287807c59b95d --- /dev/null +++ b/src/ClassFactory.cpp @@ -0,0 +1,49 @@ +/*----- PROTECTED REGION ID(Alarm::ClassFactory.cpp) ENABLED START -----*/ +static const char *RcsId = "$Header: /home/cvsadm/cvsroot/utils/alarm/tango/server/src/ClassFactory.cpp,v 1.2 2008-03-27 09:25:29 graziano Exp $"; +//+============================================================================= +// +// file : ClassFactory.cpp +// +// description : C++ source for the class_factory method of the DServer +// device class. This method is responsible to create +// all class singletin for a device server. It is called +// at device server startup +// +// project : TANGO Device Server +// +// $Author: graziano $ +// +// $Revision: 1.2 $ +// +// copyleft : Sincrotrone Trieste S.C.p.A. di interesse nazionale +// Strada Statale 14 - km 163,5 in AREA Science Park +// 34012 Basovizza, Trieste ITALY +// Tel. +39 040 37581 +// Fax. +39 040 9380902 +// +//-============================================================================= +// +// This file is generated by POGO +// (Program Obviously used to Generate tango Object) +// +// (c) - ELETTRA U.O. Controlli +//============================================================================= + + +#include <tango.h> +#include <AlarmClass.h> + +/** + * Create AlarmClass singleton and store it in DServer object. + * + * @author $Author: graziano $ + * @version $Revision: 1.2 $ $ + */ + +void Tango::DServer::class_factory() +{ + + add_class(Alarm_ns::AlarmClass::init("Alarm")); + +} +/*----- PROTECTED REGION END -----*/ // Alarm::ClassFactory.cpp diff --git a/src/alarm-thread.cpp b/src/alarm-thread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57d523bb248754008b4b99c96752ef03ca112742 --- /dev/null +++ b/src/alarm-thread.cpp @@ -0,0 +1,90 @@ +/* + * alarm-thread.cpp + * + * $Author: claudio $ + * + * $Revision: 1.7 $ + * + * $Log: alarm-thread.cpp,v $ + * Revision 1.7 2015-07-21 13:40:59 claudio + * minor cleanups + * + * Revision 1.6 2013-03-06 10:41:11 claudio + * commented out debug print statements + * + * Revision 1.5 2008-07-08 12:11:39 graziano + * omni_thread_fatal exception handling + * + * Revision 1.4 2008/07/07 09:13:12 graziano + * omni_thread_fatal exception handling + * + * Revision 1.3 2008/04/24 06:51:34 graziano + * small code cleanings + * + * + * + * copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale + * Strada Statale 14 - km 163,5 in AREA Science Park + * 34012 Basovizza, Trieste ITALY + */ + +#include "alarm-thread.h" +static const char __FILE__rev[] = __FILE__ " $Revision: 1.7 $"; + +/* + * alarm_thread::alarm_thread() + */ +alarm_thread::alarm_thread(Alarm_ns::Alarm *p) : p_Alarm(p) +{ + //cout << __FILE__rev << endl; +} + +/* + * alarm_thread::~alarm_thread() + */ +alarm_thread::~alarm_thread() +{ + p_Alarm = NULL; +} + +/* + * alarm_thread::run() + */ +void alarm_thread::run(void *) +{ + while (true) { + /* + * pop_front() will wait() on condition variable + */ + try + { + bei_t e = p_Alarm->evlist.pop_front(); + //DEBUG_STREAM << "alarm_thread::run(): woken up!!!! " << e.name << endl; + if ((e.ev_name == ALARM_THREAD_EXIT) && \ + (e.value[0] == ALARM_THREAD_EXIT_VALUE)) + break; + p_Alarm->do_alarm(e); + } + catch(omni_thread_fatal& ex) + { + ostringstream err; + err << "omni_thread_fatal exception running alarm thread, err=" << ex.error << ends; + //WARN_STREAM << "alarm_thread::run(): " << err.str() << endl; + printf("alarm_thread::run(): %s", err.str().c_str()); + } + catch(Tango::DevFailed& ex) + { + ostringstream err; + err << "exception running alarm thread: '" << ex.errors[0].desc << "'" << ends; + //WARN_STREAM << "alarm_thread::run(): " << err.str() << endl; + printf("alarm_thread::run(): %s", err.str().c_str()); + Tango::Except::print_exception(ex); + } + catch(...) + { + //WARN_STREAM << "alarm_thread::run(): catched unknown exception!!" << endl; + printf("alarm_thread::run(): catched unknown exception!!"); + } + } + //cout << "alarm_thread::run(): returning" << endl; +} /* alarm_thread::run() */ diff --git a/src/alarm-thread.h b/src/alarm-thread.h new file mode 100644 index 0000000000000000000000000000000000000000..221cdabff7c97b90cd3dfd2ea615ebd21ec4f6ae --- /dev/null +++ b/src/alarm-thread.h @@ -0,0 +1,41 @@ +/* + * alarm-thread.h + * + * $Author: graziano $ + * + * $Revision: 1.3 $ + * + * $Log: alarm-thread.h,v $ + * Revision 1.3 2008-04-23 15:00:57 graziano + * small code cleanings + * + * + * + * copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale + * Strada Statale 14 - km 163,5 in AREA Science Park + * 34012 Basovizza, Trieste ITALY + */ + +#ifndef ALARM_THREAD_H +#define ALARM_THREAD_H + +#include <omnithread.h> +#include <tango.h> +#include <Alarm.h> + +#define ALARM_THREAD_EXIT "alarm_thread_exit" +#define ALARM_THREAD_EXIT_VALUE -100 + +class alarm_thread : public omni_thread { + public: + alarm_thread(Alarm_ns::Alarm *p); + ~alarm_thread(); + protected: + void run(void *); + private: + Alarm_ns::Alarm *p_Alarm; +}; + +#endif /* ALARM_THREAD_H */ + +/* EOF */ diff --git a/src/alarm_grammar.h b/src/alarm_grammar.h new file mode 100644 index 0000000000000000000000000000000000000000..f9746994d750094d7fd2286d6331bafcd77333cd --- /dev/null +++ b/src/alarm_grammar.h @@ -0,0 +1,280 @@ +/* + * alarm_grammar.h + * + * $Author: $ + * + * $Revision: $ + * + * $Log: alarm_grammar.h,v $ + * + * + * copyleft: Sincrotrone Trieste S.C.p.A. di interesse nazionale + * Strada Statale 14 - km 163,5 in AREA Science Park + * 34012 Basovizza, Trieste ITALY + */ + + +#ifndef ALARM_GRAMMAR_H_ +#define ALARM_GRAMMAR_H_ + +//--------------------------NOTE!!--------------------------------- +//----if a grammar is intended to be used in multithreaded code---- +//----it is required to "#define BOOST_SPIRIT_THREADSAFE" and------ +//----to link against Boost.Threads-------------------------------- +//----------------------------------------------------------------- +#if BOOST_VERSION < 103600 +#ifndef BOOST_SPIRIT_THREADSAFE +#define BOOST_SPIRIT_THREADSAFE +#endif + +#ifndef PHOENIX_THREADSAFE +#define PHOENIX_THREADSAFE +#endif +#endif + +#if BOOST_VERSION < 103600 +#include <boost/spirit/core.hpp> +#include <boost/spirit/actor/assign_actor.hpp> //for assign_a +#include <boost/spirit/actor/push_back_actor.hpp> //for push_back_a +#include <boost/spirit/actor/insert_at_actor.hpp> //for insert_at_a +#include <boost/spirit/actor/clear_actor.hpp> //for clear_a +#include <boost/spirit/symbols/symbols.hpp> //for symbol table +#include <boost/spirit/utility/confix.hpp> //for confix +#include <boost/spirit/phoenix/primitives.hpp> //needed for "var" in group rule +#include <boost/spirit/phoenix/operators.hpp> //needed for "var" in group rule +#include <boost/spirit/phoenix/functions.hpp> +#else +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_assign_actor.hpp> //for assign_a +#include <boost/spirit/include/classic_push_back_actor.hpp> //for push_back_a +#include <boost/spirit/include/classic_insert_at_actor.hpp> //for insert_at_a +#include <boost/spirit/include/classic_clear_actor.hpp> //for clear_a +#include <boost/spirit/include/classic_symbols.hpp> //for symbol table +#include <boost/spirit/include/classic_confix.hpp> //for confix +#include <boost/spirit/include/phoenix1_primitives.hpp> //needed for "var" in group rule +#include <boost/spirit/include/phoenix1_operators.hpp> //needed for "var" in group rule +#include <boost/spirit/include/phoenix1_functions.hpp> +#endif + +//#include <boost/spirit/attribute.hpp> //for closure + +//#include <boost/spirit/tree/ast.hpp> //for ast parse trees (in tree_formula) + +#include <iostream> +#include <string> +#include <map> + +#include "event_table.h" +#include "formula_grammar.h" + +//////////////////////////////////////////////////////////////////////////// +using namespace std; +#if BOOST_VERSION < 103600 +using namespace boost::spirit; +#else +using namespace boost::spirit::classic; +#endif +using namespace phoenix; //needed for "var" in group rule + +//////////////////////////////////////////////////////////////////////////// +// +// Semantic actions for alarm gramamr +// +//////////////////////////////////////////////////////////////////////////// +#if 0 +struct push_back_impl +{ + template <typename Container, typename Item> + struct result + { + typedef void type; + }; + + template <typename Container, typename Item> + void operator()(Container& c, Item const& item) const + { + c.push_back(item); + } +}; + +function<push_back_impl> const push_back = push_back_impl(); + +struct insert_map_impl +{ + template <typename Container, typename Item1, typename Item2> + struct result + { + typedef void type; + }; + + template <typename Container, typename Item1, typename Item2> + void operator()(Container& c, Item1 const& item1, Item2 const& item2) const + { + c.insert(make_pair(item1, item2)); + } +}; + +function<insert_map_impl> const insert_map = insert_map_impl(); +#endif +//////////////////////////////////////////////////////////////////////////// +// +// alarm grammar +// +//////////////////////////////////////////////////////////////////////////// +struct alarm_parse : public grammar<alarm_parse> +{ + alarm_t &m_alarm; + + symbols<unsigned int> sym_grp; + + alarm_parse(alarm_t &a) \ + : m_alarm(a) + { + //init symbol table with group defined in alarm_t::grp_str + map<string,unsigned int>::iterator i = m_alarm.grp_str.begin(); + while(i != m_alarm.grp_str.end()) + { + sym_grp.add(i->first.c_str(), i->second); + i++; + } + } + + template <typename ScannerT> + struct definition + { + definition(alarm_parse const& self) + { + //-------BOOST.SPIRIT GLOSSARY------- + // >> : sequence + // | : union (i.e. alternative) + // - : difference + // * : kleene star (matches 0 or more times) + // + : positive (matches 1 or more times) + // ! : optional (matches 0 or 1 time) + // str_p : matches string + // ch_p : matches char + // hex_p : + // alnum_p : matches alpha-numeric characters + // anychar_p : matches any single character (including the null terminator: '\0') + // lexemd_d : turns off white space skipping + // confix : recognize a sequence of: an opening, an expression and a closing + // assign_a : + // push_back_a : + + //std::pair<string, vector<string> > temp; + + expression + = discard_node_d + [ + name + [ + assign_a(self.m_alarm.name) //save name in alarm_t + ] + ] //discard_node_d + >> + root_node_d + [ + formula + [ + assign_a(self.m_alarm.formula) //save formula in alarm_t + ] + ] //root_node_d + + >> discard_node_d[!time_threshold] //save time_threshold in alarm_t (leave it optional) + + >> discard_node_d + [ + level + [ + assign_a(self.m_alarm.lev) //save level in alarm_t + ] + ] //discard_node_d + + >> discard_node_d[!silent_time] //save silent_time in alarm_t (leave it optional) + + >> discard_node_d[group] + + >> discard_node_d[msg] //save msg in alarm_t + + >> discard_node_d + [ + !name //leave it optional + [ + assign_a(self.m_alarm.cmd_name_a) //save cmd_name_a in alarm_t + ] + ] //discard_node_d + + >> discard_node_d[!ch_p(';')] //action_a and action_n separed by ';' + + >> discard_node_d + [ + !name //leave it optional + [ + assign_a(self.m_alarm.cmd_name_n) //save cmd_name_n in alarm_t + ] + ] //discard_node_d + ; + //------------------------------ALARM NAME-------------------------------------- + symbol + = alnum_p | '.' | '_' | '-' | '+' //any alpha numeric char plus '.', '_', '-', '+' + ; + name + = (+symbol) >> '/' >> (+symbol) + >> '/' >> (+symbol) >> '/' >> (+symbol) + ; + //------------------------------LEVEL-------------------------------------- + level + = lexeme_d[(+alnum_p)] //match only possible levels?? (fault, log, ...) + ; + //------------------------------GROUP-------------------------------------- + group + = self.sym_grp //match only group defined in sym_grp symbol table + [ + var(self.m_alarm.grp) |= arg1 //using phoenix::var + ] + >> *( + ch_p('|') + >> self.sym_grp //match only group defined in sym_grp symbol table + [ + var(self.m_alarm.grp) |= arg1 //using phoenix::var + ] + ) + ; + //------------------------------MESSAGE-------------------------------------- + msg + = ch_p('"') + >> (+(anychar_p - '\"')) //one ore more char except '"' + [ + assign_a(self.m_alarm.msg) + ] + >> '"' + ; + //---------------------------TIME THRESHOLD---------------------------------- + time_threshold + = uint_p + [ + assign_a(self.m_alarm.time_threshold) + ] + ; + //-----------------------------SILENT TIME------------------------------------ + silent_time + = int_p + [ + assign_a(self.m_alarm.silent_time) + ] + ; + + } + + typedef rule<ScannerT> rule_t; + rule_t expression, event; + rule_t symbol, name, val, token, oper, msg, group, level, time_threshold, silent_time; + formula_grammar formula; + + rule_t const& + start() const { return expression; } + }; +}; + + +#endif /*ALARM_GRAMMAR_H_*/ diff --git a/src/alarm_table.cpp b/src/alarm_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa6b4cebef35d39a54649f16afa76e3f7d5801ef --- /dev/null +++ b/src/alarm_table.cpp @@ -0,0 +1,722 @@ +/* + * 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 "alarm_table.h" +#include "alarm_grammar.h" +#include "log_thread.h" +#include "cmd_thread.h" + +#define _ACCESS_NODE_D 1 + +static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $"; + +/* + * alarm_t class methods + */ +alarm_t::alarm_t() +{ + grp=0; + counter=0; +} + +bool alarm_t::operator==(const alarm_t &that) +{ +// return((stat == that.stat) && (ack == that.ack)); + //verify if stat not equal but only contained because added *n in internal alarm + return((stat.find(that.stat) != std::string::npos) && (ack == that.ack)); +} + +bool alarm_t::operator==(const string &n) +{ + return(name == n); +} + +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 + temp_msg << is.rdbuf(); //read all remaining characters as msg + msg += temp_msg.str(); + str2grp(temp_grp); +} + +string alarm_t::alm2str(void) +{ + ostringstream os; + os.clear(); + 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; + return(os.str()); +} + +map<string, unsigned int> alarm_t::grp_str; //needed here because static +void alarm_t::init_static_map(vector<string> &group_names) +{ + //LOG_STREAM << "alarm_table::init_static_map(vector<string> &group_names): Entering..." << endl; + int j=0; + vector<string>::iterator i; + if(grp_str.size() > 0) + return; + if(group_names.empty()) + { + //LOG_STREAM << "alarm_table::init_static_map(): inserting: default group " << GR_NONE_NAME << " = " << showbase << hex << GR_NONE << endl; + grp_str.insert(make_pair(string(GR_NONE_NAME), GR_NONE)); + } + for (i = group_names.begin(); i != group_names.end(); i++) + { + if((*i) == string(GR_ALL_NAME)) + continue; + if(i == group_names.begin()) + { + //LOG_STREAM << "alarm_table::init_static_map(): inserting: group " << *i << " = " << showbase << hex << GR_NONE << endl; + grp_str.insert(make_pair(*i, GR_NONE)); + } + else + { + //LOG_STREAM << "alarm_table::init_static_map(): inserting: group " << *i << " = " << showbase << hex << int(0x1 << j) << endl; + grp_str.insert(make_pair(*i, 0x1 << j)); + j++; + } + } + //LOG_STREAM << "alarm_table::init_static_map(): inserting: group " << GR_ALL_NAME << " = " << showbase << hex << GR_ALL << endl; + grp_str.insert(make_pair(string(GR_ALL_NAME), GR_ALL)); +} + +string alarm_t::grp2str(void) +{ + map<string, unsigned int>::iterator i = grp_str.begin(); + bool first=true; + string argout; + if(grp == GR_ALL) + argout = string(GR_ALL_NAME); + else if(grp == GR_NONE) + { + if(i != grp_str.end()) + argout = i->first; + else + argout = string(GR_NONE_NAME); + } + else + { + for (; i != grp_str.end(); i++) + { + if(i->first == string(GR_ALL_NAME)) + continue; + if(grp & i->second) + { + if(first) + { + argout = i->first; + first = false; + } + else + argout += string("|") + i->first; + } + } + } + return argout; +} + +void alarm_t::add_grp_from_str(string &s) +{ + map<string, unsigned int>::iterator i = grp_str.find(s); + if(i != grp_str.end()) + grp |= (*i).second; +} + +void alarm_t::str2grp(string &s) +{ + for(map<string, unsigned int>::iterator i=grp_str.begin(); i != grp_str.end(); i++) + if(s.find(i->first) != string::npos) + grp |= i->second; +} + +void alarm_t::insert(const string& s) +{ + s_event.insert(s); +} + +void alarm_t::clear() +{ + name.clear(); + formula.clear(); + msg.clear(); + lev.clear(); + grp=0; + s_event.clear(); + to_be_evaluated = false; + stat.clear(); + ack.clear(); + done = false; +// ts = 0; +} + +/* + * alarm_table class methods + */ +/* typedef std::string::iterator iterator_t; + typedef boost::spirit::node_val_data_factory<unsigned int> factory_t; /////TEMP!!!!!!!!!!!!!!!!!!! + typedef boost::spirit::tree_match<iterator_t, factory_t> parse_tree_match_t; +typedef boost::spirit::tree_parse_info<iterator_t, factory_t> tree_parse_info_t; +*/ +/* +void alarm_table::init(vector<string>& avs, vector<string> &evn, map< string,vector<string> > &alarm_event) +{ + //LOG_STREAM << "alarm_table::init(vector<string>& avs,map< string,vector<string> > &alarm_event): Entering..." << endl; + alarm_t tmp_alm; + LOG_STREAM << gettime().tv_sec << " " << __FILE__rev << endl; + LOG_STREAM << gettime().tv_sec << " alarm_table::init(): Creating Spirit Parser..." << endl; + alarm_parse al(tmp_alm); // Construct Spirit grammar + + if (avs.empty() == false) { + for (vector<string>::iterator i = avs.begin(); \ + i != avs.end(); i++) { + + tmp_alm.name.clear(); + tmp_alm.formula.clear(); + tmp_alm.msg.clear(); + tmp_alm.lev.clear(); + tmp_alm.grp=0; +#ifndef _ACCESS_NODE_D + parse_info<> info = parse(i->c_str(), al, space_p); //parse string i with grammar al, skipping white spaces +#else + tree_parse_info_t info = ast_parse<factory_t>(i->begin(), i->end(), al, space_p); +#endif + if (info.full) + { + LOG_STREAM << gettime().tv_sec << " Parsing succeeded: " << tmp_alm.name << endl; + for (vector<string>::iterator i = evn.begin(); i != evn.end(); i++) + LOG_STREAM << gettime().tv_sec << " READ Event! ->" << *i << endl; + } + else + { +#ifndef _ACCESS_NODE_D + LOG_STREAM << gettime().tv_sec << " Parsing failed, stopped at: " << info.stop << endl; +#else + LOG_STREAM << gettime().tv_sec << " Parsing failed, stopped at: " << string(info.stop, i->end()) << ends; //TODO +#endif + } + + if ((tmp_alm.name.empty() == false) && \ + (tmp_alm.formula.empty() == false) && \ + ((tmp_alm.lev==LEV_LOG)||(tmp_alm.lev==LEV_WARNING)|| \ + (tmp_alm.lev==LEV_FAULT)||(tmp_alm.lev.empty() == true))) + { + tmp_alm.stat = S_NORMAL; + tmp_alm.ack = ACK; + tmp_alm.done = false; + if(tmp_alm.grp == 0) + tmp_alm.grp = GR_DEFAULT; + if(tmp_alm.lev.empty() == true) + tmp_alm.lev = LEV_DEFAULT; + push_back(tmp_alm); + } else { + cerr << gettime().tv_sec << " alarm_table::init(): syntax error in '" << *i \ + << "', skipping!" << endl; + } + } + } +}*/ + +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) { + log_msg << "### alarms table: ###" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + alarm_container_t::iterator i = v_alarm.begin(); + unsigned int j = 0; + while (i != v_alarm.end()) { + log_msg << j << " - name: '" << i->second.name << "'" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + log_msg << " formula: '" << i->second.formula << "'" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + log_msg << " stat: '" << i->second.stat << "'" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + log_msg << " ack: '" << i->second.ack << "'" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + log_msg << " msg: '" << i->second.msg << "'" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + log_msg << " grp: '" << showbase << hex << i->second.grp << "'" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + log_msg << " lev: '" << i->second.lev << "'" << ends; + al_table_string.push_back(log_msg.str()); + log_msg.str(string()); + i++; + j++; + } + } +#ifndef _RW_LOCK + this->unlock(); +#else + vlock->readerOut(); +#endif +} + +unsigned int alarm_table::size(void) +{ + return(v_alarm.size()); +} + +alarm_container_t& alarm_table::get(void) +{ + return(v_alarm); +} + +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++) + { + alarm_container_t::iterator found = v_alarm.find(i->name); + if (found != v_alarm.end()) { + found->second.ts = i->ts; + found->second.stat = i->stat; + found->second.ack = i->ack; + found->second.done = i->done; + found->second.is_new = i->is_new; + } else { + /* + * shouldn't happen!!! + */ + LOG_STREAM << "alarm_table::stored(): " << i->name \ + << " NOT found in alarm table" << endl; + } + } /* for */ + } /* if */ +#ifndef _RW_LOCK + this->unlock(); +#else + vlock->readerOut(); +#endif +} + +bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, int res, string &attr_values, string grp, string msg, string formula) +{ + bool ret_changed=false; + //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()) + { + if(found->second.silenced > 0) + { + Tango::TimeVal now = gettime(); + double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000; + 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; + } + + bool status_time_threshold; + if(found->second.time_threshold > 0) //if enabled time threshold + status_time_threshold = (res) && (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 + else + status_time_threshold = res; + //if status changed: + // - from S_NORMAL to S_ALARM considering also time threshold + //or + // - from S_ALARM to S_NORMAL + if((status_time_threshold && (found->second.stat == S_NORMAL)) || (!res && (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 = res ? S_ALARM : S_NORMAL; + //a.level = found->second.lev; + if(res) + 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 = res ? found->second.msg : ""; + logloop->log_alarm_db(a); + found->second.ts = ts; /* store event timestamp into alarm timestamp */ //here update ts only if status changed + if(res) + { + 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 + { + /*try { + long call_id; + ostringstream tmp; + tmp << alm_name << ";" << attr_values; + Tango::DevString str = CORBA::string_dup(tmp.str().c_str()); + Tango::DeviceData Din; + Din << str; + CORBA::string_free(str); + //found->second.dp_a->ping(); + cmdloop->mutex_dp->lock(); + //call_id = found->second.dp_a->command_inout_asynch(found->second.cmd_action_a, Din, true); //true -> "fire and forget" mode: client do not care at all about the server answer + call_id = found->second.dp_a->command_inout_asynch(found->second.cmd_action_a, Din); //true -> "fire and forget" mode: client do not care at all about the server answer + cmdloop->mutex_dp->unlock(); + LOG_STREAM << "alarm_table::update() executed action: " << found->second.cmd_name_a << " !!!" << endl; + cmd_t arg; + arg.cmd_id = call_id; + arg.dp_add = (long)found->second.dp_a; + arg.arg_s = found->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 " << found->second.cmd_name_a << ", err=" << e.errors[0].desc << ends; + //LOG_STREAM << "alarm_table::update() ERROR: " << out_stream.str() << endl; + }*/ + ostringstream tmp; + string tmp_attr_val = attr_values; + 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; + cmd_t arg; + arg.cmd_id = CMD_COMMAND; + arg.dp_add = (long)found->second.dp_a; + arg.arg_s1 = tmp.str(); + arg.arg_s2 = found->second.cmd_action_a; + arg.arg_s3 = found->second.cmd_name_a; + arg.arg_b = found->second.send_arg_a; + cmdloop->list.push_back(arg); + } + } + else + { + if(found->second.dp_n && ((ts.tv_sec - startup_complete.tv_sec) > 10)) //action from S_ALARM to S_NORMAL + { + /*try { + long call_id; + ostringstream tmp; + tmp << alm_name << ";" << attr_values; + Tango::DevString str = CORBA::string_dup(tmp.str().c_str()); + Tango::DeviceData Din; + Din << str; + CORBA::string_free(str); + //found->second.dp_n->ping(); + cmdloop->mutex_dp->lock(); + //call_id = found->second.dp_n->command_inout_asynch(found->second.cmd_action_n, Din, true); //true -> "fire and forget" mode: client do not care at all about the server answer + call_id = found->second.dp_n->command_inout_asynch(found->second.cmd_action_n, Din); //true -> "fire and forget" mode: client do not care at all about the server answer + cmdloop->mutex_dp->unlock(); + LOG_STREAM << "alarm_table::update() executed action: " << found->second.cmd_name_n << " !!!" << endl; + cmd_t arg; + arg.cmd_id = call_id; + arg.dp_add = (long)found->second.dp_n; + arg.arg_s = found->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 " << found->second.cmd_name_n << ", err=" << e.errors[0].desc << ends; + //LOG_STREAM << "alarm_table::update() ERROR: " << out_stream.str() << endl; + }*/ + ostringstream tmp; + string tmp_attr_val = attr_values; + 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; + cmd_t arg; + arg.cmd_id = CMD_COMMAND; + arg.dp_add = (long)found->second.dp_n; + arg.arg_s1 = tmp.str(); + arg.arg_s2 = found->second.cmd_action_n; + arg.arg_s3 = found->second.cmd_name_n; + arg.arg_b = found->second.send_arg_n; + cmdloop->list.push_back(arg); + } + } + } + if (status_time_threshold) { + found->second.stat = S_ALARM; + //found->second.ack = NOT_ACK; + } + if(res) { + found->second.counter++; + } else { + 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 + + //found->second.ts = ts; /* store event timestamp into alarm timestamp */ //here update ts everytime + } else { + /* + * shouldn't happen!!!! + */ + 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; +} + +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 + + //if status changed from S_NORMAL to S_ALARM considering also time threshold + if(status_time_threshold && (i->second.stat == S_NORMAL)) + { + ret_changed = true; + 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; + } + + 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); + 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)) + { + /*try { + long call_id; + 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; + 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; + 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); + } + } + if (status_time_threshold) { + i->second.stat = S_ALARM; + //found->second.ack = NOT_ACK; + } + //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; +} + +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) +{ + alarm_container_t::iterator found = v_alarm.find(s); + if (found != v_alarm.end()) + return true; + else + return false; +} + +#ifdef _RW_LOCK +void alarm_table::new_rwlock() +{ + vlock = new(ReadersWritersLock); +} +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() +{ + cmdloop = new cmd_thread(); + cmdloop->start(); +} + +void alarm_table::stop_cmdthread() +{ + cmd_t arg; + //arg.arg_s = CMD_THREAD_EXIT; + arg.cmd_id = CMD_THREAD_EXIT; + 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) +{ + 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); +} + +void alarm_table::get_alarm_list_db(vector<string> &al_list) +{ + logloop->get_alarm_list(al_list); +} + +/* EOF */ diff --git a/src/alarm_table.h b/src/alarm_table.h new file mode 100644 index 0000000000000000000000000000000000000000..ee826948efb172d288c775de1351fc514bcfa054 --- /dev/null +++ b/src/alarm_table.h @@ -0,0 +1,212 @@ +/* + * 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 + */ + +#ifndef ALARM_TABLE_H +#define ALARM_TABLE_H + +#define _RW_LOCK + +#include <iostream> +#include <string> +#include <map> + +#include <tango.h> + +//spirit defines have to be put befor first inclusion of spirit headers +#ifndef BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT +#define BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT 2 //tmp scanner_list +#endif + +/*#ifndef BOOST_SPIRIT_THREADSAFE +#define BOOST_SPIRIT_THREADSAFE +#endif + +#ifndef PHOENIX_THREADSAFE +#define PHOENIX_THREADSAFE +#endif +*/ +//#include "spirit-parser.h" +//#include <boost/spirit/core.hpp> +#include <boost/version.hpp> +#if BOOST_VERSION < 103600 +#include <boost/spirit/tree/ast.hpp> //for ast parse trees (in tree_formula) +#else +#include <boost/spirit/include/classic_ast.hpp> //for ast parse trees (in tree_formula) +#endif + +//#include "log_thread.h" + +#define LOG_STREAM cout + +using namespace std; + +//#define _ACCESS_NODE_D 1 +#if BOOST_VERSION < 103600 +#ifndef _ACCESS_NODE_D +typedef char const* iterator_t; +typedef boost::spirit::tree_match<iterator_t> parse_tree_match_t; +typedef boost::spirit::tree_parse_info<> tree_parse_info_t; +#else +typedef std::string::iterator iterator_t; +typedef boost::spirit::node_val_data_factory<unsigned int> factory_t; //want a modified node to contain an unsigned int value +typedef boost::spirit::tree_match<iterator_t, factory_t> parse_tree_match_t; +typedef boost::spirit::tree_parse_info<iterator_t, factory_t> tree_parse_info_t; +#endif +#else +#ifndef _ACCESS_NODE_D +typedef char const* iterator_t; +typedef boost::spirit::classic::tree_match<iterator_t> parse_tree_match_t; +typedef boost::spirit::classic::tree_parse_info<> tree_parse_info_t; +#else +typedef std::string::iterator iterator_t; +typedef boost::spirit::classic::node_val_data_factory<unsigned int> factory_t; //want a modified node to contain an unsigned int value +typedef boost::spirit::classic::tree_match<iterator_t, factory_t> parse_tree_match_t; +typedef boost::spirit::classic::tree_parse_info<iterator_t, factory_t> tree_parse_info_t; +#endif +#endif + +typedef parse_tree_match_t::tree_iterator iter_t; + +#define S_NORMAL "NORMAL" +#define S_ALARM "ALARM" + +#define NOT_ACK "NACK" +#define ACK "ACK" + +#define GR_ALL 0xffffffff +#define GR_NONE 0x00000000 +#define GR_DEFAULT GR_NONE //or GR_ALL?? +//#define MAX_GRP 32 +#define GR_ALL_NAME "gr_all" +#define GR_NONE_NAME "gr_none" + +#define LEV_LOG "log" +#define LEV_WARNING "warning" +#define LEV_FAULT "fault" +#define LEV_DEFAULT LEV_FAULT + +class alarm_t; +class alarm_table; +class log_thread; +class cmd_thread; + +/* + * store the alarm-name/alarm-formula pair + */ +class alarm_t { + public: + string name, + formula; + Tango::TimeVal ts; + string stat, + ack; + unsigned int counter; + + tree_parse_info_t formula_tree; + + static map<string, unsigned int> grp_str; + + bool done; + bool to_be_evaluated; + string msg; + unsigned int grp; + 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_time_silenced; //says when it has been silenced + int silent_time; //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 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_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 + Tango::DeviceProxy *dp_n; + /* + * methods + */ + alarm_t(); //constructor + void init_static_map(vector<string> &group_names); + bool operator==(const alarm_t& that); + bool operator==(const string& n); + void str2alm(const string &s); + string alm2str(void); + string grp2str(void); + void add_grp_from_str(string &s); + void str2grp(string &s); + void insert(const string& s); + void clear(); + + protected: + private: + +}; + +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() {} + + //void init(vector<string>& avs); + //void init(vector<string>& avs, vector<string> &evn, map< string,vector<string> > &alarm_event); + void push_back(alarm_t& a); + void show(vector<string> &al_table_string); + unsigned int size(void); + alarm_container_t& get(void); + void stored(vector<alarm_t>& a); + bool update(const string& alm_name, Tango::TimeVal ts, int res, string &attr_values, string grp, string msg, string formula); + bool timer_update(); + void erase(alarm_container_t::iterator i); + bool exist(string& s); + //vector<alarm_t> v_alarm; + alarm_container_t v_alarm; +#ifdef _RW_LOCK + ReadersWritersLock *vlock; + 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 get_alarm_list_db(vector<string> &al_list); + void init_cmdthread(); + void stop_cmdthread(); + Tango::TimeVal startup_complete; //to disable action execution at startup + + protected: + private: + + log_thread *logloop; + cmd_thread *cmdloop; +}; + + +#endif /* ALARM_TABLE_H */ diff --git a/src/cmd_thread.cpp b/src/cmd_thread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21db6bc054194db4e3160337605ec9ea71cf7b85 --- /dev/null +++ b/src/cmd_thread.cpp @@ -0,0 +1,288 @@ +/* + * 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 + */ + +#include "cmd_thread.h" +static const char __FILE__rev[] = __FILE__ " $Revision: 1.3 $"; + +/* + * cmd_thread::cmd_thread() + */ +cmd_thread::cmd_thread() +{ + cout << __FILE__rev << endl; + cout << gettime().tv_sec << " cmd_thread::cmd_thread(): constructor... !" << endl; + //mutex_dp = new omni_mutex::omni_mutex(); +} + +/* + * cmd_thread::~cmd_thread() + */ +cmd_thread::~cmd_thread() +{ + cout << gettime().tv_sec << " cmd_thread::~cmd_thread(): delete device entering..." << endl; + //delete mutex_dp; +} + +/* + * cmd_thread::run() + */ +void cmd_thread::run(void *) +{ + long call_id; + while (true) { + /* + * pop_front() will wait() on condition variable + */ + try + { + cmd_t cmd = list.pop_front(); + switch(cmd.cmd_id) + { + case CMD_THREAD_EXIT: + cout << 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; + dp = (Tango::DeviceProxy *)cmd.dp_add; + if(cmd.arg_b) + { + Tango::DevString str = CORBA::string_dup(cmd.arg_s1.c_str()); + Tango::DeviceData Din; + Din << str; + CORBA::string_free(str); + //found->second.dp_a->ping(); + //call_id = dp->command_inout_asynch(cmd.arg_s2, Din, true); //true -> "fire and forget" mode: client do not care at all about the server answer + call_id = dp->command_inout_asynch(cmd.arg_s2, Din); //true -> "fire and forget" mode: client do not care at all about the server answer + } + 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; + /*cmd_t arg; + arg.cmd_id = CMD_RESPONSE; + arg.call_id = call_id; + arg.dp_add = cmd.dp_add; + arg.arg_s1 = cmd.arg_s1; + arg.arg_s2 = cmd.arg_s2; + arg.arg_s3 = cmd.arg_s3; + cmdloop->list.push_back(arg);*/ + 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) + { + 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; + } + else + { + cout << 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 + } + + } + } + break; + + case CMD_RESPONSE: + { + //cout << 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) + { + TangoSys_MemStream out_stream; + out_stream << "EXCEPTION executing action " << cmd.arg_s3 << ", err=" << e.errors[0].desc << ends; + + if(out_stream.str().find("is not yet arrived") != string::npos) //TODO: change this!! + { + + list.push_back(cmd); //if exception "not yet arrived" push in list another request of response + omni_thread::sleep(0,300000000); //0.3 s + } + else + { + cout << gettime().tv_sec << " cmd_thread::run() " << out_stream.str() << endl; + Tango::Except::print_exception(e); + } + } + } + break; + } +/* if(cmd.arg_s == CMD_THREAD_EXIT) + { + cout << 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::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) + { + TangoSys_MemStream out_stream; + out_stream << "EXCEPTION executing action " << cmd.arg_s << ", err=" << e.errors[0].desc << ends; + + if(out_stream.str().find("is not yet arrived") != string::npos) //TODO: change this!! + { + + list.push_back(cmd); + omni_thread::sleep(0,300000000); //0.2 s + } + else + cout << gettime().tv_sec << " cmd_thread::run() " << out_stream.str() << endl; + } + }*/ + + } + catch(omni_thread_fatal& ex) + { + ostringstream err; + err << "omni_thread_fatal exception running command thread, err=" << ex.error << ends; + //WARN_STREAM << "alarm_thread::run(): " << err.str() << endl; + printf("cmd_thread::run(): %s", err.str().c_str()); + } + catch(Tango::DevFailed& ex) + { + ostringstream err; + err << "exception running command thread: '" << ex.errors[0].desc << "'" << ends; + //WARN_STREAM << "alarm_thread::run(): " << err.str() << endl; + printf("cmd_thread::run(): %s", err.str().c_str()); + Tango::Except::print_exception(ex); + } + catch(...) + { + //WARN_STREAM << "alarm_thread::run(): catched unknown exception!!" << endl; + printf("cmd_thread::run(): catched unknown exception!!"); + } + } + //cout << "alarm_thread::run(): returning" << endl; +} /* cmd_thread::run() */ + +/* + * cmd_list class methods + */ +void cmd_list::push_back(cmd_t& cmd) +{ + this->lock(); + + //cout << "event_list::push_back: " << e.name << " value=" << e.value[0] << endl; + try{ + l_cmd.push_back(cmd); + empty.signal(); + } + catch(omni_thread_fatal& ex) + { + ostringstream err; + err << "omni_thread_fatal exception signaling omni_condition, err=" << ex.error << ends; + //WARN_STREAM << "event_list::push_back(): " << err.str() << endl; + printf("cmd_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 << "event_list::push_back(): " << err.str() << endl; + printf("cmd_list::push_back: %s", err.str().c_str()); + Tango::Except::print_exception(ex); + } + catch(...) + { + printf("cmd_list::push_back(): catched unknown exception signaling omni_condition!!"); + } + this->unlock(); +} + +const cmd_t cmd_list::pop_front(void) +{ + this->lock(); + //omni_mutex_lock l((omni_mutex)this); //call automatically unlock on destructor and on exception + try{ + while (l_cmd.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; + printf("cmd_list::pop_front(): %s", err.str().c_str()); + this->unlock(); + sleep(1); + cmd_t c; + return c; + } + catch(Tango::DevFailed& ex) + { + ostringstream err; + err << "exception waiting on omni_condition: '" << ex.errors[0].desc << "'" << ends; + printf("cmd_list::pop_front: %s", err.str().c_str()); + Tango::Except::print_exception(ex); + this->unlock(); + sleep(1); + cmd_t c; + return c; + } + catch(...) + { + printf("cmd_list::pop_front(): catched unknown exception waiting on omni_condition!!"); + this->unlock(); + sleep(1); + cmd_t c; + return c; + } + /*const*/ cmd_t cmd; + + cmd = *(l_cmd.begin()); + //cout << "event_list::pop_front: " << e.name << " value=" << e.value[0] << endl; + l_cmd.pop_front(); + + this->unlock(); + return cmd; +} + +void cmd_list::clear(void) +{ + //this->lock(); + l_cmd.clear(); + //this->unlock(); +} diff --git a/src/cmd_thread.h b/src/cmd_thread.h new file mode 100644 index 0000000000000000000000000000000000000000..4405122f767d29b144dd53cba66246b49a5c2c72 --- /dev/null +++ b/src/cmd_thread.h @@ -0,0 +1,85 @@ +/* + *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 + * + * + * + * 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 CMD_THREAD_H +#define CMD_THREAD_H + +#ifndef _LOGA +#define _LOGA 1 +#endif // _LOGA + +//#define CMD_THREAD_EXIT "EXIT" +#define CMD_COMMAND 1 +#define CMD_RESPONSE 2 +#define CMD_THREAD_EXIT 3 + +#include <omnithread.h> +#include <tango.h> +#include "Alarm.h" + +struct cmd_t +{ + short cmd_id; + long call_id; + string arg_s1; + string arg_s2; + string arg_s3; + bool arg_b; + long dp_add; +}; + +class cmd_list : public omni_mutex { + public: + cmd_list(void): empty(this) {} + ~cmd_list(void) {} + void push_back(cmd_t& cmd); + const cmd_t pop_front(void); + void clear(void); + protected: + list<cmd_t> l_cmd; + private: + omni_condition empty; +}; + +class cmd_thread : public omni_thread{ + public: + cmd_thread(); + ~cmd_thread(); + cmd_list list; + //omni_mutex::omni_mutex *mutex_dp; + protected: + void run(void *); + private: + Tango::DeviceProxy *dp; +}; + +#endif /* CMD_THREAD_H */ + +/* EOF */ diff --git a/src/event_table.cpp b/src/event_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..846e5cb6ed3f4187fc423d9392d76619f00e1d1e --- /dev/null +++ b/src/event_table.cpp @@ -0,0 +1,549 @@ +/* + * 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 "event_table.h" + +static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $"; + +/* + * event_list class methods + */ +void event_list::push_back(bei_t& e) +{ + this->lock(); + + try{ + l_event.push_back(e); + empty.signal(); + } + catch(omni_thread_fatal& ex) + { + ostringstream err; + err << "omni_thread_fatal exception signaling omni_condition, err=" << ex.error << ends; + //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; + //WARN_STREAM << "event_list::push_back(): " << err.str() << endl; + printf("event_list::push_back: %s", err.str().c_str()); + Tango::Except::print_exception(ex); + } + catch(...) + { + //WARN_STREAM << "event_list::push_back(): catched unknown exception!!" << endl; + printf("event_list::push_back(): catched unknown exception signaling omni_condition!!"); + } + this->unlock(); +} + +const bei_t event_list::pop_front(void) +{ + this->lock(); + //omni_mutex_lock l((omni_mutex)this); //call automatically unlock on destructor and on exception + try{ + while (l_event.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 << "event_list::pop_front(): " << err.str() << endl; + printf("event_list::pop_front(): %s", err.str().c_str()); + bei_t e; + this->unlock(); + sleep(1); + return(e); + } + catch(Tango::DevFailed& ex) + { + ostringstream err; + err << "exception waiting on omni_condition: '" << ex.errors[0].desc << "'" << ends; + //WARN_STREAM << "event_list::pop_front(): " << err.str() << endl; + printf("event_list::pop_front: %s", err.str().c_str()); + Tango::Except::print_exception(ex); + bei_t e; + this->unlock(); + sleep(1); + return(e); + } + catch(...) + { + //WARN_STREAM << "event_list::pop_front(): catched unknown exception!!" << endl; + printf("event_list::pop_front(): catched unknown exception waiting on omni_condition!!"); + bei_t e; + this->unlock(); + sleep(1); + return(e); + } + /*const*/ bei_t e; + + e = *(l_event.begin()); + + l_event.pop_front(); + + this->unlock(); + return(e); +} + +void event_list::clear(void) +{ + //this->lock(); + l_event.clear(); + //this->unlock(); +} + +list<bei_t> event_list::show(void) +{ + list<bei_t> el; + + this->lock(); + el = l_event; + this->unlock(); + return(el); +} + + +/* + * event class methods + */ +event::event(string& s, value_t& v, Tango::TimeVal& t) : \ + name(s), value(v), ts(t) +{ + const char *c = name.c_str(); + int j = 0; + int num_slashes=3; //not FQDN + if(name.find("tango://") != string::npos) //FQDN!! + num_slashes = 6; + while (*c) { + if (*c == '/') + j++; + if (j < num_slashes) + device.push_back(*c); + else if (*c != '/') + attribute.push_back(*c); + c++; + } + type = -1; + eid = 0; + err_counter = 0; + valid = false; +} + +event::event(string& s) : name(s) +{ + const char *c = name.c_str(); + int j = 0; + int num_slashes=3; //not FQDN + if(name.find("tango://") != string::npos) //FQDN!! + num_slashes = 6; + while (*c) { + if (*c == '/') + j++; + if (j < num_slashes) + device.push_back(*c); + else if (*c != '/') + attribute.push_back(*c); + c++; + } + type = -1; + eid = 0; + 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); + m_alarm.erase(it); + +} + +bool event::operator==(const event& e) +{ + return(name == e.name); +} + +bool event::operator==(const string& s) +{ + return(name == s); +} + +/* + * event_table class methods + */ +void event_table::push_back(event e) +{ + v_event.push_back(e); +} + +void event_table::show(void) +{ + DEBUG_STREAM << "events found:" << endl; + if (v_event.empty() == false) { + vector<event>::iterator i = v_event.begin(); + while (i != v_event.end()) { + DEBUG_STREAM << "\t" << i->name << endl; + i++; + } + } +} + +unsigned int event_table::size(void) +{ + return(v_event.size()); +} + +void event_table::init_proxy(void) throw(vector<string> &) +{ + vector<string> proxy_error; + if (v_event.empty() == false) { + for (vector<event>::iterator i = v_event.begin(); \ + i != v_event.end(); i++) + { + try { + i->dp = new Tango::DeviceProxy(i->device); + } catch(Tango::DevFailed& e) + { + ostringstream o; + o << "new DeviceProxy() failed for " \ + << i->device << ends; + ERROR_STREAM << o.str() << endl; + //throw o.str(); + proxy_error.push_back(o.str()); + } + } + } + if(!proxy_error.empty()) + throw proxy_error; +} + +void event_table::free_proxy(void) +{ + if (v_event.empty() == false) { + for (vector<event>::iterator i = v_event.begin(); \ + i != v_event.end(); i++) { + try{ + delete i->dp; + DEBUG_STREAM << gettime().tv_sec << " event_table::free_proxy(): deleted proxy " << i->device << endl; + } catch(...) + { + ERROR_STREAM << "event_table::free_proxy: exception deleting proxy of event: " << i->name << endl; + } + } + } +} + +void event_table::subscribe(EventCallBack& ecb) throw(vector<string> &)//throw(string&) +{ + vector<string> subscribe_error; + if (v_event.empty() == false) { + for (vector<event>::iterator i = v_event.begin(); \ + i != v_event.end(); i++) { + try { + i->eid = i->dp->subscribe_event(i->attribute, \ + Tango::CHANGE_EVENT, \ + &ecb, i->filter); + } catch (...) { + ostringstream o; + o << "subscribe_event() failed for " \ + << i->name << ends; + ERROR_STREAM << o.str() << endl; + //throw o.str(); + subscribe_error.push_back(o.str()); + } + } + } + if(!subscribe_error.empty()) + throw subscribe_error; +} + +void event_table::unsubscribe(void) throw(string&) +{ + ostringstream o; + if (v_event.empty() == false) { + for (vector<event>::iterator i = v_event.begin(); \ + i != v_event.end(); i++) { + try { + i->dp->unsubscribe_event(i->eid); + DEBUG_STREAM << gettime().tv_sec << " event_table::unsubscribe(): unsubscribed " << i->name << endl; + } catch (Tango::DevFailed& e) { + o << " unsubscribe_event() failed for " << i->name << " err=" << e.errors[0].desc; + ERROR_STREAM << gettime().tv_sec << " event_table::unsubscribe(): " << o.str() << endl; + //throw o.str(); + } catch (...) { + o << " unsubscribe_event() failed for " \ + << i->name; + ERROR_STREAM << gettime().tv_sec << " event_table::unsubscribe(): " << o.str() << endl; + //throw o.str(); + } + } + } + if(o.str().length() > 0) + throw o.str(); +} + +void event_table::update_events(bei_t &e) throw(string&) +{ + //LOG_STREAM << "event_table::update_events(bei_t &e): Entering..." << endl ; + vector<event>::iterator found = \ + find(v_event.begin(), v_event.end(), e.ev_name); + + if (found == v_event.end()) + { + //try to remove network domain and FQDN + string ev_name_str(e.ev_name); + string::size_type pos_slash = ev_name_str.find("tango://"); + if (pos_slash != string::npos) //FQDN!! + { + //first remove network domain if any + string::size_type pos_dot = ev_name_str.find(".",8); //look for first . after tango:// + string::size_type pos_colon = ev_name_str.find(":",8); //look for first : after tango:// + pos_slash = ev_name_str.find('/',8); //look for first / after tango:// + if(pos_dot < pos_slash && pos_dot != string::npos && pos_colon != string::npos && pos_slash != string::npos) //dot is in the TANGO_HOST part + { + string ev_name_str_no_domain = ev_name_str.substr(0,pos_dot) + ev_name_str.substr(pos_colon); + //LOG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without domain: " << ev_name_str_no_domain << endl; + found = \ + find(v_event.begin(), v_event.end(), ev_name_str_no_domain); + } + if (found == v_event.end() && pos_slash != string::npos) + { + ev_name_str = ev_name_str.substr(pos_slash + 1);//remove FQDN + //LOG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without fqdn: " << ev_name_str << endl; + found = \ + find(v_event.begin(), v_event.end(), ev_name_str); + } + } + if (found == v_event.end()) + { + /* + * shouldn't happen!!! + */ + ostringstream o; + o << "event_table::update_events(): event '" \ + << e.ev_name << "' not found! error=" << e.msg << ends; + ERROR_STREAM << o.str() << endl; + //cerr << o.str() << endl; + throw o.str(); + } + } + + if (found != v_event.end()) + { + found->value = e.value; + found->ts = e.ts; + found->type = e.type; + } +} + + +/* + * EventCallBack class methods + */ +EventCallBack::EventCallBack(void) +{ + e_ptr = NULL; +} + +EventCallBack::~EventCallBack(void) +{ + e_ptr = NULL; +} + +void EventCallBack::push_event(Tango::EventData* ev) +{ + string temp_name; + bei_t e; + + try { + if (!ev->err) { + +#if 0//TANGO_VER >= 711 + string ev_name_str(ev->attr_name); + string::size_type pos = ev_name_str.find("tango://"); + if (pos != string::npos) + { + pos = ev_name_str.find('/',8); + ev_name_str = ev_name_str.substr(pos + 1); + } + e.ev_name = ev_name_str.c_str(); +#else + e.ev_name = ev->attr_name; +#endif + e.ts = ev->attr_value->time; + extract_values(ev->attr_value, e.value, e.type); + } else { +#if 0//TANGO_VER >= 711 + string ev_name_str(ev->attr_name); + string::size_type pos = ev_name_str.find("tango://"); + if (pos != string::npos) + { + pos = ev_name_str.find('/',8); + ev_name_str = ev_name_str.substr(pos + 1); + } + temp_name = ev_name_str.c_str() + string(".") + ev->event; +#else + temp_name = ev->attr_name + string(".") + ev->event; //TODO: BUG IN TANGO: part of attr_name after first dot continues in field event +#endif + size_t pos_change = temp_name.find(".change"); + if(pos_change != string::npos) + { + temp_name = temp_name.substr(0,pos_change); + } + ostringstream o; + o << "Tango error for '" << temp_name << "'=" << ev->errors[0].desc.in() << ends; + e.ev_name = temp_name; + e.type = TYPE_TANGO_ERR; + //e.ev_name = INTERNAL_ERROR; + //e.type = -1; + e.msg = o.str(); + } + } + catch (string &err) { + e.msg = err + " for event '" + ev->attr_name + "'"; + e.ev_name = ev->attr_name; + e.type = TYPE_GENERIC_ERR; + //e.value.i = 0; + e.ts = gettime(); + //cerr << o.str() << endl; + } catch(Tango::DevFailed& Terr) + { + ostringstream o; + o << "Event exception for'" \ + << ev->attr_name << "' error=" << Terr.errors[0].desc << ends; + 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; + } + catch (...) { + ostringstream o; + o << "Generic Event exception for'" \ + << ev->attr_name << "'" << ends; + 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_ptr->push_back(e); +} /* push_event() */ + +void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, int &type) +{ + Tango::DevState stval; + vector<Tango::DevState> v_st; +#if TANGO_VER >= 600 + vector<Tango::DevULong> v_ulo; +#endif + vector<Tango::DevUChar> v_uch; + vector<Tango::DevShort> v_sh; + vector<Tango::DevUShort> v_ush; + vector<Tango::DevLong> v_lo; + vector<Tango::DevDouble> v_do; + vector<Tango::DevFloat> v_fl; + vector<Tango::DevBoolean> v_bo; + + if (attr_value->get_type() == Tango::DEV_UCHAR) { + *(attr_value) >> 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; + 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; + 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; + 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 + type = Tango::DEV_STATE; +#if TANGO_VER >= 600 + } else if (attr_value->get_type() == Tango::DEV_ULONG) { + *(attr_value) >> 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; + 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; + 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; + 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 { + ostringstream o; + o << "unknown type" << ends; + throw o.str(); + } +} + +void EventCallBack::init(event_list* e) +{ + e_ptr = e; +} + + +Tango::TimeVal gettime(void) +{ + struct timeval tv; + struct timezone tz; + Tango::TimeVal t; + + gettimeofday(&tv, &tz); + t.tv_sec = tv.tv_sec; + t.tv_usec = tv.tv_usec; + t.tv_nsec = 0; + return t; +} + +/* EOF */ diff --git a/src/event_table.h b/src/event_table.h new file mode 100644 index 0000000000000000000000000000000000000000..395c9ec3fe695cbd62cf970efd1b66e81f1ea696 --- /dev/null +++ b/src/event_table.h @@ -0,0 +1,144 @@ +/* + * 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 + */ + +#ifndef EVENT_TABLE_H +#define EVENT_TABLE_H + +#include <iostream> +#include <string> +#include <map> + +#include <tango.h> + + +using namespace std; + +#define INTERNAL_ERROR "internal_error" +#define TYPE_TANGO_ERR -2 +#define TYPE_GENERIC_ERR -3 + +class event; +class event_list; +class event_table; +class EventCallBack; + +typedef vector<Tango::DevDouble> value_t; + +/* + * basic event type + */ +class event { + public: + string name, /* event name */ + device, /* device name */ + attribute; /* attribute name */ + value_t value; /* event value */ + Tango::TimeVal ts; /* event timestamp */ + int type, /* attribute data type */ + counter, /* molteplicita' */ + err_counter; /* molteplicita' errore */ + //map<string, string> m_alarm; + vector<string> m_alarm; + bool valid; + + Tango::DeviceProxy *dp; + unsigned int eid; + vector<string> filter; + /* + * methods + */ + event(string& s, value_t& v, Tango::TimeVal& t); + event(string& s); + event() {} + ~event() {} + 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?? + bool operator==(const string& s); + protected: + private: +}; + +typedef struct basic_event_info_s { + string ev_name; + value_t value; + int type; + Tango::TimeVal ts; + string msg; +} bei_t; + +/* + * here the event callback handler will store the relevant + * events info coming from subscribed events for the + * processing thread + */ +class event_list : public omni_mutex { + public: + event_list(void): full(this), empty(this) {} + ~event_list(void) {} + void push_back(bei_t& e); + const bei_t pop_front(void); + void clear(void); + list<bei_t> show(void); + protected: + list<bei_t> l_event; + private: + omni_condition full, + empty; +}; + +/* + * store all the events + */ +class event_table : public event , Tango::LogAdapter { + public: + event_table(Tango::DeviceImpl *s):Tango::LogAdapter(s) {} + ~event_table(void) {} + void push_back(event e); + void show(void); + unsigned int size(void); + 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 update_events(bei_t& e) throw(string&); + vector<event> v_event; + protected: + private: +}; /* class event_table */ + + +/* + * event callback + */ +class EventCallBack : public Tango::CallBack { + public: + EventCallBack(void); + ~EventCallBack(void); + void push_event(Tango::EventData* ev); + void init(event_list* e); + void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, int &type); + private: + event_list* e_ptr; +}; + +/* + * utility function + */ +Tango::TimeVal gettime(void); + +#endif /* EVENT_TABLE_H */ diff --git a/src/formula_grammar.h b/src/formula_grammar.h new file mode 100644 index 0000000000000000000000000000000000000000..f3bc90adde35fcd81d3de02c4028680448065ff2 --- /dev/null +++ b/src/formula_grammar.h @@ -0,0 +1,291 @@ +/* + * 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 + */ +#ifndef FORMULA_GRAMMAR_H_ +#define FORMULA_GRAMMAR_H_ + + +//#define BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING //test trying to have node also if formula of type (ev/ev/ev/ev) 27/02/2008 + +#if BOOST_VERSION < 103600 +#ifndef BOOST_SPIRIT_THREADSAFE +#define BOOST_SPIRIT_THREADSAFE +#endif +#endif + +#if BOOST_VERSION < 103600 +#include <boost/spirit/core.hpp> +#include <boost/spirit/tree/ast.hpp> +using namespace boost::spirit; +#else +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_ast.hpp> +using namespace boost::spirit::classic; +#endif + //for ast parse trees (in tree_formula) +//#include <boost/spirit/symbols/symbols.hpp> //for symbol table + +using namespace std; + + + +#ifdef _ACCESS_NODE_D +/*typedef char const* iterator_t; +typedef node_val_data_factory<unsigned int> factory_t; +typedef tree_match<iterator_t, factory_t> parse_tree_match_t; +typedef tree_parse_info<iterator_t, factory_t> tree_parse_t; +typedef parse_tree_match_t::tree_iterator iter_t;*/ +typedef node_val_data<iterator_t, unsigned int> node_t; +typedef tree_node<node_t> tree_node_t; + +/*static unsigned int stat_tmp; +static void Save_Stat (unsigned int val) +{ + stat_tmp = val; +} + +static void Assign_Stat (tree_node_t & node, const iterator_t & begin, const iterator_t & end) +{ + node.value.value(stat_tmp); +}*/ + +unsigned int stat_tmp; +struct Save_Stat +{ + void operator () (unsigned int val) const + { + stat_tmp = val; + } +}; + +struct Assign_Stat +{ + void operator () (tree_node_t & node, const iterator_t & begin, const iterator_t & end) const + { + node.value.value(stat_tmp); + } +}; + +#endif //_ACCESS_NODE_D +struct formula_grammar : public grammar<formula_grammar> +{ + static const int val_rID = 1; + static const int val_hID = 2; + static const int val_stID = 3; + static const int event_ID = 4; + static const int nameID = 5; + static const int indexID = 6; + static const int funcID = 7; + static const int logical_exprID = 8; + static const int bitwise_exprID = 9; + static const int equality_exprID = 10; + static const int compare_exprID = 11; + static const int add_exprID = 12; + static const int mult_exprID = 13; + static const int expr_atomID = 14; + static const int shift_exprID = 15; + static const int unary_exprID = 16; + + symbols<unsigned int> tango_states; + + formula_grammar() + { + tango_states.add("ON", (unsigned int)Tango::ON); + tango_states.add("OFF", (unsigned int)Tango::OFF); + tango_states.add("CLOSE", (unsigned int)Tango::CLOSE); + tango_states.add("OPEN", (unsigned int)Tango::OPEN); + tango_states.add("INSERT", (unsigned int)Tango::INSERT); + tango_states.add("EXTRACT", (unsigned int)Tango::EXTRACT); + tango_states.add("MOVING", (unsigned int)Tango::MOVING); + tango_states.add("STANDBY", (unsigned int)Tango::STANDBY); + tango_states.add("FAULT", (unsigned int)Tango::FAULT); + tango_states.add("INIT", (unsigned int)Tango::INIT); + tango_states.add("RUNNING", (unsigned int)Tango::RUNNING); + tango_states.add("ALARM", (unsigned int)Tango::ALARM); + tango_states.add("DISABLE", (unsigned int)Tango::DISABLE); + tango_states.add("UNKNOWN", (unsigned int)Tango::UNKNOWN); + } + + template <typename ScannerT> + struct definition + { + +/* typedef + scanner< + typename ScannerT::iterator_t, + scanner_policies< + typename ScannerT::iteration_policy_t, + ast_match_policy< + typename ScannerT::match_policy_t::iterator_t, + typename ScannerT::match_policy_t::factory_t + >, + typename ScannerT::action_policy_t + > + > ast_scanner;*/ + + //typedef scanner_list< ScannerT, phrase_scanner_t > scanners; //try using multiple scanners + + definition(formula_grammar const& self) + { + symbol + = (alnum_p | '.' | '_' | '-' | '+') //any alpha numeric char plus '.', '_', '-', '+' + ; + //------------------------------ALARM NAME-------------------------------------- + name +#if BOOST_VERSION < 103600 + = token_node_d[ +#else + = reduced_node_d[ +#endif + lexeme_d[ //needed to ignore "space_p" (skip white spaces) evaluating name + !("tango://" >> (+symbol) >> ':' >> uint_p >> "/") //eventually match FQDN + >> (+symbol) >> '/' >> (+symbol) + >> '/' >> (+symbol) >> '/' >> (+symbol) + ] + ] +// = repeat_p(3)[(+symbol) >> ch_p('/')] >> (+symbol) + ; + index + = inner_node_d[ch_p('[') >> uint_p >> ch_p(']')] + ; + //------------------------------FORMULA-------------------------------------- + val_r +#if BOOST_VERSION < 103600 + = leaf_node_d[real_p] +#else + = reduced_node_d[real_p] +#endif + ; + val_h +#if BOOST_VERSION < 103600 + = token_node_d[(str_p("0x") >> hex_p)] //token_node_d here to create only one node with all chars +#else + = reduced_node_d[(str_p("0x") >> hex_p)] //token_node_d here to create only one node with all chars +#endif + ; + val_st + = +#ifndef _ACCESS_NODE_D + token_node_d[self.tango_states] //match only group defined in sym_grp symbol table +#else + //access_node_d[self.tango_states[&Save_Stat]][&Assign_Stat] //save Tango::state value in node + access_node_d[self.tango_states[Save_Stat()]][Assign_Stat()] //save Tango::state value in node +#endif //_ACCESS_NODE_D + ; + + event_ + = name + >> !(index) + ; + + top = logical_expr + ; + + logical_expr + = bitwise_expr + >> *( (root_node_d[str_p("&&")] >> bitwise_expr) + | (root_node_d[str_p("||")] >> bitwise_expr) + ) + ; + + bitwise_expr + = equality_expr + >> *( (root_node_d[ch_p('&')] >> equality_expr) + | (root_node_d[ch_p('|')] >> equality_expr) + | (root_node_d[ch_p('^')] >> equality_expr) + ) + ; + + equality_expr + = compare_expr + >> *( (root_node_d[str_p("==")] >> compare_expr) + | (root_node_d[str_p("!=")] >> compare_expr) + ) + ; + + compare_expr + = shift_expr + >> *( (root_node_d[str_p("<=")] >> add_expr) + | (root_node_d[str_p(">=")] >> add_expr) + | (root_node_d[ch_p('<')] >> add_expr) + | (root_node_d[ch_p('>')] >> add_expr) + ) + ; + shift_expr + = add_expr + >> *( (root_node_d[str_p("<<")] >> add_expr) + | (root_node_d[str_p(">>")] >> add_expr) + ) + ; + add_expr + = mult_expr + >> *( (root_node_d[ch_p('+')] >> mult_expr) + | (root_node_d[ch_p('-')] >> mult_expr) + ) + ; + mult_expr + = expr_atom + >> *( (root_node_d[ch_p('*')] >> expr_atom) + | (root_node_d[ch_p('/')] >> expr_atom) + ) + ; + function + = root_node_d[str_p("abs")] >> (inner_node_d[ch_p('(') >> logical_expr >> ')']) + ; + unary_expr + = ( (root_node_d[ch_p('+')] >> expr_atom) + | (root_node_d[ch_p('-')] >> expr_atom) + | (root_node_d[ch_p('!')] >> expr_atom) + ) + ; + expr_atom + = //val_h | val_r + event_ + | unary_expr + | val_h | val_r | val_st + | function + //| (inner_node_d[ch_p('(') >> logical_expr >> ')']) + | (discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')]) + | unary_expr + + ; + } + + rule<ScannerT> top; + //rule<ScannerT> symbol; + rule<typename lexeme_scanner<ScannerT>::type> symbol; //neede to use lexeme_d in rule name + rule<ScannerT, parser_context<>, parser_tag<val_rID> > val_r; + rule<ScannerT, parser_context<>, parser_tag<val_hID> > val_h; + rule<ScannerT, parser_context<>, parser_tag<val_stID> > val_st; + rule<ScannerT, parser_context<>, parser_tag<event_ID> > event_; + rule<ScannerT, parser_context<>, parser_tag<logical_exprID> > logical_expr; + rule<ScannerT, parser_context<>, parser_tag<bitwise_exprID> > bitwise_expr; + rule<ScannerT, parser_context<>, parser_tag<shift_exprID> > shift_expr; + rule<ScannerT, parser_context<>, parser_tag<equality_exprID> > equality_expr; + rule<ScannerT, parser_context<>, parser_tag<compare_exprID> > compare_expr; + rule<ScannerT, parser_context<>, parser_tag<add_exprID> > add_expr; + rule<ScannerT, parser_context<>, parser_tag<mult_exprID> > mult_expr; + rule<ScannerT, parser_context<>, parser_tag<unary_exprID> > unary_expr; + 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<indexID> > index; + + rule<ScannerT> const& + start() const { return top; } + + }; +}; + +#endif /*FORMULA_GRAMMAR_H_*/ diff --git a/src/log_thread.cpp b/src/log_thread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21ac238ba9f4dd75963ff193e14fb62d1b10291d --- /dev/null +++ b/src/log_thread.cpp @@ -0,0 +1,510 @@ +/* + * 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); +} diff --git a/src/log_thread.h b/src/log_thread.h new file mode 100644 index 0000000000000000000000000000000000000000..17ab49278206a107ed805a75667cccecea00c4c5 --- /dev/null +++ b/src/log_thread.h @@ -0,0 +1,133 @@ +/* + * 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 */ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a947974f3db58a7b8e7b47d52a2e529ef6c3143 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,88 @@ +/*----- PROTECTED REGION ID(Alarm::main.cpp) ENABLED START -----*/ +static const char *RcsId = "$Id: $"; +//============================================================================= +// +// file : main.cpp +// +// description : C++ source for the Alarm 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 +// +// This file is part of Tango device class. +// +// Tango is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Tango is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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.h> + + +int main(int argc,char *argv[]) +{ + + Tango::Util *tg; + try + { + // Initialise the device server + //---------------------------------------- + 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 + //---------------------------------------- + tg->server_init(false); + + // Run the endless loop + //---------------------------------------- + cout << "Ready to accept request" << endl; + tg->server_run(); + } + catch (bad_alloc) + { + cout << "Can't allocate memory to store device object !!!" << endl; + cout << "Exiting" << endl; + } + catch (CORBA::Exception &e) + { + Tango::Except::print_exception(e); + + cout << "Received a CORBA_Exception" << endl; + cout << "Exiting" << endl; + } + tg->server_cleanup(); + return(0); +} + + +/*----- PROTECTED REGION END -----*/ // Alarm::main.cpp diff --git a/src/update-thread.cpp b/src/update-thread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..313913e398be3abe714c5c19d3070b91824b67b5 --- /dev/null +++ b/src/update-thread.cpp @@ -0,0 +1,65 @@ +/* + * 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" +static const char __FILE__rev[] = __FILE__ " $Revision: 1.2 $"; + +/* + * alarm_thread::alarm_thread() + */ +update_thread::update_thread(Alarm_ns::Alarm *p) : p_Alarm(p) +{ + //cout << __FILE__rev << endl; +} + +/* + * alarm_thread::~alarm_thread() + */ +update_thread::~update_thread() +{ + p_Alarm = NULL; +} + +/* + * alarm_thread::run() + */ +void update_thread::run(void *) +{ + //printf("update_thread::run(): running...\n"); + unsigned int pausasec, pausanano; + pausasec=1; + pausanano = 100000000; //0.1 sec + omni_thread::sleep(pausasec,pausanano); + while (!p_Alarm->abortflag) { + try + { + omni_thread::sleep(pausasec,pausanano); + p_Alarm->timer_update(); + //printf("update_thread::run(): TIMER!!\n"); + } + catch(...) + { + printf("update_thread::run(): catched unknown exception!!\n"); + } + } + //cout << "update_thread::run(): exiting!" << endl; +} /* update_thread::run() */ diff --git a/src/update-thread.h b/src/update-thread.h new file mode 100644 index 0000000000000000000000000000000000000000..ebf71021ebd16274f603124d0987d3c11ec90aa7 --- /dev/null +++ b/src/update-thread.h @@ -0,0 +1,39 @@ +/* + * 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 + */ + +#ifndef UPDATE_THREAD_H +#define UPDATE_THREAD_H + +#include <omnithread.h> +#include <tango.h> +#include <Alarm.h> + +class update_thread : public omni_thread { + public: + update_thread(Alarm_ns::Alarm *p); + ~update_thread(); + protected: + void run(void *); + private: + Alarm_ns::Alarm *p_Alarm; +}; + +#endif /* UPDATE_THREAD_H */ + +/* EOF */