@@ -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
146272Fw::Success FpySequencer::readBody () {
0 commit comments