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