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");
28 m_freeListHead(nullptr),
29 m_currentNode(nullptr),
30 m_currentXmitNode(nullptr),
33 m_stateFileData(nullptr),
34 m_stateFileEntries(0),
39 m_catalogBuilt(false),
40 m_xmitInProgress(false),
47 m_remainActive(false) {}
59 this->m_stateFile = stateFile;
68 static const FwSizeType slotSize =
sizeof(DpBtreeNode) +
sizeof(DpDstateFileEntry);
72 this->m_memPtr = allocator.
allocate(memId, this->m_memSize, notUsed);
90 if ((this->m_memSize >= slotSize) and (this->m_memPtr !=
nullptr)) {
92 this->m_numDpSlots = this->m_memSize / slotSize;
93 this->resetBinaryTree();
95 this->m_stateFileData =
reinterpret_cast<DpDstateFileEntry*
>(&this->m_freeListHead[this->m_numDpSlots]);
99 this->m_numDpSlots = 0;
103 for (
FwSizeType dir = 0; dir < numDirs; dir++) {
104 this->m_directories[dir] = directories[dir];
106 this->m_numDirectories = numDirs;
109 this->m_allocator = &allocator;
110 this->m_allocatorId = memId;
111 this->m_initialized =
true;
114 void DpCatalog::resetBinaryTree() {
118 this->m_freeListHead =
static_cast<DpBtreeNode*
>(this->m_memPtr);
119 for (
FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) {
121 (void)
new (&this->m_freeListHead[slot]) DpBtreeNode();
122 this->m_freeListHead[slot].left =
nullptr;
123 this->m_freeListHead[slot].right =
nullptr;
126 this->m_freeListHead[slot - 1].left = &this->m_freeListHead[slot];
130 this->m_dpTree =
nullptr;
132 this->m_pendingFiles = 0;
133 this->m_pendingDpBytes = 0;
135 this->m_catalogBuilt =
false;
138 void DpCatalog::resetStateFileData() {
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();
145 this->m_stateFileEntries = 0;
152 if (this->m_stateFile.
length() == 0) {
171 this->m_stateFileEntries = 0;
174 for (
FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) {
177 stat = stateFile.
read(buffer, size);
191 if (size !=
sizeof(buffer)) {
193 static_cast<I32>(size));
198 Fw::SerializeStatus serStat = entryBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(size));
201 entryBuffer.resetDeser();
207 Fw::SerializeStatus status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.dir);
209 status = entryBuffer.deserializeTo(this->m_stateFileData[entry].entry.record);
211 this->m_stateFileData[entry].used =
true;
212 this->m_stateFileData[entry].visited =
false;
216 this->m_stateFileEntries++;
222 void DpCatalog::getFileState(DpStateEntry& entry) {
225 for (
FwSizeType line = 0; line < this->m_stateFileEntries; line++) {
227 if (this->m_stateFileData[line].entry.dir == entry.dir && this->m_stateFileData[line].entry == entry) {
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());
232 this->m_stateFileData[line].visited =
true;
238 void DpCatalog::pruneAndWriteStateFile() {
263 for (
FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) {
265 if ((this->m_stateFileData[entry].used) and (this->m_stateFileData[entry].visited)) {
267 entryBuffer.resetSer();
269 Fw::SerializeStatus serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.dir);
272 serStat = entryBuffer.serializeFrom(this->m_stateFileData[entry].entry.record);
278 stat = stateFile.
write(buffer, size);
290 void DpCatalog::appendFileState(
const DpStateEntry& entry) {
292 FW_ASSERT(entry.dir < static_cast<FwIndexType>(this->m_numDirectories), static_cast<FwAssertArgType>(entry.dir),
293 static_cast<FwAssertArgType>(this->m_numDirectories));
309 BYTE buffer[
sizeof(entry.dir) +
sizeof(entry.record)];
312 entryBuffer.resetSer();
317 serStat = entryBuffer.serializeFrom(entry.record);
322 stat = stateFile.
write(buffer, size);
334 if (not this->checkInit()) {
339 if (0 == this->m_numDpSlots) {
345 if (this->m_xmitInProgress) {
351 this->resetStateFileData();
357 this->resetBinaryTree();
360 response = this->fillBinaryTree();
363 this->resetBinaryTree();
364 this->resetStateFileData();
369 this->pruneAndWriteStateFile();
374 this->m_catalogBuilt =
true;
384 for (
FwSizeType dir = 0; dir < this->m_numDirectories; dir++) {
388 U32 filesProcessed = 0;
396 status = dpDir.
readDirectory(this->m_fileList, (this->m_numDpSlots - totalFiles), filesRead);
404 FW_ASSERT(filesRead <= this->m_numDpSlots - totalFiles, static_cast<FwAssertArgType>(filesRead),
405 static_cast<FwAssertArgType>(this->m_numDpSlots - totalFiles));
408 for (
FwSizeType file = 0; file < filesRead; file++) {
420 fullFile.
format(
"%s/%s", this->m_directories[dir].toChar(), this->m_fileList[file].toChar());
422 int ret = processFile(fullFile, dir);
427 filesProcessed +=
static_cast<U32
>(ret);
431 totalFiles += filesProcessed;
434 this->m_pendingFiles, this->m_pendingDpBytes);
438 if (totalFiles == this->m_numDpSlots) {
463 for (
FwSizeType dir = 0; dir < this->m_numDirectories; dir++) {
508 stat = dpFile.
read(dpBuff, size);
544 entry.record.set_id(container.
getId());
545 entry.record.set_priority(container.
getPriority());
546 entry.record.set_state(container.
getState());
549 entry.record.set_size(static_cast<U64>(fileSize));
552 this->getFileState(entry);
555 DpBtreeNode* addedEntry = this->insertEntry(entry);
556 if (addedEntry ==
nullptr) {
563 this->m_pendingFiles++;
564 this->m_pendingDpBytes += entry.record.get_size();
567 if (this->m_pendingFiles > this->m_numDpSlots) {
574 entry.record.get_tSec(), entry.record.get_tSub());
581 if (this->m_currentNode ==
nullptr) {
582 this->m_currentNode = addedEntry;
583 }
else if (entry < this->m_currentNode->entry) {
584 this->m_currentNode = addedEntry;
593 int DpCatalog::DpStateEntry::compareEntries(
const DpStateEntry& left,
const DpStateEntry& right) {
595 if (left.record.get_priority() < right.record.get_priority()) {
597 }
else if (left.record.get_priority() > right.record.get_priority()) {
602 else if (left.record.get_tSec() < right.record.get_tSec()) {
604 }
else if (left.record.get_tSec() > right.record.get_tSec()) {
609 else if (left.record.get_tSub() < right.record.get_tSub()) {
611 }
else if (left.record.get_tSub() > right.record.get_tSub()) {
616 else if (left.record.get_id() < right.record.get_id()) {
618 }
else if (left.record.get_id() > right.record.get_id()) {
628 bool DpCatalog::DpStateEntry::operator==(
const DpStateEntry& other)
const {
629 return compareEntries(*
this, other) == 0;
631 bool DpCatalog::DpStateEntry::operator!=(
const DpStateEntry& other)
const {
632 return compareEntries(*
this, other) != 0;
635 bool DpCatalog::DpStateEntry::operator>(
const DpStateEntry& other)
const {
636 return compareEntries(*
this, other) > 0;
638 bool DpCatalog::DpStateEntry::operator<(
const DpStateEntry& other)
const {
639 return compareEntries(*
this, other) < 0;
642 DpCatalog::DpBtreeNode* DpCatalog::insertEntry(DpStateEntry& entry) {
651 if (this->m_dpTree ==
nullptr) {
652 bool goodInsert = this->allocateNode(this->m_dpTree, entry);
653 if (not goodInsert) {
657 return this->m_dpTree;
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);
668 if (stat == CheckStat::CHECK_ERROR) {
670 }
else if (stat == CheckStat::CHECK_OK) {
679 DpCatalog::CheckStat DpCatalog::checkLeftRight(
bool condition, DpBtreeNode*& node,
const DpStateEntry& newEntry) {
681 if (node->left ==
nullptr) {
682 bool allocated = this->allocateNode(node->left, newEntry);
684 return CheckStat::CHECK_ERROR;
686 node->left->parent = node;
689 return CheckStat::CHECK_OK;
692 return CheckStat::CHECK_CONT;
695 if (node->right ==
nullptr) {
696 bool allocated = this->allocateNode(node->right, newEntry);
698 return CheckStat::CHECK_ERROR;
700 node->right->parent = node;
703 return CheckStat::CHECK_OK;
706 return CheckStat::CHECK_CONT;
711 bool DpCatalog::allocateNode(DpBtreeNode*& newNode,
const DpStateEntry& newEntry) {
715 if (this->m_freeListHead ==
nullptr) {
721 newNode = this->m_freeListHead;
724 this->m_freeListHead = this->m_freeListHead->left;
727 newNode->left =
nullptr;
728 newNode->right =
nullptr;
729 newNode->parent =
nullptr;
730 newNode->entry = newEntry;
736 void DpCatalog::deallocateNode(DpBtreeNode* node) {
737 DpBtreeNode* parent = node->parent;
741 if (node->left !=
nullptr) {
747 DpBtreeNode* rightmostNode = node->left;
752 for (
FwSizeType record = 0; record < this->m_numDpSlots && rightmostNode->right !=
nullptr; record++) {
753 rightmostNode = rightmostNode->right;
756 FW_ASSERT(rightmostNode != this->m_freeListHead);
761 FW_ASSERT(rightmostNode->parent !=
nullptr);
767 if (parent ==
nullptr) {
769 this->m_dpTree = rightmostNode;
772 if (parent->left == node) {
773 parent->left = rightmostNode;
775 parent->right = rightmostNode;
780 if (rightmostNode == node->left) {
791 rightmostNode->parent->right = rightmostNode->left;
794 rightmostNode->left = node->left;
795 node->left->parent = rightmostNode;
799 rightmostNode->right = node->right;
801 if (node->right !=
nullptr) {
802 node->right->parent = rightmostNode;
807 rightmostNode->parent = parent;
816 if (parent ==
nullptr) {
817 this->m_dpTree = node->right;
821 if (parent->left == node) {
822 parent->left = node->right;
824 parent->right = node->right;
830 if (node->right !=
nullptr) {
831 FW_ASSERT(node->right->parent !=
nullptr);
832 node->right->parent = parent;
839 node->left = m_freeListHead;
842 if (node->right !=
nullptr) {
847 node->right =
nullptr;
849 DpBtreeNode* oldFreeListHead = this->m_freeListHead;
851 this->m_freeListHead = node;
856 node->parent =
nullptr;
859 FW_ASSERT(node->left == oldFreeListHead);
864 void DpCatalog::sendNextEntry() {
866 if (this->m_xmitInProgress !=
true) {
871 this->m_currentXmitNode = this->findNextTreeNode();
873 if (this->m_currentXmitNode ==
nullptr) {
875 this->m_xmitInProgress =
false;
881 this->m_currXmitFileName.
format(
883 this->m_currentXmitNode->entry.record.get_id(), this->m_currentXmitNode->entry.record.get_tSec(),
884 this->m_currentXmitNode->entry.record.get_tSub());
886 static_cast<U32>(this->m_currentXmitNode->entry.record.get_size()),
887 this->m_currentXmitNode->entry.record.get_priority());
898 DpCatalog::DpBtreeNode* DpCatalog::findNextTreeNode() {
902 if (this->m_dpTree ==
nullptr) {
904 this->m_xmitInProgress =
false;
909 if (this->m_currentNode ==
nullptr) {
910 this->m_currentNode = this->m_dpTree;
916 for (
FwSizeType record = 0; record < this->m_numDpSlots && this->m_currentNode->left !=
nullptr; record++) {
917 this->m_currentNode = this->m_currentNode->left;
920 FW_ASSERT(this->m_currentNode != this->m_freeListHead);
921 FW_ASSERT(this->m_currentNode !=
nullptr);
925 DpBtreeNode* found = this->m_currentNode;
929 if (this->m_currentNode->right !=
nullptr) {
930 this->m_currentNode = this->m_currentNode->right;
932 this->m_currentNode = this->m_currentNode->parent;
938 bool DpCatalog::checkInit() {
939 if (not this->m_initialized) {
942 }
else if (0 == this->m_numDpSlots) {
954 if ((this->m_allocator !=
nullptr) and (this->m_memPtr !=
nullptr)) {
955 this->m_allocator->
deallocate(this->m_allocatorId, this->m_memPtr);
967 this->m_xmitInProgress =
false;
972 if (!this->m_catalogBuilt) {
981 this->m_pendingDpBytes -= this->m_currentXmitNode->entry.record.get_size();
982 this->m_pendingFiles--;
989 this->appendFileState(this->m_currentXmitNode->entry);
991 this->m_xmitBytes += this->m_currentXmitNode->entry.record.get_size();
993 this->deallocateNode(this->m_currentXmitNode);
995 this->sendNextEntry();
998 void DpCatalog ::pingIn_handler(
FwIndexType portNum, U32 key) {
1003 void DpCatalog ::addToCat_handler(
FwIndexType portNum,
1008 if (not this->checkInit()) {
1013 if (0 == this->m_numDpSlots) {
1019 if (not this->m_catalogBuilt) {
1030 FwSizeType dir = this->determineDirectory(fileName);
1039 int ret = processFile(fileName, dir);
1043 if (!this->m_xmitInProgress && this->m_remainActive) {
1044 this->m_currentNode = this->m_dpTree;
1045 this->m_xmitInProgress =
true;
1046 this->sendNextEntry();
1052 this->pruneAndWriteStateFile();
1060 void DpCatalog ::BUILD_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
1065 void DpCatalog ::START_XMIT_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq,
Fw::Wait wait,
bool remainActive) {
1067 this->m_remainActive = remainActive;
1074 this->m_xmitCmdWait =
false;
1075 this->m_xmitOpCode = 0;
1076 this->m_xmitCmdSeq = 0;
1078 this->m_xmitCmdWait =
true;
1079 this->m_xmitOpCode = opCode;
1080 this->m_xmitCmdSeq = cmdSeq;
1087 if (not this->checkInit()) {
1092 if (0 == this->m_numDpSlots) {
1098 if (this->m_xmitInProgress) {
1104 if (not this->m_catalogBuilt) {
1110 this->m_xmitBytes = 0;
1112 this->m_xmitInProgress =
true;
1114 this->sendNextEntry();
1118 void DpCatalog ::STOP_XMIT_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
1119 if (not this->m_xmitInProgress) {
1126 this->m_xmitInProgress =
false;
1136 void DpCatalog ::CLEAR_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
1137 this->resetBinaryTree();
1138 this->resetStateFileData();
1144 if (this->m_xmitCmdWait) {
1145 this->
cmdResponse_out(this->m_xmitOpCode, this->m_xmitCmdSeq, response);
1148 this->m_xmitCmdWait =
false;
1149 this->m_xmitOpCode = 0;
1150 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.
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::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
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
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.
~DpCatalog()
DpCatalog destructor.
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 pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
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
The size of the serial representation.
Don't wait for something.
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()