GCC Code Coverage Report


Directory: ./
File: Svc/ComLoggerDp/ComLoggerDp.cpp
Date: 2026-11-03 21:15:54
Exec Total Coverage
Lines: 128 132 97.0%
Functions: 20 21 95.2%
Branches: 92 102 90.2%

Line Branch Exec Source
1 // ======================================================================
2 // \title ComLoggerDp.cpp
3 // \author tcanham
4 // \brief cpp file for ComLoggerDp component implementation class
5 // ======================================================================
6
7 #include "Svc/ComLoggerDp/ComLoggerDp.hpp"
8 #include "Fw/FPrimeBasicTypes.hpp"
9
10 namespace Svc {
11
12 // ----------------------------------------------------------------------
13 // Component construction and destruction
14 // ----------------------------------------------------------------------
15
16
1/1
✓ Branch 15 taken 29 times.
29 ComLoggerDp ::ComLoggerDp(const char* const compName) : ComLoggerDpComponentBase(compName) {}
17
18 58 ComLoggerDp ::~ComLoggerDp() {}
19
20 // ----------------------------------------------------------------------
21 // Public interface
22 // ----------------------------------------------------------------------
23
24 6 void ComLoggerDp ::configure(bool enabled,
25 FwSizeType packetsPerContainer,
26 FwDpPriorityType priority,
27 U32 flushTimeout) {
28 // Store flush timeout setting
29 6 this->m_flushTimeout = flushTimeout;
30
31 // If enabling, use the internal start function which validates parameters
32
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (enabled) {
33 // This will validate packetsPerContainer and set m_enabled
34
1/1
✓ Branch 2 taken 4 times.
4 const Fw::Success started = this->startRecordingInternal(packetsPerContainer, priority);
35 4 FW_ASSERT(started == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(packetsPerContainer));
36 4 } else {
37 // Just disable if not enabling
38 2 this->m_enabled = false;
39 }
40 6 }
41
42 // ----------------------------------------------------------------------
43 // Handler implementations for typed input ports
44 // ----------------------------------------------------------------------
45
46 49 void ComLoggerDp ::comIn_handler(FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
47 // portNum and context are unused
48 (void)portNum;
49 (void)context;
50
51 // If logging is not enabled, return immediately
52
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 49 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 46 times.
49 if (!this->m_enabled) {
53 3 return;
54 }
55
56 // Reset inactivity counter - we received a packet
57 46 this->m_schedCallsSinceLastPacket = 0;
58
59 // Allocate container if needed
60
11/15
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 15 times.
✓ Branch 8 taken 31 times.
✓ Branch 14 taken 8 times.
✓ Branch 15 taken 23 times.
✓ Branch 16 taken 31 times.
✓ Branch 17 taken 15 times.
✓ Branch 20 taken 31 times.
✓ Branch 21 taken 15 times.
✓ Branch 23 taken 8 times.
✓ Branch 24 taken 38 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
46 if ((this->m_currentPacketCount == 0) && (this->allocateAndSetupContainer() != Fw::Success::SUCCESS)) {
61 8 return;
62 }
63
64 // Get data from ComBuffer
65 38 const FwSizeType dataSize = data.getSize();
66 38 const U8* dataPtr = data.getBuffAddr();
67
68 // Serialize the packet
69 38 this->serializePacket(dataPtr, dataSize);
70
71 // Increment counters
72 38 ++this->m_currentPacketCount;
73 38 ++this->m_numBuffersLogged;
74
75 // Check if container has reached the limit
76
2/2
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 26 times.
38 if (this->m_currentPacketCount >= this->m_packetsPerContainer) {
77 12 this->finalizeContainer();
78 }
79 }
80
81 1 void ComLoggerDp ::pingIn_handler(FwIndexType portNum, U32 key) {
82 // Return the key via pingOut port
83 1 this->pingOut_out(portNum, key);
84 1 }
85
86 46 void ComLoggerDp ::schedIn_handler(FwIndexType portNum, U32 context) {
87 // portNum and context are unused
88 (void)portNum;
89 (void)context;
90 46 bool expected = false;
91
1/2
✓ Branch 4 taken 46 times.
✗ Branch 5 not taken.
46 if (this->m_schedInQueued.compare_exchange_strong(expected, true)) {
92
1/1
✓ Branch 5 taken 46 times.
46 this->schedInInternal_internalInterfaceInvoke();
93 }
94 46 }
95
96 ✗ void ComLoggerDp ::schedInInternal_overflowHook() {
97 ✗ this->m_schedInQueued = false;
98 ✗ }
99
100 46 void ComLoggerDp ::schedInInternal_internalInterfaceHandler() {
101 46 this->m_schedInQueued = false;
102
103 // Check for auto-flush condition
104 // Note: m_flushTimeout > 0 check ensures auto-flush is disabled when timeout is 0
105 // Without this check, flushTimeout=0 would cause immediate flush (0 >= 0 is true)
106
7/8
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 43 times.
✓ Branch 6 taken 3 times.
✓ Branch 11 taken 33 times.
✓ Branch 12 taken 10 times.
✓ Branch 17 taken 28 times.
✓ Branch 18 taken 5 times.
46 if (this->m_enabled && this->m_currentPacketCount > 0 && this->m_flushTimeout > 0) {
107 28 ++this->m_schedCallsSinceLastPacket;
108
109
2/2
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 26 times.
28 if (this->m_schedCallsSinceLastPacket >= this->m_flushTimeout) {
110 // Flush the partial container
111 2 this->finalizeContainer();
112 2 this->m_schedCallsSinceLastPacket = 0;
113 }
114 }
115
116 // Write telemetry
117
3/4
✓ Branch 6 taken 46 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 46 times.
✓ Branch 14 taken 46 times.
46 this->tlmWrite_LoggingEnabled(this->m_enabled);
118
2/2
✓ Branch 6 taken 46 times.
✓ Branch 13 taken 46 times.
46 this->tlmWrite_NumBuffersLogged(this->m_numBuffersLogged);
119
2/2
✓ Branch 6 taken 46 times.
✓ Branch 13 taken 46 times.
46 this->tlmWrite_NumBuffersDropped(this->m_numBuffersDropped);
120
3/3
✓ Branch 6 taken 46 times.
✓ Branch 13 taken 46 times.
✓ Branch 16 taken 46 times.
46 this->tlmWrite_NumQueueDrops(static_cast<U32>(this->getNumMsgsDropped()));
121 46 }
122
123 2 void ComLoggerDp ::startRecordingIn_handler(FwIndexType portNum,
124 FwSizeType packetsPerContainer,
125 FwDpPriorityType priority) {
126 // portNum is unused
127 (void)portNum;
128
129 // Call internal helper function and check for validation failure
130
1/1
✓ Branch 2 taken 2 times.
2 const Fw::Success success = this->startRecordingInternal(packetsPerContainer, priority);
131
132 // Log warning if validation failed
133
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if (success != Fw::Success::SUCCESS) {
134
1/1
✓ Branch 5 taken 1 times.
1 this->log_WARNING_LO_StartRecordingFailed(packetsPerContainer);
135 }
136 4 }
137
138 1 void ComLoggerDp ::stopRecordingIn_handler(FwIndexType portNum) {
139 // portNum is unused
140 (void)portNum;
141
142 // Call internal helper function
143
1/1
✓ Branch 2 taken 1 times.
1 (void)this->stopRecordingInternal();
144 1 }
145
146 // ----------------------------------------------------------------------
147 // Private helper functions
148 // ----------------------------------------------------------------------
149
150 29 Fw::Success ComLoggerDp ::startRecordingInternal(FwSizeType packetsPerContainer, FwDpPriorityType priority) {
151 // The container (header + records) is requested through Fw.BufferGet, whose size argument is a U32,
152 // so reserve the header and bound the record count to what fits in the remaining U32 range
153 29 constexpr FwSizeType MAX_PACKETS_PER_CONTAINER =
154 (static_cast<FwSizeType>(std::numeric_limits<U32>::max()) - Fw::DpContainer::MIN_PACKET_SIZE) / RECORD_SIZE;
155
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 25 times.
29 if ((packetsPerContainer == 0) || (packetsPerContainer > MAX_PACKETS_PER_CONTAINER)) {
156 // Disable logging on validation failure, flushing any partial container first
157
1/1
✓ Branch 2 taken 4 times.
4 (void)this->sendContainerIfNonEmpty();
158 4 this->m_enabled = false;
159 4 return Fw::Success::FAILURE;
160 }
161
162 // If recording is already active and there's a partial container, send it before reconfiguring
163
1/1
✓ Branch 2 taken 25 times.
25 (void)this->sendContainerIfNonEmpty();
164
165 // Store configuration
166 25 this->m_packetsPerContainer = packetsPerContainer;
167 25 this->m_priority = priority;
168
169 // Reset inactivity counter
170 25 this->m_schedCallsSinceLastPacket = 0;
171
172 // Enable logging
173 25 this->m_enabled = true;
174
175 // Log event
176 25 this->log_ACTIVITY_HI_ComDpStarted(packetsPerContainer);
177
178 25 return Fw::Success::SUCCESS;
179 }
180
181 5 ComLoggerDp_PartialContainerStatus ComLoggerDp ::stopRecordingInternal() {
182 // If there's a partial container, send it before stopping
183 5 const ComLoggerDp_PartialContainerStatus partialContainer = this->sendContainerIfNonEmpty();
184
185 // Disable logging
186 5 this->m_enabled = false;
187
188 // Reset inactivity counter
189 5 this->m_schedCallsSinceLastPacket = 0;
190
191 // Log event
192
1/1
✓ Branch 5 taken 5 times.
5 this->log_ACTIVITY_HI_ComDpStopped(partialContainer);
193
194 5 return partialContainer;
195 ✗ }
196
197 8 void ComLoggerDp ::handleBufferDrop(U32 size) {
198 8 this->log_WARNING_HI_DpBufferError(size);
199 8 ++this->m_numBuffersDropped;
200 8 }
201
202 31 Fw::Success ComLoggerDp ::allocateAndSetupContainer() {
203 // Calculate data size needed for the requested number of packets
204 // Each record holds a sentry plus up to FW_COM_BUFFER_MAX_SIZE bytes
205 // Note: DpManager adds the container header overhead, so we only request the data size
206 31 const FwSizeType containerSize = this->m_packetsPerContainer * RECORD_SIZE;
207
208 // Get a container buffer
209
2/2
✓ Branch 9 taken 31 times.
✓ Branch 12 taken 31 times.
31 const Fw::Success status = this->dpGet_ComBuffContainer(containerSize, this->m_container);
210
211 // Check for allocation failure
212
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 23 times.
31 if (status != Fw::Success::SUCCESS) {
213
1/1
✓ Branch 4 taken 8 times.
8 this->handleBufferDrop(static_cast<U32>(containerSize));
214
1/1
✓ Branch 1 taken 8 times.
8 return Fw::Success::FAILURE;
215 }
216
217 // Set the priority on the newly allocated container
218 23 this->m_container.setPriority(this->m_priority);
219
1/1
✓ Branch 1 taken 23 times.
23 return Fw::Success::SUCCESS;
220 31 }
221
222 38 void ComLoggerDp ::serializePacket(const U8* dataPtr, FwSizeType dataSize) {
223 // Create buffer with sentry followed by ComBuffer data
224 // Use sizeof to get sentry size (supports user changing the constant type)
225 38 const FwSizeType sentrySize = sizeof(ComLoggerDpSentry);
226 38 const FwSizeType totalSize = sentrySize + dataSize;
227
228 // Use F Prime serialization to insert sentry value (handles endianness automatically)
229
1/1
✓ Branch 4 taken 38 times.
38 Fw::ExternalSerializeBuffer serBuf(this->m_recordBuffer, sizeof(this->m_recordBuffer));
230
1/1
✓ Branch 2 taken 38 times.
38 Fw::SerializeStatus serStatus = serBuf.serializeFrom(ComLoggerDpSentry);
231 38 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
232
233 // Copy ComBuffer data after sentry
234
1/1
✓ Branch 2 taken 38 times.
38 serStatus = serBuf.serializeFrom(dataPtr, dataSize, Fw::Serialization::OMIT_LENGTH);
235 38 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
236
237 // Serialize the complete record into the container
238
1/1
✓ Branch 8 taken 38 times.
38 serStatus = this->m_container.serializeRecord_ComBufferRecord(this->m_recordBuffer, totalSize);
239 38 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
240 76 }
241
242 48 ComLoggerDp_PartialContainerStatus ComLoggerDp ::sendContainerIfNonEmpty() {
243 // Send container if logging is enabled and it has any packets
244 // Handles both full and partial containers
245
5/6
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 27 times.
✓ Branch 11 taken 19 times.
✓ Branch 12 taken 2 times.
48 if (this->m_enabled && this->m_currentPacketCount > 0) {
246
2/2
✓ Branch 7 taken 19 times.
✓ Branch 13 taken 19 times.
19 this->dpSend(this->m_container);
247 // Note: dpSend() invalidates the container; will allocate new one on next packet
248 19 this->m_currentPacketCount = 0;
249 19 return ComLoggerDp_PartialContainerStatus::SENT;
250 }
251 29 return ComLoggerDp_PartialContainerStatus::NOT_SENT;
252 }
253
254 14 void ComLoggerDp ::finalizeContainer() {
255 // Send the container (full or partial) and reset the packet count
256
1/1
✓ Branch 2 taken 14 times.
14 (void)this->sendContainerIfNonEmpty();
257 14 }
258
259 // ----------------------------------------------------------------------
260 // Handler implementations for commands
261 // ----------------------------------------------------------------------
262
263 23 void ComLoggerDp ::StartComDp_cmdHandler(FwOpcodeType opCode,
264 U32 cmdSeq,
265 FwSizeType packetsPerContainer,
266 FwDpPriorityType priority) {
267 // Call internal helper function
268
1/1
✓ Branch 2 taken 23 times.
23 const Fw::Success success = this->startRecordingInternal(packetsPerContainer, priority);
269
270 // Send command response
271
2/2
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 3 times.
23 if (success == Fw::Success::SUCCESS) {
272
2/2
✓ Branch 6 taken 20 times.
✓ Branch 9 taken 20 times.
20 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
273 } else {
274 // Log warning event for validation failure (consistent with port path)
275
1/1
✓ Branch 5 taken 3 times.
3 this->log_WARNING_LO_StartRecordingFailed(packetsPerContainer);
276
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
277 }
278 46 }
279
280 3 void ComLoggerDp ::UpdatePriority_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, FwDpPriorityType priority) {
281 // Store the new priority
282 3 this->m_priority = priority;
283
284 // Update priority if logging is enabled and there's an active container
285
5/6
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
3 if (this->m_enabled && (this->m_currentPacketCount > 0)) {
286 1 this->m_container.setPriority(this->m_priority);
287 }
288
289 // Log event
290 3 this->log_ACTIVITY_LO_PriorityUpdated(priority);
291
292
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
293 3 }
294
295 4 void ComLoggerDp ::StopComDp_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
296 // Call internal helper function
297
1/1
✓ Branch 2 taken 4 times.
4 (void)this->stopRecordingInternal();
298
299 // Send command response
300
2/2
✓ Branch 6 taken 4 times.
✓ Branch 9 taken 4 times.
4 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
301 4 }
302
303 3 void ComLoggerDp ::CLEAR_COUNTERS_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
304 // Clear the NumBuffersLogged counter
305 3 this->m_numBuffersLogged = 0;
306
307 // Clear the NumBuffersDropped counter
308 3 this->m_numBuffersDropped = 0;
309
310 // Clear the DpBufferError event throttle
311 3 this->log_WARNING_HI_DpBufferError_ThrottleClear();
312
313 // Log event
314 3 this->log_ACTIVITY_LO_CountersCleared();
315
316 // Send command response
317
2/2
✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
318 3 }
319
320 } // namespace Svc
321