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