Add API allowing xAPPs to send alarm messages 07/4407/3 2.0.0
authorE. Scott Daniels <daniels@research.att.com>
Wed, 15 Jul 2020 12:03:22 +0000 (08:03 -0400)
committerE. Scott Daniels <daniels@research.att.com>
Fri, 17 Jul 2020 16:00:44 +0000 (12:00 -0400)
This change adds the ability for an xAPP to send alarms to
the alarm collector/manager via RMR messages.

This is a BREAKING change because the C++ framework classes
are all now wrapped in the xapp:: namespace.

Issue-ID: RIC-426

Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: I552292d57e987313ec684bd55f8780ef5fba74fe

44 files changed:
CHANGES
CMakeLists.txt
doc/src/lib/README [new file with mode: 0644]
doc/src/lib/front_junk.im
doc/src/lib/setup.im
doc/src/master.mk [new file with mode: 0644]
doc/src/rtd/Makefile
doc/src/rtd/gen_rel_notes.sh
doc/src/rtd/rel-notes.rst
doc/src/rtd/rel-notes.xfm [deleted file]
doc/src/rtd/setup.im [deleted file]
doc/src/user/.gitignore
doc/src/user/Makefile
doc/src/user/alarm.im [new file with mode: 0644]
doc/src/user/alloc_proto.im [new file with mode: 0644]
doc/src/user/cpp_frame.im
doc/src/user/example4.im [new file with mode: 0644]
doc/src/user/jhash.im
doc/src/user/raise_proto.im [new file with mode: 0644]
doc/src/user/user_guide.xfm
docs/rel-notes.rst
docs/user-guide.rst
examples/rmr_dump.cpp
examples/xapp_t1.cpp
examples/xapp_t2.cpp
src/alarm/CMakeLists.txt [new file with mode: 0644]
src/alarm/alarm.cpp [new file with mode: 0644]
src/alarm/alarm.hpp [new file with mode: 0644]
src/json/jhash.cpp
src/json/jhash.hpp
src/messaging/callback.cpp
src/messaging/callback.hpp
src/messaging/default_cb.cpp
src/messaging/default_cb.hpp
src/messaging/message.cpp
src/messaging/message.hpp
src/messaging/messenger.cpp
src/messaging/messenger.hpp
src/messaging/msg_component.hpp
src/xapp/xapp.hpp
test/Makefile
test/jhash_test.cpp
test/rmr_em.c
test/unit_test.cpp

diff --git a/CHANGES b/CHANGES
index d7bd724..b856218 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,17 @@
 # This file contains a brief summary of each version bump.
+# Its contents are parsed by a document builder and the rel-notes.rst
+# file for the RTD site is generated. Changes must start with a date
+# and version string. Blank are used to separate items when a version
+# has several changes.  Multiple blank lines between versions are
+# squished to one.
+
+release = Cherry
+2020 July 17; version 2.0.0
+       Add alarm support.
+
+       Add xapp namespace for Message, Msg_component, Alarm and Jhah
+       objects.  This is a BREAKING change and thus the major version
+       number was bumped to 2.
 
 2020 June 29; version 1.2.0
        Add support for json parsing
@@ -9,6 +22,8 @@
        Version bump to 1.1.0 to allow patches to bronze code to
        continue to be done on the 1.0.* level.
 
+
+release= Bronze
 2020 April 28; version 1.0.0
        Bump version to force package build (old CI version added
        incorrect install prefix). Bump to 1.0.0 for release.
index fc913fa..949b158 100644 (file)
@@ -28,9 +28,9 @@
 project( ricxfcpp )
 cmake_minimum_required( VERSION 3.5 )
 
-set( major_version "1" )               # should be automatically populated from git tag later, but until CI process sets a tag we use this
-set( minor_version "2" )
-set( patch_level "1" )
+set( major_version "2" )               # should be automatically populated from git tag later, but until CI process sets a tag we use this
+set( minor_version "0" )
+set( patch_level "0" )
 
 set( install_root "${CMAKE_INSTALL_PREFIX}" )
 set( install_inc "include/ricxfcpp" )
@@ -149,17 +149,21 @@ endif()
 
 
 
+# bleeding cmake names are short novels; and when lines cannot be split they're a pain
+set ( srcd "${CMAKE_CURRENT_SOURCE_DIR}" )
+
 # this gets us round a chicken/egg problem. include files don't exist until make is run
 # but Cmake insists on having these exist when we add them to include directories to
 # enable code to find them after we build them.
 #
-include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/src/messaging;${CMAKE_CURRENT_SOURCE_DIR}/src/json;${CMAKE_CURRENT_SOURCE_DIR}/ext/jsmn" )
+include_directories( "${srcd}/src/messaging;${srcd}/src/json;${srcd}/src/alarm;${srcd}/ext/jsmn" )
 
 # Compiler flags
 #
 set( CMAKE_POSITION_INDEPENDENT_CODE ON )
 set( CMAKE_C_FLAGS "-g " )
 set( CMAKE_CPP_FLAGS "-g " )
+set( CMAKE_CXX_FLAGS "-g " )
 if( GPROF )                                    # if set, we'll set profiling flag on compiles
        message( "+++ profiling is on" )
        set( CMAKE_C_FLAGS "-pg " )
@@ -181,12 +185,13 @@ execute_process( COMMAND  git submodule update --init -- ext/jsmn
 add_subdirectory( src/json )
 add_subdirectory( src/messaging )
 add_subdirectory( src/xapp )
+add_subdirectory( src/alarm )
 #add_subdirectory( doc )                               # this will auto skip if {X}fm is not available
 
 # shared and static libraries are built from the same object files.
 #
 add_library( ricxfcpp_shared SHARED
-       "$<TARGET_OBJECTS:message_objects>;$<TARGET_OBJECTS:json_objects>;$<TARGET_OBJECTS:xapp_objects>"
+       "$<TARGET_OBJECTS:message_objects>;$<TARGET_OBJECTS:json_objects>;$<TARGET_OBJECTS:alarm_objects>;$<TARGET_OBJECTS:xapp_objects>"
 )
 set_target_properties( ricxfcpp_shared
        PROPERTIES
@@ -232,9 +237,9 @@ else()
 endif()
 
 install( TARGETS ${target_list} EXPORT LibraryConfig
-       LIBRARY  DESTINATION ${install_lib}
-       ARCHIVE  DESTINATION ${install_lib}
-       PUBLIC_HEADER DESTINATION ${install_inc}
+       LIBRARY  DESTINATION ${install_lib}
+       ARCHIVE  DESTINATION ${install_lib}
+       PUBLIC_HEADER DESTINATION ${install_inc}
 )
 
 unset( DEV_PKG  CACHE )                        # prevent from being a hidden setting if user redoes things
diff --git a/doc/src/lib/README b/doc/src/lib/README
new file mode 100644 (file)
index 0000000..559e586
--- /dev/null
@@ -0,0 +1,4 @@
+
+This directory contains imbed files (headers) for the various
+documentation source in other directories. These imbed files
+provide common macros, variables, etc.
index 1109537..0d4b41a 100644 (file)
                                        doc_subtitle
                                        orig_date
 
+                               Setup.im must be embedded first, or &lib must be defined
+                               by the doc which imbeds this file.
+
        Date:           21 April 2020
 .fi
 
 .if ! _front_junk
        .gv e OUTPUT_TYPE ot
        .if "&ot" "generic_ps" =
+               .cd 1 6.5i m=1i
+
+               .sf &{textfont!Helvetica}
                .sp 20
                .st 24
                .bc start
@@ -75,7 +81,7 @@
                .** ensure these happen after toc is rendered
                .if pfm
                        .pn on 0 noline center f=%d
-                       .cd 1 180i
+                       .cd 1 6.5i
                .fi
        .ei
                .if "&ot" "rst" =
                        .im &{lib}/raw_license.im
                        .cd 1 6.5i m=0i
                        .ll 6i
-
-.if false
-                       .if doc_title
-                               &many_equals
-                               &doc_title
-                               &many_equals
-                       .fi
-                       .if doc_subtitle
-                               &many_dashes
-                               &doc_subtitle
-                               &many_dashes
-                       .fi
-.fi
                .fi
 
        .dv _front_junk 1
index c04a8ca..6d51a00 100644 (file)
 
 .if false
     Mnemonic:   setup.im
-    Abstract:   Look at environment variables and pull in the correct setup prep
-                imbed file based on the desired output type (when running tfm).
-                Obviously, when running pfm we are always generating postscript
-                so this isn't really doing much.
+    Abstract:   Provide general setup for all documents. It will include the
+                               {X}fm common macro definitions (cmd) which provide the ability
+                               to generate markdown, roff, and RST "source" from {X}fm source
+                               while still allowing postscript to be generated.
+
+                               Visit gitlab.com/rouxware/xfm for info on how to bulid
+                               {X}fm if needed.
+
     Date:       29 July 2019
 .fi
 
 
 .if ! _setup_im
-       .gv e XFM_IM_LIB lib
-       .if ! lib
-               .dv lib ../lib
-       .fi
+       .dv _setup_im 1
+
+       .** our imbeds live here
+       .dv lib ../lib
 
        .** sane default for everything except rst
        .dv col_width 6.5i
        .dv textsize 10
        .dv textfont Helvetica
+       .hn off
+       .tm .75i
 
        .**  imbed output type specific macro file
        .gv e OUTPUT_TYPE ot
        .dv output_type &{ot!txt}
 
+       .** {X}fm package provided common macro definitions
        .im cmd_master.im
-       .** .im  &{lib}/&{ot}.im
 
        .gv e XFM_PASS pass
        .dv pass &{pass!1}
 
 
-       .**  define a 'subroutine' to add a variable and place it into the forward reference file
-       .**  fref_sub.ca contains code to execute by the set_fref macor and fref.ca contains the
-       .**  forward references to include during pass2. The macro set_ref will define the variable
-       .**  passed as $1 (name) with the value passed as $2 and will add it to the fref.ca file.
+       .** check that current version of {X}fm is greater/equal to our minimum req'd
+       .if ! [ "2.3.2" CVGE ]
+               .gv
+               .mg ### WARN ###  this document source expects {X}fm version 2.3.2 or greater; found &{_major}.&{_minor}.&_patch
+       .fi
+
+       .gv e XFM_PATH xpath
+       .if ! xpath
+               .gv e TFM_PATH xpath
+               .if ! xpath
+                       .mg ### WARNING ###  XFM_PATH should be set to reference the shared imbed files; likely these are in /usr/local/share/xfm
+               .fi
+       .fi
+
+       .** forward variable reference support
+       .** define a 'subroutine' to add a variable and place it into the forward reference file
+       .** fref_sub.ca contains code to execute by the set_fref macor and fref.ca contains the
+       .** forward references to include during pass2. The macro set_ref will define the variable
+       .** passed as $1 (name) with the value passed as $2 and will add it to the fref.ca file.
        .**
-.ca shift start fref_sub.ca
-       .ca expand extend fref.ca
-       .dv &vname &vval
-       .ca end
+       .ca shift start _fref_sub.ca
+               .** be careful... the next  'ca end' MUST be tab indented before {X} version 2.4.
+               .** with 2.4 and after it can be space indented
+
+               .ca expand extend _fref.ca
+               .dv &vname &vval
+               .ca end
+.** this ca end MUST be in col 0
 .ca end
-       .dv set_fref .dv vname $1 ^: .dv vval $2 ^: .dv $1 $2 ^: .im fref_sub.ca
+       .dv export_var .dv vname $1 ^: .dv vval $2 ^: .dv $1 $2 ^: .im _fref_sub.ca
+       .dv export_fig  .dv vname $1 ^: .gv fig .ev ^`.dv vval ^^&_fig ^: ^`  .im _fref_sub.ca
+       .dv export_tab  .dv vname $1 ^: .gv table .ev ^`.dv vval ^^&_table ^` ^: .im _fref_sub.ca
+       .dv export_pg  .dv vname $1 ^: .gv page .ev ^`.dv vval ^^&_page ^` ^: .im _fref_sub.ca
 
 
        .if &pass 2 =
-               .im fref.ca
+               .im _fref.ca
        .ei
                .** initialise the forward ref file
-               .ca start fref.ca
+               .ca start _fref.ca
                        .** forward reference variables; auto generated
 .ca end
        .fi
 
        .** set up for an index when using pfm and snare file is defined
        .if pfm
+               .** {X}fm macro definitions are too big
+               .dh 1 p=14 s=2,1 e=off
+               .dh 2 p=12 s=1,.5
+               .dh 3 p=&{textsize!10} s=1,0
+
                .if index_snare_file
                        .ix space .sp 1 .cc 5 %c .ln  ^: .sp 0
                        .ix term .br %s  `^`   ^`` %d
                .fi
        .fi
 
-       .dv _setup_im 1
-
 .fi
diff --git a/doc/src/master.mk b/doc/src/master.mk
new file mode 100644 (file)
index 0000000..b4e252c
--- /dev/null
@@ -0,0 +1,41 @@
+#==================================================================================
+#   Copyright (c) 2020 Nokia
+#   Copyright (c) 2020 AT&T Intellectual Property.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#==================================================================================
+
+# common make meta rules and vars for all subdirectories
+
+XPATH=XFM_PATH=.:/usr/local/share/xfm TFM_PATH=.:/usr/local/share/xfm
+
+# use care: the output type is used to source the macros based on the type
+# of output being rendered.
+# Two pass builds allow for table of contents gen/insert, forward var
+# references etc.
+#
+%.ps: %.xfm
+       $(XPATH) OUTPUT_TYPE=generic_ps XFM_PASS=1 pfm $< /dev/null
+       $(XPATH) OUTPUT_TYPE=generic_ps XFM_PASS=2 pfm $< $@
+
+%.md: %.xfm
+       $(XPATH) OUTPUT_TYPE=markdown XFM_PASS=1 tfm $< /dev/null
+       $(XPATH) OUTPUT_TYPE=markdown XFM_PASS=2 tfm $< | sed 's/^ //' >$@
+
+%.rst: %.xfm
+       $(XPATH) OUTPUT_TYPE=rst XFM_PASS=1 tfm $< /dev/null
+       $(XPATH) OUTPUT_TYPE=rst XFM_PASS=2 tfm $< | sed 's/^ //; s/ *$$//' >$@
+
+%.txt: %.xfm
+       $(XPATH) OUTPUT_TYPE=txt XFM_PASS=1 tfm $< /dev/null
+       $(XPATH) OUTPUT_TYPE=txt XFM_PASS=2 tfm $< $@
index eda0613..716358c 100644 (file)
@@ -22,26 +22,9 @@ src = rel-notes.xfm
 imbed_src =
 desired_out = rst
 
-# use care: the output type is used to source the macros based on the type
-# of output being rendered.
-# Two pass builds allow for table of contents gen/insert, forward var
-# references etc.
-#
-%.ps: %.xfm
-       OUTPUT_TYPE=generic_ps XFM_PASS=1 pfm $< /dev/null
-       OUTPUT_TYPE=generic_ps XFM_PASS=2 pfm $< $@
-
-%.md: %.xfm
-       OUTPUT_TYPE=markdown XFM_PASS=1 tfm $< /dev/null
-       OUTPUT_TYPE=markdown XFM_PASS=2 tfm $< | sed 's/^ //' >$@
-
-%.rst: %.xfm
-       OUTPUT_TYPE=rst XFM_PASS=1 tfm $< /dev/null
-       GEN_TITLE=1 OUTPUT_TYPE=rst XFM_PASS=2 tfm $< | sed 's/ $$//; s/^ //' >$@
+include ../master.mk 
 
-%.txt: %.xfm
-       OUTPUT_TYPE=txt XFM_PASS=1 tfm $< /dev/null
-       OUTPUT_TYPE=txt XFM_PASS=2 tfm $< $@
+XPATH = XFM_PATH=.:/usr/local/share/xfm
 
 # -----------------------------------------------------------------------------------
 
@@ -70,6 +53,7 @@ clean:
 # Destroy anything that can be built
 nuke: clean
        rm -fr *.md *.ps *.pdf *.txt *.rst *.toc
+       rm -fr rel-notes.xfm
 
 # make hack to force a rule to always be out of date
 always:
index eb3b99b..fb19338 100755 (executable)
@@ -31,8 +31,10 @@ cat <<endKat
 .dv GEN_TITLE 1
 .dv doc_title Release Notes
 
-.im setup.im
-.dh 1 u=off
+.im ../lib/setup.im
+.im ../lib/front_junk.im
+.dh 1 u=off s=1,0
+.dh 2 u=off s=1,0
 
 &h1(C++ Framework Release Notes)
 The following is a list of release highlights for the C++ xAPP Framework.
@@ -44,8 +46,12 @@ do
        awk '
                /^#/ { next }           # ditch all comments
 
-               # tag project releases by matching release tag associated
-               /1\.0\.0$/  { printf( "&h1(Bronze Release)\n" ) }
+               # tag project releases by matching release tag in CHANGES file
+               /^release=/ || /^release =/ {
+                       n = split( $0, a, "=" )
+                       printf( "&h1(%s Release)\n", a[n] )
+                       next
+               }
 
                print_raw && /^$/ {                             # include blank lines after first real stuff
                        printf( "&space\n\n" );
index 0be1017..935e799 100644 (file)
@@ -1,3 +1,6 @@
+=============
+RELEASE NOTES
+=============
 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
 .. SPDX-License-Identifier: CC-BY-4.0
 ..
@@ -6,28 +9,31 @@
 .. Do NOT make changes directly to .rst or .md files.
 
 
-============================================================================================
-Release Notes
-============================================================================================
-
 
 C++ Framework Release Notes
 ===========================
-
 The following is a list of release highlights for the C++
 xAPP Framework.
 
+Cherry Release
+==============
 
-2020 June 29; version 1.2.0
+2020 July 17; version 2.0.0
 ---------------------------
+Add alarm support.
 
-Add support for json parsing
+Add xapp namespace for Message, Msg_component, Alarm and Jhah
+objects. This is a BREAKING change and thus the major version
+number was bumped to 2.
 
 
+2020 June 29; version 1.2.0
+---------------------------
+Add support for json parsing
+
 
 2020 June 26; version 1.1.0
 ---------------------------
-
 Change the port type in constructors to indicate "const"
 
 Version bump to 1.1.0 to allow patches to bronze code to
@@ -38,19 +44,14 @@ continue to be done on the 1.0.* level.
 Bronze Release
 ==============
 
-
-
 2020 April 28; version 1.0.0
 ----------------------------
-
 Bump version to force package build (old CI version added
 incorrect install prefix). Bump to 1.0.0 for release.
 
 
-
 2020 March 27; version 0.1.2
 ----------------------------
-
 Changes identified by sonar (missing copy/move builders)
 rmr_dump example programme Improvements to code for better
 test coverage
diff --git a/doc/src/rtd/rel-notes.xfm b/doc/src/rtd/rel-notes.xfm
deleted file mode 100644 (file)
index 370cda7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-
-.** ------------------------------------------------------------------------
-.** CAUTION: This .xfm file is automatically generated by fmt_changes.ksh
-.**          do NOT edit. Use 'make rel-notes.xfm' to regenerate.
-.** ------------------------------------------------------------------------
-
-.dv GEN_TITLE 1
-.dv doc_title Release Notes
-
-.im setup.im
-.dh 1 u=off
-
-&h1(C++ Framework Release Notes)
-The following is a list of release highlights for the C++ xAPP Framework.
-
-&h2(2020 June 29; version 1.2.0)
-       Add support for json parsing
-&space
-
-&h2(2020 June 26; version 1.1.0)
-       Change the port type in constructors to indicate "const"
-&space
-
-       Version bump to 1.1.0 to allow patches to bronze code to
-       continue to be done on the 1.0.* level.
-&space
-
-&h1(Bronze Release)
-&h2(2020 April 28; version 1.0.0)
-       Bump version to force package build (old CI version added
-       incorrect install prefix). Bump to 1.0.0 for release.
-&space
-
-&h2(2020 March 27; version 0.1.2)
-       Changes identified by sonar (missing copy/move builders)
-       rmr_dump example programme
-       Improvements to code for better test coverage
diff --git a/doc/src/rtd/setup.im b/doc/src/rtd/setup.im
deleted file mode 100644 (file)
index 86f3be8..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-.** vim: ts=4 sw=4 noet:
-.if false
-==================================================================================
-       Copyright (c) 2019-2020 Nokia
-       Copyright (c) 2018-2020 AT&T Intellectual Property.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================================
-.fi
-
-.if false
-       Mnemonic:       setup.im
-       Abstract:       Look at environment variables and pull in the correct setup prep
-                               imbed file based on the desired output type (when running tfm).
-                               Obviously, when running pfm we are always generating postscirpt
-                               so this isn't really doing much.
-       Date:           6 November 2019
-.fi
-
-.if  ! _setup_im
-.dv _setup_im 1
-
-.** allow environment LIB to override
-.gv e LIB lib
-.if ! lib
-       .dv lib ../lib
-.fi
-
-.hn off
-
-.** CAUTION:  xfm comparisons are reverse polish so  "a b ="  is true if a == b.
-.if pfm
-       .dv ot postscript
-       .im &{lib}/generic_ps.im
-.ei
-       .gv e OUTPUT_TYPE ot
-       .if "&ot" "txt" =
-               .im &{lib}/txt.im
-       .fi
-       .if "&ot" "rst" =
-               .im &{lib}/rst.im
-       .fi
-       .if "&ot" "markdown" =
-               .im &{lib}/markdown.im
-       .fi
-       .if "&ot" "troff" =
-               .im &{lib}/roff.im
-       .fi
-       .if "&ot" "html" =
-               .im &{lib}/html.im
-       .fi
-.fi
-
-.** if we can set a license into the output, do it early
-.cd 1 11i
-&line_len(10i)
-.im &{lib}/license.im
-.cd 1 6.5i m=0 i=0
-&line_len( 6i)
-
-.if ! textsize
-       .dv textsize 10
-.fi
-.if ! textfont
-       .dv textfont Helvetica
-.fi
-
-.if doc_title
-       .im &{lib}/front_junk.im
-.fi
-
-.fi
-
index 8ef4aae..6e87a29 100644 (file)
@@ -1,7 +1,17 @@
+# don't stash generated things
 *.ps
 *.rst
 *.txt
+*.md
 *.html
+*.eps
+
+# don't stash intermediate things
 *.sp
 *.ca
 *.toc
+*.bcnfile
+
+# don't stash backups
+*-
+*.bak
index 70ab002..303cc20 100644 (file)
 
 # this uses {X}fm which can be cloned from: https://gitlab.com/rouxware/xfm
 
-XPATH=XFM_PATH=.:/usr/local/share/xfm TFM_PATH=.:/usr/local/share/xfm
-
 docs = user_guide
 src = user_guide.xfm
-imbed_src = cpp_frame.im example1.im example2.im example3.im jhash.im
-desired_out = rst ps
-
-# use care: the output type is used to source the macros based on the type
-# of output being rendered.
-# Two pass builds allow for table of contents gen/insert, forward var
-# references etc.
-#
-%.ps: %.xfm
-       $(XPATH) OUTPUT_TYPE=generic_ps XFM_PASS=1 pfm $< /dev/null
-       $(XPATH) OUTPUT_TYPE=generic_ps XFM_PASS=2 pfm $< $@
-
-%.md: %.xfm
-       $(XPATH) OUTPUT_TYPE=markdown XFM_PASS=1 tfm $< /dev/null
-       $(XPATH) OUTPUT_TYPE=markdown XFM_PASS=2 tfm $< | sed 's/^ //' >$@
-
-%.rst: %.xfm
-       $(XPATH) OUTPUT_TYPE=rst XFM_PASS=1 tfm $< /dev/null
-       $(XPATH) GEN_TITLE=1 OUTPUT_TYPE=rst XFM_PASS=2 tfm $< | sed 's/^ //; s/ *$$//' >$@
+imbed_src = cpp_frame.im example1.im example2.im example3.im jhash.im example4.im
+desired_out = rst ps md
 
-%.txt: %.xfm
-       $(XPATH) OUTPUT_TYPE=txt XFM_PASS=1 tfm $< /dev/null
-       $(XPATH) OUTPUT_TYPE=txt XFM_PASS=2 tfm $< $@
+include ../master.mk
 
 # -----------------------------------------------------------------------------------
 all:    $(desired_out:%=user_guide.%)
diff --git a/doc/src/user/alarm.im b/doc/src/user/alarm.im
new file mode 100644 (file)
index 0000000..e020a67
--- /dev/null
@@ -0,0 +1,196 @@
+.** vim: sw=4 ts=4 et :
+.if false
+==================================================================================
+    Copyright (c) 2020 Nokia
+    Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+.fi
+
+
+.if false
+       This imbed file contains the portion of the document that describes the
+       alarm collector AIP provided by the framework.
+.fi
+
+
+.if pfm
+    .** work round bug in cmd_ps.im
+    .dv beg_table .ta $1
+    .dv end_table .et
+    .dv col .cl ^:
+    .dv row .tr ^:
+.fi
+
+.** ------ positioning -------------------------------------
+
+&h1(Alarm Manager Interface)
+The C++ framework provides an API which allows the xAPP to easily construct and
+generate alarm messages.
+Alarm messages are a special class of RMR message, allocated in a similar fashion
+as an RMR message through the framework's &cw(Alloc_alarm()) function.
+
+&space
+The API consists of the following function types:
+
+&half_space
+&indent
+&beg_dlist( 1i &ditemtext: )
+       &di(Raise) Cause the alarm to be assigned a severity and and sent via RMR
+                       message to the alarm collector process.
+
+       &half_space
+       &di(Clear) Cause a clear message to be sent to the alarm collector.
+
+       &half_space
+       &di(Raise Again) Cause a clear followed by a raise message to be sent to
+                       the alarm collector.
+&end_dlist
+&uindent
+&space
+
+&h2(Allocating Alarms)
+The &cw(xapp::Alloc_alarm()) function provided by the framework is used to create
+an alarm object.
+Once the xAPP has an alarm object it can be used to send one, or more, alarm
+messages to the collector.
+
+&space
+The allocation function has three prototypes which allow the xAPP to create
+an alarm with an initial set of information as is appropriate.
+The following are the prototypes for the allocate functions:
+
+&half_space
+.im alloc_proto.im
+
+
+Each of the allocation functions returns a unique pointer to the alarm.
+In the simplest form (1) the alarm is initialised with an empty meid
+(managed element ID) string, and unset problem ID (-1).
+The second prototype allows the xAPP to supply the meid, and in the
+third form both the problem ID and the meid are used to initialise the
+alarm.
+
+&h2(Raising An Alarm)
+Once an alarm has been allocated, its &cw(Raise()) function can be used
+to cause the alarm to be sent to the collector.
+The raise process allows the xAPP to perform the following modifications
+to the alarm before sending the message:
+
+&half_space
+&indent
+&beg_list(&lic1)
+       &li Set the alarm severity
+       &half_space
+       &li Set the problem ID value
+       &half_space
+       &li Set the alarm information string
+       &half_space
+       &li Set the additional information string
+&end_list
+&uindent
+&space
+
+The following are the prototypes for the &cw(Raise()) functions of an alarm object:
+.....
+
+
+
+In its simplest form (1) the &cw(Raise()) function will send the alarm without making any
+changes to the data.
+The final two forms allow the xAPP to supply additional data which is added to the
+alarm before sending the message.
+
+Each of the raise functions returns &cw(true) on success and &cw(false) if the alarm
+message could not be sent.
+
+&h3(Severity)
+The severity is one of the &cw(SEV_) constants listed below.
+These map to alarm collector strings and insulate the xAPP from any future alarm collector
+changes.
+The specific meaning of these severity types are defined by the alarm collector and thus
+no attempt is made to guess what their actual meaning is.
+These constants are available by including &cw(alarm.hpp.)
+
+&half_space
+&indent
+&ex_start
+    SEV_MAJOR
+    SEV_MINOR
+    SEV_WARN
+    SEV_DEFAULT
+&ex_end
+&uindent
+&fig_cen(Severity constants available in alarm.hpp.)
+
+&h3(The Problem ID)
+The problem ID is an integer which is assigned by the xAPP.
+The framework makes no attempt to verify that it has been se, nor does it attempt
+to validate the value.
+If the xAPP does not set the value, &cw(-1) is used.
+
+&h3(Information Strings)
+The two information strings are also xAPP defined and provide the information that
+the xAPP deems necessary and related to the alarm.
+What the collector expects, and how these strings are used, is beyond the scope of
+the framework to describe or validate.
+If not supplied, empty strings are sent in the alarm message.
+
+&h2(Clearing An Alarm)
+The &cw(Clear()) function of an alarm may be used to send a clear message.
+In a manner similar to the &cw(Raise()) functions, the &cw(Clear()) functions allow
+the existing alarm data to be sent without change, or for the xAPP to modify the
+data before the message is sent to the collector.
+The following are the prototype for these functions.
+
+
+&ex_start
+   bool Clear( );
+   bool Clear( int severity, int problem, std::string info );
+   bool Clear( int severity, int problem, std::string info, std::string addional_info );
+   bool Clear_all( );
+
+&ex_end
+&fig_cen(Clear function prototypes. )
+&space
+
+Each of the clear functions returns &cw(true) on success and &cw(false) if the alarm
+message could not be sent.
+
+
+&space
+The &cw(Clear_all()) function sends a special action code to the collector which is assumed
+to clear all alarms.
+However, it is unknown whether that implies &bold(all) alarms, or all alarms matching the
+&cw(problem_id,) or some other interpretation.
+Please consult the alarm collector documentation for these specifics.
+
+
+&h2(Adjusting Alarm Contents)
+It might be necessary for the xAPP to adjust the alarm contents outside of the scope of
+the &cw(Raise()) function, or to adjust data that cannot be manipulated by &cw(Raise().)
+The following are the (self explanatory) prototypes for the &ital(setter) functions
+which are available to the xAPP.
+&half_space
+
+&ex_start
+  void Set_additional( std::string new_info );
+  void Set_appid( std::string new_id );
+  void Set_info( std::string new_info );
+  void Set_meid( std::string new_meid );
+  void Set_problem( int new_id );
+  void Set_severity( int new_sev );
+&ex_end
+&fig_cen(Alarm Setters)
+&space
diff --git a/doc/src/user/alloc_proto.im b/doc/src/user/alloc_proto.im
new file mode 100644 (file)
index 0000000..bcb48c8
--- /dev/null
@@ -0,0 +1,51 @@
+.** vim: sw=4 ts=4 et :
+.if false
+==================================================================================
+    Copyright (c) 2020 Nokia
+    Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+.fi
+
+
+.** for now we have to sort out based on pfm vs tfm since table
+.** constuction for any of the "mark*" parsers sucks.
+
+.ca start proto.ca
+&ex_start
+  std::unique_ptr<xapp::Alarm> Alloc_alarm( );
+  std::unique_ptr<xapp::Alarm> Alloc_alarm( std::string meid );
+  std::unique_ptr<xapp::Alarm> Alloc_alarm( int prob_id, std::string meid );
+&ex_end
+.ca end
+
+.if pfm
+&beg_table( 5.25i .3i  b=0 : 80,15 )
+.im proto.ca
+&col
+&ex_start
+(1)
+(2)
+(3)
+&ex_end
+&end_table
+
+.ei
+
+.im proto.ca
+
+.fi
+
+&fig_cen(Alarm allocation prototypes.)
+&space
index 0c7a560..f9e3963 100644 (file)
@@ -34,6 +34,22 @@ the instance of the object.
 The following paragraphs cover the various steps involved to create an xApp instance, wait for a route
 table to arrive, send a message, and wait for messages to arrive.
 
+&h2(The Namespace)
+Starting with version 2.0.0 the framwork introduces a &ital(namespace) of &cw(xapp) for the following
+classes and types:
+&half_space
+&indent
+&beg_list(&lic1)
+       &li Alarm
+       &li Jhash
+       &li Message
+       &li Msg_component
+&end_list
+&uindent
+&space
+
+This is a breaking change and as such the major version was bumpped from 1 to 2.
+
 &h2(Creating the xApp instance)
 The creation of the xApp instance is as simple as invoking the object's constructor with two required
 parameters:
@@ -67,7 +83,7 @@ The following code sample illustrates the simplicity of creating the instance of
               new Xapp( listen_port, wait4table ) );
     }
 &ex_end
-&fig( Creating an xAPP instance.)
+&fig_cen( Creating an xAPP instance.)
 &space
 
 From a compilation perspective, the following is the simple compiler invocation string needed to compile
@@ -102,11 +118,11 @@ The following is the prototype which callback functions must be defined with:
 &half_space
 
 &ex_start
-    void cb_name( Message& m, int mtype, int subid,
-          int payload_len, Msg_component payload,
+    void cb_name( xapp::Message& m, int mtype, int subid,
+          int payload_len, xapp::Msg_component payload,
           void* usr_data );
 &ex_end
-&fig( Callback function signature)
+&fig_cen( Callback function signature)
 &space
 
 The parameters passed to the callback function are as follows:
@@ -146,8 +162,8 @@ framework (explained in the next section).
     long m1001_count = 0;
 
     // callback function that will increase the appropriate counter
-    void cbf( Message& mbuf, int mtype, int subid, int len,
-                Msg_component payload,  void* data ) {
+    void cbf( xapp::Message& mbuf, int mtype, int subid, int len,
+                xapp::Msg_component payload,  void* data ) {
         long* counter;
 
         if( (counter = (long *) data) != NULL ) {
@@ -170,7 +186,7 @@ framework (explained in the next section).
         xapp->Run( 1 );        // start the callback driver
     }
 &ex_end
-&fig( Callback function example.)
+&fig_cen( Callback function example.)
 &space
 
 As before, the program does nothing useful, but now it will execute and receive messages.
@@ -232,7 +248,7 @@ with the following prototypes.
 
    bool Send_response(  int response_len, std::shared_ptr<unsigned char> response );
 &ex_end
-&fig( Reply function prototypes. )
+&fig_cen( Reply function prototypes. )
 &space
 
 In the first prototype the xApp must supply the new message type and subscription ID values, where the
@@ -245,10 +261,10 @@ constant can be used as illustrated below.
 &half_space
 
 &ex_start
-    msg->Send_response( Message::NO_CHANGE, Message::NO_SUBID,
+    msg->Send_response( xapp::Message::NO_CHANGE, xapp::Message::NO_SUBID,
         pl_length, (unsigned char *) payload );
 &ex_end
-&fig( Send response prototype. )
+&fig_cen( Send response prototype. )
 &space
 
 In addition to the two function prototypes for &cw(Send_response()) there are two additional prototypes
@@ -273,7 +289,7 @@ functions and are shown below.
 
     bool Send_msg( int payload_len, unsigned char* payload );
 &ex_end
-&fig( Send function prototypes. )
+&fig_cen( Send function prototypes. )
 &space
 
 Each send function accepts the message, copies in the payload provided, sets the message type and subscription
@@ -314,7 +330,7 @@ for the response string, the response is just not sent).
       msg->Send_response( M_TYPE, SID, strlen( raw_pl ), NULL );
     }
 &ex_end
-&fig( Send message without buffer copy. )
+&fig_cen( Send message without buffer copy. )
 &space
 
 &h2(Sending Multiple Responses)
diff --git a/doc/src/user/example4.im b/doc/src/user/example4.im
new file mode 100644 (file)
index 0000000..a1968bf
--- /dev/null
@@ -0,0 +1,37 @@
+.if false
+==================================================================================
+    Copyright (c) 2020 Nokia
+    Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+.fi
+
+&h2(Alarm Example)
+This is an extension of a previous example which sends an alarm
+during initialisation and clears the alarm as soon as messages
+are being received.
+It is unknown if this is the type of alarm that is expected at the
+collector, but illustrates how an alarm is allocated, raised and
+cleared.
+
+
+&space
+&indent
+.** pull in the code from the example directory
+&ex_start
+.im  j=start-example ../../../examples/xapp_alarm.cpp
+&ex_end
+&fig( Simple looping sender application with alarm generation. )
+&space
+
index ec30b0c..66bbb57 100644 (file)
@@ -46,7 +46,7 @@ The Jhash object is created simply by passing a json string to the constructor.
 
     jh =  new Jhash( jstring.c_str() );
 &ex_end
-&fig(The creation of the Jhash object.)
+&fig_cen(The creation of the Jhash object.)
 &space
 
 
@@ -59,9 +59,11 @@ The approach taken by Jhash is a "directory view" approach, where the "current d
 or current &ital(blob,) limits the scope of visible fields.
 
 &space
-As an example, the json contained in figure jblob_fig, contains a "root" blob and
+As an example, the json contained in figure &jblob_fig, contains a "root" blob and
 two &ital(sub-blobs) (address and lease_info).
+&half_space
 
+.ca start blob_ex.ca
 &ex_start
     {
         "lodge_name": "Water Buffalo Lodge 714",
@@ -82,26 +84,26 @@ two &ital(sub-blobs) (address and lease_info).
         }
     }
 &ex_end
-.gv fig
-.sv _fig
-&set_fref(jblob_fig:&_fig)
-&fig(Sample json with a root and too blobs.)
-
+&export_fig( jblob_fig )
+&fig_cen(Sample json with a root and two blobs.)
 &space
+.ca end
+&ifroom( 3i : blob_ex.ca )
+
+
 Upon creation of the Jhash object, the &ital(root) fields, &cw(lodge_name,) &cw(member_count,) and
 &cw(grand_poobah) are immediately available.
-The fields in the &ital(sub-blobs) are avalable only when the correct blob is selected.
+The fields in the &ital(sub-blobs) are available only when the correct blob is selected.
 The code sample in figure &fig_blob_sample illustrates how  a &ital(sub-blob) is selected.
 
 &ex_start
     jh->Set_blob( (char *) "address" );     // select address
     jh->Unset_blob();                       // return to root
-    jh->Set_blob( (char *) "lease_info" );  // slect the lease blob
+    jh->Set_blob( (char *) "lease_info" );  // select the lease blob
 &ex_end
-.gv fig
-.sv _fig
-&set_fref(fig_blob_sample:&_fig)
-&fig(Blob selection example.)
+.sv export_fig
+&export_fig( fig_blob_sample )
+&fig_cen(Blob selection example.)
 &space
 
 Currently, the selected blob must be unset in order to select a blob at the root
@@ -126,7 +128,7 @@ The following are the prototypes for the functions which allow values to be extr
 &ex_end
 &space
 
-Each of these funcitons returns the value associated with the field with the given &ital(name.)
+Each of these functions returns the value associated with the field with the given &ital(name.)
 If the value is missing, the following default values are returned:
 
 &half_space
@@ -146,8 +148,8 @@ If the user needs to disambiguate between a missing value and the default value
 Two functions allow the developer to determine whether or not a field is included in the
 json.
 Both of these functions work on the current &ital(blob,) therefore it is important to ensure
-that the correct blob is selected before using either of these funcitons.
-The prototpyes for the &cw(Exists) and &cw(Missing) functions are below:
+that the correct blob is selected before using either of these functions.
+The prototypes for the &cw(Exists) and &cw(Missing) functions are below:
 
 &ex_start
     bool Exists( const char* name );
@@ -155,7 +157,7 @@ The prototpyes for the &cw(Exists) and &cw(Missing) functions are below:
 &ex_end
 
 The &cw(Exists) function returns &ital(true) if the field name exists in the json and &ital(false) otherwise.
-Conversly, the &cw(Missing) funciton returns &ital(true) when the field name does not exist in the json.
+Conversely, the &cw(Missing) function returns &ital(true) when the field name does not exist in the json.
 
 
 &h2(Testing Field Type)
@@ -173,7 +175,7 @@ The following are the prototypes for these functions:
 &ex_end
 
 &space
-Each of these funcitons return &ital(true) if the field with the given name is of the type
+Each of these functions return &ital(true) if the field with the given name is of the type
 being tested for.
 
 
@@ -202,7 +204,7 @@ For each of these functions the &cw(eidx) is the zero based element index which
 be tested or selected.
 
 &h3(Arrays of Blobs)
-An array containing blobs, rather than simiple field value pairs, the blob must
+An array containing blobs, rather than simple field value pairs, the blob must
 be selected prior to using it, just as a sub-blob needed to be selected.
 The &cw(Set_blob_ele) function is used to do this and has the following prototype:
 
@@ -211,7 +213,7 @@ The &cw(Set_blob_ele) function is used to do this and has the following prototyp
 &ex_end
 &space
 
-As with selecting a sub-blob, an unset must be preformed before selecting the next blob.
+As with selecting a sub-blob, an unset must be performed before selecting the next blob.
 Figure &array_blob_code_fig illustrates how these functions can be used to read and print
 values from the json in figure &array_blob_json_fig.
 
@@ -225,9 +227,8 @@ values from the json in figure &array_blob_json_fig.
         { "name": "Kyle Limestone", "member_num": 49 }
     ]
 &ex_end
-.gv fig
-&set_fref(array_blob_code_fig:&_fig)
-&fig(Json array containing blobs.)
+&export_fig(array_blob_code_fig)
+&fig_cen(Json array containing blobs.)
 &space
 
 
@@ -248,8 +249,7 @@ values from the json in figure &array_blob_json_fig.
         jh->Unset_blob();                           // back to root
     }
 &ex_end
-.gv fig
-&set_fref(array_blob_json_fig:&_fig)
-&fig(Code to process the array of blobs.)
+&export_fig(array_blob_json_fig )
+&fig_cen(Code to process the array of blobs.)
 &space
 
diff --git a/doc/src/user/raise_proto.im b/doc/src/user/raise_proto.im
new file mode 100644 (file)
index 0000000..13f906f
--- /dev/null
@@ -0,0 +1,57 @@
+.** vim: sw=4 ts=4 et :
+.if false
+==================================================================================
+    Copyright (c) 2020 Nokia
+    Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+.fi
+
+
+.** we cant generate ncie tables it seems in any mark* language
+.** so do nice formatting in pfm, and just embed the protos
+.** for the bloody ascii based things.
+
+.ca start proto.ca
+&ex_end
+  bool Raise( );
+  bool Raise( int severity, int problem, std::string info );
+  bool Raise( int severity, int problem, std::string info,
+              std::string addional_info );
+  bool Raise_again( );
+&ex_end
+.ca end
+
+.if pfm
+
+
+&beg_table( 5.25i .3i : 80,15 )
+&col
+.im proto.ca
+&ex_start
+(1)
+(2)
+(3)
+
+(4)
+&ex_end
+&end_table
+
+
+.ei
+.im proto.ca
+.fi
+
+&fig_cen(The Raise function prototypes.)
+&space
index 4a469f7..e6e47f1 100644 (file)
@@ -55,6 +55,7 @@
 .**  ------ major sections --------
 .im cpp_frame.im
 .im jhash.im
+.im alarm.im
 
 &h1(Example Programmes)
 The following sections contain several example programmes which are written on
@@ -63,3 +64,4 @@ top of the C++ framework.
 .im example1.im
 .im example2.im
 .im example3.im
+.im example4.im
index 0be1017..935e799 100644 (file)
@@ -1,3 +1,6 @@
+=============
+RELEASE NOTES
+=============
 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
 .. SPDX-License-Identifier: CC-BY-4.0
 ..
@@ -6,28 +9,31 @@
 .. Do NOT make changes directly to .rst or .md files.
 
 
-============================================================================================
-Release Notes
-============================================================================================
-
 
 C++ Framework Release Notes
 ===========================
-
 The following is a list of release highlights for the C++
 xAPP Framework.
 
+Cherry Release
+==============
 
-2020 June 29; version 1.2.0
+2020 July 17; version 2.0.0
 ---------------------------
+Add alarm support.
 
-Add support for json parsing
+Add xapp namespace for Message, Msg_component, Alarm and Jhah
+objects. This is a BREAKING change and thus the major version
+number was bumped to 2.
 
 
+2020 June 29; version 1.2.0
+---------------------------
+Add support for json parsing
+
 
 2020 June 26; version 1.1.0
 ---------------------------
-
 Change the port type in constructors to indicate "const"
 
 Version bump to 1.1.0 to allow patches to bronze code to
@@ -38,19 +44,14 @@ continue to be done on the 1.0.* level.
 Bronze Release
 ==============
 
-
-
 2020 April 28; version 1.0.0
 ----------------------------
-
 Bump version to force package build (old CI version added
 incorrect install prefix). Bump to 1.0.0 for release.
 
 
-
 2020 March 27; version 0.1.2
 ----------------------------
-
 Changes identified by sonar (missing copy/move builders)
 rmr_dump example programme Improvements to code for better
 test coverage
index e0ac2e1..17f741d 100644 (file)
@@ -36,6 +36,23 @@ involved to create an xApp instance, wait for a route table
 to arrive, send a message, and wait for messages to arrive.
 
 
+The Namespace
+-------------
+
+Starting with version 2.0.0 the framwork introduces a
+*namespace* of ``xapp`` for the following classes and types:
+
+
+   * Alarm
+   * Jhash
+   * Message
+   * Msg_component
+
+
+This is a breaking change and as such the major version was
+bumpped from 1 to 2.
+
+
 Creating the xApp instance
 --------------------------
 
@@ -43,27 +60,27 @@ The creation of the xApp instance is as simple as invoking
 the object's constructor with two required parameters:
 
 
-      .. list-table::
-        :widths: auto
-        :header-rows: 0
-        :class: borderless
+       .. list-table::
+         :widths: auto
+         :header-rows: 0
+         :class: borderless
 
-        * - **port**
-          -
-            A C string (pointer to char) which defines the port that
-            RMR will open to listen for connections.
+         * - **port**
+           -
+             A C string (pointer to char) which defines the port that
+             RMR will open to listen for connections.
 
 
-            |
+             |
 
-        * - **wait**
-          -
-            A Boolean value which indicates whether or not the
-            initialization process should wait for the arrival of a
-            valid route table before completing. When true is
-            supplied, the initialization will not complete until RMR
-            has received a valid route table (or one is located via
-            the ``RMR_SEED_RT`` environment variable).
+         * - **wait**
+           -
+             A Boolean value which indicates whether or not the
+             initialization process should wait for the arrival of a
+             valid route table before completing. When true is
+             supplied, the initialization will not complete until RMR
+             has received a valid route table (or one is located via
+             the ``RMR_SEED_RT`` environment variable).
 
 
 
@@ -73,16 +90,16 @@ creating the instance of the xApp object.
 
 ::
 
-     #include <memory>
-     #include <ricxfcpp/xapp.hpp>
-     int main( ) {
-         std::unique_ptr<Xapp> xapp;
-         char* listen_port = (char *) "4560";    //RMR listen port
-         bool  wait4table = true;            // wait for a route table
-
-         xapp = std::unique_ptr<Xapp>(
-               new Xapp( listen_port, wait4table ) );
-     }
+      #include <memory>
+      #include <ricxfcpp/xapp.hpp>
+      int main( ) {
+          std::unique_ptr<Xapp> xapp;
+          char* listen_port = (char *) "4560";    //RMR listen port
+          bool  wait4table = true;            // wait for a route table
+
+          xapp = std::unique_ptr<Xapp>(
+                new Xapp( listen_port, wait4table ) );
+      }
 
 Figure 1: Creating an xAPP instance.
 
@@ -94,7 +111,7 @@ called ``man_ex1.cpp``.
 
 ::
 
-    g++ man_ex1.cpp -o man_ex1 -lricxfcpp -lrmr_si -lpthread
+     g++ man_ex1.cpp -o man_ex1 -lricxfcpp -lrmr_si -lpthread
 
 
 The above program, while complete and capable of being
@@ -131,9 +148,9 @@ which callback functions must be defined with:
 
 ::
 
-     void cb_name( Message& m, int mtype, int subid,
-           int payload_len, Msg_component payload,
-           void* usr_data );
+      void cb_name( xapp::Message& m, int mtype, int subid,
+            int payload_len, xapp::Msg_component payload,
+            void* usr_data );
 
 Figure 2: Callback function signature
 
@@ -141,55 +158,55 @@ The parameters passed to the callback function are as
 follows:
 
 
-      .. list-table::
-        :widths: auto
-        :header-rows: 0
-        :class: borderless
+       .. list-table::
+         :widths: auto
+         :header-rows: 0
+         :class: borderless
 
-        * - **m**
-          -
-            A reference to the Message that was received.
+         * - **m**
+           -
+             A reference to the Message that was received.
 
 
-            |
+             |
 
-        * - **mtype**
-          -
-            The message type (allows for disambiguation if the
-            callback is registered for multiple message types).
+         * - **mtype**
+           -
+             The message type (allows for disambiguation if the
+             callback is registered for multiple message types).
 
 
-            |
+             |
 
-        * - **subid**
-          -
-            The subscription ID from the message.
+         * - **subid**
+           -
+             The subscription ID from the message.
 
 
-            |
+             |
 
-        * - **payload len**
-          -
-            The number of bytes which the sender has placed into the
-            payload.
+         * - **payload len**
+           -
+             The number of bytes which the sender has placed into the
+             payload.
 
 
-            |
+             |
 
-        * - **payload**
-          -
-            A direct reference (smart pointer) to the payload. (The
-            smart pointer is wrapped in a special class in order to
-            provide a custom destruction function without burdening
-            the xApp developer with that knowledge.)
+         * - **payload**
+           -
+             A direct reference (smart pointer) to the payload. (The
+             smart pointer is wrapped in a special class in order to
+             provide a custom destruction function without burdening
+             the xApp developer with that knowledge.)
 
 
-            |
+             |
 
-        * - **user data**
-          -
-            A pointer to user data. This is the pointer that was
-            provided when the function was registered.
+         * - **user data**
+           -
+             A pointer to user data. This is the pointer that was
+             provided when the function was registered.
 
 
 
@@ -201,35 +218,35 @@ section).
 
 ::
 
-     #include <memory>
-     #include <ricxfcpp/xapp.hpp>
-     long m1000_count = 0;    // message counters, one for each type
-     long m1001_count = 0;
+      #include <memory>
+      #include <ricxfcpp/xapp.hpp>
+      long m1000_count = 0;    // message counters, one for each type
+      long m1001_count = 0;
 
-     // callback function that will increase the appropriate counter
-     void cbf( Message& mbuf, int mtype, int subid, int len,
-                 Msg_component payload,  void* data ) {
-         long* counter;
+      // callback function that will increase the appropriate counter
+      void cbf( xapp::Message& mbuf, int mtype, int subid, int len,
+                  xapp::Msg_component payload,  void* data ) {
+          long* counter;
 
-         if( (counter = (long *) data) != NULL ) {
-             (*counter)++;
-         }
-     }
+          if( (counter = (long *) data) != NULL ) {
+              (*counter)++;
+          }
+      }
 
-     int main( ) {
-         std::unique_ptr<Xapp> xapp;
-         char* listen_port = (char *) "4560";
-         bool  wait4table = false;
+      int main( ) {
+          std::unique_ptr<Xapp> xapp;
+          char* listen_port = (char *) "4560";
+          bool  wait4table = false;
 
-         xapp = std::unique_ptr<Xapp>(
-               new Xapp( listen_port, wait4table ) );
+          xapp = std::unique_ptr<Xapp>(
+                new Xapp( listen_port, wait4table ) );
 
-         // register the same callback function for both msg types
-         xapp->Add_msg_cb( 1000, cbf, (void *) &m1000_count );
-         xapp->Add_msg_cb( 1001, cbf, (void *) &m1001_count );
+          // register the same callback function for both msg types
+          xapp->Add_msg_cb( 1000, cbf, (void *) &m1000_count );
+          xapp->Add_msg_cb( 1001, cbf, (void *) &m1001_count );
 
-         xapp->Run( 1 );        // start the callback driver
-     }
+          xapp->Run( 1 );        // start the callback driver
+      }
 
 Figure 3: Callback function example.
 
@@ -283,10 +300,10 @@ message is a function of the message object itself and can
 take one of two forms:
 
 
-  * Replying to the sender of a received message
+   * Replying to the sender of a received message
 
-  * Sending a message (routed based on the message type and
-    subscription ID)
+   * Sending a message (routed based on the message type and
+     subscription ID)
 
 
 When replying to the sender, the message type and
@@ -303,10 +320,10 @@ following prototypes.
 
 ::
 
-    bool Send_response(  int mtype, int subid, int response_len,
-         std:shared_ptr<unsigned char> response );
+     bool Send_response(  int mtype, int subid, int response_len,
+          std:shared_ptr<unsigned char> response );
 
-    bool Send_response(  int response_len, std::shared_ptr<unsigned char> response );
+     bool Send_response(  int response_len, std::shared_ptr<unsigned char> response );
 
 Figure 4: Reply function prototypes.
 
@@ -324,8 +341,8 @@ message type, or the subscription ID, but not both, the
 
 ::
 
-     msg->Send_response( Message::NO_CHANGE, Message::NO_SUBID,
-         pl_length, (unsigned char *) payload );
+      msg->Send_response( xapp::Message::NO_CHANGE, xapp::Message::NO_SUBID,
+          pl_length, (unsigned char *) payload );
 
 Figure 5: Send response prototype.
 
@@ -343,16 +360,16 @@ are shown below.
 
 ::
 
-     bool Send_msg( int mtype, int subid, int payload_len,
-         std::shared_ptr<unsigned char> payload );
+      bool Send_msg( int mtype, int subid, int payload_len,
+          std::shared_ptr<unsigned char> payload );
 
-     bool Send_msg( int mtype, int subid, int payload_len,
-         unsigned char* payload );
+      bool Send_msg( int mtype, int subid, int payload_len,
+          unsigned char* payload );
 
-     bool Send_msg( int payload_len,
-         std::shared_ptr<unsigned char> payload );
+      bool Send_msg( int payload_len,
+          std::shared_ptr<unsigned char> payload );
 
-     bool Send_msg( int payload_len, unsigned char* payload );
+      bool Send_msg( int payload_len, unsigned char* payload );
 
 Figure 6: Send function prototypes.
 
@@ -397,15 +414,15 @@ not sent).
 
 ::
 
-     Msg_component payload;  // smart reference
-     int pl_size;            // max size of payload
+      Msg_component payload;  // smart reference
+      int pl_size;            // max size of payload
 
-     payload = msg->Get_payload();
-     pl_size = msg->Get_available_size();
-     if( snprintf( (char *) payload.get(), pl_size,
-         "Msg Received\\n" ) < pl_size ) {
-       msg->Send_response( M_TYPE, SID, strlen( raw_pl ), NULL );
-     }
+      payload = msg->Get_payload();
+      pl_size = msg->Get_available_size();
+      if( snprintf( (char *) payload.get(), pl_size,
+          "Msg Received\\n" ) < pl_size ) {
+        msg->Send_response( M_TYPE, SID, strlen( raw_pl ), NULL );
+      }
 
 Figure 7: Send message without buffer copy.
 
@@ -474,12 +491,12 @@ to the constructor.
 
 ::
 
-     #include <ricxfcpp/Jhash>
+      #include <ricxfcpp/Jhash>
 
-     std::string jstring = "{ \\"tag\\": \\"Hello World\\" }";
-     Jhash*  jh;
+      std::string jstring = "{ \\"tag\\": \\"Hello World\\" }";
+      Jhash*  jh;
 
-     jh =  new Jhash( jstring.c_str() );
+      jh =  new Jhash( jstring.c_str() );
 
 Figure 8: The creation of the Jhash object.
 
@@ -496,44 +513,44 @@ this representation. The approach taken by Jhash is a
 "directory view" approach, where the "current directory," or
 current *blob,* limits the scope of visible fields.
 
-As an example, the json contained in figure jblob_fig,
-contains a "root" blob and two *sub-blobs* (address and
-lease_info).
+As an example, the json contained in figure 9, contains a
+"root" blob and two *sub-blobs* (address and lease_info).
 
-::
 
-     {
-         "lodge_name": "Water Buffalo Lodge 714",
-         "member_count": 41,
-         "grand_poobah": "Larry K. Slate",
-         "attendance":   [ 23, 14, 41, 38, 24 ],
-         "address": {
-             "street":    "16801 Stonway Lane",
-             "suite":     null,
-             "city":      "Bedrock",
-             "post_code": "45701"
-         },
-         "lease_info": {
-             "owner":    "Stonegate Properties",
-             "amount":   216.49,
-             "due":      "monthly",
-             "contact:"  "Kyle Limestone"
-         }
-     }
+::
 
-Figure 9: Sample json with a root and too blobs.
+      {
+          "lodge_name": "Water Buffalo Lodge 714",
+          "member_count": 41,
+          "grand_poobah": "Larry K. Slate",
+          "attendance":   [ 23, 14, 41, 38, 24 ],
+          "address": {
+              "street":    "16801 Stonway Lane",
+              "suite":     null,
+              "city":      "Bedrock",
+              "post_code": "45701"
+          },
+          "lease_info": {
+              "owner":    "Stonegate Properties",
+              "amount":   216.49,
+              "due":      "monthly",
+              "contact:"  "Kyle Limestone"
+          }
+      }
+
+Figure 9: Sample json with a root and two blobs.
 
 Upon creation of the Jhash object, the *root* fields,
 ``lodge_name,`` ``member_count,`` and ``grand_poobah`` are
 immediately available. The fields in the *sub-blobs* are
-avalable only when the correct blob is selected. The code
+available only when the correct blob is selected. The code
 sample in figure 10 illustrates how a *sub-blob* is selected.
 
 ::
 
-     jh->Set_blob( (char *) "address" );     // select address
-     jh->Unset_blob();                       // return to root
-     jh->Set_blob( (char *) "lease_info" );  // slect the lease blob
+      jh->Set_blob( (char *) "address" );     // select address
+      jh->Unset_blob();                       // return to root
+      jh->Set_blob( (char *) "lease_info" );  // select the lease blob
 
 Figure 10: Blob selection example.
 
@@ -560,36 +577,36 @@ extracted:
 
 ::
 
-     std::string String( const char* name );
-     float Value( const char* name );
-     bool Bool( const char* name );
+      std::string String( const char* name );
+      float Value( const char* name );
+      bool Bool( const char* name );
 
 
-Each of these funcitons returns the value associated with the
+Each of these functions returns the value associated with the
 field with the given *name.* If the value is missing, the
 following default values are returned:
 
 
-      .. list-table::
-        :widths: 15,80
-        :header-rows: 0
-        :class: borderless
+       .. list-table::
+         :widths: 15,80
+         :header-rows: 0
+         :class: borderless
 
-        * - **String**
-          -
-            An empty string (.e.g "").
+         * - **String**
+           -
+             An empty string (.e.g "").
 
-            |
+             |
 
-        * - **Value**
-          -
-            Zero (e.g 0.0)
+         * - **Value**
+           -
+             Zero (e.g 0.0)
 
-            |
+             |
 
-        * - **bool**
-          -
-            false
+         * - **bool**
+           -
+             false
 
 
 
@@ -605,17 +622,17 @@ Two functions allow the developer to determine whether or not
 a field is included in the json. Both of these functions work
 on the current *blob,* therefore it is important to ensure
 that the correct blob is selected before using either of
-these funcitons. The prototpyes for the ``Exists`` and
+these functions. The prototypes for the ``Exists`` and
 ``Missing`` functions are below:
 
 ::
 
-     bool Exists( const char* name );
-     bool Is_missing( const char* name );
+      bool Exists( const char* name );
+      bool Is_missing( const char* name );
 
 The ``Exists`` function returns *true* if the field name
-exists in the json and *false* otherwise. Conversly, the
-``Missing`` funciton returns *true* when the field name does
+exists in the json and *false* otherwise. Conversely, the
+``Missing`` function returns *true* when the field name does
 not exist in the json.
 
 
@@ -630,13 +647,13 @@ for these functions:
 
 ::
 
-     bool Is_bool( const char* name );
-     bool Is_null( const char* name );
-     bool Is_string( const char* name );
-     bool Is_value( const char* name );
+      bool Is_bool( const char* name );
+      bool Is_null( const char* name );
+      bool Is_string( const char* name );
+      bool Is_value( const char* name );
 
 
-Each of these funcitons return *true* if the field with the
+Each of these functions return *true* if the field with the
 given name is of the type being tested for.
 
 
@@ -652,16 +669,16 @@ based functions are below:
 
 ::
 
-     int Array_len( const char* name );
+      int Array_len( const char* name );
 
-     bool Is_bool_ele( const char* name, int eidx );
-     bool Is_null_ele( const char* name, int eidx );
-     bool Is_string_ele( const char* name, int eidx );
-     bool Is_value_ele( const char* name, int eidx );
+      bool Is_bool_ele( const char* name, int eidx );
+      bool Is_null_ele( const char* name, int eidx );
+      bool Is_string_ele( const char* name, int eidx );
+      bool Is_value_ele( const char* name, int eidx );
 
-     bool Bool_ele( const char* name, int eidx );
-     std::string String_ele( const char* name, int eidx );
-     float Value_ele( const char* name, int eidx );
+      bool Bool_ele( const char* name, int eidx );
+      std::string String_ele( const char* name, int eidx );
+      float Value_ele( const char* name, int eidx );
 
 
 For each of these functions the ``eidx`` is the zero based
@@ -671,54 +688,249 @@ element index which is to be tested or selected.
 Arrays of Blobs
 ---------------
 
-An array containing blobs, rather than simiple field value
+An array containing blobs, rather than simple field value
 pairs, the blob must be selected prior to using it, just as a
 sub-blob needed to be selected. The ``Set_blob_ele`` function
 is used to do this and has the following prototype:
 
 ::
 
-     bool Set_blob_ele( const char* name, int eidx );
+      bool Set_blob_ele( const char* name, int eidx );
 
 
-As with selecting a sub-blob, an unset must be preformed
+As with selecting a sub-blob, an unset must be performed
 before selecting the next blob. Figure 11 illustrates how
 these functions can be used to read and print values from the
 json in figure 12.
 
 ::
 
-     "members": [
-         { "name": "Fred Flinstone", "member_num": 42 },
-         { "name": "Barney Rubble", "member_num": 48 },
-         { "name": "Larry K Slate", "member_num": 22 },
-         { "name": "Kyle Limestone", "member_num": 49 }
-     ]
+      "members": [
+          { "name": "Fred Flinstone", "member_num": 42 },
+          { "name": "Barney Rubble", "member_num": 48 },
+          { "name": "Larry K Slate", "member_num": 22 },
+          { "name": "Kyle Limestone", "member_num": 49 }
+      ]
 
 Figure 11: Json array containing blobs.
 
 
 ::
 
-     std::string mname;
-     float mnum;
-     int len;
+      std::string mname;
+      float mnum;
+      int len;
 
-     len = jh->Array_len( (char *) "members" );
-     for( i = 0; i < len; i++ ) {
-         jh->Set_blob_ele( (char *) "members", i );  // select blob
+      len = jh->Array_len( (char *) "members" );
+      for( i = 0; i < len; i++ ) {
+          jh->Set_blob_ele( (char *) "members", i );  // select blob
 
-         mname = jh->String( (char *) "name" );      // read values
-         mnum = jh->Value( (char *) "member_num" );
-         fprintf( stdout, "%s is member %d\\n", mname.c_str(), (int) mnum );
+          mname = jh->String( (char *) "name" );      // read values
+          mnum = jh->Value( (char *) "member_num" );
+          fprintf( stdout, "%s is member %d\\n", mname.c_str(), (int) mnum );
 
-         jh->Unset_blob();                           // back to root
-     }
+          jh->Unset_blob();                           // back to root
+      }
 
 Figure 12: Code to process the array of blobs.
 
 
 
+ALARM MANAGER INTERFACE
+=======================
+
+The C++ framework provides an API which allows the xAPP to
+easily construct and generate alarm messages. Alarm messages
+are a special class of RMR message, allocated in a similar
+fashion as an RMR message through the framework's
+``Alloc_alarm()`` function.
+
+The API consists of the following function types:
+
+
+       .. list-table::
+         :widths: auto
+         :header-rows: 0
+         :class: borderless
+
+         * - **Raise**
+           -
+             Cause the alarm to be assigned a severity and and sent via
+             RMR message to the alarm collector process.
+
+
+             |
+
+         * - **Clear**
+           -
+             Cause a clear message to be sent to the alarm collector.
+
+
+             |
+
+         * - **Raise Again**
+           -
+             Cause a clear followed by a raise message to be sent to
+             the alarm collector.
+
+
+
+
+
+Allocating Alarms
+-----------------
+
+The ``xapp`` function provided by the framework is used to
+create an alarm object. Once the xAPP has an alarm object it
+can be used to send one, or more, alarm messages to the
+collector.
+
+The allocation function has three prototypes which allow the
+xAPP to create an alarm with an initial set of information as
+is appropriate. The following are the prototypes for the
+allocate functions:
+
+
+::
+
+    std::unique_ptr<xapp::Alarm> Alloc_alarm( );
+    std::unique_ptr<xapp::Alarm> Alloc_alarm( std::string meid );
+    std::unique_ptr<xapp::Alarm> Alloc_alarm( int prob_id, std::string meid );
+
+Figure 13: Alarm allocation prototypes.
+
+Each of the allocation functions returns a unique pointer to
+the alarm. In the simplest form (1) the alarm is initialised
+with an empty meid (managed element ID) string, and unset
+problem ID (-1). The second prototype allows the xAPP to
+supply the meid, and in the third form both the problem ID
+and the meid are used to initialise the alarm.
+
+
+Raising An Alarm
+----------------
+
+Once an alarm has been allocated, its ``Raise()`` function
+can be used to cause the alarm to be sent to the collector.
+The raise process allows the xAPP to perform the following
+modifications to the alarm before sending the message:
+
+
+   * Set the alarm severity
+
+   * Set the problem ID value
+
+   * Set the alarm information string
+
+   * Set the additional information string
+
+
+The following are the prototypes for the ``Raise()``
+functions of an alarm object: ..... In its simplest form (1)
+the ``Raise()`` function will send the alarm without making
+any changes to the data. The final two forms allow the xAPP
+to supply additional data which is added to the alarm before
+sending the message. Each of the raise functions returns
+``true`` on success and ``false`` if the alarm message could
+not be sent.
+
+
+Severity
+--------
+
+The severity is one of the ``SEV_`` constants listed below.
+These map to alarm collector strings and insulate the xAPP
+from any future alarm collector changes. The specific meaning
+of these severity types are defined by the alarm collector
+and thus no attempt is made to guess what their actual
+meaning is. These constants are available by including
+``alarm.hpp.``
+
+
+   ::
+
+         SEV_MAJOR
+         SEV_MINOR
+         SEV_WARN
+         SEV_DEFAULT
+
+Figure 14: Severity constants available in alarm.hpp.
+
+
+The Problem ID
+--------------
+
+The problem ID is an integer which is assigned by the xAPP.
+The framework makes no attempt to verify that it has been se,
+nor does it attempt to validate the value. If the xAPP does
+not set the value, ``-1`` is used.
+
+
+Information Strings
+-------------------
+
+The two information strings are also xAPP defined and provide
+the information that the xAPP deems necessary and related to
+the alarm. What the collector expects, and how these strings
+are used, is beyond the scope of the framework to describe or
+validate. If not supplied, empty strings are sent in the
+alarm message.
+
+
+Clearing An Alarm
+-----------------
+
+The ``Clear()`` function of an alarm may be used to send a
+clear message. In a manner similar to the ``Raise()``
+functions, the ``Clear()`` functions allow the existing alarm
+data to be sent without change, or for the xAPP to modify the
+data before the message is sent to the collector. The
+following are the prototype for these functions.
+
+::
+
+     bool Clear( );
+     bool Clear( int severity, int problem, std::string info );
+     bool Clear( int severity, int problem, std::string info, std::string addional_info );
+     bool Clear_all( );
+
+
+Figure 15: Clear function prototypes.
+
+Each of the clear functions returns ``true`` on success and
+``false`` if the alarm message could not be sent.
+
+The ``Clear_all()`` function sends a special action code to
+the collector which is assumed to clear all alarms. However,
+it is unknown whether that implies **all** alarms, or all
+alarms matching the ``problem_id,`` or some other
+interpretation. Please consult the alarm collector
+documentation for these specifics.
+
+
+Adjusting Alarm Contents
+------------------------
+
+It might be necessary for the xAPP to adjust the alarm
+contents outside of the scope of the ``Raise()`` function, or
+to adjust data that cannot be manipulated by ``Raise().`` The
+following are the (self explanatory) prototypes for the
+*setter* functions which are available to the xAPP.
+
+
+::
+
+    void Set_additional( std::string new_info );
+    void Set_appid( std::string new_id );
+    void Set_info( std::string new_info );
+    void Set_meid( std::string new_meid );
+    void Set_problem( int new_id );
+    void Set_severity( int new_sev );
+
+Figure 16: Alarm Setters
+
+
+
 EXAMPLE PROGRAMMES
 ==================
 
@@ -762,233 +974,233 @@ omitted. The full code is in the framework repository.
 
 
 
-  ::
-
-    #include <stdio.h>
-    #include <unistd.h>
-    #include <atomic>
-
-    #include "ricxfcpp/xapp.hpp"
-
-    /*
-        Information that the callback needs outside
-        of what is given to it via parms on a call
-        by the framework.
-    */
-    typedef struct {
-        int        vlevel;             // verbosity level
-        bool    forward;            // if true, message is forwarded
-        int        stats_freq;         // header/stats after n messages
-        std::atomic<long>    pcount; // messages processed
-        std::atomic<long>    icount; // messages ignored
-        std::atomic<int>    hdr;    // number of messages before next header
-    } cb_info_t;
-
-    // ----------------------------------------------------------------------
-
-    /*
-        Dump bytes to tty.
-    */
-    void dump( unsigned const char* buf, int len ) {
-        int        i;
-        int        j;
-        char    cheater[17];
-
-        fprintf( stdout, "<RD> 0000 | " );
-        j = 0;
-        for( i = 0; i < len; i++ ) {
-            cheater[j++] =  isprint( buf[i] ) ? buf[i] : '.';
-            fprintf( stdout, "%02x ", buf[i] );
-
-            if( j == 16 ) {
-                cheater[j] = 0;
-                fprintf( stdout, " | %s\\n<RD> %04x | ", cheater, i+1 );
-                j = 0;
-            }
-        }
-
-        if( j ) {
-            i = 16 - (i % 16);
-            for( ; i > 0; i-- ) {
-                fprintf( stdout, "   " );
-            }
-            cheater[j] = 0;
-            fprintf( stdout, " | %s\\n", cheater );
-        }
-    }
-
-    /*
-        generate stats when the hdr count reaches 0. Only one active
-        thread will ever see it be exactly 0, so this is thread safe.
-    */
-    void stats( cb_info_t& cbi ) {
-        int curv;                    // current stat trigger value
-
-        curv = cbi.hdr--;
-
-        if( curv == 0 ) {                    // stats when we reach 0
-            fprintf( stdout, "ignored: %ld  processed: %ld\\n",
-                cbi.icount.load(), cbi.pcount.load() );
-            if( cbi.vlevel > 0 ) {
-                fprintf( stdout, "\\n     %5s %5s %2s %5s\\n",
-                    "MTYPE", "SUBID", "ST", "PLLEN" );
-            }
+   ::
+
+     #include <stdio.h>
+     #include <unistd.h>
+     #include <atomic>
+
+     #include "ricxfcpp/xapp.hpp"
+
+     /*
+         Information that the callback needs outside
+         of what is given to it via parms on a call
+         by the framework.
+     */
+     typedef struct {
+         int        vlevel;             // verbosity level
+         bool    forward;            // if true, message is forwarded
+         int        stats_freq;         // header/stats after n messages
+         std::atomic<long>    pcount; // messages processed
+         std::atomic<long>    icount; // messages ignored
+         std::atomic<int>    hdr;    // number of messages before next header
+     } cb_info_t;
+
+     // ----------------------------------------------------------------------
+
+     /*
+         Dump bytes to tty.
+     */
+     void dump( unsigned const char* buf, int len ) {
+         int        i;
+         int        j;
+         char    cheater[17];
+
+         fprintf( stdout, "<RD> 0000 | " );
+         j = 0;
+         for( i = 0; i < len; i++ ) {
+             cheater[j++] =  isprint( buf[i] ) ? buf[i] : '.';
+             fprintf( stdout, "%02x ", buf[i] );
+
+             if( j == 16 ) {
+                 cheater[j] = 0;
+                 fprintf( stdout, " | %s\\n<RD> %04x | ", cheater, i+1 );
+                 j = 0;
+             }
+         }
 
-            cbi.hdr = cbi.stats_freq;        // reset must be last
-        }
-    }
+         if( j ) {
+             i = 16 - (i % 16);
+             for( ; i > 0; i-- ) {
+                 fprintf( stdout, "   " );
+             }
+             cheater[j] = 0;
+             fprintf( stdout, " | %s\\n", cheater );
+         }
+     }
 
-    void cb1( Message& mbuf, int mtype, int subid, int len,
-                    Msg_component payload,  void* data ) {
-        cb_info_t*    cbi;
-        long total_count;
+     /*
+         generate stats when the hdr count reaches 0. Only one active
+         thread will ever see it be exactly 0, so this is thread safe.
+     */
+     void stats( cb_info_t& cbi ) {
+         int curv;                    // current stat trigger value
 
-        if( (cbi = (cb_info_t *) data) == NULL ) {
-            return;
-        }
+         curv = cbi.hdr--;
 
-        cbi->pcount++;
-        stats( *cbi );            // gen stats & header if needed
+         if( curv == 0 ) {                    // stats when we reach 0
+             fprintf( stdout, "ignored: %ld  processed: %ld\\n",
+                 cbi.icount.load(), cbi.pcount.load() );
+             if( cbi.vlevel > 0 ) {
+                 fprintf( stdout, "\\n     %5s %5s %2s %5s\\n",
+                     "MTYPE", "SUBID", "ST", "PLLEN" );
+             }
 
-        if( cbi->vlevel > 0 ) {
-            fprintf( stdout, "<RD> %-5d %-5d %02d %-5d \\n",
-                    mtype, subid, mbuf.Get_state(), len );
+             cbi.hdr = cbi.stats_freq;        // reset must be last
+         }
+     }
 
-            if( cbi->vlevel > 1 ) {
-                dump(  payload.get(), len > 64 ? 64 : len );
-            }
-        }
+     void cb1( xapp::Message& mbuf, int mtype, int subid, int len,
+                     xapp::Msg_component payload,  void* data ) {
+         cb_info_t*    cbi;
+         long total_count;
 
-        if( cbi->forward ) {
-            // forward with no change to len or payload
-            mbuf.Send_msg( Message::NO_CHANGE, NULL );
-        }
-    }
-
-    /*
-        registered as the default callback; it counts the
-        messages that we aren't giving details about.
-    */
-    void cbd( Message& mbuf, int mtype, int subid, int len,
-                    Msg_component payload,  void* data ) {
-        cb_info_t*    cbi;
-
-        if( (cbi = (cb_info_t *) data) == NULL ) {
-            return;
-        }
-
-        cbi->icount++;
-        stats( *cbi );
+         if( (cbi = (cb_info_t *) data) == NULL ) {
+             return;
+         }
 
-        if( cbi->forward ) {
-            // forward with no change to len or payload
-            mbuf.Send_msg( Message::NO_CHANGE, NULL );
-        }
-    }
-
-    int main( int argc, char** argv ) {
-        std::unique_ptr<Xapp> x;
-        char*    port = (char *) "4560";
-        int ai = 1;                    // arg processing index
-        cb_info_t*    cbi;
-        int        ncb = 0;            // number of callbacks registered
-        int        mtype;
-        int        nthreads = 1;
-
-        cbi = (cb_info_t *) malloc( sizeof( *cbi ) );
-        cbi->pcount = 0;
-        cbi->icount = 0;
-        cbi->stats_freq = 10;
-
-        ai = 1;
-        // very simple flag parsing (no error/bounds checking)
-        while( ai < argc ) {
-            if( argv[ai][0] != '-' )  {        // break on first non-flag
-                break;
-            }
+         cbi->pcount++;
+         stats( *cbi );            // gen stats & header if needed
 
-            // very simple arg parsing; each must be separate -x -y not -xy.
-            switch( argv[ai][1] ) {
-                case 'f':                    // enable packet forwarding
-                    cbi->forward = true;
-                    break;
+         if( cbi->vlevel > 0 ) {
+             fprintf( stdout, "<RD> %-5d %-5d %02d %-5d \\n",
+                     mtype, subid, mbuf.Get_state(), len );
 
-                case 'p':                     // define port
-                    port = argv[ai+1];
-                    ai++;
-                    break;
+             if( cbi->vlevel > 1 ) {
+                 dump(  payload.get(), len > 64 ? 64 : len );
+             }
+         }
 
-                case 's':                        // stats frequency
-                    cbi->stats_freq = atoi( argv[ai+1] );
-                    if( cbi->stats_freq < 5 ) {    // enforce sanity
-                        cbi->stats_freq = 5;
-                    }
-                    ai++;
-                    break;
+         if( cbi->forward ) {
+             // forward with no change to len or payload
+             mbuf.Send_msg( xapp::Message::NO_CHANGE, NULL );
+         }
+     }
 
-                case 't':                        // thread count
-                    nthreads = atoi( argv[ai+1] );
-                    if( nthreads < 1 ) {
-                        nthreads = 1;
-                    }
-                    ai++;
-                    break;
+     /*
+         registered as the default callback; it counts the
+         messages that we aren't giving details about.
+     */
+     void cbd( xapp::Message& mbuf, int mtype, int subid, int len,
+                     xapp::Msg_component payload,  void* data ) {
+         cb_info_t*    cbi;
 
-                case 'v':            // simple verbose bump
-                    cbi->vlevel++;
-                    break;
+         if( (cbi = (cb_info_t *) data) == NULL ) {
+             return;
+         }
 
-                case 'V':            // explicit verbose level
-                    cbi->vlevel = atoi( argv[ai+1] );
-                    ai++;
-                    break;
+         cbi->icount++;
+         stats( *cbi );
 
-                default:
-                    fprintf( stderr, "unrecognised option: %s\\n", argv[ai] );
-                    fprintf( stderr, "usage: %s [-f] [-p port] "
-                                    "[-s stats-freq]  [-t thread-count] "
-                                    "[-v | -V n] msg-type1 ... msg-typen\\n",
-                                    argv[0] );
-                    fprintf( stderr, "\\tstats frequency is based on # of messages received\\n" );
-                    fprintf( stderr, "\\tverbose levels (-V) 0 counts only, "
-                                    "1 message info 2 payload dump\\n" );
-                    exit( 1 );
-            }
+         if( cbi->forward ) {
+             // forward with no change to len or payload
+             mbuf.Send_msg( xapp::Message::NO_CHANGE, NULL );
+         }
+     }
 
-            ai++;
-        }
+     int main( int argc, char** argv ) {
+         std::unique_ptr<Xapp> x;
+         char*    port = (char *) "4560";
+         int ai = 1;                    // arg processing index
+         cb_info_t*    cbi;
+         int        ncb = 0;            // number of callbacks registered
+         int        mtype;
+         int        nthreads = 1;
+
+         cbi = (cb_info_t *) malloc( sizeof( *cbi ) );
+         cbi->pcount = 0;
+         cbi->icount = 0;
+         cbi->stats_freq = 10;
+
+         ai = 1;
+         // very simple flag parsing (no error/bounds checking)
+         while( ai < argc ) {
+             if( argv[ai][0] != '-' )  {        // break on first non-flag
+                 break;
+             }
+
+             // very simple arg parsing; each must be separate -x -y not -xy.
+             switch( argv[ai][1] ) {
+                 case 'f':                    // enable packet forwarding
+                     cbi->forward = true;
+                     break;
+
+                 case 'p':                    // define port
+                     port = argv[ai+1];
+                     ai++;
+                     break;
+
+                 case 's':                        // stats frequency
+                     cbi->stats_freq = atoi( argv[ai+1] );
+                     if( cbi->stats_freq < 5 ) {    // enforce sanity
+                         cbi->stats_freq = 5;
+                     }
+                     ai++;
+                     break;
+
+                 case 't':                        // thread count
+                     nthreads = atoi( argv[ai+1] );
+                     if( nthreads < 1 ) {
+                         nthreads = 1;
+                     }
+                     ai++;
+                     break;
+
+                 case 'v':            // simple verbose bump
+                     cbi->vlevel++;
+                     break;
+
+                 case 'V':            // explicit verbose level
+                     cbi->vlevel = atoi( argv[ai+1] );
+                     ai++;
+                     break;
+
+                 default:
+                     fprintf( stderr, "unrecognised option: %s\\n", argv[ai] );
+                     fprintf( stderr, "usage: %s [-f] [-p port] "
+                                     "[-s stats-freq]  [-t thread-count] "
+                                     "[-v | -V n] msg-type1 ... msg-typen\\n",
+                                     argv[0] );
+                     fprintf( stderr, "\\tstats frequency is based on # of messages received\\n" );
+                     fprintf( stderr, "\\tverbose levels (-V) 0 counts only, "
+                                     "1 message info 2 payload dump\\n" );
+                     exit( 1 );
+             }
+
+             ai++;
+         }
 
-        cbi->hdr = cbi->stats_freq;
-        fprintf( stderr, "<RD> listening on port: %s\\n", port );
+         cbi->hdr = cbi->stats_freq;
+         fprintf( stderr, "<RD> listening on port: %s\\n", port );
 
-        // create xapp, wait for route table if forwarding
-        x = std::unique_ptr<Xapp>( new Xapp( port, cbi->forward ) );
+         // create xapp, wait for route table if forwarding
+         x = std::unique_ptr<Xapp>( new Xapp( port, cbi->forward ) );
 
-        // register callback for each type on the command line
-        while( ai < argc ) {
-            mtype = atoi( argv[ai] );
-            ai++;
-            fprintf( stderr, "<RD> capturing messages for type %d\\n", mtype );
-            x->Add_msg_cb( mtype, cb1, cbi );
-            ncb++;
-        }
+         // register callback for each type on the command line
+         while( ai < argc ) {
+             mtype = atoi( argv[ai] );
+             ai++;
+             fprintf( stderr, "<RD> capturing messages for type %d\\n", mtype );
+             x->Add_msg_cb( mtype, cb1, cbi );
+             ncb++;
+         }
 
-        if( ncb < 1 ) {
-            fprintf( stderr, "<RD> no message types specified on the command line\\n" );
-            exit( 1 );
-        }
+         if( ncb < 1 ) {
+             fprintf( stderr, "<RD> no message types specified on the command line\\n" );
+             exit( 1 );
+         }
 
-        x->Add_msg_cb( x->DEFAULT_CALLBACK, cbd, cbi );        // register default cb
+         x->Add_msg_cb( x->DEFAULT_CALLBACK, cbd, cbi );        // register default cb
 
-        fprintf( stderr, "<RD> starting driver\\n" );
-        x->Run( nthreads );
+         fprintf( stderr, "<RD> starting driver\\n" );
+         x->Run( nthreads );
 
-        // return from run() is not expected, but some compilers might
-        // compilain if there isn't a return value here.
-        return 0;
-    }
+         // return from run() is not expected, but some compilers might
+         // compilain if there isn't a return value here.
+         return 0;
+     }
 
-  Figure 13: Simple callback application.
+   Figure 17: Simple callback application.
 
 
 Callback Receiver
@@ -1010,87 +1222,87 @@ this example as simple as possible, the counters are not
 locked when incremented.
 
 
-  ::
+   ::
 
-    #include <stdio.h>
+     #include <stdio.h>
 
-    #include "ricxfcpp/message.hpp"
-    #include "ricxfcpp/msg_component.hpp"
-    #include "ricxfcpp/xapp.hpp"
+     #include "ricxfcpp/message.hpp"
+     #include "ricxfcpp/msg_component.hpp"
+     #include "ricxfcpp/xapp.hpp"
 
-    // counts; not thread safe
-    long cb1_count = 0;
-    long cb2_count = 0;
-    long cbd_count = 0;
+     // counts; not thread safe
+     long cb1_count = 0;
+     long cb2_count = 0;
+     long cbd_count = 0;
 
-    long cb1_lastts = 0;
-    long cb1_lastc = 0;
+     long cb1_lastts = 0;
+     long cb1_lastc = 0;
 
-    // respond with 2 messages for each type 1 received
-    void cb1( Message& mbuf, int mtype, int subid, int len,
-                Msg_component payload,  void* data ) {
-        long now;
-        long total_count;
+     // respond with 2 messages for each type 1 received
+     void cb1( xapp::Message& mbuf, int mtype, int subid, int len,
+                 xapp::Msg_component payload,  void* data ) {
+         long now;
+         long total_count;
 
-        // illustrate that we can use the same buffer for 2 rts calls
-        mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK1\\n" );
-        mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\\n" );
+         // illustrate that we can use the same buffer for 2 rts calls
+         mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK1\\n" );
+         mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\\n" );
 
-        cb1_count++;
-    }
-
-    // just count messages
-    void cb2( Message& mbuf, int mtype, int subid, int len,
-                Msg_component payload,  void* data ) {
-        cb2_count++;
-    }
-
-    // default to count all unrecognised messages
-    void cbd( Message& mbuf, int mtype, int subid, int len,
-                Msg_component payload,  void* data ) {
-        cbd_count++;
-    }
-
-    int main( int argc, char** argv ) {
-        Xapp* x;
-        char*    port = (char *) "4560";
-        int ai = 1;                            // arg processing index
-        int nthreads = 1;
-
-        // very simple flag processing (no bounds/error checking)
-        while( ai < argc ) {
-            if( argv[ai][0] != '-' )  {
-                break;
-            }
+         cb1_count++;
+     }
 
-            switch( argv[ai][1] ) {            // we only support -x so -xy must be -x -y
-                case 'p':
-                    port = argv[ai+1];
-                    ai++;
-                    break;
+     // just count messages
+     void cb2( xapp::Message& mbuf, int mtype, int subid, int len,
+                 xapp::Msg_component payload,  void* data ) {
+         cb2_count++;
+     }
 
-                case 't':
-                    nthreads = atoi( argv[ai+1] );
-                    ai++;
-                    break;
-            }
+     // default to count all unrecognised messages
+     void cbd( xapp::Message& mbuf, int mtype, int subid, int len,
+                 xapp::Msg_component payload,  void* data ) {
+         cbd_count++;
+     }
 
-            ai++;
-        }
+     int main( int argc, char** argv ) {
+         Xapp* x;
+         char*    port = (char *) "4560";
+         int ai = 1;                            // arg processing index
+         int nthreads = 1;
+
+         // very simple flag processing (no bounds/error checking)
+         while( ai < argc ) {
+             if( argv[ai][0] != '-' )  {
+                 break;
+             }
+
+             switch( argv[ai][1] ) {            // we only support -x so -xy must be -x -y
+                 case 'p':
+                     port = argv[ai+1];
+                     ai++;
+                     break;
+
+                 case 't':
+                     nthreads = atoi( argv[ai+1] );
+                     ai++;
+                     break;
+             }
+
+             ai++;
+         }
 
-        fprintf( stderr, "<XAPP> listening on port: %s\\n", port );
-        fprintf( stderr, "<XAPP> starting %d threads\\n", nthreads );
+         fprintf( stderr, "<XAPP> listening on port: %s\\n", port );
+         fprintf( stderr, "<XAPP> starting %d threads\\n", nthreads );
 
-        x = new Xapp( port, true );
-        x->Add_msg_cb( 1, cb1, NULL );                // register callbacks
-        x->Add_msg_cb( 2, cb2, NULL );
-        x->Add_msg_cb( x->DEFAULT_CALLBACK, cbd, NULL );
+         x = new Xapp( port, true );
+         x->Add_msg_cb( 1, cb1, NULL );                // register callbacks
+         x->Add_msg_cb( 2, cb2, NULL );
+         x->Add_msg_cb( x->DEFAULT_CALLBACK, cbd, NULL );
 
-        x->Run( nthreads );                // let framework drive
-        // control should not return
-    }
+         x->Run( nthreads );                // let framework drive
+         // control should not return
+     }
 
-  Figure 14: Simple callback application.
+   Figure 18: Simple callback application.
 
 
 
@@ -1104,103 +1316,229 @@ checking is skipped, and short cuts have been made in order
 to keep the example small and to the point.
 
 
-  ::
+   ::
+
 
+     #include <stdio.h>
+     #include <string.h>
+     #include <unistd.h>
 
-    #include <stdio.h>
-    #include <string.h>
-    #include <unistd.h>
+     #include <iostream>
+     #include <memory>
 
-    #include <iostream>
-    #include <memory>
+     #include "ricxfcpp/xapp.hpp"
+
+     extern int main( int argc, char** argv ) {
+         std::unique_ptr<Xapp> xfw;
+         std::unique_ptr<xapp::Message> msg;
+         xapp::Msg_component payload;                // special type of unique pointer to the payload
+
+         int    sz;
+         int len;
+         int i;
+         int ai;
+         int response_to = 0;                // max timeout wating for a response
+         char*    port = (char *) "4555";
+         int    mtype = 0;
+         int rmtype;                            // received message type
+         int delay = 1000000;                // mu-sec delay; default 1s
+
+
+         // very simple flag processing (no bounds/error checking)
+         while( ai < argc ) {
+             if( argv[ai][0] != '-' )  {
+                 break;
+             }
+
+             // we only support -x so -xy must be -x -y
+             switch( argv[ai][1] ) {
+                 // delay between messages (mu-sec)
+                 case 'd':
+                     delay = atoi( argv[ai+1] );
+                     ai++;
+                     break;
+
+                 case 'p':
+                     port = argv[ai+1];
+                     ai++;
+                     break;
+
+                 // timeout in seconds; we need to convert to ms for rmr calls
+                 case 't':
+                     response_to = atoi( argv[ai+1] ) * 1000;
+                     ai++;
+                     break;
+             }
+             ai++;
+         }
 
-    #include "ricxfcpp/xapp.hpp"
+         fprintf( stderr, "<XAPP> response timeout set to: %d\\n", response_to );
+         fprintf( stderr, "<XAPP> listening on port: %s\\n", port );
+
+         // get an instance and wait for a route table to be loaded
+         xfw = std::unique_ptr<Xapp>( new Xapp( port, true ) );
+         msg = xfw->Alloc_msg( 2048 );
+
+         for( i = 0; i < 100; i++ ) {
+             mtype++;
+             if( mtype > 10 ) {
+                 mtype = 0;
+             }
+
+             // we'll reuse a received message; get max size
+             sz = msg->Get_available_size();
+
+             // direct access to payload; add something silly
+             payload = msg->Get_payload();
+             len = snprintf( (char *) payload.get(), sz, "This is message %d\\n", i );
+
+             // payload updated in place, prevent copy by passing nil
+             if ( ! msg->Send_msg( mtype, xapp::Message::NO_SUBID,  len, NULL )) {
+                 fprintf( stderr, "<SNDR> send failed: %d\\n", i );
+             }
+
+             // receive anything that might come back
+             msg = xfw->Receive( response_to );
+             if( msg != NULL ) {
+                 rmtype = msg->Get_mtype();
+                 payload = msg->Get_payload();
+                 fprintf( stderr, "got: mtype=%d payload=(%s)\\n",
+                     rmtype, (char *) payload.get() );
+             } else {
+                 msg = xfw->Alloc_msg( 2048 );
+             }
+
+             if( delay > 0 ) {
+                 usleep( delay );
+             }
+         }
+     }
 
-    extern int main( int argc, char** argv ) {
-        std::unique_ptr<Xapp> xfw;
-        std::unique_ptr<Message> msg;
-        Msg_component payload;                // special type of unique pointer to the payload
+   Figure 19: Simple looping sender application.
 
-        int    sz;
-        int len;
-        int i;
-        int ai;
-        int response_to = 0;                // max timeout wating for a response
-        char*    port = (char *) "4555";
-        int    mtype = 0;
-        int rmtype;                            // received message type
-        int delay = 1000000;                // mu-sec delay; default 1s
 
 
-        // very simple flag processing (no bounds/error checking)
-        while( ai < argc ) {
-            if( argv[ai][0] != '-' )  {
-                break;
-            }
+Alarm Example
+-------------
 
-            // we only support -x so -xy must be -x -y
-            switch( argv[ai][1] ) {
-                // delay between messages (mu-sec)
-                case 'd':
-                    delay = atoi( argv[ai+1] );
-                    ai++;
-                    break;
+   This is an extension of a previous example which sends an
+   alarm during initialisation and clears the alarm as soon
+   as messages are being received. It is unknown if this is
+   the type of alarm that is expected at the collector, but
+   illustrates how an alarm is allocated, raised and cleared.
 
-                case 'p':
-                    port = argv[ai+1];
-                    ai++;
-                    break;
 
-                // timeout in seconds; we need to convert to ms for rmr calls
-                case 't':
-                    response_to = atoi( argv[ai+1] ) * 1000;
-                    ai++;
+      ::
+
+
+        #include <stdio.h>
+        #include <string.h>
+        #include <unistd.h>
+
+        #include <iostream>
+        #include <memory>
+
+        #include "ricxfcpp/xapp.hpp"
+        #include "ricxfcpp/alarm.hpp"
+
+        extern int main( int argc, char** argv ) {
+            std::unique_ptr<Xapp> xfw;
+            std::unique_ptr<xapp::Message> msg;
+            xapp::Msg_component payload;                // special type of unique pointer to the payload
+            std::unique_ptr<xapp::Alarm>    alarm;
+
+            bool received = false;                // false until we've received a message
+            int    sz;
+            int len;
+            int i;
+            int ai = 1;
+            int response_to = 0;                // max timeout wating for a response
+            char*    port = (char *) "4555";
+            int    mtype = 0;
+            int rmtype;                            // received message type
+            int delay = 1000000;                // mu-sec delay; default 1s
+
+
+            // very simple flag processing (no bounds/error checking)
+            while( ai < argc ) {
+                if( argv[ai][0] != '-' )  {
                     break;
+                }
+
+                // we only support -x so -xy must be -x -y
+                switch( argv[ai][1] ) {
+                    // delay between messages (mu-sec)
+                    case 'd':
+                        delay = atoi( argv[ai+1] );
+                        ai++;
+                        break;
+
+                    case 'p':
+                        port = argv[ai+1];
+                        ai++;
+                        break;
+
+                    // timeout in seconds; we need to convert to ms for rmr calls
+                    case 't':
+                        response_to = atoi( argv[ai+1] ) * 1000;
+                        ai++;
+                        break;
+                }
+                ai++;
             }
-            ai++;
-        }
 
-        fprintf( stderr, "<XAPP> response timeout set to: %d\\n", response_to );
-        fprintf( stderr, "<XAPP> listening on port: %s\\n", port );
+            fprintf( stderr, "<XAPP> response timeout set to: %d\\n", response_to );
+            fprintf( stderr, "<XAPP> listening on port: %s\\n", port );
 
-        // get an instance and wait for a route table to be loaded
-        xfw = std::unique_ptr<Xapp>( new Xapp( port, true ) );
-        msg = xfw->Alloc_msg( 2048 );
+            // get an instance and wait for a route table to be loaded
+            xfw = std::unique_ptr<Xapp>( new Xapp( port, true ) );
+            msg = xfw->Alloc_msg( 2048 );
 
-        for( i = 0; i < 100; i++ ) {
-            mtype++;
-            if( mtype > 10 ) {
-                mtype = 0;
-            }
 
-            // we'll reuse a received message; get max size
-            sz = msg->Get_available_size();
+            // raise an unavilable alarm which we'll clear on the first recevied message
+            alarm =  xfw->Alloc_alarm( "meid-1234"  );
+            alarm->Raise( xapp::Alarm::SEV_MINOR, 13, "unavailable", "no data recevied" );
 
-            // direct access to payload; add something silly
-            payload = msg->Get_payload();
-            len = snprintf( (char *) payload.get(), sz, "This is message %d\\n", i );
+            for( i = 0; i < 100; i++ ) {
+                mtype++;
+                if( mtype > 10 ) {
+                    mtype = 0;
+                }
 
-            // payload updated in place, prevent copy by passing nil
-            if ( ! msg->Send_msg( mtype, Message::NO_SUBID,  len, NULL )) {
-                fprintf( stderr, "<SNDR> send failed: %d\\n", i );
-            }
+                // we'll reuse a received message; get max size
+                sz = msg->Get_available_size();
 
-            // receive anything that might come back
-            msg = xfw->Receive( response_to );
-            if( msg != NULL ) {
-                rmtype = msg->Get_mtype();
+                // direct access to payload; add something silly
                 payload = msg->Get_payload();
-                fprintf( stderr, "got: mtype=%d payload=(%s)\\n",
-                    rmtype, (char *) payload.get() );
-            } else {
-                msg = xfw->Alloc_msg( 2048 );
-            }
+                len = snprintf( (char *) payload.get(), sz, "This is message %d\\n", i );
+
+                // payload updated in place, prevent copy by passing nil
+                if ( ! msg->Send_msg( mtype, xapp::Message::NO_SUBID,  len, NULL )) {
+                    fprintf( stderr, "<SNDR> send failed: %d\\n", i );
+                }
+
+                // receive anything that might come back
+                msg = xfw->Receive( response_to );
+                if( msg != NULL ) {
+                    if( ! received ) {
+                        alarm->Clear( xapp::Alarm::SEV_MINOR, 13, "messages flowing", "" );                // clear the alarm on first received message
+                        received = true;
+                    }
 
-            if( delay > 0 ) {
-                usleep( delay );
+                    rmtype = msg->Get_mtype();
+                    payload = msg->Get_payload();
+                    fprintf( stderr, "got: mtype=%d payload=(%s)\\n",
+                        rmtype, (char *) payload.get() );
+                } else {
+                    msg = xfw->Alloc_msg( 2048 );
+                }
+
+                if( delay > 0 ) {
+                    usleep( delay );
+                }
             }
         }
-    }
 
-  Figure 15: Simple looping sender application.
+      Figure 20: Simple looping sender application with alarm
+      generation.
 
index 52fe23d..860caf5 100644 (file)
@@ -117,8 +117,8 @@ void stats( cb_info_t& cbi ) {
        }
 }
 
-void cb1( Message& mbuf, int mtype, int subid, int len,
-                               Msg_component payload,  void* data ) {
+void cb1( xapp::Message& mbuf, int mtype, int subid, int len,
+                               xapp::Msg_component payload,  void* data ) {
        cb_info_t*      cbi;
        long total_count;
 
@@ -140,7 +140,7 @@ void cb1( Message& mbuf, int mtype, int subid, int len,
 
        if( cbi->forward ) {
                // forward with no change to len or payload
-               mbuf.Send_msg( Message::NO_CHANGE, NULL );
+               mbuf.Send_msg( xapp::Message::NO_CHANGE, NULL );
        }
 }
 
@@ -148,8 +148,8 @@ void cb1( Message& mbuf, int mtype, int subid, int len,
        registered as the default callback; it counts the
        messages that we aren't giving details about.
 */
-void cbd( Message& mbuf, int mtype, int subid, int len,
-                               Msg_component payload,  void* data ) {
+void cbd( xapp::Message& mbuf, int mtype, int subid, int len,
+                               xapp::Msg_component payload,  void* data ) {
        cb_info_t*      cbi;
 
        if( (cbi = (cb_info_t *) data) == NULL ) {
@@ -161,7 +161,7 @@ void cbd( Message& mbuf, int mtype, int subid, int len,
 
        if( cbi->forward ) {
                // forward with no change to len or payload
-               mbuf.Send_msg( Message::NO_CHANGE, NULL );
+               mbuf.Send_msg( xapp::Message::NO_CHANGE, NULL );
        }
 }
 
@@ -192,7 +192,7 @@ int main( int argc, char** argv ) {
                                cbi->forward = true;
                                break;
 
-                       case 'p':                                       // define port
+                       case 'p':                                       // define port
                                port = argv[ai+1];
                                ai++;
                                break;
index 51b3ba6..5ec8536 100644 (file)
@@ -56,8 +56,8 @@ long cb1_lastts = 0;
 long cb1_lastc = 0;
 
 // respond with 2 messages for each type 1 received
-void cb1( Message& mbuf, int mtype, int subid, int len,
-                       Msg_component payload,  void* data ) {
+void cb1( xapp::Message& mbuf, int mtype, int subid, int len,
+                       xapp::Msg_component payload,  void* data ) {
        long now;
        long total_count;
 
@@ -69,14 +69,14 @@ void cb1( Message& mbuf, int mtype, int subid, int len,
 }
 
 // just count messages
-void cb2( Message& mbuf, int mtype, int subid, int len, 
-                       Msg_component payload,  void* data ) {
+void cb2( xapp::Message& mbuf, int mtype, int subid, int len,
+                       xapp::Msg_component payload,  void* data ) {
        cb2_count++;
 }
 
 // default to count all unrecognised messages
-void cbd( Message& mbuf, int mtype, int subid, int len, 
-                       Msg_component payload,  void* data ) {
+void cbd( xapp::Message& mbuf, int mtype, int subid, int len,
+                       xapp::Msg_component payload,  void* data ) {
        cbd_count++;
 }
 
index 67aa72f..1dc4da3 100644 (file)
@@ -45,8 +45,8 @@
 
 extern int main( int argc, char** argv ) {
        std::unique_ptr<Xapp> xfw;
-       std::unique_ptr<Message> msg;
-       Msg_component payload;                          // special type of unique pointer to the payload
+       std::unique_ptr<xapp::Message> msg;
+       xapp::Msg_component payload;                            // special type of unique pointer to the payload
 
        int     sz;
        int len;
@@ -108,7 +108,7 @@ extern int main( int argc, char** argv ) {
                len = snprintf( (char *) payload.get(), sz, "This is message %d\n", i );
 
                // payload updated in place, prevent copy by passing nil
-               if ( ! msg->Send_msg( mtype, Message::NO_SUBID,  len, NULL )) {
+               if ( ! msg->Send_msg( mtype, xapp::Message::NO_SUBID,  len, NULL )) {
                        fprintf( stderr, "<SNDR> send failed: %d\n", i );
                }
 
diff --git a/src/alarm/CMakeLists.txt b/src/alarm/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2bdde59
--- /dev/null
@@ -0,0 +1,40 @@
+# vim: sw=4 ts=4 noet:
+#
+#==================================================================================
+#   Copyright (c) 2020 Nokia
+#   Copyright (c) 2020 AT&T Intellectual Property.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#==================================================================================
+#
+
+
+# For clarity: this generates object, not a lib as the CM command implies.
+#
+add_library( alarm_objects OBJECT
+       alarm.cpp
+)
+
+target_include_directories (alarm_objects PUBLIC
+       $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+       $<INSTALL_INTERFACE:include>
+       PRIVATE src)
+
+# header files should go into .../include/xfcpp/
+if( DEV_PKG )
+       install( FILES
+               alarm.hpp
+               DESTINATION ${install_inc}
+       )
+endif()
+
diff --git a/src/alarm/alarm.cpp b/src/alarm/alarm.cpp
new file mode 100644 (file)
index 0000000..2648ed1
--- /dev/null
@@ -0,0 +1,460 @@
+// vi: ts=4 sw=4 noet:
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       alarm.cpp
+       Abstract:       This class provides an API to the alarm collector/reporter.
+                               An object is insanced by the user xAPP allowing the xAPP
+                               to send, clear, or resend the alarm as is necessary.
+
+
+       Date:           15 July 2020
+       Author:         E. Scott Daniels
+*/
+
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <rmr/RIC_message_types.h>
+#ifndef RIC_ALARM
+       #define RIC_ALARM 110
+#endif
+
+#include <iostream>
+
+#include "msg_component.hpp"
+#include "message.hpp"
+#include "alarm.hpp"
+
+extern char* __progname;                       // runtime lib supplied since we don't get argv[0]
+
+namespace xapp {
+
+
+
+// ------ private ----------------------------------------------
+
+/*
+       Suss out the alarm target from environment.
+
+       We expect two variables in the environment:
+               ALARM_MGR_SERVICE_NAME
+               ALARM_MGR_SERVICE_PORT
+
+       If name is not given, localhost is assumed. If port is not given
+       then we assume 4560 (the defacto RMR listen port).
+*/
+static std::string endpoint_addr( ) {
+       char*   et;                                                                     // environment token
+       std::string addr = "localhost";
+       std::string port = "4560";
+
+       if( (et = getenv( "ALARM_MGR_SERVICE_NAME" )) != NULL ) {
+               addr = std::string( et );
+       }
+
+       if( (et = getenv( "ALARM_MGR_SERVICE_PORT" )) != NULL ) {
+               port = std::string( et );
+       }
+
+       return addr + ":" + port;
+}
+
+
+/*
+       Return the current time in milliseconds past the UNIX epoch.
+*/
+static long long now( void ) {
+       struct timespec ts;
+       long long       now = 0;
+
+       clock_gettime( CLOCK_REALTIME, &ts );
+       now = (ts.tv_sec * 1000000) + (ts.tv_nsec/1000000);     // convert nano to milli and bang onto seconds
+
+       return now;
+}
+
+
+/*
+       Build the alarm json message with the current data.
+       Returns the length of the payload inserted.
+*/
+int xapp::Alarm::build_alarm( int action_id, xapp::Msg_component payload, int payload_len ) {
+       //char  wbuf[4096];
+       std::string action;
+       int used;
+
+       if( app_id.compare( "" ) == 0 ) {
+               app_id = std::string( __progname );                             // see comment for extern above
+       }
+
+       if( severity.compare( "" ) == 0 ) {
+               Set_severity( Alarm::SEV_WARN );
+       }
+
+       switch( action_id ) {
+               case    Alarm::ACT_CLEAR:
+                       action = "CLEAR";
+                       break;
+
+               case    Alarm::ACT_CLEAR_ALL:
+                       action = "CLEARALL";
+                       break;
+
+               default:
+                       action = "RAISE";
+                       break;
+       }
+
+       //memset( wbuf, 0, sizeof( wbuf ) );
+       //snprintf( wbuf, sizeof( wbuf ),
+       used = snprintf( (char *) payload.get(), payload_len,
+                       "{  "
+                       "\"managedObjectId\": \"%s\", "
+                       "\"applicationId\": \"%s\", "
+                       "\"specificProblem\": %d, "
+                       "\"perceivedSeverity\": \"%s\", "
+                       "\"identifyingInfo\": \"%s\", "
+                       "\"additionalInfo\": \"%s\", "
+                       "\"AlarmAction\": \"%s\", "
+                       "\"AlarmTime\": %lld"
+                       " }",
+
+                       me_id.c_str(),
+                       app_id.c_str(),
+                       problem_id,
+                       severity.c_str(),
+                       info.c_str(),
+                       add_info.c_str(),
+                       action.c_str(),
+                       now()
+       );
+
+       //action = std::string( wbuf );
+       return used;
+}
+
+// --------------- builders/operators  -------------------------------------
+
+/*
+       Create a new message wrapper for an existing RMR msg buffer.
+
+       msg is a message which was allocaed by the framework and thus has the
+       mrc reference embedded.
+*/
+xapp::Alarm::Alarm( std::shared_ptr<Message> msg ) :
+       msg( msg ),
+       endpoint( endpoint_addr() ),
+       whid( -1 ),
+       app_id( "" ),
+       me_id( "" ),
+       problem_id( -1 ),
+       info( "" ),
+       add_info( "" ),
+       action( "" )
+{ /* empty body */ }
+
+/*
+       Parameterised constructor (avoids calling setters after creation).
+*/
+xapp::Alarm::Alarm( std::shared_ptr<Message> msg, int prob_id, std::string meid  ) :
+       msg( msg ),
+       endpoint( endpoint_addr() ),
+       whid( -1 ),
+       app_id( "" ),
+       me_id( meid ),
+       problem_id( prob_id ),
+       info( "" ),
+       add_info( "" ),
+       action( "" )
+{ /* empty body */ }
+
+xapp::Alarm::Alarm( std::shared_ptr<Message> msg, std::string meid  ) :
+       msg( msg ),
+       endpoint( endpoint_addr() ),
+       whid( -1 ),
+       app_id( "" ),
+       me_id( meid ),
+       problem_id( -1 ),
+       info( "" ),
+       add_info( "" ),
+       action( "" )
+{ /* empty body */ }
+
+
+
+// ------------------ copy and move support ---------------------------------
+
+/*
+       Copy builder.  Given a source object instance (soi), create a copy.
+       Creating a copy should be avoided as it can be SLOW!
+*/
+xapp::Alarm::Alarm( const Alarm& soi ) {
+       msg = soi.msg;
+       endpoint = soi.endpoint;
+       whid = soi.whid;
+
+       me_id = soi.me_id;                              // user stuff
+       app_id = soi.app_id;
+       problem_id = soi.problem_id;
+       severity = soi.severity;
+       info = soi.info;
+       add_info = soi.add_info;
+}
+
+/*
+       Assignment operator. Simiolar to the copycat, but "this" object exists and
+       may have data that needs to be released prior to making a copy of the soi.
+*/
+Alarm& xapp::Alarm::operator=( const Alarm& soi ) {
+       if( this != &soi ) {                            // cannot do self assignment
+               msg = soi.msg;
+               endpoint = soi.endpoint;
+               whid = soi.whid;
+
+               me_id = soi.me_id;
+               app_id = soi.app_id;
+               problem_id = soi.problem_id;
+               severity = soi.severity;
+               info = soi.info;
+               add_info = soi.add_info;
+       }
+
+       return *this;
+}
+
+/*
+       Move builder.  Given a source object instance (soi), move the information from
+       the soi ensuring that the destriction of the soi doesn't trash things from
+       under us.
+*/
+xapp::Alarm::Alarm( Alarm&& soi ) {
+       msg = soi.msg;          // capture pointers and copy data before setting soruce things to nil
+       endpoint = soi.endpoint;
+       whid = soi.whid;
+
+       me_id = soi.me_id;
+       app_id = soi.app_id;
+       problem_id = soi.problem_id;
+       severity = soi.severity;
+       info = soi.info;
+       add_info = soi.add_info;
+
+       soi.msg = NULL;         // prevent closing of RMR stuff on soi destroy
+}
+
+/*
+       Move Assignment operator. Move the message data to the existing object
+       ensure the object reference is cleaned up, and ensuring that the source
+       object references are removed.
+*/
+Alarm& xapp::Alarm::operator=( Alarm&& soi ) {
+       if( this != &soi ) {                            // cannot do self assignment
+               // anything that needs to be freed/delted from soi, must be done here
+
+               msg = soi.msg;                  // move pointers and values
+               endpoint = soi.endpoint;
+               whid = soi.whid;
+
+               me_id = soi.me_id;
+               app_id = soi.app_id;
+               problem_id = soi.problem_id;
+               severity = soi.severity;
+               info = soi.info;
+               add_info = soi.add_info;
+
+               soi.msg = NULL;                 // prevent bad things when source is destroyed
+       }
+
+       return *this;
+}
+
+/*
+       Destroyer.
+*/
+xapp::Alarm::~Alarm() {
+
+       msg = NULL;
+}
+
+
+// ---- setters -------------------------------------------------
+
+void xapp::Alarm::Set_meid( std::string new_meid ) {
+       me_id = new_meid;
+}
+
+void xapp::Alarm::Set_severity( int new_sev ) {
+       switch( new_sev ) {
+               case    Alarm::SEV_CRIT:
+                       severity = "CRITICAL";
+                       break;
+
+               case    Alarm::SEV_MAJOR:
+                       severity = "MAJOR";
+                       break;
+
+               case    Alarm::SEV_MINOR:
+                       severity = "MINOR";
+                       break;
+
+               case    Alarm::SEV_WARN:
+                       severity = "WARNING";
+                       break;
+
+               case    Alarm::SEV_CLEAR:
+                       severity = "CLEARED";
+                       break;
+
+               default:
+                       severity = "DEFAULT";
+                       break;
+       }
+}
+
+void xapp::Alarm::Set_appid( std::string new_id ) {
+       app_id = new_id;
+}
+
+void xapp::Alarm::Set_problem( int new_id ) {
+       problem_id = new_id;
+}
+
+void xapp::Alarm::Set_info( std::string new_info ) {
+       info = new_info;
+}
+
+void xapp::Alarm::Set_additional( std::string new_info ) {
+       add_info = new_info;
+}
+
+void xapp::Alarm::Set_whid( int new_whid ) {
+       whid = new_whid;
+}
+
+void xapp::Alarm::Dump() {
+       fprintf( stderr, "Alarm: prob id: %d\n", problem_id );
+       fprintf( stderr, "Alarm: meid: %s\n", me_id.c_str() );
+       fprintf( stderr, "Alarm: app: %s\n", app_id.c_str() );
+       fprintf( stderr, "Alarm: info: %s\n", info.c_str() );
+       fprintf( stderr, "Alarm: ainfo: %s\n", add_info.c_str() );
+}
+
+// ------------------- getters ------------------------------------
+
+/*
+       Return the enpoint address string we have.
+*/
+std::string xapp::Alarm::Get_endpoint( ) {
+       return endpoint;
+}
+
+// ------- message sending ---------------------------------------
+
+/*
+       Send a raise message with the alarm contents unchanged.
+*/
+bool xapp::Alarm::Raise( ) {
+       int used;
+       used = build_alarm( ACT_RAISE, msg->Get_payload(), msg->Get_available_size() );
+       msg->Wormhole_send( whid,  RIC_ALARM, xapp::Message::NO_SUBID, used + 1, NULL );
+}
+
+/*
+       Additional prototypes allow for avoiding some setter calls when raising alarms.
+       Severity is one of our SEV_* constants. Problem is the caller's assigned
+       problem ID. Info and addional_info are user supplied data that is just passed
+       through.
+*/
+bool xapp::Alarm::Raise( int severity, int problem, std::string info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+
+       Raise();
+}
+
+bool xapp::Alarm::Raise( int severity, int problem, std::string info, std::string additional_info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+       this->add_info = additional_info;
+
+       Raise();
+}
+
+/*
+       Send a clear message with the contents of the alarm otherwise unchanged.
+*/
+bool xapp::Alarm::Clear( ) {
+       int used;
+
+       used = build_alarm( ACT_CLEAR, msg->Get_payload(), msg->Get_available_size() );
+       msg->Wormhole_send( whid,  RIC_ALARM, xapp::Message::NO_SUBID, used + 1, NULL );
+}
+
+/*
+       Additional prototypes allow for avoiding some setter calls when raising alarms.
+       Severity is one of our SEV_* constants. Problem is the caller's assigned
+       problem ID. Info and addional_info are user supplied data that is just passed
+       through.
+*/
+bool xapp::Alarm::Clear( int severity, int problem, std::string info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+
+       Clear();
+}
+
+bool xapp::Alarm::Clear( int severity, int problem, std::string info, std::string additional_info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+       this->add_info = additional_info;
+
+       Clear();
+}
+
+
+/*
+       Send a clear-all message. The contents of the alarm are unaffected.
+*/
+bool xapp::Alarm::Clear_all( ) {
+       int used;
+
+       used = build_alarm( ACT_CLEAR_ALL, msg->Get_payload(), msg->Get_available_size() );
+       msg->Wormhole_send( whid,  RIC_ALARM, xapp::Message::NO_SUBID, used + 1, NULL );
+}
+
+
+/*
+       This is a convenience function which sends a clear message followed by a
+       raise message. Alarm contents are not adjusted.
+*/
+bool xapp::Alarm::Raise_again( ) {
+       Clear();
+       Raise();
+}
+
+
+
+} // namespace
diff --git a/src/alarm/alarm.hpp b/src/alarm/alarm.hpp
new file mode 100644 (file)
index 0000000..539e385
--- /dev/null
@@ -0,0 +1,111 @@
+// vi: ts=4 sw=4 noet:
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       alarm.hpp
+       Abstract:       Headers for the alarm class.
+                               This class provides for an alarm API.
+
+       Date:           15 July 2020
+       Author:         E. Scott Daniels
+*/
+
+#ifndef _XAPP_ALARM_HPP
+#define _XAPP_ALARM_HPP
+
+
+#include <iostream>
+#include <string>
+
+#include "msg_component.hpp"
+
+namespace xapp {
+
+// ------------------------------------------------------------------------
+
+class Alarm {
+       private:
+               std::shared_ptr<Message> msg;           // message to send
+               std::shared_ptr<char> psp;                      // shared pointer to the payload to give out
+               std::string endpoint;                           // the ip:port addr:port of the alarm collector
+               int                     whid;
+
+                                                                                       // data for the payload
+               std::string     me_id;                                  // managed element ID
+               std::string app_id;                                     // application ID
+               int                     problem_id;                             // problem ID (specific problem)
+               std::string     severity;                               // SEV_* constants
+               std::string     action;                                 // ACT_* constants
+               std::string info;                                       // info string supplied by user
+               std::string add_info;                           // additional information supplied by user
+
+               int build_alarm( int action_id, xapp::Msg_component payload, int payload_len );
+
+       public:
+               static const int        SEV_CRIT = 1;                   // allow translation to string on send/gen
+               static const int        SEV_MAJOR = 2;
+               static const int        SEV_MINOR = 3;
+               static const int        SEV_WARN = 4;
+               static const int        SEV_CLEAR = 5;
+               static const int        SEV_DEFAULT = 6;
+
+               static const int        ACT_RAISE = 1;                  // action const map to alarm manager strings
+               static const int        ACT_CLEAR = 2;
+               static const int        ACT_CLEAR_ALL = 3;
+
+               Alarm( std::shared_ptr<Message> msg );          // builders
+               Alarm( std::shared_ptr<Message> msg, std::string meid  );
+               Alarm( std::shared_ptr<Message> msg, int prob_id, std::string meid  );
+
+               Alarm( const Alarm& soi );                                      // copy to newly created instance
+               Alarm& operator=( const Alarm& soi );           // copy operator
+               Alarm( Alarm&& soi );                                           // mover
+               Alarm& operator=( Alarm&& soi );                        // move operator
+               ~Alarm();                                                                       // destroyer
+
+
+               std::string Get_endpoint( );
+
+               void Set_additional( std::string new_info );
+               void Set_appid( std::string new_id );
+               void Set_info( std::string new_info );
+               void Set_meid( std::string new_meid );
+               void Set_problem( int new_id );
+               void Set_severity( int new_sev );
+               void Set_whid( int whid );
+
+
+               bool Raise( );
+               bool Raise( int severity, int problem, std::string info );
+               bool Raise( int severity, int problem, std::string info, std::string addional_info );
+               bool Raise_again( );
+
+               bool Clear( );
+               bool Clear( int severity, int problem, std::string info );
+               bool Clear( int severity, int problem, std::string info, std::string addional_info );
+               bool Clear_all( );
+
+
+               void Dump();
+};
+
+} // namespace
+
+#endif
index ad0bd9c..df95e13 100644 (file)
 #include "jwrapper.h"
 #include "jhash.hpp"
 
+
+namespace xapp {
+
+
 // ------------------------------------------------------------------------
 
 
@@ -44,7 +48,7 @@
        after which the functions provided by the class can be used to
        suss out the values.
 */
-Jhash::Jhash( const char* jbuf ) :
+xapp::Jhash::Jhash( const char* jbuf ) :
        master_st( NULL ),
        st( jw_new( jbuf ) )
 { /* empty body */ }
@@ -79,7 +83,7 @@ Jhash& Jhash::operator=( Jhash&& soi ) {
 /*
        Blow it away.
 */
-Jhash::~Jhash() {
+xapp::Jhash::~Jhash() {
        if( master_st != NULL ) {               // revert blob set if needed
                st = master_st;
        }
@@ -106,7 +110,7 @@ Jhash::~Jhash() {
        overlays with the named root; unset needs only to be called to
        return to the top level.
 */
-bool Jhash::Set_blob( const char* name ) {
+bool xapp::Jhash::Set_blob( const char* name ) {
        void*   bst;                                            // blob symbol table
 
        if( master_st == NULL ) {                       // must capture master
@@ -124,7 +128,7 @@ bool Jhash::Set_blob( const char* name ) {
 /*
        Return the suss root (blob root) to the root of the symtab.
 */
-void Jhash::Unset_blob( ) {
+void xapp::Jhash::Unset_blob( ) {
        if( master_st != NULL ) {
                st = master_st;
        }
@@ -138,14 +142,14 @@ void Jhash::Unset_blob( ) {
        Right now we don't have much to work with other than checking for a
        nil table.
 */
-bool Jhash::Parse_errors( ) {
+bool xapp::Jhash::Parse_errors( ) {
        return st == NULL;
 }
 
 /*
        Dump the selected blob as much as we can.
 */
-void Jhash::Dump() {
+void xapp::Jhash::Dump() {
        jw_dump( st );
 }
 
@@ -155,19 +159,19 @@ void Jhash::Dump() {
        These funcitons return true if the named object in the current blob
        is the indicated type
 */
-bool Jhash::Is_value( const char* name ) {
+bool xapp::Jhash::Is_value( const char* name ) {
        return jw_is_value( st, name ) == 1;
 }
 
-bool Jhash::Is_bool( const char* name ) {
+bool xapp::Jhash::Is_bool( const char* name ) {
        return jw_is_bool( st, name ) == 1;
 }
 
-bool Jhash::Is_null( const char* name ) {
+bool xapp::Jhash::Is_null( const char* name ) {
        return jw_is_null( st, name ) == 1;
 }
 
-bool Jhash::Is_string( const char* name ) {
+bool xapp::Jhash::Is_string( const char* name ) {
        return jw_is_string( st, name ) == 1;
 }
 
@@ -175,19 +179,19 @@ bool Jhash::Is_string( const char* name ) {
        These functions return true if the indicated element in the array
        <name> is the indicated type.
 */
-bool Jhash::Is_string_ele( const char* name, int eidx ) {
+bool xapp::Jhash::Is_string_ele( const char* name, int eidx ) {
        return jw_is_string_ele( st, name, eidx ) == 1;
 }
 
-bool Jhash::Is_value_ele( const char* name, int eidx ) {
+bool xapp::Jhash::Is_value_ele( const char* name, int eidx ) {
        return jw_is_value_ele( st, name, eidx ) == 1;
 }
 
-bool Jhash::Is_bool_ele( const char* name, int eidx ) {
+bool xapp::Jhash::Is_bool_ele( const char* name, int eidx ) {
        return jw_is_bool_ele( st, name, eidx ) == 1;
 }
 
-bool Jhash::Is_null_ele( const char* name, int eidx ) {
+bool xapp::Jhash::Is_null_ele( const char* name, int eidx ) {
        return jw_is_null_ele( st, name, eidx ) == 1;
 }
 
@@ -196,14 +200,14 @@ bool Jhash::Is_null_ele( const char* name, int eidx ) {
 /*
        Returns true if the named element is in the hash.
 */
-bool Jhash::Exists( const char* name ) {
+bool xapp::Jhash::Exists( const char* name ) {
        return jw_exists( st, name ) == 1;
 }
 
 /*
        Returns true if the named element is not in the hash.
 */
-bool Jhash::Is_missing( const char* name ) {
+bool xapp::Jhash::Is_missing( const char* name ) {
        return jw_missing( st, name ) == 1;
 }
 
@@ -215,7 +219,7 @@ bool Jhash::Is_missing( const char* name ) {
        Symtab saves bool values as 1 for true and doesn't provide a bool fetch
        function. So, fetch the value and return true if it is 1.
 */
-bool Jhash::Bool( const char* name ) {
+bool xapp::Jhash::Bool( const char* name ) {
        int v;
        v = (int) jw_value( st, name );
        return v == 1;
@@ -225,7 +229,7 @@ bool Jhash::Bool( const char* name ) {
        Returns a C++ string to the named object; If the element is not
        in the hash an empty string is returned.
 */
-std::string Jhash::String( const char* name ) {
+std::string xapp::Jhash::String( const char* name ) {
        std::string rv = "";
        char*   hashv;
 
@@ -241,7 +245,7 @@ std::string Jhash::String( const char* name ) {
        Returns the value assocated with the named object; If the element is not
        in the hash 0 is returned.
 */
-double Jhash::Value( const char* name ) {
+double xapp::Jhash::Value( const char* name ) {
        return jw_value( st, name );
 }
 
@@ -250,7 +254,7 @@ double Jhash::Value( const char* name ) {
 /*
        Return the length of the named array, or -1 if it doesn't exist.
 */
-int Jhash::Array_len( const char* name ) {
+int xapp::Jhash::Array_len( const char* name ) {
        return jw_array_len( st, name );
 }
 
@@ -258,7 +262,7 @@ int Jhash::Array_len( const char* name ) {
 /*
        Sets the blob in the array <name>[eidx] to the current reference blob.
 */
-bool Jhash::Set_blob_ele( const char* name, int eidx ) {
+bool xapp::Jhash::Set_blob_ele( const char* name, int eidx ) {
        void*   bst;
 
        if( (bst = jw_obj_ele( st, name, eidx )) != NULL ) {
@@ -275,7 +279,7 @@ bool Jhash::Set_blob_ele( const char* name, int eidx ) {
 /*
        Return the string at index eidx in the array <name>.
 */
-std::string Jhash::String_ele( const char* name, int eidx ) {
+std::string xapp::Jhash::String_ele( const char* name, int eidx ) {
        std::string rv = "";
        char*   hashv;
 
@@ -289,14 +293,17 @@ std::string Jhash::String_ele( const char* name, int eidx ) {
 /*
        Return the value at index eidx in the array <name>.
 */
-double Jhash::Value_ele( const char* name, int eidx ) {
+double xapp::Jhash::Value_ele( const char* name, int eidx ) {
        return jw_value_ele( st, name, eidx );
 }
 
 /*
        Return the bool value at index eidx in the array <name>.
 */
-bool Jhash::Bool_ele( const char* name, int eidx ) {
+bool xapp::Jhash::Bool_ele( const char* name, int eidx ) {
        return jw_bool_ele( st, name, eidx ) == 1;
 }
 
+
+
+} // namespace
index 2963610..6ba1e50 100644 (file)
@@ -34,6 +34,8 @@
 
 #include <string>
 
+namespace xapp {
+
 // ------------------------------------------------------------------------
 
 class Jhash {
@@ -83,4 +85,6 @@ class Jhash {
 };
 
 
+
+} // namespace
 #endif
index d4d697d..9fd603f 100644 (file)
@@ -30,8 +30,8 @@
 #include <rmr/rmr.h>
 
 #include "message.hpp"
-//class Messenger;
 
+namespace xapp {
 
 /*
        Builder.
@@ -49,10 +49,12 @@ Callback::Callback( user_callback ufun, void* data ) {              // builder
 /*
        Drive_cb will invoke the callback and pass along the stuff passed here.
 */
-void Callback::Drive_cb( Message& m ) {
+void xapp::Callback::Drive_cb( Message& m ) {
        if( user_fun != NULL ) {
                user_fun( m, m.Get_mtype(), m.Get_subid(), m.Get_len(), m.Get_payload(),  udata );
        }
 }
 
 
+
+} // namespace
index b8e9dfa..0c892a8 100644 (file)
 
 #include <memory>
 
+#include "msg_component.hpp"
+
+namespace xapp {
+
+
 class Messenger;
 class Message;
-#include "message.hpp"
 
-typedef void(*user_callback)( Message& m, int mtype, int subid, int payload_len, Msg_component payload, void* usr_data );
+typedef void(*user_callback)( xapp::Message& m, int mtype, int subid, int payload_len, xapp::Msg_component payload, void* usr_data );
 
 class Callback {
 
@@ -48,5 +52,7 @@ class Callback {
                void Drive_cb( Message& m );                                                    // invoker
 };
 
+} // namespace
 
 #endif
+
index 1083293..2156ad3 100644 (file)
@@ -38,6 +38,9 @@
 
 #include "messenger.hpp"
 
+namespace xapp {
+
+
 /*
        This is the default health check function that we provide (user
        may override it).  It will respond to health check messages by
@@ -52,3 +55,6 @@ void Health_ck_cb( Message& mbuf, int mtype, int sid, int len, Msg_component pay
        snprintf( (char* ) response, sizeof( response ), "OK\n" );
        mbuf.Send_response( RIC_HEALTH_CHECK_RESP, sid, strlen( (char *) response )+1, response );
 }
+
+
+} // namespace
index 2e96003..7f9d1ad 100644 (file)
 #ifndef _DEF_CB_H
 #define _DEF_CB_H
 
+namespace xapp {
 
 void Health_ck_cb( Message& mbuf, int mtype, int sid, int len, Msg_component payload, void* data );
 
 
+
+} // namespace
+
 #endif
index 30a0fbc..41f5a78 100644 (file)
 
 #include "message.hpp"
 
+namespace xapp {
+
+
+
 // --------------- private ------------------------------------------------
 
 // --------------- builders/operators  -------------------------------------
 /*
        Create a new message wrapper for an existing RMR msg buffer.
 */
-Message::Message( rmr_mbuf_t* mbuf, void* mrc ) {
+xapp::Message::Message( rmr_mbuf_t* mbuf, void* mrc ) {
        this->mrc = mrc;                        // the message router context for sends
        this->mbuf = mbuf;
 }
 
-Message::Message( void* mrc, int payload_len ) {
+xapp::Message::Message( void* mrc, int payload_len ) {
        this->mrc = mrc;
        this->mbuf = rmr_alloc_msg( mrc, payload_len );
 }
@@ -62,29 +66,29 @@ Message::Message( void* mrc, int payload_len ) {
        Copy builder.  Given a source object instance (soi), create a copy.
        Creating a copy should be avoided as it can be SLOW!
 */
-Message::Message( const Message& soi ) {
+xapp::Message::Message( const Message& soi ) {
        int payload_size;
 
        mrc = soi.mrc;
        payload_size = rmr_payload_size( soi.mbuf );            // rmr can handle a nil pointer
-       mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );      
+       mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );
 }
 
 /*
        Assignment operator. Simiolar to the copycat, but "this" object exists and
        may have data that needs to be released prior to making a copy of the soi.
 */
-Message& Message::operator=( const Message& soi ) {
+Message& xapp::Message::operator=( const Message& soi ) {
        int     payload_size;
 
        if( this != &soi ) {                            // cannot do self assignment
                if( mbuf != NULL ) {
                        rmr_free_msg( mbuf );           // release the old one so we don't leak
                }
-       
+
                payload_size = rmr_payload_size( soi.mbuf );            // rmr can handle a nil pointer
                mrc = soi.mrc;
-               mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );      
+               mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );
        }
 
        return *this;
@@ -95,7 +99,7 @@ Message& Message::operator=( const Message& soi ) {
        the soi ensuring that the destriction of the soi doesn't trash things from
        under us.
 */
-Message::Message( Message&& soi ) {
+xapp::Message::Message( Message&& soi ) {
        mrc = soi.mrc;
        mbuf = soi.mbuf;
 
@@ -108,12 +112,12 @@ Message::Message( Message&& soi ) {
        ensure the object reference is cleaned up, and ensuring that the source
        object references are removed.
 */
-Message& Message::operator=( Message&& soi ) {
+Message& xapp::Message::operator=( Message&& soi ) {
        if( this != &soi ) {                            // cannot do self assignment
                if( mbuf != NULL ) {
                        rmr_free_msg( mbuf );           // release the old one so we don't leak
                }
-       
+
                mrc = soi.mrc;
                mbuf = soi.mbuf;
 
@@ -128,7 +132,7 @@ Message& Message::operator=( Message&& soi ) {
 /*
        Destroyer.
 */
-Message::~Message() {
+xapp::Message::~Message() {
        if( mbuf != NULL ) {
                rmr_free_msg( mbuf );
        }
@@ -147,7 +151,7 @@ Message::~Message() {
        This function will return a NULL pointer if malloc fails.
 */
 //char* Message::Copy_payload( ){
-std::unique_ptr<unsigned char> Message::Copy_payload( ){
+std::unique_ptr<unsigned char> xapp::Message::Copy_payload( ){
        unsigned char*  new_payload = NULL;
 
        if( mbuf != NULL ) {
@@ -161,7 +165,7 @@ std::unique_ptr<unsigned char> Message::Copy_payload( ){
 /*
        Makes a copy of the MEID and returns a smart pointer to it.
 */
-std::unique_ptr<unsigned char> Message::Get_meid(){
+std::unique_ptr<unsigned char> xapp::Message::Get_meid(){
        unsigned char* m = NULL;
 
        m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_MEID );
@@ -176,11 +180,11 @@ std::unique_ptr<unsigned char> Message::Get_meid(){
        If mbuf isn't valid (nil, or message has a broken header) the return
        will be -1.
 */
-int Message::Get_available_size(){
+int xapp::Message::Get_available_size(){
        return rmr_payload_size( mbuf );                // rmr can handle a nil pointer
 }
 
-int    Message::Get_mtype(){
+int    xapp::Message::Get_mtype(){
        int rval = INVALID_MTYPE;
 
        if( mbuf != NULL ) {
@@ -193,7 +197,7 @@ int Message::Get_mtype(){
 /*
        Makes a copy of the source field and returns a smart pointer to it.
 */
-std::unique_ptr<unsigned char> Message::Get_src(){
+std::unique_ptr<unsigned char> xapp::Message::Get_src(){
        unsigned char* m = NULL;
 
        m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_SRC );
@@ -206,7 +210,7 @@ std::unique_ptr<unsigned char> Message::Get_src(){
        return std::unique_ptr<unsigned char>( m );
 }
 
-int    Message::Get_state( ){
+int    xapp::Message::Get_state( ){
        int state = INVALID_STATUS;
 
        if( mbuf != NULL ) {
@@ -216,7 +220,7 @@ int Message::Get_state( ){
        return state;
 }
 
-int    Message::Get_subid(){
+int    xapp::Message::Get_subid(){
        int     rval = INVALID_SUBID;
 
        if( mbuf != NULL ) {
@@ -230,7 +234,7 @@ int Message::Get_subid(){
        Return the amount of the payload (bytes) which is used. See
        Get_available_size() to get the total usable space in the payload.
 */
-int    Message::Get_len(){
+int    xapp::Message::Get_len(){
        int rval = 0;
 
        if( mbuf != NULL ) {
@@ -248,7 +252,7 @@ int Message::Get_len(){
        length by calling Message:Get_available_size(), and ensuring that
        writing beyond the indicated size does not happen.
 */
-Msg_component Message::Get_payload(){
+Msg_component xapp::Message::Get_payload(){
        if( mbuf != NULL ) {
                return std::unique_ptr<unsigned char, unfreeable>( mbuf->payload );
        }
@@ -256,25 +260,25 @@ Msg_component Message::Get_payload(){
        return NULL;
 }
 
-void Message::Set_meid( std::shared_ptr<unsigned char> new_meid ) {
+void xapp::Message::Set_meid( std::shared_ptr<unsigned char> new_meid ) {
        if( mbuf != NULL ) {
                rmr_str2meid( mbuf, (unsigned char *) new_meid.get() );
        }
 }
 
-void Message::Set_mtype( int new_type ){
+void xapp::Message::Set_mtype( int new_type ){
        if( mbuf != NULL ) {
                mbuf->mtype = new_type;
        }
 }
 
-void Message::Set_len( int new_len ){
+void xapp::Message::Set_len( int new_len ){
        if( mbuf != NULL  && new_len >= 0 ) {
                mbuf->len = new_len;
        }
 }
 
-void Message::Set_subid( int new_subid ){
+void xapp::Message::Set_subid( int new_subid ){
        if( mbuf != NULL ) {
                mbuf->sub_id = new_subid;
        }
@@ -288,7 +292,7 @@ void Message::Set_subid( int new_subid ){
        failed with a retry and thus is ready to be processed by RMR.
        Exposed to the user, but not expected to be frequently used.
 */
-bool Message::Send( ) {
+bool xapp::Message::Send( ) {
        bool state = false;
 
        if( mbuf != NULL ) {
@@ -303,7 +307,7 @@ bool Message::Send( ) {
        Similar to Send(), this assumes that the message is already set up and this is a retry.
        Exposed to the user, but not expected to be frequently used.
 */
-bool Message::Reply( ) {
+bool xapp::Message::Reply( ) {
        bool state = false;
 
        if( mbuf != NULL ) {
@@ -325,7 +329,7 @@ bool Message::Reply( ) {
 
        This is public, but most users should use Send_msg or Send_response functions.
 */
-bool Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype ) {
+bool xapp::Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype, rmr_whid_t whid ) {
        bool state = false;
 
        if( mbuf != NULL ) {
@@ -349,10 +353,18 @@ bool Message::Send( int mtype, int subid, int payload_len, unsigned char* payloa
                        memcpy( mbuf->payload, payload, mbuf->len );
                }
 
-               if( stype == RESPONSE ) {
-                       mbuf = rmr_rts_msg( mrc, mbuf );
-               } else {
-                       mbuf = rmr_send_msg( mrc, mbuf );
+               switch( stype ) {
+                       case RESPONSE:
+                               mbuf = rmr_rts_msg( mrc, mbuf );
+                               break;
+
+                       case MESSAGE:
+                               mbuf = rmr_send_msg( mrc, mbuf );
+                               break;
+
+                       case WORMHOLE_MSG:
+                               mbuf = rmr_wh_send_msg( mrc, whid,  mbuf );
+                               break;
                }
 
                state = mbuf->state == RMR_OK;
@@ -370,23 +382,23 @@ bool Message::Send( int mtype, int subid, int payload_len, unsigned char* payloa
        The second form of the call allows for a stack allocated buffer (e.g. char foo[120]) to
        be passed as the payload.
 */
-bool Message::Send_response(  int mtype, int subid, int response_len, std::shared_ptr<unsigned char> response ) {
-       return Send( mtype, subid, response_len, response.get(), RESPONSE );
+bool xapp::Message::Send_response(  int mtype, int subid, int response_len, std::shared_ptr<unsigned char> response ) {
+       return Send( mtype, subid, response_len, response.get(), RESPONSE, NO_WHID );
 }
 
-bool Message::Send_response(  int mtype, int subid, int response_len, unsigned char* response ) {
-       return Send( mtype, subid, response_len, response, RESPONSE );
+bool xapp::Message::Send_response(  int mtype, int subid, int response_len, unsigned char* response ) {
+       return Send( mtype, subid, response_len, response, RESPONSE, NO_WHID );
 }
 
 /*
        These allow a response message to be sent without changing the mtype/subid.
 */
-bool Message::Send_response(  int response_len, std::shared_ptr<unsigned char> response ) {
-       return Send( NO_CHANGE, NO_CHANGE, response_len, response.get(), RESPONSE );
+bool xapp::Message::Send_response(  int response_len, std::shared_ptr<unsigned char> response ) {
+       return Send( NO_CHANGE, NO_CHANGE, response_len, response.get(), RESPONSE, NO_WHID );
 }
 
-bool Message::Send_response(  int response_len, unsigned char* response ) {
-       return Send( NO_CHANGE, NO_CHANGE, response_len, response, RESPONSE );
+bool xapp::Message::Send_response(  int response_len, unsigned char* response ) {
+       return Send( NO_CHANGE, NO_CHANGE, response_len, response, RESPONSE, NO_WHID );
 }
 
 
@@ -399,21 +411,35 @@ bool Message::Send_response(  int response_len, unsigned char* response ) {
        Return is a new mbuf suitable for sending another message, or the original buffer with
        a bad state sent if there was a failure.
 */
-bool Message::Send_msg(  int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
-       return Send( mtype, subid, payload_len, payload.get(), MESSAGE );
+bool xapp::Message::Send_msg(  int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
+       return Send( mtype, subid, payload_len, payload.get(), MESSAGE, NO_WHID );
 }
 
-bool Message::Send_msg(  int mtype, int subid, int payload_len, unsigned char* payload ) {
-       return Send( mtype, subid, payload_len, payload, MESSAGE );
+bool xapp::Message::Send_msg(  int mtype, int subid, int payload_len, unsigned char* payload ) {
+       return Send( mtype, subid, payload_len, payload, MESSAGE, NO_WHID );
 }
 
 /*
        Similar send functions that allow the message type/subid to remain unchanged
 */
-bool Message::Send_msg(  int payload_len, std::shared_ptr<unsigned char> payload ) {
-       return Send( NO_CHANGE, NO_CHANGE, payload_len, payload.get(), MESSAGE );
+bool xapp::Message::Send_msg(  int payload_len, std::shared_ptr<unsigned char> payload ) {
+       return Send( NO_CHANGE, NO_CHANGE, payload_len, payload.get(), MESSAGE, NO_WHID );
 }
 
-bool Message::Send_msg(  int payload_len, unsigned char* payload ) {
-       return Send( NO_CHANGE, NO_CHANGE, payload_len, payload, MESSAGE );
+bool xapp::Message::Send_msg(  int payload_len, unsigned char* payload ) {
+       return Send( NO_CHANGE, NO_CHANGE, payload_len, payload, MESSAGE, NO_WHID );
 }
+
+
+/*
+       Wormhole send allows an xAPP to send a message directly based on an existing
+       wormhole ID (use xapp::Wormhole_open() to get one). Wormholes should NOT be
+       used for reponse messages, but are intended for things like route tables and
+       alarm messages where routing doesn't exist/apply.
+*/
+bool xapp::Message::Wormhole_send( int whid, int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
+       return Send( mtype, subid, payload_len, payload.get(), WORMHOLE_MSG, whid );
+}
+
+
+} // namespace
index 0db0927..df71d88 100644 (file)
@@ -49,6 +49,8 @@
 #endif
 
 
+namespace xapp {
+
 // ------------------------------------------------------------------------
 
 class Message {
@@ -59,6 +61,7 @@ class Message {
 
        public:
                static const int        NO_CHANGE = -99;                        // indicates no change to a send/reply parameter
+               static const int        NO_WHID = -1;                           // no wormhole id applies
                static const int        INVALID_MTYPE = -1;
                static const int        INVALID_STATUS = -1;
                static const int        INVALID_SUBID = -2;
@@ -66,6 +69,7 @@ class Message {
 
                static const int        RESPONSE = 0;                                   // send types
                static const int        MESSAGE = 1;
+               static const int        WORMHOLE_MSG = 2;
 
                Message( rmr_mbuf_t* mbuf, void* mrc );         // builders
                Message( void* mrc, int payload_len );
@@ -93,7 +97,7 @@ class Message {
 
                bool Reply( );
                bool Send( );
-               bool Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype );
+               bool Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype, int whid );
 
                bool Send_msg( int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload );
                bool Send_msg( int mtype, int subid, int payload_len, unsigned char* payload );
@@ -104,7 +108,10 @@ class Message {
                bool Send_response( int mtype, int subid, int payload_len, unsigned char* response );
                bool Send_response( int payload_len, std::shared_ptr<unsigned char> response );
                bool Send_response( int payload_len, unsigned char* response );
+
+               bool Wormhole_send( int whid, int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload );
 };
 
+} // namespace
 
 #endif
index 4e5a278..67d5e2d 100644 (file)
 #include "default_cb.hpp"              // default callback prototypes
 #include "message.hpp"
 #include "messenger.hpp"
+#include "alarm.hpp"
 
+namespace xapp {
 
 // --------------- private -----------------------------------------------------
 
 
 // ---------------- C++ buggerd up way of maintining class constants ----------
-const int Messenger::MAX_PAYLOAD = (1024*64);
-const int Messenger::DEFAULT_CALLBACK = -1;
+const int xapp::Messenger::MAX_PAYLOAD = (1024*64);
+const int xapp::Messenger::DEFAULT_CALLBACK = -1;
 
 // --------------- builders -----------------------------------------------
 /*
@@ -60,7 +62,7 @@ const int Messenger::DEFAULT_CALLBACK = -1;
 
        If port is nil, then the default port is used (4560).
 */
-Messenger::Messenger( const char* uport, bool wait4table ) {
+xapp::Messenger::Messenger( const char* uport, bool wait4table ) {
 
        if( uport == NULL ) {
                listen_port = strdup( "4560" );
@@ -87,7 +89,7 @@ Messenger::Messenger( const char* uport, bool wait4table ) {
        the new object, and then DELETE what was moved so that when the
        user frees the soi, it doesn't destroy what we snarfed.
 */
-Messenger::Messenger( Messenger&& soi ) {
+xapp::Messenger::Messenger( Messenger&& soi ) {
        mrc = soi.mrc;
        listen_port = soi.listen_port;
        ok_2_run = soi.ok_2_run;
@@ -103,7 +105,7 @@ Messenger::Messenger( Messenger&& soi ) {
        Move operator. Given a source object instance, movee it's contents
        to this insance.  We must first clean up this instance.
 */
-Messenger& Messenger::operator=( Messenger&& soi ) {
+xapp::Messenger& Messenger::operator=( Messenger&& soi ) {
        if( this != &soi ) {                            // cannot move onto ourself
                if( mrc != NULL ) {
                        rmr_close( mrc );
@@ -129,7 +131,7 @@ Messenger& Messenger::operator=( Messenger&& soi ) {
 /*
        Destroyer.
 */
-Messenger::~Messenger() {
+xapp::Messenger::~Messenger() {
        if( mrc != NULL ) {
                rmr_close( mrc );
        }
@@ -151,7 +153,7 @@ Messenger::~Messenger() {
        is defined for a message type, the default callback function is invoked.
        If a default is not provided, a non-matching message is silently dropped.
 */
-void Messenger::Add_msg_cb( int mtype, user_callback fun_name, void* data ) {
+void xapp::Messenger::Add_msg_cb( int mtype, user_callback fun_name, void* data ) {
        Callback*       cb;
 
        cb = new Callback( fun_name, data );
@@ -165,18 +167,57 @@ void Messenger::Add_msg_cb( int mtype, user_callback fun_name, void* data ) {
        finished, but may keep the message for as long as is necessary
        and reuse it over and over.
 */
-//Message* Messenger::Alloc_msg( int payload_size ) {
-std::unique_ptr<Message> Messenger::Alloc_msg( int payload_size ) {
+std::unique_ptr<Message> xapp::Messenger::Alloc_msg( int payload_size ) {
        return std::unique_ptr<Message>( new Message( mrc, payload_size ) );
 }
 
-void Messenger::Listen( ) {
+
+// ----------------- alarm support -----------------------------------------------
+/*
+       Allocate an alarm object.
+       Alarms must be allocated via the framework becasue we need a wormhole
+       id and to get one of those we need the mrc.  We can easily send with
+       just a message, but to avoid having the user pass the framework
+       object in, we'll just supply a "factory" function.
+*/
+std::unique_ptr<xapp::Alarm> xapp::Messenger::Alloc_alarm( int prob_id, std::string meid ) {
+       std::shared_ptr<Message> m;
+       Alarm* a;
+
+       m = Alloc_msg( 4096 );
+       a = new Alarm( m, prob_id, meid );
+       a->Set_whid( Wormhole_open( a->Get_endpoint() ) );
+
+       return std::unique_ptr<Alarm>( a );
+}
+
+std::unique_ptr<xapp::Alarm> xapp::Messenger::Alloc_alarm( std::string meid ) {
+       return Alloc_alarm( -1, meid );
+}
+
+std::unique_ptr<xapp::Alarm> xapp::Messenger::Alloc_alarm( ) {
+       return Alloc_alarm( -1, "" );
+}
+
+
+// ------------------- listening support -----------------------------------------------
+
+/*
+       The Listen function waits for messages and drives the appropriate callback
+       function when one is received. This function will return to the caller
+       only when the ok to run flag in the object has been set to false (likely
+       never, or only at graceful termination). Callers should normally not
+       expect to have controll returned in the calling thread.
+
+       Concurrently executing listeners are allowed.
+*/
+void xapp::Messenger::Listen( ) {
        int count = 0;
        rmr_mbuf_t*     mbuf = NULL;
        std::map<int,Callback*>::iterator mi;   // map iterator; silly indirect way to point at the value
        Callback*       dcb = NULL;                                     // default callback so we don't search
        Callback*       sel_cb;                                         // callback selected to invoke
-       std::unique_ptr<Message>m;
+       std::unique_ptr<Message> m;
 
        if( mrc == NULL ) {
                return;
@@ -212,8 +253,9 @@ void Messenger::Listen( ) {
 
 /*
        Wait for the next message, up to a max timout, and return the message received.
+       This function allows the user xAPP to implement their own polling loop (no callbacks).
 */
-std::unique_ptr<Message>  Messenger::Receive( int timeout ) {
+std::unique_ptr<Message>  xapp::Messenger::Receive( int timeout ) {
        rmr_mbuf_t*     mbuf = NULL;
        std::unique_ptr<Message> m = NULL;
 
@@ -230,7 +272,7 @@ std::unique_ptr<Message>  Messenger::Receive( int timeout ) {
 /*
        Called to gracefully stop all listeners.
 */
-void Messenger::Stop( ) {
+void xapp::Messenger::Stop( ) {
        ok_2_run = false;
 }
 
@@ -238,7 +280,7 @@ void Messenger::Stop( ) {
        RMR messages must be released by RMR as there might be transport
        buffers that have to be dealt with. Every callback is expected to
        call this function when finished with the message.
-void Messenger::Release_mbuf( void* vmbuf ) {
+void xapp::Messenger::Release_mbuf( void* vmbuf ) {
        rmr_free_msg( (rmr_mbuf_t *)  vmbuf );
 }
 */
@@ -262,7 +304,7 @@ void Messenger::Release_mbuf( void* vmbuf ) {
        incidcates all is ready.  If max_wait is 0, then this will only
        return when RMR is ready to send.
 */
-bool Messenger::Wait_for_cts( int max_wait ) {
+bool xapp::Messenger::Wait_for_cts( int max_wait ) {
        bool block_4ever;
        bool    state = false;
 
@@ -279,3 +321,17 @@ bool Messenger::Wait_for_cts( int max_wait ) {
 
        return state;
 }
+
+/*
+       Open a wormhole to the indicated endpoint and return the wormhole ID.
+*/
+int xapp::Messenger::Wormhole_open( std::string endpoint ) {
+       rmr_whid_t whid;
+
+       whid = rmr_wh_open( mrc, endpoint.c_str() );
+
+       return (int) whid;
+}
+
+
+} // namespace
index b6e46b6..173426c 100644 (file)
 #include <rmr/rmr.h>
 
 #include "message.hpp"
+#include "alarm.hpp"
 
 #ifndef RMR_FALSE
        #define RMR_FALSE       0
        #define RMR_TRUE        1
 #endif
 
+namespace xapp {
+
+
 class Messenger {
 
        private:
@@ -57,7 +61,7 @@ class Messenger {
                char*           listen_port;                    // port we ask msg router to listen on
 
                // copy and assignment are PRIVATE so that they fail if xapp tries; messenger cannot be copied!
-               Messenger( const Messenger& soi );      
+               Messenger( const Messenger& soi );
                Messenger& operator=( const Messenger& soi );
 
        public:
@@ -71,12 +75,21 @@ class Messenger {
                ~Messenger();                                                           // destroyer
 
                void Add_msg_cb( int mtype, user_callback fun_name, void* data );
+
                std::unique_ptr<Message> Alloc_msg( int payload_size );                 // message allocation
+
+               std::unique_ptr<xapp::Alarm> Alloc_alarm( );                                    // alarm allocation
+               std::unique_ptr<xapp::Alarm> Alloc_alarm( std::string meid );
+               std::unique_ptr<xapp::Alarm> Alloc_alarm( int prob_id, std::string meid );
+
                void Listen( );                                                                                                 // lisen driver
                std::unique_ptr<Message> Receive( int timeout );                                // receive 1 message
                void Stop( );                                                                                                   // force to stop
-               //void Release_mbuf( void* vmbuf );
                bool Wait_for_cts( int max_wait );
+
+               int     Wormhole_open( std::string endpoint );
 };
 
+
+} // namespace
 #endif
index d707257..40662a2 100644 (file)
@@ -35,6 +35,8 @@
 
 #include <memory>
 
+namespace xapp {
+
 //  -------------- smart pointer support  --------------------------------
 /*
        Pointers to a lot of things in the RMR message aren't directly
@@ -54,4 +56,6 @@ typedef struct {
 */
 using Msg_component = std::unique_ptr<unsigned char, unfreeable>;
 
+
+} // namespace
 #endif
index 5ba47ec..a00a1dc 100644 (file)
@@ -42,7 +42,7 @@
 #include "callback.hpp"
 #include "messenger.hpp"
 
-class Xapp : public Messenger {
+class Xapp : public xapp::Messenger {
 
        private:
                std::string name;
index 4245d3b..691f365 100644 (file)
@@ -11,7 +11,7 @@ rmr_em.o::    rmr_em.c
 
 unit_test:: unit_test.cpp rmr_em.o
        # do NOT link the xapp lib; we include all modules in the test programme
-       g++ -g $(coverage_opts) -I ../src/messaging unit_test.cpp -o unit_test rmr_em.o  -lpthread
+       g++ -g $(coverage_opts) -I ../src/alarm -I ../src/messaging unit_test.cpp -o unit_test rmr_em.o  -lpthread
 
 # build a special jwrapper object with coverage settings
 jwrapper_test.o:: ../src/json/jwrapper.c ../src/json/jwrapper.h
index 972e6e6..028fd11 100644 (file)
@@ -80,7 +80,7 @@ static char* read_jstring( char* fname ) {
 
 int main( int argc, char** argv ) {
        int             errors = 0;
-       Jhash*  jh;
+       xapp::Jhash*    jh;
        char*   jstr;
        std::string     sval;
        double  val;
@@ -94,7 +94,7 @@ int main( int argc, char** argv ) {
 
        fprintf( stderr, "read: (%s)\n", jstr );
 
-       jh = new Jhash( jstr );
+       jh = new xapp::Jhash( jstr );
        free( jstr );
 
        if( jh == NULL ) {
@@ -240,9 +240,9 @@ int main( int argc, char** argv ) {
 
 
        //  ----- jhashes can be moved, drive that logic for coverage
-       Jhash  j2( "{}" );
+       xapp::Jhash  j2( "{}" );
 
-       Jhash j1 = std::move( *jh );                            // drives move constructor function
+       xapp::Jhash j1 = std::move( *jh );                              // drives move constructor function
        j2 = std::move( j1 );                                           // drives move operator function
 
 
@@ -251,18 +251,18 @@ int main( int argc, char** argv ) {
 
        fprintf( stderr, "<INFO> testing for failures; jwrapper error and warning messages expected\n" );
        // ---- these shouild all fail to parse, generate warnings to stderr, and drive error handling coverage ----
-    jh = new Jhash( (char *) "{ \"bad\": [ [ 1, 2, 3 ], [ 3, 4, 5]] }" );              // drive the exception process for bad json
+    jh = new xapp::Jhash( (char *) "{ \"bad\": [ [ 1, 2, 3 ], [ 3, 4, 5]] }" );                // drive the exception process for bad json
        delete jh;
 
-    jh = new Jhash( (char *) " \"bad\":  5 }" );                       // no opening brace
+    jh = new xapp::Jhash( (char *) " \"bad\":  5 }" );                 // no opening brace
        state = jh->Parse_errors();
        errors += fail_if( !state, "parse errors check returned false when known errors exist" );
        delete jh;
 
-    jh = new Jhash( (char *) "{ \"bad\":  fred }" );           // no quotes
+    jh = new xapp::Jhash( (char *) "{ \"bad\":  fred }" );             // no quotes
        delete jh;
 
-    jh = new Jhash( (char *) "{ \"bad:  456, \"good\": 100 }" );                       // missing quote; impossible to detect error
+    jh = new xapp::Jhash( (char *) "{ \"bad:  456, \"good\": 100 }" );                 // missing quote; impossible to detect error
        jh->Dump();                                                                                                                             // but dump should provide details
        fprintf( stderr, "<INFO> good value=%d\n", (int) val );
        delete jh;
index c9f85cf..9d5c621 100644 (file)
@@ -22,7 +22,7 @@
        Mnemonic:       rmr_em.c
        Abstract:       RMR emulation for testing
 
-       Date:           20 March        
+       Date:           20 March
        Author:         E. Scott Daniels
 */
 
@@ -115,7 +115,7 @@ char* rmr_get_meid( rmr_mbuf_t* mbuf, char* m ) {
 
        if( mbuf != NULL ) {
                if( m == NULL ) {
-                       m = (char *) malloc( sizeof( char ) * 32 );             
+                       m = (char *) malloc( sizeof( char ) * 32 );     
                }
                h = (header_t *) mbuf->tp_buf;
                memcpy( m, h->meid, 32 );
@@ -138,7 +138,7 @@ char *rmr_get_src( rmr_mbuf_t* mbuf, char *m ) {
 
        if( mbuf != NULL ) {
                if( m == NULL ) {
-                       m = (char *) malloc( sizeof( char ) * 32 );             
+                       m = (char *) malloc( sizeof( char ) * 32 );     
                }
                h = (header_t *) mbuf->tp_buf;
                memcpy( m, h->src, 32 );
@@ -170,18 +170,18 @@ int rmr_str2meid( rmr_mbuf_t* mbuf, unsigned char* s ) {
 rmr_mbuf_t* rmr_send_msg( void* mrc, rmr_mbuf_t* mbuf ) {
 
        if( mbuf != NULL ) {
-               mbuf->state = 0;        
+               mbuf->state = 0;
        }
-       
+
        return mbuf;
 }
 
 rmr_mbuf_t* rmr_rts_msg( void* mrc, rmr_mbuf_t* mbuf ) {
 
        if( mbuf != NULL ) {
-               mbuf->state = 0;        
+               mbuf->state = 0;
        }
-       
+
        return mbuf;
 }
 
@@ -248,8 +248,43 @@ int rmr_ready( void* mrc ) {
        if( ! state )  {
                state = 1;
                return 0;
-       } 
+       }
 
        return 1;
 }
 
+// ----------------------- wormhole dummies ---------------------------------------------
+
+typedef int rmr_whid_t;
+
+extern rmr_whid_t rmr_wh_open( void* vctx, char const* target ) {
+       static int whid = 0;
+
+       if( vctx == NULL ) {
+               return -1;
+       }
+       return whid++;
+}
+
+//extern rmr_mbuf_t* rmr_wh_call( void* vctx, rmr_whid_t whid, rmr_mbuf_t* msg, int call_id, int max_wait );
+
+extern rmr_mbuf_t* rmr_wh_send_msg( void* vctx, rmr_whid_t whid, rmr_mbuf_t* mbuf ) {
+       if( mbuf != NULL ) {
+               if( whid >= 0 ) {
+                       mbuf->state = 0;
+               }
+
+               mbuf->state = 7;
+       }
+
+       return mbuf;
+}
+
+extern int rmr_wh_state( void* vctx, rmr_whid_t whid ) {
+       return whid >= 0;
+}
+
+extern void rmr_wh_close( void* vctx, int whid ){
+       return;
+}
+
index b0612d8..56f40b8 100644 (file)
 
 /*
        Mnemonic:       Unit_test.cpp
-       Abstract:       This is the unit test driver for the C++ xAPP framework. It 
+       Abstract:       This is the unit test driver for the C++ xAPP framework. It
                                operates by including all of the modules directly (in order
-                               to build them with the necessary coverage flags), then 
+                               to build them with the necessary coverage flags), then
                                drives all that it can.  The RMR emulation module provides
                                emulated RMR functions which simulate the creation, sending
                                and receiving of messages etc.
 
        Date:           20 March 2020
-       Author:         E. Scott Daniels
+       Author:         E. Scott Daniels
 */
 
 #include <memory>
 #include "../src/messaging/message.hpp"
 #include "../src/messaging/messenger.hpp"
 #include "../src/messaging/msg_component.hpp"
+#include "../src/alarm/alarm.hpp"
 #include "../src/xapp/xapp.hpp"
 
 #include "../src/messaging/callback.cpp"
 #include "../src/messaging/default_cb.cpp"
 #include "../src/messaging/message.cpp"
 #include "../src/messaging/messenger.cpp"
+#include "../src/alarm/alarm.cpp"
 #include "../src/xapp/xapp.cpp"
 
+#include "ut_support.cpp"
+
+// ---------------------------------------------------------------------------------------------
 /*
        callback error counts are global for ease. They track the number of times each callback
        was invoked with the expected message type(s) and any times they were not.
@@ -60,25 +65,25 @@ int good_cb2 = 0;
 int good_cbd = 0;
 
 /*
-       callback functions to register; driven as we "receive" messages (the RMR emulation package 
+       callback functions to register; driven as we "receive" messages (the RMR emulation package
        will generate a message every time the receive function is called).
 */
-void cb1( Message& mbuf, int mtype, int subid, int len, Msg_component payload,  void* data ) {
+void cb1( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload,  void* data ) {
        if( mtype != 1 ) {      // should only be driven for type 1 messages
                err_cb1++;
        } else {
                good_cb1++;
        }
 }
-void cb2( Message& mbuf, int mtype, int subid, int len, Msg_component payload,  void* data ) {
+void cb2( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload,  void* data ) {
        if( mtype != 2 ) {      // should only be driven for type 2 messages
                err_cb2++;
        } else {
                good_cb2++;
        }
 }
-void cbd( Message& mbuf, int mtype, int subid, int len, Msg_component payload,  void* data ) {
-       if( mtype > 0 && mtype < 3 ) {                          // should only be driven for types that arent 1 or 2 
+void cbd( xapp::Message& mbuf, int mtype, int subid, int len, xapp::Msg_component payload,  void* data ) {
+       if( mtype > 0 && mtype < 3 ) {                          // should only be driven for types that arent 1 or 2
                if( err_cbd < 10 ) {
                        fprintf( stderr, "<FAIL> cbd: bad message type: %d\n", mtype );
                }
@@ -90,8 +95,8 @@ void cbd( Message& mbuf, int mtype, int subid, int len, Msg_component payload,
 
 /*
        The Xapp Run() function only returns when Xapp is asked to stop, and that
-       isn't supported from inside any of the callbacks.  This funciton is 
-       started in a thread and after a few seconds it will drive the halt 
+       isn't supported from inside any of the callbacks.  This funciton is
+       started in a thread and after a few seconds it will drive the halt
        function in the Xapp instance to stop the run function and allow the
        unit test to finish.
 */
@@ -104,9 +109,9 @@ void killer( std::shared_ptr<Xapp> x ) {
 
 int main( int argc, char** argv ) {
        std::thread* tinfo;                                     // we'll start a thread that will shut things down after a few seconds
-       std::unique_ptr<Message> msg;
+       std::unique_ptr<xapp::Message> msg;
        std::shared_ptr<Xapp> x;
-       Msg_component payload;
+       xapp::Msg_component payload;
        std::unique_ptr<unsigned char> ucs;
        unsigned char* new_payload;
        std::shared_ptr<unsigned char> new_p_ref;       // reference to payload to pass to send functions
@@ -125,8 +130,8 @@ int main( int argc, char** argv ) {
                }
 
                switch( argv[ai][1] ) {                 // we only support -x so -xy must be -x -y
-                       case 'p': 
-                               port = argv[ai+1];      
+                       case 'p':
+                               port = argv[ai+1];
                                ai++;
                                break;
 
@@ -138,7 +143,10 @@ int main( int argc, char** argv ) {
 
                ai++;
        }
-       
+
+       set_test_name( "unit_test" );
+
+       // ------------------- generic xapp tests ----------------------------------------------
        x = std::shared_ptr<Xapp>( new Xapp( port, true ) );
        x->Add_msg_cb( 1, cb1, NULL );
        x->Add_msg_cb( 2, cb2, NULL );
@@ -243,21 +251,21 @@ int main( int argc, char** argv ) {
        }
 
        // -----  specific move/copy coverage drivers ---------------------------
-       
-       Messenger m1( (char *) "1234", false );         // messenger class does NOT permit copies, so no need to test
-       Messenger m2( (char *) "9999", false );
+
+       xapp::Messenger m1( (char *) "1234", false );           // messenger class does NOT permit copies, so no need to test
+       xapp::Messenger m2( (char *) "9999", false );
        m1 = std::move( m2 );                                           // drives move operator= function
-       Messenger m3 = std::move( m1 );                         // drives move constructor function
+       xapp::Messenger m3 = std::move( m1 );                           // drives move constructor function
 
-       std::unique_ptr<Message> msg2 = x->Alloc_msg( 2048 );
-       std::unique_ptr<Message> msg3 = x->Alloc_msg( 4096 );
+       std::unique_ptr<xapp::Message> msg2 = x->Alloc_msg( 2048 );
+       std::unique_ptr<xapp::Message> msg3 = x->Alloc_msg( 4096 );
 
        snprintf( wbuf, sizeof( wbuf ), "Stand up and cheer!!" );
        msg3->Set_len( strlen( wbuf ) );
        strcpy( (char *) (msg3->Get_payload()).get(), wbuf );                   // populate the payload to vet copy later
        fprintf( stderr, "<DBUG> set string (%s) \n", (char *) (msg3->Get_payload()).get() );
 
-       Message msg4 = *(msg3.get());                                                                   // drive copy builder; msg4 should have a 4096 byte payload
+       xapp::Message msg4 = *(msg3.get());                                                                     // drive copy builder; msg4 should have a 4096 byte payload
        fprintf( stderr, "<DBUG> copy string (%s) \n", (char *) (msg4.Get_payload()).get() );   // and payload should be coppied
        if( msg4.Get_available_size() != 4096 ) {
                errors++;
@@ -281,7 +289,7 @@ int main( int argc, char** argv ) {
                fprintf( stderr, "<FAIL> message copy builder payload of copy not the expected string\n" );
        }
 
-       Message msg5 = std::move( *(msg3.get()) );                                      // drive move constructor
+       xapp::Message msg5 = std::move( *(msg3.get()) );                                        // drive move constructor
        if( msg5.Get_available_size() != 2048 ) {
                errors++;
                fprintf( stderr, "<FAIL> message copy operator payload size smells: expected 2048, got %d\n", msg5.Get_available_size() );
@@ -298,5 +306,58 @@ int main( int argc, char** argv ) {
                fprintf( stderr, "<FAIL> message move operator payload len smells: expected 21, got %d\n", msg5.Get_len() );
        }
 
+       // --------------------- alarm testing ------------------------------------------
+       std::shared_ptr<xapp::Alarm> a;
+
+       a = x->Alloc_alarm( );                                                  // drive all possible constructors through the framework
+       errors += fail_if( a == NULL, "unable to allcoate a generic alarm" );
+
+       setenv( "ALARM_MGR_SERVICE_NAME", "alarm_svc", 1 );
+       setenv( "ALARM_MGR_SERVICE_PORT", "9999", 1 );
+
+       a = x->Alloc_alarm( "meid-123" );
+       errors += fail_if( a == NULL, "unable to allcoate an alarm with just  meid" );
+
+       a = x->Alloc_alarm( 13, "meid-abc" );
+       errors += fail_if( a == NULL, "unable to allcoate an alarm with meid and  problem id" );
+
+
+    //#####:  210:xapp::Alarm::Alarm( const Alarm& soi ) {
+    //#####:  227:Alarm& xapp::Alarm::operator=( const Alarm& soi ) {
+    //#####:  249:xapp::Alarm::Alarm( Alarm&& soi ) {
+    //#####:  269:Alarm& xapp::Alarm::operator=( Alarm&& soi ) {
+
+       a->Set_meid( "changed_meid" );
+       for( i = 0; i < 6; i++ ) {
+               a->Set_severity( i );                   // drive all switch possibilities
+       }
+
+       a->Set_appid( "new-appid" );
+       a->Set_problem( 99 );
+       a->Set_info( "new information string" );
+       a->Set_additional( "new additional information string" );
+
+       a->Dump();
+       errors += fail_if( !a->Raise(), "alarm raise with no parms failed" );
+       errors += fail_if( !a->Raise( xapp::Alarm::SEV_CRIT, 15, "problem string" ), "alarm raise s/p/i failed" );
+       errors += fail_if( !a->Raise( xapp::Alarm::SEV_CRIT, 15, "problem string", "addtl info" ), "alarm raise s/p/i/a failed" );
+
+       errors += fail_if( !a->Clear( ), "clear alarm failed" );
+       errors += fail_if( !a->Clear( xapp::Alarm::SEV_CRIT, 15, "problem string" ), "alarm clear s/p/i failed" );
+       errors += fail_if( !a->Clear( xapp::Alarm::SEV_CRIT, 15, "problem string", "addtl info" ), "alarm clear s/p/i/a failed" );
+       errors += fail_if( !a->Clear_all( ), "clear all failed" );
+
+       errors += fail_if( !a->Raise_again( ), "alarm raise again failed" );
+
+       xapp::Alarm b = *a.get();                               // force the move/copy operator functions to trigger
+       xapp::Alarm c( NULL );                                  // a useless alarm without a message
+       xapp::Alarm f( NULL, "meid" );                  // a useless alarm to drive direct construction
+       c = *a.get();                                                   // drive copy = operator
+
+       b = std::move( c );                                             // move = operator
+       xapp::Alarm d = std::move( b );                 // move constructor
+
+       announce_results( errors );
        return errors > 0;
 }
+