GCC Code Coverage Report


Directory: ./
File: Svc/TlmPacketizer/TlmPacketizer.cpp
Date: 2026-09-23 21:11:01
Exec Total Coverage
Lines: 276 299 92.3%
Functions: 20 20 100.0%
Branches: 239 305 78.4%

Line Branch Exec Source
1 // ======================================================================
2 // \title TlmPacketizerImpl.cpp
3 // \author tcanham
4 // \brief cpp file for TlmPacketizer component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2015, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10
11 #include <Fw/Com/ComPacket.hpp>
12 #include <Fw/FPrimeBasicTypes.hpp>
13 #include <Fw/Prm/ParamValid.hpp>
14 #include <Svc/TlmPacketizer/TlmPacketizer.hpp>
15 #include <TlmPacketizerConfig/FppConstantsAc.hpp>
16 #include <cstring>
17
18 namespace Svc {
19
20 const TlmPacketizer_TelemetrySendPortMap TlmPacketizer::TELEMETRY_SEND_PORT_MAP = {};
21
22 static_assert(Svc::TelemetrySection::NUM_SECTIONS >= 1, "At least one telemetry section is required");
23
24 // ----------------------------------------------------------------------
25 // Construction, initialization, and destruction
26 // ----------------------------------------------------------------------
27
28 19 TlmPacketizer ::TlmPacketizer(const char* const compName)
29
11/17
✓ Branch 20 taken 950 times.
✓ Branch 23 taken 950 times.
✓ Branch 24 taken 19 times.
✓ Branch 30 taken 19 times.
✓ Branch 41 taken 19 times.
✓ Branch 48 taken 19 times.
✓ Branch 56 taken 1862 times.
✓ Branch 57 taken 38 times.
✓ Branch 58 taken 19 times.
✓ Branch 59 taken 19 times.
✓ Branch 68 taken 19 times.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
2850 : TlmPacketizerComponentBase(compName), m_numPackets(0), m_configured(false), m_numChannels(0) {
30 // Register self as parameter delegate
31
1/1
✓ Branch 7 taken 19 times.
19 this->registerExternalParameters(this);
32 // clear missing tlm channel check
33
2/2
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 19 times.
494 for (FwChanIdType entry = 0; entry < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; entry++) {
34 475 this->m_missTlmCheck[entry].checked = false;
35 475 this->m_missTlmCheck[entry].id = 0;
36 }
37
38 // clear packet buffers
39
2/2
✓ Branch 0 taken 950 times.
✓ Branch 1 taken 19 times.
969 for (FwChanIdType buffer = 0; buffer < MAX_PACKETIZER_PACKETS; buffer++) {
40 950 this->m_fillBuffers[buffer].updated = false;
41 }
42
43 static_assert(NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS == MAX_CONFIGURABLE_TLMPACKETIZER_GROUP + 1,
44 "NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS MUST BE MAX_CONFIGURABLE_TLMPACKETIZER_GROUP + 1");
45 19 }
46
47
3/4
✓ Branch 31 taken 19 times.
✗ Branch 32 not taken.
✓ Branch 38 taken 950 times.
✓ Branch 39 taken 19 times.
1938 TlmPacketizer ::~TlmPacketizer() {}
48
49 14 void TlmPacketizer::setPacketList(const TlmPacketizerPacketList& packetList,
50 const Svc::TlmPacketizerPacket& ignoreList,
51 const FwChanIdType startLevel) {
52 // Ignore list may be nullptr as long as numEntries is 0. Providing an ignore list with numEntries 0 disables
53 // functionality for two reasons:
54 // 1. There are no ignored channels as configured by FPP.
55 // 2. Ignore functionality is intentionally disabled by project where nullptr was intentionally supplied.
56 14 FW_ASSERT(ignoreList.list || ignoreList.numEntries == 0);
57 14 FW_ASSERT(packetList.numEntries <= MAX_PACKETIZER_PACKETS, static_cast<FwAssertArgType>(packetList.numEntries));
58
59 // Reset key data members incase of reentrant calls
60 14 this->m_numChannels = 0;
61 14 this->m_channelIndices.clear();
62 14 this->m_configured = false;
63
64 // validate packet sizes against maximum com buffer size and populate hash
65 // table
66 14 FwChanIdType maxLevel = 0;
67
2/2
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 14 times.
46 for (FwChanIdType pktEntry = 0; pktEntry < packetList.numEntries; pktEntry++) {
68 // Initial size is packetized telemetry descriptor + size of time tag + sizeof packet ID
69 32 FwSizeType packetLen =
70 sizeof(FwPacketDescriptorType) + Fw::Time::SERIALIZED_SIZE + sizeof(FwTlmPacketizeIdType);
71 // A packet with no channels is autocoded with a nullptr list and is permitted
72 32 FW_ASSERT(packetList.list[pktEntry]->list != nullptr || packetList.list[pktEntry]->numEntries == 0,
73 static_cast<FwAssertArgType>(pktEntry));
74 // add up entries for each defined packet
75
2/2
✓ Branch 5 taken 97 times.
✓ Branch 6 taken 32 times.
129 for (FwChanIdType tlmEntry = 0; tlmEntry < packetList.list[pktEntry]->numEntries; tlmEntry++) {
76 97 FwChanIdType id = packetList.list[pktEntry]->list[tlmEntry].id;
77 97 const FwSizeType channelSize = packetList.list[pktEntry]->list[tlmEntry].size;
78 97 FwSizeType entryIndex = 0;
79
3/3
✓ Branch 4 taken 97 times.
✓ Branch 13 taken 82 times.
✓ Branch 14 taken 15 times.
97 if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
80 // New channel - allocate a slot and initialize offsets to -1 (not in any packet)
81 82 entryIndex = this->m_numChannels++;
82
1/1
✓ Branch 4 taken 82 times.
82 this->m_channels[entryIndex].id = id;
83
1/1
✓ Branch 4 taken 82 times.
82 this->m_channels[entryIndex].hasValue = false;
84
1/1
✓ Branch 4 taken 82 times.
82 this->m_channels[entryIndex].channelSize = channelSize;
85
2/2
✓ Branch 0 taken 4100 times.
✓ Branch 1 taken 82 times.
4182 for (FwChanIdType pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
86
1/1
✓ Branch 4 taken 4100 times.
4100 this->m_channels[entryIndex].packetOffset[pktOffsetEntry] = -1;
87 }
88
1/1
✓ Branch 4 taken 82 times.
82 const Fw::Success insertStatus = this->m_channelIndices.insert(id, entryIndex);
89 82 FW_ASSERT(insertStatus == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(insertStatus));
90 82 } else {
91 // Existing channel - a channel ID may repeat across packets, but its definition (size) must match.
92 // A conflicting size would corrupt the packet offsets computed from the earlier definition and
93 // overflow the fill buffer during TlmRecv/TlmGet copies, so reject the misconfiguration here.
94 15 FW_ASSERT(this->m_channels[entryIndex].channelSize == channelSize, static_cast<FwAssertArgType>(id),
95 static_cast<FwAssertArgType>(channelSize),
96 static_cast<FwAssertArgType>(this->m_channels[entryIndex].channelSize));
97 }
98 // not ignored channel - update entry in place via reference
99
1/1
✓ Branch 4 taken 97 times.
97 TlmEntry& entry = this->m_channels[entryIndex];
100 97 entry.ignored = false;
101 97 entry.channelSize = channelSize;
102 // the offset into the buffer will be the current packet length
103 // the offset must fit within FwSignedSizeType to allow for negative values
104 97 FW_ASSERT(packetLen <= static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max()),
105 static_cast<FwAssertArgType>(packetLen));
106 97 entry.packetOffset[pktEntry] = static_cast<FwSignedSizeType>(packetLen);
107
108 97 packetLen += entry.channelSize;
109
110 } // end channel in packet
111 32 FW_ASSERT(packetLen <= FW_COM_BUFFER_MAX_SIZE, static_cast<FwAssertArgType>(packetLen),
112 static_cast<FwAssertArgType>(pktEntry));
113 // clear contents
114
1/2
✗ Branch 7 not taken.
✓ Branch 8 taken 32 times.
32 (void)memset(this->m_fillBuffers[pktEntry].buffer.getBuffAddr(), 0, static_cast<size_t>(packetLen));
115 // serialize packet descriptor and packet ID now since it will always be the same
116 32 Fw::SerializeStatus stat = this->m_fillBuffers[pktEntry].buffer.serializeFrom(
117 static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_PACKETIZED_TLM));
118 32 FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
119 32 stat = this->m_fillBuffers[pktEntry].buffer.serializeFrom(packetList.list[pktEntry]->id);
120 32 FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
121 // set packet buffer length
122 32 stat = this->m_fillBuffers[pktEntry].buffer.setBuffLen(packetLen);
123 32 FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
124 // save ID
125 32 this->m_fillBuffers[pktEntry].id = packetList.list[pktEntry]->id;
126 // save level
127 32 this->m_fillBuffers[pktEntry].level = packetList.list[pktEntry]->level;
128 // store max level
129
2/2
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 4 times.
32 if (packetList.list[pktEntry]->level > maxLevel) {
130 28 maxLevel = packetList.list[pktEntry]->level;
131 }
132
133 } // end packet list
134 14 FW_ASSERT(maxLevel <= MAX_CONFIGURABLE_TLMPACKETIZER_GROUP, static_cast<FwAssertArgType>(maxLevel));
135
136 // This section adds entries in the map for channels that are intended to be ignored. When the user supplies
137 // a list with no length, this loop is skipped. To turn-off ignoring of channels, the user can provide a null
138 // list with 0 length.
139
2/2
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 14 times.
36 for (FwChanIdType channelEntry = 0; channelEntry < ignoreList.numEntries; channelEntry++) {
140 22 FwChanIdType id = ignoreList.list[channelEntry].id;
141 22 FwSizeType entryIndex = 0;
142
2/3
✓ Branch 4 taken 22 times.
✓ Branch 13 taken 22 times.
✗ Branch 14 not taken.
22 if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
143 // New channel - allocate a slot and initialize offsets to -1 (not in any packet)
144 22 entryIndex = this->m_numChannels++;
145
1/1
✓ Branch 4 taken 22 times.
22 this->m_channels[entryIndex].id = id;
146
1/1
✓ Branch 4 taken 22 times.
22 this->m_channels[entryIndex].hasValue = false;
147
2/2
✓ Branch 0 taken 1100 times.
✓ Branch 1 taken 22 times.
1122 for (FwChanIdType pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
148
1/1
✓ Branch 4 taken 1100 times.
1100 this->m_channels[entryIndex].packetOffset[pktOffsetEntry] = -1;
149 }
150
1/1
✓ Branch 4 taken 22 times.
22 const Fw::Success insertStatus = this->m_channelIndices.insert(id, entryIndex);
151 22 FW_ASSERT(insertStatus == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(insertStatus));
152 22 } else {
153 // Ensure it is a duplicate in the ignore list, not a duplicate of a valid channel
154 ✗ FW_ASSERT(this->m_channels[entryIndex].ignored, static_cast<FwAssertArgType>(id));
155 }
156 // is ignored channel - update entry in place via reference
157
1/1
✓ Branch 4 taken 22 times.
22 TlmEntry& entry = this->m_channels[entryIndex];
158 22 entry.ignored = true;
159 22 entry.channelSize = ignoreList.list[channelEntry].size;
160 } // end ignore list
161
162 // store number of packets
163 14 this->m_numPackets = packetList.numEntries;
164
165 // indicate configured
166 14 this->m_configured = true;
167 14 }
168
169 // ----------------------------------------------------------------------
170 // Handler implementations for user-defined typed input ports
171 // ----------------------------------------------------------------------
172
173 106 void TlmPacketizer ::TlmRecv_handler(const FwIndexType portNum,
174 FwChanIdType id,
175 Fw::Time& timeTag,
176 Fw::TlmBuffer& val) {
177 106 FW_ASSERT(this->m_configured);
178 106 FwSizeType entryIndex = 0;
179
180 // Search to see if the channel is being tracked
181
3/3
✓ Branch 4 taken 106 times.
✓ Branch 13 taken 51 times.
✓ Branch 14 taken 55 times.
106 if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
182 // channel not part of a packet and not ignored
183
1/1
✓ Branch 4 taken 51 times.
51 this->missingChannel(id);
184 51 return;
185 }
186
187
1/1
✓ Branch 4 taken 55 times.
55 TlmEntry& entry = this->m_channels[entryIndex];
188
189 // check to see if the channel is ignored. If so, just return.
190
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 54 times.
55 if (entry.ignored) {
191 1 return;
192 }
193
194 // An update larger than the configured channel size would overrun the packet
195 // fill buffer. Values may arrive from external sources (e.g. a hub bridging
196 // another address space), so reject rather than assert.
197
3/3
✓ Branch 5 taken 54 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 53 times.
54 if (val.getSize() > entry.channelSize) {
198
2/2
✓ Branch 11 taken 1 times.
✓ Branch 14 taken 1 times.
1 this->log_WARNING_HI_OversizedChannel(id, val.getSize(), entry.channelSize);
199 1 return;
200 }
201
202 // copy telemetry value into active buffers; hasValue written in-place via reference
203
2/2
✓ Branch 0 taken 2650 times.
✓ Branch 1 taken 53 times.
2703 for (FwChanIdType pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) {
204 // check if current packet has this channel
205
2/2
✓ Branch 3 taken 68 times.
✓ Branch 4 taken 2582 times.
2650 if (entry.packetOffset[pkt] != -1) {
206 // get destination address
207
1/1
✓ Branch 6 taken 68 times.
68 this->m_lock.lock();
208 68 this->m_fillBuffers[pkt].updated = true;
209
1/1
✓ Branch 8 taken 68 times.
68 this->m_fillBuffers[pkt].latestTime = timeTag;
210 68 U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entry.packetOffset[pkt]];
211
212
3/5
✓ Branch 5 taken 68 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 68 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 68 times.
68 (void)memcpy(ptr, val.getBuffAddr(), static_cast<size_t>(val.getSize()));
213 // set under the lock, after the copy, so TlmGet cannot see a value-less VALID entry
214 68 entry.hasValue = true;
215
1/1
✓ Branch 6 taken 68 times.
68 this->m_lock.unLock();
216 }
217 }
218 }
219
220 1 void TlmPacketizer ::configureSectionGroupRate_handler(FwIndexType portNum,
221 const Svc::TelemetrySection& section,
222 FwChanIdType tlmGroup,
223 const Svc::RateLogic& rateLogic,
224 U32 minDelta,
225 U32 maxDelta) {
226 1 this->configureSectionGroupRate(section, tlmGroup, rateLogic, minDelta, maxDelta);
227 1 }
228
229 //! Handler for input port TlmGet
230 4 Fw::TlmValid TlmPacketizer ::TlmGet_handler(FwIndexType portNum, //!< The port number
231 FwChanIdType id, //!< Telemetry Channel ID
232 Fw::Time& timeTag, //!< Time Tag
233 Fw::TlmBuffer& val //!< Buffer containing serialized telemetry value.
234 //!< Size set to 0 if channel not found.
235 ) {
236 4 FW_ASSERT(this->m_configured);
237 4 FwSizeType entryIndex = 0;
238
239 // Search to see if the channel is being tracked
240
3/3
✓ Branch 4 taken 4 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 3 times.
4 if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
241 // channel not part of a packet and not ignored
242
1/1
✓ Branch 4 taken 1 times.
1 this->missingChannel(id);
243
1/1
✓ Branch 5 taken 1 times.
1 val.resetSer();
244
1/1
✓ Branch 1 taken 1 times.
1 return Fw::TlmValid::INVALID;
245 }
246
1/1
✓ Branch 4 taken 3 times.
3 const TlmEntry& entry = this->m_channels[entryIndex];
247
248 // check to see if the channel is ignored. If so, just return, as
249 // we don't store the bytes of ignored channels
250
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
3 if (entry.ignored) {
251
1/1
✓ Branch 5 taken 1 times.
1 val.resetSer();
252
1/1
✓ Branch 1 taken 1 times.
1 return Fw::TlmValid::INVALID;
253 }
254
255
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
2 if (!entry.hasValue) {
256 // haven't received a value yet for this entry.
257
1/1
✓ Branch 5 taken 1 times.
1 val.resetSer();
258
1/1
✓ Branch 1 taken 1 times.
1 return Fw::TlmValid::INVALID;
259 }
260
261 // make sure we have enough space to store this entry in our buf
262 1 FW_ASSERT(entry.channelSize <= val.getCapacity(), static_cast<FwAssertArgType>(entry.channelSize),
263 static_cast<FwAssertArgType>(val.getCapacity()));
264
265 // okay, we have the matching entry.
266 // go over each packet and find the first one which stores this channel
267
268
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 for (FwChanIdType pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) {
269 // check if current packet has this channel
270
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 if (entry.packetOffset[pkt] != -1) {
271 // okay, it has the channel. copy chan val into the tlm buf
272
1/1
✓ Branch 6 taken 1 times.
1 this->m_lock.lock();
273
1/1
✓ Branch 8 taken 1 times.
1 timeTag = this->m_fillBuffers[pkt].latestTime;
274 1 U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entry.packetOffset[pkt]];
275
2/4
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
1 (void)memcpy(val.getBuffAddr(), ptr, static_cast<size_t>(entry.channelSize));
276 // set buf len to the channelSize. keep in mind, this is the MAX serialized size of the channel.
277 // so we may actually be filling val with some junk after the value of the channel.
278
1/1
✓ Branch 7 taken 1 times.
1 const Fw::SerializeStatus setStatus = val.setBuffLen(entry.channelSize);
279 1 FW_ASSERT(setStatus == Fw::SerializeStatus::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(setStatus));
280
1/1
✓ Branch 6 taken 1 times.
1 this->m_lock.unLock();
281
1/1
✓ Branch 1 taken 1 times.
1 return Fw::TlmValid::VALID;
282 }
283 }
284
285 // did not find a packet which stores this channel.
286 // coding error, this was not an ignored channel so it must be in a packet somewhere
287 ✗ FW_ASSERT(false, static_cast<FwAssertArgType>(entry.id));
288 // TPP (tim paranoia principle)
289 ✗ val.resetSer();
290 ✗ return Fw::TlmValid::INVALID;
291 }
292
293 35 void TlmPacketizer ::Run_handler(const FwIndexType portNum, U32 context) {
294 35 FW_ASSERT(this->m_configured);
295
296
2/2
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 35 times.
125 for (FwChanIdType pkt = 0; pkt < this->m_numPackets; pkt++) {
297 // Local flags to track which sections require a packet dispatch
298 90 bool sectionNeedsSend[TelemetrySection::NUM_SECTIONS] = {false};
299 90 bool anySectionNeedsSend = false;
300
301 // Lock only to capture the update status and reset the fill buffer flag.
302
1/1
✓ Branch 6 taken 90 times.
90 this->m_lock.lock();
303
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 90 times.
90 bool isNewData = this->m_fillBuffers[pkt].updated;
304 90 FwChanIdType entryGroup = this->m_fillBuffers[pkt].level;
305 90 this->m_fillBuffers[pkt].updated = false;
306
1/1
✓ Branch 6 taken 90 times.
90 this->m_lock.unLock();
307
308
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 90 times.
270 for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
309 180 PktSendCounters& pktEntryFlags = this->m_packetFlags[static_cast<FwSizeType>(section)][pkt];
310 TlmPacketizer_GroupConfig& entryGroupConfig =
311
2/2
✓ Branch 6 taken 180 times.
✓ Branch 12 taken 180 times.
180 this->m_groupConfigs[static_cast<FwSizeType>(section)][entryGroup];
312
313 // Packet is updated and not REQUESTED (Keep REQUESTED marking to bypass disable checks)
314
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 106 times.
✓ Branch 4 taken 71 times.
✓ Branch 5 taken 3 times.
180 if (isNewData && pktEntryFlags.updateFlag != UpdateFlag::REQUESTED) {
315 71 pktEntryFlags.updateFlag = UpdateFlag::NEW;
316 }
317
318 /* Base conditions for sending
319 1. Output port is connected
320 2. The packet was requested (Override Checks).
321
322 If the packet wasn't requested:
323 3. The Section and Group in Section is enabled OR the Group in Section is force enabled
324 4. The rate logic is not SILENCED.
325 5. The packet has data (marked updated in the past or new)
326 */
327
3/4
✓ Branch 5 taken 180 times.
✓ Branch 8 taken 180 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 180 times.
180 if (!this->isConnected_PktSend_OutputPort(this->sectionGroupToPort(section, entryGroup))) {
328 ✗ continue;
329 }
330
331
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 177 times.
180 if (pktEntryFlags.updateFlag == UpdateFlag::REQUESTED) {
332 3 sectionNeedsSend[section] = true;
333 } else {
334
6/6
✓ Branch 4 taken 114 times.
✓ Branch 5 taken 63 times.
✓ Branch 6 taken 63 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 63 times.
✓ Branch 9 taken 114 times.
354 if (not((entryGroupConfig.get_enabled() and
335
3/3
✓ Branch 6 taken 114 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 112 times.
114 this->m_sectionEnabled[static_cast<FwSizeType>(section)] == Fw::Enabled::ENABLED) or
336 65 entryGroupConfig.get_forceEnabled() == Fw::Enabled::ENABLED)) {
337 63 continue;
338 }
339
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 114 times.
114 if (entryGroupConfig.get_rateLogic() == Svc::RateLogic::SILENCED) {
340 ✗ continue;
341 }
342
2/2
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 104 times.
114 if (pktEntryFlags.updateFlag == UpdateFlag::NEVER_UPDATED) {
343 10 continue; // Avoid No Data
344 }
345 }
346
347 // Update Counter, prevent overflow.
348
2/2
✓ Branch 2 taken 79 times.
✓ Branch 3 taken 28 times.
107 if (pktEntryFlags.prevSentCounter < std::numeric_limits<U32>::max()) {
349 79 pktEntryFlags.prevSentCounter++;
350 }
351
352 /*
353 1. Packet has been updated
354 2. Group Logic includes checking MIN
355 3. Packet sent counter at MIN
356 */
357
1/2
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
162 if (pktEntryFlags.updateFlag == UpdateFlag::NEW and
358
5/6
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 52 times.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 55 times.
✓ Branch 9 taken 52 times.
162 entryGroupConfig.get_rateLogic() != Svc::RateLogic::EVERY_MAX and
359 55 pktEntryFlags.prevSentCounter >= entryGroupConfig.get_min()) {
360 55 sectionNeedsSend[section] = true;
361 }
362
363 /*
364 1. Group Logic includes checking MAX
365 2. Packet set counter is at MAX
366 */
367
5/6
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 103 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 103 times.
111 if (entryGroupConfig.get_rateLogic() != Svc::RateLogic::ON_CHANGE_MIN and
368 4 pktEntryFlags.prevSentCounter >= entryGroupConfig.get_max()) {
369 4 sectionNeedsSend[section] = true;
370 }
371
372
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 62 times.
✓ Branch 4 taken 45 times.
107 if (sectionNeedsSend[section]) {
373 62 anySectionNeedsSend = true;
374 }
375 }
376
377 // Only perform the buffer copy if at least one section needs to send.
378
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 57 times.
90 if (anySectionNeedsSend) {
379
1/1
✓ Branch 6 taken 33 times.
33 this->m_lock.lock();
380
1/1
✓ Branch 6 taken 33 times.
33 BufferEntry sendBuffer = this->m_fillBuffers[pkt];
381
1/1
✓ Branch 6 taken 33 times.
33 this->m_lock.unLock();
382
383 // serialize time into time offset in packet
384 33 Fw::ExternalSerializeBuffer buff(
385 33 &sendBuffer.buffer.getBuffAddr()[sizeof(FwPacketDescriptorType) + sizeof(FwTlmPacketizeIdType)],
386
1/1
✓ Branch 2 taken 33 times.
33 Fw::Time::SERIALIZED_SIZE);
387
1/1
✓ Branch 2 taken 33 times.
33 (void)buff.serializeFrom(sendBuffer.latestTime);
388
389
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 33 times.
99 for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
390
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 62 times.
✓ Branch 4 taken 4 times.
66 if (sectionNeedsSend[section]) {
391 62 PktSendCounters& pktEntryFlags = this->m_packetFlags[section][pkt];
392
1/1
✓ Branch 1 taken 62 times.
62 FwIndexType outIndex = this->sectionGroupToPort(section, entryGroup);
393
394
1/1
✓ Branch 6 taken 62 times.
62 this->PktSend_out(outIndex, sendBuffer.buffer, pktEntryFlags.prevSentCounter);
395
396 62 pktEntryFlags.prevSentCounter = 0;
397 62 pktEntryFlags.updateFlag = UpdateFlag::PAST;
398 }
399 }
400 33 }
401 }
402 35 }
403
404 2 void TlmPacketizer ::controlIn_handler(FwIndexType portNum,
405 const Svc::TelemetrySection& section,
406 const Fw::Enabled& enabled) {
407 // NUM_SECTIONS is an enum constant (not a standalone constant), so isValid() accepts it.
408 // The explicit bounds check prevents an out-of-bounds write to m_sectionEnabled.
409
4/8
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
2 if (section.isValid() && section < TelemetrySection::NUM_SECTIONS && enabled.isValid()) {
410 2 (void)(this->m_sectionEnabled[static_cast<FwSizeType>(section)] = enabled);
411 } else {
412 ✗ this->log_WARNING_LO_SectionUnconfigurable(section, enabled);
413 }
414 2 }
415
416 1 void TlmPacketizer ::pingIn_handler(const FwIndexType portNum, U32 key) {
417 // return key
418 1 this->pingOut_out(0, key);
419 1 }
420
421 // ----------------------------------------------------------------------
422 // Command handler implementations
423 // ----------------------------------------------------------------------
424
425 3 void TlmPacketizer ::SET_LEVEL_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, FwChanIdType level) {
426
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (level > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
427 1 this->log_WARNING_LO_MaxLevelExceed(level, MAX_CONFIGURABLE_TLMPACKETIZER_GROUP);
428
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
429 1 return;
430 }
431
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
432
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
20 for (FwChanIdType group = 0; group < NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS; group++) {
433
2/2
✓ Branch 13 taken 8 times.
✓ Branch 14 taken 8 times.
16 this->m_groupConfigs[static_cast<FwSizeType>(section)][group].set_enabled(
434 group <= level ? Fw::Enabled::ENABLED : Fw::Enabled::DISABLED);
435 }
436 }
437
2/2
✓ Branch 6 taken 2 times.
✓ Branch 12 taken 2 times.
2 this->tlmWrite_GroupConfigs(this->m_groupConfigs);
438 2 this->log_ACTIVITY_HI_LevelSet(level);
439
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
440 }
441
442 4 void TlmPacketizer ::SEND_PKT_cmdHandler(const FwOpcodeType opCode,
443 const U32 cmdSeq,
444 const U32 id,
445 const Svc::TelemetrySection& section) {
446 4 FW_ASSERT(section.isValid());
447
3/6
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 4 times.
4 if (section < 0 or section >= TelemetrySection::NUM_SECTIONS) {
448 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
449 ✗ return;
450 }
451 4 FwChanIdType pkt = 0;
452
2/2
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 1 times.
8 for (pkt = 0; pkt < this->m_numPackets; pkt++) {
453
2/2
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 4 times.
7 if (this->m_fillBuffers[pkt].id == id) {
454 3 this->m_lock.lock();
455 3 this->m_fillBuffers[pkt].updated = true;
456
2/2
✓ Branch 3 taken 3 times.
✓ Branch 13 taken 3 times.
3 this->m_fillBuffers[pkt].latestTime = this->getTime();
457 3 this->m_lock.unLock();
458
459 3 this->m_packetFlags[section][pkt].updateFlag = UpdateFlag::REQUESTED;
460
461 3 this->log_ACTIVITY_LO_PacketSent(id);
462 3 break;
463 }
464 }
465
466 // couldn't find it
467
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
4 if (pkt == this->m_numPackets) {
468 1 log_WARNING_LO_PacketNotFound(id);
469
2/2
✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
470 1 return;
471 }
472
473
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
474 }
475
476 41 void TlmPacketizer ::ENABLE_SECTION_cmdHandler(FwOpcodeType opCode,
477 U32 cmdSeq,
478 const Svc::TelemetrySection& section,
479 const Fw::Enabled& enable) {
480 41 FW_ASSERT(section.isValid());
481 41 FW_ASSERT(enable.isValid());
482
3/6
✓ Branch 4 taken 41 times.
✗ Branch 5 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 41 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 41 times.
41 if (section < 0 or section >= TelemetrySection::NUM_SECTIONS) {
483 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
484 ✗ return;
485 }
486 41 (void)(this->m_sectionEnabled[section] = enable);
487
2/2
✓ Branch 6 taken 41 times.
✓ Branch 12 taken 41 times.
41 this->tlmWrite_SectionEnabled(this->m_sectionEnabled);
488
2/2
✓ Branch 6 taken 41 times.
✓ Branch 9 taken 41 times.
41 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
489 }
490
491 156 void TlmPacketizer ::ENABLE_GROUP_cmdHandler(FwOpcodeType opCode,
492 U32 cmdSeq,
493 const Svc::TelemetrySection& section,
494 FwChanIdType tlmGroup,
495 const Fw::Enabled& enable) {
496 156 FW_ASSERT(section.isValid());
497 156 FW_ASSERT(enable.isValid());
498
4/8
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 156 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 156 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 156 times.
156 if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
499 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
500 ✗ return;
501 }
502 156 this->m_groupConfigs[section][tlmGroup].set_enabled(enable);
503
2/2
✓ Branch 6 taken 156 times.
✓ Branch 12 taken 156 times.
156 this->tlmWrite_GroupConfigs(this->m_groupConfigs);
504
2/2
✓ Branch 6 taken 156 times.
✓ Branch 9 taken 156 times.
156 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
505 }
506
507 2 void TlmPacketizer ::FORCE_GROUP_cmdHandler(FwOpcodeType opCode,
508 U32 cmdSeq,
509 const Svc::TelemetrySection& section,
510 FwChanIdType tlmGroup,
511 const Fw::Enabled& enable) {
512 2 FW_ASSERT(section.isValid());
513 2 FW_ASSERT(enable.isValid());
514
4/8
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
2 if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
515 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
516 ✗ return;
517 }
518 2 this->m_groupConfigs[section][tlmGroup].set_forceEnabled(enable);
519
2/2
✓ Branch 6 taken 2 times.
✓ Branch 12 taken 2 times.
2 this->tlmWrite_GroupConfigs(this->m_groupConfigs);
520
2/2
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
521 }
522
523 154 void TlmPacketizer ::CONFIGURE_GROUP_RATES_cmdHandler(FwOpcodeType opCode,
524 U32 cmdSeq,
525 const Svc::TelemetrySection& section,
526 FwChanIdType tlmGroup,
527 const Svc::RateLogic& rateLogic,
528 U32 minDelta,
529 U32 maxDelta) {
530 154 FW_ASSERT(section.isValid());
531 154 FW_ASSERT(rateLogic.isValid());
532
4/8
✓ Branch 4 taken 154 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 154 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 154 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 154 times.
154 if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
533 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
534 ✗ return;
535 }
536 154 this->configureSectionGroupRate(section, tlmGroup, rateLogic, minDelta, maxDelta);
537
2/2
✓ Branch 6 taken 154 times.
✓ Branch 9 taken 154 times.
154 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
538 }
539
540 155 void TlmPacketizer::configureSectionGroupRate(
541 const Svc::TelemetrySection& section, //!< Section grouping
542 FwChanIdType tlmGroup, //!< Group Identifier
543 const Svc::RateLogic& rateLogic, //!< Rate Logic
544 U32 minDelta, //!< Minimum Sched Ticks to send packets on updates when using ON_CHANGE logic
545 U32 maxDelta //!< Maximum Sched Ticks between packets to send when using EVERY_MAX logic
546 ) {
547 155 FW_ASSERT(section.isValid());
548 155 FW_ASSERT(rateLogic.isValid());
549 // These two asserts are an "if" statement in a command so they will no assert on bad user data
550 155 FW_ASSERT(section >= 0 and section < TelemetrySection::NUM_SECTIONS);
551 155 FW_ASSERT(tlmGroup <= MAX_CONFIGURABLE_TLMPACKETIZER_GROUP);
552
553 155 TlmPacketizer_GroupConfig& groupConfig = this->m_groupConfigs[section][tlmGroup];
554 155 groupConfig.set_rateLogic(rateLogic);
555 155 groupConfig.set_min(minDelta);
556 155 groupConfig.set_max(maxDelta);
557
2/2
✓ Branch 6 taken 155 times.
✓ Branch 12 taken 155 times.
155 this->tlmWrite_GroupConfigs(this->m_groupConfigs);
558 155 }
559
560 244 FwIndexType TlmPacketizer::sectionGroupToPort(const FwIndexType section, const FwSizeType group) {
561 // Confirm the indices will not overflow the size of the array
562 244 FW_ASSERT(group < TlmPacketizer_TelemetrySendSection::SIZE, static_cast<FwAssertArgType>(group));
563 244 FW_ASSERT(section < TlmPacketizer_TelemetrySendPortMap::SIZE, static_cast<FwAssertArgType>(section));
564
565 244 const FwIndexType outIndex = TlmPacketizer::TELEMETRY_SEND_PORT_MAP[static_cast<FwSizeType>(section)][group];
566
567 // Confirm the output port index is within the valid number of telemetry send ports
568 244 FW_ASSERT(outIndex < TELEMETRY_SEND_PORTS, static_cast<FwAssertArgType>(outIndex));
569 244 return outIndex;
570 }
571
572 52 void TlmPacketizer::missingChannel(FwChanIdType id) {
573 // search to see if missing channel has already been sent
574
2/2
✓ Branch 0 taken 676 times.
✓ Branch 1 taken 1 times.
677 for (FwChanIdType slot = 0; slot < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; slot++) {
575 // if it's been checked, return
576
5/6
✗ Branch 4 not taken.
✓ Branch 5 taken 676 times.
✓ Branch 6 taken 650 times.
✓ Branch 7 taken 26 times.
✓ Branch 13 taken 25 times.
✓ Branch 14 taken 625 times.
676 if (this->m_missTlmCheck[slot].checked and (this->m_missTlmCheck[slot].id == id)) {
577 25 return;
578
3/4
✗ Branch 4 not taken.
✓ Branch 5 taken 651 times.
✓ Branch 6 taken 26 times.
✓ Branch 7 taken 625 times.
651 } else if (not this->m_missTlmCheck[slot].checked) {
579 26 this->m_missTlmCheck[slot].checked = true;
580 26 this->m_missTlmCheck[slot].id = id;
581 26 this->log_WARNING_LO_NoChan(id);
582 26 return;
583 }
584 }
585 }
586
587 42 Fw::SerializeStatus TlmPacketizer::deserializeParam(const FwPrmIdType base_id,
588 const FwPrmIdType local_id,
589 const Fw::ParamValid prmStat,
590 Fw::SerialBufferBase& buff) {
591
4/6
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 40 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 42 times.
✗ Branch 11 not taken.
42 if (FW_PARAM_OK(prmStat)) {
592
2/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 switch (local_id) {
593 21 case PARAMID_SECTION_ENABLED:
594 21 return buff.deserializeTo(this->m_sectionEnabled);
595 21 case PARAMID_SECTION_CONFIGS:
596 21 return buff.deserializeTo(this->m_groupConfigs);
597 ✗ default:
598 ✗ FW_ASSERT(false, static_cast<FwAssertArgType>(local_id));
599 }
600 }
601 ✗ return Fw::SerializeStatus::FW_DESERIALIZE_TYPE_MISMATCH;
602 }
603
604 2 Fw::SerializeStatus TlmPacketizer::serializeParam(const FwPrmIdType base_id,
605 const FwPrmIdType local_id,
606 Fw::SerialBufferBase& buff) const {
607
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (local_id) {
608 1 case PARAMID_SECTION_ENABLED:
609 1 return buff.serializeFrom(this->m_sectionEnabled);
610 1 case PARAMID_SECTION_CONFIGS:
611 1 return buff.serializeFrom(this->m_groupConfigs);
612 ✗ default:
613 ✗ FW_ASSERT(false, static_cast<FwAssertArgType>(local_id));
614 }
615 ✗ return Fw::SerializeStatus::FW_SERIALIZE_FORMAT_ERROR;
616 }
617
618 } // end namespace Svc
619