diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index caff371f61..ab90ce62aa 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -21,11 +21,11 @@ ACTIVERATEGROUPIMPLCFG ACTIVERATEGROUPIMPLTESTER ACTIVETEXTLOGGERIMPL actools -acwrap acxz addoffset addon adminlist +adoc aeiouy afterstatinfo agg @@ -67,6 +67,7 @@ arijitdas arinc arity arpa +asciidoctor asm aspx ASTRING @@ -205,7 +206,6 @@ closedir CLOSEFILE cloudbees cls -cmak cmake cmath Cmdd @@ -241,7 +241,6 @@ config configparser configurability configurator -Connectedoutput cookiecutter cooldown coor @@ -336,7 +335,6 @@ deserialized deserializing dest DEVNULL -dfdc DFL DFPRIME DGRAM @@ -346,7 +344,6 @@ diafile dictgen dicts dictvalue -differend difflib diffs diles @@ -416,7 +413,6 @@ dylib EACCES EAGAIN eay -eb EBADF EBUSY ECLIPSEHELP @@ -495,7 +491,6 @@ exitcode expandtabs expr exprtokens -EXTN Fabcdef FADV fadvise @@ -513,7 +508,7 @@ fflush Ffs fgetc fgets -FH +fh filecmp filedown FILEDOWNLINK @@ -529,15 +524,12 @@ finalizer findall fio Firefox -Fixme -Fixme -FIXME +fixme flist FNDELAY fnmatch fno fns -followd FONTNAME FONTPATH FONTSIZE @@ -561,6 +553,7 @@ fprintf fprofile fptr fputil +fpv frontend frox frsize @@ -752,7 +745,7 @@ integertypename interoperability intlimits ints -inttype +Inttype invisi ioc ioctl @@ -847,16 +840,13 @@ len lestarch levelname lflag -lgcov lgtm lhash -libasan libc libclang libcrc libgtest libiconv -libsan LIBLOC lic lifecycle @@ -877,7 +867,6 @@ ljust lkml lld llvm -llx loadfile localhost localtime @@ -992,6 +981,7 @@ mstat mstring MTIME mtype +mul multiline multioptionals multirequired @@ -1037,6 +1027,7 @@ nmsgs noargport NOCOLOR NOCTTY +nodemon nogen nolog nomagic @@ -1048,7 +1039,6 @@ Nop noreturn normalwidths normpath -nosetests NOSIZE NOSPEC nostdlib @@ -1082,7 +1072,6 @@ OMG OMG's onchange onlinepubs -OParg OPCODEBASE opcodes opendir @@ -1128,7 +1117,6 @@ params PARENB PARODD parseable -PASSIVEC pathmaker pbuild pcmake @@ -1146,7 +1134,6 @@ phtml pid PINGSEND pinit -pipsetup pkill pkts plainnat @@ -1213,7 +1200,6 @@ ptbool ptestrun ptf pthread -PTLM ptmcg pton ptr @@ -1234,7 +1220,6 @@ Pymodule pyparsing PYPI pytest -PYTHON PYTHONPATH pyw qch @@ -1360,7 +1345,6 @@ seqgen serafin serializables serializer -serialns setaffinity setattr setbuf @@ -1371,12 +1355,9 @@ SETFL setinheritsched setitem SETLOGGING -setname setop -setopt setprotocol setquaternion -setresult setschedparam setschedpolicy setsize @@ -1387,7 +1368,6 @@ settime settingsini settype setuptools -setval setw sev sface @@ -1439,7 +1419,6 @@ spidev splitext splitlines sprintf -SQL's Sqlite sramanan srand @@ -1464,7 +1443,6 @@ startuml startword staticmethod statvfs -stdarg STDC stddef stderr @@ -1628,6 +1606,8 @@ tmptokens tmptree tname tnum +toc +toclevels toctree todo TODOLIST @@ -1743,6 +1723,7 @@ vla vlist vm VMIN +vn vsnprintf VTIME vtype diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl index 3299400680..693448ea8e 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl @@ -1,5 +1,5 @@ // ====================================================================== -// \title ${name}ComponentImpl.cpp +// \title ${name}.cpp // \author $user // \brief cpp file for ${name} component implementation class // @@ -11,7 +11,7 @@ // ====================================================================== -\#include <${include_path}/${name}ComponentImpl.hpp> +\#include <${include_path}/${name}.hpp> \#include "Fw/Types/BasicTypes.hpp" #if $namespace_list != None @@ -24,15 +24,15 @@ namespace ${namespace} { // Construction, initialization, and destruction // ---------------------------------------------------------------------- - ${name}ComponentImpl :: - ${name}ComponentImpl( + ${name} :: + ${name}( $emit_non_port_params([ $param_compName ]) ) : ${component_base}(compName) { } - void ${name}ComponentImpl :: + void ${name} :: init( $emit_non_port_params($params_init_cpp) ) @@ -46,8 +46,8 @@ $emit_non_port_params($params_init_cpp) #end if } - ${name}ComponentImpl :: - ~${name}ComponentImpl() + ${name} :: + ~${name}() { } @@ -59,7 +59,7 @@ $emit_non_port_params($params_init_cpp) #for $instance, $type, $sync, $priority, $full, $role, $max_num in $typed_user_input_ports: #set $return_type = $port_return_type_strs[$instance] - ${return_type}${name}ComponentImpl :: + ${return_type}${name} :: ${instance}_handler( $emit_port_params([ $param_portNum ] + $port_params[instance]) ) @@ -79,7 +79,7 @@ $emit_port_params([ $param_portNum ] + $port_params[instance]) // ---------------------------------------------------------------------- #for $instance, $sync, $priority, $full, $max_num in $serial_input_ports: - void ${name}ComponentImpl :: + void ${name} :: ${instance}_handler( NATIVE_INT_TYPE portNum, $doxygen_post_comment("The port number") Fw::SerializeBufferBase &Buffer $doxygen_post_comment("The serialization buffer") @@ -97,7 +97,7 @@ $emit_port_params([ $param_portNum ] + $port_params[instance]) #for $mnemonic, $opcode, $sync, $priority, $full, $comment in $commands: #set $params = $command_params[$mnemonic] - void ${name}ComponentImpl :: + void ${name} :: ${mnemonic}_cmdHandler( $emit_non_port_params([ $param_opCode, $param_cmdSeq ] + $params) ) diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl index 932255a187..b9455b2a27 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl @@ -1,5 +1,5 @@ // ====================================================================== -// \title ${name}ComponentImpl.hpp +// \title ${name}.hpp // \author $user // \brief hpp file for ${name} component implementation class // @@ -21,7 +21,7 @@ namespace ${namespace} { #end for #end if - class ${name}ComponentImpl : + class ${name} : public $component_base { @@ -33,7 +33,7 @@ namespace ${namespace} { //! Construct object $name //! - ${name}ComponentImpl( + ${name}( $emit_non_port_params([ $param_compName ]) ); @@ -45,7 +45,7 @@ $emit_non_port_params($params_init_hpp) //! Destroy object $name //! - ~${name}ComponentImpl(); + ~${name}(); #if len($typed_user_input_ports) > 0: PRIVATE: diff --git a/Ref/Top/CMakeLists.txt b/Ref/Top/CMakeLists.txt index f4ba9f8fab..a88d1f7032 100644 --- a/Ref/Top/CMakeLists.txt +++ b/Ref/Top/CMakeLists.txt @@ -8,8 +8,6 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/instances.fpp" "${CMAKE_CURRENT_LIST_DIR}/topology.fpp" -# "${CMAKE_CURRENT_LIST_DIR}/RefTopologyAc.cpp" -# "${CMAKE_CURRENT_LIST_DIR}/RefTopologyAppAi.xml" "${CMAKE_CURRENT_LIST_DIR}/RefTopologyDefs.cpp" ) set(MOD_DEPS diff --git a/Ref/Top/FppConstantsAc.hpp b/Ref/Top/FppConstantsAc.hpp index e26a94e87a..8d665860da 100644 --- a/Ref/Top/FppConstantsAc.hpp +++ b/Ref/Top/FppConstantsAc.hpp @@ -9,8 +9,8 @@ // All rights reserved. // ====================================================================== -#ifndef RefTop_FppConstantsAc_HPP -#define RefTop_FppConstantsAc_HPP +#ifndef Ref_Top_FppConstantsAc_HPP +#define Ref_Top_FppConstantsAc_HPP #include "Fw/Types/BasicTypes.hpp" @@ -23,7 +23,7 @@ namespace Ref { }; enum FppConstant_stackSize { - stackSize = 10240 + stackSize = 16384 }; } diff --git a/Ref/Top/Main.cpp b/Ref/Top/Main.cpp index 943f265d88..4987b9b6ca 100644 --- a/Ref/Top/Main.cpp +++ b/Ref/Top/Main.cpp @@ -2,6 +2,7 @@ #include #include +#include #include void print_usage(const char* app) { @@ -12,6 +13,8 @@ void print_usage(const char* app) { #include Ref::TopologyState state; +// Enable the console logging provided by Os::Log +Os::Log logger; volatile sig_atomic_t terminate = 0; diff --git a/Ref/Top/RefTopologyAc.cpp b/Ref/Top/RefTopologyAc.cpp index f5ca64ae51..6fb61bea3d 100644 --- a/Ref/Top/RefTopologyAc.cpp +++ b/Ref/Top/RefTopologyAc.cpp @@ -1211,7 +1211,7 @@ namespace Ref { StackSizes::cmdSeq ); // Initialize socket server if and only if there is a valid specification - if (state.hostName != NULL && state.portNumber != 0) { + if (state.hostName != nullptr && state.portNumber != 0) { Os::TaskString name("ReceiveTask"); // Uplink is configured for receive so a socket task is started comm.configure(state.hostName, state.portNumber); @@ -1287,21 +1287,21 @@ namespace Ref { // Free threads void freeThreads(const TopologyState& state) { - (void) blockDrv.ActiveComponentBase::join(NULL); - (void) chanTlm.ActiveComponentBase::join(NULL); - (void) cmdDisp.ActiveComponentBase::join(NULL); - (void) cmdSeq.ActiveComponentBase::join(NULL); + (void) blockDrv.ActiveComponentBase::join(nullptr); + (void) chanTlm.ActiveComponentBase::join(nullptr); + (void) cmdDisp.ActiveComponentBase::join(nullptr); + (void) cmdSeq.ActiveComponentBase::join(nullptr); comm.stopSocketTask(); - (void) comm.joinSocketTask(NULL); - (void) eventLogger.ActiveComponentBase::join(NULL); - (void) fileDownlink.ActiveComponentBase::join(NULL); - (void) fileManager.ActiveComponentBase::join(NULL); - (void) fileUplink.ActiveComponentBase::join(NULL); - (void) pingRcvr.ActiveComponentBase::join(NULL); - (void) prmDb.ActiveComponentBase::join(NULL); - (void) rateGroup1Comp.ActiveComponentBase::join(NULL); - (void) rateGroup2Comp.ActiveComponentBase::join(NULL); - (void) rateGroup3Comp.ActiveComponentBase::join(NULL); + (void) comm.joinSocketTask(nullptr); + (void) eventLogger.ActiveComponentBase::join(nullptr); + (void) fileDownlink.ActiveComponentBase::join(nullptr); + (void) fileManager.ActiveComponentBase::join(nullptr); + (void) fileUplink.ActiveComponentBase::join(nullptr); + (void) pingRcvr.ActiveComponentBase::join(nullptr); + (void) prmDb.ActiveComponentBase::join(nullptr); + (void) rateGroup1Comp.ActiveComponentBase::join(nullptr); + (void) rateGroup2Comp.ActiveComponentBase::join(nullptr); + (void) rateGroup3Comp.ActiveComponentBase::join(nullptr); } // Tear down components diff --git a/Ref/Top/RefTopologyAc.hpp b/Ref/Top/RefTopologyAc.hpp index 2024d069e9..5617dff5a2 100644 --- a/Ref/Top/RefTopologyAc.hpp +++ b/Ref/Top/RefTopologyAc.hpp @@ -196,19 +196,19 @@ namespace Ref { namespace StackSizes { enum { - blockDrv = 10240, - chanTlm = 10240, - cmdDisp = 10240, - cmdSeq = 10240, - eventLogger = 10240, - fileDownlink = 10240, - fileManager = 10240, - fileUplink = 10240, - pingRcvr = 10240, - prmDb = 10240, - rateGroup1Comp = 10240, - rateGroup2Comp = 10240, - rateGroup3Comp = 10240, + blockDrv = 16384, + chanTlm = 16384, + cmdDisp = 16384, + cmdSeq = 16384, + eventLogger = 16384, + fileDownlink = 16384, + fileManager = 16384, + fileUplink = 16384, + pingRcvr = 16384, + prmDb = 16384, + rateGroup1Comp = 16384, + rateGroup2Comp = 16384, + rateGroup3Comp = 16384, }; } diff --git a/Ref/Top/cpp.do b/Ref/Top/cpp.do index de6a5598bf..407a7f523f 100644 --- a/Ref/Top/cpp.do +++ b/Ref/Top/cpp.do @@ -2,5 +2,4 @@ . ./defs.sh -export FPP_TO_CPP_OPTS='-g RefTop' cpp_do "$@" diff --git a/cmake/fpp-download/fpp.cmake b/cmake/fpp-download/fpp.cmake index 2a2e5b0cf8..ea267fdc2d 100644 --- a/cmake/fpp-download/fpp.cmake +++ b/cmake/fpp-download/fpp.cmake @@ -4,7 +4,7 @@ # A setup to install fpp tool suite automatically as part of the CMake run. If the user wants to avoid this, the user # should install FPP on the system path and that will be used. #### -set(FPP_VERSION 7d1a68c64b4451b69a86503e93c6ea55c5b30d12) +set(FPP_VERSION 8c70c2bf5c44ad9b894e7c710efc465c01da6209) set(FPP_TOOLS_PATH "${CMAKE_BINARY_DIR}/fpp-tools-install" CACHE PATH "Installation path for fpp tools") #### diff --git a/docs/Tutorials/MathComponent/CMakeLists.txt b/docs/Tutorials/MathComponent/CMakeLists.txt new file mode 100644 index 0000000000..b9d97bec5b --- /dev/null +++ b/docs/Tutorials/MathComponent/CMakeLists.txt @@ -0,0 +1,57 @@ +#### +# 'Ref' Deployment: +# +# This sets up the build for the 'Ref' Application, including the custom reference +# components. In addition, it imports FPrime.cmake, which includes the core F Prime +# components. +# +# This file has several sections. +# +# 1. Header Section: define basic properties of the build +# 2. F prime core: includes all F prime core components, and build-system properties +# 3. Local subdirectories: contains all deployment specific directory additions +#### + +## +# Section 1: Basic Project Setup +# +# This contains the basic project information. Specifically, a cmake version and +# project definition. +## +cmake_minimum_required(VERSION 3.13) +cmake_policy(SET CMP0048 NEW) +project(Ref VERSION 1.0.0 LANGUAGES C CXX) + +## +# Section 2: F prime Core +# +# This includes all of the F prime core components, and imports the make-system. F prime core +# components will be placed in the F-Prime binary subdirectory to keep them from +# colliding with deployment specific items. +## +include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime.cmake") +# NOTE: register custom targets between these two lines +include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime-Code.cmake") +## +# Section 3: Components and Topology +# +# This section includes deployment specific directories. This allows use of non- +# core components in the topology, which is also added here. +## +# Add component subdirectories +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathPorts/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathReceiver/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathSender/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathTypes/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PingReceiver/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RecvBuffApp/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SendBuffApp/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SignalGen/") + +# Add Topology subdirectory +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Top/") + +set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Top/Main.cpp") +set(MOD_DEPS ${PROJECT_NAME}/Top) + +register_fprime_deployment() diff --git a/docs/Tutorials/MathComponent/MathPorts/CMakeLists.txt b/docs/Tutorials/MathComponent/MathPorts/CMakeLists.txt index c8910e8182..36f86a667d 100644 --- a/docs/Tutorials/MathComponent/MathPorts/CMakeLists.txt +++ b/docs/Tutorials/MathComponent/MathPorts/CMakeLists.txt @@ -1,14 +1,5 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding files -# MOD_DEPS: (optional) module dependencies -# -# Note: using PROJECT_NAME as EXECUTABLE_NAME -#### set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathOpPortAi.xml" - "${CMAKE_CURRENT_LIST_DIR}/MathResultPortAi.xml" + "${CMAKE_CURRENT_LIST_DIR}/MathPorts.fpp" ) register_fprime_module() diff --git a/docs/Tutorials/MathComponent/MathPorts/MathOpPortAi.xml b/docs/Tutorials/MathComponent/MathPorts/MathOpPortAi.xml deleted file mode 100644 index 0943fc8295..0000000000 --- a/docs/Tutorials/MathComponent/MathPorts/MathOpPortAi.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - Port to perform an operation on two numbers - - - - - - - - - - - - - - operation argument - - - - diff --git a/docs/Tutorials/MathComponent/MathPorts/MathPorts.fpp b/docs/Tutorials/MathComponent/MathPorts/MathPorts.fpp new file mode 100644 index 0000000000..0197e7b651 --- /dev/null +++ b/docs/Tutorials/MathComponent/MathPorts/MathPorts.fpp @@ -0,0 +1,15 @@ +module Ref { + + @ Port for requesting an operation on two numbers + port MathOp( + val1: F32 @< The first operand + op: MathOp @< The operation + val2: F32 @< The second operand + ) + + @ Port for returning the result of a math operation + port MathResult( + result: F32 @< the result of the operation + ) + +} diff --git a/docs/Tutorials/MathComponent/MathPorts/MathResultPortAi.xml b/docs/Tutorials/MathComponent/MathPorts/MathResultPortAi.xml deleted file mode 100644 index cdf8af370b..0000000000 --- a/docs/Tutorials/MathComponent/MathPorts/MathResultPortAi.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Port to return the result of a math operation - - - - the result of the operation - - - - diff --git a/docs/Tutorials/MathComponent/MathReceiver/CMakeLists.txt b/docs/Tutorials/MathComponent/MathReceiver/CMakeLists.txt index 9db6546cd2..c1126f9b71 100644 --- a/docs/Tutorials/MathComponent/MathReceiver/CMakeLists.txt +++ b/docs/Tutorials/MathComponent/MathReceiver/CMakeLists.txt @@ -1,13 +1,15 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding files -# MOD_DEPS: (optional) module dependencies -# -#### +# Register the standard build set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathReceiverComponentAi.xml" - "${CMAKE_CURRENT_LIST_DIR}/MathReceiverComponentImpl.cpp" + "${CMAKE_CURRENT_LIST_DIR}/MathReceiver.cpp" + "${CMAKE_CURRENT_LIST_DIR}/MathReceiver.fpp" ) - register_fprime_module() + +# Register the unit test build +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathReceiver.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp" +) +set(UT_MOD_DEPS STest) +register_fprime_ut() diff --git a/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.cpp b/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.cpp new file mode 100644 index 0000000000..3e312eb09e --- /dev/null +++ b/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.cpp @@ -0,0 +1,151 @@ +// ====================================================================== +// \title MathReceiver.cpp +// \author tcanham, bocchino +// \brief cpp file for MathReceiver component implementation class +// +// \copyright +// Copyright 2009-2021, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "Fw/Types/Assert.hpp" +#include "Fw/Types/BasicTypes.hpp" +#include "Ref/MathReceiver/MathReceiver.hpp" + +namespace Ref { + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + MathReceiver :: + MathReceiver( + const char *const compName + ) : + MathReceiverComponentBase(compName) + { + + } + + void MathReceiver :: + init( + const NATIVE_INT_TYPE queueDepth, + const NATIVE_INT_TYPE instance + ) + { + MathReceiverComponentBase::init(queueDepth, instance); + } + + MathReceiver :: + ~MathReceiver() + { + + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + void MathReceiver :: + mathOpIn_handler( + const NATIVE_INT_TYPE portNum, + F32 val1, + const MathOp& op, + F32 val2 + ) + { + + // Get the initial result + F32 res = 0.0; + switch (op.e) { + case MathOp::ADD: + res = val1 + val2; + break; + case MathOp::SUB: + res = val1 - val2; + break; + case MathOp::MUL: + res = val1 * val2; + break; + case MathOp::DIV: + res = val1 / val2; + break; + default: + FW_ASSERT(0, op.e); + break; + } + + // Get the factor value + Fw::ParamValid valid; + F32 factor = paramGet_FACTOR(valid); + FW_ASSERT( + valid.e == Fw::ParamValid::VALID || valid.e == Fw::ParamValid::DEFAULT, + valid.e + ); + + // Multiply result by factor + res *= factor; + + // Emit telemetry and events + this->log_ACTIVITY_HI_OPERATION_PERFORMED(op); + this->tlmWrite_OPERATION(op); + + // Emit result + this->mathResultOut_out(0, res); + + } + + void MathReceiver :: + schedIn_handler( + const NATIVE_INT_TYPE portNum, + NATIVE_UINT_TYPE context + ) + { + U32 numMsgs = this->m_queue.getNumMsgs(); + for (U32 i = 0; i < numMsgs; ++i) { + (void) this->doDispatch(); + } + + } + + // ---------------------------------------------------------------------- + // Command handler implementations + // ---------------------------------------------------------------------- + + void MathReceiver :: + CLEAR_EVENT_THROTTLE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) + { + // clear throttle + this->log_ACTIVITY_HI_FACTOR_UPDATED_ThrottleClear(); + // send event that throttle is cleared + this->log_ACTIVITY_HI_THROTTLE_CLEARED(); + // reply with completion status + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + } + + void MathReceiver :: + parameterUpdated(FwPrmIdType id) + { + switch (id) { + case PARAMID_FACTOR: { + Fw::ParamValid valid; + F32 val = this->paramGet_FACTOR(valid); + FW_ASSERT( + valid.e == Fw::ParamValid::VALID || valid.e == Fw::ParamValid::DEFAULT, + valid.e + ); + this->log_ACTIVITY_HI_FACTOR_UPDATED(val); + break; + } + default: + FW_ASSERT(0, id); + break; + } + } + +} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.fpp b/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.fpp new file mode 100644 index 0000000000..599aae607f --- /dev/null +++ b/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.fpp @@ -0,0 +1,106 @@ +module Ref { + + @ Component for receiving and performing a math operation + queued component MathReceiver { + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Port for receiving the math operation + async input port mathOpIn: MathOp + + @ Port for returning the math result + output port mathResultOut: MathResult + + @ The rate group scheduler input + sync input port schedIn: Svc.Sched + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + + @ Command receive + command recv port cmdIn + + @ Command registration + command reg port cmdRegOut + + @ Command response + command resp port cmdResponseOut + + @ Event + event port eventOut + + @ Parameter get + param get port prmGetOut + + @ Parameter set + param set port prmSetOut + + @ Telemetry + telemetry port tlmOut + + @ Text event + text event port textEventOut + + @ Time get + time get port timeGetOut + + # ---------------------------------------------------------------------- + # Parameters + # ---------------------------------------------------------------------- + + @ The multiplier in the math operation + param FACTOR: F32 default 1.0 id 0 \ + set opcode 10 \ + save opcode 11 + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + @ Factor updated + event FACTOR_UPDATED( + val: F32 @< The factor value + ) \ + severity activity high \ + id 0 \ + format "Factor updated to {f}" \ + throttle 3 + + @ Math operation performed + event OPERATION_PERFORMED( + val: MathOp @< The operation + ) \ + severity activity high \ + id 1 \ + format "{} operation performed" + + @ Event throttle cleared + event THROTTLE_CLEARED \ + severity activity high \ + id 2 \ + format "Event throttle cleared" + + # ---------------------------------------------------------------------- + # Commands + # ---------------------------------------------------------------------- + + @ Clear the event throttle + async command CLEAR_EVENT_THROTTLE \ + opcode 1 + + # ---------------------------------------------------------------------- + # Telemetry + # ---------------------------------------------------------------------- + + @ The operation + telemetry OPERATION: MathOp id 0 + + @ Multiplication factor + telemetry FACTOR: F32 id 1 + + } + +} diff --git a/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentImpl.hpp b/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.hpp similarity index 52% rename from docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentImpl.hpp rename to docs/Tutorials/MathComponent/MathReceiver/MathReceiver.hpp index e9fd6a0ef5..c085650274 100644 --- a/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentImpl.hpp +++ b/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.hpp @@ -1,10 +1,10 @@ // ====================================================================== // \title MathReceiverImpl.hpp -// \author tcanham +// \author tcanham, bocchino // \brief hpp file for MathReceiver component implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2021, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // @@ -17,7 +17,7 @@ namespace Ref { - class MathReceiverComponentImpl : + class MathReceiver : public MathReceiverComponentBase { @@ -29,20 +29,20 @@ namespace Ref { //! Construct object MathReceiver //! - MathReceiverComponentImpl( - const char *const compName /*!< The component name*/ + MathReceiver( + const char *const compName //!< The component name ); //! Initialize object MathReceiver //! void init( - const NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + const NATIVE_INT_TYPE queueDepth, //!< The queue depth + const NATIVE_INT_TYPE instance = 0 //!< The instance number ); //! Destroy object MathReceiver //! - ~MathReceiverComponentImpl(); + ~MathReceiver(); PRIVATE: @@ -50,20 +50,20 @@ namespace Ref { // Handler implementations for user-defined typed input ports // ---------------------------------------------------------------------- - //! Handler implementation for mathIn + //! Handler implementation for mathOpIn //! - void mathIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ + void mathOpIn_handler( + const NATIVE_INT_TYPE portNum, //!< The port number F32 val1, - F32 val2, - MathOperation operation /*!< operation argument*/ + const MathOp& op, //!< operation argument + F32 val2 ); //! Handler implementation for SchedIn //! - void SchedIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - NATIVE_UINT_TYPE context /*!< The call order*/ + void schedIn_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + NATIVE_UINT_TYPE context //!< The call order ); PRIVATE: @@ -72,28 +72,15 @@ namespace Ref { // Command handler implementations // ---------------------------------------------------------------------- - //! Implementation for MR_SET_FACTOR1 command handler - //! Set operation multiplication factor1 - void MR_SET_FACTOR1_cmdHandler( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - F32 val /*!< The first factor*/ - ); - - //! Implementation for MR_CLEAR_EVENT_THROTTLE command handler + //! Implementation for CLEAR_EVENT_THROTTLE command handler //! Clear the event throttle - void MR_CLEAR_EVENT_THROTTLE_cmdHandler( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq /*!< The command sequence number*/ + void CLEAR_EVENT_THROTTLE_cmdHandler( + const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq //!< The command sequence number ); - // stored factor1 - F32 m_factor1; - // number of times factor1 has been written - U32 m_factor1s; - void parameterUpdated( - FwPrmIdType id /*!< The parameter ID*/ + FwPrmIdType id //!< The parameter ID ); }; diff --git a/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentAi.xml b/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentAi.xml deleted file mode 100644 index a76cd8836c..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentAi.xml +++ /dev/null @@ -1,107 +0,0 @@ - - Ref/MathPorts/MathOpPortAi.xml - Ref/MathPorts/MathResultPortAi.xml - Svc/Sched/SchedPortAi.xml - Ref/MathTypes/MathOpSerializableAi.xml - Component sending a math operation - - - - Port for receiving the math operation - - - - - Port for returning the math result - - - - - The rate group scheduler input - - - - - - - Set operation multiplication factor1 - - - - The first factor - - - - - Clear the event throttle - - - - - - - The operation - - - - - The number of MR_SET_FACTOR1 commands - - - - - Factor 1 value - - - - - Factor 2 value - - - - - - - Operation factor 1 - - - - The factor value - - - - - - Updated factor 2 - - - - The factor value - - - - - - Math operation performed - - - - The operation - - - - - - Event throttle cleared - - - - - - - A test parameter - - - - - diff --git a/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentImpl.cpp b/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentImpl.cpp deleted file mode 100644 index cf1435cb29..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/MathReceiverComponentImpl.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// ====================================================================== -// \title MathReceiverImpl.cpp -// \author tcanham -// \brief cpp file for MathReceiver component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - - -#include -#include "Fw/Types/BasicTypes.hpp" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - MathReceiverComponentImpl :: - MathReceiverComponentImpl( - const char *const compName - ) : MathReceiverComponentBase(compName), - m_factor1(0.0), - m_factor1s(0) - { - - } - - void MathReceiverComponentImpl :: - init( - const NATIVE_INT_TYPE queueDepth, - const NATIVE_INT_TYPE instance - ) - { - MathReceiverComponentBase::init(queueDepth, instance); - } - - MathReceiverComponentImpl :: - ~MathReceiverComponentImpl() - { - - } - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - void MathReceiverComponentImpl :: - mathIn_handler( - const NATIVE_INT_TYPE portNum, - F32 val1, - F32 val2, - MathOperation operation - ) - { - // declare result serializable - Ref::MathOp op; - F32 res = 0.0; - switch (operation) { - case MATH_ADD: - op.setop(ADD); - res = (val1 + val2)*this->m_factor1; - break; - case MATH_SUB: - op.setop(SUB); - res = (val1 - val2)*this->m_factor1; - break; - case MATH_MULTIPLY: - op.setop(MULT); - res = (val1 * val2)*this->m_factor1; - break; - case MATH_DIVIDE: - op.setop(DIVIDE); - res = (val1 / val2)*this->m_factor1; - break; - default: - FW_ASSERT(0,operation); - break; - } - Fw::ParamValid valid; - res = res/this->paramGet_factor2(valid); - - op.setval1(val1); - op.setval2(val2); - op.setresult(res); - this->log_ACTIVITY_HI_MR_OPERATION_PERFORMED(op); - this->tlmWrite_MR_OPERATION(op); - this->mathOut_out(0,res); - } - - void MathReceiverComponentImpl :: - SchedIn_handler( - const NATIVE_INT_TYPE portNum, - NATIVE_UINT_TYPE context - ) - { - QueuedComponentBase::MsgDispatchStatus stat = QueuedComponentBase::MSG_DISPATCH_OK; - // empty message queue - while (stat != MSG_DISPATCH_EMPTY) { - stat = this->doDispatch(); - } - - } - - // ---------------------------------------------------------------------- - // Command handler implementations - // ---------------------------------------------------------------------- - - void MathReceiverComponentImpl :: - MR_SET_FACTOR1_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - F32 val - ) - { - this->m_factor1 = val; - this->log_ACTIVITY_HI_MR_SET_FACTOR1(val); - this->tlmWrite_MR_FACTOR1(val); - this->tlmWrite_MR_FACTOR1S(++this->m_factor1s); - // reply with completion status - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void MathReceiverComponentImpl :: - MR_CLEAR_EVENT_THROTTLE_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq - ) - { - // clear throttle - this->log_ACTIVITY_HI_MR_SET_FACTOR1_ThrottleClear(); - // send event that throttle is cleared - this->log_ACTIVITY_HI_MR_THROTTLE_CLEARED(); - // reply with completion status - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void MathReceiverComponentImpl :: - parameterUpdated( - FwPrmIdType id /*!< The parameter ID*/ - ) { - if (id == PARAMID_FACTOR2) { - Fw::ParamValid valid; - F32 val = this->paramGet_factor2(valid); - this->log_ACTIVITY_HI_MR_UPDATED_FACTOR2(val); - } - } - - -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/GTestBase.cpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/GTestBase.cpp deleted file mode 100644 index a178c95b01..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/GTestBase.cpp +++ /dev/null @@ -1,562 +0,0 @@ -// ====================================================================== -// \title MathReceiver/test/ut/GTestBase.cpp -// \author Auto-generated -// \brief cpp file for MathReceiver component Google Test harness base class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include "GTestBase.hpp" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - MathReceiverGTestBase :: - MathReceiverGTestBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, - const U32 maxHistorySize -#else - const U32 maxHistorySize -#endif - ) : - MathReceiverTesterBase ( -#if FW_OBJECT_NAMES == 1 - compName, -#endif - maxHistorySize - ) - { - - } - - MathReceiverGTestBase :: - ~MathReceiverGTestBase(void) - { - - } - - // ---------------------------------------------------------------------- - // Commands - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertCmdResponse_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ((unsigned long) size, this->cmdResponseHistory->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of command response history\n" - << " Expected: " << size << "\n" - << " Actual: " << this->cmdResponseHistory->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertCmdResponse( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const FwOpcodeType opCode, - const U32 cmdSeq, - const Fw::CommandResponse response - ) - const - { - ASSERT_LT(index, this->cmdResponseHistory->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into command response history\n" - << " Expected: Less than size of command response history (" - << this->cmdResponseHistory->size() << ")\n" - << " Actual: " << index << "\n"; - const CmdResponse& e = this->cmdResponseHistory->at(index); - ASSERT_EQ(opCode, e.opCode) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Opcode at index " - << index - << " in command response history\n" - << " Expected: " << opCode << "\n" - << " Actual: " << e.opCode << "\n"; - ASSERT_EQ(cmdSeq, e.cmdSeq) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Command sequence number at index " - << index - << " in command response history\n" - << " Expected: " << cmdSeq << "\n" - << " Actual: " << e.cmdSeq << "\n"; - ASSERT_EQ(response, e.response) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Command response at index " - << index - << " in command response history\n" - << " Expected: " << response << "\n" - << " Actual: " << e.response << "\n"; - } - - // ---------------------------------------------------------------------- - // Telemetry - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertTlm_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->tlmSize) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Total size of all telemetry histories\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmSize << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MR_OPERATION - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertTlm_MR_OPERATION_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MR_OPERATION->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MR_OPERATION\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MR_OPERATION->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertTlm_MR_OPERATION( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const Ref::MathOp& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MR_OPERATION->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MR_OPERATION\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MR_OPERATION->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MR_OPERATION& e = - this->tlmHistory_MR_OPERATION->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MR_OPERATION\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1S - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertTlm_MR_FACTOR1S_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MR_FACTOR1S->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MR_FACTOR1S\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MR_FACTOR1S->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertTlm_MR_FACTOR1S( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const U32& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MR_FACTOR1S->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MR_FACTOR1S\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MR_FACTOR1S->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MR_FACTOR1S& e = - this->tlmHistory_MR_FACTOR1S->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MR_FACTOR1S\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1 - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertTlm_MR_FACTOR1_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MR_FACTOR1->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MR_FACTOR1\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MR_FACTOR1->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertTlm_MR_FACTOR1( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MR_FACTOR1->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MR_FACTOR1\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MR_FACTOR1->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MR_FACTOR1& e = - this->tlmHistory_MR_FACTOR1->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MR_FACTOR1\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR2 - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertTlm_MR_FACTOR2_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MR_FACTOR2->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MR_FACTOR2\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MR_FACTOR2->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertTlm_MR_FACTOR2( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MR_FACTOR2->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MR_FACTOR2\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MR_FACTOR2->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MR_FACTOR2& e = - this->tlmHistory_MR_FACTOR2->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MR_FACTOR2\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Events - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertEvents_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventsSize) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Total size of all event histories\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventsSize << "\n"; - } - - // ---------------------------------------------------------------------- - // Event: MR_SET_FACTOR1 - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertEvents_MR_SET_FACTOR1_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventHistory_MR_SET_FACTOR1->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for event MR_SET_FACTOR1\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventHistory_MR_SET_FACTOR1->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertEvents_MR_SET_FACTOR1( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32 val - ) const - { - ASSERT_GT(this->eventHistory_MR_SET_FACTOR1->size(), index) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of event MR_SET_FACTOR1\n" - << " Expected: Less than size of history (" - << this->eventHistory_MR_SET_FACTOR1->size() << ")\n" - << " Actual: " << index << "\n"; - const EventEntry_MR_SET_FACTOR1& e = - this->eventHistory_MR_SET_FACTOR1->at(index); - ASSERT_EQ(val, e.val) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value of argument val at index " - << index - << " in history of event MR_SET_FACTOR1\n" - << " Expected: " << val << "\n" - << " Actual: " << e.val << "\n"; - } - - // ---------------------------------------------------------------------- - // Event: MR_UPDATED_FACTOR2 - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertEvents_MR_UPDATED_FACTOR2_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventHistory_MR_UPDATED_FACTOR2->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for event MR_UPDATED_FACTOR2\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventHistory_MR_UPDATED_FACTOR2->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertEvents_MR_UPDATED_FACTOR2( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32 val - ) const - { - ASSERT_GT(this->eventHistory_MR_UPDATED_FACTOR2->size(), index) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of event MR_UPDATED_FACTOR2\n" - << " Expected: Less than size of history (" - << this->eventHistory_MR_UPDATED_FACTOR2->size() << ")\n" - << " Actual: " << index << "\n"; - const EventEntry_MR_UPDATED_FACTOR2& e = - this->eventHistory_MR_UPDATED_FACTOR2->at(index); - ASSERT_EQ(val, e.val) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value of argument val at index " - << index - << " in history of event MR_UPDATED_FACTOR2\n" - << " Expected: " << val << "\n" - << " Actual: " << e.val << "\n"; - } - - // ---------------------------------------------------------------------- - // Event: MR_OPERATION_PERFORMED - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertEvents_MR_OPERATION_PERFORMED_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventHistory_MR_OPERATION_PERFORMED->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for event MR_OPERATION_PERFORMED\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventHistory_MR_OPERATION_PERFORMED->size() << "\n"; - } - - void MathReceiverGTestBase :: - assertEvents_MR_OPERATION_PERFORMED( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const Ref::MathOp val - ) const - { - ASSERT_GT(this->eventHistory_MR_OPERATION_PERFORMED->size(), index) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of event MR_OPERATION_PERFORMED\n" - << " Expected: Less than size of history (" - << this->eventHistory_MR_OPERATION_PERFORMED->size() << ")\n" - << " Actual: " << index << "\n"; - const EventEntry_MR_OPERATION_PERFORMED& e = - this->eventHistory_MR_OPERATION_PERFORMED->at(index); - ASSERT_EQ(val, e.val) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value of argument val at index " - << index - << " in history of event MR_OPERATION_PERFORMED\n" - << " Expected: " << val << "\n" - << " Actual: " << e.val << "\n"; - } - - // ---------------------------------------------------------------------- - // Event: MR_THROTTLE_CLEARED - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertEvents_MR_THROTTLE_CLEARED_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventsSize_MR_THROTTLE_CLEARED) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for event MR_THROTTLE_CLEARED\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventsSize_MR_THROTTLE_CLEARED << "\n"; - } - - // ---------------------------------------------------------------------- - // From ports - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assertFromPortHistory_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->fromPortHistorySize) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Total size of all from port histories\n" - << " Expected: " << size << "\n" - << " Actual: " << this->fromPortHistorySize << "\n"; - } - - // ---------------------------------------------------------------------- - // From port: mathOut - // ---------------------------------------------------------------------- - - void MathReceiverGTestBase :: - assert_from_mathOut_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->fromPortHistory_mathOut->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for from_mathOut\n" - << " Expected: " << size << "\n" - << " Actual: " << this->fromPortHistory_mathOut->size() << "\n"; - } - -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/GTestBase.hpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/GTestBase.hpp deleted file mode 100644 index 0d764041b6..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/GTestBase.hpp +++ /dev/null @@ -1,383 +0,0 @@ -// ====================================================================== -// \title MathReceiver/test/ut/GTestBase.hpp -// \author Auto-generated -// \brief hpp file for MathReceiver component Google Test harness base class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef MathReceiver_GTEST_BASE_HPP -#define MathReceiver_GTEST_BASE_HPP - -#include "TesterBase.hpp" -#include "gtest/gtest.h" - -// ---------------------------------------------------------------------- -// Macros for command history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_CMD_RESPONSE_SIZE(size) \ - this->assertCmdResponse_size(__FILE__, __LINE__, size) - -#define ASSERT_CMD_RESPONSE(index, opCode, cmdSeq, response) \ - this->assertCmdResponse(__FILE__, __LINE__, index, opCode, cmdSeq, response) - -// ---------------------------------------------------------------------- -// Macros for telemetry history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_TLM_SIZE(size) \ - this->assertTlm_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MR_OPERATION_SIZE(size) \ - this->assertTlm_MR_OPERATION_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MR_OPERATION(index, value) \ - this->assertTlm_MR_OPERATION(__FILE__, __LINE__, index, value) - -#define ASSERT_TLM_MR_FACTOR1S_SIZE(size) \ - this->assertTlm_MR_FACTOR1S_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MR_FACTOR1S(index, value) \ - this->assertTlm_MR_FACTOR1S(__FILE__, __LINE__, index, value) - -#define ASSERT_TLM_MR_FACTOR1_SIZE(size) \ - this->assertTlm_MR_FACTOR1_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MR_FACTOR1(index, value) \ - this->assertTlm_MR_FACTOR1(__FILE__, __LINE__, index, value) - -#define ASSERT_TLM_MR_FACTOR2_SIZE(size) \ - this->assertTlm_MR_FACTOR2_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MR_FACTOR2(index, value) \ - this->assertTlm_MR_FACTOR2(__FILE__, __LINE__, index, value) - -// ---------------------------------------------------------------------- -// Macros for event history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_EVENTS_SIZE(size) \ - this->assertEvents_size(__FILE__, __LINE__, size) - -#define ASSERT_EVENTS_MR_SET_FACTOR1_SIZE(size) \ - this->assertEvents_MR_SET_FACTOR1_size(__FILE__, __LINE__, size) - -#define ASSERT_EVENTS_MR_SET_FACTOR1(index, _val) \ - this->assertEvents_MR_SET_FACTOR1(__FILE__, __LINE__, index, _val) - -#define ASSERT_EVENTS_MR_UPDATED_FACTOR2_SIZE(size) \ - this->assertEvents_MR_UPDATED_FACTOR2_size(__FILE__, __LINE__, size) - -#define ASSERT_EVENTS_MR_UPDATED_FACTOR2(index, _val) \ - this->assertEvents_MR_UPDATED_FACTOR2(__FILE__, __LINE__, index, _val) - -#define ASSERT_EVENTS_MR_OPERATION_PERFORMED_SIZE(size) \ - this->assertEvents_MR_OPERATION_PERFORMED_size(__FILE__, __LINE__, size) - -#define ASSERT_EVENTS_MR_OPERATION_PERFORMED(index, _val) \ - this->assertEvents_MR_OPERATION_PERFORMED(__FILE__, __LINE__, index, _val) - -#define ASSERT_EVENTS_MR_THROTTLE_CLEARED_SIZE(size) \ - this->assertEvents_MR_THROTTLE_CLEARED_size(__FILE__, __LINE__, size) - -// ---------------------------------------------------------------------- -// Macros for typed user from port history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_FROM_PORT_HISTORY_SIZE(size) \ - this->assertFromPortHistory_size(__FILE__, __LINE__, size) - -#define ASSERT_from_mathOut_SIZE(size) \ - this->assert_from_mathOut_size(__FILE__, __LINE__, size) - -#define ASSERT_from_mathOut(index, _result) \ - { \ - ASSERT_GT(this->fromPortHistory_mathOut->size(), static_cast(index)) \ - << "\n" \ - << " File: " << __FILE__ << "\n" \ - << " Line: " << __LINE__ << "\n" \ - << " Value: Index into history of from_mathOut\n" \ - << " Expected: Less than size of history (" \ - << this->fromPortHistory_mathOut->size() << ")\n" \ - << " Actual: " << index << "\n"; \ - const FromPortEntry_mathOut& _e = \ - this->fromPortHistory_mathOut->at(index); \ - ASSERT_EQ(_result, _e.result) \ - << "\n" \ - << " File: " << __FILE__ << "\n" \ - << " Line: " << __LINE__ << "\n" \ - << " Value: Value of argument result at index " \ - << index \ - << " in history of from_mathOut\n" \ - << " Expected: " << _result << "\n" \ - << " Actual: " << _e.result << "\n"; \ - } - -namespace Ref { - - //! \class MathReceiverGTestBase - //! \brief Auto-generated base class for MathReceiver component Google Test harness - //! - class MathReceiverGTestBase : - public MathReceiverTesterBase - { - - protected: - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - //! Construct object MathReceiverGTestBase - //! - MathReceiverGTestBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, /*!< The component name*/ - const U32 maxHistorySize /*!< The maximum size of each history*/ -#else - const U32 maxHistorySize /*!< The maximum size of each history*/ -#endif - ); - - //! Destroy object MathReceiverGTestBase - //! - virtual ~MathReceiverGTestBase(void); - - protected: - - // ---------------------------------------------------------------------- - // Commands - // ---------------------------------------------------------------------- - - //! Assert size of command response history - //! - void assertCmdResponse_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - //! Assert command response in history at index - //! - void assertCmdResponse( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - const Fw::CommandResponse response /*!< The command response*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Telemetry - // ---------------------------------------------------------------------- - - //! Assert size of telemetry history - //! - void assertTlm_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_OPERATION - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MR_OPERATION_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MR_OPERATION( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const Ref::MathOp& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1S - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MR_FACTOR1S_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MR_FACTOR1S( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const U32& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1 - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MR_FACTOR1_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MR_FACTOR1( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR2 - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MR_FACTOR2_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MR_FACTOR2( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Events - // ---------------------------------------------------------------------- - - void assertEvents_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_SET_FACTOR1 - // ---------------------------------------------------------------------- - - void assertEvents_MR_SET_FACTOR1_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertEvents_MR_SET_FACTOR1( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32 val /*!< The factor value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_UPDATED_FACTOR2 - // ---------------------------------------------------------------------- - - void assertEvents_MR_UPDATED_FACTOR2_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertEvents_MR_UPDATED_FACTOR2( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32 val /*!< The factor value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_OPERATION_PERFORMED - // ---------------------------------------------------------------------- - - void assertEvents_MR_OPERATION_PERFORMED_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertEvents_MR_OPERATION_PERFORMED( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const Ref::MathOp val /*!< The operation*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_THROTTLE_CLEARED - // ---------------------------------------------------------------------- - - void assertEvents_MR_THROTTLE_CLEARED_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // From ports - // ---------------------------------------------------------------------- - - void assertFromPortHistory_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // From port: mathOut - // ---------------------------------------------------------------------- - - void assert_from_mathOut_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - }; - -} // end namespace Ref - -#endif diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/TesterBase.cpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/TesterBase.cpp deleted file mode 100644 index ac08d5ebff..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/TesterBase.cpp +++ /dev/null @@ -1,1538 +0,0 @@ -// ====================================================================== -// \title MathReceiver/test/ut/TesterBase.cpp -// \author Auto-generated -// \brief cpp file for MathReceiver component test harness base class -// -// \copyright -// Copyright 2009-2016, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include -#include -#include "TesterBase.hpp" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - MathReceiverTesterBase :: - MathReceiverTesterBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, - const U32 maxHistorySize -#else - const U32 maxHistorySize -#endif - ) : -#if FW_OBJECT_NAMES == 1 - Fw::PassiveComponentBase(compName) -#else - Fw::PassiveComponentBase() -#endif - { - // Initialize command history - this->cmdResponseHistory = new History(maxHistorySize); - // Initialize telemetry histories - this->tlmHistory_MR_OPERATION = - new History(maxHistorySize); - this->tlmHistory_MR_FACTOR1S = - new History(maxHistorySize); - this->tlmHistory_MR_FACTOR1 = - new History(maxHistorySize); - this->tlmHistory_MR_FACTOR2 = - new History(maxHistorySize); - // Initialize event histories -#if FW_ENABLE_TEXT_LOGGING - this->textLogHistory = new History(maxHistorySize); -#endif - this->eventHistory_MR_SET_FACTOR1 = - new History(maxHistorySize); - this->eventHistory_MR_UPDATED_FACTOR2 = - new History(maxHistorySize); - this->eventHistory_MR_OPERATION_PERFORMED = - new History(maxHistorySize); - // Initialize histories for typed user output ports - this->fromPortHistory_mathOut = - new History(maxHistorySize); - // Clear history - this->clearHistory(); - } - - MathReceiverTesterBase :: - ~MathReceiverTesterBase(void) - { - // Destroy command history - delete this->cmdResponseHistory; - // Destroy telemetry histories - delete this->tlmHistory_MR_OPERATION; - delete this->tlmHistory_MR_FACTOR1S; - delete this->tlmHistory_MR_FACTOR1; - delete this->tlmHistory_MR_FACTOR2; - // Destroy event histories -#if FW_ENABLE_TEXT_LOGGING - delete this->textLogHistory; -#endif - delete this->eventHistory_MR_SET_FACTOR1; - delete this->eventHistory_MR_UPDATED_FACTOR2; - delete this->eventHistory_MR_OPERATION_PERFORMED; - } - - void MathReceiverTesterBase :: - init( - const NATIVE_INT_TYPE instance - ) - { - this->m_param_factor2_valid = Fw::PARAM_UNINIT; - - // Initialize base class - - Fw::PassiveComponentBase::init(instance); - - // Attach input port mathOut - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_mathOut(); - ++_port - ) { - - this->m_from_mathOut[_port].init(); - this->m_from_mathOut[_port].addCallComp( - this, - from_mathOut_static - ); - this->m_from_mathOut[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_mathOut[%d]", - this->m_objName, - _port - ); - this->m_from_mathOut[_port].setObjName(_portName); -#endif - - } - - // Attach input port CmdStatus - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_CmdStatus(); - ++_port - ) { - - this->m_from_CmdStatus[_port].init(); - this->m_from_CmdStatus[_port].addCallComp( - this, - from_CmdStatus_static - ); - this->m_from_CmdStatus[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_CmdStatus[%d]", - this->m_objName, - _port - ); - this->m_from_CmdStatus[_port].setObjName(_portName); -#endif - - } - - // Attach input port CmdReg - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_CmdReg(); - ++_port - ) { - - this->m_from_CmdReg[_port].init(); - this->m_from_CmdReg[_port].addCallComp( - this, - from_CmdReg_static - ); - this->m_from_CmdReg[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_CmdReg[%d]", - this->m_objName, - _port - ); - this->m_from_CmdReg[_port].setObjName(_portName); -#endif - - } - - // Attach input port ParamGet - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_ParamGet(); - ++_port - ) { - - this->m_from_ParamGet[_port].init(); - this->m_from_ParamGet[_port].addCallComp( - this, - from_ParamGet_static - ); - this->m_from_ParamGet[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_ParamGet[%d]", - this->m_objName, - _port - ); - this->m_from_ParamGet[_port].setObjName(_portName); -#endif - - } - - // Attach input port ParamSet - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_ParamSet(); - ++_port - ) { - - this->m_from_ParamSet[_port].init(); - this->m_from_ParamSet[_port].addCallComp( - this, - from_ParamSet_static - ); - this->m_from_ParamSet[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_ParamSet[%d]", - this->m_objName, - _port - ); - this->m_from_ParamSet[_port].setObjName(_portName); -#endif - - } - - // Attach input port Tlm - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_Tlm(); - ++_port - ) { - - this->m_from_Tlm[_port].init(); - this->m_from_Tlm[_port].addCallComp( - this, - from_Tlm_static - ); - this->m_from_Tlm[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_Tlm[%d]", - this->m_objName, - _port - ); - this->m_from_Tlm[_port].setObjName(_portName); -#endif - - } - - // Attach input port Time - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_Time(); - ++_port - ) { - - this->m_from_Time[_port].init(); - this->m_from_Time[_port].addCallComp( - this, - from_Time_static - ); - this->m_from_Time[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_Time[%d]", - this->m_objName, - _port - ); - this->m_from_Time[_port].setObjName(_portName); -#endif - - } - - // Attach input port Log - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_Log(); - ++_port - ) { - - this->m_from_Log[_port].init(); - this->m_from_Log[_port].addCallComp( - this, - from_Log_static - ); - this->m_from_Log[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_Log[%d]", - this->m_objName, - _port - ); - this->m_from_Log[_port].setObjName(_portName); -#endif - - } - - // Attach input port LogText - -#if FW_ENABLE_TEXT_LOGGING == 1 - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_LogText(); - ++_port - ) { - - this->m_from_LogText[_port].init(); - this->m_from_LogText[_port].addCallComp( - this, - from_LogText_static - ); - this->m_from_LogText[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_LogText[%d]", - this->m_objName, - _port - ); - this->m_from_LogText[_port].setObjName(_portName); -#endif - - } -#endif - - // Initialize output port mathIn - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_to_mathIn(); - ++_port - ) { - this->m_to_mathIn[_port].init(); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - snprintf( - _portName, - sizeof(_portName), - "%s_to_mathIn[%d]", - this->m_objName, - _port - ); - this->m_to_mathIn[_port].setObjName(_portName); -#endif - - } - - // Initialize output port SchedIn - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_to_SchedIn(); - ++_port - ) { - this->m_to_SchedIn[_port].init(); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - snprintf( - _portName, - sizeof(_portName), - "%s_to_SchedIn[%d]", - this->m_objName, - _port - ); - this->m_to_SchedIn[_port].setObjName(_portName); -#endif - - } - - } - - // ---------------------------------------------------------------------- - // Getters for port counts - // ---------------------------------------------------------------------- - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_to_mathIn(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_to_mathIn); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_mathOut(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_mathOut); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_to_SchedIn(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_to_SchedIn); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_to_CmdDisp(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_to_CmdDisp); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_CmdStatus(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_CmdStatus); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_CmdReg(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_CmdReg); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_ParamGet(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_ParamGet); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_ParamSet(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_ParamSet); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_Tlm(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_Tlm); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_Time(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_Time); - } - - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_Log(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_Log); - } - -#if FW_ENABLE_TEXT_LOGGING == 1 - NATIVE_INT_TYPE MathReceiverTesterBase :: - getNum_from_LogText(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_LogText); - } -#endif - - // ---------------------------------------------------------------------- - // Connectors for to ports - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - connect_to_mathIn( - const NATIVE_INT_TYPE portNum, - Ref::InputMathOpPort *const mathIn - ) - { - FW_ASSERT(portNum < this->getNum_to_mathIn(),static_cast(portNum)); - this->m_to_mathIn[portNum].addCallPort(mathIn); - } - - void MathReceiverTesterBase :: - connect_to_SchedIn( - const NATIVE_INT_TYPE portNum, - Svc::InputSchedPort *const SchedIn - ) - { - FW_ASSERT(portNum < this->getNum_to_SchedIn(),static_cast(portNum)); - this->m_to_SchedIn[portNum].addCallPort(SchedIn); - } - - void MathReceiverTesterBase :: - connect_to_CmdDisp( - const NATIVE_INT_TYPE portNum, - Fw::InputCmdPort *const CmdDisp - ) - { - FW_ASSERT(portNum < this->getNum_to_CmdDisp(),static_cast(portNum)); - this->m_to_CmdDisp[portNum].addCallPort(CmdDisp); - } - - - // ---------------------------------------------------------------------- - // Invocation functions for to ports - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - invoke_to_mathIn( - const NATIVE_INT_TYPE portNum, - F32 val1, - F32 val2, - MathOperation operation - ) - { - FW_ASSERT(portNum < this->getNum_to_mathIn(),static_cast(portNum)); - FW_ASSERT(portNum < this->getNum_to_mathIn(),static_cast(portNum)); - this->m_to_mathIn[portNum].invoke( - val1, val2, operation - ); - } - - void MathReceiverTesterBase :: - invoke_to_SchedIn( - const NATIVE_INT_TYPE portNum, - NATIVE_UINT_TYPE context - ) - { - FW_ASSERT(portNum < this->getNum_to_SchedIn(),static_cast(portNum)); - FW_ASSERT(portNum < this->getNum_to_SchedIn(),static_cast(portNum)); - this->m_to_SchedIn[portNum].invoke( - context - ); - } - - // ---------------------------------------------------------------------- - // Connection status for to ports - // ---------------------------------------------------------------------- - - bool MathReceiverTesterBase :: - isConnected_to_mathIn(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_to_mathIn(), static_cast(portNum)); - return this->m_to_mathIn[portNum].isConnected(); - } - - bool MathReceiverTesterBase :: - isConnected_to_SchedIn(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_to_SchedIn(), static_cast(portNum)); - return this->m_to_SchedIn[portNum].isConnected(); - } - - bool MathReceiverTesterBase :: - isConnected_to_CmdDisp(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_to_CmdDisp(), static_cast(portNum)); - return this->m_to_CmdDisp[portNum].isConnected(); - } - - // ---------------------------------------------------------------------- - // Getters for from ports - // ---------------------------------------------------------------------- - - Ref::InputMathResultPort *MathReceiverTesterBase :: - get_from_mathOut(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_mathOut(),static_cast(portNum)); - return &this->m_from_mathOut[portNum]; - } - - Fw::InputCmdResponsePort *MathReceiverTesterBase :: - get_from_CmdStatus(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_CmdStatus(),static_cast(portNum)); - return &this->m_from_CmdStatus[portNum]; - } - - Fw::InputCmdRegPort *MathReceiverTesterBase :: - get_from_CmdReg(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_CmdReg(),static_cast(portNum)); - return &this->m_from_CmdReg[portNum]; - } - - Fw::InputPrmGetPort *MathReceiverTesterBase :: - get_from_ParamGet(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_ParamGet(),static_cast(portNum)); - return &this->m_from_ParamGet[portNum]; - } - - Fw::InputPrmSetPort *MathReceiverTesterBase :: - get_from_ParamSet(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_ParamSet(),static_cast(portNum)); - return &this->m_from_ParamSet[portNum]; - } - - Fw::InputTlmPort *MathReceiverTesterBase :: - get_from_Tlm(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_Tlm(),static_cast(portNum)); - return &this->m_from_Tlm[portNum]; - } - - Fw::InputTimePort *MathReceiverTesterBase :: - get_from_Time(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_Time(),static_cast(portNum)); - return &this->m_from_Time[portNum]; - } - - Fw::InputLogPort *MathReceiverTesterBase :: - get_from_Log(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_Log(),static_cast(portNum)); - return &this->m_from_Log[portNum]; - } - -#if FW_ENABLE_TEXT_LOGGING == 1 - Fw::InputLogTextPort *MathReceiverTesterBase :: - get_from_LogText(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_LogText(),static_cast(portNum)); - return &this->m_from_LogText[portNum]; - } -#endif - - // ---------------------------------------------------------------------- - // Static functions for from ports - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - from_mathOut_static( - Fw::PassiveComponentBase *const callComp, - const NATIVE_INT_TYPE portNum, - F32 result - ) - { - FW_ASSERT(callComp); - MathReceiverTesterBase* _testerBase = - static_cast(callComp); - _testerBase->from_mathOut_handlerBase( - portNum, - result - ); - } - - void MathReceiverTesterBase :: - from_CmdStatus_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - const FwOpcodeType opCode, - const U32 cmdSeq, - const Fw::CommandResponse response - ) - { - MathReceiverTesterBase* _testerBase = - static_cast(component); - _testerBase->cmdResponseIn(opCode, cmdSeq, response); - } - - void MathReceiverTesterBase :: - from_CmdReg_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - const FwOpcodeType opCode - ) - { - - } - - void MathReceiverTesterBase :: - from_Tlm_static( - Fw::PassiveComponentBase *const component, - NATIVE_INT_TYPE portNum, - FwChanIdType id, - Fw::Time &timeTag, - Fw::TlmBuffer &val - ) - { - MathReceiverTesterBase* _testerBase = - static_cast(component); - _testerBase->dispatchTlm(id, timeTag, val); - } - - void MathReceiverTesterBase :: - from_Log_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - FwEventIdType id, - Fw::Time &timeTag, - Fw::LogSeverity severity, - Fw::LogBuffer &args - ) - { - MathReceiverTesterBase* _testerBase = - static_cast(component); - _testerBase->dispatchEvents(id, timeTag, severity, args); - } - -#if FW_ENABLE_TEXT_LOGGING == 1 - void MathReceiverTesterBase :: - from_LogText_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - FwEventIdType id, - Fw::Time &timeTag, - Fw::TextLogSeverity severity, - Fw::TextLogString &text - ) - { - MathReceiverTesterBase* _testerBase = - static_cast(component); - _testerBase->textLogIn(id,timeTag,severity,text); - } -#endif - - void MathReceiverTesterBase :: - from_Time_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - Fw::Time& time - ) - { - MathReceiverTesterBase* _testerBase = - static_cast(component); - time = _testerBase->m_testTime; - } - - - Fw::ParamValid MathReceiverTesterBase :: - from_ParamGet_static( - Fw::PassiveComponentBase* component, - NATIVE_INT_TYPE portNum, - FwPrmIdType id, - Fw::ParamBuffer &val - ) - { - MathReceiverTesterBase* _testerBase = - static_cast(component); - - Fw::SerializeStatus _status; - Fw::ParamValid _ret = Fw::PARAM_VALID; - val.resetSer(); - - const U32 idBase = _testerBase->getIdBase(); - FW_ASSERT(id >= idBase, id, idBase); - - switch (id - idBase) { - case 0: - { - _status = val.serialize(_testerBase->m_param_factor2); - _ret = _testerBase->m_param_factor2_valid; - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - } - break; - default: - FW_ASSERT(id); - break; - } - - return _ret; - } - - void MathReceiverTesterBase :: - from_ParamSet_static( - Fw::PassiveComponentBase* component, - NATIVE_INT_TYPE portNum, - FwPrmIdType id, - Fw::ParamBuffer &val - ) - { - MathReceiverTesterBase* _testerBase = - static_cast(component); - - Fw::SerializeStatus _status; - val.resetDeser(); - - // This is exercised completely in autocode, - // so just verify that it works. If it doesn't - // it probably is an autocoder error. - - const U32 idBase = _testerBase->getIdBase(); - FW_ASSERT(id >= idBase, id, idBase); - - switch (id - idBase) { - case 0: - { - F32 factor2Val; - _status = val.deserialize(factor2Val); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT( - factor2Val == - _testerBase->m_param_factor2 - ); - break; - } - - default: { - FW_ASSERT(id); - break; - } - - } - } - - // ---------------------------------------------------------------------- - // Histories for typed from ports - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - clearFromPortHistory(void) - { - this->fromPortHistorySize = 0; - this->fromPortHistory_mathOut->clear(); - } - - // ---------------------------------------------------------------------- - // From port: mathOut - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - pushFromPortEntry_mathOut( - F32 result - ) - { - FromPortEntry_mathOut _e = { - result - }; - this->fromPortHistory_mathOut->push_back(_e); - ++this->fromPortHistorySize; - } - - // ---------------------------------------------------------------------- - // Handler base functions for from ports - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - from_mathOut_handlerBase( - const NATIVE_INT_TYPE portNum, - F32 result - ) - { - FW_ASSERT(portNum < this->getNum_from_mathOut(),static_cast(portNum)); - this->from_mathOut_handler( - portNum, - result - ); - } - - // ---------------------------------------------------------------------- - // Command response handling - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - cmdResponseIn( - const FwOpcodeType opCode, - const U32 seq, - const Fw::CommandResponse response - ) - { - CmdResponse e = { opCode, seq, response }; - this->cmdResponseHistory->push_back(e); - } - - // ---------------------------------------------------------------------- - // Command: MR_SET_FACTOR1 - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - sendCmd_MR_SET_FACTOR1( - const NATIVE_INT_TYPE instance, - const U32 cmdSeq, - F32 val - ) - { - - // Serialize arguments - - Fw::CmdArgBuffer buff; - Fw::SerializeStatus _status; - _status = buff.serialize(val); - FW_ASSERT(_status == Fw::FW_SERIALIZE_OK,static_cast(_status)); - - // Call output command port - - FwOpcodeType _opcode; - const U32 idBase = this->getIdBase(); - _opcode = MathReceiverComponentBase::OPCODE_MR_SET_FACTOR1 + idBase; - - if (this->m_to_CmdDisp[0].isConnected()) { - this->m_to_CmdDisp[0].invoke( - _opcode, - cmdSeq, - buff - ); - } - else { - printf("Test Command Output port not connected!\n"); - } - - } - - // ---------------------------------------------------------------------- - // Command: MR_CLEAR_EVENT_THROTTLE - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - sendCmd_MR_CLEAR_EVENT_THROTTLE( - const NATIVE_INT_TYPE instance, - const U32 cmdSeq - ) - { - - // Serialize arguments - - Fw::CmdArgBuffer buff; - - // Call output command port - - FwOpcodeType _opcode; - const U32 idBase = this->getIdBase(); - _opcode = MathReceiverComponentBase::OPCODE_MR_CLEAR_EVENT_THROTTLE + idBase; - - if (this->m_to_CmdDisp[0].isConnected()) { - this->m_to_CmdDisp[0].invoke( - _opcode, - cmdSeq, - buff - ); - } - else { - printf("Test Command Output port not connected!\n"); - } - - } - - - void MathReceiverTesterBase :: - sendRawCmd(FwOpcodeType opcode, U32 cmdSeq, Fw::CmdArgBuffer& args) { - - const U32 idBase = this->getIdBase(); - FwOpcodeType _opcode = opcode + idBase; - if (this->m_to_CmdDisp[0].isConnected()) { - this->m_to_CmdDisp[0].invoke( - _opcode, - cmdSeq, - args - ); - } - else { - printf("Test Command Output port not connected!\n"); - } - - } - - // ---------------------------------------------------------------------- - // History - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - clearHistory() - { - this->cmdResponseHistory->clear(); - this->clearTlm(); - this->textLogHistory->clear(); - this->clearEvents(); - this->clearFromPortHistory(); - } - - // ---------------------------------------------------------------------- - // Time - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - setTestTime(const Fw::Time& time) - { - this->m_testTime = time; - } - - // ---------------------------------------------------------------------- - // Telemetry dispatch - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - dispatchTlm( - const FwChanIdType id, - const Fw::Time &timeTag, - Fw::TlmBuffer &val - ) - { - - val.resetDeser(); - - const U32 idBase = this->getIdBase(); - FW_ASSERT(id >= idBase, id, idBase); - - switch (id - idBase) { - - case MathReceiverComponentBase::CHANNELID_MR_OPERATION: - { - Ref::MathOp arg; - const Fw::SerializeStatus _status = val.deserialize(arg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MR_OPERATION: %d\n", _status); - return; - } - this->tlmInput_MR_OPERATION(timeTag, arg); - break; - } - - case MathReceiverComponentBase::CHANNELID_MR_FACTOR1S: - { - U32 arg; - const Fw::SerializeStatus _status = val.deserialize(arg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MR_FACTOR1S: %d\n", _status); - return; - } - this->tlmInput_MR_FACTOR1S(timeTag, arg); - break; - } - - case MathReceiverComponentBase::CHANNELID_MR_FACTOR1: - { - F32 arg; - const Fw::SerializeStatus _status = val.deserialize(arg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MR_FACTOR1: %d\n", _status); - return; - } - this->tlmInput_MR_FACTOR1(timeTag, arg); - break; - } - - case MathReceiverComponentBase::CHANNELID_MR_FACTOR2: - { - F32 arg; - const Fw::SerializeStatus _status = val.deserialize(arg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MR_FACTOR2: %d\n", _status); - return; - } - this->tlmInput_MR_FACTOR2(timeTag, arg); - break; - } - - default: { - FW_ASSERT(0, id); - break; - } - - } - - } - - void MathReceiverTesterBase :: - clearTlm(void) - { - this->tlmSize = 0; - this->tlmHistory_MR_OPERATION->clear(); - this->tlmHistory_MR_FACTOR1S->clear(); - this->tlmHistory_MR_FACTOR1->clear(); - this->tlmHistory_MR_FACTOR2->clear(); - } - - // ---------------------------------------------------------------------- - // Channel: MR_OPERATION - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - tlmInput_MR_OPERATION( - const Fw::Time& timeTag, - const Ref::MathOp& val - ) - { - TlmEntry_MR_OPERATION e = { timeTag, val }; - this->tlmHistory_MR_OPERATION->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1S - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - tlmInput_MR_FACTOR1S( - const Fw::Time& timeTag, - const U32& val - ) - { - TlmEntry_MR_FACTOR1S e = { timeTag, val }; - this->tlmHistory_MR_FACTOR1S->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1 - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - tlmInput_MR_FACTOR1( - const Fw::Time& timeTag, - const F32& val - ) - { - TlmEntry_MR_FACTOR1 e = { timeTag, val }; - this->tlmHistory_MR_FACTOR1->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR2 - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - tlmInput_MR_FACTOR2( - const Fw::Time& timeTag, - const F32& val - ) - { - TlmEntry_MR_FACTOR2 e = { timeTag, val }; - this->tlmHistory_MR_FACTOR2->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Event dispatch - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - dispatchEvents( - const FwEventIdType id, - Fw::Time &timeTag, - const Fw::LogSeverity severity, - Fw::LogBuffer &args - ) - { - - args.resetDeser(); - - const U32 idBase = this->getIdBase(); - FW_ASSERT(id >= idBase, id, idBase); - switch (id - idBase) { - - case MathReceiverComponentBase::EVENTID_MR_SET_FACTOR1: - { - - Fw::SerializeStatus _status = Fw::FW_SERIALIZE_OK; -#if FW_AMPCS_COMPATIBLE - // Deserialize the number of arguments. - U8 _numArgs; - _status = args.deserialize(_numArgs); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - // verify they match expected. - FW_ASSERT(_numArgs == 1,_numArgs,1); - -#endif - F32 val; -#if FW_AMPCS_COMPATIBLE - { - // Deserialize the argument size - U8 _argSize; - _status = args.deserialize(_argSize); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT(_argSize == sizeof(F32),_argSize,sizeof(F32)); - } -#endif - _status = args.deserialize(val); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - - this->logIn_ACTIVITY_HI_MR_SET_FACTOR1(val); - - break; - - } - - case MathReceiverComponentBase::EVENTID_MR_UPDATED_FACTOR2: - { - - Fw::SerializeStatus _status = Fw::FW_SERIALIZE_OK; -#if FW_AMPCS_COMPATIBLE - // Deserialize the number of arguments. - U8 _numArgs; - _status = args.deserialize(_numArgs); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - // verify they match expected. - FW_ASSERT(_numArgs == 1,_numArgs,1); - -#endif - F32 val; -#if FW_AMPCS_COMPATIBLE - { - // Deserialize the argument size - U8 _argSize; - _status = args.deserialize(_argSize); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT(_argSize == sizeof(F32),_argSize,sizeof(F32)); - } -#endif - _status = args.deserialize(val); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - - this->logIn_ACTIVITY_HI_MR_UPDATED_FACTOR2(val); - - break; - - } - - case MathReceiverComponentBase::EVENTID_MR_OPERATION_PERFORMED: - { - - Fw::SerializeStatus _status = Fw::FW_SERIALIZE_OK; -#if FW_AMPCS_COMPATIBLE - // Deserialize the number of arguments. - U8 _numArgs; - _status = args.deserialize(_numArgs); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - // verify they match expected. - FW_ASSERT(_numArgs == 1,_numArgs,1); - -#endif - Ref::MathOp val; -#if FW_AMPCS_COMPATIBLE - { - // Deserialize the argument size - U8 _argSize; - _status = args.deserialize(_argSize); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT(_argSize == sizeof(Ref::MathOp),_argSize,sizeof(Ref::MathOp)); - } -#endif - _status = args.deserialize(val); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - - this->logIn_ACTIVITY_HI_MR_OPERATION_PERFORMED(val); - - break; - - } - - case MathReceiverComponentBase::EVENTID_MR_THROTTLE_CLEARED: - { - -#if FW_AMPCS_COMPATIBLE - // For AMPCS, decode zero arguments - Fw::SerializeStatus _zero_status = Fw::FW_SERIALIZE_OK; - U8 _noArgs; - _zero_status = args.deserialize(_noArgs); - FW_ASSERT( - _zero_status == Fw::FW_SERIALIZE_OK, - static_cast(_zero_status) - ); -#endif - this->logIn_ACTIVITY_HI_MR_THROTTLE_CLEARED(); - - break; - - } - - default: { - FW_ASSERT(0, id); - break; - } - - } - - } - - void MathReceiverTesterBase :: - clearEvents(void) - { - this->eventsSize = 0; - this->eventHistory_MR_SET_FACTOR1->clear(); - this->eventHistory_MR_UPDATED_FACTOR2->clear(); - this->eventHistory_MR_OPERATION_PERFORMED->clear(); - this->eventsSize_MR_THROTTLE_CLEARED = 0; - } - -#if FW_ENABLE_TEXT_LOGGING - - // ---------------------------------------------------------------------- - // Text events - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - textLogIn( - const U32 id, - Fw::Time &timeTag, - const Fw::TextLogSeverity severity, - const Fw::TextLogString &text - ) - { - TextLogEntry e = { id, timeTag, severity, text }; - textLogHistory->push_back(e); - } - - void MathReceiverTesterBase :: - printTextLogHistoryEntry( - const TextLogEntry& e, - FILE* file - ) - { - const char *severityString = "UNKNOWN"; - switch (e.severity) { - case Fw::LOG_FATAL: - severityString = "FATAL"; - break; - case Fw::LOG_WARNING_HI: - severityString = "WARNING_HI"; - break; - case Fw::LOG_WARNING_LO: - severityString = "WARNING_LO"; - break; - case Fw::LOG_COMMAND: - severityString = "COMMAND"; - break; - case Fw::LOG_ACTIVITY_HI: - severityString = "ACTIVITY_HI"; - break; - case Fw::LOG_ACTIVITY_LO: - severityString = "ACTIVITY_LO"; - break; - case Fw::LOG_DIAGNOSTIC: - severityString = "DIAGNOSTIC"; - break; - default: - severityString = "SEVERITY ERROR"; - break; - } - - fprintf( - file, - "EVENT: (%d) (%d:%d,%d) %s: %s\n", - e.id, - const_cast(e).timeTag.getTimeBase(), - const_cast(e).timeTag.getSeconds(), - const_cast(e).timeTag.getUSeconds(), - severityString, - e.text.toChar() - ); - - } - - void MathReceiverTesterBase :: - printTextLogHistory(FILE *file) - { - for (U32 i = 0; i < this->textLogHistory->size(); ++i) { - this->printTextLogHistoryEntry( - this->textLogHistory->at(i), - file - ); - } - } - -#endif - - // ---------------------------------------------------------------------- - // Event: MR_SET_FACTOR1 - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - logIn_ACTIVITY_HI_MR_SET_FACTOR1( - F32 val - ) - { - EventEntry_MR_SET_FACTOR1 e = { - val - }; - eventHistory_MR_SET_FACTOR1->push_back(e); - ++this->eventsSize; - } - - // ---------------------------------------------------------------------- - // Event: MR_UPDATED_FACTOR2 - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - logIn_ACTIVITY_HI_MR_UPDATED_FACTOR2( - F32 val - ) - { - EventEntry_MR_UPDATED_FACTOR2 e = { - val - }; - eventHistory_MR_UPDATED_FACTOR2->push_back(e); - ++this->eventsSize; - } - - // ---------------------------------------------------------------------- - // Event: MR_OPERATION_PERFORMED - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - logIn_ACTIVITY_HI_MR_OPERATION_PERFORMED( - Ref::MathOp val - ) - { - EventEntry_MR_OPERATION_PERFORMED e = { - val - }; - eventHistory_MR_OPERATION_PERFORMED->push_back(e); - ++this->eventsSize; - } - - // ---------------------------------------------------------------------- - // Event: MR_THROTTLE_CLEARED - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - logIn_ACTIVITY_HI_MR_THROTTLE_CLEARED( - void - ) - { - ++this->eventsSize_MR_THROTTLE_CLEARED; - ++this->eventsSize; - } - - // ---------------------------------------------------------------------- - // Parameter factor2 - // ---------------------------------------------------------------------- - - void MathReceiverTesterBase :: - paramSet_factor2( - const F32& val, - Fw::ParamValid valid - ) - { - this->m_param_factor2 = val; - this->m_param_factor2_valid = valid; - } - - void MathReceiverTesterBase :: - paramSend_factor2( - NATIVE_INT_TYPE instance, - U32 cmdSeq - ) - { - - // Build command for parameter set - - Fw::CmdArgBuffer args; - FW_ASSERT( - args.serialize( - this->m_param_factor2 - ) == Fw::FW_SERIALIZE_OK - ); - const U32 idBase = this->getIdBase(); - FwOpcodeType _prmOpcode; - _prmOpcode = MathReceiverComponentBase::OPCODE_FACTOR2_SET + idBase; - if (not this->m_to_CmdDisp[0].isConnected()) { - printf("Test Command Output port not connected!\n"); - } - else { - this->m_to_CmdDisp[0].invoke( - _prmOpcode, - cmdSeq, - args - ); - } - - } - - void MathReceiverTesterBase :: - paramSave_factor2 ( - NATIVE_INT_TYPE instance, - U32 cmdSeq - ) - - { - Fw::CmdArgBuffer args; - FwOpcodeType _prmOpcode; - const U32 idBase = this->getIdBase(); - _prmOpcode = MathReceiverComponentBase::OPCODE_FACTOR2_SAVE + idBase; - if (not this->m_to_CmdDisp[0].isConnected()) { - printf("Test Command Output port not connected!\n"); - } - else { - this->m_to_CmdDisp[0].invoke( - _prmOpcode, - cmdSeq, - args - ); - } - } - -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/TesterBase.hpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/TesterBase.hpp deleted file mode 100644 index 543313c988..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Handcode/TesterBase.hpp +++ /dev/null @@ -1,979 +0,0 @@ -// ====================================================================== -// \title MathReceiver/test/ut/TesterBase.hpp -// \author Auto-generated -// \brief hpp file for MathReceiver component test harness base class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef MathReceiver_TESTER_BASE_HPP -#define MathReceiver_TESTER_BASE_HPP - -#include -#include -#include -#include -#include - -namespace Ref { - - //! \class MathReceiverTesterBase - //! \brief Auto-generated base class for MathReceiver component test harness - //! - class MathReceiverTesterBase : - public Fw::PassiveComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Initialization - // ---------------------------------------------------------------------- - - //! Initialize object MathReceiverTesterBase - //! - virtual void init( - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - public: - - // ---------------------------------------------------------------------- - // Connectors for 'to' ports - // Connect these output ports to the input ports under test - // ---------------------------------------------------------------------- - - //! Connect mathIn to to_mathIn[portNum] - //! - void connect_to_mathIn( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Ref::InputMathOpPort *const mathIn /*!< The port*/ - ); - - //! Connect SchedIn to to_SchedIn[portNum] - //! - void connect_to_SchedIn( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Svc::InputSchedPort *const SchedIn /*!< The port*/ - ); - - //! Connect CmdDisp to to_CmdDisp[portNum] - //! - void connect_to_CmdDisp( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::InputCmdPort *const CmdDisp /*!< The port*/ - ); - - public: - - // ---------------------------------------------------------------------- - // Getters for 'from' ports - // Connect these input ports to the output ports under test - // ---------------------------------------------------------------------- - - //! Get the port that receives input from mathOut - //! - //! \return from_mathOut[portNum] - //! - Ref::InputMathResultPort* get_from_mathOut( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from CmdStatus - //! - //! \return from_CmdStatus[portNum] - //! - Fw::InputCmdResponsePort* get_from_CmdStatus( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from CmdReg - //! - //! \return from_CmdReg[portNum] - //! - Fw::InputCmdRegPort* get_from_CmdReg( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from ParamGet - //! - //! \return from_ParamGet[portNum] - //! - Fw::InputPrmGetPort* get_from_ParamGet( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from ParamSet - //! - //! \return from_ParamSet[portNum] - //! - Fw::InputPrmSetPort* get_from_ParamSet( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from Tlm - //! - //! \return from_Tlm[portNum] - //! - Fw::InputTlmPort* get_from_Tlm( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from Time - //! - //! \return from_Time[portNum] - //! - Fw::InputTimePort* get_from_Time( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from Log - //! - //! \return from_Log[portNum] - //! - Fw::InputLogPort* get_from_Log( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! Get the port that receives input from LogText - //! - //! \return from_LogText[portNum] - //! - Fw::InputLogTextPort* get_from_LogText( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); -#endif - - protected: - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - //! Construct object MathReceiverTesterBase - //! - MathReceiverTesterBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, /*!< The component name*/ - const U32 maxHistorySize /*!< The maximum size of each history*/ -#else - const U32 maxHistorySize /*!< The maximum size of each history*/ -#endif - ); - - //! Destroy object MathReceiverTesterBase - //! - virtual ~MathReceiverTesterBase(void); - - // ---------------------------------------------------------------------- - // Test history - // ---------------------------------------------------------------------- - - protected: - - //! \class History - //! \brief A history of port inputs - //! - template class History { - - public: - - //! Create a History - //! - History( - const U32 maxSize /*!< The maximum history size*/ - ) : - numEntries(0), - maxSize(maxSize) - { - this->entries = new T[maxSize]; - } - - //! Destroy a History - //! - ~History() { - delete[] this->entries; - } - - //! Clear the history - //! - void clear() { this->numEntries = 0; } - - //! Push an item onto the history - //! - void push_back( - T entry /*!< The item*/ - ) { - FW_ASSERT(this->numEntries < this->maxSize); - entries[this->numEntries++] = entry; - } - - //! Get an item at an index - //! - //! \return The item at index i - //! - T at( - const U32 i /*!< The index*/ - ) const { - FW_ASSERT(i < this->numEntries); - return entries[i]; - } - - //! Get the number of entries in the history - //! - //! \return The number of entries in the history - //! - U32 size(void) const { return this->numEntries; } - - private: - - //! The number of entries in the history - //! - U32 numEntries; - - //! The maximum history size - //! - const U32 maxSize; - - //! The entries - //! - T *entries; - - }; - - //! Clear all history - //! - void clearHistory(void); - - protected: - - // ---------------------------------------------------------------------- - // Handler prototypes for typed from ports - // ---------------------------------------------------------------------- - - //! Handler prototype for from_mathOut - //! - virtual void from_mathOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 result /*!< the result of the operation*/ - ) = 0; - - //! Handler base function for from_mathOut - //! - void from_mathOut_handlerBase( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 result /*!< the result of the operation*/ - ); - - protected: - - // ---------------------------------------------------------------------- - // Histories for typed from ports - // ---------------------------------------------------------------------- - - //! Clear from port history - //! - void clearFromPortHistory(void); - - //! The total number of from port entries - //! - U32 fromPortHistorySize; - - //! Push an entry on the history for from_mathOut - void pushFromPortEntry_mathOut( - F32 result /*!< the result of the operation*/ - ); - - //! A history entry for from_mathOut - //! - typedef struct { - F32 result; - } FromPortEntry_mathOut; - - //! The history for from_mathOut - //! - History - *fromPortHistory_mathOut; - - protected: - - // ---------------------------------------------------------------------- - // Invocation functions for to ports - // ---------------------------------------------------------------------- - - //! Invoke the to port connected to mathIn - //! - void invoke_to_mathIn( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 val1, - F32 val2, - MathOperation operation /*!< operation argument*/ - ); - - //! Invoke the to port connected to SchedIn - //! - void invoke_to_SchedIn( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - NATIVE_UINT_TYPE context /*!< The call order*/ - ); - - public: - - // ---------------------------------------------------------------------- - // Getters for port counts - // ---------------------------------------------------------------------- - - //! Get the number of to_mathIn ports - //! - //! \return The number of to_mathIn ports - //! - NATIVE_INT_TYPE getNum_to_mathIn(void) const; - - //! Get the number of from_mathOut ports - //! - //! \return The number of from_mathOut ports - //! - NATIVE_INT_TYPE getNum_from_mathOut(void) const; - - //! Get the number of to_SchedIn ports - //! - //! \return The number of to_SchedIn ports - //! - NATIVE_INT_TYPE getNum_to_SchedIn(void) const; - - //! Get the number of to_CmdDisp ports - //! - //! \return The number of to_CmdDisp ports - //! - NATIVE_INT_TYPE getNum_to_CmdDisp(void) const; - - //! Get the number of from_CmdStatus ports - //! - //! \return The number of from_CmdStatus ports - //! - NATIVE_INT_TYPE getNum_from_CmdStatus(void) const; - - //! Get the number of from_CmdReg ports - //! - //! \return The number of from_CmdReg ports - //! - NATIVE_INT_TYPE getNum_from_CmdReg(void) const; - - //! Get the number of from_ParamGet ports - //! - //! \return The number of from_ParamGet ports - //! - NATIVE_INT_TYPE getNum_from_ParamGet(void) const; - - //! Get the number of from_ParamSet ports - //! - //! \return The number of from_ParamSet ports - //! - NATIVE_INT_TYPE getNum_from_ParamSet(void) const; - - //! Get the number of from_Tlm ports - //! - //! \return The number of from_Tlm ports - //! - NATIVE_INT_TYPE getNum_from_Tlm(void) const; - - //! Get the number of from_Time ports - //! - //! \return The number of from_Time ports - //! - NATIVE_INT_TYPE getNum_from_Time(void) const; - - //! Get the number of from_Log ports - //! - //! \return The number of from_Log ports - //! - NATIVE_INT_TYPE getNum_from_Log(void) const; - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! Get the number of from_LogText ports - //! - //! \return The number of from_LogText ports - //! - NATIVE_INT_TYPE getNum_from_LogText(void) const; -#endif - - protected: - - // ---------------------------------------------------------------------- - // Connection status for to ports - // ---------------------------------------------------------------------- - - //! Check whether port is connected - //! - //! Whether to_mathIn[portNum] is connected - //! - bool isConnected_to_mathIn( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Check whether port is connected - //! - //! Whether to_SchedIn[portNum] is connected - //! - bool isConnected_to_SchedIn( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Check whether port is connected - //! - //! Whether to_CmdDisp[portNum] is connected - //! - bool isConnected_to_CmdDisp( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - // ---------------------------------------------------------------------- - // Functions for sending commands - // ---------------------------------------------------------------------- - - protected: - - // send command buffers directly - used for intentional command encoding errors - void sendRawCmd(FwOpcodeType opcode, U32 cmdSeq, Fw::CmdArgBuffer& args); - - //! Send a MR_SET_FACTOR1 command - //! - void sendCmd_MR_SET_FACTOR1( - const NATIVE_INT_TYPE instance, /*!< The instance number*/ - const U32 cmdSeq, /*!< The command sequence number*/ - F32 val /*!< The first factor*/ - ); - - //! Send a MR_CLEAR_EVENT_THROTTLE command - //! - void sendCmd_MR_CLEAR_EVENT_THROTTLE( - const NATIVE_INT_TYPE instance, /*!< The instance number*/ - const U32 cmdSeq /*!< The command sequence number*/ - ); - - protected: - - // ---------------------------------------------------------------------- - // Command response handling - // ---------------------------------------------------------------------- - - //! Handle a command response - //! - virtual void cmdResponseIn( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - const Fw::CommandResponse response /*!< The command response*/ - ); - - //! A type representing a command response - //! - typedef struct { - FwOpcodeType opCode; - U32 cmdSeq; - Fw::CommandResponse response; - } CmdResponse; - - //! The command response history - //! - History *cmdResponseHistory; - - protected: - - // ---------------------------------------------------------------------- - // Event dispatch - // ---------------------------------------------------------------------- - - //! Dispatch an event - //! - void dispatchEvents( - const FwEventIdType id, /*!< The event ID*/ - Fw::Time& timeTag, /*!< The time*/ - const Fw::LogSeverity severity, /*!< The severity*/ - Fw::LogBuffer& args /*!< The serialized arguments*/ - ); - - //! Clear event history - //! - void clearEvents(void); - - //! The total number of events seen - //! - U32 eventsSize; - -#if FW_ENABLE_TEXT_LOGGING - - protected: - - // ---------------------------------------------------------------------- - // Text events - // ---------------------------------------------------------------------- - - //! Handle a text event - //! - virtual void textLogIn( - const FwEventIdType id, /*!< The event ID*/ - Fw::Time& timeTag, /*!< The time*/ - const Fw::TextLogSeverity severity, /*!< The severity*/ - const Fw::TextLogString& text /*!< The event string*/ - ); - - //! A history entry for the text log - //! - typedef struct { - U32 id; - Fw::Time timeTag; - Fw::TextLogSeverity severity; - Fw::TextLogString text; - } TextLogEntry; - - //! The history of text log events - //! - History *textLogHistory; - - //! Print a text log history entry - //! - static void printTextLogHistoryEntry( - const TextLogEntry& e, - FILE* file - ); - - //! Print the text log history - //! - void printTextLogHistory(FILE *const file); - -#endif - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_SET_FACTOR1 - // ---------------------------------------------------------------------- - - //! Handle event MR_SET_FACTOR1 - //! - virtual void logIn_ACTIVITY_HI_MR_SET_FACTOR1( - F32 val /*!< The factor value*/ - ); - - //! A history entry for event MR_SET_FACTOR1 - //! - typedef struct { - F32 val; - } EventEntry_MR_SET_FACTOR1; - - //! The history of MR_SET_FACTOR1 events - //! - History - *eventHistory_MR_SET_FACTOR1; - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_UPDATED_FACTOR2 - // ---------------------------------------------------------------------- - - //! Handle event MR_UPDATED_FACTOR2 - //! - virtual void logIn_ACTIVITY_HI_MR_UPDATED_FACTOR2( - F32 val /*!< The factor value*/ - ); - - //! A history entry for event MR_UPDATED_FACTOR2 - //! - typedef struct { - F32 val; - } EventEntry_MR_UPDATED_FACTOR2; - - //! The history of MR_UPDATED_FACTOR2 events - //! - History - *eventHistory_MR_UPDATED_FACTOR2; - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_OPERATION_PERFORMED - // ---------------------------------------------------------------------- - - //! Handle event MR_OPERATION_PERFORMED - //! - virtual void logIn_ACTIVITY_HI_MR_OPERATION_PERFORMED( - Ref::MathOp val /*!< The operation*/ - ); - - //! A history entry for event MR_OPERATION_PERFORMED - //! - typedef struct { - Ref::MathOp val; - } EventEntry_MR_OPERATION_PERFORMED; - - //! The history of MR_OPERATION_PERFORMED events - //! - History - *eventHistory_MR_OPERATION_PERFORMED; - - protected: - - // ---------------------------------------------------------------------- - // Event: MR_THROTTLE_CLEARED - // ---------------------------------------------------------------------- - - //! Handle event MR_THROTTLE_CLEARED - //! - virtual void logIn_ACTIVITY_HI_MR_THROTTLE_CLEARED( - void - ); - - //! Size of history for event MR_THROTTLE_CLEARED - //! - U32 eventsSize_MR_THROTTLE_CLEARED; - - protected: - - // ---------------------------------------------------------------------- - // Telemetry dispatch - // ---------------------------------------------------------------------- - - //! Dispatch telemetry - //! - void dispatchTlm( - const FwChanIdType id, /*!< The channel ID*/ - const Fw::Time& timeTag, /*!< The time*/ - Fw::TlmBuffer& val /*!< The channel value*/ - ); - - //! Clear telemetry history - //! - void clearTlm(void); - - //! The total number of telemetry inputs seen - //! - U32 tlmSize; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_OPERATION - // ---------------------------------------------------------------------- - - //! Handle channel MR_OPERATION - //! - virtual void tlmInput_MR_OPERATION( - const Fw::Time& timeTag, /*!< The time*/ - const Ref::MathOp& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MR_OPERATION - //! - typedef struct { - Fw::Time timeTag; - Ref::MathOp arg; - } TlmEntry_MR_OPERATION; - - //! The history of MR_OPERATION values - //! - History - *tlmHistory_MR_OPERATION; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1S - // ---------------------------------------------------------------------- - - //! Handle channel MR_FACTOR1S - //! - virtual void tlmInput_MR_FACTOR1S( - const Fw::Time& timeTag, /*!< The time*/ - const U32& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MR_FACTOR1S - //! - typedef struct { - Fw::Time timeTag; - U32 arg; - } TlmEntry_MR_FACTOR1S; - - //! The history of MR_FACTOR1S values - //! - History - *tlmHistory_MR_FACTOR1S; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR1 - // ---------------------------------------------------------------------- - - //! Handle channel MR_FACTOR1 - //! - virtual void tlmInput_MR_FACTOR1( - const Fw::Time& timeTag, /*!< The time*/ - const F32& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MR_FACTOR1 - //! - typedef struct { - Fw::Time timeTag; - F32 arg; - } TlmEntry_MR_FACTOR1; - - //! The history of MR_FACTOR1 values - //! - History - *tlmHistory_MR_FACTOR1; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MR_FACTOR2 - // ---------------------------------------------------------------------- - - //! Handle channel MR_FACTOR2 - //! - virtual void tlmInput_MR_FACTOR2( - const Fw::Time& timeTag, /*!< The time*/ - const F32& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MR_FACTOR2 - //! - typedef struct { - Fw::Time timeTag; - F32 arg; - } TlmEntry_MR_FACTOR2; - - //! The history of MR_FACTOR2 values - //! - History - *tlmHistory_MR_FACTOR2; - - protected: - - // ---------------------------------------------------------------------- - // Test time - // ---------------------------------------------------------------------- - - //! Set the test time for events and telemetry - //! - void setTestTime( - const Fw::Time& timeTag /*!< The time*/ - ); - - protected: - - // ---------------------------------------------------------------------- - // Parameter: factor2 - // ---------------------------------------------------------------------- - - void paramSet_factor2( - const F32& val, /*!< The parameter value*/ - Fw::ParamValid valid /*!< The parameter valid flag*/ - ); - - void paramSend_factor2( - const NATIVE_INT_TYPE instance, /*!< The instance number*/ - const U32 cmdSeq /*!< The command sequence number*/ - ); - - void paramSave_factor2( - const NATIVE_INT_TYPE instance, /*!< The instance number*/ - const U32 cmdSeq /*!< The command sequence number*/ - ); - - private: - - // ---------------------------------------------------------------------- - // To ports - // ---------------------------------------------------------------------- - - //! To port connected to mathIn - //! - Ref::OutputMathOpPort m_to_mathIn[1]; - - //! To port connected to SchedIn - //! - Svc::OutputSchedPort m_to_SchedIn[1]; - - //! To port connected to CmdDisp - //! - Fw::OutputCmdPort m_to_CmdDisp[1]; - - private: - - // ---------------------------------------------------------------------- - // From ports - // ---------------------------------------------------------------------- - - //! From port connected to mathOut - //! - Ref::InputMathResultPort m_from_mathOut[1]; - - //! From port connected to CmdStatus - //! - Fw::InputCmdResponsePort m_from_CmdStatus[1]; - - //! From port connected to CmdReg - //! - Fw::InputCmdRegPort m_from_CmdReg[1]; - - //! From port connected to ParamGet - //! - Fw::InputPrmGetPort m_from_ParamGet[1]; - - //! From port connected to ParamSet - //! - Fw::InputPrmSetPort m_from_ParamSet[1]; - - //! From port connected to Tlm - //! - Fw::InputTlmPort m_from_Tlm[1]; - - //! From port connected to Time - //! - Fw::InputTimePort m_from_Time[1]; - - //! From port connected to Log - //! - Fw::InputLogPort m_from_Log[1]; - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! From port connected to LogText - //! - Fw::InputLogTextPort m_from_LogText[1]; -#endif - - private: - - // ---------------------------------------------------------------------- - // Static functions for output ports - // ---------------------------------------------------------------------- - - //! Static function for port from_mathOut - //! - static void from_mathOut_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 result /*!< the result of the operation*/ - ); - - //! Static function for port from_CmdStatus - //! - static void from_CmdStatus_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwOpcodeType opCode, /*!< Command Op Code*/ - U32 cmdSeq, /*!< Command Sequence*/ - Fw::CommandResponse response /*!< The command response argument*/ - ); - - //! Static function for port from_CmdReg - //! - static void from_CmdReg_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwOpcodeType opCode /*!< Command Op Code*/ - ); - - //! Static function for port from_ParamGet - //! - static Fw::ParamValid from_ParamGet_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwPrmIdType id, /*!< Parameter ID*/ - Fw::ParamBuffer &val /*!< Buffer containing serialized parameter value*/ - ); - - //! Static function for port from_ParamSet - //! - static void from_ParamSet_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwPrmIdType id, /*!< Parameter ID*/ - Fw::ParamBuffer &val /*!< Buffer containing serialized parameter value*/ - ); - - //! Static function for port from_Tlm - //! - static void from_Tlm_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwChanIdType id, /*!< Telemetry Channel ID*/ - Fw::Time &timeTag, /*!< Time Tag*/ - Fw::TlmBuffer &val /*!< Buffer containing serialized telemetry value*/ - ); - - //! Static function for port from_Time - //! - static void from_Time_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Time &time /*!< The U32 cmd argument*/ - ); - - //! Static function for port from_Log - //! - static void from_Log_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwEventIdType id, /*!< Log ID*/ - Fw::Time &timeTag, /*!< Time Tag*/ - Fw::LogSeverity severity, /*!< The severity argument*/ - Fw::LogBuffer &args /*!< Buffer containing serialized log entry*/ - ); - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! Static function for port from_LogText - //! - static void from_LogText_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwEventIdType id, /*!< Log ID*/ - Fw::Time &timeTag, /*!< Time Tag*/ - Fw::TextLogSeverity severity, /*!< The severity argument*/ - Fw::TextLogString &text /*!< Text of log message*/ - ); -#endif - - private: - - // ---------------------------------------------------------------------- - // Test time - // ---------------------------------------------------------------------- - - //! Test time stamp - //! - Fw::Time m_testTime; - - private: - - // ---------------------------------------------------------------------- - // Parameter validity flags - // ---------------------------------------------------------------------- - - //! True if parameter factor2 was successfully received - //! - Fw::ParamValid m_param_factor2_valid; - - private: - - // ---------------------------------------------------------------------- - // Parameter variables - // ---------------------------------------------------------------------- - - //! Parameter factor2 - //! - F32 m_param_factor2; - - }; - -} // end namespace Ref - -#endif diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.cpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.cpp index a5fa66015d..31b34023ed 100644 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.cpp +++ b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.cpp @@ -1,15 +1,16 @@ // ====================================================================== // \title MathReceiver.hpp -// \author tcanham +// \author tcanham, bocchino // \brief cpp file for MathReceiver test harness implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2021, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // // ====================================================================== +#include "STest/Pick/Pick.hpp" #include "Tester.hpp" #define INSTANCE 0 @@ -24,13 +25,8 @@ namespace Ref { Tester :: Tester() : -#if FW_OBJECT_NAMES == 1 MathReceiverGTestBase("Tester", MAX_HISTORY_SIZE), component("MathReceiver") -#else - MathReceiverGTestBase(MAX_HISTORY_SIZE), - component() -#endif { this->initComponents(); this->connectPorts(); @@ -47,342 +43,45 @@ namespace Ref { // ---------------------------------------------------------------------- void Tester :: - testAddCommand() + testAdd() { - // load parameters - this->component.loadParameters(); - // invoke operation port with add operation - this->invoke_to_mathIn(0,2.0,3.0,Ref::MATH_ADD); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - - // verify the result of the operation was returned - - // check that there was one and only one port invocation - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // check that only the port we expected was invoked - ASSERT_from_mathOut_SIZE(1); - // check that the component did the operation correctly. - // Since factor1 is the default value of 0, result will be zero - ASSERT_from_mathOut(0,0.0); - // verify telemetry and events - - // the event and telemetry channel use the Ref::MathOp type for values - Ref::MathOp checkOp(2.0,3.0,Ref::ADD,0.0); - - // check that there was only one event - ASSERT_EVENTS_SIZE(1); - // check that it was the op event - ASSERT_EVENTS_MR_OPERATION_PERFORMED_SIZE(1); - // check that the event has the correct argument - ASSERT_EVENTS_MR_OPERATION_PERFORMED(0,checkOp); - - // check that there was only one channel written - ASSERT_TLM_SIZE(1); - // check that it was the op channel - ASSERT_TLM_MR_OPERATION_SIZE(1); - // check for the correct value of the channel - ASSERT_TLM_MR_OPERATION(0,checkOp); - - // clear the history before sending the command - this->clearHistory(); - // send the command to set factor1 to 2.0 - this->sendCmd_MR_SET_FACTOR1(0,10,2.0); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - // verify the changed value events - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1(0,2.0); - // verify the changed value channel - ASSERT_TLM_SIZE(2); - ASSERT_TLM_MR_FACTOR1_SIZE(1); - ASSERT_TLM_MR_FACTOR1(0,2.0); - ASSERT_TLM_MR_FACTOR1S_SIZE(1); - ASSERT_TLM_MR_FACTOR1S(0,1); - // verify the command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,MathReceiverComponentBase::OPCODE_MR_SET_FACTOR1,10,Fw::CmdResponse::OK); - - // Repeat the operation with the new factor - - // clear the history before sending the port call - this->clearHistory(); - - // invoke operation port with add operation - this->invoke_to_mathIn(0,2.0,3.0,Ref::MATH_ADD); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - - // verify the result of the operation was returned - - // check that there was one and only one port invocation - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // check that only the port we expected was invoked - ASSERT_from_mathOut_SIZE(1); - // check that the component did the operation correctly. - // Now that factor1 is updated, the result should be: - F32 result = (2.0+3.0)*2.0; - ASSERT_from_mathOut(0,result); - // verify telemetry and events - - // the event and telemetry channel use the Ref::MathOp type for values - checkOp.set(2.0,3.0,Ref::ADD,result); - - // check that there was only one event - ASSERT_EVENTS_SIZE(1); - // check that it was the op event - ASSERT_EVENTS_MR_OPERATION_PERFORMED_SIZE(1); - // check that the event has the correct argument - ASSERT_EVENTS_MR_OPERATION_PERFORMED(0,checkOp); - - // check that there was only one channel written - ASSERT_TLM_SIZE(1); - // check that it was the op channel - ASSERT_TLM_MR_OPERATION_SIZE(1); - // check for the correct value of the channel - ASSERT_TLM_MR_OPERATION(0,checkOp); - - // clear the history - this->clearHistory(); - - // set the test value for the parameter - this->paramSet_factor2(3.0,Fw::PARAM_VALID); - // now send the factor2 parameter to the component - this->paramSend_factor2(0,0); - // verify the parameter update notification event was sent - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_UPDATED_FACTOR2_SIZE(1); - ASSERT_EVENTS_MR_UPDATED_FACTOR2(0,3.0); - - // Do the computation again and verify that the parameter was used - - // clear the history - this->clearHistory(); - - // invoke operation port with add operation - this->invoke_to_mathIn(0,2.0,3.0,Ref::MATH_ADD); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - - // verify the result of the operation was returned - - // check that there was one and only one port invocation - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // check that only the port we expected was invoked - ASSERT_from_mathOut_SIZE(1); - // check that the component did the operation correctly. - // Now that factor2 parameter is updated, the result should be: - result = (2.0+3.0)*2.0/3.0; - ASSERT_from_mathOut(0,result); - // verify telemetry and events - - // the event and telemetry channel use the Ref::MathOp type for values - checkOp.set(2.0,3.0,Ref::ADD,result); - - // check that there was only one event - ASSERT_EVENTS_SIZE(1); - // check that it was the op event - ASSERT_EVENTS_MR_OPERATION_PERFORMED_SIZE(1); - // check that the event has the correct argument - ASSERT_EVENTS_MR_OPERATION_PERFORMED(0,checkOp); - - // check that there was only one channel written - ASSERT_TLM_SIZE(1); - // check that it was the op channel - ASSERT_TLM_MR_OPERATION_SIZE(1); - // check for the correct value of the channel - ASSERT_TLM_MR_OPERATION(0,checkOp); - -} + // Set the factor parameter by command + const F32 factor = pickF32Value(); + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + // Do the add operation + this->doMathOp(MathOp::ADD, factor); + } void Tester :: - testSubCommand() + testSub() { - // set the test value for the parameter before loading - it will be initialized to this value - this->paramSet_factor2(5.0,Fw::PARAM_VALID); - - // load parameters + // Set the factor parameter by loading parameters + const F32 factor = pickF32Value(); + this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); this->component.loadParameters(); - - // send the command to set factor1 to 2.0 - this->sendCmd_MR_SET_FACTOR1(0,10,2.0); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - // verify the changed value events - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1(0,2.0); - // verify the changed value channel - ASSERT_TLM_SIZE(2); - ASSERT_TLM_MR_FACTOR1_SIZE(1); - ASSERT_TLM_MR_FACTOR1(0,2.0); - ASSERT_TLM_MR_FACTOR1S_SIZE(1); - ASSERT_TLM_MR_FACTOR1S(0,1); - // verify the command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,MathReceiverComponentBase::OPCODE_MR_SET_FACTOR1,10,Fw::CmdResponse::OK); - - // clear the history - this->clearHistory(); - - // invoke operation port with add operation - this->invoke_to_mathIn(0,2.0,3.0,Ref::MATH_SUB); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - - // verify the result of the operation was returned - F32 result = (2.0-3.0)*2.0/5.0; - // the event and telemetry channel use the Ref::MathOp type for values - Ref::MathOp checkOp(2.0,3.0,Ref::SUB,result); - - // check that there was one and only one port invocation - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // check that only the port we expected was invoked - ASSERT_from_mathOut_SIZE(1); - // check that the component did the operation correctly. - ASSERT_from_mathOut(0,result); - // verify telemetry and events - - // check that there was only one event - ASSERT_EVENTS_SIZE(1); - // check that it was the op event - ASSERT_EVENTS_MR_OPERATION_PERFORMED_SIZE(1); - // check that the event has the correct argument - ASSERT_EVENTS_MR_OPERATION_PERFORMED(0,checkOp); - - // check that there was only one channel written - ASSERT_TLM_SIZE(1); - // check that it was the op channel - ASSERT_TLM_MR_OPERATION_SIZE(1); - // check for the correct value of the channel - ASSERT_TLM_MR_OPERATION(0,checkOp); + // Do the operation + this->doMathOp(MathOp::SUB, factor); } void Tester :: - testMultCommand() + testMul() { - // set the test value for the parameter before loading - it will be initialized to this value - this->paramSet_factor2(-1.0,Fw::PARAM_VALID); - - // load parameters - this->component.loadParameters(); - - // send the command to set factor1 to 2.0 - this->sendCmd_MR_SET_FACTOR1(0,10,2.0); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - // verify the changed value events - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1(0,2.0); - ASSERT_TLM_MR_FACTOR1S_SIZE(1); - ASSERT_TLM_MR_FACTOR1S(0,1); - // verify the changed value channel - ASSERT_TLM_SIZE(2); - ASSERT_TLM_MR_FACTOR1_SIZE(1); - ASSERT_TLM_MR_FACTOR1(0,2.0); - // verify the command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,MathReceiverComponentBase::OPCODE_MR_SET_FACTOR1,10,Fw::CmdResponse::OK); - - // clear the history - this->clearHistory(); - - // invoke operation port with add operation - this->invoke_to_mathIn(0,2.0,3.0,Ref::MATH_MULTIPLY); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - - // verify the result of the operation was returned - F32 result = (2.0*3.0)*2.0/-1.0; - // the event and telemetry channel use the Ref::MathOp type for values - Ref::MathOp checkOp(2.0,3.0,Ref::MULT,result); - - // check that there was one and only one port invocation - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // check that only the port we expected was invoked - ASSERT_from_mathOut_SIZE(1); - // check that the component did the operation correctly. - ASSERT_from_mathOut(0,result); - // verify telemetry and events - - // check that there was only one event - ASSERT_EVENTS_SIZE(1); - // check that it was the op event - ASSERT_EVENTS_MR_OPERATION_PERFORMED_SIZE(1); - // check that the event has the correct argument - ASSERT_EVENTS_MR_OPERATION_PERFORMED(0,checkOp); - - // check that there was only one channel written - ASSERT_TLM_SIZE(1); - // check that it was the op channel - ASSERT_TLM_MR_OPERATION_SIZE(1); - // check for the correct value of the channel - ASSERT_TLM_MR_OPERATION(0,checkOp); + // Set the factor parameter by command + const F32 factor = 3.0; + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + // Do the add operation + this->doMathOp(MathOp::MUL, factor); } void Tester :: - testDivCommand() + testDiv() { - // set the test value for the parameter before loading - it will be initialized to this value - this->paramSet_factor2(25.0,Fw::PARAM_VALID); - - // load parameters + // Set the factor parameter by loading parameters + const F32 factor = 3.0; + this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); this->component.loadParameters(); - - // send the command to set factor1 to 2.0 - this->sendCmd_MR_SET_FACTOR1(0,10,2.0); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - // verify the changed value events - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1(0,2.0); - ASSERT_TLM_MR_FACTOR1S_SIZE(1); - ASSERT_TLM_MR_FACTOR1S(0,1); - // verify the changed value channel - ASSERT_TLM_SIZE(2); - ASSERT_TLM_MR_FACTOR1_SIZE(1); - ASSERT_TLM_MR_FACTOR1(0,2.0); - // verify the command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,MathReceiverComponentBase::OPCODE_MR_SET_FACTOR1,10,Fw::CmdResponse::OK); - - // clear the history - this->clearHistory(); - - // invoke operation port with add operation - this->invoke_to_mathIn(0,2.0,3.0,Ref::MATH_DIVIDE); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - - // verify the result of the operation was returned - F32 result = (2.0/3.0)*2.0/25; - // the event and telemetry channel use the Ref::MathOp type for values - Ref::MathOp checkOp(2.0,3.0,Ref::DIVIDE,result); - - // check that there was one and only one port invocation - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // check that only the port we expected was invoked - ASSERT_from_mathOut_SIZE(1); - // check that the component did the operation correctly. - ASSERT_from_mathOut(0,result); - // verify telemetry and events - - // check that there was only one event - ASSERT_EVENTS_SIZE(1); - // check that it was the op event - ASSERT_EVENTS_MR_OPERATION_PERFORMED_SIZE(1); - // check that the event has the correct argument - ASSERT_EVENTS_MR_OPERATION_PERFORMED(0,checkOp); - - // check that there was only one channel written - ASSERT_TLM_SIZE(1); - // check that it was the op channel - ASSERT_TLM_MR_OPERATION_SIZE(1); - // check for the correct value of the channel - ASSERT_TLM_MR_OPERATION(0,checkOp); + // Do the operation + this->doMathOp(MathOp::DIV, factor); } void Tester :: @@ -392,68 +91,31 @@ namespace Ref { // send the number of commands required to throttle the event // Use the autocoded value so the unit test passes if the // throttle value is changed - for (NATIVE_UINT_TYPE cycle = 0; cycle < MathReceiverComponentBase::EVENTID_MR_SET_FACTOR1_THROTTLE; cycle++) { - // send the command to set factor1 to 2.0 - this->sendCmd_MR_SET_FACTOR1(0,10,2.0); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - // verify the changed value events - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1(0,2.0); - // verify the changed value channel - ASSERT_TLM_SIZE(2); - ASSERT_TLM_MR_FACTOR1_SIZE(1); - ASSERT_TLM_MR_FACTOR1(0,2.0); - ASSERT_TLM_MR_FACTOR1S_SIZE(1); - ASSERT_TLM_MR_FACTOR1S(0,cycle+1); - - // verify the command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,MathReceiverComponentBase::OPCODE_MR_SET_FACTOR1,10,Fw::CmdResponse::OK); - - // clear the history - this->clearHistory(); + const F32 factor = pickF32Value(); + for ( + U16 cycle = 0; + cycle < MathReceiverComponentBase::EVENTID_FACTOR_UPDATED_THROTTLE; + cycle++ + ) { + this->setFactor(factor, ThrottleState::NOT_THROTTLED); } - // sending the command now will not result in an event since - // the throttle value has been reached - - // send the command to set factor1 to 2.0 - this->sendCmd_MR_SET_FACTOR1(0,10,2.0); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - // verify the changed value events - ASSERT_EVENTS_SIZE(0); - // verify the changed value channel - ASSERT_TLM_SIZE(2); - ASSERT_TLM_MR_FACTOR1_SIZE(1); - ASSERT_TLM_MR_FACTOR1(0,2.0); - // verify the command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,MathReceiverComponentBase::OPCODE_MR_SET_FACTOR1,10,Fw::CmdResponse::OK); - - // clear the history - this->clearHistory(); + // Event should now be throttled + this->setFactor(factor, ThrottleState::THROTTLED); // send the command to clear the throttle - this->sendCmd_MR_CLEAR_EVENT_THROTTLE(0,10); + const U32 instance = STest::Pick::any(); + const U32 cmdSeq = STest::Pick::any(); + this->sendCmd_CLEAR_EVENT_THROTTLE(instance, cmdSeq); // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); + const U32 context = STest::Pick::any(); + this->invoke_to_schedIn(0, context); // verify clear event was sent ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_THROTTLE_CLEARED_SIZE(1); + ASSERT_EVENTS_THROTTLE_CLEARED_SIZE(1); - // clear the history - this->clearHistory(); - // sending the command will now produce the event again - this->sendCmd_MR_SET_FACTOR1(0,10,2.0); - // invoke scheduler port to dispatch message - this->invoke_to_SchedIn(0,0); - // verify the changed value event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1_SIZE(1); - ASSERT_EVENTS_MR_SET_FACTOR1(0,2.0); + // Throttling should be cleared + this->setFactor(factor, ThrottleState::NOT_THROTTLED); } @@ -462,92 +124,200 @@ namespace Ref { // ---------------------------------------------------------------------- void Tester :: - from_mathOut_handler( + from_mathResultOut_handler( const NATIVE_INT_TYPE portNum, F32 result ) { - this->pushFromPortEntry_mathOut(result); + this->pushFromPortEntry_mathResultOut(result); } // ---------------------------------------------------------------------- // Helper methods // ---------------------------------------------------------------------- + F32 Tester :: + pickF32Value() + { + const F32 m = 10e6; + return m * (1.0 - 2 * STest::Pick::inUnitInterval()); + } + + void Tester :: + setFactor( + F32 factor, + ThrottleState throttleState + ) + { + // clear history + this->clearHistory(); + // set the parameter + this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); + const U32 instance = STest::Pick::any(); + const U32 cmdSeq = STest::Pick::any(); + this->paramSend_FACTOR(instance, cmdSeq); + if (throttleState == ThrottleState::NOT_THROTTLED) { + // verify the parameter update notification event was sent + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_FACTOR_UPDATED_SIZE(1); + ASSERT_EVENTS_FACTOR_UPDATED(0, factor); + } + else { + ASSERT_EVENTS_SIZE(0); + } + } + + F32 Tester :: + computeResult( + F32 val1, + MathOp op, + F32 val2, + F32 factor + ) + { + F32 result = 0; + switch (op.e) { + case MathOp::ADD: + result = val1 + val2; + break; + case MathOp::SUB: + result = val1 - val2; + break; + case MathOp::MUL: + result = val1 * val2; + break; + case MathOp::DIV: + result = val1 / val2; + break; + default: + FW_ASSERT(0, op.e); + break; + } + result *= factor; + return result; + } + + void Tester :: + doMathOp(MathOp op, F32 factor) + { + + // pick values + const F32 val1 = pickF32Value(); + const F32 val2 = pickF32Value(); + + // clear history + this->clearHistory(); + + // invoke operation port with add operation + this->invoke_to_mathOpIn(0, val1, op, val2); + // invoke scheduler port to dispatch message + const U32 context = STest::Pick::any(); + this->invoke_to_schedIn(0, context); + + // verify the result of the operation was returned + + // check that there was one port invocation + ASSERT_FROM_PORT_HISTORY_SIZE(1); + // check that the port we expected was invoked + ASSERT_from_mathResultOut_SIZE(1); + // check that the component performed the operation correctly + const F32 result = computeResult(val1, op, val2, factor); + ASSERT_from_mathResultOut(0, result); + + // verify events + + // check that there was one event + ASSERT_EVENTS_SIZE(1); + // check that it was the op event + ASSERT_EVENTS_OPERATION_PERFORMED_SIZE(1); + // check that the event has the correct argument + ASSERT_EVENTS_OPERATION_PERFORMED(0, op); + + // verify telemetry + + // check that one channel was written + ASSERT_TLM_SIZE(1); + // check that it was the op channel + ASSERT_TLM_OPERATION_SIZE(1); + // check for the correct value of the channel + ASSERT_TLM_OPERATION(0, op); + + } + void Tester :: connectPorts() { - // mathIn - this->connect_to_mathIn( + // mathOpIn + this->connect_to_mathOpIn( 0, - this->component.get_mathIn_InputPort(0) + this->component.get_mathOpIn_InputPort(0) ); - // SchedIn - this->connect_to_SchedIn( + // schedIn + this->connect_to_schedIn( 0, - this->component.get_SchedIn_InputPort(0) + this->component.get_schedIn_InputPort(0) ); - // CmdDisp - this->connect_to_CmdDisp( + // cmdIn + this->connect_to_cmdIn( 0, - this->component.get_CmdDisp_InputPort(0) + this->component.get_cmdIn_InputPort(0) ); - // mathOut - this->component.set_mathOut_OutputPort( + // mathResultOut + this->component.set_mathResultOut_OutputPort( 0, - this->get_from_mathOut(0) + this->get_from_mathResultOut(0) ); - // CmdStatus - this->component.set_CmdStatus_OutputPort( + // cmdResponseOut + this->component.set_cmdResponseOut_OutputPort( 0, - this->get_from_CmdStatus(0) + this->get_from_cmdResponseOut(0) ); - // CmdReg - this->component.set_CmdReg_OutputPort( + // cmdRegOut + this->component.set_cmdRegOut_OutputPort( 0, - this->get_from_CmdReg(0) + this->get_from_cmdRegOut(0) ); - // ParamGet - this->component.set_ParamGet_OutputPort( + // prmGetOut + this->component.set_prmGetOut_OutputPort( 0, - this->get_from_ParamGet(0) + this->get_from_prmGetOut(0) ); - // ParamSet - this->component.set_ParamSet_OutputPort( + // prmSetOut + this->component.set_prmSetOut_OutputPort( 0, - this->get_from_ParamSet(0) + this->get_from_prmSetOut(0) ); - // Tlm - this->component.set_Tlm_OutputPort( + // tlmOut + this->component.set_tlmOut_OutputPort( 0, - this->get_from_Tlm(0) + this->get_from_tlmOut(0) ); - // Time - this->component.set_Time_OutputPort( + // timeGetOut + this->component.set_timeGetOut_OutputPort( 0, - this->get_from_Time(0) + this->get_from_timeGetOut(0) ); - // Log - this->component.set_Log_OutputPort( + // eventOut + this->component.set_eventOut_OutputPort( 0, - this->get_from_Log(0) + this->get_from_eventOut(0) ); - // LogText - this->component.set_LogText_OutputPort( + // textEventOut + this->component.set_textEventOut_OutputPort( 0, - this->get_from_LogText(0) + this->get_from_textEventOut(0) ); } @@ -556,9 +326,7 @@ namespace Ref { initComponents() { this->init(); - this->component.init( - QUEUE_DEPTH, INSTANCE - ); + this->component.init(QUEUE_DEPTH, INSTANCE); } } // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.hpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.hpp index 1a149458d1..1e18417ae0 100644 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.hpp +++ b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.hpp @@ -1,10 +1,10 @@ // ====================================================================== // \title MathReceiver/test/ut/Tester.hpp -// \author tcanham +// \author tcanham, bocchino // \brief hpp file for MathReceiver test harness implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2021, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // @@ -14,7 +14,7 @@ #define TESTER_HPP #include "GTestBase.hpp" -#include "Ref/MathReceiver/MathReceiverComponentImpl.hpp" +#include "Ref/MathReceiver/MathReceiver.hpp" namespace Ref { @@ -22,12 +22,23 @@ namespace Ref { public MathReceiverGTestBase { + private: + // ---------------------------------------------------------------------- - // Construction and destruction + // Types // ---------------------------------------------------------------------- + enum class ThrottleState { + THROTTLED, + NOT_THROTTLED + }; + public: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + //! Construct object Tester //! Tester(); @@ -44,10 +55,10 @@ namespace Ref { //! To do //! - void testAddCommand(); - void testSubCommand(); - void testMultCommand(); - void testDivCommand(); + void testAdd(); + void testSub(); + void testMul(); + void testDiv(); void testThrottle(); private: @@ -56,11 +67,11 @@ namespace Ref { // Handlers for typed from ports // ---------------------------------------------------------------------- - //! Handler for from_mathOut + //! Handler for from_mathResultOut //! - void from_mathOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 result /*!< the result of the operation*/ + void from_mathResultOut_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + F32 result //!< the result of the operation ); private: @@ -69,6 +80,30 @@ namespace Ref { // Helper methods // ---------------------------------------------------------------------- + //! Pick an F32 value + static F32 pickF32Value(); + + //! Set the factor parameter + void setFactor( + F32 factor, //!< The parameter value + ThrottleState throttleState //!< The throttle state + ); + + //! Compute a result + F32 computeResult( + F32 val1, + MathOp op, + F32 val2, + F32 factor + ); + + //! Do a math operation + //! Factor parameter must be set + void doMathOp( + MathOp op, + F32 factor + ); + //! Connect ports //! void connectPorts(); @@ -85,7 +120,7 @@ namespace Ref { //! The component under test //! - MathReceiverComponentImpl component; + MathReceiver component; }; diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/TestMain.cpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/main.cpp similarity index 54% rename from docs/Tutorials/MathComponent/MathSender/test/ut/TestMain.cpp rename to docs/Tutorials/MathComponent/MathReceiver/test/ut/main.cpp index 039df54e45..8b840a94fa 100644 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/TestMain.cpp +++ b/docs/Tutorials/MathComponent/MathReceiver/test/ut/main.cpp @@ -1,30 +1,37 @@ // ---------------------------------------------------------------------- -// Main.cpp +// Main.cpp // ---------------------------------------------------------------------- +#include "STest/Random/Random.hpp" #include "Tester.hpp" -TEST(Nominal, AddOperationTest) { +TEST(Nominal, Add) { Ref::Tester tester; - tester.testAddCommand(); + tester.testAdd(); } -TEST(Nominal, SubOperationTest) { +TEST(Nominal, Sub) { Ref::Tester tester; - tester.testSubCommand(); + tester.testSub(); } -TEST(Nominal, MultOperationTest) { +TEST(Nominal, Mul) { Ref::Tester tester; - tester.testMultCommand(); + tester.testMul(); } -TEST(Nominal, DivideOperationTest) { +TEST(Nominal, Div) { Ref::Tester tester; - tester.testDivCommand(); + tester.testDiv(); +} + +TEST(Nominal, Throttle) { + Ref::Tester tester; + tester.testThrottle(); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); return RUN_ALL_TESTS(); } diff --git a/docs/Tutorials/MathComponent/MathSender/CMakeLists.txt b/docs/Tutorials/MathComponent/MathSender/CMakeLists.txt index 072349e8cc..5f3ff699f8 100644 --- a/docs/Tutorials/MathComponent/MathSender/CMakeLists.txt +++ b/docs/Tutorials/MathComponent/MathSender/CMakeLists.txt @@ -1,13 +1,15 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding files -# MOD_DEPS: (optional) module dependencies -# -#### +# Register the standard build set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathSenderComponentAi.xml" - "${CMAKE_CURRENT_LIST_DIR}/MathSenderComponentImpl.cpp" + "${CMAKE_CURRENT_LIST_DIR}/MathSender.cpp" + "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" ) - register_fprime_module() + +# Register the unit test build +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp" +) +set(UT_MOD_DEPS STest) +register_fprime_ut() diff --git a/docs/Tutorials/MathComponent/MathSender/MathSender.cpp b/docs/Tutorials/MathComponent/MathSender/MathSender.cpp new file mode 100644 index 0000000000..e74f498309 --- /dev/null +++ b/docs/Tutorials/MathComponent/MathSender/MathSender.cpp @@ -0,0 +1,81 @@ +// ====================================================================== +// \title MathSender.cpp +// \author tcanham, bocchino +// \brief cpp file for MathSender component implementation class +// +// \copyright +// Copyright 2009-2021, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + + +#include +#include "Fw/Types/BasicTypes.hpp" + +namespace Ref { + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + MathSender :: + MathSender( + const char *const compName + ) : MathSenderComponentBase(compName) + { + + } + + void MathSender :: + init( + const NATIVE_INT_TYPE queueDepth, + const NATIVE_INT_TYPE instance + ) + { + MathSenderComponentBase::init(queueDepth, instance); + } + + MathSender :: + ~MathSender() + { + + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + void MathSender :: + mathResultIn_handler( + const NATIVE_INT_TYPE portNum, + F32 result + ) + { + this->tlmWrite_RESULT(result); + this->log_ACTIVITY_HI_RESULT(result); + } + + // ---------------------------------------------------------------------- + // Command handler implementations + // ---------------------------------------------------------------------- + + void MathSender :: + DO_MATH_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + F32 val1, + MathOp op, + F32 val2 + ) + { + this->tlmWrite_VAL1(val1); + this->tlmWrite_OP(op); + this->tlmWrite_VAL2(val2); + this->log_ACTIVITY_LO_COMMAND_RECV(val1, op, val2); + this->mathOpOut_out(0, val1, op, val2); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + } + +} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathSender/MathSender.fpp b/docs/Tutorials/MathComponent/MathSender/MathSender.fpp new file mode 100644 index 0000000000..869f69f4c1 --- /dev/null +++ b/docs/Tutorials/MathComponent/MathSender/MathSender.fpp @@ -0,0 +1,90 @@ +module Ref { + + @ Component for sending a math operation + active component MathSender { + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Port for sending the operation request + output port mathOpOut: MathOp + + @ Port for receiving the result + async input port mathResultIn: MathResult + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + + @ Command receive port + command recv port cmdIn + + @ Command registration port + command reg port cmdRegOut + + @ Command response port + command resp port cmdResponseOut + + @ Event port + event port eventOut + + @ Telemetry port + telemetry port tlmOut + + @ Text event port + text event port textEventOut + + @ Time get port + time get port timeGetOut + + # ---------------------------------------------------------------------- + # Commands + # ---------------------------------------------------------------------- + + @ Do a math operation + async command DO_MATH( + val1: F32 @< The first operand + op: MathOp @< The operation + val2: F32 @< The second operand + ) + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + @ Math command received + event COMMAND_RECV( + val1: F32 @< The first operand + op: MathOp @< The operation + val2: F32 @< The second operand + ) \ + severity activity low \ + format "Math command received: {f} {} {f}" + + @ Received math result + event RESULT( + result: F32 @< The math result + ) \ + severity activity high \ + format "Math result is {f}" + + # ---------------------------------------------------------------------- + # Telemetry + # ---------------------------------------------------------------------- + + @ The first value + telemetry VAL1: F32 + + @ The operation + telemetry OP: MathOp + + @ The second value + telemetry VAL2: F32 + + @ The result + telemetry RESULT: F32 + + } + +} diff --git a/docs/Tutorials/MathComponent/MathSender/MathSenderComponentImpl.hpp b/docs/Tutorials/MathComponent/MathSender/MathSender.hpp similarity index 59% rename from docs/Tutorials/MathComponent/MathSender/MathSenderComponentImpl.hpp rename to docs/Tutorials/MathComponent/MathSender/MathSender.hpp index acd2d8c964..874818e0b5 100644 --- a/docs/Tutorials/MathComponent/MathSender/MathSenderComponentImpl.hpp +++ b/docs/Tutorials/MathComponent/MathSender/MathSender.hpp @@ -1,23 +1,23 @@ // ====================================================================== // \title MathSenderImpl.hpp -// \author tcanham +// \author tcanham, bocchino // \brief hpp file for MathSender component implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2021, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // // ====================================================================== -#ifndef MathSender_HPP -#define MathSender_HPP +#ifndef Ref_MathSender_HPP +#define Ref_MathSender_HPP #include "Ref/MathSender/MathSenderComponentAc.hpp" namespace Ref { - class MathSenderComponentImpl : + class MathSender : public MathSenderComponentBase { @@ -29,20 +29,20 @@ namespace Ref { //! Construct object MathSender //! - MathSenderComponentImpl( - const char *const compName /*!< The component name*/ + MathSender( + const char *const compName //!< The component name ); //! Initialize object MathSender //! void init( - const NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + const NATIVE_INT_TYPE queueDepth, //!< The queue depth + const NATIVE_INT_TYPE instance = 0 //!< The instance number ); //! Destroy object MathSender //! - ~MathSenderComponentImpl(); + ~MathSender(); PRIVATE: @@ -50,11 +50,11 @@ namespace Ref { // Handler implementations for user-defined typed input ports // ---------------------------------------------------------------------- - //! Handler implementation for mathIn + //! Handler implementation for mathResultIn //! - void mathIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 result /*!< the result of the operation*/ + void mathResultIn_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + F32 result //!< the result of the operation ); PRIVATE: @@ -63,17 +63,16 @@ namespace Ref { // Command handler implementations // ---------------------------------------------------------------------- - //! Implementation for MS_DO_MATH command handler + //! Implementation for DO_MATH command handler //! Do a math operation - void MS_DO_MATH_cmdHandler( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - F32 val1, /*!< The first value*/ - F32 val2, /*!< The second value*/ - MathOp operation /*!< The operation to perform*/ + void DO_MATH_cmdHandler( + const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number + F32 val1, //!< The first value + MathOp operation, //!< The operation to perform + F32 val2 //!< The second value ); - }; } // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathSender/MathSenderComponentAi.xml b/docs/Tutorials/MathComponent/MathSender/MathSenderComponentAi.xml deleted file mode 100644 index 2acd22a6a4..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/MathSenderComponentAi.xml +++ /dev/null @@ -1,103 +0,0 @@ - - Ref/MathPorts/MathOpPortAi.xml - Ref/MathPorts/MathResultPortAi.xml - Component sending a math operation - - - - Port for sending the math operation - - - - - Port for returning the math result - - - - - - - Do a math operation - - - - The first value - - - The second value - - - - - - - - - The operation to perform - - - - - - - - The first value - - - - - The second value - - - - - - - - - - - The operation - - - - - The result - - - - - - - Math command received - - - - The val1 argument - - - The val2 argument - - - The requested operation - - - - - - - - - - - - Received math result - - - - The math result - - - - - diff --git a/docs/Tutorials/MathComponent/MathSender/MathSenderComponentImpl.cpp b/docs/Tutorials/MathComponent/MathSender/MathSenderComponentImpl.cpp deleted file mode 100644 index 76dca607c8..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/MathSenderComponentImpl.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// ====================================================================== -// \title MathSenderImpl.cpp -// \author tcanham -// \brief cpp file for MathSender component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - - -#include -#include "Fw/Types/BasicTypes.hpp" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - MathSenderComponentImpl :: - MathSenderComponentImpl( - const char *const compName - ) : MathSenderComponentBase(compName) - { - - } - - void MathSenderComponentImpl :: - init( - const NATIVE_INT_TYPE queueDepth, - const NATIVE_INT_TYPE instance - ) - { - MathSenderComponentBase::init(queueDepth, instance); - } - - MathSenderComponentImpl :: - ~MathSenderComponentImpl() - { - - } - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - void MathSenderComponentImpl :: - mathIn_handler( - const NATIVE_INT_TYPE portNum, - F32 result - ) - { - this->tlmWrite_MS_RES(result); - this->log_ACTIVITY_HI_MS_RESULT(result); - } - - // ---------------------------------------------------------------------- - // Command handler implementations - // ---------------------------------------------------------------------- - - void MathSenderComponentImpl :: - MS_DO_MATH_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - F32 val1, - F32 val2, - MathOp operation - ) - { - MathOpTlm opTlm; - MathOperation opPort; - MathOpEv opEv; - switch (operation) { - case ADD: - opTlm = ADD_TLM; - opPort = MATH_ADD; - opEv = ADD_EV; - break; - case SUBTRACT: - opTlm = SUB_TLM; - opPort = MATH_SUB; - opEv = SUB_EV; - break; - case MULTIPLY: - opTlm = MULT_TLM; - opPort = MATH_MULTIPLY; - opEv = MULT_EV; - break; - case DIVIDE: - opTlm = DIV_TLM; - opPort = MATH_DIVIDE; - opEv = DIV_EV; - break; - default: - FW_ASSERT(0,operation); - break; - } - - this->tlmWrite_MS_OP(opTlm); - this->tlmWrite_MS_VAL1(val1); - this->tlmWrite_MS_VAL2(val2); - this->log_ACTIVITY_LO_MS_COMMAND_RECV(val1,val2,opEv); - this->mathOut_out(0,val1,val2,opPort); - // reply with completion status - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathSender/docs/MathSender.md b/docs/Tutorials/MathComponent/MathSender/docs/MathSender.md deleted file mode 100644 index 8e4422af4f..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/docs/MathSender.md +++ /dev/null @@ -1,32 +0,0 @@ -MathSender Component Dictionary -# MathSender Component Dictionary - - -## Command List - -|Mnemonic|ID|Description|Arg Name|Arg Type|Comment -|---|---|---|---|---|---| -|MS_DO_MATH|0 (0x0)|Do a math operation| | | -| | | |val1|F32|The first value| -| | | |val2|F32|The second value| -| | | |operation|MathOp|The operation to perform| - -## Telemetry Channel List - -|Channel Name|ID|Type|Description| -|---|---|---|---| -|MS_VAL1|0 (0x0)|F32|The first value| -|MS_VAL2|1 (0x1)|F32|The second value| -|MS_OP|2 (0x2)|MathOpTlm|The operation| -|MS_RES|3 (0x3)|F32|The result| - -## Event List - -|Event Name|ID|Description|Arg Name|Arg Type|Arg Size|Description -|---|---|---|---|---|---|---| -|MS_COMMAND_RECV|0 (0x0)|Math command received| | | | | -| | | |val1|F32||The val1 argument| -| | | |val2|F32||The val1 argument| -| | | |op|MathOpEv||The requested operation| -|MS_RESULT|1 (0x1)|Received math result| | | | | -| | | |result|F32||The math result| diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/GTestBase.cpp b/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/GTestBase.cpp deleted file mode 100644 index 90fe9cdea7..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/GTestBase.cpp +++ /dev/null @@ -1,513 +0,0 @@ -// ====================================================================== -// \title MathSender/test/ut/GTestBase.cpp -// \author Auto-generated -// \brief cpp file for MathSender component Google Test harness base class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include "GTestBase.hpp" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - MathSenderGTestBase :: - MathSenderGTestBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, - const U32 maxHistorySize -#else - const U32 maxHistorySize -#endif - ) : - MathSenderTesterBase ( -#if FW_OBJECT_NAMES == 1 - compName, -#endif - maxHistorySize - ) - { - - } - - MathSenderGTestBase :: - ~MathSenderGTestBase(void) - { - - } - - // ---------------------------------------------------------------------- - // Commands - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertCmdResponse_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ((unsigned long) size, this->cmdResponseHistory->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of command response history\n" - << " Expected: " << size << "\n" - << " Actual: " << this->cmdResponseHistory->size() << "\n"; - } - - void MathSenderGTestBase :: - assertCmdResponse( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const FwOpcodeType opCode, - const U32 cmdSeq, - const Fw::CommandResponse response - ) - const - { - ASSERT_LT(index, this->cmdResponseHistory->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into command response history\n" - << " Expected: Less than size of command response history (" - << this->cmdResponseHistory->size() << ")\n" - << " Actual: " << index << "\n"; - const CmdResponse& e = this->cmdResponseHistory->at(index); - ASSERT_EQ(opCode, e.opCode) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Opcode at index " - << index - << " in command response history\n" - << " Expected: " << opCode << "\n" - << " Actual: " << e.opCode << "\n"; - ASSERT_EQ(cmdSeq, e.cmdSeq) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Command sequence number at index " - << index - << " in command response history\n" - << " Expected: " << cmdSeq << "\n" - << " Actual: " << e.cmdSeq << "\n"; - ASSERT_EQ(response, e.response) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Command response at index " - << index - << " in command response history\n" - << " Expected: " << response << "\n" - << " Actual: " << e.response << "\n"; - } - - // ---------------------------------------------------------------------- - // Telemetry - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertTlm_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->tlmSize) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Total size of all telemetry histories\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmSize << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MS_VAL1 - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertTlm_MS_VAL1_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MS_VAL1->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MS_VAL1\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MS_VAL1->size() << "\n"; - } - - void MathSenderGTestBase :: - assertTlm_MS_VAL1( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MS_VAL1->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MS_VAL1\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MS_VAL1->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MS_VAL1& e = - this->tlmHistory_MS_VAL1->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MS_VAL1\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MS_VAL2 - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertTlm_MS_VAL2_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MS_VAL2->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MS_VAL2\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MS_VAL2->size() << "\n"; - } - - void MathSenderGTestBase :: - assertTlm_MS_VAL2( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MS_VAL2->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MS_VAL2\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MS_VAL2->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MS_VAL2& e = - this->tlmHistory_MS_VAL2->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MS_VAL2\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MS_OP - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertTlm_MS_OP_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MS_OP->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MS_OP\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MS_OP->size() << "\n"; - } - - void MathSenderGTestBase :: - assertTlm_MS_OP( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const MathSenderComponentBase::MathOpTlm& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MS_OP->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MS_OP\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MS_OP->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MS_OP& e = - this->tlmHistory_MS_OP->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MS_OP\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Channel: MS_RES - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertTlm_MS_RES_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(this->tlmHistory_MS_RES->size(), size) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for telemetry channel MS_RES\n" - << " Expected: " << size << "\n" - << " Actual: " << this->tlmHistory_MS_RES->size() << "\n"; - } - - void MathSenderGTestBase :: - assertTlm_MS_RES( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32& val - ) - const - { - ASSERT_LT(index, this->tlmHistory_MS_RES->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of telemetry channel MS_RES\n" - << " Expected: Less than size of history (" - << this->tlmHistory_MS_RES->size() << ")\n" - << " Actual: " << index << "\n"; - const TlmEntry_MS_RES& e = - this->tlmHistory_MS_RES->at(index); - ASSERT_EQ(val, e.arg) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value at index " - << index - << " on telemetry channel MS_RES\n" - << " Expected: " << val << "\n" - << " Actual: " << e.arg << "\n"; - } - - // ---------------------------------------------------------------------- - // Events - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertEvents_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventsSize) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Total size of all event histories\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventsSize << "\n"; - } - - // ---------------------------------------------------------------------- - // Event: MS_COMMAND_RECV - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertEvents_MS_COMMAND_RECV_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventHistory_MS_COMMAND_RECV->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for event MS_COMMAND_RECV\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventHistory_MS_COMMAND_RECV->size() << "\n"; - } - - void MathSenderGTestBase :: - assertEvents_MS_COMMAND_RECV( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32 val1, - const F32 val2, - MathSenderComponentBase::MathOpEv op - ) const - { - ASSERT_GT(this->eventHistory_MS_COMMAND_RECV->size(), index) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of event MS_COMMAND_RECV\n" - << " Expected: Less than size of history (" - << this->eventHistory_MS_COMMAND_RECV->size() << ")\n" - << " Actual: " << index << "\n"; - const EventEntry_MS_COMMAND_RECV& e = - this->eventHistory_MS_COMMAND_RECV->at(index); - ASSERT_EQ(val1, e.val1) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value of argument val1 at index " - << index - << " in history of event MS_COMMAND_RECV\n" - << " Expected: " << val1 << "\n" - << " Actual: " << e.val1 << "\n"; - ASSERT_EQ(val2, e.val2) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value of argument val2 at index " - << index - << " in history of event MS_COMMAND_RECV\n" - << " Expected: " << val2 << "\n" - << " Actual: " << e.val2 << "\n"; - ASSERT_EQ(op, e.op) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value of argument op at index " - << index - << " in history of event MS_COMMAND_RECV\n" - << " Expected: " << op << "\n" - << " Actual: " << e.op << "\n"; - } - - // ---------------------------------------------------------------------- - // Event: MS_RESULT - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertEvents_MS_RESULT_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->eventHistory_MS_RESULT->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for event MS_RESULT\n" - << " Expected: " << size << "\n" - << " Actual: " << this->eventHistory_MS_RESULT->size() << "\n"; - } - - void MathSenderGTestBase :: - assertEvents_MS_RESULT( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 index, - const F32 result - ) const - { - ASSERT_GT(this->eventHistory_MS_RESULT->size(), index) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Index into history of event MS_RESULT\n" - << " Expected: Less than size of history (" - << this->eventHistory_MS_RESULT->size() << ")\n" - << " Actual: " << index << "\n"; - const EventEntry_MS_RESULT& e = - this->eventHistory_MS_RESULT->at(index); - ASSERT_EQ(result, e.result) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Value of argument result at index " - << index - << " in history of event MS_RESULT\n" - << " Expected: " << result << "\n" - << " Actual: " << e.result << "\n"; - } - - // ---------------------------------------------------------------------- - // From ports - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assertFromPortHistory_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->fromPortHistorySize) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Total size of all from port histories\n" - << " Expected: " << size << "\n" - << " Actual: " << this->fromPortHistorySize << "\n"; - } - - // ---------------------------------------------------------------------- - // From port: mathOut - // ---------------------------------------------------------------------- - - void MathSenderGTestBase :: - assert_from_mathOut_size( - const char *const __callSiteFileName, - const U32 __callSiteLineNumber, - const U32 size - ) const - { - ASSERT_EQ(size, this->fromPortHistory_mathOut->size()) - << "\n" - << " File: " << __callSiteFileName << "\n" - << " Line: " << __callSiteLineNumber << "\n" - << " Value: Size of history for from_mathOut\n" - << " Expected: " << size << "\n" - << " Actual: " << this->fromPortHistory_mathOut->size() << "\n"; - } - -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/GTestBase.hpp b/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/GTestBase.hpp deleted file mode 100644 index 2460198e73..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/GTestBase.hpp +++ /dev/null @@ -1,363 +0,0 @@ -// ====================================================================== -// \title MathSender/test/ut/GTestBase.hpp -// \author Auto-generated -// \brief hpp file for MathSender component Google Test harness base class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef MathSender_GTEST_BASE_HPP -#define MathSender_GTEST_BASE_HPP - -#include "TesterBase.hpp" -#include "gtest/gtest.h" - -// ---------------------------------------------------------------------- -// Macros for command history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_CMD_RESPONSE_SIZE(size) \ - this->assertCmdResponse_size(__FILE__, __LINE__, size) - -#define ASSERT_CMD_RESPONSE(index, opCode, cmdSeq, response) \ - this->assertCmdResponse(__FILE__, __LINE__, index, opCode, cmdSeq, response) - -// ---------------------------------------------------------------------- -// Macros for telemetry history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_TLM_SIZE(size) \ - this->assertTlm_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MS_VAL1_SIZE(size) \ - this->assertTlm_MS_VAL1_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MS_VAL1(index, value) \ - this->assertTlm_MS_VAL1(__FILE__, __LINE__, index, value) - -#define ASSERT_TLM_MS_VAL2_SIZE(size) \ - this->assertTlm_MS_VAL2_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MS_VAL2(index, value) \ - this->assertTlm_MS_VAL2(__FILE__, __LINE__, index, value) - -#define ASSERT_TLM_MS_OP_SIZE(size) \ - this->assertTlm_MS_OP_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MS_OP(index, value) \ - this->assertTlm_MS_OP(__FILE__, __LINE__, index, value) - -#define ASSERT_TLM_MS_RES_SIZE(size) \ - this->assertTlm_MS_RES_size(__FILE__, __LINE__, size) - -#define ASSERT_TLM_MS_RES(index, value) \ - this->assertTlm_MS_RES(__FILE__, __LINE__, index, value) - -// ---------------------------------------------------------------------- -// Macros for event history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_EVENTS_SIZE(size) \ - this->assertEvents_size(__FILE__, __LINE__, size) - -#define ASSERT_EVENTS_MS_COMMAND_RECV_SIZE(size) \ - this->assertEvents_MS_COMMAND_RECV_size(__FILE__, __LINE__, size) - -#define ASSERT_EVENTS_MS_COMMAND_RECV(index, _val1, _val2, _op) \ - this->assertEvents_MS_COMMAND_RECV(__FILE__, __LINE__, index, _val1, _val2, _op) - -#define ASSERT_EVENTS_MS_RESULT_SIZE(size) \ - this->assertEvents_MS_RESULT_size(__FILE__, __LINE__, size) - -#define ASSERT_EVENTS_MS_RESULT(index, _result) \ - this->assertEvents_MS_RESULT(__FILE__, __LINE__, index, _result) - -// ---------------------------------------------------------------------- -// Macros for typed user from port history assertions -// ---------------------------------------------------------------------- - -#define ASSERT_FROM_PORT_HISTORY_SIZE(size) \ - this->assertFromPortHistory_size(__FILE__, __LINE__, size) - -#define ASSERT_from_mathOut_SIZE(size) \ - this->assert_from_mathOut_size(__FILE__, __LINE__, size) - -#define ASSERT_from_mathOut(index, _val1, _val2, _operation) \ - { \ - ASSERT_GT(this->fromPortHistory_mathOut->size(), static_cast(index)) \ - << "\n" \ - << " File: " << __FILE__ << "\n" \ - << " Line: " << __LINE__ << "\n" \ - << " Value: Index into history of from_mathOut\n" \ - << " Expected: Less than size of history (" \ - << this->fromPortHistory_mathOut->size() << ")\n" \ - << " Actual: " << index << "\n"; \ - const FromPortEntry_mathOut& _e = \ - this->fromPortHistory_mathOut->at(index); \ - ASSERT_EQ(_val1, _e.val1) \ - << "\n" \ - << " File: " << __FILE__ << "\n" \ - << " Line: " << __LINE__ << "\n" \ - << " Value: Value of argument val1 at index " \ - << index \ - << " in history of from_mathOut\n" \ - << " Expected: " << _val1 << "\n" \ - << " Actual: " << _e.val1 << "\n"; \ - ASSERT_EQ(_val2, _e.val2) \ - << "\n" \ - << " File: " << __FILE__ << "\n" \ - << " Line: " << __LINE__ << "\n" \ - << " Value: Value of argument val2 at index " \ - << index \ - << " in history of from_mathOut\n" \ - << " Expected: " << _val2 << "\n" \ - << " Actual: " << _e.val2 << "\n"; \ - ASSERT_EQ(_operation, _e.operation) \ - << "\n" \ - << " File: " << __FILE__ << "\n" \ - << " Line: " << __LINE__ << "\n" \ - << " Value: Value of argument operation at index " \ - << index \ - << " in history of from_mathOut\n" \ - << " Expected: " << _operation << "\n" \ - << " Actual: " << _e.operation << "\n"; \ - } - -namespace Ref { - - //! \class MathSenderGTestBase - //! \brief Auto-generated base class for MathSender component Google Test harness - //! - class MathSenderGTestBase : - public MathSenderTesterBase - { - - protected: - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - //! Construct object MathSenderGTestBase - //! - MathSenderGTestBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, /*!< The component name*/ - const U32 maxHistorySize /*!< The maximum size of each history*/ -#else - const U32 maxHistorySize /*!< The maximum size of each history*/ -#endif - ); - - //! Destroy object MathSenderGTestBase - //! - virtual ~MathSenderGTestBase(void); - - protected: - - // ---------------------------------------------------------------------- - // Commands - // ---------------------------------------------------------------------- - - //! Assert size of command response history - //! - void assertCmdResponse_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - //! Assert command response in history at index - //! - void assertCmdResponse( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - const Fw::CommandResponse response /*!< The command response*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Telemetry - // ---------------------------------------------------------------------- - - //! Assert size of telemetry history - //! - void assertTlm_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_VAL1 - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MS_VAL1_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MS_VAL1( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_VAL2 - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MS_VAL2_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MS_VAL2( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_OP - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MS_OP_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MS_OP( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const MathSenderComponentBase::MathOpTlm& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_RES - // ---------------------------------------------------------------------- - - //! Assert telemetry value in history at index - //! - void assertTlm_MS_RES_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertTlm_MS_RES( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32& val /*!< The channel value*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Events - // ---------------------------------------------------------------------- - - void assertEvents_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Event: MS_COMMAND_RECV - // ---------------------------------------------------------------------- - - void assertEvents_MS_COMMAND_RECV_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertEvents_MS_COMMAND_RECV( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32 val1, /*!< The val1 argument*/ - const F32 val2, /*!< The val1 argument*/ - MathSenderComponentBase::MathOpEv op /*!< The requested operation*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // Event: MS_RESULT - // ---------------------------------------------------------------------- - - void assertEvents_MS_RESULT_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - void assertEvents_MS_RESULT( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 index, /*!< The index*/ - const F32 result /*!< The math result*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // From ports - // ---------------------------------------------------------------------- - - void assertFromPortHistory_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - protected: - - // ---------------------------------------------------------------------- - // From port: mathOut - // ---------------------------------------------------------------------- - - void assert_from_mathOut_size( - const char *const __callSiteFileName, /*!< The name of the file containing the call site*/ - const U32 __callSiteLineNumber, /*!< The line number of the call site*/ - const U32 size /*!< The asserted size*/ - ) const; - - }; - -} // end namespace Ref - -#endif diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/TesterBase.cpp b/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/TesterBase.cpp deleted file mode 100644 index a26de4c3e4..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/TesterBase.cpp +++ /dev/null @@ -1,1168 +0,0 @@ -// ====================================================================== -// \title MathSender/test/ut/TesterBase.cpp -// \author Auto-generated -// \brief cpp file for MathSender component test harness base class -// -// \copyright -// Copyright 2009-2016, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include -#include -#include "TesterBase.hpp" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - MathSenderTesterBase :: - MathSenderTesterBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, - const U32 maxHistorySize -#else - const U32 maxHistorySize -#endif - ) : -#if FW_OBJECT_NAMES == 1 - Fw::PassiveComponentBase(compName) -#else - Fw::PassiveComponentBase() -#endif - { - // Initialize command history - this->cmdResponseHistory = new History(maxHistorySize); - // Initialize telemetry histories - this->tlmHistory_MS_VAL1 = - new History(maxHistorySize); - this->tlmHistory_MS_VAL2 = - new History(maxHistorySize); - this->tlmHistory_MS_OP = - new History(maxHistorySize); - this->tlmHistory_MS_RES = - new History(maxHistorySize); - // Initialize event histories -#if FW_ENABLE_TEXT_LOGGING - this->textLogHistory = new History(maxHistorySize); -#endif - this->eventHistory_MS_COMMAND_RECV = - new History(maxHistorySize); - this->eventHistory_MS_RESULT = - new History(maxHistorySize); - // Initialize histories for typed user output ports - this->fromPortHistory_mathOut = - new History(maxHistorySize); - // Clear history - this->clearHistory(); - } - - MathSenderTesterBase :: - ~MathSenderTesterBase(void) - { - // Destroy command history - delete this->cmdResponseHistory; - // Destroy telemetry histories - delete this->tlmHistory_MS_VAL1; - delete this->tlmHistory_MS_VAL2; - delete this->tlmHistory_MS_OP; - delete this->tlmHistory_MS_RES; - // Destroy event histories -#if FW_ENABLE_TEXT_LOGGING - delete this->textLogHistory; -#endif - delete this->eventHistory_MS_COMMAND_RECV; - delete this->eventHistory_MS_RESULT; - } - - void MathSenderTesterBase :: - init( - const NATIVE_INT_TYPE instance - ) - { - - // Initialize base class - - Fw::PassiveComponentBase::init(instance); - - // Attach input port mathOut - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_mathOut(); - ++_port - ) { - - this->m_from_mathOut[_port].init(); - this->m_from_mathOut[_port].addCallComp( - this, - from_mathOut_static - ); - this->m_from_mathOut[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_mathOut[%d]", - this->m_objName, - _port - ); - this->m_from_mathOut[_port].setObjName(_portName); -#endif - - } - - // Attach input port CmdStatus - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_CmdStatus(); - ++_port - ) { - - this->m_from_CmdStatus[_port].init(); - this->m_from_CmdStatus[_port].addCallComp( - this, - from_CmdStatus_static - ); - this->m_from_CmdStatus[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_CmdStatus[%d]", - this->m_objName, - _port - ); - this->m_from_CmdStatus[_port].setObjName(_portName); -#endif - - } - - // Attach input port CmdReg - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_CmdReg(); - ++_port - ) { - - this->m_from_CmdReg[_port].init(); - this->m_from_CmdReg[_port].addCallComp( - this, - from_CmdReg_static - ); - this->m_from_CmdReg[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_CmdReg[%d]", - this->m_objName, - _port - ); - this->m_from_CmdReg[_port].setObjName(_portName); -#endif - - } - - // Attach input port Tlm - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_Tlm(); - ++_port - ) { - - this->m_from_Tlm[_port].init(); - this->m_from_Tlm[_port].addCallComp( - this, - from_Tlm_static - ); - this->m_from_Tlm[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_Tlm[%d]", - this->m_objName, - _port - ); - this->m_from_Tlm[_port].setObjName(_portName); -#endif - - } - - // Attach input port Time - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_Time(); - ++_port - ) { - - this->m_from_Time[_port].init(); - this->m_from_Time[_port].addCallComp( - this, - from_Time_static - ); - this->m_from_Time[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_Time[%d]", - this->m_objName, - _port - ); - this->m_from_Time[_port].setObjName(_portName); -#endif - - } - - // Attach input port Log - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_Log(); - ++_port - ) { - - this->m_from_Log[_port].init(); - this->m_from_Log[_port].addCallComp( - this, - from_Log_static - ); - this->m_from_Log[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_Log[%d]", - this->m_objName, - _port - ); - this->m_from_Log[_port].setObjName(_portName); -#endif - - } - - // Attach input port LogText - -#if FW_ENABLE_TEXT_LOGGING == 1 - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_LogText(); - ++_port - ) { - - this->m_from_LogText[_port].init(); - this->m_from_LogText[_port].addCallComp( - this, - from_LogText_static - ); - this->m_from_LogText[_port].setPortNum(_port); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - (void) snprintf( - _portName, - sizeof(_portName), - "%s_from_LogText[%d]", - this->m_objName, - _port - ); - this->m_from_LogText[_port].setObjName(_portName); -#endif - - } -#endif - - // Initialize output port mathIn - - for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_to_mathIn(); - ++_port - ) { - this->m_to_mathIn[_port].init(); - -#if FW_OBJECT_NAMES == 1 - char _portName[80]; - snprintf( - _portName, - sizeof(_portName), - "%s_to_mathIn[%d]", - this->m_objName, - _port - ); - this->m_to_mathIn[_port].setObjName(_portName); -#endif - - } - - } - - // ---------------------------------------------------------------------- - // Getters for port counts - // ---------------------------------------------------------------------- - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_from_mathOut(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_mathOut); - } - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_to_mathIn(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_to_mathIn); - } - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_to_CmdDisp(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_to_CmdDisp); - } - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_from_CmdStatus(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_CmdStatus); - } - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_from_CmdReg(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_CmdReg); - } - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_from_Tlm(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_Tlm); - } - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_from_Time(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_Time); - } - - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_from_Log(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_Log); - } - -#if FW_ENABLE_TEXT_LOGGING == 1 - NATIVE_INT_TYPE MathSenderTesterBase :: - getNum_from_LogText(void) const - { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_from_LogText); - } -#endif - - // ---------------------------------------------------------------------- - // Connectors for to ports - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - connect_to_mathIn( - const NATIVE_INT_TYPE portNum, - Ref::InputMathResultPort *const mathIn - ) - { - FW_ASSERT(portNum < this->getNum_to_mathIn(),static_cast(portNum)); - this->m_to_mathIn[portNum].addCallPort(mathIn); - } - - void MathSenderTesterBase :: - connect_to_CmdDisp( - const NATIVE_INT_TYPE portNum, - Fw::InputCmdPort *const CmdDisp - ) - { - FW_ASSERT(portNum < this->getNum_to_CmdDisp(),static_cast(portNum)); - this->m_to_CmdDisp[portNum].addCallPort(CmdDisp); - } - - - // ---------------------------------------------------------------------- - // Invocation functions for to ports - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - invoke_to_mathIn( - const NATIVE_INT_TYPE portNum, - F32 result - ) - { - FW_ASSERT(portNum < this->getNum_to_mathIn(),static_cast(portNum)); - FW_ASSERT(portNum < this->getNum_to_mathIn(),static_cast(portNum)); - this->m_to_mathIn[portNum].invoke( - result - ); - } - - // ---------------------------------------------------------------------- - // Connection status for to ports - // ---------------------------------------------------------------------- - - bool MathSenderTesterBase :: - isConnected_to_mathIn(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_to_mathIn(), static_cast(portNum)); - return this->m_to_mathIn[portNum].isConnected(); - } - - bool MathSenderTesterBase :: - isConnected_to_CmdDisp(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_to_CmdDisp(), static_cast(portNum)); - return this->m_to_CmdDisp[portNum].isConnected(); - } - - // ---------------------------------------------------------------------- - // Getters for from ports - // ---------------------------------------------------------------------- - - Ref::InputMathOpPort *MathSenderTesterBase :: - get_from_mathOut(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_mathOut(),static_cast(portNum)); - return &this->m_from_mathOut[portNum]; - } - - Fw::InputCmdResponsePort *MathSenderTesterBase :: - get_from_CmdStatus(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_CmdStatus(),static_cast(portNum)); - return &this->m_from_CmdStatus[portNum]; - } - - Fw::InputCmdRegPort *MathSenderTesterBase :: - get_from_CmdReg(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_CmdReg(),static_cast(portNum)); - return &this->m_from_CmdReg[portNum]; - } - - Fw::InputTlmPort *MathSenderTesterBase :: - get_from_Tlm(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_Tlm(),static_cast(portNum)); - return &this->m_from_Tlm[portNum]; - } - - Fw::InputTimePort *MathSenderTesterBase :: - get_from_Time(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_Time(),static_cast(portNum)); - return &this->m_from_Time[portNum]; - } - - Fw::InputLogPort *MathSenderTesterBase :: - get_from_Log(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_Log(),static_cast(portNum)); - return &this->m_from_Log[portNum]; - } - -#if FW_ENABLE_TEXT_LOGGING == 1 - Fw::InputLogTextPort *MathSenderTesterBase :: - get_from_LogText(const NATIVE_INT_TYPE portNum) - { - FW_ASSERT(portNum < this->getNum_from_LogText(),static_cast(portNum)); - return &this->m_from_LogText[portNum]; - } -#endif - - // ---------------------------------------------------------------------- - // Static functions for from ports - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - from_mathOut_static( - Fw::PassiveComponentBase *const callComp, - const NATIVE_INT_TYPE portNum, - F32 val1, - F32 val2, - MathOperation operation - ) - { - FW_ASSERT(callComp); - MathSenderTesterBase* _testerBase = - static_cast(callComp); - _testerBase->from_mathOut_handlerBase( - portNum, - val1, val2, operation - ); - } - - void MathSenderTesterBase :: - from_CmdStatus_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - const FwOpcodeType opCode, - const U32 cmdSeq, - const Fw::CommandResponse response - ) - { - MathSenderTesterBase* _testerBase = - static_cast(component); - _testerBase->cmdResponseIn(opCode, cmdSeq, response); - } - - void MathSenderTesterBase :: - from_CmdReg_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - const FwOpcodeType opCode - ) - { - - } - - void MathSenderTesterBase :: - from_Tlm_static( - Fw::PassiveComponentBase *const component, - NATIVE_INT_TYPE portNum, - FwChanIdType id, - Fw::Time &timeTag, - Fw::TlmBuffer &val - ) - { - MathSenderTesterBase* _testerBase = - static_cast(component); - _testerBase->dispatchTlm(id, timeTag, val); - } - - void MathSenderTesterBase :: - from_Log_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - FwEventIdType id, - Fw::Time &timeTag, - Fw::LogSeverity severity, - Fw::LogBuffer &args - ) - { - MathSenderTesterBase* _testerBase = - static_cast(component); - _testerBase->dispatchEvents(id, timeTag, severity, args); - } - -#if FW_ENABLE_TEXT_LOGGING == 1 - void MathSenderTesterBase :: - from_LogText_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - FwEventIdType id, - Fw::Time &timeTag, - Fw::TextLogSeverity severity, - Fw::TextLogString &text - ) - { - MathSenderTesterBase* _testerBase = - static_cast(component); - _testerBase->textLogIn(id,timeTag,severity,text); - } -#endif - - void MathSenderTesterBase :: - from_Time_static( - Fw::PassiveComponentBase *const component, - const NATIVE_INT_TYPE portNum, - Fw::Time& time - ) - { - MathSenderTesterBase* _testerBase = - static_cast(component); - time = _testerBase->m_testTime; - } - - // ---------------------------------------------------------------------- - // Histories for typed from ports - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - clearFromPortHistory(void) - { - this->fromPortHistorySize = 0; - this->fromPortHistory_mathOut->clear(); - } - - // ---------------------------------------------------------------------- - // From port: mathOut - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - pushFromPortEntry_mathOut( - F32 val1, - F32 val2, - MathOperation operation - ) - { - FromPortEntry_mathOut _e = { - val1, val2, operation - }; - this->fromPortHistory_mathOut->push_back(_e); - ++this->fromPortHistorySize; - } - - // ---------------------------------------------------------------------- - // Handler base functions for from ports - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - from_mathOut_handlerBase( - const NATIVE_INT_TYPE portNum, - F32 val1, - F32 val2, - MathOperation operation - ) - { - FW_ASSERT(portNum < this->getNum_from_mathOut(),static_cast(portNum)); - this->from_mathOut_handler( - portNum, - val1, val2, operation - ); - } - - // ---------------------------------------------------------------------- - // Command response handling - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - cmdResponseIn( - const FwOpcodeType opCode, - const U32 seq, - const Fw::CommandResponse response - ) - { - CmdResponse e = { opCode, seq, response }; - this->cmdResponseHistory->push_back(e); - } - - // ---------------------------------------------------------------------- - // Command: MS_DO_MATH - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - sendCmd_MS_DO_MATH( - const NATIVE_INT_TYPE instance, - const U32 cmdSeq, - F32 val1, - F32 val2, - MathSenderComponentBase::MathOp operation - ) - { - - // Serialize arguments - - Fw::CmdArgBuffer buff; - Fw::SerializeStatus _status; - _status = buff.serialize(val1); - FW_ASSERT(_status == Fw::FW_SERIALIZE_OK,static_cast(_status)); - _status = buff.serialize(val2); - FW_ASSERT(_status == Fw::FW_SERIALIZE_OK,static_cast(_status)); - _status = buff.serialize((FwEnumStoreType) operation); - FW_ASSERT(_status == Fw::FW_SERIALIZE_OK,static_cast(_status)); - - // Call output command port - - FwOpcodeType _opcode; - const U32 idBase = this->getIdBase(); - _opcode = MathSenderComponentBase::OPCODE_MS_DO_MATH + idBase; - - if (this->m_to_CmdDisp[0].isConnected()) { - this->m_to_CmdDisp[0].invoke( - _opcode, - cmdSeq, - buff - ); - } - else { - printf("Test Command Output port not connected!\n"); - } - - } - - - void MathSenderTesterBase :: - sendRawCmd(FwOpcodeType opcode, U32 cmdSeq, Fw::CmdArgBuffer& args) { - - const U32 idBase = this->getIdBase(); - FwOpcodeType _opcode = opcode + idBase; - if (this->m_to_CmdDisp[0].isConnected()) { - this->m_to_CmdDisp[0].invoke( - _opcode, - cmdSeq, - args - ); - } - else { - printf("Test Command Output port not connected!\n"); - } - - } - - // ---------------------------------------------------------------------- - // History - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - clearHistory() - { - this->cmdResponseHistory->clear(); - this->clearTlm(); - this->textLogHistory->clear(); - this->clearEvents(); - this->clearFromPortHistory(); - } - - // ---------------------------------------------------------------------- - // Time - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - setTestTime(const Fw::Time& time) - { - this->m_testTime = time; - } - - // ---------------------------------------------------------------------- - // Telemetry dispatch - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - dispatchTlm( - const FwChanIdType id, - const Fw::Time &timeTag, - Fw::TlmBuffer &val - ) - { - - val.resetDeser(); - - const U32 idBase = this->getIdBase(); - FW_ASSERT(id >= idBase, id, idBase); - - switch (id - idBase) { - - case MathSenderComponentBase::CHANNELID_MS_VAL1: - { - F32 arg; - const Fw::SerializeStatus _status = val.deserialize(arg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MS_VAL1: %d\n", _status); - return; - } - this->tlmInput_MS_VAL1(timeTag, arg); - break; - } - - case MathSenderComponentBase::CHANNELID_MS_VAL2: - { - F32 arg; - const Fw::SerializeStatus _status = val.deserialize(arg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MS_VAL2: %d\n", _status); - return; - } - this->tlmInput_MS_VAL2(timeTag, arg); - break; - } - - case MathSenderComponentBase::CHANNELID_MS_OP: - { - FwEnumStoreType MS_OParg; - const Fw::SerializeStatus _status = val.deserialize(MS_OParg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MS_OP: %d\n", _status); - return; - } - MathSenderComponentBase::MathOpTlm arg = - static_cast(MS_OParg); - this->tlmInput_MS_OP(timeTag, arg); - break; - } - - case MathSenderComponentBase::CHANNELID_MS_RES: - { - F32 arg; - const Fw::SerializeStatus _status = val.deserialize(arg); - if (_status != Fw::FW_SERIALIZE_OK) { - printf("Error deserializing MS_RES: %d\n", _status); - return; - } - this->tlmInput_MS_RES(timeTag, arg); - break; - } - - default: { - FW_ASSERT(0, id); - break; - } - - } - - } - - void MathSenderTesterBase :: - clearTlm(void) - { - this->tlmSize = 0; - this->tlmHistory_MS_VAL1->clear(); - this->tlmHistory_MS_VAL2->clear(); - this->tlmHistory_MS_OP->clear(); - this->tlmHistory_MS_RES->clear(); - } - - // ---------------------------------------------------------------------- - // Channel: MS_VAL1 - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - tlmInput_MS_VAL1( - const Fw::Time& timeTag, - const F32& val - ) - { - TlmEntry_MS_VAL1 e = { timeTag, val }; - this->tlmHistory_MS_VAL1->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Channel: MS_VAL2 - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - tlmInput_MS_VAL2( - const Fw::Time& timeTag, - const F32& val - ) - { - TlmEntry_MS_VAL2 e = { timeTag, val }; - this->tlmHistory_MS_VAL2->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Channel: MS_OP - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - tlmInput_MS_OP( - const Fw::Time& timeTag, - const MathSenderComponentBase::MathOpTlm& val - ) - { - TlmEntry_MS_OP e = { timeTag, val }; - this->tlmHistory_MS_OP->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Channel: MS_RES - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - tlmInput_MS_RES( - const Fw::Time& timeTag, - const F32& val - ) - { - TlmEntry_MS_RES e = { timeTag, val }; - this->tlmHistory_MS_RES->push_back(e); - ++this->tlmSize; - } - - // ---------------------------------------------------------------------- - // Event dispatch - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - dispatchEvents( - const FwEventIdType id, - Fw::Time &timeTag, - const Fw::LogSeverity severity, - Fw::LogBuffer &args - ) - { - - args.resetDeser(); - - const U32 idBase = this->getIdBase(); - FW_ASSERT(id >= idBase, id, idBase); - switch (id - idBase) { - - case MathSenderComponentBase::EVENTID_MS_COMMAND_RECV: - { - - Fw::SerializeStatus _status = Fw::FW_SERIALIZE_OK; -#if FW_AMPCS_COMPATIBLE - // Deserialize the number of arguments. - U8 _numArgs; - _status = args.deserialize(_numArgs); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - // verify they match expected. - FW_ASSERT(_numArgs == 3,_numArgs,3); - -#endif - F32 val1; -#if FW_AMPCS_COMPATIBLE - { - // Deserialize the argument size - U8 _argSize; - _status = args.deserialize(_argSize); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT(_argSize == sizeof(F32),_argSize,sizeof(F32)); - } -#endif - _status = args.deserialize(val1); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - - F32 val2; -#if FW_AMPCS_COMPATIBLE - { - // Deserialize the argument size - U8 _argSize; - _status = args.deserialize(_argSize); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT(_argSize == sizeof(F32),_argSize,sizeof(F32)); - } -#endif - _status = args.deserialize(val2); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - -#if FW_AMPCS_COMPATIBLE - { - // Deserialize the argument size - U8 _argSize; - _status = args.deserialize(_argSize); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT(_argSize == sizeof(FwEnumStoreType),_argSize,sizeof(FwEnumStoreType)); - } -#endif - FwEnumStoreType opInt; - _status = args.deserialize(opInt); - MathSenderComponentBase::MathOpEv op = static_cast(opInt); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - - this->logIn_ACTIVITY_LO_MS_COMMAND_RECV(val1, val2, op); - - break; - - } - - case MathSenderComponentBase::EVENTID_MS_RESULT: - { - - Fw::SerializeStatus _status = Fw::FW_SERIALIZE_OK; -#if FW_AMPCS_COMPATIBLE - // Deserialize the number of arguments. - U8 _numArgs; - _status = args.deserialize(_numArgs); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - // verify they match expected. - FW_ASSERT(_numArgs == 1,_numArgs,1); - -#endif - F32 result; -#if FW_AMPCS_COMPATIBLE - { - // Deserialize the argument size - U8 _argSize; - _status = args.deserialize(_argSize); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - FW_ASSERT(_argSize == sizeof(F32),_argSize,sizeof(F32)); - } -#endif - _status = args.deserialize(result); - FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) - ); - - this->logIn_ACTIVITY_HI_MS_RESULT(result); - - break; - - } - - default: { - FW_ASSERT(0, id); - break; - } - - } - - } - - void MathSenderTesterBase :: - clearEvents(void) - { - this->eventsSize = 0; - this->eventHistory_MS_COMMAND_RECV->clear(); - this->eventHistory_MS_RESULT->clear(); - } - -#if FW_ENABLE_TEXT_LOGGING - - // ---------------------------------------------------------------------- - // Text events - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - textLogIn( - const U32 id, - Fw::Time &timeTag, - const Fw::TextLogSeverity severity, - const Fw::TextLogString &text - ) - { - TextLogEntry e = { id, timeTag, severity, text }; - textLogHistory->push_back(e); - } - - void MathSenderTesterBase :: - printTextLogHistoryEntry( - const TextLogEntry& e, - FILE* file - ) - { - const char *severityString = "UNKNOWN"; - switch (e.severity) { - case Fw::LOG_FATAL: - severityString = "FATAL"; - break; - case Fw::LOG_WARNING_HI: - severityString = "WARNING_HI"; - break; - case Fw::LOG_WARNING_LO: - severityString = "WARNING_LO"; - break; - case Fw::LOG_COMMAND: - severityString = "COMMAND"; - break; - case Fw::LOG_ACTIVITY_HI: - severityString = "ACTIVITY_HI"; - break; - case Fw::LOG_ACTIVITY_LO: - severityString = "ACTIVITY_LO"; - break; - case Fw::LOG_DIAGNOSTIC: - severityString = "DIAGNOSTIC"; - break; - default: - severityString = "SEVERITY ERROR"; - break; - } - - fprintf( - file, - "EVENT: (%d) (%d:%d,%d) %s: %s\n", - e.id, - const_cast(e).timeTag.getTimeBase(), - const_cast(e).timeTag.getSeconds(), - const_cast(e).timeTag.getUSeconds(), - severityString, - e.text.toChar() - ); - - } - - void MathSenderTesterBase :: - printTextLogHistory(FILE *file) - { - for (U32 i = 0; i < this->textLogHistory->size(); ++i) { - this->printTextLogHistoryEntry( - this->textLogHistory->at(i), - file - ); - } - } - -#endif - - // ---------------------------------------------------------------------- - // Event: MS_COMMAND_RECV - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - logIn_ACTIVITY_LO_MS_COMMAND_RECV( - F32 val1, - F32 val2, - MathSenderComponentBase::MathOpEv op - ) - { - EventEntry_MS_COMMAND_RECV e = { - val1, val2, op - }; - eventHistory_MS_COMMAND_RECV->push_back(e); - ++this->eventsSize; - } - - // ---------------------------------------------------------------------- - // Event: MS_RESULT - // ---------------------------------------------------------------------- - - void MathSenderTesterBase :: - logIn_ACTIVITY_HI_MS_RESULT( - F32 result - ) - { - EventEntry_MS_RESULT e = { - result - }; - eventHistory_MS_RESULT->push_back(e); - ++this->eventsSize; - } - -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/TesterBase.hpp b/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/TesterBase.hpp deleted file mode 100644 index 08e8be6194..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Handcode/TesterBase.hpp +++ /dev/null @@ -1,820 +0,0 @@ -// ====================================================================== -// \title MathSender/test/ut/TesterBase.hpp -// \author Auto-generated -// \brief hpp file for MathSender component test harness base class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef MathSender_TESTER_BASE_HPP -#define MathSender_TESTER_BASE_HPP - -#include -#include -#include -#include -#include - -namespace Ref { - - //! \class MathSenderTesterBase - //! \brief Auto-generated base class for MathSender component test harness - //! - class MathSenderTesterBase : - public Fw::PassiveComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Initialization - // ---------------------------------------------------------------------- - - //! Initialize object MathSenderTesterBase - //! - virtual void init( - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - public: - - // ---------------------------------------------------------------------- - // Connectors for 'to' ports - // Connect these output ports to the input ports under test - // ---------------------------------------------------------------------- - - //! Connect mathIn to to_mathIn[portNum] - //! - void connect_to_mathIn( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Ref::InputMathResultPort *const mathIn /*!< The port*/ - ); - - //! Connect CmdDisp to to_CmdDisp[portNum] - //! - void connect_to_CmdDisp( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::InputCmdPort *const CmdDisp /*!< The port*/ - ); - - public: - - // ---------------------------------------------------------------------- - // Getters for 'from' ports - // Connect these input ports to the output ports under test - // ---------------------------------------------------------------------- - - //! Get the port that receives input from mathOut - //! - //! \return from_mathOut[portNum] - //! - Ref::InputMathOpPort* get_from_mathOut( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from CmdStatus - //! - //! \return from_CmdStatus[portNum] - //! - Fw::InputCmdResponsePort* get_from_CmdStatus( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from CmdReg - //! - //! \return from_CmdReg[portNum] - //! - Fw::InputCmdRegPort* get_from_CmdReg( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from Tlm - //! - //! \return from_Tlm[portNum] - //! - Fw::InputTlmPort* get_from_Tlm( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from Time - //! - //! \return from_Time[portNum] - //! - Fw::InputTimePort* get_from_Time( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Get the port that receives input from Log - //! - //! \return from_Log[portNum] - //! - Fw::InputLogPort* get_from_Log( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! Get the port that receives input from LogText - //! - //! \return from_LogText[portNum] - //! - Fw::InputLogTextPort* get_from_LogText( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); -#endif - - protected: - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - //! Construct object MathSenderTesterBase - //! - MathSenderTesterBase( -#if FW_OBJECT_NAMES == 1 - const char *const compName, /*!< The component name*/ - const U32 maxHistorySize /*!< The maximum size of each history*/ -#else - const U32 maxHistorySize /*!< The maximum size of each history*/ -#endif - ); - - //! Destroy object MathSenderTesterBase - //! - virtual ~MathSenderTesterBase(void); - - // ---------------------------------------------------------------------- - // Test history - // ---------------------------------------------------------------------- - - protected: - - //! \class History - //! \brief A history of port inputs - //! - template class History { - - public: - - //! Create a History - //! - History( - const U32 maxSize /*!< The maximum history size*/ - ) : - numEntries(0), - maxSize(maxSize) - { - this->entries = new T[maxSize]; - } - - //! Destroy a History - //! - ~History() { - delete[] this->entries; - } - - //! Clear the history - //! - void clear() { this->numEntries = 0; } - - //! Push an item onto the history - //! - void push_back( - T entry /*!< The item*/ - ) { - FW_ASSERT(this->numEntries < this->maxSize); - entries[this->numEntries++] = entry; - } - - //! Get an item at an index - //! - //! \return The item at index i - //! - T at( - const U32 i /*!< The index*/ - ) const { - FW_ASSERT(i < this->numEntries); - return entries[i]; - } - - //! Get the number of entries in the history - //! - //! \return The number of entries in the history - //! - U32 size(void) const { return this->numEntries; } - - private: - - //! The number of entries in the history - //! - U32 numEntries; - - //! The maximum history size - //! - const U32 maxSize; - - //! The entries - //! - T *entries; - - }; - - //! Clear all history - //! - void clearHistory(void); - - protected: - - // ---------------------------------------------------------------------- - // Handler prototypes for typed from ports - // ---------------------------------------------------------------------- - - //! Handler prototype for from_mathOut - //! - virtual void from_mathOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 val1, - F32 val2, - MathOperation operation /*!< operation argument*/ - ) = 0; - - //! Handler base function for from_mathOut - //! - void from_mathOut_handlerBase( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 val1, - F32 val2, - MathOperation operation /*!< operation argument*/ - ); - - protected: - - // ---------------------------------------------------------------------- - // Histories for typed from ports - // ---------------------------------------------------------------------- - - //! Clear from port history - //! - void clearFromPortHistory(void); - - //! The total number of from port entries - //! - U32 fromPortHistorySize; - - //! Push an entry on the history for from_mathOut - void pushFromPortEntry_mathOut( - F32 val1, - F32 val2, - MathOperation operation /*!< operation argument*/ - ); - - //! A history entry for from_mathOut - //! - typedef struct { - F32 val1; - F32 val2; - MathOperation operation; - } FromPortEntry_mathOut; - - //! The history for from_mathOut - //! - History - *fromPortHistory_mathOut; - - protected: - - // ---------------------------------------------------------------------- - // Invocation functions for to ports - // ---------------------------------------------------------------------- - - //! Invoke the to port connected to mathIn - //! - void invoke_to_mathIn( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 result /*!< the result of the operation*/ - ); - - public: - - // ---------------------------------------------------------------------- - // Getters for port counts - // ---------------------------------------------------------------------- - - //! Get the number of from_mathOut ports - //! - //! \return The number of from_mathOut ports - //! - NATIVE_INT_TYPE getNum_from_mathOut(void) const; - - //! Get the number of to_mathIn ports - //! - //! \return The number of to_mathIn ports - //! - NATIVE_INT_TYPE getNum_to_mathIn(void) const; - - //! Get the number of to_CmdDisp ports - //! - //! \return The number of to_CmdDisp ports - //! - NATIVE_INT_TYPE getNum_to_CmdDisp(void) const; - - //! Get the number of from_CmdStatus ports - //! - //! \return The number of from_CmdStatus ports - //! - NATIVE_INT_TYPE getNum_from_CmdStatus(void) const; - - //! Get the number of from_CmdReg ports - //! - //! \return The number of from_CmdReg ports - //! - NATIVE_INT_TYPE getNum_from_CmdReg(void) const; - - //! Get the number of from_Tlm ports - //! - //! \return The number of from_Tlm ports - //! - NATIVE_INT_TYPE getNum_from_Tlm(void) const; - - //! Get the number of from_Time ports - //! - //! \return The number of from_Time ports - //! - NATIVE_INT_TYPE getNum_from_Time(void) const; - - //! Get the number of from_Log ports - //! - //! \return The number of from_Log ports - //! - NATIVE_INT_TYPE getNum_from_Log(void) const; - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! Get the number of from_LogText ports - //! - //! \return The number of from_LogText ports - //! - NATIVE_INT_TYPE getNum_from_LogText(void) const; -#endif - - protected: - - // ---------------------------------------------------------------------- - // Connection status for to ports - // ---------------------------------------------------------------------- - - //! Check whether port is connected - //! - //! Whether to_mathIn[portNum] is connected - //! - bool isConnected_to_mathIn( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Check whether port is connected - //! - //! Whether to_CmdDisp[portNum] is connected - //! - bool isConnected_to_CmdDisp( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - // ---------------------------------------------------------------------- - // Functions for sending commands - // ---------------------------------------------------------------------- - - protected: - - // send command buffers directly - used for intentional command encoding errors - void sendRawCmd(FwOpcodeType opcode, U32 cmdSeq, Fw::CmdArgBuffer& args); - - //! Send a MS_DO_MATH command - //! - void sendCmd_MS_DO_MATH( - const NATIVE_INT_TYPE instance, /*!< The instance number*/ - const U32 cmdSeq, /*!< The command sequence number*/ - F32 val1, /*!< The first value*/ - F32 val2, /*!< The second value*/ - MathSenderComponentBase::MathOp operation /*!< The operation to perform*/ - ); - - protected: - - // ---------------------------------------------------------------------- - // Command response handling - // ---------------------------------------------------------------------- - - //! Handle a command response - //! - virtual void cmdResponseIn( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - const Fw::CommandResponse response /*!< The command response*/ - ); - - //! A type representing a command response - //! - typedef struct { - FwOpcodeType opCode; - U32 cmdSeq; - Fw::CommandResponse response; - } CmdResponse; - - //! The command response history - //! - History *cmdResponseHistory; - - protected: - - // ---------------------------------------------------------------------- - // Event dispatch - // ---------------------------------------------------------------------- - - //! Dispatch an event - //! - void dispatchEvents( - const FwEventIdType id, /*!< The event ID*/ - Fw::Time& timeTag, /*!< The time*/ - const Fw::LogSeverity severity, /*!< The severity*/ - Fw::LogBuffer& args /*!< The serialized arguments*/ - ); - - //! Clear event history - //! - void clearEvents(void); - - //! The total number of events seen - //! - U32 eventsSize; - -#if FW_ENABLE_TEXT_LOGGING - - protected: - - // ---------------------------------------------------------------------- - // Text events - // ---------------------------------------------------------------------- - - //! Handle a text event - //! - virtual void textLogIn( - const FwEventIdType id, /*!< The event ID*/ - Fw::Time& timeTag, /*!< The time*/ - const Fw::TextLogSeverity severity, /*!< The severity*/ - const Fw::TextLogString& text /*!< The event string*/ - ); - - //! A history entry for the text log - //! - typedef struct { - U32 id; - Fw::Time timeTag; - Fw::TextLogSeverity severity; - Fw::TextLogString text; - } TextLogEntry; - - //! The history of text log events - //! - History *textLogHistory; - - //! Print a text log history entry - //! - static void printTextLogHistoryEntry( - const TextLogEntry& e, - FILE* file - ); - - //! Print the text log history - //! - void printTextLogHistory(FILE *const file); - -#endif - - protected: - - // ---------------------------------------------------------------------- - // Event: MS_COMMAND_RECV - // ---------------------------------------------------------------------- - - //! Handle event MS_COMMAND_RECV - //! - virtual void logIn_ACTIVITY_LO_MS_COMMAND_RECV( - F32 val1, /*!< The val1 argument*/ - F32 val2, /*!< The val1 argument*/ - MathSenderComponentBase::MathOpEv op /*!< The requested operation*/ - ); - - //! A history entry for event MS_COMMAND_RECV - //! - typedef struct { - F32 val1; - F32 val2; - MathSenderComponentBase::MathOpEv op; - } EventEntry_MS_COMMAND_RECV; - - //! The history of MS_COMMAND_RECV events - //! - History - *eventHistory_MS_COMMAND_RECV; - - protected: - - // ---------------------------------------------------------------------- - // Event: MS_RESULT - // ---------------------------------------------------------------------- - - //! Handle event MS_RESULT - //! - virtual void logIn_ACTIVITY_HI_MS_RESULT( - F32 result /*!< The math result*/ - ); - - //! A history entry for event MS_RESULT - //! - typedef struct { - F32 result; - } EventEntry_MS_RESULT; - - //! The history of MS_RESULT events - //! - History - *eventHistory_MS_RESULT; - - protected: - - // ---------------------------------------------------------------------- - // Telemetry dispatch - // ---------------------------------------------------------------------- - - //! Dispatch telemetry - //! - void dispatchTlm( - const FwChanIdType id, /*!< The channel ID*/ - const Fw::Time& timeTag, /*!< The time*/ - Fw::TlmBuffer& val /*!< The channel value*/ - ); - - //! Clear telemetry history - //! - void clearTlm(void); - - //! The total number of telemetry inputs seen - //! - U32 tlmSize; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_VAL1 - // ---------------------------------------------------------------------- - - //! Handle channel MS_VAL1 - //! - virtual void tlmInput_MS_VAL1( - const Fw::Time& timeTag, /*!< The time*/ - const F32& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MS_VAL1 - //! - typedef struct { - Fw::Time timeTag; - F32 arg; - } TlmEntry_MS_VAL1; - - //! The history of MS_VAL1 values - //! - History - *tlmHistory_MS_VAL1; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_VAL2 - // ---------------------------------------------------------------------- - - //! Handle channel MS_VAL2 - //! - virtual void tlmInput_MS_VAL2( - const Fw::Time& timeTag, /*!< The time*/ - const F32& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MS_VAL2 - //! - typedef struct { - Fw::Time timeTag; - F32 arg; - } TlmEntry_MS_VAL2; - - //! The history of MS_VAL2 values - //! - History - *tlmHistory_MS_VAL2; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_OP - // ---------------------------------------------------------------------- - - //! Handle channel MS_OP - //! - virtual void tlmInput_MS_OP( - const Fw::Time& timeTag, /*!< The time*/ - const MathSenderComponentBase::MathOpTlm& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MS_OP - //! - typedef struct { - Fw::Time timeTag; - MathSenderComponentBase::MathOpTlm arg; - } TlmEntry_MS_OP; - - //! The history of MS_OP values - //! - History - *tlmHistory_MS_OP; - - protected: - - // ---------------------------------------------------------------------- - // Channel: MS_RES - // ---------------------------------------------------------------------- - - //! Handle channel MS_RES - //! - virtual void tlmInput_MS_RES( - const Fw::Time& timeTag, /*!< The time*/ - const F32& val /*!< The channel value*/ - ); - - //! A telemetry entry for channel MS_RES - //! - typedef struct { - Fw::Time timeTag; - F32 arg; - } TlmEntry_MS_RES; - - //! The history of MS_RES values - //! - History - *tlmHistory_MS_RES; - - protected: - - // ---------------------------------------------------------------------- - // Test time - // ---------------------------------------------------------------------- - - //! Set the test time for events and telemetry - //! - void setTestTime( - const Fw::Time& timeTag /*!< The time*/ - ); - - private: - - // ---------------------------------------------------------------------- - // To ports - // ---------------------------------------------------------------------- - - //! To port connected to mathIn - //! - Ref::OutputMathResultPort m_to_mathIn[1]; - - //! To port connected to CmdDisp - //! - Fw::OutputCmdPort m_to_CmdDisp[1]; - - private: - - // ---------------------------------------------------------------------- - // From ports - // ---------------------------------------------------------------------- - - //! From port connected to mathOut - //! - Ref::InputMathOpPort m_from_mathOut[1]; - - //! From port connected to CmdStatus - //! - Fw::InputCmdResponsePort m_from_CmdStatus[1]; - - //! From port connected to CmdReg - //! - Fw::InputCmdRegPort m_from_CmdReg[1]; - - //! From port connected to Tlm - //! - Fw::InputTlmPort m_from_Tlm[1]; - - //! From port connected to Time - //! - Fw::InputTimePort m_from_Time[1]; - - //! From port connected to Log - //! - Fw::InputLogPort m_from_Log[1]; - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! From port connected to LogText - //! - Fw::InputLogTextPort m_from_LogText[1]; -#endif - - private: - - // ---------------------------------------------------------------------- - // Static functions for output ports - // ---------------------------------------------------------------------- - - //! Static function for port from_mathOut - //! - static void from_mathOut_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 val1, - F32 val2, - MathOperation operation /*!< operation argument*/ - ); - - //! Static function for port from_CmdStatus - //! - static void from_CmdStatus_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwOpcodeType opCode, /*!< Command Op Code*/ - U32 cmdSeq, /*!< Command Sequence*/ - Fw::CommandResponse response /*!< The command response argument*/ - ); - - //! Static function for port from_CmdReg - //! - static void from_CmdReg_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwOpcodeType opCode /*!< Command Op Code*/ - ); - - //! Static function for port from_Tlm - //! - static void from_Tlm_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwChanIdType id, /*!< Telemetry Channel ID*/ - Fw::Time &timeTag, /*!< Time Tag*/ - Fw::TlmBuffer &val /*!< Buffer containing serialized telemetry value*/ - ); - - //! Static function for port from_Time - //! - static void from_Time_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Time &time /*!< The U32 cmd argument*/ - ); - - //! Static function for port from_Log - //! - static void from_Log_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwEventIdType id, /*!< Log ID*/ - Fw::Time &timeTag, /*!< Time Tag*/ - Fw::LogSeverity severity, /*!< The severity argument*/ - Fw::LogBuffer &args /*!< Buffer containing serialized log entry*/ - ); - -#if FW_ENABLE_TEXT_LOGGING == 1 - //! Static function for port from_LogText - //! - static void from_LogText_static( - Fw::PassiveComponentBase *const callComp, /*!< The component instance*/ - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwEventIdType id, /*!< Log ID*/ - Fw::Time &timeTag, /*!< Time Tag*/ - Fw::TextLogSeverity severity, /*!< The severity argument*/ - Fw::TextLogString &text /*!< Text of log message*/ - ); -#endif - - private: - - // ---------------------------------------------------------------------- - // Test time - // ---------------------------------------------------------------------- - - //! Test time stamp - //! - Fw::Time m_testTime; - - }; - -} // end namespace Ref - -#endif diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.cpp b/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.cpp index e3510f79ad..2b2955c9f7 100644 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.cpp +++ b/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.cpp @@ -1,16 +1,17 @@ // ====================================================================== // \title MathSender.hpp -// \author tcanham +// \author tcanham, bocchino // \brief cpp file for MathSender test harness implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2021, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // // ====================================================================== #include "Tester.hpp" +#include "STest/Pick/Pick.hpp" #define INSTANCE 0 #define MAX_HISTORY_SIZE 10 @@ -24,13 +25,8 @@ namespace Ref { Tester :: Tester() : -#if FW_OBJECT_NAMES == 1 MathSenderGTestBase("Tester", MAX_HISTORY_SIZE), component("MathSender") -#else - MathSenderGTestBase(MAX_HISTORY_SIZE), - component() -#endif { this->initComponents(); this->connectPorts(); @@ -46,296 +42,195 @@ namespace Ref { // Tests // ---------------------------------------------------------------------- + F32 Tester :: + pickF32Value() + { + const F32 m = 10e6; + return m * (1.0 - 2 * STest::Pick::inUnitInterval()); + } + void Tester :: testAddCommand() { - // send MS_DO_MATH command - this->sendCmd_MS_DO_MATH(0,10,1.0,2.0,MathSenderComponentBase::ADD); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify that that only one output port was called - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // verify that the math operation port was only called once - ASSERT_from_mathOut_SIZE(1); - // verify the arguments of the operation port - ASSERT_from_mathOut(0,1.0,2.0,MATH_ADD); - // verify telemetry - 3 channels were written - ASSERT_TLM_SIZE(3); - // verify that the desired telemetry values were only sent once - ASSERT_TLM_MS_VAL1_SIZE(1); - ASSERT_TLM_MS_VAL2_SIZE(1); - ASSERT_TLM_MS_OP_SIZE(1); - // verify that the correct telemetry values were sent - ASSERT_TLM_MS_VAL1(0,1.0); - ASSERT_TLM_MS_VAL2(0,2.0); - ASSERT_TLM_MS_OP(0,MathSenderComponentBase::ADD_TLM); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_COMMAND_RECV_SIZE(1); - // verify the correct event arguments were sent - ASSERT_EVENTS_MS_COMMAND_RECV(0,1.0,2.0,MathSenderComponentBase::ADD_EV); - // verify command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - // verify the command response was correct as expected - ASSERT_CMD_RESPONSE(0,MathSenderComponentBase::OPCODE_MS_DO_MATH,10,Fw::CmdResponse::OK); - - // reset all telemetry and port history - this->clearHistory(); - // call result port. We don't care about the value being correct since MathSender doesn't - this->invoke_to_mathIn(0,10.0); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify only one telemetry value was written - ASSERT_TLM_SIZE(1); - // verify the desired telemetry channel was sent only once - ASSERT_TLM_MS_RES_SIZE(1); - // verify the values of the telemetry channel - ASSERT_TLM_MS_RES(0,10.0); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_RESULT_SIZE(1); - // verify the expected value of the event arguments - ASSERT_EVENTS_MS_RESULT(0,10.0); + this->testDoMath(MathOp::ADD); } void Tester :: testSubCommand() { - // send MS_DO_MATH command - this->sendCmd_MS_DO_MATH(0,10,1.0,2.0,MathSenderComponentBase::SUBTRACT); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify that that only one output port was called - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // verify that the math operation port was only called once - ASSERT_from_mathOut_SIZE(1); - // verify the arguments of the operation port - ASSERT_from_mathOut(0,1.0,2.0,MATH_SUB); - // verify telemetry - 3 channels were written - ASSERT_TLM_SIZE(3); - // verify that the desired telemetry values were only sent once - ASSERT_TLM_MS_VAL1_SIZE(1); - ASSERT_TLM_MS_VAL2_SIZE(1); - ASSERT_TLM_MS_OP_SIZE(1); - // verify that the correct telemetry values were sent - ASSERT_TLM_MS_VAL1(0,1.0); - ASSERT_TLM_MS_VAL2(0,2.0); - ASSERT_TLM_MS_OP(0,MathSenderComponentBase::SUB_TLM); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_COMMAND_RECV_SIZE(1); - // verify the correct event arguments were sent - ASSERT_EVENTS_MS_COMMAND_RECV(0,1.0,2.0,MathSenderComponentBase::SUB_EV); - // verify command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - // verify the command response was correct as expected - ASSERT_CMD_RESPONSE(0,MathSenderComponentBase::OPCODE_MS_DO_MATH,10,Fw::CmdResponse::OK); - - // reset all telemetry and port history - this->clearHistory(); - // call result port. We don't care about the value being correct since MathSender doesn't - this->invoke_to_mathIn(0,10.0); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify only one telemetry value was written - ASSERT_TLM_SIZE(1); - // verify the desired telemetry channel was sent only once - ASSERT_TLM_MS_RES_SIZE(1); - // verify the values of the telemetry channel - ASSERT_TLM_MS_RES(0,10.0); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_RESULT_SIZE(1); - // verify the expect value of the event - ASSERT_EVENTS_MS_RESULT(0,10.0); + this->testDoMath(MathOp::SUB); } void Tester :: - testMultCommand() + testMulCommand() { - // send MS_DO_MATH command - this->sendCmd_MS_DO_MATH(0,10,1.0,2.0,MathSenderComponentBase::MULTIPLY); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify that that only one output port was called - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // verify that the math operation port was only called once - ASSERT_from_mathOut_SIZE(1); - // verify the arguments of the operation port - ASSERT_from_mathOut(0,1.0,2.0,MATH_MULTIPLY); - // verify telemetry - 3 channels were written - ASSERT_TLM_SIZE(3); - // verify that the desired telemetry values were only sent once - ASSERT_TLM_MS_VAL1_SIZE(1); - ASSERT_TLM_MS_VAL2_SIZE(1); - ASSERT_TLM_MS_OP_SIZE(1); - // verify that the correct telemetry values were sent - ASSERT_TLM_MS_VAL1(0,1.0); - ASSERT_TLM_MS_VAL2(0,2.0); - ASSERT_TLM_MS_OP(0,MathSenderComponentBase::MULT_TLM); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_COMMAND_RECV_SIZE(1); - // verify the correct event arguments were sent - ASSERT_EVENTS_MS_COMMAND_RECV(0,1.0,2.0,MathSenderComponentBase::MULT_EV); - // verify command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - // verify the command response was correct as expected - ASSERT_CMD_RESPONSE(0,MathSenderComponentBase::OPCODE_MS_DO_MATH,10,Fw::CmdResponse::OK); - - // reset all telemetry and port history - this->clearHistory(); - // call result port. We don't care about the value being correct since MathSender doesn't - this->invoke_to_mathIn(0,10.0); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify only one telemetry value was written - ASSERT_TLM_SIZE(1); - // verify the desired telemetry channel was sent only once - ASSERT_TLM_MS_RES_SIZE(1); - // verify the values of the telemetry channel - ASSERT_TLM_MS_RES(0,10.0); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_RESULT_SIZE(1); - // verify the expect value of the event - ASSERT_EVENTS_MS_RESULT(0,10.0); + this->testDoMath(MathOp::MUL); } void Tester :: testDivCommand() { - // send MS_DO_MATH command - this->sendCmd_MS_DO_MATH(0,10,1.0,2.0,MathSenderComponentBase::DIVIDE); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify that that only one output port was called - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // verify that the math operation port was only called once - ASSERT_from_mathOut_SIZE(1); - // verify the arguments of the operation port - ASSERT_from_mathOut(0,1.0,2.0,MATH_DIVIDE); - // verify telemetry - 3 channels were written - ASSERT_TLM_SIZE(3); - // verify that the desired telemetry values were only sent once - ASSERT_TLM_MS_VAL1_SIZE(1); - ASSERT_TLM_MS_VAL2_SIZE(1); - ASSERT_TLM_MS_OP_SIZE(1); - // verify that the correct telemetry values were sent - ASSERT_TLM_MS_VAL1(0,1.0); - ASSERT_TLM_MS_VAL2(0,2.0); - ASSERT_TLM_MS_OP(0,MathSenderComponentBase::DIV_TLM); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_COMMAND_RECV_SIZE(1); - // verify the correct event arguments were sent - ASSERT_EVENTS_MS_COMMAND_RECV(0,1.0,2.0,MathSenderComponentBase::DIV_EV); - // verify command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - // verify the command response was correct as expected - ASSERT_CMD_RESPONSE(0,MathSenderComponentBase::OPCODE_MS_DO_MATH,10,Fw::CmdResponse::OK); + this->testDoMath(MathOp::DIV); + } + void Tester :: + testResult() + { + // Generate an expected result + const F32 result = pickF32Value(); // reset all telemetry and port history this->clearHistory(); - // call result port. We don't care about the value being correct since MathSender doesn't - this->invoke_to_mathIn(0,10.0); + // call result port with result + this->invoke_to_mathResultIn(0, result); // retrieve the message from the message queue and dispatch the command to the handler this->component.doDispatch(); - // verify only one telemetry value was written + // verify one telemetry value was written ASSERT_TLM_SIZE(1); - // verify the desired telemetry channel was sent only once - ASSERT_TLM_MS_RES_SIZE(1); + // verify the desired telemetry channel was sent once + ASSERT_TLM_RESULT_SIZE(1); // verify the values of the telemetry channel - ASSERT_TLM_MS_RES(0,10.0); - // verify only one event was sent + ASSERT_TLM_RESULT(0, result); + // verify one event was sent ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_RESULT_SIZE(1); + // verify the expected event was sent once + ASSERT_EVENTS_RESULT_SIZE(1); // verify the expect value of the event - ASSERT_EVENTS_MS_RESULT(0,10.0); + ASSERT_EVENTS_RESULT(0, result); } + // ---------------------------------------------------------------------- // Handlers for typed from ports // ---------------------------------------------------------------------- void Tester :: - from_mathOut_handler( + from_mathOpOut_handler( const NATIVE_INT_TYPE portNum, F32 val1, - F32 val2, - MathOperation operation + const MathOp& op, + F32 val2 ) { - this->pushFromPortEntry_mathOut(val1, val2, operation); + this->pushFromPortEntry_mathOpOut(val1, op, val2); } // ---------------------------------------------------------------------- // Helper methods // ---------------------------------------------------------------------- + void Tester :: + testDoMath(MathOp op) + { + + // Pick values + + const F32 val1 = pickF32Value(); + const F32 val2 = pickF32Value(); + + // Send the command + + // pick a command sequence number + const U32 cmdSeq = STest::Pick::any(); + // send DO_MATH command + this->sendCmd_DO_MATH(0, cmdSeq, val1, op, val2); + // retrieve the message from the message queue and dispatch the command to the handler + this->component.doDispatch(); + + // Verify command receipt and response + + // verify command response was sent + ASSERT_CMD_RESPONSE_SIZE(1); + // verify the command response was correct as expected + ASSERT_CMD_RESPONSE(0, MathSenderComponentBase::OPCODE_DO_MATH, cmdSeq, Fw::CmdResponse::OK); + + // Verify operation request on mathOpOut + + // verify that that one output port was invoked overall + ASSERT_FROM_PORT_HISTORY_SIZE(1); + // verify that the math operation port was invoked once + ASSERT_from_mathOpOut_SIZE(1); + // verify the arguments of the operation port + ASSERT_from_mathOpOut(0, val1, op, val2); + + // Verify telemetry + + // verify that 3 channels were written + ASSERT_TLM_SIZE(3); + // verify that the desired telemetry values were sent once + ASSERT_TLM_VAL1_SIZE(1); + ASSERT_TLM_VAL2_SIZE(1); + ASSERT_TLM_OP_SIZE(1); + // verify that the correct telemetry values were sent + ASSERT_TLM_VAL1(0, val1); + ASSERT_TLM_VAL2(0, val2); + ASSERT_TLM_OP(0, op); + + // Verify event reports + + // verify that one event was sent + ASSERT_EVENTS_SIZE(1); + // verify the expected event was sent once + ASSERT_EVENTS_COMMAND_RECV_SIZE(1); + // verify the correct event arguments were sent + ASSERT_EVENTS_COMMAND_RECV(0, val1, op, val2); + + } + void Tester :: connectPorts() { - // mathIn - this->connect_to_mathIn( + // mathResultIn + this->connect_to_mathResultIn( 0, - this->component.get_mathIn_InputPort(0) + this->component.get_mathResultIn_InputPort(0) ); - // CmdDisp - this->connect_to_CmdDisp( + // cmdIn + this->connect_to_cmdIn( 0, - this->component.get_CmdDisp_InputPort(0) + this->component.get_cmdIn_InputPort(0) ); - // mathOut - this->component.set_mathOut_OutputPort( + // mathOpOut + this->component.set_mathOpOut_OutputPort( 0, - this->get_from_mathOut(0) + this->get_from_mathOpOut(0) ); - // CmdStatus - this->component.set_CmdStatus_OutputPort( + // cmdResponseOut + this->component.set_cmdResponseOut_OutputPort( 0, - this->get_from_CmdStatus(0) + this->get_from_cmdResponseOut(0) ); - // CmdReg - this->component.set_CmdReg_OutputPort( + // cmdRegOut + this->component.set_cmdRegOut_OutputPort( 0, - this->get_from_CmdReg(0) + this->get_from_cmdRegOut(0) ); - // Tlm - this->component.set_Tlm_OutputPort( + // tlmOut + this->component.set_tlmOut_OutputPort( 0, - this->get_from_Tlm(0) + this->get_from_tlmOut(0) ); - // Time - this->component.set_Time_OutputPort( + // timeGetOut + this->component.set_timeGetOut_OutputPort( 0, - this->get_from_Time(0) + this->get_from_timeGetOut(0) ); - // Log - this->component.set_Log_OutputPort( + // eventOut + this->component.set_eventOut_OutputPort( 0, - this->get_from_Log(0) + this->get_from_eventOut(0) ); - // LogText - this->component.set_LogText_OutputPort( + // textEventOut + this->component.set_textEventOut_OutputPort( 0, - this->get_from_LogText(0) + this->get_from_textEventOut(0) ); } diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.hpp b/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.hpp index 5b1d69831e..fbe94c5604 100644 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.hpp +++ b/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.hpp @@ -1,10 +1,10 @@ // ====================================================================== // \title MathSender/test/ut/Tester.hpp -// \author tcanham +// \author tcanham, bocchino // \brief hpp file for MathSender test harness implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2021, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // @@ -14,7 +14,7 @@ #define TESTER_HPP #include "GTestBase.hpp" -#include "Ref/MathSender/MathSenderComponentImpl.hpp" +#include "Ref/MathSender/MathSender.hpp" namespace Ref { @@ -42,13 +42,21 @@ namespace Ref { // Tests // ---------------------------------------------------------------------- - //! Test operation command - //! + //! Test an ADD command void testAddCommand(); + + //! Test a SUB command void testSubCommand(); - void testMultCommand(); + + //! Test a MUL command + void testMulCommand(); + + //! Test a DIV command void testDivCommand(); + //! Test receipt of a result + void testResult(); + private: // ---------------------------------------------------------------------- @@ -57,11 +65,11 @@ namespace Ref { //! Handler for from_mathOut //! - void from_mathOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - F32 val1, - F32 val2, - MathOperation operation /*!< operation argument*/ + void from_mathOpOut_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + F32 val1, //!< First operand + const MathOp& op, //!< operation + F32 val2 //!< Second operand ); private: @@ -70,6 +78,12 @@ namespace Ref { // Helper methods // ---------------------------------------------------------------------- + //! Pick a random value + static F32 pickF32Value(); + + //! Test a DO_MATH command + void testDoMath(MathOp op); + //! Connect ports //! void connectPorts(); @@ -86,7 +100,7 @@ namespace Ref { //! The component under test //! - MathSenderComponentImpl component; + MathSender component; }; diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/TestMain.cpp b/docs/Tutorials/MathComponent/MathSender/test/ut/main.cpp similarity index 65% rename from docs/Tutorials/MathComponent/MathReceiver/test/ut/TestMain.cpp rename to docs/Tutorials/MathComponent/MathSender/test/ut/main.cpp index 8e9a38374c..7fe0415d25 100644 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/TestMain.cpp +++ b/docs/Tutorials/MathComponent/MathSender/test/ut/main.cpp @@ -1,35 +1,37 @@ // ---------------------------------------------------------------------- -// Main.cpp +// Main.cpp // ---------------------------------------------------------------------- +#include "STest/Random/Random.hpp" #include "Tester.hpp" -TEST(Nominal, AddOperationTest) { +TEST(Nominal, AddCommand) { Ref::Tester tester; tester.testAddCommand(); } -TEST(Nominal, SubOperationTest) { +TEST(Nominal, SubCommand) { Ref::Tester tester; tester.testSubCommand(); } -TEST(Nominal, MultOperationTest) { +TEST(Nominal, MulCommand) { Ref::Tester tester; - tester.testMultCommand(); + tester.testMulCommand(); } -TEST(Nominal, DivideOperationTest) { +TEST(Nominal, DivCommand) { Ref::Tester tester; tester.testDivCommand(); } -TEST(Nominal, ThrottleTest) { +TEST(Nominal, Result) { Ref::Tester tester; - tester.testThrottle(); + tester.testResult(); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); return RUN_ALL_TESTS(); } diff --git a/docs/Tutorials/MathComponent/MathTypes/CMakeLists.txt b/docs/Tutorials/MathComponent/MathTypes/CMakeLists.txt index b866b8f041..2fc3269205 100644 --- a/docs/Tutorials/MathComponent/MathTypes/CMakeLists.txt +++ b/docs/Tutorials/MathComponent/MathTypes/CMakeLists.txt @@ -1,13 +1,5 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding diles -# MOD_DEPS: (optional) module dependencies -# -# Note: using PROJECT_NAME as EXECUTABLE_NAME -#### set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathOpSerializableAi.xml" + "${CMAKE_CURRENT_LIST_DIR}/MathTypes.fpp" ) register_fprime_module() diff --git a/docs/Tutorials/MathComponent/MathTypes/MathOpSerializableAi.xml b/docs/Tutorials/MathComponent/MathTypes/MathOpSerializableAi.xml deleted file mode 100644 index 41d7aa99f3..0000000000 --- a/docs/Tutorials/MathComponent/MathTypes/MathOpSerializableAi.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - This value holds the values of a math operation - - - - - - - - - - - - - - - diff --git a/docs/Tutorials/MathComponent/MathTypes/MathTypes.fpp b/docs/Tutorials/MathComponent/MathTypes/MathTypes.fpp new file mode 100644 index 0000000000..32085c868a --- /dev/null +++ b/docs/Tutorials/MathComponent/MathTypes/MathTypes.fpp @@ -0,0 +1,11 @@ +module Ref { + + @ A math operation + enum MathOp { + ADD @< Addition + SUB @< Subtraction + MUL @< Multiplication + DIV @< Division + } + +} diff --git a/docs/Tutorials/MathComponent/Top/RefTopologyAppAi.xml b/docs/Tutorials/MathComponent/Top/RefTopologyAppAi.xml deleted file mode 100644 index b60d4a5b05..0000000000 --- a/docs/Tutorials/MathComponent/Top/RefTopologyAppAi.xml +++ /dev/null @@ -1,115 +0,0 @@ - Ref/MathSender/MathSenderComponentAi.xml - Ref/MathReceiver/MathReceiverComponentAi.xml - -... - - - - -... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/Tutorials/MathComponent/Top/instances.fpp b/docs/Tutorials/MathComponent/Top/instances.fpp new file mode 100644 index 0000000000..1e97ee6a65 --- /dev/null +++ b/docs/Tutorials/MathComponent/Top/instances.fpp @@ -0,0 +1,373 @@ +module Ref { + + # ---------------------------------------------------------------------- + # Defaults + # ---------------------------------------------------------------------- + + module Default { + + constant queueSize = 10 + + constant stackSize = 16 * 1024 + + } + + # ---------------------------------------------------------------------- + # Active component instances + # ---------------------------------------------------------------------- + + instance blockDrv: Drv.BlockDriver base id 0x0100 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 140 \ + { + + phase Fpp.ToCpp.Phases.instances """ + // Declared in RefTopologyDefs.cpp + """ + + } + + instance rateGroup1Comp: Svc.ActiveRateGroup base id 0x0200 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 120 \ + { + + phase Fpp.ToCpp.Phases.configObjects """ + NATIVE_UINT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + """ + + phase Fpp.ToCpp.Phases.instances """ + Svc::ActiveRateGroup rateGroup1Comp( + FW_OPTIONAL_NAME("rateGroup1Comp"), + ConfigObjects::rateGroup1Comp::context, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup1Comp::context) + ); + """ + + } + + instance rateGroup2Comp: Svc.ActiveRateGroup base id 0x0300 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 119 \ + { + + phase Fpp.ToCpp.Phases.configObjects """ + NATIVE_UINT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + """ + + phase Fpp.ToCpp.Phases.instances """ + Svc::ActiveRateGroup rateGroup2Comp( + FW_OPTIONAL_NAME("rateGroup2Comp"), + ConfigObjects::rateGroup2Comp::context, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup2Comp::context) + ); + """ + + } + + instance rateGroup3Comp: Svc.ActiveRateGroup base id 0x0400 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 118 \ + { + + phase Fpp.ToCpp.Phases.configObjects """ + NATIVE_UINT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + """ + + phase Fpp.ToCpp.Phases.instances """ + Svc::ActiveRateGroup rateGroup3Comp( + FW_OPTIONAL_NAME("rateGroup3Comp"), + ConfigObjects::rateGroup3Comp::context, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup3Comp::context) + ); + """ + + } + + instance cmdDisp: Svc.CommandDispatcher base id 0x0500 \ + queue size 20 \ + stack size Default.stackSize \ + priority 101 + + instance cmdSeq: Svc.CmdSequencer base id 0x0600 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 100 \ + { + + phase Fpp.ToCpp.Phases.configConstants """ + enum { + BUFFER_SIZE = 5*1024 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + cmdSeq.allocateBuffer( + 0, + Allocation::mallocator, + ConfigConstants::cmdSeq::BUFFER_SIZE + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + cmdSeq.deallocateBuffer(Allocation::mallocator); + """ + + } + + instance fileDownlink: Svc.FileDownlink base id 0x0700 \ + queue size 30 \ + stack size Default.stackSize \ + priority 100 \ + { + + phase Fpp.ToCpp.Phases.configConstants """ + enum { + TIMEOUT = 1000, + COOLDOWN = 1000, + CYCLE_TIME = 1000, + FILE_QUEUE_DEPTH = 10 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + fileDownlink.configure( + ConfigConstants::fileDownlink::TIMEOUT, + ConfigConstants::fileDownlink::COOLDOWN, + ConfigConstants::fileDownlink::CYCLE_TIME, + ConfigConstants::fileDownlink::FILE_QUEUE_DEPTH + ); + """ + + } + + instance fileManager: Svc.FileManager base id 0x0800 \ + queue size 30 \ + stack size Default.stackSize \ + priority 100 + + instance fileUplink: Svc.FileUplink base id 0x0900 \ + queue size 30 \ + stack size Default.stackSize \ + priority 100 + + instance pingRcvr: Ref.PingReceiver base id 0x0A00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 100 + + instance eventLogger: Svc.ActiveLogger base id 0x0B00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 98 + + instance chanTlm: Svc.TlmChan base id 0x0C00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 97 + + instance prmDb: Svc.PrmDb base id 0x0D00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 96 \ + { + + phase Fpp.ToCpp.Phases.instances """ + Svc::PrmDb prmDb(FW_OPTIONAL_NAME("prmDb"), "PrmDb.dat"); + """ + + phase Fpp.ToCpp.Phases.readParameters """ + prmDb.readParamFile(); + """ + + } + + instance mathSender: Ref.MathSender base id 0xE00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 100 + + # ---------------------------------------------------------------------- + # Queued component instances + # ---------------------------------------------------------------------- + + instance $health: Svc.Health base id 0x2000 \ + queue size 25 \ + { + + phase Fpp.ToCpp.Phases.configConstants """ + enum { + WATCHDOG_CODE = 0x123 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + health.setPingEntries( + ConfigObjects::health::pingEntries, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::health::pingEntries), + ConfigConstants::health::WATCHDOG_CODE + ); + """ + + } + + instance SG1: Ref.SignalGen base id 0x2100 \ + queue size Default.queueSize + + instance SG2: Ref.SignalGen base id 0x2200 \ + queue size Default.queueSize + + instance SG3: Ref.SignalGen base id 0x2300 \ + queue size Default.queueSize + + instance SG4: Ref.SignalGen base id 0x2400 \ + queue size Default.queueSize + + instance SG5: Ref.SignalGen base id 0x2500 \ + queue size Default.queueSize + + instance sendBuffComp: Ref.SendBuff base id 0x2600 \ + queue size Default.queueSize + + instance mathReceiver: Ref.MathReceiver base id 0x2700 \ + queue size Default.queueSize + + # ---------------------------------------------------------------------- + # Passive component instances + # ---------------------------------------------------------------------- + + @ Communications driver. May be swapped with other comm drivers like UART + @ Note: Here we have TCP reliable uplink and UDP (low latency) downlink + instance comm: Drv.ByteStreamDriverModel base id 0x4000 \ + at "../../Drv/TcpClient/TcpClient.hpp" \ + { + + phase Fpp.ToCpp.Phases.instances """ + Drv::TcpClient comm(FW_OPTIONAL_NAME("comm")); + """ + + phase Fpp.ToCpp.Phases.configConstants """ + enum { + PRIORITY = 100, + STACK_SIZE = Default::stackSize + }; + """ + + phase Fpp.ToCpp.Phases.startTasks """ + // Initialize socket server if and only if there is a valid specification + if (state.hostName != nullptr && state.portNumber != 0) { + Os::TaskString name("ReceiveTask"); + // Uplink is configured for receive so a socket task is started + comm.configure(state.hostName, state.portNumber); + comm.startSocketTask( + name, + ConfigConstants::comm::PRIORITY, + ConfigConstants::comm::STACK_SIZE + ); + } + """ + + phase Fpp.ToCpp.Phases.freeThreads """ + comm.stopSocketTask(); + (void) comm.joinSocketTask(nullptr); + """ + + } + + instance downlink: Svc.Framer base id 0x4100 { + + phase Fpp.ToCpp.Phases.configObjects """ + Svc::FprimeFraming framing; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + downlink.setup(ConfigObjects::downlink::framing); + """ + + } + + instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4200 + + instance fatalHandler: Svc.FatalHandler base id 0x4300 + + instance fileUplinkBufferManager: Svc.BufferManager base id 0x4400 { + + phase Fpp.ToCpp.Phases.configConstants """ + enum { + STORE_SIZE = 3000, + QUEUE_SIZE = 30, + MGR_ID = 200 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + Svc::BufferManager::BufferBins upBuffMgrBins; + memset(&upBuffMgrBins, 0, sizeof(upBuffMgrBins)); + { + using namespace ConfigConstants::fileUplinkBufferManager; + upBuffMgrBins.bins[0].bufferSize = STORE_SIZE; + upBuffMgrBins.bins[0].numBuffers = QUEUE_SIZE; + fileUplinkBufferManager.setup( + MGR_ID, + 0, + Allocation::mallocator, + upBuffMgrBins + ); + } + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + fileUplinkBufferManager.cleanup(); + """ + + } + + instance linuxTime: Svc.Time base id 0x4500 \ + at "../../Svc/LinuxTime/LinuxTime.hpp" \ + { + + phase Fpp.ToCpp.Phases.instances """ + Svc::LinuxTime linuxTime(FW_OPTIONAL_NAME("linuxTime")); + """ + + } + + instance rateGroupDriverComp: Svc.RateGroupDriver base id 0x4600 { + + phase Fpp.ToCpp.Phases.configObjects """ + NATIVE_INT_TYPE rgDivs[Svc::RateGroupDriver::DIVIDER_SIZE] = { 1, 2, 4 }; + """ + + phase Fpp.ToCpp.Phases.instances """ + Svc::RateGroupDriver rateGroupDriverComp( + FW_OPTIONAL_NAME("rateGroupDriverComp"), + ConfigObjects::rateGroupDriverComp::rgDivs, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroupDriverComp::rgDivs) + ); + """ + + } + + instance recvBuffComp: Ref.RecvBuff base id 0x4700 + + instance staticMemory: Svc.StaticMemory base id 0x4800 + + instance textLogger: Svc.PassiveTextLogger base id 0x4900 + + instance uplink: Svc.Deframer base id 0x4A00 { + + phase Fpp.ToCpp.Phases.configObjects """ + Svc::FprimeDeframing deframing; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + uplink.setup(ConfigObjects::uplink::deframing); + """ + + } + +} diff --git a/docs/Tutorials/MathComponent/Top/topology.fpp b/docs/Tutorials/MathComponent/Top/topology.fpp new file mode 100644 index 0000000000..c6ab2274aa --- /dev/null +++ b/docs/Tutorials/MathComponent/Top/topology.fpp @@ -0,0 +1,160 @@ +module Ref { + + # ---------------------------------------------------------------------- + # Symbolic constants for port numbers + # ---------------------------------------------------------------------- + + enum Ports_RateGroups { + rateGroup1 + rateGroup2 + rateGroup3 + } + + enum Ports_StaticMemory { + downlink + uplink + } + + topology Ref { + + # ---------------------------------------------------------------------- + # Instances used in the topology + # ---------------------------------------------------------------------- + + instance $health + instance SG1 + instance SG2 + instance SG3 + instance SG4 + instance SG5 + instance blockDrv + instance chanTlm + instance cmdDisp + instance cmdSeq + instance comm + instance downlink + instance eventLogger + instance fatalAdapter + instance fatalHandler + instance fileDownlink + instance fileManager + instance fileUplink + instance fileUplinkBufferManager + instance linuxTime + instance mathReceiver + instance mathSender + instance pingRcvr + instance prmDb + instance rateGroup1Comp + instance rateGroup2Comp + instance rateGroup3Comp + instance rateGroupDriverComp + instance recvBuffComp + instance sendBuffComp + instance staticMemory + instance textLogger + instance uplink + + # ---------------------------------------------------------------------- + # Pattern graph specifiers + # ---------------------------------------------------------------------- + + command connections instance cmdDisp + + event connections instance eventLogger + + param connections instance prmDb + + telemetry connections instance chanTlm + + text event connections instance textLogger + + time connections instance linuxTime + + health connections instance $health + + # ---------------------------------------------------------------------- + # Direct graph specifiers + # ---------------------------------------------------------------------- + + connections Downlink { + + chanTlm.PktSend -> downlink.comIn + eventLogger.PktSend -> downlink.comIn + fileDownlink.bufferSendOut -> downlink.bufferIn + + downlink.framedAllocate -> staticMemory.bufferAllocate[Ports_StaticMemory.downlink] + downlink.framedOut -> comm.send + downlink.bufferDeallocate -> fileDownlink.bufferReturn + + comm.deallocate -> staticMemory.bufferDeallocate[Ports_StaticMemory.downlink] + + } + + connections FaultProtection { + eventLogger.FatalAnnounce -> fatalHandler.FatalReceive + } + + connections RateGroups { + + # Block driver + blockDrv.CycleOut -> rateGroupDriverComp.CycleIn + + # Rate group 1 + rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup1] -> rateGroup1Comp.CycleIn + rateGroup1Comp.RateGroupMemberOut[0] -> SG1.schedIn + rateGroup1Comp.RateGroupMemberOut[1] -> SG2.schedIn + rateGroup1Comp.RateGroupMemberOut[2] -> chanTlm.Run + rateGroup1Comp.RateGroupMemberOut[3] -> fileDownlink.Run + rateGroup1Comp.RateGroupMemberOut[4] -> mathReceiver.schedIn + + # Rate group 2 + rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup2] -> rateGroup2Comp.CycleIn + rateGroup2Comp.RateGroupMemberOut[0] -> cmdSeq.schedIn + rateGroup2Comp.RateGroupMemberOut[1] -> sendBuffComp.SchedIn + rateGroup2Comp.RateGroupMemberOut[2] -> SG3.schedIn + rateGroup2Comp.RateGroupMemberOut[3] -> SG4.schedIn + + # Rate group 3 + rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup3] -> rateGroup3Comp.CycleIn + rateGroup3Comp.RateGroupMemberOut[0] -> $health.Run + rateGroup3Comp.RateGroupMemberOut[1] -> SG5.schedIn + rateGroup3Comp.RateGroupMemberOut[2] -> blockDrv.Sched + rateGroup3Comp.RateGroupMemberOut[3] -> fileUplinkBufferManager.schedIn + + } + + connections Ref { + sendBuffComp.Data -> blockDrv.BufferIn + blockDrv.BufferOut -> recvBuffComp.Data + } + + connections Sequencer { + cmdSeq.comCmdOut -> cmdDisp.seqCmdBuff + cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn + } + + connections Uplink { + + comm.allocate -> staticMemory.bufferAllocate[Ports_StaticMemory.uplink] + comm.$recv -> uplink.framedIn + uplink.framedDeallocate -> staticMemory.bufferDeallocate[Ports_StaticMemory.uplink] + + uplink.comOut -> cmdDisp.seqCmdBuff + cmdDisp.seqCmdStatus -> uplink.cmdResponseIn + + uplink.bufferAllocate -> fileUplinkBufferManager.bufferGetCallee + uplink.bufferOut -> fileUplink.bufferSendIn + uplink.bufferDeallocate -> fileUplinkBufferManager.bufferSendIn + fileUplink.bufferSendOut -> fileUplinkBufferManager.bufferSendIn + + } + + connections Math { + mathSender.mathOpOut -> mathReceiver.mathOpIn + mathReceiver.mathResultOut -> mathSender.mathResultIn + } + + } + +} diff --git a/docs/Tutorials/MathComponent/Tutorial.adoc b/docs/Tutorials/MathComponent/Tutorial.adoc new file mode 100644 index 0000000000..f8b9741146 --- /dev/null +++ b/docs/Tutorials/MathComponent/Tutorial.adoc @@ -0,0 +1,2228 @@ += Math Component Tutorial +:toc: left +:toclevels: 3 + +== Introduction + +This tutorial shows how to develop, test, and deploy a simple topology +consisting of two components: + +. `MathSender`: A component that receives commands and forwards work to `MathReceiver`. +. `MathReceiver`: A component that carries out arithmetic operations and returns the results +to `MathSender`. + +See the diagram below. + +[#math-top] +.A simple topology for arithmetic computation +image::png/top.png[Math Sender and Math Receiver] + +*What is covered:* The tutorial covers the following concepts: + +. Using the https://fprime-community.github.io/fpp[FPP modeling language] +to specify the types and ports used by the components. +. Using the F Prime build system to build the types and ports. +. Developing the `MathSender` component: Specifying the component, +building the component, +completing the {cpp} component implementation, and writing +component unit tests. +. Developing the `MathReceiver` component. +. Adding the new components and connections to the F Prime +`Ref` application. +. Using the F Prime Ground Data System (GDS) to run the updated `Ref` +application. + +*Prerequisites:* This tutorial assumes the following: + +. Basic knowledge of Unix: How to navigate in a shell and execute programs. +. Basic knowledge of git: How to create a branch. +. Basic knowledge of {cpp}, including class declarations, inheritance, +and virtual functions. + +If you have not yet installed F Prime on your system, do so now. +Follow the installation guide at `INSTALL.md` +in the https://github.com/nasa/fprime[F Prime git repository]. +You may also wish to work through the Getting Started tutorial at +`docs/GettingStarted/Tutorial.md`. + +*Git branch:* This tutorial is designed to work on the branch `release/v3.0.0`. + +Working on this tutorial will modify some files under version control in the +F Prime git repository. +Therefore it is a good idea to do this work on a new branch. +For example: + +[source,bash] +---- +git checkout release/v3.0.0 +git checkout -b math-tutorial +---- + +If you wish, you can save your work by committing to this branch. + +== The MathOp Type + +In F Prime, a *type definition* defines a kind of data that you can pass +between components or use in commands and telemetry. + +For this tutorial, we need one type definition. +It defines an enumeration called `MathOp`, which +represents a mathematical operation. + +We will add the specification for the `MathOp` type to the +`Ref` topology. +We will do this in three stages: + +. Construct the FPP model. +. Add the model to the project. +. Build the model. + +=== Construct the FPP Model + +*Create the MathTypes directory:* +Go to the directory `Ref` at the top-level of the +F Prime repository and run `mkdir MathTypes`. +This step creates a new directory `Ref/MathTypes`. +This directory will contain our new type. + +*Create the FPP model file:* +Now go into the directory `Ref/MathTypes`. +In that directory, create a file `MathTypes.fpp` with the following contents: + +[source,fpp] +---- +module Ref { + + @ A math operation + enum MathOp { + ADD @< Addition + SUB @< Subtraction + MUL @< Multiplication + DIV @< Division + } + +} +---- + +You can do this by typing, or by copy-paste. + +This file defines an enumeration or *enum* +with enumerated constants `ADD`, `SUB`, `MUL`, and `DIV`. +These four constants represent the operations +of addition, subtraction, multiplication, and division. +The enum also defines a type `MathOp`; the enumerated +constants are the values of this type. +For more information on enums, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Enums[_The FPP User's Guide_]. + +The enum `MathTypes` resides in an FPP module `Ref`. +An FPP module is like a {cpp} namespace: it encloses +several definitions, each of which is qualified with the +name of the module. +For more information on FPP modules, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Modules[_The FPP User's Guide_]. + +The text following a symbol `@` or `@<` is called an +*annotation*. +These annotations are carried through the parsing and +become comments in the generated code. +For more information, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Writing-Comments-and-Annotations[_The FPP User's Guide_]. + + +[[types_add]] +=== Add the Model to the Project + +*Create Ref/MathTypes/CMakeLists.txt:* +Create a file `Ref/MathTypes/CMakeLists.txt` with the following contents: + +[source,cmake] +---- +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathTypes.fpp" +) + +register_fprime_module() +---- + +This code will tell the build system how to build the FPP model. + +*Update Ref/CMakeLists.txt:* +Now we need to add the new directory to the `Ref` project. +To do that, open the file `Ref/CMakeLists.txt`. +This file should already exist; it was put there by the developers +of the `Ref` topology. +In this file, you should see several lines starting with `add_fprime_subdirectory`. +Immediately after the last of those lines, add the following new line: + +[source,cmake] +---- +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathTypes/") +---- + +[[types_build]] +=== Build the Model + +*Run the build:* +Do the following: + +. Go to the directory `Ref/MathTypes`. +. If you have not already run `fprime-util generate`, then do so now. +. Run the command `fprime-util build`. + +The output should indicate that the model built without any errors. +If not, try to identify and correct what is wrong, +either by deciphering the error output, or by going over the steps again. +If you get stuck, you can look at the <>. + +*Inspect the generated code:* +Now go to the directory `Ref/build-fprime-automatic-native/Ref/MathTypes` +(you may want to use `pushd`, or do this in a separate shell, +so you don't lose your current working directory). +The directory `build-fprime-automatic-native` is where all the +generated code lives for the "automatic native" build of the `Ref` +project. +Within that directory is a directory tree that mirrors the project +structure. +In particular, `Ref/build-fprime-automatic-native/Ref/MathTypes` +contains the generated code for `Ref/MathTypes`. + +Run `ls`. +You should see something like this: + +[source,bash] +---- +CMakeFiles MathOpEnumAc.cpp MathOpEnumAi.xml.prev cmake_install.cmake +Makefile MathOpEnumAc.hpp autocoder +---- + +The files `MathOpEnumAc.hpp` and +`MathOpEnumAc.cpp` are the auto-generated {cpp} files +corresponding to the `MathOp` enum. +You may wish to study the file `MathOpEnumAc.hpp`. +This file gives the interface to the {cpp} class `Ref::MathOp`. +All enum types have a similar auto-generated class +interface. + +[[types_ref]] +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathTypes`. +To build this implementation from a clean repository, +do the following: + +. Go to the `Ref` directory. + +. Run `cp -R ../docs/Tutorials/MathComponent/MathTypes .` + +. Update `Ref/CMakeLists.txt` as stated +<>. + +. Follow the steps for <>. + +If you have modified the repo, revise the steps accordingly. +For example, switch git branches, use `git stash` to stash +your changes, or move `MathTypes` to another directory such +as `MathTypes-saved`. + +[[ports]] +== The MathOp and MathResult Ports + +A *port* is the endpoint of a connection between +two components. +A *port definition* is like a function signature; +it defines the type of the data carried on a port. + +For this tutorial, we need two port definitions: + +* `MathOp` for sending an arithmetic operation request from +`MathSender` to `MathReceiver`. + +* `MathResult` for sending the result of an arithmetic +operation from `MathReceiver` to `MathSender`. + +We follow the same three steps as in the previous section. + +=== Construct the FPP Model + +*Create the MathPorts directory:* +Go to the directory `Ref` at the top-level of the +F Prime repository and run `mkdir MathPorts`. +This directory will contain our new ports. + +*Create the FPP model file:* +Now go into the directory `Ref/MathPorts`. +Create a file `MathPorts.fpp` with the following contents: + +[source,fpp] +---- +module Ref { + + @ Port for requesting an operation on two numbers + port MathOp( + val1: F32 @< The first operand + op: MathOp @< The operation + val2: F32 @< The second operand + ) + + @ Port for returning the result of a math operation + port MathResult( + result: F32 @< the result of the operation + ) + +} +---- + +This file defines the ports `MathOp` and `MathResult`. +`MathOp` has three formal parameters: a first operand, an +operation, and a second operand. +The operands have type `F32`, which represents a 32-bit +floating-point number. +The operation has type `MathOp`, which is the enum type +we defined in the previous section. +`MathResult` has a single formal parameter, the value of type `F32` +returned as the result of the operation. + +For more information about port definitions, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Ports[_The FPP User's Guide_]. + +=== Add the Model to the Project + +Add add the model +`Ref/MathPorts/MathPorts.fpp` to the `Ref` project. +Carry out the steps in the +<>, after +substituting `MathPorts` for `MathTypes`. + +=== Build the Model + +Carry out the steps in the +<>, +in directory `MathPorts` instead of `MathTypes`. +The generated code will go in +`Ref/build-fprime-automatic-native/Ref/MathPorts`. +For port definitions, the names of the auto-generated {cpp} +files end in `PortAc.hpp` and `PortAc.cpp`. +You can look at this code if you wish. +However, the auto-generated {cpp} port files are used +by the autocoded component implementations (described below); +you won't ever program directly against their interfaces. + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathPorts`. +To build this implementation, follow the steps +described for <>. + +[[math-sender]] +== The MathSender Component + +Now we can build and test the `MathSender` component. +There are five steps: + +. Construct the FPP model. +. Add the model to the project. +. Build the stub implementation. +. Complete the implementation. +. Write and run unit tests. + +=== Construct the FPP Model + +*Create the MathSender directory:* +Go to the directory `Ref` at the top-level of the +F Prime repository. +Run `mkdir MathSender` to create a directory for the new component. + +*Create the FPP model file:* +Now go into the directory `Ref/MathSender`. +Create a file `MathSender.fpp` with the following contents: + +[source,fpp] +---- +module Ref { + + @ Component for sending a math operation + active component MathSender { + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Port for sending the operation request + output port mathOpOut: MathOp + + @ Port for receiving the result + async input port mathResultIn: MathResult + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + + @ Command receive port + command recv port cmdIn + + @ Command registration port + command reg port cmdRegOut + + @ Command response port + command resp port cmdResponseOut + + @ Event port + event port eventOut + + @ Telemetry port + telemetry port tlmOut + + @ Text event port + text event port textEventOut + + @ Time get port + time get port timeGetOut + + # ---------------------------------------------------------------------- + # Commands + # ---------------------------------------------------------------------- + + @ Do a math operation + async command DO_MATH( + val1: F32 @< The first operand + op: MathOp @< The operation + val2: F32 @< The second operand + ) + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + @ Math command received + event COMMAND_RECV( + val1: F32 @< The first operand + op: MathOp @< The operation + val2: F32 @< The second operand + ) \ + severity activity low \ + format "Math command received: {f} {} {f}" + + @ Received math result + event RESULT( + result: F32 @< The math result + ) \ + severity activity high \ + format "Math result is {f}" + + # ---------------------------------------------------------------------- + # Telemetry + # ---------------------------------------------------------------------- + + @ The first value + telemetry VAL1: F32 + + @ The operation + telemetry OP: MathOp + + @ The second value + telemetry VAL2: F32 + + @ The result + telemetry RESULT: F32 + + } + +} +---- + +This code defines a component `Ref.MathSender`. +The component is *active*, which means it has its +own thread. + +Inside the definition of the `MathSender` component are +several specifiers. +We have divided the specifiers into five groups: + +. *General ports:* These are user-defined ports for +application-specific functions. +There are two general ports: an output port `mathOpOut` +of type `MathOp` and an input port `mathResultIn` of +type `MathResult`. +Notice that these port specifiers use the ports that +we defined <>. +The input port is *asynchronous*. +This means that invoking the port (i.e., sending +data on the port) puts a message on a queue. +The handler runs later, on the thread of this component. + +. *Special ports:* These are ports that have a special +meaning in F Prime. +There are ports for registering commands with the dispatcher, +receiving commands, sending command responses, emitting +event reports, emitting telemetry, and getting the time. + +. *Commands:* These are commands sent from the ground +or from a sequencer and dispatched to this component. +There is one command `DO_MATH` for doing a math operation. +The command is asynchronous. +This means that when the command arrives, it goes on a queue +and its handler is later run on the thread of this component. + +. *Events:* These are event reports that this component +can emit. +There are two event reports, one for receiving a command +and one for receiving a result. + +. *Telemetry:* These are *channels* that define telemetry +points that the this component can emit. +There are four telemetry channels: three for the arguments +to the last command received and one for the last +result received. + +For more information on defining components, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components[_The FPP User's Guide_]. + +[[math-sender_add-model]] +=== Add the Model to the Project + +*Create Ref/MathSender/CMakeLists.txt:* +Create a file `Ref/MathSender/CMakeLists.txt` with the following contents: + +[source,cmake] +---- +# Register the standard build +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathSender.cpp" + "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" +) +register_fprime_module() +---- + +This code will tell the build system how to build the FPP model +and component implementation. + +*Update Ref/CMakeLists.txt:* +Add `Ref/MathSender` to `Ref/CMakeLists.txt`, as we did +for <>. + +[[math-sender_build-stub]] +=== Build the Stub Implementation + +*Run the build:* +Go into the directory `Ref/MathTypes`. +Run the following commands: + +[source,bash] +---- +touch MathSender.cpp +fprime-util impl +---- + +The first command creates an empty file `MathSender.cpp`. +The build rules we wrote in the previous section expect +this file to be there. +After the second command, the build system should +run for a bit. +At the end there should be two new files +in the directory: +`MathSenderComponentImpl.cpp-template` and +`MathSenderComponentImpl.hpp-template`. + +Run the following commands: + +[source,bash] +---- +mv MathSenderComponentImpl.cpp-template MathSender.cpp +mv MathSenderComponentImpl.hpp-template MathSender.hpp +---- + +These commands produce a template, or stub implementation, +of the `MathSender` implementation class. +You will fill in this implementation class below. + +Now run the command `fprime-util build --jobs 4`. +The model and the stub implementation should build. +The option `--jobs 4` says to use four cores for the build. +This should make the build go faster. +You can use any number after `--jobs`, up to the number +of cores available on your system. + +*Inspect the generated code:* +The generated code resides in the directory +`Ref/fprime-build-automatic-native-ut/Ref/MathSender`. +You may wish to look over the file `MathSenderComponentAc.hpp` +to get an idea of the interface to the auto-generated +base class `MathSenderComponentBase`. +The `MathSender` implementation class is a derived class +of this base class. + +=== Complete the Implementation + +Now we can complete the stub implementation. +In an editor, open the file `MathSender.cpp`. + +*Fill in the DO_MATH command handler:* +You should see a stub handler for the `DO_MATH` +command that looks like this: + +[source,c++] +---- +void MathSender :: + DO_MATH_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + F32 val1, + MathOp op, + F32 val2 + ) +{ + // TODO + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); +} +---- + +The handler `DO_MATH_handler` is called when the `MathSender` +component receives a `DO_MATH` command. +This handler overrides the corresponding pure virtual +function in the auto-generated base class. +Fill in the handler so that it looks like this: + +[source,c++] +---- +void MathSender :: + DO_MATH_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + F32 val1, + MathOp op, + F32 val2 + ) +{ + this->tlmWrite_VAL1(val1); + this->tlmWrite_OP(op); + this->tlmWrite_VAL2(val2); + this->log_ACTIVITY_LO_COMMAND_RECV(val1, op, val2); + this->mathOpOut_out(0, val1, op, val2); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} +---- + +The first two arguments to the handler function provide +the command opcode and the command sequence number +(a unique identifier generated by the command dispatcher). +The remaining arguments are supplied when the command is sent, +for example, from the F Prime ground data system (GDS). +The implementation code does the following: + +. Emit telemetry and events. +. Invoke the `mathOpOut` port to request that `MathReceiver` +perform the operation. +. Send a command response indicating success. +The command response goes out on the special port +`cmdResponseOut`. + +In F Prime, every execution of a command handler must end by +sending a command response. +The proper behavior of other framework components (e.g., command +dispatcher, command sequencer) depends upon adherence to this rule. + +*Check the build:* +Run `fprime-util build` again to make sure that everything still builds. + +*Fill in the mathResultIn handler:* +You should see a stub handler for the `mathResultIn` +port that looks like this: + +[source,c++] +---- +void MathSender :: + mathResultIn_handler( + const NATIVE_INT_TYPE portNum, + F32 result + ) +{ + // TODO +} +---- + +The handler `mathResultIn_handler` is called when the `MathReceiver` +component code returns a result by invoking the `mathResultIn` port. +Again the handler overrides the corresponding pure virtual +function in the auto-generated base class. +Fill in the handler so that it looks like this: + +[source,c++] +---- +void MathSender :: + mathResultIn_handler( + const NATIVE_INT_TYPE portNum, + F32 result + ) +{ + this->tlmWrite_RESULT(result); + this->log_ACTIVITY_HI_RESULT(result); +} +---- + +The implementation code emits the result on the `RESULT` +telemetry channel and as a `RESULT` event report. + +*Check the build:* +Run `fprime-util build`. + +[[math-sender_unit]] +=== Write and Run Unit Tests + +*Unit tests* are an important part of FSW development. +At the component level, unit tests typically invoke input ports, send commands, +and check for expected values on output ports (including telemetry and event +ports). + +We will carry out the unit testing for the `MathSender` component +in three steps: + +. Set up the unit test environment +. Write and run one unit test +. Write and run additional unit tests + +[[math-sender_unit_setup]] +==== Set Up the Unit Test Environment + +*Create the stub Tester class:* +Do the following in directory `Ref/MathSender`: + +. Run `mkdir -p test/ut` to create the directory where +the unit tests will reside. + +. Run the command `fprime-util impl --ut`. +It should generate files `Tester.cpp` and `Tester.hpp`. + +. Move these files to the `test/ut` directory: + ++ +[source,bash] +---- +mv Tester.* test/ut +---- + +*Create a stub main.cpp file:* +Now go to the directory `Ref/MathSender/test/ut`. +In that directory, create a file `main.cpp` with the +following contents: + +[source,c++] +---- +#include "Tester.hpp" + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +---- + +This file is a stub for running tests using the +https://github.com/google/googletest[Google Test framework]. +Right now there aren't any tests to run; we will add one +in the next section. + +*Update Ref/MathSender/CMakeLists.txt:* +Go back to the directory `Ref/MathSender`. +Add the following lines to `CMakeLists.txt`: + +[source,cmake] +---- +# Register the unit test build +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp" +) +register_fprime_ut() +---- + +This code tells the build system how to build +and run the unit tests. + +*Run the build:* +Now we can check that the unit test build is working. + +. If you have not yet run `fprime-util generate --ut`, +then do so now. +This step generates the CMake build cache for the unit +tests. + +. Run `fprime-util build --ut`. +Everything should build without errors. + +*Inspect the generated code:* +The generated code is located at +`Ref/build-fprime-automatic-native-ut/Ref/MathSender`. +This directory contains two auto-generated classes: + +. `MathSenderGTestBase`: This is the direct base +class of `Tester`. +It provides a test interface implemented with Google Test +macros. + +. `MathSenderTesterBase`: This is the direct base +class of `MathSenderGTestBase`. +It provides basic features such as histories of port +invocations. +It is not specific to Google Test, so you can +use this class without Google Test if desired. + +You can look at the header files for these generated classes +to see what operations they provide. +In the next sections we will provide some example uses +of these operations. + +==== Write and Run One Test + +Now we will write a unit test that exercises the +`DO_MATH` command. +We will do this in three phases: + +. In the `Tester` class, add a helper function for sending the command and +checking the responses. +That way multiple tests can reuse the same code. + +. In the `Tester` class, write a test function that +calls the helper to run a test. + +. In the `main` function, write a Google Test macro +that invokes the test function. + +. Run the test. + +*Add a helper function:* +Go into the directory `Ref/MathSender/test/ut`. +In the file `Tester.hpp`, add the following lines +to the section entitled "Helper methods": + +[source,c++] +---- +//! Test a DO_MATH command +void testDoMath(MathOp op); +---- + +In the file `Tester.cpp`, add the corresponding +function body: + +[source,c++] +---- +void Tester :: + testDoMath(MathOp op) +{ + + // Pick values + + const F32 val1 = 2.0; + const F32 val2 = 3.0; + + // Send the command + + // pick a command sequence number + const U32 cmdSeq = 10; + // send DO_MATH command + this->sendCmd_DO_MATH(0, cmdSeq, val1, op, val2); + // retrieve the message from the message queue and dispatch the command to the handler + this->component.doDispatch(); + + // Verify command receipt and response + + // verify command response was sent + ASSERT_CMD_RESPONSE_SIZE(1); + // verify the command response was correct as expected + ASSERT_CMD_RESPONSE(0, MathSenderComponentBase::OPCODE_DO_MATH, cmdSeq, Fw::CmdResponse::OK); + + // Verify operation request on mathOpOut + + // verify that that one output port was invoked overall + ASSERT_FROM_PORT_HISTORY_SIZE(1); + // verify that the math operation port was invoked once + ASSERT_from_mathOpOut_SIZE(1); + // verify the arguments of the operation port + ASSERT_from_mathOpOut(0, val1, op, val2); + + // Verify telemetry + + // verify that 3 channels were written + ASSERT_TLM_SIZE(3); + // verify that the desired telemetry values were sent once + ASSERT_TLM_VAL1_SIZE(1); + ASSERT_TLM_VAL2_SIZE(1); + ASSERT_TLM_OP_SIZE(1); + // verify that the correct telemetry values were sent + ASSERT_TLM_VAL1(0, val1); + ASSERT_TLM_VAL2(0, val2); + ASSERT_TLM_OP(0, op); + + // Verify event reports + + // verify that one event was sent + ASSERT_EVENTS_SIZE(1); + // verify the expected event was sent once + ASSERT_EVENTS_COMMAND_RECV_SIZE(1); + // verify the correct event arguments were sent + ASSERT_EVENTS_COMMAND_RECV(0, val1, op, val2); + +} +---- + +This function is parameterized over different +operations. +It is divided into five sections: sending the command, +checking the command response, checking the output on +`mathOpOut`, checking telemetry, and checking events. +The comments explain what is happening in each section. +For further information about the F Prime unit test +interface, see the F Prime User's Guide. + +Notice that after sending the command to the component, we call +the function `doDispatch` on the component. +We do this in order to simulate the behavior of the active +component in a unit test environment. +In a flight configuration, the component has its own thread, +and the thread blocks on the `doDispatch` call until another +thread puts a message on the queue. +In a unit test context, there is only one thread, so the pattern +is to place work on the queue and then call `doDispatch` on +the same thread. + +There are a couple of pitfalls to watch out for with this pattern: + +. If you put work on the queue and forget to call `doDispatch`, +the work won't get dispatched. +Likely this will cause a unit test failure. + +. If you call `doDispatch` without putting work on the queue, +the unit test will block until you kill the process (e.g., +with control-C). + +*Write a test function:* +Next we will write a test function that calls +`testDoMath` to test an `ADD` operation. +In `Tester.hpp`, add the following line in the +section entitled "Tests": + +[source,c++] +---- +//! Test an ADD command +void testAddCommand(); +---- + +In `Tester.cpp`, add the corresponding function +body: + +[source,c++] +---- +void Tester :: + testAddCommand() +{ + this->testDoMath(MathOp::ADD); +} +---- + +This function calls `testDoMath` to test an `ADD` command. + +*Write a test macro:* +Add the following code to the file `main.cpp`, +before the definition of the `main` function: + +[source,c++] +---- +TEST(Nominal, AddCommand) { + Ref::Tester tester; + tester.testAddCommand(); +} +---- + +The `TEST` macro is an instruction to Google Test to run a test. +`Nominal` is the name of a test suite. +We put this test in the `Nominal` suite because it addresses +nominal (expected) behavior. +`AddCommand` is the name of the test. +Inside the body of the macro, the first line declares a new +object `tester` of type `Tester`. +We typically declare a new object for each unit test, so that +each test starts in a fresh state. +The second line invokes the function `testAddCommand` +that we wrote in the previous section. + +*Run the test:* +Go back to directory `Ref/MathSender`. +Run the command `fprime-util check`. +The build system should compile and run the unit +tests. +You should see output indicating that the test ran +and passed. + +As an exercise, try the following: + +. Change the behavior of the component +so that it does something correct. +For example, try adding one to a telemetry +value before emitting it. + +. Rerun the test and observe what happens. + +==== Write and Run More Tests + +*Add more command tests:* +Try to follow the pattern given in the previous +section to add three more tests, one each +for operations `SUB`, `MUL`, and `DIV`. +Most of the work should be done in the helper +that we already wrote. +Each new test requires just a short test function +and a short test macro. + +Run the tests to make sure everything compiles and +the tests pass. + +*Add a result test:* +Add a test for exercising the scenario in which the `MathReceiver` +component sends a result back to `MathSender`. + +. Add the following function signature in the "Tests" +section of to `Tester.hpp`: + ++ +[source,c++] +---- +//! Test receipt of a result +void testResult(); +---- + +. Add the corresponding function body in `Tester.cpp`: + ++ +[source,cpp] +---- +void Tester :: + testResult() +{ + // Generate an expected result + const F32 result = 10.0; + // reset all telemetry and port history + this->clearHistory(); + // call result port with result + this->invoke_to_mathResultIn(0, result); + // retrieve the message from the message queue and dispatch the command to the handler + this->component.doDispatch(); + // verify one telemetry value was written + ASSERT_TLM_SIZE(1); + // verify the desired telemetry channel was sent once + ASSERT_TLM_RESULT_SIZE(1); + // verify the values of the telemetry channel + ASSERT_TLM_RESULT(0, result); + // verify one event was sent + ASSERT_EVENTS_SIZE(1); + // verify the expected event was sent once + ASSERT_EVENTS_RESULT_SIZE(1); + // verify the expect value of the event + ASSERT_EVENTS_RESULT(0, result); +} +---- + ++ +This code is similar to the helper function in the previous section. +The main difference is that it invokes a port directly +(the `mathResultIn` port) instead of sending a command. + +. Add the following test macro to `main.cpp`: + ++ +[source,cpp] +---- +TEST(Nominal, Result) { + Ref::Tester tester; + tester.testResult(); +} +---- + +. Run the tests. +Again you can try altering something in the component code +to see what effect it has on the test output. + +[[math-sender_exercise]] +==== Exercise: Random Testing + +F Prime provides a module called `STest` +that provides helper classes and functions for writing +unit tests. +As an exercise, use the interface provided by +`STest/STest/Pick.hpp` to pick random values to use in the +tests instead of using hard-coded values such as 2.0, 3.0, +and 10. + +*Modifying the code:* You will need to do the following: + +. Add `#include "STest/Pick/Pick.hpp"` to `Tester.cpp`. + +. Add the following +line to `Ref/MathSender/CMakeLists.txt`, before `register_fprime_ut`: + ++ +[source,cmake] +---- +set(UT_MOD_DEPS STest) +---- + ++ +This line tells the build system to make the unit test build +depend on the `STest` build module. + +. Add `#include STest/Random/Random.hpp` to `main.cpp`. + +. Add the following line to the `main` function of `main.cpp`, +just before the return statement: + ++ +[source,cpp] +---- +STest::Random::seed(); +---- + ++ +This line seeds the random number generator used by STest. + +*Running the tests:* +Recompile and rerun the tests. +Now go to +`Ref/build-fprime-automatic-native-ut/Ref/MathSender` and inspect the +file `seed-history`. +This file is a log of random seed values. +Each line represents the seed used in the corresponding run. + +*Fixing the random seed:* +Sometimes you may want to run a test with a particular seed value, +e.g., for replay debugging. +To do this, put the seed value into a file `seed` in the same +directory as `seed-history`. +If the file `seed` exists, then STest will use the seed it contains instead +of generating a new seed. + +Try the following: + +. Copy the last value _S_ of `seed-history` into `seed`. + +. In `Ref/MathSender`, re-run the unit tests a few times. + +. Inspect `Ref/build-fprime-automatic-native-ut/Ref/MathSender/seed-history`. +You should see that the value _S_ was used in the runs you just did +(corresponding to the last few entries in `seed-history`). + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathSender`. + +== The MathReceiver Component + +Now we will build and test the `MathReceiver` component. +We will use the same five steps as for the +<>. + +=== Construct the FPP Model + +*Create the MathReceiver directory:* +Create the directory `Ref/MathReceiver`. + +*Create the FPP model file:* +In directory `Ref/MathReceiver`, create a file +`MathReceiver.fpp` with the following contents: + +[source,fpp] +---- +module Ref { + + @ Component for receiving and performing a math operation + queued component MathReceiver { + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Port for receiving the math operation + async input port mathOpIn: MathOp + + @ Port for returning the math result + output port mathResultOut: MathResult + + @ The rate group scheduler input + sync input port schedIn: Svc.Sched + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + + @ Command receive + command recv port cmdIn + + @ Command registration + command reg port cmdRegOut + + @ Command response + command resp port cmdResponseOut + + @ Event + event port eventOut + + @ Parameter get + param get port prmGetOut + + @ Parameter set + param set port prmSetOut + + @ Telemetry + telemetry port tlmOut + + @ Text event + text event port textEventOut + + @ Time get + time get port timeGetOut + + # ---------------------------------------------------------------------- + # Parameters + # ---------------------------------------------------------------------- + + @ The multiplier in the math operation + param FACTOR: F32 default 1.0 id 0 \ + set opcode 10 \ + save opcode 11 + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + @ Factor updated + event FACTOR_UPDATED( + val: F32 @< The factor value + ) \ + severity activity high \ + id 0 \ + format "Factor updated to {f}" \ + throttle 3 + + @ Math operation performed + event OPERATION_PERFORMED( + val: MathOp @< The operation + ) \ + severity activity high \ + id 1 \ + format "{} operation performed" + + @ Event throttle cleared + event THROTTLE_CLEARED \ + severity activity high \ + id 2 \ + format "Event throttle cleared" + + # ---------------------------------------------------------------------- + # Commands + # ---------------------------------------------------------------------- + + @ Clear the event throttle + async command CLEAR_EVENT_THROTTLE \ + opcode 1 + + # ---------------------------------------------------------------------- + # Telemetry + # ---------------------------------------------------------------------- + + @ The operation + telemetry OPERATION: MathOp id 0 + + @ Multiplication factor + telemetry FACTOR: F32 id 1 + + } + +} +---- + +This code defines a component `Ref.MathReceiver`. +The component is *queued*, which means it has a queue +but no thread. +Work occurs when the thread of another component invokes +the `schedIn` port of this component. + +We have divided the specifiers of this component into six groups: + +. *General ports:* There are three ports: +an input port `mathOpIn` for receiving a math operation, +an output port `mathResultOut` for sending a math result, and +an input port `schedIn` for receiving invocations from the scheduler. +`mathOpIn` is asynchronous. +That means invocations of `mathOpIn` put messages on a queue. +`schedIn` is synchronous. +That means invocations of `schedIn` immediately call the +handler function to do work. + +. *Special ports:* +As before, there are special ports for commands, events, telemetry, +and time. +There are also special ports for getting and setting parameters. +We will explain the function of these ports below. + +. *Parameters:* There is one *parameter*. +A parameter is a constant that is configurable by command. +In this case there is one parameter `FACTOR`. +It has the default value 1.0 until its value is changed by command. +When doing math, the `MathReceiver` component performs the requested +operation and then multiplies by this factor. +For example, if the arguments of the `mathOpIn` port +are _v1_, `ADD`, and _v2_, and the factor is _f_, +then the result sent on `mathResultOut` is +_(v1 + v2) f_. + +. *Events:* There are three event reports: + +.. `FACTOR_UPDATED`: Emitted when the `FACTOR` parameter +is updated by command. +This event is *throttled* to a limit of three. +That means that after the event is emitted three times +it will not be emitted any more, until the throttling +is cleared by command (see below). + +.. `OPERATION_PERFORMED`: Emitted when this component +performs a math operation. + +.. `THROTTLE_CLEARED`: Emitted when the event throttling +is cleared. + +. *Commands:* There is one command for clearing +the event throttle. + +. *Telemetry:* +There two telemetry channels: one for reporting +the last operation received and one for reporting +the factor parameter. + +For the parameters, events, commands, and telemetry, we chose +to put in all the opcodes and identifiers explicitly. +These can also be left implicit, as in the `MathSender` +component example. +For more information, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components[_The FPP User's Guide_]. + +=== Add the Model to the Project + +Follow the steps given for the +<>. + +=== Build the Stub Implementation + +Follow the same steps as for the +<>. + +=== Complete the Implementation + +*Fill in the mathOpIn handler:* +In `MathReceiver.cpp`, complete the implementation of +`mathOpIn_handler` so that it looks like this: + +[source,cpp] +---- +void MathReceiver :: + mathOpIn_handler( + const NATIVE_INT_TYPE portNum, + F32 val1, + const MathOp& op, + F32 val2 + ) +{ + + // Get the initial result + F32 res = 0.0; + switch (op.e) { + case MathOp::ADD: + res = val1 + val2; + break; + case MathOp::SUB: + res = val1 - val2; + break; + case MathOp::MUL: + res = val1 * val2; + break; + case MathOp::DIV: + res = val1 / val2; + break; + default: + FW_ASSERT(0, op.e); + break; + } + + // Get the factor value + Fw::ParamValid valid; + F32 factor = paramGet_FACTOR(valid); + FW_ASSERT( + valid.e == Fw::ParamValid::VALID || valid.e == Fw::ParamValid::DEFAULT, + valid.e + ); + + // Multiply result by factor + res *= factor; + + // Emit telemetry and events + this->log_ACTIVITY_HI_OPERATION_PERFORMED(op); + this->tlmWrite_OPERATION(op); + + // Emit result + this->mathResultOut_out(0, res); + +} +---- + +This code does the following: + +. Compute an initial result based on the input values and +the requested operation. + +. Get the value of the factor parameter. +Check that the value is a valid value from the parameter +database or a default parameter value. + +. Multiply the initial result by the factor to generate +the final result. + +. Emit telemetry and events. + +. Emit the result. + +Note that in step 1, `op` is an enum (a {cpp} class type), and `op.e` +is the corresponding numeric value (an integer type). +Note also that in the `default` case we deliberately fail +an assertion. +This is a standard pattern for exhaustive case checking. +We should never hit the assertion. +If we do, then a bug has occurred: we missed a case. + +*Fill in the schedIn handler:* +In `MathReceiver.cpp`, complete the implementation of +`schedIn_handler` so that it looks like this: + +[source,cpp] +---- +void MathReceiver :: + schedIn_handler( + const NATIVE_INT_TYPE portNum, + NATIVE_UINT_TYPE context + ) +{ + U32 numMsgs = this->m_queue.getNumMsgs(); + for (U32 i = 0; i < numMsgs; ++i) { + (void) this->doDispatch(); + } +} +---- + +This code dispatches all the messages on the queue. +Note that for a queued component, we have to do this +dispatch explicitly in the `schedIn` handler. +For an active component, the framework auto-generates +the dispatch code. + +*Fill in the CLEAR_EVENT_THROTTLE command handler:* +In `MathReceiver.cpp`, complete the implementation of +`CLEAR_EVENT_THROTTLE_cmdHandler` so that it looks like this: + +[source,cpp] +---- +void MathReceiver :: + CLEAR_EVENT_THROTTLE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) +{ + // clear throttle + this->log_ACTIVITY_HI_FACTOR_UPDATED_ThrottleClear(); + // send event that throttle is cleared + this->log_ACTIVITY_HI_THROTTLE_CLEARED(); + // reply with completion status + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} +---- + +The call to `log_ACTIVITY_HI_FACTOR_UPDATED_ThrottleClear` clears +the throttling of the `FACTOR_UPDATED` event. +The next two lines send a notification event and send +a command response. + +*Add a parameterUpdated function:* +Add the following function to `MathReceiver.cpp`. +You will need to add the corresponding function header +to `MathReceiver.hpp`. + +[source,cpp] +---- +void MathReceiver :: + parameterUpdated(FwPrmIdType id) +{ + switch (id) { + case PARAMID_FACTOR: { + Fw::ParamValid valid; + F32 val = this->paramGet_FACTOR(valid); + FW_ASSERT( + valid.e == Fw::ParamValid::VALID || valid.e == Fw::ParamValid::DEFAULT, + valid.e + ); + this->log_ACTIVITY_HI_FACTOR_UPDATED(val); + break; + } + default: + FW_ASSERT(0, id); + break; + } +} +---- + +This code implements an optional function that, if present, +is called when a parameter is updated by command. +The parameter identifier is passed in as the `id` argument +of the function. +Here we do the following: + +. If the parameter identifier is `PARAMID_FACTOR` (the parameter +identifier corresponding to the `FACTOR` parameter, +then get the parameter value and emit an event report. + +. Otherwise fail an assertion. +This code should never run, because there are no other +parameters. + +=== Write and Run Unit Tests + +==== Set up the Unit Test Environment + +. Follow the steps given for the +<>. + +. Follow the steps given under *Modifying the code* +for the +<>, +so that you can use STest to pick random values. + +==== Add Helper Code + +*Add a ThrottleState enum class:* +Add the following code to the beginning of the +`Tester` class in `Tester.hpp`: + +[source,cpp] +---- +private: + + // ---------------------------------------------------------------------- + // Types + // ---------------------------------------------------------------------- + + enum class ThrottleState { + THROTTLED, + NOT_THROTTLED + }; +---- + +This code defines a {cpp} enum class for recording whether an +event is throttled. + +*Add helper functions:* +Add each of the functions described below to the +"Helper methods" section of `Tester.cpp`. +For each function, you must add +the corresponding function prototype to `Tester.hpp`. +After adding each function, compile the unit tests +to make sure that everything still compiles. +Fix any errors that occur. + +Add a `pickF32Value` function. + +[source,cpp] +---- +F32 Tester :: + pickF32Value() +{ + const F32 m = 10e6; + return m * (1.0 - 2 * STest::Pick::inUnitInterval()); +} +---- + +This function picks a random `F32` value in the range +_[ -10^6, 10^6 ]_. + +Add a `setFactor` function. + +[source,cpp] +---- +void Tester :: + setFactor( + F32 factor, + ThrottleState throttleState + ) +{ + // clear history + this->clearHistory(); + // set the parameter + this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); + const U32 instance = STest::Pick::any(); + const U32 cmdSeq = STest::Pick::any(); + this->paramSend_FACTOR(instance, cmdSeq); + if (throttleState == ThrottleState::NOT_THROTTLED) { + // verify the parameter update notification event was sent + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_FACTOR_UPDATED_SIZE(1); + ASSERT_EVENTS_FACTOR_UPDATED(0, factor); + } + else { + ASSERT_EVENTS_SIZE(0); + } +} +---- + +This function does the following: + +. Clear the test history. + +. Send a command to the component to set the `FACTOR` parameter +to the value `factor`. + +. If `throttleState` is `NOT_THROTTLED`, then check +that the event was emitted. +Otherwise check that the event was throttled (not emitted). + +Add a function `computeResult` to `Tester.cpp`. + +[source,cpp] +---- +F32 Tester :: + computeResult( + F32 val1, + MathOp op, + F32 val2, + F32 factor + ) +{ + F32 result = 0; + switch (op.e) { + case MathOp::ADD: + result = val1 + val2; + break; + case MathOp::SUB: + result = val1 - val2; + break; + case MathOp::MUL: + result = val1 * val2; + break; + case MathOp::DIV: + result = val1 / val2; + break; + default: + FW_ASSERT(0, op.e); + break; + } + result *= factor; + return result; +} +---- + +This function carries out the math computation of the +math component. +By running this function and comparing, we can +check the output of the component. + +Add a `doMathOp` function to `Tester.cpp`. + +[source,cpp] +---- +void Tester :: + doMathOp( + MathOp op, + F32 factor + ) +{ + + // pick values + const F32 val1 = pickF32Value(); + const F32 val2 = pickF32Value(); + + // clear history + this->clearHistory(); + + // invoke operation port with add operation + this->invoke_to_mathOpIn(0, val1, op, val2); + // invoke scheduler port to dispatch message + const U32 context = STest::Pick::any(); + this->invoke_to_schedIn(0, context); + + // verify the result of the operation was returned + + // check that there was one port invocation + ASSERT_FROM_PORT_HISTORY_SIZE(1); + // check that the port we expected was invoked + ASSERT_from_mathResultOut_SIZE(1); + // check that the component performed the operation correctly + const F32 result = computeResult(val1, op, val2, factor); + ASSERT_from_mathResultOut(0, result); + + // verify events + + // check that there was one event + ASSERT_EVENTS_SIZE(1); + // check that it was the op event + ASSERT_EVENTS_OPERATION_PERFORMED_SIZE(1); + // check that the event has the correct argument + ASSERT_EVENTS_OPERATION_PERFORMED(0, op); + + // verify telemetry + + // check that one channel was written + ASSERT_TLM_SIZE(1); + // check that it was the op channel + ASSERT_TLM_OPERATION_SIZE(1); + // check for the correct value of the channel + ASSERT_TLM_OPERATION(0, op); + +} +---- + +This function is similar to the `doMath` helper function that +we wrote for the `MathSender` component. +Notice that the method for invoking a port is different. +Since the component is queued, we don't call `doDispatch` +directly. +Instead we invoke `schedIn`. + +==== Write and Run Tests + +For each of the tests described below, you must add the +corresponding function prototype to `Tester.hpp` +and the corresponding test macro to `main.cpp`. +If you can't remember how to do it, look back at the +`MathSender` examples. +After writing each test, run all the tests and make sure +that they pass. + +*Write an ADD test:* +Add the following function to the "Tests" section of `Tester.cpp`: + +[source,cpp] +---- +void Tester :: + testAdd() +{ + // Set the factor parameter by command + const F32 factor = pickF32Value(); + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + // Do the add operation + this->doMathOp(MathOp::ADD, factor); +} +---- + +This function calls the `setFactor` helper function +to set the factor parameter. +Then it calls the `doMathOp` function to +do a math operation. + +*Write a SUB test:* +Add the following function to the "Tests" section of `Tester.cpp`: + +[source,cpp] +---- +void Tester :: + testSub() +{ + // Set the factor parameter by loading parameters + const F32 factor = pickF32Value(); + this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); + this->component.loadParameters(); + // Do the operation + this->doMathOp(MathOp::SUB, factor); +} +---- + +This test is similar to `testAdd`, but it shows +another way to set a parameter. +`testAdd` showed how to set a parameter by command. +You can also set a parameter by initialization, as follows: + +. Call the `paramSet` function as shown. +This function sets the parameter value in +the part of the test harness that mimics the behavior of the +parameter database component. + +. Call the `loadParameters` function as shown. +In flight, the function `loadParameters` is typically called at the +start of FSW to load the parameters from the database; +here it loads the parameters from the test harness. +There is no command to update a parameter, so `parameterUpdated` +is not called, and no event is emitted. + +As before, after setting the parameter we call `doMathOp` +to do the operation. + +*Write a MUL test:* +This test is the same as the ADD test, except that it +uses MUL instead of add. + +*Write a DIV test:* +This test is the same as the SUB test, except that it +uses DIV instead of SUB. + +*Write a throttle test:* +Add the following function to the "Tests" section of `Tester.cpp`: + +[source,cpp] +---- +void Tester :: + testThrottle() +{ + + // send the number of commands required to throttle the event + // Use the autocoded value so the unit test passes if the + // throttle value is changed + const F32 factor = pickF32Value(); + for ( + U16 cycle = 0; + cycle < MathReceiverComponentBase::EVENTID_FACTOR_UPDATED_THROTTLE; + cycle++ + ) { + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + } + + // Event should now be throttled + this->setFactor(factor, ThrottleState::THROTTLED); + + // send the command to clear the throttle + this->sendCmd_CLEAR_EVENT_THROTTLE(INSTANCE, CMD_SEQ); + // invoke scheduler port to dispatch message + const U32 context = STest::Pick::any(); + this->invoke_to_schedIn(0, context); + // verify clear event was sent + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_THROTTLE_CLEARED_SIZE(1); + + // Throttling should be cleared + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + +} +---- + +This test first loops over the throttle count, which is stored +for us in the constant `EVENTID_FACTOR_UPDATED_THROTTLE` +of the `MathReceiver` component base class. +On each iteration, it calls `setFactor`. +At the end of this loop, the `FACTOR_UPDATED` event should be +throttled. + +Next the test calls `setFactor` with a second argument of +`ThrottleState::THROTTLED`. +This code checks that the event is throttled. + +Next the test sends the command `CLEAR_EVENT_THROTTLE`, +checks for the corresponding notification event, +and checks that the throttling is cleared. + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathReceiver`. + +=== Exercises + +==== Adding Telemetry + +Add a telemetry channel that records the number of math +operations performed. + +. Add the channel to the FPP model. + +. In the component implementation class, add a member +variable `numMathOps` of type `U32`. +Initialize the variable to zero in the class constructor. + +. Revise the `mathOpIn` handler so that it increments +`numMathOps` and emits the updated value as telemetry. + +. Revise the unit tests to cover the new behavior. + +==== Error Handling + +Think about what will happen if the floating-point +math operation performed by `MathReceiver` causes an error. +For example, suppose that `mathOpIn` is invoked with `op = DIV` +and `val2 = 0.0`. +What will happen? +As currently designed and implemented, the `MathReceiver` +component will perform the requested operation. +On some systems the result will be `INF` (floating-point infinity). +In this case, the result will be sent back to `MathSender` +and reported in the usual way. +On other systems, the hardware could issue a floating-point exception. + +Suppose you wanted to handle the case of division by zero +explicitly. +How would you change the design? +Here are some questions to think about: + +. How would you check for division by zero? +Note that `val2 = 0.0` is not the only case in which a division +by zero error can occur. +It can also occur for very small values of `val2`. + +. Should the error be caught in `MathSender` or `MathReceiver`? + +. Suppose the design says that `MathSender` catches the error, +and so never sends requests to `MathReceiver` to divide by zero. +What if anything should `MathReceiver` do if it receives +a divide by zero request? +Carry out the operation normally? +Emit a warning? +Fail a FSW assertion? + +. If the error is caught by `MathReceiver`, does the +interface between the components have to change? +If so, how? +What should `MathSender` do if `MathReceiver` +reports an error instead of a valid result? + +Revise the MathSender and MathReceiver components to implement your +ideas. +Add unit tests covering the new behavior. + +== Updating the Ref Deployment + +The next step in the tutorial is to define instances of the +`MathSender` and `MathReceiver` components and add them +to the `Ref` topology. + +=== Defining the Component Instances + +Go to the directory `Ref/Top` and open the file `instances.fpp`. +This file defines the instances used in the topology for the +`Ref` application. +Update this file as described below. + +*Define the mathSender instance:* +At the end of the section entitled "Active component instances," +add the following lines: + +[source,fpp] +---- +instance mathSender: Ref.MathSender base id 0xE00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 100 +---- + +This code defines an instance `mathSender` of component +`MathSender`. +It has *base identifier* 0xE00. +FPP adds the base identifier to each the relative identifier +defined in the component to compute the corresponding +identifier for the instance. +For example, component `MathSender` has a telemetry channel +`MathOp` with identifier 1, so instance `mathSender` +has a command `MathOp` with identifier 0xE01. + +The following lines define the queue size, stack size, +and thread priority for the active component. +Here we give `mathSender` the default queue size +and stack size and a priority of 100. + +*Define the mathReceiver instance:* +At the end of the section "Queued component instances," +add the following lines: + +[source,fpp] +---- +instance mathReceiver: Ref.MathReceiver base id 0x2700 \ + queue size Default.queueSize +---- + +This code defines an instance `mathReceiver` of +component `MathReceiver`. +It has base identifier 0x2700 and the default queue size. + +*More information:* +For more information on defining component instances, +see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Component-Instances[_The FPP User's Guide_]. + +=== Updating the Topology + +Go to the directory `Ref/Top` and open the file `topology.fpp`. +This file defines the topology for the `Ref` application. +Update this file as described below. + +*Add the new instances:* +You should see a list of instances, each of which begins +with the keyword `instance`. +After the line `instance linuxTime`, add the following +lines: + +[source,fpp] +---- +instance mathSender +instance mathReceiver +---- + +These lines add the `mathSender` and `mathReceiver` +instances to the topology. + +*Check for unconnected ports:* +This capability does not yet exist in the F Prime build system. +When it does, you will be able to see a list of ports +that are unconnected in the `Ref` topology. +Those ports will include the ports for the new instances +`mathSender` and `mathReceiver`. + +*Connect mathReceiver to rate group 1:* +Find the line that starts `connections RateGroups`. +This is the beginning of the definition of the `RateGroups` +connection graph. +Inside the block of that definition, +find the line +`rateGroup1Comp.RateGroupMemberOut[3] pass:[->] fileDownlink.Run`. +After that line, add the line + +[source,fpp] +---- +rateGroup1Comp.RateGroupMemberOut[4] -> mathReceiver.schedIn +---- + +This line adds the connection that drives the `schedIn` +port of the `mathReceiver` component instance. + +*Re-run the check for unconnected ports:* +When this capability exists, you will be able to see +that `mathReceiver.schedIn` is now connected +(it no longer appears in the list). + +*Add the Math connections:* +Find the Uplink connections that begin with the line +`connections Uplink`. +After the block of that definition, add the following +lines: + +[source,fpp] +---- +connections Math { + mathSender.mathOpOut -> mathReceiver.mathOpIn + mathReceiver.mathResultOut -> mathSender.mathResultIn +} +---- + +These lines add the connections between the `mathSender` +and `mathReceiver` instances. + +*Re-run the check for unconnected ports:* +When this capability exists, you will be able to see +that the `mathSender` and `mathReceiver` ports are connected. + +*More information:* +For more information on defining topologies, +see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Topologies[_The FPP User's Guide_]. + +=== Building the Ref Deployment + +Go to the `Ref` directory. +Run `fprime-util build --jobs 4`. +The updated deployment should build without errors. +The generated files are located at +`Ref/build-fprime-automatic-native/Ref/Top`. + +=== Visualizing the Ref Topology + +Now we will see how to create a visualization (graphical rendering) +of the Ref topology. + +*Generate the layout:* +For this step, we will use the F Prime Layout (FPL) tool. +If FPL is not installed on your system, then install it how: +clone +https://github.com/fprime-community/fprime-layout[this +repository] and follow the instructions. + +In directory `Ref/Top`, run the following commands in an sh-compatible +shell such as bash. +If you are using a different shell, you can run `sh` +to enter the `sh` shell, run these commands, and enter +`exit` when done. +Or you can stay in your preferred shell and adjust these commands +appropriately. + +[source,bash] +---- +cp ../build-fprime-automatic-native/Ref/Top/RefTopologyAppAi.xml . +mkdir visual +cd visual +fpl-extract-xml < ../RefTopologyAppAi.xml +mkdir Ref +for file in `ls *.xml` +do +echo "laying out $file" +base=`basename $file .xml` +fpl-convert-xml $file | fpl-layout > Ref/$base.json +done +---- + +This step extracts the connection graphs from the topology XML and +converts each one to a JSON layout file. + +*Render the layout:* +For this step, we will use the F Prime Visualizer (FPV) tool. +If FPV is not installed on your system, then install it now: +clone +https://github.com/fprime-community/fprime-visual[this +repository] and follow the instructions. + +In directory `Ref/Top`, run the following commands in an sh-compatible +shell. +Replace `[path to fpv root]` with the path to the +root of the FPV repo on your system. + +[source,bash] +---- +echo DATA_FOLDER=Ref/ > .fpv-env +nodemon [path to fpv root]/server/index.js ./.fpv-env +---- + +You should see the FPV server application start up on the +console. + +Now open a browser and navigate to `http://localhost:3000`. +You should see a Topology menu at the top of the window +and a rendering of the Command topology below. +Select Math from the topology menu. +You should see a rendering of the Math topology. +It should look similar to <>. + +You can use the menu to view other topology graphs. +When you are done, close the browser window and +type control-C in the console to shut down the FPV server. + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/Top`. +To build this implementation, copy the files +`instances.fpp` and `topology.fpp` from +that directory to `Ref/Top`. + +== Running the Ref Deployment + +Now we will use the F Prime Ground Data System (GDS) to run the Ref deployment. +Go to the `Ref` directory and run `fprime-gds`. +You should see some activity on the console. +The system is starting the Ref deployment executable, starting the GDS, +and connecting them over the local network on your machine. +After several seconds, a browser window should appear. + +=== Sending a Command + +At the top of the window are several buttons, each of which corresponds to +a GDS view. +Select the Commanding button (this is the view that is selected +when you first start the GDS). +In the Mnemonic menu, start typing `mathSender.DO_MATH` in the text box. +As you type, the GDS will filter the menu selections. +When only one choice remains, stop typing and press return. +You should see three boxes appear: + +. A text box for entering `val1`. +. A menu for entering `op`. +. A text box for entering `val2`. + +Fill in the arguments corresponding to the operation `1 + 2`. +You can use the tab key to move between the boxes. +When you have done this, click the Send Command button. +You should see a table entry at the bottom of the window +indicating that the command was sent. + +=== Checking Events + +Now click on the Events button at the top of the window. +The view changes to the Events tab. +You should see events indicating that the command you sent was +dispatched, received, and completed. +You should also see events indicating that `mathReceiver` +performed an `ADD` operation and `mathSender` +received a result of 3.0. + +=== Checking Telemetry + +Click on the Channels button at the top of the window. +You should see a table of telemetry channels. +Each row corresponds to the latest value of a telemetry +channel received by the GDS. +You should see the channels corresponding to the input +values, the operation, and the result. + +=== Setting Parameters + +Go back to the Commanding tab. +Select the command `mathReceiver.FACTOR_PRM_SET`. +This is an auto-generated command for setting the +parameter `FACTOR`. +Type the value 2.0 in the `val` box and click Send Command. +Check the events to see that the command was dispatched +and executed. +You should also see the events sent by the code +that you implemented. + +In the Commanding tab, issue the command `1 + 2` again. +Check the Events tab. +Because the factor is now 2.0, you should see a result +value of 6.0. + +=== Saving Parameters + +When you set a parameter by command, the new parameter +value resides in the component that receives the command. +At this point, if you stop and restart FSW, the parameter +will return to its original value (the value before you +sent the command). + +At some point you may wish to update parameters more permanently. +You can do this by saving them to non-volatile storage. +For the Ref application, "non-volatile storage" means the +file system on your machine. + +To save the parameter `mathReceiver.FACTOR` to non-volatile storage, +do the following: + +. Send the command `mathReceiver.FACTOR_PRM_SAVE`. +This command saves the parameter value to the *parameter database*, +which is a standard F Prime component for storing system parameters. + +. Send the command `prmDb.PRM_SAVE_FILE`. +This command saves the parameter values in the parameter database +to non-volatile storage. + +Note that saving parameters is a two-step process. +The first step copies a single parameter from a component +to the database. +The second step saves all parameters in the database +to the disk. +If you do only the first step, the parameter will not be +saved to the disk. + +=== GDS Logs + +As it runs, the GDS writes a log into a subdirectory of `Ref/logs`. +The subdirectory is stamped with the current date. +Go into the directory for the run you just performed. +(If the GDS is still running, you will have to do this in a +different shell.) +You should see the following logs, among others: + +* `Ref.log`: FSW console output. +* `command.log`: Commands sent. +* `event.log`: Event reports received. +* `channel.log`: Telemetry points received. + +You can also view these logs via the GDS browser interface. +Click the Logs tab to go the Logs view. +Select the log you wish to inspect from the drop-down menu. +By default, there is no log selected. diff --git a/docs/Tutorials/MathComponent/Tutorial.md b/docs/Tutorials/MathComponent/Tutorial.md deleted file mode 100644 index 44a0787513..0000000000 --- a/docs/Tutorials/MathComponent/Tutorial.md +++ /dev/null @@ -1,2216 +0,0 @@ -# Math Component Tutorial - -The following example shows the steps to implement a simple pair of components connected by a pair of ports. The first, -`MathSender`, will invoke the second, `MathReceiver`, via a `MathOp` port to perform a math operation and return the -result via a `MathResult` port. - -![`Component` Diagram](img/Comp.jpg "Component Pair") - -All the code in this tutorial can be found in this directory. This code will work if it is copied or reimplemented -within the `Ref` directory of F´. This tutorial will walk the user through modifying the Reference app, Ref, to -implement the math components. - -## Prerequisites - -This tutorial requires the user to have some basic skills and have installed F´. The prerequisite skills to understand -this tutorial are as follows: - -1) Working knowledge of Unix; how to navigate in a shell and execute programs -2) An understanding of C++, including class declarations and inheritance -3) An understanding of how XML is structured - -Installation can be done by following the installation guide found at: [INSTALL.md](../../INSTALL.md). This guide -will walk the user through the installation process and verifying the installation. In addition, users may wish to -follow the [Getting Started Tutorial](../GettingStarted/Tutorial.md) in order to get a feel for the F´ environment and -tools. - -# 1 Component Descriptions - -This section will cover the components that will be built in this tutorial. Each component may define the commands, -events, telemetry channels, and parameters. This section will list commands, events, telemetry channels, and parameters -for each component that will be created. - -## 1.1 MathSender -`MathSender` must do the following: - -### 1.1.1 Commands - -`MathSender` should implement a `MS_DO_MATH` command. This command will have three arguments: -1) A first value in the operation -2) A second value in the operation -3) An enumerated argument specifying the operation to perform - -### 1.1.2 Events -`MathSender` should emit an event telling that a command was received to perform the operation. It should also emit an event when the result is received back from `MathReceiver`. - -### 1.1.3 Telemetry Channels -MathSender should have four channels: -1) The first value -2) The second value -3) The operation -4) The result - -### 1.1.4 Parameters -MathSender will have no parameters. - -`MathSender` should be an active (i.e. threaded) component, so it will process the commands immediately. The command will be *asynchronous*, which means the handler will be executed on the thread of the active component. It will delegate the operation to `MathReceiver`. - -## 1.2 MathReceiver - -`MathReceiver` will be a queued component that performs the requested operation and returns the result. `MathReceiver` will be connected to the 1Hz rate group that is part of the reference example. The simple operation in this component could have just as easily been done in a passive or active component; it is done here as a queued component to illustrate how to implement one. - -### 1.2.1 Commands - -`MathReceiver` should implement a MR_SET_FACTOR1 command. This command will set a factor used for any subsequent operations. The result of the commanded operation will be multiplied by this factor. It should default to 0 if the command is never invoked. - -`MathReceiver` should also implement a MR_CLEAR_EVENT_THROTTLE command to clear the throttled MR_SET_FACTOR1 event (see below). - -### 1.2.2 Events - -`MathReceiver` should have the following events: - -1) MR_SET_FACTOR1 command event. When the command is received, `MathReceiver` should emit an event with the updated factor. The event should be throttled (i.e. stop emitting) after three invocations. Normally, throttling is used to prevent event floods if there is an endlessly repeating condition. -2) MR_UPDATED_FACTOR2 event. When the factor2 parameter (see below) is updated, `MathReceiver` should emit an event with the updated value. -3) MR_OPERATION_PERFORMED event. When the component receives a request to perform the operation, it should emit an event with the arguments and operation. -4) MR_THROTTLE_CLEARED in response to the MR_CLEAR_EVENT_THROTTLE command above. - -### 1.2.3 Channels - -`MathReceiver` should have the following channels: - -1) A channel that has a serializable structure argument that contains the two terms in the operation as well as the operation and the result. This will be used to illustrate an XML defined serializable as a single telemetry channel. -2) A channel that counts the number of MR_SET_FACTOR1 commands received, so that a count can be known past the throttled event. -3) A channel for each of the factors used in the operation. - -### 1.2.4 Parameters - -`MathReceiver` will have one parameter, a second factor used in the operation. - -## 1.3 Operation - -`MathReceiver` will perform the following operation when requested by `MathSender`: - -result = (value1 operation value2)*factor1/factor2 - -# 2 Implementation - -This section will cover the implementation of the components for this tutorial. The implementation of these components -will have the following steps: - -1) Define the `MathOpPort` and `MathResultPort` ports that are used between the components. -2) Define the `MathSender` component in XML and compile it. -3) Implement the `MathSender` derived implementation class. -4) Unit test the `MathSender` implementation component. -5) Define the `MathReceiver` component in XML. -6) Implement the `MathReceiver` implementation class. -7) Unit test the `MathReceiver` implementation class. -8) Connect the classes to the `Ref` topology. -9) Run the ground system and exercise the commands and view the telemetry and events in the GUI. - -## 2.1 Port definition - -There are two ports to define in order to perform the operation between the components. The XML for the ports will be first shown in their entirety, and then the individual parts will be described. - -### 2.1.1 MathOpPort - -`MathOpPort` is responsible for passing the invocation of the operation from `MathSender` to `MathReceiver`. The new XML file should be placed in a new directory `Ref/MathPorts` with the name `MathOpPortAi.xml`. The XML for the port is as follows: - -```xml - - - Port to perform an operation on two numbers - - - - - - - - - - - - - - operation argument - - - -``` - -#### 2.1.1.1 Port Name Specification - -```xml - - - Port to perform an operation on two numbers - -... - -``` - -The `interface` tag specifies that a port is being defined. The attributes are as follows: - -|Attribute|Description| -|---|---| -|name|The name of the component type. Becomes the C++ class name| -|namespace|The namespace of the component. The C++ namespace where the component class will appear| - -#### 2.1.1.2 Port Argument Specification - -The port arguments are passed from component to component when they are connected. The port argument XML is as follows: - -```xml - - - - - - - - - - - - - operation argument - - -``` - -The `` tag begins the section of the XML defining the arguments, while the `` tag defines a particular argument. The port argument attributes are defined as follows: - -|Attribute|Description| -|---|---| -|name|The name of the argument. Becomes the argument name in the C++ call| -|type|The type of the arguments. Can be one of the built-in types, a user-defined type, or an enumeration| - -The enumerations are a special type of argument. When `type="ENUM"` is an attribute of the arguments, a further listing of the elements of the enumeration are needed. For each element of the array, a name is specified. These end up being C++ enumerated types. - -```xml - - - - - - - ``` -#### 2.1.1.3 Adding the port to the build - -The build system needs to be made aware of the port XML. To do this, the user needs to create a `CMakeLists.txt` file in -the directory of the port. Create a file named `CMakeLists.txt` in the `MathPorts` directory. This file tells the build -system that a new file needs to be added to the build. Here are the contents: - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathOpPortAi.xml" -) -register_fprime_module() -``` - -Here the source files for this module are listed. In the case of ports, only the Ai.xml file is needed. The next step is -to add the `MathPorts` to the `Ref` project. - -The port can be added into the `Ref` project by editing the `Ref/CMakeLists.txt`. This will add the port directory into -the directories available to the `Ref` build. Find the following lines in `Ref/CMakeLists.txt` and append a record with -the current directory. - -```cmake -... -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PingReceiver/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RecvBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SendBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SignalGen/") -``` - -The file after modification should look like the following: - -```cmake -... -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PingReceiver/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RecvBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SendBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SignalGen/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathPorts/") -``` - -Now that the ports directory is part of the build system, the port can be built. If you have not already generated a -build directory for `Ref` as described in the "INSTALL.md" and the "Getting Started" tutorial, then run the following -commands to generate a build. - -```shell -# Change to Ref directory -cd fprime/Ref -fprime-util generate -``` - -Now, the port code can be generated and compiled: - -```shell -# Change to the MathPorts directory from Ref -cd MathPorts -fprime-util build -``` - -The code generation from the XML produces two files, both of which are part of the generated build directory: - -``` - MathOpPortAc.cpp - MathOpPortAc.hpp -``` -These contain the C++ classes that implement the port functionality. The build system will automatically compile them when it is aware of the port XML file. - -### 2.1.2 MathResultPort - -`MathResultPort` is responsible for passing the result of the operation from `MathReceiver` to `MathSender`. The new XML file should be placed in the `Ref/MathPorts` directory with the name `MathResultPortAi.xml`. The XML for the port is as follows: - -```xml - - - Port to return the result of a math operation - - - - the result of the operation - - - - -``` - -This file can be added to the `CMakeLists.txt` in the `Ref/MathPorts` directory: - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathOpPortAi.xml" - "${CMAKE_CURRENT_LIST_DIR}/MathResultPortAi.xml" - -) -register_fprime_module() -``` - -Running `fprime-util build` as before will compile the new port XML file and generate the C++ Autogenerated -files. The code generated to implement ports is complete. Developers do not need to add any implementation code of their -own to port definitions. - -## 2.2 Serializable Definition - -A structure needs to be defined that represents the channel value needed by `MathReceiver`. All port calls, telemetry channels, events and parameters need to be comprised of `Serializable` values, or values that can be turned into a byte stream. This is needed to pass port arguments through message queues and to pass commands and telemetry to and from the ground system. Built-in basic types like integers, floating point numbers and boolean values are supported by the framework, but there are times when a developer wishes to use a custom-defined type, perhaps to keep members of an object consistent with each other. These structures can be defined in XML and the code generator will generate the C++ classes with all the necessary serialization functions. Developers can hand-code their own, but they are not usable for telemetry since the ground system needs an XML definition to decode them. - -### 2.2.1 MathOp - -The `MathOp` serializable structure is needed by `MathReceiver` for a telemetry channel that gives the values of the operation. A new directory named `Ref/MathTypes` should be created for the structure, and the file should be named `MathOpSerializableAi.xml`. The XML is as follows: - -```xml - - - This value holds the values of a math operation - - - - - - - - - - - - - - - -``` - -Add a `CMakeLists.txt` file for the serializable: - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathOpSerializableAi.xml" -) -register_fprime_module() -``` - -#### 2.2.1.1 Serializable Name Specification - -The opening tag of the XML specifies the type name and namespace of the structure: - -```xml - -... - -``` - -#### 2.2.1.2 Serializable Members - -The `members` tag starts the section of the XML that specifies the members of the structure: - -```xml - - - - - - - - - - - - - -``` - -As with the arguments to port definitions, built-in types can be specified as well as enumerations. - -As before with the port definitions, the `Ref/MathTypes` directory needs to be added to `Ref/CMakeLists.txt`. - -```cmake -... -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PingReceiver/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RecvBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SendBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SignalGen/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathPorts/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathTypes/") -``` - -This XML defined structure compiles to a C++ class that has accessors for the members of the structure. - -## 2.3 Component Definition - -### 2.3.1 MathSender Component - -The `MathSender` component XML definition is as follows. The XML should be placed in a file `Ref/MathSender/MathSenderComponentAi.xml` - -```xml - - Ref/MathPorts/MathOpPortAi.xml - Ref/MathPorts/MathResultPortAi.xml - Component sending a math operation - - - - Port for sending the math operation - - - - - Port for returning the math result - - - - - - - Do a math operation - - - - The first value - - - The second value - - - - - - - - - The operation to perform - - - - - - - - The first value - - - - - The second value - - - - - - - - - - - The operation - - - - - The result - - - - - - - Math command received - - - - The val1 argument - - - The val2 argument - - - The requested operation - - - - - - - - - - - - Received math result - - - - The math result - - - - - -``` - -#### 2.3.1.1 Component Name Specification - -The component name is specified in the opening tag of the XML: - -```xml - -... - -``` - -The attributes of the tag are as follows: - -|Attribute|Description| -|---|---| -|name|The component name| -|kind|What the threading/queuing model of the component is. Can be `passive`, `queued`, or `active`| -|namespace|The C++ namespace the component will be defined in| - -#### 2.3.1.2 Port Imports - -The ports needed for the component are imported using `import_port_type` tags: - -```xml - Ref/MathPorts/MathOpPortAi.xml - Ref/MathPorts/MathResultPortAi.xml -``` - -The path in the port import statement is relative to the root of the repository. There are a number of ports automatically included by the code generator when commands, telemetry, events or parameters are defined. They are: - -|Facility|Ports| -|---|---| -|Commands|`Fw/Command/CmdPortAi.xml`,`Fw/Command/CmdResponsePortAi.xml`,`Fw/Command/CmdRegPortAi.xml`| -|Events|`Fw/Log/LogPortAi.xml`,`Fw/Log/LogTextPortAi.xml`| -|Telemetry|`Fw/Tlm/TlmPortAi.xml`| -|Parameters|`Fw/PrmGetPortAi.xml`,`Fw/PrmSetPortAi.xml`| - -#### 2.3.1.3 Port Declarations - -Ports and their attributes are declared once the port definitions are included. - -```xml - - - - Port for sending the math operation - - - - - Port for returning the math result - - - -``` - -The port attributes are: - -|Attribute|Description| -|---|---| -|name|The port name| -|data_type|The type of the port as defined in the included port definitions, in the form `namespace::name`| -|kind|The kind of port. Can be `sync_input`,`async_input`,`guarded_input`, or `output`| - -For `MathSender`, the request for the operation will be sent on the `mathOut` output port, and the result will be returned on the `mathIn` asynchronous port. Because the component is active and the result input port is asynchronous, the port handler will execute on the thread of `MathSender`. - -#### 2.3.1.4 Command Declarations - -The commands defined for the component are: - -```xml - - - - Do a math operation - - - - The first value - - - The second value - - - - - - - - - The operation to perform - - - - -``` - -The `` tag starts the section containing commands for `MathSender`. For each command, the following attributes are defined: - -|Attribute|Description| -|---|---| -|mnemonic|A text version of the command name, used in sequences and the ground tool| -|opcode|A numeric value for the command. The value is relative to a base value set when the component is added to a topology| -|kind|The kind of command. Can be `sync_input`,`async_input`,`guarded_input`, or `output`| - -#### 2.3.1.5 Telemetry - -The telemetry XML is as follows: - -```xml - - - - The first value - - - - - The second value - - - - - - - - - - - The operation - - - - - The result - - - -``` - -The `` tag starts the section containing telemetry channels for `MathSender`. For each channel, the following attributes are defined: - -|Attribute|Description| -|---|---| -|name|The channel name| -|id|A numeric value for the channel. The value is relative to a base value set when the component is added to a topology| -|data_type|The data type of the channel. Can be a built-in type, an enumeration or an externally defined serializable type| - -#### 2.3.1.6 Events - -The XML for the defined events is as follows: - -```xml - - - - Math command received - - - - The val1 argument - - - The val2 argument - - - The requested operation - - - - - - - - - - - - Received math result - - - - The math result - - - - -``` - -The `` tag starts the section containing events for `MathSender`. For each event, the following attributes are defined: - -|Attribute|Description| -|---|---| -|name|The event name| -|severity|The severity of the event. Can be DIAGNOSTIC, ACTIVITY_LO, ACTIVITY_HI, WARNING_LO, WARNING_HI or FATAL. -|id|A numeric value for the event. The value is relative to a base value set when the component is added to a topology| -|format_string|A C-style format string for displaying the event and the argument values.| - -The directory containing the component XML can be added to the list of modules in `Ref/CMakeLists.txt`: - -```cmake -... -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PingReceiver/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RecvBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SendBuffApp/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SignalGen/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathPorts/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathTypes/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathSender/") -``` - -Create a `CMakeLists.txt` file in `Ref/MathSender` and add `MathSenderComponentAi.xml`. - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathSenderComponentAi.xml" -) - -register_fprime_module() -``` - -Once it is added, add the directory to the build and build the component by typing `fprime-util build` from the `Ref` directory. - -### 2.3.2 MathReceiver Component - -#### 2.3.2.1 Component Specification - -The `MathReceiver` component XML is as follows: - -```xml - - Ref/MathPorts/MathOpPortAi.xml - Ref/MathPorts/MathResultPortAi.xml - Svc/Sched/SchedPortAi.xml - Ref/MathTypes/MathOpSerializableAi.xml - Component sending a math operation - - - - Port for receiving the math operation - - - - - Port for returning the math result - - - - - The rate group scheduler input - - - - - - - Set operation multiplication factor1 - - - - The first factor - - - - - Clear the event throttle - - - - - - - The operation - - - - - The number of MR_SET_FACTOR1 commands - - - - - Factor 1 value - - - - - Factor 2 value - - - - - - - Operation factor 1 - - - - The factor value - - - - - - Updated factor 2 - - - - The factor value - - - - - - Math operation performed - - - - The operation - - - - - - Event throttle cleared - - - - - - - A test parameter - - - - - -``` - - -The `CMakeLists.txt` file for this component is as follows: - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathReceiverComponentAi.xml" -) - -register_fprime_module() -``` - -Don't forget to `Ref/MathReceiver` to `Ref/CMakeLists.txt`. - - -Many of the elements are the same as described in `MathSender`, so this section will highlight the differences. - -#### 2.3.2.1 Queued component - -The `MathReceiver` component is queued, which means it can receive asynchronous port invocations as messages, but needs an external thread to dequeue them. - -#### 2.3.2.2 Importing the serializable type - -The telemetry channels and events use a serializable type, `Ref::MathOp` to illustrate the use of those types. The following line specifies the import for this type: - -```xml - Ref/MathTypes/MathOpSerializableAi.xml -``` - -This type is then available for events and channels, but are not available for parameters and command arguments. - -#### 2.3.2.3 Scheduler port - -The queued component has a scheduler port that is `sync_input`. That means the port invocation is not put on a message queue, but calls the handler on the thread of the caller of the port: - -```xml - - - The rate group scheduler input - - - -``` - -This synchronous call allows the caller to pull any pending messages of the message queue using the thread of the component invoking the `SchedIn` port. - -#### 2.3.2.4 Throttled Event - -The `MR_SET_FACTOR1` event has a new argument `throttle = "3"` that specifies how many events will be emitted before the event is throttled so no more appear. - -```xml - - - Operation factor 1 - - - - The factor value - - - -``` - -#### 2.3.2.5 Parameters - -The `MathReceiver` component has a declaration for a parameter: - -```xml - - - - A test parameter - - - - -``` - -The `parameter` attributes are as follows: - -|Attribute|Description| -|---|---| -|id|The unique parameter ID. Relative to base ID set for the component in the topology| -|name|The parameter name| -|data_type|The data type of the parameter. Must be a built-in type| -|default|Default value assigned to the parameter if there is an error retrieving it.| -|set_opcode|The opcode of the command to set the parameter. Must not overlap with any of the command opcodes| -|save_opcode|The opcode of the command to save the parameter. Must not overlap with any of the command opcodes| - - - -## 2.4 Component Implementation - -The component implementation consists of writing a class that is derived from the code-generated base class and filling in member functions that implement the port calls. - -### 2.4.1 MathSender Implementation - -#### 2.4.1.1 Stub Generation - -There is a F´ utility command that will generate stubs that the developer can fill in. The command to generate the stubs is: `fprime-util impl`. -This should be run in the directory for the MathSender component, and will generate two files: - -``` -MathSenderComponentImpl.hpp-template -MathSenderComponentImpl.cpp-template -``` - -Rename the files by removing the `-template` from the end of the file names. - -``` -MathSenderComponentImpl.hpp -MathSenderComponentImpl.cpp -``` - -Add the new files to the MathSender's `CMakeLists.txt` file: - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathSenderComponentAi.xml" - "${CMAKE_CURRENT_LIST_DIR}/MathSenderComponentImpl.cpp" -) -register_fprime_module() -``` - -Now attempt to build the component with: - -``` -fprime-util build -``` - -The stub files should successfully compile. - -#### 2.4.1.2 Handler implementation - -The next step is to fill in the handler with implementation code. - -First, find the empty command handler in the `MathSenderComponentImpl.cpp` file: - -```c++ - void MathSenderComponentImpl :: - MS_DO_MATH_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - F32 val1, - F32 val2, - MathOp operation - ) - { - // TODO - } -``` -Then, fill in the function with the code to perform the functions described at the beginning of the tutorial: - -```c++ - void MathSenderComponentImpl :: - MS_DO_MATH_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - F32 val1, - F32 val2, - MathOp operation - ) - { - MathOpTlm opTlm; - MathOperation opPort; - MathOpEv opEv; - switch (operation) { - case ADD: - opTlm = ADD_TLM; - opPort = MATH_ADD; - opEv = ADD_EV; - break; - case SUBTRACT: - opTlm = SUB_TLM; - opPort = MATH_SUB; - opEv = SUB_EV; - break; - case MULTIPLY: - opTlm = MULT_TLM; - opPort = MATH_MULTIPLY; - opEv = MULT_EV; - break; - case DIVIDE: - opTlm = DIV_TLM; - opPort = MATH_DIVIDE; - opEv = DIV_EV; - break; - default: - FW_ASSERT(0,operation); - break; - } - - this->tlmWrite_MS_OP(opTlm); - this->tlmWrite_MS_VAL1(val1); - this->tlmWrite_MS_VAL2(val2); - this->log_ACTIVITY_LO_MS_COMMAND_RECV(val1,val2,opEv); - this->mathOut_out(0,val1,val2,opPort); - // reply with completion status - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - -``` - -The handler will send the appropriate events and telemetry values, then invoke the output math operation port to request the operation. -Note that each channel and event argument that has an enumeration has a unique type declaration. -Finally, note that the output command response port must be called with a command status in order to let the framework components know that the command is complete. -If the completion status isn't sent, it will stall any sequences the command was part of. -There are command error status along with successful completions. -Most commands return this status at the end of the handler, but component implementations can store the `opCode` and `cmdSeq` values to return later, but those specific values must be returned in order to match the status with the command originally sent. - -Find the empty result handler: - -```c++ - void MathSenderComponentImpl :: - mathIn_handler( - const NATIVE_INT_TYPE portNum, - F32 result - ) - { - // TODO - } -``` - -Fill in the result handler with code that reports telemetry and an event: - -```c++ - void MathSenderComponentImpl :: - mathIn_handler( - const NATIVE_INT_TYPE portNum, - F32 result - ) - { - this->tlmWrite_MS_RES(result); - this->log_ACTIVITY_HI_MS_RESULT(result); - } - -``` - -This handler reports the result via a telemetry channel and an event. - -Once complete, add the directory to the build and build the component by typing `fprime-util build` from the `Ref` directory. - -#### 2.4.1.3 Unit Tests - -Unit Tests are used to exercise the component's functions by invoking input ports and commands and checking the values of output ports, telemetry and events. - -##### 2.4.1.3.1 Test Code Generation - -The code generator will generate test components that can be connected to the component to enable a set of unit tests to check functionality and to get coverage of all the code. To generate a set of files for testing, from the module directory type: - -```shell -fprime-util impl --ut -``` - -The files that are generated are: - -``` -Tester.hpp -Tester.cpp -TestMain.cpp -``` - -**Note:** TesterBase.* and GTestBase.* files can be removed. These will be regenerated when the unit test builds. - -The functions of the files are: - -|File|Function| -|---|---| -|TesterBase.*| Base class for test class. Defines necessary handlers as well as helper functions. **Autocoded** | -|GTestBase.*|Helper class derived from TesterBase that has macros that use Google Test to test interfaces. **Autocoded** | -|Tester.*|Derived tester class that inherits from GTestBase. Includes instance of the component and helpers to connect ports| -|TestMain.cpp|Main unit test implementation file| - -Unit tests are built in subdirectories of the module, so the unit test file must be copied there. The build system supports a standard subdirectory of `test/ut` below the module being tested. While in the MathSender directory, create the `test/ut` directory: - -``` -mkdir -p test/ut -``` - -Move the above set of files into that subdirectory. - -The new unit test files have to be registered with the build system, so modifications to the `CMakeLists.txt` files are -necessary. To do this, add a "UT_SOURCE_FILES" variable to `CMakeLists.txt` followed by a call `register_fprime_ut()`. -The UT_SOURCE_FILES variable contains a list of the C++ files associated with the UT (see list above). - -The final `CMakeLists.txt` file should look like the following: - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathSenderComponentAi.xml" - "${CMAKE_CURRENT_LIST_DIR}/MathSenderComponentImpl.cpp" -) -register_fprime_module() - -set(UT_SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" -) -register_fprime_ut() -``` -The `UT_SOURCE_FILES` variable includes any source code needed to run the test. It usually only includes the generated -test code and a `main.cpp`, but it can include any code the user needs to test. - -A `UT_MODS` variable may be set should the UT depend on modules not automatically included by the component. - -##### 2.4.1.3.2 Test Code Implementation - -The unit tests must be added to `TestMain.cpp`. Change the default code to appear -like this: - -```c++ -#include "Tester.hpp" - -TEST(Nominal, AddOperationTest) { - Ref::Tester tester; - tester.testAddCommand(); -} - -TEST(Nominal, SubOperationTest) { - Ref::Tester tester; - tester.testSubCommand(); -} - -TEST(Nominal, MultOperationTest) { - Ref::Tester tester; - tester.testMultCommand(); -} - -TEST(Nominal, DivideOperationTest) { - Ref::Tester tester; - tester.testDivCommand(); -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} -``` - -F' uses the Google Test framework to run unit tests. For more information about the Google Test Framework see here: - -https://github.com/google/googletest - - -In the Google Test framework, the following lines of code are standard: - -```c++ -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} -``` - -For each test, there is a Google Test macro defined: - -```c++ -TEST(Name1, Name2) { - // run some code -} -``` - -The code in each of the macros defined this way will automatically be run by the framework. - -In this case, the tests are defined as follows: - -```c++ -TEST(Nominal, AddOperationTest) { - Ref::Tester tester; - tester.testAddCommand(); -} - -TEST(Nominal, SubOperationTest) { - Ref::Tester tester; - tester.testSubCommand(); -} - -TEST(Nominal, MultOperationTest) { - Ref::Tester tester; - tester.testMultCommand(); -} - -TEST(Nominal, DivideOperationTest) { - Ref::Tester tester; - tester.testDivCommand(); -} -``` -For each unit test, the Google Test test case for F' components looks like: - -```c++ -TEST(Nominal, DivideOperationTest) { - NameSpace::Tester tester; - tester.someUnitTestFunc(); -} -``` -The test component is instantiated here: - -```c++ - NameSpace::Tester tester; -``` - -This allows the component to start from a newly initialized state for each unit test. - -The unit test is executed by calling a member function of the `tester` class: - -```c++ - tester.someUnitTestFunc(); -``` - -> NOTE: The autogenerated `Tester.*` files include a placeholder "toDo" function. Feel -free to leave that in or delete it. - -The `Tester.hpp` stub can be updated to include the declarations of the unit test functions: - -```c++ - ... - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - //! To do - //! - void toDo(void); - - //! Test operation command - //! - void testAddCommand(); - void testSubCommand(); - void testMultCommand(); - void testDivCommand(); - - private: - ... -``` - -The next step is to add the specific test cases to the `Tester.cpp` implementation file. It is important to note that the unit tests are designed to be single-threaded. The active components do not have their threads started, so any messages to asynchronous ports are manually retrieved from the message queue and dispatched to handlers. This makes testing simpler since the execution of the thread in response to port calls or commands does not need to be managed. Examples of this will be seen in the test code. - -The first test case will be to test the `MS_DO_MATH` command for the addition operation. In the example component implementation, `MS_DO_MATH` command calls the `mathOut` output port and emits some channelized telemetry and events. The test component provides methods for invoking the command and checking that the telemetry and events were emitted as expected. The steps to write the test case are as follows: - -Add a member function to the implementation class in `Tester.cpp` to implement the test case: - -```c++ - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void Tester :: - testAddCommand() - { - // send MS_DO_MATH command - this->sendCmd_MS_DO_MATH(0,10,1.0,2.0,MathSenderComponentBase::ADD); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify that only one output port was called - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // verify that the math operation port was only called once - ASSERT_from_mathOut_SIZE(1); - // verify the arguments of the operation port - ASSERT_from_mathOut(0,1.0,2.0,MATH_ADD); - // verify telemetry - 3 channels were written - ASSERT_TLM_SIZE(3); - // verify that the desired telemetry values were only sent once - ASSERT_TLM_MS_VAL1_SIZE(1); - ASSERT_TLM_MS_VAL2_SIZE(1); - ASSERT_TLM_MS_OP_SIZE(1); - // verify that the correct telemetry values were sent - ASSERT_TLM_MS_VAL1(0,1.0); - ASSERT_TLM_MS_VAL2(0,2.0); - ASSERT_TLM_MS_OP(0,MathSenderComponentBase::ADD_TLM); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_COMMAND_RECV_SIZE(1); - // verify the correct event arguments were sent - ASSERT_EVENTS_MS_COMMAND_RECV(0,1.0,2.0,MathSenderComponentBase::ADD_EV); - // verify command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - // verify the command response was correct as expected - ASSERT_CMD_RESPONSE(0,MathSenderComponentBase::OPCODE_MS_DO_MATH,10,Fw::CmdResponse::OK); - - // reset all telemetry and port history - this->clearHistory(); - // call result port. We don't care about the value being correct since MathSender doesn't - this->invoke_to_mathIn(0,10.0); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); - // verify only one telemetry value was written - ASSERT_TLM_SIZE(1); - // verify the desired telemetry channel was sent only once - ASSERT_TLM_MS_RES_SIZE(1); - // verify the values of the telemetry channel - ASSERT_TLM_MS_RES(0,10.0); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_RESULT_SIZE(1); - // verify the expected value of the event arguments - ASSERT_EVENTS_MS_RESULT(0,10.0); - } -``` - -Some highlights are: - -Send the `MS_DO_MATH` command: - -```c++ - // send MS_DO_MATH command - this->sendCmd_MS_DO_MATH(0,10,1.0,2.0,MathSenderComponentBase::ADD); - // retrieve the message from the message queue and dispatch - this->component.doDispatch(); -``` - -Verify that the operation port was called as expected: - -```c++ - // verify that that only one output port was called - ASSERT_FROM_PORT_HISTORY_SIZE(1); - // verify that the math operation port was only called once - ASSERT_from_mathOut_SIZE(1); - // verify the arguments of the operation port - ASSERT_from_mathOut(0,1.0,2.0,MATH_ADD); -``` - -The first call verifies that one and only one port call was made. This can be used to confirm that there were no other ports called besides the expected one. - -The second call verifies that the port call that was made was the expected one. - -The third call looks at a stored history of calls to this port and verifies the expected call arguments were made. The history can store multiple calls, so the first argument indicates which index in the history to examine. - -Verify that the telemetry channels were written: - -```c++ - // verify telemetry - 3 channels were written - ASSERT_TLM_SIZE(3); - // verify that the desired telemetry values were only sent once - ASSERT_TLM_MS_VAL1_SIZE(1); - ASSERT_TLM_MS_VAL2_SIZE(1); - ASSERT_TLM_MS_OP_SIZE(1); - // verify that the correct telemetry values were sent - ASSERT_TLM_MS_VAL1(0,1.0); - ASSERT_TLM_MS_VAL2(0,2.0); - ASSERT_TLM_MS_OP(0,MathSenderComponentBase::ADD_TLM); -``` -The first statement verifies that three channels were written as expected. The following statements verify that the correct channels were written with the expected values. - -Verify that the event for the command was sent: - -```c++ - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_COMMAND_RECV_SIZE(1); - // verify the correct event arguments were sent - ASSERT_EVENTS_MS_COMMAND_RECV(0,1.0,2.0,MathSenderComponentBase::ADD_EV); - -``` - -Next, verify that the correct response to the command was sent: - -```c++ - // verify command response was sent - ASSERT_CMD_RESPONSE_SIZE(1); - // verify the command response was correct as expected - ASSERT_CMD_RESPONSE(0,MathSenderComponentBase::OPCODE_MS_DO_MATH,10,Fw::CmdResponse::OK); -``` - -Next, prepare for calling `MathSender`'s result port by clearing the port and telemetry history: - -```c++ - // reset all telemetry and port history - this->clearHistory(); -``` - -As ports and commands are invoked in the component, the test component stores the history of calls. This function clears the history, in order to provide a clean slate for the next test. There are calls to clear individual histories as well. See `TesterBase.hpp` for a list. The `this->clearHistory()` call will clear them all, so is generally preferable. - -The next step is to invoke the port that the `MathReceiver` component will call in the example program. For the unit test, the `MathReceiver` is not present to send the result back, so the unit test will emulate that call. - -First, the port invocation is made: - -```c++ - // call result port. We don't care about the value being correct since MathSender doesn't - this->invoke_to_mathIn(0,10.0); - // retrieve the message from the message queue and dispatch the command to the handler - this->component.doDispatch(); -``` - -Next, the test checks for the expected telemetry and events: - -```c++ - // verify only one telemetry value was written - ASSERT_TLM_SIZE(1); - // verify the desired telemetry channel was sent only once - ASSERT_TLM_MS_RES_SIZE(1); - // verify the values of the telemetry channel - ASSERT_TLM_MS_RES(0,10.0); - // verify only one event was sent - ASSERT_EVENTS_SIZE(1); - // verify the expected event was only sent once - ASSERT_EVENTS_MS_RESULT_SIZE(1); - // verify the expected value of the event arguments - ASSERT_EVENTS_MS_RESULT(0,10.0); -``` - -The other test cases are similarly implemented for the other operations. See the tutorial code for their implementation. - -You must first generate the unit test before you can build it. Enter: - -``` -fprime-util generate --ut -``` - -Once you generate the unit test, you can build the unit test by entering: - -``` -fprime-util build --ut -``` - -You can run the unit test by typing the following in the `MathSender` (not `test/ut`) directory: - -```shell -$ fprime-util check -[==========] Running 4 tests from 1 test case. -[----------] Global test environment set-up. -[----------] 4 tests from Nominal -[ RUN ] Nominal.AddOperationTest -[ OK ] Nominal.AddOperationTest (2 ms) -[ RUN ] Nominal.SubOperationTest -[ OK ] Nominal.SubOperationTest (0 ms) -[ RUN ] Nominal.MultOperationTest -[ OK ] Nominal.MultOperationTest (0 ms) -[ RUN ] Nominal.DivideOperationTest -[ OK ] Nominal.DivideOperationTest (0 ms) -[----------] 4 tests from Nominal (3 ms total) - -[----------] Global test environment tear-down -[==========] 4 tests from 1 test case ran. (3 ms total) -[ PASSED ] 4 tests. - -``` - -### 2.4.2 MathReceiver Implementation - -#### 2.4.2.1 Component Implementation - -As before, a stub can be generated: - -``` -cd fprime/Ref/MathReceiver -fprime-util impl -mv MathReceiverComponentImpl.cpp-template MathReceiverComponentImpl.cpp -mv MathReceiverComponentImpl.hpp-template MathReceiverComponentImpl.hpp -``` - -Add the stub files to `CMakeLists.txt`: - -```cmake -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathReceiverComponentAi.xml" - "${CMAKE_CURRENT_LIST_DIR}/MathReceiverComponentImpl.cpp" -) -register_fprime_module() -``` - -Add the files and compile them: `fprime-util build` - -##### 2.4.2.1.1 Port handler - -Look for the empty port handler in the sub class: - -```c++ - void MathReceiverComponentImpl :: - mathIn_handler( - const NATIVE_INT_TYPE portNum, - F32 val1, - F32 val2, - MathOperation operation - ) - { - // TODO - } -``` - -Fill the handler in with the computation of the result. The handler will also update telemetry and events: - -```c++ - void MathReceiverComponentImpl :: - mathIn_handler( - const NATIVE_INT_TYPE portNum, - F32 val1, - F32 val2, - MathOperation operation - ) - { - // declare result serializable - Ref::MathOp op; - F32 res = 0.0; - switch (operation) { - case MATH_ADD: - op.setop(ADD); - res = (val1 + val2)*this->m_factor1; - break; - case MATH_SUB: - op.setop(SUB); - res = (val1 - val2)*this->m_factor1; - break; - case MATH_MULTIPLY: - op.setop(MULT); - res = (val1 * val2)*this->m_factor1; - break; - case MATH_DIVIDE: - op.setop(DIVIDE); - res = (val1 / val2)*this->m_factor1; - break; - default: - FW_ASSERT(0,operation); - break; - } - Fw::ParamValid valid; - res = res/paramGet_factor2(valid); - - op.setval1(val1); - op.setval2(val2); - op.setresult(res); - this->log_ACTIVITY_HI_MR_OPERATION_PERFORMED(op); - this->tlmWrite_MR_OPERATION(op); - this->mathOut_out(0,res); - } - -``` - -If needed, add `m_factor1` and `m_factor1s` as private variables in `MathReceiverComponentImpl.hpp`: - - -```c++ -//! Implementation for MR_CLEAR_EVENT_THROTTLE command handler -//! Clear the event throttle -void MR_CLEAR_EVENT_THROTTLE_cmdHandler( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq /*!< The command sequence number*/ -); - -// stored factor1 -F32 m_factor1; -// number of times factor1 has been written -U32 m_factor1s; -``` - - - -In this handler, the operation is done based on the port arguments from `MathSender`. -The `op` structure is populated for the event and telemetry calls, and the `mathOut` port is called to send the result back to `MathSender`. -The parameter value is retrieved during initialization and is returned via the `paramGet_factor2()` call. -The commands to set and save the factor2 parameter run entirely in the code generated base classes. - -##### 2.4.2.1.2 Commands - -The command handler to update the value of `factor1` is as follows: - -```c++ - void MathReceiverComponentImpl :: - MR_SET_FACTOR1_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - F32 val - ) - { - this->m_factor1 = val; - this->log_ACTIVITY_HI_MR_SET_FACTOR1(val); - this->tlmWrite_MR_FACTOR1(val); - this->tlmWrite_MR_FACTOR1S(++this->m_factor1s); - // reply with completion status - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - -``` - -The telemetry and log values are sent, and the command response is sent. -Note that after three calls to the handler, the `this->log_ACTIVITY_HI_MR_SET_FACTOR1(val)` call will not actually send any events until the throttle is cleared. -The throttled state is part of the generated code. - -The handler to clear the throttle is as follows: - -```c++ - void MathReceiverComponentImpl :: - MR_CLEAR_EVENT_THROTTLE_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq - ) - { - // clear throttle - this->log_ACTIVITY_HI_MR_SET_FACTOR1_ThrottleClear(); - // send event that throttle is cleared - this->log_ACTIVITY_HI_MR_THROTTLE_CLEARED(); - // reply with completion status - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } -``` -##### 2.4.2.1.3 Scheduler Call - -The port invoked by the scheduler retrieves the messages from the message queue and dispatches them. -The message dispatches invoke the command and input port handlers that were implemented earlier in the tutorial. - -```c++ - void MathReceiverComponentImpl :: - SchedIn_handler( - const NATIVE_INT_TYPE portNum, - NATIVE_UINT_TYPE context - ) - { - QueuedComponentBase::MsgDispatchStatus stat = QueuedComponentBase::MSG_DISPATCH_OK; - // empty message queue - while (stat != MSG_DISPATCH_EMPTY) { - stat = this->doDispatch(); - } - } - -``` - -##### 2.4.2.1.4 Parameter Updates - -The developer can optionally receive a notification that a parameter has been updated by overriding a virtual function in the code generated base class: - -```c++ - void MathReceiverComponentImpl :: - parameterUpdated( - FwPrmIdType id /*!< The parameter ID*/ - ) { - if (id == PARAMID_FACTOR2) { - Fw::ParamValid valid; - F32 val = this->paramGet_factor2(valid); - this->log_ACTIVITY_HI_MR_UPDATED_FACTOR2(val); - } - } -``` - -Add the function to the header file: - -```c++ - // stored factor1 - F32 m_factor1; - // number of times factor1 has been written - U32 m_factor1s; - - void parameterUpdated( - FwPrmIdType id /*!< The parameter ID*/ - ); -``` - -Once it is added, add the directory to the build and build the component by typing `fprime-util build` from the `Ref` directory. - -#### 2.4.2.2 Unit Tests - -See section `2.4.1.3.1` for directions on how to generate unit test stubs and copy them to the correct subdirectory. -The `MathReceiver` tests are similar to `MathSender`. - -##### 2.4.2.2.1 Test Code Implementation - -The full unit test code for the `MathReceiver` component can be found in the `docs/Tutorials/MathComponent/MathReceiver/test/ut` directory. Many of the patterns are the same. Following are some highlights: - -##### 2.4.2.2.2 Parameter Initialization - -`Tester.cpp`, line 60: - -```c++ - void Tester :: - testAddCommand() - { - // load parameters - this->component.loadParameters(); - ... -``` - -The `loadParameters()` call will attempt to load any parameters that the component needs. -The `this->paramSet_*` functions in the `*TesterBase` base classes allow the developer to set parameter and status values prior to the `loadParameters()` -With no manually set parameter values preceding the call, in this test case the parameter value is set to the default value. -It is a way to test default settings for parameters. - -`Tester.cpp`, line 206: - -```c++ - void Tester :: - testSubCommand() - { - // set the test value for the parameter before loading - it will be initialized to this value - this->paramSet_factor2(5.0,Fw::PARAM_VALID); - - // load parameters - this->component.loadParameters(); - -``` - -In this test case, the parameter value was set prior to the `loadParameters()` call. A `Fw::PARAM_VALID` status is also set, which allows the component to consider the value valid and use it. - -##### 2.4.2.2.3 Serializable Usage - -`Tester.cpp`, line 78: - -```c++ - ... - // verify the result of the operation was returned - F32 result = (2.0-3.0)*2.0/5.0; - // the event and telemetry channel use the Ref::MathOp type for values - Ref::MathOp checkOp(2.0,3.0,Ref::SUB,result); - ... -``` - -The `Ref::Mathop` class is the C++ implementation of the serializable type defined in `2.2.1`. When checking event and telemetry histories against the expected values, simply instantiate the serializable class in the test code and use it for comparisons. - -##### 2.4.2.2.4 Event Throttling - -`Tester.cpp`, line 395: - -```c++ - void Tester :: - testThrottle() - { -``` - -This unit test demonstrates how event throttling works. The event is repeatedly issued until it reaches the throttle count and then is suppressed from then on. The throttle is reset by the `MR_CLEAR_EVENT_THROTTLE` command: - -`Tester.cpp`, line 446: - -```c++ - // send the command to clear the throttle - this->sendCmd_MR_CLEAR_EVENT_THROTTLE(0,10); -``` - -The header file should be updated to include the `testThrottle` method as a public member. - -`Tester.hpp`, line 51: - -```c++ -void testThrottle(); -``` - - -# 3 Topology - -Now that the two components are defined, implemented and unit tested they can to be added to the `Ref` topology. -The topology describes the interconnection of all the components so the system operates as intended. -They consist of the core Command and Data Handling (C&DH) components that are part of the reusable set of components that come with the F´ repository as well as custom components written for the `Ref` reference example including the ones in this tutorial. -The `Ref` topology has already been developed as an example. -The tutorial will add the `MathSender` and `MathReceiver` components to the existing demonstration. -It involves modification of a topology description XML file as well as accompanying C++ code to instantiate and initialize the components. - -## 3.1 Define C++ Component Instances - -The first step is to include the implementation files in the topology source code. - -### 3.1.1 Components.hpp - -There is a C++ header file that declares all the component instances as externals for use by the initialization code and the generated code that interconnects the components. The two new components can be added to this file. First, include the header files for the implementation classes: - -`Ref/Top/Components.hpp`, line 30: - -```c++ -#include - -#include -#include -``` - -`extern` declarations need to be made in this header file for use by the topology connection file that is discussed later as well as initialization code. - -`Ref/Top/Components.hpp`, line 62: - -```c++ -extern Ref::PingReceiverComponentImpl pingRcvr; - -extern Ref::MathSenderComponentImpl mathSender; -extern Ref::MathReceiverComponentImpl mathReceiver; -``` - -### 3.1.2 Topology.cpp - -This C++ file is where the instances of all the components are declared and initialized. The generated topology connection function is called from this file. - -#### 3.1.2.1 Component Instantiation - -Put these declarations after the declarations for the other `Ref` components: - -`Ref/Top/Topology.cpp`, line 106: - -```c++ -Ref::MathSenderComponentImpl mathSender(FW_OPTIONAL_NAME("mathSender")); -Ref::MathReceiverComponentImpl mathReceiver(FW_OPTIONAL_NAME("mathReceiver")); -``` - -Where the other components are initialized, add `MathSender` and `MathReceiver`: - -`Ref/Top/Topology.cpp`, line 172: - -```c++ - pingRcvr.init(10); - - mathSender.init(10,0); - mathReceiver.init(10,0); -``` - -The first argument is the queue message depth. -This is the number of messages that can be pending while other messages are being dispatched. - -After all the components are initialized, the generated function `constructRefArchitecture()` (see `RefTopologyAppAc.cpp`) can be called to connect the components together. How this function is generated will be seen later in the tutorial. - -`Ref/Top/Topology.cpp`, line 177: - -```c++ - // Connect rate groups to rate group driver - constructRefArchitecture(); - -``` - -Next, the components commands are registered. - -`Ref/Top/Topology.cpp`, line 202: - -```c++ - health.regCommands(); - pingRcvr.regCommands(); - pktTlm.regCommands(); - - mathSender.regCommands(); - mathReceiver.regCommands(); -``` - -Component parameters are retrieved from disk by `prmDb` prior to the components requesting them: - -`Ref/Top/Topology.cpp`, line 206: - -```c++ - // read parameters - prmDb.readParamFile(); -``` - -Once the parameters are read by `prmDb`, the components can request them: - -`Ref/Top/Topology.cpp`, line 209: - -```c++ - sendBuffComp.loadParameters(); - - mathReceiver.loadParameters(); -``` - -The thread for the active `MathSender` component needs to be started: - -`Ref/Top/Topology.cpp`, line 261: - -```c++ - pingRcvr.start(); - - mathSender.start(); -``` - -The start call without arguments uses the OS defaults for priority, stack size, etc. - -The `MathReceiver` queued component will execute on the thread of the 1Hz rate group, which will be shown later. -It does not need to have a thread started, since queued components do not have threads. - -The `exitTasks()` function is called when the process is shut down. -It contains `exit()` calls to all the active components. -These functions internally send a message to the component's thread to shut down. - -`Ref/Top/Topology.cpp`, line 289: - -```c++ - pingRcvr.exit(); - - mathSender.exit(); -``` -## 3.2 Define Component Connections - -Components need to be connected to invoke each other via ports. -The connections are specified via a topology XML file. -The file for the Ref example is located in `Ref/Top/RefTopologyAppAi.xml` -The connections for the new components will be added to the existing connections. - -### 3.2.1 Component Imports - -The component XML definitions must be imported into the topology file: - -`Ref/Top/RefTopologyAppAi.xml`, line 33: - -```xml - Svc/Deframer/DeframerComponentAi.xml - - Ref/MathSender/MathSenderComponentAi.xml - Ref/MathReceiver/MathReceiverComponentAi.xml -``` - -### 3.2.2 Component Instances - -The Component instances must be declared. - -`Ref/Top/RefTopologyAppAi.xml`, line 55: - -```xml - - - - -``` - -The name in the `name=` attribute must match the one declared previously in `Ref/Top/Components.hpp`. For example: - -```c++ -extern Ref::MathSenderComponentImpl mathSender; -``` - -The type must match the type declared in the component XML: - -`Ref/MathSender/MathSenderComponentAi.xml`: - -```xml - -``` - -The `base_id` attribute specifies the beginning range of the assigned IDs for commands, telemetry, events, and parameters. -The values declared in the component XML are added to this base address. -This allows multiple instances of components to be declared with unique ID ranges. -The `base_id_window` attribute is used to set a limit on ID ranges for spacing the base IDs from different components sufficiently apart. -If the IDs exceed the limit, the code generator will issue a warning. - -### 3.2.3 Command connections - -The command connections should follow these rules: - -1. The port number of the command registration port on the `cmdDisp` component connection from the commanded components must be unique for all components. -2. The port number of the command dispatch port connection from the `cmdDisp` component to the commanded component must match the registration port number. -3. The command status from the components can go to port 0 of the command status port of the `cmdDisp` component. - -The following XML shows the command connection for the tutorial components. - -The port number used for the registration and dispatch ports is selected as 20, -a unique number that hasn't been used yet in the `Ref` example. - -`Ref/Top/RefTopologyAppAi.xml`, line 154: - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -### 3.2.4 Event Connections - -The output connections for log ports are connected to the `eventLogger` component. - -`Ref/Top/RefTopologyAppAi.xml`, line 376: - -```xml - - - - - - - - - - - - - - - - - - - - - -``` - -There are two kinds of connections for logging: One for a binary form that will be sent to the ground system, and a text version for displaying on standard output of the target machine. - -### 3.2.5 Telemetry Connections - -The telemetry output ports are connected to the `chanTlm` component. - -`Ref/Top/RefTopologyAppAi.xml`, line 546: - -```xml - - - - - - - - - - - -``` - -### 3.2.6 Parameter Connections - -There are two parameter connections, a `PrmGet` connection for reading parameters during software initialization and a `PrmSet` for updating parameters in the component that manages parameter values. F' has a basic parameter storage component `prmDb` that stores parameters in files. Upon bootup, they are read from a file specified in the constructor and stored in memory. Subsequent to this, components request their parameters via the `PrmGet` connection. If they are updated by command, they can be saved to storage by issuing a command to call the `PrmSet` with the new value and issuing the `PRM_SAVE_FILE` command. - -`Ref/Top/RefTopologyAppAi.xml`, line 629: - -```xml - - - - - - - - - - -``` - -### 3.2.7 Time Connections - -Components that have telemetry or events need to be able to time stamp the events. The time connections connect the components to a time source to provide the time stamps. - -`Ref/Top/RefTopologyAppAi.xml`, line 648: - -```xml - - - - - - - - - - -``` - -### 3.2.8 Scheduler Connection - -The `MathReceiver` component does not have a thread of its own, but relies on the thread of another component to drive it via the `SchedIn` port. The `SchedIn` port is connected to the 1Hz rate group component that is part of the `Ref` example. This means that every second the component gets a call and can unload messages from its message queue and dispatch them to handlers. - -`Ref/Top/RefTopologyAppAi.xml`, can be added near the end of the file after the previous connection's closing brace (``): - -```xml - - - - - -``` - -### 3.2.9 The Math Operation Connection - -The final connection is the connection that performs the math operation. It goes from `MathSender` to `MathReceiver`. - -`Ref/Top/RefTopologyAppAi.xml`, can be added after the Scheduler Connection which was inserted in the previous step: - -```xml - - - - - - - - - - - -``` - -Once all the updates to the topology file have been made, the module can be built by typing `fprime-util build` at the command line in the `Ref/` directory. -If the updates were correct, the module should compile with no errors. -The overall `Ref` deployment can be built by changing to the `Ref` directory and typing `fprime-util build`. - -If running on a different platform, you can specify the build target by typing `fprime-util generate `. - -## 4.1 Running the Ground System - -Once the `Ref` example has built successfully, you can run the ground system and executable by entering `fprime-gds -r fprime/Ref/build-artifacts`. The ground system GUI should appear. - -### 4.1.1 Executing Commands - -Commands can be executed by selecting the `Commands` tab and clicking on the `Cmds` drop-down list. - -For the tutorial example, select the `MathSender` command `MS_DO_MATH` and fill in the arguments. - -Clicking on the `Send` button will send the command to the software. When the command is sent, it is placed in the command history. It can be selected and sent again if the user desires. - -### 4.1.2 Checking Events - -The `Events` tab shows events that are generated by the software. For the tutorial, the events tab shows the events that were sent by the `MS_DO_MATH` command: - -It shows the F' `CmdDispatcher` event indicating a command was dispatched and completed. It also has the events defined by the tutorial example that are sent as a result of requesting a math operation. The result is zero, since the `factor1` value is zero, as shown in the unit testing in section `2.4.2.2`. - -The events are also echoed to `stdout` of the application, which can be found in the `Logs` tab, selecting "Ref.log" in the -dropdown. - -### 4.1.3 Checking Telemetry - -The `Channel Telemetry` tab shows channelized telemetry sent by the software. The channels defined by the tutorial have the last values and time they were updated: - -### 4.1.5 Updating `factor1` - -In order to get a non-zero result, `factor1` needs to be updated. The tutorial defined a command to update it, `MR_SET_FACTOR1`. It can be selected from the command tab: - -When the command is executed, the `Log Events` tab will show the event indicating the value was updated. - -The `Channel Telemetry` tab shows the two channels related to the update. `MR_FACTOR1` shows the new value, while `MR_FACTOR1S` show how many times the value has been updated. - -### 4.1.6 Running the Command Again - -After `factor1` has been updated, the command can be repeated: - -### 4.1.7 Updated Events and Telemetry - -The new events will appear in the `Log Events` tab: - -Notice that the updated events are added to the end of the log, since events are meant to be a record of events in the software. - -The `Channel Telemetry` tab will also show the updated values: - -Notice that the `MS_OP`, `MS_VAL1`, `MS_VAL2`, `MR_OPERATION`, and `MS_RESULT` are updated to the latest value with a more recent time stamp, since telemetry channels are meant to show the latest value. The new result is `10.0` now that `factor1` has been updated. - -### 4.1.8 Parameter Updates - -The tutorial defined a `factor2` parameter in the `MathReceiver` component. The code generator creates two commands for each parameter: `XXXX_PRM_SET` and `XXX_PRM_SAVE` where `XXX` is an upper case version of the parameter name. The `FACTOR2_PRM_SET` command will set the value in `MathReceiver`, while `FACTOR2_PRM_SAVE` will send the current value to `PrmDb` for storage. `PrmDb` is an F' infrastructure component that reads and writes parameters to storage. It is important to note that `PrmDb` does not immediately write the value to storage. There is an explicit `PRM_SAVE_FILE` command that will take all the parameter values currently in RAM and write them. - -#### 4.1.8.1 Setting the Parameter Value - -The `FACTOR1_PRM_SET` command can be sent to the software: - -The notification function that was implemented as part of the tutorial will send an event indicating the value was updated: - -The `MS_DO_MATH` command can now be executed with the new value: - -The `MathReceiver` component sends the events with the new result: - -The new result is `1.0` with the new value of `factor2`. The "Channel Telemetry" tab also shows the new values: - -#### 4.1.8.2 Saving the Parameter Value - -Once the parameter value has been tested to the user's satisfaction, it can be saved to `PrmDb` by sending the `FACTOR2_PRM_SAVE` command: - -The `Log Events` tab has an event from `PrmDb` indicating that the `FACTOR2` parameter value was added: - -#### 4.1.8.3 Writing the Parameter to Storage - -The parameter can be written to storage by sending the `PRM_SAVE_FILE` command: - -`PrmDb` sends an event indicating that the parameters in RAM were stored: - -### 4.1.9 Ground System Logs - -The ground system keeps logs of all received events and telemetry. They can be found in the directories `/logs/`, where `` is the location of the deployment. e.g. `Ref`. - -# Conclusion - -This tutorial is an attempt to communicate the concepts and implementation. If there are aspects that are confusing, -feel free to submit GitHub issues asking for clarification or to report errors: - -https://github.com/nasa/fprime/issues diff --git a/docs/Tutorials/MathComponent/adoc/Tutorial.adoc b/docs/Tutorials/MathComponent/adoc/Tutorial.adoc new file mode 100644 index 0000000000..9553a14a0e --- /dev/null +++ b/docs/Tutorials/MathComponent/adoc/Tutorial.adoc @@ -0,0 +1,2010 @@ += Math Component Tutorial +:toc: left +:toclevels: 3 + +== Introduction + +This tutorial shows how to develop, test, and deploy a simple topology +consisting of two components: + +. `MathSender`: A component that receives commands and forwards work to `MathReceiver`. +. `MathReceiver`: A component that carries out arithmetic operations and returns the results +to `MathSender`. + +See the diagram below. + +[#math-top] +.A simple topology for arithmetic computation +image::png/top.png[Math Sender and Math Receiver] + +*What is covered:* The tutorial covers the following concepts: + +. Using the https://fprime-community.github.io/fpp[FPP modeling language] +to specify the types and ports used by the components. +. Using the F Prime build system to build the types and ports. +. Developing the `MathSender` component: Specifying the component, +building the component, +completing the {cpp} component implementation, and writing +component unit tests. +. Developing the `MathReceiver` component. +. Adding the new components and connections to the F Prime +`Ref` application. +. Using the F Prime Ground Data System (GDS) to run the updated `Ref` +application. + +*Prerequisites:* This tutorial assumes the following: + +. Basic knowledge of Unix: How to navigate in a shell and execute programs. +. Basic knowledge of git: How to create a branch. +. Basic knowledge of {cpp}, including class declarations, inheritance, +and virtual functions. + +If you have not yet installed F Prime on your system, do so now. +Follow the installation guide at `INSTALL.md` +in the https://github.com/nasa/fprime[F Prime git repository]. +You may also wish to work through the Getting Started tutorial at +`docs/GettingStarted/Tutorial.md`. + +*Git branch:* This tutorial is designed to work on the branch `release/v3.0.0`. + +Working on this tutorial will modify some files under version control in the +F Prime git repository. +Therefore it is a good idea to do this work on a new branch. +For example: + +[source,bash] +---- +git checkout release/v3.0.0 +git checkout -b math-tutorial +---- + +If you wish, you can save your work by committing to this branch. + +== The MathOp Type + +In F Prime, a *type definition* defines a kind of data that you can pass +between components or use in commands and telemetry. + +For this tutorial, we need one type definition. +It defines an enumeration called `MathOp`, which +represents a mathematical operation. + +We will add the specification for the `MathOp` type to the +`Ref` topology. +We will do this in three stages: + +. Construct the FPP model. +. Add the model to the project. +. Build the model. + +=== Construct the FPP Model + +*Create the MathTypes directory:* +Go to the directory `Ref` at the top-level of the +F Prime repository and run `mkdir MathTypes`. +This step creates a new directory `Ref/MathTypes`. +This directory will contain our new type. + +*Create the FPP model file:* +Now go into the directory `Ref/MathTypes`. +In that directory, create a file `MathTypes.fpp` with the following contents: + +[source,fpp] +---- +include::../MathTypes/MathTypes.fpp[] +---- + +You can do this by typing, or by copy-paste. + +This file defines an enumeration or *enum* +with enumerated constants `ADD`, `SUB`, `MUL`, and `DIV`. +These four constants represent the operations +of addition, subtraction, multiplication, and division. +The enum also defines a type `MathOp`; the enumerated +constants are the values of this type. +For more information on enums, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Enums[_The FPP User's Guide_]. + +The enum `MathTypes` resides in an FPP module `Ref`. +An FPP module is like a {cpp} namespace: it encloses +several definitions, each of which is qualified with the +name of the module. +For more information on FPP modules, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Modules[_The FPP User's Guide_]. + +The text following a symbol `@` or `@<` is called an +*annotation*. +These annotations are carried through the parsing and +become comments in the generated code. +For more information, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Writing-Comments-and-Annotations[_The FPP User's Guide_]. + + +[[types_add]] +=== Add the Model to the Project + +*Create Ref/MathTypes/CMakeLists.txt:* +Create a file `Ref/MathTypes/CMakeLists.txt` with the following contents: + +[source,cmake] +---- +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathTypes.fpp" +) + +register_fprime_module() +---- + +This code will tell the build system how to build the FPP model. + +*Update Ref/CMakeLists.txt:* +Now we need to add the new directory to the `Ref` project. +To do that, open the file `Ref/CMakeLists.txt`. +This file should already exist; it was put there by the developers +of the `Ref` topology. +In this file, you should see several lines starting with `add_fprime_subdirectory`. +Immediately after the last of those lines, add the following new line: + +[source,cmake] +---- +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathTypes/") +---- + +[[types_build]] +=== Build the Model + +*Run the build:* +Do the following: + +. Go to the directory `Ref/MathTypes`. +. If you have not already run `fprime-util generate`, then do so now. +. Run the command `fprime-util build`. + +The output should indicate that the model built without any errors. +If not, try to identify and correct what is wrong, +either by deciphering the error output, or by going over the steps again. +If you get stuck, you can look at the <>. + +*Inspect the generated code:* +Now go to the directory `Ref/build-fprime-automatic-native/Ref/MathTypes` +(you may want to use `pushd`, or do this in a separate shell, +so you don't lose your current working directory). +The directory `build-fprime-automatic-native` is where all the +generated code lives for the "automatic native" build of the `Ref` +project. +Within that directory is a directory tree that mirrors the project +structure. +In particular, `Ref/build-fprime-automatic-native/Ref/MathTypes` +contains the generated code for `Ref/MathTypes`. + +Run `ls`. +You should see something like this: + +[source,bash] +---- +CMakeFiles MathOpEnumAc.cpp MathOpEnumAi.xml.prev cmake_install.cmake +Makefile MathOpEnumAc.hpp autocoder +---- + +The files `MathOpEnumAc.hpp` and +`MathOpEnumAc.cpp` are the auto-generated {cpp} files +corresponding to the `MathOp` enum. +You may wish to study the file `MathOpEnumAc.hpp`. +This file gives the interface to the {cpp} class `Ref::MathOp`. +All enum types have a similar auto-generated class +interface. + +[[types_ref]] +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathTypes`. +To build this implementation from a clean repository, +do the following: + +. Go to the `Ref` directory. + +. Run `cp -R ../docs/Tutorials/MathComponent/MathTypes .` + +. Update `Ref/CMakeLists.txt` as stated +<>. + +. Follow the steps for <>. + +If you have modified the repo, revise the steps accordingly. +For example, switch git branches, use `git stash` to stash +your changes, or move `MathTypes` to another directory such +as `MathTypes-saved`. + +[[ports]] +== The MathOp and MathResult Ports + +A *port* is the endpoint of a connection between +two components. +A *port definition* is like a function signature; +it defines the type of the data carried on a port. + +For this tutorial, we need two port definitions: + +* `MathOp` for sending an arithmetic operation request from +`MathSender` to `MathReceiver`. + +* `MathResult` for sending the result of an arithmetic +operation from `MathReceiver` to `MathSender`. + +We follow the same three steps as in the previous section. + +=== Construct the FPP Model + +*Create the MathPorts directory:* +Go to the directory `Ref` at the top-level of the +F Prime repository and run `mkdir MathPorts`. +This directory will contain our new ports. + +*Create the FPP model file:* +Now go into the directory `Ref/MathPorts`. +Create a file `MathPorts.fpp` with the following contents: + +[source,fpp] +---- +include::../MathPorts/MathPorts.fpp[] +---- + +This file defines the ports `MathOp` and `MathResult`. +`MathOp` has three formal parameters: a first operand, an +operation, and a second operand. +The operands have type `F32`, which represents a 32-bit +floating-point number. +The operation has type `MathOp`, which is the enum type +we defined in the previous section. +`MathResult` has a single formal parameter, the value of type `F32` +returned as the result of the operation. + +For more information about port definitions, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Ports[_The FPP User's Guide_]. + +=== Add the Model to the Project + +Add add the model +`Ref/MathPorts/MathPorts.fpp` to the `Ref` project. +Carry out the steps in the +<>, after +substituting `MathPorts` for `MathTypes`. + +=== Build the Model + +Carry out the steps in the +<>, +in directory `MathPorts` instead of `MathTypes`. +The generated code will go in +`Ref/build-fprime-automatic-native/Ref/MathPorts`. +For port definitions, the names of the auto-generated {cpp} +files end in `PortAc.hpp` and `PortAc.cpp`. +You can look at this code if you wish. +However, the auto-generated {cpp} port files are used +by the autocoded component implementations (described below); +you won't ever program directly against their interfaces. + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathPorts`. +To build this implementation, follow the steps +described for <>. + +[[math-sender]] +== The MathSender Component + +Now we can build and test the `MathSender` component. +There are five steps: + +. Construct the FPP model. +. Add the model to the project. +. Build the stub implementation. +. Complete the implementation. +. Write and run unit tests. + +=== Construct the FPP Model + +*Create the MathSender directory:* +Go to the directory `Ref` at the top-level of the +F Prime repository. +Run `mkdir MathSender` to create a directory for the new component. + +*Create the FPP model file:* +Now go into the directory `Ref/MathSender`. +Create a file `MathSender.fpp` with the following contents: + +[source,fpp] +---- +include::../MathSender/MathSender.fpp[] +---- + +This code defines a component `Ref.MathSender`. +The component is *active*, which means it has its +own thread. + +Inside the definition of the `MathSender` component are +several specifiers. +We have divided the specifiers into five groups: + +. *General ports:* These are user-defined ports for +application-specific functions. +There are two general ports: an output port `mathOpOut` +of type `MathOp` and an input port `mathResultIn` of +type `MathResult`. +Notice that these port specifiers use the ports that +we defined <>. +The input port is *asynchronous*. +This means that invoking the port (i.e., sending +data on the port) puts a message on a queue. +The handler runs later, on the thread of this component. + +. *Special ports:* These are ports that have a special +meaning in F Prime. +There are ports for registering commands with the dispatcher, +receiving commands, sending command responses, emitting +event reports, emitting telemetry, and getting the time. + +. *Commands:* These are commands sent from the ground +or from a sequencer and dispatched to this component. +There is one command `DO_MATH` for doing a math operation. +The command is asynchronous. +This means that when the command arrives, it goes on a queue +and its handler is later run on the thread of this component. + +. *Events:* These are event reports that this component +can emit. +There are two event reports, one for receiving a command +and one for receiving a result. + +. *Telemetry:* These are *channels* that define telemetry +points that the this component can emit. +There are four telemetry channels: three for the arguments +to the last command received and one for the last +result received. + +For more information on defining components, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components[_The FPP User's Guide_]. + +[[math-sender_add-model]] +=== Add the Model to the Project + +*Create Ref/MathSender/CMakeLists.txt:* +Create a file `Ref/MathSender/CMakeLists.txt` with the following contents: + +[source,cmake] +---- +# Register the standard build +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathSender.cpp" + "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" +) +register_fprime_module() +---- + +This code will tell the build system how to build the FPP model +and component implementation. + +*Update Ref/CMakeLists.txt:* +Add `Ref/MathSender` to `Ref/CMakeLists.txt`, as we did +for <>. + +[[math-sender_build-stub]] +=== Build the Stub Implementation + +*Run the build:* +Go into the directory `Ref/MathTypes`. +Run the following commands: + +[source,bash] +---- +touch MathSender.cpp +fprime-util impl +---- + +The first command creates an empty file `MathSender.cpp`. +The build rules we wrote in the previous section expect +this file to be there. +After the second command, the build system should +run for a bit. +At the end there should be two new files +in the directory: +`MathSenderComponentImpl.cpp-template` and +`MathSenderComponentImpl.hpp-template`. + +Run the following commands: + +[source,bash] +---- +mv MathSenderComponentImpl.cpp-template MathSender.cpp +mv MathSenderComponentImpl.hpp-template MathSender.hpp +---- + +These commands produce a template, or stub implementation, +of the `MathSender` implementation class. +You will fill in this implementation class below. + +Now run the command `fprime-util build --jobs 4`. +The model and the stub implementation should build. +The option `--jobs 4` says to use four cores for the build. +This should make the build go faster. +You can use any number after `--jobs`, up to the number +of cores available on your system. + +*Inspect the generated code:* +The generated code resides in the directory +`Ref/fprime-build-automatic-native-ut/Ref/MathSender`. +You may wish to look over the file `MathSenderComponentAc.hpp` +to get an idea of the interface to the auto-generated +base class `MathSenderComponentBase`. +The `MathSender` implementation class is a derived class +of this base class. + +=== Complete the Implementation + +Now we can complete the stub implementation. +In an editor, open the file `MathSender.cpp`. + +*Fill in the DO_MATH command handler:* +You should see a stub handler for the `DO_MATH` +command that looks like this: + +[source,c++] +---- +void MathSender :: + DO_MATH_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + F32 val1, + MathOp op, + F32 val2 + ) +{ + // TODO + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); +} +---- + +The handler `DO_MATH_handler` is called when the `MathSender` +component receives a `DO_MATH` command. +This handler overrides the corresponding pure virtual +function in the auto-generated base class. +Fill in the handler so that it looks like this: + +[source,c++] +---- +void MathSender :: + DO_MATH_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + F32 val1, + MathOp op, + F32 val2 + ) +{ + this->tlmWrite_VAL1(val1); + this->tlmWrite_OP(op); + this->tlmWrite_VAL2(val2); + this->log_ACTIVITY_LO_COMMAND_RECV(val1, op, val2); + this->mathOpOut_out(0, val1, op, val2); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} +---- + +The first two arguments to the handler function provide +the command opcode and the command sequence number +(a unique identifier generated by the command dispatcher). +The remaining arguments are supplied when the command is sent, +for example, from the F Prime ground data system (GDS). +The implementation code does the following: + +. Emit telemetry and events. +. Invoke the `mathOpOut` port to request that `MathReceiver` +perform the operation. +. Send a command response indicating success. +The command response goes out on the special port +`cmdResponseOut`. + +In F Prime, every execution of a command handler must end by +sending a command response. +The proper behavior of other framework components (e.g., command +dispatcher, command sequencer) depends upon adherence to this rule. + +*Check the build:* +Run `fprime-util build` again to make sure that everything still builds. + +*Fill in the mathResultIn handler:* +You should see a stub handler for the `mathResultIn` +port that looks like this: + +[source,c++] +---- +void MathSender :: + mathResultIn_handler( + const NATIVE_INT_TYPE portNum, + F32 result + ) +{ + // TODO +} +---- + +The handler `mathResultIn_handler` is called when the `MathReceiver` +component code returns a result by invoking the `mathResultIn` port. +Again the handler overrides the corresponding pure virtual +function in the auto-generated base class. +Fill in the handler so that it looks like this: + +[source,c++] +---- +void MathSender :: + mathResultIn_handler( + const NATIVE_INT_TYPE portNum, + F32 result + ) +{ + this->tlmWrite_RESULT(result); + this->log_ACTIVITY_HI_RESULT(result); +} +---- + +The implementation code emits the result on the `RESULT` +telemetry channel and as a `RESULT` event report. + +*Check the build:* +Run `fprime-util build`. + +[[math-sender_unit]] +=== Write and Run Unit Tests + +*Unit tests* are an important part of FSW development. +At the component level, unit tests typically invoke input ports, send commands, +and check for expected values on output ports (including telemetry and event +ports). + +We will carry out the unit testing for the `MathSender` component +in three steps: + +. Set up the unit test environment +. Write and run one unit test +. Write and run additional unit tests + +[[math-sender_unit_setup]] +==== Set Up the Unit Test Environment + +*Create the stub Tester class:* +Do the following in directory `Ref/MathSender`: + +. Run `mkdir -p test/ut` to create the directory where +the unit tests will reside. + +. Run the command `fprime-util impl --ut`. +It should generate files `Tester.cpp` and `Tester.hpp`. + +. Move these files to the `test/ut` directory: + ++ +[source,bash] +---- +mv Tester.* test/ut +---- + +*Create a stub main.cpp file:* +Now go to the directory `Ref/MathSender/test/ut`. +In that directory, create a file `main.cpp` with the +following contents: + +[source,c++] +---- +#include "Tester.hpp" + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +---- + +This file is a stub for running tests using the +https://github.com/google/googletest[Google Test framework]. +Right now there aren't any tests to run; we will add one +in the next section. + +*Update Ref/MathSender/CMakeLists.txt:* +Go back to the directory `Ref/MathSender`. +Add the following lines to `CMakeLists.txt`: + +[source,cmake] +---- +# Register the unit test build +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp" +) +register_fprime_ut() +---- + +This code tells the build system how to build +and run the unit tests. + +*Run the build:* +Now we can check that the unit test build is working. + +. If you have not yet run `fprime-util generate --ut`, +then do so now. +This step generates the CMake build cache for the unit +tests. + +. Run `fprime-util build --ut`. +Everything should build without errors. + +*Inspect the generated code:* +The generated code is located at +`Ref/build-fprime-automatic-native-ut/Ref/MathSender`. +This directory contains two auto-generated classes: + +. `MathSenderGTestBase`: This is the direct base +class of `Tester`. +It provides a test interface implemented with Google Test +macros. + +. `MathSenderTesterBase`: This is the direct base +class of `MathSenderGTestBase`. +It provides basic features such as histories of port +invocations. +It is not specific to Google Test, so you can +use this class without Google Test if desired. + +You can look at the header files for these generated classes +to see what operations they provide. +In the next sections we will provide some example uses +of these operations. + +==== Write and Run One Test + +Now we will write a unit test that exercises the +`DO_MATH` command. +We will do this in three phases: + +. In the `Tester` class, add a helper function for sending the command and +checking the responses. +That way multiple tests can reuse the same code. + +. In the `Tester` class, write a test function that +calls the helper to run a test. + +. In the `main` function, write a Google Test macro +that invokes the test function. + +. Run the test. + +*Add a helper function:* +Go into the directory `Ref/MathSender/test/ut`. +In the file `Tester.hpp`, add the following lines +to the section entitled "Helper methods": + +[source,c++] +---- +//! Test a DO_MATH command +void testDoMath(MathOp op); +---- + +In the file `Tester.cpp`, add the corresponding +function body: + +[source,c++] +---- +void Tester :: + testDoMath(MathOp op) +{ + + // Pick values + + const F32 val1 = 2.0; + const F32 val2 = 3.0; + + // Send the command + + // pick a command sequence number + const U32 cmdSeq = 10; + // send DO_MATH command + this->sendCmd_DO_MATH(0, cmdSeq, val1, op, val2); + // retrieve the message from the message queue and dispatch the command to the handler + this->component.doDispatch(); + + // Verify command receipt and response + + // verify command response was sent + ASSERT_CMD_RESPONSE_SIZE(1); + // verify the command response was correct as expected + ASSERT_CMD_RESPONSE(0, MathSenderComponentBase::OPCODE_DO_MATH, cmdSeq, Fw::CmdResponse::OK); + + // Verify operation request on mathOpOut + + // verify that that one output port was invoked overall + ASSERT_FROM_PORT_HISTORY_SIZE(1); + // verify that the math operation port was invoked once + ASSERT_from_mathOpOut_SIZE(1); + // verify the arguments of the operation port + ASSERT_from_mathOpOut(0, val1, op, val2); + + // Verify telemetry + + // verify that 3 channels were written + ASSERT_TLM_SIZE(3); + // verify that the desired telemetry values were sent once + ASSERT_TLM_VAL1_SIZE(1); + ASSERT_TLM_VAL2_SIZE(1); + ASSERT_TLM_OP_SIZE(1); + // verify that the correct telemetry values were sent + ASSERT_TLM_VAL1(0, val1); + ASSERT_TLM_VAL2(0, val2); + ASSERT_TLM_OP(0, op); + + // Verify event reports + + // verify that one event was sent + ASSERT_EVENTS_SIZE(1); + // verify the expected event was sent once + ASSERT_EVENTS_COMMAND_RECV_SIZE(1); + // verify the correct event arguments were sent + ASSERT_EVENTS_COMMAND_RECV(0, val1, op, val2); + +} +---- + +This function is parameterized over different +operations. +It is divided into five sections: sending the command, +checking the command response, checking the output on +`mathOpOut`, checking telemetry, and checking events. +The comments explain what is happening in each section. +For further information about the F Prime unit test +interface, see the F Prime User's Guide. + +Notice that after sending the command to the component, we call +the function `doDispatch` on the component. +We do this in order to simulate the behavior of the active +component in a unit test environment. +In a flight configuration, the component has its own thread, +and the thread blocks on the `doDispatch` call until another +thread puts a message on the queue. +In a unit test context, there is only one thread, so the pattern +is to place work on the queue and then call `doDispatch` on +the same thread. + +There are a couple of pitfalls to watch out for with this pattern: + +. If you put work on the queue and forget to call `doDispatch`, +the work won't get dispatched. +Likely this will cause a unit test failure. + +. If you call `doDispatch` without putting work on the queue, +the unit test will block until you kill the process (e.g., +with control-C). + +*Write a test function:* +Next we will write a test function that calls +`testDoMath` to test an `ADD` operation. +In `Tester.hpp`, add the following line in the +section entitled "Tests": + +[source,c++] +---- +//! Test an ADD command +void testAddCommand(); +---- + +In `Tester.cpp`, add the corresponding function +body: + +[source,c++] +---- +void Tester :: + testAddCommand() +{ + this->testDoMath(MathOp::ADD); +} +---- + +This function calls `testDoMath` to test an `ADD` command. + +*Write a test macro:* +Add the following code to the file `main.cpp`, +before the definition of the `main` function: + +[source,c++] +---- +TEST(Nominal, AddCommand) { + Ref::Tester tester; + tester.testAddCommand(); +} +---- + +The `TEST` macro is an instruction to Google Test to run a test. +`Nominal` is the name of a test suite. +We put this test in the `Nominal` suite because it addresses +nominal (expected) behavior. +`AddCommand` is the name of the test. +Inside the body of the macro, the first line declares a new +object `tester` of type `Tester`. +We typically declare a new object for each unit test, so that +each test starts in a fresh state. +The second line invokes the function `testAddCommand` +that we wrote in the previous section. + +*Run the test:* +Go back to directory `Ref/MathSender`. +Run the command `fprime-util check`. +The build system should compile and run the unit +tests. +You should see output indicating that the test ran +and passed. + +As an exercise, try the following: + +. Change the behavior of the component +so that it does something correct. +For example, try adding one to a telemetry +value before emitting it. + +. Rerun the test and observe what happens. + +==== Write and Run More Tests + +*Add more command tests:* +Try to follow the pattern given in the previous +section to add three more tests, one each +for operations `SUB`, `MUL`, and `DIV`. +Most of the work should be done in the helper +that we already wrote. +Each new test requires just a short test function +and a short test macro. + +Run the tests to make sure everything compiles and +the tests pass. + +*Add a result test:* +Add a test for exercising the scenario in which the `MathReceiver` +component sends a result back to `MathSender`. + +. Add the following function signature in the "Tests" +section of to `Tester.hpp`: + ++ +[source,c++] +---- +//! Test receipt of a result +void testResult(); +---- + +. Add the corresponding function body in `Tester.cpp`: + ++ +[source,cpp] +---- +void Tester :: + testResult() +{ + // Generate an expected result + const F32 result = 10.0; + // reset all telemetry and port history + this->clearHistory(); + // call result port with result + this->invoke_to_mathResultIn(0, result); + // retrieve the message from the message queue and dispatch the command to the handler + this->component.doDispatch(); + // verify one telemetry value was written + ASSERT_TLM_SIZE(1); + // verify the desired telemetry channel was sent once + ASSERT_TLM_RESULT_SIZE(1); + // verify the values of the telemetry channel + ASSERT_TLM_RESULT(0, result); + // verify one event was sent + ASSERT_EVENTS_SIZE(1); + // verify the expected event was sent once + ASSERT_EVENTS_RESULT_SIZE(1); + // verify the expect value of the event + ASSERT_EVENTS_RESULT(0, result); +} +---- + ++ +This code is similar to the helper function in the previous section. +The main difference is that it invokes a port directly +(the `mathResultIn` port) instead of sending a command. + +. Add the following test macro to `main.cpp`: + ++ +[source,cpp] +---- +TEST(Nominal, Result) { + Ref::Tester tester; + tester.testResult(); +} +---- + +. Run the tests. +Again you can try altering something in the component code +to see what effect it has on the test output. + +[[math-sender_exercise]] +==== Exercise: Random Testing + +F Prime provides a module called `STest` +that provides helper classes and functions for writing +unit tests. +As an exercise, use the interface provided by +`STest/STest/Pick.hpp` to pick random values to use in the +tests instead of using hard-coded values such as 2.0, 3.0, +and 10. + +*Modifying the code:* You will need to do the following: + +. Add `#include "STest/Pick/Pick.hpp"` to `Tester.cpp`. + +. Add the following +line to `Ref/MathSender/CMakeLists.txt`, before `register_fprime_ut`: + ++ +[source,cmake] +---- +set(UT_MOD_DEPS STest) +---- + ++ +This line tells the build system to make the unit test build +depend on the `STest` build module. + +. Add `#include STest/Random/Random.hpp` to `main.cpp`. + +. Add the following line to the `main` function of `main.cpp`, +just before the return statement: + ++ +[source,cpp] +---- +STest::Random::seed(); +---- + ++ +This line seeds the random number generator used by STest. + +*Running the tests:* +Recompile and rerun the tests. +Now go to +`Ref/build-fprime-automatic-native-ut/Ref/MathSender` and inspect the +file `seed-history`. +This file is a log of random seed values. +Each line represents the seed used in the corresponding run. + +*Fixing the random seed:* +Sometimes you may want to run a test with a particular seed value, +e.g., for replay debugging. +To do this, put the seed value into a file `seed` in the same +directory as `seed-history`. +If the file `seed` exists, then STest will use the seed it contains instead +of generating a new seed. + +Try the following: + +. Copy the last value _S_ of `seed-history` into `seed`. + +. In `Ref/MathSender`, re-run the unit tests a few times. + +. Inspect `Ref/build-fprime-automatic-native-ut/Ref/MathSender/seed-history`. +You should see that the value _S_ was used in the runs you just did +(corresponding to the last few entries in `seed-history`). + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathSender`. + +== The MathReceiver Component + +Now we will build and test the `MathReceiver` component. +We will use the same five steps as for the +<>. + +=== Construct the FPP Model + +*Create the MathReceiver directory:* +Create the directory `Ref/MathReceiver`. + +*Create the FPP model file:* +In directory `Ref/MathReceiver`, create a file +`MathReceiver.fpp` with the following contents: + +[source,fpp] +---- +include::../MathReceiver/MathReceiver.fpp[] +---- + +This code defines a component `Ref.MathReceiver`. +The component is *queued*, which means it has a queue +but no thread. +Work occurs when the thread of another component invokes +the `schedIn` port of this component. + +We have divided the specifiers of this component into six groups: + +. *General ports:* There are three ports: +an input port `mathOpIn` for receiving a math operation, +an output port `mathResultOut` for sending a math result, and +an input port `schedIn` for receiving invocations from the scheduler. +`mathOpIn` is asynchronous. +That means invocations of `mathOpIn` put messages on a queue. +`schedIn` is synchronous. +That means invocations of `schedIn` immediately call the +handler function to do work. + +. *Special ports:* +As before, there are special ports for commands, events, telemetry, +and time. +There are also special ports for getting and setting parameters. +We will explain the function of these ports below. + +. *Parameters:* There is one *parameter*. +A parameter is a constant that is configurable by command. +In this case there is one parameter `FACTOR`. +It has the default value 1.0 until its value is changed by command. +When doing math, the `MathReceiver` component performs the requested +operation and then multiplies by this factor. +For example, if the arguments of the `mathOpIn` port +are _v1_, `ADD`, and _v2_, and the factor is _f_, +then the result sent on `mathResultOut` is +_(v1 + v2) f_. + +. *Events:* There are three event reports: + +.. `FACTOR_UPDATED`: Emitted when the `FACTOR` parameter +is updated by command. +This event is *throttled* to a limit of three. +That means that after the event is emitted three times +it will not be emitted any more, until the throttling +is cleared by command (see below). + +.. `OPERATION_PERFORMED`: Emitted when this component +performs a math operation. + +.. `THROTTLE_CLEARED`: Emitted when the event throttling +is cleared. + +. *Commands:* There is one command for clearing +the event throttle. + +. *Telemetry:* +There two telemetry channels: one for reporting +the last operation received and one for reporting +the factor parameter. + +For the parameters, events, commands, and telemetry, we chose +to put in all the opcodes and identifiers explicitly. +These can also be left implicit, as in the `MathSender` +component example. +For more information, see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components[_The FPP User's Guide_]. + +=== Add the Model to the Project + +Follow the steps given for the +<>. + +=== Build the Stub Implementation + +Follow the same steps as for the +<>. + +=== Complete the Implementation + +*Fill in the mathOpIn handler:* +In `MathReceiver.cpp`, complete the implementation of +`mathOpIn_handler` so that it looks like this: + +[source,cpp] +---- +void MathReceiver :: + mathOpIn_handler( + const NATIVE_INT_TYPE portNum, + F32 val1, + const MathOp& op, + F32 val2 + ) +{ + + // Get the initial result + F32 res = 0.0; + switch (op.e) { + case MathOp::ADD: + res = val1 + val2; + break; + case MathOp::SUB: + res = val1 - val2; + break; + case MathOp::MUL: + res = val1 * val2; + break; + case MathOp::DIV: + res = val1 / val2; + break; + default: + FW_ASSERT(0, op.e); + break; + } + + // Get the factor value + Fw::ParamValid valid; + F32 factor = paramGet_FACTOR(valid); + FW_ASSERT( + valid.e == Fw::ParamValid::VALID || valid.e == Fw::ParamValid::DEFAULT, + valid.e + ); + + // Multiply result by factor + res *= factor; + + // Emit telemetry and events + this->log_ACTIVITY_HI_OPERATION_PERFORMED(op); + this->tlmWrite_OPERATION(op); + + // Emit result + this->mathResultOut_out(0, res); + +} +---- + +This code does the following: + +. Compute an initial result based on the input values and +the requested operation. + +. Get the value of the factor parameter. +Check that the value is a valid value from the parameter +database or a default parameter value. + +. Multiply the initial result by the factor to generate +the final result. + +. Emit telemetry and events. + +. Emit the result. + +Note that in step 1, `op` is an enum (a {cpp} class type), and `op.e` +is the corresponding numeric value (an integer type). +Note also that in the `default` case we deliberately fail +an assertion. +This is a standard pattern for exhaustive case checking. +We should never hit the assertion. +If we do, then a bug has occurred: we missed a case. + +*Fill in the schedIn handler:* +In `MathReceiver.cpp`, complete the implementation of +`schedIn_handler` so that it looks like this: + +[source,cpp] +---- +void MathReceiver :: + schedIn_handler( + const NATIVE_INT_TYPE portNum, + NATIVE_UINT_TYPE context + ) +{ + U32 numMsgs = this->m_queue.getNumMsgs(); + for (U32 i = 0; i < numMsgs; ++i) { + (void) this->doDispatch(); + } +} +---- + +This code dispatches all the messages on the queue. +Note that for a queued component, we have to do this +dispatch explicitly in the `schedIn` handler. +For an active component, the framework auto-generates +the dispatch code. + +*Fill in the CLEAR_EVENT_THROTTLE command handler:* +In `MathReceiver.cpp`, complete the implementation of +`CLEAR_EVENT_THROTTLE_cmdHandler` so that it looks like this: + +[source,cpp] +---- +void MathReceiver :: + CLEAR_EVENT_THROTTLE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) +{ + // clear throttle + this->log_ACTIVITY_HI_FACTOR_UPDATED_ThrottleClear(); + // send event that throttle is cleared + this->log_ACTIVITY_HI_THROTTLE_CLEARED(); + // reply with completion status + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} +---- + +The call to `log_ACTIVITY_HI_FACTOR_UPDATED_ThrottleClear` clears +the throttling of the `FACTOR_UPDATED` event. +The next two lines send a notification event and send +a command response. + +*Add a parameterUpdated function:* +Add the following function to `MathReceiver.cpp`. +You will need to add the corresponding function header +to `MathReceiver.hpp`. + +[source,cpp] +---- +void MathReceiver :: + parameterUpdated(FwPrmIdType id) +{ + switch (id) { + case PARAMID_FACTOR: { + Fw::ParamValid valid; + F32 val = this->paramGet_FACTOR(valid); + FW_ASSERT( + valid.e == Fw::ParamValid::VALID || valid.e == Fw::ParamValid::DEFAULT, + valid.e + ); + this->log_ACTIVITY_HI_FACTOR_UPDATED(val); + break; + } + default: + FW_ASSERT(0, id); + break; + } +} +---- + +This code implements an optional function that, if present, +is called when a parameter is updated by command. +The parameter identifier is passed in as the `id` argument +of the function. +Here we do the following: + +. If the parameter identifier is `PARAMID_FACTOR` (the parameter +identifier corresponding to the `FACTOR` parameter, +then get the parameter value and emit an event report. + +. Otherwise fail an assertion. +This code should never run, because there are no other +parameters. + +=== Write and Run Unit Tests + +==== Set up the Unit Test Environment + +. Follow the steps given for the +<>. + +. Follow the steps given under *Modifying the code* +for the +<>, +so that you can use STest to pick random values. + +==== Add Helper Code + +*Add a ThrottleState enum class:* +Add the following code to the beginning of the +`Tester` class in `Tester.hpp`: + +[source,cpp] +---- +private: + + // ---------------------------------------------------------------------- + // Types + // ---------------------------------------------------------------------- + + enum class ThrottleState { + THROTTLED, + NOT_THROTTLED + }; +---- + +This code defines a {cpp} enum class for recording whether an +event is throttled. + +*Add helper functions:* +Add each of the functions described below to the +"Helper methods" section of `Tester.cpp`. +For each function, you must add +the corresponding function prototype to `Tester.hpp`. +After adding each function, compile the unit tests +to make sure that everything still compiles. +Fix any errors that occur. + +Add a `pickF32Value` function. + +[source,cpp] +---- +F32 Tester :: + pickF32Value() +{ + const F32 m = 10e6; + return m * (1.0 - 2 * STest::Pick::inUnitInterval()); +} +---- + +This function picks a random `F32` value in the range +_[ -10^6, 10^6 ]_. + +Add a `setFactor` function. + +[source,cpp] +---- +void Tester :: + setFactor( + F32 factor, + ThrottleState throttleState + ) +{ + // clear history + this->clearHistory(); + // set the parameter + this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); + const U32 instance = STest::Pick::any(); + const U32 cmdSeq = STest::Pick::any(); + this->paramSend_FACTOR(instance, cmdSeq); + if (throttleState == ThrottleState::NOT_THROTTLED) { + // verify the parameter update notification event was sent + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_FACTOR_UPDATED_SIZE(1); + ASSERT_EVENTS_FACTOR_UPDATED(0, factor); + } + else { + ASSERT_EVENTS_SIZE(0); + } +} +---- + +This function does the following: + +. Clear the test history. + +. Send a command to the component to set the `FACTOR` parameter +to the value `factor`. + +. If `throttleState` is `NOT_THROTTLED`, then check +that the event was emitted. +Otherwise check that the event was throttled (not emitted). + +Add a function `computeResult` to `Tester.cpp`. + +[source,cpp] +---- +F32 Tester :: + computeResult( + F32 val1, + MathOp op, + F32 val2, + F32 factor + ) +{ + F32 result = 0; + switch (op.e) { + case MathOp::ADD: + result = val1 + val2; + break; + case MathOp::SUB: + result = val1 - val2; + break; + case MathOp::MUL: + result = val1 * val2; + break; + case MathOp::DIV: + result = val1 / val2; + break; + default: + FW_ASSERT(0, op.e); + break; + } + result *= factor; + return result; +} +---- + +This function carries out the math computation of the +math component. +By running this function and comparing, we can +check the output of the component. + +Add a `doMathOp` function to `Tester.cpp`. + +[source,cpp] +---- +void Tester :: + doMathOp( + MathOp op, + F32 factor + ) +{ + + // pick values + const F32 val1 = pickF32Value(); + const F32 val2 = pickF32Value(); + + // clear history + this->clearHistory(); + + // invoke operation port with add operation + this->invoke_to_mathOpIn(0, val1, op, val2); + // invoke scheduler port to dispatch message + const U32 context = STest::Pick::any(); + this->invoke_to_schedIn(0, context); + + // verify the result of the operation was returned + + // check that there was one port invocation + ASSERT_FROM_PORT_HISTORY_SIZE(1); + // check that the port we expected was invoked + ASSERT_from_mathResultOut_SIZE(1); + // check that the component performed the operation correctly + const F32 result = computeResult(val1, op, val2, factor); + ASSERT_from_mathResultOut(0, result); + + // verify events + + // check that there was one event + ASSERT_EVENTS_SIZE(1); + // check that it was the op event + ASSERT_EVENTS_OPERATION_PERFORMED_SIZE(1); + // check that the event has the correct argument + ASSERT_EVENTS_OPERATION_PERFORMED(0, op); + + // verify telemetry + + // check that one channel was written + ASSERT_TLM_SIZE(1); + // check that it was the op channel + ASSERT_TLM_OPERATION_SIZE(1); + // check for the correct value of the channel + ASSERT_TLM_OPERATION(0, op); + +} +---- + +This function is similar to the `doMath` helper function that +we wrote for the `MathSender` component. +Notice that the method for invoking a port is different. +Since the component is queued, we don't call `doDispatch` +directly. +Instead we invoke `schedIn`. + +==== Write and Run Tests + +For each of the tests described below, you must add the +corresponding function prototype to `Tester.hpp` +and the corresponding test macro to `main.cpp`. +If you can't remember how to do it, look back at the +`MathSender` examples. +After writing each test, run all the tests and make sure +that they pass. + +*Write an ADD test:* +Add the following function to the "Tests" section of `Tester.cpp`: + +[source,cpp] +---- +void Tester :: + testAdd() +{ + // Set the factor parameter by command + const F32 factor = pickF32Value(); + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + // Do the add operation + this->doMathOp(MathOp::ADD, factor); +} +---- + +This function calls the `setFactor` helper function +to set the factor parameter. +Then it calls the `doMathOp` function to +do a math operation. + +*Write a SUB test:* +Add the following function to the "Tests" section of `Tester.cpp`: + +[source,cpp] +---- +void Tester :: + testSub() +{ + // Set the factor parameter by loading parameters + const F32 factor = pickF32Value(); + this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); + this->component.loadParameters(); + // Do the operation + this->doMathOp(MathOp::SUB, factor); +} +---- + +This test is similar to `testAdd`, but it shows +another way to set a parameter. +`testAdd` showed how to set a parameter by command. +You can also set a parameter by initialization, as follows: + +. Call the `paramSet` function as shown. +This function sets the parameter value in +the part of the test harness that mimics the behavior of the +parameter database component. + +. Call the `loadParameters` function as shown. +In flight, the function `loadParameters` is typically called at the +start of FSW to load the parameters from the database; +here it loads the parameters from the test harness. +There is no command to update a parameter, so `parameterUpdated` +is not called, and no event is emitted. + +As before, after setting the parameter we call `doMathOp` +to do the operation. + +*Write a MUL test:* +This test is the same as the ADD test, except that it +uses MUL instead of add. + +*Write a DIV test:* +This test is the same as the SUB test, except that it +uses DIV instead of SUB. + +*Write a throttle test:* +Add the following function to the "Tests" section of `Tester.cpp`: + +[source,cpp] +---- +void Tester :: + testThrottle() +{ + + // send the number of commands required to throttle the event + // Use the autocoded value so the unit test passes if the + // throttle value is changed + const F32 factor = pickF32Value(); + for ( + U16 cycle = 0; + cycle < MathReceiverComponentBase::EVENTID_FACTOR_UPDATED_THROTTLE; + cycle++ + ) { + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + } + + // Event should now be throttled + this->setFactor(factor, ThrottleState::THROTTLED); + + // send the command to clear the throttle + this->sendCmd_CLEAR_EVENT_THROTTLE(INSTANCE, CMD_SEQ); + // invoke scheduler port to dispatch message + const U32 context = STest::Pick::any(); + this->invoke_to_schedIn(0, context); + // verify clear event was sent + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_THROTTLE_CLEARED_SIZE(1); + + // Throttling should be cleared + this->setFactor(factor, ThrottleState::NOT_THROTTLED); + +} +---- + +This test first loops over the throttle count, which is stored +for us in the constant `EVENTID_FACTOR_UPDATED_THROTTLE` +of the `MathReceiver` component base class. +On each iteration, it calls `setFactor`. +At the end of this loop, the `FACTOR_UPDATED` event should be +throttled. + +Next the test calls `setFactor` with a second argument of +`ThrottleState::THROTTLED`. +This code checks that the event is throttled. + +Next the test sends the command `CLEAR_EVENT_THROTTLE`, +checks for the corresponding notification event, +and checks that the throttling is cleared. + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/MathReceiver`. + +=== Exercises + +==== Adding Telemetry + +Add a telemetry channel that records the number of math +operations performed. + +. Add the channel to the FPP model. + +. In the component implementation class, add a member +variable `numMathOps` of type `U32`. +Initialize the variable to zero in the class constructor. + +. Revise the `mathOpIn` handler so that it increments +`numMathOps` and emits the updated value as telemetry. + +. Revise the unit tests to cover the new behavior. + +==== Error Handling + +Think about what will happen if the floating-point +math operation performed by `MathReceiver` causes an error. +For example, suppose that `mathOpIn` is invoked with `op = DIV` +and `val2 = 0.0`. +What will happen? +As currently designed and implemented, the `MathReceiver` +component will perform the requested operation. +On some systems the result will be `INF` (floating-point infinity). +In this case, the result will be sent back to `MathSender` +and reported in the usual way. +On other systems, the hardware could issue a floating-point exception. + +Suppose you wanted to handle the case of division by zero +explicitly. +How would you change the design? +Here are some questions to think about: + +. How would you check for division by zero? +Note that `val2 = 0.0` is not the only case in which a division +by zero error can occur. +It can also occur for very small values of `val2`. + +. Should the error be caught in `MathSender` or `MathReceiver`? + +. Suppose the design says that `MathSender` catches the error, +and so never sends requests to `MathReceiver` to divide by zero. +What if anything should `MathReceiver` do if it receives +a divide by zero request? +Carry out the operation normally? +Emit a warning? +Fail a FSW assertion? + +. If the error is caught by `MathReceiver`, does the +interface between the components have to change? +If so, how? +What should `MathSender` do if `MathReceiver` +reports an error instead of a valid result? + +Revise the MathSender and MathReceiver components to implement your +ideas. +Add unit tests covering the new behavior. + +== Updating the Ref Deployment + +The next step in the tutorial is to define instances of the +`MathSender` and `MathReceiver` components and add them +to the `Ref` topology. + +=== Defining the Component Instances + +Go to the directory `Ref/Top` and open the file `instances.fpp`. +This file defines the instances used in the topology for the +`Ref` application. +Update this file as described below. + +*Define the mathSender instance:* +At the end of the section entitled "Active component instances," +add the following lines: + +[source,fpp] +---- +instance mathSender: Ref.MathSender base id 0xE00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 100 +---- + +This code defines an instance `mathSender` of component +`MathSender`. +It has *base identifier* 0xE00. +FPP adds the base identifier to each the relative identifier +defined in the component to compute the corresponding +identifier for the instance. +For example, component `MathSender` has a telemetry channel +`MathOp` with identifier 1, so instance `mathSender` +has a command `MathOp` with identifier 0xE01. + +The following lines define the queue size, stack size, +and thread priority for the active component. +Here we give `mathSender` the default queue size +and stack size and a priority of 100. + +*Define the mathReceiver instance:* +At the end of the section "Queued component instances," +add the following lines: + +[source,fpp] +---- +instance mathReceiver: Ref.MathReceiver base id 0x2700 \ + queue size Default.queueSize +---- + +This code defines an instance `mathReceiver` of +component `MathReceiver`. +It has base identifier 0x2700 and the default queue size. + +*More information:* +For more information on defining component instances, +see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Component-Instances[_The FPP User's Guide_]. + +=== Updating the Topology + +Go to the directory `Ref/Top` and open the file `topology.fpp`. +This file defines the topology for the `Ref` application. +Update this file as described below. + +*Add the new instances:* +You should see a list of instances, each of which begins +with the keyword `instance`. +After the line `instance linuxTime`, add the following +lines: + +[source,fpp] +---- +instance mathSender +instance mathReceiver +---- + +These lines add the `mathSender` and `mathReceiver` +instances to the topology. + +*Check for unconnected ports:* +This capability does not yet exist in the F Prime build system. +When it does, you will be able to see a list of ports +that are unconnected in the `Ref` topology. +Those ports will include the ports for the new instances +`mathSender` and `mathReceiver`. + +*Connect mathReceiver to rate group 1:* +Find the line that starts `connections RateGroups`. +This is the beginning of the definition of the `RateGroups` +connection graph. +Inside the block of that definition, +find the line +`rateGroup1Comp.RateGroupMemberOut[3] pass:[->] fileDownlink.Run`. +After that line, add the line + +[source,fpp] +---- +rateGroup1Comp.RateGroupMemberOut[4] -> mathReceiver.schedIn +---- + +This line adds the connection that drives the `schedIn` +port of the `mathReceiver` component instance. + +*Re-run the check for unconnected ports:* +When this capability exists, you will be able to see +that `mathReceiver.schedIn` is now connected +(it no longer appears in the list). + +*Add the Math connections:* +Find the Uplink connections that begin with the line +`connections Uplink`. +After the block of that definition, add the following +lines: + +[source,fpp] +---- +connections Math { + mathSender.mathOpOut -> mathReceiver.mathOpIn + mathReceiver.mathResultOut -> mathSender.mathResultIn +} +---- + +These lines add the connections between the `mathSender` +and `mathReceiver` instances. + +*Re-run the check for unconnected ports:* +When this capability exists, you will be able to see +that the `mathSender` and `mathReceiver` ports are connected. + +*More information:* +For more information on defining topologies, +see +https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Topologies[_The FPP User's Guide_]. + +=== Building the Ref Deployment + +Go to the `Ref` directory. +Run `fprime-util build --jobs 4`. +The updated deployment should build without errors. +The generated files are located at +`Ref/build-fprime-automatic-native/Ref/Top`. + +=== Visualizing the Ref Topology + +Now we will see how to create a visualization (graphical rendering) +of the Ref topology. + +*Generate the layout:* +For this step, we will use the F Prime Layout (FPL) tool. +If FPL is not installed on your system, then install it how: +clone +https://github.com/fprime-community/fprime-layout[this +repository] and follow the instructions. + +In directory `Ref/Top`, run the following commands in an sh-compatible +shell such as bash. +If you are using a different shell, you can run `sh` +to enter the `sh` shell, run these commands, and enter +`exit` when done. +Or you can stay in your preferred shell and adjust these commands +appropriately. + +[source,bash] +---- +cp ../build-fprime-automatic-native/Ref/Top/RefTopologyAppAi.xml . +mkdir visual +cd visual +fpl-extract-xml < ../RefTopologyAppAi.xml +mkdir Ref +for file in `ls *.xml` +do +echo "laying out $file" +base=`basename $file .xml` +fpl-convert-xml $file | fpl-layout > Ref/$base.json +done +---- + +This step extracts the connection graphs from the topology XML and +converts each one to a JSON layout file. + +*Render the layout:* +For this step, we will use the F Prime Visualizer (FPV) tool. +If FPV is not installed on your system, then install it now: +clone +https://github.com/fprime-community/fprime-visual[this +repository] and follow the instructions. + +In directory `Ref/Top`, run the following commands in an sh-compatible +shell. +Replace `[path to fpv root]` with the path to the +root of the FPV repo on your system. + +[source,bash] +---- +echo DATA_FOLDER=Ref/ > .fpv-env +nodemon [path to fpv root]/server/index.js ./.fpv-env +---- + +You should see the FPV server application start up on the +console. + +Now open a browser and navigate to `http://localhost:3000`. +You should see a Topology menu at the top of the window +and a rendering of the Command topology below. +Select Math from the topology menu. +You should see a rendering of the Math topology. +It should look similar to <>. + +You can use the menu to view other topology graphs. +When you are done, close the browser window and +type control-C in the console to shut down the FPV server. + +=== Reference Implementation + +A reference implementation for this section is available at +`docs/Tutorials/MathComponent/Top`. +To build this implementation, copy the files +`instances.fpp` and `topology.fpp` from +that directory to `Ref/Top`. + +== Running the Ref Deployment + +Now we will use the F Prime Ground Data System (GDS) to run the Ref deployment. +Go to the `Ref` directory and run `fprime-gds`. +You should see some activity on the console. +The system is starting the Ref deployment executable, starting the GDS, +and connecting them over the local network on your machine. +After several seconds, a browser window should appear. + +=== Sending a Command + +At the top of the window are several buttons, each of which corresponds to +a GDS view. +Select the Commanding button (this is the view that is selected +when you first start the GDS). +In the Mnemonic menu, start typing `mathSender.DO_MATH` in the text box. +As you type, the GDS will filter the menu selections. +When only one choice remains, stop typing and press return. +You should see three boxes appear: + +. A text box for entering `val1`. +. A menu for entering `op`. +. A text box for entering `val2`. + +Fill in the arguments corresponding to the operation `1 + 2`. +You can use the tab key to move between the boxes. +When you have done this, click the Send Command button. +You should see a table entry at the bottom of the window +indicating that the command was sent. + +=== Checking Events + +Now click on the Events button at the top of the window. +The view changes to the Events tab. +You should see events indicating that the command you sent was +dispatched, received, and completed. +You should also see events indicating that `mathReceiver` +performed an `ADD` operation and `mathSender` +received a result of 3.0. + +=== Checking Telemetry + +Click on the Channels button at the top of the window. +You should see a table of telemetry channels. +Each row corresponds to the latest value of a telemetry +channel received by the GDS. +You should see the channels corresponding to the input +values, the operation, and the result. + +=== Setting Parameters + +Go back to the Commanding tab. +Select the command `mathReceiver.FACTOR_PRM_SET`. +This is an auto-generated command for setting the +parameter `FACTOR`. +Type the value 2.0 in the `val` box and click Send Command. +Check the events to see that the command was dispatched +and executed. +You should also see the events sent by the code +that you implemented. + +In the Commanding tab, issue the command `1 + 2` again. +Check the Events tab. +Because the factor is now 2.0, you should see a result +value of 6.0. + +=== Saving Parameters + +When you set a parameter by command, the new parameter +value resides in the component that receives the command. +At this point, if you stop and restart FSW, the parameter +will return to its original value (the value before you +sent the command). + +At some point you may wish to update parameters more permanently. +You can do this by saving them to non-volatile storage. +For the Ref application, "non-volatile storage" means the +file system on your machine. + +To save the parameter `mathReceiver.FACTOR` to non-volatile storage, +do the following: + +. Send the command `mathReceiver.FACTOR_PRM_SAVE`. +This command saves the parameter value to the *parameter database*, +which is a standard F Prime component for storing system parameters. + +. Send the command `prmDb.PRM_SAVE_FILE`. +This command saves the parameter values in the parameter database +to non-volatile storage. + +Note that saving parameters is a two-step process. +The first step copies a single parameter from a component +to the database. +The second step saves all parameters in the database +to the disk. +If you do only the first step, the parameter will not be +saved to the disk. + +=== GDS Logs + +As it runs, the GDS writes a log into a subdirectory of `Ref/logs`. +The subdirectory is stamped with the current date. +Go into the directory for the run you just performed. +(If the GDS is still running, you will have to do this in a +different shell.) +You should see the following logs, among others: + +* `Ref.log`: FSW console output. +* `command.log`: Commands sent. +* `event.log`: Event reports received. +* `channel.log`: Telemetry points received. + +You can also view these logs via the GDS browser interface. +Click the Logs tab to go the Logs view. +Select the log you wish to inspect from the drop-down menu. +By default, there is no log selected. diff --git a/docs/Tutorials/MathComponent/adoc/refresh b/docs/Tutorials/MathComponent/adoc/refresh new file mode 100755 index 0000000000..c7a8353f93 --- /dev/null +++ b/docs/Tutorials/MathComponent/adoc/refresh @@ -0,0 +1,23 @@ +#!/bin/sh -e + +files=`awk ' +/^include::/ { + file = $0 + sub(/^include::/, "", file) + sub(/\[\]/, "", file) + print file +}' Tutorial.adoc` +redo-ifchange $files + +awk ' +/^include::/ { + file = $0 + sub(/^include::/, "", file) + sub(/\[\]/, "", file) + command = "cat " file + print "" | command + close(command) + next +} + +{ print }' Tutorial.adoc > ../Tutorial.adoc diff --git a/docs/Tutorials/MathComponent/img/App1.jpg b/docs/Tutorials/MathComponent/img/App1.jpg deleted file mode 100644 index 0075170ae1..0000000000 Binary files a/docs/Tutorials/MathComponent/img/App1.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/App2.jpg b/docs/Tutorials/MathComponent/img/App2.jpg deleted file mode 100644 index 78ffdfe719..0000000000 Binary files a/docs/Tutorials/MathComponent/img/App2.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Comp.jpg b/docs/Tutorials/MathComponent/img/Comp.jpg deleted file mode 100644 index 659b115357..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Comp.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/CompDiag.pptx b/docs/Tutorials/MathComponent/img/CompDiag.pptx deleted file mode 100644 index 86f9051351..0000000000 Binary files a/docs/Tutorials/MathComponent/img/CompDiag.pptx and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd1.jpg b/docs/Tutorials/MathComponent/img/Gnd1.jpg deleted file mode 100644 index e3c6762f67..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd1.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd10.jpg b/docs/Tutorials/MathComponent/img/Gnd10.jpg deleted file mode 100644 index 94d06f685c..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd10.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd11.jpg b/docs/Tutorials/MathComponent/img/Gnd11.jpg deleted file mode 100644 index b0539bfc5f..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd11.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd12.jpg b/docs/Tutorials/MathComponent/img/Gnd12.jpg deleted file mode 100644 index 446cb043c3..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd12.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd13.jpg b/docs/Tutorials/MathComponent/img/Gnd13.jpg deleted file mode 100644 index 2bc52c523e..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd13.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd14.jpg b/docs/Tutorials/MathComponent/img/Gnd14.jpg deleted file mode 100644 index 65a76fb9c8..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd14.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd15.jpg b/docs/Tutorials/MathComponent/img/Gnd15.jpg deleted file mode 100644 index ed7ff8e392..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd15.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd16.jpg b/docs/Tutorials/MathComponent/img/Gnd16.jpg deleted file mode 100644 index 771097f681..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd16.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd17.jpg b/docs/Tutorials/MathComponent/img/Gnd17.jpg deleted file mode 100644 index 65cef6efd8..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd17.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd18.jpg b/docs/Tutorials/MathComponent/img/Gnd18.jpg deleted file mode 100644 index ebf44548ff..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd18.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd19.jpg b/docs/Tutorials/MathComponent/img/Gnd19.jpg deleted file mode 100644 index a42395fe2a..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd19.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd2.jpg b/docs/Tutorials/MathComponent/img/Gnd2.jpg deleted file mode 100644 index b2012a8991..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd2.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd20.jpg b/docs/Tutorials/MathComponent/img/Gnd20.jpg deleted file mode 100644 index 3bab0f4119..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd20.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd21.jpg b/docs/Tutorials/MathComponent/img/Gnd21.jpg deleted file mode 100644 index 4c5123972c..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd21.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd3.jpg b/docs/Tutorials/MathComponent/img/Gnd3.jpg deleted file mode 100644 index 5e3786659f..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd3.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd30.jpg b/docs/Tutorials/MathComponent/img/Gnd30.jpg deleted file mode 100644 index 83c2f8d462..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd30.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd31.jpg b/docs/Tutorials/MathComponent/img/Gnd31.jpg deleted file mode 100644 index ce3a9de845..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd31.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd32.jpg b/docs/Tutorials/MathComponent/img/Gnd32.jpg deleted file mode 100644 index 07171935dc..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd32.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd4.jpg b/docs/Tutorials/MathComponent/img/Gnd4.jpg deleted file mode 100644 index 9a6181575a..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd4.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd5.jpg b/docs/Tutorials/MathComponent/img/Gnd5.jpg deleted file mode 100644 index bb822627b8..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd5.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd6.jpg b/docs/Tutorials/MathComponent/img/Gnd6.jpg deleted file mode 100644 index 6b69ba6518..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd6.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd7.jpg b/docs/Tutorials/MathComponent/img/Gnd7.jpg deleted file mode 100644 index b61f4315b6..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd7.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd8.jpg b/docs/Tutorials/MathComponent/img/Gnd8.jpg deleted file mode 100644 index 95f6ede5d3..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd8.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/img/Gnd9.jpg b/docs/Tutorials/MathComponent/img/Gnd9.jpg deleted file mode 100644 index 8c52bc532c..0000000000 Binary files a/docs/Tutorials/MathComponent/img/Gnd9.jpg and /dev/null differ diff --git a/docs/Tutorials/MathComponent/json/refresh b/docs/Tutorials/MathComponent/json/refresh new file mode 100755 index 0000000000..c39ab771af --- /dev/null +++ b/docs/Tutorials/MathComponent/json/refresh @@ -0,0 +1,3 @@ +#!/bin/sh -e + +fpl-layout < top.txt > top.json diff --git a/docs/Tutorials/MathComponent/json/top.json b/docs/Tutorials/MathComponent/json/top.json new file mode 100644 index 0000000000..dccf0d9750 --- /dev/null +++ b/docs/Tutorials/MathComponent/json/top.json @@ -0,0 +1,76 @@ +{ + "columns" : [ + [ + { + "instanceName" : "mathSender", + "inputPorts" : [ + { + "name" : "mathResultIn", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [ + { + "name" : "mathOpOut", + "portNumbers" : [ + 0 + ] + } + ] + } + ], + [ + { + "instanceName" : "mathReceiver", + "inputPorts" : [ + { + "name" : "mathOpIn", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [ + { + "name" : "mathResultOut", + "portNumbers" : [ + 0 + ] + } + ] + } + ] + ], + "connections" : [ + [ + [ + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0 + ] + ], + [ + [ + 1, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0 + ] + ] + ] +} diff --git a/docs/Tutorials/MathComponent/json/top.txt b/docs/Tutorials/MathComponent/json/top.txt new file mode 100644 index 0000000000..69d31efece --- /dev/null +++ b/docs/Tutorials/MathComponent/json/top.txt @@ -0,0 +1,13 @@ +mathSender +mathOpOut +0 +mathReceiver +mathOpIn +0 + +mathReceiver +mathResultOut +0 +mathSender +mathResultIn +0 diff --git a/docs/Tutorials/MathComponent/png/top.png b/docs/Tutorials/MathComponent/png/top.png new file mode 100644 index 0000000000..3eaca2d3be Binary files /dev/null and b/docs/Tutorials/MathComponent/png/top.png differ diff --git a/docs/Tutorials/MathComponent/refresh b/docs/Tutorials/MathComponent/refresh new file mode 100755 index 0000000000..34803343b8 --- /dev/null +++ b/docs/Tutorials/MathComponent/refresh @@ -0,0 +1,5 @@ +#!/bin/sh -e + +(cd adoc; ./refresh) +(cd json; ./refresh) +asciidoctor -vn -o Tutorial.html Tutorial.adoc diff --git a/docs/Tutorials/MathComponent/scripts/math_script.txt b/docs/Tutorials/MathComponent/scripts/math_script.txt deleted file mode 100644 index ab32cbecb0..0000000000 --- a/docs/Tutorials/MathComponent/scripts/math_script.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Run this script to replicate the MathComponent tutorial - -MS_DO_MATH, 2.0, 3.0, ADD # Add two numbers together -MR_SET_FACTOR1, 2.0 # Set factor1 to 2.0 -MS_DO_MATH, 2.0, 3.0, ADD # Re-run math operation with new factor1 value -WAIT, 2 # Wait two seconds -FACTOR2_PRM_SET, 10.0 # Set factor2 to 10.0 -MS_DO_MATH, 2.0, 3.0, ADD # Re-run math operation with new factor2 value -FACTOR2_PRM_SAVE # Save parameter -PRM_SAVE_FILE # Save parameters to disk diff --git a/docs/Tutorials/MathComponent/sequences/math_sequence.seq b/docs/Tutorials/MathComponent/sequences/math_sequence.seq deleted file mode 100644 index 1df43f876b..0000000000 --- a/docs/Tutorials/MathComponent/sequences/math_sequence.seq +++ /dev/null @@ -1,9 +0,0 @@ -; Run this sequence to replicate the MathComponent tutorial - -R00:00:00 MS_DO_MATH 2.0, 3.0, ADD ; Add two numbers together -R00:00:00 MR_SET_FACTOR1 2.0 ; Set factor1 to 2.0 -R00:00:00 MS_DO_MATH 2.0, 3.0, ADD ; Re-run math operation with new factor1 value -R00:00:02 FACTOR2_PRM_SET 10.0 ; Set factor2 to 10.0 -R00:00:00 MS_DO_MATH 2.0, 3.0, ADD ; Re-run math operation with new factor2 value -R00:00:00 FACTOR2_PRM_SAVE ; Save parameter -R00:00:00 PRM_SAVE_FILE ; Save parameters to disk