diff --git a/.gitignore b/.gitignore index 70428b516..f6f8a08e4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,5 @@ !modules/core_private/fsw/inc/cfe_evs_log_typedef.h # FS -# !cfe_fs* -# !modules/fs/fsw/* +!cfe_fs* +!modules/fs/fsw/* diff --git a/modules/core_api/eds/cfe_fs.xml b/modules/core_api/eds/cfe_fs.xml new file mode 100644 index 000000000..da85a5912 --- /dev/null +++ b/modules/core_api/eds/cfe_fs.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + Executive Services Exception/Reset Log File which is generated in response to a + \link #CFE_ES_WRITE_ERLOG_CC \ES_WRITEERLOG2FILE \endlink + command. + + + + + Executive Services System Log File which is generated in response to a + \link #CFE_ES_WRITE_SYSLOG_CC \ES_WRITESYSLOG2FILE \endlink + command. + + + + + Executive Services Information on All Applications File which is generated in response to a + \link #CFE_ES_QUERY_ALL_CC \ES_WRITEAPPINFO2FILE \endlink + command. + + + + + Executive Services Performance Analyzer Data File which is generated in response to a + \link #CFE_ES_PERF_STOPDATA_CC \ES_STOPLADATA \endlink + command. + + + + + Executive Services Shell Response Data File which is generated in response to a + \link #CFE_ES_SHELL_CMD_CC \ES_SHELL \endlink + command. + + + + + Executive Services Critical Data Store Registry Dump File which is generated in response to a + \link #CFE_ES_DUMP_CDS_REG_CC \ES_DUMPCDSREG \endlink + command. + + + + + Table Services Registry Dump File which is generated in response to a + \link #CFE_TBL_DUMP_REG_CC \TBL_WRITEREG2FILE \endlink + command. + + + + + Table Services Table Image File which is generated either on the ground or in response to a + \link #CFE_TBL_DUMP_CC \TBL_DUMP \endlink command. + + + + + Event Services Application Data Dump File which is generated in response to a + \link #CFE_EVS_FILE_WRITE_APP_DATA_CC \EVS_WRITEAPPDATA2FILE \endlink + command. + + + + + Event Services Local Event Log Dump File which is generated in response to a + \link #CFE_EVS_FILE_WRITE_LOG_DATA_CC \EVS_WRITELOG2FILE \endlink + command. + + + + + Software Bus Pipe Data Dump File which is generated in response to a + \link #CFE_SB_SEND_PIPE_INFO_CC \SB_WRITEPIPE2FILE \endlink + command. + + + + + Software Bus Message Routing Data Dump File which is generated in response to a + \link #CFE_SB_SEND_ROUTING_INFO_CC \SB_WRITEROUTING2FILE \endlink + command. + + + + + Software Bus Message Mapping Data Dump File which is generated in response to a + \link #CFE_SB_SEND_MAP_INFO_CC \SB_WRITEMAP2FILE \endlink + command. + + + + + Executive Services Query All Tasks Data File which is generated in response to a + \link #CFE_ES_QUERY_ALL_TASKS_CC \ES_WRITETASKINFO2FILE \endlink + command. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/core_api/fsw/inc/cfe_fs.h b/modules/core_api/fsw/inc/cfe_fs.h new file mode 100644 index 000000000..6bca3f5c4 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_fs.h @@ -0,0 +1,344 @@ +/* +** 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 File Services (FS) library API header file + * + * Author: S.Walling/Microtel + * + */ + +#ifndef CFE_FS_H +#define CFE_FS_H + +/* +** Required header files... +*/ +#include "common_types.h" +#include "osconfig.h" +#include "cfe_platform_cfg.h" +#include "cfe_error.h" +#include "cfe_fs_api_typedefs.h" +#include "cfe_fs_extern_typedefs.h" + +/** @defgroup CFEAPIFSHeader cFE File Header Management APIs + * @{ + */ + +/*****************************************************************************/ +/** +** \brief Read the contents of the Standard cFE File Header +** +** \par Description +** This API will fill the specified #CFE_FS_Header_t variable with the +** contents of the Standard cFE File Header of the file identified by +** the given File Descriptor. +** +** \par Assumptions, External Events, and Notes: +** -# The File has already been successfully opened using #OS_OpenCreate and +** the caller has a legitimate File Descriptor. +** +** \param[in] FileDes File Descriptor obtained from a previous call to #OS_OpenCreate +** that is associated with the file whose header is to be read. +** +** \param[in, out] Hdr Pointer to a variable of type #CFE_FS_Header_t that will be +** filled with the contents of the Standard cFE File Header. *Hdr is the contents of the +** Standard cFE File Header for the specified file. +** +** \return Execution status, see \ref CFEReturnCodes +** +** \sa #CFE_FS_WriteHeader +** +******************************************************************************/ +CFE_Status_t CFE_FS_ReadHeader(CFE_FS_Header_t *Hdr, osal_id_t FileDes); + +/*****************************************************************************/ +/** +** \brief Initializes the contents of the Standard cFE File Header +** +** \par Description +** This API will clear the specified #CFE_FS_Header_t variable and +** initialize the description field with the specified value +** +** \param[in] Hdr Pointer to a variable of type #CFE_FS_Header_t that will be +** cleared and initialized +** +** \param[in] *Description Initializes Header's Description +** +** \param[in] SubType Initializes Header's SubType +** +** \sa #CFE_FS_WriteHeader +** +******************************************************************************/ +void CFE_FS_InitHeader(CFE_FS_Header_t *Hdr, const char *Description, uint32 SubType); + +/*****************************************************************************/ +/** +** \brief Write the specified Standard cFE File Header to the specified file +** +** \par Description +** This API will output the specified #CFE_FS_Header_t variable, with some +** fields automatically updated, to the specified file as the Standard cFE +** File Header. This API will automatically populate the following fields +** in the specified #CFE_FS_Header_t: +** +** -# \link #CFE_FS_Header_t::ContentType \c ContentType \endlink - Filled with 0x63464531 ('cFE1') +** -# \link #CFE_FS_Header_t::Length \c Length \endlink - Filled with the sizeof(CFE_FS_Header_t) +** -# \link #CFE_FS_Header_t::SpacecraftID \c SpacecraftID \endlink - Filled with the Spacecraft ID +** -# \link #CFE_FS_Header_t::ProcessorID \c ProcessorID \endlink - Filled with the Processor ID +** -# \link #CFE_FS_Header_t::ApplicationID \c ApplicationID \endlink - Filled with the Application ID +** -# \link #CFE_FS_Header_t::TimeSeconds \c TimeSeconds \endlink - Filled with the Time, in seconds, as obtained +** by #CFE_TIME_GetTime +** -# \link #CFE_FS_Header_t::TimeSubSeconds \c TimeSubSeconds \endlink - Filled with the Time, subseconds, as +** obtained by #CFE_TIME_GetTime +** +** \par Assumptions, External Events, and Notes: +** -# The File has already been successfully opened using #OS_OpenCreate and +** the caller has a legitimate File Descriptor. +** -# The \c SubType field has been filled appropriately by the Application. +** -# The \c Description field has been filled appropriately by the Application. +** +** \param[in] FileDes File Descriptor obtained from a previous call to #OS_OpenCreate +** that is associated with the file whose header is to be read. +** +** \param[in, out] Hdr Pointer to a variable of type #CFE_FS_Header_t that will be +** filled with the contents of the Standard cFE File Header. *Hdr is the contents of the +** Standard cFE File Header for the specified file. +** +** \return Execution status, see \ref CFEReturnCodes +** +** \sa #CFE_FS_ReadHeader +** +******************************************************************************/ +CFE_Status_t CFE_FS_WriteHeader(osal_id_t FileDes, CFE_FS_Header_t *Hdr); + +/*****************************************************************************/ +/** +** \brief Modifies the Time Stamp field in the Standard cFE File Header for the specified file +** +** \par Description +** This API will modify the \link #CFE_FS_Header_t::TimeSeconds timestamp \endlink found +** in the Standard cFE File Header of the specified file. The timestamp will be replaced +** with the time specified by the caller. +** +** \par Assumptions, External Events, and Notes: +** -# The File has already been successfully opened using #OS_OpenCreate and +** the caller has a legitimate File Descriptor. +** -# The \c NewTimestamp field has been filled appropriately by the Application. +** +** \param[in] FileDes File Descriptor obtained from a previous call to #OS_OpenCreate +** that is associated with the file whose header is to be read. +** +** \param[in] NewTimestamp A #CFE_TIME_SysTime_t data structure containing the desired time +** to be put into the file's Standard cFE File Header. +** +** \return Execution status, see \ref CFEReturnCodes +** +******************************************************************************/ +CFE_Status_t CFE_FS_SetTimestamp(osal_id_t FileDes, CFE_TIME_SysTime_t NewTimestamp); +/**@}*/ + +/** @defgroup CFEAPIFSUtil cFE File Utility APIs + * @{ + */ + +/*****************************************************************************/ +/** +** \brief Get the default virtual mount point for a file category +** +** Certain classes of files generally reside in a common directory, mainly +** either the persistent storage (/cf typically) or ram disk (/ram typically). +** +** Ephemeral status files are generally in the ram disk while application +** modules and scripts are generally in the persistent storage. +** +** This returns the expected directory for a given class of files in the form +** of a virtual OSAL mount point string. +** +** \returns String containing the mount point, or NULL if unkown/invalid +*/ +const char *CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_t FileCategory); + +/*****************************************************************************/ +/** +** \brief Get the default filename extension for a file category +** +** Certain file types may have an extension that varies from system to system. +** This is primarily an issue for application modules which are ".so" on +** Linux systems, ".dll" on Windows, ".o" on VxWorks, ".obj" on RTEMS, and so on. +** +** This uses a combination of compile-time configuration and hints from the +** build environment to get the default/expected extension for a given file +** category. +** +** \returns String containing the extension, or NULL if unkown/invalid +*/ +const char *CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_t FileCategory); + +/*****************************************************************************/ +/** +** \brief Parse a filename input from an input buffer into a local buffer +** +** \par Description +** This provides a more user friendly way to specify file names, +** using default values for the path and extension, which can +** vary from system to system. +** +** If InputBuffer is null or its length is zero, then DefaultInput +** is used as if it was the content of the input buffer. +** +** If either the pathname or extension is missing from the input, +** it will be added from defaults, with the complete fully-qualified +** filename stored in the output buffer. +** +** \par Assumptions, External Events, and Notes: +** -# The paths and filenames used here are the standard unix style +** filenames separated by "/" (path) and "." (extension) characters. +** -# Input Buffer has a fixed max length. Parsing will not exceed InputBufSize, +** and does not need to be null terminated. However parsing will stop +** at the first null char, when the input is shorter than the maximum. +** +** \param[out] OutputBuffer Buffer to store result. +** \param[in] InputBuffer A input buffer that may contain a file name (e.g. from command). +** \param[in] OutputBufSize Maximum Size of output buffer. +** \param[in] InputBufSize Maximum Size of input buffer. +** \param[in] DefaultInput Default value to use for input if InputBffer is empty +** \param[in] DefaultPath Default value to use for pathname if omitted from input +** \param[in] DefaultExtension Default value to use for extension if omitted from input +** +** \return Execution status, see \ref CFEReturnCodes +** +******************************************************************************/ +int32 CFE_FS_ParseInputFileNameEx(char *OutputBuffer, const char *InputBuffer, size_t OutputBufSize, + size_t InputBufSize, const char *DefaultInput, const char *DefaultPath, + const char *DefaultExtension); + +/*****************************************************************************/ +/** +** \brief Parse a filename string from the user into a local buffer +** +** \par Description +** Simplified API for CFE_FS_ParseInputFileNameEx() where input is +** always known to be a non-empty, null terminated string and the fixed-length +** input buffer not needed. For instance this may be used where +** the input is a fixed string from cfe_platform_cfg.h or similar. +** +** \par Assumptions, External Events, and Notes: +** The parameters are organized such that this is basically like strncpy() with an +** extra argument, and existing file name accesses which use a direct copy can +** easily change to use this instead. +** +** \sa CFE_FS_ParseInputFileNameEx() +** +** \param[out] OutputBuffer Buffer to store result. +** \param[in] InputName A null terminated input string +** \param[in] OutputBufSize Maximum Size of output buffer. +** \param[in] FileCategory The generalized category of file (implies default path/extension) +** +** \return Execution status, see \ref CFEReturnCodes +** +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_FS_ParseInputFileName(char *OutputBuffer, const char *InputName, size_t OutputBufSize, + CFE_FS_FileCategory_t FileCategory); + +/*****************************************************************************/ +/** +** \brief Extracts the filename from a unix style path and filename string. +** +** \par Description +** This API will take the original unix path/filename combination and +** extract the base filename. Example: Given the path/filename : "/cf/apps/myapp.o.gz" +** this function will return the filename: "myapp.o.gz". +** +** \par Assumptions, External Events, and Notes: +** -# The paths and filenames used here are the standard unix style +** filenames separated by "/" characters. +** -# The extracted filename (including terminator) is no longer than #OS_MAX_PATH_LEN +** +** \param[in] OriginalPath The original path. +** \param[out] FileNameOnly The filename that is extracted from the path. +** +** \return Execution status, see \ref CFEReturnCodes +** +******************************************************************************/ +CFE_Status_t CFE_FS_ExtractFilenameFromPath(const char *OriginalPath, char *FileNameOnly); + +/*****************************************************************************/ +/** +** \brief Register a background file dump request +** +** \par Description +** Puts the previously-initialized metadata into the pending request queue +** +** \par Assumptions, External Events, and Notes: +** Metadata structure should be stored in a static memory area (not on heap) as it +** must persist and be accessible by the file writer task throughout the asynchronous +** job operation. +** +** \param[inout] Meta The background file write persistent state object +** +** \return Execution status, see \ref CFEReturnCodes +** +******************************************************************************/ +int32 CFE_FS_BackgroundFileDumpRequest(CFE_FS_FileWriteMetaData_t *Meta); + +/*****************************************************************************/ +/** +** \brief Query if a background file write request is currently pending +** +** \par Description +** This returns "true" while the request is on the background work queue +** This returns "false" once the request is complete and removed from the queue. +** +** \par Assumptions, External Events, and Notes: +** None +** +** \param[inout] Meta The background file write persistent state object +** +** \return true if request is already pending, false if not +** +******************************************************************************/ +bool CFE_FS_BackgroundFileDumpIsPending(const CFE_FS_FileWriteMetaData_t *Meta); + +/*****************************************************************************/ +/** +** \brief Execute the background file write job(s) +** +** \par Description +** Runs the state machine associated with background file write requests +** +** \par Assumptions, External Events, and Notes: +** This should only be invoked as a background job from the ES background task, +** it should not be invoked directly. +** +** \param[in] ElapsedTime The amount of time passed since last invocation (ms) +** \param[in] Arg Not used/ignored +** +** \return true if jobs are pending, false if idle +** +******************************************************************************/ +bool CFE_FS_RunBackgroundFileDump(uint32 ElapsedTime, void *Arg); + +/**@}*/ + +#endif /* CFE_FS_H */ diff --git a/modules/core_api/fsw/inc/cfe_fs_api_typedefs.h b/modules/core_api/fsw/inc/cfe_fs_api_typedefs.h new file mode 100644 index 000000000..0e7a80594 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_fs_api_typedefs.h @@ -0,0 +1,121 @@ +/* +** 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 File Services (FS) library API header file + * + * Author: S.Walling/Microtel + * + */ + +#ifndef CFE_FS_API_TYPEDEFS_H +#define CFE_FS_API_TYPEDEFS_H + +/* +** Required header files... +*/ +#include "common_types.h" +#include "osconfig.h" +#include "cfe_fs_extern_typedefs.h" + +/** + * \brief Generalized file types/categories known to FS + * + * This defines different categories of files, where they + * may reside in different default locations of the virtualized file system. + * + * This is different from, and should not be confused with, the "SubType" + * field in the FS header. This value is only used at runtime for FS APIs + * and should not actually appear in any output file or message. + */ +typedef enum +{ + CFE_FS_FileCategory_UNKNOWN, /**< Placeholder, unknown file category */ + CFE_FS_FileCategory_DYNAMIC_MODULE, /**< Dynamically loadable apps/libraries (e.g. .so, .o, .dll, etc) */ + CFE_FS_FileCategory_BINARY_DATA_DUMP, /**< Binary log file generated by various data dump commands */ + CFE_FS_FileCategory_TEXT_LOG, /**< Text-based log file generated by various commands */ + CFE_FS_FileCategory_SCRIPT, /**< Text-based Script files (e.g. ES startup script) */ + CFE_FS_FileCategory_TEMP, /**< Temporary/Ephemeral files */ + CFE_FS_FileCategory_MAX /**< Placeholder, keep last */ +} CFE_FS_FileCategory_t; + +/* + * Because FS is a library not an app, it does not have its own context or + * event IDs. The file writer runs in the context of the ES background task + * on behalf of whatever App requested the file write. + * + * This is a list of abstract events associated with background file write jobs. + * An app requesting the file write must supply a callback function to translate + * these into its own event IDs for feedback (i.e. file complete, error conditions, etc). + */ +typedef enum +{ + CFE_FS_FileWriteEvent_UNDEFINED, /* placeholder, no-op, keep as 0 */ + + CFE_FS_FileWriteEvent_COMPLETE, /**< File is completed successfully */ + CFE_FS_FileWriteEvent_CREATE_ERROR, /**< Unable to create/open file */ + CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR, /**< Unable to write FS header */ + CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR, /**< Unable to write data record */ + + CFE_FS_FileWriteEvent_MAX /* placeholder, no-op, keep last */ + +} CFE_FS_FileWriteEvent_t; + +/** + * Data Getter routine provided by requester + * + * Outputs a data block. Should return true if the file is complete (last record/EOF), otherwise return false. + */ +typedef bool (*CFE_FS_FileWriteGetData_t)(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize); + +/** + * Event generator routine provided by requester + * + * Invoked from certain points in the file write process. Implementation may invoke CFE_EVS_SendEvent() appropriately + * to inform of progress. + */ +typedef void (*CFE_FS_FileWriteOnEvent_t)(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, + size_t BlockSize, size_t Position); + +/** + * \brief External Metadata/State object associated with background file writes + * + * Applications intending to schedule background file write jobs should instantiate + * this object in static/global data memory. This keeps track of the state of the + * file write request(s). + */ +typedef struct CFE_FS_FileWriteMetaData +{ + volatile bool IsPending; /**< Whether request is pending (volatile as it may be checked outside lock) */ + + char FileName[OS_MAX_PATH_LEN]; /**< Name of file to write */ + + /* Data for FS header */ + uint32 FileSubType; /**< Type of file to write (for FS header) */ + char Description[CFE_FS_HDR_DESC_MAX_LEN]; /**< Description of file (for FS header) */ + + CFE_FS_FileWriteGetData_t GetData; /**< Application callback to get a data record */ + CFE_FS_FileWriteOnEvent_t OnEvent; /**< Application callback for abstract event processing */ + +} CFE_FS_FileWriteMetaData_t; + +#endif /* CFE_FS_API_TYPEDEFS_H */ diff --git a/modules/core_api/fsw/inc/cfe_fs_core_internal.h b/modules/core_api/fsw/inc/cfe_fs_core_internal.h new file mode 100644 index 000000000..ee1f8768d --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_fs_core_internal.h @@ -0,0 +1,60 @@ +/* +** 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 File Services (FS) library API header file + * + * Author: S.Walling/Microtel + * + */ + +#ifndef CFE_FS_CORE_INTERNAL_H +#define CFE_FS_CORE_INTERNAL_H + +#include "common_types.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 CFEAPIFSCoreInternal cFE Internal File Service APIs, internal to CFE core + * @{ + */ + +/*****************************************************************************/ +/** +** \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_FS_EarlyInit(void); + +/**@}*/ + +#endif /* CFE_FS_CORE_INTERNAL_H */ diff --git a/modules/core_api/fsw/inc/cfe_fs_extern_typedefs.h b/modules/core_api/fsw/inc/cfe_fs_extern_typedefs.h new file mode 100644 index 000000000..d1780b544 --- /dev/null +++ b/modules/core_api/fsw/inc/cfe_fs_extern_typedefs.h @@ -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 + * + * Declarations and prototypes for cfe_fs_extern_typedefs module + */ + +#ifndef CFE_FS_EXTERN_TYPEDEFS_H +#define CFE_FS_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_fs_eds_typedefs.h" + +#else +/* Use the local definitions of these types */ + +#include "common_types.h" + +/******************* Macro Definitions ***********************/ + +/* + * NOTE: the value of CFE_FS_HDR_DESC_MAX_LEN, if modified, should + * be constrained to multiples of 4, as it is used within a structure that + * also contains uint32 types. This ensures that the entire structure + * remains 32-bit aligned without the need for implicit padding bytes. + */ + +#define CFE_FS_HDR_DESC_MAX_LEN 32 /**< \brief Max length of description field in a standard cFE File Header */ + +#define CFE_FS_FILE_CONTENT_ID 0x63464531 /**< \brief Magic Number for cFE compliant files (= 'cFE1') */ + +/** + * @brief Label definitions associated with CFE_FS_SubType_Enum_t + */ +enum CFE_FS_SubType +{ + + /** + * @brief Executive Services Exception/Reset Log Type + * + * Executive Services Exception/Reset Log File which is generated in response to a + * \link #CFE_ES_WRITE_ER_LOG_CC \ES_WRITEERLOG2FILE \endlink + * command. + * + */ + CFE_FS_SubType_ES_ERLOG = 1, + + /** + * @brief Executive Services System Log Type + * + * Executive Services System Log File which is generated in response to a + * \link #CFE_ES_WRITE_SYSLOG_CC \ES_WRITESYSLOG2FILE \endlink + * command. + * + */ + CFE_FS_SubType_ES_SYSLOG = 2, + + /** + * @brief Executive Services Information on All Applications File + * + * Executive Services Information on All Applications File which is generated in response to a + * \link #CFE_ES_QUERY_ALL_CC \ES_WRITEAPPINFO2FILE \endlink + * command. + * + */ + CFE_FS_SubType_ES_QUERYALL = 3, + + /** + * @brief Executive Services Performance Data File + * + * Executive Services Performance Analyzer Data File which is generated in response to a + * \link #CFE_ES_STOP_PERF_DATA_CC \ES_STOPLADATA \endlink + * command. + * + */ + CFE_FS_SubType_ES_PERFDATA = 4, + + /** + * @brief Executive Services Shell Response File + * + * Executive Services Shell Response Data File which is generated in response to a + * shell command. + * + */ + CFE_FS_SubType_ES_SHELL = 5, + + /** + * @brief Executive Services Critical Data Store Registry Dump File + * + * Executive Services Critical Data Store Registry Dump File which is generated in response to a + * \link #CFE_ES_DUMP_CDS_REGISTRY_CC \ES_DUMPCDSREG \endlink + * command. + * + */ + CFE_FS_SubType_ES_CDS_REG = 6, + + /** + * @brief Table Services Registry Dump File + * + * Table Services Registry Dump File which is generated in response to a + * \link #CFE_TBL_DUMP_REGISTRY_CC \TBL_WRITEREG2FILE \endlink + * command. + * + */ + CFE_FS_SubType_TBL_REG = 9, + + /** + * @brief Table Services Table Image File + * + * Table Services Table Image File which is generated either on the ground or in response to a + * \link #CFE_TBL_DUMP_CC \TBL_DUMP \endlink command. + * + */ + CFE_FS_SubType_TBL_IMG = 8, + + /** + * @brief Event Services Application Data Dump File + * + * Event Services Application Data Dump File which is generated in response to a + * \link #CFE_EVS_WRITE_APP_DATA_FILE_CC \EVS_WRITEAPPDATA2FILE \endlink + * command. + * + */ + CFE_FS_SubType_EVS_APPDATA = 15, + + /** + * @brief Event Services Local Event Log Dump File + * + * Event Services Local Event Log Dump File which is generated in response to a + * \link #CFE_EVS_WRITE_LOG_DATA_FILE_CC \EVS_WRITELOG2FILE \endlink + * command. + * + */ + CFE_FS_SubType_EVS_EVENTLOG = 16, + + /** + * @brief Software Bus Pipe Data Dump File + * + * Software Bus Pipe Data Dump File which is generated in response to a + * \link #CFE_SB_WRITE_PIPE_INFO_CC \SB_WRITEPIPE2FILE \endlink + * command. + * + */ + CFE_FS_SubType_SB_PIPEDATA = 20, + + /** + * @brief Software Bus Message Routing Data Dump File + * + * Software Bus Message Routing Data Dump File which is generated in response to a + * \link #CFE_SB_WRITE_ROUTING_INFO_CC \SB_WRITEROUTING2FILE \endlink + * command. + * + */ + CFE_FS_SubType_SB_ROUTEDATA = 21, + + /** + * @brief Software Bus Message Mapping Data Dump File + * + * Software Bus Message Mapping Data Dump File which is generated in response to a + * \link #CFE_SB_WRITE_MAP_INFO_CC \SB_WRITEMAP2FILE \endlink + * command. + * + */ + CFE_FS_SubType_SB_MAPDATA = 22, + + /** + * @brief Executive Services Query All Tasks Data File + * + * Executive Services Query All Tasks Data File which is generated in response to a + * \link #CFE_ES_QUERY_ALL_TASKS_CC \ES_WRITETASKINFO2FILE \endlink + * command. + * + */ + CFE_FS_SubType_ES_QUERYALLTASKS = 23 +}; + +/** + * @brief Content descriptor for File Headers + * + * @sa enum CFE_FS_SubType + */ +typedef uint32 CFE_FS_SubType_Enum_t; + +/** +** \brief Standard cFE File header structure definition +*/ +typedef struct CFE_FS_Header +{ + uint32 ContentType; /**< \brief Identifies the content type (='cFE1'=0x63464531)*/ + uint32 SubType; /**< \brief Type of \c ContentType, if necessary */ + /**< Standard SubType definitions can be found + \link #CFE_FS_SubType_ES_ERLOG here \endlink */ + uint32 Length; /**< \brief Length of primary header */ + uint32 SpacecraftID; /**< \brief Spacecraft that generated the file */ + uint32 ProcessorID; /**< \brief Processor that generated the file */ + uint32 ApplicationID; /**< \brief Application that generated the file */ + + uint32 TimeSeconds; /**< \brief File creation timestamp (seconds) */ + uint32 TimeSubSeconds; /**< \brief File creation timestamp (sub-seconds) */ + + char Description[CFE_FS_HDR_DESC_MAX_LEN]; /**< \brief File description */ + +} CFE_FS_Header_t; + +#endif /* CFE_EDS_ENABLED_BUILD */ + +#endif /* CFE_FS_EXTERN_TYPEDEFS_H */ diff --git a/modules/fs/fsw/src/cfe_fs_api.c b/modules/fs/fsw/src/cfe_fs_api.c new file mode 100644 index 000000000..b3703eedf --- /dev/null +++ b/modules/fs/fsw/src/cfe_fs_api.c @@ -0,0 +1,886 @@ +/* +** 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_fs_api.c +** +** Purpose: cFE File Services (FS) library API source file +** +** Author: S.Walling/Microtel +** +** Notes: +** +*/ + +/* +** Required header files... +*/ +#include "cfe_fs_module_all.h" + +#include + +/* The target config allows refs into global CONFIGDATA object(s) */ +#include "target_config.h" + +/* + * Fixed default file system extensions (not platform dependent) + */ +const char CFE_FS_DEFAULT_SCRIPT_EXTENSION[] = ".scr"; +const char CFE_FS_DEFAULT_DUMP_FILE_EXTENSION[] = ".dat"; +const char CFE_FS_DEFAULT_TEMP_FILE_EXTENSION[] = ".tmp"; +const char CFE_FS_DEFAULT_LOG_FILE_EXTENSION[] = ".log"; + +const char *CFE_FS_GetDefaultMountPoint(CFE_FS_FileCategory_t FileCategory) +{ + const char *Result; + + switch (FileCategory) + { + case CFE_FS_FileCategory_SCRIPT: + case CFE_FS_FileCategory_DYNAMIC_MODULE: + /* scripts and app/lib modules reside in the non-volatile/CF mount by default */ + Result = GLOBAL_CFE_CONFIGDATA.NonvolMountPoint; + break; + case CFE_FS_FileCategory_TEMP: + case CFE_FS_FileCategory_BINARY_DATA_DUMP: + case CFE_FS_FileCategory_TEXT_LOG: + /* temporary and data dump files are put in the RAM DISK mount by default */ + Result = GLOBAL_CFE_CONFIGDATA.RamdiskMountPoint; + break; + default: + Result = NULL; /* Should not be used */ + break; + } + + return Result; +} + +const char *CFE_FS_GetDefaultExtension(CFE_FS_FileCategory_t FileCategory) +{ + const char *Result; + + switch (FileCategory) + { + case CFE_FS_FileCategory_SCRIPT: + Result = CFE_FS_DEFAULT_SCRIPT_EXTENSION; + break; + case CFE_FS_FileCategory_DYNAMIC_MODULE: + /* app/lib modules use a platform-specific extension, and the + * default is derived from the build system */ + Result = GLOBAL_CONFIGDATA.Default_ModuleExtension; + break; + case CFE_FS_FileCategory_TEMP: + Result = CFE_FS_DEFAULT_TEMP_FILE_EXTENSION; + break; + case CFE_FS_FileCategory_BINARY_DATA_DUMP: + Result = CFE_FS_DEFAULT_DUMP_FILE_EXTENSION; + break; + case CFE_FS_FileCategory_TEXT_LOG: + Result = CFE_FS_DEFAULT_LOG_FILE_EXTENSION; + break; + default: + Result = NULL; /* Should not be used */ + break; + } + + return Result; +} + +/* +** CFE_FS_ReadHeader() - See API and header file for details +*/ +int32 CFE_FS_ReadHeader(CFE_FS_Header_t *Hdr, osal_id_t FileDes) +{ + int32 Result; + int32 EndianCheck = 0x01020304; + + if (Hdr == NULL) + { + return CFE_FS_BAD_ARGUMENT; + } + + /* + ** Ensure that we are at the start of the file... + */ + Result = OS_lseek(FileDes, 0, OS_SEEK_SET); + + if (Result == OS_SUCCESS) + { + /* + ** Read header structure into callers buffer... + */ + Result = OS_read(FileDes, Hdr, sizeof(CFE_FS_Header_t)); + + /* Determine if this processor is a little endian processor */ + if ((*(char *)(&EndianCheck)) == 0x04) + { + /* If this is a little endian processor, then convert the header data structure from */ + /* its standard big-endian format into a little endian format to ease user access */ + CFE_FS_ByteSwapCFEHeader(Hdr); + } + } + + return (Result); + +} /* End of CFE_FS_ReadHeader() */ + +/* +** CFE_FS_InitHeader() - See API and header file for details +*/ +void CFE_FS_InitHeader(CFE_FS_Header_t *Hdr, const char *Description, uint32 SubType) +{ + if (Hdr == NULL || Description == NULL) + { + CFE_ES_WriteToSysLog("CFE_FS:InitHeader-Failed invalid arguments\n"); + } + else + { + memset(Hdr, 0, sizeof(CFE_FS_Header_t)); + strncpy((char *)Hdr->Description, Description, sizeof(Hdr->Description) - 1); + Hdr->SubType = SubType; + } +} + +/* +** CFE_FS_WriteHeader() - See API and header file for details +*/ +int32 CFE_FS_WriteHeader(osal_id_t FileDes, CFE_FS_Header_t *Hdr) +{ + CFE_TIME_SysTime_t Time; + int32 Result; + int32 EndianCheck = 0x01020304; + CFE_ES_AppId_t AppID; + + if (Hdr == NULL) + { + return CFE_FS_BAD_ARGUMENT; + } + + /* + ** Ensure that we are at the start of the file... + */ + Result = OS_lseek(FileDes, 0, OS_SEEK_SET); + + if (Result == OS_SUCCESS) + { + /* + ** Fill in the ID fields... + */ + Hdr->SpacecraftID = CFE_PSP_GetSpacecraftId(); + Hdr->ProcessorID = CFE_PSP_GetProcessorId(); + CFE_ES_GetAppID(&AppID); + Hdr->ApplicationID = CFE_RESOURCEID_TO_ULONG(AppID); + + /* Fill in length field */ + + Hdr->Length = sizeof(CFE_FS_Header_t); + + /* put the header, 'cfe1' in hex, in to the content type */ + Hdr->ContentType = 0x63464531; + + /* + ** Fill in the timestamp fields... + */ + Time = CFE_TIME_GetTime(); + Hdr->TimeSeconds = Time.Seconds; + Hdr->TimeSubSeconds = Time.Subseconds; + + /* + ** Determine if this is a little endian processor + */ + if ((*(char *)(&EndianCheck)) == 0x04) + { + /* If this is a little endian processor, then convert the header data structure from */ + /* the native little endian format to the required CFE standard big endian format */ + CFE_FS_ByteSwapCFEHeader(Hdr); + } + + /* + ** Write header structure from callers buffer... + */ + Result = OS_write(FileDes, Hdr, sizeof(CFE_FS_Header_t)); + + /* + ** Determine if this is a little endian processor + */ + if ((*(char *)(&EndianCheck)) == 0x04) + { + /* If this is a little endian processor, then convert the header data structure back */ + /* from the required CFE standard big endian format to the little endian format */ + CFE_FS_ByteSwapCFEHeader(Hdr); + } + } + + return (Result); + +} /* End of CFE_FS_WriteHeader() */ + +/* +** CFE_FS_SetTimestamp - See API and header file for details +*/ +int32 CFE_FS_SetTimestamp(osal_id_t FileDes, CFE_TIME_SysTime_t NewTimestamp) +{ + int32 Result; + CFE_FS_Header_t TempHdr; + int32 EndianCheck = 0x01020304; + CFE_TIME_SysTime_t OutTimestamp = NewTimestamp; + int32 FileOffset = 0; + + FileOffset = ((char *)&TempHdr.TimeSeconds - (char *)&TempHdr.ContentType); + Result = OS_lseek(FileDes, FileOffset, OS_SEEK_SET); + + if (Result == FileOffset) + { + /* + ** Determine if this is a little endian processor + */ + if ((*(char *)(&EndianCheck)) == 0x04) + { + /* If this processor is a little endian processor, then convert the timestamp to a big */ + /* endian format so that it is compatible with the standard cFE File Header format */ + CFE_FS_ByteSwapUint32(&OutTimestamp.Seconds); + CFE_FS_ByteSwapUint32(&OutTimestamp.Subseconds); + } + + Result = OS_write(FileDes, &OutTimestamp.Seconds, sizeof(OutTimestamp.Seconds)); + + /* On a good write, the value returned will equal the number of bytes written */ + if (Result == sizeof(OutTimestamp.Seconds)) + { + Result = OS_write(FileDes, &OutTimestamp.Subseconds, sizeof(OutTimestamp.Subseconds)); + + if (Result == sizeof(OutTimestamp.Subseconds)) + { + Result = OS_SUCCESS; + } + else + { + CFE_ES_WriteToSysLog("CFE_FS:SetTime-Failed to write Seconds (Status=0x%08X)\n", (unsigned int)Result); + } + } + else + { + CFE_ES_WriteToSysLog("CFE_FS:SetTime-Failed to write Seconds (Status=0x%08X)\n", (unsigned int)Result); + } + } + else + { + CFE_ES_WriteToSysLog("CFE_FS:SetTime-Failed to lseek time fields (Status=0x%08X)\n", (unsigned int)Result); + } + + return (Result); +} /* End of CFE_FS_SetTimestamp() */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* */ +/* CFE_FS_ByteSwapCFEHeader() -- byte swap cFE file header structure */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void CFE_FS_ByteSwapCFEHeader(CFE_FS_Header_t *Hdr) +{ + CFE_FS_ByteSwapUint32(&Hdr->ContentType); + CFE_FS_ByteSwapUint32(&Hdr->SubType); + CFE_FS_ByteSwapUint32(&Hdr->Length); + CFE_FS_ByteSwapUint32(&Hdr->SpacecraftID); + CFE_FS_ByteSwapUint32(&Hdr->ProcessorID); + CFE_FS_ByteSwapUint32(&Hdr->ApplicationID); + CFE_FS_ByteSwapUint32(&Hdr->TimeSeconds); + CFE_FS_ByteSwapUint32(&Hdr->TimeSubSeconds); + +} /* End of CFE_FS_ByteSwapCFEHeader() */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* */ +/* CFE_FS_ByteSwapUint32() -- byte swap an uint32 */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void CFE_FS_ByteSwapUint32(uint32 *Uint32ToSwapPtr) +{ + int32 Temp = *Uint32ToSwapPtr; + char *InPtr = (char *)&Temp; + char *OutPtr = (char *)Uint32ToSwapPtr; + + OutPtr[0] = InPtr[3]; + OutPtr[1] = InPtr[2]; + OutPtr[2] = InPtr[1]; + OutPtr[3] = InPtr[0]; +} /* End of CFE_FS_ByteSwapUint32() */ + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_FS_ParseInputFileNameEx +** +** Purpose: This reads a file name from user input with extra logic to make more user friendly +** - absolute path is optional; assume default dir if missing +** - module extension is optional; append default for OS/platform if missing +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_FS_ParseInputFileNameEx(char *OutputBuffer, const char *InputBuffer, size_t OutputBufSize, + size_t InputBufSize, const char *DefaultInput, const char *DefaultPath, + const char *DefaultExtension) +{ + int32 Status; + const char *InputPtr; + const char *ComponentPtr; + size_t ComponentLen; + char ComponentTerm; + size_t OutputLen; + size_t InputLen; + bool LastPathReached; + + /* The filename consists of a pathname, filename, and extension component. */ + enum + { + PROCESS_INIT, + PATHNAME_COMPONENT, + PATHNAME_SEPARATOR, + FILENAME_COMPONENT, + EXTENSION_SEPARATOR, + EXTENSION_COMPONENT, + END_COMPONENT + } Component; + + /* Sanity check buffer input */ + if (OutputBuffer == NULL || OutputBufSize == 0) + { + return CFE_FS_BAD_ARGUMENT; + } + + Status = CFE_FS_INVALID_PATH; + OutputLen = 0; + ComponentTerm = 0; + LastPathReached = false; + + /* If input buffer is not empty, then use it, otherwise use DefaultInput */ + if (InputBuffer != NULL && InputBufSize > 0 && InputBuffer[0] != 0) + { + InputPtr = InputBuffer; + InputLen = InputBufSize; + } + else if (DefaultInput != NULL) + { + /* This must be a normal null terminated string */ + InputPtr = DefaultInput; + InputLen = strlen(DefaultInput); + } + else + { + /* No input */ + InputPtr = NULL; + InputLen = 0; + } + + Component = PROCESS_INIT; + while (InputPtr != NULL && Component < END_COMPONENT) + { + /* Move to next component */ + if (Component == PATHNAME_SEPARATOR && !LastPathReached) + { + /* repeat until LastPathReached */ + Component = PATHNAME_COMPONENT; + } + else + { + ++Component; + } + + switch (Component) + { + case PATHNAME_COMPONENT: + /* path part ends with the last / char, which begins the filename */ + ComponentTerm = '/'; + ComponentPtr = memchr(InputPtr, ComponentTerm, InputLen); + if (ComponentPtr != NULL) + { + /* has path: use pathname from input, advance InputPtr to next part (filename) */ + ComponentLen = ComponentPtr - InputPtr; + ComponentPtr = InputPtr; + InputPtr += ComponentLen; + InputLen -= ComponentLen; + } + else + { + LastPathReached = true; + + /* no path: if no output at all yet, use default pathname, otherwise move on. */ + if (DefaultPath != NULL && OutputLen == 0) + { + ComponentLen = strlen(DefaultPath); + ComponentPtr = DefaultPath; + } + else + { + /* use no pathname at all */ + ComponentLen = 0; + ComponentPtr = NULL; + } + } + break; + + case FILENAME_COMPONENT: + /* filename ends with a . char, which begins the extension */ + ComponentTerm = '.'; + ComponentPtr = memchr(InputPtr, ComponentTerm, InputLen); + if (ComponentPtr != NULL) + { + /* has ext: use pathname from input, advance InputPtr to next part (extension) */ + ComponentLen = ComponentPtr - InputPtr; + ComponentPtr = InputPtr; + InputPtr += ComponentLen; + InputLen -= ComponentLen; + } + else + { + /* no ext: use remainder of input here - then use default extension for next part */ + ComponentLen = InputLen; + ComponentPtr = InputPtr; + if (DefaultExtension != NULL) + { + InputPtr = DefaultExtension; + InputLen = strlen(DefaultExtension); + } + else + { + /* Use no extension */ + InputPtr = NULL; + InputLen = 0; + } + } + + if (ComponentLen > 0 && *ComponentPtr != 0) + { + /* + * If the filename part is non-empty, then consider the conversion successful + * (note that extension is not really needed for an acceptable filename) + */ + Status = CFE_SUCCESS; + } + + break; + + case PATHNAME_SEPARATOR: + case EXTENSION_SEPARATOR: + /* Remove duplicate terminators that may have been in the input */ + while (OutputLen > 0 && OutputBuffer[OutputLen - 1] == ComponentTerm) + { + --OutputLen; + } + + ComponentLen = 1; + ComponentPtr = &ComponentTerm; + + /* advance past any separators in input to get to the next content */ + while (*InputPtr == ComponentTerm && InputLen > 0) + { + ++InputPtr; + --InputLen; + } + break; + + case EXTENSION_COMPONENT: + /* Intentional fall through to default case */ + + default: + /* Just consume the rest of input - + * should already be pointing to correct data */ + ComponentTerm = 0; + ComponentLen = InputLen; + ComponentPtr = InputPtr; + InputPtr = NULL; /* no more input */ + InputLen = 0; + break; + } + + /* Append component */ + while (ComponentLen > 0 && *ComponentPtr != 0) + { + OutputBuffer[OutputLen] = *ComponentPtr; + ++ComponentPtr; + ++OutputLen; + --ComponentLen; + + if (OutputLen >= OutputBufSize) + { + /* name is too long to fit in output buffer */ + Status = CFE_FS_FNAME_TOO_LONG; + InputPtr = NULL; /* no more input */ + InputLen = 0; + --OutputLen; /* back up one char for term */ + break; + } + } + } + + /* + * Always add a final terminating NUL char. + * + * Note that the loop above should never entirely fill + * buffer (length check includes extra char). + */ + OutputBuffer[OutputLen] = 0; + + return Status; +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_FS_ParseInputFileName +** +** Purpose: Simplified API for CFE_FS_ParseInputFileNameEx where input is always known to be +** a non-empty, null terminated string and the fixed-length input buffer not needed. +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_FS_ParseInputFileName(char *OutputBuffer, const char *InputName, size_t OutputBufSize, + CFE_FS_FileCategory_t FileCategory) +{ + return CFE_FS_ParseInputFileNameEx(OutputBuffer, NULL, OutputBufSize, 0, InputName, + CFE_FS_GetDefaultMountPoint(FileCategory), + CFE_FS_GetDefaultExtension(FileCategory)); +} + +/* +** CFE_FS_ExtractFilenameFromPath - See API and header file for details +*/ +int32 CFE_FS_ExtractFilenameFromPath(const char *OriginalPath, char *FileNameOnly) +{ + uint32 i, j; + int StringLength; + int DirMarkIdx; + int32 ReturnCode; + + if (OriginalPath == NULL || FileNameOnly == NULL) + { + ReturnCode = CFE_FS_BAD_ARGUMENT; + } + else + { + + /* + ** Get the string length of the original file path + */ + StringLength = strlen(OriginalPath); + + /* + ** Extract the filename from the Path + */ + + /* + ** Find the last '/' Character + */ + DirMarkIdx = -1; + for (i = 0; i < StringLength; i++) + { + if (OriginalPath[i] == '/') + { + DirMarkIdx = i; + } + } + + /* + ** Verify the filename isn't too long + */ + if ((StringLength - (DirMarkIdx + 1)) < OS_MAX_PATH_LEN) + { + /* + ** Extract the filename portion + */ + if (DirMarkIdx > 0) + { + /* + ** Extract the filename portion + */ + j = 0; + for (i = DirMarkIdx + 1; i < StringLength; i++) + { + FileNameOnly[j] = OriginalPath[i]; + j++; + } + FileNameOnly[j] = '\0'; + + ReturnCode = CFE_SUCCESS; + } + else + { + ReturnCode = CFE_FS_INVALID_PATH; + } + } + else + { + ReturnCode = CFE_FS_FNAME_TOO_LONG; + } + } + + return (ReturnCode); +} + +/* +** CFE_FS_RunBackgroundFileDump - See API and header file for details +*/ +bool CFE_FS_RunBackgroundFileDump(uint32 ElapsedTime, void *Arg) +{ + CFE_FS_CurrentFileState_t * State; + CFE_FS_BackgroundFileDumpEntry_t *Curr; + CFE_FS_FileWriteMetaData_t * Meta; + int32 Status; + CFE_FS_Header_t FileHdr; + void * RecordPtr; + size_t RecordSize; + bool IsEOF; + + State = &CFE_FS_Global.FileDump.Current; + Curr = NULL; + IsEOF = false; + RecordPtr = NULL; + RecordSize = 0; + + State->Credit += (ElapsedTime * CFE_FS_BACKGROUND_CREDIT_PER_SECOND) / 1000; + if (State->Credit > CFE_FS_BACKGROUND_MAX_CREDIT) + { + State->Credit = CFE_FS_BACKGROUND_MAX_CREDIT; + } + + /* + * Lock shared data. + * Not strictly necessary as the "CompleteCount" is only updated + * by this task but this helps in case the access isn't atomic. + */ + CFE_FS_LockSharedData(__func__); + + if (CFE_FS_Global.FileDump.CompleteCount != CFE_FS_Global.FileDump.RequestCount) + { + Curr = &CFE_FS_Global.FileDump + .Entries[CFE_FS_Global.FileDump.CompleteCount & (CFE_FS_MAX_BACKGROUND_FILE_WRITES - 1)]; + } + + CFE_FS_UnlockSharedData(__func__); + + if (Curr == NULL) + { + return false; + } + + Meta = Curr->Meta; + + if (!OS_ObjectIdDefined(State->Fd) && Meta->IsPending) + { + /* First time processing this entry - open the file */ + Status = OS_OpenCreate(&State->Fd, Meta->FileName, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); + if (Status < 0) + { + State->Fd = OS_OBJECT_ID_UNDEFINED; + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_CREATE_ERROR, Status, 0, 0, 0); + } + else + { + CFE_FS_InitHeader(&FileHdr, Meta->Description, Meta->FileSubType); + + /* write the cFE header to the file */ + Status = CFE_FS_WriteHeader(State->Fd, &FileHdr); + if (Status != sizeof(CFE_FS_Header_t)) + { + OS_close(State->Fd); + State->Fd = OS_OBJECT_ID_UNDEFINED; + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR, Status, State->RecordNum, + sizeof(CFE_FS_Header_t), State->FileSize); + } + else + { + State->FileSize = sizeof(CFE_FS_Header_t); + State->Credit -= sizeof(CFE_FS_Header_t); + State->RecordNum = 0; + } + } + } + + while (OS_ObjectIdDefined(State->Fd) && State->Credit > 0 && !IsEOF) + { + /* + * Getter should return false on EOF (last record), true if more data is still waiting + */ + IsEOF = Meta->GetData(Meta, State->RecordNum, &RecordPtr, &RecordSize); + + /* + * if the getter outputs a record size of 0, this means there is no data for + * this entry, but the cycle keeps going (in case of "holes" or unused table entries + * in the database). + */ + if (RecordSize > 0) + { + State->Credit -= RecordSize; + + /* + * Now write to file + */ + Status = OS_write(State->Fd, RecordPtr, RecordSize); + + if (Status != RecordSize) + { + /* end the file early (cannot set "IsEOF" as this would cause the complete event to be generated too) */ + OS_close(State->Fd); + State->Fd = OS_OBJECT_ID_UNDEFINED; + + /* generate write error event */ + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR, Status, State->RecordNum, RecordSize, + State->FileSize); + break; + } + else + { + State->FileSize += RecordSize; + } + } + + ++State->RecordNum; + + } /* end if */ + + /* On normal EOF close the file and generate the complete event */ + if (IsEOF) + { + OS_close(State->Fd); + State->Fd = OS_OBJECT_ID_UNDEFINED; + + /* generate complete event */ + Meta->OnEvent(Meta, CFE_FS_FileWriteEvent_COMPLETE, CFE_SUCCESS, State->RecordNum, 0, State->FileSize); + } + + /* + * if the file is not open, consider this file complete, and advance the head position. + * (done this way so it also catches the case where the file failed to create, not just EOF) + */ + if (!OS_ObjectIdDefined(State->Fd)) + { + CFE_FS_LockSharedData(__func__); + + /* Wipe the entry structure, as it will be reused */ + memset(Curr, 0, sizeof(*Curr)); + ++CFE_FS_Global.FileDump.CompleteCount; + + /* Set the "IsPending" flag to false - this indicates that the originator may re-post now */ + Meta->IsPending = false; + + CFE_FS_UnlockSharedData(__func__); + + } /* end if */ + + return !IsEOF; +} + +/* +** CFE_FS_BackgroundFileDumpRequest - See API and header file for details +*/ +int32 CFE_FS_BackgroundFileDumpRequest(CFE_FS_FileWriteMetaData_t *Meta) +{ + CFE_FS_BackgroundFileDumpEntry_t *Curr; + int32 Status; + uint32 PendingRequestCount; + + /* Pre-validate inputs */ + if (Meta == NULL) + { + return CFE_FS_BAD_ARGUMENT; + } + + /* getter and event functions must be set */ + if (Meta->GetData == NULL || Meta->OnEvent == NULL) + { + return CFE_FS_BAD_ARGUMENT; + } + + /* filename cannot be empty */ + if (Meta->FileName[0] == 0) + { + return CFE_FS_INVALID_PATH; + } + + /* request must not already be pending */ + if (Meta->IsPending) + { + return CFE_STATUS_REQUEST_ALREADY_PENDING; + } + + CFE_FS_LockSharedData(__func__); + + PendingRequestCount = CFE_FS_Global.FileDump.RequestCount + 1; + + /* Check if queue is full before writing to tail position */ + if (PendingRequestCount == (CFE_FS_Global.FileDump.CompleteCount + CFE_FS_MAX_BACKGROUND_FILE_WRITES)) + { + Status = CFE_STATUS_REQUEST_ALREADY_PENDING; + } + else + { + Curr = &CFE_FS_Global.FileDump + .Entries[CFE_FS_Global.FileDump.RequestCount & (CFE_FS_MAX_BACKGROUND_FILE_WRITES - 1)]; + + /* + * store the meta object - note this retains the pointer that was submitted + * (caller must not reuse/change this object until request is completed) + */ + Curr->Meta = Meta; + + /* + * The "IsPending" Flag will be set true whenever while this is waiting in the request queue. + * It will be set false when the file is done. + * + * The requester can check this flag to determine if/when the request is complete + */ + Meta->IsPending = true; + + /* update tail position */ + CFE_FS_Global.FileDump.RequestCount = PendingRequestCount; + + Status = CFE_SUCCESS; + } + + CFE_FS_UnlockSharedData(__func__); + + if (Status == CFE_SUCCESS) + { + /* + * If successfully added to write queue, then wake the ES background task to get started. + * + * This may reduce the overall latency between request and completion (depending on other + * background task work). If this is the only pending job, this should get it started faster. + */ + CFE_ES_BackgroundWakeup(); + } + + return Status; +} + +/* +** CFE_FS_ExtractFilenameFromPath - See API and header file for details +*/ +bool CFE_FS_BackgroundFileDumpIsPending(const CFE_FS_FileWriteMetaData_t *Meta) +{ + if (Meta == NULL) + { + return false; + } + + return Meta->IsPending; +} + +/************************/ +/* End of File Comment */ +/************************/ diff --git a/modules/fs/fsw/src/cfe_fs_module_all.h b/modules/fs/fsw/src/cfe_fs_module_all.h new file mode 100644 index 000000000..9c2affb85 --- /dev/null +++ b/modules/fs/fsw/src/cfe_fs_module_all.h @@ -0,0 +1,41 @@ +/* +** 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 FS 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_FS_MODULE_ALL_H +#define CFE_FS_MODULE_ALL_H + +/* +** Includes +*/ +#include "cfe.h" +#include "cfe_fs_priv.h" +#include "cfe_fs_core_internal.h" + +#endif /* CFE_FS_MODULE_ALL_H */ diff --git a/modules/fs/fsw/src/cfe_fs_priv.c b/modules/fs/fsw/src/cfe_fs_priv.c new file mode 100644 index 000000000..4344aaddc --- /dev/null +++ b/modules/fs/fsw/src/cfe_fs_priv.c @@ -0,0 +1,140 @@ +/* +** 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_fs_priv.c +** +** Purpose: cFE File Services (FS) library API Initialization +** +** Author: Alan Cudmore/NASA GSFC +** +** Notes: +** +*/ + +/* +** Required header files +*/ +#include "cfe_fs_module_all.h" + +#include + +/* +** Global data +** +*/ +CFE_FS_Global_t CFE_FS_Global; + +/****************************************************************************** +** Function: CFE_FS_EarlyInit() +** +** Purpose: +** Initialize the FS data structures before the cFE runs. +** +** Arguments: +** +** Notes: +** This function MUST be called before any FS API's are called. +** +** Return: +** CFE_SUCCESS +*/ +int32 CFE_FS_EarlyInit(void) +{ + int32 Stat; + + memset(&CFE_FS_Global, 0, sizeof(CFE_FS_Global)); + + Stat = OS_MutSemCreate(&CFE_FS_Global.SharedDataMutexId, "CFE_FS_SharedMutex", 0); + if (Stat != OS_SUCCESS) + { + CFE_ES_WriteToSysLog("FS Shared Data Mutex creation failed! RC=0x%08x\n", (unsigned int)Stat); + return Stat; + } /* end if */ + + return Stat; + +} /* end CFE_FS_EarlyInit */ + +/****************************************************************************** +** Function: CFE_FS_LockSharedData() +** +** Purpose: +** FS internal function to handle a semaphore take failure for the FS +** Data Mutex +** +** Arguments: +** FunctionName - the Function Name of the code that generated the error. +** +** Return: +** None +*/ +void CFE_FS_LockSharedData(const char *FunctionName) +{ + int32 Status; + CFE_ES_AppId_t AppId; + + Status = OS_MutSemTake(CFE_FS_Global.SharedDataMutexId); + if (Status != OS_SUCCESS) + { + CFE_ES_GetAppID(&AppId); + + CFE_ES_WriteToSysLog("FS SharedData Mutex Take Err Stat=0x%x,App=%lu,Function=%s\n", (unsigned int)Status, + CFE_RESOURCEID_TO_ULONG(AppId), FunctionName); + + } /* end if */ + + return; + +} /* end CFE_FS_LockSharedData */ + +/****************************************************************************** +** Function: CFE_FS_UnlockSharedData() +** +** Purpose: +** FS internal function to handle a semaphore give failure for the Shared +** Data Mutex +** +** Arguments: +** FunctionName - the Function containing the code that generated the error. +** +** Return: +** None +*/ +void CFE_FS_UnlockSharedData(const char *FunctionName) +{ + int32 Status; + CFE_ES_AppId_t AppId; + + Status = OS_MutSemGive(CFE_FS_Global.SharedDataMutexId); + if (Status != OS_SUCCESS) + { + CFE_ES_GetAppID(&AppId); + CFE_ES_WriteToSysLog("FS SharedData Mutex Give Err Stat=0x%x,App=%lu,Function=%s\n", (unsigned int)Status, + CFE_RESOURCEID_TO_ULONG(AppId), FunctionName); + + } /* end if */ + return; + +} /* end CFE_FS_UnlockSharedData */ + +/************************/ +/* End of File Comment */ +/************************/ diff --git a/modules/fs/fsw/src/cfe_fs_priv.h b/modules/fs/fsw/src/cfe_fs_priv.h new file mode 100644 index 000000000..3979d98ec --- /dev/null +++ b/modules/fs/fsw/src/cfe_fs_priv.h @@ -0,0 +1,155 @@ +/* +** 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 contains prototypes for private functions and type + * definitions for FS internal use. + * + * Author: A. Cudmore/NASA GSFC + * + */ + +#ifndef CFE_FS_PRIV_H +#define CFE_FS_PRIV_H + +/* +** Includes +*/ +#include "common_types.h" +#include "cfe_fs_api_typedefs.h" +#include "cfe_es_api_typedefs.h" + +/* +** Macro Definitions +*/ + +/* + * Max Number of file write requests that can be queued + * + * This needs to be a power of two to simplify the masking/wraparound (bitwise AND). + */ +#define CFE_FS_MAX_BACKGROUND_FILE_WRITES 4 + +/* + * Background file credit accumulation rate + * + * The background file writer will limit the total bytes written over time. This + * controls the amount of "credit" (bytes that can be written) per second + * of elapsed time. + * + * This permits a file writing rate of up to 10kbytes/sec. + */ +#define CFE_FS_BACKGROUND_CREDIT_PER_SECOND 10000 + +/* + * Maximum credit that the background write task can accumulate + * + * The background file writer will limit the total bytes written over time, and + * will accumulate credit against this limit while no writes are in progress. + * This is an upper cap on the amount of credit that can be accumulated. + * + * Without this limit, after a long period of inactivity without any file + * writes, a large credit would essentially bypass the rate limiting for + * the next file write command(s) once they are issued. + */ +#define CFE_FS_BACKGROUND_MAX_CREDIT 10000 + +/* +** Type Definitions +*/ + +/* + * Background file dump entry structure + * + * This structure is stored in global memory and keeps the state + * of the file dump from one iteration to the next. + */ +typedef struct +{ + CFE_ES_AppId_t RequestorAppId; + CFE_FS_FileWriteMetaData_t *Meta; +} CFE_FS_BackgroundFileDumpEntry_t; + +typedef struct +{ + osal_id_t Fd; + int32 Credit; + uint32 RecordNum; + size_t FileSize; +} CFE_FS_CurrentFileState_t; + +/** + * \brief Background file dump queue structure + * + * This structure is stored in global memory and keeps the state + * of the file dump from one iteration to the next. + * + * Normally when idle the "RequestCount" and "CompleteCount" are the + * same value. When an application requests a background file dump, + * the "RequestCount" is incremented accordingly, and when the background + * job finishes, the "CompleteCount" is incremented accordingly. + */ +typedef struct +{ + uint32 RequestCount; /**< Total Number of background file writes requested */ + uint32 CompleteCount; /**< Total Number of background file writes completed */ + + /** + * Data related to each background file write request + */ + CFE_FS_BackgroundFileDumpEntry_t Entries[CFE_FS_MAX_BACKGROUND_FILE_WRITES]; + + /** + * Persistent storage for the current file write + * (reused for each file) + */ + CFE_FS_CurrentFileState_t Current; + +} CFE_FS_BackgroundFileDumpState_t; + +/****************************************************************************** +** Typedef: CFE_FS_Global_t +** +** Purpose: +** This structure contains the FS global variables. +*/ +typedef struct +{ + osal_id_t SharedDataMutexId; + + CFE_FS_BackgroundFileDumpState_t FileDump; + +} CFE_FS_Global_t; + +extern CFE_FS_Global_t CFE_FS_Global; + +/* +** FS Function Prototypes +*/ + +extern void CFE_FS_LockSharedData(const char *FunctionName); +extern void CFE_FS_UnlockSharedData(const char *FunctionName); +extern void CFE_FS_ByteSwapCFEHeader(CFE_FS_Header_t *Hdr); +extern void CFE_FS_ByteSwapUint32(uint32 *Uint32ToSwapPtr); + +#endif /* CFE_FS_PRIV_H */