Skip to content
Snippets Groups Projects
AlarmHandler.cpp 214 KiB
Newer Older
	{
		argout->length(complete.size());
		for(size_t i=0; i<complete.size(); i++)
			(*argout)[i] = Tango::string_dup(complete[i].c_str());
	}
	else
	{
		vector<string> out;
		//out.push_back(NAME_KEY + string("=") + it->first);
		for(size_t arg_i=0; arg_i < argin->length()-1; arg_i++)
		{
			map<string,string>::iterator it2 = info.find(string((*argin)[arg_i+1]));
			if(it2 != info.end())
			{
				out.push_back(it2->first + string("=") + it2->second);
			}
		}
		argout->length(out.size()/*+1*/);
		vector<string>::iterator it3;
		size_t i=0;
		for(it3=out.begin(); it3!=out.end(); it3++)
		{
			(*argout)[i] = Tango::string_dup(it3->c_str());
			i++;
		}
	}
	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::get_alarm_info
	return argout;
}
//--------------------------------------------------------
/**
 *	Command ReLoadAll related method
 *	Description: Re Load all alarms.
 *
 */
//--------------------------------------------------------
void AlarmHandler::re_load_all()
{
	DEBUG_STREAM << "AlarmHandler::ReLoadAll()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(AlarmHandler::re_load_all) ENABLED START -----*/
	//	Add your own code
	vector<string> tmp_alm_vec;
	alarms.get_alarm_list_db(tmp_alm_vec, saved_alarms, savedlock);//holds write locks savedlock
	for(const auto &it_al : tmp_alm_vec)
	{
		bool modify_err=false;
		try
		{
			modify((Tango::DevString)it_al.c_str());
		}
		catch(Tango::DevFailed &e)
		{
			INFO_STREAM << __func__ << ": error modifying '" << it_al << "' err='" << e.errors[0].desc << "'";
			modify_err=true;		
		}
		if(modify_err)
		{
			try
			{
				load((Tango::DevString)it_al.c_str());
			}
			catch(Tango::DevFailed &e)
			{
				INFO_STREAM << __func__ << ": error loading '" << it_al << "' err='" << e.errors[0].desc << "'";
			}
		}
	}
	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::re_load_all
}
//--------------------------------------------------------
 *	Method      : AlarmHandler::add_dynamic_commands()
 *	Description : Create the dynamic commands if any
 *                for specified device.
 */
//--------------------------------------------------------
void AlarmHandler::add_dynamic_commands()
	/*----- PROTECTED REGION ID(AlarmHandler::add_dynamic_commands) ENABLED START -----*/
	
	//	Add your own code to create and add dynamic commands if any
	
	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::add_dynamic_commands
/*----- PROTECTED REGION ID(AlarmHandler::namespace_ending) ENABLED START -----*/
void AlarmHandler::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
	DEBUG_STREAM << "AlarmHandler::load_alarm(): Creating Spirit Parser... ->" << alarm_string << endl;
	alarm_parse al_gr(alm);    //  Construct Spirit grammar		
	alm.name.clear();
	alm.quality = Tango::ATTR_INVALID;
	alm.ex_reason=string("NOT_SUBSCRIBED");
	alm.ex_desc=string("One or more events not subscribed");
	alm.error = false;
	alm.ts_err_delay = gettime();
	alm.ts_err_delay.tv_sec -= errorDelay;
	alm.err_counter = 0;
	alm.url.clear();
	alm.lev.clear();
	alm.grp=0;
	alm.to_be_evaluated = false;
	alm.on_delay = 0;
	alm.off_delay = 0;
	alm.silent_time = -1;
	alm.silenced = -1;
	alm.cmd_name_a.clear();
	alm.cmd_dp_a.clear();
	alm.cmd_action_a.clear();
	alm.send_arg_a = false;
	alm.dp_a = NULL;	
	alm.cmd_name_n.clear();
	alm.cmd_dp_n.clear();
	alm.cmd_action_n.clear();
	alm.send_arg_n = false;	
	alm.dp_n = NULL;
	evn.clear();	

	alm.formula_tree = 
	//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
	ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p);	//parse string s with grammar al_gr, skipping white spaces
	if (alm.formula_tree.full)
	{
    	std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower);		//transform to lowercase
    	//replace / with __
    	if(!alm.name.empty())
    	{
    		alm.attr_name = alm.name;
			alm.attr_name = std::regex_replace(alm.attr_name, std::regex("/"), "_");
    	//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower);		//transform to lowercase: incorrect, state has to be written uppercase
    	std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower);		//transform to lowercase
		alm.msg = std::regex_replace(alm.msg, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
		alm.url = std::regex_replace(alm.url, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
    	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;
	else
	{
		ostringstream o;
		o << "AlarmHandler::load_alarm(): Parsing Failed, '" << string(alarm_string.begin(), alm.formula_tree.stop) << "' parsed ok, BUT '" << string(alm.formula_tree.stop, alarm_string.end()) << "' not parsed"; //TODO
		DEBUG_STREAM << o.str() << endl;
		Tango::Except::throw_exception( \
			(const char*)"Parsing Failed!", \
			(const char*)o.str().c_str(), \
			(const char*)"AlarmHandler::load_alarm()", Tango::ERR);
	}
	DEBUG_STREAM << "AlarmHandler::load_alarm(): name     = '" << alm.name << "'" << endl;
	DEBUG_STREAM << "               attr_name      = '" << alm.attr_name << "'" << endl;
	DEBUG_STREAM << "               formula        = '" << alm.formula << "'" << endl;
	DEBUG_STREAM << "               on_delay       = '" << alm.on_delay << "'" << endl;
	DEBUG_STREAM << "               off_delay      = '" << alm.off_delay << "'" << endl;
	DEBUG_STREAM << "               msg            = '" << alm.msg << "'" << endl;
	DEBUG_STREAM << "               url            = '" << alm.url << "'" << endl;
	DEBUG_STREAM << "               grp            = '" << showbase << hex << alm.grp << "'=" << alm.grp2str() << endl;
	DEBUG_STREAM << "               silent_time    = '" << alm.silent_time << "'" << endl;
	DEBUG_STREAM << "               silenced       = '" << alm.silenced << "'" << endl;
	DEBUG_STREAM << "               lev            = '" << alm.lev << "'" << endl;
	DEBUG_STREAM << "               action_a       = '" << alm.cmd_name_a << "'" << endl;	
	DEBUG_STREAM << "               action_n       = '" << alm.cmd_name_n << "'" << endl;
	DEBUG_STREAM << "               enabled        = '" << (alm.enabled ? "1" : "0") << "'" << endl;
	if ((alm.name.empty() == false) && \
			(alm.formula.empty() == false) && \
			(alm.msg.empty() == false) && \
			((alm.lev==LEV_LOG)||(alm.lev==LEV_WARNING)|| \
			(alm.lev==LEV_FAULT)||(alm.lev==LEV_LOWEST)||(alm.lev==LEV_LOW)|| \
			(alm.lev==LEV_MEDIUM)||(alm.lev==LEV_HIGH)||(alm.lev==LEV_HIGHEST)||(alm.lev.empty() == true))) {
		alm.stat = S_NORMAL;
		alm.ack = ACK;
		alm.done = false;
//		alm.grp = GR_DEFAULT;
//		alm.lev = LEV_DEFAULT;
	} else {
		ostringstream o;
		o << "AlarmHandler::load_alarm(): syntax error in '" << alarm_string << "'";
		WARN_STREAM << o.str() << endl;
	
		Tango::Except::throw_exception( \
				(const char*)o.str().c_str(), \
				(const char*)"", \
				(const char*)"AlarmHandler::load_alarm()", Tango::ERR);
		o << "AlarmHandler::load_alarm(): alarm '" << alm.name << "' already exist";
		WARN_STREAM << o.str() << endl;
		Tango::Except::throw_exception( \
				(const char*)o.str().c_str(), \
				(const char*)o.str().c_str(), \
				(const char*)"AlarmHandler::load_alarm()", Tango::ERR);
void AlarmHandler::init_alarms(map< string,vector<string> > &alarm_events)
{
	alarms.vlock->readerIn();
	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 << "AlarmHandler::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 << "AlarmHandler::init_alarms(): looking in events table for Event= " << (*j) << endl;
				if (found != events->v_event.end())
				{
					i->second.insert(found->name);
					found->m_alarm.push(i->second.name);
					DEBUG_STREAM << "AlarmHandler::init_alarms(): found Event= " << found->name << " <- Alarm= " << i->second.name << endl;
void AlarmHandler::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()) {
			//TODOevents->push_back(event(*j));
void AlarmHandler::add_alarm(alarm_t& a, bool starting)
	alarms.push_back(a);	//take and release writer vlock
	DEBUG_STREAM << "AlarmHandler::add_alarm(): added alarm '" \
Graziano Scalamera's avatar
Graziano Scalamera committed
	if(!starting)
	{
		alarms.vlock->readerIn();
Graziano Scalamera's avatar
Graziano Scalamera committed
		alarm_container_t::iterator italm = alarms.v_alarm.find(a.name);
		add_AlarmState_dynamic_attribute(italm->second.attr_name);
		Tango::DevEnum *attr_value = get_AlarmState_data_ptr(italm->second.attr_name);
		italm->second.attr_value = attr_value;

		italm->second.attr_name_formula = italm->second.attr_name + string("Formula");
#if _FORMULA_ATTR
		add_AlarmFormula_dynamic_attribute(italm->second.attr_name_formula);
		Tango::DevString *attr_value_formula = get_AlarmFormula_data_ptr(italm->second.attr_name_formula);
		*attr_value_formula = Tango::string_dup(italm->second.formula.c_str());
		italm->second.attr_value_formula = attr_value_formula;
#endif
		alarms.vlock->readerOut();
void AlarmHandler::add_event(alarm_t& a, vector<string> &evn) throw(string&)
	DEBUG_STREAM << "AlarmHandler::add_event(): formula '" << a.formula << "' found " << evn.size() << " events" << 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())	//if not already present
		{
			string name=*j;
			vector<string> context;//TODO
			events->add(name, context, UPDATE_PROP, false);//throws exception if already present
		}
	}

	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->m_alarm.push(a.name);
			DEBUG_STREAM << "AlarmHandler::add_event(): '" << *j << "' found, added " \
									 << " alarm '"  << a.name << "' to list, valid=" << k->valid << endl;
			alarms.vlock->readerIn();
			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 << "AlarmHandler::add_event():	error inserting event '" << *j << "' in set of alarm '"
							<< a.name << "'" << endl;
			}
			alarms.vlock->readerOut();
		} 
		else 
		{
			/*
			 * new event; add to event table
			 */
			//event e(*j);
			//events->push_back(e);
			DEBUG_STREAM << "AlarmHandler::add_event(): adding '" << *j \
									 << "' to event list of alarm '" << a.name << "'" << endl;
			alarms.vlock->readerIn();
			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 << "AlarmHandler::add_event():	error inserting event '" << *j << "' in set of alarm '"
							<< a.name << "'" << endl;
			}
			alarms.vlock->readerOut();
			/*
			 * now, for the just-added event
			 */
			k = find(events->v_event.begin(), events->v_event.end(), *j);
			if (k != events->v_event.end())
			{
				k->m_alarm.push(a.name);
				//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->read_size);
					msg << "AlarmHandler::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->m_alarm.pop(a.name);		//remove alarm/formula just added to event
					//events->v_event.pop_back();
					events->v_event.erase(k);	//remove event just added to event_table
					//delete attr_value;
#endif										
					throw out_stream.str();
				} catch(string & e) 
				{
					TangoSys_MemStream out_stream;
					out_stream << "Error reading initial value of " << k->name << " = " << e << ends;
					k->m_alarm.pop(a.name);		//remove alarm/formula just added to event
					//events->v_event.pop_back();
					events->v_event.erase(k);	//remove event just added to event_table
					//delete attr_value;					
					throw out_stream.str();
				}
			}
		}
	} //for (vector<string>::iterator j = evn.begin(); ...

	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 already present
			string name=*j;
			events->start(name);//throws exception if not found
		}
	}
/*
 * because called asynchronously by alarm evaluating thread
 * will use an alarm to report errors
 */
void AlarmHandler::do_alarm(bei_t& e)
	if(e.type == TYPE_TANGO_ERR || e.type == TYPE_GENERIC_ERR)
	{
		WARN_STREAM << "AlarmHandler::"<<__func__<<": " <<  o.str() << endl;
		events->veclock.readerIn();
		vector<event>::iterator found_ev = \
			find(events->v_event.begin(), events->v_event.end(), e.ev_name);
		if (found_ev == events->v_event.end())
		{
			//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 << "AlarmHandler::"<<__func__<<": 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 << "AlarmHandler::"<<__func__<<": 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!";
				WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
				set_internal_alarm(e.ev_name, gettime(), o.str());
			}
		}
		if(found_ev != events->v_event.end())
		{
			Tango::TimeVal ts = gettime();
			if(e.type == TYPE_TANGO_ERR)
				found_ev->ex_reason = string("Event_ERROR");
			else
				found_ev->ex_reason = string("Alarm_ERROR");
			found_ev->ex_desc = o.str();
			found_ev->ex_origin = e.ev_name;
			found_ev->quality = e.quality;
			//LOOP ALARMS IN WHICH THIS EVENT IS USED
			list<string> m_alarm=found_ev->m_alarm.show();
			string found_ev_ex_reason = found_ev->ex_reason;
			string found_ev_ex_desc = found_ev->ex_desc;
			string found_ev_ex_origin = found_ev->ex_origin;
			events->veclock.readerOut();
			list<string>::iterator j = m_alarm.begin();
			while (j != m_alarm.end())
			{
				alarms.vlock->readerIn();
				alarm_container_t::iterator it = alarms.v_alarm.find(*j);
				if(it != alarms.v_alarm.end())
				{
					it->second.err_counter++;
					//if first error, reset ACK
					if(it->second.ex_reason.empty() && it->second.ex_desc.empty() && it->second.ex_origin.empty())
					{
						it->second.ack = NOT_ACK;
						it->second.ts_err_delay = gettime();		//first occurrance of this error, now begin to wait for err delay
					if(e.type == TYPE_TANGO_ERR)
						it->second.ex_reason = found_ev_ex_reason;
						it->second.ex_reason = found_ev_ex_reason;
					it->second.ex_desc = found_ev_ex_desc;
					it->second.ex_origin = found_ev_ex_origin;
					if(errorDelay > 0)
						if((ts.tv_sec - errorDelay) > it->second.ts_err_delay.tv_sec)	//error is present and err delay has passed
						{
							if(!it->second.error)
								it->second.is_new = 1;
							it->second.error = true;
					{
						if(!it->second.error)
							it->second.is_new = 1;
						it->second.error = true;
					}
					alarm_t alm = it->second;
					alarms.vlock->readerOut();
					try
					{
						Tango::DevErrorList errors(1);
						errors.length(1);
						errors[0].desc = CORBA::string_dup(alm.ex_desc.c_str());
						errors[0].reason = CORBA::string_dup(alm.ex_reason.c_str());
						errors[0].origin = CORBA::string_dup(alm.ex_origin.c_str());
						DEBUG_STREAM << "AlarmHandler::"<<__func__<<": PUSHING EXCEPTION FOR " << alm.attr_name << " " << alm.ex_desc << "-" << alm.ex_reason << "-" << alm.ex_origin << endl;
						push_change_event(alm.attr_name, &except);
						push_archive_event(alm.attr_name, &except);
				else
				{
					alarms.vlock->readerOut();
				}
				j++;
			prepare_alarm_attr();//TODO: frequencyAlarm should be updated anyway
			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);
			}
			push_change_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
			push_change_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
			push_change_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
			push_change_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
			push_change_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
			push_change_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
			push_change_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
			push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
			push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
			push_change_event("alarmAudible",attr_alarmAudible_read);
			push_change_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
			push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
			push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
			push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
			push_archive_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
			push_archive_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
			push_archive_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
			push_archive_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
			push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
			push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
			push_archive_event("alarmAudible",attr_alarmAudible_read);
			push_archive_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
	DEBUG_STREAM << "AlarmHandler::"<<__func__<<": arrived event=" << e.ev_name << endl;
	events->veclock.readerIn();
	vector<event>::iterator found = \
			find(events->v_event.begin(), events->v_event.end(), e.ev_name);
	if (found == events->v_event.end())
	{
		//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 << "AlarmHandler::"<<__func__<<": 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 << "AlarmHandler::"<<__func__<<": 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!";
			WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
			set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
		}
	}
	if (found != events->v_event.end())
	{	
		found->value = e.value;
		found->value_string = e.value_string;
		found->quality = e.quality;
		//found->errors = e.errors;
		found->ex_reason = e.ex_reason;
		found->ex_desc = e.ex_desc;
		found->ex_origin = e.ex_origin;
		found->valid = true;
		found->ts = e.ts;
		found->type = e.type;
		found->read_size = e.read_size;
		list<string> m_alarm=found->m_alarm.show();
		Tango::TimeVal ts = found->ts;
		events->veclock.readerOut(); //do not hold events->veclock in do_alarm_eval which push events
		list<string>::iterator j = m_alarm.begin();
		while (j != m_alarm.end()) 
			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": before do_alarm_eval name=" << *j << " ev=" << e.ev_name << endl;
			changed = do_alarm_eval(*j, e.ev_name, ts);
		{
			alarms.vlock->readerIn();
			prepare_alm_mtx->lock();
			alarm_container_t::iterator ai;
			size_t freq_ind = 0;
			for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++)
			{
				attr_alarmFrequency_read[freq_ind] = ai->second.freq_counter;
				freq_ind++;
			}
			prepare_alm_mtx->unlock();
			alarms.vlock->readerOut();
			push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
			push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
		prepare_alarm_attr();//TODO: frequencyAlarm should be updated anyway
		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);
		push_change_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
		push_change_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
		push_change_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
		push_change_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
		push_change_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
		push_change_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
		push_change_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
		push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
		push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
		push_change_event("alarmAudible",attr_alarmAudible_read);
		push_change_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
		push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
		push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
		push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
		push_archive_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
		push_archive_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
		push_archive_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
		push_archive_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
		push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
		push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
		push_archive_event("alarmAudible",attr_alarmAudible_read);
		push_archive_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
		DEBUG_STREAM << "AlarmHandler::"<<__func__<<": event=" << e.ev_name << "NOT FOUND IN EVENT TABLE" << endl;
bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal ts)
	bool prev_error = false;
	formula_res_t res;
	//alarm_container_t::iterator it = alarms.v_alarm.find(j->first);
	alarms.vlock->readerIn();
	alarm_container_t::iterator it = alarms.v_alarm.find(alm_name);
	if(it != alarms.v_alarm.end())
	{
		string attr_name = it->second.attr_name;
		if(ev_name == "FORCED_EVAL" && !it->second.to_be_evaluated)
		{
			DEBUG_STREAM << __func__ << ": ev_name=" << ev_name << " -> FORCED_EVAL && !it->second.to_be_evaluated -> changed=false" << endl;
			alarms.vlock->readerOut();
			return 	false;
		}
		if(ev_name != "FORCED_EVAL")
				it->second.freq_counter++;
		string ex_reason = it->second.ex_reason;
		string ex_desc = it->second.ex_desc;
		string ex_origin = it->second.ex_origin;
		prev_error = it->second.error;
		if(prev_error)
		{
			prev_error = true;
			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": before evaluating exception {"<<ex_reason<<","<<ex_desc.length()<<","<<ex_origin<<"}"<<endl;
			it->second.attr_values = string("{");
			res = eval_formula(it->second.formula_tree, it->second.attr_values);
			it->second.to_be_evaluated = false;
			it->second.attr_values.erase(it->second.attr_values.size()-1);
			it->second.attr_values += string("}");
			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": Evaluation of " << it->second.formula << "; result=" << res.value << " quality=" << res.quality << endl;
			changed = alarms.update(tmpname, ts, res, it->second.attr_values, it->second.grp2str(), it->second.msg, it->second.formula); 		//update internal structure and log to db
			changed = changed || prev_error;
			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": changed=" << (int)changed << endl;
			Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
			if(!it->second.enabled)
				*attr_value = _OOSRV;
			else if(it->second.shelved && it->second.silenced > 0)
				*attr_value = _SHLVD;
			else if((it->second.stat == S_NORMAL) && it->second.ack == ACK)
				*attr_value = _NORM;
			else if((it->second.stat == S_ALARM) && it->second.ack == NOT_ACK)
				*attr_value = _UNACK;
			else if((it->second.stat == S_ALARM) && it->second.ack == ACK)
				*attr_value = _ACKED;
			else if((it->second.stat == S_NORMAL) && it->second.ack == NOT_ACK)
				*attr_value = _RTNUN;
			Tango::AttrQuality quality = (Tango::AttrQuality)it->second.quality;
Graziano Scalamera's avatar
Graziano Scalamera committed
			ex_reason = it->second.ex_reason;	//copying again because updated with formula result res.ex_reason in alarms.update
			ex_desc = it->second.ex_desc;
			ex_origin = it->second.ex_origin;
			alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
				if(!it->second.error)
					timeval now;
					gettimeofday(&now, NULL);
					push_change_event(attr_name,(Tango::DevEnum *)attr_value,now,quality, 1/*size*/, 0, false);
					push_archive_event(attr_name,(Tango::DevEnum *)attr_value,now,quality, 1/*size*/, 0, false);
					Tango::DevErrorList errors(1);
					errors.length(1);
					errors[0].desc = CORBA::string_dup(ex_desc.c_str());
					errors[0].reason = CORBA::string_dup(ex_reason.c_str());
					errors[0].origin = CORBA::string_dup(ex_origin.c_str());
					push_change_event(attr_name, &except);
					push_archive_event(attr_name, &except);
				WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
			changed = !prev_error;
			it->second.to_be_evaluated = true;
			o << tmpname << ": in formula array index out of range!";
			WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
			set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
			try
			{	//DevFailed for push events
				Tango::DevErrorList errors(1);
				errors.length(1);
				it->second.ex_reason = string("OUT_OF_RANGE");
				it->second.ex_desc = ev_name + ": " + o.str();
				it->second.ex_origin = ev_name;
				errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
				errors[0].severity = Tango::ERR;
				errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
				errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
				Tango::DevFailed except(errors);
				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
				push_change_event(attr_name, &except);
				push_archive_event(attr_name, &except);
				WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
			changed = !prev_error;
			it->second.to_be_evaluated = true;
			o << tmpname << ": in formula err=" << ex;
			WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
			set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
			try
			{	//DevFailed for push events
				Tango::DevErrorList errors(1);
				errors.length(1);
				it->second.ex_reason = string("FORMULA_ERROR");
				it->second.ex_desc = ev_name + ": " + o.str();
				it->second.ex_origin = ev_name;
				errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
				errors[0].severity = Tango::ERR;
				errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
				errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
				Tango::DevFailed except(errors);
				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
				push_change_event(attr_name, &except);
				push_archive_event(attr_name, &except);
				WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
	}
	else
	{
		ostringstream o;
		//o << j->first << ": not found formula in alarm table" << ends;
		o << (alm_name) << ": not found formula in alarm table";
		WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
		set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
#if 0	//TODO: attribute not existing -> cannot notify error pushing exception
		try
		{	//DevFailed for push events
			Tango::DevErrorList errors(1);
			errors.length(1);
			string ex_reason = string("NOT_FOUND");
			string ex_desc = ev_name + ": " + o.str();
			string ex_origin = ev_name;
			errors[0].desc = CORBA::string_dup(ex_desc.c_str());
			errors[0].reason = CORBA::string_dup(ex_reason.c_str());
			errors[0].origin = CORBA::string_dup(ex_origin.c_str());
			//push_change_event(it->second.attr_name, &except);
			//push_archive_event(it->second.attr_name, &except);
			WARN_STREAM << "AlarmHandler::"<<__func__<<": EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
	//alarms.vlock->readerOut();
void AlarmHandler::timer_update()
	//DEBUG_STREAM << "AlarmHandler::timer_update(): entering..." << endl;
	try {
		changed=alarms.timer_update();
	} catch(string & e)
	{
		ostringstream o;
		o << "Error checking time thresholds and updating alarm status=" << e;
		WARN_STREAM << "AlarmHandler::timer_update(): " << o.str() << endl;
		set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
/*		Tango::DevErrorList errors(1);
		errors.length(1);
		it->second.ex_reason = string("INTERNAL_ERROR");
		it->second.ex_desc = o.str();
		it->second.ex_origin = string("AlarmHandler::timer_update");
		errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
		errors[0].severity = Tango::ERR;
		errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
		errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
		Tango::DevFailed except(errors);
		push_change_event(it->second.attr_name, &except);
		push_archive_event(it->second.attr_name, &except);*/
	prepare_alarm_attr();//TODO: frequencyAlarm should be updated anyway
	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);
		push_change_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
		push_change_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
		push_change_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
		push_change_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
		push_change_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
		push_change_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
		push_change_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
		push_change_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
		push_change_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
		push_change_event("alarmAudible",attr_alarmAudible_read);
		push_change_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
		push_archive_event("alarmNormal",&attr_alarmNormal_read[0], normalAlarms_sz);
		push_archive_event("alarmUnacknowledged",&attr_alarmUnacknowledged_read[0], unacknowledgedAlarms_sz);
		push_archive_event("alarmAcknowledged",&attr_alarmAcknowledged_read[0], acknowledgedAlarms_sz);
		push_archive_event("alarmUnacknowledgedNormal",&attr_alarmUnacknowledgedNormal_read[0], unacknowledgedNormalAlarms_sz);
		push_archive_event("alarmShelved",&attr_alarmShelved_read[0], shelvedAlarms_sz);
		push_archive_event("alarmOutOfService",&attr_alarmOutOfService_read[0], outOfServiceAlarms_sz);
		push_archive_event("alarmSilenced",&attr_alarmSilenced_read[0], silencedAlarms_sz);
		push_archive_event("alarmList",&attr_alarmList_read[0], listAlarms_sz);
		push_archive_event("alarmFrequency",&attr_alarmFrequency_read[0], listAlarms_sz);
		push_archive_event("alarmAudible",attr_alarmAudible_read);
		push_archive_event("alarmSummary",attr_alarmSummary_read, alarmSummary_sz);
	} catch(Tango::DevFailed& e)
	{
		ostringstream err;
		err << "error pushing alarm change event err=" << e.errors[0].desc;
		INFO_STREAM << __func__<<": " << err.str() << endl;
	}
}

bool AlarmHandler::remove_alarm(string& s) throw(string&)
	DEBUG_STREAM << "AlarmHandler::"<<__func__<<": entering alm name=" << s << endl;
	alarms.vlock->writerIn();
	alarm_container_t::iterator i = alarms.v_alarm.find(s);
	if (i != alarms.v_alarm.end()) {
		DEBUG_STREAM << "AlarmHandler::"<<__func__<<": found in table alm name=" << s << endl;
		for (set<string>::iterator j = i->second.s_event.begin(); \
				 j != i->second.s_event.end(); j++) {
			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": looping event =" << *j << endl;