| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title TimeConverter.cpp | ||
| 3 | // \author devin | ||
| 4 | // \brief cpp file for TimeConverter component implementation class | ||
| 5 | // ====================================================================== | ||
| 6 | |||
| 7 | #include "Svc/TimeConverter/TimeConverter.hpp" | ||
| 8 | |||
| 9 | namespace Svc { | ||
| 10 | |||
| 11 | constexpr I64 TimeConverter::US_PER_SECOND; | ||
| 12 | constexpr I64 TimeConverter::MAX_TIME_US; | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | //! Numeric value of a time base, used to order a pair canonically | ||
| 16 | 516 | FwTimeBaseStoreType timeBaseValue(const TimeBase& timeBase) { | |
| 17 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 516 times.
|
516 | return static_cast<FwTimeBaseStoreType>(timeBase.e); |
| 18 | } | ||
| 19 | |||
| 20 | //! A time base denotes a clock, rather than the absence of one or a wildcard | ||
| 21 | 238 | bool usableTimeBase(const TimeBase& timeBase) { | |
| 22 |
6/8✗ Branch 3 not taken.
✓ Branch 4 taken 238 times.
✓ Branch 5 taken 227 times.
✓ Branch 6 taken 11 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 227 times.
✓ Branch 12 taken 224 times.
✓ Branch 13 taken 3 times.
|
238 | return (timeBase.e != TimeBase::TB_NONE) && (timeBase.e != TimeBase::TB_DONT_CARE); |
| 23 | } | ||
| 24 | |||
| 25 | //! A pair of time bases in canonical order, lesser numeric value first | ||
| 26 | 83 | Svc::TimeBasePair canonicalPair(const TimeBase& from, const TimeBase& to) { | |
| 27 | 83 | const bool ascending = timeBaseValue(from) < timeBaseValue(to); | |
| 28 |
16/16✓ Branch 0 taken 36 times.
✓ Branch 1 taken 47 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 47 times.
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 47 times.
✓ Branch 9 taken 36 times.
✓ Branch 10 taken 47 times.
✓ Branch 12 taken 36 times.
✓ Branch 13 taken 47 times.
✓ Branch 15 taken 36 times.
✓ Branch 16 taken 47 times.
✓ Branch 17 taken 36 times.
✓ Branch 18 taken 47 times.
✓ Branch 21 taken 36 times.
✓ Branch 22 taken 47 times.
|
83 | return Svc::TimeBasePair(ascending ? from : to, ascending ? to : from); |
| 29 | } | ||
| 30 | } // namespace | ||
| 31 | |||
| 32 | // ---------------------------------------------------------------------- | ||
| 33 | // Component construction and destruction | ||
| 34 | // ---------------------------------------------------------------------- | ||
| 35 | |||
| 36 |
1/1✓ Branch 10 taken 20 times.
|
20 | TimeConverter ::TimeConverter(const char* const compName) : TimeConverterComponentBase(compName) {} |
| 37 | |||
| 38 | 40 | TimeConverter ::~TimeConverter() {} | |
| 39 | |||
| 40 | // ---------------------------------------------------------------------- | ||
| 41 | // Handler implementations for user-defined typed input ports | ||
| 42 | // ---------------------------------------------------------------------- | ||
| 43 | |||
| 44 | 6 | 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 |
3/3✓ Branch 13 taken 6 times.
✓ Branch 22 taken 6 times.
✓ Branch 26 taken 6 times.
|
6 | (void)this->storeOffset(offset.get_from(), offset.get_to(), offset.get_offset_us()); |
| 47 | 6 | } | |
| 48 | |||
| 49 | 32 | Svc::ConvertTimeStatus TimeConverter ::convertTime_handler(FwIndexType portNum, | |
| 50 | const Fw::Time& in_time, | ||
| 51 | Fw::Time& out_time) { | ||
| 52 |
1/1✓ Branch 2 taken 32 times.
|
32 | const TimeBase in_tb = in_time.getTimeBase(); |
| 53 |
1/1✓ Branch 2 taken 32 times.
|
32 | const TimeBase out_tb = out_time.getTimeBase(); |
| 54 | |||
| 55 |
3/3✓ Branch 2 taken 32 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 31 times.
|
32 | if (this->checkTimeBases(in_tb, out_tb) != Fw::Success::SUCCESS) { |
| 56 |
1/1✓ Branch 1 taken 1 times.
|
1 | return Svc::ConvertTimeStatus::UNKNOWN_TIMEBASE; |
| 57 | } | ||
| 58 | |||
| 59 | // A time is already in the requested base: no offset is needed | ||
| 60 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 30 times.
|
31 | if (timeBaseValue(in_tb) == timeBaseValue(out_tb)) { |
| 61 |
1/1✓ Branch 4 taken 1 times.
|
1 | out_time = in_time; |
| 62 |
1/1✓ Branch 1 taken 1 times.
|
1 | return Svc::ConvertTimeStatus::OK; |
| 63 | } | ||
| 64 | |||
| 65 | 30 | I64 offset_us = 0; | |
| 66 |
3/3✓ Branch 2 taken 30 times.
✓ Branch 11 taken 12 times.
✓ Branch 12 taken 18 times.
|
30 | if (this->lookupOffset(in_tb, out_tb, offset_us) != Fw::Success::SUCCESS) { |
| 67 |
1/1✓ Branch 5 taken 12 times.
|
12 | this->log_WARNING_LO_NoConversionAvailable(in_tb, out_tb); |
| 68 |
1/1✓ Branch 1 taken 12 times.
|
12 | return Svc::ConvertTimeStatus::UNKNOWN_TIMEBASE; |
| 69 | } | ||
| 70 | |||
| 71 | // Offsets are range-checked when stored, so this addition cannot overflow | ||
| 72 |
2/2✓ Branch 4 taken 18 times.
✓ Branch 10 taken 18 times.
|
18 | const I64 in_time_us = static_cast<I64>(in_time.getSeconds()) * US_PER_SECOND + in_time.getUSeconds(); |
| 73 | 18 | const I64 out_time_us = in_time_us + offset_us; | |
| 74 |
4/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 8 times.
|
18 | if ((out_time_us < 0) || (out_time_us > MAX_TIME_US)) { |
| 75 |
1/1✓ Branch 5 taken 10 times.
|
10 | this->log_WARNING_LO_InvalidTime(in_tb, out_tb, offset_us, in_time_us); |
| 76 |
1/1✓ Branch 1 taken 10 times.
|
10 | return Svc::ConvertTimeStatus::INVALID_TIME; |
| 77 | } | ||
| 78 | |||
| 79 |
3/3✓ Branch 6 taken 8 times.
✓ Branch 10 taken 8 times.
✓ Branch 13 taken 8 times.
|
16 | out_time.set(out_tb, in_time.getContext(), static_cast<U32>(out_time_us / US_PER_SECOND), |
| 80 | 8 | static_cast<U32>(out_time_us % US_PER_SECOND)); | |
| 81 |
1/1✓ Branch 1 taken 8 times.
|
8 | return Svc::ConvertTimeStatus::OK; |
| 82 | 32 | } | |
| 83 | |||
| 84 | // ---------------------------------------------------------------------- | ||
| 85 | // Handler implementations for commands | ||
| 86 | // ---------------------------------------------------------------------- | ||
| 87 | |||
| 88 | 66 | void TimeConverter ::SET_OFFSET_cmdHandler(FwOpcodeType opCode, | |
| 89 | U32 cmdSeq, | ||
| 90 | const TimeBase& from, | ||
| 91 | const TimeBase& to, | ||
| 92 | I64 offset_us) { | ||
| 93 |
1/1✓ Branch 2 taken 66 times.
|
66 | Fw::CmdResponse response = Fw::CmdResponse::OK; |
| 94 |
4/5✓ Branch 4 taken 66 times.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 29 times.
✗ Branch 9 not taken.
|
66 | switch (this->storeOffset(from, to, offset_us)) { |
| 95 | 28 | case StoreStatus::OK: | |
| 96 |
1/1✓ Branch 5 taken 28 times.
|
28 | this->log_ACTIVITY_HI_OffsetSet(from, to, offset_us); |
| 97 | 28 | break; | |
| 98 | // A full table is a state the operator clears, not a bad argument | ||
| 99 | 9 | case StoreStatus::TABLE_FULL: | |
| 100 |
1/1✓ Branch 2 taken 9 times.
|
9 | response = Fw::CmdResponse::EXECUTION_ERROR; |
| 101 | 9 | break; | |
| 102 | 29 | case StoreStatus::INVALID: | |
| 103 |
1/1✓ Branch 2 taken 29 times.
|
29 | response = Fw::CmdResponse::VALIDATION_ERROR; |
| 104 | 29 | break; | |
| 105 | } | ||
| 106 |
2/2✓ Branch 6 taken 66 times.
✓ Branch 9 taken 66 times.
|
66 | this->cmdResponse_out(opCode, cmdSeq, response); |
| 107 | 132 | } | |
| 108 | |||
| 109 | 8 | void TimeConverter ::CLEAR_OFFSETS_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 110 | 8 | const FwSizeType cleared = this->m_offsets.getSize(); | |
| 111 | 8 | this->m_offsets.clear(); | |
| 112 | // Clearing the table is the operator's recovery action, so re-arm the throttled warnings | ||
| 113 | 8 | this->log_WARNING_LO_NoConversionAvailable_ThrottleClear(); | |
| 114 | 8 | this->log_WARNING_LO_InvalidTime_ThrottleClear(); | |
| 115 | 8 | this->log_WARNING_LO_IdenticalTimeBases_ThrottleClear(); | |
| 116 | 8 | this->log_WARNING_HI_OffsetOutOfRange_ThrottleClear(); | |
| 117 | 8 | this->log_WARNING_HI_OffsetTableFull_ThrottleClear(); | |
| 118 | 8 | this->log_WARNING_HI_UnusableTimeBase_ThrottleClear(); | |
| 119 | 8 | this->log_ACTIVITY_HI_OffsetsCleared(static_cast<U32>(cleared)); | |
| 120 |
2/2✓ Branch 6 taken 8 times.
✓ Branch 9 taken 8 times.
|
8 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 121 | 8 | } | |
| 122 | |||
| 123 | 15 | void TimeConverter ::GET_OFFSET_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const TimeBase& from, const TimeBase& to) { | |
| 124 |
3/3✓ Branch 2 taken 15 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 14 times.
|
15 | if (this->checkTimeBases(from, to) != Fw::Success::SUCCESS) { |
| 125 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); |
| 126 | 1 | return; | |
| 127 | } | ||
| 128 | |||
| 129 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 13 times.
|
14 | if (timeBaseValue(from) == timeBaseValue(to)) { |
| 130 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_LO_IdenticalTimeBases(from); |
| 131 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); |
| 132 | 1 | return; | |
| 133 | } | ||
| 134 | |||
| 135 | 13 | I64 offset_us = 0; | |
| 136 |
3/3✓ Branch 2 taken 13 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 11 times.
|
13 | if (this->lookupOffset(from, to, offset_us) != Fw::Success::SUCCESS) { |
| 137 |
1/1✓ Branch 5 taken 2 times.
|
2 | this->log_WARNING_LO_NoOffsetStored(from, to); |
| 138 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); |
| 139 | 2 | return; | |
| 140 | } | ||
| 141 | |||
| 142 |
1/1✓ Branch 5 taken 11 times.
|
11 | this->log_ACTIVITY_HI_OffsetReport(from, to, offset_us); |
| 143 |
2/2✓ Branch 6 taken 11 times.
✓ Branch 9 taken 11 times.
|
11 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 144 | } | ||
| 145 | |||
| 146 | 4 | void TimeConverter ::DUMP_OFFSETS_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 147 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 7 taken 3 times.
|
4 | if (this->m_offsets.getSize() == 0) { |
| 148 | 1 | this->log_ACTIVITY_HI_OffsetTableEmpty(); | |
| 149 | } | ||
| 150 |
6/6✓ Branch 4 taken 4 times.
✓ Branch 7 taken 5 times.
✓ Branch 13 taken 9 times.
✓ Branch 17 taken 9 times.
✓ Branch 21 taken 5 times.
✓ Branch 22 taken 4 times.
|
14 | for (auto it = this->m_offsets.begin(); it != this->m_offsets.end(); ++it) { |
| 151 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 10 taken 5 times.
|
5 | const Svc::TimeBasePair& pair = it->getKey(); |
| 152 |
5/5✓ Branch 5 taken 5 times.
✓ Branch 14 taken 5 times.
✓ Branch 23 taken 5 times.
✓ Branch 32 taken 5 times.
✓ Branch 36 taken 5 times.
|
5 | this->log_ACTIVITY_HI_OffsetReport(pair.get_lower(), pair.get_upper(), it->getValue()); |
| 153 | 4 | } | |
| 154 |
2/2✓ Branch 6 taken 4 times.
✓ Branch 9 taken 4 times.
|
4 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 155 | 4 | } | |
| 156 | |||
| 157 | // ---------------------------------------------------------------------- | ||
| 158 | // Helper functions | ||
| 159 | // ---------------------------------------------------------------------- | ||
| 160 | |||
| 161 | 43 | Fw::Success TimeConverter ::lookupOffset(const TimeBase& from, const TimeBase& to, I64& offset_us) const { | |
| 162 | 43 | I64 stored_us = 0; | |
| 163 |
2/2✓ Branch 4 taken 43 times.
✓ Branch 9 taken 43 times.
|
43 | const Fw::Success status = this->m_offsets.find(canonicalPair(from, to), stored_us); |
| 164 |
2/2✓ Branch 3 taken 29 times.
✓ Branch 4 taken 14 times.
|
43 | if (status == Fw::Success::SUCCESS) { |
| 165 | // Offsets are stored in canonical order; the reverse conversion negates them | ||
| 166 |
2/2✓ Branch 2 taken 20 times.
✓ Branch 3 taken 9 times.
|
29 | offset_us = (timeBaseValue(from) < timeBaseValue(to)) ? stored_us : -stored_us; |
| 167 | } | ||
| 168 | 86 | return status; | |
| 169 | } | ||
| 170 | |||
| 171 | 72 | TimeConverter::StoreStatus TimeConverter ::storeOffset(const TimeBase& from, const TimeBase& to, I64 offset_us) { | |
| 172 |
3/3✓ Branch 2 taken 72 times.
✓ Branch 11 taken 11 times.
✓ Branch 12 taken 61 times.
|
72 | if (this->checkTimeBases(from, to) != Fw::Success::SUCCESS) { |
| 173 | 11 | return StoreStatus::INVALID; | |
| 174 | } | ||
| 175 |
2/2✓ Branch 2 taken 10 times.
✓ Branch 3 taken 51 times.
|
61 | if (timeBaseValue(from) == timeBaseValue(to)) { |
| 176 |
1/1✓ Branch 5 taken 10 times.
|
10 | this->log_WARNING_LO_IdenticalTimeBases(from); |
| 177 | 10 | return StoreStatus::INVALID; | |
| 178 | } | ||
| 179 | // Bound stored offsets so that applying or negating one cannot overflow | ||
| 180 |
4/4✓ Branch 0 taken 41 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 40 times.
|
51 | if ((offset_us > MAX_TIME_US) || (offset_us < -MAX_TIME_US)) { |
| 181 |
1/1✓ Branch 5 taken 11 times.
|
11 | this->log_WARNING_HI_OffsetOutOfRange(from, to, offset_us); |
| 182 | 11 | return StoreStatus::INVALID; | |
| 183 | } | ||
| 184 | |||
| 185 | 40 | const bool ascending = timeBaseValue(from) < timeBaseValue(to); | |
| 186 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 14 times.
|
40 | 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 |
4/4✓ Branch 5 taken 40 times.
✓ Branch 9 taken 40 times.
✓ Branch 21 taken 10 times.
✓ Branch 22 taken 30 times.
|
40 | if (this->m_offsets.insert(canonicalPair(from, to), stored_us) != Fw::Success::SUCCESS) { |
| 190 |
1/1✓ Branch 5 taken 10 times.
|
10 | this->log_WARNING_HI_OffsetTableFull(from, to, static_cast<U32>(Svc::TimeConverterCfg::MAX_OFFSET_ENTRIES)); |
| 191 | 10 | return StoreStatus::TABLE_FULL; | |
| 192 | } | ||
| 193 | 30 | return StoreStatus::OK; | |
| 194 | } | ||
| 195 | |||
| 196 | 119 | 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 | ||
| 198 | 119 | Fw::Success status = Fw::Success::SUCCESS; | |
| 199 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 107 times.
|
119 | if (!usableTimeBase(from)) { |
| 200 |
1/1✓ Branch 5 taken 12 times.
|
12 | this->log_WARNING_HI_UnusableTimeBase(from); |
| 201 |
1/1✓ Branch 3 taken 12 times.
|
12 | status = Fw::Success::FAILURE; |
| 202 | } | ||
| 203 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 117 times.
|
119 | if (!usableTimeBase(to)) { |
| 204 |
1/1✓ Branch 5 taken 2 times.
|
2 | this->log_WARNING_HI_UnusableTimeBase(to); |
| 205 |
1/1✓ Branch 3 taken 2 times.
|
2 | status = Fw::Success::FAILURE; |
| 206 | } | ||
| 207 | 119 | return status; | |
| 208 | ✗ | } | |
| 209 | |||
| 210 | } // namespace Svc | ||
| 211 |