| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | |||
| 3 | // \title DpCatalog.cpp | ||
| 4 | // \author tcanham | ||
| 5 | // \brief cpp file for DpCatalog component implementation class | ||
| 6 | // ====================================================================== | ||
| 7 | |||
| 8 | #include "Svc/DpCatalog/DpCatalog.hpp" | ||
| 9 | #include "Fw/Dp/DpContainer.hpp" | ||
| 10 | #include "Fw/FPrimeBasicTypes.hpp" | ||
| 11 | |||
| 12 | #include <new> // placement new | ||
| 13 | #include "Fw/Types/StringUtils.hpp" | ||
| 14 | #include "Os/File.hpp" | ||
| 15 | #include "Os/FileSystem.hpp" | ||
| 16 | #include "Utils/Hash/Hash.hpp" | ||
| 17 | |||
| 18 | namespace Svc { | ||
| 19 | static_assert(DP_MAX_DIRECTORIES > 0, "Configuration DP_MAX_DIRECTORIES must be positive"); | ||
| 20 | static_assert(DP_MAX_FILES > 0, "Configuration DP_MAX_FILES must be positive"); | ||
| 21 | // ---------------------------------------------------------------------- | ||
| 22 | // Component construction and destruction | ||
| 23 | // ---------------------------------------------------------------------- | ||
| 24 | |||
| 25 |
7/13✓ Branch 15 taken 526 times.
✓ Branch 21 taken 526 times.
✓ Branch 35 taken 1052 times.
✓ Branch 38 taken 1052 times.
✓ Branch 39 taken 526 times.
✓ Branch 49 taken 526 times.
✓ Branch 87 taken 526 times.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 131 not taken.
✗ Branch 132 not taken.
|
1578 | DpCatalog ::DpCatalog(const char* const compName) : DpCatalogComponentBase(compName) { |
| 26 | // Members are default-initialized via in-class initializers in the header. | ||
| 27 | 526 | } | |
| 28 | |||
| 29 | 618 | void DpCatalog::configure(const Fw::ExternalArray<Fw::FileNameString>& directories, | |
| 30 | Fw::FileNameString& stateFile, | ||
| 31 | FwEnumStoreType memId, | ||
| 32 | Fw::MemAllocator& allocator) { | ||
| 33 | 618 | const FwSizeType numDirs = directories.getSize(); | |
| 34 | // Do some assertion checks | ||
| 35 | 618 | FW_ASSERT(numDirs <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(numDirs)); | |
| 36 | |||
| 37 |
1/1✓ Branch 7 taken 618 times.
|
618 | this->m_stateFile = stateFile; |
| 38 | |||
| 39 | // Request memory for state file data storage. | ||
| 40 | // RedBlackTreeSet storage is allocated as a member variable, so we only need | ||
| 41 | // to allocate memory for the state file tracking array. | ||
| 42 | static const FwSizeType slotSize = sizeof(DpDstateFileEntry); | ||
| 43 | 618 | this->m_memSize = DP_MAX_FILES * slotSize; | |
| 44 | 618 | bool notUsed; // we don't need to recover the catalog. | |
| 45 | // request memory. this->m_memSize will be modified if there is less than we requested | ||
| 46 |
1/1✓ Branch 11 taken 618 times.
|
618 | this->m_memPtr = allocator.allocate(memId, this->m_memSize, notUsed); |
| 47 | |||
| 48 | // Initialize if there is enough room for at least one record and memory was allocated | ||
| 49 |
2/4✓ Branch 4 taken 618 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 618 times.
✗ Branch 11 not taken.
|
618 | if ((this->m_memSize >= slotSize) and (this->m_memPtr != nullptr)) { |
| 50 | // set the number of available record slots based on how much memory we actually got, | ||
| 51 | // never exceeding the DP_MAX_FILES working arrays even if the allocator returned more | ||
| 52 | // memory than was requested | ||
| 53 | 618 | const FwSizeType allocatedSlots = this->m_memSize / slotSize; | |
| 54 | 618 | this->m_numDpSlots = (allocatedSlots < DP_MAX_FILES) ? allocatedSlots : DP_MAX_FILES; | |
| 55 | // Initialize the catalog | ||
| 56 |
1/1✓ Branch 4 taken 618 times.
|
618 | this->resetCatalog(); |
| 57 | // assign pointer for the state file storage | ||
| 58 | 618 | this->m_stateFileData = static_cast<DpDstateFileEntry*>(this->m_memPtr); | |
| 59 | 618 | } else { | |
| 60 | // if we don't have enough memory, set the number of records | ||
| 61 | // to zero for later detection | ||
| 62 | ✗ | this->m_numDpSlots = 0; | |
| 63 | } | ||
| 64 | |||
| 65 | // assign directory names | ||
| 66 |
2/2✓ Branch 0 taken 721 times.
✓ Branch 1 taken 618 times.
|
1339 | for (FwSizeType dir = 0; dir < numDirs; dir++) { |
| 67 |
2/2✓ Branch 2 taken 721 times.
✓ Branch 11 taken 721 times.
|
721 | this->m_directories[dir] = directories[dir]; |
| 68 | } | ||
| 69 | 618 | this->m_numDirectories = numDirs; | |
| 70 | |||
| 71 | // store allocator | ||
| 72 | 618 | this->m_allocator = &allocator; | |
| 73 | 618 | this->m_allocatorId = memId; | |
| 74 | 618 | this->m_initialized = true; | |
| 75 | 618 | } | |
| 76 | |||
| 77 | ✗ | void DpCatalog::configure(Fw::FileNameString directories[DP_MAX_DIRECTORIES], | |
| 78 | FwSizeType numDirs, | ||
| 79 | Fw::FileNameString& stateFile, | ||
| 80 | FwEnumStoreType memId, | ||
| 81 | Fw::MemAllocator& allocator) { | ||
| 82 | ✗ | FW_ASSERT(numDirs <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(numDirs)); | |
| 83 | ✗ | const Fw::ExternalArray<Fw::FileNameString> directoryArray(directories, numDirs); | |
| 84 | ✗ | this->configure(directoryArray, stateFile, memId, allocator); | |
| 85 | ✗ | } | |
| 86 | |||
| 87 | 1235 | void DpCatalog::resetCatalog() { | |
| 88 | // Clear the catalog | ||
| 89 | 1235 | this->m_dpCatalog.clear(); | |
| 90 | // Clear transmission state | ||
| 91 | 1235 | this->m_hasCurrentXmit = false; | |
| 92 | // Reset counters | ||
| 93 | 1235 | this->m_pendingFiles = 0; | |
| 94 | 1235 | this->m_pendingDpBytes = 0; | |
| 95 | // Mark the catalog as un-built | ||
| 96 | 1235 | this->m_catalogBuilt = false; | |
| 97 | 1235 | } | |
| 98 | |||
| 99 | 115 | void DpCatalog::resetStateFileData() { | |
| 100 | // clear state file data | ||
| 101 |
2/2✓ Branch 4 taken 14605 times.
✓ Branch 5 taken 115 times.
|
14720 | for (FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) { |
| 102 | 14605 | this->m_stateFileData[slot].used = false; | |
| 103 | 14605 | this->m_stateFileData[slot].visited = false; | |
| 104 |
1/3✓ Branch 9 taken 14605 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
14605 | (void)new (&this->m_stateFileData[slot].entry.record) DpRecord(); |
| 105 | } | ||
| 106 | 115 | this->m_stateFileEntries = 0; | |
| 107 | 115 | } | |
| 108 | |||
| 109 | 112 | Fw::CmdResponse DpCatalog::loadStateFile() { | |
| 110 | 112 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 111 | |||
| 112 | // Make sure that a file was specified | ||
| 113 |
3/3✓ Branch 6 taken 112 times.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 107 times.
|
112 | if (this->m_stateFile.length() == 0) { |
| 114 |
1/1✓ Branch 5 taken 5 times.
|
5 | this->log_WARNING_LO_NoStateFileSpecified(); |
| 115 |
1/1✓ Branch 1 taken 5 times.
|
5 | return Fw::CmdResponse::OK; |
| 116 | } | ||
| 117 | |||
| 118 | // buffer for reading entries | ||
| 119 | |||
| 120 | 107 | BYTE buffer[sizeof(FwIndexType) + DpRecord::SERIALIZED_SIZE]; | |
| 121 |
1/1✓ Branch 2 taken 107 times.
|
107 | Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer)); |
| 122 | |||
| 123 | // open the state file | ||
| 124 |
1/1✓ Branch 2 taken 107 times.
|
107 | Os::File stateFile; |
| 125 |
1/1✓ Branch 8 taken 107 times.
|
107 | Os::File::Status stat = stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_READ); |
| 126 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 1 times.
|
107 | if (stat == Os::File::DOESNT_EXIST) { |
| 127 | // A missing state file is expected on first boot and is not an error | ||
| 128 |
1/1✓ Branch 8 taken 106 times.
|
106 | this->log_WARNING_LO_NoStateFile(this->m_stateFile); |
| 129 |
1/1✓ Branch 1 taken 106 times.
|
106 | return Fw::CmdResponse::OK; |
| 130 | } | ||
| 131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (stat != Os::File::OP_OK) { |
| 132 | ✗ | this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat); | |
| 133 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 134 | } | ||
| 135 | |||
| 136 | 1 | FwSizeType fileLoc = 0; | |
| 137 | 1 | this->m_stateFileEntries = 0; | |
| 138 | |||
| 139 | // read entries from the state file | ||
| 140 |
1/2✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | for (FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) { |
| 141 | 1 | FwSizeType size = static_cast<FwSizeType>(sizeof(buffer)); | |
| 142 | // read the directory index | ||
| 143 |
1/1✓ Branch 2 taken 1 times.
|
1 | stat = stateFile.read(buffer, size); |
| 144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (stat != Os::File::OP_OK) { |
| 145 | ✗ | this->log_WARNING_HI_StateFileReadError(this->m_stateFile, stat, static_cast<I32>(fileLoc)); | |
| 146 | ✗ | stateFile.close(); | |
| 147 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 148 | } | ||
| 149 | |||
| 150 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (0 == size) { |
| 151 | // no more entries | ||
| 152 | ✗ | break; | |
| 153 | } | ||
| 154 | |||
| 155 | // check to see if the full entry was read. If not, | ||
| 156 | // abandon it and finish. We can at least operate on | ||
| 157 | // the entries that were read. | ||
| 158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size != sizeof(buffer)) { |
| 159 | ✗ | this->log_WARNING_HI_StateFileTruncated(this->m_stateFile, static_cast<I32>(fileLoc), | |
| 160 | static_cast<I32>(size)); | ||
| 161 | ✗ | stateFile.close(); | |
| 162 | ✗ | return Fw::CmdResponse::OK; | |
| 163 | } | ||
| 164 | |||
| 165 | // reset the buffer for deserializing the entry | ||
| 166 |
1/1✓ Branch 2 taken 1 times.
|
1 | Fw::SerializeStatus serStat = entryBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(size)); |
| 167 | // should always fit | ||
| 168 | 1 | FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, serStat); | |
| 169 |
1/1✓ Branch 2 taken 1 times.
|
1 | entryBuffer.resetDeser(); |
| 170 | |||
| 171 | // deserialization after this point should always work, since | ||
| 172 | // the source buffer was specifically sized to hold the data | ||
| 173 | |||
| 174 | // Deserialize the file directory index. If an error occurs processing the file, | ||
| 175 | // generate event and return EXECUTION_ERROR. | ||
| 176 |
1/1✓ Branch 10 taken 1 times.
|
1 | Fw::SerializeStatus status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.dir); |
| 177 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (status != Fw::FW_SERIALIZE_OK) { |
| 178 | ✗ | this->log_WARNING_HI_FileCorruptedDataError(this->m_stateFile, static_cast<I32>(status)); | |
| 179 | ✗ | stateFile.close(); | |
| 180 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 181 | } | ||
| 182 |
1/1✓ Branch 10 taken 1 times.
|
1 | status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.record); |
| 183 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (status != Fw::FW_SERIALIZE_OK) { |
| 184 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_FileCorruptedDataError(this->m_stateFile, static_cast<I32>(status)); |
| 185 |
1/1✓ Branch 2 taken 1 times.
|
1 | stateFile.close(); |
| 186 |
1/1✓ Branch 1 taken 1 times.
|
1 | return Fw::CmdResponse::EXECUTION_ERROR; |
| 187 | } | ||
| 188 | ✗ | this->m_stateFileData[entry].used = true; | |
| 189 | ✗ | this->m_stateFileData[entry].visited = false; | |
| 190 | |||
| 191 | // increment the file location | ||
| 192 | ✗ | fileLoc += size; | |
| 193 | ✗ | this->m_stateFileEntries++; | |
| 194 | } | ||
| 195 | ✗ | stateFile.close(); | |
| 196 | ✗ | return Fw::CmdResponse::OK; | |
| 197 | 107 | } | |
| 198 | |||
| 199 | 6020 | void DpCatalog::getFileState(DpStateEntry& entry) { | |
| 200 | 6020 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 201 | // search the file state data for the entry | ||
| 202 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 6020 times.
|
6020 | for (FwSizeType line = 0; line < this->m_stateFileEntries; line++) { |
| 203 | // check for a match (compare dir, then id, priority, & time) | ||
| 204 | ✗ | if (this->m_stateFileData[line].entry.dir == entry.dir && this->m_stateFileData[line].entry == entry) { | |
| 205 | // update the transmitted state | ||
| 206 | ✗ | entry.record.set_state(this->m_stateFileData[line].entry.record.get_state()); | |
| 207 | ✗ | entry.record.set_blocks(this->m_stateFileData[line].entry.record.get_blocks()); | |
| 208 | // mark it as visited for later pruning if necessary | ||
| 209 | ✗ | this->m_stateFileData[line].visited = true; | |
| 210 | ✗ | return; | |
| 211 | } | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | 3098 | void DpCatalog::pruneAndWriteStateFile() { | |
| 216 | 3098 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 217 | |||
| 218 | // There is a chance that a data product file can disappear after | ||
| 219 | // the state file is written from the last catalog build and transmit. | ||
| 220 | // This function will walk the state file data and write back only | ||
| 221 | // the entries that were visited during the last catalog build. This will | ||
| 222 | // remove any entries that are no longer valid. | ||
| 223 | |||
| 224 | // open the state file | ||
| 225 |
1/1✓ Branch 2 taken 3098 times.
|
3098 | Os::File stateFile; |
| 226 | // we open it as a new file so we don't accumulate invalid entries | ||
| 227 | Os::File::Status stat = | ||
| 228 |
1/1✓ Branch 8 taken 3098 times.
|
3098 | stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_CREATE, Os::FileInterface::OVERWRITE); |
| 229 | |||
| 230 |
1/2✓ Branch 0 taken 3098 times.
✗ Branch 1 not taken.
|
3098 | if (stat != Os::File::OP_OK) { |
| 231 |
1/1✓ Branch 8 taken 3098 times.
|
3098 | this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat); |
| 232 | 3098 | return; | |
| 233 | } | ||
| 234 | |||
| 235 | // buffer for writing entries | ||
| 236 | ✗ | BYTE buffer[sizeof(FwIndexType) + DpRecord::SERIALIZED_SIZE]; | |
| 237 | ✗ | Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer)); | |
| 238 | |||
| 239 | // write entries to the state file | ||
| 240 | ✗ | for (FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) { | |
| 241 | // only write entries that were used | ||
| 242 | ✗ | if ((this->m_stateFileData[entry].used) and (this->m_stateFileData[entry].visited)) { | |
| 243 | // reset the buffer for serializing the entry | ||
| 244 | ✗ | entryBuffer.resetSer(); | |
| 245 | // serialize the file directory index | ||
| 246 | ✗ | Fw::SerializeStatus serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.dir); | |
| 247 | // Should always fit | ||
| 248 | ✗ | FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, serStat); | |
| 249 | ✗ | serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.record); | |
| 250 | // Should always fit | ||
| 251 | ✗ | FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, serStat); | |
| 252 | // write the entry | ||
| 253 | ✗ | FwSizeType size = entryBuffer.getSize(); | |
| 254 | // Protect against overflow | ||
| 255 | ✗ | stat = stateFile.write(buffer, size); | |
| 256 | ✗ | if (stat != Os::File::OP_OK) { | |
| 257 | ✗ | this->log_WARNING_HI_StateFileWriteError(this->m_stateFile, stat); | |
| 258 | ✗ | stateFile.close(); | |
| 259 | ✗ | return; | |
| 260 | } | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | // close the state file | ||
| 265 | ✗ | stateFile.close(); | |
| 266 | 3098 | } | |
| 267 | |||
| 268 | 5886 | void DpCatalog::appendFileState(const DpStateEntry& entry) { | |
| 269 | 5886 | FW_ASSERT(this->m_stateFileData != nullptr); | |
| 270 | 5886 | FW_ASSERT(entry.dir < static_cast<FwIndexType>(this->m_numDirectories), static_cast<FwAssertArgType>(entry.dir), | |
| 271 | static_cast<FwAssertArgType>(this->m_numDirectories)); | ||
| 272 | |||
| 273 | // We will append state to the existing state file | ||
| 274 | // TODO: Have to handle case where state file has partially transmitted | ||
| 275 | // state already | ||
| 276 | |||
| 277 | // open the state file | ||
| 278 |
1/1✓ Branch 2 taken 5886 times.
|
5886 | Os::File stateFile; |
| 279 | // we open it as a new file so we don't accumulate invalid entries | ||
| 280 |
1/1✓ Branch 8 taken 5886 times.
|
5886 | Os::File::Status stat = stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_APPEND); |
| 281 |
1/2✓ Branch 0 taken 5886 times.
✗ Branch 1 not taken.
|
5886 | if (stat != Os::File::OP_OK) { |
| 282 |
1/1✓ Branch 8 taken 5886 times.
|
5886 | this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat); |
| 283 | 5886 | return; | |
| 284 | } | ||
| 285 | |||
| 286 | // buffer for writing entries | ||
| 287 | ✗ | BYTE buffer[sizeof(FwIndexType) + DpRecord::SERIALIZED_SIZE]; | |
| 288 | ✗ | Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer)); | |
| 289 | // reset the buffer for serializing the entry | ||
| 290 | ✗ | entryBuffer.resetSer(); | |
| 291 | // serialize the file directory index | ||
| 292 | ✗ | Fw::SerializeStatus serStat = entryBuffer.serializeFrom(entry.dir); | |
| 293 | // should fit | ||
| 294 | ✗ | FW_ASSERT(serStat == Fw::FW_SERIALIZE_OK, serStat); | |
| 295 | ✗ | serStat = entryBuffer.serializeFrom(entry.record); | |
| 296 | // should fit | ||
| 297 | ✗ | FW_ASSERT(serStat == Fw::FW_SERIALIZE_OK, serStat); | |
| 298 | // write the entry | ||
| 299 | ✗ | FwSizeType size = entryBuffer.getSize(); | |
| 300 | ✗ | stat = stateFile.write(buffer, size); | |
| 301 | ✗ | if (stat != Os::File::OP_OK) { | |
| 302 | ✗ | stateFile.close(); | |
| 303 | ✗ | this->log_WARNING_HI_StateFileWriteError(this->m_stateFile, stat); | |
| 304 | ✗ | return; | |
| 305 | } | ||
| 306 | |||
| 307 | // close the state file | ||
| 308 | ✗ | stateFile.close(); | |
| 309 | 5886 | } | |
| 310 | |||
| 311 | 112 | Fw::CmdResponse DpCatalog::doCatalogBuild() { | |
| 312 | // check initialization | ||
| 313 |
2/3✓ Branch 4 taken 112 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 112 times.
|
112 | if (not this->checkInit()) { |
| 314 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 315 | } | ||
| 316 | |||
| 317 | // check that initialization got memory | ||
| 318 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
|
112 | if (0 == this->m_numDpSlots) { |
| 319 | ✗ | this->log_WARNING_HI_NoDpMemory(); | |
| 320 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 321 | } | ||
| 322 | |||
| 323 | // make sure a downlink is not in progress | ||
| 324 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112 times.
|
112 | if (this->m_xmitInProgress) { |
| 325 | ✗ | this->log_WARNING_LO_DpXmitInProgress(); | |
| 326 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 327 | } | ||
| 328 | |||
| 329 | // reset state file data | ||
| 330 |
1/1✓ Branch 4 taken 112 times.
|
112 | this->resetStateFileData(); |
| 331 | |||
| 332 | // load state data from file; proceeding on a failed load would later | ||
| 333 | // overwrite the state file and destroy the transmit state it records | ||
| 334 |
1/1✓ Branch 2 taken 112 times.
|
112 | Fw::CmdResponse response = this->loadStateFile(); |
| 335 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 111 times.
|
112 | if (response != Fw::CmdResponse::OK) { |
| 336 |
1/1✓ Branch 4 taken 1 times.
|
1 | this->resetStateFileData(); |
| 337 |
1/1✓ Branch 1 taken 1 times.
|
1 | return response; |
| 338 | } | ||
| 339 | |||
| 340 | // reset catalog | ||
| 341 |
1/1✓ Branch 4 taken 111 times.
|
111 | this->resetCatalog(); |
| 342 | |||
| 343 | // fill the catalog with DP files | ||
| 344 |
2/2✓ Branch 2 taken 111 times.
✓ Branch 7 taken 111 times.
|
111 | response = this->fillBinaryTree(); |
| 345 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 111 times.
|
111 | if (response != Fw::CmdResponse::OK) { |
| 346 | // clean up the catalog | ||
| 347 | ✗ | this->resetCatalog(); | |
| 348 | ✗ | this->resetStateFileData(); | |
| 349 | ✗ | return response; | |
| 350 | } | ||
| 351 | |||
| 352 | // prune and rewrite the state file | ||
| 353 |
1/1✓ Branch 4 taken 111 times.
|
111 | this->pruneAndWriteStateFile(); |
| 354 | |||
| 355 |
1/1✓ Branch 5 taken 111 times.
|
111 | this->log_ACTIVITY_HI_CatalogBuildComplete(); |
| 356 | |||
| 357 | // Flag so addToCat knows it is good to go | ||
| 358 | 111 | this->m_catalogBuilt = true; | |
| 359 | |||
| 360 |
1/1✓ Branch 1 taken 111 times.
|
111 | return Fw::CmdResponse::OK; |
| 361 | 112 | } | |
| 362 | |||
| 363 | 111 | Fw::CmdResponse DpCatalog::fillBinaryTree() { | |
| 364 | // keep cumulative number of files | ||
| 365 | 111 | FwSizeType totalFiles = 0; | |
| 366 | |||
| 367 | // get file listings from file system | ||
| 368 | // double bounds to appease static analysis | ||
| 369 |
3/4✓ Branch 4 taken 214 times.
✓ Branch 5 taken 110 times.
✓ Branch 6 taken 214 times.
✗ Branch 7 not taken.
|
324 | for (FwSizeType dir = 0; dir < this->m_numDirectories && dir < static_cast<FwSizeType>(DP_MAX_DIRECTORIES); dir++) { |
| 370 | // read in each directory and keep track of total | ||
| 371 |
1/1✓ Branch 9 taken 214 times.
|
214 | this->log_ACTIVITY_LO_ProcessingDirectory(this->m_directories[dir]); |
| 372 | 214 | FwSizeType filesProcessed = 0; | |
| 373 | |||
| 374 |
1/1✓ Branch 2 taken 214 times.
|
214 | Os::Directory dpDir; |
| 375 |
1/1✓ Branch 9 taken 214 times.
|
214 | Os::Directory::Status status = dpDir.open(this->m_directories[dir].toChar(), Os::Directory::OpenMode::READ); |
| 376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
|
214 | if (status != Os::Directory::OP_OK) { |
| 377 | ✗ | this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status); | |
| 378 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 379 | } | ||
| 380 | |||
| 381 | // bound the read loop by the number of entries in the directory | ||
| 382 | 214 | FwSizeType fileCount = 0; | |
| 383 |
1/1✓ Branch 2 taken 214 times.
|
214 | status = dpDir.getFileCount(fileCount); |
| 384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
|
214 | if (status != Os::Directory::OP_OK) { |
| 385 | ✗ | this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status); | |
| 386 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 387 | } | ||
| 388 | |||
| 389 | // read entries one at a time so non-DP files do not consume catalog slots | ||
| 390 |
1/1✓ Branch 2 taken 214 times.
|
214 | Fw::String fileName; |
| 391 |
2/2✓ Branch 0 taken 3163 times.
✓ Branch 1 taken 214 times.
|
3377 | for (FwSizeType entry = 0; entry < fileCount; entry++) { |
| 392 |
1/1✓ Branch 2 taken 3163 times.
|
3163 | status = dpDir.read(fileName); |
| 393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3163 times.
|
3163 | if (status == Os::Directory::NO_MORE_FILES) { |
| 394 | ✗ | break; | |
| 395 | } | ||
| 396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3163 times.
|
3163 | if (status != Os::Directory::OP_OK) { |
| 397 | ✗ | this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status); | |
| 398 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 399 | } | ||
| 400 | |||
| 401 | // only consider files with the DP extension | ||
| 402 |
1/1✓ Branch 2 taken 3163 times.
|
3163 | const FwSizeType fileNameLength = fileName.length(); |
| 403 |
1/1✓ Branch 1 taken 3163 times.
|
3163 | const FwSizeType dpExtLength = Fw::StringUtils::string_length(DP_EXT, sizeof(DP_EXT)); |
| 404 | const FwSignedSizeType loc = | ||
| 405 |
1/1✓ Branch 3 taken 3163 times.
|
3163 | Fw::StringUtils::substring_find_last(fileName.toChar(), fileNameLength, DP_EXT, dpExtLength); |
| 406 | |||
| 407 | // Only accept files whose final suffix is the data product extension | ||
| 408 |
3/4✓ Branch 0 taken 3036 times.
✓ Branch 1 taken 127 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3036 times.
|
3163 | if ((-1 == loc) || (static_cast<FwSizeType>(loc) + dpExtLength != fileNameLength)) { |
| 409 | 127 | continue; | |
| 410 | } | ||
| 411 | |||
| 412 | // stop if there is no free catalog slot for this DP file | ||
| 413 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 3036 times.
|
3036 | if ((totalFiles + filesProcessed) == this->m_numDpSlots) { |
| 414 | ✗ | break; | |
| 415 | } | ||
| 416 | |||
| 417 |
1/1✓ Branch 2 taken 3036 times.
|
3036 | Fw::String fullFile; |
| 418 | Fw::FormatStatus formatStatus = | ||
| 419 |
1/1✓ Branch 11 taken 3036 times.
|
3036 | fullFile.format("%s/%s", this->m_directories[dir].toChar(), fileName.toChar()); |
| 420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3036 times.
|
3036 | if (formatStatus != Fw::FormatStatus::SUCCESS) { |
| 421 | ✗ | this->log_WARNING_HI_FileNameFormatError(fileName, | |
| 422 | static_cast<Fw::StringFormatStatus::T>(formatStatus)); | ||
| 423 | ✗ | continue; | |
| 424 | } | ||
| 425 | |||
| 426 |
1/1✓ Branch 4 taken 3036 times.
|
3036 | const ProcessFileStatus ret = processFile(fullFile, dir); |
| 427 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3036 times.
|
3036 | if (ret == ProcessFileStatus::QUIT) { |
| 428 | ✗ | break; | |
| 429 | } | ||
| 430 | |||
| 431 |
2/2✓ Branch 0 taken 3033 times.
✓ Branch 1 taken 3 times.
|
3036 | if (ret == ProcessFileStatus::SUCCESS) { |
| 432 | 3033 | filesProcessed++; | |
| 433 | } | ||
| 434 | |||
| 435 | 3036 | } // end for each file in a directory | |
| 436 | |||
| 437 | 214 | totalFiles += filesProcessed; | |
| 438 | |||
| 439 |
1/1✓ Branch 13 taken 214 times.
|
642 | this->log_ACTIVITY_HI_ProcessingDirectoryComplete(this->m_directories[dir], static_cast<U32>(totalFiles), |
| 440 | 428 | this->m_pendingFiles, this->m_pendingDpBytes); | |
| 441 | |||
| 442 | // check to see if catalog is full | ||
| 443 | // that means generated products exceed the catalog size | ||
| 444 |
2/2✓ Branch 4 taken 1 times.
✓ Branch 5 taken 213 times.
|
214 | if (totalFiles == this->m_numDpSlots) { |
| 445 |
1/1✓ Branch 9 taken 1 times.
|
1 | this->log_WARNING_HI_CatalogFull(this->m_directories[dir]); |
| 446 | 1 | break; | |
| 447 | } | ||
| 448 | 215 | } // end for each directory | |
| 449 | |||
| 450 | 111 | return Fw::CmdResponse::OK; | |
| 451 | |||
| 452 | } // end fillBinaryTree() | ||
| 453 | |||
| 454 | 2987 | FwSizeType DpCatalog::determineDirectory(const Fw::String& fullFile) { | |
| 455 | 2987 | FW_ASSERT(this->m_numDirectories <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(this->m_numDirectories)); | |
| 456 | // Grab the directory string (up until the final slash) | ||
| 457 | // Could be found directly w/ a dirname func or regex | ||
| 458 | 8961 | FwSignedSizeType loc = Fw::StringUtils::substring_find_last( | |
| 459 | 5974 | fullFile.toChar(), fullFile.length(), DIRECTORY_DELIMITER, | |
| 460 | Fw::StringUtils::string_length(DIRECTORY_DELIMITER, sizeof(DIRECTORY_DELIMITER))); | ||
| 461 | |||
| 462 | // Seems like the logic works so long as the path styles match (i.e. relative vs absolute) | ||
| 463 | // Full path resolution might be a worthwhile add | ||
| 464 | |||
| 465 | // No directory delimiter found; return DP_MAX_DIRECTORIES to signal failure | ||
| 466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2987 times.
|
2987 | if (-1 == loc) { |
| 467 | ✗ | return DP_MAX_DIRECTORIES; | |
| 468 | } | ||
| 469 | |||
| 470 |
1/2✓ Branch 4 taken 4470 times.
✗ Branch 5 not taken.
|
4470 | for (FwSizeType dir = 0; dir < this->m_numDirectories; dir++) { |
| 471 | 4470 | const Fw::FileNameString& dir_string = this->m_directories[dir]; | |
| 472 | |||
| 473 | // Compare both strings up to location of final slash | ||
| 474 | // StringUtils::substring_find will return zero if both paths agree | ||
| 475 | // memory safe since both are fixed width strings | ||
| 476 | // and loc is before the fixed width | ||
| 477 |
3/4✓ Branch 7 taken 4470 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2987 times.
✓ Branch 10 taken 1483 times.
|
8940 | if ((dir_string.length() == static_cast<FwSizeType>(loc)) && |
| 478 |
2/2✓ Branch 16 taken 2987 times.
✓ Branch 17 taken 1483 times.
|
4470 | (Fw::StringUtils::substring_find(dir_string.toChar(), dir_string.length(), fullFile.toChar(), |
| 479 | static_cast<FwSizeType>(loc)) == 0)) { | ||
| 480 | 2987 | return dir; | |
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | // No directory matched | ||
| 485 | ✗ | return DP_MAX_DIRECTORIES; | |
| 486 | } | ||
| 487 | |||
| 488 | 6023 | DpCatalog::ProcessFileStatus DpCatalog::processFile(const Fw::String& fullFile, FwSizeType dir) { | |
| 489 | 6023 | FW_ASSERT(dir < static_cast<FwSizeType>(DP_MAX_DIRECTORIES), static_cast<FwAssertArgType>(dir)); | |
| 490 | // file class instance for processing files | ||
| 491 |
1/1✓ Branch 2 taken 6023 times.
|
6023 | Os::File dpFile; |
| 492 | |||
| 493 | // Working buffer for DP headers | ||
| 494 | 6023 | U8 dpBuff[Fw::DpContainer::MIN_PACKET_SIZE]; // Header buffer | |
| 495 |
1/1✓ Branch 2 taken 6023 times.
|
6023 | Fw::Buffer hdrBuff(dpBuff, sizeof(dpBuff)); // buffer for container header decoding |
| 496 |
1/1✓ Branch 2 taken 6023 times.
|
6023 | Fw::DpContainer container; // container object for extracting header fields |
| 497 | |||
| 498 |
1/1✓ Branch 8 taken 6023 times.
|
6023 | this->log_ACTIVITY_LO_ProcessingFile(fullFile); |
| 499 | |||
| 500 | // get file size | ||
| 501 | 6023 | FwSizeType fileSize = 0; | |
| 502 |
1/1✓ Branch 5 taken 6023 times.
|
6023 | Os::FileSystem::Status sizeStat = Os::FileSystem::getFileSize(fullFile.toChar(), fileSize); |
| 503 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6023 times.
|
6023 | if (sizeStat != Os::FileSystem::OP_OK) { |
| 504 | ✗ | this->log_WARNING_HI_FileSizeError(fullFile, sizeStat); | |
| 505 | ✗ | return ProcessFileStatus::FAILED; | |
| 506 | } | ||
| 507 | |||
| 508 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6022 times.
|
6023 | if (fileSize < Fw::DpContainer::MIN_PACKET_SIZE) { |
| 509 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_FileReadError(fullFile, Os::File::BAD_SIZE); |
| 510 | 1 | return ProcessFileStatus::FAILED; | |
| 511 | } | ||
| 512 | |||
| 513 |
1/1✓ Branch 6 taken 6022 times.
|
6022 | Os::File::Status stat = dpFile.open(fullFile.toChar(), Os::File::OPEN_READ); |
| 514 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6022 times.
|
6022 | if (stat != Os::File::OP_OK) { |
| 515 | ✗ | this->log_WARNING_HI_FileOpenError(fullFile, stat); | |
| 516 | ✗ | return ProcessFileStatus::FAILED; | |
| 517 | } | ||
| 518 | |||
| 519 | // Read DP header and header hash | ||
| 520 | 6022 | FwSizeType size = Fw::DpContainer::MIN_PACKET_SIZE; | |
| 521 | |||
| 522 |
1/1✓ Branch 2 taken 6022 times.
|
6022 | stat = dpFile.read(dpBuff, size); |
| 523 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6022 times.
|
6022 | if (stat != Os::File::OP_OK) { |
| 524 | ✗ | this->log_WARNING_HI_FileReadError(fullFile, stat); | |
| 525 | ✗ | dpFile.close(); | |
| 526 | ✗ | return ProcessFileStatus::FAILED; | |
| 527 | } | ||
| 528 | |||
| 529 | // if full header and hashes aren't read, something's wrong with the file, so skip | ||
| 530 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6022 times.
|
6022 | if (size != Fw::DpContainer::MIN_PACKET_SIZE) { |
| 531 | ✗ | this->log_WARNING_HI_FileReadError(fullFile, Os::File::BAD_SIZE); | |
| 532 | ✗ | dpFile.close(); | |
| 533 | ✗ | return ProcessFileStatus::FAILED; | |
| 534 | } | ||
| 535 | |||
| 536 | // if all is well, don't need the file any more | ||
| 537 |
1/1✓ Branch 2 taken 6022 times.
|
6022 | dpFile.close(); |
| 538 | |||
| 539 | // give buffer to container instance | ||
| 540 |
1/1✓ Branch 2 taken 6022 times.
|
6022 | container.setBuffer(hdrBuff); |
| 541 | |||
| 542 | // make sure the header metadata matches its stored hash before trusting it | ||
| 543 |
1/1✓ Branch 2 taken 6022 times.
|
6022 | Utils::HashBuffer storedHash; |
| 544 |
1/1✓ Branch 2 taken 6022 times.
|
6022 | Utils::HashBuffer computedHash; |
| 545 |
1/1✓ Branch 2 taken 6022 times.
|
6022 | Fw::Success::T hashStatus = container.checkHeaderHash(storedHash, computedHash); |
| 546 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6021 times.
|
6022 | if (hashStatus != Fw::Success::SUCCESS) { |
| 547 |
4/4✓ Branch 5 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 20 taken 1 times.
|
2 | this->log_WARNING_HI_FileHdrError(fullFile, DpHdrField::CRC, computedHash.asBigEndianU32(), |
| 548 | 1 | storedHash.asBigEndianU32()); | |
| 549 | 1 | return ProcessFileStatus::FAILED; | |
| 550 | } | ||
| 551 | |||
| 552 | // reset header deserialization in the container | ||
| 553 |
1/1✓ Branch 2 taken 6021 times.
|
6021 | Fw::SerializeStatus desStat = container.deserializeHeader(); |
| 554 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6021 times.
|
6021 | if (desStat != Fw::FW_SERIALIZE_OK) { |
| 555 | ✗ | this->log_WARNING_HI_FileHdrDesError(fullFile, desStat); | |
| 556 | ✗ | return ProcessFileStatus::FAILED; | |
| 557 | } | ||
| 558 | |||
| 559 | 6021 | const FwSizeType dataSize = container.getDataSize(); | |
| 560 | 6021 | const FwSizeType expectedDataSize = fileSize - Fw::DpContainer::MIN_PACKET_SIZE; | |
| 561 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6021 times.
|
6021 | if (dataSize != expectedDataSize) { |
| 562 | ✗ | this->log_WARNING_HI_FileReadError(fullFile, Os::File::BAD_SIZE); | |
| 563 | ✗ | return ProcessFileStatus::FAILED; | |
| 564 | } | ||
| 565 | |||
| 566 |
1/1✓ Branch 2 taken 6021 times.
|
6021 | Fw::FileNameString canonicalFileName; |
| 567 | Fw::FormatStatus canonicalFormatStatus = | ||
| 568 |
3/3✓ Branch 2 taken 6021 times.
✓ Branch 5 taken 6021 times.
✓ Branch 17 taken 6021 times.
|
18063 | canonicalFileName.format(DP_FILENAME_FORMAT, this->m_directories[dir].toChar(), container.getId(), |
| 569 |
2/2✓ Branch 2 taken 6021 times.
✓ Branch 9 taken 6021 times.
|
18063 | container.getTimeTag().getSeconds(), container.getTimeTag().getUSeconds()); |
| 570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6021 times.
|
6021 | if (canonicalFormatStatus != Fw::FormatStatus::SUCCESS) { |
| 571 | ✗ | this->log_WARNING_HI_FileNameFormatError(fullFile, | |
| 572 | static_cast<Fw::StringFormatStatus::T>(canonicalFormatStatus)); | ||
| 573 | ✗ | return ProcessFileStatus::FAILED; | |
| 574 | } | ||
| 575 |
3/3✓ Branch 5 taken 6021 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 6020 times.
|
6021 | if (canonicalFileName != fullFile) { |
| 576 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_InvalidFileName(fullFile, canonicalFileName); |
| 577 | 1 | return ProcessFileStatus::FAILED; | |
| 578 | } | ||
| 579 | |||
| 580 | // skip adding an already transmitted file | ||
| 581 |
2/3✓ Branch 2 taken 6020 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6020 times.
|
6020 | if (container.getState() == Fw::DpState::TRANSMITTED) { |
| 582 | ✗ | this->log_ACTIVITY_HI_DpFileSkipped(fullFile); | |
| 583 | ✗ | return ProcessFileStatus::FAILED; | |
| 584 | } | ||
| 585 | |||
| 586 | // add entry to catalog. | ||
| 587 |
1/1✓ Branch 2 taken 6020 times.
|
6020 | DpStateEntry entry; |
| 588 | 6020 | entry.dir = static_cast<FwIndexType>(dir); | |
| 589 |
1/1✓ Branch 4 taken 6020 times.
|
6020 | entry.record.set_id(container.getId()); |
| 590 |
1/1✓ Branch 4 taken 6020 times.
|
6020 | entry.record.set_priority(container.getPriority()); |
| 591 |
2/2✓ Branch 3 taken 6020 times.
✓ Branch 10 taken 6020 times.
|
6020 | entry.record.set_state(container.getState()); |
| 592 |
3/3✓ Branch 3 taken 6020 times.
✓ Branch 9 taken 6020 times.
✓ Branch 12 taken 6020 times.
|
6020 | entry.record.set_tSec(container.getTimeTag().getSeconds()); |
| 593 |
3/3✓ Branch 3 taken 6020 times.
✓ Branch 9 taken 6020 times.
✓ Branch 12 taken 6020 times.
|
6020 | entry.record.set_tSub(container.getTimeTag().getUSeconds()); |
| 594 |
1/1✓ Branch 2 taken 6020 times.
|
6020 | entry.record.set_size(static_cast<U64>(fileSize)); |
| 595 | |||
| 596 | // check the state file to see if there is transmit state | ||
| 597 |
1/1✓ Branch 4 taken 6020 times.
|
6020 | this->getFileState(entry); |
| 598 | |||
| 599 | // a duplicate insert updates the tree in place; skip it so pending counters are not double-counted | ||
| 600 |
2/3✓ Branch 4 taken 6020 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6020 times.
|
6020 | if (this->m_dpCatalog.find(entry) == Fw::Success::SUCCESS) { |
| 601 | ✗ | this->log_ACTIVITY_HI_DpFileSkipped(fullFile); | |
| 602 | ✗ | return ProcessFileStatus::FAILED; | |
| 603 | } | ||
| 604 | |||
| 605 | // insert entry into sorted catalog. if can't insert, quit | ||
| 606 |
1/1✓ Branch 4 taken 6020 times.
|
6020 | bool inserted = this->insertEntry(entry); |
| 607 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6020 times.
|
6020 | if (!inserted) { |
| 608 | ✗ | this->log_WARNING_HI_DpInsertError(entry.record); | |
| 609 | // return and hope new slots open up later | ||
| 610 | ✗ | return ProcessFileStatus::QUIT; | |
| 611 | } | ||
| 612 | |||
| 613 | // increment our counters | ||
| 614 | 6020 | this->m_pendingFiles++; | |
| 615 | 6020 | this->m_pendingDpBytes += entry.record.get_size(); | |
| 616 | |||
| 617 | // make sure we haven't exceeded the limit | ||
| 618 |
1/2✗ Branch 8 not taken.
✓ Branch 9 taken 6020 times.
|
6020 | if (this->m_pendingFiles > this->m_numDpSlots) { |
| 619 | ✗ | this->log_WARNING_HI_DpCatalogFull(entry.record); | |
| 620 | ✗ | return ProcessFileStatus::QUIT; | |
| 621 | } | ||
| 622 | |||
| 623 |
1/1✓ Branch 5 taken 6020 times.
|
6020 | this->log_ACTIVITY_HI_DpFileAdded(canonicalFileName); |
| 624 | |||
| 625 | // No need to track iterator state - begin() always gives us the highest priority entry | ||
| 626 | // and we remove entries as we transmit them | ||
| 627 | |||
| 628 | 6020 | return ProcessFileStatus::SUCCESS; | |
| 629 | 6023 | } | |
| 630 | |||
| 631 | // ---------------------------------------------------------------------- | ||
| 632 | // DpStateEntry Comparison Ops | ||
| 633 | // ---------------------------------------------------------------------- | ||
| 634 | 1707139 | I8 DpCatalog::DpStateEntry::compareEntries(const DpStateEntry& left, const DpStateEntry& right) { | |
| 635 | // check priority. Lower is higher priority | ||
| 636 |
2/2✓ Branch 22 taken 630060 times.
✓ Branch 23 taken 1077079 times.
|
1707139 | if (left.record.get_priority() < right.record.get_priority()) { |
| 637 | 630060 | return -1; | |
| 638 |
2/2✓ Branch 22 taken 327477 times.
✓ Branch 23 taken 749602 times.
|
1077079 | } else if (left.record.get_priority() > right.record.get_priority()) { |
| 639 | 327477 | return 1; | |
| 640 | } | ||
| 641 | |||
| 642 | // check time. Older is higher priority | ||
| 643 |
2/2✓ Branch 22 taken 239428 times.
✓ Branch 23 taken 510174 times.
|
749602 | else if (left.record.get_tSec() < right.record.get_tSec()) { |
| 644 | 239428 | return -1; | |
| 645 |
2/2✓ Branch 22 taken 120588 times.
✓ Branch 23 taken 389586 times.
|
510174 | } else if (left.record.get_tSec() > right.record.get_tSec()) { |
| 646 | 120588 | return 1; | |
| 647 | } | ||
| 648 | |||
| 649 | // check subsecond time. Older is higher priority | ||
| 650 |
2/2✓ Branch 22 taken 2 times.
✓ Branch 23 taken 389584 times.
|
389586 | else if (left.record.get_tSub() < right.record.get_tSub()) { |
| 651 | 2 | return -1; | |
| 652 |
2/2✓ Branch 22 taken 1 times.
✓ Branch 23 taken 389583 times.
|
389584 | } else if (left.record.get_tSub() > right.record.get_tSub()) { |
| 653 | 1 | return 1; | |
| 654 | } | ||
| 655 | |||
| 656 | // check ID. Lower is higher priority | ||
| 657 |
2/2✓ Branch 22 taken 176600 times.
✓ Branch 23 taken 212983 times.
|
389583 | else if (left.record.get_id() < right.record.get_id()) { |
| 658 | 176600 | return -1; | |
| 659 |
2/2✓ Branch 22 taken 136985 times.
✓ Branch 23 taken 75998 times.
|
212983 | } else if (left.record.get_id() > right.record.get_id()) { |
| 660 | 136985 | return 1; | |
| 661 | } | ||
| 662 | |||
| 663 | // if ids are equal we have two nodes with the same value | ||
| 664 | else { | ||
| 665 | 75998 | return 0; | |
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | 658658 | bool DpCatalog::DpStateEntry::operator==(const DpStateEntry& other) const { | |
| 670 | 658658 | return compareEntries(*this, other) == 0; | |
| 671 | } | ||
| 672 | 1 | bool DpCatalog::DpStateEntry::operator!=(const DpStateEntry& other) const { | |
| 673 | 1 | return compareEntries(*this, other) != 0; | |
| 674 | } | ||
| 675 | |||
| 676 | 1 | bool DpCatalog::DpStateEntry::operator>(const DpStateEntry& other) const { | |
| 677 | 1 | return compareEntries(*this, other) > 0; | |
| 678 | } | ||
| 679 | 1048479 | bool DpCatalog::DpStateEntry::operator<(const DpStateEntry& other) const { | |
| 680 | 1048479 | return compareEntries(*this, other) < 0; | |
| 681 | } | ||
| 682 | |||
| 683 | 66831 | bool DpCatalog::insertEntry(DpStateEntry& entry) { | |
| 684 | // Insert into the RedBlackTreeSet | ||
| 685 | // The tree maintains sorting by priority, time, and ID via DpStateEntry comparison operators | ||
| 686 |
1/1✓ Branch 5 taken 66831 times.
|
66831 | Fw::Success status = this->m_dpCatalog.insert(entry); |
| 687 | 133662 | return (status == Fw::Success::SUCCESS); | |
| 688 | 66831 | } | |
| 689 | |||
| 690 | 6002 | void DpCatalog::sendNextEntry() { | |
| 691 | // Use xmit flag to break upon STOP_XMIT_CATALOG | ||
| 692 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 6002 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6002 times.
|
6002 | if (this->m_xmitInProgress != true) { |
| 693 | ✗ | return; | |
| 694 | } | ||
| 695 | |||
| 696 | // Look for the next entry to send | ||
| 697 |
1/1✓ Branch 2 taken 6002 times.
|
6002 | DpStateEntry entry; |
| 698 |
3/3✓ Branch 4 taken 6002 times.
✓ Branch 6 taken 113 times.
✓ Branch 7 taken 5889 times.
|
6002 | if (!this->findNextEntry(entry)) { |
| 699 | // if no entry found, we are done | ||
| 700 | 113 | this->m_xmitInProgress = false; | |
| 701 |
1/1✓ Branch 9 taken 113 times.
|
113 | this->log_ACTIVITY_HI_CatalogXmitCompleted(this->m_xmitBytes); |
| 702 |
2/2✓ Branch 5 taken 113 times.
✓ Branch 8 taken 113 times.
|
113 | this->dispatchWaitedResponse(Fw::CmdResponse::OK); |
| 703 | 113 | return; | |
| 704 | } | ||
| 705 | |||
| 706 | // Save current entry for fileDone_handler | ||
| 707 |
1/1✓ Branch 4 taken 5889 times.
|
5889 | this->m_currentXmitEntry = entry; |
| 708 | 5889 | this->m_hasCurrentXmit = true; | |
| 709 | |||
| 710 | // Build file name based on the found entry | ||
| 711 | Fw::FormatStatus formatStatus = | ||
| 712 |
1/1✓ Branch 16 taken 5889 times.
|
23556 | this->m_currXmitFileName.format(DP_FILENAME_FORMAT, this->m_directories[entry.dir].toChar(), |
| 713 | 17667 | entry.record.get_id(), entry.record.get_tSec(), entry.record.get_tSub()); | |
| 714 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5889 times.
|
5889 | if (formatStatus != Fw::FormatStatus::SUCCESS) { |
| 715 | ✗ | this->log_WARNING_HI_FileNameFormatError(this->m_currXmitFileName, | |
| 716 | static_cast<Fw::StringFormatStatus::T>(formatStatus)); | ||
| 717 | // No send is in flight, so no fileDone will arrive: abort the transmit | ||
| 718 | // rather than leaving it wedged in progress | ||
| 719 | ✗ | this->m_hasCurrentXmit = false; | |
| 720 | ✗ | this->m_xmitInProgress = false; | |
| 721 | ✗ | this->dispatchWaitedResponse(Fw::CmdResponse::EXECUTION_ERROR); | |
| 722 | ✗ | return; | |
| 723 | } | ||
| 724 |
1/1✓ Branch 11 taken 5889 times.
|
11778 | this->log_ACTIVITY_LO_SendingProduct(this->m_currXmitFileName, static_cast<U32>(entry.record.get_size()), |
| 725 | 5889 | entry.record.get_priority()); | |
| 726 |
1/1✓ Branch 9 taken 5889 times.
|
5889 | Svc::SendFileResponse resp = this->fileOut_out(0, this->m_currXmitFileName, this->m_currXmitFileName, 0, 0); |
| 727 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 5889 times.
|
5889 | if (resp.get_status() != Svc::SendFileStatus::STATUS_OK) { |
| 728 | ✗ | this->log_WARNING_HI_DpFileSendError(this->m_currXmitFileName, resp.get_status()); | |
| 729 | // A rejected send produces no fileDone callback: abort the transmit | ||
| 730 | // rather than leaving it wedged in progress | ||
| 731 | ✗ | this->m_hasCurrentXmit = false; | |
| 732 | ✗ | this->m_xmitInProgress = false; | |
| 733 | ✗ | this->dispatchWaitedResponse(Fw::CmdResponse::EXECUTION_ERROR); | |
| 734 | } | ||
| 735 | 6002 | } // end sendNextEntry() | |
| 736 | |||
| 737 | 63171 | bool DpCatalog::findNextEntry(DpStateEntry& entry) { | |
| 738 | // If catalog is empty, return false | ||
| 739 |
3/3✓ Branch 6 taken 63171 times.
✓ Branch 8 taken 1121 times.
✓ Branch 9 taken 62050 times.
|
63171 | if (this->m_dpCatalog.getSize() == 0) { |
| 740 | 1121 | return false; | |
| 741 | } | ||
| 742 | |||
| 743 | // Get the highest priority entry (begin() returns highest priority) | ||
| 744 | // Since we remove entries as we transmit them, begin() always gives us the next entry | ||
| 745 |
1/1✓ Branch 4 taken 62050 times.
|
62050 | typename Fw::RedBlackTreeSet<DpStateEntry, DP_MAX_FILES>::ConstIterator iter = this->m_dpCatalog.begin(); |
| 746 | |||
| 747 | // Verify iterator is valid | ||
| 748 |
3/4✓ Branch 4 taken 62050 times.
✓ Branch 8 taken 62050 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 62050 times.
|
62050 | if (iter == this->m_dpCatalog.end()) { |
| 749 | ✗ | return false; | |
| 750 | } | ||
| 751 | |||
| 752 | // Get the entry | ||
| 753 |
2/2✓ Branch 1 taken 62050 times.
✓ Branch 5 taken 62050 times.
|
62050 | entry = *iter; |
| 754 | |||
| 755 | 62050 | return true; | |
| 756 | 62050 | } | |
| 757 | |||
| 758 | 3212 | bool DpCatalog::checkInit() { | |
| 759 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 3212 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 3211 times.
|
3212 | if (not this->m_initialized) { |
| 760 | 1 | this->log_WARNING_HI_ComponentNotInitialized(); | |
| 761 | 1 | return false; | |
| 762 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 3211 times.
|
3211 | } else if (0 == this->m_numDpSlots) { |
| 763 | ✗ | this->log_WARNING_HI_ComponentNoMemory(); | |
| 764 | ✗ | return false; | |
| 765 | } | ||
| 766 | |||
| 767 | 3211 | return true; | |
| 768 | } | ||
| 769 | |||
| 770 | 618 | void DpCatalog::shutdown() { | |
| 771 | // only try to deallocate if both pointers are non-zero | ||
| 772 | // it's a way to more gracefully shut down if there are missing | ||
| 773 | // pointers | ||
| 774 |
2/4✓ Branch 4 taken 618 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 618 times.
✗ Branch 11 not taken.
|
618 | if ((this->m_allocator != nullptr) and (this->m_memPtr != nullptr)) { |
| 775 | 618 | this->m_allocator->deallocate(this->m_allocatorId, this->m_memPtr); | |
| 776 | } | ||
| 777 | 618 | } | |
| 778 | |||
| 779 | // ---------------------------------------------------------------------- | ||
| 780 | // Handler implementations for user-defined typed input ports | ||
| 781 | // ---------------------------------------------------------------------- | ||
| 782 | |||
| 783 | 5891 | void DpCatalog ::fileDone_handler(FwIndexType portNum, const Svc::SendFileResponse& resp) { | |
| 784 | // check file status | ||
| 785 |
2/2✓ Branch 4 taken 3 times.
✓ Branch 5 taken 5888 times.
|
5891 | if (resp.get_status() != Svc::SendFileStatus::STATUS_OK) { |
| 786 |
2/2✓ Branch 10 taken 3 times.
✓ Branch 17 taken 3 times.
|
3 | this->log_WARNING_HI_DpFileXmitError(this->m_currXmitFileName, resp.get_status()); |
| 787 | 3 | this->m_xmitInProgress = false; | |
| 788 |
2/2✓ Branch 5 taken 3 times.
✓ Branch 8 taken 3 times.
|
3 | this->dispatchWaitedResponse(Fw::CmdResponse::EXECUTION_ERROR); |
| 789 | 3 | return; | |
| 790 | } | ||
| 791 | |||
| 792 | // Catalog cleared while this file was sent; clear xmit state and answer any waited command | ||
| 793 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 5888 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 5886 times.
|
5888 | if (!this->m_catalogBuilt) { |
| 794 | 2 | this->m_hasCurrentXmit = false; | |
| 795 | 2 | this->m_xmitInProgress = false; | |
| 796 |
2/2✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
|
2 | this->dispatchWaitedResponse(Fw::CmdResponse::EXECUTION_ERROR); |
| 797 | 2 | return; | |
| 798 | } | ||
| 799 | |||
| 800 | // Should have a valid current transmit entry | ||
| 801 | 5886 | FW_ASSERT(this->m_hasCurrentXmit); | |
| 802 | |||
| 803 | // Reduce pending | ||
| 804 | 5886 | this->m_pendingDpBytes -= this->m_currentXmitEntry.record.get_size(); | |
| 805 | 5886 | this->m_pendingFiles--; | |
| 806 | // Log File Complete & pending | ||
| 807 |
1/1✓ Branch 16 taken 5886 times.
|
5886 | this->log_ACTIVITY_LO_ProductComplete(this->m_currXmitFileName, this->m_pendingFiles, this->m_pendingDpBytes); |
| 808 | |||
| 809 | // mark the entry as transmitted | ||
| 810 |
1/1✓ Branch 6 taken 5886 times.
|
5886 | this->m_currentXmitEntry.record.set_state(Fw::DpState::TRANSMITTED); |
| 811 | // update the transmitted state in the state file | ||
| 812 |
1/1✓ Branch 7 taken 5886 times.
|
5886 | this->appendFileState(this->m_currentXmitEntry); |
| 813 | // add the size | ||
| 814 | 5886 | this->m_xmitBytes += this->m_currentXmitEntry.record.get_size(); | |
| 815 | |||
| 816 | // Remove from catalog | ||
| 817 |
1/1✓ Branch 7 taken 5886 times.
|
5886 | Fw::Success status = this->m_dpCatalog.remove(this->m_currentXmitEntry); |
| 818 | 5886 | FW_ASSERT(status == Fw::Success::SUCCESS); | |
| 819 | |||
| 820 | 5886 | this->m_hasCurrentXmit = false; | |
| 821 | |||
| 822 | // send the next entry, if it exists | ||
| 823 |
1/1✓ Branch 4 taken 5886 times.
|
5886 | this->sendNextEntry(); |
| 824 | 5886 | } | |
| 825 | |||
| 826 | 1 | void DpCatalog ::pingIn_handler(FwIndexType portNum, U32 key) { | |
| 827 | // return code for health ping | ||
| 828 | 1 | this->pingOut_out(0, key); | |
| 829 | 1 | } | |
| 830 | |||
| 831 | 2987 | void DpCatalog ::addToCat_handler(FwIndexType portNum, | |
| 832 | const Fw::StringBase& fileName, | ||
| 833 | FwDpPriorityType priority, | ||
| 834 | FwSizeType size) { | ||
| 835 | // check initialization | ||
| 836 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 2987 times.
|
2987 | if (not this->checkInit()) { |
| 837 | ✗ | return; | |
| 838 | } | ||
| 839 | |||
| 840 | // check that initialization got memory | ||
| 841 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 2987 times.
|
2987 | if (0 == this->m_numDpSlots) { |
| 842 | ✗ | this->log_WARNING_HI_NoDpMemory(); | |
| 843 | ✗ | return; | |
| 844 | } | ||
| 845 | |||
| 846 | // Check the catalog has been built | ||
| 847 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 2987 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2987 times.
|
2987 | if (not this->m_catalogBuilt) { |
| 848 | ✗ | this->log_ACTIVITY_HI_NotLoaded(fileName); | |
| 849 | ✗ | return; | |
| 850 | } | ||
| 851 | |||
| 852 | // Both of these are grabbed from the header | ||
| 853 | (void)priority; | ||
| 854 | (void)size; | ||
| 855 | |||
| 856 | // Since this is a runtime addition | ||
| 857 | // Check if file is in one of our directories | ||
| 858 |
2/2✓ Branch 8 taken 2987 times.
✓ Branch 12 taken 2987 times.
|
2987 | FwSizeType dir = this->determineDirectory(fileName); |
| 859 | |||
| 860 | // Not in one of our directories; skip this file | ||
| 861 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2987 times.
|
2987 | if (dir == DP_MAX_DIRECTORIES) { |
| 862 | ✗ | this->log_WARNING_HI_DirectoryNotManaged(fileName); | |
| 863 | ✗ | return; | |
| 864 | } | ||
| 865 | |||
| 866 |
2/2✓ Branch 8 taken 2987 times.
✓ Branch 12 taken 2987 times.
|
2987 | const ProcessFileStatus ret = processFile(fileName, dir); |
| 867 | |||
| 868 |
1/2✓ Branch 0 taken 2987 times.
✗ Branch 1 not taken.
|
2987 | if (ret == ProcessFileStatus::SUCCESS) { |
| 869 | // If we already finished, sendNext only if remainingActive | ||
| 870 |
5/8✗ Branch 3 not taken.
✓ Branch 4 taken 2987 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 2981 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 6 times.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
|
2987 | if (!this->m_xmitInProgress && this->m_remainActive) { |
| 871 | 6 | this->m_xmitInProgress = true; | |
| 872 | 6 | this->sendNextEntry(); | |
| 873 | } | ||
| 874 | // Otherwise, Current File finishing will invoke sendNextFile & find the right file | ||
| 875 | // Or will be manually tx-ed at next command | ||
| 876 | |||
| 877 | // prune and rewrite the state file | ||
| 878 | 2987 | this->pruneAndWriteStateFile(); | |
| 879 | } | ||
| 880 | } | ||
| 881 | |||
| 882 | // ---------------------------------------------------------------------- | ||
| 883 | // Handler implementations for commands | ||
| 884 | // ---------------------------------------------------------------------- | ||
| 885 | |||
| 886 | 112 | void DpCatalog ::BUILD_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 887 | // invoke helper | ||
| 888 |
2/2✓ Branch 6 taken 112 times.
✓ Branch 9 taken 112 times.
|
112 | this->cmdResponse_out(opCode, cmdSeq, this->doCatalogBuild()); |
| 889 | 112 | } | |
| 890 | |||
| 891 | 113 | void DpCatalog ::START_XMIT_CATALOG_cmdHandler(FwOpcodeType opCode, | |
| 892 | U32 cmdSeq, | ||
| 893 | const Fw::Wait& wait, | ||
| 894 | bool remainActive) { | ||
| 895 | 113 | this->m_remainActive = remainActive; | |
| 896 | |||
| 897 | // Arm the waited response before starting: an empty catalog completes the | ||
| 898 | // transmit inside doCatalogXmit and must still answer a waited command | ||
| 899 |
2/2✓ Branch 4 taken 55 times.
✓ Branch 5 taken 58 times.
|
113 | if (Fw::Wait::WAIT == wait) { |
| 900 | 55 | this->m_xmitCmdWait = true; | |
| 901 | 55 | this->m_xmitOpCode = opCode; | |
| 902 | 55 | this->m_xmitCmdSeq = cmdSeq; | |
| 903 | } | ||
| 904 | |||
| 905 |
1/1✓ Branch 2 taken 113 times.
|
113 | Fw::CmdResponse resp = this->doCatalogXmit(); |
| 906 | 113 | FW_ASSERT(resp.isValid(), static_cast<FwAssertArgType>(resp.e)); | |
| 907 | |||
| 908 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 3 taken 110 times.
|
113 | if (resp != Fw::CmdResponse::OK) { |
| 909 | 3 | this->m_xmitCmdWait = false; | |
| 910 | 3 | this->m_xmitOpCode = 0; | |
| 911 | 3 | this->m_xmitCmdSeq = 0; | |
| 912 |
2/2✓ Branch 6 taken 3 times.
✓ Branch 9 taken 3 times.
|
3 | this->cmdResponse_out(opCode, cmdSeq, resp); |
| 913 |
2/2✓ Branch 4 taken 56 times.
✓ Branch 5 taken 54 times.
|
110 | } else if (Fw::Wait::NO_WAIT == wait) { |
| 914 |
2/2✓ Branch 6 taken 56 times.
✓ Branch 9 taken 56 times.
|
56 | this->cmdResponse_out(opCode, cmdSeq, resp); |
| 915 | } | ||
| 916 | 226 | } | |
| 917 | |||
| 918 | 113 | Fw::CmdResponse DpCatalog::doCatalogXmit() { | |
| 919 | // check initialization | ||
| 920 |
2/2✓ Branch 4 taken 1 times.
✓ Branch 5 taken 112 times.
|
113 | if (not this->checkInit()) { |
| 921 | 1 | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 922 | } | ||
| 923 | |||
| 924 | // check that initialization got memory | ||
| 925 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
|
112 | if (0 == this->m_numDpSlots) { |
| 926 | ✗ | this->log_WARNING_HI_NoDpMemory(); | |
| 927 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 928 | } | ||
| 929 | |||
| 930 | // make sure a downlink is not in progress | ||
| 931 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112 times.
|
112 | if (this->m_xmitInProgress) { |
| 932 | ✗ | this->log_WARNING_LO_DpXmitInProgress(); | |
| 933 | ✗ | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 934 | } | ||
| 935 | |||
| 936 | // Check the catalog has been built | ||
| 937 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 112 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 110 times.
|
112 | if (not this->m_catalogBuilt) { |
| 938 | 2 | this->log_WARNING_HI_XmitUnbuiltCatalog(); | |
| 939 | 2 | return Fw::CmdResponse::EXECUTION_ERROR; | |
| 940 | } | ||
| 941 | |||
| 942 | // start transmission | ||
| 943 | 110 | this->m_xmitBytes = 0; | |
| 944 | |||
| 945 | 110 | this->m_xmitInProgress = true; | |
| 946 | // Step 3b - search for and send first entry | ||
| 947 | 110 | this->sendNextEntry(); | |
| 948 | 110 | return Fw::CmdResponse::OK; | |
| 949 | } | ||
| 950 | |||
| 951 | 3 | void DpCatalog ::STOP_XMIT_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 952 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
|
3 | if (not this->m_xmitInProgress) { |
| 953 | 1 | this->log_WARNING_LO_XmitNotActive(); | |
| 954 | // benign error, so don't fail the command | ||
| 955 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 956 | } else { | ||
| 957 | 2 | this->log_ACTIVITY_HI_CatalogXmitStopped(this->m_xmitBytes); | |
| 958 | // Disarm the flag so next sendNextEntry stops transmission | ||
| 959 | 2 | this->m_xmitInProgress = false; | |
| 960 | // Respond to original cmd to start xmit | ||
| 961 | // (if we haven't already) | ||
| 962 |
2/2✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
|
2 | this->dispatchWaitedResponse(Fw::CmdResponse::OK); |
| 963 | |||
| 964 | // Respond to this command | ||
| 965 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 966 | } | ||
| 967 | 3 | } | |
| 968 | |||
| 969 | 2 | void DpCatalog ::CLEAR_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 970 | 2 | this->resetCatalog(); | |
| 971 | 2 | this->resetStateFileData(); | |
| 972 | |||
| 973 |
2/2✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 974 | 2 | } | |
| 975 | |||
| 976 | 120 | void DpCatalog ::dispatchWaitedResponse(Fw::CmdResponse response) { | |
| 977 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 120 times.
✓ Branch 5 taken 54 times.
✓ Branch 6 taken 66 times.
|
120 | if (this->m_xmitCmdWait) { |
| 978 |
2/2✓ Branch 6 taken 54 times.
✓ Branch 17 taken 54 times.
|
54 | this->cmdResponse_out(this->m_xmitOpCode, this->m_xmitCmdSeq, response); |
| 979 | |||
| 980 | // Prevent a Duplicate Cmd Response | ||
| 981 | 54 | this->m_xmitCmdWait = false; | |
| 982 | 54 | this->m_xmitOpCode = 0; | |
| 983 | 54 | this->m_xmitCmdSeq = 0; | |
| 984 | } | ||
| 985 | 120 | } | |
| 986 | |||
| 987 | } // namespace Svc | ||
| 988 |