GCC Code Coverage Report


Directory: ./
File: Svc/CmdSequencer/CmdSequencerImpl.hpp
Date: 2026-11-03 21:15:54
Exec Total Coverage
Lines: 15 15 100.0%
Functions: 7 7 100.0%
Branches: 8 10 80.0%

Line Branch Exec Source
1 // ======================================================================
2 // \title CmdSequencerImpl.hpp
3 // \author Bocchino/Canham
4 // \brief hpp file for CmdSequencer component implementation class
5 //
6 // Copyright (C) 2009-2018 California Institute of Technology.
7 // ALL RIGHTS RESERVED. United States Government Sponsorship
8 // acknowledged.
9 // ======================================================================
10
11 #ifndef Svc_CmdSequencerImpl_HPP
12 #define Svc_CmdSequencerImpl_HPP
13
14 #include <Utils/Hash/Hash.hpp>
15 #include "Fw/Com/ComBuffer.hpp"
16 #include "Fw/Types/FileNameString.hpp"
17 #include "Fw/Types/MemAllocator.hpp"
18 #include "Os/File.hpp"
19 #include "Os/FilePathUtils.hpp"
20 #include "Os/ValidateFile.hpp"
21 #include "Svc/CmdSequencer/CmdSequencerComponentAc.hpp"
22 #include "Svc/Seq/BlockStateEnumAc.hpp"
23
24 namespace Svc {
25
26 // Forward declaration for UTs
27 namespace ImmediateBase {
28 class CmdSequencerTester;
29 }
30 namespace Immediate {
31 class CmdSequencerTester;
32 }
33 namespace ImmediateEOS {
34 class CmdSequencerTester;
35 }
36 namespace Mixed {
37 class CmdSequencerTester;
38 }
39 namespace MixedRelativeBase {
40 class CmdSequencerTester;
41 }
42 namespace Relative {
43 class CmdSequencerTester;
44 }
45 namespace JoinWait {
46 class CmdSequencerTester;
47 }
48
49 class CmdSequencerComponentImpl final : public CmdSequencerComponentBase {
50 friend class CmdSequencerTester;
51 friend class Svc::ImmediateBase::CmdSequencerTester;
52 friend class Svc::Immediate::CmdSequencerTester;
53 friend class Svc::ImmediateEOS::CmdSequencerTester;
54 friend class Svc::Mixed::CmdSequencerTester;
55 friend class Svc::MixedRelativeBase::CmdSequencerTester;
56 friend class Svc::Relative::CmdSequencerTester;
57 friend class Svc::JoinWait::CmdSequencerTester;
58
59 private:
60 // ----------------------------------------------------------------------
61 // Private enumerations
62 // ----------------------------------------------------------------------
63
64 //! The run mode
65 enum RunMode { STOPPED, RUNNING };
66
67 //! The step mode
68 enum StepMode { AUTO, MANUAL };
69
70 public:
71 // ----------------------------------------------------------------------
72 // Public classes
73 // ----------------------------------------------------------------------
74
75 //! \class Sequence
76 //! \brief A sequence with unspecified binary format
77 class Sequence {
78 public:
79 //! \class Events
80 //! \brief Sequence event reporting
81 class Events {
82 public:
83 //! Construct an Events object
84 Events(Sequence& sequence //!< The enclosing sequence
85 );
86
87 public:
88 //! File CRC failure
89 void fileCRCFailure(const U32 storedCRC, //!< The CRC stored in the file
90 const U32 computedCRC //!< The CRC computed over the file
91 );
92
93 //! File invalid
94 void fileInvalid(const CmdSequencer_FileReadStage::t stage, //!< The file read stage
95 const I32 error //!< The error
96 );
97
98 //! File not found
99 void fileNotFound();
100
101 //! File read error
102 void fileReadError();
103
104 //! File size error
105 void fileSizeError(const U32 size //!< The size
106 );
107
108 //! Record invalid
109 void recordInvalid(const U32 recordNumber, //!< The record number
110 const I32 error //!< The error
111 );
112
113 //! Record mismatch
114 void recordMismatch(const U32 numRecords, //!< The number of records in the header
115 const U32 extraBytes //!< The number of bytes beyond last record
116 );
117
118 //! Time base mismatch
119 void timeBaseMismatch(const TimeBase currTimeBase, //!< The current time base
120 const TimeBase seqTimeBase //!< The sequence file time base
121 );
122
123 //! Time context mismatch
124 void timeContextMismatch(const FwTimeContextStoreType currTimeContext, //!< The current time context
125 const FwTimeContextStoreType seqTimeContext //!< The sequence file time context
126 );
127
128 // No Records
129 void noRecords();
130
131 private:
132 //! The enclosing component
133 Sequence& m_sequence;
134 };
135
136 public:
137 //! Construct a Sequence object
138 Sequence(CmdSequencerComponentImpl& component //!< The enclosing component
139 );
140
141 //! Destroy a Sequence object
142 virtual ~Sequence();
143
144 public:
145 //! \class Header
146 //! \brief A sequence header
147 class Header {
148 public:
149 enum Constants {
150 //! Serialized size of header
151 SERIALIZED_SIZE =
152 sizeof(U32) + sizeof(U32) + sizeof(FwTimeBaseStoreType) + sizeof(FwTimeContextStoreType)
153 };
154
155 public:
156 //! Construct a Header object
157 Header();
158
159 public:
160 //! Validate the time field of the sequence header
161 //! \return Success or failure
162 bool validateTime(CmdSequencerComponentImpl& component //!< Component for time and events
163 );
164
165 public:
166 //! The file size
167 U32 m_fileSize;
168
169 //! The number of records in the sequence
170 U32 m_numRecords;
171
172 //! The time base of the sequence
173 TimeBase m_timeBase;
174
175 //! The context of the sequence
176 FwTimeContextStoreType m_timeContext;
177 };
178
179 public:
180 //! \class Record
181 //! \brief A sequence record
182 class Record {
183 public:
184 enum Descriptor {
185 ABSOLUTE, //!< Absolute time
186 RELATIVE, //!< Relative time
187 END_OF_SEQUENCE //!< end of sequence
188 };
189
190 public:
191 //! Construct a Record object
192
1/1
✓ Branch 9 taken 199 times.
199 Record() : m_descriptor(END_OF_SEQUENCE) {}
193
194 public:
195 //! The descriptor
196 Descriptor m_descriptor;
197
198 //! The time tag. NOTE: timeBase and context not filled in
199 Fw::Time m_timeTag;
200
201 //! The command
202 Fw::ComBuffer m_command;
203 };
204
205 public:
206 //! Give the sequence representation a memory buffer
207 void allocateBuffer(FwEnumStoreType identifier, //!< The identifier
208 Fw::MemAllocator& allocator, //!< The allocator
209 FwSizeType bytes //!< The number of bytes
210 );
211
212 //! Deallocate the buffer
213 void deallocateBuffer(Fw::MemAllocator& allocator //!< The allocator
214 );
215
216 //! Set the file name. Also sets the log file name.
217 void setFileName(const Fw::ConstStringBase& fileName);
218
219 //! Get the file name
220 //! \return The file name
221 Fw::FileNameString& getFileName();
222
223 //! Get the log file name
224 //! \return The log file name
225 Fw::LogStringArg& getLogFileName();
226
227 //! Get the normal string file name
228 //! \return The normal string file name
229 Fw::String& getStringFileName();
230
231 //! Get the sequence header
232 const Header& getHeader() const;
233
234 //! Load a sequence file
235 //! \return Success or failure
236 virtual bool loadFile(const Fw::ConstStringBase& fileName //!< The file name
237 ) = 0;
238
239 //! Query whether the sequence has any more records
240 //! \return Yes or no
241 virtual bool hasMoreRecords() const = 0;
242
243 //! Get the next record in the sequence
244 //! Asserts on failure
245 virtual void nextRecord(Record& record //!< The returned record
246 ) = 0;
247
248 //! Reset the sequence to the beginning.
249 //! After calling this, hasMoreRecords should return true,
250 //! unless the sequence has no records
251 virtual void reset() = 0;
252
253 //! Clear the sequence records.
254 //! After calling this, hasMoreRecords should return false
255 virtual void clear() = 0;
256
257 protected:
258 //! The enclosing component
259 CmdSequencerComponentImpl& m_component;
260
261 //! Event reporting
262 Events m_events;
263
264 //! The sequence file name
265 Fw::FileNameString m_fileName;
266
267 //! Copy of file name for events
268 Fw::LogStringArg m_logFileName;
269
270 //! Copy of file name for ports
271 Fw::String m_stringFileName;
272
273 //! Serialize buffer to hold the binary sequence data
274 Fw::ExternalSerializeBuffer m_buffer;
275
276 //! The allocator ID
277 FwEnumStoreType m_allocatorId;
278
279 //! The sequence header
280 Header m_header;
281 };
282
283 //! \class FPrimeSequence
284 //! \brief A sequence that uses the F Prime binary format
285 class FPrimeSequence : public Sequence {
286 private:
287 enum Constants { INITIAL_COMPUTED_VALUE = 0xFFFFFFFFU };
288
289 public:
290 //! \class CRC
291 //! \brief Container for computed and stored CRC values
292 struct CRC {
293 //! Construct a CRC
294 CRC();
295
296 //! Initialize computed CRC
297 void init();
298
299 //! Update computed CRC
300 void update(const BYTE* buffer, //!< The buffer
301 FwSizeType bufferSize //!< The buffer size
302 );
303
304 //! Return the finalized CRC
305 U32 finalize();
306
307 //! Computed CRC
308 Utils::Hash m_computed;
309
310 //! Stored CRC
311 U32 m_stored;
312 };
313
314 public:
315 //! Construct an FPrimeSequence
316 FPrimeSequence(CmdSequencerComponentImpl& component //!< The enclosing component
317 );
318
319 public:
320 //! Load a sequence file
321 //! \return Success or failure
322 bool loadFile(const Fw::ConstStringBase& fileName //!< The file name
323 );
324
325 //! Query whether the sequence has any more records
326 //! \return Yes or no
327 bool hasMoreRecords() const;
328
329 //! Get the next record in the sequence.
330 //! Asserts on failure
331 void nextRecord(Record& record //!< The returned record
332 );
333
334 //! Reset the sequence to the beginning.
335 //! After calling this, hasMoreRecords should return true, unless
336 //! the sequence has no records.
337 void reset();
338
339 //! Clear the sequence records.
340 //! After calling this, hasMoreRecords should return false.
341 void clear();
342
343 private:
344 //! Read a sequence file
345 //! \return Success or failure
346 bool readFile();
347
348 //! Read an open sequence file
349 //! \return Success or failure
350 bool readOpenFile();
351
352 //! Read a binary sequence header from the sequence file
353 //! into the buffer
354 //! \return Success or failure
355 bool readHeader();
356
357 //! Deserialize the binary sequence header from the buffer
358 //! \return Success or failure
359 bool deserializeHeader();
360
361 //! Read records and CRC into buffer
362 //! \return Success or failure
363 bool readRecordsAndCRC();
364
365 //! Extract CRC from record data
366 //! \return Success or failure
367 bool extractCRC();
368
369 //! Validate the CRC
370 //! \return Success or failure
371 bool validateCRC();
372
373 //! Deserialize a record from a buffer
374 //! \return Serialize status
375 Fw::SerializeStatus deserializeRecord(Record& record //!< The record
376 );
377
378 //! Deserialize a record descriptor
379 //! \return Serialize status
380 Fw::SerializeStatus deserializeDescriptor(Record::Descriptor& descriptor //!< The descriptor
381 );
382
383 //! Deserialize a time tag
384 //! \return Serialize status; FW_DESERIALIZE_FORMAT_ERROR if microseconds >= 1000000
385 Fw::SerializeStatus deserializeTimeTag(Fw::Time& timeTag //!< The time tag
386 );
387
388 //! Deserialize the record size
389 //! \return Serialize status
390 Fw::SerializeStatus deserializeRecordSize(U32& recordSize //!< The record size
391 );
392
393 //! Copy the serialized command into a com buffer
394 //! \return Serialize status
395 Fw::SerializeStatus copyCommand(Fw::ComBuffer& comBuffer, //!< The com buffer
396 const U32 recordSize //!< The record size
397 );
398
399 //! Validate the sequence records in the buffer
400 //! \return Success or failure
401 bool validateRecords();
402
403 private:
404 //! The CRC values
405 CRC m_crc;
406
407 //! The sequence file
408 Os::File m_sequenceFile;
409 };
410
411 private:
412 // ----------------------------------------------------------------------
413 // Private classes
414 // ----------------------------------------------------------------------
415
416 //! \class Timer
417 //! \brief A class representing a timer
418 class Timer {
419 friend class CmdSequencerTester;
420 friend class Svc::ImmediateBase::CmdSequencerTester;
421 friend class Svc::Immediate::CmdSequencerTester;
422 friend class Svc::ImmediateEOS::CmdSequencerTester;
423 friend class Svc::Mixed::CmdSequencerTester;
424 friend class Svc::MixedRelativeBase::CmdSequencerTester;
425 friend class Svc::Relative::CmdSequencerTester;
426 friend class Svc::JoinWait::CmdSequencerTester;
427
428 private:
429 //! The timer state
430 typedef enum { SET, CLEAR } State;
431
432 public:
433 //! Construct a Timer object
434 186 Timer() : m_state(CLEAR) {}
435
436 //! Set the expiration time
437 145 void set(Fw::Time time //!< The time
438 ) {
439 145 this->m_state = SET;
440 145 this->expirationTime = time;
441 145 }
442
443 //! Clear the timer
444 164 void clear() { this->m_state = CLEAR; }
445
446 //! Determine whether the timer is set
447 //! \return Yes or no
448
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 bool isSet() const { return this->m_state == SET; }
449
450 //! Get the expiration time
451 //! \return The time at which a set timer expires
452 1 Fw::Time getExpirationTime() const { return this->expirationTime; }
453
454 //! Determine whether the timer is expired at a given time
455 //! \return Yes or no
456 43 bool isExpiredAt(Fw::Time time //!< The time
457 ) {
458
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 23 times.
43 if (this->m_state == CLEAR) {
459 20 return false;
460
3/3
✓ Branch 5 taken 23 times.
✓ Branch 14 taken 9 times.
✓ Branch 15 taken 14 times.
23 } else if (Fw::Time::compare(this->expirationTime, time) == Fw::TimeComparison::GT) {
461 9 return false;
462 }
463 14 return true;
464 }
465
466 private:
467 //! The timer state
468 State m_state;
469
470 //! The expiration time
471 Fw::Time expirationTime;
472 };
473
474 public:
475 // ----------------------------------------------------------------------
476 // Construction, initialization, and destruction
477 // ----------------------------------------------------------------------
478
479 //! Construct a CmdSequencer
480 CmdSequencerComponentImpl(const char* compName //!< The component name
481 );
482
483 //! (Optional) Set a timeout.
484 //! Sequence will quit if a command takes longer than the number of
485 //! seconds in the timeout value.
486 void setTimeout(const U32 seconds //!< The number of seconds
487 );
488
489 //! (Optional) Set the sequence format.
490 //! CmdSequencer will use the sequence object you pass in
491 //! to load and run sequences. By default, it uses an FPrimeSequence
492 //! object.
493 void setSequenceFormat(Sequence& sequence //!< The sequence object
494 );
495
496 //! (Optional) Restrict sequence file loads to a directory.
497 //! Every sequence load (CS_RUN, CS_VALIDATE, seqRunIn, seqDispatchIn) whose file name
498 //! resolves outside the directory is rejected with CS_FileOutsideSandbox before the file
499 //! is opened. Until this is called, any path is allowed.
500 void configureSandbox(const char* directory //!< The allowed directory (absolute, or relative to CWD)
501 );
502
503 //! Give the sequence a memory buffer.
504 //! Call this after constructor and init, and after setting
505 //! the sequence format, but before task is spawned.
506 void allocateBuffer(const FwEnumStoreType identifier, //!< The identifier
507 Fw::MemAllocator& allocator, //!< The allocator
508 const FwSizeType bytes //!< The number of bytes
509 );
510
511 //! (Optional) Load a sequence to run later.
512 //! When you call this function, the event ports must be connected.
513 void loadSequence(const Fw::ConstStringBase& fileName //!< The file name
514 );
515
516 //! Return allocated buffer. Call during shutdown.
517 void deallocateBuffer(Fw::MemAllocator& allocator //!< The allocator
518 );
519
520 //! Destroy a CmdDispatcherComponentBase
521 ~CmdSequencerComponentImpl();
522
523 private:
524 // ----------------------------------------------------------------------
525 // Handler implementations for input ports
526 // ----------------------------------------------------------------------
527
528 //! Handler for input port cmdResponseIn
529 void cmdResponseIn_handler(FwIndexType portNum, //!< The port number
530 FwOpcodeType opcode, //!< The command opcode
531 U32 cmdSeq, //!< The command sequence number
532 const Fw::CmdResponse& response //!< The command response
533 ) override;
534
535 //! Handler for input port schedIn
536 void schedIn_handler(FwIndexType portNum, //!< The port number
537 U32 order //!< The call order
538 ) override;
539
540 //! Handler for input port seqRunIn
541 void seqRunIn_handler(FwIndexType portNum, //!< The port number
542 const Fw::StringBase& filename, //!< The sequence file
543 const Svc::SeqArgs& args //!< Sequence arguments (not currently used)
544 ) override;
545
546 //! Handler implementation for seqDispatchIn
547 //!
548 //! Port for file dispatches to run sequences
549 void seqDispatchIn_handler(FwIndexType portNum, //!< The port number
550 Fw::StringBase& file_name //!< The file to dispatch
551 ) override;
552
553 //! Handler for ping port
554 void pingIn_handler(FwIndexType portNum, //!< The port number
555 U32 key //!< Value to return to pinger
556 ) override;
557
558 //! Handler implementation for seqCancelIn
559 //!
560 void seqCancelIn_handler(const FwIndexType portNum /*!< The port number*/
561 ) override;
562
563 private:
564 // ----------------------------------------------------------------------
565 // Command handler implementations
566 // ----------------------------------------------------------------------
567
568 //! Handler for command CS_AUTO
569 //! Set the run mode to AUTO.
570 void CS_AUTO_cmdHandler(FwOpcodeType opcode, //!< The opcode
571 U32 cmdSeq //!< The command sequence number
572 ) override;
573
574 //! Handler for command CS_CANCEL
575 //! Validate a command sequence file
576 void CS_CANCEL_cmdHandler(FwOpcodeType opCode, //!< The opcode
577 U32 cmdSeq //!< The command sequence number
578 ) override;
579
580 //! Handler for command CS_MANUAL
581 //! Set the run mode to MANUAL.
582 void CS_MANUAL_cmdHandler(FwOpcodeType opcode, //!< The opcode
583 U32 cmdSeq //!< The command sequence number
584 ) override;
585
586 //! Handler for command CS_RUN
587 void CS_RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
588 U32 cmdSeq, //!< The command sequence number
589 const Fw::CmdStringArg& fileName, //!< The file name
590 const Svc::BlockState& block /*!< Return command status when complete or not*/
591 ) override;
592
593 //! Handler for command CS_START
594 //! Start running a command sequence
595 void CS_START_cmdHandler(FwOpcodeType opcode, //!< The opcode
596 U32 cmdSeq //!< The command sequence number
597 ) override;
598
599 //! Handler for command CS_STEP
600 //! Perform one step in a command sequence.
601 //! Valid only if SequenceRunner is in MANUAL run mode.
602 void CS_STEP_cmdHandler(FwOpcodeType opcode, //!< The opcode
603 U32 cmdSeq //!< The command sequence number
604 ) override;
605
606 //! Handler for command CS_VALIDATE
607 //! Run a command sequence file
608 void CS_VALIDATE_cmdHandler(FwOpcodeType opCode, //!< The opcode
609 U32 cmdSeq, //!< The command sequence number
610 const Fw::CmdStringArg& fileName //!< The name of the sequence file
611 ) override;
612
613 //! Implementation for CS_JOIN command handler
614 //! Wait for sequences that are running to finish.
615 //! Allow user to run multiple seq files in SEQ_NO_BLOCK mode
616 //! then wait for them to finish before allowing more seq run request.
617 void CS_JOIN_WAIT_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/
618 const U32 cmdSeq /*!< The command sequence number*/
619 ) override;
620
621 private:
622 // ----------------------------------------------------------------------
623 // Private helper methods
624 // ----------------------------------------------------------------------
625
626 //! Load a sequence file
627 //! \return Success or failure
628 bool loadFile(const Fw::ConstStringBase& fileName //!< The file name
629 );
630
631 //! Perform a Cancel command
632 void performCmd_Cancel();
633
634 //! Perform a Step command
635 void performCmd_Step();
636
637 //! Perform a Step command with a relative time
638 void performCmd_Step_RELATIVE(Fw::Time& currentTime //!< The time
639 );
640
641 //! Perform a Step command with an absolute time
642 void performCmd_Step_ABSOLUTE(Fw::Time& currentTime //!< The time
643 );
644
645 //! Record a completed command
646 void commandComplete(const FwOpcodeType opCode //!< The opcode
647 );
648
649 //! Record a sequence complete event
650 void sequenceComplete();
651
652 //! Record an error
653 void error();
654
655 //! Record an error in executing a sequence command
656 void commandError(const U32 number, //!< The command number
657 const FwOpcodeType opCode, //!< The command opcode
658 const U32 error //!< The error code
659 );
660
661 //! Require a run mode
662 //! \return Whether we are in the correct mode
663 bool requireRunMode(RunMode mode //!< The required mode
664 );
665
666 //! Set command timeout timer
667 void setCmdTimeout(const Fw::Time& currentTime //!< The current time
668 );
669
670 //! Check a sequence file name against the configured sandbox directory, if any.
671 //! Emits CS_FileOutsideSandbox and counts an error on rejection.
672 //! \return true if the file may be opened
673 bool checkSandbox(const Fw::ConstStringBase& fileName //!< The file name
674 );
675
676 //! Shared body of the seqRunIn and seqDispatchIn handlers
677 void doSequenceRun(const Fw::StringBase& fileName);
678
679 //! Answer a rejected seqRunIn / seqDispatchIn request with EXECUTION_ERROR on seqDone,
680 //! if that port is connected
681 void rejectSequenceRun();
682
683 private:
684 // ----------------------------------------------------------------------
685 // Private member variables
686 // ----------------------------------------------------------------------
687
688 //! The F Prime sequence
689 FPrimeSequence m_FPrimeSequence;
690
691 //! The abstract sequence
692 Sequence* m_sequence;
693
694 //! The number of Load commands executed
695 U32 m_loadCmdCount;
696
697 //! The number of Cancel commands executed
698 U32 m_cancelCmdCount;
699
700 //! The number of errors
701 U32 m_errorCount;
702
703 //! The run mode
704 RunMode m_runMode;
705
706 //! The step mode
707 StepMode m_stepMode;
708
709 //! The sequence record currently being processed
710 Sequence::Record m_record;
711
712 //! The command time timer
713 Timer m_cmdTimer;
714
715 //! The number of commands executed in this sequence
716 U32 m_executedCount;
717
718 //! The total number of commands executed across all sequences
719 U32 m_totalExecutedCount;
720
721 //! The total number of sequences completed
722 U32 m_sequencesCompletedCount;
723
724 //! timeout value
725 U32 m_timeout;
726
727 //! timeout timer
728 Timer m_cmdTimeoutTimer;
729
730 //! Block mode for command status
731 Svc::BlockState::t m_blockState;
732 FwOpcodeType m_opCode;
733 U32 m_cmdSeq;
734 bool m_join_waiting;
735
736 //! Directory sequence file loads are restricted to (resolved, with trailing '/')
737 char m_sandboxDir[Os::FilePathUtils::MAX_PATH_LENGTH];
738
739 //! Whether configureSandbox() has been called; until then any path is allowed
740 bool m_sandboxConfigured;
741
742 //! Telemetry to update sequence not running
743 const Fw::String NO_SEQ{"<no seq>"};
744 };
745
746 } // namespace Svc
747
748 #endif
749