GCC Code Coverage Report


Directory: ./
File: Svc/DpCatalog/DpCatalog.hpp
Date: 2026-11-03 22:10:14
Exec Total Coverage
Lines: 1 1 100.0%
Functions: 1 1 100.0%
Branches: 3 4 75.0%

Line Branch Exec Source
1 // ======================================================================
2 // \title DpCatalog.hpp
3 // \author tcanham
4 // \brief hpp file for DpCatalog component implementation class
5 // ======================================================================
6
7 #ifndef Svc_DpCatalog_HPP
8 #define Svc_DpCatalog_HPP
9
10 #include "Svc/DpCatalog/DpCatalogComponentAc.hpp"
11 #include "Svc/DpCatalog/DpCatalog_EntryLookupStatusEnumAc.hpp"
12 #include "Svc/DpCatalog/DpCatalog_PriorityChangeStatusEnumAc.hpp"
13 #include "Svc/DpCatalog/DpCatalog_StateFileUpdateStatusEnumAc.hpp"
14 #include "Svc/DpCatalog/DpCatalog_StateFileWriteStatusEnumAc.hpp"
15 #include "Svc/DpCatalog/DpRecordSerializableAc.hpp"
16
17 #include <Fw/DataStructures/ExternalArray.hpp>
18 #include <Fw/DataStructures/RedBlackTreeSet.hpp>
19 #include <Fw/Deprecate.hpp>
20 #include <Fw/Types/MemAllocator.hpp>
21 #include <limits>
22
23 #include <Fw/Types/FileNameString.hpp>
24 #include <config/DpCatalogCfg.hpp>
25 #include <config/DpCfg.hpp>
26
27 #define DIRECTORY_DELIMITER "/"
28
29 namespace Svc {
30
31 class DpCatalog final : public DpCatalogComponentBase {
32 friend class DpCatalogTester;
33
34 public:
35 // ----------------------------------------------------------------------
36 // Component construction and destruction
37 // ----------------------------------------------------------------------
38
39 /// @brief DpCatalog constructor
40 /// @param compName component name
41 DpCatalog(const char* const compName //!< The component name
42 );
43
44 /// @brief DpCatalog destructor
45
3/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
6 ~DpCatalog() = default;
46
47 /// @brief Configure the DpCatalog
48 /// @param directories array of directories to scan; at most DP_MAX_DIRECTORIES entries
49 /// @param stateFile file to store transmit state. Provide a zero-length string if no state tracking
50 /// @param memId memory ID for allocator
51 /// @param allocator Allocator to supply memory for catalog.
52 /// Instance must survive for shutdown to use for reclaiming memory
53 void configure(const Fw::ExternalArray<Fw::FileNameString>& directories,
54 Fw::FileNameString& stateFile,
55 FwEnumStoreType memId,
56 Fw::MemAllocator& allocator);
57
58 /// @brief Configure the DpCatalog
59 /// @param directories list of directories to scan
60 /// @param numDirs number of supplied directories
61 /// @param stateFile file to store transmit state. Provide a zero-length string if no state tracking
62 /// @param memId memory ID for allocator
63 /// @param allocator Allocator to supply memory for catalog.
64 /// Instance must survive for shutdown to use for reclaiming memory
65 DEPRECATED(void configure(Fw::FileNameString directories[DP_MAX_DIRECTORIES],
66 FwSizeType numDirs,
67 Fw::FileNameString& stateFile,
68 FwEnumStoreType memId,
69 Fw::MemAllocator& allocator),
70 "Use configure(const Fw::ExternalArray<Fw::FileNameString>& directories, ...) instead");
71
72 // @brief clean up component.
73 // Deallocates memory.
74 void shutdown();
75
76 private:
77 // ----------------------------------------------------------------------
78 // Handler implementations for user-defined typed input ports
79 // ----------------------------------------------------------------------
80
81 //! Handler implementation for fileDone
82 //!
83 //! File Downlink send complete port
84 void fileDone_handler(FwIndexType portNum, //!< The port number
85 const Svc::SendFileResponse& resp) override;
86
87 //! Handler implementation for pingIn
88 //!
89 //! Ping input port
90 void pingIn_handler(FwIndexType portNum, //!< The port number
91 U32 key //!< Value to return to pinger
92 ) override;
93
94 //! Handler implementation for addToCat
95 //!
96 //! DP Writer Add File to Cat
97 void addToCat_handler(FwIndexType portNum, //!< The port number
98 const Fw::StringBase& fileName, //!< The file name
99 FwDpPriorityType priority, //!< The priority
100 FwSizeType size //!< The file size
101 ) override;
102
103 private:
104 // ----------------------------------------------------------------------
105 // Handler implementations for commands
106 // ----------------------------------------------------------------------
107
108 //! Handler implementation for command BUILD_CATALOG
109 //!
110 //! Build catalog from data product directory
111 void BUILD_CATALOG_cmdHandler(FwOpcodeType opCode, //!< The opcode
112 U32 cmdSeq //!< The command sequence number
113 ) override;
114
115 //! Handler implementation for command START_XMIT_CATALOG
116 //!
117 //! Start transmitting catalog
118 void START_XMIT_CATALOG_cmdHandler(
119 FwOpcodeType opCode, //!< The opcode
120 U32 cmdSeq, //!< The command sequence number
121 const Fw::Wait& wait, //!< have START_XMIT command wait for catalog to complete transmitting
122 bool remainActive //!< should the catalog resume transmission when Dps are added at runtime
123 ) override;
124
125 //! Handler implementation for command START_XMIT_CATALOG_WITH_PRIORITY
126 //!
127 //! Start transmitting the catalog products inside a priority range
128 void START_XMIT_CATALOG_WITH_PRIORITY_cmdHandler(
129 FwOpcodeType opCode, //!< The opcode
130 U32 cmdSeq, //!< The command sequence number
131 const Fw::Wait& wait, //!< have the command wait for the in-range products to finish transmitting
132 bool remainActive, //!< resume transmission when an in-range DP is added at runtime
133 FwDpPriorityType startPriority, //!< lowest priority value (most urgent) to transmit, inclusive
134 FwDpPriorityType endPriority //!< highest priority value (least urgent) to transmit, inclusive
135 ) override;
136
137 //! Handler implementation for command STOP_XMIT_CATALOG
138 //!
139 //! Stop transmitting catalog
140 void STOP_XMIT_CATALOG_cmdHandler(FwOpcodeType opCode, //!< The opcode
141 U32 cmdSeq //!< The command sequence number
142 ) override;
143
144 //! Handler implementation for command CLEAR_CATALOG
145 //!
146 //! clear existing catalog
147 void CLEAR_CATALOG_cmdHandler(FwOpcodeType opCode, //!< The opcode
148 U32 cmdSeq //!< The command sequence number
149 ) override;
150
151 //! Handler implementation for command SET_DP_PRIORITY
152 //!
153 //! Set the transmit priority of one data product; the change is recorded in the state file if one is configured
154 void SET_DP_PRIORITY_cmdHandler(FwOpcodeType opCode, //!< The opcode
155 U32 cmdSeq, //!< The command sequence number
156 FwDpIdType id, //!< Container ID of the data product
157 U32 tSec, //!< Seconds of the data product time tag
158 U32 tSub, //!< Microseconds of the data product time tag
159 FwDpPriorityType priority //!< New transmit priority
160 ) override;
161
162 // ----------------------------------
163 // Private data structures
164 // ----------------------------------
165
166 struct DpStateEntry {
167 friend class DpCatalogTester;
168 FwIndexType dir; //!< index to m_directories entry that has directory name where DP exists
169 DpRecord record; //!< data product metadata
170
171 /// @brief check whether the entry is the data product with the given identity (id and time tag)
172 /// @param id container ID
173 /// @param tSec seconds of the time tag
174 /// @param tSub microseconds of the time tag
175 /// @return true if the entry has that identity
176 bool hasIdentity(FwDpIdType id, U32 tSec, U32 tSub) const;
177
178 /// @brief check whether the entry is the same data product as another: same directory and identity
179 /// (id and time tag). The priority and state, which change, are not compared
180 /// @param other the entry to compare with
181 /// @return true if both entries are the same data product
182 bool isSameProduct(const DpStateEntry& other) const;
183
184 /// @brief compare two entries by transmit priority, then time tag, id, and directory (the catalog sort order)
185 /// @param left an entry to compare
186 /// @param right other entry to compare
187 /// @return -1 if left is higher priority, 0 if equal, and 1 if right is higher priority
188 static I8 compareEntries(const DpStateEntry& left, const DpStateEntry& right);
189
190 bool operator==(const DpStateEntry& other) const;
191 bool operator!=(const DpStateEntry& other) const;
192 bool operator>(const DpStateEntry& other) const;
193 bool operator<(const DpStateEntry& other) const;
194 };
195
196 struct DpDstateFileEntry {
197 bool used; //!< if the entry is used
198 bool visited; //!< used for state file state; indicates that the entry was found in the search of current data
199 //!< products
200 DpStateEntry entry; //!< state entry from file
201 };
202
203 // ----------------------------------
204 // Private helpers
205 // ----------------------------------
206
207 //! Status of a processFile() call
208 enum class ProcessFileStatus {
209 SUCCESS, //!< file added to the catalog
210 FAILED, //!< file could not be processed; continue with the next file
211 QUIT //!< catalog is full; stop processing files
212 };
213
214 /// @brief determine in which managed directory a file resides
215 /// @param fullFile full path to file to be processed
216 /// @return directory index in m_directories; DP_MAX_DIRECTORIES if not in a managed dir
217 FwSizeType determineDirectory(const Fw::String& fullFile);
218
219 /// @brief add entry to sorted list and state file; called on each file in it & upon addToCat
220 /// @param fullFile full path to file to be processed
221 /// @param dir directory index in m_directories
222 /// @return QUIT to stop processing, FAILED for failure but continue, SUCCESS for success
223 ProcessFileStatus processFile(const Fw::String& fullFile, FwSizeType dir);
224
225 /// @brief insert an entry into the sorted catalog; if it exists, update the metadata
226 /// @param entry new entry
227 /// @return true if inserted successfully, false if the tree insert failed
228 bool insertEntry(DpStateEntry& entry);
229
230 /// @brief reset the catalog
231 void resetCatalog();
232
233 /// #brief fill the binary tree from DP files
234 Fw::CmdResponse fillBinaryTree();
235
236 /// @brief reset the state file data
237 void resetStateFileData();
238
239 /// @brief get file state from the stored state file
240 /// @param entry entry to update from file state
241 void getFileState(DpStateEntry& entry);
242
243 /// @brief prune the state file data and write the remaining entries back
244 /// @return WRITTEN, or the error (also reported by event)
245 DpCatalog_StateFileWriteStatus pruneAndWriteStateFile();
246
247 /// @brief load state data from file
248 Fw::CmdResponse loadStateFile();
249
250 /// @brief get file state from the stored state file
251 /// @param entry entry to add to state file
252 void appendFileState(const DpStateEntry& entry);
253
254 /// @brief send the next entry to file downlink
255 void sendNextEntry();
256
257 /// @brief find the next entry in the catalog inside the active priority range
258 /// @param entry entry to return
259 /// @return true if an in-range entry was found, false if no more entries are in range
260 bool findNextEntry(DpStateEntry& entry);
261
262 /// @brief check to see if component successfully initialized
263 /// @return bool if it was initialized
264 bool checkInit();
265
266 /// @brief build catalog. Shared between command and port
267 /// @return command response for pass/fail
268 Fw::CmdResponse doCatalogBuild();
269
270 /// @brief handle a START_XMIT_CATALOG or START_XMIT_CATALOG_WITH_PRIORITY command: validate the range,
271 /// then start transmitting and send (or arm, for a waited command) the command response
272 /// @param opCode the command opcode
273 /// @param cmdSeq the command sequence number
274 /// @param wait whether the command response waits for the transmission to complete
275 /// @param remainActive whether runtime additions resume transmission
276 /// @param startPriority lowest priority value to transmit, inclusive
277 /// @param endPriority highest priority value to transmit, inclusive
278 void startXmitCmd(FwOpcodeType opCode,
279 U32 cmdSeq,
280 const Fw::Wait& wait,
281 bool remainActive,
282 FwDpPriorityType startPriority,
283 FwDpPriorityType endPriority);
284
285 /// @brief start transmitting catalog. Called only by startXmitCmd, which validates the range
286 /// @param startPriority lowest priority value to transmit, inclusive
287 /// @param endPriority highest priority value to transmit, inclusive; must be >= startPriority
288 /// @return command response for pass/fail
289 Fw::CmdResponse doCatalogXmit(FwDpPriorityType startPriority, FwDpPriorityType endPriority);
290
291 /// @brief send a cmdResponse to the start xmit cmd if user waited
292 /// @param response the command response for pass/fail
293 void dispatchWaitedResponse(Fw::CmdResponse response);
294
295 /// @brief abandon the transmit: clear both transmit flags and answer a waited START_XMIT_CATALOG
296 /// @param response the command response for the waited command
297 void abortXmit(Fw::CmdResponse response);
298
299 /// @brief find the catalog entry for a data product by its stable identity (directory, id and time tag)
300 /// @param product the data product to find; its priority and state are not compared
301 /// @param entry the entry found
302 /// @return FOUND if an entry was found (and copied to entry), NOT_FOUND otherwise
303 DpCatalog_EntryLookupStatus findEntryByIdentity(const DpStateEntry& product, DpStateEntry& entry) const;
304
305 /// @brief find the first catalog entry of a data product named by id and time tag, as SET_DP_PRIORITY names it
306 /// @param id container ID
307 /// @param tSec seconds of the time tag
308 /// @param tSub microseconds of the time tag
309 /// @param entry the entry found
310 /// @return FOUND if an entry was found (and copied to entry), NOT_FOUND otherwise
311 DpCatalog_EntryLookupStatus findProductEntry(FwDpIdType id, U32 tSec, U32 tSub, DpStateEntry& entry) const;
312
313 /// @brief set the transmit priority of a catalog entry and record it in the state file, if one is configured
314 /// @param entry a copy of the catalog entry; updated to the new priority
315 /// @param priority the new priority
316 /// @return UNCHANGED if the entry already had the priority, CHANGED if it was set (and recorded if a state file
317 /// is configured), NOT_RECORDED if it was set but could not be recorded in the configured state file
318 DpCatalog_PriorityChangeStatus setDpPriority(DpStateEntry& entry, FwDpPriorityType priority);
319
320 /// @brief find the state file data slot for an entry's product (same directory, id and time tag)
321 /// @param entry the entry to look up
322 /// @return the slot index, or m_stateFileEntries if the product has no slot
323 FwSizeType findStateFileSlot(const DpStateEntry& entry) const;
324
325 /// @brief record an entry's state in the state file data, reusing the product's slot or a stale one
326 /// @param entry the entry to record
327 /// @return RECORDED, or FULL if the state file data has no free slot (StateFileFull is reported when a state
328 /// file is configured)
329 DpCatalog_StateFileUpdateStatus updateStateFileData(const DpStateEntry& entry);
330
331 // ----------------------------------
332 // Private data
333 // ----------------------------------
334 bool m_initialized = false; //!< set when the component has been initialized
335
336 Fw::RedBlackTreeSet<DpStateEntry, DP_MAX_FILES> m_dpCatalog; //!< The sorted catalog of DPs
337 DpStateEntry m_currentXmitEntry; //!< Entry currently being transmitted
338 bool m_hasCurrentXmit = false; //!< Whether m_currentXmitEntry is valid
339 U32 m_currXmitContext = 0; //!< FileDownlink context of the send in flight, echoed back in fileDone
340
341 FwSizeType m_numDpSlots = 0; //!< Stores the available number of record slots.
342
343 Fw::FileNameString m_directories[DP_MAX_DIRECTORIES]; //!< List of supplied DP directories
344 FwSizeType m_numDirectories = 0; //!< number of supplied directories
345
346 Fw::FileNameString m_stateFile; //!< file to store transmit state
347 DpDstateFileEntry* m_stateFileData = nullptr; //!< DP state loaded from file
348 FwSizeType m_stateFileEntries = 0; //!< size of state file data
349
350 FwSizeType m_memSize = 0; //!< size of allocated buffer
351 void* m_memPtr = nullptr; //!< stored for shutdown
352 FwEnumStoreType m_allocatorId = 0; //!< stored for shutdown
353 Fw::MemAllocator* m_allocator = nullptr; //!< stored for shutdown
354
355 bool m_catalogBuilt = false; //!< catalog build is complete (can add DPs at runtime)
356 bool m_xmitInProgress = false; //!< set if DP files are in the process of being sent
357 Fw::FileNameString m_currXmitFileName; //!< current file being transmitted
358 bool m_xmitCmdWait = false; //!< true if waiting for transmission complete to complete xmit command
359 U64 m_xmitBytes = 0; //!< bytes transmitted for downlink session
360 FwOpcodeType m_xmitOpCode = 0; //!< stored xmit command opcode
361 U32 m_xmitCmdSeq = 0; //!< stored command sequence id
362
363 U32 m_pendingFiles = 0; //!< Pending Files to Transmit
364 U64 m_pendingDpBytes = 0; //!< Pending Bytes to Transmit
365
366 bool m_remainActive = false; //!< Does the DpCat resume transmission when
367 //!< a runtime Dp is received after
368 //!< the in-range catalog is sent
369
370 FwDpPriorityType m_xmitStartPriority = 0; //!< Lowest priority value sent by the active/last transmit command
371 FwDpPriorityType m_xmitEndPriority =
372 std::numeric_limits<FwDpPriorityType>::max(); //!< Highest priority value sent by the active/last
373 //!< transmit command
374 };
375
376 } // namespace Svc
377
378 #endif
379