GCC Code Coverage Report


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