From 17068b4c1991806e5bf1512df406c9cb5e217599 Mon Sep 17 00:00:00 2001
From: "Gerardo E. Cruz-Ortiz" <59618057+astrogeco@users.noreply.github.com>
Date: Wed, 7 Apr 2021 21:19:29 -0400
Subject: [PATCH] CaelumReview-CFE40, Add ES files
---
.gitignore | 8 +
modules/core_api/fsw/inc/cfe_es.h | 1635 +++++++++++++
.../core_api/fsw/inc/cfe_es_api_typedefs.h | 193 ++
.../core_api/fsw/inc/cfe_es_core_internal.h | 136 ++
.../core_api/fsw/inc/cfe_es_extern_typedefs.h | 573 +++++
.../fsw/inc/cfe_es_erlog_typedef.h | 98 +
.../fsw/inc/cfe_es_perfdata_typedef.h | 75 +
.../fsw/inc/cfe_es_resetdata_typedef.h | 99 +
modules/es/CMakeLists.txt | 39 +
modules/es/fsw/inc/cfe_es_events.h | 1451 +++++++++++
modules/es/fsw/inc/cfe_es_msg.h | 1570 ++++++++++++
modules/es/fsw/src/cfe_es_api.c | 2136 +++++++++++++++++
modules/es/fsw/src/cfe_es_apps.c | 1819 ++++++++++++++
modules/es/fsw/src/cfe_es_apps.h | 303 +++
modules/es/fsw/src/cfe_es_backgroundtask.c | 230 ++
modules/es/fsw/src/cfe_es_cds.c | 931 +++++++
modules/es/fsw/src/cfe_es_cds.h | 641 +++++
modules/es/fsw/src/cfe_es_cds_mempool.c | 371 +++
modules/es/fsw/src/cfe_es_cds_mempool.h | 78 +
modules/es/fsw/src/cfe_es_erlog.c | 430 ++++
modules/es/fsw/src/cfe_es_generic_pool.c | 676 ++++++
modules/es/fsw/src/cfe_es_generic_pool.h | 283 +++
modules/es/fsw/src/cfe_es_global.h | 239 ++
modules/es/fsw/src/cfe_es_log.h | 361 +++
modules/es/fsw/src/cfe_es_mempool.c | 672 ++++++
modules/es/fsw/src/cfe_es_mempool.h | 200 ++
modules/es/fsw/src/cfe_es_module_all.h | 57 +
modules/es/fsw/src/cfe_es_objtab.c | 137 ++
modules/es/fsw/src/cfe_es_perf.c | 724 ++++++
modules/es/fsw/src/cfe_es_perf.h | 135 ++
modules/es/fsw/src/cfe_es_resource.c | 408 ++++
modules/es/fsw/src/cfe_es_resource.h | 552 +++++
modules/es/fsw/src/cfe_es_start.c | 954 ++++++++
modules/es/fsw/src/cfe_es_start.h | 94 +
modules/es/fsw/src/cfe_es_syslog.c | 556 +++++
modules/es/fsw/src/cfe_es_task.c | 2077 ++++++++++++++++
modules/es/fsw/src/cfe_es_task.h | 129 +
modules/es/fsw/src/cfe_es_verify.h | 337 +++
38 files changed, 21407 insertions(+)
create mode 100644 modules/core_api/fsw/inc/cfe_es.h
create mode 100644 modules/core_api/fsw/inc/cfe_es_api_typedefs.h
create mode 100644 modules/core_api/fsw/inc/cfe_es_core_internal.h
create mode 100644 modules/core_api/fsw/inc/cfe_es_extern_typedefs.h
create mode 100644 modules/core_private/fsw/inc/cfe_es_erlog_typedef.h
create mode 100644 modules/core_private/fsw/inc/cfe_es_perfdata_typedef.h
create mode 100644 modules/core_private/fsw/inc/cfe_es_resetdata_typedef.h
create mode 100644 modules/es/CMakeLists.txt
create mode 100644 modules/es/fsw/inc/cfe_es_events.h
create mode 100644 modules/es/fsw/inc/cfe_es_msg.h
create mode 100644 modules/es/fsw/src/cfe_es_api.c
create mode 100644 modules/es/fsw/src/cfe_es_apps.c
create mode 100644 modules/es/fsw/src/cfe_es_apps.h
create mode 100644 modules/es/fsw/src/cfe_es_backgroundtask.c
create mode 100644 modules/es/fsw/src/cfe_es_cds.c
create mode 100644 modules/es/fsw/src/cfe_es_cds.h
create mode 100644 modules/es/fsw/src/cfe_es_cds_mempool.c
create mode 100644 modules/es/fsw/src/cfe_es_cds_mempool.h
create mode 100644 modules/es/fsw/src/cfe_es_erlog.c
create mode 100644 modules/es/fsw/src/cfe_es_generic_pool.c
create mode 100644 modules/es/fsw/src/cfe_es_generic_pool.h
create mode 100644 modules/es/fsw/src/cfe_es_global.h
create mode 100644 modules/es/fsw/src/cfe_es_log.h
create mode 100644 modules/es/fsw/src/cfe_es_mempool.c
create mode 100644 modules/es/fsw/src/cfe_es_mempool.h
create mode 100644 modules/es/fsw/src/cfe_es_module_all.h
create mode 100644 modules/es/fsw/src/cfe_es_objtab.c
create mode 100644 modules/es/fsw/src/cfe_es_perf.c
create mode 100644 modules/es/fsw/src/cfe_es_perf.h
create mode 100644 modules/es/fsw/src/cfe_es_resource.c
create mode 100644 modules/es/fsw/src/cfe_es_resource.h
create mode 100644 modules/es/fsw/src/cfe_es_start.c
create mode 100644 modules/es/fsw/src/cfe_es_start.h
create mode 100644 modules/es/fsw/src/cfe_es_syslog.c
create mode 100644 modules/es/fsw/src/cfe_es_task.c
create mode 100644 modules/es/fsw/src/cfe_es_task.h
create mode 100644 modules/es/fsw/src/cfe_es_verify.h
diff --git a/.gitignore b/.gitignore
index 5a17b9313..637b047dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,11 @@
!modules/core_api/fsw/inc/cfe_endian.h
!modules/core_api/fsw/inc/cfe_error.h
!modules/core_api/fsw/inc/cfe_version.h
+
+# ES
+!modules/core_api/fsw/inc/cfe_es*
+!modules/core_private/fsw/inc/cfe_es*
+
+!modules/es/fsw/**
+
+!modules/es/CMakeLists.txt
diff --git a/modules/core_api/fsw/inc/cfe_es.h b/modules/core_api/fsw/inc/cfe_es.h
new file mode 100644
index 000000000..3af8c2f6d
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_es.h
@@ -0,0 +1,1635 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * Unit specification for Executive Services library functions and macros.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_H
+#define CFE_ES_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_error.h"
+#include "cfe_es_api_typedefs.h"
+
+/*
+** The OS_PRINTF macro may be defined by OSAL to enable
+** printf-style argument checking. If using a version of OSAL
+** that does not define this then define it as a no-op.
+*/
+#ifndef OS_PRINTF
+#define OS_PRINTF(m, n)
+#endif
+
+/*
+** Macro Definitions
+*/
+
+#define CFE_ES_DBIT(x) (1L << (x)) /* Places a one at bit positions 0 thru 31 */
+#define CFE_ES_DTEST(i, x) (((i)&CFE_ES_DBIT(x)) != 0) /* true iff bit x of i is set */
+#define CFE_ES_TEST_LONG_MASK(m, s) \
+ (CFE_ES_DTEST(m[(s) / 32], (s) % 32)) /* Test a bit within an array of 32-bit integers. */
+
+/*****************************************************************************/
+/*
+** Exported Functions
+*/
+
+/*****************************************************************************/
+
+/** @defgroup CFEAPIESResourceID cFE Resource ID APIs
+ * @{
+ */
+
+/**
+ * @brief Obtain an index value correlating to an ES Application ID
+ *
+ * This calculates a zero based integer value that may be used for indexing
+ * into a local resource table/array.
+ *
+ * Index values are only guaranteed to be unique for resources of the same
+ * type. For instance, the indices corresponding to two [valid] application
+ * IDs will never overlap, but the index of an application and a library ID
+ * may be the same. Furthermore, indices may be reused if a resource is
+ * deleted and re-created.
+ *
+ * @note There is no inverse of this function - indices cannot be converted
+ * back to the original AppID value. The caller should retain the original ID
+ * for future use.
+ *
+ * @param[in] AppID Application ID to convert
+ * @param[out] Idx Buffer where the calculated index will be stored
+ *
+ * @return Execution status, see @ref CFEReturnCodes
+ * @retval #CFE_SUCCESS @copybrief CFE_SUCCESS
+ * @retval #CFE_ES_ERR_RESOURCEID_NOT_VALID @copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+ */
+CFE_Status_t CFE_ES_AppID_ToIndex(CFE_ES_AppId_t AppID, uint32 *Idx);
+
+/**
+ * @brief Obtain an index value correlating to an ES Library ID
+ *
+ * This calculates a zero based integer value that may be used for indexing
+ * into a local resource table/array.
+ *
+ * Index values are only guaranteed to be unique for resources of the same
+ * type. For instance, the indices corresponding to two [valid] Library
+ * IDs will never overlap, but the index of an Library and a library ID
+ * may be the same. Furthermore, indices may be reused if a resource is
+ * deleted and re-created.
+ *
+ * @note There is no inverse of this function - indices cannot be converted
+ * back to the original LibID value. The caller should retain the original ID
+ * for future use.
+ *
+ * @param[in] LibID Library ID to convert
+ * @param[out] Idx Buffer where the calculated index will be stored
+ *
+ * @return Execution status, see @ref CFEReturnCodes
+ * @retval #CFE_SUCCESS @copybrief CFE_SUCCESS
+ * @retval #CFE_ES_ERR_RESOURCEID_NOT_VALID @copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+ */
+int32 CFE_ES_LibID_ToIndex(CFE_ES_LibId_t LibID, uint32 *Idx);
+
+/**
+ * @brief Obtain an index value correlating to an ES Task ID
+ *
+ * This calculates a zero based integer value that may be used for indexing
+ * into a local resource table/array.
+ *
+ * Index values are only guaranteed to be unique for resources of the same
+ * type. For instance, the indices corresponding to two [valid] Task
+ * IDs will never overlap, but the index of an Task and a library ID
+ * may be the same. Furthermore, indices may be reused if a resource is
+ * deleted and re-created.
+ *
+ * @note There is no inverse of this function - indices cannot be converted
+ * back to the original TaskID value. The caller should retain the original ID
+ * for future use.
+ *
+ * @param[in] TaskID Task ID to convert
+ * @param[out] Idx Buffer where the calculated index will be stored
+ *
+ * @return Execution status, see @ref CFEReturnCodes
+ * @retval #CFE_SUCCESS @copybrief CFE_SUCCESS
+ * @retval #CFE_ES_ERR_RESOURCEID_NOT_VALID @copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+ */
+CFE_Status_t CFE_ES_TaskID_ToIndex(CFE_ES_TaskId_t TaskID, uint32 *Idx);
+
+/**
+ * @brief Obtain an index value correlating to an ES Counter ID
+ *
+ * This calculates a zero based integer value that may be used for indexing
+ * into a local resource table/array.
+ *
+ * Index values are only guaranteed to be unique for resources of the same
+ * type. For instance, the indices corresponding to two [valid] Counter
+ * IDs will never overlap, but the index of an Counter and a library ID
+ * may be the same. Furthermore, indices may be reused if a resource is
+ * deleted and re-created.
+ *
+ * @note There is no inverse of this function - indices cannot be converted
+ * back to the original CounterID value. The caller should retain the original ID
+ * for future use.
+ *
+ * @param[in] CounterID Counter ID to convert
+ * @param[out] Idx Buffer where the calculated index will be stored
+ *
+ * @return Execution status, see @ref CFEReturnCodes
+ * @retval #CFE_SUCCESS @copybrief CFE_SUCCESS
+ * @retval #CFE_ES_ERR_RESOURCEID_NOT_VALID @copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+ */
+CFE_Status_t CFE_ES_CounterID_ToIndex(CFE_ES_CounterId_t CounterID, uint32 *Idx);
+
+/** @} */
+
+/*****************************************************************************/
+
+/** @defgroup CFEAPIESEntryExit cFE Entry/Exit APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief cFE Main Entry Point used by Board Support Package to start cFE
+**
+** \par Description
+** cFE main entry point. This is the entry point into the cFE software.
+** It is called only by the Board Support Package software.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] StartType Identifies whether this was a #CFE_PSP_RST_TYPE_POWERON or #CFE_PSP_RST_TYPE_PROCESSOR.
+**
+** \param[in] StartSubtype Specifies, in more detail, what caused the \c StartType identified above.
+** See #CFE_PSP_RST_SUBTYPE_POWER_CYCLE for possible examples.
+**
+** \param[in] ModeId Identifies the source of the Boot as determined by the BSP.
+**
+** \param[in] StartFilePath Identifies the startup file to use to initialize the cFE apps.
+**
+** \sa #CFE_ES_ResetCFE
+**
+******************************************************************************/
+void CFE_ES_Main(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const char *StartFilePath);
+
+/*****************************************************************************/
+/**
+** \brief Reset the cFE Core and all cFE Applications
+**
+** \par Description
+** This API causes an immediate reset of the cFE Kernel and all cFE Applications.
+** The caller can specify whether the reset should clear all memory (#CFE_PSP_RST_TYPE_POWERON)
+** or try to retain volatile memory areas (#CFE_PSP_RST_TYPE_PROCESSOR).
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] ResetType Identifies the type of reset desired. Allowable settings are:
+** \arg #CFE_PSP_RST_TYPE_POWERON - Causes all memory to be cleared
+** \arg #CFE_PSP_RST_TYPE_PROCESSOR - Attempts to retain volatile disk, critical data store
+** and user reserved memory.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+** \retval #CFE_ES_NOT_IMPLEMENTED \copybrief CFE_ES_NOT_IMPLEMENTED
+**
+** \sa #CFE_ES_Main
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_ResetCFE(uint32 ResetType);
+/**@}*/
+
+/** @defgroup CFEAPIESAppControl cFE Application Control APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Restart a single cFE Application
+**
+** \par Description
+** This API causes a cFE Application to be unloaded and restarted
+** from the same file name as the last start.
+**
+** \par Assumptions, External Events, and Notes:
+** The filename is checked for existance prior to load. A missing file
+** will be reported and the reload operation will be aborted prior
+** to unloading the app.
+**
+** Goes through the standard CFE_ES_CleanUpApp which unloads,
+** then attempts a load using the original file name.
+**
+** In the event that an application cannot be reloaded due to a
+** missing file or any other load issue, the application may no longer be
+** restarted or reloaded when given a valid load file (the app has been
+** deleted and no longer exists). To recover, the application
+** may be started by loading the application via the ES_STARTAPP
+** command (#CFE_ES_START_APP_CC).
+**
+** \param[in] AppID Identifies the application to be reset.
+**
+** \return Execution status, see \ref CFEReturnCodes
+**
+** \sa #CFE_ES_ReloadApp, #CFE_ES_DeleteApp
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_RestartApp(CFE_ES_AppId_t AppID);
+
+/*****************************************************************************/
+/**
+** \brief Reload a single cFE Application
+**
+** \par Description
+** This API causes a cFE Application to be stopped and restarted from
+** the specified file.
+**
+** \par Assumptions, External Events, and Notes:
+** The filename is checked for existance prior to load. A missing file
+** will be reported and the reload operation will be aborted prior
+** to unloading the app.
+**
+** Goes through the standard CFE_ES_CleanUpApp which unloads,
+** then attempts a load using the specified file name.
+**
+** In the event that an application cannot be reloaded due to
+** a corrupt file, the application may no longer be reloaded when given a valid
+** load file (it has been deleted and no longer exists). To recover, the
+** application may be started by loading the application via the ES_STARTAPP
+** command (#CFE_ES_START_APP_CC).
+**
+** \param[in] AppID Identifies the application to be reset.
+**
+** \param[in] AppFileName Identifies the new file to start.
+**
+** \return Execution status, see \ref CFEReturnCodes
+**
+** \sa #CFE_ES_RestartApp, #CFE_ES_DeleteApp, #CFE_ES_START_APP_CC
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_ReloadApp(CFE_ES_AppId_t AppID, const char *AppFileName);
+
+/*****************************************************************************/
+/**
+** \brief Delete a cFE Application
+**
+** \par Description
+** This API causes a cFE Application to be stopped deleted.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] AppID Identifies the application to be reset.
+**
+** \return Execution status, see \ref CFEReturnCodes
+**
+** \sa #CFE_ES_RestartApp, #CFE_ES_ReloadApp
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_DeleteApp(CFE_ES_AppId_t AppID);
+/**@}*/
+
+/** @defgroup CFEAPIESAppBehavior cFE Application Behavior APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Exit a cFE Application
+**
+** \par Description
+** This API is the "Exit Point" for the cFE application
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] ExitStatus Acceptable values are: \arg #CFE_ES_RunStatus_APP_EXIT - \copybrief CFE_ES_RunStatus_APP_EXIT
+** \arg #CFE_ES_RunStatus_APP_ERROR - \copybrief CFE_ES_RunStatus_APP_ERROR
+** \arg #CFE_ES_RunStatus_CORE_APP_INIT_ERROR - \copybrief CFE_ES_RunStatus_CORE_APP_INIT_ERROR
+** \arg #CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR - \copybrief CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR
+**
+**
+** \sa #CFE_ES_RunLoop
+**
+******************************************************************************/
+void CFE_ES_ExitApp(uint32 ExitStatus);
+
+/*****************************************************************************/
+/**
+** \brief Check for Exit, Restart, or Reload commands
+**
+** \par Description
+** This is the API that allows an app to check for exit requests from
+** the system.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] ExitStatus A pointer to a variable containing the Application's
+** desired run status. Acceptable values are:
+** \arg #CFE_ES_RunStatus_APP_RUN - \copybrief CFE_ES_RunStatus_APP_RUN
+** \arg #CFE_ES_RunStatus_APP_EXIT - \copybrief CFE_ES_RunStatus_APP_EXIT
+** \arg #CFE_ES_RunStatus_APP_ERROR - \copybrief CFE_ES_RunStatus_APP_ERROR
+**
+** \return Boolean indicating application should continue running
+** \retval true Application should continue running
+** \retval false Application should not continue running
+**
+** \sa #CFE_ES_ExitApp
+**
+******************************************************************************/
+bool CFE_ES_RunLoop(uint32 *ExitStatus);
+
+/*****************************************************************************/
+/**
+** \brief Allow an Application to Wait for a minimum global system state
+**
+** \par Description
+** This is the API that allows an app to wait for the rest of the apps
+** to complete a given stage of initialization before continuing.
+**
+** This gives finer grained control than #CFE_ES_WaitForStartupSync
+**
+** \par Assumptions, External Events, and Notes:
+** This API assumes that the caller has also been initialized sufficiently
+** to satisfy the global system state it is waiting for, and the apps own
+** state will be updated accordingly.
+**
+** \param[in] TimeOutMilliseconds The timeout value in Milliseconds.
+** This parameter must be at least 1000. Lower values
+** will be rounded up. There is not an option to
+** wait indefinitely to avoid hanging a critical
+** application because a non-critical app did not start.
+**
+** \param[in] MinSystemState Determine the state of the App
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS State successfully achieved
+** \retval #CFE_ES_OPERATION_TIMED_OUT Timeout was reached
+**
+** \sa #CFE_ES_RunLoop
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_WaitForSystemState(uint32 MinSystemState, uint32 TimeOutMilliseconds);
+
+/*****************************************************************************/
+/**
+** \brief Allow an Application to Wait for the "OPERATIONAL" global system state
+**
+** \par Description
+** This is the API that allows an app to wait for the rest of the apps
+** to complete their entire initialization before continuing. It is most
+** useful for applications such as Health and Safety or the Scheduler that need
+** to wait until applications exist and are running before sending out
+** packets to them.
+**
+** This is a specialized wrapper for CFE_ES_WaitForSystemState for compatibility
+** with applications using this API.
+**
+** \par Assumptions, External Events, and Notes:
+** This API should only be called as the last item of an Apps initialization.
+** In addition, this API should only be called by an App that is started
+** from the ES Startup file. It should not be used by an App that is
+** started after the system is running. ( Although it will cause no harm )
+**
+** \param[in] TimeOutMilliseconds The timeout value in Milliseconds.
+** This parameter must be at least 1000. Lower values
+** will be rounded up. There is not an option to
+** wait indefinitely to avoid hanging a critical
+** application because a non-critical app did not start.
+**
+** \sa #CFE_ES_RunLoop
+**
+******************************************************************************/
+void CFE_ES_WaitForStartupSync(uint32 TimeOutMilliseconds);
+
+/*****************************************************************************/
+/**
+** \ingroup CFEAPIESAppBehavior
+** \brief Increments the execution counter for the calling task
+**
+** \par Description
+** This routine increments the execution counter that is stored for
+** the calling task. It can be called from cFE Application main tasks, child
+** tasks, or cFE Core application main tasks. Normally, the call is not
+** necessary from a cFE Application, since the CFE_ES_RunLoop call increments
+** the counter for the Application.
+**
+** \par Assumptions, External Events, and Notes:
+** NOTE: This API is not needed for Appplications that call the CFE_ES_RunLoop call.
+**
+** \sa #CFE_ES_RunLoop
+**
+******************************************************************************/
+void CFE_ES_IncrementTaskCounter(void);
+/**@}*/
+
+/** @defgroup CFEAPIESInfo cFE Information APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Return the most recent Reset Type
+**
+** \par Description
+** Provides the caller with codes that identifies the type of Reset
+** the processor most recently underwent. The caller can also obtain
+** information on what caused the reset by supplying a pointer to a
+** variable that will be filled with the Reset Sub-Type.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in, out] ResetSubtypePtr Pointer to \c uint32 type variable in which the Reset Sub-Type will be stored.
+** The caller can set this pointer to NULL if the Sub-Type is of no interest. \n
+** ResetSubtypePtr If the provided pointer was not \c NULL, the Reset Sub-Type is
+** stored at the given address. For a list of possible Sub-Type values, see \link
+** #CFE_PSP_RST_SUBTYPE_POWER_CYCLE "Reset Sub-Types" \endlink.
+**
+** \return Processor reset type
+** \retval #CFE_PSP_RST_TYPE_POWERON \copybrief CFE_PSP_RST_TYPE_POWERON
+** \retval #CFE_PSP_RST_TYPE_PROCESSOR \copybrief CFE_PSP_RST_TYPE_PROCESSOR
+**
+** \sa #CFE_ES_GetAppID, #CFE_ES_GetAppIDByName, #CFE_ES_GetAppName, #CFE_ES_GetTaskInfo
+**
+******************************************************************************/
+int32 CFE_ES_GetResetType(uint32 *ResetSubtypePtr);
+
+/*****************************************************************************/
+/**
+** \brief Get an Application ID for the calling Application
+**
+** \par Description
+** This routine retrieves the cFE Application ID for the calling Application.
+**
+** \par Assumptions, External Events, and Notes:
+** NOTE: \b All tasks associated with the Application would return the same Application ID.
+**
+** \param[out] AppIdPtr Pointer to variable that is to receive the Application's ID.
+** *AppIdPtr will be set to the application ID of the calling Application.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetResetType, #CFE_ES_GetAppIDByName, #CFE_ES_GetAppName, #CFE_ES_GetTaskInfo
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetAppID(CFE_ES_AppId_t *AppIdPtr);
+
+/*****************************************************************************/
+/**
+** \brief Get the task ID of the calling context
+**
+** \par Description
+** This retrieves the current task context from OSAL
+**
+** \par Assumptions, External Events, and Notes:
+** Applications which desire to call other CFE ES services such as
+** CFE_ES_TaskGetInfo() should use this API rather than getting the ID
+** from OSAL directly via OS_TaskGetId().
+**
+** \param[out] TaskIdPtr Pointer to variable that is to receive the ID.
+** Will be set to the ID of the calling task.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetTaskID(CFE_ES_TaskId_t *TaskIdPtr);
+
+/*****************************************************************************/
+/**
+** \brief Get an Application ID associated with a specified Application name
+**
+** \par Description
+** This routine retrieves the cFE Application ID associated with a
+** specified Application name.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] AppIdPtr Pointer to variable that is to receive the Application's ID.
+** \param[in] AppName Pointer to null terminated character string containing an Application name.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_NAME_NOT_FOUND \copybrief CFE_ES_ERR_NAME_NOT_FOUND
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetAppID, #CFE_ES_GetAppName, #CFE_ES_GetAppInfo
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetAppIDByName(CFE_ES_AppId_t *AppIdPtr, const char *AppName);
+
+/*****************************************************************************/
+/**
+** \brief Get a Library ID associated with a specified Library name
+**
+** \par Description
+** This routine retrieves the cFE Library ID associated with a
+** specified Library name.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] LibIdPtr Pointer to variable that is to receive the Library's ID.
+** \param[in] LibName Pointer to null terminated character string containing a Library name.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_NAME_NOT_FOUND \copybrief CFE_ES_ERR_NAME_NOT_FOUND
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetLibName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetLibIDByName(CFE_ES_LibId_t *LibIdPtr, const char *LibName);
+
+/*****************************************************************************/
+/**
+** \brief Get an Application name for a specified Application ID
+**
+** \par Description
+** This routine retrieves the cFE Application name associated with a
+** specified Application ID.
+**
+** \par Assumptions, External Events, and Notes:
+** In the case of a failure (#CFE_ES_ERR_RESOURCEID_NOT_VALID), an empty string is returned.
+**
+** \param[out] AppName Pointer to a character array of at least \c BufferLength in size that will
+** be filled with the appropriate Application name.
+**
+** \param[in] AppId Application ID of Application whose name is being requested.
+**
+** \param[in] BufferLength The maximum number of characters, including the null terminator, that can be put
+** into the \c AppName buffer. This routine will truncate the name to this length,
+** if necessary.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetAppID, #CFE_ES_GetAppIDByName, #CFE_ES_GetAppInfo
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetAppName(char *AppName, CFE_ES_AppId_t AppId, size_t BufferLength);
+
+/*****************************************************************************/
+/**
+** \brief Get a Library name for a specified Library ID
+**
+** \par Description
+** This routine retrieves the cFE Library name associated with a
+** specified Library ID.
+**
+** \par Assumptions, External Events, and Notes:
+** In the case of a failure (#CFE_ES_ERR_RESOURCEID_NOT_VALID), an empty string is returned.
+**
+** \param[out] LibName Pointer to a character array of at least \c BufferLength in size that will
+** be filled with the Library name.
+**
+** \param[in] LibId Library ID of Library whose name is being requested.
+**
+** \param[in] BufferLength The maximum number of characters, including the null terminator, that can be put
+** into the \c LibName buffer. This routine will truncate the name to this length,
+** if necessary.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetLibIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetLibName(char *LibName, CFE_ES_LibId_t LibId, size_t BufferLength);
+
+/*****************************************************************************/
+/**
+** \brief Get Application Information given a specified App ID
+**
+** \par Description
+** This routine retrieves the information about an App associated with a
+** specified App ID. The information includes all of the information ES
+** maintains for an application ( documented in the CFE_ES_AppInfo_t type )
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] AppInfo Pointer to a structure that will be filled with
+** resource name and memory addresses information.
+** \param[in] AppId ID of application to obtain information about
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetAppID, #CFE_ES_GetAppIDByName, #CFE_ES_GetAppName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetAppInfo(CFE_ES_AppInfo_t *AppInfo, CFE_ES_AppId_t AppId);
+
+/*****************************************************************************/
+/**
+** \brief Get Task Information given a specified Task ID
+**
+** \par Description
+** This routine retrieves the information about a Task associated with a
+** specified Task ID. The information includes Task Name, and Parent/Creator
+** Application ID.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] TaskInfo Pointer to a \c CFE_ES_TaskInfo_t structure that holds the specific
+** task information. *TaskInfo is the filled out \c CFE_ES_TaskInfo_t structure containing
+** the Task Name, Parent App Name, Parent App ID among other fields.
+**
+** \param[in] TaskId Application ID of Application whose name is being requested.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetTaskID, #CFE_ES_GetTaskIDByName, #CFE_ES_GetTaskName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetTaskInfo(CFE_ES_TaskInfo_t *TaskInfo, CFE_ES_TaskId_t TaskId);
+
+/*****************************************************************************/
+/**
+** \brief Get Library Information given a specified Resource ID
+**
+** \par Description
+** This routine retrieves the information about a Library
+** associated with a specified ID. The information includes all of the
+** information ES maintains for this resource type ( documented in
+** the CFE_ES_AppInfo_t type ).
+**
+** This shares the same output structure as CFE_ES_GetAppInfo, such that
+** informational commands can be executed against either applications or
+** libraries. When applied to a library, the task information in the
+** structure will be omitted, as libraries do not have tasks associated.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] LibInfo Pointer to a structure that will be filled with
+** resource name and memory addresses information.
+** \param[in] LibId ID of application to obtain information about
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetLibIDByName, #CFE_ES_GetLibName
+**
+******************************************************************************/
+int32 CFE_ES_GetLibInfo(CFE_ES_AppInfo_t *LibInfo, CFE_ES_LibId_t LibId);
+
+/*****************************************************************************/
+/**
+** \brief Get Information given a specified Resource ID
+**
+** \par Description
+** This routine retrieves the information about an Application or Library
+** associated with a specified ID.
+**
+** This is a wrapper API that in turn calls either CFE_ES_GetAppInfo or
+** CFE_ES_GetLibInfo if passed an AppId or LibId, respectively.
+**
+** This allows commands originally targeted to operate on AppIDs to be
+** easily ported to operate on either Libraries or Applications, where
+** relevant.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] ModuleInfo Pointer to a structure that will be filled with
+** resource name and memory addresses information.
+** \param[in] ResourceId ID of application or library to obtain information about
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetLibInfo, #CFE_ES_GetAppInfo
+**
+******************************************************************************/
+int32 CFE_ES_GetModuleInfo(CFE_ES_AppInfo_t *ModuleInfo, CFE_ResourceId_t ResourceId);
+
+/**@}*/
+
+/** @defgroup CFEAPIESChildTask cFE Child Task APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Creates a new task under an existing Application
+**
+** \par Description
+** This routine creates a new task (a separate execution thread) owned by the calling Application.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in, out] TaskIdPtr A pointer to a variable that will be filled in with the new task's ID. *TaskIdPtr is
+** the Task ID of the newly created child task.
+**
+** \param[in] TaskName A pointer to a string containing the desired name of the new task.
+** This can be up to #OS_MAX_API_NAME characters, including the trailing null.
+**
+** \param[in] FunctionPtr A pointer to the function that will be spawned as a new task. This function
+** must have the following signature: uint32 function(void). Input parameters
+** for the new task are not supported.
+**
+** \param[in] StackPtr A pointer to the location where the child task's stack pointer should start.
+** NOTE: Not all underlying operating systems support this parameter.
+** The CFE_ES_TASK_STACK_ALLOCATE constant may be passed to indicate that the
+** stack should be dynamically allocated.
+**
+** \param[in] StackSize The number of bytes to allocate for the new task's stack.
+**
+** \param[in] Priority The priority for the new task. Lower numbers are higher priority, with 0 being
+** the highest priority. Applications cannot create tasks with a higher priority
+** (lower number) than their own priority.
+**
+** \param[in] Flags Reserved for future expansion.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_CHILD_TASK_CREATE \copybrief CFE_ES_ERR_CHILD_TASK_CREATE
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_DeleteChildTask, #CFE_ES_ExitChildTask
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_CreateChildTask(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName,
+ CFE_ES_ChildTaskMainFuncPtr_t FunctionPtr, CFE_ES_StackPointer_t StackPtr,
+ size_t StackSize, CFE_ES_TaskPriority_Atom_t Priority, uint32 Flags);
+
+/*****************************************************************************/
+/**
+** \brief Get a Task ID associated with a specified Task name
+**
+** \par Description
+** This routine retrieves the cFE Task ID associated with a
+** specified Task name.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] TaskIdPtr Pointer to variable that is to receive the Task's ID.
+** \param[in] TaskName Pointer to null terminated character string containing an Task name.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_NAME_NOT_FOUND \copybrief CFE_ES_ERR_NAME_NOT_FOUND
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetTaskName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetTaskIDByName(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName);
+
+/*****************************************************************************/
+/**
+** \brief Get a Task name for a specified Task ID
+**
+** \par Description
+** This routine retrieves the cFE Task name associated with a
+** specified Task ID.
+**
+** \par Assumptions, External Events, and Notes:
+** In the case of a failure (#CFE_ES_ERR_RESOURCEID_NOT_VALID), an empty string is returned.
+**
+** \param[out] TaskName Pointer to a character array of at least \c BufferLength in size that will
+** be filled with the Task name.
+**
+** \param[in] TaskId Task ID of Task whose name is being requested.
+**
+** \param[in] BufferLength The maximum number of characters, including the null terminator, that can be put
+** into the \c TaskName buffer. This routine will truncate the name to this length,
+** if necessary.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetTaskIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetTaskName(char *TaskName, CFE_ES_TaskId_t TaskId, size_t BufferLength);
+
+/*****************************************************************************/
+/**
+** \brief Deletes a task under an existing Application
+**
+** \par Description
+** This routine deletes a task under an Application specified by the \c TaskId obtained
+** when the child task was created using the #CFE_ES_CreateChildTask API.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] TaskId The task ID previously obtained when the Child Task was created with the
+*#CFE_ES_CreateChildTask API.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_NOT_IMPLEMENTED \copybrief CFE_ES_NOT_IMPLEMENTED
+**
+** \sa #CFE_ES_CreateChildTask, #CFE_ES_ExitChildTask
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_DeleteChildTask(CFE_ES_TaskId_t TaskId);
+
+/*****************************************************************************/
+/**
+** \brief Exits a child task
+**
+** \par Description
+** This routine allows the current executing child task to exit and
+** be deleted by ES.
+**
+** \par Assumptions, External Events, and Notes:
+** This function cannot be called from an Application's Main Task.
+**
+** \note This function does not return a value, but if it does return
+** at all, it is assumed that the Task was either unregistered or
+** this function was called from a cFE Application's main task.
+**
+** \sa #CFE_ES_CreateChildTask, #CFE_ES_DeleteChildTask
+**
+******************************************************************************/
+void CFE_ES_ExitChildTask(void);
+/**@}*/
+
+/** @defgroup CFEAPIESMisc cFE Miscellaneous APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Wakes up the CFE background task
+**
+** \par Description
+** Normally the ES background task wakes up at a periodic interval.
+** Whenever new background work is added, this can be used to wake the task early,
+** which may reduce the delay between adding the job and the job getting processed.
+**
+** \par Assumptions, External Events, and Notes:
+** Note the amount of work that the background task will perform is pro-rated
+** based on the amount of time elapsed since the last wakeup. Waking the task
+** early will not cause the background task to do more work than it otherwise
+** would - it just reduces the delay before work starts initially.
+**
+******************************************************************************/
+void CFE_ES_BackgroundWakeup(void);
+
+/*****************************************************************************/
+/**
+** \brief Write a string to the cFE System Log
+**
+** \par Description
+** This routine writes a formatted string to the cFE system log. This
+** can be used to record very low-level errors that can't be reported
+** using the Event Services. This function is used in place of printf
+** for flight software. It should be used for significant startup events,
+** critical errors, and conditionally compiled debug software.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] SpecStringPtr The format string for the log message.
+** This is similar to the format string for a printf() call.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_SYS_LOG_FULL \copybrief CFE_ES_ERR_SYS_LOG_FULL
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_WriteToSysLog(const char *SpecStringPtr, ...) OS_PRINTF(1, 2);
+
+/*****************************************************************************/
+/**
+** \brief Calculate a CRC on a block of memory
+**
+** \par Description
+** This routine calculates a cyclic redundancy check (CRC) on a block of memory. The CRC algorithm
+** used is determined by the last parameter.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] DataPtr Pointer to the base of the memory block.
+**
+** \param[in] DataLength The number of bytes in the memory block.
+**
+** \param[in] InputCRC A starting value for use in the CRC calculation. This parameter
+** allows the user to calculate the CRC of non-contiguous blocks as
+** a single value. Nominally, the user should set this value to zero.
+**
+** \param[in] TypeCRC One of the following CRC algorithm selections:
+** \arg \c CFE_MISSION_ES_CRC_8 - (Not currently implemented)
+** \arg \c CFE_MISSION_ES_CRC_16 - CRC-16/ARC
+** Polynomial: 0x8005
+** Initialization: 0x0000
+** Reflect Input/Output: true
+** XorOut: 0x0000
+** \arg \c CFE_MISSION_ES_CRC_32 - (not currently implemented)
+**
+** \return The result of the CRC calculation on the specified memory block, or error code \ref CFEReturnCodes
+**
+******************************************************************************/
+uint32 CFE_ES_CalculateCRC(const void *DataPtr, size_t DataLength, uint32 InputCRC, uint32 TypeCRC);
+
+/*****************************************************************************/
+/**
+** \ingroup CFEAPIESMisc
+** \brief Notification that an asynchronous event was detected by the underlying OS/PSP
+**
+** \par Description
+** This hook routine is called from the PSP when an exception or
+** other asynchronous system event occurs
+**
+** \par Assumptions, External Events, and Notes:
+** The PSP must guarantee that this function is only invoked from a
+** context which may use OSAL primitives. In general this means that
+** it shouldn't be _directly_ invoked from an ISR/signal context.
+**
+******************************************************************************/
+void CFE_ES_ProcessAsyncEvent(void);
+
+/**@}*/
+
+/** @defgroup CFEAPIESCritData cFE Critical Data Store APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Reserve space (or re-obtain previously reserved space) in the Critical Data Store (CDS)
+**
+** \par Description
+** This routine allocates a block of memory in the Critical Data Store and associates it with
+** the calling Application. The memory can survive an Application restart as well as a Processor Reset.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in, out] HandlePtr Pointer Application's variable that will contain the CDS Memory Block Handle.
+** HandlePtr is the handle of the CDS block that can be used in
+** #CFE_ES_CopyToCDS and #CFE_ES_RestoreFromCDS.
+**
+** \param[in] BlockSize The number of bytes needed in the CDS.
+**
+** \param[in] Name A pointer to a character string containing an application
+** unique name of #CFE_MISSION_ES_CDS_MAX_NAME_LENGTH characters or less.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS The memory block was successfully created in the CDS.
+** \retval #CFE_ES_NOT_IMPLEMENTED The processor does not support a Critical Data Store.
+** \retval #CFE_ES_CDS_ALREADY_EXISTS \copybrief CFE_ES_CDS_ALREADY_EXISTS
+** \retval #CFE_ES_CDS_INVALID_SIZE \copybrief CFE_ES_CDS_INVALID_SIZE
+** \retval #CFE_ES_CDS_INVALID_NAME \copybrief CFE_ES_CDS_INVALID_NAME
+** \retval #CFE_ES_CDS_REGISTRY_FULL \copybrief CFE_ES_CDS_REGISTRY_FULL
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_CopyToCDS, #CFE_ES_RestoreFromCDS
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_RegisterCDS(CFE_ES_CDSHandle_t *HandlePtr, size_t BlockSize, const char *Name);
+
+/*****************************************************************************/
+/**
+** \brief Get a CDS Block ID associated with a specified CDS Block name
+**
+** \par Description
+** This routine retrieves the CDS Block ID associated with a
+** specified CDS Block name.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[out] BlockIdPtr Pointer to variable that is to receive the CDS Block ID.
+** \param[in] BlockName Pointer to null terminated character string containing a CDS Block name.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_NAME_NOT_FOUND \copybrief CFE_ES_ERR_NAME_NOT_FOUND
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetCDSBlockName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetCDSBlockIDByName(CFE_ES_CDSHandle_t *BlockIdPtr, const char *BlockName);
+
+/*****************************************************************************/
+/**
+** \brief Get a Block name for a specified Block ID
+**
+** \par Description
+** This routine retrieves the cFE Block name associated with a
+** specified Block ID.
+**
+** \par Assumptions, External Events, and Notes:
+** In the case of a failure (#CFE_ES_ERR_RESOURCEID_NOT_VALID), an empty string is returned.
+**
+** \param[out] BlockName Pointer to a character array of at least \c BufferLength in size that will
+** be filled with the CDS Block name.
+**
+** \param[in] BlockId Block ID/Handle of CDS registry entry whose name is being requested.
+**
+** \param[in] BufferLength The maximum number of characters, including the null terminator, that can be put
+** into the \c BlockName buffer. This routine will truncate the name to this length,
+** if necessary.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetCDSBlockIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetCDSBlockName(char *BlockName, CFE_ES_CDSHandle_t BlockId, size_t BufferLength);
+
+/*****************************************************************************/
+/**
+** \brief Save a block of data in the Critical Data Store (CDS)
+**
+** \par Description
+** This routine copies a specified block of memory into the Critical Data Store that
+** had been previously registered via #CFE_ES_RegisterCDS. The block of memory to be
+** copied must be at least as big as the size specified when registering the CDS.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] Handle The handle of the CDS block that was previously obtained from #CFE_ES_RegisterCDS.
+**
+** \param[in] DataToCopy A Pointer to the block of memory to be copied into the CDS.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_RegisterCDS, #CFE_ES_RestoreFromCDS
+**
+*/
+CFE_Status_t CFE_ES_CopyToCDS(CFE_ES_CDSHandle_t Handle, void *DataToCopy);
+
+/*****************************************************************************/
+/**
+** \brief Recover a block of data from the Critical Data Store (CDS)
+**
+** \par Description
+** This routine copies data from the Critical Data Store identified with the \c Handle into
+** the area of memory pointed to by the \c RestoreToMemory pointer. The area of memory to
+** be copied into must be at least as big as the size specified when registering the CDS.
+** The recovery will indicate an error if the data integrity check maintained by the CDS
+** indicates the contents of the CDS have changed. However, the contents will still be
+** copied into the specified area of memory.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] Handle The handle of the CDS block that was previously obtained from #CFE_ES_RegisterCDS.
+**
+** \param[in, out] RestoreToMemory A Pointer to the block of memory that is to be restored with the contents of
+** the CDS. *RestoreToMemory is the contents of the specified CDS.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_CDS_BLOCK_CRC_ERR \copybrief CFE_ES_CDS_BLOCK_CRC_ERR
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_RegisterCDS, #CFE_ES_CopyToCDS
+**
+*/
+CFE_Status_t CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t Handle);
+/**@}*/
+
+/** @defgroup CFEAPIESMemManage cFE Memory Manager APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Initializes a memory pool created by an application without using a semaphore during processing.
+**
+** \par Description
+** This routine initializes a pool of memory supplied by the calling application. When a memory pool
+** created by this routine is processed, no mutex handling is performed.
+**
+** \par Assumptions, External Events, and Notes:
+** -# The size of the pool must be an integral number of 32-bit words
+** -# The start address of the pool must be 32-bit aligned
+** -# 168 bytes are used for internal bookkeeping, therefore, they will not be available for allocation.
+**
+** \param[in, out] PoolID A pointer to the variable the caller wishes to have the memory pool handle kept in.
+** PoolID is the memory pool handle.
+**
+** \param[in] MemPtr A Pointer to the pool of memory created by the calling application. This address must
+** be on a 32-bit boundary.
+**
+** \param[in] Size The size of the pool of memory. Note that this must be an integral number of 32 bit words.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, size_t Size);
+
+/*****************************************************************************/
+/**
+** \brief Initializes a memory pool created by an application while using a semaphore during processing.
+**
+** \par Description
+** This routine initializes a pool of memory supplied by the calling application. When a memory pool
+** created by this routine is processed, mutex handling will be performed.
+**
+** \par Assumptions, External Events, and Notes:
+** -# The size of the pool must be an integral number of 32-bit words
+** -# The start address of the pool must be 32-bit aligned
+** -# 168 bytes are used for internal bookkeeping, therefore, they will not be available for allocation.
+**
+** \param[in, out] PoolID A pointer to the variable the caller wishes to have the memory pool handle kept in.
+** PoolID is the memory pool handle.
+**
+** \param[in] MemPtr A Pointer to the pool of memory created by the calling application. This address must
+** be on a 32-bit boundary.
+**
+** \param[in] Size The size of the pool of memory. Note that this must be an integral number of 32 bit words.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_PoolCreate(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, size_t Size);
+
+/*****************************************************************************/
+/**
+** \brief Initializes a memory pool created by an application with application specified block sizes.
+**
+** \par Description
+** This routine initializes a pool of memory supplied by the calling application.
+**
+** \par Assumptions, External Events, and Notes:
+** -# The size of the pool must be an integral number of 32-bit words
+** -# The start address of the pool must be 32-bit aligned
+** -# 168 bytes are used for internal bookkeeping, therefore, they will not be available for allocation.
+**
+** \param[in, out] PoolID A pointer to the variable the caller wishes to have the memory pool handle kept in.
+** PoolID is the memory pool handle.
+**
+** \param[in] MemPtr A Pointer to the pool of memory created by the calling application. This address must
+** be on a 32-bit boundary.
+**
+** \param[in] Size The size of the pool of memory. Note that this must be an integral number of 32 bit
+** words.
+**
+** \param[in] NumBlockSizes The number of different block sizes specified in the \c BlockSizes array. If set equal to
+** zero or if greater than 17, then default block sizes are used.
+**
+** \param[in] BlockSizes Pointer to an array of sizes to be used instead of the default block sizes specified by
+** #CFE_PLATFORM_ES_MEM_BLOCK_SIZE_01 through #CFE_PLATFORM_ES_MAX_BLOCK_SIZE. If the
+** pointer is equal to NULL, the default block sizes are used.
+**
+** \param[in] UseMutex Flag indicating whether the new memory pool will be processing with mutex handling or
+** not. Valid parameter values are #CFE_ES_USE_MUTEX and #CFE_ES_NO_MUTEX
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, size_t Size, uint16 NumBlockSizes,
+ const size_t *BlockSizes, bool UseMutex);
+
+/*****************************************************************************/
+/**
+** \brief Deletes a memory pool that was previously created
+**
+** \par Description
+** This routine removes the pool ID and frees the global table
+** entry for future re-use.
+**
+** \par Assumptions, External Events, and Notes:
+** All buffers associated with the pool become invalid after this call.
+** The application should ensure that buffers/references to the
+** pool are returned before deleting the pool.
+**
+** \param[in] PoolID The ID of the pool to delete
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+**
+** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats
+**
+******************************************************************************/
+int32 CFE_ES_PoolDelete(CFE_ES_MemHandle_t PoolID);
+
+/*****************************************************************************/
+/**
+** \brief Gets a buffer from the memory pool created by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem
+**
+** \par Description
+** This routine obtains a block of memory from the memory pool supplied by the calling application.
+**
+** \par Assumptions, External Events, and Notes:
+** -# The size allocated from the memory pool is, at a minimum, 12 bytes more than requested.
+**
+** \param[in, out] BufPtr A pointer to the Application's pointer in which will be stored the address of the
+** allocated memory buffer. *BufPtr is the address of the requested buffer.
+**
+** \param[in] PoolID The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem.
+**
+** \param[in] Size The size of the buffer requested. NOTE: The size allocated may be larger.
+**
+** \return Bytes Allocated, or error code \ref CFEReturnCodes
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_ERR_MEM_BLOCK_SIZE \copybrief CFE_ES_ERR_MEM_BLOCK_SIZE
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats,
+*#CFE_ES_GetPoolBufInfo
+**
+******************************************************************************/
+int32 CFE_ES_GetPoolBuf(CFE_ES_MemPoolBuf_t *BufPtr, CFE_ES_MemHandle_t PoolID, size_t Size);
+
+/*****************************************************************************/
+/**
+** \brief Gets info on a buffer previously allocated via #CFE_ES_GetPoolBuf
+**
+** \par Description
+** This routine gets info on a buffer in the memory pool.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] PoolID The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem.
+**
+** \param[in] BufPtr A pointer to the memory buffer to provide status for.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BUFFER_NOT_IN_POOL \copybrief CFE_ES_BUFFER_NOT_IN_POOL
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_GetMemPoolStats,
+*#CFE_ES_PutPoolBuf
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t PoolID, CFE_ES_MemPoolBuf_t BufPtr);
+
+/*****************************************************************************/
+/**
+** \brief Releases a buffer from the memory pool that was previously allocated via #CFE_ES_GetPoolBuf
+**
+** \par Description
+** This routine releases a buffer back into the memory pool.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] PoolID The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem.
+**
+** \param[in] BufPtr A pointer to the memory buffer to be released.
+**
+** \return Bytes released, or error code \ref CFEReturnCodes
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_GetMemPoolStats,
+*#CFE_ES_GetPoolBufInfo
+**
+******************************************************************************/
+int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t PoolID, CFE_ES_MemPoolBuf_t BufPtr);
+
+/*****************************************************************************/
+/**
+** \brief Extracts the statistics maintained by the memory pool software
+**
+** \par Description
+** This routine fills the #CFE_ES_MemPoolStats_t data structure with the statistics
+** maintained by the memory pool software. These statistics can then be telemetered
+** by the calling Application.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in, out] BufPtr Pointer to #CFE_ES_MemPoolStats_t data structure to be
+** filled with memory statistics. *BufPtr is the Memory Pool Statistics stored in given
+** data structure.
+**
+** \param[in] Handle The handle to the memory pool whose statistics are desired.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetMemPoolStats(CFE_ES_MemPoolStats_t *BufPtr, CFE_ES_MemHandle_t Handle);
+/**@}*/
+
+/** @defgroup CFEAPIESPerfMon cFE Performance Monitor APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Entry marker for use with Software Performance Analysis Tool.
+**
+** \par Description
+** This macro logs the entry or start event/marker for the specified
+** entry \c id. This macro, in conjunction with the #CFE_ES_PerfLogExit,
+** is used by the Software Performance Analysis tool (see section 5.15).
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] id Identifier of the specific event or marker.
+**
+** \sa #CFE_ES_PerfLogExit, #CFE_ES_PerfLogAdd
+**
+******************************************************************************/
+#define CFE_ES_PerfLogEntry(id) (CFE_ES_PerfLogAdd(id, 0))
+
+/*****************************************************************************/
+/**
+** \brief Exit marker for use with Software Performance Analysis Tool.
+**
+** \par Description
+** This macro logs the exit or end event/marker for the specified
+** entry \c id. This macro, in conjunction with the #CFE_ES_PerfLogEntry,
+** is used by the Software Performance Analysis tool (see section 5.15).
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] id Identifier of the specific event or marker.
+**
+** \sa #CFE_ES_PerfLogEntry, #CFE_ES_PerfLogAdd
+**
+******************************************************************************/
+#define CFE_ES_PerfLogExit(id) (CFE_ES_PerfLogAdd(id, 1))
+
+/*****************************************************************************/
+/**
+** \brief Function called by #CFE_ES_PerfLogEntry and #CFE_ES_PerfLogExit macros
+**
+** \par Description
+** This function logs the entry and exit marker for the specified
+** \c id. This function is used by the Software Performance Analysis
+** tool (see section 5.15).
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] Marker Identifier of the specific event or marker.
+** \param[in] EntryExit Used to specify Entry(0) or Exit(1)
+**
+** \sa #CFE_ES_PerfLogEntry, #CFE_ES_PerfLogExit
+**
+******************************************************************************/
+void CFE_ES_PerfLogAdd(uint32 Marker, uint32 EntryExit);
+/**@}*/
+
+/** @defgroup CFEAPIESGenCount cFE Generic Counter APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Register a generic counter
+**
+** \par Description
+** This routine registers a generic counter.
+**
+** \par Assumptions, External Events, and Notes:
+** None.
+**
+** \param[in] *CounterName The Name of the generic counter.
+**
+** \param[out] *CounterIdPtr The Counter Id of the newly created counter.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_IncrementGenCounter, #CFE_ES_DeleteGenCounter, #CFE_ES_SetGenCount, #CFE_ES_GetGenCount,
+*#CFE_ES_GetGenCounterIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_RegisterGenCounter(CFE_ES_CounterId_t *CounterIdPtr, const char *CounterName);
+
+/*****************************************************************************/
+/**
+** \brief Delete a generic counter
+**
+** \par Description
+** This routine deletes a previously registered generic counter.
+**
+** \par Assumptions, External Events, and Notes:
+** None.
+**
+** \param[in] CounterId The Counter Id of the newly created counter.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_IncrementGenCounter, #CFE_ES_RegisterGenCounter, #CFE_ES_SetGenCount, #CFE_ES_GetGenCount,
+*#CFE_ES_GetGenCounterIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_DeleteGenCounter(CFE_ES_CounterId_t CounterId);
+
+/*****************************************************************************/
+/**
+** \brief Increments the specified generic counter
+**
+** \par Description
+** This routine increments the specified generic counter.
+**
+** \par Assumptions, External Events, and Notes:
+** None.
+**
+** \param[in] CounterId The Counter to be incremented.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_RegisterGenCounter, #CFE_ES_DeleteGenCounter, #CFE_ES_SetGenCount, #CFE_ES_GetGenCount,
+*#CFE_ES_GetGenCounterIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_IncrementGenCounter(CFE_ES_CounterId_t CounterId);
+
+/*****************************************************************************/
+/**
+** \brief Set the specified generic counter
+**
+** \par Description
+** This routine sets the specified generic counter to the specified value.
+**
+** \par Assumptions, External Events, and Notes:
+** None.
+**
+** \param[in] CounterId The Counter to be set.
+**
+** \param[in] Count The new value of the Counter.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_RegisterGenCounter, #CFE_ES_DeleteGenCounter, #CFE_ES_IncrementGenCounter, #CFE_ES_GetGenCount,
+*#CFE_ES_GetGenCounterIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_SetGenCount(CFE_ES_CounterId_t CounterId, uint32 Count);
+
+/*****************************************************************************/
+/**
+** \brief Get the specified generic counter count
+**
+** \par Description
+** This routine gets the value of a generic counter.
+**
+** \par Assumptions, External Events, and Notes:
+** None.
+**
+** \param[in] CounterId The Counter to get the value from.
+**
+** \param[in] *Count The value of the Counter.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_RegisterGenCounter, #CFE_ES_DeleteGenCounter, #CFE_ES_SetGenCount, #CFE_ES_IncrementGenCounter,
+*#CFE_ES_GetGenCounterIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetGenCount(CFE_ES_CounterId_t CounterId, uint32 *Count);
+
+/*****************************************************************************/
+/**
+** \brief Get the Id associated with a generic counter name
+**
+** \par Description
+** This routine gets the Counter Id for a generic counter specified by name.
+**
+** \par Assumptions, External Events, and Notes:
+** None.
+**
+** \param[out] CounterIdPtr Pointer to variable that is to receive the Counter's ID.
+** \param[in] CounterName Pointer to null terminated character string containing a Counter name.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_NAME_NOT_FOUND \copybrief CFE_ES_ERR_NAME_NOT_FOUND
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetGenCounterName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetGenCounterIDByName(CFE_ES_CounterId_t *CounterIdPtr, const char *CounterName);
+
+/*****************************************************************************/
+/**
+** \brief Get a Counter name for a specified Counter ID
+**
+** \par Description
+** This routine retrieves the cFE Counter name associated with a
+** specified Counter ID.
+**
+** \par Assumptions, External Events, and Notes:
+** In the case of a failure (#CFE_ES_ERR_RESOURCEID_NOT_VALID), an empty string is returned.
+**
+** \param[out] CounterName Pointer to a character array of at least \c BufferLength in size that will
+** be filled with the Counter name.
+**
+** \param[in] CounterId ID of Counter whose name is being requested.
+**
+** \param[in] BufferLength The maximum number of characters, including the null terminator, that can be put
+** into the \c CounterName buffer. This routine will truncate the name to this length,
+** if necessary.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_ES_ERR_RESOURCEID_NOT_VALID \copybrief CFE_ES_ERR_RESOURCEID_NOT_VALID
+** \retval #CFE_ES_BAD_ARGUMENT \copybrief CFE_ES_BAD_ARGUMENT
+**
+** \sa #CFE_ES_GetGenCounterIDByName
+**
+******************************************************************************/
+CFE_Status_t CFE_ES_GetGenCounterName(char *CounterName, CFE_ES_CounterId_t CounterId, size_t BufferLength);
+
+/**@}*/
+
+#endif /* CFE_ES_H */
diff --git a/modules/core_api/fsw/inc/cfe_es_api_typedefs.h b/modules/core_api/fsw/inc/cfe_es_api_typedefs.h
new file mode 100644
index 000000000..d8edef745
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_es_api_typedefs.h
@@ -0,0 +1,193 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * Unit specification for Executive Services library functions and macros.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_API_TYPEDEFS_H
+#define CFE_ES_API_TYPEDEFS_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_es_extern_typedefs.h"
+
+/*
+** Note about reset type and subtypes:
+**
+** These values come from the PSP so the actual definition of these enumerations
+** was moved to the PSP header file .
+**
+** In the future the Electronic Data sheets (EDS) for PSP/ES
+** will define the exact values to use in telemetry messages.
+*/
+
+/*
+** Reset types
+*/
+/** \name Reset Type extensions */
+/** \{ */
+#define CFE_ES_APP_RESTART CFE_PSP_RST_TYPE_MAX /**< Application only was reset (extend the PSP enumeration here) */
+/** \} */
+
+/*****************************************************************************/
+/*
+** Type Definitions
+*/
+
+/*
+** Entry Function Prototypes
+*/
+typedef void (*CFE_ES_TaskEntryFuncPtr_t)(void); /**< \brief Required Prototype of Task Main Functions */
+typedef int32 (*CFE_ES_LibraryEntryFuncPtr_t)(
+ CFE_ES_LibId_t LibId); /**< \brief Required Prototype of Library Initialization Functions */
+
+/**
+ * \brief Compatible typedef for ES child task entry point.
+ *
+ * All ES task functions (main + child) use the same entry point type.
+ */
+typedef CFE_ES_TaskEntryFuncPtr_t CFE_ES_ChildTaskMainFuncPtr_t;
+
+/**
+ * @brief Type for the stack pointer of tasks.
+ *
+ * This type is used in the CFE ES task API.
+ */
+typedef void *CFE_ES_StackPointer_t; /* aka osal_stackptr_t in proposed OSAL change */
+
+/**
+ * \brief Pool Alignement
+ *
+ * Union that can be used for minimum memory alignment of ES memory pools on the target.
+ * It contains the longest native data types such that the alignment of this structure
+ * should reflect the largest possible alignment requirements for any data on this processor.
+ */
+typedef union CFE_ES_PoolAlign
+{
+ void *Ptr; /**< \brief Aligned pointer */
+ /* note -- native types (int/double) are intentional here */
+ long long int LongInt; /**< \brief Aligned Long Integer */
+ long double LongDouble; /**< \brief Aligned Long Double */
+} CFE_ES_PoolAlign_t;
+
+/**
+ * \brief Static Pool Type
+ *
+ * A macro to help instantiate static memory pools that are correctly aligned.
+ * This resolves to a union type that contains a member called "Data" that will
+ * be correctly aligned to be a memory pool and sized according to the argument.
+ */
+#define CFE_ES_STATIC_POOL_TYPE(size) \
+ union \
+ { \
+ CFE_ES_PoolAlign_t Align; \
+ uint8 Data[size]; \
+ }
+
+/**
+ * @brief Pointer type used for memory pool API
+ *
+ * This is used in the Get/Put API calls to refer to a pool buffer.
+ *
+ * This pointer is expected to be type cast to the real object
+ * type after getting a new buffer. Using void* allows this
+ * type conversion to occur easily.
+ *
+ * @note Older versions of CFE implemented the API using a uint32*,
+ * which required explicit type casting everywhere it was called.
+ * Although the API type is now void* to make usage easier, the
+ * pool buffers are aligned to machine requirements - typically 64 bits.
+ */
+typedef void *CFE_ES_MemPoolBuf_t;
+
+/**
+ * @brief Conversion macro to create buffer pointer from another type
+ *
+ * In cases where the actual buffer pointer is computed, this macro
+ * aids in converting the computed address (typically an OSAL "cpuaddr"
+ * type) into a buffer pointer.
+ *
+ * @note Any address calculation needs to take machine alignment
+ * requirements into account.
+ */
+#define CFE_ES_MEMPOOLBUF_C(x) ((CFE_ES_MemPoolBuf_t)(x))
+
+/** \name Conversions for ES resource IDs */
+/** \{ */
+
+/*
+ * Conversion macros for each ES resource ID subtype
+ *
+ * These accept a generic/non-specific CFE_ResourceId_t value
+ * and convert it to the corresponding resource-specific type.
+ *
+ * These should only be used when with the resource ID constants,
+ * or where the code has confirmed or is determining the generic
+ * identifier does correspond to a resource of that type.
+ */
+#define CFE_ES_APPID_C(val) ((CFE_ES_AppId_t)CFE_RESOURCEID_WRAP(val))
+#define CFE_ES_TASKID_C(val) ((CFE_ES_TaskId_t)CFE_RESOURCEID_WRAP(val))
+#define CFE_ES_LIBID_C(val) ((CFE_ES_LibId_t)CFE_RESOURCEID_WRAP(val))
+#define CFE_ES_COUNTERID_C(val) ((CFE_ES_CounterId_t)CFE_RESOURCEID_WRAP(val))
+#define CFE_ES_MEMHANDLE_C(val) ((CFE_ES_MemHandle_t)CFE_RESOURCEID_WRAP(val))
+#define CFE_ES_CDSHANDLE_C(val) ((CFE_ES_CDSHandle_t)CFE_RESOURCEID_WRAP(val))
+
+/** \} */
+
+/** \name Type-specific initalizers for "undefined" resource IDs */
+/** \{ */
+
+#define CFE_ES_APPID_UNDEFINED CFE_ES_APPID_C(CFE_RESOURCEID_UNDEFINED)
+#define CFE_ES_TASKID_UNDEFINED CFE_ES_TASKID_C(CFE_RESOURCEID_UNDEFINED)
+#define CFE_ES_LIBID_UNDEFINED CFE_ES_LIBID_C(CFE_RESOURCEID_UNDEFINED)
+#define CFE_ES_COUNTERID_UNDEFINED CFE_ES_COUNTERID_C(CFE_RESOURCEID_UNDEFINED)
+#define CFE_ES_MEMHANDLE_UNDEFINED CFE_ES_MEMHANDLE_C(CFE_RESOURCEID_UNDEFINED)
+#define CFE_ES_CDS_BAD_HANDLE CFE_ES_CDSHANDLE_C(CFE_RESOURCEID_UNDEFINED)
+/** \} */
+
+/** \name Task Stack Constants */
+/** \{ */
+
+/**
+ * \brief Indicates that the stack for the child task should be dynamically allocated.
+ *
+ * This value may be supplied as the Stack Pointer argument to CFE_ES_ChildTaskCreate()
+ * to indicate that the stack should be dynamically allocated.
+ */
+#define CFE_ES_TASK_STACK_ALLOCATE NULL /* aka OS_TASK_STACK_ALLOCATE in proposed OSAL change */
+/** \} */
+
+#define CFE_ES_NO_MUTEX false /**< \brief Indicates that the memory pool selection will not use a semaphore */
+#define CFE_ES_USE_MUTEX true /**< \brief Indicates that the memory pool selection will use a semaphore */
+
+#endif /* CFE_ES_API_TYPEDEFS_H */
diff --git a/modules/core_api/fsw/inc/cfe_es_core_internal.h b/modules/core_api/fsw/inc/cfe_es_core_internal.h
new file mode 100644
index 000000000..e9e38a4b3
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_es_core_internal.h
@@ -0,0 +1,136 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * Unit specification for Executive Services library functions and macros.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_CORE_INTERNAL_H
+#define CFE_ES_CORE_INTERNAL_H
+
+#include "common_types.h"
+#include "cfe_es_extern_typedefs.h"
+
+/*
+ * The internal APIs prototyped within this block are only intended to be invoked from
+ * other CFE core apps. They still need to be prototyped in the shared header such that
+ * they can be called from other core modules, but applications should not call these.
+ */
+
+/** @defgroup CFEAPIESCoreInternal cFE Internal Executive Service APIs, internal to CFE core
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Entry Point for cFE Core Application
+**
+** \par Description
+** This is the entry point to the cFE ES Core Application.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+******************************************************************************/
+extern void CFE_ES_TaskMain(void);
+
+/*****************************************************************************/
+/**
+** \brief Initializes the cFE core module API Library
+**
+** \par Description
+** Initializes the cFE core module API Library
+**
+** \par Assumptions, External Events, and Notes:
+** -# This function MUST be called before any module API's are called.
+**
+******************************************************************************/
+extern int32 CFE_ES_CDS_EarlyInit(void);
+
+/*****************************************************************************/
+/**
+** \brief Reserve space (or re-obtain previously reserved space) in the Critical Data Store (CDS)
+**
+** \par Description
+** This routine is identical to #CFE_ES_RegisterCDS except it identifies the contents
+** of the CDS as a critical table. This is crucial because a critical table CDS must
+** only be deleted by cFE Table Services, not via an ES delete CDS command. Otherwise,
+** Table Services may be out of sync with the contents of the CDS.
+**
+** \par Assumptions, External Events, and Notes:
+** -# This function assumes input parameters are error free and have met size/value restrictions.
+** -# The calling function is responsible for issuing any event messages associated with errors.
+**
+** \param[in, out] HandlePtr Pointer Application's variable that will contain the CDS Memory Block Handle.
+** HandlePtr is the handle of the CDS block that can be used in #CFE_ES_CopyToCDS and
+** #CFE_ES_RestoreFromCDS.
+**
+** \param[in] UserBlockSize The number of bytes needed in the CDS.
+**
+** \param[in] Name Pointer to character string containing the Application's local name for
+** the CDS.
+**
+** \param[in] CriticalTbl Indicates whether the CDS is to be used as a Critical Table or not
+**
+** \return See return codes for #CFE_ES_RegisterCDS
+**
+******************************************************************************/
+int32 CFE_ES_RegisterCDSEx(CFE_ES_CDSHandle_t *HandlePtr, size_t UserBlockSize, const char *Name, bool CriticalTbl);
+
+/*****************************************************************************/
+/**
+** \brief Deletes the specified CDS from the CDS Registry and frees CDS Memory
+**
+** \par Description
+** Removes the record of the specified CDS from the CDS Registry and
+** frees the associated CDS memory for future use.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] CDSName - Pointer to character string containing complete
+** CDS Name (of the format "AppName.CDSName").
+**
+** \param[in] CalledByTblServices - Flag that identifies whether the CDS is supposed to
+** be a Critical Table Image or not.
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return #CFE_ES_CDS_WRONG_TYPE_ERR \copydoc CFE_ES_CDS_WRONG_TYPE_ERR
+** \return #CFE_ES_CDS_OWNER_ACTIVE_ERR \copydoc CFE_ES_CDS_OWNER_ACTIVE_ERR
+** \return #CFE_ES_ERR_NAME_NOT_FOUND \copydoc CFE_ES_ERR_NAME_NOT_FOUND
+** \return Any of the return values from CFE_ES_UpdateCDSRegistry
+** \return Any of the return values from CFE_ES_GenPoolPutBlock
+**
+******************************************************************************/
+int32 CFE_ES_DeleteCDS(const char *CDSName, bool CalledByTblServices);
+
+/**@}*/
+
+#endif /* CFE_ES_CORE_INTERNAL_H */
diff --git a/modules/core_api/fsw/inc/cfe_es_extern_typedefs.h b/modules/core_api/fsw/inc/cfe_es_extern_typedefs.h
new file mode 100644
index 000000000..b0c70194b
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_es_extern_typedefs.h
@@ -0,0 +1,573 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Declarations and prototypes for cfe_es_extern_typedefs module
+ */
+
+#ifndef CFE_ES_EXTERN_TYPEDEFS_H
+#define CFE_ES_EXTERN_TYPEDEFS_H
+
+/* This header may be generated from an EDS file,
+ * tools are available and the feature is enabled */
+#ifdef CFE_EDS_ENABLED_BUILD
+
+/* Use the EDS generated version of these types */
+#include "cfe_es_eds_typedefs.h"
+
+#else
+/* Use the local definitions of these types */
+
+#include "common_types.h"
+#include "cfe_resourceid_typedef.h"
+#include "cfe_mission_cfg.h"
+
+/**
+ * @brief Label definitions associated with CFE_ES_LogMode_Enum_t
+ */
+enum CFE_ES_LogMode
+{
+
+ /**
+ * @brief Overwrite Log Mode
+ */
+ CFE_ES_LogMode_OVERWRITE = 0,
+
+ /**
+ * @brief Discard Log Mode
+ */
+ CFE_ES_LogMode_DISCARD = 1
+};
+
+/**
+ * @brief Identifies handling of log messages after storage is filled
+ *
+ * @sa enum CFE_ES_LogMode
+ */
+typedef uint8 CFE_ES_LogMode_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_ES_ExceptionAction_Enum_t
+ */
+enum CFE_ES_ExceptionAction
+{
+
+ /**
+ * @brief Restart application if exception occurs
+ */
+ CFE_ES_ExceptionAction_RESTART_APP = 0,
+
+ /**
+ * @brief Restart processor if exception occurs
+ */
+ CFE_ES_ExceptionAction_PROC_RESTART = 1
+};
+
+/**
+ * @brief Identifies action to take if exception occurs
+ *
+ * @sa enum CFE_ES_ExceptionAction
+ */
+typedef uint8 CFE_ES_ExceptionAction_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_ES_AppType_Enum_t
+ */
+enum CFE_ES_AppType
+{
+
+ /**
+ * @brief CFE core application
+ */
+ CFE_ES_AppType_CORE = 1,
+
+ /**
+ * @brief CFE external application
+ */
+ CFE_ES_AppType_EXTERNAL = 2,
+
+ /**
+ * @brief CFE library
+ */
+ CFE_ES_AppType_LIBRARY = 3
+};
+
+/**
+ * @brief Identifies type of CFE application
+ *
+ * @sa enum CFE_ES_AppType
+ */
+typedef uint8 CFE_ES_AppType_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_ES_RunStatus_Enum_t
+ */
+enum CFE_ES_RunStatus
+{
+ /**
+ * @brief Reserved value, should not be used
+ */
+ CFE_ES_RunStatus_UNDEFINED = 0,
+
+ /**
+ * @brief Indicates that the Application should continue to run
+ */
+ CFE_ES_RunStatus_APP_RUN = 1,
+
+ /**
+ * @brief Indicates that the Application wants to exit normally
+ */
+ CFE_ES_RunStatus_APP_EXIT = 2,
+
+ /**
+ * @brief Indicates that the Application is quitting with an error
+ */
+ CFE_ES_RunStatus_APP_ERROR = 3,
+
+ /**
+ * @brief The cFE App caused an exception
+ */
+ CFE_ES_RunStatus_SYS_EXCEPTION = 4,
+
+ /**
+ * @brief The system is requesting a restart of the cFE App
+ */
+ CFE_ES_RunStatus_SYS_RESTART = 5,
+
+ /**
+ * @brief The system is requesting a reload of the cFE App
+ */
+ CFE_ES_RunStatus_SYS_RELOAD = 6,
+
+ /**
+ * @brief The system is requesting that the cFE App is stopped
+ */
+ CFE_ES_RunStatus_SYS_DELETE = 7,
+
+ /**
+ * @brief Indicates that the Core Application could not Init
+ */
+ CFE_ES_RunStatus_CORE_APP_INIT_ERROR = 8,
+
+ /**
+ * @brief Indicates that the Core Application had a runtime failure
+ */
+ CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR = 9,
+
+ /**
+ * @brief Reserved value, marker for the maximum state
+ */
+ CFE_ES_RunStatus_MAX
+
+};
+
+/**
+ * @brief Run Status and Exit Status identifiers
+ *
+ * @sa enum CFE_ES_RunStatus
+ */
+typedef uint32 CFE_ES_RunStatus_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_ES_SystemState_Enum_t
+ */
+enum CFE_ES_SystemState
+{
+
+ /**
+ * @brief reserved
+ */
+ CFE_ES_SystemState_UNDEFINED = 0,
+
+ /**
+ * @brief single threaded mode while setting up CFE itself
+ */
+ CFE_ES_SystemState_EARLY_INIT = 1,
+
+ /**
+ * @brief core apps (CFE_ES_ObjectTable) are starting (multi-threaded)
+ */
+ CFE_ES_SystemState_CORE_STARTUP = 2,
+
+ /**
+ * @brief core is ready, starting other external apps/libraries (if any)
+ */
+ CFE_ES_SystemState_CORE_READY = 3,
+
+ /**
+ * @brief startup apps have all completed their early init, but not necessarily operational yet
+ */
+ CFE_ES_SystemState_APPS_INIT = 4,
+
+ /**
+ * @brief normal operation mode; all apps are RUNNING
+ */
+ CFE_ES_SystemState_OPERATIONAL = 5,
+
+ /**
+ * @brief reserved for future use, all apps would be STOPPED
+ */
+ CFE_ES_SystemState_SHUTDOWN = 6,
+
+ /**
+ * @brief Reserved value, marker for the maximum state
+ */
+ CFE_ES_SystemState_MAX
+};
+
+/**
+ * @brief The overall cFE System State
+ *
+ * These values are used with the #CFE_ES_WaitForSystemState API call to synchronize application startup.
+ *
+ * @note These are defined in order so that relational comparisons e.g. if (STATEA < STATEB) are possible
+ *
+ * @sa enum CFE_ES_SystemState
+ */
+typedef uint32 CFE_ES_SystemState_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_ES_LogEntryType_Enum_t
+ */
+enum CFE_ES_LogEntryType
+{
+
+ /**
+ * @brief Log entry from a core subsystem
+ */
+ CFE_ES_LogEntryType_CORE = 1,
+
+ /**
+ * @brief Log entry from an application
+ */
+ CFE_ES_LogEntryType_APPLICATION = 2
+};
+
+/**
+ * @brief Type of entry in the Error and Reset (ER) Log
+ *
+ * @sa enum CFE_ES_LogEntryType
+ */
+typedef uint8 CFE_ES_LogEntryType_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_ES_AppState_Enum_t
+ */
+enum CFE_ES_AppState
+{
+
+ /**
+ * @brief Initial state before app thread is started
+ */
+ CFE_ES_AppState_UNDEFINED = 0,
+
+ /**
+ * @brief App thread has started, app performing early initialization of its own data
+ */
+ CFE_ES_AppState_EARLY_INIT = 1,
+
+ /**
+ * @brief Early/Local initialization is complete. First sync point.
+ */
+ CFE_ES_AppState_LATE_INIT = 2,
+
+ /**
+ * @brief All initialization is complete. Second sync point.
+ */
+ CFE_ES_AppState_RUNNING = 3,
+
+ /**
+ * @brief Application is waiting on a Restart/Reload/Delete request
+ */
+ CFE_ES_AppState_WAITING = 4,
+
+ /**
+ * @brief Application is stopped
+ */
+ CFE_ES_AppState_STOPPED = 5,
+
+ /**
+ * @brief Reserved entry, marker for the maximum state
+ */
+ CFE_ES_AppState_MAX
+};
+
+/**
+ * @brief Application Run State
+ *
+ * The normal progression of APP states:
+ * UNDEFINED -> EARLY_INIT -> LATE_INIT -> RUNNING -> WAITING -> STOPPED
+ *
+ * @note These are defined in order so that relational comparisons e.g. if (STATEA < STATEB) are possible
+ *
+ * @sa enum CFE_ES_AppState
+ */
+typedef uint32 CFE_ES_AppState_Enum_t;
+
+/**
+ * @brief A type for Application IDs
+ *
+ * This is the type that is used for any API accepting or returning an App ID
+ */
+typedef CFE_RESOURCEID_BASE_TYPE CFE_ES_AppId_t;
+
+/**
+ * @brief A type for Task IDs
+ *
+ * This is the type that is used for any API accepting or returning a Task ID
+ */
+typedef CFE_RESOURCEID_BASE_TYPE CFE_ES_TaskId_t;
+
+/**
+ * @brief A type for Library IDs
+ *
+ * This is the type that is used for any API accepting or returning a Lib ID
+ */
+typedef CFE_RESOURCEID_BASE_TYPE CFE_ES_LibId_t;
+
+/**
+ * @brief A type for Counter IDs
+ *
+ * This is the type that is used for any API accepting or returning an Counter ID
+ */
+typedef CFE_RESOURCEID_BASE_TYPE CFE_ES_CounterId_t;
+
+/**
+ * @brief Memory Handle type
+ *
+ * Data type used to hold Handles of Memory Pools
+ * created via CFE_ES_PoolCreate and CFE_ES_PoolCreateNoSem
+ */
+typedef CFE_RESOURCEID_BASE_TYPE CFE_ES_MemHandle_t;
+
+/**
+ * @brief CDS Handle type
+ *
+ * Data type used to hold Handles of Critical Data Stores. See #CFE_ES_RegisterCDS
+ */
+typedef CFE_RESOURCEID_BASE_TYPE CFE_ES_CDSHandle_t;
+
+/**
+ * @brief Type used for task priority in CFE ES as
+ * including the commands/telemetry messages.
+ *
+ * @note the valid range is only 0-255 (same as OSAL) but
+ * a wider type is used for backward compatibility
+ * in binary formats of messages.
+ */
+typedef uint16 CFE_ES_TaskPriority_Atom_t;
+
+/**
+ * @brief Type used for memory sizes and offsets in commands and telemetry
+ *
+ * For backward compatibility with existing CFE code this should be uint32,
+ * but all telemetry information will be limited to 4GB in size as a result.
+ *
+ * On 64-bit platforms this can be a 64-bit value which will allow larger
+ * memory objects, but this will break compatibility with existing control
+ * systems, and may also change the alignment/padding of messages.
+ *
+ * In either case this must be an unsigned type.
+ */
+typedef uint32 CFE_ES_MemOffset_t;
+
+/*
+ * A converter macro to use when initializing an CFE_ES_MemOffset_t
+ * from an integer value of a different type.
+ */
+#define CFE_ES_MEMOFFSET_C(x) ((CFE_ES_MemOffset_t)(x))
+
+/**
+ * @brief Type used for memory addresses in command and telemetry messages
+ *
+ * For backward compatibility with existing CFE code this should be uint32,
+ * but if running on a 64-bit platform, addresses in telemetry will be
+ * truncated to 32 bits and therefore will not be valid.
+ *
+ * On 64-bit platforms this can be a 64-bit address which will allow the
+ * full memory address in commands and telemetry, but this will break
+ * compatibility with existing control systems, and may also change
+ * the alignment/padding of messages.
+ *
+ * In either case this must be an unsigned type.
+ *
+ * FSW code should access this value via the macros provided, which
+ * converts to the native "cpuaddr" type provided by OSAL. This macro
+ * provides independence between the message representation and local
+ * representation of a memory address.
+ */
+typedef uint32 CFE_ES_MemAddress_t;
+
+/*
+ * A converter macro to use when initializing an CFE_ES_MemAddress_t
+ * from a pointer value of a different type.
+ *
+ * @note on a 64 bit platform, this macro will truncate the address such
+ * that it will fit into a 32-bit telemetry field. Obviously, the resulting
+ * value is no longer usable as a memory address after this.
+ */
+#define CFE_ES_MEMADDRESS_C(x) ((CFE_ES_MemAddress_t)((cpuaddr)(x)&0xFFFFFFFF))
+
+/*
+ * Data Sructures shared between API and Message (CMD/TLM) interfaces
+ */
+
+/**
+ * \brief Application Information
+ *
+ * Structure that is used to provide information about an app.
+ * It is primarily used for the QueryOne and QueryAll Commands.
+ *
+ * While this structure is primarily intended for Application info,
+ * it can also represent Library information where only a subset of
+ * the information applies.
+ */
+typedef struct CFE_ES_AppInfo
+{
+ CFE_ResourceId_t ResourceId; /**< \cfetlmmnemonic \ES_APP_ID
+ \brief Application or Library ID for this resource */
+ uint32 Type; /**< \cfetlmmnemonic \ES_APPTYPE
+ \brief The type of App: CORE or EXTERNAL */
+
+ char Name[CFE_MISSION_MAX_API_LEN]; /**< \cfetlmmnemonic \ES_APPNAME
+ \brief The Registered Name of the Application */
+ char EntryPoint[CFE_MISSION_MAX_API_LEN]; /**< \cfetlmmnemonic \ES_APPENTRYPT
+ \brief The Entry Point label for the Application */
+ char FileName[CFE_MISSION_MAX_PATH_LEN]; /**< \cfetlmmnemonic \ES_APPFILENAME
+ \brief The Filename of the file containing the Application */
+
+ CFE_ES_MemOffset_t StackSize; /**< \cfetlmmnemonic \ES_STACKSIZE
+ \brief The Stack Size of the Application */
+ uint32 AddressesAreValid; /**< \cfetlmmnemonic \ES_ADDRVALID
+ \brief Indicates that the Code, Data, and BSS addresses/sizes are valid */
+ CFE_ES_MemAddress_t CodeAddress; /**< \cfetlmmnemonic \ES_CODEADDR
+ \brief The Address of the Application Code Segment*/
+ CFE_ES_MemOffset_t CodeSize; /**< \cfetlmmnemonic \ES_CODESIZE
+ \brief The Code Size of the Application */
+ CFE_ES_MemAddress_t DataAddress; /**< \cfetlmmnemonic \ES_DATAADDR
+ \brief The Address of the Application Data Segment*/
+ CFE_ES_MemOffset_t DataSize; /**< \cfetlmmnemonic \ES_DATASIZE
+ \brief The Data Size of the Application */
+ CFE_ES_MemAddress_t BSSAddress; /**< \cfetlmmnemonic \ES_BSSADDR
+ \brief The Address of the Application BSS Segment*/
+ CFE_ES_MemOffset_t BSSSize; /**< \cfetlmmnemonic \ES_BSSSIZE
+ \brief The BSS Size of the Application */
+ CFE_ES_MemAddress_t StartAddress; /**< \cfetlmmnemonic \ES_STARTADDR
+ \brief The Start Address of the Application */
+ CFE_ES_ExceptionAction_Enum_t ExceptionAction; /**< \cfetlmmnemonic \ES_EXCEPTNACTN
+ \brief What should occur if Application has an exception
+ (Restart Application OR Restart Processor) */
+ CFE_ES_TaskPriority_Atom_t Priority; /**< \cfetlmmnemonic \ES_PRIORITY
+ \brief The Priority of the Application */
+ CFE_ES_TaskId_t MainTaskId; /**< \cfetlmmnemonic \ES_MAINTASKID
+ \brief The Application's Main Task ID */
+ uint32 ExecutionCounter; /**< \cfetlmmnemonic \ES_MAINTASKEXECNT
+ \brief The Application's Main Task Execution Counter */
+ char MainTaskName[CFE_MISSION_MAX_API_LEN]; /**< \cfetlmmnemonic \ES_MAINTASKNAME
+ \brief The Application's Main Task ID */
+ uint32 NumOfChildTasks; /**< \cfetlmmnemonic \ES_CHILDTASKS
+ \brief Number of Child tasks for an App */
+
+} CFE_ES_AppInfo_t;
+
+/**
+ * \brief Task Information
+ *
+ * Structure that is used to provide information about a task. It is primarily
+ * used for the Query All Tasks (#CFE_ES_QUERY_ALL_TASKS_CC) command.
+ *
+ * \note There is not currently a telemetry message directly containing this
+ * data structure, but it does define the format of the data file generated
+ * by the Query All Tasks command. Therefore it should be considered
+ * part of the overall telemetry interface.
+ */
+typedef struct CFE_ES_TaskInfo
+{
+ CFE_ES_TaskId_t TaskId; /**< \brief Task Id */
+ uint32 ExecutionCounter; /**< \brief Task Execution Counter */
+ char TaskName[CFE_MISSION_MAX_API_LEN]; /**< \brief Task Name */
+ CFE_ES_AppId_t AppId; /**< \brief Parent Application ID */
+ char AppName[CFE_MISSION_MAX_API_LEN]; /**< \brief Parent Application Name */
+ CFE_ES_MemOffset_t StackSize; /**< Size of task stack */
+ CFE_ES_TaskPriority_Atom_t Priority; /**< Priority of task */
+ uint8 Spare[2]; /**< Spare bytes for alignment */
+} CFE_ES_TaskInfo_t;
+
+/**
+ * \brief CDS Register Dump Record
+ *
+ * Structure that is used to provide information about a critical data store.
+ * It is primarily used for the Dump CDS registry (#CFE_ES_DUMP_CDS_REGISTRY_CC)
+ * command.
+ *
+ * \note There is not currently a telemetry message directly containing this
+ * data structure, but it does define the format of the data file generated
+ * by the Dump CDS registry command. Therefore it should be considered
+ * part of the overall telemetry interface.
+ */
+typedef struct CFE_ES_CDSRegDumpRec
+{
+ CFE_ES_CDSHandle_t Handle; /**< \brief Handle of CDS */
+ CFE_ES_MemOffset_t Size; /**< \brief Size, in bytes, of the CDS memory block */
+ bool Table; /**< \brief Flag that indicates whether CDS contains a Critical Table */
+ char Name[CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN]; /**< \brief Processor Unique Name of CDS */
+ uint8 ByteAlignSpare[3]; /**< \brief Spare bytes to ensure structure size is multiple of 4 bytes */
+} CFE_ES_CDSRegDumpRec_t;
+
+/**
+ * \brief Block statistics
+ *
+ * Sub-Structure that is used to provide information about a specific
+ * block size/bucket within a memory pool.
+ */
+typedef struct CFE_ES_BlockStats
+{
+ CFE_ES_MemOffset_t BlockSize; /**< \brief Number of bytes in each of these blocks */
+ uint32 NumCreated; /**< \brief Number of Memory Blocks of this size created */
+ uint32 NumFree; /**< \brief Number of Memory Blocks of this size that are free */
+} CFE_ES_BlockStats_t;
+
+/**
+ * \brief Memory Pool Statistics
+ *
+ * Structure that is used to provide information about a memory
+ * pool. Used by the Memory Pool Stats telemetry message.
+ *
+ * \sa #CFE_ES_SEND_MEM_POOL_STATS_CC
+ */
+typedef struct CFE_ES_MemPoolStats
+{
+ CFE_ES_MemOffset_t PoolSize; /**< \cfetlmmnemonic \ES_POOLSIZE
+ \brief Size of Memory Pool (in bytes) */
+ uint32 NumBlocksRequested; /**< \cfetlmmnemonic \ES_BLKSREQ
+ \brief Number of times a memory block has been allocated */
+ uint32 CheckErrCtr; /**< \cfetlmmnemonic \ES_BLKERRCTR
+ \brief Number of errors detected when freeing a memory block */
+ CFE_ES_MemOffset_t NumFreeBytes; /**< \cfetlmmnemonic \ES_FREEBYTES
+ \brief Number of bytes never allocated to a block */
+ CFE_ES_BlockStats_t BlockStats[CFE_MISSION_ES_POOL_MAX_BUCKETS]; /**< \cfetlmmnemonic \ES_BLKSTATS
+ \brief Contains stats on each block size */
+} CFE_ES_MemPoolStats_t;
+
+#endif /* CFE_EDS_ENABLED_BUILD */
+
+#endif /* CFE_ES_EXTERN_TYPEDEFS_H */
diff --git a/modules/core_private/fsw/inc/cfe_es_erlog_typedef.h b/modules/core_private/fsw/inc/cfe_es_erlog_typedef.h
new file mode 100644
index 000000000..ee1810e77
--- /dev/null
+++ b/modules/core_private/fsw/inc/cfe_es_erlog_typedef.h
@@ -0,0 +1,98 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Definition of the CFE_ES_ERLog structure type.
+ * This was moved into its own header file since it is referenced by multiple CFE core apps.
+ */
+
+#ifndef CFE_ES_ERLOG_TYPEDEF_H
+#define CFE_ES_ERLOG_TYPEDEF_H
+
+#include "common_types.h"
+#include "cfe_platform_cfg.h"
+
+#include "cfe_time_extern_typedefs.h" /* Needed for CFE_TIME_SysTime_t */
+#include "cfe_es_extern_typedefs.h" /* Needed for CFE_ES_AppId_t */
+
+#define CFE_ES_ERLOG_DESCRIPTION_MAX_LENGTH 80
+
+/*
+** Debug variables type
+*/
+typedef struct
+{
+ uint32 DebugFlag;
+ uint32 WatchdogWriteFlag;
+ uint32 PrintfEnabledFlag;
+ uint32 LastAppId;
+
+} CFE_ES_DebugVariables_t;
+
+/*
+** Exception and Reset Log Base Structure
+**
+** This is the common data structure that is stored in RAM and log files
+*/
+typedef struct
+{
+ uint32 LogEntryType; /* What type of log entry */
+ uint32 ResetType; /* Main cause for the reset */
+ uint32 ResetSubtype; /* The sub-type for the reset */
+ uint32 BootSource; /* The boot source */
+ uint32 ProcessorResetCount; /* The number of processor resets */
+ uint32 MaxProcessorResetCount; /* The maximum number before a Power On */
+ CFE_ES_DebugVariables_t DebugVars; /* ES Debug variables */
+ CFE_TIME_SysTime_t TimeCode; /* Time code */
+ char Description[CFE_ES_ERLOG_DESCRIPTION_MAX_LENGTH]; /* The ascii data for the event */
+} CFE_ES_ERLog_BaseInfo_t;
+
+/*
+** Exception and Reset Log File Structure
+**
+** This is the "export" data structure that gets written to a log file
+** It is intended to be binary-compatible with the historical definition of this
+** structure, to work with existing tools that may read log files.
+**
+** Note that "AppID" really belongs in the base info, but it is kept here
+** for backward compatibility.
+*/
+typedef struct
+{
+ CFE_ES_ERLog_BaseInfo_t BaseInfo; /* basic info about the event */
+ uint32 ContextSize; /* Indicates the context data is valid */
+ uint32 AppID; /* The application ID */
+ uint8 Context[CFE_PLATFORM_ES_ER_LOG_MAX_CONTEXT_SIZE]; /* cpu context */
+} CFE_ES_ERLog_FileEntry_t;
+
+/*
+** Exception and Reset Log Metadata Structure
+** This is stored in ES RAM, not _directly_ written to ER log files.
+*/
+typedef struct
+{
+ CFE_ES_ERLog_BaseInfo_t BaseInfo; /**< Core Log Data */
+ CFE_ES_AppId_t AppID; /* The application ID */
+ uint32 PspContextId; /**< Reference to context information stored in PSP */
+} CFE_ES_ERLog_MetaData_t;
+
+#endif /* CFE_ES_ERLOG_TYPEDEF_H */
diff --git a/modules/core_private/fsw/inc/cfe_es_perfdata_typedef.h b/modules/core_private/fsw/inc/cfe_es_perfdata_typedef.h
new file mode 100644
index 000000000..35d635c8f
--- /dev/null
+++ b/modules/core_private/fsw/inc/cfe_es_perfdata_typedef.h
@@ -0,0 +1,75 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Definition of CFE_ES_PerfData_t structure type
+ */
+
+#ifndef CFE_ES_PERFDATA_TYPEDEF_H
+#define CFE_ES_PERFDATA_TYPEDEF_H
+
+#include "common_types.h"
+#include "cfe_mission_cfg.h" /* Required for CFE_MISSION_ES_PERF_MAX_IDS */
+#include "cfe_platform_cfg.h" /* Required for CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE */
+
+#define CFE_ES_PERF_32BIT_WORDS_IN_MASK ((CFE_MISSION_ES_PERF_MAX_IDS) / 32)
+
+typedef struct
+{
+ uint32 Data;
+ uint32 TimerUpper32; /* TBU - timebase register */
+ uint32 TimerLower32; /* TBL - timebase register */
+} CFE_ES_PerfDataEntry_t;
+
+typedef struct
+{
+ uint8 Version;
+ uint8 Endian;
+ uint8 Spare[2];
+ uint32 TimerTicksPerSecond;
+ uint32 TimerLow32Rollover;
+ /*
+ * The "State" member is marked volatile to help
+ * ensure that an optimizing compiler does not rearrange
+ * or eliminate reads/writes of this value. It is read
+ * outside of any locking to determine whether or not
+ * the performance log function is enabled.
+ */
+ volatile uint32 State;
+ uint32 Mode;
+ uint32 TriggerCount;
+ uint32 DataStart;
+ uint32 DataEnd;
+ uint32 DataCount;
+ uint32 InvalidMarkerReported;
+ uint32 FilterTriggerMaskSize;
+ uint32 FilterMask[CFE_ES_PERF_32BIT_WORDS_IN_MASK];
+ uint32 TriggerMask[CFE_ES_PERF_32BIT_WORDS_IN_MASK];
+} CFE_ES_PerfMetaData_t;
+
+typedef struct
+{
+ CFE_ES_PerfMetaData_t MetaData;
+ CFE_ES_PerfDataEntry_t DataBuffer[CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE];
+} CFE_ES_PerfData_t;
+
+#endif /* CFE_ES_PERFDATA_TYPEDEF_H */
diff --git a/modules/core_private/fsw/inc/cfe_es_resetdata_typedef.h b/modules/core_private/fsw/inc/cfe_es_resetdata_typedef.h
new file mode 100644
index 000000000..5549c2890
--- /dev/null
+++ b/modules/core_private/fsw/inc/cfe_es_resetdata_typedef.h
@@ -0,0 +1,99 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Definition of the CFE_ES_ResetData structure type.
+ * This was moved into its own header file since it is referenced by multiple CFE core apps.
+ */
+
+#ifndef CFE_ES_RESETDATA_TYPEDEF_H
+#define CFE_ES_RESETDATA_TYPEDEF_H
+
+#include "common_types.h"
+
+#include "cfe_time_resetvars_typedef.h" /* Required for CFE_TIME_ResetVars_t definition */
+#include "cfe_es_erlog_typedef.h" /* Required for CFE_ES_ERLog_t definition */
+#include "cfe_es_perfdata_typedef.h" /* Required for CFE_ES_PerfData_t definition */
+#include "cfe_evs_log_typedef.h" /* Required for CFE_EVS_Log_t definition */
+#include "cfe_platform_cfg.h" /* CFE_PLATFORM_ES_ER_LOG_ENTRIES, CFE_PLATFORM_ES_SYSTEM_LOG_SIZE */
+
+/*
+** Reset Variables type
+*/
+typedef struct
+{
+ uint32 ResetType;
+ uint32 ResetSubtype;
+ uint32 BootSource;
+ uint32 ES_CausedReset;
+ uint32 ProcessorResetCount;
+ uint32 MaxProcessorResetCount;
+} CFE_ES_ResetVariables_t;
+
+/*
+** Executive Services Global Reset Data type
+** This is the special memory area for ES that is preserved
+** on a processor reset.
+*/
+typedef struct
+{
+ /*
+ ** Exception and Reset log declaration
+ */
+ CFE_ES_ERLog_MetaData_t ERLog[CFE_PLATFORM_ES_ER_LOG_ENTRIES];
+ uint32 ERLogIndex;
+ uint32 ERLogEntries;
+ uint32 LastAppId;
+
+ /*
+ ** System Log declaration
+ */
+ char SystemLog[CFE_PLATFORM_ES_SYSTEM_LOG_SIZE];
+ size_t SystemLogWriteIdx;
+ size_t SystemLogEndIdx;
+ uint32 SystemLogMode;
+ uint32 SystemLogEntryNum;
+
+ /*
+ ** Performance Data
+ */
+ CFE_ES_PerfData_t Perf;
+
+ /*
+ ** Reset Variables
+ */
+ CFE_ES_ResetVariables_t ResetVars;
+
+ /*
+ ** Time variables that are
+ ** preserved on a processor reset
+ */
+ CFE_TIME_ResetVars_t TimeResetVars;
+
+ /*
+ ** EVS Log and associated variables. This needs to be preserved on a processor reset.
+ */
+ CFE_EVS_Log_t EVS_Log;
+
+} CFE_ES_ResetData_t;
+
+#endif /* CFE_ES_RESETDATA_TYPEDEF_H */
diff --git a/modules/es/CMakeLists.txt b/modules/es/CMakeLists.txt
new file mode 100644
index 000000000..0e8ebe701
--- /dev/null
+++ b/modules/es/CMakeLists.txt
@@ -0,0 +1,39 @@
+##################################################################
+#
+# cFE Executive Services (ES) module CMake build recipe
+#
+##################################################################
+
+project(CFE_ES C)
+
+# Executive services source files
+set(es_SOURCES
+ fsw/src/cfe_es_api.c
+ fsw/src/cfe_es_apps.c
+ fsw/src/cfe_es_backgroundtask.c
+ fsw/src/cfe_es_cds.c
+ fsw/src/cfe_es_cds_mempool.c
+ fsw/src/cfe_es_erlog.c
+ fsw/src/cfe_es_generic_pool.c
+ fsw/src/cfe_es_mempool.c
+ fsw/src/cfe_es_objtab.c
+ fsw/src/cfe_es_perf.c
+ fsw/src/cfe_es_resource.c
+ fsw/src/cfe_es_start.c
+ fsw/src/cfe_es_syslog.c
+ fsw/src/cfe_es_task.c
+)
+add_library(es STATIC ${es_SOURCES})
+
+target_include_directories(es PUBLIC fsw/inc)
+target_link_libraries(es PRIVATE core_private)
+
+# Add unit test coverage subdirectory
+if (ENABLE_UNIT_TESTS)
+ add_subdirectory(ut-coverage)
+endif (ENABLE_UNIT_TESTS)
+
+cfs_app_check_intf(${DEP}
+ cfe_es_msg.h
+ cfe_es_events.h
+)
diff --git a/modules/es/fsw/inc/cfe_es_events.h b/modules/es/fsw/inc/cfe_es_events.h
new file mode 100644
index 000000000..5024fa38b
--- /dev/null
+++ b/modules/es/fsw/inc/cfe_es_events.h
@@ -0,0 +1,1451 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * cFE Executive Services (ES) Event IDs
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_EVENTS_H
+#define CFE_ES_EVENTS_H
+
+/* **************************
+** ****** Maximum EID. ******
+** **************************
+** The EID's below may not necessarily be in order, so it can be difficult to
+** determine what the next EID is to use. When you add EID's, start with MAX_EID + 1
+** and when you're done adding, set this to the highest EID you used. It may
+** be worthwhile to, on occasion, re-number the EID's to put them back in order.
+*/
+#define CFE_ES_MAX_EID 92
+
+/*
+** ES task event message ID's.
+*/
+
+/** \brief 'cFE ES Initialized'
+** \event 'cFE ES Initialized'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always automatically issued when the Executive Services
+** Task completes its Initialization.
+**/
+#define CFE_ES_INIT_INF_EID 1 /* start up message "informational" */
+
+/** \brief 'cFE Version \%d.\%d.\%d chksm \%d, OSAL Version \%d.\%d'
+** \event 'cFE Version \%d.\%d.\%d chksm \%d, OSAL Version \%d.\%d'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always automatically issued when the Executive Services
+** Task completes its Initialization.
+**
+** The \c Version field identifies the tagged version for the cFE Build, the \c chksm field
+** provides the 16-bit checksum of the cFE Build and the \c OSAL \c Version field identifies
+** the version of the OS Abstraction Layer on which this particular version of the cFE was built.
+**/
+#define CFE_ES_INITSTATS_INF_EID 2
+
+/** \brief 'No-op command'
+** \event 'No-op command'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always automatically issued in response
+** to a cFE Executive Services \link #CFE_ES_NOOP_CC NO-OP command \endlink
+**/
+#define CFE_ES_NOOP_INF_EID 3 /* processed command "informational" */
+
+/** \brief 'Reset Counters command'
+** \event 'Reset Counters command'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always automatically issued in response
+** to a cFE Executive Services \link #CFE_ES_RESET_COUNTERS_CC Reset Counters command \endlink
+**/
+#define CFE_ES_RESET_INF_EID 4
+
+/** \brief 'Started \%s from \%s, AppID = \%d'
+** \event 'Started \%s from \%s, AppID = \%d'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is automatically issued upon successful completion of
+** a cFE Executive Services \link #CFE_ES_START_APP_CC Start Application command \endlink
+**
+** The first \c 's' string identifies the name of the started Application, the
+** second \c 's' string identifies the filename from which the Application was
+** loaded and the \c AppId field specifies the Application ID assigned to the
+** newly started Application by the cFE Executive Services.
+**/
+#define CFE_ES_START_INF_EID 6
+
+/** \brief 'Stop Application \%s Initiated.'
+** \event 'Stop Application \%s Initiated.'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is issued upon successful processing of the
+** cFE Executive Services \link #CFE_ES_STOP_APP_CC Stop Application command \endlink
+** Note that when this event is displayed, the Application is not deleted. ES has
+** accepted the request to delete the application, and it will be deleted after the app exits
+** it's main loop, or times out.
+**
+** The \c 's' field identifies the name of the Application that will be stopped.
+**/
+#define CFE_ES_STOP_DBG_EID 7
+
+/** \brief 'Stop Application \%s Completed.'
+** \event 'Stop Application \%s Completed.'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is issued when the cFE finishes deleting the cFE Application
+** That was started when the \link #CFE_ES_STOP_APP_CC Stop Application command \endlink
+** was issued.
+**
+** The \c 's' field identifies the name of the Application that was stopped.
+*/
+#define CFE_ES_STOP_INF_EID 8
+
+/** \brief 'Restart Application \%s Initiated.'
+** \event 'Restart Application \%s Initiated.'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is issued upon successful processing of the
+** cFE Executive Services \link #CFE_ES_RESTART_APP_CC Restart Application command \endlink
+** Note that when this event is displayed, the Application is not restarted. ES has
+** accepted the request to restart the application, and it will be restarted after the app exits
+** it's main loop, or times out.
+**
+** The \c 's' field identifies the name of the Application that will be restarted.
+**/
+#define CFE_ES_RESTART_APP_DBG_EID 9
+
+/** \brief 'Restart Application \%s Completed, AppID=%lu'
+** \event 'Restart Application \%s Completed, AppID=%lu'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is issued when the cFE finishes Restarting the cFE Application
+** That was started when the \link #CFE_ES_RESTART_APP_CC Restart Application command \endlink
+** was issued.
+**
+** The \c 's' field identifies the name of the Application that was restarted, and
+** the %lu field identifies the new Application ID
+*/
+#define CFE_ES_RESTART_APP_INF_EID 10
+
+/** \brief 'Reload Application \%s Initiated.'
+** \event 'Reload Application \%s Initiated.'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is issued upon successful processing of the
+** cFE Executive Services \link #CFE_ES_RELOAD_APP_CC Reload Application command \endlink
+** Note that when this event is displayed, the Application is not reloaded. ES has
+** accepted the request to reload the application, and it will be reloaded after the app exits
+** it's main loop, or times out.
+**
+** The \c 's' field identifies the name of the Application that will be reloaded.
+**/
+#define CFE_ES_RELOAD_APP_DBG_EID 11
+
+/** \brief 'Reload Application \%s Completed, AppID=%lu'
+** \event 'Reload Application \%s Completed, AppID=%lu'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is issued when the cFE finishes Reloading the cFE Application
+** That was started when the \link #CFE_ES_RELOAD_APP_CC Restart Application command \endlink
+** was issued.
+**
+** The \c 's' field identifies the name of the Application that was reloaded, and
+** the %lu field identifies the new Application ID
+*/
+#define CFE_ES_RELOAD_APP_INF_EID 12
+
+/** \brief 'Exit Application \%s Completed.'
+** \event 'Exit Application \%s Completed.'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is issued when the cFE finishes exiting/cleaning up an
+** application that called the CFE_ES_ExitApp API with the CFE_ES_RunStatus_APP_EXIT parameter.
+** When an App calls this API, the request is recorded and the Executive Services App will
+** actually delete cFE Application before issuing this event message.
+**
+** The \c 's' field identifies the name of the Application that was exited.
+*/
+#define CFE_ES_EXIT_APP_INF_EID 13
+
+/** \brief 'Exit Application \%s Completed.'
+** \event 'Exit Application \%s Completed.'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is issued when the cFE finishes exiting/cleaning up an
+** application that called the CFE_ES_ExitApp API with an ERROR condition.
+** When an App calls this API, with the CFE_ES_RunStatus_APP_ERROR parameter, it indicates
+** that the Application exited due to an error condition. The details of the
+** error that occurred should be given by the Application through an event message,
+** System Log entry, or both.
+** The request is recorded and the Executive Services App will actually delete
+** cFE Application before issuing this event message.
+**
+** The \c 's' field identifies the name of the Application that was exited.
+*/
+#define CFE_ES_ERREXIT_APP_INF_EID 14
+
+/** \brief 'Sent \%s application data'
+** \event 'Sent \%s application data'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is issued upon successful completion of the
+** cFE Executive Services \link #CFE_ES_QUERY_ONE_CC Query One Application command \endlink
+**
+** The \c 's' field identifies the name of the Application whose Executive Services
+** Application information has been telemetered.
+**/
+#define CFE_ES_ONE_APP_EID 15
+
+/** \brief 'App Info file written to \%s, Entries=\%d, FileSize=\%d'
+** \event 'App Info file written to \%s, Entries=\%d, FileSize=\%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is issued upon successful completion of the cFE Executive
+** Services \link #CFE_ES_QUERY_ALL_CC Query All Applications command \endlink
+**
+** The \c 's' field identifies the name of the file to which all Executive Services Application
+** data has been written. The \c Entries field identifies, in decimal, the number of Applications
+** whose data was written and the \c FileSize field gives the total number of bytes written to the
+** file.
+**/
+#define CFE_ES_ALL_APPS_EID 16
+
+/** \brief 'Cleared Executive Services log data'
+** \event 'Cleared Executive Services log data'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion of the cFE Executive
+** Services \link #CFE_ES_CLEAR_SYSLOG_CC Clear System Log command \endlink
+**/
+#define CFE_ES_SYSLOG1_INF_EID 17
+
+/** \brief '\%s written:Size=\%d,Entries=\%d'
+** \event '\%s written:Size=\%d,Entries=\%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated when the System Log has been successfully written
+** to a file after receiving the cFE Executive Services \link #CFE_ES_CLEAR_SYSLOG_CC Write Executive
+** Services System Log command \endlink
+**
+** The \c 's' field identifies the name of the file written to, the \c Size field specifies, in decimal,
+** the number of bytes written to the file and the \c Entries field identifies the number of System Log
+** messages that were written.
+**/
+#define CFE_ES_SYSLOG2_EID 18
+
+/** \brief 'Cleared mode log data'
+** \event 'Cleared mode log data'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion of the cFE Executive
+** Services \link #CFE_ES_CLEAR_ER_LOG_CC Clear Exception Reset Log command \endlink
+**/
+#define CFE_ES_ERLOG1_INF_EID 19
+
+/** \brief '\%s written:Size=\%d'
+** \event '\%s written:Size=\%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated when the Exception Reset Log has been successfully written
+** to a file after receiving the cFE Executive Services \link #CFE_ES_WRITE_ER_LOG_CC Write Executive
+** Services Exception Reset Log command \endlink
+**
+** The \c 's' field identifies the name of the file written to and the \c Size field specifies, in decimal,
+** the number of bytes written to the file.
+**/
+#define CFE_ES_ERLOG2_EID 20
+
+/** \brief 'Invalid command pipe message ID: 0x\%X'
+** \event 'Invalid command pipe message ID: 0x\%X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when a message has arrived on
+** the cFE Executive Services Application's Message Pipe that has a
+** Message ID that is neither #CFE_ES_SEND_HK_MID or #CFE_ES_CMD_MID.
+** Most likely, the cFE Software Bus routing table has become corrupt
+** and is sending messages targeted for other Applications to the cFE
+** Executive Services Application.
+**
+** The \c ID field in the event message identifies
+** the message ID (in hex) that was found in the message.
+**/
+#define CFE_ES_MID_ERR_EID 21 /* invalid command packet "error" */
+
+/** \brief 'Invalid ground command code: ID = 0x\%X, CC = \%d'
+** \event 'Invalid ground command code: ID = 0x\%X, CC = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when a message with the #CFE_ES_CMD_MID
+** message ID has arrived but whose Command Code is not one of the command
+** codes specified in \link #CFE_ES_NOOP_CC cfe_es.h \endlink. This
+** problem is most likely to occur when:
+** -# A Message ID meant for another Application became corrupted and was
+** set equal to #CFE_ES_CMD_MID.
+** -# The Command Code field in the Message became corrupted.
+** -# The command database at the ground station has been corrupted.
+**
+** The \c ID field in the event message specifies the Message ID (in hex) and the
+** \c CC field specifies the Command Code (in decimal) found in the message.
+**/
+#define CFE_ES_CC1_ERR_EID 22
+
+/** \brief 'Invalid cmd length: ID = 0x\%X, CC = \%d, Exp Len = \%d, Len = \%d'
+** \event 'Invalid cmd length: ID = 0x\%X, CC = \%d, Exp Len = \%d, Len = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when a message with the #CFE_ES_CMD_MID
+** message ID has arrived but whose packet length does not match the expected
+** length for the specified command code.
+**
+** The \c ID field in the event message specifies the Message ID (in hex), the \c CC field
+** specifies the Command Code (in decimal), the \c Exp Len field specified the Expected
+** Length (in decimal ), and \c Len specifies the message Length (in decimal)
+** found in the message.
+**/
+#define CFE_ES_LEN_ERR_EID 23
+
+/** \brief 'Invalid cFE restart type \%d'
+** \event 'Invalid cFE restart type \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is issued when the cFE Executive Services receives a
+** \link #CFE_ES_RESTART_CC cFE Restart Command \endlink whose parameter
+** identifying the restart type is not equal to either #CFE_PSP_RST_TYPE_PROCESSOR
+** or #CFE_PSP_RST_TYPE_POWERON.
+**
+** The 'd' field identifies the numeric, in decimal, of the restart type found
+** in the received cFE Restart Command Packet.
+**/
+#define CFE_ES_BOOT_ERR_EID 24 /* command specific "error" */
+
+/** \brief 'Failed to start \%s from \%s, RC = \%08X'
+** \event 'Failed to start \%s from \%s, RC = \%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated for an error encountered in response
+** to an Executive Services \link #CFE_ES_START_APP_CC Start Application Command \endlink.
+**
+** This message is a general failure when the command passes the parameter validation, but
+** fails when a call to CFE_ES_AppCreate is called.
+**
+** The \c 's' term identifies the name of the Application that was attempted to start.
+** The second \c 's' field specifies the file from which the Application was loaded.
+** The \c 'X' field is the return code returned by the CFE_ES_AppCreate.
+**/
+#define CFE_ES_START_ERR_EID 26
+
+/** \brief 'CFE_ES_StartAppCmd: invalid filename: \%s'
+** \event 'CFE_ES_StartAppCmd: invalid filename: \%s'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated for an error encountered in response
+** to an Executive Services \link #CFE_ES_START_APP_CC Start Application Command \endlink.
+**
+** This message reports a command failure when the Start Appplication Command is given
+** an invalid filename. ( Either NULL or too short to be a valid cFE file name ).
+**
+** The \c 's' term identifies the invalid filename that was sent with the command.
+**/
+#define CFE_ES_START_INVALID_FILENAME_ERR_EID 27
+
+/** \brief 'CFE_ES_StartAppCmd: App Entry Point is NULL.'
+** \event 'CFE_ES_StartAppCmd: App Entry Point is NULL.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated for an error encountered in response
+** to an Executive Services \link #CFE_ES_START_APP_CC Start Application Command \endlink.
+**
+** This message reports a command failure when the Start Appplication Command is given
+** a NULL Application Entry Point parameter. The command must contain an application entry
+** point string. ( Example: "SC_AppMain" ).
+**
+**/
+#define CFE_ES_START_INVALID_ENTRY_POINT_ERR_EID 28
+
+/** \brief 'CFE_ES_StartAppCmd: App Name is NULL.'
+** \event 'CFE_ES_StartAppCmd: App Name is NULL.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated for an error encountered in response
+** to an Executive Services \link #CFE_ES_START_APP_CC Start Application Command \endlink.
+**
+** This message reports a command failure when the Start Appplication Command is given
+** a NULL Application Name parameter. The command must contain an application name string.
+**/
+#define CFE_ES_START_NULL_APP_NAME_ERR_EID 29
+
+/** \brief 'CFE_ES_StartAppCmd: Priority is too large: \%d.'
+** \event 'CFE_ES_StartAppCmd: Priority is too large: \%d.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated for an error encountered in response
+** to an Executive Services \link #CFE_ES_START_APP_CC Start Application Command \endlink.
+**
+** This message reports a command failure when the Application priority greater than the
+** maximum priority for a Task defined by the OS Abstraction Layer ( 256 ).
+**
+** The \c 'd' term identifies the priority that was given in the command.
+**/
+#define CFE_ES_START_PRIORITY_ERR_EID 31
+
+/** \brief 'CFE_ES_StartAppCmd: Invalid Exception Action: \%d.'
+** \event 'CFE_ES_StartAppCmd: Invalid Exception Action: \%d.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated for an error encountered in response
+** to an Executive Services \link #CFE_ES_START_APP_CC Start Application Command \endlink.
+**
+** This message reports a command failure when the Application Exception Action parameter is
+** invalid. The valid options for this parameter are: 0 = Application will restart on an exception
+** 1 = Application cause a processor restart on
+** exception.
+**
+** The \c 'd' term identifies the Exception Action parameter that was given in the command.
+**/
+#define CFE_ES_START_EXC_ACTION_ERR_EID 32
+
+/** \brief 'Exit Application \%s on Error Failed: CleanUpApp Error 0x\%08X.'
+** \event 'Exit Application \%s on Error Failed: CleanUpApp Error 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when ES is completing the processing of the
+** CFE_ES_ExitApp API call with the CFE_ES_RunStatus_APP_ERROR parameter and the call to CFE_ES_CleanUpApp fails.
+** At this point the Application will likely be stopped or deleted, but it may be in an unknown state.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** reloaded and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_ERREXIT_APP_ERR_EID 33
+
+/** \brief 'Stop Application \%s Failed, RC = 0x\%08X'
+** \event 'Stop Application \%s Failed, RC = 0x\%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_STOP_APP_CC Stop Application Command \endlink which fails.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** stopped and the \c rc field identifies the error code, in hex, that may identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_STOP_ERR1_EID 35
+
+/** \brief 'Stop Application \%s, GetAppIDByName failed. RC = 0x\%08X.'
+** \event 'Stop Application \%s, GetAppIDByName failed. RC = 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_STOP_APP_CC Stop Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_GetAppIDByName fails. The application
+** will not be deleted at this point.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** stopped and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_STOP_ERR2_EID 36
+
+/*
+** "Stop Application \%s Failed: CleanUpApp Error 0x\%08X."
+*/
+
+/** \brief 'Stop Application \%s Failed: CleanUpApp Error 0x\%08X.'
+** \event 'Stop Application \%s Failed: CleanUpApp Error 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_STOP_APP_CC Stop Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_GetAppIDByName fails. The application
+** will not be deleted at this point.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** stopped and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_STOP_ERR3_EID 37
+
+/** \brief 'Restart Application \%s Failed, RC = 0x\%08X'
+** \event 'Restart Application \%s Failed, RC = 0x\%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_RESTART_APP_CC Restart Application
+** Command \endlink fails.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** reset and the \c rc field identifies the error code, in hex, that may identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RESTART_APP_ERR1_EID 38
+
+/** \brief 'Restart Application \%s, GetAppIDByName failed. RC = 0x\%08X.'
+** \event 'Restart Application \%s, GetAppIDByName failed. RC = 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_RESTART_APP_CC Restart Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_GetAppIDByName fails. The application
+** will not be restarted at this point.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** restarted and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RESTART_APP_ERR2_EID 39
+
+/*
+** "Restart Application \%s Failed: AppCreate Error 0x\%08X."
+*/
+
+/** \brief 'Restart Application \%s Failed: AppCreate Error 0x\%08X.'
+** \event 'Restart Application \%s Failed: AppCreate Error 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_RESTART_APP_CC Restart Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_AppCreate fails. The application
+** will not be restarted at this point.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** restarted and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RESTART_APP_ERR3_EID 40
+
+/** \brief 'Restart Application \%s Failed: CleanUpApp Error 0x\%08X.'
+** \event 'Restart Application \%s Failed: CleanUpApp Error 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_RESTART_APP_CC Restart Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_CleanUpApp fails. The application
+** will not be restarted at this point, but will likely be deleted or in an unknown state.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** restarted and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RESTART_APP_ERR4_EID 41
+
+/** \brief 'Failed to reload Application \%s, rc = \%08X'
+** \event 'Failed to reload Application \%s, rc = \%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_RELOAD_APP_CC Reload Application
+** Command \endlink fails.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** reloaded and the \c rc field identifies the error code, in hex, that may identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RELOAD_APP_ERR1_EID 42
+
+/** \brief 'Reload Application \%s, GetAppIDByName failed. RC = 0x\%08X.'
+** \event 'Reload Application \%s, GetAppIDByName failed. RC = 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_RELOAD_APP_CC Reload Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_GetAppIDByName fails. The application
+** will not be reloaded at this point.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** reloaded and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RELOAD_APP_ERR2_EID 43
+
+/** \brief 'Reload Application \%s Failed: AppCreate Error 0x\%08X.'
+** \event 'Reload Application \%s Failed: AppCreate Error 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_RELOAD_APP_CC Reload Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_AppCreate fails. The application
+** will not be reloaded at this point.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** reloaded and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RELOAD_APP_ERR3_EID 44
+
+/** \brief 'Reload Application \%s Failed: CleanUpApp Error 0x\%08X.'
+** \event 'Reload Application \%s Failed: CleanUpApp Error 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an Executive Services
+** \link #CFE_ES_RELOAD_APP_CC Reload Application Command \endlink which fails. This message
+** is for a specific failure when the call to CFE_ES_CleanUpApp fails. The application
+** will not be reloaded at this point, and will likely be deleted or in an unknown state.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** reloaded and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_RELOAD_APP_ERR4_EID 45
+
+/** \brief 'Exit Application \%s Failed: CleanUpApp Error 0x\%08X.'
+** \event 'Exit Application \%s Failed: CleanUpApp Error 0x\%08X.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when ES is completing the processing of the
+** CFE_ES_ExitApp API call and the call to CFE_ES_CleanUpApp fails. At this point the Application will
+** likely be stopped or deleted, but it may be in an unknown state.
+**
+** The \c 's' field identifies the name of the Application which was attempted to be
+** reloaded and the \c RC field identifies the error code, in hex, that will identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_EXIT_APP_ERR_EID 46
+
+/** \brief 'ES_ProcControlReq: Invalid State (EXCEPTION) Application \%s.'
+** \event 'ES_ProcControlReq: Invalid State (EXCEPTION) Application \%s.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when ES is processing it's internal Application table and encounters
+** an App with the EXCEPTION state. Because exceptions are supposed to be processed immediately, this is
+** an invalid state and should not happen. It may indicate some sort of memory corruption or other problem.
+**/
+#define CFE_ES_PCR_ERR1_EID 47
+
+/*
+** "CFE_ES_CleanUpApp: Unknown State ( \%d ) Application \%s."
+*/
+/** \brief 'ES_ProcControlReq: Unknown State ( \%d ) Application \%s.'
+** \event 'ES_ProcControlReq: Unknown State ( \%d ) Application \%s.'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when ES is processing it's internal Application table and encounters
+** an App with an unknown state. If this message occurs, it might be an indication of a memory corruption
+** or other problem.
+**/
+#define CFE_ES_PCR_ERR2_EID 48
+
+/** \brief 'Failed to send \%s application data, RC = \%08X'
+** \event 'Failed to send \%s application data, RC = \%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_QUERY_ONE_CC Request Application
+** Data Command \endlink failed.
+**
+** The \c 's' field identifies the name of the Application whose data was attempted
+** to be telemetered and the \c rc field identifies the error code, in hex, that may identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_ONE_ERR_EID 49
+
+/** \brief 'Failed to send \%s application data: GetAppIDByName Failed, RC = 0x\%08X'
+** \event 'Failed to send \%s application data: GetAppIDByName Failed, RC = 0x\%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_QUERY_ONE_CC Request Application
+** Data Command \endlink failed.
+**
+** The \c 's' field identifies the name of the Application whose data was attempted
+** to be telemetered and the \c rc field identifies the error code, in hex, that may identify
+** the precise reason for the failure.
+**/
+#define CFE_ES_ONE_APPID_ERR_EID 50
+
+/** \brief 'Failed to write App Info file, OS_OpenCreate returned \%d'
+** \event 'Failed to write App Info file, OS_OpenCreate returned \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_QUERY_ALL_CC Dump Application
+** Data Command \endlink fails to create the dump file.
+**
+** The \c 'd' parameter identifies, in decimal, the error code returned by #OS_OpenCreate when the attempt was made
+** to create the file.
+**/
+#define CFE_ES_OSCREATE_ERR_EID 51
+
+/** \brief 'Failed to write App Info file, WriteHdr rtnd \%08X, exp \%d'
+** \event 'Failed to write App Info file, WriteHdr rtnd \%08X, exp \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_QUERY_ALL_CC Dump Application
+** Data Command \endlink fails while writing the cFE Standard File Header.
+**
+** The \c rtnd field contains the error code returned by the #CFE_FS_WriteHeader API. Nominally, the
+** returned result should have been equal to the \c exp field (i.e. - sizeof(#CFE_FS_Header_t)).
+**/
+#define CFE_ES_WRHDR_ERR_EID 52
+
+/** \brief 'Failed to write App Info file, Task write RC = 0x\%08X, exp \%d'
+** \event 'Failed to write App Info file, Task write RC = 0x\%08X, exp \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever an Executive Services \link #CFE_ES_QUERY_ALL_CC Dump Application
+** Data Command \endlink fails while writing Application data to the specified file.
+**
+** The \c rtnd field contains, in hex, the error code returned from the #OS_write API. The expected return
+** value is identified, in decimal, in the \c exp field.
+**/
+#define CFE_ES_TASKWR_ERR_EID 53
+
+/** \brief 'Error creating file \%s, stat=0x\%x'
+** \event 'Error creating file \%s, stat=0x\%x'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_WRITE_SYSLOG_CC Dump System Log
+** Command \endlink fails while attempting to create the specified file.
+**
+** The \c 's' field identifies the name of the file that was attempted to be created and the \c stat field
+** specifies, in hex, the error code returned by the #OS_OpenCreate API.
+**/
+#define CFE_ES_SYSLOG2_ERR_EID 55
+
+/** \brief 'Error creating file \%s, stat=0x\%x'
+** \event 'Error creating file \%s, stat=0x\%x'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_WRITE_ER_LOG_CC Dump Exception Reset Log
+** Command \endlink fails while attempting to create the specified file.
+**
+** The \c 's' field identifies the name of the file that was attempted to be created and the \c stat field
+** specifies, in hex, the error code returned by the #OS_OpenCreate API.
+**/
+#define CFE_ES_ERLOG2_ERR_EID 56
+
+/** \brief 'Start collecting performance data command, trigger mode = %d'
+** \event 'Start collecting performance data command, trigger mode = %d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated in response to receiving an Executive Services
+** \link #CFE_ES_START_PERF_DATA_CC Start Performance Analyzer Data Collection Command \endlink
+**
+** The \c 'd' field identifies the requested trigger mode as defined by CFE_ES_PerfMode_t.
+**/
+#define CFE_ES_PERF_STARTCMD_EID 57
+
+/** \brief 'Cannot start collecting performance data,perf data write in progress'
+** \event 'Cannot start collecting performance data,perf data write in progress'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated in response to receiving an Executive Services
+** \link #CFE_ES_START_PERF_DATA_CC Start Performance Analyzer Data Collection Command \endlink
+**/
+#define CFE_ES_PERF_STARTCMD_ERR_EID 58
+
+/** \brief 'Cannot start collecting performance data, trigger mode (%d) out of range (%d to %d)'
+** \event 'Cannot start collecting performance data, trigger mode (%d) out of range (%d to %d)'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_START_PERF_DATA_CC
+** Start Performance Analyzer Data Collection Command \endlink command is received with a bad
+** value for the requested trigger mode.
+**
+** The first \c 'd' field identifies the received trigger mode value as defined by CFE_ES_PerfMode_t.
+** The second and third \c 'd' fields specify the valid range of values for the trigger mode.
+**/
+#define CFE_ES_PERF_STARTCMD_TRIG_ERR_EID 59
+
+/** \brief 'Perf Stop Cmd Rcvd,\%s will write \%d entries.\%dmS dly every \%d entries'
+** \event 'Perf Stop Cmd Rcvd,\%s will write \%d entries.\%dmS dly every \%d entries'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of a successful Performance Data Stop
+** Command after receiving the cFE Executive Services \link #CFE_ES_STOP_PERF_DATA_CC Stop
+** Performance Analyzer Data Collection Command \endlink
+**
+** The \c 's' field identifies the name of the file write task that has begun execution.
+** The first \c 'd' identifies the total number of performance entries(in decimal) that will be written to the file.
+** A performance data entry is defined by an unsigned 32 bit data point and an unsigned 64 bit time stamp.
+** The second \c 'd' identifies the millisecond delay between writes and the
+** third \c 'd' identifies the number of entries written (in decimal) between delays.
+**/
+#define CFE_ES_PERF_STOPCMD_EID 60
+
+/** \brief 'Stop performance data cmd ignored,perf data write in progress'
+** \event 'Stop performance data cmd ignored,perf data write in progress'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon receipt of an unsuccessful Performance Data Stop
+** Command after receiving the cFE Executive Services \link #CFE_ES_STOP_PERF_DATA_CC Stop
+** Performance Analyzer Data Collection Command \endlink
+**
+**/
+#define CFE_ES_PERF_STOPCMD_ERR2_EID 62
+
+/** \brief 'Set Performance Filter Mask command'
+** \event 'Set Performance Filter Mask command'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated in response to receiving an Executive Services
+** \link #CFE_ES_SET_PERF_FILTER_MASK_CC Set Performance Analyzer Filter Mask Command \endlink.
+**
+**/
+#define CFE_ES_PERF_FILTMSKCMD_EID 63
+
+/** \brief 'Performance Filter Mask Cmd Error,Index(%u)out of range(%u)'
+** \event 'Performance Filter Mask Cmd Error,Index(%u)out of range(%u)'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated in response to receiving an Executive Services
+** \link #CFE_ES_SET_PERF_FILTER_MASK_CC Set Performance Analyzer Filter Mask Command \endlink.
+**
+**/
+#define CFE_ES_PERF_FILTMSKERR_EID 64
+
+/** \brief 'Set Performance Trigger Mask command'
+** \event 'Set Performance Trigger Mask command'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated in response to receiving an Executive Services
+** \link #CFE_ES_SET_PERF_TRIGGER_MASK_CC Set Performance Analyzer Trigger Mask Command \endlink.
+**
+**/
+#define CFE_ES_PERF_TRIGMSKCMD_EID 65
+
+/** \brief 'Performance Trigger Mask Cmd Error,Index(%u)out of range(%u)'
+** \event 'Performance Trigger Mask Cmd Error,Index(%u)out of range(%u)'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated in response to receiving an Executive Services
+** \link #CFE_ES_SET_PERF_TRIGGER_MASK_CC Set Performance Analyzer Trigger Mask Command \endlink.
+**
+**/
+#define CFE_ES_PERF_TRIGMSKERR_EID 66
+
+/** \brief 'Error creating file \%s, stat=\%d'
+** \event 'Error creating file \%s, stat=\%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_STOP_PERF_DATA_CC Stop Performance Analyzer Data Collection Command \endlink
+** fails to create the associated logic analyzer dump file.
+**
+** The \c 's' field identifies the name of the file that was attempted to be created and the \c stat field
+** specifies, in decimal, the error code returned by the #OS_OpenCreate API.
+**/
+#define CFE_ES_PERF_LOG_ERR_EID 67
+
+/** \brief '\%s written:Size=\%d,EntryCount=\%d'
+** \event '\%s written:Size=\%d,EntryCount=\%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated when the Performance Log has been successfully written
+** to a file after receiving the cFE Executive Services \link #CFE_ES_STOP_PERF_DATA_CC Stop
+** Performance Analyzer Data Collection Command \endlink
+**
+** The \c 's' field identifies the name of the file written to, the \c Size field specifies, in decimal,
+** the number of bytes written to the file and the \c EntryCount field identifies the number of data
+** entries that were written.
+**/
+#define CFE_ES_PERF_DATAWRITTEN_EID 68
+
+/** \brief '\%s Failed to Register CDS '\%s', Status=0x\%08X'
+** \event '\%s Failed to Register CDS '\%s', Status=0x\%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever an Application calls the #CFE_ES_RegisterCDS API and
+** fails to successfully create the desired CDS.
+**
+** The first \c 's' field identifies the name of the Application which made the API call, the second
+** \c 's' field specifies the name of the CDS as requested by the Application and the \c Status field
+** provides the error code which identifies in more detail the nature of the failure (See return codes
+** for the #CFE_ES_RegisterCDS API).
+**/
+#define CFE_ES_CDS_REGISTER_ERR_EID 69
+
+/** \brief 'Set OverWriteSysLog Command Received with Mode setting = \%d'
+** \event 'Set OverWriteSysLog Command Received with Mode setting = \%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion of an Executive Services \link
+*#CFE_ES_OVER_WRITE_SYSLOG_CC
+** Set System Log Overwrite Mode Command \endlink.
+**
+** The \c setting field identifies the newly chosen Overwrite Mode and should be equal to either
+** #CFE_ES_LogMode_OVERWRITE or #CFE_ES_LogMode_DISCARD.
+**/
+#define CFE_ES_SYSLOGMODE_EID 70
+
+/** \brief 'Set OverWriteSysLog Command: Invalid Mode setting = \%d'
+** \event 'Set OverWriteSysLog Command: Invalid Mode setting = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated upon unsuccessful completion of an Executive Services \link
+*#CFE_ES_OVER_WRITE_SYSLOG_CC
+** Set System Log Overwrite Mode Command \endlink.
+**
+** The \c setting field identifies the illegal Overwrite Mode found in the command message. The mode
+** must be either #CFE_ES_LogMode_OVERWRITE (0) or #CFE_ES_LogMode_DISCARD (1).
+**/
+#define CFE_ES_ERR_SYSLOGMODE_EID 71
+
+/** \brief 'Reset Processor Reset Count to Zero'
+** \event 'Reset Processor Reset Count to Zero'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always generated in response to the Executive Services
+** \link #CFE_ES_RESET_PR_COUNT_CC Set Processor Reset Counter to Zero Command \endlink.
+**/
+#define CFE_ES_RESET_PR_COUNT_EID 72
+
+/** \brief 'Maximum Processor Reset Count set to: \%d'
+** \event 'Maximum Processor Reset Count set to: \%d'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always generated in response to the Executive Services
+** \link #CFE_ES_RESET_PR_COUNT_CC Set Maximum Processor Reset Limit Command \endlink.
+**
+** The \c 'd' field identifies, in decimal, the number of Processor Resets that will need
+** to occur before a Power-On Reset is automatically performed.
+**/
+#define CFE_ES_SET_MAX_PR_COUNT_EID 73
+
+/** \brief 'File write,byte cnt err,file \%s,request=\%d,actual=\%d'
+** \event 'File write,byte cnt err,file \%s,request=\%d,actual=\%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated in response to any command requesting information to be written
+** to a file and whose data is not completely written to the specified file.
+**
+** The \c file field identifies the filename of the file to which the data failed to write completely,
+** the \c request field specifies, in decimal, the number of bytes that were attempted to be written and
+** the \c actual field indicates, in decimal, the actual number of bytes written to the file.
+**/
+#define CFE_ES_FILEWRITE_ERR_EID 74
+
+/** \brief 'Error while deleting '\%s' from CDS, See SysLog.(Err=0x\%08X)'
+** \event 'Error while deleting '\%s' from CDS, See SysLog.(Err=0x\%08X)'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DELETE_CDS_CC Delete CDS Command \endlink
+** fails to cleanly remove the specified CDS.
+**
+** The \c 's' field identifies the name of the CDS that was attempted to be deleted the \c Err field
+** specifies, in hex, the error code.
+**/
+#define CFE_ES_CDS_DELETE_ERR_EID 76
+
+/** \brief 'Unable to locate '\%s' in CDS Registry'
+** \event 'Unable to locate '\%s' in CDS Registry'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DELETE_CDS_CC Delete CDS Command \endlink
+** specifies a name for a CDS that cannot be found in the CDS Registry.
+**
+** The \c 's' field identifies the name of the CDS that was attempted to be deleted.
+**/
+#define CFE_ES_CDS_NAME_ERR_EID 77
+
+/** \brief 'Successfully removed '\%s' from CDS'
+** \event 'Successfully removed '\%s' from CDS'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DELETE_CDS_CC Delete CDS Command \endlink
+** is successfully completed.
+**
+** The \c 's' field identifies the name of the CDS that was deleted.
+**/
+#define CFE_ES_CDS_DELETED_INFO_EID 78
+
+/** \brief 'CDS '\%s' is a Critical Table CDS. Must be deleted via TBL Command'
+** \event 'CDS '\%s' is a Critical Table CDS. Must be deleted via TBL Command'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DELETE_CDS_CC Delete CDS Command \endlink
+** specifies a name for a CDS that is a Critical Table image.
+** Critical Table images can only be deleted via a Table Services
+** command (#CFE_TBL_DELETE_CDS_CC).
+**
+** The \c 's' field identifies the name of the CDS that was attempted to be deleted.
+**/
+#define CFE_ES_CDS_DELETE_TBL_ERR_EID 79
+
+/** \brief 'CDS '\%s' not deleted because owning app is active'
+** \event 'CDS '\%s' not deleted because owning app is active'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DELETE_CDS_CC Delete CDS Command \endlink
+** specifies a name for a CDS whose prefix name identifies
+** an application that is still registered in the system.
+** CDSs can only be deleted when their owning applications
+** have been removed from the system.
+**
+** The \c 's' field identifies the name of the CDS that was attempted to be deleted.
+**/
+#define CFE_ES_CDS_OWNER_ACTIVE_EID 80
+
+/** \brief 'Successfully telemetered memory pool stats for 0x\%08X'
+** \event 'Successfully telemetered memory pool stats for 0x\%08X'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated following successful execution of the
+** \link #CFE_ES_SEND_MEM_POOL_STATS_CC Telemeter Memory Statistics Command \endlink.
+**/
+#define CFE_ES_TLM_POOL_STATS_INFO_EID 81
+
+/** \brief 'Cannot telemeter memory pool stats. Illegal Handle (0x\%08X)'
+** \event 'Cannot telemeter memory pool stats. Illegal Handle (0x\%08X)'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_SEND_MEM_POOL_STATS_CC Telemeter Memory Statistics Command \endlink
+** specifies a memory pool handle that is invalid. A handle is determined to
+** be invalid when any of the following are true:
+** -# The handle does not contain a value that is an integral multiple of 4
+** -# The handle does not specify a valid area of memory
+** -# The handle does not point to an area of memory that contains the handle itself
+** -# The handle does not point to an area of memory whose Size field is an integral multiple of 4
+** -# The handle does not point to an area of memory whose End field is equal to the Start plus the Size
+**
+** The \c '08X' field identifies the handle that was found in the command.
+**/
+#define CFE_ES_INVALID_POOL_HANDLE_ERR_EID 82
+
+/** \brief 'Successfully dumped CDS Registry to '\%s':Size=\%d,Entries=\%d'
+** \event 'Successfully dumped CDS Registry to '\%s':Size=\%d,Entries=\%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DUMP_CDS_REGISTRY_CC Dump Critical Data Store Registry Command \endlink
+** is successfully executed. The specified file should have been created
+** and contains the CDS Registry Entries.
+**
+** The \c 's' field identifies the CDS Registry Dump Filename.
+** The first \c 'd' field specifies the size of the file (in bytes)
+** The second \c 'd' field specifies the number of CDS Registry Records that were written
+**/
+#define CFE_ES_CDS_REG_DUMP_INF_EID 83
+
+/** \brief 'Error writing CDS Registry to '\%s', Status=0x\%08X'
+** \event 'Error writing CDS Registry to '\%s', Status=0x\%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DUMP_CDS_REGISTRY_CC Dump Critical Data Store Registry Command \endlink
+** was being performed and it encountered a filesystem write error while writing
+** a CDS Registry record.
+**
+** The \c 's' field identifies the CDS Registry Dump Filename.
+** The \c '08X' field identifies the error code returned from #OS_write that caused the command to abort.
+**/
+#define CFE_ES_CDS_DUMP_ERR_EID 84
+
+/** \brief 'Error writing cFE File Header to '\%s', Status=0x\%08X'
+** \event 'Error writing cFE File Header to '\%s', Status=0x\%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DUMP_CDS_REGISTRY_CC Dump Critical Data Store Registry Command \endlink
+** command successfully created the CDS Dump File onboard but encountered an error
+** while writing the standard cFE File Header to the file.
+**
+** The \c 's' field identifies the CDS Registry Dump Filename.
+** The \c '08X' field identifies error code returned by the API #CFE_FS_WriteHeader.
+**/
+#define CFE_ES_WRITE_CFE_HDR_ERR_EID 85
+
+/** \brief 'Error creating CDS dump file '\%s', Status=0x\%08X'
+** \event 'Error creating CDS dump file '\%s', Status=0x\%08X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services
+** \link #CFE_ES_DUMP_CDS_REGISTRY_CC Dump Critical Data Store Registry Command \endlink
+** is unable to create the specified file on the onboard filesystem.
+**
+** The \c 's' field identifies the CDS Registry Dump Filename.
+** The \c '08X' field identifies error code returned by the API #OS_OpenCreate.
+**/
+#define CFE_ES_CREATING_CDS_DUMP_ERR_EID 86
+
+/** \brief 'Task Info file written to \%s, Entries=\%d, FileSize=\%d'
+** \event 'Task Info file written to \%s, Entries=\%d, FileSize=\%d'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is issued upon successful completion of the cFE Executive
+** Services \link #CFE_ES_QUERY_ALL_TASKS_CC Query All Tasks command \endlink
+**
+** The \c 's' field identifies the name of the file to which all Executive Services Task
+** data has been written. The \c Entries field identifies, in decimal, the number of Tasks
+** whose data was written and the \c FileSize field gives the total number of bytes written to the
+** file.
+**/
+#define CFE_ES_TASKINFO_EID 87
+
+/** \brief 'Failed to write Task Info file, OS_OpenCreate returned \%d'
+** \event 'Failed to write Task Info file, OS_OpenCreate returned \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_QUERY_ALL_TASKS_CC Dump Task
+** Data Command \endlink fails to create the dump file.
+**
+** The \c 'd' parameter identifies, in decimal, the error code returned by #OS_OpenCreate when the attempt was made
+** to create the file.
+**/
+#define CFE_ES_TASKINFO_OSCREATE_ERR_EID 88
+
+/** \brief 'Failed to write Task Info file, WriteHdr rtnd \%08X, exp \%d'
+** \event 'Failed to write Task Info file, WriteHdr rtnd \%08X, exp \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_QUERY_ALL_TASKS_CC Dump Task
+** Data Command \endlink fails while writing the cFE Standard File Header.
+**
+** The \c rtnd field contains the error code returned by the #CFE_FS_WriteHeader API. Nominally, the
+** returned result should have been equal to the \c exp field (i.e. - sizeof(#CFE_FS_Header_t)).
+**/
+#define CFE_ES_TASKINFO_WRHDR_ERR_EID 89
+
+/** \brief 'Failed to write Task Info file, Task write RC = 0x\%08X, exp \%d'
+** \event 'Failed to write Task Info file, Task write RC = 0x\%08X, exp \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever an Executive Services \link #CFE_ES_QUERY_ALL_TASKS_CC Dump Tasks
+** Data Command \endlink fails while writing Tasks data to the specified file.
+**
+** The \c rtnd field contains, in hex, the error code returned from the #OS_write API. The expected return
+** value is identified, in decimal, in the \c exp field.
+**/
+#define CFE_ES_TASKINFO_WR_ERR_EID 90
+
+/** \brief 'Version Info: %s, %s'
+** \event 'Version Info: %s, %s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always automatically issued when the Executive Services
+** Task completes its Initialization and as part of the Noop command
+**
+** A separate version info event will be generated for every module which is statically
+** linked into the CFE core executable (e.g. OSAL, PSP, MSG, SBR, etc).
+**
+** The version information reported in this event is derived from the source revision
+** control system at build time, as opposed to manually-assigned semantic version numbers.
+** It is intendended to uniquely identify the actual source code that is currently running,
+** to the extent this is possible.
+**
+** The \c Mission version information also identifies the build configuration name, if available.
+**/
+#define CFE_ES_VERSION_INF_EID 91
+
+/** \brief 'Build %s by %s@%s, config %s'
+** \event 'Build %s by %s@%s, config %s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always automatically issued when the Executive Services
+** Task completes its Initialization, and as part of the Noop command.
+**
+** The \c Build field identifies the build date, time, hostname and user identifier of
+** the build host machine for the current running binary. The first string is the
+** build date/time, and the second string is formatted as "user@hostname"
+**
+** This additionally reports the configuration name that was selected by the user,
+** which may affect various platform/mission limits.
+**
+** By default, if not specified/overridden, the default values of these variables will be:
+** BUILDDATE ==> the output of "date +%Y%m%d%H%M"
+** HOSTNAME ==> the output of "hostname"
+** USER ==> the output of "whoami"
+**
+** The values can be overridden by setting an environment variable with the names above
+** to the value desired for the field when running "make".
+**/
+#define CFE_ES_BUILD_INF_EID 92
+
+/** \brief 'Error log write to file \%s already in progress'
+** \event 'Error log write to file \%s already in progress'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated when an Executive Services \link #CFE_ES_WRITE_ER_LOG_CC Dump Exception Reset Log
+** Command \endlink is received before a previously-issued command has finished executing
+**
+**/
+#define CFE_ES_ERLOG_PENDING_ERR_EID 93
+
+#endif /* CFE_ES_EVENTS_H */
diff --git a/modules/es/fsw/inc/cfe_es_msg.h b/modules/es/fsw/inc/cfe_es_msg.h
new file mode 100644
index 000000000..a52965c4c
--- /dev/null
+++ b/modules/es/fsw/inc/cfe_es_msg.h
@@ -0,0 +1,1570 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * cFE Executive Services (ES) Command and Telemetry packet definition file.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_MSG_H
+#define CFE_ES_MSG_H
+
+/*
+** Includes
+*/
+#include "common_types.h" /* Basic data types */
+#include "cfe_msg_hdr.h" /* for header definitions */
+#include "cfe_es_extern_typedefs.h"
+
+/*
+** ES task command packet command codes
+*/
+/** \name Executive Services Command Codes */
+/** \{ */
+/** \cfeescmd Executive Services No-Op
+**
+** \par Description
+** This command performs no other function than to increment the
+** command execution counter. The command may be used to verify
+** general aliveness of the Executive Services task.
+**
+** \cfecmdmnemonic \ES_NOOP
+**
+** \par Command Structure
+** #CFE_ES_NoopCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_NOOP_INF_EID informational event message will
+** be generated
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - the #CFE_ES_LEN_ERR_EID error event message will be generated
+**
+** \par Criticality
+** None
+**
+** \sa
+*/
+#define CFE_ES_NOOP_CC 0
+
+/** \cfeescmd Executive Services Reset Counters
+**
+** \par Description
+** This command resets the following counters within the Executive
+** Services housekeeping telemetry:
+** - Command Execution Counter
+** - Command Error Counter
+**
+** \cfecmdmnemonic \ES_RESETCTRS
+**
+** \par Command Structure
+** #CFE_ES_ResetCountersCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_RESET_INF_EID informational event message will be
+** generated
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - the #CFE_ES_LEN_ERR_EID error event message will be generated
+**
+** \par Criticality
+** This command is not inherently dangerous. However, it is
+** possible for ground systems and on-board safing procedures
+** to be designed such that they react to changes in the counter
+** values that are reset by this command.
+**
+** \sa #CFE_ES_RESET_PR_COUNT_CC
+*/
+#define CFE_ES_RESET_COUNTERS_CC 1
+
+/** \cfeescmd Executive Services Processor / Power-On Reset
+**
+** \par Description
+** This command restarts the cFE in one of two modes. The Power-On Reset
+** will cause the cFE to restart as though the power were first applied
+** to the processor. The Processor Reset will attempt to retain the contents
+** of the volatile disk and the contents of the Critical Data Store.
+** NOTE: If a requested Processor Reset should cause the
+** Processor Reset Counter (\b \c \ES_PROCRESETCNT)
+** to exceed OR EQUAL the limit #CFE_PLATFORM_ES_MAX_PROCESSOR_RESETS (which is reported in
+** housekeeping telemetry as \b \c \ES_MAXPROCRESETS),
+** the command is \b AUTOMATICALLY upgraded to a Power-On Reset.
+**
+** \cfecmdmnemonic \ES_RESET
+**
+** \par Command Structure
+** #CFE_ES_RestartCmd_t
+**
+** \par Command Verification
+** Successful execution of this command (as a Processor Reset)
+** may be verified with the following telemetry:
+** - \b \c \ES_PROCRESETCNT - processor reset counter will increment
+** - New entries in the Exception Reset Log and System Log can be found
+** NOTE: Verification of a Power-On Reset is shown through the loss of
+** data nominally retained through a Processor Reset
+** NOTE: Since the reset of the processor resets the command execution
+** counter (\b \c \ES_CMDPC), this counter \b CANNOT be used to verify
+** command execution.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The \link #CFE_ES_RestartCmd_Payload_t Restart Type \endlink was
+** not a recognized value.
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - the #CFE_ES_BOOT_ERR_EID error event message will be generated
+**
+** \par Criticality
+** This command is, by definition, dangerous. Significant loss of
+** data will occur. All processes and the cFE itself will be stopped
+** and restarted. With the Power-On reset option, all data on the
+** volatile disk and the contents of the Critical Data Store will be
+** lost.
+**
+** \sa #CFE_ES_RESET_PR_COUNT_CC, #CFE_ES_SET_MAX_PR_COUNT_CC
+*/
+#define CFE_ES_RESTART_CC 2
+
+/** \cfeescmd Load and Start an Application
+**
+** \par Description
+** This command starts the specified application with the
+** specified start address, stack size, etc options.
+**
+** \cfecmdmnemonic \ES_STARTAPP
+**
+** \par Command Structure
+** #CFE_ES_StartAppCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_START_INF_EID informational event message will be
+** generated
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The specified application filename string is either a NULL string
+** or less than four characters in length
+** - The specified application entry point is a NULL string
+** - The specified application name is a NULL string
+** - The specified stack size is less than #CFE_PLATFORM_ES_DEFAULT_STACK_SIZE
+** - The specified priority is greater than MAX_PRIORITY (as defined in osapi.c)
+** - The specified exception action is neither #CFE_ES_ExceptionAction_RESTART_APP (0) or
+** #CFE_ES_ExceptionAction_PROC_RESTART (1)
+** - The Operating System was unable to load the specified application file
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous although system resources
+** could be taxed beyond their limits with the starting of erroneous
+** or invalid applications.
+**
+** \sa #CFE_ES_STOP_APP_CC, #CFE_ES_RESTART_APP_CC, #CFE_ES_RELOAD_APP_CC
+*/
+#define CFE_ES_START_APP_CC 4
+
+/** \cfeescmd Stop and Unload Application
+**
+** \par Description
+** This command halts and removes the specified Application
+** from the system. \b NOTE: This command should never be used
+** on the Command Ingest application. This would prevent further
+** commands from entering the system. If Command Ingest needs to
+** be stopped and restarted, use #CFE_ES_RESTART_APP_CC or
+** #CFE_ES_RELOAD_APP_CC.
+**
+** \cfecmdmnemonic \ES_STOPAPP
+**
+** \par Command Structure
+** #CFE_ES_StopAppCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_STOP_DBG_EID debug event message will be
+** generated. NOTE: This event message only identifies that the
+** stop has been started, not that is has completed.
+** - Once the stop has successfully completed, the list of Applications
+** and Tasks created in response to the \b \c \ES_WRITEAPPINFO2FILE,
+** \b \c \ES_WRITETASKINFO2FILE should no longer contain the
+** specified application.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The specified application name is not recognized as an active application
+** - The specified application is one of the cFE's Core applications (ES, EVS, SB, TBL, TIME)
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+** - Additional information on the reason for command failure may be found
+** in the System Log
+**
+** \par Criticality
+** This command is not inherently dangerous, however the removal of certain
+** applications (e.g. - Spacecraft Attitude and Control) may have a detrimental effect
+** on the spacecraft.
+**
+** \sa #CFE_ES_START_APP_CC, #CFE_ES_RESTART_APP_CC, #CFE_ES_RELOAD_APP_CC
+*/
+#define CFE_ES_STOP_APP_CC 5
+
+/** \cfeescmd Stops, Unloads, Loads using the previous File name, and Restarts an Application
+**
+** \par Description
+** This command halts and removes the specified Application
+** from the system. Then it immediately loads the Application from
+** the same filename last used to start. This command is
+** especially useful for restarting a Command Ingest Application
+** since once it has been stopped, no further commands can come in
+** to restart it.
+**
+** \cfecmdmnemonic \ES_RESTARTAPP
+**
+** \par Command Structure
+** #CFE_ES_RestartAppCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_RESTART_APP_DBG_EID debug event message will be
+** generated. NOTE: This event message only identifies that the
+** act of stopping the application has begun, not that is has completed.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The original file is missing
+** - The specified application name is not recognized as an active application
+** - The specified application is one of the cFE's Core applications (ES, EVS, SB, TBL, TIME)
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+** - Additional information on the reason for command failure may be found
+** in the System Log
+**
+** \par Criticality
+** This command is not inherently dangerous, however the restarting of certain
+** applications (e.g. - Spacecraft Attitude and Control) may have a detrimental effect
+** on the spacecraft.
+**
+** \sa #CFE_ES_START_APP_CC, #CFE_ES_STOP_APP_CC, #CFE_ES_RELOAD_APP_CC
+*/
+#define CFE_ES_RESTART_APP_CC 6
+
+/** \cfeescmd Stops, Unloads, Loads from the command specfied File and Restarts an Application
+**
+** \par Description
+** This command halts and removes the specified Application
+** from the system. Then it immediately loads the Application from
+** the command specified file and restarts it. This command is
+** especially useful for restarting a Command Ingest Application
+** since once it has been stopped, no further commands can come in
+** to restart it.
+**
+** \cfecmdmnemonic \ES_RELOADAPP
+**
+** \par Command Structure
+** #CFE_ES_ReloadAppCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_RELOAD_APP_DBG_EID debug event message will be
+** generated. NOTE: This event message only identifies that the
+** act of stopping the application has begun, not that is has completed.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The reload file is missing
+** - The specified application name is not recognized as an active application
+** - The specified application is one of the cFE's Core applications (ES, EVS, SB, TBL, TIME)
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+** - Additional information on the reason for command failure may be found
+** in the System Log
+**
+** \par Criticality
+** This command is not inherently dangerous, however the restarting of certain
+** applications (e.g. - Spacecraft Attitude and Control) may have a detrimental effect
+** on the spacecraft.
+**
+** \sa #CFE_ES_START_APP_CC, #CFE_ES_STOP_APP_CC, #CFE_ES_RESTART_APP_CC
+*/
+#define CFE_ES_RELOAD_APP_CC 7
+
+/** \cfeescmd Request Executive Services Information on a Specified Application
+**
+** \par Description
+** This command takes the information kept by Executive Services on the
+** specified application and telemeters it to the ground.
+**
+** \cfecmdmnemonic \ES_QUERYAPP
+**
+** \par Command Structure
+** #CFE_ES_QueryOneCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_ONE_APP_EID debug event message will be
+** generated. NOTE: This event message only identifies that the
+** act of stopping the application has begun, not that is has completed.
+** - Receipt of the #CFE_ES_OneAppTlm_t telemetry packet
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The specified application name is not recognized as an active application
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** None
+**
+** \sa #CFE_ES_QUERY_ALL_CC, #CFE_ES_QUERY_ALL_TASKS_CC
+*/
+#define CFE_ES_QUERY_ONE_CC 8
+
+/** \cfeescmd Writes all Executive Services Information on All Applications to a File
+**
+** \par Description
+** This command takes the information kept by Executive Services on all of the
+** registered applications and writes it to the specified file.
+**
+** \cfecmdmnemonic \ES_WRITEAPPINFO2FILE
+**
+** \par Command Structure
+** #CFE_ES_QueryAllCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_ALL_APPS_EID debug event message will be
+** generated.
+** - The file specified in the command (or the default specified
+** by the #CFE_PLATFORM_ES_DEFAULT_APP_LOG_FILE configuration parameter) will be
+** updated with the lastest information.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - An Error occurs while trying to write to the file
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system (or overwrite an existing one) and could,
+** if performed repeatedly without sufficient file management by the
+** operator, fill the file system.
+**
+** \sa #CFE_ES_QUERY_ONE_CC, #CFE_ES_QUERY_ALL_TASKS_CC
+*/
+#define CFE_ES_QUERY_ALL_CC 9
+
+/** \cfeescmd Clear Executive Services System Log
+**
+** \par Description
+** This command clears the contents of the Executive Services System Log.
+**
+** \cfecmdmnemonic \ES_CLEARSYSLOG
+**
+** \par Command Structure
+** #CFE_ES_ClearSysLogCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_SYSLOG1_INF_EID informational event message will be
+** generated.
+** - \b \c \ES_SYSLOGBYTEUSED - System Log Bytes Used will go to zero
+** - \b \c \ES_SYSLOGENTRIES - Number of System Log Entries will go to zero
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not dangerous. However, any previously logged data
+** will be lost.
+**
+** \sa #CFE_ES_WRITE_SYSLOG_CC, #CFE_ES_CLEAR_ER_LOG_CC, #CFE_ES_WRITE_ER_LOG_CC,
+** #CFE_ES_OVER_WRITE_SYSLOG_CC
+*/
+#define CFE_ES_CLEAR_SYSLOG_CC 10
+
+/** \cfeescmd Writes contents of Executive Services System Log to a File
+**
+** \par Description
+** This command causes the contents of the Executive Services System Log
+** to be written to a log file.
+**
+** \cfecmdmnemonic \ES_WRITESYSLOG2FILE
+**
+** \par Command Structure
+** #CFE_ES_WriteSysLogCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_SYSLOG2_EID debug event message will be
+** generated.
+** - The file specified in the command (or the default specified
+** by the #CFE_PLATFORM_ES_DEFAULT_SYSLOG_FILE configuration parameter) will be
+** updated with the lastest information.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - An Error occurs while trying to write to the file
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system (or overwrite an existing one) and could,
+** if performed repeatedly without sufficient file management by the
+** operator, fill the file system.
+**
+** \sa #CFE_ES_CLEAR_SYSLOG_CC, #CFE_ES_CLEAR_ER_LOG_CC, #CFE_ES_WRITE_ER_LOG_CC,
+** #CFE_ES_OVER_WRITE_SYSLOG_CC
+*/
+#define CFE_ES_WRITE_SYSLOG_CC 11
+
+/** \cfeescmd Clears the contents of the Exeception and Reset Log
+**
+** \par Description
+** This command causes the contents of the Executive Services Exception
+** and Reset Log to be cleared.
+**
+** \cfecmdmnemonic \ES_CLEARERLOG
+**
+** \par Command Structure
+** #CFE_ES_ClearERLogCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_ERLOG1_INF_EID informational event message will be
+** generated.
+** - \b \c \ES_ERLOGINDEX - Index into Exception Reset Log goes to zero
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not dangerous. However, any previously logged data
+** will be lost.
+**
+** \sa #CFE_ES_CLEAR_SYSLOG_CC, #CFE_ES_WRITE_SYSLOG_CC, #CFE_ES_WRITE_ER_LOG_CC
+*/
+#define CFE_ES_CLEAR_ER_LOG_CC 12
+
+/** \cfeescmd Writes Exeception and Reset Log to a File
+**
+** \par Description
+** This command causes the contents of the Executive Services Exception
+** and Reset Log to be written to the specified file.
+**
+** \cfecmdmnemonic \ES_WRITEERLOG2FILE
+**
+** \par Command Structure
+** #CFE_ES_WriteERLogCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_ERLOG2_EID debug event message will be
+** generated.
+** - The file specified in the command (or the default specified
+** by the #CFE_PLATFORM_ES_DEFAULT_ER_LOG_FILE configuration parameter) will be
+** updated with the lastest information.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - An Error occurs while trying to write to the file
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system (or overwrite an existing one) and could,
+** if performed repeatedly without sufficient file management by the
+** operator, fill the file system.
+**
+** \sa #CFE_ES_CLEAR_SYSLOG_CC, #CFE_ES_WRITE_SYSLOG_CC, #CFE_ES_CLEAR_ER_LOG_CC
+*/
+#define CFE_ES_WRITE_ER_LOG_CC 13
+
+/** \cfeescmd Start Performance Analyzer
+**
+** \par Description
+** This command causes the Performance Analyzer to begin collecting data using the specified trigger mode.
+**
+** \cfecmdmnemonic \ES_STARTLADATA
+**
+** \par Command Structure
+** #CFE_ES_StartPerfDataCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - \b \c \ES_PERFSTATE - Current performance analyzer state will change to
+** either WAITING FOR TRIGGER or, if conditions are appropriate fast enough,
+** TRIGGERED.
+** - \b \c \ES_PERFMODE - Performance Analyzer Mode will change to the commanded trigger mode (TRIGGER START,
+** TRIGGER CENTER, or TRIGGER END).
+** - \b \c \ES_PERFTRIGCNT - Performance Trigger Count will go to zero
+** - \b \c \ES_PERFDATASTART - Data Start Index will go to zero
+** - \b \c \ES_PERFDATAEND - Data End Index will go to zero
+** - \b \c \ES_PERFDATACNT - Performance Data Counter will go to zero
+** - The #CFE_ES_PERF_STARTCMD_EID debug event message will be
+** generated.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - A previous #CFE_ES_STOP_PERF_DATA_CC command has not completely finished.
+** - An invalid trigger mode is requested.
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous but may cause a small increase in CPU
+** utilization as the performance analyzer data is collected.
+**
+** \sa #CFE_ES_STOP_PERF_DATA_CC, #CFE_ES_SET_PERF_FILTER_MASK_CC, #CFE_ES_SET_PERF_TRIGGER_MASK_CC
+*/
+#define CFE_ES_START_PERF_DATA_CC 14
+
+/** \cfeescmd Stop Performance Analyzer
+**
+** \par Description
+** This command stops the Performance Analyzer from collecting any more data.
+**
+** \cfecmdmnemonic \ES_STOPLADATA
+**
+** \par Command Structure
+** #CFE_ES_StopPerfDataCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - \b \c \ES_PERFSTATE - Current performance analyzer state will change to
+** IDLE.
+** - The #CFE_ES_PERF_STOPCMD_EID debug event message will be
+** generated.
+** - The file specified in the command (or the default specified
+** by the #CFE_PLATFORM_ES_DEFAULT_PERF_DUMP_FILENAME configuration parameter) will be
+** updated with the lastest information.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - A previous Stop Performance Analyzer command is still in process
+** - An error occurred while spawning the child task responsible for
+** dumping the Performance Analyzer data to a file
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous. An additional low priority child
+** task will be spawned, however, to dump the performance analyzer data to a file.
+**
+** \sa #CFE_ES_START_PERF_DATA_CC, #CFE_ES_SET_PERF_FILTER_MASK_CC, #CFE_ES_SET_PERF_TRIGGER_MASK_CC
+*/
+#define CFE_ES_STOP_PERF_DATA_CC 15
+
+/** \cfeescmd Set Performance Analyzer's Filter Masks
+**
+** \par Description
+** This command sets the Performance Analyzer's Filter Masks.
+**
+** \cfecmdmnemonic \ES_LAFILTERMASK
+**
+** \par Command Structure
+** #CFE_ES_SetPerfFilterMaskCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - \b \c \ES_PERFFLTRMASK - the current performance filter mask
+** value(s) should reflect the commanded value
+** - The #CFE_ES_PERF_FILTMSKCMD_EID debug event message will be
+** generated.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The Filter Mask ID number is out of range
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** Changing the filter masks may cause a small change in the Performance
+** Analyzer's CPU utilization.
+**
+** \sa #CFE_ES_START_PERF_DATA_CC, #CFE_ES_STOP_PERF_DATA_CC, #CFE_ES_SET_PERF_TRIGGER_MASK_CC
+*/
+#define CFE_ES_SET_PERF_FILTER_MASK_CC 16
+
+/** \cfeescmd Set Performance Analyzer's Trigger Masks
+**
+** \par Description
+** This command sets the Performance Analyzer's Trigger Masks.
+**
+** \cfecmdmnemonic \ES_LATRIGGERMASK
+**
+** \par Command Structure
+** #CFE_ES_SetPerfTriggerMaskCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - \b \c \ES_PERFTRIGMASK - the current performance trigger mask
+** value(s) should reflect the commanded value
+** - The #CFE_ES_PERF_TRIGMSKCMD_EID debug event message will be
+** generated.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The Trigger Mask ID number is out of range
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** Changing the trigger masks may cause a small change in the Performance
+** Analyzer's CPU utilization.
+**
+** \sa #CFE_ES_START_PERF_DATA_CC, #CFE_ES_STOP_PERF_DATA_CC, #CFE_ES_SET_PERF_FILTER_MASK_CC
+*/
+#define CFE_ES_SET_PERF_TRIGGER_MASK_CC 17
+
+/** \cfeescmd Set Executive Services System Log Mode to Discard/Overwrite
+**
+** \par Description
+** This command allows the user to configure the Executive Services
+** to either discard new System Log messages when it is full or to
+** overwrite the oldest messages.
+**
+** \cfecmdmnemonic \ES_OVERWRITESYSLOGMODE
+**
+** \par Command Structure
+** #CFE_ES_OverWriteSysLogCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - \b \c \ES_SYSLOGMODE - Current System Log Mode should reflect
+** the commanded value
+** - The #CFE_ES_SYSLOGMODE_EID debug event message will be
+** generated.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The desired mode is neither #CFE_ES_LogMode_OVERWRITE or #CFE_ES_LogMode_DISCARD
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** None. (It should be noted that "Overwrite" mode would allow a message
+** identifying the cause of a problem to be lost by a subsequent flood of
+** additional messages).
+**
+** \sa #CFE_ES_CLEAR_SYSLOG_CC, #CFE_ES_WRITE_SYSLOG_CC
+*/
+#define CFE_ES_OVER_WRITE_SYSLOG_CC 18
+
+/** \cfeescmd Resets the Processor Reset Counter to Zero
+**
+** \par Description
+** This command allows the user to reset the Processor Reset Counter to zero.
+** The Processor Reset Counter counts the number of Processor Resets that
+** have occurred so as to identify when a Processor Reset should automatically
+** be upgraded to a full Power-On Reset.
+**
+** \cfecmdmnemonic \ES_RESETPRCNT
+**
+** \par Command Structure
+** #CFE_ES_ResetPRCountCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - \b \c \ES_PROCRESETCNT - Current number of processor resets will go to zero
+** - The #CFE_ES_RESET_PR_COUNT_EID informational event message will be
+** generated.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not critical. The only impact would be that the system
+** would have to have more processor resets before an automatic power-on reset
+** occurred.
+**
+** \sa #CFE_ES_SET_MAX_PR_COUNT_CC, #CFE_ES_RESET_COUNTERS_CC
+*/
+#define CFE_ES_RESET_PR_COUNT_CC 19
+
+/** \cfeescmd Configure the Maximum Number of Processor Resets before a Power-On Reset
+**
+** \par Description
+** This command allows the user to specify the number of Processor Resets that
+** are allowed before the next Processor Reset is upgraded to a Power-On Reset.
+**
+** \cfecmdmnemonic \ES_SETMAXPRCNT
+**
+** \par Command Structure
+** #CFE_ES_SetMaxPRCountCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - \b \c \ES_MAXPROCRESETS - Current maximum number of processor resets
+** before an automatic power-on reset will go to the command specified value.
+** - The #CFE_ES_SET_MAX_PR_COUNT_EID informational event message will be
+** generated.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** If the operator were to set the Maximum Processor Reset Count to too high a value,
+** the processor would require an inordinate number of consecutive processor resets
+** before an automatic power-on reset would occur. This could potentially leave the
+** spacecraft without any control for a significant amount of time if a processor reset
+** fails to clear a problem.
+**
+** \sa #CFE_ES_RESET_PR_COUNT_CC
+*/
+#define CFE_ES_SET_MAX_PR_COUNT_CC 20
+
+/** \cfeescmd Delete Critical Data Store
+**
+** \par Description
+** This command allows the user to delete a Critical Data Store that was created
+** by an Application that is now no longer executing.
+**
+** \cfecmdmnemonic \ES_DELETECDS
+**
+** \par Command Structure
+** #CFE_ES_DeleteCDSCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_CDS_DELETED_INFO_EID informational event message will be
+** generated.
+** - The specified CDS should no longer appear in a CDS Registry dump generated
+** upon receipt of the #CFE_ES_DUMP_CDS_REGISTRY_CC command
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The specified CDS is the CDS portion of a Critical Table. See #CFE_TBL_DELETE_CDS_CC.
+** - The specified CDS is not found in the CDS Registry
+** - The specified CDS is associated with an Application that is still active
+** - An error occurred while accessing the CDS memory (see the System Log for more details)
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not critical because it is not possible to delete a CDS that is
+** associated with an active application. However, deleting a CDS does eliminate
+** any "history" that an application may be wishing to keep.
+**
+** \sa #CFE_ES_DUMP_CDS_REGISTRY_CC, #CFE_TBL_DELETE_CDS_CC
+*/
+#define CFE_ES_DELETE_CDS_CC 21
+
+/** \cfeescmd Telemeter Memory Pool Statistics
+**
+** \par Description
+** This command allows the user to obtain a snapshot of the statistics maintained
+** for a specified memory pool.
+**
+** \cfecmdmnemonic \ES_TLMPOOLSTATS
+**
+** \par Command Structure
+** #CFE_ES_SendMemPoolStatsCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_TLM_POOL_STATS_INFO_EID debug event message will be
+** generated.
+** - The \link #CFE_ES_MemStatsTlm_t Memory Pool Statistics Telemetry Packet \endlink
+** is produced
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - The specified handle is not associated with a known memory pool
+** - The specified handle caused a processor exception because it improperly
+** identified a segment of memory
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** An incorrect Memory Pool Handle value can cause a system crash.
+** Extreme care should be taken to ensure the memory handle value
+** used in the command is correct.
+**
+** \sa
+*/
+#define CFE_ES_SEND_MEM_POOL_STATS_CC 22
+
+/** \cfeescmd Dump Critical Data Store Registry to a File
+**
+** \par Description
+** This command allows the user to dump the Critical Data Store
+** Registry to an onboard file.
+**
+** \cfecmdmnemonic \ES_DUMPCDSREG
+**
+** \par Command Structure
+** #CFE_ES_DumpCDSRegistryCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_CDS_REG_DUMP_INF_EID debug event message will be
+** generated.
+** - The file specified in the command (or the default specified
+** by the #CFE_PLATFORM_ES_DEFAULT_CDS_REG_DUMP_FILE configuration parameter) will be
+** updated with the lastest information.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - Error occurred while trying to create the dump file
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system (or overwrite an existing one) and could,
+** if performed repeatedly without sufficient file management by the
+** operator, fill the file system.
+**
+** \sa #CFE_ES_DELETE_CDS_CC, #CFE_TBL_DELETE_CDS_CC
+*/
+#define CFE_ES_DUMP_CDS_REGISTRY_CC 23
+
+/** \cfeescmd Writes a list of All Executive Services Tasks to a File
+**
+** \par Description
+** This command takes the information kept by Executive Services on all of the
+** registered tasks and writes it to the specified file.
+**
+** \cfecmdmnemonic \ES_WRITETASKINFO2FILE
+**
+** \par Command Structure
+** #CFE_ES_QueryAllTasksCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with
+** the following telemetry:
+** - \b \c \ES_CMDPC - command execution counter will
+** increment
+** - The #CFE_ES_TASKINFO_EID debug event message will be
+** generated.
+** - The file specified in the command (or the default specified
+** by the #CFE_PLATFORM_ES_DEFAULT_TASK_LOG_FILE configuration parameter) will be
+** updated with the lastest information.
+**
+** \par Error Conditions
+** This command may fail for the following reason(s):
+** - The command packet length is incorrect
+** - An Error occurs while trying to write to the file
+**
+** Evidence of failure may be found in the following telemetry:
+** - \b \c \ES_CMDEC - command error counter will increment
+** - A command specific error event message is issued for all error
+** cases
+**
+** \par Criticality
+** This command is not inherently dangerous. It will create a new
+** file in the file system (or overwrite an existing one) and could,
+** if performed repeatedly without sufficient file management by the
+** operator, fill the file system.
+**
+** \sa #CFE_ES_QUERY_ALL_CC, CFE_ES_QUERY_ONE_CC
+*/
+#define CFE_ES_QUERY_ALL_TASKS_CC 24
+
+/** \} */
+
+/*************************************************************************/
+/********************************/
+/* Command Message Data Formats */
+/********************************/
+/**
+** \brief Generic "no arguments" command
+**
+** This command structure is used for commands that do not have any parameters.
+** This includes:
+** -# The Housekeeping Request Message
+** -# The No-Op Command (For details, see #CFE_ES_NOOP_CC)
+** -# The Reset Counters Command (For details, see #CFE_ES_RESET_COUNTERS_CC)
+*/
+typedef struct CFE_ES_NoArgsCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+} CFE_ES_NoArgsCmd_t;
+
+/*
+ * The following commands all share the "NoArgs" format
+ *
+ * They are each given their own type name matching the command name, which
+ * allows them to change independently in the future without changing the prototype
+ * of the handler function.
+ */
+typedef CFE_ES_NoArgsCmd_t CFE_ES_NoopCmd_t;
+typedef CFE_ES_NoArgsCmd_t CFE_ES_ResetCountersCmd_t;
+typedef CFE_ES_NoArgsCmd_t CFE_ES_ClearSysLogCmd_t;
+typedef CFE_ES_NoArgsCmd_t CFE_ES_ClearERLogCmd_t;
+typedef CFE_ES_NoArgsCmd_t CFE_ES_ResetPRCountCmd_t;
+
+/**
+** \brief Restart cFE Command Payload
+**
+** For command details, see #CFE_ES_RESTART_CC
+**
+**/
+typedef struct CFE_ES_RestartCmd_Payload
+{
+ uint16 RestartType; /**< \brief #CFE_PSP_RST_TYPE_PROCESSOR=Processor Reset
+ or #CFE_PSP_RST_TYPE_POWERON=Power-On Reset */
+} CFE_ES_RestartCmd_Payload_t;
+
+/**
+ * \brief Restart cFE Command
+ */
+typedef struct CFE_ES_RestartCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_RestartCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_RestartCmd_t;
+
+/**
+** \brief Generic file name command payload
+**
+** This format is shared by several executive services commands.
+** For command details, see #CFE_ES_QUERY_ALL_CC, #CFE_ES_QUERY_ALL_TASKS_CC,
+** #CFE_ES_WRITE_SYSLOG_CC, and #CFE_ES_WRITE_ER_LOG_CC
+**
+**/
+typedef struct CFE_ES_FileNameCmd_Payload
+{
+ char FileName[CFE_MISSION_MAX_PATH_LEN]; /**< \brief ASCII text string containing full path and
+ filename of file in which Application data is to be dumped */
+} CFE_ES_FileNameCmd_Payload_t;
+
+/**
+ * \brief Generic file name command
+ */
+typedef struct CFE_ES_FileNameCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_FileNameCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_FileNameCmd_t;
+
+/*
+ * Unique typedefs for each of the commands that utilize the FileNameCmd
+ * packet format
+ */
+typedef CFE_ES_FileNameCmd_t CFE_ES_QueryAllCmd_t;
+typedef CFE_ES_FileNameCmd_t CFE_ES_QueryAllTasksCmd_t;
+typedef CFE_ES_FileNameCmd_t CFE_ES_WriteSysLogCmd_t;
+typedef CFE_ES_FileNameCmd_t CFE_ES_WriteERLogCmd_t;
+
+/**
+** \brief Overwrite/Discard System Log Configuration Command Payload
+**
+** For command details, see #CFE_ES_OVER_WRITE_SYSLOG_CC
+**
+**/
+typedef struct CFE_ES_OverWriteSysLogCmd_Payload
+{
+ uint32 Mode; /**< \brief #CFE_ES_LogMode_DISCARD=Throw away most recent messages,
+ #CFE_ES_LogMode_OVERWRITE=Overwrite oldest with most recent */
+
+} CFE_ES_OverWriteSysLogCmd_Payload_t;
+
+/**
+ * \brief Overwrite/Discard System Log Configuration Command Payload
+ */
+typedef struct CFE_ES_OverWriteSysLogCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_OverWriteSysLogCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_OverWriteSysLogCmd_t;
+
+/**
+** \brief Start Application Command Payload
+**
+** For command details, see #CFE_ES_START_APP_CC
+**
+**/
+typedef struct CFE_ES_StartAppCmd_Payload
+{
+ char Application[CFE_MISSION_MAX_API_LEN]; /**< \brief Name of Application to be started */
+ char AppEntryPoint[CFE_MISSION_MAX_API_LEN]; /**< \brief Symbolic name of Application's entry point */
+ char AppFileName[CFE_MISSION_MAX_PATH_LEN]; /**< \brief Full path and filename of Application's
+ executable image */
+
+ CFE_ES_MemOffset_t StackSize; /**< \brief Desired stack size for the new application */
+
+ CFE_ES_ExceptionAction_Enum_t ExceptionAction; /**< \brief #CFE_ES_ExceptionAction_RESTART_APP=On exception,
+ restart Application,
+ #CFE_ES_ExceptionAction_PROC_RESTART=On exception,
+ perform a Processor Reset */
+ CFE_ES_TaskPriority_Atom_t Priority; /**< \brief The new Applications runtime priority. */
+
+} CFE_ES_StartAppCmd_Payload_t;
+
+/**
+ * \brief Start Application Command
+ */
+typedef struct CFE_ES_StartApp
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_StartAppCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_StartAppCmd_t;
+
+/**
+** \brief Generic application name command payload
+**
+** For command details, see #CFE_ES_STOP_APP_CC, #CFE_ES_RESTART_APP_CC, #CFE_ES_QUERY_ONE_CC
+**
+**/
+typedef struct CFE_ES_AppNameCmd_Payload
+{
+ char Application[CFE_MISSION_MAX_API_LEN]; /**< \brief ASCII text string containing Application Name */
+} CFE_ES_AppNameCmd_Payload_t;
+
+/**
+ * \brief Generic application name command
+ */
+typedef struct CFE_ES_AppNameCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_AppNameCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_AppNameCmd_t;
+
+/*
+ * Like NoArgsCmd, this message definition is shared by multiple commands.
+ * Create a separate typedef for each one so they can all evolve independently
+ * without affecting the prototype.
+ */
+typedef CFE_ES_AppNameCmd_t CFE_ES_StopAppCmd_t;
+typedef CFE_ES_AppNameCmd_t CFE_ES_RestartAppCmd_t;
+typedef CFE_ES_AppNameCmd_t CFE_ES_QueryOneCmd_t;
+
+/**
+** \brief Reload Application Command Payload
+**
+** For command details, see #CFE_ES_RELOAD_APP_CC
+**
+**/
+typedef struct CFE_ES_AppReloadCmd_Payload
+{
+ char Application[CFE_MISSION_MAX_API_LEN]; /**< \brief ASCII text string containing Application Name */
+ char AppFileName[CFE_MISSION_MAX_PATH_LEN]; /**< \brief Full path and filename of Application's
+ executable image */
+} CFE_ES_AppReloadCmd_Payload_t;
+
+/**
+ * \brief Reload Application Command
+ */
+typedef struct CFE_ES_ReloadAppCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_AppReloadCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_ReloadAppCmd_t;
+
+/**
+** \brief Set Maximum Processor Reset Count Command Payload
+**
+** For command details, see #CFE_ES_SET_MAX_PR_COUNT_CC
+**
+**/
+typedef struct CFE_ES_SetMaxPRCountCmd_Payload
+{
+ uint16 MaxPRCount; /**< \brief New maximum number of Processor Resets before
+ an automatic Power-On Reset is performed */
+} CFE_ES_SetMaxPRCountCmd_Payload_t;
+
+/**
+ * \brief Set Maximum Processor Reset Count Command
+ */
+typedef struct CFE_ES_SetMaxPRCountCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_SetMaxPRCountCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_SetMaxPRCountCmd_t;
+
+/**
+** \brief Delete Critical Data Store Command Payload
+**
+** For command details, see #CFE_ES_DELETE_CDS_CC
+**
+**/
+typedef struct CFE_ES_DeleteCDSCmd_Payload
+{
+ char
+ CdsName[CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN]; /**< \brief ASCII text string containing name of CDS to delete */
+
+} CFE_ES_DeleteCDSCmd_Payload_t;
+
+/**
+ * \brief Delete Critical Data Store Command
+ */
+typedef struct CFE_ES_DeleteCDSCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_DeleteCDSCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_DeleteCDSCmd_t;
+
+/**
+** \brief Start Performance Analyzer Command Payload
+**
+** For command details, see #CFE_ES_START_PERF_DATA_CC
+**
+**/
+typedef struct CFE_ES_StartPerfCmd_Payload
+{
+ uint32 TriggerMode; /**< \brief Desired trigger position (Start, Center, End) */
+} CFE_ES_StartPerfCmd_Payload_t;
+
+/**
+ * \brief Start Performance Analyzer Command
+ */
+typedef struct CFE_ES_StartPerfDataCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_StartPerfCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_StartPerfDataCmd_t;
+
+/**
+** \brief Stop Performance Analyzer Command Payload
+**
+** For command details, see #CFE_ES_STOP_PERF_DATA_CC
+**
+**/
+typedef struct CFE_ES_StopPerfCmd_Payload
+{
+ char DataFileName[CFE_MISSION_MAX_PATH_LEN]; /**< \brief ASCII text string of full path and filename
+ of file Performance Analyzer data is to be written */
+} CFE_ES_StopPerfCmd_Payload_t;
+
+/**
+ * \brief Stop Performance Analyzer Command
+ */
+typedef struct CFE_ES_StopPerfDataCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_StopPerfCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_StopPerfDataCmd_t;
+
+/**
+** \brief Set Performance Analyzer Filter Mask Command Payload
+**
+** For command details, see #CFE_ES_SET_PERF_FILTER_MASK_CC
+**
+**/
+typedef struct CFE_ES_SetPerfFilterMaskCmd_Payload
+{
+ uint32 FilterMaskNum; /**< \brief Index into array of Filter Masks */
+ uint32 FilterMask; /**< \brief New Mask for specified entry in array of Filter Masks */
+
+} CFE_ES_SetPerfFilterMaskCmd_Payload_t;
+
+/**
+ * \brief Set Performance Analyzer Filter Mask Command
+ */
+typedef struct CFE_ES_SetPerfFilterMaskCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_SetPerfFilterMaskCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_SetPerfFilterMaskCmd_t;
+
+/**
+** \brief Set Performance Analyzer Trigger Mask Command Payload
+**
+** For command details, see #CFE_ES_SET_PERF_TRIGGER_MASK_CC
+**
+**/
+typedef struct CFE_ES_SetPerfTrigMaskCmd_Payload
+{
+ uint32 TriggerMaskNum; /**< \brief Index into array of Trigger Masks */
+ uint32 TriggerMask; /**< \brief New Mask for specified entry in array of Trigger Masks */
+
+} CFE_ES_SetPerfTrigMaskCmd_Payload_t;
+
+/**
+ * \brief Set Performance Analyzer Trigger Mask Command
+ */
+typedef struct CFE_ES_SetPerfTriggerMaskCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_SetPerfTrigMaskCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_SetPerfTriggerMaskCmd_t;
+
+/**
+** \brief Send Memory Pool Statistics Command Payload
+**
+** For command details, see #CFE_ES_SEND_MEM_POOL_STATS_CC
+**
+**/
+typedef struct CFE_ES_SendMemPoolStatsCmd_Payload
+{
+ char Application[CFE_MISSION_MAX_API_LEN]; /**< \brief - RESERVED - should be all zeroes */
+ CFE_ES_MemHandle_t PoolHandle; /**< \brief Handle of Pool whose statistics are to be telemetered */
+
+} CFE_ES_SendMemPoolStatsCmd_Payload_t;
+
+/**
+ * \brief Send Memory Pool Statistics Command
+ */
+typedef struct CFE_ES_SendMemPoolStatsCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_SendMemPoolStatsCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_SendMemPoolStatsCmd_t;
+
+/**
+** \brief Dump CDS Registry Command Payload
+**
+** For command details, see #CFE_ES_DUMP_CDS_REGISTRY_CC
+**
+**/
+typedef struct CFE_ES_DumpCDSRegistryCmd_Payload
+{
+ char DumpFilename[CFE_MISSION_MAX_PATH_LEN]; /**< \brief ASCII text string of full path and filename
+ of file CDS Registry is to be written */
+} CFE_ES_DumpCDSRegistryCmd_Payload_t;
+
+/**
+ * \brief Dump CDS Registry Command
+ */
+typedef struct CFE_ES_DumpCDSRegistryCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_ES_DumpCDSRegistryCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_ES_DumpCDSRegistryCmd_t;
+
+/*************************************************************************/
+
+/************************************/
+/* Telemetry Interface Data Formats */
+/************************************/
+
+/**********************************/
+/* Telemetry Message Data Formats */
+/**********************************/
+/**
+** \cfeestlm Single Application Information Packet
+**/
+typedef struct CFE_ES_OneAppTlm_Payload
+{
+ CFE_ES_AppInfo_t AppInfo; /**< \brief For more information, see #CFE_ES_AppInfo_t */
+
+} CFE_ES_OneAppTlm_Payload_t;
+
+typedef struct CFE_ES_OneAppTlm
+{
+ CFE_MSG_TelemetryHeader_t TlmHeader; /**< \brief Telemetry header */
+ CFE_ES_OneAppTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_ES_OneAppTlm_t;
+
+/**
+** \cfeestlm Memory Pool Statistics Packet
+**/
+typedef struct CFE_ES_PoolStatsTlm_Payload
+{
+ CFE_ES_MemHandle_t PoolHandle; /**< \cfetlmmnemonic \ES_POOLHANDLE
+ \brief Handle of memory pool whose stats are being telemetered */
+ CFE_ES_MemPoolStats_t PoolStats; /**< \brief For more info, see #CFE_ES_MemPoolStats_t */
+} CFE_ES_PoolStatsTlm_Payload_t;
+
+typedef struct CFE_ES_MemStatsTlm
+{
+ CFE_MSG_TelemetryHeader_t TlmHeader; /**< \brief Telemetry header */
+ CFE_ES_PoolStatsTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_ES_MemStatsTlm_t;
+
+/*************************************************************************/
+
+/**
+** \cfeestlm Executive Services Housekeeping Packet
+**/
+typedef struct CFE_ES_HousekeepingTlm_Payload
+{
+ uint8 CommandCounter; /**< \cfetlmmnemonic \ES_CMDPC
+ \brief The ES Application Command Counter */
+ uint8 CommandErrorCounter; /**< \cfetlmmnemonic \ES_CMDEC
+ \brief The ES Application Command Error Counter */
+
+ uint16 CFECoreChecksum; /**< \cfetlmmnemonic \ES_CKSUM
+ \brief Checksum of cFE Core Code */
+ uint8 CFEMajorVersion; /**< \cfetlmmnemonic \ES_CFEMAJORVER
+ \brief Major Version Number of cFE */
+ uint8 CFEMinorVersion; /**< \cfetlmmnemonic \ES_CFEMINORVER
+ \brief Minor Version Number of cFE */
+ uint8 CFERevision; /**< \cfetlmmnemonic \ES_CFEREVISION
+ \brief Sub-Minor Version Number of cFE */
+ uint8 CFEMissionRevision; /**< \cfetlmmnemonic \ES_CFEMISSIONREV
+ \brief Mission Version Number of cFE */
+ uint8 OSALMajorVersion; /**< \cfetlmmnemonic \ES_OSMAJORVER
+ \brief OS Abstraction Layer Major Version Number */
+ uint8 OSALMinorVersion; /**< \cfetlmmnemonic \ES_OSMINORVER
+ \brief OS Abstraction Layer Minor Version Number */
+ uint8 OSALRevision; /**< \cfetlmmnemonic \ES_OSREVISION
+ \brief OS Abstraction Layer Revision Number */
+ uint8 OSALMissionRevision; /**< \cfetlmmnemonic \ES_OSMISSIONREV
+ \brief OS Abstraction Layer MissionRevision Number */
+
+ uint8 PSPMajorVersion; /**< \cfetlmmnemonic \ES_PSPMAJORVER
+ \brief Platform Support Package Major Version Number */
+ uint8 PSPMinorVersion; /**< \cfetlmmnemonic \ES_PSPMINORVER
+ \brief Platform Support Package Minor Version Number */
+ uint8 PSPRevision; /**< \cfetlmmnemonic \ES_PSPREVISION
+ \brief Platform Support Package Revision Number */
+ uint8 PSPMissionRevision; /**< \cfetlmmnemonic \ES_PSPMISSIONREV
+ \brief Platform Support Package MissionRevision Number */
+
+ CFE_ES_MemOffset_t SysLogBytesUsed; /**< \cfetlmmnemonic \ES_SYSLOGBYTEUSED
+ \brief Total number of bytes used in system log */
+ CFE_ES_MemOffset_t SysLogSize; /**< \cfetlmmnemonic \ES_SYSLOGSIZE
+ \brief Total size of the system log */
+ uint32 SysLogEntries; /**< \cfetlmmnemonic \ES_SYSLOGENTRIES
+ \brief Number of entries in the system log */
+ uint32 SysLogMode; /**< \cfetlmmnemonic \ES_SYSLOGMODE
+ \brief Write/Overwrite Mode */
+
+ uint32 ERLogIndex; /**< \cfetlmmnemonic \ES_ERLOGINDEX
+ \brief Current index of the ER Log (wraps around) */
+ uint32 ERLogEntries; /**< \cfetlmmnemonic \ES_ERLOGENTRIES
+ \brief Number of entries made in the ER Log since the power on */
+
+ uint32 RegisteredCoreApps; /**< \cfetlmmnemonic \ES_REGCOREAPPS
+ \brief Number of Applications registered with ES */
+ uint32 RegisteredExternalApps; /**< \cfetlmmnemonic \ES_REGEXTAPPS
+ \brief Number of Applications registered with ES */
+ uint32 RegisteredTasks; /**< \cfetlmmnemonic \ES_REGTASKS
+ \brief Number of Tasks ( main AND child tasks ) registered with ES */
+ uint32 RegisteredLibs; /**< \cfetlmmnemonic \ES_REGLIBS
+ \brief Number of Libraries registered with ES */
+
+ uint32 ResetType; /**< \cfetlmmnemonic \ES_RESETTYPE
+ \brief Reset type ( PROCESSOR or POWERON ) */
+ uint32 ResetSubtype; /**< \cfetlmmnemonic \ES_RESETSUBTYPE
+ \brief Reset Sub Type */
+ uint32 ProcessorResets; /**< \cfetlmmnemonic \ES_PROCRESETCNT
+ \brief Number of processor resets since last power on */
+ uint32 MaxProcessorResets; /**< \cfetlmmnemonic \ES_MAXPROCRESETS
+ \brief Max processor resets before a power on is done */
+ uint32 BootSource; /**< \cfetlmmnemonic \ES_BOOTSOURCE
+ \brief Boot source ( as provided from BSP ) */
+
+ uint32 PerfState; /**< \cfetlmmnemonic \ES_PERFSTATE
+ \brief Current state of Performance Analyzer */
+ uint32 PerfMode; /**< \cfetlmmnemonic \ES_PERFMODE
+ \brief Current mode of Performance Analyzer */
+ uint32 PerfTriggerCount; /**< \cfetlmmnemonic \ES_PERFTRIGCNT
+ \brief Number of Times Perfomance Analyzer has Triggered */
+ uint32 PerfFilterMask[CFE_MISSION_ES_PERF_MAX_IDS / 32]; /**< \cfetlmmnemonic \ES_PERFFLTRMASK
+ \brief Current Setting of Performance Analyzer Filter Masks */
+ uint32
+ PerfTriggerMask[CFE_MISSION_ES_PERF_MAX_IDS / 32]; /**< \cfetlmmnemonic \ES_PERFTRIGMASK
+ \brief Current Setting of Performance Analyzer Trigger Masks */
+ uint32 PerfDataStart; /**< \cfetlmmnemonic \ES_PERFDATASTART
+ \brief Identifies First Stored Entry in Performance Analyzer Log */
+ uint32 PerfDataEnd; /**< \cfetlmmnemonic \ES_PERFDATAEND
+ \brief Identifies Last Stored Entry in Performance Analyzer Log */
+ uint32 PerfDataCount; /**< \cfetlmmnemonic \ES_PERFDATACNT
+ \brief Number of Entries Put Into the Performance Analyzer Log */
+ uint32
+ PerfDataToWrite; /**< \cfetlmmnemonic \ES_PERFDATA2WRITE
+ \brief Number of Performance Analyzer Log Entries Left to be Written to Log Dump File */
+ CFE_ES_MemOffset_t HeapBytesFree; /**< \cfetlmmnemonic \ES_HEAPBYTESFREE
+ \brief Number of free bytes remaining in the OS heap */
+ CFE_ES_MemOffset_t HeapBlocksFree; /**< \cfetlmmnemonic \ES_HEAPBLKSFREE
+ \brief Number of free blocks remaining in the OS heap */
+ CFE_ES_MemOffset_t HeapMaxBlockSize; /**< \cfetlmmnemonic \ES_HEAPMAXBLK
+ \brief Number of bytes in the largest free block */
+} CFE_ES_HousekeepingTlm_Payload_t;
+
+typedef struct CFE_ES_HousekeepingTlm
+{
+ CFE_MSG_TelemetryHeader_t TlmHeader; /**< \brief Telemetry header */
+ CFE_ES_HousekeepingTlm_Payload_t Payload; /**< \brief Telemetry payload */
+
+} CFE_ES_HousekeepingTlm_t;
+
+#endif /* CFE_ES_MSG_H */
diff --git a/modules/es/fsw/src/cfe_es_api.c b/modules/es/fsw/src/cfe_es_api.c
new file mode 100644
index 000000000..3ac9f1ff0
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_api.c
@@ -0,0 +1,2136 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_api.c
+**
+** Purpose:
+** This file implements the cFE Executive Services API functions.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+** Notes:
+**
+*/
+
+/*
+** Required header files.
+*/
+#include "cfe_es_module_all.h"
+
+#include
+#include
+#include
+
+/*
+** Function: CFE_ES_GetResetType - See API and header file for details
+*/
+int32 CFE_ES_GetResetType(uint32 *ResetSubtypePtr)
+{
+ if (ResetSubtypePtr != NULL)
+ {
+ *ResetSubtypePtr = CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype;
+ }
+
+ return (CFE_ES_Global.ResetDataPtr->ResetVars.ResetType);
+
+} /* End of CFE_ES_GetResetType() */
+
+/*
+** Function: CFE_ES_ResetCFE - See API and header file for details
+*/
+int32 CFE_ES_ResetCFE(uint32 ResetType)
+{
+ int32 ReturnCode;
+
+ if (ResetType == CFE_PSP_RST_TYPE_PROCESSOR)
+ {
+ /*
+ ** Increment the processor reset count
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount++;
+
+ /*
+ ** Before doing a Processor reset, check to see
+ ** if the maximum number has been exceeded
+ */
+ if (CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount >
+ CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount)
+ {
+ CFE_ES_WriteToSysLog("POWER ON RESET due to max proc resets (Commanded).\n");
+
+ /*
+ ** Log the reset in the ER Log. The log will be wiped out, but it's good to have
+ ** the entry just in case something fails.
+ */
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, CFE_PSP_RST_SUBTYPE_RESET_COMMAND,
+ "POWER ON RESET due to max proc resets (Commanded).");
+ /*
+ ** Call the BSP reset routine
+ */
+ CFE_PSP_Restart(CFE_PSP_RST_TYPE_POWERON);
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("PROCESSOR RESET called from CFE_ES_ResetCFE (Commanded).\n");
+
+ /*
+ ** Update the reset variables
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.ES_CausedReset = true;
+
+ /*
+ ** Log the reset in the ER Log
+ */
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, CFE_PSP_RST_SUBTYPE_RESET_COMMAND,
+ "PROCESSOR RESET called from CFE_ES_ResetCFE (Commanded).");
+ /*
+ ** Call the BSP reset routine
+ */
+ CFE_PSP_Restart(CFE_PSP_RST_TYPE_PROCESSOR);
+
+ } /* end if */
+
+ /*
+ ** If the BSP routine is not implemented,
+ ** it will return.
+ */
+ ReturnCode = CFE_ES_NOT_IMPLEMENTED;
+ }
+ else if (ResetType == CFE_PSP_RST_TYPE_POWERON)
+ {
+ CFE_ES_WriteToSysLog("POWERON RESET called from CFE_ES_ResetCFE (Commanded).\n");
+
+ /*
+ ** Log the reset in the ER Log. The log will be wiped out, but it's good to have
+ ** the entry just in case something fails.
+ */
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, CFE_PSP_RST_SUBTYPE_RESET_COMMAND,
+ "POWERON RESET called from CFE_ES_ResetCFE (Commanded).");
+
+ /*
+ ** Call the BSP reset routine
+ */
+ CFE_PSP_Restart(CFE_PSP_RST_TYPE_POWERON);
+
+ /*
+ ** If the BSP routine is not implemented,
+ ** it will return.
+ */
+ ReturnCode = CFE_ES_NOT_IMPLEMENTED;
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("ES ResetCFE: Invalid Reset Type: %d.\n", (int)ResetType);
+ ReturnCode = CFE_ES_BAD_ARGUMENT;
+ }
+
+ return (ReturnCode);
+
+} /* End of CFE_ES_ResetCFE() */
+
+/*
+** Function: CFE_ES_RestartApp - See API and header file for details
+*/
+int32 CFE_ES_RestartApp(CFE_ES_AppId_t AppID)
+{
+ int32 ReturnCode = CFE_SUCCESS;
+ os_fstat_t FileStatus;
+ CFE_ES_AppRecord_t *AppRecPtr;
+
+ AppRecPtr = CFE_ES_LocateAppRecordByID(AppID);
+ if (AppRecPtr != NULL)
+ {
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Check to see if the App is an external cFE App.
+ */
+ if (AppRecPtr->Type == CFE_ES_AppType_CORE)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_RestartApp: Cannot Restart a CORE Application: %s.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else if (AppRecPtr->AppState != CFE_ES_AppState_RUNNING)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_RestartApp: Cannot Restart Application %s, It is not running.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else
+ {
+ /*
+ ** Check to see if the file exists
+ */
+ if (OS_stat(AppRecPtr->StartParams.BasicInfo.FileName, &FileStatus) == OS_SUCCESS)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_RestartApp: Restart Application %s Initiated\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART;
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_RestartApp: Cannot Restart Application %s, File %s does not exist.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr),
+ AppRecPtr->StartParams.BasicInfo.FileName);
+ ReturnCode = CFE_ES_FILE_IO_ERR;
+ }
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+ }
+ else /* App ID is not valid */
+ {
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+
+ CFE_ES_WriteToSysLog("CFE_ES_RestartApp: Invalid Application ID received, AppID = %lu\n",
+ CFE_RESOURCEID_TO_ULONG(AppID));
+
+ } /* end if */
+
+ return (ReturnCode);
+
+} /* End of CFE_ES_RestartApp() */
+
+/*
+** Function: CFE_ES_ReloadApp - See API and header file for details
+*/
+int32 CFE_ES_ReloadApp(CFE_ES_AppId_t AppID, const char *AppFileName)
+{
+ int32 ReturnCode = CFE_SUCCESS;
+ os_fstat_t FileStatus;
+ CFE_ES_AppRecord_t *AppRecPtr = CFE_ES_LocateAppRecordByID(AppID);
+
+ if (AppRecPtr == NULL)
+ {
+ return CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Check to see if the App is an external cFE App.
+ */
+ if (AppRecPtr->Type == CFE_ES_AppType_CORE)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteApp: Cannot Reload a CORE Application: %s.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else if (AppRecPtr->AppState != CFE_ES_AppState_RUNNING)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ReloadApp: Cannot Reload Application %s, It is not running.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else
+ {
+ /*
+ ** Check to see if the file exists
+ */
+ if (OS_stat(AppFileName, &FileStatus) == OS_SUCCESS)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ReloadApp: Reload Application %s Initiated. New filename = %s\n",
+ CFE_ES_AppRecordGetName(AppRecPtr), AppFileName);
+ strncpy(AppRecPtr->StartParams.BasicInfo.FileName, AppFileName,
+ sizeof(AppRecPtr->StartParams.BasicInfo.FileName) - 1);
+ AppRecPtr->StartParams.BasicInfo.FileName[sizeof(AppRecPtr->StartParams.BasicInfo.FileName) - 1] = 0;
+ AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD;
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ReloadApp: Cannot Reload Application %s, File %s does not exist.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr), AppFileName);
+ ReturnCode = CFE_ES_FILE_IO_ERR;
+ }
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (ReturnCode);
+
+} /* End of CFE_ES_ReloadApp() */
+
+/*
+** Function: CFE_ES_DeleteApp - See API and header file for details
+*/
+int32 CFE_ES_DeleteApp(CFE_ES_AppId_t AppID)
+{
+ int32 ReturnCode = CFE_SUCCESS;
+ CFE_ES_AppRecord_t *AppRecPtr = CFE_ES_LocateAppRecordByID(AppID);
+
+ if (AppRecPtr == NULL)
+ {
+ return CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Check to see if the App is an external cFE App.
+ */
+ if (AppRecPtr->Type == CFE_ES_AppType_CORE)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteApp: Cannot Delete a CORE Application: %s.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else if (AppRecPtr->AppState != CFE_ES_AppState_RUNNING)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteApp: Cannot Delete Application %s, It is not running.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteApp: Delete Application %s Initiated\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (ReturnCode);
+
+} /* End of CFE_ES_DeleteApp() */
+
+/*
+** Function: CFE_ES_ExitApp - See API and header file for details
+*/
+void CFE_ES_ExitApp(uint32 ExitStatus)
+{
+ int32 ReturnCode;
+ CFE_ES_AppRecord_t *AppRecPtr;
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ * This should only be called with a valid ExitStatus, anything else is invalid
+ * and indicates a bug in the caller.
+ */
+
+ if (ExitStatus == CFE_ES_RunStatus_UNDEFINED || ExitStatus >= CFE_ES_RunStatus_MAX)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ExitApp: Called with invalid status (%u).\n", (unsigned int)ExitStatus);
+
+ /* revert to the ERROR status */
+ ExitStatus = CFE_ES_RunStatus_APP_ERROR;
+ }
+
+ AppRecPtr = CFE_ES_GetAppRecordByContext();
+ if (AppRecPtr != NULL)
+ {
+ /*
+ * Set the status in the global table.
+ *
+ * The passed-in status should only be stored if there was no already-pending
+ * request from a ground command or other source, such as an exception, etc.
+ *
+ * If a control request is already pending, it is assumed that this exit is
+ * part of an orderly shutdown caused by that request, and therefore it
+ * should not be overwritten here.
+ */
+ if (AppRecPtr->ControlReq.AppControlRequest == CFE_ES_RunStatus_APP_RUN)
+ {
+ AppRecPtr->ControlReq.AppControlRequest = ExitStatus;
+ }
+
+ /*
+ ** Check to see if the App is an external cFE App.
+ */
+ if (AppRecPtr->Type == CFE_ES_AppType_CORE)
+ {
+ /*
+ ** A core app should only call this function with one of two ExitStatus codes.
+ */
+ if (ExitStatus == CFE_ES_RunStatus_CORE_APP_INIT_ERROR)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ExitApp: CORE Application %s Had an Init Error.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+
+ /*
+ ** Unlock the ES Shared data before calling ResetCFE
+ */
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** Do a Processor Reset the cFE
+ */
+ ReturnCode = CFE_ES_ResetCFE(CFE_PSP_RST_TYPE_PROCESSOR);
+
+ /*
+ ** The CFE_ES_ResetCFE function does not normally return,
+ ** but it may return during unit testing. If it does,
+ ** log the return code (even if it claims CFE_SUCCESS).
+ */
+ CFE_ES_WriteToSysLog("CFE_ES_ExitApp: CORE Application Init Error Processor Reset, RC = 0x%08X\n",
+ (unsigned int)ReturnCode);
+
+ return;
+ }
+ else if (ExitStatus == CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ExitApp: CORE Application %s Had a Runtime Error.\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+
+ /*
+ ** Unlock the ES Shared data before killing the main task
+ */
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** Exit this task
+ */
+ OS_TaskExit();
+
+ /*
+ ** Code will not return, except under unit test
+ */
+ return;
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ExitApp, Cannot Exit CORE Application %s\n",
+ CFE_ES_AppRecordGetName(AppRecPtr));
+ }
+ }
+ else /* It is an external App */
+ {
+
+ CFE_ES_SysLogWrite_Unsync("Application %s called CFE_ES_ExitApp\n", CFE_ES_AppRecordGetName(AppRecPtr));
+
+ AppRecPtr->AppState = CFE_ES_AppState_STOPPED;
+
+ /*
+ ** Unlock the ES Shared data before suspending the app
+ */
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** Suspend the Application until ES kills it.
+ ** It might be better to have a way of suspending the app in the OS
+ */
+ while (1)
+ {
+ OS_TaskDelay(500);
+ }
+
+ } /* end if */
+
+ } /* end if ReturnCode == CFE_SUCCESS */
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+} /* End of CFE_ES_ExitApp() */
+
+/*
+** Function: CFE_ES_RunLoop - See API and header file for details
+*/
+bool CFE_ES_RunLoop(uint32 *RunStatus)
+{
+ bool ReturnCode;
+ CFE_ES_AppRecord_t *AppRecPtr;
+
+ /*
+ * call CFE_ES_IncrementTaskCounter() so this is
+ * recorded as task activity for outgoing telemetry.
+ *
+ * This will update the counter for whatever task context
+ * is calling this API, which is expected to be the main
+ * task of the app. This can be done outside of any lock
+ * because each task has its own counter which is only updated
+ * by itself.
+ */
+ CFE_ES_IncrementTaskCounter();
+
+ /*
+ * This API should generally only be called with the status as CFE_ES_RunStatus_APP_RUN.
+ * Anything else gets an immediate "false" return which should cause the caller to
+ * break out of its main loop. There is no need to take the lock or do any other
+ * accounting in that case.
+ *
+ * Note that the RunStatus really doesn't add much value here, so this also allows
+ * this function to be called with NULL, with the possibility of phasing this out
+ * entirely.
+ */
+ if (RunStatus != NULL && *RunStatus != CFE_ES_RunStatus_APP_RUN)
+ {
+ return false;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Get App Record
+ */
+ AppRecPtr = CFE_ES_GetAppRecordByContext();
+ if (AppRecPtr != NULL)
+ {
+ /*
+ ** App state must be RUNNING (no-op if already set to running)
+ */
+ if (AppRecPtr->AppState < CFE_ES_AppState_RUNNING)
+ {
+ AppRecPtr->AppState = CFE_ES_AppState_RUNNING;
+ }
+
+ /*
+ * Check if the control request is also set to "RUN"
+ * Anything else should also return false, so the the loop will exit.
+ */
+ if (AppRecPtr->ControlReq.AppControlRequest == CFE_ES_RunStatus_APP_RUN)
+ {
+ ReturnCode = true;
+ }
+ else
+ {
+ /*
+ * Just in case, also output the status, just in case the app looks at this.
+ */
+ if (RunStatus != NULL)
+ {
+ *RunStatus = AppRecPtr->ControlReq.AppControlRequest;
+ }
+ ReturnCode = false;
+ }
+ }
+ else
+ {
+ /*
+ * Cannot do anything without the AppID
+ */
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_RunLoop Error: Cannot get AppID for the caller\n");
+ ReturnCode = false;
+
+ } /* end if Status == CFE_SUCCESS */
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (ReturnCode);
+
+} /* End of CFE_ES_RunLoop() */
+
+/*
+** Function: CFE_ES_WaitForSystemState - See API and header file for details
+*/
+int32 CFE_ES_WaitForSystemState(uint32 MinSystemState, uint32 TimeOutMilliseconds)
+{
+ int32 Status = CFE_SUCCESS;
+ CFE_ES_AppRecord_t *AppRecPtr;
+ uint32 RequiredAppState;
+ uint32 WaitTime;
+ uint32 WaitRemaining;
+
+ /*
+ * Calling app is assumed to have completed its own initialization up to the point
+ * it is waiting for.
+ *
+ * Determine the implicit app state based on the system state it is indicating
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Get App Record
+ */
+ AppRecPtr = CFE_ES_GetAppRecordByContext();
+ if (AppRecPtr != NULL)
+ {
+ RequiredAppState = CFE_ES_AppState_EARLY_INIT;
+ /*
+ * If a core app waits for anything above "CORE_READY" then it is assumed to be RUNNING
+ *
+ * External apps have additional finer-grained sync:
+ * - SYSTEM_STATE_APPS_INIT requires that all apps are at least up to LATE_INIT
+ * - SYSTEM_STATE_OPERATIONAL requires that all apps are RUNNING
+ * - SYSTEM_STATE_SHUTDOWN requires that all apps are STOPPED (in concept anyway)
+ */
+ if (AppRecPtr->Type == CFE_ES_AppType_CORE)
+ {
+ if (MinSystemState >= CFE_ES_SystemState_CORE_READY)
+ {
+ RequiredAppState = CFE_ES_AppState_RUNNING;
+ }
+ }
+ else if (MinSystemState >= CFE_ES_SystemState_SHUTDOWN)
+ {
+ RequiredAppState = CFE_ES_AppState_STOPPED;
+ }
+ else if (MinSystemState >= CFE_ES_SystemState_OPERATIONAL)
+ {
+ RequiredAppState = CFE_ES_AppState_RUNNING;
+ }
+ else if (MinSystemState >= CFE_ES_SystemState_APPS_INIT)
+ {
+ RequiredAppState = CFE_ES_AppState_LATE_INIT;
+ }
+
+ /*
+ * NOTE -- a call to "CFE_ES_WaitForSystemState()" implies that the calling app MUST also
+ * be in the requisite state. This is hooked into here to avoid needing to update all existing
+ * apps to add an explicit state change call, but it makes sense because if this was not done an app could
+ * be waiting for itself (which will always time out).
+ */
+ if (AppRecPtr->AppState < RequiredAppState)
+ {
+ AppRecPtr->AppState = RequiredAppState;
+ }
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * Do the actual delay loop.
+ *
+ * This is only dependent on the main (startup) task updating the global variable
+ * to be at least the state requested.
+ */
+ WaitRemaining = TimeOutMilliseconds;
+ while (CFE_ES_Global.SystemState < MinSystemState)
+ {
+ /* TBD: Very Crude timing here, but not sure if it matters,
+ * as this is only done during startup, not real work */
+ if (WaitRemaining > CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC)
+ {
+ WaitTime = CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC;
+ }
+ else if (WaitRemaining > 0)
+ {
+ WaitTime = WaitRemaining;
+ }
+ else
+ {
+ Status = CFE_ES_OPERATION_TIMED_OUT;
+ break;
+ }
+
+ OS_TaskDelay(WaitTime);
+ WaitRemaining -= WaitTime;
+ }
+
+ return Status;
+
+} /* End of CFE_ES_WaitForSystemState() */
+
+/*
+** Function: CFE_ES_WaitForStartupSync - See API and header file for details
+*/
+void CFE_ES_WaitForStartupSync(uint32 TimeOutMilliseconds)
+{
+ CFE_ES_WaitForSystemState(CFE_ES_SystemState_OPERATIONAL, TimeOutMilliseconds);
+}
+
+/*
+** Function: CFE_ES_GetAppIDByName - See API and header file for details
+*/
+int32 CFE_ES_GetAppIDByName(CFE_ES_AppId_t *AppIdPtr, const char *AppName)
+{
+ CFE_ES_AppRecord_t *AppRecPtr;
+ int32 Result;
+
+ if (AppName == NULL || AppIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ AppRecPtr = CFE_ES_LocateAppRecordByName(AppName);
+ if (AppRecPtr == NULL)
+ {
+ /*
+ * ensure the output value is set to a safe value,
+ * in case the does not check the return code.
+ */
+ Result = CFE_ES_ERR_NAME_NOT_FOUND;
+ *AppIdPtr = CFE_ES_APPID_UNDEFINED;
+ }
+ else
+ {
+ Result = CFE_SUCCESS;
+ *AppIdPtr = CFE_ES_AppRecordGetID(AppRecPtr);
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (Result);
+
+} /* End of CFE_ES_GetAppIDByName() */
+
+/*
+** Function: CFE_ES_GetLibIDByName - See API and header file for details
+*/
+int32 CFE_ES_GetLibIDByName(CFE_ES_LibId_t *LibIdPtr, const char *LibName)
+{
+ CFE_ES_LibRecord_t *LibRecPtr;
+ int32 Result;
+
+ if (LibName == NULL || LibIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ LibRecPtr = CFE_ES_LocateLibRecordByName(LibName);
+ if (LibRecPtr == NULL)
+ {
+ /*
+ * ensure the output value is set to a safe value,
+ * in case the does not check the return code.
+ */
+ Result = CFE_ES_ERR_NAME_NOT_FOUND;
+ *LibIdPtr = CFE_ES_LIBID_UNDEFINED;
+ }
+ else
+ {
+ Result = CFE_SUCCESS;
+ *LibIdPtr = CFE_ES_LibRecordGetID(LibRecPtr);
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (Result);
+} /* End of CFE_ES_GetLibIDByName() */
+
+/*
+** Function: CFE_ES_GetTaskIDByName - See API and header file for details
+*/
+CFE_Status_t CFE_ES_GetTaskIDByName(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName)
+{
+ osal_id_t OsalId;
+ int32 Status;
+ CFE_Status_t Result;
+
+ if (TaskName == NULL || TaskIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /* For tasks IDs, defer to OSAL for name lookup */
+ Status = OS_TaskGetIdByName(&OsalId, TaskName);
+ if (Status == OS_SUCCESS)
+ {
+ Result = CFE_SUCCESS;
+ *TaskIdPtr = CFE_ES_TaskId_FromOSAL(OsalId);
+ }
+ else
+ {
+ Result = CFE_ES_ERR_NAME_NOT_FOUND;
+ *TaskIdPtr = CFE_ES_TASKID_UNDEFINED;
+ }
+
+ return (Result);
+} /* End of CFE_ES_GetTaskIDByName() */
+
+/*
+** Function: CFE_ES_GetAppID - See API and header file for details
+*/
+int32 CFE_ES_GetAppID(CFE_ES_AppId_t *AppIdPtr)
+{
+ CFE_ES_AppRecord_t *AppRecPtr;
+ int32 Result;
+
+ if (AppIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ AppRecPtr = CFE_ES_GetAppRecordByContext();
+
+ if (AppRecPtr != NULL)
+ {
+ *AppIdPtr = CFE_ES_AppRecordGetID(AppRecPtr);
+ Result = CFE_SUCCESS;
+ }
+ else
+ {
+ *AppIdPtr = CFE_ES_APPID_UNDEFINED;
+ Result = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (Result);
+
+} /* End of CFE_ES_GetAppID() */
+
+/*
+** Function: CFE_ES_GetTaskID - See API and header file for details
+*/
+int32 CFE_ES_GetTaskID(CFE_ES_TaskId_t *TaskIdPtr)
+{
+ int32 Result;
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+
+ if (TaskIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ TaskRecPtr = CFE_ES_GetTaskRecordByContext();
+ if (TaskRecPtr == NULL)
+ {
+ *TaskIdPtr = CFE_ES_TASKID_UNDEFINED;
+ Result = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else
+ {
+ *TaskIdPtr = CFE_ES_TaskRecordGetID(TaskRecPtr);
+ Result = CFE_SUCCESS;
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+ return Result;
+}
+
+/*
+** Function: CFE_ES_GetAppName - See API and header file for details
+*/
+int32 CFE_ES_GetAppName(char *AppName, CFE_ES_AppId_t AppId, size_t BufferLength)
+{
+ int32 Result;
+ CFE_ES_AppRecord_t *AppRecPtr;
+
+ if (BufferLength == 0 || AppName == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /*
+ ** Get App Record
+ */
+ AppRecPtr = CFE_ES_LocateAppRecordByID(AppId);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ * confirm that the app record is a match,
+ * which must be done while locked.
+ */
+ if (CFE_ES_AppRecordIsMatch(AppRecPtr, AppId))
+ {
+ strncpy(AppName, CFE_ES_AppRecordGetName(AppRecPtr), BufferLength - 1);
+ AppName[BufferLength - 1] = '\0';
+ Result = CFE_SUCCESS;
+ }
+ else
+ {
+ AppName[0] = 0;
+ Result = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (Result);
+
+} /* End of CFE_ES_GetAppName() */
+
+/*
+** Function: CFE_ES_GetLibName - See API and header file for details
+*/
+int32 CFE_ES_GetLibName(char *LibName, CFE_ES_LibId_t LibId, size_t BufferLength)
+{
+ int32 Result;
+ CFE_ES_LibRecord_t *LibRecPtr;
+
+ if (BufferLength == 0 || LibName == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /*
+ ** Get Lib Record
+ */
+ LibRecPtr = CFE_ES_LocateLibRecordByID(LibId);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ * confirm that the Lib record is a match,
+ * which must be done while locked.
+ */
+ if (CFE_ES_LibRecordIsMatch(LibRecPtr, LibId))
+ {
+ strncpy(LibName, CFE_ES_LibRecordGetName(LibRecPtr), BufferLength - 1);
+ LibName[BufferLength - 1] = '\0';
+ Result = CFE_SUCCESS;
+ }
+ else
+ {
+ LibName[0] = 0;
+ Result = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (Result);
+
+} /* End of CFE_ES_GetLibName() */
+
+/*
+** Function: CFE_ES_GetTaskName - See API and header file for details
+*/
+int32 CFE_ES_GetTaskName(char *TaskName, CFE_ES_TaskId_t TaskId, size_t BufferLength)
+{
+ int32 Result;
+ osal_id_t OsalId;
+
+ if (BufferLength == 0 || TaskName == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ if (!CFE_RESOURCEID_TEST_DEFINED(TaskId))
+ {
+ return CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ /*
+ * Query OSAL to get the task name
+ */
+ OsalId = CFE_ES_TaskId_ToOSAL(TaskId);
+ Result = OS_GetResourceName(OsalId, TaskName, BufferLength);
+
+ if (Result != OS_SUCCESS)
+ {
+ return CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_ES_GetTaskName() */
+
+/*
+** Function: CFE_ES_GetAppInfo - See API and header file for details
+*/
+int32 CFE_ES_GetAppInfo(CFE_ES_AppInfo_t *AppInfo, CFE_ES_AppId_t AppId)
+{
+ CFE_ES_AppRecord_t * AppRecPtr;
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+ int32 Status;
+ osal_id_t ModuleId;
+ uint32 i;
+
+ if (AppInfo == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_GetAppInfo: Invalid Parameter ( Null Pointer )\n");
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ memset(AppInfo, 0, sizeof(*AppInfo));
+ ModuleId = OS_OBJECT_ID_UNDEFINED;
+
+ AppRecPtr = CFE_ES_LocateAppRecordByID(AppId);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (!CFE_ES_AppRecordIsMatch(AppRecPtr, AppId))
+ {
+ /*
+ * Log a message if called with an invalid ID.
+ */
+ CFE_ES_WriteToSysLog("CFE_ES_GetAppInfo: App ID not active: %lu\n", CFE_RESOURCEID_TO_ULONG(AppId));
+
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else
+ {
+ AppInfo->ResourceId = CFE_RESOURCEID_UNWRAP(AppId); /* make into a generic resource ID */
+ AppInfo->Type = AppRecPtr->Type;
+
+ strncpy(AppInfo->Name, CFE_ES_AppRecordGetName(AppRecPtr), sizeof(AppInfo->Name) - 1);
+
+ CFE_ES_CopyModuleBasicInfo(&AppRecPtr->StartParams.BasicInfo, AppInfo);
+ CFE_ES_CopyModuleStatusInfo(&AppRecPtr->LoadStatus, AppInfo);
+
+ AppInfo->ExceptionAction = AppRecPtr->StartParams.ExceptionAction;
+ AppInfo->MainTaskId = AppRecPtr->MainTaskId;
+
+ ModuleId = AppRecPtr->LoadStatus.ModuleId;
+
+ /*
+ ** Calculate the number of child tasks
+ */
+ AppInfo->NumOfChildTasks = 0;
+ TaskRecPtr = CFE_ES_Global.TaskTable;
+ for (i = 0; i < OS_MAX_TASKS; i++)
+ {
+ if (CFE_ES_TaskRecordIsUsed(TaskRecPtr) && CFE_RESOURCEID_TEST_EQUAL(TaskRecPtr->AppId, AppId))
+ {
+ if (CFE_RESOURCEID_TEST_EQUAL(CFE_ES_TaskRecordGetID(TaskRecPtr), AppInfo->MainTaskId))
+ {
+ /* This is the main task - capture its name and execution count */
+ AppInfo->ExecutionCounter = TaskRecPtr->ExecutionCounter;
+ strncpy(AppInfo->MainTaskName, TaskRecPtr->TaskName, sizeof(AppInfo->MainTaskName) - 1);
+ AppInfo->MainTaskName[sizeof(AppInfo->MainTaskName) - 1] = '\0';
+
+ AppInfo->StackSize = TaskRecPtr->StartParams.StackSize;
+ AppInfo->Priority = TaskRecPtr->StartParams.Priority;
+ }
+ else
+ {
+ /* This is a child task, no extra info, just increment count */
+ ++AppInfo->NumOfChildTasks;
+ }
+ }
+ ++TaskRecPtr;
+ }
+
+ Status = CFE_SUCCESS;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** Get the address information from the OSAL
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_ES_CopyModuleAddressInfo(ModuleId, AppInfo);
+ }
+
+ return Status;
+}
+
+/*
+** Function: CFE_ES_GetLibInfo - See API and header file for details
+*/
+int32 CFE_ES_GetLibInfo(CFE_ES_AppInfo_t *LibInfo, CFE_ES_LibId_t LibId)
+{
+ int32 Status;
+ CFE_ES_LibRecord_t *LibRecPtr;
+ osal_id_t ModuleId;
+
+ if (LibInfo == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_GetLibInfo: Invalid Parameter ( Null Pointer )\n");
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ memset(LibInfo, 0, sizeof(*LibInfo));
+ ModuleId = OS_OBJECT_ID_UNDEFINED;
+
+ LibRecPtr = CFE_ES_LocateLibRecordByID(LibId);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (!CFE_ES_LibRecordIsMatch(LibRecPtr, LibId))
+ {
+ /*
+ * Log a message if called with an invalid ID.
+ */
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_GetLibInfo: Lib ID not active: %lu\n", CFE_RESOURCEID_TO_ULONG(LibId));
+
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else
+ {
+ LibInfo->ResourceId = CFE_RESOURCEID_UNWRAP(LibId); /* make into generic ID */
+ LibInfo->Type = CFE_ES_AppType_LIBRARY;
+
+ strncpy(LibInfo->Name, CFE_ES_LibRecordGetName(LibRecPtr), sizeof(LibInfo->Name) - 1);
+
+ CFE_ES_CopyModuleBasicInfo(&LibRecPtr->LoadParams, LibInfo);
+ CFE_ES_CopyModuleStatusInfo(&LibRecPtr->LoadStatus, LibInfo);
+
+ ModuleId = LibRecPtr->LoadStatus.ModuleId;
+
+ Status = CFE_SUCCESS;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** Get the address information from the OSAL
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ CFE_ES_CopyModuleAddressInfo(ModuleId, LibInfo);
+ }
+
+ return Status;
+}
+
+/*
+** Function: CFE_ES_GetModuleInfo - See API and header file for details
+*/
+int32 CFE_ES_GetModuleInfo(CFE_ES_AppInfo_t *ModuleInfo, CFE_ResourceId_t ResourceId)
+{
+ int32 Status;
+
+ switch (CFE_ResourceId_GetBase(ResourceId))
+ {
+ case CFE_ES_APPID_BASE:
+ Status = CFE_ES_GetAppInfo(ModuleInfo, CFE_ES_APPID_C(ResourceId));
+ break;
+ case CFE_ES_LIBID_BASE:
+ Status = CFE_ES_GetLibInfo(ModuleInfo, CFE_ES_LIBID_C(ResourceId));
+ break;
+ default:
+ /*
+ * Log a message if called with an invalid ID.
+ */
+ CFE_ES_WriteToSysLog("CFE_ES_GetModuleInfo: Resource ID not valid: %lu\n",
+ CFE_ResourceId_ToInteger(ResourceId));
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ break;
+ }
+
+ return (Status);
+
+} /* End of CFE_ES_GetModuleInfo() */
+
+/*
+** Function: CFE_ES_GetTaskInfo - See API and header file for details
+*/
+int32 CFE_ES_GetTaskInfo(CFE_ES_TaskInfo_t *TaskInfo, CFE_ES_TaskId_t TaskId)
+{
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+ CFE_ES_AppRecord_t * AppRecPtr;
+ int32 Status;
+
+ if (TaskInfo == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_GetTaskInfo: Invalid Parameter ( Null Pointer )\n");
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ memset(TaskInfo, 0, sizeof(*TaskInfo));
+
+ TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (!CFE_ES_TaskRecordIsMatch(TaskRecPtr, TaskId))
+ {
+ /* task ID is bad */
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_GetTaskInfo: Task ID Not Active: %lu\n", CFE_RESOURCEID_TO_ULONG(TaskId));
+ }
+ else
+ {
+
+ /*
+ ** Get the Application ID and Task Name
+ */
+ TaskInfo->AppId = TaskRecPtr->AppId;
+ strncpy(TaskInfo->TaskName, CFE_ES_TaskRecordGetName(TaskRecPtr), sizeof(TaskInfo->TaskName) - 1);
+ TaskInfo->TaskName[sizeof(TaskInfo->TaskName) - 1] = '\0';
+
+ /*
+ ** Store away the Task ID ( for the QueryAllTasks Cmd )
+ */
+ TaskInfo->TaskId = CFE_ES_TaskRecordGetID(TaskRecPtr);
+
+ /*
+ ** Get the other stats for the task
+ */
+ TaskInfo->ExecutionCounter = TaskRecPtr->ExecutionCounter;
+ TaskInfo->StackSize = TaskRecPtr->StartParams.StackSize;
+ TaskInfo->Priority = TaskRecPtr->StartParams.Priority;
+
+ /*
+ ** Get the Application Details
+ */
+ AppRecPtr = CFE_ES_LocateAppRecordByID(TaskRecPtr->AppId);
+ if (CFE_ES_AppRecordIsMatch(AppRecPtr, TaskRecPtr->AppId))
+ {
+ strncpy(TaskInfo->AppName, CFE_ES_AppRecordGetName(AppRecPtr), sizeof(TaskInfo->AppName) - 1);
+ TaskInfo->AppName[sizeof(TaskInfo->AppName) - 1] = '\0';
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ /* task ID was OK but parent app ID is bad */
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (Status);
+
+} /* End of CFE_ES_GetTaskInfo() */
+
+/*
+** Function: CFE_ES_CreateChildTask - See API and header file for details
+*/
+int32 CFE_ES_CreateChildTask(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName,
+ CFE_ES_ChildTaskMainFuncPtr_t FunctionPtr, CFE_ES_StackPointer_t StackPtr,
+ size_t StackSize, CFE_ES_TaskPriority_Atom_t Priority, uint32 Flags)
+{
+ int32 ReturnCode;
+ CFE_ES_AppRecord_t * AppRecPtr;
+ CFE_ES_AppId_t ParentAppId;
+ CFE_ES_TaskId_t SelfTaskId;
+ CFE_ES_TaskStartParams_t Params;
+
+ ParentAppId = CFE_ES_APPID_UNDEFINED;
+
+ memset(&Params, 0, sizeof(Params));
+ Params.Priority = Priority;
+ Params.StackSize = StackSize;
+
+ /*
+ ** Validate some of the arguments
+ */
+ if (TaskIdPtr == NULL)
+ {
+ if (TaskName == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Task Id and Name Pointer Parameters are NULL.\n");
+ ReturnCode = CFE_ES_BAD_ARGUMENT;
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Task Id Pointer Parameter is NULL for Task '%s'.\n",
+ TaskName);
+ ReturnCode = CFE_ES_BAD_ARGUMENT;
+ }
+ }
+ else if (TaskName == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: TaskName Parameter is NULL\n");
+ ReturnCode = CFE_ES_BAD_ARGUMENT;
+ }
+ else if (FunctionPtr == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Function Pointer Parameter is NULL for Task '%s'\n", TaskName);
+ ReturnCode = CFE_ES_BAD_ARGUMENT;
+ }
+ else
+ {
+ /*
+ ** First, Make sure the Calling Task is a cFE Main task.
+ ** TaskID must be the same as the Parent Task ID.
+ */
+ SelfTaskId = CFE_ES_TaskId_FromOSAL(OS_TaskGetId());
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Get the App Record of the calling Application
+ */
+ AppRecPtr = CFE_ES_GetAppRecordByContext();
+ if (AppRecPtr == NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Invalid calling context when creating Task '%s'\n",
+ TaskName);
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ else if (!CFE_RESOURCEID_TEST_EQUAL(SelfTaskId, AppRecPtr->MainTaskId))
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Error: Cannot call from a Child Task (for Task '%s').\n",
+ TaskName);
+ ReturnCode = CFE_ES_ERR_CHILD_TASK_CREATE;
+ }
+ else
+ {
+ ParentAppId = CFE_ES_AppRecordGetID(AppRecPtr);
+ ReturnCode = CFE_SUCCESS;
+ } /* end If AppID is valid */
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ } /* end if parameter checking */
+
+ /*
+ ** Step 2: Create the new task if the parameter validation succeeded
+ */
+ if (ReturnCode == CFE_SUCCESS)
+ {
+ ReturnCode = CFE_ES_StartAppTask(TaskIdPtr, TaskName, FunctionPtr, &Params, ParentAppId);
+ }
+
+ return (ReturnCode);
+
+} /* End of CFE_ES_CreateChildTask() */
+
+/*
+** Function: CFE_ES_IncrementTaskCounter - See API and header file for details
+*/
+void CFE_ES_IncrementTaskCounter(void)
+{
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+ CFE_ES_TaskId_t TaskID;
+
+ /*
+ * Note this locates a task record but intentionally does _not_
+ * lock the global data structure. Locking is avoided for
+ * efficiency reasons.
+ *
+ * As tasks can only increment their own counters, there is no risk
+ * of concurrent access to the same counter.
+ *
+ * Because the global data is not locked, only minimal validation
+ * is performed.
+ */
+ TaskID = CFE_ES_TaskId_FromOSAL(OS_TaskGetId());
+ TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskID);
+ if (TaskRecPtr != NULL)
+ {
+ TaskRecPtr->ExecutionCounter++;
+ }
+
+} /* End of CFE_ES_IncrementTaskCounter() */
+
+/*
+** Function: CFE_ES_DeleteChildTask - See API and header file for details
+*/
+int32 CFE_ES_DeleteChildTask(CFE_ES_TaskId_t TaskId)
+{
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+ CFE_ES_AppRecord_t * AppRecPtr;
+ uint32 i;
+ bool TaskIsMain;
+ int32 ReturnCode = CFE_SUCCESS;
+ int32 OSReturnCode;
+ osal_id_t OsalId;
+
+ /*
+ ** Make sure the task ID is within range
+ */
+ TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId);
+ if (TaskRecPtr != NULL)
+ {
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Make sure the task is active/valid
+ */
+ if (CFE_ES_TaskRecordIsMatch(TaskRecPtr, TaskId))
+ {
+ /*
+ ** Search for this task ID in the ES App Table to make sure
+ ** it is not a cFE App Main Task
+ */
+ TaskIsMain = false;
+ AppRecPtr = CFE_ES_Global.AppTable;
+ for (i = 0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS; i++)
+ {
+ if (CFE_ES_AppRecordIsUsed(AppRecPtr))
+ {
+ if (CFE_RESOURCEID_TEST_EQUAL(AppRecPtr->MainTaskId, TaskId))
+ {
+ /*
+ ** Error, the task Id is an App Main Task ID
+ */
+ TaskIsMain = true;
+ break;
+ } /* end if */
+ } /* end if */
+ ++AppRecPtr;
+ } /* end for */
+
+ if (TaskIsMain == false)
+ {
+ /*
+ ** Can delete the Task
+ */
+ OsalId = CFE_ES_TaskId_ToOSAL(TaskId);
+ OSReturnCode = OS_TaskDelete(OsalId);
+ if (OSReturnCode == OS_SUCCESS)
+ {
+ /*
+ ** Invalidate the task table entry
+ */
+ CFE_ES_TaskRecordSetFree(TaskRecPtr);
+ CFE_ES_Global.RegisteredTasks--;
+
+ /*
+ ** Report the task delete
+ */
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteChildTask Task %lu Deleted\n",
+ CFE_RESOURCEID_TO_ULONG(TaskId));
+ ReturnCode = CFE_SUCCESS;
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync(
+ "CFE_ES_DeleteChildTask Error: Error Calling OS_TaskDelete: Task %lu, RC = 0x%08X\n",
+ CFE_RESOURCEID_TO_ULONG(TaskId), (unsigned int)OSReturnCode);
+ ReturnCode = CFE_ES_ERR_CHILD_TASK_DELETE;
+ }
+ }
+ else
+ {
+ /*
+ ** Error: The task is a cFE Application Main task
+ */
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteChildTask Error: Task %lu is a cFE Main Task.\n",
+ CFE_RESOURCEID_TO_ULONG(TaskId));
+ ReturnCode = CFE_ES_ERR_CHILD_TASK_DELETE_MAIN_TASK;
+ } /* end if TaskMain == false */
+ }
+ else
+ {
+ /*
+ ** Task ID is not in use, so it is invalid
+ */
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteChildTask Error: Task ID is not active: %lu\n",
+ CFE_RESOURCEID_TO_ULONG(TaskId));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+
+ } /* end if */
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+ }
+ else
+ {
+ /*
+ ** Task ID is invalid ( too large )
+ */
+ CFE_ES_WriteToSysLog("CFE_ES_DeleteChildTask Error: Invalid Task ID: %lu\n", CFE_RESOURCEID_TO_ULONG(TaskId));
+ ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+ return (ReturnCode);
+
+} /* End of CFE_ES_DeleteTask() */
+
+/*
+** Function: CFE_ES_ExitChildTask
+**
+** Purpose: Stop execution of a child task.
+**
+*/
+void CFE_ES_ExitChildTask(void)
+{
+ CFE_ES_AppRecord_t * AppRecPtr;
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Check to see if this is being called from a cFE Application's
+ ** main task.
+ */
+ TaskRecPtr = CFE_ES_GetTaskRecordByContext();
+ if (TaskRecPtr != NULL)
+ {
+ AppRecPtr = CFE_ES_LocateAppRecordByID(TaskRecPtr->AppId);
+
+ if (CFE_ES_AppRecordIsMatch(AppRecPtr, TaskRecPtr->AppId) &&
+ !CFE_ES_TaskRecordIsMatch(TaskRecPtr, AppRecPtr->MainTaskId))
+ {
+ /*
+ ** Invalidate the task table entry
+ */
+ CFE_ES_TaskRecordSetFree(TaskRecPtr);
+ CFE_ES_Global.RegisteredTasks--;
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** Call the OS AL routine
+ */
+ OS_TaskExit();
+ /*
+ ** Does not return from OS_TaskExit, except under unit test
+ */
+ return;
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ExitChildTask Error: Cannot Call from a cFE App Main Task. ID = %lu\n",
+ CFE_RESOURCEID_TO_ULONG(CFE_ES_TaskRecordGetID(TaskRecPtr)));
+ }
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_ExitChildTask called from invalid task context\n");
+ } /* end if GetAppId */
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+} /* End of CFE_ES_ExitChildTask() */
+
+/*
+** Function: CFE_ES_WriteToSysLog - See API and header file for details
+*/
+int32 CFE_ES_WriteToSysLog(const char *SpecStringPtr, ...)
+{
+ char TmpString[CFE_ES_MAX_SYSLOG_MSG_SIZE];
+ int32 ReturnCode;
+ va_list ArgPtr;
+
+ if (SpecStringPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ va_start(ArgPtr, SpecStringPtr);
+ CFE_ES_SysLog_vsnprintf(TmpString, sizeof(TmpString), SpecStringPtr, ArgPtr);
+ va_end(ArgPtr);
+
+ /*
+ * Append to the syslog buffer, which must be done while locked.
+ * Only one thread can actively write into the buffer at time.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ ReturnCode = CFE_ES_SysLogAppend_Unsync(TmpString);
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /* Output the entry to the console */
+ OS_printf("%s", TmpString);
+
+ return (ReturnCode);
+
+} /* End of CFE_ES_WriteToSysLog() */
+
+/*
+** Function: CFE_ES_CalculateCRC - See API and header file for details
+*/
+uint32 CFE_ES_CalculateCRC(const void *DataPtr, size_t DataLength, uint32 InputCRC, uint32 TypeCRC)
+{
+ uint32 i;
+ int16 Index;
+ int16 Crc = 0;
+ const uint8 *BufPtr;
+ uint8 ByteValue;
+
+ static const uint16 CrcTable[256] = {
+
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1,
+ 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40,
+ 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1,
+ 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1,
+ 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40,
+ 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1,
+ 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0,
+ 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740,
+ 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0,
+ 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1,
+ 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140,
+ 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0,
+ 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0,
+ 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341,
+ 0x4100, 0x81C1, 0x8081, 0x4040
+
+ };
+
+ if (DataPtr == NULL || DataLength == 0)
+ {
+ return InputCRC;
+ }
+
+ switch (TypeCRC)
+ {
+ case CFE_MISSION_ES_CRC_32:
+ CFE_ES_WriteToSysLog("CFE ES Calculate CRC32 not Implemented\n");
+ break;
+
+ case CFE_MISSION_ES_CRC_16:
+ Crc = (int16)(0xFFFF & InputCRC);
+ BufPtr = (const uint8 *)DataPtr;
+
+ for (i = 0; i < DataLength; i++, BufPtr++)
+ {
+ /*
+ * It is assumed that the supplied buffer is in a
+ * directly-accessible memory space that does not
+ * require special logic to access
+ */
+ ByteValue = *BufPtr;
+ Index = ((Crc ^ ByteValue) & 0x00FF);
+ Crc = ((Crc >> 8) & 0x00FF) ^ CrcTable[Index];
+ }
+ break;
+
+ case CFE_MISSION_ES_CRC_8:
+ CFE_ES_WriteToSysLog("CFE ES Calculate CRC8 not Implemented\n");
+ break;
+
+ default:
+ break;
+ }
+ return (Crc);
+
+} /* End of CFE_ES_CalculateCRC() */
+
+/*
+** Function: CFE_ES_RegisterCDS
+**
+** Purpose: Allocate a data block for a Critical Data Store.
+**
+*/
+int32 CFE_ES_RegisterCDS(CFE_ES_CDSHandle_t *CDSHandlePtr, size_t BlockSize, const char *Name)
+{
+ int32 Status;
+ size_t NameLen;
+ CFE_ES_AppId_t ThisAppId;
+
+ char AppName[OS_MAX_API_NAME] = {"UNKNOWN"};
+ char CDSName[CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN] = {""};
+
+ /* Check to make sure calling application is legit */
+ Status = CFE_ES_GetAppID(&ThisAppId);
+
+ if (CDSHandlePtr == NULL || Name == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_RegisterCDS:-Failed invalid arguments\n");
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /* Initialize output to safe value, in case this fails */
+ *CDSHandlePtr = CFE_ES_CDS_BAD_HANDLE;
+
+ if (Status != CFE_SUCCESS) /* Application ID was invalid */
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:Register-Bad AppId context\n");
+ }
+ else if (!CFE_ES_Global.CDSIsAvailable)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:Register-CDS not available\n");
+ Status = CFE_ES_NOT_IMPLEMENTED;
+ }
+ else
+ {
+ /* Make sure specified CDS name is not too long or too short */
+ NameLen = strlen(Name);
+ if ((NameLen > CFE_MISSION_ES_CDS_MAX_NAME_LENGTH) || (NameLen == 0))
+ {
+ Status = CFE_ES_CDS_INVALID_NAME;
+
+ /* Perform a buffer overrun safe copy of name for debug log message */
+
+ strncpy(CDSName, Name, sizeof(CDSName) - 1);
+ CDSName[sizeof(CDSName) - 1] = '\0';
+ CFE_ES_WriteToSysLog("CFE_CDS:Register-CDS Name (%s) is too long\n", CDSName);
+ }
+ else
+ {
+ /* Modify specified name to be processor specific name */
+ /* of the form "AppName.Name" */
+ CFE_ES_FormCDSName(CDSName, Name, ThisAppId);
+
+ /* Create CDS and designate it as NOT being a Critical Table */
+ Status = CFE_ES_RegisterCDSEx(CDSHandlePtr, BlockSize, CDSName, false);
+
+ /* If size is unacceptable, log it */
+ if (Status == CFE_ES_CDS_INVALID_SIZE)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:Register-CDS %s has invalid size (%lu)\n", Name,
+ (unsigned long)BlockSize);
+ }
+ }
+ }
+
+ /* On Error conditions, notify ground of screw up */
+ if (Status < 0)
+ {
+ /* Translate AppID of caller into App Name */
+ CFE_ES_GetAppName(AppName, ThisAppId, sizeof(AppName));
+
+ CFE_EVS_SendEventWithAppID(CFE_ES_CDS_REGISTER_ERR_EID, CFE_EVS_EventType_ERROR, ThisAppId,
+ "%s Failed to Register CDS '%s', Status=0x%08X", AppName, Name,
+ (unsigned int)Status);
+ }
+
+ return Status;
+} /* End of CFE_ES_RegisterCDS */
+
+/*
+ * Function: CFE_ES_GetCDSBlockIDByName
+ *
+ * Purpose: Obtain CDS Block ID from name
+ * See full API description in header file
+ */
+CFE_Status_t CFE_ES_GetCDSBlockIDByName(CFE_ES_CDSHandle_t *BlockIdPtr, const char *BlockName)
+{
+ CFE_Status_t Status;
+ CFE_ES_CDS_RegRec_t *RegRecPtr;
+
+ if (BlockName == NULL || BlockIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+ if (!CFE_ES_Global.CDSIsAvailable)
+ {
+ return CFE_ES_NOT_IMPLEMENTED;
+ }
+
+ CFE_ES_LockCDS();
+
+ RegRecPtr = CFE_ES_LocateCDSBlockRecordByName(BlockName);
+
+ if (RegRecPtr != NULL)
+ {
+ *BlockIdPtr = CFE_ES_CDSBlockRecordGetID(RegRecPtr);
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ *BlockIdPtr = CFE_ES_CDS_BAD_HANDLE;
+ Status = CFE_ES_ERR_NAME_NOT_FOUND;
+ }
+
+ CFE_ES_UnlockCDS();
+
+ return Status;
+}
+
+/*
+ * Function: CFE_ES_GetCDSBlockName
+ *
+ * Purpose: Obtain CDS Block Name from ID
+ * See full API description in header file
+ */
+CFE_Status_t CFE_ES_GetCDSBlockName(char *BlockName, CFE_ES_CDSHandle_t BlockId, size_t BufferLength)
+{
+ CFE_Status_t Status;
+ CFE_ES_CDS_RegRec_t *RegRecPtr;
+
+ if (BufferLength == 0 || BlockName == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+ if (!CFE_ES_Global.CDSIsAvailable)
+ {
+ return CFE_ES_NOT_IMPLEMENTED;
+ }
+
+ RegRecPtr = CFE_ES_LocateCDSBlockRecordByID(BlockId);
+
+ CFE_ES_LockCDS();
+
+ if (CFE_ES_CDSBlockRecordIsMatch(RegRecPtr, BlockId))
+ {
+ strncpy(BlockName, RegRecPtr->Name, BufferLength - 1);
+ BlockName[BufferLength - 1] = 0;
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ BlockName[0] = 0;
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockCDS();
+
+ return Status;
+}
+
+/*
+** Function: CFE_ES_CopyToCDS
+**
+** Purpose: Copies a data block to a Critical Data Store.
+**
+*/
+int32 CFE_ES_CopyToCDS(CFE_ES_CDSHandle_t Handle, void *DataToCopy)
+{
+ if (DataToCopy == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ return CFE_ES_CDSBlockWrite(Handle, DataToCopy);
+} /* End of CFE_ES_CopyToCDS() */
+
+/*
+** Function: CFE_ES_RestoreFromCDS
+**
+** Purpose: Restores a data block from a Critical Data Store.
+**
+*/
+int32 CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t Handle)
+{
+ if (RestoreToMemory == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ return CFE_ES_CDSBlockRead(RestoreToMemory, Handle);
+} /* End of CFE_ES_RestoreFromCDS() */
+
+/*
+** Function: CFE_ES_RegisterGenCounter
+**
+** Purpose: Allocates a generic counter resource and assigns ID
+*/
+int32 CFE_ES_RegisterGenCounter(CFE_ES_CounterId_t *CounterIdPtr, const char *CounterName)
+{
+ CFE_ES_GenCounterRecord_t *CountRecPtr;
+ CFE_ResourceId_t PendingResourceId;
+ int32 Status;
+
+ if (CounterName == NULL || CounterIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ if (strlen(CounterName) >= sizeof(CountRecPtr->CounterName))
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ * Check for an existing entry with the same name.
+ */
+ CountRecPtr = CFE_ES_LocateCounterRecordByName(CounterName);
+ if (CountRecPtr != NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: Duplicate Counter name '%s'\n", CounterName);
+ Status = CFE_ES_ERR_DUPLICATE_NAME;
+ PendingResourceId = CFE_RESOURCEID_UNDEFINED;
+ }
+ else
+ {
+ /* scan for a free slot */
+ PendingResourceId = CFE_ResourceId_FindNext(CFE_ES_Global.LastCounterId, CFE_PLATFORM_ES_MAX_GEN_COUNTERS,
+ CFE_ES_CheckCounterIdSlotUsed);
+ CountRecPtr = CFE_ES_LocateCounterRecordByID(CFE_ES_COUNTERID_C(PendingResourceId));
+
+ if (CountRecPtr == NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: No free Counter slots available\n");
+ Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE;
+ }
+ else
+ {
+ strncpy(CountRecPtr->CounterName, CounterName, sizeof(CountRecPtr->CounterName) - 1);
+ CountRecPtr->CounterName[sizeof(CountRecPtr->CounterName) - 1] = '\0';
+ CountRecPtr->Counter = 0;
+ CFE_ES_CounterRecordSetUsed(CountRecPtr, PendingResourceId);
+ CFE_ES_Global.LastCounterId = PendingResourceId;
+ Status = CFE_SUCCESS;
+ }
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ *CounterIdPtr = CFE_ES_COUNTERID_C(PendingResourceId);
+ return Status;
+}
+
+/*
+** Function: CFE_ES_DeleteGenCounter
+**
+** Purpose: Delete a Generic Counter.
+**
+*/
+int32 CFE_ES_DeleteGenCounter(CFE_ES_CounterId_t CounterId)
+{
+ CFE_ES_GenCounterRecord_t *CountRecPtr;
+ int32 Status = CFE_ES_BAD_ARGUMENT;
+
+ CountRecPtr = CFE_ES_LocateCounterRecordByID(CounterId);
+ if (CountRecPtr != NULL)
+ {
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ if (CFE_ES_CounterRecordIsMatch(CountRecPtr, CounterId))
+ {
+ CountRecPtr->Counter = 0;
+ CFE_ES_CounterRecordSetFree(CountRecPtr);
+ Status = CFE_SUCCESS;
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+ }
+
+ return Status;
+
+} /* End of CFE_ES_DeleteGenCounter() */
+
+/*
+** Function: CFE_ES_IncrementGenCounter
+**
+** Purpose: Increment a Generic Counter.
+**
+*/
+int32 CFE_ES_IncrementGenCounter(CFE_ES_CounterId_t CounterId)
+{
+ int32 Status = CFE_ES_BAD_ARGUMENT;
+ CFE_ES_GenCounterRecord_t *CountRecPtr;
+
+ CountRecPtr = CFE_ES_LocateCounterRecordByID(CounterId);
+ if (CFE_ES_CounterRecordIsMatch(CountRecPtr, CounterId))
+ {
+ ++CountRecPtr->Counter;
+ Status = CFE_SUCCESS;
+ }
+ return Status;
+
+} /* End of CFE_ES_IncrementGenCounter() */
+
+/*
+** Function: CFE_ES_SetGenCount
+**
+** Purpose: Sets a Generic Counter's count.
+**
+*/
+int32 CFE_ES_SetGenCount(CFE_ES_CounterId_t CounterId, uint32 Count)
+{
+ int32 Status = CFE_ES_BAD_ARGUMENT;
+ CFE_ES_GenCounterRecord_t *CountRecPtr;
+
+ CountRecPtr = CFE_ES_LocateCounterRecordByID(CounterId);
+ if (CFE_ES_CounterRecordIsMatch(CountRecPtr, CounterId))
+ {
+ CountRecPtr->Counter = Count;
+ Status = CFE_SUCCESS;
+ }
+ return Status;
+} /* End of CFE_ES_SetGenCount() */
+
+/*
+** Function: CFE_ES_GetGenCount
+**
+** Purpose: Gets the value of a Generic Counter.
+**
+*/
+int32 CFE_ES_GetGenCount(CFE_ES_CounterId_t CounterId, uint32 *Count)
+{
+ int32 Status = CFE_ES_BAD_ARGUMENT;
+ CFE_ES_GenCounterRecord_t *CountRecPtr;
+
+ CountRecPtr = CFE_ES_LocateCounterRecordByID(CounterId);
+ if (CFE_ES_CounterRecordIsMatch(CountRecPtr, CounterId) && Count != NULL)
+ {
+ *Count = CountRecPtr->Counter;
+ Status = CFE_SUCCESS;
+ }
+ return Status;
+} /* End of CFE_ES_GetGenCount() */
+
+int32 CFE_ES_GetGenCounterIDByName(CFE_ES_CounterId_t *CounterIdPtr, const char *CounterName)
+{
+ CFE_ES_GenCounterRecord_t *CounterRecPtr;
+ int32 Result;
+
+ if (CounterName == NULL || CounterIdPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /*
+ ** Search the ES Generic Counter table for a counter with a matching name.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ CounterRecPtr = CFE_ES_LocateCounterRecordByName(CounterName);
+ if (CounterRecPtr == NULL)
+ {
+ /*
+ * ensure the output value is set to a safe value,
+ * in case the does not check the return code.
+ */
+ Result = CFE_ES_ERR_NAME_NOT_FOUND;
+ *CounterIdPtr = CFE_ES_COUNTERID_UNDEFINED;
+ }
+ else
+ {
+ Result = CFE_SUCCESS;
+ *CounterIdPtr = CFE_ES_CounterRecordGetID(CounterRecPtr);
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (Result);
+
+} /* End of CFE_ES_GetGenCounterIDByName() */
+
+/*
+ * Function: CFE_ES_GetGenCounterName
+ *
+ * Purpose: Obtain Counter Name from ID
+ * See full API description in header file
+ */
+CFE_Status_t CFE_ES_GetGenCounterName(char *CounterName, CFE_ES_CounterId_t CounterId, size_t BufferLength)
+{
+ CFE_ES_GenCounterRecord_t *CountRecPtr;
+ CFE_Status_t Status;
+
+ if (BufferLength == 0 || CounterName == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ CountRecPtr = CFE_ES_LocateCounterRecordByID(CounterId);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (CFE_ES_CounterRecordIsMatch(CountRecPtr, CounterId))
+ {
+ strncpy(CounterName, CFE_ES_CounterRecordGetName(CountRecPtr), BufferLength - 1);
+ CounterName[BufferLength - 1] = 0;
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ CounterName[0] = 0;
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return Status;
+}
+
+/*
+ * A conversion function to obtain an index value correlating to an AppID
+ * This is a zero based value that can be used for indexing into a table.
+ */
+int32 CFE_ES_AppID_ToIndex(CFE_ES_AppId_t AppID, uint32 *Idx)
+{
+ return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(AppID), CFE_ES_APPID_BASE, CFE_PLATFORM_ES_MAX_APPLICATIONS,
+ Idx);
+}
+
+/*
+ * A conversion function to obtain an index value correlating to a LibID
+ * This is a zero based value that can be used for indexing into a table.
+ */
+int32 CFE_ES_LibID_ToIndex(CFE_ES_LibId_t LibId, uint32 *Idx)
+{
+ return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(LibId), CFE_ES_LIBID_BASE, CFE_PLATFORM_ES_MAX_LIBRARIES, Idx);
+}
+
+/*
+ * A conversion function to obtain an index value correlating to an TaskID
+ * This is a zero based value that can be used for indexing into a table.
+ *
+ * Task IDs come from OSAL, so this is currently a wrapper around the OSAL converter.
+ * This is an alias for consistency with the ES AppID paradigm.
+ */
+int32 CFE_ES_TaskID_ToIndex(CFE_ES_TaskId_t TaskID, uint32 *Idx)
+{
+ osal_id_t OsalID;
+ osal_index_t OsalIndex;
+
+ if (!CFE_RESOURCEID_TEST_DEFINED(TaskID))
+ {
+ return CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ OsalID = CFE_ES_TaskId_ToOSAL(TaskID);
+ if (OS_ObjectIdToArrayIndex(OS_OBJECT_TYPE_OS_TASK, OsalID, &OsalIndex) != OS_SUCCESS)
+ {
+ return CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ *Idx = OsalIndex;
+
+ return CFE_SUCCESS;
+}
+
+/*
+ * A conversion function to obtain an index value correlating to a CounterID
+ * This is a zero based value that can be used for indexing into a table.
+ */
+int32 CFE_ES_CounterID_ToIndex(CFE_ES_CounterId_t CounterId, uint32 *Idx)
+{
+ return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(CounterId), CFE_ES_COUNTID_BASE,
+ CFE_PLATFORM_ES_MAX_GEN_COUNTERS, Idx);
+}
+
+/***************************************************************************************
+** Private API functions
+*/
+
+/******************************************************************************
+** Function: CFE_ES_LockSharedData()
+**
+** Purpose:
+** ES internal function to take the Shared Data Mutex and handle
+** error conditions.
+**
+** Arguments:
+** FunctionName - the name of the function containing the code that generated the error.
+** LineNumber - the file line number of the code that generated the error.
+**
+** Return:
+** None
+*/
+void CFE_ES_LockSharedData(const char *FunctionName, int32 LineNumber)
+{
+ int32 Status;
+
+ Status = OS_MutSemTake(CFE_ES_Global.SharedDataMutex);
+ if (Status != OS_SUCCESS)
+ {
+ /*
+ * NOTE: this is going to write into a buffer that itself
+ * is _supposed_ to be protected by this same mutex.
+ */
+ CFE_ES_SysLogWrite_Unsync("ES SharedData Mutex Take Err Stat=0x%x,Func=%s,Line=%d\n", (unsigned int)Status,
+ FunctionName, (int)LineNumber);
+
+ } /* end if */
+
+ return;
+
+} /* end CFE_ES_LockSharedData */
+
+/******************************************************************************
+** Function: CFE_ES_UnlockSharedData()
+**
+** Purpose:
+** ES internal function to Release the shared data mutex and handle error
+** conditions.
+**
+** Arguments:
+** FunctionName - the name of the function containing the code that generated the error.
+** LineNumber - the file line number of the code that generated the error.
+**
+** Return:
+** None
+*/
+void CFE_ES_UnlockSharedData(const char *FunctionName, int32 LineNumber)
+{
+ int32 Status;
+
+ Status = OS_MutSemGive(CFE_ES_Global.SharedDataMutex);
+ if (Status != OS_SUCCESS)
+ {
+ /*
+ * NOTE: this is going to write into a buffer that itself
+ * is _supposed_ to be protected by this same mutex.
+ */
+ CFE_ES_SysLogWrite_Unsync("ES SharedData Mutex Give Err Stat=0x%x,Func=%s,Line=%d\n", (unsigned int)Status,
+ FunctionName, (int)LineNumber);
+
+ } /* end if */
+
+ return;
+
+} /* end CFE_ES_UnlockSharedData */
+
+/******************************************************************************
+** Function: CFE_ES_ProcessAsyncEvent()
+**
+** Purpose:
+** Called by the PSP to notify CFE ES that an asynchronous event occurred.
+*/
+void CFE_ES_ProcessAsyncEvent(void)
+{
+ /* This just wakes up the background task to log/handle the event. */
+ CFE_ES_BackgroundWakeup();
+}
diff --git a/modules/es/fsw/src/cfe_es_apps.c b/modules/es/fsw/src/cfe_es_apps.c
new file mode 100644
index 000000000..aed7353c8
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_apps.c
@@ -0,0 +1,1819 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_apps.c
+**
+** Purpose:
+** This file contains functions for starting cFE applications from a filesystem.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+** Notes:
+**
+*/
+
+/*
+** Includes
+*/
+#include "cfe_es_module_all.h"
+
+#include "cfe_evs_core_internal.h"
+#include "cfe_sb_core_internal.h"
+#include "cfe_tbl_core_internal.h"
+#include "cfe_time_core_internal.h"
+
+#include
+#include /* memset() */
+#include
+
+/*
+** Defines
+*/
+#define ES_START_BUFF_SIZE 128
+
+/*
+**
+** Global Variables
+**
+*/
+
+/*
+****************************************************************************
+** Functions
+***************************************************************************
+*/
+
+/*
+** Name:
+** CFE_ES_StartApplications
+**
+** Purpose:
+** This routine loads/starts cFE applications.
+**
+*/
+void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath)
+{
+ char ES_AppLoadBuffer[ES_START_BUFF_SIZE]; /* A buffer of for a line in a file */
+ char ScriptFileName[OS_MAX_PATH_LEN];
+ const char *TokenList[CFE_ES_STARTSCRIPT_MAX_TOKENS_PER_LINE];
+ uint32 NumTokens;
+ uint32 BuffLen; /* Length of the current buffer */
+ osal_id_t AppFile = OS_OBJECT_ID_UNDEFINED;
+ int32 Status;
+ char c;
+ bool LineTooLong = false;
+ bool FileOpened = false;
+
+ /*
+ ** Get the ES startup script filename.
+ ** If this is a Processor Reset, try to open the file in the volatile disk first.
+ */
+ if (ResetType == CFE_PSP_RST_TYPE_PROCESSOR)
+ {
+ /*
+ ** First Attempt to parse as file in the volatile disk (temp area).
+ */
+ Status = CFE_FS_ParseInputFileName(ScriptFileName, CFE_PLATFORM_ES_VOLATILE_STARTUP_FILE,
+ sizeof(ScriptFileName), CFE_FS_FileCategory_TEMP);
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = OS_OpenCreate(&AppFile, ScriptFileName, OS_FILE_FLAG_NONE, OS_READ_ONLY);
+ }
+
+ if (Status >= 0)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Opened ES App Startup file: %s\n", ScriptFileName);
+ FileOpened = true;
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Cannot Open Volatile Startup file, Trying Nonvolatile.\n");
+ }
+
+ } /* end if */
+
+ /*
+ ** This if block covers two cases: A Power on reset, and a Processor reset when
+ ** the startup file on the volatile file system could not be opened.
+ */
+ if (FileOpened == false)
+ {
+ /*
+ ** Try to Open the file passed in to the cFE start.
+ */
+ Status = CFE_FS_ParseInputFileName(ScriptFileName, StartFilePath, sizeof(ScriptFileName),
+ CFE_FS_FileCategory_SCRIPT);
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = OS_OpenCreate(&AppFile, ScriptFileName, OS_FILE_FLAG_NONE, OS_READ_ONLY);
+ }
+
+ if (Status >= 0)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Opened ES App Startup file: %s\n", ScriptFileName);
+ FileOpened = true;
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error, Can't Open ES App Startup file: %s EC = 0x%08X\n", StartFilePath,
+ (unsigned int)Status);
+ }
+ }
+
+ /*
+ ** If the file is opened in either the Nonvolatile or the Volatile disk, process it.
+ */
+ if (FileOpened == true)
+ {
+ memset(ES_AppLoadBuffer, 0x0, ES_START_BUFF_SIZE);
+ BuffLen = 0;
+ NumTokens = 0;
+ TokenList[0] = ES_AppLoadBuffer;
+
+ /*
+ ** Parse the lines from the file. If it has an error
+ ** or reaches EOF, then abort the loop.
+ */
+ while (1)
+ {
+ Status = OS_read(AppFile, &c, 1);
+ if (Status < 0)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error Reading Startup file. EC = 0x%08X\n", (unsigned int)Status);
+ break;
+ }
+ else if (Status == 0)
+ {
+ /*
+ ** EOF Reached
+ */
+ break;
+ }
+ else if (c != '!')
+ {
+ if (c <= ' ')
+ {
+ /*
+ ** Skip all white space in the file
+ */
+ ;
+ }
+ else if (c == ',')
+ {
+ /*
+ ** replace the field delimiter with a null
+ ** This is used to separate the tokens
+ */
+ if (BuffLen < ES_START_BUFF_SIZE)
+ {
+ ES_AppLoadBuffer[BuffLen] = 0;
+ }
+ else
+ {
+ LineTooLong = true;
+ }
+ BuffLen++;
+
+ if (NumTokens < (CFE_ES_STARTSCRIPT_MAX_TOKENS_PER_LINE - 1))
+ {
+ /*
+ * NOTE: pointer never deferenced unless "LineTooLong" is false.
+ */
+ ++NumTokens;
+ TokenList[NumTokens] = &ES_AppLoadBuffer[BuffLen];
+ }
+ }
+ else if (c != ';')
+ {
+ /*
+ ** Regular data gets copied in
+ */
+ if (BuffLen < ES_START_BUFF_SIZE)
+ {
+ ES_AppLoadBuffer[BuffLen] = c;
+ }
+ else
+ {
+ LineTooLong = true;
+ }
+ BuffLen++;
+ }
+ else
+ {
+ if (LineTooLong == true)
+ {
+ /*
+ ** The was too big for the buffer
+ */
+ CFE_ES_WriteToSysLog("ES Startup: ES Startup File Line is too long: %u bytes.\n",
+ (unsigned int)BuffLen);
+ LineTooLong = false;
+ }
+ else
+ {
+ /*
+ ** Send the line to the file parser
+ ** Ensure termination of the last token and send it along
+ */
+ ES_AppLoadBuffer[BuffLen] = 0;
+ CFE_ES_ParseFileEntry(TokenList, 1 + NumTokens);
+ }
+ BuffLen = 0;
+ NumTokens = 0;
+ }
+ }
+ else
+ {
+ /*
+ ** break when EOF character '!' is reached
+ */
+ break;
+ }
+ }
+ /*
+ ** close the file
+ */
+ OS_close(AppFile);
+ }
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_ParseFileEntry
+**
+** Purpose: This function parses the startup file line for an individual
+** cFE application.
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens)
+{
+ const char * ModuleName;
+ const char * EntryType;
+ unsigned long ParsedValue;
+ union
+ {
+ CFE_ES_AppId_t AppId;
+ CFE_ES_LibId_t LibId;
+ } IdBuf;
+ int32 Status;
+ CFE_ES_AppStartParams_t ParamBuf;
+
+ /*
+ ** Check to see if the correct number of items were parsed
+ */
+ if (NumTokens < 8)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Invalid ES Startup file entry: %u\n", (unsigned int)NumTokens);
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /* Get pointers to specific tokens that are simple strings used as-is */
+ EntryType = TokenList[0];
+ ModuleName = TokenList[3];
+
+ /*
+ * Other tokens will need to be scrubbed/converted.
+ * Both Libraries and Apps use File Name (1) and Symbol Name (2) fields so copy those now
+ */
+ memset(&ParamBuf, 0, sizeof(ParamBuf));
+ Status = CFE_FS_ParseInputFileName(ParamBuf.BasicInfo.FileName, TokenList[1], sizeof(ParamBuf.BasicInfo.FileName),
+ CFE_FS_FileCategory_DYNAMIC_MODULE);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Invalid ES Startup script file name: %s\n", TokenList[1]);
+ return Status;
+ }
+
+ strncpy(ParamBuf.BasicInfo.InitSymbolName, TokenList[2], sizeof(ParamBuf.BasicInfo.InitSymbolName) - 1);
+
+ if (strcmp(EntryType, "CFE_APP") == 0)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Loading file: %s, APP: %s\n", ParamBuf.BasicInfo.FileName, ModuleName);
+
+ /*
+ * Priority and Exception action have limited ranges, which is checked here
+ * Task priority cannot be bigger than OS_MAX_TASK_PRIORITY
+ */
+ ParsedValue = strtoul(TokenList[4], NULL, 0);
+ if (ParsedValue > OS_MAX_TASK_PRIORITY)
+ {
+ ParamBuf.MainTaskInfo.Priority = OS_MAX_TASK_PRIORITY;
+ }
+ else
+ {
+ /* convert parsed value to correct type */
+ ParamBuf.MainTaskInfo.Priority = (CFE_ES_TaskPriority_Atom_t)ParsedValue;
+ }
+
+ /* No specific upper/lower limit for stack size - will pass value through */
+ ParamBuf.MainTaskInfo.StackSize = strtoul(TokenList[5], NULL, 0);
+
+ /*
+ ** Validate Some parameters
+ ** Exception action should be 0 ( Restart App ) or
+ ** 1 ( Processor reset ). If it's non-zero, assume it means
+ ** reset CPU.
+ */
+ ParsedValue = strtoul(TokenList[7], NULL, 0);
+ if (ParsedValue > CFE_ES_ExceptionAction_RESTART_APP)
+ {
+ ParamBuf.ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART;
+ }
+ else
+ {
+ /* convert parsed value to correct type */
+ ParamBuf.ExceptionAction = (CFE_ES_ExceptionAction_Enum_t)ParsedValue;
+ }
+
+ /*
+ ** Now create the application
+ */
+ Status = CFE_ES_AppCreate(&IdBuf.AppId, ModuleName, &ParamBuf);
+ }
+ else if (strcmp(EntryType, "CFE_LIB") == 0)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Loading shared library: %s\n", ParamBuf.BasicInfo.FileName);
+
+ /*
+ ** Now load the library
+ */
+ Status = CFE_ES_LoadLibrary(&IdBuf.LibId, ModuleName, &ParamBuf.BasicInfo);
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Unexpected EntryType %s in startup file.\n", EntryType);
+ Status = CFE_ES_ERR_APP_CREATE;
+ }
+
+ return (Status);
+}
+
+/*
+**-------------------------------------------------------------------------------------
+** Name: CFE_ES_LoadModule
+**
+** Helper function to load + configure (but not start) a new app/lib module
+**
+** Loads the module file via OSAL and stores all relevant info in the table entry as necessary.
+**
+**-------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_LoadModule(CFE_ResourceId_t ParentResourceId, const char *ModuleName,
+ const CFE_ES_ModuleLoadParams_t *LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus)
+{
+ osal_id_t ModuleId;
+ cpuaddr InitSymbolAddress;
+ int32 ReturnCode;
+ int32 StatusCode;
+ uint32 LoadFlags;
+
+ LoadFlags = 0;
+ InitSymbolAddress = 0;
+ ReturnCode = CFE_SUCCESS;
+
+ if (LoadParams->FileName[0] != 0)
+ {
+ switch (CFE_ResourceId_GetBase(ParentResourceId))
+ {
+ case CFE_ES_APPID_BASE:
+ /*
+ * Apps should not typically have symbols exposed to other apps.
+ *
+ * Keeping symbols local/private may help ensure this module is unloadable
+ * in the future, depending on underlying OS/loader implementation.
+ */
+ LoadFlags |= OS_MODULE_FLAG_LOCAL_SYMBOLS;
+ break;
+ case CFE_ES_LIBID_BASE:
+ /*
+ * Libraries need to have their symbols exposed to other apps.
+ *
+ * Note on some OS/loader implementations this may make it so the module
+ * cannot be unloaded, if there is no way to ensure that symbols
+ * are not being referenced. CFE does not currently support unloading
+ * of libraries for this reason, among others.
+ */
+ LoadFlags |= OS_MODULE_FLAG_GLOBAL_SYMBOLS;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Load the module via OSAL.
+ */
+ StatusCode = OS_ModuleLoad(&ModuleId, ModuleName, LoadParams->FileName, LoadFlags);
+
+ if (StatusCode != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Could not load file:%s. EC = 0x%08X\n", LoadParams->FileName,
+ (unsigned int)StatusCode);
+ ModuleId = OS_OBJECT_ID_UNDEFINED;
+ ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL;
+ }
+ }
+ else
+ {
+ ModuleId = OS_OBJECT_ID_UNDEFINED;
+ }
+
+ /*
+ * If the Load was OK, then lookup the address of the entry point
+ */
+ if (ReturnCode == CFE_SUCCESS && LoadParams->InitSymbolName[0] != 0)
+ {
+ StatusCode = OS_ModuleSymbolLookup(ModuleId, &InitSymbolAddress, LoadParams->InitSymbolName);
+ if (StatusCode != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Could not find symbol:%s. EC = 0x%08X\n", LoadParams->InitSymbolName,
+ (unsigned int)StatusCode);
+ ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL;
+ }
+ }
+
+ if (ReturnCode == CFE_SUCCESS)
+ {
+ /* store the data in the app record after successful load+lookup */
+ LoadStatus->ModuleId = ModuleId;
+ LoadStatus->InitSymbolAddress = InitSymbolAddress;
+ }
+ else if (OS_ObjectIdDefined(ModuleId))
+ {
+ /* If the module had been successfully loaded, then unload it,
+ * so that it does not consume resources */
+ StatusCode = OS_ModuleUnload(ModuleId);
+ if (StatusCode != OS_SUCCESS) /* There's not much we can do except notify */
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Failed to unload: %s. EC = 0x%08X\n", ModuleName,
+ (unsigned int)StatusCode);
+ }
+ }
+
+ return ReturnCode;
+}
+
+/*
+**-------------------------------------------------------------------------------------
+** Name: CFE_ES_GetTaskFunction
+**
+** Helper function to act as the intermediate entry point of an app
+** This is to support starting apps before having a fully completed entry in the
+** global app table. The app startup will delay until the app creation is completed
+** and verified, then the actual entry point will be determined.
+**
+**-------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GetTaskFunction(CFE_ES_TaskEntryFuncPtr_t *FuncPtr)
+{
+ CFE_ES_TaskRecord_t * TaskRecPtr;
+ CFE_ES_TaskEntryFuncPtr_t EntryFunc;
+ int32 ReturnCode;
+ int32 Timeout;
+
+ /*
+ * Use the same timeout as was used for the startup script itself.
+ */
+ ReturnCode = CFE_ES_ERR_APP_REGISTER;
+ Timeout = CFE_PLATFORM_ES_STARTUP_SCRIPT_TIMEOUT_MSEC;
+ EntryFunc = NULL;
+
+ while (true)
+ {
+ OS_TaskDelay(CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ TaskRecPtr = CFE_ES_GetTaskRecordByContext();
+ if (TaskRecPtr != NULL)
+ {
+ EntryFunc = TaskRecPtr->EntryFunc;
+ if (CFE_RESOURCEID_TEST_DEFINED(TaskRecPtr->AppId) && EntryFunc != 0)
+ {
+ ReturnCode = CFE_SUCCESS;
+ }
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ if (ReturnCode == CFE_SUCCESS || Timeout <= 0)
+ {
+ /* end of loop condition */
+ break;
+ }
+
+ Timeout -= CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC;
+ }
+
+ /* output function address to caller */
+ if (FuncPtr != NULL)
+ {
+ *FuncPtr = EntryFunc;
+ }
+
+ return (ReturnCode);
+}
+
+/*
+**-------------------------------------------------------------------------------------
+** Name: CFE_ES_TaskEntryPoint
+**
+** Helper function to act as the intermediate entry point of an app
+** This is to support starting apps before having a fully completed entry in the
+** global app table. The app startup will delay until the app creation is completed
+** and verified, then the actual entry point will be determined.
+**
+**-------------------------------------------------------------------------------------
+*/
+void CFE_ES_TaskEntryPoint(void)
+{
+ CFE_ES_TaskEntryFuncPtr_t RealEntryFunc;
+
+ if (CFE_ES_GetTaskFunction(&RealEntryFunc) == CFE_SUCCESS && RealEntryFunc != NULL)
+ {
+ /*
+ * Set the default exception environment, which should
+ * be done serialized (i.e. only one task at a time should
+ * call into CFE_PSP_SetDefaultExceptionEnvironment).
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ CFE_PSP_SetDefaultExceptionEnvironment();
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * Call the actual task entry function
+ */
+ (*RealEntryFunc)();
+ }
+}
+
+/*
+**-------------------------------------------------------------------------------------
+** Name: CFE_ES_StartMainTask
+**
+** Helper function to start (but not load) a new app/lib module
+**
+** Note that OSAL does not separate the action of creating and start a task, providing
+** only OS_TaskCreate which does both. But there is a potential race condition if
+** the real task code starts and calls any function that depends on having an AppID
+** context before its fully registered in the global app table.
+**
+** Therefore this calls a dedicated CFE_ES_AppEntryPoint which then will wait until
+** the task is fully registered in the global, before calling the actual app entry point.
+**
+**-------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_StartAppTask(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName, CFE_ES_TaskEntryFuncPtr_t EntryFunc,
+ const CFE_ES_TaskStartParams_t *Params, CFE_ES_AppId_t ParentAppId)
+{
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+ osal_id_t OsalTaskId;
+ CFE_ES_TaskId_t LocalTaskId;
+ int32 StatusCode;
+ int32 ReturnCode;
+
+ /*
+ * Create the primary task for the newly loaded task
+ */
+ StatusCode = OS_TaskCreate(&OsalTaskId, /* task id */
+ TaskName, /* task name matches app name for main task */
+ CFE_ES_TaskEntryPoint, /* task function pointer */
+ OSAL_TASK_STACK_ALLOCATE, /* stack pointer (allocate) */
+ Params->StackSize, /* stack size */
+ Params->Priority, /* task priority */
+ OS_FP_ENABLED); /* task options */
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (StatusCode == OS_SUCCESS)
+ {
+ /*
+ * As this is a newly-created task, this shouldn't fail.
+ * The entry is not (yet) matching the task ID - it will be
+ * initialized here.
+ */
+ LocalTaskId = CFE_ES_TaskId_FromOSAL(OsalTaskId);
+ TaskRecPtr = CFE_ES_LocateTaskRecordByID(LocalTaskId);
+ if (CFE_ES_TaskRecordIsUsed(TaskRecPtr))
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: Error: ES_TaskTable slot for ID %lx in use at task creation!\n",
+ OS_ObjectIdToInteger(OsalTaskId));
+ }
+
+ /*
+ * Clear any other/stale data that might be in the entry,
+ * and reset all fields to the correct value.
+ */
+ memset(TaskRecPtr, 0, sizeof(*TaskRecPtr));
+
+ TaskRecPtr->AppId = ParentAppId;
+ TaskRecPtr->EntryFunc = EntryFunc;
+ TaskRecPtr->StartParams = *Params;
+
+ strncpy(TaskRecPtr->TaskName, TaskName, sizeof(TaskRecPtr->TaskName) - 1);
+ TaskRecPtr->TaskName[sizeof(TaskRecPtr->TaskName) - 1] = 0;
+
+ CFE_ES_TaskRecordSetUsed(TaskRecPtr, CFE_RESOURCEID_UNWRAP(LocalTaskId));
+
+ /*
+ * Increment the registered Task count.
+ */
+ CFE_ES_Global.RegisteredTasks++;
+ ReturnCode = CFE_SUCCESS;
+ *TaskIdPtr = CFE_ES_TaskRecordGetID(TaskRecPtr);
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: AppCreate Error: TaskCreate %s Failed. EC = 0x%08X!\n", TaskName,
+ (unsigned int)StatusCode);
+ ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL;
+ *TaskIdPtr = CFE_ES_TASKID_UNDEFINED;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return ReturnCode;
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: ES_AppCreate
+**
+** Purpose: This function loads and creates a cFE Application.
+** This function can be called from the ES startup code when it
+** loads the cFE Applications from the disk using the startup script, or it
+** can be called when the ES Start Application command is executed.
+**
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, const char *AppName, const CFE_ES_AppStartParams_t *Params)
+{
+ CFE_Status_t Status;
+ CFE_ES_AppRecord_t *AppRecPtr;
+ CFE_ResourceId_t PendingResourceId = CFE_RESOURCEID_UNDEFINED;
+
+ /*
+ * The AppName must not be NULL
+ */
+ if (AppName == NULL || Params == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /* Confirm name will fit inside the record */
+ if (memchr(AppName, 0, sizeof(AppRecPtr->AppName)) == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /*
+ ** Allocate an ES_AppTable entry
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Find an ES AppTable entry, and set to RESERVED
+ **
+ ** In this state, the entry is no longer free, but also will not pass the
+ ** validation test. So this function effectively has exclusive access
+ ** without holding the global lock.
+ **
+ ** IMPORTANT: it must set the ID to something else before leaving
+ ** this function or else the resource will be leaked. After this
+ ** point, execution must proceed to the end of the function to
+ ** guarantee that the entry is either completed or freed.
+ */
+
+ /*
+ * Check for an existing entry with the same name.
+ * Also check for a matching Library name.
+ * (Apps and libraries should be uniquely named)
+ */
+ AppRecPtr = CFE_ES_LocateAppRecordByName(AppName);
+ if (AppRecPtr != NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: Duplicate app name '%s'\n", AppName);
+ Status = CFE_ES_ERR_DUPLICATE_NAME;
+ }
+ else
+ {
+ /* scan for a free slot */
+ PendingResourceId = CFE_ResourceId_FindNext(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS,
+ CFE_ES_CheckAppIdSlotUsed);
+ AppRecPtr = CFE_ES_LocateAppRecordByID(CFE_ES_APPID_C(PendingResourceId));
+
+ if (AppRecPtr == NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: No free application slots available\n");
+ Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE;
+ }
+ else
+ {
+ /* Fully clear the entry, just in case of stale data */
+ memset(AppRecPtr, 0, sizeof(*AppRecPtr));
+
+ /* Store the app name from passed-in value */
+ strncpy(AppRecPtr->AppName, AppName, sizeof(AppRecPtr->AppName) - 1);
+
+ AppRecPtr->Type = CFE_ES_AppType_EXTERNAL;
+
+ /*
+ * Fill out the parameters in the StartParams sub-structure
+ *
+ * This contains all relevant info, including file name, entry point,
+ * main task info, etc. which is required to start the app now
+ * or in a future restart/reload request.
+ */
+ AppRecPtr->StartParams = *Params;
+
+ /*
+ * Fill out the Task State info
+ */
+ AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN;
+ AppRecPtr->ControlReq.AppTimerMsec = 0;
+
+ CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_RESOURCEID_RESERVED);
+ CFE_ES_Global.LastAppId = PendingResourceId;
+ Status = CFE_SUCCESS;
+ }
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * If ID allocation was not successful, return now.
+ * A message regarding the issue should have already been logged
+ */
+ if (Status != CFE_SUCCESS)
+ {
+ return Status;
+ }
+
+ /*
+ * Load the module based on StartParams configured above.
+ */
+ Status = CFE_ES_LoadModule(PendingResourceId, AppName, &AppRecPtr->StartParams.BasicInfo, &AppRecPtr->LoadStatus);
+
+ /*
+ * If the Load was OK, then complete the initialization
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ Status =
+ CFE_ES_StartAppTask(&AppRecPtr->MainTaskId, /* Task ID (output) stored in App Record as main task */
+ AppName, /* Main Task name matches app name */
+ (CFE_ES_TaskEntryFuncPtr_t)
+ AppRecPtr->LoadStatus.InitSymbolAddress, /* Init Symbol is main task entry point */
+ &AppRecPtr->StartParams.MainTaskInfo, /* Main task parameters */
+ CFE_ES_APPID_C(PendingResourceId)); /* Parent App ID */
+ }
+
+ /*
+ * Finalize data in the app table entry, which must be done under lock.
+ * This transitions the entry from being RESERVED to the real ID.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ * important - set the ID to its proper value
+ * which turns this into a real/valid table entry
+ */
+ CFE_ES_AppRecordSetUsed(AppRecPtr, PendingResourceId);
+
+ /*
+ ** Increment the registered App counter.
+ */
+ CFE_ES_Global.RegisteredExternalApps++;
+ }
+ else
+ {
+ /*
+ * Set the table entry back to free
+ */
+ CFE_ES_AppRecordSetFree(AppRecPtr);
+ PendingResourceId = CFE_RESOURCEID_UNDEFINED;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ *ApplicationIdPtr = CFE_ES_APPID_C(PendingResourceId);
+
+ return Status;
+
+} /* End Function */
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_LoadLibrary
+**
+** Purpose: This function loads and initializes a cFE Shared Library.
+**
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, const char *LibName, const CFE_ES_ModuleLoadParams_t *Params)
+{
+ CFE_ES_LibraryEntryFuncPtr_t FunctionPointer;
+ CFE_ES_LibRecord_t * LibSlotPtr;
+ int32 Status;
+ CFE_ResourceId_t PendingResourceId;
+
+ /*
+ * The LibName must not be NULL
+ */
+ if (LibName == NULL || Params == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /* Confirm name will fit inside the record */
+ if (memchr(LibName, 0, sizeof(LibSlotPtr->LibName)) == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /*
+ ** Allocate an ES_LibTable entry
+ */
+ FunctionPointer = NULL;
+ PendingResourceId = CFE_RESOURCEID_UNDEFINED;
+
+ /*
+ ** Find an ES AppTable entry, and set to RESERVED
+ **
+ ** In this state, the entry is no longer free, but also will not pass the
+ ** validation test. So this function effectively has exclusive access
+ ** without holding the global lock.
+ **
+ ** IMPORTANT: it must set the ID to something else before leaving
+ ** this function or else the resource will be leaked. After this
+ ** point, execution must proceed to the end of the function to
+ ** guarantee that the entry is either completed or freed.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ * Check for an existing entry with the same name.
+ * Also check for a matching Library name.
+ * (Libs and libraries should be uniquely named)
+ */
+ LibSlotPtr = CFE_ES_LocateLibRecordByName(LibName);
+ if (LibSlotPtr != NULL || CFE_ES_LocateAppRecordByName(LibName) != NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: Duplicate Lib name '%s'\n", LibName);
+ if (LibSlotPtr != NULL)
+ {
+ PendingResourceId = CFE_RESOURCEID_UNWRAP(CFE_ES_LibRecordGetID(LibSlotPtr));
+ }
+ Status = CFE_ES_ERR_DUPLICATE_NAME;
+ }
+ else
+ {
+ /* scan for a free slot */
+ PendingResourceId =
+ CFE_ResourceId_FindNext(CFE_ES_Global.LastLibId, CFE_PLATFORM_ES_MAX_LIBRARIES, CFE_ES_CheckLibIdSlotUsed);
+ LibSlotPtr = CFE_ES_LocateLibRecordByID(CFE_ES_LIBID_C(PendingResourceId));
+
+ if (LibSlotPtr == NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: No free library slots available\n");
+ Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE;
+ }
+ else
+ {
+ /* Fully clear the entry, just in case of stale data */
+ memset(LibSlotPtr, 0, sizeof(*LibSlotPtr));
+
+ /*
+ * Fill out the parameters in the AppStartParams sub-structure
+ */
+ strncpy(LibSlotPtr->LibName, LibName, sizeof(LibSlotPtr->LibName) - 1);
+ LibSlotPtr->LibName[sizeof(LibSlotPtr->LibName) - 1] = '\0';
+ LibSlotPtr->LoadParams = *Params;
+
+ CFE_ES_LibRecordSetUsed(LibSlotPtr, CFE_RESOURCEID_RESERVED);
+ CFE_ES_Global.LastLibId = PendingResourceId;
+ Status = CFE_SUCCESS;
+ }
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * If any off-nominal condition exists, skip the rest of this logic.
+ * (Log message already written)
+ */
+ if (Status != CFE_SUCCESS)
+ {
+ *LibraryIdPtr = CFE_ES_LIBID_C(PendingResourceId);
+ return Status;
+ }
+
+ /*
+ * Load the module based on StartParams configured above.
+ */
+ Status = CFE_ES_LoadModule(PendingResourceId, LibName, &LibSlotPtr->LoadParams, &LibSlotPtr->LoadStatus);
+ if (Status == CFE_SUCCESS)
+ {
+ FunctionPointer = (CFE_ES_LibraryEntryFuncPtr_t)LibSlotPtr->LoadStatus.InitSymbolAddress;
+ if (FunctionPointer != NULL)
+ {
+ Status = (*FunctionPointer)(CFE_ES_LIBID_C(PendingResourceId));
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Load Shared Library Init Error = 0x%08x\n", (unsigned int)Status);
+ }
+ }
+ }
+
+ /*
+ * Finalize data in the app table entry, which must be done under lock.
+ * This transitions the entry from being RESERVED to the real type,
+ * either MAIN_TASK (success) or returning to INVALID (failure).
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ * important - set the ID to its proper value
+ * which turns this into a real/valid table entry
+ */
+ CFE_ES_LibRecordSetUsed(LibSlotPtr, PendingResourceId);
+
+ /*
+ * Increment the registered Lib counter.
+ */
+ CFE_ES_Global.RegisteredLibs++;
+ }
+ else
+ {
+ CFE_ES_LibRecordSetFree(LibSlotPtr);
+ PendingResourceId = CFE_RESOURCEID_UNDEFINED;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ *LibraryIdPtr = CFE_ES_LIBID_C(PendingResourceId);
+
+ return (Status);
+
+} /* End Function */
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_RunAppTableScan
+**
+** Purpose: This function scans the ES Application table and acts on the changes
+** in application states. This is where the external cFE Applications are
+** restarted, reloaded, or deleted.
+**---------------------------------------------------------------------------------------
+*/
+bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg)
+{
+ CFE_ES_AppTableScanState_t *State = (CFE_ES_AppTableScanState_t *)Arg;
+ uint32 i;
+ CFE_ES_AppRecord_t * AppPtr;
+ CFE_ES_AppId_t AppTimeoutList[CFE_PLATFORM_ES_MAX_APPLICATIONS];
+ uint32 NumAppTimeouts;
+
+ if (State->PendingAppStateChanges == 0)
+ {
+ /*
+ * If the command count changes, then a scan becomes due immediately.
+ */
+ if (State->LastScanCommandCount == CFE_ES_Global.TaskData.CommandCounter &&
+ State->BackgroundScanTimer > ElapsedTime)
+ {
+ /* no action at this time, background scan is not due yet */
+ State->BackgroundScanTimer -= ElapsedTime;
+ return false;
+ }
+ }
+
+ /*
+ * Every time a scan is initiated (for any reason)
+ * reset the background scan timer to the full value,
+ * and take a snapshot of the the command counter.
+ */
+ NumAppTimeouts = 0;
+ State->BackgroundScanTimer = CFE_PLATFORM_ES_APP_SCAN_RATE;
+ State->LastScanCommandCount = CFE_ES_Global.TaskData.CommandCounter;
+ State->PendingAppStateChanges = 0;
+
+ /*
+ * Scan needs to be done with the table locked,
+ * as these state changes need to be done atomically
+ * with respect to other tasks that also access/update
+ * the state.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Scan the ES Application table. Skip entries that are:
+ ** - Not in use, or
+ ** - cFE Core apps, or
+ ** - Currently running
+ */
+ AppPtr = CFE_ES_Global.AppTable;
+ for (i = 0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS; i++)
+ {
+ if (CFE_ES_AppRecordIsUsed(AppPtr) && AppPtr->Type == CFE_ES_AppType_EXTERNAL)
+ {
+ if (AppPtr->AppState > CFE_ES_AppState_RUNNING)
+ {
+ /*
+ * Increment the "pending" counter which reflects
+ * the number of apps that are in some phase of clean up.
+ */
+ ++State->PendingAppStateChanges;
+
+ /*
+ * Decrement the wait timer, if active.
+ * When the timeout value becomes zero, take the action to delete/restart/reload the app
+ */
+ if (AppPtr->ControlReq.AppTimerMsec > ElapsedTime)
+ {
+ AppPtr->ControlReq.AppTimerMsec -= ElapsedTime;
+ }
+ else
+ {
+ AppPtr->ControlReq.AppTimerMsec = 0;
+
+ /* Add it to the list to be processed later */
+ AppTimeoutList[NumAppTimeouts] = CFE_ES_AppRecordGetID(AppPtr);
+ ++NumAppTimeouts;
+ }
+ }
+ else if (AppPtr->AppState == CFE_ES_AppState_RUNNING &&
+ AppPtr->ControlReq.AppControlRequest > CFE_ES_RunStatus_APP_RUN)
+ {
+ /* this happens after a command arrives to restart/reload/delete an app */
+ /* switch to WAITING state, and set the timer for transition */
+ AppPtr->AppState = CFE_ES_AppState_WAITING;
+ AppPtr->ControlReq.AppTimerMsec = CFE_PLATFORM_ES_APP_KILL_TIMEOUT * CFE_PLATFORM_ES_APP_SCAN_RATE;
+ }
+
+ } /* end if */
+
+ ++AppPtr;
+
+ } /* end for loop */
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * Now invoke the CFE_ES_ProcessControlRequest() routine for any app
+ * which has reached that point.
+ */
+ for (i = 0; i < NumAppTimeouts; i++)
+ {
+ /*
+ * Call CFE_ES_ProcessControlRequest() with a reference to
+ * the _copies_ of the app record details. (This avoids
+ * needing to access the global records outside of the lock).
+ */
+ CFE_ES_ProcessControlRequest(AppTimeoutList[i]);
+ }
+
+ /*
+ * This state machine is considered active if there are any
+ * pending app state changes. Returning "true" will cause this job
+ * to be called from the background task at a faster interval.
+ */
+ return (State->PendingAppStateChanges != 0);
+
+} /* End Function */
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_ProcessControlRequest
+**
+** Purpose: This function will perform the requested control action for an application.
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_ProcessControlRequest(CFE_ES_AppId_t AppId)
+{
+ CFE_ES_AppRecord_t * AppRecPtr;
+ uint32 PendingControlReq;
+ CFE_ES_AppStartParams_t RestartParams;
+ char OrigAppName[OS_MAX_API_NAME];
+ CFE_Status_t CleanupStatus;
+ CFE_Status_t StartupStatus;
+ CFE_ES_AppId_t NewAppId;
+ const char * ReqName;
+ char MessageDetail[48];
+ uint16 EventID;
+ CFE_EVS_EventType_Enum_t EventType;
+
+ /* Init/clear all local state variables */
+ ReqName = NULL;
+ MessageDetail[0] = 0;
+ EventID = 0;
+ EventType = 0;
+ StartupStatus = CFE_SUCCESS;
+ PendingControlReq = 0;
+ NewAppId = CFE_ES_APPID_UNDEFINED;
+ OrigAppName[0] = 0;
+ memset(&RestartParams, 0, sizeof(RestartParams));
+
+ AppRecPtr = CFE_ES_LocateAppRecordByID(AppId);
+
+ /*
+ * Take a local snapshot of the important app record data
+ * This way it becomes private and can be accessed without
+ * concerns about other threads/tasks, even after the global
+ * data records are eventually cleared.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (CFE_ES_AppRecordIsMatch(AppRecPtr, AppId))
+ {
+ PendingControlReq = AppRecPtr->ControlReq.AppControlRequest;
+ strncpy(OrigAppName, AppRecPtr->AppName, sizeof(OrigAppName) - 1);
+ OrigAppName[sizeof(OrigAppName) - 1] = 0;
+
+ /* If a restart was requested, copy the parameters to re-use in new app */
+ if (PendingControlReq == CFE_ES_RunStatus_SYS_RESTART || PendingControlReq == CFE_ES_RunStatus_SYS_RELOAD)
+ {
+ RestartParams = AppRecPtr->StartParams;
+ }
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * All control requests start by deleting the app/task and
+ * all associated resources.
+ *
+ * The reload/restart requests will start it again, and it gets
+ * a new appID. For other requests it just leaves it deleted.
+ *
+ * Note that Cleanup can fail for a variety of reasons, including
+ * situations where e.g. a task ID had become stale because the task
+ * already exited itself. In most cases these are minor errors and
+ * reflect problems with the consistency of the old app record.
+ *
+ * Even when this happens the cleanup should still do its best effort
+ * to release all relevant global data entries. So it should not
+ * prevent starting the new app, if a restart/reload is indicated.
+ */
+ CleanupStatus = CFE_ES_CleanUpApp(AppId);
+
+ /*
+ * Attempt to restart the app if the request indicated to do so,
+ * regardless of the CleanupStatus.
+ */
+ if (PendingControlReq == CFE_ES_RunStatus_SYS_RESTART || PendingControlReq == CFE_ES_RunStatus_SYS_RELOAD)
+ {
+ StartupStatus = CFE_ES_AppCreate(&NewAppId, OrigAppName, &RestartParams);
+ }
+
+ /*
+ * Determine the event ID associated with the control request,
+ * which indicates the success/failure of the operation and
+ * any other relevant detail.
+ *
+ * Note that the specific event ID that gets generated is the only
+ * other difference between all these control request types.
+ */
+ switch (PendingControlReq)
+ {
+ case CFE_ES_RunStatus_APP_EXIT:
+ ReqName = "Exit";
+ if (CleanupStatus != CFE_SUCCESS)
+ {
+ /* error event for this request */
+ EventID = CFE_ES_EXIT_APP_ERR_EID;
+ }
+ else
+ {
+ /* success event for this request */
+ EventID = CFE_ES_EXIT_APP_INF_EID;
+ }
+ break;
+
+ case CFE_ES_RunStatus_APP_ERROR:
+ ReqName = "Exit";
+ if (CleanupStatus != CFE_SUCCESS)
+ {
+ /* error event for this request */
+ EventID = CFE_ES_ERREXIT_APP_ERR_EID;
+ }
+ else
+ {
+ /* success event for this request */
+ EventID = CFE_ES_ERREXIT_APP_INF_EID;
+ }
+ break;
+
+ case CFE_ES_RunStatus_SYS_DELETE:
+ ReqName = "Stop";
+ if (CleanupStatus != CFE_SUCCESS)
+ {
+ /* error event for this request */
+ EventID = CFE_ES_STOP_ERR3_EID;
+ }
+ else
+ {
+ /* success event for this request */
+ EventID = CFE_ES_STOP_INF_EID;
+ }
+ break;
+
+ case CFE_ES_RunStatus_SYS_RESTART:
+ ReqName = "Restart";
+ if (CleanupStatus != CFE_SUCCESS)
+ {
+ /* error event for this request */
+ EventID = CFE_ES_RESTART_APP_ERR4_EID;
+ }
+ else if (StartupStatus != CFE_SUCCESS)
+ {
+ /* error event for this request */
+ EventID = CFE_ES_RESTART_APP_ERR3_EID;
+ }
+ else
+ {
+ /* success event for this request */
+ EventID = CFE_ES_RESTART_APP_INF_EID;
+ }
+ break;
+
+ case CFE_ES_RunStatus_SYS_RELOAD:
+ ReqName = "Reload";
+ if (CleanupStatus != CFE_SUCCESS)
+ {
+ /* error event for this request */
+ EventID = CFE_ES_RELOAD_APP_ERR4_EID;
+ }
+ else if (StartupStatus != CFE_SUCCESS)
+ {
+ /* error event for this request */
+ EventID = CFE_ES_RELOAD_APP_ERR3_EID;
+ }
+ else
+ {
+ /* success event for this request */
+ EventID = CFE_ES_RELOAD_APP_INF_EID;
+ }
+ break;
+
+ /*
+ * These two cases below should never occur so they are always
+ * reported as errors, but the CFE_ES_CleanUpApp() should hopefully
+ * have fixed it either way.
+ */
+ case CFE_ES_RunStatus_SYS_EXCEPTION:
+ ReqName = "ES_ProcControlReq: Invalid State";
+ EventID = CFE_ES_PCR_ERR1_EID;
+ snprintf(MessageDetail, sizeof(MessageDetail), "EXCEPTION");
+ break;
+
+ default:
+ ReqName = "ES_ProcControlReq: Unknown State";
+ EventID = CFE_ES_PCR_ERR2_EID;
+ snprintf(MessageDetail, sizeof(MessageDetail), "( %lu )", (unsigned long)PendingControlReq);
+ break;
+ }
+
+ if (MessageDetail[0] != 0)
+ {
+ /* Detail message already set, assume it is an error event */
+ EventType = CFE_EVS_EventType_ERROR;
+ }
+ else if (StartupStatus != CFE_SUCCESS)
+ {
+ /* Make detail message for event containing startup error code */
+ EventType = CFE_EVS_EventType_ERROR;
+ snprintf(MessageDetail, sizeof(MessageDetail), "Failed: AppCreate Error 0x%08X.", (unsigned int)StartupStatus);
+ }
+ else if (CleanupStatus != CFE_SUCCESS)
+ {
+ /* Make detail message for event containing cleanup error code */
+ EventType = CFE_EVS_EventType_ERROR;
+ snprintf(MessageDetail, sizeof(MessageDetail), "Failed: CleanUpApp Error 0x%08X.", (unsigned int)CleanupStatus);
+ }
+ else if (CFE_RESOURCEID_TEST_DEFINED(NewAppId))
+ {
+ /* Record success message for event where app is restarted */
+ EventType = CFE_EVS_EventType_INFORMATION;
+ snprintf(MessageDetail, sizeof(MessageDetail), "Completed, AppID=%lu", CFE_RESOURCEID_TO_ULONG(NewAppId));
+ }
+ else
+ {
+ /* Record success message for event */
+ EventType = CFE_EVS_EventType_INFORMATION;
+ snprintf(MessageDetail, sizeof(MessageDetail), "Completed.");
+ }
+
+ CFE_EVS_SendEvent(EventID, EventType, "%s Application %s %s", ReqName, OrigAppName, MessageDetail);
+
+} /* End Function */
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CleanUpApp
+**
+** Purpose: Delete an application by cleaning up all of it's resources.
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_CleanUpApp(CFE_ES_AppId_t AppId)
+{
+ uint32 i;
+ int32 Status;
+ int32 ReturnCode;
+ CFE_ES_TaskId_t TaskList[OS_MAX_TASKS];
+ CFE_ES_MemHandle_t PoolList[CFE_PLATFORM_ES_MAX_MEMORY_POOLS];
+ osal_id_t ModuleId;
+ uint32 NumTasks;
+ uint32 NumPools;
+ CFE_ES_AppRecord_t * AppRecPtr;
+ CFE_ES_TaskRecord_t * TaskRecPtr;
+ CFE_ES_MemPoolRecord_t *MemPoolRecPtr;
+
+ NumTasks = 0;
+ NumPools = 0;
+ ModuleId = OS_OBJECT_ID_UNDEFINED;
+ ReturnCode = CFE_SUCCESS;
+
+ AppRecPtr = CFE_ES_LocateAppRecordByID(AppId);
+
+ /*
+ * Collect a list of resources previously owned by this app, which
+ * must be done while the global data is locked.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (CFE_ES_AppRecordIsMatch(AppRecPtr, AppId))
+ {
+ if (AppRecPtr->Type == CFE_ES_AppType_EXTERNAL)
+ {
+ CFE_ES_Global.RegisteredExternalApps--;
+
+ /*
+ * Get the Module ID, if it was an external app
+ *
+ * (this will be OS_OBJECT_ID_UNDEFINED if it was not loaded dynamically)
+ */
+ ModuleId = AppRecPtr->LoadStatus.ModuleId;
+ }
+
+ /*
+ * Collect all tasks associated with this app
+ */
+ TaskRecPtr = CFE_ES_Global.TaskTable;
+ for (i = 0; i < OS_MAX_TASKS; i++)
+ {
+ if (CFE_ES_TaskRecordIsUsed(TaskRecPtr) && CFE_RESOURCEID_TEST_EQUAL(TaskRecPtr->AppId, AppId))
+ {
+ TaskList[NumTasks] = CFE_ES_TaskRecordGetID(TaskRecPtr);
+
+ /* Store the main task ID at index 0 (swap with whatever was there) */
+ if (CFE_RESOURCEID_TEST_EQUAL(TaskList[NumTasks], AppRecPtr->MainTaskId) && NumTasks != 0)
+ {
+ TaskList[NumTasks] = TaskList[0];
+ TaskList[0] = AppRecPtr->MainTaskId;
+ }
+
+ /* Mark record for removal */
+ CFE_ES_TaskRecordSetUsed(TaskRecPtr, CFE_RESOURCEID_RESERVED);
+ ++NumTasks;
+ }
+
+ ++TaskRecPtr;
+ } /* end for */
+
+ CFE_ES_Global.RegisteredTasks -= NumTasks;
+
+ /*
+ * Collect memory pools associated with this app
+ */
+ MemPoolRecPtr = CFE_ES_Global.MemPoolTable;
+ for (i = 0; i < CFE_PLATFORM_ES_MAX_MEMORY_POOLS; i++)
+ {
+ if (CFE_ES_MemPoolRecordIsUsed(MemPoolRecPtr) &&
+ CFE_RESOURCEID_TEST_EQUAL(MemPoolRecPtr->OwnerAppID, AppId))
+ {
+ PoolList[NumPools] = CFE_ES_MemPoolRecordGetID(MemPoolRecPtr);
+ ++NumPools;
+ }
+
+ ++MemPoolRecPtr;
+ } /* end for */
+
+ /*
+ * Set the record to RESERVED.
+ *
+ * This prevents reallocation of this slot while the remainder
+ * of resources are freed.
+ */
+ CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_RESOURCEID_RESERVED);
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_CleanUpApp: AppID %lu is not valid for deletion\n",
+ CFE_RESOURCEID_TO_ULONG(AppId));
+ ReturnCode = CFE_ES_APP_CLEANUP_ERR;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ if (ReturnCode != CFE_SUCCESS)
+ {
+ return ReturnCode;
+ }
+
+ /*
+ * Now actually delete all the resources associated with the task.
+ *
+ * Most of this involves calling into other subsystems, so it is
+ * done while the ES global data is UNLOCKED to avoid holding more
+ * than one lock at a time.
+ */
+
+ /*
+ ** Call the Table Clean up function
+ */
+ CFE_TBL_CleanUpApp(AppId);
+
+ /*
+ ** Call the Software Bus clean up function
+ */
+ CFE_SB_CleanUpApp(AppId);
+
+ /*
+ ** Call the TIME Clean up function
+ */
+ CFE_TIME_CleanUpApp(AppId);
+
+ /*
+ ** Call the EVS Clean up function
+ */
+ Status = CFE_EVS_CleanUpApp(AppId);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_CleanUpApp: Call to CFE_EVS_CleanUpApp returned Error: 0x%08X\n",
+ (unsigned int)Status);
+ ReturnCode = CFE_ES_APP_CLEANUP_ERR;
+ }
+
+ /*
+ * Delete all tasks.
+ *
+ * Note that the main task is always positioned at index 0 in this list.
+ *
+ * This iterates the list in reverse order, such that the child
+ * tasks are deleted first (in any order) and main task is deleted last.
+ */
+ i = NumTasks;
+ while (i > 0)
+ {
+ --i;
+ Status = CFE_ES_CleanupTaskResources(TaskList[i]);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_CleanUpApp: CleanUpTaskResources for Task ID:%lu returned Error: 0x%08X\n",
+ CFE_RESOURCEID_TO_ULONG(TaskList[i]), (unsigned int)Status);
+ ReturnCode = CFE_ES_APP_CLEANUP_ERR;
+ }
+ }
+
+ /*
+ * Delete all mem pools.
+ */
+ for (i = 0; i < NumPools; ++i)
+ {
+ Status = CFE_ES_PoolDelete(PoolList[i]);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_MemPoolCleanupApp: delete pool %lu returned Error: 0x%08X\n",
+ CFE_RESOURCEID_TO_ULONG(PoolList[i]), (unsigned int)Status);
+ ReturnCode = CFE_ES_APP_CLEANUP_ERR;
+ }
+ }
+
+ /*
+ ** Unload the module, if applicable
+ */
+ if (OS_ObjectIdDefined(ModuleId))
+ {
+ /*
+ ** Unload the module only if it is an external app
+ */
+ Status = OS_ModuleUnload(ModuleId);
+ if (Status != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_CleanUpApp: Module (ID:0x%08lX) Unload failed. RC=0x%08X\n",
+ OS_ObjectIdToInteger(ModuleId), (unsigned int)Status);
+ ReturnCode = CFE_ES_APP_CLEANUP_ERR;
+ }
+ }
+
+ /*
+ * Finally, re-acquire the ES lock and set all
+ * table entries free for re-use.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ * Free all task records.
+ */
+ for (i = 0; i < NumTasks; ++i)
+ {
+ TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskList[i]);
+ if (CFE_ES_TaskRecordIsMatch(TaskRecPtr, CFE_ES_TASKID_C(CFE_RESOURCEID_RESERVED)))
+ {
+ CFE_ES_TaskRecordSetFree(TaskRecPtr);
+ }
+ }
+
+ /*
+ * Now finally delete the record and allow re-use of the slot.
+ */
+ if (CFE_ES_AppRecordIsMatch(AppRecPtr, CFE_ES_APPID_C(CFE_RESOURCEID_RESERVED)))
+ {
+ CFE_ES_AppRecordSetFree(AppRecPtr);
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (ReturnCode);
+
+} /* end function */
+
+/*
+ * Simple state structure used when cleaning up objects associated with tasks
+ *
+ * This is used locally by CFE_ES_CleanupTaskResources
+ */
+typedef struct
+{
+ uint32 ErrorFlag;
+ uint32 FoundObjects;
+ uint32 PrevFoundObjects;
+ uint32 DeletedObjects;
+ int32 OverallStatus;
+} CFE_ES_CleanupState_t;
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CleanupObjectCallback
+**
+** Purpose: Helper function clean up all objects.
+**
+** NOTE: This is called while holding the ES global lock
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_CleanupObjectCallback(osal_id_t ObjectId, void *arg)
+{
+ CFE_ES_CleanupState_t *CleanState;
+ int32 Status;
+ osal_objtype_t ObjType;
+ bool ObjIsValid;
+
+ CleanState = (CFE_ES_CleanupState_t *)arg;
+ ObjIsValid = true;
+
+ ObjType = OS_IdentifyObject(ObjectId);
+ switch (ObjType)
+ {
+ case OS_OBJECT_TYPE_OS_TASK:
+ Status = OS_TaskDelete(ObjectId);
+ break;
+ case OS_OBJECT_TYPE_OS_QUEUE:
+ Status = OS_QueueDelete(ObjectId);
+ break;
+ case OS_OBJECT_TYPE_OS_BINSEM:
+ Status = OS_BinSemDelete(ObjectId);
+ break;
+ case OS_OBJECT_TYPE_OS_COUNTSEM:
+ Status = OS_CountSemDelete(ObjectId);
+ break;
+ case OS_OBJECT_TYPE_OS_MUTEX:
+ Status = OS_MutSemDelete(ObjectId);
+ break;
+ case OS_OBJECT_TYPE_OS_TIMECB:
+ Status = OS_TimerDelete(ObjectId);
+ break;
+ case OS_OBJECT_TYPE_OS_STREAM:
+ Status = OS_close(ObjectId);
+ break;
+ case OS_OBJECT_TYPE_OS_MODULE:
+ Status = OS_ModuleUnload(ObjectId);
+ break;
+ default:
+ ObjIsValid = false;
+ Status = OS_ERROR;
+ break;
+ }
+
+ if (ObjIsValid)
+ {
+ ++CleanState->FoundObjects;
+ if (Status == OS_SUCCESS)
+ {
+ ++CleanState->DeletedObjects;
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("Call to OSAL Delete Object (ID:%lu) failed. RC=0x%08X\n",
+ OS_ObjectIdToInteger(ObjectId), (unsigned int)Status);
+ if (CleanState->OverallStatus == CFE_SUCCESS)
+ {
+ /*
+ * Translate any OS failures into the appropriate CFE_ES return codes
+ * (Some object types have special return codes, depending on what type
+ * of object failed to delete)
+ */
+ switch (ObjType)
+ {
+ case OS_OBJECT_TYPE_OS_TASK:
+ CleanState->OverallStatus = CFE_ES_ERR_CHILD_TASK_DELETE;
+ break;
+ case OS_OBJECT_TYPE_OS_QUEUE:
+ CleanState->OverallStatus = CFE_ES_QUEUE_DELETE_ERR;
+ break;
+ case OS_OBJECT_TYPE_OS_BINSEM:
+ CleanState->OverallStatus = CFE_ES_BIN_SEM_DELETE_ERR;
+ break;
+ case OS_OBJECT_TYPE_OS_COUNTSEM:
+ CleanState->OverallStatus = CFE_ES_COUNT_SEM_DELETE_ERR;
+ break;
+ case OS_OBJECT_TYPE_OS_MUTEX:
+ CleanState->OverallStatus = CFE_ES_MUT_SEM_DELETE_ERR;
+ break;
+ case OS_OBJECT_TYPE_OS_TIMECB:
+ CleanState->OverallStatus = CFE_ES_TIMER_DELETE_ERR;
+ break;
+ default:
+ /* generic failure */
+ CleanState->OverallStatus = CFE_ES_APP_CLEANUP_ERR;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CleanupTaskResources
+**
+** Purpose: Clean up the OS resources associated with an individual Task
+** Note: This is called when the ES global is UNLOCKED - so it should not touch
+** any ES global data structures. It should only clean up at the OSAL level.
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_CleanupTaskResources(CFE_ES_TaskId_t TaskId)
+{
+ CFE_ES_CleanupState_t CleanState;
+ int32 Result;
+ osal_id_t OsalId;
+
+ /* Get the Task ID for calling OSAL APIs (convert type) */
+ OsalId = CFE_ES_TaskId_ToOSAL(TaskId);
+
+ /*
+ ** Delete all OSAL resources that belong to this task
+ */
+ memset(&CleanState, 0, sizeof(CleanState));
+ --CleanState.PrevFoundObjects;
+ while (1)
+ {
+ OS_ForEachObject(OsalId, CFE_ES_CleanupObjectCallback, &CleanState);
+ if (CleanState.FoundObjects == 0 || CleanState.ErrorFlag != 0)
+ {
+ break;
+ }
+ /*
+ * The number of found objects should show a downward trend,
+ * if not, then stop and do not loop here forever. (This can
+ * happen when using the UT stub functions, or if an object
+ * cannot be fully deleted successfully).
+ */
+ CleanState.ErrorFlag =
+ (CleanState.DeletedObjects == 0 || CleanState.FoundObjects >= CleanState.PrevFoundObjects);
+ CleanState.PrevFoundObjects = CleanState.FoundObjects;
+ CleanState.FoundObjects = 0;
+ CleanState.DeletedObjects = 0;
+ }
+
+ /*
+ ** Delete the task itself
+ **
+ ** Note, if the task self exited, then the ID becomes invalid.
+ ** In this case the OS_ERR_INVALID_ID status is returned, but
+ ** that is OK, there is nothing else needed to do.
+ */
+ Result = OS_TaskDelete(OsalId);
+ if (Result == OS_SUCCESS || Result == OS_ERR_INVALID_ID)
+ {
+ Result = CleanState.OverallStatus;
+ if (Result == CFE_SUCCESS && CleanState.FoundObjects > 0)
+ {
+ /* Objects leftover after cleanup -- resource leak */
+ Result = CFE_ES_APP_CLEANUP_ERR;
+ }
+ }
+ else
+ {
+ Result = CFE_ES_TASK_DELETE_ERR;
+ }
+
+ return (Result);
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CopyModuleBasicInfo
+**
+** Purpose: Populate the cFE_ES_AppInfo structure with the data for an app.
+**
+** This internal function does not log any errors/events. The caller is expected
+** to check the return code and log any relevant errors based on the context.
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_CopyModuleBasicInfo(const CFE_ES_ModuleLoadParams_t *ParamsPtr, CFE_ES_AppInfo_t *AppInfoPtr)
+{
+ strncpy(AppInfoPtr->EntryPoint, ParamsPtr->InitSymbolName, sizeof(AppInfoPtr->EntryPoint) - 1);
+ AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 1] = '\0';
+
+ strncpy(AppInfoPtr->FileName, ParamsPtr->FileName, sizeof(AppInfoPtr->FileName) - 1);
+ AppInfoPtr->FileName[sizeof(AppInfoPtr->FileName) - 1] = '\0';
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CopyModuleStatusInfo
+**
+** Purpose: Populate the cFE_ES_AppInfo structure with the data for an app.
+**
+** This internal function does not log any errors/events. The caller is expected
+** to check the return code and log any relevant errors based on the context.
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_CopyModuleStatusInfo(const CFE_ES_ModuleLoadStatus_t *StatusPtr, CFE_ES_AppInfo_t *AppInfoPtr)
+{
+ AppInfoPtr->StartAddress = CFE_ES_MEMADDRESS_C(StatusPtr->InitSymbolAddress);
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CopyModuleAddressInfo
+**
+** Purpose: Populate the cFE_ES_AppInfo structure with the data for an app.
+**
+** This internal function does not log any errors/events. The caller is expected
+** to check the return code and log any relevant errors based on the context.
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_CopyModuleAddressInfo(osal_id_t ModuleId, CFE_ES_AppInfo_t *AppInfoPtr)
+{
+ OS_module_prop_t ModuleInfo;
+ int32 ReturnCode;
+
+ ReturnCode = OS_ModuleInfo(ModuleId, &ModuleInfo);
+ if (ReturnCode == OS_SUCCESS)
+ {
+ AppInfoPtr->AddressesAreValid =
+ (sizeof(ModuleInfo.addr.code_address) <= sizeof(AppInfoPtr->CodeAddress)) && ModuleInfo.addr.valid;
+ }
+ else
+ {
+ AppInfoPtr->AddressesAreValid = false;
+ memset(&ModuleInfo, 0, sizeof(ModuleInfo));
+ }
+
+ /*
+ * Convert the internal size and address to the telemetry format.
+ * (The telemetry format may be a different bitwidth than the native processor)
+ */
+ AppInfoPtr->CodeAddress = CFE_ES_MEMADDRESS_C(ModuleInfo.addr.code_address);
+ AppInfoPtr->CodeSize = CFE_ES_MEMOFFSET_C(ModuleInfo.addr.code_size);
+ AppInfoPtr->DataAddress = CFE_ES_MEMADDRESS_C(ModuleInfo.addr.data_address);
+ AppInfoPtr->DataSize = CFE_ES_MEMOFFSET_C(ModuleInfo.addr.data_size);
+ AppInfoPtr->BSSAddress = CFE_ES_MEMADDRESS_C(ModuleInfo.addr.bss_address);
+ AppInfoPtr->BSSSize = CFE_ES_MEMOFFSET_C(ModuleInfo.addr.bss_size);
+}
diff --git a/modules/es/fsw/src/cfe_es_apps.h b/modules/es/fsw/src/cfe_es_apps.h
new file mode 100644
index 000000000..3b8e3c56f
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_apps.h
@@ -0,0 +1,303 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * This file contains the Internal interface for the cFE Application control functions of ES.
+ * These functions and data structures manage the Applications and Child tasks in the cFE.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ */
+
+#ifndef CFE_ES_APPS_H
+#define CFE_ES_APPS_H
+
+/*
+** Include Files
+*/
+#include "common_types.h"
+
+#include "cfe_es_api_typedefs.h"
+#include "cfe_fs_api_typedefs.h"
+
+/*
+** Macro Definitions
+*/
+#define CFE_ES_STARTSCRIPT_MAX_TOKENS_PER_LINE 8
+
+/*
+** Type Definitions
+*/
+
+/*
+** CFE_ES_AppState_t is a structure of information for External cFE Apps.
+** This information is used to control/alter the state of External Apps.
+** The fields in this structure are not needed or used for the cFE Core Apps.
+*/
+typedef struct
+{
+ uint32 AppControlRequest; /* What the App should be doing next */
+ int32 AppTimerMsec; /* Countdown timer for killing an app, in milliseconds */
+
+} CFE_ES_ControlReq_t;
+
+/*
+** CFE_ES_ModuleLoadParams_t contains the information used when a module
+** (library or app) load request initially processed in the system. It captures
+** the fundamental information - the name, the file to load, its entry point.
+** It contains information directly provided by the user, not runtime status or
+** other derived information.
+**
+** This information should remain fairly constant after initial allocation, even
+** if the application is restarted for some reason. The major exception is the
+** ReloadApp command, which can change the FileName.
+*/
+typedef struct
+{
+ char InitSymbolName[OS_MAX_API_NAME];
+ char FileName[OS_MAX_PATH_LEN];
+
+} CFE_ES_ModuleLoadParams_t;
+
+/*
+** CFE_ES_ModuleLoadStatus_t is a structure of information used when a module
+** (library or app) is actually loaded in the system. It captures the
+** runtime information - the module ID and starting address.
+**
+** This information may change if the module is reloaded.
+*/
+typedef struct
+{
+ osal_id_t ModuleId;
+ cpuaddr InitSymbolAddress;
+
+} CFE_ES_ModuleLoadStatus_t;
+
+/*
+** CFE_ES_TaskStartParams_t contains basic details about a CFE task
+**
+** This information needs to be specified when starting a task and is
+** stored as part of the task record for future reference.
+*/
+typedef struct
+{
+ size_t StackSize;
+ CFE_ES_TaskPriority_Atom_t Priority;
+
+} CFE_ES_TaskStartParams_t;
+
+/*
+** CFE_ES_AppStartParams_t contains basic details about a CFE app.
+**
+** This is an extension of the CFE_ES_ModuleLoadParams_t which adds information
+** about the main task and exception action. It is only used for apps, as libraries
+** do not have a task associated.
+*/
+typedef struct
+{
+ /*
+ * Basic (static) information about the module
+ */
+ CFE_ES_ModuleLoadParams_t BasicInfo;
+
+ CFE_ES_TaskStartParams_t MainTaskInfo;
+ CFE_ES_ExceptionAction_Enum_t ExceptionAction;
+
+} CFE_ES_AppStartParams_t;
+
+/*
+** CFE_ES_AppRecord_t is an internal structure used to keep track of
+** CFE Applications that are active in the system.
+*/
+typedef struct
+{
+ CFE_ES_AppId_t AppId; /* The actual AppID of this entry, or undefined */
+ char AppName[OS_MAX_API_NAME]; /* The name of the app */
+ CFE_ES_AppState_Enum_t AppState; /* Is the app running, or stopped, or waiting? */
+ CFE_ES_AppType_Enum_t Type; /* The type of App: CORE or EXTERNAL */
+ CFE_ES_AppStartParams_t StartParams; /* The start parameters for an App */
+ CFE_ES_ModuleLoadStatus_t LoadStatus; /* Runtime module information */
+ CFE_ES_ControlReq_t ControlReq; /* The Control Request Record for External cFE Apps */
+ CFE_ES_TaskId_t MainTaskId; /* The Application's Main Task ID */
+
+} CFE_ES_AppRecord_t;
+
+/*
+** CFE_ES_TaskRecord_t is an internal structure used to keep track of
+** CFE Tasks that are active in the system.
+*/
+typedef struct
+{
+ CFE_ES_TaskId_t TaskId; /* The actual TaskID of this entry, or undefined */
+ char TaskName[OS_MAX_API_NAME]; /* Task Name */
+ CFE_ES_AppId_t AppId; /* The parent Application's App ID */
+ CFE_ES_TaskStartParams_t StartParams; /* The start parameters for the task */
+ CFE_ES_TaskEntryFuncPtr_t EntryFunc; /* Task entry function */
+ uint32 ExecutionCounter; /* The execution counter for the task */
+
+} CFE_ES_TaskRecord_t;
+
+/*
+** CFE_ES_LibRecord_t is an internal structure used to keep track of
+** CFE Shared Libraries that are loaded in the system.
+*/
+typedef struct
+{
+ CFE_ES_LibId_t LibId; /* The actual LibID of this entry, or undefined */
+ char LibName[OS_MAX_API_NAME]; /* Library Name */
+ CFE_ES_ModuleLoadParams_t LoadParams; /* Basic (static) information about the module */
+ CFE_ES_ModuleLoadStatus_t LoadStatus; /* Runtime information about the module */
+
+} CFE_ES_LibRecord_t;
+
+/*
+** CFE_ES_AppTableScanState_t is an internal structure used to keep state of
+** the background app table scan/cleanup process
+*/
+typedef struct
+{
+ uint32 PendingAppStateChanges;
+ uint32 BackgroundScanTimer;
+ uint8 LastScanCommandCount;
+} CFE_ES_AppTableScanState_t;
+
+/*****************************************************************************/
+/*
+** Function prototypes
+*/
+
+/*
+** Internal function start applications based on the startup script
+*/
+void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath);
+
+/*
+** Internal function to parse/execute a line of the cFE application startup 'script'
+*/
+int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens);
+
+/*
+** Internal function to load a module (app or library)
+** This only loads the code and looks up relevent runtime information.
+** It does not start any tasks.
+*/
+int32 CFE_ES_LoadModule(CFE_ResourceId_t ParentResourceId, const char *ModuleName,
+ const CFE_ES_ModuleLoadParams_t *LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus);
+
+/*
+** Internal function to determine the entry point of an app.
+** If the app isn't fully registered in the global app table,
+** then this delays until the app is completely configured and the entry point is
+** confirmed to be valid.
+*/
+int32 CFE_ES_GetTaskFunction(CFE_ES_TaskEntryFuncPtr_t *FuncPtr);
+
+/*
+** Intermediate entry point of all tasks. Determines the actual
+** entry point from the global data structures.
+*/
+void CFE_ES_TaskEntryPoint(void);
+
+/*
+** Internal function to start a task associated with an app.
+*/
+int32 CFE_ES_StartAppTask(CFE_ES_TaskId_t *TaskIdPtr, const char *TaskName, CFE_ES_TaskEntryFuncPtr_t EntryFunc,
+ const CFE_ES_TaskStartParams_t *Params, CFE_ES_AppId_t ParentAppId);
+
+/*
+** Internal function to create/start a new cFE app
+** based on the parameters passed in
+*/
+int32 CFE_ES_AppCreate(CFE_ES_AppId_t *ApplicationIdPtr, const char *AppName, const CFE_ES_AppStartParams_t *Params);
+
+/*
+** Internal function to load a a new cFE shared Library
+*/
+int32 CFE_ES_LoadLibrary(CFE_ES_LibId_t *LibraryIdPtr, const char *LibName, const CFE_ES_ModuleLoadParams_t *Params);
+
+/*
+** Scan the Application Table for actions to take
+*/
+bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg);
+
+/*
+** Scan for new exceptions stored in the PSP
+*/
+bool CFE_ES_RunExceptionScan(uint32 ElapsedTime, void *Arg);
+
+/*
+ * Background file write data getter for ER log entry
+ */
+bool CFE_ES_BackgroundERLogFileDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize);
+
+/*
+ * Background file write event handler for ER log entry
+ */
+void CFE_ES_BackgroundERLogFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum,
+ size_t BlockSize, size_t Position);
+
+/*
+** Perform the requested control action for an application
+*/
+void CFE_ES_ProcessControlRequest(CFE_ES_AppId_t AppId);
+
+/*
+** Clean up all app resources and delete it
+*/
+int32 CFE_ES_CleanUpApp(CFE_ES_AppId_t AppId);
+
+/*
+** Clean up all Task resources and detete the task
+*/
+int32 CFE_ES_CleanupTaskResources(CFE_ES_TaskId_t TaskId);
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CopyModuleBasicInfo
+**
+** Purpose: Populate the cFE_ES_AppInfo structure from the CFE_ES_ModuleLoadParams_t data
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_CopyModuleBasicInfo(const CFE_ES_ModuleLoadParams_t *ParamsPtr, CFE_ES_AppInfo_t *AppInfoPtr);
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CopyModuleStatusInfo
+**
+** Purpose: Populate the cFE_ES_AppInfo structure from the CFE_ES_ModuleLoadStatus_t data
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_CopyModuleStatusInfo(const CFE_ES_ModuleLoadStatus_t *StatusPtr, CFE_ES_AppInfo_t *AppInfoPtr);
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_CopyModuleAddressInfo
+**
+** Purpose: Populate the cFE_ES_AppInfo structure with address information from OSAL.
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_CopyModuleAddressInfo(osal_id_t ModuleId, CFE_ES_AppInfo_t *AppInfoPtr);
+
+#endif /* CFE_ES_APPS_H */
diff --git a/modules/es/fsw/src/cfe_es_backgroundtask.c b/modules/es/fsw/src/cfe_es_backgroundtask.c
new file mode 100644
index 000000000..046c1545c
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_backgroundtask.c
@@ -0,0 +1,230 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File: cfe_es_backgroundtask.c
+**
+** Purpose: This file contains the implementation of the ES "background task"
+**
+** This task sits idle most of the time, but is woken by the ES application
+** for various maintenance duties that may take time to execute, such as
+** writing status/log files.
+**
+*/
+
+/*
+** Include Section
+*/
+
+#include
+
+#include "cfe_es_module_all.h"
+
+#define CFE_ES_BACKGROUND_SEM_NAME "ES_BG_SEM"
+#define CFE_ES_BACKGROUND_CHILD_NAME "ES_BG_TASK"
+#define CFE_ES_BACKGROUND_CHILD_STACK_PTR CFE_ES_TASK_STACK_ALLOCATE
+#define CFE_ES_BACKGROUND_CHILD_STACK_SIZE CFE_PLATFORM_ES_PERF_CHILD_STACK_SIZE
+#define CFE_ES_BACKGROUND_CHILD_PRIORITY CFE_PLATFORM_ES_PERF_CHILD_PRIORITY
+#define CFE_ES_BACKGROUND_CHILD_FLAGS 0
+#define CFE_ES_BACKGROUND_MAX_IDLE_DELAY 30000 /* 30 seconds */
+
+typedef struct
+{
+ bool (*RunFunc)(uint32 ElapsedTime, void *Arg);
+ void * JobArg;
+ uint32 ActivePeriod; /**< max wait/delay time between calls when job is active */
+ uint32 IdlePeriod; /**< max wait/delay time between calls when job is idle */
+} CFE_ES_BackgroundJobEntry_t;
+
+/*
+ * List of "background jobs"
+ *
+ * This is just a list of functions to periodically call from the context of the background task,
+ * and can be added/extended as needed.
+ *
+ * Each Job function returns a boolean, and should return "true" if it is active, or "false" if it is idle.
+ *
+ * This uses "cooperative multitasking" -- the function should do some limited work, then return to the
+ * background task. It will be called again after a delay period to do more work.
+ */
+const CFE_ES_BackgroundJobEntry_t CFE_ES_BACKGROUND_JOB_TABLE[] = {
+ {/* ES app table background scan */
+ .RunFunc = CFE_ES_RunAppTableScan,
+ .JobArg = &CFE_ES_Global.BackgroundAppScanState,
+ .ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE / 4,
+ .IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE},
+ {/* Performance Log Data Dump to file */
+ .RunFunc = CFE_ES_RunPerfLogDump,
+ .JobArg = &CFE_ES_Global.BackgroundPerfDumpState,
+ .ActivePeriod = CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY,
+ .IdlePeriod = CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY * 1000},
+ {/* Check for exceptions stored in the PSP */
+ .RunFunc = CFE_ES_RunExceptionScan,
+ .JobArg = NULL,
+ .ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE,
+ .IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE},
+ {/* Call FS to handle background file writes */
+ .RunFunc = CFE_FS_RunBackgroundFileDump,
+ .JobArg = NULL,
+ .ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE,
+ .IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE}};
+
+#define CFE_ES_BACKGROUND_NUM_JOBS (sizeof(CFE_ES_BACKGROUND_JOB_TABLE) / sizeof(CFE_ES_BACKGROUND_JOB_TABLE[0]))
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Name: CFE_ES_BackgroundTask */
+/* */
+/* Purpose: A helper task for low priority routines that may take time to */
+/* execute, such as writing log files. */
+/* */
+/* Assumptions and Notes: This is started from the ES initialization, and */
+/* pends on a semaphore until a work request comes in. This is intended to */
+/* avoid the need to create a child task "on demand" when work items arrive, */
+/* which is a form of dynamic allocation. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void CFE_ES_BackgroundTask(void)
+{
+ int32 status;
+ uint32 JobTotal;
+ uint32 NumJobsRunning;
+ uint32 NextDelay;
+ uint32 ElapsedTime;
+ OS_time_t CurrTime;
+ OS_time_t LastTime;
+ const CFE_ES_BackgroundJobEntry_t *JobPtr;
+
+ CFE_PSP_GetTime(&LastTime);
+
+ while (true)
+ {
+ /*
+ * compute the elapsed time (difference) between last
+ * execution and now, in milliseconds.
+ */
+ CFE_PSP_GetTime(&CurrTime);
+ ElapsedTime = OS_TimeGetTotalMilliseconds(OS_TimeSubtract(CurrTime, LastTime));
+ LastTime = CurrTime;
+
+ NextDelay = CFE_ES_BACKGROUND_MAX_IDLE_DELAY; /* default; will be adjusted based on active jobs */
+ JobPtr = CFE_ES_BACKGROUND_JOB_TABLE;
+ JobTotal = CFE_ES_BACKGROUND_NUM_JOBS;
+ NumJobsRunning = 0;
+
+ while (JobTotal > 0)
+ {
+ /*
+ * call the background job -
+ * if it returns "true" that means it is active,
+ * if it returns "false" that means it is idle
+ */
+ if (JobPtr->RunFunc != NULL && JobPtr->RunFunc(ElapsedTime, JobPtr->JobArg))
+ {
+ ++NumJobsRunning;
+
+ if (JobPtr->ActivePeriod != 0 && NextDelay > JobPtr->ActivePeriod)
+ {
+ /* next delay is based on this active job wait time */
+ NextDelay = JobPtr->ActivePeriod;
+ }
+ }
+ else if (JobPtr->IdlePeriod != 0 && NextDelay > JobPtr->IdlePeriod)
+ {
+ /* next delay is based on this idle job wait time */
+ NextDelay = JobPtr->IdlePeriod;
+ }
+ --JobTotal;
+ ++JobPtr;
+ }
+
+ CFE_ES_Global.BackgroundTask.NumJobsRunning = NumJobsRunning;
+
+ status = OS_BinSemTimedWait(CFE_ES_Global.BackgroundTask.WorkSem, NextDelay);
+ if (status != OS_SUCCESS && status != OS_SEM_TIMEOUT)
+ {
+ /* should never occur */
+ CFE_ES_WriteToSysLog("CFE_ES: Failed to take background sem: %08lx\n", (unsigned long)status);
+ break;
+ }
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Name: CFE_ES_BackgroundInit */
+/* */
+/* Purpose: Initialize the background task */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_ES_BackgroundInit(void)
+{
+ int32 status;
+
+ status = OS_BinSemCreate(&CFE_ES_Global.BackgroundTask.WorkSem, CFE_ES_BACKGROUND_SEM_NAME, 0, 0);
+ if (status != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES: Failed to create background sem: %08lx\n", (unsigned long)status);
+ return status;
+ }
+
+ /* Spawn a task to write the performance data to a file */
+ status = CFE_ES_CreateChildTask(&CFE_ES_Global.BackgroundTask.TaskID, CFE_ES_BACKGROUND_CHILD_NAME,
+ CFE_ES_BackgroundTask, CFE_ES_BACKGROUND_CHILD_STACK_PTR,
+ CFE_ES_BACKGROUND_CHILD_STACK_SIZE, CFE_ES_BACKGROUND_CHILD_PRIORITY,
+ CFE_ES_BACKGROUND_CHILD_FLAGS);
+
+ if (status != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES: Failed to create background task: %08lx\n", (unsigned long)status);
+ return status;
+ }
+
+ return CFE_SUCCESS;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Name: CFE_ES_BackgroundCleanup */
+/* */
+/* Purpose: Exit/Stop the background task */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void CFE_ES_BackgroundCleanup(void)
+{
+ CFE_ES_DeleteChildTask(CFE_ES_Global.BackgroundTask.TaskID);
+ OS_BinSemDelete(CFE_ES_Global.BackgroundTask.WorkSem);
+
+ CFE_ES_Global.BackgroundTask.TaskID = CFE_ES_TASKID_UNDEFINED;
+ CFE_ES_Global.BackgroundTask.WorkSem = OS_OBJECT_ID_UNDEFINED;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Name: CFE_ES_BackgroundWakeup */
+/* */
+/* Purpose: Wake up the background task */
+/* Notifies the background task to perform an extra poll for new work */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void CFE_ES_BackgroundWakeup(void)
+{
+ /* wake up the background task by giving the sem.
+ * This is "informational" and not strictly required,
+ * but it will make the task immediately wake up and check for new
+ * work if it was idle. */
+ OS_BinSemGive(CFE_ES_Global.BackgroundTask.WorkSem);
+}
diff --git a/modules/es/fsw/src/cfe_es_cds.c b/modules/es/fsw/src/cfe_es_cds.c
new file mode 100644
index 000000000..9e6d58603
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_cds.c
@@ -0,0 +1,931 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_cds.c
+**
+** Purpose:
+** This file implements the cFE Executive Services Critical Data Store functions.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+** Notes:
+**
+** Modification History:
+**
+*/
+
+/*
+** Required header files.
+*/
+#include "cfe_es_module_all.h"
+
+#include
+#include
+#include
+
+/*****************************************************************************/
+/*
+ * CFE_ES_CDS_EarlyInit
+ *
+ * NOTE: For complete prolog information, see 'cfe_es_cds.h'
+ */
+/*****************************************************************************/
+int32 CFE_ES_CDS_EarlyInit(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ uint32 PlatformSize;
+ size_t MinRequiredSize;
+ int32 Status;
+
+ CFE_ES_Global.CDSIsAvailable = false;
+
+ /* Create CDS general access mutex */
+ Status = OS_MutSemCreate(&CDS->GenMutex, CFE_ES_CDS_MUT_REG_NAME, CFE_ES_CDS_MUT_REG_VALUE);
+ if (Status != OS_SUCCESS)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES_CDS_EarlyInit: Failed to create mutex with error %d\n", (int)Status);
+ return CFE_STATUS_EXTERNAL_RESOURCE_FAIL;
+ }
+
+ CDS->LastCDSBlockId = CFE_ResourceId_FromInteger(CFE_ES_CDSBLOCKID_BASE);
+
+ /* Get CDS size from PSP. Note that the PSP interface
+ * uses "uint32" for size here. */
+ Status = CFE_PSP_GetCDSSize(&PlatformSize);
+ if (Status != CFE_PSP_SUCCESS)
+ {
+ /* Error getting the size of the CDS from the BSP */
+ CFE_ES_WriteToSysLog("CFE_CDS:EarlyInit-Unable to obtain CDS Size from BSP (Err=0x%08X)\n",
+ (unsigned int)Status);
+ return Status;
+ }
+
+ /* Always truncate the size to the nearest 4 byte boundary */
+ CDS->TotalSize = PlatformSize & 0xfffffffc;
+
+ /* Compute the minimum size required for the CDS with the current configuration of the cFE */
+ MinRequiredSize = CDS_RESERVED_MIN_SIZE;
+ MinRequiredSize += CFE_ES_CDSReqdMinSize(CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES); /* Max # of Min Sized Blocks */
+
+ if (CDS->TotalSize < MinRequiredSize)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:EarlyInit-CDS Size (%lu) less than required (%lu)\n",
+ (unsigned long)CDS->TotalSize, (unsigned long)MinRequiredSize);
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ CDS->DataSize = CDS->TotalSize;
+ CDS->DataSize -= CDS_RESERVED_MIN_SIZE;
+
+ /* If the size was obtained successfully and meets the minimum requirements, then check its contents */
+ Status = CFE_ES_ValidateCDS();
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* If a valid CDS was found, rebuild the memory pool */
+ Status = CFE_ES_RebuildCDS();
+ }
+
+ /* If the CDS is accessible but invalid, then create a new one */
+ if (Status == CFE_ES_CDS_INVALID)
+ {
+ /* First wipe the entire CDS area */
+ Status = CFE_ES_ClearCDS();
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_ES_InitCDSSignatures();
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* Initialize the variables for managing the CDS Memory Pool */
+ Status = CFE_ES_CreateCDSPool(CDS->DataSize, CDS_POOL_OFFSET);
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_ES_InitCDSRegistry();
+ }
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ /* Unrecoverable error while reading the CDS */
+ CFE_ES_WriteToSysLog("CFE_CDS:EarlyInit-error validating/initializing CDS (0x%08lX)\n",
+ (unsigned long)Status);
+ }
+ else
+ {
+ /* Set the CDS Overall flag to be present/valid */
+ CFE_ES_Global.CDSIsAvailable = true;
+ }
+ }
+
+ return Status;
+
+} /* End of CFE_ES_CDS_EarlyInit() */
+
+/*******************************************************************/
+/*
+ * CFE_ES_LocateCDSBlockRecordByID
+ *
+ * NOTE: For complete prolog information, see 'cfe_es_cds.h'
+ */
+/*******************************************************************/
+int32 CFE_ES_CDSHandle_ToIndex(CFE_ES_CDSHandle_t BlockID, uint32 *Idx)
+{
+ return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(BlockID), CFE_ES_CDSBLOCKID_BASE,
+ CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES, Idx);
+}
+
+/*---------------------------------------------------------------------------------------
+ * Function: CFE_ES_CheckCDSHandleSlotUsed
+ *
+ * Purpose: Helper function, Aids in allocating a new ID by checking if
+ * a given ID is available. Must be called while locked.
+ *---------------------------------------------------------------------------------------
+ */
+bool CFE_ES_CheckCDSHandleSlotUsed(CFE_ResourceId_t CheckId)
+{
+ CFE_ES_CDS_RegRec_t *CDSRegRecPtr;
+ /*
+ * Note - The pointer here should never be NULL because the ID should always be
+ * within the expected range, but if it ever is NULL, this should return true
+ * such that the caller will _not_ attempt to use the record.
+ */
+ CDSRegRecPtr = CFE_ES_LocateCDSBlockRecordByID(CFE_ES_CDSHANDLE_C(CheckId));
+ return (CDSRegRecPtr == NULL || CFE_ES_CDSBlockRecordIsUsed(CDSRegRecPtr));
+}
+
+/*******************************************************************/
+/*
+ * CFE_ES_LocateCDSBlockRecordByID
+ *
+ * NOTE: For complete prolog information, see 'cfe_es_cds.h'
+ */
+/*******************************************************************/
+CFE_ES_CDS_RegRec_t *CFE_ES_LocateCDSBlockRecordByID(CFE_ES_CDSHandle_t BlockID)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ CFE_ES_CDS_RegRec_t * CDSRegRecPtr;
+ uint32 Idx;
+
+ if (CFE_ES_CDSHandle_ToIndex(BlockID, &Idx) == CFE_SUCCESS)
+ {
+ CDSRegRecPtr = &CDS->Registry[Idx];
+ }
+ else
+ {
+ CDSRegRecPtr = NULL;
+ }
+
+ return CDSRegRecPtr;
+}
+
+/*******************************************************************/
+/*
+ * CFE_ES_CacheRead()
+ *
+ * NOTE: For complete prolog information, see 'cfe_es_cds.h'
+ */
+/*******************************************************************/
+int32 CFE_ES_CDS_CacheFetch(CFE_ES_CDS_AccessCache_t *Cache, size_t Offset, size_t Size)
+{
+ int32 Status;
+
+ if (Size > 0 && Size <= sizeof(Cache->Data))
+ {
+ Cache->AccessStatus = CFE_PSP_ReadFromCDS(&Cache->Data, Offset, Size);
+
+ if (Cache->AccessStatus == CFE_PSP_SUCCESS)
+ {
+ Cache->Offset = Offset;
+ Cache->Size = Size;
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ Status = CFE_ES_CDS_ACCESS_ERROR;
+ }
+ }
+ else
+ {
+ Status = CFE_ES_CDS_INVALID_SIZE;
+ }
+
+ return Status;
+}
+
+/*******************************************************************/
+/*
+ * CFE_ES_CDS_CacheFlush()
+ *
+ * NOTE: For complete prolog information, see 'cfe_es_cds.h'
+ */
+/*******************************************************************/
+int32 CFE_ES_CDS_CacheFlush(CFE_ES_CDS_AccessCache_t *Cache)
+{
+ int32 Status;
+
+ if (Cache->Size > 0 && Cache->Size <= sizeof(Cache->Data))
+ {
+ Cache->AccessStatus = CFE_PSP_WriteToCDS(&Cache->Data, Cache->Offset, Cache->Size);
+
+ if (Cache->AccessStatus == CFE_PSP_SUCCESS)
+ {
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ Status = CFE_ES_CDS_ACCESS_ERROR;
+ }
+ }
+ else
+ {
+ Status = CFE_ES_CDS_INVALID_SIZE;
+ }
+
+ return Status;
+}
+
+/*******************************************************************/
+/*
+ * CFE_ES_CDS_CachePreload()
+ *
+ * NOTE: For complete prolog information, see 'cfe_es_cds.h'
+ */
+/*******************************************************************/
+int32 CFE_ES_CDS_CachePreload(CFE_ES_CDS_AccessCache_t *Cache, const void *Source, size_t Offset, size_t Size)
+{
+ int32 Status;
+
+ if (Size > 0 && Size <= sizeof(Cache->Data))
+ {
+ if (Source == NULL)
+ {
+ /* just zero it out */
+ memset(&Cache->Data, 0, Size);
+ }
+ else if (Source != &Cache->Data)
+ {
+ /* copy from the user-supplied preload data */
+ memcpy(&Cache->Data, Source, Size);
+ }
+ Cache->Size = Size;
+ Cache->Offset = Offset;
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ Status = CFE_ES_CDS_INVALID_SIZE;
+ }
+
+ return Status;
+}
+
+/*******************************************************************
+**
+** CFE_ES_RegisterCDSEx
+**
+** NOTE: For complete prolog information, see 'cfe_es_cds.h'
+********************************************************************/
+
+int32 CFE_ES_RegisterCDSEx(CFE_ES_CDSHandle_t *HandlePtr, size_t UserBlockSize, const char *Name, bool CriticalTbl)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+ int32 RegUpdateStatus;
+ CFE_ES_CDS_RegRec_t * RegRecPtr;
+ size_t BlockOffset;
+ size_t OldBlockSize;
+ size_t NewBlockSize;
+ CFE_ResourceId_t PendingBlockId;
+ bool IsNewEntry;
+ bool IsNewOffset;
+
+ Status = CFE_SUCCESS;
+ RegUpdateStatus = CFE_SUCCESS;
+ IsNewEntry = false;
+ IsNewOffset = false;
+
+ if (UserBlockSize == 0 || UserBlockSize > CDS_ABS_MAX_BLOCK_SIZE)
+ {
+ /* Block size is not supportable */
+ return CFE_ES_CDS_INVALID_SIZE;
+ }
+
+ /* Lock Registry for update. This prevents two applications from */
+ /* trying to register CDSs at the same location at the same time */
+ CFE_ES_LockCDS();
+
+ /*
+ * Check for an existing entry with the same name.
+ */
+ RegRecPtr = CFE_ES_LocateCDSBlockRecordByName(Name);
+ if (RegRecPtr != NULL)
+ {
+ /* in CDS a duplicate name is not necessarily an error, we
+ * may reuse/resize the existing entry */
+ PendingBlockId = CFE_RESOURCEID_UNWRAP(CFE_ES_CDSBlockRecordGetID(RegRecPtr));
+ }
+ else
+ {
+ /* scan for a free slot */
+ PendingBlockId = CFE_ResourceId_FindNext(CDS->LastCDSBlockId, CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES,
+ CFE_ES_CheckCDSHandleSlotUsed);
+ RegRecPtr = CFE_ES_LocateCDSBlockRecordByID(CFE_ES_CDSHANDLE_C(PendingBlockId));
+
+ if (RegRecPtr != NULL)
+ {
+ /* Fully clear the entry, just in case of stale data */
+ memset(RegRecPtr, 0, sizeof(*RegRecPtr));
+ CDS->LastCDSBlockId = PendingBlockId;
+ IsNewEntry = true;
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE;
+ PendingBlockId = CFE_RESOURCEID_UNDEFINED;
+ }
+ }
+
+ if (RegRecPtr != NULL)
+ {
+ /* Account for the extra header which will be added */
+ NewBlockSize = UserBlockSize;
+ NewBlockSize += sizeof(CFE_ES_CDS_BlockHeader_t);
+
+ /* If a reallocation is needed, the old block may need to be freed first */
+ if (Status == CFE_SUCCESS && RegRecPtr->BlockOffset != 0 && NewBlockSize != RegRecPtr->BlockSize)
+ {
+ /* If the new size is different, the old CDS must be deleted first */
+ Status = CFE_ES_GenPoolPutBlock(&CDS->Pool, &OldBlockSize, RegRecPtr->BlockOffset);
+
+ /*
+ * Note because CDS puts a signature at the very beginning of the memory,
+ * valid data offsets are never zero.
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ RegRecPtr->BlockOffset = 0;
+ RegRecPtr->BlockSize = 0;
+ }
+ }
+
+ /* If a new allocation is needed, do it now */
+ if (Status == CFE_SUCCESS && RegRecPtr->BlockOffset == 0)
+ {
+ /* Allocate the block for the CDS */
+ Status = CFE_ES_GenPoolGetBlock(&CDS->Pool, &BlockOffset, NewBlockSize);
+ if (Status == CFE_SUCCESS)
+ {
+ /* Save the size of the CDS */
+ RegRecPtr->BlockOffset = BlockOffset;
+ RegRecPtr->BlockSize = NewBlockSize;
+ IsNewOffset = true;
+ }
+ }
+
+ if (Status == CFE_SUCCESS && IsNewEntry)
+ {
+ /* Save flag indicating whether it is a Critical Table or not */
+ RegRecPtr->Table = CriticalTbl;
+
+ /* Save CDS Name in Registry */
+ strncpy(RegRecPtr->Name, Name, sizeof(RegRecPtr->Name) - 1);
+ RegRecPtr->Name[sizeof(RegRecPtr->Name) - 1] = 0;
+ CFE_ES_CDSBlockRecordSetUsed(RegRecPtr, PendingBlockId);
+ }
+
+ if (Status == CFE_SUCCESS && (IsNewOffset || IsNewEntry))
+ {
+ /* If we succeeded at creating a CDS, save updated registry in the CDS */
+ RegUpdateStatus = CFE_ES_UpdateCDSRegistry();
+ }
+ }
+
+ /* Unlock Registry for update */
+ CFE_ES_UnlockCDS();
+
+ /* Log any failures AFTER releasing the lock */
+ if (RegUpdateStatus != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:RegCDS-Failed to update CDS Registry (Stat=0x%08X)\n",
+ (unsigned int)RegUpdateStatus);
+
+ /*
+ * Return failure only if this was the primary error,
+ * do not overwrite a preexisting error.
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ Status = RegUpdateStatus;
+ }
+ }
+
+ if (Status == CFE_SUCCESS && !IsNewOffset)
+ {
+ /*
+ * For backward compatibility, return the
+ * special non-success success code when
+ * reallocating an existing CDS.
+ *
+ * Note this intentionally needs to return CFE_SUCCESS
+ * when reusing an exiting entry but changing the size.
+ */
+ Status = CFE_ES_CDS_ALREADY_EXISTS;
+ }
+
+ *HandlePtr = CFE_ES_CDSHANDLE_C(PendingBlockId);
+
+ return (Status);
+
+} /* End of CFE_ES_RegisterCDSEx() */
+
+/*******************************************************************
+**
+** CFE_ES_ValidateCDS
+**
+** NOTE: For complete prolog information, see prototype above
+********************************************************************/
+
+int32 CFE_ES_ValidateCDS(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ size_t TrailerOffset;
+ const size_t SIG_CDS_SIZE = {CFE_ES_CDS_SIGNATURE_LEN};
+ int32 Status;
+
+ /* Perform 2 checks to validate the CDS Memory Pool */
+ /* First, determine if the first validity check field is correct */
+ Status = CFE_ES_CDS_CacheFetch(&CDS->Cache, CDS_SIG_BEGIN_OFFSET, SIG_CDS_SIZE);
+ if (Status != CFE_PSP_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:Validate-1st ReadFromCDS Failed. Status=0x%X\n", (unsigned int)Status);
+ return Status;
+ }
+
+ if (strncmp(CDS->Cache.Data.Sig, CFE_ES_CDS_SIGNATURE_BEGIN, CFE_ES_CDS_SIGNATURE_LEN) != 0)
+ {
+ /* Beginning Validity Field failed */
+ return CFE_ES_CDS_INVALID;
+ }
+
+ TrailerOffset = CDS->TotalSize;
+ TrailerOffset -= sizeof(CFE_ES_CDS_PersistentTrailer_t);
+
+ Status = CFE_ES_CDS_CacheFetch(&CDS->Cache, TrailerOffset, SIG_CDS_SIZE);
+ if (Status != CFE_PSP_SUCCESS)
+ {
+ /* BSP reported an error reading from CDS */
+ CFE_ES_WriteToSysLog("CFE_CDS:Validate-2nd ReadFromCDS Failed. Status=0x%X\n", (unsigned int)Status);
+ return Status;
+ }
+
+ if (strncmp(CDS->Cache.Data.Sig, CFE_ES_CDS_SIGNATURE_END, CFE_ES_CDS_SIGNATURE_LEN) != 0)
+ {
+ /* Ending Validity Field failed */
+ return CFE_ES_CDS_INVALID;
+ }
+
+ /* All sanity checks passed */
+ return CFE_SUCCESS;
+} /* End of CFE_ES_ValidateCDS() */
+
+/*******************************************************************
+**
+** CFE_ES_ClearCDS
+**
+** NOTE: For complete prolog information, see prototype above
+********************************************************************/
+
+int32 CFE_ES_ClearCDS(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ size_t RemainSize;
+ int32 Status;
+
+ /* Clear the CDS to ensure everything is gone */
+ /* Create a block of zeros to write to the CDS */
+ Status = CFE_ES_CDS_CachePreload(&CDS->Cache, NULL, 0, sizeof(CDS->Cache.Data.Zero));
+
+ /* While there is space to write another block of zeros, then do so */
+ while (CDS->Cache.Offset < CDS->TotalSize)
+ {
+ RemainSize = CDS->TotalSize - CDS->Cache.Offset;
+ if (RemainSize < sizeof(CDS->Cache.Data.Zero))
+ {
+ /* partial size */
+ CDS->Cache.Size = RemainSize;
+ }
+ Status = CFE_ES_CDS_CacheFlush(&CDS->Cache);
+ if (Status != CFE_SUCCESS)
+ {
+ break;
+ }
+
+ CDS->Cache.Offset += CDS->Cache.Size;
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:Init-Clear CDS failed @ Offset=%lu Status=0x%08X\n",
+ (unsigned long)CDS->Cache.Offset, (unsigned int)CDS->Cache.AccessStatus);
+ }
+
+ return Status;
+}
+
+/*******************************************************************
+**
+** CFE_ES_InitCDSSignatures
+**
+** NOTE: For complete prolog information, see prototype above
+********************************************************************/
+
+int32 CFE_ES_InitCDSSignatures(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ size_t SigOffset;
+ int32 Status;
+
+ /* Initialize the Validity Check strings */
+ SigOffset = 0;
+ CFE_ES_CDS_CachePreload(&CDS->Cache, CFE_ES_CDS_SIGNATURE_BEGIN, SigOffset, CFE_ES_CDS_SIGNATURE_LEN);
+ Status = CFE_ES_CDS_CacheFlush(&CDS->Cache);
+ if (Status != CFE_SUCCESS)
+ {
+ /* BSP reported an error writing to CDS */
+ CFE_ES_WriteToSysLog("CFE_CDS:Init-'_CDSBeg_' write failed. Status=0x%08X\n",
+ (unsigned int)CDS->Cache.AccessStatus);
+ return Status;
+ }
+
+ SigOffset = CDS->TotalSize;
+ SigOffset -= sizeof(CFE_ES_CDS_PersistentTrailer_t);
+
+ CFE_ES_CDS_CachePreload(&CDS->Cache, CFE_ES_CDS_SIGNATURE_END, SigOffset, CFE_ES_CDS_SIGNATURE_LEN);
+ Status = CFE_ES_CDS_CacheFlush(&CDS->Cache);
+ if (Status != CFE_PSP_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:Init-'_CDSEnd_' write failed. Status=0x%08X\n",
+ (unsigned int)CDS->Cache.AccessStatus);
+ return Status;
+ }
+
+ return Status;
+} /* End of CFE_ES_InitCDSSignatures() */
+
+/*******************************************************************
+**
+** CFE_ES_InitCDSRegistry
+**
+** NOTE: For complete prolog information, see prototype above
+********************************************************************/
+
+int32 CFE_ES_InitCDSRegistry(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+ uint32 RegSize;
+
+ /* Initialize the local CDS Registry */
+ RegSize = CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES;
+ CFE_ES_CDS_CachePreload(&CDS->Cache, &RegSize, CDS_REG_SIZE_OFFSET, sizeof(RegSize));
+ /* Copy the number of registry entries to the CDS */
+ Status = CFE_ES_CDS_CacheFlush(&CDS->Cache);
+ if (Status == CFE_SUCCESS)
+ {
+ memset(CDS->Registry, 0, sizeof(CDS->Registry));
+
+ Status = CFE_ES_UpdateCDSRegistry();
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:InitReg-Failed to write Reg Size. Status=0x%08X\n",
+ (unsigned int)CDS->Cache.AccessStatus);
+ }
+
+ return Status;
+} /* End of CFE_ES_InitCDSRegistry() */
+
+/*******************************************************************
+**
+** CFE_ES_UpdateCDSRegistry
+**
+** NOTE: For complete prolog information, see 'cfe_es_cds.h'
+********************************************************************/
+
+int32 CFE_ES_UpdateCDSRegistry(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+
+ /* Copy the contents of the local registry to the CDS */
+ Status = CFE_PSP_WriteToCDS(CDS->Registry, CDS_REG_OFFSET, sizeof(CDS->Registry));
+
+ if (Status != CFE_PSP_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:UpdateReg-Failed to write CDS Registry. Status=0x%08X\n", (unsigned int)Status);
+ Status = CFE_ES_CDS_ACCESS_ERROR;
+ }
+
+ return Status;
+}
+
+/*******************************************************************
+**
+** CFE_ES_FormCDSName
+**
+** NOTE: For complete prolog information, see 'cfe_es_cds.h'
+********************************************************************/
+
+void CFE_ES_FormCDSName(char *FullCDSName, const char *CDSName, CFE_ES_AppId_t ThisAppId)
+{
+ char AppName[OS_MAX_API_NAME];
+
+ CFE_ES_GetAppName(AppName, ThisAppId, sizeof(AppName));
+
+ /* Ensure that AppName is null terminated */
+ AppName[OS_MAX_API_NAME - 1] = '\0';
+
+ /* Complete formation of processor specific table name */
+ sprintf(FullCDSName, "%s.%s", AppName, CDSName);
+
+ return;
+} /* End of CFE_ES_FormCDSName() */
+
+/*******************************************************************
+**
+** CFE_ES_LockCDSRegistry
+**
+** NOTE: For complete prolog information, see 'cfe_es_cds.h'
+********************************************************************/
+
+int32 CFE_ES_LockCDS(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+
+ Status = OS_MutSemTake(CDS->GenMutex);
+
+ /* Convert to CFE return code */
+ if (Status == OS_SUCCESS)
+ {
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ Status = CFE_STATUS_EXTERNAL_RESOURCE_FAIL;
+ }
+
+ return Status;
+
+} /* End of CFE_ES_LockCDSRegistry() */
+
+/*******************************************************************
+**
+** CFE_ES_UnlockCDSRegistry
+**
+** NOTE: For complete prolog information, see 'cfe_es_cds.h'
+********************************************************************/
+
+int32 CFE_ES_UnlockCDS(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+
+ Status = OS_MutSemGive(CDS->GenMutex);
+
+ /* Convert to CFE return code */
+ if (Status == OS_SUCCESS)
+ {
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ Status = CFE_STATUS_EXTERNAL_RESOURCE_FAIL;
+ }
+
+ return Status;
+
+} /* End of CFE_ES_UnlockCDSRegistry() */
+
+/*******************************************************************
+**
+** CFE_ES_LocateCDSBlockRecordByName
+**
+** NOTE: For complete prolog information, see 'cfe_es_cds.h'
+********************************************************************/
+
+CFE_ES_CDS_RegRec_t *CFE_ES_LocateCDSBlockRecordByName(const char *CDSName)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ CFE_ES_CDS_RegRec_t * CDSRegRecPtr;
+ uint32 NumReg;
+
+ CDSRegRecPtr = CDS->Registry;
+ NumReg = CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES;
+ while (true)
+ {
+ if (NumReg == 0)
+ {
+ CDSRegRecPtr = NULL; /* not found */
+ break;
+ }
+
+ if (CFE_ES_CDSBlockRecordIsUsed(CDSRegRecPtr))
+ {
+ /* Perform a case sensitive name comparison */
+ if (strcmp(CDSName, CDSRegRecPtr->Name) == 0)
+ {
+ /* If the names match, then stop */
+ break;
+ }
+ }
+
+ ++CDSRegRecPtr;
+ --NumReg;
+ }
+
+ return CDSRegRecPtr;
+} /* End of CFE_ES_LocateCDSBlockRecordByName() */
+
+/*******************************************************************
+**
+** CFE_ES_RebuildCDS
+**
+** NOTE: For complete prolog information, see above
+********************************************************************/
+
+int32 CFE_ES_RebuildCDS(void)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+
+ /* First, determine if the CDS registry stored in the CDS is smaller or equal */
+ /* in size to the CDS registry we are currently configured for */
+ /* Copy the number of registry entries to the CDS */
+ Status = CFE_ES_CDS_CacheFetch(&CDS->Cache, CDS_REG_SIZE_OFFSET, sizeof(CDS->Cache.Data.RegistrySize));
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("CFE_CDS:Rebuild-PSP Error reading Registry size (%lx)\n",
+ (unsigned long)CDS->Cache.AccessStatus);
+ return CFE_ES_CDS_INVALID;
+ }
+
+ if (CDS->Cache.Data.RegistrySize != CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES)
+ {
+ /* Registry in CDS is incompatible size to recover */
+ CFE_ES_WriteToSysLog("CFE_CDS:Rebuild-Registry in CDS incorrect size (%lu)\n",
+ (unsigned long)CDS->Cache.Data.RegistrySize);
+ return CFE_ES_CDS_INVALID;
+ }
+
+ Status = CFE_PSP_ReadFromCDS(&CDS->Registry, CDS_REG_OFFSET, sizeof(CDS->Registry));
+
+ if (Status == CFE_PSP_SUCCESS)
+ {
+ /* Scan the memory pool and identify the created but currently unused memory blocks */
+ Status = CFE_ES_RebuildCDSPool(CDS->DataSize, CDS_POOL_OFFSET);
+ }
+ else
+ {
+ /* Registry in CDS is unreadable */
+ CFE_ES_WriteToSysLog("CFE_CDS:Rebuild-Registry in CDS is unreadable, PSP error %lx\n", (unsigned long)Status);
+ Status = CFE_ES_CDS_INVALID;
+ }
+
+ return Status;
+}
+
+/*******************************************************************
+**
+** CFE_ES_DeleteCDS
+**
+** NOTE: For complete prolog information, see 'cfe_es_cds.h'
+********************************************************************/
+
+int32 CFE_ES_DeleteCDS(const char *CDSName, bool CalledByTblServices)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+ CFE_ES_CDS_RegRec_t * RegRecPtr;
+ char OwnerName[OS_MAX_API_NAME];
+ CFE_ES_AppId_t AppId;
+ uint32 i;
+ char LogMessage[CFE_ES_MAX_SYSLOG_MSG_SIZE];
+ size_t OldBlockSize;
+
+ LogMessage[0] = 0;
+
+ /* Lock Registry for update. This prevents two applications from */
+ /* trying to change the CDS registry at the same time */
+ CFE_ES_LockCDS();
+
+ /* Find CDS name in registry */
+ RegRecPtr = CFE_ES_LocateCDSBlockRecordByName(CDSName);
+
+ /* Check to see if CDS is already in the registry */
+ if (RegRecPtr != NULL)
+ {
+ /* Critical tables are not allowed to be deleted via an ES Command. */
+ /* They must be deleted by a Table Services Command */
+ if (RegRecPtr->Table != CalledByTblServices)
+ {
+ Status = CFE_ES_CDS_WRONG_TYPE_ERR;
+ }
+ else
+ {
+ /* Check to see if the owning application is still active */
+ /* First, extract the owning application name */
+ i = 0;
+ while ((i < (OS_MAX_API_NAME - 1) && (RegRecPtr->Name[i] != '.')))
+ {
+ OwnerName[i] = RegRecPtr->Name[i];
+ i++;
+ }
+
+ /* Null terminate the application name */
+ OwnerName[i] = '\0';
+
+ /* Check to see if the Application Name is in the Registered Apps list */
+ Status = CFE_ES_GetAppIDByName(&AppId, OwnerName);
+
+ /* If we can't find the name, then things are good */
+ if (Status != CFE_SUCCESS)
+ {
+ /* Free the registry entry and the CDS memory block associated with it */
+ Status = CFE_ES_GenPoolPutBlock(&CDS->Pool, &OldBlockSize, RegRecPtr->BlockOffset);
+
+ /* Report any errors incurred while freeing the CDS Memory Block */
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_SysLog_snprintf(
+ LogMessage, sizeof(LogMessage),
+ "CFE_ES:DeleteCDS-Failed to free CDS Mem Block (Handle=0x%08lX)(Stat=0x%08X)\n",
+ (unsigned long)RegRecPtr->BlockOffset, (unsigned int)Status);
+ }
+ else
+ {
+ /* Remove entry from the CDS Registry */
+ CFE_ES_CDSBlockRecordSetFree(RegRecPtr);
+
+ Status = CFE_ES_UpdateCDSRegistry();
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage),
+ "CFE_ES:DeleteCDS-Failed to update CDS Registry (Stat=0x%08X)\n",
+ (unsigned int)Status);
+ }
+ }
+ }
+ else
+ {
+ Status = CFE_ES_CDS_OWNER_ACTIVE_ERR;
+ }
+ }
+ }
+ else /* Error - CDS not in registry */
+ {
+ Status = CFE_ES_ERR_NAME_NOT_FOUND;
+ }
+
+ /* Unlock Registry for future updates */
+ CFE_ES_UnlockCDS();
+
+ /* Output the message to syslog once the CDS registry resource is unlocked */
+ if (LogMessage[0] != 0)
+ {
+ CFE_ES_SYSLOG_APPEND(LogMessage);
+ }
+
+ return Status;
+} /* End of CFE_ES_DeleteCDS() */
+
+/* end of file */
diff --git a/modules/es/fsw/src/cfe_es_cds.h b/modules/es/fsw/src/cfe_es_cds.h
new file mode 100644
index 000000000..0a952a58a
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_cds.h
@@ -0,0 +1,641 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * This file contains the Internal interface for the cFE Critical Data Store functions.
+ * These functions and data structures manage the Critical Data Store in the cFE.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_CDS_H
+#define CFE_ES_CDS_H
+
+/*
+** Include Files
+*/
+#include "common_types.h"
+#include "cfe_es_generic_pool.h"
+
+/*
+** Macro Definitions
+*/
+
+/** \name Registry Mutex Definitions */
+/** \{ */
+#define CFE_ES_CDS_MUT_REG_NAME "CDS_MUTEX" /**< \brief Name of Mutex controlling CDS Access */
+#define CFE_ES_CDS_MUT_REG_VALUE 0 /**< \brief Initial Value of CDS Access Mutex */
+/** \} */
+
+/** \name Registry Signature Definitions */
+/** \{ */
+#define CFE_ES_CDS_SIGNATURE_LEN 8 /**< \brief Length of CDS signature field. */
+#define CFE_ES_CDS_SIGNATURE_BEGIN "_CDSBeg_" /**< \brief Fixed signature at beginning of CDS */
+#define CFE_ES_CDS_SIGNATURE_END "_CDSEnd_" /**< \brief Fixed signature at end of CDS */
+/** \} */
+
+/*
+ * Space in CDS should be aligned to a multiple of uint32
+ * These helper macros round up to a whole number of words
+ */
+#define CDS_SIZE_TO_U32WORDS(x) (((x) + 3) / sizeof(uint32))
+#define CDS_RESERVE_SPACE(name, size) uint32 name[CDS_SIZE_TO_U32WORDS(size)]
+
+/* Define offset addresses for CDS data segments */
+#define CDS_SIG_BEGIN_OFFSET offsetof(CFE_ES_CDS_PersistentHeader_t, SignatureBegin)
+#define CDS_REG_SIZE_OFFSET offsetof(CFE_ES_CDS_PersistentHeader_t, RegistrySize)
+#define CDS_REG_OFFSET offsetof(CFE_ES_CDS_PersistentHeader_t, RegistryContent)
+#define CDS_POOL_OFFSET sizeof(CFE_ES_CDS_PersistentHeader_t)
+
+/*
+ * Absolute Minimum CDS size conceivably supportable by the implementation.
+ * This is the space required for the basic signatures and registry information.
+ * It is not possible to create a CDS with a storage area smaller than this.
+ */
+#define CDS_RESERVED_MIN_SIZE sizeof(CFE_ES_CDS_PersistentHeader_t) + sizeof(CFE_ES_CDS_PersistentTrailer_t)
+
+/*
+ * Absolute Maximum Block size conceivably supportable by the implementation.
+ * User-defined platform limits (in cfe_platform_cfg.h) may be lower,
+ * but this is a hard limit to avoid overflow of a 32 bit integer.
+ *
+ * This ensures the size is safe for a PSP that uses 32 bit CDS offsets.
+ * (It is not anticipated that a CDS would need to exceed this size)
+ */
+#define CDS_ABS_MAX_BLOCK_SIZE ((size_t)(1 << 30) - sizeof(CFE_ES_CDS_BlockHeader_t))
+
+/*
+** Type Definitions
+*/
+
+/**
+ * The structure cached in RAM for each block within the CDS non-volatile memory
+ * This has the basic runtime info without having to go to CDS.
+ */
+typedef struct
+{
+ /*
+ * Note that the block size and offset stored here are for the
+ * total block size. The CDS code adds is own extra metadata
+ * which has a CRC, and therefore the actual user data size is
+ * less than this.
+ */
+ CFE_ES_CDSHandle_t BlockID; /**< Abstract ID associated with this CDS block */
+ size_t BlockOffset; /**< Start offset of the block in CDS memory */
+ size_t BlockSize; /**< Size, in bytes, of the CDS memory block */
+ char Name[CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN];
+ bool Table; /**< \brief Flag that indicates whether CDS contains a Critical Table */
+} CFE_ES_CDS_RegRec_t;
+
+typedef struct CFE_ES_CDSBlockHeader
+{
+ uint32 Crc; /**< CRC of content */
+} CFE_ES_CDS_BlockHeader_t;
+
+/*
+ * A generic buffer to hold the various objects that need
+ * to be cached in RAM from the CDS non-volatile storage.
+ */
+typedef union CFE_ES_CDS_AccessCacheData
+{
+ char Sig[CFE_ES_CDS_SIGNATURE_LEN]; /**< A signature field (beginning or end) */
+ uint32 RegistrySize; /**< Registry Size Field */
+ uint32 Zero[4]; /**< Used when clearing CDS content */
+ CFE_ES_GenPoolBD_t Desc; /**< A generic block descriptor */
+ CFE_ES_CDS_BlockHeader_t BlockHeader; /**< A user block header */
+ CFE_ES_CDS_RegRec_t RegEntry; /**< A registry entry */
+} CFE_ES_CDS_AccessCacheData_t;
+
+typedef struct CFE_ES_CDS_AccessCache
+{
+ CFE_ES_CDS_AccessCacheData_t Data; /**< Cached data (varies in size) */
+ size_t Offset; /**< The offset where Data is cached from */
+ size_t Size; /**< The size of cached Data */
+ int32 AccessStatus; /**< The PSP status of the last read/write from CDS memory */
+} CFE_ES_CDS_AccessCache_t;
+
+/**
+ * Instance data associated with a CDS
+ *
+ * Currently there is just one global CDS instance (i.e. a singleton)
+ * stored in the CFE_ES_Global structure.
+ */
+typedef struct
+{
+ /*
+ * The generic pool structure
+ * This must be the first entry in this structure.
+ */
+ CFE_ES_GenPoolRecord_t Pool;
+
+ /*
+ * Cache of last accessed data block
+ * Because CDS memory is not memory mapped, this serves
+ * as temporary holding location for data being actively accessed.
+ */
+ CFE_ES_CDS_AccessCache_t Cache;
+
+ osal_id_t GenMutex; /**< \brief Mutex that controls access to CDS and registry */
+ size_t TotalSize; /**< \brief Total size of the CDS as reported by BSP */
+ size_t DataSize; /**< \brief Size of actual user data pool */
+ CFE_ResourceId_t LastCDSBlockId; /**< \brief Last issued CDS block ID */
+ CFE_ES_CDS_RegRec_t Registry[CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES]; /**< \brief CDS Registry (Local Copy) */
+} CFE_ES_CDS_Instance_t;
+
+/*
+ * structs representing the intended layout of data
+ * in the actual CDS/PSP-provided non-volatile memory
+ *
+ * All blocks should be multiples of uint32
+ *
+ * NOTE: these aren't necessarily instantiated in RAM,
+ * just in CDS. Mainly interested in the size of these
+ * elements, and offset of the various members within.
+ */
+typedef struct CFE_ES_CDS_PersistentHeader
+{
+ CDS_RESERVE_SPACE(SignatureBegin, CFE_ES_CDS_SIGNATURE_LEN);
+ CDS_RESERVE_SPACE(RegistrySize, sizeof(uint32));
+ CDS_RESERVE_SPACE(RegistryContent, CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES * sizeof(CFE_ES_CDS_RegRec_t));
+} CFE_ES_CDS_PersistentHeader_t;
+
+typedef struct CFE_ES_CDS_PersistentTrailer
+{
+ CDS_RESERVE_SPACE(SignatureEnd, CFE_ES_CDS_SIGNATURE_LEN);
+} CFE_ES_CDS_PersistentTrailer_t;
+
+/*****************************************************************************/
+/*
+** Function prototypes
+*/
+
+/**
+ * @brief Fetch data from the non-volatile storage and store in RAM cache
+ *
+ * This fetches a data segment from the PSP and loads it into the
+ * local CDS cache buffer. The content can be accessed via the
+ * "Data" member inside the cache structure.
+ *
+ * Only one thread can use CDS cache at a given time, so the CDS access
+ * control mutex must be obtained before calling this function.
+ *
+ * @param[inout] Cache the global CDS cache buffer
+ * @param[in] Offset the CDS offset to fetch
+ * @param[in] Size the CDS data size to fetch
+ * @returns #CFE_SUCCESS on success, or appropriate error code.
+ */
+int32 CFE_ES_CDS_CacheFetch(CFE_ES_CDS_AccessCache_t *Cache, size_t Offset, size_t Size);
+
+/**
+ * @brief Write data from the RAM cache back to non-volatile storage
+ *
+ * This stores a data segment from the cache into the PSP for
+ * permanent storage. Data should be loaded into the cache
+ * prior to invoking this function, either via CFE_ES_CDS_CacheFetch()
+ * or CFE_ES_CDS_CachePreload().
+ *
+ * Only one thread can use CDS cache at a given time, so the CDS access
+ * control mutex must be obtained before calling this function.
+ *
+ * @param[inout] Cache the global CDS cache buffer
+ * @returns #CFE_SUCCESS on success, or appropriate error code.
+ */
+int32 CFE_ES_CDS_CacheFlush(CFE_ES_CDS_AccessCache_t *Cache);
+
+/**
+ * @brief Preload the cache data from a local buffer
+ *
+ * This loads the CDS cache directly from a provided object/buffer to
+ * prepare for writing to PSP. The data can then be committed to PSP
+ * at a later time using CFE_ES_CDS_CacheFlush().
+ *
+ * If Source is NULL, then the cache data will be initialized to zero.
+ *
+ * If Source refers to the cache buffer, then no copying will take place, because
+ * source and destination are the same. No copy is performed, and the data will be
+ * unchanged. In this mode only the size and offset are updated.
+ *
+ * Only one thread can use CDS cache at a given time, so the CDS access
+ * control mutex must be obtained before calling this function.
+ *
+ * @param[inout] Cache the global CDS cache buffer
+ * @param[in] Source the local object to load into cache
+ * @param[in] Offset the CDS offset to fetch
+ * @param[in] Size the CDS data size to fetch
+ * @returns #CFE_SUCCESS on success, or appropriate error code.
+ */
+int32 CFE_ES_CDS_CachePreload(CFE_ES_CDS_AccessCache_t *Cache, const void *Source, size_t Offset, size_t Size);
+
+/**
+ * @brief Get the registry array index correlating with a CDS block ID
+ *
+ * Calculates the array position/index of the CDS registry entry for
+ * the given block ID.
+ *
+ * @param[in] BlockID the ID/handle of the CDS block to retrieve
+ * @param[out] Idx Output buffer to store the index
+ * @returns #CFE_SUCCESS if conversion successful. @copydoc CFE_SUCCESS
+ * #CFE_ES_ERR_RESOURCEID_NOT_VALID if block ID is outside valid range
+ */
+int32 CFE_ES_CDSHandle_ToIndex(CFE_ES_CDSHandle_t BlockID, uint32 *Idx);
+
+/**
+ * @brief Get a registry record within the CDS, given a block ID/handle
+ *
+ * Retrieves a pointer to the registry record associated with a CDS block ID/handle
+ * Returns NULL if the handle is outside the valid range
+ *
+ * @note This only does the lookup, it does not validate that the handle
+ * actually matches the returned record. The caller should lock the CDS and
+ * confirm that the record is a match to the expected ID before using it.
+ *
+ * @param[in] BlockID the ID/handle of the CDS block to retrieve
+ * @returns Pointer to registry record, or NULL if ID/handle invalid.
+ */
+CFE_ES_CDS_RegRec_t *CFE_ES_LocateCDSBlockRecordByID(CFE_ES_CDSHandle_t BlockID);
+
+/**
+ * @brief Check if a Memory Pool record is in use or free/empty
+ *
+ * This routine checks if the Pool table entry is in use or if it is free
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CDSBlockRecPtr pointer to Pool table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline bool CFE_ES_CDSBlockRecordIsUsed(const CFE_ES_CDS_RegRec_t *CDSBlockRecPtr)
+{
+ return CFE_RESOURCEID_TEST_DEFINED(CDSBlockRecPtr->BlockID);
+}
+
+/**
+ * @brief Get the ID value from a Memory Pool table entry
+ *
+ * This routine converts the table entry back to an abstract ID.
+ *
+ * @param[in] CDSBlockRecPtr pointer to Pool table entry
+ * @returns BlockID of entry
+ */
+static inline CFE_ES_CDSHandle_t CFE_ES_CDSBlockRecordGetID(const CFE_ES_CDS_RegRec_t *CDSBlockRecPtr)
+{
+ return (CDSBlockRecPtr->BlockID);
+}
+
+/**
+ * @brief Marks a Memory Pool table entry as used (not free)
+ *
+ * This sets the internal field(s) within this entry, and marks
+ * it as being associated with the given Pool ID.
+ *
+ * @param[in] CDSBlockRecPtr pointer to Pool table entry
+ * @param[in] PendingId the Pool ID of this entry
+ */
+static inline void CFE_ES_CDSBlockRecordSetUsed(CFE_ES_CDS_RegRec_t *CDSBlockRecPtr, CFE_ResourceId_t PendingId)
+{
+ CDSBlockRecPtr->BlockID = CFE_ES_CDSHANDLE_C(PendingId);
+}
+
+/**
+ * @brief Set a Memory Pool record table entry free (not used)
+ *
+ * This clears the internal field(s) within this entry, and allows the
+ * memory to be re-used in the future.
+ *
+ * @param[in] CDSBlockRecPtr pointer to Pool table entry
+ */
+static inline void CFE_ES_CDSBlockRecordSetFree(CFE_ES_CDS_RegRec_t *CDSBlockRecPtr)
+{
+ CDSBlockRecPtr->BlockID = CFE_ES_CDS_BAD_HANDLE;
+}
+
+/**
+ * @brief Check if a CDS block record is a match for the given BlockID
+ *
+ * This routine confirms that the previously-located record is valid
+ * and matches the expected block ID.
+ *
+ * As this dereferences fields within the record, CDS access mutex must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CDSBlockRecPtr pointer to registry table entry
+ * @param[in] BlockID expected block ID
+ * @returns true if the entry matches the given block ID
+ */
+static inline bool CFE_ES_CDSBlockRecordIsMatch(const CFE_ES_CDS_RegRec_t *CDSBlockRecPtr, CFE_ES_CDSHandle_t BlockID)
+{
+ return (CDSBlockRecPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(CDSBlockRecPtr->BlockID, BlockID));
+}
+
+/**
+ * @brief Gets the data size from a given registry record
+ *
+ * This computes the usable data size of the CDS registry entry
+ *
+ * As this dereferences fields within the record, CDS access mutex must be
+ * locked prior to invoking this function.
+ *
+ * @note CDS entries include an extra header in addition to the data,
+ * which contains error checking information. Therefore the usable data
+ * size is less than the raw block size.
+ *
+ * @param[in] CDSBlockRecPtr pointer to registry table entry
+ * @returns Usable size of the CDS
+ */
+static inline size_t CFE_ES_CDSBlockRecordGetUserSize(const CFE_ES_CDS_RegRec_t *CDSBlockRecPtr)
+{
+ return (CDSBlockRecPtr->BlockSize - sizeof(CFE_ES_CDS_BlockHeader_t));
+}
+
+/**
+ * @brief Check if a CDS Block ID table slot is used
+ *
+ * Checks if a table slot is available for a potential new ID
+ * This is a helper function intended to be used with
+ * CFE_ResourceId_FindNext() for allocating new IDs
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CheckId pending/candidate Block ID to check
+ * @returns true if the table slot for the ID is occupied, false if available
+ */
+bool CFE_ES_CheckCDSHandleSlotUsed(CFE_ResourceId_t CheckId);
+
+/*****************************************************************************/
+/**
+** \brief Initializes CDS data constructs
+**
+** \par Description
+** Locates and validates any pre-existing CDS memory or initializes the
+** memory as a fresh CDS.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \par SysLog Messages
+**
+** \return None
+**
+******************************************************************************/
+int32 CFE_ES_CDS_EarlyInit(void);
+
+/*****************************************************************************/
+/**
+** \brief Determines whether a CDS currently exists
+**
+** \par Description
+** Reads a set of bytes from the beginning and end of the CDS memory
+** area and determines if a fixed pattern is present, thus determining
+** whether the CDS still likely contains valid data or not.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return #CFE_ES_CDS_INVALID \copydoc CFE_ES_CDS_INVALID
+** \return Any of the return values from #CFE_PSP_ReadFromCDS
+**
+******************************************************************************/
+int32 CFE_ES_ValidateCDS(void);
+
+/*****************************************************************************/
+/**
+** \brief Initializes the CDS Registry
+**
+** \par Description
+** Initializes the data structure used to keep track of CDS blocks and
+** who they belong to.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \retval #CFE_SUCCESS \copydoc CFE_SUCCESS
+**
+******************************************************************************/
+int32 CFE_ES_InitCDSRegistry(void);
+
+/*****************************************************************************/
+/**
+** \brief Rebuilds memory pool for CDS and recovers existing registry
+**
+** \par Description
+** Scans memory for existing CDS and initializes memory pool and registry
+** settings accordingly
+**
+** \par Assumptions, External Events, and Notes:
+** -# Assumes the validity of the CDS has already been determined
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return Any of the return values from #CFE_PSP_ReadFromCDS
+**
+******************************************************************************/
+int32 CFE_ES_RebuildCDS(void);
+
+/*****************************************************************************/
+/**
+** \brief Copies the local version of the CDS Registry to the actual CDS
+**
+** \par Description
+** Copies the local working copy of the CDS Registry to the CDS.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return Any of the return values from #CFE_PSP_WriteToCDS
+**
+******************************************************************************/
+int32 CFE_ES_UpdateCDSRegistry(void);
+
+/*****************************************************************************/
+/**
+** \brief Creates a Full CDS name from application name and CDS name
+**
+** \par Description
+** Takes a given CDS Name and combines it with the calling
+** Application's name to make a processor specific name of the
+** form: "AppName.CDSName"
+**
+** \par Assumptions, External Events, and Notes:
+** Note: AppName portion will be truncated to OS_MAX_API_NAME.
+**
+** \param[in, out] FullCDSName pointer to character buffer of #CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN size
+** that will be filled with the processor specific CDS Name. *FullCDSName is the processor
+** specific CDS Name of the form "AppName.CDSName".
+**
+** \param[in] CDSName pointer to character string containing the Application's local name for
+** the CDS.
+**
+** \param[in] ThisAppId the Application ID of the Application making the call.
+**
+******************************************************************************/
+void CFE_ES_FormCDSName(char *FullCDSName, const char *CDSName, CFE_ES_AppId_t ThisAppId);
+
+/*****************************************************************************/
+/**
+** \brief Returns the Registry Record for the specified CDS Name
+**
+** \par Description
+** Locates given CDS Name in the CDS Registry and
+** returns the appropriate Registry Index.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] CDSName - Pointer to character string containing complete
+** CDS Name (of the format "AppName.CDSName").
+**
+** \retval NULL if not found, Non null entry pointer on success
+**
+******************************************************************************/
+CFE_ES_CDS_RegRec_t *CFE_ES_LocateCDSBlockRecordByName(const char *CDSName);
+
+/*****************************************************************************/
+/**
+** \brief Locks access to the CDS
+**
+** \par Description
+** Locks the CDS to prevent multiple tasks/threads
+** from modifying it at once.
+**
+** This lock covers both the registry and the data access.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \retval #CFE_SUCCESS \copydoc CFE_SUCCESS
+******************************************************************************/
+int32 CFE_ES_LockCDS(void);
+
+/*****************************************************************************/
+/**
+** \brief Unlocks access to the CDS
+**
+** \par Description
+** Unlocks CDS to allow other tasks/threads to
+** modify the CDS contents.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \retval #CFE_SUCCESS \copydoc CFE_SUCCESS
+**
+******************************************************************************/
+int32 CFE_ES_UnlockCDS(void);
+
+/*****************************************************************************/
+/**
+** \brief Rebuilds memory pool for CDS and recovers existing registry
+**
+** \par Description
+** Scans memory for existing CDS and initializes memory pool and registry
+** settings accordingly
+**
+** \par Assumptions, External Events, and Notes:
+** -# Assumes the validity of the CDS has already been determined
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return Any of the return values from #CFE_PSP_ReadFromCDS
+**
+******************************************************************************/
+int32 CFE_ES_RebuildCDS(void);
+
+/*****************************************************************************/
+/**
+** \brief Initializes the CDS Registry
+**
+** \par Description
+** Initializes the data structure used to keep track of CDS blocks and
+** who they belong to.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \retval #CFE_SUCCESS \copydoc CFE_SUCCESS
+**
+******************************************************************************/
+int32 CFE_ES_InitCDSRegistry(void);
+
+/*****************************************************************************/
+/**
+** \brief Determines whether a CDS currently exists
+**
+** \par Description
+** Reads a set of bytes from the beginning and end of the CDS memory
+** area and determines if a fixed pattern is present, thus determining
+** whether the CDS still likely contains valid data or not.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return #CFE_ES_CDS_INVALID \copydoc CFE_ES_CDS_INVALID
+** \return Any of the return values from #CFE_PSP_ReadFromCDS
+**
+******************************************************************************/
+int32 CFE_ES_ValidateCDS(void);
+
+/*****************************************************************************/
+/**
+** \brief Clears the contents of the CDS
+**
+** \par Description
+** Writes zeros to the entire CDS storage area
+**
+** This prevents any stale data that may exist in the
+** memory area from being potentially interpreted as valid
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return Any of the return values from #CFE_ES_CDS_CacheFlush
+**
+******************************************************************************/
+int32 CFE_ES_ClearCDS(void);
+
+/*****************************************************************************/
+/**
+** \brief Initializes the signatures of the CDS area
+**
+** \par Description
+** Stores a fixed pattern at the beginning and end of the CDS memory
+** to tag it for future verification following a reset.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+** \return Any of the return values from #CFE_ES_CDS_CacheFlush
+**
+******************************************************************************/
+int32 CFE_ES_InitCDSSignatures(void);
+
+#endif /* CFE_ES_CDS_H */
diff --git a/modules/es/fsw/src/cfe_es_cds_mempool.c b/modules/es/fsw/src/cfe_es_cds_mempool.c
new file mode 100644
index 000000000..4f02386fc
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_cds_mempool.c
@@ -0,0 +1,371 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_cds_mempool.c
+**
+** Purpose:
+** Set of services for management of the CDS discrete sized memory pools.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+*/
+
+/*
+** Includes
+*/
+#include
+#include
+#include
+
+#include "cfe_es_module_all.h"
+
+/*****************************************************************************/
+/*
+** Type Definitions
+*/
+
+/*****************************************************************************/
+/*
+** File Global Data
+*/
+
+const size_t CFE_ES_CDSMemPoolDefSize[CFE_ES_CDS_NUM_BLOCK_SIZES] = {
+ CFE_PLATFORM_ES_CDS_MAX_BLOCK_SIZE, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_16, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_15,
+ CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_14, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_13, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_12,
+ CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_11, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_10, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_09,
+ CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_08, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_07, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_06,
+ CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_05, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_04, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_03,
+ CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_02, CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_01};
+
+/*****************************************************************************/
+/*
+** Functions
+*/
+
+/*
+** CFE_ES_CDS_PoolRetrieve will obtain a block descriptor from CDS storage.
+**
+** This is a bridge between the generic pool implementation and the CDS cache.
+*/
+int32 CFE_ES_CDS_PoolRetrieve(CFE_ES_GenPoolRecord_t *GenPoolRecPtr, size_t Offset, CFE_ES_GenPoolBD_t **BdPtr)
+{
+ CFE_ES_CDS_Instance_t *CDS = (CFE_ES_CDS_Instance_t *)GenPoolRecPtr;
+
+ *BdPtr = &CDS->Cache.Data.Desc;
+
+ return CFE_ES_CDS_CacheFetch(&CDS->Cache, Offset, sizeof(CFE_ES_GenPoolBD_t));
+}
+
+/*
+** CFE_ES_CDS_PoolCommit will write a block descriptor to CDS storage.
+**
+** This is a bridge between the generic pool implementation and the CDS cache.
+*/
+int32 CFE_ES_CDS_PoolCommit(CFE_ES_GenPoolRecord_t *GenPoolRecPtr, size_t Offset, const CFE_ES_GenPoolBD_t *BdPtr)
+{
+ CFE_ES_CDS_Instance_t *CDS = (CFE_ES_CDS_Instance_t *)GenPoolRecPtr;
+
+ CFE_ES_CDS_CachePreload(&CDS->Cache, BdPtr, Offset, sizeof(CFE_ES_GenPoolBD_t));
+
+ return CFE_ES_CDS_CacheFlush(&CDS->Cache);
+}
+
+/*
+** CFE_ES_CreateCDSPool will initialize a pre-allocated memory pool.
+**
+** NOTE:
+** This function is only ever called during "Early Init" phase,
+** where it is not possible to have contention writing into the syslog.
+** Therefore the use of CFE_ES_SysLogWrite_Unsync() is acceptable
+*/
+int32 CFE_ES_CreateCDSPool(size_t CDSPoolSize, size_t StartOffset)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+ size_t SizeCheck;
+ size_t ActualSize;
+
+ SizeCheck = CFE_ES_GenPoolCalcMinSize(CFE_ES_CDS_NUM_BLOCK_SIZES, CFE_ES_CDSMemPoolDefSize, 1);
+ ActualSize = CDSPoolSize;
+
+ if (ActualSize < SizeCheck)
+ {
+ /* Must be able make Pool verification, block descriptor and at least one of the smallest blocks */
+ CFE_ES_SysLogWrite_Unsync("CFE_ES:CreateCDSPool-Pool size(%lu) too small for one CDS Block, need >=%lu\n",
+ (unsigned long)ActualSize, (unsigned long)SizeCheck);
+ return CFE_ES_CDS_INVALID_SIZE;
+ }
+
+ Status = CFE_ES_GenPoolInitialize(&CDS->Pool, StartOffset, /* starting offset */
+ ActualSize, /* total size */
+ 4, /* alignment */
+ CFE_ES_CDS_NUM_BLOCK_SIZES, CFE_ES_CDSMemPoolDefSize, CFE_ES_CDS_PoolRetrieve,
+ CFE_ES_CDS_PoolCommit);
+
+ return Status;
+}
+
+/*
+** Function:
+** CFE_ES_RebuildCDSPool
+**
+** Purpose:
+**
+** NOTE:
+** This function is only ever called during "Early Init" phase,
+** where it is not possible to have contention writing into the syslog.
+** Therefore the use of CFE_ES_SysLogWrite_Unsync() is acceptable
+*/
+int32 CFE_ES_RebuildCDSPool(size_t CDSPoolSize, size_t StartOffset)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ int32 Status;
+
+ /*
+ * Start by creating the pool in a clean state, as it would be in a non-rebuild.
+ */
+ Status = CFE_ES_CreateCDSPool(CDSPoolSize, StartOffset);
+ if (Status != CFE_SUCCESS)
+ {
+ return Status;
+ }
+
+ /* Now walk through the CDS memory and attempt to recover existing CDS blocks */
+ Status = CFE_ES_GenPoolRebuild(&CDS->Pool);
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_SysLogWrite_Unsync("CFE_ES:RebuildCDS-Err rebuilding CDS (Stat=0x%08x)\n", (unsigned int)Status);
+ Status = CFE_ES_CDS_ACCESS_ERROR;
+ }
+
+ return Status;
+}
+
+/*
+** Function:
+** CFE_ES_CDSBlockWrite
+**
+** Purpose:
+**
+*/
+int32 CFE_ES_CDSBlockWrite(CFE_ES_CDSHandle_t Handle, const void *DataToWrite)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ char LogMessage[CFE_ES_MAX_SYSLOG_MSG_SIZE];
+ int32 Status;
+ size_t BlockSize;
+ size_t UserDataSize;
+ size_t UserDataOffset;
+ CFE_ES_CDS_RegRec_t * CDSRegRecPtr;
+
+ /* Ensure the the log message is an empty string in case it is never written to */
+ LogMessage[0] = 0;
+
+ CDSRegRecPtr = CFE_ES_LocateCDSBlockRecordByID(Handle);
+
+ /*
+ * A CDS block ID must be accessed by only one thread at a time.
+ * Checking the validity of the block requires access to the registry.
+ */
+ CFE_ES_LockCDS();
+
+ if (CFE_ES_CDSBlockRecordIsMatch(CDSRegRecPtr, Handle))
+ {
+ /*
+ * Getting the buffer size via this function retrieves it from the
+ * internal descriptor, and validates the descriptor as part of the operation.
+ * This should always agree with the size in the registry for this block.
+ */
+ Status = CFE_ES_GenPoolGetBlockSize(&CDS->Pool, &BlockSize, CDSRegRecPtr->BlockOffset);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage),
+ "CFE_ES:CDSBlkWrite-Invalid Handle or Block Descriptor.\n");
+ }
+ else if (BlockSize <= sizeof(CFE_ES_CDS_BlockHeader_t) || BlockSize != CDSRegRecPtr->BlockSize)
+ {
+ CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage),
+ "CFE_ES:CDSBlkWrite-Block size %lu invalid, expected %lu\n",
+ (unsigned long)BlockSize, (unsigned long)CDSRegRecPtr->BlockSize);
+ Status = CFE_ES_CDS_INVALID_SIZE;
+ }
+ else
+ {
+ UserDataSize = CDSRegRecPtr->BlockSize;
+ UserDataSize -= sizeof(CFE_ES_CDS_BlockHeader_t);
+ UserDataOffset = CDSRegRecPtr->BlockOffset;
+ UserDataOffset += sizeof(CFE_ES_CDS_BlockHeader_t);
+
+ CDS->Cache.Data.BlockHeader.Crc =
+ CFE_ES_CalculateCRC(DataToWrite, UserDataSize, 0, CFE_MISSION_ES_DEFAULT_CRC);
+ CDS->Cache.Offset = CDSRegRecPtr->BlockOffset;
+ CDS->Cache.Size = sizeof(CFE_ES_CDS_BlockHeader_t);
+
+ /* Write the new block descriptor for the data coming from the Application */
+ Status = CFE_ES_CDS_CacheFlush(&CDS->Cache);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_SysLog_snprintf(
+ LogMessage, sizeof(LogMessage),
+ "CFE_ES:CDSBlkWrite-Err writing header data to CDS (Stat=0x%08x) @Offset=0x%08lx\n",
+ (unsigned int)CDS->Cache.AccessStatus, (unsigned long)CDSRegRecPtr->BlockOffset);
+ }
+ else
+ {
+ Status = CFE_PSP_WriteToCDS(DataToWrite, UserDataOffset, UserDataSize);
+ if (Status != CFE_PSP_SUCCESS)
+ {
+ CFE_ES_SysLog_snprintf(
+ LogMessage, sizeof(LogMessage),
+ "CFE_ES:CDSBlkWrite-Err writing user data to CDS (Stat=0x%08x) @Offset=0x%08lx\n",
+ (unsigned int)Status, (unsigned long)UserDataOffset);
+ }
+ }
+ }
+ }
+ else
+ {
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockCDS();
+
+ /* Do the actual syslog if something went wrong */
+ if (LogMessage[0] != 0)
+ {
+ CFE_ES_SYSLOG_APPEND(LogMessage);
+ }
+
+ return Status;
+}
+
+/*
+** Function:
+** CFE_ES_CDSBlockRead
+**
+** Purpose:
+**
+*/
+int32 CFE_ES_CDSBlockRead(void *DataRead, CFE_ES_CDSHandle_t Handle)
+{
+ CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars;
+ char LogMessage[CFE_ES_MAX_SYSLOG_MSG_SIZE];
+ int32 Status;
+ uint32 CrcOfCDSData;
+ size_t BlockSize;
+ size_t UserDataSize;
+ size_t UserDataOffset;
+ CFE_ES_CDS_RegRec_t * CDSRegRecPtr;
+
+ /* Validate the handle before doing anything */
+ LogMessage[0] = 0;
+
+ CDSRegRecPtr = CFE_ES_LocateCDSBlockRecordByID(Handle);
+
+ /*
+ * A CDS block ID must be accessed by only one thread at a time.
+ * Checking the validity of the block requires access to the registry.
+ */
+ CFE_ES_LockCDS();
+
+ if (CFE_ES_CDSBlockRecordIsMatch(CDSRegRecPtr, Handle))
+ {
+ /*
+ * Getting the buffer size via this function retrieves it from the
+ * internal descriptor, and validates the descriptor as part of the operation.
+ * This should always agree with the size in the registry for this block.
+ */
+ Status = CFE_ES_GenPoolGetBlockSize(&CDS->Pool, &BlockSize, CDSRegRecPtr->BlockOffset);
+ if (Status == CFE_SUCCESS)
+ {
+ if (BlockSize <= sizeof(CFE_ES_CDS_BlockHeader_t) || BlockSize != CDSRegRecPtr->BlockSize)
+ {
+ Status = CFE_ES_CDS_INVALID_SIZE;
+ }
+ else
+ {
+ UserDataSize = CDSRegRecPtr->BlockSize;
+ UserDataSize -= sizeof(CFE_ES_CDS_BlockHeader_t);
+ UserDataOffset = CDSRegRecPtr->BlockOffset;
+ UserDataOffset += sizeof(CFE_ES_CDS_BlockHeader_t);
+
+ /* Read the header */
+ Status =
+ CFE_ES_CDS_CacheFetch(&CDS->Cache, CDSRegRecPtr->BlockOffset, sizeof(CFE_ES_CDS_BlockHeader_t));
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* Read the data block */
+ Status = CFE_PSP_ReadFromCDS(DataRead, UserDataOffset, UserDataSize);
+ if (Status == CFE_PSP_SUCCESS)
+ {
+ /* Compute the CRC for the data read from the CDS and determine if the data is still valid */
+ CrcOfCDSData = CFE_ES_CalculateCRC(DataRead, UserDataSize, 0, CFE_MISSION_ES_DEFAULT_CRC);
+
+ /* If the CRCs do not match, report an error */
+ if (CrcOfCDSData != CDS->Cache.Data.BlockHeader.Crc)
+ {
+ Status = CFE_ES_CDS_BLOCK_CRC_ERR;
+ }
+ else
+ {
+ Status = CFE_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockCDS();
+
+ /* Do the actual syslog if something went wrong */
+ if (LogMessage[0] != 0)
+ {
+ CFE_ES_SYSLOG_APPEND(LogMessage);
+ }
+
+ return Status;
+}
+
+/*
+** Function:
+** CFE_ES_CDSReqdMinSize
+**
+** Purpose:
+**
+*/
+size_t CFE_ES_CDSReqdMinSize(uint32 MaxNumBlocksToSupport)
+{
+ size_t ReqSize;
+
+ ReqSize = CFE_ES_GenPoolCalcMinSize(CFE_ES_CDS_NUM_BLOCK_SIZES, CFE_ES_CDSMemPoolDefSize, MaxNumBlocksToSupport);
+
+ return ReqSize;
+}
diff --git a/modules/es/fsw/src/cfe_es_cds_mempool.h b/modules/es/fsw/src/cfe_es_cds_mempool.h
new file mode 100644
index 000000000..696fca5d1
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_cds_mempool.h
@@ -0,0 +1,78 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * This file contains the Internal interface for the cFE Critical Data Store
+ * memory pool functions.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_CDS_MEMPOOL_H
+#define CFE_ES_CDS_MEMPOOL_H
+
+/*
+** Include Files
+*/
+#include "cfe_es_cds.h"
+
+/*
+** Macro Definitions
+*/
+#define CFE_ES_CDS_NUM_BLOCK_SIZES 17
+
+/*****************************************************************************/
+/*
+** Function prototypes
+*/
+
+/*****************************************************************************/
+/**
+** \brief Creates a CDS memory pool from scratch
+**
+** \par Description
+** Creates a memory pool of the specified size starting at the specified
+** offset into the CDS memory.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return #CFE_SUCCESS \copydoc CFE_SUCCESS
+**
+******************************************************************************/
+int32 CFE_ES_CreateCDSPool(size_t CDSPoolSize, size_t StartOffset);
+
+int32 CFE_ES_RebuildCDSPool(size_t CDSPoolSize, size_t StartOffset);
+
+int32 CFE_ES_CDSBlockWrite(CFE_ES_CDSHandle_t Handle, const void *DataToWrite);
+
+int32 CFE_ES_CDSBlockRead(void *DataRead, CFE_ES_CDSHandle_t Handle);
+
+size_t CFE_ES_CDSReqdMinSize(uint32 MaxNumBlocksToSupport);
+
+#endif /* CFE_ES_CDS_MEMPOOL_H */
diff --git a/modules/es/fsw/src/cfe_es_erlog.c b/modules/es/fsw/src/cfe_es_erlog.c
new file mode 100644
index 000000000..7370df0bd
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_erlog.c
@@ -0,0 +1,430 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_erlog.c
+**
+** Purpose:
+** This file implements the cFE Executive Services Exception and Reset Log functions.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+** Notes:
+**
+** Modification History:
+**
+*/
+
+/*
+** Required header files.
+*/
+#include "cfe_es_module_all.h"
+
+#include
+#include
+#include
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/*
+** Function: CFE_ES_WriteToERLogWithContext
+**
+** Purpose: Create an entry in the ES Exception and Reset Log.
+** This log API accepts extra context information (AppID and ContextID)
+** and is used when the app/task invoking this API is not the same app
+** as where the event occurred.
+**
+*/
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_ES_WriteToERLogWithContext(CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype,
+ const char *Description, CFE_ES_AppId_t AppId, uint32 PspContextId)
+{
+ uint32 LogIdx;
+ CFE_ES_ERLog_MetaData_t *EntryPtr;
+ CFE_TIME_SysTime_t PendingTime;
+
+ /*
+ * Snapshot the time before locking (different subsystem)
+ */
+ PendingTime = CFE_TIME_GetTime();
+
+ /*
+ * Ensure that description string is not NULL.
+ */
+ if (Description == NULL)
+ {
+ Description = "No Description String Given.";
+ }
+
+ /*
+ * This routine needs to lock in case it is called
+ * from concurrent threads
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /*
+ ** Try to clean up an invalid ER log index variable.
+ */
+ if (CFE_ES_Global.ResetDataPtr->ERLogIndex >= CFE_PLATFORM_ES_ER_LOG_ENTRIES)
+ {
+ CFE_ES_Global.ResetDataPtr->ERLogIndex = 0;
+ }
+ LogIdx = CFE_ES_Global.ResetDataPtr->ERLogIndex;
+
+ /*
+ ** Now that the Local Index variable is set, increment the index for the next entry.
+ */
+ CFE_ES_Global.ResetDataPtr->ERLogIndex++;
+ if (CFE_ES_Global.ResetDataPtr->ERLogIndex >= CFE_PLATFORM_ES_ER_LOG_ENTRIES)
+ {
+ CFE_ES_Global.ResetDataPtr->ERLogIndex = 0;
+ }
+
+ /*
+ ** Clear out the log entry we are about to use.
+ */
+ EntryPtr = &CFE_ES_Global.ResetDataPtr->ERLog[LogIdx];
+ memset(EntryPtr, 0, sizeof(*EntryPtr));
+
+ /*
+ ** Fill out the log fields
+ */
+ EntryPtr->BaseInfo.LogEntryType = EntryType;
+ EntryPtr->BaseInfo.ResetType = ResetType;
+ EntryPtr->BaseInfo.ResetSubtype = ResetSubtype;
+ EntryPtr->BaseInfo.BootSource = CFE_ES_Global.ResetDataPtr->ResetVars.BootSource;
+ EntryPtr->BaseInfo.ProcessorResetCount = CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount;
+ EntryPtr->BaseInfo.MaxProcessorResetCount = CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount;
+
+ /*
+ ** Copy the ES Reset variables to the log (before they are modified by the log entry).
+ */
+ memcpy(&EntryPtr->BaseInfo.DebugVars, &CFE_ES_Global.DebugVars, sizeof(EntryPtr->BaseInfo.DebugVars));
+
+ /*
+ ** Time Stamp the log entry with the system time
+ */
+ EntryPtr->BaseInfo.TimeCode = PendingTime;
+
+ /*
+ ** Copy the Description string to the log.
+ */
+ strncpy(EntryPtr->BaseInfo.Description, Description, sizeof(EntryPtr->BaseInfo.Description) - 1);
+ EntryPtr->BaseInfo.Description[sizeof(EntryPtr->BaseInfo.Description) - 1] = '\0';
+
+ /*
+ * Store the context info (if any)
+ */
+ EntryPtr->AppID = AppId;
+ EntryPtr->PspContextId = PspContextId;
+
+ /*
+ ** Increment the number of ER log entries made
+ */
+ CFE_ES_Global.ResetDataPtr->ERLogEntries++;
+
+ /*
+ * Shared data update is complete
+ */
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ return (CFE_SUCCESS);
+
+} /* End of CFE_ES_WriteToERLogWithContext() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/*
+** Function: CFE_ES_WriteToERLog
+**
+** Purpose: Create an entry in the ES Exception and Reset Log.
+** This log API is simplified for cases which do not have a separate context
+**
+*/
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_ES_WriteToERLog(CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype,
+ const char *Description)
+{
+ /* passing 0xFFFFFFFF as the appid avoids confusion with actual appid 0 */
+ return CFE_ES_WriteToERLogWithContext(EntryType, ResetType, ResetSubtype, Description, CFE_ES_APPID_UNDEFINED,
+ CFE_ES_ERLOG_NO_CONTEXT);
+
+} /* End of CFE_ES_WriteToERLog() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Function: CFE_ES_BackgroundERLogFileDataGetter() */
+/* */
+/* Purpose: */
+/* Gets a single record from exception & reset log to write to a file. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+bool CFE_ES_BackgroundERLogFileDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize)
+{
+ CFE_ES_BackgroundLogDumpGlobal_t *BgFilePtr;
+ CFE_ES_ERLog_FileEntry_t * FileBufferPtr;
+ CFE_ES_ERLog_MetaData_t * EntryPtr;
+ int32 PspStatus;
+
+ BgFilePtr = (CFE_ES_BackgroundLogDumpGlobal_t *)Meta;
+ FileBufferPtr = &BgFilePtr->EntryBuffer;
+
+ if (RecordNum < CFE_PLATFORM_ES_ER_LOG_ENTRIES)
+ {
+ EntryPtr = &CFE_ES_Global.ResetDataPtr->ERLog[RecordNum];
+
+ /* First wipe the buffer before re-use */
+ memset(FileBufferPtr, 0, sizeof(*FileBufferPtr));
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /* The basic info comes directly from the ES log */
+ FileBufferPtr->BaseInfo = EntryPtr->BaseInfo;
+
+ /*
+ * The context info, if available, comes from the PSP.
+ * This returns the actual size of the context info, or <0 on error.
+ */
+ PspStatus = CFE_PSP_Exception_CopyContext(EntryPtr->PspContextId, &FileBufferPtr->Context,
+ sizeof(FileBufferPtr->Context));
+ if (PspStatus > 0)
+ {
+ FileBufferPtr->ContextSize = PspStatus;
+ }
+ else
+ {
+ /*
+ * errors here are OK - just means there is no context available.
+ * Record a size of 0 in the log file.
+ */
+ FileBufferPtr->ContextSize = 0;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * Export data to caller for actual write
+ */
+ *Buffer = FileBufferPtr;
+ *BufSize = sizeof(*FileBufferPtr);
+ }
+ else
+ {
+ *Buffer = NULL;
+ *BufSize = 0;
+ }
+
+ /* Check for EOF (last entry) */
+ return (RecordNum >= (CFE_PLATFORM_ES_ER_LOG_ENTRIES - 1));
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Function: CFE_ER_BackgroundERLogFileEventHandler() */
+/* */
+/* Purpose: */
+/* Report events during writing exception & reset log to a file. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void CFE_ES_BackgroundERLogFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum,
+ size_t BlockSize, size_t Position)
+{
+ CFE_ES_BackgroundLogDumpGlobal_t *BgFilePtr;
+
+ BgFilePtr = (CFE_ES_BackgroundLogDumpGlobal_t *)Meta;
+
+ /*
+ * Note that this runs in the context of ES background task (file writer background job)
+ * It does NOT run in the context of the CFE_TBL app task.
+ *
+ * Events should use CFE_EVS_SendEventWithAppID() rather than CFE_EVS_SendEvent()
+ * to get proper association with TBL task.
+ */
+ switch (Event)
+ {
+ case CFE_FS_FileWriteEvent_COMPLETE:
+ CFE_EVS_SendEvent(CFE_ES_ERLOG2_EID, CFE_EVS_EventType_DEBUG, "%s written:Size=%lu",
+ BgFilePtr->FileWrite.FileName, (unsigned long)Position);
+ break;
+
+ case CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR:
+ case CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR:
+ CFE_EVS_SendEvent(CFE_ES_FILEWRITE_ERR_EID, CFE_EVS_EventType_ERROR,
+ "File write,byte cnt err,file %s,request=%u,actual=%u", BgFilePtr->FileWrite.FileName,
+ (int)BlockSize, (int)Status);
+ break;
+
+ case CFE_FS_FileWriteEvent_CREATE_ERROR:
+ CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID, CFE_EVS_EventType_ERROR, "Error creating file %s, RC = %d",
+ BgFilePtr->FileWrite.FileName, (int)Status);
+ break;
+
+ default:
+ /* unhandled event - ignore */
+ break;
+ }
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_RunExceptionScan
+**
+** Purpose: This function pools the PSP to check if any exceptions have been logged
+** since the last background cycle. If an exception is present, retreive
+** the details, add it to the ER log, and trigger the action (e.g. app restart).
+**---------------------------------------------------------------------------------------
+*/
+bool CFE_ES_RunExceptionScan(uint32 ElapsedTime, void *Arg)
+{
+ int32 Status;
+ uint32 PspContextId;
+ char ReasonString[CFE_ES_ERLOG_DESCRIPTION_MAX_LENGTH];
+ CFE_ES_TaskInfo_t EsTaskInfo;
+ osal_id_t ExceptionTaskID;
+ uint32 ResetType;
+ CFE_ES_LogEntryType_Enum_t LogType;
+ CFE_ES_AppRecord_t * AppRecPtr;
+
+ if (CFE_PSP_Exception_GetCount() == 0)
+ {
+ /* no exceptions pending, nothing to do */
+ return false;
+ }
+
+ /*
+ * Note a reset type of 0 is not defined by the PSP -
+ * the real values are all nonzero
+ */
+ ResetType = 0;
+ memset(&EsTaskInfo, 0, sizeof(EsTaskInfo));
+ Status = CFE_PSP_Exception_GetSummary(&PspContextId, &ExceptionTaskID, ReasonString, sizeof(ReasonString));
+ if (Status != CFE_PSP_SUCCESS)
+ {
+ /* reason string is not available - populate with something for the log */
+ snprintf(ReasonString, sizeof(ReasonString), "Unknown - CFE_PSP_ExceptionGetSummary() error %ld", (long)Status);
+ PspContextId = 0;
+ ExceptionTaskID = OS_OBJECT_ID_UNDEFINED;
+ } /* end if */
+
+ /*
+ * Note that writes to the ES ER log actually do not get propagated to the debug console.
+ * so by writing to SysLog here it becomes visible in both places.
+ */
+ CFE_ES_WriteToSysLog("ExceptionID 0x%lx in TaskID %lu: %s\n", (unsigned long)PspContextId,
+ OS_ObjectIdToInteger(ExceptionTaskID), ReasonString);
+
+ /*
+ * If task ID is 0, this means it was a system level exception and
+ * not associated with a specific task.
+ *
+ * Otherwise, if it was related to a task, determine the associated AppID
+ * so the exception action can be checked.
+ */
+ if (OS_ObjectIdDefined(ExceptionTaskID))
+ {
+ Status = CFE_ES_GetTaskInfo(&EsTaskInfo, CFE_ES_TaskId_FromOSAL(ExceptionTaskID));
+
+ /*
+ * The App ID was found, now see if the ExceptionAction is set for a reset
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ AppRecPtr = CFE_ES_LocateAppRecordByID(EsTaskInfo.AppId);
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ if (CFE_ES_AppRecordIsMatch(AppRecPtr, EsTaskInfo.AppId) &&
+ AppRecPtr->StartParams.ExceptionAction == CFE_ES_ExceptionAction_RESTART_APP)
+ {
+ /*
+ * Log the Application reset
+ */
+ ResetType = CFE_ES_APP_RESTART;
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+ }
+ }
+
+ do
+ {
+ /*
+ * If no disposition is identified yet, then trigger a PSP reset.
+ * Need to determine if a processor or poweron reset is needed.
+ */
+ if (ResetType == 0)
+ {
+ if (CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount >=
+ CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount)
+ {
+ CFE_ES_WriteToSysLog("Maximum Processor Reset count reached (%u)",
+ (unsigned int)CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount);
+
+ ResetType = CFE_PSP_RST_TYPE_POWERON;
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("Processor Reset count not reached (%u/%u)",
+ (unsigned int)CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount,
+ (unsigned int)CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount);
+
+ /*
+ ** Update the reset variables
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount++;
+ CFE_ES_Global.ResetDataPtr->ResetVars.ES_CausedReset = true;
+
+ ResetType = CFE_PSP_RST_TYPE_PROCESSOR;
+ }
+ }
+
+ if (ResetType == CFE_ES_APP_RESTART)
+ {
+ LogType = CFE_ES_LogEntryType_APPLICATION;
+ }
+ else
+ {
+ LogType = CFE_ES_LogEntryType_CORE;
+ }
+
+ CFE_ES_WriteToERLogWithContext(LogType, ResetType, CFE_PSP_RST_SUBTYPE_EXCEPTION, ReasonString,
+ EsTaskInfo.AppId, PspContextId);
+
+ if (ResetType == CFE_ES_APP_RESTART)
+ {
+ /*
+ * Restart the App. This call is just a request
+ * to ES, but the request could fail. If that happens,
+ * proceed to a processor reset.
+ */
+ Status = CFE_ES_RestartApp(EsTaskInfo.AppId);
+ if (Status != CFE_SUCCESS)
+ {
+ ResetType = 0;
+ snprintf(ReasonString, sizeof(ReasonString), "App Restart Failed");
+ }
+ }
+ else
+ {
+ /* normally this will not return */
+ CFE_PSP_Restart(ResetType);
+ }
+ } while (ResetType == 0);
+
+ return true; /* returning true because there was an exception to deal with */
+}
+
+/* end of file */
diff --git a/modules/es/fsw/src/cfe_es_generic_pool.c b/modules/es/fsw/src/cfe_es_generic_pool.c
new file mode 100644
index 000000000..742c4da43
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_generic_pool.c
@@ -0,0 +1,676 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_generic_pool.c
+**
+** Purpose:
+** Set of services for management of discrete sized memory pools.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+*/
+
+/*
+** Includes
+*/
+#include "cfe_es_module_all.h"
+
+#include
+#include
+#include
+
+/*****************************************************************************/
+/*
+** Functions
+*/
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolFindBucket
+**
+** Local Helper function to find the appropriate bucket given a requested block size
+**---------------------------------------------------------------------------------------
+*/
+uint16 CFE_ES_GenPoolFindBucket(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t ReqSize)
+{
+ uint16 Index;
+
+ for (Index = 0; Index < PoolRecPtr->NumBuckets; ++Index)
+ {
+ if (ReqSize <= PoolRecPtr->Buckets[Index].BlockSize)
+ {
+ /* it fits - stop here */
+ break;
+ }
+ }
+
+ /*
+ * Invert output such that if a bucket wasn't found, this
+ * will return 0. A valid bucket ID will be nonzero.
+ */
+ return (PoolRecPtr->NumBuckets - Index);
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolGetBucketState
+**
+** Local Helper function to obtain the structure associated with a given bucket ID.
+**---------------------------------------------------------------------------------------
+*/
+CFE_ES_GenPoolBucket_t *CFE_ES_GenPoolGetBucketState(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId)
+{
+ uint16 Index;
+
+ Index = PoolRecPtr->NumBuckets - BucketId;
+ if (Index >= PoolRecPtr->NumBuckets)
+ {
+ return NULL;
+ }
+
+ return &PoolRecPtr->Buckets[Index];
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolRecyclePoolBlock
+**
+** Local helper function to find and re-allocate a previously returned block
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GenPoolRecyclePoolBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId, size_t NewSize,
+ size_t *BlockOffsetPtr)
+{
+ CFE_ES_GenPoolBucket_t *BucketPtr;
+ size_t DescOffset;
+ size_t BlockOffset;
+ size_t NextOffset;
+ CFE_ES_GenPoolBD_t * BdPtr;
+ uint16 RecycleBucketId;
+ int32 Status;
+
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+ if (BucketPtr == NULL || BucketPtr->RecycleCount == BucketPtr->ReleaseCount || BucketPtr->FirstOffset == 0)
+ {
+ /* no buffers in pool to recycle */
+ return CFE_ES_BUFFER_NOT_IN_POOL;
+ }
+
+ BlockOffset = BucketPtr->FirstOffset;
+ DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE;
+ Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr);
+ if (Status == CFE_SUCCESS)
+ {
+ RecycleBucketId = BdPtr->Allocated - CFE_ES_MEMORY_DEALLOCATED;
+ if (BdPtr->CheckBits != CFE_ES_CHECK_PATTERN || RecycleBucketId != BucketId)
+ {
+ /* sanity check failed - possible pool corruption? */
+ Status = CFE_ES_BUFFER_NOT_IN_POOL;
+ }
+ else
+ {
+ /*
+ * Get it off the top on the list
+ */
+ NextOffset = BdPtr->NextOffset;
+
+ BdPtr->Allocated = CFE_ES_MEMORY_ALLOCATED + BucketId; /* Flag memory block as allocated */
+ BdPtr->ActualSize = NewSize;
+ BdPtr->NextOffset = 0;
+
+ Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr);
+ if (Status == CFE_SUCCESS)
+ {
+ *BlockOffsetPtr = BlockOffset;
+ BucketPtr->FirstOffset = NextOffset;
+ ++BucketPtr->RecycleCount;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolCreatePoolBlock
+**
+** Local helper function to create a new block of the given size
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GenPoolCreatePoolBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId, size_t NewSize,
+ size_t *BlockOffsetPtr)
+{
+ CFE_ES_GenPoolBucket_t *BucketPtr;
+ size_t DescOffset;
+ size_t BlockOffset;
+ size_t NextTailPosition;
+ CFE_ES_GenPoolBD_t * BdPtr;
+ int32 Status;
+
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+ if (BucketPtr == NULL)
+ {
+ /* no buffers in pool to create */
+ return CFE_ES_BUFFER_NOT_IN_POOL;
+ }
+
+ /*
+ * Determine the offsets of the new user block,
+ * which must be aligned according to the AlignMask member.
+ *
+ * Note - just pre-calculating offsets here, nothing is committed yet.
+ */
+ BlockOffset = PoolRecPtr->TailPosition + CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE;
+ BlockOffset += PoolRecPtr->AlignMask;
+ BlockOffset &= ~PoolRecPtr->AlignMask;
+
+ DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE;
+ NextTailPosition = BlockOffset + BucketPtr->BlockSize;
+
+ /*
+ * Check if there is enough space remaining in the pool -- the
+ * proposed start address plus the block size must not exceed the pool end.
+ */
+ if (NextTailPosition > PoolRecPtr->PoolMaxOffset)
+ {
+ /* can't fit in remaining mem */
+ return CFE_ES_ERR_MEM_BLOCK_SIZE;
+ }
+
+ /*
+ * Now commit the new block
+ */
+ Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr);
+ if (Status == CFE_SUCCESS)
+ {
+ BdPtr->CheckBits = CFE_ES_CHECK_PATTERN;
+ BdPtr->Allocated = CFE_ES_MEMORY_ALLOCATED + BucketId; /* Flag memory block as allocated */
+ BdPtr->ActualSize = NewSize;
+ BdPtr->NextOffset = 0;
+
+ Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr);
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ ** adjust pool current pointer and other record keeping
+ */
+ PoolRecPtr->TailPosition = NextTailPosition;
+ ++BucketPtr->AllocationCount;
+ ++PoolRecPtr->AllocationCount;
+
+ *BlockOffsetPtr = BlockOffset;
+ }
+ }
+
+ return Status;
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolInitialize
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GenPoolInitialize(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t StartOffset, size_t PoolSize,
+ size_t AlignSize, uint16 NumBlockSizes, const size_t *BlockSizeList,
+ CFE_ES_PoolRetrieve_Func_t RetrieveFunc, CFE_ES_PoolCommit_Func_t CommitFunc)
+{
+ cpuaddr AlignMask;
+ uint32 i;
+ uint32 j;
+ CFE_ES_GenPoolBucket_t *BucketPtr;
+
+ /*
+ * Note - being an internal/non-public API this does not need to
+ * check the directly-supplied arguments, it is assumed they are already
+ * sanity checked.
+ */
+ memset(PoolRecPtr, 0, sizeof(*PoolRecPtr));
+
+ /*
+ * Convert alignment to a bit mask.
+ * This sets all LSBs if the passed in value was not actually a power of 2.
+ */
+ if (AlignSize <= 1)
+ {
+ AlignMask = 0;
+ }
+ else
+ {
+ AlignMask = AlignSize - 1;
+ AlignMask |= AlignMask >> 1;
+ AlignMask |= AlignMask >> 2;
+ AlignMask |= AlignMask >> 4;
+ AlignMask |= AlignMask >> 8;
+ AlignMask |= AlignMask >> 16;
+ }
+
+ /* complete initialization of pool record entry */
+ PoolRecPtr->AlignMask = AlignMask;
+ PoolRecPtr->PoolTotalSize = PoolSize;
+ PoolRecPtr->PoolMaxOffset = PoolSize + StartOffset;
+ PoolRecPtr->NumBuckets = NumBlockSizes;
+ PoolRecPtr->Retrieve = RetrieveFunc;
+ PoolRecPtr->Commit = CommitFunc;
+ PoolRecPtr->TailPosition = StartOffset;
+
+ /* initially copy all block sizes */
+ BucketPtr = PoolRecPtr->Buckets;
+ for (i = 0; i < NumBlockSizes; ++i)
+ {
+ BucketPtr->BlockSize = BlockSizeList[i];
+ ++BucketPtr;
+ }
+
+ /* Sort by block size - a simple bubble sort -
+ * this does not run often and the list is relatively small. */
+ do
+ {
+ j = 0;
+ BucketPtr = PoolRecPtr->Buckets;
+ for (i = 1; i < NumBlockSizes; ++i)
+ {
+ if (BucketPtr[0].BlockSize > BucketPtr[1].BlockSize)
+ {
+ /* swap */
+ BucketPtr[0].BlockSize ^= BucketPtr[1].BlockSize;
+ BucketPtr[1].BlockSize ^= BucketPtr[0].BlockSize;
+ BucketPtr[0].BlockSize ^= BucketPtr[1].BlockSize;
+ ++j;
+ }
+ ++BucketPtr;
+ }
+ } while (j > 0);
+
+ /*
+ * Additional sanity check - after sorting the list,
+ * confirm that the smallest block size (first entry)
+ * is not zero.
+ */
+ if (PoolRecPtr->Buckets[0].BlockSize == 0)
+ {
+ return CFE_ES_ERR_MEM_BLOCK_SIZE;
+ }
+
+ return CFE_SUCCESS;
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolCalcMinSize
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+size_t CFE_ES_GenPoolCalcMinSize(uint16 NumBlockSizes, const size_t *BlockSizeList, uint32 NumBlocks)
+{
+ uint16 BucketId;
+ size_t MinBlockSize;
+
+ MinBlockSize = 0;
+
+ if (NumBlockSizes > 0)
+ {
+ MinBlockSize = BlockSizeList[0];
+ for (BucketId = 1; BucketId < NumBlockSizes; ++BucketId)
+ {
+ if (BlockSizeList[BucketId] < MinBlockSize)
+ {
+ MinBlockSize = BlockSizeList[BucketId];
+ }
+ }
+ }
+
+ MinBlockSize += sizeof(CFE_ES_GenPoolBD_t);
+
+ return (NumBlocks * MinBlockSize);
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolGetBlock
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GenPoolGetBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t *BlockOffsetPtr, size_t ReqSize)
+{
+ int32 Status;
+ uint16 BucketId;
+
+ /* Find the bucket which can accommodate the requested size. */
+ BucketId = CFE_ES_GenPoolFindBucket(PoolRecPtr, ReqSize);
+ if (BucketId == 0)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES:getPoolBlock err:size(%lu) > max(%lu).\n", (unsigned long)ReqSize,
+ (unsigned long)PoolRecPtr->Buckets[PoolRecPtr->NumBuckets - 1].BlockSize);
+ return (CFE_ES_ERR_MEM_BLOCK_SIZE);
+ }
+
+ /* first attempt to recycle any buffers from the same bucket that were freed */
+ Status = CFE_ES_GenPoolRecyclePoolBlock(PoolRecPtr, BucketId, ReqSize, BlockOffsetPtr);
+ if (Status != CFE_SUCCESS)
+ {
+ /* recycling not available - try making a new one instead */
+ Status = CFE_ES_GenPoolCreatePoolBlock(PoolRecPtr, BucketId, ReqSize, BlockOffsetPtr);
+ }
+
+ return (Status);
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolGetBlockSize
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GenPoolGetBlockSize(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t *BlockSizePtr, size_t BlockOffset)
+{
+ size_t DescOffset;
+ CFE_ES_GenPoolBucket_t *BucketPtr;
+ CFE_ES_GenPoolBD_t * BdPtr;
+ int32 Status;
+ uint16 BucketId;
+
+ if (BlockOffset >= PoolRecPtr->TailPosition || BlockOffset < CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE)
+ {
+ /* outside the bounds of the pool */
+ return CFE_ES_BUFFER_NOT_IN_POOL;
+ }
+
+ DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE;
+
+ Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr);
+ if (Status == CFE_SUCCESS)
+ {
+ BucketId = BdPtr->Allocated - CFE_ES_MEMORY_ALLOCATED;
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+
+ if (BdPtr->CheckBits != CFE_ES_CHECK_PATTERN || BucketPtr == NULL || BdPtr->ActualSize == 0 ||
+ BucketPtr->BlockSize < BdPtr->ActualSize)
+ {
+ /* This does not appear to be a valid data buffer */
+ Status = CFE_ES_POOL_BLOCK_INVALID;
+ }
+ else
+ {
+ *BlockSizePtr = BdPtr->ActualSize;
+ }
+ }
+
+ return Status;
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolPutBlock
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GenPoolPutBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t *BlockSizePtr, size_t BlockOffset)
+{
+ size_t DescOffset;
+ CFE_ES_GenPoolBucket_t *BucketPtr;
+ CFE_ES_GenPoolBD_t * BdPtr;
+ int32 Status;
+ uint16 BucketId;
+
+ if (BlockOffset >= PoolRecPtr->TailPosition || BlockOffset < CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE)
+ {
+ /* outside the bounds of the pool */
+ return CFE_ES_BUFFER_NOT_IN_POOL;
+ }
+
+ DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE;
+
+ Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr);
+ if (Status == CFE_SUCCESS)
+ {
+ BucketId = BdPtr->Allocated - CFE_ES_MEMORY_ALLOCATED;
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+
+ if (BdPtr->CheckBits != CFE_ES_CHECK_PATTERN || BucketPtr == NULL || BdPtr->ActualSize == 0 ||
+ BucketPtr->BlockSize < BdPtr->ActualSize)
+ {
+ /* This does not appear to be a valid data buffer */
+ ++PoolRecPtr->ValidationErrorCount;
+ Status = CFE_ES_POOL_BLOCK_INVALID;
+ }
+ else
+ {
+ BdPtr->Allocated = CFE_ES_MEMORY_DEALLOCATED + BucketId;
+ BdPtr->NextOffset = BucketPtr->FirstOffset;
+ *BlockSizePtr = BdPtr->ActualSize;
+
+ Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr);
+ if (Status == CFE_SUCCESS)
+ {
+ BucketPtr->FirstOffset = BlockOffset;
+ ++BucketPtr->ReleaseCount;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolRebuild
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+int32 CFE_ES_GenPoolRebuild(CFE_ES_GenPoolRecord_t *PoolRecPtr)
+{
+ int32 Status;
+ size_t DescOffset;
+ size_t BlockOffset;
+ CFE_ES_GenPoolBucket_t *BucketPtr;
+ CFE_ES_GenPoolBD_t * BdPtr;
+ uint16 BucketId;
+ bool IsDeallocatedBlock;
+
+ Status = CFE_SUCCESS;
+
+ /* Scan the pool to find blocks that were created and freed */
+ while (true)
+ {
+ IsDeallocatedBlock = false;
+ BucketId = 0;
+ BucketPtr = NULL;
+
+ /*
+ * Determine the offsets of the next user block,
+ * which must be aligned according to the AlignMask member.
+ */
+ BlockOffset = PoolRecPtr->TailPosition + CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE;
+ BlockOffset += PoolRecPtr->AlignMask;
+ BlockOffset &= ~PoolRecPtr->AlignMask;
+
+ if (BlockOffset > PoolRecPtr->PoolMaxOffset)
+ {
+ /* End of pool reached, stop now */
+ break;
+ }
+
+ DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE;
+ Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr);
+ if (Status != CFE_SUCCESS)
+ {
+ /* Failed to read descriptor */
+ break;
+ }
+
+ /*
+ * If the CheckBits indicate the block was in use,
+ * then do further inspection to find the block size
+ * and allocated/deallocated status.
+ */
+ if (BdPtr->CheckBits == CFE_ES_CHECK_PATTERN)
+ {
+ /* Test if block is deallocated */
+ BucketId = BdPtr->Allocated - CFE_ES_MEMORY_DEALLOCATED;
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+ if (BucketPtr != 0)
+ {
+ IsDeallocatedBlock = true;
+ }
+ else
+ {
+ /*
+ * Test if block is allocated.
+ * In this case there is nothing more to do, just
+ * get the size and skip the block.
+ */
+ BucketId = BdPtr->Allocated - CFE_ES_MEMORY_ALLOCATED;
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+ }
+ }
+
+ /*
+ * Sanity check that the actual size is less than the bucket size -
+ * it always should be, as long as the pool was created with the same
+ * set of bucket sizes.
+ */
+ if (BucketPtr == NULL || BucketPtr->BlockSize < BdPtr->ActualSize)
+ {
+ /* Not a valid block signature - stop recovery now */
+ break;
+ }
+
+ PoolRecPtr->TailPosition = BlockOffset + BucketPtr->BlockSize;
+
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+ ++BucketPtr->AllocationCount;
+ ++PoolRecPtr->AllocationCount;
+
+ /*
+ * If it was a deallocated block, then add it to the local
+ * pool linked list structure and rewrite the descriptor.
+ */
+ if (IsDeallocatedBlock)
+ {
+ ++BucketPtr->ReleaseCount;
+ BdPtr->NextOffset = BucketPtr->FirstOffset;
+ BucketPtr->FirstOffset = BlockOffset;
+ Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr);
+ if (Status != CFE_SUCCESS)
+ {
+ break;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolValidateState
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+bool CFE_ES_GenPoolValidateState(const CFE_ES_GenPoolRecord_t *PoolRecPtr)
+{
+ return (PoolRecPtr->PoolTotalSize > 0 && PoolRecPtr->TailPosition <= PoolRecPtr->PoolMaxOffset &&
+ PoolRecPtr->NumBuckets > 0 && PoolRecPtr->NumBuckets <= CFE_PLATFORM_ES_POOL_MAX_BUCKETS);
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolGetUsage
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_GenPoolGetUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t *FreeSizeBuf,
+ CFE_ES_MemOffset_t *TotalSizeBuf)
+{
+ if (TotalSizeBuf != NULL)
+ {
+ *TotalSizeBuf = CFE_ES_MEMOFFSET_C(PoolRecPtr->PoolTotalSize);
+ }
+ if (FreeSizeBuf != NULL)
+ {
+ *FreeSizeBuf = CFE_ES_MEMOFFSET_C(PoolRecPtr->PoolMaxOffset - PoolRecPtr->TailPosition);
+ }
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolGetCounts
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_GenPoolGetCounts(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 *NumBucketsBuf, uint32 *AllocCountBuf,
+ uint32 *ValidationErrorCountBuf)
+{
+ if (NumBucketsBuf != NULL)
+ {
+ *NumBucketsBuf = PoolRecPtr->NumBuckets;
+ }
+ if (AllocCountBuf != NULL)
+ {
+ *AllocCountBuf = PoolRecPtr->AllocationCount;
+ }
+ if (ValidationErrorCountBuf != NULL)
+ {
+ *ValidationErrorCountBuf = PoolRecPtr->ValidationErrorCount;
+ }
+}
+
+/*
+**---------------------------------------------------------------------------------------
+** Name: CFE_ES_GenPoolGetFreeSize
+**
+** ES Internal API - See Prototype for full API description
+**---------------------------------------------------------------------------------------
+*/
+void CFE_ES_GenPoolGetBucketUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId,
+ CFE_ES_BlockStats_t *BlockStatsBuf)
+{
+ const CFE_ES_GenPoolBucket_t * BucketPtr;
+ static const CFE_ES_GenPoolBucket_t ZeroBucket = {0};
+
+ BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId);
+ if (BucketPtr == NULL)
+ {
+ /* bucket ID is not valid */
+ BucketPtr = &ZeroBucket;
+ }
+
+ if (BlockStatsBuf != NULL)
+ {
+ BlockStatsBuf->NumCreated = BucketPtr->AllocationCount;
+ BlockStatsBuf->BlockSize = CFE_ES_MEMOFFSET_C(BucketPtr->BlockSize);
+ BlockStatsBuf->NumFree = BucketPtr->ReleaseCount - BucketPtr->RecycleCount;
+ }
+}
diff --git a/modules/es/fsw/src/cfe_es_generic_pool.h b/modules/es/fsw/src/cfe_es_generic_pool.h
new file mode 100644
index 000000000..6021da2c1
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_generic_pool.h
@@ -0,0 +1,283 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * This file contains the Internal interface for the cFE Critical Data Store
+ * memory pool functions.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_GENERIC_POOL_H
+#define CFE_ES_GENERIC_POOL_H
+
+/*
+** Include Files
+*/
+#include "common_types.h"
+
+/*
+** Macro Definitions
+*/
+#define CFE_ES_CHECK_PATTERN ((uint16)0x5a5a)
+#define CFE_ES_MEMORY_ALLOCATED ((uint16)0xaaaa)
+#define CFE_ES_MEMORY_DEALLOCATED ((uint16)0xdddd)
+
+#define CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE \
+ sizeof(CFE_ES_GenPoolBD_t) /* amount of space to reserve with every allocation */
+
+/*
+** Type Definitions
+*/
+
+typedef struct CFE_ES_GenPoolBD
+{
+ uint16 CheckBits; /**< Set to a fixed bit pattern after init */
+ uint16 Allocated; /**< Set to a bit pattern depending on allocation state */
+ size_t ActualSize; /**< The actual requested size of the block */
+ size_t NextOffset; /**< The offset of the next descriptor in the free stack */
+} CFE_ES_GenPoolBD_t;
+
+typedef struct CFE_ES_GenPoolBucket
+{
+ size_t BlockSize;
+ size_t FirstOffset; /**< Top of the "free stack" of buffers which have been returned */
+ uint32 AllocationCount; /**< Total number of buffers of this block size that exist (initial get) */
+ uint32 ReleaseCount; /**< Total number of buffers that have been released (put back) */
+ uint32 RecycleCount; /**< Total number of buffers that have been recycled (get after put) */
+} CFE_ES_GenPoolBucket_t;
+
+/*
+ * Forward struct typedef so it can be used in retrieve/commit prototype
+ */
+typedef struct CFE_ES_GenPoolRecord CFE_ES_GenPoolRecord_t;
+
+/**
+ * \brief Function to retrieve a buffer descriptor from the pool storage
+ *
+ * The generic pool implementation does not assume that buffers can be
+ * directly accessed as memory. This routine obtains a reference to
+ * the descriptor data. On memory mapped pools it may output a direct
+ * pointer to the data instead of copying it.
+ */
+typedef int32 (*CFE_ES_PoolRetrieve_Func_t)(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offset,
+ CFE_ES_GenPoolBD_t **BdPtr);
+
+/**
+ * \brief Function to commit a buffer descriptor to the pool storage
+ *
+ * The generic pool implementation does not assume that buffers can be
+ * directly accessed as memory. This routine writes data back to pool
+ * storage. It may be a no-op for memory mapped pools.
+ */
+typedef int32 (*CFE_ES_PoolCommit_Func_t)(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offset,
+ const CFE_ES_GenPoolBD_t *BdPtr);
+
+/**
+ * \brief Generic Memory Pool Type
+ */
+struct CFE_ES_GenPoolRecord
+{
+ size_t PoolTotalSize; /**< Total size of the pool area, in bytes */
+ size_t PoolMaxOffset; /**< End offset (position) of the pool */
+ size_t AlignMask; /**< Alignment mask applied to all new allocations */
+ size_t TailPosition; /**< Current high watermark of the pool, end of last allocation */
+
+ CFE_ES_PoolRetrieve_Func_t Retrieve; /**< Function to access a buffer descriptor in the pool storage */
+ CFE_ES_PoolCommit_Func_t Commit; /**< Function to commit a buffer descriptor to the pool storage */
+
+ uint32 AllocationCount; /**< Total number of block allocations of any size */
+ uint32 ValidationErrorCount; /**< Count of validation errors */
+
+ uint16 NumBuckets; /**< Number of entries in the "Buckets" array that are valid */
+ CFE_ES_GenPoolBucket_t Buckets[CFE_PLATFORM_ES_POOL_MAX_BUCKETS]; /**< Bucket States */
+};
+
+/*****************************************************************************/
+/*
+** Function prototypes
+*/
+
+/**
+ * \brief Initialize a generic pool structure
+ *
+ * Resets the pool to its initial state, given the size
+ * and alignment specifications.
+ *
+ * \param[out] PoolRecPtr Pointer to pool structure
+ * \param[in] StartOffset Initial starting location of pool
+ * \param[in] PoolSize Size of pool (beyond start offset)
+ * \param[in] AlignSize Required Alignment of blocks
+ * \param[in] NumBlockSizes Number of entries in the BlockSizeList
+ * \param[in] BlockSizeList Size of pool blocks
+ * \param[in] RetrieveFunc Function to retrieve buffer descriptors
+ * \param[in] CommitFunc Function to commit buffer descriptors
+ *
+ * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes
+ */
+int32 CFE_ES_GenPoolInitialize(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t StartOffset, size_t PoolSize,
+ size_t AlignSize, uint16 NumBlockSizes, const size_t *BlockSizeList,
+ CFE_ES_PoolRetrieve_Func_t RetrieveFunc, CFE_ES_PoolCommit_Func_t CommitFunc);
+
+/**
+ * \brief Gets a block from the pool
+ *
+ * This may recycle a previously returned block or allocate
+ * a new block, depending on availability.
+ *
+ * \param[inout] PoolRecPtr Pointer to pool structure
+ * \param[out] BlockOffsetPtr Location to output new block offset
+ * \param[in] ReqSize Size of block requested
+ *
+ * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes
+ */
+int32 CFE_ES_GenPoolGetBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t *BlockOffsetPtr, size_t ReqSize);
+
+/**
+ * \brief Returns a block to the pool
+ *
+ * This marks the previously allocated block as deallocated,
+ * and allows it to be recycled on a future get request.
+ *
+ * \param[inout] PoolRecPtr Pointer to pool structure
+ * \param[out] BlockSizePtr Location to output original allocation size
+ * \param[in] BlockOffset Offset of data block
+ *
+ * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes
+ */
+int32 CFE_ES_GenPoolPutBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t *BlockSizePtr, size_t BlockOffset);
+
+/**
+ * \brief Rebuild list of free blocks in pool
+ *
+ * If pools are stored in a nonvolatile memory area, then it is
+ * possible to resume pool operation from a previously initialized
+ * pool. This function attempts to restore the state of the pool
+ * by scanning for allocated and deallocated block markers.
+ *
+ * Before using this function, one should call CFE_ES_GenPoolInitialize()
+ * to first configure the basic pool structure and block size list.
+ *
+ * This function will then attempt to recreate the internal free lists
+ * based on descriptors/signatures already existing in the memory area.
+ *
+ * \param[inout] PoolRecPtr Pointer to pool structure
+ *
+ * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes
+ */
+int32 CFE_ES_GenPoolRebuild(CFE_ES_GenPoolRecord_t *PoolRecPtr);
+
+/**
+ * \brief Get size of pool block
+ *
+ * Given a previously allocated block, look up its descriptor information
+ * and return the actual size.
+ *
+ * \param[inout] PoolRecPtr Pointer to pool structure
+ * \param[out] BlockSizePtr Location to output original allocation size
+ * \param[in] BlockOffset Offset of data block
+ *
+ * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes
+ */
+int32 CFE_ES_GenPoolGetBlockSize(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t *BlockSizePtr, size_t BlockOffset);
+
+/**
+ * \brief Validate a pool structure
+ *
+ * Perform basic sanity checks on the pool internal data.
+ *
+ * \param[in] PoolRecPtr Pointer to pool structure
+ *
+ * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes
+ */
+bool CFE_ES_GenPoolValidateState(const CFE_ES_GenPoolRecord_t *PoolRecPtr);
+
+/**
+ * \brief Query basic usage of the pool structure
+ *
+ * Obtain basic pool usage info for telemetry/statistics reporting.
+ *
+ * \param[in] PoolRecPtr Pointer to pool structure
+ * \param[out] FreeSizeBuf Buffer to store free size
+ * \param[out] TotalSizeBuf Buffer to store total size
+ *
+ * \note This function is intended for telemetry purposes, so it
+ * uses the message size type (CFE_ES_MemOffset_t) rather
+ * than size_t, to be compatible with the type used in telemetry
+ * messages.
+ */
+void CFE_ES_GenPoolGetUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t *FreeSizeBuf,
+ CFE_ES_MemOffset_t *TotalSizeBuf);
+
+/**
+ * \brief Query counters associated with the pool structure
+ *
+ * Obtain pool counters for telemetry/statistics reporting.
+ *
+ * \param[in] PoolRecPtr Pointer to pool structure
+ * \param[out] NumBucketsBuf Buffer to store bucket count
+ * \param[out] AllocCountBuf Buffer to store allocation count
+ * \param[out] ValidationErrorCountBuf Buffer to store validation error count
+ */
+void CFE_ES_GenPoolGetCounts(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 *NumBucketsBuf, uint32 *AllocCountBuf,
+ uint32 *ValidationErrorCountBuf);
+
+/**
+ * \brief Query bucket-specific usage of the pool structure
+ *
+ * Obtain pool per-bucket stats for telemetry/statistics reporting.
+ *
+ * If the bucket number is not valid, this sets all output values to zero.
+ *
+ * \param[in] PoolRecPtr Pointer to pool structure
+ * \param[in] BucketId Bucket number (non-zero)
+ * \param[out] BlockStatsBuf Buffer to store block stats
+ */
+void CFE_ES_GenPoolGetBucketUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId,
+ CFE_ES_BlockStats_t *BlockStatsBuf);
+
+/**
+ * \brief Calculate the pool size required for the specified number of blocks
+ *
+ * Given a block size list, determine the amount of bytes required to allocate
+ * the requested number of minimally-sized blocks, including descriptor overhead.
+ *
+ * \note This is intended only as a sanity check on pool sizes, and does not
+ * guarantee the ability to actually allocate buffers in a real pool. In particular,
+ * alignment is not factored into the this size calculation, and this may require
+ * some additional overhead.
+ *
+ * \param[in] NumBlockSizes Number of entries in BlockSizeList
+ * \param[in] BlockSizeList Size of pool blocks
+ * \param[in] NumBlocks Number of blocks
+ *
+ * \return Minimum size required for requested number of blocks.
+ */
+size_t CFE_ES_GenPoolCalcMinSize(uint16 NumBlockSizes, const size_t *BlockSizeList, uint32 NumBlocks);
+
+#endif /* CFE_ES_GENERIC_POOL_H */
diff --git a/modules/es/fsw/src/cfe_es_global.h b/modules/es/fsw/src/cfe_es_global.h
new file mode 100644
index 000000000..fa5cdd001
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_global.h
@@ -0,0 +1,239 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * This file contains the ES global data definitions.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ */
+
+#ifndef CFE_ES_GLOBAL_H
+#define CFE_ES_GLOBAL_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_es_msg.h"
+#include "cfe_es_api_typedefs.h"
+
+#include "cfe_es_erlog_typedef.h"
+#include "cfe_es_resetdata_typedef.h"
+#include "cfe_es_cds.h"
+
+#include /* for sig_atomic_t */
+
+/*
+** Typedefs
+*/
+
+/*
+** CFE_ES_GenCounterRecord_t is an internal structure used to keep track of
+** Generic Counters that are active in the system.
+*/
+typedef struct
+{
+ CFE_ES_CounterId_t CounterId; /**< The actual counter ID of this entry, or undefined */
+ uint32 Counter;
+ char CounterName[OS_MAX_API_NAME]; /* Counter Name */
+} CFE_ES_GenCounterRecord_t;
+
+/*
+ * Encapsulates the state of the ES background task
+ */
+typedef struct
+{
+ CFE_ES_TaskId_t TaskID; /**< ES ID of the background task */
+ osal_id_t WorkSem; /**< Semaphore that is given whenever background work is pending */
+ uint32 NumJobsRunning; /**< Current Number of active jobs (updated by background task) */
+} CFE_ES_BackgroundTaskState_t;
+
+/*
+ * Background log dump state structure
+ *
+ * This structure is stored in global memory and keeps the state
+ * of the log dump from one iteration to the next.
+ *
+ * NOTE: This is used for log structures which are expected to be small
+ * enough so such that it is not necessary to throttle the file write or
+ * spread it over time.
+ *
+ * Therefore, the only thing necessary to be stored is whether there
+ * is a pending write request, and the data file name.
+ *
+ * Larger log files, such as the Perf log, must implement a state machine
+ * with a dedicated state data structure.
+ */
+typedef struct
+{
+ CFE_FS_FileWriteMetaData_t FileWrite; /**< FS state data - must be first */
+ CFE_ES_ERLog_FileEntry_t EntryBuffer; /**< Temp holding area for record to write */
+} CFE_ES_BackgroundLogDumpGlobal_t;
+
+/*
+** Type definition (ES task global data)
+*/
+typedef struct
+{
+ /*
+ ** ES Task command interface counters
+ */
+ uint8 CommandCounter;
+ uint8 CommandErrorCounter;
+
+ /*
+ ** ES Task housekeeping telemetry
+ */
+ CFE_ES_HousekeepingTlm_t HkPacket;
+
+ /*
+ ** Single application telemetry
+ */
+ CFE_ES_OneAppTlm_t OneAppPacket;
+
+ /*
+ ** Memory statistics telemetry
+ */
+ CFE_ES_MemStatsTlm_t MemStatsPacket;
+
+ /*
+ ** ES Task operational data (not reported in housekeeping)
+ */
+ CFE_SB_PipeId_t CmdPipe;
+
+} CFE_ES_TaskData_t;
+
+/*
+** Executive Services Global Memory Data
+** This is the regular global data that is not preserved on a
+** processor reset.
+*/
+typedef struct
+{
+ /*
+ ** Debug Variables
+ */
+ CFE_ES_DebugVariables_t DebugVars;
+
+ /*
+ ** Shared Data Semaphore
+ */
+ osal_id_t SharedDataMutex;
+
+ /*
+ ** Performance Data Mutex
+ */
+ osal_id_t PerfDataMutex;
+
+ /*
+ ** Startup Sync
+ */
+ volatile sig_atomic_t SystemState;
+
+ /*
+ ** ES Task Table
+ */
+ uint32 RegisteredTasks;
+ CFE_ES_TaskRecord_t TaskTable[OS_MAX_TASKS];
+
+ /*
+ ** ES App Table
+ */
+ uint32 RegisteredCoreApps;
+ uint32 RegisteredExternalApps;
+ CFE_ResourceId_t LastAppId;
+ CFE_ES_AppRecord_t AppTable[CFE_PLATFORM_ES_MAX_APPLICATIONS];
+
+ /*
+ ** ES Shared Library Table
+ */
+ uint32 RegisteredLibs;
+ CFE_ResourceId_t LastLibId;
+ CFE_ES_LibRecord_t LibTable[CFE_PLATFORM_ES_MAX_LIBRARIES];
+
+ /*
+ ** ES Generic Counters Table
+ */
+ CFE_ResourceId_t LastCounterId;
+ CFE_ES_GenCounterRecord_t CounterTable[CFE_PLATFORM_ES_MAX_GEN_COUNTERS];
+
+ /*
+ ** Critical Data Store Management Variables
+ */
+ CFE_ES_CDS_Instance_t CDSVars;
+ bool CDSIsAvailable; /**< \brief Whether or not the CDS service is active/valid */
+
+ /*
+ * Background task for handling long-running, non real time tasks
+ * such as maintenance, file writes, and other items.
+ */
+ CFE_ES_BackgroundTaskState_t BackgroundTask;
+
+ /*
+ ** Memory Pools
+ */
+ CFE_ResourceId_t LastMemPoolId;
+ CFE_ES_MemPoolRecord_t MemPoolTable[CFE_PLATFORM_ES_MAX_MEMORY_POOLS];
+
+ /*
+ ** ES Task initialization data (not reported in housekeeping)
+ */
+ CFE_ES_BackgroundLogDumpGlobal_t BackgroundERLogDumpState;
+
+ /*
+ * Persistent state data associated with performance log data file writes
+ */
+ CFE_ES_PerfDumpGlobal_t BackgroundPerfDumpState;
+
+ /*
+ * Persistent state data associated with background app table scans
+ */
+ CFE_ES_AppTableScanState_t BackgroundAppScanState;
+
+ /*
+ * Task global data (formerly a separate global).
+ */
+ CFE_ES_TaskData_t TaskData;
+
+ /*
+ * Pointer to the Reset data that is preserved on a processor reset
+ */
+ CFE_ES_ResetData_t *ResetDataPtr;
+
+} CFE_ES_Global_t;
+
+/*
+** The Executive Services Global Data declaration
+*/
+extern CFE_ES_Global_t CFE_ES_Global;
+
+/*
+** Functions used to lock/unlock shared data
+*/
+extern void CFE_ES_LockSharedData(const char *FunctionName, int32 LineNumber);
+extern void CFE_ES_UnlockSharedData(const char *FunctionName, int32 LineNumber);
+
+#endif /* CFE_ES_GLOBAL_H */
diff --git a/modules/es/fsw/src/cfe_es_log.h b/modules/es/fsw/src/cfe_es_log.h
new file mode 100644
index 000000000..cac9267c7
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_log.h
@@ -0,0 +1,361 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * This file contains definitions needed for the cFE ES Logs. The
+ * logs include the Mode Transition log, the System Log, and the
+ * Performance log.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_LOG_H
+#define CFE_ES_LOG_H
+
+/*
+** Include Files
+*/
+#include "common_types.h"
+#include "cfe_es_api_typedefs.h"
+#include "cfe_time_api_typedefs.h"
+
+#include /* required for "va_list" */
+
+/*
+** Macro Definitions
+*/
+
+/**
+ * Buffer size for system log messages
+ *
+ * This is based on the EVS maximum event message size, plus a time stamp
+ * and required extra formatting characters.
+ *
+ * Two extra characters are necessary:
+ * - for the space between the timestamp and the message in the system log
+ * - to enforce a newline character at the end of the string
+ *
+ * note that a null terminator byte is accounted for in "CFE_TIME_PRINTED_STRING_SIZE"
+ */
+#define CFE_ES_MAX_SYSLOG_MSG_SIZE (CFE_MISSION_EVS_MAX_MESSAGE_LENGTH + CFE_TIME_PRINTED_STRING_SIZE + 2)
+
+/**
+ * Size of the syslog "dump buffer"
+ *
+ * This is a temporary buffer that serves as a holding place for syslog data as
+ * it is being dumped to a file on disk. Since disks are comparatively slow and
+ * access to the syslog buffer must be synchronized, copying to a temporary buffer
+ * first significantly decreases the amount of time that the syslog is locked after
+ * a file dump is requested.
+ *
+ * This buffer also reflects the SysLog "burst size" that is guaranteed to be
+ * safe for concurrent writes and reads/dump operations. If applications Log more than
+ * this amount of data in less time than it takes to write this amount of data to disk,
+ * then some log messages may be corrupt or lost in the output file.
+ *
+ * @note If contention occurs where applications would overwrite logs that are still
+ * being "read" by a dump process, the realtime applications are given preference and
+ * therefore NOT blocked. Design preference is given to applications over the absolute
+ * integrity of the dump file.
+ */
+#define CFE_ES_SYSLOG_READ_BUFFER_SIZE (3 * CFE_ES_MAX_SYSLOG_MSG_SIZE)
+
+/**
+ * \brief Self-synchronized macro to call CFE_ES_SysLogAppend_Unsync
+ *
+ * Calls CFE_ES_SysLogAppend_Unsync() with appropriate synchronization.
+ * It will acquire the shared data lock and release it after appending the log.
+ *
+ * This is implemented as a macro such that the "__func__" and "__LINE__" directives
+ * will reflect the actual place that the append was done, rather than where this
+ * wrapper was defined.
+ *
+ * \sa CFE_ES_SysLogAppend_Unsync()
+ */
+#define CFE_ES_SYSLOG_APPEND(LogString) \
+ { \
+ CFE_ES_LockSharedData(__func__, __LINE__); \
+ CFE_ES_SysLogAppend_Unsync(LogString); \
+ CFE_ES_UnlockSharedData(__func__, __LINE__); \
+ OS_printf("%s", LogString); \
+ }
+
+/**
+ * \brief Indicates no context information Error Logs
+ *
+ * For use with the CFE_ES_WriteToERLog() function when no context
+ * information is available.
+ */
+#define CFE_ES_ERLOG_NO_CONTEXT (0)
+
+/*
+** Type Definitions
+*/
+
+/**
+ * \brief Buffer structure for reading data out of the SysLog
+ *
+ * Access to the syslog must be synchronized, so it is not possible to
+ * directly access the contents. This structure keeps the state of
+ * read operations such that the syslog can be read in segments.
+ *
+ * @sa CFE_ES_SysLogReadData(), CFE_ES_SysLogReadStart_Unsync()
+ */
+typedef struct
+{
+ size_t SizeLeft; /**< Total amount of unread syslog data */
+ size_t BlockSize; /**< Size of content currently in the "Data" member */
+ size_t EndIdx; /**< End of the syslog buffer at the time reading started */
+ size_t LastOffset; /**< Current Read Position */
+
+ char Data[CFE_ES_SYSLOG_READ_BUFFER_SIZE]; /**< Actual syslog content */
+} CFE_ES_SysLogReadBuffer_t;
+
+/*
+** Function prototypes
+*/
+
+/*
+** System log management
+**
+** NOTE: CFE_ES_WriteToSysLog() is a public routine in cfe_es.h, it is not prototyped here
+*/
+
+/**
+ * \brief Clear system log
+ *
+ * This discards the entire system log buffer and resets internal index values
+ *
+ * \note This function requires external thread synchronization
+ */
+void CFE_ES_SysLogClear_Unsync(void);
+
+/**
+ * \brief Begin reading the system log
+ *
+ * This a helper function is intended to assist with the "Write" command to dump
+ * the contents of the syslog to a disk file. This locates the oldest complete
+ * log message currently contained in the buffer.
+ *
+ * The oldest log message may be overwritten when any application calls
+ * CFE_ES_WriteToSysLog() if set to OVERWRITE mode.
+ *
+ * This function only locates the first message, it does not actually copy any
+ * data to the supplied buffer. The CFE_ES_SysLogReadData() should be called
+ * to read log data.
+ *
+ * \param Buffer A local buffer which will be initialized to the start of the log buffer
+ *
+ * \note This function requires external thread synchronization
+ * \sa CFE_ES_SysLogReadData()
+ */
+void CFE_ES_SysLogReadStart_Unsync(CFE_ES_SysLogReadBuffer_t *Buffer);
+
+/**
+ * \brief Write a printf-style formatted string to the system log
+ *
+ * This is a drop-in replacement for the existing CFE_ES_WriteToSysLog() API
+ * that does _not_ perform any synchronization or locking. It is intended for
+ * logging from within the ES subsystem where the appropriate lock is
+ * already held for other reasons.
+ *
+ * \note This function requires external thread synchronization
+ */
+int32 CFE_ES_SysLogWrite_Unsync(const char *SpecStringPtr, ...);
+
+/**
+ * \brief Append a complete pre-formatted string to the ES SysLog
+ *
+ * The new message will be copied to the current write location in the
+ * system log buffer. If there is not sufficient space to completely store
+ * the message, then the behavior depends on the "LogMode" setting.
+ *
+ * If "LogMode" is set to DISCARD, then the message will be truncated
+ * to fit in the available space, or completely discarded if no space exists.
+ *
+ * If "LogMode" is set to OVERWRITE, then the oldest message(s) in the
+ * system log will be overwritten with this new message.
+ *
+ * \param LogString Message to append
+ *
+ * \note This function requires external thread synchronization
+ * \sa CFE_ES_SysLogSetMode()
+ */
+int32 CFE_ES_SysLogAppend_Unsync(const char *LogString);
+
+/**
+ * \brief Read data from the system log buffer into the local buffer
+ *
+ * Prior to calling this function, the buffer structure should be initialized
+ * using CFE_ES_SysLogReadStart_Unsync()
+ *
+ * This copies the data from the syslog memory space into the local buffer, starting
+ * from the end of the previously read data. To read the complete system log,
+ * this function should be called repeatedly until the "BlockSize" member in the
+ * returned buffer is returned as zero, indicating there is no more data in the syslog.
+ *
+ * There is no specific external synchronization requirement on this function, since
+ * copies of the relevant log indices are kept in the buffer structure itself. However,
+ * if system log data is overwritten between calls to this function, it may result in
+ * undefined data being returned to the caller.
+ *
+ * Therefore, in cases where it is critically important to read log message data, the
+ * lock should be held for the entire procedure (initialization through complete read).
+ * However this may have significant realtime implications, so it is not the required
+ * mode of operation.
+ *
+ * \param Buffer A local buffer which will be filled with data from the log buffer
+ */
+void CFE_ES_SysLogReadData(CFE_ES_SysLogReadBuffer_t *Buffer);
+
+/**
+ * \brief Sets the operating mode of the system log buffer
+ *
+ * The operating mode of the system log controls its behavior once filled to the point
+ * where additional messages can no longer be stored.
+ *
+ * If "Mode" is set to DISCARD, then the message will be truncated
+ * to fit in the available space, or completely discarded if no space exists.
+ *
+ * If "Mode" is set to OVERWRITE, then the oldest message(s) in the
+ * system log will be overwritten with this new message.
+ *
+ * \note Switching from OVERWRITE to DISCARD mode may take effect immediately, as the
+ * setting only takes effect when the buffer "wrap-point" is reached at the end.
+ *
+ * \param Mode The desired operating mode
+ * \return CFE_SUCCESS if set successfully
+ */
+int32 CFE_ES_SysLogSetMode(CFE_ES_LogMode_Enum_t Mode);
+
+/**
+ * \brief Format a message intended for output to the system log
+ *
+ * This function prepares a complete message for passing into CFE_ES_SysLogAppend_Unsync(),
+ * based on the given vsnprintf-style specification string and argument list.
+ *
+ * The message is prefixed with a time stamp based on the current time, followed by the
+ * caller-specified string. An ending newline and terminating null character are both
+ * ensured on the output string.
+ *
+ * To account for the timestamp, newline, and terminating null character, the supplied buffer
+ * must be greater than (CFE_TIME_PRINTED_STRING_SIZE+2) to get a useful output. Any user-specified
+ * output string will be truncated to fit into the remaining space.
+ *
+ * \param Buffer User supplied buffer to output formatted sting into
+ * \param BufferSize Size of "Buffer" parameter. Should be greater than (CFE_TIME_PRINTED_STRING_SIZE+2)
+ * \param SpecStringPtr Printf-style format string
+ * \param ArgPtr Variable argument list as obtained by va_start() in the caller
+ *
+ * \sa CFE_ES_SysLogAppend_Unsync()
+ */
+void CFE_ES_SysLog_vsnprintf(char *Buffer, size_t BufferSize, const char *SpecStringPtr, va_list ArgPtr);
+
+/**
+ * \brief Format a message intended for output to the system log
+ *
+ * Identical to the CFE_ES_SysLog_vsnprintf() call but with a variable argument set,
+ * for use in functions that need to directly handle a log message string.
+ *
+ * Similar in definition to the "snprintf()" C library call.
+ *
+ * \param Buffer User supplied buffer to output formatted sting into
+ * \param BufferSize Size of "Buffer" parameter. Should be greater than (CFE_TIME_PRINTED_STRING_SIZE+2)
+ * \param SpecStringPtr Printf-style format string
+ *
+ * \sa CFE_ES_SysLogAppend_Unsync()
+ */
+void CFE_ES_SysLog_snprintf(char *Buffer, size_t BufferSize, const char *SpecStringPtr, ...) OS_PRINTF(3, 4);
+
+/**
+ * \brief Write the contents of the syslog to a disk file
+ *
+ * Writes the current contents of the syslog buffer to a file specified
+ * by the Filename parameter. The log messages will be written to the file
+ * in the same order in which they were written into the syslog buffer.
+ *
+ * A snapshot of the log indices is taken at the beginning of the writing
+ * process. Additional log entries added after this (e.g. from applications
+ * calling CFE_ES_WriteToSysLog() after starting a syslog dump) will not be
+ * included in the dump file.
+ *
+ * Note that preference is given to the realtime application threads over
+ * any pending log read activities, such as a dumping to a file. The design
+ * of this function can tolerate a limited level of logging activity while
+ * the dump is in progress without any negative side effects. However, a significant
+ * "flood" of log messages may corrupt the output file, by overwriting older data
+ * before it has actually been written.
+ *
+ * \param Filename Output file to write
+ * \return CFE_SUCCESS if successful, or an appropriate error code from cfe_error.h
+ *
+ * \sa CFE_ES_SYSLOG_READ_BUFFER_SIZE
+ *
+ */
+int32 CFE_ES_SysLogDump(const char *Filename);
+
+/*
+** Processor Performance log management
+*/
+int32 CFE_ES_PerfLogClear(void);
+void CFE_ES_PerfLogDump(void);
+
+/*
+** Exception and Reset Log API
+*/
+
+/**
+ * \brief Create an entry in the ES Exception and Reset Log.
+ *
+ * The exception and reset log is used to track significant system-level events and anomalies
+ * for later analysis.
+ *
+ * \param EntryType Whether the event is relevant to the CORE or an APPLICATION (#CFE_ES_LogEntryType_Enum_t)
+ * \param ResetType The type of the last reset
+ * \param ResetSubtype The subtype of the last reset
+ * \param Description A summary of the event
+ *
+ * \return CFE_SUCCESS if successful, or an appropriate error code from cfe_error.h
+ */
+int32 CFE_ES_WriteToERLog(CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype,
+ const char *Description);
+
+/**
+ * \copydoc CFE_ES_WriteToERLog()
+ *
+ * This log API accepts extra context information (AppID and ContextID)
+ * and is used when the app/task invoking this API is not the same app
+ * as where the event occurred.
+ *
+ * \param AppId The Application ID associated with the task that caused the exception
+ * \param PspContextId Identifier of extended context info stored in the PSP (if available)
+ */
+int32 CFE_ES_WriteToERLogWithContext(CFE_ES_LogEntryType_Enum_t EntryType, uint32 ResetType, uint32 ResetSubtype,
+ const char *Description, CFE_ES_AppId_t AppId, uint32 PspContextId);
+
+#endif /* CFE_ES_LOG_H */
diff --git a/modules/es/fsw/src/cfe_es_mempool.c b/modules/es/fsw/src/cfe_es_mempool.c
new file mode 100644
index 000000000..6a7107547
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_mempool.c
@@ -0,0 +1,672 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_mempool.c
+**
+** Purpose:
+** Set of services for management of discrete sized memory pools.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+*/
+
+/*
+** Includes
+*/
+#include "cfe_es_module_all.h"
+
+#include
+#include
+#include
+
+/**
+ * Macro that determines the native alignment requirement of a specific type
+ *
+ * By getting the offset of the structure after following a single char,
+ * this effectively gets how much padding the compiler added, which in turn reveals its
+ * minimum alignment requirement. (C99 is lacking a standardized "alignof" operator,
+ * and this is intended to substitute).
+ */
+#define ALIGN_OF(type) \
+ ((cpuaddr) & ((struct { \
+ char Byte; \
+ type Align; \
+ } *)0) \
+ ->Align)
+
+/*****************************************************************************/
+/*
+** Type Definitions
+*/
+
+const size_t CFE_ES_MemPoolDefSize[CFE_PLATFORM_ES_POOL_MAX_BUCKETS] = {
+ CFE_PLATFORM_ES_MAX_BLOCK_SIZE, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_16, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_15,
+ CFE_PLATFORM_ES_MEM_BLOCK_SIZE_14, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_13, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_12,
+ CFE_PLATFORM_ES_MEM_BLOCK_SIZE_11, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_10, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_09,
+ CFE_PLATFORM_ES_MEM_BLOCK_SIZE_08, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_07, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_06,
+ CFE_PLATFORM_ES_MEM_BLOCK_SIZE_05, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_04, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_03,
+ CFE_PLATFORM_ES_MEM_BLOCK_SIZE_02, CFE_PLATFORM_ES_MEM_BLOCK_SIZE_01};
+
+/*****************************************************************************/
+/*
+** Functions
+*/
+
+int32 CFE_ES_MemPoolDirectRetrieve(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offset, CFE_ES_GenPoolBD_t **BdPtr)
+{
+ cpuaddr DataAddress;
+ CFE_ES_MemPoolRecord_t *MemPoolRecPtr = (CFE_ES_MemPoolRecord_t *)PoolRecPtr;
+
+ DataAddress = MemPoolRecPtr->BaseAddr + Offset;
+ *BdPtr = (CFE_ES_GenPoolBD_t *)DataAddress;
+
+ return CFE_SUCCESS;
+}
+
+int32 CFE_ES_MemPoolDirectCommit(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offset, const CFE_ES_GenPoolBD_t *BdPtr)
+{
+ return CFE_SUCCESS;
+}
+
+int32 CFE_ES_MemPoolID_ToIndex(CFE_ES_MemHandle_t PoolID, uint32 *Idx)
+{
+ return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(PoolID), CFE_ES_POOLID_BASE, CFE_PLATFORM_ES_MAX_MEMORY_POOLS,
+ Idx);
+}
+
+/*---------------------------------------------------------------------------------------
+ * Function: CFE_ES_CheckMemPoolSlotUsed
+ *
+ * Purpose: Helper function, Aids in allocating a new ID by checking if
+ * a given table slot is available. Must be called while locked.
+ *---------------------------------------------------------------------------------------
+ */
+bool CFE_ES_CheckMemPoolSlotUsed(CFE_ResourceId_t CheckId)
+{
+ CFE_ES_MemPoolRecord_t *MemPoolRecPtr;
+ /*
+ * Note - The pointer here should never be NULL because the ID should always be
+ * within the expected range, but if it ever is NULL, this should return true
+ * such that the caller will _not_ attempt to use the record.
+ */
+ MemPoolRecPtr = CFE_ES_LocateMemPoolRecordByID(CFE_ES_MEMHANDLE_C(CheckId));
+ return (MemPoolRecPtr == NULL || CFE_ES_MemPoolRecordIsUsed(MemPoolRecPtr));
+}
+
+CFE_ES_MemPoolRecord_t *CFE_ES_LocateMemPoolRecordByID(CFE_ES_MemHandle_t PoolID)
+{
+ CFE_ES_MemPoolRecord_t *MemPoolRecPtr;
+ uint32 Idx;
+
+ if (CFE_ES_MemPoolID_ToIndex(PoolID, &Idx) == CFE_SUCCESS)
+ {
+ MemPoolRecPtr = &CFE_ES_Global.MemPoolTable[Idx];
+ }
+ else
+ {
+ MemPoolRecPtr = NULL;
+ }
+
+ return MemPoolRecPtr;
+}
+
+/*
+** CFE_ES_PoolCreateNoSem will initialize a pre-allocated memory pool without using a mutex.
+*/
+int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, size_t Size)
+{
+ return CFE_ES_PoolCreateEx(PoolID, MemPtr, Size, CFE_PLATFORM_ES_POOL_MAX_BUCKETS, &CFE_ES_MemPoolDefSize[0],
+ CFE_ES_NO_MUTEX);
+}
+
+/*
+** CFE_ES_PoolCreate will initialize a pre-allocated memory pool while using a mutex.
+*/
+int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, size_t Size)
+{
+ return CFE_ES_PoolCreateEx(PoolID, MemPtr, Size, CFE_PLATFORM_ES_POOL_MAX_BUCKETS, &CFE_ES_MemPoolDefSize[0],
+ CFE_ES_USE_MUTEX);
+}
+
+int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, size_t Size, uint16 NumBlockSizes,
+ const size_t *BlockSizes, bool UseMutex)
+{
+ int32 Status;
+ CFE_ResourceId_t PendingID;
+ CFE_ES_MemPoolRecord_t *PoolRecPtr;
+ size_t Alignment;
+ size_t MinimumSize;
+ char MutexName[OS_MAX_API_NAME];
+
+ /* Sanity Check inputs */
+ if (MemPtr == NULL || PoolID == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ /* If too many sizes are specified, return an error */
+ if (NumBlockSizes > CFE_PLATFORM_ES_POOL_MAX_BUCKETS)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES:poolCreate Num Block Sizes (%d) greater than max (%d)\n", (int)NumBlockSizes,
+ CFE_PLATFORM_ES_POOL_MAX_BUCKETS);
+ return (CFE_ES_BAD_ARGUMENT);
+ }
+
+ /*
+ * Use default block sizes if not specified
+ */
+ if (BlockSizes == NULL)
+ {
+ BlockSizes = CFE_ES_MemPoolDefSize;
+ if (NumBlockSizes == 0)
+ {
+ NumBlockSizes = CFE_PLATFORM_ES_POOL_MAX_BUCKETS;
+ }
+ }
+
+ /*
+ * Sanity check the pool size
+ */
+ MinimumSize = CFE_ES_GenPoolCalcMinSize(NumBlockSizes, BlockSizes, 1);
+ if (Size < MinimumSize)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES:poolCreate Pool size(%lu) too small, need >=%lu bytes\n", (unsigned long)Size,
+ (unsigned long)MinimumSize);
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /* scan for a free slot */
+ PendingID = CFE_ResourceId_FindNext(CFE_ES_Global.LastMemPoolId, CFE_PLATFORM_ES_MAX_MEMORY_POOLS,
+ CFE_ES_CheckMemPoolSlotUsed);
+ PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(CFE_ES_MEMHANDLE_C(PendingID));
+
+ if (PoolRecPtr == NULL)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: No free MemPoolrary slots available\n");
+ Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE;
+ }
+ else
+ {
+ /* Fully clear the entry, just in case of stale data */
+ memset(PoolRecPtr, 0, sizeof(*PoolRecPtr));
+ CFE_ES_MemPoolRecordSetUsed(PoolRecPtr, CFE_RESOURCEID_RESERVED);
+ CFE_ES_Global.LastMemPoolId = PendingID;
+ Status = CFE_SUCCESS;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ * If no open resource ID was found, return now.
+ *
+ * No more inline returns after this point; execution
+ * must continue to the end of this function where the ID is freed
+ * if not fully successful.
+ */
+ if (Status != CFE_SUCCESS)
+ {
+ return Status;
+ }
+
+ Alignment = ALIGN_OF(CFE_ES_PoolAlign_t); /* memory mapped pools should be aligned */
+ if (Alignment < CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN)
+ {
+ /*
+ * Note about path coverage testing - depending on the
+ * system architecture and configuration this line may be
+ * unreachable. This is OK.
+ */
+ Alignment = CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN;
+ }
+
+ /*
+ * Most of the work is done by the generic pool implementation.
+ * This subsystem works in offsets, not pointers.
+ */
+ Status = CFE_ES_GenPoolInitialize(&PoolRecPtr->Pool, 0, Size, Alignment, NumBlockSizes, BlockSizes,
+ CFE_ES_MemPoolDirectRetrieve, CFE_ES_MemPoolDirectCommit);
+
+ /*
+ * If successful, complete the process.
+ */
+ if (Status == CFE_SUCCESS && UseMutex == CFE_ES_USE_MUTEX)
+ {
+ /*
+ ** Construct a name for the Mutex from the address
+ ** This is needed only because OS_MutSemCreate requires
+ ** a unique name for each semaphore created.
+ */
+ snprintf(MutexName, OS_MAX_API_NAME, "Pool%08lX", CFE_ResourceId_ToInteger(PendingID));
+
+ /* create a mutex to protect this memory pool */
+ Status = OS_MutSemCreate(&PoolRecPtr->MutexId, MutexName, 0);
+ if (Status != OS_SUCCESS)
+ {
+ /* log error and rewrite to CFE status code */
+ CFE_ES_WriteToSysLog("CFE_ES:poolCreate OSAL error %d while creating mutex\n", (int)Status);
+
+ Status = CFE_STATUS_EXTERNAL_RESOURCE_FAIL;
+ }
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ * Store the base address.
+ * This is only relevant for memory-mapped pools which is why it is done here.
+ */
+ PoolRecPtr->BaseAddr = (cpuaddr)MemPtr;
+
+ /*
+ * Get the calling context.
+ * If this not a valid CFE context, then AppID will be undefined.
+ * We can still permit the creation of the pool but automatic cleanup
+ * if an exception or other event occurs will not be possible.
+ */
+ CFE_ES_GetAppID(&PoolRecPtr->OwnerAppID);
+
+ /*
+ * Store the actual/correct pool ID in the record.
+ */
+ CFE_ES_MemPoolRecordSetUsed(PoolRecPtr, PendingID);
+ }
+ else
+ {
+ /*
+ * Free the entry that was reserved earlier
+ */
+ CFE_ES_MemPoolRecordSetFree(PoolRecPtr);
+ PendingID = CFE_RESOURCEID_UNDEFINED;
+
+ if (Status == CFE_ES_POOL_BOUNDS_ERROR)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES:poolCreate Pool size(%lu) too small\n", (unsigned long)Size);
+ }
+ }
+
+ /*
+ * Export pool ID to caller as handle
+ */
+ *PoolID = CFE_ES_MEMHANDLE_C(PendingID);
+
+ return (Status);
+}
+
+int32 CFE_ES_PoolDelete(CFE_ES_MemHandle_t PoolID)
+{
+ CFE_ES_MemPoolRecord_t *PoolRecPtr;
+ osal_id_t MutexId;
+ int32 Status;
+ int32 MutDeleteStatus;
+
+ PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(PoolID);
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ /* basic sanity check */
+ if (CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, PoolID))
+ {
+ MutexId = PoolRecPtr->MutexId; /* snapshot mutex ID, will be freed later */
+ CFE_ES_MemPoolRecordSetFree(PoolRecPtr);
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ MutexId = OS_OBJECT_ID_UNDEFINED;
+ Status = CFE_ES_ERR_RESOURCEID_NOT_VALID;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /* Release the mutex if it was configured.
+ * This is done after releasing the ES lock, to avoid
+ * potential conflict with holding two locks. */
+ if (OS_ObjectIdDefined(MutexId))
+ {
+ MutDeleteStatus = OS_MutSemDelete(MutexId);
+ if (MutDeleteStatus != OS_SUCCESS)
+ {
+ /*
+ * Report to syslog for informational purposes only.
+ *
+ * The MemPool entry has already been deleted, so this
+ * function should not return an error at this point.
+ */
+ CFE_ES_WriteToSysLog("CFE_ES:poolDelete error %d deleting mutex\n", (int)MutDeleteStatus);
+ }
+ }
+
+ return Status;
+}
+
+/*
+** Function:
+** CFE_ES_GetPoolBuf
+**
+** Purpose:
+** CFE_ES_GetPoolBuf allocates a block from the memory pool.
+*/
+int32 CFE_ES_GetPoolBuf(CFE_ES_MemPoolBuf_t *BufPtr, CFE_ES_MemHandle_t Handle, size_t Size)
+{
+ int32 Status;
+ CFE_ES_AppId_t AppId;
+ CFE_ES_MemPoolRecord_t *PoolRecPtr;
+ size_t DataOffset;
+
+ if (BufPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle);
+
+ /* basic sanity check */
+ if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle))
+ {
+ CFE_ES_GetAppID(&AppId);
+ CFE_ES_WriteToSysLog("CFE_ES:getPoolBuf err:Bad handle(0x%08lX) AppId=%lu\n", CFE_RESOURCEID_TO_ULONG(Handle),
+ CFE_RESOURCEID_TO_ULONG(AppId));
+ return (CFE_ES_ERR_RESOURCEID_NOT_VALID);
+ }
+
+ /*
+ * Real work begins here.
+ * If pool is mutex-protected, take the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemTake(PoolRecPtr->MutexId);
+ }
+
+ /*
+ * Fundamental work is done as a generic routine.
+ *
+ * If successful, this gets an offset, which can then
+ * be translated into a pointer to return to the caller.
+ */
+ Status = CFE_ES_GenPoolGetBlock(&PoolRecPtr->Pool, &DataOffset, Size);
+
+ /*
+ * Real work ends here.
+ * If pool is mutex-protected, release the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemGive(PoolRecPtr->MutexId);
+ }
+
+ /* If not successful, return error now */
+ if (Status != CFE_SUCCESS)
+ {
+ return (Status);
+ }
+
+ /* Compute the actual buffer address. */
+ *BufPtr = CFE_ES_MEMPOOLBUF_C(PoolRecPtr->BaseAddr + DataOffset);
+
+ return (int32)Size;
+}
+
+/*
+** CFE_ES_GetPoolBufInfo gets the size of the specified block (if it exists).
+*/
+int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t Handle, CFE_ES_MemPoolBuf_t BufPtr)
+{
+ int32 Status;
+ CFE_ES_MemPoolRecord_t *PoolRecPtr;
+ size_t DataOffset;
+ size_t DataSize;
+
+ if (BufPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle);
+
+ /* basic sanity check */
+ if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle))
+ {
+ return (CFE_ES_ERR_RESOURCEID_NOT_VALID);
+ }
+
+ /*
+ * Real work begins here.
+ * If pool is mutex-protected, take the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemTake(PoolRecPtr->MutexId);
+ }
+
+ DataOffset = (cpuaddr)BufPtr - PoolRecPtr->BaseAddr;
+
+ Status = CFE_ES_GenPoolGetBlockSize(&PoolRecPtr->Pool, &DataSize, DataOffset);
+
+ /*
+ * Real work ends here.
+ * If pool is mutex-protected, release the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemGive(PoolRecPtr->MutexId);
+ }
+
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ * Historically this function returns the size of the buffer
+ * as an int32. This is not workable for large (64 bit) pools.
+ */
+ Status = (int32)DataSize;
+ }
+
+ return Status;
+}
+
+/*
+** CFE_ES_putPoolBuf returns a block back to the memory pool.
+*/
+int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t Handle, CFE_ES_MemPoolBuf_t BufPtr)
+{
+ CFE_ES_MemPoolRecord_t *PoolRecPtr;
+ size_t DataSize;
+ size_t DataOffset;
+ int32 Status;
+
+ if (BufPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle);
+
+ /* basic sanity check */
+ if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle))
+ {
+ CFE_ES_WriteToSysLog("CFE_ES:putPoolBuf err:Invalid Memory Handle (0x%08lX).\n",
+ CFE_RESOURCEID_TO_ULONG(Handle));
+
+ return (CFE_ES_ERR_RESOURCEID_NOT_VALID);
+ }
+
+ /*
+ * Real work begins here.
+ * If pool is mutex-protected, take the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemTake(PoolRecPtr->MutexId);
+ }
+
+ DataOffset = (cpuaddr)BufPtr - PoolRecPtr->BaseAddr;
+
+ /*
+ * Fundamental work is done as a generic routine.
+ *
+ * If successful, this gets an offset, which can then
+ * be translated into a pointer to return to the caller.
+ */
+ Status = CFE_ES_GenPoolPutBlock(&PoolRecPtr->Pool, &DataSize, DataOffset);
+
+ /*
+ * Real work ends here.
+ * If pool is mutex-protected, release the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemGive(PoolRecPtr->MutexId);
+ }
+
+ /*
+ * If successful then modify return code to be
+ * the size of the original buffer that was put (backward compatible)
+ *
+ * Otherwise if not successful, log the relevant detail
+ */
+ if (Status == CFE_SUCCESS)
+ {
+ Status = (int32)DataSize;
+ }
+ else if (Status == CFE_ES_POOL_BLOCK_INVALID)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES:putPoolBuf err:Deallocating invalid or corrupt memory block @ 0x%08lX\n",
+ (unsigned long)BufPtr);
+ }
+ else if (Status == CFE_ES_BUFFER_NOT_IN_POOL)
+ {
+ CFE_ES_WriteToSysLog("CFE_ES_GenPoolPutBlock err:Bad offset(%lu) outside pool boundary\n",
+ (unsigned long)DataOffset);
+ }
+
+ return Status;
+}
+
+/*
+** Function:
+** CFE_ES_GetMemPoolStats
+**
+** Purpose:
+**
+*/
+int32 CFE_ES_GetMemPoolStats(CFE_ES_MemPoolStats_t *BufPtr, CFE_ES_MemHandle_t Handle)
+{
+ CFE_ES_AppId_t AppId;
+ CFE_ES_MemPoolRecord_t *PoolRecPtr;
+ uint16 NumBuckets;
+ uint16 Idx;
+
+ if (BufPtr == NULL)
+ {
+ return CFE_ES_BAD_ARGUMENT;
+ }
+
+ PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle);
+
+ /* basic sanity check */
+ if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle))
+ {
+ CFE_ES_GetAppID(&AppId);
+ CFE_ES_WriteToSysLog("CFE_ES:getMemPoolStats err:Bad handle(0x%08lX) AppId=%lu\n",
+ CFE_RESOURCEID_TO_ULONG(Handle), CFE_RESOURCEID_TO_ULONG(AppId));
+ return (CFE_ES_ERR_RESOURCEID_NOT_VALID);
+ }
+
+ /*
+ * Real work begins here.
+ * If pool is mutex-protected, take the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemTake(PoolRecPtr->MutexId);
+ }
+
+ /*
+ * Obtain the free and total byte count
+ */
+ CFE_ES_GenPoolGetUsage(&PoolRecPtr->Pool, &BufPtr->NumFreeBytes, &BufPtr->PoolSize);
+
+ /*
+ * Obtain the allocation and validation error counts
+ */
+ CFE_ES_GenPoolGetCounts(&PoolRecPtr->Pool, &NumBuckets, &BufPtr->NumBlocksRequested, &BufPtr->CheckErrCtr);
+
+ for (Idx = 0; Idx < CFE_MISSION_ES_POOL_MAX_BUCKETS; ++Idx)
+ {
+ CFE_ES_GenPoolGetBucketUsage(&PoolRecPtr->Pool, NumBuckets, &BufPtr->BlockStats[Idx]);
+
+ if (NumBuckets > 0)
+ {
+ --NumBuckets;
+ }
+ }
+
+ /*
+ * Real work ends here.
+ * If pool is mutex-protected, release the mutex now.
+ */
+ if (OS_ObjectIdDefined(PoolRecPtr->MutexId))
+ {
+ OS_MutSemGive(PoolRecPtr->MutexId);
+ }
+
+ return CFE_SUCCESS;
+}
+
+/*
+** Function:
+** CFE_ES_ValidateHandle
+**
+** Purpose:
+** Insures that the handle passed in meets all of the requirements of a valid handle.
+*/
+bool CFE_ES_ValidateHandle(CFE_ES_MemHandle_t Handle)
+{
+ CFE_ES_MemPoolRecord_t *PoolRecPtr;
+ CFE_ES_MemOffset_t TotalSize;
+
+ /* Test #1) Handle must be valid */
+ PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle);
+ if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle))
+ {
+ return false;
+ }
+
+ /* Test #2) Check critical internal fields are within reason */
+ if (!CFE_ES_GenPoolValidateState(&PoolRecPtr->Pool))
+ {
+ return false;
+ }
+
+ /* Test #3) Check memory address in PSP (allows both RAM and EEPROM) */
+ CFE_ES_GenPoolGetUsage(&PoolRecPtr->Pool, NULL, &TotalSize);
+ if (CFE_PSP_MemValidateRange(PoolRecPtr->BaseAddr, TotalSize, CFE_PSP_MEM_ANY) != CFE_PSP_SUCCESS)
+ {
+ return false;
+ }
+
+ return true;
+}
diff --git a/modules/es/fsw/src/cfe_es_mempool.h b/modules/es/fsw/src/cfe_es_mempool.h
new file mode 100644
index 000000000..5c15f4cf6
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_mempool.h
@@ -0,0 +1,200 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Contains data structure definitions used by the ES mempool implementation.
+ *
+ * The ES memory pools are now built on top of the generic memory pool implementation,
+ * with a layer on top to translate into memory mapped buffer addresses.
+ */
+
+#ifndef CFE_ES_MEMPOOL_H
+#define CFE_ES_MEMPOOL_H
+
+/*
+** Include Files
+*/
+#include "common_types.h"
+#include "cfe_resourceid.h"
+#include "cfe_es_generic_pool.h"
+
+typedef struct
+{
+ /*
+ * The generic pool structure
+ * This must be the first entry in this structure.
+ */
+ CFE_ES_GenPoolRecord_t Pool;
+
+ /*
+ * The ID of this pool record
+ */
+ CFE_ES_MemHandle_t PoolID;
+
+ /**
+ * This indicates the start/base address
+ * of the memory block.
+ */
+ cpuaddr BaseAddr;
+
+ /**
+ * The "owner" field stores the AppID of the creator of the pool.
+ * If an exception or other event occurs that causes this app to exit,
+ * this allows ES to also release the memory pool entry.
+ *
+ * It is still possible for pools to be created outside the context of
+ * an ES app, but in that case the resource cannot be cleaned up if the
+ * app exits unexpectedly.
+ */
+ CFE_ES_AppId_t OwnerAppID;
+
+ /**
+ * Optional Mutex for serializing get/put operations
+ */
+ osal_id_t MutexId;
+} CFE_ES_MemPoolRecord_t;
+
+/**
+ * @brief Obtain an index value correlating to an ES Memory Pool ID
+ *
+ * This calculates a zero based integer value that may be used for indexing
+ * into a local resource table/array.
+ *
+ * Index values are only guaranteed to be unique for resources of the same
+ * type. For instance, the indices corresponding to two [valid] Memory Pool
+ * IDs will never overlap, but the index of an Memory Pool and a library ID
+ * may be the same. Furthermore, indices may be reused if a resource is
+ * deleted and re-created.
+ *
+ * @note There is no inverse of this function - indices cannot be converted
+ * back to the original PoolID value. The caller should retain the original ID
+ * for future use.
+ *
+ * @param[in] PoolID Memory Pool ID to convert
+ * @param[out] Idx Buffer where the calculated index will be stored
+ *
+ * @return Execution status, see @ref CFEReturnCodes
+ * @retval #CFE_SUCCESS @copybrief CFE_SUCCESS
+ */
+int32 CFE_ES_MemPoolID_ToIndex(CFE_ES_MemHandle_t PoolID, uint32 *Idx);
+
+/**
+ * @brief Locate the Pool table entry correlating with a given Pool ID.
+ *
+ * This only returns a pointer to the table entry and does _not_
+ * otherwise check/validate the entry.
+ *
+ * @param[in] PoolID the Pool ID to locate
+ * @return pointer to Pool Table entry for the given Pool ID
+ */
+CFE_ES_MemPoolRecord_t *CFE_ES_LocateMemPoolRecordByID(CFE_ES_MemHandle_t PoolID);
+
+/**
+ * @brief Check if a Memory Pool record is in use or free/empty
+ *
+ * This routine checks if the Pool table entry is in use or if it is free
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] PoolRecPtr pointer to Pool table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline bool CFE_ES_MemPoolRecordIsUsed(const CFE_ES_MemPoolRecord_t *PoolRecPtr)
+{
+ return CFE_RESOURCEID_TEST_DEFINED(PoolRecPtr->PoolID);
+}
+
+/**
+ * @brief Get the ID value from a Memory Pool table entry
+ *
+ * This routine converts the table entry back to an abstract ID.
+ *
+ * @param[in] PoolRecPtr pointer to Pool table entry
+ * @returns PoolID of entry
+ */
+static inline CFE_ES_MemHandle_t CFE_ES_MemPoolRecordGetID(const CFE_ES_MemPoolRecord_t *PoolRecPtr)
+{
+ return (PoolRecPtr->PoolID);
+}
+
+/**
+ * @brief Marks a Memory Pool table entry as used (not free)
+ *
+ * This sets the internal field(s) within this entry, and marks
+ * it as being associated with the given Pool ID.
+ *
+ * @param[in] PoolRecPtr pointer to Pool table entry
+ * @param[in] PendingId the Pool ID of this entry
+ */
+static inline void CFE_ES_MemPoolRecordSetUsed(CFE_ES_MemPoolRecord_t *PoolRecPtr, CFE_ResourceId_t PendingId)
+{
+ PoolRecPtr->PoolID = CFE_ES_MEMHANDLE_C(PendingId);
+}
+
+/**
+ * @brief Set a Memory Pool record table entry free (not used)
+ *
+ * This clears the internal field(s) within this entry, and allows the
+ * memory to be re-used in the future.
+ *
+ * @param[in] PoolRecPtr pointer to Pool table entry
+ */
+static inline void CFE_ES_MemPoolRecordSetFree(CFE_ES_MemPoolRecord_t *PoolRecPtr)
+{
+ PoolRecPtr->PoolID = CFE_ES_MEMHANDLE_UNDEFINED;
+}
+
+/**
+ * @brief Check if an Mem Pool record is a match for the given Pool ID
+ *
+ * This routine confirms that the previously-located record is valid
+ * and matches the expected Pool ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] PoolRecPtr pointer to Pool table entry
+ * @param[in] PoolID expected Pool ID
+ * @returns true if the entry matches the given pool ID
+ */
+static inline bool CFE_ES_MemPoolRecordIsMatch(const CFE_ES_MemPoolRecord_t *PoolRecPtr, CFE_ES_MemHandle_t PoolID)
+{
+ return (PoolRecPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(PoolRecPtr->PoolID, PoolID));
+}
+
+/**
+ * @brief Check if a Pool ID table slot is used
+ *
+ * Checks if a table slot is available for a potential new ID
+ * This is a helper function intended to be used with
+ * CFE_ResourceId_FindNext() for allocating new IDs
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CheckId pending/candidate Pool ID to check
+ * @returns true if the table slot for the ID is occupied, false if available
+ */
+bool CFE_ES_CheckMemPoolSlotUsed(CFE_ResourceId_t CheckId);
+
+#endif /* CFE_ES_MEMPOOL_H */
diff --git a/modules/es/fsw/src/cfe_es_module_all.h b/modules/es/fsw/src/cfe_es_module_all.h
new file mode 100644
index 000000000..116a890f8
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_module_all.h
@@ -0,0 +1,57 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Encapsulates all ES module internal header files, as well
+ * as the public API from all other CFE core modules, OSAL, and PSP.
+ *
+ * This simplifies the set of include files that need to be put at the
+ * start of every source file.
+ */
+
+#ifndef CFE_ES_MODULE_ALL_H
+#define CFE_ES_MODULE_ALL_H
+
+/*
+** Includes
+*/
+#include "cfe.h"
+#include "cfe_platform_cfg.h"
+
+#include "cfe_msgids.h"
+#include "cfe_perfids.h"
+
+#include "cfe_es_core_internal.h"
+#include "cfe_es_apps.h"
+#include "cfe_es_cds.h"
+#include "cfe_es_perf.h"
+#include "cfe_es_generic_pool.h"
+#include "cfe_es_mempool.h"
+#include "cfe_es_global.h"
+#include "cfe_es_cds_mempool.h"
+#include "cfe_es_events.h"
+#include "cfe_es_start.h"
+#include "cfe_es_task.h"
+#include "cfe_es_resource.h"
+#include "cfe_es_log.h"
+
+#endif /* CFE_ES_MODULE_ALL_H */
diff --git a/modules/es/fsw/src/cfe_es_objtab.c b/modules/es/fsw/src/cfe_es_objtab.c
new file mode 100644
index 000000000..2d8782e75
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_objtab.c
@@ -0,0 +1,137 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_objtab.c
+**
+** Purpose:
+** This file contains the OS_object_table for MAP Build1.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+** Notes:
+**
+*/
+
+/*
+** Include files
+*/
+#include "cfe_es_module_all.h"
+
+/* Init functions from other modules are in separate headers */
+#include "cfe_evs_core_internal.h"
+#include "cfe_fs_core_internal.h"
+#include "cfe_sb_core_internal.h"
+#include "cfe_tbl_core_internal.h"
+#include "cfe_time_core_internal.h"
+
+/*
+**
+** ES_object_table
+** Note: The name field in this table should be no more than OS_MAX_API_NAME -1 characters.
+**
+*/
+CFE_ES_ObjectTable_t CFE_ES_ObjectTable[CFE_PLATFORM_ES_OBJECT_TABLE_SIZE] = {
+ /*
+ ** Spare entries -- The spares should be distributed evenly through this table
+ */
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+
+ /*
+ ** cFE core early initialization calls. These must be done before the tasks start
+ */
+ {.ObjectType = CFE_ES_FUNCTION_CALL,
+ .ObjectName = "CFE_ES_CDSEarlyInit",
+ .FuncPtrUnion.FunctionPtr = CFE_ES_CDS_EarlyInit},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_FUNCTION_CALL,
+ .ObjectName = "CFE_EVS_EarlyInit",
+ .FuncPtrUnion.FunctionPtr = CFE_EVS_EarlyInit},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_FUNCTION_CALL,
+ .ObjectName = "CFE_SB_EarlyInit",
+ .FuncPtrUnion.FunctionPtr = CFE_SB_EarlyInit},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_FUNCTION_CALL,
+ .ObjectName = "CFE_TIME_EarlyInit",
+ .FuncPtrUnion.FunctionPtr = CFE_TIME_EarlyInit},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_FUNCTION_CALL,
+ .ObjectName = "CFE_TBL_EarlyInit",
+ .FuncPtrUnion.FunctionPtr = CFE_TBL_EarlyInit},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_FUNCTION_CALL,
+ .ObjectName = "CFE_FS_EarlyInit",
+ .FuncPtrUnion.FunctionPtr = CFE_FS_EarlyInit},
+
+ /*
+ ** Spare entries
+ */
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+
+ /*
+ ** cFE core tasks
+ */
+ {.ObjectType = CFE_ES_CORE_TASK,
+ .ObjectName = "CFE_EVS",
+ .FuncPtrUnion.MainTaskPtr = CFE_EVS_TaskMain,
+ .ObjectPriority = CFE_PLATFORM_EVS_START_TASK_PRIORITY,
+ .ObjectSize = CFE_PLATFORM_EVS_START_TASK_STACK_SIZE},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_CORE_TASK,
+ .ObjectName = "CFE_SB",
+ .FuncPtrUnion.MainTaskPtr = CFE_SB_TaskMain,
+ .ObjectPriority = CFE_PLATFORM_SB_START_TASK_PRIORITY,
+ .ObjectSize = CFE_PLATFORM_SB_START_TASK_STACK_SIZE},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_CORE_TASK,
+ .ObjectName = "CFE_ES",
+ .FuncPtrUnion.MainTaskPtr = CFE_ES_TaskMain,
+ .ObjectPriority = CFE_PLATFORM_ES_START_TASK_PRIORITY,
+ .ObjectSize = CFE_PLATFORM_ES_START_TASK_STACK_SIZE},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_CORE_TASK,
+ .ObjectName = "CFE_TIME",
+ .FuncPtrUnion.MainTaskPtr = CFE_TIME_TaskMain,
+ .ObjectPriority = CFE_PLATFORM_TIME_START_TASK_PRIORITY,
+ .ObjectSize = CFE_PLATFORM_TIME_START_TASK_STACK_SIZE},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_CORE_TASK,
+ .ObjectName = "CFE_TBL",
+ .FuncPtrUnion.MainTaskPtr = CFE_TBL_TaskMain,
+ .ObjectPriority = CFE_PLATFORM_TBL_START_TASK_PRIORITY,
+ .ObjectSize = CFE_PLATFORM_TBL_START_TASK_STACK_SIZE},
+
+ /*
+ ** Spare entries
+ */
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_NULL_ENTRY},
+ {.ObjectType = CFE_ES_NULL_ENTRY}
+
+};
diff --git a/modules/es/fsw/src/cfe_es_perf.c b/modules/es/fsw/src/cfe_es_perf.c
new file mode 100644
index 000000000..60a00b3aa
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_perf.c
@@ -0,0 +1,724 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File: cfe_es_perf.c
+**
+** Purpose: This file contains the functions that implement the software timing
+** performance markers.
+**
+*/
+
+/*
+** Include Section
+*/
+#include "cfe_es_module_all.h"
+
+#include
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Name: CFE_ES_SetupPerfVariables */
+/* */
+/* Purpose:This function initializes filter mask,trigger mask, data & state vals */
+/* */
+/* Assumptions and Notes: This gets called from CFE_ES_Main() at startup */
+/* This code must be called before any other task or code that would use */
+/* CFE_ES_PerfLogEntry() / CFE_ES_PerfLogExit() functions */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void CFE_ES_SetupPerfVariables(uint32 ResetType)
+{
+ /* Create a constant union -
+ * The "Endian" field will have "0x01" on a big endian processor
+ * and will have value "0x00" on a little endian processor.
+ */
+ const union
+ {
+ uint16 Word;
+ uint8 Endian;
+ } EndianCheck = {.Word = 0x0100};
+
+ uint32 i;
+ CFE_ES_PerfData_t *Perf;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ if (ResetType == CFE_PSP_RST_TYPE_PROCESSOR)
+ {
+ /*
+ ** On a processor reset, just IDLE the data
+ ** collection so the ground can dump the data
+ */
+ Perf->MetaData.State = CFE_ES_PERF_IDLE;
+ }
+ else
+ {
+
+ Perf->MetaData.Version = 1;
+ Perf->MetaData.Endian = EndianCheck.Endian;
+ Perf->MetaData.TimerTicksPerSecond = CFE_PSP_GetTimerTicksPerSecond();
+ Perf->MetaData.TimerLow32Rollover = CFE_PSP_GetTimerLow32Rollover();
+
+ /* set data collection state to waiting for command state */
+ Perf->MetaData.State = CFE_ES_PERF_IDLE;
+ Perf->MetaData.Mode = CFE_ES_PERF_TRIGGER_START;
+ Perf->MetaData.TriggerCount = 0;
+ Perf->MetaData.DataStart = 0;
+ Perf->MetaData.DataEnd = 0;
+ Perf->MetaData.DataCount = 0;
+ Perf->MetaData.InvalidMarkerReported = false;
+ Perf->MetaData.FilterTriggerMaskSize = CFE_ES_PERF_32BIT_WORDS_IN_MASK;
+
+ for (i = 0; i < CFE_ES_PERF_32BIT_WORDS_IN_MASK; i++)
+ {
+ Perf->MetaData.FilterMask[i] = CFE_PLATFORM_ES_PERF_FILTMASK_INIT;
+ Perf->MetaData.TriggerMask[i] = CFE_PLATFORM_ES_PERF_TRIGMASK_INIT;
+ }
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_GetPerfLogDumpRemaining() -- */
+/* Estimate the number of perf log entries left to write */
+/* This is used for telemetry/progress reporting for the perf log dump request */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+uint32 CFE_ES_GetPerfLogDumpRemaining(void)
+{
+ CFE_ES_PerfDumpGlobal_t *PerfDumpState = &CFE_ES_Global.BackgroundPerfDumpState;
+ CFE_ES_PerfDumpState_t CurrentState = PerfDumpState->CurrentState;
+ uint32 Result;
+ CFE_ES_PerfData_t * Perf;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ /* note this reads the data "live" without exclusion and as such it
+ * may change even between checking the state and checking the value.
+ * This shouldn't be a big deal, as the result should still be meaningful
+ * for a progress report, and the actual 32-bit counters should be atomic */
+ if (CurrentState > CFE_ES_PerfDumpState_IDLE && CurrentState < CFE_ES_PerfDumpState_WRITE_PERF_ENTRIES)
+ {
+ /* dump is requested but not yet to entry writing state,
+ * report the entire data count from perf log */
+ Result = Perf->MetaData.DataCount;
+ }
+ else if (CurrentState == CFE_ES_PerfDumpState_WRITE_PERF_ENTRIES)
+ {
+ /* dump is in active writing state,
+ * report the block counter (number remaining) */
+ Result = PerfDumpState->StateCounter;
+ }
+ else
+ {
+ /* no dump active or dump is complete, report 0 */
+ Result = 0;
+ }
+
+ return Result;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_StartPerfDataCmd() -- */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_ES_StartPerfDataCmd(const CFE_ES_StartPerfDataCmd_t *data)
+{
+ const CFE_ES_StartPerfCmd_Payload_t *CmdPtr = &data->Payload;
+ CFE_ES_PerfDumpGlobal_t * PerfDumpState = &CFE_ES_Global.BackgroundPerfDumpState;
+ CFE_ES_PerfData_t * Perf;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ /* Ensure there is no file write in progress before proceeding */
+ if (PerfDumpState->CurrentState == CFE_ES_PerfDumpState_IDLE &&
+ PerfDumpState->PendingState == CFE_ES_PerfDumpState_IDLE)
+ {
+ /* Make sure Trigger Mode is valid */
+ /* cppcheck-suppress unsignedPositive */
+ if ((CmdPtr->TriggerMode >= CFE_ES_PERF_TRIGGER_START) && (CmdPtr->TriggerMode < CFE_ES_PERF_MAX_MODES))
+ {
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+
+ /* Taking lock here as this might be changing states from one active mode to another.
+ * In that case, need to make sure that the log is not written to while resetting the counters. */
+ OS_MutSemTake(CFE_ES_Global.PerfDataMutex);
+ Perf->MetaData.Mode = CmdPtr->TriggerMode;
+ Perf->MetaData.TriggerCount = 0;
+ Perf->MetaData.DataStart = 0;
+ Perf->MetaData.DataEnd = 0;
+ Perf->MetaData.DataCount = 0;
+ Perf->MetaData.InvalidMarkerReported = false;
+ Perf->MetaData.State = CFE_ES_PERF_WAITING_FOR_TRIGGER; /* this must be done last */
+ OS_MutSemGive(CFE_ES_Global.PerfDataMutex);
+
+ CFE_EVS_SendEvent(CFE_ES_PERF_STARTCMD_EID, CFE_EVS_EventType_DEBUG,
+ "Start collecting performance data cmd received, trigger mode = %d",
+ (int)CmdPtr->TriggerMode);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_PERF_STARTCMD_TRIG_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Cannot start collecting performance data, trigger mode (%d) out of range (%d to %d)",
+ (int)CmdPtr->TriggerMode, (int)CFE_ES_PERF_TRIGGER_START, (int)CFE_ES_PERF_TRIGGER_END);
+ } /* end if */
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_PERF_STARTCMD_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Cannot start collecting performance data,perf data write in progress");
+ } /* end if */
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_StartPerfDataCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_StopPerfDataCmd() -- */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_ES_StopPerfDataCmd(const CFE_ES_StopPerfDataCmd_t *data)
+{
+ const CFE_ES_StopPerfCmd_Payload_t *CmdPtr = &data->Payload;
+ CFE_ES_PerfDumpGlobal_t * PerfDumpState = &CFE_ES_Global.BackgroundPerfDumpState;
+ CFE_ES_PerfData_t * Perf;
+ int32 Status;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ /* Ensure there is no file write in progress before proceeding */
+ /* note - also need to check the PendingState here, in case this command
+ * was sent twice in succession and the background task has not awakened yet */
+ if (PerfDumpState->CurrentState == CFE_ES_PerfDumpState_IDLE &&
+ PerfDumpState->PendingState == CFE_ES_PerfDumpState_IDLE)
+ {
+ Perf->MetaData.State = CFE_ES_PERF_IDLE;
+
+ /* Copy out the string, using default if unspecified */
+ Status = CFE_FS_ParseInputFileNameEx(PerfDumpState->DataFileName, CmdPtr->DataFileName,
+ sizeof(PerfDumpState->DataFileName), sizeof(CmdPtr->DataFileName),
+ CFE_PLATFORM_ES_DEFAULT_PERF_DUMP_FILENAME,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Status == CFE_SUCCESS)
+ {
+ PerfDumpState->PendingState = CFE_ES_PerfDumpState_INIT;
+ CFE_ES_BackgroundWakeup();
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+
+ CFE_EVS_SendEvent(CFE_ES_PERF_STOPCMD_EID, CFE_EVS_EventType_DEBUG,
+ "Perf Stop Cmd Rcvd, will write %d entries.%dmS dly every %d entries",
+ (int)Perf->MetaData.DataCount, (int)CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY,
+ (int)CFE_PLATFORM_ES_PERF_ENTRIES_BTWN_DLYS);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_PERF_LOG_ERR_EID, CFE_EVS_EventType_ERROR, "Error parsing filename, RC = %d",
+ (int)Status);
+ }
+
+ } /* if data to write == 0 */
+ else
+ {
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_PERF_STOPCMD_ERR2_EID, CFE_EVS_EventType_ERROR,
+ "Stop performance data cmd ignored,perf data write in progress");
+ } /* end if */
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_StopPerfDataCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Function: CFE_ES_RunPerfLogDump() */
+/* */
+/* Purpose: */
+/* Write performance data to a file */
+/* This is implemented as a state machine that is invoked in the background */
+/* Each iteration should perform a limited amount of work, which will resume */
+/* on the next iteration. State is kept in a global structure. */
+/* */
+/* Arguments: */
+/* None */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+bool CFE_ES_RunPerfLogDump(uint32 ElapsedTime, void *Arg)
+{
+ CFE_ES_PerfDumpGlobal_t *State = (CFE_ES_PerfDumpGlobal_t *)Arg;
+ int32 Status;
+ CFE_FS_Header_t FileHdr;
+ size_t BlockSize;
+ CFE_ES_PerfData_t * Perf;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ /*
+ * each time this background job is re-entered after a time delay,
+ * accumulate a work credit amount based on the elapsed time.
+ *
+ * This implements work-throttling as a form of cooperative
+ * CPU sharing with other low priority background jobs.
+ */
+ State->WorkCredit += (ElapsedTime * CFE_PLATFORM_ES_PERF_ENTRIES_BTWN_DLYS) / CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY;
+
+ /*
+ * do not allow credit to accumulate indefinitely -
+ * after a long idle time this would defeat the purpose.
+ */
+ if (State->WorkCredit > CFE_PLATFORM_ES_PERF_ENTRIES_BTWN_DLYS)
+ {
+ State->WorkCredit = CFE_PLATFORM_ES_PERF_ENTRIES_BTWN_DLYS;
+ }
+
+ while (State->WorkCredit > 0)
+ {
+ --State->WorkCredit;
+
+ if (State->PendingState != State->CurrentState)
+ {
+ /*
+ * Handle state change/entry logic.
+ * Zero the block counter register (may be changed later).
+ */
+ State->StateCounter = 0;
+
+ switch (State->PendingState)
+ {
+ case CFE_ES_PerfDumpState_OPEN_FILE:
+ /* Create the file to dump to */
+ Status = OS_OpenCreate(&State->FileDesc, State->DataFileName,
+ OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
+ if (Status < 0)
+ {
+ State->FileDesc = OS_OBJECT_ID_UNDEFINED;
+ CFE_EVS_SendEvent(CFE_ES_PERF_LOG_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Error creating file %s, RC = %d", State->DataFileName, (int)Status);
+ }
+ State->FileSize = 0;
+ break;
+
+ case CFE_ES_PerfDumpState_DELAY:
+ /*
+ * Add a state entry delay before locking the "Perf" structure to
+ * ensure that any foreground task that may have been writing to this
+ * structure has completed its access.
+ *
+ * Note that the state should already have been set to IDLE, so
+ * no new writes will start, this is just to yield the CPU such that
+ * any already-started writes may finish.
+ *
+ * This can be done by simply zeroing out the current credit,
+ * which will cause this loop to exit for now and resume after
+ * some time delay (does not really matter how much time).
+ */
+ State->WorkCredit = 0;
+ break;
+
+ case CFE_ES_PerfDumpState_LOCK_DATA:
+ OS_MutSemTake(CFE_ES_Global.PerfDataMutex);
+ break;
+
+ case CFE_ES_PerfDumpState_WRITE_FS_HDR:
+ case CFE_ES_PerfDumpState_WRITE_PERF_METADATA:
+ State->StateCounter = 1;
+ break;
+
+ case CFE_ES_PerfDumpState_WRITE_PERF_ENTRIES:
+ State->DataPos = Perf->MetaData.DataStart;
+ State->StateCounter = Perf->MetaData.DataCount;
+ break;
+
+ case CFE_ES_PerfDumpState_UNLOCK_DATA:
+ OS_MutSemGive(CFE_ES_Global.PerfDataMutex);
+ break;
+
+ case CFE_ES_PerfDumpState_CLOSE_FILE:
+ /* close the fd */
+ if (OS_ObjectIdDefined(State->FileDesc))
+ {
+ OS_close(State->FileDesc);
+ State->FileDesc = OS_OBJECT_ID_UNDEFINED;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ State->CurrentState = State->PendingState;
+ }
+
+ if (State->CurrentState == CFE_ES_PerfDumpState_IDLE)
+ {
+ break;
+ }
+
+ if (State->StateCounter == 0)
+ {
+ /*
+ * State is finished, do any final error checking and logging
+ *
+ * Default transition is to the next state by numeric value.
+ * This prevent endless looping in the same state.
+ *
+ * The switch statement can override this transition, however,
+ * based on any relevant error checks.
+ */
+ State->PendingState = 1 + State->CurrentState;
+ if (State->PendingState >= CFE_ES_PerfDumpState_MAX)
+ {
+ State->PendingState = CFE_ES_PerfDumpState_IDLE;
+ }
+ switch (State->CurrentState)
+ {
+ case CFE_ES_PerfDumpState_OPEN_FILE:
+ if (!OS_ObjectIdDefined(State->FileDesc))
+ {
+ State->PendingState = CFE_ES_PerfDumpState_IDLE;
+ } /* end if */
+ break;
+
+ case CFE_ES_PerfDumpState_WRITE_PERF_ENTRIES:
+ CFE_EVS_SendEvent(CFE_ES_PERF_DATAWRITTEN_EID, CFE_EVS_EventType_DEBUG,
+ "%s written:Size=%lu,EntryCount=%lu", State->DataFileName,
+ (unsigned long)State->FileSize, (unsigned long)Perf->MetaData.DataCount);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * State is in progress, perform work item(s) as required
+ */
+ Status = 0;
+ BlockSize = 0;
+ switch (State->CurrentState)
+ {
+ case CFE_ES_PerfDumpState_WRITE_FS_HDR:
+ /* Zero cFE header, then fill in fields */
+ CFE_FS_InitHeader(&FileHdr, CFE_ES_PERF_LOG_DESC, CFE_FS_SubType_ES_PERFDATA);
+ /* predicted total length of final output */
+ FileHdr.Length =
+ sizeof(CFE_ES_PerfMetaData_t) + (Perf->MetaData.DataCount * sizeof(CFE_ES_PerfDataEntry_t));
+ /* write the cFE header to the file */
+ Status = CFE_FS_WriteHeader(State->FileDesc, &FileHdr);
+ BlockSize = sizeof(CFE_FS_Header_t);
+ break;
+
+ case CFE_ES_PerfDumpState_WRITE_PERF_METADATA:
+ /* write the performance metadata to the file */
+ BlockSize = sizeof(CFE_ES_PerfMetaData_t);
+ Status = OS_write(State->FileDesc, &Perf->MetaData, BlockSize);
+ break;
+
+ case CFE_ES_PerfDumpState_WRITE_PERF_ENTRIES:
+ BlockSize = sizeof(CFE_ES_PerfDataEntry_t);
+ Status = OS_write(State->FileDesc, &Perf->DataBuffer[State->DataPos], BlockSize);
+
+ ++State->DataPos;
+ if (State->DataPos >= CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE)
+ {
+ State->DataPos = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (BlockSize != 0)
+ {
+ if (Status != BlockSize)
+ {
+ CFE_ES_FileWriteByteCntErr(State->DataFileName, BlockSize, Status);
+
+ /* skip to cleanup */
+ if (State->CurrentState < CFE_ES_PerfDumpState_CLEANUP)
+ {
+ State->PendingState = CFE_ES_PerfDumpState_CLEANUP;
+ }
+ }
+ else
+ {
+ State->FileSize += BlockSize;
+ }
+ }
+
+ --State->StateCounter;
+ }
+ }
+
+ /*
+ * Return "true" if activity is ongoing, or "false" if not active
+ */
+ return (State->CurrentState != CFE_ES_PerfDumpState_IDLE);
+} /* end CFE_ES_PerfLogDump */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_SetPerfFilterMaskCmd() -- */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_ES_SetPerfFilterMaskCmd(const CFE_ES_SetPerfFilterMaskCmd_t *data)
+{
+ const CFE_ES_SetPerfFilterMaskCmd_Payload_t *cmd = &data->Payload;
+ CFE_ES_PerfData_t * Perf;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ if (cmd->FilterMaskNum < CFE_ES_PERF_32BIT_WORDS_IN_MASK)
+ {
+
+ Perf->MetaData.FilterMask[cmd->FilterMaskNum] = cmd->FilterMask;
+
+ CFE_EVS_SendEvent(CFE_ES_PERF_FILTMSKCMD_EID, CFE_EVS_EventType_DEBUG,
+ "Set Performance Filter Mask Cmd rcvd, num %u, val 0x%08X", (unsigned int)cmd->FilterMaskNum,
+ (unsigned int)cmd->FilterMask);
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+ }
+ else
+ {
+ CFE_EVS_SendEvent(CFE_ES_PERF_FILTMSKERR_EID, CFE_EVS_EventType_ERROR,
+ "Performance Filter Mask Cmd Error,Index(%u)out of range(%u)",
+ (unsigned int)cmd->FilterMaskNum, (unsigned int)CFE_ES_PERF_32BIT_WORDS_IN_MASK);
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_SetPerfFilterMaskCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_SetPerfTriggerMaskCmd() -- */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_ES_SetPerfTriggerMaskCmd(const CFE_ES_SetPerfTriggerMaskCmd_t *data)
+{
+ const CFE_ES_SetPerfTrigMaskCmd_Payload_t *cmd = &data->Payload;
+ CFE_ES_PerfData_t * Perf;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ if (cmd->TriggerMaskNum < CFE_ES_PERF_32BIT_WORDS_IN_MASK)
+ {
+
+ Perf->MetaData.TriggerMask[cmd->TriggerMaskNum] = cmd->TriggerMask;
+
+ CFE_EVS_SendEvent(CFE_ES_PERF_TRIGMSKCMD_EID, CFE_EVS_EventType_DEBUG,
+ "Set Performance Trigger Mask Cmd rcvd,num %u, val 0x%08X", (unsigned int)cmd->TriggerMaskNum,
+ (unsigned int)cmd->TriggerMask);
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+ }
+ else
+ {
+ CFE_EVS_SendEvent(CFE_ES_PERF_TRIGMSKERR_EID, CFE_EVS_EventType_ERROR,
+ "Performance Trigger Mask Cmd Error,Index(%u)out of range(%u)",
+ (unsigned int)cmd->TriggerMaskNum, (unsigned int)CFE_ES_PERF_32BIT_WORDS_IN_MASK);
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_SetPerfTriggerMaskCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Name: CFE_ES_PerfLogAdd */
+/* */
+/* Purpose: This function adds a new entry to the data buffer. */
+/* */
+/* Assumptions and Notes: */
+/* */
+/* This function implements a circular buffer using an array. */
+/* DataStart points to first stored entry */
+/* DataEnd points to next available entry */
+/* if DataStart == DataEnd then the buffer is either empty or full */
+/* depending on the value of the DataCount */
+/* */
+/* Time is stored as 2 32 bit integers, (TimerLower32, TimerUpper32): */
+/* TimerLower32 is the curent value of the hardware timer register. */
+/* TimerUpper32 is the number of times the timer has rolled over. */
+/* */
+/* Time is stored as a absolute time instead of a relative time between log */
+/* entries. This will yield better accuracy since storing relative time between */
+/* entries will accumulate (rounding/sampling) errors over time. It also is */
+/* faster since the time does not need to be calculated. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void CFE_ES_PerfLogAdd(uint32 Marker, uint32 EntryExit)
+{
+ CFE_ES_PerfDataEntry_t EntryData;
+ uint32 DataEnd;
+ CFE_ES_PerfData_t * Perf;
+
+ /*
+ ** Set the pointer to the data area
+ */
+ Perf = &CFE_ES_Global.ResetDataPtr->Perf;
+
+ /*
+ * If the global state is idle, exit immediately without locking or doing anything
+ */
+ if (Perf->MetaData.State == CFE_ES_PERF_IDLE)
+ {
+ return;
+ }
+
+ /* if marker is out of range... */
+ if (Marker >= CFE_MISSION_ES_PERF_MAX_IDS)
+ {
+ /* if marker has not been reported previously ... */
+ if (Perf->MetaData.InvalidMarkerReported == false)
+ {
+ CFE_ES_WriteToSysLog("ES PERF:Invalid performance marker %d,max is %d\n", (unsigned int)Marker,
+ (CFE_MISSION_ES_PERF_MAX_IDS - 1));
+ Perf->MetaData.InvalidMarkerReported = true;
+ } /* end if */
+
+ return;
+ } /* end if */
+
+ /*
+ * check if this ID is filtered.
+ * This is also done outside the lock -
+ * normally masks should NOT be changed while perf log is active / non-idle,
+ * so although this is reading a global it should be constant, and this avoids
+ * locking (and potential task switch) if the data is ultimately not going to
+ * be written to the log.
+ */
+ if (!CFE_ES_TEST_LONG_MASK(Perf->MetaData.FilterMask, Marker))
+ {
+ return;
+ }
+
+ /*
+ * prepare the entry data (timestamp) before locking,
+ * just in case the locking operation incurs a delay
+ */
+ EntryData.Data = (Marker | (EntryExit << CFE_MISSION_ES_PERF_EXIT_BIT));
+ CFE_PSP_Get_Timebase(&EntryData.TimerUpper32, &EntryData.TimerLower32);
+
+ /*
+ * Acquire the perflog mutex before writing into the shared area.
+ * Note this lock is held for long periods while a background dump
+ * is taking place, but the dump should never be active at the
+ * same time that a capture/record is taking place.
+ */
+ OS_MutSemTake(CFE_ES_Global.PerfDataMutex);
+
+ /*
+ * Confirm that the global is still non-idle after lock
+ * (state could become idle while getting lock)
+ */
+ if (Perf->MetaData.State != CFE_ES_PERF_IDLE)
+ {
+ /* copy data to next perflog slot */
+ DataEnd = Perf->MetaData.DataEnd;
+ Perf->DataBuffer[DataEnd] = EntryData;
+
+ ++DataEnd;
+ if (DataEnd >= CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE)
+ {
+ DataEnd = 0;
+ }
+ Perf->MetaData.DataEnd = DataEnd;
+
+ /* we have filled up the buffer */
+ if (Perf->MetaData.DataCount < CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE)
+ {
+ Perf->MetaData.DataCount++;
+ }
+ else
+ {
+ /* after the buffer fills up start and end point to the same entry since we
+ are now overwriting old data */
+ Perf->MetaData.DataStart = Perf->MetaData.DataEnd;
+ }
+
+ /* waiting for trigger */
+ if (Perf->MetaData.State == CFE_ES_PERF_WAITING_FOR_TRIGGER)
+ {
+ if (CFE_ES_TEST_LONG_MASK(Perf->MetaData.TriggerMask, Marker))
+ {
+ Perf->MetaData.State = CFE_ES_PERF_TRIGGERED;
+ }
+ }
+
+ /* triggered */
+ if (Perf->MetaData.State == CFE_ES_PERF_TRIGGERED)
+ {
+ Perf->MetaData.TriggerCount++;
+ if (Perf->MetaData.Mode == CFE_ES_PERF_TRIGGER_START)
+ {
+ if (Perf->MetaData.TriggerCount >= CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE)
+ {
+ Perf->MetaData.State = CFE_ES_PERF_IDLE;
+ }
+ }
+ else if (Perf->MetaData.Mode == CFE_ES_PERF_TRIGGER_CENTER)
+ {
+ if (Perf->MetaData.TriggerCount >= CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE / 2)
+ {
+ Perf->MetaData.State = CFE_ES_PERF_IDLE;
+ }
+ }
+ else if (Perf->MetaData.Mode == CFE_ES_PERF_TRIGGER_END)
+ {
+ Perf->MetaData.State = CFE_ES_PERF_IDLE;
+ }
+ }
+ }
+
+ OS_MutSemGive(CFE_ES_Global.PerfDataMutex);
+
+} /* end CFE_ES_PerfLogAdd */
diff --git a/modules/es/fsw/src/cfe_es_perf.h b/modules/es/fsw/src/cfe_es_perf.h
new file mode 100644
index 000000000..fa0a43599
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_perf.h
@@ -0,0 +1,135 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose: Performance Analyzer data structures
+ *
+ * Design Notes:
+ *
+ * References:
+ *
+ */
+
+#ifndef CFE_ES_PERF_H
+#define CFE_ES_PERF_H
+
+/*
+** Include Files
+*/
+#include "common_types.h"
+#include "osconfig.h"
+#include "cfe_es_api_typedefs.h"
+
+/*
+** Defines
+*/
+
+enum CFE_ES_PerfState_t
+{
+ CFE_ES_PERF_IDLE = 0,
+ CFE_ES_PERF_WAITING_FOR_TRIGGER,
+ CFE_ES_PERF_TRIGGERED,
+ CFE_ES_PERF_MAX_STATES
+};
+
+enum CFE_ES_PerfMode_t
+{
+ CFE_ES_PERF_TRIGGER_START = 0,
+ CFE_ES_PERF_TRIGGER_CENTER,
+ CFE_ES_PERF_TRIGGER_END,
+ CFE_ES_PERF_MAX_MODES
+};
+
+/*
+ * Perflog Dump Background Job states
+ *
+ * Writing performance log data is now handled by a state machine that runs
+ * as a background job in Executive services. When a performance log dump is
+ * pending, each iteration of the state machine performs a limited amount of
+ * work. Each iteration resumes work where the last iteration left off.
+ */
+typedef enum
+{
+ CFE_ES_PerfDumpState_IDLE, /* Placeholder for idle, no action */
+ CFE_ES_PerfDumpState_INIT, /* Placeholder for entry/init, no action */
+ CFE_ES_PerfDumpState_OPEN_FILE, /* Opening of the output file */
+ CFE_ES_PerfDumpState_DELAY, /* Wait-state to ensure in-progress writes are finished */
+ CFE_ES_PerfDumpState_LOCK_DATA, /* Locking of the global data structure */
+ CFE_ES_PerfDumpState_WRITE_FS_HDR, /* Write the CFE FS file header */
+ CFE_ES_PerfDumpState_WRITE_PERF_METADATA, /* Write the Perf global metadata */
+ CFE_ES_PerfDumpState_WRITE_PERF_ENTRIES, /* Write the Perf Log entries (throttled) */
+ CFE_ES_PerfDumpState_CLEANUP, /* Placeholder for cleanup, no action */
+ CFE_ES_PerfDumpState_UNLOCK_DATA, /* Unlocking of the global data structure */
+ CFE_ES_PerfDumpState_CLOSE_FILE, /* Closing of the output file */
+ CFE_ES_PerfDumpState_MAX /* Placeholder for last state, no action, always last */
+} CFE_ES_PerfDumpState_t;
+
+/*
+ * Performance log dump state structure
+ *
+ * This structure is stored in global memory and keeps the state
+ * of the performance log dump from one iteration to the next.
+ *
+ * When state is IDLE, the background task does nothing and does not
+ * access or update any other members.
+ *
+ * The first state transition (IDLE->INIT) is triggered via ES command,
+ * where the command processor sets the PendingState.
+ *
+ * Once state is non-IDLE, the structure becomes owned by the background
+ * task. It will progress through the remainder of the state machine,
+ * eventually arriving back at IDLE when the request is completed.
+ */
+typedef struct
+{
+ CFE_ES_PerfDumpState_t CurrentState; /* the current state of the job */
+ CFE_ES_PerfDumpState_t PendingState; /* the pending/next state, if transitioning */
+
+ char DataFileName[OS_MAX_PATH_LEN]; /* output file name from dump command */
+ osal_id_t FileDesc; /* file descriptor for writing */
+ uint32 WorkCredit; /* accumulator based on the passage of time */
+ uint32 StateCounter; /* number of blocks/items left in current state */
+ uint32 DataPos; /* last position within the Perf Log */
+ size_t FileSize; /* Total file size, for progress reporing in telemetry */
+} CFE_ES_PerfDumpGlobal_t;
+
+/*
+ * Helper function to obtain the progress/remaining items from
+ * the background task that is writing the performance log data
+ *
+ * This is no longer just simply reading a single value from a struct,
+ * as it depends on the state of the overall process. The return value
+ * from this should mimic the value which was historically
+ * returned in the ES telemetry to report progress on this task.
+ *
+ * Foreground tasks/telemetry code shouldn't directly "peek"
+ * into data structures which it does not own.
+ */
+uint32 CFE_ES_GetPerfLogDumpRemaining(void);
+
+/*
+ * Implementation of the background state machine for writing
+ * performance log data.
+ */
+bool CFE_ES_RunPerfLogDump(uint32 ElapsedTime, void *Arg);
+
+#endif /* CFE_ES_PERF_H */
diff --git a/modules/es/fsw/src/cfe_es_resource.c b/modules/es/fsw/src/cfe_es_resource.c
new file mode 100644
index 000000000..4ea57e553
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_resource.c
@@ -0,0 +1,408 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_resource.c
+**
+** Purpose:
+** Function definitions related to CFE resource management
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+*/
+
+/*
+** Includes
+*/
+#include "cfe_es_module_all.h"
+
+#include
+#include
+#include
+
+/*********************************************************************/
+/*
+ * Function: CFE_ES_TaskId_ToOSAL
+ *
+ * For complete API information, see prototype in header
+ */
+osal_id_t CFE_ES_TaskId_ToOSAL(CFE_ES_TaskId_t id)
+{
+ osal_id_t Result;
+ unsigned long Val;
+
+ Val = CFE_ResourceId_ToInteger(CFE_RESOURCEID_UNWRAP(id));
+ Result = OS_ObjectIdFromInteger(Val ^ CFE_RESOURCEID_MARK);
+
+ return Result;
+}
+
+/*********************************************************************/
+/*
+ * Function: CFE_TaskId_FromOSAL
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_TaskId_t CFE_ES_TaskId_FromOSAL(osal_id_t id)
+{
+ CFE_ResourceId_t Result;
+ unsigned long Val;
+
+ Val = OS_ObjectIdToInteger(id);
+ Result = CFE_ResourceId_FromInteger(Val ^ CFE_RESOURCEID_MARK);
+
+ return CFE_ES_TASKID_C(Result);
+}
+
+/*********************************************************************/
+/*
+ * CFE_ES_LocateAppRecordByName
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_AppRecord_t *CFE_ES_LocateAppRecordByName(const char *Name)
+{
+ CFE_ES_AppRecord_t *AppRecPtr;
+ uint32 Count;
+
+ /*
+ ** Search the Application table for an app with a matching name.
+ */
+ AppRecPtr = CFE_ES_Global.AppTable;
+ Count = CFE_PLATFORM_ES_MAX_APPLICATIONS;
+ while (true)
+ {
+ if (Count == 0)
+ {
+ AppRecPtr = NULL;
+ break;
+ }
+ if (CFE_ES_AppRecordIsUsed(AppRecPtr) && strcmp(Name, CFE_ES_AppRecordGetName(AppRecPtr)) == 0)
+ {
+ break;
+ }
+
+ ++AppRecPtr;
+ --Count;
+ }
+
+ return AppRecPtr;
+
+} /* End of CFE_ES_LocateAppRecordByName() */
+
+/*********************************************************************/
+/*
+ * CFE_ES_LocateLibRecordByName
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_LibRecord_t *CFE_ES_LocateLibRecordByName(const char *Name)
+{
+ CFE_ES_LibRecord_t *LibRecPtr;
+ uint32 Count;
+
+ /*
+ ** Search the Library table for a library with a matching name.
+ */
+ LibRecPtr = CFE_ES_Global.LibTable;
+ Count = CFE_PLATFORM_ES_MAX_LIBRARIES;
+ while (true)
+ {
+ if (Count == 0)
+ {
+ LibRecPtr = NULL;
+ break;
+ }
+ if (CFE_ES_LibRecordIsUsed(LibRecPtr) && strcmp(Name, CFE_ES_LibRecordGetName(LibRecPtr)) == 0)
+ {
+ break;
+ }
+
+ ++LibRecPtr;
+ --Count;
+ }
+
+ return LibRecPtr;
+
+} /* End of CFE_ES_LocateLibRecordByName() */
+
+/*********************************************************************/
+/*
+ * CFE_ES_LocateCounterRecordByName
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_GenCounterRecord_t *CFE_ES_LocateCounterRecordByName(const char *Name)
+{
+ CFE_ES_GenCounterRecord_t *CounterRecPtr;
+ uint32 Count;
+
+ /*
+ ** Search the Counter table for a matching name.
+ */
+ CounterRecPtr = CFE_ES_Global.CounterTable;
+ Count = CFE_PLATFORM_ES_MAX_GEN_COUNTERS;
+ while (true)
+ {
+ if (Count == 0)
+ {
+ CounterRecPtr = NULL;
+ break;
+ }
+ if (CFE_ES_CounterRecordIsUsed(CounterRecPtr) && strcmp(Name, CFE_ES_CounterRecordGetName(CounterRecPtr)) == 0)
+ {
+ break;
+ }
+
+ ++CounterRecPtr;
+ --Count;
+ }
+
+ return CounterRecPtr;
+}
+
+/*********************************************************************/
+/*
+ * CFE_ES_LocateAppRecordByID
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_AppRecord_t *CFE_ES_LocateAppRecordByID(CFE_ES_AppId_t AppID)
+{
+ CFE_ES_AppRecord_t *AppRecPtr;
+ uint32 Idx;
+
+ if (CFE_ES_AppID_ToIndex(AppID, &Idx) == CFE_SUCCESS)
+ {
+ AppRecPtr = &CFE_ES_Global.AppTable[Idx];
+ }
+ else
+ {
+ AppRecPtr = NULL;
+ }
+
+ return AppRecPtr;
+}
+
+/*********************************************************************/
+/*
+ * CFE_ES_LocateLibRecordByID
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_LibRecord_t *CFE_ES_LocateLibRecordByID(CFE_ES_LibId_t LibID)
+{
+ CFE_ES_LibRecord_t *LibRecPtr;
+ uint32 Idx;
+
+ if (CFE_ES_LibID_ToIndex(LibID, &Idx) == CFE_SUCCESS)
+ {
+ LibRecPtr = &CFE_ES_Global.LibTable[Idx];
+ }
+ else
+ {
+ LibRecPtr = NULL;
+ }
+
+ return LibRecPtr;
+}
+
+/*********************************************************************/
+/*
+ * CFE_ES_LocateTaskRecordByID
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_TaskRecord_t *CFE_ES_LocateTaskRecordByID(CFE_ES_TaskId_t TaskID)
+{
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+ uint32 Idx;
+
+ if (CFE_ES_TaskID_ToIndex(TaskID, &Idx) == CFE_SUCCESS)
+ {
+ TaskRecPtr = &CFE_ES_Global.TaskTable[Idx];
+ }
+ else
+ {
+ TaskRecPtr = NULL;
+ }
+
+ return TaskRecPtr;
+}
+
+/*********************************************************************/
+/*
+ * CFE_ES_LocateCounterRecordByID
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_GenCounterRecord_t *CFE_ES_LocateCounterRecordByID(CFE_ES_CounterId_t CounterID)
+{
+ CFE_ES_GenCounterRecord_t *CounterRecPtr;
+ uint32 Idx;
+
+ if (CFE_ES_CounterID_ToIndex(CounterID, &Idx) == CFE_SUCCESS)
+ {
+ CounterRecPtr = &CFE_ES_Global.CounterTable[Idx];
+ }
+ else
+ {
+ CounterRecPtr = NULL;
+ }
+
+ return CounterRecPtr;
+}
+
+/*********************************************************************/
+/*
+ * CFE_ES_GetTaskRecordByContext
+ *
+ * For complete API information, see prototype in header
+ *
+ * This function does additional validation on the task record
+ * and should only be called when global data is locked.
+ */
+CFE_ES_TaskRecord_t *CFE_ES_GetTaskRecordByContext(void)
+{
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+ CFE_ES_TaskId_t TaskID;
+
+ /*
+ ** Use the OS task ID to get the ES task record
+ */
+ TaskID = CFE_ES_TaskId_FromOSAL(OS_TaskGetId());
+ TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskID);
+
+ /*
+ * Confirm that the entry is actually a match (this requires/assumes
+ * the global data is locked).
+ *
+ * If not a match, return NULL.
+ */
+ if (!CFE_ES_TaskRecordIsMatch(TaskRecPtr, TaskID))
+ {
+ TaskRecPtr = NULL;
+ }
+
+ return TaskRecPtr;
+}
+
+/*********************************************************************/
+/*
+ * CFE_ES_GetAppRecordByContext
+ *
+ * For complete API information, see prototype in header
+ */
+CFE_ES_AppRecord_t *CFE_ES_GetAppRecordByContext(void)
+{
+ CFE_ES_AppRecord_t * AppRecPtr;
+ CFE_ES_TaskRecord_t *TaskRecPtr;
+
+ /*
+ ** Step 1: Get the task record
+ */
+ TaskRecPtr = CFE_ES_GetTaskRecordByContext();
+ if (TaskRecPtr != NULL)
+ {
+ /*
+ ** Step 2: get the Application ID for the current task
+ */
+ AppRecPtr = CFE_ES_LocateAppRecordByID(TaskRecPtr->AppId);
+
+ /*
+ * Confirm that the entry is actually a match (this requires/assumes
+ * the global data is locked).
+ *
+ * If not a match, return NULL.
+ */
+ if (!CFE_ES_AppRecordIsMatch(AppRecPtr, TaskRecPtr->AppId))
+ {
+ AppRecPtr = NULL;
+ }
+ }
+ else
+ {
+ AppRecPtr = NULL;
+ }
+
+ return AppRecPtr;
+}
+
+/*
+ * ---------------------------------------------------------------------------------------
+ * Function: CFE_ES_CheckCounterIdSlotUsed
+ *
+ * Purpose: Helper function, Aids in allocating a new ID by checking if
+ * a given ID is available. Must be called while locked.
+ * ---------------------------------------------------------------------------------------
+ */
+bool CFE_ES_CheckCounterIdSlotUsed(CFE_ResourceId_t CheckId)
+{
+ CFE_ES_GenCounterRecord_t *GenCounterRecPtr;
+ /*
+ * Note - The pointer here should never be NULL because the ID should always be
+ * within the expected range, but if it ever is NULL, this should return true
+ * such that the caller will _not_ attempt to use the record.
+ */
+ GenCounterRecPtr = CFE_ES_LocateCounterRecordByID(CFE_ES_COUNTERID_C(CheckId));
+ return (GenCounterRecPtr == NULL || CFE_ES_CounterRecordIsUsed(GenCounterRecPtr));
+}
+
+/*
+ *---------------------------------------------------------------------------------------
+ * Function: CFE_ES_CheckAppIdSlotUsed
+ *
+ * Purpose: Helper function, Aids in allocating a new ID by checking if
+ * a given ID is available. Must be called while locked.
+ *---------------------------------------------------------------------------------------
+ */
+bool CFE_ES_CheckAppIdSlotUsed(CFE_ResourceId_t CheckId)
+{
+ CFE_ES_AppRecord_t *AppRecPtr;
+ /*
+ * Note - The pointer here should never be NULL because the ID should always be
+ * within the expected range, but if it ever is NULL, this should return true
+ * such that the caller will _not_ attempt to use the record.
+ */
+ AppRecPtr = CFE_ES_LocateAppRecordByID(CFE_ES_APPID_C(CheckId));
+ return (AppRecPtr == NULL || CFE_ES_AppRecordIsUsed(AppRecPtr));
+}
+
+/*
+ * ---------------------------------------------------------------------------------------
+ * Function: CFE_ES_CheckLibIdSlotUsed
+ *
+ * Purpose: Helper function, Aids in allocating a new ID by checking if
+ * a given ID is available. Must be called while locked.
+ * ---------------------------------------------------------------------------------------
+ */
+bool CFE_ES_CheckLibIdSlotUsed(CFE_ResourceId_t CheckId)
+{
+ CFE_ES_LibRecord_t *LibRecPtr;
+ /*
+ * Note - The pointer here should never be NULL because the ID should always be
+ * within the expected range, but if it ever is NULL, this should return true
+ * such that the caller will _not_ attempt to use the record.
+ */
+ LibRecPtr = CFE_ES_LocateLibRecordByID(CFE_ES_LIBID_C(CheckId));
+ return (LibRecPtr == NULL || CFE_ES_LibRecordIsUsed(LibRecPtr));
+}
diff --git a/modules/es/fsw/src/cfe_es_resource.h b/modules/es/fsw/src/cfe_es_resource.h
new file mode 100644
index 000000000..6d6f387b4
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_resource.h
@@ -0,0 +1,552 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Contains basic prototypes and definitions related to CFE ES resource
+ * management and related resource IDs.
+ *
+ * A CFE ES Resource ID is a common way to identify CFE-managed resources such
+ * as apps, tasks, counters, memory pools, CDS blocks, and other entities.
+ */
+
+#ifndef CFE_ES_RESOURCE_H
+#define CFE_ES_RESOURCE_H
+
+/*
+** Include Files
+*/
+#include "cfe_resourceid.h"
+#include "cfe_core_resourceid_basevalues.h"
+#include "cfe_es_global.h"
+
+/**
+ * @brief Locate the app table entry correlating with a given app ID.
+ *
+ * This only returns a pointer to the table entry and does _not_
+ * otherwise check/validate the entry.
+ *
+ * @param[in] AppID the app ID to locate
+ * @return pointer to App Table entry for the given app ID
+ */
+extern CFE_ES_AppRecord_t *CFE_ES_LocateAppRecordByID(CFE_ES_AppId_t AppID);
+
+/**
+ * @brief Locate the Library table entry correlating with a given Lib ID.
+ *
+ * This only returns a pointer to the table entry and does _not_
+ * otherwise check/validate the entry.
+ *
+ * @param[in] LibID the Lib ID to locate
+ * @return pointer to Library Table entry for the given Lib ID
+ */
+extern CFE_ES_LibRecord_t *CFE_ES_LocateLibRecordByID(CFE_ES_LibId_t LibID);
+
+/**
+ * @brief Locate the task table entry correlating with a given task ID.
+ *
+ * This only returns a pointer to the table entry and does _not_
+ * otherwise check/validate the entry.
+ *
+ * @param[in] TaskID the task ID to locate
+ * @return pointer to Task Table entry for the given task ID
+ */
+extern CFE_ES_TaskRecord_t *CFE_ES_LocateTaskRecordByID(CFE_ES_TaskId_t TaskID);
+
+/**
+ * @brief Locate the Counter table entry correlating with a given Counter ID.
+ *
+ * This only returns a pointer to the table entry and does _not_
+ * otherwise check/validate the entry.
+ *
+ * @param[in] CounterID the Counter ID to locate
+ * @return pointer to Counter Table entry for the given Counter ID
+ */
+extern CFE_ES_GenCounterRecord_t *CFE_ES_LocateCounterRecordByID(CFE_ES_CounterId_t CounterID);
+
+/**
+ * @brief Check if an app record is in use or free/empty
+ *
+ * This routine checks if the App table entry is in use or if it is free
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] AppRecPtr pointer to app table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline bool CFE_ES_AppRecordIsUsed(const CFE_ES_AppRecord_t *AppRecPtr)
+{
+ return CFE_RESOURCEID_TEST_DEFINED(AppRecPtr->AppId);
+}
+
+/**
+ * @brief Get the ID value from an app table entry
+ *
+ * This routine converts the table entry back to an abstract ID.
+ *
+ * @param[in] AppRecPtr pointer to app table entry
+ * @returns AppID of entry
+ */
+static inline CFE_ES_AppId_t CFE_ES_AppRecordGetID(const CFE_ES_AppRecord_t *AppRecPtr)
+{
+ return AppRecPtr->AppId;
+}
+
+/**
+ * @brief Marks an app table entry as used (not free)
+ *
+ * This sets the internal field(s) within this entry, and marks
+ * it as being associated with the given app ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] AppRecPtr pointer to app table entry
+ * @param[in] PendingId the app ID of this entry
+ */
+static inline void CFE_ES_AppRecordSetUsed(CFE_ES_AppRecord_t *AppRecPtr, CFE_ResourceId_t PendingId)
+{
+ AppRecPtr->AppId = CFE_ES_APPID_C(PendingId);
+}
+
+/**
+ * @brief Set an app record table entry free (not used)
+ *
+ * This clears the internal field(s) within this entry, and allows the
+ * memory to be re-used in the future.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] AppRecPtr pointer to app table entry
+ */
+static inline void CFE_ES_AppRecordSetFree(CFE_ES_AppRecord_t *AppRecPtr)
+{
+ AppRecPtr->AppId = CFE_ES_APPID_UNDEFINED;
+}
+
+/**
+ * @brief Check if an app record is a match for the given AppID
+ *
+ * This routine confirms that the previously-located record is valid
+ * and matches the expected app ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] AppRecPtr pointer to app table entry
+ * @param[in] AppID expected app ID
+ * @returns true if the entry matches the given app ID
+ */
+static inline bool CFE_ES_AppRecordIsMatch(const CFE_ES_AppRecord_t *AppRecPtr, CFE_ES_AppId_t AppID)
+{
+ return (AppRecPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(AppRecPtr->AppId, AppID));
+}
+
+/**
+ * @brief Obtain the name associated with the Application record
+ *
+ * Returns the name field from within the Application record
+ *
+ * @param[in] AppRecPtr pointer to App table entry
+ * @returns Pointer to Application name
+ */
+static inline const char *CFE_ES_AppRecordGetName(const CFE_ES_AppRecord_t *AppRecPtr)
+{
+ return AppRecPtr->AppName;
+}
+
+/**
+ * @brief Check if a Library record is in use or free/empty
+ *
+ * This routine checks if the Lib table entry is in use or if it is free
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] LibRecPtr pointer to Lib table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline bool CFE_ES_LibRecordIsUsed(const CFE_ES_LibRecord_t *LibRecPtr)
+{
+ return CFE_RESOURCEID_TEST_DEFINED(LibRecPtr->LibId);
+}
+
+/**
+ * @brief Get the ID value from a Library table entry
+ *
+ * This routine converts the table entry back to an abstract ID.
+ *
+ * @param[in] LibRecPtr pointer to Lib table entry
+ * @returns LibID of entry
+ */
+static inline CFE_ES_LibId_t CFE_ES_LibRecordGetID(const CFE_ES_LibRecord_t *LibRecPtr)
+{
+ /*
+ * The initial implementation does not store the ID in the entry;
+ * the ID is simply the zero-based index into the table.
+ */
+ return (LibRecPtr->LibId);
+}
+
+/**
+ * @brief Marks a Library table entry as used (not free)
+ *
+ * This sets the internal field(s) within this entry, and marks
+ * it as being associated with the given Lib ID.
+ *
+ * @param[in] LibRecPtr pointer to Lib table entry
+ * @param[in] PendingId the Lib ID of this entry
+ */
+static inline void CFE_ES_LibRecordSetUsed(CFE_ES_LibRecord_t *LibRecPtr, CFE_ResourceId_t PendingId)
+{
+ LibRecPtr->LibId = CFE_ES_LIBID_C(PendingId);
+}
+
+/**
+ * @brief Set a Library record table entry free (not used)
+ *
+ * This clears the internal field(s) within this entry, and allows the
+ * memory to be re-used in the future.
+ *
+ * @param[in] LibRecPtr pointer to Lib table entry
+ */
+static inline void CFE_ES_LibRecordSetFree(CFE_ES_LibRecord_t *LibRecPtr)
+{
+ LibRecPtr->LibId = CFE_ES_LIBID_UNDEFINED;
+}
+
+/**
+ * @brief Check if a Library record is a match for the given LibID
+ *
+ * This routine confirms that the previously-located record is valid
+ * and matches the expected Lib ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] LibRecPtr pointer to Lib table entry
+ * @param[in] LibID expected Lib ID
+ * @returns true if the entry matches the given Lib ID
+ */
+static inline bool CFE_ES_LibRecordIsMatch(const CFE_ES_LibRecord_t *LibRecPtr, CFE_ES_LibId_t LibID)
+{
+ return (LibRecPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(LibRecPtr->LibId, LibID));
+}
+
+/**
+ * @brief Obtain the name associated with the Library record
+ *
+ * Returns the name field from within the Library record
+ *
+ * @param[in] LibRecPtr pointer to Lib table entry
+ * @returns Pointer to Library name
+ */
+static inline const char *CFE_ES_LibRecordGetName(const CFE_ES_LibRecord_t *LibRecPtr)
+{
+ return LibRecPtr->LibName;
+}
+
+/**
+ * @brief Get the ID value from an Task table entry
+ *
+ * This routine converts the table entry back to an abstract ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] TaskRecPtr pointer to Task table entry
+ * @returns TaskID of entry
+ */
+static inline CFE_ES_TaskId_t CFE_ES_TaskRecordGetID(const CFE_ES_TaskRecord_t *TaskRecPtr)
+{
+ return (TaskRecPtr->TaskId);
+}
+
+/**
+ * @brief Check if a Task record is in use or free/empty
+ *
+ * This routine checks if the Task table entry is in use or if it is free
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] TaskRecPtr pointer to task table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline bool CFE_ES_TaskRecordIsUsed(const CFE_ES_TaskRecord_t *TaskRecPtr)
+{
+ return CFE_RESOURCEID_TEST_DEFINED(TaskRecPtr->TaskId);
+}
+
+/**
+ * @brief Marks an Task table entry as used (not free)
+ *
+ * This sets the internal field(s) within this entry, and marks
+ * it as being associated with the given Task ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] TaskRecPtr pointer to Task table entry
+ * @param[in] PendingId the Task ID of this entry
+ */
+static inline void CFE_ES_TaskRecordSetUsed(CFE_ES_TaskRecord_t *TaskRecPtr, CFE_ResourceId_t PendingId)
+{
+ TaskRecPtr->TaskId = CFE_ES_TASKID_C(PendingId);
+}
+
+/**
+ * @brief Set a Task record table entry free
+ *
+ * This allows the table entry to be re-used by another Task.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] TaskRecPtr pointer to task table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline void CFE_ES_TaskRecordSetFree(CFE_ES_TaskRecord_t *TaskRecPtr)
+{
+ TaskRecPtr->TaskId = CFE_ES_TASKID_UNDEFINED;
+}
+
+/**
+ * @brief Check if a Task record is a match for the given TaskID
+ *
+ * This routine confirms that the previously-located record is valid
+ * and matches the expected Task ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] TaskRecPtr pointer to task table entry
+ * @param[in] TaskID The expected task ID to verify
+ * @returns true if the entry matches the given task ID
+ */
+static inline bool CFE_ES_TaskRecordIsMatch(const CFE_ES_TaskRecord_t *TaskRecPtr, CFE_ES_TaskId_t TaskID)
+{
+ return (TaskRecPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(TaskRecPtr->TaskId, TaskID));
+}
+
+/**
+ * @brief Obtain the name associated with the Task record
+ *
+ * Returns the name field from within the Task record
+ *
+ * @param[in] TaskRecPtr pointer to Task table entry
+ * @returns Pointer to Task name
+ */
+static inline const char *CFE_ES_TaskRecordGetName(const CFE_ES_TaskRecord_t *TaskRecPtr)
+{
+ return TaskRecPtr->TaskName;
+}
+
+/**
+ * @brief Check if an Counter record is in use or free/empty
+ *
+ * This routine checks if the Counter table entry is in use or if it is free
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CounterRecPtr pointer to Counter table entry
+ * @returns true if the entry is in use/configured, or false if it is free/empty
+ */
+static inline bool CFE_ES_CounterRecordIsUsed(const CFE_ES_GenCounterRecord_t *CounterRecPtr)
+{
+ return CFE_RESOURCEID_TEST_DEFINED(CounterRecPtr->CounterId);
+}
+
+/**
+ * @brief Get the ID value from an Counter table entry
+ *
+ * This routine converts the table entry back to an abstract ID.
+ *
+ * @param[in] CounterRecPtr pointer to Counter table entry
+ * @returns CounterID of entry
+ */
+static inline CFE_ES_CounterId_t CFE_ES_CounterRecordGetID(const CFE_ES_GenCounterRecord_t *CounterRecPtr)
+{
+ return CounterRecPtr->CounterId;
+}
+
+/**
+ * @brief Marks an Counter table entry as used (not free)
+ *
+ * This sets the internal field(s) within this entry, and marks
+ * it as being associated with the given Counter ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CounterRecPtr pointer to Counter table entry
+ * @param[in] PendingId the Counter ID of this entry
+ */
+static inline void CFE_ES_CounterRecordSetUsed(CFE_ES_GenCounterRecord_t *CounterRecPtr, CFE_ResourceId_t PendingId)
+{
+ CounterRecPtr->CounterId = CFE_ES_COUNTERID_C(PendingId);
+}
+
+/**
+ * @brief Set an Counter record table entry free (not used)
+ *
+ * This clears the internal field(s) within this entry, and allows the
+ * memory to be re-used in the future.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CounterRecPtr pointer to Counter table entry
+ */
+static inline void CFE_ES_CounterRecordSetFree(CFE_ES_GenCounterRecord_t *CounterRecPtr)
+{
+ CounterRecPtr->CounterId = CFE_ES_COUNTERID_UNDEFINED;
+}
+
+/**
+ * @brief Check if an Counter record is a match for the given CounterID
+ *
+ * This routine confirms that the previously-located record is valid
+ * and matches the expected Counter ID.
+ *
+ * As this dereferences fields within the record, global data must be
+ * locked prior to invoking this function.
+ *
+ * @param[in] CounterRecPtr pointer to Counter table entry
+ * @param[in] CounterID expected Counter ID
+ * @returns true if the entry matches the given Counter ID
+ */
+static inline bool CFE_ES_CounterRecordIsMatch(const CFE_ES_GenCounterRecord_t *CounterRecPtr,
+ CFE_ES_CounterId_t CounterID)
+{
+ return (CounterRecPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(CounterRecPtr->CounterId, CounterID));
+}
+
+/**
+ * @brief Obtain the name associated with the counter record
+ *
+ * Returns the name field from within the counter record
+ *
+ * @param[in] CounterRecPtr pointer to Counter table entry
+ * @returns Pointer to counter name
+ */
+static inline const char *CFE_ES_CounterRecordGetName(const CFE_ES_GenCounterRecord_t *CounterRecPtr)
+{
+ return CounterRecPtr->CounterName;
+}
+
+/**
+ * Locate and validate the app record for the calling context.
+ *
+ * Finds and validates the ES AppTable entry corresponding to the
+ * caller. This confirms that the fields within the table entry match the
+ * expected value(s), otherwise NULL is returned if no matching entry
+ * is found.
+ *
+ * The global data lock should be obtained prior to invoking this function.
+ */
+extern CFE_ES_AppRecord_t *CFE_ES_GetAppRecordByContext(void);
+
+/**
+ * Locate and validate the task record for the calling context.
+ *
+ * Finds and validates the ES TaskTable entry corresponding to the
+ * caller. This confirms that the fields within the table entry match the
+ * expected value(s), otherwise NULL is returned if no matching entry
+ * is found.
+ *
+ * The global data lock should be obtained prior to invoking this function.
+ */
+extern CFE_ES_TaskRecord_t *CFE_ES_GetTaskRecordByContext(void);
+
+/*
+ * OSAL <-> CFE task ID conversion
+ *
+ * CFE ES does not currently allocate its own task IDs; instead it piggybacks on top
+ * of the allocation that is already done by OSAL. This is partly for backward
+ * compatibility - historically the OSAL task IDs were used directly by CFE task APIs.
+ *
+ * This is _only_ used for tasks - for all other resource types ES should allocate
+ * its own identifiers independently of any other subsystem. This conversion may also
+ * be removed in a future version of CFE, if ES starts allocating task IDs independently
+ * of OSAL task IDs.
+ */
+
+/**
+ * @brief Convert an ES Task ID to an OSAL task ID
+ *
+ * Task IDs created via CFE ES are also OSAL task IDs, but technically
+ * do refer to a different scope and therefore have a different type
+ * to represent them.
+ *
+ * This function facilitates converting between the types.
+ *
+ * @note With "simple" resource IDs, numeric values are the same and can be interchanged
+ * for backward compatibility, however they will be different when using "strict" IDs.
+ * New code should not assume equivalence between OSAL and ES task IDs.
+ *
+ * @sa CFE_ES_TaskId_FromOSAL
+ *
+ * @param[in] id The CFE task ID
+ * @returns The OSAL task ID
+ */
+extern osal_id_t CFE_ES_TaskId_ToOSAL(CFE_ES_TaskId_t id);
+
+/**
+ * @brief Convert an ES Task ID to an OSAL task ID
+ *
+ * Task IDs created via CFE ES are also OSAL task IDs, but technically
+ * do refer to a different scope and therefore have a different type
+ * to represent them.
+ *
+ * This function facilitates converting between the types.
+ *
+ * @note With "simple" resource IDs, numeric values are the same and can be interchanged
+ * for backward compatibility, however they will be different when using "strict" IDs.
+ * New code should not assume equivalence between OSAL and ES task IDs.
+ *
+ * @sa CFE_ES_TaskId_ToOSAL
+ *
+ * @param[in] id The OSAL task ID
+ * @returns The CFE task ID
+ */
+extern CFE_ES_TaskId_t CFE_ES_TaskId_FromOSAL(osal_id_t id);
+
+/*
+ * Internal functions to perform name based resource lookups
+ *
+ * These functions do not lock, they must only be used internally by ES when
+ * the lock is already held.
+ */
+CFE_ES_AppRecord_t * CFE_ES_LocateAppRecordByName(const char *Name);
+CFE_ES_LibRecord_t * CFE_ES_LocateLibRecordByName(const char *Name);
+CFE_ES_TaskRecord_t * CFE_ES_LocateTaskRecordByName(const char *Name);
+CFE_ES_GenCounterRecord_t *CFE_ES_LocateCounterRecordByName(const char *Name);
+
+/* Availability check functions used in conjunction with CFE_ResourceId_FindNext() */
+bool CFE_ES_CheckAppIdSlotUsed(CFE_ResourceId_t CheckId);
+bool CFE_ES_CheckLibIdSlotUsed(CFE_ResourceId_t CheckId);
+bool CFE_ES_CheckCounterIdSlotUsed(CFE_ResourceId_t CheckId);
+
+#endif /* CFE_ES_RESOURCE_H */
diff --git a/modules/es/fsw/src/cfe_es_start.c b/modules/es/fsw/src/cfe_es_start.c
new file mode 100644
index 000000000..0d65c3db3
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_start.c
@@ -0,0 +1,954 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_start.c
+**
+** Purpose:
+** This file contains the Main entrypoint and startup code for the cFE core.
+** The entry point is called by the board support package for the OS. When the
+** entry point is finished, the cFE should be fully initialized and running.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+*/
+
+/*
+** Includes
+*/
+
+#include "cfe_es_module_all.h"
+
+#include
+#include
+
+static int32 CFE_ES_MainTaskSyncDelay(uint32 AppStateId, uint32 TimeOutMilliseconds);
+
+/***************************************************************************/
+
+/*
+** Defines for this module
+*/
+
+/*
+** Number of msecs to delay before exiting cFE. Allows LogMsg to get through
+*/
+#define CFE_ES_PANIC_DELAY 500
+
+/*
+** Global data for the ES startup code and Runtime library
+*/
+CFE_ES_Global_t CFE_ES_Global;
+
+/***************************************************************************/
+/*
+** Code
+*/
+
+/*
+** Name: CFE_ES_Main - See API and header file for details
+*/
+void CFE_ES_Main(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const char *StartFilePath)
+{
+ int32 ReturnCode;
+
+ /*
+ * Clear the entire global data structure.
+ * This also takes care of setting all resource IDs on all table entries
+ * to be "undefined" (not in use).
+ */
+ memset(&CFE_ES_Global, 0, sizeof(CFE_ES_Global));
+
+ /*
+ ** Indicate that the CFE is the earliest initialization state
+ */
+ CFE_ES_Global.SystemState = CFE_ES_SystemState_EARLY_INIT;
+
+ /*
+ ** Create the ES Shared Data Mutex
+ ** This must be done before ANY calls to CFE_ES_WriteToSysLog(), since this uses the mutex
+ */
+ ReturnCode = OS_MutSemCreate(&(CFE_ES_Global.SharedDataMutex), "ES_DATA_MUTEX", 0);
+ if (ReturnCode != OS_SUCCESS)
+ {
+ /* Cannot use SysLog here, since that requires the reset area to be set up */
+ OS_printf("ES Startup: Error: ES Shared Data Mutex could not be created. RC=0x%08X\n",
+ (unsigned int)ReturnCode);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_STARTUP_SEM);
+
+ /*
+ * Normally CFE_PSP_Panic() will not return but it will under UT
+ */
+ return;
+ } /* end if */
+
+ /*
+ ** Initialize the Reset variables. This call is required
+ ** Before most of the ES functions can be used including the
+ ** ES System log.
+ */
+ CFE_ES_SetupResetVariables(StartType, StartSubtype, ModeId);
+
+ /*
+ ** Initialize the Logic Perf variables
+ ** Because this is in the ES Reset area, it must be called after
+ ** CFE_ES_SetupResetVariables.
+ */
+ CFE_ES_SetupPerfVariables(StartType);
+
+ /*
+ ** Also Create the ES Performance Data Mutex
+ ** This is to separately protect against concurrent writes to the global performance log data
+ */
+ ReturnCode = OS_MutSemCreate(&CFE_ES_Global.PerfDataMutex, "ES_PERF_MUTEX", 0);
+ if (ReturnCode != OS_SUCCESS)
+ {
+ CFE_ES_SysLogWrite_Unsync("ES Startup: Error: ES Performance Data Mutex could not be created. RC=0x%08X\n",
+ (unsigned int)ReturnCode);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_STARTUP_SEM);
+
+ /*
+ * Normally CFE_PSP_Panic() will not return but it will under UT
+ */
+ return;
+ }
+
+ /*
+ ** Announce the startup
+ */
+ CFE_ES_WriteToSysLog("ES Startup: CFE_ES_Main in EARLY_INIT state\n");
+
+ /*
+ ** Create and Mount the filesystems needed
+ */
+ CFE_ES_InitializeFileSystems(StartType);
+
+ /*
+ ** Install exception Handlers ( Placeholder )
+ */
+ CFE_PSP_AttachExceptions();
+
+ /*
+ ** Initialize the Last Id
+ */
+ CFE_ES_Global.LastAppId = CFE_ResourceId_FromInteger(CFE_ES_APPID_BASE);
+ CFE_ES_Global.LastLibId = CFE_ResourceId_FromInteger(CFE_ES_LIBID_BASE);
+ CFE_ES_Global.LastCounterId = CFE_ResourceId_FromInteger(CFE_ES_COUNTID_BASE);
+ CFE_ES_Global.LastMemPoolId = CFE_ResourceId_FromInteger(CFE_ES_POOLID_BASE);
+
+ /*
+ ** Indicate that the CFE core is now starting up / going multi-threaded
+ */
+ CFE_ES_WriteToSysLog("ES Startup: CFE_ES_Main entering CORE_STARTUP state\n");
+ CFE_ES_Global.SystemState = CFE_ES_SystemState_CORE_STARTUP;
+
+ /*
+ ** Create the tasks, OS objects, and initialize hardware
+ */
+ CFE_ES_CreateObjects();
+
+ /*
+ ** Indicate that the CFE core is ready
+ */
+ CFE_ES_WriteToSysLog("ES Startup: CFE_ES_Main entering CORE_READY state\n");
+ CFE_ES_Global.SystemState = CFE_ES_SystemState_CORE_READY;
+
+ /*
+ ** Start the cFE Applications from the disk using the file
+ ** specified in the CFE_PLATFORM_ES_NONVOL_STARTUP_FILE or CFE_PLATFORM_ES_VOLATILE_STARTUP_FILE
+ ** ( defined in the cfe_platform_cfg.h file )
+ */
+ CFE_ES_StartApplications(StartType, StartFilePath);
+
+ /*
+ * Wait for applications to be in at least "LATE_INIT"
+ *
+ * However, if not everything starts up, that is not a fatal error, we will
+ * continue anyway since the core apps are OK and control/telemetry should function.
+ * The problem app could be deleted/restarted/etc by the ground station.
+ */
+ if (CFE_ES_MainTaskSyncDelay(CFE_ES_AppState_LATE_INIT, CFE_PLATFORM_ES_STARTUP_SCRIPT_TIMEOUT_MSEC) != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Startup Sync failed - Applications may not have all initialized\n");
+ }
+
+ CFE_ES_WriteToSysLog("ES Startup: CFE_ES_Main entering APPS_INIT state\n");
+ CFE_ES_Global.SystemState = CFE_ES_SystemState_APPS_INIT;
+
+ /*
+ * Wait for applications to be "RUNNING" before moving to operational system state.
+ *
+ * However, if not everything starts up, that is not a fatal error, we will
+ * continue anyway since the core apps are OK and control/telemetry should function.
+ * The problem app could be deleted/restarted/etc by the ground station.
+ */
+ if (CFE_ES_MainTaskSyncDelay(CFE_ES_AppState_RUNNING, CFE_PLATFORM_ES_STARTUP_SCRIPT_TIMEOUT_MSEC) != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Startup Sync failed - Applications may not have all started\n");
+ }
+
+ /*
+ ** Startup is fully complete
+ */
+ CFE_ES_WriteToSysLog("ES Startup: CFE_ES_Main entering OPERATIONAL state\n");
+ CFE_ES_Global.SystemState = CFE_ES_SystemState_OPERATIONAL;
+}
+
+/*
+** Name: CFE_ES_SetupResetVariables
+**
+** Purpose: This function initializes the ES reset variables depending on the reset type.
+** It will also initiate a power on reset when too many processor resets
+** have happened.
+**
+** SYSLOGGING NOTE: Any logging in here must use CFE_ES_SysLogWrite_Unsync() as the necessary
+** primitives are not even initialized yet. There is no chance for log contention here.
+**
+*/
+void CFE_ES_SetupResetVariables(uint32 StartType, uint32 StartSubtype, uint32 BootSource)
+{
+
+ int32 status;
+ uint32 resetAreaSize;
+ cpuaddr ResetDataAddr;
+
+ /*
+ ** Get the pointer to the Reset area from the BSP
+ */
+ status = CFE_PSP_GetResetArea(&ResetDataAddr, &resetAreaSize);
+
+ /*
+ ** Make sure the status is OK or size is big enough
+ */
+ if (status != CFE_PSP_SUCCESS)
+ {
+ /*
+ ** Cannot use the ES System log without the Reset Area
+ */
+ OS_printf("ES Startup: CFE_PSP_GetResetArea call Failed (0x%08x)!\n", (unsigned int)status);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_MEMORY_ALLOC);
+
+ /*
+ * Normally unreachable, except in UT where
+ * CFE_PSP_Panic is a stub that may return
+ */
+ return;
+ }
+ else if (resetAreaSize < sizeof(CFE_ES_ResetData_t))
+ {
+ /*
+ ** Cannot use the ES system log without the Reset Area
+ */
+ OS_printf("ES Startup: Error: ES Reset area not big enough. Needed: %d, Given: %d.\n",
+ (int)sizeof(CFE_ES_ResetData_t), (int)resetAreaSize);
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_MEMORY_ALLOC);
+
+ /*
+ * Normally unreachable, except in UT where
+ * CFE_PSP_Panic is a stub that may return
+ */
+ return;
+ }
+
+ CFE_ES_Global.ResetDataPtr = (CFE_ES_ResetData_t *)ResetDataAddr;
+
+ /*
+ ** Record the BootSource (bank) so it will be valid in the ER log entries.
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.BootSource = BootSource;
+
+ /*
+ ** Determine how the system was started. The choices are:
+ ** CFE_ES_POWER_ON_RESET, or CFE_PSP_RST_TYPE_PROCESSOR
+ ** The subtypes include:
+ ** CFE_PSP_RST_SUBTYPE_POWER_CYCLE, CFE_PSP_RST_SUBTYPE_PUSH_BUTTON, CFE_PSP_RST_SUBTYPE_HW_SPECIAL_COMMAND,
+ ** CFE_PSP_RST_SUBTYPE_HW_WATCHDOG, CFE_PSP_RST_TYPE_COMMAND, or CFE_PSP_RST_SUBTYPE_EXCEPTION.
+ ** Some of these reset types are logged before the system is restarted.
+ ** ( CFE_PSP_RST_TYPE_COMMAND, CFE_PSP_RST_SUBTYPE_EXCEPTION ) while others occur
+ ** without the knowledge of the software and must be logged here.
+ */
+ if (StartType == CFE_PSP_RST_TYPE_POWERON)
+ {
+ /*
+ ** Record the reset type and subtype
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype = StartSubtype;
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetType = CFE_PSP_RST_TYPE_POWERON;
+
+ /*
+ ** Log the power-on reset.
+ */
+ if (StartSubtype == CFE_PSP_RST_SUBTYPE_POWER_CYCLE)
+ {
+ CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to Power Cycle (Power Cycle).\n");
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype,
+ "POWER ON RESET due to Power Cycle (Power Cycle)");
+ }
+ else if (StartSubtype == CFE_PSP_RST_SUBTYPE_HW_SPECIAL_COMMAND)
+ {
+ CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to HW Special Cmd (Hw Spec Cmd).\n");
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype,
+ "POWER ON RESET due to HW Special Cmd (Hw Spec Cmd)");
+ }
+ else
+ {
+ CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to other cause (See Subtype).\n");
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype,
+ "POWER ON RESET due to other cause (See Subtype)");
+ }
+
+ /*
+ ** Initialize all reset counters.
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount = 0;
+ CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount = CFE_PLATFORM_ES_MAX_PROCESSOR_RESETS;
+ CFE_ES_Global.DebugVars.DebugFlag = 0;
+ }
+ else if (StartType == CFE_PSP_RST_TYPE_PROCESSOR)
+ {
+ /*
+ ** If a Processor reset was not commanded, it must be a watchdog or other non-commanded reset
+ ** Log the reset before updating any reset variables.
+ */
+ if (CFE_ES_Global.ResetDataPtr->ResetVars.ES_CausedReset != true)
+ {
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetType = CFE_PSP_RST_TYPE_PROCESSOR;
+ CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount++;
+
+ /*
+ ** When coming up from a Processor reset that was not caused by ES, check to see
+ ** if the maximum number has been exceeded
+ */
+ if (CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount >
+ CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount)
+ {
+ if (StartSubtype == CFE_PSP_RST_SUBTYPE_HW_SPECIAL_COMMAND)
+ {
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype = CFE_PSP_RST_SUBTYPE_HW_SPECIAL_COMMAND;
+ CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to max proc resets (HW Spec Cmd).\n");
+
+ /*
+ ** Log the reset in the ER Log. The log will be wiped out, but it's good to have
+ ** the entry just in case something fails.
+ */
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype,
+ "POWER ON RESET due to max proc resets (HW Spec Cmd).");
+ }
+ else
+ {
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype = CFE_PSP_RST_SUBTYPE_HW_WATCHDOG;
+ CFE_ES_SysLogWrite_Unsync("POWER ON RESET due to max proc resets (Watchdog).\n");
+
+ /*
+ ** Log the reset in the ER Log. The log will be wiped out, but it's good to have
+ ** the entry just in case something fails.
+ */
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, StartSubtype,
+ "POWER ON RESET due to max proc resets (Watchdog).");
+ }
+ /*
+ ** Call the BSP reset routine
+ */
+ CFE_PSP_Restart(CFE_PSP_RST_TYPE_POWERON);
+
+ /*
+ ** Should not return here.
+ */
+ CFE_ES_SysLogWrite_Unsync("ES Startup: Error: CFE_PSP_Restart returned.\n");
+ }
+ else /* Maximum processor reset not exceeded */
+ {
+ if (StartSubtype == CFE_PSP_RST_SUBTYPE_HW_SPECIAL_COMMAND)
+ {
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype = CFE_PSP_RST_SUBTYPE_HW_SPECIAL_COMMAND;
+ CFE_ES_SysLogWrite_Unsync("PROCESSOR RESET due to Hardware Special Command (HW Spec Cmd).\n");
+
+ /*
+ ** Log the watchdog reset
+ */
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, StartSubtype,
+ "PROCESSOR RESET due to Hardware Special Command (Hw Spec Cmd).");
+ }
+ else
+ {
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype = CFE_PSP_RST_SUBTYPE_HW_WATCHDOG;
+ CFE_ES_SysLogWrite_Unsync("PROCESSOR RESET due to Watchdog (Watchdog).\n");
+
+ /*
+ ** Log the watchdog reset
+ */
+ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, StartSubtype,
+ "PROCESSOR RESET due to Watchdog (Watchdog).");
+ }
+
+ } /* end if */
+ }
+ /*
+ ** If a processor reset is due to a command or exception, the reset has already been logged.
+ ** Update the reset variables only.
+ ** The logic for detecting maximum resets is done on the command/exception side
+ ** on the "way down" when the command or exception handler is executed.
+ */
+ else
+ {
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetType = CFE_PSP_RST_TYPE_PROCESSOR;
+ CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype = StartSubtype;
+ }
+
+ /*
+ ** Initialize processor reset counters.
+ */
+ CFE_ES_Global.DebugVars.DebugFlag = 0;
+ }
+
+ /*
+ ** Clear the commanded reset flag, in case a watchdog happens.
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.ES_CausedReset = false;
+}
+
+/*
+** Name: CFE_ES_InitializeFileSystems
+**
+** Purpose: This function initializes the file systems used in the cFE core.
+**
+*/
+void CFE_ES_InitializeFileSystems(uint32 StartType)
+{
+ int32 RetStatus;
+ cpuaddr RamDiskMemoryAddress;
+ uint32 RamDiskMemorySize;
+ int32 PercentFree;
+ OS_statvfs_t StatBuf;
+
+ /*
+ ** Get the memory area for the RAM disk
+ */
+ RetStatus = CFE_PSP_GetVolatileDiskMem(&(RamDiskMemoryAddress), &(RamDiskMemorySize));
+
+ if (RetStatus != CFE_PSP_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Cannot Get Memory for Volatile Disk. EC = 0x%08X\n", (unsigned int)RetStatus);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+ }
+
+ /*
+ ** Next, either format, or just initialize the RAM disk depending on
+ ** the reset type
+ */
+ if (StartType == CFE_PSP_RST_TYPE_POWERON)
+ {
+ RetStatus = OS_mkfs((void *)RamDiskMemoryAddress, "/ramdev0", "RAM", CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE,
+ CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS);
+ if (RetStatus != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error Creating Volatile(RAM) Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+ }
+ }
+ else
+ {
+ RetStatus = OS_initfs((void *)RamDiskMemoryAddress, "/ramdev0", "RAM", CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE,
+ CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS);
+ if (RetStatus != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error Initializing Volatile(RAM) Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+ CFE_ES_WriteToSysLog("ES Startup: Formatting Volatile(RAM) Volume.\n");
+
+ RetStatus = OS_mkfs((void *)RamDiskMemoryAddress, "/ramdev0", "RAM", CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE,
+ CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS);
+ if (RetStatus != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error Creating Volatile(RAM) Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+ }
+ }
+ }
+
+ /*
+ ** Now, mount the RAM disk
+ */
+ RetStatus = OS_mount("/ramdev0", CFE_PLATFORM_ES_RAM_DISK_MOUNT_STRING);
+ if (RetStatus != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error Mounting Volatile(RAM) Volume. EC = 0x%08X\n", (unsigned int)RetStatus);
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+ }
+
+ /*
+ ** During a Processor reset, if the RAM disk has less than a defined
+ ** amount of free space, reformat and re-mount it.
+ ** The parameter being checked is CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED
+ ** Note: When CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED is set to 0, this feature is
+ ** disabled.
+ */
+ if ((StartType == CFE_PSP_RST_TYPE_PROCESSOR) && (CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED > 0))
+ {
+ /*
+ ** See how many blocks are free in the RAM disk
+ */
+ RetStatus = OS_FileSysStatVolume(CFE_PLATFORM_ES_RAM_DISK_MOUNT_STRING, &StatBuf);
+ if (RetStatus == OS_SUCCESS && StatBuf.total_blocks > 0)
+ {
+ /*
+ ** Determine if the disk is too full
+ */
+ PercentFree = (StatBuf.blocks_free * 100) / StatBuf.total_blocks;
+ CFE_ES_WriteToSysLog("Volatile Disk has %d Percent free space.\n", (int)PercentFree);
+
+ if (PercentFree < CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Insufficent Free Space on Volatile Disk, Reformatting.\n");
+
+ /*
+ ** First, unmount the disk
+ */
+ RetStatus = OS_unmount(CFE_PLATFORM_ES_RAM_DISK_MOUNT_STRING);
+ if (RetStatus == OS_SUCCESS)
+ {
+
+ /*
+ ** Remove the file system from the OSAL
+ */
+ RetStatus = OS_rmfs("/ramdev0");
+ if (RetStatus == OS_SUCCESS)
+ {
+
+ /*
+ ** Next, make a new file system on the disk
+ */
+ RetStatus = OS_mkfs((void *)RamDiskMemoryAddress, "/ramdev0", "RAM",
+ CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE, CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS);
+ if (RetStatus == OS_SUCCESS)
+ {
+ /*
+ ** Last, remount the disk
+ */
+ RetStatus = OS_mount("/ramdev0", CFE_PLATFORM_ES_RAM_DISK_MOUNT_STRING);
+ if (RetStatus != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog(
+ "ES Startup: Error Re-Mounting Volatile(RAM) Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+
+ } /* end if mount */
+ }
+ else
+ {
+
+ CFE_ES_WriteToSysLog("ES Startup: Error Re-Formating Volatile(RAM) Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+
+ } /* end if mkfs */
+ }
+ else /* could not Remove File system */
+ {
+
+ CFE_ES_WriteToSysLog("ES Startup: Error Removing Volatile(RAM) Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+
+ } /* end if OS_rmfs */
+ }
+ else /* could not un-mount disk */
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error Un-Mounting Volatile(RAM) Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+ }
+
+ } /* end if enough free space */
+ }
+ else /* could not determine free blocks */
+ {
+ /* Log error message -- note that BlocksFree returns the error code in this case */
+ CFE_ES_WriteToSysLog("ES Startup: Error Determining Blocks Free on Volume. EC = 0x%08X\n",
+ (unsigned int)RetStatus);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_VOLATILE_DISK);
+
+ } /* end if BlocksFree */
+
+ } /* end if processor reset */
+
+} /* end function */
+
+/*-------------------------------------------------------------------------
+**
+** Functional Prolog
+**
+** Name: CFE_ES_CreateObjects
+**
+** Purpose: This function reads the es_object_table and performs all of the
+** application layer initialization.
+**----------------------------------------------------------------------------
+*/
+void CFE_ES_CreateObjects(void)
+{
+ int32 ReturnCode;
+ uint16 i;
+ CFE_ES_AppRecord_t *AppRecPtr;
+ CFE_ResourceId_t PendingAppId;
+
+ CFE_ES_WriteToSysLog("ES Startup: Starting Object Creation calls.\n");
+
+ for (i = 0; i < CFE_PLATFORM_ES_OBJECT_TABLE_SIZE; i++)
+ {
+ switch (CFE_ES_ObjectTable[i].ObjectType)
+ {
+ case CFE_ES_DRIVER_TASK:
+ case CFE_ES_CORE_TASK:
+
+ /*
+ ** Allocate an ES AppTable entry
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ PendingAppId = CFE_ResourceId_FindNext(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS,
+ CFE_ES_CheckAppIdSlotUsed);
+ AppRecPtr = CFE_ES_LocateAppRecordByID(CFE_ES_APPID_C(PendingAppId));
+ if (AppRecPtr != NULL)
+ {
+ /*
+ ** Fill out the parameters in the AppStartParams sub-structure
+ */
+ AppRecPtr->Type = CFE_ES_AppType_CORE;
+
+ strncpy(AppRecPtr->AppName, CFE_ES_ObjectTable[i].ObjectName, sizeof(AppRecPtr->AppName) - 1);
+ AppRecPtr->AppName[sizeof(AppRecPtr->AppName) - 1] = '\0';
+
+ /* FileName and EntryPoint is not valid for core apps */
+ AppRecPtr->StartParams.MainTaskInfo.StackSize = CFE_ES_ObjectTable[i].ObjectSize;
+ AppRecPtr->StartParams.MainTaskInfo.Priority = CFE_ES_ObjectTable[i].ObjectPriority;
+ AppRecPtr->StartParams.ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART;
+
+ /*
+ ** Fill out the Task State info
+ */
+ AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN;
+ AppRecPtr->ControlReq.AppTimerMsec = 0;
+
+ CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_RESOURCEID_RESERVED);
+ CFE_ES_Global.LastAppId = PendingAppId;
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** If a slot was found, create the application
+ */
+ if (AppRecPtr != NULL)
+ {
+ /*
+ ** Start the core app main task
+ ** (core apps are already in memory - no loading needed)
+ */
+ ReturnCode = CFE_ES_StartAppTask(
+ &AppRecPtr->MainTaskId, AppRecPtr->AppName, CFE_ES_ObjectTable[i].FuncPtrUnion.MainTaskPtr,
+ &AppRecPtr->StartParams.MainTaskInfo, CFE_ES_APPID_C(PendingAppId));
+
+ /*
+ * Finalize data in the app table entry, which must be done under lock.
+ * This transitions the entry from being RESERVED to the real type,
+ * either MAIN_TASK (success) or returning to INVALID (failure).
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+
+ if (ReturnCode == OS_SUCCESS)
+ {
+ CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId);
+
+ /*
+ ** Increment the Core App counter.
+ */
+ CFE_ES_Global.RegisteredCoreApps++;
+ ReturnCode = CFE_SUCCESS;
+ }
+ else
+ {
+ /* failure mode - just clear the whole app table entry.
+ * This will set the AppType back to CFE_ES_ResourceType_INVALID (0),
+ * as well as clearing any other data that had been written */
+ memset(AppRecPtr, 0, sizeof(*AppRecPtr));
+ }
+
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+ }
+ else
+ {
+ /* appSlot not found -- This should never happen!*/
+ CFE_ES_WriteToSysLog("ES Startup: Error, No free application slots available for CORE App!\n");
+ ReturnCode = CFE_ES_ERR_APP_CREATE;
+ }
+
+ if (ReturnCode == CFE_SUCCESS)
+ {
+ /*
+ * CFE_ES_MainTaskSyncDelay() will delay this thread until the
+ * newly-started thread calls CFE_ES_WaitForSystemState()
+ */
+ ReturnCode =
+ CFE_ES_MainTaskSyncDelay(CFE_ES_AppState_RUNNING, CFE_PLATFORM_CORE_MAX_STARTUP_MSEC * 1000);
+ }
+
+ if (ReturnCode != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: OS_TaskCreate error creating core App: %s: EC = 0x%08X\n",
+ CFE_ES_ObjectTable[i].ObjectName, (unsigned int)ReturnCode);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_CORE_APP);
+ }
+ break;
+
+ case CFE_ES_FUNCTION_CALL: /*----------------------------------------------------------*/
+
+ if (CFE_ES_ObjectTable[i].FuncPtrUnion.FunctionPtr != NULL)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Calling %s\n", CFE_ES_ObjectTable[i].ObjectName);
+ /*
+ ** Call the function
+ */
+ ReturnCode = (*CFE_ES_ObjectTable[i].FuncPtrUnion.FunctionPtr)();
+ if (ReturnCode != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES Startup: Error returned when calling function: %s: EC = 0x%08X\n",
+ CFE_ES_ObjectTable[i].ObjectName, (unsigned int)ReturnCode);
+
+ /*
+ ** Delay to allow the message to be read
+ */
+ OS_TaskDelay(CFE_ES_PANIC_DELAY);
+
+ /*
+ ** cFE Cannot continue to start up.
+ */
+ CFE_PSP_Panic(CFE_PSP_PANIC_CORE_APP);
+
+ } /* end if */
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("ES Startup: bad function pointer ( table entry = %d).\n", i);
+ }
+ break;
+
+ case CFE_ES_NULL_ENTRY: /*-------------------------------------------------------*/
+ break;
+ default:
+ break;
+ } /* end switch */
+
+ } /* end for */
+
+ CFE_ES_WriteToSysLog("ES Startup: Finished ES CreateObject table entries.\n");
+}
+
+/*
+** Function: CFE_ES_MainTaskSyncDelay
+**
+** Purpose: Waits for all of the applications that CFE has started thus far to
+** reach the indicated state, by polling the app counters in a delay loop.
+**
+*/
+int32 CFE_ES_MainTaskSyncDelay(uint32 AppStateId, uint32 TimeOutMilliseconds)
+{
+ int32 Status;
+ uint32 i;
+ uint32 WaitTime;
+ uint32 WaitRemaining;
+ uint32 AppNotReadyCounter;
+ CFE_ES_AppRecord_t *AppRecPtr;
+
+ Status = CFE_ES_OPERATION_TIMED_OUT;
+ WaitRemaining = TimeOutMilliseconds;
+ while (true)
+ {
+ AppNotReadyCounter = 0;
+
+ /*
+ * Count the number of apps that are NOT in (at least) in the state requested
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ AppRecPtr = CFE_ES_Global.AppTable;
+ for (i = 0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS; i++)
+ {
+ if (CFE_ES_AppRecordIsUsed(AppRecPtr) && (AppRecPtr->AppState < AppStateId))
+ {
+ ++AppNotReadyCounter;
+ }
+ ++AppRecPtr;
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ if (AppNotReadyCounter == 0)
+ {
+ /* Condition Met */
+ Status = CFE_SUCCESS;
+ break;
+ }
+
+ /*
+ * Must delay and check again
+ */
+ if (WaitRemaining > CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC)
+ {
+ WaitTime = CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC;
+ }
+ else if (WaitRemaining > 0)
+ {
+ WaitTime = WaitRemaining;
+ }
+ else
+ {
+ break;
+ }
+
+ OS_TaskDelay(WaitTime);
+ WaitRemaining -= WaitTime;
+ }
+
+ return Status;
+}
diff --git a/modules/es/fsw/src/cfe_es_start.h b/modules/es/fsw/src/cfe_es_start.h
new file mode 100644
index 000000000..e9408d370
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_start.h
@@ -0,0 +1,94 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * cFE core startup module defines, data types and prototypes.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_START_H
+#define CFE_ES_START_H
+
+/*
+** Include Files
+*/
+#include "cfe_es_api_typedefs.h"
+
+/*
+** Macro Definitions
+*/
+
+/*
+** values of object_type in OS object table
+*/
+#define CFE_ES_NULL_ENTRY 0x00
+#define CFE_ES_CORE_TASK 0x01
+#define CFE_ES_DRIVER_TASK 0x02
+#define CFE_ES_BIN_SEM 0x03
+#define CFE_ES_FUNCTION_CALL 0x04
+#define CFE_ES_MUTEX_SEM 0x05
+
+/*
+** Type Definitions
+*/
+
+typedef int32 (*CFE_ES_EarlyInitFuncPtr_t)(void); /**< \brief Req'd prototype of Early Init Functions */
+
+typedef union
+{
+ CFE_ES_EarlyInitFuncPtr_t FunctionPtr;
+ CFE_ES_TaskEntryFuncPtr_t MainTaskPtr;
+ void * VoidPtr;
+} CFE_ES_FuncPtrUnion_t;
+
+typedef struct
+{
+ uint32 ObjectType; /* The type of object being created */
+ char ObjectName[OS_MAX_API_NAME]; /* task or OS object name */
+ CFE_ES_FuncPtrUnion_t FuncPtrUnion; /* task or function reference */
+ uint32 ObjectPriority; /* object priority */
+ uint32 ObjectSize; /* size used for stack, queue size, etc. */
+ uint32 ObjectFlags; /* extra flags to pass */
+
+} CFE_ES_ObjectTable_t;
+
+/*
+** Exported data
+*/
+extern CFE_ES_ObjectTable_t CFE_ES_ObjectTable[CFE_PLATFORM_ES_OBJECT_TABLE_SIZE]; /* es object table */
+
+/*
+** Function prototypes
+*/
+extern void CFE_ES_CreateObjects(void);
+extern void CFE_ES_SetupResetVariables(uint32 StartType, uint32 StartSubtype, uint32 BootSource);
+extern void CFE_ES_InitializeFileSystems(uint32 StartType);
+extern void CFE_ES_SetupPerfVariables(uint32 ResetType);
+
+#endif /* CFE_ES_START_H */
diff --git a/modules/es/fsw/src/cfe_es_syslog.c b/modules/es/fsw/src/cfe_es_syslog.c
new file mode 100644
index 000000000..7f0376872
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_syslog.c
@@ -0,0 +1,556 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File:
+** cfe_es_syslog.c
+**
+** Purpose:
+** This file implements the cFE Executive Services System Log functions.
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+** Notes:
+**
+** Some functions have EXTERNAL SYNC REQUIREMENTS
+**
+** SysLog functions marked with "Unsync" in their name are designated
+** as functions which are _not_ safe to be called concurrently by multiple
+** threads, and also do _not_ implement any locking or protection. These
+** functions expect the caller to perform all thread synchronization before
+** calling it.
+**
+** The synchronization requirement is across all functions; i.e. it is not safe
+** to call B_Unsync() while A_Unsync() is executing or vice-versa. The external
+** lock must wait until A_Unsync() finishes before calling B_Unsync().
+**
+** The expectation is that the required level of synchronization can be achieved
+** using the existing ES shared data lock. However, if it becomes necessary, this
+** could be replaced with a finer grained syslog-specific lock.
+*/
+
+/*
+** Required header files.
+*/
+#include "cfe_es_module_all.h"
+
+#include
+#include
+#include
+#include
+
+/*******************************************************************
+ *
+ * Non-synchronized helper functions
+ *
+ * An external mutex be held while calling any function marked "Unsync"
+ * These helper functions are local to the ES subsystem and must _NOT_
+ * be exposed to the public API.
+ *
+ * For external access, a public wrapper API must first acquire the
+ * necessary mutex before calling any function marked as "Unsync"
+ *
+ *******************************************************************/
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLogClear --
+ * Clear system log & index
+ * -----------------------------------------------------------------
+ */
+void CFE_ES_SysLogClear_Unsync(void)
+{
+ /*
+ * Note - no need to actually memset the SystemLog buffer -
+ * by simply zeroing out the indices will cover it.
+ */
+
+ CFE_ES_Global.ResetDataPtr->SystemLogWriteIdx = 0;
+ CFE_ES_Global.ResetDataPtr->SystemLogEndIdx = 0;
+ CFE_ES_Global.ResetDataPtr->SystemLogEntryNum = 0;
+
+} /* End of CFE_ES_SysLogClear_Unsync() */
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLogReadStart_Unsync --
+ * Locate start (oldest message) of syslog for reading
+ * -----------------------------------------------------------------
+ */
+void CFE_ES_SysLogReadStart_Unsync(CFE_ES_SysLogReadBuffer_t *Buffer)
+{
+ size_t ReadIdx;
+ size_t EndIdx;
+ size_t TotalSize;
+
+ ReadIdx = CFE_ES_Global.ResetDataPtr->SystemLogWriteIdx;
+ EndIdx = CFE_ES_Global.ResetDataPtr->SystemLogEndIdx;
+ TotalSize = EndIdx;
+
+ /*
+ * Ensure that we start reading at the start of a message
+ * Likely pointing to an old fragment right now -- find the end of it
+ */
+ while (TotalSize > 0 && ReadIdx < EndIdx)
+ {
+ ++ReadIdx;
+ --TotalSize;
+ if (CFE_ES_Global.ResetDataPtr->SystemLog[ReadIdx - 1] == '\n')
+ {
+ break;
+ }
+ }
+
+ Buffer->SizeLeft = TotalSize;
+ Buffer->LastOffset = ReadIdx;
+ Buffer->EndIdx = EndIdx;
+ Buffer->BlockSize = 0;
+} /* End of CFE_ES_SysLogReadStart_Unsync() */
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLogAppend_Unsync() --
+ * Append a preformatted string to the syslog
+ * -----------------------------------------------------------------
+ */
+int32 CFE_ES_SysLogAppend_Unsync(const char *LogString)
+{
+ int32 ReturnCode;
+ size_t MessageLen;
+ size_t WriteIdx;
+ size_t EndIdx;
+
+ /*
+ * Sanity check - Make sure the message length is actually reasonable
+ * Do not allow any single message to consume more than half of the total log
+ * (even this may be overly generous)
+ */
+ MessageLen = strlen(LogString);
+ if (MessageLen > (CFE_PLATFORM_ES_SYSTEM_LOG_SIZE / 2))
+ {
+ MessageLen = CFE_PLATFORM_ES_SYSTEM_LOG_SIZE / 2;
+ ReturnCode = CFE_ES_ERR_SYS_LOG_TRUNCATED;
+ }
+ else
+ {
+ ReturnCode = CFE_SUCCESS;
+ }
+
+ /*
+ * Final sanity check -- do not bother logging empty messages
+ */
+ if (MessageLen == 0)
+ {
+ return ReturnCode;
+ }
+
+ /*
+ * Real work begins --
+ * Take a local snapshot of the head & tail index values
+ *
+ * WriteIdx -> indicates 1 byte past the end of the newest message
+ * (this is the place where new messages will be added)
+ *
+ * EndIdx -> indicates the entire size of the buffer
+ *
+ * Keeping them in local stack variables allows more efficient modification,
+ * since CFE_ES_Global.ResetDataPtr may point directly into a slower NVRAM space.
+ */
+ WriteIdx = CFE_ES_Global.ResetDataPtr->SystemLogWriteIdx;
+ EndIdx = CFE_ES_Global.ResetDataPtr->SystemLogEndIdx;
+
+ /*
+ * Check if the log message plus will fit between
+ * the HeadIdx and the end of the buffer.
+ *
+ * If so, then the process can proceed as normal.
+ *
+ * If not, then the action depends on the setting of "SystemLogMode" which will be
+ * to either discard (default) or overwrite
+ */
+ if ((WriteIdx + MessageLen) > CFE_PLATFORM_ES_SYSTEM_LOG_SIZE)
+ {
+ if (CFE_ES_Global.ResetDataPtr->SystemLogMode == CFE_ES_LogMode_OVERWRITE)
+ {
+ /* In "overwrite" mode, start back at the beginning of the buffer */
+ EndIdx = WriteIdx;
+ WriteIdx = 0;
+ }
+ else if (WriteIdx < (CFE_PLATFORM_ES_SYSTEM_LOG_SIZE - CFE_TIME_PRINTED_STRING_SIZE))
+ {
+ /* In "discard" mode, save as much as possible and discard the remainder of the message
+ * However this should only be done if there is enough room for at least a full timestamp,
+ * otherwise the fragment will not be useful at all. */
+ MessageLen = CFE_PLATFORM_ES_SYSTEM_LOG_SIZE - WriteIdx;
+ ReturnCode = CFE_ES_ERR_SYS_LOG_TRUNCATED;
+ }
+ else
+ {
+ /* entire message must be discarded */
+ MessageLen = 0;
+ }
+ }
+
+ if (MessageLen == 0)
+ {
+ ReturnCode = CFE_ES_ERR_SYS_LOG_FULL;
+ }
+ else
+ {
+ /*
+ * Copy the message in, EXCEPT for the last char which is probably a newline
+ */
+ memcpy(&CFE_ES_Global.ResetDataPtr->SystemLog[WriteIdx], LogString, MessageLen - 1);
+ WriteIdx += MessageLen;
+
+ /*
+ * Ensure the that last-written character is a newline.
+ * This would have been enforced already except in cases where
+ * the message got truncated.
+ */
+ CFE_ES_Global.ResetDataPtr->SystemLog[WriteIdx - 1] = '\n';
+
+ /*
+ * Keep track of the buffer endpoint for future reference
+ */
+ if (WriteIdx > EndIdx)
+ {
+ EndIdx = WriteIdx;
+ }
+
+ /*
+ * Export updated index values to the reset area for next time.
+ */
+ CFE_ES_Global.ResetDataPtr->SystemLogWriteIdx = WriteIdx;
+ CFE_ES_Global.ResetDataPtr->SystemLogEndIdx = EndIdx;
+ ++CFE_ES_Global.ResetDataPtr->SystemLogEntryNum;
+ }
+
+ return (ReturnCode);
+} /* End of CFE_ES_SysLogAppend_Unsync() */
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLogWrite_Unsync() --
+ * Identical to the public CFE_ES_WriteToSysLog() function, except
+ * that it operates in an unsynchronized manner. It can be used in
+ * cases where the appropriate lock is already held for other reasons
+ * -----------------------------------------------------------------
+ */
+int32 CFE_ES_SysLogWrite_Unsync(const char *SpecStringPtr, ...)
+{
+ char TmpString[CFE_ES_MAX_SYSLOG_MSG_SIZE];
+ va_list ArgPtr;
+
+ va_start(ArgPtr, SpecStringPtr);
+ CFE_ES_SysLog_vsnprintf(TmpString, sizeof(TmpString), SpecStringPtr, ArgPtr);
+ va_end(ArgPtr);
+
+ /* Output the entry to the console */
+ OS_printf("%s", TmpString);
+
+ /*
+ * Append to the syslog buffer
+ */
+ return CFE_ES_SysLogAppend_Unsync(TmpString);
+} /* End of CFE_ES_SysLogWrite_Unsync() */
+
+/*******************************************************************
+ *
+ * Additional helper functions
+ *
+ * These functions either perform all necessary synchronization internally,
+ * or they have no specific synchronization requirements
+ *
+ *******************************************************************/
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLogReadData --
+ * Copy data out of the syslog buffer into a local buffer
+ * -----------------------------------------------------------------
+ */
+void CFE_ES_SysLogReadData(CFE_ES_SysLogReadBuffer_t *Buffer)
+{
+ size_t BlockSize;
+
+ Buffer->BlockSize = 0;
+ while (Buffer->SizeLeft > 0 && Buffer->BlockSize < sizeof(Buffer->Data))
+ {
+ /*
+ * The next block to copy will be the SMALLEST of:
+ * - total remaining (un-copied) size of the syslog data
+ * - space available in the output buffer
+ * - space between the current read offset and the end of the log buffer (wrap point)
+ */
+ BlockSize = sizeof(Buffer->Data) - Buffer->BlockSize;
+ if (Buffer->LastOffset >= Buffer->EndIdx)
+ {
+ Buffer->LastOffset = 0;
+ }
+ if ((Buffer->LastOffset + BlockSize) > Buffer->EndIdx)
+ {
+ BlockSize = Buffer->EndIdx - Buffer->LastOffset;
+ }
+ if (BlockSize > Buffer->SizeLeft)
+ {
+ BlockSize = Buffer->SizeLeft;
+ }
+
+ if (BlockSize == 0)
+ {
+ /* should be impossible for this to happen,
+ * just in case, do not spin endlessly */
+ break;
+ }
+
+ memcpy(&Buffer->Data[Buffer->BlockSize], &CFE_ES_Global.ResetDataPtr->SystemLog[Buffer->LastOffset], BlockSize);
+
+ Buffer->BlockSize += BlockSize;
+ Buffer->LastOffset += BlockSize;
+ Buffer->SizeLeft -= BlockSize;
+ }
+} /* End of CFE_ES_SysLogReadData() */
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLogOverwrite() --
+ * Sets the SysLog Write mode (discard or overwrite)
+ * -----------------------------------------------------------------
+ */
+int32 CFE_ES_SysLogSetMode(CFE_ES_LogMode_Enum_t Mode)
+{
+ int32 Status;
+
+ if ((Mode == CFE_ES_LogMode_OVERWRITE) || (Mode == CFE_ES_LogMode_DISCARD))
+ {
+ CFE_ES_Global.ResetDataPtr->SystemLogMode = Mode;
+ Status = CFE_SUCCESS;
+ }
+ else
+ {
+ Status = CFE_ES_BAD_ARGUMENT;
+ }
+
+ return Status;
+} /* End of CFE_ES_SysLogSetMode() */
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLog_vsnprintf() --
+ * Obtain a correctly formatted, time stamped message for output to the syslog,
+ * with arguments similar to the "vsnprintf()" C library API call
+ * -----------------------------------------------------------------
+ */
+void CFE_ES_SysLog_vsnprintf(char *Buffer, size_t BufferSize, const char *SpecStringPtr, va_list ArgPtr)
+{
+ size_t StringLen;
+ size_t MaxLen;
+ int PrintLen;
+
+ /*
+ * write the current time into the TmpString buffer
+ *
+ * Note that CFE_TIME_Print() is expected to produce a string of exactly
+ * CFE_TIME_PRINTED_STRING_SIZE in length.
+ */
+ StringLen = 0;
+ if (BufferSize > (CFE_TIME_PRINTED_STRING_SIZE + 2))
+ {
+ /*
+ * The "useful" buffer size is two less than the supplied buffer -
+ * due to the addition of a newline and a null char to terminate the string
+ */
+ MaxLen = BufferSize - 2;
+
+ CFE_TIME_Print(Buffer, CFE_TIME_GetTime());
+
+ /* using strlen() anyway in case the specific format of CFE_TIME_Print() changes someday */
+ StringLen = strlen(Buffer);
+ if (StringLen < MaxLen)
+ {
+ /* overwrite null with a space to separate the timestamp from the content */
+ Buffer[StringLen] = ' ';
+ ++StringLen;
+
+ /* note that vsnprintf() may return a size larger than the buffer, if it truncates. */
+ PrintLen = vsnprintf(&Buffer[StringLen], BufferSize - StringLen, SpecStringPtr, ArgPtr);
+ if (PrintLen > 0)
+ {
+ StringLen += PrintLen;
+ }
+ }
+
+ if (StringLen > MaxLen)
+ {
+ /* the message got truncated */
+ StringLen = MaxLen;
+ }
+
+ /*
+ * Finalize the output string.
+ *
+ * To be consistent when writing to the console, it is important that
+ * every printed string end in a newline - particularly if the console is buffered.
+ *
+ * The caller may or may not have included a newline in the original format
+ * string. Most callers do, but some do not.
+ *
+ * Strip off all trailing whitespace, and add back a single newline
+ */
+ while (StringLen > 0 && isspace((unsigned char)Buffer[StringLen - 1]))
+ {
+ --StringLen;
+ }
+ Buffer[StringLen] = '\n';
+ ++StringLen;
+ }
+
+ if (BufferSize > 0)
+ {
+ /* always output a null terminated string */
+ Buffer[StringLen] = 0;
+ }
+} /* End of CFE_ES_SysLog_vsnprintf() */
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLog_snprintf() --
+ * Obtain a correctly formatted, time stamped message for output to the syslog,
+ * with arguments similar to the "snprintf()" C library API call
+ * -----------------------------------------------------------------
+ */
+void CFE_ES_SysLog_snprintf(char *Buffer, size_t BufferSize, const char *SpecStringPtr, ...)
+{
+ va_list ArgPtr;
+
+ va_start(ArgPtr, SpecStringPtr);
+ CFE_ES_SysLog_vsnprintf(Buffer, BufferSize, SpecStringPtr, ArgPtr);
+ va_end(ArgPtr);
+} /* End of CFE_ES_SysLog_snprintf() */
+
+/*
+ * -----------------------------------------------------------------
+ * CFE_ES_SysLogDump() --
+ * Writes the contents of the syslog buffer to disk file
+ * -----------------------------------------------------------------
+ */
+int32 CFE_ES_SysLogDump(const char *Filename)
+{
+ osal_id_t fd;
+ int32 Status;
+ size_t WritePos;
+ size_t TotalSize;
+ size_t LastReqSize;
+ union
+ {
+ CFE_ES_SysLogReadBuffer_t LogData;
+ CFE_FS_Header_t FileHdr;
+ } Buffer;
+
+ Status = OS_OpenCreate(&fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
+ if (Status < 0)
+ {
+ CFE_EVS_SendEvent(CFE_ES_SYSLOG2_ERR_EID, CFE_EVS_EventType_ERROR, "Error creating file %s, RC = 0x%08X",
+ Filename, (unsigned int)Status);
+ return CFE_ES_FILE_IO_ERR;
+ } /* end if */
+
+ CFE_FS_InitHeader(&Buffer.FileHdr, CFE_ES_SYS_LOG_DESC, CFE_FS_SubType_ES_SYSLOG);
+
+ TotalSize = 0;
+ LastReqSize = sizeof(CFE_FS_Header_t);
+ Status = CFE_FS_WriteHeader(fd, &Buffer.FileHdr);
+ if (Status >= 0)
+ {
+ TotalSize += Status;
+
+ /*
+ * Get a snapshot of the buffer pointers and read the first block of
+ * data while locked - ensuring that nothing additional can be written
+ * into the syslog buffer while getting the first block of log data.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ CFE_ES_SysLogReadStart_Unsync(&Buffer.LogData);
+ CFE_ES_SysLogReadData(&Buffer.LogData);
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ while (Buffer.LogData.BlockSize > 0)
+ {
+ WritePos = 0;
+ while (WritePos < Buffer.LogData.BlockSize)
+ {
+ LastReqSize = Buffer.LogData.BlockSize - WritePos;
+ Status = OS_write(fd, &Buffer.LogData.Data[WritePos], LastReqSize);
+ if (Status <= 0)
+ {
+ break;
+ } /* end if */
+
+ WritePos += Status;
+ TotalSize += Status;
+ }
+
+ if (Status <= 0)
+ {
+ break;
+ }
+
+ /*
+ * _NOT_ taking the lock for subsequent reads --
+ *
+ * All syslog index values use the local snapshots that were taken earlier.
+ * (The shared memory index values are not referenced on subsequent reads)
+ *
+ * If a new syslog message _does_ get written while this is in progress, it
+ * should be writing to a different part of the syslog buffer anyway, and
+ * probably will not overwrite the data about to be read here.
+ *
+ * There is still a possibility of a "flood" of syslogs coming in which would
+ * potentially overwrite unread data and cause message loss/corruption. However
+ * taking a lock here will not alleviate that situation - this means that the
+ * buffer simply isn't big enough.
+ */
+ CFE_ES_SysLogReadData(&Buffer.LogData);
+ }
+ }
+
+ OS_close(fd);
+
+ if (Status <= 0)
+ {
+ CFE_ES_FileWriteByteCntErr(Filename, LastReqSize, Status);
+ Status = CFE_ES_FILE_IO_ERR;
+ }
+ else
+ {
+ CFE_EVS_SendEvent(CFE_ES_SYSLOG2_EID, CFE_EVS_EventType_DEBUG, "%s written:Size=%lu,Entries=%u", Filename,
+ (unsigned long)TotalSize,
+ (unsigned int)CFE_ES_Global.TaskData.HkPacket.Payload.SysLogEntries);
+ Status = CFE_SUCCESS;
+ }
+
+ return Status;
+
+} /* End of CFE_ES_SysLogDump() */
+
+/* end of file */
diff --git a/modules/es/fsw/src/cfe_es_task.c b/modules/es/fsw/src/cfe_es_task.c
new file mode 100644
index 000000000..5c2f28301
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_task.c
@@ -0,0 +1,2077 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/*
+** File: cfe_es_task.c
+**
+** Purpose:
+** cFE Executive Services (ES) task
+**
+** References:
+** Flight Software Branch C Coding Standard Version 1.0a
+** cFE Flight Software Application Developers Guide
+**
+** Notes:
+**
+*/
+
+/*
+** Includes
+*/
+#include "cfe_es_module_all.h"
+
+#include "cfe_version.h"
+#include "target_config.h"
+
+#include
+
+/*
+** Defines
+*/
+#define CFE_ES_PERF_TRIGGERMASK_INT_SIZE \
+ (sizeof(CFE_ES_Global.ResetDataPtr->Perf.MetaData.TriggerMask) / sizeof(uint32))
+#define CFE_ES_PERF_TRIGGERMASK_EXT_SIZE \
+ (sizeof(CFE_ES_Global.TaskData.HkPacket.Payload.PerfTriggerMask) / sizeof(uint32))
+#define CFE_ES_PERF_FILTERMASK_INT_SIZE (sizeof(CFE_ES_Global.ResetDataPtr->Perf.MetaData.FilterMask) / sizeof(uint32))
+#define CFE_ES_PERF_FILTERMASK_EXT_SIZE \
+ (sizeof(CFE_ES_Global.TaskData.HkPacket.Payload.PerfFilterMask) / sizeof(uint32))
+
+/*
+** This define should be put in the OS API headers -- Right now it matches what the OS API uses
+*/
+#define OS_MAX_PRIORITY 255
+
+/*
+** Executive Services (ES) task global data.
+*/
+CFE_ES_TaskData_t CFE_ES_TaskData;
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_TaskMain() -- Task entry point and main process loop */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_ES_TaskMain(void)
+{
+ int32 Status;
+ uint32 AppRunStatus = CFE_ES_RunStatus_APP_RUN;
+ CFE_SB_Buffer_t *SBBufPtr;
+
+ /*
+ ** Performance Time Stamp Entry
+ */
+ CFE_ES_PerfLogEntry(CFE_MISSION_ES_MAIN_PERF_ID);
+
+ /*
+ ** Perform task specific initialization.
+ */
+ Status = CFE_ES_TaskInit();
+ if (Status != CFE_SUCCESS)
+ {
+ /*
+ ** Create a syslog entry
+ */
+ CFE_ES_WriteToSysLog("ES:Application Init Failed,RC=0x%08X\n", (unsigned int)Status);
+
+ /*
+ ** Allow Core App to Exit
+ */
+ AppRunStatus = CFE_ES_RunStatus_CORE_APP_INIT_ERROR;
+
+ } /* end if */
+
+ /*
+ * Wait for other apps to start.
+ * It is important that the core apps are present before this starts receiving
+ * messages from the command pipe, as some of those handlers might depend on
+ * the other core apps.
+ */
+ CFE_ES_WaitForSystemState(CFE_ES_SystemState_CORE_READY, CFE_PLATFORM_CORE_MAX_STARTUP_MSEC);
+
+ /*
+ ** Main process loop
+ */
+ while (AppRunStatus == CFE_ES_RunStatus_APP_RUN)
+ {
+ /*
+ ** Increment the main task execution counter
+ ** This is normally done in the CFE_ES_RunLoop call, but
+ ** currently CFE Child tasks and the cFE core tasks do not
+ ** use the RunLoop call.
+ */
+ CFE_ES_IncrementTaskCounter();
+
+ /*
+ ** Performance Time Stamp Exit
+ */
+ CFE_ES_PerfLogExit(CFE_MISSION_ES_MAIN_PERF_ID);
+
+ /*
+ ** Wait for the next Software Bus message.
+ */
+ Status = CFE_SB_ReceiveBuffer(&SBBufPtr, CFE_ES_Global.TaskData.CmdPipe, CFE_SB_PEND_FOREVER);
+
+ /*
+ ** Performance Time Stamp Entry
+ */
+ CFE_ES_PerfLogEntry(CFE_MISSION_ES_MAIN_PERF_ID);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /*
+ ** Process message.
+ */
+ CFE_ES_TaskPipe(SBBufPtr);
+
+ /*
+ * Wake up the background task, which includes the
+ * scanning of the ES app table for entries that may need cleanup
+ */
+ CFE_ES_BackgroundWakeup();
+ }
+ else
+ {
+ /*
+ ** SB Error: Write a SysLog Message
+ */
+ CFE_ES_WriteToSysLog("ES:Error reading cmd pipe,RC=0x%08X\n", (unsigned int)Status);
+
+ /*
+ ** Allow Core App to Exit
+ */
+ AppRunStatus = CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR;
+
+ } /* end if */
+
+ } /* end while */
+
+ /*
+ ** Performance Time Stamp Exit
+ */
+ CFE_ES_PerfLogExit(CFE_MISSION_ES_MAIN_PERF_ID);
+
+ /*
+ ** Exit the application, CFE_ES_ExitApp will not return.
+ */
+ CFE_ES_ExitApp(AppRunStatus);
+
+} /* End of CFE_ES_TaskMain() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_FindConfigKeyValue() -- Find value for given config key */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+const char *CFE_ES_FindConfigKeyValue(const CFE_ConfigKeyValue_t *ConfigList, const char *KeyName)
+{
+ const char *ValuePtr;
+
+ ValuePtr = NULL;
+ if (KeyName != NULL && ConfigList != NULL)
+ {
+ while (ConfigList->Key != NULL)
+ {
+ if (strcmp(KeyName, ConfigList->Key) == 0)
+ {
+ ValuePtr = ConfigList->Value;
+ break;
+ }
+
+ ++ConfigList;
+ }
+ }
+
+ return ValuePtr;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_GenerateSingleVersionEvent() -- Send CFE_ES_VERSION_INF_EID */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_GenerateSingleVersionEvent(const char *ModuleType, const char *ModuleName)
+{
+ int32 Status;
+ const char *VersionString;
+
+ /* The mission version which should appear in the version list under the mission name */
+ VersionString = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.ModuleVersionList, ModuleName);
+
+ /* If NULL that means the source code was either uncontrolled or there was no way to determine its version */
+ if (VersionString == NULL)
+ {
+ VersionString = "[unknown]";
+ }
+
+ /*
+ * Advertise the mission version information
+ */
+ Status = CFE_EVS_SendEvent(CFE_ES_VERSION_INF_EID, CFE_EVS_EventType_INFORMATION, "Version Info: %s %s, version %s",
+ ModuleType, ModuleName, VersionString);
+
+ return Status;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_GenerateVersionEvents() -- Send CFE_ES_VERSION_INF_EID's */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_ES_GenerateVersionEvents(void)
+{
+ int32 Status;
+ CFE_ConfigName_t * ModuleNamePtr;
+ CFE_StaticModuleLoadEntry_t *StaticModulePtr;
+
+ /*
+ * Advertise the mission version information
+ */
+ Status = CFE_ES_GenerateSingleVersionEvent("Mission", GLOBAL_CONFIGDATA.MissionName);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Error sending mission version event:RC=0x%08X\n", (unsigned int)Status);
+ }
+
+ /*
+ * Also Advertise the version information for all statically-linked core modules.
+ * Send a separate CFE_ES_VERSION_INF_EID for every component.
+ */
+ ModuleNamePtr = GLOBAL_CONFIGDATA.CoreModuleList;
+ if (ModuleNamePtr != NULL)
+ {
+ while (Status == CFE_SUCCESS && ModuleNamePtr->Name != NULL)
+ {
+ Status = CFE_ES_GenerateSingleVersionEvent("Core Module", ModuleNamePtr->Name);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Error sending core module version event:RC=0x%08X\n", (unsigned int)Status);
+ }
+ ++ModuleNamePtr;
+ }
+ }
+
+ /*
+ * Advertise PSP module versions
+ */
+ StaticModulePtr = GLOBAL_CONFIGDATA.PspModuleList;
+ if (StaticModulePtr != NULL)
+ {
+ while (Status == CFE_SUCCESS && StaticModulePtr->Name != NULL)
+ {
+ Status = CFE_ES_GenerateSingleVersionEvent("PSP Module", StaticModulePtr->Name);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Error sending PSP module version event:RC=0x%08X\n", (unsigned int)Status);
+ }
+ ++StaticModulePtr;
+ }
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_GenerateBuildInfoEvents() -- Send CFE_ES_BUILD_INF_EID */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_ES_GenerateBuildInfoEvents(void)
+{
+ int32 Status;
+ const char *BuildDate;
+ const char *BuildUser;
+ const char *BuildHost;
+
+ BuildDate = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.BuildEnvironment, "BUILDDATE");
+ BuildUser = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.BuildEnvironment, "BUILDUSER");
+ BuildHost = CFE_ES_FindConfigKeyValue(GLOBAL_CONFIGDATA.BuildEnvironment, "BUILDHOST");
+
+ /* Ensure all strings are set to something non-NULL */
+ if (BuildDate == NULL)
+ {
+ BuildDate = "[unknown]";
+ }
+
+ if (BuildUser == NULL)
+ {
+ BuildUser = "[unknown]";
+ }
+
+ if (BuildHost == NULL)
+ {
+ BuildHost = "[unknown]";
+ }
+
+ Status = CFE_EVS_SendEvent(CFE_ES_BUILD_INF_EID, CFE_EVS_EventType_INFORMATION, "Build %s by %s@%s, config %s",
+ BuildDate, BuildUser, BuildHost, GLOBAL_CONFIGDATA.Config);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Error sending build info event:RC=0x%08X\n", (unsigned int)Status);
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_TaskInit() -- ES task initialization */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_TaskInit(void)
+{
+ int32 Status;
+ uint32 SizeofCfeSegment;
+ cpuaddr CfeSegmentAddr;
+ uint8 VersionNumber[4];
+
+ /*
+ ** Initialize task command execution counters
+ */
+ CFE_ES_Global.TaskData.CommandCounter = 0;
+ CFE_ES_Global.TaskData.CommandErrorCounter = 0;
+
+ /*
+ ** Initialize systemlog to default Power On or Processor Reset mode
+ */
+ if (CFE_ES_GetResetType(NULL) == CFE_PSP_RST_TYPE_POWERON)
+ {
+ CFE_ES_Global.ResetDataPtr->SystemLogMode = CFE_PLATFORM_ES_DEFAULT_POR_SYSLOG_MODE;
+ }
+ else
+ {
+ CFE_ES_Global.ResetDataPtr->SystemLogMode = CFE_PLATFORM_ES_DEFAULT_PR_SYSLOG_MODE;
+ }
+
+ /*
+ ** Register event filter table.
+ */
+ Status = CFE_EVS_Register(NULL, 0, CFE_EVS_EventFilter_BINARY);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Call to CFE_EVS_Register Failed, RC = 0x%08X\n", (unsigned int)Status);
+ return (Status);
+ }
+
+ /*
+ ** Initialize housekeeping packet (clear user data area)
+ */
+ CFE_MSG_Init(&CFE_ES_Global.TaskData.HkPacket.TlmHeader.Msg, CFE_SB_ValueToMsgId(CFE_ES_HK_TLM_MID),
+ sizeof(CFE_ES_Global.TaskData.HkPacket));
+
+ /*
+ ** Initialize single application telemetry packet
+ */
+ CFE_MSG_Init(&CFE_ES_Global.TaskData.OneAppPacket.TlmHeader.Msg, CFE_SB_ValueToMsgId(CFE_ES_APP_TLM_MID),
+ sizeof(CFE_ES_Global.TaskData.OneAppPacket));
+
+ /*
+ ** Initialize memory pool statistics telemetry packet
+ */
+ CFE_MSG_Init(&CFE_ES_Global.TaskData.MemStatsPacket.TlmHeader.Msg, CFE_SB_ValueToMsgId(CFE_ES_MEMSTATS_TLM_MID),
+ sizeof(CFE_ES_Global.TaskData.MemStatsPacket));
+
+ /*
+ ** Create Software Bus message pipe
+ */
+ Status = CFE_SB_CreatePipe(&CFE_ES_Global.TaskData.CmdPipe, CFE_ES_PIPE_DEPTH, CFE_ES_PIPE_NAME);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Cannot Create SB Pipe, RC = 0x%08X\n", (unsigned int)Status);
+ return (Status);
+ }
+
+ /*
+ ** Subscribe to Housekeeping request commands
+ */
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_ES_SEND_HK_MID), CFE_ES_Global.TaskData.CmdPipe);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Cannot Subscribe to HK packet, RC = 0x%08X\n", (unsigned int)Status);
+ return (Status);
+ }
+
+ /*
+ ** Subscribe to ES task ground command packets
+ */
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_ES_CMD_MID), CFE_ES_Global.TaskData.CmdPipe);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Cannot Subscribe to ES ground commands, RC = 0x%08X\n", (unsigned int)Status);
+ return (Status);
+ }
+
+ /*
+ ** Compute the CRC for the cfe core code segment and place
+ ** in ES Housekeeping pkt.
+ */
+ Status = CFE_PSP_GetCFETextSegmentInfo(&CfeSegmentAddr, &SizeofCfeSegment);
+
+ if (Status == CFE_PSP_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.HkPacket.Payload.CFECoreChecksum =
+ CFE_ES_CalculateCRC((void *)(CfeSegmentAddr), SizeofCfeSegment, 0, CFE_MISSION_ES_DEFAULT_CRC);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.HkPacket.Payload.CFECoreChecksum = 0xFFFF;
+ }
+
+ /*
+ ** Initialize the version numbers in the ES Housekeeping pkt
+ */
+ CFE_ES_Global.TaskData.HkPacket.Payload.CFEMajorVersion = CFE_MAJOR_VERSION;
+ CFE_ES_Global.TaskData.HkPacket.Payload.CFEMinorVersion = CFE_MINOR_VERSION;
+ CFE_ES_Global.TaskData.HkPacket.Payload.CFERevision = CFE_REVISION;
+ CFE_ES_Global.TaskData.HkPacket.Payload.CFEMissionRevision = CFE_MISSION_REV;
+
+ OS_GetVersionNumber(VersionNumber);
+ CFE_ES_Global.TaskData.HkPacket.Payload.OSALMajorVersion = VersionNumber[0];
+ CFE_ES_Global.TaskData.HkPacket.Payload.OSALMinorVersion = VersionNumber[1];
+ CFE_ES_Global.TaskData.HkPacket.Payload.OSALRevision = VersionNumber[2];
+ CFE_ES_Global.TaskData.HkPacket.Payload.OSALMissionRevision = VersionNumber[3];
+
+ CFE_PSP_GetVersionNumber(VersionNumber);
+ CFE_ES_Global.TaskData.HkPacket.Payload.PSPMajorVersion = VersionNumber[0];
+ CFE_ES_Global.TaskData.HkPacket.Payload.PSPMinorVersion = VersionNumber[1];
+ CFE_ES_Global.TaskData.HkPacket.Payload.PSPRevision = VersionNumber[2];
+ CFE_ES_Global.TaskData.HkPacket.Payload.PSPMissionRevision = VersionNumber[3];
+
+ /*
+ ** Task startup event message.
+ */
+ Status = CFE_EVS_SendEvent(CFE_ES_INIT_INF_EID, CFE_EVS_EventType_INFORMATION, "cFE ES Initialized");
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Error sending init event:RC=0x%08X\n", (unsigned int)Status);
+ return (Status);
+ }
+
+ Status =
+ CFE_EVS_SendEvent(CFE_ES_INITSTATS_INF_EID, CFE_EVS_EventType_INFORMATION,
+ "cFS Versions: cfe %s, osal %s, psp %s. cFE chksm %d", CFE_SRC_VERSION, OS_GetVersionString(),
+ CFE_PSP_GetVersionString(), (int)CFE_ES_Global.TaskData.HkPacket.Payload.CFECoreChecksum);
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Error sending init stats event:RC=0x%08X\n", (unsigned int)Status);
+ return (Status);
+ }
+
+ /*
+ * Generate all module version and build info events.
+ */
+ CFE_ES_GenerateVersionEvents();
+ CFE_ES_GenerateBuildInfoEvents();
+
+ /*
+ * Initialize the "background task" which is a low priority child task
+ * devoted to maintence duties that do not need to execute on a
+ * strict/precise schedule.
+ */
+ Status = CFE_ES_BackgroundInit();
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("ES:Error initializing background task:RC=0x%08X\n", (unsigned int)Status);
+ return (Status);
+ }
+
+ return (CFE_SUCCESS);
+
+} /* End of CFE_ES_TaskInit() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_TaskPipe() -- Process command pipe message */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_ES_TaskPipe(CFE_SB_Buffer_t *SBBufPtr)
+{
+ CFE_SB_MsgId_t MessageID = CFE_SB_INVALID_MSG_ID;
+ CFE_MSG_FcnCode_t CommandCode = 0;
+
+ CFE_MSG_GetMsgId(&SBBufPtr->Msg, &MessageID);
+ switch (CFE_SB_MsgIdToValue(MessageID))
+ {
+ /*
+ ** Housekeeping telemetry request
+ */
+ case CFE_ES_SEND_HK_MID:
+ CFE_ES_HousekeepingCmd((CFE_MSG_CommandHeader_t *)SBBufPtr);
+ break;
+
+ /*
+ ** ES task ground commands
+ */
+ case CFE_ES_CMD_MID:
+
+ CFE_MSG_GetFcnCode(&SBBufPtr->Msg, &CommandCode);
+ switch (CommandCode)
+ {
+ case CFE_ES_NOOP_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_NoopCmd_t)))
+ {
+ CFE_ES_NoopCmd((CFE_ES_NoopCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_RESET_COUNTERS_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_ResetCountersCmd_t)))
+ {
+ CFE_ES_ResetCountersCmd((CFE_ES_ResetCountersCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_RESTART_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_RestartCmd_t)))
+ {
+ CFE_ES_RestartCmd((CFE_ES_RestartCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_START_APP_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_StartAppCmd_t)))
+ {
+ CFE_ES_StartAppCmd((CFE_ES_StartAppCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_STOP_APP_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_StopAppCmd_t)))
+ {
+ CFE_ES_StopAppCmd((CFE_ES_StopAppCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_RESTART_APP_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_RestartAppCmd_t)))
+ {
+ CFE_ES_RestartAppCmd((CFE_ES_RestartAppCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_RELOAD_APP_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_ReloadAppCmd_t)))
+ {
+ CFE_ES_ReloadAppCmd((CFE_ES_ReloadAppCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_QUERY_ONE_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_QueryOneCmd_t)))
+ {
+ CFE_ES_QueryOneCmd((CFE_ES_QueryOneCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_QUERY_ALL_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_QueryAllCmd_t)))
+ {
+ CFE_ES_QueryAllCmd((CFE_ES_QueryAllCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_QUERY_ALL_TASKS_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_QueryAllTasksCmd_t)))
+ {
+ CFE_ES_QueryAllTasksCmd((CFE_ES_QueryAllTasksCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_CLEAR_SYSLOG_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_ClearSysLogCmd_t)))
+ {
+ CFE_ES_ClearSysLogCmd((CFE_ES_ClearSysLogCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_WRITE_SYSLOG_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_WriteSysLogCmd_t)))
+ {
+ CFE_ES_WriteSysLogCmd((CFE_ES_WriteSysLogCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_OVER_WRITE_SYSLOG_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_OverWriteSysLogCmd_t)))
+ {
+ CFE_ES_OverWriteSysLogCmd((CFE_ES_OverWriteSysLogCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_CLEAR_ER_LOG_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_ClearERLogCmd_t)))
+ {
+ CFE_ES_ClearERLogCmd((CFE_ES_ClearERLogCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_WRITE_ER_LOG_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_WriteERLogCmd_t)))
+ {
+ CFE_ES_WriteERLogCmd((CFE_ES_WriteERLogCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_START_PERF_DATA_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_StartPerfDataCmd_t)))
+ {
+ CFE_ES_StartPerfDataCmd((CFE_ES_StartPerfDataCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_STOP_PERF_DATA_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_StopPerfDataCmd_t)))
+ {
+ CFE_ES_StopPerfDataCmd((CFE_ES_StopPerfDataCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_SET_PERF_FILTER_MASK_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_SetPerfFilterMaskCmd_t)))
+ {
+ CFE_ES_SetPerfFilterMaskCmd((CFE_ES_SetPerfFilterMaskCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_SET_PERF_TRIGGER_MASK_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_SetPerfTriggerMaskCmd_t)))
+ {
+ CFE_ES_SetPerfTriggerMaskCmd((CFE_ES_SetPerfTriggerMaskCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_RESET_PR_COUNT_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_ResetPRCountCmd_t)))
+ {
+ CFE_ES_ResetPRCountCmd((CFE_ES_ResetPRCountCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_SET_MAX_PR_COUNT_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_SetMaxPRCountCmd_t)))
+ {
+ CFE_ES_SetMaxPRCountCmd((CFE_ES_SetMaxPRCountCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_DELETE_CDS_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_DeleteCDSCmd_t)))
+ {
+ CFE_ES_DeleteCDSCmd((CFE_ES_DeleteCDSCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_SEND_MEM_POOL_STATS_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_SendMemPoolStatsCmd_t)))
+ {
+ CFE_ES_SendMemPoolStatsCmd((CFE_ES_SendMemPoolStatsCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_ES_DUMP_CDS_REGISTRY_CC:
+ if (CFE_ES_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_ES_DumpCDSRegistryCmd_t)))
+ {
+ CFE_ES_DumpCDSRegistryCmd((CFE_ES_DumpCDSRegistryCmd_t *)SBBufPtr);
+ }
+ break;
+
+ default:
+ CFE_EVS_SendEvent(CFE_ES_CC1_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Invalid ground command code: ID = 0x%X, CC = %d",
+ (unsigned int)CFE_SB_MsgIdToValue(MessageID), (int)CommandCode);
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ break;
+ }
+ break;
+
+ default:
+
+ CFE_EVS_SendEvent(CFE_ES_MID_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid command pipe message ID: 0x%X",
+ (unsigned int)CFE_SB_MsgIdToValue(MessageID));
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ break;
+ }
+
+} /* End of CFE_ES_TaskPipe() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_HousekeepingCmd() -- On-board command (HK request) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_HousekeepingCmd(const CFE_MSG_CommandHeader_t *data)
+{
+ OS_heap_prop_t HeapProp;
+ int32 stat;
+ uint32 PerfIdx;
+
+ /*
+ ** Get command execution counters, system log entry count & bytes used.
+ */
+ CFE_ES_Global.TaskData.HkPacket.Payload.CommandCounter = CFE_ES_Global.TaskData.CommandCounter;
+ CFE_ES_Global.TaskData.HkPacket.Payload.CommandErrorCounter = CFE_ES_Global.TaskData.CommandErrorCounter;
+
+ CFE_ES_Global.TaskData.HkPacket.Payload.SysLogBytesUsed =
+ CFE_ES_MEMOFFSET_C(CFE_ES_Global.ResetDataPtr->SystemLogEndIdx);
+ CFE_ES_Global.TaskData.HkPacket.Payload.SysLogSize = CFE_ES_MEMOFFSET_C(CFE_PLATFORM_ES_SYSTEM_LOG_SIZE);
+ CFE_ES_Global.TaskData.HkPacket.Payload.SysLogEntries = CFE_ES_Global.ResetDataPtr->SystemLogEntryNum;
+ CFE_ES_Global.TaskData.HkPacket.Payload.SysLogMode = CFE_ES_Global.ResetDataPtr->SystemLogMode;
+
+ CFE_ES_Global.TaskData.HkPacket.Payload.ERLogIndex = CFE_ES_Global.ResetDataPtr->ERLogIndex;
+ CFE_ES_Global.TaskData.HkPacket.Payload.ERLogEntries = CFE_ES_Global.ResetDataPtr->ERLogEntries;
+
+ CFE_ES_Global.TaskData.HkPacket.Payload.RegisteredCoreApps = CFE_ES_Global.RegisteredCoreApps;
+ CFE_ES_Global.TaskData.HkPacket.Payload.RegisteredExternalApps = CFE_ES_Global.RegisteredExternalApps;
+ CFE_ES_Global.TaskData.HkPacket.Payload.RegisteredTasks = CFE_ES_Global.RegisteredTasks;
+ CFE_ES_Global.TaskData.HkPacket.Payload.RegisteredLibs = CFE_ES_Global.RegisteredLibs;
+
+ CFE_ES_Global.TaskData.HkPacket.Payload.ResetType = CFE_ES_Global.ResetDataPtr->ResetVars.ResetType;
+ CFE_ES_Global.TaskData.HkPacket.Payload.ResetSubtype = CFE_ES_Global.ResetDataPtr->ResetVars.ResetSubtype;
+ CFE_ES_Global.TaskData.HkPacket.Payload.ProcessorResets = CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount;
+ CFE_ES_Global.TaskData.HkPacket.Payload.MaxProcessorResets =
+ CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount;
+ CFE_ES_Global.TaskData.HkPacket.Payload.BootSource = CFE_ES_Global.ResetDataPtr->ResetVars.BootSource;
+
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfState = CFE_ES_Global.ResetDataPtr->Perf.MetaData.State;
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfMode = CFE_ES_Global.ResetDataPtr->Perf.MetaData.Mode;
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfTriggerCount = CFE_ES_Global.ResetDataPtr->Perf.MetaData.TriggerCount;
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfDataStart = CFE_ES_Global.ResetDataPtr->Perf.MetaData.DataStart;
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfDataEnd = CFE_ES_Global.ResetDataPtr->Perf.MetaData.DataEnd;
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfDataCount = CFE_ES_Global.ResetDataPtr->Perf.MetaData.DataCount;
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfDataToWrite = CFE_ES_GetPerfLogDumpRemaining();
+
+ /*
+ * Fill out the perf trigger/filter mask objects
+ * The entire array in the HK payload object (external size) must be filled,
+ * to avoid sending garbage data.
+ *
+ * If it is larger than what the platform supports (internal size), it will
+ * be padded with 0's
+ *
+ * If it is smaller than what the platform supports, then truncate.
+ */
+ for (PerfIdx = 0; PerfIdx < CFE_ES_PERF_TRIGGERMASK_EXT_SIZE; ++PerfIdx)
+ {
+ if (PerfIdx < CFE_ES_PERF_TRIGGERMASK_INT_SIZE)
+ {
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfTriggerMask[PerfIdx] =
+ CFE_ES_Global.ResetDataPtr->Perf.MetaData.TriggerMask[PerfIdx];
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfTriggerMask[PerfIdx] = 0;
+ }
+ }
+
+ for (PerfIdx = 0; PerfIdx < CFE_ES_PERF_FILTERMASK_EXT_SIZE; ++PerfIdx)
+ {
+ if (PerfIdx < CFE_ES_PERF_FILTERMASK_INT_SIZE)
+ {
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfFilterMask[PerfIdx] =
+ CFE_ES_Global.ResetDataPtr->Perf.MetaData.FilterMask[PerfIdx];
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.HkPacket.Payload.PerfFilterMask[PerfIdx] = 0;
+ }
+ }
+
+ stat = OS_HeapGetInfo(&HeapProp);
+
+ /*
+ * If retrieving info from OSAL was not successful,
+ * zero out the property struct, so all sizes will
+ * in turn be reported in telemetry as 0.
+ */
+ if (stat != OS_SUCCESS)
+ {
+ memset(&HeapProp, 0, sizeof(HeapProp));
+ }
+
+ CFE_ES_Global.TaskData.HkPacket.Payload.HeapBytesFree = CFE_ES_MEMOFFSET_C(HeapProp.free_bytes);
+ CFE_ES_Global.TaskData.HkPacket.Payload.HeapBlocksFree = CFE_ES_MEMOFFSET_C(HeapProp.free_blocks);
+ CFE_ES_Global.TaskData.HkPacket.Payload.HeapMaxBlockSize = CFE_ES_MEMOFFSET_C(HeapProp.largest_free_block);
+
+ /*
+ ** Send housekeeping telemetry packet.
+ */
+ CFE_SB_TimeStampMsg(&CFE_ES_Global.TaskData.HkPacket.TlmHeader.Msg);
+ CFE_SB_TransmitMsg(&CFE_ES_Global.TaskData.HkPacket.TlmHeader.Msg, true);
+
+ /*
+ ** This command does not affect the command execution counter.
+ */
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_HousekeepingCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_NoopCmd() -- ES task ground command (NO-OP) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_NoopCmd(const CFE_ES_NoopCmd_t *Cmd)
+{
+ /*
+ ** Advertise the build and version information with the no-op command
+ ** For unit testing purposes, it helps to put this first - the UT
+ ** is checking for the last event sent to be NOOP_INF_EID.
+ */
+ CFE_ES_GenerateBuildInfoEvents();
+
+ /*
+ ** This command will always succeed.
+ */
+ CFE_ES_Global.TaskData.CommandCounter++;
+
+ CFE_EVS_SendEvent(CFE_ES_NOOP_INF_EID, CFE_EVS_EventType_INFORMATION,
+ "No-op command:\n cFS Versions: cfe %s, osal %s, psp %s", CFE_SRC_VERSION, OS_GetVersionString(),
+ CFE_PSP_GetVersionString());
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_NoopCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_ResetCountersCmd() -- ES task ground command (reset counters) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_ResetCountersCmd(const CFE_ES_ResetCountersCmd_t *data)
+{
+ CFE_ES_Global.TaskData.CommandCounter = 0;
+ CFE_ES_Global.TaskData.CommandErrorCounter = 0;
+
+ /*
+ ** This command will always succeed.
+ */
+ CFE_EVS_SendEvent(CFE_ES_RESET_INF_EID, CFE_EVS_EventType_INFORMATION, "Reset Counters command");
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_ResetCountersCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_RestartCmd() -- Restart cFE (may reset processor) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_RestartCmd(const CFE_ES_RestartCmd_t *data)
+{
+ const CFE_ES_RestartCmd_Payload_t *cmd = &data->Payload;
+
+ if ((cmd->RestartType != CFE_PSP_RST_TYPE_PROCESSOR) && (cmd->RestartType != CFE_PSP_RST_TYPE_POWERON))
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_BOOT_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid cFE restart type: %d",
+ (int)cmd->RestartType);
+ }
+ else
+ {
+ /*
+ ** This function will not return.
+ */
+ CFE_ES_ResetCFE(cmd->RestartType);
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_RestartCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_StartAppCmd() -- Load (and start) single application */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_StartAppCmd(const CFE_ES_StartAppCmd_t *data)
+{
+ const CFE_ES_StartAppCmd_Payload_t *cmd = &data->Payload;
+ CFE_ES_AppId_t AppID;
+ int32 Result;
+ int32 AppEntryLen;
+ int32 AppNameLen;
+ char LocalAppName[OS_MAX_API_NAME];
+ CFE_ES_AppStartParams_t StartParams;
+
+ /* Create local copies of all input strings and ensure null termination */
+ Result = CFE_FS_ParseInputFileNameEx(StartParams.BasicInfo.FileName, cmd->AppFileName,
+ sizeof(StartParams.BasicInfo.FileName), sizeof(cmd->AppFileName), NULL,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_DYNAMIC_MODULE),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_DYNAMIC_MODULE));
+
+ AppEntryLen = CFE_SB_MessageStringGet(StartParams.BasicInfo.InitSymbolName, cmd->AppEntryPoint, NULL,
+ sizeof(StartParams.BasicInfo.InitSymbolName), sizeof(cmd->AppEntryPoint));
+
+ AppNameLen =
+ CFE_SB_MessageStringGet(LocalAppName, cmd->Application, NULL, sizeof(LocalAppName), sizeof(cmd->Application));
+
+ /*
+ ** Verify command parameters
+ */
+ if (Result != CFE_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_START_INVALID_FILENAME_ERR_EID, CFE_EVS_EventType_ERROR,
+ "CFE_ES_StartAppCmd: invalid filename, status=%lx", (unsigned long)Result);
+ }
+ else if (AppEntryLen <= 0)
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_START_INVALID_ENTRY_POINT_ERR_EID, CFE_EVS_EventType_ERROR,
+ "CFE_ES_StartAppCmd: App Entry Point is empty.");
+ }
+ else if (AppNameLen <= 0)
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_START_NULL_APP_NAME_ERR_EID, CFE_EVS_EventType_ERROR,
+ "CFE_ES_StartAppCmd: App Name is empty.");
+ }
+ else if (cmd->Priority > OS_MAX_PRIORITY)
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_START_PRIORITY_ERR_EID, CFE_EVS_EventType_ERROR,
+ "CFE_ES_StartAppCmd: Priority is too large: %d.", (int)cmd->Priority);
+ }
+ else if ((cmd->ExceptionAction != CFE_ES_ExceptionAction_RESTART_APP) &&
+ (cmd->ExceptionAction != CFE_ES_ExceptionAction_PROC_RESTART))
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_START_EXC_ACTION_ERR_EID, CFE_EVS_EventType_ERROR,
+ "CFE_ES_StartAppCmd: Invalid Exception Action: %d.", (int)cmd->ExceptionAction);
+ }
+ else
+ {
+ /* If stack size was provided, use it, otherwise use default. */
+ if (cmd->StackSize == 0)
+ {
+ StartParams.MainTaskInfo.StackSize = CFE_PLATFORM_ES_DEFAULT_STACK_SIZE;
+ }
+ else
+ {
+ StartParams.MainTaskInfo.StackSize = cmd->StackSize;
+ }
+
+ StartParams.MainTaskInfo.Priority = cmd->Priority;
+ StartParams.ExceptionAction = cmd->ExceptionAction;
+
+ /*
+ ** Invoke application loader/startup function.
+ */
+ Result = CFE_ES_AppCreate(&AppID, LocalAppName, &StartParams);
+
+ /*
+ ** Send appropriate event message
+ */
+ if (Result == CFE_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_START_INF_EID, CFE_EVS_EventType_INFORMATION, "Started %s from %s, AppID = %lu",
+ LocalAppName, StartParams.BasicInfo.FileName, CFE_RESOURCEID_TO_ULONG(AppID));
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_START_ERR_EID, CFE_EVS_EventType_ERROR, "Failed to start %s from %s, RC = 0x%08X",
+ LocalAppName, StartParams.BasicInfo.FileName, (unsigned int)Result);
+ }
+
+ } /* End if -- command parameter validation */
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_StartAppCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_StopAppCmd() -- Stop single application */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_StopAppCmd(const CFE_ES_StopAppCmd_t *data)
+{
+ const CFE_ES_AppNameCmd_Payload_t *cmd = &data->Payload;
+ char LocalApp[OS_MAX_API_NAME];
+ CFE_ES_AppId_t AppID;
+ int32 Result;
+
+ CFE_SB_MessageStringGet(LocalApp, (char *)cmd->Application, NULL, sizeof(LocalApp), sizeof(cmd->Application));
+
+ Result = CFE_ES_GetAppIDByName(&AppID, LocalApp);
+
+ if (Result == CFE_SUCCESS)
+ {
+ /*
+ ** Delete the App
+ */
+ Result = CFE_ES_DeleteApp(AppID);
+
+ /*
+ ** Send appropriate event message.
+ */
+ if (Result == CFE_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_STOP_DBG_EID, CFE_EVS_EventType_DEBUG, "Stop Application %s Initiated.", LocalApp);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_STOP_ERR1_EID, CFE_EVS_EventType_ERROR, "Stop Application %s Failed, RC = 0x%08X",
+ LocalApp, (unsigned int)Result);
+ }
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_STOP_ERR2_EID, CFE_EVS_EventType_ERROR,
+ "Stop Application %s, GetAppIDByName failed. RC = 0x%08X.", LocalApp, (unsigned int)Result);
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_StopAppCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_RestartAppCmd() -- Restart a single application */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_RestartAppCmd(const CFE_ES_RestartAppCmd_t *data)
+{
+ const CFE_ES_AppNameCmd_Payload_t *cmd = &data->Payload;
+ char LocalApp[OS_MAX_API_NAME];
+ CFE_ES_AppId_t AppID;
+ int32 Result;
+
+ CFE_SB_MessageStringGet(LocalApp, (char *)cmd->Application, NULL, sizeof(LocalApp), sizeof(cmd->Application));
+
+ Result = CFE_ES_GetAppIDByName(&AppID, LocalApp);
+
+ if (Result == CFE_SUCCESS)
+ {
+ Result = CFE_ES_RestartApp(AppID);
+
+ /*
+ ** Send appropriate event message.
+ */
+ if (Result == CFE_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_RESTART_APP_DBG_EID, CFE_EVS_EventType_DEBUG, "Restart Application %s Initiated.",
+ LocalApp);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_RESTART_APP_ERR1_EID, CFE_EVS_EventType_ERROR,
+ "Restart Application %s Failed, RC = 0x%08X", LocalApp, (unsigned int)Result);
+ }
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_RESTART_APP_ERR2_EID, CFE_EVS_EventType_ERROR,
+ "Restart Application %s, GetAppIDByName failed. RC = 0x%08X.", LocalApp,
+ (unsigned int)Result);
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_ResetAppCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_ReloadAppCmd() -- Reload a single application */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_ReloadAppCmd(const CFE_ES_ReloadAppCmd_t *data)
+{
+ const CFE_ES_AppReloadCmd_Payload_t *cmd = &data->Payload;
+ char LocalApp[OS_MAX_API_NAME];
+ char LocalFileName[OS_MAX_PATH_LEN];
+ CFE_ES_AppId_t AppID;
+ int32 Result;
+
+ CFE_SB_MessageStringGet(LocalApp, (char *)cmd->Application, NULL, sizeof(LocalApp), sizeof(cmd->Application));
+
+ Result = CFE_ES_GetAppIDByName(&AppID, LocalApp);
+
+ if (Result == CFE_SUCCESS)
+ {
+ /* Read input string as a file name for dynamic module */
+ Result = CFE_FS_ParseInputFileNameEx(LocalFileName, cmd->AppFileName, sizeof(LocalFileName),
+ sizeof(cmd->AppFileName), NULL,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_DYNAMIC_MODULE),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_DYNAMIC_MODULE));
+
+ if (Result == CFE_SUCCESS)
+ {
+ Result = CFE_ES_ReloadApp(AppID, LocalFileName);
+ }
+
+ /*
+ ** Send appropriate event message.
+ */
+ if (Result == CFE_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_RELOAD_APP_DBG_EID, CFE_EVS_EventType_DEBUG, "Reload Application %s Initiated.",
+ LocalApp);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_RELOAD_APP_ERR1_EID, CFE_EVS_EventType_ERROR,
+ "Reload Application %s Failed, RC = 0x%08X", LocalApp, (unsigned int)Result);
+ }
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_RELOAD_APP_ERR2_EID, CFE_EVS_EventType_ERROR,
+ "Reload Application %s, GetAppIDByName failed. RC = 0x%08X.", LocalApp, (unsigned int)Result);
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_ReloadAppCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_QueryOneCmd() -- Request tlm packet with single app data */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_QueryOneCmd(const CFE_ES_QueryOneCmd_t *data)
+{
+ const CFE_ES_AppNameCmd_Payload_t *cmd = &data->Payload;
+ char LocalApp[OS_MAX_API_NAME];
+ union
+ {
+ CFE_ES_AppId_t AppId;
+ CFE_ES_LibId_t LibId;
+ CFE_ResourceId_t ResourceID;
+ } IdBuf;
+ int32 Result;
+
+ CFE_SB_MessageStringGet(LocalApp, (char *)cmd->Application, NULL, sizeof(LocalApp), sizeof(cmd->Application));
+
+ Result = CFE_ES_GetAppIDByName(&IdBuf.AppId, LocalApp);
+ if (Result == CFE_ES_ERR_NAME_NOT_FOUND)
+ {
+ /* Also check for a matching library name */
+ Result = CFE_ES_GetLibIDByName(&IdBuf.LibId, LocalApp);
+ }
+
+ if (Result == CFE_SUCCESS)
+ {
+ Result = CFE_ES_GetModuleInfo(&(CFE_ES_Global.TaskData.OneAppPacket.Payload.AppInfo), IdBuf.ResourceID);
+ }
+
+ /*
+ ** Send appropriate event message...
+ */
+ if (Result == CFE_SUCCESS)
+ {
+ /*
+ ** Send application status telemetry packet.
+ */
+ CFE_SB_TimeStampMsg(&CFE_ES_Global.TaskData.OneAppPacket.TlmHeader.Msg);
+ Result = CFE_SB_TransmitMsg(&CFE_ES_Global.TaskData.OneAppPacket.TlmHeader.Msg, true);
+ if (Result == CFE_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_ONE_APP_EID, CFE_EVS_EventType_DEBUG, "Sent %s application data", LocalApp);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_ONE_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to send %s application data, RC = 0x%08X", LocalApp, (unsigned int)Result);
+ }
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_ONE_APPID_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to send %s application data: GetAppIDByName Failed, RC = 0x%08X", LocalApp,
+ (unsigned int)Result);
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_QueryOneCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_QueryAllCmd() -- Write all app data to file */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_QueryAllCmd(const CFE_ES_QueryAllCmd_t *data)
+{
+ CFE_FS_Header_t FileHeader;
+ osal_id_t FileDescriptor = OS_OBJECT_ID_UNDEFINED;
+ uint32 i;
+ uint32 EntryCount = 0;
+ uint32 FileSize = 0;
+ int32 Result;
+ CFE_ES_AppInfo_t AppInfo;
+ const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload;
+ char QueryAllFilename[OS_MAX_PATH_LEN];
+ CFE_ResourceId_t ResourceList[CFE_ES_QUERY_ALL_MAX_ENTRIES];
+ uint32 NumResources;
+ CFE_ES_AppRecord_t * AppRecPtr;
+ CFE_ES_LibRecord_t * LibRecPtr;
+
+ /*
+ * Collect list of active resource IDs.
+ *
+ * This should be done while locked, but the actual writing
+ * of the AppInfo data should be done while NOT locked.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ NumResources = 0;
+ AppRecPtr = CFE_ES_Global.AppTable;
+ for (i = 0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS && NumResources < CFE_ES_QUERY_ALL_MAX_ENTRIES; ++i)
+ {
+ if (CFE_ES_AppRecordIsUsed(AppRecPtr))
+ {
+ ResourceList[NumResources] = CFE_RESOURCEID_UNWRAP(CFE_ES_AppRecordGetID(AppRecPtr));
+ ++NumResources;
+ }
+ ++AppRecPtr;
+ }
+ LibRecPtr = CFE_ES_Global.LibTable;
+ for (i = 0; i < CFE_PLATFORM_ES_MAX_LIBRARIES && NumResources < CFE_ES_QUERY_ALL_MAX_ENTRIES; ++i)
+ {
+ if (CFE_ES_LibRecordIsUsed(LibRecPtr))
+ {
+ ResourceList[NumResources] = CFE_RESOURCEID_UNWRAP(CFE_ES_LibRecordGetID(LibRecPtr));
+ ++NumResources;
+ }
+ ++LibRecPtr;
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /* Copy the commanded filename, using default if unspecified */
+ Result = CFE_FS_ParseInputFileNameEx(QueryAllFilename, CmdPtr->FileName, sizeof(QueryAllFilename),
+ sizeof(CmdPtr->FileName), CFE_PLATFORM_ES_DEFAULT_APP_LOG_FILE,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Result == CFE_SUCCESS)
+ {
+ /*
+ ** Check to see if the file already exists
+ */
+ Result = OS_OpenCreate(&FileDescriptor, QueryAllFilename, OS_FILE_FLAG_NONE, OS_READ_ONLY);
+ if (Result >= 0)
+ {
+ OS_close(FileDescriptor);
+ OS_remove(QueryAllFilename);
+ }
+
+ /*
+ ** Create ES task log data file
+ */
+ Result = OS_OpenCreate(&FileDescriptor, QueryAllFilename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE,
+ OS_WRITE_ONLY);
+ }
+
+ if (Result >= 0)
+ {
+ /*
+ ** Initialize cFE file header
+ */
+ CFE_FS_InitHeader(&FileHeader, CFE_ES_APP_LOG_DESC, CFE_FS_SubType_ES_QUERYALL);
+
+ /*
+ ** Output the Standard cFE File Header to the App File
+ */
+ Result = CFE_FS_WriteHeader(FileDescriptor, &FileHeader);
+
+ if (Result != sizeof(CFE_FS_Header_t))
+ {
+ OS_close(FileDescriptor);
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_WRHDR_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to write App Info file, WriteHdr RC = 0x%08X, exp %d", (unsigned int)Result,
+ (int)sizeof(CFE_FS_Header_t));
+ /*
+ * returning "success" here as there is no other recourse;
+ * the full extent of the error recovery has been done
+ */
+ return CFE_SUCCESS;
+ } /* end if */
+
+ /*
+ ** Maintain statistics of amount of data written to file
+ */
+ FileSize += Result;
+
+ /*
+ ** Loop through the ES AppTable for main applications
+ */
+ for (i = 0; i < NumResources; ++i)
+ {
+ /*
+ ** Populate the AppInfo entry
+ */
+ Result = CFE_ES_GetModuleInfo(&AppInfo, ResourceList[i]);
+ if (Result == CFE_SUCCESS)
+ {
+ /*
+ ** Write the local entry to file
+ */
+ Result = OS_write(FileDescriptor, &AppInfo, sizeof(CFE_ES_AppInfo_t));
+ if (Result != sizeof(CFE_ES_AppInfo_t))
+ {
+ OS_close(FileDescriptor);
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_TASKWR_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to write App Info file, Task write RC = 0x%08X, exp %d",
+ (unsigned int)Result, (int)sizeof(CFE_ES_AppInfo_t));
+ /*
+ * returning "success" here as there is no other recourse;
+ * the full extent of the error recovery has been done
+ */
+ return CFE_SUCCESS;
+ } /* end if */
+
+ FileSize += Result;
+ EntryCount++;
+ }
+
+ } /* end for */
+
+ OS_close(FileDescriptor);
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_ALL_APPS_EID, CFE_EVS_EventType_DEBUG,
+ "App Info file written to %s, Entries=%d, FileSize=%d", QueryAllFilename, (int)EntryCount,
+ (int)FileSize);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_OSCREATE_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to write App Info file, OS_OpenCreate RC = 0x%08X", (unsigned int)Result);
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_QueryAllCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_QueryAllTasksCmd() -- Write all Task Data to a file */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_QueryAllTasksCmd(const CFE_ES_QueryAllTasksCmd_t *data)
+{
+ CFE_FS_Header_t FileHeader;
+ osal_id_t FileDescriptor = OS_OBJECT_ID_UNDEFINED;
+ uint32 i;
+ uint32 EntryCount = 0;
+ uint32 FileSize = 0;
+ int32 Result;
+ CFE_ES_TaskInfo_t TaskInfo;
+ const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload;
+ char QueryAllFilename[OS_MAX_PATH_LEN];
+ CFE_ES_TaskId_t TaskList[OS_MAX_TASKS];
+ uint32 NumTasks;
+ CFE_ES_TaskRecord_t * TaskRecPtr;
+
+ /*
+ * Collect list of active task IDs.
+ *
+ * This should be done while locked, but the actual writing
+ * of the AppInfo data should be done while NOT locked.
+ */
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ NumTasks = 0;
+ TaskRecPtr = CFE_ES_Global.TaskTable;
+ for (i = 0; i < OS_MAX_TASKS; ++i)
+ {
+ if (CFE_ES_TaskRecordIsUsed(TaskRecPtr))
+ {
+ TaskList[NumTasks] = CFE_ES_TaskRecordGetID(TaskRecPtr);
+ ++NumTasks;
+ }
+ ++TaskRecPtr;
+ }
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** Copy the commanded filename into local buffer to ensure size limitation and to allow for modification
+ */
+ Result = CFE_FS_ParseInputFileNameEx(QueryAllFilename, CmdPtr->FileName, sizeof(QueryAllFilename),
+ sizeof(CmdPtr->FileName), CFE_PLATFORM_ES_DEFAULT_TASK_LOG_FILE,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Result == CFE_SUCCESS)
+ {
+ /*
+ ** Check to see if the file already exists
+ */
+ Result = OS_OpenCreate(&FileDescriptor, QueryAllFilename, OS_FILE_FLAG_NONE, OS_READ_ONLY);
+ if (Result >= 0)
+ {
+ OS_close(FileDescriptor);
+ OS_remove(QueryAllFilename);
+ }
+
+ /*
+ ** Create ES task log data file
+ */
+ Result = OS_OpenCreate(&FileDescriptor, QueryAllFilename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE,
+ OS_WRITE_ONLY);
+ }
+
+ if (Result >= 0)
+ {
+ /*
+ ** Initialize cFE file header
+ */
+ CFE_FS_InitHeader(&FileHeader, CFE_ES_TASK_LOG_DESC, CFE_FS_SubType_ES_QUERYALLTASKS);
+
+ /*
+ ** Output the Standard cFE File Header to the App File
+ */
+ Result = CFE_FS_WriteHeader(FileDescriptor, &FileHeader);
+
+ if (Result != sizeof(CFE_FS_Header_t))
+ {
+ OS_close(FileDescriptor);
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_TASKINFO_WRHDR_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to write Task Info file, WriteHdr RC = 0x%08X, exp %d", (unsigned int)Result,
+ (int)sizeof(CFE_FS_Header_t));
+ /*
+ * returning "success" here as there is no other recourse;
+ * the full extent of the error recovery has been done
+ */
+ return CFE_SUCCESS;
+ } /* end if */
+
+ /*
+ ** Maintain statistics of amount of data written to file
+ */
+ FileSize += Result;
+
+ /*
+ ** Loop through the ES AppTable for main applications
+ */
+ for (i = 0; i < NumTasks; ++i)
+ {
+ /*
+ ** Populate the AppInfo entry
+ */
+ Result = CFE_ES_GetTaskInfo(&TaskInfo, TaskList[i]);
+ if (Result == CFE_SUCCESS)
+ {
+ /*
+ ** Write the local entry to file
+ */
+ Result = OS_write(FileDescriptor, &TaskInfo, sizeof(CFE_ES_TaskInfo_t));
+ if (Result != sizeof(CFE_ES_TaskInfo_t))
+ {
+ OS_close(FileDescriptor);
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_TASKINFO_WR_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to write Task Info file, Task write RC = 0x%08X, exp %d",
+ (unsigned int)Result, (int)sizeof(CFE_ES_TaskInfo_t));
+ /*
+ * returning "success" here as there is no other recourse;
+ * the full extent of the error recovery has been done
+ */
+ return CFE_SUCCESS;
+ } /* end if */
+
+ FileSize += Result;
+ EntryCount++;
+ }
+
+ } /* end for */
+
+ OS_close(FileDescriptor);
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_TASKINFO_EID, CFE_EVS_EventType_DEBUG,
+ "Task Info file written to %s, Entries=%d, FileSize=%d", QueryAllFilename, (int)EntryCount,
+ (int)FileSize);
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_TASKINFO_OSCREATE_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Failed to write Task Info file, OS_OpenCreate RC = 0x%08X", (unsigned int)Result);
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_QueryAllTasksCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_ClearSysLogCmd() -- Clear executive services system log */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_ClearSysLogCmd(const CFE_ES_ClearSysLogCmd_t *data)
+{
+ /*
+ ** Clear syslog index and memory area
+ */
+
+ CFE_ES_LockSharedData(__func__, __LINE__);
+ CFE_ES_SysLogClear_Unsync();
+ CFE_ES_UnlockSharedData(__func__, __LINE__);
+
+ /*
+ ** This command will always succeed...
+ */
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_SYSLOG1_INF_EID, CFE_EVS_EventType_INFORMATION, "Cleared Executive Services log data");
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_ClearSysLogCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_OverWriteSysLogCmd() -- set syslog mode */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_OverWriteSysLogCmd(const CFE_ES_OverWriteSysLogCmd_t *data)
+{
+ int32 Status;
+ const CFE_ES_OverWriteSysLogCmd_Payload_t *CmdPtr = &data->Payload;
+
+ Status = CFE_ES_SysLogSetMode(CmdPtr->Mode);
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_EVS_SendEvent(CFE_ES_ERR_SYSLOGMODE_EID, CFE_EVS_EventType_ERROR,
+ "Set OverWriteSysLog Command: Invalid Mode setting = %d", (int)CmdPtr->Mode);
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+ else
+ {
+ CFE_EVS_SendEvent(CFE_ES_SYSLOGMODE_EID, CFE_EVS_EventType_DEBUG,
+ "Set OverWriteSysLog Command Received with Mode setting = %d", (int)CmdPtr->Mode);
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+ }
+
+ return CFE_SUCCESS;
+} /* End CFE_ES_OverWriteSysLogCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_WriteSysLogCmd() -- Process Cmd to write ES System Log to file */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_WriteSysLogCmd(const CFE_ES_WriteSysLogCmd_t *data)
+{
+ const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload;
+ int32 Stat;
+ char LogFilename[OS_MAX_PATH_LEN];
+
+ /*
+ ** Copy the filename into local buffer with default name/path/extension if not specified
+ **
+ ** Note even though this fundamentally contains strings, it is written as a binary file with an FS header,
+ ** not as normal text file, so still using the BINARY DATA DUMP category for its default extension.
+ */
+ Stat = CFE_FS_ParseInputFileNameEx(LogFilename, CmdPtr->FileName, sizeof(LogFilename), sizeof(CmdPtr->FileName),
+ CFE_PLATFORM_ES_DEFAULT_SYSLOG_FILE,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Stat != CFE_SUCCESS)
+ {
+ CFE_EVS_SendEvent(CFE_ES_SYSLOG2_ERR_EID, CFE_EVS_EventType_ERROR, "Error parsing file name RC = 0x%08X",
+ (unsigned int)Stat);
+ }
+ else
+ {
+ Stat = CFE_ES_SysLogDump(LogFilename);
+ }
+
+ if (Stat == CFE_SUCCESS)
+ {
+ CFE_ES_Global.TaskData.CommandCounter++;
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ } /* end if */
+
+ return CFE_SUCCESS;
+} /* end CFE_ES_WriteSysLogCmd */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_ClearERLogCmd() -- Clear The exception and reset log. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_ClearERLogCmd(const CFE_ES_ClearERLogCmd_t *data)
+{
+ /*
+ ** Clear ER log data buffer
+ */
+
+ memset(CFE_ES_Global.ResetDataPtr->ERLog, 0, sizeof(CFE_ES_Global.ResetDataPtr->ERLog));
+
+ /*
+ ** Reset ER log buffer index
+ */
+
+ CFE_ES_Global.ResetDataPtr->ERLogIndex = 0;
+
+ /*
+ ** Set Number of Entries in ER log buffer back to zero
+ */
+ CFE_ES_Global.ResetDataPtr->ERLogEntries = 0;
+
+ /*
+ ** This command will always succeed
+ */
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_ERLOG1_INF_EID, CFE_EVS_EventType_INFORMATION, "Cleared ES Exception and Reset Log data");
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_ClearERLogCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_WriteERLogCmd() -- Process Cmd to write exception & reset*/
+/* log to a file. */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_WriteERLogCmd(const CFE_ES_WriteERLogCmd_t *data)
+{
+ const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload;
+ CFE_ES_BackgroundLogDumpGlobal_t * StatePtr;
+ int32 Status;
+
+ StatePtr = &CFE_ES_Global.BackgroundERLogDumpState;
+
+ /* check if pending before overwriting fields in the structure */
+ if (CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite))
+ {
+ Status = CFE_STATUS_REQUEST_ALREADY_PENDING;
+ }
+ else
+ {
+ /* Reset the entire state object (just for good measure, ensure no stale data) */
+ memset(StatePtr, 0, sizeof(*StatePtr));
+
+ /*
+ * Fill out the remainder of meta data.
+ * This data is currently the same for every request
+ */
+ StatePtr->FileWrite.FileSubType = CFE_FS_SubType_ES_ERLOG;
+ snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), CFE_ES_ER_LOG_DESC);
+
+ StatePtr->FileWrite.GetData = CFE_ES_BackgroundERLogFileDataGetter;
+ StatePtr->FileWrite.OnEvent = CFE_ES_BackgroundERLogFileEventHandler;
+
+ /*
+ ** Copy the filename into local buffer with default name/path/extension if not specified
+ */
+ Status = CFE_FS_ParseInputFileNameEx(StatePtr->FileWrite.FileName, CmdPtr->FileName,
+ sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->FileName),
+ CFE_PLATFORM_ES_DEFAULT_ER_LOG_FILE,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite);
+ }
+ }
+
+ if (Status != CFE_SUCCESS)
+ {
+ if (Status == CFE_STATUS_REQUEST_ALREADY_PENDING)
+ {
+ /* Specific event if already pending */
+ CFE_EVS_SendEvent(CFE_ES_ERLOG_PENDING_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Error log write already in progress");
+ }
+ else
+ {
+ /* Some other validation issue e.g. bad file name */
+ CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID, CFE_EVS_EventType_ERROR, "Error creating file, RC = %d",
+ (int)Status);
+ }
+
+ /* background dump did not start, consider this an error */
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandCounter++;
+ }
+
+ return CFE_SUCCESS;
+} /* end CFE_ES_WriteERLogCmd */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_VerifyCmdLength() -- Verify command packet length */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+bool CFE_ES_VerifyCmdLength(CFE_MSG_Message_t *MsgPtr, size_t ExpectedLength)
+{
+ bool result = true;
+ CFE_MSG_Size_t ActualLength = 0;
+ CFE_MSG_FcnCode_t FcnCode = 0;
+ CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID;
+
+ CFE_MSG_GetSize(MsgPtr, &ActualLength);
+
+ /*
+ ** Verify the command packet length
+ */
+ if (ExpectedLength != ActualLength)
+ {
+ CFE_MSG_GetMsgId(MsgPtr, &MsgId);
+ CFE_MSG_GetFcnCode(MsgPtr, &FcnCode);
+
+ CFE_EVS_SendEvent(CFE_ES_LEN_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Invalid msg length: ID = 0x%X, CC = %u, Len = %u, Expected = %u",
+ (unsigned int)CFE_SB_MsgIdToValue(MsgId), (unsigned int)FcnCode, (unsigned int)ActualLength,
+ (unsigned int)ExpectedLength);
+ result = false;
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+
+ return (result);
+
+} /* End of CFE_ES_VerifyCmdLength() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_ResetPRCountCmd() -- ES task ground command */
+/* (Processor Reset Count) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_ResetPRCountCmd(const CFE_ES_ResetPRCountCmd_t *data)
+{
+ /*
+ ** Reset the processor reset count
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.ProcessorResetCount = 0;
+
+ /*
+ ** This command will always succeed.
+ */
+ CFE_EVS_SendEvent(CFE_ES_RESET_PR_COUNT_EID, CFE_EVS_EventType_INFORMATION, "Set Processor Reset Count to Zero");
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_ResetPRCountCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_SetMaxPRCountCmd() -- Set Maximum Processor reset count */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_SetMaxPRCountCmd(const CFE_ES_SetMaxPRCountCmd_t *data)
+{
+ const CFE_ES_SetMaxPRCountCmd_Payload_t *cmd = &data->Payload;
+
+ /*
+ ** Set the MAX Processor reset count
+ */
+ CFE_ES_Global.ResetDataPtr->ResetVars.MaxProcessorResetCount = cmd->MaxPRCount;
+
+ /*
+ ** This command will always succeed.
+ */
+ CFE_EVS_SendEvent(CFE_ES_SET_MAX_PR_COUNT_EID, CFE_EVS_EventType_INFORMATION,
+ "Maximum Processor Reset Count set to: %d", (int)cmd->MaxPRCount);
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_RestartCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_DeleteCDSCmd() -- Delete Specified Critical Data Store */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_DeleteCDSCmd(const CFE_ES_DeleteCDSCmd_t *data)
+{
+ int32 Status;
+ const CFE_ES_DeleteCDSCmd_Payload_t *cmd = &data->Payload;
+ char LocalCdsName[CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN];
+
+ CFE_SB_MessageStringGet(LocalCdsName, (char *)cmd->CdsName, NULL, sizeof(LocalCdsName), sizeof(cmd->CdsName));
+
+ Status = CFE_ES_DeleteCDS(LocalCdsName, false);
+
+ if (Status == CFE_ES_CDS_WRONG_TYPE_ERR)
+ {
+ CFE_EVS_SendEvent(CFE_ES_CDS_DELETE_TBL_ERR_EID, CFE_EVS_EventType_ERROR,
+ "CDS '%s' is a Critical Table CDS. Must be deleted via TBL Command", LocalCdsName);
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+ else if (Status == CFE_ES_CDS_OWNER_ACTIVE_ERR)
+ {
+ CFE_EVS_SendEvent(CFE_ES_CDS_OWNER_ACTIVE_EID, CFE_EVS_EventType_ERROR,
+ "CDS '%s' not deleted because owning app is active", LocalCdsName);
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+ else if (Status == CFE_ES_ERR_NAME_NOT_FOUND)
+ {
+ CFE_EVS_SendEvent(CFE_ES_CDS_NAME_ERR_EID, CFE_EVS_EventType_ERROR, "Unable to locate '%s' in CDS Registry",
+ LocalCdsName);
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+ else if (Status != CFE_SUCCESS)
+ {
+ CFE_EVS_SendEvent(CFE_ES_CDS_DELETE_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Error while deleting '%s' from CDS, See SysLog.(Err=0x%08X)", LocalCdsName,
+ (unsigned int)Status);
+
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+ else
+ {
+ CFE_EVS_SendEvent(CFE_ES_CDS_DELETED_INFO_EID, CFE_EVS_EventType_INFORMATION,
+ "Successfully removed '%s' from CDS", LocalCdsName);
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_DeleteCDSCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_SendMemPoolStatsCmd() -- Telemeter Memory Pool Statistics */
+/* */
+/* Note: The "Application" parameter of the */
+/* CFE_ES_TlmPoolStats_t structure is not used. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_SendMemPoolStatsCmd(const CFE_ES_SendMemPoolStatsCmd_t *data)
+{
+ const CFE_ES_SendMemPoolStatsCmd_Payload_t *Cmd;
+ CFE_ES_MemHandle_t MemHandle;
+ bool ValidHandle;
+
+ Cmd = &data->Payload;
+
+ /* Verify the handle to make sure it is legit */
+ MemHandle = Cmd->PoolHandle;
+ ValidHandle = CFE_ES_ValidateHandle(MemHandle);
+
+ if (ValidHandle)
+ {
+ /* Extract the memory statistics from the memory pool */
+ CFE_ES_GetMemPoolStats(&CFE_ES_Global.TaskData.MemStatsPacket.Payload.PoolStats, MemHandle);
+
+ /* Echo the specified pool handle in the telemetry packet */
+ CFE_ES_Global.TaskData.MemStatsPacket.Payload.PoolHandle = MemHandle;
+
+ /*
+ ** Send memory statistics telemetry packet.
+ */
+ CFE_SB_TimeStampMsg(&CFE_ES_Global.TaskData.MemStatsPacket.TlmHeader.Msg);
+ CFE_SB_TransmitMsg(&CFE_ES_Global.TaskData.MemStatsPacket.TlmHeader.Msg, true);
+
+ CFE_ES_Global.TaskData.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_ES_TLM_POOL_STATS_INFO_EID, CFE_EVS_EventType_DEBUG,
+ "Successfully telemetered memory pool stats for 0x%08lX",
+ CFE_RESOURCEID_TO_ULONG(Cmd->PoolHandle));
+ }
+ else
+ {
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_ES_INVALID_POOL_HANDLE_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Cannot telemeter memory pool stats. Illegal Handle (0x%08lX)",
+ CFE_RESOURCEID_TO_ULONG(Cmd->PoolHandle));
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_SendMemPoolStatsCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_DumpCDSRegistryCmd() -- Dump CDS Registry to a file */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_ES_DumpCDSRegistryCmd(const CFE_ES_DumpCDSRegistryCmd_t *data)
+{
+ CFE_FS_Header_t StdFileHeader;
+ osal_id_t FileDescriptor = OS_OBJECT_ID_UNDEFINED;
+ int32 Status;
+ int16 RegIndex = 0;
+ const CFE_ES_DumpCDSRegistryCmd_Payload_t *CmdPtr = &data->Payload;
+ char DumpFilename[OS_MAX_PATH_LEN];
+ CFE_ES_CDS_RegRec_t * RegRecPtr;
+ CFE_ES_CDSRegDumpRec_t DumpRecord;
+ int32 FileSize = 0;
+ int32 NumEntries = 0;
+
+ /*
+ ** Copy the filename into local buffer with default name/path/extension if not specified
+ */
+ Status = CFE_FS_ParseInputFileNameEx(DumpFilename, CmdPtr->DumpFilename, sizeof(DumpFilename),
+ sizeof(CmdPtr->DumpFilename), CFE_PLATFORM_ES_DEFAULT_CDS_REG_DUMP_FILE,
+ CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_BINARY_DATA_DUMP),
+ CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_BINARY_DATA_DUMP));
+
+ if (Status != OS_SUCCESS)
+ {
+ CFE_EVS_SendEvent(CFE_ES_CREATING_CDS_DUMP_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Error parsing CDS dump filename, Status=0x%08X", (unsigned int)Status);
+ }
+ else
+ {
+ /* Create a new dump file, overwriting anything that may have existed previously */
+ Status =
+ OS_OpenCreate(&FileDescriptor, DumpFilename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
+
+ if (Status != OS_SUCCESS)
+ {
+ CFE_EVS_SendEvent(CFE_ES_CREATING_CDS_DUMP_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Error creating CDS dump file '%s', Status=0x%08X", DumpFilename, (unsigned int)Status);
+ }
+ }
+
+ if (Status == OS_SUCCESS)
+ {
+ /* Initialize the standard cFE File Header for the Dump File */
+ CFE_FS_InitHeader(&StdFileHeader, "CDS_Registry", CFE_FS_SubType_ES_CDS_REG);
+
+ /* Output the Standard cFE File Header to the Dump File */
+ Status = CFE_FS_WriteHeader(FileDescriptor, &StdFileHeader);
+
+ /* Maintain statistics of amount of data written to file */
+ FileSize += Status;
+
+ if (Status == sizeof(CFE_FS_Header_t))
+ {
+ Status = sizeof(CFE_ES_CDSRegDumpRec_t);
+ RegRecPtr = CFE_ES_Global.CDSVars.Registry;
+ while ((RegIndex < CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES) && (Status == sizeof(CFE_ES_CDSRegDumpRec_t)))
+ {
+ /* Check to see if the Registry entry is empty */
+ if (CFE_ES_CDSBlockRecordIsUsed(RegRecPtr))
+ {
+ /* Fill CDS Registry Dump Record with relevant information */
+ memset(&DumpRecord, 0, sizeof(DumpRecord));
+ DumpRecord.Size = CFE_ES_MEMOFFSET_C(CFE_ES_CDSBlockRecordGetUserSize(RegRecPtr));
+ DumpRecord.Handle = CFE_ES_CDSBlockRecordGetID(RegRecPtr);
+ DumpRecord.Table = RegRecPtr->Table;
+ strncpy(DumpRecord.Name, RegRecPtr->Name, sizeof(DumpRecord.Name) - 1);
+
+ /* Output Registry Dump Record to Registry Dump File */
+ Status = OS_write(FileDescriptor, &DumpRecord, sizeof(CFE_ES_CDSRegDumpRec_t));
+
+ FileSize += Status;
+ NumEntries++;
+ }
+
+ /* Look at the next entry in the Registry */
+ ++RegIndex;
+ ++RegRecPtr;
+ }
+
+ if (Status == sizeof(CFE_ES_CDSRegDumpRec_t))
+ {
+ CFE_EVS_SendEvent(CFE_ES_CDS_REG_DUMP_INF_EID, CFE_EVS_EventType_DEBUG,
+ "Successfully dumped CDS Registry to '%s':Size=%d,Entries=%d", DumpFilename,
+ (int)FileSize, (int)NumEntries);
+
+ /* Increment Successful Command Counter */
+ CFE_ES_Global.TaskData.CommandCounter++;
+ }
+ else
+ {
+ CFE_EVS_SendEvent(CFE_ES_CDS_DUMP_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Error writing CDS Registry to '%s', Status=0x%08X", DumpFilename,
+ (unsigned int)Status);
+
+ /* Increment Command Error Counter */
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+ }
+ else
+ {
+ CFE_EVS_SendEvent(CFE_ES_WRITE_CFE_HDR_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Error writing cFE File Header to '%s', Status=0x%08X", DumpFilename,
+ (unsigned int)Status);
+
+ /* Increment Command Error Counter */
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+
+ /* We are done outputting data to the dump file. Close it. */
+ OS_close(FileDescriptor);
+ }
+ else
+ {
+ /* Increment Command Error Counter */
+ CFE_ES_Global.TaskData.CommandErrorCounter++;
+ }
+
+ return CFE_SUCCESS;
+} /* End of CFE_ES_DumpCDSRegistryCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_ES_FileWriteByteCntErr() -- Send event to inform ground that*/
+/* a byte count discrepancy has been*/
+/* detected during the file write */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void CFE_ES_FileWriteByteCntErr(const char *Filename, size_t Requested, int32 Status)
+{
+
+ CFE_EVS_SendEvent(CFE_ES_FILEWRITE_ERR_EID, CFE_EVS_EventType_ERROR,
+ "File write,byte cnt err,file %s,request=%u,status=0x%08x", Filename, (unsigned int)Requested,
+ (unsigned int)Status);
+
+} /* End of CFE_ES_FileWriteByteCntErr() */
+
+/************************/
+/* End of File Comment */
+/************************/
diff --git a/modules/es/fsw/src/cfe_es_task.h b/modules/es/fsw/src/cfe_es_task.h
new file mode 100644
index 000000000..eaf8d7fbf
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_task.h
@@ -0,0 +1,129 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * cFE Executive Services (ES) task header file
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_ES_TASK_H
+#define CFE_ES_TASK_H
+
+/*
+** Includes
+*/
+#include "cfe_es_msg.h"
+
+#include "cfe_es_api_typedefs.h"
+#include "cfe_fs_api_typedefs.h"
+#include "cfe_sb_api_typedefs.h"
+#include "cfe_es_erlog_typedef.h"
+
+/*************************************************************************/
+
+#define CFE_ES_PIPE_NAME "ES_CMD_PIPE"
+#define CFE_ES_PIPE_DEPTH 12
+#define CFE_ES_LIMIT_HK 2
+#define CFE_ES_LIMIT_CMD 4
+
+/*
+** ES File descriptions
+*/
+#define CFE_ES_SYS_LOG_DESC "ES system log data file"
+#define CFE_ES_TASK_LOG_DESC "ES Task Info file"
+#define CFE_ES_APP_LOG_DESC "ES Application Info file"
+#define CFE_ES_ER_LOG_DESC "ES ERlog data file"
+#define CFE_ES_PERF_LOG_DESC "ES Performance data file"
+
+/*
+ * Limit for the total number of entries that may be
+ * produced by a "query all" type command.
+ */
+#define CFE_ES_QUERY_ALL_MAX_ENTRIES (CFE_PLATFORM_ES_MAX_APPLICATIONS + CFE_PLATFORM_ES_MAX_LIBRARIES)
+
+/*************************************************************************/
+/*
+** Type definitions
+*/
+
+/*************************************************************************/
+
+/*
+** ES Task function prototypes
+*/
+void CFE_ES_TaskMain(void);
+int32 CFE_ES_TaskInit(void);
+void CFE_ES_TaskPipe(CFE_SB_Buffer_t *SBBufPtr);
+
+/*
+ * Functions related to the ES background helper task for low-priority tasks
+ */
+int32 CFE_ES_BackgroundInit(void);
+void CFE_ES_BackgroundTask(void);
+void CFE_ES_BackgroundCleanup(void);
+
+/*
+** ES Task message dispatch functions
+*/
+int32 CFE_ES_HousekeepingCmd(const CFE_MSG_CommandHeader_t *data);
+int32 CFE_ES_NoopCmd(const CFE_ES_NoopCmd_t *Cmd);
+int32 CFE_ES_ResetCountersCmd(const CFE_ES_ResetCountersCmd_t *data);
+int32 CFE_ES_RestartCmd(const CFE_ES_RestartCmd_t *data);
+int32 CFE_ES_StartAppCmd(const CFE_ES_StartAppCmd_t *data);
+int32 CFE_ES_StopAppCmd(const CFE_ES_StopAppCmd_t *data);
+int32 CFE_ES_RestartAppCmd(const CFE_ES_RestartAppCmd_t *data);
+int32 CFE_ES_ReloadAppCmd(const CFE_ES_ReloadAppCmd_t *data);
+int32 CFE_ES_QueryOneCmd(const CFE_ES_QueryOneCmd_t *data);
+int32 CFE_ES_QueryAllCmd(const CFE_ES_QueryAllCmd_t *data);
+int32 CFE_ES_QueryAllTasksCmd(const CFE_ES_QueryAllTasksCmd_t *data);
+int32 CFE_ES_ClearSysLogCmd(const CFE_ES_ClearSysLogCmd_t *data);
+int32 CFE_ES_OverWriteSysLogCmd(const CFE_ES_OverWriteSysLogCmd_t *data);
+int32 CFE_ES_WriteSysLogCmd(const CFE_ES_WriteSysLogCmd_t *data);
+int32 CFE_ES_ClearERLogCmd(const CFE_ES_ClearERLogCmd_t *data);
+int32 CFE_ES_WriteERLogCmd(const CFE_ES_WriteERLogCmd_t *data);
+int32 CFE_ES_ResetPRCountCmd(const CFE_ES_ResetPRCountCmd_t *data);
+int32 CFE_ES_SetMaxPRCountCmd(const CFE_ES_SetMaxPRCountCmd_t *data);
+int32 CFE_ES_DeleteCDSCmd(const CFE_ES_DeleteCDSCmd_t *data);
+int32 CFE_ES_StartPerfDataCmd(const CFE_ES_StartPerfDataCmd_t *data);
+int32 CFE_ES_StopPerfDataCmd(const CFE_ES_StopPerfDataCmd_t *data);
+int32 CFE_ES_SetPerfFilterMaskCmd(const CFE_ES_SetPerfFilterMaskCmd_t *data);
+int32 CFE_ES_SetPerfTriggerMaskCmd(const CFE_ES_SetPerfTriggerMaskCmd_t *data);
+int32 CFE_ES_SendMemPoolStatsCmd(const CFE_ES_SendMemPoolStatsCmd_t *data);
+int32 CFE_ES_DumpCDSRegistryCmd(const CFE_ES_DumpCDSRegistryCmd_t *data);
+
+/*
+** Message Handler Helper Functions
+*/
+bool CFE_ES_ValidateHandle(CFE_ES_MemHandle_t Handle);
+bool CFE_ES_VerifyCmdLength(CFE_MSG_Message_t *MsgPtr, size_t ExpectedLength);
+void CFE_ES_FileWriteByteCntErr(const char *Filename, size_t Requested, int32 Status);
+
+/*************************************************************************/
+
+#endif /* CFE_ES_TASK_H */
diff --git a/modules/es/fsw/src/cfe_es_verify.h b/modules/es/fsw/src/cfe_es_verify.h
new file mode 100644
index 000000000..751eb5a0d
--- /dev/null
+++ b/modules/es/fsw/src/cfe_es_verify.h
@@ -0,0 +1,337 @@
+/*
+** GSC-18128-1, "Core Flight Executive Version 6.7"
+**
+** Copyright (c) 2006-2019 United States Government as represented by
+** the Administrator of the National Aeronautics and Space Administration.
+** All Rights Reserved.
+**
+** 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.
+*/
+
+/**
+ * @file
+ *
+ * Purpose:
+ * This header file performs compile time checking for ES configuration
+ * parameters.
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ * cFE Flight Software Application Developers Guide
+ *
+ * Notes:
+ * The upper limits are somewhat arbitrary right now.
+ *
+ */
+
+#ifndef CFE_ES_VERIFY_H
+#define CFE_ES_VERIFY_H
+
+#include
+
+#if CFE_PLATFORM_ES_MAX_APPLICATIONS < 6
+#error CFE_PLATFORM_ES_MAX_APPLICATIONS cannot be less than 6!
+#endif
+
+#if CFE_PLATFORM_ES_MAX_LIBRARIES < 1
+#error CFE_PLATFORM_ES_MAX_LIBRARIES cannot be less than 1!
+#endif
+
+#if CFE_PLATFORM_ES_ER_LOG_ENTRIES < 1
+#error CFE_PLATFORM_ES_ER_LOG_ENTRIES cannot be less than 10!
+#endif
+
+#if CFE_PLATFORM_ES_SYSTEM_LOG_SIZE < 512
+#error CFE_PLATFORM_ES_SYSTEM_LOG_SIZE cannot be less than 512 Bytes!
+#endif
+
+#if CFE_PLATFORM_ES_DEFAULT_STACK_SIZE < 2048
+#error CFE_PLATFORM_ES_DEFAULT_STACK_SIZE cannot be less than 2048 Bytes!
+#endif
+
+/*
+** Number of entries in the ES Object table ( The table that controls core cFE startup )
+*/
+#if CFE_PLATFORM_ES_OBJECT_TABLE_SIZE < 15
+#error CFE_PLATFORM_ES_OBJECT_TABLE_SIZE cannot be less than 15!
+#endif
+
+/*
+** ES Application Control Scan Rate.
+*/
+#if CFE_PLATFORM_ES_APP_SCAN_RATE < 100
+#error CFE_PLATFORM_ES_APP_SCAN_RATE cannot be less than 100 milliseconds!
+#elif CFE_PLATFORM_ES_APP_SCAN_RATE > 20000
+#error CFE_PLATFORM_ES_APP_SCAN_RATE cannot be greater than 20 seconds!
+#endif
+
+/*
+** ES Application Kill Timeout
+*/
+#if CFE_PLATFORM_ES_APP_KILL_TIMEOUT < 1
+#error CFE_PLATFORM_ES_APP_KILL_TIMEOUT cannot be less than 1!
+#elif CFE_PLATFORM_ES_APP_KILL_TIMEOUT > 100
+#error CFE_PLATFORM_ES_APP_KILL_TIMEOUT cannot be greater than 100!
+#endif
+
+/*
+** ES / cFE RAM disk parameters
+*/
+#if CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE < 128
+#error CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE cannot be less than 128!
+#endif
+
+#if CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS < 128
+#error CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS cannot be less than 128!
+#endif
+
+#if CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED < 0
+#error CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED cannot be less than 0!
+#elif CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED > 75
+#error CFE_PLATFORM_ES_RAM_DISK_PERCENT_RESERVED cannot be greater than 75!
+#endif
+
+/*
+** Critical data store size
+*/
+#if CFE_PLATFORM_ES_CDS_SIZE < (8 * 1024)
+#error CFE_PLATFORM_ES_CDS_SIZE cannot be less than 8Kbytes!
+#elif CFE_PLATFORM_ES_CDS_SIZE > UINT32_MAX
+#error CFE_PLATFORM_ES_CDS_SIZE cannot be greater than UINT32_MAX (4 Gigabytes)!
+#endif
+
+/*
+** User Reserved Memory Size.
+*/
+#if CFE_PLATFORM_ES_USER_RESERVED_SIZE < (1 * 1024)
+#error CFE_PLATFORM_ES_USER_RESERVED_SIZE cannot be less than 1Kbytes!
+#elif CFE_PLATFORM_ES_USER_RESERVED_SIZE > UINT32_MAX
+#error CFE_PLATFORM_ES_USER_RESERVED_SIZE cannot be greater than UINT32_MAX (4 Gigabytes)!
+#endif
+
+/*
+** SysLog mode
+*/
+#if CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE < 0
+#error CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE cannot be less than 0!
+#elif CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE > 1
+#error CFE_PLATFORM_ES_DEFAULT_SYSLOG_MODE cannot be greater than 1!
+#endif
+
+/*
+** Maximum number of performance IDs
+*/
+#if CFE_MISSION_ES_PERF_MAX_IDS < 32
+#error CFE_MISSION_ES_PERF_MAX_IDS cannot be less than 32!
+#endif
+
+/*
+** Performance data buffer size
+*/
+#if CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE < 1025
+#error CFE_PLATFORM_ES_PERF_DATA_BUFFER_SIZE cannot be less than 1025 entries!
+#endif
+
+/*
+** Maximum number of Registered CDS blocks
+*/
+#if CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES < 8
+#error CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES cannot be less than 8!
+#endif
+
+/*
+** Maximum number of processor resets before a power-on
+*/
+#if CFE_PLATFORM_ES_MAX_PROCESSOR_RESETS < 0
+#error CFE_PLATFORM_ES_MAX_PROCESSOR_RESETS cannot be less than 0!
+#endif
+
+/*
+** Alignment of ES memory pool
+*/
+#if CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN <= 0
+#error CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN cannot be 0!
+#elif (CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN & (CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN - 1)) != 0
+#error CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN must be a power of 2!
+#endif
+
+/*
+** Intermediate ES Memory Pool Block Sizes
+*/
+#if CFE_PLATFORM_ES_MAX_BLOCK_SIZE < CFE_MISSION_SB_MAX_SB_MSG_SIZE
+#error CFE_PLATFORM_ES_MAX_BLOCK_SIZE must be larger than CFE_MISSION_SB_MAX_SB_MSG_SIZE!
+#endif
+
+#if CFE_PLATFORM_ES_MAX_BLOCK_SIZE < CFE_PLATFORM_TBL_MAX_SNGL_TABLE_SIZE
+#error CFE_PLATFORM_ES_MAX_BLOCK_SIZE must be larger than CFE_PLATFORM_TBL_MAX_SNGL_TABLE_SIZE!
+#endif
+
+#if CFE_PLATFORM_ES_MAX_BLOCK_SIZE < CFE_PLATFORM_TBL_MAX_DBL_TABLE_SIZE
+#error CFE_PLATFORM_ES_MAX_BLOCK_SIZE must be larger than CFE_PLATFORM_TBL_MAX_DBL_TABLE_SIZE!
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_01 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_02
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_01 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_02
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_02 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_03
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_02 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_03
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_03 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_04
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_03 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_04
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_04 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_05
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_04 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_05
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_05 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_06
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_05 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_06
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_06 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_07
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_06 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_07
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_07 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_08
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_07 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_08
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_08 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_09
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_08 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_09
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_09 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_10
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_09 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_10
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_10 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_11
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_10 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_11
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_11 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_12
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_11 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_12
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_12 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_13
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_12 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_13
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_13 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_14
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_13 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_14
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_14 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_15
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_14 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_15
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_15 > CFE_PLATFORM_ES_MEM_BLOCK_SIZE_16
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_15 must be less than CFE_PLATFORM_ES_MEM_BLOCK_SIZE_16
+#endif
+
+#if CFE_PLATFORM_ES_MEM_BLOCK_SIZE_16 > CFE_PLATFORM_ES_MAX_BLOCK_SIZE
+#error CFE_PLATFORM_ES_MEM_BLOCK_SIZE_16 must be less than CFE_PLATFORM_ES_MAX_BLOCK_SIZE
+#endif
+
+/*
+** Intermediate ES Critical Data Store Memory Pool Block Sizes
+*/
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_01 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_02
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_01 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_02
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_02 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_03
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_02 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_03
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_03 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_04
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_03 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_04
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_04 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_05
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_04 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_05
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_05 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_06
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_05 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_06
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_06 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_07
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_06 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_07
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_07 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_08
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_07 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_08
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_08 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_09
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_08 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_09
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_09 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_10
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_09 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_10
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_10 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_11
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_10 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_11
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_11 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_12
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_11 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_12
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_12 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_13
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_12 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_13
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_13 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_14
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_13 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_14
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_14 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_15
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_14 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_15
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_15 > CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_16
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_15 must be less than CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_16
+#endif
+
+#if CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_16 > CFE_PLATFORM_ES_CDS_MAX_BLOCK_SIZE
+#error CFE_PLATFORM_ES_CDS_MEM_BLOCK_SIZE_16 must be less than CFE_PLATFORM_ES_CDS_MAX_BLOCK_SIZE
+#endif
+
+/*
+** Validate task stack size...
+*/
+#if CFE_PLATFORM_ES_START_TASK_STACK_SIZE < 2048
+#error CFE_PLATFORM_ES_START_TASK_STACK_SIZE must be greater than or equal to 2048
+#endif
+
+#if ((CFE_MISSION_MAX_API_LEN % 4) != 0)
+#error CFE_MISSION_MAX_API_LEN must be a multiple of 4
+#endif
+#if ((CFE_MISSION_MAX_PATH_LEN % 4) != 0)
+#error CFE_MISSION_MAX_PATH_LEN must be a multiple of 4
+#endif
+#if ((CFE_MISSION_MAX_FILE_LEN % 4) != 0)
+#error CFE_MISSION_MAX_FILE_LEN must be a multiple of 4
+#endif
+#if ((CFE_MISSION_ES_CDS_MAX_NAME_LENGTH % 4) != 0)
+#error CFE_MISSION_ES_CDS_MAX_NAME_LENGTH must be a multiple of 4
+#endif
+#if ((CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN % 4) != 0)
+#error CFE_MISSION_ES_CDS_MAX_FULL_NAME_LEN must be a multiple of 4
+#endif
+
+#endif /* CFE_ES_VERIFY_H */