diff --git a/.gitignore b/.gitignore
index 08d4d122f..09be9d371 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,9 +17,9 @@
!modules/tbl/CMakeLists.txt
# Time Services (TIME)
-# !modules/core_private/fsw/inc/cfe_time*
-# !modules/core_api/fsw/inc/cfe_time*
+!modules/core_private/fsw/inc/cfe_time*
+!modules/core_api/fsw/inc/cfe_time*
-# !modules/time/fsw/**
-# !modules/time/CMakeLists.txt
+!modules/time/fsw/**
+!modules/time/CMakeLists.txt
diff --git a/modules/core_api/fsw/inc/cfe_time.h b/modules/core_api/fsw/inc/cfe_time.h
new file mode 100644
index 000000000..1ca214ba3
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_time.h
@@ -0,0 +1,722 @@
+/*
+** 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 Time Services (TIME) library API header file
+ *
+ * Author: S.Walling/Microtel
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_TIME_H
+#define CFE_TIME_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_error.h"
+#include "cfe_time_api_typedefs.h"
+#include "cfe_es_api_typedefs.h"
+
+/**
+** \brief Time Copy
+**
+** Macro to copy systime into another systime.
+** Preferred to use this macro as it does not require the two arguments to be exactly the same type,
+** it will work with any two structures that define "Seconds" and "Subseconds" members.
+*/
+#define CFE_TIME_Copy(m, t) \
+ { \
+ (m)->Seconds = (t)->Seconds; \
+ (m)->Subseconds = (t)->Subseconds; \
+ }
+
+/*****************************************************************************/
+/*
+** Exported Functions
+*/
+
+/** @defgroup CFEAPITIMEGetCurrent cFE Get Current Time APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Get the current spacecraft time
+**
+** \par Description
+** This routine returns the current spacecraft time. The time returned
+** is either TAI (no leap seconds) or UTC (including leap seconds). This choice
+** is made in the mission configuration file by defining either #CFE_MISSION_TIME_CFG_DEFAULT_TAI
+** or #CFE_MISSION_TIME_CFG_DEFAULT_UTC as true at compile time. To maintain re-usability
+** across missions, most applications should be using this function
+** (or #CFE_TIME_GetTime) rather than the specific routines for getting UTC/TAI directly.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return The current spacecraft time in default format
+**
+** \sa #CFE_TIME_GetTAI, #CFE_TIME_GetUTC, #CFE_TIME_GetMET,
+** #CFE_TIME_GetMETseconds, #CFE_TIME_GetMETsubsecs
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_GetTime(void);
+
+/*****************************************************************************/
+/**
+** \brief Get the current TAI (MET + SCTF) time
+**
+** \par Description
+** This routine returns the current TAI time to the caller. TAI is an
+** international time standard that does not include leap seconds.
+** This routine should only be used in situations where TAI is absolutely
+** required. Applications that call #CFE_TIME_GetTAI may not be portable
+** to all missions. Maintenance of correct TAI in flight is not guaranteed
+** under all mission operations scenarios. To maintain re-usability across
+** missions, most applications should be using #CFE_TIME_GetTime, rather
+** than the specific routines for getting UTC/TAI directly.
+**
+** \par Assumptions, External Events, and Notes:
+** -# The "TAI" time returned is referenced to the mission-defined time epoch,
+** which may or may not be the same as the standard TAI epoch.
+** -# Even though TAI does not include leap seconds, the time returned by this
+** function can still jump forward or backward without warning when the
+** spacecraft clock is set or adjusted by operators. Applications using
+** this function must be able to handle these time discontinuities gracefully.
+**
+** \return The current spacecraft time in TAI
+**
+** \sa #CFE_TIME_GetTime, #CFE_TIME_GetUTC, #CFE_TIME_GetMET,
+** #CFE_TIME_GetMETseconds, #CFE_TIME_GetMETsubsecs
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_GetTAI(void);
+
+/*****************************************************************************/
+/**
+** \brief Get the current UTC (MET + SCTF - Leap Seconds) time
+**
+** \par Description
+** This routine returns the current UTC time to the caller. This routine
+** should only be used in situations where UTC is absolutely required.
+** Applications that call #CFE_TIME_GetUTC may not be portable to all
+** missions. Maintenance of correct UTC in flight is not guaranteed under
+** all mission operations scenarios. If UTC is maintained in flight, it will
+** jump backwards occasionally due to leap second adjustments. To maintain
+** re-usability across missions, most applications should be using
+** #CFE_TIME_GetTime, rather than the specific routines for getting
+** UTC/TAI directly.
+**
+** \par Assumptions, External Events, and Notes:
+** Note: The "UTC" time returned is referenced to the mission-defined time epoch,
+** which may or may not be the same as the standard UTC epoch.
+**
+** \return The current spacecraft time in UTC
+**
+** \sa #CFE_TIME_GetTime, #CFE_TIME_GetTAI, #CFE_TIME_GetMET,
+** #CFE_TIME_GetMETseconds, #CFE_TIME_GetMETsubsecs
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_GetUTC(void);
+
+/*****************************************************************************/
+/**
+** \brief Get the current value of the Mission Elapsed Time (MET).
+**
+** \par Description
+** This routine returns the current mission-elapsed time (MET). MET is
+** usually derived from a hardware-based clock that is not adjusted
+** during normal operations. Callers of this routine should not assume
+** that the MET return value has any specific relationship to any
+** ground-based time standard.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return The current MET
+**
+** \sa #CFE_TIME_GetTime, #CFE_TIME_GetTAI, #CFE_TIME_GetUTC,
+** #CFE_TIME_GetMETseconds, #CFE_TIME_GetMETsubsecs, #CFE_TIME_MET2SCTime
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_GetMET(void);
+
+/*****************************************************************************/
+/**
+** \brief Get the current seconds count of the mission-elapsed time.
+**
+** \par Description
+** This routine is the same as #CFE_TIME_GetMET, except that it
+** returns only the integer seconds portion of the MET time.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return The current MET seconds
+**
+** \sa #CFE_TIME_GetTime, #CFE_TIME_GetTAI, #CFE_TIME_GetUTC, #CFE_TIME_GetMET,
+** #CFE_TIME_GetMETsubsecs, #CFE_TIME_MET2SCTime
+**
+******************************************************************************/
+uint32 CFE_TIME_GetMETseconds(void);
+
+/*****************************************************************************/
+/**
+** \brief Get the current sub-seconds count of the mission-elapsed time.
+**
+** \par Description
+** This routine is the same as #CFE_TIME_GetMET, except that it
+** returns only the integer sub-seconds portion of the MET time.
+** Each count is equal to 2^(-32) seconds.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return The current MET sub-seconds
+**
+** \sa #CFE_TIME_GetTime, #CFE_TIME_GetTAI, #CFE_TIME_GetUTC, #CFE_TIME_GetMET,
+** #CFE_TIME_GetMETseconds, #CFE_TIME_MET2SCTime
+**
+******************************************************************************/
+uint32 CFE_TIME_GetMETsubsecs(void);
+/**@}*/
+
+/** @defgroup CFEAPITIMEGetInfo cFE Get Time Information APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Get the current value of the spacecraft time correction factor (STCF).
+**
+** \par Description
+** This routine returns the current value of the spacecraft time correction
+** factor. This is the delta time between the MET and the TAI time.
+** Applications cannot set or adjust the STCF; that can only be done
+** through ground commands. However, science applications may want to
+** include the STCF in their data products to aid in time correlation
+** during downstream science data processing.
+**
+** \par Assumptions, External Events, and Notes:
+** Does not include leap seconds
+**
+** \return The current SCTF
+**
+** \sa #CFE_TIME_GetLeapSeconds, #CFE_TIME_GetClockState, #CFE_TIME_GetClockInfo
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_GetSTCF(void);
+
+/*****************************************************************************/
+/**
+** \brief Get the current value of the leap seconds counter.
+**
+** \par Description
+** This routine returns the current value of the leap seconds counter.
+** This is the delta seconds between international atomic time (TAI)
+** and universal coordinated time (UTC). Applications cannot set or
+** adjust the leap seconds; that can only be done through ground commands.
+** However, science applications may want to include the leap seconds
+** counter in their data products to aid in time correlation during
+** downstream science data processing. Note that some mission operations
+** teams do not maintain the leap seconds count, preferring to adjust the
+** STCF instead. Users of this function should check with their mission
+** ops team to see how they are planning to handle leap seconds.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \returns The current spacecraft leap seconds.
+**
+** \sa #CFE_TIME_GetSTCF, #CFE_TIME_GetClockState, #CFE_TIME_GetClockInfo
+**
+******************************************************************************/
+int16 CFE_TIME_GetLeapSeconds(void);
+
+/*****************************************************************************/
+/**
+** \brief Get the current state of the spacecraft clock.
+**
+** \par Description
+** This routine returns the spacecraft clock state. Applications that
+** are highly dependent on valid time may want to call this routine
+** before taking actions based on the times returned by the various
+** clock routines
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return The current spacecraft clock state
+**
+** \sa #CFE_TIME_GetSTCF, #CFE_TIME_GetLeapSeconds, #CFE_TIME_GetClockInfo
+**
+******************************************************************************/
+CFE_TIME_ClockState_Enum_t CFE_TIME_GetClockState(void);
+
+/*****************************************************************************/
+/**
+** \brief Provides information about the spacecraft clock.
+**
+** \par Description
+** This routine returns information on the spacecraft clock in a bit mask.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \return Spacecraft clock information, \ref CFETIMEClkStates.
+** To extract the information from the
+** returned value, the flags can be used as in the following:
+** if ((ReturnValue & CFE_TIME_FLAG_xxxxxx) == CFE_TIME_FLAG_xxxxxx) then
+** the following definition of the \c CFE_TIME_FLAG_xxxxxx is true.
+**
+** \sa #CFE_TIME_GetSTCF, #CFE_TIME_GetLeapSeconds, #CFE_TIME_GetClockState
+**
+******************************************************************************/
+uint16 CFE_TIME_GetClockInfo(void);
+/**@}*/
+
+/** @defgroup CFEAPITIMEArithmetic cFE Time Arithmetic APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Adds two time values
+**
+** \par Description
+** This routine adds the two specified times and returns the result.
+** Normally, at least one of the input times should be a value representing
+** a delta time. Adding two absolute times together will not cause an error,
+** but the result will probably be meaningless.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] Time1 The first time to be added.
+**
+** \param[in] Time2 The second time to be added.
+**
+** \return The sum of the two times.
+** If the sum is greater than the maximum value that can be stored in a
+** #CFE_TIME_SysTime_t, the result will roll over (this is not considered an error).
+**
+** \sa #CFE_TIME_Subtract, #CFE_TIME_Compare
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_Add(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2);
+
+/*****************************************************************************/
+/**
+** \brief Subtracts two time values
+**
+** \par Description
+** This routine subtracts time2 from time1 and returns the result. The
+** time values can represent either absolute or delta times, but not all
+** combinations make sense.
+** - AbsTime - AbsTime = DeltaTime
+** - AbsTime - DeltaTime = AbsTime
+** - DeltaTime - DeltaTime = DeltaTime
+** - DeltaTime - AbsTime = garbage
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] Time1 The base time.
+**
+** \param[in] Time2 The time to be subtracted from the base time.
+**
+** \return The result of subtracting the two times.
+** If the subtraction results in an underflow, the result will
+** roll over (this is not considered an error).
+**
+** \sa #CFE_TIME_Add, #CFE_TIME_Compare
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_Subtract(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2);
+
+/*****************************************************************************/
+/**
+** \brief Compares two time values
+**
+** \par Description
+** This routine compares two time values to see which is "greater". It
+** is important that applications use this function rather than trying
+** to directly compare the component pieces of times. This function will
+** handle roll-over cases seamlessly, which may not be intuitively obvious.
+** The cFE's internal representation of time "rolls over" when the 32 bit
+** seconds count reaches 0xFFFFFFFF. Also, subtracting a delta time from
+** an absolute time close to the epoch could result in "roll under". The
+** strange cases that result from these situations can be handled by defining
+** the comparison function for times as follows:
+** Plot the two times on the circumference of a circle where 0 is at the
+** top and 0x80000000 is at the bottom. If the shortest arc from time A
+** to time B runs clockwise around the circle, then time A is less than
+** time B. If the shortest arc from A to B runs counter-clockwise, then
+** time A is greater than time B.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] TimeA The first time to compare.
+**
+** \param[in] TimeB The second time to compare.
+**
+** \return The result of comparing the two times.
+** \retval #CFE_TIME_EQUAL \copybrief CFE_TIME_EQUAL
+** \retval #CFE_TIME_A_GT_B \copybrief CFE_TIME_A_GT_B
+** \retval #CFE_TIME_A_LT_B \copybrief CFE_TIME_A_LT_B
+**
+** \sa #CFE_TIME_Add, #CFE_TIME_Subtract
+**
+******************************************************************************/
+CFE_TIME_Compare_t CFE_TIME_Compare(CFE_TIME_SysTime_t TimeA, CFE_TIME_SysTime_t TimeB);
+/**@}*/
+
+/** @defgroup CFEAPITIMEConvert cFE Time Conversion APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Convert specified MET into Spacecraft Time
+**
+** \par Description
+** This function returns Spacecraft Time given MET. Note that Spacecraft
+** Time is returned as either UTC or TAI depeneding on whether the mission
+** configuration parameter #CFE_MISSION_TIME_CFG_DEFAULT_UTC or #CFE_MISSION_TIME_CFG_DEFAULT_TAI
+** was set to true at compile time.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] METTime The MET to be converted.
+**
+** \return Spacecraft Time (UTC or TAI) corresponding to the specified MET
+**
+** \sa #CFE_TIME_GetMET, #CFE_TIME_GetMETseconds, #CFE_TIME_GetMETsubsecs,
+** #CFE_TIME_Sub2MicroSecs, #CFE_TIME_Micro2SubSecs
+**
+******************************************************************************/
+CFE_TIME_SysTime_t CFE_TIME_MET2SCTime(CFE_TIME_SysTime_t METTime);
+
+/*****************************************************************************/
+/**
+** \brief Converts a sub-seconds count to an equivalent number of microseconds
+**
+** \par Description
+** This routine converts from a sub-seconds count
+** (each tick is 1 / 2^32 seconds) to microseconds (each tick is 1e-06 seconds).
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] SubSeconds The sub-seconds count to convert.
+**
+** \return The equivalent number of microseconds.
+**
+** \sa #CFE_TIME_MET2SCTime, #CFE_TIME_Micro2SubSecs,
+**
+******************************************************************************/
+uint32 CFE_TIME_Sub2MicroSecs(uint32 SubSeconds);
+
+/*****************************************************************************/
+/**
+** \brief Converts a number of microseconds to an equivalent sub-seconds count.
+**
+** \par Description
+** This routine converts from microseconds (each tick is 1e-06 seconds)
+** to a subseconds count (each tick is 1 / 2^32 seconds).
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+** \param[in] MicroSeconds The sub-seconds count to convert.
+**
+** \return The equivalent number of subseconds. If the number of microseconds
+** passed in is greater than one second, (i.e. > 999,999), the return
+** value is equal to \c 0xffffffff.
+**
+** \sa #CFE_TIME_MET2SCTime, #CFE_TIME_Sub2MicroSecs,
+**
+******************************************************************************/
+uint32 CFE_TIME_Micro2SubSecs(uint32 MicroSeconds);
+
+/**@}*/
+
+/** @defgroup CFEAPITIMEExternSource cFE External Time Source APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Provides the 1 Hz signal from an external source
+**
+** \par Description
+** This routine provides a method for cFE TIME software to be notified
+** of the occurance of the 1Hz tone signal without knowledge of the
+** specific hardware design. Regardless of the source of the tone,
+** this routine should be called as soon as possible after detection
+** to allow cFE TIME software the opportunity to latch the local clock
+** as close as possible to the instant of the tone.
+**
+** \par Assumptions, External Events, and Notes:
+** - This routine may be called directly from within the context of an
+** interrupt handler.
+**
+** \sa #CFE_TIME_ExternalMET, #CFE_TIME_ExternalGPS, #CFE_TIME_ExternalTime
+**
+******************************************************************************/
+void CFE_TIME_ExternalTone(void);
+
+/*
+** Function prototypes (external time source)...
+**
+** If a Time Server has been configured to accept external time
+** data, then one of the following functions will be enabled.
+**
+** If the Time Server has also been commanded to use the external
+** time data (as opposed to getting time data from a local MET)
+** then the Time Server will use the external data in computing
+** time.
+**
+** However, regardless whether the external time data is accepted
+** by the Time Server, these functions also act as the signal to
+** create and distribute the "time at the tone" command packet.
+*/
+
+/*****************************************************************************/
+/**
+** \brief Provides the Mission Elapsed Time from an external source
+**
+** \par Description
+** This routine provides a method to provide cFE TIME with MET acquired
+** from an external source. There is a presumption that this function
+** will be called at the appropriate time (relative to the tone) such
+** that this call may be used by cFE TIME as the signal to generate the
+** "time at the tone" data command. The "time at the tone" data command
+** must arrive within the configuration parameter specified window for
+** tone signal and data packet verification.
+** The MET value at the tone "should" have zero subseconds. Although the
+** interface accepts non-zero values for sub-seconds, it may be harmful
+** to other applications that expect zero subseconds at the moment of the
+** tone. Any decision to use non-zero subseconds should be carefully considered.
+**
+** \par Assumptions, External Events, and Notes:
+** - This routine is included in the API only when 3 specific configuration
+** parameters are set to true. The first is #CFE_PLATFORM_TIME_CFG_SERVER which defines
+** this instantiation of cFE TIME as a time server (not a client). The
+** second required configuration parameter is #CFE_PLATFORM_TIME_CFG_SOURCE which
+** enables time source selection commands to the cFE TIME task, and further
+** enables configuration definitions for the selected type of external time
+** data. The third configuration parameter required for this routine is
+** #CFE_PLATFORM_TIME_CFG_SRC_MET, which indicates that the external time data consists
+** of MET.
+**
+** \param[in] NewMET The MET value at the next (or previous) 1 Hz tone signal.
+**
+** \sa #CFE_TIME_ExternalTone, #CFE_TIME_ExternalGPS, #CFE_TIME_ExternalTime
+**
+******************************************************************************/
+void CFE_TIME_ExternalMET(CFE_TIME_SysTime_t NewMET);
+
+/*****************************************************************************/
+/**
+** \brief Provide the time from an external source that has data common to GPS receivers.
+**
+** \par Description
+** This routine provides a method to provide cFE TIME with current time
+** data acquired from an external source. There is a presumption that
+** this function will be called at the appropriate time (relative to the
+** tone) such that this call may be used by cFE TIME as the signal to
+** generate the "time at the tone" data command. The "time at the tone"
+** data command must arrive within the configuration parameter specified
+** window for tone signal and data packet verification.
+** Internally, cFE TIME will calculate a new STCF as the difference between
+** this new time value and the spacecraft MET value at the tone. This allows
+** cFE TIME to always calculate time as the sum of MET and STCF. The value
+** of STCF will change only as much as the drift factor between spacecraft
+** MET and the external time source.
+**
+** \par Assumptions, External Events, and Notes:
+** - This routine is included in the API only when 3 specific configuration
+** parameters are set to true. The first is #CFE_PLATFORM_TIME_CFG_SERVER which defines this
+** instantiation of cFE TIME as a time server (not a client). The second
+** required configuration parameter is #CFE_PLATFORM_TIME_CFG_SOURCE which enables
+** time source selection commands to the cFE TIME task, and further enables
+** configuration definitions for the selected type of external time data.
+** The third configuration parameter required for this routine is
+** #CFE_PLATFORM_TIME_CFG_SRC_GPS, which indicates that the external time data consists
+** of a time value relative to a known epoch, plus a leap seconds value.
+**
+** \param[in] NewTime The MET value at the next (or previous) 1 Hz tone signal.
+**
+** \param[in] NewLeaps The Leap Seconds value used to calculate time as UTC.
+**
+** \sa #CFE_TIME_ExternalTone, #CFE_TIME_ExternalMET, #CFE_TIME_ExternalTime
+**
+******************************************************************************/
+void CFE_TIME_ExternalGPS(CFE_TIME_SysTime_t NewTime, int16 NewLeaps);
+
+/*****************************************************************************/
+/**
+** \brief Provide the time from an external source that measures time relative to a known epoch.
+**
+** \par Description
+** This routine provides a method to provide cFE TIME with current time
+** data acquired from an external source. There is a presumption that
+** this function will be called at the appropriate time (relative to the
+** tone) such that this call may be used by cFE TIME as the signal to
+** generate the "time at the tone" data command. The "time at the tone"
+** data command must arrive within the configuration specified window for
+** tone signal and data packet verification.
+** Internally, cFE TIME will calculate a new STCF as the difference between
+** this new time value and the spacecraft MET value at the tone. This allows
+** cFE TIME to always calculate time as the sum of MET and STCF. The value
+** of STCF will change only as much as the drift factor between spacecraft
+** MET and the external time source.
+**
+** \par Assumptions, External Events, and Notes:
+** - This routine is included in the API only when 3 specific configuration
+** parameters are set to true. The first is #CFE_PLATFORM_TIME_CFG_SERVER which defines this
+** instanciation of cFE TIME as a time server (not a client). The second
+** required configuration parameter is #CFE_PLATFORM_TIME_CFG_SOURCE which enables
+** time source selection commands to the cFE TIME task, and further enables
+** configuration definitions for the selected type of external time data.
+** The third configuration parameter required for this routine is
+** #CFE_PLATFORM_TIME_CFG_SRC_TIME, which indicates that the external time data consists
+** of a time value relative to a known epoch.
+**
+** \param[in] NewTime The MET value at the next (or previous) 1 Hz tone signal.
+**
+** \sa #CFE_TIME_ExternalTone, #CFE_TIME_ExternalMET, #CFE_TIME_ExternalGPS
+**
+******************************************************************************/
+void CFE_TIME_ExternalTime(CFE_TIME_SysTime_t NewTime);
+
+/*****************************************************************************/
+/**
+** \brief Registers a callback function that is called whenever time synchronization occurs
+**
+** \par Description
+** This routine passes a callback function pointer for an Application that wishes to
+** be notified whenever a legitimate time synchronization signal (typically a 1 Hz)
+** is received.
+**
+** \par Assumptions, External Events, and Notes:
+** Only a single callback per application is supported, and this function should only
+** be called from a single thread within each application (typically the apps main thread).
+** If an application requires triggering multiple child tasks at 1Hz, it should distribute
+** the timing signal internally, rather than registering for multiple callbacks.
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_TIME_TOO_MANY_SYNCH_CALLBACKS \copybrief CFE_TIME_TOO_MANY_SYNCH_CALLBACKS
+**
+** \sa #CFE_TIME_UnregisterSynchCallback
+**
+******************************************************************************/
+CFE_Status_t CFE_TIME_RegisterSynchCallback(CFE_TIME_SynchCallbackPtr_t CallbackFuncPtr);
+
+/*****************************************************************************/
+/**
+** \brief Unregisters a callback function that is called whenever time synchronization occurs
+**
+** \par Description
+** This routine removes the specified callback function pointer from the list
+** of Callback functions that are called whenever a time synchronization (typically
+** the 1Hz signal) is received.
+**
+** \par Assumptions, External Events, and Notes:
+** Only a single callback per application is supported, and this function should only
+** be called from a single thread within each application (typically the apps main thread).
+**
+** \return Execution status, see \ref CFEReturnCodes
+** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS
+** \retval #CFE_TIME_CALLBACK_NOT_REGISTERED \copybrief CFE_TIME_CALLBACK_NOT_REGISTERED
+**
+** \sa #CFE_TIME_RegisterSynchCallback
+**
+******************************************************************************/
+CFE_Status_t CFE_TIME_UnregisterSynchCallback(CFE_TIME_SynchCallbackPtr_t CallbackFuncPtr);
+/**@}*/
+
+/** @defgroup CFEAPITIMEMisc cFE Miscellaneous Time APIs
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Print a time value as a string
+**
+** \par Description
+** This routine prints the specified time to the specified string buffer
+** in the following format:
+** \c yyyy-ddd-hh:mm:ss.xxxxx\\0
+** where:
+** - \c yyyy = year
+** - \c ddd = Julian day of the year
+** - \c hh = hour of the day (0 to 23)
+** - \c mm = minute (0 to 59)
+** - \c ss = second (0 to 59)
+** - \c xxxxx = subsecond formatted as a decimal fraction (1/4 second = 0.25000)
+** - \c \\0 = trailing null
+**
+** \par Assumptions, External Events, and Notes:
+** - The value of the time argument is simply added to the configuration
+** definitions for the ground epoch and converted into a fixed length
+** string in the buffer provided by the caller.
+** - A loss of data during the string conversion will occur if the
+** computed year exceeds 9999. However, a year that large would
+** require an unrealistic definition for the ground epoch since
+** the maximum amount of time represented by a CFE_TIME_SysTime
+** structure is approximately 136 years.
+**
+** \param[in, out] PrintBuffer Pointer to a character array of at least
+** #CFE_TIME_PRINTED_STRING_SIZE characters in length. *PrintBuffer is the time as a
+** character string as described above.
+**
+** \param[in] TimeToPrint The time to print into the character array.
+**
+******************************************************************************/
+void CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint);
+
+/*****************************************************************************/
+/**
+** \brief This function should be called from the system PSP layer once per second
+**
+** \par Description
+** Drives the time processing logic from the system PSP layer. This must be called
+** once per second based on a hardware interrupt or OS kernel signal.
+**
+** \par Assumptions, External Events, and Notes:
+** This will update the global data structures accordingly, incrementing each
+** by the 1Hz amount.
+**
+******************************************************************************/
+void CFE_TIME_Local1HzISR(void);
+/**@}*/
+
+#endif /* CFE_TIME_H */
diff --git a/modules/core_api/fsw/inc/cfe_time_api_typedefs.h b/modules/core_api/fsw/inc/cfe_time_api_typedefs.h
new file mode 100644
index 000000000..6c3dd9f4f
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_time_api_typedefs.h
@@ -0,0 +1,79 @@
+/*
+** 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 Time Services (TIME) library API header file
+ *
+ * Author: S.Walling/Microtel
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_TIME_API_TYPEDEFS_H
+#define CFE_TIME_API_TYPEDEFS_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_time_extern_typedefs.h"
+
+/*****************************************************************************/
+/*
+** Macro Definitions
+*/
+
+#define CFE_TIME_PRINTED_STRING_SIZE \
+ 24 /**< \brief Required size of buffer to be passed into #CFE_TIME_Print (includes null terminator) */
+
+/*****************************************************************************/
+/*
+** Type Definitions
+*/
+
+/**
+** \brief Enumerated types identifying the relative relationships of two times
+**
+** \par Description
+** Since time fields contain numbers that are relative to an epoch time, then it is possible for a time value
+** to be "negative". This can lead to some confusion about what relationship exists between two time values.
+** To resolve this confusion, the cFE provides the API #CFE_TIME_Compare which returns these enumerated values.
+*/
+typedef enum CFE_TIME_Compare
+{
+ CFE_TIME_A_LT_B = -1, /**< \brief The first specified time is considered to be before the second specified time */
+ CFE_TIME_EQUAL = 0, /**< \brief The two specified times are considered to be equal */
+ CFE_TIME_A_GT_B = 1 /**< \brief The first specified time is considered to be after the second specified time */
+} CFE_TIME_Compare_t;
+
+/**
+** \brief Time Synchronization Callback Function Ptr Type
+**
+** \par Description
+** Applications that wish to get direct notification of the receipt of the cFE Time Synchronization signal
+** (typically a 1 Hz signal), must register a callback function with the following prototype via the
+** #CFE_TIME_RegisterSynchCallback API.
+*/
+typedef int32 (*CFE_TIME_SynchCallbackPtr_t)(void);
+
+#endif /* CFE_TIME_API_TYPEDEFS_H */
diff --git a/modules/core_api/fsw/inc/cfe_time_core_internal.h b/modules/core_api/fsw/inc/cfe_time_core_internal.h
new file mode 100644
index 000000000..0c0fc5839
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_time_core_internal.h
@@ -0,0 +1,88 @@
+/*
+** 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 Time Services (TIME) library API header file
+ *
+ * Author: S.Walling/Microtel
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_TIME_CORE_INTERNAL_H
+#define CFE_TIME_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 CFEAPITIMECoreInternal cFE Internal Time APIs, internal to CFE core
+ * @{
+ */
+
+/*****************************************************************************/
+/**
+** \brief Entry Point for cFE Core Application
+**
+** \par Description
+** This is the entry point to the cFE TIME Core Application.
+**
+** \par Assumptions, External Events, and Notes:
+** None
+**
+******************************************************************************/
+extern void CFE_TIME_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_TIME_EarlyInit(void);
+
+/*****************************************************************************/
+/**
+** \brief Removes TIME resources associated with specified Application
+**
+** \par Description
+** This function is called by cFE Executive Services to cleanup after
+** an Application has been terminated. It frees resources
+** that have been allocated to the specified Application.
+**
+******************************************************************************/
+extern int32 CFE_TIME_CleanUpApp(CFE_ES_AppId_t AppId);
+
+/**@}*/
+
+#endif /* CFE_TIME_CORE_INTERNAL_H */
diff --git a/modules/core_api/fsw/inc/cfe_time_extern_typedefs.h b/modules/core_api/fsw/inc/cfe_time_extern_typedefs.h
new file mode 100644
index 000000000..7a2aeb126
--- /dev/null
+++ b/modules/core_api/fsw/inc/cfe_time_extern_typedefs.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
+ *
+ * Declarations and prototypes for cfe_time_extern_typedefs module
+ */
+
+#ifndef CFE_TIME_EXTERN_TYPEDEFS_H
+#define CFE_TIME_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_time_eds_typedefs.h"
+
+#else
+/* Use the local definitions of these types */
+
+#include "common_types.h"
+
+/**
+** \brief Data structure used to hold system time values
+**
+** \par Description
+** The #CFE_TIME_SysTime_t data structure is used to hold time
+** values. Time is referred to as the elapsed time (in seconds
+** and subseconds) since a specified epoch time. The subseconds
+** field contains the number of 2^(-32) second intervals that have
+** elapsed since the epoch.
+**
+*/
+typedef struct CFE_TIME_SysTime
+{
+ uint32 Seconds; /**< \brief Number of seconds since epoch */
+ uint32 Subseconds; /**< \brief Number of subseconds since epoch (LSB = 2^(-32) seconds) */
+} CFE_TIME_SysTime_t;
+
+/**
+ * @brief Label definitions associated with CFE_TIME_FlagBit_Enum_t
+ */
+enum CFE_TIME_FlagBit
+{
+
+ /**
+ * @brief The spacecraft time has been set
+ */
+ CFE_TIME_FlagBit_CLKSET = 0,
+
+ /**
+ * @brief This instance of Time Services is flywheeling
+ */
+ CFE_TIME_FlagBit_FLYING = 1,
+
+ /**
+ * @brief The clock source is set to internal
+ */
+ CFE_TIME_FlagBit_SRCINT = 2,
+
+ /**
+ * @brief The clock signal is set to primary
+ */
+ CFE_TIME_FlagBit_SIGPRI = 3,
+
+ /**
+ * @brief The Time Server is in flywheel mode
+ */
+ CFE_TIME_FlagBit_SRVFLY = 4,
+
+ /**
+ * @brief This instance of Time Services was commanded into flywheel mode
+ */
+ CFE_TIME_FlagBit_CMDFLY = 5,
+
+ /**
+ * @brief One time STCF Adjustment is to be done in positive direction
+ */
+ CFE_TIME_FlagBit_ADDADJ = 6,
+
+ /**
+ * @brief 1 Hz STCF Adjustment is to be done in a positive direction
+ */
+ CFE_TIME_FlagBit_ADD1HZ = 7,
+
+ /**
+ * @brief Time Client Latency is applied in a positive direction
+ */
+ CFE_TIME_FlagBit_ADDTCL = 8,
+
+ /**
+ * @brief This instance of Time Services is a Time Server
+ */
+ CFE_TIME_FlagBit_SERVER = 9,
+
+ /**
+ * @brief The tone received is good compared to the last tone received
+ */
+ CFE_TIME_FlagBit_GDTONE = 10
+};
+
+/**
+ * @brief Bit positions of the various clock state flags
+ *
+ * @sa enum CFE_TIME_FlagBit
+ */
+typedef uint8 CFE_TIME_FlagBit_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_TIME_ClockState_Enum_t
+ */
+enum CFE_TIME_ClockState
+{
+
+ /**
+ *
+ * The spacecraft time has not been set since the last clock
+ * reset. Times returned by clock routines have no relationship
+ * to any ground-based time reference.
+ *
+ */
+ CFE_TIME_ClockState_INVALID = -1,
+
+ /**
+ *
+ * The spacecraft time has been set at least once since the last
+ * clock reset, and it is synchronized with the primary on-board
+ * time base. Times returned by clock routines can be trusted.
+ *
+ */
+ CFE_TIME_ClockState_VALID = 0,
+
+ /**
+ *
+ * The spacecraft time has been set at least once since the last
+ * clock reset, but it is not currently synchronized with the
+ * primary on-board time base. Times returned by clock routines
+ * are a "best guess" based on a non-optimal oscillator.
+ *
+ */
+ CFE_TIME_ClockState_FLYWHEEL = 1
+};
+
+/**
+ * @brief Enumerated types identifying the quality of the current time
+ *
+ * \par Description
+ * The #CFE_TIME_ClockState_Enum_t enumerations identify the three recognized states of the current time.
+ * If the clock has never been successfully synchronized with the primary onboard clock source, the
+ * time is conisdered to be #CFE_TIME_ClockState_INVALID. If the time is currently synchronized (i.e. - the
+ * primary synchronization mechanism has not been dropped for any significant amount of time), then
+ * the current time is considered to be #CFE_TIME_ClockState_VALID. If the time had, at some point in the past,
+ * been synchronized, but the synchronization with the primary onboard clock has since been lost, then
+ * the time is considered to be #CFE_TIME_ClockState_FLYWHEEL. Since different clocks drift at different rates
+ * from one another, the accuracy of the time while in #CFE_TIME_ClockState_FLYWHEEL is dependent upon the time
+ * spent in that state.
+ *
+ * @sa enum CFE_TIME_ClockState
+ */
+typedef int16 CFE_TIME_ClockState_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_TIME_SourceSelect_Enum_t
+ */
+enum CFE_TIME_SourceSelect
+{
+
+ /**
+ * @brief Use Internal Source
+ */
+ CFE_TIME_SourceSelect_INTERNAL = 1,
+
+ /**
+ * @brief Use External Source
+ */
+ CFE_TIME_SourceSelect_EXTERNAL = 2
+};
+
+/**
+ * @brief Clock Source Selection Parameters
+ *
+ * @sa enum CFE_TIME_SourceSelect
+ */
+typedef uint8 CFE_TIME_SourceSelect_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_TIME_ToneSignalSelect_Enum_t
+ */
+enum CFE_TIME_ToneSignalSelect
+{
+
+ /**
+ * @brief Primary Source
+ */
+ CFE_TIME_ToneSignalSelect_PRIMARY = 1,
+
+ /**
+ * @brief Redundant Source
+ */
+ CFE_TIME_ToneSignalSelect_REDUNDANT = 2
+};
+
+/**
+ * @brief Tone Signal Selection Parameters
+ *
+ * @sa enum CFE_TIME_ToneSignalSelect
+ */
+typedef uint8 CFE_TIME_ToneSignalSelect_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_TIME_AdjustDirection_Enum_t
+ */
+enum CFE_TIME_AdjustDirection
+{
+
+ /**
+ * @brief Add time adjustment
+ */
+ CFE_TIME_AdjustDirection_ADD = 1,
+
+ /**
+ * @brief Subtract time adjustment
+ */
+ CFE_TIME_AdjustDirection_SUBTRACT = 2
+};
+
+/**
+ * @brief STCF adjustment direction (for both one-time and 1Hz adjustments)
+ *
+ * @sa enum CFE_TIME_AdjustDirection
+ */
+typedef uint8 CFE_TIME_AdjustDirection_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_TIME_FlywheelState_Enum_t
+ */
+enum CFE_TIME_FlywheelState
+{
+
+ /**
+ * @brief Not in flywheel state
+ */
+ CFE_TIME_FlywheelState_NO_FLY = 0,
+
+ /**
+ * @brief In flywheel state
+ */
+ CFE_TIME_FlywheelState_IS_FLY = 1
+};
+
+/**
+ * @brief Fly-wheel status values
+ *
+ * @sa enum CFE_TIME_FlywheelState
+ */
+typedef uint8 CFE_TIME_FlywheelState_Enum_t;
+
+/**
+ * @brief Label definitions associated with CFE_TIME_SetState_Enum_t
+ */
+enum CFE_TIME_SetState
+{
+
+ /**
+ * @brief Spacecraft time has not been set
+ */
+ CFE_TIME_SetState_NOT_SET = 0,
+
+ /**
+ * @brief Spacecraft time has been set
+ */
+ CFE_TIME_SetState_WAS_SET = 1
+};
+
+/**
+ * @brief Clock status values (has the clock been set to correct time)
+ *
+ * @sa enum CFE_TIME_SetState
+ */
+typedef uint8 CFE_TIME_SetState_Enum_t;
+
+#endif /* CFE_EDS_ENABLED_BUILD */
+
+#endif /* CFE_TIME_EXTERN_TYPEDEFS_H */
diff --git a/modules/core_private/fsw/inc/cfe_time_resetvars_typedef.h b/modules/core_private/fsw/inc/cfe_time_resetvars_typedef.h
new file mode 100644
index 000000000..6970b897b
--- /dev/null
+++ b/modules/core_private/fsw/inc/cfe_time_resetvars_typedef.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
+ *
+ * Definition of the CFE_TIME_ResetVars_t structure type
+ */
+
+#ifndef CFE_TIME_RESETVARS_TYPEDEF_H
+#define CFE_TIME_RESETVARS_TYPEDEF_H
+
+/*
+** Includes
+*/
+#include "common_types.h"
+#include "cfe_time_extern_typedefs.h"
+
+#define CFE_TIME_RESET_SIGNATURE 0xA5A55A5A
+
+/**
+** \brief Time related variables that are maintained through a Processor Reset
+**
+** \par Description
+** The #CFE_TIME_ResetVars_t data structure contains those variables that are maintained
+** in an area of memory that is not cleared during a Processor Reset. This allows the
+** cFE Time Service to maintain time to the best of its ability after a Processor Reset.
+*/
+typedef struct CFE_TIME_ResetVars
+{
+ uint32 Signature; /**< \brief Data validation signature used to verify data structure contents*/
+ int16 LeapSeconds; /**< \brief Leap seconds value */
+ uint16 ClockSignal; /**< \brief Current clock signal selection */
+ CFE_TIME_SysTime_t CurrentMET; /**< \brief Current Mission Elapsed Time (MET) */
+ CFE_TIME_SysTime_t CurrentSTCF; /**< \brief Current Spacecraft Time Correlation Factor (STCF) */
+ CFE_TIME_SysTime_t CurrentDelay; /**< \brief Current time client delay value */
+
+} CFE_TIME_ResetVars_t;
+
+#endif /* CFE_TIME_RESETVARS_TYPEDEF_H */
diff --git a/modules/time/CMakeLists.txt b/modules/time/CMakeLists.txt
new file mode 100644
index 000000000..2168ed154
--- /dev/null
+++ b/modules/time/CMakeLists.txt
@@ -0,0 +1,33 @@
+##################################################################
+#
+# cFE Time Services (TIME) module CMake build recipe
+#
+##################################################################
+
+project(CFE_TIME C)
+
+# Time Services source files
+set(time_SOURCES
+ fsw/src/cfe_time_api.c
+ fsw/src/cfe_time_task.c
+ fsw/src/cfe_time_tone.c
+ fsw/src/cfe_time_utils.c
+ fsw/src/cfe_time_api.c
+ fsw/src/cfe_time_task.c
+ fsw/src/cfe_time_tone.c
+ fsw/src/cfe_time_utils.c
+)
+add_library(time STATIC ${time_SOURCES})
+
+target_include_directories(time PUBLIC fsw/inc)
+target_link_libraries(time 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_time_events.h
+ cfe_time_msg.h
+)
diff --git a/modules/time/fsw/inc/cfe_time_events.h b/modules/time/fsw/inc/cfe_time_events.h
new file mode 100644
index 000000000..ae43e9b3b
--- /dev/null
+++ b/modules/time/fsw/inc/cfe_time_events.h
@@ -0,0 +1,622 @@
+/*
+** 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 Time Services (Time) Event IDs
+ *
+ * Design Notes:
+ *
+ * References:
+ * Flight Software Branch C Coding Standard Version 1.0a
+ *
+ */
+
+#ifndef CFE_TIME_EVENTS_H
+#define CFE_TIME_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_TIME_MAX_EID 49
+
+/*
+** Event message ID's...
+*/
+/** \brief 'cFE TIME Initialized'
+** \event 'cFE TIME Initialized'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is always automatically issued when the Time Services
+** Task completes its Initialization.
+**/
+#define CFE_TIME_INIT_EID 1 /* start up message "informational" */
+
+/** \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 Time Services \link #CFE_TIME_NOOP_CC NO-OP command \endlink
+**/
+#define CFE_TIME_NOOP_EID 4 /* processed command "informational" */
+
+/** \brief 'Reset Counters command'
+** \event 'Reset Counters command'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is always automatically issued in response
+** to a cFE Time Services \link #CFE_TIME_RESET_COUNTERS_CC Reset Counters command \endlink
+**/
+#define CFE_TIME_RESET_EID 5
+
+/** \brief 'Request diagnostics command'
+** \event 'Request diagnostics command'
+**
+** \par Type: DEBUG
+**
+** \par Cause:
+**
+** This event message is always automatically issued in response
+** to a cFE Time Services \link #CFE_TIME_SEND_DIAGNOSTIC_TLM_CC Request Diagnostics command \endlink
+**/
+#define CFE_TIME_DIAG_EID 6
+
+/** \brief 'Set Clock State = \%s'
+** \event 'Set Clock State = \%s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of a cFE Time Services \link #CFE_TIME_SET_STATE_CC Set Time State command \endlink
+**
+** The \c '\%s' field will identify whether the command specified
+** \c VALID, \c INVALID, or \c FLYWHEEL.
+**/
+#define CFE_TIME_STATE_EID 7
+
+/** \brief 'Set Time Source = \%s'
+** \event 'Set Time Source = \%s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of a cFE Time Services \link #CFE_TIME_SET_SOURCE_CC Set Time Source command \endlink
+**
+** The \c '\%s' field will identify whether the command specified
+** \c INTERNAL, or \c EXTERNAL.
+**/
+#define CFE_TIME_SOURCE_EID 8
+
+/** \brief 'Set Tone Source = \%s'
+** \event 'Set Tone Source = \%s'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of a cFE Time Services \link #CFE_TIME_SET_SIGNAL_CC Set Clock Signal command \endlink
+**
+** The \c '\%s' field will identify whether the command specified
+** \c PRIMARY, or \c REDUNDANT.
+**/
+#define CFE_TIME_SIGNAL_EID 9
+
+/** \brief 'Set Tone Delay -- secs = \%d, usecs = \%d, ssecs = 0x\%X, dir = \%d'
+** \event 'Set Tone Delay -- secs = \%d, usecs = \%d, ssecs = 0x\%X, dir = \%d'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of either a cFE Time Services
+** \link #CFE_TIME_ADD_DELAY_CC Add Time Delay \endlink OR a
+** \link #CFE_TIME_SUB_DELAY_CC Subtract Time Delay command \endlink
+**
+** The \c secs field specifies the new delay (in seconds), the \c usecs
+** field specifies the delay in micro-seconds, the \c ssecs field is
+** the micro-seconds field converted to Spacecraft Time sub-seconds and
+** the \c dir field identifies the direction of the delay. The direction
+** can be either #CFE_TIME_AdjustDirection_ADD or #CFE_TIME_AdjustDirection_SUBTRACT.
+**/
+#define CFE_TIME_DELAY_EID 11
+
+/** \brief 'Set Time -- secs = \%d, usecs = \%d, ssecs = 0x\%X'
+** \event 'Set Time -- secs = \%d, usecs = \%d, ssecs = 0x\%X'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of a cFE Time Services \link #CFE_TIME_SET_TIME_CC Set Time command \endlink
+**
+** The \c secs field specifies the new spacecraft time (in seconds), the \c usecs
+** field specifies the spacecraft time micro-seconds, the \c ssecs field is
+** the micro-seconds field converted to Spacecraft Time sub-seconds
+**/
+#define CFE_TIME_TIME_EID 12
+
+/** \brief 'Set MET -- secs = \%d, usecs = \%d, ssecs = 0x\%X'
+** \event 'Set MET -- secs = \%d, usecs = \%d, ssecs = 0x\%X'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of a cFE Time Services \link #CFE_TIME_SET_MET_CC Set Mission Elapsed Time command \endlink
+**
+** The \c secs field specifies the new MET (in seconds), the \c usecs
+** field specifies the MET micro-seconds, the \c ssecs field is
+** the micro-seconds field converted to Spacecraft Time sub-seconds
+**/
+#define CFE_TIME_MET_EID 13
+
+/** \brief 'Set STCF -- secs = \%d, usecs = \%d, ssecs = 0x\%X'
+** \event 'Set STCF -- secs = \%d, usecs = \%d, ssecs = 0x\%X'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of a cFE Time Services \link #CFE_TIME_SET_STCF_CC Set Spacecraft Time
+** Correlation Factor command \endlink
+**
+** The \c secs field specifies the new STCF (in seconds), the \c usecs
+** field specifies the STCF micro-seconds, the \c ssecs field is
+** the micro-seconds field converted to Spacecraft Time sub-seconds.
+**/
+#define CFE_TIME_STCF_EID 14
+
+/** \brief 'STCF Adjust -- secs = \%d, usecs = \%d, ssecs = 0x\%X, dir[1=Positive, 2=Negative] = \%d'
+** \event 'STCF Adjust -- secs = \%d, usecs = \%d, ssecs = 0x\%X, dir[1=Positive, 2=Negative] = \%d'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of any of the following cFE Time Services STCF Adjustment Commands:
+** - \link #CFE_TIME_ADD_ADJUST_CC Add Single STCF Adjustment command \endlink
+** - \link #CFE_TIME_SUB_ADJUST_CC Subtract Single STCF Adjustment command \endlink
+**
+** The \c secs field specifies the number of seconds the STCF is to be adjusted by,
+** the \c usecs field specifies the number of micro-seconds, the \c ssecs field is
+** the micro-seconds field converted to Spacecraft Time sub-seconds and the \c dir
+** field identifies whether the adjustment was added or subtracted. The direction
+** can be either #CFE_TIME_AdjustDirection_ADD or #CFE_TIME_AdjustDirection_SUBTRACT.
+**/
+#define CFE_TIME_DELTA_EID 15
+
+/** \brief 'STCF 1Hz Adjust -- secs = \%d, ssecs = 0x\%X, dir = \%d'
+** \event 'STCF 1Hz Adjust -- secs = \%d, ssecs = 0x\%X, dir = \%d'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of any of the following cFE Time Services STCF Adjustment Commands:
+** - \link #CFE_TIME_ADD_1HZ_ADJUSTMENT_CC Add STCF Adjustment each second command \endlink
+** - \link #CFE_TIME_SUB_1HZ_ADJUSTMENT_CC Subtract STCF Adjustment each second command \endlink
+**
+** The \c secs field specifies the number of seconds the STCF is to be adjusted by,
+** the \c ssecs field specifies the number of sub-seconds (1/2^32 seconds) the STCF
+** is to be adjusted by and the \c dir field identifies whether the adjustment was
+** added or subtracted. The direction value can be either #CFE_TIME_AdjustDirection_ADD or
+** #CFE_TIME_AdjustDirection_SUBTRACT.
+**/
+#define CFE_TIME_1HZ_EID 16
+
+/** \brief 'Set Leap Seconds = \%d'
+** \event 'Set Leap Seconds = \%d'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated upon successful completion
+** of the \link #CFE_TIME_SET_LEAP_SECONDS_CC Set Leap Seconds command \endlink
+**
+** The \c \%d field contains the number of seconds the Spacecraft's Leap Seconds
+** has been set to.
+**/
+#define CFE_TIME_LEAPS_EID 17
+
+/** \brief 'Start FLYWHEEL'
+** \event 'Start FLYWHEEL'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated whenever the Time Services enters FLYWHEEL mode.
+**/
+#define CFE_TIME_FLY_ON_EID 20 /* flywheel state "informational" */
+
+/** \brief 'Stop FLYWHEEL'
+** \event 'Stop FLYWHEEL'
+**
+** \par Type: INFORMATION
+**
+** \par Cause:
+**
+** This event message is generated whenever the Time Services exits FLYWHEEL mode.
+**/
+#define CFE_TIME_FLY_OFF_EID 21
+
+#define CFE_TIME_EXIT_ERR_EID 25 /* task termination "error" */
+
+/** \brief 'Invalid message ID -- ID = 0x\%X'
+** \event 'Invalid message ID -- ID = 0x\%X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a message from the software bus that is not one of Time Services
+** recognized messages.
+**
+** The \c ID field specifies, in hex, the message ID of the inappropriately
+** received message.
+**/
+#define CFE_TIME_ID_ERR_EID 26 /* invalid command packet "error" */
+
+/** \brief 'Invalid command code -- ID = 0x\%X, CC = \%d'
+** \event 'Invalid command code -- ID = 0x\%X, CC = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a message from the software bus that contains a unrecognized command
+** code in its header..
+**
+** The \c ID field specifies, in hex, the message ID of the message containing
+** the unrecognized command code, identified, in decimal, by the \c CC field.
+**/
+#define CFE_TIME_CC_ERR_EID 27
+
+/** \brief 'Invalid Clock State = 0x\%X'
+** \event 'Invalid Clock State = 0x\%X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_STATE_CC Set Clock State Command \endlink
+** that contains a desired clock state that is none of the following:
+** - #CFE_TIME_ClockState_INVALID
+** - #CFE_TIME_ClockState_VALID
+** - #CFE_TIME_ClockState_FLYWHEEL
+**
+** The \c State field specifies, in hex, the state value received
+** in the command message.
+**/
+#define CFE_TIME_STATE_ERR_EID 30 /* processed command "error" */
+
+/** \brief 'Invalid Time Source = 0x\%X'
+** \event 'Invalid Time Source = 0x\%X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_SOURCE_CC Set Clock Source Command \endlink
+** that contains a desired clock source that is none of the following:
+** - #CFE_TIME_SourceSelect_INTERNAL
+** - #CFE_TIME_SourceSelect_EXTERNAL
+**
+** The \c Source field specifies, in hex, the source value received
+** in the command message.
+**/
+#define CFE_TIME_SOURCE_ERR_EID 31
+
+/** \brief 'Invalid Tone Source = 0x\%X'
+** \event 'Invalid Tone Source = 0x\%X'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_SIGNAL_CC Set Clock Signal Command \endlink
+** that contains a desired clock source that is none of the following:
+** - #CFE_TIME_ToneSignalSelect_PRIMARY
+** - #CFE_TIME_ToneSignalSelect_REDUNDANT
+**
+** The \c Source field specifies, in hex, the signal source value received
+** in the command message.
+**/
+#define CFE_TIME_SIGNAL_ERR_EID 32
+
+/** \brief 'Invalid Tone Delay -- secs = \%d, usecs = \%d'
+** \event 'Invalid Tone Delay -- secs = \%d, usecs = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** either a \link #CFE_TIME_ADD_DELAY_CC Add Tone Delay Command \endlink
+** OR a \link #CFE_TIME_SUB_DELAY_CC Subtract Tone Delay Command \endlink
+** that contains a microsecond field that is greater than or equal to
+** 1000000.
+**
+** The \c secs field specifies, in decimal, the tone signal delay in seconds
+** and the \c usecs field specifies, in decimal, the micro-second delay that
+** was in error.
+**/
+#define CFE_TIME_DELAY_ERR_EID 33
+
+/** \brief 'Invalid Time -- secs = \%d, usecs = \%d'
+** \event 'Invalid Time -- secs = \%d, usecs = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_TIME_CC Set Spacecraft Time Command \endlink
+** that contains a microsecond field that is greater than or equal to
+** 1,000,000.
+**
+** The \c secs field specifies, in decimal, the spacecraft time in seconds
+** and the \c usecs field specifies, in decimal, the micro-second field of
+** the spacecraft time that was in error.
+**/
+#define CFE_TIME_TIME_ERR_EID 34
+
+/** \brief 'Invalid MET -- secs = \%d, usecs = \%d'
+** \event 'Invalid MET -- secs = \%d, usecs = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_MET_CC Set Mission Elapsed Time Command \endlink
+** that contains a microsecond field that is greater than or equal to
+** 1,000,000.
+**
+** The \c secs field specifies, in decimal, the MET in seconds
+** and the \c usecs field specifies, in decimal, the micro-second field of
+** the MET that was in error.
+**/
+#define CFE_TIME_MET_ERR_EID 35
+
+/** \brief 'Invalid STCF -- secs = \%d, usecs = \%d'
+** \event 'Invalid STCF -- secs = \%d, usecs = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_STCF_CC Set Spacecraft Time Correlation Factor Command \endlink
+** that contains a microsecond field that is greater than or equal to
+** 1,000,000.
+**
+** The \c secs field specifies, in decimal, the STCF in seconds
+** and the \c usecs field specifies, in decimal, the micro-second field of
+** the STCF that was in error.
+**/
+#define CFE_TIME_STCF_ERR_EID 36
+
+/** \brief 'Invalid STCF Adjust -- secs = \%d, usecs = \%d, dir[1=Positive, 2=Negative] = \%d'
+** \event 'Invalid STCF Adjust -- secs = \%d, usecs = \%d, dir[1=Positive, 2=Negative] = \%d'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** either a \link #CFE_TIME_ADD_ADJUST_CC Add Single STCF Adjustment Command \endlink
+** OR a \link #CFE_TIME_SUB_ADJUST_CC Subtract Single STCF Adjustment command \endlink
+** that contains a microsecond field that is greater than or equal to
+** 1,000,000.
+**
+** The \c secs field specifies the number of seconds the STCF is to be adjusted by,
+** the \c usecs field specifies the number of micro-seconds that was in error, the \c dir
+** field identifies whether the adjustment was to be added or subtracted. The direction
+** can be either #CFE_TIME_AdjustDirection_ADD or #CFE_TIME_AdjustDirection_SUBTRACT.
+**/
+#define CFE_TIME_DELTA_ERR_EID 37
+
+/** (obsolete - unused)
+ **/
+#define CFE_TIME_1HZ_ERR_EID 38
+
+/** \brief 'Set Source commands invalid without CFE_PLATFORM_TIME_CFG_SOURCE set to true'
+** \event 'Set Source commands invalid without CFE_PLATFORM_TIME_CFG_SOURCE set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_SOURCE_CC Set Clock Source Command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SOURCE has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_SOURCE_CFG_EID 40 /* cmd disabled per cfg "error" */
+
+/** \brief 'Set Signal commands invalid without CFE_PLATFORM_TIME_CFG_SIGNAL set to true'
+** \event 'Set Signal commands invalid without CFE_PLATFORM_TIME_CFG_SIGNAL set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_SIGNAL_CC Set Clock Signal Command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SIGNAL has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_SIGNAL_CFG_EID 41
+
+/** \brief 'Set Delay commands invalid without CFE_PLATFORM_TIME_CFG_CLIENT set to true'
+** \event 'Set Delay commands invalid without CFE_PLATFORM_TIME_CFG_CLIENT set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** either a \link #CFE_TIME_ADD_DELAY_CC Add Tone Delay Command \endlink
+** OR a \link #CFE_TIME_SUB_DELAY_CC Subtract Tone Delay Command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_CLIENT has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_DELAY_CFG_EID 42
+
+/** \brief 'Set Time commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+** \event 'Set Time commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_TIME_CC Set Spacecraft Time Command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SERVER has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_TIME_CFG_EID 43
+
+/** \brief 'Set MET commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+** \event 'Set MET commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_MET_CC Set Mission Elapsed Time Command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SERVER has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_MET_CFG_EID 44
+
+/** \brief 'Set STCF commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+** \event 'Set STCF commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_STCF_CC Set Spacecraft Time Correlation Factor Command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SERVER has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_STCF_CFG_EID 45
+
+/** \brief 'Set Leaps commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+** \event 'Set Leaps commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** a \link #CFE_TIME_SET_LEAP_SECONDS_CC Set Leap Seconds Command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SERVER has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_LEAPS_CFG_EID 46
+
+/** \brief 'STCF Adjust commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+** \event 'STCF Adjust commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** either a \link #CFE_TIME_ADD_ADJUST_CC Add Single STCF Adjustment Command \endlink
+** OR a \link #CFE_TIME_SUB_ADJUST_CC Subtract Single STCF Adjustment command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SERVER has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_DELTA_CFG_EID 47
+
+/** \brief '1Hz Adjust commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+** \event '1Hz Adjust commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to true'
+**
+** \par Type: ERROR
+**
+** \par Cause:
+**
+** This event message is generated whenever Time Services receives
+** either a \link #CFE_TIME_ADD_1HZ_ADJUSTMENT_CC Add STCF Adjustment each second Command \endlink
+** OR a \link #CFE_TIME_SUB_1HZ_ADJUSTMENT_CC Subtract STCF Adjustment each second command \endlink
+** and the Time Services configuration parameter #CFE_PLATFORM_TIME_CFG_SERVER has
+** not been set to true in the cfe_platform_cfg.h file.
+**/
+#define CFE_TIME_1HZ_CFG_EID 48
+
+/** \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_TIME_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_TIME_LEN_ERR_EID 49
+
+#endif /* CFE_TIME_EVENTS_H */
diff --git a/modules/time/fsw/inc/cfe_time_msg.h b/modules/time/fsw/inc/cfe_time_msg.h
new file mode 100644
index 000000000..9aad58e12
--- /dev/null
+++ b/modules/time/fsw/inc/cfe_time_msg.h
@@ -0,0 +1,1126 @@
+/*
+** 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 Time Services (TIME) SB message definitions header file
+ *
+ * Author: S.Walling/Microtel
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_TIME_MSG_H
+#define CFE_TIME_MSG_H
+
+/*
+** Required header files...
+*/
+#include "common_types.h" /* Basic data types */
+#include "cfe_msg_hdr.h" /* for header definitions */
+#include "cfe_time_extern_typedefs.h"
+
+/*************************************************************************/
+
+/*
+** Time task command packet command codes...
+*/
+/** \name Time Services Command Codes */
+/** \{ */
+
+/** \cfetimecmd Time 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 Time Services task.
+**
+** \cfecmdmnemonic \TIME_NOOP
+**
+** \par Command Structure
+** #CFE_TIME_NoopCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - The #CFE_TIME_NOOP_EID informational event message will be generated
+**
+** \par Error Conditions
+** There are no error conditions for this command. If the Time
+** Services receives the command, the event is sent (although it
+** may be filtered by EVS) and the counter is incremented
+** unconditionally.
+**
+** \par Criticality
+** None
+**
+** \sa
+*/
+#define CFE_TIME_NOOP_CC 0 /* no-op command */
+
+/** \cfetimecmd Time Reset Counters
+**
+** \par Description
+** This command resets the following counters within the Time
+** Services \link CFE_TIME_HousekeepingTlm_t Housekeeping Telemetry \endlink:
+** - Command Execution Counter (\TIME_CMDPC)
+** - Command Error Counter (\TIME_CMDEC)
+** This command also resets the following counters within the
+** Time Services \link CFE_TIME_DiagnosticTlm_t Diagnostic Telemetry \endlink:
+** - Tone Signal Detected Software Bus Message Counter (\TIME_TSDETCNT)
+** - Time at the Tone Data Software Bus Message Counter (\TIME_TATTCNT)
+** - Tone Signal/Data Verify Counter (\TIME_VERIFYCNT)
+** - Tone Signal/Data Error Counter (\TIME_VERIFYER)
+** - Tone Signal Interrupt Counter (\TIME_TSISRCNT)
+** - Tone Signal Interrupt Error Counter (\TIME_TSISRERR)
+** - Tone Signal Task Counter (\TIME_TSTASKCNT)
+** - Local 1 Hz Interrupt Counter (\TIME_1HZISRCNT)
+** - Local 1 Hz Task Counter (\TIME_1HZTASKCNT)
+** - Reference Time Version Counter (\TIME_VERSIONCNT)
+**
+** \cfecmdmnemonic \TIME_RESETCTRS
+**
+** \par Command Structure
+** #CFE_TIME_ResetCountersCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - The #CFE_TIME_RESET_EID informational event message will be generated
+**
+** \par Error Conditions
+** There are no error conditions for this command. If the Time
+** Services receives the command, the event is sent (although it
+** may be filtered by EVS) and the counter is incremented
+** unconditionally.
+**
+** \par Criticality
+** None
+**
+** \sa
+*/
+#define CFE_TIME_RESET_COUNTERS_CC 1 /* reset counters */
+
+/** \cfetimecmd Request TIME Diagnostic Telemetry
+**
+** \par Description
+** This command requests that the Time Service generate a message
+** containing various data values not included in the normal Time
+** Service housekeeping message. The command requests only a single
+** copy of the diagnostic message. Refer to #CFE_TIME_DiagnosticTlm_t for
+** a description of the Time Service diagnostic message contents.
+**
+** \cfecmdmnemonic \TIME_REQUESTDIAG
+**
+** \par Command Structure
+** #CFE_TIME_SendDiagnosticCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - Sequence Counter for #CFE_TIME_DiagnosticTlm_t will increment
+** - The #CFE_TIME_DIAG_EID debug event message will be generated
+**
+** \par Error Conditions
+** There are no error conditions for this command. If the Time
+** Services receives the command, the event and telemetry is sent
+** (although one or both may be filtered by EVS and TO) and the
+** counter is incremented unconditionally.
+**
+** \par Criticality
+** None
+**
+** \sa
+*/
+#define CFE_TIME_SEND_DIAGNOSTIC_TLM_CC 2 /* request diagnostic hk telemetry */
+
+/** \cfetimecmd Set Time Source
+**
+** \par Description
+** This command selects the Time Service clock source. Although the
+** list of potential clock sources is mission specific and defined
+** via configuration parameters, this command provides a common method
+** for switching between the local processor clock and an external
+** source for time data.
+** When commanded to accept external time data (GPS, MET, spacecraft
+** time, etc.), the Time Server will enable input via an API function
+** specific to the configuration definitions for the particular source.
+** When commanded to use internal time data, the Time Server will ignore
+** the external data. However, the Time Server will continue to use the
+** API function as the trigger to generate a "time at the tone" command
+** packet regardless of the internal/external command selection.
+** Notes:
+** - Operating in FLYWHEEL mode is not considered a choice related
+** to clock source, but rather an element of the clock state. See below
+** for a description of the #CFE_TIME_SET_STATE_CC command.
+** - This command is only valid when the #CFE_PLATFORM_TIME_CFG_SOURCE configuration
+** parameter in the cfe_platform_cfg.h file has been set to true.
+**
+** \cfecmdmnemonic \TIME_SETSOURCE
+**
+** \par Command Structure
+** #CFE_TIME_SetSourceCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_SOURCE - Diagnostic Telemetry point will indicate the
+** command specified value
+** - The #CFE_TIME_SOURCE_EID informational event message will be generated
+**
+** \par Error Conditions
+** - Invalid Source selection
+** (a value other than #CFE_TIME_SourceSelect_INTERNAL or #CFE_TIME_SourceSelect_EXTERNAL was specified)
+** - Time source selection not allowed on this platform
+**
Evidence of failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - Command Error counter will increment
+** - Error specific event message (either #CFE_TIME_SOURCE_CFG_EID or #CFE_TIME_SOURCE_ERR_EID)
+**
+** \par Criticality
+** Although clock source selection is important, this command is not critical.
+**
+** \sa #CFE_TIME_SET_STATE_CC, #CFE_TIME_SET_SIGNAL_CC
+*/
+#define CFE_TIME_SET_SOURCE_CC 3 /* set clock source (int vs ext) */
+
+/** \cfetimecmd Set Time State
+**
+** \par Description
+** This command indirectly affects the Time Service on-board determination
+** of clock state. Clock state is a combination of factors, most significantly
+** whether the spacecraft time has been accurately set, and whether Time Service
+** is operating in FLYWHEEL mode.
+** This command may be used to notify the Time Server that spacecraft time is
+** now correct, or that time is no longer correct. This information will be
+** distributed to Time Clients, and in turn, to any interested sub-systems.
+** Also, this command may be used to force a Time Server or Time Client into
+** FLYWHEEL mode. Use of FLYWHEEL mode is mainly for debug purposes although
+** in extreme circumstances, it may be of value to force Time Service not to rely
+** on normal time updates. Note that when commanded into FLYWHEEL mode, the Time
+** Service will remain so until receipt of another "set state" command setting the
+** state into a mode other than FLYWHEEL.
+** Note also that setting the clock state to VALID or INVALID on a Time Client that
+** is currently getting time updates from the Time Server will have very limited
+** effect. As soon as the Time Client receives the next time update, the VALID/INVALID
+** selection will be set to that of the Time Server. However, setting a Time Client
+** to FLYWHEEL cannot be overridden by the Time Server since the Time Client will
+** ignore time updates from the Time Server while in FLYWHEEL mode.
+**
+** \cfecmdmnemonic \TIME_SETSTATE
+**
+** \par Command Structure
+** #CFE_TIME_SetStateCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_STATEFLG - Housekeeping Telemetry point "may"l indicate the
+** command specified value (see above)
+** - The #CFE_TIME_STATE_EID informational event message will be generated
+**
+** \par Error Conditions
+** - Invalid State selection
+** (a value other than #CFE_TIME_ClockState_INVALID, #CFE_TIME_ClockState_VALID or
+** #CFE_TIME_ClockState_FLYWHEEL was specified)
+** - Time source selection not allowed on this platform
+**
Evidence of failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - Command Error counter will increment
+** - Error specific event message (#CFE_TIME_STATE_ERR_EID)
+**
+** \par Criticality
+** Setting Time Service into FLYWHEEL mode is not particularly hazardous, as
+** the result may be that the calculation of spacecraft time is done using a
+** less than optimal timer. However, inappropriately setting the clock state
+** to VALID (indicating that spacecraft time is accurate) may result in other
+** sub-systems performing incorrect time based calculations. The specific risk
+** is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_SET_SOURCE_CC, #CFE_TIME_SET_SIGNAL_CC
+*/
+#define CFE_TIME_SET_STATE_CC 4 /* set clock state */
+
+/** \cfetimecmd Add Time to Tone Time Delay
+**
+** \par Description
+** This command is used to factor out a known, predictable latency between the
+** Time Server and a particular Time Client. The correction is applied (added)
+** to the current time calculation for Time Clients, so this command has no
+** meaning for Time Servers. Each Time Client can have a unique latency setting.
+** The latency value is a positive number of seconds and microseconds that represent
+** the deviation from the time maintained by the Time Server.
+**
+** \cfecmdmnemonic \TIME_ADDCLOCKLAT
+**
+** \par Command Structure
+** #CFE_TIME_AddDelayCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_LATENTS - Housekeeping Telemetry point indicating command specified values
+** - \b \c \TIME_LATENTDIR - Diagnostic Telemetry point indicating commanded latency direction
+** - The #CFE_TIME_DELAY_EID informational event message will be generated
+**
+** \par Error Conditions
+** - An invalid number of microseconds was specified (must be less than 1 million)
+** - Platorm receiving the command is not a Time Client
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_DELAY_CFG_EID or #CFE_TIME_DELAY_ERR_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_SUB_DELAY_CC
+*/
+#define CFE_TIME_ADD_DELAY_CC 5 /* add tone delay value */
+
+/** \cfetimecmd Subtract Time from Tone Time Delay
+**
+** \par Description
+** This command is used to factor out a known, predictable latency between the Time Server
+** and a particular Time Client. The correction is applied (subtracted) to the current time
+** calculation for Time Clients, so this command has no meaning for Time Servers. Each Time
+** Client can have a unique latency setting. The latency value is a positive number of seconds
+** and microseconds that represent the deviation from the time maintained by the Time Server.
+** Note that it is unimaginable that the seconds value will ever be anything but zero.
+**
+** \cfecmdmnemonic \TIME_SUBCLOCKLAT
+**
+** \par Command Structure
+** #CFE_TIME_SubDelayCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_LATENTS - Housekeeping Telemetry point indicating command specified values
+** - \b \c \TIME_LATENTDIR - Diagnostic Telemetry point indicating commanded latency direction
+** - The #CFE_TIME_DELAY_EID informational event message will be generated
+**
+** \par Error Conditions
+** - An invalid number of microseconds was specified (must be less than 1 million)
+** - Platorm receiving the command is not a Time Client
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_DELAY_CFG_EID or #CFE_TIME_DELAY_ERR_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_ADD_DELAY_CC
+*/
+#define CFE_TIME_SUB_DELAY_CC 6 /* sub tone delay value */
+
+/** \cfetimecmd Set Spacecraft Time
+**
+** \par Description
+** This command sets the spacecraft clock to a new value,
+** regardless of the current setting (time jam). The new time
+** value represents the desired offset from the mission-defined
+** time epoch and takes effect immediately upon execution of
+** this command. Time Service will calculate a new STCF value
+** based on the current MET and the desired new time using one
+** of the following:
+** If Time Service is configured to compute current time as TAI
+** - STCF = (new time) - (current MET)
+** - (current time) = (current MET) + STCF
+**
If Time Service is configured to compute current time as UTC
+** - STCF = ((new time) - (current MET)) + (Leap Seconds)
+** - (current time) = ((curent MET) + STCF) - (Leap Seconds)
+**
+** \cfecmdmnemonic \TIME_SETCLOCK
+**
+** \par Command Structure
+** #CFE_TIME_SetTimeCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_STCFSECS - Housekeeping Telemetry point indicating newly calculated STCF seconds value
+** - \b \c \TIME_STCFSUBSECS - Housekeeping Telemetry point indicating newly calculated STCF subseconds value
+** - The #CFE_TIME_TIME_EID informational event message will be generated
+**
+** \par Error Conditions
+** - An invalid number of microseconds was specified (must be less than 1 million)
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_TIME_CFG_EID or #CFE_TIME_TIME_ERR_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_SET_MET_CC, #CFE_TIME_SET_STCF_CC, #CFE_TIME_SET_LEAP_SECONDS_CC
+*/
+#define CFE_TIME_SET_TIME_CC 7 /* set time */
+
+/** \cfetimecmd Set Mission Elapsed Time
+**
+** \par Description
+** This command sets the Mission Elapsed Timer (MET) to the specified value.
+** Note that the MET (as implemented for cFE Time Service) is a logical representation
+** and not a physical timer. Thus, setting the MET is not dependent on whether the
+** hardware supports a MET register that can be written to.
+** Note also that Time Service "assumes" that during normal operation, the MET is
+** synchronized to the tone signal. Therefore, unless operating in FLYWHEEL mode,
+** the sub-seconds portion of the MET will be set to zero at the next tone signal interrupt.
+** The new MET takes effect immediately upon execution of this command.
+**
+** \cfecmdmnemonic \TIME_SETCLOCKMET
+**
+** \par Command Structure
+** #CFE_TIME_SetMETCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_METSECS - Housekeeping Telemetry point indicating new MET seconds value
+** - \b \c \TIME_METSUBSECS - Housekeeping Telemetry point indicating new MET subseconds value
+** - The #CFE_TIME_MET_EID informational event message will be generated
+**
+** \par Error Conditions
+** - An invalid number of microseconds was specified (must be less than 1 million)
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_MET_CFG_EID or #CFE_TIME_MET_ERR_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_SET_TIME_CC, #CFE_TIME_SET_STCF_CC, #CFE_TIME_SET_LEAP_SECONDS_CC
+*/
+#define CFE_TIME_SET_MET_CC 8 /* set MET */
+
+/** \cfetimecmd Set Spacecraft Time Correlation Factor
+**
+** \par Description
+** This command sets the Spacecraft Time Correlation Factor (STCF) to the specified value.
+** This command differs from the previously described SET CLOCK in the nature of the command
+** argument. This command sets the STCF value directly, rather than extracting the STCF
+** from a value representing the total of MET, STCF and optionally, Leap Seconds. The new
+** STCF takes effect immediately upon execution of this command.
+**
+** \cfecmdmnemonic \TIME_SETCLOCKSTCF
+**
+** \par Command Structure
+** #CFE_TIME_SetSTCFCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_STCFSECS - Housekeeping Telemetry point indicating new STCF seconds value
+** - \b \c \TIME_STCFSUBSECS - Housekeeping Telemetry point indicating new STCF subseconds value
+** - The #CFE_TIME_STCF_EID informational event message will be generated
+**
+** \par Error Conditions
+** - An invalid number of microseconds was specified (must be less than 1 million)
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_STCF_CFG_EID or #CFE_TIME_STCF_ERR_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_SET_TIME_CC, #CFE_TIME_SET_MET_CC, #CFE_TIME_SET_LEAP_SECONDS_CC
+*/
+#define CFE_TIME_SET_STCF_CC 9 /* set STCF */
+
+/** \cfetimecmd Set Leap Seconds
+**
+** \par Description
+** This command sets the spacecraft Leap Seconds to the specified value.
+** Leap Seconds may be positive or negative, and there is no limit to the
+** value except, of course, the limit imposed by the 16 bit signed integer
+** data type. The new Leap Seconds value takes effect immediately upon
+** execution of this command.
+**
+** \cfecmdmnemonic \TIME_SETCLOCKLEAP
+**
+** \par Command Structure
+** #CFE_TIME_SetLeapSecondsCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_LEAPSECS - Housekeeping Telemetry point indicating new Leap seconds value
+** - The #CFE_TIME_LEAPS_EID informational event message will be generated
+**
+** \par Error Conditions
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_LEAPS_CFG_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_SET_TIME_CC, #CFE_TIME_SET_MET_CC, #CFE_TIME_SET_STCF_CC
+*/
+#define CFE_TIME_SET_LEAP_SECONDS_CC 10 /* set Leap Seconds */
+
+/** \cfetimecmd Add Delta to Spacecraft Time Correlation Factor
+**
+** \par Description
+** This command adjusts the Spacecraft Time Correlation Factor (STCF) by
+** adding the specified value. The new STCF takes effect immediately upon
+** execution of this command.
+**
+** \cfecmdmnemonic \TIME_ADDSTCFADJ
+**
+** \par Command Structure
+** #CFE_TIME_AddAdjustCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_STCFSECS - Housekeeping Telemetry point indicating new STCF seconds value
+** - \b \c \TIME_STCFSUBSECS - Housekeeping Telemetry point indicating new STCF subseconds value
+** - The #CFE_TIME_DELTA_EID informational event message will be generated
+**
+** \par Error Conditions
+** - An invalid number of microseconds was specified (must be less than 1 million)
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_DELTA_ERR_EID or #CFE_TIME_DELTA_CFG_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_ADD_ADJUST_CC, #CFE_TIME_SUB_ADJUST_CC, #CFE_TIME_ADD_1HZ_ADJUSTMENT_CC,
+*#CFE_TIME_SUB_1HZ_ADJUSTMENT_CC
+*/
+#define CFE_TIME_ADD_ADJUST_CC 11 /* add one time STCF adjustment */
+
+/** \cfetimecmd Subtract Delta from Spacecraft Time Correlation Factor
+**
+** \par Description
+** This command adjusts the Spacecraft Time Correlation Factor (STCF) by subtracting the specified
+** value. The new STCF takes effect immediately upon execution of this command.
+**
+** \cfecmdmnemonic \TIME_SUBSTCFADJ
+**
+** \par Command Structure
+** #CFE_TIME_SubAdjustCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_STCFSECS - Housekeeping Telemetry point indicating new STCF seconds value
+** - \b \c \TIME_STCFSUBSECS - Housekeeping Telemetry point indicating new STCF subseconds value
+** - The #CFE_TIME_DELTA_EID informational event message will be generated
+**
+** \par Error Conditions
+** - An invalid number of microseconds was specified (must be less than 1 million)
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event messages will be issued (#CFE_TIME_DELTA_ERR_EID or #CFE_TIME_DELTA_CFG_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_ADD_ADJUST_CC, #CFE_TIME_ADD_1HZ_ADJUSTMENT_CC, #CFE_TIME_SUB_1HZ_ADJUSTMENT_CC
+*/
+#define CFE_TIME_SUB_ADJUST_CC 12 /* subtract one time STCF adjustment */
+
+/** \cfetimecmd Add Delta to Spacecraft Time Correlation Factor each 1Hz
+**
+** \par Description
+** This command has been updated to take actual sub-seconds (1/2^32 seconds)
+** rather than micro-seconds as an input argument. This change occurred
+** after the determination was made that one micro-second is too large an
+** increment for a constant 1Hz adjustment.
+** This command continuously adjusts the Spacecraft Time Correlation Factor (STCF)
+** every second, by adding the specified value. The adjustment to the STCF is
+** applied in the Time Service local 1Hz interrupt handler. As the local 1Hz
+** interrupt is not synchronized to the tone signal, one cannot say when the
+** adjustment will occur, other than once a second, at about the same time
+** relative to the tone.
+** There was some debate about whether the maximum 1Hz clock drift correction
+** factor would ever need to exceed some small fraction of a second. But, the
+** decision was made to provide the capability to make 1Hz adjustments greater
+** than one second and leave it to the ground system to provide mission specific
+** limits.
+**
+** \cfecmdmnemonic \TIME_ADD1HZSTCF
+**
+** \par Command Structure
+** #CFE_TIME_Add1HZAdjustmentCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_STCFSECS - Housekeeping Telemetry point indicating new STCF seconds value
+** - \b \c \TIME_STCFSUBSECS - Housekeeping Telemetry point indicating new STCF subseconds value
+** - The #CFE_TIME_1HZ_EID informational event message will be generated
+**
+** \par Error Conditions
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event message will be issued (#CFE_TIME_1HZ_CFG_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_ADD_ADJUST_CC, #CFE_TIME_SUB_ADJUST_CC, #CFE_TIME_SUB_1HZ_ADJUSTMENT_CC
+*/
+#define CFE_TIME_ADD_1HZ_ADJUSTMENT_CC 13 /* add 1Hz STCF adjustment */
+
+/** \cfetimecmd Subtract Delta from Spacecraft Time Correlation Factor each 1Hz
+**
+** \par Description
+** This command has been updated to take actual sub-seconds (1/2^32 seconds)
+** rather than micro-seconds as an input argument. This change occurred
+** after the determination was made that one micro-second is too large an
+** increment for a constant 1Hz adjustment.
+** This command continuously adjusts the Spacecraft Time Correlation Factor (STCF)
+** every second, by subtracting the specified value. The adjustment to the STCF
+** is applied in the Time Service local 1Hz interrupt handler. As the local 1Hz
+** interrupt is not synchronized to the tone signal, one cannot say when the
+** adjustment will occur, other than once a second, at about the same time
+** relative to the tone.
+** There was some debate about whether the maximum 1Hz clock drift correction
+** factor would ever need to exceed some small fraction of a second. But, the
+** decision was made to provide the capability to make 1Hz adjustments greater
+** than one second and leave it to the ground system to provide mission specific
+** limits.
+**
+** \cfecmdmnemonic \TIME_SUB1HZSTCF
+**
+** \par Command Structure
+** #CFE_TIME_Sub1HZAdjustmentCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will increment
+** - \b \c \TIME_STCFSECS - Housekeeping Telemetry point indicating new STCF seconds value
+** - \b \c \TIME_STCFSUBSECS - Housekeeping Telemetry point indicating new STCF subseconds value
+** - The #CFE_TIME_1HZ_EID informational event message will be generated
+**
+** \par Error Conditions
+** - Platorm receiving the command is not a Time Server
+**
Evidence of Failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - command error counter will increment
+** - Error specific event message will be issued (#CFE_TIME_1HZ_CFG_EID)
+**
+** \par Criticality
+** Inappropriately setting the clock may result in other sub-systems performing incorrect
+** time based calculations. The specific risk is dependent upon the behavior of those sub-systems.
+**
+** \sa #CFE_TIME_ADD_ADJUST_CC, #CFE_TIME_SUB_ADJUST_CC, #CFE_TIME_ADD_1HZ_ADJUSTMENT_CC
+*/
+#define CFE_TIME_SUB_1HZ_ADJUSTMENT_CC 14 /* subtract 1Hz STCF adjustment */
+
+/** \cfetimecmd Set Tone Signal Source
+**
+** \par Description
+** This command selects the Time Service tone signal source. Although the
+** list of potential tone signal sources is mission specific, a common
+** choice is the selection of primary or redundant tone signal. The selection
+** may be available to both the Time Server and Time Clients, depending on
+** hardware configuration.
+** Notes:
+** - This command is only valid when the #CFE_PLATFORM_TIME_CFG_SIGNAL configuration
+** parameter in the cfe_platform_cfg.h file has been set to true.
+**
+** \cfecmdmnemonic \TIME_SETSIGNAL
+**
+** \par Command Structure
+** #CFE_TIME_SetSignalCmd_t
+**
+** \par Command Verification
+** Successful execution of this command may be verified with the
+** following telemetry:
+** - \b \c \TIME_CMDPC - command execution counter will
+** increment
+** - \b \c \TIME_SIGNAL - Diagnostic Telemetry point will indicate the
+** command specified value
+** - The #CFE_TIME_SIGNAL_EID informational event message will
+** be generated
+**
+** \par Error Conditions
+** - Invalid Signal selection
+** (a value other than #CFE_TIME_ToneSignalSelect_PRIMARY or #CFE_TIME_ToneSignalSelect_REDUNDANT was specified)
+** - Multiple Tone Signal Sources not available on this platform
+**
Evidence of failure may be found in the following telemetry:
+** - \b \c \TIME_CMDEC - Command Error counter will increment
+** - Error specific event message (either #CFE_TIME_SIGNAL_CFG_EID or #CFE_TIME_SIGNAL_ERR_EID)
+**
+** \par Criticality
+** Although tone signal source selection is important, this command is not critical
+**
+** \sa #CFE_TIME_SET_STATE_CC, #CFE_TIME_SET_SOURCE_CC
+*/
+#define CFE_TIME_SET_SIGNAL_CC 15 /* set clock signal (pri vs red) */
+/** \} */
+
+/** \defgroup CFETIMEClkStates cFE Clock State Flag Defines
+ * \{
+ */
+#define CFE_TIME_FLAG_CLKSET 0x8000 /**< \brief The spacecraft time has been set */
+#define CFE_TIME_FLAG_FLYING 0x4000 /**< \brief This instance of Time Services is flywheeling */
+#define CFE_TIME_FLAG_SRCINT 0x2000 /**< \brief The clock source is set to "internal" */
+#define CFE_TIME_FLAG_SIGPRI 0x1000 /**< \brief The clock signal is set to "primary" */
+#define CFE_TIME_FLAG_SRVFLY 0x0800 /**< \brief The Time Server is in flywheel mode */
+#define CFE_TIME_FLAG_CMDFLY 0x0400 /**< \brief This instance of Time Services was commanded into flywheel mode */
+#define CFE_TIME_FLAG_ADDADJ 0x0200 /**< \brief One time STCF Adjustment is to be done in positive direction */
+#define CFE_TIME_FLAG_ADD1HZ 0x0100 /**< \brief 1 Hz STCF Adjustment is to be done in a positive direction */
+#define CFE_TIME_FLAG_ADDTCL 0x0080 /**< \brief Time Client Latency is applied in a positive direction */
+#define CFE_TIME_FLAG_SERVER 0x0040 /**< \brief This instance of Time Services is a Time Server */
+#define CFE_TIME_FLAG_GDTONE 0x0020 /**< \brief The tone received is good compared to the last tone received */
+#define CFE_TIME_FLAG_UNUSED 0x001F /**< \brief Reserved flags - should be zero */
+/** \} */
+
+/*************************************************************************/
+
+/**
+ * \brief Generic no argument command
+ */
+typedef struct CFE_TIME_NoArgsCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+
+} CFE_TIME_NoArgsCmd_t;
+
+/*
+ * A separate typedef for each of the commands that share this definition
+ * This follows the convention for command handler prototypes and allows
+ * each one to independently evolve as necessary.
+ */
+typedef CFE_TIME_NoArgsCmd_t CFE_TIME_NoopCmd_t;
+typedef CFE_TIME_NoArgsCmd_t CFE_TIME_ResetCountersCmd_t;
+typedef CFE_TIME_NoArgsCmd_t CFE_TIME_SendDiagnosticCmd_t;
+typedef CFE_TIME_NoArgsCmd_t CFE_TIME_1HzCmd_t;
+typedef CFE_TIME_NoArgsCmd_t CFE_TIME_ToneSignalCmd_t;
+typedef CFE_TIME_NoArgsCmd_t CFE_TIME_FakeToneCmd_t;
+
+/**
+ * \brief Set leap seconds command payload
+ */
+typedef struct CFE_TIME_LeapsCmd_Payload
+{
+ int16 LeapSeconds;
+} CFE_TIME_LeapsCmd_Payload_t;
+
+/**
+ * \brief Set leap seconds command
+ */
+typedef struct CFE_TIME_SetLeapSecondsCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_TIME_LeapsCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_TIME_SetLeapSecondsCmd_t;
+
+/**
+ * \brief Set clock state command payload
+ */
+typedef struct CFE_TIME_StateCmd_Payload
+{
+ int16 ClockState; /**< \brief #CFE_TIME_ClockState_INVALID=Spacecraft time has not been accurately set,
+ #CFE_TIME_ClockState_VALID=Spacecraft clock has been accurately set,
+ #CFE_TIME_ClockState_FLYWHEEL=Force into FLYWHEEL mode */
+ /**< Selects the current clock state */
+} CFE_TIME_StateCmd_Payload_t;
+
+/**
+ * \brief Set clock state command
+ */
+typedef struct CFE_TIME_SetStateCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_TIME_StateCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_TIME_SetStateCmd_t;
+
+/**
+ * \brief Set time data source command payload
+ */
+typedef struct CFE_TIME_SourceCmd_Payload
+{
+ int16 TimeSource; /**< \brief #CFE_TIME_SourceSelect_INTERNAL=Internal Source,
+ #CFE_TIME_SourceSelect_EXTERNAL=External Source */
+ /**< Selects either the "Internal" and "External" clock source */
+} CFE_TIME_SourceCmd_Payload_t;
+
+/**
+ * \brief Set time data source command
+ */
+typedef struct CFE_TIME_SetSourceCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_TIME_SourceCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_TIME_SetSourceCmd_t;
+
+/**
+ * \brief Set tone signal source command payload
+ */
+typedef struct CFE_TIME_SignalCmd_Payload
+{
+ int16 ToneSource; /**< \brief #CFE_TIME_ToneSignalSelect_PRIMARY=Primary Source,
+ #CFE_TIME_ToneSignalSelect_REDUNDANT=Redundant Source */
+ /**< Selects either the "Primary" or "Redundant" tone signal source */
+} CFE_TIME_SignalCmd_Payload_t;
+
+/**
+ * \brief Set tone signal source command
+ */
+typedef struct CFE_TIME_SetSignalCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_TIME_SignalCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_TIME_SetSignalCmd_t;
+
+/**
+ * \brief Generic seconds, microseconds command payload
+ */
+typedef struct CFE_TIME_TimeCmd_Payload
+{
+ uint32 Seconds;
+ uint32 MicroSeconds;
+} CFE_TIME_TimeCmd_Payload_t;
+
+/**
+ * \brief Generic seconds, microseconds argument command
+ */
+typedef struct CFE_TIME_TimeCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_TIME_TimeCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_TIME_TimeCmd_t;
+
+/*
+ * A separate typedef for each of the commands that share this definition
+ * This follows the convention for command handler prototypes and allows
+ * each one to independently evolve as necessary.
+ */
+typedef CFE_TIME_TimeCmd_t CFE_TIME_AddDelayCmd_t;
+typedef CFE_TIME_TimeCmd_t CFE_TIME_SubDelayCmd_t;
+typedef CFE_TIME_TimeCmd_t CFE_TIME_SetMETCmd_t;
+typedef CFE_TIME_TimeCmd_t CFE_TIME_SetSTCFCmd_t;
+typedef CFE_TIME_TimeCmd_t CFE_TIME_AddAdjustCmd_t;
+typedef CFE_TIME_TimeCmd_t CFE_TIME_SubAdjustCmd_t;
+typedef CFE_TIME_TimeCmd_t CFE_TIME_SetTimeCmd_t;
+
+/**
+ * \brief Generic seconds, subseconds command payload
+ */
+typedef struct CFE_TIME_OneHzAdjustmentCmd_Payload
+{
+ uint32 Seconds;
+ uint32 Subseconds;
+
+} CFE_TIME_OneHzAdjustmentCmd_Payload_t;
+
+/**
+ * \brief Generic seconds, subseconds adjustment command
+ */
+typedef struct CFE_TIME_OneHzAdjustmentCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_TIME_OneHzAdjustmentCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_TIME_OneHzAdjustmentCmd_t;
+
+/*
+ * A separate typedef for each of the commands that share this definition
+ * This follows the convention for command handler prototypes and allows
+ * each one to independently evolve as necessary.
+ */
+typedef CFE_TIME_OneHzAdjustmentCmd_t CFE_TIME_Add1HZAdjustmentCmd_t;
+typedef CFE_TIME_OneHzAdjustmentCmd_t CFE_TIME_Sub1HZAdjustmentCmd_t;
+
+/**
+ * \brief Time at tone data command payload
+ */
+typedef struct CFE_TIME_ToneDataCmd_Payload
+{
+ CFE_TIME_SysTime_t AtToneMET; /**< \brief MET at time of tone */
+ CFE_TIME_SysTime_t AtToneSTCF; /**< \brief STCF at time of tone */
+ int16 AtToneLeapSeconds; /**< \brief Leap Seconds at time of tone */
+ int16 AtToneState; /**< \brief Clock state at time of tone */
+} CFE_TIME_ToneDataCmd_Payload_t;
+
+/**
+ * \brief Time at tone data command
+ */
+typedef struct CFE_TIME_ToneDataCmd
+{
+ CFE_MSG_CommandHeader_t CmdHeader; /**< \brief Command header */
+ CFE_TIME_ToneDataCmd_Payload_t Payload; /**< \brief Command payload */
+} CFE_TIME_ToneDataCmd_t;
+
+/*************************************************************************/
+
+/**
+** \cfetimetlm Time Services Housekeeping Packet
+**/
+typedef struct CFE_TIME_HousekeepingTlm_Payload
+{
+ /*
+ ** Task command interface counters...
+ */
+ uint8 CommandCounter; /**< \cfetlmmnemonic \TIME_CMDPC
+ \brief Time Command Execution Counter */
+ uint8 CommandErrorCounter; /**< \cfetlmmnemonic \TIME_CMDEC
+ \brief Time Command Error Counter */
+
+ /*
+ ** Clock state flags and "as calculated" clock state...
+ */
+ uint16 ClockStateFlags; /**< \cfetlmmnemonic \TIME_STATEFLG
+ \brief State Flags */
+ int16 ClockStateAPI; /**< \cfetlmmnemonic \TIME_APISTATE
+ \brief API State */
+
+ /*
+ ** Leap Seconds...
+ */
+ int16 LeapSeconds; /**< \cfetlmmnemonic \TIME_LEAPSECS
+ \brief Current Leaps Seconds */
+
+ /*
+ ** Current MET and STCF time values...
+ */
+ uint32 SecondsMET; /**< \cfetlmmnemonic \TIME_METSECS
+ \brief Current MET (seconds) */
+ uint32 SubsecsMET; /**< \cfetlmmnemonic \TIME_METSUBSECS
+ \brief Current MET (sub-seconds) */
+
+ uint32 SecondsSTCF; /**< \cfetlmmnemonic \TIME_STCFSECS
+ \brief Current STCF (seconds) */
+ uint32 SubsecsSTCF; /**< \cfetlmmnemonic \TIME_STCFSUBSECS
+ \brief Current STCF (sub-seconds) */
+
+/*
+** 1Hz STCF adjustment values (server only)...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ uint32 Seconds1HzAdj; /**< \cfetlmmnemonic \TIME_1HZADJSECS
+ \brief Current 1 Hz SCTF adjustment (seconds) */
+ uint32 Subsecs1HzAdj; /**< \cfetlmmnemonic \TIME_1HZADJSSECS
+ \brief Current 1 Hz SCTF adjustment (sub-seconds) */
+#endif
+
+/*
+** Time at tone delay values (client only)...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ uint32 SecondsDelay; /**< \cfetlmmnemonic \TIME_1HZDLYSECS
+ \brief Current 1 Hz SCTF Delay (seconds) */
+ uint32 SubsecsDelay; /**< \cfetlmmnemonic \TIME_1HZDLYSSECS
+ \brief Current 1 Hz SCTF Delay (sub-seconds) */
+#endif
+
+} CFE_TIME_HousekeepingTlm_Payload_t;
+
+typedef struct CFE_TIME_HousekeepingTlm
+{
+ CFE_MSG_TelemetryHeader_t TlmHeader; /**< \brief Telemetry header */
+ CFE_TIME_HousekeepingTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_TIME_HousekeepingTlm_t;
+
+/*************************************************************************/
+
+/**
+** \cfetimetlm Time Services Diagnostics Packet
+**/
+typedef struct CFE_TIME_DiagnosticTlm_Payload
+{
+ /*
+ ** Data values used to compute time (in reference to "tone")...
+ */
+ CFE_TIME_SysTime_t AtToneMET; /**< \cfetlmmnemonic \TIME_TMETS
+ \brief MET at time of tone */
+ CFE_TIME_SysTime_t AtToneSTCF; /**< \cfetlmmnemonic \TIME_STCFS
+ \brief STCF at time of tone */
+ CFE_TIME_SysTime_t AtToneDelay; /**< \cfetlmmnemonic \TIME_LATENTS
+ \brief Adjustment for slow tone detection */
+ CFE_TIME_SysTime_t AtToneLatch; /**< \cfetlmmnemonic \TIME_TVALIDS
+ \brief Local clock latched at time of tone */
+
+ int16 AtToneLeapSeconds; /**< \cfetlmmnemonic \TIME_LEAPS
+ \brief Leap Seconds at time of tone */
+ int16 ClockStateAPI; /**< \cfetlmmnemonic \TIME_APISTATE
+ \brief Clock state as per API */
+
+ /*
+ ** Data values that reflect the time (right now)...
+ */
+ CFE_TIME_SysTime_t TimeSinceTone; /**< \cfetlmmnemonic \TIME_ELAPSEDS
+ \brief Time elapsed since the tone */
+ CFE_TIME_SysTime_t CurrentLatch; /**< \cfetlmmnemonic \TIME_LOCALS
+ \brief Local clock latched just "now" */
+ CFE_TIME_SysTime_t CurrentMET; /**< \cfetlmmnemonic \TIME_METS
+ \brief MET at this instant */
+ CFE_TIME_SysTime_t CurrentTAI; /**< \cfetlmmnemonic \TIME_TAIS
+ \brief TAI at this instant */
+ CFE_TIME_SysTime_t CurrentUTC; /**< \cfetlmmnemonic \TIME_UTCS
+ \brief UTC at this instant */
+
+ /*
+ ** Data values used to define the current clock state...
+ */
+ int16 ClockSetState; /**< \cfetlmmnemonic \TIME_VALID
+ \brief Time has been "set" */
+ int16 ClockFlyState; /**< \cfetlmmnemonic \TIME_FLYWHEEL
+ \brief Current fly-wheel state */
+ int16 ClockSource; /**< \cfetlmmnemonic \TIME_SOURCE
+ \brief Internal vs external, etc. */
+ int16 ClockSignal; /**< \cfetlmmnemonic \TIME_SIGNAL
+ \brief Primary vs redundant, etc. */
+ int16 ServerFlyState; /**< \cfetlmmnemonic \TIME_SRVFLY
+ \brief Used by clients only */
+ int16 Forced2Fly; /**< \cfetlmmnemonic \TIME_CMD2FLY
+ \brief Commanded into fly-wheel */
+
+ /*
+ ** Clock state flags...
+ */
+ uint16 ClockStateFlags; /**< \cfetlmmnemonic \TIME_STATEFLAGS
+ \brief Clock State Flags */
+
+ /*
+ ** STCF adjustment direction values...
+ */
+ int16 OneTimeDirection; /**< \cfetlmmnemonic \TIME_ADJUSTDIR
+ \brief One time STCF adjustment direction (Add = 1, Sub = 2) */
+ int16 OneHzDirection; /**< \cfetlmmnemonic \TIME_1HZADJDIR
+ \brief 1Hz STCF adjustment direction */
+ int16 DelayDirection; /**< \cfetlmmnemonic \TIME_LATENTDIR
+ \brief Client latency adjustment direction */
+
+ /*
+ ** STCF adjustment values...
+ */
+ CFE_TIME_SysTime_t OneTimeAdjust; /**< \cfetlmmnemonic \TIME_ADJUSTS
+ \brief Previous one-time STCF adjustment */
+ CFE_TIME_SysTime_t OneHzAdjust; /**< \cfetlmmnemonic \TIME_1HZADJS
+ \brief Current 1Hz STCF adjustment */
+
+ /*
+ ** Most recent local clock latch values...
+ */
+ CFE_TIME_SysTime_t ToneSignalLatch; /**< \cfetlmmnemonic \TIME_TTS
+ \brief Local Clock latched at most recent tone signal */
+ CFE_TIME_SysTime_t ToneDataLatch; /**< \cfetlmmnemonic \TIME_TDS
+ \brief Local Clock latched at arrival of tone data */
+
+ /*
+ ** Miscellaneous counters (subject to reset command)...
+ */
+ uint32 ToneMatchCounter; /**< \cfetlmmnemonic \TIME_VERIFYCNT
+ \brief Tone signal / data verification count */
+ uint32 ToneMatchErrorCounter; /**< \cfetlmmnemonic \TIME_VERIFYER
+ \brief Tone signal / data verification error count */
+ uint32 ToneSignalCounter; /**< \cfetlmmnemonic \TIME_TSDETCNT
+ \brief Tone signal detected SB message count */
+ uint32 ToneDataCounter; /**< \cfetlmmnemonic \TIME_TATTCNT
+ \brief Time at the tone data SB message count */
+ uint32 ToneIntCounter; /**< \cfetlmmnemonic \TIME_TSISRCNT
+ \brief Tone signal ISR execution count */
+ uint32 ToneIntErrorCounter; /**< \cfetlmmnemonic \TIME_TSISRERR
+ \brief Tone signal ISR error count */
+ uint32 ToneTaskCounter; /**< \cfetlmmnemonic \TIME_TSTASKCNT
+ \brief Tone task execution count */
+ uint32 VersionCounter; /**< \cfetlmmnemonic \TIME_VERSIONCNT
+ \brief Count of mods to time at tone reference data (version) */
+ uint32 LocalIntCounter; /**< \cfetlmmnemonic \TIME_1HZISRCNT
+ \brief Local 1Hz ISR execution count */
+ uint32 LocalTaskCounter; /**< \cfetlmmnemonic \TIME_1HZTASKCNT
+ \brief Local 1Hz task execution count */
+
+ /*
+ ** Miscellaneous counters (not subject to reset command)...
+ */
+ uint32 VirtualMET; /**< \cfetlmmnemonic \TIME_LOGICALMET
+ \brief Software MET */
+
+ /*
+ ** Time window verification values (converted from micro-secs)...
+ **
+ ** Regardless of whether the tone follows the time packet, or vice
+ ** versa, these values define the acceptable window of time for
+ ** the second event to follow the first. The minimum value may
+ ** be as little as zero, and the maximum must be something less
+ ** than a second.
+ */
+ uint32 MinElapsed; /**< \cfetlmmnemonic \TIME_MINWINDOW
+ \brief Min tone signal / data pkt arrival window (Sub-seconds) */
+ uint32 MaxElapsed; /**< \cfetlmmnemonic \TIME_MAXWINDOW
+ \brief Max tone signal / data pkt arrival window (Sub-seconds) */
+
+ /*
+ ** Maximum local clock value (before roll-over)...
+ */
+ CFE_TIME_SysTime_t MaxLocalClock; /**< \cfetlmmnemonic \TIME_WRAPS
+ \brief Max local clock value before rollover */
+
+ /*
+ ** Tone signal tolerance limits...
+ */
+ uint32 ToneOverLimit; /**< \cfetlmmnemonic \TIME_MAXSS
+ \brief Max between tone signal interrupts */
+ uint32 ToneUnderLimit; /**< \cfetlmmnemonic \TIME_MINSS
+ \brief Min between tone signal interrupts */
+
+ /*
+ ** Reset Area...
+ */
+ uint32 DataStoreStatus; /**< \cfetlmmnemonic \TIME_ATASTSTAT
+ \brief Data Store status (preserved across processor reset) */
+} CFE_TIME_DiagnosticTlm_Payload_t;
+
+typedef struct CFE_TIME_DiagnosticTlm
+{
+ CFE_MSG_TelemetryHeader_t TlmHeader; /**< \brief Telemetry header */
+ CFE_TIME_DiagnosticTlm_Payload_t Payload; /**< \brief Telemetry payload */
+} CFE_TIME_DiagnosticTlm_t;
+
+#endif /* CFE_TIME_MSG_H */
diff --git a/modules/time/fsw/src/cfe_time_api.c b/modules/time/fsw/src/cfe_time_api.c
new file mode 100644
index 000000000..3176e08ca
--- /dev/null
+++ b/modules/time/fsw/src/cfe_time_api.c
@@ -0,0 +1,808 @@
+/*
+** 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_time_api.c
+**
+** Purpose: cFE Time Services (TIME) library API source file
+**
+** Author: S.Walling/Microtel
+**
+** Notes: Partially derived from SDO source code
+**
+*/
+
+/*
+** Required header files...
+*/
+#include "cfe_time_module_all.h"
+
+#include
+
+/*
+ * Function: CFE_TIME_GetTime - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_GetTime(void)
+{
+ CFE_TIME_SysTime_t CurrentTime;
+
+#if (CFE_MISSION_TIME_CFG_DEFAULT_TAI == true)
+
+ CurrentTime = CFE_TIME_GetTAI();
+
+#else
+
+ CurrentTime = CFE_TIME_GetUTC();
+
+#endif
+
+ return (CurrentTime);
+
+} /* End of CFE_TIME_GetTime() */
+
+/*
+ * Function: CFE_TIME_GetTAI - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_GetTAI(void)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t tai;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** Calculate current TAI...
+ */
+ tai = CFE_TIME_CalculateTAI(&Reference);
+
+ return (tai);
+
+} /* End of CFE_TIME_GetTAI() */
+
+/*
+ * Function: CFE_TIME_GetUTC - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_GetUTC(void)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t utc;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** Calculate current UTC...
+ */
+ utc = CFE_TIME_CalculateUTC(&Reference);
+
+ return (utc);
+
+} /* End of CFE_TIME_GetUTC() */
+
+/*
+ * Function: CFE_TIME_MET2SCTime - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_MET2SCTime(CFE_TIME_SysTime_t METTime)
+{
+
+ CFE_TIME_SysTime_t STCF;
+ CFE_TIME_SysTime_t TIATime;
+ CFE_TIME_SysTime_t ReturnTime;
+#if (CFE_MISSION_TIME_CFG_DEFAULT_TAI != true)
+ CFE_TIME_SysTime_t LeapSecsAsSysTime;
+#endif
+
+ STCF = CFE_TIME_GetSTCF();
+
+ /* TIA = MET + STCF */
+ TIATime = CFE_TIME_Add(METTime, STCF);
+
+#if (CFE_MISSION_TIME_CFG_DEFAULT_TAI == true)
+
+ ReturnTime = TIATime;
+
+#else
+
+ /* Put leap seconds in correct format */
+ LeapSecsAsSysTime.Seconds = CFE_TIME_GetLeapSeconds();
+ LeapSecsAsSysTime.Subseconds = 0;
+
+ /* UTC Time = TIA Time - Leap Seconds */
+ ReturnTime = CFE_TIME_Subtract(TIATime, LeapSecsAsSysTime);
+
+#endif
+
+ return (ReturnTime);
+} /* end CFE_TIME_MET2SCTime() */
+
+/*
+ * Function: CFE_TIME_GetClockState - See API and header file for details
+ */
+CFE_TIME_ClockState_Enum_t CFE_TIME_GetClockState(void)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_ClockState_Enum_t state;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** Determine the current clock state...
+ */
+ state = (CFE_TIME_ClockState_Enum_t)CFE_TIME_CalculateState(&Reference);
+
+ return (state);
+
+} /* End of CFE_TIME_GetClockState() */
+
+/*
+ * Function: CFE_TIME_GetClockInfo - See API and header file for details
+ */
+uint16 CFE_TIME_GetClockInfo(void)
+{
+ uint16 StateFlags = 0;
+ volatile CFE_TIME_ReferenceState_t *RefState = CFE_TIME_GetReferenceState();
+
+ /*
+ ** Spacecraft time has been set...
+ */
+ if (RefState->ClockSetState == CFE_TIME_SetState_WAS_SET)
+ {
+ StateFlags |= CFE_TIME_FLAG_CLKSET;
+ }
+ /*
+ ** This instance of Time Service is in FLYWHEEL mode...
+ */
+ if (RefState->ClockFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ StateFlags |= CFE_TIME_FLAG_FLYING;
+ }
+ /*
+ ** Clock source set to "internal"...
+ */
+ if (CFE_TIME_Global.ClockSource == CFE_TIME_SourceSelect_INTERNAL)
+ {
+ StateFlags |= CFE_TIME_FLAG_SRCINT;
+ }
+ /*
+ ** Clock signal set to "primary"...
+ */
+ if (CFE_TIME_Global.ClockSignal == CFE_TIME_ToneSignalSelect_PRIMARY)
+ {
+ StateFlags |= CFE_TIME_FLAG_SIGPRI;
+ }
+ /*
+ ** Time Server is in FLYWHEEL mode...
+ */
+ if (CFE_TIME_Global.ServerFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ StateFlags |= CFE_TIME_FLAG_SRVFLY;
+ }
+ /*
+ ** This instance of Time Services commanded into FLYWHEEL...
+ */
+ if (CFE_TIME_Global.Forced2Fly)
+ {
+ StateFlags |= CFE_TIME_FLAG_CMDFLY;
+ }
+ /*
+ ** One time STCF adjustment direction...
+ */
+ if (CFE_TIME_Global.OneTimeDirection == CFE_TIME_AdjustDirection_ADD)
+ {
+ StateFlags |= CFE_TIME_FLAG_ADDADJ;
+ }
+ /*
+ ** 1 Hz STCF adjustment direction...
+ */
+ if (CFE_TIME_Global.OneHzDirection == CFE_TIME_AdjustDirection_ADD)
+ {
+ StateFlags |= CFE_TIME_FLAG_ADD1HZ;
+ }
+ /*
+ ** Time Client Latency adjustment direction...
+ */
+ if (RefState->DelayDirection == CFE_TIME_AdjustDirection_ADD)
+ {
+ StateFlags |= CFE_TIME_FLAG_ADDTCL;
+ }
+/*
+** This instance of Time Service is a "server"...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ StateFlags |= CFE_TIME_FLAG_SERVER;
+#endif
+
+ /*
+ ** The tone is good
+ */
+ if (CFE_TIME_Global.IsToneGood == true)
+ {
+ StateFlags |= CFE_TIME_FLAG_GDTONE;
+ }
+
+ return (StateFlags);
+
+} /* End of CFE_TIME_GetClockInfo() */
+
+/*
+ * Function: CFE_TIME_GetLeapSeconds - See API and header file for details
+ */
+int16 CFE_TIME_GetLeapSeconds(void)
+{
+ CFE_TIME_Reference_t Reference;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ return (Reference.AtToneLeapSeconds);
+
+} /* End of CFE_TIME_GetLeapSeconds() */
+
+/*
+ * Function: CFE_TIME_GetSTCF - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_GetSTCF(void)
+{
+ CFE_TIME_Reference_t Reference;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ return (Reference.AtToneSTCF);
+
+} /* End of CFE_TIME_GetSTCF() */
+
+/*
+ * Function: CFE_TIME_GetMET - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_GetMET(void)
+{
+ CFE_TIME_Reference_t Reference;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ return (Reference.CurrentMET);
+
+} /* End of CFE_TIME_GetMET() */
+
+/*
+ * Function: CFE_TIME_GetMETseconds - See API and header file for details
+ */
+uint32 CFE_TIME_GetMETseconds(void)
+{
+ CFE_TIME_Reference_t Reference;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ return (Reference.CurrentMET.Seconds);
+
+} /* End of CFE_TIME_GetMETseconds() */
+
+/*
+ * Function: CFE_TIME_GetMETsubsecs - See API and header file for details
+ */
+uint32 CFE_TIME_GetMETsubsecs(void)
+{
+ CFE_TIME_Reference_t Reference;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ return (Reference.CurrentMET.Subseconds);
+
+} /* End of CFE_TIME_GetMETsubsecs() */
+
+/*
+ * Function: CFE_TIME_Add - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_Add(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2)
+{
+ CFE_TIME_SysTime_t Result;
+
+ Result.Subseconds = Time1.Subseconds + Time2.Subseconds;
+
+ /*
+ ** Check for sub-seconds roll-over
+ */
+ if (Result.Subseconds < Time1.Subseconds)
+ {
+ Result.Seconds = (Time1.Seconds + Time2.Seconds) + 1;
+ }
+ else
+ {
+ Result.Seconds = Time1.Seconds + Time2.Seconds;
+ }
+
+ return (Result);
+
+} /* End of CFE_TIME_Add() */
+
+/*
+ * Function: CFE_TIME_Subtract - See API and header file for details
+ */
+CFE_TIME_SysTime_t CFE_TIME_Subtract(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2)
+{
+ CFE_TIME_SysTime_t Result;
+
+ Result.Subseconds = Time1.Subseconds - Time2.Subseconds;
+
+ if (Result.Subseconds > Time1.Subseconds)
+ {
+ Result.Seconds = (Time1.Seconds - Time2.Seconds) - 1;
+ }
+ else
+ {
+ Result.Seconds = Time1.Seconds - Time2.Seconds;
+ }
+
+ return (Result);
+
+} /* End of CFE_TIME_Subtract() */
+
+/*
+ * Function: CFE_TIME_Compare - See API and header file for details
+ */
+CFE_TIME_Compare_t CFE_TIME_Compare(CFE_TIME_SysTime_t TimeA, CFE_TIME_SysTime_t TimeB)
+{
+ CFE_TIME_Compare_t Result;
+
+ if (TimeA.Seconds > TimeB.Seconds)
+ {
+ /*
+ ** Assume rollover if difference is too large...
+ */
+ if ((TimeA.Seconds - TimeB.Seconds) > CFE_TIME_NEGATIVE)
+ {
+ Result = CFE_TIME_A_LT_B;
+ }
+ else
+ {
+ Result = CFE_TIME_A_GT_B;
+ }
+ }
+ else if (TimeA.Seconds < TimeB.Seconds)
+ {
+ /*
+ ** Assume rollover if difference is too large...
+ */
+ if ((TimeB.Seconds - TimeA.Seconds) > CFE_TIME_NEGATIVE)
+ {
+ Result = CFE_TIME_A_GT_B;
+ }
+ else
+ {
+ Result = CFE_TIME_A_LT_B;
+ }
+ }
+ else
+ {
+ /*
+ ** Seconds are equal, check sub-seconds
+ */
+ if (TimeA.Subseconds > TimeB.Subseconds)
+ {
+ Result = CFE_TIME_A_GT_B;
+ }
+ else if (TimeA.Subseconds < TimeB.Subseconds)
+ {
+ Result = CFE_TIME_A_LT_B;
+ }
+ else
+ {
+ Result = CFE_TIME_EQUAL;
+ }
+ }
+
+ return (Result);
+
+} /* End of CFE_TIME_Compare() */
+
+/*
+ * Function: CFE_TIME_Sub2MicroSecs - See API and header file for details
+ */
+uint32 CFE_TIME_Sub2MicroSecs(uint32 SubSeconds)
+{
+ OS_time_t tm;
+
+ /*
+ ** Convert using the OSAL method. Note that there
+ ** is no range check here because any uint32 value is valid,
+ ** and OSAL will handle and properly convert any input.
+ */
+ tm = OS_TimeAssembleFromSubseconds(0, SubSeconds);
+
+ return OS_TimeGetMicrosecondsPart(tm);
+
+} /* End of CFE_TIME_Sub2MicroSecs() */
+
+/*
+ * Function: CFE_TIME_Micro2SubSecs - See API and header file for details
+ */
+uint32 CFE_TIME_Micro2SubSecs(uint32 MicroSeconds)
+{
+ OS_time_t tm;
+ uint32 SubSeconds;
+
+ /*
+ ** Conversion amount must be less than one second
+ ** (preserves existing behavior where output saturates at max value)
+ */
+ if (MicroSeconds > 999999)
+ {
+ SubSeconds = 0xFFFFFFFF;
+ }
+ else
+ {
+ /*
+ ** Convert micro-seconds count to sub-seconds (1/2^32) count using OSAL
+ */
+ tm = OS_TimeAssembleFromNanoseconds(0, MicroSeconds * 1000);
+ SubSeconds = OS_TimeGetSubsecondsPart(tm);
+ }
+
+ return (SubSeconds);
+
+} /* End of CFE_TIME_Micro2SubSecs() */
+
+/*
+ * Function: CFE_TIME_Print - See API and header file for details
+ */
+void CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint)
+{
+ uint32 NumberOfYears;
+ uint32 NumberOfDays;
+ uint32 NumberOfHours;
+ uint32 NumberOfMinutes;
+ uint32 NumberOfSeconds;
+ uint32 NumberOfMicros;
+ uint32 DaysInThisYear;
+
+ bool StillCountingYears = true;
+
+ if (PrintBuffer == NULL)
+ {
+ CFE_ES_WriteToSysLog("CFE_TIME:Print-Failed invalid arguments\n");
+ return;
+ }
+
+ /*
+ ** Convert the cFE time (offset from epoch) into calendar time...
+ */
+ NumberOfMinutes = (TimeToPrint.Seconds / 60) + CFE_MISSION_TIME_EPOCH_MINUTE;
+ NumberOfSeconds = (TimeToPrint.Seconds % 60) + CFE_MISSION_TIME_EPOCH_SECOND;
+
+ /*
+ ** Adding the epoch "seconds" after computing the minutes avoids
+ ** overflow problems when the input time value (seconds) is
+ ** at, or near, 0xFFFFFFFF...
+ */
+ while (NumberOfSeconds >= 60)
+ {
+ NumberOfMinutes++;
+ NumberOfSeconds -= 60;
+ }
+
+ /*
+ ** Compute the years/days/hours/minutes...
+ */
+ NumberOfHours = (NumberOfMinutes / 60) + CFE_MISSION_TIME_EPOCH_HOUR;
+ NumberOfMinutes = (NumberOfMinutes % 60);
+
+ /*
+ ** Unlike hours and minutes, epoch days are counted as Jan 1 = day 1...
+ */
+ NumberOfDays = (NumberOfHours / 24) + (CFE_MISSION_TIME_EPOCH_DAY - 1);
+ NumberOfHours = (NumberOfHours % 24);
+
+ NumberOfYears = CFE_MISSION_TIME_EPOCH_YEAR;
+
+ /*
+ ** Convert total number of days into years and remainder days...
+ */
+ while (StillCountingYears)
+ {
+ /*
+ ** Set number of days in this year (leap year?)...
+ */
+ DaysInThisYear = 365;
+
+ if ((NumberOfYears % 4) == 0)
+ {
+ if ((NumberOfYears % 100) != 0)
+ {
+ DaysInThisYear = 366;
+ }
+ else if ((NumberOfYears % 400) == 0)
+ {
+ DaysInThisYear = 366;
+ }
+ else
+ {
+ /* Do Nothing. Non-leap year. */
+ }
+ }
+
+ /*
+ ** When we have less than a years worth of days, we're done...
+ */
+ if (NumberOfDays < DaysInThisYear)
+ {
+ StillCountingYears = false;
+ }
+ else
+ {
+ /*
+ ** Add a year and remove the number of days in that year...
+ */
+ NumberOfYears++;
+ NumberOfDays -= DaysInThisYear;
+ }
+ }
+
+ /*
+ ** Unlike hours and minutes, days are displayed as Jan 1 = day 1...
+ */
+ NumberOfDays++;
+
+ /*
+ ** After computing microseconds, convert to 5 digits from 6 digits...
+ */
+ NumberOfMicros = CFE_TIME_Sub2MicroSecs(TimeToPrint.Subseconds) / 10;
+
+ /*
+ ** Build formatted output string (yyyy-ddd-hh:mm:ss.xxxxx)...
+ */
+ *PrintBuffer++ = '0' + (char)(NumberOfYears / 1000);
+ NumberOfYears = NumberOfYears % 1000;
+ *PrintBuffer++ = '0' + (char)(NumberOfYears / 100);
+ NumberOfYears = NumberOfYears % 100;
+ *PrintBuffer++ = '0' + (char)(NumberOfYears / 10);
+ *PrintBuffer++ = '0' + (char)(NumberOfYears % 10);
+ *PrintBuffer++ = '-';
+
+ *PrintBuffer++ = '0' + (char)(NumberOfDays / 100);
+ NumberOfDays = NumberOfDays % 100;
+ *PrintBuffer++ = '0' + (char)(NumberOfDays / 10);
+ *PrintBuffer++ = '0' + (char)(NumberOfDays % 10);
+ *PrintBuffer++ = '-';
+
+ *PrintBuffer++ = '0' + (char)(NumberOfHours / 10);
+ *PrintBuffer++ = '0' + (char)(NumberOfHours % 10);
+ *PrintBuffer++ = ':';
+
+ *PrintBuffer++ = '0' + (char)(NumberOfMinutes / 10);
+ *PrintBuffer++ = '0' + (char)(NumberOfMinutes % 10);
+ *PrintBuffer++ = ':';
+
+ *PrintBuffer++ = '0' + (char)(NumberOfSeconds / 10);
+ *PrintBuffer++ = '0' + (char)(NumberOfSeconds % 10);
+ *PrintBuffer++ = '.';
+
+ *PrintBuffer++ = '0' + (char)(NumberOfMicros / 10000);
+ NumberOfMicros = NumberOfMicros % 10000;
+ *PrintBuffer++ = '0' + (char)(NumberOfMicros / 1000);
+ NumberOfMicros = NumberOfMicros % 1000;
+ *PrintBuffer++ = '0' + (char)(NumberOfMicros / 100);
+ NumberOfMicros = NumberOfMicros % 100;
+ *PrintBuffer++ = '0' + (char)(NumberOfMicros / 10);
+ *PrintBuffer++ = '0' + (char)(NumberOfMicros % 10);
+ *PrintBuffer++ = '\0';
+
+ return;
+
+} /* End of CFE_TIME_Print() */
+
+/*
+ * Function: CFE_TIME_ExternalTone - See API and header file for details
+ */
+void CFE_TIME_ExternalTone(void)
+{
+ /*
+ ** Call tone signal ISR (OK if called from non-ISR context)...
+ */
+ CFE_TIME_Tone1HzISR();
+
+ return;
+
+} /* End of CFE_TIME_ExternalTone() */
+
+/*
+ * Function: CFE_TIME_RegisterSynchCallback - See API and header file for details
+ */
+int32 CFE_TIME_RegisterSynchCallback(CFE_TIME_SynchCallbackPtr_t CallbackFuncPtr)
+{
+ int32 Status;
+ CFE_ES_AppId_t AppId;
+ uint32 AppIndex;
+
+ if (CallbackFuncPtr == NULL)
+ {
+ return CFE_TIME_BAD_ARGUMENT;
+ }
+
+ Status = CFE_ES_GetAppID(&AppId);
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_ES_AppID_ToIndex(AppId, &AppIndex);
+
+ if (Status == CFE_SUCCESS)
+ {
+
+ if (AppIndex >= (sizeof(CFE_TIME_Global.SynchCallback) / sizeof(CFE_TIME_Global.SynchCallback[0])) ||
+ CFE_TIME_Global.SynchCallback[AppIndex].Ptr != NULL)
+ {
+ Status = CFE_TIME_TOO_MANY_SYNCH_CALLBACKS;
+ }
+ else
+ {
+ CFE_TIME_Global.SynchCallback[AppIndex].Ptr = CallbackFuncPtr;
+ }
+ }
+ }
+
+ return Status;
+} /* End of CFE_TIME_RegisterSynchCallback() */
+
+/*
+ * Function: CFE_TIME_UnregisterSynchCallback - See API and header file for details
+ */
+int32 CFE_TIME_UnregisterSynchCallback(CFE_TIME_SynchCallbackPtr_t CallbackFuncPtr)
+{
+ int32 Status;
+ CFE_ES_AppId_t AppId;
+ uint32 AppIndex;
+
+ if (CallbackFuncPtr == NULL)
+ {
+ return CFE_TIME_BAD_ARGUMENT;
+ }
+
+ Status = CFE_ES_GetAppID(&AppId);
+ if (Status == CFE_SUCCESS)
+ {
+ Status = CFE_ES_AppID_ToIndex(AppId, &AppIndex);
+
+ if (Status == CFE_SUCCESS)
+ {
+
+ if (AppIndex >= (sizeof(CFE_TIME_Global.SynchCallback) / sizeof(CFE_TIME_Global.SynchCallback[0])) ||
+ CFE_TIME_Global.SynchCallback[AppIndex].Ptr != CallbackFuncPtr)
+ {
+ Status = CFE_TIME_CALLBACK_NOT_REGISTERED;
+ }
+ else
+ {
+ CFE_TIME_Global.SynchCallback[AppIndex].Ptr = NULL;
+ }
+ }
+ }
+
+ return Status;
+} /* End of CFE_TIME_UnregisterSynchCallback() */
+
+/*
+ * Function: CFE_TIME_ExternalMET - See API and header file for details
+ */
+#if (CFE_PLATFORM_TIME_CFG_SRC_MET == true)
+void CFE_TIME_ExternalMET(CFE_TIME_SysTime_t NewMET)
+{
+ /*
+ ** Process external MET data...
+ */
+ CFE_TIME_ToneSendMET(NewMET);
+
+ return;
+
+} /* End of CFE_TIME_ExternalMET() */
+#endif /* CFE_PLATFORM_TIME_CFG_SRC_MET */
+
+/*
+ * Function: CFE_TIME_ExternalGPS - See API and header file for details
+ */
+#if (CFE_PLATFORM_TIME_CFG_SRC_GPS == true)
+void CFE_TIME_ExternalGPS(CFE_TIME_SysTime_t NewTime, int16 NewLeaps)
+{
+ /*
+ ** Process external GPS time data...
+ */
+ CFE_TIME_ToneSendGPS(NewTime, NewLeaps);
+
+ return;
+
+} /* End of CFE_TIME_ExternalGPS() */
+#endif /* CFE_PLATFORM_TIME_CFG_SRC_GPS */
+
+/*
+ * Function: CFE_TIME_ExternalTime - See API and header file for details
+ */
+#if (CFE_PLATFORM_TIME_CFG_SRC_TIME == true)
+void CFE_TIME_ExternalTime(CFE_TIME_SysTime_t NewTime)
+{
+ /*
+ ** Process external time data...
+ */
+ CFE_TIME_ToneSendTime(NewTime);
+
+ return;
+
+} /* End of CFE_TIME_ExternalTime() */
+#endif /* CFE_PLATFORM_TIME_CFG_SRC_TIME */
+
+/************************/
+/* End of File Comment */
+/************************/
diff --git a/modules/time/fsw/src/cfe_time_module_all.h b/modules/time/fsw/src/cfe_time_module_all.h
new file mode 100644
index 000000000..3fcf23d66
--- /dev/null
+++ b/modules/time/fsw/src/cfe_time_module_all.h
@@ -0,0 +1,48 @@
+/*
+** 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 TIME 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_TIME_MODULE_ALL_H
+#define CFE_TIME_MODULE_ALL_H
+
+/********************* Include Files ************************/
+
+#include "cfe.h" /* All CFE+OSAL public API definitions */
+#include "cfe_platform_cfg.h"
+
+#include "cfe_msgids.h"
+#include "cfe_perfids.h"
+
+#include "cfe_time_core_internal.h"
+
+#include "cfe_time_msg.h"
+#include "cfe_time_events.h"
+#include "cfe_time_utils.h"
+
+#endif /* CFE_TIME_MODULE_ALL_H */
diff --git a/modules/time/fsw/src/cfe_time_task.c b/modules/time/fsw/src/cfe_time_task.c
new file mode 100644
index 000000000..5994e31b7
--- /dev/null
+++ b/modules/time/fsw/src/cfe_time_task.c
@@ -0,0 +1,1438 @@
+/*
+** 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_time_task.c
+**
+** Subsystem: cFE TIME Task
+**
+** Author: S. Walling (Microtel)
+**
+** Notes:
+**
+*/
+
+/*
+** Required header files...
+*/
+#include "cfe_time_module_all.h"
+#include "cfe_version.h"
+
+/*
+** Time task global data...
+*/
+CFE_TIME_Global_t CFE_TIME_Global;
+
+/*
+** Command handler for "HK request"...
+*/
+int32 CFE_TIME_HousekeepingCmd(const CFE_MSG_CommandHeader_t *data);
+
+/*
+** Command handler for "tone signal detected"...
+*/
+int32 CFE_TIME_ToneSignalCmd(const CFE_TIME_ToneSignalCmd_t *data);
+
+/*
+** Command handler for "time at the tone"...
+*/
+int32 CFE_TIME_ToneDataCmd(const CFE_TIME_ToneDataCmd_t *data);
+
+/*
+** Command handler for 1Hz signal...
+*/
+int32 CFE_TIME_OneHzCmd(const CFE_TIME_1HzCmd_t *data);
+
+/*
+** Command handler for "request time at the tone"...
+**
+** Note: This command (sent by the scheduler) is used to
+** signal that now is the right time (in relation
+** to the "real" tone signal) for a Time Server to
+** send the "time at the tone" data packet. We do
+** not need (or want) this command if we are not a
+** Time Server.
+**
+** In "fake tone" mode this command is locally generated
+** however it is still sent via the software bus, thereby
+** utilizing (mostly) the same code path as the
+** non-fake tone mode.
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+int32 CFE_TIME_ToneSendCmd(const CFE_TIME_FakeToneCmd_t *data);
+#endif
+
+/*
+ * Ground command helper functions
+ */
+void CFE_TIME_SetDelayImpl(const CFE_TIME_TimeCmd_Payload_t *CommandPtr, CFE_TIME_AdjustDirection_Enum_t Direction);
+void CFE_TIME_1HzAdjImpl(const CFE_TIME_OneHzAdjustmentCmd_Payload_t *CommandPtr,
+ CFE_TIME_AdjustDirection_Enum_t Direction);
+void CFE_TIME_AdjustImpl(const CFE_TIME_TimeCmd_Payload_t *CommandPtr, CFE_TIME_AdjustDirection_Enum_t Direction);
+
+/*
+** Ground command handlers...
+*/
+int32 CFE_TIME_Add1HZAdjustmentCmd(const CFE_TIME_Add1HZAdjustmentCmd_t *data);
+int32 CFE_TIME_AddAdjustCmd(const CFE_TIME_AddAdjustCmd_t *data);
+int32 CFE_TIME_AddDelayCmd(const CFE_TIME_AddDelayCmd_t *data);
+int32 CFE_TIME_SendDiagnosticTlm(const CFE_TIME_SendDiagnosticCmd_t *data);
+int32 CFE_TIME_NoopCmd(const CFE_TIME_NoopCmd_t *data);
+int32 CFE_TIME_ResetCountersCmd(const CFE_TIME_ResetCountersCmd_t *data);
+int32 CFE_TIME_SetLeapSecondsCmd(const CFE_TIME_SetLeapSecondsCmd_t *data);
+int32 CFE_TIME_SetMETCmd(const CFE_TIME_SetMETCmd_t *data);
+int32 CFE_TIME_SetSignalCmd(const CFE_TIME_SetSignalCmd_t *data);
+int32 CFE_TIME_SetSourceCmd(const CFE_TIME_SetSourceCmd_t *data);
+int32 CFE_TIME_SetStateCmd(const CFE_TIME_SetStateCmd_t *data);
+int32 CFE_TIME_SetSTCFCmd(const CFE_TIME_SetSTCFCmd_t *data);
+int32 CFE_TIME_SetTimeCmd(const CFE_TIME_SetTimeCmd_t *data);
+int32 CFE_TIME_Sub1HZAdjustmentCmd(const CFE_TIME_Sub1HZAdjustmentCmd_t *data);
+int32 CFE_TIME_SubAdjustCmd(const CFE_TIME_SubAdjustCmd_t *data);
+int32 CFE_TIME_SubDelayCmd(const CFE_TIME_SubDelayCmd_t *data);
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_EarlyInit() -- API initialization before any tasks */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_EarlyInit(void)
+{
+ /*
+ ** Initialize global Time Services nonzero data...
+ */
+ CFE_TIME_InitData();
+
+ return (CFE_SUCCESS);
+
+} /* End of CFE_TIME_EarlyInit() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_TaskMain() -- Task entry point and main process loop */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_TaskMain(void)
+{
+ int32 Status;
+ CFE_SB_Buffer_t *SBBufPtr;
+
+ CFE_ES_PerfLogEntry(CFE_MISSION_TIME_MAIN_PERF_ID);
+
+ Status = CFE_TIME_TaskInit();
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Application Init Failed,RC=0x%08X\n", (unsigned int)Status);
+ CFE_ES_PerfLogExit(CFE_MISSION_TIME_MAIN_PERF_ID);
+ /* Note: CFE_ES_ExitApp will not return */
+ CFE_ES_ExitApp(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 loop */
+ while (Status == CFE_SUCCESS)
+ {
+
+ /* Increment the Main task Execution Counter */
+ CFE_ES_IncrementTaskCounter();
+
+ CFE_ES_PerfLogExit(CFE_MISSION_TIME_MAIN_PERF_ID);
+
+ /* Pend on receipt of packet */
+ Status = CFE_SB_ReceiveBuffer(&SBBufPtr, CFE_TIME_Global.CmdPipe, CFE_SB_PEND_FOREVER);
+
+ CFE_ES_PerfLogEntry(CFE_MISSION_TIME_MAIN_PERF_ID);
+
+ if (Status == CFE_SUCCESS)
+ {
+ /* Process cmd pipe msg */
+ CFE_TIME_TaskPipe(SBBufPtr);
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("TIME:Error reading cmd pipe,RC=0x%08X\n", (unsigned int)Status);
+ } /* end if */
+
+ } /* end while */
+
+ /* while loop exits only if CFE_SB_ReceiveBuffer returns error */
+ CFE_ES_ExitApp(CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR);
+
+} /* end CFE_TIME_TaskMain */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_TaskInit() -- Time task initialization */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_TaskInit(void)
+{
+ int32 Status;
+ osal_id_t TimeBaseId;
+ osal_id_t TimerId;
+
+ Status = CFE_EVS_Register(NULL, 0, 0);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Call to CFE_EVS_Register Failed:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = OS_BinSemCreate(&CFE_TIME_Global.ToneSemaphore, CFE_TIME_SEM_TONE_NAME, CFE_TIME_SEM_VALUE,
+ CFE_TIME_SEM_OPTIONS);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error creating tone semaphore:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = OS_BinSemCreate(&CFE_TIME_Global.LocalSemaphore, CFE_TIME_SEM_1HZ_NAME, CFE_TIME_SEM_VALUE,
+ CFE_TIME_SEM_OPTIONS);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error creating local semaphore:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_ES_CreateChildTask(&CFE_TIME_Global.ToneTaskID, CFE_TIME_TASK_TONE_NAME, CFE_TIME_Tone1HzTask,
+ CFE_TIME_TASK_STACK_PTR, CFE_PLATFORM_TIME_TONE_TASK_STACK_SIZE,
+ CFE_PLATFORM_TIME_TONE_TASK_PRIORITY, CFE_TIME_TASK_FLAGS);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error creating tone 1Hz child task:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_ES_CreateChildTask(&CFE_TIME_Global.LocalTaskID, CFE_TIME_TASK_1HZ_NAME, CFE_TIME_Local1HzTask,
+ CFE_TIME_TASK_STACK_PTR, CFE_PLATFORM_TIME_1HZ_TASK_STACK_SIZE,
+ CFE_PLATFORM_TIME_1HZ_TASK_PRIORITY, CFE_TIME_TASK_FLAGS);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error creating local 1Hz child task:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_SB_CreatePipe(&CFE_TIME_Global.CmdPipe, CFE_TIME_TASK_PIPE_DEPTH, CFE_TIME_TASK_PIPE_NAME);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error creating cmd pipe:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_TIME_SEND_HK_MID), CFE_TIME_Global.CmdPipe);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error subscribing to HK Request:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+/*
+** Subscribe to time at the tone "signal" commands...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_TIME_TONE_CMD_MID), CFE_TIME_Global.CmdPipe);
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ Status = CFE_SB_SubscribeLocal(CFE_SB_ValueToMsgId(CFE_TIME_TONE_CMD_MID), CFE_TIME_Global.CmdPipe, 4);
+#endif
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error subscribing to tone cmd:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+/*
+** Subscribe to time at the tone "data" commands...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_TIME_DATA_CMD_MID), CFE_TIME_Global.CmdPipe);
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ Status = CFE_SB_SubscribeLocal(CFE_SB_ValueToMsgId(CFE_TIME_DATA_CMD_MID), CFE_TIME_Global.CmdPipe, 4);
+#endif
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error subscribing to time data cmd:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+/*
+** Subscribe to 1Hz signal commands...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_TIME_1HZ_CMD_MID), CFE_TIME_Global.CmdPipe);
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ Status = CFE_SB_SubscribeLocal(CFE_SB_ValueToMsgId(CFE_TIME_1HZ_CMD_MID), CFE_TIME_Global.CmdPipe, 4);
+#endif
+
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error subscribing to fake tone signal cmds:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+/*
+** Subscribe to time at the tone "request data" commands...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_TIME_SEND_CMD_MID), CFE_TIME_Global.CmdPipe);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error subscribing to time at the tone request data cmds:RC=0x%08X\n",
+ (unsigned int)Status);
+ return Status;
+ } /* end if */
+#endif
+
+ /*
+ ** Subscribe to Time task ground command packets...
+ */
+ Status = CFE_SB_Subscribe(CFE_SB_ValueToMsgId(CFE_TIME_CMD_MID), CFE_TIME_Global.CmdPipe);
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error subscribing to time task gnd cmds:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+ Status = CFE_EVS_SendEvent(CFE_TIME_INIT_EID, CFE_EVS_EventType_INFORMATION, "cFE TIME Initialized");
+ if (Status != CFE_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:Error sending init event:RC=0x%08X\n", (unsigned int)Status);
+ return Status;
+ } /* end if */
+
+/*
+** Select primary vs redundant tone interrupt signal...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SIGNAL == true)
+ OS_SelectTone(CFE_TIME_Global.ClockSignal);
+#endif
+
+ /*
+ * Check to see if the OSAL in use implements the TimeBase API
+ * and if the PSP has set up a system time base. If so, then create
+ * a 1Hz callback based on that system time base. This call should
+ * return OS_ERR_NOT_IMPLEMENTED if the OSAL does not support this,
+ * or OS_ERR_NAME_NOT_FOUND if the PSP didn't set this up. Either
+ * way any error here means the PSP must use the "old way" and call
+ * the 1hz function directly.
+ */
+ Status = OS_TimeBaseGetIdByName(&TimeBaseId, "cFS-Master");
+ if (Status == OS_SUCCESS)
+ {
+ /* Create the 1Hz callback */
+ Status = OS_TimerAdd(&TimerId, "cFS-1Hz", TimeBaseId, CFE_TIME_Local1HzTimerCallback, NULL);
+ if (Status == OS_SUCCESS)
+ {
+ Status = OS_TimerSet(TimerId, 500000, 1000000);
+ if (Status != OS_SUCCESS)
+ {
+ CFE_ES_WriteToSysLog("TIME:1Hz OS_TimerSet failed:RC=0x%08X\n", (unsigned int)Status);
+ }
+ }
+ else
+ {
+ CFE_ES_WriteToSysLog("TIME:1Hz OS_TimerAdd failed:RC=0x%08X\n", (unsigned int)Status);
+ }
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_TaskInit() */
+
+/******************************************************************************
+** Function: CFE_TIME_VerifyCmdLength()
+**
+** Purpose:
+** Function to verify the length of incoming TIME command packets
+**
+** Arguments:
+** Message pointer and expected length
+**
+** Return:
+** true if length is acceptable
+*/
+bool CFE_TIME_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_TIME_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_TIME_Global.CommandErrorCounter;
+ }
+
+ return (result);
+
+} /* End of CFE_TIME_VerifyCmdLength() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_TaskPipe() -- Process command pipe message */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_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_TIME_SEND_HK_MID:
+ CFE_TIME_HousekeepingCmd((CFE_MSG_CommandHeader_t *)SBBufPtr);
+ break;
+
+ /*
+ ** Time at the tone "signal"...
+ */
+ case CFE_TIME_TONE_CMD_MID:
+ CFE_TIME_ToneSignalCmd((CFE_TIME_ToneSignalCmd_t *)SBBufPtr);
+ break;
+
+ /*
+ ** Time at the tone "data"...
+ */
+ case CFE_TIME_DATA_CMD_MID:
+ CFE_TIME_ToneDataCmd((CFE_TIME_ToneDataCmd_t *)SBBufPtr);
+ break;
+
+ /*
+ ** Run time state machine at 1Hz...
+ */
+ case CFE_TIME_1HZ_CMD_MID:
+ CFE_TIME_OneHzCmd((CFE_TIME_1HzCmd_t *)SBBufPtr);
+ break;
+
+/*
+** Request for time at the tone "data"...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ case CFE_TIME_SEND_CMD_MID:
+ CFE_TIME_ToneSendCmd((CFE_TIME_FakeToneCmd_t *)SBBufPtr);
+ break;
+#endif
+
+ /*
+ ** Time task ground commands...
+ */
+ case CFE_TIME_CMD_MID:
+
+ CFE_MSG_GetFcnCode(&SBBufPtr->Msg, &CommandCode);
+ switch (CommandCode)
+ {
+ case CFE_TIME_NOOP_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_NoopCmd_t)))
+ {
+ CFE_TIME_NoopCmd((CFE_TIME_NoopCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_RESET_COUNTERS_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_ResetCountersCmd_t)))
+ {
+ CFE_TIME_ResetCountersCmd((CFE_TIME_ResetCountersCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SEND_DIAGNOSTIC_TLM_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SendDiagnosticCmd_t)))
+ {
+ CFE_TIME_SendDiagnosticTlm((CFE_TIME_SendDiagnosticCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SET_STATE_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetStateCmd_t)))
+ {
+ CFE_TIME_SetStateCmd((CFE_TIME_SetStateCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SET_SOURCE_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetSourceCmd_t)))
+ {
+ CFE_TIME_SetSourceCmd((CFE_TIME_SetSourceCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SET_SIGNAL_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetSignalCmd_t)))
+ {
+ CFE_TIME_SetSignalCmd((CFE_TIME_SetSignalCmd_t *)SBBufPtr);
+ }
+ break;
+
+ /*
+ ** Time Clients process "tone delay" commands...
+ */
+ case CFE_TIME_ADD_DELAY_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_AddDelayCmd_t)))
+ {
+ CFE_TIME_AddDelayCmd((CFE_TIME_AddDelayCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SUB_DELAY_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SubDelayCmd_t)))
+ {
+ CFE_TIME_SubDelayCmd((CFE_TIME_SubDelayCmd_t *)SBBufPtr);
+ }
+ break;
+
+ /*
+ ** Time Servers process "set time" commands...
+ */
+ case CFE_TIME_SET_TIME_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetTimeCmd_t)))
+ {
+ CFE_TIME_SetTimeCmd((CFE_TIME_SetTimeCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SET_MET_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetMETCmd_t)))
+ {
+ CFE_TIME_SetMETCmd((CFE_TIME_SetMETCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SET_STCF_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetSTCFCmd_t)))
+ {
+ CFE_TIME_SetSTCFCmd((CFE_TIME_SetSTCFCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SET_LEAP_SECONDS_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetLeapSecondsCmd_t)))
+ {
+ CFE_TIME_SetLeapSecondsCmd((CFE_TIME_SetLeapSecondsCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_ADD_ADJUST_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_AddAdjustCmd_t)))
+ {
+ CFE_TIME_AddAdjustCmd((CFE_TIME_AddAdjustCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SUB_ADJUST_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SubAdjustCmd_t)))
+ {
+ CFE_TIME_SubAdjustCmd((CFE_TIME_SubAdjustCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_ADD_1HZ_ADJUSTMENT_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_Add1HZAdjustmentCmd_t)))
+ {
+ CFE_TIME_Add1HZAdjustmentCmd((CFE_TIME_Add1HZAdjustmentCmd_t *)SBBufPtr);
+ }
+ break;
+
+ case CFE_TIME_SUB_1HZ_ADJUSTMENT_CC:
+ if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_Sub1HZAdjustmentCmd_t)))
+ {
+ CFE_TIME_Sub1HZAdjustmentCmd((CFE_TIME_Sub1HZAdjustmentCmd_t *)SBBufPtr);
+ }
+ break;
+
+ default:
+
+ CFE_TIME_Global.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_CC_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Invalid command code -- ID = 0x%X, CC = %d",
+ (unsigned int)CFE_SB_MsgIdToValue(MessageID), (int)CommandCode);
+ break;
+ } /* switch (CFE_TIME_CMD_MID -- command code)*/
+ break;
+
+ default:
+
+ /*
+ ** Note: we only increment the command error counter when
+ ** processing CFE_TIME_CMD_MID commands...
+ */
+ CFE_EVS_SendEvent(CFE_TIME_ID_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid message ID -- ID = 0x%X",
+ (unsigned int)CFE_SB_MsgIdToValue(MessageID));
+ break;
+
+ } /* switch (message ID) */
+
+ return;
+
+} /* End of CFE_TIME_TaskPipe() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_HousekeepingCmd() -- On-board command (HK request) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_HousekeepingCmd(const CFE_MSG_CommandHeader_t *data)
+{
+ CFE_TIME_Reference_t Reference;
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** Update TIME portion of Critical Data Store...
+ */
+ CFE_TIME_UpdateResetVars(&Reference);
+
+ /*
+ ** Collect housekeeping data from Time Services utilities...
+ */
+ CFE_TIME_GetHkData(&Reference);
+
+ /*
+ ** Send housekeeping telemetry packet...
+ */
+ CFE_SB_TimeStampMsg(&CFE_TIME_Global.HkPacket.TlmHeader.Msg);
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.HkPacket.TlmHeader.Msg, true);
+
+ /*
+ ** Note: we only increment the command execution counter when
+ ** processing CFE_TIME_CMD_MID commands...
+ */
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_HousekeepingCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneSignalCmd() -- Time at tone command (signal) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_ToneSignalCmd(const CFE_TIME_ToneSignalCmd_t *data)
+{
+ /*
+ ** Indication that tone signal occurred recently...
+ */
+ CFE_TIME_ToneSignal();
+
+ /*
+ ** Note: we only increment the command execution counter when
+ ** processing CFE_TIME_CMD_MID commands...
+ */
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_ToneSignalCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneDataCmd() -- Time at tone command (data) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_ToneDataCmd(const CFE_TIME_ToneDataCmd_t *data)
+{
+ /*
+ ** This command packet contains "time at the tone" data...
+ */
+ CFE_TIME_ToneData(&data->Payload);
+
+ /*
+ ** Note: we only increment the command execution counter when
+ ** processing CFE_TIME_CMD_MID commands...
+ */
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_ToneDataCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * CFE_TIME_OneHzCmd() -- Execute state machine tasks required at 1Hz
+ *
+ * Service the "1Hz" notification message, and perform any state machine
+ * tasks that are intended to be executed at local 1Hz intervals.
+ *
+ * This also implements the "fake tone" functionality when that is enabled,
+ * as we do not need a separate MID for this job.
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_TIME_OneHzCmd(const CFE_TIME_1HzCmd_t *data)
+{
+ /*
+ * Run the state machine updates required at 1Hz.
+ *
+ * This task used to be performed as part of the 1Hz ISR, but this was unsafe on SMP
+ * as the updates cannot be synchronized with the command handlers in this environment
+ */
+ CFE_TIME_Local1HzStateMachine();
+
+#if (CFE_MISSION_TIME_CFG_FAKE_TONE == true)
+ /*
+ ** Fake the call-back from the "real" h/w ISR...
+ */
+ CFE_TIME_Tone1HzISR();
+#endif /* CFE_MISSION_TIME_CFG_FAKE_TONE */
+
+ /*
+ ** Note: we only increment the command execution counter when
+ ** processing CFE_TIME_CMD_MID commands...
+ */
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_OneHzCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneSendCmd() -- Time at tone command (send data) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+int32 CFE_TIME_ToneSendCmd(const CFE_TIME_FakeToneCmd_t *data)
+{
+ /*
+ ** Request for "time at tone" data packet (probably scheduler)...
+ */
+ CFE_TIME_ToneSend();
+
+ /*
+ ** Note: we only increment the command execution counter when
+ ** processing CFE_TIME_CMD_MID commands...
+ */
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SendCmd() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_NoopCmd() -- Time task ground command (NO-OP) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_NoopCmd(const CFE_TIME_NoopCmd_t *data)
+{
+
+ CFE_TIME_Global.CommandCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_NOOP_EID, CFE_EVS_EventType_INFORMATION, "No-op command.%s", CFE_VERSION_STRING);
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_NoopCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ResetCountersCmd() -- Time task ground command (reset counters)*/
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_ResetCountersCmd(const CFE_TIME_ResetCountersCmd_t *data)
+{
+
+ CFE_TIME_Global.CommandCounter = 0;
+ CFE_TIME_Global.CommandErrorCounter = 0;
+
+ CFE_TIME_Global.ToneMatchCounter = 0;
+ CFE_TIME_Global.ToneMatchErrorCounter = 0;
+
+ CFE_TIME_Global.ToneSignalCounter = 0;
+ CFE_TIME_Global.ToneDataCounter = 0;
+
+ CFE_TIME_Global.ToneIntCounter = 0;
+ CFE_TIME_Global.ToneIntErrorCounter = 0;
+ CFE_TIME_Global.ToneTaskCounter = 0;
+
+ /*
+ * Note: Not resetting "LastVersion" counter here, that might
+ * disturb access to the time reference data by other tasks
+ */
+ CFE_TIME_Global.ResetVersionCounter = CFE_TIME_Global.LastVersionCounter;
+
+ CFE_TIME_Global.LocalIntCounter = 0;
+ CFE_TIME_Global.LocalTaskCounter = 0;
+
+ CFE_TIME_Global.InternalCount = 0;
+ CFE_TIME_Global.ExternalCount = 0;
+
+ CFE_EVS_SendEvent(CFE_TIME_RESET_EID, CFE_EVS_EventType_DEBUG, "Reset Counters command");
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_ResetCountersCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_DiagCmd() -- Time task ground command (diagnostics) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SendDiagnosticTlm(const CFE_TIME_SendDiagnosticCmd_t *data)
+{
+ CFE_TIME_Global.CommandCounter++;
+
+ /*
+ ** Collect diagnostics data from Time Services utilities...
+ */
+ CFE_TIME_GetDiagData();
+
+ /*
+ ** Send diagnostics telemetry packet...
+ */
+ CFE_SB_TimeStampMsg(&CFE_TIME_Global.DiagPacket.TlmHeader.Msg);
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.DiagPacket.TlmHeader.Msg, true);
+
+ CFE_EVS_SendEvent(CFE_TIME_DIAG_EID, CFE_EVS_EventType_DEBUG, "Request diagnostics command");
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_DiagCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetStateCmd() -- Time task command (set clock state) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SetStateCmd(const CFE_TIME_SetStateCmd_t *data)
+{
+ const CFE_TIME_StateCmd_Payload_t *CommandPtr = &data->Payload;
+ const char * ClockStateText;
+
+ /*
+ ** Verify command argument value (clock state)...
+ */
+ if ((CommandPtr->ClockState == CFE_TIME_ClockState_INVALID) ||
+ (CommandPtr->ClockState == CFE_TIME_ClockState_VALID) ||
+ (CommandPtr->ClockState == CFE_TIME_ClockState_FLYWHEEL))
+ {
+ CFE_TIME_SetState(CommandPtr->ClockState);
+
+ /*
+ ** Select appropriate text for event message...
+ */
+ if (CommandPtr->ClockState == CFE_TIME_ClockState_INVALID)
+ {
+ ClockStateText = "INVALID";
+ }
+ else if (CommandPtr->ClockState == CFE_TIME_ClockState_VALID)
+ {
+ ClockStateText = "VALID";
+ }
+ else
+ {
+ ClockStateText = "FLYWHEEL";
+ }
+
+ CFE_TIME_Global.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_STATE_EID, CFE_EVS_EventType_INFORMATION, "Set Clock State = %s", ClockStateText);
+ }
+ else
+ {
+ CFE_TIME_Global.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_STATE_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid Clock State = 0x%X",
+ (unsigned int)CommandPtr->ClockState);
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SetStateCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetSourceCmd() -- Time task command (set time source) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SetSourceCmd(const CFE_TIME_SetSourceCmd_t *data)
+{
+ const CFE_TIME_SourceCmd_Payload_t *CommandPtr = &data->Payload;
+
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+ const char *TimeSourceText;
+#endif
+
+ /*
+ ** Verify command argument value (time data source)...
+ */
+ if ((CommandPtr->TimeSource == CFE_TIME_SourceSelect_INTERNAL) ||
+ (CommandPtr->TimeSource == CFE_TIME_SourceSelect_EXTERNAL))
+ {
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+ /*
+ ** Only systems configured to select source of time data...
+ */
+ CFE_TIME_Global.CommandCounter++;
+
+ CFE_TIME_SetSource(CommandPtr->TimeSource);
+
+ /*
+ ** Select appropriate text for event message...
+ */
+ if (CommandPtr->TimeSource == CFE_TIME_SourceSelect_INTERNAL)
+ {
+ TimeSourceText = "INTERNAL";
+ }
+ else
+ {
+ TimeSourceText = "EXTERNAL";
+ }
+
+ CFE_EVS_SendEvent(CFE_TIME_SOURCE_EID, CFE_EVS_EventType_INFORMATION, "Set Time Source = %s", TimeSourceText);
+
+#else /* not CFE_PLATFORM_TIME_CFG_SOURCE */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_SOURCE_CFG_EID, CFE_EVS_EventType_ERROR,
+ "Set Source commands invalid without CFE_PLATFORM_TIME_CFG_SOURCE set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SOURCE */
+ }
+ else
+ {
+ /*
+ ** Ground system database will prevent most of these errors...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_SOURCE_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid Time Source = 0x%X",
+ (unsigned int)CommandPtr->TimeSource);
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SetSourceCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetSignalCmd() -- Time task command (set tone source) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int32 CFE_TIME_SetSignalCmd(const CFE_TIME_SetSignalCmd_t *data)
+{
+ const CFE_TIME_SignalCmd_Payload_t *CommandPtr = &data->Payload;
+
+#if (CFE_PLATFORM_TIME_CFG_SIGNAL == true)
+ const char *ToneSourceText;
+#endif
+
+ /*
+ ** Verify command argument value (tone source)...
+ */
+ if ((CommandPtr->ToneSource == CFE_TIME_ToneSignalSelect_PRIMARY) ||
+ (CommandPtr->ToneSource == CFE_TIME_ToneSignalSelect_REDUNDANT))
+ {
+#if (CFE_PLATFORM_TIME_CFG_SIGNAL == true)
+ /*
+ ** Only systems configured to select tone signal...
+ */
+ CFE_TIME_Global.CommandCounter++;
+
+ CFE_TIME_SetSignal(CommandPtr->ToneSource);
+
+ /*
+ ** Select appropriate text for event message...
+ */
+ if (CommandPtr->ToneSource == CFE_TIME_ToneSignalSelect_PRIMARY)
+ {
+ ToneSourceText = "PRIMARY";
+ }
+ else
+ {
+ ToneSourceText = "REDUNDANT";
+ }
+
+ CFE_EVS_SendEvent(CFE_TIME_SIGNAL_EID, CFE_EVS_EventType_INFORMATION, "Set Tone Source = %s", ToneSourceText);
+
+#else /* not CFE_PLATFORM_TIME_CFG_SIGNAL */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_SIGNAL_CFG_EID, CFE_EVS_EventType_ERROR,
+ "Set Signal commands invalid without CFE_PLATFORM_TIME_CFG_SIGNAL set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SIGNAL */
+ }
+ else
+ {
+ /*
+ ** Ground system database will prevent most of these errors...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_SIGNAL_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid Tone Source = 0x%X",
+ (unsigned int)CommandPtr->ToneSource);
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SetSignalCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetDelayImpl() -- Time task ground command (tone delay)*/
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_SetDelayImpl(const CFE_TIME_TimeCmd_Payload_t *CommandPtr, CFE_TIME_AdjustDirection_Enum_t Direction)
+{
+ /*
+ ** Verify "micro-seconds" command argument...
+ */
+ if (CommandPtr->MicroSeconds < 1000000)
+ {
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+
+ CFE_TIME_SysTime_t Delay;
+
+ Delay.Seconds = CommandPtr->Seconds;
+ Delay.Subseconds = CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds);
+
+ CFE_TIME_SetDelay(Delay, Direction);
+
+ CFE_TIME_Global.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_DELAY_EID, CFE_EVS_EventType_INFORMATION,
+ "Set Tone Delay -- secs = %u, usecs = %u, ssecs = 0x%X, dir = %d",
+ (unsigned int)CommandPtr->Seconds, (unsigned int)CommandPtr->MicroSeconds,
+ (unsigned int)CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds), (int)Direction);
+
+#else /* not CFE_PLATFORM_TIME_CFG_CLIENT */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_DELAY_CFG_EID, CFE_EVS_EventType_ERROR,
+ "Set Delay commands invalid without CFE_PLATFORM_TIME_CFG_CLIENT set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_CLIENT */
+ }
+ else
+ {
+ CFE_TIME_Global.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_DELAY_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Invalid Tone Delay -- secs = %u, usecs = %u", (unsigned int)CommandPtr->Seconds,
+ (unsigned int)CommandPtr->MicroSeconds);
+ }
+
+} /* End of CFE_TIME_SetDelayImpl() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_AddSubDelayCmd() -- Time task ground command (tone delay) */
+/* */
+/* Wrapper around CFE_TIME_SetDelayImpl() for add/subtract operations */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_AddDelayCmd(const CFE_TIME_AddDelayCmd_t *data)
+{
+ CFE_TIME_SetDelayImpl(&data->Payload, CFE_TIME_AdjustDirection_ADD);
+ return CFE_SUCCESS;
+}
+int32 CFE_TIME_SubDelayCmd(const CFE_TIME_SubDelayCmd_t *data)
+{
+ CFE_TIME_SetDelayImpl(&data->Payload, CFE_TIME_AdjustDirection_SUBTRACT);
+ return CFE_SUCCESS;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetTimeCmd() -- Time task ground command (calc STCF) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SetTimeCmd(const CFE_TIME_SetTimeCmd_t *data)
+{
+ const CFE_TIME_TimeCmd_Payload_t *CommandPtr = &data->Payload;
+
+ /*
+ ** Verify "micro-seconds" command argument...
+ */
+ if (CommandPtr->MicroSeconds < 1000000)
+ {
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+
+ CFE_TIME_SysTime_t NewTime;
+
+ NewTime.Seconds = CommandPtr->Seconds;
+ NewTime.Subseconds = CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds);
+
+ CFE_TIME_SetTime(NewTime);
+
+ CFE_TIME_Global.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_TIME_EID, CFE_EVS_EventType_INFORMATION,
+ "Set Time -- secs = %u, usecs = %u, ssecs = 0x%X", (unsigned int)CommandPtr->Seconds,
+ (unsigned int)CommandPtr->MicroSeconds,
+ (unsigned int)CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds));
+
+#else /* not CFE_PLATFORM_TIME_CFG_SERVER */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_TIME_CFG_EID, CFE_EVS_EventType_ERROR,
+ "Set Time commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+ }
+ else
+ {
+ CFE_TIME_Global.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_TIME_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid Time -- secs = %u, usecs = %u",
+ (unsigned int)CommandPtr->Seconds, (unsigned int)CommandPtr->MicroSeconds);
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SetTimeCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetMETCmd() -- Time task ground command (set MET) */
+/* */
+/* Note: This command will not have lasting effect if configured */
+/* to get external time of type MET. Also, there cannot */
+/* be a local h/w MET and an external MET since both would */
+/* need to be synchronized to the same tone signal. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SetMETCmd(const CFE_TIME_SetMETCmd_t *data)
+{
+ const CFE_TIME_TimeCmd_Payload_t *CommandPtr = &data->Payload;
+
+ /*
+ ** Verify "micro-seconds" command argument...
+ */
+ if (CommandPtr->MicroSeconds < 1000000)
+ {
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+
+ CFE_TIME_SysTime_t NewMET;
+
+ NewMET.Seconds = CommandPtr->Seconds;
+ NewMET.Subseconds = CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds);
+
+ CFE_TIME_SetMET(NewMET);
+
+ CFE_TIME_Global.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_MET_EID, CFE_EVS_EventType_INFORMATION,
+ "Set MET -- secs = %u, usecs = %u, ssecs = 0x%X", (unsigned int)CommandPtr->Seconds,
+ (unsigned int)CommandPtr->MicroSeconds,
+ (unsigned int)CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds));
+
+#else /* not CFE_PLATFORM_TIME_CFG_SERVER */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_MET_CFG_EID, CFE_EVS_EventType_ERROR,
+ "Set MET commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+ }
+ else
+ {
+ CFE_TIME_Global.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_MET_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid MET -- secs = %u, usecs = %u",
+ (unsigned int)CommandPtr->Seconds, (unsigned int)CommandPtr->MicroSeconds);
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SetMETCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetSTCFCmd() -- Time task ground command (set STCF) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SetSTCFCmd(const CFE_TIME_SetSTCFCmd_t *data)
+{
+ const CFE_TIME_TimeCmd_Payload_t *CommandPtr = &data->Payload;
+
+ /*
+ ** Verify "micro-seconds" command argument...
+ */
+ if (CommandPtr->MicroSeconds < 1000000)
+ {
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+
+ CFE_TIME_SysTime_t NewSTCF;
+
+ NewSTCF.Seconds = CommandPtr->Seconds;
+ NewSTCF.Subseconds = CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds);
+
+ CFE_TIME_SetSTCF(NewSTCF);
+
+ CFE_TIME_Global.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_STCF_EID, CFE_EVS_EventType_INFORMATION,
+ "Set STCF -- secs = %u, usecs = %u, ssecs = 0x%X", (unsigned int)CommandPtr->Seconds,
+ (unsigned int)CommandPtr->MicroSeconds,
+ (unsigned int)CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds));
+
+#else /* not CFE_PLATFORM_TIME_CFG_SERVER */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_STCF_CFG_EID, CFE_EVS_EventType_ERROR,
+ "Set STCF commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+ }
+ else
+ {
+ CFE_TIME_Global.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_STCF_ERR_EID, CFE_EVS_EventType_ERROR, "Invalid STCF -- secs = %u, usecs = %u",
+ (unsigned int)CommandPtr->Seconds, (unsigned int)CommandPtr->MicroSeconds);
+ }
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SetSTCFCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetLeapSecondsCmd() -- Time task ground command (set leaps) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SetLeapSecondsCmd(const CFE_TIME_SetLeapSecondsCmd_t *data)
+{
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+
+ const CFE_TIME_LeapsCmd_Payload_t *CommandPtr = &data->Payload;
+
+ /*
+ ** No value checking (leaps may be positive or negative)...
+ */
+ CFE_TIME_SetLeapSeconds(CommandPtr->LeapSeconds);
+
+ CFE_TIME_Global.CommandCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_LEAPS_EID, CFE_EVS_EventType_INFORMATION, "Set Leap Seconds = %d",
+ (int)CommandPtr->LeapSeconds);
+
+#else /* not CFE_PLATFORM_TIME_CFG_SERVER */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_LEAPS_CFG_EID, CFE_EVS_EventType_ERROR,
+ "Set Leaps commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+ return CFE_SUCCESS;
+
+} /* End of CFE_TIME_SetLeapSecondsCmd() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_AdjustImpl() -- Time task ground command (adjust STCF) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_AdjustImpl(const CFE_TIME_TimeCmd_Payload_t *CommandPtr, CFE_TIME_AdjustDirection_Enum_t Direction)
+{
+ /*
+ ** Verify command arguments...
+ */
+ if (CommandPtr->MicroSeconds < 1000000)
+ {
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+
+ CFE_TIME_SysTime_t Adjust;
+
+ Adjust.Seconds = CommandPtr->Seconds;
+ Adjust.Subseconds = CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds);
+
+ CFE_TIME_SetAdjust(Adjust, Direction);
+
+ CFE_TIME_Global.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_DELTA_EID, CFE_EVS_EventType_INFORMATION,
+ "STCF Adjust -- secs = %u, usecs = %u, ssecs = 0x%X, dir[1=Pos, 2=Neg] = %d",
+ (unsigned int)CommandPtr->Seconds, (unsigned int)CommandPtr->MicroSeconds,
+ (unsigned int)CFE_TIME_Micro2SubSecs(CommandPtr->MicroSeconds), (int)Direction);
+
+#else /* not CFE_PLATFORM_TIME_CFG_SERVER */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_DELTA_CFG_EID, CFE_EVS_EventType_ERROR,
+ "STCF Adjust commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+ }
+ else
+ {
+ CFE_TIME_Global.CommandErrorCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_DELTA_ERR_EID, CFE_EVS_EventType_ERROR,
+ "Invalid STCF Adjust -- secs = %u, usecs = %u, dir[1=Pos, 2=Neg] = %d",
+ (unsigned int)CommandPtr->Seconds, (unsigned int)CommandPtr->MicroSeconds, (int)Direction);
+ }
+
+} /* End of CFE_TIME_AdjustImpl() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_AddAdjustCmd() -- Time task ground command (1Hz adjust) */
+/* */
+/* This is a wrapper around CFE_TIME_AdjustImpl() */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_AddAdjustCmd(const CFE_TIME_AddAdjustCmd_t *data)
+{
+ CFE_TIME_AdjustImpl(&data->Payload, CFE_TIME_AdjustDirection_ADD);
+ return CFE_SUCCESS;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SubAdjustCmd() -- Time task ground command (1Hz adjust) */
+/* */
+/* This is a wrapper around CFE_TIME_AdjustImpl() */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_SubAdjustCmd(const CFE_TIME_SubAdjustCmd_t *data)
+{
+ CFE_TIME_AdjustImpl(&data->Payload, CFE_TIME_AdjustDirection_SUBTRACT);
+ return CFE_SUCCESS;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_1HzAdjImpl() -- Time task ground command (1Hz adjust) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_1HzAdjImpl(const CFE_TIME_OneHzAdjustmentCmd_Payload_t *CommandPtr,
+ CFE_TIME_AdjustDirection_Enum_t Direction)
+{
+/*
+** 1Hz adjustments are only valid for "Time Servers"...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+
+ CFE_TIME_SysTime_t Adjust;
+
+ CFE_TIME_Copy(&Adjust, CommandPtr);
+
+ CFE_TIME_Set1HzAdj(Adjust, Direction);
+
+ CFE_TIME_Global.CommandCounter++;
+ CFE_EVS_SendEvent(CFE_TIME_1HZ_EID, CFE_EVS_EventType_INFORMATION,
+ "STCF 1Hz Adjust -- secs = %d, ssecs = 0x%X, dir[1=Pos, 2=Neg] = %d", (int)CommandPtr->Seconds,
+ (unsigned int)CommandPtr->Subseconds, (int)Direction);
+
+#else /* not CFE_PLATFORM_TIME_CFG_SERVER */
+ /*
+ ** We want to know if disabled commands are being sent...
+ */
+ CFE_TIME_Global.CommandErrorCounter++;
+
+ CFE_EVS_SendEvent(CFE_TIME_1HZ_CFG_EID, CFE_EVS_EventType_ERROR,
+ "1Hz Adjust commands invalid without CFE_PLATFORM_TIME_CFG_SERVER set to TRUE");
+
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+} /* End of CFE_TIME_1HzAdjImpl() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Add1HZAdjustmentCmd() -- Time task ground command (1Hz adjust) */
+/* */
+/* This is a wrapper around CFE_TIME_1HzAdjImpl() */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_Add1HZAdjustmentCmd(const CFE_TIME_Add1HZAdjustmentCmd_t *data)
+{
+ CFE_TIME_1HzAdjImpl(&data->Payload, CFE_TIME_AdjustDirection_ADD);
+ return CFE_SUCCESS;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Sub1HZAdjustmentCmd() -- Time task ground command (1Hz adjust) */
+/* */
+/* This is a wrapper around CFE_TIME_1HzAdjImpl() */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_Sub1HZAdjustmentCmd(const CFE_TIME_Sub1HZAdjustmentCmd_t *data)
+{
+ CFE_TIME_1HzAdjImpl(&data->Payload, CFE_TIME_AdjustDirection_SUBTRACT);
+ return CFE_SUCCESS;
+}
+
+/************************/
+/* End of File Comment */
+/************************/
diff --git a/modules/time/fsw/src/cfe_time_tone.c b/modules/time/fsw/src/cfe_time_tone.c
new file mode 100644
index 000000000..d03de6225
--- /dev/null
+++ b/modules/time/fsw/src/cfe_time_tone.c
@@ -0,0 +1,1433 @@
+/*
+** 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_time_tone.c
+**
+** Purpose: cFE Time Services (TIME) library utilities source file
+**
+** Author: S.Walling/Microtel
+**
+** Notes: This module was created from a portion of the source file
+** "cfe_time_utils.c" because that file had grown too large.
+**
+** This module contains functions related to the detection
+** and processing of the "time at the tone" event signal.
+**
+** This module contains functions related to the detection
+** and processing of the local 1Hz interrupt.
+**
+*/
+
+/*
+** Required header files...
+*/
+#include "cfe_time_module_all.h"
+
+#include
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneSend() -- Send "time at the tone" (local time) */
+/* */
+/* There is a presumption that this function will be called at */
+/* the appropriate time (relative to the tone) such that the */
+/* "time at the tone" data command will arrive within the */
+/* specified window for tone and data packet verification. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_ToneSend(void)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t NewMET;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** Get the new MET from the appropriate source...
+ */
+ if (Reference.ClockFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ /*
+ ** At least one of the following conditions is true...
+ **
+ ** 1) loss of tone signal
+ ** 2) loss of "time at the tone" data packet
+ ** 3) signal and packet not within valid window
+ ** 4) we were commanded into fly-wheel mode
+ **
+ ** Set the new MET to our fly-wheel best guess...
+ */
+ NewMET.Seconds = Reference.CurrentMET.Seconds;
+ }
+ else
+ {
+/*
+** MET seconds is the count of tone interrupts...
+*/
+#if (CFE_PLATFORM_TIME_CFG_VIRTUAL == true)
+ NewMET.Seconds = CFE_TIME_Global.VirtualMET;
+#endif
+
+/*
+** Read MET seconds from a h/w register...
+*/
+#if (CFE_PLATFORM_TIME_CFG_VIRTUAL != true)
+ OS_GetLocalMET(&NewMET.Seconds);
+#endif
+ }
+
+/*
+** Add a second if the tone has not yet occurred...
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+ NewMET.Seconds++;
+#endif
+
+ /*
+ ** Need to fix this if the tone is not 1Hz...
+ */
+ NewMET.Subseconds = 0;
+
+ /*
+ ** Current clock state is a combination of factors...
+ */
+
+#ifdef CFE_PLATFORM_TIME_CFG_BIGENDIAN
+
+ /*
+ ** Current clock state is a combination of factors...
+ */
+ uint16 AtToneState = CFE_TIME_CalculateState(&Reference);
+
+ /*
+ ** Payload must be big-endian.
+ */
+
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Seconds = CFE_MAKE_BIG32(NewMET.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Subseconds = CFE_MAKE_BIG32(NewMET.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Seconds = CFE_MAKE_BIG32(Reference.AtToneSTCF.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Subseconds = CFE_MAKE_BIG32(Reference.AtToneSTCF.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = CFE_MAKE_BIG16(Reference.AtToneLeapSeconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = CFE_MAKE_BIG16(AtToneState);
+
+#else /* !CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ /*
+ ** Remainder of time values are unchanged...
+ */
+ CFE_TIME_Copy(&CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET, &NewMET);
+ CFE_TIME_Copy(&CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF, &Reference.AtToneSTCF);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = Reference.AtToneLeapSeconds;
+
+ /*
+ ** Current clock state is a combination of factors...
+ */
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = CFE_TIME_CalculateState(&Reference);
+
+#endif /* CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ /*
+ ** Send "time at the tone" command data packet...
+ */
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.ToneDataCmd.CmdHeader.Msg, false);
+
+ /*
+ ** Count of "time at the tone" commands sent with internal data...
+ */
+ CFE_TIME_Global.InternalCount++;
+
+ return;
+
+} /* End of CFE_TIME_ToneSend() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneSendMET() -- Send "time at tone" (external MET) */
+/* */
+/* There is a presumption that this function will be called at */
+/* the appropriate time (relative to the tone) such that the */
+/* "time at the tone" data command will arrive within the */
+/* specified window for tone and data packet verification. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SRC_MET == true)
+int32 CFE_TIME_ToneSendMET(CFE_TIME_SysTime_t NewMET)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t Expected;
+ CFE_TIME_SysTime_t MinValid;
+ CFE_TIME_SysTime_t MaxValid;
+ CFE_TIME_Compare_t MinResult;
+ CFE_TIME_Compare_t MaxResult;
+
+ int16 ClockState;
+ int32 Result = CFE_SUCCESS;
+
+ /* Start Performance Monitoring */
+ CFE_ES_PerfLogEntry(CFE_MISSION_TIME_SENDMET_PERF_ID);
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Ignore external time data if commanded to use local MET...
+ */
+ if (CFE_TIME_Global.ClockSource == CFE_TIME_SourceSelect_INTERNAL)
+ {
+ Result = CFE_TIME_INTERNAL_ONLY;
+
+ /*
+ ** Use internal clock but still send "time at the tone"...
+ */
+ CFE_TIME_ToneSend();
+ }
+ else
+ {
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** cFE defines MET as being synchronized to the tone signal...
+ */
+ Expected.Seconds = Reference.CurrentMET.Seconds;
+ Expected.Subseconds = 0;
+
+/*
+** Add a second if the tone has not yet occurred...
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+ Expected.Seconds++;
+#endif
+
+ /*
+ ** Compute minimum and maximum values for valid MET...
+ */
+ MinValid = CFE_TIME_Subtract(Expected, CFE_TIME_Global.MaxDelta);
+ MaxValid = CFE_TIME_Add(Expected, CFE_TIME_Global.MaxDelta);
+
+ /*
+ ** Compare new MET to minimum and maximum MET...
+ */
+ MinResult = CFE_TIME_Compare(NewMET, MinValid);
+ MaxResult = CFE_TIME_Compare(NewMET, MaxValid);
+
+ /*
+ ** Ignore bad external time data only if clock state is valid...
+ */
+ if ((Reference.ClockSetState == CFE_TIME_SetState_WAS_SET) &&
+ ((MinResult == CFE_TIME_A_LT_B) || (MaxResult == CFE_TIME_A_GT_B)))
+ {
+ Result = CFE_TIME_OUT_OF_RANGE;
+
+ /*
+ ** Use internal clock but still send "time at the tone"...
+ */
+ CFE_TIME_ToneSend();
+ }
+ else
+ {
+ ClockState = CFE_TIME_CalculateState(&Reference);
+
+ /*
+ ** Set "time at the tone" command data packet arguments...
+ */
+
+#ifdef CFE_PLATFORM_TIME_CFG_BIGENDIAN
+
+ /*
+ ** Payload must be big-endian.
+ */
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Seconds = CFE_MAKE_BIG32(NewMET.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Subseconds = CFE_MAKE_BIG32(NewMET.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Seconds = CFE_MAKE_BIG32(Reference.AtToneSTCF.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Subseconds = CFE_MAKE_BIG32(Reference.AtToneSTCF.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = CFE_MAKE_BIG16(Reference.AtToneLeapSeconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = CFE_MAKE_BIG16(ClockState);
+
+#else /* !CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET = NewMET;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF = Reference.AtToneSTCF;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = Reference.AtToneLeapSeconds;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = ClockState;
+
+#endif /* CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ /*
+ ** Send "time at the tone" command data packet...
+ */
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.ToneDataCmd.CmdHeader.Msg, false);
+
+ /*
+ ** Count of "time at the tone" commands sent with external data...
+ */
+ CFE_TIME_Global.ExternalCount++;
+ }
+ }
+
+ /* Exit performance monitoring */
+ CFE_ES_PerfLogExit(CFE_MISSION_TIME_SENDMET_PERF_ID);
+ return (Result);
+
+} /* End of CFE_TIME_ToneSendMET() */
+#endif /* CFE_PLATFORM_TIME_CFG_SRC_MET */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneSendGPS() -- Send "time at tone" (external GPS) */
+/* */
+/* There is a presumption that this function will be called at */
+/* the appropriate time (relative to the tone) such that the */
+/* "time at the tone" data command will arrive within the */
+/* specified window for tone and data packet verification. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SRC_GPS == true)
+int32 CFE_TIME_ToneSendGPS(CFE_TIME_SysTime_t NewTime, int16 NewLeaps)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t NewSTCF;
+ CFE_TIME_SysTime_t NewMET;
+ CFE_TIME_SysTime_t MinValid;
+ CFE_TIME_SysTime_t MaxValid;
+ CFE_TIME_Compare_t MinResult;
+ CFE_TIME_Compare_t MaxResult;
+
+ int16 ClockState;
+ int32 Result = CFE_SUCCESS;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Ignore external time data if commanded to use local MET...
+ */
+ if (CFE_TIME_Global.ClockSource == CFE_TIME_SourceSelect_INTERNAL)
+ {
+ Result = CFE_TIME_INTERNAL_ONLY;
+
+ /*
+ ** Use internal clock but still send "time at the tone"...
+ */
+ CFE_TIME_ToneSend();
+ }
+ else
+ {
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** cFE defines MET as being synchronized to the tone signal...
+ */
+ NewMET.Seconds = Reference.CurrentMET.Seconds;
+ NewMET.Subseconds = 0;
+
+/*
+** Add a second if the tone has not yet occurred...
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+ NewMET.Seconds++;
+#endif
+
+ /*
+ ** Remove MET from the new time value (leaves STCF)...
+ */
+ NewSTCF = CFE_TIME_Subtract(NewTime, NewMET);
+
+/*
+** Restore leap seconds if default time format is UTC...
+*/
+#if (CFE_MISSION_TIME_CFG_DEFAULT_UTC == true)
+ NewSTCF.Seconds += NewLeaps;
+#endif
+
+ /*
+ ** Compute minimum and maximum values for valid STCF...
+ */
+ MinValid = CFE_TIME_Subtract(Reference.AtToneSTCF, CFE_TIME_Global.MaxDelta);
+ MaxValid = CFE_TIME_Add(Reference.AtToneSTCF, CFE_TIME_Global.MaxDelta);
+
+ /*
+ ** Compare new STCF to minimum and maximum STCF...
+ */
+ MinResult = CFE_TIME_Compare(NewSTCF, MinValid);
+ MaxResult = CFE_TIME_Compare(NewSTCF, MaxValid);
+
+ /*
+ ** If state is valid then ignore bad external time data...
+ */
+ if ((Reference.ClockSetState == CFE_TIME_SetState_WAS_SET) &&
+ ((MinResult == CFE_TIME_A_LT_B) || (MaxResult == CFE_TIME_A_GT_B)))
+ {
+ Result = CFE_TIME_OUT_OF_RANGE;
+
+ /*
+ ** Use internal clock but still send "time at the tone"...
+ */
+ CFE_TIME_ToneSend();
+ }
+ else
+ {
+ ClockState = CFE_TIME_CalculateState(&Reference);
+ /*
+ ** Set "time at the tone" command data packet arguments...
+ */
+
+#ifdef CFE_PLATFORM_TIME_CFG_BIGENDIAN
+
+ /*
+ ** Payload must be big-endian.
+ */
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Seconds = CFE_MAKE_BIG32(NewMET.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Subseconds = CFE_MAKE_BIG32(NewMET.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Seconds = CFE_MAKE_BIG32(NewSTCF.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Subseconds = CFE_MAKE_BIG32(NewSTCF.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = CFE_MAKE_BIG16(NewLeaps);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = CFE_MAKE_BIG16(ClockState);
+
+#else /* !CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET = NewMET;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF = NewSTCF;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = NewLeaps;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = ClockState;
+
+#endif /* CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ /*
+ ** Send "time at the tone" command data packet...
+ */
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.ToneDataCmd.CmdHeader.Msg, false);
+
+ /*
+ ** Count of "time at the tone" commands sent with external data...
+ */
+ CFE_TIME_Global.ExternalCount++;
+ }
+ }
+
+ return (Result);
+
+} /* End of CFE_TIME_ToneSendGPS() */
+#endif /* CFE_PLATFORM_TIME_CFG_SRC_GPS */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneSendTime() -- Send "time at tone" (external time) */
+/* */
+/* There is a presumption that this function will be called at */
+/* the appropriate time (relative to the tone) such that the */
+/* "time at the tone" data command will arrive within the */
+/* specified window for tone and data packet verification. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SRC_TIME == true)
+int32 CFE_TIME_ToneSendTime(CFE_TIME_SysTime_t NewTime)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t NewSTCF;
+ CFE_TIME_SysTime_t NewMET;
+ CFE_TIME_SysTime_t MinValid;
+ CFE_TIME_SysTime_t MaxValid;
+ CFE_TIME_Compare_t MinResult;
+ CFE_TIME_Compare_t MaxResult;
+
+ int16 ClockState;
+ int32 Result = CFE_SUCCESS;
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+ /*
+ ** Ignore external time data if commanded to use local MET...
+ */
+ if (CFE_TIME_Global.ClockSource == CFE_TIME_SourceSelect_INTERNAL)
+ {
+ Result = CFE_TIME_INTERNAL_ONLY;
+
+ /*
+ ** Use internal clock but still send "time at the tone"...
+ */
+ CFE_TIME_ToneSend();
+ }
+ else
+ {
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** cFE defines MET as being synchronized to the tone signal...
+ */
+ NewMET.Seconds = Reference.CurrentMET.Seconds;
+ NewMET.Subseconds = 0;
+
+/*
+** Add a second if the tone has not yet occurred...
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+ NewMET.Seconds++;
+#endif
+
+ /*
+ ** Remove MET from the new time value (leaves STCF)...
+ */
+ NewSTCF = CFE_TIME_Subtract(NewTime, NewMET);
+
+/*
+** Restore leap seconds if default time format is UTC...
+*/
+#if (CFE_MISSION_TIME_CFG_DEFAULT_UTC == true)
+ NewSTCF.Seconds += Reference.AtToneLeapSeconds;
+#endif
+
+ /*
+ ** Compute minimum and maximum values for valid STCF...
+ */
+ MinValid = CFE_TIME_Subtract(Reference.AtToneSTCF, CFE_TIME_Global.MaxDelta);
+ MaxValid = CFE_TIME_Add(Reference.AtToneSTCF, CFE_TIME_Global.MaxDelta);
+
+ /*
+ ** Compare new STCF to minimum and maximum STCF...
+ */
+ MinResult = CFE_TIME_Compare(NewSTCF, MinValid);
+ MaxResult = CFE_TIME_Compare(NewSTCF, MaxValid);
+
+ /*
+ ** If state is valid then ignore bad external time data...
+ */
+ if ((Reference.ClockSetState == CFE_TIME_SetState_WAS_SET) &&
+ ((MinResult == CFE_TIME_A_LT_B) || (MaxResult == CFE_TIME_A_GT_B)))
+ {
+ Result = CFE_TIME_OUT_OF_RANGE;
+
+ /*
+ ** Use internal clock but still send "time at the tone"...
+ */
+ CFE_TIME_ToneSend();
+ }
+ else
+ {
+ ClockState = CFE_TIME_CalculateState(&Reference);
+
+ /*
+ ** Set "time at the tone" command data packet arguments...
+ */
+
+#ifdef CFE_PLATFORM_TIME_CFG_BIGENDIAN
+
+ /*
+ ** Payload must be big-endian.
+ */
+
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Seconds = CFE_MAKE_BIG32(NewMET.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET.Subseconds = CFE_MAKE_BIG32(NewMET.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Seconds = CFE_MAKE_BIG32(NewSTCF.Seconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF.Subseconds = CFE_MAKE_BIG32(NewSTCF.Subseconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = CFE_MAKE_BIG16(Reference.AtToneLeapSeconds);
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = CFE_MAKE_BIG16(ClockState);
+
+#else /* !CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneMET = NewMET;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneSTCF = NewSTCF;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneLeapSeconds = Reference.AtToneLeapSeconds;
+ CFE_TIME_Global.ToneDataCmd.Payload.AtToneState = ClockState;
+
+#endif /* CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ /*
+ ** Send "time at the tone" command data packet...
+ */
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.ToneDataCmd.CmdHeader.Msg, false);
+
+ /*
+ ** Count of "time at the tone" commands sent with external data...
+ */
+ CFE_TIME_Global.ExternalCount++;
+ }
+ }
+
+ return (Result);
+
+} /* End of CFE_TIME_ToneSendTime() */
+#endif /* CFE_PLATFORM_TIME_CFG_SRC_TIME */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneData() -- process "time at tone" data packet */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_ToneData(const CFE_TIME_ToneDataCmd_Payload_t *ToneDataCmd)
+{
+ /*
+ ** Save the time when the data packet was received...
+ */
+ CFE_TIME_Global.ToneDataLatch = CFE_TIME_LatchClock();
+
+ /*
+ ** Save the data packet (may be a while before the data is used)...
+ */
+
+#ifdef CFE_PLATFORM_TIME_CFG_BIGENDIAN
+
+ /*
+ ** Tone data will be big-endian, convert to platform-endian.
+ */
+ CFE_TIME_Global.PendingMET.Seconds = CFE_MAKE_BIG32(ToneDataCmd->AtToneMET.Seconds);
+ CFE_TIME_Global.PendingMET.Subseconds = CFE_MAKE_BIG32(ToneDataCmd->AtToneMET.Subseconds);
+ CFE_TIME_Global.PendingSTCF.Seconds = CFE_MAKE_BIG32(ToneDataCmd->AtToneSTCF.Seconds);
+ CFE_TIME_Global.PendingSTCF.Subseconds = CFE_MAKE_BIG32(ToneDataCmd->AtToneSTCF.Subseconds);
+ CFE_TIME_Global.PendingLeaps = CFE_MAKE_BIG16(ToneDataCmd->AtToneLeapSeconds);
+ CFE_TIME_Global.PendingState = CFE_MAKE_BIG16(ToneDataCmd->AtToneState);
+
+#else /* !CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+ CFE_TIME_Copy(&CFE_TIME_Global.PendingMET, &ToneDataCmd->AtToneMET);
+ CFE_TIME_Copy(&CFE_TIME_Global.PendingSTCF, &ToneDataCmd->AtToneSTCF);
+ CFE_TIME_Global.PendingLeaps = ToneDataCmd->AtToneLeapSeconds;
+ CFE_TIME_Global.PendingState = ToneDataCmd->AtToneState;
+
+#endif /* CFE_PLATFORM_TIME_CFG_BIGENDIAN */
+
+/*
+** If the data packet is designed to arrive after the tone...
+**
+** Check to see if the most recent tone signal matches this
+** data packet. If so, we have a matched pair and can
+** now start using the new data to compute time.
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WAS == true)
+ CFE_TIME_ToneVerify(CFE_TIME_Global.ToneSignalLatch, CFE_TIME_Global.ToneDataLatch);
+#endif
+
+/*
+** If the data packet is designed to arrive before the tone...
+**
+** We don't really need to do anything except to save the time
+** and contents of this data packet. (above)
+**
+** Note that we do not immediately start using the data packet
+** values to compute current time. We continue to use the
+** old tone/data combo until we get a new matched pair.
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+#endif
+
+ /*
+ ** Maintain a count of tone data packets...
+ */
+ CFE_TIME_Global.ToneDataCounter++;
+
+ return;
+
+} /* End of CFE_TIME_ToneData() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneSignal() -- "tone signal" occurred recently */
+/* */
+/* This function is called upon receipt of a command indicating */
+/* that a time at the tone signal was detected. The mission */
+/* dependent h/w or s/w that detected the tone signal latched */
+/* the local clock and generated this command. The use of a */
+/* command announcing the tone signal ensures that this code */
+/* is not called from within an interrupt handler. */
+/* */
+/* It is not a concern that some amount of time has elapsed since */
+/* the tone actually occurred. We are currently computing */
+/* time as a delta (as measured on our local clock) from a */
+/* previously latched tone. It just doesn't matter if the */
+/* size of the delta slightly exceeds a second. The quality */
+/* of our local clock will always be sufficient to measure */
+/* time for a couple of seconds. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_ToneSignal(void)
+{
+/*
+** If the data packet is designed to arrive after the tone signal...
+**
+** We don't really need to do anything except latch the local clock
+** at the moment of the tone. And that has already happened at
+** the time when the tone was detected.
+**
+** Note that we do not immediately start using this latched value to
+** compute current time. We continue to use the old tone/data
+** combo until we get a new matched pair.
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WAS == true)
+#endif
+
+/*
+** If the data packet is designed to arrive before the tone signal...
+**
+** Check to see if the most recent data packet matches this
+** tone signal. If so, we have a matched pair and can
+** now start using the new data to compute time.
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+ CFE_TIME_ToneVerify(CFE_TIME_Global.ToneDataLatch, CFE_TIME_Global.ToneSignalLatch);
+#endif
+
+ /*
+ ** Maintain a count of tone signal packets...
+ */
+ CFE_TIME_Global.ToneSignalCounter++;
+
+ return;
+
+} /* End of CFE_TIME_ToneSignal() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneVerify() -- validate tone and data packet */
+/* */
+/* */
+/* If the data packet is designed to arrive after the tone, then */
+/* */
+/* Time1 = local clock latched at the detection of the tone */
+/* Time2 = local clock latched at the arrival of the packet */
+/* */
+/* */
+/* If the data packet is designed to arrive before the tone, then */
+/* */
+/* Time1 = local clock latched at the arrival of the packet */
+/* Time2 = local clock latched at the detection of the tone */
+/* */
+/* */
+/* In either case, Time1 occurred before Time2 */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_ToneVerify(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2)
+{
+ CFE_TIME_Compare_t result;
+ CFE_TIME_SysTime_t elapsed;
+
+ static CFE_TIME_SysTime_t PrevTime1 = {0, 0};
+ static CFE_TIME_SysTime_t PrevTime2 = {0, 0};
+
+ /*
+ ** It is possible to call this func with static time value...
+ */
+ result = CFE_TIME_Compare(PrevTime1, Time1);
+ if (result == CFE_TIME_EQUAL)
+ {
+ CFE_TIME_Global.ToneMatchErrorCounter++;
+ }
+ else
+ {
+ result = CFE_TIME_Compare(PrevTime2, Time2);
+ if (result == CFE_TIME_EQUAL)
+ {
+ CFE_TIME_Global.ToneMatchErrorCounter++;
+ }
+ else
+ {
+ /*
+ ** Compute elapsed time between tone and data packet...
+ */
+ result = CFE_TIME_Compare(Time1, Time2);
+ if (result == CFE_TIME_A_GT_B)
+ {
+ /*
+ ** Local clock has rolled over...
+ */
+ elapsed = CFE_TIME_Subtract(CFE_TIME_Global.MaxLocalClock, Time1);
+ elapsed = CFE_TIME_Add(elapsed, Time2);
+ }
+ else
+ {
+ /*
+ ** Normal case...
+ */
+ elapsed = CFE_TIME_Subtract(Time2, Time1);
+ }
+
+ /*
+ ** Ensure that time between packet and tone is within limits...
+ */
+ if ((elapsed.Seconds != 0) || (elapsed.Subseconds < CFE_TIME_Global.MinElapsed) ||
+ (elapsed.Subseconds > CFE_TIME_Global.MaxElapsed))
+ {
+ /*
+ ** Maintain count of tone vs data packet mis-matches...
+ */
+ CFE_TIME_Global.ToneMatchErrorCounter++;
+ }
+ else
+ {
+ CFE_TIME_Global.ToneMatchCounter++;
+
+ /*
+ ** Skip tone packet update if commanded into "flywheel" mode...
+ */
+ if (!CFE_TIME_Global.Forced2Fly)
+ {
+ /*
+ ** Process "matching" tone and data packet...
+ */
+ CFE_TIME_ToneUpdate();
+ }
+ }
+ }
+ }
+
+ PrevTime1 = Time1;
+ PrevTime2 = Time2;
+
+ return;
+
+} /* End of CFE_TIME_ToneVerify() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_ToneUpdate() -- process "matching" tone & data packet */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_ToneUpdate(void)
+{
+ CFE_TIME_Reference_t Reference;
+ bool NewFlywheelStatus = false;
+ volatile CFE_TIME_ReferenceState_t *NextState;
+
+ /*
+ ** Get current reference state before starting any update
+ **
+ ** If we have been flywheeling, VirtualMET may be incorrect
+ ** (e.g. missing tone signals -- VirtualMET is tone count)
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** Ensure that reader(s) know of the pending update
+ */
+ NextState = CFE_TIME_StartReferenceUpdate();
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ /*
+ ** Time servers cannot always use the new time data from the
+ ** packet (saved as "pending" when the packet arrived).
+ **
+ ** If the time source is "internal" then the time data came
+ ** from the same values that we would be updating, hence
+ ** there is no need to do the update. And if there has
+ ** been a command to set new values during the moment
+ ** between making the time at the tone packet and now,
+ ** then we would want to use the command values anyway.
+ **
+ ** If the time source is "external" then things get complex.
+ ** If the external data is MET then we only want to take
+ ** the MET from the packet. But, if the external data
+ ** is "time" then we only want to take the STCF from the
+ ** packet. And, if the external data is GPS then we
+ ** need to take both the STCF and the leap seconds from
+ ** the packet. Also, by definition, we cannot have both
+ ** external data and a local h/w MET - so we don't need
+ ** to worry about updating a local MET to external time.
+ */
+ NextState->AtToneLatch = CFE_TIME_Global.ToneSignalLatch;
+
+ if (CFE_TIME_Global.ClockSource == CFE_TIME_SourceSelect_INTERNAL)
+ {
+ /*
+ ** If we have been flywheeling, VirtualMET may be incorrect
+ ** (flywheel state is changed later in this function)
+ */
+ if (NextState->ClockFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ CFE_TIME_Global.VirtualMET = Reference.CurrentMET.Seconds;
+ }
+
+ /*
+ ** Update "time at tone" to match virtual MET counter...
+ **
+ ** Note: It is OK to not bother with reading the h/w MET
+ ** since we sync'ed them at the moment of the tone.
+ */
+ NextState->AtToneMET.Seconds = CFE_TIME_Global.VirtualMET;
+ NextState->AtToneMET.Subseconds = 0;
+ }
+ else
+ {
+/*
+** Update "time at tone" with external MET data...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SRC_MET == true)
+ NextState->AtToneMET = CFE_TIME_Global.PendingMET;
+ CFE_TIME_Global.VirtualMET = CFE_TIME_Global.PendingMET.Seconds;
+#endif
+
+/*
+** Update "time at tone" with external GPS data...
+**
+** STCF = GPS time at the tone - local MET at the tone
+** Leaps = GPS leaps
+**
+** It is possible that a command changed the MET after it was used
+** to calculate the pending STCF -- in which case the current
+** time will jump next second when the STCF gets calculated
+** again with the new MET value. This (small) possibility can
+** be prevented by switching to "internal" mode before sending
+** set time commands...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SRC_GPS == true)
+ NextState->AtToneMET.Seconds = CFE_TIME_Global.VirtualMET;
+ NextState->AtToneMET.Subseconds = 0;
+ NextState->AtToneSTCF = CFE_TIME_Global.PendingSTCF;
+ NextState->AtToneLeapSeconds = CFE_TIME_Global.PendingLeaps;
+#endif
+
+/*
+** Update "time at tone" with external time data...
+**
+** STCF = external time at the tone - local MET at the tone
+*/
+#if (CFE_PLATFORM_TIME_CFG_SRC_TIME == true)
+ NextState->AtToneMET.Seconds = CFE_TIME_Global.VirtualMET;
+ NextState->AtToneMET.Subseconds = 0;
+ NextState->AtToneSTCF = CFE_TIME_Global.PendingSTCF;
+#endif
+ }
+
+ /*
+ ** With a "time" update, this server cannot be "flywheeling"
+ ** (we won't get this update if commanded to flywheel)
+ */
+ if (NextState->ClockFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ NextState->ClockFlyState = CFE_TIME_FlywheelState_NO_FLY;
+ CFE_TIME_Global.ServerFlyState = CFE_TIME_FlywheelState_NO_FLY;
+ NewFlywheelStatus = true;
+ }
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ /*
+ ** Set local clock latch time that matches the tone...
+ */
+ NextState->AtToneLatch = CFE_TIME_Global.ToneSignalLatch;
+
+ /*
+ ** Time clients need all the "time at the tone" command data...
+ */
+ NextState->AtToneMET = CFE_TIME_Global.PendingMET;
+ NextState->AtToneSTCF = CFE_TIME_Global.PendingSTCF;
+ NextState->AtToneLeapSeconds = CFE_TIME_Global.PendingLeaps;
+
+ /*
+ ** Convert the server clock state into its component parts...
+ */
+ if (CFE_TIME_Global.PendingState == CFE_TIME_ClockState_INVALID)
+ {
+ NextState->ClockSetState = CFE_TIME_SetState_NOT_SET;
+ CFE_TIME_Global.ServerFlyState = CFE_TIME_FlywheelState_NO_FLY;
+ }
+ else
+ {
+ NextState->ClockSetState = CFE_TIME_SetState_WAS_SET;
+
+ /*
+ ** If the server is fly-wheel then the client must also
+ ** report fly-wheel (even if it is not)...
+ */
+ if (CFE_TIME_Global.PendingState == CFE_TIME_ClockState_FLYWHEEL)
+ {
+ CFE_TIME_Global.ServerFlyState = CFE_TIME_FlywheelState_IS_FLY;
+ }
+ else
+ {
+ CFE_TIME_Global.ServerFlyState = CFE_TIME_FlywheelState_NO_FLY;
+ }
+ }
+
+ /*
+ ** With a "time" update, this client cannot be "flywheeling"...
+ ** (we won't get this update if commanded to flywheel)
+ */
+ if (NextState->ClockFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ NextState->ClockFlyState = CFE_TIME_FlywheelState_NO_FLY;
+ NewFlywheelStatus = true;
+ }
+#endif /* CFE_PLATFORM_TIME_CFG_CLIENT */
+
+ /*
+ ** Complete the time update.
+ */
+ CFE_TIME_FinishReferenceUpdate(NextState);
+
+ /*
+ ** Wait until after interrupts are enabled to send event...
+ */
+ if (NewFlywheelStatus)
+ {
+ CFE_EVS_SendEvent(CFE_TIME_FLY_OFF_EID, CFE_EVS_EventType_INFORMATION, "Stop FLYWHEEL");
+ }
+
+ return;
+
+} /* End of CFE_TIME_ToneUpdate() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Local1HzTimerCallback() -- 1Hz callback routine */
+/* */
+/* This is a wrapper around CFE_TIME_Local1HzISR that conforms to */
+/* the prototype of an OSAL Timer callback routine. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_Local1HzTimerCallback(osal_id_t TimerId, void *Arg)
+{
+ CFE_TIME_Local1HzISR();
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Tone1HzISR() -- Tone signal ISR */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_Tone1HzISR(void)
+{
+
+ CFE_TIME_SysTime_t ToneSignalLatch;
+ CFE_TIME_SysTime_t Elapsed;
+ CFE_TIME_Compare_t Result;
+
+ /* Start Performance Monitoring */
+ CFE_ES_PerfLogEntry(CFE_MISSION_TIME_TONE1HZISR_PERF_ID);
+
+ /*
+ ** Latch the local clock when the tone signal occurred...
+ */
+ ToneSignalLatch = CFE_TIME_LatchClock();
+
+ /*
+ ** Compute elapsed time since the previous tone signal...
+ */
+ Result = CFE_TIME_Compare(ToneSignalLatch, CFE_TIME_Global.ToneSignalLatch);
+
+ if (Result == CFE_TIME_A_LT_B)
+ {
+ /*
+ ** Local clock has rolled over...
+ */
+ Elapsed = CFE_TIME_Subtract(CFE_TIME_Global.MaxLocalClock, CFE_TIME_Global.ToneSignalLatch);
+ Elapsed = CFE_TIME_Add(Elapsed, ToneSignalLatch);
+ }
+ else
+ {
+ /*
+ ** Normal case...
+ */
+ Elapsed = CFE_TIME_Subtract(ToneSignalLatch, CFE_TIME_Global.ToneSignalLatch);
+ }
+
+ /*
+ ** Verify that tone occurred ~1 second after previous tone...
+ */
+ if (((Elapsed.Seconds == 1) && (Elapsed.Subseconds < CFE_TIME_Global.ToneOverLimit)) ||
+ ((Elapsed.Seconds == 0) && (Elapsed.Subseconds > CFE_TIME_Global.ToneUnderLimit)))
+ {
+ /*
+ ** Maintain count of valid tone signal interrupts...
+ ** (set to zero by reset command)
+ */
+ CFE_TIME_Global.ToneIntCounter++;
+
+ /* Since the tone occured ~1 seonds after the previous one, we
+ ** can mark this tone as 'good'
+ */
+ CFE_TIME_Global.IsToneGood = true;
+
+/*
+** Maintain virtual MET as count of valid tone signal interrupts...
+** (not set to zero by reset command)
+*/
+#if (CFE_PLATFORM_TIME_CFG_VIRTUAL == true)
+ CFE_TIME_Global.VirtualMET++;
+#endif
+
+/*
+** Maintain virtual MET as count read from h/w MET register...
+*/
+#if (CFE_PLATFORM_TIME_CFG_VIRTUAL != true)
+ OS_GetLocalMET(&CFE_TIME_Global.VirtualMET);
+#endif
+
+ /*
+ ** Enable tone task (we can't send a SB message from here)...
+ */
+ OS_BinSemGive(CFE_TIME_Global.ToneSemaphore);
+ }
+ else
+ {
+ /*
+ ** Maintain count of invalid tone signal interrupts...
+ ** (set to zero by reset command)
+ */
+ CFE_TIME_Global.ToneIntErrorCounter++;
+
+ /* Since the tone didn't occur ~1 seonds after the previous one, we
+ ** can mark this tone as 'not good'
+ */
+ CFE_TIME_Global.IsToneGood = false;
+ }
+
+ /*
+ ** Save local time latch of most recent tone signal...
+ */
+ CFE_TIME_Global.ToneSignalLatch = ToneSignalLatch;
+
+ /* Notify registered time synchronization applications */
+ CFE_TIME_NotifyTimeSynchApps();
+
+ /* Exit performance monitoring */
+ CFE_ES_PerfLogExit(CFE_MISSION_TIME_TONE1HZISR_PERF_ID);
+
+ return;
+
+} /* End of CFE_TIME_Tone1HzISR() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Tone1HzTask() -- Tone 1Hz task */
+/* */
+/* This task exists solely to generate the tone signal command. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_Tone1HzTask(void)
+{
+ int32 Result;
+
+ while (true)
+ {
+ /* Increment the Main task Execution Counter */
+ CFE_ES_IncrementTaskCounter();
+
+ /*
+ ** Pend on semaphore given by tone ISR (above)...
+ */
+ Result = OS_BinSemTake(CFE_TIME_Global.ToneSemaphore);
+ if (Result != OS_SUCCESS)
+ {
+ break;
+ }
+
+ /* Start Performance Monitoring */
+ CFE_ES_PerfLogEntry(CFE_MISSION_TIME_TONE1HZTASK_PERF_ID);
+
+ /*
+ ** Send tone signal command packet...
+ */
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.ToneSignalCmd.CmdHeader.Msg, false);
+
+#if (CFE_MISSION_TIME_CFG_FAKE_TONE == true)
+ /*
+ ** If we are simulating the tone signal, also generate the message
+ ** to send the tone to other time clients.
+ ** (this is done by scheduler in non-fake mode)
+ */
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.ToneSendCmd.CmdHeader.Msg, false);
+#endif
+
+ /*
+ ** Maintain count of tone task wake-ups...
+ */
+ CFE_TIME_Global.ToneTaskCounter++;
+
+ /* Exit performance monitoring */
+ CFE_ES_PerfLogExit(CFE_MISSION_TIME_TONE1HZTASK_PERF_ID);
+ }
+
+ /*
+ ** This should never happen - but during development we
+ ** had an error in the creation of the semaphore.
+ */
+ return;
+
+} /* End of CFE_TIME_Tone1HzTask() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Local1HzStateMachine() -- */
+/* Update the TIME state, should be called at 1Hz */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_Local1HzStateMachine(void)
+{
+
+ CFE_TIME_Reference_t Reference;
+ volatile CFE_TIME_ReferenceState_t *NextState;
+
+ /* Start Performance Monitoring */
+ CFE_ES_PerfLogEntry(CFE_MISSION_TIME_LOCAL1HZISR_PERF_ID);
+
+ /* Zero out the Reference variable because we pass it into
+ * a function before using it
+ * */
+ memset(&Reference, 0, sizeof(CFE_TIME_Reference_t));
+
+/*
+** Apply 1Hz adjustment to STCF...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ if ((CFE_TIME_Global.OneHzAdjust.Seconds != 0) || (CFE_TIME_Global.OneHzAdjust.Subseconds != 0))
+ {
+ CFE_TIME_SysTime_t NewSTCF;
+ NextState = CFE_TIME_StartReferenceUpdate();
+
+ if (CFE_TIME_Global.OneHzDirection == CFE_TIME_AdjustDirection_ADD)
+ {
+ NewSTCF = CFE_TIME_Add(NextState->AtToneSTCF, CFE_TIME_Global.OneHzAdjust);
+ }
+ else
+ {
+ NewSTCF = CFE_TIME_Subtract(NextState->AtToneSTCF, CFE_TIME_Global.OneHzAdjust);
+ }
+
+ NextState->AtToneSTCF = NewSTCF;
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(NextState);
+ }
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+ /*
+ ** Get reference time (calculates time since tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** See if it has been long enough without receiving a time update
+ ** to autonomously start "fly-wheel" mode...
+ */
+ if (Reference.ClockFlyState == CFE_TIME_FlywheelState_NO_FLY)
+ {
+ if (Reference.TimeSinceTone.Seconds >= CFE_PLATFORM_TIME_CFG_START_FLY)
+ {
+ NextState = CFE_TIME_StartReferenceUpdate();
+
+ /*
+ ** Change current state to "fly-wheel"...
+ */
+ NextState->ClockFlyState = CFE_TIME_FlywheelState_IS_FLY;
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ CFE_TIME_Global.ServerFlyState = CFE_TIME_FlywheelState_IS_FLY;
+#endif
+
+ CFE_TIME_Global.AutoStartFly = true;
+
+ /*
+ ** Force anyone currently reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(NextState);
+ }
+ }
+
+ /*
+ ** See if it has been long enough without receiving a time update
+ ** (or since last doing this update) to autonomously update the
+ ** MET at the tone and local clock latched at the tone...
+ */
+ if (Reference.ClockFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ if (Reference.TimeSinceTone.Seconds >= CFE_PLATFORM_TIME_CFG_LATCH_FLY)
+ {
+ NextState = CFE_TIME_StartReferenceUpdate();
+
+ /*
+ ** Update MET at tone and local clock latched at tone...
+ **
+ ** This does not increase the accuracy of the local clock,
+ ** but it does avoid some problems. It is not uncommon
+ ** for a local clock to roll over after only a few
+ ** seconds, so we try and keep the elapsed time since
+ ** the "tone" to a relatively small number of seconds.
+ ** We can handle a simple roll-over but need to prevent
+ ** the local clock from completely wrapping around the
+ ** time latched at the tone.
+ */
+ NextState->AtToneMET = Reference.CurrentMET;
+ NextState->AtToneLatch = Reference.CurrentLatch;
+
+ /*
+ ** Force anyone currently reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(NextState);
+ }
+ }
+
+ /* Exit performance monitoring */
+ CFE_ES_PerfLogExit(CFE_MISSION_TIME_LOCAL1HZISR_PERF_ID);
+}
+
+/*
+ * Function: CFE_TIME_Local1HzISR - See API and header file for details
+ */
+void CFE_TIME_Local1HzISR(void)
+{
+
+ CFE_TIME_Global.LocalIntCounter++;
+
+ /*
+ ** Enable 1Hz task (we can't send a SB message from here)...
+ */
+ OS_BinSemGive(CFE_TIME_Global.LocalSemaphore);
+
+ return;
+
+} /* End of CFE_TIME_Local1HzISR() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Local1HzTask() -- Local 1Hz task (not the tone) */
+/* */
+/* This task exists solely to generate the 1Hz wake-up command. */
+/* */
+/* This is a temporary solution until a scheduler is implemented. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_Local1HzTask(void)
+{
+ int32 Result;
+
+ while (true)
+ {
+
+ /* Increment the Main task Execution Counter */
+ CFE_ES_IncrementTaskCounter();
+
+ /*
+ ** Pend on the 1HZ semaphore (given by local 1Hz ISR)...
+ */
+ Result = OS_BinSemTake(CFE_TIME_Global.LocalSemaphore);
+ if (Result != OS_SUCCESS)
+ {
+ break;
+ }
+
+ /* Start Performance Monitoring */
+ CFE_ES_PerfLogEntry(CFE_MISSION_TIME_LOCAL1HZTASK_PERF_ID);
+
+ /*
+ ** Send "info" event if we just started flywheel mode...
+ */
+ if (CFE_TIME_Global.AutoStartFly)
+ {
+ CFE_TIME_Global.AutoStartFly = false;
+
+ CFE_EVS_SendEvent(CFE_TIME_FLY_ON_EID, CFE_EVS_EventType_INFORMATION, "Start FLYWHEEL");
+ }
+
+ /*
+ ** Send 1Hz timing packet...
+ ** This used to be optional in previous CFE versions, but it is now required
+ ** as TIME subscribes to this itself to do state machine tasks.
+ */
+ CFE_SB_TransmitMsg(&CFE_TIME_Global.Local1HzCmd.CmdHeader.Msg, false);
+
+ CFE_TIME_Global.LocalTaskCounter++;
+
+ /* Exit performance monitoring */
+ CFE_ES_PerfLogExit(CFE_MISSION_TIME_LOCAL1HZTASK_PERF_ID);
+ }
+
+ /*
+ ** This should never happen - but during development we had an
+ ** error in the creation of the semaphore.
+ */
+ return;
+
+} /* End of CFE_TIME_Local1HzTask() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_NotifyTimeSynchApps() -- Call App Synch Callback Funcs */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_NotifyTimeSynchApps(void)
+{
+ uint32 i;
+ CFE_TIME_SynchCallbackPtr_t Func;
+
+ /*
+ ** Notify applications that have requested tone synchronization
+ */
+ if (CFE_TIME_Global.IsToneGood)
+ {
+ for (i = 0; i < (sizeof(CFE_TIME_Global.SynchCallback) / sizeof(CFE_TIME_Global.SynchCallback[0])); ++i)
+ {
+ /* IMPORTANT:
+ * Read the global pointer only once, since a thread could be unregistering
+ * the same pointer in parallel with this action.
+ */
+ Func = CFE_TIME_Global.SynchCallback[i].Ptr;
+ if (Func != NULL)
+ {
+ Func();
+ }
+ }
+ }
+
+ return;
+}
+
+/************************/
+/* End of File Comment */
+/************************/
diff --git a/modules/time/fsw/src/cfe_time_utils.c b/modules/time/fsw/src/cfe_time_utils.c
new file mode 100644
index 000000000..fdfb305bf
--- /dev/null
+++ b/modules/time/fsw/src/cfe_time_utils.c
@@ -0,0 +1,1074 @@
+/*
+** 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_time_utils.c
+**
+** Purpose: cFE Time Services (TIME) library utilities source file
+**
+** Author: S.Walling/Microtel
+**
+** Notes:
+**
+*/
+
+/*
+** Required header files...
+*/
+#include "cfe_time_utils.h"
+#include "cfe_msgids.h"
+#include "cfe_es_resetdata_typedef.h"
+
+#include "cfe_es.h"
+#include "cfe_msg.h"
+#include "cfe_sb.h"
+
+#include
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_StartReferenceUpdate() */
+/* Initiate an update to the global time reference data */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+volatile CFE_TIME_ReferenceState_t *CFE_TIME_StartReferenceUpdate(void)
+{
+ uint32 Version = CFE_TIME_Global.LastVersionCounter;
+ volatile CFE_TIME_ReferenceState_t *CurrState;
+ volatile CFE_TIME_ReferenceState_t *NextState;
+
+ CurrState = &CFE_TIME_Global.ReferenceState[Version & CFE_TIME_REFERENCE_BUF_MASK];
+ ++Version;
+ NextState = &CFE_TIME_Global.ReferenceState[Version & CFE_TIME_REFERENCE_BUF_MASK];
+
+ NextState->StateVersion = Version;
+
+ /* initially propagate all previous values to next values */
+ NextState->AtToneLeapSeconds = CurrState->AtToneLeapSeconds;
+ NextState->ClockSetState = CurrState->ClockSetState;
+ NextState->ClockFlyState = CurrState->ClockFlyState;
+ NextState->DelayDirection = CurrState->DelayDirection;
+ NextState->AtToneMET = CurrState->AtToneMET;
+ NextState->AtToneSTCF = CurrState->AtToneSTCF;
+ NextState->AtToneDelay = CurrState->AtToneDelay;
+ NextState->AtToneLatch = CurrState->AtToneLatch;
+
+ return NextState;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_LatchClock() -- query local clock */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+CFE_TIME_SysTime_t CFE_TIME_LatchClock(void)
+{
+ CFE_TIME_SysTime_t LatchTime;
+ OS_time_t LocalTime;
+
+ /*
+ ** Get time in O/S format (seconds : microseconds)...
+ */
+ CFE_PSP_GetTime(&LocalTime);
+
+ /*
+ ** Convert time to cFE format (seconds : 1/2^32 subseconds)...
+ */
+ LatchTime.Seconds = OS_TimeGetTotalSeconds(LocalTime);
+ LatchTime.Subseconds = OS_TimeGetSubsecondsPart(LocalTime);
+
+ return (LatchTime);
+
+} /* End of CFE_TIME_LatchClock() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_QueryResetVars() -- query contents of Reset Variables */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_QueryResetVars(void)
+{
+
+ CFE_TIME_ResetVars_t LocalResetVars;
+ uint32 DefSubsMET;
+ uint32 DefSubsSTCF;
+ int32 status;
+ volatile CFE_TIME_ReferenceState_t *RefState;
+ uint32 resetAreaSize;
+ cpuaddr resetAreaAddr;
+ CFE_ES_ResetData_t * CFE_TIME_ResetDataPtr;
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ /*
+ ** Get the pointer to the Reset area from the BSP
+ */
+ status = CFE_PSP_GetResetArea(&(resetAreaAddr), &(resetAreaSize));
+
+ if (status != CFE_PSP_SUCCESS)
+ {
+ /* There is something wrong with the Reset Area */
+ CFE_TIME_Global.DataStoreStatus = CFE_TIME_RESET_AREA_BAD;
+ }
+
+ else
+ {
+ CFE_TIME_ResetDataPtr = (CFE_ES_ResetData_t *)resetAreaAddr;
+
+ /* Get the structure from the Reset Area */
+ LocalResetVars = CFE_TIME_ResetDataPtr->TimeResetVars;
+
+ /*
+ ** Verify TIME data signature and clock signal selection...
+ ** (other data fields have no verifiable limits)
+ */
+ if ((LocalResetVars.Signature == CFE_TIME_RESET_SIGNATURE) &&
+ ((LocalResetVars.ClockSignal == CFE_TIME_ToneSignalSelect_PRIMARY) ||
+ (LocalResetVars.ClockSignal == CFE_TIME_ToneSignalSelect_REDUNDANT)))
+ {
+ /*
+ ** Initialize TIME to valid Reset Area values...
+ */
+ RefState->AtToneMET = LocalResetVars.CurrentMET;
+ RefState->AtToneSTCF = LocalResetVars.CurrentSTCF;
+ RefState->AtToneDelay = LocalResetVars.CurrentDelay;
+ RefState->AtToneLeapSeconds = LocalResetVars.LeapSeconds;
+ CFE_TIME_Global.ClockSignal = LocalResetVars.ClockSignal;
+
+ CFE_TIME_Global.DataStoreStatus = CFE_TIME_RESET_AREA_EXISTING;
+ }
+ else
+ {
+ /*
+ ** We got a blank area from the reset variables
+ */
+ CFE_TIME_Global.DataStoreStatus = CFE_TIME_RESET_AREA_NEW;
+ }
+ }
+ /*
+ ** Initialize TIME to default values if no valid Reset data...
+ */
+ if (CFE_TIME_Global.DataStoreStatus != CFE_TIME_RESET_AREA_EXISTING)
+ {
+ DefSubsMET = CFE_TIME_Micro2SubSecs(CFE_MISSION_TIME_DEF_MET_SUBS);
+ DefSubsSTCF = CFE_TIME_Micro2SubSecs(CFE_MISSION_TIME_DEF_STCF_SUBS);
+
+ RefState->AtToneMET.Seconds = CFE_MISSION_TIME_DEF_MET_SECS;
+ RefState->AtToneMET.Subseconds = DefSubsMET;
+ RefState->AtToneSTCF.Seconds = CFE_MISSION_TIME_DEF_STCF_SECS;
+ RefState->AtToneSTCF.Subseconds = DefSubsSTCF;
+ RefState->AtToneLeapSeconds = CFE_MISSION_TIME_DEF_LEAPS;
+ CFE_TIME_Global.ClockSignal = CFE_TIME_ToneSignalSelect_PRIMARY;
+ RefState->AtToneDelay.Seconds = 0;
+ RefState->AtToneDelay.Subseconds = 0;
+ }
+
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_QueryResetVars() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_UpdateResetVars() -- update contents of Reset Variables*/
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_UpdateResetVars(const CFE_TIME_Reference_t *Reference)
+{
+ CFE_TIME_ResetVars_t LocalResetVars;
+ uint32 resetAreaSize;
+ cpuaddr resetAreaAddr;
+ CFE_ES_ResetData_t * CFE_TIME_ResetDataPtr;
+ /*
+ ** Update the data only if our Reset Area is valid...
+ */
+ if (CFE_TIME_Global.DataStoreStatus != CFE_TIME_RESET_AREA_ERROR)
+ {
+
+ /* Store all of our critical variables to a ResetVars_t
+ * then copy that to the Reset Area */
+ LocalResetVars.Signature = CFE_TIME_RESET_SIGNATURE;
+
+ LocalResetVars.CurrentMET = Reference->CurrentMET;
+ LocalResetVars.CurrentSTCF = Reference->AtToneSTCF;
+ LocalResetVars.CurrentDelay = Reference->AtToneDelay;
+ LocalResetVars.LeapSeconds = Reference->AtToneLeapSeconds;
+
+ LocalResetVars.ClockSignal = CFE_TIME_Global.ClockSignal;
+
+ /*
+ ** Get the pointer to the Reset area from the BSP
+ */
+ if (CFE_PSP_GetResetArea(&(resetAreaAddr), &(resetAreaSize)) == CFE_PSP_SUCCESS)
+ {
+ CFE_TIME_ResetDataPtr = (CFE_ES_ResetData_t *)resetAreaAddr;
+ CFE_TIME_ResetDataPtr->TimeResetVars = LocalResetVars;
+ }
+ }
+
+ return;
+
+} /* End of CFE_TIME_UpdateResetVars() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_InitData() -- initialize global time task nonzero data */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_InitData(void)
+{
+ uint32 i;
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ /* Clear task global */
+ memset(&CFE_TIME_Global, 0, sizeof(CFE_TIME_Global));
+
+ /*
+ ** Initialize task configuration data...
+ */
+ for (i = 0; i < CFE_TIME_REFERENCE_BUF_DEPTH; ++i)
+ {
+ CFE_TIME_Global.ReferenceState[i].StateVersion = 0xFFFFFFFF;
+ }
+
+ /*
+ ** Try to get values used to compute time from Reset Area...
+ */
+ CFE_TIME_QueryResetVars();
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ /*
+ ** Remaining data values used to compute time...
+ */
+ RefState->AtToneLatch = CFE_TIME_LatchClock();
+
+ /*
+ ** Data values used to define the current clock state...
+ */
+ RefState->ClockSetState = CFE_TIME_SetState_NOT_SET;
+ RefState->ClockFlyState = CFE_TIME_FlywheelState_IS_FLY;
+
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+ CFE_TIME_Global.ClockSource = CFE_TIME_SourceSelect_EXTERNAL;
+#else
+ CFE_TIME_Global.ClockSource = CFE_TIME_SourceSelect_INTERNAL;
+#endif
+ CFE_TIME_Global.ServerFlyState = CFE_TIME_FlywheelState_IS_FLY;
+
+ /*
+ ** Pending data values (from "time at tone" command data packet)...
+ */
+ CFE_TIME_Global.PendingState = CFE_TIME_ClockState_INVALID;
+
+ /*
+ ** Nonzero adjustment values...
+ */
+ CFE_TIME_Global.OneTimeDirection = CFE_TIME_AdjustDirection_ADD;
+ CFE_TIME_Global.OneHzDirection = CFE_TIME_AdjustDirection_ADD;
+ RefState->DelayDirection = CFE_TIME_AdjustDirection_ADD;
+
+ /*
+ ** Miscellaneous counters...
+ */
+ CFE_TIME_Global.VirtualMET = RefState->AtToneMET.Seconds;
+
+ /*
+ ** Time window verification values...
+ */
+ CFE_TIME_Global.MinElapsed = CFE_TIME_Micro2SubSecs(CFE_MISSION_TIME_MIN_ELAPSED);
+ CFE_TIME_Global.MaxElapsed = CFE_TIME_Micro2SubSecs(CFE_MISSION_TIME_MAX_ELAPSED);
+
+/*
+** Range checking for external time source data...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+ CFE_TIME_Global.MaxDelta.Seconds = CFE_PLATFORM_TIME_MAX_DELTA_SECS;
+ CFE_TIME_Global.MaxDelta.Subseconds = CFE_TIME_Micro2SubSecs(CFE_PLATFORM_TIME_MAX_DELTA_SUBS);
+#endif
+
+ /*
+ ** Maximum local clock value (before roll-over)...
+ */
+ CFE_TIME_Global.MaxLocalClock.Seconds = CFE_PLATFORM_TIME_MAX_LOCAL_SECS;
+ CFE_TIME_Global.MaxLocalClock.Subseconds = CFE_PLATFORM_TIME_MAX_LOCAL_SUBS;
+
+ /*
+ ** Range limits for time between tone signal interrupts...
+ */
+ CFE_TIME_Global.ToneOverLimit = CFE_TIME_Micro2SubSecs(CFE_PLATFORM_TIME_CFG_TONE_LIMIT);
+ CFE_TIME_Global.ToneUnderLimit = CFE_TIME_Micro2SubSecs((1000000 - CFE_PLATFORM_TIME_CFG_TONE_LIMIT));
+
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ /*
+ ** Initialize housekeeping packet (clear user data area)...
+ */
+ CFE_MSG_Init(&CFE_TIME_Global.HkPacket.TlmHeader.Msg, CFE_SB_ValueToMsgId(CFE_TIME_HK_TLM_MID),
+ sizeof(CFE_TIME_Global.HkPacket));
+
+ /*
+ ** Initialize diagnostic packet (clear user data area)...
+ */
+ CFE_MSG_Init(&CFE_TIME_Global.DiagPacket.TlmHeader.Msg, CFE_SB_ValueToMsgId(CFE_TIME_DIAG_TLM_MID),
+ sizeof(CFE_TIME_Global.DiagPacket));
+
+ /*
+ ** Initialize "time at the tone" signal command packet...
+ */
+ CFE_MSG_Init(&CFE_TIME_Global.ToneSignalCmd.CmdHeader.Msg, CFE_SB_ValueToMsgId(CFE_TIME_TONE_CMD_MID),
+ sizeof(CFE_TIME_Global.ToneSignalCmd));
+
+/*
+** Initialize "time at the tone" data command packet...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ CFE_MSG_Init(&CFE_TIME_Global.ToneDataCmd.CmdHeader.Msg, CFE_SB_ValueToMsgId(CFE_TIME_DATA_CMD_MID),
+ sizeof(CFE_TIME_Global.ToneDataCmd));
+#endif
+
+ /*
+ ** Initialize simulated tone send message ("fake tone" mode only)...
+ */
+#if (CFE_MISSION_TIME_CFG_FAKE_TONE == true)
+ CFE_MSG_Init(&CFE_TIME_Global.ToneSendCmd.CmdHeader.Msg, CFE_SB_ValueToMsgId(CFE_TIME_SEND_CMD_MID),
+ sizeof(CFE_TIME_Global.ToneSendCmd));
+#endif
+
+ /*
+ ** Initialize local 1Hz "wake-up" command packet (optional)...
+ */
+ CFE_MSG_Init(&CFE_TIME_Global.Local1HzCmd.CmdHeader.Msg, CFE_SB_ValueToMsgId(CFE_TIME_1HZ_CMD_MID),
+ sizeof(CFE_TIME_Global.Local1HzCmd));
+
+ return;
+
+} /* End of CFE_TIME_InitData() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_GetHkData() -- Report local housekeeping data */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_GetHkData(const CFE_TIME_Reference_t *Reference)
+{
+
+ /*
+ ** Get command execution counters...
+ */
+ CFE_TIME_Global.HkPacket.Payload.CommandCounter = CFE_TIME_Global.CommandCounter;
+ CFE_TIME_Global.HkPacket.Payload.CommandErrorCounter = CFE_TIME_Global.CommandErrorCounter;
+
+ /*
+ ** Current "as calculated" clock state...
+ */
+ CFE_TIME_Global.HkPacket.Payload.ClockStateAPI = (int16)CFE_TIME_CalculateState(Reference);
+
+ /*
+ ** Current clock state flags...
+ */
+ CFE_TIME_Global.HkPacket.Payload.ClockStateFlags = CFE_TIME_GetClockInfo();
+
+ /*
+ ** Leap Seconds...
+ */
+ CFE_TIME_Global.HkPacket.Payload.LeapSeconds = Reference->AtToneLeapSeconds;
+
+ /*
+ ** Current MET and STCF time values...
+ */
+ CFE_TIME_Global.HkPacket.Payload.SecondsMET = Reference->CurrentMET.Seconds;
+ CFE_TIME_Global.HkPacket.Payload.SubsecsMET = Reference->CurrentMET.Subseconds;
+
+ CFE_TIME_Global.HkPacket.Payload.SecondsSTCF = Reference->AtToneSTCF.Seconds;
+ CFE_TIME_Global.HkPacket.Payload.SubsecsSTCF = Reference->AtToneSTCF.Subseconds;
+
+/*
+** 1Hz STCF adjustment values (server only)...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ CFE_TIME_Global.HkPacket.Payload.Seconds1HzAdj = CFE_TIME_Global.OneHzAdjust.Seconds;
+ CFE_TIME_Global.HkPacket.Payload.Subsecs1HzAdj = CFE_TIME_Global.OneHzAdjust.Subseconds;
+#endif
+
+/*
+** Time at tone delay values (client only)...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ CFE_TIME_Global.HkPacket.Payload.SecondsDelay = Reference->AtToneDelay.Seconds;
+ CFE_TIME_Global.HkPacket.Payload.SubsecsDelay = Reference->AtToneDelay.Subseconds;
+#endif
+
+ return;
+
+} /* End of CFE_TIME_GetHkData() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_GetDiagData() -- Report diagnostics data */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_GetDiagData(void)
+{
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t TempTime;
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.AtToneMET, &Reference.AtToneMET);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.AtToneSTCF, &Reference.AtToneSTCF);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.AtToneDelay, &Reference.AtToneDelay);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.AtToneLatch, &Reference.AtToneLatch);
+
+ CFE_TIME_Global.DiagPacket.Payload.AtToneLeapSeconds = Reference.AtToneLeapSeconds;
+ CFE_TIME_Global.DiagPacket.Payload.ClockStateAPI = CFE_TIME_CalculateState(&Reference);
+
+ /*
+ ** Data values that reflect the time (right now)...
+ */
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.TimeSinceTone, &Reference.TimeSinceTone);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.CurrentLatch, &Reference.CurrentLatch);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.CurrentMET, &Reference.CurrentMET);
+ TempTime = CFE_TIME_CalculateTAI(&Reference);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.CurrentTAI, &TempTime);
+ TempTime = CFE_TIME_CalculateUTC(&Reference);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.CurrentUTC, &TempTime);
+
+ /*
+ ** Data values used to define the current clock state...
+ */
+ CFE_TIME_Global.DiagPacket.Payload.ClockSetState = Reference.ClockSetState;
+ CFE_TIME_Global.DiagPacket.Payload.ClockFlyState = Reference.ClockFlyState;
+ CFE_TIME_Global.DiagPacket.Payload.ClockSource = CFE_TIME_Global.ClockSource;
+ CFE_TIME_Global.DiagPacket.Payload.ClockSignal = CFE_TIME_Global.ClockSignal;
+ CFE_TIME_Global.DiagPacket.Payload.ServerFlyState = CFE_TIME_Global.ServerFlyState;
+ CFE_TIME_Global.DiagPacket.Payload.Forced2Fly = (int16)CFE_TIME_Global.Forced2Fly;
+
+ /*
+ ** Clock state flags...
+ */
+ CFE_TIME_Global.DiagPacket.Payload.ClockStateFlags = CFE_TIME_GetClockInfo();
+
+ /*
+ ** STCF adjustment direction values...
+ */
+ CFE_TIME_Global.DiagPacket.Payload.OneTimeDirection = CFE_TIME_Global.OneTimeDirection;
+ CFE_TIME_Global.DiagPacket.Payload.OneHzDirection = CFE_TIME_Global.OneHzDirection;
+ CFE_TIME_Global.DiagPacket.Payload.DelayDirection = Reference.DelayDirection;
+
+ /*
+ ** STCF adjustment values...
+ */
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.OneTimeAdjust, &CFE_TIME_Global.OneTimeAdjust);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.OneHzAdjust, &CFE_TIME_Global.OneHzAdjust);
+
+ /*
+ ** Most recent local clock latch values...
+ */
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.ToneSignalLatch, &CFE_TIME_Global.ToneSignalLatch);
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.ToneDataLatch, &CFE_TIME_Global.ToneDataLatch);
+
+ /*
+ ** Miscellaneous counters (subject to reset command)...
+ */
+ CFE_TIME_Global.DiagPacket.Payload.ToneMatchCounter = CFE_TIME_Global.ToneMatchCounter;
+ CFE_TIME_Global.DiagPacket.Payload.ToneMatchErrorCounter = CFE_TIME_Global.ToneMatchErrorCounter;
+ CFE_TIME_Global.DiagPacket.Payload.ToneSignalCounter = CFE_TIME_Global.ToneSignalCounter;
+ CFE_TIME_Global.DiagPacket.Payload.ToneDataCounter = CFE_TIME_Global.ToneDataCounter;
+ CFE_TIME_Global.DiagPacket.Payload.ToneIntCounter = CFE_TIME_Global.ToneIntCounter;
+ CFE_TIME_Global.DiagPacket.Payload.ToneIntErrorCounter = CFE_TIME_Global.ToneIntErrorCounter;
+ CFE_TIME_Global.DiagPacket.Payload.ToneTaskCounter = CFE_TIME_Global.ToneTaskCounter;
+ CFE_TIME_Global.DiagPacket.Payload.VersionCounter =
+ CFE_TIME_Global.LastVersionCounter - CFE_TIME_Global.ResetVersionCounter;
+ CFE_TIME_Global.DiagPacket.Payload.LocalIntCounter = CFE_TIME_Global.LocalIntCounter;
+ CFE_TIME_Global.DiagPacket.Payload.LocalTaskCounter = CFE_TIME_Global.LocalTaskCounter;
+
+ /*
+ ** Miscellaneous counters (not subject to reset command)...
+ */
+ CFE_TIME_Global.DiagPacket.Payload.VirtualMET = CFE_TIME_Global.VirtualMET;
+
+ /*
+ ** Time window verification values (converted from micro-secs)...
+ **
+ ** Regardless of whether the tone follows the time packet, or vice
+ ** versa, these values define the acceptable window of time for
+ ** the second event to follow the first. The minimum value may
+ ** be as little as zero, and the maximum must be something less
+ ** than a second.
+ */
+ CFE_TIME_Global.DiagPacket.Payload.MinElapsed = CFE_TIME_Global.MinElapsed;
+ CFE_TIME_Global.DiagPacket.Payload.MaxElapsed = CFE_TIME_Global.MaxElapsed;
+
+ /*
+ ** Maximum local clock value (before roll-over)...
+ */
+ CFE_TIME_Copy(&CFE_TIME_Global.DiagPacket.Payload.MaxLocalClock, &CFE_TIME_Global.MaxLocalClock);
+
+ /*
+ ** Tone signal tolerance limits...
+ */
+ CFE_TIME_Global.DiagPacket.Payload.ToneOverLimit = CFE_TIME_Global.ToneOverLimit;
+ CFE_TIME_Global.DiagPacket.Payload.ToneUnderLimit = CFE_TIME_Global.ToneUnderLimit;
+
+ /*
+ ** Reset Area access status...
+ */
+ CFE_TIME_Global.DiagPacket.Payload.DataStoreStatus = CFE_TIME_Global.DataStoreStatus;
+
+ return;
+
+} /* End of CFE_TIME_GetDiagData() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_GetReference() -- get reference data (time at "tone") */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_GetReference(CFE_TIME_Reference_t *Reference)
+{
+ CFE_TIME_SysTime_t TimeSinceTone;
+ CFE_TIME_SysTime_t CurrentMET;
+ uint32 VersionCounter;
+ uint32 RetryCount = 4;
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ /*
+ ** VersionCounter is incremented when reference data is modified...
+ */
+ while (true)
+ {
+ VersionCounter = CFE_TIME_Global.LastVersionCounter;
+ RefState = &CFE_TIME_Global.ReferenceState[VersionCounter & CFE_TIME_REFERENCE_BUF_MASK];
+
+ Reference->CurrentLatch = CFE_TIME_LatchClock();
+
+ Reference->AtToneMET = RefState->AtToneMET;
+ Reference->AtToneSTCF = RefState->AtToneSTCF;
+ Reference->AtToneLeapSeconds = RefState->AtToneLeapSeconds;
+ Reference->AtToneDelay = RefState->AtToneDelay;
+ Reference->AtToneLatch = RefState->AtToneLatch;
+
+ Reference->ClockSetState = RefState->ClockSetState;
+ Reference->ClockFlyState = RefState->ClockFlyState;
+ Reference->DelayDirection = RefState->DelayDirection;
+
+ /*
+ * If the version counter inside the state record
+ * is the same value as the global _after_ copying the
+ * data, then the value is considered valid.
+ */
+ if (VersionCounter == RefState->StateVersion)
+ {
+ /* successful read */
+ break;
+ }
+
+ /*
+ * The value was caught mid-update, so the reference data
+ * might not be consistent. Try again to read it.
+ *
+ * The number of retries is limited, to prevent getting
+ * stuck in this loop forever. There is currently no
+ * way to handle the inability to read the time reference.
+ */
+ if (RetryCount == 0)
+ {
+ /* unsuccessful read */
+ break;
+ }
+
+ --RetryCount;
+ }
+
+ /*
+ ** Compute the amount of time "since" the tone...
+ */
+ if (CFE_TIME_Compare(Reference->CurrentLatch, Reference->AtToneLatch) == CFE_TIME_A_LT_B)
+ {
+ /*
+ ** Local clock has rolled over since last tone...
+ */
+ TimeSinceTone = CFE_TIME_Subtract(CFE_TIME_Global.MaxLocalClock, Reference->AtToneLatch);
+ TimeSinceTone = CFE_TIME_Add(TimeSinceTone, Reference->CurrentLatch);
+ }
+ else
+ {
+ /*
+ ** Normal case -- local clock is greater than latch at tone...
+ */
+ TimeSinceTone = CFE_TIME_Subtract(Reference->CurrentLatch, Reference->AtToneLatch);
+ }
+
+ Reference->TimeSinceTone = TimeSinceTone;
+
+ /*
+ ** Add in the MET at the tone...
+ */
+ CurrentMET = CFE_TIME_Add(TimeSinceTone, Reference->AtToneMET);
+
+/*
+** Synchronize "this" time client to the time server...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ if (Reference->DelayDirection == CFE_TIME_AdjustDirection_ADD)
+ {
+ CurrentMET = CFE_TIME_Add(CurrentMET, Reference->AtToneDelay);
+ }
+ else
+ {
+ CurrentMET = CFE_TIME_Subtract(CurrentMET, Reference->AtToneDelay);
+ }
+#endif
+
+ Reference->CurrentMET = CurrentMET;
+
+ return;
+
+} /* End of CFE_TIME_GetReference() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_CalculateTAI() -- calculate TAI from reference data */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+CFE_TIME_SysTime_t CFE_TIME_CalculateTAI(const CFE_TIME_Reference_t *Reference)
+{
+ CFE_TIME_SysTime_t TimeAsTAI;
+
+ TimeAsTAI = CFE_TIME_Add(Reference->CurrentMET, Reference->AtToneSTCF);
+
+ return (TimeAsTAI);
+
+} /* End of CFE_TIME_CalculateTAI() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_CalculateUTC() -- calculate UTC from reference data */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+CFE_TIME_SysTime_t CFE_TIME_CalculateUTC(const CFE_TIME_Reference_t *Reference)
+{
+ CFE_TIME_SysTime_t TimeAsUTC;
+
+ TimeAsUTC = CFE_TIME_Add(Reference->CurrentMET, Reference->AtToneSTCF);
+ TimeAsUTC.Seconds -= Reference->AtToneLeapSeconds;
+
+ return (TimeAsUTC);
+
+} /* End of CFE_TIME_CalculateUTC() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_CalculateState() -- determine current time state (per API) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int16 CFE_TIME_CalculateState(const CFE_TIME_Reference_t *Reference)
+{
+ int16 ClockState;
+
+ /*
+ ** Determine the current clock state...
+ */
+ if (Reference->ClockSetState == CFE_TIME_SetState_WAS_SET)
+ {
+ if (Reference->ClockFlyState == CFE_TIME_FlywheelState_NO_FLY)
+ {
+ /*
+ ** CFE_TIME_ClockState_VALID = clock set and not fly-wheeling...
+ */
+ ClockState = CFE_TIME_ClockState_VALID;
+
+/*
+** If the server is fly-wheel then the client must also
+** report fly-wheel (even if it is not)...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+ if (CFE_TIME_Global.ServerFlyState == CFE_TIME_FlywheelState_IS_FLY)
+ {
+ ClockState = CFE_TIME_ClockState_FLYWHEEL;
+ }
+#endif
+ }
+ else
+ {
+ /*
+ ** CFE_TIME_ClockState_FLYWHEEL = clock set and fly-wheeling...
+ */
+ ClockState = CFE_TIME_ClockState_FLYWHEEL;
+ }
+ }
+ else
+ {
+ /*
+ ** CFE_TIME_ClockState_INVALID = clock not set...
+ */
+ ClockState = CFE_TIME_ClockState_INVALID;
+ }
+
+ return (ClockState);
+
+} /* End of CFE_TIME_CalculateState() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetState() -- set clock state */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void CFE_TIME_SetState(int16 NewState)
+{
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ /*
+ ** If we get a command to set the clock to "flywheel" mode, then
+ ** set a global flag so that we can choose to ignore time
+ ** updates until we get another clock state command...
+ */
+ if (NewState == CFE_TIME_ClockState_FLYWHEEL)
+ {
+ CFE_TIME_Global.Forced2Fly = true;
+ RefState->ClockFlyState = CFE_TIME_FlywheelState_IS_FLY;
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+ CFE_TIME_Global.ServerFlyState = CFE_TIME_FlywheelState_IS_FLY;
+#endif
+ }
+ else if (NewState == CFE_TIME_ClockState_VALID)
+ {
+ CFE_TIME_Global.Forced2Fly = false;
+ RefState->ClockSetState = CFE_TIME_SetState_WAS_SET;
+ }
+ else
+ {
+ CFE_TIME_Global.Forced2Fly = false;
+ RefState->ClockSetState = CFE_TIME_SetState_NOT_SET;
+ }
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_SetState() */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetSource() -- set clock source */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+void CFE_TIME_SetSource(int16 NewSource)
+{
+ CFE_TIME_Global.ClockSource = NewSource;
+
+} /* End of CFE_TIME_SetSource() */
+#endif /* CFE_PLATFORM_TIME_CFG_SOURCE */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetSignal() -- set tone signal (pri vs red) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SIGNAL == true)
+void CFE_TIME_SetSignal(int16 NewSignal)
+{
+ /*
+ ** Maintain current tone signal selection for telemetry...
+ */
+ CFE_TIME_Global.ClockSignal = NewSignal;
+
+} /* End of CFE_TIME_SetSignal() */
+#endif /* CFE_PLATFORM_TIME_CFG_SIGNAL */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetDelay() -- set tone delay (time client only) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+void CFE_TIME_SetDelay(CFE_TIME_SysTime_t NewDelay, int16 Direction)
+{
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ RefState->AtToneDelay = NewDelay;
+ RefState->DelayDirection = Direction;
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_SetDelay() */
+#endif /* CFE_PLATFORM_TIME_CFG_CLIENT */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetTime() -- set time (time server only) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_SetTime(CFE_TIME_SysTime_t NewTime)
+{
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ /*
+ ** The input to this function is a time value that includes MET
+ ** and STCF. If the default time format is UTC, the input
+ ** time value has had leaps seconds removed from the total.
+ */
+ CFE_TIME_Reference_t Reference;
+ CFE_TIME_SysTime_t NewSTCF;
+
+ /*
+ ** Get reference time values (local time, time at tone, etc.)...
+ */
+ CFE_TIME_GetReference(&Reference);
+
+ /*
+ ** Remove current MET from the new time value (leaves STCF)...
+ */
+ NewSTCF = CFE_TIME_Subtract(NewTime, Reference.CurrentMET);
+
+/*
+** Restore leap seconds if default time format is UTC...
+*/
+#if (CFE_MISSION_TIME_CFG_DEFAULT_UTC == true)
+ NewSTCF.Seconds += Reference.AtToneLeapSeconds;
+#endif
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ RefState->AtToneSTCF = NewSTCF;
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_SetTime() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetMET() -- set MET (time server only) */
+/* */
+/* Note: This command will not have lasting effect if configured */
+/* to get external time of type MET. Also, there cannot */
+/* be a local h/w MET and an external MET since both would */
+/* need to be synchronized to the same tone signal. */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_SetMET(CFE_TIME_SysTime_t NewMET)
+{
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ /*
+ ** Update reference values used to compute current time...
+ */
+ RefState->AtToneMET = NewMET;
+ CFE_TIME_Global.VirtualMET = NewMET.Seconds;
+ RefState->AtToneLatch = CFE_TIME_LatchClock();
+
+/*
+** Update h/w MET register...
+*/
+#if (CFE_PLATFORM_TIME_CFG_VIRTUAL != true)
+ OS_SetLocalMET(NewMET.Seconds);
+#endif
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_SetMET() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetSTCF() -- set STCF (time server only) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_SetSTCF(CFE_TIME_SysTime_t NewSTCF)
+{
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ RefState->AtToneSTCF = NewSTCF;
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_SetSTCF() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetLeapSeconds() -- set leap seconds (time server only) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_SetLeapSeconds(int16 NewLeaps)
+{
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ RefState->AtToneLeapSeconds = NewLeaps;
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_SetLeapSeconds() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_SetAdjust() -- one time STCF adjustment (server only) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_SetAdjust(CFE_TIME_SysTime_t NewAdjust, int16 Direction)
+{
+ CFE_TIME_SysTime_t NewSTCF;
+ volatile CFE_TIME_ReferenceState_t *RefState;
+
+ RefState = CFE_TIME_StartReferenceUpdate();
+
+ CFE_TIME_Global.OneTimeAdjust = NewAdjust;
+ CFE_TIME_Global.OneTimeDirection = Direction;
+
+ if (Direction == CFE_TIME_AdjustDirection_ADD)
+ {
+ NewSTCF = CFE_TIME_Add(RefState->AtToneSTCF, NewAdjust);
+ }
+ else
+ {
+ NewSTCF = CFE_TIME_Subtract(RefState->AtToneSTCF, NewAdjust);
+ }
+
+ RefState->AtToneSTCF = NewSTCF;
+
+ /*
+ ** Time has changed, force anyone reading time to retry...
+ */
+ CFE_TIME_FinishReferenceUpdate(RefState);
+
+ return;
+
+} /* End of CFE_TIME_SetAdjust() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_Set1HzAdj() -- 1Hz STCF adjustment (time server only) */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_Set1HzAdj(CFE_TIME_SysTime_t NewAdjust, int16 Direction)
+{
+ /*
+ ** Store values for 1Hz adjustment...
+ */
+ CFE_TIME_Global.OneHzAdjust = NewAdjust;
+ CFE_TIME_Global.OneHzDirection = Direction;
+
+} /* End of CFE_TIME_Set1HzAdj() */
+#endif /* CFE_PLATFORM_TIME_CFG_SERVER */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* */
+/* CFE_TIME_CleanUpApp() -- Free resources associated with App */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int32 CFE_TIME_CleanUpApp(CFE_ES_AppId_t AppId)
+{
+ int32 Status;
+ uint32 AppIndex;
+
+ Status = CFE_ES_AppID_ToIndex(AppId, &AppIndex);
+ if (Status != CFE_SUCCESS)
+ {
+ /* Do nothing */
+ }
+ else if (AppIndex < (sizeof(CFE_TIME_Global.SynchCallback) / sizeof(CFE_TIME_Global.SynchCallback[0])))
+ {
+ CFE_TIME_Global.SynchCallback[AppIndex].Ptr = NULL;
+ }
+ else
+ {
+ Status = CFE_TIME_CALLBACK_NOT_REGISTERED;
+ }
+
+ return Status;
+}
+
+/************************/
+/* End of File Comment */
+/************************/
diff --git a/modules/time/fsw/src/cfe_time_utils.h b/modules/time/fsw/src/cfe_time_utils.h
new file mode 100644
index 000000000..5b11a06e2
--- /dev/null
+++ b/modules/time/fsw/src/cfe_time_utils.h
@@ -0,0 +1,451 @@
+/*
+** 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 Time Services (TIME) library utilities header file
+ *
+ * Author: S.Walling/Microtel
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_TIME_UTILS_H
+#define CFE_TIME_UTILS_H
+
+/*
+** Required header files...
+*/
+#include "cfe_time_module_all.h"
+
+/*************************************************************************/
+
+#define CFE_TIME_NEGATIVE 0x80000000 /* ~ 68 * 31,536,000 seconds */
+
+/*************************************************************************/
+
+/*
+** Main task definitions...
+*/
+#define CFE_TIME_TASK_NAME "CFE_TIME"
+
+/*
+** Interrupt task definitions...
+*/
+#define CFE_TIME_TASK_TONE_NAME "TIME_TONE_TASK"
+#define CFE_TIME_TASK_1HZ_NAME "TIME_1HZ_TASK"
+#define CFE_TIME_TASK_STACK_PTR CFE_ES_TASK_STACK_ALLOCATE
+#define CFE_TIME_TASK_FLAGS 0
+
+/*
+** Interrupt semaphore definitions...
+*/
+#define CFE_TIME_SEM_TONE_NAME "TIME_TONE_SEM"
+#define CFE_TIME_SEM_1HZ_NAME "TIME_1HZ_SEM"
+#define CFE_TIME_SEM_VALUE 0
+#define CFE_TIME_SEM_OPTIONS 0
+
+/*
+** Main Task Pipe definitions...
+*/
+
+#define CFE_TIME_TASK_PIPE_NAME "TIME_CMD_PIPE"
+#define CFE_TIME_TASK_PIPE_DEPTH 12
+
+/*
+** Reset Area state state at startup...
+*/
+
+#define CFE_TIME_RESET_AREA_ERROR 1 /* no mem available */
+#define CFE_TIME_RESET_AREA_BAD 2 /* had invalid data */
+#define CFE_TIME_RESET_AREA_NEW 3 /* new memory block */
+#define CFE_TIME_RESET_AREA_EXISTING 4 /* had valid data */
+
+/*
+ * Definitions for time reference multi-buffering
+ *
+ * To allow higher priority tasks and ISRs to get the time reference,
+ * it must be buffered in case the ISR occurs mid-update.
+ *
+ * This controls the depth of the buffer. Higher values will be
+ * more resilient to concurrent updates at the cost of using more
+ * memory.
+ *
+ * Note that the 1Hz state machine can make several updates to this
+ * in rapid succession, and the "fake tone" processing tied to 1Hz
+ * might make another update.
+ *
+ * This must be a power of 2.
+ */
+#define CFE_TIME_REFERENCE_BUF_DEPTH 4
+#define CFE_TIME_REFERENCE_BUF_MASK (CFE_TIME_REFERENCE_BUF_DEPTH - 1)
+
+/*************************************************************************/
+
+/*
+** Type definition (time reference data)...
+*/
+typedef struct
+{
+
+ CFE_TIME_SysTime_t AtToneMET; /* MET at time of tone */
+ CFE_TIME_SysTime_t AtToneSTCF; /* STCF at time of tone */
+ int16 AtToneLeapSeconds; /* Leap Seconds at time of tone */
+ int16 ClockSetState; /* Time has been "set" */
+ int16 ClockFlyState; /* Current fly-wheel state */
+ int16 DelayDirection; /* Wheter "AtToneDelay" is add or subtract */
+ CFE_TIME_SysTime_t AtToneDelay; /* Adjustment for slow tone detection */
+ CFE_TIME_SysTime_t AtToneLatch; /* Local clock latched at time of tone */
+ CFE_TIME_SysTime_t CurrentLatch; /* Local clock latched just "now" */
+ CFE_TIME_SysTime_t TimeSinceTone; /* Time elapsed since the tone */
+ CFE_TIME_SysTime_t CurrentMET; /* MET at this instant */
+
+} CFE_TIME_Reference_t;
+
+/*
+** Time Synchronization Callback Registry Information
+*/
+typedef struct
+{
+ volatile CFE_TIME_SynchCallbackPtr_t Ptr; /**< \brief Pointer to Callback function */
+} CFE_TIME_SynchCallbackRegEntry_t;
+
+/*
+** Data values used to compute time (in reference to "tone")...
+**
+** These are all the global values used during CFE_TIME_GetReference()
+** to compute the current reference time. They are kept in a separate
+** structure so every update can be synchronized.
+*/
+typedef struct
+{
+ uint32 StateVersion;
+
+ int16 AtToneLeapSeconds;
+ int16 ClockSetState;
+ int16 ClockFlyState;
+ int16 DelayDirection;
+
+ CFE_TIME_SysTime_t AtToneMET;
+ CFE_TIME_SysTime_t AtToneSTCF;
+ CFE_TIME_SysTime_t AtToneDelay;
+ CFE_TIME_SysTime_t AtToneLatch;
+
+} CFE_TIME_ReferenceState_t;
+
+/*************************************************************************/
+
+/*
+** Type definition (time task global data)...
+*/
+typedef struct
+{
+ /*
+ ** Task command interface counters...
+ */
+ uint8 CommandCounter;
+ uint8 CommandErrorCounter;
+
+ /*
+ ** Task housekeeping and diagnostics telemetry packets...
+ */
+ CFE_TIME_HousekeepingTlm_t HkPacket;
+ CFE_TIME_DiagnosticTlm_t DiagPacket;
+
+ /*
+ ** Task operational data (not reported in housekeeping)...
+ */
+ CFE_SB_PipeId_t CmdPipe;
+
+ /*
+ ** Task initialization data (not reported in housekeeping)...
+ */
+ int16 ClockSource;
+ int16 ClockSignal;
+ int16 ServerFlyState;
+
+ /*
+ ** Pending data values (from "time at tone" command data)...
+ */
+ CFE_TIME_SysTime_t PendingMET;
+ CFE_TIME_SysTime_t PendingSTCF;
+ int16 PendingLeaps;
+ int16 PendingState;
+
+ /*
+ ** STCF adjustment values...
+ */
+ CFE_TIME_SysTime_t OneTimeAdjust;
+ CFE_TIME_SysTime_t OneHzAdjust;
+
+ int16 OneTimeDirection; /* Add = true */
+ int16 OneHzDirection;
+
+ /*
+ ** Most recent local clock latch values...
+ */
+ CFE_TIME_SysTime_t ToneSignalLatch; /* Latched at tone */
+ CFE_TIME_SysTime_t ToneDataLatch; /* Latched at packet */
+
+ /*
+ ** Miscellaneous counters...
+ */
+ uint32 ToneMatchCounter; /* Tone and data match */
+ uint32 ToneMatchErrorCounter; /* Tone and data mismatch */
+ uint32 ToneSignalCounter; /* Tone signal commands */
+ uint32 ToneDataCounter; /* Tone data commands */
+ uint32 ToneIntCounter; /* Tone interrupts (valid) */
+ uint32 ToneIntErrorCounter; /* Tone interrupts (invalid) */
+ uint32 ToneTaskCounter; /* Tone task wake-ups */
+ uint32 VirtualMET; /* Software MET */
+ uint32 LocalIntCounter; /* Local 1Hz interrupts */
+ uint32 LocalTaskCounter; /* Local 1Hz task wake-ups */
+ uint32 InternalCount; /* Time from internal data */
+ uint32 ExternalCount; /* Time from external data */
+
+ volatile CFE_TIME_ReferenceState_t ReferenceState[CFE_TIME_REFERENCE_BUF_DEPTH];
+ volatile uint32 LastVersionCounter; /* Completed Updates to "AtTone" values */
+ uint32 ResetVersionCounter; /* Version counter at last counter reset */
+
+ /*
+ ** Time window verification values (converted from micro-secs)...
+ **
+ ** Regardless of whether the tone follows the time packet, or vice
+ ** versa, these values define the acceptable window of time for
+ ** the second event to follow the first. The minimum value may
+ ** be as little as zero, and the maximum must be something less
+ ** than a second.
+ */
+ uint32 MinElapsed;
+ uint32 MaxElapsed;
+
+ /*
+ ** Maximum local clock value (before roll-over)...
+ */
+ CFE_TIME_SysTime_t MaxLocalClock;
+
+ /*
+ ** Clock state has been commanded into (CFE_TIME_ClockState_FLYWHEEL)...
+ */
+ bool Forced2Fly;
+
+ /*
+ ** Clock state has just transitioned into (CFE_TIME_ClockState_FLYWHEEL)...
+ ** (not in HK since it won't be true long enough to detect)
+ */
+
+ bool AutoStartFly;
+ bool IsToneGood;
+
+ /*
+ ** Spare byte for alignment
+ */
+ bool Spare;
+
+ /*
+ ** Local 1Hz wake-up command packet (not related to time at tone)...
+ */
+ CFE_TIME_1HzCmd_t Local1HzCmd;
+
+ /*
+ ** Time at the tone command packets (sent by time servers)...
+ */
+ CFE_TIME_ToneDataCmd_t ToneDataCmd;
+ CFE_TIME_ToneSignalCmd_t ToneSignalCmd;
+
+ /*
+ * Normally "tone send" commands come from the scheduler based on the
+ * configured action table, so it occurs at the right point between tones.
+ *
+ * However when "fake tone" mode is enabled, then we will locally generate the
+ * "tone send" message as part of the Tone task, in addition to the regular
+ * "tone signal" message above.
+ */
+#if (CFE_MISSION_TIME_CFG_FAKE_TONE == true)
+ CFE_TIME_FakeToneCmd_t ToneSendCmd;
+#endif
+
+ /*
+ ** Interrupt task semaphores...
+ */
+ osal_id_t LocalSemaphore;
+ osal_id_t ToneSemaphore;
+ /*
+ ** Interrupt task ID's...
+ */
+ CFE_ES_TaskId_t LocalTaskID;
+ CFE_ES_TaskId_t ToneTaskID;
+
+ /*
+ ** Maximum difference from expected for external time sources...
+ */
+
+ CFE_TIME_SysTime_t MaxDelta;
+
+ /*
+ ** Tone signal tolerance limits...
+ */
+ uint32 ToneOverLimit;
+ uint32 ToneUnderLimit;
+
+ /*
+ ** Reset Area ...
+ */
+ uint32 DataStoreStatus;
+
+ /*
+ ** Synchronization Callback Registry
+ ** One callback per app is allowed
+ */
+ CFE_TIME_SynchCallbackRegEntry_t SynchCallback[CFE_PLATFORM_ES_MAX_APPLICATIONS];
+
+} CFE_TIME_Global_t;
+
+/*
+** Time task global data (from "cfe_time_task.c")...
+*/
+extern CFE_TIME_Global_t CFE_TIME_Global;
+
+/*************************************************************************/
+/*
+** Function prototypes (get local clock)...
+*/
+CFE_TIME_SysTime_t CFE_TIME_LatchClock(void);
+
+/*
+** Function prototypes (Time Services utilities data)...
+*/
+int32 CFE_TIME_TaskInit(void);
+void CFE_TIME_TaskPipe(CFE_SB_Buffer_t *SBBufPtr);
+void CFE_TIME_InitData(void);
+void CFE_TIME_QueryResetVars(void);
+void CFE_TIME_UpdateResetVars(const CFE_TIME_Reference_t *Reference);
+void CFE_TIME_GetDiagData(void);
+void CFE_TIME_GetHkData(const CFE_TIME_Reference_t *Reference);
+
+/*
+** Function prototypes (reference)...
+*/
+void CFE_TIME_GetReference(CFE_TIME_Reference_t *Reference);
+
+/*
+** Function prototypes (calculate TAI/UTC)...
+*/
+CFE_TIME_SysTime_t CFE_TIME_CalculateTAI(const CFE_TIME_Reference_t *Reference);
+CFE_TIME_SysTime_t CFE_TIME_CalculateUTC(const CFE_TIME_Reference_t *Reference);
+
+int16 CFE_TIME_CalculateState(const CFE_TIME_Reference_t *Reference);
+
+/*
+** Function prototypes (set time globals)...
+*/
+void CFE_TIME_SetState(int16 NewState);
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+void CFE_TIME_SetSource(int16 NewSource);
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SIGNAL == true)
+void CFE_TIME_SetSignal(int16 NewSignal);
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+void CFE_TIME_SetDelay(CFE_TIME_SysTime_t NewDelay, int16 Direction);
+#endif
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_SetTime(CFE_TIME_SysTime_t NewTime);
+void CFE_TIME_SetMET(CFE_TIME_SysTime_t NewMET);
+void CFE_TIME_SetSTCF(CFE_TIME_SysTime_t NewSTCF);
+void CFE_TIME_SetLeapSeconds(int16 NewLeaps);
+void CFE_TIME_SetAdjust(CFE_TIME_SysTime_t NewAdjust, int16 Direction);
+void CFE_TIME_Set1HzAdj(CFE_TIME_SysTime_t NewAdjust, int16 Direction);
+#endif
+
+/*
+** Function prototypes (send time at tone data packet -- local MET)...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+void CFE_TIME_ToneSend(void); /* signal to send time at tone packet */
+#endif
+
+/*
+** Function prototypes (send time at tone data packet -- external time)...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SRC_MET == true)
+int32 CFE_TIME_ToneSendMET(CFE_TIME_SysTime_t NewMET);
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SRC_GPS == true)
+int32 CFE_TIME_ToneSendGPS(CFE_TIME_SysTime_t NewTime, int16 NewLeaps);
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SRC_TIME == true)
+int32 CFE_TIME_ToneSendTime(CFE_TIME_SysTime_t NewTime);
+#endif
+
+/*
+ * Helper function for updating the "Reference" value
+ * This is the local replacement for "OS_IntLock()"
+ */
+volatile CFE_TIME_ReferenceState_t *CFE_TIME_StartReferenceUpdate(void);
+
+/*
+ * Helper function for updating the "Reference" value
+ * This is the local replacement for "OS_IntUnlock()"
+ */
+static inline void CFE_TIME_FinishReferenceUpdate(volatile CFE_TIME_ReferenceState_t *NextState)
+{
+ CFE_TIME_Global.LastVersionCounter = NextState->StateVersion;
+}
+
+/*
+ * Helper function for getting the "Reference" value
+ * This is the replacement for direct memory reads of
+ * the state info from the global data structure.
+ */
+static inline volatile CFE_TIME_ReferenceState_t *CFE_TIME_GetReferenceState(void)
+{
+ return &CFE_TIME_Global.ReferenceState[CFE_TIME_Global.LastVersionCounter & CFE_TIME_REFERENCE_BUF_MASK];
+}
+
+/*
+** Function prototypes (process time at the tone signal and data packet)...
+*/
+void CFE_TIME_ToneSignal(void);
+void CFE_TIME_ToneData(const CFE_TIME_ToneDataCmd_Payload_t *ToneDataCmd);
+void CFE_TIME_ToneVerify(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2);
+void CFE_TIME_ToneUpdate(void);
+
+/*
+** Function prototypes (tone 1Hz interrupt)...
+*/
+void CFE_TIME_Tone1HzISR(void);
+void CFE_TIME_Tone1HzTask(void);
+void CFE_TIME_NotifyTimeSynchApps(void);
+
+/*
+** Function prototypes (local 1Hz interrupt)...
+*/
+void CFE_TIME_Local1HzTask(void);
+void CFE_TIME_Local1HzStateMachine(void);
+void CFE_TIME_Local1HzTimerCallback(osal_id_t TimerId, void *Arg);
+
+#endif /* CFE_TIME_UTILS_H */
diff --git a/modules/time/fsw/src/cfe_time_verify.h b/modules/time/fsw/src/cfe_time_verify.h
new file mode 100644
index 000000000..015e8cc60
--- /dev/null
+++ b/modules/time/fsw/src/cfe_time_verify.h
@@ -0,0 +1,187 @@
+/*
+** 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 Time Services (TIME) configuration verification
+ *
+ * Author: S.Walling/Microtel
+ *
+ * Notes:
+ *
+ */
+
+#ifndef CFE_TIME_VERIFY_H
+#define CFE_TIME_VERIFY_H
+
+#include "cfe_mission_cfg.h"
+#include "cfe_platform_cfg.h"
+
+/*************************************************************************/
+
+/*
+** Validate default time client/server selection...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SERVER == true)
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+#error Cannot define both CFE_PLATFORM_TIME_CFG_SERVER and CFE_PLATFORM_TIME_CFG_CLIENT as true!
+#endif
+#else
+#if (CFE_PLATFORM_TIME_CFG_CLIENT != true)
+#error Must define either CFE_PLATFORM_TIME_CFG_SERVER or CFE_PLATFORM_TIME_CFG_CLIENT as true!
+#endif
+#endif
+
+/*
+** Validate default time format selection...
+*/
+#if (CFE_MISSION_TIME_CFG_DEFAULT_TAI == true)
+#if (CFE_MISSION_TIME_CFG_DEFAULT_UTC == true)
+#error Cannot define both CFE_MISSION_TIME_CFG_DEFAULT_UTC and CFE_MISSION_TIME_CFG_DEFAULT_TAI as true!
+#endif
+#else
+#if (CFE_MISSION_TIME_CFG_DEFAULT_UTC != true)
+#error Must define either CFE_MISSION_TIME_CFG_DEFAULT_UTC or CFE_MISSION_TIME_CFG_DEFAULT_TAI as true!
+#endif
+#endif
+
+/*
+** Validate time source selection...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+#error Cannot define both CFE_PLATFORM_TIME_CFG_CLIENT and CFE_PLATFORM_TIME_CFG_SOURCE as true!
+#endif
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+#if (CFE_PLATFORM_TIME_CFG_VIRTUAL != true)
+#error Cannot define CFE_PLATFORM_TIME_CFG_SOURCE as true without defining CFE_PLATFORM_TIME_CFG_VIRTUAL as true!
+#endif
+#endif
+
+/*
+** Validate local MET selections...
+*/
+#if (CFE_PLATFORM_TIME_CFG_CLIENT == true)
+#if (CFE_PLATFORM_TIME_CFG_VIRTUAL != true)
+#error Cannot define CFE_PLATFORM_TIME_CFG_CLIENT as true without defining CFE_PLATFORM_TIME_CFG_VIRTUAL as true!
+#endif
+#endif
+
+/*
+** Validate time source type selection...
+*/
+#if (CFE_PLATFORM_TIME_CFG_SRC_MET == true)
+#if (CFE_PLATFORM_TIME_CFG_SOURCE != true)
+#error Cannot define CFE_PLATFORM_TIME_CFG_SRC_MET as true without defining CFE_PLATFORM_TIME_CFG_SOURCE as true!
+#endif
+#if (CFE_PLATFORM_TIME_CFG_SRC_GPS == true)
+#error Cannot define both CFE_PLATFORM_TIME_CFG_SRC_MET and CFE_PLATFORM_TIME_CFG_SRC_GPS as true!
+#endif
+#if (CFE_PLATFORM_TIME_CFG_SRC_TIME == true)
+#error Cannot define both CFE_PLATFORM_TIME_CFG_SRC_MET and CFE_PLATFORM_TIME_CFG_SRC_TIME as true!
+#endif
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SRC_GPS == true)
+#if (CFE_PLATFORM_TIME_CFG_SOURCE != true)
+#error Cannot define CFE_PLATFORM_TIME_CFG_SRC_GPS as true without defining CFE_PLATFORM_TIME_CFG_SOURCE as true!
+#endif
+#if (CFE_PLATFORM_TIME_CFG_SRC_TIME == true)
+#error Cannot define both CFE_PLATFORM_TIME_CFG_SRC_GPS and CFE_PLATFORM_TIME_CFG_SRC_TIME as true!
+#endif
+#endif
+
+#if (CFE_PLATFORM_TIME_CFG_SRC_TIME == true)
+#if (CFE_PLATFORM_TIME_CFG_SOURCE != true)
+#error Cannot define CFE_PLATFORM_TIME_CFG_SRC_TIME as true without defining CFE_PLATFORM_TIME_CFG_SOURCE as true!
+#endif
+#endif
+
+/*
+** Validate tone signal and data packet arrival selection...
+*/
+#if (CFE_MISSION_TIME_AT_TONE_WAS == true)
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+#error Both CFE_MISSION_TIME_AT_TONE_WAS and CFE_MISSION_TIME_AT_TONE_WILL_BE have been defined as true!
+#endif
+#else
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE != true)
+#error Either CFE_MISSION_TIME_AT_TONE_WAS or CFE_MISSION_TIME_AT_TONE_WILL_BE must be defined as true!
+#endif
+#endif
+
+/*
+** Validate simulated tone signal and external time source selection...
+*/
+#if (CFE_MISSION_TIME_CFG_FAKE_TONE == true)
+#if (CFE_PLATFORM_TIME_CFG_SOURCE == true)
+#error Cannot define both CFE_MISSION_TIME_CFG_FAKE_TONE and CFE_PLATFORM_TIME_CFG_SOURCE as true!
+#endif
+#endif
+
+/*
+** Validate simulated tone signal and data packet arrival selection...
+*/
+#if (CFE_MISSION_TIME_CFG_FAKE_TONE == true)
+#if (CFE_MISSION_TIME_AT_TONE_WILL_BE == true)
+#error Cannot define both CFE_MISSION_TIME_CFG_FAKE_TONE and CFE_MISSION_TIME_AT_TONE_WILL_BE as true!
+#endif
+#endif
+
+/*
+** Validate task priorities...
+*/
+#if CFE_PLATFORM_TIME_START_TASK_PRIORITY < 0
+#error CFE_PLATFORM_TIME_START_TASK_PRIORITY must be greater than or equal to zero
+#elif CFE_PLATFORM_TIME_START_TASK_PRIORITY > 255
+#error CFE_PLATFORM_TIME_START_TASK_PRIORITY must be less than or equal to 255
+#endif
+#if CFE_PLATFORM_TIME_TONE_TASK_PRIORITY < 0
+#error CFE_PLATFORM_TIME_TONE_TASK_PRIORITY must be greater than or equal to zero
+#elif CFE_PLATFORM_TIME_TONE_TASK_PRIORITY > 255
+#error CFE_PLATFORM_TIME_TONE_TASK_PRIORITY must be less than or equal to 255
+#endif
+#if CFE_PLATFORM_TIME_1HZ_TASK_PRIORITY < 0
+#error CFE_PLATFORM_TIME_1HZ_TASK_PRIORITY must be greater than or equal to zero
+#elif CFE_PLATFORM_TIME_1HZ_TASK_PRIORITY > 255
+#error CFE_PLATFORM_TIME_1HZ_TASK_PRIORITY must be less than or equal to 255
+#endif
+
+/*
+** Validate task stack sizes...
+*/
+#if CFE_PLATFORM_TIME_START_TASK_STACK_SIZE < 2048
+#error CFE_PLATFORM_TIME_START_TASK_STACK_SIZE must be greater than or equal to 2048
+#endif
+
+#if CFE_PLATFORM_TIME_TONE_TASK_STACK_SIZE < 2048
+#error CFE_PLATFORM_TIME_TONE_TASK_STACK_SIZE must be greater than or equal to 2048
+#endif
+
+#if CFE_PLATFORM_TIME_1HZ_TASK_STACK_SIZE < 2048
+#error CFE_PLATFORM_TIME_1HZ_TASK_STACK_SIZE must be greater than or equal to 2048
+#endif
+
+/*************************************************************************/
+
+#endif /* CFE_TIME_VERIFY_H */