Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Svc/CmdSequencer/CmdSequencerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,7 @@ void CmdSequencerComponentImpl::doSequenceRun(const Fw::StringBase& filename) {
this->log_ACTIVITY_HI_CS_PortSequenceStarted(this->m_sequence->getLogFileName());
}

void CmdSequencerComponentImpl::seqRunIn_handler(FwIndexType portNum,
const Fw::StringBase& filename,
const Svc::SeqArgs& args) {
void CmdSequencerComponentImpl::seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename, const Svc::SeqArgs& args) {
(void)args; // Suppress unused parameter warning
this->doSequenceRun(filename);
}
Expand Down
30 changes: 29 additions & 1 deletion Svc/FpySequencer/FpySequencer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ class FpySequencer : public FpySequencerComponentBase {
const Fw::CmdStringArg& fileName, //!< The name of the sequence file
FpySequencer_BlockState block //!< Return command status when complete or not
) override;

//! Handler implementation for command RUN_ARGS
void RUN_ARGS_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName, //!< The name of the sequence file
Svc::FpySequencer_BlockState block, //!< Return command status when complete or not
Svc::SeqArgs args //!< Arguments to pass to the sequencer
) override;

//! Handler implementation for command RUN_ARGS
void RUN_ARGS_cmdHandler(FwOpcodeType opCode, //!< The opcode
Expand All @@ -161,7 +169,6 @@ class FpySequencer : public FpySequencerComponentBase {
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName //!< The name of the sequence file
) override;

//! Handler implementation for command VALIDATE_ARGS
//!
//! Loads and validates a sequence with arguments
Expand Down Expand Up @@ -269,6 +276,15 @@ class FpySequencer : public FpySequencerComponentBase {
Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
const Svc::FpySequencer_SequenceExecutionArgs& value //!< The value
) override;

//! Implementation for action setSequenceArguments of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! sets the arguments to pass to the sequence
void Svc_FpySequencer_SequencerStateMachine_action_setSequenceArguments(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal, //!< The signal
const Svc::FpySequencer_SequenceExecutionArgs& value //!< The value
) override;

//! Implementation for action setSequenceArguments of state machine Svc_FpySequencer_SequencerStateMachine
//!
Expand Down Expand Up @@ -359,6 +375,14 @@ class FpySequencer : public FpySequencerComponentBase {
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;

//! Implementation for action clearSequenceArguments of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! clears arguments
void Svc_FpySequencer_SequencerStateMachine_action_clearSequenceArguments(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;

//! Implementation for action clearSequenceArguments of state machine Svc_FpySequencer_SequencerStateMachine
//!
Expand Down Expand Up @@ -640,6 +664,10 @@ class FpySequencer : public FpySequencerComponentBase {
// live running computation of CRC (updated as we read)
U32 m_computedCRC;

// Size of arguments read in current sequence. Used for validation between
// User provided arguments and what is requested of the sequence.
Fpy::StackSizeType m_totalExpectedArgSize{0};

// whether or not the sequence we're about to run should return immediately or
// block on completion
FpySequencer_BlockState m_sequenceBlockState;
Expand Down
17 changes: 17 additions & 0 deletions Svc/FpySequencer/FpySequencerEvents.fppi
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,23 @@ event TooManySequenceDirectives(
severity warning high \
format "A sequence specified it had {} directives but the max was {}"

event ArgSizeMismatch(
expected: Fpy.StackSizeType
actual: FwSizeType
filePath: string
) \
severity warning high \
format "Expected {} bytes of arguments, but received {} in sequence file {}"

event ArgTotalSizeExceedsStackLimit(
argSize: Fpy.StackSizeType
maxStackSize: Fpy.StackSizeType
filePath: string
) \
severity warning high \
format "Adding argument of size {} would exceed max stack size {} in sequence file {}"


event SequencePaused(
stmtIdx: U32
) \
Expand Down
18 changes: 16 additions & 2 deletions Svc/FpySequencer/FpySequencerTypes.fpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Svc {
module Fpy {
@ the current schema version (must be representable in U8)
constant SCHEMA_VERSION = 5;
constant SCHEMA_VERSION = 6;

@ the type which everything referencing a size or offset on the stack is represented in
# we use a U32 because U16 is too small (would only allow up to 65 kB max stack size)
Expand Down Expand Up @@ -130,6 +130,20 @@ module Svc {
CMD_FAIL = 17
}

@ Maximum length for argument or type names in arg_specs
@ Fpy serializes these as U8 length prefix, so max is 255
constant MAX_ARG_SPEC_NAME_LEN = 255

@ Argument specification describing an input argument's name, type, and stack size
@ NOTE: This struct does NOT use FPP's auto-generated serialization!
@ Serialization is handled manually in C++ to match Fpy's format:
struct ArgSpec {
argName: string size MAX_ARG_SPEC_NAME_LEN
typeName: string size MAX_ARG_SPEC_NAME_LEN
@ Size of this argument on the stack in bytes
argSize: StackSizeType
} default {argName = "", typeName = "", argSize = 0 }

struct Header {
@ the major version of the FSW
majorVersion: U8
Expand Down Expand Up @@ -165,7 +179,7 @@ module Svc {
header: Header
@ an array of size m_header.argumentCount mapping argument position to local
@ variable index
args: [MAX_SEQUENCE_ARG_COUNT] U8
args: [MAX_SEQUENCE_ARG_COUNT] ArgSpec
statements: [MAX_SEQUENCE_STATEMENT_COUNT] Statement
footer: Footer
}
Expand Down
67 changes: 59 additions & 8 deletions Svc/FpySequencer/FpySequencerValidationState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Fw::Success FpySequencer::validate() {
if (readStatus != Fw::Success::SUCCESS) {
return Fw::Success::FAILURE;
}

// read footer bytes but don't include in CRC
readStatus = this->readBytes(sequenceFile, Fpy::Footer::SERIALIZED_SIZE, FpySequencer_FileReadStage::FOOTER, false);

Expand Down Expand Up @@ -145,20 +145,71 @@ Fw::Success FpySequencer::readHeader() {
// return SUCCESS if sequence is valid, FAILURE otherwise
Fw::Success FpySequencer::readBody() {
Fw::SerializeStatus deserStatus;
// deser body:
// deser arg mappings
for (U8 argMappingIdx = 0; argMappingIdx < this->m_sequenceObj.get_header().get_argumentCount(); argMappingIdx++) {
// serializable register index of arg $argMappingIdx
// TODO should probably check that this serReg is inside range
deserStatus = this->m_sequenceBuffer.deserializeTo(this->m_sequenceObj.get_args()[argMappingIdx]);
if (deserStatus != Fw::FW_SERIALIZE_OK) {

const U8 argumentCount = this->m_sequenceObj.get_header().get_argumentCount();
this->m_totalExpectedArgSize = 0;

// deser arguments
// Read and deserialize each arg_spec incrementally since they're variable-length
for (U8 i = 0; i < argumentCount; i++) {
Fpy::ArgSpec& argSpec = this->m_sequenceObj.get_args()[i];
Fw::String myString{};
// Read arg_name (length + string)
deserStatus = this->m_sequenceBuffer.deserializeTo(myString);
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_FileReadDeserializeError(
FpySequencer_FileReadStage::BODY,
this->m_sequenceFilePath,
static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getDeserializeSizeLeft(),
this->m_sequenceBuffer.getSize()
);
return Fw::Success::FAILURE;
}
argSpec.set_argName(myString);

// Read type_name (length + string)
deserStatus = this->m_sequenceBuffer.deserializeTo(myString);
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_FileReadDeserializeError(
FpySequencer_FileReadStage::BODY,
this->m_sequenceFilePath,
static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getDeserializeSizeLeft(),
this->m_sequenceBuffer.getSize()
);
return Fw::Success::FAILURE;
}
argSpec.set_typeName(myString);

// Read and deserialize size field
Fpy::StackSizeType argSize = 0;
deserStatus = this->m_sequenceBuffer.deserializeTo(argSize);
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_FileReadDeserializeError(
FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
return Fw::Success::FAILURE;
}

// Check for overflow before accumulation
if (m_totalExpectedArgSize > Fpy::MAX_STACK_SIZE - argSize) {
this->log_WARNING_HI_ArgTotalSizeExceedsStackLimit(argSize, Fpy::MAX_STACK_SIZE,
this->m_sequenceFilePath);
return Fw::Success::FAILURE;
}
argSpec.set_argSize(argSize);
m_totalExpectedArgSize += argSize;
}

// Validate total argument size
if (this->m_totalExpectedArgSize != this->m_sequenceArgs.get_size()){
this->log_WARNING_HI_ArgSizeMismatch(this->m_sequenceObj.get_header().get_argumentCount(),
this->m_sequenceArgs.get_size(),
this->m_sequenceFilePath);
return Fw::Success::FAILURE;
}

// deser statements
for (U16 statementIdx = 0; statementIdx < this->m_sequenceObj.get_header().get_statementCount(); statementIdx++) {
// deser statement
Expand Down
Loading
Loading