GCC Code Coverage Report


Directory: /home/runner/work/fprime/fprime/Svc/ComLoggerDp/
File: ComLoggerDp.cpp
Date: 2026-11-03 22:11:30
Exec Total Coverage
Lines: 0 132 0.0%
Functions: 0 21 0.0%
Branches: 0 88 0.0%

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