From 46ef64b4c099277d10680eb8ed903c6d38bf0029 Mon Sep 17 00:00:00 2001
From: "ezekiel.dohmen" <ezekiel.dohmen@ligo.org>
Date: Wed, 10 Apr 2024 09:34:38 -0700
Subject: [PATCH] Adding init to RT model

---
 src/epics/util/lib/Statespace.pm              | 13 +++++++
 src/fe/moduleLoad.c                           | 18 +++++++++
 src/fe/statespace/stateSpaceCtrl_cdev.c       |  6 ++-
 src/fe/statespace/stateSpacePart.c            | 39 ++++++++++++-------
 .../part_headers/statespace/stateSpacePart.h  |  4 +-
 5 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/src/epics/util/lib/Statespace.pm b/src/epics/util/lib/Statespace.pm
index 6cb27383d..c29febc76 100644
--- a/src/epics/util/lib/Statespace.pm
+++ b/src/epics/util/lib/Statespace.pm
@@ -50,6 +50,19 @@ sub printEpics {
     
 }
 
+# return an array of EpicsVariable objects
+# this function should be idempotent: calling it over and over should give the same
+# result and have no side effects.
+sub getEpicsVariables {
+    my ($i) = @_;
+    @epics_vars = ();
+
+    # Add EPICS input to reset the state of the statespace part
+    push @epics_vars, CDS::EpicsVariable::new("$::xpartName[$i]\_RESET", "$::xpartName[$i]\_RESET", "int",  "ai", 1, 0, {"PREC" => 0});
+
+    return @epics_vars;
+}
+
 # Print variable declarations int front-end file
 # Current part number is passed as first argument
 sub printFrontEndVars  {
diff --git a/src/fe/moduleLoad.c b/src/fe/moduleLoad.c
index 3fd048a27..bb85a45d9 100644
--- a/src/fe/moduleLoad.c
+++ b/src/fe/moduleLoad.c
@@ -16,6 +16,9 @@
 #include "../fe/verify_slots.h"
 #include "../fe/mapApp.h" //initmap()
 #include "../fe/dolphin.h"
+#include "part_headers/statespace/stateSpacePart.h"
+#include "part_headers/statespace/stateSpaceCtrl_cdev.h"
+
 
 
 #include <linux/uaccess.h>
@@ -94,6 +97,17 @@ static int __init rt_fe_init( void )
 
     demodulation_init();
 
+    //Statespace Setup
+    if ( globStateSpaceInit( STATESPACE_NUM_PARTS ) != 0 ) { //STATESPACE_NUM_PARTS defined in FE_HEADER
+        RTSLOG_ERROR( "rt_fe_init() - Failed to initialize statespace parts, num: %d\n", STATESPACE_NUM_PARTS );
+        return -5;
+    }
+
+    if( initStateSpaceCtrl_cdev(SYSTEM_NAME_STRING_LOWER) != 0 ) {
+        RTSLOG_ERROR( "rt_fe_init() - Failed to initialize the statespace cdev: /dev/%s\n", SYSTEM_NAME_STRING_LOWER );
+        return -5;
+    }
+
 
 #ifdef DOLPHIN_TEST
     {
@@ -320,6 +334,10 @@ static void  rt_fe_cleanup( void )
     finish_dolphin( );
 #endif
 
+    //Clean up Statespace global state
+    cleanupStateSpaceCtrl_cdev();
+    globStateSpaceFree();
+
     // Print out any error messages from FE code on exit
     print_exit_messages( fe_status_return, fe_status_return_subcode, SYSTEM_NAME_STRING_LOWER );
     detach_shared_memory( );
diff --git a/src/fe/statespace/stateSpaceCtrl_cdev.c b/src/fe/statespace/stateSpaceCtrl_cdev.c
index 3db78d057..1f1ade016 100644
--- a/src/fe/statespace/stateSpaceCtrl_cdev.c
+++ b/src/fe/statespace/stateSpaceCtrl_cdev.c
@@ -258,7 +258,11 @@ static long     stateSpaceCtrl_ioctl(struct file *file, unsigned int cmd, unsign
             if (whole_cfg_ptr == NULL) return -ENOMEM;
             ((struct stateSpace_part_config_t *)whole_cfg_ptr)->ioctl_version = STATE_SPACE_IOCTL_V0;
 
-            getConfigAndDataOfPartStateSpace(req_part_index, data_block_sz, (void*)whole_cfg_ptr);
+            if ( getConfigAndDataOfPartStateSpace(req_part_index, data_block_sz, (void*)whole_cfg_ptr) != 0 ) {
+                RTSLOG_ERROR("stateSpaceCtrl_cdev - getConfigAndDataOfPartStateSpace(%d) failed, has the part been configured?\n", req_part_index);
+                vfree(whole_cfg_ptr);
+                return -EINVAL;
+            }
             if( copy_to_user(config_req_usr_ptr, whole_cfg_ptr, sizeof(struct stateSpace_part_config_t) + data_block_sz ) != 0)
             {
                 RTSLOG_ERROR("stateSpaceCtrl_cdev - copy_to_user() failed\n");
diff --git a/src/fe/statespace/stateSpacePart.c b/src/fe/statespace/stateSpacePart.c
index 79c6f75e0..673be4bff 100644
--- a/src/fe/statespace/stateSpacePart.c
+++ b/src/fe/statespace/stateSpacePart.c
@@ -18,22 +18,24 @@ int globStateSpaceInit( unsigned num_parts )
 {
     g_model_config.num_parts = num_parts;
     
+    if ( num_parts > 0 ) { //Don't try a 0 byte allocation
 
-    g_model_config.ss_parts_ptr = vmalloc(sizeof(*g_model_config.ss_parts_ptr) * num_parts);
-    if ( g_model_config.ss_parts_ptr == NULL ) {
-        RTSLOG_ERROR("stateSpace - Failed to allocate memory for state space parts.\n");
-        return -1;
-    }
-
-    for(int i=0; i < num_parts; ++i)
-    {
-        g_model_config.ss_parts_ptr[i].context = (StateSpaceCtx_t*) vmalloc(sizeof(StateSpaceCtx_t));
-        if( g_model_config.ss_parts_ptr[i].context == NULL) {
-            RTSLOG_ERROR("Failed to vmalloc() conbtext for the StateSpace part.");
+        g_model_config.ss_parts_ptr = vmalloc(sizeof(*g_model_config.ss_parts_ptr) * num_parts);
+        if ( g_model_config.ss_parts_ptr == NULL ) {
+            RTSLOG_ERROR("stateSpace - Failed to allocate memory for state space parts.\n");
             return -1;
         }
-        //Zero out the ctx
-        memset((void*)g_model_config.ss_parts_ptr[i].context, 0, sizeof(StateSpaceCtx_t));
+
+        for(int i=0; i < num_parts; ++i)
+        {
+            g_model_config.ss_parts_ptr[i].context = (StateSpaceCtx_t*) vmalloc(sizeof(StateSpaceCtx_t));
+            if( g_model_config.ss_parts_ptr[i].context == NULL) {
+                RTSLOG_ERROR("Failed to vmalloc() context for the StateSpace part.");
+                return -1;
+            }
+            //Zero out the ctx
+            memset((void*)g_model_config.ss_parts_ptr[i].context, 0, sizeof(StateSpaceCtx_t));
+        }
     }
 
     return 0;
@@ -268,8 +270,15 @@ void getConfigOfPartStateSpace(unsigned part_index, struct stateSpace_part_confi
     fill_me->state_vec_len = g_model_config.ss_parts_ptr[part_index].context->state_len;
 }
 
-void getConfigAndDataOfPartStateSpace(unsigned part_index, unsigned data_sz, struct stateSpace_part_config_t * fill_me)
+int getConfigAndDataOfPartStateSpace(unsigned part_index, unsigned data_sz, struct stateSpace_part_config_t * fill_me)
 {
+    if ( g_model_config.ss_parts_ptr[part_index].context == NULL || 
+         g_model_config.ss_parts_ptr[part_index].context->mem_block_ptr == NULL) {
+         //mem_block_ptr will be NULL after the model starts until matrixInitStateSpace() 
+         //through the IOCTL interface is called.
+            return -1;
+    
+    }
     fill_me->part_index = part_index;
     fill_me->input_vec_len = g_model_config.ss_parts_ptr[part_index].model_inputs;
     fill_me->output_vec_len = g_model_config.ss_parts_ptr[part_index].model_outputs;
@@ -278,6 +287,8 @@ void getConfigAndDataOfPartStateSpace(unsigned part_index, unsigned data_sz, str
     memcpy( &fill_me->data_block[fill_me->state_vec_len], 
             g_model_config.ss_parts_ptr[part_index].context->state_matrix, 
             data_sz - (fill_me->state_vec_len * 8));
+            
+    return 0;
 }
 
 
diff --git a/src/include/part_headers/statespace/stateSpacePart.h b/src/include/part_headers/statespace/stateSpacePart.h
index e4d2a413b..84140f1d0 100644
--- a/src/include/part_headers/statespace/stateSpacePart.h
+++ b/src/include/part_headers/statespace/stateSpacePart.h
@@ -45,7 +45,9 @@ void setStateVecStateSpace(unsigned part_index, double * state_vec);
 unsigned getNumPartsStateSpace( void );
 void getPartNamePtrStateSpace( unsigned part_index, char ** name_ptr );
 void getConfigOfPartStateSpace(unsigned part_index, struct stateSpace_part_config_t * );
-void getConfigAndDataOfPartStateSpace(unsigned part_index, unsigned data_sz, struct stateSpace_part_config_t * fill_me);
+
+// @return -1 if data for part is not available
+int getConfigAndDataOfPartStateSpace(unsigned part_index, unsigned data_sz, struct stateSpace_part_config_t * fill_me);
 
 //Test Methods
 int testBufferOverrun(unsigned part_index);
-- 
GitLab