Repository: nasa-itc/generic_fss
Pull request #10: [nasa/nos3#604] fss system check tolerance
Author: login: kevincbruce
Created: 2025-04-02T21:31:25Z | Merged: 2025-04-10T19:51:57Z



Diff:
diff --git a/fsw/cfs/src/generic_fss_app.c b/fsw/cfs/src/generic_fss_app.c
index 2fa20e1..f36851f 100644
--- a/fsw/cfs/src/generic_fss_app.c
+++ b/fsw/cfs/src/generic_fss_app.c
@@ -270,10 +270,18 @@ static void GENERIC_FSS_ProcessGroundCommand(void)
             */
             if (GENERIC_FSS_VerifyCmdLength(GENERIC_FSS_AppData.MsgPtr, sizeof(GENERIC_FSS_NoArgs_cmd_t)) == OS_SUCCESS)
             {
-                /* Second, send EVS event on successful receipt ground commands*/
+                /* Do any necessary checks, none for a NOOP */
+
+                /* Increment Command Success or error counter, NOOP can only be successful*/
+                GENERIC_FSS_AppData.HkTelemetryPkt.CommandCount++;
+
+                /* Third, do the desired command action if applicable, in the case of NOOP it is no operation */
+
+                /* Increment device success or error counter, none for NOOP as application only */
+
+                /* Send EVS event on successful receipt ground commands*/
                 CFE_EVS_SendEvent(GENERIC_FSS_CMD_NOOP_INF_EID, CFE_EVS_EventType_INFORMATION,
                                   "GENERIC_FSS: NOOP command received");
-                /* Third, do the desired command action if applicable, in the case of NOOP it is no operation */
             }
             break;
 
@@ -283,9 +291,12 @@ static void GENERIC_FSS_ProcessGroundCommand(void)
         case GENERIC_FSS_RESET_COUNTERS_CC:
             if (GENERIC_FSS_VerifyCmdLength(GENERIC_FSS_AppData.MsgPtr, sizeof(GENERIC_FSS_NoArgs_cmd_t)) == OS_SUCCESS)
             {
+                GENERIC_FSS_AppData.HkTelemetryPkt.CommandCount++;
+
+                GENERIC_FSS_ResetCounters();
+
                 CFE_EVS_SendEvent(GENERIC_FSS_CMD_RESET_INF_EID, CFE_EVS_EventType_INFORMATION,
                                   "GENERIC_FSS: RESET counters command received");
-                GENERIC_FSS_ResetCounters();
             }
             break;
 
@@ -295,9 +306,10 @@ static void GENERIC_FSS_ProcessGroundCommand(void)
         case GENERIC_FSS_ENABLE_CC:
             if (GENERIC_FSS_VerifyCmdLength(GENERIC_FSS_AppData.MsgPtr, sizeof(GENERIC_FSS_NoArgs_cmd_t)) == OS_SUCCESS)
             {
+                GENERIC_FSS_Enable();
+
                 CFE_EVS_SendEvent(GENERIC_FSS_CMD_ENABLE_INF_EID, CFE_EVS_EventType_INFORMATION,
                                   "GENERIC_FSS: Enable command received");
-                GENERIC_FSS_Enable();
             }
             break;
 
@@ -307,9 +319,10 @@ static void GENERIC_FSS_ProcessGroundCommand(void)
         case GENERIC_FSS_DISABLE_CC:
             if (GENERIC_FSS_VerifyCmdLength(GENERIC_FSS_AppData.MsgPtr, sizeof(GENERIC_FSS_NoArgs_cmd_t)) == OS_SUCCESS)
             {
+                GENERIC_FSS_Disable();
+
                 CFE_EVS_SendEvent(GENERIC_FSS_CMD_DISABLE_INF_EID, CFE_EVS_EventType_INFORMATION,
                                   "GENERIC_FSS: Disable command received");
-                GENERIC_FSS_Disable();
             }
             break;
 
@@ -431,7 +444,6 @@ static int32 GENERIC_FSS_VerifyCmdLength(CFE_MSG_Message_t *msg, uint16 expected
     if (expected_length == actual_length)
     {
         /* Increment the command counter upon receipt of a valid command */
-        GENERIC_FSS_AppData.HkTelemetryPkt.CommandCount++;
     }
     else
     {
@@ -460,6 +472,9 @@ static void GENERIC_FSS_Enable(void)
     /* Check that device is disabled */
     if (GENERIC_FSS_AppData.HkTelemetryPkt.DeviceEnabled == GENERIC_FSS_DEVICE_DISABLED)
     {
+        /* Increment command success counter */
+        GENERIC_FSS_AppData.HkTelemetryPkt.CommandCount++;
+
         /*
         ** Initialize hardware interface data
         */
@@ -475,6 +490,7 @@ static void GENERIC_FSS_Enable(void)
         status = spi_init_dev(&GENERIC_FSS_AppData.Generic_fssSpi);
         if (status == OS_SUCCESS)
         {
+
             GENERIC_FSS_AppData.HkTelemetryPkt.DeviceCount++;
             GENERIC_FSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_FSS_DEVICE_ENABLED;
             CFE_EVS_SendEvent(GENERIC_FSS_ENABLE_INF_EID, CFE_EVS_EventType_INFORMATION, "GENERIC_FSS: Device enabled");
@@ -488,7 +504,7 @@ static void GENERIC_FSS_Enable(void)
     }
     else
     {
-        GENERIC_FSS_AppData.HkTelemetryPkt.DeviceErrorCount++;
+        GENERIC_FSS_AppData.HkTelemetryPkt.CommandErrorCount++;
         CFE_EVS_SendEvent(GENERIC_FSS_ENABLE_ERR_EID, CFE_EVS_EventType_ERROR,
                           "GENERIC_FSS: Device enable failed, already enabled");
     }
@@ -505,6 +521,9 @@ static void GENERIC_FSS_Disable(void)
     /* Check that device is enabled */
     if (GENERIC_FSS_AppData.HkTelemetryPkt.DeviceEnabled == GENERIC_FSS_DEVICE_ENABLED)
     {
+        /* Increment command success counter */
+        GENERIC_FSS_AppData.HkTelemetryPkt.CommandCount++;
+
         /* Close device specific protocols */
         status = spi_close_device(&GENERIC_FSS_AppData.Generic_fssSpi);
         if (status == OS_SUCCESS)
@@ -523,7 +542,7 @@ static void GENERIC_FSS_Disable(void)
     }
     else
     {
-        GENERIC_FSS_AppData.HkTelemetryPkt.DeviceErrorCount++;
+        GENERIC_FSS_AppData.HkTelemetryPkt.CommandErrorCount++;
         CFE_EVS_SendEvent(GENERIC_FSS_DISABLE_ERR_EID, CFE_EVS_EventType_ERROR,
                           "GENERIC_FSS: Device disable failed, already disabled");
     }
diff --git a/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_CMD.txt b/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_CMD.txt
index c6859df..d9dd868 100644
--- a/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_CMD.txt
+++ b/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_CMD.txt
@@ -1,41 +1,41 @@
-COMMAND GENERIC_FSS GENERIC_FSS_NOOP_CC BIG_ENDIAN "Generic_fss NOOP Command"
-  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" 
-  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" 
-  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" 
+COMMAND GENERIC_FSS GENERIC_FSS_NOOP_CC <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "Generic_fss NOOP Command"
+  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" BIG_ENDIAN
   APPEND_PARAMETER CCSDS_FC            8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Function Code" 
   APPEND_PARAMETER CCSDS_CHECKSUM      8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Checksum"
 
-COMMAND GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC BIG_ENDIAN "Generic_fss Reset Counters Command"
-  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" 
-  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" 
-  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" 
+COMMAND GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "Generic_fss Reset Counters Command"
+  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" BIG_ENDIAN
   APPEND_PARAMETER CCSDS_FC            8  UINT MIN_UINT8 MAX_UINT8 1        "CCSDS Command Function Code" 
   APPEND_PARAMETER CCSDS_CHECKSUM      8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Checksum"
 
-COMMAND GENERIC_FSS GENERIC_FSS_ENABLE_CC BIG_ENDIAN "Generic_fss Enable Command"
-  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" 
-  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" 
-  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" 
+COMMAND GENERIC_FSS GENERIC_FSS_ENABLE_CC <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "Generic_fss Enable Command"
+  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" BIG_ENDIAN
   APPEND_PARAMETER CCSDS_FC            8  UINT MIN_UINT8 MAX_UINT8 2        "CCSDS Command Function Code" 
   APPEND_PARAMETER CCSDS_CHECKSUM      8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Checksum"
 
-COMMAND GENERIC_FSS GENERIC_FSS_DISABLE_CC BIG_ENDIAN "Generic_fss Disable Command"
-  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" 
-  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" 
-  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" 
+COMMAND GENERIC_FSS GENERIC_FSS_DISABLE_CC <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "Generic_fss Disable Command"
+  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1920 "CCSDS Packet Identification" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" BIG_ENDIAN
   APPEND_PARAMETER CCSDS_FC            8  UINT MIN_UINT8 MAX_UINT8 3        "CCSDS Command Function Code" 
   APPEND_PARAMETER CCSDS_CHECKSUM      8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Checksum"
 
-COMMAND GENERIC_FSS GENERIC_FSS_REQ_HK BIG_ENDIAN "Generic_fss Request HK Packet Command"
-  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1921 "CCSDS Packet Identification" 
-  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" 
-  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" 
+COMMAND GENERIC_FSS GENERIC_FSS_REQ_HK <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "Generic_fss Request HK Packet Command"
+  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1921 "CCSDS Packet Identification" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" BIG_ENDIAN
   APPEND_PARAMETER CCSDS_FC            8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Function Code" 
   APPEND_PARAMETER CCSDS_CHECKSUM      8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Checksum"
 
-COMMAND GENERIC_FSS GENERIC_FSS_REQ_DATA BIG_ENDIAN "Generic_fss Request Data Packet Command"
-  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1921 "CCSDS Packet Identification" 
-  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" 
-  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" 
+COMMAND GENERIC_FSS GENERIC_FSS_REQ_DATA <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "Generic_fss Request Data Packet Command"
+  APPEND_PARAMETER CCSDS_STREAMID      16 UINT MIN_UINT16 MAX_UINT16 0x1921 "CCSDS Packet Identification" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_SEQUENCE      16 UINT MIN_UINT16 MAX_UINT16 0xC000 "CCSDS Packet Sequence Control" BIG_ENDIAN
+  APPEND_PARAMETER CCSDS_LENGTH        16 UINT MIN_UINT16 MAX_UINT16 1      "CCSDS Packet Data Length" BIG_ENDIAN
   APPEND_PARAMETER CCSDS_FC            8  UINT MIN_UINT8 MAX_UINT8 1        "CCSDS Command Function Code" 
   APPEND_PARAMETER CCSDS_CHECKSUM      8  UINT MIN_UINT8 MAX_UINT8 0        "CCSDS Command Checksum"
diff --git a/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_TLM.txt b/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_TLM.txt
index 912fb6c..022eb85 100644
--- a/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_TLM.txt
+++ b/gsw/GENERIC_FSS/cmd_tlm/GENERIC_FSS_TLM.txt
@@ -1,4 +1,4 @@
-TELEMETRY GENERIC_FSS GENERIC_FSS_HK_TLM LITTLE_ENDIAN "GENERIC_FSS_Hk_tlm_t"
+TELEMETRY GENERIC_FSS GENERIC_FSS_HK_TLM <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "GENERIC_FSS_Hk_tlm_t"
   APPEND_ID_ITEM CCSDS_STREAMID       16 UINT 0x0920  "CCSDS Packet Identification" BIG_ENDIAN
   APPEND_ITEM    CCSDS_SEQUENCE       16 UINT         "CCSDS Packet Sequence Control" BIG_ENDIAN
   APPEND_ITEM    CCSDS_LENGTH         16 UINT         "CCSDS Packet Data Length" BIG_ENDIAN
@@ -13,7 +13,7 @@ TELEMETRY GENERIC_FSS GENERIC_FSS_HK_TLM LITTLE_ENDIAN "GENERIC_FSS_Hk_tlm_t"
     STATE DISABLED 0
     STATE ENABLED  1 
 
-TELEMETRY GENERIC_FSS GENERIC_FSS_DATA_TLM LITTLE_ENDIAN "GENERIC_FSS_Device_tlm_t"
+TELEMETRY GENERIC_FSS GENERIC_FSS_DATA_TLM <%= CosmosCfsConfig::PROCESSOR_ENDIAN %> "GENERIC_FSS_Device_tlm_t"
   APPEND_ID_ITEM CCSDS_STREAMID         16 UINT 0x0921  "CCSDS Packet Identification" BIG_ENDIAN
   APPEND_ITEM    CCSDS_SEQUENCE         16 UINT         "CCSDS Packet Sequence Control" BIG_ENDIAN
   APPEND_ITEM    CCSDS_LENGTH           16 UINT         "CCSDS Packet Data Length" BIG_ENDIAN
diff --git a/gsw/GENERIC_FSS/lib/generic_fss_lib.rb b/gsw/GENERIC_FSS/lib/generic_fss_lib.rb
new file mode 100644
index 0000000..db0f7a1
--- /dev/null
+++ b/gsw/GENERIC_FSS/lib/generic_fss_lib.rb
@@ -0,0 +1,132 @@
+# Library for GENERIC_FSS Target
+require 'cosmos'
+require 'cosmos/script'
+
+#
+# Definitions
+#
+GENERIC_FSS_CMD_SLEEP = 0.25
+GENERIC_FSS_RESPONSE_TIMEOUT = 5
+GENERIC_FSS_TEST_LOOP_COUNT = 1
+GENERIC_FSS_DEVICE_LOOP_COUNT = 5
+
+#
+# Functions
+#
+def get_fss_hk()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_HK_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def get_fss_data()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_DATA_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def fss_cmd(*command)
+    count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT") + 1
+
+    if (count == 256)
+        count = 0
+    end
+
+    cmd(*command)
+    get_fss_hk()
+    current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    if (current != count)
+        # Try again
+        cmd(*command)
+        get_fss_hk()
+        current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        if (current != count)
+            # Third times the charm
+            cmd(*command)
+            get_fss_hk()
+            current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        end
+    end
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT >= #{count}")
+end
+
+def enable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'")
+end
+
+def disable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'")
+end
+
+def safe_fss()
+    get_fss_hk()
+    state = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED")
+    if (state != "DISABLED")
+        disable_fss()
+    end
+end
+
+def confirm_fss_data()
+    dev_cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT")
+    dev_cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
+    
+    get_fss_data()
+    svb0 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_0")
+    svb1 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_1")
+    svb2 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_2")
+
+    fss_error = tlm("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_ERROR_CODE")
+
+    truth_42_alpha = -Math.atan2(svb2, svb0)
+    truth_42_beta = Math.atan2(svb1, svb0)
+
+    diff = 0.03
+
+    if fss_error == 0
+        wait_check_tolerance("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_ALPHA", truth_42_alpha, diff, GENERIC_FSS_RESPONSE_TIMEOUT)
+
+        wait_check_tolerance("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_BETA", truth_42_beta, diff, GENERIC_FSS_RESPONSE_TIMEOUT)
+    end
+
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT >= #{dev_cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{dev_cmd_err_cnt}")
+end
+
+def confirm_fss_data_loop()
+    GENERIC_FSS_DEVICE_LOOP_COUNT.times do |n|
+        confirm_fss_data()
+    end
+end
+
+#
+# Simulator Functions
+#
+def fss_prepare_ast()
+    # Get to known state
+    safe_fss()
+
+    # Enable
+    enable_fss()
+
+    # Confirm data
+    confirm_fss_data_loop()
+end
+
+def fss_sim_enable()
+    cmd("SIM_CMDBUS_BRIDGE GENERIC_FSS_SIM_ENABLE")
+end
+
+def fss_sim_disable()
+    cmd("SIM_CMDBUS_BRIDGE GENERIC_FSS_SIM_DISABLE")
+end
+
+def fss_sim_set_status(status)
+    cmd("SIM_CMDBUS_BRIDGE GENERIC_FSS_SIM_SET_STATUS with STATUS #{status}")
+end
diff --git a/gsw/GENERIC_FSS/procedures/generic_fss_test.rb b/gsw/GENERIC_FSS/procedures/generic_fss_test.rb
index e946a87..437cc3d 100644
--- a/gsw/GENERIC_FSS/procedures/generic_fss_test.rb
+++ b/gsw/GENERIC_FSS/procedures/generic_fss_test.rb
@@ -1,45 +1,51 @@
 require 'cosmos'
 require 'cosmos/script'
-require 'mission_lib.rb'
+require 'generic_fss_lib.rb'
 
-class FSS_LPT < Cosmos::Test
+class GENERIC_FSS_Functional_Test < Cosmos::Test
   def setup
-    
+    safe_fss()
   end
 
-  def test_lpt
-    start("tests/generic_fss_lpt_test.rb")
+  def test_application
+      start("tests/generic_fss_app_test.rb")
   end
 
-  def teardown
+  def test_device
+    start("tests/generic_fss_device_test.rb")
+  end
 
+  def teardown
+    safe_fss()
   end
 end
 
-class FSS_CPT < Cosmos::Test
-  def setup
-      
+class GENERIC_FSS_Automated_Scenario_Test < Cosmos::Test
+  def setup 
+    safe_fss()
   end
 
-  def test_cpt
-    start("tests/generic_fss_cpt_test.rb")
+  def test_AST
+      start("tests/generic_fss_ast_test.rb")
   end
 
   def teardown
-
+    safe_fss()
   end
 end
 
 class Generic_fss_Test < Cosmos::TestSuite
   def initialize
       super()
-      add_test('FSS_CPT')
-      add_test('FSS_LPT')
+      add_test('GENERIC_FSS_Functional_Test')
+      add_test('GENERIC_FSS_Automated_Scenario_Test')
   end
 
   def setup
+    safe_fss()
   end
   
   def teardown
+    safe_fss()
   end
-end
\ No newline at end of file
+end
diff --git a/gsw/GENERIC_FSS/procedures/tests/generic_fss_app_test.rb b/gsw/GENERIC_FSS/procedures/tests/generic_fss_app_test.rb
new file mode 100644
index 0000000..406f5e0
--- /dev/null
+++ b/gsw/GENERIC_FSS/procedures/tests/generic_fss_app_test.rb
@@ -0,0 +1,64 @@
+require 'cosmos'
+require 'cosmos/script'
+require "generic_fss_lib.rb"
+
+##
+## This script tests the standard cFS component application functionality.
+## Currently this includes: 
+##   Housekeeping, request telemetry to be published on the software bus
+##   NOOP, no operation but confirm correct counters increment
+##   Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+
+
+##
+##   Housekeeping, request telemetry to be published on the software bus
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    get_fss_hk()
+end
+
+
+##
+## NOOP, no operation but confirm correct counters increment
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+end
+
+
+##
+## Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+    cmd("GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC") # Note standard `cmd` as we can't reset counters and then confirm increment
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == 0")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == 0")
+end
+
+
+##
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    # Bad length
+    cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
+    cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC with CCSDS_LENGTH #{n+2}") # Note +2 due to CCSDS already being +1
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == #{cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{cmd_err_cnt+1}")
+end
+
+for n in 6..(5 + GENERIC_FSS_TEST_LOOP_COUNT)
+    # Bad command codes
+    cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
+    cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC with CCSDS_FC #{n+1}")
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == #{cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{cmd_err_cnt+1}")
+end
diff --git a/gsw/GENERIC_FSS/procedures/tests/generic_fss_ast_test.rb b/gsw/GENERIC_FSS/procedures/tests/generic_fss_ast_test.rb
new file mode 100644
index 0000000..696c0db
--- /dev/null
+++ b/gsw/GENERIC_FSS/procedures/tests/generic_fss_ast_test.rb
@@ -0,0 +1,30 @@
+require 'cosmos'
+require 'cosmos/script'
+require "generic_fss_lib.rb"
+
+##
+## This script tests the cFS component in an automated scenario.
+## Currently this includes: 
+##   Hardware failure
+##   Hardware status reporting fault
+##
+
+
+##
+## Hardware failure
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    # Prepare
+    fss_prepare_ast()
+
+    # Disable sim and confirm device error counts increase
+    dev_cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT")
+    dev_cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
+    fss_sim_disable()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT == #{dev_cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT >= #{dev_cmd_err_cnt}")
+
+    # Enable sim and confirm return to nominal operation
+    fss_sim_enable()
+    confirm_fss_data_loop()
+end
\ No newline at end of file
diff --git a/gsw/GENERIC_FSS/procedures/tests/generic_fss_cpt_test.rb b/gsw/GENERIC_FSS/procedures/tests/generic_fss_cpt_test.rb
deleted file mode 100644
index 1d8acac..0000000
--- a/gsw/GENERIC_FSS/procedures/tests/generic_fss_cpt_test.rb
+++ /dev/null
@@ -1,154 +0,0 @@
-require 'cosmos'
-require 'cosmos/script'
-require "cfs_lib.rb"
-#require 'math'
-
-##
-## NOOP
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Successful Disable
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'", 30)
-
-sleep(5)
-
-##
-## Failed Disable (doubled)
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT > #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'", 30)
-
-sleep(5)
-
-##
-## HK without Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Data without Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Successful Enable
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'", 30)
-
-sleep(5)
-
-##
-## Failed Enable (doubled)
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT > #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'", 30)
-
-sleep(5)
-
-##
-## Housekeeping w/ Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Data w/ Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-
-cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
-
-svb0 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_0")
-svb1 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_1")
-svb2 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_2")
-
-fss_alpha = tlm("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_ALPHA")
-fss_beta = tlm("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_BETA")
-fss_error = tlm("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_ERROR_CODE")
-
-truth_42_alpha = -Math.atan2(svb2, svb0)
-truth_42_beta = Math.atan2(svb1, svb0)
-
-truth_42_alpha_diff = (fss_alpha - truth_42_alpha).abs()
-truth_42_beta_diff = (fss_beta - truth_42_beta).abs()
-diff_margin = 0.025
-
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-if fss_error == 0
-  wait_check_expression("truth_42_alpha_diff <= diff_margin # #{truth_42_alpha_diff} <= #{diff_margin}", 15)
-
-  wait_check_expression("truth_42_beta_diff <= diff_margin # #{truth_42_beta_diff} <= #{diff_margin}", 15)
-end
-
-sleep(5)
-
-##
-## Reset Counters
-##
-cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC") # disable to be able to properly check that device count gets reset
-cmd("GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == 0", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == 0", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT == 0", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == 0", 30)
-
-##
-## Reenable so test can be run multiple times
-##
-cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
\ No newline at end of file
diff --git a/gsw/GENERIC_FSS/procedures/tests/generic_fss_device_test.rb b/gsw/GENERIC_FSS/procedures/tests/generic_fss_device_test.rb
new file mode 100644
index 0000000..2bf5a6e
--- /dev/null
+++ b/gsw/GENERIC_FSS/procedures/tests/generic_fss_device_test.rb
@@ -0,0 +1,46 @@
+require 'cosmos'
+require 'cosmos/script'
+require "generic_fss_lib.rb"
+
+##
+## This script tests the cFS component device functionality.
+## Currently this includes: 
+##   Enable / disable, control hardware communications
+##
+
+
+##
+## Enable / disable, control hardware communications
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    safe_fss() # Get to known state
+
+    # Manually command to disable when already disabled
+    cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
+    cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == #{cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{cmd_err_cnt+1}")
+
+    # Enable
+    enable_fss()
+
+    # Confirm device counters increment without errors
+    confirm_fss_data_loop()
+
+    # Manually command to enable when already enabled
+    cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
+    cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == #{cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{cmd_err_cnt+1}")
+
+    # Reconfirm data remains as expected
+    confirm_fss_data_loop()
+
+    # Disable
+    disable_fss()
+end
+
diff --git a/gsw/GENERIC_FSS/procedures/tests/generic_fss_lpt_test.rb b/gsw/GENERIC_FSS/procedures/tests/generic_fss_lpt_test.rb
deleted file mode 100644
index 1d8acac..0000000
--- a/gsw/GENERIC_FSS/procedures/tests/generic_fss_lpt_test.rb
+++ /dev/null
@@ -1,154 +0,0 @@
-require 'cosmos'
-require 'cosmos/script'
-require "cfs_lib.rb"
-#require 'math'
-
-##
-## NOOP
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Successful Disable
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'", 30)
-
-sleep(5)
-
-##
-## Failed Disable (doubled)
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT > #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'", 30)
-
-sleep(5)
-
-##
-## HK without Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Data without Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Successful Enable
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'", 30)
-
-sleep(5)
-
-##
-## Failed Enable (doubled)
-##
-initial_command_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT > #{initial_command_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT > #{initial_device_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'", 30)
-
-sleep(5)
-
-##
-## Housekeeping w/ Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-
-sleep(5)
-
-##
-## Data w/ Device
-##
-initial_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
-initial_device_error_count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
-
-cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
-
-svb0 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_0")
-svb1 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_1")
-svb2 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_2")
-
-fss_alpha = tlm("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_ALPHA")
-fss_beta = tlm("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_BETA")
-fss_error = tlm("GENERIC_FSS GENERIC_FSS_DATA_TLM GENERIC_FSS_ERROR_CODE")
-
-truth_42_alpha = -Math.atan2(svb2, svb0)
-truth_42_beta = Math.atan2(svb1, svb0)
-
-truth_42_alpha_diff = (fss_alpha - truth_42_alpha).abs()
-truth_42_beta_diff = (fss_beta - truth_42_beta).abs()
-diff_margin = 0.025
-
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{initial_error_count}", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == #{initial_device_error_count}", 30)
-if fss_error == 0
-  wait_check_expression("truth_42_alpha_diff <= diff_margin # #{truth_42_alpha_diff} <= #{diff_margin}", 15)
-
-  wait_check_expression("truth_42_beta_diff <= diff_margin # #{truth_42_beta_diff} <= #{diff_margin}", 15)
-end
-
-sleep(5)
-
-##
-## Reset Counters
-##
-cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC") # disable to be able to properly check that device count gets reset
-cmd("GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC")
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == 0", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == 0", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT == 0", 30)
-wait_check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT == 0", 30)
-
-##
-## Reenable so test can be run multiple times
-##
-cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
\ No newline at end of file
diff --git a/gsw/GENERIC_FSS_SIM_CMD.txt b/gsw/GENERIC_FSS_SIM_CMD.txt
new file mode 100644
index 0000000..45c18f4
--- /dev/null
+++ b/gsw/GENERIC_FSS_SIM_CMD.txt
@@ -0,0 +1,5 @@
+COMMAND SIM_CMDBUS_BRIDGE GENERIC_FSS_SIM_ENABLE BIG_ENDIAN "Enable FSS Sim"
+  APPEND_PARAMETER CMD_TEMPLATE 0 STRING '{"node":"sample-command","cmd":"ENABLE"}'
+
+COMMAND SIM_CMDBUS_BRIDGE GENERIC_FSS_SIM_DISABLE BIG_ENDIAN "Disable FSS Sim"
+  APPEND_PARAMETER CMD_TEMPLATE 0 STRING '{"node":"sample-command","cmd":"DISABLE"}'
\ No newline at end of file


Reviews:
user: login: jlucas9
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-09T19:23:47Z
user: login: zlynch2
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T19:26:30Z
user: login: jlucas9
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T20:07:32Z
user: login: zlynch2
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T22:25:00Z
user: login: zlynch2
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T22:26:01Z
user: login: jlucas9
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T07:50:41Z
user: login: kevincbruce
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T13:27:32Z
user: login: jlucas9
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T17:13:24Z

Review comments:
diff_hunk: @@ -0,0 +1,64 @@
+require 'cosmos'
+require 'cosmos/script'
+require "generic_fss_lib.rb"
+
+##
+## This script tests the standard cFS component application functionality.
+## Currently this includes: 
+##   Housekeeping, request telemetry to be published on the software bus
+##   NOOP, no operation but confirm correct counters increment
+##   Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+
+
+##
+##   Housekeeping, request telemetry to be published on the software bus
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    get_fss_hk()
+end
+
+
+##
+## NOOP, no operation but confirm correct counters increment
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+end
+
+
+##
+## Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+    cmd("GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC") # Note standard `cmd` as we can't reset counters and then confirm increment
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == 0")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == 0")
+end
+
+
+##
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    # Bad length
+    cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
+    cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC with CCSDS_LENGTH #{n+2}") # Note +2 due to CCSDS already being +1
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == #{cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{cmd_err_cnt+1}")
path: gsw/GENERIC_FSS/procedures/tests/generic_fss_app_test.rb
user: login: zlynch2
body: if you dont want to add the +1 you could just set your variable after the command. either way works. Could we abstract the command too? if possible?
created_at: 2025-04-09T19:26:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,64 @@
+require 'cosmos'
+require 'cosmos/script'
+require "generic_fss_lib.rb"
+
+##
+## This script tests the standard cFS component application functionality.
+## Currently this includes: 
+##   Housekeeping, request telemetry to be published on the software bus
+##   NOOP, no operation but confirm correct counters increment
+##   Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+
+
+##
+##   Housekeeping, request telemetry to be published on the software bus
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    get_fss_hk()
+end
+
+
+##
+## NOOP, no operation but confirm correct counters increment
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+end
+
+
+##
+## Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+    cmd("GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC") # Note standard `cmd` as we can't reset counters and then confirm increment
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == 0")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == 0")
+end
+
+
+##
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    # Bad length
+    cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
+    cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC with CCSDS_LENGTH #{n+2}") # Note +2 due to CCSDS already being +1
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == #{cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{cmd_err_cnt+1}")
path: gsw/GENERIC_FSS/procedures/tests/generic_fss_app_test.rb
user: login: jlucas9
body: Think we need to us the regular `cmd` here as we're sending an invalid command and are manually checking the error count goes up.
created_at: 2025-04-09T20:07:32Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,64 @@
+require 'cosmos'
+require 'cosmos/script'
+require "generic_fss_lib.rb"
+
+##
+## This script tests the standard cFS component application functionality.
+## Currently this includes: 
+##   Housekeeping, request telemetry to be published on the software bus
+##   NOOP, no operation but confirm correct counters increment
+##   Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+
+
+##
+##   Housekeeping, request telemetry to be published on the software bus
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    get_fss_hk()
+end
+
+
+##
+## NOOP, no operation but confirm correct counters increment
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+end
+
+
+##
+## Reset counters, increment as done in NOOP and confirm ability to clear repeatably
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    fss_cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC")
+    cmd("GENERIC_FSS GENERIC_FSS_RST_COUNTERS_CC") # Note standard `cmd` as we can't reset counters and then confirm increment
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == 0")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == 0")
+end
+
+
+##
+##   Invalid ground command, confirm bad lengths and codes are rejected
+##
+GENERIC_FSS_TEST_LOOP_COUNT.times do |n|
+    # Bad length
+    cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT")
+    cmd("GENERIC_FSS GENERIC_FSS_NOOP_CC with CCSDS_LENGTH #{n+2}") # Note +2 due to CCSDS already being +1
+    get_fss_hk()
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT == #{cmd_cnt}")
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_ERR_COUNT == #{cmd_err_cnt+1}")
path: gsw/GENERIC_FSS/procedures/tests/generic_fss_app_test.rb
user: login: zlynch2
body: That make sense resolving
created_at: 2025-04-09T22:25:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,132 @@
+# Library for GENERIC_FSS Target
+require 'cosmos'
+require 'cosmos/script'
+
+#
+# Definitions
+#
+GENERIC_FSS_CMD_SLEEP = 0.25
+GENERIC_FSS_RESPONSE_TIMEOUT = 5
+GENERIC_FSS_TEST_LOOP_COUNT = 1
+GENERIC_FSS_DEVICE_LOOP_COUNT = 5
+
+#
+# Functions
+#
+def get_fss_hk()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_HK_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def get_fss_data()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_DATA_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def fss_cmd(*command)
+    count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT") + 1
+
+    if (count == 256)
+        count = 0
+    end
+
+    cmd(*command)
+    get_fss_hk()
+    current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    if (current != count)
+        # Try again
+        cmd(*command)
+        get_fss_hk()
+        current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        if (current != count)
+            # Third times the charm
+            cmd(*command)
+            get_fss_hk()
+            current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        end
+    end
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT >= #{count}")
+end
+
+def enable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'")
+end
+
+def disable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'")
+end
+
+def safe_fss()
+    get_fss_hk()
+    state = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED")
+    if (state != "DISABLED")
+        disable_fss()
+    end
+end
+
+def confirm_fss_data()
+    dev_cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT")
+    dev_cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
+    
+    get_fss_data()
+    svb0 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_0")
path: gsw/GENERIC_FSS/lib/generic_fss_lib.rb
user: login: jlucas9
body: Do we need to check if we're actually in sun here for this to be true?
created_at: 2025-04-10T07:50:41Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,132 @@
+# Library for GENERIC_FSS Target
+require 'cosmos'
+require 'cosmos/script'
+
+#
+# Definitions
+#
+GENERIC_FSS_CMD_SLEEP = 0.25
+GENERIC_FSS_RESPONSE_TIMEOUT = 5
+GENERIC_FSS_TEST_LOOP_COUNT = 1
+GENERIC_FSS_DEVICE_LOOP_COUNT = 5
+
+#
+# Functions
+#
+def get_fss_hk()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_HK_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def get_fss_data()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_DATA_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def fss_cmd(*command)
+    count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT") + 1
+
+    if (count == 256)
+        count = 0
+    end
+
+    cmd(*command)
+    get_fss_hk()
+    current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    if (current != count)
+        # Try again
+        cmd(*command)
+        get_fss_hk()
+        current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        if (current != count)
+            # Third times the charm
+            cmd(*command)
+            get_fss_hk()
+            current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        end
+    end
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT >= #{count}")
+end
+
+def enable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'")
+end
+
+def disable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'")
+end
+
+def safe_fss()
+    get_fss_hk()
+    state = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED")
+    if (state != "DISABLED")
+        disable_fss()
+    end
+end
+
+def confirm_fss_data()
+    dev_cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT")
+    dev_cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
+    
+    get_fss_data()
+    svb0 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_0")
path: gsw/GENERIC_FSS/lib/generic_fss_lib.rb
user: login: kevincbruce
body: If I remember right, checking is-valid should be built into the check.
created_at: 2025-04-10T13:27:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,132 @@
+# Library for GENERIC_FSS Target
+require 'cosmos'
+require 'cosmos/script'
+
+#
+# Definitions
+#
+GENERIC_FSS_CMD_SLEEP = 0.25
+GENERIC_FSS_RESPONSE_TIMEOUT = 5
+GENERIC_FSS_TEST_LOOP_COUNT = 1
+GENERIC_FSS_DEVICE_LOOP_COUNT = 5
+
+#
+# Functions
+#
+def get_fss_hk()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_HK")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_HK_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def get_fss_data()
+    cmd("GENERIC_FSS GENERIC_FSS_REQ_DATA")
+    wait_check_packet("GENERIC_FSS", "GENERIC_FSS_DATA_TLM", 1, GENERIC_FSS_RESPONSE_TIMEOUT)
+    sleep(GENERIC_FSS_CMD_SLEEP)
+end
+
+def fss_cmd(*command)
+    count = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT") + 1
+
+    if (count == 256)
+        count = 0
+    end
+
+    cmd(*command)
+    get_fss_hk()
+    current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+    if (current != count)
+        # Try again
+        cmd(*command)
+        get_fss_hk()
+        current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        if (current != count)
+            # Third times the charm
+            cmd(*command)
+            get_fss_hk()
+            current = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT")
+        end
+    end
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM CMD_COUNT >= #{count}")
+end
+
+def enable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_ENABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'ENABLED'")
+end
+
+def disable_fss()
+    # Send command
+    fss_cmd("GENERIC_FSS GENERIC_FSS_DISABLE_CC")
+    # Confirm
+    check("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED == 'DISABLED'")
+end
+
+def safe_fss()
+    get_fss_hk()
+    state = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ENABLED")
+    if (state != "DISABLED")
+        disable_fss()
+    end
+end
+
+def confirm_fss_data()
+    dev_cmd_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_COUNT")
+    dev_cmd_err_cnt = tlm("GENERIC_FSS GENERIC_FSS_HK_TLM DEVICE_ERR_COUNT")
+    
+    get_fss_data()
+    svb0 = tlm("SIM_42_TRUTH SIM_42_TRUTH_DATA SVB_0")
path: gsw/GENERIC_FSS/lib/generic_fss_lib.rb
user: login: jlucas9
body: Covered by fss_error here
created_at: 2025-04-10T17:13:24Z
author_association: MEMBER

PR comments:
user: login: zlynch2
created_at: 2025-04-09T19:28:22Z
body: Can we use the abstraction of the fss_cmd as defined in the lib? looks like in the other tests we are calling cmd() instead.
author_association: CONTRIBUTOR
user: login: zlynch2
created_at: 2025-04-09T22:25:39Z
body: > Can we use the abstraction of the fss_cmd as defined in the lib? looks like in the other tests we are calling cmd() instead.

we were suppose to use normal cmd() calls for bad commands
author_association: CONTRIBUTOR