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");
36 this->m_stateFile = stateFile;
45 static const FwSizeType slotSize =
sizeof(DpBtreeNode) +
sizeof(DpDstateFileEntry);
49 this->m_memPtr = allocator.
allocate(memId, this->m_memSize, notUsed);
67 if ((this->m_memSize >= slotSize) and (this->m_memPtr !=
nullptr)) {
69 this->m_numDpSlots = this->m_memSize / slotSize;
70 this->resetBinaryTree();
72 this->m_stateFileData =
reinterpret_cast<DpDstateFileEntry*
>(&this->m_freeListHead[this->m_numDpSlots]);
76 this->m_numDpSlots = 0;
80 for (
FwSizeType dir = 0; dir < numDirs; dir++) {
81 this->m_directories[dir] = directories[dir];
83 this->m_numDirectories = numDirs;
86 this->m_allocator = &allocator;
87 this->m_allocatorId = memId;
88 this->m_initialized =
true;
91 void DpCatalog::resetBinaryTree() {
95 this->m_freeListHead =
static_cast<DpBtreeNode*
>(this->m_memPtr);
96 for (
FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) {
98 (void)
new (&this->m_freeListHead[slot]) DpBtreeNode();
99 this->m_freeListHead[slot].left =
nullptr;
100 this->m_freeListHead[slot].right =
nullptr;
103 this->m_freeListHead[slot - 1].left = &this->m_freeListHead[slot];
107 this->m_dpTree =
nullptr;
109 this->m_pendingFiles = 0;
110 this->m_pendingDpBytes = 0;
112 this->m_catalogBuilt =
false;
115 void DpCatalog::resetStateFileData() {
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();
122 this->m_stateFileEntries = 0;
129 if (this->m_stateFile.
length() == 0) {
148 this->m_stateFileEntries = 0;
151 for (
FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) {
154 stat = stateFile.
read(buffer, size);
168 if (size !=
sizeof(buffer)) {
170 static_cast<I32>(size));
175 Fw::SerializeStatus serStat = entryBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(size));
178 entryBuffer.resetDeser();
184 Fw::SerializeStatus status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.dir);
186 status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.record);
188 this->m_stateFileData[entry].used =
true;
189 this->m_stateFileData[entry].visited =
false;
193 this->m_stateFileEntries++;
199 void DpCatalog::getFileState(DpStateEntry& entry) {
202 for (
FwSizeType line = 0; line < this->m_stateFileEntries; line++) {
204 if (this->m_stateFileData[line].entry.dir == entry.dir && this->m_stateFileData[line].entry == entry) {
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());
209 this->m_stateFileData[line].visited =
true;
215 void DpCatalog::pruneAndWriteStateFile() {
240 for (
FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) {
242 if ((this->m_stateFileData[entry].used) and (this->m_stateFileData[entry].visited)) {
244 entryBuffer.resetSer();
246 Fw::SerializeStatus serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.dir);
249 serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.record);
255 stat = stateFile.
write(buffer, size);
267 void DpCatalog::appendFileState(
const DpStateEntry& entry) {
269 FW_ASSERT(entry.dir < static_cast<FwIndexType>(this->m_numDirectories), static_cast<FwAssertArgType>(entry.dir),
270 static_cast<FwAssertArgType>(this->m_numDirectories));
286 BYTE buffer[
sizeof(entry.dir) +
sizeof(entry.record)];
289 entryBuffer.resetSer();
294 serStat = entryBuffer.serializeFrom(entry.record);
299 stat = stateFile.
write(buffer, size);
311 if (not this->checkInit()) {
316 if (0 == this->m_numDpSlots) {
322 if (this->m_xmitInProgress) {
328 this->resetStateFileData();
334 this->resetBinaryTree();
337 response = this->fillBinaryTree();
340 this->resetBinaryTree();
341 this->resetStateFileData();
346 this->pruneAndWriteStateFile();
351 this->m_catalogBuilt =
true;
366 U32 filesProcessed = 0;
374 status = dpDir.
readDirectory(this->m_fileList, (this->m_numDpSlots - totalFiles), filesRead);
382 FW_ASSERT(filesRead <= this->m_numDpSlots - totalFiles, static_cast<FwAssertArgType>(filesRead),
383 static_cast<FwAssertArgType>(this->m_numDpSlots - totalFiles));
386 for (
FwSizeType file = 0; file < filesRead; file++) {
398 fullFile.
format(
"%s/%s", this->m_directories[dir].toChar(), this->m_fileList[file].toChar());
400 int ret = processFile(fullFile, dir);
405 filesProcessed +=
static_cast<U32
>(ret);
409 totalFiles += filesProcessed;
412 this->m_pendingFiles, this->m_pendingDpBytes);
416 if (totalFiles == this->m_numDpSlots) {
441 for (
FwSizeType dir = 0; dir < this->m_numDirectories; dir++) {
487 stat = dpFile.
read(dpBuff, size);
523 entry.record.set_id(container.
getId());
524 entry.record.set_priority(container.
getPriority());
525 entry.record.set_state(container.
getState());
528 entry.record.set_size(static_cast<U64>(fileSize));
531 this->getFileState(entry);
534 DpBtreeNode* addedEntry = this->insertEntry(entry);
535 if (addedEntry ==
nullptr) {
542 this->m_pendingFiles++;
543 this->m_pendingDpBytes += entry.record.get_size();
546 if (this->m_pendingFiles > this->m_numDpSlots) {
553 entry.record.get_tSec(), entry.record.get_tSub());
560 if (this->m_currentNode ==
nullptr) {
561 this->m_currentNode = addedEntry;
562 }
else if (entry < this->m_currentNode->entry) {
563 this->m_currentNode = addedEntry;
572 int DpCatalog::DpStateEntry::compareEntries(
const DpStateEntry& left,
const DpStateEntry& right) {
574 if (left.record.get_priority() < right.record.get_priority()) {
576 }
else if (left.record.get_priority() > right.record.get_priority()) {
581 else if (left.record.get_tSec() < right.record.get_tSec()) {
583 }
else if (left.record.get_tSec() > right.record.get_tSec()) {
588 else if (left.record.get_tSub() < right.record.get_tSub()) {
590 }
else if (left.record.get_tSub() > right.record.get_tSub()) {
595 else if (left.record.get_id() < right.record.get_id()) {
597 }
else if (left.record.get_id() > right.record.get_id()) {
607 bool DpCatalog::DpStateEntry::operator==(
const DpStateEntry& other)
const {
608 return compareEntries(*
this, other) == 0;
610 bool DpCatalog::DpStateEntry::operator!=(
const DpStateEntry& other)
const {
611 return compareEntries(*
this, other) != 0;
614 bool DpCatalog::DpStateEntry::operator>(
const DpStateEntry& other)
const {
615 return compareEntries(*
this, other) > 0;
617 bool DpCatalog::DpStateEntry::operator<(
const DpStateEntry& other)
const {
618 return compareEntries(*
this, other) < 0;
621 DpCatalog::DpBtreeNode* DpCatalog::insertEntry(DpStateEntry& entry) {
630 if (this->m_dpTree ==
nullptr) {
631 bool goodInsert = this->allocateNode(this->m_dpTree, entry);
632 if (not goodInsert) {
636 return this->m_dpTree;
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);
647 if (stat == CheckStat::CHECK_ERROR) {
649 }
else if (stat == CheckStat::CHECK_OK) {
658 DpCatalog::CheckStat DpCatalog::checkLeftRight(
bool condition, DpBtreeNode*& node,
const DpStateEntry& newEntry) {
660 if (node->left ==
nullptr) {
661 bool allocated = this->allocateNode(node->left, newEntry);
663 return CheckStat::CHECK_ERROR;
665 node->left->parent = node;
668 return CheckStat::CHECK_OK;
671 return CheckStat::CHECK_CONT;
674 if (node->right ==
nullptr) {
675 bool allocated = this->allocateNode(node->right, newEntry);
677 return CheckStat::CHECK_ERROR;
679 node->right->parent = node;
682 return CheckStat::CHECK_OK;
685 return CheckStat::CHECK_CONT;
690 bool DpCatalog::allocateNode(DpBtreeNode*& newNode,
const DpStateEntry& newEntry) {
694 if (this->m_freeListHead ==
nullptr) {
700 newNode = this->m_freeListHead;
703 this->m_freeListHead = this->m_freeListHead->left;
706 newNode->left =
nullptr;
707 newNode->right =
nullptr;
708 newNode->parent =
nullptr;
709 newNode->entry = newEntry;
715 void DpCatalog::deallocateNode(DpBtreeNode* node) {
716 DpBtreeNode* parent = node->parent;
720 if (node->left !=
nullptr) {
726 DpBtreeNode* rightmostNode = node->left;
731 for (
FwSizeType record = 0; record < this->m_numDpSlots && rightmostNode->right !=
nullptr; record++) {
732 rightmostNode = rightmostNode->right;
735 FW_ASSERT(rightmostNode != this->m_freeListHead);
740 FW_ASSERT(rightmostNode->parent !=
nullptr);
746 if (parent ==
nullptr) {
748 this->m_dpTree = rightmostNode;
751 if (parent->left == node) {
752 parent->left = rightmostNode;
754 parent->right = rightmostNode;
759 if (rightmostNode == node->left) {
770 rightmostNode->parent->right = rightmostNode->left;
773 rightmostNode->left = node->left;
774 node->left->parent = rightmostNode;
778 rightmostNode->right = node->right;
780 if (node->right !=
nullptr) {
781 node->right->parent = rightmostNode;
786 rightmostNode->parent = parent;
795 if (parent ==
nullptr) {
796 this->m_dpTree = node->right;
800 if (parent->left == node) {
801 parent->left = node->right;
803 parent->right = node->right;
809 if (node->right !=
nullptr) {
810 FW_ASSERT(node->right->parent !=
nullptr);
811 node->right->parent = parent;
818 node->left = m_freeListHead;
821 if (node->right !=
nullptr) {
826 node->right =
nullptr;
828 DpBtreeNode* oldFreeListHead = this->m_freeListHead;
830 this->m_freeListHead = node;
835 node->parent =
nullptr;
838 FW_ASSERT(node->left == oldFreeListHead);
843 void DpCatalog::sendNextEntry() {
845 if (this->m_xmitInProgress !=
true) {
850 this->m_currentXmitNode = this->findNextTreeNode();
852 if (this->m_currentXmitNode ==
nullptr) {
854 this->m_xmitInProgress =
false;
860 this->m_currXmitFileName.
format(
862 this->m_currentXmitNode->entry.record.get_id(), this->m_currentXmitNode->entry.record.get_tSec(),
863 this->m_currentXmitNode->entry.record.get_tSub());
865 static_cast<U32>(this->m_currentXmitNode->entry.record.get_size()),
866 this->m_currentXmitNode->entry.record.get_priority());
877 DpCatalog::DpBtreeNode* DpCatalog::findNextTreeNode() {
881 if (this->m_dpTree ==
nullptr) {
883 this->m_xmitInProgress =
false;
888 if (this->m_currentNode ==
nullptr) {
889 this->m_currentNode = this->m_dpTree;
895 for (
FwSizeType record = 0; record < this->m_numDpSlots && this->m_currentNode->left !=
nullptr; record++) {
896 this->m_currentNode = this->m_currentNode->left;
899 FW_ASSERT(this->m_currentNode != this->m_freeListHead);
900 FW_ASSERT(this->m_currentNode !=
nullptr);
904 DpBtreeNode* found = this->m_currentNode;
908 if (this->m_currentNode->right !=
nullptr) {
909 this->m_currentNode = this->m_currentNode->right;
911 this->m_currentNode = this->m_currentNode->parent;
917 bool DpCatalog::checkInit() {
918 if (not this->m_initialized) {
921 }
else if (0 == this->m_numDpSlots) {
933 if ((this->m_allocator !=
nullptr) and (this->m_memPtr !=
nullptr)) {
934 this->m_allocator->
deallocate(this->m_allocatorId, this->m_memPtr);
946 this->m_xmitInProgress =
false;
951 if (!this->m_catalogBuilt) {
960 this->m_pendingDpBytes -= this->m_currentXmitNode->entry.record.get_size();
961 this->m_pendingFiles--;
968 this->appendFileState(this->m_currentXmitNode->entry);
970 this->m_xmitBytes += this->m_currentXmitNode->entry.record.get_size();
972 this->deallocateNode(this->m_currentXmitNode);
974 this->sendNextEntry();
977 void DpCatalog ::pingIn_handler(
FwIndexType portNum, U32 key) {
982 void DpCatalog ::addToCat_handler(
FwIndexType portNum,
987 if (not this->checkInit()) {
992 if (0 == this->m_numDpSlots) {
998 if (not this->m_catalogBuilt) {
1009 FwSizeType dir = this->determineDirectory(fileName);
1018 int ret = processFile(fileName, dir);
1022 if (!this->m_xmitInProgress && this->m_remainActive) {
1023 this->m_currentNode = this->m_dpTree;
1024 this->m_xmitInProgress =
true;
1025 this->sendNextEntry();
1031 this->pruneAndWriteStateFile();
1039 void DpCatalog ::BUILD_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
1044 void DpCatalog ::START_XMIT_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq,
Fw::Wait wait,
bool remainActive) {
1046 this->m_remainActive = remainActive;
1053 this->m_xmitCmdWait =
false;
1054 this->m_xmitOpCode = 0;
1055 this->m_xmitCmdSeq = 0;
1057 this->m_xmitCmdWait =
true;
1058 this->m_xmitOpCode = opCode;
1059 this->m_xmitCmdSeq = cmdSeq;
1066 if (not this->checkInit()) {
1071 if (0 == this->m_numDpSlots) {
1077 if (this->m_xmitInProgress) {
1083 if (not this->m_catalogBuilt) {
1089 this->m_xmitBytes = 0;
1091 this->m_xmitInProgress =
true;
1093 this->sendNextEntry();
1097 void DpCatalog ::STOP_XMIT_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
1098 if (not this->m_xmitInProgress) {
1105 this->m_xmitInProgress =
false;
1115 void DpCatalog ::CLEAR_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
1116 this->resetBinaryTree();
1117 this->resetStateFileData();
1123 if (this->m_xmitCmdWait) {
1124 this->
cmdResponse_out(this->m_xmitOpCode, this->m_xmitCmdSeq, response);
1127 this->m_xmitCmdWait =
false;
1128 this->m_xmitOpCode = 0;
1129 this->m_xmitCmdSeq = 0;
void log_WARNING_HI_DpCatalogFull(Svc::DpRecord dp)
Serialization/Deserialization operation was successful.
A data product Container.
Status readDirectory(Fw::String filenameArray[], const FwSizeType arraySize, FwSizeType &filenameCount)
Read the contents of the directory and store filenames in filenameArray of size arraySize.
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.
void log_WARNING_HI_ComponentNoMemory()
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)
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
Wait or don't wait for something.
static constexpr FwSizeType MIN_PACKET_SIZE
static const FwIndexType DP_MAX_DIRECTORIES
const char * toChar() const
Convert to a C-style char*.
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.
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
void log_ACTIVITY_HI_DpFileAdded(const Fw::StringBase &file) const
void setBuffer(const Buffer &buffer)
Set the packet buffer.
void log_ACTIVITY_HI_CatalogBuildComplete() const
void log_WARNING_LO_DpXmitInProgress()
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)
void log_WARNING_HI_FileReadError(const Fw::StringBase &file, I32 stat)
const char * toChar() const
Convert to a C-style char*.
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.
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.
void log_WARNING_HI_ComponentNotInitialized()
constexpr const char * DP_FILENAME_FORMAT
Fw::Time getTimeTag() const
void close() override
close the file, if not opened then do nothing
Status write(const U8 *buffer, FwSizeType &size)
write data to this file from the supplied buffer bounded by size
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
Command successfully executed.
void log_ACTIVITY_HI_CatalogXmitStopped(U64 bytes) const
uint8_t U8
8-bit unsigned integer
DpCatalog(const char *const compName)
DpCatalog constructor.
static Status getFileSize(const char *path, FwSizeType &size)
Get the size of the file (in bytes) at the specified path.
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
Status read(U8 *buffer, FwSizeType &size)
read data from this file into supplied buffer bounded by size
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.
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.
Send file response struct.
Status open(const char *path, OpenMode mode) override
Open or create a directory.
RateGroupDivider component implementation.
virtual SizeType length() const
Get the length of the string.
Fw::SerializeStatus deserializeHeader()
Operation was successful.
virtual void deallocate(const FwEnumStoreType identifier, void *ptr)=0
Don't wait for something.
The size of the serial representation.
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
Open file for writing and truncates file if it exists, ie same flags as creat()