F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
ComLoggerDp.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title ComLoggerDp.cpp
3 // \author tcanham
4 // \brief cpp file for ComLoggerDp component implementation class
5 // ======================================================================
6 
9 
10 namespace Svc {
11 
12 // ----------------------------------------------------------------------
13 // Component construction and destruction
14 // ----------------------------------------------------------------------
15 
16 ComLoggerDp ::ComLoggerDp(const char* const compName) : ComLoggerDpComponentBase(compName) {}
17 
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 
91  // Check for auto-flush condition
92  // Note: m_flushTimeout > 0 check ensures auto-flush is disabled when timeout is 0
93  // Without this check, flushTimeout=0 would cause immediate flush (0 >= 0 is true)
94  if (this->m_enabled && this->m_currentPacketCount > 0 && this->m_flushTimeout > 0) {
95  ++this->m_schedCallsSinceLastPacket;
96 
97  if (this->m_schedCallsSinceLastPacket >= this->m_flushTimeout) {
98  // Flush the partial container
99  this->finalizeContainer();
100  this->m_schedCallsSinceLastPacket = 0;
101  }
102  }
103 
104  // Write telemetry
105  this->tlmWrite_LoggingEnabled(this->m_enabled);
106  this->tlmWrite_NumBuffersLogged(this->m_numBuffersLogged);
107  this->tlmWrite_NumBuffersDropped(this->m_numBuffersDropped);
108  this->tlmWrite_NumQueueDrops(static_cast<U32>(this->getNumMsgsDropped()));
109 }
110 
111 void ComLoggerDp ::startRecordingIn_handler(FwIndexType portNum,
112  FwSizeType packetsPerContainer,
113  FwDpPriorityType priority) {
114  // portNum is unused
115  (void)portNum;
116 
117  // Call internal helper function and check for validation failure
118  const Fw::Success success = this->startRecordingInternal(packetsPerContainer, priority);
119 
120  // Log warning if validation failed
121  if (success != Fw::Success::SUCCESS) {
122  this->log_WARNING_LO_StartRecordingFailed(packetsPerContainer);
123  }
124 }
125 
126 void ComLoggerDp ::stopRecordingIn_handler(FwIndexType portNum) {
127  // portNum is unused
128  (void)portNum;
129 
130  // Call internal helper function
131  (void)this->stopRecordingInternal();
132 }
133 
134 // ----------------------------------------------------------------------
135 // Private helper functions
136 // ----------------------------------------------------------------------
137 
138 Fw::Success ComLoggerDp ::startRecordingInternal(FwSizeType packetsPerContainer, FwDpPriorityType priority) {
139  // The container (header + records) is requested through Fw.BufferGet, whose size argument is a U32,
140  // so reserve the header and bound the record count to what fits in the remaining U32 range
141  constexpr FwSizeType MAX_PACKETS_PER_CONTAINER =
142  (static_cast<FwSizeType>(std::numeric_limits<U32>::max()) - Fw::DpContainer::MIN_PACKET_SIZE) / RECORD_SIZE;
143  if ((packetsPerContainer == 0) || (packetsPerContainer > MAX_PACKETS_PER_CONTAINER)) {
144  // Disable logging on validation failure, flushing any partial container first
145  (void)this->sendContainerIfNonEmpty();
146  this->m_enabled = false;
147  return Fw::Success::FAILURE;
148  }
149 
150  // If recording is already active and there's a partial container, send it before reconfiguring
151  (void)this->sendContainerIfNonEmpty();
152 
153  // Store configuration
154  this->m_packetsPerContainer = packetsPerContainer;
155  this->m_priority = priority;
156 
157  // Reset inactivity counter
158  this->m_schedCallsSinceLastPacket = 0;
159 
160  // Enable logging
161  this->m_enabled = true;
162 
163  // Log event
164  this->log_ACTIVITY_HI_ComDpStarted(packetsPerContainer);
165 
166  return Fw::Success::SUCCESS;
167 }
168 
169 ComLoggerDp_PartialContainerStatus ComLoggerDp ::stopRecordingInternal() {
170  // If there's a partial container, send it before stopping
171  const ComLoggerDp_PartialContainerStatus partialContainer = this->sendContainerIfNonEmpty();
172 
173  // Disable logging
174  this->m_enabled = false;
175 
176  // Reset inactivity counter
177  this->m_schedCallsSinceLastPacket = 0;
178 
179  // Log event
180  this->log_ACTIVITY_HI_ComDpStopped(partialContainer);
181 
182  return partialContainer;
183 }
184 
185 void ComLoggerDp ::handleBufferDrop(U32 size) {
186  this->log_WARNING_HI_DpBufferError(size);
187  ++this->m_numBuffersDropped;
188 }
189 
190 Fw::Success ComLoggerDp ::allocateAndSetupContainer() {
191  // Calculate data size needed for the requested number of packets
192  // Each record holds a sentry plus up to FW_COM_BUFFER_MAX_SIZE bytes
193  // Note: DpManager adds the container header overhead, so we only request the data size
194  const FwSizeType containerSize = this->m_packetsPerContainer * RECORD_SIZE;
195 
196  // Get a container buffer
197  const Fw::Success status = this->dpGet_ComBuffContainer(containerSize, this->m_container);
198 
199  // Check for allocation failure
200  if (status != Fw::Success::SUCCESS) {
201  this->handleBufferDrop(static_cast<U32>(containerSize));
202  return Fw::Success::FAILURE;
203  }
204 
205  // Set the priority on the newly allocated container
206  this->m_container.setPriority(this->m_priority);
207  return Fw::Success::SUCCESS;
208 }
209 
210 void ComLoggerDp ::serializePacket(const U8* dataPtr, FwSizeType dataSize) {
211  // Create buffer with sentry followed by ComBuffer data
212  // Use sizeof to get sentry size (supports user changing the constant type)
213  const FwSizeType sentrySize = sizeof(ComLoggerDpSentry);
214  const FwSizeType totalSize = sentrySize + dataSize;
215 
216  // Use F Prime serialization to insert sentry value (handles endianness automatically)
217  Fw::ExternalSerializeBuffer serBuf(this->m_recordBuffer, sizeof(this->m_recordBuffer));
218  Fw::SerializeStatus serStatus = serBuf.serializeFrom(ComLoggerDpSentry);
219  FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
220 
221  // Copy ComBuffer data after sentry
222  serStatus = serBuf.serializeFrom(dataPtr, dataSize, Fw::Serialization::OMIT_LENGTH);
223  FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
224 
225  // Serialize the complete record into the container
226  serStatus = this->m_container.serializeRecord_ComBufferRecord(this->m_recordBuffer, totalSize);
227  FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
228 }
229 
230 ComLoggerDp_PartialContainerStatus ComLoggerDp ::sendContainerIfNonEmpty() {
231  // Send container if logging is enabled and it has any packets
232  // Handles both full and partial containers
233  if (this->m_enabled && this->m_currentPacketCount > 0) {
234  this->dpSend(this->m_container);
235  // Note: dpSend() invalidates the container; will allocate new one on next packet
236  this->m_currentPacketCount = 0;
238  }
240 }
241 
242 void ComLoggerDp ::finalizeContainer() {
243  // Send the container (full or partial) and reset the packet count
244  (void)this->sendContainerIfNonEmpty();
245 }
246 
247 // ----------------------------------------------------------------------
248 // Handler implementations for commands
249 // ----------------------------------------------------------------------
250 
251 void ComLoggerDp ::StartComDp_cmdHandler(FwOpcodeType opCode,
252  U32 cmdSeq,
253  FwSizeType packetsPerContainer,
254  FwDpPriorityType priority) {
255  // Call internal helper function
256  const Fw::Success success = this->startRecordingInternal(packetsPerContainer, priority);
257 
258  // Send command response
259  if (success == Fw::Success::SUCCESS) {
260  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
261  } else {
262  // Log warning event for validation failure (consistent with port path)
263  this->log_WARNING_LO_StartRecordingFailed(packetsPerContainer);
264  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
265  }
266 }
267 
268 void ComLoggerDp ::UpdatePriority_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, FwDpPriorityType priority) {
269  // Store the new priority
270  this->m_priority = priority;
271 
272  // Update priority if logging is enabled and there's an active container
273  if (this->m_enabled && (this->m_currentPacketCount > 0)) {
274  this->m_container.setPriority(this->m_priority);
275  }
276 
277  // Log event
278  this->log_ACTIVITY_LO_PriorityUpdated(priority);
279 
280  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
281 }
282 
283 void ComLoggerDp ::StopComDp_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
284  // Call internal helper function
285  (void)this->stopRecordingInternal();
286 
287  // Send command response
288  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
289 }
290 
291 void ComLoggerDp ::CLEAR_COUNTERS_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
292  // Clear the NumBuffersLogged counter
293  this->m_numBuffersLogged = 0;
294 
295  // Clear the NumBuffersDropped counter
296  this->m_numBuffersDropped = 0;
297 
298  // Clear the DpBufferError event throttle
300 
301  // Log event
303 
304  // Send command response
305  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
306 }
307 
308 } // namespace Svc
Serialization/Deserialization operation was successful.
FwIdType FwOpcodeType
The type of a command opcode.
Representing success.
PlatformSizeType FwSizeType
Fw::Success::T dpGet_ComBuffContainer(FwSizeType dataSize, DpContainer &container)
U32 FwDpPriorityType
The type of a data product priority.
void dpSend(DpContainer &container, Fw::Time timeTag=Fw::ZERO_TIME)
Send a data product.
void configure(bool enabled, FwSizeType packetsPerContainer, FwDpPriorityType priority, U32 flushTimeout)
Definition: ComLoggerDp.cpp:24
static constexpr FwSizeType MIN_PACKET_SIZE
Definition: DpContainer.hpp:65
Serializable::SizeType getSize() const override
Get current buffer size.
void tlmWrite_NumBuffersDropped(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
ComLoggerDp(const char *const compName)
Construct ComLoggerDp object.
Definition: ComLoggerDp.cpp:16
SerializeStatus
forward declaration for string
void log_WARNING_HI_DpBufferError(U32 size)
Log event DpBufferError.
Auto-generated base for ComLoggerDp component.
~ComLoggerDp()
Destroy ComLoggerDp object.
Definition: ComLoggerDp.cpp:18
FwSizeType getNumMsgsDropped()
return number of messages dropped
U8 * getBuffAddr()
Get buffer address for data filling (non-const version)
Omit length from serialization.
void log_ACTIVITY_LO_PriorityUpdated(FwDpPriorityType priority) const
External serialize buffer with no copy semantics.
Fw::SerializeStatus serializeRecord_ComBufferRecord(const U8 *array, FwSizeType size)
void pingOut_out(FwIndexType portNum, U32 key) const
Invoke output port pingOut.
Representing failure.
Command successfully executed.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:54
constexpr U32 ComLoggerDpSentry
void log_WARNING_LO_StartRecordingFailed(FwSizeType packetsPerContainer) const
PlatformIndexType FwIndexType
Command failed validation.
RateGroupDivider component implementation.
void tlmWrite_NumQueueDrops(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void log_ACTIVITY_HI_ComDpStarted(FwSizeType packetsPerContainer) const
void log_ACTIVITY_HI_ComDpStopped(const Svc::ComLoggerDp_PartialContainerStatus &partialContainer) const
void log_WARNING_HI_DpBufferError_ThrottleClear()
Reset throttle value for DpBufferError.
void setPriority(FwDpPriorityType priority)
Set the priority.
void tlmWrite_NumBuffersLogged(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
#define FW_ASSERT(...)
Definition: Assert.hpp:14
void tlmWrite_LoggingEnabled(bool arg, Fw::Time _tlmTime=Fw::Time()) const
Success/Failure.
static constexpr FwSizeType RECORD_SIZE
Serialized size of one ComBufferRecord holding MAX_RECORD_DATA_SIZE bytes.
Definition: ComLoggerDp.hpp:32