F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
DpCatalog.cpp
Go to the documentation of this file.
1 // ======================================================================
2 
3 // \title DpCatalog.cpp
4 // \author tcanham
5 // \brief cpp file for DpCatalog component implementation class
6 // ======================================================================
7 
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 
17 namespace Svc {
18 static_assert(DP_MAX_DIRECTORIES > 0, "Configuration DP_MAX_DIRECTORIES must be positive");
19 static_assert(DP_MAX_FILES > 0, "Configuration DP_MAX_FILES must be positive");
20 // ----------------------------------------------------------------------
21 // Component construction and destruction
22 // ----------------------------------------------------------------------
23 
24 DpCatalog ::DpCatalog(const char* const compName) : DpCatalogComponentBase(compName) {
25  // Members are default-initialized via in-class initializers in the header.
26 }
27 
29  FwSizeType numDirs,
30  Fw::FileNameString& stateFile,
31  FwEnumStoreType memId,
32  Fw::MemAllocator& allocator) {
33  // Do some assertion checks
34  FW_ASSERT(numDirs <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(numDirs));
35 
36  this->m_stateFile = stateFile;
37 
38  // request memory for catalog which is DP_MAX_FILES * slot size.
39  //
40  // A "slot" consists of a set of two memory locations for each data product consisting
41  // an entry in the binary tree and
42  // an entry in the state file data. These may not be fully used in a given
43  // situation based on the number of actual data products, but this provides room for the
44  // maximum possible.
45  static const FwSizeType slotSize = sizeof(DpBtreeNode) + sizeof(DpDstateFileEntry);
46  this->m_memSize = DP_MAX_FILES * slotSize;
47  bool notUsed; // we don't need to recover the catalog.
48  // request memory. this->m_memSize will be modified if there is less than we requested
49  this->m_memPtr = allocator.allocate(memId, this->m_memSize, notUsed);
50  // adjust to actual size if less allocated and only initialize
51  // if there is enough room for at least one record and memory
52  // was allocated.
53 
54  // Since we are given a monolithic block of memory, the data structures
55  // are interspersed in the memory using the following method:
56  //
57  // 1) Recompute how many slots can fit in the provided memory if we
58  // don't get the full amount requested. This allows for graceful degradation
59  // if there are memory issues.
60  //
61  // 2) Place the binary tree free list at the beginning of the memory.
62  //
63  // 3) Place the state file data in memory after the binary free list
64  // by indexing the free list to one element past the end of
65  // the free list.
66 
67  if ((this->m_memSize >= slotSize) and (this->m_memPtr != nullptr)) {
68  // set the number of available record slots based on how much memory we actually got
69  this->m_numDpSlots = this->m_memSize / slotSize; // Step 1.
70  this->resetBinaryTree(); // Step 2
71  // assign pointer for the state file storage - Step 3
72  this->m_stateFileData = reinterpret_cast<DpDstateFileEntry*>(&this->m_freeListHead[this->m_numDpSlots]);
73  } else {
74  // if we don't have enough memory, set the number of records
75  // to zero for later detection
76  this->m_numDpSlots = 0;
77  }
78 
79  // assign directory names
80  for (FwSizeType dir = 0; dir < numDirs; dir++) {
81  this->m_directories[dir] = directories[dir];
82  }
83  this->m_numDirectories = numDirs;
84 
85  // store allocator
86  this->m_allocator = &allocator;
87  this->m_allocatorId = memId;
88  this->m_initialized = true;
89 }
90 
91 void DpCatalog::resetBinaryTree() {
92  // initialize data structures in the free list
93  // Step 2 in memory partition (see configure() comments)
94  FW_ASSERT(this->m_memPtr);
95  this->m_freeListHead = static_cast<DpBtreeNode*>(this->m_memPtr);
96  for (FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) {
97  // overlay new instance of the DpState entry on the memory
98  (void)new (&this->m_freeListHead[slot]) DpBtreeNode();
99  this->m_freeListHead[slot].left = nullptr;
100  this->m_freeListHead[slot].right = nullptr;
101  // link the free list
102  if (slot > 0) {
103  this->m_freeListHead[slot - 1].left = &this->m_freeListHead[slot];
104  }
105  }
106  // clear binary tree
107  this->m_dpTree = nullptr;
108  // reset number of records
109  this->m_pendingFiles = 0;
110  this->m_pendingDpBytes = 0;
111  // Mark the catalog as un-built
112  this->m_catalogBuilt = false;
113 }
114 
115 void DpCatalog::resetStateFileData() {
116  // clear state file data
117  for (FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) {
118  this->m_stateFileData[slot].used = false;
119  this->m_stateFileData[slot].visited = false;
120  (void)new (&this->m_stateFileData[slot].entry.record) DpRecord();
121  }
122  this->m_stateFileEntries = 0;
123 }
124 
125 Fw::CmdResponse DpCatalog::loadStateFile() {
126  FW_ASSERT(this->m_stateFileData);
127 
128  // Make sure that a file was specified
129  if (this->m_stateFile.length() == 0) {
131  return Fw::CmdResponse::OK;
132  }
133 
134  // buffer for reading entries
135 
136  BYTE buffer[sizeof(FwIndexType) + DpRecord::SERIALIZED_SIZE];
137  Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer));
138 
139  // open the state file
140  Os::File stateFile;
141  Os::File::Status stat = stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_READ);
142  if (stat != Os::File::OP_OK) {
143  this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat);
145  }
146 
147  FwSizeType fileLoc = 0;
148  this->m_stateFileEntries = 0;
149 
150  // read entries from the state file
151  for (FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) {
152  FwSizeType size = static_cast<FwSizeType>(sizeof(buffer));
153  // read the directory index
154  stat = stateFile.read(buffer, size);
155  if (stat != Os::File::OP_OK) {
156  this->log_WARNING_HI_StateFileReadError(this->m_stateFile, stat, static_cast<I32>(fileLoc));
158  }
159 
160  if (0 == size) {
161  // no more entries
162  break;
163  }
164 
165  // check to see if the full entry was read. If not,
166  // abandon it and finish. We can at least operate on
167  // the entries that were read.
168  if (size != sizeof(buffer)) {
169  this->log_WARNING_HI_StateFileTruncated(this->m_stateFile, static_cast<I32>(fileLoc),
170  static_cast<I32>(size));
171  return Fw::CmdResponse::OK;
172  }
173 
174  // reset the buffer for deserializing the entry
175  Fw::SerializeStatus serStat = entryBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(size));
176  // should always fit
177  FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, serStat);
178  entryBuffer.resetDeser();
179 
180  // deserialization after this point should always work, since
181  // the source buffer was specifically sized to hold the data
182 
183  // Deserialize the file directory index
184  Fw::SerializeStatus status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.dir);
185  FW_ASSERT(Fw::FW_SERIALIZE_OK == status, status);
186  status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.record);
187  FW_ASSERT(Fw::FW_SERIALIZE_OK == status, status);
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 
196  return Fw::CmdResponse::OK;
197 }
198 
199 void DpCatalog::getFileState(DpStateEntry& entry) {
200  FW_ASSERT(this->m_stateFileData);
201  // search the file state data for the entry
202  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 void DpCatalog::pruneAndWriteStateFile() {
216  FW_ASSERT(this->m_stateFileData);
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  Os::File stateFile;
226  // we open it as a new file so we don't accumulate invalid entries
227  Os::File::Status stat =
228  stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_CREATE, Os::FileInterface::OVERWRITE);
229 
230  if (stat != Os::File::OP_OK) {
231  this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat);
232  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  return;
259  }
260  }
261  }
262 
263  // close the state file
264  stateFile.close();
265 }
266 
267 void DpCatalog::appendFileState(const DpStateEntry& entry) {
268  FW_ASSERT(this->m_stateFileData);
269  FW_ASSERT(entry.dir < static_cast<FwIndexType>(this->m_numDirectories), static_cast<FwAssertArgType>(entry.dir),
270  static_cast<FwAssertArgType>(this->m_numDirectories));
271 
272  // We will append state to the existing state file
273  // TODO: Have to handle case where state file has partially transmitted
274  // state already
275 
276  // open the state file
277  Os::File stateFile;
278  // we open it as a new file so we don't accumulate invalid entries
279  Os::File::Status stat = stateFile.open(this->m_stateFile.toChar(), Os::File::OPEN_APPEND);
280  if (stat != Os::File::OP_OK) {
281  this->log_WARNING_HI_StateFileOpenError(this->m_stateFile, stat);
282  return;
283  }
284 
285  // buffer for writing entries
286  BYTE buffer[sizeof(entry.dir) + sizeof(entry.record)];
287  Fw::ExternalSerializeBuffer entryBuffer(buffer, sizeof(buffer));
288  // reset the buffer for serializing the entry
289  entryBuffer.resetSer();
290  // serialize the file directory index
291  Fw::SerializeStatus serStat = entryBuffer.serializeFrom(entry.dir);
292  // should fit
293  FW_ASSERT(serStat == Fw::FW_SERIALIZE_OK, serStat);
294  serStat = entryBuffer.serializeFrom(entry.record);
295  // should fit
296  FW_ASSERT(serStat == Fw::FW_SERIALIZE_OK, serStat);
297  // write the entry
298  FwSizeType size = entryBuffer.getSize();
299  stat = stateFile.write(buffer, size);
300  if (stat != Os::File::OP_OK) {
301  this->log_WARNING_HI_StateFileWriteError(this->m_stateFile, stat);
302  return;
303  }
304 
305  // close the state file
306  stateFile.close();
307 }
308 
309 Fw::CmdResponse DpCatalog::doCatalogBuild() {
310  // check initialization
311  if (not this->checkInit()) {
313  }
314 
315  // check that initialization got memory
316  if (0 == this->m_numDpSlots) {
319  }
320 
321  // make sure a downlink is not in progress
322  if (this->m_xmitInProgress) {
325  }
326 
327  // reset state file data
328  this->resetStateFileData();
329 
330  // load state data from file
331  Fw::CmdResponse response = this->loadStateFile();
332 
333  // reset free list for entries
334  this->resetBinaryTree();
335 
336  // fill the binary tree with DP files
337  response = this->fillBinaryTree();
338  if (response != Fw::CmdResponse::OK) {
339  // clean up the binary tree
340  this->resetBinaryTree();
341  this->resetStateFileData();
342  return response;
343  }
344 
345  // prune and rewrite the state file
346  this->pruneAndWriteStateFile();
347 
349 
350  // Flag so addToCat knows it is good to go
351  this->m_catalogBuilt = true;
352 
353  return Fw::CmdResponse::OK;
354 }
355 
356 Fw::CmdResponse DpCatalog::fillBinaryTree() {
357  // keep cumulative number of files
358  FwSizeType totalFiles = 0;
359 
360  // get file listings from file system
361  // double bounds to appease static analysis
362  for (FwSizeType dir = 0; dir < this->m_numDirectories && dir < static_cast<FwSizeType>(DP_MAX_DIRECTORIES); dir++) {
363  // read in each directory and keep track of total
364  this->log_ACTIVITY_LO_ProcessingDirectory(this->m_directories[dir]);
365  FwSizeType filesRead = 0;
366  U32 filesProcessed = 0;
367 
368  Os::Directory dpDir;
369  Os::Directory::Status status = dpDir.open(this->m_directories[dir].toChar(), Os::Directory::OpenMode::READ);
370  if (status != Os::Directory::OP_OK) {
371  this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status);
373  }
374  status = dpDir.readDirectory(this->m_fileList, (this->m_numDpSlots - totalFiles), filesRead);
375 
376  if (status != Os::Directory::OP_OK) {
377  this->log_WARNING_HI_DirectoryOpenError(this->m_directories[dir], status);
379  }
380 
381  // Assert number of files isn't more than asked
382  FW_ASSERT(filesRead <= this->m_numDpSlots - totalFiles, static_cast<FwAssertArgType>(filesRead),
383  static_cast<FwAssertArgType>(this->m_numDpSlots - totalFiles));
384 
385  // extract metadata for each file
386  for (FwSizeType file = 0; file < filesRead; file++) {
387  // only consider files with the DP extension
388 
389  FwSignedSizeType loc =
390  Fw::StringUtils::substring_find(this->m_fileList[file].toChar(), this->m_fileList[file].length(),
392 
393  if (-1 == loc) {
394  continue;
395  }
396 
397  Fw::String fullFile;
398  fullFile.format("%s/%s", this->m_directories[dir].toChar(), this->m_fileList[file].toChar());
399 
400  int ret = processFile(fullFile, dir);
401  if (ret < 0) {
402  break;
403  }
404 
405  filesProcessed += static_cast<U32>(ret);
406 
407  } // end for each file in a directory
408 
409  totalFiles += filesProcessed;
410 
411  this->log_ACTIVITY_HI_ProcessingDirectoryComplete(this->m_directories[dir], static_cast<U32>(totalFiles),
412  this->m_pendingFiles, this->m_pendingDpBytes);
413 
414  // check to see if catalog is full
415  // that means generated products exceed the catalog size
416  if (totalFiles == this->m_numDpSlots) {
417  this->log_WARNING_HI_CatalogFull(this->m_directories[dir]);
418  break;
419  }
420  } // end for each directory
421 
422  return Fw::CmdResponse::OK;
423 
424 } // end fillBinaryTree()
425 
426 FwSizeType DpCatalog::determineDirectory(Fw::String fullFile) {
427  // Grab the directory string (up until the final slash)
428  // Could be found directly w/ a dirname func or regex
430  fullFile.toChar(), fullFile.length(), DIRECTORY_DELIMITER,
432 
433  // Seems like the logic works so long as the path styles match (i.e. relative vs absolute)
434  // Full path resolution might be a worthwhile add
435 
436  // No directory delimiter found; return DP_MAX_DIRECTORIES to signal failure
437  if (-1 == loc) {
438  return DP_MAX_DIRECTORIES;
439  }
440 
441  for (FwSizeType dir = 0; dir < this->m_numDirectories; dir++) {
442  const Fw::FileNameString& dir_string = this->m_directories[dir];
443 
444  // Compare both strings up to location of final slash
445  // StringUtils::substring_find will return zero if both paths agree
446  // memory safe since both are fixed width strings
447  // and loc is before the fixed width
448  if (Fw::StringUtils::substring_find(dir_string.toChar(), dir_string.length(), fullFile.toChar(),
449  static_cast<FwSizeType>(loc)) == 0) {
450  return dir;
451  }
452  }
453 
454  // No directory matched
455  return DP_MAX_DIRECTORIES;
456 }
457 
458 int DpCatalog::processFile(Fw::String fullFile, FwSizeType dir) {
459  FW_ASSERT(dir < static_cast<FwSizeType>(DP_MAX_DIRECTORIES), static_cast<FwAssertArgType>(dir));
460  // file class instance for processing files
461  Os::File dpFile;
462 
463  // Working buffer for DP headers
464  U8 dpBuff[Fw::DpContainer::MIN_PACKET_SIZE]; // Header buffer
465  Fw::Buffer hdrBuff(dpBuff, sizeof(dpBuff)); // buffer for container header decoding
466  Fw::DpContainer container; // container object for extracting header fields
467 
468  this->log_ACTIVITY_LO_ProcessingFile(fullFile);
469 
470  // get file size
471  FwSizeType fileSize = 0;
472  Os::FileSystem::Status sizeStat = Os::FileSystem::getFileSize(fullFile.toChar(), fileSize);
473  if (sizeStat != Os::FileSystem::OP_OK) {
474  this->log_WARNING_HI_FileSizeError(fullFile, sizeStat);
475  return 0;
476  }
477 
478  Os::File::Status stat = dpFile.open(fullFile.toChar(), Os::File::OPEN_READ);
479  if (stat != Os::File::OP_OK) {
480  this->log_WARNING_HI_FileOpenError(fullFile, stat);
481  return 0;
482  }
483 
484  // Read DP header
486 
487  stat = dpFile.read(dpBuff, size);
488  if (stat != Os::File::OP_OK) {
489  this->log_WARNING_HI_FileReadError(fullFile, stat);
490  dpFile.close();
491  return 0;
492  }
493 
494  // if full header isn't read, something's wrong with the file, so skip
495  if (size != Fw::DpContainer::Header::SIZE) {
497  dpFile.close();
498  return 0;
499  }
500 
501  // if all is well, don't need the file any more
502  dpFile.close();
503 
504  // give buffer to container instance
505  container.setBuffer(hdrBuff);
506 
507  // reset header deserialization in the container
508  Fw::SerializeStatus desStat = container.deserializeHeader();
509  if (desStat != Fw::FW_SERIALIZE_OK) {
510  this->log_WARNING_HI_FileHdrDesError(fullFile, desStat);
511  return 0;
512  }
513 
514  // skip adding an already transmitted file
515  if (container.getState() == Fw::DpState::TRANSMITTED) {
516  this->log_ACTIVITY_HI_DpFileSkipped(fullFile);
517  return 0;
518  }
519 
520  // add entry to catalog.
521  DpStateEntry entry;
522  entry.dir = static_cast<FwIndexType>(dir);
523  entry.record.set_id(container.getId());
524  entry.record.set_priority(container.getPriority());
525  entry.record.set_state(container.getState());
526  entry.record.set_tSec(container.getTimeTag().getSeconds());
527  entry.record.set_tSub(container.getTimeTag().getUSeconds());
528  entry.record.set_size(static_cast<U64>(fileSize));
529 
530  // check the state file to see if there is transmit state
531  this->getFileState(entry);
532 
533  // insert entry into sorted list. if can't insert, quit
534  DpBtreeNode* addedEntry = this->insertEntry(entry);
535  if (addedEntry == nullptr) {
536  this->log_WARNING_HI_DpInsertError(entry.record);
537  // return and hope new slots open up later
538  return -1;
539  }
540 
541  // increment our counters
542  this->m_pendingFiles++;
543  this->m_pendingDpBytes += entry.record.get_size();
544 
545  // make sure we haven't exceeded the limit
546  if (this->m_pendingFiles > this->m_numDpSlots) {
547  this->log_WARNING_HI_DpCatalogFull(entry.record);
548  return -1;
549  }
550 
551  Fw::FileNameString addedFileName;
552  addedFileName.format(DP_FILENAME_FORMAT, this->m_directories[dir].toChar(), entry.record.get_id(),
553  entry.record.get_tSec(), entry.record.get_tSub());
554 
555  this->log_ACTIVITY_HI_DpFileAdded(addedFileName);
556 
557  // Compute relative priority to current exploration node
558  // For Handling adding a node to a catalog that has
559  // already moved past the inserted node's priority
560  if (this->m_currentNode == nullptr) {
561  this->m_currentNode = addedEntry;
562  } else if (entry < this->m_currentNode->entry) {
563  this->m_currentNode = addedEntry;
564  }
565 
566  return 1;
567 }
568 
569 // ----------------------------------------------------------------------
570 // DpStateEntry Comparison Ops
571 // ----------------------------------------------------------------------
572 int DpCatalog::DpStateEntry::compareEntries(const DpStateEntry& left, const DpStateEntry& right) {
573  // check priority. Lower is higher priority
574  if (left.record.get_priority() < right.record.get_priority()) {
575  return -1;
576  } else if (left.record.get_priority() > right.record.get_priority()) {
577  return 1;
578  }
579 
580  // check time. Older is higher priority
581  else if (left.record.get_tSec() < right.record.get_tSec()) {
582  return -1;
583  } else if (left.record.get_tSec() > right.record.get_tSec()) {
584  return 1;
585  }
586 
587  // check subsecond time. Older is higher priority
588  else if (left.record.get_tSub() < right.record.get_tSub()) {
589  return -1;
590  } else if (left.record.get_tSub() > right.record.get_tSub()) {
591  return 1;
592  }
593 
594  // check ID. Lower is higher priority
595  else if (left.record.get_id() < right.record.get_id()) {
596  return -1;
597  } else if (left.record.get_id() > right.record.get_id()) {
598  return 1;
599  }
600 
601  // if ids are equal we have two nodes with the same value
602  else {
603  return 0;
604  }
605 }
606 
607 bool DpCatalog::DpStateEntry::operator==(const DpStateEntry& other) const {
608  return compareEntries(*this, other) == 0;
609 }
610 bool DpCatalog::DpStateEntry::operator!=(const DpStateEntry& other) const {
611  return compareEntries(*this, other) != 0;
612 }
613 
614 bool DpCatalog::DpStateEntry::operator>(const DpStateEntry& other) const {
615  return compareEntries(*this, other) > 0;
616 }
617 bool DpCatalog::DpStateEntry::operator<(const DpStateEntry& other) const {
618  return compareEntries(*this, other) < 0;
619 }
620 
621 DpCatalog::DpBtreeNode* DpCatalog::insertEntry(DpStateEntry& entry) {
622  // the tree is filled in the following priority order:
623  // 1. DP priority - lower number is higher priority
624  // 2. DP time - older is higher priority
625  // 3. DP ID - lower number is higher priority
626 
627  // Higher priority is to the left of the tree
628 
629  // if the tree is empty, add the first entry
630  if (this->m_dpTree == nullptr) {
631  bool goodInsert = this->allocateNode(this->m_dpTree, entry);
632  if (not goodInsert) {
633  return nullptr;
634  }
635 
636  return this->m_dpTree;
637 
638  // otherwise, search depth-first to sort the entry
639  } else {
640  // to avoid recursion, loop through a max of the number of available records
641  DpBtreeNode* node = this->m_dpTree;
642  for (FwSizeType record = 0; record < this->m_numDpSlots; record++) {
643  CheckStat stat = CheckStat::CHECK_CONT;
644  stat = this->checkLeftRight(entry < node->entry, node, entry);
645 
646  // act on status
647  if (stat == CheckStat::CHECK_ERROR) {
648  return nullptr;
649  } else if (stat == CheckStat::CHECK_OK) {
650  return node;
651  }
652  } // end for each possible record
653 
654  return nullptr;
655  }
656 }
657 
658 DpCatalog::CheckStat DpCatalog::checkLeftRight(bool condition, DpBtreeNode*& node, const DpStateEntry& newEntry) {
659  if (condition) {
660  if (node->left == nullptr) {
661  bool allocated = this->allocateNode(node->left, newEntry);
662  if (not allocated) {
663  return CheckStat::CHECK_ERROR;
664  }
665  node->left->parent = node;
666  // Let the caller know where node ended up
667  node = node->left;
668  return CheckStat::CHECK_OK;
669  } else {
670  node = node->left;
671  return CheckStat::CHECK_CONT;
672  }
673  } else {
674  if (node->right == nullptr) {
675  bool allocated = this->allocateNode(node->right, newEntry);
676  if (not allocated) {
677  return CheckStat::CHECK_ERROR;
678  }
679  node->right->parent = node;
680  // Let the caller know where node ended up
681  node = node->right;
682  return CheckStat::CHECK_OK;
683  } else {
684  node = node->right;
685  return CheckStat::CHECK_CONT;
686  }
687  }
688 }
689 
690 bool DpCatalog::allocateNode(DpBtreeNode*& newNode, const DpStateEntry& newEntry) {
691  // should always be null since we are allocating an empty slot
692  FW_ASSERT(newNode == nullptr);
693  // make sure there is an entry from the free list
694  if (this->m_freeListHead == nullptr) {
695  this->log_WARNING_HI_DpCatalogFull(newEntry.record);
696  return false;
697  }
698 
699  // get a new node from the free list
700  newNode = this->m_freeListHead;
701  // move the head of the free list to the next node
702  // If we've at the bottom of the free list, head will now be nullptr
703  this->m_freeListHead = this->m_freeListHead->left;
704 
705  // initialize the new node
706  newNode->left = nullptr;
707  newNode->right = nullptr;
708  newNode->parent = nullptr;
709  newNode->entry = newEntry;
710 
711  // we got one, so return success
712  return true;
713 }
714 
715 void DpCatalog::deallocateNode(DpBtreeNode* node) {
716  DpBtreeNode* parent = node->parent;
717 
718  // since nodes are deallocated after xmit, left should be gone
719  // However, left node could be added during xmit
720  if (node->left != nullptr) {
721  // Since we aren't limited to adding just 1 node during file transfer
722  // the left child might not be a leaf
723  // Instead, find the node of closest (but higher) priority to this node
724  // This is the lowest priority node on the left branch
725  // Which is the rightmost node of the left branch
726  DpBtreeNode* rightmostNode = node->left;
727 
728  // (i.e. node->left->right->right ... ->right until we hit null)
729 
730  // bounded while loop (in case we're linked onto the free list somehow)
731  for (FwSizeType record = 0; record < this->m_numDpSlots && rightmostNode->right != nullptr; record++) {
732  rightmostNode = rightmostNode->right;
733 
734  // I really hope these never fire
735  FW_ASSERT(rightmostNode != this->m_freeListHead);
736  FW_ASSERT(rightmostNode != nullptr);
737  }
738 
739  FW_ASSERT(rightmostNode != nullptr);
740  FW_ASSERT(rightmostNode->parent != nullptr);
741 
742  // We can then swap the node to be deallocated w/ the rightmost
743  // (since it is immediately higher priority than us)
744 
745  // Make the "parent" of the deallocated node point at the rightmost
746  if (parent == nullptr) {
747  // this is the root node: has no parent, but needs the root pointer to shift
748  this->m_dpTree = rightmostNode;
749  } else {
750  // patch onto the appropriate parent branch
751  if (parent->left == node) {
752  parent->left = rightmostNode;
753  } else {
754  parent->right = rightmostNode;
755  }
756  }
757 
758  // Handle the children of the rightmost node
759  if (rightmostNode == node->left) {
760  // The rightmost node is the immediate left child of the deallocated node
761  // Since it only has left children, shift the left branch up
762  // with node->left taking the place of the deallocated node
763 
764  // Nothing we need to do
765  // Just avoid the infinite loop that would occur in this case
766  // on the other branch
767  } else {
768  // If the rightmost node isn't the node to be deallocated's left child,
769  // we can stitch its left branch onto its parent in its place
770  rightmostNode->parent->right = rightmostNode->left;
771 
772  // Now connect the deallocated node's left branch onto rightmostNode
773  rightmostNode->left = node->left;
774  node->left->parent = rightmostNode;
775  }
776 
777  // Regardless, connect the deallocated node's right branch onto rightmostNode
778  rightmostNode->right = node->right;
779 
780  if (node->right != nullptr) {
781  node->right->parent = rightmostNode;
782  }
783 
784  // Now that we're done using the parent of rightmost node
785  // Point at actual parent or nullptr if this is the new root
786  rightmostNode->parent = parent;
787 
788  // Ensure the Left node no longer points at us
789  FW_ASSERT(node->left->parent != node);
790  } else {
791  // This node only had a right branch
792  // cut out this node and shift the right branch up
793 
794  // The root node has no parent, but needs the tree root pointer to shift
795  if (parent == nullptr) {
796  this->m_dpTree = node->right;
797  } else {
798  // Patch the right branch onto
799  // the appropriate parent branch of this node
800  if (parent->left == node) {
801  parent->left = node->right;
802  } else {
803  parent->right = node->right;
804  }
805  }
806 
807  // If there is a right branch
808  // Point it at the parent of the removed node
809  if (node->right != nullptr) {
810  FW_ASSERT(node->right->parent != nullptr);
811  node->right->parent = parent;
812  }
813  }
814 
815  // clear out the entry
816  node->entry = {};
817  // point this node @ the old head of the free list
818  node->left = m_freeListHead;
819 
820  // Ensure the Right node no longer points at us
821  if (node->right != nullptr) {
822  FW_ASSERT(node->right->parent != node);
823  }
824 
825  // clear out our right reference
826  node->right = nullptr;
827 
828  DpBtreeNode* oldFreeListHead = this->m_freeListHead;
829  // make this node the new head of the free list
830  this->m_freeListHead = node;
831 
832  // Node is the head of the free list
833  FW_ASSERT(this->m_freeListHead == node);
834 
835  node->parent = nullptr;
836 
837  // Ensure this Node only points at next in free list
838  FW_ASSERT(node->left == oldFreeListHead);
839  FW_ASSERT(node->right == nullptr);
840  FW_ASSERT(node->parent == nullptr);
841 }
842 
843 void DpCatalog::sendNextEntry() {
844  // Use xmit flag to break upon STOP_XMIT_CATALOG
845  if (this->m_xmitInProgress != true) {
846  return;
847  }
848 
849  // look in the tree for the next entry to send
850  this->m_currentXmitNode = this->findNextTreeNode();
851 
852  if (this->m_currentXmitNode == nullptr) {
853  // if no entry found, we are done
854  this->m_xmitInProgress = false;
855  this->log_ACTIVITY_HI_CatalogXmitCompleted(this->m_xmitBytes);
856  this->dispatchWaitedResponse(Fw::CmdResponse::OK);
857  return;
858  } else {
859  // build file name based on the found entry
860  this->m_currXmitFileName.format(
861  DP_FILENAME_FORMAT, this->m_directories[this->m_currentXmitNode->entry.dir].toChar(),
862  this->m_currentXmitNode->entry.record.get_id(), this->m_currentXmitNode->entry.record.get_tSec(),
863  this->m_currentXmitNode->entry.record.get_tSub());
864  this->log_ACTIVITY_LO_SendingProduct(this->m_currXmitFileName,
865  static_cast<U32>(this->m_currentXmitNode->entry.record.get_size()),
866  this->m_currentXmitNode->entry.record.get_priority());
867  Svc::SendFileResponse resp = this->fileOut_out(0, this->m_currXmitFileName, this->m_currXmitFileName, 0, 0);
868  if (resp.get_status() != Svc::SendFileStatus::STATUS_OK) {
869  // warn, but keep going since it may be an issue with this file but others could
870  // make it
871  this->log_WARNING_HI_DpFileSendError(this->m_currXmitFileName, resp.get_status());
872  }
873  }
874 
875 } // end sendNextEntry()
876 
877 DpCatalog::DpBtreeNode* DpCatalog::findNextTreeNode() {
878  // check some asserts
879  FW_ASSERT(this->m_xmitInProgress);
880 
881  if (this->m_dpTree == nullptr) {
882  // We've run out of entries, we are done
883  this->m_xmitInProgress = false;
884  return nullptr;
885  }
886 
887  // start back at the top
888  if (this->m_currentNode == nullptr) {
889  this->m_currentNode = this->m_dpTree;
890  }
891 
892  // Nav left until nullptr
893  // Leads to highest priority node
894  // bounded while loop (in case we're linked onto the free list somehow)
895  for (FwSizeType record = 0; record < this->m_numDpSlots && this->m_currentNode->left != nullptr; record++) {
896  this->m_currentNode = this->m_currentNode->left;
897 
898  // I really hope these never fire
899  FW_ASSERT(this->m_currentNode != this->m_freeListHead);
900  FW_ASSERT(this->m_currentNode != nullptr);
901  }
902 
903  // save the high prio & find next best
904  DpBtreeNode* found = this->m_currentNode;
905 
906  // On the next cycle, explore the node to the right, if available,
907  // otherwise the node above
908  if (this->m_currentNode->right != nullptr) {
909  this->m_currentNode = this->m_currentNode->right;
910  } else {
911  this->m_currentNode = this->m_currentNode->parent;
912  }
913 
914  return found;
915 }
916 
917 bool DpCatalog::checkInit() {
918  if (not this->m_initialized) {
920  return false;
921  } else if (0 == this->m_numDpSlots) {
923  return false;
924  }
925 
926  return true;
927 }
928 
930  // only try to deallocate if both pointers are non-zero
931  // it's a way to more gracefully shut down if there are missing
932  // pointers
933  if ((this->m_allocator != nullptr) and (this->m_memPtr != nullptr)) {
934  this->m_allocator->deallocate(this->m_allocatorId, this->m_memPtr);
935  }
936 }
937 
938 // ----------------------------------------------------------------------
939 // Handler implementations for user-defined typed input ports
940 // ----------------------------------------------------------------------
941 
942 void DpCatalog ::fileDone_handler(FwIndexType portNum, const Svc::SendFileResponse& resp) {
943  // check file status
945  this->log_WARNING_HI_DpFileXmitError(this->m_currXmitFileName, resp.get_status());
946  this->m_xmitInProgress = false;
947  this->dispatchWaitedResponse(Fw::CmdResponse::EXECUTION_ERROR);
948  }
949 
950  // Catalog cleared while this file was sent
951  if (!this->m_catalogBuilt) {
952  return;
953  }
954 
955  // Since catalog built flag is true
956  // we should have a tree w/ at least one element
957  FW_ASSERT(this->m_dpTree);
958 
959  // Reduce pending
960  this->m_pendingDpBytes -= this->m_currentXmitNode->entry.record.get_size();
961  this->m_pendingFiles--;
962  // Log File Complete & pending
963  this->log_ACTIVITY_LO_ProductComplete(this->m_currXmitFileName, this->m_pendingFiles, this->m_pendingDpBytes);
964 
965  // mark the entry as transmitted
966  this->m_currentXmitNode->entry.record.set_state(Fw::DpState::TRANSMITTED);
967  // update the transmitted state in the state file
968  this->appendFileState(this->m_currentXmitNode->entry);
969  // add the size
970  this->m_xmitBytes += this->m_currentXmitNode->entry.record.get_size();
971  // deallocate this node
972  this->deallocateNode(this->m_currentXmitNode);
973  // send the next entry, if it exists
974  this->sendNextEntry();
975 }
976 
977 void DpCatalog ::pingIn_handler(FwIndexType portNum, U32 key) {
978  // return code for health ping
979  this->pingOut_out(0, key);
980 }
981 
982 void DpCatalog ::addToCat_handler(FwIndexType portNum,
983  const Fw::StringBase& fileName,
984  FwDpPriorityType priority,
985  FwSizeType size) {
986  // check initialization
987  if (not this->checkInit()) {
988  return;
989  }
990 
991  // check that initialization got memory
992  if (0 == this->m_numDpSlots) {
994  return;
995  }
996 
997  // Check the catalog has been built
998  if (not this->m_catalogBuilt) {
999  this->log_ACTIVITY_HI_NotLoaded(fileName);
1000  return;
1001  }
1002 
1003  // Both of these are grabbed from the header
1004  (void)priority;
1005  (void)size;
1006 
1007  // Since this is a runtime addition
1008  // Check if file is in one of our directories
1009  FwSizeType dir = this->determineDirectory(fileName);
1010 
1011  // Not in one of our directories; skip this file
1012  if (dir == DP_MAX_DIRECTORIES) {
1013  this->log_WARNING_HI_DirectoryNotManaged(fileName);
1014  return;
1015  }
1016 
1017  // ret > 0 := success
1018  int ret = processFile(fileName, dir);
1019 
1020  if (ret > 0) {
1021  // If we already finished, sendNext only if remainingActive
1022  if (!this->m_xmitInProgress && this->m_remainActive) {
1023  this->m_currentNode = this->m_dpTree;
1024  this->m_xmitInProgress = true;
1025  this->sendNextEntry();
1026  }
1027  // Otherwise, Current File finishing will invoke sendNextFile & find the right file
1028  // Or will be manually tx-ed at next command
1029 
1030  // prune and rewrite the state file
1031  this->pruneAndWriteStateFile();
1032  }
1033 }
1034 
1035 // ----------------------------------------------------------------------
1036 // Handler implementations for commands
1037 // ----------------------------------------------------------------------
1038 
1039 void DpCatalog ::BUILD_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
1040  // invoke helper
1041  this->cmdResponse_out(opCode, cmdSeq, this->doCatalogBuild());
1042 }
1043 
1044 void DpCatalog ::START_XMIT_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Fw::Wait wait, bool remainActive) {
1045  Fw::CmdResponse resp = this->doCatalogXmit();
1046  this->m_remainActive = remainActive;
1047 
1048  if (resp != Fw::CmdResponse::OK) {
1049  this->cmdResponse_out(opCode, cmdSeq, resp);
1050  } else {
1051  if (Fw::Wait::NO_WAIT == wait) {
1052  this->cmdResponse_out(opCode, cmdSeq, resp);
1053  this->m_xmitCmdWait = false;
1054  this->m_xmitOpCode = 0;
1055  this->m_xmitCmdSeq = 0;
1056  } else {
1057  this->m_xmitCmdWait = true;
1058  this->m_xmitOpCode = opCode;
1059  this->m_xmitCmdSeq = cmdSeq;
1060  }
1061  }
1062 }
1063 
1064 Fw::CmdResponse DpCatalog::doCatalogXmit() {
1065  // check initialization
1066  if (not this->checkInit()) {
1068  }
1069 
1070  // check that initialization got memory
1071  if (0 == this->m_numDpSlots) {
1072  this->log_WARNING_HI_NoDpMemory();
1074  }
1075 
1076  // make sure a downlink is not in progress
1077  if (this->m_xmitInProgress) {
1080  }
1081 
1082  // Check the catalog has been built
1083  if (not this->m_catalogBuilt) {
1086  }
1087 
1088  // start transmission
1089  this->m_xmitBytes = 0;
1090 
1091  this->m_xmitInProgress = true;
1092  // Step 3b - search for and send first entry
1093  this->sendNextEntry();
1094  return Fw::CmdResponse::OK;
1095 }
1096 
1097 void DpCatalog ::STOP_XMIT_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
1098  if (not this->m_xmitInProgress) {
1100  // benign error, so don't fail the command
1101  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
1102  } else {
1103  this->log_ACTIVITY_HI_CatalogXmitStopped(this->m_xmitBytes);
1104  // Disarm the flag so next sendNextEntry stops transmission
1105  this->m_xmitInProgress = false;
1106  // Respond to original cmd to start xmit
1107  // (if we haven't already)
1108  this->dispatchWaitedResponse(Fw::CmdResponse::OK);
1109 
1110  // Respond to this command
1111  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
1112  }
1113 }
1114 
1115 void DpCatalog ::CLEAR_CATALOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
1116  this->resetBinaryTree();
1117  this->resetStateFileData();
1118 
1119  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
1120 }
1121 
1122 void DpCatalog ::dispatchWaitedResponse(Fw::CmdResponse response) {
1123  if (this->m_xmitCmdWait) {
1124  this->cmdResponse_out(this->m_xmitOpCode, this->m_xmitCmdSeq, response);
1125 
1126  // Prevent a Duplicate Cmd Response
1127  this->m_xmitCmdWait = false;
1128  this->m_xmitOpCode = 0;
1129  this->m_xmitCmdSeq = 0;
1130  }
1131 }
1132 
1133 } // namespace Svc
void log_WARNING_HI_DpCatalogFull(Svc::DpRecord dp)
Serialization/Deserialization operation was successful.
A data product Container.
Definition: DpContainer.hpp:26
Status readDirectory(Fw::String filenameArray[], const FwSizeType arraySize, FwSizeType &filenameCount)
Read the contents of the directory and store filenames in filenameArray of size arraySize.
Definition: Directory.cpp:113
void pingOut_out(FwIndexType portNum, U32 key) const
Invoke output port pingOut.
FwDpPriorityType getPriority() const
virtual void * allocate(const FwEnumStoreType identifier, FwSizeType &size, bool &recoverable, FwSizeType alignment=alignof(std::max_align_t))=0
void log_WARNING_HI_StateFileTruncated(const Fw::StringBase &file, I32 offset, I32 size) const
Log event StateFileTruncated.
FwIdType FwOpcodeType
The type of a command opcode.
void log_WARNING_HI_DirectoryOpenError(const Fw::StringBase &loc, I32 stat) const
void log_WARNING_HI_DpFileXmitError(const Fw::StringBase &file, Svc::SendFileStatus stat)
Log event DpFileXmitError.
PlatformSizeType FwSizeType
U32 FwDpPriorityType
The type of a data product priority.
void log_ACTIVITY_HI_NotLoaded(const Fw::StringBase &file) const
Log event NotLoaded.
void log_WARNING_HI_DpInsertError(Svc::DpRecord dp)
I32 FwEnumStoreType
Auto-generated base for DpCatalog component.
FwSignedSizeType substring_find(const CHAR *source_string, FwSizeType source_size, const CHAR *sub_string, FwSizeType sub_size)
find the first occurrence of a substring
Definition: StringUtils.cpp:35
Wait or don&#39;t wait for something.
Definition: WaitEnumAc.hpp:17
static constexpr FwSizeType MIN_PACKET_SIZE
Definition: DpContainer.hpp:65
static const FwIndexType DP_MAX_DIRECTORIES
const char * toChar() const
Convert to a C-style char*.
Definition: String.hpp:50
Svc::SendFileResponse fileOut_out(FwIndexType portNum, const Fw::StringBase &sourceFileName, const Fw::StringBase &destFileName, U32 offset, U32 length) const
Invoke output port fileOut.
Svc::SendFileStatus::T get_status() const
Get member status.
Overwrite file when it exists and creation was requested.
Definition: File.hpp:58
PlatformSignedSizeType FwSignedSizeType
void log_WARNING_HI_StateFileOpenError(const Fw::StringBase &file, I32 stat) const
Log event StateFileOpenError.
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
Enum representing a command response.
void log_WARNING_HI_DpFileSendError(const Fw::StringBase &file, Svc::SendFileStatus stat)
Log event DpFileSendError.
#define DIRECTORY_DELIMITER
Definition: DpCatalog.hpp:19
void log_ACTIVITY_HI_DpFileAdded(const Fw::StringBase &file) const
void setBuffer(const Buffer &buffer)
Set the packet buffer.
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
SerializeStatus
forward declaration for string
void log_WARNING_HI_FileOpenError(const Fw::StringBase &loc, I32 stat)
void log_ACTIVITY_LO_ProductComplete(const Fw::StringBase &file, U32 pending, U64 pending_bytes) const
void log_WARNING_HI_NoDpMemory() const
Log event NoDpMemory.
void log_WARNING_HI_FileSizeError(const Fw::StringBase &file, I32 stat)
The transmitted state.
void log_WARNING_HI_FileReadError(const Fw::StringBase &file, I32 stat)
const char * toChar() const
Convert to a C-style char*.
Open file for appending.
Definition: File.hpp:36
void log_ACTIVITY_HI_DpFileSkipped(const Fw::StringBase &file) const
void configure(Fw::FileNameString directories[DP_MAX_DIRECTORIES], FwSizeType numDirs, Fw::FileNameString &stateFile, FwEnumStoreType memId, Fw::MemAllocator &allocator)
Configure the DpCatalog.
Definition: DpCatalog.cpp:28
void log_ACTIVITY_LO_ProcessingDirectory(const Fw::StringBase &directory) const
void log_ACTIVITY_HI_ProcessingDirectoryComplete(const Fw::StringBase &loc, U32 total, U32 pending, U64 pending_bytes) const
void log_ACTIVITY_LO_SendingProduct(const Fw::StringBase &file, U32 bytes, U32 prio) const
void log_WARNING_LO_NoStateFileSpecified() const
Log event NoStateFileSpecified.
External serialize buffer with no copy semantics.
U32 getSeconds() const
Definition: Time.cpp:118
constexpr const char * DP_FILENAME_FORMAT
Definition: DpCfg.hpp:21
Fw::Time getTimeTag() const
void close() override
close the file, if not opened then do nothing
Definition: File.cpp:96
Status write(const U8 *buffer, FwSizeType &size)
write data to this file from the supplied buffer bounded by size
Definition: File.cpp:213
void log_WARNING_LO_XmitNotActive() const
Log event XmitNotActive.
void log_ACTIVITY_HI_CatalogXmitCompleted(U64 bytes) const
void log_ACTIVITY_LO_ProcessingFile(const Fw::StringBase &file) const
static const FwIndexType DP_MAX_FILES
FormatStatus format(const CHAR *formatString,...)
write formatted string to buffer
Definition: StringBase.cpp:39
Command successfully executed.
void log_ACTIVITY_HI_CatalogXmitStopped(U64 bytes) const
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:53
DpCatalog(const char *const compName)
DpCatalog constructor.
Definition: DpCatalog.cpp:24
Directory class.
Definition: Directory.hpp:114
static Status getFileSize(const char *path, FwSizeType &size)
Get the size of the file (in bytes) at the specified path.
Definition: FileSystem.cpp:226
FwSignedSizeType substring_find_last(const CHAR *source_string, FwSizeType source_size, const CHAR *sub_string, FwSizeType sub_size)
find the last occurrence of a substring
Definition: StringUtils.cpp:77
Status read(U8 *buffer, FwSizeType &size)
read data from this file into supplied buffer bounded by size
Definition: File.cpp:194
Command had execution error.
void log_WARNING_HI_StateFileReadError(const Fw::StringBase &file, I32 stat, I32 offset) const
Log event StateFileReadError.
Fw::DpState getState() const
Get the product state.
void log_WARNING_HI_DirectoryNotManaged(const Fw::StringBase &file) const
Memory Allocation base class.
void log_WARNING_HI_CatalogFull(const Fw::StringBase &dir)
Operation was successful.
Definition: File.hpp:41
U32 getUSeconds() const
Definition: Time.cpp:122
void log_WARNING_HI_XmitUnbuiltCatalog() const
Log event XmitUnbuiltCatalog.
PlatformIndexType FwIndexType
void log_WARNING_HI_FileHdrDesError(const Fw::StringBase &file, I32 stat)
Operation was successful.
Definition: Directory.hpp:20
Open file for reading.
Definition: File.hpp:32
Send file response struct.
static constexpr FwSizeType SIZE
The header size.
Definition: DpContainer.hpp:55
#define DP_EXT
Definition: DpCfg.hpp:20
Status open(const char *path, OpenMode mode) override
Open or create a directory.
Definition: Directory.cpp:31
RateGroupDivider component implementation.
virtual SizeType length() const
Get the length of the string.
U8 BYTE
byte type
Definition: BasicTypes.h:56
Fw::SerializeStatus deserializeHeader()
Definition: DpContainer.cpp:38
Operation was successful.
Definition: FileSystem.hpp:24
virtual void deallocate(const FwEnumStoreType identifier, void *ptr)=0
Invalid size parameter.
Definition: File.hpp:45
FwDpIdType getId() const
Definition: DpContainer.hpp:98
Don&#39;t wait for something.
Definition: WaitEnumAc.hpp:35
The size of the serial representation.
#define FW_ASSERT(...)
Definition: Assert.hpp:14
void log_WARNING_HI_StateFileWriteError(const Fw::StringBase &file, I32 stat) const
Log event StateFileWriteError.
FwSizeType string_length(const CHAR *source, FwSizeType buffer_size)
get the length of the source string
Definition: StringUtils.cpp:24
Open file for writing and truncates file if it exists, ie same flags as creat()
Definition: File.hpp:33