GCC Code Coverage Report


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