From 1fca52e494218f37903f58cb949ad6d2ae28cc16 Mon Sep 17 00:00:00 2001 From: "Gerardo E. Cruz-Ortiz" <59618057+astrogeco@users.noreply.github.com> Date: Wed, 7 Apr 2021 14:17:18 -0400 Subject: [PATCH 1/5] CaelumReview-CFS40, Cmake build system --- .gitignore | 23 + CMakeLists.txt | 126 +++++ cmake/arch_build.cmake | 713 ++++++++++++++++++++++++ cmake/cfe_generated_file.h.in | 5 + cmake/check_header.c.in | 4 + cmake/generate_build_env.cmake | 48 ++ cmake/generate_git_module_version.cmake | 75 +++ cmake/global_functions.cmake | 266 +++++++++ cmake/mission_build.cmake | 487 ++++++++++++++++ cmake/mission_defaults.cmake | 64 +++ cmake/target/CMakeLists.txt | 276 +++++++++ cmake/target/inc/target_config.h | 211 +++++++ cmake/target/src/target_config.c | 182 ++++++ 13 files changed, 2480 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cmake/arch_build.cmake create mode 100644 cmake/cfe_generated_file.h.in create mode 100644 cmake/check_header.c.in create mode 100644 cmake/generate_build_env.cmake create mode 100644 cmake/generate_git_module_version.cmake create mode 100644 cmake/global_functions.cmake create mode 100644 cmake/mission_build.cmake create mode 100644 cmake/mission_defaults.cmake create mode 100644 cmake/target/CMakeLists.txt create mode 100644 cmake/target/inc/target_config.h create mode 100644 cmake/target/src/target_config.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e4d4dc2a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Ignore everything +* + +# ...even if they are in subdirectories +!*/ + +# But not these files... +!/.gitignore + + +# Build Files +!cmake/**/target_config.* +!cmake/target/CMAKELists.txt +!cmake/arch_build.cmake +!cmake/cfe_generated_file.h.in +!cmake/check_header.c.in +!cmake/generate_build_env.cmake +!cmake/generate_git_module_version.cmake +!cmake/global_functions.cmake +!cmake/mission_build.cmake +!cmake/mission_defaults.cmake + +!/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..1765e5dec --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,126 @@ +########################################################################## +# +# Core Flight Software Mission top-level CMake build script +# This will build cFS for all target machine(s) defined by the mission +# +# Note that the target CPUs may use different architectures, therefore each +# architecture must be done as a separate sub-build since none of the binaries +# can be shared. +# +# This is actually two build scripts in one: +# - A "top-level" script which divides the overall build by architecture +# (This is run when TARGETSYSTEM is unset) +# - An architecture-specific build that generates the binaries +# (This is run when TARGETSYSTEM is set) +# +# This file implements the common operation sequence between the mission build +# and the architecture-specific sub build. It relies on several functions +# that are implemented in a separate include files: +# +# initialize_globals: +# This function sets up the basic global variables such as MISSION_SOURCE_DIR, +# MISSIONCONFIG, ENABLE_UNIT_TESTS, SIMULATION and others. These are the +# basic variables that must exist _before_ the mission configuration is read. +# +# read_targetconfig: +# Parse the information from targets.cmake and create the build lists. Note +# this function is common to both mission and arch-specific builds. +# +# prepare: +# Use the information in the target config to set up additional variables +# and satisfy any preequisites for targets. Most importantly this stage +# is reposible for finding the actual location of all source files for apps +# listed in the mission configuration, along with collecting any supplemental +# sources, such as EDS files or additional compiler flags. +# +# process_arch: +# This is called multiple times, once for each CPU architecture specfied in +# the main targets.cmake file. At the mission level, this creates a sub +# project target using the correct toolchain for cross compile. In the arch +# specific level (inside the sub-project) it generates the actual library and +# executable targets. +# +# +########################################################################## + +# Squelch a warning when building on Win32/Cygwin +set(CMAKE_LEGACY_CYGWIN_WIN32 0) + +# Add a path for any locally-supplied CMake modules +# These would typically be a part of any custom PSPs in use. +# (this is not required, and the directory can be empty/nonexistent) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../psp/cmake/Modules" ${CMAKE_MODULE_PATH}) + +# The minimum CMake version is chosen because v3.5.1 is what is +# available by default with Ubuntu 16.04 LTS at the time of development +# RHEL/CentOS users should install the "cmake3" package from EPEL repo +cmake_minimum_required(VERSION 3.5) + +# This top-level file does not define ANY targets directly but we know +# that the subdirectories will at least use the "C" language, so +# indicate that now. Doing this early initializes the CFLAGS +# so they won't change later. +# Note: this line defines the CFE_SOURCE_DIR variable. +project(CFE C) + +# Allow unit tests to be added by any recipe +enable_testing() + +# Include the global routines +include("cmake/global_functions.cmake") + +# Load a sub-script that defines the other functions, +# depending on whether TARGETSYSTEM is defined or not +if (TARGETSYSTEM) + # Arch-specific/CPU build mode -- use the "arch_build" implementation + set(IS_CFS_ARCH_BUILD TRUE) + include("cmake/arch_build.cmake") +else (TARGETSYSTEM) + # Host System/Top Level build mode -- use the "mission_build" implementation + set(IS_CFS_MISSION_BUILD TRUE) + include("cmake/mission_build.cmake") +endif (TARGETSYSTEM) + +# Call the initialization function defined by the sub-script +# This is implemented differently depending on whether this is a +# top-level or arch-specific build +initialize_globals() + +# Load the target configuration information (used by all builds) +# This is at the top level so all vars set in here will become globals. +# The "defaults" file is included first, which the user-supplied targets +# file may override as necessary. +include("cmake/mission_defaults.cmake") +include(${MISSION_DEFS}/targets.cmake) + +# Scan the list of targets and organize by target system type. +read_targetconfig() + +# Include global-scope build customization +# Note if this feature is used it should only set basic options +# that have wide support (e.g. add_definitions). It should not +# set anything target or machine specific. +include("${MISSION_DEFS}/global_build_options.cmake" OPTIONAL) + +# Additionally the target mission might require additional +# custom build steps or override some routines. In particular +# some architectures might need some special installation steps +# The custom script may override functions such as the +# cfe_exec_do_install() and cfe_app_do_install() functions for this +if (IS_CFS_ARCH_BUILD) + include("${MISSION_DEFS}/arch_build_custom.cmake" OPTIONAL) + include("${MISSION_DEFS}/arch_build_custom_${TARGETSYSTEM}.cmake" OPTIONAL) +elseif (IS_CFS_MISSION_BUILD) + include("${MISSION_DEFS}/mission_build_custom.cmake" OPTIONAL) +endif (IS_CFS_ARCH_BUILD) + +# Call the prepare function defined by the sub-script +# This is implemented differently depending on whether this is a +# top-level or arch-specific build +prepare() + +# Call the process_arch macro for each architecture +foreach(SYSVAR ${TGTSYS_LIST}) + process_arch(${SYSVAR}) +endforeach(SYSVAR IN LISTS TGTSYS_LIST) + diff --git a/cmake/arch_build.cmake b/cmake/arch_build.cmake new file mode 100644 index 000000000..cd2575b52 --- /dev/null +++ b/cmake/arch_build.cmake @@ -0,0 +1,713 @@ +################################################################## +# +# Core Flight System architecture-specific build recipes +# +# This file is invoked by the top-level mission recipe for +# to build cFE/cFS for each target processor +# +# Note that the target CPUs may use different architectures, therefore each +# architecture must be done as a separate sub-build since none of the binaries +# can be shared. +# +################################################################## + +# define a custom property to track dependencies on CFE module targets. +# users should not typically maniplate this directly +define_property(TARGET PROPERTY CFE_MODULE_DEPENDENCIES + BRIEF_DOCS + "A set of CFE module dependencies" + FULL_DOCS + "This is a CFE-specific target property that is added to CFE modules that contains the module dependencies" +) + + +################################################################## +# +# FUNCTION: initialize_globals +# +# Set up global mission configuration variables. +# This function determines the mission configuration directory and +# also reads any startup state info from file(s) on the disk +# +# In the CPU (cross) build this only reads a cache file that was +# generated by the mission (top-level) build. Therefore all +# architecture-specific cross builds will get the same settings. +# +function(initialize_globals) + + # Sanity check -- the parent build script should have set MISSION_BINARY_DIR + if (NOT IS_DIRECTORY "${MISSION_BINARY_DIR}") + message(FATAL_ERROR "BUG -- MISSION_BINARY_DIR not a valid directory in arch_build.cmake") + endif() + + # Read the variable values from the cache file. + set(MISSION_IMPORTED_VARS) + file(READ "${MISSION_BINARY_DIR}/mission_vars.cache" PARENTVARS) + string(REGEX REPLACE ";" "\\\\;" PARENTVARS "${PARENTVARS}") + string(REGEX REPLACE "\n" ";" PARENTVARS "${PARENTVARS}") + foreach(PV ${PARENTVARS}) + if (VARNAME) + set(${VARNAME} ${PV} PARENT_SCOPE) + list(APPEND MISSION_IMPORTED_VARS ${VARNAME}) + unset(VARNAME) + else() + set(VARNAME ${PV}) + endif() + endforeach(PV ${PARENTVARS}) + unset(VARNAME) + unset(PARENTVARS) + set(MISSION_IMPORTED_VARS ${MISSION_IMPORTED_VARS} PARENT_SCOPE) + +endfunction(initialize_globals) + + +################################################################## +# +# FUNCTION: add_psp_module +# +# Simplified routine to add a driver to the PSP in use on this arch +# Called by module listfiles +# +function(add_psp_module MOD_NAME MOD_SRC_FILES) + + # Create the module + add_library(${MOD_NAME} STATIC ${MOD_SRC_FILES} ${ARGN}) + target_link_libraries(${MOD_NAME} PRIVATE psp_module_api) + + target_compile_definitions(${MOD_NAME} PRIVATE + _CFE_PSP_MODULE_ + ) + +endfunction(add_psp_module) + +################################################################## +# +# FUNCTION: add_cfe_app +# +# Simplified routine to add a CFS app or lib this arch +# Called by module listfiles +# +function(add_cfe_app APP_NAME APP_SRC_FILES) + + # currently this will build an app with either static linkage or shared/module linkage, + # but this does not currently support both for a single arch (could be revised if that is needed) + if (APP_DYNAMIC_TARGET_LIST) + set(APPTYPE "MODULE") + else() + set(APPTYPE "STATIC") + endif() + + # Create the app module + add_library(${APP_NAME} ${APPTYPE} ${APP_SRC_FILES} ${ARGN}) + target_link_libraries(${APP_NAME} core_api) + + # An "install" step is only needed for dynamic/runtime loaded apps + if (APP_DYNAMIC_TARGET_LIST) + cfs_app_do_install(${APP_NAME} ${APP_DYNAMIC_TARGET_LIST}) + endif (APP_DYNAMIC_TARGET_LIST) + +endfunction(add_cfe_app) + +################################################################## +# +# FUNCTION: add_cfe_app_dependency +# +# Adds a library dependency to a previously-created +# app/library target +# +# it adds the interface include directories and compile definitions +# of the dependency into the compilation for the module. +# +function(add_cfe_app_dependency MODULE_NAME DEPENDENCY_MODULE) + + # assemble a list of include directories and compile definitions + set(INCLUDE_LIST) + set(COMPILE_DEF_LIST) + foreach(DEP ${DEPENDENCY_MODULE} ${ARGN}) + list(APPEND INCLUDE_LIST "$") + list(APPEND COMPILE_DEF_LIST "$") + endforeach() + + target_include_directories(${MODULE_NAME} PUBLIC + ${INCLUDE_LIST} + ) + target_compile_definitions(${MODULE_NAME} PUBLIC + ${COMPILE_DEF_LIST} + ) + + # append to the custom property to track this dependency (this helpful for UT) + set_property(TARGET ${MODULE_NAME} APPEND PROPERTY CFE_MODULE_DEPENDENCIES ${DEPENDENCY_MODULE} ${ARGN}) + +endfunction(add_cfe_app_dependency) + +################################################################## +# +# FUNCTION: add_cfe_tables +# +# Simplified routine to add CFS tables to be built with an app +# +function(add_cfe_tables APP_NAME TBL_SRC_FILES) + + # The table source must be compiled using the same "include_directories" + # as any other target, but it uses the "add_custom_command" so there is + # no automatic way to do this (at least in the older cmakes) + + # Create the intermediate table objects using the target compiler, + # then use "elf2cfetbl" to convert to a .tbl file + set(TBL_LIST) + foreach(TBL ${TBL_SRC_FILES} ${ARGN}) + + # Get name without extension (NAME_WE) and append to list of tables + get_filename_component(TBLWE ${TBL} NAME_WE) + + foreach(TGT ${APP_STATIC_TARGET_LIST} ${APP_DYNAMIC_TARGET_LIST}) + set(TABLE_DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/tables_${TGT}") + file(MAKE_DIRECTORY ${TABLE_DESTDIR}) + list(APPEND TBL_LIST "${TABLE_DESTDIR}/${TBLWE}.tbl") + + # Check if an override exists at the mission level (recommended practice) + # This allows a mission to implement a customized table without modifying + # the original - this also makes for easier merging/updating if needed. + if (EXISTS "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.c") + set(TBL_SRC "${MISSION_DEFS}/tables/${TGT}_${TBLWE}.c") + elseif (EXISTS "${MISSION_SOURCE_DIR}/tables/${TGT}_${TBLWE}.c") + set(TBL_SRC "${MISSION_SOURCE_DIR}/tables/${TGT}_${TBLWE}.c") + elseif (EXISTS "${MISSION_DEFS}/tables/${TBLWE}.c") + set(TBL_SRC "${MISSION_DEFS}/tables/${TBLWE}.c") + elseif (EXISTS "${MISSION_SOURCE_DIR}/tables/${TBLWE}.c") + set(TBL_SRC "${MISSION_SOURCE_DIR}/tables/${TBLWE}.c") + elseif (EXISTS "${MISSION_DEFS}/${TGT}/tables/${TBLWE}.c") + set(TBL_SRC "${MISSION_DEFS}/${TGT}/tables/${TBLWE}.c") + elseif (IS_ABSOLUTE "${TBL}") + set(TBL_SRC "${TBL}") + else() + set(TBL_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${TBL}") + endif() + + if (NOT EXISTS "${TBL_SRC}") + message(FATAL_ERROR "ERROR: No source file for table ${TBLWE}") + else() + message("NOTE: Selected ${TBL_SRC} as source for ${TBLWE}") + endif() + + # NOTE: On newer CMake versions this should become an OBJECT library which makes this simpler. + # On older versions one may not referece the TARGET_OBJECTS property from the custom command. + # As a workaround this is built into a static library, and then the desired object is extracted + # before passing to elf2cfetbl. It is roundabout but it works. + add_library(${TGT}_${TBLWE}-obj STATIC ${TBL_SRC}) + target_link_libraries(${TGT}_${TBLWE}-obj PRIVATE core_api) + + get_filename_component(TBLOBJ ${TBL} NAME) + string(APPEND TBLOBJ ${CMAKE_C_OUTPUT_EXTENSION}) + + # IMPORTANT: This rule assumes that the output filename of elf2cfetbl matches + # the input file name but with a different extension (.o -> .tbl) + # The actual output filename is embedded in the source file (.c), however + # this must match and if it does not the build will break. That's just the + # way it is, because NO make system supports changing rules based on the + # current content of a dependency (rightfully so). + add_custom_command( + OUTPUT "${TABLE_DESTDIR}/${TBLWE}.tbl" + COMMAND ${CMAKE_AR} x $ + COMMAND ${MISSION_BINARY_DIR}/tools/elf2cfetbl/elf2cfetbl "${TBLOBJ}" + DEPENDS ${MISSION_BINARY_DIR}/tools/elf2cfetbl/elf2cfetbl ${TGT}_${TBLWE}-obj + WORKING_DIRECTORY ${TABLE_DESTDIR} + ) + # Create the install targets for all the tables + install(FILES ${TABLE_DESTDIR}/${TBLWE}.tbl DESTINATION ${TGT}/${INSTALL_SUBDIR}) + endforeach(TGT ${APP_STATIC_TARGET_LIST} ${APP_DYNAMIC_TARGET_LIST}) + + + endforeach(TBL ${TBL_SRC_FILES} ${ARGN}) + + # Make a custom target that depends on all the tables + add_custom_target(${APP_NAME}_tables ALL DEPENDS ${TBL_LIST}) + +endfunction(add_cfe_tables) + +################################################################## +# +# FUNCTION: add_cfe_coverage_dependency +# +# Adds a stub library dependency to a previously-created +# coverage test runner target +# +# If a unit under test calls functions provided by another unit +# (such as a library) then the stubs from that library will be +# added to the LINK_LIBRARIES of the coverage test. +# +function(add_cfe_coverage_dependency MODULE_NAME UNIT_NAME DEPENDENCY_MODULE) + + # the stub library correlating to the module should be named: + # coverage-${MODULE_NAME}-stubs + # (assuming it was added by the add_cfe_coverage_stubs above) + set(DEP_LIST) + foreach(DEP ${DEPENDENCY_MODULE} ${ARGN}) + list(APPEND DEP_LIST "coverage-${DEP}-stubs") + endforeach() + + target_link_libraries(coverage-${MODULE_NAME}-${UNIT_NAME}-testrunner + ${DEP_LIST} + ) + +endfunction(add_cfe_coverage_dependency) + + +################################################################## +# +# FUNCTION: add_cfe_coverage_test +# +# Add executable target for coverage testing. This builds the target +# units with extra compiler flags for coverage instrumentation, along with +# a "testrunner" executable to run the tests. It also registers +# that testrunner with ctest via the add_test() function. +# +# NOTE: The first argument (MODULE_NAME) must match the name that was previously +# passed to the add_cfe_app() function - as this references that previous +# target to use the same compile definitions and include paths. +# +# The executable target name follows the pattern: +# "coverage-${MODULE_NAME}-${UNIT_NAME}-testrunner" +# +# The calling script may call target_link_libraries() (or other target functions) +# to customize this target as needed. +# +function(add_cfe_coverage_test MODULE_NAME UNIT_NAME TESTCASE_SRC UT_SRCS) + + # A consistent name convention for all targets generated by this funtion + set(TEST_NAME "coverage-${MODULE_NAME}-${UNIT_NAME}") + set(OBJECT_TARGET "${TEST_NAME}-object") + set(RUNNER_TARGET "${TEST_NAME}-testrunner") + + # Compile the source unit(s) under test as a separate library + # This is done so that special coverage-specific compile flags can be used on these files + add_library(${OBJECT_TARGET} OBJECT + ${UT_SRCS} + ) + + # Apply the UT_COVERAGE_COMPILE_FLAGS to the units under test + # This should enable coverage analysis on platforms that support this + target_compile_options(${OBJECT_TARGET} PRIVATE + ${UT_COVERAGE_COMPILE_FLAGS} + ) + + # Include the same set of include dirs/definitions that is used from the app target + target_include_directories(${OBJECT_TARGET} PUBLIC + $ + ) + target_compile_definitions(${OBJECT_TARGET} PUBLIC + $ + ) + + # Compile a test runner application, which contains the + # actual coverage test code (test cases) and the unit under test + add_executable(${RUNNER_TARGET} + ${TESTCASE_SRC} + $ + ) + + # Include the same set of include dirs/definitions that is used from the app target + target_include_directories(${RUNNER_TARGET} PUBLIC + $ + ) + target_compile_definitions(${RUNNER_TARGET} PUBLIC + $ + ) + + # This also needs to be linked with UT_COVERAGE_LINK_FLAGS (for coverage) + # This is also linked with any other stub libraries needed, + # as well as the UT assert framework + target_link_libraries(${RUNNER_TARGET} + ${UT_COVERAGE_LINK_FLAGS} + ut_core_api_stubs + ut_assert + ) + + # for whatever app/lib dependencies the real FSW app had, the unit test + # should have the same dependencies but on the stubs instead. + get_target_property(MODULE_DEPENDENCIES ${MODULE_NAME} CFE_MODULE_DEPENDENCIES) + if (MODULE_DEPENDENCIES) + add_cfe_coverage_dependency(${MODULE_NAME} ${UNIT_NAME} ${MODULE_DEPENDENCIES}) + endif(MODULE_DEPENDENCIES) + + # Add it to the set of tests to run as part of "make test" + add_test(${TEST_NAME} ${RUNNER_TARGET}) + foreach(TGT ${INSTALL_TARGET_LIST}) + install(TARGETS ${RUNNER_TARGET} DESTINATION ${TGT}/${UT_INSTALL_SUBDIR}) + endforeach() + +endfunction(add_cfe_coverage_test) + + +################################################################## +# +# FUNCTION: add_cfe_coverage_unit_include +# +# Add an "override" include directory for a specific unit test +# +# This can be used if a coverage test needs to override certain +# C library header files only for a specific unit under test. The +# include path is added only for the particular source files in the +# specified coverage test unit. (Not for the coverage test itself). +# +# The executable target name follows the pattern: +# "coverage-${MODULE_NAME}-${UNIT_NAME}-testrunner" +# +function(add_cfe_coverage_unit_include MODULE_NAME UNIT_NAME OVERRIDE_INCLUDE_DIRS) + # For the object target only, the "override" includes should be injected + # into the include path. Note it is important that this is only included + # for the specific unit under test (object lib) not the coverage + # test executable or test cases, since these typically need the real + # version of these functions. + target_include_directories(coverage-${MODULE_NAME}-${UNIT_NAME}-object PRIVATE + ${OVERRIDE_INCLUDE_DIRS} ${ARGN} + ) + +endfunction(add_cfe_coverage_unit_include) + + +################################################################## +# +# FUNCTION: add_cfe_coverage_stubs +# +# Add stub library target for coverage testing. The stub library should +# contain a stub implementation for every function defined in the public +# API of the current module. +# +# NOTE: The first argument (MODULE_NAME) should match a name that was previously +# passed to the add_cfe_app() function - as this references that previous +# target to use the same compile definitions and include paths. +# (however this does also allow extra stub libs to be created that are not +# related to an existing module) +# +# The stub library target name follows the pattern: +# "coverage-${MODULE_NAME}-stubs" +# +# The calling script may call target_link_libraries() (or other target functions) +# to customize this target as needed. +# +# NOTE: To simplify linking and avoid possible problems there should ideally be a 1:1 +# relationship between module source files and the stub files. Each stub file +# should provide the same set of functions that the fsw source file provides. +# (although its is not strictly required, it does help keep things more manageable). +# +function(add_cfe_coverage_stubs MODULE_NAME STUB_SRCS) + + set(STUB_TARGET "coverage-${MODULE_NAME}-stubs") + + add_library(${STUB_TARGET} STATIC + ${STUB_SRCS} ${ARGN} + ) + + # If the MODULE_NAME refers to an existing CFE APP/LIB target, then + # use the same set of include dirs/definitions that is used from the app target + # This is not required; "extra" stub libs may be created that are not + # directly associated with an existing module. + if (TARGET ${MODULE_NAME}) + target_include_directories(${STUB_TARGET} PUBLIC + $ + ) + target_compile_definitions(${STUB_TARGET} PUBLIC + $ + ) + endif() + + target_link_libraries(${STUB_TARGET} ut_assert) + +endfunction(add_cfe_coverage_stubs) + + +################################################################## +# +# FUNCTION: cfe_exec_do_install +# +# Called to install a CFE core executable target to the staging area. +# Some architectures/OS's need special extra steps, and this +# function can be overridden in a custom cmake file for those platforms +# +function(cfe_exec_do_install CPU_NAME) + + # By default just stage it to a directory of the same name + install(TARGETS core-${CPU_NAME} DESTINATION ${CPU_NAME}) + +endfunction(cfe_exec_do_install) + +################################################################## +# +# FUNCTION: cfs_app_do_install +# +# Called to install a CFS application target to the staging area. +# Some architectures/OS's need special extra steps, and this +# function can be overridden in a custom cmake file for those platforms +# +function(cfs_app_do_install APP_NAME) + + # override the default behavior of attaching a "lib" prefix + set_target_properties(${APP_NAME} PROPERTIES + PREFIX "" OUTPUT_NAME "${APP_NAME}") + + # Create the install targets for this shared/modular app + foreach(TGT ${ARGN}) + install(TARGETS ${APP_NAME} DESTINATION ${TGT}/${INSTALL_SUBDIR}) + endforeach() + +endfunction(cfs_app_do_install) + +################################################################## +# +# FUNCTION: cfs_app_check_intf +# +# Adds a special target that checks the structure of header files +# in the public interface for this module. A synthetic .c source file +# is created which has a "#include" of each individual header, which +# then compiled as part of the validation. The intent is to confirm +# that each header is valid in a standalone fashion and have no +# implicit prerequisites. +# +function(cfs_app_check_intf MODULE_NAME) + set(${MODULE_NAME}_hdrcheck_SOURCES) + foreach(HDR ${ARGN}) + configure_file(${CFE_SOURCE_DIR}/cmake/check_header.c.in ${CMAKE_CURRENT_BINARY_DIR}/src/check_${HDR}.c) + list(APPEND ${MODULE_NAME}_hdrcheck_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/src/check_${HDR}.c) + endforeach(HDR ${ARGN}) + add_library(${MODULE_NAME}_headercheck STATIC EXCLUDE_FROM_ALL ${${MODULE_NAME}_hdrcheck_SOURCES}) + + # This causes the check to compile with the same set of defines and include dirs as specified + # in the "INTERFACE" properties of the actual module + target_link_libraries(${MODULE_NAME}_headercheck PRIVATE + core_api + ${DEP} + ) + + # Build this as part of the synthetic "check-headers" target + add_dependencies(check-headers ${MODULE_NAME}_headercheck) +endfunction(cfs_app_check_intf) + + + + +################################################################## +# +# FUNCTION: prepare +# +# Called by the top-level CMakeLists.txt to set up prerequisites +# +function(prepare) + + # Choose the configuration file to use for OSAL on this system + set(OSAL_CONFIGURATION_FILE) + foreach(CONFIG ${BUILD_CONFIG_${TARGETSYSTEM}} ${OSAL_SYSTEM_OSCONFIG}) + if (EXISTS "${MISSION_DEFS}/${CONFIG}_osconfig.cmake") + list(APPEND OSAL_CONFIGURATION_FILE "${MISSION_DEFS}/${CONFIG}_osconfig.cmake") + endif() + endforeach() + list(REVERSE OSAL_CONFIGURATION_FILE) + set(OSAL_CONFIGURATION_FILE ${OSAL_CONFIGURATION_FILE} PARENT_SCOPE) + + # Allow sources to "ifdef" certain things if running on simulated hardware + # This should be used sparingly, typically to fake access to hardware that is not present + if (SIMULATION) + add_definitions(-DSIMULATION=${SIMULATION}) + endif (SIMULATION) + + # Check that PSPNAME is set properly for this arch + if (NOT CFE_SYSTEM_PSPNAME) + if (CMAKE_CROSSCOMPILING) + message(FATAL_ERROR "Cross-compile toolchain ${CMAKE_TOOLCHAIN_FILE} must define CFE_SYSTEM_PSPNAME") + elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" OR + "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN") + # Export the variables determined here up to the parent scope + SET(CFE_SYSTEM_PSPNAME "pc-linux" PARENT_SCOPE) + else () + # Not cross compiling and host system is not recognized + message(FATAL_ERROR "Do not know how to set CFE_SYSTEM_PSPNAME on ${CMAKE_SYSTEM_NAME} system") + endif() + endif (NOT CFE_SYSTEM_PSPNAME) + + # Truncate the global TGTSYS_LIST to be only the target architecture + set(TGTSYS_LIST ${TARGETSYSTEM} PARENT_SCOPE) + + # set the BUILD_CONFIG variable from the cached data + set(BUILD_CONFIG ${BUILD_CONFIG_${TARGETSYSTEM}}) + list(REMOVE_AT BUILD_CONFIG 0) + set(BUILD_CONFIG ${BUILD_CONFIG} PARENT_SCOPE) + + # Pull in any application-specific platform-scope configuration + # This may include user configuration files such as cfe_platform_cfg.h, + # or any other configuration/preparation that needs to happen at + # platform/arch scope. + foreach(DEP_NAME ${MISSION_DEPS}) + include("${${DEP_NAME}_MISSION_DIR}/arch_build.cmake" OPTIONAL) + endforeach(DEP_NAME ${MISSION_DEPS}) + +endfunction(prepare) + + +################################################################## +# +# FUNCTION: process_arch +# +# Called by the top-level CMakeLists.txt to set up targets for this arch +# This is where the real work is done +# +function(process_arch SYSVAR) + + # Check if something actually uses this arch; + # if this list is empty then do nothing, skip building osal/psp + if (NOT DEFINED TGTSYS_${SYSVAR}) + return() + endif() + + # Generate a list of targets that share this system architecture + set(INSTALL_TARGET_LIST ${TGTSYS_${SYSVAR}}) + + # Assume use of an OSAL BSP of the same name as the CFE PSP + # This can be overridden by the PSP-specific build_options but normally this is expected. + set(CFE_PSP_EXPECTED_OSAL_BSPTYPE ${CFE_SYSTEM_PSPNAME}) + + # Include any specific compiler flags or config from the selected PSP + include(${MISSION_SOURCE_DIR}/psp/fsw/${CFE_SYSTEM_PSPNAME}/make/build_options.cmake) + + if (NOT DEFINED OSAL_SYSTEM_BSPTYPE) + # Implicitly use the OSAL BSP that corresponds with the CFE PSP + set(OSAL_SYSTEM_BSPTYPE ${CFE_PSP_EXPECTED_OSAL_BSPTYPE}) + elseif (NOT OSAL_SYSTEM_BSPTYPE STREQUAL CFE_PSP_EXPECTED_OSAL_BSPTYPE) + # Generate a warning about the BSPTYPE not being expected. + # Not calling this a fatal error because it could possibly be intended during development + message(WARNING "Mismatched PSP/BSP: ${CFE_SYSTEM_PSPNAME} implies ${CFE_PSP_EXPECTED_OSAL_BSPTYPE}, but ${OSAL_SYSTEM_BSPTYPE} is configured") + endif() + + # The "inc" directory in the binary dir contains the generated wrappers, if any + include_directories(${MISSION_BINARY_DIR}/inc) + include_directories(${CMAKE_BINARY_DIR}/inc) + + # Add a custom target for "headercheck" - this is a special target confirms that + # checks the sanity of headers within the public interface of modules + add_custom_target(check-headers) + + # Configure OSAL target first, as it also determines important compiler flags + add_subdirectory("${osal_MISSION_DIR}" osal) + + # The OSAL displays its selected OS, so it is logical to display the selected PSP + # This can help with debugging if things go wrong. + message(STATUS "PSP Selection: ${CFE_SYSTEM_PSPNAME}") + + # Append the PSP and OSAL selections to the Doxyfile so it will be included + # in the generated documentation automatically. + # Also extract the "-D" options within CFLAGS and inform Doxygen about these + string(REGEX MATCHALL "-D[A-Za-z0-9_=]+" DOXYGEN_DEFINED_MACROS "${CMAKE_C_FLAGS}") + string(REGEX REPLACE "-D" " " DOXYGEN_DEFINED_MACROS "${DOXYGEN_DEFINED_MACROS}") + file(APPEND "${MISSION_BINARY_DIR}/doc/mission-content.doxyfile" + "PREDEFINED += ${DOXYGEN_DEFINED_MACROS}\n" + "INPUT += ${MISSION_SOURCE_DIR}/osal/src/os/${OSAL_SYSTEM_OSTYPE}\n" + "INPUT += ${MISSION_SOURCE_DIR}/psp/fsw/${CFE_SYSTEM_PSPNAME}\n" + "INPUT += ${CMAKE_BINARY_DIR}/inc") + + # Append to usersguide.doxyfile + file(APPEND "${MISSION_BINARY_DIR}/doc/cfe-usersguide.doxyfile" + "INPUT += ${MISSION_SOURCE_DIR}/psp/fsw/${CFE_SYSTEM_PSPNAME}/src\n" + "INPUT += ${CMAKE_BINARY_DIR}/inc") + + # The PSP and/or OSAL should have defined where to install the binaries. + # If not, just install them in /cf as a default (this can be modified + # by the packaging script if it is wrong for the target) + if (NOT INSTALL_SUBDIR) + set(INSTALL_SUBDIR cf) + endif (NOT INSTALL_SUBDIR) + + # confirm that all dependencies have a MISSION_DIR defined that indicates the source. + # This should have been set up by the parent script. However, if any dir is not set, + # this may result in "add_subdirectory" of itself which causes a loop. This can happen + # if the variables/lists were modified unexpectedly. + foreach(DEP + ${MISSION_CORE_MODULES} + ${TGTSYS_${SYSVAR}_PSPMODULES} + ${TGTSYS_${SYSVAR}_STATICAPPS} + ${TGTSYS_${SYSVAR}_APPS}) + if(NOT DEFINED ${DEP}_MISSION_DIR) + message(FATAL_ERROR "ERROR: core module ${DEP} has no MISSION_DIR defined") + endif() + endforeach() + + + # Add all core modules + # The osal is handled explicitly (above) since this has special extra config + foreach(DEP ${MISSION_CORE_MODULES}) + if(NOT DEP STREQUAL "osal") + message(STATUS "Building Core Module: ${DEP}") + add_subdirectory("${${DEP}_MISSION_DIR}" ${DEP}) + endif(NOT DEP STREQUAL "osal") + endforeach(DEP ${MISSION_CORE_MODULES}) + + # For the PSP it may define the FSW as either + # "psp-${CFE_SYSTEM_PSPNAME}" or just simply "psp" + if (NOT TARGET psp) + add_library(psp ALIAS psp-${CFE_SYSTEM_PSPNAME}) + endif (NOT TARGET psp) + + # Process each PSP module that is referenced on this system architecture (any cpu) + foreach(PSPMOD ${TGTSYS_${SYSVAR}_PSPMODULES}) + message(STATUS "Building PSP Module: ${PSPMOD}") + add_subdirectory("${${PSPMOD}_MISSION_DIR}" psp/${PSPMOD}) + endforeach() + + # Process each app that is used on this system architecture + # First Pass: Assemble the list of apps that should be compiled + foreach(APP ${TGTSYS_${SYSVAR}_APPS} ${TGTSYS_${SYSVAR}_STATICAPPS}) + set(TGTLIST_${APP}) + endforeach() + + foreach(TGTNAME ${TGTSYS_${SYSVAR}}) + + # Append to the app install list for this CPU + foreach(APP ${${TGTNAME}_APPLIST} ${${TGTNAME}_STATIC_APPLIST}) + list(APPEND TGTLIST_${APP} ${TGTNAME}) + endforeach(APP ${${TGTNAME}_APPLIST}) + + endforeach(TGTNAME ${TGTSYS_${SYSVAR}}) + + foreach(APP ${TGTSYS_${SYSVAR}_STATICAPPS}) + set(APP_STATIC_TARGET_LIST ${TGTLIST_${APP}}) + message(STATUS "Building Static App: ${APP} targets=${APP_STATIC_TARGET_LIST}") + add_subdirectory("${${APP}_MISSION_DIR}" apps/${APP}) + endforeach() + unset(APP_STATIC_TARGET_LIST) + + # Process each app that is used on this system architecture + foreach(APP ${TGTSYS_${SYSVAR}_APPS}) + set(APP_DYNAMIC_TARGET_LIST ${TGTLIST_${APP}}) + message(STATUS "Building Dynamic App: ${APP} targets=${APP_DYNAMIC_TARGET_LIST}") + add_subdirectory("${${APP}_MISSION_DIR}" apps/${APP}) + endforeach() + unset(APP_DYNAMIC_TARGET_LIST) + + # Process each target that shares this system architecture + # Second Pass: Build and link final target executable + foreach(TGTNAME ${TGTSYS_${SYSVAR}}) + + # Target to generate the actual executable file + add_subdirectory(cmake/target ${TGTNAME}) + + foreach(INSTFILE ${${TGTNAME}_FILELIST}) + if(EXISTS ${MISSION_DEFS}/${TGTNAME}/${INSTFILE}) + set(FILESRC ${MISSION_DEFS}/${TGTNAME}/${INSTFILE}) + elseif(EXISTS ${MISSION_DEFS}/${TGTNAME}_${INSTFILE}) + set(FILESRC ${MISSION_DEFS}/${TGTNAME}_${INSTFILE}) + elseif(EXISTS ${MISSION_DEFS}/${INSTFILE}) + set(FILESRC ${MISSION_DEFS}/${INSTFILE}) + else() + set(FILESRC) + endif() + if (FILESRC) + # In case the file is a symlink, follow it to get to the actual file + get_filename_component(FILESRC "${FILESRC}" REALPATH) + message("NOTE: Selected ${FILESRC} as source for ${INSTFILE} on ${TGTNAME}") + install(FILES ${FILESRC} DESTINATION ${TGTNAME}/${INSTALL_SUBDIR} RENAME ${INSTFILE}) + else(FILESRC) + message("WARNING: Install file ${INSTFILE} for ${TGTNAME} not found") + endif (FILESRC) + endforeach(INSTFILE ${${TGTNAME}_FILELIST}) + endforeach(TGTNAME ${TGTSYS_${SYSVAR}}) + +endfunction(process_arch SYSVAR) + diff --git a/cmake/cfe_generated_file.h.in b/cmake/cfe_generated_file.h.in new file mode 100644 index 000000000..5bc4d4108 --- /dev/null +++ b/cmake/cfe_generated_file.h.in @@ -0,0 +1,5 @@ +@GENERATED_FILE_HEADER@ + +@GENERATED_FILE_CONTENT@ + +@GENERATED_FILE_TRAILER@ diff --git a/cmake/check_header.c.in b/cmake/check_header.c.in new file mode 100644 index 000000000..a3a9d8031 --- /dev/null +++ b/cmake/check_header.c.in @@ -0,0 +1,4 @@ +#include "@HDR@" + +/* A no-op function so this compilation unit is not empty */ +void CheckHeader(void) {} diff --git a/cmake/generate_build_env.cmake b/cmake/generate_build_env.cmake new file mode 100644 index 000000000..ea179281e --- /dev/null +++ b/cmake/generate_build_env.cmake @@ -0,0 +1,48 @@ +################################################################## +# +# cFS version metadata collection script +# +# This small script runs at build time (as opposed to prep time) +# and is intended to extract information about the current +# build environment - this may change after initial makefile creation +# +################################################################## + +# All 3 of these may be passed via environment variables to force a particular +# date, user, or hostname i.e. if hoping to reproduce an exact binary of a prior build +# They are free-form strings, will be built/linked into the final CONFIGDATA object. + +# Get the current date and time +set(BUILDDATE $ENV{BUILDDATE}) +if (NOT BUILDDATE) + execute_process( + COMMAND date "+%Y%m%d%H%M" + OUTPUT_VARIABLE BUILDDATE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif(NOT BUILDDATE) + +# Get the build host +set(BUILDHOST $ENV{HOSTNAME}) +if (NOT BUILDHOST) + execute_process( + COMMAND hostname + OUTPUT_VARIABLE BUILDHOST + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif (NOT BUILDHOST) + +# Get the user ID +set(BUILDUSER $ENV{USER}) +if (NOT BUILDUSER) + execute_process( + COMMAND whoami + OUTPUT_VARIABLE BUILDUSER + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif (NOT BUILDUSER) + +# Use configure_file() command to generate the final output file because this can detect +# and only update it if it changes. +set(CFE_KEYVALUE_TABLE_NAME "CFE_BUILD_ENV_TABLE") +configure_file(${BIN}/cfe_build_env.in ${BIN}/src/cfe_build_env_table.c @ONLY) diff --git a/cmake/generate_git_module_version.cmake b/cmake/generate_git_module_version.cmake new file mode 100644 index 000000000..7a2559324 --- /dev/null +++ b/cmake/generate_git_module_version.cmake @@ -0,0 +1,75 @@ +################################################################## +# +# cFS version metadata collection script +# +# This small script runs at build time (as opposed to prep time) +# and is intended to extract version metadata from the current source +# tree. It is done each time that the code is built, since the +# metadata could change at any time (i.e. a different branch could +# be checked out, or additional changes committed) +# +# Currently only git is supported as a version control source, however +# it could be extended to others by adding the appropriate command +# +################################################################## + +set(GIT_EXECUTABLE git) + +function(get_version DEP) + if (DEP STREQUAL "MISSION") + set(NAME ${MISSION_NAME}) + set(DIR ${MISSION_SOURCE_DIR}) + else() + if(EXISTS ${${DEP}_MISSION_DIR}/version_info.cmake) + include(${${DEP}_MISSION_DIR}/version_info.cmake) + else() + set(NAME ${DEP}) + endif() + set(DIR ${${DEP}_MISSION_DIR}) + endif() + message("inside get_version for ${DEP}") + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty + WORKING_DIRECTORY ${DIR} + OUTPUT_VARIABLE GIT_DESC_OUTPUT + RESULT_VARIABLE GIT_RESULT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Export output to parent scope + set(${DEP}_NAME "${NAME}" PARENT_SCOPE) + + # If result was successful, then string-ify it, otherwise use NULL + if (GIT_RESULT EQUAL 0) + set(${DEP}_VERSION "\"git:${GIT_DESC_OUTPUT}\"" PARENT_SCOPE) + else() + set(${DEP}_VERSION "NULL" PARENT_SCOPE) + endif() + +endfunction() + + +# First read in any variables that are passed in from the parent process +# There may be many of these and they may not all be passable via -D options +file(STRINGS "${BIN}/mission_vars.cache" PARENTVARS) +set(VARNAME) +foreach(PV ${PARENTVARS}) + if (VARNAME) + set(${VARNAME} ${PV}) + set(VARNAME) + else() + set(VARNAME ${PV}) + endif() +endforeach(PV ${PARENTVARS}) + +# Get version for all mission apps/dependencies (they may be different) +foreach(DEP "MISSION" ${MISSION_DEPS}) + get_version(${DEP}) +endforeach() + + +# Use configure_file() command to generate the final output file because this can detect +# and only update it if it changes. +set(CFE_KEYVALUE_TABLE_NAME "CFE_MODULE_VERSION_TABLE") +configure_file(${BIN}/cfe_module_version.in ${BIN}/src/cfe_module_version_table.c @ONLY) diff --git a/cmake/global_functions.cmake b/cmake/global_functions.cmake new file mode 100644 index 000000000..8289363cc --- /dev/null +++ b/cmake/global_functions.cmake @@ -0,0 +1,266 @@ +################################################################## +# +# cFS Mission global CMake function definitions +# +# This is included by the top-level script and can define +# common routines and variables that may be referenced in both +# the mission (non-arch) and arch-specific builds +# +################################################################## + +include(CMakeParseArguments) + +################################################################## +# +# FUNCTION: generate_c_headerfile +# +# Generates a C header file in the build directory. +# First argument is the file name to write. All remaining arguments will be +# concatenated and written to the file. +# +function(generate_c_headerfile FILE_NAME) + + # Determine the absolute location for this wrapper file + # If it is relative path then assume it is relative to ${CMAKE_BINARY_DIR} + # This should not write generated files to ${CMAKE_SOURCE_DIR} + if (NOT IS_ABSOLUTE "${FILE_NAME}") + set(FILE_NAME "${CMAKE_BINARY_DIR}/${FILE_NAME}") + endif (NOT IS_ABSOLUTE "${FILE_NAME}") + + # Generate an include guard + get_filename_component(FILE_GUARD "${FILE_NAME}" NAME) + string(REGEX REPLACE "[^A-Za-z0-9]" "_" FILE_GUARD "${FILE_GUARD}") + string(TOUPPER "GENERATED_INCLUDE_${FILE_GUARD}" FILE_GUARD) + set(GENERATED_FILE_HEADER + "/* Generated header file. Do not edit */\n\n" + "#ifndef ${FILE_GUARD}\n" + "#define ${FILE_GUARD}\n\n" + ) + set(GENERATED_FILE_TRAILER + "#endif /* ${FILE_GUARD} */\n" + ) + + # Use configure_file() to write the file, as this automatically + # has the logic to not update the timestamp on the file unless it changes. + string(REPLACE ";" "" GENERATED_FILE_CONTENT "${ARGN}") + string(REPLACE ";" "" GENERATED_FILE_HEADER "${GENERATED_FILE_HEADER}") + string(REPLACE ";" "" GENERATED_FILE_TRAILER "${GENERATED_FILE_TRAILER}") + configure_file( + "${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in" + "${FILE_NAME}" + @ONLY) + +endfunction(generate_c_headerfile) + +################################################################## +# +# FUNCTION: generate_config_includefile +# +# A function to create safe include file wrappers +# +# Rather than symlinking to the include file (which might not work the same on all platforms) +# we can create a build-specific include file that just #include's the real file +# +# This also supports "stacking" multiple component files together by specifying more than one +# source file for the wrapper. +# +# This function now accepts named parameters: +# FILE_NAME - the name of the file to write +# FALLBACK_FILE - if no files are found in "defs" using the name match, this file will be used instead. +# MATCH_SUFFIX - the suffix to match in the "defs" directory (optional) +# PREFIXES - a list of prefixes to match in the "defs" directory (optional) +# +function(generate_config_includefile) + + cmake_parse_arguments(GENCONFIG_ARG "" "OUTPUT_DIRECTORY;FILE_NAME;FALLBACK_FILE;MATCH_SUFFIX" "PREFIXES" ${ARGN} ) + if (NOT GENCONFIG_ARG_OUTPUT_DIRECTORY) + set(GENCONFIG_ARG_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/inc") + endif (NOT GENCONFIG_ARG_OUTPUT_DIRECTORY) + + set(WRAPPER_FILE_CONTENT) + set(ITEM_FOUND FALSE) + + # Assemble a list of file names to test for + # Check for existence of a file in defs directory with an exact matching name + # Then Check for existence of file(s) with a matching prefix+suffix + set(CHECK_PATH_LIST "${MISSION_DEFS}/${GENCONFIG_ARG_FILE_NAME}") + if (GENCONFIG_ARG_MATCH_SUFFIX) + foreach(PREFIX ${GENCONFIG_ARG_PREFIXES} ${GENCONFIG_ARG_UNPARSED_ARGUMENTS}) + list(APPEND CHECK_PATH_LIST "${MISSION_DEFS}/${PREFIX}_${GENCONFIG_ARG_MATCH_SUFFIX}") + endforeach() + endif(GENCONFIG_ARG_MATCH_SUFFIX) + + # Check for existence of files, and add to content if present + # Note that all files are appended/concatenated together. + foreach(SRC_LOCAL_PATH ${CHECK_PATH_LIST}) + if (EXISTS "${SRC_LOCAL_PATH}") + file(TO_NATIVE_PATH "${SRC_LOCAL_PATH}" SRC_NATIVE_PATH) + list(APPEND WRAPPER_FILE_CONTENT "#include \"${SRC_NATIVE_PATH}\"\n") + set(ITEM_FOUND TRUE) + else() + list(APPEND WRAPPER_FILE_CONTENT "/* ${SRC_LOCAL_PATH} does not exist */\n") + endif (EXISTS "${SRC_LOCAL_PATH}") + endforeach() + + # If _no_ files were found in the above loop, + # then check for and use the fallback file. + # (if specified by the caller it should always exist) + # Also produce a message on the console showing whether mission config or fallback was used + if (ITEM_FOUND) + message(STATUS "Generated ${GENCONFIG_ARG_FILE_NAME} from ${MISSION_DEFS} configuration") + elseif (GENCONFIG_ARG_FALLBACK_FILE) + file(TO_NATIVE_PATH "${GENCONFIG_ARG_FALLBACK_FILE}" SRC_NATIVE_PATH) + list(APPEND WRAPPER_FILE_CONTENT + "\n\n/* No configuration for ${GENCONFIG_ARG_FILE_NAME}, using fallback */\n" + "#include \"${GENCONFIG_ARG_FALLBACK_FILE}\"\n") + message(STATUS "Using ${GENCONFIG_ARG_FALLBACK_FILE} for ${GENCONFIG_ARG_FILE_NAME}") + else() + message("ERROR: No implementation for ${GENCONFIG_ARG_FILE_NAME} found") + message(FATAL_ERROR "Tested: ${CHECK_PATH_LIST}") + endif() + + # Generate a header file + generate_c_headerfile("${GENCONFIG_ARG_OUTPUT_DIRECTORY}/${GENCONFIG_ARG_FILE_NAME}" ${WRAPPER_FILE_CONTENT}) + +endfunction(generate_config_includefile) + + +################################################################## +# +# FUNCTION: read_targetconfig +# +# Scan the list of targets and organize by target system type. +# This function sets up the following variables in the global scope: +# TGTSYS_LIST: list of CPU architectures used in the build. Note this +# will always contain a "native" target (for tools at least) which +# is forced to be last. +# MISSION_APPS: full list of applications specified in the whole mission +# SYSID_: set for each entry of TGTSYS_LIST, and indicates the +# toolchain specified in the target file for that CPU arch. +# TGTSYS_: set to a list of CPU numbers that utilize the same arch +# TGTSYS__APPS: set for each entry of TGTSYS_LIST, and indicates the +# full set of applications that need to built for that target architecture +# TGTSYS__DRIVERS: set for each entry of TGTSYS_LIST, and indicates the +# full set of device drivers that need to built for that target architecture +# +function(read_targetconfig) + + set(TGTSYS_LIST) + set(MISSION_APPS) + set(MISSION_PSPMODULES) + + # This while loop checks for a sequential set of variables prefixed with TGT_ + # where is a sequence number starting with 1. The first "gap" (undefined name) + # is treated as the end of list. + # This is the historical way of specifying CPU configs. New/future development should + # prefer the name-based specification. This translates the sequential TGT variable + # to a name-based variable. + set(TGTID 0) + while(1) + math(EXPR TGTID "${TGTID} + 1") + if (NOT DEFINED TGT${TGTID}_NAME) + break() + endif() + set(CPUNAME ${TGT${TGTID}_NAME}) + # by default if PROCESSORID isn't specified, then use TGTID number. + if(NOT DEFINED TGT${TGTID}_PROCESSORID) + set(TGT${TGTID}_PROCESSORID ${TGTID}) + endif() + + # Translate the TGT prefix to the CPU name prefix + # also propagate the value to parent scope + foreach(PROP PROCESSORID + APPLIST + STATIC_APPLIST + STATIC_SYMLIST + PSP_MODULELIST + FILELIST + EMBED_FILELIST + SYSTEM + PLATFORM) + set(${CPUNAME}_${PROP} ${TGT${TGTID}_${PROP}}) + set(${CPUNAME}_${PROP} ${${CPUNAME}_${PROP}} PARENT_SCOPE) + endforeach() + list(APPEND MISSION_CPUNAMES ${CPUNAME}) + endwhile() + + foreach(CPUNAME ${MISSION_CPUNAMES}) + if (SIMULATION) + # if simulation use simulation system architecture for all targets + set(TOOLCHAIN_NAME "${SIMULATION}") + elseif (${CPUNAME}_SYSTEM) + # get the target system arch identifier string + set(TOOLCHAIN_NAME "${${CPUNAME}_SYSTEM}") + else() + # assume a toolchain name matching the CPU name + set(TOOLCHAIN_NAME "${CPUNAME}") + set(${CPUNAME}_SYSTEM ${TOOLCHAIN_NAME} PARENT_SCOPE) + endif () + + if (NOT DEFINED ${CPUNAME}_PLATFORM) + set(${CPUNAME}_PLATFORM "default" "${CPUNAME}") + set(${CPUNAME}_PLATFORM "${${CPUNAME}_PLATFORM}" PARENT_SCOPE) + endif() + + set(BUILD_CONFIG ${TOOLCHAIN_NAME} ${${CPUNAME}_PLATFORM}) + + # convert to a the string which is safe for a variable name + string(REGEX REPLACE "[^A-Za-z0-9]" "_" SYSVAR "${BUILD_CONFIG}") + + # save the unmodified name for future reference + set(BUILD_CONFIG_${SYSVAR} "${BUILD_CONFIG}" PARENT_SCOPE) + + # if the "global" applist is not empty, append to every CPU applist + if (MISSION_GLOBAL_APPLIST) + list(APPEND ${CPUNAME}_APPLIST ${MISSION_GLOBAL_APPLIST}) + set(${CPUNAME}_APPLIST ${${CPUNAME}_APPLIST} PARENT_SCOPE) + endif (MISSION_GLOBAL_APPLIST) + + if (MISSION_GLOBAL_STATIC_APPLIST) + list(APPEND ${CPUNAME}_STATIC_APPLIST ${MISSION_GLOBAL_STATIC_APPLIST}) + set(${CPUNAME}_STATIC_APPLIST ${${CPUNAME}_STATIC_APPLIST} PARENT_SCOPE) + endif (MISSION_GLOBAL_STATIC_APPLIST) + + # Append to global lists + list(APPEND TGTSYS_LIST "${SYSVAR}") + list(APPEND TGTSYS_${SYSVAR} "${CPUNAME}") + list(APPEND TGTSYS_${SYSVAR}_APPS ${${CPUNAME}_APPLIST}) + list(APPEND TGTSYS_${SYSVAR}_STATICAPPS ${${CPUNAME}_STATIC_APPLIST}) + list(APPEND TGTSYS_${SYSVAR}_PSPMODULES ${${CPUNAME}_PSP_MODULELIST}) + list(APPEND MISSION_APPS ${${CPUNAME}_APPLIST} ${${CPUNAME}_STATIC_APPLIST}) + list(APPEND MISSION_PSPMODULES ${${CPUNAME}_PSP_MODULELIST}) + + endforeach() + + # Remove duplicate entries in the generated lists + list(REMOVE_DUPLICATES TGTSYS_LIST) + if (MISSION_APPS) + list(REMOVE_DUPLICATES MISSION_APPS) + endif (MISSION_APPS) + if (MISSION_PSPMODULES) + list(REMOVE_DUPLICATES MISSION_PSPMODULES) + endif(MISSION_PSPMODULES) + + # Set the final variable value(s) in the parent scope + set(TGTSYS_LIST ${TGTSYS_LIST} PARENT_SCOPE) + set(MISSION_APPS ${MISSION_APPS} PARENT_SCOPE) + set(MISSION_PSPMODULES ${MISSION_PSPMODULES} PARENT_SCOPE) + set(MISSION_CPUNAMES ${MISSION_CPUNAMES} PARENT_SCOPE) + + foreach(SYSVAR ${TGTSYS_LIST}) + set(TGTSYS_${SYSVAR} ${TGTSYS_${SYSVAR}} PARENT_SCOPE) + if(TGTSYS_${SYSVAR}_APPS) + list(REMOVE_DUPLICATES TGTSYS_${SYSVAR}_APPS) + set(TGTSYS_${SYSVAR}_APPS ${TGTSYS_${SYSVAR}_APPS} PARENT_SCOPE) + endif(TGTSYS_${SYSVAR}_APPS) + if(TGTSYS_${SYSVAR}_STATICAPPS) + list(REMOVE_DUPLICATES TGTSYS_${SYSVAR}_STATICAPPS) + set(TGTSYS_${SYSVAR}_STATICAPPS ${TGTSYS_${SYSVAR}_STATICAPPS} PARENT_SCOPE) + endif(TGTSYS_${SYSVAR}_STATICAPPS) + if(TGTSYS_${SYSVAR}_PSPMODULES) + list(REMOVE_DUPLICATES TGTSYS_${SYSVAR}_PSPMODULES) + set(TGTSYS_${SYSVAR}_PSPMODULES ${TGTSYS_${SYSVAR}_PSPMODULES} PARENT_SCOPE) + endif(TGTSYS_${SYSVAR}_PSPMODULES) + endforeach(SYSVAR ${TGTSYS_LIST}) + +endfunction(read_targetconfig) diff --git a/cmake/mission_build.cmake b/cmake/mission_build.cmake new file mode 100644 index 000000000..6568eea2c --- /dev/null +++ b/cmake/mission_build.cmake @@ -0,0 +1,487 @@ +################################################################## +# +# cFS project top-level mission build recipes +# +# This manages the overall top-level build environment +# +# Note that the target CPUs may use different architectures, therefore each +# architecture must be done as a separate sub-build since none of the binaries +# can be shared. +# +# This is a normal (non-cross) build recipe and a custom target +# is generated per-cpu which is typically a cross (arch-specific) build. +# +# In addition to those custom targets, targets for tools that execute directly +# on the development host may also be created via this recipe. +# +################################################################## + + +################################################################## +# +# FUNCTION: initialize_globals +# +# Set up global mission configuration variables. +# In the top level mode (this file)t reads extracts state info from +# configuration files within the project source tree (the _defs directory) +# +function(initialize_globals) + + # Entry point for the "mission" (top level) build + # Determine the values for the cache variables + if (NOT DEFINED MISSION_BINARY_DIR) + set(MISSION_BINARY_DIR ${CMAKE_BINARY_DIR} CACHE PATH "Top level mission binary directory") + endif (NOT DEFINED MISSION_BINARY_DIR) + + # this is the parent (mission) build and variable values must be determined + # Obtain the "real" top-level source directory and set it in parent scope + if (NOT DEFINED MISSION_SOURCE_DIR) + get_filename_component(MISSION_SOURCE_DIR "${CFE_SOURCE_DIR}/.." ABSOLUTE) + set(MISSION_SOURCE_DIR ${MISSION_SOURCE_DIR} CACHE PATH "Top level mission source directory") + endif(NOT DEFINED MISSION_SOURCE_DIR) + + # The configuration should be in a subdirectory named "_defs". If there is one + # and only one of these, this is assumed to be it. If there is more than one then the + # user MUST specify which one is intended to be used by setting MISSIONCONFIG in the environment + if (NOT MISSIONCONFIG) + set(MCTEMP $ENV{MISSIONCONFIG}) + if ("${MCTEMP}" STREQUAL "") + file(GLOB DEFDIRS RELATIVE "${MISSION_SOURCE_DIR}" "${MISSION_SOURCE_DIR}/*_defs") + list(LENGTH DEFDIRS DDLEN) + if (NOT DDLEN EQUAL 1) + message(FATAL_ERROR "Unable to automatically determine the mission config directory. Specify it with the MISSIONCONFIG variable.") + endif (NOT DDLEN EQUAL 1) + string(REPLACE "_defs" "" MCTEMP ${DEFDIRS}) + message(STATUS "Mission configuration ${MCTEMP} automatically selected") + endif ("${MCTEMP}" STREQUAL "") + # Set the MISSIONCONFIG as a CMake cache variable so it will be preserved for future runs + set(MISSIONCONFIG ${MCTEMP} CACHE STRING "Mission configuration selection") + unset(MCTEMP) + endif(NOT MISSIONCONFIG) + + # Cache the values of certain environment variables used during the setup process + # The issue with environment variables is that they are transient and may change at any time, + # such as if the build is invoked from a different shell. Whenever the build system is regenerated + # in the future, we need to use the same values for these options even if the user has modified them + # in the local environment. + set(SIMULATION $ENV{SIMULATION} CACHE STRING "Enable simulation mode using specified toolchain") + set(ENABLE_UNIT_TESTS $ENV{ENABLE_UNIT_TESTS} CACHE BOOL "Enable build of unit tests") + + # Export values to parent level + set(MISSION_DEFS ${MISSION_SOURCE_DIR}/${MISSIONCONFIG}_defs CACHE PATH "Full path to mission definitions directory") + +endfunction(initialize_globals) + +################################################################## +# +# FUNCTION: generate_build_version_templates +# +# Generates file templates for use with configure_file() which is +# invoked at build time to get the required information. +# +# Note that some information may change between generation and build +# times, hence why only a template can be generated here, the final +# file content must be generated via a build rule. +# +function(generate_build_version_templates) + + # File header for build info template (tag file as auto-generated) + string(CONCAT GENERATED_FILE_HEADER + "/* This file is auto-generated from CMake build system. Do not manually edit! */\n" + "#include \"target_config.h\"\n" + "const CFE_ConfigKeyValue_t @CFE_KEYVALUE_TABLE_NAME@[] = {\n" + ) + + # File trailer for build info template + string(CONCAT GENERATED_FILE_TRAILER + "{ NULL, NULL } /* End of list */\n" + "};\n" + "/* End of file */\n" + ) + + # These variables are deferred until build time + foreach (VAR BUILDDATE BUILDUSER BUILDHOST) + list (APPEND GENERATED_FILE_CONTENT "{ \"${VAR}\", \"@${VAR}@\" },") + endforeach () + string(REPLACE ";" "\n" GENERATED_FILE_CONTENT "${GENERATED_FILE_CONTENT}") + + # Write a template for build/config information + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_BINARY_DIR}/cfe_build_env.in) + + # Content for version info - all are deferred until build time + set(GENERATED_FILE_CONTENT) + foreach(DEP "MISSION" ${MISSION_DEPS}) + list (APPEND GENERATED_FILE_CONTENT "{ \"${DEP}\", @${DEP}_VERSION@ },") + endforeach() + string(REPLACE ";" "\n" GENERATED_FILE_CONTENT "${GENERATED_FILE_CONTENT}") + + # Write a template for version information + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_BINARY_DIR}/cfe_module_version.in) + + # The actual version information (to fill out the template above) is obtained at build time + # via a script that is executed as a build target. If this script exists in the mission defs + # directory (user-supplied) then use that. Otherwise a pre-canned "git" version is included + # as a fallback, which should work for source trees assembled via git submodules or subtrees. + if (EXISTS "${MISSION_DEFS}/generate_module_version.cmake") + set(VERSION_SCRIPT "${MISSION_DEFS}/generate_module_version.cmake") + else() + set(VERSION_SCRIPT "${CFE_SOURCE_DIR}/cmake/generate_git_module_version.cmake") + endif() + + add_custom_target(cfe-module-version + COMMAND + ${CMAKE_COMMAND} -D BIN=${CMAKE_BINARY_DIR} + -P "${VERSION_SCRIPT}" + WORKING_DIRECTORY + ${CMAKE_SOURCE_DIR} + VERBATIM + ) + + add_custom_target(cfe-build-env + COMMAND + ${CMAKE_COMMAND} -D BIN=${CMAKE_BINARY_DIR} + -P "${CFE_SOURCE_DIR}/cmake/generate_build_env.cmake" + WORKING_DIRECTORY + ${CMAKE_SOURCE_DIR} + VERBATIM + ) + + # Content for build info - these vars can be evaulated right now, no need to defer + set(GENERATED_FILE_HEADER "/* Automatically generated from CMake build system */") + string(CONCAT GENERATED_FILE_CONTENT + "const char CFE_MISSION_NAME[] = \"${MISSION_NAME}\";\n" + "const char CFE_MISSION_CONFIG[] = \"${MISSIONCONFIG}\";\n" + ) + set(GENERATED_FILE_TRAILER "/* End of file */") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_BINARY_DIR}/src/cfe_mission_strings.c) + + add_custom_target(mission-version + DEPENDS cfe-module-version cfe-build-env + ) + +endfunction(generate_build_version_templates) + +################################################################## +# +# FUNCTION: prepare +# +# Called by the top-level CMakeLists.txt to set up prerequisites +# +function(prepare) + + # Propagate the SIMULATION variable if set + if (SIMULATION) + add_definitions(-DSIMULATION=${SIMULATION}) + endif (SIMULATION) + + # Create custom targets for building and cleaning all architectures + # This is required particularly for doing extra stuff in the clean step + add_custom_target(mission-all COMMAND $(MAKE) all) + add_custom_target(mission-install COMMAND $(MAKE) install) + add_custom_target(mission-clean COMMAND $(MAKE) clean) + add_custom_target(mission-prebuild) + + # Locate the source location for all the apps found within the target file + # This is done by searching through the list of paths to find a matching name + # The environment variable is cached so it will be retained across runs. + set(CFS_APP_PATH "$ENV{CFS_APP_PATH}" + CACHE STRING "Extra search path for code modules" + ) + string(REPLACE ":" ";" CFS_APP_PATH "${CFS_APP_PATH}") + set(MISSION_MODULE_SEARCH_PATH ${CFS_APP_PATH} ${MISSION_MODULE_SEARCH_PATH}) + + # The "MISSION_DEPS" list is the complete set of all dependencies used in the build. + # This reflects all modules for all CPUs. It is set as a usage convenience + # for iterating through the full set of dependencies regardless of which level + # or context each dependency relates to (CFE, PSP, apps, etc). + set(MISSION_DEPS ${MISSION_APPS} ${MISSION_CORE_MODULES} ${MISSION_PSPMODULES}) + set(APP_MISSING_COUNT 0) + + message(STATUS "Search path for modules: ${MISSION_MODULE_SEARCH_PATH}") + + # Now search for the rest of CFS applications/libraries/modules - these may exist in + # any directory within the search path. + foreach(APP ${MISSION_DEPS}) + set (APPFOUND FALSE) + foreach(APPSRC ${MISSION_MODULE_SEARCH_PATH} ${${APP}_SEARCH_PATH}) + if (NOT IS_ABSOLUTE "${APPSRC}") + set(APPSRC "${MISSION_SOURCE_DIR}/${APPSRC}") + endif() + if(IS_DIRECTORY "${APPSRC}/${APP}") + set(APPFOUND "${APPSRC}/${APP}") + break() + endif() + endforeach() + if (APPFOUND) + get_filename_component(${APP}_MISSION_DIR "${APPFOUND}" ABSOLUTE) + message(STATUS "Module '${APP}' found at ${${APP}_MISSION_DIR}") + else() + message("** Module ${APP} NOT found **") + math(EXPR APP_MISSING_COUNT "${APP_MISSING_COUNT} + 1") + endif() + endforeach() + + if (APP_MISSING_COUNT GREATER 0) + message(FATAL_ERROR "Target build incomplete, source for ${APP_MISSING_COUNT} module(s) not found.") + endif (APP_MISSING_COUNT GREATER 0) + + # Export the full set of dependencies to the parent build + # including the individual dependency paths to each component + set(MISSION_DEPS ${MISSION_DEPS} PARENT_SCOPE) + foreach(DEP ${MISSION_DEPS}) + set(${DEP}_MISSION_DIR ${${DEP}_MISSION_DIR} PARENT_SCOPE) + endforeach(DEP ${MISSION_DEPS}) + + # Doxygen-based documentation generation targets + # Create a directory for documentation output + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/doc") + + # Generate a customized Doxyfile file for the Doxygen docs. + # This file must be present in the directory where "doxygen" is executed + # If the user has provided a "Doxyfile" in their top level documentation directory, + # then assume they have also set PROJECT_NAME and PROJECT_BRIEF in that. + # Otherwise, generate reasonable strings for these values. + set(MISSION_DOXYFILE_USER_CONTENT) + if (EXISTS "${MISSION_SOURCE_DIR}/doc/Doxyfile") + list(APPEND MISSION_DOXYFILE_USER_CONTENT "@INCLUDE = ${MISSION_SOURCE_DIR}/doc/Doxyfile\n") + endif (EXISTS "${MISSION_SOURCE_DIR}/doc/Doxyfile") + + foreach(APP ${MISSION_DEPS}) + # OSAL is handled specially, as only part of it is used + if (NOT APP STREQUAL "osal") + if (EXISTS "${${APP}_MISSION_DIR}/docs/${APP}.doxyfile.in") + # If the module provides its own doxyfile, then include it directly + # This allows for app-specific fine-tuning of the sources, based on its own source tree + configure_file("${${APP}_MISSION_DIR}/docs/${APP}.doxyfile.in" + "${CMAKE_BINARY_DIR}/doc/${APP}.doxyfile") + list(APPEND MISSION_DOXYFILE_USER_CONTENT "@INCLUDE = ${CMAKE_BINARY_DIR}/doc/${APP}.doxyfile\n") + else() + # Otherwise just add this entire directory to the "INPUT" list + list(APPEND MISSION_DOXYFILE_USER_CONTENT "INPUT += ${${APP}_MISSION_DIR}\n") + endif() + endif() + endforeach() + + # In all cases it is assumed to include the CFE documentation as well (could be configurable?) + file(WRITE "${CMAKE_BINARY_DIR}/doc/mission-content.doxyfile" + ${MISSION_DOXYFILE_USER_CONTENT}) + + configure_file("${CFE_SOURCE_DIR}/cmake/cfe-common.doxyfile.in" + "${CMAKE_BINARY_DIR}/doc/cfe-common.doxyfile") + + configure_file("${CFE_SOURCE_DIR}/cmake/osal-common.doxyfile.in" + "${CMAKE_BINARY_DIR}/doc/osal-common.doxyfile") + + configure_file("${CFE_SOURCE_DIR}/cmake/mission-detaildesign.doxyfile.in" + "${CMAKE_BINARY_DIR}/doc/mission-detaildesign.doxyfile") + + # Generate an "empty" osconfig.h file for doxygen purposes + # this does not have the actual user-defined values, but will + # have the documentation associated with each macro definition. + configure_file("${osal_MISSION_DIR}/osconfig.h.in" + "${CMAKE_BINARY_DIR}/doc/osconfig-example.h") + + # The user guide should include the doxygen from the _public_ API files from CFE + OSAL + # NOTE: the userguide is built against the headers of the default core apps. Even if + # an alternate version of the module is in use, it should adhere to the same interface. + set(SUBMODULE_HEADER_PATHS + "${osal_MISSION_DIR}/src/os/inc/*.h" + "${psp_MISSION_DIR}/psp/fsw/inc/*.h" + ) + foreach(MODULE core_api es evs fs msg sb tbl time) + list(APPEND SUBMODULE_HEADER_PATHS "${${MODULE}_MISSION_DIR}/fsw/inc/*.h") + endforeach() + file(GLOB MISSION_USERGUIDE_HEADERFILES + ${SUBMODULE_HEADER_PATHS} + "${CMAKE_BINARY_DIR}/doc/osconfig-example.h" + ) + + string(REPLACE ";" " \\\n" MISSION_USERGUIDE_HEADERFILES "${MISSION_USERGUIDE_HEADERFILES}") + + # OSAL API GUIDE include PUBLIC API + file(GLOB MISSION_OSAL_HEADERFILES + "${osal_MISSION_DIR}/src/os/inc/*.h" + "${CMAKE_BINARY_DIR}/doc/osconfig-example.h") + string(REPLACE ";" " \\\n" MISSION_OSAL_HEADERFILES "${MISSION_OSAL_HEADERFILES}") + + configure_file("${CFE_SOURCE_DIR}/cmake/cfe-usersguide.doxyfile.in" + "${CMAKE_BINARY_DIR}/doc/cfe-usersguide.doxyfile") + + configure_file("${CFE_SOURCE_DIR}/cmake/osalguide.doxyfile.in" + "${CMAKE_BINARY_DIR}/doc/osalguide.doxyfile") + + add_custom_target(mission-doc + doxygen mission-detaildesign.doxyfile + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/doc") + + add_custom_target(cfe-usersguide + doxygen cfe-usersguide.doxyfile + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/doc") + + add_custom_target(osalguide + doxygen osalguide.doxyfile + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/doc") + + # Pull in any application-specific mission-scope configuration + # This may include user configuration files such as cfe_mission_cfg.h, + # msgid definitions, or any other configuration/preparation that needs to + # happen at mission/global scope. + foreach(DEP_NAME ${MISSION_DEPS}) + include("${${DEP_NAME}_MISSION_DIR}/mission_build.cmake" OPTIONAL) + endforeach(DEP_NAME ${MISSION_DEPS}) + + # Certain runtime variables need to be "exported" to the subordinate build, such as + # the specific arch settings and the location of all the apps. This is done by creating + # a temporary file within the dir and then the subprocess will read that file and re-create + # variables out of them. The alternative to this is to specify many "-D" parameters to the + # subordinate build but that would not scale well to many vars. + set(VARLIST + "MISSION_NAME" + "SIMULATION" + "MISSION_DEFS" + "MISSION_SOURCE_DIR" + "MISSION_BINARY_DIR" + "MISSIONCONFIG" + "MISSION_APPS" + "MISSION_PSPMODULES" + "MISSION_DEPS" + "ENABLE_UNIT_TESTS" + ) + foreach(APP ${MISSION_DEPS}) + list(APPEND VARLIST "${APP}_MISSION_DIR") + endforeach(APP ${MISSION_APPS}) + + foreach(SYSVAR ${TGTSYS_LIST}) + list(APPEND VARLIST "BUILD_CONFIG_${SYSVAR}") + endforeach(SYSVAR ${TGTSYS_LIST}) + + set(MISSION_VARCACHE) + foreach(VARL ${VARLIST}) + # It is important to avoid putting any blank lines in the output, + # This will cause the reader to misinterpret the data + if (NOT "${${VARL}}" STREQUAL "") + set(MISSION_VARCACHE "${MISSION_VARCACHE}${VARL}\n${${VARL}}\n") + endif (NOT "${${VARL}}" STREQUAL "") + endforeach(VARL ${VARLIST}) + file(WRITE "${CMAKE_BINARY_DIR}/mission_vars.cache" "${MISSION_VARCACHE}") + + generate_build_version_templates() + + # Generate the tools for the native (host) arch + # Add all public include dirs for core components to include path for tools + include_directories( + ${core_api_MISSION_DIR}/fsw/inc + #${es_MISSION_DIR}/fsw/inc + #${evs_MISSION_DIR}/fsw/inc + #${fs_MISSION_DIR}/fsw/inc + #${sb_MISSION_DIR}/fsw/inc + #${tbl_MISSION_DIR}/fsw/inc + #${time_MISSION_DIR}/fsw/inc + ${osal_MISSION_DIR}/src/os/inc + ${psp_MISSION_DIR}/psp/fsw/inc + ) + add_subdirectory(${MISSION_SOURCE_DIR}/tools tools) + + # Add a dependency on the table generator tool as this is required for table builds + # The "elf2cfetbl" target should have been added by the "tools" above + add_dependencies(mission-prebuild elf2cfetbl) + + # Build version information should be generated as part of the pre-build process + add_dependencies(mission-prebuild mission-version) + + # Install the functional test code into the host directory + if (IS_DIRECTORY ${MISSION_DEFS}/functional-test AND DEFINED FT_INSTALL_SUBDIR) + install(DIRECTORY ${MISSION_DEFS}/functional-test/ DESTINATION ${FT_INSTALL_SUBDIR}) + endif() + +endfunction(prepare) + +################################################################## +# +# FUNCTION: process_arch +# +# Called by the top-level CMakeLists.txt to set up targets for this arch +# This is where the real work is done +# +function(process_arch TARGETSYSTEM) + + # The "BUILD_CONFIG" is a list of items to uniquely identify this build + # The first element in the list is the toolchain name, followed by config name(s) + set(BUILD_CONFIG ${BUILD_CONFIG_${TARGETSYSTEM}}) + list(GET BUILD_CONFIG 0 ARCH_TOOLCHAIN_NAME) + list(REMOVE_AT BUILD_CONFIG 0) + # convert to a the string which is safe for a directory name + string(REGEX REPLACE "[^A-Za-z0-9]" "_" ARCH_CONFIG_NAME "${BUILD_CONFIG}") + set(ARCH_BINARY_DIR "${CMAKE_BINARY_DIR}/${ARCH_TOOLCHAIN_NAME}/${ARCH_CONFIG_NAME}") + file(MAKE_DIRECTORY "${ARCH_BINARY_DIR}" "${ARCH_BINARY_DIR}/inc") + + message(STATUS "Configuring for system arch: ${ARCH_TOOLCHAIN_NAME}/${ARCH_CONFIG_NAME}") + + # Note - A warning is issued if you pass CMAKE_TOOLCHAIN_FILE to an already-configured build area + # so an extra check is added to see if this is an initial run or a re-run by checking for a CMakeCache file. + if (NOT ARCH_TOOLCHAIN_NAME STREQUAL "native" AND NOT EXISTS "${ARCH_BINARY_DIR}/CMakeCache.txt") + # Find the toolchain file - allow a file in the mission defs dir to supercede one in the compile dir + if (EXISTS "${MISSION_DEFS}/toolchain-${ARCH_TOOLCHAIN_NAME}.cmake") + set(TOOLCHAIN_FILE "${MISSION_DEFS}/toolchain-${ARCH_TOOLCHAIN_NAME}.cmake") + elseif(EXISTS "${CFE_SOURCE_DIR}/cmake/toolchain-${ARCH_TOOLCHAIN_NAME}.cmake") + set(TOOLCHAIN_FILE "${CFE_SOURCE_DIR}/cmake/toolchain-${ARCH_TOOLCHAIN_NAME}.cmake") + else() + message(FATAL_ERROR "Unable to find toolchain file for ${ARCH_TOOLCHAIN_NAME}") + endif() + set(SELECTED_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE}") + else() + # Do not supply any toolchain file option to the subprocess + set(SELECTED_TOOLCHAIN_FILE) + endif () + + # Execute CMake subprocess to create a binary build tree for the specific CPU architecture + execute_process( + COMMAND ${CMAKE_COMMAND} + -G "Unix Makefiles" + -DTARGETSYSTEM=${TARGETSYSTEM} + -DMISSION_BINARY_DIR=${MISSION_BINARY_DIR} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + ${SELECTED_TOOLCHAIN_FILE} + ${CFE_SOURCE_DIR} + WORKING_DIRECTORY + "${ARCH_BINARY_DIR}" + RESULT_VARIABLE + RESULT + ) + if (NOT RESULT EQUAL 0) + message(FATAL_ERROR "Failed to configure ${TARGETSYSTEM}") + endif (NOT RESULT EQUAL 0) + + # Hook the "make all", "make clean", and "make install" targets for the subordinate build + # to top-level build targets prefixed by the CPU architecture. + add_custom_target(${TARGETSYSTEM}-all + COMMAND + $(MAKE) all + WORKING_DIRECTORY + "${ARCH_BINARY_DIR}" + ) + add_custom_target(${TARGETSYSTEM}-clean + COMMAND + $(MAKE) clean + WORKING_DIRECTORY + "${ARCH_BINARY_DIR}" + ) + add_custom_target(${TARGETSYSTEM}-install + COMMAND + $(MAKE) install + WORKING_DIRECTORY + "${ARCH_BINARY_DIR}" + ) + + # All subordinate builds depend on the generated files being present first + add_dependencies(${TARGETSYSTEM}-install mission-prebuild) + add_dependencies(${TARGETSYSTEM}-all mission-prebuild) + + add_dependencies(mission-all ${TARGETSYSTEM}-all) + add_dependencies(mission-clean ${TARGETSYSTEM}-clean) + add_dependencies(mission-install ${TARGETSYSTEM}-install) + +endfunction(process_arch TARGETSYSTEM) + + diff --git a/cmake/mission_defaults.cmake b/cmake/mission_defaults.cmake new file mode 100644 index 000000000..e023e791a --- /dev/null +++ b/cmake/mission_defaults.cmake @@ -0,0 +1,64 @@ +################################################################## +# +# cFS Mission default values +# +# This file provides default values for mission applications +# and module/library selection. +# +################################################################## + +# The "MISSION_CORE_MODULES" will be built and statically linked as part +# of the CFE core executable on every target. These can be used to amend +# or override parts of the CFE core on a mission-specific basis. +# The "intf" modules are headers only, and define the interface(s) between components +set(MISSION_CORE_MODULES + "core_api" + "core_private" + "es" + "evs" + "fs" + "sb" + "tbl" + "time" + "osal" + "psp" + "msg" + "sbr" + "resourceid" +) + +# The "MISSION_GLOBAL_APPLIST" is a set of apps/libs that will be built +# for every defined and target. These are built as dynamic modules +# and must be loaded explicitly via startup script or command. +# This list is effectively appended to every TGTx_APPLIST in targets.cmake. +set(MISSION_GLOBAL_APPLIST) + +# The "MISSION_GLOBAL_STATIC_APPLIST" is similar to MISSION_GLOBAL_APPLIST +# but the apps are statically linked. +# This list is effectively appended to every TGTx_STATIC_APPLIST in targets.cmake. +set(MISSION_GLOBAL_STATIC_APPLIST) + +# The "MISSION_MODULE_SEARCH_PATH" is a list of subdirectories +# which will be searched for modules (apps and libs) specified in +# the targets.cmake file. It may also be locally extended by setting +# the environment variable "CFS_APP_PATH" +set(MISSION_MODULE_SEARCH_PATH + "apps" # general purpose $[top}/apps directory + "libs" # general purpose $[top}/libs directory + "psp/fsw/modules" # modules for optional platform abstraction, associated with PSP + "cfe/modules" # modules for optional core functions, associated with CFE +) + +# The path for specific components can also be set via +# a variable named "_SEARCH_PATH". This is +# used for locating other modules that are not part +# of the standard search path. +set(osal_SEARCH_PATH ".") +set(psp_SEARCH_PATH ".") + +# If ENABLE_UNIT_TEST is enabled, then include the cfe_assert library in +# all targets. This can still be overridden in targets.cmake. +if (ENABLE_UNIT_TESTS) + list(APPEND MISSION_GLOBAL_APPLIST cfe_assert cfe_testrunner cfe_testcase) +endif (ENABLE_UNIT_TESTS) + diff --git a/cmake/target/CMakeLists.txt b/cmake/target/CMakeLists.txt new file mode 100644 index 000000000..33ad47da0 --- /dev/null +++ b/cmake/target/CMakeLists.txt @@ -0,0 +1,276 @@ +################################################################## +# +# cFS executable target recipe +# +# This CMake script integrates the CFE core, PSP, and selected CFS +# apps into a final executable target. +# +# No additional source code is built here, it only serves as a final build +# stage to link the libraries together. +# +################################################################## + +project(CFETARGET C) + +# Sanity check on inputs - these should be set in the parent script(s) +if (NOT DEFINED TGTNAME) + message(FATAL_ERROR "TGTNAME must be defined to link a final exe") +endif (NOT DEFINED TGTNAME) + +if (NOT DEFINED ${TGTNAME}_PROCESSORID) + message(FATAL_ERROR "${TGTNAME}_PROCESSORID must be defined to link a final exe") +endif (NOT DEFINED ${TGTNAME}_PROCESSORID) + +string(CONCAT GENERATED_FILE_HEADER + "/* This file is auto-generated from CMake build system. Do not manually edit! */\n" + "#include \"target_config.h\"\n" +) + +string(CONCAT GENERATED_FILE_TRAILER + "/* End of file */\n" +) + +# Generate a list of PSP modules along with a pointer to its API structure/entry point +set(GENERATED_EXTERNS) +set(GENERATED_KEYVALS) +foreach(PSPMOD ${${TGTNAME}_PSP_MODULELIST}) + list(APPEND GENERATED_EXTERNS "extern char CFE_PSP_${PSPMOD}_API\;\n") + list(APPEND GENERATED_KEYVALS "{ .Name = \"${PSPMOD}\", .Api = &CFE_PSP_${PSPMOD}_API },\n") +endforeach(PSPMOD ${${TGTNAME}_PSP_MODULELIST}) + +string(CONCAT GENERATED_FILE_CONTENT + ${GENERATED_EXTERNS} + "const CFE_StaticModuleLoadEntry_t CFE_PSP_MODULE_LIST[] = {\n" + ${GENERATED_KEYVALS} + "{ NULL } /* End of list */\n" + "};\n" +) + +configure_file(${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_CURRENT_BINARY_DIR}/cfe_psp_module_list.c) + +# Generate lists of modules that will be statically linked into this CFE core target +set(GENERATED_ENTRIES_CORE_MODULES) +foreach(DEP ${MISSION_CORE_MODULES}) + list(APPEND GENERATED_ENTRIES_CORE_MODULES "{ \"${DEP}\" },\n") +endforeach() + +set(GENERATED_ENTRIES_STATIC_APPS) +foreach(DEP ${${TGTNAME}_STATIC_APPLIST}) + list(APPEND GENERATED_ENTRIES_STATIC_APPS "{ \"${DEP}\" },\n") +endforeach() + +string(CONCAT GENERATED_FILE_CONTENT + "CFE_ConfigName_t CFE_CORE_MODULE_LIST[] = {\n" + ${GENERATED_ENTRIES_CORE_MODULES} + "{ NULL } /* End of list */\n" + "};\n" + "CFE_ConfigName_t CFE_STATIC_APP_LIST[] = {\n" + ${GENERATED_ENTRIES_STATIC_APPS} + "{ NULL } /* End of list */\n" + "};\n" +) + +configure_file(${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_module_list.c) + +# Generate a list of symbol names that must be known at runtime without OS loader support +set(GENERATED_EXTERNS) +set(GENERATED_KEYVALS) +foreach(CFSSYM ${${TGTNAME}_STATIC_SYMLIST}) + string(REPLACE "," ";" CFSSYM "${CFSSYM}") + list(GET CFSSYM 0 SYM_NAME) + list(GET CFSSYM 1 SYM_MODULE) + list(APPEND GENERATED_EXTERNS "extern void ${SYM_NAME} (void)\;\n") + list(APPEND GENERATED_KEYVALS "{ .Name = \"${SYM_NAME}\", .Address = &${SYM_NAME}, .Module = \"${SYM_MODULE}\" },") +endforeach(CFSSYM ${${TGTNAME}_STATIC_SYMLIST}) + +string(CONCAT GENERATED_FILE_HEADER + "/* This file is auto-generated from CMake build system. Do not manually edit! */\n" + "#include \"osapi-module.h\"\n" +) + +string(CONCAT GENERATED_FILE_CONTENT + ${GENERATED_EXTERNS} + "OS_static_symbol_record_t OS_STATIC_SYMBOL_TABLE[] = {\n" + ${GENERATED_KEYVALS} + "{ NULL } /* End of list */\n" + "};\n" +) + +configure_file(${CFE_SOURCE_DIR}/cmake/cfe_generated_file.h.in ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_symbol_list.c) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cfe_build_env_table.c + COMMAND ${CMAKE_COMMAND} -E copy + ${MISSION_BINARY_DIR}/src/cfe_build_env_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_build_env_table.c + DEPENDS + ${MISSION_BINARY_DIR}/src/cfe_build_env_table.c +) +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cfe_module_version_table.c + COMMAND ${CMAKE_COMMAND} -E copy + ${MISSION_BINARY_DIR}/src/cfe_module_version_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_module_version_table.c + DEPENDS + ${MISSION_BINARY_DIR}/src/cfe_module_version_table.c +) + +# Target for the final executable +add_executable(core-${TGTNAME} + ${MISSION_BINARY_DIR}/src/cfe_mission_strings.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_module_version_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_build_env_table.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_psp_module_list.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_symbol_list.c + ${CMAKE_CURRENT_BINARY_DIR}/cfe_static_module_list.c + src/target_config.c +) + +target_compile_definitions(core-${TGTNAME} PRIVATE + CFE_DEFAULT_MODULE_EXTENSION="${CMAKE_SHARED_MODULE_SUFFIX}" + CFE_DEFAULT_CORE_FILENAME="$" + CFE_CPU_NAME_VALUE="${TGTNAME}" + CFE_SPACECRAFT_ID_VALUE=${SPACECRAFT_ID} + CFE_CPU_ID_VALUE=${${TGTNAME}_PROCESSORID} +) + +target_include_directories(core-${TGTNAME} PRIVATE + "${CMAKE_BINARY_DIR}/${CFE_CORE_TARGET}/inc" +) + +# This next section provides a method for adding the "-u" switch to the +# linker in order to make sure the linker includes certain symbols in the link. +# This problem may exist for the entry point or other symbols if the +# linker doesn't know that they are unresolved when it links those files. +set (TARGET_LINK_FLAGS) +foreach(SYM ${CFE_ENTRY_SYM}) + set (TARGET_LINK_FLAGS "${TARGET_LINK_FLAGS} -u ${SYM}") +endforeach() + +set_target_properties(core-${TGTNAME} PROPERTIES LINK_FLAGS "${TARGET_LINK_FLAGS}") + +# We may need to use the "--whole-archive" flags to CFE, OSAL, and PSP to ensure that ALL +# symbols make their way into the final executable. The "--enable-exports" +# (enabled by the ENABLE_EXPORTS property) does not apply to static libs on the link line +# This is only a concern when relying on the dynamic module loader, if we are statically +# linking the entire CFE system into a single binary then no special help is needed. +if (${TGTNAME}_APPLIST) + + set_target_properties(core-${TGTNAME} PROPERTIES ENABLE_EXPORTS TRUE) + + if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + # The option pair for GNU gcc/ld tools + set(START_WHOLE_ARCHIVE "--whole-archive") + set(STOP_WHOLE_ARCHIVE "--no-whole-archive") + + # the linker option prefix may or may not be needed, see below + set(COMPILER_LINKER_OPTION_PREFIX "-Wl,") + else() + # Other toolchain options may be added here + endif() + + # Determine if a pass-through prefix is needed for a linker option. + # This prefix is required if the link is invoked through gcc, + # but will fail if calling the linker directory + # Unfortunately there is no way to directly get this info, + # but the platform should set CMAKE_EXE_EXPORTS_C_FLAG + # for the ENABLE_EXPORTS property, so this just checks + # if this starts with -Wl, and if so, use it here too. + if (DEFINED COMPILER_LINKER_OPTION_PREFIX AND + "${CMAKE_EXE_EXPORTS_C_FLAG}" MATCHES "^${COMPILER_LINKER_OPTION_PREFIX}") + set(START_WHOLE_ARCHIVE "${COMPILER_LINKER_OPTION_PREFIX}${START_WHOLE_ARCHIVE}") + set(STOP_WHOLE_ARCHIVE "${COMPILER_LINKER_OPTION_PREFIX}${STOP_WHOLE_ARCHIVE}") + endif() + +endif (${TGTNAME}_APPLIST) + +# Collect any additional libraries that should be included on the link line +# This depends on whether any special features are included or not +set(CFE_LINK_WHOLE_LIBS + ${MISSION_CORE_MODULES} +) +set(CFE_LINK_NORMAL_LIBS + ${${TGTNAME}_PSP_MODULELIST} + ${${TGTNAME}_STATIC_APPLIST} +) + +# Handle the list of "embedded files" that should be linked into CFE. +# These are arbitrary files in the mission config that are converted +# into C data structures and linked with the executable. This is +# a helpful feature for use when statically linking the CFE. +if (DEFINED ${TGTNAME}_EMBED_FILELIST) + + set(EMBFILE_GENSRC_LIST) # a list of C source files to compile + set(EMBFILE_CONTENT_LIST) # a list of content targets for dependencies + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/embed") # work area + + # Loop through each entry, which should be of the form: + # VARIABLE_NAME,FILE_NAME + # Where "VARIABLE_NAME" indicates the name to use for the + # generated C data structure, and FILE_NAME is the data file + # that it is sourced from (no paths, it will be searched). + foreach(LISTENT ${${TGTNAME}_EMBED_FILELIST}) + string(REPLACE "," ";" LISTENT ${LISTENT}) # split on the comma + list(GET LISTENT 0 EMBNAME) # EMBNAME => C variable name + list(GET LISTENT 1 EMBFILE) # EMBFILE => File name + + # Find the real source of the file and store in FILESRC + if(EXISTS ${MISSION_DEFS}/${TGTNAME}_${EMBFILE}) + set(FILESRC ${MISSION_DEFS}/${TGTNAME}_${EMBFILE}) + elseif(EXISTS ${MISSION_DEFS}/${EMBFILE}) + set(FILESRC ${MISSION_DEFS}/${EMBFILE}) + else() + message(FATAL_ERROR "ERROR: Embed file ${EMBFILE} for ${TGTNAME} not found") + endif() + + # Use the "xxd" utility to convert the binary file to a C array + # Note that this pipes the original file to stdin of xxd, so it + # does not create a usable C file, just array content. + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBNAME}.inc" + COMMAND xxd -i < "${FILESRC}" > "${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBNAME}.inc" + DEPENDS "${FILESRC}") + + # Create a ".c" file that wraps the binary file, using the + # configure_file() command. This is done this way (rather than + # using xxd entirely) for two reasons: + # a) it can use our preferred VARIABLE_NAME + # b) it can be qualified as "const" + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBNAME}.c" + "const unsigned char ${EMBNAME}_DATA[] = {\n" + "#include \"${EMBNAME}.inc\"\n" + "};\n" + "const unsigned long ${EMBNAME}_SIZE = sizeof(${EMBNAME}_DATA);\n") + + list(APPEND EMBFILE_GENSRC_LIST "${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBNAME}.c") + list(APPEND EMBFILE_CONTENT_LIST "${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBNAME}.inc") + + endforeach(LISTENT ${${TGTNAME}_EMBED_FILELIST}) + + # Finally, generate a static library that contains all embeded binary files + # and add this to the list of libraries that the CFE will be linked with. + # add a dependency so that the "inc" files are regenerated and the library + # is rebuilt before the static library is built. + add_library(${TGTNAME}_embed_files STATIC ${EMBFILE_GENSRC_LIST}) + add_custom_target(${TGTNAME}_embed_content DEPENDS ${EMBFILE_CONTENT_LIST}) + add_dependencies(${TGTNAME}_embed_files ${TGTNAME}_embed_content) + list(APPEND CFE_LINK_NORMAL_LIBS ${TGTNAME}_embed_files) + +endif (DEFINED ${TGTNAME}_EMBED_FILELIST) + +target_link_libraries(core-${TGTNAME} + # The following libs should be included whole, even if they + # do not necessarily resolve any symbols, because they may be needed by apps + ${START_WHOLE_ARCHIVE} + ${CFE_LINK_WHOLE_LIBS} + ${STOP_WHOLE_ARCHIVE} + + # The remainder are static libraries that should only be + # included if they resolve an undefined symbol (normal link logic) + ${CFE_LINK_NORMAL_LIBS} + ${OSAL_LINK_LIBS} +) + +# Install the final executable +# This is implemented in a separate function so +# it may be overridden in an OS-specific manner if necessary. +cfe_exec_do_install(${TGTNAME}) + diff --git a/cmake/target/inc/target_config.h b/cmake/target/inc/target_config.h new file mode 100644 index 000000000..170a38f05 --- /dev/null +++ b/cmake/target/inc/target_config.h @@ -0,0 +1,211 @@ +/* +** 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 + * + * Defines structures for the global system-wide configuration data. + * These structures can be accessed at runtime and are an alternative to + * setting tunable parameters with preprocessor macros. By putting the + * tunable parameter in here and accessing it at runtime, the object + * code becomes more portable. + */ + +#ifndef TARGET_CONFIG_H +#define TARGET_CONFIG_H + +#include "common_types.h" + +/** + * Prototype for the main system entry function implemented in CFE ES + * The PSP should call this at start up. + */ +typedef void (*System_MainFunc_t)(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const char *StartFilePath); + +/** + * Prototype for 1Hz ISR function implemented in CFE TIME + * The PSP should call this at 1Hz. + */ +typedef void (*System_1HzISRFunc_t)(void); + +/** + * Prototype for notification function implemented in CFE ES + * The PSP should call this when exceptions occur. + * + * NOTE: the PSP must call this routine only from a context where + * it is possible to use OSAL primitives. This means it must _not_ + * be called from an ISR/signal context on systems where these are + * restricted. + */ +typedef void (*System_NotifyFunc_t)(void); + +/** + * Abstract pointer to a module API + * Contents are not defined at this level - the PSP/CFE implementation actually defines this. + */ +typedef const void CFE_StaticModuleApi_t; + +/** + * Combines a module API with a name to create the static module list. + */ +typedef const struct +{ + const char * Name; + CFE_StaticModuleApi_t *Api; +} CFE_StaticModuleLoadEntry_t; + +/** + * A record containing a configuration name + * This is a single entry in a list of simple strings. + */ +typedef const struct +{ + const char *Name; +} CFE_ConfigName_t; + +/** + * A record containing a configuration key-value pair + * The data are simple strings defined at compile time, and + * do not change until next build (always const). + */ +typedef const struct +{ + const char *Key; + const void *Value; +} CFE_ConfigKeyValue_t; + +/** + * Core Flight Executive configuration information. + */ +typedef const struct +{ + /** + * 1Hz ISR entry point. Called from PSP once per second on HW clock. + */ + System_1HzISRFunc_t System1HzISR; + + /** + * Main CFE entry point. Called from PSP startup code. + */ + System_MainFunc_t SystemMain; + + /** + * Notification function. Called from PSP after async event handling. + */ + System_NotifyFunc_t SystemNotify; + + /* + * Sizes of memory segments required by the CFE based on the current config + */ + uint32 CdsSize; /***< CDS segment size */ + uint32 ResetAreaSize; /***< Reset area segment size */ + uint32 UserReservedSize; /***< User reserved area segment size */ + uint32 RamDiskSectorSize; /***< RAM disk sector size */ + uint32 RamDiskTotalSectors; /***< RAM disk number of sectors */ + + /** + * Default value for nonvolatile file system mount point + */ + const char *NonvolMountPoint; + + /** + * Default value for volatile file system mount point + */ + const char *RamdiskMountPoint; + + /** + * File name of startup script + */ + const char *NonvolStartupFile; + +} Target_CfeConfigData; + +/** + * Extern reference to cfe config struct. + * Allows the actual instantiation to be done outside this module + */ +extern Target_CfeConfigData GLOBAL_CFE_CONFIGDATA; + +/** + * Build system information + * This data will be auto-populated by the build scripts + * + * Note that with some PSP's (such as the linux ones) the values + * for CPU name and number may be overridden, so the correct value + * for these should be acquired through the PSP via the normal API. + * The values in this structure are only the defaults. + */ +typedef const struct +{ + const char *MissionName; /**< The Mission Name from confguration */ + + /* + * Note: the version strings in these fields should reflect the administratively-assigned + * "semantic version" identifiers, typically from a "version.h" header file of + * some type which is manually updated at various points in the development cycle. + * + * This is separate/distinct from the source control based revision + * information, although it may be similar/related. All automatically + * obtained source revision info is in the "ModuleVersionList" below. + */ + const char *MissionVersion; /**< Version string from mission source tree at build time (currently unused/unset) */ + const char *CfeVersion; /**< Version string from CFE source tree at build time */ + const char *OsalVersion; /**< Version string from OSAL source tree at build time */ + + const char *Config; /**< Configuration used for build */ + + /* + * Note: date and user info have been moved into the BuildEnvironment below, + * but these members must exist in this structure (for now) for compatibility. + * These pointers will be NULL at runtime. + */ + const char *Date; /**< Not set. Get value from BuildEnvironment instead. */ + const char *User; /**< Not set. Get value from BuildEnvironment instead. */ + + /* + * Default values for CPU ID and CPU Name + */ + const char *Default_CpuName; /**< Compile-time value for CPU name */ + uint16 Default_CpuId; /**< Compile-time value for CPU number */ + uint16 Default_SpacecraftId; /**< Compile-time value for Spacecraft ID (mission-wide) */ + + const char *Default_ModuleExtension; /**< Default system extension for dynamic modules */ + const char *Default_CoreFilename; /**< Default file name for CFE core executable/library */ + + Target_CfeConfigData *CfeConfig; /**< CFE configuration sub-structure */ + CFE_StaticModuleLoadEntry_t + *PspModuleList; /**< List of PSP modules (API structures) statically linked into the core EXE */ + + CFE_ConfigKeyValue_t + *BuildEnvironment; /**< Environment details of build system at the last time CFE core was built */ + CFE_ConfigKeyValue_t *ModuleVersionList; /**< List of module versions at the last time CFE core was built */ + CFE_ConfigName_t * CoreModuleList; /**< List of CFE core support module names that are statically linked */ + CFE_ConfigName_t + *StaticAppList; /**< List of additional CFS Applications that are statically linked into this binary */ + +} Target_ConfigData; + +/** + * Extern reference to global config struct. + * This object is always instantiated within this module + */ +extern Target_ConfigData GLOBAL_CONFIGDATA; + +#endif /* TARGET_CONFIG_H */ diff --git a/cmake/target/src/target_config.c b/cmake/target/src/target_config.c new file mode 100644 index 000000000..2995bd73c --- /dev/null +++ b/cmake/target/src/target_config.c @@ -0,0 +1,182 @@ +/* +** 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 target_config.c + * + * Created on: Dec 3, 2013 + * Created by: joseph.p.hickey@nasa.gov + * + * Defines constant configuration structures and pointers that link together + * the CFE core, PSP, OSAL. The content of these configuration structures + * can be used to avoid directly using #include to reference a function + * implemented in another library, which can greatly simplify include paths + * and create a more modular build. + * + */ + +#include "target_config.h" +#include "cfe_mission_cfg.h" +#include "cfe_platform_cfg.h" +#include "cfe_es.h" +#include "cfe_time.h" +#include "cfe_es_resetdata_typedef.h" +#include "cfe_version.h" /* for CFE_VERSION_STRING */ +#include "osapi-version.h" /* for OS_VERSION_STRING */ + +#ifndef CFE_CPU_NAME_VALUE +#define CFE_CPU_NAME_VALUE "unknown" +#endif + +#ifndef CFE_CPU_ID_VALUE +#define CFE_CPU_ID_VALUE 0 +#endif + +#ifndef CFE_SPACECRAFT_ID_VALUE +#define CFE_SPACECRAFT_ID_VALUE 0x42 +#endif + +#ifndef CFE_DEFAULT_MODULE_EXTENSION +#define CFE_DEFAULT_MODULE_EXTENSION "" +#endif + +#ifndef CFE_DEFAULT_CORE_FILENAME +#define CFE_DEFAULT_CORE_FILENAME "" +#endif + +/* + * Many configdata items are instantiated by the + * build system, where it generates a .c file containing + * the data, which is then compiled and linked with this file. + */ + +extern const char CFE_MISSION_NAME[]; /**< Name of CFE mission */ +extern const char CFE_MISSION_CONFIG[]; /**< Configuration name used for build */ + +/** + * A list of modules which are statically linked into CFE core. + * + * For module names which appear in this list, the code is directly + * linked into the core executable binary file, and therefore means + * several things: + * + * - the module code is guaranteed to be present + * - functions it provides may be used by CFE core apps + * - it cannot be updated/changed without rebuilding CFE core. + */ +extern CFE_ConfigName_t CFE_CORE_MODULE_LIST[]; + +/** + * A list of CFS apps which are also statically linked with this binary. + * + * These apps can be started without dynamically loading any modules, + * however the entry point must be separately provided in order to avoid + * needing any support from the OS dynamic loader subsystem. + */ +extern CFE_ConfigName_t CFE_STATIC_APP_LIST[]; + +/** + * A key-value table containing certain environment information from the build system + * at the time CFE core was built. + * + * This contains basic information such as the time of day, build host, and user. + */ +extern CFE_ConfigKeyValue_t CFE_BUILD_ENV_TABLE[]; + +/** + * Version control (source code) versions of all modules + * + * This list includes all modules known to the build system as determined by the + * version control system in use (e.g. git). It is generated by a post-build step + * to query version control and should change automatically every time code is + * checked in or out. + * + * Notably this includes _all_ modules known to the build system at the time CFE + * core was built, regardless of whether those modules are configured for runtime + * (dynamic) or static linkage. + * + * For dynamic modules, this means the version info can become outdated if/when + * a single module is rebuilt/reloaded after the original CFE build. The keys in + * this table may be be checked against the CFE_STATIC_MODULE_LIST above to + * determine if static or dynamic linkage was used. In the case of dynamic linkage, + * then this table only represents the version of the module that was present at the + * time CFE was built, not necessarily the version on the target filesystem. + */ +extern CFE_ConfigKeyValue_t CFE_MODULE_VERSION_TABLE[]; + +/** + * A list of PSP modules included in this build of CFE core. + * + * These are always statically linked, and this table contains a pointer + * to its API structure, which in turn contains its entry point. + */ +extern CFE_StaticModuleLoadEntry_t CFE_PSP_MODULE_LIST[]; + +/** + * A structure that encapsulates all the CFE static configuration + */ +Target_CfeConfigData GLOBAL_CFE_CONFIGDATA = { + /* + * Entry points to CFE code called by the PSP + */ + .System1HzISR = CFE_TIME_Local1HzISR, + .SystemMain = CFE_ES_Main, + .SystemNotify = CFE_ES_ProcessAsyncEvent, + + /* + * Default values for various file paths + */ + .NonvolMountPoint = CFE_PLATFORM_ES_NONVOL_DISK_MOUNT_STRING, + .RamdiskMountPoint = CFE_PLATFORM_ES_RAM_DISK_MOUNT_STRING, + .NonvolStartupFile = CFE_PLATFORM_ES_NONVOL_STARTUP_FILE, + + /* + * Sizes of other memory segments + */ + .CdsSize = CFE_PLATFORM_ES_CDS_SIZE, + .ResetAreaSize = sizeof(CFE_ES_ResetData_t), + .UserReservedSize = CFE_PLATFORM_ES_USER_RESERVED_SIZE, + + .RamDiskSectorSize = CFE_PLATFORM_ES_RAM_DISK_SECTOR_SIZE, + .RamDiskTotalSectors = CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS}; + +/** + * Instantiation of global system-wide configuration struct + * This contains build info plus pointers to the PSP and CFE + * configuration structures. Everything will be linked together + * in the final executable. + */ +Target_ConfigData GLOBAL_CONFIGDATA = { + .MissionName = CFE_MISSION_NAME, + .CfeVersion = CFE_SRC_VERSION, + .OsalVersion = OS_VERSION, + .Config = CFE_MISSION_CONFIG, + .Default_CpuName = CFE_CPU_NAME_VALUE, + .Default_CpuId = CFE_CPU_ID_VALUE, + .Default_SpacecraftId = CFE_SPACECRAFT_ID_VALUE, + .Default_ModuleExtension = CFE_DEFAULT_MODULE_EXTENSION, + .Default_CoreFilename = CFE_DEFAULT_CORE_FILENAME, + .CfeConfig = &GLOBAL_CFE_CONFIGDATA, + .PspModuleList = CFE_PSP_MODULE_LIST, + .BuildEnvironment = CFE_BUILD_ENV_TABLE, + .ModuleVersionList = CFE_MODULE_VERSION_TABLE, + .CoreModuleList = CFE_CORE_MODULE_LIST, + .StaticAppList = CFE_STATIC_APP_LIST, +}; From 8968169839569bc4d58ba76ba363f9c41f930a6e Mon Sep 17 00:00:00 2001 From: "Gerardo E. Cruz-Ortiz" <59618057+astrogeco@users.noreply.github.com> Date: Wed, 7 Apr 2021 21:18:51 -0400 Subject: [PATCH 2/5] CaelumReview-CFS40, cFE-core --- .gitignore | 6 + modules/core_api/fsw/inc/cfe.h | 57 + modules/core_api/fsw/inc/cfe_endian.h | 71 ++ modules/core_api/fsw/inc/cfe_error.h | 1368 ++++++++++++++++++++++++ modules/core_api/fsw/inc/cfe_version.h | 61 ++ 5 files changed, 1563 insertions(+) create mode 100644 modules/core_api/fsw/inc/cfe.h create mode 100644 modules/core_api/fsw/inc/cfe_endian.h create mode 100644 modules/core_api/fsw/inc/cfe_error.h create mode 100644 modules/core_api/fsw/inc/cfe_version.h diff --git a/.gitignore b/.gitignore index e4d4dc2a1..5a17b9313 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,9 @@ !cmake/mission_defaults.cmake !/CMakeLists.txt + +# cFE-Core +!modules/core_api/fsw/inc/cfe.h +!modules/core_api/fsw/inc/cfe_endian.h +!modules/core_api/fsw/inc/cfe_error.h +!modules/core_api/fsw/inc/cfe_version.h diff --git a/modules/core_api/fsw/inc/cfe.h b/modules/core_api/fsw/inc/cfe.h new file mode 100644 index 000000000..218afd9cb --- /dev/null +++ b/modules/core_api/fsw/inc/cfe.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 + * + * Purpose: cFE header file + * + * Author: David Kobe, the Hammers Company, Inc. + * + * Notes: This header file centralizes the includes for all cFE + * Applications. It includes all header files necessary + * to completely define the cFE interface. + * + */ + +#ifndef CFE_H +#define CFE_H + +#include "common_types.h" /* Define basic data types */ + +#include "osapi.h" /* Define OS API function prototypes */ + +#include "cfe_mission_cfg.h" /* Define mission configuration parameters */ + +#include "cfe_error.h" /* Define common cFE error codes */ + +#include "cfe_es.h" /* Define Executive Service API */ +#include "cfe_evs.h" /* Define Event Service API */ +#include "cfe_fs.h" /* Define File Service API */ +#include "cfe_sb.h" /* Define Software Bus API */ +#include "cfe_time.h" /* Define Time Service API */ +#include "cfe_tbl.h" /* Define Table Service API */ + +#include "cfe_msg.h" /* Define Message API */ +#include "cfe_resourceid.h" /* Define ResourceID API */ + +#include "cfe_psp.h" /* Define Platform Support Package API */ + +#endif /* CFE_H */ diff --git a/modules/core_api/fsw/inc/cfe_endian.h b/modules/core_api/fsw/inc/cfe_endian.h new file mode 100644 index 000000000..16f578631 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_endian.h @@ -0,0 +1,71 @@ +/* +** 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: + * Define macros to enforce big-endian/network byte order for 16 and 32 bit integers + * + */ + +#ifndef CFE_ENDIAN_H +#define CFE_ENDIAN_H + +/* +** Include Files +*/ +#include "common_types.h" + +/* + * SOFTWARE_BIG/LITTLE_BIT_ORDER COMPATIBILITY MACRO - + * + * This is provided only for backward compatibilty. Do not write any new code that + * uses this macro. + */ +#if !defined(SOFTWARE_BIG_BIT_ORDER) && !defined(SOFTWARE_LITTLE_BIT_ORDER) + +#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || defined(__BIG_ENDIAN__) || defined(__ARMEB__) || \ + defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) +/* It is a big-endian target architecture */ +#define SOFTWARE_BIG_BIT_ORDER +#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \ + defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \ + defined(__i386) || defined(__i386__) || defined(__i686) || defined(__i686__) || defined(__x86_64) || \ + defined(__x86_64__) +/* It is a little-endian target architecture */ +#define SOFTWARE_LITTLE_BIT_ORDER +#else +#error Unknown byte order on this platform +#endif + +#endif /* !defined(SOFTWARE_BIG_BIT_ORDER) && !defined(SOFTWARE_LITTLE_BIT_ORDER) */ + +/* Macro to convert 16/32 bit types from platform "endianness" to Big Endian */ +#ifdef SOFTWARE_BIG_BIT_ORDER +#define CFE_MAKE_BIG16(n) (n) +#define CFE_MAKE_BIG32(n) (n) +#else +#define CFE_MAKE_BIG16(n) ((((n) << 8) & 0xFF00) | (((n) >> 8) & 0x00FF)) +#define CFE_MAKE_BIG32(n) \ + ((((n) << 24) & 0xFF000000) | (((n) << 8) & 0x00FF0000) | (((n) >> 8) & 0x0000FF00) | (((n) >> 24) & 0x000000FF)) +#endif + +#endif /* CFE_ENDIAN_H */ diff --git a/modules/core_api/fsw/inc/cfe_error.h b/modules/core_api/fsw/inc/cfe_error.h new file mode 100644 index 000000000..8b9461cb8 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_error.h @@ -0,0 +1,1368 @@ +/* +** 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 + * + * Title: cFE Status Code Definition Header File + * + * Purpose: + * Common source of cFE API return status codes. + * + * Design Notes: + * + * References: + * Flight Software Branch C Coding Standard Version 1.0a + * + */ + +#ifndef CFE_ERROR_H +#define CFE_ERROR_H + +/* Include Files */ +#include "osapi.h" + +/* + * Define a type for readability. + */ +typedef int32 CFE_Status_t; + +/* +** Status Codes are 32 bit values formatted as follows: +** +** 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +** 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +** +---+---+-----+-----------------+-------------------------------+ +** |Sev| R | Srv | Mission Defined | Code | +** +---+---+-----+-----------------+-------------------------------+ +** +** where +** +** Sev - is the severity code +** +** 00 - Success +** 01 - Informational +** 11 - Error +** +** R - are reserved bits +** +** Srv - is the cFE Service Identifier +** +** 000 - Not a cFE Service +** 001 - Events Services +** 010 - Executive Services +** 011 - File Services +** 100 - Generic code for all services +** 101 - Software Bus Services +** 110 - Tables Services +** 111 - Time Services +** +** Mission Defined - These bits are available for Mission +** specific coding standards. They can +** be used to classify error codes related +** to mission specific library function calls, etc. +** +** Code - is the status code +*/ + +/* +** Error Severity +*/ +#define CFE_SEVERITY_BITMASK ((CFE_Status_t)0xc0000000) /**< @brief Error Severity Bitmask */ + +#define CFE_SEVERITY_SUCCESS ((CFE_Status_t)0x00000000) /**< @brief Severity Success */ +#define CFE_SEVERITY_INFO ((CFE_Status_t)0x40000000) /**< @brief Severity Info */ +#define CFE_SEVERITY_ERROR ((CFE_Status_t)0xc0000000) /**< @brief Severity Error */ + +/* +** cFE Service Identifiers +*/ +#define CFE_SERVICE_BITMASK ((CFE_Status_t)0x0e000000) /**< @brief Error Service Bitmask */ + +#define CFE_EVENTS_SERVICE ((CFE_Status_t)0x02000000) /**< @brief Event Service */ +#define CFE_EXECUTIVE_SERVICE ((CFE_Status_t)0x04000000) /**< @brief Executive Service */ +#define CFE_FILE_SERVICE ((CFE_Status_t)0x06000000) /**< @brief File Service */ +#define CFE_GENERIC_SERVICE ((CFE_Status_t)0x08000000) /**< @brief Generic Service */ +#define CFE_SOFTWARE_BUS_SERVICE ((CFE_Status_t)0x0a000000) /**< @brief Software Bus Service */ +#define CFE_TABLE_SERVICE ((CFE_Status_t)0x0c000000) /**< @brief Table Service */ +#define CFE_TIME_SERVICE ((CFE_Status_t)0x0e000000) /**< @brief Time Service */ + +/* +************* COMMON STATUS CODES ************* +*/ + +/** @defgroup CFEReturnCodes cFE Return Code Defines + * @{ + */ + +/** + * @brief Sucessful execution + * + * Operation was performed successfully + */ +#define CFE_SUCCESS (0) + +/** + * @brief No Counter Increment + * + * Informational code indicating that a command was processed + * successfully but that the command counter should _not_ be incremented. + */ +#define CFE_STATUS_NO_COUNTER_INCREMENT ((CFE_Status_t)0x48000001) + +/** + * @brief Wrong Message Length + * + * This error code will be returned when a message validation process + * determined that the message length is incorrect + * + */ +#define CFE_STATUS_WRONG_MSG_LENGTH ((CFE_Status_t)0xc8000002) + +/** + * @brief Unknown Message ID + * + * This error code will be returned when a message identification process + * determined that the message ID does not correspond to a known value + * + */ +#define CFE_STATUS_UNKNOWN_MSG_ID ((CFE_Status_t)0xc8000003) + +/** + * @brief Bad Command Code + * + * This error code will be returned when a message identification process + * determined that the command code is does not correspond to any known value + * + */ +#define CFE_STATUS_BAD_COMMAND_CODE ((CFE_Status_t)0xc8000004) + +/** + * @brief External failure + * + * This error indicates that the operation failed for + * some reason outside the scope of CFE. The real failure may + * have been in OSAL, PSP, or another dependent library. + * + * Details of the original failure should be written to syslog + * and/or a system event before returning this error. + */ +#define CFE_STATUS_EXTERNAL_RESOURCE_FAIL ((CFE_Status_t)0xc8000005) + +/** + * @brief Request already pending + * + * Commands or requests are already pending or the pending request + * limit has been reached. No more requests can be made until + * the current request(s) complete. + */ +#define CFE_STATUS_REQUEST_ALREADY_PENDING ((int32)0xc8000006) + +/** + * @brief Not Implemented + * + * Current version does not have the function or the feature + * of the function implemented. This could be due to either an early + * build for this platform or the platform does not support + * the specified feature. + * + */ +#define CFE_STATUS_NOT_IMPLEMENTED ((CFE_Status_t)0xc800ffff) + +/* +************* EVENTS SERVICES STATUS CODES ************* +*/ + +/** + * @brief Unknown Filter + * + * #CFE_EVS_Register FilterScheme parameter was illegal + * + */ +#define CFE_EVS_UNKNOWN_FILTER ((CFE_Status_t)0xc2000001) + +/** + * @brief Application Not Registered + * + * Calling application never previously called #CFE_EVS_Register + * + */ +#define CFE_EVS_APP_NOT_REGISTERED ((CFE_Status_t)0xc2000002) + +/** + * @brief Illegal Application ID + * + * Application ID returned by #CFE_ES_GetAppIDByName is greater + * than #CFE_PLATFORM_ES_MAX_APPLICATIONS + * + */ +#define CFE_EVS_APP_ILLEGAL_APP_ID ((CFE_Status_t)0xc2000003) + +/** + * @brief Application Filter Overload + * + * Number of Application event filters input upon + * registration is greater than #CFE_PLATFORM_EVS_MAX_EVENT_FILTERS + * + */ +#define CFE_EVS_APP_FILTER_OVERLOAD ((CFE_Status_t)0xc2000004) + +/** + * @brief Reset Area Pointer Failure + * + * Could not get pointer to the ES Reset area, so we could + * not get the pointer to the EVS Log. + * + */ +#define CFE_EVS_RESET_AREA_POINTER ((CFE_Status_t)0xc2000005) + +/** + * @brief Event Not Registered + * + * #CFE_EVS_ResetFilter EventID argument was not found in + * any event filter registered by the calling application. + * + */ +#define CFE_EVS_EVT_NOT_REGISTERED ((CFE_Status_t)0xc2000006) + +/** + * @brief File Write Error + * + * A file write error occurred while processing an EVS command + * + */ +#define CFE_EVS_FILE_WRITE_ERROR ((CFE_Status_t)0xc2000007) + +/** + * @brief Invalid Pointer + * + * Invalid parameter supplied to EVS command + * + */ +#define CFE_EVS_INVALID_PARAMETER ((CFE_Status_t)0xc2000008) + +/** + * @brief Not Implemented + * + * Current version of cFE does not have the function or the feature + * of the function implemented. This could be due to either an early + * build of the cFE for this platform or the platform does not support + * the specified feature. + * + */ +#define CFE_EVS_NOT_IMPLEMENTED ((CFE_Status_t)0xc200ffff) + +/* +************* EXECUTIVE SERVICES STATUS CODES ************* +*/ + +/** + * @brief Resource ID is not valid + * + * This error indicates that the passed in resource identifier + * (App ID, Lib ID, Counter ID, etc) did not validate. + * + */ +#define CFE_ES_ERR_RESOURCEID_NOT_VALID ((CFE_Status_t)0xc4000001) + +/** + * @brief Resource Name Error + * + * There is no match in the system for the given name. + * + */ +#define CFE_ES_ERR_NAME_NOT_FOUND ((CFE_Status_t)0xc4000002) + +/** + * @brief Application Create Error + * + * There was an error loading or creating the App. + * + */ +#define CFE_ES_ERR_APP_CREATE ((CFE_Status_t)0xc4000004) + +/** + * @brief Child Task Create Error + * + * There was an error creating a child task. + * + */ +#define CFE_ES_ERR_CHILD_TASK_CREATE ((CFE_Status_t)0xc4000005) + +/** + * @brief System Log Full + * + * The cFE system Log is full. + * This error means the message was not logged at all + * + */ +#define CFE_ES_ERR_SYS_LOG_FULL ((CFE_Status_t)0xc4000006) + +/** + * @brief Memory Block Size Error + * + * The block size requested is invalid. + * + */ +#define CFE_ES_ERR_MEM_BLOCK_SIZE ((CFE_Status_t)0xc4000008) + +/** + * @brief Load Library Error + * + * Could not load the shared library. + * + */ +#define CFE_ES_ERR_LOAD_LIB ((CFE_Status_t)0xc4000009) + +/** + * @brief Bad Argument + * + * Bad parameter passed into an ES API. + * + */ +#define CFE_ES_BAD_ARGUMENT ((CFE_Status_t)0xc400000a) + +/** + * @brief Child Task Register Error + * + * Errors occured when trying to register a child task. + * + */ +#define CFE_ES_ERR_CHILD_TASK_REGISTER ((CFE_Status_t)0xc400000b) + +/** + * @brief Shell Command Error + * + * Error occured ehen trying to pass a system call to the OS shell + * + */ +#define CFE_ES_ERR_SHELL_CMD ((CFE_Status_t)0xc400000c) + +/** + * @brief CDS Already Exists + * + * The Application is receiving the pointer to a CDS that was already present. + * + */ +#define CFE_ES_CDS_ALREADY_EXISTS ((CFE_Status_t)0x4400000d) + +/** + * @brief CDS Insufficient Memory + * + * The Application is requesting a CDS Block that is larger than the remaining + * CDS memory. + * + */ +#define CFE_ES_CDS_INSUFFICIENT_MEMORY ((CFE_Status_t)0xc400000e) + +/** + * @brief CDS Invalid Name + * + * The Application is requesting a CDS Block with an invalid ASCII string name. + * Either the name is too long (> #CFE_MISSION_ES_CDS_MAX_NAME_LENGTH) or was an empty string. + * + */ +#define CFE_ES_CDS_INVALID_NAME ((CFE_Status_t)0xc400000f) + +/** + * @brief CDS Invalid Size + * + * The Application is requesting a CDS Block or Pool with a size + * beyond the applicable limits, either too large or too small/zero. + * + */ +#define CFE_ES_CDS_INVALID_SIZE ((CFE_Status_t)0xc4000010) + +/** + * @brief CDS Invalid + * + * The CDS contents are invalid. + * + */ +#define CFE_ES_CDS_INVALID ((CFE_Status_t)0xc4000012) + +/** + * @brief CDS Access Error + * + * The CDS was inaccessible + * + */ +#define CFE_ES_CDS_ACCESS_ERROR ((CFE_Status_t)0xc4000013) + +/** + * @brief File IO Error + * + * Occurs when a file operation fails + * + */ +#define CFE_ES_FILE_IO_ERR ((CFE_Status_t)0xc4000014) + +/** + * @brief Reset Area Access Error + * + * Occurs when the BSP is not successful in returning the reset area address. + * + */ +#define CFE_ES_RST_ACCESS_ERR ((CFE_Status_t)0xc4000015) + +/** + * @brief Application Register Error + * + * Occurs when a task cannot be registered in ES global tables + * + */ +#define CFE_ES_ERR_APP_REGISTER ((CFE_Status_t)0xc4000017) + +/** + * @brief Child Task Delete Error + * + * There was an error deleting a child task. + * + */ +#define CFE_ES_ERR_CHILD_TASK_DELETE ((CFE_Status_t)0xc4000018) + +/** + * @brief Child Task Delete Passed Main Task + * + * There was an attempt to delete a cFE App Main Task with + * the #CFE_ES_DeleteChildTask API. + * + */ +#define CFE_ES_ERR_CHILD_TASK_DELETE_MAIN_TASK ((CFE_Status_t)0xc4000019) + +/** + * @brief CDS Block CRC Error + * + * Occurs when trying to read a CDS Data block and the CRC of the current + * data does not match the stored CRC for the data. Either the contents of + * the CDS Data Block are corrupted or the CDS Control Block is corrupted. + * + */ +#define CFE_ES_CDS_BLOCK_CRC_ERR ((CFE_Status_t)0xc400001A) + +/** + * @brief Mutex Semaphore Delete Error + * + * Occurs when trying to delete a Mutex that belongs to a task that ES + * is cleaning up. + * + */ +#define CFE_ES_MUT_SEM_DELETE_ERR ((CFE_Status_t)0xc400001B) + +/** + * @brief Binary Semaphore Delete Error + * + * Occurs when trying to delete a Binary Semaphore that belongs to a task that ES + * is cleaning up. + * + */ +#define CFE_ES_BIN_SEM_DELETE_ERR ((CFE_Status_t)0xc400001C) + +/** + * @brief Counte Semaphore Delete Error + * + * Occurs when trying to delete a Counting Semaphore that belongs to a task that ES + * is cleaning up. + * + */ +#define CFE_ES_COUNT_SEM_DELETE_ERR ((CFE_Status_t)0xc400001D) + +/** + * @brief Queue Delete Error + * + * Occurs when trying to delete a Queue that belongs to a task that ES + * is cleaning up. + * + */ +#define CFE_ES_QUEUE_DELETE_ERR ((CFE_Status_t)0xc400001E) + +/** + * @brief File Close Error + * + * Occurs when trying to close a file that belongs to a task that ES + * is cleaning up. + * + */ +#define CFE_ES_FILE_CLOSE_ERR ((CFE_Status_t)0xc400001F) + +/** + * @brief CDS Wrong Type Error + * + * Occurs when Table Services is trying to delete a Critical Data Store that + * is not a Critical Table Image or when Executive Services is trying to delete + * a Critical Table Image. + * + */ +#define CFE_ES_CDS_WRONG_TYPE_ERR ((CFE_Status_t)0xc4000020) + +/** + * @brief CDS Owner Active Error + * + * Occurs when an attempt was made to delete a CDS when an application + * with the same name associated with the CDS is still present. CDSs + * can ONLY be deleted when Applications that created them are not present + * in the system. + * + */ +#define CFE_ES_CDS_OWNER_ACTIVE_ERR ((CFE_Status_t)0xc4000022) + +/** + * @brief Application Cleanup Error + * + * Occurs when an attempt was made to Clean Up an application + * which involves calling Table, EVS, and SB cleanup functions, then + * deleting all ES resources, child tasks, and unloading the + * object module. The approach here is to keep going even though one + * of these steps had an error. There will be syslog messages detailing + * each problem. + * + */ +#define CFE_ES_APP_CLEANUP_ERR ((CFE_Status_t)0xc4000023) + +/** + * @brief Timer Delete Error + * + * Occurs when trying to delete a Timer that belongs to a task that ES + * is cleaning up. + * + */ +#define CFE_ES_TIMER_DELETE_ERR ((CFE_Status_t)0xc4000024) + +/** + * @brief Buffer Not In Pool + * + * The specified address is not in the memory pool. + * + */ +#define CFE_ES_BUFFER_NOT_IN_POOL ((CFE_Status_t)0xc4000025) + +/** + * @brief Task Delete Error + * + * Occurs when trying to delete a task that ES + * is cleaning up. + * + */ +#define CFE_ES_TASK_DELETE_ERR ((CFE_Status_t)0xc4000026) + +/** + * @brief Operation Timed Out + * + * Occurs if the timeout for a given operation was exceeded + * + */ +#define CFE_ES_OPERATION_TIMED_OUT ((CFE_Status_t)0xc4000027) + +/** + * @brief Library Already Loaded + * + * Occurs if CFE_ES_LoadLibrary detects that the requested + * library name is already loaded. + * + */ +#define CFE_ES_LIB_ALREADY_LOADED ((CFE_Status_t)0x44000028) + +/** + * @brief System Log Message Truncated + * + * This information code means the last syslog message was truncated + * due to insufficient space in the log buffer. + * + */ +#define CFE_ES_ERR_SYS_LOG_TRUNCATED ((CFE_Status_t)0x44000029) + +/** + * @brief Resource ID is not available + * + * This error indicates that the maximum resource identifiers + * (App ID, Lib ID, Counter ID, etc) has already been reached + * and a new ID cannot be allocated. + * + */ +#define CFE_ES_NO_RESOURCE_IDS_AVAILABLE ((CFE_Status_t)0xc400002B) + +/** + * @brief Invalid pool block + * + * Software attempted to "put" a block back into a pool which + * does not appear to belong to that pool. This may mean the + * pool has become unusable due to memory corruption. + * + */ +#define CFE_ES_POOL_BLOCK_INVALID ((CFE_Status_t)0xc400002C) + +/** + * @brief Invalid pool size or buffer address + * + * A specified pool address or size is outside the acceptable + * bounds for that pool configuration. + * + */ +#define CFE_ES_POOL_BOUNDS_ERROR ((CFE_Status_t)0xc400002D) + +/** + * @brief Duplicate Name Error + * + * Resource creation failed due to the name already existing in the system. + * + */ +#define CFE_ES_ERR_DUPLICATE_NAME ((CFE_Status_t)0xc400002E) + +/** + * @brief Not Implemented + * + * Current version of cFE does not have the function or the feature + * of the function implemented. This could be due to either an early + * build of the cFE for this platform or the platform does not support + * the specified feature. + * + */ +#define CFE_ES_NOT_IMPLEMENTED ((CFE_Status_t)0xc400ffff) + +/* +************* FILE SERVICES STATUS CODES ************* +*/ + +/** + * @brief Bad Argument + * + * A parameter given by a caller to a File Services API did not pass + * validation checks. + * + */ +#define CFE_FS_BAD_ARGUMENT ((CFE_Status_t)0xc6000001) + +/** + * @brief Invalid Path + * + * FS was unable to extract a filename from a path string + * + */ +#define CFE_FS_INVALID_PATH ((CFE_Status_t)0xc6000002) + +/** + * @brief Filename Too Long + * + * FS filename string is too long + * + */ +#define CFE_FS_FNAME_TOO_LONG ((CFE_Status_t)0xc6000003) + +/** + * @brief Not Implemented + * + * Current version of cFE does not have the function or the feature + * of the function implemented. This could be due to either an early + * build of the cFE for this platform or the platform does not support + * the specified feature. + * + */ +#define CFE_FS_NOT_IMPLEMENTED ((CFE_Status_t)0xc600ffff) + +/* +************* SOFTWARE BUS SERVICES STATUS CODES ************* +*/ + +/** + * @brief Time Out + * + * In #CFE_SB_ReceiveBuffer, this return value indicates that a packet has not + * been received in the time given in the "timeout" parameter. + * + */ +#define CFE_SB_TIME_OUT ((CFE_Status_t)0xca000001) + +/** + * @brief No Message + * + * When "Polling" a pipe for a message in #CFE_SB_ReceiveBuffer, this return + * value indicates that there was not a message on the pipe. + * + */ +#define CFE_SB_NO_MESSAGE ((CFE_Status_t)0xca000002) + +/** + * @brief Bad Argument + * + * A parameter given by a caller to a Software Bus API did not pass + * validation checks. + * + */ +#define CFE_SB_BAD_ARGUMENT ((CFE_Status_t)0xca000003) + +/** + * @brief Max Pipes Met + * + * This error code will be returned from #CFE_SB_CreatePipe when the + * SB cannot accomodate the request to create a pipe because the maximum + * number of pipes (#CFE_PLATFORM_SB_MAX_PIPES) are in use. This configuration + * parameter is defined in the cfe_platform_cfg.h file. + * + */ +#define CFE_SB_MAX_PIPES_MET ((CFE_Status_t)0xca000004) + +/** + * @brief Pipe Create Error + * + * The maximum number of queues(#OS_MAX_QUEUES) are in use. Or possibly a + * lower level problem with creating the underlying queue has occurred + * such as a lack of memory. If the latter is the problem, the status + * code displayed in the event must be tracked. + * + */ +#define CFE_SB_PIPE_CR_ERR ((CFE_Status_t)0xca000005) + +/** + * @brief Pipe Read Error + * + * This return value indicates an error at the Queue read level. This + * error typically cannot be corrected by the caller. Some possible + * causes are: queue was not properly initialized or created, the number + * of bytes read from the queue was not the number of bytes requested in + * the read. The queue id is invalid. Similar errors regarding the pipe + * will be caught by higher level code in the Software Bus. + * + */ +#define CFE_SB_PIPE_RD_ERR ((CFE_Status_t)0xca000006) + +/** + * @brief Message Too Big + * + * The size field in the message header indicates the message exceeds the + * max Software Bus message size. The max size is defined by + * configuration parameter #CFE_MISSION_SB_MAX_SB_MSG_SIZE in cfe_mission_cfg.h + * + */ +#define CFE_SB_MSG_TOO_BIG ((CFE_Status_t)0xca000007) + +/** + * @brief Buffer Allocation Error + * + * Returned when the memory in the SB message buffer pool has been depleted. + * The amount of memory in the pool is dictated by the configuration parameter + * #CFE_PLATFORM_SB_BUF_MEMORY_BYTES specified in the cfe_platform_cfg.h file. Also + * the memory statistics, including current utilization figures and high + * water marks for the SB Buffer memory pool can be monitored by sending + * a Software Bus command to send the SB statistics packet. + * + */ +#define CFE_SB_BUF_ALOC_ERR ((CFE_Status_t)0xca000008) + +/** + * @brief Max Messages Met + * + * Will be returned when calling one of the SB subscription API's if the + * SB routing table cannot accomodate another unique message ID because + * the platform configuration parameter #CFE_PLATFORM_SB_MAX_MSG_IDS has been met. + * + */ +#define CFE_SB_MAX_MSGS_MET ((CFE_Status_t)0xca000009) + +/** + * @brief Max Destinations Met + * + * Will be returned when calling one of the SB subscription API's if the + * SB routing table cannot accomodate another destination for a + * particular the given message ID. This occurs when the number of + * destinations in use meets the platform configuration parameter + * #CFE_PLATFORM_SB_MAX_DEST_PER_PKT. + * + */ +#define CFE_SB_MAX_DESTS_MET ((CFE_Status_t)0xca00000a) + +/** + * @brief No Subscribers + * + * This error code is returned by the #CFE_SB_Unsubscribe API if there has + * not been an entry in the routing tables for the MsgId/PipeId given as + * parameters. + */ +#define CFE_SB_NO_SUBSCRIBERS ((CFE_Status_t)0xca00000b) + +/** + * @brief Internal Error + * + * This error code will be returned by the #CFE_SB_Subscribe API if the + * code detects an internal index is out of range. The most likely + * cause would be a Single Event Upset. + * + */ +#define CFE_SB_INTERNAL_ERR ((CFE_Status_t)0xca00000c) + +/** + * @brief Wrong Message Type + * + * This error code will be returned when a request such as #CFE_MSG_SetMsgTime + * is made on a packet that does not include a field for msg time. + * + */ +#define CFE_SB_WRONG_MSG_TYPE ((CFE_Status_t)0xca00000d) + +/** + * @brief Buffer Invalid + * + * This error code will be returned when a request to release or send a + * zero copy buffer is invalid, such as if the handle or buffer is not + * correct or the buffer was previously released. + * + */ +#define CFE_SB_BUFFER_INVALID ((CFE_Status_t)0xca00000e) + +/** + * @brief No Message Recieved + * + * When trying to determine the last senders ID, this return + * value indicates that there was not a message recived on the pipe. + * + */ +#define CFE_SB_NO_MSG_RECV ((CFE_Status_t)0xca00000f) + +/** + * @brief Not Implemented + * + * Current version of cFE does not have the function or the feature + * of the function implemented. This could be due to either an early + * build of the cFE for this platform or the platform does not support + * the specified feature. + * + */ +#define CFE_SB_NOT_IMPLEMENTED ((CFE_Status_t)0xca00ffff) + +/* +************* TABLE SERVICES STATUS CODES ************* +*/ + +/** + * @brief Invalid Handle + * + * The calling Application attempted to pass a + * Table handle that represented too large an index or + * identified a Table Access Descriptor that was not used. + * + */ +#define CFE_TBL_ERR_INVALID_HANDLE ((CFE_Status_t)0xcc000001) + +/** + * @brief Invalid Name + * + * The calling Application attempted to register a table whose + * name length exceeded the platform configuration value of + * #CFE_MISSION_TBL_MAX_NAME_LENGTH or was zero characters long. + * + */ +#define CFE_TBL_ERR_INVALID_NAME ((CFE_Status_t)0xcc000002) + +/** + * @brief Invalid Size + * + * The calling Application attempted to register a table: + * a) that was a double buffered table with size greater than #CFE_PLATFORM_TBL_MAX_DBL_TABLE_SIZE + * b) that was a single buffered table with size greater than #CFE_PLATFORM_TBL_MAX_SNGL_TABLE_SIZE + * c) that had a size of zero + * + */ +#define CFE_TBL_ERR_INVALID_SIZE ((CFE_Status_t)0xcc000003) + +/** + * @brief Update Pending + * + * The calling Application has identified a table that has a load pending. + * + */ +#define CFE_TBL_INFO_UPDATE_PENDING ((CFE_Status_t)0x4c000004) + +/** + * @brief Never Loaded + * + * Table has not been loaded with data. + * + */ +#define CFE_TBL_ERR_NEVER_LOADED ((CFE_Status_t)0xcc000005) + +/** + * @brief Registry Full + * + * An application attempted to create a table and the Table + * registry already contained #CFE_PLATFORM_TBL_MAX_NUM_TABLES in it. + * + */ +#define CFE_TBL_ERR_REGISTRY_FULL ((CFE_Status_t)0xcc000006) + +/** + * @brief Duplicate Warning + * + * This is an error that the registration is trying to replace + * an existing table with the same name. The previous table + * stays in place and the new table is rejected. + * + */ +#define CFE_TBL_WARN_DUPLICATE ((CFE_Status_t)0x4c000007) + +/** + * @brief No Access + * + * The calling application either failed when calling #CFE_TBL_Register, + * failed when calling #CFE_TBL_Share or forgot to call either one. + * + */ +#define CFE_TBL_ERR_NO_ACCESS ((CFE_Status_t)0xcc000008) + +/** + * @brief Unregistered + * + * The calling application is trying to access a table that has + * been unregistered. + * + */ +#define CFE_TBL_ERR_UNREGISTERED ((CFE_Status_t)0xcc000009) + +/** + * @brief Bad Application ID + * + * The calling application does not have a legitimate Application ID. + */ +#define CFE_TBL_ERR_BAD_APP_ID ((CFE_Status_t)0xcc00000A) + +/** + * @brief Handles Full + * + * An application attempted to create a table and the Table + * Handle Array already used all CFE_PLATFORM_TBL_MAX_NUM_HANDLES in it. + * + */ +#define CFE_TBL_ERR_HANDLES_FULL ((CFE_Status_t)0xcc00000B) + +/** + * @brief Duplicate Table With Different Size + * + * An application attempted to register a table with the same name + * as a table that is already in the registry. The size of the new + * table is different from the size already in the registry. + * + */ +#define CFE_TBL_ERR_DUPLICATE_DIFF_SIZE ((CFE_Status_t)0xcc00000C) + +/** + * @brief Dupicate Table And Not Owned + * + * An application attempted to register a table with the same name + * as a table that is already in the registry. The previously registered + * table is owned by a different application. + * + */ +#define CFE_TBL_ERR_DUPLICATE_NOT_OWNED ((CFE_Status_t)0xcc00000D) + +/** + * @brief Updated + * + * The calling Application has identified a table that has been updated.
+ * \b NOTE: This is a nominal return code informing the calling application + * that the table identified in the call has had its contents updated since + * the last time the application obtained its address or status. + * + */ +#define CFE_TBL_INFO_UPDATED ((CFE_Status_t)0x4c00000E) + +/** + * @brief No Buffer Available + * + * The calling Application has tried to allocate a working buffer but + * none were available. + * + */ +#define CFE_TBL_ERR_NO_BUFFER_AVAIL ((CFE_Status_t)0xcc00000F) + +/** + * @brief Dump Only Error + * + * The calling Application has attempted to perform a load on a + * table that was created with "Dump Only" attributes. + * + */ +#define CFE_TBL_ERR_DUMP_ONLY ((CFE_Status_t)0xcc000010) + +/** + * @brief Illegal Source Type + * + * The calling Application called #CFE_TBL_Load with an illegal + * value for the second parameter. + * + */ +#define CFE_TBL_ERR_ILLEGAL_SRC_TYPE ((CFE_Status_t)0xcc000011) + +/** + * @brief Load In Progress + * + * The calling Application called #CFE_TBL_Load when another Application + * was trying to load the table. + * + */ +#define CFE_TBL_ERR_LOAD_IN_PROGRESS ((CFE_Status_t)0xcc000012) + +/** + * @brief File Not Found + * + * The calling Application called #CFE_TBL_Load with a bad filename. + * + */ +#define CFE_TBL_ERR_FILE_NOT_FOUND ((CFE_Status_t)0xcc000013) + +/** + * @brief File Too Large + * + * The calling Application called #CFE_TBL_Load with a filename that specified a file + * that contained more data than the size of the table OR which contained more data + * than specified in the table header. + * + */ +#define CFE_TBL_ERR_FILE_TOO_LARGE ((CFE_Status_t)0xcc000014) + +/** + * @brief Short File Warning + * + * The calling Application called #CFE_TBL_Load with a filename that specified a file + * that started with the first byte of the table but contained less data than the size of the table. + * It should be noted that #CFE_TBL_WARN_PARTIAL_LOAD also indicates a partial load (one that starts + * at a non-zero offset). + * + */ +#define CFE_TBL_WARN_SHORT_FILE ((CFE_Status_t)0x4c000015) + +/** + * @brief Bad Content ID + * + * The calling Application called #CFE_TBL_Load with a filename that specified a file + * whose content ID was not that of a table image. + * + */ +#define CFE_TBL_ERR_BAD_CONTENT_ID ((CFE_Status_t)0xcc000016) + +/** + * @brief No Update Pending + * + * The calling Application has attempted to update a table without a pending load. + * + */ +#define CFE_TBL_INFO_NO_UPDATE_PENDING ((CFE_Status_t)0x4c000017) + +/** + * @brief Table Locked + * + * The calling Application tried to update a table that is locked by another user. + * + */ +#define CFE_TBL_INFO_TABLE_LOCKED ((CFE_Status_t)0x4c000018) + +/** + * Validation Pending + * + * The calling Application should call #CFE_TBL_Validate for the specified table. + * + */ +#define CFE_TBL_INFO_VALIDATION_PENDING ((CFE_Status_t)0x4c000019) + +/** + * No Validation Pending + * + * The calling Application tried to validate a table that did not have a validation request pending. + * + */ +#define CFE_TBL_INFO_NO_VALIDATION_PENDING ((CFE_Status_t)0x4c00001A) + +/** + * @brief Bad Subtype ID + * + * The calling Application tried to access a table file whose Subtype identifier indicated it was not + * a table image file. + * + */ +#define CFE_TBL_ERR_BAD_SUBTYPE_ID ((CFE_Status_t)0xcc00001B) + +/** + * @brief File Size Inconsistent + * + * The calling Application tried to access a table file whose Subtype identifier indicated it was not + * a table image file. + * + */ +#define CFE_TBL_ERR_FILE_SIZE_INCONSISTENT ((CFE_Status_t)0xcc00001C) + +/** + * @brief No Standard Header + * + * The calling Application tried to access a table file whose standard cFE File Header was the wrong size, etc. + * + */ +#define CFE_TBL_ERR_NO_STD_HEADER ((CFE_Status_t)0xcc00001D) + +/** + * @brief No Table Header + * + * The calling Application tried to access a table file whose standard cFE + * Table File Header was the wrong size, etc. + * + */ +#define CFE_TBL_ERR_NO_TBL_HEADER ((CFE_Status_t)0xcc00001E) + +/** + * @brief Filename Too Long + * + * The calling Application tried to load a table using a filename + * that was too long. + * + */ +#define CFE_TBL_ERR_FILENAME_TOO_LONG ((CFE_Status_t)0xcc00001F) + +/** + * @brief File For Wrong Table + * + * The calling Application tried to load a table using a file whose + * header indicated that it was for a different table. + * + */ +#define CFE_TBL_ERR_FILE_FOR_WRONG_TABLE ((CFE_Status_t)0xcc000020) + +/** + * @brief Load Incomplete + * + * The calling Application tried to load a table file whose header + * claimed the load was larger than what was actually read from the file. + * + */ +#define CFE_TBL_ERR_LOAD_INCOMPLETE ((CFE_Status_t)0xcc000021) + +/** + * @brief Partial Load Warning + * + * The calling Application tried to load a table file whose header + * claimed the load did not start with the first byteIt should be noted + * that #CFE_TBL_WARN_SHORT_FILE also indicates a partial load. + * + */ +#define CFE_TBL_WARN_PARTIAL_LOAD ((CFE_Status_t)0x4c000022) + +/** + * @brief Partial Load Error + * + * The calling Application tried to load a table file whose header + * claimed the load did not start with the first byte and the table + * image had NEVER been loaded before. Partial loads are not allowed + * on uninitialized tables. It should be noted that + * #CFE_TBL_WARN_SHORT_FILE also indicates a partial load. + * + */ +#define CFE_TBL_ERR_PARTIAL_LOAD ((CFE_Status_t)0xcc000023) + +/** + * @brief Dump Pending + * + * The calling Application should call #CFE_TBL_Manage for the specified table. + * The ground has requested a dump of the Dump-Only table and needs to synchronize + * with the owning application. + * + */ +#define CFE_TBL_INFO_DUMP_PENDING ((CFE_Status_t)0x4c000024) + +/** + * @brief Invalid Options + * + * The calling Application has used an illegal combination of table options. + * A summary of the illegal combinations are as follows: + * \par #CFE_TBL_OPT_USR_DEF_ADDR cannot be combined with any of the following: + * -# #CFE_TBL_OPT_DBL_BUFFER + * -# #CFE_TBL_OPT_LOAD_DUMP + * -# #CFE_TBL_OPT_CRITICAL + * \par #CFE_TBL_OPT_DBL_BUFFER cannot be combined with the following: + * -# #CFE_TBL_OPT_USR_DEF_ADDR + * -# #CFE_TBL_OPT_DUMP_ONLY + * + */ +#define CFE_TBL_ERR_INVALID_OPTIONS ((CFE_Status_t)0xcc000025) + +/** + * @brief Not Critical Warning + * + * The calling Application attempted to register a table as "Critical". + * Table Services failed to create an appropriate Critical Data Store + * (See System Log for reason) to save the table contents. The table + * will be treated as a normal table from now on. + * + */ +#define CFE_TBL_WARN_NOT_CRITICAL ((CFE_Status_t)0x4c000026) + +/** + * @brief Recovered Table + * + * The calling Application registered a critical table whose previous + * contents were discovered in the Critical Data Store. The discovered + * contents were copied back into the newly registered table as the + * table's initial contents.
+ * \b NOTE: In this situation, the contents of the table are \b NOT + * validated using the table's validation function. + * + */ +#define CFE_TBL_INFO_RECOVERED_TBL ((CFE_Status_t)0x4c000027) + +/** + * @brief Bad Spacecraft ID + * + * The selected table file failed validation for Spacecraft ID. + * The platform configuration file has verification of table files + * enabled for Spacecraft ID and an attempt was made to load a table + * with an invalid Spacecraft ID in the table file header. + * + */ +#define CFE_TBL_ERR_BAD_SPACECRAFT_ID ((CFE_Status_t)0xcc000028) + +/** + * @brief Bad Processor ID + * + * The selected table file failed validation for Processor ID. + * The platform configuration file has verification of table files + * enabled for Processor ID and an attempt was made to load a table + * with an invalid Processor ID in the table file header. + * + */ +#define CFE_TBL_ERR_BAD_PROCESSOR_ID ((CFE_Status_t)0xcc000029) + +/** + * @brief Message Error + * + * Error code indicating that the TBL command was not processed + * successfully and that the error counter should be incremented. + */ +#define CFE_TBL_MESSAGE_ERROR ((CFE_Status_t)0xcc00002a) + +/** +** Error code indicating that the TBL file is shorter than +** indicated in the file header. +*/ +#define CFE_TBL_ERR_SHORT_FILE ((CFE_Status_t)0xcc00002b) + +/** +** Error code indicating that the TBL file could not be +** opened by the OS. +*/ +#define CFE_TBL_ERR_ACCESS ((CFE_Status_t)0xcc00002c) + +/** + * @brief Bad Argument + * + * A parameter given by a caller to a Table API did not pass + * validation checks. + * + */ +#define CFE_TBL_BAD_ARGUMENT ((CFE_Status_t)0xcc00002d) + +/** + * @brief Not Implemented + * + * Current version of cFE does not have the function or the feature + * of the function implemented. This could be due to either an early + * build of the cFE for this platform or the platform does not support + * the specified feature. + * + */ +#define CFE_TBL_NOT_IMPLEMENTED ((CFE_Status_t)0xcc00ffff) + +/* +************* TIME SERVICES STATUS CODES ************* +*/ + +/** + * @brief Not Implemented + * + * Current version of cFE does not have the function or the feature + * of the function implemented. This could be due to either an early + * build of the cFE for this platform or the platform does not support + * the specified feature. + * + */ +#define CFE_TIME_NOT_IMPLEMENTED ((CFE_Status_t)0xce00ffff) + +/** + * @brief Internal Only + * + * One of the TIME Services API functions to set the time with data + * from an external time source has been called, but TIME Services + * has been commanded to not accept external time data. However, + * the command is still a signal for the Time Server to generate + * a "time at the tone" command packet using internal data. + * + */ +#define CFE_TIME_INTERNAL_ONLY ((CFE_Status_t)0xce000001) + +/** + * @brief Out Of Range + * + * One of the TIME Services API functions to set the time with data + * from an external time source has been called, but TIME Services + * has determined that the new time data is invalid. However, + * the command is still a signal for the Time Server to generate + * a "time at the tone" command packet using internal data. + * + * Note that the test for invalid time update data only occurs if TIME + * Services has previously been commanded to set the clock state + * to "valid". + */ +#define CFE_TIME_OUT_OF_RANGE ((CFE_Status_t)0xce000002) + +/** + * @brief Too Many Sync Callbacks + * + * An attempt to register too many cFE Time Services Synchronization + * callbacks has been made. Only one callback function is allowed per + * application. It is expected that the application itself will + * distribute the single callback to child threads as needed. + * + */ +#define CFE_TIME_TOO_MANY_SYNCH_CALLBACKS ((CFE_Status_t)0xce000003) + +/** + * @brief Callback Not Registered + * + * An attempt to unregister a cFE Time Services Synchronization + * callback has failed because the specified callback function was not + * located in the Synchronization Callback Registry. + * + */ +#define CFE_TIME_CALLBACK_NOT_REGISTERED ((CFE_Status_t)0xce000004) + +/** + * @brief Bad Argument + * + * A parameter given by a caller to a TIME Services API did not pass + * validation checks. + * + */ +#define CFE_TIME_BAD_ARGUMENT ((CFE_Status_t)0xce000005) +/**@}*/ + +/* Compatibility for error names which have been updated */ +#ifndef CFE_OMIT_DEPRECATED_6_8 +#define CFE_ES_ERR_TASKID CFE_ES_ERR_RESOURCEID_NOT_VALID +#define CFE_ES_ERR_APPID CFE_ES_ERR_RESOURCEID_NOT_VALID +#define CFE_ES_ERR_MEM_HANDLE CFE_ES_ERR_RESOURCEID_NOT_VALID +#define CFE_ES_ERR_APPNAME CFE_ES_ERR_NAME_NOT_FOUND +#define CFE_ES_CDS_NOT_FOUND_ERR CFE_ES_ERR_NAME_NOT_FOUND +#define CFE_ES_CDS_REGISTRY_FULL CFE_ES_NO_RESOURCE_IDS_AVAILABLE +#endif /* CFE_OMIT_DEPRECATED_6_8 */ + +#endif /* CFE_ERROR_H */ diff --git a/modules/core_api/fsw/inc/cfe_version.h b/modules/core_api/fsw/inc/cfe_version.h new file mode 100644 index 000000000..39980ed99 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_version.h @@ -0,0 +1,61 @@ +/* +** 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 + * + * Provide version identifiers for the cFE core. + */ + +#ifndef CFE_VERSION_H +#define CFE_VERSION_H + +/* Development Build Macro Definitions */ +#define CFE_BUILD_NUMBER 490 /*!< Development Build: Number of commits since baseline */ +#define CFE_BUILD_BASELINE \ + "v6.8.0-rc1" /*!< Development Build: git tag that is the base for the current development \ + */ + +/* Version Macro Definitions */ +#define CFE_MAJOR_VERSION 6 /*!< @brief ONLY APPLY for OFFICIAL releases. Major version number. */ +#define CFE_MINOR_VERSION 7 /*!< @brief ONLY APPLY for OFFICIAL releases. Minor version number. */ +#define CFE_REVISION \ + 99 /*!< @brief ONLY APPLY for OFFICIAL releases. Revision version number. A value of "99" indicates a development \ + version. */ +#define CFE_MISSION_REV 0 /*!< @brief ONLY USED by MISSION Implementations. Mission revision */ + +#define CFE_STR_HELPER(x) #x /*!< @brief Helper function to concatenate strings from integer macros */ +#define CFE_STR(x) CFE_STR_HELPER(x) /*!< @brief Helper function to concatenate strings from integer macros */ + +/*! @brief Development Build Version Number. + * @details Baseline git tag + Number of commits since baseline. @n + * See @ref cfsversions for format differences between development and release versions. + */ +#define CFE_SRC_VERSION CFE_BUILD_BASELINE "+dev" CFE_STR(CFE_BUILD_NUMBER) + +/*! @brief Development Build Version String. + * @details Reports the current development build's baseline, number, and name. Also includes a note about the latest + * official version. @n See @ref cfsversions for format differences between development and release versions. + */ +#define CFE_VERSION_STRING \ + " cFE DEVELOPMENT BUILD " CFE_SRC_VERSION " (Codename: Bootes)" /* Codename for current development */ \ + ", Last Official Release: cfe v6.7.0" /* For full support please use this version */ + +#endif /* CFE_VERSION_H */ From 1892113d48d429fc8af96521408020a20297492e 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 3/5] CaelumReview-CFE40, cFE-ES --- .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 */ From c79d66969673a37900d468203b161785bd19874f Mon Sep 17 00:00:00 2001 From: "Gerardo E. Cruz-Ortiz" <59618057+astrogeco@users.noreply.github.com> Date: Wed, 7 Apr 2021 21:20:00 -0400 Subject: [PATCH 4/5] CaelumReview-CFE40, cFE-ResoruceID --- .gitignore | 12 + modules/core_api/fsw/inc/cfe_resourceid.h | 219 ++++++++++++++++++ .../fsw/inc/cfe_resourceid_api_typedefs.h | 80 +++++++ .../fsw/inc/cfe_core_resourceid_basevalues.h | 95 ++++++++ modules/resourceid/CMakeLists.txt | 20 ++ .../resourceid/fsw/src/cfe_resourceid_api.c | 133 +++++++++++ modules/resourceid/mission_build.cmake | 32 +++ .../cfe_resourceid_osal_compatible.h | 77 ++++++ .../option_inc/cfe_resourceid_simple.h | 67 ++++++ .../option_inc/cfe_resourceid_strict.h | 93 ++++++++ 10 files changed, 828 insertions(+) create mode 100644 modules/core_api/fsw/inc/cfe_resourceid.h create mode 100644 modules/core_api/fsw/inc/cfe_resourceid_api_typedefs.h create mode 100644 modules/core_private/fsw/inc/cfe_core_resourceid_basevalues.h create mode 100644 modules/resourceid/CMakeLists.txt create mode 100644 modules/resourceid/fsw/src/cfe_resourceid_api.c create mode 100644 modules/resourceid/mission_build.cmake create mode 100644 modules/resourceid/option_inc/cfe_resourceid_osal_compatible.h create mode 100644 modules/resourceid/option_inc/cfe_resourceid_simple.h create mode 100644 modules/resourceid/option_inc/cfe_resourceid_strict.h diff --git a/.gitignore b/.gitignore index 637b047dc..2e7fd18f3 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,15 @@ !modules/es/fsw/** !modules/es/CMakeLists.txt + + +# ResourceID + +!modules/core_api/fsw/inc/cfe_resourceid* + +!modules/core_private/fsw/inc/cfe_core_resourceid_basevalues.h + +!modules/resourceid/fsw/src/* +!modules/resourceid/option_inc/* +!modules/resourceid/CMakeLists.txt +!modules/resourceid/mission_build.cmake diff --git a/modules/core_api/fsw/inc/cfe_resourceid.h b/modules/core_api/fsw/inc/cfe_resourceid.h new file mode 100644 index 000000000..428db8b68 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_resourceid.h @@ -0,0 +1,219 @@ +/* +** 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 global prototypes and definitions related to resource + * management and related CFE 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. + * + * Simple operations are provided as inline functions, which + * should alleviate the need to do direct manipulation of resource IDs: + * + * - Check for undefined ID value + * - Check for equality of two ID values + * - Convert ID to simple integer (typically for printing/logging) + * - Convert simple integer to ID (inverse of above) + */ + +#ifndef CFE_RESOURCEID_H +#define CFE_RESOURCEID_H + +/* + * The basic resource ID API definitions + */ +#include "cfe_resourceid_api_typedefs.h" + +/** \name Resource ID test/conversion macros and inline functions */ +/** \{ */ + +/** + * \brief Convert a derived (app-specific) ID directly into an "unsigned long" + * + * This generic routine is implemented as a macro so it is agnostic to the actual argument type, + * and it will evaluate correctly so long as the argument type is based on the CFE_RESOURCEID_BASE_TYPE. + * + * There is no inverse of this macro, as it depends on the actual derived type desired. + * Applications needing to recreate an ID from an integer should use CFE_ResourceId_FromInteger() + * combined with a cast/conversion to the correct/intended derived type, as needed. + * + * \note This evaluates as an "unsigned long" such that it can be used in + * printf()-style functions with the "%lx" modifier without extra casting, + * as this is the most typical use-case for representing an ID as an integer. + */ +#define CFE_RESOURCEID_TO_ULONG(id) CFE_ResourceId_ToInteger(CFE_RESOURCEID_UNWRAP(id)) + +/** + * \brief Determine if a derived (app-specific) ID is defined or not + * + * This generic routine is implemented as a macro so it is agnostic to the actual argument type, + * and it will evaluate correctly so long as the argument type is based on the CFE_RESOURCEID_BASE_TYPE. + */ +#define CFE_RESOURCEID_TEST_DEFINED(id) CFE_ResourceId_IsDefined(CFE_RESOURCEID_UNWRAP(id)) + +/** + * \brief Determine if two derived (app-specific) IDs are equal + * + * This generic routine is implemented as a macro so it is agnostic to the actual argument type, + * and it will evaluate correctly so long as the argument type is based on the CFE_RESOURCEID_BASE_TYPE. + */ +#define CFE_RESOURCEID_TEST_EQUAL(id1, id2) CFE_ResourceId_Equal(CFE_RESOURCEID_UNWRAP(id1), CFE_RESOURCEID_UNWRAP(id2)) + +/** + * @brief Convert a resource ID to an integer. + * + * This is primarily intended for logging purposes, such was writing + * to debug console, event messages, or log files, using printf-like APIs. + * + * For compatibility with C library APIs, this returns an "unsigned long" + * type and should be used with the "%lx" format specifier in a printf + * format string. + * + * @note No assumptions should be made about the actual integer value, + * such as its base/range. It may be printed, but should not be modified + * or tested/compared using other arithmetic ops, and should never be used + * as the index to an array or table. See the related function + * CFE_ResourceId_ToIndex() for cases where a zero-based array/table index + * is needed. + * + * @sa CFE_ResourceId_FromInteger() + * + * @param[in] id Resource ID to convert + * @returns Integer value corresponding to ID + */ +static inline unsigned long CFE_ResourceId_ToInteger(CFE_ResourceId_t id) +{ + return ((unsigned long)CFE_RESOURCEID_UNWRAP(id)); +} + +/** + * @brief Convert an integer to a resource ID. + * + * This is the inverse of CFE_ResourceId_ToInteger(), and reconstitutes + * the original CFE_ResourceId_t value from the integer representation. + * + * This may be used, for instance, where an ID value is parsed from a text + * file or message using C library APIs such as scanf() or strtoul(). + * + * @sa CFE_ResourceId_ToInteger() + * + * @param[in] Value Integer value to convert + * @returns ID value corresponding to integer + */ +static inline CFE_ResourceId_t CFE_ResourceId_FromInteger(unsigned long Value) +{ + return ((CFE_ResourceId_t)CFE_RESOURCEID_WRAP(Value)); +} + +/** + * @brief Compare two Resource ID values for equality + * + * @param[in] id1 Resource ID to check + * @param[in] id2 Resource ID to check + * @returns true if id1 and id2 are equal, false otherwise. + */ +static inline bool CFE_ResourceId_Equal(CFE_ResourceId_t id1, CFE_ResourceId_t id2) +{ + return (CFE_RESOURCEID_UNWRAP(id1) == CFE_RESOURCEID_UNWRAP(id2)); +} + +/** + * @brief Check if a resource ID value is defined + * + * The constant #CFE_RESOURCEID_UNDEFINED represents an undefined ID value, + * such that the expression: + * + * CFE_ResourceId_IsDefined(CFE_RESOURCEID_UNDEFINED) + * + * Always returns false. + * + * @param[in] id Resource ID to check + * @returns True if the ID may refer to a defined entity, false if invalid/undefined. + */ +static inline bool CFE_ResourceId_IsDefined(CFE_ResourceId_t id) +{ + return (CFE_RESOURCEID_UNWRAP(id) != 0); +} + +/** \} */ + +/* + * Non-inline API functions provided by the Resource ID module + */ + +/** + * @brief Get the Base value (type/category) from a resource ID value + * + * This masks out the ID serial number to obtain the base value, which is different + * for each resource type. + * + * @note The value is NOT shifted or otherwise adjusted. + * + * @param[in] ResourceId the resource ID to decode + * @returns The base value associated with that ID + */ +extern uint32 CFE_ResourceId_GetBase(CFE_ResourceId_t ResourceId); + +/** + * @brief Get the Serial Number (sequential ID) from a resource ID value + * + * This masks out the ID base value to obtain the serial number, which is different + * for each entity created. + * + * @param[in] ResourceId the resource ID to decode + * @returns The serial number associated with that ID + */ +extern uint32 CFE_ResourceId_GetSerial(CFE_ResourceId_t ResourceId); + +/** + * @brief Locate the next resource ID which does not map to an in-use table entry + * + * This begins searching from StartId which should be the most recently issued ID + * for the resource category. This will then search for the next ID which does + * _not_ map to a table entry that is in use. That is, it does not alias any + * valid ID when converted to an array index. + * + * returns an undefined ID value if no open slots are available + * + * @param[in] StartId the last issued ID for the resource category (app, lib, etc). + * @param[in] TableSize the maximum size of the target table + * @param[in] CheckFunc a function to check if the given ID is available + * @returns Next ID value which does not map to a valid entry + * @retval #CFE_RESOURCEID_UNDEFINED if no open slots. + * + */ +extern CFE_ResourceId_t CFE_ResourceId_FindNext(CFE_ResourceId_t StartId, uint32 TableSize, + bool (*CheckFunc)(CFE_ResourceId_t)); + +/** + * @brief Internal routine to aid in converting an ES resource ID to an array index + + * @param[in] Id The resource ID + * @param[in] BaseValue The respective ID base value corresponding to the ID type + * @param[in] TableSize The actual size of the internal table (MAX index value + 1) + * @param[out] Idx The output index + * @returns Status code, CFE_SUCCESS if successful. + */ +extern int32 CFE_ResourceId_ToIndex(CFE_ResourceId_t Id, uint32 BaseValue, uint32 TableSize, uint32 *Idx); + +#endif /* CFE_RESOURCEID_H */ diff --git a/modules/core_api/fsw/inc/cfe_resourceid_api_typedefs.h b/modules/core_api/fsw/inc/cfe_resourceid_api_typedefs.h new file mode 100644 index 000000000..2afdf8dd2 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_resourceid_api_typedefs.h @@ -0,0 +1,80 @@ +/* +** 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 global prototypes and definitions related to resource + * management and related CFE 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. + * + * Simple operations are provided as inline functions, which + * should alleviate the need to do direct manipulation of resource IDs: + * + * - Check for undefined ID value + * - Check for equality of two ID values + * - Convert ID to simple integer (typically for printing/logging) + * - Convert simple integer to ID (inverse of above) + */ + +#ifndef CFE_RESOURCEID_API_TYPEDEFS_H +#define CFE_RESOURCEID_API_TYPEDEFS_H + +/* + * The basic resource ID typedef + * + * This is provided via the external resourceid library + * and may be customized by the user/mission preferences. + */ +#include "cfe_resourceid_typedef.h" + +/* +** Defines +*/ + +/** \name Resource ID predefined values */ +/** \{ */ + +/** + * @brief A resource ID value that represents an undefined/unused resource + * + * This constant may be used to initialize local variables of the + * CFE_ResourceId_t type to a safe value that will not alias a valid ID. + * + * By design, this value is also the result of zeroing a CFE_ResourceId_t + * type via standard functions like memset(), such that objects initialized + * using this method will also be set to safe values. + */ +#define CFE_RESOURCEID_UNDEFINED ((CFE_ResourceId_t)CFE_RESOURCEID_WRAP(0)) + +/** + * @brief A resource ID value that represents a reserved entry + * + * This is not a valid value for any resource type, but is used to mark + * table entries that are not available for use. For instance, this may + * be used while setting up an entry initially. + */ +#define CFE_RESOURCEID_RESERVED ((CFE_ResourceId_t)CFE_RESOURCEID_WRAP(0xFFFFFFFF)) + +/** \} */ + +#endif /* CFE_RESOURCEID_API_TYPEDEFS_H */ diff --git a/modules/core_private/fsw/inc/cfe_core_resourceid_basevalues.h b/modules/core_private/fsw/inc/cfe_core_resourceid_basevalues.h new file mode 100644 index 000000000..a1289b5e0 --- /dev/null +++ b/modules/core_private/fsw/inc/cfe_core_resourceid_basevalues.h @@ -0,0 +1,95 @@ +/* +** 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 CFE internal prototypes and definitions related to resource + * management and related CFE 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_CORE_RESOURCEID_BASEVALUES_H +#define CFE_CORE_RESOURCEID_BASEVALUES_H + +/* +** Include Files +*/ +#include "cfe_resourceid_basevalue.h" + +/** @defgroup CFEESResourceIDBase cFE Resource ID base values + * @{ + */ + +/* + * Assign unique offsets per resource types used in CFE core apps. + * + * Applications should not use these values directly, but rather + * in conjuction with the CFE_RESOURCEID_MAKE_BASE macro provided + * by the Resource ID module. (see below) + */ +enum +{ + /* + * Note for Task ID base value -- + * This currently shares the same offset as OSAL tasks, such that + * when "simple" (non-enforcing/backward-compatible) IDs are selected, + * the CFE task IDs and the OSAL task IDs end up as the same value. + * + * The "CFE_RESOURCEID_MARK" bit still differentiates the value when + * in strict mode, so there is no overlap in that case. + */ + CFE_RESOURCEID_ES_TASKID_BASE_OFFSET = OS_OBJECT_TYPE_OS_TASK, + + /* Other ES managed resources */ + CFE_RESOURCEID_ES_APPID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 1, + CFE_RESOURCEID_ES_LIBID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 2, + CFE_RESOURCEID_ES_COUNTID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 3, + CFE_RESOURCEID_ES_POOLID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 4, + CFE_RESOURCEID_ES_CDSBLOCKID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 5, + + /* SB managed resources */ + CFE_RESOURCEID_SB_PIPEID_RESOURCE_BASE_OFFSET = OS_OBJECT_TYPE_USER + 6 +}; + +/* + * Assign actual base values from the offsets above + * + * Using "enum" ensures these are resolved as integers now, as opposed at to the point of use like macros. + */ +enum +{ + /* ES managed resources */ + CFE_ES_TASKID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_ES_TASKID_BASE_OFFSET), + CFE_ES_APPID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_ES_APPID_BASE_OFFSET), + CFE_ES_LIBID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_ES_LIBID_BASE_OFFSET), + CFE_ES_COUNTID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_ES_COUNTID_BASE_OFFSET), + CFE_ES_POOLID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_ES_POOLID_BASE_OFFSET), + CFE_ES_CDSBLOCKID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_ES_CDSBLOCKID_BASE_OFFSET), + + /* SB managed resources */ + CFE_SB_PIPEID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_SB_PIPEID_RESOURCE_BASE_OFFSET) +}; + +/** @} */ + +#endif /* CFE_CORE_RESOURCEID_BASEVALUES_H */ diff --git a/modules/resourceid/CMakeLists.txt b/modules/resourceid/CMakeLists.txt new file mode 100644 index 000000000..34e568bb8 --- /dev/null +++ b/modules/resourceid/CMakeLists.txt @@ -0,0 +1,20 @@ +################################################################## +# +# cFE resource ID module CMake build recipe +# +################################################################## + +project(CFE_RESOURCEID C) + +# Module library +set(resourceid_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/cfe_resourceid_api.c +) +add_library(resourceid STATIC ${resourceid_SOURCES}) + +target_link_libraries(resourceid PRIVATE core_private) + +# Add unit test coverage subdirectory +if(ENABLE_UNIT_TESTS) + add_subdirectory(ut-coverage) +endif(ENABLE_UNIT_TESTS) diff --git a/modules/resourceid/fsw/src/cfe_resourceid_api.c b/modules/resourceid/fsw/src/cfe_resourceid_api.c new file mode 100644 index 000000000..b05e4ab70 --- /dev/null +++ b/modules/resourceid/fsw/src/cfe_resourceid_api.c @@ -0,0 +1,133 @@ +/* +** 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_resource_api.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 +#include +#include + +#include "cfe.h" +#include "cfe_resourceid.h" +#include "cfe_resourceid_basevalue.h" + +/*********************************************************************/ +/* + * CFE_ResourceId_GetBase + * + * For complete API information, see prototype in header + */ +uint32 CFE_ResourceId_GetBase(CFE_ResourceId_t ResourceId) +{ + return (CFE_ResourceId_ToInteger(ResourceId) & ~((uint32)CFE_RESOURCEID_MAX)); +} + +/*********************************************************************/ +/* + * CFE_ResourceId_GetSerial + * + * For complete API information, see prototype in header + */ +uint32 CFE_ResourceId_GetSerial(CFE_ResourceId_t ResourceId) +{ + return (CFE_ResourceId_ToInteger(ResourceId) & ((uint32)CFE_RESOURCEID_MAX)); +} + +/*********************************************************************/ +/* + * CFE_ResourceId_ToIndex + * + * For complete API information, see prototype in header + */ +int32 CFE_ResourceId_ToIndex(CFE_ResourceId_t Id, uint32 BaseValue, uint32 TableSize, uint32 *Idx) +{ + uint32 Serial; + + if (Idx == NULL) + { + return CFE_ES_BAD_ARGUMENT; + } + + Serial = CFE_ResourceId_ToInteger(Id) - BaseValue; + + if (Serial > CFE_RESOURCEID_MAX || TableSize == 0) + { + return CFE_ES_ERR_RESOURCEID_NOT_VALID; + } + + *Idx = Serial % TableSize; + return CFE_SUCCESS; +} + +/*********************************************************************/ +/* + * CFE_ResourceId_FindNext + * + * For complete API information, see prototype in header + */ +CFE_ResourceId_t CFE_ResourceId_FindNext(CFE_ResourceId_t StartId, uint32 TableSize, + bool (*CheckFunc)(CFE_ResourceId_t)) +{ + uint32 Serial; + uint32 Count; + uint32 ResourceType; + CFE_ResourceId_t CheckId; + bool IsTaken; + + ResourceType = CFE_ResourceId_GetBase(StartId); + Serial = CFE_ResourceId_GetSerial(StartId); + + Count = TableSize; + IsTaken = true; + + do + { + if (Count == 0) + { + CheckId = CFE_RESOURCEID_UNDEFINED; + break; + } + + --Count; + ++Serial; + if (Serial >= CFE_RESOURCEID_MAX) + { + Serial %= TableSize; + } + + CheckId = CFE_ResourceId_FromInteger(ResourceType + Serial); + IsTaken = CheckFunc(CheckId); + } while (IsTaken); + + return CheckId; +} diff --git a/modules/resourceid/mission_build.cmake b/modules/resourceid/mission_build.cmake new file mode 100644 index 000000000..9319c48d6 --- /dev/null +++ b/modules/resourceid/mission_build.cmake @@ -0,0 +1,32 @@ +########################################################### +# +# Resource ID mission build setup +# +# This file is evaluated as part of the "prepare" stage +# and can be used to set up prerequisites for the build, +# such as generating header files +# +########################################################### + +# Check if strict/enforcing typedef should be used +if (MISSION_RESOURCEID_MODE STREQUAL "STRICT") + set(RESOURCEID_HDR_FILE "cfe_resourceid_strict.h") +else () + set(RESOURCEID_HDR_FILE "cfe_resourceid_simple.h") +endif () + +# Generate the header definition files, use local default for this module) +generate_config_includefile( + FILE_NAME "cfe_resourceid_typedef.h" + FALLBACK_FILE "${CMAKE_CURRENT_LIST_DIR}/option_inc/${RESOURCEID_HDR_FILE}" +) + +# Resource ID base value header +# Currently the "osal compatible" version is the only provided implementation, +# but missions can provide their own if desired to override this. +generate_config_includefile( + FILE_NAME "cfe_resourceid_basevalue.h" + FALLBACK_FILE "${CMAKE_CURRENT_LIST_DIR}/option_inc/cfe_resourceid_osal_compatible.h" +) + +include_directories(${CMAKE_CURRENT_LIST_DIR}/inc) diff --git a/modules/resourceid/option_inc/cfe_resourceid_osal_compatible.h b/modules/resourceid/option_inc/cfe_resourceid_osal_compatible.h new file mode 100644 index 000000000..93bbaffa7 --- /dev/null +++ b/modules/resourceid/option_inc/cfe_resourceid_osal_compatible.h @@ -0,0 +1,77 @@ +/* +** 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 + * + * An implementation of CFE resource ID base values/limits that will be + * compatible with OSAL IDs. This is intended as a transitional tool to + * provide runtime value uniqueness, particularly when the "simple" (compatible) + * resource ID implementation is used. In this mode, compiler type checking + * is disabled, and so OSAL IDs can be silently interchanged with CFE IDs. + * + * However, by ensuring uniqueness in the runtime values, any ID handling + * errors may at least be detectable at runtime. + * + * This still works fine with the "strict" resource ID option, but is less + * important as the compiler type checking should prevent this type of error + * before the code even runs. + * + * The downside to this implementation is that it has a dependency on the + * OSAL ID structure. + */ + +#ifndef CFE_RESOURCEID_OSAL_COMPATIBLE_H +#define CFE_RESOURCEID_OSAL_COMPATIBLE_H + +/* +** Include Files +*/ +#include "cfe_resourceid_typedef.h" + +/* + * In this configuration, CFE resource IDs are tailored to not + * conflict/overlap with OSAL IDs, and are structured in a similar manner. + */ +#include "osapi-idmap.h" + +/* + * Limits/definitions related to CFE_ResourceId_t values. + * + * Defining based on OSAL ID values makes this object a superset of + * the OSAL ID type, such that OSAL IDs can be represented as resource IDs + * and not conflict with/alias each other. + * + * NOTE: This reflects a bit if "inside knowledge" about how OSAL IDs are + * constructed. The overlap between OSAL IDs and ES IDs may not always be + * consistent, and they can diverge in a future version. + */ +#define CFE_RESOURCEID_SHIFT OS_OBJECT_TYPE_SHIFT +#define CFE_RESOURCEID_MAX OS_OBJECT_INDEX_MASK + +/** + * @brief A macro to generate a CFE resource ID base value from an offset + * + * Each CFE ID range is effectively an extension of OSAL ID ranges by + * starting at OS_OBJECT_TYPE_USER. + */ +#define CFE_RESOURCEID_MAKE_BASE(offset) (CFE_RESOURCEID_MARK | ((offset) << CFE_RESOURCEID_SHIFT)) + +#endif /* CFE_RESOURCEID_OSAL_COMPATIBLE_H */ diff --git a/modules/resourceid/option_inc/cfe_resourceid_simple.h b/modules/resourceid/option_inc/cfe_resourceid_simple.h new file mode 100644 index 000000000..fe6348d3a --- /dev/null +++ b/modules/resourceid/option_inc/cfe_resourceid_simple.h @@ -0,0 +1,67 @@ +/* +** 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 simple (uint32 compatible) resource ID implementation + */ + +#ifndef CFE_RESOURCEID_SIMPLE_H +#define CFE_RESOURCEID_SIMPLE_H + +#include "common_types.h" + +/** + * @brief A type that provides a common, abstract identifier for + * all ES managed resources (e.g. apps, tasks, counters, etc). + * + * Fundamentally an unsigned integer but users should treat it as + * opaque, and only go through the ES API for introspection. + */ +typedef uint32 CFE_ResourceId_t; + +/** + * @brief A macro providing a type for app-specific IDs + * + * Local ID types are just direct typedefs to CFE_ResourceId_t in this mode, + * this means all ID values can be interchanged. + */ +#define CFE_RESOURCEID_BASE_TYPE CFE_ResourceId_t + +/** + * @brief A fixed bit that will be set in all CFE resource ID values + * + * In simple mode this is zero/disabled so that OSAL IDs and CFE IDs will + * have the same underlying values. This replicates historical behavior where + * CFE Task IDs and OSAL task IDs are same thing and are interchangable. + */ +#define CFE_RESOURCEID_MARK 0 + +/* + * Wrap/Unwrap macros. + * + * In simple mode theese are a pass through/no-op as values are not + * wrapped/protected. + */ +#define CFE_RESOURCEID_WRAP(x) x +#define CFE_RESOURCEID_UNWRAP(x) x + +#endif /* CFE_RESOURCEID_SIMPLE_H */ diff --git a/modules/resourceid/option_inc/cfe_resourceid_strict.h b/modules/resourceid/option_inc/cfe_resourceid_strict.h new file mode 100644 index 000000000..f71c30727 --- /dev/null +++ b/modules/resourceid/option_inc/cfe_resourceid_strict.h @@ -0,0 +1,93 @@ +/* +** 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 strict (type-safe) resource ID implementation + */ + +#ifndef CFE_RESOURCEID_STRICT_H +#define CFE_RESOURCEID_STRICT_H + +#include "common_types.h" + +/* + * Inform other code that the "strict mode" is enabled for resource IDs + * + * This in turn allows ES to adjust other macros/conversions as necessary + * to work with the strict type checking. + */ +#define CFE_RESOURCEID_STRICT_MODE + +/** + * @brief A type that provides a common, abstract identifier for + * all CFE managed resources (e.g. apps, tasks, counters, etc). + * + * Fundamentally an unsigned integer but users should treat it as + * opaque, and only go through the ES API for introspection. + * + */ +typedef struct +{ + uint32 id; +} CFE_ResourceId_t; + +/** + * @brief A macro to generate a basetype for app-specific IDs + * + * Resource IDs may be "wrapped" a second time to make a unique + * typedef for application-specific ID values. + * + * Defining this base type as a macro rather than a typedef is intentional + * such that every time this is used it makes an equivalent but different + * type. That is, it is a different type per the compiler type checking + * but has the same content/structure. + */ +#define CFE_RESOURCEID_BASE_TYPE \ + struct \ + { \ + CFE_ResourceId_t id; \ + } + +/** + * @brief A fixed bit that should be set in all CFE resource ID values + * + * In strict mode this is nonzero so that OSAL IDs and CFE IDs will have + * different values. This means that CFE Task IDs will not be interchangable + * with OSAL task IDs, either in value or type. + */ +#define CFE_RESOURCEID_MARK 0x02000000 + +/* + * Wrap/Unwrap macros. + * + * These are helpers for transparently accessing through wrapper types. + * + * These are not type-safe - Whenever possible applications should use + * the type-safe inline functions provided in cfe_resourceid.h instead. + */ +#define CFE_RESOURCEID_WRAP(x) \ + { \ + x \ + } +#define CFE_RESOURCEID_UNWRAP(x) (x).id + +#endif /* CFE_RESOURCEID_STRICT_H */ From 3f9fff4ac38dff7daa706de0f1850bc6e52cd832 Mon Sep 17 00:00:00 2001 From: "Gerardo E. Cruz-Ortiz" <59618057+astrogeco@users.noreply.github.com> Date: Wed, 7 Apr 2021 21:57:59 -0400 Subject: [PATCH 5/5] CaelumReview-CFS40, Add Review Instructions --- README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7be7449c5..f95bb3952 100644 --- a/README.md +++ b/README.md @@ -1 +1,23 @@ -# cFE \ No newline at end of file +## cFS-Caelum Review: CFS-40 + +This branch is meant for the cFS-Caelum code review of cFE-Core, Executive Services (ES), ResourceID, and the CMake Build files. The review designation is "CFS-40" + +The corresponding, fully working cFE instance matching the code in this branch can be found under the [cFE v7.0.0-rc1 tag](https://github.com/nasa/cFE/releases/tag/v7.0.0-rc1) + +### How to add your review comments + +Navigate to the ["files changed" tab](https://github.com/nasa/cFE/pull/1283/files) in the [nasa/cFE#1283](https://github.com/nasa/cFE/pull/1283) pull request. + + +github-review-instructions-1of2 + + +You can add comments on any line of code by hovering on the line number and clicking on the plus "+" sign. Once you're finished with the comment click on the green "Start Review" button. To add more comments, just click on the relevant line number in any file, type your comment, and click on "Add review comment". + + +github-review-instructions-2of2 + + If you need to take a break, or if you're done, click the green "Finish Review" button on the top right corner of the +page, add any overall or summarizing comments and click on "Submit Review". You can always return and add new comments using the same process. + +**Thank you!**