Skip to content
Snippets Groups Projects
Alarm.cpp 127 KiB
Newer Older
/*----- 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);
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000

	/*----- 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 */