F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
TimeConverter.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title TimeConverter.cpp
3 // \author devin
4 // \brief cpp file for TimeConverter component implementation class
5 // ======================================================================
6 
8 
9 namespace Svc {
10 
11 constexpr I64 TimeConverter::US_PER_SECOND;
12 constexpr I64 TimeConverter::MAX_TIME_US;
13 
14 namespace {
16 FwTimeBaseStoreType timeBaseValue(const TimeBase& timeBase) {
17  return static_cast<FwTimeBaseStoreType>(timeBase.e);
18 }
19 
21 bool usableTimeBase(const TimeBase& timeBase) {
22  return (timeBase.e != TimeBase::TB_NONE) && (timeBase.e != TimeBase::TB_DONT_CARE);
23 }
24 
26 Svc::TimeBasePair canonicalPair(const TimeBase& from, const TimeBase& to) {
27  const bool ascending = timeBaseValue(from) < timeBaseValue(to);
28  return Svc::TimeBasePair(ascending ? from : to, ascending ? to : from);
29 }
30 } // namespace
31 
32 // ----------------------------------------------------------------------
33 // Component construction and destruction
34 // ----------------------------------------------------------------------
35 
36 TimeConverter ::TimeConverter(const char* const compName) : TimeConverterComponentBase(compName) {}
37 
39 
40 // ----------------------------------------------------------------------
41 // Handler implementations for user-defined typed input ports
42 // ----------------------------------------------------------------------
43 
44 void TimeConverter ::offsetUpdate_handler(FwIndexType portNum, const Svc::TimeOffset& offset) {
45  // storeOffset reports every failure by event, and the port carries no status back
46  (void)this->storeOffset(offset.get_from(), offset.get_to(), offset.get_offset_us());
47 }
48 
49 Svc::ConvertTimeStatus TimeConverter ::convertTime_handler(FwIndexType portNum,
50  const Fw::Time& in_time,
51  Fw::Time& out_time) {
52  const TimeBase in_tb = in_time.getTimeBase();
53  const TimeBase out_tb = out_time.getTimeBase();
54 
55  if (this->checkTimeBases(in_tb, out_tb) != Fw::Success::SUCCESS) {
57  }
58 
59  // A time is already in the requested base: no offset is needed
60  if (timeBaseValue(in_tb) == timeBaseValue(out_tb)) {
61  out_time = in_time;
63  }
64 
65  I64 offset_us = 0;
66  if (this->lookupOffset(in_tb, out_tb, offset_us) != Fw::Success::SUCCESS) {
67  this->log_WARNING_LO_NoConversionAvailable(in_tb, out_tb);
69  }
70 
71  // Offsets are range-checked when stored, so this addition cannot overflow
72  const I64 in_time_us = static_cast<I64>(in_time.getSeconds()) * US_PER_SECOND + in_time.getUSeconds();
73  const I64 out_time_us = in_time_us + offset_us;
74  if ((out_time_us < 0) || (out_time_us > MAX_TIME_US)) {
75  this->log_WARNING_LO_InvalidTime(in_tb, out_tb, offset_us, in_time_us);
77  }
78 
79  out_time.set(out_tb, in_time.getContext(), static_cast<U32>(out_time_us / US_PER_SECOND),
80  static_cast<U32>(out_time_us % US_PER_SECOND));
82 }
83 
84 // ----------------------------------------------------------------------
85 // Handler implementations for commands
86 // ----------------------------------------------------------------------
87 
88 void TimeConverter ::SET_OFFSET_cmdHandler(FwOpcodeType opCode,
89  U32 cmdSeq,
90  const TimeBase& from,
91  const TimeBase& to,
92  I64 offset_us) {
94  switch (this->storeOffset(from, to, offset_us)) {
95  case StoreStatus::OK:
96  this->log_ACTIVITY_HI_OffsetSet(from, to, offset_us);
97  break;
98  // A full table is a state the operator clears, not a bad argument
99  case StoreStatus::TABLE_FULL:
101  break;
102  case StoreStatus::INVALID:
104  break;
105  }
106  this->cmdResponse_out(opCode, cmdSeq, response);
107 }
108 
109 void TimeConverter ::CLEAR_OFFSETS_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
110  const FwSizeType cleared = this->m_offsets.getSize();
111  this->m_offsets.clear();
112  // Clearing the table is the operator's recovery action, so re-arm the throttled warnings
119  this->log_ACTIVITY_HI_OffsetsCleared(static_cast<U32>(cleared));
120  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
121 }
122 
123 void TimeConverter ::GET_OFFSET_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const TimeBase& from, const TimeBase& to) {
124  if (this->checkTimeBases(from, to) != Fw::Success::SUCCESS) {
125  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
126  return;
127  }
128 
129  if (timeBaseValue(from) == timeBaseValue(to)) {
131  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
132  return;
133  }
134 
135  I64 offset_us = 0;
136  if (this->lookupOffset(from, to, offset_us) != Fw::Success::SUCCESS) {
137  this->log_WARNING_LO_NoOffsetStored(from, to);
138  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
139  return;
140  }
141 
142  this->log_ACTIVITY_HI_OffsetReport(from, to, offset_us);
143  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
144 }
145 
146 void TimeConverter ::DUMP_OFFSETS_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
147  if (this->m_offsets.getSize() == 0) {
149  }
150  for (auto it = this->m_offsets.begin(); it != this->m_offsets.end(); ++it) {
151  const Svc::TimeBasePair& pair = it->getKey();
152  this->log_ACTIVITY_HI_OffsetReport(pair.get_lower(), pair.get_upper(), it->getValue());
153  }
154  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
155 }
156 
157 // ----------------------------------------------------------------------
158 // Helper functions
159 // ----------------------------------------------------------------------
160 
161 Fw::Success TimeConverter ::lookupOffset(const TimeBase& from, const TimeBase& to, I64& offset_us) const {
162  I64 stored_us = 0;
163  const Fw::Success status = this->m_offsets.find(canonicalPair(from, to), stored_us);
164  if (status == Fw::Success::SUCCESS) {
165  // Offsets are stored in canonical order; the reverse conversion negates them
166  offset_us = (timeBaseValue(from) < timeBaseValue(to)) ? stored_us : -stored_us;
167  }
168  return status;
169 }
170 
171 TimeConverter::StoreStatus TimeConverter ::storeOffset(const TimeBase& from, const TimeBase& to, I64 offset_us) {
172  if (this->checkTimeBases(from, to) != Fw::Success::SUCCESS) {
173  return StoreStatus::INVALID;
174  }
175  if (timeBaseValue(from) == timeBaseValue(to)) {
177  return StoreStatus::INVALID;
178  }
179  // Bound stored offsets so that applying or negating one cannot overflow
180  if ((offset_us > MAX_TIME_US) || (offset_us < -MAX_TIME_US)) {
181  this->log_WARNING_HI_OffsetOutOfRange(from, to, offset_us);
182  return StoreStatus::INVALID;
183  }
184 
185  const bool ascending = timeBaseValue(from) < timeBaseValue(to);
186  const I64 stored_us = ascending ? offset_us : -offset_us;
187 
188  // An insert replaces the entry for a pair already stored, and fails only when the table is full
189  if (this->m_offsets.insert(canonicalPair(from, to), stored_us) != Fw::Success::SUCCESS) {
191  return StoreStatus::TABLE_FULL;
192  }
193  return StoreStatus::OK;
194 }
195 
196 Fw::Success TimeConverter ::checkTimeBases(const TimeBase& from, const TimeBase& to) {
197  // TB_NONE and TB_DONT_CARE name no clock, so no offset relates them to one
199  if (!usableTimeBase(from)) {
201  status = Fw::Success::FAILURE;
202  }
203  if (!usableTimeBase(to)) {
205  status = Fw::Success::FAILURE;
206  }
207  return status;
208 }
209 
210 } // namespace Svc
TimeBase::T get_lower() const
Get member lower.
void log_WARNING_LO_InvalidTime_ThrottleClear()
Reset throttle value for InvalidTime.
void log_WARNING_LO_InvalidTime(const TimeBase &in_tb, const TimeBase &out_tb, I64 offset_us, I64 in_time_us)
ConstIterator end() const override
Definition: ArrayMap.hpp:77
conversion result is not representable as an Fw::Time
void log_ACTIVITY_HI_OffsetReport(const TimeBase &from, const TimeBase &to, I64 offset_us) const
FwIdType FwOpcodeType
The type of a command opcode.
TimeBase::T get_to() const
Get member to.
Representing success.
PlatformSizeType FwSizeType
void log_WARNING_LO_IdenticalTimeBases_ThrottleClear()
Reset throttle value for IdenticalTimeBases.
TimeConverter(const char *const compName)
Construct TimeConverter object.
Don&#39;t care value for sequences. If FwTimeBaseStoreType is changed, value should be changed (Required)...
Auto-generated base for TimeConverter component.
TimeBase getTimeBase() const
Definition: Time.cpp:136
void log_WARNING_HI_OffsetTableFull(const TimeBase &from, const TimeBase &to, U32 capacity)
I64 get_offset_us() const
Get member offset_us.
Enum representing a command response.
No time base has been established (Required)
void log_WARNING_HI_OffsetTableFull_ThrottleClear()
Reset throttle value for OffsetTableFull.
TimeBase::T get_upper() const
Get member upper.
void log_WARNING_LO_NoConversionAvailable(const TimeBase &in_tb, const TimeBase &out_tb)
Success insert(const K &key, const V &value) override
Definition: ArrayMap.hpp:97
void log_WARNING_HI_UnusableTimeBase_ThrottleClear()
Reset throttle value for UnusableTimeBase.
void set(U32 seconds, U32 useconds)
Definition: Time.cpp:24
void clear() override
Clear the map.
Definition: ArrayMap.hpp:73
~TimeConverter()
Destroy TimeConverter object.
void log_WARNING_HI_UnusableTimeBase(const TimeBase &tb)
U32 getSeconds() const
Definition: Time.cpp:128
ConstIterator begin() const override
Definition: ArrayMap.hpp:70
void log_WARNING_HI_OffsetOutOfRange(const TimeBase &from, const TimeBase &to, I64 offset_us)
TimeBase::T get_from() const
Get member from.
Representing failure.
Result of a time base conversion.
Command successfully executed.
void log_ACTIVITY_HI_OffsetsCleared(U32 entries) const
static constexpr I64 US_PER_SECOND
Microseconds in one second.
void log_ACTIVITY_HI_OffsetSet(const TimeBase &from, const TimeBase &to, I64 offset_us) const
Command had execution error.
void log_WARNING_LO_NoConversionAvailable_ThrottleClear()
Reset throttle value for NoConversionAvailable.
FwTimeContextStoreType getContext() const
Definition: Time.cpp:140
U32 getUSeconds() const
Definition: Time.cpp:132
no offset is stored for the requested pair of time bases
Success find(const K &key, V &value) const override
Definition: ArrayMap.hpp:81
PlatformIndexType FwIndexType
Command failed validation.
RateGroupDivider component implementation.
void log_WARNING_LO_IdenticalTimeBases(const TimeBase &tb)
U16 FwTimeBaseStoreType
The type used to serialize a time base value.
enum T e
The raw enum value.
void log_WARNING_HI_OffsetOutOfRange_ThrottleClear()
Reset throttle value for OffsetOutOfRange.
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
FwSizeType getSize() const override
Definition: ArrayMap.hpp:93
Define enumeration for Time base types.
Success/Failure.
static constexpr I64 MAX_TIME_US
Largest time representable by an Fw::Time, in microseconds.
void log_WARNING_LO_NoOffsetStored(const TimeBase &from, const TimeBase &to) const