From a91f24cb38d79dcb49c65d718127aa1da00d88f9 Mon Sep 17 00:00:00 2001 From: Zimri Leisher Date: Sun, 13 Jul 2025 13:22:33 -0500 Subject: [PATCH] Add float to int conversion directives, some misc changes (#3847) * Add fptoi and itofp dirs * Fix F32 literal * Add some file read stage telemetry to err msgs * Update default register count to 128 * Fix NOT directive to behave properly with if * Make fptoi and itofp signed/unsigned * fix warning * Fix another warning * Fix sp --- .github/actions/spelling/expect.txt | 5 ++ Svc/FpySequencer/FpySequencer.fpp | 6 ++ Svc/FpySequencer/FpySequencer.hpp | 85 ++++++++++--------- Svc/FpySequencer/FpySequencerDirectives.cpp | 65 ++++++++++++-- Svc/FpySequencer/FpySequencerEvents.fppi | 11 ++- Svc/FpySequencer/FpySequencerRunState.cpp | 12 ++- Svc/FpySequencer/FpySequencerTypes.fpp | 9 +- .../FpySequencerValidationState.cpp | 41 +++++---- .../test/ut/FpySequencerTestMain.cpp | 56 ++++++++++-- .../test/ut/FpySequencerTestSequences.cpp | 16 ++++ .../test/ut/FpySequencerTester.cpp | 16 +++- .../test/ut/FpySequencerTester.hpp | 6 +- default/config/FpySequencerCfg.fpp | 2 +- 13 files changed, 243 insertions(+), 87 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a05ff045b3..5d161e084a 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -244,11 +244,14 @@ fpptest fprime fptr fptrunc +fptosi +fptoui fputil fpy FPYSEQUENCER freeram Fregoso +fres frhs frsize fsblkcnt @@ -599,6 +602,7 @@ sideeffect sighandler Signedness Silveira +sitofp sle sloc socio @@ -696,6 +700,7 @@ typedef uart UDPSOCKET uge +uitofp ulhs UML UNEXP diff --git a/Svc/FpySequencer/FpySequencer.fpp b/Svc/FpySequencer/FpySequencer.fpp index c49ab1aa68..5fca4fafde 100644 --- a/Svc/FpySequencer/FpySequencer.fpp +++ b/Svc/FpySequencer/FpySequencer.fpp @@ -13,6 +13,12 @@ module Svc { IDLE } + enum FileReadStage { + HEADER + BODY + FOOTER + } + include "FpySequencerCommands.fppi" include "FpySequencerTelemetry.fppi" include "FpySequencerEvents.fppi" diff --git a/Svc/FpySequencer/FpySequencer.hpp b/Svc/FpySequencer/FpySequencer.hpp index adbd1acbf5..26cbd812f7 100644 --- a/Svc/FpySequencer/FpySequencer.hpp +++ b/Svc/FpySequencer/FpySequencer.hpp @@ -23,8 +23,7 @@ static_assert(Svc::Fpy::MAX_SEQUENCE_ARG_COUNT <= std::numeric_limits::max(), "Sequence arg count must be below U8 max"); -static_assert(Svc::Fpy::NUM_REGISTERS <= std::numeric_limits::max(), - "Register count must be below U8 max"); +static_assert(Svc::Fpy::NUM_REGISTERS <= std::numeric_limits::max(), "Register count must be below U8 max"); static_assert(Svc::Fpy::MAX_SEQUENCE_STATEMENT_COUNT <= std::numeric_limits::max(), "Sequence statement count must be below U16 max"); static_assert(Svc::Fpy::MAX_SERIALIZABLE_REGISTER_SIZE <= std::numeric_limits::max(), @@ -41,8 +40,7 @@ using State = FpySequencer_SequencerStateMachineStateMachineBase::State; using DirectiveError = FpySequencer_DirectiveErrorCode; class FpySequencer : public FpySequencerComponentBase { - - friend class FpySequencerTester; + friend class FpySequencerTester; public: union DirectiveUnion { @@ -78,17 +76,15 @@ class FpySequencer : public FpySequencerComponentBase { //! ~FpySequencer(); - private: - - //! Handler for command RUN - //! - //! Loads, validates and runs a sequence - void - RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode - U32 cmdSeq, //!< The command sequence number - const Fw::CmdStringArg& fileName, //!< The name of the sequence file - FpySequencer_BlockState block //!< Return command status when complete or not - ) override; + private: + //! Handler for command RUN + //! + //! Loads, validates and runs a sequence + void RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + const Fw::CmdStringArg& fileName, //!< The name of the sequence file + FpySequencer_BlockState block //!< Return command status when complete or not + ) override; //! Handler for command VALIDATE //! @@ -323,32 +319,30 @@ class FpySequencer : public FpySequencerComponentBase { //! //! called when a sequence failed to execute successfully void Svc_FpySequencer_SequencerStateMachine_action_report_seqFailed( - SmId smId, //!< The state machine id - Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal - ) override; + SmId smId, //!< The state machine id + Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal + ) override; //! Implementation for action report_seqStarted of state machine Svc_FpySequencer_SequencerStateMachine //! //! reports that a sequence was started void Svc_FpySequencer_SequencerStateMachine_action_report_seqStarted( - SmId smId, //!< The state machine id - Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal - ) override; + SmId smId, //!< The state machine id + Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal + ) override; - protected: + protected: + // ---------------------------------------------------------------------- + // Functions to implement for internal state machine guards + // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // Functions to implement for internal state machine guards - // ---------------------------------------------------------------------- - - //! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine - //! - //! return true if the goal state is RUNNING - bool - Svc_FpySequencer_SequencerStateMachine_guard_goalStateIs_RUNNING( - SmId smId, //!< The state machine id - Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal - ) const override; + //! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine + //! + //! return true if the goal state is RUNNING + bool Svc_FpySequencer_SequencerStateMachine_guard_goalStateIs_RUNNING( + SmId smId, //!< The state machine id + Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal + ) const override; //! Implementation for guard shouldDebugBreak of state machine Svc_FpySequencer_SequencerStateMachine //! @@ -384,9 +378,7 @@ class FpySequencer : public FpySequencerComponentBase { ) override; //! Handler for input port seqRunIn - void seqRunIn_handler(FwIndexType portNum, - const Fw::StringBase& filename - ) override; + void seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename) override; //! Handler for input port pingIn void pingIn_handler(FwIndexType portNum, //!< The port number @@ -426,13 +418,15 @@ class FpySequencer : public FpySequencerComponentBase { void directive_cmd_internalInterfaceHandler(const Svc::FpySequencer_CmdDirective& directive) override; //! Internal interface handler for directive_deserSerReg - void directive_deserSerReg_internalInterfaceHandler(const Svc::FpySequencer_DeserSerRegDirective& directive) override; + void directive_deserSerReg_internalInterfaceHandler( + const Svc::FpySequencer_DeserSerRegDirective& directive) override; //! Internal interface handler for directive_setReg void directive_setReg_internalInterfaceHandler(const Svc::FpySequencer_SetRegDirective& directive) override; //! Internal interface handler for directive_binaryRegOp - void directive_binaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_BinaryRegOpDirective& directive) override; + void directive_binaryRegOp_internalInterfaceHandler( + const Svc::FpySequencer_BinaryRegOpDirective& directive) override; //! Internal interface handler for directive_unaryRegOp void directive_unaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_UnaryRegOpDirective& directive) override; @@ -447,9 +441,9 @@ class FpySequencer : public FpySequencerComponentBase { void allocateBuffer(FwEnumStoreType identifier, Fw::MemAllocator& allocator, FwSizeType bytes); void deallocateBuffer(Fw::MemAllocator& allocator); - private : - static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU; + private: + static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU; // allocated at startup Fw::ExternalSerializeBuffer m_sequenceBuffer; @@ -570,7 +564,10 @@ class FpySequencer : public FpySequencerComponentBase { // updates the CRC by default, but can be turned off if the contents // aren't included in CRC. // return success if successful - Fw::Success readBytes(Os::File& file, FwSizeType readLen, bool updateCrc = true); + Fw::Success readBytes(Os::File& file, + FwSizeType readLen, + const FpySequencer_FileReadStage& readStage, + bool updateCrc = true); // ---------------------------------------------------------------------- // Run state @@ -648,6 +645,10 @@ class FpySequencer : public FpySequencerComponentBase { I64 unaryRegOp_not(I64 src); I64 unaryRegOp_fpext(I64 src); I64 unaryRegOp_fptrunc(I64 src); + I64 unaryRegOp_fptoui(I64 src); + I64 unaryRegOp_fptosi(I64 src); + I64 unaryRegOp_sitofp(I64 src); + I64 unaryRegOp_uitofp(I64 src); Signal exit_directiveHandler(const FpySequencer_ExitDirective& directive, DirectiveError& error); }; diff --git a/Svc/FpySequencer/FpySequencerDirectives.cpp b/Svc/FpySequencer/FpySequencerDirectives.cpp index ba411802ef..55a1d223f2 100644 --- a/Svc/FpySequencer/FpySequencerDirectives.cpp +++ b/Svc/FpySequencer/FpySequencerDirectives.cpp @@ -111,15 +111,16 @@ void FpySequencer::directive_setReg_internalInterfaceHandler(const Svc::FpySeque } //! Internal interface handler for directive_binaryRegOp -void FpySequencer::directive_binaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_BinaryRegOpDirective& directive) { +void FpySequencer::directive_binaryRegOp_internalInterfaceHandler( + const Svc::FpySequencer_BinaryRegOpDirective& directive) { DirectiveError error = DirectiveError::NO_ERROR; this->sendSignal(this->binaryRegOp_directiveHandler(directive, error)); this->m_tlm.lastDirectiveError = error; } - //! Internal interface handler for directive_unaryRegOp -void FpySequencer::directive_unaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_UnaryRegOpDirective& directive) { +void FpySequencer::directive_unaryRegOp_internalInterfaceHandler( + const Svc::FpySequencer_UnaryRegOpDirective& directive) { DirectiveError error = DirectiveError::NO_ERROR; this->sendSignal(this->unaryRegOp_directiveHandler(directive, error)); this->m_tlm.lastDirectiveError = error; @@ -488,7 +489,7 @@ I64 FpySequencer::binaryRegOp_fge(I64 lhs, I64 rhs) { } Signal FpySequencer::binaryRegOp_directiveHandler(const FpySequencer_BinaryRegOpDirective& directive, - DirectiveError& error) { + DirectiveError& error) { // coding error, should not have gotten to this binary reg op handler FW_ASSERT(directive.get_op() >= Fpy::DirectiveId::OR && directive.get_op() <= Fpy::DirectiveId::FGE, static_cast(directive.get_op())); @@ -565,7 +566,10 @@ Signal FpySequencer::binaryRegOp_directiveHandler(const FpySequencer_BinaryRegOp return Signal::stmtResponse_success; } I64 FpySequencer::unaryRegOp_not(I64 src) { - return ~src; + if (src) { + return static_cast(false); + } + return static_cast(true); } I64 FpySequencer::unaryRegOp_fpext(I64 src) { // convert F32 to F64 @@ -594,10 +598,41 @@ I64 FpySequencer::unaryRegOp_fptrunc(I64 src) { // then extend to I64 return static_cast(itrunc); } - -Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDirective& directive, DirectiveError& error) { +I64 FpySequencer::unaryRegOp_fptosi(I64 src) { + // first interpret as F64 + F64 fsrc; + memcpy(&fsrc, &src, sizeof(fsrc)); + // then static cast to int + return static_cast(fsrc); +} +I64 FpySequencer::unaryRegOp_sitofp(I64 src) { + // first static cast to float + F64 fsrc = static_cast(src); + // then return bits as I64 + I64 res; + memcpy(&res, &fsrc, sizeof(res)); + return res; +} +I64 FpySequencer::unaryRegOp_fptoui(I64 src) { + // first interpret as F64 + F64 fsrc; + memcpy(&fsrc, &src, sizeof(fsrc)); + // then static cast to unsigned int + // then return as a signed int + return static_cast(static_cast(fsrc)); +} +I64 FpySequencer::unaryRegOp_uitofp(I64 src) { + // first static cast to unsigned, then to float + F64 fsrc = static_cast(static_cast(src)); + // then return bits as I64 + I64 res; + memcpy(&res, &fsrc, sizeof(res)); + return res; +} +Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDirective& directive, + DirectiveError& error) { // coding error, should not have gotten to this unary reg op handler - FW_ASSERT(directive.get_op() >= Fpy::DirectiveId::NOT && directive.get_op() <= Fpy::DirectiveId::FPTRUNC, + FW_ASSERT(directive.get_op() >= Fpy::DirectiveId::NOT && directive.get_op() <= Fpy::DirectiveId::UITOFP, static_cast(directive.get_op())); if (directive.getsrc() >= Fpy::NUM_REGISTERS || directive.getres() >= Fpy::NUM_REGISTERS) { @@ -607,7 +642,7 @@ Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDi I64 src = reg(directive.getsrc()); I64& res = reg(directive.getres()); - + switch (directive.get_op()) { case Fpy::DirectiveId::NOT: res = this->unaryRegOp_not(src); @@ -618,6 +653,18 @@ Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDi case Fpy::DirectiveId::FPTRUNC: res = this->unaryRegOp_fptrunc(src); break; + case Fpy::DirectiveId::FPTOSI: + res = this->unaryRegOp_fptosi(src); + break; + case Fpy::DirectiveId::FPTOUI: + res = this->unaryRegOp_fptoui(src); + break; + case Fpy::DirectiveId::SITOFP: + res = this->unaryRegOp_sitofp(src); + break; + case Fpy::DirectiveId::UITOFP: + res = this->unaryRegOp_uitofp(src); + break; default: FW_ASSERT(0, directive.get_op()); break; diff --git a/Svc/FpySequencer/FpySequencerEvents.fppi b/Svc/FpySequencer/FpySequencerEvents.fppi index 68609dc9d7..d672adbb91 100644 --- a/Svc/FpySequencer/FpySequencerEvents.fppi +++ b/Svc/FpySequencer/FpySequencerEvents.fppi @@ -1,6 +1,6 @@ event InvalidCommand($state: I32) \ severity warning high \ - format "Cannot run command in state {}" + format "Cannot execute command in state {}" event InvalidSeqRunCall($state: I32) \ severity warning high \ @@ -14,26 +14,29 @@ event FileOpenError( format "File open error encountered while opening {}: {}" event FileReadError( + readStage: FileReadStage filePath: string errorCode: I32 ) \ severity warning high \ - format "File read error encountered while reading {}: {}" + format "File read error encountered while reading {} of file {}: {}" event EndOfFileError( + readStage: FileReadStage filePath: string ) \ severity warning high \ - format "End of file encountered unexpectedly while reading {}" + format "End of file encountered unexpectedly while reading {} of file {}" event FileReadDeserializeError( + readStage: FileReadStage filePath: string errorCode: I32 buffLeft: U64 buffLength: U64 ) \ severity warning high \ - format "Deserialize error encountered while reading {}: {} ({} bytes left out of {})" + format "Deserialize error encountered while reading {} of file {}: {} ({} bytes left out of {})" event WrongSchemaVersion( expected: U8 diff --git a/Svc/FpySequencer/FpySequencerRunState.cpp b/Svc/FpySequencer/FpySequencerRunState.cpp index 6050438073..27aba05a15 100644 --- a/Svc/FpySequencer/FpySequencerRunState.cpp +++ b/Svc/FpySequencer/FpySequencerRunState.cpp @@ -332,7 +332,11 @@ Fw::Success FpySequencer::deserializeDirective(const Fpy::Statement& stmt, Direc // fallthrough on purpose case Fpy::DirectiveId::NOT: case Fpy::DirectiveId::FPEXT: - case Fpy::DirectiveId::FPTRUNC: { + case Fpy::DirectiveId::FPTRUNC: + case Fpy::DirectiveId::FPTOSI: + case Fpy::DirectiveId::FPTOUI: + case Fpy::DirectiveId::SITOFP: + case Fpy::DirectiveId::UITOFP: { new (&deserializedDirective.unaryRegOp) FpySequencer_UnaryRegOpDirective(); U8 src; @@ -456,7 +460,11 @@ void FpySequencer::dispatchDirective(const DirectiveUnion& directive, const Fpy: // fallthrough on purpose case Fpy::DirectiveId::NOT: case Fpy::DirectiveId::FPEXT: - case Fpy::DirectiveId::FPTRUNC: { + case Fpy::DirectiveId::FPTRUNC: + case Fpy::DirectiveId::FPTOSI: + case Fpy::DirectiveId::FPTOUI: + case Fpy::DirectiveId::SITOFP: + case Fpy::DirectiveId::UITOFP: { this->directive_unaryRegOp_internalInterfaceInvoke(directive.unaryRegOp); return; } diff --git a/Svc/FpySequencer/FpySequencerTypes.fpp b/Svc/FpySequencer/FpySequencerTypes.fpp index 0c4f4a452a..c1b7a701e8 100644 --- a/Svc/FpySequencer/FpySequencerTypes.fpp +++ b/Svc/FpySequencer/FpySequencerTypes.fpp @@ -49,11 +49,18 @@ module Svc { # unary reg op dirs NOT = 33 + # floating point extension and truncation FPEXT = 34 FPTRUNC = 35 + # floating point conversion to signed/unsigned integer, + # and vice versa + FPTOSI = 36 + FPTOUI = 37 + SITOFP = 38 + UITOFP = 39 # end unary reg op dirs - EXIT = 36 + EXIT = 40 } struct Header { diff --git a/Svc/FpySequencer/FpySequencerValidationState.cpp b/Svc/FpySequencer/FpySequencerValidationState.cpp index 12ae566b5f..6b508b5296 100644 --- a/Svc/FpySequencer/FpySequencerValidationState.cpp +++ b/Svc/FpySequencer/FpySequencerValidationState.cpp @@ -48,7 +48,8 @@ Fw::Success FpySequencer::validate() { return Fw::Success::FAILURE; } - Fw::Success readStatus = this->readBytes(sequenceFile, Fpy::Header::SERIALIZED_SIZE); + Fw::Success readStatus = + this->readBytes(sequenceFile, Fpy::Header::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER); if (readStatus != Fw::Success::SUCCESS) { return Fw::Success::FAILURE; @@ -60,7 +61,8 @@ Fw::Success FpySequencer::validate() { return Fw::Success::FAILURE; } - readStatus = readBytes(sequenceFile, this->m_sequenceObj.getheader().getbodySize()); + readStatus = + readBytes(sequenceFile, this->m_sequenceObj.getheader().getbodySize(), FpySequencer_FileReadStage::BODY); if (readStatus != Fw::Success::SUCCESS) { return Fw::Success::FAILURE; @@ -73,7 +75,7 @@ Fw::Success FpySequencer::validate() { } // read footer bytes but don't include in CRC - readStatus = this->readBytes(sequenceFile, Fpy::Footer::SERIALIZED_SIZE, false); + readStatus = this->readBytes(sequenceFile, Fpy::Footer::SERIALIZED_SIZE, FpySequencer_FileReadStage::FOOTER, false); if (readStatus != Fw::Success::SUCCESS) { return Fw::Success::FAILURE; @@ -104,9 +106,9 @@ Fw::Success FpySequencer::readHeader() { // deser header Fw::SerializeStatus deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getheader()); if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) { - this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast(deserStatus), - this->m_sequenceBuffer.getBuffLeft(), - this->m_sequenceBuffer.getBuffLength()); + this->log_WARNING_HI_FileReadDeserializeError( + FpySequencer_FileReadStage::HEADER, this->m_sequenceFilePath, static_cast(deserStatus), + this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength()); return Fw::Success::FAILURE; } @@ -140,9 +142,9 @@ Fw::Success FpySequencer::readBody() { // TODO should probably check that this serReg is inside range deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getargs()[argMappingIdx]); if (deserStatus != Fw::FW_SERIALIZE_OK) { - this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast(deserStatus), - this->m_sequenceBuffer.getBuffLeft(), - this->m_sequenceBuffer.getBuffLength()); + this->log_WARNING_HI_FileReadDeserializeError( + FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast(deserStatus), + this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength()); return Fw::Success::FAILURE; } } @@ -152,9 +154,9 @@ Fw::Success FpySequencer::readBody() { // deser statement deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getstatements()[statementIdx]); if (deserStatus != Fw::FW_SERIALIZE_OK) { - this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast(deserStatus), - this->m_sequenceBuffer.getBuffLeft(), - this->m_sequenceBuffer.getBuffLength()); + this->log_WARNING_HI_FileReadDeserializeError( + FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast(deserStatus), + this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength()); return Fw::Success::FAILURE; } } @@ -164,9 +166,9 @@ Fw::Success FpySequencer::readBody() { Fw::Success FpySequencer::readFooter() { Fw::SerializeStatus deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getfooter()); if (deserStatus != Fw::FW_SERIALIZE_OK) { - this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast(deserStatus), - this->m_sequenceBuffer.getBuffLeft(), - this->m_sequenceBuffer.getBuffLength()); + this->log_WARNING_HI_FileReadDeserializeError( + FpySequencer_FileReadStage::FOOTER, this->m_sequenceFilePath, static_cast(deserStatus), + this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength()); return Fw::Success::FAILURE; } @@ -183,7 +185,10 @@ Fw::Success FpySequencer::readFooter() { // reads some bytes from the open file into the m_sequenceBuffer. // return success if successful -Fw::Success FpySequencer::readBytes(Os::File& file, FwSizeType expectedReadLen, bool updateCrc) { +Fw::Success FpySequencer::readBytes(Os::File& file, + FwSizeType expectedReadLen, + const FpySequencer_FileReadStage& readStage, + bool updateCrc) { FW_ASSERT(file.isOpen()); // this has to be declared a var because file.read must take a ref FwSizeType actualReadLen = expectedReadLen; @@ -200,12 +205,12 @@ Fw::Success FpySequencer::readBytes(Os::File& file, FwSizeType expectedReadLen, Os::File::Status fileStatus = file.read(this->m_sequenceBuffer.getBuffAddr(), actualReadLen); if (fileStatus != Os::File::OP_OK) { - this->log_WARNING_HI_FileReadError(this->m_sequenceFilePath, static_cast(fileStatus)); + this->log_WARNING_HI_FileReadError(readStage, this->m_sequenceFilePath, static_cast(fileStatus)); return Fw::Success::FAILURE; } if (actualReadLen < expectedReadLen) { - this->log_WARNING_HI_EndOfFileError(this->m_sequenceFilePath); + this->log_WARNING_HI_EndOfFileError(readStage, this->m_sequenceFilePath); return Fw::Success::FAILURE; } diff --git a/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp b/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp index 74e6143530..e2d22c016e 100644 --- a/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp +++ b/Svc/FpySequencer/test/ut/FpySequencerTestMain.cpp @@ -691,12 +691,12 @@ TEST_F(FpySequencerTester, setReg) { TEST_F(FpySequencerTester, unaryRegOp) { // Test NOT FpySequencer_UnaryRegOpDirective directiveNOT(0, 1, Fpy::DirectiveId::NOT); - tester_get_m_runtime_ptr()->regs[0] = 10; + tester_get_m_runtime_ptr()->regs[0] = true; DirectiveError err = DirectiveError::NO_ERROR; Signal result = tester_unaryRegOp_directiveHandler(directiveNOT, err); ASSERT_EQ(result, Signal::stmtResponse_success); ASSERT_EQ(err, DirectiveError::NO_ERROR); - ASSERT_EQ(tester_get_m_runtime_ptr()->regs[1], ~10); + ASSERT_EQ(tester_get_m_runtime_ptr()->regs[1], false); // Test out-of-bounds register index FpySequencer_UnaryRegOpDirective directiveOOB(Fpy::NUM_REGISTERS, 1, Fpy::DirectiveId::FPEXT); @@ -711,7 +711,7 @@ TEST_F(FpySequencerTester, unaryRegOp) { TEST_F(FpySequencerTester, not) { - ASSERT_EQ(tester_unaryRegOp_not(0x123), ~0x123); + ASSERT_EQ(tester_unaryRegOp_not(true), false); } TEST_F(FpySequencerTester, fptrunc) { @@ -739,6 +739,48 @@ TEST_F(FpySequencerTester, fpext) { ASSERT_EQ(res_f, expected); } +TEST_F(FpySequencerTester, fptosi) { + F64 src = 123.123; + I64 expected = static_cast(src); + + I64 isrc; + memcpy(&isrc, &src, sizeof(isrc)); + + I64 res = tester_unaryRegOp_fptosi(isrc); + ASSERT_EQ(res, expected); +} + +TEST_F(FpySequencerTester, sitofp) { + I64 src = 123; + F64 expected = static_cast(src); + + I64 res = tester_unaryRegOp_sitofp(src); + F64 fres; + memcpy(&fres, &res, sizeof(res)); + ASSERT_EQ(fres, expected); +} + +TEST_F(FpySequencerTester, fptoui) { + F64 src = 123.123; + U64 expected = static_cast(src); + + I64 isrc; + memcpy(&isrc, &src, sizeof(isrc)); + + I64 res = tester_unaryRegOp_fptoui(isrc); + ASSERT_EQ(static_cast(res), expected); +} + +TEST_F(FpySequencerTester, uitofp) { + U64 src = std::numeric_limits::max(); + F64 expected = static_cast(src); + + I64 res = tester_unaryRegOp_uitofp(static_cast(src)); + F64 fres; + memcpy(&fres, &res, sizeof(res)); + ASSERT_EQ(fres, expected); +} + TEST_F(FpySequencerTester, exit) { FpySequencer_ExitDirective directive(true); DirectiveError err = DirectiveError::NO_ERROR; @@ -1193,20 +1235,20 @@ TEST_F(FpySequencerTester, readBytes) { tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, sizeof(data)); Os::File seqFile; ASSERT_EQ(seqFile.open("test.bin", Os::File::OPEN_READ), Os::File::OP_OK); - ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, true), Fw::Success::SUCCESS); + ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER, true), Fw::Success::SUCCESS); seqFile.close(); // check capacity too low tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, Fpy::Header::SERIALIZED_SIZE - 1); ASSERT_EQ(seqFile.open("test.bin", Os::File::OPEN_READ), Os::File::OP_OK); - ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, true), Fw::Success::FAILURE); + ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER, true), Fw::Success::FAILURE); seqFile.close(); // check not enough bytes tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE + 1); ASSERT_EQ(seqFile.open("test.bin", Os::File::OPEN_READ), Os::File::OP_OK); - ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE + 1, true), + ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE + 1, FpySequencer_FileReadStage::HEADER, true), Fw::Success::FAILURE); seqFile.close(); @@ -1214,7 +1256,7 @@ TEST_F(FpySequencerTester, readBytes) { // read after close ASSERT_DEATH_IF_SUPPORTED( - tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE, true), "Assert: "); + tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER, true), "Assert: "); } TEST_F(FpySequencerTester, validate) { diff --git a/Svc/FpySequencer/test/ut/FpySequencerTestSequences.cpp b/Svc/FpySequencer/test/ut/FpySequencerTestSequences.cpp index 2ac4515d7a..c20feb5d11 100644 --- a/Svc/FpySequencer/test/ut/FpySequencerTestSequences.cpp +++ b/Svc/FpySequencer/test/ut/FpySequencerTestSequences.cpp @@ -113,5 +113,21 @@ TEST_F(FpySequencerTester, CmpIntTlm) { dispatchUntilState(State::IDLE); ASSERT_EQ(tester_get_m_statementsDispatched(), 8); } +TEST_F(FpySequencerTester, NotTrueSeq) { + // this sequence caught one bug + allocMem(); + + add_SET_REG(0, 255); + add_UNARY_REG_OP(0, 1, Fpy::DirectiveId::NOT); + add_IF(1, 4); + // should not get here + add_EXIT(false); + add_EXIT(true); + + writeAndRun(); + dispatchUntilState(State::IDLE); + // not of 255 should be interpreted as false + ASSERT_EQ(tester_get_m_tlm_ptr()->lastDirectiveError, DirectiveError::NO_ERROR); +} } \ No newline at end of file diff --git a/Svc/FpySequencer/test/ut/FpySequencerTester.cpp b/Svc/FpySequencer/test/ut/FpySequencerTester.cpp index 7f2e9de917..401d865e4a 100644 --- a/Svc/FpySequencer/test/ut/FpySequencerTester.cpp +++ b/Svc/FpySequencer/test/ut/FpySequencerTester.cpp @@ -421,8 +421,8 @@ Svc::FpySequencer::Telemetry* FpySequencerTester::tester_get_m_tlm_ptr() { return &this->cmp.m_tlm; } -Fw::Success FpySequencerTester::tester_readBytes(Os::File& file, FwSizeType readLen, bool updateCrc) { - return this->cmp.readBytes(file, readLen, updateCrc); +Fw::Success FpySequencerTester::tester_readBytes(Os::File& file, FwSizeType readLen, FpySequencer_FileReadStage readStage, bool updateCrc) { + return this->cmp.readBytes(file, readLen, readStage, updateCrc); } Fw::Success FpySequencerTester::tester_readFooter() { @@ -545,6 +545,18 @@ I64 FpySequencerTester::tester_unaryRegOp_fpext(I64 src) { I64 FpySequencerTester::tester_unaryRegOp_fptrunc(I64 src) { return this->cmp.unaryRegOp_fptrunc(src); } +I64 FpySequencerTester::tester_unaryRegOp_fptosi(I64 src) { + return this->cmp.unaryRegOp_fptosi(src); +} +I64 FpySequencerTester::tester_unaryRegOp_sitofp(I64 src) { + return this->cmp.unaryRegOp_sitofp(src); +} +I64 FpySequencerTester::tester_unaryRegOp_fptoui(I64 src) { + return this->cmp.unaryRegOp_fptoui(src); +} +I64 FpySequencerTester::tester_unaryRegOp_uitofp(I64 src) { + return this->cmp.unaryRegOp_uitofp(src); +} void FpySequencerTester::tester_doDispatch() { this->cmp.doDispatch(); } diff --git a/Svc/FpySequencer/test/ut/FpySequencerTester.hpp b/Svc/FpySequencer/test/ut/FpySequencerTester.hpp index 738c8e8aa7..958378f6e9 100644 --- a/Svc/FpySequencer/test/ut/FpySequencerTester.hpp +++ b/Svc/FpySequencer/test/ut/FpySequencerTester.hpp @@ -167,6 +167,10 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test I64 tester_unaryRegOp_not(I64 src); I64 tester_unaryRegOp_fpext(I64 src); I64 tester_unaryRegOp_fptrunc(I64 src); + I64 tester_unaryRegOp_fptoui(I64 src); + I64 tester_unaryRegOp_uitofp(I64 src); + I64 tester_unaryRegOp_fptosi(I64 src); + I64 tester_unaryRegOp_sitofp(I64 src); FpySequencer::Runtime* tester_get_m_runtime_ptr(); Fw::ExternalSerializeBuffer* tester_get_m_sequenceBuffer_ptr(); void tester_set_m_sequencesStarted(U64 val); @@ -179,7 +183,7 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test Fw::Success tester_validate(); Fw::String tester_get_m_sequenceFilePath(); void tester_set_m_sequenceFilePath(Fw::String str); - Fw::Success tester_readBytes(Os::File& file, FwSizeType readLen, bool updateCrc = true); + Fw::Success tester_readBytes(Os::File& file, FwSizeType readLen, FpySequencer_FileReadStage readStage, bool updateCrc = true); Fw::Success tester_readFooter(); Fw::Success tester_readBody(); Fw::Success tester_readHeader(); diff --git a/default/config/FpySequencerCfg.fpp b/default/config/FpySequencerCfg.fpp index ddb6f709ed..32501737bb 100644 --- a/default/config/FpySequencerCfg.fpp +++ b/default/config/FpySequencerCfg.fpp @@ -11,6 +11,6 @@ module Svc { constant MAX_SERIALIZABLE_REGISTER_SIZE = 512 - 4 - 4 @ The number of registers available to a sequence - constant NUM_REGISTERS = 4 + constant NUM_REGISTERS = 128 } } \ No newline at end of file