From e400429486c92a3b8e7533d5b973acc14bb32bc5 Mon Sep 17 00:00:00 2001
From: gscalamera <graziano.scalamera@elettra.eu>
Date: Fri, 12 Feb 2021 10:14:05 +0100
Subject: [PATCH] Add eventList and eventSummary attributes

---
 src/AlarmHandler.cpp             |  73 +++++++++++++-
 src/AlarmHandler.h               |  27 +++++
 src/AlarmHandler.xmi             |  16 +++
 src/AlarmHandlerClass.cpp        |  52 ++++++++++
 src/AlarmHandlerClass.h          |  26 +++++
 src/AlarmHandlerStateMachine.cpp |  32 ++++++
 src/SubscribeThread.cpp          |   4 +-
 src/alarm_grammar.h              |   4 +-
 src/event_table.cpp              | 166 +++++++++++++++++++++++--------
 src/event_table.h                |   7 +-
 src/formula_grammar.h            |  17 ++--
 11 files changed, 365 insertions(+), 59 deletions(-)

diff --git a/src/AlarmHandler.cpp b/src/AlarmHandler.cpp
index d1504be..62a0b4f 100644
--- a/src/AlarmHandler.cpp
+++ b/src/AlarmHandler.cpp
@@ -128,6 +128,8 @@ static const char __FILE__rev[] = __FILE__ " $Revision: 1.29 $";
 //  alarmList                  |  Tango::DevString	Spectrum  ( max = 10000)
 //  alarmFrequency             |  Tango::DevDouble	Spectrum  ( max = 10000)
 //  alarmSummary               |  Tango::DevString	Spectrum  ( max = 10000)
+//  eventList                  |  Tango::DevString	Spectrum  ( max = 10000)
+//  eventSummary               |  Tango::DevString	Spectrum  ( max = 10000)
 //================================================================
 
 namespace AlarmHandler_ns
@@ -334,6 +336,8 @@ void AlarmHandler::delete_device()
 	delete[] attr_alarmList_read;
 	delete[] attr_alarmFrequency_read;
 	delete[] attr_alarmSummary_read;
+	delete[] attr_eventList_read;
+	delete[] attr_eventSummary_read;
 }
 
 //--------------------------------------------------------
@@ -388,6 +392,8 @@ void AlarmHandler::init_device()
 	attr_alarmList_read = new Tango::DevString[10000];
 	attr_alarmFrequency_read = new Tango::DevDouble[10000];
 	attr_alarmSummary_read = new Tango::DevString[10000];
+	attr_eventList_read = new Tango::DevString[10000];
+	attr_eventSummary_read = new Tango::DevString[10000];
 	/*----- PROTECTED REGION ID(AlarmHandler::init_device) ENABLED START -----*/
 /*	for(size_t i=0; i<MAX_ALARMS; i++)
 	{
@@ -1157,6 +1163,44 @@ void AlarmHandler::read_alarmSummary(Tango::Attribute &attr)
 	
 	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::read_alarmSummary
 }
+//--------------------------------------------------------
+/**
+ *	Read attribute eventList related method
+ *	Description: List of all subscribed attributes
+ *
+ *	Data type:	Tango::DevString
+ *	Attr type:	Spectrum max = 10000
+ */
+//--------------------------------------------------------
+void AlarmHandler::read_eventList(Tango::Attribute &attr)
+{
+	//DEBUG_STREAM << "AlarmHandler::read_eventList(Tango::Attribute &attr) entering... " << endl;
+	/*----- PROTECTED REGION ID(AlarmHandler::read_eventList) ENABLED START -----*/
+	prepare_event_list();
+	//	Set the attribute value
+	attr.set_value(attr_eventList_read, eventList_sz);
+	
+	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::read_eventList
+}
+//--------------------------------------------------------
+/**
+ *	Read attribute eventSummary related method
+ *	Description: 
+ *
+ *	Data type:	Tango::DevString
+ *	Attr type:	Spectrum max = 10000
+ */
+//--------------------------------------------------------
+void AlarmHandler::read_eventSummary(Tango::Attribute &attr)
+{
+	//DEBUG_STREAM << "AlarmHandler::read_eventSummary(Tango::Attribute &attr) entering... " << endl;
+	/*----- PROTECTED REGION ID(AlarmHandler::read_eventSummary) ENABLED START -----*/
+	prepare_event_summary();
+	//	Set the attribute value
+	attr.set_value(attr_eventSummary_read, eventSummary_sz);
+	
+	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::read_eventSummary
+}
 
 //--------------------------------------------------------
 /**
@@ -3401,7 +3445,7 @@ void AlarmHandler::do_alarm(bei_t& e)
 	if(e.type == TYPE_TANGO_ERR || e.type == TYPE_GENERIC_ERR)
 	{
 		ostringstream o;
-		o << e.msg << endl;
+		o << e.msg;
 		WARN_STREAM << "AlarmHandler::"<<__func__<<": " <<  o.str() << endl;
 		vector<event>::iterator found_ev = \
 			find(events->v_event.begin(), events->v_event.end(), e.ev_name);
@@ -3454,6 +3498,7 @@ void AlarmHandler::do_alarm(bei_t& e)
 				found_ev->ex_reason = string("Alarm_ERROR");
 			found_ev->ex_desc = o.str();
 			found_ev->ex_origin = e.ev_name;
+			found_ev->quality = e.quality;
 			//LOOP ALARMS IN WHICH THIS EVENT IS USED
 			list<string> m_alarm=found_ev->m_alarm.show();
 			list<string>::iterator j = m_alarm.begin();
@@ -5332,6 +5377,32 @@ void AlarmHandler::prepare_alarm_attr()
 	dslock->writerOut();
 }
 
+void AlarmHandler::prepare_event_list()
+{
+	eventList_sz=0;
+	list<string> evl;
+	events->show(evl);
+	for(auto &ev : evl)
+	{
+		eventList_read[eventList_sz] = ev;
+		attr_eventList_read[eventList_sz] = const_cast<char*>(eventList_read[eventList_sz].c_str());
+		eventList_sz++;
+	}
+}
+
+void AlarmHandler::prepare_event_summary()
+{
+	eventSummary_sz=0;
+	list<string> evs;
+	events->summary(evs);
+	for(auto &ev : evs)
+	{
+		eventSummary_read[eventSummary_sz] = ev;
+		attr_eventSummary_read[eventSummary_sz] = const_cast<char*>(eventSummary_read[eventSummary_sz].c_str());
+		eventSummary_sz++;
+	}
+}
+
 //=============================================================================
 string AlarmHandler::remove_domain(string str)
 {
diff --git a/src/AlarmHandler.h b/src/AlarmHandler.h
index c484aa2..9f670fd 100644
--- a/src/AlarmHandler.h
+++ b/src/AlarmHandler.h
@@ -115,6 +115,8 @@ public:
 	string silencedAlarms_read[MAX_ALARMS];
 	string listAlarms_read[MAX_ALARMS];
 	string alarmSummary_read[MAX_ALARMS];
+	string eventList_read[MAX_ATTR_SUMMARY];
+	string eventSummary_read[MAX_ATTR_SUMMARY];
 
 /*	char c_normalAlarms_read[MAX_ALARMS][MAX_ATTR_NAME];
 	char c_unacknowledgedAlarms_read[MAX_ALARMS][MAX_ATTR_NAME];
@@ -136,6 +138,8 @@ public:
 	size_t silencedAlarms_sz;
 	size_t listAlarms_sz;
 	size_t alarmSummary_sz;
+	size_t eventList_sz;
+	size_t eventSummary_sz;
 
 	double last_statistics_reset_time;
 
@@ -169,6 +173,8 @@ public:
 	Tango::DevString	*attr_alarmList_read;
 	Tango::DevDouble	*attr_alarmFrequency_read;
 	Tango::DevString	*attr_alarmSummary_read;
+	Tango::DevString	*attr_eventList_read;
+	Tango::DevString	*attr_eventSummary_read;
 
 //	Constructors and destructors
 public:
@@ -347,6 +353,24 @@ public:
  */
 	virtual void read_alarmSummary(Tango::Attribute &attr);
 	virtual bool is_alarmSummary_allowed(Tango::AttReqType type);
+/**
+ *	Attribute eventList related methods
+ *	Description: List of all subscribed attributes
+ *
+ *	Data type:	Tango::DevString
+ *	Attr type:	Spectrum max = 10000
+ */
+	virtual void read_eventList(Tango::Attribute &attr);
+	virtual bool is_eventList_allowed(Tango::AttReqType type);
+/**
+ *	Attribute eventSummary related methods
+ *	Description: 
+ *
+ *	Data type:	Tango::DevString
+ *	Attr type:	Spectrum max = 10000
+ */
+	virtual void read_eventSummary(Tango::Attribute &attr);
+	virtual bool is_eventSummary_allowed(Tango::AttReqType type);
 
 //	Dynamic attribute methods
 public:
@@ -569,6 +593,9 @@ private:
 
 	void prepare_alarm_attr();	//for read attribute alarm and push_change_event
 
+	void prepare_event_list();
+	void prepare_event_summary();
+
 	void remove_AlarmState_dynamic_attribute_no_clean_db(string attname);
 
 	void parse_alarm(string &alarm_string, alarm_t &alm);
diff --git a/src/AlarmHandler.xmi b/src/AlarmHandler.xmi
index bef601f..67cd96d 100644
--- a/src/AlarmHandler.xmi
+++ b/src/AlarmHandler.xmi
@@ -290,6 +290,22 @@
       <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
       <properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
     </attributes>
+    <attributes name="eventList" attType="Spectrum" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="10000" maxY="" allocReadMember="true" isDynamic="false">
+      <dataType xsi:type="pogoDsl:StringType"/>
+      <changeEvent fire="false" libCheckCriteria="true"/>
+      <archiveEvent fire="false" libCheckCriteria="true"/>
+      <dataReadyEvent fire="false" libCheckCriteria="true"/>
+      <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
+      <properties description="List of all subscribed attributes" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
+    </attributes>
+    <attributes name="eventSummary" attType="Spectrum" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="10000" maxY="" allocReadMember="true" isDynamic="false">
+      <dataType xsi:type="pogoDsl:StringType"/>
+      <changeEvent fire="false" libCheckCriteria="true"/>
+      <archiveEvent fire="false" libCheckCriteria="true"/>
+      <dataReadyEvent fire="false" libCheckCriteria="true"/>
+      <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
+      <properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
+    </attributes>
     <dynamicAttributes name="AlarmState" attType="Scalar" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="" maxY="" allocReadMember="true" isDynamic="true">
       <dataType xsi:type="pogoDsl:EnumType"/>
       <changeEvent fire="true" libCheckCriteria="true"/>
diff --git a/src/AlarmHandlerClass.cpp b/src/AlarmHandlerClass.cpp
index d2c5d11..f0ba4bd 100644
--- a/src/AlarmHandlerClass.cpp
+++ b/src/AlarmHandlerClass.cpp
@@ -1123,6 +1123,58 @@ void AlarmHandlerClass::attribute_factory(vector<Tango::Attr *> &att_list)
 	alarmsummary->set_archive_event(true, true);
 	att_list.push_back(alarmsummary);
 
+	//	Attribute : eventList
+	eventListAttrib	*eventlist = new eventListAttrib();
+	Tango::UserDefaultAttrProp	eventlist_prop;
+	eventlist_prop.set_description("List of all subscribed attributes");
+	//	label	not set for eventList
+	//	unit	not set for eventList
+	//	standard_unit	not set for eventList
+	//	display_unit	not set for eventList
+	//	format	not set for eventList
+	//	max_value	not set for eventList
+	//	min_value	not set for eventList
+	//	max_alarm	not set for eventList
+	//	min_alarm	not set for eventList
+	//	max_warning	not set for eventList
+	//	min_warning	not set for eventList
+	//	delta_t	not set for eventList
+	//	delta_val	not set for eventList
+	
+	eventlist->set_default_properties(eventlist_prop);
+	//	Not Polled
+	eventlist->set_disp_level(Tango::OPERATOR);
+	//	Not Memorized
+	//eventlist->set_change_event(true, true);
+	//eventlist->set_archive_event(true, true);
+	att_list.push_back(eventlist);
+
+	//	Attribute : eventSummary
+	eventSummaryAttrib	*eventsummary = new eventSummaryAttrib();
+	Tango::UserDefaultAttrProp	eventsummary_prop;
+	//	description	not set for eventSummary
+	//	label	not set for eventSummary
+	//	unit	not set for eventSummary
+	//	standard_unit	not set for eventSummary
+	//	display_unit	not set for eventSummary
+	//	format	not set for eventSummary
+	//	max_value	not set for eventSummary
+	//	min_value	not set for eventSummary
+	//	max_alarm	not set for eventSummary
+	//	min_alarm	not set for eventSummary
+	//	max_warning	not set for eventSummary
+	//	min_warning	not set for eventSummary
+	//	delta_t	not set for eventSummary
+	//	delta_val	not set for eventSummary
+	
+	eventsummary->set_default_properties(eventsummary_prop);
+	//	Not Polled
+	eventsummary->set_disp_level(Tango::OPERATOR);
+	//	Not Memorized
+	//eventsummary->set_change_event(true, true);
+	//eventsummary->set_archive_event(true, true);
+	att_list.push_back(eventsummary);
+
 
 	//	Create a list of static attributes
 	create_static_attribute_list(get_class_attr()->get_attr_list());
diff --git a/src/AlarmHandlerClass.h b/src/AlarmHandlerClass.h
index 5df7fbe..25df84e 100644
--- a/src/AlarmHandlerClass.h
+++ b/src/AlarmHandlerClass.h
@@ -223,6 +223,32 @@ public:
 		{return (static_cast<AlarmHandler *>(dev))->is_alarmSummary_allowed(ty);}
 };
 
+//	Attribute eventList class definition
+class eventListAttrib: public Tango::SpectrumAttr
+{
+public:
+	eventListAttrib():SpectrumAttr("eventList",
+			Tango::DEV_STRING, Tango::READ, 10000) {};
+	~eventListAttrib() {};
+	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
+		{(static_cast<AlarmHandler *>(dev))->read_eventList(att);}
+	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
+		{return (static_cast<AlarmHandler *>(dev))->is_eventList_allowed(ty);}
+};
+
+//	Attribute eventSummary class definition
+class eventSummaryAttrib: public Tango::SpectrumAttr
+{
+public:
+	eventSummaryAttrib():SpectrumAttr("eventSummary",
+			Tango::DEV_STRING, Tango::READ, 10000) {};
+	~eventSummaryAttrib() {};
+	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
+		{(static_cast<AlarmHandler *>(dev))->read_eventSummary(att);}
+	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
+		{return (static_cast<AlarmHandler *>(dev))->is_eventSummary_allowed(ty);}
+};
+
 
 //=========================================
 //	Define classes for dynamic attributes
diff --git a/src/AlarmHandlerStateMachine.cpp b/src/AlarmHandlerStateMachine.cpp
index 0a855a3..8ffe582 100644
--- a/src/AlarmHandlerStateMachine.cpp
+++ b/src/AlarmHandlerStateMachine.cpp
@@ -252,6 +252,38 @@ bool AlarmHandler::is_alarmSummary_allowed(TANGO_UNUSED(Tango::AttReqType type))
 	return true;
 }
 
+//--------------------------------------------------------
+/**
+ *	Method      : AlarmHandler::is_eventList_allowed()
+ *	Description : Execution allowed for eventList attribute
+ */
+//--------------------------------------------------------
+bool AlarmHandler::is_eventList_allowed(TANGO_UNUSED(Tango::AttReqType type))
+{
+
+	//	Not any excluded states for eventList attribute in read access.
+	/*----- PROTECTED REGION ID(AlarmHandler::eventListStateAllowed_READ) ENABLED START -----*/
+	
+	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::eventListStateAllowed_READ
+	return true;
+}
+
+//--------------------------------------------------------
+/**
+ *	Method      : AlarmHandler::is_eventSummary_allowed()
+ *	Description : Execution allowed for eventSummary attribute
+ */
+//--------------------------------------------------------
+bool AlarmHandler::is_eventSummary_allowed(TANGO_UNUSED(Tango::AttReqType type))
+{
+
+	//	Not any excluded states for eventSummary attribute in read access.
+	/*----- PROTECTED REGION ID(AlarmHandler::eventSummaryStateAllowed_READ) ENABLED START -----*/
+	
+	/*----- PROTECTED REGION END -----*/	//	AlarmHandler::eventSummaryStateAllowed_READ
+	return true;
+}
+
 //--------------------------------------------------------
 /**
  *	Method      : AlarmHandler::is_AlarmState_allowed()
diff --git a/src/SubscribeThread.cpp b/src/SubscribeThread.cpp
index 2ddd9fc..d54d6dc 100644
--- a/src/SubscribeThread.cpp
+++ b/src/SubscribeThread.cpp
@@ -71,6 +71,8 @@ void *SubscribeThread::run_undetached(void *ptr)
 	{
 		//	Try to subscribe
 		usleep(500000);		//TODO: try to delay a bit subscribe_events
+		if(shared->get_if_stop())
+			break;
 		DEBUG_STREAM << "SubscribeThread::"<<__func__<<": AWAKE"<<endl;
 		updateProperty();
 		alarm_dev->events->subscribe_events();
@@ -98,7 +100,7 @@ void *SubscribeThread::run_undetached(void *ptr)
 			//shared->unlock();
 		}
 	}
-	shared->unsubscribe_events();
+	//shared->unsubscribe_events();
 	INFO_STREAM <<"SubscribeThread::"<< __func__<<": exiting..."<<endl;
 	return NULL;
 }
diff --git a/src/alarm_grammar.h b/src/alarm_grammar.h
index 0c166bb..2e0adb9 100644
--- a/src/alarm_grammar.h
+++ b/src/alarm_grammar.h
@@ -84,7 +84,7 @@
 #define SHELVED_KEY			"shelved"
 #define ACKNOWLEDGED_KEY	"ack"
 #define ATTR_VALUES_KEY		"values"
-#define VALUE_KEY			"state"
+#define VALUE_KEY				"state"
 #define ON_COUNTER_KEY		"on_counter"
 #define OFF_COUNTER_KEY		"off_counter"
 #define COUNTER_KEY			"counter"
@@ -93,6 +93,8 @@
 #define AUDIBLE_KEY			"audible"
 #define FREQ_COUNTER_KEY	"freq_counter"
 #define ALARM_TIME_KEY		"time"
+#define EVENT_KEY				"event"
+#define EVENT_TIME_KEY		ALARM_TIME_KEY
 #define KEY(S_VAL)  		S_VAL "="
 
 #define SEP					";"
diff --git a/src/event_table.cpp b/src/event_table.cpp
index 6b57407..386740e 100644
--- a/src/event_table.cpp
+++ b/src/event_table.cpp
@@ -17,6 +17,7 @@
 #include <tango.h>
 #include "event_table.h"
 #include "AlarmHandler.h"
+#include "alarm_grammar.h"
 
 //for get_event_system_for_event_id, to know if ZMQ
 #include <eventconsumer.h>
@@ -38,14 +39,14 @@ void event_list::push_back(bei_t& e)
 	catch(omni_thread_fatal& ex)
 	{
 		ostringstream err;
-		err << "omni_thread_fatal exception signaling omni_condition, err=" << ex.error << ends;
+		err << "omni_thread_fatal exception signaling omni_condition, err=" << ex.error;
 		//WARN_STREAM << "event_list::push_back(): " << err.str() << endl;	
 		printf("event_list::push_back(): %s", err.str().c_str());
 	}			
 	catch(Tango::DevFailed& ex)
 	{
 		ostringstream err;
-		err << "exception  signaling omni_condition: '" << ex.errors[0].desc << "'" << ends;
+		err << "exception  signaling omni_condition: '" << ex.errors[0].desc << "'";
 		//WARN_STREAM << "event_list::push_back(): " << err.str() << endl;	
 		printf("event_list::push_back: %s", err.str().c_str());
 		Tango::Except::print_exception(ex);	
@@ -69,7 +70,7 @@ const bei_t event_list::pop_front(void)
 	catch(omni_thread_fatal& ex)
 	{
 		ostringstream err;
-		err << "omni_thread_fatal exception waiting on omni_condition, err=" << ex.error << ends;
+		err << "omni_thread_fatal exception waiting on omni_condition, err=" << ex.error;
 		//WARN_STREAM << "event_list::pop_front(): " << err.str() << endl;	
 		printf("event_list::pop_front(): %s", err.str().c_str());
 		bei_t e;
@@ -80,7 +81,7 @@ const bei_t event_list::pop_front(void)
 	catch(Tango::DevFailed& ex)
 	{
 		ostringstream err;
-		err << "exception  waiting on omni_condition: '" << ex.errors[0].desc << "'" << ends;
+		err << "exception  waiting on omni_condition: '" << ex.errors[0].desc << "'";
 		//WARN_STREAM << "event_list::pop_front(): " << err.str() << endl;	
 		printf("event_list::pop_front: %s", err.str().c_str());
 		Tango::Except::print_exception(ex);
@@ -251,13 +252,90 @@ bool event::operator==(const string& s)
 //	v_event.push_back(e);//TODO: replaced with add
 }*/
 
-void event_table::show(void)
+void event_table::show(list<string> &evl)
 {
-	DEBUG_STREAM << "events found:" << endl;
-	if (v_event.empty() == false) {
+	evl.clear();
+	ReaderLock lock(veclock);
+	if (v_event.empty() == false)
+	{
 		vector<event>::iterator i = v_event.begin();
-		while (i != v_event.end()) {
-			DEBUG_STREAM << "\t" << i->name << endl;
+		while (i != v_event.end())
+		{
+			//DEBUG_STREAM << "\t" << i->name << endl;
+			evl.push_back(i->name);
+			i++;
+		}
+	}
+}
+
+void event_table::summary(list<string> &evs)
+{
+	evs.clear();
+	ReaderLock lock(veclock);
+	if (v_event.empty() == false)
+	{
+		vector<event>::iterator i = v_event.begin();
+		while (i != v_event.end())
+		{
+			ostringstream ev_summary;
+			ev_summary << KEY(EVENT_KEY) << i->name << SEP;
+			tm time_tm;
+			time_t time_sec;
+			if(i->valid)
+			{
+				time_sec= i->ts.tv_sec;
+			}
+			else
+			{
+				timeval now;
+				gettimeofday(&now, NULL);
+				time_sec = now.tv_sec;
+			}
+			//gmtime_r(&time_sec,&time_tm); //-> UTC
+			localtime_r(&time_sec,&time_tm);
+			char time_buf[64];
+			strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
+
+			ev_summary << KEY(EVENT_TIME_KEY) << time_buf << SEP;
+			ostringstream tmp_val;
+			//if(i->valid)
+			{
+				tmp_val << "[" ;
+				if(i->type != Tango::DEV_STRING)
+				{
+					if(i->read_size > 0 && i->value.size() > 0)
+					{
+						for(size_t k=0; k<i->read_size && k<i->value.size(); k++)
+						{
+							tmp_val << i->value[k];
+							if(k < i->read_size-1 && k<i->value.size()-1)
+								tmp_val << ",";
+						}
+					}
+				}
+				else
+				{
+					tmp_val << "\""<<i->value_string<<"\"";
+				}
+				tmp_val << "]";
+			}
+			ev_summary << KEY(ATTR_VALUES_KEY) << tmp_val.str() << SEP;
+			ostringstream tmp_ex;
+			//tmp_ex.str("");
+			if(!i->ex_reason.empty() || !i->ex_desc.empty() || !i->ex_origin.empty())
+			{
+				tmp_ex << "{\"Reason\":\"" << i->ex_reason << "\",\"Desc\":\"" << i->ex_desc << "\",\"Origin\":\"" << i->ex_origin << "\"}";
+			}
+			ev_summary << KEY(EXCEPTION_KEY) << tmp_ex.str() << SEP;
+			ev_summary << KEY(QUALITY_KEY);
+			try
+			{
+				ev_summary << quality_labels.at(i->quality) << SEP;
+			} catch(std::out_of_range& ex)
+			{
+				ev_summary << i->quality << SEP;
+			}
+			evs.push_back(ev_summary.str());
 			i++;
 		}
 	}
@@ -272,6 +350,7 @@ event_table::event_table(Tango::DeviceImpl *s):Tango::LogAdapter(s)
 
 unsigned int event_table::size(void)
 {
+	ReaderLock lock(veclock); //TODO: necessary?
 	return(v_event.size());
 }
 #if 0
@@ -288,7 +367,7 @@ void event_table::init_proxy(void)	throw(vector<string> &)
 			{
 				ostringstream o;
 				o << "new DeviceProxy() failed for " \
-					<< i->device << ends;
+					<< i->device;
 				ERROR_STREAM << o.str() << endl;
 				//throw o.str();
 				proxy_error.push_back(o.str());
@@ -328,7 +407,7 @@ void event_table::subscribe(EventCallBack& ecb) throw(vector<string> &)//throw(s
 			} catch (...) {
 				ostringstream o;
 				o << "subscribe_event() failed for " \
-					<< i->name << ends;
+					<< i->name;
 				ERROR_STREAM << o.str() << endl;
 				//throw o.str();
 				subscribe_error.push_back(o.str());
@@ -877,24 +956,27 @@ void event_table::subscribe_events()
 				}
 				catch (Tango::DevFailed &e)
 				{
+					string ex_reason(e.errors[0].reason);
+					ex_reason = std::regex_replace(ex_reason, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
+					string ex_desc(e.errors[0].desc);
+					ex_desc = std::regex_replace(ex_desc, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
+					string ex_origin(e.errors[0].origin);
+					ex_origin = std::regex_replace(ex_origin, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
+					bei_t ex;
 					ostringstream o;
 					o << "Error adding'" \
-					<< sig->name << "' error=" << e.errors[0].desc << ends;
+					<< sig->name << "' error=" << ex_desc;
 					INFO_STREAM << "event_table::subscribe_events: " << o.str() << endl;
-					v_event[i].ex_reason = e.errors[0].reason;
-					v_event[i].ex_desc = e.errors[0].desc;
+					v_event[i].ex_reason = ex.ex_reason = ex_reason;
+					v_event[i].ex_desc = ex.ex_desc = ex_desc;
 //					v_event[i].ex_desc.erase(std::remove(v_event[i].ex_desc.begin(), v_event[i].ex_desc.end(), '\n'), v_event[i].ex_desc.end());
-					v_event[i].ex_origin = e.errors[0].origin;
-					v_event[i].siglock->writerOut();
-					//TODO: since event callback not called for this attribute, need to manually trigger do_alarm to update interlan structures ?
-					bei_t ex;
+					v_event[i].ex_origin = ex.ex_origin = ex_origin;
+					v_event[i].ts = ex.ts = gettime();
+					v_event[i].quality = ex.quality = Tango::ATTR_INVALID;
 					ex.ev_name = sig->name;
-					ex.quality = Tango::ATTR_INVALID;
-					ex.ex_reason = e.errors[0].reason;
-					ex.ex_desc = e.errors[0].desc;
-					ex.ex_origin = e.errors[0].origin;
+					v_event[i].siglock->writerOut();
+					//TODO: since event callback not called for this attribute, need to manually trigger do_alarm to update interlan structures ?		
 					ex.type = TYPE_TANGO_ERR;
-					ex.ts = gettime();
 					ex.msg=o.str();
 					static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->do_alarm(ex);
 					continue;
@@ -930,28 +1012,31 @@ void event_table::subscribe_events()
 			}
 			catch (Tango::DevFailed &e)
 			{
+				string ex_reason(e.errors[0].reason);
+				ex_reason = std::regex_replace(ex_reason, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
+				string ex_desc(e.errors[0].desc);
+				ex_desc = std::regex_replace(ex_desc, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
+				string ex_origin(e.errors[0].origin);
+				ex_origin = std::regex_replace(ex_origin, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
+				bei_t ex;
 				ostringstream o;
 				o << "Event exception for'" \
-					<< sig->name << "' error=" << e.errors[0].desc << ends;
+					<< sig->name << "' error=" << ex_desc;
 				INFO_STREAM <<"event_table::"<<__func__<<": sig->attr->subscribe_event: " << o.str() << endl;
 				err = true;
 				Tango::Except::print_exception(e);
 				sig->siglock->writerIn();
-				sig->ex_reason = e.errors[0].reason;
-				sig->ex_desc = e.errors[0].desc;
-				sig->ex_origin = e.errors[0].origin;
+				sig->ex_reason = ex.ex_reason = ex_reason;
+				sig->ex_desc = ex.ex_desc = ex_desc;
+				sig->ex_origin = ex.ex_origin = ex_origin;
 				sig->event_id = SUB_ERR;
 				delete sig->event_cb;
+				sig->ts = ex.ts = gettime();
+				sig->quality = ex.quality = Tango::ATTR_INVALID;
+				ex.ev_name = sig->name;
 				sig->siglock->writerOut();
 				//since event callback not called for this attribute, need to manually trigger do_alarm to update interlan structures
-				bei_t ex;
-				ex.ev_name = sig->name;
-				ex.quality = Tango::ATTR_INVALID;
-				ex.ex_reason = e.errors[0].reason;
-				ex.ex_desc = e.errors[0].desc;
-				ex.ex_origin = e.errors[0].origin;
 				ex.type = TYPE_TANGO_ERR;
-				ex.ts = gettime();
 				ex.msg=o.str();
 				static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->do_alarm(ex);
 			}
@@ -1199,6 +1284,7 @@ void EventCallBack::push_event(Tango::EventData* ev)
 			e.ts = ev->attr_value->time;
 			extract_values(ev->attr_value, e.value, e.value_string, e.type, e.read_size);
 		} else {
+			e.quality = Tango::ATTR_INVALID;
 #if 0//TANGO_VER >= 711
  			string ev_name_str(ev->attr_name);
  			string::size_type pos = ev_name_str.find("tango://");
@@ -1217,13 +1303,13 @@ void EventCallBack::push_event(Tango::EventData* ev)
 				temp_name = temp_name.substr(0,pos_change);
 			}
 			ostringstream o;
-			o << "Tango error for '" << temp_name << "'=" << ev->errors[0].desc.in() << ends;			
+			o << "Tango error for '" << temp_name << "'=" << ev->errors[0].desc.in();			
 			e.ev_name = temp_name;
 			e.type = TYPE_TANGO_ERR;
 			//e.ev_name = INTERNAL_ERROR;
 			//e.type = -1;
 			e.msg = o.str();
-			e.msg = std::regex_replace(e.msg, std::regex(R"((\n)|(\t))"), " "); //match raw string "\n" or "\t" and replace with " "
+			e.msg = std::regex_replace(e.msg, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
 		}
 	} 
 	catch (string &err) {
@@ -1237,18 +1323,18 @@ void EventCallBack::push_event(Tango::EventData* ev)
 	{
 		ostringstream o;
 		o << "Event exception for'" \
-			<< ev->attr_name << "' error=" << Terr.errors[0].desc << ends;
+			<< ev->attr_name << "' error=" << Terr.errors[0].desc;
 		e.ev_name = ev->attr_name;
 		e.type = TYPE_GENERIC_ERR;
 		//e.value.i = 0;
 		e.ts = gettime();
 		e.msg = o.str();
-		//cerr << o.str() << endl;		
+		e.msg = std::regex_replace(e.msg, std::regex(R"((\n)|(\r)|(\t)|(\0))"), " "); //match raw string "\n" or "\t" and replace with " "
 	}	
 	catch (...) {
 		ostringstream o;
 		o << "Generic Event exception for'" \
-			<< ev->attr_name << "'" << ends;
+			<< ev->attr_name << "'";
 		e.ev_name = ev->attr_name;
 		e.type = TYPE_GENERIC_ERR;
 		//e.value.i = 0;
@@ -1362,7 +1448,7 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
 	}
 	else {
 		ostringstream o;
-		o << "unknown type" << ends;
+		o << "unknown type";
 		throw o.str();
 	}	
 }
diff --git a/src/event_table.h b/src/event_table.h
index 42f75e4..4e5988e 100644
--- a/src/event_table.h
+++ b/src/event_table.h
@@ -66,7 +66,6 @@ class event {
 		value_t value;				/* event value */
 		string value_string;	//added for DevString attributes
 		int quality;
-		//Tango::DevErrorList 	errors;
 		string ex_reason;
 		string ex_desc;
 		string ex_origin;
@@ -75,13 +74,10 @@ class event {
 				read_size,                                      /* attribute size of read part */
 				counter,					/* molteplicita' */
 				err_counter;					/* molteplicita' errore */				
-		//map<string, string> m_alarm;
-		//vector<string> m_alarm;
 		alarm_list m_alarm;
 		bool valid;	//TODO: old
 		bool 	first;//TODO: new
 		bool 	first_err;//TODO: new
-		//Tango::DeviceProxy *dp;
 		Tango::AttributeProxy *attr;
 		Tango::DevState			evstate;
 		unsigned int event_id;
@@ -159,7 +155,8 @@ class event_table : public Tango::TangoMonitor, public Tango::LogAdapter {
 		event_table(Tango::DeviceImpl *s);//:Tango::LogAdapter(s) {mydev = s;}
 		~event_table(void) {stop_thread();}
 		//void push_back(event e);
-		void show(void);
+		void show(list<string> &evl);
+		void summary(list<string> &evs);
 		unsigned int size(void);
 #if 0
 		void init_proxy(void)  throw(vector<string> &);
diff --git a/src/formula_grammar.h b/src/formula_grammar.h
index f2a6bad..f7a24bb 100644
--- a/src/formula_grammar.h
+++ b/src/formula_grammar.h
@@ -92,7 +92,7 @@ enum _AlarmStateEnum {
 	_ERROR
 } ;
 
-static vector<string> quality_labels;
+static vector<string> quality_labels = {"ATTR_VALID","ATTR_INVALID","ATTR_ALARM","ATTR_CHANGING","ATTR_WARNING"};
 
 struct formula_grammar : public grammar<formula_grammar>
 {
@@ -156,16 +156,11 @@ struct formula_grammar : public grammar<formula_grammar>
 		tango_states.add("DISABLE", (unsigned int)Tango::DISABLE);
 		tango_states.add("UNKNOWN", (unsigned int)Tango::UNKNOWN);
 
-		quality_labels.push_back("ATTR_VALID");
-		attr_quality.add(quality_labels.back().c_str(), (unsigned int)Tango::ATTR_VALID);
-		quality_labels.push_back("ATTR_INVALID");
-		attr_quality.add(quality_labels.back().c_str(), (unsigned int)Tango::ATTR_INVALID);
-		quality_labels.push_back("ATTR_ALARM");
-		attr_quality.add(quality_labels.back().c_str(), (unsigned int)Tango::ATTR_ALARM);
-		quality_labels.push_back("ATTR_CHANGING");
-		attr_quality.add(quality_labels.back().c_str(), (unsigned int)Tango::ATTR_CHANGING);
-		quality_labels.push_back("ATTR_WARNING");
-		attr_quality.add(quality_labels.back().c_str(), (unsigned int)Tango::ATTR_WARNING);
+		attr_quality.add("ATTR_VALID", (unsigned int)Tango::ATTR_VALID);
+		attr_quality.add("ATTR_INVALID", (unsigned int)Tango::ATTR_INVALID);
+		attr_quality.add("ATTR_ALARM", (unsigned int)Tango::ATTR_ALARM);
+		attr_quality.add("ATTR_CHANGING", (unsigned int)Tango::ATTR_CHANGING);
+		attr_quality.add("ATTR_WARNING", (unsigned int)Tango::ATTR_WARNING);
 
 
 		alarm_enum_states.add("NORM", (unsigned int)_NORM);
-- 
GitLab