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