GCC Code Coverage Report


Directory: ./
File: Svc/DpWriter/DpWriter.cpp
Date: 2026-11-03 22:10:14
Exec Total Coverage
Lines: 95 134 70.9%
Functions: 10 12 83.3%
Branches: 69 113 61.1%

Line Branch Exec Source
1 // ======================================================================
2 // \title DpWriter.cpp
3 // \author bocchino
4 // \brief cpp file for DpWriter component implementation class
5 // ======================================================================
6
7 #include "Svc/DpWriter/DpWriter.hpp"
8 #include "Fw/Com/ComPacket.hpp"
9 #include "Fw/FPrimeBasicTypes.hpp"
10 #include "Fw/Types/FileNameString.hpp"
11 #include "Fw/Types/Serializable.hpp"
12 #include "Os/File.hpp"
13 #include "Utils/Hash/Hash.hpp"
14 #include "config/DpCfg.hpp"
15
16 namespace Svc {
17
18 // ----------------------------------------------------------------------
19 // Construction, initialization, and destruction
20 // ----------------------------------------------------------------------
21
22
1/1
✓ Branch 3 taken 1 times.
1 DpWriter::DpWriter(const char* const compName) : DpWriterComponentBase(compName), m_dpFileNamePrefix() {}
23
24 2 DpWriter::~DpWriter() {}
25
26 1 void DpWriter::configure(const Fw::ConstStringBase& dpFileNamePrefix) {
27 1 this->m_dpFileNamePrefix = dpFileNamePrefix;
28 1 }
29
30 // ----------------------------------------------------------------------
31 // Handler implementations for user-defined typed input ports
32 // ----------------------------------------------------------------------
33
34 5 void DpWriter::bufferSendIn_handler(const FwIndexType portNum, Fw::Buffer& buffer) {
35 5 Fw::Success::T status = Fw::Success::SUCCESS;
36 // Update num buffers received
37 5 ++this->m_numBuffersReceived;
38 // Check that the buffer is valid
39
2/3
✓ Branch 1 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 if (!buffer.isValid()) {
40 ✗ this->log_WARNING_HI_InvalidBuffer();
41 ✗ status = Fw::Success::FAILURE;
42 }
43 // Check that the buffer is large enough to hold a data product packet
44
1/1
✓ Branch 1 taken 5 times.
5 const FwSizeType bufferSize = buffer.getSize();
45
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
46
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (bufferSize < Fw::DpContainer::MIN_PACKET_SIZE) {
47 ✗ this->log_WARNING_HI_BufferTooSmallForPacket(static_cast<U32>(bufferSize),
48 Fw::DpContainer::MIN_PACKET_SIZE);
49
50 ✗ status = Fw::Success::FAILURE;
51 }
52 }
53 // Set up the container and check that the header hash is valid
54
1/1
✓ Branch 1 taken 5 times.
5 Fw::DpContainer container;
55
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
56
1/1
✓ Branch 1 taken 5 times.
5 container.setBuffer(buffer);
57
1/1
✓ Branch 1 taken 5 times.
5 Utils::HashBuffer storedHash;
58
1/1
✓ Branch 1 taken 5 times.
5 Utils::HashBuffer computedHash;
59
1/1
✓ Branch 1 taken 5 times.
5 status = container.checkHeaderHash(storedHash, computedHash);
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (status != Fw::Success::SUCCESS) {
61 ✗ this->log_WARNING_HI_InvalidHeaderHash(static_cast<U32>(bufferSize), storedHash.asBigEndianU32(),
62 computedHash.asBigEndianU32());
63 }
64 5 }
65 // Deserialize the packet header
66
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
67
1/1
✓ Branch 1 taken 5 times.
5 status = this->deserializePacketHeader(buffer, container);
68 }
69 // Check that the packet size fits in the buffer
70
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
71
1/1
✓ Branch 1 taken 5 times.
5 const FwSizeType packetSize = container.getPacketSize();
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (bufferSize < packetSize) {
73 ✗ this->log_WARNING_HI_BufferTooSmallForData(static_cast<U32>(bufferSize), static_cast<U32>(packetSize));
74 ✗ status = Fw::Success::FAILURE;
75 }
76 }
77 // Perform the requested processing
78
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
79
1/1
✓ Branch 1 taken 5 times.
5 this->performProcessing(container);
80 }
81 // Construct the file name
82
1/1
✓ Branch 1 taken 5 times.
5 Fw::FileNameString fileName;
83
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
84 5 const FwDpIdType containerId = container.getId();
85
1/1
✓ Branch 1 taken 5 times.
5 const Fw::Time timeTag = container.getTimeTag();
86
3/3
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
✓ Branch 8 taken 5 times.
5 const Fw::FormatStatus formatStatus = fileName.format(DP_FILENAME_FORMAT, this->m_dpFileNamePrefix.toChar(),
87 containerId, timeTag.getSeconds(), timeTag.getUSeconds());
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (formatStatus != Fw::FormatStatus::SUCCESS) {
89 ✗ this->log_WARNING_HI_FileNameFormatError(static_cast<Fw::StringFormatStatus::T>(formatStatus));
90 ✗ status = Fw::Success::FAILURE;
91 }
92 5 }
93 // Calculate and populate the file data checksum
94
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
95
1/1
✓ Branch 1 taken 5 times.
5 container.updateDataHash();
96 }
97 // Write the file
98 5 FwSizeType fileSize = 0;
99
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
100
1/1
✓ Branch 1 taken 5 times.
5 status = this->writeFile(container, fileName, fileSize);
101 }
102 // Send the DpWritten notification on the path matching the input port
103
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
104
1/1
✓ Branch 1 taken 5 times.
5 this->sendNotification(portNum, container, fileName, fileSize);
105 }
106 // Return the buffer on the path matching the input port
107
2/3
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 if (buffer.isValid()) {
108
1/1
✓ Branch 1 taken 5 times.
5 this->deallocBufferSendOut_out(portNum, buffer);
109 }
110 // Update the error count
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (status != Fw::Success::SUCCESS) {
112 ✗ this->m_numErrors++;
113 }
114 5 }
115
116 66 void DpWriter::schedIn_handler(const FwIndexType portNum, U32 context) {
117 // portNum and context are not used
118 (void)portNum;
119 (void)context;
120 66 bool expected = false;
121
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 if (this->m_schedInQueued.compare_exchange_strong(expected, true)) {
122
1/1
✓ Branch 1 taken 66 times.
66 this->schedInInternal_internalInterfaceInvoke();
123 }
124 66 }
125
126 ✗ void DpWriter::schedInInternal_overflowHook() {
127 ✗ this->m_schedInQueued = false;
128 ✗ }
129
130 66 void DpWriter::schedInInternal_internalInterfaceHandler() {
131 66 this->m_schedInQueued = false;
132 // Write telemetry
133
2/2
✓ Branch 1 taken 66 times.
✓ Branch 4 taken 66 times.
66 this->tlmWrite_NumBuffersReceived(this->m_numBuffersReceived);
134
2/2
✓ Branch 1 taken 66 times.
✓ Branch 4 taken 66 times.
66 this->tlmWrite_NumBytesWritten(this->m_numBytesWritten);
135
2/2
✓ Branch 1 taken 66 times.
✓ Branch 4 taken 66 times.
66 this->tlmWrite_NumSuccessfulWrites(this->m_numSuccessfulWrites);
136
2/2
✓ Branch 1 taken 66 times.
✓ Branch 4 taken 66 times.
66 this->tlmWrite_NumFailedWrites(this->m_numFailedWrites);
137
2/2
✓ Branch 1 taken 66 times.
✓ Branch 4 taken 66 times.
66 this->tlmWrite_NumErrors(this->m_numErrors);
138 66 }
139
140 // ----------------------------------------------------------------------
141 // Handler implementations for commands
142 // ----------------------------------------------------------------------
143
144 ✗ void DpWriter::CLEAR_EVENT_THROTTLE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
145 // opCode and cmdSeq are not used
146 (void)opCode;
147 (void)cmdSeq;
148 // Clear throttling
149 ✗ this->log_WARNING_HI_BufferTooSmallForData_ThrottleClear();
150 ✗ this->log_WARNING_HI_BufferTooSmallForPacket_ThrottleClear();
151 ✗ this->log_WARNING_HI_FileOpenError_ThrottleClear();
152 ✗ this->log_WARNING_HI_FileWriteError_ThrottleClear();
153 ✗ this->log_WARNING_HI_InvalidBuffer_ThrottleClear();
154 ✗ this->log_WARNING_HI_InvalidHeaderHash_ThrottleClear();
155 ✗ this->log_WARNING_HI_InvalidHeader_ThrottleClear();
156 // Return command response
157 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
158 ✗ }
159
160 // ----------------------------------------------------------------------
161 // Private helper functions
162 // ----------------------------------------------------------------------
163
164 5 Fw::Success::T DpWriter::deserializePacketHeader(Fw::Buffer& buffer, Fw::DpContainer& container) {
165 5 Fw::Success::T status = Fw::Success::SUCCESS;
166 5 container.setBuffer(buffer);
167 5 const Fw::SerializeStatus serialStatus = container.deserializeHeader();
168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (serialStatus != Fw::FW_SERIALIZE_OK) {
169 ✗ this->log_WARNING_HI_InvalidHeader(static_cast<U32>(buffer.getSize()), static_cast<U32>(serialStatus));
170 ✗ status = Fw::Success::FAILURE;
171 }
172 5 return status;
173 }
174
175 5 void DpWriter::performProcessing(Fw::DpContainer& container) {
176 // Get the buffer
177
1/1
✓ Branch 1 taken 5 times.
5 Fw::Buffer buffer = container.getBuffer();
178 // Get the bit mask for the processing types
179 5 const Fw::DpCfg::ProcType::SerialType procTypes = container.getProcTypes();
180 // Do the processing
181 5 bool did_process = false;
182
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (FwIndexType portNum = 0; portNum < NUM_PROCBUFFERSENDOUT_OUTPUT_PORTS; ++portNum) {
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if ((procTypes & (1 << portNum)) != 0) {
184 ✗ this->procBufferSendOut_out(portNum, buffer);
185 ✗ did_process = true;
186 }
187 }
188
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (did_process) {
190 // Updated DpContainer object state with the returned value in the
191 // container buffer
192 ✗ Fw::SerializeStatus stat = container.deserializeHeader();
193 ✗ FW_ASSERT(stat == Fw::FW_SERIALIZE_OK, stat);
194
195 // Check that the buffer size is compatible with the packet size in
196 // the container header
197 ✗ FW_ASSERT(container.getPacketSize() <= buffer.getSize(),
198 static_cast<FwAssertArgType>(container.getPacketSize()),
199 static_cast<FwAssertArgType>(buffer.getSize()));
200
201 // Re-compute and serialize the container header into the buffer
202 ✗ container.updateHeaderHash();
203 ✗ container.serializeHeader();
204
205 // Shrink internal Fw::Buffer
206 ✗ container.shrinkBufferSize();
207 }
208 5 }
209
210 5 Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container,
211 const Fw::FileNameString& fileName,
212 FwSizeType& fileSize) {
213 5 Fw::Success::T status = Fw::Success::SUCCESS;
214 // Get the buffer
215
1/1
✓ Branch 1 taken 5 times.
5 Fw::Buffer buffer = container.getBuffer();
216 // Get the file size
217
1/1
✓ Branch 1 taken 5 times.
5 fileSize = container.getPacketSize();
218 // Open the file
219
1/1
✓ Branch 1 taken 5 times.
5 Os::File file;
220
1/1
✓ Branch 2 taken 5 times.
5 Os::File::Status fileStatus = file.open(fileName.toChar(), Os::File::OPEN_CREATE);
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (fileStatus != Os::File::OP_OK) {
222 ✗ this->log_WARNING_HI_FileOpenError(static_cast<U32>(fileStatus), fileName);
223 ✗ status = Fw::Success::FAILURE;
224 }
225 // Write the file
226
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
227 // Set write size to file size
228 // On entry to the write call, this is the number of bytes to write
229 // On return from the write call, this is the number of bytes written
230 5 FwSizeType writeSize = static_cast<FwSizeType>(fileSize);
231
2/2
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
5 fileStatus = file.write(buffer.getData(), writeSize);
232 // If a successful write occurred, then update the number of bytes written
233
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (fileStatus == Os::File::OP_OK) {
234 5 this->m_numBytesWritten += static_cast<U64>(writeSize);
235 }
236
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if ((fileStatus == Os::File::OP_OK) and (writeSize == static_cast<FwSizeType>(fileSize))) {
237 // If the write status is success, and the number of bytes written
238 // is the expected number, then record the success
239
1/1
✓ Branch 1 taken 5 times.
5 this->log_ACTIVITY_LO_FileWritten(static_cast<U32>(writeSize), fileName);
240 } else {
241 // Otherwise record the failure
242 ✗ this->log_WARNING_HI_FileWriteError(static_cast<U32>(fileStatus), static_cast<U32>(writeSize),
243 ✗ static_cast<U32>(fileSize), fileName);
244 ✗ status = Fw::Success::FAILURE;
245 }
246 }
247 // Update the count of successful or failed writes
248
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (status == Fw::Success::SUCCESS) {
249 5 this->m_numSuccessfulWrites++;
250 } else {
251 ✗ this->m_numFailedWrites++;
252 }
253 // Return the status
254 5 return status;
255 5 }
256
257 5 void DpWriter::sendNotification(FwIndexType portNum,
258 const Fw::DpContainer& container,
259 const Fw::FileNameString& fileName,
260 FwSizeType fileSize) {
261
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (isConnected_dpWrittenOut_OutputPort(portNum)) {
262 // Get the priority
263 5 const FwDpPriorityType priority = container.getPriority();
264 5 this->dpWrittenOut_out(portNum, fileName, priority, fileSize);
265 }
266 5 }
267
268 } // end namespace Svc
269