From c71159c30235103358da3f67c4a1c787e044ff7f Mon Sep 17 00:00:00 2001
From: Ivan Tyagov <ivan@nexedi.com>
Date: Thu, 13 Oct 2022 15:07:33 +0300
Subject: [PATCH] Coupler should know its state thus keep it accordingly.

---
 coupler/opc-ua-server/keep_alive.h            |  9 +++++++++
 coupler/opc-ua-server/keep_alive_subscriber.h | 20 ++++++++++++++-----
 coupler/opc-ua-server/server.c                |  5 +++++
 3 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/coupler/opc-ua-server/keep_alive.h b/coupler/opc-ua-server/keep_alive.h
index 5e11aa3..272584f 100644
--- a/coupler/opc-ua-server/keep_alive.h
+++ b/coupler/opc-ua-server/keep_alive.h
@@ -5,6 +5,15 @@ char *NETWORK_ADDRESS_URL_DATA_TYPE = "opc.udp://224.0.0.22:4840/";
 // global HEART BEATs of coupler
 static unsigned int HEART_BEATS = 0;
 
+// handling coupler's state
+static unsigned int CURRENT_STATE;
+const int STATE_UP =1;
+const int STATE_DOWN = 0;
+const int STATE_NO_INITIAL_HEART_BEAT = 2;
+
+// number of times the coupler was in SAFE mode 
+static unsigned int SAFE_MODE_STATE_COUNTER = 0;
+
 // the heart beat interval (in ms)
 const int DEFAULT_HEART_BEAT_INTERVAL = 250;
 static int HEART_BEAT_INTERVAL = DEFAULT_HEART_BEAT_INTERVAL;
diff --git a/coupler/opc-ua-server/keep_alive_subscriber.h b/coupler/opc-ua-server/keep_alive_subscriber.h
index b631bc4..37c3793 100644
--- a/coupler/opc-ua-server/keep_alive_subscriber.h
+++ b/coupler/opc-ua-server/keep_alive_subscriber.h
@@ -300,15 +300,25 @@ void callbackCheckHeartBeat() {
         timestamp_delta = milli_seconds - last_seen_timestamp_int;
         is_down = (timestamp_delta > HEART_BEAT_TIMEOUT_INTERVAL);
         if (is_down) {
-          UA_LOG_INFO(UA_Log_Stdout, \
-                      UA_LOGCATEGORY_USERLAND, \
-                      "DOWN: %s (delta=%d)", coupler_id_str, timestamp_delta);
-        // go to safe mode as a dependant coupler is DOWN.
-        gotoSafeMode();
+          // count for stats the switch to SAFE mode
+          if (CURRENT_STATE != STATE_DOWN) {
+            CURRENT_STATE = STATE_DOWN;
+            SAFE_MODE_STATE_COUNTER += 1;
+            UA_LOG_INFO(UA_Log_Stdout, \
+                        UA_LOGCATEGORY_USERLAND, \
+                        "DOWN: %s (delta=%d)", coupler_id_str, timestamp_delta);
+            // go to safe mode as a dependant coupler is DOWN.
+            gotoSafeMode();
+          }
+        }
+        else {
+          // all good, we received a keep alive in time
+          CURRENT_STATE = STATE_UP;
         }
       }
       else {
         // still no hear beat from this coupler ...
+        CURRENT_STATE = STATE_NO_INITIAL_HEART_BEAT;
         UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "NO INITIAL HEART BEAT: %s", coupler_id_str);
       }
     }
diff --git a/coupler/opc-ua-server/server.c b/coupler/opc-ua-server/server.c
index 0f9e27f..0c8a0b5 100644
--- a/coupler/opc-ua-server/server.c
+++ b/coupler/opc-ua-server/server.c
@@ -185,5 +185,10 @@ int main(int argc, char **argv)
   // always leave attached slaves to a known safe shutdown state
   safeShutdownI2CSlaveList();
 
+  // print statistics
+  UA_LOG_INFO(UA_Log_Stdout, \
+              UA_LOGCATEGORY_USERLAND, \
+              "SAFE mode counter=%d", SAFE_MODE_STATE_COUNTER);
+ 
   return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
2.30.9