17 static_assert(
DP_MAX_DIRECTORIES > 0,
"Configuration DP_MAX_DIRECTORIES must be positive");
18 static_assert(
DP_MAX_FILES > 0,
"Configuration DP_MAX_FILES must be positive");
27 m_freeListHead(nullptr),
28 m_freeListFoot(nullptr),
29 m_traverseStack(nullptr),
30 m_currentNode(nullptr),
31 m_currentXmitNode(nullptr),
35 m_stateFileData(nullptr),
36 m_stateFileEntries(0),
41 m_xmitInProgress(false),
57 this->m_stateFile = stateFile;
66 static const FwSizeType slotSize =
sizeof(DpBtreeNode) +
sizeof(DpBtreeNode**) +
sizeof(DpDstateFileEntry);
70 this->m_memPtr = allocator.
allocate(memId, this->m_memSize, notUsed);
92 if ((this->m_memSize >=
sizeof(DpBtreeNode)) and (this->m_memPtr !=
nullptr)) {
94 this->m_numDpSlots = this->m_memSize / slotSize;
95 this->resetBinaryTree();
97 this->m_traverseStack =
reinterpret_cast<DpBtreeNode**
>(&this->m_freeListHead[this->m_numDpSlots]);
98 this->resetTreeStack();
100 this->m_stateFileData =
reinterpret_cast<DpDstateFileEntry*
>(&this->m_traverseStack[this->m_numDpSlots]);
104 this->m_numDpSlots = 0;
108 for (
FwSizeType dir = 0; dir < numDirs; dir++) {
109 this->m_directories[dir] = directories[dir];
111 this->m_numDirectories = numDirs;
114 this->m_allocator = &allocator;
115 this->m_allocatorId = memId;
116 this->m_initialized =
true;
119 void DpCatalog::resetBinaryTree() {
123 this->m_freeListHead =
static_cast<DpBtreeNode*
>(this->m_memPtr);
124 for (
FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) {
126 (void)
new (&this->m_freeListHead[slot]) DpBtreeNode();
127 this->m_freeListHead[slot].left =
nullptr;
128 this->m_freeListHead[slot].right =
nullptr;
131 this->m_freeListHead[slot - 1].left = &this->m_freeListHead[slot];
135 this->m_freeListFoot = &this->m_freeListHead[this->m_numDpSlots - 1];
137 this->m_dpTree =
nullptr;
139 this->m_numDpRecords = 0;
142 void DpCatalog::resetStateFileData() {
144 for (
FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) {
145 this->m_stateFileData[slot].used =
false;
146 this->m_stateFileData[slot].visited =
false;
147 (void)
new (&this->m_stateFileData[slot].entry.record) DpRecord();
149 this->m_stateFileEntries = 0;
156 if (this->m_stateFile.
length() == 0) {
175 this->m_stateFileEntries = 0;
178 for (
FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) {
181 stat = stateFile.
read(buffer, size);
195 if (size !=
sizeof(buffer)) {
197 static_cast<I32>(size));
202 Fw::SerializeStatus serStat = entryBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(size));
205 entryBuffer.resetDeser();
211 Fw::SerializeStatus status = entryBuffer.deserialize(this->m_stateFileData[entry].entry.dir);
213 status = entryBuffer.deserialize(this->m_stateFileData[entry].entry.record);
215 this->m_stateFileData[entry].used =
true;
216 this->m_stateFileData[entry].visited =
false;
220 this->m_stateFileEntries++;
226 void DpCatalog::getFileState(DpStateEntry& entry) {
229 for (
FwSizeType line = 0; line < this->m_stateFileEntries; line++) {
231 if ((this->m_stateFileData[line].entry.dir == entry.dir) and
232 (this->m_stateFileData[line].entry.record.get_id() == entry.record.get_id()) and
233 (this->m_stateFileData[line].entry.record.get_tSec() == entry.record.get_tSec()) and
234 (this->m_stateFileData[line].entry.record.get_tSub() == entry.record.get_tSub()) and
235 (this->m_stateFileData[line].entry.record.get_priority() == entry.record.get_priority())) {
237 entry.record.set_state(this->m_stateFileData[line].entry.record.get_state());
238 entry.record.set_blocks(this->m_stateFileData[line].entry.record.get_blocks());
240 this->m_stateFileData[line].visited =
true;
246 void DpCatalog::pruneAndWriteStateFile() {
271 for (
FwSizeType entry = 0; entry < this->m_numDpSlots; entry++) {
273 if ((this->m_stateFileData[entry].used) and (this->m_stateFileData[entry].visited)) {
275 entryBuffer.resetSer();
277 Fw::SerializeStatus serStat = entryBuffer.serialize(this->m_stateFileData[entry].entry.dir);
280 serStat = entryBuffer.serialize(this->m_stateFileData[entry].entry.record);
284 FwSizeType size = entryBuffer.getBuffLength();
286 stat = stateFile.
write(buffer, size);
298 void DpCatalog::appendFileState(
const DpStateEntry& entry) {
300 FW_ASSERT(entry.dir < static_cast<FwIndexType>(this->m_numDirectories), static_cast<FwAssertArgType>(entry.dir),
301 static_cast<FwAssertArgType>(this->m_numDirectories));
317 BYTE buffer[
sizeof(entry.dir) +
sizeof(entry.record)];
320 entryBuffer.resetSer();
325 serStat = entryBuffer.serialize(entry.record);
329 FwSizeType size = entryBuffer.getBuffLength();
330 stat = stateFile.
write(buffer, size);
342 if (not this->checkInit()) {
348 if (0 == this->m_numDpSlots) {
354 if (this->m_xmitInProgress) {
360 this->resetStateFileData();
366 this->resetBinaryTree();
369 response = this->fillBinaryTree();
372 this->resetBinaryTree();
373 this->resetStateFileData();
378 this->pruneAndWriteStateFile();
397 for (
FwSizeType dir = 0; dir < this->m_numDirectories; dir++) {
401 U32 pendingFiles = 0;
402 U64 pendingDpBytes = 0;
403 U32 filesProcessed = 0;
411 status = dpDir.
readDirectory(this->m_fileList, (this->m_numDpSlots - totalFiles), filesRead);
419 FW_ASSERT(filesRead <= this->m_numDpSlots - totalFiles, static_cast<FwAssertArgType>(filesRead),
420 static_cast<FwAssertArgType>(this->m_numDpSlots - totalFiles));
423 for (
FwSizeType file = 0; file < filesRead; file++) {
435 fullFile.
format(
"%s/%s", this->m_directories[dir].toChar(), this->m_fileList[file].toChar());
456 stat = dpFile.
read(dpBuff, size);
485 entry.record.set_id(container.
getId());
486 entry.record.set_priority(container.
getPriority());
487 entry.record.set_state(container.
getState());
490 entry.record.set_size(static_cast<U64>(fileSize));
493 this->getFileState(entry);
496 bool insertedOk = this->insertEntry(entry);
497 if (not insertedOk) {
500 this->resetBinaryTree();
501 this->resetStateFileData();
507 pendingDpBytes += entry.record.get_size();
511 if (this->m_numDpRecords > this->m_numDpSlots) {
520 totalFiles += filesProcessed;
523 pendingFiles, pendingDpBytes);
527 if (totalFiles == this->m_numDpSlots) {
537 bool DpCatalog::insertEntry(DpStateEntry& entry) {
546 if (this->m_dpTree ==
nullptr) {
547 bool goodInsert = this->allocateNode(this->m_dpTree, entry);
548 if (not goodInsert) {
554 DpBtreeNode* node = this->m_dpTree;
555 for (
FwSizeType record = 0; record < this->m_numDpSlots; record++) {
556 CheckStat stat = CheckStat::CHECK_CONT;
558 if (entry.record.get_priority() == node->entry.record.get_priority()) {
560 if (entry.record.get_tSec() == node->entry.record.get_tSec()) {
562 stat = this->checkLeftRight(entry.record.get_id() < node->entry.record.get_id(), node, entry);
564 stat = this->checkLeftRight(entry.record.get_tSec() < node->entry.record.get_tSec(), node, entry);
568 this->checkLeftRight(entry.record.get_priority() < node->entry.record.get_priority(), node, entry);
572 if (stat == CheckStat::CHECK_ERROR) {
574 }
else if (stat == CheckStat::CHECK_OK) {
582 this->m_numDpRecords++;
587 DpCatalog::CheckStat DpCatalog::checkLeftRight(
bool condition, DpBtreeNode*& node,
const DpStateEntry& newEntry) {
589 if (node->left ==
nullptr) {
590 bool allocated = this->allocateNode(node->left, newEntry);
592 return CheckStat::CHECK_ERROR;
594 return CheckStat::CHECK_OK;
597 return CheckStat::CHECK_CONT;
600 if (node->right ==
nullptr) {
601 bool allocated = this->allocateNode(node->right, newEntry);
603 return CheckStat::CHECK_ERROR;
605 return CheckStat::CHECK_OK;
608 return CheckStat::CHECK_CONT;
613 bool DpCatalog::allocateNode(DpBtreeNode*& newNode,
const DpStateEntry& newEntry) {
617 if (this->m_freeListHead ==
nullptr) {
622 newNode = this->m_freeListHead;
624 this->m_freeListHead = this->m_freeListHead->left;
627 newNode->left =
nullptr;
628 newNode->right =
nullptr;
629 newNode->entry = newEntry;
635 void DpCatalog::deleteEntry(DpStateEntry& entry) {}
637 void DpCatalog::sendNextEntry() {
644 this->m_currentXmitNode = this->findNextTreeNode();
646 if (this->m_currentXmitNode ==
nullptr) {
648 this->m_xmitInProgress =
false;
650 if (this->m_xmitCmdWait) {
656 this->m_currXmitFileName.
format(
658 this->m_currentXmitNode->entry.record.get_id(), this->m_currentXmitNode->entry.record.get_tSec(),
659 this->m_currentXmitNode->entry.record.get_tSub());
661 static_cast<U32>(this->m_currentXmitNode->entry.record.get_size()),
662 this->m_currentXmitNode->entry.record.get_priority());
673 DpCatalog::DpBtreeNode* DpCatalog::findNextTreeNode() {
679 DpBtreeNode* found =
nullptr;
683 for (
FwSizeType record = 0; record < this->m_numDpRecords; record++) {
687 if (this->m_currentNode ==
nullptr) {
689 if (this->m_currStackEntry < 0) {
694 this->m_currentNode = this->m_traverseStack[this->m_currStackEntry--];
696 found = this->m_currentNode;
698 this->m_currentNode = this->m_currentNode->right;
699 if (found !=
nullptr) {
705 if (this->m_currentNode->left !=
nullptr) {
707 this->m_traverseStack[++this->m_currStackEntry] = this->m_currentNode;
708 this->m_currentNode = this->m_currentNode->left;
713 found = this->m_currentNode;
716 this->m_currentNode = this->m_currentNode->right;
718 if (found !=
nullptr) {
728 bool DpCatalog::checkInit() {
729 if (not this->m_initialized) {
732 }
else if (0 == this->m_numDpSlots) {
744 if ((this->m_allocator !=
nullptr) and (this->m_memPtr !=
nullptr)) {
745 this->m_allocator->
deallocate(this->m_allocatorId, this->m_memPtr);
761 this->m_xmitInProgress =
false;
770 this->appendFileState(this->m_currentXmitNode->entry);
772 this->m_xmitBytes += this->m_currentXmitNode->entry.record.get_size();
774 this->sendNextEntry();
777 void DpCatalog ::pingIn_handler(
FwIndexType portNum, U32 key) {
786 void DpCatalog ::BUILD_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
791 void DpCatalog ::START_XMIT_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq,
Fw::Wait wait) {
799 this->m_xmitCmdWait =
false;
800 this->m_xmitOpCode = 0;
801 this->m_xmitCmdSeq = 0;
803 this->m_xmitCmdWait =
true;
804 this->m_xmitOpCode = opCode;
805 this->m_xmitCmdSeq = cmdSeq;
812 if (not this->checkInit()) {
818 if (0 == this->m_numDpSlots) {
824 if (this->m_xmitInProgress) {
830 this->m_xmitBytes = 0;
839 this->resetTreeStack();
840 this->m_xmitInProgress =
true;
842 this->sendNextEntry();
846 void DpCatalog::resetTreeStack() {
849 this->m_currStackEntry = -1;
851 this->m_currentNode = this->m_dpTree;
854 void DpCatalog ::STOP_XMIT_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
855 if (not this->m_xmitInProgress) {
864 void DpCatalog ::CLEAR_CATALOG_cmdHandler(
FwOpcodeType opCode, U32 cmdSeq) {
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
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
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.
The size of the serial representation.
virtual void * allocate(const FwEnumStoreType identifier, FwSizeType &size, bool &recoverable)=0
Allocate memory.
void log_WARNING_HI_NotInitialized() const
Log event NotInitialized.
static constexpr FwSizeType MIN_PACKET_SIZE
static const FwIndexType DP_MAX_DIRECTORIES
const char * toChar() const
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.
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_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
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.
SizeType length() const
Get length of string.
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.
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.
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 pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
void log_WARNING_HI_CatalogFull(const Fw::StringBase &dir)
Operation was successful.
void log_ACTIVITY_LO_ProductComplete(const Fw::StringBase &file) const
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.
Fw::SerializeStatus deserializeHeader()
Operation was successful.
virtual void deallocate(const FwEnumStoreType identifier, void *ptr)=0
Deallocate memory.
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()