Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • cs/ds/alarm-handler
  • francesco.tripaldi/alarm-handler
2 results
Show changes
Commits on Source (158)
Showing with 554 additions and 3774 deletions
......@@ -27,3 +27,13 @@
*.exe
*.out
*.app
bin/
build/
.nse_depinfo
# Eclipse
.cproject
.project
.settings
image:
name: harbor.skao.int/production/ska-tango-images-tango-dsconfig:1.5.5
stages:
- build
- test
build_job:
stage: build
tags:
- docker
before_script:
- sudo apt update && sudo apt -y --no-install-recommends install build-essential cmake pkg-config libboost-thread-dev
script:
- mkdir build && cd build
- cmake -DBUILD_TESTS=ON ..
- make
artifacts:
paths:
- build/alarm-handler-srv
- build/bin/testdevice-srv
expire_in: 1 week
test_load_job:
stage: test
tags:
- docker
before_script:
- sudo apt update && sudo apt -y --no-install-recommends install libboost-thread-dev
script:
- sleep 10
- /usr/local/bin/DataBaseds 2 -ORBendPoint giop:tcp::10000 &
- sleep 10
- exit_code=2
- json2tango -w -a -u ./test/ah_config.json || exit_code=$?
- if [ ${exit_code} -ne 2 ]; then echo "Tango DB configuration failed!" ; else echo "Tango DB configuration succedeed!"; fi
- ./build/alarm-handler-srv 01 &
- ./build/bin/testdevice-srv 01 &
- sleep 5
- python ./test/load-alarm-conf.py --device=alarm/handler/01 --load="tag=test0;formula=(alarm/test/01/condition == 1);on_delay=0;off_delay=0;priority=high;shlvd_time=0;group=gr_test;message=Test alarm;url=;on_command=;off_command=;enabled=1"
- sleep 1
- python ./test/check-alarm-conf.py --device=alarm/handler/01 --alarm="tag=test0;formula=(alarm/test/01/condition == 1);on_delay=0;off_delay=0;priority=high;shlvd_time=0;group=gr_test;message=Test alarm;url=;on_command=;off_command=;enabled=1"
needs: ["build_job"]
services:
- name: harbor.skao.int/production/ska-tango-images-tango-db:10.4.16
alias: tangodb
image:
name: harbor.skao.int/production/ska-tango-images-tango-dsconfig:1.5.5
# The following variables are automatically passed down to the tangodb container
# as well as the tangodatabaseds container and available within each.
variables:
MYSQL_ROOT_PASSWORD: "secret"
MYSQL_DATABASE: "tango"
MYSQL_USER: "tango"
MYSQL_PASSWORD: "tango"
MYSQL_HOST: "tangodb"
TANGO_HOST: "localhost:10000"
stages:
- build
- conf
- test
services:
- name: harbor.skao.int/production/ska-tango-images-tango-db
alias: tangodb
# - name: harbor.skao.int/production/ska-tango-images-tango-cpp
# alias: tangodatabaseds
# entrypoint: ["/usr/local/bin/DataBaseds"]
# command: ["2","-ORBendPoint giop:tcp::10000"]
build_job:
stage: build
before_script:
#TODO: remove procps use for ps
- sudo apt update && sudo apt -y --no-install-recommends install build-essential cmake pkg-config libboost-thread-dev procps
script:
#- make
- mkdir build && cd build
- cmake ..
- make
artifacts:
paths:
- build/alarm-handler-srv
expire_in: 1 week
# # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time
# cache:
# paths:
# - build/CMakeFiles/
configure_and_run_job:
stage: conf
script:
- sleep 10
- /usr/local/bin/DataBaseds 2 -ORBendPoint giop:tcp::10000 &
- sleep 10
- exit_code=2
- json2tango -w -a -u ./test/ah_config.json || exit_code=$?
# json2tango returns 2 if values written to DB
- if [ ${exit_code} -ne 2 ]; then echo "Tango DB configuration failed!" ; else echo "Tango DB configuration succedeed!"; fi
- sleep 5
artifacts:
paths:
- build/alarm-handler-srv
expire_in: 1 week
needs: ["build_job"]
#services:
# - name: harbor.skao.int/production/ska-tango-images-tango-db
# alias: tangodb
test_job:
stage: test
before_script:
#TODO: remove procps use for ps
- sudo apt update && sudo apt -y --no-install-recommends install libboost-thread-dev procps
script:
- /usr/local/bin/DataBaseds 2 -ORBendPoint giop:tcp::10000 &
- sleep 10
- ./build/alarm-handler-srv 01 &
- sleep 10
- ps -ef | grep alarm-handler-srv | grep -v grep
- sleep 5
needs: ["configure_and_run_job"]
# Functions and Pre-build -----------------------------------
# Stop messy in source builds
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES OFF)
if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt." )
endif()
# Start Build Config -----------------------------------
cmake_minimum_required(VERSION 3.8)
set(CMAKE_SKIP_RPATH true)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Output name for the final binary
set(AH_NAME "alarm-handler-srv")
# Versioning
set(VERSION_MAJOR "1")
set(VERSION_MINOR "0")
set(VERSION_PATCH "0")
set(VERSION_METADATA "")
set(VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
# Add any include paths from the command line
list(APPEND INCLUDE_PATHS ${CMAKE_INCLUDE_PATH})
list(APPEND INCLUDE_PATHS ${CMAKE_SOURCE_DIR})
list(APPEND LIBRARY_PATHS ${CMAKE_LIBRARY_PATH})
# Start the project
project(alarm_handler VERSION ${VERSION_STRING} LANGUAGES CXX)
# Build options
option(ENABLE_CLANG "Enable clang code and layout analysis" OFF)
option(BUILD_TESTS "Build tests" OFF)
# arch install definitions
include(GNUInstallDirs)
message(STATUS "Searching for libraries...")
# Variable to contain a list of all the libs we depend on
set(AH_LIBRARIES)
# allow pkg-config to search the CMAKE_PREFIX_PATH
set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH ON)
list(APPEND CMAKE_PREFIX_PATH "/usr")
# Find Dependencies -----------------------------------
# Find tango if it has not already been found. Returns an interface library
# called TangoInterfaceLibrary
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(Tango)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.65.0 COMPONENTS thread)
# Code Analysis -----------------------------------
if(ENABLE_CLANG)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# To find clang, find_program will search your PATH environment variable.
# Ensure if you have a non-standard clang install, that it has been added
# to your path.
find_program(CLANG_TIDY_EXE
NAMES "clang-tidy"
DOC "Path to clang-tidy executable")
if(NOT CLANG_TIDY_EXE)
message(STATUS "clang-tidy not found.")
else(NOT CLANG_TIDY_EXE)
message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}")
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}")
endif(NOT CLANG_TIDY_EXE)
endif(ENABLE_CLANG)
# Source -----------------------------------
add_subdirectory(src)
# Build Targets -----------------------------------
# Executable --------
add_executable(alarm_handler ${SRC_FILES})
target_link_libraries(alarm_handler
PRIVATE
TangoInterfaceLibrary
${Boost_LIBRARIES}
)
target_include_directories(alarm_handler
PRIVATE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
${INCLUDE_PATHS}
"${PROJECT_BINARY_DIR}"
${Boost_INCLUDE_DIRS})
if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
set_target_properties(alarm_handler
PROPERTIES
OUTPUT_NAME ${AH_NAME}
LINK_FLAGS "-Wl,--no-undefined"
CXX_STANDARD 17)
else()
set_target_properties(alarm_handler
PROPERTIES
OUTPUT_NAME ${AH_NAME}
LINK_FLAGS ""
CXX_STANDARD 17)
endif()
if(DO_CLANG_TIDY)
set_target_properties(alarm_handler
PROPERTIES
CXX_CLANG_TIDY ${DO_CLANG_TIDY})
endif(DO_CLANG_TIDY)
target_compile_options(alarm_handler
PRIVATE "$<$<CONFIG:DEBUG>:-g>")
# Install Config -----------------------------------
install(
TARGETS alarm_handler
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
message(STATUS "Configured alarm-handler project")
# Tests -----------------------------------
if(BUILD_TESTS)
add_subdirectory(test)
endif(BUILD_TESTS)
CXXFLAGS += -std=gnu++98
TANGO_DIR ?= /usr/local/tango-8.1.2.c
OMNIORB_DIR ?= /usr/local/omniorb-4.1.6
RUNTIME_DIR ?= /runtime
TANGO_INC = ${TANGO_DIR}/include/tango
OMNIORB_INC = ${OMNIORB_DIR}/include
RUNTIME_INC = ${RUNTIME_DIR}/include
INC_DIR = -I${TANGO_INC} -I${OMNIORB_INC} -I${RUNTIME_INC}
TANGO_LIB = ${TANGO_DIR}/lib
OMNIORB_LIB = ${OMNIORB_DIR}/lib
RUNTIME_LIB = ${RUNTIME_DIR}/lib
LIB_DIR = -L${TANGO_LIB} -L${OMNIORB_LIB} -L${RUNTIME_LIB} -L/usr/local/lib
#-----------------------------------------
# Default make entry
#-----------------------------------------
default: release
release debug: bin/$(NAME_SRV)
#-----------------------------------------
# Set CXXFLAGS and LDFLAGS
#----------------------------------------r
CXXFLAGS += -D__linux__ -D__OSVERSION__=2 -pedantic -Wall -Wextra \
-Wno-non-virtual-dtor -Wno-long-long -DOMNI_UNLOADABLE_STUBS \
$(INC_DIR) -Isrc
LDFLAGS += $(LIB_DIR) -ltango -llog4tango -lomniORB4 -lomniDynamic4 \
-lCOS4 -lomnithread -lzmq
#-----------------------------------------
# Set dependencies
#-----------------------------------------
SRC_FILES += $(wildcard src/*.cpp)
OBJ_FILES += $(addprefix obj/,$(notdir $(SRC_FILES:.cpp=.o)))
obj/%.o: $(SRC_FILES:%.cpp)
$(CXX) $(CXXFLAGS) -c -o $@ $<
.nse_depinfo: $(SRC_FILES)
@$(CXX) $(CXXFLAGS) -M -MM $^ | sed 's/\(.*\)\.o/obj\/\1.o/g' > $@
-include .nse_depinfo
#-----------------------------------------
# Main make entries
#-----------------------------------------
bin/$(NAME_SRV): bin obj $(OBJ_FILES)
$(CXX) $(CXXFLAGS) $(OBJ_FILES) -o bin/$(NAME_SRV) $(LDFLAGS)
clean:
@rm -fr obj/ bin/ core* .nse_depinfo src/*~
bin obj:
@mkdir $@
#-----------------------------------------
# Target specific options
#-----------------------------------------
release: CXXFLAGS += -O2 -DNDEBUG
release: LDFLAGS += -s
debug: CXXFLAGS += -ggdb3
.PHONY: clean
NAME_SRV = alarm-srv
NAME_SRV = alarm-handler-srv
CXXFLAGS += `mysql_config --include`
CXXFLAGS +=
LDFLAGS += `mysql_config --libs_r` -lboost_thread
LDFLAGS += -lboost_thread
#include ./Make-8.1.2.c.in
include ./Make-9.2.2.in
include ../makefiles/Make-9.3.3.in
# alarm
Elettra Alarms
# Alarm-handler
Elettra alarm-handler Tango device
## Building and Installation
In its simplest form, clone the repository and assuming a standard install for all dependencies:
```
mkdir build
cd build
cmake ../
make
make install
```
### pkg-config Settings
The build system uses pkg-config to find some dependencies, for example Tango. If Tango is not installed to a standard location, set PKG_CONFIG_PATH, i.e.
```bash
export PKG_CONFIG_PATH=/non/standard/tango/install/location
...
cmake ../
...
```
The pkg-config path can also be set with the cmake argument CMAKE_PREFIX_PATH. This can be set on the command line at configuration time, i.e.:
```bash
...
cmake -DCMAKE_PREFIX_PATH=/non/standard/tango/install/location ../
...
```
### Project Flags
| Flag | Setting | Default | Description |
|------|-----|-----|-----|
| BUILD_TESTS | ON/OFF | OFF | Build test devices under test directory |
### Standard CMake Flags
The build system is CMake therefore standard CMake flags can be used to influence the build and installation process. The following is a list of common useful CMake flags and their use:
| Flag | Use |
|------|-----|
| CMAKE_INSTALL_PREFIX | Standard CMake flag to modify the install prefix. |
| CMAKE_INCLUDE_PATH | Standard CMake flag to add include paths to the search path. |
| CMAKE_LIBRARY_PATH | Standard CMake flag to add paths to the library search path |
## Legacy Building
Using Elettra makefiles, clone both alarm-handler and makefile repositories, then call make:
```bash
git clone http://gitlab.elettra.eu/cd/ds/makefiles.git
git clone http://gitlab.elettra.eu/cs/ds/alarm-handler.git
cd alarm-handler
make
```
include(CMakeParseArguments)
function(find_libraries)
# Parse the parameters
set(MULTIVALUEARGS LIBRARIES SEARCH_PATHS)
cmake_parse_arguments(FIND_LIBRARIES "" "" "${MULTIVALUEARGS}" ${ARGN})
# Clear the found libraries
unset(FOUND_LIBRARIES PARENT_SCOPE)
foreach(LIB ${FIND_LIBRARIES_LIBRARIES})
# try the user provided paths first
find_library(FOUND_LIB_${LIB} ${LIB} PATHS ${FIND_LIBRARIES_SEARCH_PATHS} NO_DEFAULT_PATH)
# if we could not find it, drop to the system paths
if(NOT FOUND_LIB_${LIB})
find_library(FOUND_LIB_${LIB} ${LIB})
endif(NOT FOUND_LIB_${LIB})
if(FOUND_LIB_${LIB})
message(STATUS "Found " ${LIB} " at: " ${FOUND_LIB_${LIB}})
list(APPEND FOUND_LIBRARIES ${FOUND_LIB_${LIB}})
else()
message(FATAL "Could not find " ${LIB})
endif(FOUND_LIB_${LIB})
endforeach(LIB ${LIBRARIES})
set(FOUND_LIBRARIES ${FOUND_LIBRARIES} PARENT_SCOPE)
endfunction(find_libraries)
\ No newline at end of file
if(NOT TARGET TangoInterfaceLibrary)
# Ensure pkg-config is installed
find_package(PkgConfig REQUIRED)
# Now search for the tango.pc file, this is a required dependency
message(STATUS "Search for TANGO package config...")
pkg_search_module(TANGO REQUIRED tango>=9.2.5)
message(STATUS "Found tango version ${TANGO_VERSION} at ${TANGO_PREFIX}")
include(FindLibraries)
find_libraries(LIBRARIES ${TANGO_LIBRARIES} SEARCH_PATHS ${TANGO_LIBRARY_DIRS})
# Create an interface library to represent the tango linkage
add_library(TangoInterfaceLibrary INTERFACE)
set_target_properties(TangoInterfaceLibrary
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${TANGO_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES "${FOUND_LIBRARIES}"
INTERFACE_COMPILE_OPTIONS "${TANGO_CFLAGS}")
message(STATUS "Configured Tango Interface for TANGO version ${TANGO_VERSION}")
endif(NOT TARGET TangoInterfaceLibrary)
\ No newline at end of file
File added
# Formula syntax
The formula is an expression with operators, operands and functions. Operands can be variables, constant values, or other expression optionally enclosed by parentheses.
## Operands
### Variables
- Attributes names with or without fqdn (e.g. ```tango://host:port/name/of/dev/attr```, ```name/of/dev/attr```)
- attribute properties ```.quality```, ```.alarm```, ```.normal``` so that
- ```name/of/dev/attr.quality``` returns the Tango quality (the integer value) of the attribute
- ```name/of/dev/attr.alarm``` returns true if the attribute ==UNACK or ==ACK
- ```name/of/dev/attr.normal``` returns true if the attribute ==NORM or ==RTNUN
### Constants
- Real numbers (e.g. ```name/of/dev/attr >= 35```, ```name/of/dev/attr < -23.5```)
- Hexadecimal numbers (e.g. ```name/of/dev/attr != 0xaf```, ```name/of/dev/attr & 0x1A```)
- Strings as any character between an opening and a closing ' (e.g. ```name/of/dev/status == 'The device is in ON state.'```)
- Tango states enum labels (*ON, OFF, CLOSE, OPEN, INSERT, EXTRACT, MOVING, STANDBY, FAULT, INIT, RUNNING, ALARM, DISABLE, UNKNOWN*) (e.g. ```name/of/dev/state == FAULT```)
- Tango quality enum labels (*ATTR_VALID, ATTR_INVALID, ATTR_WARNING, ATTR_ALARM, ATTR_CHANGING*) (e.g. ```name/of/dev/attr.quality == ATTR_ALARM```)
- Alarm state enum labels (*NORM, UNACK, ACKED, RTNUN, SHLVD, DSUPR, OOSRV*) (e.g. ```name/of/dev/alarm_attr != NORM```)
### Expressions
- A combination of operands and operators enclosed by parentheses
## Operators
### Binary Math
- Multiplication ```*```
- Division ```/```
- Addition ```+```
- Subtraction ```-```
### Binary Comparison
- Equal ```==```
- Not equal ```!=```
- Greater than ```>```
- Greater than or equal to ```>=```
- Less than ```<```
- Less than or equal to ```<=```
### Binary Logical
- Logical AND ```&&```
- Logical OR ```||```
### Binary Bitwise
- Left shift ```<<```
- Right shift ```>>```
- Bitwise AND ```&```
- Bitwise OR ```|```
- Bitwise XOR ```^```
### Unary Math
- Minus ```-```
### Unary Logical
- Logical NOT ```!```
### Binary operators order of precedence
```
*, /, +, -, <<, >>, <=, >=, >, <, ==, !=, &, |, ^, &&, ||
```
## Functions
### Unary Functions
- Absolute value of X ```abs(X)```
- Sine of X ```sin(X)```
- Cosine of X ```cos(X)```
### Binary Functions
- Minimum between two values X and Y ```min(X,Y)```
- Maximum between two values X and Y ```max(X,Y)```
- Power: X raised to the power of Y ```pow(X,Y)```
### Ternary Functions
- Conditional operator: if X then Y else Z ```X ? Y : Z```
### Reduce Functions
- Reduce OR: reduce array X applying logical OR to each element ```OR(X)```
- Reduce AND: reduce array X applying logical AND to each element ```OR(X)```
# Attributes types
The following types of attribute are supported:
```
Scalar, Spectrum, Image
```
with data types:
```
DevBoolean, DevUChar, DevShort, DevUShort, DevLong, DevULong, DevLong64, DevULong64, DevFloat, DevDouble, DevString, DevState, DevEnum
```
```DevEncoded``` is not supported.
The read part of every attribute is internally extracted in a vector of double with the ```extract_read``` method of the ```DeviceAttribute``` class. In this ways operations between attribute with different data types and sizes can be performed with the following constraints:
- DevString attributes can only be compared with 'equal' or 'not equal' operators to DevString attributes or string constants
- Binary operators can operate on arrays if both operands have the same size, or one of the two has size equal to one.
# Operation on arrays
## Indexes to access elements
- A single element of a one-dimensional array attribute (Spectrum) can be extracted with a single index between square brackets (e.g. ```name/of/dev/attr[ind]```).
- A single element of a two-dimensional array attribute (Image) can be extracted with two indexes between square brackets (e.g. ```name/of/dev/attr[ind_row][ind_column]```).
- A one-dimensional array can be extracted from a two-dimensional array attribute (Image) with a single index between square brackets (e.g. ```name/of/dev/attr[ind_row]```).
## Lists and ranges of indexes to slice arrays
Indexes can be specified as a comma separated list and/or hyphen-separated range (e.g. ```[i0,i1-i2,...]```).
In this way:
- A slice can be extracted from a one-dimensional array with a list and/or range of indexes between square brackets (e.g. ```name/of/dev/1Dattr[i0,i1-i2,...]```).
- A subset of rows can be extracted from a two-dimensional array with a list and/or range of indexes for the first dimension (e.g. ```name/of/dev/2Dattr[i0,i1-i2,...]```).
- A single column slice can be extracted from a two-dimensional array with a list and/or range of indexes for the first dimension and a single index for the second dimension (e.g. ```name/of/dev/2Dattr[i0,i1-i2,...][i3]```).
- A single row slice can be extracted from a two-dimensional array with a single index for the first dimension and list/range of indexes for the second dimension (e.g. ```name/of/dev/2Dattr[i0][i1-i2,i3,...]```).
- An array slice can be extracted from a two-dimensional array with a list and/or range of indexes for both the first and second dimensions (e.g. ```name/of/dev/2Dattr[i0-i1,...][i2,i3,...]```).
- To specify all elements of one dimension index -1 can be used (e.g. Column 3 of all rows of 2D array ```name/of/dev/2Dattr[-1][3]```).
If any index exceeds actual dimensions of the array, the formula is evaluated to ERROR with an out of bounds exception.
No check is done on the order and uniqueness of indexes, so it is allowed to concatenate duplicated and out of order elements/rows/columns (e.g. ```name/of/dev/2Dattr[0-2,1,0,..]``` evaluates to an array with rows 0,1,2,1,0 of 2Dattr)
## Limitations
- It is not possible to specify array constants (e.g. ```name/of/dev/attr > [val1,val2]```).
- It is not possible to use indexes on expressions (e.g. ```(any_expression)[ind]```).
## Unary operators and functions
Unary operators and functions are applied to every element of the array
## Binary operators and functions
- If both operands have the same size, operators are applied element by element. Result is an array with the same size.
- If one operand has size one, operators apply it to every element of the other operand. Result is an array with the same size.
- Otherwise an exception is raised and the formula is evaluated to the *ERROR* state with the Reason, Descrption and Origin DevFailed fields properly filled.
## Ternary Function
- Conditional operator: if X then Y else Z. X is implicitly reduced with *OR* to have a boolean value, then Y or Z are evaluated depending on the result
# Formula result
Every formula produce a boolean result in the following way:
1. each element of the array is tested as not equal to zero in order to have an array of booleans
2. the array of boolean is reduced with OR (i.e. if at least one element of the array is TRUE, the result is TRUE)
# Errors
If a formula cannot be evaluated, the corresponding alarm is set to the *ERROR* value with the Reason, Description and Origin DevFailed fields properly filled.
Possible errors are:
- Errors coming from the event system for one or more attributes involved in the formula
- Errors coming from evaluation of array with different sizes
- Errors coming from indexes out of bound while extracting elements from arrays
- Unexpected errors while evaluating formulas
File added
File added
File added
File added
File added
File added
/*----- PROTECTED REGION ID(Alarm.cpp) ENABLED START -----*/
static const char *RcsId = "$Id: $";
//=============================================================================
//
// file : Alarm.cpp
//
// description : C++ source for the Alarm class and its commands.
// The class is derived from Device. It represents the
// CORBA servant object which will be accessed from the
// network. All commands which can be executed on the
// Alarm are implemented in this file.
//
// project : alarm
//
// This file is part of Tango device class.
//
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Tango. If not, see <http://www.gnu.org/licenses/>.
//
// $Author: $
//
// $Revision: $
// $Date: $
//
// $HeadURL: $
//
//=============================================================================
// This file is generated by POGO
// (Program Obviously used to Generate tango Object)
//=============================================================================
#include <tango.h>
#include <Alarm.h>
#include <AlarmClass.h>
#include <ctype.h> //for tolower
#include "alarm-thread.h"
#include "alarm_grammar.h"
#include "log_thread.h"
#include "update-thread.h"
//#define _DUMP_TREE_XML
#ifdef _DUMP_TREE_XML
#if BOOST_VERSION < 103600
#include <boost/spirit/iterator/fixed_size_queue.hpp>
#include <boost/spirit/core.hpp>
#include <boost/spirit/tree/ast.hpp>
#include <boost/spirit/tree/tree_to_xml.hpp>
using namespace boost::spirit;
#else
#include <boost/spirit/include/classic_fixed_size_queue.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_ast.hpp>
#include <boost/spirit/include/classic_tree_to_xml.hpp>
using namespace boost::spirit::classic;
#endif
#include <iostream>
#include <stack>
#include <functional>
#include <string>
#include <cassert>
#endif //_DUMP_TREE_XML
#include <sstream>
std::map<parser_id, std::string> rule_names; //only for log messages
int Alarm_ns::Alarm::instanceCounter = 0;
#ifndef ALARM_BUILDTIME
#define ALARM_BUILDTIME __DATE__ " " __TIME__ " boost=" BOOST_LIB_VERSION
#endif
const char version_string[] = "$Build: @buildID@ " ALARM_BUILDTIME " $";
static const char __FILE__rev[] = __FILE__ " $Revision: 1.29 $";
/*----- PROTECTED REGION END -----*/ // Alarm.cpp
/**
* Alarm class description:
* Elettra alarm device server
*/
//================================================================
// The following table gives the correspondence
// between command and method names.
//
// Command name | Method name
//================================================================
// State | Inherited (no method)
// Status | Inherited (no method)
// Ack | ack
// Load | load
// Remove | remove
// Configured | configured
// StopNew | stop_new
// Silence | silence
// Modify | modify
//================================================================
//================================================================
// Attributes managed is:
//================================================================
// alarm | Tango::DevString Spectrum ( max = 1024)
//================================================================
namespace Alarm_ns
{
/*----- PROTECTED REGION ID(Alarm::namespace_starting) ENABLED START -----*/
// static initializations
/*----- PROTECTED REGION END -----*/ // Alarm::namespace_starting
//--------------------------------------------------------
/**
* Method : Alarm::Alarm()
* Description : Constructors for a Tango device
* implementing the classAlarm
*/
//--------------------------------------------------------
Alarm::Alarm(Tango::DeviceClass *cl, string &s)
: TANGO_BASE_CLASS(cl, s.c_str())
{
/*----- PROTECTED REGION ID(Alarm::constructor_1) ENABLED START -----*/
init_device();
/*----- PROTECTED REGION END -----*/ // Alarm::constructor_1
}
//--------------------------------------------------------
Alarm::Alarm(Tango::DeviceClass *cl, const char *s)
: TANGO_BASE_CLASS(cl, s)
{
/*----- PROTECTED REGION ID(Alarm::constructor_2) ENABLED START -----*/
init_device();
/*----- PROTECTED REGION END -----*/ // Alarm::constructor_2
}
//--------------------------------------------------------
Alarm::Alarm(Tango::DeviceClass *cl, const char *s, const char *d)
: TANGO_BASE_CLASS(cl, s, d)
{
/*----- PROTECTED REGION ID(Alarm::constructor_3) ENABLED START -----*/
init_device();
/*----- PROTECTED REGION END -----*/ // Alarm::constructor_3
}
//--------------------------------------------------------
/**
* Method : Alarm::delete_device()
* Description : will be called at device destruction or at init command
*/
//--------------------------------------------------------
void Alarm::delete_device()
{
DEBUG_STREAM << "Alarm::delete_device() " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::delete_device) ENABLED START -----*/
// Delete device allocated objects
// Delete device's allocated object
/*
* unsubscribe events and release memory
*/
DEBUG_STREAM << "Alarm::delete_device(): entering..." << endl;
abortflag = true;
DEBUG_STREAM << "Alarm::delete_device(): after abortflag=true..." << endl;
try {
events->unsubscribe();
} catch (string& err) {
ERROR_STREAM << err << endl;
}
DEBUG_STREAM << "Alarm::delete_device(): events unsubscribed!" << endl;
events->free_proxy();
DEBUG_STREAM << "Alarm::delete_device(): device proxy deleted!" << endl;
/*
* kill alarm thread
*/
bei_t e;
e.ev_name = ALARM_THREAD_EXIT;
e.value.push_back(ALARM_THREAD_EXIT_VALUE);
e.value.push_back(ALARM_THREAD_EXIT_VALUE);
evlist.push_back(e);
#ifdef _RW_LOCK
alarms.del_rwlock();
#endif
alarms.stop_logdb();
alarms.stop_cmdthread();
sleep(1); //wait for alarm_thread and log_thread to exit
//delete almloop;
DEBUG_STREAM << "Alarm::delete_device(): stopped alarm and log threads!" << endl;
//delete proxy for actions
for(alarm_container_t::iterator i = alarms.v_alarm.begin(); i!=alarms.v_alarm.end(); i++)
{
if(i->second.dp_a)
delete i->second.dp_a;
i->second.dp_a = NULL;
if(i->second.dp_n)
delete i->second.dp_n;
i->second.dp_n = NULL;
}
/*
* clear all data structures
*/
alarms.v_alarm.clear();
events->v_event.clear();
evlist.clear();
/* for (int i = ds_num - 1; i >= 0; i--) {
CORBA::string_free(ds[i]);
}*/
ds_num = 0;
/*
* store current "alarmed" table status
*/
vector<string> vs;
for (vector<alarm_t>::iterator i = alarmed.begin(); \
i != alarmed.end(); i++) {
vs.push_back(i->alm2str());
}
Tango::DbDatum as("AlarmStatus");
Tango::DbData data_del;
data_del.push_back(as);
//get_db_device()->delete_property(data_del);
as << vs;
Tango::DbData data_put;
data_put.push_back(as);
#ifndef _USE_ELETTRA_DB_RW
Tango::Database *db = new Tango::Database();
#else
//salvataggio proprietà usando host_rw e port_rw per connettersi al database
Tango::Database *db;
if(host_rw != "")
db = new Tango::Database(host_rw,port_rw);
else
db = new Tango::Database();
#endif
try {
db->put_device_property(get_name(), data_put);
}
catch(Tango::DevFailed &e)
{
ERROR_STREAM << __FUNCTION__<< " error saving properties='" << e.errors[0].desc << "'";
}
delete db;
/*
* clear storage
*/
alarmed.clear();
delete alarmedlock;
delete internallock;
delete dslock;
delete events;
DEBUG_STREAM << "Alarm::delete_device(): saved AlarmStatus in properties!!" << endl;
//Tango::leavefunc();
/*----- PROTECTED REGION END -----*/ // Alarm::delete_device
}
//--------------------------------------------------------
/**
* Method : Alarm::init_device()
* Description : will be called at device initialization.
*/
//--------------------------------------------------------
void Alarm::init_device()
{
DEBUG_STREAM << "Alarm::init_device() create device " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::init_device_before) ENABLED START -----*/
// Initialization before get_device_property() call
int dbPortint=0;
abortflag = false;
instanceCounter++;
events = new event_table(this);
//because of static map<string, unsigned int> grp_str and of exception while subscribing
//more than one time the same event in the same executable, control the number of instances
if(instanceCounter > 1)
{
ERROR_STREAM << "More than one instance in the same executable of Alarm Server is not allowed!!" << endl;
cout << "ERROR: second instance of Alarm Server, exiting..." << endl;
exit(-1);
} //-------------------------------------------
errThreshold = 0;
alarmedlock = new(ReadersWritersLock);
internallock = new(ReadersWritersLock);
dslock = new(ReadersWritersLock);
/*----- PROTECTED REGION END -----*/ // Alarm::init_device_before
// Get the device properties from database
get_device_property();
/*----- PROTECTED REGION ID(Alarm::init_device) ENABLED START -----*/
// Initialize device
#ifdef _USE_ELETTRA_DB_RW
host_rw = "";
Tango::Database *db = new Tango::Database();
try
{
Tango::DbData db_data;
db_data.push_back((Tango::DbDatum("Host")));
db_data.push_back((Tango::DbDatum("Port")));
db->get_property("Database",db_data);
db_data[0] >> host_rw;
db_data[1] >> port_rw;
}catch(Tango::DevFailed &e)
{
ERROR_STREAM << __FUNCTION__ << " Error reading Database property='" << e.errors[0].desc << "'";
}
string server = "alarm-srv/test";
Tango::DbServerInfo info = db->get_server_info(server);
INFO_STREAM << " INFO: host=" << info.host;
delete db;
#endif
dbPortint = atoi(dbPort.c_str());
if(dbHost.empty() || dbUser.empty() || dbPasswd.empty() || dbName.empty() || (dbPortint == 0) || instanceName.empty())
{
ERROR_STREAM << "Alarm::init_device(): not all necessary properties are defined: DbHost="<<dbHost<<
" DbUser="<<dbUser<<" DbPasswd="<<dbPasswd<<" DbName="<<dbName<<" DbPort="<<dbPortint<<" InstanceName="<<instanceName<< endl;
cout << "Error: not all necessary properties are defined. Exiting..." << endl;
exit(-2);
}
ds_num = 0; //initialize number of lines returned by read_alarm
internal_counter = 0;
/*Tango::DbData db_data;
db_data.push_back(Tango::DbDatum("alarm"));
get_db_device()->get_attribute_property(db_data);*/
/*
* connect to log database
*/
#ifdef _RW_LOCK
alarms.new_rwlock();
#endif
try {
if((!dbHost.empty()) && (!dbUser.empty()) && (!dbPasswd.empty()) && (!dbName.empty()) && (dbPortint != 0) )
//logloop = new log_thread(dbhost, dbuser, dbpw, dbname, dbportint,this);
alarms.init_logdb(dbHost, dbUser, dbPasswd, dbName, dbPortint, instanceName);
} catch(string & e)
{
ERROR_STREAM << "Alarm::init_device(): " << e << endl;
cout << "Error: " << e << ". Exiting..." << endl;
exit(-3);
}
try {
alarms.init_cmdthread();
} catch(...)
{
WARN_STREAM << "Alarm::init_device(): error creating cmd thread" << endl;
}
rule_names[formula_grammar::val_rID] = "ValReal";
rule_names[formula_grammar::val_hID] = "ValHex";
rule_names[formula_grammar::val_stID] = "ValStatus";
rule_names[formula_grammar::event_ID] = "EventFather";
rule_names[formula_grammar::nameID] = "EventName";
rule_names[formula_grammar::indexID] = "EventIndex";
rule_names[formula_grammar::funcID] = "Function";
rule_names[formula_grammar::logical_exprID] = "LogicalE";
rule_names[formula_grammar::bitwise_exprID] = "BitwiseE";
rule_names[formula_grammar::equality_exprID] = "EqualityE";
rule_names[formula_grammar::compare_exprID] = "CompareE";
rule_names[formula_grammar::add_exprID] = "AddE";
rule_names[formula_grammar::mult_exprID] = "MultE";
rule_names[formula_grammar::expr_atomID] = "AtomicE";
rule_names[formula_grammar::shift_exprID] = "ShiftE";
rule_names[formula_grammar::unary_exprID] = "UnaryE";
/*
* get device attribute properties and initialize internal
* data structures
*/
// short n_prop;
string expr;
string pr_name;
vector<string> tmp_alm_vec;
/* db_data[0] >> n_prop;
INFO_STREAM << "Number alarm to load = " << n_prop << endl;
for (int i = 1; i <= n_prop; i++)
{
pr_name = db_data[i].name;
db_data[i] >> expr;
DEBUG_STREAM << " -> attr property: " << pr_name << " = " << expr << endl;
size_t pos = pr_name.find('_');
int count_ = 1;
while(pos != string::npos) //TODO: better this control
{
pos = pr_name.find('_', pos+1);
count_++;
if((count_ == 3) && (pos != string::npos)) //if at least 3 _ in the attr property name, expr is OK //TODO: better this control
{
tmp_alm_vec.push_back(expr);
break;
}
}
}*/
try {
alarms.get_alarm_list_db(tmp_alm_vec);
} catch(string & e)
{
ERROR_STREAM << "Alarm::init_device(): " << e << endl;
cout << "Error: " << e << ". Exiting..." << endl;
exit(-4);
}
/*
* store the alarms into alarm table vector
*/
map< string,vector<string> > alarm_event; //map alarm->vector event popolated by parser
vector<string> evn; //vector with all event (possibly duplicated) popolated by parser
vector<string> temp_evn;
vector<string> tmp_alm_name_lst;
//alarms.init(tmp_alm_vec, evn, alarm_event);
alarm_t tmp_alm;
evn.clear();
for(vector<string>::iterator it_al = tmp_alm_vec.begin(); it_al!= tmp_alm_vec.end(); it_al++)
{
tmp_alm.clear();
temp_evn.clear();
try {
load_alarm(*it_al, tmp_alm, temp_evn);
add_alarm(tmp_alm);
tmp_alm_name_lst.push_back(tmp_alm.name);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error loading alarm=" << tmp_alm.name << " , " << e.errors[0].desc << ends;
WARN_STREAM << "Alarm::init_device(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
continue;
} catch (string& err) {
ostringstream err_out;
err_out << "error loading alarm=" << tmp_alm.name << " , " << err << ends;
WARN_STREAM << "Alarm::init_device(): " << err_out.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err_out.str());
continue;
}
//eliminate duplicated event
if (temp_evn.empty() == false)
{
sort(temp_evn.begin(), temp_evn.end());
vector<string>::iterator new_end = \
unique(temp_evn.begin(), temp_evn.end());
while (temp_evn.end() != new_end)
temp_evn.pop_back();
}
alarm_event.insert(make_pair(tmp_alm.name,temp_evn));
evn.insert(evn.end(),temp_evn.begin(),temp_evn.end());
/* alarms.log_alarm_db(TYPE_LOG_DESC_SYNC, gettime(), tmp_alm.name, "", "", //remove if alarm with the same name exist but is changed
tmp_alm.formula, tmp_alm.grp2str(), tmp_alm.lev, tmp_alm.msg);
alarms.log_alarm_db(TYPE_LOG_DESC_ADD, gettime(), tmp_alm.name, "", "", //add new alarm if there is not already one active with the same name
tmp_alm.formula, tmp_alm.grp2str(), tmp_alm.lev, tmp_alm.msg);*/
}
/* alarms.log_alarm_db(TYPE_LOG_DESC_UPD_OLD, gettime(), "", "", "", //set as not active all alarms not present in this list
"", "", "", "", tmp_alm_name_lst);*/
DEBUG_STREAM << "alarms table size = " << alarms.size() << endl;
vector<string> al_table_string;
alarms.show(al_table_string);
for(vector<string>::iterator str_it=al_table_string.begin(); str_it!=al_table_string.end(); str_it++)
DEBUG_STREAM << (*str_it) << endl;
/*
* check 'stored' alarms against current alarm table for consistency
*/
vector<string> to_remove_from_stored;
if (stored.empty() == false) {
for (vector<alarm_t>::iterator i = stored.begin(); \
i != stored.end(); i++) {
alarm_container_t::iterator found = alarms.v_alarm.find(i->name);
if (found == alarms.v_alarm.end()) {
to_remove_from_stored.push_back(i->name);
//stored.erase(i);
}
}
}
for(vector<string>::iterator k=to_remove_from_stored.begin(); k != to_remove_from_stored.end(); k++)
{
vector<alarm_t>::iterator rmv = find(stored.begin(),stored.end(),*k);
if(rmv != stored.end())
{
ERROR_STREAM << "init_device(): alarm '" << *k \
<< "' NOT found in alarm table! " \
<< "Removing from 'stored' alarms" << endl;
stored.erase(rmv);
}
else
WARN_STREAM << "init_device(): alarm " << *k << " not found while removing from stored !!!" << endl;
}
/*
* update "alarm" table with "stored" alarms
*/
alarms.stored(stored);
/*
* update "alarmed" table with "stored" alarms
*/
if (stored.empty() == false) {
alarmedlock->writerIn();
for (vector<alarm_t>::iterator i = stored.begin(); \
i != stored.end(); i++) {
alarmed.push_back(*i);
}
alarmedlock->writerOut();
}
for(alarm_container_t::iterator i = alarms.v_alarm.begin(); \
i!=alarms.v_alarm.end(); i++)
{
if(i->second.cmd_name_a.length() > 0)
{
try {
i->second.dp_a = new Tango::DeviceProxy(i->second.cmd_dp_a);
i->second.dp_a->ping();
Tango::CommandInfo info = i->second.dp_a->command_query(i->second.cmd_action_a);
if((info.in_type != Tango::DEV_STRING) && (info.in_type != Tango::DEV_VOID))
{
ostringstream err;
err << i->second.name << ": error, command " << i->second.cmd_name_a << " does not accept a Tango::DevString or a Tango::DevVoid as input value" << ends;
ERROR_STREAM << "Alarm::init_device(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
else
{
if(info.in_type == Tango::DEV_STRING)
i->second.send_arg_a = true;
else
i->second.send_arg_a = false;
DEBUG_STREAM << "Alarm::init_device(): " << i->second.name << ": successfully connected to proxy=" << i->second.cmd_dp_a << " for action=" << i->second.cmd_action_a << endl;
}
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << i->second.name << ": error connecting to device proxy=" << i->second.cmd_dp_a << ", err=" << e.errors[0].desc << ends;
WARN_STREAM << "Alarm::init_device(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
i->second.dp_a = NULL;
}
}
if(i->second.cmd_name_n.length() > 0)
{
try {
i->second.dp_n = new Tango::DeviceProxy(i->second.cmd_dp_n);
i->second.dp_n->ping();
Tango::CommandInfo info = i->second.dp_n->command_query(i->second.cmd_action_n);
if((info.in_type != Tango::DEV_STRING) && (info.in_type != Tango::DEV_VOID))
{
ostringstream err;
err << i->second.name << ": error, command " << i->second.cmd_name_n << " does not accept a Tango::DevString or a Tango::DevVoid as input value" << ends;
ERROR_STREAM << "Alarm::init_device(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
else
{
if(info.in_type == Tango::DEV_STRING)
i->second.send_arg_n = true;
else
i->second.send_arg_n = false;
DEBUG_STREAM << "Alarm::init_device(): " << i->second.name << ": successfully connected to proxy=" << i->second.cmd_dp_n << " for action=" << i->second.cmd_action_n << endl;
}
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << i->second.name << ": error connecting to device proxy=" << i->second.cmd_dp_n << ", err=" << e.errors[0].desc << ends;
WARN_STREAM << "Alarm::init_device(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
i->second.dp_n = NULL;
}
}
}
alarms.startup_complete = gettime(); //enable actions execution in 10 seconds
ecb.init(&evlist);
for(map<string, vector<string> >::iterator al_ev_it=alarm_event.begin(); \
al_ev_it!=alarm_event.end(); al_ev_it++)
{
alarm_container_t::iterator i = alarms.v_alarm.find(al_ev_it->first);
if(i != alarms.v_alarm.end())
{
#if TANGO_VER < 611
try {
add_event(i->second, al_ev_it->second);
subscribe_event(i->second, ecb, al_ev_it->second);
} catch (string& err) {
WARN_STREAM << "Alarm::init_device(): " << err << endl;
for(vector<string>::iterator j=al_ev_it->second.begin(); j!=al_ev_it->second.end(); j++)
{
DEBUG_STREAM << "Alarm::init_device(): Removing alarm=" << i->second.name << " from event=" << *j << endl;
vector<event>::iterator k = \
find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end())
{
k->pop_alarm(i->second.name); //remove alarm/formula just added to event
DEBUG_STREAM << "Alarm::init_device(): Removed!!!! alarm=" << i->second.name << " from event=" << *j << endl;
if(k->m_alarm.empty())
{
events->v_event.erase(k); //remove event just added to event_table
DEBUG_STREAM << "Alarm::init_device(): event=" << *j << " no more used, REMOVED!!!" << endl;
}
}
}
set_internal_alarm(INTERNAL_ERROR, gettime(), err);
}
#else
try {
add_event(i->second, al_ev_it->second);
} catch (string& err) {
WARN_STREAM << "Alarm::init_device(): " << err << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err);
}
try {
subscribe_event(i->second, ecb, al_ev_it->second);
} catch (string& err) {
WARN_STREAM << "Alarm::init_device(): " << err << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err);
}
#endif
}
}
/*
* update event table with fresh-subscribed event[s] data
*/
list<bei_t> el;
el = evlist.show();
try {
for (list<bei_t>::iterator j = el.begin(); j != el.end(); j++)
{
//cout << "name = " << j->name << "\ttype = " << j->type << endl;
events->update_events(*j);
}
}
catch (string& err)
{
WARN_STREAM << "init_device(): error updating events = " << err << endl;
}
set_change_event("alarm",true,false);
/*
* create alarm processing thread
*/
//almloop = new alarm_thread::alarm_thread(/*this*/);
almloop = new alarm_thread(this);
almloop->start();
updateloop = new update_thread(this);
updateloop->start();
set_state(Tango::RUNNING);
set_status("Alarm server is running");
//
// for (int i=0; i< MAX_ALARMS ; i++) ds[i]=0;
// ds_num = 0;
for (int i=0; i< MAX_ALARMS ; i++)
ds[i]=(char *) (dss[i]);
/*----- PROTECTED REGION END -----*/ // Alarm::init_device
}
//--------------------------------------------------------
/**
* Method : Alarm::get_device_property()
* Description : Read database to initialize property data members.
*/
//--------------------------------------------------------
void Alarm::get_device_property()
{
/*----- PROTECTED REGION ID(Alarm::get_device_property_before) ENABLED START -----*/
// Initialize property data members
/*----- PROTECTED REGION END -----*/ // Alarm::get_device_property_before
// Read device properties from database.
Tango::DbData dev_prop;
dev_prop.push_back(Tango::DbDatum("AlarmStatus"));
dev_prop.push_back(Tango::DbDatum("GroupNames"));
dev_prop.push_back(Tango::DbDatum("ErrThreshold"));
dev_prop.push_back(Tango::DbDatum("DbHost"));
dev_prop.push_back(Tango::DbDatum("DbUser"));
dev_prop.push_back(Tango::DbDatum("DbPasswd"));
dev_prop.push_back(Tango::DbDatum("DbName"));
dev_prop.push_back(Tango::DbDatum("DbPort"));
dev_prop.push_back(Tango::DbDatum("InstanceName"));
// is there at least one property to be read ?
if (dev_prop.size()>0)
{
// Call database and extract values
if (Tango::Util::instance()->_UseDb==true)
get_db_device()->get_property(dev_prop);
// get instance on AlarmClass to get class property
Tango::DbDatum def_prop, cl_prop;
AlarmClass *ds_class =
(static_cast<AlarmClass *>(get_device_class()));
int i = -1;
// Try to initialize AlarmStatus from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> alarmStatus;
else {
// Try to initialize AlarmStatus from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> alarmStatus;
}
// And try to extract AlarmStatus value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> alarmStatus;
// Try to initialize GroupNames from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> groupNames;
else {
// Try to initialize GroupNames from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> groupNames;
}
// And try to extract GroupNames value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> groupNames;
// Try to initialize ErrThreshold from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> errThreshold;
else {
// Try to initialize ErrThreshold from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> errThreshold;
}
// And try to extract ErrThreshold value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> errThreshold;
// Try to initialize DbHost from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> dbHost;
else {
// Try to initialize DbHost from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> dbHost;
}
// And try to extract DbHost value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbHost;
// Try to initialize DbUser from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> dbUser;
else {
// Try to initialize DbUser from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> dbUser;
}
// And try to extract DbUser value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbUser;
// Try to initialize DbPasswd from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> dbPasswd;
else {
// Try to initialize DbPasswd from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> dbPasswd;
}
// And try to extract DbPasswd value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbPasswd;
// Try to initialize DbName from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> dbName;
else {
// Try to initialize DbName from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> dbName;
}
// And try to extract DbName value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbName;
// Try to initialize DbPort from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> dbPort;
else {
// Try to initialize DbPort from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> dbPort;
}
// And try to extract DbPort value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> dbPort;
// Try to initialize InstanceName from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> instanceName;
else {
// Try to initialize InstanceName from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> instanceName;
}
// And try to extract InstanceName value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> instanceName;
}
/*----- PROTECTED REGION ID(Alarm::get_device_property_after) ENABLED START -----*/
// Check device property data members init
/*
* initialize groups
*/
alarm_t tmp_alm;
tmp_alm.init_static_map(groupNames);
/*
* retrive last saved alarms status
*/
if (alarmStatus.empty() == false) {
for (vector<string>::iterator i = alarmStatus.begin(); \
i != alarmStatus.end(); i++) {
/*
* test for string length; data[1].is_empty() will return false
* when empty string eventually initialized with jive!!!!!!
*/
if (i->length() != 0) {
alarm_t tmp_alm;
tmp_alm.str2alm(*i);
tmp_alm.is_new = /*(tmp_alm.stat == S_ALARM) ? 1 :*/ 0; //don't beep at startup on old alarms
stored.push_back(tmp_alm);
}
}
}
DEBUG_STREAM << "saved alarms table:" << endl;
if (stored.empty() == false) {
for (vector<alarm_t>::iterator a = stored.begin(); \
a != stored.end(); a++) {
DEBUG_STREAM << "\t" << a->alm2str() << endl;
}
}
/*----- PROTECTED REGION END -----*/ // Alarm::get_device_property_after
}
//--------------------------------------------------------
/**
* Method : Alarm::always_executed_hook()
* Description : method always executed before any command is executed
*/
//--------------------------------------------------------
void Alarm::always_executed_hook()
{
DEBUG_STREAM << "Alarm::always_executed_hook() " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::always_executed_hook) ENABLED START -----*/
// code always executed before all requests
/*----- PROTECTED REGION END -----*/ // Alarm::always_executed_hook
}
//--------------------------------------------------------
/**
* Method : Alarm::read_attr_hardware()
* Description : Hardware acquisition for attributes
*/
//--------------------------------------------------------
void Alarm::read_attr_hardware(TANGO_UNUSED(vector<long> &attr_list))
{
DEBUG_STREAM << "Alarm::read_attr_hardware(vector<long> &attr_list) entering... " << endl;
/*----- PROTECTED REGION ID(Alarm::read_attr_hardware) ENABLED START -----*/
// Add your own code
//DEBUG_STREAM << "In read_attr_hardware for " << attr_list.size() << " attribute(s)" << endl;
// Add your own code here
//---------------------------------
/*----- PROTECTED REGION END -----*/ // Alarm::read_attr_hardware
}
//--------------------------------------------------------
/**
* Read attribute alarm related method
* Description:
*
* Data type: Tango::DevString
* Attr type: Spectrum max = 1024
*/
//--------------------------------------------------------
void Alarm::read_alarm(Tango::Attribute &attr)
{
DEBUG_STREAM << "Alarm::read_alarm(Tango::Attribute &attr) entering... " << endl;
/*----- PROTECTED REGION ID(Alarm::read_alarm) ENABLED START -----*/
// Add your own code here
#if 0
alarm_container_t::iterator ai;
vector<alarm_t>::iterator aid;
for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) {
if (ai->second.stat == S_ALARM) {
/*
* alarm status is S_ALARM
*/
aid = find(alarmed.begin(), alarmed.end(),ai->second.name);
if (aid != alarmed.end()) {
/*
* found, change stat only if switching from
* S_NORMAL to S_ALARM status
*/
//cout << "read_attr(): S_ALARM: found: " << aid->name << endl;
if (aid->stat == S_NORMAL) {
aid->stat = S_ALARM;
aid->ack = NOT_ACK;
aid->ts = ai->second.ts;
aid->msg = ai->second.msg;
}
aid->grp = ai->second.grp;
aid->lev = ai->second.lev;
aid->is_new = ai->second.is_new; //copy is_new state
//ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0
aid->counter = ai->second.counter;
aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset
aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary)
aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update
} else {
/*
* not found: new "alarmed" item
*/
DEBUG_STREAM << "read_attr(): S_ALARM: pushing new alarm: " \
<< ai->second.name << "\t" << ai->second.stat << endl;
alarmed.push_back(ai->second);
//ai->second.is_new = 0; //set state as not more new //12-06-08: StopNew command set it to 0
}
} else if (ai->second.stat == S_NORMAL) {
/*
* alarm status is S_NORMAL
*/
aid = find(alarmed.begin(), alarmed.end(), ai->second.name);
if (aid != alarmed.end()) {
/*
* found, as it should;
* switching from S_ALARM to S_NORMAL
*/
aid->stat = S_NORMAL;
aid->ts = ai->second.ts;
//aid->msg = " "; /* no message again */
aid->msg =ai->second.msg;
aid->grp = ai->second.grp;
aid->lev = ai->second.lev;
aid->counter = ai->second.counter;
aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset
aid->is_new = ai->second.is_new; //copy is_new state
aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary)
aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update
//ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0
if (aid->ack == ACK) {
if (aid->done) {
/*
* if already ACKnowledged and visualized
* remove from "alarmed" list
*/
DEBUG_STREAM << "read_attr(): S_NORMAL: " << aid->name \
<< " ACKnowledged: removing" << endl;
alarmed.erase(aid);
} else {
aid->done = true;
}
} /* if */
} /* if */
} /* if else if */
} /* for */
vector<string> tmp_alarm_table;
string is_new;
ostringstream os1;
/*os1.clear();
os1 << header << "\t" << alarmed.size() << ends;*/
//tmp_alarm_table.push_back(os1.str());
if (alarmed.empty() == false) {
for (aid = alarmed.begin(); aid != alarmed.end(); aid++) {
if(aid->silenced > 0)
{
Tango::TimeVal now = gettime();
double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000;
double dsilent = aid->ts_time_silenced.tv_sec + ((double)aid->ts_time_silenced.tv_usec) / 1000000;
double dminutes = (dnow - dsilent)/60;
//silenced already calculated in alarm_table::update, but here updated for panel also if state not changed:
//to see minutes countdown
if(dminutes < aid->silent_time)
aid->silenced = aid->silent_time - floor(dminutes);
else
aid->silenced = 0;
}
ostringstream os;
os.clear();
is_new.clear();
is_new = (aid->is_new && aid->silenced <= 0) ? "NEW" : " ";
os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \
<< aid->name << "\t" << aid->stat << "\t" << aid->ack \
<< "\t" << aid->counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new << ends;
tmp_alarm_table.push_back(os.str());
}
}
if (internal.empty() == false) {
for (aid = internal.begin(); aid != internal.end(); aid++) {
/* size_t index;
int count = 1;
index = aid->stat.find("*");
if((index != std::string::npos) && (index+1 != std::string::npos))
{
size_t last = aid->stat.size();
string str_count= aid->stat.substr(index+1, last - index+1);
count = strtol(str_count.c_str(), 0,10);
}
//do not show internal alarms that have a molteplicity less then errThreshold
if((aid->msg.find()) && (count < errThreshold))
continue;*/
ostringstream os;
os.clear();
os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \
<< aid->name << "\t" << aid->stat << "\t" << aid->ack \
<< "\t" << aid->counter << "\t" << aid->lev << "\t"<< -1/*silenced*/ <<"\t" << aid->grp2str() << "\t" << aid->msg << "\t "<< ends; //TODO: silenced for internal errors?
tmp_alarm_table.push_back(os.str());
}
}
int i;
for (i = ds_num - 1; i >= 0; i--) {
CORBA::string_free(ds[i]);
}
ds_num = tmp_alarm_table.size();
if(ds_num > MAX_ALARMS)
ds_num = MAX_ALARMS;
for (i = 0; i < ds_num; i++) {
ds[i] = CORBA::string_dup(tmp_alarm_table[i].c_str());
}
if(ds_num == 0)
{
ostringstream os1;
ds_num++;
os1.clear();
os1 << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << -1 << "\t" << 0 << "\t" << 0 << "\t "<< ends;
ds[0] = CORBA::string_dup(os1.str().c_str());
}
#else
//bool changed;
//prepare_alarm_attr(changed);//moved in do_alarm;
#endif
if(ds_num == 0)
{
attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
attr.set_value(ds, ds_num, 0, false);
/*----- PROTECTED REGION END -----*/ // Alarm::read_alarm
}
//--------------------------------------------------------
/**
* Method : Alarm::add_dynamic_attributes()
* Description : Create the dynamic attributes if any
* for specified device.
*/
//--------------------------------------------------------
void Alarm::add_dynamic_attributes()
{
/*----- PROTECTED REGION ID(Alarm::add_dynamic_attributes) ENABLED START -----*/
// Add your own code to create and add dynamic attributes if any
/*----- PROTECTED REGION END -----*/ // Alarm::add_dynamic_attributes
}
//--------------------------------------------------------
/**
* Command Ack related method
* Description: Alarm acknowledge
*
* @param argin String array containing the alarms to be acknowledged
*/
//--------------------------------------------------------
void Alarm::ack(const Tango::DevVarStringArray *argin)
{
DEBUG_STREAM << "Alarm::Ack() - " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::ack) ENABLED START -----*/
// Add your own code
vector<string> str;
str << (*argin);
vector<string>::iterator si;
for (si = str.begin(); si != str.end(); si++) {
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
alarmedlock->readerIn();
vector<alarm_t>::iterator found = \
find(alarmed.begin(), alarmed.end(), *si);
if (found != alarmed.end())
{
alarm_container_t::iterator i = alarms.v_alarm.find(*si);
if(i != alarms.v_alarm.end())
{
//update alarm ack in alarm table
i->second.ack = ACK;
//update alarm status from alarm table
found->stat = i->second.stat;
}
if(found->ack == NOT_ACK)
{
alarms.log_alarm_db(TYPE_LOG_STATUS, gettime(), found->name, found->stat, ACK,
"", 0, "", "", "", "", -1);
}
found->ack = ACK;
} else {
internallock->readerIn();
found = find(internal.begin(), internal.end(), *si);
if (found != internal.end()) {
found->ack = ACK;
} else {
ostringstream o;
o << "\"" << *si << "\" not in 'alarmed' or 'internal' table" << endl;
WARN_STREAM << "Alarm::ack(): " << o.str() << endl;
internallock->readerOut();
alarmedlock->readerOut();
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
Tango::Except::throw_exception( \
(const char*)"Alarm not found!!", \
o.str(), \
(const char*)"Alarm::ack()", Tango::ERR);
}
internallock->readerOut();
}
alarmedlock->readerOut();
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
}
/*
* remove S_NORMAL status ACKnowledged alarms
*/
alarm_t to_be_removed;
to_be_removed.name = "";
to_be_removed.formula = "";
to_be_removed.stat = S_NORMAL;
to_be_removed.ack = ACK;
bool go = true;
while (go) {
alarmedlock->writerIn();
vector<alarm_t>::iterator found = \
find(alarmed.begin(), alarmed.end(), to_be_removed);
if (found != alarmed.end()) {
DEBUG_STREAM << "Alarm::ack(): " << found->name \
<< " S_NORMAL and ACK, removing" << endl;
alarmed.erase(found);
} else {
go = false;
}
alarmedlock->writerOut();
}
/*
* always remove internal ACKnowlwdged alarms as
* they'll wont switch to "NORMAL"
*/
to_be_removed.name = "";
to_be_removed.formula = "";
to_be_removed.stat = S_ALARM;
to_be_removed.ack = ACK;
go = true;
while (go) {
internallock->writerIn();
vector<alarm_t>::iterator found = \
find(internal.begin(), internal.end(), to_be_removed);
if (found != internal.end()) {
DEBUG_STREAM << "Alarm::ack(): " << found->name \
<< " ACK, removing" << endl;
internal.erase(found);
} else {
go = false;
}
internallock->writerOut();
}
prepare_alarm_attr();
try
{
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error pushing alarm change event err=" << e.errors[0].desc;
INFO_STREAM << __func__<<": " << err.str() << endl;
}
/*----- PROTECTED REGION END -----*/ // Alarm::ack
}
//--------------------------------------------------------
/**
* Command Load related method
* Description: Load a new alarm.
*
* @param argin Alarm entry
*/
//--------------------------------------------------------
void Alarm::load(Tango::DevString argin)
{
DEBUG_STREAM << "Alarm::Load() - " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::load) ENABLED START -----*/
// Add your own code
string s;
alarm_t alm;
vector<string> evn;
s = argin;
//std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase
Tango::TimeVal ts = gettime();
try {
load_alarm(s, alm, evn);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error loading alarm=" << alm.name << " , " << e.errors[0].desc << ends;
WARN_STREAM << "Alarm::load(): " << err.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Alarm::load()", \
err.str(), \
(const char*)"Alarm::load()", Tango::ERR);
}
try {
add_alarm(alm);
} catch (string& err) {
WARN_STREAM << "Alarm::load(): " << err << endl;
Tango::Except::throw_exception( \
(const char*)"Alarm::load()", \
(const char*)err.c_str(), \
(const char*)"Alarm::load()", Tango::ERR);
}
try {
add_event(alm, evn);
} catch (string& err) {
WARN_STREAM << "Alarm::load(): " << err << endl;
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->writerIn();
#endif
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added
if (i != alarms.v_alarm.end())
alarms.erase(i); //and remove from alarm_table
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
Tango::Except::throw_exception( \
(const char*)"Alarm::load()", \
(const char*)err.c_str(), \
(const char*)"Alarm::load()", Tango::ERR);
}
string cmd_name_full = alm.cmd_name_a + string(";") + alm.cmd_name_n;
alarms.log_alarm_db(TYPE_LOG_DESC_ADD, ts, alm.name, "", "", //add new alarm on log before subscribe event
alm.formula, alm.time_threshold, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time); //but if it fails remove it from table
try {
subscribe_event(alm, ecb, evn);
} catch (string& err) {
WARN_STREAM << "Alarm::load(): " << err << endl;
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->writerIn();
#endif
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added
if (i != alarms.v_alarm.end())
alarms.erase(i); //and remove from alarm_table
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
alarms.log_alarm_db(TYPE_LOG_DESC_REM, ts, alm.name, "", "", //remove alarm just added
"", 0, "", "", "", "", -1);
Tango::Except::throw_exception( \
(const char*)"Alarm::load()", \
(const char*)err.c_str(), \
(const char*)"Alarm::load()", Tango::ERR);
}
if(alm.cmd_name_a.length() > 0)
{
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added
if (i != alarms.v_alarm.end())
{
try {
i->second.dp_a = new Tango::DeviceProxy(i->second.cmd_dp_a);
i->second.dp_a->ping();
Tango::CommandInfo info = i->second.dp_a->command_query(i->second.cmd_action_a);
if(info.in_type != Tango::DEV_STRING)
{
ostringstream err;
err << "Error: command " << i->second.cmd_name_a << " does not accept a Tango::DevString as input value" << ends;
ERROR_STREAM << "Alarm::load(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
else
{
if(info.in_type == Tango::DEV_STRING)
i->second.send_arg_a = true;
else
i->second.send_arg_a = false;
DEBUG_STREAM << "Alarm::load(): successfully connected to proxy=" << i->second.cmd_dp_a << " for action=" << i->second.cmd_action_a << endl;
}
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_a << ", err=" << e.errors[0].desc << ends;
WARN_STREAM << "Alarm::load(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
}
if(alm.cmd_name_n.length() > 0)
{
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name); //look for alarm just added
if (i != alarms.v_alarm.end())
{
try {
i->second.dp_n = new Tango::DeviceProxy(i->second.cmd_dp_n);
i->second.dp_n->ping();
Tango::CommandInfo info = i->second.dp_n->command_query(i->second.cmd_action_a);
if(info.in_type != Tango::DEV_STRING)
{
ostringstream err;
err << "Error: command " << i->second.cmd_name_n << " does not accept a Tango::DevString as input value" << ends;
ERROR_STREAM << "Alarm::load(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
else
{
if(info.in_type == Tango::DEV_STRING)
i->second.send_arg_n = true;
else
i->second.send_arg_n = false;
DEBUG_STREAM << "Alarm::load(): successfully connected to proxy=" << i->second.cmd_dp_n << " for action=" << i->second.cmd_action_n << endl;
}
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_n << ", err=" << e.errors[0].desc << ends;
WARN_STREAM << "Alarm::load(): " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
}
//if at least one event was already existing, evaluate formula of just added alarm
if(alm.to_be_evaluated) //TODO: remove this evaluation of the formula that is not necessary
{
DEBUG_STREAM << "Alarm::load(): Evaluating formula=" << alm.formula << endl;
try {
double res;
string attr_values;
res = eval_formula(alm.formula_tree, attr_values);
DEBUG_STREAM << "Parsing succeeded of "<< alm.formula << "; result=" << res << endl;
alarms.update(alm.name, gettime(), (int)res, attr_values, alm.grp2str(), alm.msg, alm.formula); //pass "now" as timestamp in this case
} catch(std::out_of_range& e)
{
ostringstream o;
o << alm.name << ": in formula array index out of range!" << ends;
WARN_STREAM << "Alarm::load(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
} catch(string & e)
{
ostringstream o;
o << alm.name << ": in formula err=" << e << ends;
WARN_STREAM << "Alarm::load(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
} catch(Tango::DevFailed& e)
{
ostringstream o;
o << alm.name << "error=" << e.errors[0].desc << ends;
WARN_STREAM << "Alarm::load(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
}
}
prepare_alarm_attr();
try
{
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error pushing alarm change event err=" << e.errors[0].desc;
INFO_STREAM << __func__<<": " << err.str() << endl;
}
/*----- PROTECTED REGION END -----*/ // Alarm::load
}
//--------------------------------------------------------
/**
* Command Remove related method
* Description: Remove alarm.
*
* @param argin Alarm name
*/
//--------------------------------------------------------
void Alarm::remove(Tango::DevString argin)
{
DEBUG_STREAM << "Alarm::Remove() - " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::remove) ENABLED START -----*/
// Add your own code
string s, log_alm_name;
s = argin;
log_alm_name = argin;
bool ret = false;
alarmedlock->readerIn();
vector<alarm_t>::iterator found = find(alarmed.begin(), alarmed.end(), s);
if (found != alarmed.end())
{
ostringstream err;
err << s << " is in ALARM status! Acknowledge it before removing." << ends;
if((found->stat == S_ALARM) && (found->ack == NOT_ACK))
{
alarmedlock->readerOut();
Tango::Except::throw_exception( \
(const char*)"Error removing alarm", \
(const char*)err.str().c_str(), \
(const char*)"Alarm::remove", Tango::ERR);
}
}
alarmedlock->readerOut();
try {
ret = remove_alarm(s);
} catch (string& err) {
Tango::Except::throw_exception( \
(const char*)"Error removing alarm", \
(const char*)err.c_str(), \
(const char*)"Alarm::remove", Tango::ERR);
}
if (ret) {
DEBUG_STREAM << "Alarm::remove(): removing alarm '" \
<< s << "'" << endl;
while (true) {
string::size_type i = s.find_first_of("/.");
if (i == string::npos)
break;
s.replace(i, 1, "_");
}
} /* end if */
alarms.log_alarm_db(TYPE_LOG_DESC_DIS, gettime(), log_alm_name, "", "", //set active to 0
"", 0, "", "", "", "", -1);
alarmedlock->writerIn();
found = find(alarmed.begin(), alarmed.end(), s); //look again because in the meanwhile lock was not acquired
if (found != alarmed.end())
{
alarmed.erase(found); //remove from alarmed table
}
alarmedlock->writerOut();
prepare_alarm_attr();
try
{
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error pushing alarm change event err=" << e.errors[0].desc;
INFO_STREAM << __func__<<": " << err.str() << endl;
}
/*----- PROTECTED REGION END -----*/ // Alarm::remove
}
//--------------------------------------------------------
/**
* Command Configured related method
* Description: Alarms configured
*
* @param argin String containing a filter for output, if empty return all alarms
* @returns Alarms configured
*/
//--------------------------------------------------------
Tango::DevVarStringArray *Alarm::configured(Tango::DevString argin)
{
Tango::DevVarStringArray *argout;
DEBUG_STREAM << "Alarm::Configured() - " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::configured) ENABLED START -----*/
// Add your own code
// POGO has generated a method core with argout allocation.
// If you would like to use a static reference without copying,
// See "TANGO Device Server Programmer's Manual"
// (chapter : Writing a TANGO DS / Exchanging data)
//------------------------------------------------------------
argout = new Tango::DevVarStringArray();
//argout->length(1);
//(*argout)[0] = CORBA::string_dup("dummy");
DEBUG_STREAM << "Alarm::configured(): entering... !" << endl;
// Add your own code to control device here
string filter(argin);
size_t found;
vector<string> alarm_filtered;
ostringstream os1;
os1.clear();
/*os1 << headerConfig << "\t" << alarms.v_alarm.size() << ends;
alarm_filtered.push_back(os1.str());*/
alarm_container_t::iterator ai;
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++)
{
found = 0;
if(filter.length() != 0)
{
found = ai->first.find(filter);
}
if((filter.length() == 0) || (found != string::npos))
{
ostringstream os;
os.clear();
os << ai->second.ts.tv_sec << "\t" << ai->second.name << "\t" << ai->second.formula << "\t" << ai->second.time_threshold <<
"\t" << ai->second.lev << "\t" << ai->second.silent_time << "\t" << ai->second.grp2str() << "\t" << ai->second.msg << "\t" <<
ai->second.cmd_name_a << ";" << ai->second.cmd_name_n << ends;
alarm_filtered.push_back(os.str());
}
} /* for */
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
argout->length(alarm_filtered.size());
int i = 0;
for (vector<string>::iterator it= alarm_filtered.begin(); it != alarm_filtered.end(); it++)
{
(*argout)[i] = CORBA::string_dup(it->c_str());
i++;
}
/*----- PROTECTED REGION END -----*/ // Alarm::configured
return argout;
}
//--------------------------------------------------------
/**
* Command StopNew related method
* Description: Remove "NEW" field from alarm string (so alarm panel stop sound)
*
*/
//--------------------------------------------------------
void Alarm::stop_new()
{
DEBUG_STREAM << "Alarm::StopNew() - " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::stop_new) ENABLED START -----*/
// Add your own code
//12-06-08: StopNew command set is_new to 0
// Add your own code to control device here
alarm_container_t::iterator ai;
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) {
ai->second.is_new = 0; //set all alarm as no more new
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
prepare_alarm_attr();
try
{
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error pushing alarm change event err=" << e.errors[0].desc;
INFO_STREAM << __func__<<": " << err.str() << endl;
}
/*----- PROTECTED REGION END -----*/ // Alarm::stop_new
}
//--------------------------------------------------------
/**
* Command Silence related method
* Description: Alarm temporarily silence
*
* @param argin String array containing the alarms to be silenced
*/
//--------------------------------------------------------
void Alarm::silence(const Tango::DevVarStringArray *argin)
{
DEBUG_STREAM << "Alarm::Silence() - " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::silence) ENABLED START -----*/
// Add your own code
vector<string> str;
str << (*argin);
vector<string>::iterator si;
for (si = str.begin(); si != str.end(); si++)
{
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
alarm_container_t::iterator i = alarms.v_alarm.find(*si);
if(i != alarms.v_alarm.end())
{
if(i->second.silenced > 0)
{
Tango::TimeVal now = gettime();
double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000;
double dsilent = i->second.ts_time_silenced.tv_sec + ((double)i->second.ts_time_silenced.tv_usec) / 1000000;
double dminutes = (dnow - dsilent)/60;
//silenced already calculated in alarm_table::update, but here updated for panel also if state not changed:
//to see minutes countdown
if(dminutes < i->second.silent_time)
i->second.silenced = i->second.silent_time - floor(dminutes);
else
i->second.silenced = 0;
}
if(i->second.silenced > 0)
{
ostringstream err;
err << "Alarm " << *si << " already silenced for " << i->second.silenced << " more minutes" << ends;
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
Tango::Except::throw_exception( \
(const char*)"Alarm already silenced", \
err.str(), \
(const char*)"Alarm::silence()", Tango::ERR);
}
if(i->second.silent_time <= 0)
{
ostringstream err;
err << "Alarm " << *si << " cannot be silenced" << ends;
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
Tango::Except::throw_exception( \
(const char*)"Alarm cannot be silenced", \
err.str(), \
(const char*)"Alarm::silence()", Tango::ERR);
}
//load silent time
i->second.ts_time_silenced = gettime();
i->second.silenced = i->second.silent_time;
//search also in alarmed
alarmedlock->readerIn();
vector<alarm_t>::iterator found = \
find(alarmed.begin(), alarmed.end(), *si);
if (found != alarmed.end())
{
//load silent time from alarm table
found->silenced = i->second.silent_time;
found->ts_time_silenced = i->second.ts_time_silenced;
}
alarmedlock->readerOut();
}
//alarms.unlock();
if(i == alarms.v_alarm.end())
{
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
ostringstream err;
err << "Alarm " << *si << " not found" << ends;
Tango::Except::throw_exception( \
(const char*)"Alarm not found!!", \
err.str(), \
(const char*)"Alarm::silence()", Tango::ERR);
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
}
prepare_alarm_attr();
try
{
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error pushing alarm change event err=" << e.errors[0].desc;
INFO_STREAM << __func__<<": " << err.str() << endl;
}
/*----- PROTECTED REGION END -----*/ // Alarm::silence
}
//--------------------------------------------------------
/**
* Command Modify related method
* Description: Modify an existing alarm.
*
* @param argin Alarm entry
*/
//--------------------------------------------------------
void Alarm::modify(Tango::DevString argin)
{
DEBUG_STREAM << "Alarm::Modify() - " << device_name << endl;
/*----- PROTECTED REGION ID(Alarm::modify) ENABLED START -----*/
// Add your own code
//------------------------------
//1: parse to get alarm name
//------------------------------
string alarm_string(argin);
alarm_t alm;
alarm_parse al_gr(alm); // Construct Spirit grammar
alm.name.clear();
alm.formula.clear();
alm.msg.clear();
alm.lev.clear();
alm.grp=0;
alm.to_be_evaluated = false;
alm.time_threshold = 0;
alm.silent_time = -1;
alm.silenced = -1;
alm.cmd_name_a.clear();
alm.cmd_dp_a.clear();
alm.cmd_action_a.clear();
alm.send_arg_a = false;
alm.dp_a = NULL;
alm.cmd_name_n.clear();
alm.cmd_dp_n.clear();
alm.cmd_action_n.clear();
alm.send_arg_n = false;
alm.dp_n = NULL;
#ifndef _ACCESS_NODE_D
alm.formula_tree = ast_parse(alarm_string.c_str(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces
#else
alm.formula_tree =
//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces
#endif
if (alm.formula_tree.full)
{
std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower); //transform to lowercase
//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower); //transform to lowercase: incorrect, state has to be written upercase
std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower); //transform to lowercase
if(alm.cmd_name_a.length() > 0)
{
const char *c = alm.cmd_name_a.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_a.push_back(*c);
else if (*c != '/')
alm.cmd_action_a.push_back(*c);
c++;
}
}
if(alm.cmd_name_n.length() > 0)
{
const char *c = alm.cmd_name_n.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_n.push_back(*c);
else if (*c != '/')
alm.cmd_action_n.push_back(*c);
c++;
}
}
}
else
{
ostringstream o;
#ifndef _ACCESS_NODE_D
o << __func__<<": Parsing Failed, syntax error stopped at " << alm.formula_tree.stop << ends;
#else
o << __func__<<": Parsing Failed, syntax error stopped at " << string(alm.formula_tree.stop, alarm_string.end()) << ends; //TODO
#endif
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Parsing Failed!", \
(const char*)o.str().c_str(), \
(const char*)__func__, Tango::ERR);
}
//------------------------------
//2: if alarm already exist and
// formula is not changed
//------------------------------
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->writerIn();
#endif
alarm_container_t::iterator i = alarms.v_alarm.find(alm.name);
if (i != alarms.v_alarm.end())
{
if(i->second.formula == alm.formula)
{
Tango::TimeVal ts = gettime();
string cmd_name_full = alm.cmd_name_a + string(";") + alm.cmd_name_n;
if ((alm.name.empty() == false) && \
(alm.formula.empty() == false) && \
((alm.lev==LEV_LOG)||(alm.lev==LEV_WARNING)|| \
(alm.lev==LEV_FAULT)||(alm.lev.empty() == true))) {
i->second.stat = S_NORMAL;
i->second.ack = ACK;
i->second.done = false;
i->second.msg = alm.msg;
i->second.lev = alm.lev;
i->second.grp = alm.grp;
//i->second.to_be_evaluated = alm.to_be_evaluated;
i->second.time_threshold = alm.time_threshold;
i->second.silent_time = alm.silent_time;
i->second.silenced = alm.silenced;
i->second.cmd_name_a = alm.cmd_name_a;
i->second.cmd_dp_a = alm.cmd_dp_a;
i->second.cmd_action_a = alm.cmd_action_a;
//i->second.send_arg_a = alm.send_arg_a;
i->second.cmd_name_n = alm.cmd_name_n;
i->second.cmd_dp_n = alm.cmd_dp_n;
i->second.cmd_action_n = alm.cmd_action_n;
//i->second.send_arg_n = alm.send_arg_n;
} else {
ostringstream o;
o << __func__<<": syntax error in '" << alarm_string << "'" << ends;
WARN_STREAM << o.str() << endl;
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
Tango::Except::throw_exception( \
(const char*)o.str().c_str(), \
(const char*)"", \
(const char*)__func__, Tango::ERR);
}
alarms.log_alarm_db(TYPE_LOG_DESC_UPDATE, ts, alm.name, "", "",
alm.formula, alm.time_threshold, alm.grp2str(), alm.lev, alm.msg, cmd_name_full, alm.silent_time);
//delete proxy for actions
if(i->second.dp_a)
delete i->second.dp_a;
i->second.dp_a = NULL;
if(i->second.dp_n)
delete i->second.dp_n;
i->second.dp_n = NULL;
if(alm.cmd_name_a.length() > 0)
{
try {
i->second.dp_a = new Tango::DeviceProxy(i->second.cmd_dp_a);
i->second.dp_a->ping();
Tango::CommandInfo info = i->second.dp_a->command_query(i->second.cmd_action_a);
if(info.in_type != Tango::DEV_STRING)
{
ostringstream err;
err << "Error: command " << i->second.cmd_name_a << " does not accept a Tango::DevString as input value" << ends;
ERROR_STREAM << __func__<<": " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
else
{
if(info.in_type == Tango::DEV_STRING)
i->second.send_arg_a = true;
else
i->second.send_arg_a = false;
DEBUG_STREAM << __func__<<": successfully connected to proxy=" << i->second.cmd_dp_a << " for action=" << i->second.cmd_action_a << endl;
}
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_a << ", err=" << e.errors[0].desc << ends;
WARN_STREAM << __func__<<": " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
}
if(alm.cmd_name_n.length() > 0)
{
try {
i->second.dp_n = new Tango::DeviceProxy(i->second.cmd_dp_n);
i->second.dp_n->ping();
Tango::CommandInfo info = i->second.dp_n->command_query(i->second.cmd_action_a);
if(info.in_type != Tango::DEV_STRING)
{
ostringstream err;
err << "Error: command " << i->second.cmd_name_n << " does not accept a Tango::DevString as input value" << ends;
ERROR_STREAM << __func__<<": " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
else
{
if(info.in_type == Tango::DEV_STRING)
i->second.send_arg_n = true;
else
i->second.send_arg_n = false;
DEBUG_STREAM << __func__<<": successfully connected to proxy=" << i->second.cmd_dp_n << " for action=" << i->second.cmd_action_n << endl;
}
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << alm.name << ": error connecting to device proxy=" << i->second.cmd_dp_n << ", err=" << e.errors[0].desc << ends;
WARN_STREAM << __func__<<": " << err.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), err.str());
}
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
return;
}
}
else
{
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
ostringstream o;
o << "Alarm '"<<alm.name<<"' not found" << ends;
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Not found", \
(const char*)o.str().c_str(), \
(const char*)__func__, Tango::ERR);
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
//------------------------------
//3: remove (set active=0 on db)
//------------------------------
remove((Tango::DevString)alm.name.c_str());
//------------------------------
//4: load modified alarm
//------------------------------
load(argin);
prepare_alarm_attr();
try
{
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error pushing alarm change event err=" << e.errors[0].desc;
INFO_STREAM << __func__<<": " << err.str() << endl;
}
/*----- PROTECTED REGION END -----*/ // Alarm::modify
}
//--------------------------------------------------------
/**
* Method : Alarm::add_dynamic_commands()
* Description : Create the dynamic commands if any
* for specified device.
*/
//--------------------------------------------------------
void Alarm::add_dynamic_commands()
{
/*----- PROTECTED REGION ID(Alarm::add_dynamic_commands) ENABLED START -----*/
// Add your own code to create and add dynamic commands if any
/*----- PROTECTED REGION END -----*/ // Alarm::add_dynamic_commands
}
/*----- PROTECTED REGION ID(Alarm::namespace_ending) ENABLED START -----*/
// Additional Methods
/*
* private methods
*/
void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
{
DEBUG_STREAM << "Alarm::load_alarm(): Creating Spirit Parser..." << endl;
alarm_parse al_gr(alm); // Construct Spirit grammar
alm.name.clear();
alm.formula.clear();
alm.msg.clear();
alm.lev.clear();
alm.grp=0;
alm.to_be_evaluated = false;
alm.time_threshold = 0;
alm.silent_time = -1;
alm.silenced = -1;
alm.cmd_name_a.clear();
alm.cmd_dp_a.clear();
alm.cmd_action_a.clear();
alm.send_arg_a = false;
alm.dp_a = NULL;
alm.cmd_name_n.clear();
alm.cmd_dp_n.clear();
alm.cmd_action_n.clear();
alm.send_arg_n = false;
alm.dp_n = NULL;
evn.clear();
#ifndef _ACCESS_NODE_D
alm.formula_tree = ast_parse(alarm_string.c_str(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces
#else
alm.formula_tree =
//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p); //parse string s with grammar al_gr, skipping white spaces
#endif
if (alm.formula_tree.full)
{
std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower); //transform to lowercase
//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower); //transform to lowercase: incorrect, state has to be written uppercase
std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower); //transform to lowercase
if(alm.cmd_name_a.length() > 0)
{
const char *c = alm.cmd_name_a.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_a.push_back(*c);
else if (*c != '/')
alm.cmd_action_a.push_back(*c);
c++;
}
}
if(alm.cmd_name_n.length() > 0)
{
const char *c = alm.cmd_name_n.c_str();
int j = 0;
while (*c) {
if (*c == '/')
j++;
if (j < 3)
alm.cmd_dp_n.push_back(*c);
else if (*c != '/')
alm.cmd_action_n.push_back(*c);
c++;
}
}
alm.silenced = (alm.silent_time > 0) ? 0 : -1; //0: can be silenced, -1: cannot be silenced
DEBUG_STREAM << "Parsing succeeded! ->" << alm.name << endl;
find_event_formula(alm.formula_tree,evn); //populate event list found in this formula
ostringstream dbg_msg;
dbg_msg << "In " << alm.name << " Event =";
for (vector<string>::iterator i = evn.begin(); i != evn.end(); i++)
dbg_msg << *i << ", ";
dbg_msg << ends;
DEBUG_STREAM << dbg_msg.str() << endl;
}
else
{
ostringstream o;
#ifndef _ACCESS_NODE_D
o << "Alarm::load_alarm(): Parsing Failed, syntax error stopped at " << alm.formula_tree.stop << ends;
#else
o << "Alarm::load_alarm(): Parsing Failed, syntax error stopped at " << string(alm.formula_tree.stop, alarm_string.end()) << ends; //TODO
#endif
DEBUG_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)"Parsing Failed!", \
(const char*)o.str().c_str(), \
(const char*)"Alarm::load()", Tango::ERR);
}
alm.ts = gettime();
DEBUG_STREAM << "Alarm::load_alarm(): name = '" << alm.name << "'" << endl;
DEBUG_STREAM << " formula = '" << alm.formula << "'" << endl;
DEBUG_STREAM << " time_threshold = '" << alm.time_threshold << "'" << endl;
DEBUG_STREAM << " msg = '" << alm.msg << "'" << endl;
DEBUG_STREAM << " grp = '" << showbase << hex << alm.grp << "'=" << alm.grp2str() << endl;
DEBUG_STREAM << " silent_time = '" << alm.silent_time << "'" << endl;
DEBUG_STREAM << " silenced = '" << alm.silenced << "'" << endl;
DEBUG_STREAM << " lev = '" << alm.lev << "'" << endl;
DEBUG_STREAM << " action_a = '" << alm.cmd_name_a << "'" << endl;
DEBUG_STREAM << " action_n = '" << alm.cmd_name_n << "'" << endl;
if ((alm.name.empty() == false) && \
(alm.formula.empty() == false) && \
((alm.lev==LEV_LOG)||(alm.lev==LEV_WARNING)|| \
(alm.lev==LEV_FAULT)||(alm.lev.empty() == true))) {
alm.stat = S_NORMAL;
alm.ack = ACK;
alm.done = false;
// alm.grp = GR_DEFAULT;
// alm.lev = LEV_DEFAULT;
} else {
ostringstream o;
o << "Alarm::load_alarm(): syntax error in '" << alarm_string << "'" << ends;
WARN_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)o.str().c_str(), \
(const char*)"", \
(const char*)"Alarm::load_alarm()", Tango::ERR);
}
if (alarms.exist(alm.name)) {
ostringstream o;
o << "Alarm::load_alarm(): alarm '" << alm.name << "' already exist" << ends;
WARN_STREAM << o.str() << endl;
Tango::Except::throw_exception( \
(const char*)o.str().c_str(), \
(const char*)o.str().c_str(), \
(const char*)"Alarm::load_alarm()", Tango::ERR);
}
}
void Alarm::init_alarms(map< string,vector<string> > &alarm_events)
{
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
if (alarms.v_alarm.empty() == false)
{
for (alarm_container_t::iterator i = alarms.v_alarm.begin(); \
i != alarms.v_alarm.end(); i++)
{
map< string,vector<string> >::iterator f = //looking in map for alarm name as key
// find(alarm_events->begin(), alarm_events->end(), i->name);
alarm_events.find(i->second.name);
if(f == alarm_events.end())
continue; //ERROR: alarm not found in alarm_event map
DEBUG_STREAM << "Alarm::init_alarms(): found Alarm= " << i->second.name << endl;
for(vector<string>::iterator j = f->second.begin(); \
j != f->second.end(); j++)
{
vector<event>::iterator found = \
find(events->v_event.begin(), events->v_event.end(), (*j));
DEBUG_STREAM << "Alarm::init_alarms(): looking in events table for Event= " << (*j) << endl;
if (found != events->v_event.end())
{
i->second.insert(found->name);
found->push_alarm(i->second.name);
DEBUG_STREAM << "Alarm::init_alarms(): found Event= " << found->name << " <- Alarm= " << i->second.name << endl;
//break; ???
} /* if */
} /* for */
}
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
}
void Alarm::init_events(vector<string> &evn)
{
if (evn.empty() == false) {
sort(evn.begin(), evn.end());
vector<string>::iterator new_end = \
unique(evn.begin(), evn.end());
while (evn.end() != new_end) {
evn.pop_back();
}
vector<string>::iterator j = evn.begin();
while (j != evn.end()) {
events->push_back(event(*j));
j++;
}
} /* if */
}
void Alarm::add_alarm(alarm_t& a) throw(string&)
{
alarms.push_back(a);
DEBUG_STREAM << "Alarm::add_alarm(): added alarm '" \
<< a.name << "'" << endl;
}
void Alarm::add_event(alarm_t& a, vector<string> &evn) throw(string&)
{
DEBUG_STREAM << "Alarm::add_event(): formula '" << a.formula << "'" << endl;
/*
* get the list of all the events in the formula
*/
for (vector<string>::iterator j = evn.begin(); j != evn.end(); j++) {
vector<event>::iterator k = \
find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end()) {
/*
* the event already exist; push alarm name
* into the per-event alarm list
*/
k->push_alarm(a.name);
a.to_be_evaluated = true;
DEBUG_STREAM << "Alarm::add_event(): '" << *j << "' found, added " \
<< " alarm '" << a.name << "' to list, valid=" << k->valid << endl;
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
alarm_container_t::iterator l = alarms.v_alarm.find(a.name);
if (l != alarms.v_alarm.end())
{
l->second.insert(*j); //insert event name in set<string> (s_event) in alarm_t
}
else
{
WARN_STREAM << "Alarm::add_event(): error inserting event '" << *j << "' in set of alarm '"
<< a.name << "'" << endl;
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
}
else
{
/*
* new event; add to event table
*/
event e(*j);
events->push_back(e);
/*
* update per-alarm event list
*/
DEBUG_STREAM << "Alarm::add_event(): adding '" << *j \
<< "' to event list of alarm '" << a.name << "'" << endl;
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
alarm_container_t::iterator l = alarms.v_alarm.find(a.name);
if (l != alarms.v_alarm.end())
{
l->second.insert(*j); //insert event name in set<string> in alarm_t
}
else
{
WARN_STREAM << "Alarm::add_event(): error inserting event '" << *j << "' in set of alarm '"
<< a.name << "'" << endl;
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
/*
* now, for the just-added event, subscribe
*/
k = find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end())
{
k->push_alarm(a.name);
try {
k->dp = new Tango::DeviceProxy(k->device);
} catch(Tango::DevFailed& e)
{
TangoSys_MemStream out_stream;
out_stream << "Failed to connect device proxy=" << k->device << ends;
k->pop_alarm(a.name); //remove alarm/formula just added to event
//events->v_event.pop_back();
events->v_event.erase(k); //remove event just added to event_table
throw out_stream.str();
/*Tango::Except::re_throw_exception(e,
(const char *) "Error writing serial",
out_stream.str(),
(const char *) "Alarm::add_event()", Tango::ERR);*/
}
DEBUG_STREAM << "Alarm::add_event(): connected to DeviceProxy: " \
<< k->device << endl;
//now initialize value of this attribute
try {
Tango::DeviceAttribute attr_value;
attr_value = k->dp->read_attribute(k->attribute);
ecb.extract_values(&attr_value, k->value, k->type);
k->valid = true;
ostringstream msg;
msg << "Alarm::add_event(): initial values of " << k->name << " = ";
for(vector<double>::iterator dd=k->value.begin(); dd!=k->value.end(); dd++)
msg << (*dd) << " ";
msg << ", valid=" << k->valid << ends;
DEBUG_STREAM << msg.str() << endl;
//delete attr_value;
} catch(Tango::DevFailed& e)
{
TangoSys_MemStream out_stream;
out_stream << "Failed to read initial value of " << k->name << " = " << e.errors[0].desc << ends;
k->valid = false;
#if TANGO_VER < 611 //if using subscribe stateless, alarm is not removed if it fails the subscription
k->pop_alarm(a.name); //remove alarm/formula just added to event
//events->v_event.pop_back();
events->v_event.erase(k); //remove event just added to event_table
//delete attr_value;
#endif
throw out_stream.str();
} catch(string & e)
{
TangoSys_MemStream out_stream;
out_stream << "Error reading initial value of " << k->name << " = " << e << ends;
k->pop_alarm(a.name); //remove alarm/formula just added to event
//events->v_event.pop_back();
events->v_event.erase(k); //remove event just added to event_table
//delete attr_value;
throw out_stream.str();
}
}
}
} //for (vector<string>::iterator j = evn.begin(); ...
}
void Alarm::subscribe_event(alarm_t& a, EventCallBack& ecb, vector<string> &evn) throw(string&)
{
//now subscribe all events
for (vector<string>::iterator j = evn.begin(); j != evn.end(); j++)
{
vector<event>::iterator k = \
find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end())
{
if(k->eid == 0) //not subscribed yet
{
try {
#if TANGO_VER < 611
k->eid = k->dp->subscribe_event(k->attribute, \
Tango::CHANGE_EVENT, \
&ecb, k->filter);
#else
k->eid = k->dp->subscribe_event(k->attribute, \
Tango::CHANGE_EVENT, \
&ecb, k->filter,true); //stateless subscription (doesn't fail if server not running)
#endif
DEBUG_STREAM << "Alarm::add_event(): subscribed event for '" \
<< k->attribute << "' attribute" << endl;
} catch (...) {
ostringstream o;
o << "Alarm::add_event(): subscribe_event() failed for '" \
<< *j << "'" << ends;
WARN_STREAM << o.str() << endl;
k->pop_alarm(a.name); //remove alarm/formula just added to event
//events->v_event.pop_back();
events->v_event.erase(k); //remove event just added to event_table
delete k->dp;
k->dp = NULL;
throw o.str();
}
}
} // if (k != events->v_event.end())/
} // for
}
/*
* because called asynchronously by alarm evaluating thread
* will use an alarm to report errors
*/
void Alarm::do_alarm(bei_t& e)
{
bool changed=true;
//if (e.name == INTERNAL_ERROR) {
if(e.type == TYPE_TANGO_ERR) {
ostringstream o;
o << e.msg << endl;
WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
vector<event>::iterator found_ev = \
find(events->v_event.begin(), events->v_event.end(), e.ev_name);
if (found_ev == events->v_event.end())
{
//try to remove network domain and FQDN
string ev_name_str(e.ev_name);
string::size_type pos_slash = ev_name_str.find("tango://");
if (pos_slash != string::npos) //FQDN!!
{
//first remove network domain if any
string::size_type pos_dot = ev_name_str.find(".",8); //look for first . after tango://
string::size_type pos_colon = ev_name_str.find(":",8); //look for first : after tango://
pos_slash = ev_name_str.find('/',8); //look for first / after tango://
if(pos_dot < pos_slash && pos_dot != string::npos && pos_colon != string::npos && pos_slash != string::npos) //dot is in the TANGO_HOST part
{
string ev_name_str_no_domain = ev_name_str.substr(0,pos_dot) + ev_name_str.substr(pos_colon);
DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without domain: " << ev_name_str_no_domain;
found_ev = \
find(events->v_event.begin(), events->v_event.end(), ev_name_str_no_domain);
}
if (found_ev == events->v_event.end() && pos_slash != string::npos)
{
ev_name_str = ev_name_str.substr(pos_slash + 1);//remove FQDN
DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without fqdn: " << ev_name_str;
found_ev = \
find(events->v_event.begin(), events->v_event.end(), ev_name_str);
}
}
if (found_ev == events->v_event.end())
{
/*
* shouldn't happen!!!
*/
ostringstream o;
o << "TANGO Error but event '" \
<< e.ev_name << "' not found in event table!" << ends;
WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
set_internal_alarm(e.ev_name, gettime(), o.str());
}
}
if(found_ev != events->v_event.end())
{
found_ev->err_counter++;
if(found_ev->err_counter >= errThreshold)
set_internal_alarm(e.ev_name, gettime(), o.str(), errThreshold);
}
return;
}
else if(e.type == TYPE_GENERIC_ERR) {
ostringstream o;
o << e.msg << endl;
WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
set_internal_alarm(e.ev_name, gettime(), o.str());
return;
}
DEBUG_STREAM << "Alarm::do_alarm(): arrived event=" << e.ev_name << endl;
double res;
vector<event>::iterator found = \
find(events->v_event.begin(), events->v_event.end(), e.ev_name);
if (found == events->v_event.end())
{
//try to remove network domain and FQDN
string ev_name_str(e.ev_name);
string::size_type pos_slash = ev_name_str.find("tango://");
if (pos_slash != string::npos) //FQDN!!
{
//first remove network domain if any
string::size_type pos_dot = ev_name_str.find(".",8); //look for first . after tango://
string::size_type pos_colon = ev_name_str.find(":",8); //look for first : after tango://
pos_slash = ev_name_str.find('/',8); //look for first / after tango://
if(pos_dot < pos_slash && pos_dot != string::npos && pos_colon != string::npos && pos_slash != string::npos) //dot is in the TANGO_HOST part
{
string ev_name_str_no_domain = ev_name_str.substr(0,pos_dot) + ev_name_str.substr(pos_colon);
DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without domain: " << ev_name_str_no_domain;
found = \
find(events->v_event.begin(), events->v_event.end(), ev_name_str_no_domain);
}
if (found == events->v_event.end() && pos_slash != string::npos)
{
ev_name_str = ev_name_str.substr(pos_slash + 1);//remove FQDN
DEBUG_STREAM << __FUNCTION__ << " event "<< e.ev_name << " not found, trying without fqdn: " << ev_name_str;
found = \
find(events->v_event.begin(), events->v_event.end(), ev_name_str);
}
}
if (found == events->v_event.end())
{
/*
* shouldn't happen!!!
*/
ostringstream o;
o << "event '" \
<< e.ev_name << "' not found in event table!" << ends;
WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
}
}
if (found != events->v_event.end())
{
found->value = e.value;
found->valid = true;
found->ts = e.ts;
found->type = e.type;
found->err_counter = 0;
vector<string>::iterator j = found->m_alarm.begin();
while (j != found->m_alarm.end())
{
//alarm_container_t::iterator it = alarms.v_alarm.find(j->first);
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
alarm_container_t::iterator it = alarms.v_alarm.find(*j);
if(it != alarms.v_alarm.end())
{
string tmpname=it->first;
try {
string attr_values;
res = eval_formula(it->second.formula_tree, attr_values);
DEBUG_STREAM << "Alarm::do_alarm(): Evaluation of " << it->second.formula << "; result=" << res << endl;
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
changed = alarms.update(tmpname, found->ts, (int)res, attr_values, it->second.grp2str(), it->second.msg, it->second.formula); //update internal structure and log to db
} catch(std::out_of_range& e)
{
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
ostringstream o;
o << tmpname << ": in formula array index out of range!" << ends;
WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
} catch(string & e)
{
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
ostringstream o;
o << tmpname << ": in formula err=" << e << ends;
WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
}
}
else
{
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
ostringstream o;
//o << j->first << ": not found formula in alarm table" << ends;
o << (*j) << ": not found formula in alarm table" << ends;
WARN_STREAM << "Alarm::do_alarm(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
}
j++;
}
//TODO: push_change_event HERE!
prepare_alarm_attr();
if(!changed)
return;
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
}
} /* do_alarm() */
void Alarm::timer_update()
{
bool changed=true;
//DEBUG_STREAM << "Alarm::timer_update(): entering..." << endl;
try {
changed=alarms.timer_update();
} catch(string & e)
{
ostringstream o;
o << "Error checking time thresholds and updating alarm status=" << e << ends;
WARN_STREAM << "Alarm::timer_update(): " << o.str() << endl;
set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
}
prepare_alarm_attr();
if(!changed)
return;
try
{
if(ds_num == 0)
{
//attr.set_value_date_quality(ds,0/*gettime()*/,Tango::ATTR_WARNING, ds_num, 0, false);
struct timeval now;
gettimeofday(&now,NULL);
push_change_event("alarm",(char**)ds,now,Tango::ATTR_WARNING, ds_num, 0, false);
}
else
//attr.set_value(ds, ds_num, 0, false);
push_change_event("alarm",ds, ds_num, 0, false);
} catch(Tango::DevFailed& e)
{
ostringstream err;
err << "error pushing alarm change event err=" << e.errors[0].desc;
INFO_STREAM << __func__<<": " << err.str() << endl;
}
}
bool Alarm::remove_alarm(string& s) throw(string&)
{
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->writerIn();
#endif
alarm_container_t::iterator i = alarms.v_alarm.find(s);
if (i != alarms.v_alarm.end()) {
for (set<string>::iterator j = i->second.s_event.begin(); \
j != i->second.s_event.end(); j++) {
/*
* for each event into the per-alarm event list find
* the event table entry and remove this alarm from
* per-event alarm list
*/
vector<event>::iterator k = \
find(events->v_event.begin(), events->v_event.end(), *j);
if (k != events->v_event.end()) {
/*
* remove alarm
*/
k->pop_alarm(i->second.name);
if (k->m_alarm.empty()) {
/*
* no more alarms associated to this event, unsubscribe
* and remove from event table
*/
DEBUG_STREAM << "Alarm::remove_alarm(): removing event '" \
<< k->name << "' from event table" << endl;
try {
k->dp->unsubscribe_event(k->eid);
} catch (...) {
ostringstream o;
o << "unsubscribe_event() failed for " \
<< k->name << ends;
WARN_STREAM << "Alarm::remove_alarm(): " << o.str() << endl;
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
throw o.str();
//return false;
}
delete k->dp;
k->dp = NULL;
events->v_event.erase(k);
}
} else {
/*
* shouldn't happen!!!
*/
ostringstream o;
o << "event '" << *j \
<< "' not found in event table" << ends;
WARN_STREAM << "Alarm::remove_alarm(): " << o.str() << endl;
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
throw o.str();
//return false;
}
} /* for */
//delete proxy for actions
if(i->second.dp_a)
delete i->second.dp_a;
i->second.dp_a = NULL;
if(i->second.dp_n)
delete i->second.dp_n;
i->second.dp_n = NULL;
/*
* remove this alarm from alarm table
*/
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
alarms.erase(i);
return true;
}
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->writerOut();
#endif
ostringstream o;
o << "alarm '" \
<< s << "' not found in alarm table" << ends;
WARN_STREAM << "Alarm::remove_alarm(): " << o.str() << endl;
throw o.str();
//return false;
} /* remove_alarm() */
/*void Alarm::add_to_database(alarm_t& a) throw(string&)
{
Tango::DbDatum alarm("alarm");
Tango::DbData db_data;
alarm << (short)1;
db_data.push_back(alarm);
string tmpname;
tmpname = a.name;
while (true) {
string::size_type j = tmpname.find_first_of("/.");
if (j == string::npos)
break;
tmpname.replace(j, 1, "_");
}
Tango::DbDatum property(tmpname);
ostringstream num;
num.clear();
num << a.grp << ends;
// sprintf(buf, "%02X-", buf2[j]);//change here the format of saved data
// string pro = a.name+"\t"+"$"+a.formula+"$"+"\t"+"\""+a.msg+"\""+"\t"+num.str();
//DEBUG_STREAM << "Alarm::add_to_database(): a.name=" << a.name << " a.formula=" << a.formula << " a.lev=" << a.lev << " a.grp=" << a.grp2str() << " a.msg=" << a.msg << endl;
string pro = a.name+"\t"+a.formula+"\t"+string(a.time_threshold)+"\t"+ a.lev+"\t"+a.grp2str()+"\t"+"\""+a.msg+"\""+"\t"+a.cmd_name+"\t"; //grp has been transformed to string
DEBUG_STREAM << "Alarm::add_to_database(): adding to database property=" << pro << endl;
property << pro;
db_data.push_back(property);
try {
get_db_device()->put_attribute_property(db_data);
} catch (...) {
ostringstream o;
o << "Alarm::add_to_database(): put_device_attribute_property()" \
<< " failed" << ends;
ERROR_STREAM << o.str() << endl;
throw o.str();
}
}*/
void Alarm::set_internal_alarm(string name, Tango::TimeVal t, string msg, unsigned int count)
{
alarm_t alm;
bool existing=false;
ostringstream o;
//o << (internal.size() + 1);
if(internal.size() == 0)
internal_counter = 0;
o << internal_counter;
internallock->writerIn();
vector<alarm_t>::iterator it;
for(it = internal.begin(); it != internal.end(); it++)
{
if(name == INTERNAL_ERROR)
{
if(it->msg == msg)
{
existing=true;
break;
}
}
else //for tango error log only one internal error per event
{
if(it->msg.find(name) != string::npos)
{
existing=true;
if(it->counter < count)
it->counter = count;
break;
}
}
}
if(existing)
{
/*size_t index;
int count;
index = it->stat.find("*");
ostringstream temp;
if((index != std::string::npos) && (index+1 != std::string::npos))
{
size_t last = it->stat.size();
string str_count= it->stat.substr(index+1, last - index+1);
count = strtol(str_count.c_str(), 0,10);
count++;
temp << it->stat.substr(0,index+1) << count;
it->stat = temp.str();
}
else
it->stat += "*2";*/
it->counter++;
it->msg = msg; //update with the last message
}
else
{
alm.name = string(INTERNAL_ERROR) + "_" + o.str();
internal_counter++;
alm.ts = t;
/*ostringstream stat;
if(count==0)
stat << S_ALARM;
else
stat << S_ALARM << "*" << count;*/
alm.counter = count;
//alm.stat = stat.str();
alm.stat = S_ALARM;
alm.ack = NOT_ACK;
alm.done = false;
alm.msg = msg;
//alm.grp = GR_DEFAULT;
if(!alm.grp_str.empty())
alm.grp = (alm.grp_str.begin())->second; //set groupe 'none' to internal alarms
else
alm.grp = GR_DEFAULT;
//alm.lev = LEV_DEFAULT;
alm.lev = LEV_LOG;
internal.push_back(alm);
}
internallock->writerOut();
}
//==============================================================
//------------------- AST evaluation methods -------------------
//==============================================================
double Alarm::eval_formula(tree_parse_info_t tree, string &attr_values)
{
return eval_expression(tree.trees.begin(), attr_values);
}
double Alarm::eval_expression(iter_t const& i, string &attr_values, int ev_ind) //throw (string &), std::out_of_range
{
ostringstream err;
err << "Evaluating formula: ";
//iter_t it = i->children.begin();
if (i->value.id() == formula_grammar::val_rID)
{
if(i->children.size() != 0)
{
err << "in node val_rID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
string val_d(i->value.begin(), i->value.end());
DEBUG_STREAM << " node value real = " << val_d << endl;
return strtod(val_d.c_str(), 0);
}
else if (i->value.id() == formula_grammar::val_hID)
{
if(i->children.size() != 0)
{
err << "in node val_hID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
string val_d(i->value.begin(), i->value.end());
DEBUG_STREAM << " node value hex = " << val_d << endl;
return strtod(val_d.c_str(), 0);
}
else if (i->value.id() == formula_grammar::val_stID)
{
if(i->children.size() != 0)
{
err << "in node val_stID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
string val_st(i->value.begin(), i->value.end());
#ifndef _ACCESS_NODE_D
Tango::DevState st;
if(val_st == "ON")
st = Tango::ON;
else if(val_st == "OFF")
st = Tango::OFF;
else if(val_st == "CLOSE")
st = Tango::CLOSE;
else if(val_st == "OPEN")
st = Tango::OPEN;
else if(val_st == "INSERT")
st = Tango::INSERT;
else if(val_st == "EXTRACT")
st = Tango::EXTRACT;
else if(val_st == "MOVING")
st = Tango::MOVING;
else if(val_st == "STANDBY")
st = Tango::STANDBY;
else if(val_st == "FAULT")
st = Tango::FAULT;
else if(val_st == "INIT")
st = Tango::INIT;
else if(val_st == "RUNNING")
st = Tango::RUNNING;
else if(val_st == "ALARM")
st = Tango::ALARM;
else if(val_st == "DISABLE")
st = Tango::DISABLE;
else if(val_st == "UNKNOWN")
st = Tango::UNKNOWN;
#else
double st = i->value.value(); //get value directly from node saved with access_node_d
#endif //_ACCESS_NODE_D
DEBUG_STREAM << " node value state : " << val_st << "=" << st << endl;
return st;
}
else if (i->value.id() == formula_grammar::unary_exprID)
{
DEBUG_STREAM << " node unary expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 1)
{
err << "in node unary_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
if (*i->value.begin() == '+')
return + eval_expression(i->children.begin(), attr_values);
if (*i->value.begin() == '-')
return - eval_expression(i->children.begin(), attr_values);
if (*i->value.begin() == '!')
return ! eval_expression(i->children.begin(), attr_values);
}
else if (i->value.id() == formula_grammar::mult_exprID)
{
DEBUG_STREAM << " node mult expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 2)
{
err << "in node mult_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
if (*i->value.begin() == '*')
{
return eval_expression(i->children.begin(), attr_values) *
eval_expression(i->children.begin()+1, attr_values);
}
else if (*i->value.begin() == '/')
{
return eval_expression(i->children.begin(), attr_values) /
eval_expression(i->children.begin()+1, attr_values);
}
else
{
err << "in node mult_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::add_exprID)
{
DEBUG_STREAM << " node add expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 2)
{
err << "in node add_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
if (*i->value.begin() == '+')
{
return eval_expression(i->children.begin(), attr_values) +
eval_expression(i->children.begin()+1, attr_values);
}
else if (*i->value.begin() == '-')
{
return eval_expression(i->children.begin(), attr_values) -
eval_expression(i->children.begin()+1, attr_values);
}
else
{
err << "in node add_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::event_ID)
{
DEBUG_STREAM << " node event" << string(i->value.begin(), i->value.end()) << endl;
int ind;
if(i->children.size() != 2)
{
err << "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;;
throw err.str();
}
if((i->children.begin()+1)->value.id() == formula_grammar::indexID)
ind = (int)eval_expression(i->children.begin()+1, attr_values); //array index
else
{
err << "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children2 is not an index ->" << string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) << ends;;
throw err.str();
}
return eval_expression(i->children.begin(), attr_values ,ind);
}
else if (i->value.id() == formula_grammar::nameID)
{
if(i->children.size() != 0)
{
err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
vector<event>::iterator it = events->v_event.begin();
string s(i->value.begin(), i->value.end());
std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase
while ((it != events->v_event.end()) && (it->name != s))
it++;
if (it != events->v_event.end())
{
if(!it->valid)
{
err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") value not valid!" << ends;
throw err.str();
}
else if(it->value.empty())
{
err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") value not initialized!!" << ends;
throw err.str();
}
ostringstream temp_attr_val;
temp_attr_val << it->name << "[" << ev_ind << "]=" <<it->value.at(ev_ind) << ";";
attr_values += temp_attr_val.str();
DEBUG_STREAM << " node name -> " << temp_attr_val.str() << endl;
return it->value.at(ev_ind); //throw std::out_of_range
}
else
{
err << "in event: (" << string(i->value.begin(), i->value.end()) << ") not found in event table" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::indexID)
{
if(i->children.size() != 0)
{
err << "in node indexID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
string val_d(i->value.begin(), i->value.end());
DEBUG_STREAM << " node index = " << val_d << endl;
return strtod(val_d.c_str(), 0);
}
else if (i->value.id() == formula_grammar::logical_exprID)
{
DEBUG_STREAM << " node logical expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 2)
{
err << "in node logical_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
if (string(i->value.begin(), i->value.end()) == string("&&"))
{
return eval_expression(i->children.begin(), attr_values) &&
eval_expression(i->children.begin()+1, attr_values);
}
else if (string(i->value.begin(), i->value.end()) == string("||"))
{
return eval_expression(i->children.begin(), attr_values) ||
eval_expression(i->children.begin()+1, attr_values);
}
else
{
err << "in node logical_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::bitwise_exprID)
{
DEBUG_STREAM << " node bitwise expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 2)
{
err << "in node bitwise_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
double val_d1=eval_expression(i->children.begin(), attr_values),
val_d2=eval_expression(i->children.begin()+1, attr_values);
long val_l1,val_l2;
string err2("ERROR: non-int value in bitwise operation!");
val_l1 = (long)trunc(val_d1); //transform to long
val_l2 = (long)trunc(val_d2); //transform to long
if((val_l1 != val_d1) || (val_l2 != val_d2)) //if different, lost something with truncf
throw err2;
if (*i->value.begin() == '&')
{
return (double)(val_l1 & val_l2);
}
else if (*i->value.begin() == '|')
{
return (double)(val_l1 | val_l2);
}
else if (*i->value.begin() == '^')
{
return (double)(val_l1 ^ val_l2);
}
else
{
err << "in node bitwise_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::shift_exprID)
{
DEBUG_STREAM << " node shift expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 2)
{
err << "in node shift_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
double val_d1=eval_expression(i->children.begin(), attr_values),
val_d2=eval_expression(i->children.begin()+1, attr_values);
long val_l1,val_l2;
string err2("ERROR: non-int value in bitwise operation!");
val_l1 = (long)trunc(val_d1); //transform to long
val_l2 = (long)trunc(val_d2); //transform to long
if((val_l1 != val_d1) || (val_l2 != val_d2)) //if different, lost something with truncf
throw err2;
if (string(i->value.begin(), i->value.end()) == string("<<"))
{
return (double)(val_l1 << val_l2);
}
else if (string(i->value.begin(), i->value.end()) == string(">>"))
{
return (double)(val_l1 >> val_l2);
}
else
{
err << "in node shift_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::equality_exprID)
{
DEBUG_STREAM << " node equality expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 2)
{
err << "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
if (string(i->value.begin(), i->value.end()) == string("!="))
{
return eval_expression(i->children.begin(), attr_values) !=
eval_expression(i->children.begin()+1, attr_values);
}
else if (string(i->value.begin(), i->value.end()) == string("=="))
{
return eval_expression(i->children.begin(), attr_values) ==
eval_expression(i->children.begin()+1, attr_values);
}
else
{
err << "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::compare_exprID)
{
DEBUG_STREAM << " node compare expression: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 2)
{
err << "in node compare_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
if (string(i->value.begin(), i->value.end()) == string("<="))
{
return eval_expression(i->children.begin(), attr_values) <=
eval_expression(i->children.begin()+1, attr_values);
}
else if (string(i->value.begin(), i->value.end()) == string(">="))
{
return eval_expression(i->children.begin(), attr_values) >=
eval_expression(i->children.begin()+1, attr_values);
}
else if (*i->value.begin() == '<')
{
return eval_expression(i->children.begin(), attr_values) <
eval_expression(i->children.begin()+1, attr_values);
}
else if (*i->value.begin() == '>')
{
return eval_expression(i->children.begin(), attr_values) >
eval_expression(i->children.begin()+1, attr_values);
}
else
{
err << "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
throw err.str();
}
}
else if (i->value.id() == formula_grammar::funcID)
{
DEBUG_STREAM << " node function: " << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 1)
{
err << "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
return fabs(eval_expression(i->children.begin(), attr_values)); //now handled only abs as function
}
else
{
DEBUG_STREAM << " node unknown id: " << string(i->value.begin(), i->value.end()) << endl;
{
err << "node unknown!! value=" << string(i->value.begin(), i->value.end()) << ends;
throw err.str();
}
}
return 0;
}
void Alarm::find_event_formula(tree_parse_info_t tree, vector<string> & ev)
{
eval_node_event(tree.trees.begin(), ev);
return;
}
void Alarm::eval_node_event(iter_t const& i, vector<string> & ev)
{
/* DEBUG_STREAM << "In eval_node_event. i->value = " <<
string(i->value.begin(), i->value.end()) <<
" i->children.size() = " << i->children.size() << " NODE=" << rule_names[i->value.id()] << endl;*/
ostringstream err;
err << "Looking for event in formula tree: ";
/*if (i->value.id() == formula_grammar::event_ID)
{
DEBUG_STREAM << "eval_node_event(): in eventID!!!=" << string(i->value.begin(), i->value.end()) << endl;
}
else*/ if (i->value.id() == formula_grammar::nameID)
{
DEBUG_STREAM << "eval_node_event(): find event name=" << string(i->value.begin(), i->value.end()) << endl;
if(i->children.size() != 0)
{
err << "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
throw err.str();
}
string s(i->value.begin(), i->value.end());
std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower); //transform to lowercase
ev.push_back(s);
}
//cout << endl;
//iter_t it = i->children.begin();
for(iter_t it = i->children.begin(); it != i->children.end(); it++)
eval_node_event(it, ev);
return;
}
void Alarm::prepare_alarm_attr()
{
alarm_container_t::iterator ai;
vector<alarm_t>::iterator aid;
#ifndef _RW_LOCK
alarms.lock();
#else
alarms.vlock->readerIn();
#endif
for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) {
if (ai->second.stat == S_ALARM) {
/*
* alarm status is S_ALARM
*/
alarmedlock->readerIn();
aid = find(alarmed.begin(), alarmed.end(),ai->second.name);
if (aid != alarmed.end()) {
/*
* found, change stat only if switching from
* S_NORMAL to S_ALARM status
*/
//cout << "read_attr(): S_ALARM: found: " << aid->name << endl;
if (aid->stat == S_NORMAL) {
aid->stat = S_ALARM;
aid->ack = NOT_ACK;
aid->ts = ai->second.ts;
aid->msg = ai->second.msg;
}
aid->grp = ai->second.grp;
aid->lev = ai->second.lev;
aid->is_new = ai->second.is_new; //copy is_new state
//ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0
aid->counter = ai->second.counter;
aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset
aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary)
aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update
} else {
/*
* not found: new "alarmed" item
*/
DEBUG_STREAM << __func__<<": S_ALARM: pushing new alarm: " \
<< ai->second.name << "\t" << ai->second.stat << endl;
alarmedlock->readerOut();
alarmedlock->writerIn();
alarmed.push_back(ai->second);
//ai->second.is_new = 0; //set state as not more new //12-06-08: StopNew command set it to 0
alarmedlock->writerOut();
alarmedlock->readerIn();
}
alarmedlock->readerOut();
} else if (ai->second.stat == S_NORMAL) {
/*
* alarm status is S_NORMAL
*/
alarmedlock->readerIn();
aid = find(alarmed.begin(), alarmed.end(), ai->second.name);
if (aid != alarmed.end()) {
/*
* found, as it should;
* switching from S_ALARM to S_NORMAL
*/
aid->stat = S_NORMAL;
aid->ts = ai->second.ts;
//aid->msg = " "; /* no message again */
aid->msg =ai->second.msg;
aid->grp = ai->second.grp;
aid->lev = ai->second.lev;
aid->counter = ai->second.counter;
aid->ack = ai->second.ack; //if already acknowledged but has arrived new alarm ack is reset
aid->is_new = ai->second.is_new; //copy is_new state
aid->silenced = ai->second.silenced; //update silenced from alarm table (maybe not necessary)
aid->silent_time = ai->second.silent_time; //if already alarmed and not saved correctly in properties needed to update
//ai->second.is_new = 0; //and set state as not more new //12-06-08: StopNew command set it to 0
if (aid->ack == ACK) {
if (aid->done) {
/*
* if already ACKnowledged and visualized
* remove from "alarmed" list
*/
DEBUG_STREAM << __func__<<": S_NORMAL: " << aid->name \
<< " ACKnowledged: removing" << endl;
alarmedlock->readerOut();
alarmedlock->writerIn();
alarmed.erase(aid);
alarmedlock->writerOut();
alarmedlock->readerIn();
} else {
aid->done = true;
}
} /* if */
} /* if */
alarmedlock->readerOut();
} /* if else if */
} /* for */
#ifndef _RW_LOCK
alarms.unlock();
#else
alarms.vlock->readerOut();
#endif
vector<string> tmp_alarm_table;
string is_new;
ostringstream os1;
/*os1.clear();
os1 << header << "\t" << alarmed.size() << ends;*/
//tmp_alarm_table.push_back(os1.str());
alarmedlock->readerIn();
if (alarmed.empty() == false) {
for (aid = alarmed.begin(); aid != alarmed.end(); aid++) {
if(aid->silenced > 0)
{
Tango::TimeVal now = gettime();
double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000;
double dsilent = aid->ts_time_silenced.tv_sec + ((double)aid->ts_time_silenced.tv_usec) / 1000000;
double dminutes = (dnow - dsilent)/60;
//silenced already calculated in alarm_table::update, but here updated for panel also if state not changed:
//to see minutes countdown
if(dminutes < aid->silent_time)
aid->silenced = aid->silent_time - floor(dminutes);
else
aid->silenced = 0;
}
ostringstream os;
os.clear();
is_new.clear();
is_new = (aid->is_new && aid->silenced <= 0) ? "NEW" : " ";
os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \
<< aid->name << "\t" << aid->stat << "\t" << aid->ack \
<< "\t" << aid->counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new << ends;
tmp_alarm_table.push_back(os.str());
}
}
alarmedlock->readerOut();
internallock->readerIn();
if (internal.empty() == false) {
for (aid = internal.begin(); aid != internal.end(); aid++) {
/* size_t index;
int count = 1;
index = aid->stat.find("*");
if((index != std::string::npos) && (index+1 != std::string::npos))
{
size_t last = aid->stat.size();
string str_count= aid->stat.substr(index+1, last - index+1);
count = strtol(str_count.c_str(), 0,10);
}
//do not show internal alarms that have a molteplicity less then errThreshold
if((aid->msg.find()) && (count < errThreshold))
continue;*/
ostringstream os;
os.clear();
os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \
<< aid->name << "\t" << aid->stat << "\t" << aid->ack \
<< "\t" << aid->counter << "\t" << aid->lev << "\t"<< -1/*silenced*/ <<"\t" << aid->grp2str() << "\t" << aid->msg << "\t "<< ends; //TODO: silenced for internal errors?
tmp_alarm_table.push_back(os.str());
}
}
internallock->readerOut();
dslock->writerIn();
int i;
// for (i = ds_num - 1; i >= 0; i--) {
// CORBA::string_free(ds[i]);
// //ds_num--;
// }
/* for (i = 0; i < ds_num; i++) {
if (ds[i] != 0) {
CORBA::string_free(ds[i]);
ds[i] = 0;
}
}*/
ds_num = tmp_alarm_table.size();
if(ds_num > MAX_ALARMS)
ds_num = MAX_ALARMS;
for (i = 0; i < ds_num; i++) {
//ds[i] = CORBA::string_dup(tmp_alarm_table[i].c_str());
size_t len=tmp_alarm_table[i].length();
if(len >= 10124) len = 10124-1;
strncpy(dss[i],tmp_alarm_table[i].c_str(), len);
dss[i][len]=0;
}
if(ds_num == 0)
{
ostringstream os1;
ds_num++;
os1.clear();
os1 << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << -1 << "\t" << 0 << "\t" << 0 << "\t "<< ends;
//ds[0] = CORBA::string_dup(os1.str().c_str());
size_t len=os1.str().length();
if(len >= 10124) len = 10124-1;
strncpy(dss[i],os1.str().c_str(), len);
dss[i][len]=0;
}
dslock->writerOut();
}
/*----- PROTECTED REGION END -----*/ // Alarm::namespace_ending
} // namespace
<?xml version="1.0" encoding="ASCII"?>
<pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://www.esrf.fr/tango/pogo/PogoDsl">
<classes name="Alarm" pogoRevision="9.1">
<description description="Elettra alarm device server" title="Elettra alarm device server" sourcePath="/home/graziano/workspace/git/alarm/src" language="Cpp" filestogenerate="XMI file,Code files,Protected Regions" license="GPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false">
<inheritances classname="Device_4Impl" sourcePath=""/>
<identification contact="at elettra.eu - graziano.scalamera" author="graziano.scalamera" emailDomain="elettra.eu" classFamily="SoftwareSystem" siteSpecific="" platform="Unix Like" bus="Not Applicable" manufacturer="" reference=""/>
</description>
<deviceProperties name="AlarmStatus" description="Persistent storage of the alarms status">
<type xsi:type="pogoDsl:StringVectorType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="GroupNames" description="Labels for Group mask, first is for mask 0x00">
<type xsi:type="pogoDsl:StringVectorType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="ErrThreshold" description="Threshold for Tango error for being internal alarms">
<type xsi:type="pogoDsl:IntType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="DbHost" description="Host of the MySQL db">
<type xsi:type="pogoDsl:StringType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="DbUser" description="Username for the MySQL db">
<type xsi:type="pogoDsl:StringType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="DbPasswd" description="Password for the MySQL db">
<type xsi:type="pogoDsl:StringType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="DbName" description="Db name for the MySQL db">
<type xsi:type="pogoDsl:StringType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="DbPort" description="Port of the MySQL db">
<type xsi:type="pogoDsl:StringType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<deviceProperties name="InstanceName" description="Name used to associate configured alarm rules to this instance">
<type xsi:type="pogoDsl:StringType"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</deviceProperties>
<commands name="State" description="This command gets the device state (stored in its &lt;i>device_state&lt;/i> data member) and returns it to the caller." execMethod="dev_state" displayLevel="OPERATOR" polledPeriod="0">
<argin description="none.">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="State Code">
<type xsi:type="pogoDsl:StateType"/>
</argout>
<status abstract="true" inherited="true" concrete="true" concreteHere="false"/>
</commands>
<commands name="Status" description="This command gets the device status (stored in its &lt;i>device_status&lt;/i> data member) and returns it to the caller." execMethod="dev_status" displayLevel="OPERATOR" polledPeriod="0">
<argin description="none.">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="Status description">
<type xsi:type="pogoDsl:ConstStringType"/>
</argout>
<status abstract="true" inherited="true" concrete="true" concreteHere="false"/>
</commands>
<commands name="Ack" description="Alarm acknowledge" execMethod="ack" displayLevel="OPERATOR" polledPeriod="0">
<argin description="String array containing the alarms to be acknowledged">
<type xsi:type="pogoDsl:StringArrayType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="Load" description="Load a new alarm." execMethod="load" displayLevel="OPERATOR" polledPeriod="0">
<argin description="Alarm entry">
<type xsi:type="pogoDsl:StringType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="Remove" description="Remove alarm." execMethod="remove" displayLevel="OPERATOR" polledPeriod="0">
<argin description="Alarm name">
<type xsi:type="pogoDsl:StringType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="Configured" description="Alarms configured" execMethod="configured" displayLevel="OPERATOR" polledPeriod="0">
<argin description="String containing a filter for output, if empty return all alarms">
<type xsi:type="pogoDsl:StringType"/>
</argin>
<argout description="Alarms configured">
<type xsi:type="pogoDsl:StringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="StopNew" description="Remove &quot;NEW&quot; field from alarm string (so alarm panel stop sound)" execMethod="stop_new" displayLevel="OPERATOR" polledPeriod="0">
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="Silence" description="Alarm temporarily silence" execMethod="silence" displayLevel="OPERATOR" polledPeriod="0">
<argin description="String array containing the alarms to be silenced">
<type xsi:type="pogoDsl:StringArrayType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="Modify" description="Modify an existing alarm." execMethod="modify" displayLevel="OPERATOR" polledPeriod="0">
<argin description="Alarm entry">
<type xsi:type="pogoDsl:StringType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<attributes name="alarm" attType="Spectrum" rwType="READ" displayLevel="OPERATOR" polledPeriod="0" maxX="1024" maxY="0">
<dataType xsi:type="pogoDsl:StringType"/>
<changeEvent fire="false" libCheckCriteria="false"/>
<archiveEvent fire="false" libCheckCriteria="false"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
</attributes>
<preferences docHome="./doc_html" makefileHome="/usr/local/tango-8.1.2.c/share/pogo/preferences"/>
</classes>
</pogoDsl:PogoSystem>