Skip to content

Commit 6930ce7

Browse files
committed
Add arg names to header and valid
1 parent d81aefe commit 6930ce7

5 files changed

Lines changed: 168 additions & 1 deletion

File tree

Svc/FpySequencer/FpySequencer.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,9 @@ class FpySequencer : public FpySequencerComponentBase {
645645
// sequence arguments to push to stack when entering RUNNING state
646646
Svc::SeqArgs m_sequenceArgs{};
647647

648+
// the expected argument size from arg_specs (schema version 6+)
649+
Fpy::StackSizeType m_expectedArgSize{0};
650+
648651
// the goal state is the state that we're trying to reach in the sequencer
649652
// if it's RUNNING, then we should promptly go to RUNNING once we validate the
650653
// sequence. if it's VALID, we should wait after VALIDATING
@@ -746,6 +749,9 @@ class FpySequencer : public FpySequencerComponentBase {
746749
// reads and validates the header from the m_sequenceBuffer
747750
// return SUCCESS if sequence is valid, FAILURE otherwise
748751
Fw::Success readHeader();
752+
// reads and parses arg_specs from the sequence file (schema version 6+)
753+
// return SUCCESS if successful, FAILURE otherwise
754+
Fw::Success readArgSpecs(Os::File& file);
749755
// reads and validates the body from the m_sequenceBuffer
750756
// return SUCCESS if sequence is valid, FAILURE otherwise
751757
Fw::Success readBody();

Svc/FpySequencer/FpySequencerEvents.fppi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ event TooManySequenceDirectives(
215215
severity warning high \
216216
format "A sequence specified it had {} directives but the max was {}"
217217

218+
event ArgSizeMismatch(
219+
expected: Fpy.StackSizeType
220+
actual: FwSizeType
221+
) \
222+
severity warning high \
223+
format "Expected {} bytes of arguments based on arg_specs, but received {}"
224+
218225
event SequencePaused(
219226
stmtIdx: U32
220227
) \

Svc/FpySequencer/FpySequencerStateMachine.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ void FpySequencer ::Svc_FpySequencer_SequencerStateMachine_action_clearSequenceA
305305
Svc_FpySequencer_SequencerStateMachine::Signal signal
306306
) {
307307
this->m_sequenceArgs = {0, 0};
308+
this->m_expectedArgSize = 0;
308309
}
309310

310311
//! Implementation for action clearBreakpoint of state machine Svc_FpySequencer_SequencerStateMachine

Svc/FpySequencer/FpySequencerTypes.fpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Svc {
22
module Fpy {
33
@ the current schema version (must be representable in U8)
4-
constant SCHEMA_VERSION = 5;
4+
constant SCHEMA_VERSION = 6;
55

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

133+
@ Maximum length for argument or type names in arg_specs
134+
@ Fpy serializes these as U8 length prefix, so max is 255
135+
constant MAX_ARG_SPEC_NAME_LEN = 255
136+
137+
@ Argument specification describing an input argument's name, type, and stack size
138+
@ NOTE: This struct does NOT use FPP's auto-generated serialization!
139+
@ Serialization is handled manually in C++ to match Fpy's format:
140+
@ [U8 argNameLen][argNameLen bytes][U8 typeNameLen][typeNameLen bytes][U32 size]
141+
struct ArgSpec {
142+
@ Length of the argument name (0-255)
143+
argNameLen: U8
144+
@ Argument name as UTF-8 bytes (not null-terminated)
145+
argName: [MAX_ARG_SPEC_NAME_LEN] U8
146+
@ Length of the type name (0-255)
147+
typeNameLen: U8
148+
@ Type name as UTF-8 bytes (not null-terminated)
149+
typeName: [MAX_ARG_SPEC_NAME_LEN] U8
150+
@ Size of this argument on the stack in bytes
151+
size: StackSizeType
152+
} default { argNameLen = 0, argName = [0], typeNameLen = 0, typeName = [0], size = 0 }
153+
133154
struct Header {
134155
@ the major version of the FSW
135156
majorVersion: U8
@@ -149,6 +170,12 @@ module Svc {
149170
150171
@ the size of the body in bytes
151172
bodySize: U32
173+
174+
@ Argument specifications (schema version 6+)
175+
@ Only the first argumentCount entries are valid
176+
@ NOTE: These are NOT included in SERIALIZED_SIZE as they are variable-length
177+
@ and must be deserialized manually in C++
178+
argSpecs: [MAX_SEQUENCE_ARG_COUNT] ArgSpec
152179
} default { majorVersion = 0, minorVersion = 0, patchVersion = 0, schemaVersion = 0, argumentCount = 0, statementCount = 0, bodySize = 0 }
153180
154181
struct Footer {

Svc/FpySequencer/FpySequencerValidationState.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ Fw::Success FpySequencer::validate() {
6161
return Fw::Success::FAILURE;
6262
}
6363

64+
// Read and parse arg_specs (schema version 6+)
65+
if (this->m_sequenceObj.get_header().get_schemaVersion() >= 6) {
66+
readStatus = this->readArgSpecs(sequenceFile);
67+
if (readStatus != Fw::Success::SUCCESS) {
68+
return Fw::Success::FAILURE;
69+
}
70+
} else {
71+
// For older schema versions, no arg_specs validation needed
72+
this->m_expectedArgSize = 0;
73+
}
74+
6475
readStatus =
6576
readBytes(sequenceFile, this->m_sequenceObj.get_header().get_bodySize(), FpySequencer_FileReadStage::BODY);
6677

@@ -105,6 +116,14 @@ Fw::Success FpySequencer::validate() {
105116
return Fw::Success::FAILURE;
106117
}
107118

119+
// Validate argument size matches expected size from arg_specs (schema version 6+)
120+
if (this->m_sequenceObj.get_header().get_schemaVersion() >= 6 && this->m_expectedArgSize > 0) {
121+
if (this->m_sequenceArgs.get_size() != this->m_expectedArgSize) {
122+
this->log_WARNING_HI_ArgSizeMismatch(this->m_expectedArgSize, this->m_sequenceArgs.get_size());
123+
return Fw::Success::FAILURE;
124+
}
125+
}
126+
108127
return Fw::Success::SUCCESS;
109128
}
110129

@@ -141,6 +160,113 @@ Fw::Success FpySequencer::readHeader() {
141160
return Fw::Success::SUCCESS;
142161
}
143162

163+
// reads and parses arg_specs from the sequence file (schema version 6+)
164+
// stores them in the Header struct and calculates the total expected argument size
165+
// return SUCCESS if successful, FAILURE otherwise
166+
Fw::Success FpySequencer::readArgSpecs(Os::File& file) {
167+
FW_ASSERT(file.isOpen());
168+
169+
const U8 argumentCount = this->m_sequenceObj.get_header().get_argumentCount();
170+
171+
// If no arguments, no arg_specs to read
172+
if (argumentCount == 0) {
173+
this->m_expectedArgSize = 0;
174+
return Fw::Success::SUCCESS;
175+
}
176+
177+
Fpy::StackSizeType totalExpectedSize = 0;
178+
179+
for (U8 i = 0; i < argumentCount; i++) {
180+
// Get reference to the ArgSpec we're populating
181+
Fpy::ArgSpec& argSpec = this->m_sequenceObj.get_header().get_argSpecs()[i];
182+
183+
// Read arg_name length
184+
Fw::Success readStatus = this->readBytes(file, 1, FpySequencer_FileReadStage::BODY);
185+
if (readStatus != Fw::Success::SUCCESS) {
186+
return Fw::Success::FAILURE;
187+
}
188+
U8 argNameLen = 0;
189+
Fw::SerializeStatus deserStatus = this->m_sequenceBuffer.deserializeTo(argNameLen);
190+
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
191+
this->log_WARNING_HI_FileReadDeserializeError(
192+
FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
193+
this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
194+
return Fw::Success::FAILURE;
195+
}
196+
argSpec.set_argNameLen(argNameLen);
197+
198+
// Read arg_name string and store it
199+
if (argNameLen > 0) {
200+
readStatus = this->readBytes(file, argNameLen, FpySequencer_FileReadStage::BODY);
201+
if (readStatus != Fw::Success::SUCCESS) {
202+
return Fw::Success::FAILURE;
203+
}
204+
// Store the arg_name bytes in the ArgSpec
205+
for (U8 j = 0; j < argNameLen; j++) {
206+
U8 byte;
207+
deserStatus = this->m_sequenceBuffer.deserializeTo(byte);
208+
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
209+
return Fw::Success::FAILURE;
210+
}
211+
argSpec.get_argName()[j] = byte;
212+
}
213+
}
214+
215+
// Read type_name length
216+
readStatus = this->readBytes(file, 1, FpySequencer_FileReadStage::BODY);
217+
if (readStatus != Fw::Success::SUCCESS) {
218+
return Fw::Success::FAILURE;
219+
}
220+
U8 typeNameLen = 0;
221+
deserStatus = this->m_sequenceBuffer.deserializeTo(typeNameLen);
222+
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
223+
this->log_WARNING_HI_FileReadDeserializeError(
224+
FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
225+
this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
226+
return Fw::Success::FAILURE;
227+
}
228+
argSpec.set_typeNameLen(typeNameLen);
229+
230+
// Read type_name string and store it
231+
if (typeNameLen > 0) {
232+
readStatus = this->readBytes(file, typeNameLen, FpySequencer_FileReadStage::BODY);
233+
if (readStatus != Fw::Success::SUCCESS) {
234+
return Fw::Success::FAILURE;
235+
}
236+
// Store the type_name bytes in the ArgSpec
237+
for (U8 j = 0; j < typeNameLen; j++) {
238+
U8 byte;
239+
deserStatus = this->m_sequenceBuffer.deserializeTo(byte);
240+
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
241+
return Fw::Success::FAILURE;
242+
}
243+
argSpec.get_typeName()[j] = byte;
244+
}
245+
}
246+
247+
// Read size field (StackSizeType = U32, 4 bytes, big-endian)
248+
readStatus = this->readBytes(file, sizeof(Fpy::StackSizeType), FpySequencer_FileReadStage::BODY);
249+
if (readStatus != Fw::Success::SUCCESS) {
250+
return Fw::Success::FAILURE;
251+
}
252+
Fpy::StackSizeType argSize = 0;
253+
deserStatus = this->m_sequenceBuffer.deserializeTo(argSize);
254+
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
255+
this->log_WARNING_HI_FileReadDeserializeError(
256+
FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
257+
this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
258+
return Fw::Success::FAILURE;
259+
}
260+
argSpec.set_size(argSize);
261+
262+
// Accumulate the expected argument size
263+
totalExpectedSize += argSize;
264+
}
265+
266+
this->m_expectedArgSize = totalExpectedSize;
267+
return Fw::Success::SUCCESS;
268+
}
269+
144270
// reads and validates the body from the m_sequenceBuffer
145271
// return SUCCESS if sequence is valid, FAILURE otherwise
146272
Fw::Success FpySequencer::readBody() {

0 commit comments

Comments
 (0)