diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 951b41dfaa..f6a309745b 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -1,4 +1,5 @@ Aadil +aarch abcd ABCDE ABCDEF @@ -102,6 +103,7 @@ bfree bibtex Bies bindir +binrel Bitfields bitmaps bitset @@ -204,12 +206,12 @@ coldarm colno COLORSTYLE colorwheel +COMBUFFER comlogger COMMANDDISPATCHERIMPL COMMANDDISPATCHERIMPLCFG commandline commasepitem -COMBUFFER commonpath COMPACKET COMPONENTTESTERIMPL @@ -238,9 +240,9 @@ Cpkt cplusplus CPOL cpos +cppcheck cppcheckxml cpplint -cppcheck cppreference cprogramming cpuset @@ -273,13 +275,13 @@ csum ctest ctime CTORS +ctu CTX ctype culates curdir curmsgs cuz -ctu cwd CYCLEOUT cygwin @@ -371,6 +373,7 @@ Doxywizard dpi DPRIVATE DPROTECTED +DRAINBUFFERS drv drvipsocket drvsocketreadtask @@ -391,6 +394,8 @@ dumpobj DVI DWN dylib +eabi +eabihf EACCES EAGAIN eay @@ -448,11 +453,15 @@ ERRORCHECK errorlevel errornum ert +ethanchee etime ETIMEDOUT eturn +EVENTARRAY +EVENTBOOL EVENTID eventname +EVENTPRIMITIVE evr evt EXAMPLECOMPONENTIMPL @@ -517,7 +526,7 @@ FPCONFIG fpconfighpp FPGA fpi -fpl +FPL fpp fppi FPport @@ -597,6 +606,7 @@ Gnc Gnd gnd GNUC +gnueabi gnueabihf google googletest @@ -728,7 +738,6 @@ ISREG iss isspace isupper -ITAR itimerspec itle itr @@ -762,6 +771,7 @@ kislyuk kitware Kooi kthxbye +Kubernetes Lammert lammertbies LASTLOG @@ -894,8 +904,8 @@ mul multiarch multioptionals multirequired -multline multitool +multline munmap mutex mutexattr @@ -910,6 +920,7 @@ namespaced nano nanosleep nargs +nasafprime nathan nbits ncsl @@ -928,6 +939,7 @@ ninjaaron NMEA nmsgs noargport +NOBLOCK NOCOLOR NOCTTY nodemon @@ -1017,11 +1029,19 @@ packetizer Packetizing Paetz Pandian +PARAMARRAY +PARAMBOOL PARAMDOC +PARAMENUM params +PARAMSTRING +PARAMSTRUCT +PARAMU PARENB PARODD parseable +PASSIVERATEGROUP +PASSIVERATEGROUPIMPLTESTER pathlib pathmaker pbuild @@ -1137,6 +1157,7 @@ RAbrack radd RAII Ramanan +rancherdesktop randtbl rapidscat raspberrypi @@ -1289,8 +1310,8 @@ Sinha SIZ sizeof sloc -Smath smallsat +Smath SNDTIMEO snprintf sockaddr @@ -1322,8 +1343,8 @@ srand srandom srange src -srcs SRCS +srcs sre sscanf ssh @@ -1557,6 +1578,7 @@ UNEXP unexport unicode UNINIT +UNINSTANTIATED uniq unistd Unithem @@ -1612,7 +1634,7 @@ vwong vxworks VXWORKSLOGASSERT WAITALL -Watney +watney Wconversion Wdog weakref @@ -1639,6 +1661,7 @@ WRONLY wrs Wshadow Wsign +wsl WSL Wundef www @@ -1646,8 +1669,8 @@ wxgui Xabcdefx xapian xargs -Xcode XBee +Xcode xcode xdf xdffe @@ -1667,3 +1690,4 @@ XYZZY yacc yacgen yyyymmdd +zmq diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt index edd3969da1..e65d460bfc 100644 --- a/.github/actions/spelling/patterns.txt +++ b/.github/actions/spelling/patterns.txt @@ -2,7 +2,10 @@ # hit-count: 106 file-count: 28 # Compiler flags -(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) +(?:^|[\t ,"'`=(])-(?:[DLP](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})) + +# http|ftp|file URLs +#(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|] # hit-count: 48 file-count: 18 # GitHub SHAs (markdown) @@ -123,3 +126,6 @@ GithubProjectProperty # ignore long runs of a single character: \b([A-Za-z])\g{-1}{3,}\b + +# ignore docker platform paths +--platform=(linux|darwin)/(amd64|arm|arm32v5|arm32v6|arm32v7|arm64v8|i386|ppc64le|s390x|x86_64) diff --git a/.github/workflows/build-led-blinker.yml b/.github/workflows/build-led-blinker.yml new file mode 100644 index 0000000000..7d08a05723 --- /dev/null +++ b/.github/workflows/build-led-blinker.yml @@ -0,0 +1,21 @@ +# Builds and runs UTs on https://github.com/fprime-community/fprime-workshop-led-blinker + +name: "LedBlinker Tests" + +on: + push: + branches: [ master, devel ] + pull_request: + branches: [ master, devel ] + paths-ignore: + - 'docs/**' + - '**.md' + +jobs: + run: + name: "" + uses: ./.github/workflows/reusable-builder.yml + with: + target_repository: fprime-community/fprime-workshop-led-blinker + build_location: LedBlinker + run_unit_tests: true diff --git a/.github/workflows/build-test-macos.yml b/.github/workflows/build-test-macos.yml index 2de9038f70..44edc18ac3 100644 --- a/.github/workflows/build-test-macos.yml +++ b/.github/workflows/build-test-macos.yml @@ -8,7 +8,10 @@ on: push: branches: [ master, devel ] pull_request: - branches: [ master, devel, release/v3.0.0 ] + branches: [ master, devel, release/v3.0.0 ] + paths-ignore: + - 'docs/**' + - '**.md' # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: diff --git a/.github/workflows/build-test-rpi.yml b/.github/workflows/build-test-rpi.yml index dd9d1bba82..4083f64856 100644 --- a/.github/workflows/build-test-rpi.yml +++ b/.github/workflows/build-test-rpi.yml @@ -9,9 +9,12 @@ on: branches: [ master, devel ] pull_request: branches: [ master, devel, release/v3.0.0 ] + paths-ignore: + - 'docs/**' + - '**.md' env: RPI_TOOLCHAIN_DIR: /tmp/rpi-toolchain - DICTIONARY_PATH: build-artifacts/raspberrypi/dict/RPITopologyAppDictionary.xml + DICTIONARY_PATH: build-artifacts/raspberrypi/RPI/dict/RPITopologyAppDictionary.xml # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: RPI: @@ -53,7 +56,7 @@ jobs: with: name: rpi-build - name: RPI Integration Tests - run: chmod +x RPI/build-artifacts/raspberrypi/bin/RPI; /bin/bash ci/tests/RPI-Ints.bash + run: chmod +x RPI/build-artifacts/raspberrypi/RPI/bin/RPI; /bin/bash ci/tests/RPI-Ints.bash # Archive the outputs - name: 'Archive Logs' uses: actions/upload-artifact@v3 diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index ce0a7f1554..56110a35e6 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -9,6 +9,9 @@ on: branches: [ master, devel ] pull_request: branches: [ master, devel, release/v3.0.0 ] + paths-ignore: + - 'docs/**' + - '**.md' # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: diff --git a/.github/workflows/codeql-jpl-standard.yml b/.github/workflows/codeql-jpl-standard.yml index 150ebe1594..cc894f8500 100644 --- a/.github/workflows/codeql-jpl-standard.yml +++ b/.github/workflows/codeql-jpl-standard.yml @@ -9,6 +9,9 @@ on: pull_request: # The branches below must be a subset of the branches above branches: [ master, devel ] + paths-ignore: + - 'docs/**' + - '**.md' jobs: analyze: diff --git a/.github/workflows/codeql-security-scan.yml b/.github/workflows/codeql-security-scan.yml index 41509f86ae..af72c623d3 100644 --- a/.github/workflows/codeql-security-scan.yml +++ b/.github/workflows/codeql-security-scan.yml @@ -9,6 +9,9 @@ on: pull_request: # The branches below must be a subset of the branches above branches: [ master, devel ] + paths-ignore: + - 'docs/**' + - '**.md' jobs: analyze: diff --git a/.github/workflows/cppcheck-scan.yml b/.github/workflows/cppcheck-scan.yml index 09da2b5b33..83a7430cd7 100644 --- a/.github/workflows/cppcheck-scan.yml +++ b/.github/workflows/cppcheck-scan.yml @@ -7,6 +7,9 @@ on: pull_request: # The branches below must be a subset of the branches above branches: [ master, devel ] + paths-ignore: + - 'docs/**' + - '**.md' jobs: diff --git a/.github/workflows/cpplint-scan.yml b/.github/workflows/cpplint-scan.yml index 2a90fb54c8..ec913ceee2 100644 --- a/.github/workflows/cpplint-scan.yml +++ b/.github/workflows/cpplint-scan.yml @@ -6,6 +6,9 @@ on: pull_request: # The branches below must be a subset of the branches above branches: [master, devel] + paths-ignore: + - 'docs/**' + - '**.md' jobs: cpplint: diff --git a/.github/workflows/python-format.yml b/.github/workflows/python-format.yml index 742fb3930f..ed5c6cddef 100644 --- a/.github/workflows/python-format.yml +++ b/.github/workflows/python-format.yml @@ -1,6 +1,12 @@ name: Format Python -on: [push, pull_request] +on: + push: + branches: [master, devel] + pull_request: + # The branches below must be a subset of the branches above + branches: [master, devel] + jobs: format: name: Format diff --git a/.github/workflows/reusable-builder.yml b/.github/workflows/reusable-builder.yml new file mode 100644 index 0000000000..7acbe6febf --- /dev/null +++ b/.github/workflows/reusable-builder.yml @@ -0,0 +1,102 @@ +# This workflow is intended for reuse by other workflows and will not run directly (no triggers). +# The behavior is to build an external F´ project (e.g. fprime-community/system-reference) using +# the current F´ version. +name: "F´ Project Builder - Reusable Workflow" + +on: + workflow_call: + inputs: + build_location: + description: "Path to F´ module to build. E.g. MyDeployment/" + required: true + type: string + target_repository: + description: "Additional external repository to checkout (/)" + required: true + type: string + run_unit_tests: + description: "Run an additional job in parallel to run unit tests." + required: false + type: boolean + default: true + fprime_location: + description: "Relative path from the external project root to its F´ submodule" + required: false + type: string + default: "./fprime" + runs_on: + description: "Platform to run on. Defaults to ubuntu-latest" + required: false + type: string + default: "ubuntu-latest" + target_platform: + description: "Target platform to pass to fprime-util" + required: false + type: string + default: "" + +jobs: + build: + runs-on: ${{ inputs.runs_on }} + name: "Build" + steps: + - name: "Checkout target repository" + uses: actions/checkout@v3 + with: + submodules: recursive + repository: ${{ inputs.target_repository }} + - name: "Overlay current F´ revision" + uses: actions/checkout@v3 + with: + submodules: recursive + path: ${{ inputs.fprime_location }} + - name: "Install requirements.txt" + run: | + pip3 install -r ${{ inputs.fprime_location }}/requirements.txt + shell: bash + - name: "Generate build cache" + working-directory: ${{ inputs.build_location }} + run: | + fprime-util generate ${{ runner.debug == '1' && '--verbose' || '' }} ${{ inputs.target_platform }} + shell: bash + - name: "Build" + working-directory: ${{ inputs.build_location }} + run: | + fprime-util build ${{ runner.debug == '1' && '--verbose' || '' }} ${{ inputs.target_platform }} + shell: bash + + runUT: + if: ${{ inputs.run_unit_tests }} + runs-on: ${{ inputs.runs_on }} + name: "Unit Tests" + steps: + - name: "Checkout target repository" + uses: actions/checkout@v3 + with: + submodules: recursive + repository: ${{ inputs.target_repository }} + - name: "Overlay current F´ revision" + uses: actions/checkout@v3 + with: + submodules: recursive + path: ${{ inputs.fprime_location }} + - name: "Install requirements.txt" + run: | + pip3 install -r ${{ inputs.fprime_location }}/requirements.txt + shell: bash + - name: "Generate UT build cache" + working-directory: ${{ inputs.build_location }} + run: | + fprime-util generate --ut ${{ runner.debug == '1' && '--verbose' || '' }} ${{ inputs.target_platform }} + shell: bash + - name: "Build UTs" + working-directory: ${{ inputs.build_location }} + run: | + fprime-util build --ut ${{ runner.debug == '1' && '--verbose' || '' }} ${{ inputs.target_platform }} + shell: bash + - name: "Run Unit Tests" + working-directory: ${{ inputs.build_location }} + run: | + fprime-util check ${{ runner.debug == '1' && '--verbose' || '' }} ${{ inputs.target_platform }} + shell: bash + diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl index 9c6ffba64f..4a9d7649b7 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl @@ -13,7 +13,14 @@ \#include \#include \#include + +#if $kind == "passive": +\#include +#else: \#include +#end if + + #if $has_guarded_ports or $has_parameters \#include #end if diff --git a/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py b/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py index dfab2fd292..7df7523598 100644 --- a/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py +++ b/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py @@ -68,6 +68,8 @@ def check_for_serial_xml(self): member_elem.attrib["description"] = member_comment if member_default is not None: member_elem.attrib["default"] = member_default + if member_array_size is not None: + member_elem.attrib["size"] = member_array_size if isinstance(member_type, tuple): type_name = "{}::{}::{}".format( serializable_type, diff --git a/Autocoders/Python/src/fprime_ac/utils/version.py b/Autocoders/Python/src/fprime_ac/utils/version.py index b8e8ed567e..456563ecbe 100644 --- a/Autocoders/Python/src/fprime_ac/utils/version.py +++ b/Autocoders/Python/src/fprime_ac/utils/version.py @@ -2,7 +2,7 @@ import os import subprocess -FALLBACK_VERSION = "v3.2.0" # Keep up-to-date on release tag +FALLBACK_VERSION = "v3.3.0" # Keep up-to-date on release tag def get_version_str(working_dir, fallback=FALLBACK_VERSION): diff --git a/Drv/CMakeLists.txt b/Drv/CMakeLists.txt index a9e30b762e..287fd1f2e1 100644 --- a/Drv/CMakeLists.txt +++ b/Drv/CMakeLists.txt @@ -13,6 +13,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxGpioDriver/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxUartDriver/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxSpiDriver/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriver/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/StreamCrossover/") # IP Socket is only supported for Linux, Darwin, VxWorks if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "VxWorks") diff --git a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp index 8f1dbab133..d9f46b99d0 100644 --- a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp +++ b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp @@ -397,10 +397,10 @@ namespace Drv { } Os::Task::TaskStatus LinuxGpioDriverComponentImpl :: - startIntTask(NATIVE_UINT_TYPE priority, NATIVE_UINT_TYPE cpuAffinity) { + startIntTask(NATIVE_UINT_TYPE priority, NATIVE_UINT_TYPE stackSize, NATIVE_UINT_TYPE cpuAffinity) { Os::TaskString name; name.format("GPINT_%s",this->getObjName()); // The task name can only be 16 chars including null - Os::Task::TaskStatus stat = this->m_intTask.start(name, LinuxGpioDriverComponentImpl::intTaskEntry, this, priority, Os::Task::TASK_DEFAULT, cpuAffinity); + Os::Task::TaskStatus stat = this->m_intTask.start(name, LinuxGpioDriverComponentImpl::intTaskEntry, this, priority, stackSize, cpuAffinity); if (stat != Os::Task::TASK_OK) { DEBUG_PRINT("Task start error: %d\n",stat); diff --git a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp index 559dfccf2b..a0c7ecad7f 100644 --- a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp +++ b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp @@ -45,7 +45,9 @@ namespace Drv { ~LinuxGpioDriverComponentImpl(); //! Start interrupt task - Os::Task::TaskStatus startIntTask(NATIVE_UINT_TYPE priority = Os::Task::TASK_DEFAULT, NATIVE_UINT_TYPE cpuAffinity = Os::Task::TASK_DEFAULT); + Os::Task::TaskStatus startIntTask(NATIVE_UINT_TYPE priority = Os::Task::TASK_DEFAULT, + NATIVE_UINT_TYPE stackSize = Os::Task::TASK_DEFAULT, + NATIVE_UINT_TYPE cpuAffinity = Os::Task::TASK_DEFAULT); //! configure GPIO enum GpioDirection { diff --git a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp index 41663e8d67..31e9d7efe8 100644 --- a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp +++ b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp @@ -44,7 +44,7 @@ namespace Drv { } Os::Task::TaskStatus LinuxGpioDriverComponentImpl :: - startIntTask(NATIVE_UINT_TYPE priority, NATIVE_UINT_TYPE cpuAffinity) { + startIntTask(NATIVE_UINT_TYPE priority, NATIVE_UINT_TYPE stackSize, NATIVE_UINT_TYPE cpuAffinity) { return Os::Task::TASK_OK; } diff --git a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp index 180e0103a4..c07fc0e465 100644 --- a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp +++ b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp @@ -70,7 +70,8 @@ namespace Drv { bool LinuxSpiDriverComponentImpl::open(NATIVE_INT_TYPE device, NATIVE_INT_TYPE select, - SpiFrequency clock) { + SpiFrequency clock, + SpiMode spiMode) { this->m_device = device; this->m_select = select; @@ -97,9 +98,29 @@ namespace Drv { // Configure: /* - * SPI Mode 0 + * SPI Mode 0, 1, 2, 3 */ - U8 mode = SPI_MODE_0; // Mode 0 (CPOL = 0, CPHA = 0) + + U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1) + switch(spiMode) { + case SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW: + mode = SPI_MODE_0; + break; + case SpiMode::SPI_MODE_CPOL_LOW_CPHA_HIGH: + mode = SPI_MODE_1; + break; + case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_LOW: + mode = SPI_MODE_2; + break; + case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_HIGH: + mode = SPI_MODE_3; + break; + default: + //Assert if the device SPI Mode is not in the correct range + FW_ASSERT(0, spiMode); + break; + } + ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (ret == -1) { DEBUG_PRINT("ioctl SPI_IOC_WR_MODE fd %d failed. %d\n",fd,errno); diff --git a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp index e5c1eabf87..51e2a3b163 100644 --- a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp +++ b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp @@ -33,6 +33,25 @@ namespace Drv { SPI_FREQUENCY_20MHZ = 20000000UL, }; + /** + * SPI Mode Select + * + * Defines the SPI Clock Polarity and Phase for each SPI Transaction. + * + * SPI Clock Polarity(CPOL): Defines clock polarity as idle low (CPOL = 0) or idle high(CPOL = 1) + * SPI Clock Phase(CPHA): Defines if data is shifted out on the rising clock edge and sampled + * on the falling clock edge(CPHA = 0) or if data is shifted out on the + * falling clock edge and sampled on the rising clock edge(CPHA=1) + * + */ + enum SpiMode + { + SPI_MODE_CPOL_LOW_CPHA_LOW, ///< (CPOL = 0, CPHA = 0) + SPI_MODE_CPOL_LOW_CPHA_HIGH,///< (CPOL = 0, CPHA = 1) + SPI_MODE_CPOL_HIGH_CPHA_LOW,///< (CPOL = 1, CPHA = 0) + SPI_MODE_CPOL_HIGH_CPHA_HIGH,///< (CPOL = 1, CPHA = 1) + }; + class LinuxSpiDriverComponentImpl: public LinuxSpiDriverComponentBase { public: @@ -59,7 +78,8 @@ namespace Drv { //! Open device bool open(NATIVE_INT_TYPE device, NATIVE_INT_TYPE select, - SpiFrequency clock); + SpiFrequency clock, + SpiMode spiMode = SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW); PRIVATE: diff --git a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp index 3b3ebe0aa6..b7620dbbf5 100644 --- a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp +++ b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp @@ -17,7 +17,8 @@ namespace Drv { bool LinuxSpiDriverComponentImpl::open(NATIVE_INT_TYPE device, NATIVE_INT_TYPE select, - SpiFrequency clock) { + SpiFrequency clock, + SpiMode spiMode) { //TODO: fill this function out return false; } diff --git a/Drv/StreamCrossover/CMakeLists.txt b/Drv/StreamCrossover/CMakeLists.txt new file mode 100644 index 0000000000..4a6b0cf367 --- /dev/null +++ b/Drv/StreamCrossover/CMakeLists.txt @@ -0,0 +1,22 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/StreamCrossover.fpp" + "${CMAKE_CURRENT_LIST_DIR}/StreamCrossover.cpp" +) + +register_fprime_module() + +# Register the unit test build +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/StreamCrossover.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" +) +set(UT_AUTO_HELPERS ON) +register_fprime_ut() diff --git a/Drv/StreamCrossover/StreamCrossover.cpp b/Drv/StreamCrossover/StreamCrossover.cpp new file mode 100644 index 0000000000..751f03dafc --- /dev/null +++ b/Drv/StreamCrossover/StreamCrossover.cpp @@ -0,0 +1,57 @@ +// ====================================================================== +// \title StreamCrossover.cpp +// \author ethanchee +// \brief cpp file for StreamCrossover component implementation class +// ====================================================================== + + +#include +#include + +namespace Drv { + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + StreamCrossover :: + StreamCrossover( + const char *const compName + ) : StreamCrossoverComponentBase(compName) + { + + } + + StreamCrossover :: + ~StreamCrossover() + { + + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + void StreamCrossover :: + streamIn_handler( + const NATIVE_INT_TYPE portNum, + Fw::Buffer &recvBuffer, + const Drv::RecvStatus &recvStatus + ) + { + if(recvStatus == Drv::RecvStatus::RECV_ERROR || recvBuffer.getSize() == 0) + { + this->log_WARNING_HI_StreamOutError(Drv::SendStatus::SEND_ERROR); + this->errorDeallocate_out(0, recvBuffer); + return; + } + + Drv::SendStatus sendStatus = this->streamOut_out(0, recvBuffer); + + if(sendStatus != Drv::SendStatus::SEND_OK) + { + this->log_WARNING_HI_StreamOutError(sendStatus); + } + } + +} // end namespace Drv diff --git a/Drv/StreamCrossover/StreamCrossover.fpp b/Drv/StreamCrossover/StreamCrossover.fpp new file mode 100644 index 0000000000..286aaf3d09 --- /dev/null +++ b/Drv/StreamCrossover/StreamCrossover.fpp @@ -0,0 +1,28 @@ +module Drv { + + passive component StreamCrossover { + + output port streamOut: Drv.ByteStreamSend + + sync input port streamIn: Drv.ByteStreamRecv + + @ Indicates buffer failed to send to streamOut. + event StreamOutError(sendStatus: Drv.SendStatus) \ + severity warning high \ + format "StreamCrossover StreamOut Error: {}" + + @ Allows for deallocation after bad receive status + output port errorDeallocate: Fw.BufferSend + + @ Port for requesting the current time + time get port timeCaller + + @ Port for sending textual representation of events + text event port logTextOut + + @ Port for sending events to downlink + event port logOut + + } + +} diff --git a/Drv/StreamCrossover/StreamCrossover.hpp b/Drv/StreamCrossover/StreamCrossover.hpp new file mode 100644 index 0000000000..33e1b17211 --- /dev/null +++ b/Drv/StreamCrossover/StreamCrossover.hpp @@ -0,0 +1,53 @@ +// ====================================================================== +// \title StreamCrossover.hpp +// \author ethanchee +// \brief hpp file for StreamCrossover component implementation class +// ====================================================================== + +#ifndef StreamCrossover_HPP +#define StreamCrossover_HPP + +#include "Drv/StreamCrossover/StreamCrossoverComponentAc.hpp" + +namespace Drv { + + class StreamCrossover : + public StreamCrossoverComponentBase + { + + public: + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object StreamCrossover + //! + StreamCrossover( + const char *const compName /*!< The component name*/ + ); + + //! Destroy object StreamCrossover + //! + ~StreamCrossover(); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for streamIn + //! + void streamIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer &recvBuffer, + const Drv::RecvStatus &recvStatus + ); + + + }; + +} // end namespace Drv + +#endif diff --git a/Drv/StreamCrossover/docs/sdd.md b/Drv/StreamCrossover/docs/sdd.md new file mode 100644 index 0000000000..7333740342 --- /dev/null +++ b/Drv/StreamCrossover/docs/sdd.md @@ -0,0 +1,30 @@ +\page DrvStreamCrossover Drv::StreamCrossover Stream Crossover Component +# Drv::StreamCrossover Stream Crossover Component + +The Stream Crossover component allows a connection of byte stream driver model ports of type ByteStreamRecv and +ByteStreamSend. + +## Design + +The Drv::StreamCrossover utilizes the byte stream driver model to handle the incoming stream of bytes. Upon calling +the "streamIn" port, the `Fw::Buffer` containing the data will be forwarded to the "streamOut" port. This enables a +connection from a ByteStreamRecv port to a ByteStreamSend port. + +## Port Descriptions +| Name | Description | +|---|---| +| streamOut | A ByteStreamSend port for outgoing data stored in `Fw::Buffer` | +| streamIn | A ByteStreamRecv port for incoming data stored in `Fw::Buffer` | +| errorDeallocate | Deallocate a `Fw::Buffer` on error | + +## Requirements +Add requirements in the chart below +| Name | Description | Validation | +|---|---|---| +| STREAM-CROSSOVER-COMP-001 | The stream crossover component shall provide the capability to forward bytes | Unit Test | + +## Change Log +| Date | Description | +|---|---| +| 2023-06-05 | Initial Draft | +| 2023-06-09 | Implement Error Handling | diff --git a/Drv/StreamCrossover/test/ut/TestMain.cpp b/Drv/StreamCrossover/test/ut/TestMain.cpp new file mode 100644 index 0000000000..2b5a81a59b --- /dev/null +++ b/Drv/StreamCrossover/test/ut/TestMain.cpp @@ -0,0 +1,20 @@ +// ---------------------------------------------------------------------- +// TestMain.cpp +// ---------------------------------------------------------------------- + +#include "Tester.hpp" + +TEST(Nominal, TestBuffer) { + Drv::Tester tester; + tester.sendTestBuffer(); +} + +TEST(Nominal, TestFail) { + Drv::Tester tester; + tester.testFail(); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Drv/StreamCrossover/test/ut/Tester.cpp b/Drv/StreamCrossover/test/ut/Tester.cpp new file mode 100644 index 0000000000..63844e4637 --- /dev/null +++ b/Drv/StreamCrossover/test/ut/Tester.cpp @@ -0,0 +1,101 @@ +// ====================================================================== +// \title StreamCrossover.hpp +// \author ethanchee +// \brief cpp file for StreamCrossover test harness implementation class +// ====================================================================== + +#include "Tester.hpp" + +namespace Drv { + + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + Tester :: + Tester() : + StreamCrossoverGTestBase("Tester", Tester::MAX_HISTORY_SIZE), + component("StreamCrossover") + { + this->initComponents(); + this->connectPorts(); + } + + Tester :: + ~Tester() + { + + } + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + void Tester :: + sendTestBuffer() + { + U8 testStr[6] = "test\n"; + Fw::Buffer sendBuffer(testStr, sizeof(testStr)); + this->invoke_to_streamIn(0, sendBuffer, Drv::RecvStatus::RECV_OK); + + // Ensure only one buffer was sent to streamOut + ASSERT_from_streamOut_SIZE(1); + + // Ensure the sendBuffer was sent + ASSERT_from_streamOut(0, sendBuffer); + } + + void Tester :: + testFail() + { + U8 testStr[6] = "test\n"; + Fw::Buffer sendBuffer(testStr, sizeof(testStr)); + this->invoke_to_streamIn(0, sendBuffer, Drv::RecvStatus::RECV_ERROR); + + // Ensure only one buffer was sent to errorDeallocate port on RECV_ERROR + ASSERT_from_errorDeallocate_SIZE(1); + + // Ensure the sendBuffer was sent + ASSERT_from_errorDeallocate(0, sendBuffer); + + // Ensure the error event was sent + ASSERT_EVENTS_StreamOutError_SIZE(1); + + // Ensure the error is SEND_ERROR + ASSERT_EVENTS_StreamOutError(0, Drv::SendStatus::SEND_ERROR); + } + + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + Drv::SendStatus Tester :: + from_streamOut_handler( + const NATIVE_INT_TYPE portNum, + Fw::Buffer &sendBuffer + ) + { + this->pushFromPortEntry_streamOut(sendBuffer); + + U8 testStr[6] = "test\n"; + Fw::Buffer cmpBuffer(testStr, sizeof(testStr)); + + if(!(cmpBuffer == sendBuffer)) + { + return Drv::SendStatus::SEND_ERROR; + } + + return Drv::SendStatus::SEND_OK; + } + + void Tester :: + from_errorDeallocate_handler( + const NATIVE_INT_TYPE portNum, + Fw::Buffer &fwBuffer + ) + { + this->pushFromPortEntry_errorDeallocate(fwBuffer); + } + + +} // end namespace Drv diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.hpp b/Drv/StreamCrossover/test/ut/Tester.hpp similarity index 59% rename from docs/Tutorials/MathComponent/MathSender/test/ut/Tester.hpp rename to Drv/StreamCrossover/test/ut/Tester.hpp index 93bf2fd724..7ef64849aa 100644 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.hpp +++ b/Drv/StreamCrossover/test/ut/Tester.hpp @@ -1,25 +1,19 @@ // ====================================================================== -// \title MathSender/test/ut/Tester.hpp -// \author tcanham, bocchino -// \brief hpp file for MathSender test harness implementation class -// -// \copyright -// Copyright 2009-2021, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// +// \title StreamCrossover/test/ut/Tester.hpp +// \author ethanchee +// \brief hpp file for StreamCrossover test harness implementation class // ====================================================================== #ifndef TESTER_HPP #define TESTER_HPP #include "GTestBase.hpp" -#include "Ref/MathSender/MathSender.hpp" +#include "Drv/StreamCrossover/StreamCrossover.hpp" -namespace Ref { +namespace Drv { class Tester : - public MathSenderGTestBase + public StreamCrossoverGTestBase { // ---------------------------------------------------------------------- @@ -31,8 +25,6 @@ namespace Ref { static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10; // Instance ID supplied to the component instance under test static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; - // Queue depth supplied to component instance under test - static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; //! Construct object Tester //! @@ -48,20 +40,13 @@ namespace Ref { // Tests // ---------------------------------------------------------------------- - //! Test an ADD command - void testAddCommand(); - - //! Test a SUB command - void testSubCommand(); - - //! Test a MUL command - void testMulCommand(); - - //! Test a DIV command - void testDivCommand(); + //! Send a test buffer to streamOut from streamIn + //! + void sendTestBuffer(); - //! Test receipt of a result - void testResult(); + //! Send a fail RECV_STATUS to test error + //! + void testFail(); private: @@ -69,13 +54,18 @@ namespace Ref { // Handlers for typed from ports // ---------------------------------------------------------------------- - //! Handler for from_mathOut + //! Handler for from_streamOut //! - void from_mathOpOut_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - F32 val1, //!< First operand - const MathOp& op, //!< operation - F32 val2 //!< Second operand + Drv::SendStatus from_streamOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer &sendBuffer + ); + + //! Handler for from_deallocate + //! + void from_errorDeallocate_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer &fwBuffer ); private: @@ -84,12 +74,6 @@ namespace Ref { // Helper methods // ---------------------------------------------------------------------- - //! Pick a random value - static F32 pickF32Value(); - - //! Test a DO_MATH command - void testDoMath(MathOp op); - //! Connect ports //! void connectPorts(); @@ -106,10 +90,10 @@ namespace Ref { //! The component under test //! - MathSender component; + StreamCrossover component; }; -} // end namespace Ref +} // end namespace Drv #endif diff --git a/FppTest/CMakeLists.txt b/FppTest/CMakeLists.txt index 56f0f486fc..efbf5a1f96 100644 --- a/FppTest/CMakeLists.txt +++ b/FppTest/CMakeLists.txt @@ -15,7 +15,7 @@ if (BUILD_TESTING AND NOT __FPRIME_NO_UT_GEN__) add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/enum/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/array/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/struct/") - add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/port/") + add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/component/") endif() set(SOURCE_FILES "source.cpp") @@ -23,7 +23,10 @@ set(MOD_DEPS ${PROJECT_NAME}/enum ${PROJECT_NAME}/array ${PROJECT_NAME}/struct - ${PROJECT_NAME}/port + ${PROJECT_NAME}/component/empty + ${PROJECT_NAME}/component/active + ${PROJECT_NAME}/component/queued + ${PROJECT_NAME}/component/passive ) register_fprime_deployment() diff --git a/FppTest/array/FormatTest.cpp b/FppTest/array/FormatTest.cpp index 59ab523fd5..4cda42e8e9 100644 --- a/FppTest/array/FormatTest.cpp +++ b/FppTest/array/FormatTest.cpp @@ -266,7 +266,7 @@ TEST_F(FormatTest, String) { TEST_F(FormatTest, Char) { U8 testVals[FormatChar::SIZE] = - {FppTest::Utils::getU8(), FppTest::Utils::getU8(), FppTest::Utils::getU8()}; + {FppTest::Utils::getNonzeroU8(), FppTest::Utils::getNonzeroU8(), FppTest::Utils::getNonzeroU8()}; FormatChar a(testVals); buf1 << a; diff --git a/FppTest/array/main.cpp b/FppTest/array/main.cpp index 856fcc1f45..45760e5b38 100644 --- a/FppTest/array/main.cpp +++ b/FppTest/array/main.cpp @@ -71,9 +71,9 @@ void FppTest::Array::setTestVals(S (&a)[Struct::SIZE]) { U32 b[3]; for (U32 i = 0; i < Struct::SIZE; i++) { for (U32 j = 0; j < 3; j++) { - b[j] = FppTest::Utils::getU32(); + b[j] = FppTest::Utils::getNonzeroU32(); } - a[i].set(FppTest::Utils::getU32(), b); + a[i].set(FppTest::Utils::getNonzeroU32(), b); } } @@ -82,7 +82,7 @@ void FppTest::Array::setTestVals(Uint32 (&a)[Uint32Array::SIZE]) { Uint32 b; for (U32 i = 0; i < Uint32Array::SIZE; i++) { for (U32 j = 0; j < Uint32::SIZE; j++) { - b[j] = FppTest::Utils::getU32(); + b[j] = FppTest::Utils::getNonzeroU32(); } a[i] = b; } diff --git a/FppTest/component/CMakeLists.txt b/FppTest/component/CMakeLists.txt new file mode 100644 index 0000000000..9c98983e0b --- /dev/null +++ b/FppTest/component/CMakeLists.txt @@ -0,0 +1,8 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/empty/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/active/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/queued/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/passive/") diff --git a/FppTest/component/README.md b/FppTest/component/README.md new file mode 100644 index 0000000000..6d89772c69 --- /dev/null +++ b/FppTest/component/README.md @@ -0,0 +1,9 @@ +# FppTest/component + +This directory contains unit tests for the FPP component code generator. + +To use this directory, you must have installed F Prime, and you must be inside +the F Prime Python virtual environment. + +* To build the tests, run `fprime-util build --ut`. +* To run the tests, run `fprime-util check`. diff --git a/FppTest/component/active/ActiveTest.cpp b/FppTest/component/active/ActiveTest.cpp new file mode 100644 index 0000000000..1a82380e39 --- /dev/null +++ b/FppTest/component/active/ActiveTest.cpp @@ -0,0 +1,698 @@ +// ====================================================================== +// \title ActiveTest.cpp +// \author tiffany +// \brief cpp file for ActiveTest component implementation class +// ====================================================================== + + +#include "ActiveTest.hpp" +#include + +#include "FppTest/component/active/SerialPortIndexEnumAc.hpp" + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + ActiveTest :: + ActiveTest( + const char *const compName + ) : ActiveTestComponentBase(compName) + { + + } + + void ActiveTest :: + init( + NATIVE_INT_TYPE queueDepth, + NATIVE_INT_TYPE msgSize, + NATIVE_INT_TYPE instance + ) + { + ActiveTestComponentBase::init(queueDepth, msgSize, instance); + } + + ActiveTest :: + ~ActiveTest() + { + + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + void ActiveTest :: + arrayArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + void ActiveTest :: + enumArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + void ActiveTest :: + noArgsAsync_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + void ActiveTest :: + primitiveArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void ActiveTest :: + structArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + void ActiveTest :: + stringArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void ActiveTest :: + arrayArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + void ActiveTest :: + arrayArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + FormalParamArray ActiveTest :: + arrayReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + return this->arrayReturnOut_out(portNum, a, aRef); + } + + FormalParamArray ActiveTest :: + arrayReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + return this->arrayReturnOut_out(portNum, a, aRef); + } + + void ActiveTest :: + cmdOut_handler( + NATIVE_INT_TYPE portNum, + FwOpcodeType opCode, + U32 cmdSeq, + Fw::CmdArgBuffer& args + ) + { + } + + void ActiveTest :: + enumArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + void ActiveTest :: + enumArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + FormalParamEnum ActiveTest :: + enumReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + return this->enumReturnOut_out(portNum, en, enRef); + } + + FormalParamEnum ActiveTest :: + enumReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + return this->enumReturnOut_out(portNum, en, enRef); + } + + void ActiveTest :: + noArgsGuarded_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + bool ActiveTest :: + noArgsReturnGuarded_handler( + const NATIVE_INT_TYPE portNum + ) + { + return this->noArgsReturnOut_out(portNum); + } + + bool ActiveTest :: + noArgsReturnSync_handler( + const NATIVE_INT_TYPE portNum + ) + { + return this->noArgsReturnOut_out(portNum); + } + + void ActiveTest :: + noArgsSync_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + void ActiveTest :: + primitiveArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void ActiveTest :: + primitiveArgsSync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + U32 ActiveTest :: + primitiveReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + return this->primitiveReturnOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + U32 ActiveTest :: + primitiveReturnSync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + return this->primitiveReturnOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void ActiveTest :: + stringArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void ActiveTest :: + stringArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void ActiveTest :: + structArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + + void ActiveTest :: + structArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + + FormalParamStruct ActiveTest :: + structReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + return this->structReturnOut_out(portNum, s, sRef); + } + + FormalParamStruct ActiveTest :: + structReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + return this->structReturnOut_out(portNum, s, sRef); + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + void ActiveTest :: + serialAsync_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + void ActiveTest :: + serialAsyncAssert_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(SerialPortIndex::ENUM, Buffer); + } + + void ActiveTest :: + serialAsyncBlockPriority_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(SerialPortIndex::ARRAY, Buffer); + } + + void ActiveTest :: + serialAsyncDropPriority_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(SerialPortIndex::STRUCT, Buffer); + } + + void ActiveTest :: + serialGuarded_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + void ActiveTest :: + serialSync_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + // ---------------------------------------------------------------------- + // Command handler implementations + // ---------------------------------------------------------------------- + + void ActiveTest :: + CMD_ASYNC_NO_ARGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) + { + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_ASYNC_PRIMITIVE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + U32 u32_1, + U32 u32_2, + F32 f32_1, + F32 f32_2, + bool b1, + bool b2 + ) + { + this->primitiveCmd.args.val1 = u32_1; + this->primitiveCmd.args.val2 = u32_2; + this->primitiveCmd.args.val3 = f32_1; + this->primitiveCmd.args.val4 = f32_2; + this->primitiveCmd.args.val5 = b1; + this->primitiveCmd.args.val6 = b2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_ASYNC_STRINGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + const Fw::CmdStringArg& str1, + const Fw::CmdStringArg& str2 + ) + { + this->stringCmd.args.val1 = str1; + this->stringCmd.args.val2 = str2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_ASYNC_ENUM_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamEnum en + ) + { + this->enumCmd.args.val = en; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_ASYNC_ARRAY_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamArray arr + ) + { + this->arrayCmd.args.val = arr; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_ASYNC_STRUCT_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamStruct str + ) + { + this->structCmd.args.val = str; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_NO_ARGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) + { + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_PRIMITIVE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + U32 u32_1, + U32 u32_2, + F32 f32_1, + F32 f32_2, + bool b1, + bool b2 + ) + { + this->primitiveCmd.args.val1 = u32_1; + this->primitiveCmd.args.val2 = u32_2; + this->primitiveCmd.args.val3 = f32_1; + this->primitiveCmd.args.val4 = f32_2; + this->primitiveCmd.args.val5 = b1; + this->primitiveCmd.args.val6 = b2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_STRINGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + const Fw::CmdStringArg& str1, + const Fw::CmdStringArg& str2 + ) + { + this->stringCmd.args.val1 = str1; + this->stringCmd.args.val2 = str2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_ENUM_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamEnum en + ) + { + this->enumCmd.args.val = en; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_ARRAY_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamArray arr + ) + { + this->arrayCmd.args.val = arr; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveTest :: + CMD_STRUCT_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamStruct str + ) + { + this->structCmd.args.val = str; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + // ---------------------------------------------------------------------- + // Internal interface handlers + // ---------------------------------------------------------------------- + + //! Internal interface handler for internalArray + void ActiveTest :: + internalArray_internalInterfaceHandler( + const FormalParamArray& arr //!< An array + ) + { + this->arrayInterface.args.val = arr; + } + + //! Internal interface handler for internalEnum + void ActiveTest :: + internalEnum_internalInterfaceHandler( + const FormalParamEnum& en //!< An enum + ) + { + this->enumInterface.args.val = en; + } + + //! Internal interface handler for internalNoArgs + void ActiveTest :: + internalNoArgs_internalInterfaceHandler() + { + } + + //! Internal interface handler for internalPrimitive + void ActiveTest :: + internalPrimitive_internalInterfaceHandler( + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ) + { + this->primitiveInterface.args.val1 = u32_1; + this->primitiveInterface.args.val2 = u32_2; + this->primitiveInterface.args.val3 = f32_1; + this->primitiveInterface.args.val4 = f32_2; + this->primitiveInterface.args.val5 = b1; + this->primitiveInterface.args.val6 = b2; + } + + //! Internal interface handler for internalString + void ActiveTest :: + internalString_internalInterfaceHandler( + const Fw::InternalInterfaceString& str1, //!< A string + const Fw::InternalInterfaceString& str2 //!< Another string + ) + { + this->stringInterface.args.val1 = str1; + this->stringInterface.args.val2 = str2; + } + + //! Internal interface handler for internalStruct + void ActiveTest :: + internalStruct_internalInterfaceHandler( + const FormalParamStruct& str //!< A struct + ) + { + this->structInterface.args.val = str; + } + diff --git a/FppTest/component/active/ActiveTest.hpp b/FppTest/component/active/ActiveTest.hpp new file mode 100644 index 0000000000..91905d665f --- /dev/null +++ b/FppTest/component/active/ActiveTest.hpp @@ -0,0 +1,469 @@ +// ====================================================================== +// \title ActiveTest.hpp +// \author tiffany +// \brief hpp file for ActiveTest component implementation class +// ====================================================================== + +#ifndef ActiveTest_HPP +#define ActiveTest_HPP + +#include "FppTest/component/active/ActiveTestComponentAc.hpp" +#include "FppTest/component/types/FormalParamTypes.hpp" + + +class ActiveTest : + public ActiveTestComponentBase +{ + + public: + + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct ActiveTest object + ActiveTest( + const char* const compName //!< The component name + ); + + //! Initialize ActiveTest object + void init( + NATIVE_INT_TYPE queueDepth, //!< The queue depth + NATIVE_INT_TYPE msgSize, //!< The message size + NATIVE_INT_TYPE instance = 0 //!< The instance number + ); + + //! Destroy ActiveTest object + ~ActiveTest(); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for arrayArgsAsync + void arrayArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayArgsGuarded + void arrayArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayArgsSync + void arrayArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayReturnGuarded + FormalParamArray arrayReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayReturnSync + FormalParamArray arrayReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for cmdOut + void cmdOut_handler( + NATIVE_INT_TYPE portNum, //!< The port number + FwOpcodeType opCode, //!< Command Op Code + U32 cmdSeq, //!< Command Sequence + Fw::CmdArgBuffer& args //!< Buffer containing arguments + ); + + //! Handler implementation for enumArgsAsync + void enumArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumArgsGuarded + void enumArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumArgsSync + void enumArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumReturnGuarded + FormalParamEnum enumReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumReturnSync + FormalParamEnum enumReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for noArgsAsync + void noArgsAsync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsGuarded + void noArgsGuarded_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsReturnGuarded + bool noArgsReturnGuarded_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsReturnSync + bool noArgsReturnSync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsSync + void noArgsSync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for primitiveArgsAsync + void primitiveArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveArgsGuarded + void primitiveArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveArgsSync + void primitiveArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveReturnGuarded + U32 primitiveReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveReturnSync + U32 primitiveReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for stringArgsAsync + void stringArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for stringArgsGuarded + void stringArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for stringArgsSync + void stringArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for structArgsAsync + void structArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structArgsGuarded + void structArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structArgsSync + void structArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structReturnGuarded + FormalParamStruct structReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structReturnSync + FormalParamStruct structReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for serialAsync + void serialAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialAsyncAssert + void serialAsyncAssert_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialAsyncBlockPriority + void serialAsyncBlockPriority_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialAsyncDropPriority + void serialAsyncDropPriority_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialGuarded + void serialGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialSync + void serialSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for commands + // ---------------------------------------------------------------------- + + //! Handler implementation for command CMD_NO_ARGS + void CMD_NO_ARGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ); + + //! Handler implementation for command CMD_PRIMITIVE + void CMD_PRIMITIVE_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ); + + //! Handler implementation for command CMD_STRINGS + void CMD_STRINGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + const Fw::CmdStringArg& str1, //!< A string + const Fw::CmdStringArg& str2 //!< Another string + ); + + //! Handler implementation for command CMD_ENUM + void CMD_ENUM_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamEnum en //!< An enum + ); + + //! Handler implementation for command CMD_ARRAY + void CMD_ARRAY_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamArray arr //!< An array + ); + + //! Handler implementation for command CMD_STRUCT + void CMD_STRUCT_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamStruct str //!< A struct + ); + + //! Handler implementation for command CMD_ASYNC_NO_ARGS + void CMD_ASYNC_NO_ARGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ); + + //! Handler implementation for command CMD_ASYNC_PRIMITIVE + void CMD_ASYNC_PRIMITIVE_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ); + + //! Handler implementation for command CMD_ASYNC_STRINGS + void CMD_ASYNC_STRINGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + const Fw::CmdStringArg& str1, //!< A string + const Fw::CmdStringArg& str2 //!< Another string + ); + + //! Handler implementation for command CMD_ASYNC_ENUM + void CMD_ASYNC_ENUM_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamEnum en //!< An enum + ); + + //! Handler implementation for command CMD_ASYNC_ARRAY + void CMD_ASYNC_ARRAY_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamArray arr //!< An array + ); + + //! Handler implementation for command CMD_ASYNC_STRUCT + void CMD_ASYNC_STRUCT_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamStruct str //!< A struct + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined internal interfaces + // ---------------------------------------------------------------------- + + //! Handler implementation for internalArray + void internalArray_internalInterfaceHandler( + const FormalParamArray& arr //!< An array + ); + + //! Handler implementation for internalEnum + void internalEnum_internalInterfaceHandler( + const FormalParamEnum& en //!< An enum + ); + + //! Handler implementation for internalNoArgs + void internalNoArgs_internalInterfaceHandler(); + + //! Handler implementation for internalPrimitive + void internalPrimitive_internalInterfaceHandler( + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ); + + //! Handler implementation for internalString + void internalString_internalInterfaceHandler( + const Fw::InternalInterfaceString& str1, //!< A string + const Fw::InternalInterfaceString& str2 //!< Another string + ); + + //! Handler implementation for internalStruct + void internalStruct_internalInterfaceHandler( + const FormalParamStruct& str //!< A struct + ); + + public: + + //! Enables checking the serialization status of serial port invocations + Fw::SerializeStatus serializeStatus; + + // Command test values + FppTest::Types::PrimitiveParams primitiveCmd; + FppTest::Types::CmdStringParams stringCmd; + FppTest::Types::EnumParam enumCmd; + FppTest::Types::ArrayParam arrayCmd; + FppTest::Types::StructParam structCmd; + + // Internal interface test values + FppTest::Types::PrimitiveParams primitiveInterface; + FppTest::Types::InternalInterfaceStringParams stringInterface; + FppTest::Types::EnumParam enumInterface; + FppTest::Types::ArrayParam arrayInterface; + FppTest::Types::StructParam structInterface; + +}; + + +#endif diff --git a/FppTest/component/active/CMakeLists.txt b/FppTest/component/active/CMakeLists.txt new file mode 100644 index 0000000000..a88faac320 --- /dev/null +++ b/FppTest/component/active/CMakeLists.txt @@ -0,0 +1,57 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/active.fpp" + "${CMAKE_CURRENT_LIST_DIR}/port_types.fpp" + "${CMAKE_CURRENT_LIST_DIR}/port_index_enums.fpp" + "${CMAKE_CURRENT_LIST_DIR}/fpp_types.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ActiveTest.cpp" +) + +register_fprime_module() + +# Sets MODULE_NAME to unique name based on path +get_module_name(${CMAKE_CURRENT_LIST_DIR}) + +# Exclude test module from all build +set_target_properties( + ${MODULE_NAME} + PROPERTIES + EXCLUDE_FROM_ALL TRUE +) + +# Declare dependencies on test modules +set(UT_MOD_DEPS + Fw/Test + STest +) + +# Add unit test directory +# UT_SOURCE_FILES: Sources for unit test +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/active.fpp" + "${CMAKE_CURRENT_LIST_DIR}/port_types.fpp" + "${CMAKE_CURRENT_LIST_DIR}/port_index_enums.fpp" + "${CMAKE_CURRENT_LIST_DIR}/fpp_types.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TestMain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/Tests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TesterHandlers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TesterHelpers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/PortTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/CmdTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/EventTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TlmTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/ParamTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TimeTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/InternalInterfaceTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncTesterHelpers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncPortTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncCmdTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../types/FormalParamTypes.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../../utils/Utils.cpp" +) +register_fprime_ut() diff --git a/FppTest/component/active/active.fpp b/FppTest/component/active/active.fpp new file mode 100644 index 0000000000..dfe555cb88 --- /dev/null +++ b/FppTest/component/active/active.fpp @@ -0,0 +1,17 @@ +@ An active component +active component ActiveTest { + + include "../include/typed_ports.fppi" + include "../include/typed_ports_async.fppi" + include "../include/serial_ports.fppi" + include "../include/serial_ports_async.fppi" + include "../include/special_ports.fppi" + include "../include/internal_ports.fppi" + + include "../include/commands.fppi" + include "../include/commands_async.fppi" + include "../include/events.fppi" + include "../include/telemetry.fppi" + include "../include/params.fppi" + +} diff --git a/FppTest/component/active/fpp_types.fpp b/FppTest/component/active/fpp_types.fpp new file mode 100644 index 0000000000..6942d38fef --- /dev/null +++ b/FppTest/component/active/fpp_types.fpp @@ -0,0 +1,5 @@ +enum FormalParamEnum { X, Y, Z } + +array FormalParamArray = [3] U32 + +struct FormalParamStruct { x: U32, y: string } diff --git a/FppTest/port/port_index_enums.fpp b/FppTest/component/active/port_index_enums.fpp similarity index 93% rename from FppTest/port/port_index_enums.fpp rename to FppTest/component/active/port_index_enums.fpp index 141eb45668..e290788142 100644 --- a/FppTest/port/port_index_enums.fpp +++ b/FppTest/component/active/port_index_enums.fpp @@ -10,5 +10,4 @@ enum SerialPortIndex { ENUM ARRAY STRUCT - SERIAL } diff --git a/FppTest/component/active/port_types.fpp b/FppTest/component/active/port_types.fpp new file mode 100644 index 0000000000..a89decb438 --- /dev/null +++ b/FppTest/component/active/port_types.fpp @@ -0,0 +1,79 @@ +@ A port with no arguments +port NoArgs + +@ A port with primitive arguments +port PrimitiveArgs( + u32: U32 + ref u32Ref: U32 + f32: F32 + ref f32Ref: F32 + b: bool + ref bRef: bool +) + +@ A port with string arguments +port StringArgs( + str80: string @< A string of size 80 + ref str80Ref: string + str100: string size 100 @< A string of size 100 + ref str100Ref: string size 100 +) + +@ A port with enum arguments +port EnumArgs( + en: FormalParamEnum @< An enum + ref enRef: FormalParamEnum @< An enum ref +) + +@ A port with array arguments +port ArrayArgs( + a: FormalParamArray @< An array + ref aRef: FormalParamArray @< An array ref +) + +@ A port with struct arguments +port StructArgs( + s: FormalParamStruct @< A struct + ref sRef: FormalParamStruct @< A struct ref +) + +@ A port with no arguments +port NoArgsReturn -> bool + +@ A port returning a primitive type +port PrimitiveReturn( + u32: U32 + ref u32Ref: U32 + f32: F32 + ref f32Ref: F32 + b: bool + ref bRef: bool +) -> U32 + +# Commented out because of bug in Python component autocoder +# Will be tested with the FPP component autocoder +# @ A port returning a string type +# port StringReturn( +# str80: string @< A string of size 80 +# ref str80Ref: string +# str100: string size 100 @< A string of size 100 +# ref str100Ref: string size 100 +# ) -> string + +@ A port returning an enum type +port EnumReturn( + en: FormalParamEnum @< An enum + ref enRef: FormalParamEnum @< An enum ref +) -> FormalParamEnum + +@ A port returning an array type +port ArrayReturn( + a: FormalParamArray @< An array + ref aRef: FormalParamArray @< An array ref +) -> FormalParamArray + +@ A port returning a struct type +port StructReturn( + s: FormalParamStruct @< A struct + ref sRef: FormalParamStruct @< A struct ref +) -> FormalParamStruct diff --git a/FppTest/component/active/test/ut/Tester.cpp b/FppTest/component/active/test/ut/Tester.cpp new file mode 100644 index 0000000000..70908d6262 --- /dev/null +++ b/FppTest/component/active/test/ut/Tester.cpp @@ -0,0 +1,120 @@ +// ====================================================================== +// \title ActiveTest/test/ut/Tester.cpp +// \author tiffany +// \brief cpp file for ActiveTest test harness implementation class +// ====================================================================== + +#include "STest/Pick/Pick.hpp" +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() + : ActiveTestGTestBase("Tester", Tester::MAX_HISTORY_SIZE), + component("ActiveTest"), + primitiveBuf(primitiveData, sizeof(primitiveData)), + stringBuf(stringData, sizeof(stringData)), + enumBuf(enumData, sizeof(enumData)), + arrayBuf(arrayData, sizeof(arrayData)), + structBuf(structData, sizeof(structData)), + serialBuf(serialData, sizeof(serialData)), + time(STest::Pick::any(), STest::Pick::any()) { + this->initComponents(); + this->connectPorts(); + this->connectAsyncPorts(); +} + +Tester ::~Tester() {} + +void Tester ::initComponents() { + this->init(); + this->component.init(Tester::TEST_INSTANCE_QUEUE_DEPTH, Tester::TEST_INSTANCE_ID); +} + +Fw::ParamValid Tester ::from_prmGetIn_handler(const NATIVE_INT_TYPE portNum, FwPrmIdType id, Fw::ParamBuffer& val) { + val.resetSer(); + + Fw::SerializeStatus status; + U32 id_base = component.getIdBase(); + + FW_ASSERT(id >= id_base); + + switch (id - id_base) { + case ActiveTestComponentBase::PARAMID_PARAMBOOL: + status = val.serialize(boolPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMU32: + status = val.serialize(u32Prm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMSTRING: + status = val.serialize(stringPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMENUM: + status = val.serialize(enumPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMARRAY: + status = val.serialize(arrayPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMSTRUCT: + status = val.serialize(structPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + } + + this->pushFromPortEntry_prmGetIn(id, val); + + return prmValid; +} + +void Tester ::from_prmSetIn_handler(const NATIVE_INT_TYPE portNum, FwPrmIdType id, Fw::ParamBuffer& val) { + Fw::SerializeStatus status; + U32 id_base = component.getIdBase(); + + FW_ASSERT(id >= id_base); + + switch (id - id_base) { + case ActiveTestComponentBase::PARAMID_PARAMBOOL: + status = val.deserialize(boolPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMU32: + status = val.deserialize(u32Prm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMSTRING: + status = val.deserialize(stringPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMENUM: + status = val.deserialize(enumPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMARRAY: + status = val.deserialize(arrayPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case ActiveTestComponentBase::PARAMID_PARAMSTRUCT: + status = val.deserialize(structPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + } + + this->pushFromPortEntry_prmSetIn(id, val); +} diff --git a/FppTest/component/active/test/ut/Tester.hpp b/FppTest/component/active/test/ut/Tester.hpp new file mode 100644 index 0000000000..6aa58adfc6 --- /dev/null +++ b/FppTest/component/active/test/ut/Tester.hpp @@ -0,0 +1,297 @@ +// ====================================================================== +// \title ActiveTest/test/ut/Tester.hpp +// \author tiffany +// \brief hpp file for ActiveTest test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "FppTest/component/active/ActiveTest.hpp" +#include "FppTest/component/active/SerialPortIndexEnumAc.hpp" +#include "FppTest/component/active/TypedPortIndexEnumAc.hpp" +#include "FppTest/component/tests/CmdTests.hpp" +#include "FppTest/component/tests/EventTests.hpp" +#include "FppTest/component/tests/InternalInterfaceTests.hpp" +#include "FppTest/component/tests/ParamTests.hpp" +#include "FppTest/component/tests/PortTests.hpp" +#include "FppTest/component/tests/TlmTests.hpp" +#include "FppTest/component/types/FormalParamTypes.hpp" +#include "GTestBase.hpp" + +class Tester : public ActiveTestGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 100; + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + // Queue depth supplied to component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; + + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + PORT_TEST_DECLS + PORT_TEST_DECLS_ASYNC + + CMD_TEST_DECLS + CMD_TEST_DECLS_ASYNC + + EVENT_TEST_DECLS + + TLM_TEST_DECLS + + void testParam(); + PARAM_CMD_TEST_DECLS + + INTERNAL_INT_TEST_DECLS + + void testTime(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_arrayArgsOut + //! + void from_arrayArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamArray& a, /*!< + An array + */ + FormalParamArray& aRef /*!< + An array ref + */ + ); + + //! Handler for from_arrayReturnOut + //! + FormalParamArray from_arrayReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamArray& a, /*!< + An array + */ + FormalParamArray& aRef /*!< + An array ref + */ + ); + + //! Handler for from_enumArgsOut + //! + void from_enumArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamEnum& en, /*!< + An enum + */ + FormalParamEnum& enRef /*!< + An enum ref + */ + ); + + //! Handler for from_enumReturnOut + //! + FormalParamEnum from_enumReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamEnum& en, /*!< + An enum + */ + FormalParamEnum& enRef /*!< + An enum ref + */ + ); + + //! Handler for from_noArgsOut + //! + void from_noArgsOut_handler(const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_noArgsReturnOut + //! + bool from_noArgsReturnOut_handler(const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_primitiveArgsOut + //! + void from_primitiveArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef); + + //! Handler for from_primitiveReturnOut + //! + U32 from_primitiveReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef); + + //! Handler for from_prmGetIn + //! + Fw::ParamValid from_prmGetIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwPrmIdType id, /*!< + Parameter ID + */ + Fw::ParamBuffer& val /*!< + Buffer containing serialized parameter value + */ + ); + + //! Handler for from_prmGetIn + //! + void from_prmSetIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwPrmIdType id, /*!< + Parameter ID + */ + Fw::ParamBuffer& val /*!< + Buffer containing serialized parameter value + */ + ); + + //! Handler for from_stringArgsOut + //! + void from_stringArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const str80String& str80, /*!< + A string of size 80 + */ + str80RefString& str80Ref, + const str100String& str100, /*!< + A string of size 100 + */ + str100RefString& str100Ref); + + //! Handler for from_structArgsOut + //! + void from_structArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamStruct& s, /*!< + A struct + */ + FormalParamStruct& sRef /*!< + A struct ref + */ + ); + + //! Handler for from_structReturnOut + //! + FormalParamStruct from_structReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamStruct& s, /*!< + A struct + */ + FormalParamStruct& sRef /*!< + A struct ref + */ + ); + + void cmdResponseIn(const FwOpcodeType opCode, const U32 cmdSeq, const Fw::CmdResponse response); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handlers for serial from ports + // ---------------------------------------------------------------------- + + //! Handler for from_serialOut + //! + void from_serialOut_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase& Buffer /*!< The serialization buffer*/ + ); + + public: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Connect async ports + void connectAsyncPorts(); + + //! Connect prmSetIn port + void connectPrmSetIn(); + + //! Connect timeGetOut port + void connectTimeGetOut(); + + //! Connect serial ports to special ports + void connectSpecialPortsSerial(); + + //! Set prmValid + void setPrmValid(Fw::ParamValid valid); + + //! Call doDispatch() on component under test + Fw::QueuedComponentBase::MsgDispatchStatus doDispatch(); + + //! Initialize components + //! + void initComponents(); + + //! Check successful status of a serial port invocation + void checkSerializeStatusSuccess(); + + //! Check unsuccessful status of a serial port invocation + void checkSerializeStatusBufferEmpty(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + ActiveTest component; + + // Values returned by typed output ports + FppTest::Types::BoolType noParamReturnVal; + FppTest::Types::U32Type primitiveReturnVal; + FppTest::Types::EnumType enumReturnVal; + FppTest::Types::ArrayType arrayReturnVal; + FppTest::Types::StructType structReturnVal; + + // Buffers from serial output ports; + U8 primitiveData[InputPrimitiveArgsPort::SERIALIZED_SIZE]; + U8 stringData[InputStringArgsPort::SERIALIZED_SIZE]; + U8 enumData[InputEnumArgsPort::SERIALIZED_SIZE]; + U8 arrayData[InputArrayArgsPort::SERIALIZED_SIZE]; + U8 structData[InputStructArgsPort::SERIALIZED_SIZE]; + U8 serialData[SERIAL_ARGS_BUFFER_CAPACITY]; + + Fw::SerialBuffer primitiveBuf; + Fw::SerialBuffer stringBuf; + Fw::SerialBuffer enumBuf; + Fw::SerialBuffer arrayBuf; + Fw::SerialBuffer structBuf; + Fw::SerialBuffer serialBuf; + + // Command test values + Fw::CmdResponse cmdResp; + + // Parameter test values + FppTest::Types::BoolParam boolPrm; + FppTest::Types::U32Param u32Prm; + FppTest::Types::PrmStringParam stringPrm; + FppTest::Types::EnumParam enumPrm; + FppTest::Types::ArrayParam arrayPrm; + FppTest::Types::StructParam structPrm; + Fw::ParamValid prmValid; + + // Time test values + Fw::Time time; +}; + +#endif diff --git a/FppTest/port/CMakeLists.txt b/FppTest/component/empty/CMakeLists.txt similarity index 53% rename from FppTest/port/CMakeLists.txt rename to FppTest/component/empty/CMakeLists.txt index 0c6fab1e8c..11cdeadb00 100644 --- a/FppTest/port/CMakeLists.txt +++ b/FppTest/component/empty/CMakeLists.txt @@ -3,12 +3,8 @@ # ====================================================================== set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/fpp_types.fpp" - "${CMAKE_CURRENT_LIST_DIR}/no_return_ports.fpp" - "${CMAKE_CURRENT_LIST_DIR}/return_ports.fpp" - "${CMAKE_CURRENT_LIST_DIR}/port_index_enums.fpp" - "${CMAKE_CURRENT_LIST_DIR}/example_comp.fpp" - "${CMAKE_CURRENT_LIST_DIR}/Example.cpp" + "${CMAKE_CURRENT_LIST_DIR}/empty.fpp" + "${CMAKE_CURRENT_LIST_DIR}/Empty.cpp" ) register_fprime_module() @@ -32,14 +28,9 @@ set(UT_MOD_DEPS # Add unit test directory # UT_SOURCE_FILES: Sources for unit test set(UT_SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/fpp_types.fpp" - "${CMAKE_CURRENT_LIST_DIR}/no_return_ports.fpp" - "${CMAKE_CURRENT_LIST_DIR}/return_ports.fpp" - "${CMAKE_CURRENT_LIST_DIR}/port_index_enums.fpp" - "${CMAKE_CURRENT_LIST_DIR}/example_comp.fpp" - "${CMAKE_CURRENT_LIST_DIR}/../utils/Utils.cpp" - "${CMAKE_CURRENT_LIST_DIR}/PortTypes.cpp" + "${CMAKE_CURRENT_LIST_DIR}/empty.fpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TesterHelpers.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" ) register_fprime_ut() diff --git a/FppTest/component/empty/Empty.cpp b/FppTest/component/empty/Empty.cpp new file mode 100644 index 0000000000..a43b619f80 --- /dev/null +++ b/FppTest/component/empty/Empty.cpp @@ -0,0 +1,37 @@ +// ====================================================================== +// \title Empty.cpp +// \author tiffany +// \brief cpp file for Empty component implementation class +// ====================================================================== + + +#include "Empty.hpp" +#include + + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +Empty :: + Empty( + const char *const compName + ) : EmptyComponentBase(compName) +{ + +} + +void Empty :: + init( + NATIVE_INT_TYPE instance + ) +{ + EmptyComponentBase::init(instance); +} + +Empty :: + ~Empty() +{ + +} + diff --git a/FppTest/component/empty/Empty.hpp b/FppTest/component/empty/Empty.hpp new file mode 100644 index 0000000000..705d9b6275 --- /dev/null +++ b/FppTest/component/empty/Empty.hpp @@ -0,0 +1,37 @@ +// ====================================================================== +// \title Empty.hpp +// \author tiffany +// \brief hpp file for Empty component implementation class +// ====================================================================== + +#ifndef Empty_HPP +#define Empty_HPP + +#include "FppTest/component/empty/EmptyComponentAc.hpp" + +class Empty : + public EmptyComponentBase +{ + + public: + + // ---------------------------------------------------------------------- + // Component construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct Empty object + Empty( + const char* const compName //!< The component name + ); + + //! Initialize Empty object + void init( + NATIVE_INT_TYPE instance = 0 //!< The instance number + ); + + //! Destroy Empty object + ~Empty(); + +}; + +#endif diff --git a/FppTest/component/empty/empty.fpp b/FppTest/component/empty/empty.fpp new file mode 100644 index 0000000000..89443e6095 --- /dev/null +++ b/FppTest/component/empty/empty.fpp @@ -0,0 +1 @@ +passive component Empty {} diff --git a/FppTest/component/empty/test/ut/TestMain.cpp b/FppTest/component/empty/test/ut/TestMain.cpp new file mode 100644 index 0000000000..ea9da47ce4 --- /dev/null +++ b/FppTest/component/empty/test/ut/TestMain.cpp @@ -0,0 +1,15 @@ +// ---------------------------------------------------------------------- +// TestMain.cpp +// ---------------------------------------------------------------------- + +#include "Tester.hpp" + +TEST(Nominal, ToDo) { + Tester tester; + tester.test(); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/FppTest/component/empty/test/ut/Tester.cpp b/FppTest/component/empty/test/ut/Tester.cpp new file mode 100644 index 0000000000..9d5bf24342 --- /dev/null +++ b/FppTest/component/empty/test/ut/Tester.cpp @@ -0,0 +1,26 @@ +// ====================================================================== +// \title Empty/test/ut/Tester.cpp +// \author tiffany +// \brief cpp file for Empty test harness implementation class +// ====================================================================== + +#include "Tester.hpp" + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() : EmptyGTestBase("Tester", Tester::MAX_HISTORY_SIZE), component("Empty") { + this->initComponents(); + this->connectPorts(); +} + +Tester ::~Tester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::test() { + // Nothing else to test in an empty component +} diff --git a/FppTest/component/empty/test/ut/Tester.hpp b/FppTest/component/empty/test/ut/Tester.hpp new file mode 100644 index 0000000000..829ef7a68a --- /dev/null +++ b/FppTest/component/empty/test/ut/Tester.hpp @@ -0,0 +1,62 @@ +// ====================================================================== +// \title Empty/test/ut/Tester.hpp +// \author tiffany +// \brief hpp file for Empty test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "FppTest/component/empty/Empty.hpp" +#include "GTestBase.hpp" + +class Tester : public EmptyGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10; + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + void test(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + Empty component; +}; + +#endif diff --git a/FppTest/component/empty/test/ut/TesterHelpers.cpp b/FppTest/component/empty/test/ut/TesterHelpers.cpp new file mode 100644 index 0000000000..d39d3ffceb --- /dev/null +++ b/FppTest/component/empty/test/ut/TesterHelpers.cpp @@ -0,0 +1,20 @@ +// ====================================================================== +// \title Empty/test/ut/TesterHelpers.cpp +// \author Auto-generated +// \brief cpp file for Empty component test harness base class +// +// NOTE: this file was automatically generated +// +// ====================================================================== +#include "Tester.hpp" + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void Tester ::connectPorts() {} + +void Tester ::initComponents() { + this->init(); + this->component.init(Tester::TEST_INSTANCE_ID); +} diff --git a/FppTest/component/include/commands.fppi b/FppTest/component/include/commands.fppi new file mode 100644 index 0000000000..accd7e9cc5 --- /dev/null +++ b/FppTest/component/include/commands.fppi @@ -0,0 +1,27 @@ +sync command CMD_NO_ARGS + +sync command CMD_PRIMITIVE( + u32_1: U32, @< A U32 + u32_2: U32, @< A U32 + f32_1: F32, @< An F32 + f32_2: F32, @< An F32 + b1: bool @< A boolean + b2: bool @< A boolean +) opcode 0x10 + +sync command CMD_STRINGS( + str1: string, @< A string + str2: string size 100 @< Another string +) + +sync command CMD_ENUM( + en: FormalParamEnum @< An enum +) + +guarded command CMD_ARRAY( + arr: FormalParamArray @< An array +) + +guarded command CMD_STRUCT( + str: FormalParamStruct @< A struct +) diff --git a/FppTest/component/include/commands_async.fppi b/FppTest/component/include/commands_async.fppi new file mode 100644 index 0000000000..16e1eb2abb --- /dev/null +++ b/FppTest/component/include/commands_async.fppi @@ -0,0 +1,27 @@ +async command CMD_ASYNC_NO_ARGS + +async command CMD_ASYNC_PRIMITIVE ( + u32_1: U32, @< A U32 + u32_2: U32, @< A U32 + f32_1: F32, @< An F32 + f32_2: F32, @< An F32 + b1: bool @< A boolean + b2: bool @< A boolean +) + +async command CMD_ASYNC_STRINGS( + str1: string, @< A string + str2: string size 100 @< Another string +) opcode 0x20 priority 10 + +async command CMD_ASYNC_ENUM ( + en: FormalParamEnum @< An enum +) priority 20 + +async command CMD_ASYNC_ARRAY( + arr: FormalParamArray @< An array +) drop + +async command CMD_ASYNC_STRUCT( + str: FormalParamStruct @< A struct +) priority 30 drop diff --git a/FppTest/component/include/events.fppi b/FppTest/component/include/events.fppi new file mode 100644 index 0000000000..ce704f3bf8 --- /dev/null +++ b/FppTest/component/include/events.fppi @@ -0,0 +1,50 @@ +event EventNoArgs \ + severity activity high \ + format "Event Activity High occurred" + +event EventPrimitive( + u32_1: U32, @< A U32 + u32_2: U32, @< A U32 + f32_1: F32, @< An F32 + f32_2: F32, @< An F32 + b1: bool @< A boolean + b2: bool @< A boolean +) \ + severity activity low \ + id 0x10 \ + format "Event Activity Low occurred with arguments: {}, {}, {}, {}, {}, {}" \ + throttle 5 + +event EventString ( + str1: string, @< A string + str2: string size 100 @< Another string +) \ + severity command \ + format "Event Command occurred with arguments: {}, {}" + +event EventEnum( + en: FormalParamEnum @< An enum +) \ + severity diagnostic \ + format "Event Diagnostic occurred with argument: {}" + +event EventArray ( + arr: FormalParamArray @< An array +) \ + severity fatal \ + format "Event Fatal occurred with argument: {}" \ + throttle 10 + +event EventStruct ( + str: FormalParamStruct @< A struct +) \ + severity warning high \ + id 0x20 \ + format "Event Warning High occurred with argument: {}" + +event EventBool ( + b: bool @< A boolean +) \ + severity warning low \ + format "Event Warning Low occurred {}" \ + throttle 10 diff --git a/FppTest/component/include/internal_ports.fppi b/FppTest/component/include/internal_ports.fppi new file mode 100644 index 0000000000..1a87ba78a6 --- /dev/null +++ b/FppTest/component/include/internal_ports.fppi @@ -0,0 +1,27 @@ +internal port internalNoArgs priority 10 drop + +internal port internalPrimitive( + u32_1: U32, @< A U32 + u32_2: U32, @< A U32 + f32_1: F32, @< An F32 + f32_2: F32, @< An F32 + b1: bool @< A boolean + b2: bool @< A boolean +) priority 5 + +internal port internalString( + str1: string, @< A string + str2: string size 100 @< Another string +) + +internal port internalEnum( + en: FormalParamEnum @< An enum +) + +internal port internalArray( + arr: FormalParamArray @< An array +) + +internal port internalStruct( + str: FormalParamStruct @< A struct +) priority 20 drop diff --git a/FppTest/component/include/params.fppi b/FppTest/component/include/params.fppi new file mode 100644 index 0000000000..f02c01377d --- /dev/null +++ b/FppTest/component/include/params.fppi @@ -0,0 +1,17 @@ +param ParamBool: bool + +param ParamU32: U32 + +param ParamString: string \ + default "default" + +param ParamEnum: FormalParamEnum \ + id 0x30 + +param ParamArray: FormalParamArray \ + default [ 1.0, 2.0, 3.0 ] \ + save opcode 0x35 + +param ParamStruct: FormalParamStruct \ + set opcode 0x40 \ + save opcode 0x45 diff --git a/FppTest/component/include/serial_ports.fppi b/FppTest/component/include/serial_ports.fppi new file mode 100644 index 0000000000..24583178a2 --- /dev/null +++ b/FppTest/component/include/serial_ports.fppi @@ -0,0 +1,8 @@ +@ A serial sync input port +sync input port serialSync: [6] serial + +@ A serial guarded input +guarded input port serialGuarded: [6] serial + +@ A serial output port +output port serialOut: [6] serial diff --git a/FppTest/component/include/serial_ports_async.fppi b/FppTest/component/include/serial_ports_async.fppi new file mode 100644 index 0000000000..bfd4cc8ed2 --- /dev/null +++ b/FppTest/component/include/serial_ports_async.fppi @@ -0,0 +1,11 @@ +@ A serial async input port +async input port serialAsync: [3] serial + +@ A serial async input port with queue full behavior and priority +async input port serialAsyncAssert: serial assert + +@ A serial async input port with queue full behavior and priority +async input port serialAsyncBlockPriority: serial priority 10 block + +@ A serial async input port with queue full behavior and priority +async input port serialAsyncDropPriority: serial priority 5 drop diff --git a/FppTest/component/include/special_ports.fppi b/FppTest/component/include/special_ports.fppi new file mode 100644 index 0000000000..4a340a7f17 --- /dev/null +++ b/FppTest/component/include/special_ports.fppi @@ -0,0 +1,26 @@ +@ A port for receiving commands +command recv port cmdIn + +@ A port for sending command registration requests +command reg port cmdRegOut + +@ A port for sending command responses +command resp port cmdResponseOut + +@ A port for emitting events +event port eventOut + +@ A port for emitting text events +text event port textEventOut + +@ A port for emitting telemetry +telemetry port tlmOut + +@ A port for getting parameter values +param get port prmGetOut + +@ A port for setting parameter values +param set port prmSetOut + +@ A port for getting the time +time get port timeGetOut diff --git a/FppTest/component/include/telemetry.fppi b/FppTest/component/include/telemetry.fppi new file mode 100644 index 0000000000..95f8195805 --- /dev/null +++ b/FppTest/component/include/telemetry.fppi @@ -0,0 +1,21 @@ +telemetry ChannelEnum: FormalParamEnum + +telemetry ChannelArray: FormalParamArray \ + id 0x10 + +telemetry ChannelStruct: FormalParamStruct \ + update always + +telemetry ChannelU32: U32 \ + format "{x}" \ + low { red 0, orange 1, yellow 2 } + +telemetry ChannelF32: F32 \ + update always \ + format "{.3f}" \ + low { red -3, orange -2, yellow -1 } \ + high { red 3, orange 2, yellow 1 } + +telemetry ChannelString: string \ + update on change \ + format "{}" diff --git a/FppTest/component/include/typed_ports.fppi b/FppTest/component/include/typed_ports.fppi new file mode 100644 index 0000000000..0dfed00c2b --- /dev/null +++ b/FppTest/component/include/typed_ports.fppi @@ -0,0 +1,97 @@ +# ---------------------------------------------------------------------- +# Typed input ports with no return type +# ---------------------------------------------------------------------- + +sync input port noArgsSync: [2] NoArgs + +guarded input port noArgsGuarded: [2] NoArgs + +sync input port primitiveArgsSync: [2] PrimitiveArgs + +guarded input port primitiveArgsGuarded: [2] PrimitiveArgs + +sync input port stringArgsSync: [2] StringArgs + +guarded input port stringArgsGuarded: [2] StringArgs + +sync input port enumArgsSync: [2] EnumArgs + +guarded input port enumArgsGuarded: [2] EnumArgs + +sync input port arrayArgsSync: [2] ArrayArgs + +guarded input port arrayArgsGuarded: [2] ArrayArgs + +sync input port structArgsSync: [2] StructArgs + +guarded input port structArgsGuarded: [2] StructArgs + +# ---------------------------------------------------------------------- +# Typed output ports with no return type +# ---------------------------------------------------------------------- + +output port noArgsOut: [2] NoArgs + +output port primitiveArgsOut: [2] PrimitiveArgs + +output port stringArgsOut: [2] StringArgs + +output port enumArgsOut: [2] EnumArgs + +output port arrayArgsOut: [2] ArrayArgs + +output port structArgsOut: [2] StructArgs + +# ---------------------------------------------------------------------- +# Typed input ports with return type +# ---------------------------------------------------------------------- + +sync input port noArgsReturnSync: NoArgsReturn + +guarded input port noArgsReturnGuarded: NoArgsReturn + +sync input port primitiveReturnSync: PrimitiveReturn + +guarded input port primitiveReturnGuarded: PrimitiveReturn + +# sync input port stringReturnSync: StringReturn + +# guarded input port stringReturnGuarded: StringReturn + +sync input port enumReturnSync: EnumReturn + +guarded input port enumReturnGuarded: EnumReturn + +sync input port arrayReturnSync: ArrayReturn + +guarded input port arrayReturnGuarded: ArrayReturn + +sync input port structReturnSync: StructReturn + +guarded input port structReturnGuarded: StructReturn + +# ---------------------------------------------------------------------- +# Typed output ports with return type +# ---------------------------------------------------------------------- + +output port noArgsReturnOut: NoArgsReturn + +output port primitiveReturnOut: PrimitiveReturn + +# output port stringReturnOut: StringReturn + +output port enumReturnOut: EnumReturn + +output port arrayReturnOut: ArrayReturn + +output port structReturnOut: StructReturn + +# ---------------------------------------------------------------------- +# Ports for testing special ports +# ---------------------------------------------------------------------- + +sync input port cmdOut: Fw.Cmd + +output port prmGetIn: Fw.PrmGet + +output port prmSetIn: Fw.PrmSet diff --git a/FppTest/component/include/typed_ports_async.fppi b/FppTest/component/include/typed_ports_async.fppi new file mode 100644 index 0000000000..ed5c7380f2 --- /dev/null +++ b/FppTest/component/include/typed_ports_async.fppi @@ -0,0 +1,11 @@ +async input port noArgsAsync: [2] NoArgs + +async input port primitiveArgsAsync: [2] PrimitiveArgs + +async input port stringArgsAsync: [2] StringArgs + +async input port enumArgsAsync: [2] EnumArgs assert + +async input port arrayArgsAsync: [2] ArrayArgs priority 10 block + +async input port structArgsAsync: [2] StructArgs priority 5 drop diff --git a/FppTest/component/passive/CMakeLists.txt b/FppTest/component/passive/CMakeLists.txt new file mode 100644 index 0000000000..84667b0eec --- /dev/null +++ b/FppTest/component/passive/CMakeLists.txt @@ -0,0 +1,46 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/passive.fpp" + "${CMAKE_CURRENT_LIST_DIR}/PassiveTest.cpp" +) + +register_fprime_module() + +# Sets MODULE_NAME to unique name based on path +get_module_name(${CMAKE_CURRENT_LIST_DIR}) + +# Exclude test module from all build +set_target_properties( + ${MODULE_NAME} + PROPERTIES + EXCLUDE_FROM_ALL TRUE +) + +# Declare dependencies on test modules +set(UT_MOD_DEPS + Fw/Test + STest +) + +# Add unit test directory +# UT_SOURCE_FILES: Sources for unit test +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/passive.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TestMain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/Tests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TesterHandlers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TesterHelpers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/PortTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/CmdTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/EventTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TlmTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/ParamTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TimeTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../types/FormalParamTypes.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../../utils/Utils.cpp" +) +register_fprime_ut() diff --git a/FppTest/component/passive/PassiveTest.cpp b/FppTest/component/passive/PassiveTest.cpp new file mode 100644 index 0000000000..acd3908cf6 --- /dev/null +++ b/FppTest/component/passive/PassiveTest.cpp @@ -0,0 +1,434 @@ +// ====================================================================== +// \title PassiveTest.cpp +// \author tiffany +// \brief cpp file for PassiveTest component implementation class +// ====================================================================== + + +#include "PassiveTest.hpp" +#include + + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + PassiveTest :: + PassiveTest( + const char *const compName + ) : PassiveTestComponentBase(compName) + { + + } + + void PassiveTest :: + init( + NATIVE_INT_TYPE instance + ) + { + PassiveTestComponentBase::init(instance); + } + + PassiveTest :: + ~PassiveTest() + { + + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + void PassiveTest :: + arrayArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + void PassiveTest :: + arrayArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + FormalParamArray PassiveTest :: + arrayReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + return this->arrayReturnOut_out(portNum, a, aRef); + } + + FormalParamArray PassiveTest :: + arrayReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + return this->arrayReturnOut_out(portNum, a, aRef); + } + + void PassiveTest :: + cmdOut_handler( + NATIVE_INT_TYPE portNum, + FwOpcodeType opCode, + U32 cmdSeq, + Fw::CmdArgBuffer& args + ) + { + } + + void PassiveTest :: + enumArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + void PassiveTest :: + enumArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + FormalParamEnum PassiveTest :: + enumReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + return this->enumReturnOut_out(portNum, en, enRef); + } + + FormalParamEnum PassiveTest :: + enumReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + return this->enumReturnOut_out(portNum, en, enRef); + } + + void PassiveTest :: + noArgsGuarded_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + bool PassiveTest :: + noArgsReturnGuarded_handler( + const NATIVE_INT_TYPE portNum + ) + { + return this->noArgsReturnOut_out(portNum); + } + + bool PassiveTest :: + noArgsReturnSync_handler( + const NATIVE_INT_TYPE portNum + ) + { + return this->noArgsReturnOut_out(portNum); + } + + void PassiveTest :: + noArgsSync_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + void PassiveTest :: + primitiveArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void PassiveTest :: + primitiveArgsSync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + U32 PassiveTest :: + primitiveReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + return this->primitiveReturnOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + U32 PassiveTest :: + primitiveReturnSync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + return this->primitiveReturnOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void PassiveTest :: + stringArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void PassiveTest :: + stringArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void PassiveTest :: + structArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + + void PassiveTest :: + structArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + + FormalParamStruct PassiveTest :: + structReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + return this->structReturnOut_out(portNum, s, sRef); + } + + FormalParamStruct PassiveTest :: + structReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + return this->structReturnOut_out(portNum, s, sRef); + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + void PassiveTest :: + serialGuarded_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + void PassiveTest :: + serialSync_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + // ---------------------------------------------------------------------- + // Command handler implementations + // ---------------------------------------------------------------------- + + void PassiveTest :: + CMD_NO_ARGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) + { + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void PassiveTest :: + CMD_PRIMITIVE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + U32 u32_1, + U32 u32_2, + F32 f32_1, + F32 f32_2, + bool b1, + bool b2 + ) + { + this->primitiveCmd.args.val1 = u32_1; + this->primitiveCmd.args.val2 = u32_2; + this->primitiveCmd.args.val3 = f32_1; + this->primitiveCmd.args.val4 = f32_2; + this->primitiveCmd.args.val5 = b1; + this->primitiveCmd.args.val6 = b2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void PassiveTest :: + CMD_STRINGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + const Fw::CmdStringArg& str1, + const Fw::CmdStringArg& str2 + ) + { + this->stringCmd.args.val1 = str1; + this->stringCmd.args.val2 = str2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void PassiveTest :: + CMD_ENUM_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamEnum en + ) + { + this->enumCmd.args.val = en; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void PassiveTest :: + CMD_ARRAY_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamArray arr + ) + { + this->arrayCmd.args.val = arr; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void PassiveTest :: + CMD_STRUCT_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamStruct str + ) + { + this->structCmd.args.val = str; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + diff --git a/FppTest/component/passive/PassiveTest.hpp b/FppTest/component/passive/PassiveTest.hpp new file mode 100644 index 0000000000..0eea8e98f0 --- /dev/null +++ b/FppTest/component/passive/PassiveTest.hpp @@ -0,0 +1,303 @@ +// ====================================================================== +// \title PassiveTest.hpp +// \author tiffany +// \brief hpp file for PassiveTest component implementation class +// ====================================================================== + +#ifndef PassiveTest_HPP +#define PassiveTest_HPP + +#include "FppTest/component/passive/PassiveTestComponentAc.hpp" +#include "FppTest/component/types/FormalParamTypes.hpp" + + +class PassiveTest : + public PassiveTestComponentBase +{ + + public: + + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct PassiveTest object + PassiveTest( + const char* const compName //!< The component name + ); + + //! Initialize PassiveTest object + void init( + NATIVE_INT_TYPE instance = 0 //!< The instance number + ); + + //! Destroy PassiveTest object + ~PassiveTest(); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for arrayArgsGuarded + void arrayArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayArgsSync + void arrayArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayReturnGuarded + FormalParamArray arrayReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayReturnSync + FormalParamArray arrayReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for cmdOut + void cmdOut_handler( + NATIVE_INT_TYPE portNum, //!< The port number + FwOpcodeType opCode, //!< Command Op Code + U32 cmdSeq, //!< Command Sequence + Fw::CmdArgBuffer& args //!< Buffer containing arguments + ); + + //! Handler implementation for enumArgsGuarded + void enumArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumArgsSync + void enumArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumReturnGuarded + FormalParamEnum enumReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumReturnSync + FormalParamEnum enumReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for noArgsGuarded + void noArgsGuarded_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsReturnGuarded + bool noArgsReturnGuarded_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsReturnSync + bool noArgsReturnSync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsSync + void noArgsSync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for primitiveArgsGuarded + void primitiveArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveArgsSync + void primitiveArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveReturnGuarded + U32 primitiveReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveReturnSync + U32 primitiveReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for stringArgsGuarded + void stringArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for stringArgsSync + void stringArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for structArgsGuarded + void structArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structArgsSync + void structArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structReturnGuarded + FormalParamStruct structReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structReturnSync + FormalParamStruct structReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for serialGuarded + void serialGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialSync + void serialSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for commands + // ---------------------------------------------------------------------- + + //! Handler implementation for command CMD_NO_ARGS + void CMD_NO_ARGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ); + + //! Handler implementation for command CMD_PRIMITIVE + void CMD_PRIMITIVE_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ); + + //! Handler implementation for command CMD_STRINGS + void CMD_STRINGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + const Fw::CmdStringArg& str1, //!< A string + const Fw::CmdStringArg& str2 //!< Another string + ); + + //! Handler implementation for command CMD_ENUM + void CMD_ENUM_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamEnum en //!< An enum + ); + + //! Handler implementation for command CMD_ARRAY + void CMD_ARRAY_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamArray arr //!< An array + ); + + //! Handler implementation for command CMD_STRUCT + void CMD_STRUCT_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamStruct str //!< A struct + ); + + public: + + //! Enables checking the serialization status of serial port invocations + Fw::SerializeStatus serializeStatus; + + // Command test values + FppTest::Types::PrimitiveParams primitiveCmd; + FppTest::Types::CmdStringParams stringCmd; + FppTest::Types::EnumParam enumCmd; + FppTest::Types::ArrayParam arrayCmd; + FppTest::Types::StructParam structCmd; + +}; + + +#endif diff --git a/FppTest/component/passive/passive.fpp b/FppTest/component/passive/passive.fpp new file mode 100644 index 0000000000..70e15618b8 --- /dev/null +++ b/FppTest/component/passive/passive.fpp @@ -0,0 +1,17 @@ +#include "../include/fpp_types.fppi" +#include "../include/port_types.fppi" +#include "../include/port_index_enums.fppi" + +@ A passive component +passive component PassiveTest { + + include "../include/typed_ports.fppi" + include "../include/serial_ports.fppi" + include "../include/special_ports.fppi" + + include "../include/commands.fppi" + include "../include/events.fppi" + include "../include/telemetry.fppi" + include "../include/params.fppi" + +} diff --git a/FppTest/component/passive/test/ut/Tester.cpp b/FppTest/component/passive/test/ut/Tester.cpp new file mode 100644 index 0000000000..ac62fca4b1 --- /dev/null +++ b/FppTest/component/passive/test/ut/Tester.cpp @@ -0,0 +1,119 @@ +// ====================================================================== +// \title PassiveTest/test/ut/Tester.cpp +// \author tiffany +// \brief cpp file for PassiveTest test harness implementation class +// ====================================================================== + +#include "STest/Pick/Pick.hpp" +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() + : PassiveTestGTestBase("Tester", Tester::MAX_HISTORY_SIZE), + component("PassiveTest"), + primitiveBuf(primitiveData, sizeof(primitiveData)), + stringBuf(stringData, sizeof(stringData)), + enumBuf(enumData, sizeof(enumData)), + arrayBuf(arrayData, sizeof(arrayData)), + structBuf(structData, sizeof(structData)), + serialBuf(serialData, sizeof(serialData)), + time(STest::Pick::any(), STest::Pick::any()) { + this->initComponents(); + this->connectPorts(); +} + +Tester ::~Tester() {} + +void Tester ::initComponents() { + this->init(); + this->component.init(Tester::TEST_INSTANCE_ID); +} + +Fw::ParamValid Tester ::from_prmGetIn_handler(const NATIVE_INT_TYPE portNum, FwPrmIdType id, Fw::ParamBuffer& val) { + val.resetSer(); + + Fw::SerializeStatus status; + U32 id_base = component.getIdBase(); + + FW_ASSERT(id >= id_base); + + switch (id - id_base) { + case PassiveTestComponentBase::PARAMID_PARAMBOOL: + status = val.serialize(boolPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMU32: + status = val.serialize(u32Prm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMSTRING: + status = val.serialize(stringPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMENUM: + status = val.serialize(enumPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMARRAY: + status = val.serialize(arrayPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMSTRUCT: + status = val.serialize(structPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + } + + this->pushFromPortEntry_prmGetIn(id, val); + + return prmValid; +} + +void Tester ::from_prmSetIn_handler(const NATIVE_INT_TYPE portNum, FwPrmIdType id, Fw::ParamBuffer& val) { + Fw::SerializeStatus status; + U32 id_base = component.getIdBase(); + + FW_ASSERT(id >= id_base); + + switch (id - id_base) { + case PassiveTestComponentBase::PARAMID_PARAMBOOL: + status = val.deserialize(boolPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMU32: + status = val.deserialize(u32Prm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMSTRING: + status = val.deserialize(stringPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMENUM: + status = val.deserialize(enumPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMARRAY: + status = val.deserialize(arrayPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case PassiveTestComponentBase::PARAMID_PARAMSTRUCT: + status = val.deserialize(structPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + } + + this->pushFromPortEntry_prmSetIn(id, val); +} diff --git a/FppTest/component/passive/test/ut/Tester.hpp b/FppTest/component/passive/test/ut/Tester.hpp new file mode 100644 index 0000000000..74e3479d25 --- /dev/null +++ b/FppTest/component/passive/test/ut/Tester.hpp @@ -0,0 +1,287 @@ +// ====================================================================== +// \title PassiveTest/test/ut/Tester.hpp +// \author tiffany +// \brief hpp file for PassiveTest test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "FppTest/component/active/SerialPortIndexEnumAc.hpp" +#include "FppTest/component/active/TypedPortIndexEnumAc.hpp" +#include "FppTest/component/passive/PassiveTest.hpp" +#include "FppTest/component/tests/CmdTests.hpp" +#include "FppTest/component/tests/EventTests.hpp" +#include "FppTest/component/tests/ParamTests.hpp" +#include "FppTest/component/tests/PortTests.hpp" +#include "FppTest/component/tests/TlmTests.hpp" +#include "FppTest/component/types/FormalParamTypes.hpp" +#include "GTestBase.hpp" + +class Tester : public PassiveTestGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 100; + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + // Queue depth supplied to component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; + + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + PORT_TEST_DECLS + + CMD_TEST_DECLS + + EVENT_TEST_DECLS + + TLM_TEST_DECLS + + void testParam(); + + PARAM_CMD_TEST_DECLS + + void testTime(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_arrayArgsOut + //! + void from_arrayArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamArray& a, /*!< + An array + */ + FormalParamArray& aRef /*!< + An array ref + */ + ); + + //! Handler for from_arrayReturnOut + //! + FormalParamArray from_arrayReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamArray& a, /*!< + An array + */ + FormalParamArray& aRef /*!< + An array ref + */ + ); + + //! Handler for from_enumArgsOut + //! + void from_enumArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamEnum& en, /*!< + An enum + */ + FormalParamEnum& enRef /*!< + An enum ref + */ + ); + + //! Handler for from_enumReturnOut + //! + FormalParamEnum from_enumReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamEnum& en, /*!< + An enum + */ + FormalParamEnum& enRef /*!< + An enum ref + */ + ); + + //! Handler for from_noArgsOut + //! + void from_noArgsOut_handler(const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_noArgsReturnOut + //! + bool from_noArgsReturnOut_handler(const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_primitiveArgsOut + //! + void from_primitiveArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef); + + //! Handler for from_primitiveReturnOut + //! + U32 from_primitiveReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef); + + //! Handler for from_prmGetIn + //! + Fw::ParamValid from_prmGetIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwPrmIdType id, /*!< + Parameter ID + */ + Fw::ParamBuffer& val /*!< + Buffer containing serialized parameter value + */ + ); + + //! Handler for from_prmGetIn + //! + void from_prmSetIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwPrmIdType id, /*!< + Parameter ID + */ + Fw::ParamBuffer& val /*!< + Buffer containing serialized parameter value + */ + ); + + //! Handler for from_stringArgsOut + //! + void from_stringArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const str80String& str80, /*!< + A string of size 80 + */ + str80RefString& str80Ref, + const str100String& str100, /*!< + A string of size 100 + */ + str100RefString& str100Ref); + + //! Handler for from_structArgsOut + //! + void from_structArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamStruct& s, /*!< + A struct + */ + FormalParamStruct& sRef /*!< + A struct ref + */ + ); + + //! Handler for from_structReturnOut + //! + FormalParamStruct from_structReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamStruct& s, /*!< + A struct + */ + FormalParamStruct& sRef /*!< + A struct ref + */ + ); + + void cmdResponseIn(const FwOpcodeType opCode, const U32 cmdSeq, const Fw::CmdResponse response); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handlers for serial from ports + // ---------------------------------------------------------------------- + + //! Handler for from_serialOut + //! + void from_serialOut_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase& Buffer /*!< The serialization buffer*/ + ); + + public: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Connect prmSetIn port + void connectPrmSetIn(); + + //! Connect timeGetOut port + void connectTimeGetOut(); + + //! Connect serial ports to special ports + void connectSpecialPortsSerial(); + + //! Set prmValid + void setPrmValid(Fw::ParamValid valid); + + //! Initialize components + //! + void initComponents(); + + //! Check successful status of a serial port invocation + void checkSerializeStatusSuccess(); + + //! Check unsuccessful status of a serial port invocation + void checkSerializeStatusBufferEmpty(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + PassiveTest component; + + // Values returned by typed output ports + FppTest::Types::BoolType noParamReturnVal; + FppTest::Types::U32Type primitiveReturnVal; + FppTest::Types::EnumType enumReturnVal; + FppTest::Types::ArrayType arrayReturnVal; + FppTest::Types::StructType structReturnVal; + + // Buffers from serial output ports; + U8 primitiveData[InputPrimitiveArgsPort::SERIALIZED_SIZE]; + U8 stringData[InputStringArgsPort::SERIALIZED_SIZE]; + U8 enumData[InputEnumArgsPort::SERIALIZED_SIZE]; + U8 arrayData[InputArrayArgsPort::SERIALIZED_SIZE]; + U8 structData[InputStructArgsPort::SERIALIZED_SIZE]; + U8 serialData[SERIAL_ARGS_BUFFER_CAPACITY]; + + Fw::SerialBuffer primitiveBuf; + Fw::SerialBuffer stringBuf; + Fw::SerialBuffer enumBuf; + Fw::SerialBuffer arrayBuf; + Fw::SerialBuffer structBuf; + Fw::SerialBuffer serialBuf; + + // Command test values + Fw::CmdResponse cmdResp; + + // Parameter test values + FppTest::Types::BoolParam boolPrm; + FppTest::Types::U32Param u32Prm; + FppTest::Types::PrmStringParam stringPrm; + FppTest::Types::EnumParam enumPrm; + FppTest::Types::ArrayParam arrayPrm; + FppTest::Types::StructParam structPrm; + Fw::ParamValid prmValid; + + // Time test values + Fw::Time time; +}; + +#endif diff --git a/FppTest/component/queued/CMakeLists.txt b/FppTest/component/queued/CMakeLists.txt new file mode 100644 index 0000000000..35e598d802 --- /dev/null +++ b/FppTest/component/queued/CMakeLists.txt @@ -0,0 +1,51 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/queued.fpp" + "${CMAKE_CURRENT_LIST_DIR}/QueuedTest.cpp" +) + +register_fprime_module() + +# Sets MODULE_NAME to unique name based on path +get_module_name(${CMAKE_CURRENT_LIST_DIR}) + +# Exclude test module from all build +set_target_properties( + ${MODULE_NAME} + PROPERTIES + EXCLUDE_FROM_ALL TRUE +) + +# Declare dependencies on test modules +set(UT_MOD_DEPS + Fw/Test + STest +) + +# Add unit test directory +# UT_SOURCE_FILES: Sources for unit test +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/queued.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TestMain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/Tests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TesterHandlers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TesterHelpers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/PortTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/CmdTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/EventTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TlmTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/ParamTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/TimeTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/InternalInterfaceTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncTesterHelpers.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncPortTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../tests/AsyncCmdTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../types/FormalParamTypes.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../../utils/Utils.cpp" +) +register_fprime_ut() diff --git a/FppTest/component/queued/QueuedTest.cpp b/FppTest/component/queued/QueuedTest.cpp new file mode 100644 index 0000000000..682f200914 --- /dev/null +++ b/FppTest/component/queued/QueuedTest.cpp @@ -0,0 +1,698 @@ +// ====================================================================== +// \title QueuedTest.cpp +// \author tiffany +// \brief cpp file for QueuedTest component implementation class +// ====================================================================== + + +#include "QueuedTest.hpp" +#include + +#include "FppTest/component/active/SerialPortIndexEnumAc.hpp" + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + QueuedTest :: + QueuedTest( + const char *const compName + ) : QueuedTestComponentBase(compName) + { + + } + + void QueuedTest :: + init( + NATIVE_INT_TYPE queueDepth, + NATIVE_INT_TYPE msgSize, + NATIVE_INT_TYPE instance + ) + { + QueuedTestComponentBase::init(queueDepth, msgSize, instance); + } + + QueuedTest :: + ~QueuedTest() + { + + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + void QueuedTest :: + arrayArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + void QueuedTest :: + enumArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + void QueuedTest :: + noArgsAsync_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + void QueuedTest :: + primitiveArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void QueuedTest :: + structArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + void QueuedTest :: + stringArgsAsync_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void QueuedTest :: + arrayArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + void QueuedTest :: + arrayArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + FormalParamArray QueuedTest :: + arrayReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + return this->arrayReturnOut_out(portNum, a, aRef); + } + + FormalParamArray QueuedTest :: + arrayReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamArray &a, + FormalParamArray &aRef + ) + { + return this->arrayReturnOut_out(portNum, a, aRef); + } + + void QueuedTest :: + cmdOut_handler( + NATIVE_INT_TYPE portNum, + FwOpcodeType opCode, + U32 cmdSeq, + Fw::CmdArgBuffer& args + ) + { + } + + void QueuedTest :: + enumArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + void QueuedTest :: + enumArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + this->enumArgsOut_out(portNum, en, enRef); + } + + FormalParamEnum QueuedTest :: + enumReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + return this->enumReturnOut_out(portNum, en, enRef); + } + + FormalParamEnum QueuedTest :: + enumReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamEnum &en, + FormalParamEnum &enRef + ) + { + return this->enumReturnOut_out(portNum, en, enRef); + } + + void QueuedTest :: + noArgsGuarded_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + bool QueuedTest :: + noArgsReturnGuarded_handler( + const NATIVE_INT_TYPE portNum + ) + { + return this->noArgsReturnOut_out(portNum); + } + + bool QueuedTest :: + noArgsReturnSync_handler( + const NATIVE_INT_TYPE portNum + ) + { + return this->noArgsReturnOut_out(portNum); + } + + void QueuedTest :: + noArgsSync_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + void QueuedTest :: + primitiveArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void QueuedTest :: + primitiveArgsSync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + U32 QueuedTest :: + primitiveReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + return this->primitiveReturnOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + U32 QueuedTest :: + primitiveReturnSync_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + return this->primitiveReturnOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void QueuedTest :: + stringArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void QueuedTest :: + stringArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void QueuedTest :: + structArgsGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + + void QueuedTest :: + structArgsSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + + FormalParamStruct QueuedTest :: + structReturnGuarded_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + return this->structReturnOut_out(portNum, s, sRef); + } + + FormalParamStruct QueuedTest :: + structReturnSync_handler( + const NATIVE_INT_TYPE portNum, + const FormalParamStruct &s, + FormalParamStruct &sRef + ) + { + return this->structReturnOut_out(portNum, s, sRef); + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + void QueuedTest :: + serialAsync_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + void QueuedTest :: + serialAsyncAssert_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(SerialPortIndex::ENUM, Buffer); + } + + void QueuedTest :: + serialAsyncBlockPriority_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(SerialPortIndex::ARRAY, Buffer); + } + + void QueuedTest :: + serialAsyncDropPriority_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(SerialPortIndex::STRUCT, Buffer); + } + + void QueuedTest :: + serialGuarded_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + void QueuedTest :: + serialSync_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + + // ---------------------------------------------------------------------- + // Command handler implementations + // ---------------------------------------------------------------------- + + void QueuedTest :: + CMD_ASYNC_NO_ARGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) + { + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_ASYNC_PRIMITIVE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + U32 u32_1, + U32 u32_2, + F32 f32_1, + F32 f32_2, + bool b1, + bool b2 + ) + { + this->primitiveCmd.args.val1 = u32_1; + this->primitiveCmd.args.val2 = u32_2; + this->primitiveCmd.args.val3 = f32_1; + this->primitiveCmd.args.val4 = f32_2; + this->primitiveCmd.args.val5 = b1; + this->primitiveCmd.args.val6 = b2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_ASYNC_STRINGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + const Fw::CmdStringArg& str1, + const Fw::CmdStringArg& str2 + ) + { + this->stringCmd.args.val1 = str1; + this->stringCmd.args.val2 = str2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_ASYNC_ENUM_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamEnum en + ) + { + this->enumCmd.args.val = en; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_ASYNC_ARRAY_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamArray arr + ) + { + this->arrayCmd.args.val = arr; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_ASYNC_STRUCT_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamStruct str + ) + { + this->structCmd.args.val = str; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_NO_ARGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq + ) + { + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_PRIMITIVE_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + U32 u32_1, + U32 u32_2, + F32 f32_1, + F32 f32_2, + bool b1, + bool b2 + ) + { + this->primitiveCmd.args.val1 = u32_1; + this->primitiveCmd.args.val2 = u32_2; + this->primitiveCmd.args.val3 = f32_1; + this->primitiveCmd.args.val4 = f32_2; + this->primitiveCmd.args.val5 = b1; + this->primitiveCmd.args.val6 = b2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_STRINGS_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + const Fw::CmdStringArg& str1, + const Fw::CmdStringArg& str2 + ) + { + this->stringCmd.args.val1 = str1; + this->stringCmd.args.val2 = str2; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_ENUM_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamEnum en + ) + { + this->enumCmd.args.val = en; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_ARRAY_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamArray arr + ) + { + this->arrayCmd.args.val = arr; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void QueuedTest :: + CMD_STRUCT_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + FormalParamStruct str + ) + { + this->structCmd.args.val = str; + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + // ---------------------------------------------------------------------- + // Internal interface handlers + // ---------------------------------------------------------------------- + + //! Internal interface handler for internalArray + void QueuedTest :: + internalArray_internalInterfaceHandler( + const FormalParamArray& arr //!< An array + ) + { + this->arrayInterface.args.val = arr; + } + + //! Internal interface handler for internalEnum + void QueuedTest :: + internalEnum_internalInterfaceHandler( + const FormalParamEnum& en //!< An enum + ) + { + this->enumInterface.args.val = en; + } + + //! Internal interface handler for internalNoArgs + void QueuedTest :: + internalNoArgs_internalInterfaceHandler() + { + } + + //! Internal interface handler for internalPrimitive + void QueuedTest :: + internalPrimitive_internalInterfaceHandler( + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ) + { + this->primitiveInterface.args.val1 = u32_1; + this->primitiveInterface.args.val2 = u32_2; + this->primitiveInterface.args.val3 = f32_1; + this->primitiveInterface.args.val4 = f32_2; + this->primitiveInterface.args.val5 = b1; + this->primitiveInterface.args.val6 = b2; + } + + //! Internal interface handler for internalString + void QueuedTest :: + internalString_internalInterfaceHandler( + const Fw::InternalInterfaceString& str1, //!< A string + const Fw::InternalInterfaceString& str2 //!< Another string + ) + { + this->stringInterface.args.val1 = str1; + this->stringInterface.args.val2 = str2; + } + + //! Internal interface handler for internalStruct + void QueuedTest :: + internalStruct_internalInterfaceHandler( + const FormalParamStruct& str //!< A struct + ) + { + this->structInterface.args.val = str; + } + diff --git a/FppTest/component/queued/QueuedTest.hpp b/FppTest/component/queued/QueuedTest.hpp new file mode 100644 index 0000000000..6b3c6ceca9 --- /dev/null +++ b/FppTest/component/queued/QueuedTest.hpp @@ -0,0 +1,469 @@ +// ====================================================================== +// \title QueuedTest.hpp +// \author tiffany +// \brief hpp file for QueuedTest component implementation class +// ====================================================================== + +#ifndef QueuedTest_HPP +#define QueuedTest_HPP + +#include "FppTest/component/queued/QueuedTestComponentAc.hpp" +#include "FppTest/component/types/FormalParamTypes.hpp" + + +class QueuedTest : + public QueuedTestComponentBase +{ + + public: + + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct QueuedTest object + QueuedTest( + const char* const compName //!< The component name + ); + + //! Initialize QueuedTest object + void init( + NATIVE_INT_TYPE queueDepth, //!< The queue depth + NATIVE_INT_TYPE msgSize, //!< The message size + NATIVE_INT_TYPE instance = 0 //!< The instance number + ); + + //! Destroy QueuedTest object + ~QueuedTest(); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for arrayArgsAsync + void arrayArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayArgsGuarded + void arrayArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayArgsSync + void arrayArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayReturnGuarded + FormalParamArray arrayReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for arrayReturnSync + FormalParamArray arrayReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamArray& a, //!< An array + FormalParamArray& aRef //!< An array ref + ); + + //! Handler implementation for cmdOut + void cmdOut_handler( + NATIVE_INT_TYPE portNum, //!< The port number + FwOpcodeType opCode, //!< Command Op Code + U32 cmdSeq, //!< Command Sequence + Fw::CmdArgBuffer& args //!< Buffer containing arguments + ); + + //! Handler implementation for enumArgsAsync + void enumArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumArgsGuarded + void enumArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumArgsSync + void enumArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumReturnGuarded + FormalParamEnum enumReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for enumReturnSync + FormalParamEnum enumReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamEnum& en, //!< An enum + FormalParamEnum& enRef //!< An enum ref + ); + + //! Handler implementation for noArgsAsync + void noArgsAsync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsGuarded + void noArgsGuarded_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsReturnGuarded + bool noArgsReturnGuarded_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsReturnSync + bool noArgsReturnSync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for noArgsSync + void noArgsSync_handler( + NATIVE_INT_TYPE portNum //!< The port number + ); + + //! Handler implementation for primitiveArgsAsync + void primitiveArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveArgsGuarded + void primitiveArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveArgsSync + void primitiveArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveReturnGuarded + U32 primitiveReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for primitiveReturnSync + U32 primitiveReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef + ); + + //! Handler implementation for stringArgsAsync + void stringArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for stringArgsGuarded + void stringArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for stringArgsSync + void stringArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const StringArgsPortStrings::StringSize80& str80, //!< A string of size 80 + StringArgsPortStrings::StringSize80& str80Ref, + const StringArgsPortStrings::StringSize100& str100, //!< A string of size 100 + StringArgsPortStrings::StringSize100& str100Ref + ); + + //! Handler implementation for structArgsAsync + void structArgsAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structArgsGuarded + void structArgsGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structArgsSync + void structArgsSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structReturnGuarded + FormalParamStruct structReturnGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + //! Handler implementation for structReturnSync + FormalParamStruct structReturnSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + const FormalParamStruct& s, //!< A struct + FormalParamStruct& sRef //!< A struct ref + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for serialAsync + void serialAsync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialAsyncAssert + void serialAsyncAssert_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialAsyncBlockPriority + void serialAsyncBlockPriority_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialAsyncDropPriority + void serialAsyncDropPriority_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialGuarded + void serialGuarded_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + //! Handler implementation for serialSync + void serialSync_handler( + NATIVE_INT_TYPE portNum, //!< The port number + Fw::SerializeBufferBase& buffer //!< The serialization buffer + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for commands + // ---------------------------------------------------------------------- + + //! Handler implementation for command CMD_NO_ARGS + void CMD_NO_ARGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ); + + //! Handler implementation for command CMD_PRIMITIVE + void CMD_PRIMITIVE_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ); + + //! Handler implementation for command CMD_STRINGS + void CMD_STRINGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + const Fw::CmdStringArg& str1, //!< A string + const Fw::CmdStringArg& str2 //!< Another string + ); + + //! Handler implementation for command CMD_ENUM + void CMD_ENUM_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamEnum en //!< An enum + ); + + //! Handler implementation for command CMD_ARRAY + void CMD_ARRAY_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamArray arr //!< An array + ); + + //! Handler implementation for command CMD_STRUCT + void CMD_STRUCT_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamStruct str //!< A struct + ); + + //! Handler implementation for command CMD_ASYNC_NO_ARGS + void CMD_ASYNC_NO_ARGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ); + + //! Handler implementation for command CMD_ASYNC_PRIMITIVE + void CMD_ASYNC_PRIMITIVE_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ); + + //! Handler implementation for command CMD_ASYNC_STRINGS + void CMD_ASYNC_STRINGS_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + const Fw::CmdStringArg& str1, //!< A string + const Fw::CmdStringArg& str2 //!< Another string + ); + + //! Handler implementation for command CMD_ASYNC_ENUM + void CMD_ASYNC_ENUM_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamEnum en //!< An enum + ); + + //! Handler implementation for command CMD_ASYNC_ARRAY + void CMD_ASYNC_ARRAY_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamArray arr //!< An array + ); + + //! Handler implementation for command CMD_ASYNC_STRUCT + void CMD_ASYNC_STRUCT_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + FormalParamStruct str //!< A struct + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined internal interfaces + // ---------------------------------------------------------------------- + + //! Handler implementation for internalArray + void internalArray_internalInterfaceHandler( + const FormalParamArray& arr //!< An array + ); + + //! Handler implementation for internalEnum + void internalEnum_internalInterfaceHandler( + const FormalParamEnum& en //!< An enum + ); + + //! Handler implementation for internalNoArgs + void internalNoArgs_internalInterfaceHandler(); + + //! Handler implementation for internalPrimitive + void internalPrimitive_internalInterfaceHandler( + U32 u32_1, //!< A U32 + U32 u32_2, //!< A U32 + F32 f32_1, //!< An F32 + F32 f32_2, //!< An F32 + bool b1, //!< A boolean + bool b2 //!< A boolean + ); + + //! Handler implementation for internalString + void internalString_internalInterfaceHandler( + const Fw::InternalInterfaceString& str1, //!< A string + const Fw::InternalInterfaceString& str2 //!< Another string + ); + + //! Handler implementation for internalStruct + void internalStruct_internalInterfaceHandler( + const FormalParamStruct& str //!< A struct + ); + + public: + + //! Enables checking the serialization status of serial port invocations + Fw::SerializeStatus serializeStatus; + + // Command test values + FppTest::Types::PrimitiveParams primitiveCmd; + FppTest::Types::CmdStringParams stringCmd; + FppTest::Types::EnumParam enumCmd; + FppTest::Types::ArrayParam arrayCmd; + FppTest::Types::StructParam structCmd; + + // Internal interface test values + FppTest::Types::PrimitiveParams primitiveInterface; + FppTest::Types::InternalInterfaceStringParams stringInterface; + FppTest::Types::EnumParam enumInterface; + FppTest::Types::ArrayParam arrayInterface; + FppTest::Types::StructParam structInterface; + +}; + + +#endif diff --git a/FppTest/component/queued/queued.fpp b/FppTest/component/queued/queued.fpp new file mode 100644 index 0000000000..7cc8274a6a --- /dev/null +++ b/FppTest/component/queued/queued.fpp @@ -0,0 +1,17 @@ +@ A queued component +queued component QueuedTest { + + include "../include/typed_ports.fppi" + include "../include/typed_ports_async.fppi" + include "../include/serial_ports.fppi" + include "../include/serial_ports_async.fppi" + include "../include/special_ports.fppi" + include "../include/internal_ports.fppi" + + include "../include/commands.fppi" + include "../include/commands_async.fppi" + include "../include/events.fppi" + include "../include/telemetry.fppi" + include "../include/params.fppi" + +} diff --git a/FppTest/component/queued/test/ut/Tester.cpp b/FppTest/component/queued/test/ut/Tester.cpp new file mode 100644 index 0000000000..808b3de3e2 --- /dev/null +++ b/FppTest/component/queued/test/ut/Tester.cpp @@ -0,0 +1,120 @@ +// ====================================================================== +// \title QueuedTest/test/ut/Tester.cpp +// \author tiffany +// \brief cpp file for QueuedTest test harness implementation class +// ====================================================================== + +#include "STest/Pick/Pick.hpp" +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() + : QueuedTestGTestBase("Tester", Tester::MAX_HISTORY_SIZE), + component("QueuedTest"), + primitiveBuf(primitiveData, sizeof(primitiveData)), + stringBuf(stringData, sizeof(stringData)), + enumBuf(enumData, sizeof(enumData)), + arrayBuf(arrayData, sizeof(arrayData)), + structBuf(structData, sizeof(structData)), + serialBuf(serialData, sizeof(serialData)), + time(STest::Pick::any(), STest::Pick::any()) { + this->initComponents(); + this->connectPorts(); + this->connectAsyncPorts(); +} + +Tester ::~Tester() {} + +void Tester ::initComponents() { + this->init(); + this->component.init(Tester::TEST_INSTANCE_QUEUE_DEPTH, Tester::TEST_INSTANCE_ID); +} + +Fw::ParamValid Tester ::from_prmGetIn_handler(const NATIVE_INT_TYPE portNum, FwPrmIdType id, Fw::ParamBuffer& val) { + val.resetSer(); + + Fw::SerializeStatus status; + U32 id_base = component.getIdBase(); + + FW_ASSERT(id >= id_base); + + switch (id - id_base) { + case QueuedTestComponentBase::PARAMID_PARAMBOOL: + status = val.serialize(boolPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMU32: + status = val.serialize(u32Prm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMSTRING: + status = val.serialize(stringPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMENUM: + status = val.serialize(enumPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMARRAY: + status = val.serialize(arrayPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMSTRUCT: + status = val.serialize(structPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + } + + this->pushFromPortEntry_prmGetIn(id, val); + + return prmValid; +} + +void Tester ::from_prmSetIn_handler(const NATIVE_INT_TYPE portNum, FwPrmIdType id, Fw::ParamBuffer& val) { + Fw::SerializeStatus status; + U32 id_base = component.getIdBase(); + + FW_ASSERT(id >= id_base); + + switch (id - id_base) { + case QueuedTestComponentBase::PARAMID_PARAMBOOL: + status = val.deserialize(boolPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMU32: + status = val.deserialize(u32Prm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMSTRING: + status = val.deserialize(stringPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMENUM: + status = val.deserialize(enumPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMARRAY: + status = val.deserialize(arrayPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + + case QueuedTestComponentBase::PARAMID_PARAMSTRUCT: + status = val.deserialize(structPrm.args.val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + break; + } + + this->pushFromPortEntry_prmSetIn(id, val); +} diff --git a/FppTest/component/queued/test/ut/Tester.hpp b/FppTest/component/queued/test/ut/Tester.hpp new file mode 100644 index 0000000000..169952691e --- /dev/null +++ b/FppTest/component/queued/test/ut/Tester.hpp @@ -0,0 +1,297 @@ +// ====================================================================== +// \title QueuedTest/test/ut/Tester.hpp +// \author tiffany +// \brief hpp file for QueuedTest test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "FppTest/component/active/SerialPortIndexEnumAc.hpp" +#include "FppTest/component/active/TypedPortIndexEnumAc.hpp" +#include "FppTest/component/queued/QueuedTest.hpp" +#include "FppTest/component/tests/CmdTests.hpp" +#include "FppTest/component/tests/EventTests.hpp" +#include "FppTest/component/tests/InternalInterfaceTests.hpp" +#include "FppTest/component/tests/ParamTests.hpp" +#include "FppTest/component/tests/PortTests.hpp" +#include "FppTest/component/tests/TlmTests.hpp" +#include "FppTest/component/types/FormalParamTypes.hpp" +#include "GTestBase.hpp" + +class Tester : public QueuedTestGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 100; + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + // Queue depth supplied to component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; + + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + PORT_TEST_DECLS + PORT_TEST_DECLS_ASYNC + + CMD_TEST_DECLS + CMD_TEST_DECLS_ASYNC + + EVENT_TEST_DECLS + + TLM_TEST_DECLS + + void testParam(); + PARAM_CMD_TEST_DECLS + + INTERNAL_INT_TEST_DECLS + + void testTime(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_arrayArgsOut + //! + void from_arrayArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamArray& a, /*!< + An array + */ + FormalParamArray& aRef /*!< + An array ref + */ + ); + + //! Handler for from_arrayReturnOut + //! + FormalParamArray from_arrayReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamArray& a, /*!< + An array + */ + FormalParamArray& aRef /*!< + An array ref + */ + ); + + //! Handler for from_enumArgsOut + //! + void from_enumArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamEnum& en, /*!< + An enum + */ + FormalParamEnum& enRef /*!< + An enum ref + */ + ); + + //! Handler for from_enumReturnOut + //! + FormalParamEnum from_enumReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamEnum& en, /*!< + An enum + */ + FormalParamEnum& enRef /*!< + An enum ref + */ + ); + + //! Handler for from_noArgsOut + //! + void from_noArgsOut_handler(const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_noArgsReturnOut + //! + bool from_noArgsReturnOut_handler(const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_primitiveArgsOut + //! + void from_primitiveArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef); + + //! Handler for from_primitiveReturnOut + //! + U32 from_primitiveReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef); + + //! Handler for from_prmGetIn + //! + Fw::ParamValid from_prmGetIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwPrmIdType id, /*!< + Parameter ID + */ + Fw::ParamBuffer& val /*!< + Buffer containing serialized parameter value + */ + ); + + //! Handler for from_prmGetIn + //! + void from_prmSetIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwPrmIdType id, /*!< + Parameter ID + */ + Fw::ParamBuffer& val /*!< + Buffer containing serialized parameter value + */ + ); + + //! Handler for from_stringArgsOut + //! + void from_stringArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const str80String& str80, /*!< + A string of size 80 + */ + str80RefString& str80Ref, + const str100String& str100, /*!< + A string of size 100 + */ + str100RefString& str100Ref); + + //! Handler for from_structArgsOut + //! + void from_structArgsOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamStruct& s, /*!< + A struct + */ + FormalParamStruct& sRef /*!< + A struct ref + */ + ); + + //! Handler for from_structReturnOut + //! + FormalParamStruct from_structReturnOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const FormalParamStruct& s, /*!< + A struct + */ + FormalParamStruct& sRef /*!< + A struct ref + */ + ); + + void cmdResponseIn(const FwOpcodeType opCode, const U32 cmdSeq, const Fw::CmdResponse response); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handlers for serial from ports + // ---------------------------------------------------------------------- + + //! Handler for from_serialOut + //! + void from_serialOut_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase& Buffer /*!< The serialization buffer*/ + ); + + public: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Connect async ports + void connectAsyncPorts(); + + //! Connect prmSetIn port + void connectPrmSetIn(); + + //! Connect timeGetOut port + void connectTimeGetOut(); + + //! Connect serial ports to special ports + void connectSpecialPortsSerial(); + + //! Set prmValid + void setPrmValid(Fw::ParamValid valid); + + //! Call doDispatch() on component under test + Fw::QueuedComponentBase::MsgDispatchStatus doDispatch(); + + //! Initialize components + //! + void initComponents(); + + //! Check successful status of a serial port invocation + void checkSerializeStatusSuccess(); + + //! Check unsuccessful status of a serial port invocation + void checkSerializeStatusBufferEmpty(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + QueuedTest component; + + // Values returned by typed output ports + FppTest::Types::BoolType noParamReturnVal; + FppTest::Types::U32Type primitiveReturnVal; + FppTest::Types::EnumType enumReturnVal; + FppTest::Types::ArrayType arrayReturnVal; + FppTest::Types::StructType structReturnVal; + + // Buffers from serial output ports; + U8 primitiveData[InputPrimitiveArgsPort::SERIALIZED_SIZE]; + U8 stringData[InputStringArgsPort::SERIALIZED_SIZE]; + U8 enumData[InputEnumArgsPort::SERIALIZED_SIZE]; + U8 arrayData[InputArrayArgsPort::SERIALIZED_SIZE]; + U8 structData[InputStructArgsPort::SERIALIZED_SIZE]; + U8 serialData[SERIAL_ARGS_BUFFER_CAPACITY]; + + Fw::SerialBuffer primitiveBuf; + Fw::SerialBuffer stringBuf; + Fw::SerialBuffer enumBuf; + Fw::SerialBuffer arrayBuf; + Fw::SerialBuffer structBuf; + Fw::SerialBuffer serialBuf; + + // Command test values + Fw::CmdResponse cmdResp; + + // Parameter test values + FppTest::Types::BoolParam boolPrm; + FppTest::Types::U32Param u32Prm; + FppTest::Types::PrmStringParam stringPrm; + FppTest::Types::EnumParam enumPrm; + FppTest::Types::ArrayParam arrayPrm; + FppTest::Types::StructParam structPrm; + Fw::ParamValid prmValid; + + // Time test values + Fw::Time time; +}; + +#endif diff --git a/FppTest/component/queued/test/ut/TesterHelpers.cpp b/FppTest/component/queued/test/ut/TesterHelpers.cpp new file mode 100644 index 0000000000..c28e39e7ad --- /dev/null +++ b/FppTest/component/queued/test/ut/TesterHelpers.cpp @@ -0,0 +1,228 @@ +// ====================================================================== +// \title QueuedTest/test/ut/TesterHelpers.cpp +// \author Auto-generated +// \brief cpp file for QueuedTest component test harness base class +// +// NOTE: this file was automatically generated +// +// ====================================================================== +#include "Tester.hpp" + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void Tester ::connectPorts() { + // arrayArgsAsyncBlockPriority + this->connect_to_arrayArgsAsyncBlockPriority(0, this->component.get_arrayArgsAsyncBlockPriority_InputPort(0)); + + // arrayArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_arrayArgsGuarded(i, this->component.get_arrayArgsGuarded_InputPort(i)); + } + + // arrayArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_arrayArgsSync(i, this->component.get_arrayArgsSync_InputPort(i)); + } + + // arrayReturnGuarded + this->connect_to_arrayReturnGuarded(0, this->component.get_arrayReturnGuarded_InputPort(0)); + + // arrayReturnSync + this->connect_to_arrayReturnSync(0, this->component.get_arrayReturnSync_InputPort(0)); + + // cmdIn + this->connect_to_cmdIn(0, this->component.get_cmdIn_InputPort(0)); + + // enumArgsAsyncAssert + this->connect_to_enumArgsAsyncAssert(0, this->component.get_enumArgsAsyncAssert_InputPort(0)); + + // enumArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_enumArgsGuarded(i, this->component.get_enumArgsGuarded_InputPort(i)); + } + + // enumArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_enumArgsSync(i, this->component.get_enumArgsSync_InputPort(i)); + } + + // enumReturnGuarded + this->connect_to_enumReturnGuarded(0, this->component.get_enumReturnGuarded_InputPort(0)); + + // enumReturnSync + this->connect_to_enumReturnSync(0, this->component.get_enumReturnSync_InputPort(0)); + + // noArgsAsync + this->connect_to_noArgsAsync(0, this->component.get_noArgsAsync_InputPort(0)); + + // noArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_noArgsGuarded(i, this->component.get_noArgsGuarded_InputPort(i)); + } + + // noArgsReturnGuarded + this->connect_to_noArgsReturnGuarded(0, this->component.get_noArgsReturnGuarded_InputPort(0)); + + // noArgsReturnSync + this->connect_to_noArgsReturnSync(0, this->component.get_noArgsReturnSync_InputPort(0)); + + // noArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_noArgsSync(i, this->component.get_noArgsSync_InputPort(i)); + } + + // primitiveArgsAsync + this->connect_to_primitiveArgsAsync(0, this->component.get_primitiveArgsAsync_InputPort(0)); + + // primitiveArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_primitiveArgsGuarded(i, this->component.get_primitiveArgsGuarded_InputPort(i)); + } + + // primitiveArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_primitiveArgsSync(i, this->component.get_primitiveArgsSync_InputPort(i)); + } + + // primitiveReturnGuarded + this->connect_to_primitiveReturnGuarded(0, this->component.get_primitiveReturnGuarded_InputPort(0)); + + // primitiveReturnSync + this->connect_to_primitiveReturnSync(0, this->component.get_primitiveReturnSync_InputPort(0)); + + // stringArgsAsync + this->connect_to_stringArgsAsync(0, this->component.get_stringArgsAsync_InputPort(0)); + + // stringArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_stringArgsGuarded(i, this->component.get_stringArgsGuarded_InputPort(i)); + } + + // stringArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_stringArgsSync(i, this->component.get_stringArgsSync_InputPort(i)); + } + + // structArgsAsyncDropPriority + this->connect_to_structArgsAsyncDropPriority(0, this->component.get_structArgsAsyncDropPriority_InputPort(0)); + + // structArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_structArgsGuarded(i, this->component.get_structArgsGuarded_InputPort(i)); + } + + // structArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_structArgsSync(i, this->component.get_structArgsSync_InputPort(i)); + } + + // structReturnGuarded + this->connect_to_structReturnGuarded(0, this->component.get_structReturnGuarded_InputPort(0)); + + // structReturnSync + this->connect_to_structReturnSync(0, this->component.get_structReturnSync_InputPort(0)); + + // arrayArgsOut + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->component.set_arrayArgsOut_OutputPort(i, this->get_from_arrayArgsOut(i)); + } + + // arrayReturnOut + this->component.set_arrayReturnOut_OutputPort(0, this->get_from_arrayReturnOut(0)); + + // cmdRegOut + this->component.set_cmdRegOut_OutputPort(0, this->get_from_cmdRegOut(0)); + + // cmdResponseOut + this->component.set_cmdResponseOut_OutputPort(0, this->get_from_cmdResponseOut(0)); + + // enumArgsOut + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->component.set_enumArgsOut_OutputPort(i, this->get_from_enumArgsOut(i)); + } + + // enumReturnOut + this->component.set_enumReturnOut_OutputPort(0, this->get_from_enumReturnOut(0)); + + // eventOut + this->component.set_eventOut_OutputPort(0, this->get_from_eventOut(0)); + + // noArgsOut + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->component.set_noArgsOut_OutputPort(i, this->get_from_noArgsOut(i)); + } + + // noArgsReturnOut + this->component.set_noArgsReturnOut_OutputPort(0, this->get_from_noArgsReturnOut(0)); + + // primitiveArgsOut + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->component.set_primitiveArgsOut_OutputPort(i, this->get_from_primitiveArgsOut(i)); + } + + // primitiveReturnOut + this->component.set_primitiveReturnOut_OutputPort(0, this->get_from_primitiveReturnOut(0)); + + // prmGetOut + this->component.set_prmGetOut_OutputPort(0, this->get_from_prmGetOut(0)); + + // prmSetOut + this->component.set_prmSetOut_OutputPort(0, this->get_from_prmSetOut(0)); + + // stringArgsOut + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->component.set_stringArgsOut_OutputPort(i, this->get_from_stringArgsOut(i)); + } + + // structArgsOut + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->component.set_structArgsOut_OutputPort(i, this->get_from_structArgsOut(i)); + } + + // structReturnOut + this->component.set_structReturnOut_OutputPort(0, this->get_from_structReturnOut(0)); + + // textEventOut + this->component.set_textEventOut_OutputPort(0, this->get_from_textEventOut(0)); + + // timeGetOut + this->component.set_timeGetOut_OutputPort(0, this->get_from_timeGetOut(0)); + + // tlmOut + this->component.set_tlmOut_OutputPort(0, this->get_from_tlmOut(0)); + + // ---------------------------------------------------------------------- + // Connect serial output ports + // ---------------------------------------------------------------------- + for (NATIVE_INT_TYPE i = 0; i < 5; ++i) { + this->component.set_serialOut_OutputPort(i, this->get_from_serialOut(i)); + } + + // ---------------------------------------------------------------------- + // Connect serial input ports + // ---------------------------------------------------------------------- + // serialAsync + this->connect_to_serialAsync(0, this->component.get_serialAsync_InputPort(0)); + + // serialAsyncAssert + this->connect_to_serialAsyncAssert(0, this->component.get_serialAsyncAssert_InputPort(0)); + + // serialAsyncBlockPriority + this->connect_to_serialAsyncBlockPriority(0, this->component.get_serialAsyncBlockPriority_InputPort(0)); + + // serialAsyncDropPriority + this->connect_to_serialAsyncDropPriority(0, this->component.get_serialAsyncDropPriority_InputPort(0)); + + // serialGuarded + this->connect_to_serialGuarded(0, this->component.get_serialGuarded_InputPort(0)); + + // serialSync + this->connect_to_serialSync(0, this->component.get_serialSync_InputPort(0)); +} + +void Tester ::initComponents() { + this->init(); + this->component.init(Tester::TEST_INSTANCE_QUEUE_DEPTH, Tester::TEST_INSTANCE_ID); +} diff --git a/FppTest/component/tests/AsyncCmdTests.cpp b/FppTest/component/tests/AsyncCmdTests.cpp new file mode 100644 index 0000000000..02902b7657 --- /dev/null +++ b/FppTest/component/tests/AsyncCmdTests.cpp @@ -0,0 +1,18 @@ +// ====================================================================== +// \title AsyncCmdTests.cpp +// \author T. Chieu +// \brief cpp file for async command tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "CmdTests.hpp" + +#include "Fw/Cmd/CmdArgBuffer.hpp" + +CMD_TEST_INVOKE_DEFS_ASYNC +CMD_TEST_DEFS(Async) diff --git a/FppTest/component/tests/AsyncPortTests.cpp b/FppTest/component/tests/AsyncPortTests.cpp new file mode 100644 index 0000000000..e16048c9a9 --- /dev/null +++ b/FppTest/component/tests/AsyncPortTests.cpp @@ -0,0 +1,16 @@ +// ====================================================================== +// \title AsyncPortTests.cpp +// \author T. Chieu +// \brief cpp file for async port tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "PortTests.hpp" +#include "test/ut/Tester.hpp" + +PORT_TEST_DEFS_ASYNC diff --git a/FppTest/component/tests/AsyncTesterHelpers.cpp b/FppTest/component/tests/AsyncTesterHelpers.cpp new file mode 100644 index 0000000000..a396537f7e --- /dev/null +++ b/FppTest/component/tests/AsyncTesterHelpers.cpp @@ -0,0 +1,63 @@ +// ====================================================================== +// \title AsyncTesterHelpers.cpp +// \author T. Chieu +// \brief cpp file for async tester helper functions +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +void Tester ::connectAsyncPorts() { + // arrayArgsAsync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_arrayArgsAsync(i, this->component.get_arrayArgsAsync_InputPort(i)); + } + + // enumArgsAsync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_enumArgsAsync(i, this->component.get_enumArgsAsync_InputPort(i)); + } + + // noArgsAsync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_noArgsAsync(i, this->component.get_noArgsAsync_InputPort(i)); + } + + // primitiveArgsAsync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_primitiveArgsAsync(i, this->component.get_primitiveArgsAsync_InputPort(i)); + } + + // stringArgsAsync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_stringArgsAsync(i, this->component.get_stringArgsAsync_InputPort(i)); + } + + // structArgsAsync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_structArgsAsync(i, this->component.get_structArgsAsync_InputPort(i)); + } + + // serialAsync + for (NATIVE_INT_TYPE i = 0; i < 3; ++i) { + this->connect_to_serialAsync(i, this->component.get_serialAsync_InputPort(i)); + } + + // serialAsyncAssert + this->connect_to_serialAsyncAssert(0, this->component.get_serialAsyncAssert_InputPort(0)); + + // serialAsyncBlockPriority + this->connect_to_serialAsyncBlockPriority(0, this->component.get_serialAsyncBlockPriority_InputPort(0)); + + // serialAsyncDropPriority + this->connect_to_serialAsyncDropPriority(0, this->component.get_serialAsyncDropPriority_InputPort(0)); +} + +Fw::QueuedComponentBase::MsgDispatchStatus Tester ::doDispatch() { + return component.doDispatch(); +} diff --git a/FppTest/component/tests/AsyncTests.cpp b/FppTest/component/tests/AsyncTests.cpp new file mode 100644 index 0000000000..ed58ad4d5c --- /dev/null +++ b/FppTest/component/tests/AsyncTests.cpp @@ -0,0 +1,55 @@ +// ====================================================================== +// \title AsyncTests.cpp +// \author T. Chieu +// \brief cpp file for async component tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/component/types/FormalParamTypes.hpp" +#include "FppTest/typed_tests/ComponentTest.hpp" +#include "FppTest/typed_tests/PortTest.hpp" + +// Typed async port tests +using TypedAsyncPortTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, TypedAsyncPortTest, TypedAsyncPortTestImplementations); + +// Serial async port tests +using SerialAsyncPortTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, SerialAsyncPortTest, SerialAsyncPortTestImplementations); + +// Async command tests +using AsyncCommandTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, ComponentAsyncCommandTest, AsyncCommandTestImplementations); + +// Internal interface tests +using InternalInterfaceTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, ComponentInternalInterfaceTest, InternalInterfaceTestImplementations); diff --git a/FppTest/component/tests/CmdTests.cpp b/FppTest/component/tests/CmdTests.cpp new file mode 100644 index 0000000000..dc3343b773 --- /dev/null +++ b/FppTest/component/tests/CmdTests.cpp @@ -0,0 +1,18 @@ +// ====================================================================== +// \title CmdTests.cpp +// \author T. Chieu +// \brief cpp file for command tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "CmdTests.hpp" + +#include "Fw/Cmd/CmdArgBuffer.hpp" + +CMD_TEST_INVOKE_DEFS +CMD_TEST_DEFS() diff --git a/FppTest/component/tests/CmdTests.hpp b/FppTest/component/tests/CmdTests.hpp new file mode 100644 index 0000000000..2dc191842e --- /dev/null +++ b/FppTest/component/tests/CmdTests.hpp @@ -0,0 +1,319 @@ +// ====================================================================== +// \title CmdTests.hpp +// \author T. Chieu +// \brief hpp file for command tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Command test declarations +// ---------------------------------------------------------------------- + +#define CMD_TEST_INVOKE_DECL(TYPE) void invoke##TYPE##Command(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf); + +#define CMD_TEST_INVOKE_DECLS \ + CMD_TEST_INVOKE_DECL(NoArgs) \ + CMD_TEST_INVOKE_DECL(Primitive) \ + CMD_TEST_INVOKE_DECL(String) \ + CMD_TEST_INVOKE_DECL(Enum) \ + CMD_TEST_INVOKE_DECL(Array) \ + CMD_TEST_INVOKE_DECL(Struct) + +#define CMD_TEST_INVOKE_DECLS_ASYNC \ + CMD_TEST_INVOKE_DECL(AsyncNoArgs) \ + CMD_TEST_INVOKE_DECL(AsyncPrimitive) \ + CMD_TEST_INVOKE_DECL(AsyncString) \ + CMD_TEST_INVOKE_DECL(AsyncEnum) \ + CMD_TEST_INVOKE_DECL(AsyncArray) \ + CMD_TEST_INVOKE_DECL(AsyncStruct) + +#define CMD_TEST_DECL(TYPE, ASYNC) void test##ASYNC##Command(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE& data); + +#define CMD_TEST_DECLS \ + CMD_TEST_INVOKE_DECLS \ + CMD_TEST_DECL(NoParams, ) \ + CMD_TEST_DECL(PrimitiveParams, ) \ + CMD_TEST_DECL(CmdStringParams, ) \ + CMD_TEST_DECL(EnumParam, ) \ + CMD_TEST_DECL(ArrayParam, ) \ + CMD_TEST_DECL(StructParam, ) + +#define CMD_TEST_DECLS_ASYNC \ + CMD_TEST_INVOKE_DECLS_ASYNC \ + CMD_TEST_DECL(NoParams, Async) \ + CMD_TEST_DECL(PrimitiveParams, Async) \ + CMD_TEST_DECL(CmdStringParams, Async) \ + CMD_TEST_DECL(EnumParam, Async) \ + CMD_TEST_DECL(ArrayParam, Async) \ + CMD_TEST_DECL(StructParam, Async) + +// ---------------------------------------------------------------------- +// Command test definitions +// ---------------------------------------------------------------------- + +#define CMD_TEST_INVOKE_DEFS \ + void Tester ::invokeNoArgsCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_NO_ARGS, 1, buf); \ + } \ + \ + void Tester ::invokePrimitiveCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_PRIMITIVE, 1, buf); \ + } \ + \ + void Tester ::invokeStringCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_STRINGS, 1, buf); \ + } \ + \ + void Tester ::invokeEnumCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ENUM, 1, buf); \ + } \ + \ + void Tester ::invokeArrayCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ARRAY, 1, buf); \ + } \ + \ + void Tester ::invokeStructCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_STRUCT, 1, buf); \ + } + +#define CMD_TEST_INVOKE_DEFS_ASYNC \ + void Tester ::invokeAsyncNoArgsCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + Fw::QueuedComponentBase::MsgDispatchStatus status; \ + \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ASYNC_NO_ARGS, 1, buf); \ + status = this->doDispatch(); \ + \ + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); \ + } \ + \ + void Tester ::invokeAsyncPrimitiveCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + Fw::QueuedComponentBase::MsgDispatchStatus status; \ + \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ASYNC_PRIMITIVE, 1, buf); \ + status = this->doDispatch(); \ + \ + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); \ + } \ + \ + void Tester ::invokeAsyncStringCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + Fw::QueuedComponentBase::MsgDispatchStatus status; \ + \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ASYNC_STRINGS, 1, buf); \ + status = this->doDispatch(); \ + \ + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); \ + } \ + \ + void Tester ::invokeAsyncEnumCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + Fw::QueuedComponentBase::MsgDispatchStatus status; \ + \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ASYNC_ENUM, 1, buf); \ + status = this->doDispatch(); \ + \ + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); \ + } \ + \ + void Tester ::invokeAsyncArrayCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + Fw::QueuedComponentBase::MsgDispatchStatus status; \ + \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ASYNC_ARRAY, 1, buf); \ + status = this->doDispatch(); \ + \ + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); \ + } \ + \ + void Tester ::invokeAsyncStructCommand(NATIVE_INT_TYPE portNum, Fw::CmdArgBuffer& buf) { \ + Fw::QueuedComponentBase::MsgDispatchStatus status; \ + \ + this->invoke_to_cmdOut(portNum, component.OPCODE_CMD_ASYNC_STRUCT, 1, buf); \ + status = this->doDispatch(); \ + \ + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); \ + } + +#define CMD_TEST_DEFS(ASYNC) \ + void Tester ::test##ASYNC##Command(NATIVE_INT_TYPE portNum, FppTest::Types::NoParams& data) { \ + ASSERT_TRUE(component.isConnected_cmdRegOut_OutputPort(portNum)); \ + ASSERT_TRUE(component.isConnected_cmdResponseOut_OutputPort(portNum)); \ + \ + component.regCommands(); \ + \ + Fw::CmdArgBuffer buf; \ + \ + /* Test success */ \ + this->invoke##ASYNC##NoArgsCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); \ + \ + /* Test too many arguments */ \ + buf.serialize(0); \ + this->invoke##ASYNC##NoArgsCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + } \ + \ + void Tester ::test##ASYNC##Command(NATIVE_INT_TYPE portNum, FppTest::Types::PrimitiveParams& data) { \ + ASSERT_TRUE(component.isConnected_cmdRegOut_OutputPort(portNum)); \ + ASSERT_TRUE(component.isConnected_cmdResponseOut_OutputPort(portNum)); \ + \ + component.regCommands(); \ + \ + Fw::CmdArgBuffer buf; \ + \ + /* Test incorrect deserialization of first argument */ \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test incorrect deserialization of second argument */ \ + buf.serialize(data.args.val1); \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test incorrect deserialization of third argument */ \ + buf.serialize(data.args.val2); \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test incorrect deserialization of fourth argument */ \ + buf.serialize(data.args.val3); \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test incorrect deserialization of fifth argument */ \ + buf.serialize(data.args.val4); \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test incorrect deserialization of sixth argument */ \ + buf.serialize(data.args.val5); \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test success */ \ + buf.serialize(data.args.val6); \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); \ + ASSERT_EQ(component.primitiveCmd.args.val1, data.args.val1); \ + ASSERT_EQ(component.primitiveCmd.args.val2, data.args.val2); \ + ASSERT_EQ(component.primitiveCmd.args.val3, data.args.val3); \ + ASSERT_EQ(component.primitiveCmd.args.val4, data.args.val4); \ + ASSERT_EQ(component.primitiveCmd.args.val5, data.args.val5); \ + ASSERT_EQ(component.primitiveCmd.args.val6, data.args.val6); \ + \ + /* Test too many arguments */ \ + buf.serialize(data.args.val5); \ + this->invoke##ASYNC##PrimitiveCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + } \ + \ + void Tester ::test##ASYNC##Command(NATIVE_INT_TYPE portNum, FppTest::Types::CmdStringParams& data) { \ + ASSERT_TRUE(component.isConnected_cmdRegOut_OutputPort(portNum)); \ + ASSERT_TRUE(component.isConnected_cmdResponseOut_OutputPort(portNum)); \ + \ + component.regCommands(); \ + \ + Fw::CmdArgBuffer buf; \ + \ + /* Test incorrect serialization of first argument */ \ + this->invoke##ASYNC##StringCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test incorrect serialization of second argument */ \ + buf.serialize(data.args.val1); \ + this->invoke##ASYNC##StringCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test success */ \ + buf.serialize(data.args.val2); \ + this->invoke##ASYNC##StringCommand(portNum, buf); \ + \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); \ + ASSERT_EQ(component.stringCmd.args.val1, data.args.val1); \ + ASSERT_EQ(component.stringCmd.args.val2, data.args.val2); \ + \ + /* Test too many arguments */ \ + buf.serialize(data.args.val1); \ + this->invoke##ASYNC##StringCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + } \ + \ + void Tester ::test##ASYNC##Command(NATIVE_INT_TYPE portNum, FppTest::Types::EnumParam& data) { \ + ASSERT_TRUE(component.isConnected_cmdRegOut_OutputPort(portNum)); \ + ASSERT_TRUE(component.isConnected_cmdResponseOut_OutputPort(portNum)); \ + \ + component.regCommands(); \ + \ + Fw::CmdArgBuffer buf; \ + \ + /* Test incorrect serialization of first argument */ \ + this->invoke##ASYNC##EnumCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test success */ \ + buf.serialize(data.args.val); \ + this->invoke##ASYNC##EnumCommand(portNum, buf); \ + \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); \ + ASSERT_EQ(component.enumCmd.args.val, data.args.val); \ + \ + /* Test too many arguments */ \ + buf.serialize(data.args.val); \ + this->invoke##ASYNC##EnumCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + } \ + \ + void Tester ::test##ASYNC##Command(NATIVE_INT_TYPE portNum, FppTest::Types::ArrayParam& data) { \ + ASSERT_TRUE(component.isConnected_cmdRegOut_OutputPort(portNum)); \ + ASSERT_TRUE(component.isConnected_cmdResponseOut_OutputPort(portNum)); \ + \ + component.regCommands(); \ + \ + Fw::CmdArgBuffer buf; \ + \ + /* Test incorrect serialization of first argument */ \ + this->invoke##ASYNC##ArrayCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test success */ \ + buf.serialize(data.args.val); \ + this->invoke##ASYNC##ArrayCommand(portNum, buf); \ + \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); \ + ASSERT_EQ(component.arrayCmd.args.val, data.args.val); \ + \ + /* Test too many arguments */ \ + buf.serialize(data.args.val); \ + this->invoke##ASYNC##ArrayCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + } \ + \ + void Tester ::test##ASYNC##Command(NATIVE_INT_TYPE portNum, FppTest::Types::StructParam& data) { \ + ASSERT_TRUE(component.isConnected_cmdRegOut_OutputPort(portNum)); \ + ASSERT_TRUE(component.isConnected_cmdResponseOut_OutputPort(portNum)); \ + \ + component.regCommands(); \ + \ + Fw::CmdArgBuffer buf; \ + \ + /* Test incorrect serialization of first argument */ \ + this->invoke##ASYNC##StructCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + \ + /* Test success */ \ + buf.serialize(data.args.val); \ + this->invoke##ASYNC##StructCommand(portNum, buf); \ + \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); \ + ASSERT_EQ(component.structCmd.args.val, data.args.val); \ + \ + /* Test too many arguments */ \ + buf.serialize(data.args.val); \ + this->invoke##ASYNC##StructCommand(portNum, buf); \ + ASSERT_EQ(cmdResp, Fw::CmdResponse::FORMAT_ERROR); \ + } diff --git a/FppTest/component/tests/EventTests.cpp b/FppTest/component/tests/EventTests.cpp new file mode 100644 index 0000000000..b8bb367559 --- /dev/null +++ b/FppTest/component/tests/EventTests.cpp @@ -0,0 +1,137 @@ +// ====================================================================== +// \title EventTests.cpp +// \author T. Chieu +// \brief cpp file for event tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Event tests +// ---------------------------------------------------------------------- + +void Tester ::testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::NoParams& data) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + component.log_ACTIVITY_HI_EventNoArgs(); + + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_EventNoArgs_SIZE(1); +} + +void Tester ::testEventHelper(NATIVE_INT_TYPE portNum, FppTest::Types::PrimitiveParams& data, NATIVE_UINT_TYPE size) { + component.log_ACTIVITY_LO_EventPrimitive(data.args.val1, data.args.val2, data.args.val3, data.args.val4, + data.args.val5, data.args.val6); + + ASSERT_EVENTS_SIZE(size); + ASSERT_EVENTS_EventPrimitive_SIZE(size); + ASSERT_EVENTS_EventPrimitive(portNum, data.args.val1, data.args.val2, data.args.val3, data.args.val4, + data.args.val5, data.args.val6); +} + +void Tester ::testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::PrimitiveParams& data) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + for (U32 i = 0; i < component.EVENTID_EVENTPRIMITIVE_THROTTLE; i++) { + testEventHelper(portNum, data, i + 1); + } + + // Test that throttling works + testEventHelper(portNum, data, component.EVENTID_EVENTPRIMITIVE_THROTTLE); + + // Test throttle reset + component.log_ACTIVITY_LO_EventPrimitive_ThrottleClear(); + testEventHelper(portNum, data, component.EVENTID_EVENTPRIMITIVE_THROTTLE + 1); +} + +void Tester ::testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::LogStringParams& data) { + component.log_COMMAND_EventString(data.args.val1, data.args.val2); + + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_EventString_SIZE(1); + ASSERT_EVENTS_EventString(portNum, data.args.val1.toChar(), data.args.val2.toChar()); +} + +void Tester ::testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::EnumParam& data) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + component.log_DIAGNOSTIC_EventEnum(data.args.val); + + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_EventEnum_SIZE(1); + ASSERT_EVENTS_EventEnum(portNum, data.args.val); +} + +void Tester ::testEventHelper(NATIVE_INT_TYPE portNum, FppTest::Types::ArrayParam& data, NATIVE_UINT_TYPE size) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + component.log_FATAL_EventArray(data.args.val); + + ASSERT_EVENTS_SIZE(size); + ASSERT_EVENTS_EventArray_SIZE(size); + ASSERT_EVENTS_EventArray(portNum, data.args.val); +} + +void Tester ::testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::ArrayParam& data) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + for (U32 i = 0; i < component.EVENTID_EVENTARRAY_THROTTLE; i++) { + testEventHelper(portNum, data, i + 1); + } + + // Test that throttling works + testEventHelper(portNum, data, component.EVENTID_EVENTARRAY_THROTTLE); + + // Test throttle reset + component.log_FATAL_EventArray_ThrottleClear(); + testEventHelper(portNum, data, component.EVENTID_EVENTARRAY_THROTTLE + 1); +} + +void Tester ::testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::StructParam& data) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + component.log_WARNING_HI_EventStruct(data.args.val); + + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_EventStruct_SIZE(1); + ASSERT_EVENTS_EventStruct(portNum, data.args.val); +} + +void Tester ::testEventHelper(NATIVE_INT_TYPE portNum, FppTest::Types::BoolParam& data, NATIVE_UINT_TYPE size) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + component.log_WARNING_LO_EventBool(data.args.val); + + ASSERT_EVENTS_SIZE(size); + ASSERT_EVENTS_EventBool_SIZE(size); + ASSERT_EVENTS_EventBool(portNum, data.args.val); +} + +void Tester ::testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::BoolParam& data) { + ASSERT_TRUE(component.isConnected_eventOut_OutputPort(portNum)); + ASSERT_TRUE(component.isConnected_textEventOut_OutputPort(portNum)); + + for (U32 i = 0; i < component.EVENTID_EVENTBOOL_THROTTLE; i++) { + testEventHelper(portNum, data, i + 1); + } + + // Test that throttling works + testEventHelper(portNum, data, component.EVENTID_EVENTBOOL_THROTTLE); + + // Test throttle reset + component.log_WARNING_LO_EventBool_ThrottleClear(); + testEventHelper(portNum, data, component.EVENTID_EVENTBOOL_THROTTLE + 1); +} diff --git a/FppTest/component/tests/EventTests.hpp b/FppTest/component/tests/EventTests.hpp new file mode 100644 index 0000000000..f0d2e8595d --- /dev/null +++ b/FppTest/component/tests/EventTests.hpp @@ -0,0 +1,32 @@ +// ====================================================================== +// \title EventTests.hpp +// \author T. Chieu +// \brief hpp file for event tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +// ---------------------------------------------------------------------- +// Event test declarations +// ---------------------------------------------------------------------- + +#define EVENT_TEST_DECL(TYPE) void testEvent(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE& data); + +#define EVENT_TEST_HELPER_DECL(TYPE) \ + void testEventHelper(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE& data, NATIVE_UINT_TYPE size); + +#define EVENT_TEST_DECLS \ + EVENT_TEST_DECL(NoParams) \ + EVENT_TEST_HELPER_DECL(PrimitiveParams) \ + EVENT_TEST_DECL(PrimitiveParams) \ + EVENT_TEST_DECL(LogStringParams) \ + EVENT_TEST_DECL(EnumParam) \ + EVENT_TEST_HELPER_DECL(ArrayParam) \ + EVENT_TEST_DECL(ArrayParam) \ + EVENT_TEST_DECL(StructParam) \ + EVENT_TEST_HELPER_DECL(BoolParam) \ + EVENT_TEST_DECL(BoolParam) diff --git a/FppTest/component/tests/InternalInterfaceTests.cpp b/FppTest/component/tests/InternalInterfaceTests.cpp new file mode 100644 index 0000000000..8f15b7d39f --- /dev/null +++ b/FppTest/component/tests/InternalInterfaceTests.cpp @@ -0,0 +1,81 @@ +// ====================================================================== +// \title InternalInterfaceTests.cpp +// \author T. Chieu +// \brief cpp file for internal interface tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +#include "Fw/Comp/QueuedComponentBase.hpp" + +void Tester ::testInternalInterface(FppTest::Types::NoParams& data) { + Fw::QueuedComponentBase::MsgDispatchStatus status; + + this->component.internalNoArgs_internalInterfaceInvoke(); + status = this->doDispatch(); + + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); +} + +void Tester ::testInternalInterface(FppTest::Types::PrimitiveParams& data) { + Fw::QueuedComponentBase::MsgDispatchStatus status; + + this->component.internalPrimitive_internalInterfaceInvoke(data.args.val1, data.args.val2, data.args.val3, + data.args.val4, data.args.val5, data.args.val6); + status = this->doDispatch(); + + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); + ASSERT_EQ(this->component.primitiveInterface.args.val1, data.args.val1); + ASSERT_EQ(this->component.primitiveInterface.args.val2, data.args.val2); + ASSERT_EQ(this->component.primitiveInterface.args.val3, data.args.val3); + ASSERT_EQ(this->component.primitiveInterface.args.val4, data.args.val4); + ASSERT_EQ(this->component.primitiveInterface.args.val5, data.args.val5); + ASSERT_EQ(this->component.primitiveInterface.args.val6, data.args.val6); +} + +void Tester ::testInternalInterface(FppTest::Types::InternalInterfaceStringParams& data) { + Fw::QueuedComponentBase::MsgDispatchStatus status; + + this->component.internalString_internalInterfaceInvoke(data.args.val1, data.args.val2); + status = this->doDispatch(); + + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); + ASSERT_EQ(this->component.stringInterface.args.val1, data.args.val1); + ASSERT_EQ(this->component.stringInterface.args.val2, data.args.val2); +} + +void Tester ::testInternalInterface(FppTest::Types::EnumParam& data) { + Fw::QueuedComponentBase::MsgDispatchStatus status; + + this->component.internalEnum_internalInterfaceInvoke(data.args.val); + status = this->doDispatch(); + + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); + ASSERT_EQ(this->component.enumInterface.args.val, data.args.val); +} + +void Tester ::testInternalInterface(FppTest::Types::ArrayParam& data) { + Fw::QueuedComponentBase::MsgDispatchStatus status; + + this->component.internalArray_internalInterfaceInvoke(data.args.val); + status = this->doDispatch(); + + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); + ASSERT_EQ(this->component.arrayInterface.args.val, data.args.val); +} + +void Tester ::testInternalInterface(FppTest::Types::StructParam& data) { + Fw::QueuedComponentBase::MsgDispatchStatus status; + + this->component.internalStruct_internalInterfaceInvoke(data.args.val); + status = this->doDispatch(); + + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); + ASSERT_EQ(this->component.structInterface.args.val, data.args.val); +} diff --git a/FppTest/component/tests/InternalInterfaceTests.hpp b/FppTest/component/tests/InternalInterfaceTests.hpp new file mode 100644 index 0000000000..0603b0d7ac --- /dev/null +++ b/FppTest/component/tests/InternalInterfaceTests.hpp @@ -0,0 +1,27 @@ +// ====================================================================== +// \title InternalInterfaceTests.hpp +// \author T. Chieu +// \brief hpp file for internal interface tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Internal interface test declarations +// ---------------------------------------------------------------------- + +#define INTERNAL_INT_TEST_DECL(TYPE) void testInternalInterface(FppTest::Types::TYPE& data); + +#define INTERNAL_INT_TEST_DECLS \ + INTERNAL_INT_TEST_DECL(NoParams) \ + INTERNAL_INT_TEST_DECL(PrimitiveParams) \ + INTERNAL_INT_TEST_DECL(InternalInterfaceStringParams) \ + INTERNAL_INT_TEST_DECL(EnumParam) \ + INTERNAL_INT_TEST_DECL(ArrayParam) \ + INTERNAL_INT_TEST_DECL(StructParam) diff --git a/FppTest/component/tests/ParamTests.cpp b/FppTest/component/tests/ParamTests.cpp new file mode 100644 index 0000000000..d783c7891f --- /dev/null +++ b/FppTest/component/tests/ParamTests.cpp @@ -0,0 +1,242 @@ +// ====================================================================== +// \title ParamTests.cpp +// \author T. Chieu +// \brief cpp file for parameter tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Parameter tests +// ---------------------------------------------------------------------- + +void Tester ::testParam() { + ASSERT_TRUE(component.isConnected_prmGetOut_OutputPort(0)); + component.loadParameters(); + + Fw::ParamValid valid; + + bool boolVal = component.paramGet_ParamBool(valid); + ASSERT_EQ(valid, prmValid); + if (valid == Fw::ParamValid::VALID) { + ASSERT_EQ(boolVal, boolPrm.args.val); + } + + U32 u32Val = component.paramGet_ParamU32(valid); + ASSERT_EQ(valid, prmValid); + if (valid == Fw::ParamValid::VALID) { + ASSERT_EQ(u32Val, u32Prm.args.val); + } + + Fw::ParamString stringVal = component.paramGet_ParamString(valid); + if (valid == Fw::ParamValid::VALID) { + ASSERT_EQ(stringVal, stringPrm.args.val); + } else { + ASSERT_EQ(valid, Fw::ParamValid::DEFAULT); + } + + FormalParamEnum enumVal = component.paramGet_ParamEnum(valid); + ASSERT_EQ(valid, prmValid); + if (valid == Fw::ParamValid::VALID) { + ASSERT_EQ(enumVal, enumPrm.args.val); + } + + FormalParamArray arrayVal = component.paramGet_ParamArray(valid); + if (valid == Fw::ParamValid::VALID) { + ASSERT_EQ(arrayVal, arrayPrm.args.val); + } else { + ASSERT_EQ(valid, Fw::ParamValid::DEFAULT); + } + + FormalParamStruct structVal = component.paramGet_ParamStruct(valid); + ASSERT_EQ(valid, prmValid); + if (valid == Fw::ParamValid::VALID) { + ASSERT_EQ(structVal, structPrm.args.val); + } +} + +void Tester ::testParamCommand(NATIVE_INT_TYPE portNum, FppTest::Types::BoolParam& data) { + Fw::CmdArgBuffer buf; + + // Test unsuccessful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMBOOL_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::EXECUTION_ERROR); + + this->connectPrmSetIn(); + ASSERT_TRUE(component.isConnected_prmSetOut_OutputPort(portNum)); + + // Test incorrect deserialization when setting param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMBOOL_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::VALIDATION_ERROR); + + // Test successful setting of param + buf.serialize(data.args.val); + + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMBOOL_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + + // Test successful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMBOOL_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + ASSERT_EQ(boolPrm.args.val, data.args.val); +} + +void Tester ::testParamCommand(NATIVE_INT_TYPE portNum, FppTest::Types::U32Param& data) { + Fw::CmdArgBuffer buf; + + // Test unsuccessful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMU32_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::EXECUTION_ERROR); + + this->connectPrmSetIn(); + ASSERT_TRUE(component.isConnected_prmSetOut_OutputPort(portNum)); + + // Test incorrect deserialization when setting param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMU32_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::VALIDATION_ERROR); + + // Test successful setting of param + buf.serialize(data.args.val); + + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMU32_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + + // Test successful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMU32_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + ASSERT_EQ(u32Prm.args.val, data.args.val); +} + +void Tester ::testParamCommand(NATIVE_INT_TYPE portNum, FppTest::Types::PrmStringParam& data) { + Fw::CmdArgBuffer buf; + + // Test unsuccessful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRING_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::EXECUTION_ERROR); + + this->connectPrmSetIn(); + ASSERT_TRUE(component.isConnected_prmSetOut_OutputPort(portNum)); + + // Test incorrect deserialization when setting param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRING_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::VALIDATION_ERROR); + + // Test successful setting of param + buf.serialize(data.args.val); + + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRING_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + + // Test successful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRING_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + ASSERT_EQ(stringPrm.args.val, data.args.val); +} + +void Tester ::testParamCommand(NATIVE_INT_TYPE portNum, FppTest::Types::EnumParam& data) { + Fw::CmdArgBuffer buf; + + // Test unsuccessful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMENUM_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::EXECUTION_ERROR); + + this->connectPrmSetIn(); + ASSERT_TRUE(component.isConnected_prmSetOut_OutputPort(portNum)); + + // Test incorrect deserialization when setting param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMENUM_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::VALIDATION_ERROR); + + // Test successful setting of param + buf.serialize(data.args.val); + + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMENUM_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + + // Test successful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMENUM_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + ASSERT_EQ(enumPrm.args.val, data.args.val); +} + +void Tester ::testParamCommand(NATIVE_INT_TYPE portNum, FppTest::Types::ArrayParam& data) { + Fw::CmdArgBuffer buf; + + // Test unsuccessful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMARRAY_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::EXECUTION_ERROR); + + this->connectPrmSetIn(); + ASSERT_TRUE(component.isConnected_prmSetOut_OutputPort(portNum)); + + // Test incorrect deserialization when setting param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMARRAY_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::VALIDATION_ERROR); + + // Test successful setting of param + buf.serialize(data.args.val); + + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMARRAY_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + + // Test successful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMARRAY_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + ASSERT_EQ(arrayPrm.args.val, data.args.val); +} + +void Tester ::testParamCommand(NATIVE_INT_TYPE portNum, FppTest::Types::StructParam& data) { + Fw::CmdArgBuffer buf; + + // Test unsuccessful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRUCT_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::EXECUTION_ERROR); + + this->connectPrmSetIn(); + ASSERT_TRUE(component.isConnected_prmSetOut_OutputPort(portNum)); + + // Test incorrect deserialization when setting param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRUCT_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::VALIDATION_ERROR); + + // Test successful setting of param + buf.serialize(data.args.val); + + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRUCT_SET, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + + // Test successful saving of param + this->invoke_to_cmdOut(portNum, component.OPCODE_PARAMSTRUCT_SAVE, 1, buf); + + ASSERT_EQ(cmdResp, Fw::CmdResponse::OK); + ASSERT_EQ(structPrm.args.val, data.args.val); +} diff --git a/FppTest/component/tests/ParamTests.hpp b/FppTest/component/tests/ParamTests.hpp new file mode 100644 index 0000000000..46caf8efdf --- /dev/null +++ b/FppTest/component/tests/ParamTests.hpp @@ -0,0 +1,25 @@ +// ====================================================================== +// \title ParamTests.hpp +// \author T. Chieu +// \brief hpp file for parameter tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +// ---------------------------------------------------------------------- +// Parameter test declarations +// ---------------------------------------------------------------------- + +#define PARAM_CMD_TEST_DECL(TYPE) void testParamCommand(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE& data); + +#define PARAM_CMD_TEST_DECLS \ + PARAM_CMD_TEST_DECL(BoolParam) \ + PARAM_CMD_TEST_DECL(U32Param) \ + PARAM_CMD_TEST_DECL(PrmStringParam) \ + PARAM_CMD_TEST_DECL(EnumParam) \ + PARAM_CMD_TEST_DECL(ArrayParam) \ + PARAM_CMD_TEST_DECL(StructParam) diff --git a/FppTest/component/tests/PortTests.cpp b/FppTest/component/tests/PortTests.cpp new file mode 100644 index 0000000000..67ad504cda --- /dev/null +++ b/FppTest/component/tests/PortTests.cpp @@ -0,0 +1,17 @@ +// ====================================================================== +// \title PortTests.cpp +// \author T. Chieu +// \brief cpp file for port tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "PortTests.hpp" +#include "test/ut/Tester.hpp" + +PORT_TEST_DEFS(Sync) +PORT_TEST_DEFS(Guarded) diff --git a/FppTest/component/tests/PortTests.hpp b/FppTest/component/tests/PortTests.hpp new file mode 100644 index 0000000000..606a7cbb9a --- /dev/null +++ b/FppTest/component/tests/PortTests.hpp @@ -0,0 +1,730 @@ +// ====================================================================== +// \title PortTests.hpp +// \author T. Chieu +// \brief hpp file for port tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/component/active/SerialPortIndexEnumAc.hpp" +#include "FppTest/component/active/TypedPortIndexEnumAc.hpp" +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Port test declarations +// ---------------------------------------------------------------------- + +#define PORT_TEST_INVOKE_DECL(PORT_KIND, TYPE) \ + void test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE& port); + +#define PORT_TEST_INVOKE_DECLS(PORT_KIND) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, NoParams) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, PrimitiveParams) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, PortStringParams) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, EnumParams) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, ArrayParams) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, StructParams) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, NoParamReturn) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, PrimitiveReturn) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, EnumReturn) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, ArrayReturn) \ + PORT_TEST_INVOKE_DECL(PORT_KIND, StructReturn) + +#define PORT_TEST_INVOKE_SERIAL_HELPER_DECL(PORT_KIND) \ + void invoke##PORT_KIND##SerialPort(NATIVE_INT_TYPE portNum, Fw::SerialBuffer& buf); + +#define PORT_TEST_INVOKE_SERIAL_DECL(PORT_KIND, TYPE) \ + void test##PORT_KIND##PortInvokeSerial(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE& port); + +#define PORT_TEST_INVOKE_SERIAL_DECLS(PORT_KIND) \ + PORT_TEST_INVOKE_SERIAL_DECL(PORT_KIND, NoParams) \ + PORT_TEST_INVOKE_SERIAL_DECL(PORT_KIND, PrimitiveParams) \ + PORT_TEST_INVOKE_SERIAL_DECL(PORT_KIND, PortStringParams) \ + PORT_TEST_INVOKE_SERIAL_DECL(PORT_KIND, EnumParams) \ + PORT_TEST_INVOKE_SERIAL_DECL(PORT_KIND, ArrayParams) \ + PORT_TEST_INVOKE_SERIAL_DECL(PORT_KIND, StructParams) + +#define PORT_TEST_CHECK_DECL(PORT_KIND, TYPE) void test##PORT_KIND##PortCheck(FppTest::Types::TYPE& port); + +#define PORT_TEST_CHECK_DECLS(PORT_KIND) \ + PORT_TEST_CHECK_DECL(PORT_KIND, NoParams) \ + PORT_TEST_CHECK_DECL(PORT_KIND, PrimitiveParams) \ + PORT_TEST_CHECK_DECL(PORT_KIND, PortStringParams) \ + PORT_TEST_CHECK_DECL(PORT_KIND, EnumParams) \ + PORT_TEST_CHECK_DECL(PORT_KIND, ArrayParams) \ + PORT_TEST_CHECK_DECL(PORT_KIND, StructParams) \ + PORT_TEST_CHECK_DECL(PORT_KIND, NoParamReturn) \ + PORT_TEST_CHECK_DECL(PORT_KIND, PrimitiveReturn) \ + PORT_TEST_CHECK_DECL(PORT_KIND, EnumReturn) \ + PORT_TEST_CHECK_DECL(PORT_KIND, ArrayReturn) \ + PORT_TEST_CHECK_DECL(PORT_KIND, StructReturn) + +#define PORT_TEST_CHECK_SERIAL_DECL(PORT_KIND, TYPE) void test##PORT_KIND##PortCheckSerial(FppTest::Types::TYPE& port); + +#define PORT_TEST_CHECK_SERIAL_DECLS(PORT_KIND) \ + PORT_TEST_CHECK_SERIAL_DECL(PORT_KIND, NoParams) \ + PORT_TEST_CHECK_SERIAL_DECL(PORT_KIND, PrimitiveParams) \ + PORT_TEST_CHECK_SERIAL_DECL(PORT_KIND, PortStringParams) \ + PORT_TEST_CHECK_SERIAL_DECL(PORT_KIND, EnumParams) \ + PORT_TEST_CHECK_SERIAL_DECL(PORT_KIND, ArrayParams) \ + PORT_TEST_CHECK_SERIAL_DECL(PORT_KIND, StructParams) + +#define PORT_TEST_DECLS_KIND(PORT_KIND) \ + PORT_TEST_INVOKE_DECLS(PORT_KIND) \ + PORT_TEST_INVOKE_SERIAL_HELPER_DECL(PORT_KIND) \ + PORT_TEST_INVOKE_SERIAL_DECLS(PORT_KIND) \ + PORT_TEST_CHECK_DECLS(PORT_KIND) \ + PORT_TEST_CHECK_SERIAL_DECLS(PORT_KIND) + +#define PORT_TEST_DECLS \ + PORT_TEST_DECLS_KIND(Sync) \ + PORT_TEST_DECLS_KIND(Guarded) + +#define PORT_TEST_DECLS_ASYNC PORT_TEST_DECLS_KIND(Async) + +// ---------------------------------------------------------------------- +// Invoke typed input ports +// ---------------------------------------------------------------------- + +#define PORT_TEST_INVOKE_DEFS(PORT_KIND) \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::NoParams& port) { \ + ASSERT_TRUE(component.isConnected_noArgsOut_OutputPort(portNum)); \ + \ + this->invoke_to_noArgs##PORT_KIND(portNum); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::PrimitiveParams& port) { \ + ASSERT_TRUE(component.isConnected_primitiveArgsOut_OutputPort(portNum)); \ + \ + this->invoke_to_primitiveArgs##PORT_KIND(portNum, port.args.val1, port.args.val2, port.args.val3, \ + port.args.val4, port.args.val5, port.args.val6); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::PortStringParams& port) { \ + ASSERT_TRUE(component.isConnected_stringArgsOut_OutputPort(portNum)); \ + \ + this->invoke_to_stringArgs##PORT_KIND(portNum, port.args.val1, port.args.val2, port.args.val3, \ + port.args.val4); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::EnumParams& port) { \ + ASSERT_TRUE(component.isConnected_enumArgsOut_OutputPort(portNum)); \ + \ + this->invoke_to_enumArgs##PORT_KIND(portNum, port.args.val1, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::ArrayParams& port) { \ + ASSERT_TRUE(component.isConnected_arrayArgsOut_OutputPort(portNum)); \ + \ + this->invoke_to_arrayArgs##PORT_KIND(portNum, port.args.val1, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::StructParams& port) { \ + ASSERT_TRUE(component.isConnected_structArgsOut_OutputPort(portNum)); \ + \ + this->invoke_to_structArgs##PORT_KIND(portNum, port.args.val1, port.args.val2); \ + } + +#define PORT_TEST_INVOKE_RETURN_DEFS(PORT_KIND) \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::NoParamReturn& port) { \ + ASSERT_TRUE(component.isConnected_noArgsReturnOut_OutputPort(portNum)); \ + \ + bool returnVal = this->invoke_to_noArgsReturn##PORT_KIND(portNum); \ + \ + ASSERT_EQ(returnVal, this->noParamReturnVal.val); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::PrimitiveReturn& port) { \ + ASSERT_TRUE(component.isConnected_primitiveReturnOut_OutputPort(portNum)); \ + \ + U32 returnVal = this->invoke_to_primitiveReturn##PORT_KIND( \ + portNum, port.args.val1, port.args.val2, port.args.val3, port.args.val4, port.args.val5, port.args.val6); \ + \ + ASSERT_EQ(returnVal, this->primitiveReturnVal.val); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::EnumReturn& port) { \ + ASSERT_TRUE(component.isConnected_enumReturnOut_OutputPort(portNum)); \ + \ + FormalParamEnum returnVal = this->invoke_to_enumReturn##PORT_KIND(portNum, port.args.val1, port.args.val2); \ + \ + ASSERT_EQ(returnVal, this->enumReturnVal.val); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::ArrayReturn& port) { \ + ASSERT_TRUE(component.isConnected_arrayReturnOut_OutputPort(portNum)); \ + \ + FormalParamArray returnVal = this->invoke_to_arrayReturn##PORT_KIND(portNum, port.args.val1, port.args.val2); \ + \ + ASSERT_EQ(returnVal, this->arrayReturnVal.val); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvoke(NATIVE_INT_TYPE portNum, FppTest::Types::StructReturn& port) { \ + ASSERT_TRUE(component.isConnected_structReturnOut_OutputPort(portNum)); \ + \ + FormalParamStruct returnVal = \ + this->invoke_to_structReturn##PORT_KIND(portNum, port.args.val1, port.args.val2); \ + \ + ASSERT_EQ(returnVal, this->structReturnVal.val); \ + } + +// ---------------------------------------------------------------------- +// Invoke serial input ports +// ---------------------------------------------------------------------- + +#define PORT_TEST_INVOKE_SERIAL_HELPER_DEF(PORT_KIND) \ + void Tester ::invoke##PORT_KIND##SerialPort(NATIVE_INT_TYPE portNum, Fw::SerialBuffer& buf) { \ + this->invoke_to_serial##PORT_KIND(portNum, buf); \ + } + +#define PORT_TEST_INVOKE_SERIAL_HELPER_DEF_ASYNC \ + void Tester ::invokeAsyncSerialPort(NATIVE_INT_TYPE portNum, Fw::SerialBuffer& buf) { \ + Fw::QueuedComponentBase::MsgDispatchStatus status; \ + \ + switch (portNum) { \ + case SerialPortIndex::NO_ARGS: \ + case SerialPortIndex::PRIMITIVE: \ + case SerialPortIndex::STRING: \ + this->invoke_to_serialAsync(portNum, buf); \ + break; \ + \ + case SerialPortIndex::ENUM: \ + this->invoke_to_serialAsyncAssert(0, buf); \ + break; \ + \ + case SerialPortIndex::ARRAY: \ + this->invoke_to_serialAsyncBlockPriority(0, buf); \ + break; \ + \ + case SerialPortIndex::STRUCT: \ + this->invoke_to_serialAsyncDropPriority(0, buf); \ + break; \ + } \ + \ + status = this->doDispatch(); \ + \ + ASSERT_EQ(status, Fw::QueuedComponentBase::MsgDispatchStatus::MSG_DISPATCH_OK); \ + } + +#define PORT_TEST_INVOKE_SERIAL_DEFS(PORT_KIND) \ + void Tester ::test##PORT_KIND##PortInvokeSerial(NATIVE_INT_TYPE portNum, FppTest::Types::NoParams& port) { \ + ASSERT_TRUE(component.isConnected_serialOut_OutputPort(portNum)); \ + \ + U8 data[0]; \ + Fw::SerialBuffer buf(data, sizeof(data)); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::NO_ARGS, buf); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvokeSerial(NATIVE_INT_TYPE portNum, FppTest::Types::PrimitiveParams& port) { \ + ASSERT_TRUE(component.isConnected_serialOut_OutputPort(portNum)); \ + \ + Fw::SerializeStatus status; \ + \ + /* Check unsuccessful deserialization of first parameter */ \ + U8 invalidData1[0]; \ + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::PRIMITIVE, invalidBuf1); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of second parameter */ \ + U8 invalidData2[sizeof(U32)]; \ + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); \ + \ + status = invalidBuf2.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::PRIMITIVE, invalidBuf2); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of third parameter */ \ + U8 invalidData3[sizeof(U32) * 2]; \ + Fw::SerialBuffer invalidBuf3(invalidData3, sizeof(invalidData3)); \ + \ + status = invalidBuf3.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf3.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::PRIMITIVE, invalidBuf3); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of fourth parameter */ \ + U8 invalidData4[(sizeof(U32) * 2) + sizeof(F32)]; \ + Fw::SerialBuffer invalidBuf4(invalidData4, sizeof(invalidData4)); \ + \ + status = invalidBuf4.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf4.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf4.serialize(port.args.val3); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::PRIMITIVE, invalidBuf4); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of fifth parameter */ \ + U8 invalidData5[(sizeof(U32) * 2) + (sizeof(F32) * 2)]; \ + Fw::SerialBuffer invalidBuf5(invalidData5, sizeof(invalidData5)); \ + \ + status = invalidBuf5.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf5.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf5.serialize(port.args.val3); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf5.serialize(port.args.val4); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::PRIMITIVE, invalidBuf5); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of sixth parameter */ \ + U8 invalidData6[(sizeof(U32) * 2) + (sizeof(F32) * 2) + sizeof(U8)]; \ + Fw::SerialBuffer invalidBuf6(invalidData6, sizeof(invalidData6)); \ + \ + status = invalidBuf6.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf6.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf6.serialize(port.args.val3); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf6.serialize(port.args.val4); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf6.serialize(port.args.val5); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::PRIMITIVE, invalidBuf6); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check successful serialization */ \ + U8 data[InputPrimitiveArgsPort::SERIALIZED_SIZE]; \ + Fw::SerialBuffer buf(data, sizeof(data)); \ + \ + status = buf.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val3); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val4); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val5); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val6); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::PRIMITIVE, buf); \ + \ + this->checkSerializeStatusSuccess(); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvokeSerial(NATIVE_INT_TYPE portNum, FppTest::Types::PortStringParams& port) { \ + ASSERT_TRUE(component.isConnected_serialOut_OutputPort(portNum)); \ + \ + Fw::SerializeStatus status; \ + \ + /* Check unsuccessful deserialization of first parameter */ \ + U8 invalidData1[0]; \ + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRING, invalidBuf1); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of second parameter */ \ + U8 invalidData2[StringArgsPortStrings::StringSize80::SERIALIZED_SIZE]; \ + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); \ + \ + status = invalidBuf2.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRING, invalidBuf2); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of third parameter */ \ + U8 invalidData3[StringArgsPortStrings::StringSize80::SERIALIZED_SIZE * 2]; \ + Fw::SerialBuffer invalidBuf3(invalidData3, sizeof(invalidData3)); \ + \ + status = invalidBuf3.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf3.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRING, invalidBuf3); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of fourth parameter */ \ + U8 invalidData4[(StringArgsPortStrings::StringSize80::SERIALIZED_SIZE * 2) + \ + StringArgsPortStrings::StringSize100::SERIALIZED_SIZE]; \ + Fw::SerialBuffer invalidBuf4(invalidData4, sizeof(invalidData4)); \ + \ + status = invalidBuf4.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf4.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = invalidBuf4.serialize(port.args.val3); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRING, invalidBuf4); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check successful serialization */ \ + U8 data[InputStringArgsPort::SERIALIZED_SIZE]; \ + Fw::SerialBuffer buf(data, sizeof(data)); \ + \ + status = buf.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val3); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val4); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRING, buf); \ + \ + this->checkSerializeStatusSuccess(); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvokeSerial(NATIVE_INT_TYPE portNum, FppTest::Types::EnumParams& port) { \ + ASSERT_TRUE(component.isConnected_serialOut_OutputPort(portNum)); \ + \ + Fw::SerializeStatus status; \ + \ + /* Check unsuccessful deserialization of first parameter */ \ + U8 invalidData1[0]; \ + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::ENUM, invalidBuf1); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of second parameter */ \ + U8 invalidData2[FormalParamEnum::SERIALIZED_SIZE]; \ + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); \ + \ + status = invalidBuf2.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::ENUM, invalidBuf2); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check successful serialization */ \ + U8 data[InputEnumArgsPort::SERIALIZED_SIZE]; \ + Fw::SerialBuffer buf(data, sizeof(data)); \ + \ + status = buf.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::ENUM, buf); \ + \ + this->checkSerializeStatusSuccess(); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvokeSerial(NATIVE_INT_TYPE portNum, FppTest::Types::ArrayParams& port) { \ + ASSERT_TRUE(component.isConnected_serialOut_OutputPort(portNum)); \ + \ + Fw::SerializeStatus status; \ + \ + /* Check unsuccessful deserialization of first parameter */ \ + U8 invalidData1[0]; \ + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::ARRAY, invalidBuf1); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of second parameter */ \ + U8 invalidData2[FormalParamArray::SERIALIZED_SIZE]; \ + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); \ + \ + status = invalidBuf2.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::ARRAY, invalidBuf2); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + U8 data[InputArrayArgsPort::SERIALIZED_SIZE]; \ + Fw::SerialBuffer buf(data, sizeof(data)); \ + \ + status = buf.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::ARRAY, buf); \ + \ + this->checkSerializeStatusSuccess(); \ + } \ + \ + void Tester ::test##PORT_KIND##PortInvokeSerial(NATIVE_INT_TYPE portNum, FppTest::Types::StructParams& port) { \ + ASSERT_TRUE(component.isConnected_serialOut_OutputPort(portNum)); \ + \ + Fw::SerializeStatus status; \ + \ + /* Check unsuccessful deserialization of first parameter */ \ + U8 invalidData1[0]; \ + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRUCT, invalidBuf1); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + /* Check unsuccessful deserialization of second parameter */ \ + U8 invalidData2[FormalParamStruct::SERIALIZED_SIZE]; \ + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); \ + \ + status = invalidBuf2.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRUCT, invalidBuf2); \ + \ + this->checkSerializeStatusBufferEmpty(); \ + \ + U8 data[InputStructArgsPort::SERIALIZED_SIZE]; \ + Fw::SerialBuffer buf(data, sizeof(data)); \ + \ + status = buf.serialize(port.args.val1); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = buf.serialize(port.args.val2); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + this->invoke##PORT_KIND##SerialPort(SerialPortIndex::STRUCT, buf); \ + \ + this->checkSerializeStatusSuccess(); \ + } + +// ---------------------------------------------------------------------- +// Check history of typed output ports +// ---------------------------------------------------------------------- + +#define PORT_TEST_CHECK_DEFS(PORT_KIND) \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::NoParams& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_noArgsOut_SIZE(1); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::PrimitiveParams& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_primitiveArgsOut_SIZE(1); \ + ASSERT_from_primitiveArgsOut(0, port.args.val1, port.args.val2, port.args.val3, port.args.val4, \ + port.args.val5, port.args.val6); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::PortStringParams& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_stringArgsOut_SIZE(1); \ + ASSERT_from_stringArgsOut(0, port.args.val1, port.args.val2, port.args.val3, port.args.val4); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::EnumParams& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_enumArgsOut_SIZE(1); \ + ASSERT_from_enumArgsOut(0, port.args.val1, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::ArrayParams& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_arrayArgsOut_SIZE(1); \ + ASSERT_from_arrayArgsOut(0, port.args.val1, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::StructParams& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_structArgsOut_SIZE(1); \ + ASSERT_from_structArgsOut(0, port.args.val1, port.args.val2); \ + } + +#define PORT_TEST_CHECK_RETURN_DEFS(PORT_KIND) \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::NoParamReturn& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_noArgsReturnOut_SIZE(1); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::PrimitiveReturn& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_primitiveReturnOut_SIZE(1); \ + ASSERT_from_primitiveReturnOut(0, port.args.val1, port.args.val2, port.args.val3, port.args.val4, \ + port.args.val5, port.args.val6); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::EnumReturn& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_enumReturnOut_SIZE(1); \ + ASSERT_from_enumReturnOut(0, port.args.val1, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::ArrayReturn& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_arrayReturnOut_SIZE(1); \ + ASSERT_from_arrayReturnOut(0, port.args.val1, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheck(FppTest::Types::StructReturn& port) { \ + ASSERT_FROM_PORT_HISTORY_SIZE(1); \ + ASSERT_from_structReturnOut_SIZE(1); \ + ASSERT_from_structReturnOut(0, port.args.val1, port.args.val2); \ + } + +// ---------------------------------------------------------------------- +// Check serial output ports +// ---------------------------------------------------------------------- + +#define PORT_TEST_CHECK_SERIAL_DEFS(PORT_KIND) \ + void Tester ::test##PORT_KIND##PortCheckSerial(FppTest::Types::NoParams& port) {} \ + \ + void Tester ::test##PORT_KIND##PortCheckSerial(FppTest::Types::PrimitiveParams& port) { \ + Fw::SerializeStatus status; \ + U32 u32, u32Ref; \ + F32 f32, f32Ref; \ + bool b, bRef; \ + \ + status = this->primitiveBuf.deserialize(u32); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->primitiveBuf.deserialize(u32Ref); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->primitiveBuf.deserialize(f32); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->primitiveBuf.deserialize(f32Ref); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->primitiveBuf.deserialize(b); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->primitiveBuf.deserialize(bRef); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + ASSERT_EQ(u32, port.args.val1); \ + ASSERT_EQ(u32Ref, port.args.val2); \ + ASSERT_EQ(f32, port.args.val3); \ + ASSERT_EQ(f32Ref, port.args.val4); \ + ASSERT_EQ(b, port.args.val5); \ + ASSERT_EQ(bRef, port.args.val6); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheckSerial(FppTest::Types::PortStringParams& port) { \ + Fw::SerializeStatus status; \ + StringArgsPortStrings::StringSize80 str80, str80Ref; \ + StringArgsPortStrings::StringSize100 str100, str100Ref; \ + \ + status = this->stringBuf.deserialize(str80); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->stringBuf.deserialize(str80Ref); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->stringBuf.deserialize(str100); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->stringBuf.deserialize(str100Ref); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + ASSERT_EQ(str80, port.args.val1); \ + ASSERT_EQ(str80Ref, port.args.val2); \ + ASSERT_EQ(str100, port.args.val3); \ + ASSERT_EQ(str100Ref, port.args.val4); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheckSerial(FppTest::Types::EnumParams& port) { \ + Fw::SerializeStatus status; \ + FormalParamEnum en, enRef; \ + \ + status = this->enumBuf.deserialize(en); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->enumBuf.deserialize(enRef); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + ASSERT_EQ(en, port.args.val1); \ + ASSERT_EQ(enRef, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheckSerial(FppTest::Types::ArrayParams& port) { \ + Fw::SerializeStatus status; \ + FormalParamArray a, aRef; \ + \ + status = this->arrayBuf.deserialize(a); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->arrayBuf.deserialize(aRef); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + ASSERT_EQ(a, port.args.val1); \ + ASSERT_EQ(aRef, port.args.val2); \ + } \ + \ + void Tester ::test##PORT_KIND##PortCheckSerial(FppTest::Types::StructParams& port) { \ + Fw::SerializeStatus status; \ + FormalParamStruct s, sRef; \ + \ + status = this->structBuf.deserialize(s); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + status = this->structBuf.deserialize(sRef); \ + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); \ + \ + ASSERT_EQ(s, port.args.val1); \ + ASSERT_EQ(sRef, port.args.val2); \ + } + +#define PORT_TEST_DEFS(PORT_KIND) \ + PORT_TEST_INVOKE_DEFS(PORT_KIND) \ + PORT_TEST_INVOKE_RETURN_DEFS(PORT_KIND) \ + PORT_TEST_INVOKE_SERIAL_HELPER_DEF(PORT_KIND) \ + PORT_TEST_INVOKE_SERIAL_DEFS(PORT_KIND) \ + PORT_TEST_CHECK_DEFS(PORT_KIND) \ + PORT_TEST_CHECK_RETURN_DEFS(PORT_KIND) \ + PORT_TEST_CHECK_SERIAL_DEFS(PORT_KIND) + +#define PORT_TEST_DEFS_ASYNC \ + PORT_TEST_INVOKE_DEFS(Async) \ + PORT_TEST_INVOKE_SERIAL_HELPER_DEF_ASYNC \ + PORT_TEST_INVOKE_SERIAL_DEFS(Async) \ + PORT_TEST_CHECK_DEFS(Async) \ + PORT_TEST_CHECK_SERIAL_DEFS(Async) diff --git a/FppTest/component/tests/TestMain.cpp b/FppTest/component/tests/TestMain.cpp new file mode 100644 index 0000000000..d12c644fa1 --- /dev/null +++ b/FppTest/component/tests/TestMain.cpp @@ -0,0 +1,13 @@ +// ---------------------------------------------------------------------- +// TestMain.cpp +// ---------------------------------------------------------------------- + +#include "STest/Random/Random.hpp" +#include "gtest/gtest.h" + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); + + return RUN_ALL_TESTS(); +} diff --git a/FppTest/component/tests/TesterHandlers.cpp b/FppTest/component/tests/TesterHandlers.cpp new file mode 100644 index 0000000000..c4d563a2e4 --- /dev/null +++ b/FppTest/component/tests/TesterHandlers.cpp @@ -0,0 +1,140 @@ +// ====================================================================== +// \title TesterHandlers.cpp +// \author T. Chieu +// \brief cpp file for tester handler functions +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void Tester ::from_arrayArgsOut_handler(const NATIVE_INT_TYPE portNum, + const FormalParamArray& a, + FormalParamArray& aRef) { + this->pushFromPortEntry_arrayArgsOut(a, aRef); +} + +FormalParamArray Tester ::from_arrayReturnOut_handler(const NATIVE_INT_TYPE portNum, + const FormalParamArray& a, + FormalParamArray& aRef) { + this->pushFromPortEntry_arrayReturnOut(a, aRef); + return arrayReturnVal.val; +} + +void Tester ::from_enumArgsOut_handler(const NATIVE_INT_TYPE portNum, + const FormalParamEnum& en, + FormalParamEnum& enRef) { + this->pushFromPortEntry_enumArgsOut(en, enRef); +} + +FormalParamEnum Tester ::from_enumReturnOut_handler(const NATIVE_INT_TYPE portNum, + const FormalParamEnum& en, + FormalParamEnum& enRef) { + this->pushFromPortEntry_enumReturnOut(en, enRef); + return enumReturnVal.val; +} + +void Tester ::from_noArgsOut_handler(const NATIVE_INT_TYPE portNum) { + this->pushFromPortEntry_noArgsOut(); +} + +bool Tester ::from_noArgsReturnOut_handler(const NATIVE_INT_TYPE portNum) { + this->pushFromPortEntry_noArgsReturnOut(); + return noParamReturnVal.val; +} + +void Tester ::from_primitiveArgsOut_handler(const NATIVE_INT_TYPE portNum, + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef) { + this->pushFromPortEntry_primitiveArgsOut(u32, u32Ref, f32, f32Ref, b, bRef); +} + +U32 Tester ::from_primitiveReturnOut_handler(const NATIVE_INT_TYPE portNum, + U32 u32, + U32& u32Ref, + F32 f32, + F32& f32Ref, + bool b, + bool& bRef) { + this->pushFromPortEntry_primitiveReturnOut(u32, u32Ref, f32, f32Ref, b, bRef); + return primitiveReturnVal.val; +} + +void Tester ::from_stringArgsOut_handler(const NATIVE_INT_TYPE portNum, + const str80String& str80, + str80RefString& str80Ref, + const str100String& str100, + str100RefString& str100Ref) { + this->pushFromPortEntry_stringArgsOut(str80, str80Ref, str100, str100Ref); +} + +void Tester ::from_structArgsOut_handler(const NATIVE_INT_TYPE portNum, + const FormalParamStruct& s, + FormalParamStruct& sRef) { + this->pushFromPortEntry_structArgsOut(s, sRef); +} + +FormalParamStruct Tester ::from_structReturnOut_handler(const NATIVE_INT_TYPE portNum, + const FormalParamStruct& s, + FormalParamStruct& sRef) { + this->pushFromPortEntry_structReturnOut(s, sRef); + return structReturnVal.val; +} + +// ---------------------------------------------------------------------- +// Handlers for serial from ports +// ---------------------------------------------------------------------- + +void Tester ::from_serialOut_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase& Buffer /*!< The serialization buffer*/ +) { + Fw::SerializeStatus status; + + switch (portNum) { + case SerialPortIndex::NO_ARGS: + status = Fw::FW_SERIALIZE_OK; + break; + + case SerialPortIndex::PRIMITIVE: + status = Buffer.copyRaw(this->primitiveBuf, Buffer.getBuffCapacity()); + break; + + case SerialPortIndex::STRING: + status = Buffer.copyRaw(this->stringBuf, Buffer.getBuffCapacity()); + break; + + case SerialPortIndex::ENUM: + status = Buffer.copyRaw(this->enumBuf, Buffer.getBuffCapacity()); + break; + + case SerialPortIndex::ARRAY: + status = Buffer.copyRaw(this->arrayBuf, Buffer.getBuffCapacity()); + break; + + case SerialPortIndex::STRUCT: + status = Buffer.copyRaw(this->structBuf, Buffer.getBuffCapacity()); + break; + } + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); +} + +// ---------------------------------------------------------------------- +// Handlers for special from ports +// ---------------------------------------------------------------------- + +void Tester ::cmdResponseIn(const FwOpcodeType opCode, const U32 cmdSeq, const Fw::CmdResponse response) { + this->cmdResp = response; +} diff --git a/FppTest/component/tests/TesterHelpers.cpp b/FppTest/component/tests/TesterHelpers.cpp new file mode 100644 index 0000000000..7c2866ea3f --- /dev/null +++ b/FppTest/component/tests/TesterHelpers.cpp @@ -0,0 +1,272 @@ +// ====================================================================== +// \title TesterHelpers.cpp +// \author T. Chieu +// \brief cpp file for tester helper functions +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void Tester ::connectPorts() { + // arrayArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_arrayArgsGuarded(i, this->component.get_arrayArgsGuarded_InputPort(i)); + } + + // arrayArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_arrayArgsSync(i, this->component.get_arrayArgsSync_InputPort(i)); + } + + // arrayReturnGuarded + this->connect_to_arrayReturnGuarded(0, this->component.get_arrayReturnGuarded_InputPort(0)); + + // arrayReturnSync + this->connect_to_arrayReturnSync(0, this->component.get_arrayReturnSync_InputPort(0)); + + // cmdIn + this->connect_to_cmdIn(0, this->component.get_cmdIn_InputPort(0)); + + // enumArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_enumArgsGuarded(i, this->component.get_enumArgsGuarded_InputPort(i)); + } + + // enumArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_enumArgsSync(i, this->component.get_enumArgsSync_InputPort(i)); + } + + // enumReturnGuarded + this->connect_to_enumReturnGuarded(0, this->component.get_enumReturnGuarded_InputPort(0)); + + // enumReturnSync + this->connect_to_enumReturnSync(0, this->component.get_enumReturnSync_InputPort(0)); + + // noArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_noArgsGuarded(i, this->component.get_noArgsGuarded_InputPort(i)); + } + + // noArgsReturnGuarded + this->connect_to_noArgsReturnGuarded(0, this->component.get_noArgsReturnGuarded_InputPort(0)); + + // noArgsReturnSync + this->connect_to_noArgsReturnSync(0, this->component.get_noArgsReturnSync_InputPort(0)); + + // noArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_noArgsSync(i, this->component.get_noArgsSync_InputPort(i)); + } + + // primitiveArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_primitiveArgsGuarded(i, this->component.get_primitiveArgsGuarded_InputPort(i)); + } + + // primitiveArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_primitiveArgsSync(i, this->component.get_primitiveArgsSync_InputPort(i)); + } + + // primitiveReturnGuarded + this->connect_to_primitiveReturnGuarded(0, this->component.get_primitiveReturnGuarded_InputPort(0)); + + // primitiveReturnSync + this->connect_to_primitiveReturnSync(0, this->component.get_primitiveReturnSync_InputPort(0)); + + // stringArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_stringArgsGuarded(i, this->component.get_stringArgsGuarded_InputPort(i)); + } + + // stringArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_stringArgsSync(i, this->component.get_stringArgsSync_InputPort(i)); + } + + // structArgsGuarded + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_structArgsGuarded(i, this->component.get_structArgsGuarded_InputPort(i)); + } + + // structArgsSync + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_structArgsSync(i, this->component.get_structArgsSync_InputPort(i)); + } + + // structReturnGuarded + this->connect_to_structReturnGuarded(0, this->component.get_structReturnGuarded_InputPort(0)); + + // structReturnSync + this->connect_to_structReturnSync(0, this->component.get_structReturnSync_InputPort(0)); + + // arrayArgsOut + this->component.set_arrayArgsOut_OutputPort(TypedPortIndex::TYPED, + this->get_from_arrayArgsOut(TypedPortIndex::TYPED)); + + // arrayReturnOut + this->component.set_arrayReturnOut_OutputPort(0, this->get_from_arrayReturnOut(0)); + + // cmdIn + this->connect_to_cmdOut(0, this->component.get_cmdIn_InputPort(0)); + + // cmdRegOut + this->component.set_cmdRegOut_OutputPort(0, this->get_from_cmdRegOut(0)); + + // cmdResponseOut + this->component.set_cmdResponseOut_OutputPort(0, this->get_from_cmdResponseOut(0)); + + // enumArgsOut + this->component.set_enumArgsOut_OutputPort(TypedPortIndex::TYPED, + this->get_from_enumArgsOut(TypedPortIndex::TYPED)); + + // enumReturnOut + this->component.set_enumReturnOut_OutputPort(0, this->get_from_enumReturnOut(0)); + + // eventOut + this->component.set_eventOut_OutputPort(0, this->get_from_eventOut(0)); + + // noArgsOut + this->component.set_noArgsOut_OutputPort(TypedPortIndex::TYPED, this->get_from_noArgsOut(TypedPortIndex::TYPED)); + + // noArgsReturnOut + this->component.set_noArgsReturnOut_OutputPort(0, this->get_from_noArgsReturnOut(0)); + + // primitiveArgsOut + this->component.set_primitiveArgsOut_OutputPort(TypedPortIndex::TYPED, + this->get_from_primitiveArgsOut(TypedPortIndex::TYPED)); + + // primitiveReturnOut + this->component.set_primitiveReturnOut_OutputPort(0, this->get_from_primitiveReturnOut(0)); + + // stringArgsOut + this->component.set_stringArgsOut_OutputPort(TypedPortIndex::TYPED, + this->get_from_stringArgsOut(TypedPortIndex::TYPED)); + + // structArgsOut + this->component.set_structArgsOut_OutputPort(TypedPortIndex::TYPED, + this->get_from_structArgsOut(TypedPortIndex::TYPED)); + + // structReturnOut + this->component.set_structReturnOut_OutputPort(0, this->get_from_structReturnOut(0)); + + // textEventOut + this->component.set_textEventOut_OutputPort(0, this->get_from_textEventOut(0)); + + // tlmOut + this->component.set_tlmOut_OutputPort(0, this->get_from_tlmOut(0)); + + // ---------------------------------------------------------------------- + // Connect special ports + // ---------------------------------------------------------------------- + + // prmGetOut + this->component.set_prmGetOut_OutputPort(0, this->get_from_prmGetIn(0)); + + // ---------------------------------------------------------------------- + // Connect serial output ports + // ---------------------------------------------------------------------- + + this->component.set_noArgsOut_OutputPort(TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::NO_ARGS)); + + this->component.set_primitiveArgsOut_OutputPort(TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::PRIMITIVE)); + + this->component.set_stringArgsOut_OutputPort(TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::STRING)); + + this->component.set_enumArgsOut_OutputPort(TypedPortIndex::SERIAL, this->get_from_serialOut(SerialPortIndex::ENUM)); + + this->component.set_arrayArgsOut_OutputPort(TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::ARRAY)); + + this->component.set_structArgsOut_OutputPort(TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::STRUCT)); + + this->component.set_serialOut_OutputPort(SerialPortIndex::NO_ARGS, + this->get_from_noArgsOut(TypedPortIndex::SERIAL)); + + this->component.set_serialOut_OutputPort(SerialPortIndex::PRIMITIVE, + this->get_from_primitiveArgsOut(TypedPortIndex::SERIAL)); + + this->component.set_serialOut_OutputPort(SerialPortIndex::STRING, + this->get_from_stringArgsOut(TypedPortIndex::SERIAL)); + + this->component.set_serialOut_OutputPort(SerialPortIndex::ENUM, this->get_from_enumArgsOut(TypedPortIndex::SERIAL)); + + this->component.set_serialOut_OutputPort(SerialPortIndex::ARRAY, + this->get_from_arrayArgsOut(TypedPortIndex::SERIAL)); + + this->component.set_serialOut_OutputPort(SerialPortIndex::STRUCT, + this->get_from_structArgsOut(TypedPortIndex::SERIAL)); + + // ---------------------------------------------------------------------- + // Connect serial input ports + // ---------------------------------------------------------------------- + + // serialGuarded + for (NATIVE_INT_TYPE i = 0; i < 6; ++i) { + this->connect_to_serialGuarded(i, this->component.get_serialGuarded_InputPort(i)); + } + + // serialSync + for (NATIVE_INT_TYPE i = 0; i < 6; ++i) { + this->connect_to_serialSync(i, this->component.get_serialSync_InputPort(i)); + } +} + +void Tester ::connectPrmSetIn() { + // prmSetOut + this->component.set_prmSetOut_OutputPort(0, this->get_from_prmSetIn(0)); +} + +void Tester ::connectTimeGetOut() { + // timeGetOut + this->component.set_timeGetOut_OutputPort(0, this->get_from_timeGetOut(0)); +} + +void Tester ::connectSpecialPortsSerial() { + // cmdResponseOut + this->component.set_cmdResponseOut_OutputPort(0, this->get_from_serialOut(0)); + + // cmdRegOut + this->component.set_cmdRegOut_OutputPort(0, this->get_from_serialOut(0)); + + // eventOut + this->component.set_eventOut_OutputPort(0, this->get_from_serialOut(0)); + + // textEventOut + this->component.set_textEventOut_OutputPort(0, this->get_from_serialOut(0)); + + // tlmOut + this->component.set_tlmOut_OutputPort(0, this->get_from_serialOut(0)); + + // prmSetOut + this->component.set_prmSetOut_OutputPort(0, this->get_from_serialOut(0)); + + // timeGetOut + this->component.set_timeGetOut_OutputPort(0, this->get_from_serialOut(0)); +} + +void Tester ::setPrmValid(Fw::ParamValid valid) { + this->prmValid = valid; +} + +void Tester ::checkSerializeStatusSuccess() { + ASSERT_EQ(component.serializeStatus, Fw::FW_SERIALIZE_OK); +} + +void Tester ::checkSerializeStatusBufferEmpty() { + ASSERT_EQ(component.serializeStatus, Fw::FW_DESERIALIZE_BUFFER_EMPTY); +} diff --git a/FppTest/component/tests/Tests.cpp b/FppTest/component/tests/Tests.cpp new file mode 100644 index 0000000000..808018b1d9 --- /dev/null +++ b/FppTest/component/tests/Tests.cpp @@ -0,0 +1,115 @@ +// ====================================================================== +// \title Tests.cpp +// \author T. Chieu +// \brief cpp file for component tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/component/active/StringArgsPortAc.hpp" +#include "FppTest/component/types/FormalParamTypes.hpp" +#include "FppTest/typed_tests/ComponentTest.hpp" +#include "FppTest/typed_tests/PortTest.hpp" +#include "FppTest/typed_tests/StringTest.hpp" + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TypedAsyncPortTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SerialAsyncPortTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ComponentAsyncCommandTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ComponentInternalInterfaceTest); + +// Typed port tests +using TypedPortTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, TypedPortTest, TypedPortTestImplementations); + +// Serial port tests +using SerialPortTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, SerialPortTest, SerialPortTestImplementations); + +// String tests +using StringTestImplementations = + ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(Array, StringTest, StringTestImplementations); + +template <> +U32 FppTest::String::getSize() { + return 100; +} + +// Command tests +using CommandTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, ComponentCommandTest, CommandTestImplementations); +// Event tests +using EventTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, ComponentEventTest, EventTestImplementations); + +// Telemetry tests +using TelemetryTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, ComponentTelemetryTest, TelemetryTestImplementations); + +// Parameter tests +TEST(ComponentParameterTest, ParameterTest) { + Tester tester; + + tester.setPrmValid(Fw::ParamValid::VALID); + tester.testParam(); + + tester.setPrmValid(Fw::ParamValid::INVALID); + tester.testParam(); +} + +// Parameter tests +using ParamCommandTestImplementations = ::testing::Types; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, ComponentParamCommandTest, ParamCommandTestImplementations); + +// Time tests +TEST(ComponentTimeTest, TimeTest) { + Tester tester; + tester.testTime(); +} diff --git a/FppTest/component/tests/TimeTests.cpp b/FppTest/component/tests/TimeTests.cpp new file mode 100644 index 0000000000..41f034d085 --- /dev/null +++ b/FppTest/component/tests/TimeTests.cpp @@ -0,0 +1,42 @@ +// ====================================================================== +// \title TimeTests.cpp +// \author T. Chieu +// \brief cpp file for time tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "Fw/Time/Time.hpp" +#include "STest/Pick/Pick.hpp" +#include "test/ut/Tester.hpp" + +// ---------------------------------------------------------------------- +// Time test +// ---------------------------------------------------------------------- + +void Tester ::testTime() { + Fw::Time time(STest::Pick::any(), STest::Pick::any()); + Fw::Time zero_time(TB_NONE, 0, 0); + Fw::Time result; + + this->setTestTime(time); + + result = component.getTime(); + ASSERT_EQ(result, zero_time); + + this->connectTimeGetOut(); + ASSERT_TRUE(component.isConnected_timeGetOut_OutputPort(0)); + + result = component.getTime(); + ASSERT_EQ(result, time); + + this->connectSpecialPortsSerial(); + ASSERT_TRUE(component.isConnected_timeGetOut_OutputPort(0)); + + result = component.getTime(); + ASSERT_EQ(result, time); +} diff --git a/FppTest/component/tests/TlmTests.cpp b/FppTest/component/tests/TlmTests.cpp new file mode 100644 index 0000000000..2cedf185d0 --- /dev/null +++ b/FppTest/component/tests/TlmTests.cpp @@ -0,0 +1,16 @@ +// ====================================================================== +// \title TlmTests.cpp +// \author T. Chieu +// \brief cpp file for telemetry tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "TlmTests.hpp" +#include "test/ut/Tester.hpp" + +TLM_TEST_DEFS diff --git a/FppTest/component/tests/TlmTests.hpp b/FppTest/component/tests/TlmTests.hpp new file mode 100644 index 0000000000..c08153281a --- /dev/null +++ b/FppTest/component/tests/TlmTests.hpp @@ -0,0 +1,83 @@ +// ====================================================================== +// \title TlmTests.hpp +// \author T. Chieu +// \brief hpp file for telemetry tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +// ---------------------------------------------------------------------- +// Telemetry test declarations +// ---------------------------------------------------------------------- + +#define TLM_TEST_DECL(TYPE) void testTelemetry(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE##Param& data); + +#define TLM_TEST_DECLS \ + TLM_TEST_DECL(U32) \ + TLM_TEST_DECL(F32) \ + TLM_TEST_DECL(TlmString) \ + TLM_TEST_DECL(Enum) \ + TLM_TEST_DECL(Array) \ + TLM_TEST_DECL(Struct) + +// ---------------------------------------------------------------------- +// Telemetry test definitions +// ---------------------------------------------------------------------- + +#define TLM_TEST_DEF(TYPE) \ + void Tester ::testTelemetry(NATIVE_INT_TYPE portNum, FppTest::Types::TYPE##Param& data) { \ + ASSERT_TRUE(component.isConnected_tlmOut_OutputPort(portNum)); \ + \ + component.tlmWrite_Channel##TYPE(data.args.val); \ + \ + ASSERT_TLM_SIZE(1); \ + ASSERT_TLM_Channel##TYPE##_SIZE(1); \ + ASSERT_TLM_Channel##TYPE(0, data.args.val); \ + \ + Fw::Time time = Fw::ZERO_TIME; \ + component.tlmWrite_Channel##TYPE(data.args.val, time); \ + \ + ASSERT_TLM_SIZE(2); \ + ASSERT_TLM_Channel##TYPE##_SIZE(2); \ + ASSERT_TLM_Channel##TYPE(0, data.args.val); \ + } + +#define TLM_TEST_DEFS \ + TLM_TEST_DEF(U32) \ + TLM_TEST_DEF(F32) \ + \ + void Tester ::testTelemetry(NATIVE_INT_TYPE portNum, FppTest::Types::TlmStringParam& data) { \ + ASSERT_TRUE(component.isConnected_tlmOut_OutputPort(portNum)); \ + \ + component.tlmWrite_ChannelString(data.args.val); \ + \ + ASSERT_TLM_SIZE(1); \ + ASSERT_TLM_ChannelString_SIZE(1); \ + ASSERT_TLM_ChannelString(0, data.args.val.toChar()); \ + \ + /* Test unchanged value */ \ + component.tlmWrite_ChannelString(data.args.val); \ + \ + ASSERT_TLM_SIZE(1); \ + ASSERT_TLM_ChannelString_SIZE(1); \ + \ + FppTest::Types::TlmStringParam data2; \ + while (data2.args.val == data.args.val) { \ + data2 = FppTest::Types::TlmStringParam(); \ + } \ + \ + Fw::Time time = Fw::ZERO_TIME; \ + component.tlmWrite_ChannelString(data2.args.val, time); \ + \ + ASSERT_TLM_SIZE(2); \ + ASSERT_TLM_ChannelString_SIZE(2); \ + ASSERT_TLM_ChannelString(1, data2.args.val.toChar()); \ + } \ + \ + TLM_TEST_DEF(Enum) \ + TLM_TEST_DEF(Array) \ + TLM_TEST_DEF(Struct) diff --git a/FppTest/component/types/FormalParamTypes.cpp b/FppTest/component/types/FormalParamTypes.cpp new file mode 100644 index 0000000000..ba8f4e6106 --- /dev/null +++ b/FppTest/component/types/FormalParamTypes.cpp @@ -0,0 +1,193 @@ +// ====================================================================== +// \title FormalParamTypes.cpp +// \author T. Chieu +// \brief cpp file for formal param types +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FormalParamTypes.hpp" + +#include "FppTest/utils/Utils.hpp" +#include "STest/Pick/Pick.hpp" + +namespace FppTest { + +namespace Types { + +// ---------------------------------------------------------------------- +// Primitive types +// ---------------------------------------------------------------------- + +BoolType::BoolType() { + val = static_cast(STest::Pick::lowerUpper(0, 1)); +} + +U32Type::U32Type() { + val = STest::Pick::any(); +} + +F32Type::F32Type() { + val = static_cast(STest::Pick::any()); +} + +PrimitiveTypes::PrimitiveTypes() { + val1 = STest::Pick::any(); + val2 = STest::Pick::any(); + val3 = static_cast(STest::Pick::any()); + val4 = static_cast(STest::Pick::any()); + val5 = static_cast(STest::Pick::lowerUpper(0, 1)); + val6 = static_cast(STest::Pick::lowerUpper(0, 1)); +} + +// ---------------------------------------------------------------------- +// FPP types +// ---------------------------------------------------------------------- + +EnumType::EnumType() { + val = getRandomFormalParamEnum(); +} + +EnumTypes::EnumTypes() { + val1 = getRandomFormalParamEnum(); + val2 = getRandomFormalParamEnum(); +} + +ArrayType::ArrayType() { + getRandomFormalParamArray(val); +} + +ArrayTypes::ArrayTypes() { + getRandomFormalParamArray(val1); + getRandomFormalParamArray(val2); +} + +StructType::StructType() { + val = getRandomFormalParamStruct(); +} + +StructTypes::StructTypes() { + val1 = getRandomFormalParamStruct(); + val2 = getRandomFormalParamStruct(); +} + +// ---------------------------------------------------------------------- +// String types +// ---------------------------------------------------------------------- + +PortStringType::PortStringType() { + setRandomString(val); +} + +PortStringTypes::PortStringTypes() { + setRandomString(val1); + setRandomString(val2); + setRandomString(val3); + setRandomString(val4); +} + +InternalInterfaceStringType::InternalInterfaceStringType() { + setRandomString(val); +} + +InternalInterfaceStringTypes::InternalInterfaceStringTypes() { + setRandomString(val1); + setRandomString(val2); +} + +CmdStringType::CmdStringType() { + setRandomString(val, FW_CMD_STRING_MAX_SIZE); +} + +CmdStringTypes::CmdStringTypes() { + setRandomString(val1, FW_CMD_STRING_MAX_SIZE / 2); + setRandomString(val2, FW_CMD_STRING_MAX_SIZE / 2); +} + +LogStringType::LogStringType() { + setRandomString(val, FW_LOG_STRING_MAX_SIZE); +} + +LogStringTypes::LogStringTypes() { + setRandomString(val1, FW_LOG_STRING_MAX_SIZE / 2); + setRandomString(val2, FW_LOG_STRING_MAX_SIZE / 2); +} + +TlmStringType::TlmStringType() { + setRandomString(val, FW_TLM_STRING_MAX_SIZE); +} + +TlmStringTypes::TlmStringTypes() { + setRandomString(val1, FW_TLM_STRING_MAX_SIZE / 2); + setRandomString(val2, FW_TLM_STRING_MAX_SIZE / 2); +} + +PrmStringType::PrmStringType() { + setRandomString(val, FW_PARAM_STRING_MAX_SIZE); +} + +PrmStringTypes::PrmStringTypes() { + setRandomString(val1, FW_PARAM_STRING_MAX_SIZE / 2); + setRandomString(val2, FW_PARAM_STRING_MAX_SIZE / 2); +} + +// ---------------------------------------------------------------------- +// Serial type +// ---------------------------------------------------------------------- + +SerialType::SerialType() : val(data, sizeof(data)) { + U32 len = STest::Pick::lowerUpper(1, SERIAL_ARGS_BUFFER_CAPACITY); + + for (U32 i = 0; i < len; i++) { + data[i] = Utils::getNonzeroU8(); + } +} + +// ---------------------------------------------------------------------- +// Helper functions +// ---------------------------------------------------------------------- + +void setRandomString(Fw::StringBase& str) { + char buf[str.getCapacity()]; + Utils::setString(buf, sizeof(buf)); + str = buf; +} + +void setRandomString(Fw::StringBase& str, U32 size) { + char buf[size]; + Utils::setString(buf, size); + str = buf; +} + +FormalParamEnum getRandomFormalParamEnum() { + FormalParamEnum e; + + e = static_cast(STest::Pick::lowerUpper(0, FormalParamEnum::NUM_CONSTANTS - 1)); + + return e; +} + +void getRandomFormalParamArray(FormalParamArray& a) { + for (U32 i = 0; i < FormalParamArray::SIZE; i++) { + a[i] = STest::Pick::any(); + } +} + +FormalParamStruct getRandomFormalParamStruct() { + FormalParamStruct s; + char buf[s.gety().getCapacity()]; + FormalParamStruct::StringSize80 str = buf; + + Utils::setString(buf, sizeof(buf)); + s.set(STest::Pick::any(), str); + + return s; +} + +} // namespace Types + +} // namespace FppTest diff --git a/FppTest/component/types/FormalParamTypes.hpp b/FppTest/component/types/FormalParamTypes.hpp new file mode 100644 index 0000000000..b8fbdaade7 --- /dev/null +++ b/FppTest/component/types/FormalParamTypes.hpp @@ -0,0 +1,266 @@ +// ====================================================================== +// \title FormalParamTypes.hpp +// \author T. Chieu +// \brief hpp file for formal param types +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_FORMAL_PARAM_TYPES_HPP +#define FPP_TEST_FORMAL_PARAM_TYPES_HPP + +#include "Fw/Cmd/CmdString.hpp" +#include "Fw/Log/LogString.hpp" +#include "Fw/Prm/PrmString.hpp" +#include "Fw/Tlm/TlmString.hpp" +#include "Fw/Types/InternalInterfaceString.hpp" +#include "Fw/Types/SerialBuffer.hpp" + +#include "FppTest/component/active/FormalParamArrayArrayAc.hpp" +#include "FppTest/component/active/FormalParamEnumEnumAc.hpp" +#include "FppTest/component/active/FormalParamStructSerializableAc.hpp" +#include "FppTest/component/active/StringArgsPortAc.hpp" +#include "FppTest/utils/Utils.hpp" + +#define SERIAL_ARGS_BUFFER_CAPACITY 256 + +namespace FppTest { + +namespace Types { + +template +struct FormalParamsWithReturn { + ArgType args; +}; + +// Empty type +struct Empty {}; + +template +using FormalParams = FormalParamsWithReturn; + +// ---------------------------------------------------------------------- +// Primitive types +// ---------------------------------------------------------------------- + +struct BoolType { + BoolType(); + + bool val; +}; + +struct U32Type { + U32Type(); + + U32 val; +}; + +struct F32Type { + F32Type(); + + F32 val; +}; + +struct PrimitiveTypes { + PrimitiveTypes(); + + U32 val1; + U32 val2; + F32 val3; + F32 val4; + bool val5; + bool val6; +}; + +// ---------------------------------------------------------------------- +// FPP types +// ---------------------------------------------------------------------- + +struct EnumType { + EnumType(); + + FormalParamEnum val; +}; + +struct EnumTypes { + EnumTypes(); + + FormalParamEnum val1; + FormalParamEnum val2; +}; + +struct ArrayType { + ArrayType(); + + FormalParamArray val; +}; + +struct ArrayTypes { + ArrayTypes(); + + FormalParamArray val1; + FormalParamArray val2; +}; + +struct StructType { + StructType(); + + FormalParamStruct val; +}; + +struct StructTypes { + StructTypes(); + + FormalParamStruct val1; + FormalParamStruct val2; +}; + +// ---------------------------------------------------------------------- +// String types +// ---------------------------------------------------------------------- + +struct PortStringType { + PortStringType(); + + StringArgsPortStrings::StringSize80 val; +}; + +struct PortStringTypes { + PortStringTypes(); + + StringArgsPortStrings::StringSize80 val1; + StringArgsPortStrings::StringSize80 val2; + StringArgsPortStrings::StringSize100 val3; + StringArgsPortStrings::StringSize100 val4; +}; + +struct InternalInterfaceStringType { + InternalInterfaceStringType(); + + Fw::InternalInterfaceString val; +}; + +struct InternalInterfaceStringTypes { + InternalInterfaceStringTypes(); + + Fw::InternalInterfaceString val1; + Fw::InternalInterfaceString val2; +}; + +struct CmdStringType { + CmdStringType(); + + Fw::CmdStringArg val; +}; + +struct CmdStringTypes { + CmdStringTypes(); + + Fw::CmdStringArg val1; + Fw::CmdStringArg val2; +}; + +struct LogStringType { + LogStringType(); + + Fw::LogStringArg val; +}; + +struct LogStringTypes { + LogStringTypes(); + + Fw::LogStringArg val1; + Fw::LogStringArg val2; +}; + +struct TlmStringType { + TlmStringType(); + + Fw::TlmString val; +}; + +struct TlmStringTypes { + TlmStringTypes(); + + Fw::TlmString val1; + Fw::TlmString val2; +}; + +struct PrmStringType { + PrmStringType(); + + Fw::ParamString val; +}; + +struct PrmStringTypes { + PrmStringTypes(); + + Fw::ParamString val1; + Fw::ParamString val2; +}; + +// ---------------------------------------------------------------------- +// Serial type +// ---------------------------------------------------------------------- + +struct SerialType { + SerialType(); + + U8 data[SERIAL_ARGS_BUFFER_CAPACITY]; + Fw::SerialBuffer val; +}; + +// ---------------------------------------------------------------------- +// Helper functions +// ---------------------------------------------------------------------- + +void setRandomString(Fw::StringBase& str); +void setRandomString(Fw::StringBase& str, U32 size); +FormalParamEnum getRandomFormalParamEnum(); +void getRandomFormalParamArray(FormalParamArray& a); +FormalParamStruct getRandomFormalParamStruct(); + +// ---------------------------------------------------------------------- +// Typedefs +// ---------------------------------------------------------------------- + +typedef FormalParams NoParams; +typedef FormalParams BoolParam; +typedef FormalParams U32Param; +typedef FormalParams F32Param; +typedef FormalParams PrimitiveParams; +typedef FormalParams EnumParam; +typedef FormalParams EnumParams; +typedef FormalParams ArrayParam; +typedef FormalParams ArrayParams; +typedef FormalParams StructParam; +typedef FormalParams StructParams; +typedef FormalParams PortStringParam; +typedef FormalParams PortStringParams; +typedef FormalParams InternalInterfaceStringParam; +typedef FormalParams InternalInterfaceStringParams; +typedef FormalParams CmdStringParam; +typedef FormalParams CmdStringParams; +typedef FormalParams LogStringParam; +typedef FormalParams LogStringParams; +typedef FormalParams TlmStringParam; +typedef FormalParams TlmStringParams; +typedef FormalParams PrmStringParam; +typedef FormalParams PrmStringParams; +typedef FormalParams SerialParam; + +typedef FormalParamsWithReturn NoParamReturn; +typedef FormalParamsWithReturn PrimitiveReturn; +typedef FormalParamsWithReturn EnumReturn; +typedef FormalParamsWithReturn ArrayReturn; +typedef FormalParamsWithReturn StructReturn; + +} // namespace Types + +} // namespace FppTest + +#endif diff --git a/FppTest/port/Example.cpp b/FppTest/port/Example.cpp deleted file mode 100644 index 8a679f7a2f..0000000000 --- a/FppTest/port/Example.cpp +++ /dev/null @@ -1,192 +0,0 @@ -// ====================================================================== -// \title Example.cpp -// \author T. Chieu -// \brief cpp file for Example component implementation class -// ====================================================================== - - -#include -#include - - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - Example :: - Example( - const char *const compName - ) : ExampleComponentBase(compName) - { - - } - - void Example :: - init( - const NATIVE_INT_TYPE instance - ) - { - ExampleComponentBase::init(instance); - } - - Example :: - ~Example() - { - - } - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - void Example :: - arrayArgsIn_handler( - const NATIVE_INT_TYPE portNum, - const PortArray &a, - PortArray &aRef - ) - { - this->arrayArgsOut_out(portNum, a, aRef); - } - - PortArray Example :: - arrayReturnIn_handler( - const NATIVE_INT_TYPE portNum, - const PortArray &a, - PortArray &aRef - ) - { - return this->arrayReturnOut_out(portNum, a, aRef); - } - - void Example :: - enumArgsIn_handler( - const NATIVE_INT_TYPE portNum, - const PortEnum &e, - PortEnum &eRef - ) - { - this->enumArgsOut_out(portNum, e, eRef); - } - - PortEnum Example :: - enumReturnIn_handler( - const NATIVE_INT_TYPE portNum, - const PortEnum &e, - PortEnum &eRef - ) - { - return this->enumReturnOut_out(portNum, e, eRef); - } - - void Example :: - noArgsIn_handler( - const NATIVE_INT_TYPE portNum - ) - { - this->noArgsOut_out(portNum); - } - - bool Example :: - noArgsReturnIn_handler( - const NATIVE_INT_TYPE portNum - ) - { - return this->noArgsReturnOut_out(portNum); - } - - void Example :: - primitiveArgsIn_handler( - const NATIVE_INT_TYPE portNum, - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ) - { - this->primitiveArgsOut_out( - portNum, - u32, - u32Ref, - f32, - f32Ref, - b, - bRef - ); - } - - U32 Example :: - primitiveReturnIn_handler( - const NATIVE_INT_TYPE portNum, - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ) - { - return this->primitiveReturnOut_out( - portNum, - u32, - u32Ref, - f32, - f32Ref, - b, - bRef - ); - } - - void Example :: - stringArgsIn_handler( - const NATIVE_INT_TYPE portNum, - const str80String &str80, - str80RefString &str80Ref, - const str100String &str100, - str100RefString &str100Ref - ) - { - this->stringArgsOut_out( - portNum, - str80, - str80Ref, - str100, - str100Ref - ); - } - - void Example :: - structArgsIn_handler( - const NATIVE_INT_TYPE portNum, - const PortStruct &s, - PortStruct &sRef - ) - { - this->structArgsOut_out(portNum, s, sRef); - } - - PortStruct Example :: - structReturnIn_handler( - const NATIVE_INT_TYPE portNum, - const PortStruct &s, - PortStruct &sRef - ) - { - return this->structReturnOut_out(portNum, s, sRef); - } - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined serial input ports - // ---------------------------------------------------------------------- - - void Example :: - serialIn_handler( - NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ - ) - { - this->serializeStatus = this->serialOut_out(portNum, Buffer); - } - diff --git a/FppTest/port/Example.hpp b/FppTest/port/Example.hpp deleted file mode 100644 index 75510209aa..0000000000 --- a/FppTest/port/Example.hpp +++ /dev/null @@ -1,188 +0,0 @@ -// ====================================================================== -// \title Example.hpp -// \author T. Chieu -// \brief hpp file for Example component implementation class -// ====================================================================== - -#ifndef Example_HPP -#define Example_HPP - -#include "FppTest/port/ExampleComponentAc.hpp" - - - class Example : - public ExampleComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object Example - //! - Example( - const char *const compName /*!< The component name*/ - ); - - //! Initialize object Example - //! - void init( - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - //! Destroy object Example - //! - ~Example(); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for arrayArgsIn - //! - void arrayArgsIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortArray &a, /*!< - An array - */ - PortArray &aRef /*!< - An array ref - */ - ); - - //! Handler implementation for arrayReturnIn - //! - PortArray arrayReturnIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortArray &a, /*!< - An array - */ - PortArray &aRef /*!< - An array ref - */ - ); - - //! Handler implementation for enumArgsIn - //! - void enumArgsIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortEnum &e, /*!< - An enum - */ - PortEnum &eRef /*!< - An enum ref - */ - ); - - //! Handler implementation for enumReturnIn - //! - PortEnum enumReturnIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortEnum &e, /*!< - An enum - */ - PortEnum &eRef /*!< - An enum ref - */ - ); - - //! Handler implementation for noArgsIn - //! - void noArgsIn_handler( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Handler implementation for noArgsReturnIn - //! - bool noArgsReturnIn_handler( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Handler implementation for primitiveArgsIn - //! - void primitiveArgsIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ); - - //! Handler implementation for primitiveReturnIn - //! - U32 primitiveReturnIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ); - - //! Handler implementation for stringArgsIn - //! - void stringArgsIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const str80String &str80, /*!< - A string of size 80 - */ - str80RefString &str80Ref, - const str100String &str100, /*!< - A string of size 100 - */ - str100RefString &str100Ref - ); - - //! Handler implementation for structArgsIn - //! - void structArgsIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortStruct &s, /*!< - A struct - */ - PortStruct &sRef /*!< - A struct ref - */ - ); - - //! Handler implementation for structReturnIn - //! - PortStruct structReturnIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortStruct &s, /*!< - A struct - */ - PortStruct &sRef /*!< - A struct ref - */ - ); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined serial input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for serialIn - //! - void serialIn_handler( - NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ - ); - - public: - - //! Enables checking the serialization status of serial port invocations - Fw::SerializeStatus serializeStatus; - - }; - - -#endif diff --git a/FppTest/port/PortTypes.cpp b/FppTest/port/PortTypes.cpp deleted file mode 100644 index bb774e6b90..0000000000 --- a/FppTest/port/PortTypes.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// ====================================================================== -// \title PortTypes.cpp -// \author T. Chieu -// \brief cpp file for port types -// -// \copyright -// Copyright (C) 2009-2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include "PortTypes.hpp" - -#include "STest/Pick/Pick.hpp" -#include "FppTest/utils/Utils.hpp" - -namespace FppTest { - - namespace Port { - - // ---------------------------------------------------------------------- - // Argument types - // ---------------------------------------------------------------------- - - PrimitiveArgs::PrimitiveArgs() { - u32 = STest::Pick::any(); - u32Ref = STest::Pick::any(); - f32 = static_cast(STest::Pick::any()); - f32Ref = static_cast(STest::Pick::any()); - b = static_cast(STest::Pick::lowerUpper(0, 1)); - bRef = static_cast(STest::Pick::lowerUpper(0, 1)); - } - - StringArgs::StringArgs() { - char buf80[str80.getCapacity()]; - char buf100[str100.getCapacity()]; - - Utils::setString(buf80, sizeof(buf80)); - Utils::setString(buf100, sizeof(buf100)); - - str80 = buf80; - str100 = buf100; - - Utils::setString(buf80, sizeof(buf80)); - Utils::setString(buf100, sizeof(buf100)); - - str80Ref = buf80; - str100Ref = buf100; - } - - EnumArgs::EnumArgs() { - en = getRandomPortEnum(); - enRef = getRandomPortEnum(); - } - - ArrayArgs::ArrayArgs() { - a = getRandomPortArray(); - aRef = getRandomPortArray(); - } - - StructArgs::StructArgs() { - s = getRandomPortStruct(); - sRef = getRandomPortStruct(); - } - - SerialArgs::SerialArgs() : buf(data, sizeof(data)) { - U32 len = STest::Pick::lowerUpper(1, SERIAL_ARGS_BUFFER_CAPACITY); - - for (U32 i = 0; i < len; i++) { - data[i] = Utils::getU8(); - } - } - - // ---------------------------------------------------------------------- - // Return types - // ---------------------------------------------------------------------- - - - BoolReturn::BoolReturn() { - val = static_cast(STest::Pick::lowerUpper(0, 1)); - } - - PrimitiveReturn::PrimitiveReturn() { - val = STest::Pick::any(); - } - - EnumReturn::EnumReturn() { - val = getRandomPortEnum(); - } - - ArrayReturn::ArrayReturn() { - val = getRandomPortArray(); - } - - StructReturn::StructReturn() { - val = getRandomPortStruct(); - } - - // ---------------------------------------------------------------------- - // Helper functions - // ---------------------------------------------------------------------- - - PortEnum getRandomPortEnum() { - PortEnum e; - - e = static_cast(STest::Pick::lowerUpper( - 0, - PortEnum::NUM_CONSTANTS - 1 - )); - - return e; - } - - PortArray getRandomPortArray() { - PortArray a; - - for (U32 i = 0; i < PortArray::SIZE; i++) { - a[i] = STest::Pick::any(); - } - - return a; - } - - PortStruct getRandomPortStruct() { - PortStruct s; - char buf[s.gety().getCapacity()]; - PortStruct::StringSize80 str = buf; - - Utils::setString(buf, sizeof(buf)); - s.set(STest::Pick::any(), str); - - return s; - } - - } // namespace Port - -} // namespace FppTest diff --git a/FppTest/port/PortTypes.hpp b/FppTest/port/PortTypes.hpp deleted file mode 100644 index 0ae7e62c81..0000000000 --- a/FppTest/port/PortTypes.hpp +++ /dev/null @@ -1,154 +0,0 @@ -// ====================================================================== -// \title PortTypes.hpp -// \author T. Chieu -// \brief hpp file for port types -// -// \copyright -// Copyright (C) 2009-2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef FPP_TEST_PORT_STRUCTS_HPP -#define FPP_TEST_PORT_STRUCTS_HPP - -#include "Fw/Types/SerialBuffer.hpp" - -#include "FppTest/port/PortEnumEnumAc.hpp" -#include "FppTest/port/PortArrayArrayAc.hpp" -#include "FppTest/port/PortStructSerializableAc.hpp" -#include "FppTest/port/StringArgsPortAc.hpp" - -#define SERIAL_ARGS_BUFFER_CAPACITY 256 - -namespace FppTest { - - namespace Port { - - // PortType template - template - struct PortType { - ArgType args; - }; - - // Empty type - struct Empty {}; - - // ---------------------------------------------------------------------- - // Argument types - // ---------------------------------------------------------------------- - - struct PrimitiveArgs { - PrimitiveArgs(); - - U32 u32; - U32 u32Ref; - F32 f32; - F32 f32Ref; - bool b; - bool bRef; - }; - - struct StringArgs { - StringArgs(); - - StringArgsPortStrings::StringSize80 str80; - StringArgsPortStrings::StringSize80 str80Ref; - StringArgsPortStrings::StringSize100 str100; - StringArgsPortStrings::StringSize100 str100Ref; - }; - - struct EnumArgs { - EnumArgs(); - - PortEnum en; - PortEnum enRef; - }; - - struct ArrayArgs { - ArrayArgs(); - - PortArray a; - PortArray aRef; - }; - - struct StructArgs { - StructArgs(); - - PortStruct s; - PortStruct sRef; - }; - - struct SerialArgs { - SerialArgs(); - - U8 data[SERIAL_ARGS_BUFFER_CAPACITY]; - Fw::SerialBuffer buf; - }; - - // ---------------------------------------------------------------------- - // Return types - // ---------------------------------------------------------------------- - - struct BoolReturn { - BoolReturn(); - - bool val; - }; - - struct PrimitiveReturn { - PrimitiveReturn(); - - U32 val; - }; - - struct EnumReturn { - EnumReturn(); - - PortEnum val; - }; - - struct ArrayReturn { - ArrayReturn(); - - PortArray val; - }; - - struct StructReturn { - StructReturn(); - - PortStruct val; - }; - - // ---------------------------------------------------------------------- - // Helper functions - // ---------------------------------------------------------------------- - - PortEnum getRandomPortEnum(); - PortArray getRandomPortArray(); - PortStruct getRandomPortStruct(); - - // ---------------------------------------------------------------------- - // Typedefs - // ---------------------------------------------------------------------- - - typedef PortType NoArgsPort; - typedef PortType PrimitiveArgsPort; - typedef PortType StringArgsPort; - typedef PortType EnumArgsPort; - typedef PortType ArrayArgsPort; - typedef PortType StructArgsPort; - typedef PortType SerialArgsPort; - - typedef PortType NoArgsReturnPort; - typedef PortType PrimitiveReturnPort; - typedef PortType EnumReturnPort; - typedef PortType ArrayReturnPort; - typedef PortType StructReturnPort; - - } // namespace Port - -} // namespace FppTest - -#endif diff --git a/FppTest/port/README.md b/FppTest/port/README.md deleted file mode 100644 index 452871ab5f..0000000000 --- a/FppTest/port/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# FppTest/port - -This directory contains unit tests for the FPP port code generator. - -* Supports unit tests for typed-to-typed, typed-to-serial, serial-to-typed, and -serial-to-serial port connections - -To use this directory, you must have installed F Prime, and you must be inside -the F Prime Python virtual environment. - -* To build the tests, run `fprime-util build --ut`. -* To run the tests, run `fprime-util check`. - -## Generating Coverage - -Mainline F Prime doesn't generate coverage for autocoded files in a -reliable way. This directory contains some workaround scripts for -generating coverage. To generate coverage, do the following: - -``` -% fprime-util build --ut -% ./build-exe -% ./exe -% ./gen-cov-all -``` - -The output will go to the console and to `.gcov` files. To run the -coverage analysis for one file, replace the last line with `./gen-cov` -followed by the base file name, without `.cpp` or `.hpp`. For example: - -``` -% ./gen-cov NoArgsPortAc -``` diff --git a/FppTest/port/build-exe b/FppTest/port/build-exe deleted file mode 100755 index c887e28927..0000000000 --- a/FppTest/port/build-exe +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -fprime=../.. -build_cache=$fprime/FppTest/build-fprime-automatic-native-ut -srcs=" -`find . -name '*.cpp'` -`find ../utils -name '*.cpp'` -`find $build_cache/FppTest/port -name '*.cpp' | grep -v Tester.cpp | grep -v TestMain.cpp` -" -srcs=`echo $srcs | tr '\n' ' '` -flags=" ---coverage ---std=c++11 --DBUILD_UT --DPRIVATE=public --DPROTECTED=public --DTGT_OS_TYPE_DARWIN --I$build_cache --I$build_cache/F-Prime --I$build_cache/FppTest/port --I$fprime --I$fprime/STest --I$fprime/cmake/platform/types --I$fprime/config --I$fprime/gtest/googletest-src/googletest --I$fprime/gtest/googletest-src/googletest/include --I. -" -cmd="g++ -c $flags $srcs" -echo $cmd -$cmd - -libs=`find $build_cache -name '*.a'` -ofiles=`ls *.o` -cmd="g++ --coverage $ofiles $libs -o exe" -echo $cmd -$cmd diff --git a/FppTest/port/clean b/FppTest/port/clean deleted file mode 100755 index 560e745ee2..0000000000 --- a/FppTest/port/clean +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -rm -f *.o *.gcno *.gcda *.html *.gcov exe diff --git a/FppTest/port/example_comp.fpp b/FppTest/port/example_comp.fpp deleted file mode 100644 index c436649483..0000000000 --- a/FppTest/port/example_comp.fpp +++ /dev/null @@ -1,62 +0,0 @@ -@ An example component -passive component Example { - - # Typed input ports with no return types - - sync input port noArgsIn: [2] NoArgs - - sync input port primitiveArgsIn: [2] PrimitiveArgs - - sync input port stringArgsIn: [2] StringArgs - - sync input port enumArgsIn: [2] EnumArgs - - sync input port arrayArgsIn: [2] ArrayArgs - - sync input port structArgsIn: [2] StructArgs - - # Typed output ports with no return types - - output port noArgsOut: [2] NoArgs - - output port primitiveArgsOut: [2] PrimitiveArgs - - output port stringArgsOut: [2] StringArgs - - output port enumArgsOut: [2] EnumArgs - - output port arrayArgsOut: [2] ArrayArgs - - output port structArgsOut: [2] StructArgs - - # Typed input ports with return types - - sync input port noArgsReturnIn: NoArgsReturn - - sync input port primitiveReturnIn: PrimitiveReturn - - sync input port enumReturnIn: EnumReturn - - sync input port arrayReturnIn: ArrayReturn - - sync input port structReturnIn: StructReturn - - # Typed output ports with return types - - output port noArgsReturnOut: NoArgsReturn - - output port primitiveReturnOut: PrimitiveReturn - - output port enumReturnOut: EnumReturn - - output port arrayReturnOut: ArrayReturn - - output port structReturnOut: StructReturn - - # Serial ports - - sync input port serialIn: [7] serial - - output port serialOut: [7] serial - -} diff --git a/FppTest/port/fpp_types.fpp b/FppTest/port/fpp_types.fpp deleted file mode 100644 index 2ee9116103..0000000000 --- a/FppTest/port/fpp_types.fpp +++ /dev/null @@ -1,5 +0,0 @@ -enum PortEnum { X, Y, Z } - -array PortArray = [3] U32 - -struct PortStruct { x: U32, y: string } diff --git a/FppTest/port/gen-cov b/FppTest/port/gen-cov deleted file mode 100755 index 6cdfbb91a2..0000000000 --- a/FppTest/port/gen-cov +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -if ! test $# -eq 1 -then - echo 'usage: gen-cov file-base' 1>&2 - exit 1 -fi - -base=$1 -fpp_test=../build-fprime-automatic-native-ut/FppTest -src=`find $fpp_test -name $base.cpp` -gcov -o $base.gcno $src diff --git a/FppTest/port/gen-cov-all b/FppTest/port/gen-cov-all deleted file mode 100755 index 71e645e1bd..0000000000 --- a/FppTest/port/gen-cov-all +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -for file in `ls *Ac.gcno` -do - base=`basename $file .gcno` - cmd="./gen-cov $base" - echo $cmd - $cmd -done diff --git a/FppTest/port/gen-cov-html b/FppTest/port/gen-cov-html deleted file mode 100755 index a99389d369..0000000000 --- a/FppTest/port/gen-cov-html +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -if [ ! -d "coverage/" ] -then - mkdir coverage -fi - -gcovr -r .. --html-details -f '(.*)PortAc\.cpp$' -o coverage/coverage.html . diff --git a/FppTest/port/no_return_ports.fpp b/FppTest/port/no_return_ports.fpp deleted file mode 100644 index b5ae2a8a0f..0000000000 --- a/FppTest/port/no_return_ports.fpp +++ /dev/null @@ -1,38 +0,0 @@ -@ A port with no arguments -port NoArgs - -@ A port with primitive arguments -port PrimitiveArgs( - u32: U32 - ref u32Ref: U32 - f32: F32 - ref f32Ref: F32 - b: bool - ref bRef: bool -) - -@ A port with string arguments -port StringArgs( - str80: string @< A string of size 80 - ref str80Ref: string - str100: string size 100 @< A string of size 100 - ref str100Ref: string size 100 -) - -@ A port with enum arguments -port EnumArgs( - en: PortEnum @< An enum - ref enRef: PortEnum @< An enum ref -) - -@ A port with array arguments -port ArrayArgs( - a: PortArray @< An array - ref aRef: PortArray @< An array ref -) - -@ A port with struct arguments -port StructArgs( - s: PortStruct @< A struct - ref sRef: PortStruct @< A struct ref -) diff --git a/FppTest/port/return_ports.fpp b/FppTest/port/return_ports.fpp deleted file mode 100644 index 3a645589b8..0000000000 --- a/FppTest/port/return_ports.fpp +++ /dev/null @@ -1,40 +0,0 @@ -@ A port with no arguments -port NoArgsReturn -> bool - -@ A port returning a primitive type -port PrimitiveReturn( - u32: U32 - ref u32Ref: U32 - f32: F32 - ref f32Ref: F32 - b: bool - ref bRef: bool -) -> U32 - -# Commented out because of bug in Python component autocoder -# Will be tested with the FPP component autocoder -# @ A port returning a string type -# port StringReturn( -# str80: string @< A string of size 80 -# ref str80Ref: string -# str100: string size 100 @< A string of size 100 -# ref str100Ref: string size 100 -# ) -> string - -@ A port returning an enum type -port EnumReturn( - en: PortEnum @< An enum - ref enRef: PortEnum @< An enum ref -) -> PortEnum - -@ A port returning an array type -port ArrayReturn( - a: PortArray @< An array - ref aRef: PortArray @< An array ref -) -> PortArray - -@ A port returning a struct type -port StructReturn( - s: PortStruct @< A struct - ref sRef: PortStruct @< A struct ref -) -> PortStruct diff --git a/FppTest/port/test/ut/TestMain.cpp b/FppTest/port/test/ut/TestMain.cpp deleted file mode 100644 index 8d6f703952..0000000000 --- a/FppTest/port/test/ut/TestMain.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// ====================================================================== -// \title TestMain.cpp -// \author T. Chieu -// \brief main cpp file for FPP port tests -// -// \copyright -// Copyright (C) 2009-2023 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - - -#include "Tester.hpp" -#include "FppTest/port/PortTypes.hpp" -#include "FppTest/typed_tests/PortTest.hpp" -#include "FppTest/typed_tests/StringTest.hpp" -#include "FppTest/port/StringArgsPortAc.hpp" - -#include "gtest/gtest.h" - -// Typed port tests -using TypedPortTestImplementations = ::testing::Types< - FppTest::Port::NoArgsPort, - FppTest::Port::PrimitiveArgsPort, - FppTest::Port::StringArgsPort, - FppTest::Port::EnumArgsPort, - FppTest::Port::ArrayArgsPort, - FppTest::Port::StructArgsPort, - FppTest::Port::NoArgsReturnPort, - FppTest::Port::PrimitiveReturnPort, - FppTest::Port::EnumReturnPort, - FppTest::Port::ArrayReturnPort, - FppTest::Port::StructReturnPort ->; - -INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, - TypedPortTest, - TypedPortTestImplementations); - -// Serial port tests -using SerialPortTestImplementations = ::testing::Types< - FppTest::Port::NoArgsPort, - FppTest::Port::PrimitiveArgsPort, - FppTest::Port::StringArgsPort, - FppTest::Port::EnumArgsPort, - FppTest::Port::ArrayArgsPort, - FppTest::Port::StructArgsPort -// FppTest::Port::SerialArgsPort ->; - -INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, - SerialPortTest, - SerialPortTestImplementations); - -// String tests -using StringTestImplementations = ::testing::Types< - StringArgsPortStrings::StringSize80, - StringArgsPortStrings::StringSize100 ->; - -INSTANTIATE_TYPED_TEST_SUITE_P(Array, StringTest, StringTestImplementations); - -template<> -U32 FppTest::String::getSize() { - return 100; -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/FppTest/port/test/ut/Tester.cpp b/FppTest/port/test/ut/Tester.cpp deleted file mode 100644 index 2126120dac..0000000000 --- a/FppTest/port/test/ut/Tester.cpp +++ /dev/null @@ -1,1409 +0,0 @@ -// ====================================================================== -// \title Tester.cpp -// \author T. Chieu -// \brief cpp file for Example test harness implementation class -// ====================================================================== - -#include "Tester.hpp" - -#define INSTANCE 0 -#define MAX_HISTORY_SIZE 10 - - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - Tester :: - Tester() : - ExampleGTestBase("Tester", MAX_HISTORY_SIZE), - component("Example"), - primitiveBuf(primitiveData, sizeof(primitiveData)), - stringBuf(stringData, sizeof(stringData)), - enumBuf(enumData, sizeof(enumData)), - arrayBuf(arrayData, sizeof(arrayData)), - structBuf(structData, sizeof(structData)), - serialBuf(serialData, sizeof(serialData)) - { - this->initComponents(); - this->connectPorts(); - } - - Tester :: - ~Tester() - { - - } - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void Tester :: - toDo() - { - // TODO - } - - // ---------------------------------------------------------------------- - // Invoke typed input ports - // ---------------------------------------------------------------------- - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::NoArgsPort& port - ) - { - this->invoke_to_noArgsIn(portNum); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::PrimitiveArgsPort& port - ) - { - this->invoke_to_primitiveArgsIn( - portNum, - port.args.u32, - port.args.u32Ref, - port.args.f32, - port.args.f32Ref, - port.args.b, - port.args.bRef - ); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::StringArgsPort& port - ) - { - this->invoke_to_stringArgsIn( - portNum, - port.args.str80, - port.args.str80Ref, - port.args.str100, - port.args.str100Ref - ); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::EnumArgsPort& port - ) - { - this->invoke_to_enumArgsIn( - portNum, - port.args.en, - port.args.enRef - ); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::ArrayArgsPort& port - ) - { - this->invoke_to_arrayArgsIn( - portNum, - port.args.a, - port.args.aRef - ); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::StructArgsPort& port - ) - { - this->invoke_to_structArgsIn( - portNum, - port.args.s, - port.args.sRef - ); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::SerialArgsPort& port - ) - { - this->invoke_to_serialIn( - portNum, - port.args.buf - ); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::NoArgsReturnPort& port - ) - { - bool returnVal = this->invoke_to_noArgsReturnIn(portNum); - - ASSERT_EQ(returnVal, this->noArgsReturnVal.val); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::PrimitiveReturnPort& port - ) - { - U32 returnVal = this->invoke_to_primitiveReturnIn( - portNum, - port.args.u32, - port.args.u32Ref, - port.args.f32, - port.args.f32Ref, - port.args.b, - port.args.bRef - ); - - ASSERT_EQ(returnVal, this->primitiveReturnVal.val); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::EnumReturnPort& port - ) - { - PortEnum returnVal = this->invoke_to_enumReturnIn( - portNum, - port.args.en, - port.args.enRef - ); - - ASSERT_EQ(returnVal, this->enumReturnVal.val); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::ArrayReturnPort& port - ) - { - PortArray returnVal = this->invoke_to_arrayReturnIn( - portNum, - port.args.a, - port.args.aRef - ); - - ASSERT_EQ(returnVal, this->arrayReturnVal.val); - } - - void Tester :: - invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::StructReturnPort& port - ) - { - PortStruct returnVal = this->invoke_to_structReturnIn( - portNum, - port.args.s, - port.args.sRef - ); - - ASSERT_EQ(returnVal, this->structReturnVal.val); - } - - // ---------------------------------------------------------------------- - // Invoke serial input ports - // ---------------------------------------------------------------------- - - void Tester :: - invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::NoArgsPort& port - ) - { - U8 data[0]; - Fw::SerialBuffer buf(data, sizeof(data)); - - this->invoke_to_serialIn( - SerialPortIndex::NO_ARGS, - buf - ); - } - - void Tester :: - invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::PrimitiveArgsPort& port - ) - { - Fw::SerializeStatus status; - - // Check unsuccessful deserialization of first parameter - U8 invalidData1[0]; - Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); - - this->invoke_to_serialIn( - SerialPortIndex::PRIMITIVE, - invalidBuf1 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of second parameter - U8 invalidData2[sizeof(U32)]; - Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); - - status = invalidBuf2.serialize(port.args.u32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::PRIMITIVE, - invalidBuf2 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of third parameter - U8 invalidData3[sizeof(U32) * 2]; - Fw::SerialBuffer invalidBuf3(invalidData3, sizeof(invalidData3)); - - status = invalidBuf3.serialize(port.args.u32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf3.serialize(port.args.u32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::PRIMITIVE, - invalidBuf3 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of fourth parameter - U8 invalidData4[ - (sizeof(U32) * 2) + - sizeof(F32) - ]; - Fw::SerialBuffer invalidBuf4(invalidData4, sizeof(invalidData4)); - - status = invalidBuf4.serialize(port.args.u32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf4.serialize(port.args.u32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf4.serialize(port.args.f32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::PRIMITIVE, - invalidBuf4 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of fifth parameter - U8 invalidData5[ - (sizeof(U32) * 2) + - (sizeof(F32) * 2) - ]; - Fw::SerialBuffer invalidBuf5(invalidData5, sizeof(invalidData5)); - - status = invalidBuf5.serialize(port.args.u32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf5.serialize(port.args.u32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf5.serialize(port.args.f32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf5.serialize(port.args.f32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::PRIMITIVE, - invalidBuf5 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of sixth parameter - U8 invalidData6[ - (sizeof(U32) * 2) + - (sizeof(F32) * 2) + - sizeof(U8) - ]; - Fw::SerialBuffer invalidBuf6(invalidData6, sizeof(invalidData6)); - - status = invalidBuf6.serialize(port.args.u32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf6.serialize(port.args.u32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf6.serialize(port.args.f32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf6.serialize(port.args.f32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf6.serialize(port.args.b); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::PRIMITIVE, - invalidBuf6 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check successful serialization - U8 data[InputPrimitiveArgsPort::SERIALIZED_SIZE]; - Fw::SerialBuffer buf(data, sizeof(data)); - - status = buf.serialize(port.args.u32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.u32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.f32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.f32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.b); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.bRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::PRIMITIVE, - buf - ); - - this->checkSerializeStatusSuccess(); - } - - void Tester :: - invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::StringArgsPort& port - ) - { - Fw::SerializeStatus status; - - // Check unsuccessful deserialization of first parameter - U8 invalidData1[0]; - Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); - - this->invoke_to_serialIn( - SerialPortIndex::STRING, - invalidBuf1 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of second parameter - U8 invalidData2[StringArgsPortStrings::StringSize80::SERIALIZED_SIZE]; - Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); - - status = invalidBuf2.serialize(port.args.str80); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::STRING, - invalidBuf2 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of third parameter - U8 invalidData3[StringArgsPortStrings::StringSize80::SERIALIZED_SIZE * 2]; - Fw::SerialBuffer invalidBuf3(invalidData3, sizeof(invalidData3)); - - status = invalidBuf3.serialize(port.args.str80); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf3.serialize(port.args.str80Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::STRING, - invalidBuf3 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of fourth parameter - U8 invalidData4[ - (StringArgsPortStrings::StringSize80::SERIALIZED_SIZE * 2) + - StringArgsPortStrings::StringSize100::SERIALIZED_SIZE - ]; - Fw::SerialBuffer invalidBuf4(invalidData4, sizeof(invalidData4)); - - status = invalidBuf4.serialize(port.args.str80); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf4.serialize(port.args.str80Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = invalidBuf4.serialize(port.args.str100); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::STRING, - invalidBuf4 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check successful serialization - U8 data[InputStringArgsPort::SERIALIZED_SIZE]; - Fw::SerialBuffer buf(data, sizeof(data)); - - status = buf.serialize(port.args.str80); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.str80Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.str100); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.str100Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::STRING, - buf - ); - - this->checkSerializeStatusSuccess(); - } - - void Tester :: - invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::EnumArgsPort& port - ) - { - Fw::SerializeStatus status; - - // Check unsuccessful deserialization of first parameter - U8 invalidData1[0]; - Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); - - this->invoke_to_serialIn( - SerialPortIndex::ENUM, - invalidBuf1 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of second parameter - U8 invalidData2[PortEnum::SERIALIZED_SIZE]; - Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); - - status = invalidBuf2.serialize(port.args.en); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::ENUM, - invalidBuf2 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check successful serialization - U8 data[InputEnumArgsPort::SERIALIZED_SIZE]; - Fw::SerialBuffer buf(data, sizeof(data)); - - status = buf.serialize(port.args.en); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.enRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::ENUM, - buf - ); - - this->checkSerializeStatusSuccess(); - } - - void Tester :: - invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::ArrayArgsPort& port - ) - { - Fw::SerializeStatus status; - - // Check unsuccessful deserialization of first parameter - U8 invalidData1[0]; - Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); - - this->invoke_to_serialIn( - SerialPortIndex::ARRAY, - invalidBuf1 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of second parameter - U8 invalidData2[PortArray::SERIALIZED_SIZE]; - Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); - - status = invalidBuf2.serialize(port.args.a); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::ARRAY, - invalidBuf2 - ); - - this->checkSerializeStatusBufferEmpty(); - - U8 data[InputArrayArgsPort::SERIALIZED_SIZE]; - Fw::SerialBuffer buf(data, sizeof(data)); - - status = buf.serialize(port.args.a); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.aRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::ARRAY, - buf - ); - - this->checkSerializeStatusSuccess(); - } - - void Tester :: - invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::StructArgsPort& port - ) - { - Fw::SerializeStatus status; - - // Check unsuccessful deserialization of first parameter - U8 invalidData1[0]; - Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); - - this->invoke_to_serialIn( - SerialPortIndex::STRUCT, - invalidBuf1 - ); - - this->checkSerializeStatusBufferEmpty(); - - // Check unsuccessful deserialization of second parameter - U8 invalidData2[PortStruct::SERIALIZED_SIZE]; - Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); - - status = invalidBuf2.serialize(port.args.s); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::STRUCT, - invalidBuf2 - ); - - this->checkSerializeStatusBufferEmpty(); - - U8 data[InputStructArgsPort::SERIALIZED_SIZE]; - Fw::SerialBuffer buf(data, sizeof(data)); - - status = buf.serialize(port.args.s); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = buf.serialize(port.args.sRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - this->invoke_to_serialIn( - SerialPortIndex::STRUCT, - buf - ); - - this->checkSerializeStatusSuccess(); - } - - void Tester :: - invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::SerialArgsPort& port - ) - { - this->invoke_to_serialIn( - portNum, - port.args.buf - ); - - ASSERT_EQ( - component.serializeStatus, - Fw::FW_SERIALIZE_OK - ); - } - - // ---------------------------------------------------------------------- - // Check history of typed output ports - // ---------------------------------------------------------------------- - - void Tester :: - check_history( - FppTest::Port::NoArgsPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_noArgsOut_SIZE(1); - } - - void Tester :: - check_history( - FppTest::Port::PrimitiveArgsPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_primitiveArgsOut_SIZE(1); - ASSERT_from_primitiveArgsOut( - 0, - port.args.u32, - port.args.u32Ref, - port.args.f32, - port.args.f32Ref, - port.args.b, - port.args.bRef - ); - } - - void Tester :: - check_history( - FppTest::Port::StringArgsPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_stringArgsOut_SIZE(1); - ASSERT_from_stringArgsOut( - 0, - port.args.str80, - port.args.str80Ref, - port.args.str100, - port.args.str100Ref - ); - } - - void Tester :: - check_history( - FppTest::Port::EnumArgsPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_enumArgsOut_SIZE(1); - ASSERT_from_enumArgsOut( - 0, - port.args.en, - port.args.enRef - ); - } - - void Tester :: - check_history( - FppTest::Port::ArrayArgsPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_arrayArgsOut_SIZE(1); - ASSERT_from_arrayArgsOut( - 0, - port.args.a, - port.args.aRef - ); - } - - void Tester :: - check_history( - FppTest::Port::StructArgsPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_structArgsOut_SIZE(1); - ASSERT_from_structArgsOut( - 0, - port.args.s, - port.args.sRef - ); - } - - void Tester :: - check_history( - FppTest::Port::NoArgsReturnPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_noArgsReturnOut_SIZE(1); - } - - void Tester :: - check_history( - FppTest::Port::PrimitiveReturnPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_primitiveReturnOut_SIZE(1); - ASSERT_from_primitiveReturnOut( - 0, - port.args.u32, - port.args.u32Ref, - port.args.f32, - port.args.f32Ref, - port.args.b, - port.args.bRef - ); - } - - void Tester :: - check_history( - FppTest::Port::EnumReturnPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_enumReturnOut_SIZE(1); - ASSERT_from_enumReturnOut( - 0, - port.args.en, - port.args.enRef - ); - } - - void Tester :: - check_history( - FppTest::Port::ArrayReturnPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_arrayReturnOut_SIZE(1); - ASSERT_from_arrayReturnOut( - 0, - port.args.a, - port.args.aRef - ); - } - - void Tester :: - check_history( - FppTest::Port::StructReturnPort& port - ) - { - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_structReturnOut_SIZE(1); - ASSERT_from_structReturnOut( - 0, - port.args.s, - port.args.sRef - ); - } - - // ---------------------------------------------------------------------- - // Check serial output ports - // ---------------------------------------------------------------------- - - void Tester :: - check_serial( - FppTest::Port::NoArgsPort& port - ) - { - } - - void Tester :: - check_serial( - FppTest::Port::PrimitiveArgsPort& port - ) - { - Fw::SerializeStatus status; - U32 u32, u32Ref; - F32 f32, f32Ref; - bool b, bRef; - - status = this->primitiveBuf.deserialize(u32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->primitiveBuf.deserialize(u32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->primitiveBuf.deserialize(f32); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->primitiveBuf.deserialize(f32Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->primitiveBuf.deserialize(b); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->primitiveBuf.deserialize(bRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - ASSERT_EQ(u32, port.args.u32); - ASSERT_EQ(u32Ref, port.args.u32Ref); - ASSERT_EQ(f32, port.args.f32); - ASSERT_EQ(f32Ref, port.args.f32Ref); - ASSERT_EQ(b, port.args.b); - ASSERT_EQ(bRef, port.args.bRef); - } - - void Tester :: - check_serial( - FppTest::Port::StringArgsPort& port - ) - { - Fw::SerializeStatus status; - StringArgsPortStrings::StringSize80 str80, str80Ref; - StringArgsPortStrings::StringSize100 str100, str100Ref; - - status = this->stringBuf.deserialize(str80); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->stringBuf.deserialize(str80Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->stringBuf.deserialize(str100); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->stringBuf.deserialize(str100Ref); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - ASSERT_EQ(str80, port.args.str80); - ASSERT_EQ(str80Ref, port.args.str80Ref); - ASSERT_EQ(str100, port.args.str100); - ASSERT_EQ(str100Ref, port.args.str100Ref); - } - - void Tester :: - check_serial( - FppTest::Port::EnumArgsPort& port - ) - { - Fw::SerializeStatus status; - PortEnum en, enRef; - - status = this->enumBuf.deserialize(en); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->enumBuf.deserialize(enRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - ASSERT_EQ(en, port.args.en); - ASSERT_EQ(enRef, port.args.enRef); - } - - void Tester :: - check_serial( - FppTest::Port::ArrayArgsPort& port - ) - { - Fw::SerializeStatus status; - PortArray a, aRef; - - status = this->arrayBuf.deserialize(a); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->arrayBuf.deserialize(aRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - ASSERT_EQ(a, port.args.a); - ASSERT_EQ(aRef, port.args.aRef); - } - - void Tester :: - check_serial( - FppTest::Port::StructArgsPort& port - ) - { - Fw::SerializeStatus status; - PortStruct s, sRef; - - status = this->structBuf.deserialize(s); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - status = this->structBuf.deserialize(sRef); - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - - ASSERT_EQ(s, port.args.s); - ASSERT_EQ(sRef, port.args.sRef); - } - - void Tester :: - check_serial( - FppTest::Port::SerialArgsPort& port - ) - { - ASSERT_EQ(this->serialBuf, port.args.buf); - } - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_arrayArgsOut_handler( - const NATIVE_INT_TYPE portNum, - const PortArray &a, - PortArray &aRef - ) - { - this->pushFromPortEntry_arrayArgsOut(a, aRef); - } - - PortArray Tester :: - from_arrayReturnOut_handler( - const NATIVE_INT_TYPE portNum, - const PortArray &a, - PortArray &aRef - ) - { - this->pushFromPortEntry_arrayReturnOut(a, aRef); - - return this->arrayReturnVal.val; - } - - void Tester :: - from_enumArgsOut_handler( - const NATIVE_INT_TYPE portNum, - const PortEnum &en, - PortEnum &enRef - ) - { - this->pushFromPortEntry_enumArgsOut(en, enRef); - } - - PortEnum Tester :: - from_enumReturnOut_handler( - const NATIVE_INT_TYPE portNum, - const PortEnum &en, - PortEnum &enRef - ) - { - this->pushFromPortEntry_enumReturnOut(en, enRef); - - return this->enumReturnVal.val; - } - - void Tester :: - from_noArgsOut_handler( - const NATIVE_INT_TYPE portNum - ) - { - this->pushFromPortEntry_noArgsOut(); - } - - bool Tester :: - from_noArgsReturnOut_handler( - const NATIVE_INT_TYPE portNum - ) - { - this->pushFromPortEntry_noArgsReturnOut(); - - return this->noArgsReturnVal.val; - } - - void Tester :: - from_primitiveArgsOut_handler( - const NATIVE_INT_TYPE portNum, - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ) - { - this->pushFromPortEntry_primitiveArgsOut(u32, u32Ref, f32, f32Ref, b, bRef); - } - - U32 Tester :: - from_primitiveReturnOut_handler( - const NATIVE_INT_TYPE portNum, - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ) - { - this->pushFromPortEntry_primitiveReturnOut(u32, u32Ref, f32, f32Ref, b, bRef); - - return this->primitiveReturnVal.val; - } - - void Tester :: - from_stringArgsOut_handler( - const NATIVE_INT_TYPE portNum, - const str80String &str80, - str80RefString &str80Ref, - const str100String &str100, - str100RefString &str100Ref - ) - { - this->pushFromPortEntry_stringArgsOut(str80, str80Ref, str100, str100Ref); - } - - void Tester :: - from_structArgsOut_handler( - const NATIVE_INT_TYPE portNum, - const PortStruct &s, - PortStruct &sRef - ) - { - this->pushFromPortEntry_structArgsOut(s, sRef); - } - - PortStruct Tester :: - from_structReturnOut_handler( - const NATIVE_INT_TYPE portNum, - const PortStruct &s, - PortStruct &sRef - ) - { - this->pushFromPortEntry_structReturnOut(s, sRef); - - return this->structReturnVal.val; - } - - // ---------------------------------------------------------------------- - // Handlers for serial from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_serialOut_handler( - NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ - ) - { - Fw::SerializeStatus status; - - switch (portNum) { - case SerialPortIndex::NO_ARGS: - status = Fw::FW_SERIALIZE_OK; - break; - - case SerialPortIndex::PRIMITIVE: - status = Buffer.copyRaw( - this->primitiveBuf, - Buffer.getBuffCapacity() - ); - break; - - case SerialPortIndex::STRING: - status = Buffer.copyRaw( - this->stringBuf, - Buffer.getBuffCapacity() - ); - break; - - case SerialPortIndex::ENUM: - status = Buffer.copyRaw( - this->enumBuf, - Buffer.getBuffCapacity() - ); - break; - - case SerialPortIndex::ARRAY: - status = Buffer.copyRaw( - this->arrayBuf, - Buffer.getBuffCapacity() - ); - break; - - case SerialPortIndex::STRUCT: - status = Buffer.copyRaw( - this->structBuf, - Buffer.getBuffCapacity() - ); - break; - - case SerialPortIndex::SERIAL: - status = Buffer.copyRaw( - this->serialBuf, - Buffer.getBuffCapacity() - ); - break; - } - - ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); - } - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - void Tester :: - connectPorts() - { - - // arrayArgsIn - for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { - this->connect_to_arrayArgsIn( - i, - this->component.get_arrayArgsIn_InputPort(i) - ); - } - - // arrayReturnIn - this->connect_to_arrayReturnIn( - 0, - this->component.get_arrayReturnIn_InputPort(0) - ); - - // enumArgsIn - for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { - this->connect_to_enumArgsIn( - i, - this->component.get_enumArgsIn_InputPort(i) - ); - } - - // enumReturnIn - this->connect_to_enumReturnIn( - 0, - this->component.get_enumReturnIn_InputPort(0) - ); - - // noArgsIn - for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { - this->connect_to_noArgsIn( - i, - this->component.get_noArgsIn_InputPort(i) - ); - } - - // noArgsReturnIn - this->connect_to_noArgsReturnIn( - 0, - this->component.get_noArgsReturnIn_InputPort(0) - ); - - // primitiveArgsIn - for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { - this->connect_to_primitiveArgsIn( - i, - this->component.get_primitiveArgsIn_InputPort(i) - ); - } - - // primitiveReturnIn - this->connect_to_primitiveReturnIn( - 0, - this->component.get_primitiveReturnIn_InputPort(0) - ); - - // stringArgsIn - for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { - this->connect_to_stringArgsIn( - i, - this->component.get_stringArgsIn_InputPort(i) - ); - } - - // structArgsIn - for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { - this->connect_to_structArgsIn( - i, - this->component.get_structArgsIn_InputPort(i) - ); - } - - // structReturnIn - this->connect_to_structReturnIn( - 0, - this->component.get_structReturnIn_InputPort(0) - ); - - // arrayArgsOut - this->component.set_arrayArgsOut_OutputPort( - TypedPortIndex::TYPED, - this->get_from_arrayArgsOut(TypedPortIndex::TYPED) - ); - - // arrayReturnOut - this->component.set_arrayReturnOut_OutputPort( - 0, - this->get_from_arrayReturnOut(0) - ); - - // enumArgsOut - this->component.set_enumArgsOut_OutputPort( - TypedPortIndex::TYPED, - this->get_from_enumArgsOut(TypedPortIndex::TYPED) - ); - - // enumReturnOut - this->component.set_enumReturnOut_OutputPort( - 0, - this->get_from_enumReturnOut(0) - ); - - // noArgsOut - this->component.set_noArgsOut_OutputPort( - TypedPortIndex::TYPED, - this->get_from_noArgsOut(TypedPortIndex::TYPED) - ); - - // noArgsReturnOut - this->component.set_noArgsReturnOut_OutputPort( - 0, - this->get_from_noArgsReturnOut(0) - ); - - // primitiveArgsOut - this->component.set_primitiveArgsOut_OutputPort( - TypedPortIndex::TYPED, - this->get_from_primitiveArgsOut(TypedPortIndex::TYPED) - ); - - // primitiveReturnOut - this->component.set_primitiveReturnOut_OutputPort( - 0, - this->get_from_primitiveReturnOut(0) - ); - - // stringArgsOut - this->component.set_stringArgsOut_OutputPort( - TypedPortIndex::TYPED, - this->get_from_stringArgsOut(TypedPortIndex::TYPED) - ); - - // structArgsOut - this->component.set_structArgsOut_OutputPort( - TypedPortIndex::TYPED, - this->get_from_structArgsOut(TypedPortIndex::TYPED) - ); - - // structReturnOut - this->component.set_structReturnOut_OutputPort( - 0, - this->get_from_structReturnOut(0) - ); - - - // ---------------------------------------------------------------------- - // Connect serial output ports - // ---------------------------------------------------------------------- - this->component.set_noArgsOut_OutputPort( - TypedPortIndex::SERIAL, - this->get_from_serialOut(SerialPortIndex::NO_ARGS) - ); - - this->component.set_primitiveArgsOut_OutputPort( - TypedPortIndex::SERIAL, - this->get_from_serialOut(SerialPortIndex::PRIMITIVE) - ); - - this->component.set_stringArgsOut_OutputPort( - TypedPortIndex::SERIAL, - this->get_from_serialOut(SerialPortIndex::STRING) - ); - - this->component.set_enumArgsOut_OutputPort( - TypedPortIndex::SERIAL, - this->get_from_serialOut(SerialPortIndex::ENUM) - ); - - this->component.set_arrayArgsOut_OutputPort( - TypedPortIndex::SERIAL, - this->get_from_serialOut(SerialPortIndex::ARRAY) - ); - - this->component.set_structArgsOut_OutputPort( - TypedPortIndex::SERIAL, - this->get_from_serialOut(SerialPortIndex::STRUCT) - ); - - this->component.set_serialOut_OutputPort( - SerialPortIndex::NO_ARGS, - this->get_from_noArgsOut(TypedPortIndex::SERIAL) - ); - - this->component.set_serialOut_OutputPort( - SerialPortIndex::PRIMITIVE, - this->get_from_primitiveArgsOut(TypedPortIndex::SERIAL) - ); - - this->component.set_serialOut_OutputPort( - SerialPortIndex::STRING, - this->get_from_stringArgsOut(TypedPortIndex::SERIAL) - ); - - this->component.set_serialOut_OutputPort( - SerialPortIndex::ENUM, - this->get_from_enumArgsOut(TypedPortIndex::SERIAL) - ); - - this->component.set_serialOut_OutputPort( - SerialPortIndex::ARRAY, - this->get_from_arrayArgsOut(TypedPortIndex::SERIAL) - ); - - this->component.set_serialOut_OutputPort( - SerialPortIndex::STRUCT, - this->get_from_structArgsOut(TypedPortIndex::SERIAL) - ); - - this->component.set_serialOut_OutputPort( - SerialPortIndex::SERIAL, - this->get_from_serialOut(SerialPortIndex::SERIAL) - ); - - - // ---------------------------------------------------------------------- - // Connect serial input ports - // ---------------------------------------------------------------------- - for (NATIVE_INT_TYPE i = 0; i < 7; ++i) { - this->connect_to_serialIn( - i, - this->component.get_serialIn_InputPort(i) - ); - } - - } - - void Tester :: - initComponents() - { - this->init(); - this->component.init( - INSTANCE - ); - } - - void Tester :: - checkSerializeStatusSuccess() - { - ASSERT_EQ( - component.serializeStatus, - Fw::FW_SERIALIZE_OK - ); - } - - void Tester :: - checkSerializeStatusBufferEmpty() - { - ASSERT_EQ( - component.serializeStatus, - Fw::FW_DESERIALIZE_BUFFER_EMPTY - ); - } - diff --git a/FppTest/port/test/ut/Tester.hpp b/FppTest/port/test/ut/Tester.hpp deleted file mode 100644 index c4a5d4548e..0000000000 --- a/FppTest/port/test/ut/Tester.hpp +++ /dev/null @@ -1,432 +0,0 @@ -// ====================================================================== -// \title Tester.hpp -// \author T. Chieu -// \brief hpp file for Example test harness implementation class -// ====================================================================== - -#ifndef TESTER_HPP -#define TESTER_HPP - -#include "Fw/Types/SerialBuffer.hpp" - -#include "GTestBase.hpp" -#include "FppTest/port/Example.hpp" -#include "PortTypes.hpp" - -#include "FppTest/port/PrimitiveArgsPortAc.hpp" -#include "FppTest/port/StringArgsPortAc.hpp" -#include "FppTest/port/EnumArgsPortAc.hpp" -#include "FppTest/port/ArrayArgsPortAc.hpp" -#include "FppTest/port/StructArgsPortAc.hpp" -#include "FppTest/port/TypedPortIndexEnumAc.hpp" -#include "FppTest/port/SerialPortIndexEnumAc.hpp" - - class Tester : - public ExampleGTestBase - { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - - //! Construct object Tester - //! - Tester(); - - //! Destroy object Tester - //! - ~Tester(); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! To do - //! - void toDo(); - - public: - - // ---------------------------------------------------------------------- - // Invoke typed input ports - // ---------------------------------------------------------------------- - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::NoArgsPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::PrimitiveArgsPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::StringArgsPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::EnumArgsPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::ArrayArgsPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::StructArgsPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::SerialArgsPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::NoArgsReturnPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::PrimitiveReturnPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::EnumReturnPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::ArrayReturnPort& port - ); - - void invoke( - NATIVE_INT_TYPE portNum, - FppTest::Port::StructReturnPort& port - ); - - // ---------------------------------------------------------------------- - // Invoke serial input ports - // ---------------------------------------------------------------------- - - void invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::NoArgsPort& port - ); - - void invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::PrimitiveArgsPort& port - ); - - void invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::StringArgsPort& port - ); - - void invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::EnumArgsPort& port - ); - - void invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::ArrayArgsPort& port - ); - - void invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::StructArgsPort& port - ); - - void invoke_serial( - NATIVE_INT_TYPE portNum, - FppTest::Port::SerialArgsPort& port - ); - - // ---------------------------------------------------------------------- - // Check history of typed output ports - // ---------------------------------------------------------------------- - - void check_history( - FppTest::Port::NoArgsPort& port - ); - - void check_history( - FppTest::Port::PrimitiveArgsPort& port - ); - - void check_history( - FppTest::Port::StringArgsPort& port - ); - - void check_history( - FppTest::Port::EnumArgsPort& port - ); - - void check_history( - FppTest::Port::ArrayArgsPort& port - ); - - void check_history( - FppTest::Port::StructArgsPort& port - ); - - void check_history( - FppTest::Port::NoArgsReturnPort& port - ); - - void check_history( - FppTest::Port::PrimitiveReturnPort& port - ); - - void check_history( - FppTest::Port::EnumReturnPort& port - ); - - void check_history( - FppTest::Port::ArrayReturnPort& port - ); - - void check_history( - FppTest::Port::StructReturnPort& port - ); - - // ---------------------------------------------------------------------- - // Check serial output ports - // ---------------------------------------------------------------------- - - void check_serial( - FppTest::Port::NoArgsPort& port - ); - - void check_serial( - FppTest::Port::PrimitiveArgsPort& port - ); - - void check_serial( - FppTest::Port::StringArgsPort& port - ); - - void check_serial( - FppTest::Port::EnumArgsPort& port - ); - - void check_serial( - FppTest::Port::ArrayArgsPort& port - ); - - void check_serial( - FppTest::Port::StructArgsPort& port - ); - - void check_serial( - FppTest::Port::SerialArgsPort& port - ); - - private: - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_arrayArgsOut - //! - void from_arrayArgsOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortArray &a, /*!< - An array - */ - PortArray &aRef /*!< - An array ref - */ - ); - - //! Handler for from_arrayReturnOut - //! - PortArray from_arrayReturnOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortArray &a, /*!< - An array - */ - PortArray &aRef /*!< - An array ref - */ - ); - - //! Handler for from_enumArgsOut - //! - void from_enumArgsOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortEnum &en, /*!< - An enum - */ - PortEnum &enRef /*!< - An enum ref - */ - ); - - //! Handler for from_enumReturnOut - //! - PortEnum from_enumReturnOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortEnum &en, /*!< - An enum - */ - PortEnum &enRef /*!< - An enum ref - */ - ); - - //! Handler for from_noArgsOut - //! - void from_noArgsOut_handler( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Handler for from_noArgsReturnOut - //! - bool from_noArgsReturnOut_handler( - const NATIVE_INT_TYPE portNum /*!< The port number*/ - ); - - //! Handler for from_primitiveArgsOut - //! - void from_primitiveArgsOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ); - - //! Handler for from_primitiveReturnOut - //! - U32 from_primitiveReturnOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 u32, - U32 &u32Ref, - F32 f32, - F32 &f32Ref, - bool b, - bool &bRef - ); - - //! Handler for from_stringArgsOut - //! - void from_stringArgsOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const str80String &str80, /*!< - A string of size 80 - */ - str80RefString &str80Ref, - const str100String &str100, /*!< - A string of size 100 - */ - str100RefString &str100Ref - ); - - //! Handler for from_structArgsOut - //! - void from_structArgsOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortStruct &s, /*!< - A struct - */ - PortStruct &sRef /*!< - A struct ref - */ - ); - - //! Handler for from_structReturnOut - //! - PortStruct from_structReturnOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - const PortStruct &s, /*!< - A struct - */ - PortStruct &sRef /*!< - A struct ref - */ - ); - - private: - - // ---------------------------------------------------------------------- - // Handlers for serial from ports - // ---------------------------------------------------------------------- - - //! Handler for from_serialOut - //! - void from_serialOut_handler( - NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ - ); - - private: - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - //! Connect ports - //! - void connectPorts(); - - //! Initialize components - //! - void initComponents(); - - //! Check successful status of a serial port invocation - void checkSerializeStatusSuccess(); - - //! Check unsuccessful status of a serial port invocation - void checkSerializeStatusBufferEmpty(); - - private: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - Example component; - - // Values returned by typed output ports - FppTest::Port::BoolReturn noArgsReturnVal; - FppTest::Port::PrimitiveReturn primitiveReturnVal; - FppTest::Port::EnumReturn enumReturnVal; - FppTest::Port::ArrayReturn arrayReturnVal; - FppTest::Port::StructReturn structReturnVal; - - // Buffers from serial output ports; - U8 primitiveData[InputPrimitiveArgsPort::SERIALIZED_SIZE]; - U8 stringData[InputStringArgsPort::SERIALIZED_SIZE]; - U8 enumData[InputEnumArgsPort::SERIALIZED_SIZE]; - U8 arrayData[InputArrayArgsPort::SERIALIZED_SIZE]; - U8 structData[InputStructArgsPort::SERIALIZED_SIZE]; - U8 serialData[SERIAL_ARGS_BUFFER_CAPACITY]; - - Fw::SerialBuffer primitiveBuf; - Fw::SerialBuffer stringBuf; - Fw::SerialBuffer enumBuf; - Fw::SerialBuffer arrayBuf; - Fw::SerialBuffer structBuf; - Fw::SerialBuffer serialBuf; - - }; - -#endif diff --git a/FppTest/struct/NonPrimitiveStructTest.cpp b/FppTest/struct/NonPrimitiveStructTest.cpp index 508126b4f1..641cd1f44d 100644 --- a/FppTest/struct/NonPrimitiveStructTest.cpp +++ b/FppTest/struct/NonPrimitiveStructTest.cpp @@ -35,26 +35,26 @@ class NonPrimitiveStructTest : public ::testing::Test { )); for (U32 i = 0; i < StructArray::SIZE; i++) { - testArray[i] = FppTest::Utils::getU32(); + testArray[i] = FppTest::Utils::getNonzeroU32(); } testStruct.set( true, - FppTest::Utils::getU32(), - static_cast(FppTest::Utils::getU32()), - static_cast(FppTest::Utils::getU32()) + FppTest::Utils::getNonzeroU32(), + static_cast(FppTest::Utils::getNonzeroU32()), + static_cast(FppTest::Utils::getNonzeroU32()) ); for (U32 i = 0; i < 3; i++) { - testU32Arr[0] = FppTest::Utils::getU32(); + testU32Arr[0] = FppTest::Utils::getNonzeroU32(); } for (U32 i = 0; i < 3; i++) { testStructArr[i].set( true, - FppTest::Utils::getU32(), - static_cast(FppTest::Utils::getU32()), - static_cast(FppTest::Utils::getU32()) + FppTest::Utils::getNonzeroU32(), + static_cast(FppTest::Utils::getNonzeroU32()), + static_cast(FppTest::Utils::getNonzeroU32()) ); } } diff --git a/FppTest/struct/PrimitiveStructTest.cpp b/FppTest/struct/PrimitiveStructTest.cpp index c9e539b8e8..b51d15f2e4 100644 --- a/FppTest/struct/PrimitiveStructTest.cpp +++ b/FppTest/struct/PrimitiveStructTest.cpp @@ -26,9 +26,9 @@ class PrimitiveStructTest : public ::testing::Test { protected: void SetUp() override { testBool = true; - testU32 = FppTest::Utils::getU32(); - testI16 = static_cast(FppTest::Utils::getU32()); - testF64 = static_cast(FppTest::Utils::getU32()); + testU32 = FppTest::Utils::getNonzeroU32(); + testI16 = static_cast(FppTest::Utils::getNonzeroU32()); + testF64 = static_cast(FppTest::Utils::getNonzeroU32()); } void assertStructMembers(const Primitive& s) { diff --git a/FppTest/typed_tests/ComponentTest.hpp b/FppTest/typed_tests/ComponentTest.hpp new file mode 100644 index 0000000000..b4812169fb --- /dev/null +++ b/FppTest/typed_tests/ComponentTest.hpp @@ -0,0 +1,123 @@ +// ====================================================================== +// \title ComponentTest.hpp +// \author T. Chieu +// \brief hpp file for component test classes +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_COMPONENT_TEST_HPP +#define FPP_TEST_COMPONENT_TEST_HPP + +#include "test/ut/Tester.hpp" + +#include "gtest/gtest.h" + +template +class ComponentCommandTest : public ::testing::Test { +protected: + Tester tester; + FormalParamType data; +}; + +TYPED_TEST_SUITE_P(ComponentCommandTest); + +TYPED_TEST_P(ComponentCommandTest, CommandTest) { + this->tester.testCommand(0, this->data); +} + +REGISTER_TYPED_TEST_SUITE_P(ComponentCommandTest, + CommandTest +); + +template +class ComponentAsyncCommandTest : public ::testing::Test { +protected: + Tester tester; + FormalParamType data; +}; + +TYPED_TEST_SUITE_P(ComponentAsyncCommandTest); + +TYPED_TEST_P(ComponentAsyncCommandTest, AsyncCommandTest) { + this->tester.testAsyncCommand(0, this->data); +} + +REGISTER_TYPED_TEST_SUITE_P(ComponentAsyncCommandTest, + AsyncCommandTest +); + +template +class ComponentEventTest : public ::testing::Test { +protected: + Tester tester; + FormalParamType data; +}; + +TYPED_TEST_SUITE_P(ComponentEventTest); + +TYPED_TEST_P(ComponentEventTest, EventTest) { + this->tester.connectTimeGetOut(); + this->tester.testEvent(0, this->data); +} + +REGISTER_TYPED_TEST_SUITE_P(ComponentEventTest, + EventTest +); + +template +class ComponentTelemetryTest : public ::testing::Test { +protected: + Tester tester; + FormalParamType data; +}; + +TYPED_TEST_SUITE_P(ComponentTelemetryTest); + +TYPED_TEST_P(ComponentTelemetryTest, TelemetryTest) { + this->tester.connectTimeGetOut(); + this->tester.testTelemetry(0, this->data); +} + +REGISTER_TYPED_TEST_SUITE_P(ComponentTelemetryTest, + TelemetryTest +); + +template +class ComponentParamCommandTest : public ::testing::Test { +protected: + Tester tester; + FormalParamType data; +}; + +TYPED_TEST_SUITE_P(ComponentParamCommandTest); + +TYPED_TEST_P(ComponentParamCommandTest, ParamTest) { + this->tester.testParamCommand(0, this->data); +} + +REGISTER_TYPED_TEST_SUITE_P(ComponentParamCommandTest, + ParamTest +); + +template +class ComponentInternalInterfaceTest : public ::testing::Test { +protected: + Tester tester; + FormalParamType data; +}; + +TYPED_TEST_SUITE_P(ComponentInternalInterfaceTest); + +TYPED_TEST_P(ComponentInternalInterfaceTest, InternalInterfaceTest) { + this->tester.testInternalInterface(this->data); +} + +REGISTER_TYPED_TEST_SUITE_P(ComponentInternalInterfaceTest, + InternalInterfaceTest); + +#endif diff --git a/FppTest/typed_tests/PortTest.hpp b/FppTest/typed_tests/PortTest.hpp index ddf69ffd6c..b22f540fc5 100644 --- a/FppTest/typed_tests/PortTest.hpp +++ b/FppTest/typed_tests/PortTest.hpp @@ -14,11 +14,11 @@ #define FPP_TEST_PORT_TEST_HPP #include "test/ut/Tester.hpp" -#include "FppTest/port/TypedPortIndexEnumAc.hpp" +#include "FppTest/component/active/TypedPortIndexEnumAc.hpp" #include "gtest/gtest.h" -// Typed port tests +// Typed port tests (sync and guarded) template class TypedPortTest : public ::testing::Test { protected: @@ -28,16 +28,42 @@ class TypedPortTest : public ::testing::Test { TYPED_TEST_SUITE_P(TypedPortTest); -TYPED_TEST_P(TypedPortTest, TypedPort) { - this->tester.invoke(TypedPortIndex::TYPED, this->port); - this->tester.check_history(this->port); +TYPED_TEST_P(TypedPortTest, SyncPort) { + this->tester.testSyncPortInvoke(TypedPortIndex::TYPED, this->port); + this->tester.testSyncPortCheck(this->port); +} + +TYPED_TEST_P(TypedPortTest, GuardedPort) { + this->tester.testGuardedPortInvoke(TypedPortIndex::TYPED, this->port); + this->tester.testGuardedPortCheck(this->port); } REGISTER_TYPED_TEST_SUITE_P(TypedPortTest, - TypedPort + SyncPort, + GuardedPort ); -// Serial port tests +// Typed async port tests +template +class TypedAsyncPortTest : public ::testing::Test { +protected: + Tester tester; + PortType port; +}; + +TYPED_TEST_SUITE_P(TypedAsyncPortTest); + +TYPED_TEST_P(TypedAsyncPortTest, AsyncPort) { + this->tester.testAsyncPortInvoke(TypedPortIndex::TYPED, this->port); + this->tester.doDispatch(); + this->tester.testAsyncPortCheck(this->port); +} + +REGISTER_TYPED_TEST_SUITE_P(TypedAsyncPortTest, + AsyncPort +); + +// Serial port tests (sync and guarded) template class SerialPortTest : public ::testing::Test { protected: @@ -47,19 +73,57 @@ class SerialPortTest : public ::testing::Test { TYPED_TEST_SUITE_P(SerialPortTest); -TYPED_TEST_P(SerialPortTest, ToSerialTest) { - this->tester.invoke(TypedPortIndex::SERIAL, this->port); - this->tester.check_serial(this->port); +TYPED_TEST_P(SerialPortTest, ToSerialSync) { + this->tester.testSyncPortInvoke(TypedPortIndex::SERIAL, this->port); + this->tester.testSyncPortCheckSerial(this->port); +} + +TYPED_TEST_P(SerialPortTest, FromSerialSync) { + this->tester.testSyncPortInvokeSerial(TypedPortIndex::SERIAL, this->port); + this->tester.testSyncPortCheck(this->port); } -TYPED_TEST_P(SerialPortTest, FromSerialTest) { - this->tester.invoke_serial(TypedPortIndex::SERIAL, this->port); - this->tester.check_history(this->port); +TYPED_TEST_P(SerialPortTest, ToSerialGuarded) { + this->tester.testGuardedPortInvoke(TypedPortIndex::SERIAL, this->port); + this->tester.testGuardedPortCheckSerial(this->port); +} + +TYPED_TEST_P(SerialPortTest, FromSerialGuarded) { + this->tester.testGuardedPortInvokeSerial(TypedPortIndex::SERIAL, this->port); + this->tester.testGuardedPortCheck(this->port); } REGISTER_TYPED_TEST_SUITE_P(SerialPortTest, - ToSerialTest, - FromSerialTest + ToSerialSync, + FromSerialSync, + ToSerialGuarded, + FromSerialGuarded +); + +// Serial async port tests +template +class SerialAsyncPortTest : public ::testing::Test { +protected: + Tester tester; + PortType port; +}; + +TYPED_TEST_SUITE_P(SerialAsyncPortTest); + +TYPED_TEST_P(SerialAsyncPortTest, ToSerialAsync) { + this->tester.testAsyncPortInvoke(TypedPortIndex::SERIAL, this->port); + this->tester.doDispatch(); + this->tester.testAsyncPortCheckSerial(this->port); +} + +TYPED_TEST_P(SerialAsyncPortTest, FromSerialAsync) { + this->tester.testAsyncPortInvokeSerial(TypedPortIndex::SERIAL, this->port); + this->tester.testAsyncPortCheck(this->port); +} + +REGISTER_TYPED_TEST_SUITE_P(SerialAsyncPortTest, + ToSerialAsync, + FromSerialAsync ); #endif diff --git a/FppTest/utils/Utils.cpp b/FppTest/utils/Utils.cpp index 64fdd0b6b8..87c5fdd815 100644 --- a/FppTest/utils/Utils.cpp +++ b/FppTest/utils/Utils.cpp @@ -20,22 +20,22 @@ namespace FppTest { namespace Utils { - U8 getU8() { + U8 getNonzeroU8() { return static_cast(STest::Pick::lowerUpper( 1, std::numeric_limits::max() )); } - U32 getU32() { + U32 getNonzeroU32() { return STest::Pick::lowerUpper( 1, - std::numeric_limits::max() + std::numeric_limits::max() ); } char getChar() { - return static_cast(STest::Pick::lowerUpper(1, 127)); + return static_cast(STest::Pick::lowerUpper(32, 127)); } void setString(char* buf, U32 size) { diff --git a/FppTest/utils/Utils.hpp b/FppTest/utils/Utils.hpp index 24308d49a5..50be7ab1c7 100644 --- a/FppTest/utils/Utils.hpp +++ b/FppTest/utils/Utils.hpp @@ -18,10 +18,10 @@ namespace FppTest { namespace Utils { // Returns a random nonzero U8 - U8 getU8(); + U8 getNonzeroU8(); // Returns a random nonzero U32 - U32 getU32(); + U32 getNonzeroU32(); // Returns a random non-null char char getChar(); diff --git a/Fw/Buffer/Buffer.cpp b/Fw/Buffer/Buffer.cpp index 010c2dc963..65ff479bfb 100644 --- a/Fw/Buffer/Buffer.cpp +++ b/Fw/Buffer/Buffer.cpp @@ -28,11 +28,15 @@ Buffer::Buffer(): Serializable(), {} Buffer::Buffer(const Buffer& src) : Serializable(), - m_serialize_repr(src.m_bufferData, src.m_size), + m_serialize_repr(), m_bufferData(src.m_bufferData), m_size(src.m_size), m_context(src.m_context) -{} +{ + if(src.m_bufferData != nullptr){ + this->m_serialize_repr.setExtBuffer(src.m_bufferData, src.m_size); + } +} Buffer::Buffer(U8* data, U32 size, U32 context) : Serializable(), m_serialize_repr(), @@ -57,6 +61,10 @@ bool Buffer::operator==(const Buffer& src) const { return (this->m_bufferData == src.m_bufferData) && (this->m_size == src.m_size) && (this->m_context == src.m_context); } +bool Buffer::isValid() const { + return (this->m_bufferData != nullptr) && (this->m_size > 0); +} + U8* Buffer::getData() const { return this->m_bufferData; } diff --git a/Fw/Buffer/Buffer.hpp b/Fw/Buffer/Buffer.hpp index 50d021216b..f24e7971a5 100644 --- a/Fw/Buffer/Buffer.hpp +++ b/Fw/Buffer/Buffer.hpp @@ -118,6 +118,10 @@ class Buffer : public Fw::Serializable { // Accessor functions // ---------------------------------------------------------------------- + //! Returns true if the buffer is valid (data pointer != nullptr and size > 0) + //! + bool isValid() const; + //! Returns wrapped data pointer //! U8* getData() const; diff --git a/Fw/Buffer/docs/sdd.md b/Fw/Buffer/docs/sdd.md index 4dba905ea1..dddc1394a6 100644 --- a/Fw/Buffer/docs/sdd.md +++ b/Fw/Buffer/docs/sdd.md @@ -6,7 +6,7 @@ This module provides the following elements: * A type `Fw::Buffer` representing a wrapper around a variable-size buffer. This allows for passing a reference to the -allocated memory around without a copy. Typically the memory is allocated in a buffer manager or similar component but +allocated memory around without a copy. Typically the memory is allocated in a buffer manager or similar component but this is not required. * A port `Fw::BufferGet` for requesting a buffer of type `Fw::Buffer` from a [`BufferManager`](../../../Svc/BufferManager/docs/sdd.md) and similar components. @@ -30,8 +30,14 @@ Name | Type | Accessors | Purpose `m_context` | `U32` | `getContext()`/`setContext()` | Context of buffer's origin. Used to track buffers created by [`BufferManager`](../../../Svc/BufferManager/docs/sdd.md) `m_serialize_repr` | `Fw::ExternalSerializeBuffer` | `getSerializeRepr()` | Interface for serialization to internal buffer -If the size of the data is set to 0, the pointer returned by `getData()` and the serialization interface returned by -`getSerializeRepr()` are considered invalid and should not be used. +A value _B_ of type `Fw::Buffer` is **valid** if `m_bufferData != nullptr` and +`m_size > 0`; otherwise it is **invalid**. +The interface function `isValid` reports whether a buffer is valid. +Calling this function on a buffer _B_ returns `true` if _B_ is valid, otherwise `false`. + +If a buffer _B_ is invalid, then the pointer returned by _B_ `.getData()` and the +serialization interface returned by +_B_ `.getSerializeRepr()` are considered invalid and should not be used. The `getSerializeRepr()` function may be used to interact with the wrapped data buffer by serializing types to and from the data region. @@ -40,7 +46,7 @@ the data region. ### 2.2 The Port Fw::BufferGet As shown in the following diagram, `Fw::BufferGet` has one argument `size` of type `U32`. It returns a value of type -`Fw::Buffer`. The returned `Fw::Buffer`'s size must be checked for validity before using. +`Fw::Buffer`. The returned `Fw::Buffer` must be checked for validity before using. ![`Fw::BufferGet` Diagram](img/BufferGetBDD.jpg "Fw::BufferGet Port") @@ -53,16 +59,20 @@ As shown in the following diagram, `Fw::BufferSend` has one argument `fwBuffer` ## 3 Usage Notes Components allocating `Fw::Buffer` objects may use the `m_context` field at their discretion. This field is typically -used to track the origin of the buffer for eventual allocation. When a component fails to allocate memory, it must set -the `m_size` field to zero to indicate that the buffer is invalid. +used to track the origin of the buffer for eventual allocation. + +When a component fails to allocate memory, it must set +the `m_bufferData` field to `nullptr` and/or set the `m_size` field to zero to indicate that the buffer is invalid. -Receivers of `Fw::Buffer` objects are expected to check the `m_size` field before using the buffer. +A receiver of an `Fw::Buffer` object _B_ must check that _B_ is valid before accessing the +data stored in _B_. +To check validity, you can call the interface function `isValid()`. ### Serializing and Deserializing with `Fw::Buffer` Users can obtain a SerializeBuffer, `sb`, by calling `getSerializeRepr()`. This serialize buffer is backed by the memory of the `Fw::Buffer` and is initially empty. Users can serialize and deserialize through `sb` to copy to/from the backed -memory. +memory. The state of `sb` persists as long as the current `Fw::Buffer` object exists as it is stored as a member. However, all `Fw::Buffer` constructors initialize `sb` to an empty state including the `Fw::Buffer` copy constructor. Thus, if an diff --git a/Fw/Logger/LogAssert.cpp b/Fw/Logger/LogAssert.cpp index 4eca41f9b0..b7ea746d97 100644 --- a/Fw/Logger/LogAssert.cpp +++ b/Fw/Logger/LogAssert.cpp @@ -15,10 +15,10 @@ #else #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT -#define fileIdFs "Assert file ID %d: Line: %d " +#define fileIdFs "Assert: %d:%d" #define ASSERT_CAST static_cast #else -#define fileIdFs "Assert file \"%s\": Line: %d " +#define fileIdFs "Assert: \"%s:%d\"" #define ASSERT_CAST reinterpret_cast #endif diff --git a/Fw/Test/UnitTestAssert.cpp b/Fw/Test/UnitTestAssert.cpp index 77a0da89f4..3e651f8ad6 100644 --- a/Fw/Test/UnitTestAssert.cpp +++ b/Fw/Test/UnitTestAssert.cpp @@ -43,9 +43,9 @@ namespace Test { void UnitTestAssert::doAssert() { this->m_assertFailed = true; #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT - (void)fprintf(stderr,"Assert File: 0x%" PRIx32 ", Line: %" PRI_PlatformUIntType "\n", this->m_file, this->m_lineNo); + (void)fprintf(stderr,"Assert: 0x%" PRIx32 ":%" PRI_PlatformUIntType "\n", this->m_file, this->m_lineNo); #else - (void)fprintf(stderr,"Assert File: %s, Line: %" PRI_PlatformUIntType "\n", this->m_file.toChar(), this->m_lineNo); + (void)fprintf(stderr,"Assert: %s:%" PRI_PlatformUIntType "\n", this->m_file.toChar(), this->m_lineNo); #endif } diff --git a/Fw/Types/Assert.cpp b/Fw/Types/Assert.cpp index a9133ff793..68cd74454a 100644 --- a/Fw/Types/Assert.cpp +++ b/Fw/Types/Assert.cpp @@ -10,9 +10,9 @@ #else #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT -#define fileIdFs "Assert file ID 0x%08" PRIx32 ": Line: %" PRI_PlatformUIntType +#define fileIdFs "Assert: 0x%08" PRIx32 ":%" PRI_PlatformUIntType #else -#define fileIdFs "Assert file \"%s\": Line: %" PRI_PlatformUIntType +#define fileIdFs "Assert: \"%s:%" PRI_PlatformUIntType "\"" #endif namespace Fw { diff --git a/Fw/Types/CAssert.h b/Fw/Types/CAssert.h index 857e3ffa69..0b60953c0c 100644 --- a/Fw/Types/CAssert.h +++ b/Fw/Types/CAssert.h @@ -20,7 +20,7 @@ #define FILE_NAME_ARG NATIVE_UINT_TYPE #define FW_CASSERT(cond) ((void)((cond) ? (0) : (CAssert0(ASSERT_FILE_ID, __LINE__)))) #else -#define FILE_NAME_ARG const U8* +#define FILE_NAME_ARG const CHAR* #define FW_CASSERT(cond) ((void)((cond) ? (0) : (CAssert0((FILE_NAME_ARG)(__FILE__), __LINE__)))) #endif diff --git a/Fw/Types/Serializable.cpp b/Fw/Types/Serializable.cpp index ec67ea618d..940db4b508 100644 --- a/Fw/Types/Serializable.cpp +++ b/Fw/Types/Serializable.cpp @@ -707,7 +707,7 @@ namespace Fw { } void ExternalSerializeBuffer::setExtBuffer(U8* buffPtr, NATIVE_UINT_TYPE size) { - FW_ASSERT(buffPtr); + FW_ASSERT(buffPtr != nullptr); this->m_buff = buffPtr; this->m_buffSize = size; } diff --git a/Os/Baremetal/IntervalTimer.cpp b/Os/Baremetal/IntervalTimer.cpp index c6bb38a301..0851cd61d7 100644 --- a/Os/Baremetal/IntervalTimer.cpp +++ b/Os/Baremetal/IntervalTimer.cpp @@ -2,10 +2,6 @@ #include namespace Os { - IntervalTimer::IntervalTimer() {} - - IntervalTimer::~IntervalTimer() {} - void IntervalTimer::getRawTime(RawTime& time) { time.lower = 0; time.upper = 0; diff --git a/README.md b/README.md index 29fa2022e2..f5c57a5c9f 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Then, create a new project with: fprime-util new --project ``` -See the [HelloWorld Tutorial](https://nasa.github.io/fprime/Tutorials/HelloWorld/Tutorial.html) to guide you through all the steps of developing an F´ project. +See the [HelloWorld Tutorial](https://fprime-community.github.io/fprime-tutorial-hello-world/) to guide you through all the steps of developing an F´ project. New users are encouraged to read through the [User Guide](https://nasa.github.io/fprime/UsersGuide/guide.html) and explore the [other tutorials](https://nasa.github.io/fprime/Tutorials/README.html). diff --git a/RPI/test/int/rpi_integration_test.py b/RPI/test/int/rpi_integration_test.py index 8ceb43148e..dec78dfe13 100644 --- a/RPI/test/int/rpi_integration_test.py +++ b/RPI/test/int/rpi_integration_test.py @@ -1,14 +1,9 @@ import os -import platform import subprocess -import sys import time from enum import Enum -from fprime_gds.common.pipeline.standard import StandardPipeline from fprime_gds.common.testing_fw import predicates -from fprime_gds.common.testing_fw.api import IntegrationTestAPI -from fprime_gds.common.utils.config_manager import ConfigManager from fprime_gds.common.utils.event_severity import EventSeverity diff --git a/Ref/Top/RefPackets.xml b/Ref/Top/RefPackets.xml index edd64f2fc8..e597eb95ee 100644 --- a/Ref/Top/RefPackets.xml +++ b/Ref/Top/RefPackets.xml @@ -153,6 +153,10 @@ + + + + diff --git a/Ref/TypeDemo/CMakeLists.txt b/Ref/TypeDemo/CMakeLists.txt index 9a80610286..1cb0e71d0b 100644 --- a/Ref/TypeDemo/CMakeLists.txt +++ b/Ref/TypeDemo/CMakeLists.txt @@ -9,5 +9,7 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/TypeDemo.fpp" "${CMAKE_CURRENT_LIST_DIR}/TypeDemo.cpp" ) - +set(MOD_DEPS + Os +) register_fprime_module() diff --git a/Ref/TypeDemo/TypeDemo.cpp b/Ref/TypeDemo/TypeDemo.cpp index 3362a6f58b..321474ed76 100644 --- a/Ref/TypeDemo/TypeDemo.cpp +++ b/Ref/TypeDemo/TypeDemo.cpp @@ -123,4 +123,16 @@ void TypeDemo ::DUMP_TYPED_PARAMETERS_cmdHandler(const FwOpcodeType opCode, cons this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } +void TypeDemo ::DUMP_FLOATS_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq) { + Ref::FloatSet invalid; + invalid[0] = std::numeric_limits::infinity(); + invalid[1] = -1 * std::numeric_limits::infinity(); + invalid[2] = (std::numeric_limits::has_quiet_NaN) ? std::numeric_limits::quiet_NaN() : 0.0f; + this->log_ACTIVITY_HI_FloatEv(invalid[0], invalid[1], invalid[2], invalid); + this->tlmWrite_Float1Ch(invalid[0]); + this->tlmWrite_Float2Ch(invalid[1]); + this->tlmWrite_Float3Ch(invalid[2]); + this->tlmWrite_FloatSet(invalid); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} } // end namespace Ref diff --git a/Ref/TypeDemo/TypeDemo.fpp b/Ref/TypeDemo/TypeDemo.fpp index 2c5a6b0c93..5dc57da482 100644 --- a/Ref/TypeDemo/TypeDemo.fpp +++ b/Ref/TypeDemo/TypeDemo.fpp @@ -33,6 +33,9 @@ module Ref { choicePair: ChoicePair } + @ Set of floating points to emit + array FloatSet = [3] F32; + @ Component to demonstrate multiple type configurations passive component TypeDemo { ##### @@ -192,6 +195,28 @@ module Ref { @ Dump the typed parameters sync command DUMP_TYPED_PARAMETERS() + ##### + # FloatSet outputs + ##### + @ A set of floats in an event + event FloatEv(float1: F32, float2: F32, float3: F32, floats: FloatSet) severity activity high \ + format "Floats: {} {} {} as a set: {}" + + @ Float output channel 1 + telemetry Float1Ch: F32 + + @ Float output channel 2 + telemetry Float2Ch: F32 + + @ Float output channel 3 + telemetry Float3Ch: F32 + + @ Float set output channel + telemetry FloatSet: FloatSet + + @ Dump the float values + sync command DUMP_FLOATS() + # ---------------------------------------------------------------------- # Special ports # ---------------------------------------------------------------------- diff --git a/Ref/TypeDemo/TypeDemo.hpp b/Ref/TypeDemo/TypeDemo.hpp index 23c251fde3..9d2cd55335 100644 --- a/Ref/TypeDemo/TypeDemo.hpp +++ b/Ref/TypeDemo/TypeDemo.hpp @@ -19,12 +19,12 @@ class TypeDemo : public TypeDemoComponentBase { //! Construct object TypeDemo //! - TypeDemo(const char* const compName /*!< The component name*/ + TypeDemo(const char* const compName //!< The component name ); //! Initialize object TypeDemo //! - void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + void init(const NATIVE_INT_TYPE instance = 0 //!< The instance number ); //! Destroy object TypeDemo @@ -38,78 +38,76 @@ class TypeDemo : public TypeDemoComponentBase { //! Implementation for CHOICE command handler //! Single choice command - void CHOICE_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ + void CHOICE_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number Ref::Choice choice); //! Implementation for CHOICES command handler //! Multiple choice command via Array - void CHOICES_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ + void CHOICES_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number Ref::ManyChoices choices); //! Implementation for CHOICES_WITH_FRIENDS command handler //! Multiple choice command via Array with a preceding and following argument - void CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ + void CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number U8 repeat, Ref::ManyChoices choices, U8 repeat_max); //! Implementation for EXTRA_CHOICES command handler //! Multiple choice command via Array - void EXTRA_CHOICES_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ + void EXTRA_CHOICES_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number Ref::TooManyChoices choices); //! Implementation for EXTRA_CHOICES_WITH_FRIENDS command handler //! Too many choices command via Array with a preceding and following argument - void EXTRA_CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ + void EXTRA_CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number U8 repeat, Ref::TooManyChoices choices, U8 repeat_max); //! Implementation for CHOICE_PAIR command handler //! Multiple choice command via Structure - void CHOICE_PAIR_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ + void CHOICE_PAIR_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number Ref::ChoicePair choices); //! Implementation for CHOICE_PAIR_WITH_FRIENDS command handler //! Multiple choices command via Structure with a preceding and following argument - void CHOICE_PAIR_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ + void CHOICE_PAIR_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number U8 repeat, Ref::ChoicePair choices, U8 repeat_max); //! Implementation for GLUTTON_OF_CHOICE command handler //! Multiple choice command via Complex Structure - void GLUTTON_OF_CHOICE_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - Ref::ChoiceSlurry choices /*!< - A phenomenal amount of choice - */ + void GLUTTON_OF_CHOICE_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number + Ref::ChoiceSlurry choices //!< A phenomenal amount of choice ); //! Implementation for GLUTTON_OF_CHOICE_WITH_FRIENDS command handler //! Multiple choices command via Complex Structure with a preceding and following argument - void GLUTTON_OF_CHOICE_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - U8 repeat, /*!< - Number of times to repeat the choices - */ - Ref::ChoiceSlurry choices, /*!< - A phenomenal amount of choice - */ - U8 repeat_max /*!< - Limit to the number of repetitions - */ + void GLUTTON_OF_CHOICE_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number + U8 repeat, //!< Number of times to repeat the choices + Ref::ChoiceSlurry choices, //!< A phenomenal amount of choice + U8 repeat_max //!< Limit to the number of repetitions ); //! Implementation for DUMP_TYPED_PARAMETERS command handler //! Dump the typed parameters - void DUMP_TYPED_PARAMETERS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq /*!< The command sequence number*/ + void DUMP_TYPED_PARAMETERS_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq //!< The command sequence number + ); + + //! Implementation for DUMP_FLOATS command handler + //! + void DUMP_FLOATS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq /*!< The command sequence number*/ ); }; diff --git a/Ref/test/int/ref_integration_test.py b/Ref/test/int/ref_integration_test.py index 472126eca6..6682fa2882 100644 --- a/Ref/test/int/ref_integration_test.py +++ b/Ref/test/int/ref_integration_test.py @@ -1,319 +1,286 @@ -import os -import platform +""" ref_integration_test.py: + +A set of integration tests to apply to the Ref app. This is intended to be a reference of integration testing. +""" import subprocess import time from enum import Enum +from pathlib import Path -from fprime_gds.common.pipeline.standard import StandardPipeline from fprime_gds.common.testing_fw import predicates -from fprime_gds.common.testing_fw.api import IntegrationTestAPI -from fprime_gds.common.utils.config_manager import ConfigManager from fprime_gds.common.utils.event_severity import EventSeverity -class TestRefAppClass(object): - @classmethod - def setup_class(cls): - try: - cls.pipeline = StandardPipeline() - config = ConfigManager() - filename = os.path.dirname(__file__) - path = os.path.join( - filename, - "../../build-artifacts/{}/dict/RefTopologyAppDictionary.xml".format( - platform.system() - ), - ) - logpath = os.path.join(filename, "./logs") - cls.pipeline.setup(config, path, "/tmp") - cls.api = IntegrationTestAPI(cls.pipeline, logpath) - cls.case_list = [] # TODO find a better way to do this. - cls.dictionary = path - cls.pipeline.connect("tcp://127.0.0.1:50050") - except Exception as exc: - print(f"[WARNING] Exception in setup: {exc}") - cls.teardown_class() - raise - - @classmethod - def teardown_class(cls): - try: - cls.api.teardown() - except Exception as exc: - print(f"[WARNING] Exception in API teardown: {exc}") - try: - cls.pipeline.disconnect() - except Exception as exc: - print(f"[WARNING] Exception in pipeline teardown: {exc}") - - def setup_method(self, method): - self.case_list.append(method.__name__) - self.api.start_test_case(method.__name__, len(self.case_list)) - - def test_is_streaming(self): - results = self.api.assert_telemetry_count(5, timeout=10) - for result in results: - msg = "received channel {} update: {}".format( - result.get_id(), result.get_str() - ) - print(msg) - self.api.assert_telemetry( - "sendBuffComp.SendState", value="SEND_IDLE", timeout=3 - ) +""" +This enum is includes the values of EventSeverity that can be filtered by the ActiveLogger Component +""" +FilterSeverity = Enum( + "FilterSeverity", + "WARNING_HI WARNING_LO COMMAND ACTIVITY_HI ACTIVITY_LO DIAGNOSTIC", +) - def assert_command(self, command, args=[], max_delay=None, timeout=5, events=None): - """ - This helper will send a command and verify that the command was dispatched and completed - within the F' deployment. This helper can retroactively check that the delay between - dispatch and completion is less than a maximum allowable delay. - - Args: - command: the mnemonic (str) or ID (int) of the command to send - args: a list of command arguments. - max_delay: the maximum allowable delay between dispatch and completion (int/float) - timeout: the number of seconds to wait before terminating the search (int) - Return: - returns a list of the EventData objects found by the search - """ - cmd_id = self.api.translate_command_name(command) - self.api.log( - "Starting assert_command helper for {}({})".format(command, cmd_id) - ) - dispatch = [self.api.get_event_pred("cmdDisp.OpCodeDispatched", [cmd_id, None])] - complete = [self.api.get_event_pred("cmdDisp.OpCodeCompleted", [cmd_id])] - events = dispatch + (events if events else []) + complete - results = self.api.send_and_assert_event(command, args, events, timeout=timeout) - if max_delay is not None: - delay = results[1].get_time() - results[0].get_time() - msg = "The delay, {}, between the two events should be < {}".format( - delay, max_delay - ) - assert delay < max_delay, msg - self.api.log("assert_command helper completed successfully") - return results +def test_is_streaming(fprime_test_api): + """Test flight software is streaming + + Tests that the flight software is streaming by looking for 5 telemetry items in 10 seconds. Additionally, + "sendBuffComp.SendState" is verified to be SEND_IDLE. """ - This enum is includes the values of EventSeverity that can be filtered by the ActiveLogger Component - """ - FilterSeverity = Enum( - "FilterSeverity", - "WARNING_HI WARNING_LO COMMAND ACTIVITY_HI ACTIVITY_LO DIAGNOSTIC", + results = fprime_test_api.assert_telemetry_count(5, timeout=10) + for result in results: + msg = "received channel {} update: {}".format(result.get_id(), result.get_str()) + print(msg) + fprime_test_api.assert_telemetry( + "sendBuffComp.SendState", value="SEND_IDLE", timeout=3 ) - def set_event_filter(self, severity, enabled): - """ - This helper will send a command that updates the given severity filter on the ActiveLogger - Component in the Ref App. - Args: - severity: A valid FilterSeverity Enum Value (str) or an instance of FilterSeverity - enabled: a boolean of whether or not to enable the given severity - Return: - boolean of whether the report filter was set successfully. - """ - enabled = "ENABLED" if enabled else "DISABLED" - if isinstance(severity, self.FilterSeverity): - severity = severity.name - else: - severity = self.FilterSeverity[severity].name - try: - self.api.send_command( - "eventLogger.SET_EVENT_FILTER", - [severity, enabled], - ) - return True - except AssertionError: - return False - - def set_default_filters(self): - """ - Sets the default send filters on the ref aps ActiveLogger - """ - self.set_event_filter("COMMAND", True) - self.set_event_filter("ACTIVITY_LO", True) - self.set_event_filter("ACTIVITY_HI", True) - self.set_event_filter("WARNING_LO", True) - self.set_event_filter("WARNING_HI", True) - self.set_event_filter("DIAGNOSTIC", False) - - def test_send_command(self): - self.assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) - assert self.api.get_command_test_history().size() == 1 - self.assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) - assert self.api.get_command_test_history().size() == 2 - - def test_send_command_args(self): - for count, value in enumerate(["Test String 1", "Some other string"], 1): - events = [self.api.get_event_pred("cmdDisp.NoOpStringReceived", [value])] - self.assert_command( - "cmdDisp.CMD_NO_OP_STRING", - [ - value, - ], - max_delay=0.1, - events=events, - ) - assert self.api.get_command_test_history().size() == count - - def test_send_and_assert_no_op(self): - length = 100 - failed = 0 - evr_seq = [ - "cmdDisp.OpCodeDispatched", - "cmdDisp.NoOpReceived", - "cmdDisp.OpCodeCompleted", - ] - any_reordered = False - dropped = False - for i in range(0, length): - results = self.api.send_and_await_event( - "cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 - ) - msg = "Send and assert NO_OP Trial #{}".format(i) - if not self.api.test_assert(len(results) == 3, msg, True): - items = self.api.get_event_test_history().retrieve() - last = None - reordered = False - for item in items: - if last is not None: - if item.get_time() < last.get_time(): - self.api.log( - "during iteration #{}, a reordered event was detected: {}".format( - i, item - ) - ) - any_reordered = True - reordered = True - break - last = item - if not reordered: - self.api.log( - "during iteration #{}, a dropped event was detected".format(i) - ) - dropped = True - failed += 1 - self.api.clear_histories() - - case = True - case &= self.api.test_assert( - not any_reordered, "Expected no events to be reordered.", True - ) - case &= self.api.test_assert( - not dropped, "Expected no events to be dropped.", True - ) - msg = "{} sequences failed out of {}".format(failed, length) - case &= self.api.test_assert(failed == 0, msg, True) - - assert ( - case - ), "Expected all checks to pass (reordering, dropped events, all passed). See log." - - def test_bd_cycles_ascending(self): - length = 60 - count_pred = predicates.greater_than(length - 1) - results = self.api.await_telemetry_count( - count_pred, "blockDrv.BD_Cycles", timeout=length + +def set_event_filter(fprime_test_api, severity, enabled): + """Send command to set event filter + + This helper will send a command that updates the given severity filter on the ActiveLogger + Component in the Ref App. + + Args: + fprime_test_api: test api to use + severity: A valid FilterSeverity Enum Value (str) or an instance of FilterSeverity + enabled: a boolean of whether or not to enable the given severity + + Return: + boolean of whether the report filter was set successfully. + """ + enabled = "ENABLED" if enabled else "DISABLED" + if isinstance(severity, FilterSeverity): + severity = severity.name + else: + severity = FilterSeverity[severity].name + try: + fprime_test_api.send_command( + "eventLogger.SET_EVENT_FILTER", + [severity, enabled], ) - last = None - reordered = False - ascending = True - for result in results: - if last is not None: - last_time = last.get_time() - result_time = result.get_time() - if result_time - last_time > 1.5: - msg = "FSW didn't send an update between {} and {}".format( - last_time.to_readable(), result_time.to_readable() - ) - self.api.log(msg) - elif result_time < last_time: - msg = "There is potential reorder error between {} and {}".format( - last_time, result_time - ) - self.api.log(msg) - reordered = True - - if not result.get_val() > last.get_val(): - msg = "Not all updates ascended: First ({}) Second ({})".format( - last.get_val(), result.get_val() - ) - self.api.log(msg) - ascending = False - - last = result - - case = True - case &= self.api.test_assert(ascending, "Expected all updates to ascend.", True) - case &= self.api.test_assert( - not reordered, "Expected no updates to be dropped.", True + return True + except AssertionError: + return False + + +def set_default_filters(fprime_test_api): + """Set the default (initial) event filters""" + set_event_filter(fprime_test_api, "COMMAND", True) + set_event_filter(fprime_test_api, "ACTIVITY_LO", True) + set_event_filter(fprime_test_api, "ACTIVITY_HI", True) + set_event_filter(fprime_test_api, "WARNING_LO", True) + set_event_filter(fprime_test_api, "WARNING_HI", True) + set_event_filter(fprime_test_api, "DIAGNOSTIC", False) + + +def test_send_command(fprime_test_api): + """Test that commands may be sent + + Tests command send, dispatch, and receipt using send_and_assert command with a pair of NO-OP commands. + """ + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + assert fprime_test_api.get_command_test_history().size() == 1 + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + assert fprime_test_api.get_command_test_history().size() == 2 + + +def test_send_command_args(fprime_test_api): + """Test that commands may be sent with arguments + + Tests command send, dispatch, and receipt using send_and_assert command with a pair of NO-OP string commands. + """ + for count, value in enumerate(["Test String 1", "Some other string"], 1): + events = [fprime_test_api.get_event_pred("cmdDisp.NoOpStringReceived", [value])] + fprime_test_api.send_and_assert_command( + "cmdDisp.CMD_NO_OP_STRING", + [ + value, + ], + max_delay=0.1, + events=events, ) - self.api.predicate_assert( - count_pred, - len(results) - 1, - "Expected >= {} updates".format(length - 1), - True, + assert fprime_test_api.get_command_test_history().size() == count + + +def test_send_and_assert_no_op(fprime_test_api): + """Test that commands may be sent in-order + + Tests command send, dispatch, and receipt using send_and_assert command with NO-OP commands. Repeats the series of + commands 100 times and looks for no re-ordering nor drops. + """ + length = 100 + failed = 0 + evr_seq = [ + "cmdDisp.OpCodeDispatched", + "cmdDisp.NoOpReceived", + "cmdDisp.OpCodeCompleted", + ] + any_reordered = False + dropped = False + for i in range(0, length): + results = fprime_test_api.send_and_await_event( + "cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 ) - self.api.assert_telemetry_count(0, "rateGroup1Comp.RgCycleSlips") - assert case, "Expected all checks to pass (ascending, reordering). See log." - - def test_active_logger_filter(self): - self.set_default_filters() - try: - cmd_events = self.api.get_event_pred(severity=EventSeverity.COMMAND) - actHI_events = self.api.get_event_pred(severity=EventSeverity.ACTIVITY_HI) - pred = predicates.greater_than(0) - zero = predicates.equal_to(0) - # Drain time for dispatch events - time.sleep(10) - - self.assert_command("cmdDisp.CMD_NO_OP") - self.assert_command("cmdDisp.CMD_NO_OP") - - time.sleep(0.5) - - self.api.assert_event_count(pred, cmd_events) - self.api.assert_event_count(pred, actHI_events) - - self.set_event_filter(self.FilterSeverity.COMMAND, False) - # Drain time for dispatch events - time.sleep(10) - self.api.clear_histories() - self.api.send_command("cmdDisp.CMD_NO_OP") - self.api.send_command("cmdDisp.CMD_NO_OP") - - time.sleep(0.5) - - self.api.assert_event_count(zero, cmd_events) - self.api.assert_event_count(pred, actHI_events) - finally: - self.set_default_filters() - - def test_signal_generation(self): - self.assert_command("SG4.SignalGen_Settings", [1, 5, 0, "SQUARE"]) - # First telemetry item should fill only the first slot of the history - history = [0, 0, 0, 5] - pair_history = [{"time": 0, "value": value} for value in history] - info = {"type": "SQUARE", "history": history, "pairHistory": pair_history} - self.assert_command("SG4.SignalGen_Toggle") - self.api.assert_telemetry("SG4.History", history, timeout=6) - self.api.assert_telemetry("SG4.PairHistory", pair_history, timeout=1) - self.api.assert_telemetry("SG4.Info", info, timeout=1) - self.assert_command("SG4.SignalGen_Toggle") - - def test_seqgen(self): - """Tests the seqgen code""" - sequence = os.path.join(os.path.dirname(__file__), "test_seq.seq") - assert ( - subprocess.run( - [ - "fprime-seqgen", - "-d", - self.dictionary, - sequence, - "/tmp/ref_test_int.bin", - ] - ).returncode - == 0 - ), "Failed to run fprime-seqgen" - self.assert_command( - "cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + msg = "Send and assert NO_OP Trial #{}".format(i) + if not fprime_test_api.test_assert(len(results) == 3, msg, True): + items = fprime_test_api.get_event_test_history().retrieve() + last = None + reordered = False + for item in items: + if last is not None: + if item.get_time() < last.get_time(): + fprime_test_api.log( + "during iteration #{}, a reordered event was detected: {}".format( + i, item + ) + ) + any_reordered = True + reordered = True + break + last = item + if not reordered: + fprime_test_api.log( + "during iteration #{}, a dropped event was detected".format(i) + ) + dropped = True + failed += 1 + fprime_test_api.clear_histories() + + case = True + case &= fprime_test_api.test_assert( + not any_reordered, "Expected no events to be reordered.", True + ) + case &= fprime_test_api.test_assert( + not dropped, "Expected no events to be dropped.", True + ) + msg = "{} sequences failed out of {}".format(failed, length) + case &= fprime_test_api.test_assert(failed == 0, msg, True) + + assert ( + case + ), "Expected all checks to pass (reordering, dropped events, all passed). See log." + + +def test_bd_cycles_ascending(fprime_test_api): + """Test in-order block driver updates""" + length = 60 + count_pred = predicates.greater_than(length - 1) + results = fprime_test_api.await_telemetry_count( + count_pred, "blockDrv.BD_Cycles", timeout=length + ) + last = None + reordered = False + ascending = True + for result in results: + if last is not None: + last_time = last.get_time() + result_time = result.get_time() + if result_time - last_time > 1.5: + msg = "FSW didn't send an update between {} and {}".format( + last_time.to_readable(), result_time.to_readable() + ) + fprime_test_api.log(msg) + elif result_time < last_time: + msg = "There is potential reorder error between {} and {}".format( + last_time, result_time + ) + fprime_test_api.log(msg) + reordered = True + + if not result.get_val() > last.get_val(): + msg = "Not all updates ascended: First ({}) Second ({})".format( + last.get_val(), result.get_val() + ) + fprime_test_api.log(msg) + ascending = False + + last = result + + case = True + case &= fprime_test_api.test_assert( + ascending, "Expected all updates to ascend.", True + ) + case &= fprime_test_api.test_assert( + not reordered, "Expected no updates to be dropped.", True + ) + fprime_test_api.predicate_assert( + count_pred, + len(results) - 1, + "Expected >= {} updates".format(length - 1), + True, + ) + fprime_test_api.assert_telemetry_count(0, "rateGroup1Comp.RgCycleSlips") + assert case, "Expected all checks to pass (ascending, reordering). See log." + + +def test_active_logger_filter(fprime_test_api): + """Test active logger event filtering""" + set_default_filters(fprime_test_api) + try: + cmd_events = fprime_test_api.get_event_pred(severity=EventSeverity.COMMAND) + actHI_events = fprime_test_api.get_event_pred( + severity=EventSeverity.ACTIVITY_HI ) + pred = predicates.greater_than(0) + zero = predicates.equal_to(0) + # Drain time for dispatch events + time.sleep(10) + + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") + + time.sleep(0.5) + + fprime_test_api.assert_event_count(pred, cmd_events) + fprime_test_api.assert_event_count(pred, actHI_events) + + set_event_filter(fprime_test_api, FilterSeverity.COMMAND, False) + # Drain time for dispatch events + time.sleep(10) + fprime_test_api.clear_histories() + fprime_test_api.send_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("cmdDisp.CMD_NO_OP") + + time.sleep(0.5) + + fprime_test_api.assert_event_count(zero, cmd_events) + fprime_test_api.assert_event_count(pred, actHI_events) + finally: + set_default_filters(fprime_test_api) + + +def test_signal_generation(fprime_test_api): + """Tests the behavior of signal gen component""" + fprime_test_api.send_and_assert_command( + "SG4.SignalGen_Settings", [1, 5, 0, "SQUARE"] + ) + # First telemetry item should fill only the first slot of the history + history = [0, 0, 0, 5] + pair_history = [{"time": 0, "value": value} for value in history] + info = {"type": "SQUARE", "history": history, "pairHistory": pair_history} + fprime_test_api.send_and_assert_command("SG4.SignalGen_Toggle") + fprime_test_api.assert_telemetry("SG4.History", history, timeout=6) + fprime_test_api.assert_telemetry("SG4.PairHistory", pair_history, timeout=1) + fprime_test_api.assert_telemetry("SG4.Info", info, timeout=1) + fprime_test_api.send_and_assert_command("SG4.SignalGen_Toggle") + + +def test_seqgen(fprime_test_api): + """Tests the seqgen can be dispatched (requires localhost testing)""" + sequence = Path(__file__).parent / "test_seq.seq" + assert ( + subprocess.run( + [ + "fprime-seqgen", + "-d", + str(fprime_test_api.pipeline.dictionary_path), + str(sequence), + "/tmp/ref_test_int.bin", + ] + ).returncode + == 0 + ), "Failed to run fprime-seqgen" + fprime_test_api.send_and_assert_command( + "cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + ) diff --git a/STest/STest/Pick/Pick.cpp b/STest/STest/Pick/Pick.cpp index 178d77cbff..0edef7a0e9 100644 --- a/STest/STest/Pick/Pick.cpp +++ b/STest/STest/Pick/Pick.cpp @@ -1,10 +1,10 @@ // ====================================================================== // \title Pick.cpp -// \author AUTO-GENERATED: DO NOT EDIT +// \author bocchino // \brief Pick implementation // // \copyright -// Copyright (C) 2019 California Institute of Technology. +// Copyright (C) 2022 California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // ====================================================================== diff --git a/STest/STest/Pick/Pick.hpp b/STest/STest/Pick/Pick.hpp index 0ad15a3521..ca8a8e161a 100644 --- a/STest/STest/Pick/Pick.hpp +++ b/STest/STest/Pick/Pick.hpp @@ -1,10 +1,10 @@ // ====================================================================== // \title Pick.hpp -// \author AUTO-GENERATED: DO NOT EDIT +// \author bocchino // \brief Pick interface // // \copyright -// Copyright (C) 2019 California Institute of Technology. +// Copyright (C) 2022 California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // ====================================================================== @@ -12,12 +12,10 @@ #ifndef STEST_PICK_HPP #define STEST_PICK_HPP -#include -#include -#include - #include "STest/types/basic_types.h" - +#ifdef STEST_MODE_spin +#include "STest/Pick/Pick_spin.hpp" +#endif namespace STest { diff --git a/STest/STest/Pick/Pick_default.cpp b/STest/STest/Pick/Pick_default.cpp index 8763c12d58..e723bad3fd 100644 --- a/STest/STest/Pick/Pick_default.cpp +++ b/STest/STest/Pick/Pick_default.cpp @@ -1,10 +1,10 @@ // ====================================================================== // \title Pick_default.cpp -// \author AUTO-GENERATED: DO NOT EDIT +// \author bocchino // \brief Pick_default implementation // // \copyright -// Copyright (C) 2019 California Institute of Technology. +// Copyright (C) 2022 California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // ====================================================================== diff --git a/STest/STest/Pick/Pick_spin.cpp b/STest/STest/Pick/Pick_spin.cpp deleted file mode 100644 index 29d883b878..0000000000 --- a/STest/STest/Pick/Pick_spin.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// ====================================================================== -// \title Pick_spin.cpp -// \author AUTO-GENERATED: DO NOT EDIT -// \brief Pick_spin implementation -// -// \copyright -// Copyright (C) 2019 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// ====================================================================== - -#include "STest/Pick/Pick.hpp" -#include "STest/Pick/Pick_spin.hpp" -#include "STest/Random/Random.hpp" - -namespace STest { - - namespace Pick { - - namespace Spin { - - namespace { - - //! The array of random seeds - U32 seeds[NUM_RANDOM_SEEDS]; - - //! The array of random values - U32 values[NUM_RANDOM_VALUES]; - - //! Whether this module is initialized - bool initialized = false; - - } - - //! Pick a random U32 - U32 pickRandU32() { - assert(initialized); - const U32 randU32 = STest::Random::lowerUpper(0, 0xFFFFFFFFU); - return values[randU32 % NUM_RANDOM_VALUES]; - } - - //! Pick a double value in the interval [0, 1] - double inUnitInterval() { - const U32 randU32 = pickRandU32(); - const F64 ratio = static_cast(randU32) / 0xFFFFFFFFU; - return ratio; - } - - void init() { - for (U32 i = 0; i < NUM_RANDOM_SEEDS; ++i) { - seeds[i] = STest::Random::lowerUpper(0, 0xFFFFFFFFU); - } - for (U32 i = 0; i < NUM_RANDOM_VALUES; ++i) { - values[i] = STest::Random::lowerUpper(0, 0xFFFFFFFFU); - } - initialized = true; - } - - void initRule(const U32 seedIndex) { - assert(initialized); - assert(seedIndex < NUM_RANDOM_SEEDS); - const U32 seed = seeds[seedIndex]; - STest::Random::SeedValue::set(seed); - } - - } - - U32 startLength(const U32 start, const U32 length) { - assert(length > 0); - const F64 randFloat = Spin::inUnitInterval() * length; - const U32 offset = static_cast(randFloat); - return start + offset; - } - - U32 lowerUpper(const U32 lower, const U32 upper) { - assert(lower <= upper); - const F64 length = static_cast(upper) - lower + 1; - const F64 randFloat = Spin::inUnitInterval() * length; - const U32 offset = static_cast(randFloat); - return lower + offset; - } - - } - -} diff --git a/STest/STest/Pick/Pick_spin.hpp b/STest/STest/Pick/Pick_spin.hpp deleted file mode 100644 index b567656272..0000000000 --- a/STest/STest/Pick/Pick_spin.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// ====================================================================== -// \title Pick_spin.hpp -// \author AUTO-GENERATED: DO NOT EDIT -// \brief Pick_spin interface -// -// \copyright -// Copyright (C) 2019 California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// ====================================================================== - -#ifndef STEST_PICK_SPIN_HPP -#define STEST_PICK_SPIN_HPP - -#include -#include -#include - -#include "STest/types/basic_types.h" - -namespace STest { - - namespace Pick { - - namespace Spin { - - enum Constants { - //! The number of random seeds to use - NUM_RANDOM_SEEDS = 5, - //! The number of random values to use - NUM_RANDOM_VALUES = 5 - }; - - //! Initialize the module - void init(); - - //! Initialize a rule - void initRule( - const U32 seedIndex //!< The index into the random seeds - ); - - } - - } - -} - -#endif diff --git a/STest/STest/Random/Random.cpp b/STest/STest/Random/Random.cpp index 7d993f863e..130afff108 100644 --- a/STest/STest/Random/Random.cpp +++ b/STest/STest/Random/Random.cpp @@ -35,15 +35,12 @@ namespace STest { const char *const fileName, U32& value ) { - bool result = true; + bool result = false; FILE *fp = fopen(fileName, "r"); if (fp != nullptr) { result = (fscanf(fp, "%" PRIu32, &value) == 1); (void) fclose(fp); } - else { - result = false; - } return result; } @@ -55,7 +52,7 @@ namespace STest { const char *const fileName, const U32 seedValue ) { - bool result = true; + bool result = false; FILE *fp = fopen(fileName, "a"); if (fp != nullptr) { int status = fprintf( @@ -66,9 +63,6 @@ namespace STest { result = (status > 0); (void) fclose(fp); } - else { - result = false; - } return result; } @@ -79,11 +73,11 @@ namespace STest { const bool seedValueOK = SeedValue::getFromFile("seed", seedValue); if (seedValueOK) { - printf("[STest::Random] Read seed %" PRIu32 " from file\n", seedValue); + (void) printf("[STest::Random] Read seed %" PRIu32 " from file\n", seedValue); } else { seedValue = SeedValue::getFromTime(); - printf("[STest::Random] Generated seed %" PRIu32 " from system time\n", seedValue); + (void) printf("[STest::Random] Generated seed %" PRIu32 " from system time\n", seedValue); } (void) SeedValue::appendToFile("seed-history", seedValue); SeedValue::set(seedValue); @@ -94,9 +88,7 @@ namespace STest { const U32 length ) { assert(length > 0); - const F64 randFloat = inUnitInterval() * length; - const U32 offset = static_cast(randFloat); - return start + offset; + return lowerUpper(start, start + length - 1); } U32 lowerUpper( @@ -107,7 +99,9 @@ namespace STest { const F64 length = static_cast(upper) - lower + 1; const F64 randFloat = inUnitInterval() * length; const U32 offset = static_cast(randFloat); - return lower + offset; + const U32 result = lower + offset; + // Handle boundary case where inUnitInterval returns 1.0 + return (result <= upper) ? result : result - 1; } double inUnitInterval() { diff --git a/STest/STest/Scenario/ConditionalIteratedScenario.hpp b/STest/STest/Scenario/ConditionalIteratedScenario.hpp index 1be1bf1e57..e50ec7d193 100644 --- a/STest/STest/Scenario/ConditionalIteratedScenario.hpp +++ b/STest/STest/Scenario/ConditionalIteratedScenario.hpp @@ -57,7 +57,7 @@ namespace STest { } //! The virtual implementation of nextScenario required by IteratedScenario - //! \return The next scenario, assuming isDone() is false, or NULL if none + //! \return The next scenario, assuming isDone() is false, or nullptr if none Scenario* nextScenario_IteratedScenario( State& state //!< The system state ) { diff --git a/STest/STest/Scenario/ConditionalScenario.hpp b/STest/STest/Scenario/ConditionalScenario.hpp index 2cb4cd9935..5693297f0e 100644 --- a/STest/STest/Scenario/ConditionalScenario.hpp +++ b/STest/STest/Scenario/ConditionalScenario.hpp @@ -56,7 +56,7 @@ namespace STest { } //! The virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none Rule* nextRule_Scenario( State& state //!< The system state ) { diff --git a/STest/STest/Scenario/InterleavedScenario.hpp b/STest/STest/Scenario/InterleavedScenario.hpp index 634f6ee727..0d96da10f0 100644 --- a/STest/STest/Scenario/InterleavedScenario.hpp +++ b/STest/STest/Scenario/InterleavedScenario.hpp @@ -38,15 +38,20 @@ namespace STest { const U32 size //!< The size of the array ) : Scenario(name), - scenarioArray(new ScenarioArray(scenarios, size)) + scenarioArray(new ScenarioArray(scenarios, size)), + seen(new bool[size]) { } //! Destroy an InterleavedScenario object ~InterleavedScenario() { - assert(this->scenarioArray != nullptr); - delete this->scenarioArray; + if (this->scenarioArray != nullptr) { + delete this->scenarioArray; + } + if (this->seen != nullptr) { + delete[] this->seen; + } } protected: @@ -62,14 +67,13 @@ namespace STest { } //! The virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none Rule* nextRule_Scenario( State& state //!< The system state ) { assert(this->scenarioArray != nullptr); Rule* rule = nullptr; - bool seen[this->scenarioArray->size]; - memset(seen, 0, this->scenarioArray->size * sizeof(bool)); + memset(this->seen, 0, this->scenarioArray->size * sizeof(bool)); U32 numSeen = 0; Scenario* *const scenarios = this->scenarioArray->getScenarios(); @@ -79,14 +83,14 @@ namespace STest { assert(numIterations < maxIterations); ++numIterations; const U32 i = this->scenarioArray->getRandomIndex(); - if (seen[i]) { + if (this->seen[i]) { continue; } rule = scenarios[i]->nextRule(state); if (rule != nullptr) { break; } - seen[i] = true; + this->seen[i] = true; ++numSeen; } return rule; @@ -118,6 +122,9 @@ namespace STest { //! The scenarios to interleave ScenarioArray* scenarioArray; + //! An array to store the scenarios seen + bool* seen; + }; } diff --git a/STest/STest/Scenario/IteratedScenario.hpp b/STest/STest/Scenario/IteratedScenario.hpp index b13489d564..78235094a5 100644 --- a/STest/STest/Scenario/IteratedScenario.hpp +++ b/STest/STest/Scenario/IteratedScenario.hpp @@ -51,7 +51,7 @@ namespace STest { // ---------------------------------------------------------------------- //! Return the next scenario to run - //! \return The next scenario, assuming isDone() is false, or NULL if none + //! \return The next scenario, assuming isDone() is false, or nullptr if none Scenario* nextScenario( State& state //!< The system state ) { @@ -78,7 +78,7 @@ namespace STest { } //! The virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none Rule* nextRule_Scenario( State& state //!< The system state ) { @@ -118,7 +118,7 @@ namespace STest { virtual void reset_IteratedScenario() = 0; //! The virtual implementation of nextScenario required by IteratedScenario - //! \return The next scenario, assuming isDone() is false, or NULL if none + //! \return The next scenario, assuming isDone() is false, or nullptr if none virtual Scenario* nextScenario_IteratedScenario( State& state //!< The system state ) = 0; diff --git a/STest/STest/Scenario/RandomlyBoundedScenario.hpp b/STest/STest/Scenario/RandomlyBoundedScenario.hpp index c73077728f..513809f191 100644 --- a/STest/STest/Scenario/RandomlyBoundedScenario.hpp +++ b/STest/STest/Scenario/RandomlyBoundedScenario.hpp @@ -73,7 +73,7 @@ namespace STest { } //! The virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none Rule* nextRule_Scenario( State& state //!< The system state ) { diff --git a/STest/STest/Scenario/RepeatedRuleScenario.hpp b/STest/STest/Scenario/RepeatedRuleScenario.hpp index a2cbc9fb88..7ebd3404ff 100644 --- a/STest/STest/Scenario/RepeatedRuleScenario.hpp +++ b/STest/STest/Scenario/RepeatedRuleScenario.hpp @@ -49,7 +49,7 @@ namespace STest { } //! The virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none Rule* nextRule_Scenario( State& state //!< The system state ) { diff --git a/STest/STest/Scenario/RepeatedScenario.hpp b/STest/STest/Scenario/RepeatedScenario.hpp index a714a0d9fa..dce19c1d24 100644 --- a/STest/STest/Scenario/RepeatedScenario.hpp +++ b/STest/STest/Scenario/RepeatedScenario.hpp @@ -52,7 +52,7 @@ namespace STest { } //! The virtual implementation of nextScenario required by IteratedScenario - //! \return The next scenario, assuming isDone() is false, or NULL if none + //! \return The next scenario, assuming isDone() is false, or nullptr if none Scenario* nextScenario_IteratedScenario( State& state //!< The system state ) { diff --git a/STest/STest/Scenario/RuleScenario.hpp b/STest/STest/Scenario/RuleScenario.hpp index e404c6d705..4b5c2ccc7b 100644 --- a/STest/STest/Scenario/RuleScenario.hpp +++ b/STest/STest/Scenario/RuleScenario.hpp @@ -50,12 +50,12 @@ namespace STest { } //! the virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none Rule* nextRule_Scenario( State& state //!< The system state ) { Rule *rule = nullptr; - if (this->rule.precondition(state)) { + if (!this->isDone() && this->rule.precondition(state)) { rule = &this->rule; this->done = true; } diff --git a/STest/STest/Scenario/Scenario.hpp b/STest/STest/Scenario/Scenario.hpp index c2ab8e72c6..73883237a7 100644 --- a/STest/STest/Scenario/Scenario.hpp +++ b/STest/STest/Scenario/Scenario.hpp @@ -67,7 +67,7 @@ namespace STest { } //! Return the next rule to apply - //! \return The next rule, or NULL if none + //! \return The next rule, or nullptr if none Rule* nextRule( State& state //!< The system state ) { @@ -94,7 +94,7 @@ namespace STest { virtual void reset_Scenario() = 0; //! The virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none virtual Rule* nextRule_Scenario( State& state //!< The system state ) = 0; diff --git a/STest/STest/Scenario/SelectedScenario.hpp b/STest/STest/Scenario/SelectedScenario.hpp index 69c20aa9c2..c8f38ad916 100644 --- a/STest/STest/Scenario/SelectedScenario.hpp +++ b/STest/STest/Scenario/SelectedScenario.hpp @@ -40,15 +40,20 @@ namespace STest { ) : Scenario(name), scenarioArray(new ScenarioArray(scenarios, size)), - selectedScenario(nullptr) + selectedScenario(nullptr), + seen(new bool[size]) { } //! Destroy a SelectedScenario object virtual ~SelectedScenario() { - assert(this->scenarioArray != nullptr); - delete this->scenarioArray; + if (this->scenarioArray != nullptr) { + delete this->scenarioArray; + } + if (this->seen != nullptr) { + delete[] this->seen; + } } public: @@ -65,7 +70,7 @@ namespace STest { } //! The virtual implementation of nextRule required by Scenario - //! \return The next rule, assuming isDone() is false, or NULL if none + //! \return The next rule, assuming isDone() is false, or nullptr if none Rule* nextRule_Scenario( State& state //!< The system state ) { @@ -114,8 +119,7 @@ namespace STest { ) { Rule* rule = nullptr; const U32 size = this->scenarioArray->size; - bool seen[size]; - memset(seen, 0, sizeof(seen)); + memset(this->seen, 0, size * sizeof(bool)); U32 numSeen = 0; assert(this->scenarioArray != nullptr); Scenario **const scenarios = @@ -123,7 +127,7 @@ namespace STest { assert(scenarios != nullptr); while (numSeen < size) { const U32 i = this->scenarioArray->getRandomIndex(); - if (seen[i]) { + if (this->seen[i]) { continue; } Scenario *const scenario = scenarios[i]; @@ -133,7 +137,7 @@ namespace STest { this->selectedScenario = scenario; break; } - seen[i] = true; + this->seen[i] = true; ++numSeen; } return rule; @@ -151,6 +155,9 @@ namespace STest { //! The selected scenario Scenario* selectedScenario; + //! An array to store the scenarios seen + bool* seen; + }; } diff --git a/STest/STest/Scenario/SequenceScenario.hpp b/STest/STest/Scenario/SequenceScenario.hpp index 4410ce8c83..15dc729ad0 100644 --- a/STest/STest/Scenario/SequenceScenario.hpp +++ b/STest/STest/Scenario/SequenceScenario.hpp @@ -63,7 +63,7 @@ namespace STest { } //! The virtual implementation of nextScenario required by IteratedScenario - //! \return The next scenario, assuming isDone() is false, or NULL if none + //! \return The next scenario, assuming isDone() is false, or nullptr if none Scenario* nextScenario_IteratedScenario( State& state //!< The system state ) { diff --git a/STest/STest/types/basic_types.h b/STest/STest/types/basic_types.h index 907175f1bf..0b939ff1f7 100644 --- a/STest/STest/types/basic_types.h +++ b/STest/STest/types/basic_types.h @@ -1,16 +1,16 @@ // ====================================================================== // \title basic_types.h // \author bocchino -// \brief Basic types +// \brief STest basic types // // \copyright // Copyright (C) 2017 California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. +// acknowledged. // ====================================================================== -#ifndef BASIC_TYPES_H -#define BASIC_TYPES_H +#ifndef STEST_BASIC_TYPES_H +#define STEST_BASIC_TYPES_H #ifdef __cplusplus extern "C" { diff --git a/Svc/ActiveRateGroup/ActiveRateGroupImpl.cpp b/Svc/ActiveRateGroup/ActiveRateGroupImpl.cpp deleted file mode 100644 index 75d9d96eb7..0000000000 --- a/Svc/ActiveRateGroup/ActiveRateGroupImpl.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -* \author: Tim Canham -* \file: -* \brief -* -* This file implements the ActiveRateGroup component, -* which invokes a set of components the comprise the rate group. -* -* Copyright 2014-2015, by the California Institute of Technology. -* ALL RIGHTS RESERVED. United States Government Sponsorship -* acknowledged. -* -*/ - -#include -#include -#include -#include -#include - -namespace Svc { - - ActiveRateGroupImpl::ActiveRateGroupImpl(const char* compName, NATIVE_UINT_TYPE contexts[], NATIVE_UINT_TYPE numContexts) : - ActiveRateGroupComponentBase(compName), - m_cycles(0), - m_maxTime(0), - m_cycleStarted(false), - m_overrunThrottle(0), - m_cycleSlips(0) { - FW_ASSERT(contexts); - FW_ASSERT(numContexts == static_cast(this->getNum_RateGroupMemberOut_OutputPorts()),numContexts,this->getNum_RateGroupMemberOut_OutputPorts()); - FW_ASSERT(FW_NUM_ARRAY_ELEMENTS(this->m_contexts) == this->getNum_RateGroupMemberOut_OutputPorts(), - static_cast(FW_NUM_ARRAY_ELEMENTS(this->m_contexts)), - this->getNum_RateGroupMemberOut_OutputPorts()); - - // copy context values - for (NATIVE_INT_TYPE entry = 0; entry < this->getNum_RateGroupMemberOut_OutputPorts(); entry++) { - this->m_contexts[entry] = contexts[entry]; - } - } - - void ActiveRateGroupImpl::init(NATIVE_INT_TYPE queueDepth, NATIVE_INT_TYPE instance) { - ActiveRateGroupComponentBase::init(queueDepth,instance); - } - - ActiveRateGroupImpl::~ActiveRateGroupImpl() { - - } - - void ActiveRateGroupImpl::preamble() { - this->log_DIAGNOSTIC_RateGroupStarted(); - } - - void ActiveRateGroupImpl::CycleIn_handler(NATIVE_INT_TYPE portNum, Svc::TimerVal& cycleStart) { - - TimerVal end; - - this->m_cycleStarted = false; - - // invoke any members of the rate group - for (NATIVE_INT_TYPE port = 0; port < this->getNum_RateGroupMemberOut_OutputPorts(); port++) { - if (this->isConnected_RateGroupMemberOut_OutputPort(port)) { - this->RateGroupMemberOut_out(port,this->m_contexts[port]); - } - } - - // grab timer for end of cycle - end.take(); - - // get rate group execution time - U32 cycle_time = end.diffUSec(cycleStart); - - // check to see if the time has exceeded the previous maximum - if (cycle_time > this->m_maxTime) { - this->m_maxTime = cycle_time; - } - - // update cycle telemetry - this->tlmWrite_RgMaxTime(this->m_maxTime); - - // check for cycle slip. That will happen if new cycle message has been received - // which will cause flag will be set again. - if (this->m_cycleStarted) { - this->m_cycleSlips++; - if (this->m_overrunThrottle < ACTIVE_RATE_GROUP_OVERRUN_THROTTLE) { - this->log_WARNING_HI_RateGroupCycleSlip(this->m_cycles); - this->m_overrunThrottle++; - } - // update cycle slips - this->tlmWrite_RgCycleSlips(this->m_cycleSlips); - } else { // if cycle is okay start decrementing throttle value - if (this->m_overrunThrottle > 0) { - this->m_overrunThrottle--; - } - } - - // increment cycle - this->m_cycles++; - - } - - void ActiveRateGroupImpl::CycleIn_preMsgHook(NATIVE_INT_TYPE portNum, Svc::TimerVal& cycleStart) { - // set flag to indicate cycle has started. Check in thread for overflow. - this->m_cycleStarted = true; - } - - void ActiveRateGroupImpl::PingIn_handler(NATIVE_INT_TYPE portNum, U32 key) { - // return the key to health - this->PingOut_out(0,key); - } - - -} diff --git a/Svc/ActiveRateGroup/README b/Svc/ActiveRateGroup/README index 01776eb556..77705120b6 100644 --- a/Svc/ActiveRateGroup/README +++ b/Svc/ActiveRateGroup/README @@ -3,4 +3,4 @@ The Active Rate Group is a component that executes components assigned to the ra A call to the input run port wakes the task and causes it to call all the components connected to the output ports in order. ActiveRateGroupComponentAi.xml - The XML description of the active rate group component -ActiveRateGroupImpl.hpp(.cpp) - The implementation of the component \ No newline at end of file +ActiveRateGroup.hpp(.cpp) - The implementation of the component \ No newline at end of file diff --git a/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp b/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp index 5daa9318e0..0961813ea1 100644 --- a/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp +++ b/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp @@ -94,7 +94,7 @@ namespace Svc { (void) snprintf(textStr, FW_INTERNAL_INTERFACE_STRING_MAX_SIZE, - "EVENT: (%" PRI_FwEventIdType ") (%04d-%02d-%02dT%02d:%02d:%02d.%03" PRIu32 ") %s: %s\n", + "EVENT: (%" PRI_FwEventIdType ") (%04d-%02d-%02dT%02d:%02d:%02d.%06" PRIu32 ") %s: %s\n", id, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,tm.tm_sec,timeTag.getUSeconds(), severityString,text.toChar()); diff --git a/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp b/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp index 6df0c1a493..5de5b7ca56 100644 --- a/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp +++ b/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp @@ -10,98 +10,93 @@ // // ====================================================================== -#include "Svc/BufferAccumulator/BufferAccumulator.hpp" -#include - #include "Fw/Types/Assert.hpp" +#include "Fw/Types/BasicTypes.hpp" +#include "Svc/BufferAccumulator/BufferAccumulator.hpp" +#include // For placement new namespace Svc { - // ---------------------------------------------------------------------- - // Constructors - // ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------- - BufferAccumulator::ArrayFIFOBuffer :: - ArrayFIFOBuffer() : - elements(nullptr), +BufferAccumulator::ArrayFIFOBuffer ::ArrayFIFOBuffer() + : elements(nullptr), capacity(0), enqueueIndex(0), dequeueIndex(0), size(0) - { +{ +} - } +BufferAccumulator::ArrayFIFOBuffer ::~ArrayFIFOBuffer() {} + +// ---------------------------------------------------------------------- +// Public functions +// ---------------------------------------------------------------------- - BufferAccumulator::ArrayFIFOBuffer :: - ~ArrayFIFOBuffer() - { +void BufferAccumulator::ArrayFIFOBuffer ::init(Fw::Buffer* const elements, + NATIVE_UINT_TYPE capacity) { + this->elements = elements; + this->capacity = capacity; + // Construct all elements + for (NATIVE_UINT_TYPE idx = 0; idx < capacity; idx++) { + new (&this->elements[idx]) Fw::Buffer; } +} - // ---------------------------------------------------------------------- - // Public functions - // ---------------------------------------------------------------------- +bool BufferAccumulator::ArrayFIFOBuffer ::enqueue(const Fw::Buffer& e) { - void BufferAccumulator::ArrayFIFOBuffer :: - init(Fw::Buffer *const elements, NATIVE_UINT_TYPE capacity) - { - this->elements = elements; - this->capacity = capacity; + if (this->elements == nullptr) { + return false; } - bool BufferAccumulator::ArrayFIFOBuffer :: - enqueue(const Fw::Buffer& e) - { - if (this->elements == nullptr) { - return false; - } - bool status; - if (this->size < this->capacity) { - // NOTE(mereweth) enqueueIndex is unsigned, no need to compare with 0 - FW_ASSERT(enqueueIndex < this->capacity, enqueueIndex); - this->elements[this->enqueueIndex] = e; - this->enqueueIndex = (this->enqueueIndex + 1) % this->capacity; - status = true; - ++this->size; - } - else { - status = false; - } - return status; + bool status; + if (this->size < this->capacity) { + // enqueueIndex is unsigned, no need to compare with 0 + FW_ASSERT(enqueueIndex < this->capacity, enqueueIndex); + this->elements[this->enqueueIndex] = e; + this->enqueueIndex = (this->enqueueIndex + 1) % this->capacity; + status = true; + this->size++; + } else { + status = false; } - bool BufferAccumulator::ArrayFIFOBuffer :: - dequeue(Fw::Buffer& e) - { - if (this->elements == nullptr) { - return false; - } - FW_ASSERT(this->elements); - bool status; - if (this->size > 0) { - // NOTE(mereweth) dequeueIndex is unsigned, no need to compare with 0 - FW_ASSERT(dequeueIndex < this->capacity, enqueueIndex); - e = this->elements[this->dequeueIndex]; - this->dequeueIndex = (this->dequeueIndex + 1) % this->capacity; - --this->size; - status = true; - } - else { - status = false; - } - return status; - } + return status; +} + +bool BufferAccumulator::ArrayFIFOBuffer ::dequeue(Fw::Buffer& e) { - U32 BufferAccumulator::ArrayFIFOBuffer :: - getSize() const - { - return this->size; + if (this->elements == nullptr) { + return false; } - U32 BufferAccumulator::ArrayFIFOBuffer :: - getCapacity() const - { - return this->capacity; + FW_ASSERT(this->elements); + bool status; + + if (this->size > 0) { + // dequeueIndex is unsigned, no need to compare with 0 + FW_ASSERT(dequeueIndex < this->capacity, dequeueIndex); + e = this->elements[this->dequeueIndex]; + this->dequeueIndex = (this->dequeueIndex + 1) % this->capacity; + this->size--; + status = true; + } else { + status = false; } + return status; +} + +U32 BufferAccumulator::ArrayFIFOBuffer ::getSize() const { + return this->size; +} + +U32 BufferAccumulator::ArrayFIFOBuffer ::getCapacity() const { + return this->capacity; } + +} // namespace Svc diff --git a/Svc/BufferAccumulator/BufferAccumulator.cpp b/Svc/BufferAccumulator/BufferAccumulator.cpp index ea997b025a..1396f3f6f1 100644 --- a/Svc/BufferAccumulator/BufferAccumulator.cpp +++ b/Svc/BufferAccumulator/BufferAccumulator.cpp @@ -11,161 +11,226 @@ // ====================================================================== #include "Svc/BufferAccumulator/BufferAccumulator.hpp" -#include + +#include + +#include "Fw/Types/BasicTypes.hpp" + namespace Svc { - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - BufferAccumulator :: - BufferAccumulator(const char *const compName) : - BufferAccumulatorComponentBase(compName), - mode(DRAIN), - bufferMemory(nullptr), - bufferQueue(), - send(true), - numWarnings(0), - allocatorId(0) - { +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +BufferAccumulator :: + BufferAccumulator(const char* const compName) + : BufferAccumulatorComponentBase(compName), //!< The component name + mode(BufferAccumulator_OpState::ACCUMULATE), + bufferMemory(nullptr), + bufferQueue(), + send(false), + waitForBuffer(false), + numWarnings(0u), + numDrained(0u), + numToDrain(0u), + opCode(), + cmdSeq(0u), + allocatorId(0) { +} - } +void BufferAccumulator ::init(const NATIVE_INT_TYPE queueDepth, + const NATIVE_INT_TYPE instance) { + BufferAccumulatorComponentBase::init(queueDepth, instance); +} - void BufferAccumulator :: - init( - const NATIVE_INT_TYPE queueDepth, - const NATIVE_INT_TYPE instance - ) - { - BufferAccumulatorComponentBase::init(queueDepth, instance); - } +BufferAccumulator ::~BufferAccumulator() {} - BufferAccumulator :: - ~BufferAccumulator() - { - } +// ---------------------------------------------------------------------- +// Public methods +// ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // Public methods - // ---------------------------------------------------------------------- - - void BufferAccumulator :: - allocateQueue( - NATIVE_INT_TYPE identifier, - Fw::MemAllocator& allocator, - NATIVE_UINT_TYPE maxNumBuffers //!< The maximum number of buffers - ) - { - this->allocatorId = identifier; - bool recoverable; // don't need to recover - NATIVE_UINT_TYPE actualSize = sizeof(Fw::Buffer) * maxNumBuffers; - this->bufferMemory = static_cast( - allocator.allocate(identifier, actualSize, recoverable)); - NATIVE_UINT_TYPE actualBuffers = actualSize/sizeof(Fw::Buffer); - - bufferQueue.init(this->bufferMemory, actualBuffers); - } +void BufferAccumulator ::allocateQueue( + NATIVE_INT_TYPE identifier, Fw::MemAllocator& allocator, + NATIVE_UINT_TYPE maxNumBuffers //!< The maximum number of buffers +) { - void BufferAccumulator :: - deallocateQueue(Fw::MemAllocator& allocator) - { - allocator.deallocate(this->allocatorId, (void*)this->bufferMemory); - } + this->allocatorId = identifier; + NATIVE_UINT_TYPE memSize = sizeof(Fw::Buffer) * maxNumBuffers; + bool recoverable = false; + this->bufferMemory = static_cast( + allocator.allocate(identifier, memSize, recoverable)); + //TODO: Fail gracefully here + bufferQueue.init(this->bufferMemory, maxNumBuffers); +} - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - void BufferAccumulator :: - bufferSendInFill_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer& buffer - ) - { - const bool status = this->bufferQueue.enqueue(buffer); - if (status) { - if (this->numWarnings > 0) { - this->log_ACTIVITY_HI_BA_BufferAccepted(); - } - this->numWarnings = 0; - } - else { - if (this->numWarnings == 0) { - this->log_WARNING_HI_BA_QueueFull(); - } - ++numWarnings; +void BufferAccumulator ::deallocateQueue(Fw::MemAllocator& allocator) { + allocator.deallocate(this->allocatorId, this->bufferMemory); +} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void BufferAccumulator ::bufferSendInFill_handler(const NATIVE_INT_TYPE portNum, + Fw::Buffer& buffer) { + + const bool status = this->bufferQueue.enqueue(buffer); + if (status) { + if (this->numWarnings > 0) { + this->log_ACTIVITY_HI_BA_BufferAccepted(); } - if (this->send) { - this->sendStoredBuffer(); + this->numWarnings = 0; + } else { + if (this->numWarnings == 0) { + this->log_WARNING_HI_BA_QueueFull(); } + numWarnings++; + } + if (this->send) { + this->sendStoredBuffer(); } - void BufferAccumulator :: - bufferSendInReturn_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer& buffer - ) - { - this->bufferSendOutReturn_out(0, buffer); + this->tlmWrite_BA_NumQueuedBuffers(this->bufferQueue.getSize()); +} + +void BufferAccumulator ::bufferSendInReturn_handler( + const NATIVE_INT_TYPE portNum, Fw::Buffer& buffer) { + + this->bufferSendOutReturn_out(0, buffer); + this->waitForBuffer = false; + if ((this->mode == BufferAccumulator_OpState::DRAIN) || // we are draining ALL buffers + (this->numDrained < this->numToDrain)) { // OR we aren't done draining some buffers + // in a partial drain this->send = true; this->sendStoredBuffer(); } +} - void BufferAccumulator :: - pingIn_handler( - const NATIVE_INT_TYPE portNum, - U32 key - ) - { - this->pingOut_out(0, key); - } +void BufferAccumulator ::pingIn_handler(const NATIVE_INT_TYPE portNum, + U32 key) { + this->pingOut_out(0, key); +} - void BufferAccumulator :: - schedIn_handler( - const NATIVE_INT_TYPE portNum, - NATIVE_UINT_TYPE context - ) - { - // TODO +// ---------------------------------------------------------------------- +// Command handler implementations +// ---------------------------------------------------------------------- + +void BufferAccumulator ::BA_SetMode_cmdHandler(const FwOpcodeType opCode, + const U32 cmdSeq, + BufferAccumulator_OpState mode) { + + // cancel an in-progress partial drain + if (this->numToDrain > 0) { + // reset counters for partial buffer drain + this->numToDrain = 0; + this->numDrained = 0; + // respond to the original command + this->cmdResponse_out(this->opCode, this->cmdSeq, Fw::CmdResponse::OK); } - // ---------------------------------------------------------------------- - // Command handler implementations - // ---------------------------------------------------------------------- - - void BufferAccumulator :: - BA_SetMode_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - OpState mode - ) - { - this->mode = mode; - if (mode == DRAIN) { + this->mode = mode; + if (mode == BufferAccumulator_OpState::DRAIN) { + if (!this->waitForBuffer) { this->send = true; this->sendStoredBuffer(); } - else { - this->send = false; - } + } else { + this->send = false; + } + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void BufferAccumulator ::BA_DrainBuffers_cmdHandler( + const FwOpcodeType opCode, const U32 cmdSeq, U32 numToDrain, + BufferAccumulator_BlockMode blockMode) { + + if (this->numDrained < this->numToDrain) { + this->log_WARNING_HI_BA_StillDraining(this->numDrained, this->numToDrain); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY); + return; + } + + if (this->mode == BufferAccumulator_OpState::DRAIN) { + this->log_WARNING_HI_BA_AlreadyDraining(); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); + return; + } + + if (numToDrain == 0) { + this->log_ACTIVITY_HI_BA_PartialDrainDone(0); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + return; } - // ---------------------------------------------------------------------- - // Private helper methods - // ---------------------------------------------------------------------- + this->opCode = opCode; + this->cmdSeq = cmdSeq; + this->numDrained = 0; + this->numToDrain = numToDrain; + + if (blockMode == BufferAccumulator_BlockMode::NOBLOCK) { + U32 numBuffers = this->bufferQueue.getSize(); + + if (numBuffers < numToDrain) { + this->numToDrain = numBuffers; + this->log_WARNING_LO_BA_NonBlockDrain(this->numToDrain, numToDrain); + } - void BufferAccumulator :: - sendStoredBuffer() - { - FW_ASSERT(this->send); - Fw::Buffer buffer; + /* OK if there were 0 buffers queued, and we + * end up setting numToDrain to 0 + */ + if (0 == this->numToDrain) { + this->log_ACTIVITY_HI_BA_PartialDrainDone(0); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + return; + } + } + + // We are still waiting for a buffer from last time + if (!this->waitForBuffer) { + this->send = true; + this->sendStoredBuffer(); // kick off the draining; + } +} + +// ---------------------------------------------------------------------- +// Private helper methods +// ---------------------------------------------------------------------- + +void BufferAccumulator ::sendStoredBuffer() { + + FW_ASSERT(this->send); + Fw::Buffer buffer; + if ((this->numToDrain == 0) || // we are draining ALL buffers + (this->numDrained < this->numToDrain)) { // OR we aren't done draining some buffers in a + // partial drain const bool status = this->bufferQueue.dequeue(buffer); - if (status) { + if (status) { // a buffer was dequeued + this->numDrained++; this->bufferSendOutDrain_out(0, buffer); + this->waitForBuffer = true; this->send = false; + } else if (this->numToDrain > 0) { + this->log_WARNING_HI_BA_DrainStalled(this->numDrained, this->numToDrain); } } + /* This used to be "else if", but then you wait for all + * drained buffers in a partial drain to be RETURNED before returning OK. + * Correct thing is to return OK once they are SENT + */ + if ((this->numToDrain > 0) && // we are doing a partial drain + (this->numDrained == this->numToDrain)) { // AND we just finished draining + // + this->log_ACTIVITY_HI_BA_PartialDrainDone(this->numDrained); + // reset counters for partial buffer drain + this->numToDrain = 0; + this->numDrained = 0; + this->send = false; + this->cmdResponse_out(this->opCode, this->cmdSeq, Fw::CmdResponse::OK); + } + + this->tlmWrite_BA_NumQueuedBuffers(this->bufferQueue.getSize()); } + +} // namespace Svc diff --git a/Svc/BufferAccumulator/BufferAccumulator.fpp b/Svc/BufferAccumulator/BufferAccumulator.fpp new file mode 100644 index 0000000000..aa918be36c --- /dev/null +++ b/Svc/BufferAccumulator/BufferAccumulator.fpp @@ -0,0 +1,52 @@ +module Svc { + + active component BufferAccumulator { + + include "Commands.fppi" + + include "Events.fppi" + + include "Telemetry.fppi" + + @ Receive a Buffer from an upstream component to enqueue + async input port bufferSendInFill: [1] Fw.BufferSend + + @ Receive a Buffer back from a downstream component + async input port bufferSendInReturn: [1] Fw.BufferSend + + @ Pass a Buffer onwards to a downstream component + output port bufferSendOutDrain: [1] Fw.BufferSend + + @ Return a Buffer to the original upstream component + output port bufferSendOutReturn: [1] Fw.BufferSend + + @ Port for receiving commands + command recv port cmdIn + + @ Port for sending command registration requests + command reg port cmdRegOut + + @ Port for sending command response + command resp port cmdResponseOut + + @ Event port for emitting events + event port eventOut + + @ Event port for emitting text events + text event port eventOutText + + @ Ping input port for health + async input port pingIn: [1] Svc.Ping + + @ Ping output port for health + output port pingOut: [1] Svc.Ping + + @ A port for getting the time + time get port timeCaller + + @ A port for emitting telemetry + telemetry port tlmOut + + } + +} diff --git a/Svc/BufferAccumulator/BufferAccumulator.hpp b/Svc/BufferAccumulator/BufferAccumulator.hpp index 0d0fe83c1d..14e7da9d36 100644 --- a/Svc/BufferAccumulator/BufferAccumulator.hpp +++ b/Svc/BufferAccumulator/BufferAccumulator.hpp @@ -13,200 +13,206 @@ #ifndef Svc_BufferAccumulator_HPP #define Svc_BufferAccumulator_HPP -#include "Svc/BufferAccumulator/BufferAccumulatorComponentAc.hpp" -#include "Os/Queue.hpp" #include +#include "Os/Queue.hpp" +#include "Svc/BufferAccumulator/BufferAccumulatorComponentAc.hpp" + namespace Svc { - class BufferAccumulator : - public BufferAccumulatorComponentBase - { + class BufferAccumulator : public BufferAccumulatorComponentBase { + PRIVATE: - PRIVATE: + // ---------------------------------------------------------------------- + // Types + // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // Types - // ---------------------------------------------------------------------- + //! A BufferLogger file + class ArrayFIFOBuffer { + public: + //! Construct an ArrayFIFOBuffer object + ArrayFIFOBuffer(); - //! A BufferLogger file - class ArrayFIFOBuffer { + //! Destroy an ArrayFIFOBuffer File object + ~ArrayFIFOBuffer(); - public: - //! Construct an ArrayFIFOBuffer object - ArrayFIFOBuffer(); + void init(Fw::Buffer* const elements, //!< The array elements + NATIVE_UINT_TYPE capacity //!< The capacity + ); + + //! Enqueue an index. + //! Fails if the queue is full. + //! \return Whether the operation succeeded + bool enqueue(const Fw::Buffer& e //!< The element to enqueue + ); + + //! Dequeue an index. + //! Fails if the queue is empty. + bool dequeue(Fw::Buffer& e //!< The dequeued element + ); - //! Destroy an ArrayFIFOBuffer File object - ~ArrayFIFOBuffer(); + //! Get the size of the queue + //! \return The size + U32 getSize() const; - void init(Fw::Buffer *const elements, //!< The array elements - NATIVE_UINT_TYPE capacity //!< The capacity - ); - - //! Enqueue an index. - //! Fails if the queue is full. - //! \return Whether the operation succeeded - bool enqueue( - const Fw::Buffer& e //!< The element to enqueue - ); - - //! Dequeue an index. - //! Fails if the queue is empty. - bool dequeue( - Fw::Buffer& e //!< The dequeued element - ); - - //! Get the size of the queue - //! \return The size - U32 getSize() const; - - //! Get the capacity of the queue - //! \return The capacity - U32 getCapacity() const; - - PRIVATE: - - // ---------------------------------------------------------------------- - // Private member variables - // ---------------------------------------------------------------------- - - //! The memory for the elements - Fw::Buffer * elements; - - //! The capacity of the queue - NATIVE_UINT_TYPE capacity; - - //! The enqueue index - NATIVE_UINT_TYPE enqueueIndex; - - //! The dequeue index - NATIVE_UINT_TYPE dequeueIndex; - - //! The size of the queue - NATIVE_UINT_TYPE size; - }; //class ArrayFIFOBuffer - - public: - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct BufferAccumulator instance - //! - BufferAccumulator( - const char *const compName /*!< The component name*/ - ); - - //! Initialize BufferAccumulator instance - //! - void init( - const NATIVE_INT_TYPE queueDepth, //!< The queue depth - const NATIVE_INT_TYPE instance = 0 //!< The instance number - ); - - //! Destroy BufferAccumulator instance - //! - ~BufferAccumulator(); + //! Get the capacity of the queue + //! \return The capacity + U32 getCapacity() const; - // ---------------------------------------------------------------------- - // Public methods - // ---------------------------------------------------------------------- + PRIVATE: - //! Give the class a memory buffer. Should be called after constructor - //! and init, but before task is spawned. - void allocateQueue( - NATIVE_INT_TYPE identifier, //!< Identifier for queue allocation and saved for deallocation - Fw::MemAllocator& allocator, //!< Memory allocator used to allocate memory - NATIVE_UINT_TYPE maxNumBuffers //!< The maximum number of buffers - ); + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- - //! Return allocated queue. Should be done during shutdown - void deallocateQueue(Fw::MemAllocator& allocator); + //! The memory for the elements + Fw::Buffer* elements; + //! The capacity of the queue + NATIVE_UINT_TYPE capacity; - PRIVATE: + //! The enqueue index + NATIVE_UINT_TYPE enqueueIndex; - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- + //! The dequeue index + NATIVE_UINT_TYPE dequeueIndex; - //! Handler implementation for bufferSendInFill - //! - void bufferSendInFill_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - Fw::Buffer& buffer - ); + //! The size of the queue + NATIVE_UINT_TYPE size; + }; // class ArrayFIFOBuffer + + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct BufferAccumulator instance + //! + BufferAccumulator( + const char* const compName /*!< The component name*/ + ); + + //! Initialize BufferAccumulator instance + //! + void init(const NATIVE_INT_TYPE queueDepth, //!< The queue depth + const NATIVE_INT_TYPE instance = 0 //!< The instance number + ); + + //! Destroy BufferAccumulator instance + //! + ~BufferAccumulator(); + + // ---------------------------------------------------------------------- + // Public methods + // ---------------------------------------------------------------------- + + //! Give the class a memory buffer. Should be called after constructor + //! and init, but before task is spawned. + void allocateQueue( + NATIVE_INT_TYPE identifier, Fw::MemAllocator& allocator, + NATIVE_UINT_TYPE maxNumBuffers //!< The maximum number of buffers + ); - //! Handler implementation for bufferSendInReturn - //! - void bufferSendInReturn_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - Fw::Buffer& buffer - ); - - //! Handler implementation for pingIn - //! - void pingIn_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - U32 key //!< Value to return to pinger - ); + //! Return allocated queue. Should be done during shutdown + void deallocateQueue(Fw::MemAllocator& allocator); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for bufferSendInFill + //! + void + bufferSendInFill_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& buffer); + + //! Handler implementation for bufferSendInReturn + //! + void bufferSendInReturn_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& buffer); + + //! Handler implementation for pingIn + //! + void pingIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number + U32 key //!< Value to return to pinger + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Command handler implementations + // ---------------------------------------------------------------------- + + //! Implementation for SetMode command handler + //! Set the mode + void BA_SetMode_cmdHandler(const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number + BufferAccumulator_OpState mode //!< The mode + ); + + //! Implementation for BA_DrainBuffers command handler + //! Drain the commanded number of buffers + void BA_DrainBuffers_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + U32 numToDrain, + BufferAccumulator_BlockMode blockMode + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Private helper methods + // ---------------------------------------------------------------------- + + //! Send a stored buffer + void sendStoredBuffer(); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- + + //! The mode + BufferAccumulator_OpState mode; + + //! Memory for the buffer array + Fw::Buffer* bufferMemory; + + //! The FIFO queue of buffers + ArrayFIFOBuffer bufferQueue; - //! Handler implementation for schedIn - //! - void schedIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - NATIVE_UINT_TYPE context /*!< The call order*/ - ); + //! Whether to send a buffer to the downstream client + bool send; - PRIVATE: + //! If we are switched to ACCUMULATE then back to DRAIN, whether we were + //! waiting on a buffer + bool waitForBuffer; - // ---------------------------------------------------------------------- - // Command handler implementations - // ---------------------------------------------------------------------- + //! The number of QueueFull warnings sent since the last successful enqueue + //! operation + U32 numWarnings; - //! Implementation for SetMode command handler - //! Set the mode - void BA_SetMode_cmdHandler( - const FwOpcodeType opCode, //!< The opcode - const U32 cmdSeq, //!< The command sequence number - OpState mode //!< The mode - ); - PRIVATE: + //! The number of buffers drained in a partial drain command + U32 numDrained; - // ---------------------------------------------------------------------- - // Private helper methods - // ---------------------------------------------------------------------- + //! The number of buffers TO drain in a partial drain command + U32 numToDrain; - //! Send a stored buffer - void sendStoredBuffer(); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Private member variables - // ---------------------------------------------------------------------- - - //! The mode - OpState mode; - - //! Memory for the buffer array - Fw::Buffer * bufferMemory; - - //! The FIFO queue of buffers - ArrayFIFOBuffer bufferQueue; - - //! Whether to send a buffer to the downstream client - bool send; - - //! The number of QueueFull warnings sent since the last successful enqueue operation - U32 numWarnings; + //! The DrainBuffers opcode to respond to + FwOpcodeType opCode; - //! The allocator ID - NATIVE_INT_TYPE allocatorId; + //! The DrainBuffers cmdSeq to respond to + U32 cmdSeq; - }; + //! The allocator ID + NATIVE_INT_TYPE allocatorId; + }; -} +} // namespace Svc #endif diff --git a/Svc/BufferAccumulator/CMakeLists.txt b/Svc/BufferAccumulator/CMakeLists.txt new file mode 100644 index 0000000000..50dec4d3eb --- /dev/null +++ b/Svc/BufferAccumulator/CMakeLists.txt @@ -0,0 +1,30 @@ +#### +# 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 +#### +restrict_platforms(Linux Darwin) # Uses sys/time + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/BufferAccumulator.fpp" + "${CMAKE_CURRENT_LIST_DIR}/BufferAccumulator.cpp" + "${CMAKE_CURRENT_LIST_DIR}/ArrayFIFOBuffer.cpp" +) + +register_fprime_module() + +### UTS ### +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/BufferAccumulator.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Accumulate.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Drain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Errors.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Health.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Main.cpp" +) +register_fprime_ut() + diff --git a/Svc/BufferAccumulator/Commands.fppi b/Svc/BufferAccumulator/Commands.fppi new file mode 100644 index 0000000000..029ec1c7b3 --- /dev/null +++ b/Svc/BufferAccumulator/Commands.fppi @@ -0,0 +1,22 @@ +enum OpState { + ACCUMULATE = 0 + DRAIN = 1 +} + +@ Set the mode +async command BA_SetMode( + mode: OpState + ) \ + opcode 0x00 + +enum BlockMode { + NOBLOCK = 0 + BLOCK = 1 +} + +@ Drain the commanded number of buffers +async command BA_DrainBuffers( + numToDrain: U32 + blockMode: BlockMode + ) \ + opcode 0x01 diff --git a/Svc/BufferAccumulator/Commands.xml b/Svc/BufferAccumulator/Commands.xml deleted file mode 100644 index c80fb438dd..0000000000 --- a/Svc/BufferAccumulator/Commands.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - Set the mode - - - - - - - - - - - diff --git a/Svc/BufferAccumulator/Events.fppi b/Svc/BufferAccumulator/Events.fppi new file mode 100644 index 0000000000..4f156995aa --- /dev/null +++ b/Svc/BufferAccumulator/Events.fppi @@ -0,0 +1,52 @@ +@ The Buffer Accumulator instance accepted and enqueued a buffer. To avoid uncontrolled sending of events, this event occurs only when the previous buffer received caused a QueueFull error. +event BA_BufferAccepted \ + severity activity high \ + id 0x00 \ + format "Buffer accepted" + +@ The Buffer Accumulator instance received a buffer when its queue was full. To avoid uncontrolled sending of events, this event occurs only when the previous buffer received did not cause a QueueFull error. +event BA_QueueFull \ + severity warning high \ + id 0x01 \ + format "Queue full" + +@ Got DrainBuffers command while executing DrainBuffers command +event BA_StillDraining( + numDrained: U32 + numToDrain: U32 + ) \ + severity warning high \ + id 0x02 \ + format "Still draining {} of {}" + +@ Got DrainBuffers command while in DRAIN mode +event BA_AlreadyDraining \ + severity warning high \ + id 0x03 \ + format "Already in DRAIN mode" + +@ Ran out of buffers while executing DrainBuffers command +event BA_DrainStalled( + numDrained: U32 + numToDrain: U32 + ) \ + severity warning high \ + id 0x04 \ + format "Drain stalling - only drained {} of {}" + +@ Finished DrainBuffers command +event BA_PartialDrainDone( + numDrained: U32 + ) \ + severity activity high \ + id 0x05 \ + format "Partial drain of {} finished" + +@ Not enough buffers to complete requested drain, and NOBLOCK was set; will only drain what we have +event BA_NonBlockDrain( + numWillDrain: U32 + numReqDrain: U32 + ) \ + severity warning low \ + id 0x06 \ + format "Only have {}; requested drain of {}" diff --git a/Svc/BufferAccumulator/Events.xml b/Svc/BufferAccumulator/Events.xml deleted file mode 100644 index 65922d03a2..0000000000 --- a/Svc/BufferAccumulator/Events.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - The Buffer Accumulator instance accepted and enqueued a buffer. To avoid uncontrolled sending of events, this event occurs only when the previous buffer received caused a QueueFull error. - - - - The Buffer Accumulator instance received a buffer when its queue was full. To avoid uncontrolled sending of events, this event occurs only when the previous buffer received did not cause a QueueFull error. - - - diff --git a/Svc/BufferAccumulator/Telemetry.fppi b/Svc/BufferAccumulator/Telemetry.fppi new file mode 100644 index 0000000000..481fe2c08c --- /dev/null +++ b/Svc/BufferAccumulator/Telemetry.fppi @@ -0,0 +1,2 @@ +@ The number of buffers queued +telemetry BA_NumQueuedBuffers: U32 id 0 diff --git a/Svc/BufferAccumulator/Telemetry.xml b/Svc/BufferAccumulator/Telemetry.xml deleted file mode 100644 index 7710ea33cf..0000000000 --- a/Svc/BufferAccumulator/Telemetry.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - The number of buffers queued - - - diff --git a/Svc/BufferAccumulator/docs/BufferAccumulator.md b/Svc/BufferAccumulator/docs/BufferAccumulator.md new file mode 100644 index 0000000000..2e1e695c55 --- /dev/null +++ b/Svc/BufferAccumulator/docs/BufferAccumulator.md @@ -0,0 +1,38 @@ +BufferAccumulator Component Dictionary +# BufferAccumulator Component Dictionary + + +## Command List + +|Mnemonic|ID|Description|Arg Name|Arg Type|Comment +|---|---|---|---|---|---| +|BA_SetMode|0 (0x0)|Set the mode| | | +| | | |mode|OpState|| +|BA_DrainBuffers|1 (0x1)|Drain the commanded number of buffers| | | +| | | |numToDrain|U32|| +| | | |blockMode|BlockMode|| + +## Telemetry Channel List + +|Channel Name|ID|Type|Description| +|---|---|---|---| +|BA_NumQueuedBuffers|0 (0x0)|U32|The number of buffers queued| + +## Event List + +|Event Name|ID|Description|Arg Name|Arg Type|Arg Size|Description +|---|---|---|---|---|---|---| +|BA_BufferAccepted|0 (0x0)|The Buffer Accumulator instance accepted and enqueued a buffer. To avoid uncontrolled sending of events, this event occurs only when the previous buffer received caused a QueueFull error.| | | | | +|BA_QueueFull|1 (0x1)|The Buffer Accumulator instance received a buffer when its queue was full. To avoid uncontrolled sending of events, this event occurs only when the previous buffer received did not cause a QueueFull error.| | | | | +|BA_StillDraining|2 (0x2)|Got DrainBuffers command while executing DrainBuffers command| | | | | +| | | |numDrained|U32||| +| | | |numToDrain|U32||| +|BA_AlreadyDraining|3 (0x3)|Got DrainBuffers command while in DRAIN mode| | | | | +|BA_DrainStalled|4 (0x4)|Ran out of buffers while executing DrainBuffers command| | | | | +| | | |numDrained|U32||| +| | | |numToDrain|U32||| +|BA_PartialDrainDone|5 (0x5)|Finished DrainBuffers command| | | | | +| | | |numDrained|U32||| +|BA_NonBlockDrain|6 (0x6)|Not enough buffers to complete requested drain, and NOBLOCK was set; will only drain what we have| | | | | +| | | |numWillDrain|U32||| +| | | |numReqDrain|U32||| diff --git a/Svc/BufferAccumulator/test/ut/Accumulate.cpp b/Svc/BufferAccumulator/test/ut/Accumulate.cpp index 90fdef2aa5..716a22147a 100644 --- a/Svc/BufferAccumulator/test/ut/Accumulate.cpp +++ b/Svc/BufferAccumulator/test/ut/Accumulate.cpp @@ -14,69 +14,66 @@ namespace Svc { - namespace Accumulate { +namespace Accumulate { - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- - void Tester :: - OK() - { +void Tester ::OK() { + ASSERT_EQ(BufferAccumulator_OpState::DRAIN, this->component.mode.e); + this->sendCmd_BA_SetMode(0, 0, BufferAccumulator_OpState::ACCUMULATE); + this->component.doDispatch(); + ASSERT_EQ(BufferAccumulator_OpState::ACCUMULATE, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(0); - ASSERT_EQ(BufferAccumulator::DRAIN, this->component.mode); - this->sendCmd_BA_SetMode(0, 0, BufferAccumulator::ACCUMULATE); - this->component.doDispatch(); - ASSERT_EQ(BufferAccumulator::ACCUMULATE, this->component.mode); - ASSERT_FROM_PORT_HISTORY_SIZE(0); - - Fw::Buffer buffers[MAX_NUM_BUFFERS]; - const U32 managerID = 42; - const U64 data = 0; - const U32 size = 10; - for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { - const U32 bufferID = i; - Fw::Buffer b(managerID, bufferID, data, size); - buffers[i] = b; - this->invoke_to_bufferSendInFill(0, buffers[i]); - this->component.doDispatch(); - ASSERT_FROM_PORT_HISTORY_SIZE(0); - } - - this->sendCmd_BA_SetMode(0, 0, BufferAccumulator::DRAIN); - this->component.doDispatch(); - ASSERT_EQ(BufferAccumulator::DRAIN, this->component.mode); - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_bufferSendOutDrain_SIZE(1); - ASSERT_from_bufferSendOutDrain(0, buffers[0]); - - U32 expectedNumBuffers = 1; - for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { - this->invoke_to_bufferSendInReturn(0, buffers[i]); - this->component.doDispatch(); - ++expectedNumBuffers; - if (i + 1 < MAX_NUM_BUFFERS) { - ++expectedNumBuffers; - ASSERT_from_bufferSendOutDrain_SIZE(i + 2); - ASSERT_from_bufferSendOutDrain(i + 1, buffers[i + 1]); - } - ASSERT_FROM_PORT_HISTORY_SIZE(expectedNumBuffers); - ASSERT_from_bufferSendOutReturn_SIZE(i + 1); - ASSERT_from_bufferSendOutReturn(i, buffers[i]); - } - - ASSERT_EQ(2U * MAX_NUM_BUFFERS, expectedNumBuffers); - ASSERT_FROM_PORT_HISTORY_SIZE(expectedNumBuffers); - ASSERT_from_bufferSendOutDrain_SIZE(MAX_NUM_BUFFERS); - ASSERT_from_bufferSendOutReturn_SIZE(MAX_NUM_BUFFERS); + Fw::Buffer buffers[MAX_NUM_BUFFERS]; + U8* data = new U8[10]; + const U32 size = 10; + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + const U32 bufferID = i; + Fw::Buffer b(data, size, bufferID); + buffers[i] = b; + this->invoke_to_bufferSendInFill(0, buffers[i]); + this->component.doDispatch(); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + } - for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { - ASSERT_from_bufferSendOutDrain(i, buffers[i]); - ASSERT_from_bufferSendOutReturn(i, buffers[i]); - } + this->sendCmd_BA_SetMode(0, 0, BufferAccumulator_OpState::DRAIN); + this->component.doDispatch(); + ASSERT_EQ(BufferAccumulator_OpState::DRAIN, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_bufferSendOutDrain_SIZE(1); + ASSERT_from_bufferSendOutDrain(0, buffers[0]); + U32 expectedNumBuffers = 1; + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + this->invoke_to_bufferSendInReturn(0, buffers[i]); + this->component.doDispatch(); + ++expectedNumBuffers; + if (i + 1 < MAX_NUM_BUFFERS) { + ++expectedNumBuffers; + ASSERT_from_bufferSendOutDrain_SIZE(i + 2); + ASSERT_from_bufferSendOutDrain(i + 1, buffers[i + 1]); } + ASSERT_FROM_PORT_HISTORY_SIZE(expectedNumBuffers); + ASSERT_from_bufferSendOutReturn_SIZE(i + 1); + ASSERT_from_bufferSendOutReturn(i, buffers[i]); + } + + ASSERT_EQ(2U * MAX_NUM_BUFFERS, expectedNumBuffers); + ASSERT_FROM_PORT_HISTORY_SIZE(expectedNumBuffers); + ASSERT_from_bufferSendOutDrain_SIZE(MAX_NUM_BUFFERS); + ASSERT_from_bufferSendOutReturn_SIZE(MAX_NUM_BUFFERS); + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + ASSERT_from_bufferSendOutDrain(i, buffers[i]); + ASSERT_from_bufferSendOutReturn(i, buffers[i]); } + delete[] data; } + +} // namespace Accumulate + +} // namespace Svc diff --git a/Svc/BufferAccumulator/test/ut/Accumulate.hpp b/Svc/BufferAccumulator/test/ut/Accumulate.hpp index 60b26c9e51..77302f51ca 100644 --- a/Svc/BufferAccumulator/test/ut/Accumulate.hpp +++ b/Svc/BufferAccumulator/test/ut/Accumulate.hpp @@ -17,25 +17,20 @@ namespace Svc { - namespace Accumulate { +namespace Accumulate { - class Tester : - public Svc::Tester - { +class Tester : public Svc::Tester { + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- - public: + //! Send some buffers + void OK(void); +}; - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- +} // namespace Accumulate - //! Send some buffers - void OK(); - - }; - - } - -} +} // namespace Svc #endif diff --git a/Svc/BufferAccumulator/test/ut/Drain.cpp b/Svc/BufferAccumulator/test/ut/Drain.cpp index fbeb47ad94..525a6a7b72 100644 --- a/Svc/BufferAccumulator/test/ut/Drain.cpp +++ b/Svc/BufferAccumulator/test/ut/Drain.cpp @@ -10,41 +10,179 @@ // // ====================================================================== -#include - #include "Drain.hpp" +#include +#include + namespace Svc { - namespace Drain { - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void Tester :: - OK() - { - ASSERT_EQ(BufferAccumulator::DRAIN, this->component.mode); - Fw::Buffer buffers[MAX_NUM_BUFFERS]; - const U32 managerID = 42; - const U64 data = 0; - const U32 size = 10; - for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { - ASSERT_from_bufferSendOutDrain_SIZE(i); - const U32 bufferID = i; - Fw::Buffer b(managerID, bufferID, data, size); - buffers[i] = b; - this->invoke_to_bufferSendInFill(0, buffers[i]); - this->component.doDispatch(); - ASSERT_from_bufferSendOutDrain_SIZE(i + 1); - ASSERT_from_bufferSendOutDrain(i, buffers[i]); - this->invoke_to_bufferSendInReturn(0, buffers[i]); - this->component.doDispatch(); - ASSERT_from_bufferSendOutReturn(i, buffers[i]); - } +namespace Drain { + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::OK() { + ASSERT_EQ(BufferAccumulator_OpState::DRAIN, this->component.mode.e); + Fw::Buffer buffers[MAX_NUM_BUFFERS]; + // Buffer needs a valid pointer + U8* data = new U8[10]; + const U32 size = 10; + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + ASSERT_from_bufferSendOutDrain_SIZE(i); + const U32 bufferID = i; + Fw::Buffer b(data, size, bufferID); + buffers[i] = b; + this->invoke_to_bufferSendInFill(0, buffers[i]); + this->component.doDispatch(); + ASSERT_from_bufferSendOutDrain_SIZE(i + 1); + ASSERT_from_bufferSendOutDrain(i, buffers[i]); + this->invoke_to_bufferSendInReturn(0, buffers[i]); + this->component.doDispatch(); + ASSERT_from_bufferSendOutReturn(i, buffers[i]); + } + + delete[] data; +} + +void Tester ::PartialDrainOK() { + this->sendCmd_BA_SetMode(0, 0, BufferAccumulator_OpState::ACCUMULATE); + this->component.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE(0, BufferAccumulator::OPCODE_BA_SETMODE, 0, + Fw::CmdResponse::OK); + ASSERT_EQ(BufferAccumulator_OpState::ACCUMULATE, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + + Fw::Buffer buffers[MAX_NUM_BUFFERS]; + U8* data = new U8[10]; + const U32 size = 10; + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + const U32 bufferID = i; + Fw::Buffer b(data, size, bufferID); + buffers[i] = b; + this->invoke_to_bufferSendInFill(0, buffers[i]); + this->component.doDispatch(); + + this->sendCmd_BA_DrainBuffers(0, 0, 1, BufferAccumulator_BlockMode::BLOCK); + this->component.doDispatch(); + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(i + 1); + ASSERT_EVENTS_BA_PartialDrainDone(i, 1u); + // + 1 for first BufferAccumulator_OpState::ACCUMULATE command; + 1 for + // buffer drained immediately + ASSERT_CMD_RESPONSE_SIZE(i + 2); + ASSERT_CMD_RESPONSE(i + 1, BufferAccumulator::OPCODE_BA_DRAINBUFFERS, 0, + Fw::CmdResponse::OK); + // check that one buffer drained + ASSERT_from_bufferSendOutDrain_SIZE(i + 1); + ASSERT_from_bufferSendOutDrain(i, buffers[i]); + + this->invoke_to_bufferSendInReturn(0, buffers[i]); + this->component.doDispatch(); + ASSERT_from_bufferSendOutReturn(i, buffers[i]); + + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(i + 1); + ASSERT_EVENTS_BA_PartialDrainDone(i, 1u); + // + 1 for first BufferAccumulator_OpState::ACCUMULATE command; + 1 for + // buffer drained immediately + ASSERT_CMD_RESPONSE_SIZE(i + 2); + // check that ONLY one buffer drained + ASSERT_from_bufferSendOutDrain_SIZE(i + 1); + ASSERT_from_bufferSendOutDrain(i, buffers[i]); + } + + this->clearHistory(); + // refill buffers + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + const U32 bufferID = i; + Fw::Buffer b(data, size, bufferID); + buffers[i] = b; + this->invoke_to_bufferSendInFill(0, buffers[i]); + this->component.doDispatch(); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + } + + ASSERT_CMD_RESPONSE_SIZE(0); + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + ASSERT_from_bufferSendOutDrain_SIZE(i); + + this->sendCmd_BA_DrainBuffers(0, 0, 1, BufferAccumulator_BlockMode::BLOCK); + this->component.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(i + 1); + ASSERT_CMD_RESPONSE(i, BufferAccumulator::OPCODE_BA_DRAINBUFFERS, 0, + Fw::CmdResponse::OK); + + const U32 bufferID = i; + Fw::Buffer b(data, size, bufferID); + buffers[i] = b; + + // check that one buffer drained + ASSERT_from_bufferSendOutDrain_SIZE(i + 1); + ASSERT_from_bufferSendOutDrain(i, buffers[i]); + this->invoke_to_bufferSendInReturn(0, buffers[i]); + this->component.doDispatch(); + ASSERT_from_bufferSendOutReturn(i, buffers[i]); + + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(i + 1); + ASSERT_EVENTS_BA_PartialDrainDone(i, 1u); + + // check that ONLY one buffer drained + ASSERT_from_bufferSendOutDrain_SIZE(i + 1); + ASSERT_from_bufferSendOutDrain(i, buffers[i]); + ASSERT_CMD_RESPONSE_SIZE(i + 1); + } + + this->clearHistory(); + // refill buffers + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + const U32 bufferID = i; + Fw::Buffer b(data, size, bufferID); + buffers[i] = b; + this->invoke_to_bufferSendInFill(0, buffers[i]); + this->component.doDispatch(); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + } + + ASSERT_EQ(BufferAccumulator_OpState::ACCUMULATE, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + ASSERT_EQ(0u, this->component.numDrained); + ASSERT_EQ(0u, this->component.numToDrain); + + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(0); + this->sendCmd_BA_DrainBuffers(0, 0, MAX_NUM_BUFFERS, + BufferAccumulator_BlockMode::BLOCK); + this->component.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(0); + + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + const U32 bufferID = i; + Fw::Buffer b(data, size, bufferID); + buffers[i] = b; + + if (i + 1 < MAX_NUM_BUFFERS) { + ASSERT_EQ(i + 1, this->component.numDrained); + ASSERT_EQ(MAX_NUM_BUFFERS, this->component.numToDrain); + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(0); } + // check that one buffer drained + ASSERT_from_bufferSendOutDrain_SIZE(i + 1); + ASSERT_from_bufferSendOutDrain(i, buffers[i]); + this->invoke_to_bufferSendInReturn(0, buffers[i]); + this->component.doDispatch(); + ASSERT_from_bufferSendOutReturn(i, buffers[i]); } + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE(0, BufferAccumulator::OPCODE_BA_DRAINBUFFERS, 0, + Fw::CmdResponse::OK); + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(1); + ASSERT_EVENTS_BA_PartialDrainDone(0, MAX_NUM_BUFFERS); + + delete[] data; } + +} // namespace Drain + +} // namespace Svc diff --git a/Svc/BufferAccumulator/test/ut/Drain.hpp b/Svc/BufferAccumulator/test/ut/Drain.hpp index 4cd938c3b2..d732470782 100644 --- a/Svc/BufferAccumulator/test/ut/Drain.hpp +++ b/Svc/BufferAccumulator/test/ut/Drain.hpp @@ -17,25 +17,23 @@ namespace Svc { - namespace Drain { +namespace Drain { - class Tester : - public Svc::Tester - { +class Tester : public Svc::Tester { + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- - public: + //! Send some buffers + void OK(void); - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- + //! Run PartialDrain command in nominal way + void PartialDrainOK(void); +}; - //! Send some buffers - void OK(); +} // namespace Drain - }; - - } - -} +} // namespace Svc #endif diff --git a/Svc/BufferAccumulator/test/ut/Errors.cpp b/Svc/BufferAccumulator/test/ut/Errors.cpp index 01edae7ca2..9c0ffe07f9 100644 --- a/Svc/BufferAccumulator/test/ut/Errors.cpp +++ b/Svc/BufferAccumulator/test/ut/Errors.cpp @@ -14,77 +14,118 @@ namespace Svc { - namespace Errors { - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void Tester :: - QueueFull() - { - - Fw::Buffer buffer; - - // Go to Accumulate mode - ASSERT_EQ(BufferAccumulator::DRAIN, this->component.mode); - this->sendCmd_BA_SetMode(0, 0, BufferAccumulator::ACCUMULATE); - this->component.doDispatch(); - ASSERT_EQ(BufferAccumulator::ACCUMULATE, this->component.mode); - ASSERT_FROM_PORT_HISTORY_SIZE(0); - - // Fill up the buffer queue - for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { - this->invoke_to_bufferSendInFill(0, buffer); - this->component.doDispatch(); - ASSERT_FROM_PORT_HISTORY_SIZE(0); - } - - // Send another buffer and expect an event - this->invoke_to_bufferSendInFill(0, buffer); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_BA_QueueFull_SIZE(1); - - // Send another buffer and expect no new event - this->invoke_to_bufferSendInFill(0, buffer); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(1); - - // Drain one buffer - this->sendCmd_BA_SetMode(0, 0, BufferAccumulator::DRAIN); - this->component.doDispatch(); - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_bufferSendOutDrain_SIZE(1); - ASSERT_from_bufferSendOutDrain(0, buffer); - - // Send another buffer and expect an event - this->invoke_to_bufferSendInFill(0, buffer); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(2); - ASSERT_EVENTS_BA_BufferAccepted_SIZE(1); - - // Drain one buffer - this->sendCmd_BA_SetMode(0, 0, BufferAccumulator::DRAIN); - this->component.doDispatch(); - ASSERT_FROM_PORT_HISTORY_SIZE(2); - ASSERT_from_bufferSendOutDrain_SIZE(2); - ASSERT_from_bufferSendOutDrain(1, buffer); - - // Send another buffer and expect no new event - this->invoke_to_bufferSendInFill(0, buffer); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(2); - ASSERT_EVENTS_BA_BufferAccepted_SIZE(1); - - // Send another buffer and expect an event - this->invoke_to_bufferSendInFill(0, buffer); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(3); - ASSERT_EVENTS_BA_QueueFull_SIZE(2); - - } +namespace Errors { + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::PartialDrain() { + ASSERT_EQ(BufferAccumulator_OpState::DRAIN, this->component.mode.e); + this->sendCmd_BA_DrainBuffers(0, 0, 1, BufferAccumulator_BlockMode::BLOCK); + this->component.doDispatch(); // will fail - we are still in + // BufferAccumulator_OpState::DRAIN mode + ASSERT_EQ(BufferAccumulator_OpState::DRAIN, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + ASSERT_EVENTS_BA_AlreadyDraining_SIZE(1); + ASSERT_EQ(0u, this->component.numDrained); + ASSERT_EQ(0u, this->component.numToDrain); + + this->sendCmd_BA_SetMode(0, 0, BufferAccumulator_OpState::ACCUMULATE); + this->component.doDispatch(); + ASSERT_EQ(BufferAccumulator_OpState::ACCUMULATE, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + + this->sendCmd_BA_DrainBuffers(0, 0, 10, BufferAccumulator_BlockMode::BLOCK); + this->component.doDispatch(); // will succeed - now we are in ACCUMULATE + ASSERT_EQ(BufferAccumulator_OpState::ACCUMULATE, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE( + 0); // would be first buffer out, but we are empty + ASSERT_EVENTS_BA_DrainStalled_SIZE(1); + ASSERT_EVENTS_BA_DrainStalled(0, 0u, 10u); + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(0); // partial drain not done + ASSERT_EQ(true, this->component.send); + ASSERT_EQ(0u, this->component.numDrained); + ASSERT_EQ(10u, this->component.numToDrain); + + this->sendCmd_BA_DrainBuffers(0, 0, 1, BufferAccumulator_BlockMode::BLOCK); + this->component + .doDispatch(); // will fail - we are still doing a partial drain + ASSERT_EVENTS_BA_StillDraining_SIZE(1); + ASSERT_EVENTS_BA_StillDraining(0, 0u, 10u); + ASSERT_EVENTS_BA_PartialDrainDone_SIZE(0); // partial drain not done + ASSERT_EQ(BufferAccumulator_OpState::ACCUMULATE, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + ASSERT_EQ(true, this->component.send); + ASSERT_EQ(0u, this->component.numDrained); + ASSERT_EQ(10u, this->component.numToDrain); +} +void Tester ::QueueFull() { + U8* data = new U8[10]; + const U32 size = 10; + Fw::Buffer buffer(data, size); + + // Go to Accumulate mode + ASSERT_EQ(BufferAccumulator_OpState::DRAIN, this->component.mode.e); + this->sendCmd_BA_SetMode(0, 0, BufferAccumulator_OpState::ACCUMULATE); + this->component.doDispatch(); + ASSERT_EQ(BufferAccumulator_OpState::ACCUMULATE, this->component.mode.e); + ASSERT_FROM_PORT_HISTORY_SIZE(0); + + // Fill up the buffer queue + for (U32 i = 0; i < MAX_NUM_BUFFERS; ++i) { + this->invoke_to_bufferSendInFill(0, buffer); + this->component.doDispatch(); + ASSERT_FROM_PORT_HISTORY_SIZE(0); } + // Send another buffer and expect an event + this->invoke_to_bufferSendInFill(0, buffer); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_BA_QueueFull_SIZE(1); + + // Send another buffer and expect no new event + this->invoke_to_bufferSendInFill(0, buffer); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(1); + + // Drain one buffer + this->sendCmd_BA_SetMode(0, 0, BufferAccumulator_OpState::DRAIN); + this->component.doDispatch(); + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_bufferSendOutDrain_SIZE(1); + ASSERT_from_bufferSendOutDrain(0, buffer); + + // Send another buffer and expect an event + this->invoke_to_bufferSendInFill(0, buffer); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(2); + ASSERT_EVENTS_BA_BufferAccepted_SIZE(1); + + // Return the original buffer in order to drain one buffer + this->invoke_to_bufferSendInReturn(0, buffer); + this->component.doDispatch(); + ASSERT_FROM_PORT_HISTORY_SIZE(3); + ASSERT_from_bufferSendOutDrain_SIZE(2); + ASSERT_from_bufferSendOutDrain(1, buffer); + + // Send another buffer and expect no new event + this->invoke_to_bufferSendInFill(0, buffer); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(2); + ASSERT_EVENTS_BA_BufferAccepted_SIZE(1); + + // Send another buffer and expect an event + this->invoke_to_bufferSendInFill(0, buffer); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(3); + ASSERT_EVENTS_BA_QueueFull_SIZE(2); + + delete[] data; } + +} // namespace Errors + +} // namespace Svc diff --git a/Svc/BufferAccumulator/test/ut/Errors.hpp b/Svc/BufferAccumulator/test/ut/Errors.hpp index 720e4c3b4c..d901db3997 100644 --- a/Svc/BufferAccumulator/test/ut/Errors.hpp +++ b/Svc/BufferAccumulator/test/ut/Errors.hpp @@ -17,25 +17,23 @@ namespace Svc { - namespace Errors { +namespace Errors { - class Tester : - public Svc::Tester - { +class Tester : public Svc::Tester { + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- - public: + //! Queue full + void QueueFull(void); - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- + //! Run PartialDrain command in off-nominal ways + void PartialDrain(void); +}; - //! Queue full - void QueueFull(); +} // namespace Errors - }; - - } - -} +} // namespace Svc #endif diff --git a/Svc/BufferAccumulator/test/ut/Health.cpp b/Svc/BufferAccumulator/test/ut/Health.cpp index 2f0e9acf79..4e0aaaf1b0 100644 --- a/Svc/BufferAccumulator/test/ut/Health.cpp +++ b/Svc/BufferAccumulator/test/ut/Health.cpp @@ -14,23 +14,19 @@ namespace Svc { - namespace Health { +namespace Health { - void Tester :: - Ping() - { +void Tester ::Ping() { + U32 key = 42; - U32 key = 42; + this->invoke_to_pingIn(0, key); + this->component.doDispatch(); - this->invoke_to_pingIn(0, key); - this->component.doDispatch(); - - ASSERT_EVENTS_SIZE(0); - ASSERT_from_pingOut_SIZE(1); - ASSERT_from_pingOut(0, key); - - } + ASSERT_EVENTS_SIZE(0); + ASSERT_from_pingOut_SIZE(1); + ASSERT_from_pingOut(0, key); +} - } +} // namespace Health -} +} // namespace Svc diff --git a/Svc/BufferAccumulator/test/ut/Health.hpp b/Svc/BufferAccumulator/test/ut/Health.hpp index 66f3dc6cf7..2c9dcf38ef 100644 --- a/Svc/BufferAccumulator/test/ut/Health.hpp +++ b/Svc/BufferAccumulator/test/ut/Health.hpp @@ -17,25 +17,20 @@ namespace Svc { - namespace Health { +namespace Health { - class Tester : - public Svc::Tester - { +class Tester : public Svc::Tester { + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- - public: + //! Health ping test + void Ping(void); +}; - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- +} // namespace Health - //! Health ping test - void Ping(); - - }; - - } - -} +} // namespace Svc #endif diff --git a/Svc/BufferAccumulator/test/ut/Main.cpp b/Svc/BufferAccumulator/test/ut/Main.cpp index 6bb64c2e3a..138e6f53e5 100644 --- a/Svc/BufferAccumulator/test/ut/Main.cpp +++ b/Svc/BufferAccumulator/test/ut/Main.cpp @@ -1,17 +1,20 @@ -// ---------------------------------------------------------------------- -// Main.cpp -// ---------------------------------------------------------------------- +// ====================================================================== +// \title Main.cpp +// \author bocchino, mereweth +// \brief Test drain mode +// +// \copyright +// Copyright (c) 2017 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== -#include "Tester.hpp" -#include "Errors.hpp" #include "Accumulate.hpp" #include "Drain.hpp" +#include "Errors.hpp" #include "Health.hpp" - -TEST(Test, AccumNoAllocate) { - Svc::Tester tester(false); // don't call allocateQueue for the user - tester.AccumNoAllocate(); -} +#include "Tester.hpp" // ---------------------------------------------------------------------- // Test Errors @@ -22,6 +25,11 @@ TEST(TestErrors, QueueFull) { tester.QueueFull(); } +TEST(TestErrors, PartialDrain) { + Svc::Errors::Tester tester; + tester.PartialDrain(); +} + // ---------------------------------------------------------------------- // Test Accumulate // ---------------------------------------------------------------------- @@ -40,6 +48,11 @@ TEST(TestDrain, OK) { tester.OK(); } +TEST(TestPartialDrain, OK) { + Svc::Drain::Tester tester; + tester.PartialDrainOK(); +} + // ---------------------------------------------------------------------- // Test Health // ---------------------------------------------------------------------- diff --git a/Svc/BufferAccumulator/test/ut/Tester.cpp b/Svc/BufferAccumulator/test/ut/Tester.cpp index da253ea686..c75488f6de 100644 --- a/Svc/BufferAccumulator/test/ut/Tester.cpp +++ b/Svc/BufferAccumulator/test/ut/Tester.cpp @@ -11,184 +11,123 @@ // ====================================================================== #include "Tester.hpp" -#include + +#include "Fw/Types/BasicTypes.hpp" + #include "Fw/Types/MallocAllocator.hpp" #define INSTANCE 0 -#define MAX_HISTORY_SIZE 10 -#define QUEUE_DEPTH 10 +#define MAX_HISTORY_SIZE 30 +#define QUEUE_DEPTH 30 namespace Svc { - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- - Tester :: - Tester(bool doAllocateQueue) : +Tester ::Tester(bool doAllocateQueue) + : +#if FW_OBJECT_NAMES == 1 BufferAccumulatorGTestBase("Tester", MAX_HISTORY_SIZE), component("BufferAccumulator"), - doAllocateQueue(doAllocateQueue) - { - this->initComponents(); - this->connectPorts(); - - if (this->doAllocateQueue) { - Fw::MallocAllocator buffAccumMallocator; - this->component.allocateQueue(0,buffAccumMallocator,MAX_NUM_BUFFERS); - } +#else + BufferAccumulatorGTestBase(MAX_HISTORY_SIZE), + component(), +#endif + doAllocateQueue(doAllocateQueue) { + this->initComponents(); + this->connectPorts(); + + // Witch to BufferAccumulator_OpState::DRAIN at start so we don't have to + // change ut + component.mode = BufferAccumulator_OpState::DRAIN; + component.send = true; + + if (this->doAllocateQueue) { + Fw::MallocAllocator buffAccumMallocator; + this->component.allocateQueue(0, buffAccumMallocator, MAX_NUM_BUFFERS); } +} - Tester :: - ~Tester() - { - if (this->doAllocateQueue) { - Fw::MallocAllocator buffAccumMallocator; - this->component.deallocateQueue(buffAccumMallocator); - } +Tester ::~Tester() { + if (this->doAllocateQueue) { + Fw::MallocAllocator buffAccumMallocator; + this->component.deallocateQueue(buffAccumMallocator); } +} - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- - void Tester :: - AccumNoAllocate() - { - // TODO (mereweth) - make something sensible happen when no-one sets us up - } +void Tester ::from_bufferSendOutDrain_handler(const NATIVE_INT_TYPE portNum, + Fw::Buffer& fwBuffer) { + this->pushFromPortEntry_bufferSendOutDrain(fwBuffer); +} - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_bufferSendOutDrain_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer& fwBuffer - ) - { - this->pushFromPortEntry_bufferSendOutDrain(fwBuffer); - } +void Tester ::from_bufferSendOutReturn_handler(const NATIVE_INT_TYPE portNum, + Fw::Buffer& fwBuffer) { + this->pushFromPortEntry_bufferSendOutReturn(fwBuffer); +} - void Tester :: - from_bufferSendOutReturn_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer& fwBuffer - ) - { - this->pushFromPortEntry_bufferSendOutReturn(fwBuffer); - } +void Tester ::from_pingOut_handler(const NATIVE_INT_TYPE portNum, U32 key) { + this->pushFromPortEntry_pingOut(key); +} - void Tester :: - from_pingOut_handler( - const NATIVE_INT_TYPE portNum, - U32 key - ) - { - this->pushFromPortEntry_pingOut(key); - } +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - void Tester :: - connectPorts() - { - - // bufferSendInFill - this->connect_to_bufferSendInFill( - 0, - this->component.get_bufferSendInFill_InputPort(0) - ); - - // bufferSendInReturn - this->connect_to_bufferSendInReturn( - 0, - this->component.get_bufferSendInReturn_InputPort(0) - ); - - // cmdIn - this->connect_to_cmdIn( - 0, - this->component.get_cmdIn_InputPort(0) - ); - - // pingIn - this->connect_to_pingIn( - 0, - this->component.get_pingIn_InputPort(0) - ); - - // schedIn - this->connect_to_schedIn( - 0, - this->component.get_schedIn_InputPort(0) - ); - // bufferSendOutDrain - this->component.set_bufferSendOutDrain_OutputPort( - 0, - this->get_from_bufferSendOutDrain(0) - ); - - // bufferSendOutReturn - this->component.set_bufferSendOutReturn_OutputPort( - 0, - this->get_from_bufferSendOutReturn(0) - ); - - // cmdRegOut - this->component.set_cmdRegOut_OutputPort( - 0, - this->get_from_cmdRegOut(0) - ); - - // cmdResponseOut - this->component.set_cmdResponseOut_OutputPort( - 0, - this->get_from_cmdResponseOut(0) - ); - - // eventOut - this->component.set_eventOut_OutputPort( - 0, - this->get_from_eventOut(0) - ); - - // eventOutText - this->component.set_eventOutText_OutputPort( - 0, - this->get_from_eventOutText(0) - ); - // pingOut - this->component.set_pingOut_OutputPort( - 0, - this->get_from_pingOut(0) - ); - - // timeCaller - this->component.set_timeCaller_OutputPort( - 0, - this->get_from_timeCaller(0) - ); - - // tlmOut - this->component.set_tlmOut_OutputPort( - 0, - this->get_from_tlmOut(0) - ); +void Tester ::connectPorts() { + // bufferSendInFill + this->connect_to_bufferSendInFill( + 0, this->component.get_bufferSendInFill_InputPort(0)); + // bufferSendInReturn + this->connect_to_bufferSendInReturn( + 0, this->component.get_bufferSendInReturn_InputPort(0)); - } + // cmdIn + this->connect_to_cmdIn(0, this->component.get_cmdIn_InputPort(0)); - void Tester :: - initComponents() - { - this->init(); - this->component.init( - QUEUE_DEPTH, INSTANCE - ); - } + // pingIn + this->connect_to_pingIn(0, this->component.get_pingIn_InputPort(0)); + + // bufferSendOutDrain + this->component.set_bufferSendOutDrain_OutputPort( + 0, this->get_from_bufferSendOutDrain(0)); + + // bufferSendOutReturn + this->component.set_bufferSendOutReturn_OutputPort( + 0, this->get_from_bufferSendOutReturn(0)); + + // cmdRegOut + this->component.set_cmdRegOut_OutputPort(0, this->get_from_cmdRegOut(0)); + + // cmdResponseOut + this->component.set_cmdResponseOut_OutputPort( + 0, this->get_from_cmdResponseOut(0)); + + // eventOut + this->component.set_eventOut_OutputPort(0, this->get_from_eventOut(0)); + + // eventOutText + this->component.set_eventOutText_OutputPort(0, + this->get_from_eventOutText(0)); + // pingOut + this->component.set_pingOut_OutputPort(0, this->get_from_pingOut(0)); + + // timeCaller + this->component.set_timeCaller_OutputPort(0, this->get_from_timeCaller(0)); + + // tlmOut + this->component.set_tlmOut_OutputPort(0, this->get_from_tlmOut(0)); +} + +void Tester ::initComponents() { + this->init(); + this->component.init(QUEUE_DEPTH, INSTANCE); +} -} // end namespace Svc +} // end namespace Svc diff --git a/Svc/BufferAccumulator/test/ut/Tester.hpp b/Svc/BufferAccumulator/test/ut/Tester.hpp index d785cb8841..e301949c12 100644 --- a/Svc/BufferAccumulator/test/ut/Tester.hpp +++ b/Svc/BufferAccumulator/test/ut/Tester.hpp @@ -20,90 +20,69 @@ namespace Svc { - class Tester : - public BufferAccumulatorGTestBase - { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - - //! Construct object Tester - //! - Tester( - bool doAllocateQueue = true - ); - - //! Destroy object Tester - //! - ~Tester(); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! Try to accumulate without calling allocateQueue - void AccumNoAllocate(); - private: - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_bufferSendOutDrain - //! - void from_bufferSendOutDrain_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - Fw::Buffer& fwBuffer - ); - - //! Handler for from_bufferSendOutReturn - //! - void from_bufferSendOutReturn_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - Fw::Buffer& fwBuffer - ); - - //! Handler for from_pingOut - //! - void from_pingOut_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - U32 key //!< Value to return to pinger - ); - - private: - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - //! Connect ports - //! - void connectPorts(); - - //! Initialize components - //! - void initComponents(); - - protected: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - BufferAccumulator component; - - //! Whether to allocate/deallocate a queue for the user - bool doAllocateQueue; - - }; - -} // end namespace Svc - -#endif //#ifndef TESTER_HPP +class Tester : public BufferAccumulatorGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + //! Construct object Tester + //! + explicit Tester(bool doAllocateQueue = true); + + //! Destroy object Tester + //! + ~Tester(void); + + private: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_bufferSendOutDrain + //! + void from_bufferSendOutDrain_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& fwBuffer); + + //! Handler for from_bufferSendOutReturn + //! + void from_bufferSendOutReturn_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& fwBuffer); + + //! Handler for from_pingOut + //! + void from_pingOut_handler(const NATIVE_INT_TYPE portNum, //!< The port number + U32 key //!< Value to return to pinger + ); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(void); + + //! Initialize components + //! + void initComponents(void); + + protected: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + BufferAccumulator component; + + //! Whether to allocate/deallocate a queue for the user + bool doAllocateQueue; +}; + +} // end namespace Svc + +#endif //#ifndef TESTER_HPP diff --git a/Svc/CMakeLists.txt b/Svc/CMakeLists.txt index d06bcca1ce..fef3e7c53a 100644 --- a/Svc/CMakeLists.txt +++ b/Svc/CMakeLists.txt @@ -13,6 +13,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/WatchDog/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ActiveLogger/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ActiveRateGroup/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/AssertFatalAdapter/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferAccumulator/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferLogger/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferRepeater/") @@ -22,6 +23,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComSplitter/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComStub/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdDispatcher/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdSequencer/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdSplitter/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Deframer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FatalHandler/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlinkPorts/") @@ -33,6 +35,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/GroundInterface/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Framer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FramingProtocol/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Health/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PassiveRateGroup") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PolyDb/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PrmDb/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RateGroupDriver/") diff --git a/Svc/CmdDispatcher/test/int/test_cmd_dispatcher.py b/Svc/CmdDispatcher/test/int/test_cmd_dispatcher.py new file mode 100644 index 0000000000..035f9fb9b4 --- /dev/null +++ b/Svc/CmdDispatcher/test/int/test_cmd_dispatcher.py @@ -0,0 +1,12 @@ +""" test_cmd_dispatcher.py: + +Test the command dispatcher with basic integration tests. +""" + + +def test_send_command(fprime_test_api): + """Test that commands may be sent + + Tests command send, dispatch, and receipt using send_and_assert command with a pair of NO-OP commands. + """ + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) diff --git a/Svc/CmdSplitter/CMakeLists.txt b/Svc/CmdSplitter/CMakeLists.txt new file mode 100644 index 0000000000..85a5c730a0 --- /dev/null +++ b/Svc/CmdSplitter/CMakeLists.txt @@ -0,0 +1,15 @@ +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/CmdSplitter.fpp" + "${CMAKE_CURRENT_LIST_DIR}/CmdSplitter.cpp" +) +register_fprime_module() + +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/CmdSplitter.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + +) +set(UT_MOD_DEPS STest) +set(UT_AUTO_HELPERS ON) +register_fprime_ut() \ No newline at end of file diff --git a/Svc/CmdSplitter/CmdSplitter.cpp b/Svc/CmdSplitter/CmdSplitter.cpp new file mode 100644 index 0000000000..6d850e33d6 --- /dev/null +++ b/Svc/CmdSplitter/CmdSplitter.cpp @@ -0,0 +1,51 @@ +// ====================================================================== +// \title CmdSplitter.cpp +// \author watney +// \brief cpp file for CmdSplitter component implementation class +// ====================================================================== + +#include +#include +#include +#include + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +CmdSplitter ::CmdSplitter(const char* const compName) : CmdSplitterComponentBase(compName) {} + +CmdSplitter ::~CmdSplitter() {} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void CmdSplitter ::CmdBuff_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { + Fw::CmdPacket cmdPkt; + Fw::SerializeStatus stat = cmdPkt.deserialize(data); + + if (stat != Fw::FW_SERIALIZE_OK) { + // Let the local command dispatcher deal with it + this->LocalCmd_out(0, data, context); + } else { + // Check if local or remote + if (cmdPkt.getOpCode() < CMD_SPLITTER_REMOTE_OPCODE_BASE) { + this->LocalCmd_out(0, data, context); + } else { + this->RemoteCmd_out(0, data, context); + } + } +} + +void CmdSplitter ::seqCmdStatus_handler(const NATIVE_INT_TYPE portNum, + FwOpcodeType opCode, + U32 cmdSeq, + const Fw::CmdResponse& response) { + // Forward the command status + this->forwardSeqCmdStatus_out(portNum, opCode, cmdSeq, response); +} + +} // end namespace Svc diff --git a/Svc/CmdSplitter/CmdSplitter.fpp b/Svc/CmdSplitter/CmdSplitter.fpp new file mode 100644 index 0000000000..6d408f05af --- /dev/null +++ b/Svc/CmdSplitter/CmdSplitter.fpp @@ -0,0 +1,27 @@ + +module Svc { + + @ A component for splitting incoming commands to local or remote + passive component CmdSplitter { + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Input port for local or remote commands + sync input port CmdBuff: Fw.Com + + @ Input port for receiving the command status + sync input port seqCmdStatus: Fw.CmdResponse + + @ Output port for forwarding the Command status + output port forwardSeqCmdStatus: Fw.CmdResponse + + @ Output port for local commands + output port LocalCmd: Fw.Com + + @ Output port for remote commands + output port RemoteCmd: Fw.Com + + } +} \ No newline at end of file diff --git a/Svc/CmdSplitter/CmdSplitter.hpp b/Svc/CmdSplitter/CmdSplitter.hpp new file mode 100644 index 0000000000..ae76cba6b6 --- /dev/null +++ b/Svc/CmdSplitter/CmdSplitter.hpp @@ -0,0 +1,54 @@ +// ====================================================================== +// \title CmdSplitter.hpp +// \author watney +// \brief hpp file for CmdSplitter component implementation class +// ====================================================================== + +#ifndef CmdSplitter_HPP +#define CmdSplitter_HPP + +#include +#include "Svc/CmdSplitter/CmdSplitterComponentAc.hpp" + +namespace Svc { + +class CmdSplitter : public CmdSplitterComponentBase { + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object CmdSplitter + //! + CmdSplitter(const char* const compName /*!< The component name*/ + ); + + //! Destroy object CmdSplitter + //! + ~CmdSplitter(); + + PRIVATE : + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for CmdBuff + //! + void CmdBuff_handler(const NATIVE_INT_TYPE portNum, /*!< The port number */ + Fw::ComBuffer& data, /*!< Buffer containing packet data */ + U32 context /*!< Call context value; meaning chosen by user */ + ); + + //! Handler implementation for seqCmdStatus + //! + void seqCmdStatus_handler(const NATIVE_INT_TYPE portNum, /*!< The port number */ + FwOpcodeType opCode, /*!< Command Op Code */ + U32 cmdSeq, /*!< Command Sequence */ + const Fw::CmdResponse& response /*!< The command response argument */ + ); +}; + +} // end namespace Svc + +#endif diff --git a/Svc/CmdSplitter/docs/sdd.md b/Svc/CmdSplitter/docs/sdd.md new file mode 100644 index 0000000000..206b53fede --- /dev/null +++ b/Svc/CmdSplitter/docs/sdd.md @@ -0,0 +1,55 @@ +\page SvcCmdSplitter Svc::CmdSplitter Component +# Svc::CmdSplitter Component + +## 1. Introduction + +The `Svc::CmdSplitter` splits an uplinked command execution to two separate `Svc::CmdDispatcher` components: one "local" and the other "remote". This splitting is done by opcode where local commands are commands whose opcode is less than `Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE` and remote commands are those opcodes equal to or larger than that configuration setting. `Svc::CmdSplitter` is intended to be used as part of the hub pattern to route command to a command dispatcher in the remote deployment. + +## 2. Requirements + +The requirements for `Svc::CmdSplitter` are as follows: + +| Requirement | Description | Verification Method | +|----------------------|------------------------------------------------------------------------------------------------------|---------------------| +| SVC-CMD-SPLITTER-001 | The `Svc::CmdSplitter` component shall accept incoming command buffers. | Unit Test | +| SVC-CMD-SPLITTER-002 | The `Svc::CmdSplitter` component shall route commands under a configured value to the "local" port. | Unit Test | +| SVC-CMD-SPLITTER-003 | The `Svc::CmdSplitter` component shall route commands under a configured value to the "remote" port. | Unit Test | +| SVC-CMD-SPLITTER-004 | The `Svc::CmdSplitter` component shall route commands to the "local" port when an error occurs. | Unit Test | +| SVC-CMD-SPLITTER-005 | The `Svc::CmdSplitter` forward command status responses. | Unit Test | + +## 3. Design + +### 3.1 Ports + +| Name | Type | Kind | Description | +|---------------------|----------------|------------|-----------------------------------------------------------------| +| CmdBuff | Fw.Com | sync input | Incoming command buffer. | +| seqCmdStatus | Fw.CmdResponse | sync input | Incoming command status from both local and remote dispatchers. | +| LocalCmd | Fw.Com | sync input | Outgoing command buffer for local command dispatcher. | +| RemoteCmd | Fw.Com | sync input | Outgoing command buffer for remote command dispatcher. | +| forwardSeqCmdStatus | Fw.CmdResponse | sync input | Outgoing forwarded command status. | + +### 3.2 Functional Description + +The `Svc::CmdSplitter` routes an incoming command buffer of type `Fw::ComBuffer` to a local or remote command dispatcher. This is done by comparing the command's opcode to the `Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE` configuration value. All command responses are forwarded through. + +### 3.1 State + +`Svc::CmdSplitter` has no state machines nor internal state. + +### 3.2 Algorithms + +`Svc::CmdSplitter` has no significant algorithms. + +## 4. Unit Testing + +To see unit test coverage run `fprime-util check --coverage` in the `Svc::CmdSplitter` directory + +## 5. Change Log + +| Date | Description | +|------------|-------------| +| 2023-06-12 | Initial | + + + diff --git a/Svc/CmdSplitter/test/ut/TestMain.cpp b/Svc/CmdSplitter/test/ut/TestMain.cpp new file mode 100644 index 0000000000..15566c052e --- /dev/null +++ b/Svc/CmdSplitter/test/ut/TestMain.cpp @@ -0,0 +1,33 @@ +// ---------------------------------------------------------------------- +// TestMain.cpp +// ---------------------------------------------------------------------- + +#include "Tester.hpp" + +TEST(Nominal, Local) { + Svc::Tester tester; + tester.test_local_routing(); +} + +TEST(Nominal, Remote) { + Svc::Tester tester; + tester.test_remote_routing(); +} + +TEST(Nominal, Forwarding) { + Svc::Tester tester; + tester.test_response_forwarding(); +} + +TEST(Error, BadCommands) { + Svc::Tester tester; + tester.test_error_routing(); +} + + + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Svc/CmdSplitter/test/ut/Tester.cpp b/Svc/CmdSplitter/test/ut/Tester.cpp new file mode 100644 index 0000000000..6a44e98daf --- /dev/null +++ b/Svc/CmdSplitter/test/ut/Tester.cpp @@ -0,0 +1,123 @@ +// ====================================================================== +// \title CmdSplitter.hpp +// \author mstarch +// \brief cpp file for CmdSplitter test harness implementation class +// ====================================================================== + +#include "Tester.hpp" +#include +#include +#include +#include + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() : CmdSplitterGTestBase("Tester", Tester::MAX_HISTORY_SIZE), component("CmdSplitter") { + this->initComponents(); + this->connectPorts(); +} + +Tester ::~Tester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +Fw::ComBuffer Tester ::build_command_around_opcode(FwOpcodeType opcode) { + Fw::ComBuffer comBuffer; + EXPECT_EQ(comBuffer.serialize(static_cast(Fw::ComPacket::FW_PACKET_COMMAND)), Fw::FW_SERIALIZE_OK); + EXPECT_EQ(comBuffer.serialize(opcode), Fw::FW_SERIALIZE_OK); + + Fw::CmdArgBuffer args; + + U32 random_size = STest::Pick::lowerUpper(0, args.getBuffCapacity()); + args.resetSer(); + for (FwSizeType i = 0; i < random_size; i++) { + args.serialize(static_cast(STest::Pick::any())); + } + EXPECT_EQ(comBuffer.serialize(args), Fw::FW_SERIALIZE_OK); + return comBuffer; +} + +void Tester ::test_local_routing() { + REQUIREMENT("SVC-CMD-SPLITTER-001"); + REQUIREMENT("SVC-CMD-SPLITTER-002"); + + ASSERT_GT(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE, 0); // Must leave some room for local commands + FwOpcodeType local_opcode = static_cast(STest::Pick::lowerUpper( + 0, FW_MIN(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE - 1, std::numeric_limits::max()))); + Fw::ComBuffer testBuffer = this->build_command_around_opcode(local_opcode); + + U32 context = static_cast(STest::Pick::any()); + this->invoke_to_CmdBuff(0, testBuffer, context); + ASSERT_from_RemoteCmd_SIZE(0); + ASSERT_from_LocalCmd_SIZE(1); + ASSERT_from_LocalCmd(0, testBuffer, context); +} + +void Tester ::test_remote_routing() { + REQUIREMENT("SVC-CMD-SPLITTER-001"); + REQUIREMENT("SVC-CMD-SPLITTER-003"); + + ASSERT_LT(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE, + std::numeric_limits::max()); // Must leave some room for remote commands + FwOpcodeType local_opcode = static_cast( + STest::Pick::lowerUpper(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE, std::numeric_limits::max())); + Fw::ComBuffer testBuffer = this->build_command_around_opcode(local_opcode); + + U32 context = static_cast(STest::Pick::any()); + this->invoke_to_CmdBuff(0, testBuffer, context); + ASSERT_from_LocalCmd_SIZE(0); + ASSERT_from_RemoteCmd_SIZE(1); + ASSERT_from_RemoteCmd(0, testBuffer, context); +} + +void Tester ::test_error_routing() { + REQUIREMENT("SVC-CMD-SPLITTER-001"); + REQUIREMENT("SVC-CMD-SPLITTER-004"); + Fw::ComBuffer testBuffer; // Intentionally left empty + U32 context = static_cast(STest::Pick::any()); + this->invoke_to_CmdBuff(0, testBuffer, context); + ASSERT_from_RemoteCmd_SIZE(0); + ASSERT_from_LocalCmd_SIZE(1); + ASSERT_from_LocalCmd(0, testBuffer, context); +} + +void Tester ::test_response_forwarding() { + REQUIREMENT("SVC-CMD-SPLITTER-001"); + REQUIREMENT("SVC-CMD-SPLITTER-005"); + + FwOpcodeType opcode = + static_cast(STest::Pick::lowerUpper(0, std::numeric_limits::max())); + Fw::CmdResponse response; + response.e = static_cast(STest::Pick::lowerUpper(0, Fw::CmdResponse::NUM_CONSTANTS)); + U32 cmdSeq = static_cast(STest::Pick::any()); + this->invoke_to_seqCmdStatus(0, opcode, cmdSeq, response); + ASSERT_from_forwardSeqCmdStatus_SIZE(1); + ASSERT_from_forwardSeqCmdStatus(0, opcode, cmdSeq, response); +} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void Tester ::from_LocalCmd_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { + this->pushFromPortEntry_LocalCmd(data, context); +} + +void Tester ::from_RemoteCmd_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { + this->pushFromPortEntry_RemoteCmd(data, context); +} + +void Tester ::from_forwardSeqCmdStatus_handler(const NATIVE_INT_TYPE portNum, + FwOpcodeType opCode, + U32 cmdSeq, + const Fw::CmdResponse& response) { + this->pushFromPortEntry_forwardSeqCmdStatus(opCode, cmdSeq, response); +} + +} // end namespace Svc diff --git a/Svc/CmdSplitter/test/ut/Tester.hpp b/Svc/CmdSplitter/test/ut/Tester.hpp new file mode 100644 index 0000000000..02ad1d07d5 --- /dev/null +++ b/Svc/CmdSplitter/test/ut/Tester.hpp @@ -0,0 +1,111 @@ +// ====================================================================== +// \title CmdSplitter/test/ut/Tester.hpp +// \author mstarch +// \brief hpp file for CmdSplitter test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "GTestBase.hpp" +#include "Svc/CmdSplitter/CmdSplitter.hpp" + +namespace Svc { + +class Tester : public CmdSplitterGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10; + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Test that commands under a limit route locally + //! + void test_local_routing(); + + //! Test the commands above the limit route remotely + //! + void test_remote_routing(); + + //! Test that errored command route locally + //! + void test_error_routing(); + + //! Test that command response forwarding works + //! + void test_response_forwarding(); + + private: + //! Helper to build a com buffer given an opcode + //! + Fw::ComBuffer build_command_around_opcode(FwOpcodeType opcode); + + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_LocalCmd + //! + void from_LocalCmd_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::ComBuffer& data, /*!< Buffer containing packet data */ + U32 context /*!< Call context value; meaning chosen by user */ + ); + + //! Handler for from_RemoteCmd + //! + void from_RemoteCmd_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::ComBuffer& data, /*!< Buffer containing packet data */ + U32 context /*!< Call context value; meaning chosen by user */ + ); + + //! Handler for from_forwardSeqCmdStatus + //! + void from_forwardSeqCmdStatus_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwOpcodeType opCode, /*!< Command Op Code */ + U32 cmdSeq, /*!< Command Sequence */ + const Fw::CmdResponse& response /*!< The command response argument */ + ); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + private: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + CmdSplitter component; +}; + +} // end namespace Svc + +#endif diff --git a/Svc/ComLogger/ComLogger.cpp b/Svc/ComLogger/ComLogger.cpp index af1d27f621..a82d283937 100644 --- a/Svc/ComLogger/ComLogger.cpp +++ b/Svc/ComLogger/ComLogger.cpp @@ -25,21 +25,29 @@ namespace Svc { byteCount(0), writeErrorOccurred(false), openErrorOccurred(false), - storeBufferLength(storeBufferLength) + storeBufferLength(storeBufferLength), + initialized(true) { - if( this->storeBufferLength ) { - FW_ASSERT(maxFileSize > sizeof(U16), maxFileSize); // must be a positive integer greater than buffer length size - } - else { - FW_ASSERT(maxFileSize > 0, maxFileSize); // must be a positive integer - } - FW_ASSERT(Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->filePrefix)) < sizeof(this->filePrefix), - Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->filePrefix)), sizeof(this->filePrefix)); // ensure that file prefix is not too big + this->init_log_file(incomingFilePrefix, maxFileSize, storeBufferLength); + } - // Set the file prefix: - Fw::StringUtils::string_copy(this->filePrefix, incomingFilePrefix, sizeof(this->filePrefix)); + ComLogger :: + ComLogger(const char* compName) : + ComLoggerComponentBase(compName), + filePrefix(), + maxFileSize(0), + fileMode(CLOSED), + fileName(), + hashFileName(), + byteCount(0), + writeErrorOccurred(false), + openErrorOccurred(false), + storeBufferLength(), + initialized(false) + { } + void ComLogger :: init( NATIVE_INT_TYPE queueDepth, //!< The queue depth @@ -49,6 +57,25 @@ namespace Svc { ComLoggerComponentBase::init(queueDepth, instance); } + void ComLogger :: + init_log_file(const char* incomingFilePrefix, U32 maxFileSize, bool storeBufferLength) + { + FW_ASSERT(incomingFilePrefix != nullptr); + this->maxFileSize = maxFileSize; + this->storeBufferLength = storeBufferLength; + if( this->storeBufferLength ) { + FW_ASSERT(maxFileSize > sizeof(U16), maxFileSize); + } + + FW_ASSERT(Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->filePrefix)) < sizeof(this->filePrefix), + Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->filePrefix)), sizeof(this->filePrefix)); // ensure that file prefix is not too big + + (void)Fw::StringUtils::string_copy(this->filePrefix, incomingFilePrefix, sizeof(this->filePrefix)); + + this->initialized = true; + } + + ComLogger :: ~ComLogger() { @@ -142,6 +169,11 @@ namespace Svc { { FW_ASSERT( CLOSED == this->fileMode ); + if( !this->initialized ){ + this->log_WARNING_LO_FileNotInitialized(); + return; + } + U32 bytesCopied; // Create filename: diff --git a/Svc/ComLogger/ComLogger.hpp b/Svc/ComLogger/ComLogger.hpp index 248efebd47..1a8cbf53dc 100644 --- a/Svc/ComLogger/ComLogger.hpp +++ b/Svc/ComLogger/ComLogger.hpp @@ -52,11 +52,23 @@ namespace Svc { // match to an expected size on the ground during post processing. ComLogger(const char* compName, const char* filePrefix, U32 maxFileSize, bool storeBufferLength=true); + // CONSTRUCTOR: + ComLogger(const char* compName); + void init( NATIVE_INT_TYPE queueDepth, //!< The queue depth NATIVE_INT_TYPE instance //!< The instance number ); + // filePrefix: string to prepend the file name with, ie. "thermal_telemetry" + // maxFileSize: the maximum size a file should reach before being closed and a new one opened + // storeBufferLength: if true, store the length of each com buffer before storing the buffer itself, + // otherwise just store the com buffer. false might be advantageous in a system + // where you can ensure that all buffers given to the ComLogger are the same size + // in which case you do not need the overhead. Or you store an id which you can + // match to an expected size on the ground during post processing. + void init_log_file(const char* filePrefix, U32 maxFileSize, bool storeBufferLength=true); + ~ComLogger(); // ---------------------------------------------------------------------- @@ -112,6 +124,7 @@ namespace Svc { bool writeErrorOccurred; bool openErrorOccurred; bool storeBufferLength; + bool initialized; // ---------------------------------------------------------------------- // File functions: diff --git a/Svc/ComLogger/Events.fppi b/Svc/ComLogger/Events.fppi index e55a4dff74..6931201443 100644 --- a/Svc/ComLogger/Events.fppi +++ b/Svc/ComLogger/Events.fppi @@ -35,3 +35,9 @@ event FileClosed( severity diagnostic \ id 0x03 \ format "File {} closed successfully." + +event FileNotInitialized \ + severity warning low \ + id 0x04 \ + format "Could not open ComLogger file. File not initialized" \ + throttle 5 diff --git a/Svc/ComLogger/test/ut/Main.cpp b/Svc/ComLogger/test/ut/Main.cpp index 5fd18b9425..0f8a88e32b 100644 --- a/Svc/ComLogger/test/ut/Main.cpp +++ b/Svc/ComLogger/test/ut/Main.cpp @@ -31,6 +31,16 @@ TEST(Test, closeFileCommand) { tester.closeFileCommand(); } +TEST(Test, testLoggingWithInit) { + Svc::Tester tester("Tester", true); + tester.testLoggingWithInit(); +} + +TEST(Test, noInitError) { + Svc::Tester tester("Tester", true); + tester.noInitError(); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/Svc/ComLogger/test/ut/Tester.cpp b/Svc/ComLogger/test/ut/Tester.cpp index 18020874ee..b5929f7a9d 100644 --- a/Svc/ComLogger/test/ut/Tester.cpp +++ b/Svc/ComLogger/test/ut/Tester.cpp @@ -25,6 +25,20 @@ namespace Svc { this->initComponents(); } + Tester :: + Tester( + const char *const compName, + bool standardCLInit + ) : + ComLoggerGTestBase(compName, 30), + comLogger("ComLogger") + { + this->connectPorts(); + this->initComponents(); + + (void)standardCLInit; + } + Tester :: ~Tester() { @@ -553,6 +567,147 @@ namespace Svc { file.close(); } + void Tester :: + testLoggingWithInit() + { + CHAR fileName[2048]; + CHAR prevFileName[2048]; + CHAR hashFileName[2048]; + CHAR prevHashFileName[2048]; + U8 buf[1024]; + NATIVE_INT_TYPE length; + U16 bufferSize = 0; + Os::File::Status ret; + Os::File file; + + this->comLogger.init_log_file(FILE_STR, MAX_BYTES_PER_FILE); + + ASSERT_TRUE(comLogger.fileMode == ComLogger::CLOSED); + ASSERT_EVENTS_SIZE(0); + + U8 data[COM_BUFFER_LENGTH] = {0xde,0xad,0xbe,0xef}; + Fw::ComBuffer buffer(&data[0], sizeof(data)); + + Fw::SerializeStatus stat; + + for(int j = 0; j < 3; j++) + { + // Test times for the different iterations: + Fw::Time testTime(TB_NONE, j, 9876543); + Fw::Time testTimePrev(TB_NONE, j-1, 9876543); + Fw::Time testTimeNext(TB_NONE, j+1, 9876543); + + // File names for the different iterations: + memset(fileName, 0, sizeof(fileName)); + snprintf(fileName, sizeof(fileName), "%s_%d_%d_%06d.com", FILE_STR, testTime.getTimeBase(), testTime.getSeconds(), testTime.getUSeconds()); + memset(hashFileName, 0, sizeof(hashFileName)); + snprintf(hashFileName, sizeof(hashFileName), "%s_%d_%d_%06d.com%s", FILE_STR, testTime.getTimeBase(), testTime.getSeconds(), testTime.getUSeconds(), Utils::Hash::getFileExtensionString()); + memset(prevFileName, 0, sizeof(prevFileName)); + snprintf(prevFileName, sizeof(prevFileName), "%s_%d_%d_%06d.com", FILE_STR, testTime.getTimeBase(), testTimePrev.getSeconds(), testTimePrev.getUSeconds()); + memset(prevHashFileName, 0, sizeof(prevHashFileName)); + snprintf(prevHashFileName, sizeof(prevHashFileName), "%s_%d_%d_%06d.com%s", FILE_STR, testTime.getTimeBase(), testTimePrev.getSeconds(), testTimePrev.getUSeconds(), Utils::Hash::getFileExtensionString()); + + // Set the test time to the current time: + setTestTime(testTime); + + // Write to file: + for(int i = 0; i < MAX_ENTRIES_PER_FILE-1; i++) + { + invoke_to_comIn(0, buffer, 0); + dispatchAll(); + ASSERT_TRUE(comLogger.fileMode == ComLogger::OPEN); + } + + // OK a new file should be opened after this final invoke, set a new test time so that a file + // with a new name gets opened: + setTestTime(testTimeNext); + invoke_to_comIn(0, buffer, 0); + dispatchAll(); + ASSERT_TRUE(comLogger.fileMode == ComLogger::OPEN); + + // A new file should have been opened from the previous loop iteration: + if( j > 0 ) { + ASSERT_TRUE(comLogger.fileMode == ComLogger::OPEN); + ASSERT_TRUE(strcmp(static_cast(comLogger.fileName), fileName) == 0 ); + } + + // Make sure we got a closed file event: + ASSERT_EVENTS_SIZE(j); + ASSERT_EVENTS_FileClosed_SIZE(j); + if( j > 0 ) { + ASSERT_EVENTS_FileClosed(j-1, prevFileName); + } + + // Make sure the file size is smaller or equal to the limit: + Os::FileSystem::Status fsStat; + FwSizeType fileSize = 0; + fsStat = Os::FileSystem::getFileSize(fileName, fileSize); //!< gets the size of the file (in bytes) at location path + ASSERT_EQ(fsStat, Os::FileSystem::OP_OK); + ASSERT_LE(fileSize, MAX_BYTES_PER_FILE); + + // Open file: + ret = file.open(fileName, Os::File::OPEN_READ); + ASSERT_EQ(Os::File::OP_OK,ret); + + // Check data: + for(int i = 0; i < 5; i++) + { + // Get length of buffer to read + NATIVE_INT_TYPE length = sizeof(U16); + ret = file.read(&buf, length); + ASSERT_EQ(Os::File::OP_OK, ret); + ASSERT_EQ(length, static_cast(sizeof(U16))); + Fw::SerialBuffer comBuffLength(buf, length); + comBuffLength.fill(); + stat = comBuffLength.deserialize(bufferSize); + ASSERT_EQ(stat, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(COM_BUFFER_LENGTH, bufferSize); + + // Read and check buffer: + length = bufferSize; + ret = file.read(&buf, length); + ASSERT_EQ(Os::File::OP_OK,ret); + ASSERT_EQ(length, static_cast(bufferSize)); + ASSERT_EQ(memcmp(buf, data, COM_BUFFER_LENGTH), 0); + } + + // Make sure we reached the end of the file: + length = sizeof(NATIVE_INT_TYPE); + ret = file.read(&buf, length); + ASSERT_EQ(Os::File::OP_OK,ret); + ASSERT_EQ(length, 0); + file.close(); + + // Assert that the hashes match: + if( j > 0 ) { + Os::ValidateFile::Status status; + status = Os::ValidateFile::validate(prevFileName, prevHashFileName); + ASSERT_EQ(Os::ValidateFile::VALIDATION_OK, status); + } + } + } + + void Tester :: + noInitError() + { + U8 data[COM_BUFFER_LENGTH] = {0xde,0xad,0xbe,0xef}; + Fw::ComBuffer buffer(&data[0], sizeof(data)); + + this->invoke_to_comIn(0, buffer, 0); + dispatchAll(); + ASSERT_TRUE(comLogger.fileMode == ComLogger::CLOSED); + ASSERT_EVENTS_FileNotInitialized_SIZE(1); + + this->comLogger.init_log_file(FILE_STR, MAX_BYTES_PER_FILE); + + this->clearHistory(); + this->invoke_to_comIn(0, buffer, 0); + dispatchAll(); + ASSERT_TRUE(comLogger.fileMode == ComLogger::OPEN); + ASSERT_EVENTS_FileNotInitialized_SIZE(0); + + } + void Tester :: from_pingOut_handler( const NATIVE_INT_TYPE portNum, diff --git a/Svc/ComLogger/test/ut/Tester.hpp b/Svc/ComLogger/test/ut/Tester.hpp index ac6d6467c1..cbb1fc40fa 100644 --- a/Svc/ComLogger/test/ut/Tester.hpp +++ b/Svc/ComLogger/test/ut/Tester.hpp @@ -24,6 +24,10 @@ namespace Svc { public: Tester(const char *const compName); + + // This constructor will construct comLogger with its + // standard constructor + Tester(const char *const compName, bool standardCLInit); ~Tester(); void testLogging(); @@ -31,6 +35,8 @@ namespace Svc { void openError(); void writeError(); void closeFileCommand(); + void testLoggingWithInit(); + void noInitError(); private: void connectPorts(); void initComponents(); diff --git a/Svc/ComStub/test/ut/Tester.hpp b/Svc/ComStub/test/ut/Tester.hpp index 6f794d6354..e15c2479d4 100644 --- a/Svc/ComStub/test/ut/Tester.hpp +++ b/Svc/ComStub/test/ut/Tester.hpp @@ -57,21 +57,19 @@ class Tester : public ComStubGTestBase { //! Handler for from_comDataOut //! - void from_comDataOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + void from_comDataOut_handler(const NATIVE_INT_TYPE portNum, //!< The port number Fw::Buffer& recvBuffer, const Drv::RecvStatus& recvStatus); //! Handler for from_comStatus //! - void from_comStatus_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Success& condition /*!< - Status of communication state - */ + void from_comStatus_handler(const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Success& condition //!< Status of communication state ); //! Handler for from_drvDataOut //! - Drv::SendStatus from_drvDataOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Drv::SendStatus from_drvDataOut_handler(const NATIVE_INT_TYPE portNum, //!< The port number Fw::Buffer& sendBuffer); private: diff --git a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp index 2805682255..ff72572eba 100644 --- a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace Svc { diff --git a/Svc/Framer/Framer.fpp b/Svc/Framer/Framer.fpp index 3017d2380f..b71ea772ba 100644 --- a/Svc/Framer/Framer.fpp +++ b/Svc/Framer/Framer.fpp @@ -40,7 +40,7 @@ module Svc { @ Port receiving the general status from the downstream component @ indicating it is ready or not-ready for more input - guarded input port comStatusIn: Fw.SuccessCondition + sync input port comStatusIn: Fw.SuccessCondition @ Port receiving indicating the status of framer for receiving more data output port comStatusOut: Fw.SuccessCondition diff --git a/Svc/GenericHub/CMakeLists.txt b/Svc/GenericHub/CMakeLists.txt index c540994354..d6508e1a37 100644 --- a/Svc/GenericHub/CMakeLists.txt +++ b/Svc/GenericHub/CMakeLists.txt @@ -21,4 +21,5 @@ set(UT_MOD_DEPS Fw/Com STest ) + register_fprime_ut() diff --git a/Svc/GenericHub/GenericHub.fpp b/Svc/GenericHub/GenericHub.fpp index a9ddd9fa3f..a495c4a729 100644 --- a/Svc/GenericHub/GenericHub.fpp +++ b/Svc/GenericHub/GenericHub.fpp @@ -3,18 +3,34 @@ module Svc { @ A generic hub component passive component GenericHub { + # ---------------------------------------------------------------------- + # Mimic Ports + # ---------------------------------------------------------------------- + + @ Telemetry input port for mimicking an event processor + sync input port TlmRecv: Fw.Tlm + + @ Event input port for mimicking an event processor + sync input port LogRecv: Fw.Log + + @ Cross-hub event output port + output port LogSend: Fw.Log + + @ Cross-hub telemetry output port + output port TlmSend: Fw.Tlm + # ---------------------------------------------------------------------- # General Ports # ---------------------------------------------------------------------- @ Input array of generic ports to shuttle to the other side of the hub connection - guarded input port portIn: [GenericHubInputPorts] serial + sync input port portIn: [GenericHubInputPorts] serial @ Output array of generic ports shuttled from the other side of the hub connection output port portOut: [GenericHubOutputPorts] serial @ Input array of generic ports shuttling in copy-free buffers form external sources - guarded input port buffersIn: [GenericHubInputBuffers] Fw.BufferSend + sync input port buffersIn: [GenericHubInputBuffers] Fw.BufferSend @ Output array of generic ports shuttling in copy-free buffers form external sources output port buffersOut: [GenericHubOutputBuffers] Fw.BufferSend diff --git a/Svc/GenericHub/GenericHubComponentImpl.cpp b/Svc/GenericHub/GenericHubComponentImpl.cpp index 0b6623fd12..1186378f72 100644 --- a/Svc/GenericHub/GenericHubComponentImpl.cpp +++ b/Svc/GenericHub/GenericHubComponentImpl.cpp @@ -10,10 +10,10 @@ // // ====================================================================== +#include #include #include "Fw/Logger/Logger.hpp" #include "Fw/Types/Assert.hpp" -#include // Required port serialization or the hub cannot work static_assert(FW_PORT_SERIALIZATION, "FW_PORT_SERIALIZATION must be enabled to use GenericHub"); @@ -50,7 +50,6 @@ void GenericHubComponentImpl ::send_data(const HubType type, FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); outgoing.setSize(serialize.getBuffLength()); dataOut_out(0, outgoing); - } // ---------------------------------------------------------------------- @@ -62,8 +61,7 @@ void GenericHubComponentImpl ::buffersIn_handler(const NATIVE_INT_TYPE portNum, bufferDeallocate_out(0, fwBuffer); } -void GenericHubComponentImpl ::dataIn_handler(const NATIVE_INT_TYPE portNum, - Fw::Buffer& fwBuffer) { +void GenericHubComponentImpl ::dataIn_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { HubType type = HUB_TYPE_MAX; U32 type_in = 0; U32 port = 0; @@ -96,13 +94,85 @@ void GenericHubComponentImpl ::dataIn_handler(const NATIVE_INT_TYPE portNum, status = wrapper.setBuffLen(rawSize); FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); portOut_out(port, wrapper); + // Deallocate the existing buffer dataInDeallocate_out(0, fwBuffer); } else if (type == HUB_TYPE_BUFFER) { + // Fw::Buffers can reuse the existing data buffer as the storage type! No deallocation done. fwBuffer.set(rawData, rawSize, fwBuffer.getContext()); buffersOut_out(port, fwBuffer); + } else if (type == HUB_TYPE_EVENT) { + FwEventIdType id; + Fw::Time timeTag; + Fw::LogSeverity severity; + Fw::LogBuffer args; + + // Deserialize tokens for events + status = incoming.deserialize(id); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); + status = incoming.deserialize(timeTag); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); + status = incoming.deserialize(severity); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); + status = incoming.deserialize(args); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); + + // Send it! + this->LogSend_out(port, id, timeTag, severity, args); + + // Deallocate the existing buffer + dataInDeallocate_out(0, fwBuffer); + } else if (type == HUB_TYPE_CHANNEL) { + FwChanIdType id; + Fw::Time timeTag; + Fw::TlmBuffer val; + + // Deserialize tokens for channels + status = incoming.deserialize(id); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); + status = incoming.deserialize(timeTag); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); + status = incoming.deserialize(val); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast(status)); + + // Send it! + this->TlmSend_out(port, id, timeTag, val); + + // Deallocate the existing buffer + dataInDeallocate_out(0, fwBuffer); } } +void GenericHubComponentImpl ::LogRecv_handler(const NATIVE_INT_TYPE portNum, + FwEventIdType id, + Fw::Time& timeTag, + const Fw::LogSeverity& severity, + Fw::LogBuffer& args) { + U8 buffer[sizeof(FwEventIdType) + Fw::Time::SERIALIZED_SIZE + Fw::LogSeverity::SERIALIZED_SIZE + FW_LOG_BUFFER_MAX_SIZE]; + Fw::ExternalSerializeBuffer serializer(buffer, sizeof(buffer)); + serializer.resetSer(); + FW_ASSERT(serializer.serialize(id) == Fw::SerializeStatus::FW_SERIALIZE_OK);; + FW_ASSERT(serializer.serialize(timeTag) == Fw::SerializeStatus::FW_SERIALIZE_OK); + FW_ASSERT(serializer.serialize(severity) == Fw::SerializeStatus::FW_SERIALIZE_OK); + FW_ASSERT(serializer.serialize(args) == Fw::SerializeStatus::FW_SERIALIZE_OK); + U32 size = serializer.getBuffLength(); + this->send_data(HubType::HUB_TYPE_EVENT, portNum, buffer, size); + +} + +void GenericHubComponentImpl ::TlmRecv_handler(const NATIVE_INT_TYPE portNum, + FwChanIdType id, + Fw::Time& timeTag, + Fw::TlmBuffer& val) { + U8 buffer[sizeof(FwChanIdType) + Fw::Time::SERIALIZED_SIZE + FW_TLM_BUFFER_MAX_SIZE]; + Fw::ExternalSerializeBuffer serializer(buffer, sizeof(buffer)); + serializer.resetSer(); + FW_ASSERT(serializer.serialize(id) == Fw::SerializeStatus::FW_SERIALIZE_OK); + FW_ASSERT(serializer.serialize(timeTag) == Fw::SerializeStatus::FW_SERIALIZE_OK); + FW_ASSERT(serializer.serialize(val) == Fw::SerializeStatus::FW_SERIALIZE_OK); + U32 size = serializer.getBuffLength(); + this->send_data(HubType::HUB_TYPE_CHANNEL, portNum, buffer, size); +} + // ---------------------------------------------------------------------- // Handler implementations for user-defined serial input ports // ---------------------------------------------------------------------- diff --git a/Svc/GenericHub/GenericHubComponentImpl.hpp b/Svc/GenericHub/GenericHubComponentImpl.hpp index 02a0ce6f54..f53057af85 100644 --- a/Svc/GenericHub/GenericHubComponentImpl.hpp +++ b/Svc/GenericHub/GenericHubComponentImpl.hpp @@ -27,6 +27,8 @@ class GenericHubComponentImpl : public GenericHubComponentBase { enum HubType { HUB_TYPE_PORT, //!< Port type transmission HUB_TYPE_BUFFER, //!< Buffer type transmission + HUB_TYPE_EVENT, //!< Event transmission + HUB_TYPE_CHANNEL, //!< Telemetry channel type HUB_TYPE_MAX }; @@ -64,6 +66,23 @@ class GenericHubComponentImpl : public GenericHubComponentBase { void dataIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ Fw::Buffer& fwBuffer); + //! Handler implementation for LogRecv + //! + void LogRecv_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwEventIdType id, /*!< Log ID */ + Fw::Time& timeTag, /*!< Time Tag */ + const Fw::LogSeverity& severity, /*!< The severity argument */ + Fw::LogBuffer& args /*!< Buffer containing serialized log entry */ + ); + + //! Handler implementation for TlmRecv + //! + void TlmRecv_handler(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 */ + ); + // ---------------------------------------------------------------------- // Handler implementations for user-defined serial input ports // ---------------------------------------------------------------------- diff --git a/Svc/GenericHub/docs/sdd.md b/Svc/GenericHub/docs/sdd.md index 07fe96d654..d8c1d77a46 100644 --- a/Svc/GenericHub/docs/sdd.md +++ b/Svc/GenericHub/docs/sdd.md @@ -23,6 +23,9 @@ It is also essential that users never pass a **pointer** into the generic hub, a leaves the current address space. A sample configuration is shown below. Finally, the generic hub is bidirectional, so it can operate on inputs and produce outputs as long as its remote counterpart is hooked up in parallel. +The hub also provides specific handlers for events and telemetry such that it can be used with telemetry and event +pattern specifiers in the topology. + ### Example Formations This section shows how to set up the generic hub component. It is broken into several separate views. This first shows @@ -65,12 +68,22 @@ GenericHubOutputBuffers = 10 The above configuration may be used with both deployments hubs as the input/output pairs match. +To use the hub in a pattern specifier, include this in your topology: + +``` + event connections instance hub + telemetry connections instance hub +``` + ## Idiosyncrasies Currently, the `Drv::ByteStreamDriverModel` can report errors and failures. This generic hub component drops these errors. Users who expect the driver to error should adapt this component to handle this issue. Future versions of this component may correct this issue by calling to a fault port on error. +Connections are still required from the telemetry and event output ports to the system-wide event log and telemetry +handling components as the hub is not designed to look like a telemetry nor event source. + ## Requirements | Name | Description | Validation | @@ -86,3 +99,4 @@ may correct this issue by calling to a fault port on error. |---|---| | 2020-12-21 | Initial Draft | | 2021-01-29 | Updated | +| 2023-06-09 | Added telemetry and event helpers | diff --git a/Svc/GenericHub/test/ut/TestMain.cpp b/Svc/GenericHub/test/ut/TestMain.cpp index 81c038b8b7..d2d66eec2f 100644 --- a/Svc/GenericHub/test/ut/TestMain.cpp +++ b/Svc/GenericHub/test/ut/TestMain.cpp @@ -20,6 +20,16 @@ TEST(Nominal, TestRandomIo) { tester.test_random_io(); } +TEST(Nominal, TestEvents) { + Svc::Tester tester; + tester.test_events(); +} + +TEST(Nominal, TestTelemetry) { + Svc::Tester tester; + tester.test_telemetry(); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/Svc/GenericHub/test/ut/Tester.cpp b/Svc/GenericHub/test/ut/Tester.cpp index cfbbdf06fd..17046dc5ae 100644 --- a/Svc/GenericHub/test/ut/Tester.cpp +++ b/Svc/GenericHub/test/ut/Tester.cpp @@ -52,7 +52,8 @@ void Tester ::test_in_out() { } void Tester ::test_buffer_io() { - U32 max = std::min(this->componentIn.getNum_buffersIn_InputPorts(), this->componentOut.getNum_buffersOut_OutputPorts()); + U32 max = + std::min(this->componentIn.getNum_buffersIn_InputPorts(), this->componentOut.getNum_buffersOut_OutputPorts()); for (U32 i = 0; i < max; i++) { send_random_buffer(i); ASSERT_from_dataInDeallocate_SIZE(1); @@ -64,24 +65,61 @@ void Tester ::test_random_io() { for (U32 i = 0; i < 10000; i++) { U32 choice = STest::Pick::lowerUpper(0, 1); if (choice) { - U32 port = STest::Pick::lowerUpper(0, std::min(this->componentIn.getNum_portIn_InputPorts(), this->componentOut.getNum_portOut_OutputPorts()) - 1); + U32 port = STest::Pick::lowerUpper(0, std::min(this->componentIn.getNum_portIn_InputPorts(), + this->componentOut.getNum_portOut_OutputPorts()) - + 1); send_random_comm(port); } else { - U32 port = STest::Pick::lowerUpper(0, std::min(this->componentIn.getNum_buffersIn_InputPorts(), this->componentOut.getNum_buffersOut_OutputPorts()) - 1); + U32 port = STest::Pick::lowerUpper(0, std::min(this->componentIn.getNum_buffersIn_InputPorts(), + this->componentOut.getNum_buffersOut_OutputPorts()) - + 1); send_random_buffer(port); } ASSERT_from_dataInDeallocate_SIZE(1); fromPortHistory_dataInDeallocate->clear(); } } -// Helpers -void Tester ::send_random_comm(U32 port) { - U32 random_size = STest::Pick::lowerUpper(0, FW_COM_BUFFER_MAX_SIZE); - m_comm.resetSer(); +void Tester ::random_fill(Fw::SerializeBufferBase& buffer, U32 max_size) { + U32 random_size = STest::Pick::lowerUpper(0, max_size); + buffer.resetSer(); for (U32 i = 0; i < random_size; i++) { - m_comm.serialize(static_cast(STest::Pick::any())); + buffer.serialize(static_cast(STest::Pick::any())); } +} + +void Tester ::test_telemetry() { + Fw::TlmBuffer buffer; + random_fill(buffer, FW_TLM_BUFFER_MAX_SIZE); + + Fw::Time time(100, 200); + invoke_to_TlmRecv(0, 123, time, buffer); + + // **must** deallocate buffer + ASSERT_from_dataInDeallocate_SIZE(1); + ASSERT_from_TlmSend_SIZE(1); + ASSERT_from_TlmSend(0, 123, time, buffer); + clearFromPortHistory(); +} + +void Tester ::test_events() { + Fw::LogSeverity severity = Fw::LogSeverity::WARNING_HI; + Fw::LogBuffer buffer; + random_fill(buffer, FW_LOG_BUFFER_MAX_SIZE); + + Fw::Time time(100, 200); + invoke_to_LogRecv(0, 123, time, severity, buffer); + + // **must** deallocate buffer + ASSERT_from_dataInDeallocate_SIZE(1); + ASSERT_from_LogSend_SIZE(1); + ASSERT_from_LogSend(0, 123, time, severity, buffer); + clearFromPortHistory(); +} +// Helpers + +void Tester ::send_random_comm(U32 port) { + random_fill(m_comm, FW_COM_BUFFER_MAX_SIZE); m_current_port = port; invoke_to_portIn(m_current_port, m_comm); // Ensure that the data out was called, and that the portOut unwrapped properly @@ -91,14 +129,11 @@ void Tester ::send_random_comm(U32 port) { } void Tester ::send_random_buffer(U32 port) { - - U32 random_size = STest::Pick::lowerUpper(0, DATA_SIZE - (sizeof(U32) + sizeof(U32) + sizeof(FwBuffSizeType))); - m_buffer.set(m_data_store, sizeof(m_data_store)) ; - ASSERT_GE(m_buffer.getSize(), random_size); - for (U32 i = 0; i < random_size; i++) { - reinterpret_cast(m_buffer.getData())[i] = static_cast(STest::Pick::any()); - } - m_buffer.setSize(random_size); + U32 max_random_size = STest::Pick::lowerUpper(0, DATA_SIZE - (sizeof(U32) + sizeof(U32) + sizeof(FwBuffSizeType))); + m_buffer.set(m_data_store, sizeof(m_data_store)); + ASSERT_GE(m_buffer.getSize(), max_random_size); + random_fill(m_buffer.getSerializeRepr(), max_random_size); + m_buffer.setSize(max_random_size); m_current_port = port; invoke_to_buffersIn(m_current_port, m_buffer); ASSERT_from_bufferDeallocate_SIZE(1); @@ -114,14 +149,29 @@ void Tester ::send_random_buffer(U32 port) { // Handlers for typed from ports // ---------------------------------------------------------------------- +void Tester ::from_LogSend_handler(const NATIVE_INT_TYPE portNum, + FwEventIdType id, + Fw::Time& timeTag, + const Fw::LogSeverity& severity, + Fw::LogBuffer& args) { + this->pushFromPortEntry_LogSend(id, timeTag, severity, args); +} + +void Tester ::from_TlmSend_handler(const NATIVE_INT_TYPE portNum, + FwChanIdType id, + Fw::Time& timeTag, + Fw::TlmBuffer& val) { + this->pushFromPortEntry_TlmSend(id, timeTag, val); +} + void Tester ::from_dataOut_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { ASSERT_NE(fwBuffer.getData(), nullptr) << "Empty buffer to deallocate"; ASSERT_GE(fwBuffer.getData(), m_data_for_allocation) << "Incorrect data pointer deallocated"; - ASSERT_LT(fwBuffer.getData(), m_data_for_allocation + sizeof(m_data_for_allocation)) << "Incorrect data pointer deallocated"; + ASSERT_LT(fwBuffer.getData(), m_data_for_allocation + sizeof(m_data_for_allocation)) + << "Incorrect data pointer deallocated"; // Reuse m_allocate to pass into the otherside of the hub this->pushFromPortEntry_dataOut(fwBuffer); invoke_to_dataIn(0, fwBuffer); - } // ---------------------------------------------------------------------- @@ -172,7 +222,8 @@ void Tester ::from_bufferDeallocate_handler(const NATIVE_INT_TYPE portNum, Fw::B void Tester ::from_dataInDeallocate_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { ASSERT_NE(fwBuffer.getData(), nullptr) << "Empty buffer to deallocate"; ASSERT_GE(fwBuffer.getData(), m_data_for_allocation) << "Incorrect data pointer deallocated"; - ASSERT_LT(fwBuffer.getData(), m_data_for_allocation + sizeof(m_data_for_allocation)) << "Incorrect data pointer deallocated"; + ASSERT_LT(fwBuffer.getData(), m_data_for_allocation + sizeof(m_data_for_allocation)) + << "Incorrect data pointer deallocated"; m_allocate.set(nullptr, 0); this->pushFromPortEntry_dataInDeallocate(fwBuffer); @@ -184,11 +235,18 @@ void Tester ::from_dataInDeallocate_handler(const NATIVE_INT_TYPE portNum, Fw::B void Tester ::connectPorts() { // buffersIn - U32 max = std::min(this->componentIn.getNum_buffersIn_InputPorts(), this->componentOut.getNum_buffersOut_OutputPorts()); + U32 max = + std::min(this->componentIn.getNum_buffersIn_InputPorts(), this->componentOut.getNum_buffersOut_OutputPorts()); for (U32 i = 0; i < max; ++i) { this->connect_to_buffersIn(i, this->componentIn.get_buffersIn_InputPort(i)); } + // LogRecv + this->connect_to_LogRecv(0, this->componentIn.get_LogRecv_InputPort(0)); + + // TlmRecv + this->connect_to_TlmRecv(0, this->componentIn.get_TlmRecv_InputPort(0)); + // dataIn this->connect_to_dataIn(0, this->componentOut.get_dataIn_InputPort(0)); @@ -197,6 +255,12 @@ void Tester ::connectPorts() { this->componentOut.set_buffersOut_OutputPort(i, this->get_from_buffersOut(i)); } + // LogSend + this->componentOut.set_LogSend_OutputPort(0, this->get_from_LogSend(0)); + + // TlmSend + this->componentOut.set_TlmSend_OutputPort(0, this->get_from_TlmSend(0)); + // dataOut this->componentIn.set_dataOut_OutputPort(0, this->get_from_dataOut(0)); diff --git a/Svc/GenericHub/test/ut/Tester.hpp b/Svc/GenericHub/test/ut/Tester.hpp index df1327be3a..4a99367c6f 100644 --- a/Svc/GenericHub/test/ut/Tester.hpp +++ b/Svc/GenericHub/test/ut/Tester.hpp @@ -52,11 +52,39 @@ class Tester : public GenericHubGTestBase { //! void test_random_io(); + //! Test of telemetry in-out + //! + void test_telemetry(); + + //! Test of event in-out + //! + void test_events(); + + + private: // ---------------------------------------------------------------------- // Handlers for typed from ports // ---------------------------------------------------------------------- + //! Handler for from_LogSend + //! + void from_LogSend_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwEventIdType id, /*!< Log ID */ + Fw::Time& timeTag, /*!< Time Tag */ + const Fw::LogSeverity& severity, /*!< The severity argument */ + Fw::LogBuffer& args /*!< Buffer containing serialized log entry */ + ); + + //! Handler for from_TlmSend + //! + void from_TlmSend_handler( + 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 */ + ); + //! Handler for from_buffersOut //! void from_buffersOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ @@ -98,6 +126,8 @@ class Tester : public GenericHubGTestBase { void send_random_buffer(U32 port); + void random_fill(Fw::SerializeBufferBase& buffer, U32 max_size); + // ---------------------------------------------------------------------- // Helper methods // ---------------------------------------------------------------------- diff --git a/Svc/PassiveRateGroup/CMakeLists.txt b/Svc/PassiveRateGroup/CMakeLists.txt new file mode 100644 index 0000000000..83d35a7a0c --- /dev/null +++ b/Svc/PassiveRateGroup/CMakeLists.txt @@ -0,0 +1,29 @@ +#### CMakeLists.txt PassiveRateGroup #### + +# Specifies the sources for this module with optional sources included by platform +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/PassiveRateGroup.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PassiveRateGroup.hpp" + "${CMAKE_CURRENT_LIST_DIR}/PassiveRateGroup.fpp" +) + + +# Specifies any module dependencies not detectable via the model file dependency detection +#set(MOD_DEPS ...) + +# Registers this module with the fprime build system +register_fprime_module() + +# Specifies the sources specifically associated with unit tests in this module +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/test/ut/PassiveRateGroupTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/PassiveRateGroupImplTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PassiveRateGroup.fpp" +) + + +# Specifies any unit test modules +#set(UT_MOD_DEPS ...) + +# Registers this module with the fprime build system +register_fprime_ut() diff --git a/Svc/PassiveRateGroup/PassiveRateGroup.cpp b/Svc/PassiveRateGroup/PassiveRateGroup.cpp new file mode 100644 index 0000000000..c04212ba98 --- /dev/null +++ b/Svc/PassiveRateGroup/PassiveRateGroup.cpp @@ -0,0 +1,67 @@ +/* + * \author: Tim Canham + * \file: + * \brief + * + * This file implements the PassiveRateGroup component, + * which invokes a set of components the comprise the rate group. + * + * Copyright 2014-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + */ + +#include +#include +#include +#include + +namespace Svc { +PassiveRateGroup::PassiveRateGroup(const char* compName) + : PassiveRateGroupComponentBase(compName), m_cycles(0), m_maxTime(0), m_numContexts(0) { +} + +PassiveRateGroup::~PassiveRateGroup() {} + +void PassiveRateGroup::configure(NATIVE_INT_TYPE contexts[], NATIVE_INT_TYPE numContexts) { + FW_ASSERT(contexts); + FW_ASSERT(numContexts == this->getNum_RateGroupMemberOut_OutputPorts(),numContexts,this->getNum_RateGroupMemberOut_OutputPorts()); + FW_ASSERT(FW_NUM_ARRAY_ELEMENTS(this->m_contexts) == this->getNum_RateGroupMemberOut_OutputPorts(), + FW_NUM_ARRAY_ELEMENTS(this->m_contexts), + this->getNum_RateGroupMemberOut_OutputPorts()); + + this->m_numContexts = numContexts; + // copy context values + for (NATIVE_INT_TYPE entry = 0; entry < this->m_numContexts; entry++) { + this->m_contexts[entry] = contexts[entry]; + } +} + + +void PassiveRateGroup::CycleIn_handler(NATIVE_INT_TYPE portNum, Svc::TimerVal& cycleStart) { + TimerVal end; + FW_ASSERT(this->m_numContexts); + + // invoke any members of the rate group + for (NATIVE_INT_TYPE port = 0; port < this->getNum_RateGroupMemberOut_OutputPorts(); port++) { + if (this->isConnected_RateGroupMemberOut_OutputPort(port)) { + this->RateGroupMemberOut_out(port, this->m_contexts[port]); + } + } + + // grab timer for end of cycle + end.take(); + + // get rate group execution time + U32 cycle_time = end.diffUSec(cycleStart); + + // check to see if the time has exceeded the previous maximum + if (cycle_time > this->m_maxTime) { + this->m_maxTime = cycle_time; + } + this->tlmWrite_MaxCycleTime(this->m_maxTime); + this->tlmWrite_CycleTime(cycle_time); + this->tlmWrite_CycleCount(++this->m_cycles); +} + +} // namespace Svc diff --git a/Svc/PassiveRateGroup/PassiveRateGroup.fpp b/Svc/PassiveRateGroup/PassiveRateGroup.fpp new file mode 100644 index 0000000000..8237423871 --- /dev/null +++ b/Svc/PassiveRateGroup/PassiveRateGroup.fpp @@ -0,0 +1,30 @@ +module Svc { + + @ A rate group passive component with input and output scheduler ports + passive component PassiveRateGroup { + + @ The rate group cycle input + sync input port CycleIn: Cycle + + @ Scheduler output port to rate group members + output port RateGroupMemberOut: [PassiveRateGroupOutputPorts] Sched + + @ Max execution time of rate group cycle + telemetry MaxCycleTime: U32 update on change format "{} us" + + @ Execution time of current cycle + telemetry CycleTime: U32 format "{} us" + + @ Count of number of cycles + telemetry CycleCount: U32 + + # Standard ports + @ A port for getting the time + time get port Time + + @ A port for emitting telemetry + telemetry port Tlm + + } + +} diff --git a/Svc/PassiveRateGroup/PassiveRateGroup.hpp b/Svc/PassiveRateGroup/PassiveRateGroup.hpp new file mode 100644 index 0000000000..5849fa5760 --- /dev/null +++ b/Svc/PassiveRateGroup/PassiveRateGroup.hpp @@ -0,0 +1,75 @@ +/* + * \author: Tim Canham + * \file: + * \brief + * + * This file implements the PassiveRateGroup component, + * which invokes a set of components the comprise the rate group. + * + * Copyright 2014-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + */ + +#ifndef SVC_PASSIVERATEGROUP_IMPL_HPP +#define SVC_PASSIVERATEGROUP_IMPL_HPP + +#include + +namespace Svc { + +//! \class PassiveRateGroupImpl +//! \brief Executes a set of components as part of a rate group +//! +//! PassiveRateGroup takes an input cycle call to begin the rate group cycle. +//! It calls each output port in succession and passes the value in the context +//! array at the index corresponding to the output port number. It keeps track of the execution +//! time of the rate group and detects overruns. +//! + +class PassiveRateGroup : public PassiveRateGroupComponentBase { + public: + //! \brief PassiveRateGroupImpl constructor + //! + //! The constructor of the class clears all the flags and copies the + //! contents of the context array to private storage. + //! + //! \param compName Name of the component + explicit PassiveRateGroup(const char* compName); //! \brief PassiveRateGroupImpl initialization function + + //! \brief PassiveRateGroup configuration function + //! + //! The configuration function takes an array of context values to pass to + //! members of the rate group. + //! + //! \param contexts Array of integers that contain the context values that will be sent + //! to each member component. The index of the array corresponds to the + //! output port number. + //! \param numContexts The number of elements in the context array. + void configure(NATIVE_INT_TYPE contexts[], NATIVE_INT_TYPE numContexts); + + //! \brief PassiveRateGroupImpl destructor + //! + //! The destructor of the class is empty + ~PassiveRateGroup(); + + PRIVATE: + //! \brief Input cycle port handler + //! + //! The cycle port handler calls each component in the rate group in turn, + //! passing the context value. It computes the execution time each cycle, + //! and writes it to a telemetry value if it reaches a maximum time + //! + //! \param portNum incoming port call. For this class, should always be zero + //! \param cycleStart value stored by the cycle driver, used to compute execution time. + void CycleIn_handler(NATIVE_INT_TYPE portNum, Svc::TimerVal& cycleStart); + + U32 m_cycles; //!< cycles executed + U32 m_maxTime; //!< maximum execution time in microseconds + NATIVE_INT_TYPE m_numContexts; //!< number of contexts + NATIVE_INT_TYPE m_contexts[NUM_RATEGROUPMEMBEROUT_OUTPUT_PORTS]; //!< Must match number of output ports +}; + +} // namespace Svc + +#endif diff --git a/Svc/PassiveRateGroup/docs/img/PassiveRateGroupBDD.png b/Svc/PassiveRateGroup/docs/img/PassiveRateGroupBDD.png new file mode 100644 index 0000000000..b5d58d9d62 Binary files /dev/null and b/Svc/PassiveRateGroup/docs/img/PassiveRateGroupBDD.png differ diff --git a/Svc/PassiveRateGroup/docs/sdd.md b/Svc/PassiveRateGroup/docs/sdd.md new file mode 100644 index 0000000000..d18dd6be08 --- /dev/null +++ b/Svc/PassiveRateGroup/docs/sdd.md @@ -0,0 +1,77 @@ +PassiveRateGroup Component SDD +# RateGroupDriver Component + +## 1. Introduction + +`Svc::PassiveRateGroup` is an passive component that drives a set of components connected to `Svc::Sched` output ports. It contains an synchronous input `Svc::Cycle` port that drives all the operations. The component invokes each output port in order, passing an argument specified in the supplied context list. It tracks execution time of the cycle. + +## 2. Requirements + +The requirements for `Svc::PassiveRateGroup` are as follows: + +Requirement | Description | Verification Method +----------- | ----------- | ------------------- +FPRIME-PRG-001 | The `Svc::PassiveRateGroup` component shall be passive and will be driven by an input synchronous port call | Inspection, Unit test +FPRIME-PRG-002 | The `Svc::PassiveRateGroup` component shall invoke its output ports in order, passing the value contained in a table based on port number | Unit Test +FPRIME-PRG-003 | The `Svc::PassiveRateGroup` component shall track the time required to execute the rate group and report it as telemetry | Unit Test + + +## 3. Design + +### 3.1 Context + +#### 3.1.1 Component Diagram + +The `Svc::PassiveRateGroup` component has the following component diagram: + +![PassiveRateGroup Diagram](img/PassiveRateGroupBDD.png "PassiveRateGroup") + +#### 3.1.2 Ports + +The `Svc::PassiveRateGroup` component uses the following port types: + +Port Data Type | Name | Direction | Kind | Usage +-------------- | ---- | --------- | ---- | ----- +Svc::Cycle | CycleIn | Input | synchronous | Receive a call to run one cycle of the rate group +[`Svc::Sched`](../../Sched/docs/sdd.md) | RateGroupMemberOut | Output | n/a | Rate group ports + +#### 3.2 Functional Description + +The `Svc::PassiveRateGroup` component has one input port that is used to drive all of the processing. The component calls the output ports in order, passing the context from the context list as the port argument. + +### 3.3 Scenarios + +#### 3.3.1 Rate Group Port Call + +As described in the Functional Description section, the `Svc::PassiveRateGroup` component accepts calls to the CycleIn and invokes the RateGroupMemberOut ports: + +**Sequence Diagram** +```mermaid +sequenceDiagram + participant RateGroupDriver + participant PassiveRateGroup + participant Callee + RateGroupDriver ->> PassiveRateGroup: CycleIn + loop for each callee + PassiveRateGroup ->> Callee: RateGroupMemberOut[N] + Callee -->> PassiveRateGroup: + end + PassiveRateGroup -->> RateGroupDriver: +``` + +### 3.4 State + +`Svc::PassiveRateGroup` has no state machines. + +### 3.5 Algorithms + +`Svc::PassiveRateGroup` has no significant algorithms. + +## 4. Change Log + +Date | Description +---- | ----------- +2/9/2017 | First Draft + + + diff --git a/Svc/PassiveRateGroup/test/ut/PassiveRateGroupImplTester.cpp b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupImplTester.cpp new file mode 100644 index 0000000000..8664970227 --- /dev/null +++ b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupImplTester.cpp @@ -0,0 +1,84 @@ +/* + * \author Tim Canham + * \file + * \brief + * + * This file is the test component for the active rate group unit test. + * + * Code Generated Source Code Header + * + * Copyright 2014-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + */ + +#include +#include +#include + +#include +#include + +namespace Svc { + +void PassiveRateGroupTester::init(NATIVE_INT_TYPE instance) { + PassiveRateGroupGTestBase::init(); +} + +PassiveRateGroupTester::PassiveRateGroupTester(Svc::PassiveRateGroup& inst) + : PassiveRateGroupGTestBase("testerbase", 100), m_impl(inst), m_callOrder(0) { + this->clearPortCalls(); +} + +void PassiveRateGroupTester::clearPortCalls() { + memset(this->m_callLog, 0, sizeof(this->m_callLog)); + this->m_callOrder = 0; +} + +PassiveRateGroupTester::~PassiveRateGroupTester() {} + +void PassiveRateGroupTester::from_RateGroupMemberOut_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) { + ASSERT_TRUE(portNum < static_cast(FW_NUM_ARRAY_ELEMENTS(m_impl.m_RateGroupMemberOut_OutputPort))); + this->m_callLog[portNum].portCalled = true; + this->m_callLog[portNum].contextVal = context; + this->m_callLog[portNum].order = this->m_callOrder++; +} + +void PassiveRateGroupTester::runNominal(NATIVE_INT_TYPE contexts[], + NATIVE_UINT_TYPE numContexts, + NATIVE_INT_TYPE instance) { + TEST_CASE(101.1.1, "Run nominal rate group execution"); + + // clear events + this->clearTlm(); + + Svc::TimerVal timer; + timer.take(); + + // clear port call log + this->clearPortCalls(); + + REQUIREMENT("FPRIME-PRG-001"); + // call active rate group with timer val + this->invoke_to_CycleIn(0, timer); + + + // check calls + REQUIREMENT("FPRIME-PRG-002"); + for (NATIVE_UINT_TYPE portNum = 0; + portNum < static_cast(FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_RateGroupMemberOut_OutputPort)); portNum++) { + ASSERT_TRUE(this->m_callLog[portNum].portCalled); + ASSERT_EQ(this->m_callLog[portNum].contextVal, contexts[portNum]); + ASSERT_EQ(this->m_callLog[portNum].order, portNum); + } + // Cycle times should be non-zero + REQUIREMENT("FPRIME-PRG-003"); + ASSERT_TLM_MaxCycleTime_SIZE(1); + ASSERT_TLM_CycleTime_SIZE(1); + ASSERT_TLM_CycleCount_SIZE(1); + ASSERT_GT(this->tlmHistory_MaxCycleTime->at(0).arg, 0); + ASSERT_GT(this->tlmHistory_CycleTime->at(0).arg, 0); + ASSERT_GT(this->tlmHistory_CycleCount->at(0).arg, 0); +} + +} // namespace Svc diff --git a/Svc/PassiveRateGroup/test/ut/PassiveRateGroupImplTester.hpp b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupImplTester.hpp new file mode 100644 index 0000000000..f1ae74f64b --- /dev/null +++ b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupImplTester.hpp @@ -0,0 +1,53 @@ +/* +* \author Tim Canham +* \file +* \brief +* +* This file is the test component header for the active rate group unit test. +* +* Code Generated Source Code Header +* +* Copyright 2014-2015, by the California Institute of Technology. +* ALL RIGHTS RESERVED. United States Government Sponsorship +* acknowledged. +*/ + +#ifndef PASSIVERATEGROUP_TEST_UT_PASSIVERATEGROUPIMPLTESTER_HPP_ +#define PASSIVERATEGROUP_TEST_UT_PASSIVERATEGROUPIMPLTESTER_HPP_ + +#include +#include + +namespace Svc { + + class PassiveRateGroupTester: public PassiveRateGroupGTestBase { + public: + PassiveRateGroupTester(Svc::PassiveRateGroup& inst); + virtual ~PassiveRateGroupTester(); + + void init(NATIVE_INT_TYPE instance = 0); + + void runNominal(NATIVE_UINT_TYPE contexts[], NATIVE_UINT_TYPE numContexts, NATIVE_INT_TYPE instance); + + private: + + void from_RateGroupMemberOut_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context); + + Svc::PassiveRateGroup& m_impl; + + void clearPortCalls(); + + struct { + bool portCalled; + NATIVE_UINT_TYPE contextVal; + NATIVE_UINT_TYPE order; + } m_callLog[Svc::PassiveRateGroupComponentBase::NUM_RATEGROUPMEMBEROUT_OUTPUT_PORTS]; + + bool m_causeOverrun; //!< flag to cause an overrun during a rate group member port call + NATIVE_UINT_TYPE m_callOrder; //!< tracks order of port call. + + }; + +} /* namespace Svc */ + +#endif /* PASSIVERATEGROUP_TEST_UT_PASSIVERATEGROUPIMPLTESTER_HPP_ */ diff --git a/Svc/PassiveRateGroup/test/ut/PassiveRateGroupTester.cpp b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupTester.cpp new file mode 100644 index 0000000000..f7a2268c62 --- /dev/null +++ b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupTester.cpp @@ -0,0 +1,55 @@ +/* + * \author Tim Canham + * \file + * \brief + * + * This file is the test driver for the active rate group unit test. + * + * Code Generated Source Code Header + * + * Copyright 2014-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + */ +#include + +#include +#include +#include + +#include + +void connectPorts(Svc::PassiveRateGroup& impl, Svc::PassiveRateGroupTester& tester) { + tester.connect_to_CycleIn(0, impl.get_CycleIn_InputPort(0)); + + for (NATIVE_INT_TYPE portNum = 0; + portNum < static_cast(FW_NUM_ARRAY_ELEMENTS(impl.m_RateGroupMemberOut_OutputPort)); portNum++) { + impl.set_RateGroupMemberOut_OutputPort(portNum, tester.get_from_RateGroupMemberOut(portNum)); + } + + impl.set_Tlm_OutputPort(0, tester.get_from_Tlm(0)); + impl.set_Time_OutputPort(0, tester.get_from_Time(0)); +} + +TEST(PassiveRateGroupTest, NominalSchedule) { + for (NATIVE_INT_TYPE inst = 0; inst < 3; inst++) { + NATIVE_INT_TYPE contexts[FppConstant_PassiveRateGroupOutputPorts::PassiveRateGroupOutputPorts] = {1, 2, 3, 4, 5}; + + Svc::PassiveRateGroup impl("PassiveRateGroup"); + impl.configure(contexts, FW_NUM_ARRAY_ELEMENTS(contexts)); + Svc::PassiveRateGroupTester tester(impl); + + tester.init(); + impl.init(inst); + + // connect ports + connectPorts(impl, tester); + + tester.runNominal(contexts, FW_NUM_ARRAY_ELEMENTS(contexts), inst); + } +} + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Svc/PassiveRateGroup/test/ut/PassiveRateGroupTester.hpp b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupTester.hpp new file mode 100644 index 0000000000..9502e26980 --- /dev/null +++ b/Svc/PassiveRateGroup/test/ut/PassiveRateGroupTester.hpp @@ -0,0 +1,52 @@ +/* +* \author Tim Canham +* \file +* \brief +* +* This file is the test component header for the active rate group unit test. +* +* Code Generated Source Code Header +* +* Copyright 2014-2015, by the California Institute of Technology. +* ALL RIGHTS RESERVED. United States Government Sponsorship +* acknowledged. +*/ + +#ifndef PASSIVERATEGROUP_TEST_UT_PASSIVERATEGROUPIMPLTESTER_HPP_ +#define PASSIVERATEGROUP_TEST_UT_PASSIVERATEGROUPIMPLTESTER_HPP_ + +#include +#include + +namespace Svc { + + class PassiveRateGroupTester: public PassiveRateGroupGTestBase { + public: + PassiveRateGroupTester(Svc::PassiveRateGroup& inst); + virtual ~PassiveRateGroupTester(); + + void init(NATIVE_INT_TYPE instance = 0); + + void runNominal(NATIVE_INT_TYPE contexts[], NATIVE_UINT_TYPE numContexts, NATIVE_INT_TYPE instance); + + private: + + void from_RateGroupMemberOut_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context); + + Svc::PassiveRateGroup& m_impl; + + void clearPortCalls(); + + struct { + bool portCalled; + NATIVE_UINT_TYPE contextVal; + NATIVE_UINT_TYPE order; + } m_callLog[Svc::PassiveRateGroupComponentBase::NUM_RATEGROUPMEMBEROUT_OUTPUT_PORTS]; + + NATIVE_UINT_TYPE m_callOrder; //!< tracks order of port call. + + }; + +} /* namespace Svc */ + +#endif /* PASSIVERATEGROUP_TEST_UT_PASSIVERATEGROUPIMPLTESTER_HPP_ */ diff --git a/Svc/TlmChan/test/ut/Tester.hpp b/Svc/TlmChan/test/ut/Tester.hpp index 6b61ec2ce7..7370ed4b23 100644 --- a/Svc/TlmChan/test/ut/Tester.hpp +++ b/Svc/TlmChan/test/ut/Tester.hpp @@ -42,21 +42,15 @@ class Tester : public TlmChanGTestBase { //! Handler for from_PktSend //! - void from_PktSend_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::ComBuffer& data, /*!< - Buffer containing packet data - */ - U32 context /*!< - Call context value; meaning chosen by user - */ + void from_PktSend_handler(const NATIVE_INT_TYPE portNum, //!< The port number + Fw::ComBuffer& data, //!< Buffer containing packet data + U32 context //!< Call context value; meaning chosen by user ); //! Handler for from_pingOut //! - void from_pingOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 key /*!< - Value to return to pinger - */ + void from_pingOut_handler(const NATIVE_INT_TYPE portNum, //!< The port number + U32 key //!< Value to return to pinger ); private: diff --git a/ci/tests/fputil.bash b/ci/tests/fputil.bash index 58afee3a4c..4e2ec64dff 100755 --- a/ci/tests/fputil.bash +++ b/ci/tests/fputil.bash @@ -69,7 +69,7 @@ function integration_test_run { mkdir -p "${LOG_DIR}/gds-logs" # Start the GDS layer and give it time to run echo "[INFO] Starting headless GDS layer" - fprime-gds -n --dictionary "${ROOTDIR}/"*"/dict/${BINARY}TopologyAppDictionary.xml" -g none -l "${LOG_DIR}/gds-logs" 1>${LOG_DIR}/gds-logs/fprime-gds.stdout.log 2>${LOG_DIR}/gds-logs/fprime-gds.stderr.log & + fprime-gds -n --dictionary "${ROOTDIR}/"*"/${BINARY}/dict/${BINARY}TopologyAppDictionary.xml" -g none -l "${LOG_DIR}/gds-logs" 1>${LOG_DIR}/gds-logs/fprime-gds.stdout.log 2>${LOG_DIR}/gds-logs/fprime-gds.stderr.log & GDS_PID=$! # run the app with valgrind in the background if command -v valgrind &> /dev/null @@ -82,9 +82,9 @@ function integration_test_run { --show-leak-kinds=all \ --track-origins=yes \ --log-file=${LOG_DIR}/gds-logs/valgrind.log \ - ${ROOTDIR}/*/bin/${BINARY} -a 127.0.0.1 -p 50000 1>${LOG_DIR}/gds-logs/${BINARY}.stdout.log 2>${LOG_DIR}/gds-logs/${BINARY}.stderr.log & + ${ROOTDIR}/*/${BINARY}/bin/${BINARY} -a 127.0.0.1 -p 50000 1>${LOG_DIR}/gds-logs/${BINARY}.stdout.log 2>${LOG_DIR}/gds-logs/${BINARY}.stderr.log & else - ${ROOTDIR}/*/bin/${BINARY} -a 127.0.0.1 -p 50000 1>${LOG_DIR}/gds-logs/${BINARY}.stdout.log 2>${LOG_DIR}/gds-logs/${BINARY}.stderr.log & + ${ROOTDIR}/*/${BINARY}/bin/${BINARY} -a 127.0.0.1 -p 50000 1>${LOG_DIR}/gds-logs/${BINARY}.stdout.log 2>${LOG_DIR}/gds-logs/${BINARY}.stderr.log & fi VALGRIND_PID=$! @@ -95,7 +95,7 @@ function integration_test_run { ps -p ${VALGRIND_PID} 2> /dev/null 1> /dev/null || fail_and_stop "Failed to start ${BINARY} with Valgrind" # Run integration tests ( - cd "${WORKDIR}/test" + cd "${WORKDIR}" if [[ "${DICTIONARY_PATH}" != "" ]] then DICTIONARY_ARGS="--dictionary ${WORKDIR}/${DICTIONARY_PATH}" diff --git a/cmake/API.cmake b/cmake/API.cmake index 9bf7a33d25..2e0a9dccaa 100644 --- a/cmake/API.cmake +++ b/cmake/API.cmake @@ -29,11 +29,39 @@ set(FPRIME_AUTOCODER_TARGET_LIST "" CACHE INTERNAL "FPRIME_AUTOCODER_TARGET_LIST ##### macro(restrict_platforms) set(__CHECKER ${ARGN}) - if (NOT CMAKE_SYSTEM_NAME IN_LIST __CHECKER) - get_module_name("${CMAKE_CURRENT_LIST_DIR}") - message(STATUS "Platform ${CMAKE_SYSTEM_NAME} not supported for module ${MODULE_NAME}") - return() - endif() + if (NOT CMAKE_SYSTEM_NAME IN_LIST __CHECKER) + get_module_name("${CMAKE_CURRENT_LIST_DIR}") + message(STATUS "Platform ${CMAKE_SYSTEM_NAME} not supported for module ${MODULE_NAME}") + return() + endif() +endmacro() + +#### +# Macro `prevent_prescan`: +# +# Prevents a CMakeLists.txt file from being processed in the prescan phase of the project. Will generate fake targets +# for all those targets specified to ensure that dependencies may be attached to these targets in the larger system. +# +# Usage: +# prevent_prescan(target1 target2 ...) # Generate fake targets and skip prescan +# +# Args: +# ARGN: list of targets to synthesize +##### +macro(prevent_prescan) + set(__CHECKER_TARGETS ${ARGN}) + if (DEFINED FPRIME_PRESCAN) + foreach (__TARGET IN LISTS __CHECKER_TARGETS) + # Make prevent prescan safe in the case of multiple calls + if (NOT TARGET ${__TARGET}) + add_custom_target(${__TARGET}) + endif() + endforeach() + string(REPLACE ";" " " __SPACE_LIST_TARGETS "${__CHECKER_TARGETS}") + get_module_name("${CMAKE_CURRENT_LIST_DIR}") + message(STATUS "Skipping ${MODULE_NAME} during prescan, adding faux libraries: ${__SPACE_LIST_TARGETS}") + return() + endif() endmacro() #### @@ -64,6 +92,9 @@ endmacro() # https://cmake.org/cmake/help/latest/command/add_fprime_subdirectory.html #### function(add_fprime_subdirectory FP_SOURCE_DIR) + get_module_name("${FP_SOURCE_DIR}") + set(FPRIME_CURRENT_MODULE "${MODULE_NAME}") + # Check if the binary and source directory are in agreement. If they agree, then normally add # the directory, as no adjustments need be made. get_filename_component(CBD_NAME "${CMAKE_CURRENT_BINARY_DIR}" NAME) @@ -90,13 +121,13 @@ endfunction(add_fprime_subdirectory) # # Required variables (defined in calling scope): # -# - **SOURCE_FILES:** cmake list of input source files. Place any "*.fpp", "*Ai.xml", "*.c", "*.cpp" +# - **SOURCE_FILES:** cmake list of input source files. Place any "*.fpp", "*.c", "*.cpp" # etc files here. This list will be split into autocoder inputs, and hand-coded sources based on the name/type. # # **i.e.:** # ``` # set(SOURCE_FILES -# MyComponentAi.xml +# MyComponent.fpp # SomeFile.cpp # MyComponentImpl.cpp) # ``` @@ -123,7 +154,7 @@ endfunction(add_fprime_subdirectory) # # ``` # set(SOURCE_FILE -# MyComponentAi.xml +# MyComponent.fpp # SomeFile.cpp # MyComponentImpl.cpp) # @@ -146,7 +177,7 @@ endfunction(add_fprime_subdirectory) # # ``` # set(SOURCE_FILE -# MyComponentAi.xml) +# MyComponent.fpp) # # register_fprime_module() # ``` @@ -159,7 +190,7 @@ endfunction(add_fprime_subdirectory) # # ``` # set(SOURCE_FILE -# MyComponentAi.xml +# MyComponent.fpp # SomeFile.cpp # MyComponentImpl.cpp) # @@ -179,7 +210,12 @@ function(register_fprime_module) if (${ARGC} GREATER 0) set(MODULE_NAME ${ARGV0}) else() - get_module_name("${CMAKE_CURRENT_LIST_DIR}") + # Check to be sure before using + if (NOT DEFINED FPRIME_CURRENT_MODULE) + message(FATAL_ERROR "FPRIME_CURRENT_MODULE not defined. Please supply name to: register_fprime_module()") + endif() + + set(MODULE_NAME ${FPRIME_CURRENT_MODULE}) endif() # Explicit call to module register generate_library("${MODULE_NAME}" "${SOURCE_FILES}" "${MOD_DEPS}") @@ -202,14 +238,14 @@ endfunction(register_fprime_module) # # # - **EXECUTABLE_NAME:** (optional) executable name supplied. If not set, nor passed in, then -# PROJECT_NAME from the CMake definitions is used. +# FPRIME_CURRENT_MODULE from the CMake definitions is used. # -# - **SOURCE_FILES:** cmake list of input source files. Place any "*Ai.xml", "*.c", "*.cpp" +# - **SOURCE_FILES:** cmake list of input source files. Place any "*.fpp", "*.c", "*.cpp" # etc. files here. This list will be split into autocoder inputs and sources. # **i.e.:** # ``` # set(SOURCE_FILES -# MyComponentAi.xml +# MyComponent.fpp # SomeFile.cpp # MyComponentImpl.cpp) # ``` @@ -250,17 +286,20 @@ endfunction(register_fprime_module) # ``` #### function(register_fprime_executable) - get_module_name("${CMAKE_CURRENT_LIST_DIR}") if (NOT DEFINED SOURCE_FILES AND NOT DEFINED MOD_DEPS) message(FATAL_ERROR "SOURCE_FILES or MOD_DEPS must be defined when registering an executable") - elseif (NOT DEFINED EXECUTABLE_NAME AND ARGC LESS 1 AND TARGET "${MODULE_NAME}") + elseif (NOT DEFINED EXECUTABLE_NAME AND ARGC LESS 1 AND TARGET "${FPRIME_CURRENT_MODULE}") message(FATAL_ERROR "EXECUTABLE_NAME must be set or passed in. Use register_fprime_deployment() for deployments") endif() # MODULE_NAME is used for the executable name, unless otherwise specified. if(NOT DEFINED EXECUTABLE_NAME AND ARGC GREATER 0) set(EXECUTABLE_NAME "${ARGV0}") elseif(NOT DEFINED EXECUTABLE_NAME) - set(EXECUTABLE_NAME "${MODULE_NAME}") + # Check to be sure before using + if (NOT DEFINED FPRIME_CURRENT_MODULE) + message(FATAL_ERROR "FPRIME_CURRENT_MODULE not defined. Please supply name to: register_fprime_executable()") + endif() + set(EXECUTABLE_NAME "${FPRIME_CURRENT_MODULE}") endif() get_nearest_build_root(${CMAKE_CURRENT_LIST_DIR}) generate_executable("${EXECUTABLE_NAME}" "${SOURCE_FILES}" "${MOD_DEPS}") @@ -282,12 +321,12 @@ endfunction(register_fprime_executable) # # Required variables (defined in calling scope): # -# - **SOURCE_FILES:** cmake list of input source files. Place any "*Ai.xml", "*.c", "*.cpp" +# - **SOURCE_FILES:** cmake list of input source files. Place any "*.fpp", "*.c", "*.cpp" # etc. files here. This list will be split into autocoder inputs and sources. # **i.e.:** # ``` # set(SOURCE_FILES -# MyComponentAi.xml +# MyComponent.fpp # SomeFile.cpp # MyComponentImpl.cpp) # ``` @@ -299,7 +338,7 @@ endfunction(register_fprime_executable) # **i.e.:** # ``` # set(MOD_DEPS -# ${PROJECT_NAME}/Top +# ${FPRIME_CURRENT_MODULE}/Top # Module1 # Module2 # -lpthread) @@ -307,36 +346,34 @@ endfunction(register_fprime_executable) # # **Note:** this operates almost identically to `register_fprime_executable` and `register_fprime_module` with respect # to the variable definitions. The difference is deployment targets will be run (e.g. dictionary generation), and the -# executable binary will be named for ${PROJECT_NAME}. +# executable binary will be named after the module, or if project when defined directly in a project CMakeLists.txt # # ### Standard fprime Deployment Example ### # -# To create a standard fprime deployment, an executable needs to be created. This executable -# uses the CMake PROJECT_NAME as the executable name. Thus, it can be created with the following -# source lists. In most fprime deployments, some modules must be specified as they don't tie -# directly to an Ai.xml. +# To create a standard fprime deployment, an the user must call `register_fprime_deployment()` after defining +# SOURCE_FILES and MOD_DEPS. # # ``` # set(SOURCE_FILES # "${CMAKE_CURRENT_LIST_DIR}/Main.cpp" # ) -# # Note: supply non-explicit dependencies here. These are implementations to an XML that is -# # defined in a different module. +# # Note: supply dependencies that cannot be detected via the model here. # set(MOD_DEPS -# ${PROJECT_NAME}/Top +# ${FPRIME_CURRENT_MODULE}/Top # ) # register_fprime_deployment() # ``` #### function(register_fprime_deployment) - get_module_name("${CMAKE_CURRENT_LIST_DIR}") if (NOT DEFINED SOURCE_FILES AND NOT DEFINED MOD_DEPS) message(FATAL_ERROR "SOURCE_FILES or MOD_DEPS must be defined when registering an executable") - elseif(NOT MODULE_NAME STREQUAL PROJECT_NAME) - message(WARNING "Project name ${PROJECT_NAME} does not match expected name ${MODULE_NAME}") + endif() + # Fallback to PROJECT_NAME when it is not set + if (NOT DEFINED FPRIME_CURRENT_MODULE) + set(FPRIME_CURRENT_MODULE "${PROJECT_NAME}") endif() get_nearest_build_root(${CMAKE_CURRENT_LIST_DIR}) - generate_deployment("${PROJECT_NAME}" "${SOURCE_FILES}" "${MOD_DEPS}") + generate_deployment("${FPRIME_CURRENT_MODULE}" "${SOURCE_FILES}" "${MOD_DEPS}") endfunction(register_fprime_deployment) @@ -357,14 +394,14 @@ endfunction(register_fprime_deployment) # - **UT_NAME:** (optional) executable name supplied. If not supplied, or passed in, then # the _ut_exe will be used. # -# - **UT_SOURCE_FILES:** cmake list of UT source files. Place any "*Ai.xml", "*.c", "*.cpp" +# - **UT_SOURCE_FILES:** cmake list of UT source files. Place any "*.fpp", "*.c", "*.cpp" # etc. files here. This list will be split into autocoder inputs or sources. These sources only apply to the unit # test. # # **i.e.:** # ``` # set(UT_SOURCE_FILES -# MyComponentAi.xml +# MyComponent.fpp # SomeFile.cpp # MyComponentImpl.cpp) # ``` @@ -390,13 +427,12 @@ endfunction(register_fprime_deployment) # # ### Unit-Test Example ### # -# A standard unit test defines only UT_SOURCES. These sources have the test cpp files and the module -# Ai.xml of the module being tested. This is used to generate the GTest and TesterBase files from this -# Ai.xml. The other UT source files define the implementation of the test. +# A standard unit test defines only UT_SOURCES. These sources have the test cpp files and the model +# .fpp of the module being tested. This is used to generate the GTest harness. # # ``` # set(UT_SOURCE_FILES -# "${FPRIME_FRAMEWORK_PATH}/Svc/CmdDispatcher/CommandDispatcherComponentAi.xml" +# "${FPRIME_FRAMEWORK_PATH}/Svc/CmdDispatcher/CommandDispatcher.fpp" # "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherTester.cpp" # "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherImplTester.cpp" # ) diff --git a/cmake/FPrime-Code.cmake b/cmake/FPrime-Code.cmake index 39dee7a408..1a4708afb6 100644 --- a/cmake/FPrime-Code.cmake +++ b/cmake/FPrime-Code.cmake @@ -26,13 +26,14 @@ if (FPRIME_ENABLE_FRAMEWORK_UTS) endif() # Faux libraries used as interfaces to non-autocoded fpp items add_library(Fpp INTERFACE) +set(FPRIME_CURRENT_MODULE config) add_subdirectory("${FPRIME_CONFIG_DIR}" "${CMAKE_BINARY_DIR}/config") -add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Fw/" "${CMAKE_BINARY_DIR}/F-Prime/Fw") -add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Svc/" "${CMAKE_BINARY_DIR}/F-Prime/Svc") -add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Os/" "${CMAKE_BINARY_DIR}/F-Prime/Os") -add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Drv/" "${CMAKE_BINARY_DIR}/F-Prime/Drv") -add_subdirectory("${FPRIME_FRAMEWORK_PATH}/CFDP/" "${CMAKE_BINARY_DIR}/F-Prime/CFDP") -add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Utils/" "${CMAKE_BINARY_DIR}/F-Prime/Utils") +set(_FP_CORE_PACKAGES Fw Svc Os Drv CFDP Utils) +foreach (_FP_PACKAGE_DIR IN LISTS _FP_CORE_PACKAGES) + set(FPRIME_CURRENT_MODULE "${_FP_PACKAGE_DIR}") + add_subdirectory("${FPRIME_FRAMEWORK_PATH}/${_FP_PACKAGE_DIR}/" "${CMAKE_BINARY_DIR}/F-Prime/${_FP_PACKAGE_DIR}") +endforeach () +unset(FPRIME_CURRENT_MODULE) # Always enable UTs for a project set(__FPRIME_NO_UT_GEN__ OFF) foreach (LIBRARY_DIR IN LISTS FPRIME_LIBRARY_LOCATIONS) diff --git a/cmake/FPrime.cmake b/cmake/FPrime.cmake index f30dd16a38..78d1716cfa 100644 --- a/cmake/FPrime.cmake +++ b/cmake/FPrime.cmake @@ -69,7 +69,6 @@ register_fprime_target(target/fpp_locs) register_fprime_target(target/build) register_fprime_build_autocoder(autocoder/fpp) register_fprime_build_autocoder(autocoder/ai_xml) -register_fprime_build_autocoder(autocoder/deployment_validation) register_fprime_build_autocoder(autocoder/packets) register_fprime_target(target/noop) register_fprime_target(target/version) diff --git a/cmake/autocoder/ai-parser/ai_parser.py b/cmake/autocoder/ai-parser/ai_parser.py index badfbdd50b..fe8c89e751 100755 --- a/cmake/autocoder/ai-parser/ai_parser.py +++ b/cmake/autocoder/ai-parser/ai_parser.py @@ -141,7 +141,7 @@ def print_fprime_dependencies(root, current_library, import_base): gcc_order.append(dep) # Find module dependencies, and anything else left over goes last for dep in dependencies: - if not dep in gcc_order: + if dep not in gcc_order: gcc_order.append(dep) # Write out CMake style list sys.stdout.write(";".join(gcc_order)) diff --git a/cmake/autocoder/ai_xml.cmake b/cmake/autocoder/ai_xml.cmake index 7a8013ccdf..e278e231f6 100644 --- a/cmake/autocoder/ai_xml.cmake +++ b/cmake/autocoder/ai_xml.cmake @@ -94,8 +94,9 @@ function(ai_xml_setup_autocode AC_INPUT_FILE) # Check type and respond if(XML_LOWER_TYPE STREQUAL "topologyapp") # Are we excluding the generated files or not - set_property(GLOBAL PROPERTY "${PROJECT_NAME}_FPRIME_DICTIONARY_FILE" - "${CMAKE_CURRENT_BINARY_DIR}/${OBJ_NAME}${XML_TYPE}Dictionary.xml") + set(FPRIME_CURRENT_DICTIONARY_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OBJ_NAME}${XML_TYPE}Dictionary.xml" + CACHE INTERNAL "" FORCE + ) if (EXCLUDE_TOP_ACS) set(REMOVALS "${GENERATED_FILES}") set(GENERATED_FILES "${CMAKE_CURRENT_BINARY_DIR}/${OBJ_NAME}${XML_TYPE}Dictionary.xml") @@ -107,7 +108,7 @@ function(ai_xml_setup_autocode AC_INPUT_FILE) OUTPUT ${GENERATED_FILES} COMMAND ${AI_BASE_SCRIPT} --connect_only --xml_topology_dict "${AC_INPUT_FILE}" COMMAND ${CMAKE_COMMAND} -E remove ${REMOVALS} - DEPENDS "${AC_INPUT_FILE}" "${MODULE_DEPENDENCIES}" "${AC_INPUT_FILE}" "${FILE_DEPENDENCIES}" + DEPENDS "${AC_INPUT_FILE}" "${MODULE_DEPENDENCIES}" "${FILE_DEPENDENCIES}" "${CODEGEN_TARGET}" ) else() add_custom_command( diff --git a/cmake/autocoder/deployment_validation.cmake b/cmake/autocoder/deployment_validation.cmake deleted file mode 100644 index 47c20ebbc8..0000000000 --- a/cmake/autocoder/deployment_validation.cmake +++ /dev/null @@ -1,47 +0,0 @@ -#### -# autocoder/deployment_validation.cmake -# -# An autocoder that performs validation steps on the deployment to ensure that it is well-formed. This will produce -# warning output when validation fails. -# -# Note: this autocoder is for validation purposes and DOES NOT produce any autocoded files. -##### -include(utilities) -include(autocoder/helpers) - -autocoder_setup_for_multiple_sources() - -#### -# `deployment_validation_is_supported`: -# -# Required function, processes .fpp files -#### -function(deployment_validation_is_supported AC_INPUT_FILE) - autocoder_support_by_suffix(".fpp" "${AC_INPUT_FILE}") # No re-scan, already done in FPP -endfunction (deployment_validation_is_supported) - -#### -# `deployment_validation_is_supported`: -# -# Required function, look for .fpp files defining a topology block and ensure the following equivalence: -# ${PROJECT_NAME} == topology name -# No files are produced by this autocoder. It runs to validate items as part of the autocoder system. -# -#### -function(deployment_validation_setup_autocode AC_INPUT_FILES) - foreach(AC_FILE IN LISTS AC_INPUT_FILES) - file(READ "${AC_FILE}" FILE_TEXT) - # Does this file match the pattern (module { topology {} }) - if (NOT FPRIME_SKIP_PROJECT_NAME_VALIDATION AND - FILE_TEXT MATCHES "^(.*\n)?[^\n#@]*topology +([a-zA-Z0-9_]+)" AND - NOT CMAKE_MATCH_2 STREQUAL "${PROJECT_NAME}") - message(WARNING - "Cmake project name '${PROJECT_NAME}' does not match topology name '${CMAKE_MATCH_2}'\n" - " Project CMakeLists.txt: ${PROJECT_SOURCE_DIR}/CMakeLists.txt\n" - " Topology FPP model: ${AC_FILE}\n" - ) - endif() - endforeach() - # This autocoder specifically does not produce any autocoder output - set(AUTOCODER_GENERATED "" PARENT_SCOPE) -endfunction(deployment_validation_setup_autocode) diff --git a/cmake/autocoder/fpp-locs-differ/fpp-locs-differ.py b/cmake/autocoder/fpp-locs-differ/fpp-locs-differ.py index 64984c4fb7..1a6569ec8f 100644 --- a/cmake/autocoder/fpp-locs-differ/fpp-locs-differ.py +++ b/cmake/autocoder/fpp-locs-differ/fpp-locs-differ.py @@ -3,7 +3,7 @@ import os import sys -from fprime_ac.utils.buildroot import build_root_relative_path, set_build_roots +from fprime_ac.utils.buildroot import set_build_roots def main(): @@ -23,7 +23,7 @@ def main(): sys.exit(1) # Previous files not generated if not os.path.exists(args_ns.prev_locs): - print(f"No pervious locations") + print("No pervious locations") sys.exit(1) with open(args_ns.prev_locs, "r") as prev_locs_fh: diff --git a/cmake/settings/ini-to-stdio.py b/cmake/settings/ini-to-stdio.py index 226b99e77d..ae8e2fb077 100644 --- a/cmake/settings/ini-to-stdio.py +++ b/cmake/settings/ini-to-stdio.py @@ -75,7 +75,7 @@ def main(): assert ( setting_value == ut_setting_value - ), f"CMake can only parse unittest independent settings" + ), "CMake can only parse unittest independent settings" output = loaded_settings[setting] handler(output) except KeyError as key_error: diff --git a/cmake/target/build.cmake b/cmake/target/build.cmake index 2430a2b577..ecd5fa5a2f 100644 --- a/cmake/target/build.cmake +++ b/cmake/target/build.cmake @@ -91,6 +91,11 @@ function(build_setup_build_module MODULE SOURCES GENERATED EXCLUDED_SOURCES DEPE endif() endforeach() set_property(TARGET "${MODULE}" PROPERTY FPRIME_TARGET_DEPENDENCIES ${TARGET_DEPENDENCIES}) + # Special flags applied to modules when compiling with testing enabled + if (BUILD_TESTING) + target_compile_options("${MODULE}" PRIVATE ${FPRIME_TESTING_REQUIRED_COMPILE_FLAGS}) + target_link_libraries("${MODULE}" PRIVATE ${FPRIME_TESTING_REQUIRED_LINK_FLAGS}) + endif() endfunction() #### @@ -120,11 +125,6 @@ function(build_add_module_target MODULE TARGET SOURCES DEPENDENCIES) run_ac_set("${SOURCES}" ${CUSTOM_AUTOCODERS}) resolve_dependencies(RESOLVED ${DEPENDENCIES} ${AC_DEPENDENCIES} ) build_setup_build_module("${MODULE}" "${SOURCES}" "${AC_GENERATED}" "${AC_SOURCES}" "${RESOLVED}") - # Special flags applied to modules when compiling with testing enabled - if (BUILD_TESTING) - target_compile_options("${MODULE}" PRIVATE ${FPRIME_TESTING_REQUIRED_COMPILE_FLAGS}) - target_link_libraries("${MODULE}" PRIVATE ${FPRIME_TESTING_REQUIRED_LINK_FLAGS}) - endif() if (CMAKE_DEBUG_OUTPUT) introspect("${MODULE}") diff --git a/cmake/target/check.cmake b/cmake/target/check.cmake index 4d7ddbd4c3..0bced5053b 100644 --- a/cmake/target/check.cmake +++ b/cmake/target/check.cmake @@ -11,9 +11,7 @@ # - **TARGET_NAME:** target name to be generated #### function(check_add_global_target TARGET_NAME) - add_custom_target(${TARGET_NAME} - COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR} find . -name "*.gcda" -delete - COMMAND ${CMAKE_CTEST_COMMAND}) + add_custom_target(${TARGET_NAME} COMMAND ${CMAKE_CTEST_COMMAND}) endfunction(check_add_global_target) #### @@ -33,12 +31,18 @@ function(check_add_deployment_target MODULE TARGET SOURCES DEPENDENCIES FULL_DEP get_property(DEPENDENCY_UTS TARGET "${DEPENDENCY}" PROPERTY FPRIME_UTS) list(APPEND ALL_UTS ${DEPENDENCY_UTS}) endforeach() - string(REPLACE ";" "\\|" JOINED_UTS "${ALL_UTS}") - add_custom_target(${MODULE}_${TARGET_NAME} - COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR} find . -name "*.gcda" -delete - COMMAND ${CMAKE_CTEST_COMMAND} -R "${JOINED_UTS}" - DEPENDS ${ALL_UTS} - ) + # Only run deployment UTs when some are defined + if (ALL_UTS) + string(REPLACE ";" "\\|" JOINED_UTS "${ALL_UTS}") + add_custom_target(${MODULE}_${TARGET_NAME} + COMMAND ${CMAKE_CTEST_COMMAND} -R "${JOINED_UTS}" + DEPENDS ${ALL_UTS} + ) + else() + add_custom_target(${MODULE}_${TARGET_NAME} + COMMAND ${CMAKE_COMMAND} -E echo "No unit tests defined for ${MODULE}" + ) + endif() endfunction() #### @@ -58,7 +62,6 @@ function(check_add_module_target MODULE_NAME TARGET_NAME SOURCE_FILES DEPENDENCI elseif (NOT TARGET ${MODULE_NAME}_${TARGET_NAME}) add_custom_target( "${MODULE_NAME}_${TARGET_NAME}" - COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR} find . -name "*.gcda" -delete COMMAND ${CMAKE_CTEST_COMMAND} --verbose ) endif() diff --git a/cmake/target/install.cmake b/cmake/target/install.cmake index 118b8e8c9e..0b3df79e49 100644 --- a/cmake/target/install.cmake +++ b/cmake/target/install.cmake @@ -43,12 +43,16 @@ function(install_add_deployment_target MODULE TARGET SOURCES DEPENDENCIES FULL_D set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE) _install_real_helper(INSTALL_DEPENDENCIES "${FULL_DEPENDENCIES}") install(TARGETS ${MODULE} ${INSTALL_DEPENDENCIES} - RUNTIME DESTINATION ${TOOLCHAIN_NAME}/bin - LIBRARY DESTINATION ${TOOLCHAIN_NAME}/lib - ARCHIVE DESTINATION ${TOOLCHAIN_NAME}/lib/static) - get_property(DICTIONARY GLOBAL PROPERTY "${PROJECT_NAME}_FPRIME_DICTIONARY_FILE") - install(FILES ${DICTIONARY} DESTINATION ${TOOLCHAIN_NAME}/dict) - add_custom_command(TARGET "${MODULE}" POST_BUILD COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target install) + RUNTIME DESTINATION ${TOOLCHAIN_NAME}/${MODULE}/bin + COMPONENT ${MODULE} + LIBRARY DESTINATION ${TOOLCHAIN_NAME}/${MODULE}/lib + COMPONENT ${MODULE} + ARCHIVE DESTINATION ${TOOLCHAIN_NAME}/${MODULE}/lib/static + COMPONENT ${MODULE} + ) + install(FILES ${FPRIME_CURRENT_DICTIONARY_FILE} DESTINATION ${TOOLCHAIN_NAME}/${MODULE}/dict COMPONENT ${MODULE}) + add_custom_command(TARGET "${MODULE}" POST_BUILD COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=${MODULE} -P ${CMAKE_BINARY_DIR}/cmake_install.cmake) endfunction() # Install is per-deployment, a module-by-module variant does not make sense diff --git a/cmake/test/src/test_feature.py b/cmake/test/src/test_feature.py index fb700f0c1e..780269939d 100644 --- a/cmake/test/src/test_feature.py +++ b/cmake/test/src/test_feature.py @@ -59,7 +59,7 @@ def test_feature_library(FEATURE_BUILD): def test_feature_deployment(FEATURE_BUILD): """Feature build check deployment properly detected""" cmake.assert_process_success(FEATURE_BUILD) - library_name = f"TestDeployment" + library_name = "TestDeployment" output_path = FEATURE_BUILD["build"] / "bin" / platform.system() / library_name assert output_path.exists(), f"Failed to locate {library_name} in build output" @@ -87,6 +87,7 @@ def test_feature_targets(FEATURE_BUILD): def test_feature_installation(FEATURE_BUILD): """Run reference and assert reference targets exit""" cmake.assert_process_success(FEATURE_BUILD) + deployment_name = "TestDeployment" for module in settings.FRAMEWORK_MODULES + [ "Svc_CmdDispatcher", "TestLibrary_TestComponent", @@ -96,12 +97,17 @@ def test_feature_installation(FEATURE_BUILD): output_path = ( FEATURE_BUILD["install"] / platform.system() + / deployment_name / "lib" / "static" / library_name ) assert output_path.exists(), f"Failed to locate {library_name} in build output" output_path = ( - FEATURE_BUILD["install"] / platform.system() / "bin" / "TestDeployment" + FEATURE_BUILD["install"] + / platform.system() + / deployment_name + / "bin" + / deployment_name ) - assert output_path.exists(), f"Failed to locate TestDeployment in build output" + assert output_path.exists(), "Failed to locate TestDeployment in build output" diff --git a/cmake/test/src/test_ref_shared.py b/cmake/test/src/test_ref_shared.py index ab7a8357d6..2f4fa17805 100644 --- a/cmake/test/src/test_ref_shared.py +++ b/cmake/test/src/test_ref_shared.py @@ -36,7 +36,7 @@ def test_ref_targets(REF_BUILD): output_path = REF_BUILD["build"] / "lib" / platform.system() / library_name assert output_path.exists(), f"Failed to locate {library_name} in build output" output_path = REF_BUILD["build"] / "bin" / platform.system() / "Ref" - assert output_path.exists(), f"Failed to locate Ref in build output" + assert output_path.exists(), "Failed to locate Ref in build output" def test_ref_installation(REF_BUILD): @@ -46,10 +46,12 @@ def test_ref_installation(REF_BUILD): library_name = ( f"lib{module}{'.so' if platform.system() != 'Darwin' else '.dylib'}" ) - output_path = REF_BUILD["install"] / platform.system() / "lib" / library_name + output_path = ( + REF_BUILD["install"] / platform.system() / "Ref" / "lib" / library_name + ) assert output_path.exists(), f"Failed to locate {library_name} in build output" - output_path = REF_BUILD["install"] / platform.system() / "bin" / "Ref" - assert output_path.exists(), f"Failed to locate Ref in build output" + output_path = REF_BUILD["install"] / platform.system() / "Ref" / "bin" / "Ref" + assert output_path.exists(), "Failed to locate Ref in build output" def test_ref_dictionary(REF_BUILD): @@ -58,7 +60,8 @@ def test_ref_dictionary(REF_BUILD): output_path = ( REF_BUILD["install"] / platform.system() + / "Ref" / "dict" / "RefTopologyAppDictionary.xml" ) - assert output_path.exists(), f"Failed to locate Ref in build output" + assert output_path.exists(), "Failed to locate Ref in build output" diff --git a/cmake/test/src/test_unittests.py b/cmake/test/src/test_unittests.py index 8dd9f0f3ea..2adc6e6859 100644 --- a/cmake/test/src/test_unittests.py +++ b/cmake/test/src/test_unittests.py @@ -78,7 +78,7 @@ def test_unittest_targets(UT_BUILD): assert output_path.exists(), f"Failed to locate {library_name} in build output" for executable in ["Ref"] + UNIT_TESTS: output_path = UT_BUILD["build"] / "bin" / platform.system() / executable - assert output_path.exists(), f"Failed to locate Ref in build output" + assert output_path.exists(), "Failed to locate Ref in build output" def test_unittest_installation(UT_BUILD): @@ -87,11 +87,16 @@ def test_unittest_installation(UT_BUILD): for module in MODULES: library_name = f"lib{module}.a" output_path = ( - UT_BUILD["install"] / platform.system() / "lib" / "static" / library_name + UT_BUILD["install"] + / platform.system() + / "Ref" + / "lib" + / "static" + / library_name ) assert output_path.exists(), f"Failed to locate {library_name} in build output" - output_path = UT_BUILD["install"] / platform.system() / "bin" / "Ref" - assert output_path.exists(), f"Failed to locate Ref in build output" + output_path = UT_BUILD["install"] / platform.system() / "Ref" / "bin" / "Ref" + assert output_path.exists(), "Failed to locate Ref in build output" def test_unittest_dictionary(UT_BUILD): @@ -100,7 +105,8 @@ def test_unittest_dictionary(UT_BUILD): output_path = ( UT_BUILD["install"] / platform.system() + / "Ref" / "dict" / "RefTopologyAppDictionary.xml" ) - assert output_path.exists(), f"Failed to locate Ref in build output" + assert output_path.exists(), "Failed to locate Ref in build output" diff --git a/cmake/toolchain/aarch64-linux.cmake b/cmake/toolchain/aarch64-linux.cmake new file mode 100644 index 0000000000..0c5dc4b421 --- /dev/null +++ b/cmake/toolchain/aarch64-linux.cmake @@ -0,0 +1,18 @@ +#### +# ARM 64-bit Toolchain +# +# This ARM toolchain will compile for 64-bit ARM systems running linux. It uses the arm packages installed on the system +# path for cross-compilation. To override the location of the tools use -DARM_TOOLS_PATH=... to specify the root +# directory of the tools installation. That directory should contain folders bin, lib, etc where the tools are located. +# +# These toolchains will use the linux libraries shipped with the compiler to build the final image. To override this, +# users should set -DCMAKE_SYSROOT=... to a directory containing a valid sysroot for their device. +# +# Cautions: +# 1. Care must be taken to ensure that the Linux OS running on the target is newer than the cross-compilers, or sysroot +# should be used to specify fixed library targets to compile against. +# 2. Specifying sysroot should be used with care as both libraries and headers must exist both in the sysroot +# +#### +set(CMAKE_SYSTEM_PROCESSOR "aarch64") +include("${CMAKE_CURRENT_LIST_DIR}/helpers/arm-linux-base.cmake") diff --git a/cmake/toolchain/arm-hf-linux.cmake b/cmake/toolchain/arm-hf-linux.cmake new file mode 100644 index 0000000000..47e7f098f2 --- /dev/null +++ b/cmake/toolchain/arm-hf-linux.cmake @@ -0,0 +1,20 @@ +#### +# ARM 32-bit Toolchain with Hardware Floating Point +# +# This ARM toolchain will compile for 32-bit ARM linux systems supporting hardware floating point operations. It uses +# the arm packages installed on the system path for cross-compilation. To override the location of the tools use +# -DARM_TOOLS_PATH=... to specify the root directory of the tools installation. That directory should contain folders +# bin, lib, etc where the tools are located. +# +# These toolchains will use the linux libraries shipped with the compiler to build the final image. To override this, +# users should set -DCMAKE_SYSROOT=... to a directory containing a valid sysroot for their device. +# +# Cautions: +# 1. Care must be taken to ensure that the Linux OS running on the target is newer than the cross-compilers, or sysroot +# should be used to specify fixed library targets to compile against. +# 2. Specifying sysroot should be used with care as both libraries and headers must both exist in the sysroot +# +#### +set(CMAKE_SYSTEM_PROCESSOR "arm") +set(ARM_TOOL_SUFFIX eabihf) +include("${CMAKE_CURRENT_LIST_DIR}/helpers/arm-linux-base.cmake") diff --git a/cmake/toolchain/arm-sf-linux.cmake b/cmake/toolchain/arm-sf-linux.cmake new file mode 100644 index 0000000000..60c25d4429 --- /dev/null +++ b/cmake/toolchain/arm-sf-linux.cmake @@ -0,0 +1,20 @@ +#### +# ARM 32-bit Toolchain with Software Floating Point +# +# This ARM toolchain will compile for 32-bit ARM linux systems supporting software floating point operations. It uses +# the arm packages installed on the system path for cross-compilation. To override the location of the tools use +# -DARM_TOOLS_PATH=... to specify the root directory of the tools installation. That directory should contain folders +# bin, lib, etc where the tools are located. +# +# These toolchains will use the linux libraries shipped with the compiler to build the final image. To override this, +# users should set -DCMAKE_SYSROOT=... to a directory containing a valid sysroot for their device. +# +# Cautions: +# 1. Care must be taken to ensure that the Linux OS running on the target is newer than the cross-compilers, or sysroot +# should be used to specify fixed library targets to compile against. +# 2. Specifying sysroot should be used with care as both libraries and headers must both exist in the sysroot +# +#### +set(CMAKE_SYSTEM_PROCESSOR "arm") +set(ARM_TOOL_SUFFIX eabi) +include("${CMAKE_CURRENT_LIST_DIR}/helpers/arm-linux-base.cmake") diff --git a/cmake/toolchain/helpers/arm-linux-base.cmake b/cmake/toolchain/helpers/arm-linux-base.cmake new file mode 100644 index 0000000000..388e0bbf51 --- /dev/null +++ b/cmake/toolchain/helpers/arm-linux-base.cmake @@ -0,0 +1,42 @@ +#### +# ARM Linux Toolchain Base: +# +# This file provides the basic work for ARM toolchains running on Linux systems. It uses the ARM_TOOL_PREFIX variable to +# determine the names of the tools to search for. This variable must be set in the calling script. This toolchain will +# find the ARM tools under the path specified with -DARM_TOOLS_PATH=... and if -DCMAKE_SYSROOT=... is specified then +# this path will be used for searching for libraries/headers to compile against. +#### +# Set the system information +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_VERSION 0.2) + +# Check ARM tools path +set(FIND_INPUTS PATHS ENV ARM_TOOLS_PATH PATH_SUFFIXES bin REQUIRED) +set(PREFIX_1 "${CMAKE_SYSTEM_PROCESSOR}-linux-gnu${ARM_TOOL_SUFFIX}") +set(PREFIX_2 "${CMAKE_SYSTEM_PROCESSOR}-none-linux-gnu${ARM_TOOL_SUFFIX}") +# Set the GNU ARM toolchain +find_program(CMAKE_ASM_COMPILER NAMES ${PREFIX_1}-as ${PREFIX_2}-as ${FIND_INPUTS}) +find_program(CMAKE_C_COMPILER NAMES ${PREFIX_1}-gcc ${PREFIX_2}-gcc ${FIND_INPUTS}) +find_program(CMAKE_CXX_COMPILER NAMES ${PREFIX_1}-g++ ${PREFIX_2}-g++ ${FIND_INPUTS}) +find_program(CMAKE_AR NAMES ${PREFIX_1}-ar ${PREFIX_2}-ar ${FIND_INPUTS}) +find_program(CMAKE_OBJCOPY NAMES ${PREFIX_1}-objcopy ${PREFIX_2}-objcopy ${FIND_INPUTS}) +find_program(CMAKE_OBJDUMP NAMES ${PREFIX_1}-objdump ${PREFIX_2}-objdump ${FIND_INPUTS}) + +# List programs as found +if (CMAKE_DEBUG_OUTPUT) + message(STATUS "[arm-linux] Assembler: ${CMAKE_ASM_COMPILER}") + message(STATUS "[arm-linux] C Compiler: ${CMAKE_C_COMPILER}") + message(STATUS "[arm-linux] CXX Compiler: ${CMAKE_CXX_COMPILER}") +endif() + +# Force sysroot onto +if (DEFINED CMAKE_SYSROOT) + message(STATUS "sysroot set to: ${CMAKE_SYSROOT}") + set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} "${CMAKE_SYSROOT}") +endif() + +# Configure the find commands for finding the toolchain +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/cmake/toolchain/raspberrypi.cmake b/cmake/toolchain/raspberrypi.cmake index 799ec18fa1..c23a5a828a 100644 --- a/cmake/toolchain/raspberrypi.cmake +++ b/cmake/toolchain/raspberrypi.cmake @@ -1,35 +1,18 @@ #### # Raspberry PI Toolchain # -# This is a toolchain for the Raspberry Pi. This toolchain can be used ot build +# This is a toolchain for the Raspberry Pi. This toolchain can be used to build # against the Raspberry Pi embedded Linux target. In order to use this toolchain, # the Raspberry Pi cross-compiler should be installed on a Linux host. These # tools are installable as follows: # sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf gdb-multiarch #### -# Set the system information -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR arm) -set(CMAKE_SYSTEM_VERSION 1) -# Configure the find commands for cross-compiling: tools from host, libraries, includes, and packages from cross-compiler/sysroot -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(CMAKE_SYSTEM_PROCESSOR "arm") +set(ARM_TOOL_SUFFIX eabihf) -# Check CMake sysroot -if (DEFINED CMAKE_SYSROOT) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT} ) +if(DEFINED ENV{RPI_TOOLCHAIN_DIR}) + set(ENV{ARM_TOOLS_PATH} "$ENV{RPI_TOOLCHAIN_DIR}") endif() -# Set the GNU ARM toolchain -find_program(CMAKE_AR NAMES arm-linux-gnueabihf-ar PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) -find_program(CMAKE_C_COMPILER NAMES arm-linux-gnueabihf-gcc PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) -find_program(CMAKE_CXX_COMPILER NAMES arm-linux-gnueabihf-g++ PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) -message(STATUS "[arm-linux] C Compiler: ${CMAKE_C_COMPILER}") -message(STATUS "[arm-linux] CXX Compiler: ${CMAKE_CXX_COMPILER}") -find_program(CMAKE_ASM_COMPILER NAMES arm-linux-gnueabihf-as PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) -find_program(CMAKE_OBJCOPY NAMES arm-linux-gnueabihf-objcopy PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) -find_program(CMAKE_OBJDUMP NAMES arm-linux-gnueabihf-objdump PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) - +include("${CMAKE_CURRENT_LIST_DIR}/helpers/arm-linux-base.cmake") diff --git a/config/AcConstants.fpp b/config/AcConstants.fpp index c3a2e81da2..a6d399d4a5 100644 --- a/config/AcConstants.fpp +++ b/config/AcConstants.fpp @@ -6,6 +6,9 @@ @ Number of rate group member output ports for ActiveRateGroup constant ActiveRateGroupOutputPorts = 10 +@ Number of rate group member output ports for PassiveRateGroup +constant PassiveRateGroupOutputPorts = 10 + @ Used to drive rate groups constant RateGroupDriverRateGroupPorts = 3 diff --git a/config/CmdSplitterCfg.hpp b/config/CmdSplitterCfg.hpp new file mode 100644 index 0000000000..048d773559 --- /dev/null +++ b/config/CmdSplitterCfg.hpp @@ -0,0 +1,16 @@ +/* + * CmdSplitterCfg.hpp: + * + * Used to configure the Svc::CmdSplitter component's remote opcode base. + * + */ + +#ifndef CONFIG_CMD_SPLITTER_CFG_HPP_ +#define CONFIG_CMD_SPLITTER_CFG_HPP_ + +namespace Svc { +//!< Base value for remote opcodes used by Svc::CmdSplitter +static const FwOpcodeType CMD_SPLITTER_REMOTE_OPCODE_BASE = 0x10000000; +}; + +#endif /* CONFIG_CMD_SPLITTER_CFG_HPP_ */ diff --git a/config/UdpReceiverComponentImplCfg.hpp b/config/UdpReceiverComponentImplCfg.hpp index f09ee10e07..4b69dd24eb 100644 --- a/config/UdpReceiverComponentImplCfg.hpp +++ b/config/UdpReceiverComponentImplCfg.hpp @@ -11,7 +11,7 @@ #include namespace Svc { - const static NATIVE_UINT_TYPE UDP_RECEIVER_MSG_SIZE = 256; + static const NATIVE_UINT_TYPE UDP_RECEIVER_MSG_SIZE = 256; } #endif /* SVC_UDPRECEIVER_UDPRECEIVERCOMPONENTIMPLCFG_HPP_ */ diff --git a/docs/Design/general.md b/docs/Design/general.md index 61f98d3006..4e03e2ab21 100644 --- a/docs/Design/general.md +++ b/docs/Design/general.md @@ -4,6 +4,7 @@ This section of the documentation captures the design and philosophy of F´, the viewed through F´. -| Table of Contents | -|------------------------------------------------| -| [Numerical Types Design](./numerical-types.md) | \ No newline at end of file +| Table of Contents | +|-------------------------------------------------------------------------| +| [Numerical Types Design](./numerical-types.md) | +| [Communication Adapter Interface](./communication-adapter-interface.md) | diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 7c398b69a9..c65d0b57d4 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -31,8 +31,7 @@ The ecosystem of tools supporting F´ is installed as python packages available pip install fprime-tools ``` -> Python is used by many operating systems. To prevent problems users are encouraged to run F´ python from within a [virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/). This is set up when creating a new F´ project. - +> You may need to install with `sudo` or install into a [virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/). ### Creating a New F´ Project @@ -50,7 +49,7 @@ Select install_venv: Choose from 1, 2 [1]: 1 ``` -Next steps: [HelloWorld Tutorial](Tutorials/HelloWorld/Tutorial.md) +Next steps: [HelloWorld Tutorial](https://fprime-community.github.io/fprime-tutorial-hello-world/) ## Advanced diff --git a/docs/Tutorials/CrossCompilation/Tutorial.md b/docs/Tutorials/CrossCompilation/Tutorial.md deleted file mode 100644 index 75890b32b8..0000000000 --- a/docs/Tutorials/CrossCompilation/Tutorial.md +++ /dev/null @@ -1,118 +0,0 @@ -# F´ Cross-Compilation Tutorial - -## Table of Contents - -* 1. Introduction - * 1.1. Cross-Compiling - * 1.2. Upload to the Raspberry Pi - * 1.3. Running Ref on the Raspberry Pi - * 1.4. Setting A Default Toolchain -* 2. Conclusion - -## 1. Introduction - -In this section, we will take our Ref topology and cross-compile it for the -Raspberry Pi. In order to fully benefit from this tutorial, the user should -acquire a Raspberry Pi and have the cross-compilation toolchain as described -in [RPI](https://github.com/nasa/fprime/blob/master/RPI/README.md). - -This part of the tutorial requires the user to have gone through the previous -sections and have a complete Ref topology. The user should also have an -understanding of the Raspberry Pi and specifically how to SSH into the Pi and -run applications. - - -### 1.1. Cross-Compiling - -In order to cross-compile for a specific architecture, the user needs to -generate a new build directory using a CMake toolchain file for that specific -architecture. F´ includes a toolchain for the Raspberry Pi (assuming that the -tools are installed correctly). This toolchain is called “raspberrypi”. The -cross-compilation build for the Raspberry Pi can be generated by running the -following commands in the Ref directory: - -```sh -fprime-util generate raspberrypi -``` - -followed by: -```sh -fprime-util build raspberrypi -``` - -This will generate the binary at `Ref/build-artifacts/raspberrypi/bin/Ref`. - - -### 1.2. Upload to the Raspberry Pi - -The user can then run the ground system as before with some additional -arguments: -```sh -fprime-gds -n --dictionary build-artifacts/raspberrypi/dict/RefTopologyAppDictionary.xml -``` - -Assuming that there is no firewall or other network limitations between the -Raspberry Pi and the host, the user can then copy the binary to the Raspberry -Pi by running the following from the Ref directory: - -```sh -scp build-artifacts/raspberrypi/bin/Ref pi@:~ -``` - -This will use the secure copy protocol (scp) to copy the executable over to -your Raspberry Pi's home directory. - - -### 1.3. Running Ref on the Raspberry Pi - -You can log into the Raspberry Pi via SSH by running: -```sh -ssh pi@ -``` - -Finally, you can run the Ref deployment on the Raspberry Pi as follows: -```sh -./Ref -a -p 50000 -``` - -Now the Raspberry Pi should be powered up and running the Ref deployment and -our host system should be running the ground system. - -> If the code worked when running natively but it isn't connecting for this -example then the cause is likely a firewall or network issue. Make sure -port 50000 is exposed to the Pi, and that the Pi can ping the ground system -machine. - - -### 1.4. Setting A Default Toolchain - -As we have seen in the previous sections, cross-compilation builds can be done -explicitly by setting the toolchain. However, some users may wish to make a -particular toolchain the default and don't want to specify it every time. - -A recommended way of setting a default toolchain in F´ is by adding a -[settings.ini file](../../UsersGuide/user/settings.md). This file provides -build-time configuration settings for F´ and can be used to set a default -toolchain as follows: - -```ini -[fprime] -; ... other options in file ... -default_toolchain: raspberrypi -``` - -Now the "raspberrypi" build can be created with a call to -`fprime-util generate` and the original native build can be made by explicitly -setting the native toolchain: `fprime-util generate native`. - -### 2. Conclusion - -The Cross-Compilation tutorial has shown us how to cross-compile our simple Ref -application to the Raspberry Pi. We have seen how to copy our deployment to the -Raspberry Pi and run the ground system on our host computer to interact with -our deployment on the Raspberry Pi. - -The user is now directed back to the [Tutorials](../README.md) for further -reading or to the [GPS Tutorial](../GpsTutorial/Tutorial.md) for a more -advanced tutorial. For information on porting F´ to a new platform please -refer to the [User's Guide](../../UsersGuide/guide.md). \ No newline at end of file diff --git a/docs/Tutorials/CrossCompilationSetup/ArmLinuxTutorial.md b/docs/Tutorials/CrossCompilationSetup/ArmLinuxTutorial.md new file mode 100644 index 0000000000..94adf9111a --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/ArmLinuxTutorial.md @@ -0,0 +1,45 @@ +# F´ Running on ARM Linux Tutorial + +For this tutorial, the assumption is that the ARM Linux machine is available on the network, is running SSH, and the username, password, device address, and host address are known. Without this configuration, users should skip to the next section of the tutorial. + +First, in a terminal upload the software to hardware platform. This is done with: + +```sh +# For ARM 64-bit hardware +# In: Deployment Folder +scp -r build-artifacts/aarch64-linux @:deployment + +# For ARM 32-bit hardware +# In: Deployment Folder +scp -r build-artifacts/arm-hf-linux @:deployment +``` +> Users must fill in the username and device address above. + +Next run the F´ GDS without launching the native compilation (`-n`) and with the +dictionary from the build above (`--dictionary ./build-artifacts//<.xml document>`). + +```sh +# For in-person workshops and ARM 64-bit hardware +# In: Deployment Folder +fprime-gds -n --dictionary build-artifacts/aarch64-linux/dict/.xml + +# For ARM 32-bit hardware +# In: Deployment Folder +fprime-gds -n --dictionary build-artifacts/aarch64-linux/dict/.xml +``` + +In another terminal SSH into the device and run the uploaded software: +```sh +ssh @ +sudo deployment/bin/ -a -p 50000 +``` +> User should fill in the username and device address above and ensure the executable is supplied the address of the host computer (that ran the GDS). + +> If the device does not connect, ensure that the firewall port 50000 is open on the host computer. + +## Troubleshooting + +If you are getting errors for missing Libc.c files, make sure when you generate +that the logs show that it is using the `/opt/toolchains` path and not `/bin`. +You can additionally verify that the correct toolchain is being used by watching +the logs scroll by when you initially `fprime-util generate `. \ No newline at end of file diff --git a/docs/Tutorials/CrossCompilationSetup/CrossCompilationSetupTutorial.md b/docs/Tutorials/CrossCompilationSetup/CrossCompilationSetupTutorial.md new file mode 100644 index 0000000000..51760a9442 --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/CrossCompilationSetupTutorial.md @@ -0,0 +1,61 @@ +# F´ Cross-Compilation Setup Tutorial + +## Table of Contents + +* 1. Introduction + * Prerequisites +* 2. Installing Dependencies +* 3. Installing the Toolchain + + +## 1. Introduction + +In this section, we will learn how to install all the dependencies required for cross-compiling for different architectures. +This tutorial will use the Raspberry Pi ARM x64 as an example. In order to fully benefit from this tutorial, the user should acquire a Raspberry Pi. + + +### Prerequisites + +To run through this tutorial, you must have a computer that meets the following basic requirements. + +1. Computer running Windows 10, Mac OS X, or Ubuntu +2. Administrator access +3. 5GB of free disk space, 8 GB of RAM +4. Knowledge of the command line for your operating system (Bash, Powershell, Zsh, etc). + + +## 2. Installing Dependencies + +Choose the operating system you are using to install F Prime: + +- [Windows 10/11 WSL](./Windows.md) +- [Mac OS X](./MacOS.md) +- [Ubuntu 20.04 / 22.04 / Generic Linux](./Linux.md) + + +## 3. Installing the Toolchain + +> Note: macOS users must run these commands from within the Docker container described in [Appendix I](./appendix-1.md) or setup a Linux virtual machine. + +Installing the cross-compiler will use the pre-built packages provided by ARM. Follow these +instructions to install these tools for the target hardware into the `/opt/toolchains` directory. + +```bash +sudo mkdir -p /opt/toolchains +sudo chown $USER /opt/toolchains +# For in-person workshops, and users running on 64-bit ARM +curl -Ls https://developer.arm.com/-/media/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu.tar.xz | tar -JC /opt/toolchains --strip-components=1 -x +# For users running on 32-bit ARM +curl -Ls https://developer.arm.com/-/media/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz | tar -JC /opt/toolchains --strip-components=1 -x +``` + +Next, ensure that the ARM toolchains were installed properly. To test, run the following command: +```shell +# For 64-bit ARM hardware +/opt/toolchains/bin/aarch64-none-linux-gnu-gcc -v +# For 32-bit ARM hardware +/opt/toolchains/bin/arm-linux-gnueabi-gcc -v +``` + Any output other than "file/command not found" is good. + +**Next:** [Compiling for ARM](./CrossCompilationTutorial.md) diff --git a/docs/Tutorials/CrossCompilationSetup/CrossCompilationTutorial.md b/docs/Tutorials/CrossCompilationSetup/CrossCompilationTutorial.md new file mode 100644 index 0000000000..493fece2e7 --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/CrossCompilationTutorial.md @@ -0,0 +1,54 @@ +# F´ Cross-Compilation Tutorial + +## Table of Contents + +* 1. Introduction +* 2. Compiling for ARM +* 3. Troubleshooting + + + +## 1. Introduction + +In this section, we will learn how to cross-compile for different architectures. This tutorial will use the Raspberry Pi ARM x64 as an example. In order to fully benefit from this tutorial, the user should acquire a Raspberry Pi. + +The user should also have an understanding of the Raspberry Pi and specifically how to SSH into the Pi and run applications. + + +### Prerequisites +Install the dependencies required for compiling for ARM. See the steps in the [Cross-Compilation Setup Tutorial](./CrossCompilationSetupTutorial.md) for more information. + + + +## 2. Compiling for ARM + +Cross-compiling is as easy as building the deployment for a specific platform. +For users running on 64-bit arm the platform is called `aarch64-linux`, and for users +on 32-bit arm use `arm-hf-linux`. This package expects the environment variable +`ARM_TOOLS_PATH` to point to the installation directory of the ARM cross-compilers. + +> Users need to generate for each platform they wish to run on. + +Here is how to build for the 64-bit Arm Linux platform: + +```sh +export ARM_TOOLS_PATH=/opt/toolchains + +#You can check to make sure the environment variable is set by running: +echo $ARM_TOOLS_PATH + +#This should return the path /opt/toolchains + +# For in-person workshops and ARM 64-bit hardware +# In: Deployment Folder +fprime-util generate aarch64-linux +fprime-util build aarch64-linux + +# For ARM 32-bit hardware +# In: Deployment Folder +fprime-util generate arm-hf-linux +fprime-util build arm-hf-linux +``` +> Note: macOS users must run these commands from within the Docker container described in [Appendix I](./appendix-1.md). + +**Next:** [Running on ARM Linux](./ArmLinuxTutorial.md) \ No newline at end of file diff --git a/docs/Tutorials/CrossCompilationSetup/Linux.md b/docs/Tutorials/CrossCompilationSetup/Linux.md new file mode 100644 index 0000000000..3ed3d1d514 --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/Linux.md @@ -0,0 +1,10 @@ +# Ubuntu 20.04 / 22.04 / Generic Linux + +Ensure that your distribution is up to date. + +```sh +sudo apt update +sudo apt install build-essential git g++ gdb cmake python3 python3-venv python3-pip +``` + +After the steps above are completed, [return to the tutorial.](../CrossCompilationSetup/CrossCompilationSetupTutorial.md) diff --git a/docs/Tutorials/CrossCompilationSetup/MacOS.md b/docs/Tutorials/CrossCompilationSetup/MacOS.md new file mode 100644 index 0000000000..b76b78f971 --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/MacOS.md @@ -0,0 +1,29 @@ +# Mac OS X + +MacOS like Linux is a unix system and thus may be used directly for most of this +tutorial. However, Mac users must install the following utilities +*and ensure they are available on the command line path*. + +1. [Python 3](https://www.python.org/downloads/release/python-3913/) +2. [CMake](https://cmake.org/download/) +3. GCC/CLang typically installed with xcode-select + +**Installing GCC/CLang on macOS** +```bash +xcode-select --install +``` + +Installing Python and running the above command to install gcc/CLang should ensure +that those tools are on the path. + +CMake requires one additional step to ensure it is on the path: + +```bash +sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install +``` + +In order to cross-compile, a Linux box is essential. You may choose to use a virtual +machine or may choose to follow the instructions in [Appendix I](./appendix-1.md) to +install a docker container including the necessary tools. + +After the steps above are completed, [return to the tutorial.](../CrossCompilationSetup/CrossCompilationSetupTutorial.md) \ No newline at end of file diff --git a/docs/Tutorials/CrossCompilationSetup/README.md b/docs/Tutorials/CrossCompilationSetup/README.md new file mode 100644 index 0000000000..e69a760190 --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/README.md @@ -0,0 +1,7 @@ +# F´ Cross-Compilation Tutorial + +## Table of Contents + +1. [Cross-Compilation Setup](./CrossCompilationSetupTutorial.md) +2. [Compiling for ARM](./CrossCompilationTutorial.md) +3. [Running on ARM Linux](./ArmLinuxTutorial.md) diff --git a/docs/Tutorials/CrossCompilationSetup/Windows.md b/docs/Tutorials/CrossCompilationSetup/Windows.md new file mode 100644 index 0000000000..1f6e876c5c --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/Windows.md @@ -0,0 +1,44 @@ +# Microsoft Windows 10/11 WSL + +Windows 10 ships with a technology known as WSL. WSL allows users to run Linux virtual machines transparently within the Windows 10 operating system. + +**Powershell: Install WSL with Default Ubuntu** +```powershell +wsl --install +``` + +To start Ubuntu under WSL, search for Ubuntu in the start menu and select the "Ubuntu on Windows" app. All class commands should be run on these Ubuntu terminals. + +> Full instructions and troubleshooting help is available in the +> [Microsoft documentation](https://learn.microsoft.com/en-us/windows/wsl/install). + +Lastly, Windows users must open up a firewall port and forward that port to WSL to +ensure the hardware can call back into F' ground data system running in WSL. First we'll +need to note the IP address of the WSL machine. This is done with the following +command *in an administrator PowerShell*. + +```powershell +wsl hostname -I +``` + +> Record the output of this command for the next step. For this guide, we will use +> the value `127.0.0.1`. + +Next, we will add a firewall rule and forward it to the WSL instance. This is done with the following commands: + +> Warning: these commands work with the Windows firewall. Security and antivirus tools +> can run extra firewall rules. Users must allow the port `50000` (Or whichever port that +> is going to be used) or disable these extra firewall settings. + +**PowerShell: Add and Forward External Firewall Rule** +```PowerShell +New-NetFirewallRule -DisplayName "fprime" -Direction inbound -Profile Any -Action Allow -LocalPort 50000 -Protocol TCP +``` + +> Remember to change `127.0.0.1` to your recorded ip address as discovered with +> `wsl hostname -I`. Users are advised to remove this rule after the class has been completed. + + +**IMPORTANT:** + +Go to the [Ubuntu 20.04 / 22.04 / Generic](./Linux.md) Linux to finish setting up your WSL environment. diff --git a/docs/Tutorials/CrossCompilationSetup/appendix-1.md b/docs/Tutorials/CrossCompilationSetup/appendix-1.md new file mode 100644 index 0000000000..4f4d937a83 --- /dev/null +++ b/docs/Tutorials/CrossCompilationSetup/appendix-1.md @@ -0,0 +1,42 @@ +# Appendix I: Installing Rancher Desktop and the F´ ARM Container + +Some users may with to run cross-compilers within docker to minimize the impact of those tools on their systems. Macintosh users will be required to use docker as the ARM/Linux cross-compilers are not available natively for macOS and simple virtualization of a Linux box is no longer practical since the introduction of M1 and M2 hardware. + +## Rancher Desktop Setup + +Rancher Desktop is an alternative to Docker Desktop that allows users to run docker containers directly on their desktop computer. It does not require a license for use like Docker Desktop does and also supports both intel and ARM based Macintosh computers. + +> Non-Macintosh users are advised to run without the below Docker container + +To install [Rancher Desktop](https://rancherdesktop.io/), follow the instructions for your operating system. When presented with a "Welcome to Rancher Desktop" dialog, choose the following settings: +1. Disable Kubernetes +2. Select `dockerd` +3. Configure PATH Automatic + +![Rancher Config](./img/rancher-config.png) + +Ensure that Rancher Desktop is running and that the VM it uses has been started. You can confirm this by ensuring no pop-ups nor progress bars are visible in Rancher Desktop's main window as shown below. + +![Rancher Main Window](./img/rancher-running.png) + +Once this is done, users can install the container by running the following command in their host terminal. It should complete without errors. + +```bash +docker pull nasafprime/fprime-arm:latest +``` + +## Running The Container + +In order to run the commands provided by the docker container (i.e. the cross-compilers), users must start the container and attach to a terminal inside. This should be done **after** the user has created a project to work within. + +To run this container, users may wish to download [this script](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/bin/macos-docker) to a `bin` directory in the root of their project. This will start the docker container with appropriate settings. + +Alternatively, the user may run the following command to start the terminal +```bash +docker run --platform=linux/amd64 --net host -e USER=$USER -u "`id -u`:`id -g`" -v "/path/to/project:/project" -it \ + docker pull nasafprime/fprime-arm:latest +``` + +> Anytime Macintosh users run cross-compilation commands, they **must** do so in a terminal inside the docker container. + +[Return to Macintosh tutorial.](./MacOS.md) \ No newline at end of file diff --git a/docs/Tutorials/CrossCompilationSetup/img/rancher-config.png b/docs/Tutorials/CrossCompilationSetup/img/rancher-config.png new file mode 100644 index 0000000000..1a6b761fcb Binary files /dev/null and b/docs/Tutorials/CrossCompilationSetup/img/rancher-config.png differ diff --git a/docs/Tutorials/CrossCompilationSetup/img/rancher-running.png b/docs/Tutorials/CrossCompilationSetup/img/rancher-running.png new file mode 100644 index 0000000000..f0f1a38f13 Binary files /dev/null and b/docs/Tutorials/CrossCompilationSetup/img/rancher-running.png differ diff --git a/docs/Tutorials/HelloWorld/Deployments.md b/docs/Tutorials/HelloWorld/Deployments.md deleted file mode 100644 index b3193d53e7..0000000000 --- a/docs/Tutorials/HelloWorld/Deployments.md +++ /dev/null @@ -1,179 +0,0 @@ -# Getting Started: Integration and Testing With F´ Deployments - -This section will walk new users through creating a new F´ [deployment](./Tutorial.md#deployment). This deployment will -build a [topology](./Tutorial.md#topology) containing the standard F´ stack of components and a single `HelloWorld` -component instance. The `HelloWorld` was created in the [last section](./HelloWorld.md). The tutorial will close by -testing the deployment and `HelloWorld` component through the `fprime-gds`. - -### Prerequisites: -- [Getting Started: F´ Hello World Component](./HelloWorld.md) - -### Tutorial Steps: -- [Creating A New Deployment](#creating-a-new-deployment) -- [Adding The Hello World Component](#adding-the-hello-world-component) -- [Testing With `fprime-gds`](#testing-with-fprime-gds) -- [Conclusion](#conclusion) - -## Creating A New Deployment - -F´ deployments represent one flight software executable. All the components we develop for F´ run within a deployment. -The deployment created here will contain the standard command and data handling stack. This stack enables -ground control and data collection of the deployment. - -To create a deployment, run the following commands: -```bash -cd MyProject -fprime-util new --deployment -``` -This command will ask for some input. Respond with the following answers: - -``` -deployment_name [MyDeployment]: MyDeployment -path_to_fprime [./fprime]: -author_name []: LeStarch -``` - -> For any other questions, select the default response. - -At this point, the `MyDeployment` has been created, but our `HelloWorld` component has not been added. - -## Adding The Hello World Component - -First, the project's components should be added to this deployment's build. This can be done by adding the following -to `MyDeployment/CMakeLists.txt`. - -```cmake -... -### -# Components and Topology -### -include("${FPRIME_PROJECT_ROOT}/project.cmake") -... -``` - -In this section the `HelloWorld` component will be added to the `MyDeployment` deployment. This can be done by adding -the component to the topology defined in `MyDeployment/Top`. - -Topologies instantiate all the components in a running system and link them together. For some port types, like the -commanding, event, and telemetry ports used by `HelloWorld`, the connections are made automatically. In addition, the -topology specifies how to construct the component instance. This is also done automatically unless the component has -specific configuration. - -In order to add a component to the topology, it must be added to the topology model. An instance definition and an -instance initializer must both be added. - -To add an instance definition, add `instance helloWorld` to the instance definition list in the `topology Ref` section -of `MyDeployment/Top/topology.fpp`. This is shown below. - -``` -... - topology Ref { - # ---------------------------------------------------------------------- - # Instances used in the topology - # ---------------------------------------------------------------------- - - instance ... - instance ... - instance helloWorld -``` -> Be careful to not remove any other instances from the list. - -`helloWorld` is the name of the component instance. Like variable names, component instance names should be descriptive -and are typically named in camel or snake case. - -Next, an instance initializer must be added to topology instances defined in `MyDeploymment/Top/instances.fpp` file. -Since the `HelloWorld` component is an `active` component it should be added to the active components section and should -define a priority and queue depth options. This is shown below. - -``` -... - # ---------------------------------------------------------------------- - # Active component instances - # ---------------------------------------------------------------------- - instance ... - ... - ... - ... - - instance ... - - instance helloWorld: MyComponents.HelloWorld base id 0x0F00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 50 -``` -> The user must ensure that the base id (0x0F00) does not conflict with any other base ids in the topology. 0x0F00 -> should be safe for deployments created with `fprime-util new --deployment`. - -> Make sure to use the same instance name (i.e. helloWorld) as defined in the instance definition just added to -> `topology.fpp`. - -Finally, our new telemetry channel should be added to our telemetry packet specification. For this tutorial the -channel can be ignored as the deployment will not use the telemetry packetizer. Add the following to the `ignore` -section of `MyDeployment/Top/MyDeploymentPackets.xml`. - -``` - - ... - - -``` - -Since this component has no custom ports nor does it require special configuration, our addition to the topology is -completed. The deployment can now be set up and built using the following commands: - -``` -cd MyDeployment -fprime-util generate -fprime-util build -j4 -``` -Resolve any errors that occur before continuing to the testing section. - -> Notice `fprime-util generate` was used again. This is because this new deployment builds in a separate environment. - -## Testing With `fprime-gds` - -It is now time to test the `HelloWorld` component by running the deployment created in this section. This can be -accomplished by running the `fprime-gds` command in the deployment, verifying connection, sending the new SEND_HELLO -command and verifying that the `Hello` event and `GreetingCount` channel appears. - -To start the deployment with default settings, run: -```bash -fprime-gds -``` - -The F´ GDS control page should open up in your web browser. If it does not open up, navigate to `http://127.0.0.1:5000`. - -Once the F´ GDS page is visible, look for a green circle icon in the upper right corner. This shows that the flight -software deployment has connected to the GDS system. If a red X appears instead, navigate to the Logs tab and look for -errors in the various logs. - -Now that communication is verified, navigate to the "Commanding" tab and select `helloWorld.SAY_HELLO` from the -dropdown list. Type a greeting into the argument input box and click the button "Send Command". If the argument has -validated successfully the command will send. Resolve all errors and ensure the command has sent. - -> Notice commands are instance specific. Had several HelloWorld component instances been used, there would be multiple -> `SAY_HELLO` listings, one for each component instance. - -Now that the command has sent, navigate to the "Events" tab. Ensure that the event list contains the Hello event with -the text entered when sending the command. - -Lastly, navigate to the "Channels" tab. Look for "helloWorld.GreetingCount" in the channel list. Ensure it has recorded -the number of times a `helloWorld.SAY_HELLO` was sent. - -Congratulations, you have now set up a project, component, and deployment in F´. - -## Conclusion - -This concludes both the adding deployment section of the Getting Started tutorial and the tutorial itself. The user has -been able to perform the following actions: - -1. Create a new blank F´ projects -2. Create a new F´ components -3. Create a new F´ deployments and add components it - -To explore components more in-depth and see how components communicate with one another, see the -[Math Component Tutorial](../MathComponent/Tutorial.md). - -**Next:** [Math Component Tutorial](../MathComponent/Tutorial.md) - diff --git a/docs/Tutorials/HelloWorld/HelloWorld.md b/docs/Tutorials/HelloWorld/HelloWorld.md deleted file mode 100644 index 527d08413e..0000000000 --- a/docs/Tutorials/HelloWorld/HelloWorld.md +++ /dev/null @@ -1,189 +0,0 @@ -# Getting Started: Creating an F´ Hello World Component - -This tutorial will walk new users through creating a basic F´ component. Users should have completed the new project -tutorial and have the tools sourced as shown in the [conclusion](./NewProject.md#conclusion) portion of that tutorial. - -F´ components encapsulate the various parts of system behavior. These components can interact with the ground system -through [commands](Tutorial.md#command), [events](./Tutorial.md#event), and -[telemetry channels](./Tutorial.md#telemetry-channel). Components communicate with other components through -[ports](./Tutorial.md#port), which covered in-depth in [another tutorial](../MathComponent/Tutorial.md). - -### Prerequisites: -- [Getting Started: Creating an F´ Project](./NewProject.md) - -### Tutorial Steps: -- [Hello World Component](#hello-world-component-requirements) -- [Creating the Hello World Component](#creating-the-hello-world-component) -- [Editing the Component Model](#editing-the-component-model) -- [Implementing Component Behavior](#implementing-component-behavior) -- [Conclusion](#conclusion) - -## Hello World Component Requirements - -The first step for creating a new component is understanding what it is that we wish to implement. This is called -defining requirements. In the spirit of "Hello World" this component will encapsulate greeting behavior. The component -will define three items to implement greeting behaviour: - -1. A [command](./Tutorial.md#command) called `SAY_HELLO` that will command the component to send a greeting -2. An [event](./Tutorial.md#event) called `Hello` that is the greeting sent in response to the `SAY_HELLO` command -3. A [telemetry channel](./Tutorial.md#telemetry-channel) called `GreetingCount` that will count each `Hello` event sent - -These are a simple set of requirements for this component. - -## Creating the Hello World Component - -The next step is to create the new component. First, create a directory called `MyComponents` to contain this project's -components and change into that directory. - -```bash -mkdir MyComponents -cd MyComponents -``` - -Creating a new component is accomplished with the following command: - -```bash -fprime-util new --component -``` -This command will ask for some input. You should respond with the following answers: - -``` -[INFO] Cookiecutter source: using builtin -component_name [MyComponent]: HelloWorld -component_short_description [Example Component for F Prime FSW framework.]: Hello World Tutorial Component -component_namespace [HelloWorld]: MyComponents -Select component_kind: -1 - active -2 - passive -3 - queued -Choose from 1, 2, 3 [1]: 1 -Select enable_commands: -1 - yes -2 - no -Choose from 1, 2 [1]: 1 -Select enable_telemetry: -1 - yes -2 - no -Choose from 1, 2 [1]: 1 -Select enable_events: -1 - yes -2 - no -Choose from 1, 2 [1]: 1 -Select enable_parameters: -1 - yes -2 - no -Choose from 1, 2 [1]: 2 -[INFO] Found CMake file at 'MyProject/project.cmake' -Add component MyComponents/HelloWorld to MyProject/project.cmake at end of file (yes/no)? yes -Generate implementation files (yes/no)? no -``` - -> For any other questions, select the default response. - -This will create a new component called "HelloWorld" in the "MyProject" namespace. This new component will be able to -define commands, events, and telemetry channels. - -We should navigate to the component's directory and look around: - -```bash -cd HelloWorld -ls -``` -This will show the following files: -1. `HelloWorld.fpp`: design model for the component -2. `HelloWorld.hpp` and `HelloWorld.cpp`: C++ implementation files for the component, currently empty. -3. `CMakeList.txt`: build definitions for the component. -4. `docs` folder to place component documentation - -To build this component run `fprime-util build` in the current folder. - -> Any component in F´ can be built by navigating to the component's folder and running `fprime-util build`. - -## Editing the Component Model - -A component model defines the interface of the component with the rest of the F´ system and with the ground system F´ -communicates with. In this case we intend to define a command, an event, and a telemetry channel as specified above. - -Open the model file `HelloWorld.fpp` and add replace the line - -`async command TODO opcode 0` - -with the following: - -``` -@ Command to issue greeting with maximum length of 20 characters -async command SAY_HELLO( - greeting: string size 20 @ Greeting to repeat in the Hello event -) - -@ Greeting event with maximum greeting length of 20 characters -event Hello( - greeting: string size 20 @ Greeting supplied from the SAY_HELLO command -) severity activity high format "I say: {}" - -@ A count of the number of greetings issued -telemetry GreetingCount: U32 -``` -> You should ensure to replace any existing command, event, and channel definitions with those supplied above but leave -> the 'Standard AC Ports' section untouched. - -With this step completed you can generate a basic implementation with the following command: - -```bash -fprime-util impl -``` - -This creates `HelloWorld.hpp-template` and `HelloWorld.cpp-template` files that contain our new fill-in template. While -normally one would merge new templates with the existing code, we will instead overwrite the existing implementations as -we have not edited those files yet. To do this: - -```bash -mv HelloWorld.hpp-template HelloWorld.hpp -mv HelloWorld.cpp-template HelloWorld.cpp -``` -We are now ready for implementing component behavior. - -## Implementing Component Behavior - -F´ behavior is implemented in two types of methods command handler functions to implement command behavior and handler -functions to implement port behavior (as described in the next tutorial). For this tutorial we need to implement the -`SAY_HELLO` command, so we need to edit the `SAY_HELLO_cmdHandler` function in the `HelloWorld.cpp` file. Ensure its -contents look like: - -```c++ -void HelloWorld:: SAY_HELLO_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& greeting) { - // Copy the command string input into an event string for the Hello event - Fw::LogStringArg eventGreeting(greeting.toChar()); - // Emit the Hello event with the copied string - this->log_ACTIVITY_HI_Hello(eventGreeting); - - this->tlmWrite_GreetingCount(++this->m_greetingCount); - - // Tell the fprime command system that we have completed the processing of the supplied command with OK status - this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); -} -``` -> We must also add the m_greetingCount member variable to the class defined in `HelloWorld.hpp` and the constructor -> defined in `HelloWorld.cpp`. This looks like: -> -> **HelloWorld.hpp: Adding New Member Variable** -> ```c++ -> private: -> U32 m_greetingCount; -> ``` -> **HelloWorld.cpp: Updating Constructor** -> ```c++ -> HelloWorld:: HelloWorld() : -> m_greetingCount(0), -> HelloWorldComponentBase(compName) { -> ``` - -The component should build without errors by running `fprime-util build`. Resolve any errors that occur before -proceeding to the next section. - -## Conclusion - -This tutorial has walked through the creation of component that implements a "Hello World" style greeting behavior for -our F´ system. In the next tutorial, this component will be hooked-up to an F´ deployment and tested! - -**Next:** [Getting Started: Integration and Testing With F´ Deployments](./Deployments.md) diff --git a/docs/Tutorials/HelloWorld/NewProject.md b/docs/Tutorials/HelloWorld/NewProject.md deleted file mode 100644 index ba45857cd9..0000000000 --- a/docs/Tutorials/HelloWorld/NewProject.md +++ /dev/null @@ -1,77 +0,0 @@ -# Getting Started: Creating an F´ Project - -This tutorial will walk new users through creating a new F´ project. - -### Tutorial Steps: -- [Bootstrapping F´](#bootstrapping-f) -- [Creating a New F´ Project](#creating-a-new-f-project) -- [Building the New F´ Project](#building-the-new-f-project) -- [Conclusion](#conclusion) - -## Bootstrapping F´ - -An F´ [project](./Tutorial.md#project) ties to a specific version of tools to work with F´. In order to create -this project and install the correct version of tools, an initial bootstrap version of F´ tools must be installed. This -is accomplished with the following command: - -```bash -pip install fprime-tools -``` - -## Creating a New F´ Project - -Now that to tools are installed a new F´ project should be created. An F´ project internalizes the version of F´ that -the project will build upon and provides the user the basic setup for creating, building, and testing components. - -In order to make a new project, run the following command and answer the questions as indicated below: - -```bash -fprime-util new --project -``` - -This command will ask for some input. Respond with the following answers: -``` -project_name [MyProject]: MyProject -fprime_branch_or_tag [devel]: devel -Select install_venv: -1 - yes -2 - no -Choose from 1, 2 [1]: 1 -``` - -Use the default for anything not specified. This command will take a moment to run. - -The above command creates a new F´ project structure in a folder called `MyProject`, use the `devel` branch of F´ as -the basis for the project, and set up the matching tools in a new Virtual Environment. - -> Experienced F´ users may note that we have not yet created a deployment, but rather just the base project structure. - -## Building the New F´ Project - -The next step is to set up and build the newly created project. This will serve as a build environment for any newly -created components, and will build the F´ framework supplied components. - -```bash -cd MyProject -fprime-util generate -fprime-util build -j4 -``` - -> `fprime-util generate` sets up the build environment for a project/deployment. It only needs to be done once. At the -> end of this tutorial, a new deployment will be created and `fprime-util generate` will also be used then. - -## Conclusion - -A new project has been created with the name `MyProject` and has been placed in a new folder called in `MyProject` in -the current directory. It includes the initial build system setup, and F´ version. It is still empty in that the user -will still need to create components and deployments. - -For the remainder of this Getting Started tutorial we should use the tools installed for our project and issue commands -within this new project's folder. Change into the project directory and load the newly install tools with: - -```bash -cd MyProject -. venv/bin/activate -``` - -**Next:** [Getting Started: Creating an F´ Hello World Component](./HelloWorld.md) diff --git a/docs/Tutorials/HelloWorld/README.md b/docs/Tutorials/HelloWorld/README.md new file mode 100644 index 0000000000..6bf352ed4a --- /dev/null +++ b/docs/Tutorials/HelloWorld/README.md @@ -0,0 +1,3 @@ +## Welcome + +HelloWorld tutorial has been reworked and moved to [fprime-community/fprime-tutorial-hello-world](https://fprime-community.github.io/fprime-tutorial-hello-world/) \ No newline at end of file diff --git a/docs/Tutorials/HelloWorld/Tutorial.md b/docs/Tutorials/HelloWorld/Tutorial.md deleted file mode 100644 index 3c3f952a11..0000000000 --- a/docs/Tutorials/HelloWorld/Tutorial.md +++ /dev/null @@ -1,78 +0,0 @@ -# Getting Started: Introduction and F´ Terminology - -The getting started tutorial is designed to teach new users the basics of F´ usage, instruct existing users on new -command that help in F´ development, and act as the canonical "Hello World" example for F´. - -This tutorial walks through the following steps: -1. [Creating an F´ Project](./NewProject.md) -2. [Creating an F´ Hello World Component](./HelloWorld.md) -3. [Integration and Testing With F´ Deployments](./Deployments.md) - -Once finished, users should have a good understanding of the basic development mechanics for working with F´ and then -could dive deeper into concepts through the [Math Component Tutorial](../MathComponent/Tutorial.md). - -## F´ Terminology - -F´ uses specific terminology to refer to specific parts of the system. This section dives into the basic F´ terminology -used in this tutorial and an explanation of how the terminology is used. - -#### Project - -An F´ project is a collection of files and folders used to work with F´. At its core, a project is just a folder that -can be used to hold F´ code. Projects should specifically exclude the core F´ library to avoid the "clone and own" -problem. Rather projects should link-to a version of F´. - -This tutorial will create a new `MyProject` project used to contain the other things created by the tutorial. - -#### Component - -An F´ component encapsulates a unit of system behavior. Components use ports to communicate with other components and -define commands, events, telemetry channels, and parameters. - -This tutorial will create a new `HelloWorld` component that defines a `SAY_HELLO` command, `Hello` event, and -`GreetingCount` telemetry channel. The component only used built-in ports. It does not use custom ports nor parameters. - -#### Port - -A port is an interface used to communicate between components. This tutorial only uses built-in ports. - -#### Command - -Commands represent actions that a component can execute. Commands can be sent from the ground or via command sequences. -Command behavior is defined in a command handler defined in the component's implementation. - -This tutorial defines one command `SAY_HELLO` with a single argument `greeting`. This command will be sent via the -ground system and will echo the greeting back via the `Hello` event. - -#### Event - -Events represent actions that a component has performed. Events are akin to software log messages. Events are received -and displayed by the ground system. - -This tutorial defines one event `Hello` emitted in response to the `SAY_HELLO` command and containing the same greeting -that the command had. - -#### Telemetry Channel - -Telemetry channels provide the active state of the component. Each channel represents a single item of state that will -be sent to the ground system. - -This tutorial defines a single channel `GreetingCount` that contains the count of the number of `SAY_HELLO` greeting -commands received. - -#### Deployment - -Deployments are a single build of F´ software. Each deployment results in one software executable that can be run along -with other associated files. Each deployment has a topology that defines the system. - -This tutorial will create the `MyDeployment` deployment, run this deployment, and test it through the F´ GDS. - -#### Topology - -Topologies are networks of connected components that define the software. Multiple instances of a component may be added -to the topology. - -This tutorial will use a standard command and data handling topology. A single `HelloWorld` component instance called -`helloWorld` will be added to the standard topology. - -**Next:** [Getting Started: Creating an F´ Project](./NewProject.md) diff --git a/docs/Tutorials/MathComponent/CMakeLists.txt b/docs/Tutorials/MathComponent/CMakeLists.txt deleted file mode 100644 index b9d97bec5b..0000000000 --- a/docs/Tutorials/MathComponent/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -#### -# '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 deleted file mode 100644 index 36f86a667d..0000000000 --- a/docs/Tutorials/MathComponent/MathPorts/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathPorts.fpp" -) - -register_fprime_module() diff --git a/docs/Tutorials/MathComponent/MathPorts/MathPorts.fpp b/docs/Tutorials/MathComponent/MathPorts/MathPorts.fpp deleted file mode 100644 index 0197e7b651..0000000000 --- a/docs/Tutorials/MathComponent/MathPorts/MathPorts.fpp +++ /dev/null @@ -1,15 +0,0 @@ -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/MathReceiver/CMakeLists.txt b/docs/Tutorials/MathComponent/MathReceiver/CMakeLists.txt deleted file mode 100644 index c1126f9b71..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Register the standard build -set(SOURCE_FILES - "${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 deleted file mode 100644 index 50340b3b5e..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// ====================================================================== -// \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 -#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 deleted file mode 100644 index 603bfd7c88..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.fpp +++ /dev/null @@ -1,106 +0,0 @@ -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 0 - - # ---------------------------------------------------------------------- - # Telemetry - # ---------------------------------------------------------------------- - - @ The operation - telemetry OPERATION: MathOp id 0 - - @ Multiplication factor - telemetry FACTOR: F32 id 1 - - } - -} diff --git a/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.hpp b/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.hpp deleted file mode 100644 index c085650274..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/MathReceiver.hpp +++ /dev/null @@ -1,90 +0,0 @@ -// ====================================================================== -// \title MathReceiverImpl.hpp -// \author tcanham, bocchino -// \brief hpp file for MathReceiver component implementation class -// -// \copyright -// Copyright 2009-2021, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef MathReceiver_HPP -#define MathReceiver_HPP - -#include "Ref/MathReceiver/MathReceiverComponentAc.hpp" - -namespace Ref { - - class MathReceiver : - public MathReceiverComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object MathReceiver - //! - 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 - ); - - //! Destroy object MathReceiver - //! - ~MathReceiver(); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for mathOpIn - //! - void mathOpIn_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - F32 val1, - 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 - ); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Command handler implementations - // ---------------------------------------------------------------------- - - //! Implementation for CLEAR_EVENT_THROTTLE command handler - //! Clear the event throttle - void CLEAR_EVENT_THROTTLE_cmdHandler( - const FwOpcodeType opCode, //!< The opcode - const U32 cmdSeq //!< The command sequence number - ); - - void parameterUpdated( - FwPrmIdType id //!< The parameter ID - ); - - }; - -} // end namespace Ref - -#endif diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.cpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.cpp deleted file mode 100644 index 1f3de5edb3..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.cpp +++ /dev/null @@ -1,242 +0,0 @@ -// ====================================================================== -// \title MathReceiver.hpp -// \author tcanham, bocchino -// \brief cpp file for MathReceiver test harness implementation class -// -// \copyright -// 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" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - Tester :: - Tester() : - MathReceiverGTestBase("Tester", MAX_HISTORY_SIZE), - component("MathReceiver") - { - this->initComponents(); - this->connectPorts(); - } - - Tester :: - ~Tester() - { - - } - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - 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); - } - - 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); - } - - void Tester :: - testMul() - { - // 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 :: - testDiv() - { - // Set the factor parameter by loading parameters - const F32 factor = 3.0; - this->paramSet_FACTOR(factor, Fw::ParamValid::VALID); - this->component.loadParameters(); - // Do the operation - this->doMathOp(MathOp::DIV, factor); - } - - 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 - 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 - 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); - - } - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_mathResultOut_handler( - const NATIVE_INT_TYPE portNum, - F32 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); - - } -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.hpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.hpp deleted file mode 100644 index 04b70f36b3..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/Tester.hpp +++ /dev/null @@ -1,136 +0,0 @@ -// ====================================================================== -// \title MathReceiver/test/ut/Tester.hpp -// \author tcanham, bocchino -// \brief hpp file for MathReceiver test harness implementation class -// -// \copyright -// Copyright 2009-2021, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef TESTER_HPP -#define TESTER_HPP - -#include "GTestBase.hpp" -#include "Ref/MathReceiver/MathReceiver.hpp" - -namespace Ref { - - class Tester : - public MathReceiverGTestBase - { - public: - // Maximum size of histories storing events, telemetry, and port outputs - static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10; - // Instance ID supplied to the component instance under test - static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; - // Queue depth supplied to component instance under test - static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; - - private: - - // ---------------------------------------------------------------------- - // Types - // ---------------------------------------------------------------------- - - enum class ThrottleState { - THROTTLED, - NOT_THROTTLED - }; - - public: - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - //! Construct object Tester - //! - Tester(); - - //! Destroy object Tester - //! - ~Tester(); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! To do - //! - void testAdd(); - void testSub(); - void testMul(); - void testDiv(); - void testThrottle(); - - private: - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_mathResultOut - //! - void from_mathResultOut_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - F32 result //!< the result of the operation - ); - - private: - - // ---------------------------------------------------------------------- - // 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(); - - //! Initialize components - //! - void initComponents(); - - private: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - MathReceiver component; - - }; - -} // end namespace Ref - -#endif diff --git a/docs/Tutorials/MathComponent/MathReceiver/test/ut/main.cpp b/docs/Tutorials/MathComponent/MathReceiver/test/ut/main.cpp deleted file mode 100644 index 8b840a94fa..0000000000 --- a/docs/Tutorials/MathComponent/MathReceiver/test/ut/main.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// ---------------------------------------------------------------------- -// Main.cpp -// ---------------------------------------------------------------------- - -#include "STest/Random/Random.hpp" -#include "Tester.hpp" - -TEST(Nominal, Add) { - Ref::Tester tester; - tester.testAdd(); -} - -TEST(Nominal, Sub) { - Ref::Tester tester; - tester.testSub(); -} - -TEST(Nominal, Mul) { - Ref::Tester tester; - tester.testMul(); -} - -TEST(Nominal, Div) { - Ref::Tester tester; - 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 deleted file mode 100644 index 5f3ff699f8..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Register the standard build -set(SOURCE_FILES - "${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 deleted file mode 100644 index ad839ed6d2..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/MathSender.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// ====================================================================== -// \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 - -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 deleted file mode 100644 index 869f69f4c1..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/MathSender.fpp +++ /dev/null @@ -1,90 +0,0 @@ -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/MathSender.hpp b/docs/Tutorials/MathComponent/MathSender/MathSender.hpp deleted file mode 100644 index 874818e0b5..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/MathSender.hpp +++ /dev/null @@ -1,80 +0,0 @@ -// ====================================================================== -// \title MathSenderImpl.hpp -// \author tcanham, bocchino -// \brief hpp file for MathSender component implementation class -// -// \copyright -// Copyright 2009-2021, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef Ref_MathSender_HPP -#define Ref_MathSender_HPP - -#include "Ref/MathSender/MathSenderComponentAc.hpp" - -namespace Ref { - - class MathSender : - public MathSenderComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object MathSender - //! - 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 - ); - - //! Destroy object MathSender - //! - ~MathSender(); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for mathResultIn - //! - void mathResultIn_handler( - const NATIVE_INT_TYPE portNum, //!< The port number - F32 result //!< the result of the operation - ); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Command handler implementations - // ---------------------------------------------------------------------- - - //! Implementation for DO_MATH command handler - //! Do a math operation - 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 - -#endif diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.cpp b/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.cpp deleted file mode 100644 index be15213201..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/Tester.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// ====================================================================== -// \title MathSender.hpp -// \author tcanham, bocchino -// \brief cpp file for MathSender test harness implementation class -// -// \copyright -// 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 -#define QUEUE_DEPTH 10 - -namespace Ref { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - Tester :: - Tester() : - MathSenderGTestBase("Tester", MAX_HISTORY_SIZE), - component("MathSender") - { - this->initComponents(); - this->connectPorts(); - } - - Tester :: - ~Tester() - { - - } - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - F32 Tester :: - pickF32Value() - { - const F32 m = 10e6; - return m * (1.0 - 2 * STest::Pick::inUnitInterval()); - } - - void Tester :: - testAddCommand() - { - this->testDoMath(MathOp::ADD); - } - - void Tester :: - testSubCommand() - { - this->testDoMath(MathOp::SUB); - } - - void Tester :: - testMulCommand() - { - this->testDoMath(MathOp::MUL); - } - - void Tester :: - testDivCommand() - { - 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 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); - } - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_mathOpOut_handler( - const NATIVE_INT_TYPE portNum, - F32 val1, - const MathOp& op, - F32 val2 - ) - { - 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 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); - - } -} // end namespace Ref diff --git a/docs/Tutorials/MathComponent/MathSender/test/ut/main.cpp b/docs/Tutorials/MathComponent/MathSender/test/ut/main.cpp deleted file mode 100644 index 7fe0415d25..0000000000 --- a/docs/Tutorials/MathComponent/MathSender/test/ut/main.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// ---------------------------------------------------------------------- -// Main.cpp -// ---------------------------------------------------------------------- - -#include "STest/Random/Random.hpp" -#include "Tester.hpp" - -TEST(Nominal, AddCommand) { - Ref::Tester tester; - tester.testAddCommand(); -} - -TEST(Nominal, SubCommand) { - Ref::Tester tester; - tester.testSubCommand(); -} - -TEST(Nominal, MulCommand) { - Ref::Tester tester; - tester.testMulCommand(); -} - -TEST(Nominal, DivCommand) { - Ref::Tester tester; - tester.testDivCommand(); -} - -TEST(Nominal, Result) { - Ref::Tester tester; - 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 deleted file mode 100644 index 2fc3269205..0000000000 --- a/docs/Tutorials/MathComponent/MathTypes/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathTypes.fpp" -) - -register_fprime_module() diff --git a/docs/Tutorials/MathComponent/MathTypes/MathTypes.fpp b/docs/Tutorials/MathComponent/MathTypes/MathTypes.fpp deleted file mode 100644 index 32085c868a..0000000000 --- a/docs/Tutorials/MathComponent/MathTypes/MathTypes.fpp +++ /dev/null @@ -1,11 +0,0 @@ -module Ref { - - @ A math operation - enum MathOp { - ADD @< Addition - SUB @< Subtraction - MUL @< Multiplication - DIV @< Division - } - -} diff --git a/docs/Tutorials/MathComponent/README.md b/docs/Tutorials/MathComponent/README.md new file mode 100644 index 0000000000..9abda83483 --- /dev/null +++ b/docs/Tutorials/MathComponent/README.md @@ -0,0 +1,3 @@ +## Welcome + +The MathComponent tutorial has been reworked and moved to [fprime-community/fprime-tutorial-math-component](https://fprime-community.github.io/fprime-tutorial-math-component/) \ No newline at end of file diff --git a/docs/Tutorials/MathComponent/Top/instances.fpp b/docs/Tutorials/MathComponent/Top/instances.fpp deleted file mode 100644 index efd36a3ceb..0000000000 --- a/docs/Tutorials/MathComponent/Top/instances.fpp +++ /dev/null @@ -1,369 +0,0 @@ -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_INT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - rateGroup1Comp.configure( - 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_INT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - rateGroup2Comp.configure( - 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_INT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - rateGroup3Comp.configure( - 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.configComponents """ - rateGroupDriverComp.configure( - 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 deleted file mode 100644 index c6ab2274aa..0000000000 --- a/docs/Tutorials/MathComponent/Top/topology.fpp +++ /dev/null @@ -1,160 +0,0 @@ -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.md b/docs/Tutorials/MathComponent/Tutorial.md deleted file mode 100644 index e6c9e3004f..0000000000 --- a/docs/Tutorials/MathComponent/Tutorial.md +++ /dev/null @@ -1,2320 +0,0 @@ -# F' Math Component Tutorial - -## Table of Contents - -* 1. Introduction -* 2. The MathOp Type - * 2.1. Construct the FPP Model - * 2.2. Add the Model to the Project - * 2.3. Build the Model - * 2.4. Reference Implementation -* 3. The MathOp and MathResult Ports - * 3.1. Construct the FPP Model - * 3.2. Add the Model to the Project - * 3.3. Build the Model - * 3.4. Reference Implementation -* 4. The MathSender Component - * 4.1. Construct the FPP Model - * 4.2. Add the Model to the Project - * 4.3. Build the Stub Implementation - * 4.4. Complete the Implementation - * 4.5. Write and Run Unit Tests - * 4.5.1. Set Up the Unit Test Environment - * 4.5.2. Write and Run One Test - * 4.5.3. Write and Run More Tests - * 4.5.4. Exercise: Random Testing - * 4.6. Reference Implementation -* 5. The MathReceiver Component - * 5.1. Construct the FPP Model - * 5.2. Add the Model to the Project - * 5.3. Build the Stub Implementation - * 5.4. Complete the Implementation - * 5.5. Write and Run Unit Tests - * 5.5.1. Set up the Unit Test Environment - * 5.5.2. Add Helper Code - * 5.5.3. Write and Run Tests - * 5.6. Reference Implementation - * 5.7. Exercises - * 5.7.1. Adding Telemetry - * 5.7.2. Error Handling -* 6. Updating the Ref Deployment - * 6.1. Defining the Component Instances - * 6.2. Updating the Topology - * 6.3. Building the Ref Deployment - * 6.4. Visualizing the Ref Topology - * 6.5. Reference Implementation -* 7. Running the Ref Deployment - * 7.1. Sending a Command - * 7.2. Checking Events - * 7.3. Checking Telemetry - * 7.4. Setting Parameters - * 7.5. Saving Parameters - * 7.6. GDS Logs -* 8. Conclusion - - -## 1. Introduction - -This tutorial shows how to develop, test, and deploy a simple topology -consisting of two components: - -1. `MathSender`: A component that receives commands and forwards work to - `MathReceiver`. - -1. `MathReceiver`: A component that carries out arithmetic operations and - returns the results to `MathSender`. - -See the diagram below. - - -![A simple topology for arithmetic computation](png/top.png) - -**What is covered:** The tutorial covers the following concepts: - -1. Using the [FPP modeling language](https://fprime-community.github.io/fpp) to - specify the types and ports used by the components. - -1. Using the F Prime build system to build the types and ports. - -1. Developing the `MathSender` component: Specifying the component, building - the component, completing the C++ component implementation, and writing - component unit tests. - -1. Developing the `MathReceiver` component. - -1. Adding the new components and connections to the F Prime `Ref` application. - -1. Using the F Prime Ground Data System (GDS) to run the updated `Ref` - application. - -**Prerequisites:** This tutorial assumes the following: - -1. Basic knowledge of Unix: How to navigate in a shell and execute programs. - -1. Basic knowledge of git: How to create a branch. - -1. Basic knowledge of C++, 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 [F Prime git repository](https://github.com/nasa/fprime). -You may also wish to work through the Getting Started tutorial at -`docs/GettingStarted/Tutorial.md`. - -**Version control:** -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: - -```bash -git checkout -b math-tutorial -``` - -If you wish, you can save your work by committing to this branch. - - -## 2. 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: - -1. Construct the FPP model. - -1. Add the model to the project. - -1. Build the model. - - -### 2.1. 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: - -```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 [_The FPP User's -Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Enums). - -The enum `MathTypes` resides in an FPP module `Ref`. - -An FPP module is like a C++ namespace: it encloses several definitions, each of -which is qualified with the name of the module. -For more information on FPP modules, see [_The FPP User's -Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Modules). - -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 [_The FPP User's -Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Writing-Comments-and-Annotations). - - - -### 2.2. Add the Model to the Project - -**Create Ref/MathTypes/CMakeLists.txt:** -Create a file `Ref/MathTypes/CMakeLists.txt` with the following contents: - -```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: - -```cmake -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathTypes/") -``` - - - -### 2.3. Build the Model - -**Run the build:** -Do the following: - -1. Go to the directory `Ref/MathTypes`. - -1. If you have not already run `fprime-util generate`, then do so now. - -1. 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 -reference implementation. - -**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: - -```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 C++ files -corresponding to the `MathOp` enum. -You may wish to study the file `MathOpEnumAc.hpp`. -This file gives the interface to the C++ class `Ref::MathOp`. -All enum types have a similar auto-generated class -interface. - - - -### 2.4. 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: - -1. Go to the `Ref` directory. - -1. Run `cp -R ../docs/Tutorials/MathComponent/MathTypes .` - -1. Update `Ref/CMakeLists.txt` as stated above. - -1. Follow the steps for building the model. - -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`. - - - -## 3. 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. - - -### 3.1. 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: - -```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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Ports). - - -### 3.2. Add the Model to the Project - -Add add the model -`Ref/MathPorts/MathPorts.fpp` to the `Ref` project. -Carry out the steps in the -previous section, after -substituting `MathPorts` for `MathTypes`. - - -### 3.3. Build the Model - -Carry out the steps in the -previous section, -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 C++ -files end in `PortAc.hpp` and `PortAc.cpp`. -You can look at this code if you wish. -However, the auto-generated C++ port files are used -by the autocoded component implementations (described below); -you won't ever program directly against their interfaces. - - -### 3.4. Reference Implementation - -A reference implementation for this section is available at -`docs/Tutorials/MathComponent/MathPorts`. -To build this implementation, follow the steps -described for `MathTypes`. - - - -## 4. The MathSender Component - -Now we can build and test the `MathSender` component. -There are five steps: - -1. Construct the FPP model. -1. Add the model to the project. -1. Build the stub implementation. -1. Complete the implementation. -1. Write and run unit tests. - - -### 4.1. 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: - -```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: - -1. **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 above. -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. - -1. **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. - -1. **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. - -1. **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. - -1. **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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components). - - - -### 4.2. Add the Model to the Project - -**Create Ref/MathSender/CMakeLists.txt:** -Create a file `Ref/MathSender/CMakeLists.txt` with the following contents: - -```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 `Ref/MathTypes`. - - - -### 4.3. Build the Stub Implementation - -**Run the build:** -Go into the directory `Ref/MathSender`. -Run the following commands: - -```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: -`MathSender.cpp-template` and -`MathSender.hpp-template`. - -Run the following commands: - -```bash -mv MathSender.cpp-template MathSender.cpp -mv MathSender.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. - - -### 4.4. 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: - -```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: - -```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: - -1. Emit telemetry and events. - -1. Invoke the `mathOpOut` port to request that `MathReceiver` -perform the operation. - -1. 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: - -```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: - -```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`. - - - -### 4.5. 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: - -1. Set up the unit test environment - -1. Write and run one unit test - -1. Write and run additional unit tests - - - -#### 4.5.1. Set Up the Unit Test Environment - -**Create the stub Tester class:** -In the directory `Ref/MathSender`, run `mkdir -p test/ut`. -This will create the directory where -the unit tests will reside. - -**Update Ref/MathSender/CMakeLists.txt:** -Go back to the directory `Ref/MathSender`. -Add the following lines to `CMakeLists.txt`: - -```cmake -# Register the unit test build -set(UT_SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" -) -set(UT_AUTO_HELPERS ON) -register_fprime_ut() -``` - -**Generate the unit test stub:** -We will now generate a stub implementation of the unit tests. -This stub contains all the boilerplate necessary to write and -run unit tests against the `MathSender` component. -In a later step, we will fill in the stub with tests. - -1. 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. - -1. Run the command `fprime-util impl --ut`. - It should generate files `Tester.cpp`, `Tester.hpp`, and `TestMain.cpp`. - -1. Move these files to the `test/ut` directory: - - ```bash - mv Tester.* TestMain.cpp test/ut - ``` - -**Update Ref/MathSender/CMakeLists.txt:** -Open `MathSender/CMakeLists.txt` and update the definition of -`UT_SOURCE_FILES` by adding your new test files: - -```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" -) -set(UT_AUTO_HELPERS ON) -register_fprime_ut() -``` - -**Run the build:** -Now we can check that the unit test build is working. -Run `fprime-util build --ut`. -Everything should build without errors. - -**Inspect the generated code:** -The unit test build generates some code to support unit testing. -The code is located at `Ref/build-fprime-automatic-native-ut/Ref/MathSender`. -This directory contains two auto-generated classes: - -1. `MathSenderGTestBase`: This is the direct base -class of `Tester`. -It provides a test interface implemented with Google Test -macros. - -1. `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. - - -#### 4.5.2. 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: - -1. 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. - -1. In the `Tester` class, write a test function that -calls the helper to run a test. - -1. In the `main` function, write a Google Test macro -that invokes the test function. - -1. 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": - -```c++ -//! Test a DO_MATH command -void testDoMath(MathOp op); -``` - -In the file `Tester.cpp`, add the corresponding -function body: - -```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 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: - -1. 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. - -1. 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": - -```c++ -//! Test an ADD command -void testAddCommand(); -``` - -In `Tester.cpp`, add the corresponding function -body: - -```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: - -```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: - -1. Change the behavior of the component -so that it does something incorrect. -For example, try adding one to a telemetry -value before emitting it. - -1. Rerun the test and observe what happens. - - -#### 4.5.3. 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`. - -1. Add the following function signature in the "Tests" section of `Tester.hpp`: - - ```c++ - //! Test receipt of a result - void testResult(); - ``` - -1. Add the corresponding function body in `Tester.cpp`: - - ```c++ - 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. - -1. Add the following test macro to `main.cpp`: - - ```c++ - TEST(Nominal, Result) { - Ref::Tester tester; - tester.testResult(); - } - ``` - -1. Run the tests. -Again you can try altering something in the component code -to see what effect it has on the test output. - - - -#### 4.5.4. 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: - -1. Add `#include "STest/Pick/Pick.hpp"` to `Tester.cpp`. - -1. Add the following - line to `Ref/MathSender/CMakeLists.txt`, before `register_fprime_ut`: - - ```cmake - set(UT_MOD_DEPS STest) - ``` - - This line tells the build system to make the unit test build - depend on the `STest` build module. - -1. Add `#include "STest/Random/Random.hpp"` to `main.cpp`. - -1. Add the following line to the `main` function of `main.cpp`, - just before the return statement: - - ```c++ - 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: - -1. Copy the last value _S_ of `seed-history` into `seed`. - -1. In `Ref/MathSender`, re-run the unit tests a few times. - -1. 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`). - - -### 4.6. Reference Implementation - -A reference implementation for this section is available at -`docs/Tutorials/MathComponent/MathSender`. - - -## 5. The MathReceiver Component - -Now we will build and test the `MathReceiver` component. -We will use the same five steps as for the -`MathSender` component. - - -### 5.1. 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: - -```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 0 - - # ---------------------------------------------------------------------- - # 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: - -1. **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. - -1. **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. - -1. **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_. - -1. **Events:** There are three event reports: - - 1. `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). - - 1. `OPERATION_PERFORMED`: Emitted when this component - performs a math operation. - - 1. `THROTTLE_CLEARED`: Emitted when the event throttling - is cleared. - -1. **Commands:** There is one command for clearing -the event throttle. - -1. **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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components). - - -### 5.2. Add the Model to the Project - -Follow the steps given for the -`MathSender` component. - - -### 5.3. Build the Stub Implementation - -Follow the same steps as for the -`MathSender` component. - - -### 5.4. Complete the Implementation - -**Fill in the mathOpIn handler:** -In `MathReceiver.cpp`, complete the implementation of -`mathOpIn_handler` so that it looks like this: - -```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: - -1. Compute an initial result based on the input values and -the requested operation. - -1. Get the value of the factor parameter. -Check that the value is a valid value from the parameter -database or a default parameter value. - -1. Multiply the initial result by the factor to generate -the final result. - -1. Emit telemetry and events. - -1. Emit the result. - -Note that in step 1, `op` is an enum (a C++ 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: - -```c++ -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: - -```c++ -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`. - -```c++ -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: - -1. 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. - -1. Otherwise fail an assertion. -This code should never run, because there are no other -parameters. - - -### 5.5. Write and Run Unit Tests - - -#### 5.5.1. Set up the Unit Test Environment - -1. Follow the steps given for the -`MathSender` component. - -1. Follow the steps given under **Modifying the code** -for the -random testing exercise, -so that you can use STest to pick random values. - - -#### 5.5.2. Add Helper Code - -**Add a ThrottleState enum class:** -Add the following code to the beginning of the -`Tester` class in `Tester.hpp`: - -```c++ -private: - - // ---------------------------------------------------------------------- - // Types - // ---------------------------------------------------------------------- - - enum class ThrottleState { - THROTTLED, - NOT_THROTTLED - }; -``` - -This code defines a C++ 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. - -```c++ -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. - -```c++ -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: - -1. Clear the test history. - -1. Send a command to the component to set the `FACTOR` parameter -to the value `factor`. - -1. 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`. - -```c++ -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`. - -```c++ -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`. - - -#### 5.5.3. 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`: - -```c++ -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`: - -```c++ -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: - -1. 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. - -1. 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 constant definition to the top of the `Tester.cpp` file: - -```C++ -#define CMD_SEQ 42 -``` - -Then add the following function to the "Tests" section of `Tester.cpp`: - -```c++ -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(TEST_INSTANCE_ID, 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. - - -### 5.6. Reference Implementation - -A reference implementation for this section is available at -`docs/Tutorials/MathComponent/MathReceiver`. - - -### 5.7. Exercises - - -#### 5.7.1. Adding Telemetry - -Add a telemetry channel that records the number of math -operations performed. - -1. Add the channel to the FPP model. - -1. In the component implementation class, add a member -variable `numMathOps` of type `U32`. -Initialize the variable to zero in the class constructor. - -1. Revise the `mathOpIn` handler so that it increments -`numMathOps` and emits the updated value as telemetry. - -1. Revise the unit tests to cover the new behavior. - - -#### 5.7.2. 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: - -1. 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`. - -1. Should the error be caught in `MathSender` or `MathReceiver`? - -1. 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? - -1. 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. - - -## 6. 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. - - -### 6.1. 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: - -```fpp -instance mathSender: Ref.MathSender base id 0xE00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - 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: - -```fpp -instance mathReceiver: Ref.MathReceiver base id 0x2700 \ - queue size Default.QUEUE_SIZE -``` - -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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Component-Instances). - - -### 6.2. 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: - -```fpp -instance mathSender -instance mathReceiver -``` - -These lines add the `mathSender` and `mathReceiver` -instances to the topology. - -**Packetize the telemetry channels:** -Open the file `RefPackets.xml`. At the bottom, right before ``, add the following lines: -``` - - - - - - - - - - - -``` - -These lines describe the packet definitions for the `mathSender` and `mathReceiver` telemetry channels. - -**Check for unconnected ports:** -Run the following commands in the `Ref/Top` directory: - -```bash -fprime-util fpp-check -u unconnected.txt -cat unconnected.txt -``` - -You should 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. -After the last entry for the `rateGroup1Comp` (rate group 1) add -the following line: - -```fpp -rateGroup1Comp.RateGroupMemberOut -> mathReceiver.schedIn -``` - -This line adds the connection that drives the `schedIn` -port of the `mathReceiver` component instance. - -**Re-run the check for unconnected ports:** -You should 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: - -```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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Topologies). - - -### 6.3. 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`. - - -### 6.4. 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 now: -clone [this repository](https://github.com/fprime-community/fprime-layout) -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. - -```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 [this repository](https://github.com/fprime-community/fprime-visual) -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. - -```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 the -topology diagram shown above. - -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. - - -### 6.5. 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`. - - -## 7. 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. - - -### 7.1. 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: - -1. A text box for entering `val1`. - -1. A menu for entering `op`. - -1. 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. - - -### 7.2. 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. - - -### 7.3. 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. - - -### 7.4. 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. - - -### 7.5. 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: - -1. 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. - -1. 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. - - -### 7.6. 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. - - -## 8. Conclusion - -The Math Component tutorial has shown us how to create simple types, ports and -components for our application using the FPP modeling language. We have learned -how to use `fprime-util` to generate implementation stubs, the build cache, and -unit tests. We learned how to define our topology and use tools provided by -F´ to check and visualize the topology. Lastly, we learned how to use the -ground system to interact with our deployment. - -The user is now directed back to the [Tutorials](../README.md) for further -reading or to the [Cross-Compilation Tutorial](../CrossCompilation/Tutorial.md) -for instructions on how to cross-compile the Ref application completed in this -tutorial for the Raspberry Pi. diff --git a/docs/Tutorials/MathComponent/json/refresh b/docs/Tutorials/MathComponent/json/refresh deleted file mode 100755 index c39ab771af..0000000000 --- a/docs/Tutorials/MathComponent/json/refresh +++ /dev/null @@ -1,3 +0,0 @@ -#!/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 deleted file mode 100644 index dccf0d9750..0000000000 --- a/docs/Tutorials/MathComponent/json/top.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "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 deleted file mode 100644 index 69d31efece..0000000000 --- a/docs/Tutorials/MathComponent/json/top.txt +++ /dev/null @@ -1,13 +0,0 @@ -mathSender -mathOpOut -0 -mathReceiver -mathOpIn -0 - -mathReceiver -mathResultOut -0 -mathSender -mathResultIn -0 diff --git a/docs/Tutorials/MathComponent/md/.gitignore b/docs/Tutorials/MathComponent/md/.gitignore deleted file mode 100644 index 5e2df058f8..0000000000 --- a/docs/Tutorials/MathComponent/md/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -defined-tags.txt -toc.md -used-tags.txt diff --git a/docs/Tutorials/MathComponent/md/Tutorial.md b/docs/Tutorials/MathComponent/md/Tutorial.md deleted file mode 100644 index ee15a6d52e..0000000000 --- a/docs/Tutorials/MathComponent/md/Tutorial.md +++ /dev/null @@ -1,1983 +0,0 @@ -# F' Math Component Tutorial - -!include toc.md - -## Introduction - -This tutorial shows how to develop, test, and deploy a simple topology -consisting of two components: - -1. `MathSender`: A component that receives commands and forwards work to - `MathReceiver`. - -1. `MathReceiver`: A component that carries out arithmetic operations and - returns the results to `MathSender`. - -See the diagram below. - - -![A simple topology for arithmetic computation](png/top.png) - -**What is covered:** The tutorial covers the following concepts: - -1. Using the [FPP modeling language](https://fprime-community.github.io/fpp) to - specify the types and ports used by the components. - -1. Using the F Prime build system to build the types and ports. - -1. Developing the `MathSender` component: Specifying the component, building - the component, completing the C++ component implementation, and writing - component unit tests. - -1. Developing the `MathReceiver` component. - -1. Adding the new components and connections to the F Prime `Ref` application. - -1. Using the F Prime Ground Data System (GDS) to run the updated `Ref` - application. - -**Prerequisites:** This tutorial assumes the following: - -1. Basic knowledge of Unix: How to navigate in a shell and execute programs. - -1. Basic knowledge of git: How to create a branch. - -1. Basic knowledge of C++, 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 [F Prime git repository](https://github.com/nasa/fprime). -You may also wish to work through the Getting Started tutorial at -`docs/GettingStarted/Tutorial.md`. - -**Version control:** -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: - -```bash -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: - -1. Construct the FPP model. - -1. Add the model to the project. - -1. 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: - -```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 [_The FPP User's -Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Enums). - -The enum `MathTypes` resides in an FPP module `Ref`. - -An FPP module is like a C++ namespace: it encloses several definitions, each of -which is qualified with the name of the module. -For more information on FPP modules, see [_The FPP User's -Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Modules). - -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 [_The FPP User's -Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Writing-Comments-and-Annotations). - - -### Add the Model to the Project - -**Create Ref/MathTypes/CMakeLists.txt:** -Create a file `Ref/MathTypes/CMakeLists.txt` with the following contents: - -```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: - -```cmake -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathTypes/") -``` - - -### Build the Model - -**Run the build:** -Do the following: - -1. Go to the directory `Ref/MathTypes`. - -1. If you have not already run `fprime-util generate`, then do so now. - -1. 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 -reference implementation. - -**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: - -```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 C++ files -corresponding to the `MathOp` enum. -You may wish to study the file `MathOpEnumAc.hpp`. -This file gives the interface to the C++ class `Ref::MathOp`. -All enum types have a similar auto-generated class -interface. - - -### 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: - -1. Go to the `Ref` directory. - -1. Run `cp -R ../docs/Tutorials/MathComponent/MathTypes .` - -1. Update `Ref/CMakeLists.txt` as stated above. - -1. Follow the steps for building the model. - -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`. - - -## 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: - -```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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Ports). - -### Add the Model to the Project - -Add add the model -`Ref/MathPorts/MathPorts.fpp` to the `Ref` project. -Carry out the steps in the -previous section, after -substituting `MathPorts` for `MathTypes`. - -### Build the Model - -Carry out the steps in the -previous section, -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 C++ -files end in `PortAc.hpp` and `PortAc.cpp`. -You can look at this code if you wish. -However, the auto-generated C++ 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 `MathTypes`. - - -## The MathSender Component - -Now we can build and test the `MathSender` component. -There are five steps: - -1. Construct the FPP model. -1. Add the model to the project. -1. Build the stub implementation. -1. Complete the implementation. -1. 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: - -```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: - -1. **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 above. -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. - -1. **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. - -1. **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. - -1. **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. - -1. **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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components). - - -### Add the Model to the Project - -**Create Ref/MathSender/CMakeLists.txt:** -Create a file `Ref/MathSender/CMakeLists.txt` with the following contents: - -```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 `Ref/MathTypes`. - - -### Build the Stub Implementation - -**Run the build:** -Go into the directory `Ref/MathSender`. -Run the following commands: - -```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: -`MathSender.cpp-template` and -`MathSender.hpp-template`. - -Run the following commands: - -```bash -mv MathSender.cpp-template MathSender.cpp -mv MathSender.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: - -```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: - -```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: - -1. Emit telemetry and events. - -1. Invoke the `mathOpOut` port to request that `MathReceiver` -perform the operation. - -1. 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: - -```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: - -```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`. - - -### 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: - -1. Set up the unit test environment - -1. Write and run one unit test - -1. Write and run additional unit tests - - -#### Set Up the Unit Test Environment - -**Create the stub Tester class:** -In the directory `Ref/MathSender`, run `mkdir -p test/ut`. -This will create the directory where -the unit tests will reside. - -**Update Ref/MathSender/CMakeLists.txt:** -Go back to the directory `Ref/MathSender`. -Add the following lines to `CMakeLists.txt`: - -```cmake -# Register the unit test build -set(UT_SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/MathSender.fpp" -) -register_fprime_ut() -``` - -**Generate the unit test stub:** -We will now generate a stub implementation of the unit tests. -This stub contains all the boilerplate necessary to write and -run unit tests against the `MathSender` component. -In a later step, we will fill in the stub with tests. - -1. 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. - -1. Run the command `fprime-util impl --ut`. - It should generate files `Tester.cpp`, `Tester.hpp`, and `TestMain.cpp`. - -1. Move these files to the `test/ut` directory: - - ```bash - mv Tester.* TestMain.cpp test/ut - ``` - -**Update Ref/MathSender/CMakeLists.txt:** -Open `MathSender/CMakeLists.txt` and update the definition of -`UT_SOURCE_FILES` by adding your new test files: - -```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() -``` - -**Run the build:** -Now we can check that the unit test build is working. -Run `fprime-util build --ut`. -Everything should build without errors. - -**Inspect the generated code:** -The unit test build generates some code to support unit testing. -The code is located at `Ref/build-fprime-automatic-native-ut/Ref/MathSender`. -This directory contains two auto-generated classes: - -1. `MathSenderGTestBase`: This is the direct base -class of `Tester`. -It provides a test interface implemented with Google Test -macros. - -1. `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: - -1. 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. - -1. In the `Tester` class, write a test function that -calls the helper to run a test. - -1. In the `main` function, write a Google Test macro -that invokes the test function. - -1. 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": - -```c++ -//! Test a DO_MATH command -void testDoMath(MathOp op); -``` - -In the file `Tester.cpp`, add the corresponding -function body: - -```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 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: - -1. 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. - -1. 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": - -```c++ -//! Test an ADD command -void testAddCommand(); -``` - -In `Tester.cpp`, add the corresponding function -body: - -```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: - -```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: - -1. Change the behavior of the component -so that it does something incorrect. -For example, try adding one to a telemetry -value before emitting it. - -1. 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`. - -1. Add the following function signature in the "Tests" section of `Tester.hpp`: - - ```c++ - //! Test receipt of a result - void testResult(); - ``` - -1. Add the corresponding function body in `Tester.cpp`: - - ```c++ - 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. - -1. Add the following test macro to `main.cpp`: - - ```c++ - TEST(Nominal, Result) { - Ref::Tester tester; - tester.testResult(); - } - ``` - -1. Run the tests. -Again you can try altering something in the component code -to see what effect it has on the test output. - - -#### 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: - -1. Add `#include "STest/Pick/Pick.hpp"` to `Tester.cpp`. - -1. Add the following - line to `Ref/MathSender/CMakeLists.txt`, before `register_fprime_ut`: - - ```cmake - set(UT_MOD_DEPS STest) - ``` - - This line tells the build system to make the unit test build - depend on the `STest` build module. - -1. Add `#include "STest/Random/Random.hpp"` to `main.cpp`. - -1. Add the following line to the `main` function of `main.cpp`, - just before the return statement: - - ```c++ - 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: - -1. Copy the last value _S_ of `seed-history` into `seed`. - -1. In `Ref/MathSender`, re-run the unit tests a few times. - -1. 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 -`MathSender` component. - -### 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: - -```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: - -1. **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. - -1. **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. - -1. **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_. - -1. **Events:** There are three event reports: - - 1. `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). - - 1. `OPERATION_PERFORMED`: Emitted when this component - performs a math operation. - - 1. `THROTTLE_CLEARED`: Emitted when the event throttling - is cleared. - -1. **Commands:** There is one command for clearing -the event throttle. - -1. **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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Components). - -### Add the Model to the Project - -Follow the steps given for the -`MathSender` component. - -### Build the Stub Implementation - -Follow the same steps as for the -`MathSender` component. - -### Complete the Implementation - -**Fill in the mathOpIn handler:** -In `MathReceiver.cpp`, complete the implementation of -`mathOpIn_handler` so that it looks like this: - -```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: - -1. Compute an initial result based on the input values and -the requested operation. - -1. Get the value of the factor parameter. -Check that the value is a valid value from the parameter -database or a default parameter value. - -1. Multiply the initial result by the factor to generate -the final result. - -1. Emit telemetry and events. - -1. Emit the result. - -Note that in step 1, `op` is an enum (a C++ 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: - -```c++ -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: - -```c++ -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`. - -```c++ -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: - -1. 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. - -1. 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 - -1. Follow the steps given for the -`MathSender` component. - -1. Follow the steps given under **Modifying the code** -for the -random testing exercise, -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`: - -```c++ -private: - - // ---------------------------------------------------------------------- - // Types - // ---------------------------------------------------------------------- - - enum class ThrottleState { - THROTTLED, - NOT_THROTTLED - }; -``` - -This code defines a C++ 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. - -```c++ -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. - -```c++ -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: - -1. Clear the test history. - -1. Send a command to the component to set the `FACTOR` parameter -to the value `factor`. - -1. 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`. - -```c++ -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`. - -```c++ -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`: - -```c++ -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`: - -```c++ -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: - -1. 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. - -1. 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 constant definition to the top of the `Tester.cpp` file: - -```C++ -#define CMD_SEQ 42 -``` - -Then add the following function to the "Tests" section of `Tester.cpp`: - -```c++ -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. - -1. Add the channel to the FPP model. - -1. In the component implementation class, add a member -variable `numMathOps` of type `U32`. -Initialize the variable to zero in the class constructor. - -1. Revise the `mathOpIn` handler so that it increments -`numMathOps` and emits the updated value as telemetry. - -1. 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: - -1. 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`. - -1. Should the error be caught in `MathSender` or `MathReceiver`? - -1. 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? - -1. 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: - -```fpp -instance mathSender: Ref.MathSender base id 0xE00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - 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: - -```fpp -instance mathReceiver: Ref.MathReceiver base id 0x2700 \ - queue size Default.QUEUE_SIZE -``` - -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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Component-Instances). - -### 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: - -```fpp -instance mathSender -instance mathReceiver -``` - -These lines add the `mathSender` and `mathReceiver` -instances to the topology. - -**Check for unconnected ports:** -Run the following commands in the `Ref/Top` directory: - -```bash -fprime-util fpp-check -u unconnected.txt -cat unconnected.txt -``` - -You should 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. -After the last entry for the `rateGroup1Comp` (rate group 1) add -the following line: - -```fpp -rateGroup1Comp.RateGroupMemberOut -> mathReceiver.schedIn -``` - -This line adds the connection that drives the `schedIn` -port of the `mathReceiver` component instance. - -**Re-run the check for unconnected ports:** -You should 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: - -```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 -[_The FPP User's Guide_](https://fprime-community.github.io/fpp/fpp-users-guide.html#Defining-Topologies). - -### 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 now: -clone [this repository](https://github.com/fprime-community/fprime-layout) -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. - -```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 [this repository](https://github.com/fprime-community/fprime-visual) -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. - -```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 the -topology diagram shown above. - -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: - -1. A text box for entering `val1`. - -1. A menu for entering `op`. - -1. 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: - -1. 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. - -1. 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. - -## Conclusion - -The Math Component tutorial has shown us how to create simple types, ports and -components for our application using the FPP modeling language. We have learned -how to use `fprime-util` to generate implementation stubs, the build cache, and -unit tests. We learned how to define our topology and use tools provided by -F´ to check and visualize the topology. Lastly, we learned how to use the -ground system to interact with our deployment. - -The user is now directed back to the [Tutorials](../README.md) for further -reading or to the [Cross-Compilation Tutorial](../CrossCompilation/Tutorial.md) -for instructions on how to cross-compile the Ref application completed in this -tutorial for the Raspberry Pi. diff --git a/docs/Tutorials/MathComponent/md/bad-refs.awk b/docs/Tutorials/MathComponent/md/bad-refs.awk deleted file mode 100644 index 62272e5b27..0000000000 --- a/docs/Tutorials/MathComponent/md/bad-refs.awk +++ /dev/null @@ -1,15 +0,0 @@ -# ---------------------------------------------------------------------- -# Check for refs that are not of the form -# #... (local ref) or http... (internet URL) -# The most common error here is to forget the # at the start of a local ref -# ---------------------------------------------------------------------- - -/&2 - exit 1 -fi - -./defined-tags < $1 > defined-tags.txt -./used-tags < $1 > used-tags.txt -undefined_tags=`./undefined-tags defined-tags.txt used-tags.txt` -if test -n "$undefined_tags" -then - echo "WARNING: References use undefined tags" 1>&2 - echo $undefined_tags | tr ' ' '\n' -fi - -bad_refs=`awk -f bad-refs.awk $1 | tr '\n' ',' | sed s'/,$//'` -if test -n "$bad_refs" -then - echo "WARNING: Malformed references" - echo $bad_refs | tr ',' '\n' -fi diff --git a/docs/Tutorials/MathComponent/md/defined-tags b/docs/Tutorials/MathComponent/md/defined-tags deleted file mode 100755 index 71ac652e42..0000000000 --- a/docs/Tutorials/MathComponent/md/defined-tags +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -e - -awk '/^ toc.md - -# Generate the final Markdown file -cat Tutorial.md | \ - awk -f tags.awk | \ - awk -f sections.awk | \ - awk -f include.awk \ - > ../Tutorial.md - -# Check for broken refs in the final Markdown file -./check-refs ../Tutorial.md diff --git a/docs/Tutorials/MathComponent/md/sections.awk b/docs/Tutorials/MathComponent/md/sections.awk deleted file mode 100644 index 687c333599..0000000000 --- a/docs/Tutorials/MathComponent/md/sections.awk +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env awk -f - -# ---------------------------------------------------------------------- -# sections.awk -# Add hierarchical section numbers to Markdown headers -# ---------------------------------------------------------------------- - -BEGIN { - MAX_LEVELS = 10 - in_code_block = 0 -} - -$1 ~ "^```" { in_code_block = !in_code_block } - -/^##+ / && !in_code_block { - new_level = length($1) - 1 - if (new_level > MAX_LEVELS) { - print "sections.awk: too many levels (" new_level ")" > "/dev/stderr" - exit(1) - } - ++levels[new_level] - for (i = new_level + 1; i <= MAX_LEVELS; ++i) - levels[i] = 0 - printf("%s ", $1) - for (i = 1; i <= new_level; ++i) { - printf("%d.", levels[i]) - } - line = $0 - sub(/^#+ +/, "", line) - printf(" %s\n", line) - next -} - -{ print } diff --git a/docs/Tutorials/MathComponent/md/tags.awk b/docs/Tutorials/MathComponent/md/tags.awk deleted file mode 100644 index 018cf22d86..0000000000 --- a/docs/Tutorials/MathComponent/md/tags.awk +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env awk -f - -# ---------------------------------------------------------------------- -# tags.awk -# Insert anchor tags for Markdown sections -# ---------------------------------------------------------------------- - -BEGIN { - level = 0 - in_code_block = 0 -} - -$1 ~ /^```/ && in_code_block == 0 { in_code_block = 1; print; next } -$1 ~ /^```/ && in_code_block == 1 { in_code_block = 0; print; next } - -$1 ~ /^##+$/ && !in_code_block { - level = length($1) - level_tag = "" - for (i = 2; i <= NF; ++i) { - if (level_tag == "") - level_tag = $i - else - level_tag = level_tag "-" $i - } - gsub(/[,:]/, "", level_tag) - level_tags[level] = level_tag - tag = "" - for (i = 1; i <= level; ++i) { - if (tag == "") - tag = level_tags[i] - else - tag = tag "_" level_tags[i] - } - print "" -} - -{ print $0 } diff --git a/docs/Tutorials/MathComponent/md/toc.awk b/docs/Tutorials/MathComponent/md/toc.awk deleted file mode 100644 index 50f5e04f0e..0000000000 --- a/docs/Tutorials/MathComponent/md/toc.awk +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env awk -f - -# ---------------------------------------------------------------------- -# toc.awk -# Generate table of contents -# Must generate tags first -# ---------------------------------------------------------------------- - -BEGIN { - in_code_block = 0 - print "## Table of Contents" - print "" -} - -$1 ~ "^```" { in_code_block = !in_code_block } - -/^##+ / && !in_code_block { - indent_level = length($1) - 2 - tag = prev_line - sub(/^[^"]*"/, "", tag) - sub(/"[^"]*$/, "", tag) - header = $0 - sub(/^#* */, "", header) - for (i = 1; i <= indent_level; ++i) - printf(" ") - print "* " header "" -} - -{ - prev_line = $0 -} diff --git a/docs/Tutorials/MathComponent/md/undefined-tags b/docs/Tutorials/MathComponent/md/undefined-tags deleted file mode 100755 index e1a401eccf..0000000000 --- a/docs/Tutorials/MathComponent/md/undefined-tags +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -e - -if ! test $# -eq 2 -then - echo 'usage: undefined-tags defined-tags used-tags' 1>&2 - exit 1 -fi - -diff -u $1 $2 | grep '^+' | grep -v '++' | sed 's/^\+//' diff --git a/docs/Tutorials/MathComponent/md/used-tags b/docs/Tutorials/MathComponent/md/used-tags deleted file mode 100755 index 98cf79c0ef..0000000000 --- a/docs/Tutorials/MathComponent/md/used-tags +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -e - -awk '/ This tutorial can be run without hardware with the exception of section 6 "Running on Hardware". + +1. [Project Setup](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/project-setup.md) +2. [Component Design and Initial Implementation](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/component-implementation-1.md) +3. [Initial Component Integration](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/initial-integration.md) +4. [Continuing Component Implementation](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/component-implementation-2.md) +5. [Full System Integration](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/full-integration.md) +6. [Running on Hardware](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/running-on-hardware.md) +7. [Unit-Testing](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/unit-testing.md) +8. [System Testing](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/docs/system-testing.md) + + +## [MathComponent](https://fprime-community.github.io/fprime-tutorial-math-component/): Custom Ports and Types + +The MathComponent tutorial walks users through constructing a full F´ application including custom Ports, and Enumeration data types. Events, Telemetry, Commands, and Parameters are covered as well. Unit-Testing is also covered. diff --git a/docs/UsersGuide/gds/gds-cli.md b/docs/UsersGuide/gds/gds-cli.md index 97a2ad9fda..82591934d9 100644 --- a/docs/UsersGuide/gds/gds-cli.md +++ b/docs/UsersGuide/gds/gds-cli.md @@ -84,44 +84,68 @@ learn more about each one, you can include the `-h` or `--help` flag after the c ```bash $ fprime-cli events --help -usage: fprime-cli events [-h] [-d DICTIONARY] [-ip IP] [-p PORT] [-t SECONDS] - [-l] [-i ID [ID ...]] [-c COMP [COMP ...]] - [-s STRING] [-j] +usage: fprime-cli events [-h] [--zmq] [--zmq-server] + [--zmq-transport serverInUrl serverOutUrl] [--tts-port TTS_PORT] + [--tts-addr TTS_ADDR] [-r ROOT_INPUT] [--dictionary DICTIONARY] + [--packet-spec PACKET_SPEC] [-l LOGS] [--log-directly] + [--log-to-stdout] [--file-storage-directory FILES_DIRECTORY] + [--list] [-i ID] [-c COMP [COMP ...]] [-s SEARCH] [-t SECONDS] [-j] print out new events that have occurred on the F Prime instance, sorted by timestamp -optional arguments: +options: -h, --help show this help message and exit - -d DICTIONARY, --dictionary DICTIONARY - path from the current working directory to the - "Dictionary.xml" file for the project - you're using the API with; if unused, tries to search - the current working directory for such a file - -ip IP, --ip-address IP - connect to the GDS server using the given IP or - hostname (default=127.0.0.1 (i.e. localhost)) - -p PORT, --port PORT connect to the GDS server using the given port number - (default=50050) - -t SECONDS, --timeout SECONDS - wait at most SECONDS seconds for a single new message, - then exit (defaults to listening until the user exits - via CTRL+C, and logging all messages) - -l, --list list all possible event types the current F Prime + +GDS Options: + --zmq Switch to using the ZMQ transportation layer + --zmq-server Sets the ZMQ connection to be a server. + Default: false (client) + --zmq-transport serverInUrl serverOutUrl + Pair of URls used with --zmq to setup ZeroMQ transportation + [default: ['ipc:///tmp/fprime-server-in', + 'ipc:///tmp/fprime-server-out']] + --tts-port TTS_PORT Set the threaded TCP socket server port [default: 50050] + --tts-addr TTS_ADDR Set the threaded TCP socket server address + [default: 0.0.0.0] + -r ROOT_INPUT, --root ROOT_INPUT + Root directory of build artifacts, used to automatically + find app and dictionary. + [default: install_dest field in settings.ini] + --dictionary DICTIONARY + Path to dictionary. Overrides automatic dictionary + detection. + --packet-spec PACKET_SPEC + Path to packet specification. + -l LOGS, --logs LOGS Logging directory. Created if nonexistent. + [default: /workspaces/macos/DefaultMission/logs] + --log-directly Logging directory is used directly, no extra dated + directories created. + --log-to-stdout Log to standard out along with log output files + --file-storage-directory FILES_DIRECTORY + File to store uplink and downlink files. + Default: /tmp/fprime-downlink/ + +Search/Filtering Options: + --list list all possible event types the current F Prime instance could produce, based on the events dictionary, sorted by event type ID - -i ID [ID ...], --ids ID [ID ...] - only show events matching the given type ID(s) "ID"; + -i ID, --ids ID only show events matching the given type ID(s) 'ID'; can provide multiple IDs to show all given types -c COMP [COMP ...], --components COMP [COMP ...] - only show events from the given component name "COMP"; - can provide multiple components to show events from - all components given - -s STRING, --search STRING + only show events from the given component name 'COMP'; + can provide multiple components to show events from all + components given + -s SEARCH, --search SEARCH only show events whose name or output string exactly matches or contains the entire given string "STRING" - -j, --json return the JSON response of the API call, with events - filtered based on other flags provided + +Retrieval Options: + -t SECONDS, --timeout SECONDS + wait at most SECONDS seconds for a single new event, + then exit (defaults to listening until the user exits + via CTRL+C, and logging all events) + -j, --json returns response in JSON format ``` ### Supplying F´ Dictionary @@ -216,44 +240,68 @@ directly. Help Message: ``` -usage: fprime-cli channels [-h] [-d DICTIONARY] [-ip IP] [-p PORT] - [-t SECONDS] [-l] [-i ID [ID ...]] - [-c COMP [COMP ...]] [-s STRING] [-j] - -print out new telemetry data that has been received from the F Prime instance, +usage: fprime-cli channels [-h] [--zmq] [--zmq-server] + [--zmq-transport serverInUrl serverOutUrl] [--tts-port TTS_PORT] + [--tts-addr TTS_ADDR] [-r ROOT_INPUT] [--dictionary DICTIONARY] + [--packet-spec PACKET_SPEC] [-l LOGS] [--log-directly] + [--log-to-stdout] [--file-storage-directory FILES_DIRECTORY] + [--list] [-i ID] [-c COMP [COMP ...]] [-s SEARCH] [-t SECONDS] [-j] + +print out new telemetry data that has been received from the F Prime instance, sorted by timestamp -optional arguments: +options: -h, --help show this help message and exit - -d DICTIONARY, --dictionary DICTIONARY - path from the current working directory to the - "Dictionary.xml" file for the project - you're using the API with; if unused, tries to search - the current working directory for such a file - -ip IP, --ip-address IP - connect to the GDS server using the given IP or - hostname (default=127.0.0.1 (i.e. localhost)) - -p PORT, --port PORT connect to the GDS server using the given port number - (default=50050) - -t SECONDS, --timeout SECONDS - wait at most SECONDS seconds for a single new message, - then exit (defaults to listening until the user exits - via CTRL+C, and logging all messages) - -l, --list list all possible channel types the current F Prime + +GDS Options: + --zmq Switch to using the ZMQ transportation layer + --zmq-server Sets the ZMQ connection to be a server. + Default: false (client) + --zmq-transport serverInUrl serverOutUrl + Pair of URls used with --zmq to setup ZeroMQ transportation + [default: ['ipc:///tmp/fprime-server-in', + 'ipc:///tmp/fprime-server-out']] + --tts-port TTS_PORT Set the threaded TCP socket server port [default: 50050] + --tts-addr TTS_ADDR Set the threaded TCP socket server address + [default: 0.0.0.0] + -r ROOT_INPUT, --root ROOT_INPUT + Root directory of build artifacts, used to automatically + find app and dictionary. + [default: install_dest field in settings.ini] + --dictionary DICTIONARY + Path to dictionary. Overrides automatic dictionary + detection. + --packet-spec PACKET_SPEC + Path to packet specification. + -l LOGS, --logs LOGS Logging directory. Created if nonexistent. + [default: /workspaces/macos/DefaultMission/logs] + --log-directly Logging directory is used directly, no extra dated + directories created. + --log-to-stdout Log to standard out along with log output files + --file-storage-directory FILES_DIRECTORY + File to store uplink and downlink files. + Default: /tmp/fprime-downlink/ + +Search/Filtering Options: + --list list all possible channel types the current F Prime instance could produce, based on the channels dictionary, sorted by channel type ID - -i ID [ID ...], --ids ID [ID ...] - only show channels matching the given type ID(s) "ID"; + -i ID, --ids ID only show channels matching the given type ID(s) 'ID'; can provide multiple IDs to show all given types -c COMP [COMP ...], --components COMP [COMP ...] - only show channels from the given component name - "COMP"; can provide multiple components to show - channels from all components given - -s STRING, --search STRING + only show channels from the given component name 'COMP'; + can provide multiple components to show channels from all + components given + -s SEARCH, --search SEARCH only show channels whose name or output string exactly matches or contains the entire given string "STRING" - -j, --json return the JSON response of the API call, with - channels filtered based on other flags provided + +Retrieval Options: + -t SECONDS, --timeout SECONDS + wait at most SECONDS seconds for a single new channel, + then exit (defaults to listening until the user exits + via CTRL+C, and logging all channels) + -j, --json returns response in JSON format ``` ### `command-send` @@ -261,48 +309,71 @@ optional arguments: Help Message: ``` -usage: fprime-cli command-send [-h] [-d DICTIONARY] [-ip IP] [-p PORT] - [-args [ARGUMENTS [ARGUMENTS ...]]] [-l] - [-i ID [ID ...]] [-c COMP [COMP ...]] - [-s STRING] [-j] - [command-name] +usage: fprime-cli command-send [-h] [-r ROOT_INPUT] [--dictionary DICTIONARY] + [--packet-spec PACKET_SPEC] [-l LOGS] [--log-directly] + [--log-to-stdout] [--file-storage-directory FILES_DIRECTORY] + [--zmq] [--zmq-server] [--zmq-transport serverInUrl serverOutUrl] + [--tts-port TTS_PORT] [--tts-addr TTS_ADDR] + [--arguments [ARGUMENTS ...]] [--list] [-i ID] [-c COMP [COMP ...]] + [-s SEARCH] [-j] [command-name] sends the given command to the spacecraft via the GDS positional arguments: - command-name the full name of the command you want to execute in - "." form + command-name the full name of the command you want to execute + in "." form -optional arguments: +options: -h, --help show this help message and exit - -d DICTIONARY, --dictionary DICTIONARY - path from the current working directory to the - "Dictionary.xml" file for the project - you're using the API with; if unused, tries to search - the current working directory for such a file - -ip IP, --ip-address IP - connect to the GDS server using the given IP or - hostname (default=127.0.0.1 (i.e. localhost)) - -p PORT, --port PORT connect to the GDS server using the given port number - (default=50050) - -args [ARGUMENTS [ARGUMENTS ...]], --arguments [ARGUMENTS [ARGUMENTS ...]] - provide a space-separated set of arguments to the - command being sent - -l, --list list all possible command types the current F Prime + --arguments [ARGUMENTS ...] + provide a space-separated set of arguments to + the command being sent + +GDS Options: + -r ROOT_INPUT, --root ROOT_INPUT + Root directory of build artifacts, used to automatically + find app and dictionary. + [default: install_dest field in settings.ini] + --dictionary DICTIONARY + Path to dictionary. Overrides automatic dictionary + detection. + --packet-spec PACKET_SPEC + Path to packet specification. + -l LOGS, --logs LOGS Logging directory. Created if nonexistent. + [default: /workspaces/macos/DefaultMission/logs] + --log-directly Logging directory is used directly, no extra dated + directories created. + --log-to-stdout Log to standard out along with log output files + --file-storage-directory FILES_DIRECTORY + File to store uplink and downlink files. + Default: /tmp/fprime-downlink/ + --zmq Switch to using the ZMQ transportation layer + --zmq-server Sets the ZMQ connection to be a server. + Default: false (client) + --zmq-transport serverInUrl serverOutUrl + Pair of URls used with --zmq to setup ZeroMQ transportation + [default: ['ipc:///tmp/fprime-server-in', + 'ipc:///tmp/fprime-server-out']] + --tts-port TTS_PORT Set the threaded TCP socket server port [default: 50050] + --tts-addr TTS_ADDR Set the threaded TCP socket server address + [default: 0.0.0.0] + +Search/Filtering Options: + --list list all possible command types the current F Prime instance could produce, based on the commands dictionary, sorted by command type ID - -i ID [ID ...], --ids ID [ID ...] - only show commands matching the given type ID(s) "ID"; + -i ID, --ids ID only show commands matching the given type ID(s) 'ID'; can provide multiple IDs to show all given types -c COMP [COMP ...], --components COMP [COMP ...] - only show commands from the given component name - "COMP"; can provide multiple components to show - commands from all components given - -s STRING, --search STRING + only show commands from the given component name 'COMP'; + can provide multiple components to show commands from all + components given + -s SEARCH, --search SEARCH only show commands whose name or output string exactly matches or contains the entire given string "STRING" - -j, --json return the JSON response of the API call, with - commands filtered based on other flags provided + +Retrieval Options: + -j, --json returns response in JSON format ``` ### `events` @@ -310,44 +381,68 @@ optional arguments: Help message: ``` -usage: fprime-cli events [-h] [-d DICTIONARY] [-ip IP] [-p PORT] [-t SECONDS] - [-l] [-i ID [ID ...]] [-c COMP [COMP ...]] - [-s STRING] [-j] +usage: fprime-cli events [-h] [--zmq] [--zmq-server] + [--zmq-transport serverInUrl serverOutUrl] [--tts-port TTS_PORT] + [--tts-addr TTS_ADDR] [-r ROOT_INPUT] [--dictionary DICTIONARY] + [--packet-spec PACKET_SPEC] [-l LOGS] [--log-directly] + [--log-to-stdout] [--file-storage-directory FILES_DIRECTORY] + [--list] [-i ID] [-c COMP [COMP ...]] [-s SEARCH] [-t SECONDS] [-j] print out new events that have occurred on the F Prime instance, sorted by timestamp -optional arguments: +options: -h, --help show this help message and exit - -d DICTIONARY, --dictionary DICTIONARY - path from the current working directory to the - "Dictionary.xml" file for the project - you're using the API with; if unused, tries to search - the current working directory for such a file - -ip IP, --ip-address IP - connect to the GDS server using the given IP or - hostname (default=127.0.0.1 (i.e. localhost)) - -p PORT, --port PORT connect to the GDS server using the given port number - (default=50050) - -t SECONDS, --timeout SECONDS - wait at most SECONDS seconds for a single new message, - then exit (defaults to listening until the user exits - via CTRL+C, and logging all messages) - -l, --list list all possible event types the current F Prime + +GDS Options: + --zmq Switch to using the ZMQ transportation layer + --zmq-server Sets the ZMQ connection to be a server. + Default: false (client) + --zmq-transport serverInUrl serverOutUrl + Pair of URls used with --zmq to setup ZeroMQ transportation + [default: ['ipc:///tmp/fprime-server-in', + 'ipc:///tmp/fprime-server-out']] + --tts-port TTS_PORT Set the threaded TCP socket server port [default: 50050] + --tts-addr TTS_ADDR Set the threaded TCP socket server address + [default: 0.0.0.0] + -r ROOT_INPUT, --root ROOT_INPUT + Root directory of build artifacts, used to automatically + find app and dictionary. + [default: install_dest field in settings.ini] + --dictionary DICTIONARY + Path to dictionary. Overrides automatic dictionary + detection. + --packet-spec PACKET_SPEC + Path to packet specification. + -l LOGS, --logs LOGS Logging directory. Created if nonexistent. + [default: /workspaces/macos/DefaultMission/logs] + --log-directly Logging directory is used directly, no extra dated + directories created. + --log-to-stdout Log to standard out along with log output files + --file-storage-directory FILES_DIRECTORY + File to store uplink and downlink files. + Default: /tmp/fprime-downlink/ + +Search/Filtering Options: + --list list all possible event types the current F Prime instance could produce, based on the events dictionary, sorted by event type ID - -i ID [ID ...], --ids ID [ID ...] - only show events matching the given type ID(s) "ID"; + -i ID, --ids ID only show events matching the given type ID(s) 'ID'; can provide multiple IDs to show all given types -c COMP [COMP ...], --components COMP [COMP ...] - only show events from the given component name "COMP"; - can provide multiple components to show events from - all components given - -s STRING, --search STRING + only show events from the given component name 'COMP'; + can provide multiple components to show events from all + components given + -s SEARCH, --search SEARCH only show events whose name or output string exactly matches or contains the entire given string "STRING" - -j, --json return the JSON response of the API call, with events - filtered based on other flags provided + +Retrieval Options: + -t SECONDS, --timeout SECONDS + wait at most SECONDS seconds for a single new event, + then exit (defaults to listening until the user exits + via CTRL+C, and logging all events) + -j, --json returns response in JSON format ``` ## Conclusion diff --git a/docs/UsersGuide/gds/gds-introduction.md b/docs/UsersGuide/gds/gds-introduction.md index 863b0e5566..fcff4eb5a3 100644 --- a/docs/UsersGuide/gds/gds-introduction.md +++ b/docs/UsersGuide/gds/gds-introduction.md @@ -5,16 +5,17 @@ systems. It was designed for projects that have not already chosen a GDS, for de project's GDS is fully online, and for integration testers who wish to automate tests against F´ software. This guide will give you a quick introduction to what the F´ GDS is and how you can use it. -- [What is the GDS?](#what-is-the-gds) -- [Getting Started](#getting-started) +- [A Brief Guide to the F´ Ground Data System](#a-brief-guide-to-the-f-ground-data-system) + - [What is the GDS?](#what-is-the-gds) + - [Getting Started](#getting-started) - [Running the GDS](#running-the-gds) -- [GDS Options](#gds-options) + - [GDS Options](#gds-options) - [Specify the Deployment or Dictionary](#specify-the-deployment-or-dictionary) - [Disable Automatic Flight Software Execution](#disable-automatic-flight-software-execution) - [Specify GDS Addresses and Ports](#specify-gds-addresses-and-ports) - [Run the GDS Without a UI](#run-the-gds-without-a-ui) - [Help and Other Options](#help-and-other-options) -- [Navigating the GDS GUI](#navigating-the-gds-gui) + - [Navigating the GDS GUI](#navigating-the-gds-gui) - [Commanding](#commanding) - [Events](#events) - [Channels](#channels) @@ -22,7 +23,7 @@ will give you a quick introduction to what the F´ GDS is and how you can use it - [Downlink](#downlink) - [Logs](#logs) - [Dashboard](#dashboard) -- [Conclusion](#conclusion) + - [Conclusion](#conclusion) ![GDS Image](../media/gds_gui_events.png) @@ -208,8 +209,7 @@ disconnected and not sending/receiving any data. This is reset to an X via timeo timeout in the `config.js` file. This widget is fondly referred to as "the orb" as it quickly shows if there is data flow from the embedded F´ system. -There's also a NASA logo on the far left. It doesn't do anything right now, but hopefully, the meatball continues to -inspire our users. This logo is also configurable in `config.js`. +There's also an F´ logo on the far left, which is configurable in `config.js`. The tabs across the top perform most of the functionality of the GDS. What do the tabs contain? Do they contain things? Let's find out! diff --git a/docs/UsersGuide/guide.md b/docs/UsersGuide/guide.md index 121b89bdff..409ac152f8 100644 --- a/docs/UsersGuide/guide.md +++ b/docs/UsersGuide/guide.md @@ -66,14 +66,15 @@ This section is divided into three sub-sections: - [Sequencing in F´](./gds/seqgen.md) - Full Development Guides: technical details for full F´ implementations - [Configuring F´](./dev/configuring-fprime.md) - - [v3 Migration Guide](./user/v3-migration-guide.md) + - [F´ Modeling with FPP](./user/fpp-user-guide.md) - [A Tour of the Source Tree](./dev/source-tree.md) - - [F´ XML Specifications](./dev/xml-specification.md): + - [F´ XML Specifications](./dev/xml-specification.md) - [F´ Implementation Classes](./dev/implementation.md) - [Constructing the F´ Topology](./dev/building-topology.md) - [Asserts in F´](./dev/assert.md) - [GDS Dashboard Reference](./dev/gds-dashboard-reference.md) - [Integration Test API](./dev/testAPI/user_guide.md) + - [v3 Migration Guide](./user/v3-migration-guide.md) - Advanced F´ Topics: - [F´ Python Guidelines](./dev/py-dev.md) - [Porting F´ To a New Platform](./dev/porting-guide.md) diff --git a/docs/UsersGuide/media/dashboard_header.png b/docs/UsersGuide/media/dashboard_header.png index bc3335e5fb..fdbf17d557 100644 Binary files a/docs/UsersGuide/media/dashboard_header.png and b/docs/UsersGuide/media/dashboard_header.png differ diff --git a/docs/UsersGuide/media/gds_cli_user_guide_cover.png b/docs/UsersGuide/media/gds_cli_user_guide_cover.png index ec68e07588..75ef6c4d8d 100644 Binary files a/docs/UsersGuide/media/gds_cli_user_guide_cover.png and b/docs/UsersGuide/media/gds_cli_user_guide_cover.png differ diff --git a/docs/UsersGuide/media/gds_gui_channels.png b/docs/UsersGuide/media/gds_gui_channels.png index 5835ca2136..0179ce0dc0 100644 Binary files a/docs/UsersGuide/media/gds_gui_channels.png and b/docs/UsersGuide/media/gds_gui_channels.png differ diff --git a/docs/UsersGuide/media/gds_gui_channels_edit.png b/docs/UsersGuide/media/gds_gui_channels_edit.png index 795235cc79..4036425a3f 100644 Binary files a/docs/UsersGuide/media/gds_gui_channels_edit.png and b/docs/UsersGuide/media/gds_gui_channels_edit.png differ diff --git a/docs/UsersGuide/media/gds_gui_commanding.png b/docs/UsersGuide/media/gds_gui_commanding.png index 64da515af4..2757eeecbd 100644 Binary files a/docs/UsersGuide/media/gds_gui_commanding.png and b/docs/UsersGuide/media/gds_gui_commanding.png differ diff --git a/docs/UsersGuide/media/gds_gui_downlink.png b/docs/UsersGuide/media/gds_gui_downlink.png index 0090b6c5bd..393dfdcd14 100644 Binary files a/docs/UsersGuide/media/gds_gui_downlink.png and b/docs/UsersGuide/media/gds_gui_downlink.png differ diff --git a/docs/UsersGuide/media/gds_gui_events.png b/docs/UsersGuide/media/gds_gui_events.png index 750c5f9a73..3a2b485bdd 100644 Binary files a/docs/UsersGuide/media/gds_gui_events.png and b/docs/UsersGuide/media/gds_gui_events.png differ diff --git a/docs/UsersGuide/media/gds_gui_logs.png b/docs/UsersGuide/media/gds_gui_logs.png index b0fe0a3c15..eb4d18864e 100644 Binary files a/docs/UsersGuide/media/gds_gui_logs.png and b/docs/UsersGuide/media/gds_gui_logs.png differ diff --git a/docs/UsersGuide/media/gds_gui_uplink.png b/docs/UsersGuide/media/gds_gui_uplink.png index 4f86b9fadd..a9250f17eb 100644 Binary files a/docs/UsersGuide/media/gds_gui_uplink.png and b/docs/UsersGuide/media/gds_gui_uplink.png differ diff --git a/docs/UsersGuide/user/cmd-evt-chn-prm.md b/docs/UsersGuide/user/cmd-evt-chn-prm.md index 1342beed20..b11c53472b 100644 --- a/docs/UsersGuide/user/cmd-evt-chn-prm.md +++ b/docs/UsersGuide/user/cmd-evt-chn-prm.md @@ -23,7 +23,7 @@ These types will be elaborated within this guide. It contains: ## Commands -Each **Component** defines a set of commands for operations. Unlike pipes, which are intended for component to component communication, commands are designed for user interaction with a component. Commands are defined through a series of +Each **Component** defines a set of commands for operations. Unlike ports, which are intended for component to component communication, commands are designed for user interaction with a component. Commands are defined through a series of properties. Users can send commands to the F´ system and via `Svc::CmdDispatcher` these commands are dispatched to a handling component to invoke some behavior. The handling component handles a command by defining a command handler function to run when the command arrives. @@ -56,10 +56,10 @@ the command dispatcher connecting the registration, dispatch, and response ports The command opcode is extracted, and a lookup table is used to find the handling component. The argument buffer is then passed to the component, and the command dispatcher waits without blocking for the component to return status.. -In many projects, commands need to be sequenced in order. In order to facilitate this, the framework provides -`Svc::CmdSequencer`. The command sequencer reads a defined sequence of commands and sends each in turn to the command -dispatcher to be dispatched and the command execution status is returned to the sequencer. This is an alternate path to -send command buffers to the command dispatcher than the external path from ground. +In many projects, commands need to be sequenced in order. In order to facilitate this, the framework provides +`Svc::CmdSequencer`. The command sequencer reads a defined sequence of commands and sends each in turn to the command +dispatcher; after each command is dispatched, the status of its execution is returned to the sequencer. Sending command buffers +to the command dispatcher through the command sequencer is an alternate path to sending them externally from the ground. ### Command Sequencing @@ -72,11 +72,11 @@ while a successful response moves to the next command in the sequence. ## Events Events represent a log of activities taken by the embedded system. Events can be thought of in the same way as a program -execution log in that they enable the ability to trace the execution of the system. Events are sent out of the system via the -`Svc::ActiveLogger` component and components defining commands should hook up the log port to it. If console logging is +execution log in that they enable the ability to trace the execution of the system. Events are sent out of the system via +the `Svc::ActiveLogger` component and components defining events should hook up the log port to it. If console logging is desired, the text log port can be hooked up to the `Svc::PassiveConsoleTextLogger` component. Events are defined per -component and are typically used to capture what the component is doing. Events can be sporadic; however, should all be -captured for downlink. Events are defined by the following properties: +component and are typically used to capture what the component is doing. Events can occur sporadically; however, they +should all be captured for downlink. Events are defined by the following properties: 1. id: a numeric id uniquely define this event. It is automatically offset by the component's base id to ensure global uniqueness. @@ -123,7 +123,7 @@ current value. Channels are broken up per component and are typically sampled at id, time, and value triples and are defined per component with the following properties: 1. id: the unique id of the channel. This is offset by the base id of the component for global uniqueness. -2. name: the unique text name of the channel. This is prepended with the component name for global uniqueness. +2. name: the unique text name of the channel. This is prepended with the component instance name for global uniqueness. 3. data_type: type of the value of the channel. Can be primitive and complex types. 4. update: "on_change" to update only when the written value changes, and omitted to always downlink @@ -134,7 +134,7 @@ The code generator automatically adds ports for retrieving time tags and sending ### Telemetry Database The telemetry database acts as a double-buffered store for telemetry values. Components are free to update channels at -any time, however; at a set rate the current value will be read from the telemetry database and sent to the ground. +any time; however, the current value will be read from the telemetry database and sent to the ground at a set rate. Components using this service should hook up the telemetry port to the telemetry database (`Svc::TlmChan`). ![Telemetry Database](../media/data_model4.png) @@ -170,10 +170,12 @@ provides ports to get and set parameters, which are stored in a file to persist **Figure 8. Parameter manager.** The parameter manager or database loads the file containing parameters from the file system during initialization. The initialization subsequently calls *loadParameters()* on components with parameters. Components can set and retrieve parameters. The parameter manager saves the updated values to the file system via the -command. +set and save commands auto-generated for every parameter; the set command updates the value of the parameter locally +within the component that owns it, and the save command pushing the current value of the parameter to non-volatile storage, +meaning it will persist within the files of the system across system resets. ## A Note On Serialized Ports The `Svc` components use serialize ports to generically handle port data of different types to support uplink and -downlink. \ No newline at end of file +downlink. diff --git a/docs/UsersGuide/user/fpp-user-guide.md b/docs/UsersGuide/user/fpp-user-guide.md new file mode 100644 index 0000000000..4500db24b6 --- /dev/null +++ b/docs/UsersGuide/user/fpp-user-guide.md @@ -0,0 +1,9 @@ +# F´ Modeling: FPP User Guide + +F´ v3 introduced a new way of modeling with F´, the FPP (F Prime Prime) modeling language. The [MathComponent Tutorial](https://fprime-community.github.io/fprime-tutorial-math-component/) is a good introduction to FPP. + +To go into more detail, the full FPP documentation can be found here: [FPP Wiki](https://github.com/fprime-community/fpp/wiki). + +**Quick links:** +- [FPP User Guide](https://fprime-community.github.io/fpp/fpp-users-guide.html) +- [FPP Language Specification](https://fprime-community.github.io/fpp/fpp-spec.html) diff --git a/docs/index.md b/docs/index.md index bfffc3bac5..6acc54955b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,22 +24,21 @@ F´ has the following features: - [Discussions](https://github.com/nasa/fprime/discussions) - [Issues](https://github.com/nasa/fprime/issues) - [Community GitHub Organization](https://github.com/fprime-community) -- [Architecture Overview](./Architecture/FPrimeArchitectureShort.pdf) - -### Discontinued: -- [Community Forum and Mailing List](https://groups.google.com/d/forum/fprime-community) - - **Note**: Community forum has been replaced by [Discussions](https://github.com/nasa/fprime/discussions) since mid june 2021. +- [User Guide](./UsersGuide/guide.md) ## F´ Documentation ### F´ Release - [Latest Documentation](./latest.md) +- [v3.3.0 Documentation](https://nasa.github.io/fprime/v3.3.0) +- [v3.2.0 Documentation](https://nasa.github.io/fprime/v3.2.0) +- [v3.1.0 Documentation](https://nasa.github.io/fprime/v3.1.0) +- [v3.0.0 Documentation](https://nasa.github.io/fprime/v3.0.0) +- [v2.1.0 Documentation](https://nasa.github.io/fprime/v2.1.0) +- [v2.0.1 Documentation](https://nasa.github.io/fprime/v2.0.1) - [v2.0.0 Documentation](https://nasa.github.io/fprime/v2.0.0) - [v1.5 Series Documentation](https://nasa.github.io/fprime/v1.5) ## Further References -To start with F´, follow the [installation guide](./INSTALL.md). Then inspect -either the [reference application](https://github.com/nasa/fprime/blob/master/Ref/README.md), -[raspberry pi reference](https://github.com/nasa/fprime/blob/master/RPI/README.md), or the -[tutorials](Tutorials/README.md). +To start with F´, follow the [installation guide](./INSTALL.md). Then follow our [tutorials](Tutorials/README.md), or inspect our [reference applications](https://github.com/fprime-community#references). diff --git a/requirements.txt b/requirements.txt index 3d4b312cbf..5b1372fd33 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,50 +1,53 @@ aniso8601==9.0.1 -argcomplete==2.0.0 +argcomplete==3.1.1 arrow==1.2.3 -attrs==22.2.0 binaryornot==0.4.4 Brotli==1.0.9 -certifi==2022.12.7 -chardet==5.1.0 -charset-normalizer==3.0.1 +certifi==2023.7.22 +chardet==5.2.0 +charset-normalizer==3.2.0 Cheetah3==3.2.6.post1 -click==8.1.3 -cookiecutter==2.1.1 +click==8.1.6 +cookiecutter==2.2.3 et-xmlfile==1.1.0 -exceptiongroup==1.1.0 -Flask==2.2.2 +exceptiongroup==1.1.2 +Flask==2.2.3 Flask-Compress==1.13 -Flask-RESTful==0.3.9 -fprime-fpp==1.2.0 -fprime-gds==3.2.0 -fprime-tools==3.2.0 -gcovr==5.2 +Flask-RESTful==0.3.10 +fprime-fpl-convert-xml==1.0.0 +fprime-fpl-extract-xml==1.0.0 +fprime-fpl-layout==1.0.0 +fprime-fpl-write-pic==1.0.0 +fprime-fpp==1.3.0 +fprime-gds==3.3.0 +fprime-tools==3.3.1 +fprime-visual==1.0.0 +gcovr==6.0 idna==3.4 -importlib-metadata==4.13.0 +importlib-metadata==6.7.0 iniconfig==2.0.0 itsdangerous==2.1.2 Jinja2==3.1.2 -jinja2-time==0.2.0 -lxml==4.9.2 -Markdown==3.4.1 -MarkupSafe==2.1.2 -openpyxl==3.1.0 -packaging==23.0 +lxml==4.9.3 +Markdown==3.4.4 +MarkupSafe==2.1.3 +openpyxl==3.1.2 +packaging==23.1 pexpect==4.8.0 -pluggy==1.0.0 +pluggy==1.2.0 ptyprocess==0.7.0 -Pygments==2.14.0 -pytest==7.2.1 +Pygments==2.15.1 +pytest==7.4.0 python-dateutil==2.8.2 -python-slugify==8.0.0 -pytz==2022.7.1 -PyYAML==6.0 -pyzmq==25.0.0 -requests==2.28.2 +python-slugify==8.0.1 +pytz==2023.3 +PyYAML==6.0.1 +pyzmq==25.1.0 +requests==2.31.0 six==1.16.0 text-unidecode==1.3 -toml==0.10.2 tomli==2.0.1 -urllib3==1.26.14 -Werkzeug==2.2.2 -zipp==3.12.0 +typing-extensions==4.7.1 +urllib3==1.26.16 +Werkzeug==2.2.3 +zipp==3.15.0