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