From f853ccbe04e52c8e0bfbf513d63a51bb32f7af90 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 29 May 2025 11:25:25 -0700 Subject: [PATCH 01/52] Added led-blinker workflow for aarch64-linux platform --- .../ext-aarch64-linux-led-blinker.yml | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 .github/workflows/ext-aarch64-linux-led-blinker.yml diff --git a/.github/workflows/ext-aarch64-linux-led-blinker.yml b/.github/workflows/ext-aarch64-linux-led-blinker.yml new file mode 100644 index 00000000000..5dc13c6b7ba --- /dev/null +++ b/.github/workflows/ext-aarch64-linux-led-blinker.yml @@ -0,0 +1,106 @@ +# Cross-compile https://github.com/fprime-community/fprime-workshop-led-blinker +# Runs integration tests on aarch64-linux + +name: "External Repo: AArch64 Linux LedBlinker" + +on: + push: + branches: [ devel, release/** ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ devel, release/** ] + paths-ignore: + - 'docs/**' + - '**.md' + - '.github/actions/spelling/**' + - '.github/ISSUE_TEMPLATE/**' + +env: + AARCH64_TOOLCHAIN_DIR: /tmp/aarch64-toolchain + AARCH64_TOOLCHAIN_URL: 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 + ARM_TOOLS_PATH: /tmp/aarch64-toolchain + +jobs: + get-branch: + name: "Get target branch" + uses: ./.github/workflows/reusable-get-pr-branch.yml + with: + target_repository: fprime-community/fprime-workshop-led-blinker + + cross-compilation: + name: "Cross Compilation" + runs-on: ubuntu-22.04 + needs: get-branch + steps: + - name: "Checkout target repository" + uses: actions/checkout@v4 + with: + submodules: false + repository: fprime-community/fprime-workshop-led-blinker + ref: ${{ needs.get-branch.outputs.target-branch }} + - name: "Overlay current F´ revision" + uses: actions/checkout@v4 + with: + submodules: true + path: ./fprime + fetch-depth: 0 + - uses: ./fprime/.github/actions/setup + with: + location: ./fprime + - name: "Download and Setup AArch64 Linux Toolchain" + run: | + mkdir -p ${AARCH64_TOOLCHAIN_DIR} + wget -q ${AARCH64_TOOLCHAIN_URL} + tar -xf $(basename ${AARCH64_TOOLCHAIN_URL}) -C ${AARCH64_TOOLCHAIN_DIR} --strip-components 1 + echo "${AARCH64_TOOLCHAIN_DIR}/bin" >> $GITHUB_PATH + - name: "Generate AArch64 Linux Build Cache" + run: | + fprime-util generate aarch64-linux + - name: "Build AArch64 Linux" + run: | + fprime-util build aarch64-linux + - name: "Prepare artifacts" + run: | + mkdir -p aarch64-linux-artifacts + cp -r ./build-artifacts aarch64-linux-artifacts + cp -r Components/Led/test/int aarch64-linux-artifacts + - name: 'Archive Build Artifacts' + uses: actions/upload-artifact@v4 + with: + name: aarch64-linux-artifacts + path: aarch64-linux-artifacts + retention-days: 5 + + aarch64-integration: + name: "AArch64 Linux Integration Tests" + runs-on: self-hosted + needs: cross-compilation + steps: + - name: "Checkout F´ Repository" + uses: actions/checkout@v4 + with: + sparse-checkout: 'requirements.txt' + - name: "Setup environment" + run: | + python -m venv venv + . venv/bin/activate + pip install -r requirements.txt + - name: "Artifacts Download" + uses: actions/download-artifact@v4 + with: + name: aarch64-linux-artifacts + - name: Run Integration Tests + run: | + . venv/bin/activate + mkdir -p ci-logs + chmod +x ./build-artifacts/aarch64-linux/LedBlinker/bin/LedBlinker + fprime-gds --ip-client -d ./build-artifacts/aarch64-linux/LedBlinker --logs ./ci-logs & + sleep 10 + pytest --dictionary ./build-artifacts/aarch64-linux/LedBlinker/dict/LedBlinkerTopologyDictionary.json ./int/led_integration_tests.py + - name: 'Archive logs' + uses: actions/upload-artifact@v4 + if: always() + with: + name: aarch64-linux-logs + path: ci-logs + retention-days: 5 From b542ecb6af79f42944ba1d81f6d16e04751e9176 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 29 May 2025 13:37:47 -0700 Subject: [PATCH 02/52] Update runner label --- .github/workflows/ext-aarch64-linux-led-blinker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ext-aarch64-linux-led-blinker.yml b/.github/workflows/ext-aarch64-linux-led-blinker.yml index 5dc13c6b7ba..fd32489b2d2 100644 --- a/.github/workflows/ext-aarch64-linux-led-blinker.yml +++ b/.github/workflows/ext-aarch64-linux-led-blinker.yml @@ -73,7 +73,7 @@ jobs: aarch64-integration: name: "AArch64 Linux Integration Tests" - runs-on: self-hosted + runs-on: [self-hosted, aarch64-linux] needs: cross-compilation steps: - name: "Checkout F´ Repository" From ecd1bf9d2894612facaecc6144c1811cc3e40d03 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 29 May 2025 14:38:01 -0700 Subject: [PATCH 03/52] Added Tags to RPI self hosted workflows, sparse-checkout-cone-mode false --- .github/workflows/build-test-rpi.yml | 2 +- .github/workflows/ext-aarch64-linux-led-blinker.yml | 1 + .github/workflows/ext-raspberry-led-blinker.yml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test-rpi.yml b/.github/workflows/build-test-rpi.yml index 077bb3ef230..6b18cf64f14 100644 --- a/.github/workflows/build-test-rpi.yml +++ b/.github/workflows/build-test-rpi.yml @@ -52,7 +52,7 @@ jobs: retention-days: 5 RPI-Integration: - runs-on: self-hosted + runs-on: [self-hosted, raspberrypi] needs: RPI steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ext-aarch64-linux-led-blinker.yml b/.github/workflows/ext-aarch64-linux-led-blinker.yml index fd32489b2d2..4bfb9cc5cc9 100644 --- a/.github/workflows/ext-aarch64-linux-led-blinker.yml +++ b/.github/workflows/ext-aarch64-linux-led-blinker.yml @@ -80,6 +80,7 @@ jobs: uses: actions/checkout@v4 with: sparse-checkout: 'requirements.txt' + sparse-checkout-cone-mode: false - name: "Setup environment" run: | python -m venv venv diff --git a/.github/workflows/ext-raspberry-led-blinker.yml b/.github/workflows/ext-raspberry-led-blinker.yml index 23254ee6d1a..c01c4c84af3 100644 --- a/.github/workflows/ext-raspberry-led-blinker.yml +++ b/.github/workflows/ext-raspberry-led-blinker.yml @@ -67,7 +67,7 @@ jobs: RPI-integration: name: "RPI Integration Tests" - runs-on: self-hosted + runs-on: [self-hosted, raspberrypi] needs: cross-compilation steps: - name: "Checkout F´ Repository" From 4cd3832e90d2720636af93319085a8b22a0c8026 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Wed, 4 Jun 2025 10:46:45 -0700 Subject: [PATCH 04/52] Add subtopologies to Svc/ restructing of Ref to include CDH subtopology --- Ref/CMakeLists.txt | 2 +- Ref/Top/CMakeLists.txt | 1 + Ref/Top/RefTopology.cpp | 3 + Ref/Top/RefTopologyDefs.hpp | 3 + Ref/Top/topology.fpp | 33 +- Svc/CMakeLists.txt | 1 + .../CDHCore/ActiveLogger/ActiveLogger.fpp | 152 +++ .../CDHCore/ActiveLogger/ActiveLogger.hpp | 17 + .../CDHCore/ActiveLogger/ActiveLoggerImpl.cpp | 205 ++++ .../CDHCore/ActiveLogger/ActiveLoggerImpl.hpp | 67 ++ .../CDHCore/ActiveLogger/CMakeLists.txt | 26 + Svc/Subtopologies/CDHCore/ActiveLogger/README | 6 + .../CDHCore/ActiveLogger/changed-symbols.txt | 86 ++ .../CDHCore/ActiveLogger/docs/.gitignore | 1 + .../ActiveLogger/docs/Checklist_Code.xlsx | Bin 0 -> 29740 bytes .../ActiveLogger/docs/Checklist_Design.xlsx | Bin 0 -> 24983 bytes .../ActiveLogger/docs/Checklist_Unit_Test.xls | Bin 0 -> 51200 bytes .../ActiveLogger/docs/img/ActiveLoggerBDD.jpg | Bin 0 -> 103324 bytes .../ActiveLogger/docs/img/ReceiveEvents.jpg | Bin 0 -> 67078 bytes .../docs/img/WriteEventBuffer.jpg | Bin 0 -> 38763 bytes .../CDHCore/ActiveLogger/docs/sdd.md | 117 +++ .../CDHCore/ActiveLogger/test/ut/.gitignore | 1 + .../test/ut/ActiveLoggerImplTester.cpp | 625 ++++++++++++ .../test/ut/ActiveLoggerImplTester.hpp | 80 ++ .../test/ut/ActiveLoggerTester.cpp | 158 ++++ .../CDHCore/ActiveLogger/test/ut/Readme.txt | 9 + Svc/Subtopologies/CDHCore/CMakeLists.txt | 1 + .../CDHCore/CmdDispatcher/CMakeLists.txt | 22 + .../CDHCore/CmdDispatcher/CmdDispatcher.fpp | 199 ++++ .../CmdDispatcher/CommandDispatcher.hpp | 17 + .../CmdDispatcher/CommandDispatcherImpl.cpp | 201 ++++ .../CmdDispatcher/CommandDispatcherImpl.hpp | 168 ++++ .../CDHCore/CmdDispatcher/README | 6 + .../CDHCore/CmdDispatcher/changed-symbols.txt | 41 + .../CDHCore/CmdDispatcher/docs/.gitignore | 1 + .../CmdDispatcher/docs/Checklist_Code.xlsx | Bin 0 -> 29709 bytes .../CmdDispatcher/docs/Checklist_Design.xlsx | Bin 0 -> 25044 bytes .../docs/Checklist_Unit_Test.xls | Bin 0 -> 51200 bytes .../docs/img/CommandDispatcherBDD.jpg | Bin 0 -> 142623 bytes .../CDHCore/CmdDispatcher/docs/sdd.md | 127 +++ .../test/int/test_cmd_dispatcher.py | 12 + .../test/ut/CommandDispatcherImplTester.cpp | 887 ++++++++++++++++++ .../test/ut/CommandDispatcherImplTester.hpp | 55 ++ .../test/ut/CommandDispatcherTester.cpp | 211 +++++ .../CDHCore/Subtopology/CDHCore.fpp | 28 + .../Subtopology/CDHCoreTopologyDefs.hpp | 15 + .../CDHCore/Subtopology/CMakeLists.txt | 13 + .../SubtopologyConfig/CmakeLists.txt | 5 + .../Subtopology/SubtopologyConfig/config.fpp | 13 + .../Subtopology/intentionally-empty.cpp | 0 .../CDHCore/TlmChan/CMakeLists.txt | 23 + Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp | 241 +++++ Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp | 26 + Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp | 63 ++ .../CDHCore/TlmChan/docs/.gitignore | 1 + .../CDHCore/TlmChan/docs/Checklist_Code.xlsx | Bin 0 -> 31188 bytes .../TlmChan/docs/Checklist_Design.xlsx | Bin 0 -> 24324 bytes .../TlmChan/docs/Checklist_Unit_Test.xls | Bin 0 -> 51712 bytes .../TlmChan/docs/img/DatabaseScenario.jpg | Bin 0 -> 48738 bytes .../TlmChan/docs/img/ExternalUserScenario.jpg | Bin 0 -> 72528 bytes .../CDHCore/TlmChan/docs/img/TlmChanBDD.jpg | Bin 0 -> 60478 bytes Svc/Subtopologies/CDHCore/TlmChan/docs/sdd.md | 98 ++ .../CDHCore/TlmChan/test/ut/TlmChanMain.cpp | 65 ++ .../CDHCore/TlmChan/test/ut/TlmChanTester.cpp | 351 +++++++ .../CDHCore/TlmChan/test/ut/TlmChanTester.hpp | 95 ++ Svc/Subtopologies/CMakeLists.txt | 1 + 66 files changed, 4564 insertions(+), 15 deletions(-) create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/CMakeLists.txt create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/README create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/changed-symbols.txt create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/.gitignore create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Code.xlsx create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Design.xlsx create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Unit_Test.xls create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/ActiveLoggerBDD.jpg create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/ReceiveEvents.jpg create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/WriteEventBuffer.jpg create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp create mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt create mode 100644 Svc/Subtopologies/CDHCore/CMakeLists.txt create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/README create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Code.xlsx create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Design.xlsx create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Unit_Test.xls create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/img/CommandDispatcherBDD.jpg create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/int/test_cmd_dispatcher.py create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp create mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp create mode 100644 Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp create mode 100644 Svc/Subtopologies/CDHCore/Subtopology/CDHCoreTopologyDefs.hpp create mode 100644 Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt create mode 100644 Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt create mode 100644 Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp create mode 100644 Svc/Subtopologies/CDHCore/Subtopology/intentionally-empty.cpp create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Code.xlsx create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Design.xlsx create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Unit_Test.xls create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/img/DatabaseScenario.jpg create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/img/ExternalUserScenario.jpg create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/img/TlmChanBDD.jpg create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/sdd.md create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanMain.cpp create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp create mode 100644 Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp create mode 100644 Svc/Subtopologies/CMakeLists.txt diff --git a/Ref/CMakeLists.txt b/Ref/CMakeLists.txt index 246dc158a2e..5ce3354e35a 100644 --- a/Ref/CMakeLists.txt +++ b/Ref/CMakeLists.txt @@ -45,7 +45,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime.cmake") # NOTE: register custom targets between these two lines fprime_setup_included_code() ## -# Section 3: Components and Topology +# Section 3: Components and Topology and Subtopologies # # This section includes deployment specific directories. This allows use of non- # core components in the topology, which is also added here. diff --git a/Ref/Top/CMakeLists.txt b/Ref/Top/CMakeLists.txt index 62ac01e3760..eaa235b403d 100644 --- a/Ref/Top/CMakeLists.txt +++ b/Ref/Top/CMakeLists.txt @@ -7,6 +7,7 @@ add_compile_options( -Wno-shadow ) + set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/instances.fpp" "${CMAKE_CURRENT_LIST_DIR}/topology.fpp" diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index b65d442bd08..88217576601 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -20,6 +20,9 @@ // Used for 1Hz synthetic cycling #include +//Subtopology includes +#include + // Allows easy reference to objects in FPP/autocoder required namespaces using namespace Ref; diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 0e2e9f45c6b..8158cc3be73 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -16,6 +16,9 @@ #include "Ref/Top/FppConstantsAc.hpp" #include "Svc/Health/Health.hpp" +// Subtopology includes +#include + // Definitions are placed within a namespace named after the deployment namespace Ref { diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 3461626c17e..c41ae91a966 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -21,6 +21,11 @@ module Ref { topology Ref { + # ---------------------------------------------------------------------- + # Subtopology imports + # ---------------------------------------------------------------------- + import CDHCore.Subtopology + # ---------------------------------------------------------------------- # Instances used in the topology # ---------------------------------------------------------------------- @@ -32,14 +37,14 @@ module Ref { instance SG4 instance SG5 instance blockDrv - instance tlmSend - instance cmdDisp + #instance tlmSend + #instance cmdDisp instance cmdSeq instance comDriver instance comStub instance comQueue instance deframer - instance eventLogger + #instance eventLogger instance fatalAdapter instance fatalHandler instance fileDownlink @@ -71,13 +76,13 @@ module Ref { # Pattern graph specifiers # ---------------------------------------------------------------------- - command connections instance cmdDisp + #command connections instance cmdDisp - event connections instance eventLogger + #event connections instance eventLogger param connections instance prmDb - telemetry connections instance tlmSend + #telemetry connections instance tlmSend text event connections instance textLogger @@ -100,8 +105,8 @@ module Ref { dpCat.fileOut -> fileDownlink.SendFile fileDownlink.FileComplete -> dpCat.fileDone # Inputs to ComQueue (events, telemetry, file) - eventLogger.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] - tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] + Subtopology.eventLogger.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] + Subtopology.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn # ComQueue <-> Framer @@ -123,7 +128,7 @@ module Ref { } connections FaultProtection { - eventLogger.FatalAnnounce -> fatalHandler.FatalReceive + Subtopology.eventLogger.FatalAnnounce -> fatalHandler.FatalReceive } connections RateGroups { @@ -135,7 +140,7 @@ module Ref { rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup1] -> rateGroup1Comp.CycleIn rateGroup1Comp.RateGroupMemberOut[0] -> SG1.schedIn rateGroup1Comp.RateGroupMemberOut[1] -> SG2.schedIn - rateGroup1Comp.RateGroupMemberOut[2] -> tlmSend.Run + rateGroup1Comp.RateGroupMemberOut[2] -> Subtopology.tlmSend.Run rateGroup1Comp.RateGroupMemberOut[3] -> fileDownlink.Run rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run rateGroup1Comp.RateGroupMemberOut[5] -> comQueue.run @@ -164,8 +169,8 @@ module Ref { } connections Sequencer { - cmdSeq.comCmdOut -> cmdDisp.seqCmdBuff - cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn + cmdSeq.comCmdOut -> Subtopology.cmdDisp.seqCmdBuff + Subtopology.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn } connections Uplink { @@ -191,8 +196,8 @@ module Ref { fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn # Router <-> CmdDispatcher/FileUplink - fprimeRouter.commandOut -> cmdDisp.seqCmdBuff - cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn + fprimeRouter.commandOut -> Subtopology.cmdDisp.seqCmdBuff + Subtopology.cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn fprimeRouter.fileOut -> fileUplink.bufferSendIn fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn } diff --git a/Svc/CMakeLists.txt b/Svc/CMakeLists.txt index 6ebfef10f15..b8487361a16 100644 --- a/Svc/CMakeLists.txt +++ b/Svc/CMakeLists.txt @@ -53,6 +53,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/StaticMemory/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TlmChan/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TlmPacketizer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SystemResources/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Subtopologies/") # Text logger components included by default, # but can be disabled if FW_ENABLE_TEXT_LOGGING=0 is desired. diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp new file mode 100644 index 00000000000..acd06a8e175 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp @@ -0,0 +1,152 @@ +module Svc { + + @ A component for logging events + active component ActiveLogger { + + # ---------------------------------------------------------------------- + # Types + # ---------------------------------------------------------------------- + + @ Severity level for event filtering + @ Similar to Fw::LogSeverity, but no FATAL event + enum FilterSeverity { + WARNING_HI = 0 @< Filter WARNING_HI events + WARNING_LO = 1 @< Filter WARNING_LO events + COMMAND = 2 @< Filter COMMAND events + ACTIVITY_HI = 3 @< Filter ACTIVITY_HI events + ACTIVITY_LO = 4 @< Filter ACTIVITY_LO events + DIAGNOSTIC = 5 @< Filter DIAGNOSTIC events + } + + # TODO: Consider replacing this enum with Fw::Enabled + # However, the sense of 0 and 1 are reversed + @ Enabled and disabled state + enum Enabled { + ENABLED = 0 @< Enabled state + DISABLED = 1 @< Disabled state + } + + # ---------------------------------------------------------------------- + # Internal ports + # ---------------------------------------------------------------------- + + @ Internal interface to send log messages to component thread + internal port loqQueue( + $id: FwEventIdType @< Log ID + timeTag: Fw.Time @< Time Tag + $severity: Fw.LogSeverity @< The severity argument + args: Fw.LogBuffer @< Buffer containing serialized log entry + ) \ + drop + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Event input port + sync input port LogRecv: Fw.Log + + @ Packet send port + output port PktSend: Fw.Com + + @ FATAL event announce port + output port FatalAnnounce: Svc.FatalEvent + + @ Ping input port + async input port pingIn: Svc.Ping + + @ Ping output port + output port pingOut: Svc.Ping + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + + @ Port for receiving commands + command recv port CmdDisp + + @ Port for sending command registration requests + command reg port CmdReg + + @ Port for sending command responses + command resp port CmdStatus + + @ Port for emitting events + event port Log + + @ Port for emitting text events + text event port LogText + + @ Port for getting the time + time get port Time + + # ---------------------------------------------------------------------- + # Commands + # ---------------------------------------------------------------------- + + @ Set filter for reporting events. Events are not stored in component. + sync command SET_EVENT_FILTER( + filterLevel: FilterSeverity @< Filter level + filterEnabled: Enabled @< Filter state + ) \ + opcode 0 + + @ Filter a particular ID + async command SET_ID_FILTER( + ID: U32 + idFilterEnabled: Enabled @< ID filter state + ) \ + opcode 2 + + @ Dump the filter states via events + async command DUMP_FILTER_STATE \ + opcode 3 + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + @ Dump severity filter state + event SEVERITY_FILTER_STATE( + $severity: FilterSeverity @< The severity level + enabled: bool + ) \ + severity activity low \ + id 0 \ + format "{} filter state. {}" + + @ Indicate ID is filtered + event ID_FILTER_ENABLED( + ID: U32 @< The ID filtered + ) \ + severity activity high \ + id 1 \ + format "ID {} is filtered." + + @ Attempted to add ID to full ID filter ID + event ID_FILTER_LIST_FULL( + ID: U32 @< The ID filtered + ) \ + severity warning low \ + id 2 \ + format "ID filter list is full. Cannot filter {} ." + + @ Removed an ID from the filter + event ID_FILTER_REMOVED( + ID: U32 @< The ID removed + ) \ + severity activity high \ + id 3 \ + format "ID filter ID {} removed." + + @ ID not in filter + event ID_FILTER_NOT_FOUND( + ID: U32 @< The ID removed + ) \ + severity warning low \ + id 4 \ + format "ID filter ID {} not found." + + } + +} diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp new file mode 100644 index 00000000000..e7ecdde9346 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp @@ -0,0 +1,17 @@ +// ====================================================================== +// ActiveLogger.hpp +// Standardization header for ActiveLogger +// ====================================================================== + +#ifndef Svc_ActiveLogger_HPP +#define Svc_ActiveLogger_HPP + +#include "Svc/ActiveLogger/ActiveLoggerImpl.hpp" + +namespace Svc { + + typedef ActiveLoggerImpl ActiveLogger; + +} + +#endif diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp new file mode 100644 index 00000000000..3be0b42bcd8 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp @@ -0,0 +1,205 @@ +/* + * TestCommand1Impl.cpp + * + * Created on: Mar 28, 2014 + * Author: tcanham + */ + +#include + +#include +#include +#include + +namespace Svc { + static_assert(std::numeric_limits::max() >= TELEM_ID_FILTER_SIZE, "TELEM_ID_FILTER_SIZE must fit within range of FwSizeType"); + typedef ActiveLogger_Enabled Enabled; + typedef ActiveLogger_FilterSeverity FilterSeverity; + + ActiveLoggerImpl::ActiveLoggerImpl(const char* name) : + ActiveLoggerComponentBase(name) + { + // set filter defaults + this->m_filterState[FilterSeverity::WARNING_HI].enabled = + FILTER_WARNING_HI_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; + this->m_filterState[FilterSeverity::WARNING_LO].enabled = + FILTER_WARNING_LO_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; + this->m_filterState[FilterSeverity::COMMAND].enabled = + FILTER_COMMAND_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; + this->m_filterState[FilterSeverity::ACTIVITY_HI].enabled = + FILTER_ACTIVITY_HI_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; + this->m_filterState[FilterSeverity::ACTIVITY_LO].enabled = + FILTER_ACTIVITY_LO_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; + this->m_filterState[FilterSeverity::DIAGNOSTIC].enabled = + FILTER_DIAGNOSTIC_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; + + memset(m_filteredIDs,0,sizeof(m_filteredIDs)); + + } + + ActiveLoggerImpl::~ActiveLoggerImpl() { + } + + void ActiveLoggerImpl::LogRecv_handler(FwIndexType portNum, FwEventIdType id, Fw::Time &timeTag, const Fw::LogSeverity& severity, Fw::LogBuffer &args) { + + // make sure ID is not zero. Zero is reserved for ID filter. + FW_ASSERT(id != 0); + + switch (severity.e) { + case Fw::LogSeverity::FATAL: // always pass FATAL + break; + case Fw::LogSeverity::WARNING_HI: + if (this->m_filterState[FilterSeverity::WARNING_HI].enabled == Enabled::DISABLED) { + return; + } + break; + case Fw::LogSeverity::WARNING_LO: + if (this->m_filterState[FilterSeverity::WARNING_LO].enabled == Enabled::DISABLED) { + return; + } + break; + case Fw::LogSeverity::COMMAND: + if (this->m_filterState[FilterSeverity::COMMAND].enabled == Enabled::DISABLED) { + return; + } + break; + case Fw::LogSeverity::ACTIVITY_HI: + if (this->m_filterState[FilterSeverity::ACTIVITY_HI].enabled == Enabled::DISABLED) { + return; + } + break; + case Fw::LogSeverity::ACTIVITY_LO: + if (this->m_filterState[FilterSeverity::ACTIVITY_LO].enabled == Enabled::DISABLED) { + return; + } + break; + case Fw::LogSeverity::DIAGNOSTIC: + if (this->m_filterState[FilterSeverity::DIAGNOSTIC].enabled == Enabled::DISABLED) { + return; + } + break; + default: + FW_ASSERT(0,static_cast(severity.e)); + return; + } + + // check ID filters + for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { + if ( + (m_filteredIDs[entry] == id) && + (severity != Fw::LogSeverity::FATAL) + ) { + return; + } + } + + // send event to the logger thread + this->loqQueue_internalInterfaceInvoke(id,timeTag,severity,args); + + // if connected, announce the FATAL + if (Fw::LogSeverity::FATAL == severity.e) { + if (this->isConnected_FatalAnnounce_OutputPort(0)) { + this->FatalAnnounce_out(0,id); + } + } + } + + void ActiveLoggerImpl::loqQueue_internalInterfaceHandler(FwEventIdType id, const Fw::Time &timeTag, const Fw::LogSeverity& severity, const Fw::LogBuffer &args) { + + // Serialize event + this->m_logPacket.setId(id); + this->m_logPacket.setTimeTag(timeTag); + this->m_logPacket.setLogBuffer(args); + this->m_comBuffer.resetSer(); + Fw::SerializeStatus stat = this->m_logPacket.serialize(this->m_comBuffer); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); + + if (this->isConnected_PktSend_OutputPort(0)) { + this->PktSend_out(0, this->m_comBuffer,0); + } + } + + void ActiveLoggerImpl::SET_EVENT_FILTER_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, FilterSeverity filterLevel, Enabled filterEnable) { + this->m_filterState[filterLevel.e].enabled = filterEnable; + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveLoggerImpl::SET_ID_FILTER_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + U32 ID, + Enabled idEnabled //!< ID filter state + ) { + + if (Enabled::ENABLED == idEnabled.e) { // add ID + // search list for existing entry + for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { + if (this->m_filteredIDs[entry] == ID) { + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + this->log_ACTIVITY_HI_ID_FILTER_ENABLED(ID); + return; + } + } + // if not already a match, search for an open slot + for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { + if (this->m_filteredIDs[entry] == 0) { + this->m_filteredIDs[entry] = ID; + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + this->log_ACTIVITY_HI_ID_FILTER_ENABLED(ID); + return; + } + } + // if an empty slot was not found, send an error event + this->log_WARNING_LO_ID_FILTER_LIST_FULL(ID); + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::EXECUTION_ERROR); + } else { // remove ID + // search list for existing entry + for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { + if (this->m_filteredIDs[entry] == ID) { + this->m_filteredIDs[entry] = 0; // zero entry + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + this->log_ACTIVITY_HI_ID_FILTER_REMOVED(ID); + return; + } + } + // if it gets here, wasn't found + this->log_WARNING_LO_ID_FILTER_NOT_FOUND(ID); + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::EXECUTION_ERROR); + } + + } + + void ActiveLoggerImpl::DUMP_FILTER_STATE_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ) { + + // first, iterate through severity filters + for (FwEnumStoreType filter = 0; filter < FilterSeverity::NUM_CONSTANTS; filter++) { + FilterSeverity filterState(static_cast(filter)); + this->log_ACTIVITY_LO_SEVERITY_FILTER_STATE( + filterState, + Enabled::ENABLED == this->m_filterState[filter].enabled.e + ); + } + + // iterate through ID filter + for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { + if (this->m_filteredIDs[entry] != 0) { + this->log_ACTIVITY_HI_ID_FILTER_ENABLED(this->m_filteredIDs[entry]); + } + } + + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void ActiveLoggerImpl::pingIn_handler( + const FwIndexType portNum, + U32 key + ) + { + // return key + this->pingOut_out(0,key); + } + +} // namespace Svc diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp new file mode 100644 index 00000000000..140933275d7 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp @@ -0,0 +1,67 @@ +/* + * ActiveLoggerImpl.hpp + * + * Created on: Mar 28, 2014 + * Author: tcanham + */ + +#ifndef ACTIVELOGGERIMPL_HPP_ +#define ACTIVELOGGERIMPL_HPP_ + +#include +#include +#include + +namespace Svc { + + class ActiveLoggerImpl final : public ActiveLoggerComponentBase { + public: + ActiveLoggerImpl(const char* compName); //!< constructor + virtual ~ActiveLoggerImpl(); //!< destructor + PROTECTED: + PRIVATE: + void LogRecv_handler(FwIndexType portNum, FwEventIdType id, Fw::Time &timeTag, const Fw::LogSeverity& severity, Fw::LogBuffer &args); + void loqQueue_internalInterfaceHandler(FwEventIdType id, const Fw::Time &timeTag, const Fw::LogSeverity& severity, const Fw::LogBuffer &args); + + void SET_EVENT_FILTER_cmdHandler( + FwOpcodeType opCode, + U32 cmdSeq, + ActiveLogger_FilterSeverity filterLevel, + ActiveLogger_Enabled filterEnabled); + + void SET_ID_FILTER_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq, //!< The command sequence number + U32 ID, + ActiveLogger_Enabled idFilterEnabled //!< ID filter state + ); + + void DUMP_FILTER_STATE_cmdHandler( + FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ); + + //! Handler implementation for pingIn + //! + void pingIn_handler( + const FwIndexType portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ); + + // Filter state + struct t_filterState { + ActiveLogger_Enabled enabled; //~ zSL#!{s&++Q3K#?h01N;E004jxKzCOYtpyMO;Pa=63;+S7C1hvoY+~!Ir|e;G;-o|C zZevYQ2m(Zr4*>Mj|Nn0P2TR~@>bm7VJwoU;v=4aEIuiAzpoV0&?t}d*jrB92vISDs zNw8@mncW|w63CL`+f0mBHndij@8`IKS$D@S*H(3bezF%y?NlQL|K&brU)=~ky11ge zLVm?93T$p=LtqNqvSYKPG#QXz>}y7(mWA%bq-R*!{fxplAEs!DN`q|{v_*5!EZ`n2 zczRN}+yP~XEm($}9bp-onpAj8AMWQQ0U`<;Hsr0bkNTa4v#Y4A1`ve z;m|O~J-I!k8l^_S@vLa}C)4y%t_fBty&t86DU9s_acj7|&h|E&do!f<^OwCzo`F0O&g2cix9kAky1q<1G7!%yHxw7KHJ;D5tAH6 zV=lz|1Bk3E&#NApVyF%aRvvjHtM>|nX-U8RF!sd2M&v@*1_v-)R> z{C@}n{Fx_z`u?B2btg|-4$#94UkCjTn)Pu=wAI0M@m#@p=yZYCwI8DltMq@e4 zm?#gn#yX^_G>yQ4+Ld?@NRkdFnO5LxEu@gB=fZX0h)TYNaMJ_Q-+@Z{0=vDVn7Y(Z z_pvWunRkR|O!8;Kg8`1IplROVJ@o%dr7YlK+?jv@08qgJ0N{Ug6jk|DGBTBQItNJz(;P4y!DN#YVtz8uSfZE_oF3OkHJ3>_*g` zCqhY2WAz^Y)NCx9$Eh4ZWp|?2{%vz4(b=)XA@32;cgI8?0-5^=aXXQGeuQ&XQn%{A zGcc{5(>;Fag}u#_BdO5rF{Mh}0=s(*C~9N`HS-+qM(HhT*_~);n1T7J)?%8wwgjBN zb@+RgqRsGtx^|TVz~39J)%d-Osx4$R12p` z%$QsT%A@L48>uO!$}XuaV{G7JMM2%ZiMssUtgbk6y;@RBWg4ldqy{R19t$8J6Ks;x3f#=9*OVw z%O%}#)tU*!wCNYosdhJ^7XKLrEQ~7)NN5*_yv~((=-OMBK*QTxr~kuEN1~&8dQ_tj z#@3XT=rwJJOAz?%4&W169yfh_VrWvI4|hAh8;X~1ytQ`2963up&IMk(Eu7$3(`4p* zG8cKQbp+^{pb}B7*B5}^eWP&?O@YXl{`VyXz6d4E7&i{U_sV$6?zm0rjAt(PP5Eya zJFy8wS+T0wi%+`UEqn5OV&0-J6ijF6isc1_QYepou!f zGwP-+InS47WFwAD-g(1vb`Z2ek%HrwF>>wX9g;wjLe1GF40A$`?3XLxjzPGqxlY?q z!DGy~=V_3UssnDkePi6Xv@uJ@SW^bP=~Am~X{YEi$gk^$9DLnnC(;5!F8QTTy{*Sd zRlK>9g2y3`dbHxe(3KK4Z4g1|eEngkx#(eG(Ph>xziTR8HOeuFz}F7# zkx2@bN_9QWLVfV1UWo-!_1g3^M5oEj2J~+5aEW(k-Nf6G#YRo=PVBZB|c;#S>R46>=qR7{X zRMuMB-A6|xCFmp0`_7}XY&BU7oL^ZiB6E4PnwLvhYOSSru>KVu+GX<=Zk0+NVE+3U zu9hwiCQF@Gi%Y_#z>WCFCT-M@l9MA`cWOt@w#}L~o<$2oP%H%R4Xj~$Rn<$ZX*}J4 z8s0u|dR8{A>s5GL{=a-(;I@Cysn@)^1508~!XM476>Qp4`aoeiw&DiY0eaUc_M1_J zhgvwFl7@1tMH$izJa?P`@dIP3GK*Pi#}md9My|7;Lq`%T?_^71l>bueOhJ9A^0PWp zlA()RhIBnzEl{6=wUCLA2BlGEdP67{g*#Zhzt-dNi`3=ubNskjy&cGl#pmJleJM&g zl-U^e*pu~sy)^Ul{bYFCKV_rC_d^_(LjOL8&-=K$KQ+!x@Zz8Abd3$)i z#slBU0(#bQk24i6)H;B;yoGr(h1s`~ecSV9@}w-?g2@iN@IQ%_Kdc?JJxB#h*};d_ z5OppNnkx&jU(Q6J7<#mUR}dfo&73aa3UanB=ff;YGV)l62(kJ-Ym0> z_6gVnfG~2FR*mol?wLv051enuyP)e@aj)aunW$X|S*}FG|Ad?v@#fH_|I-_%iI6PR z#Q%l|Z`%BeQ_&1X{S%~Oc{`z#Cq*{#jSR=XU}23{;4sSmTM%fwzsNg{f9h}23D=kJ z$o8yX?jQ8SyP>A1=<XoN@uiZ9E9u5Z75J)^A$@j@J1Oz zhAji&uI@vZDrJV!$C>HA?u|2%X!c7(sr+C}Jm3TP84@#5#iJh$(8E3wFB3{8+k0r5|J z?oseLs#uy=+SD(9$vUQ0(Wu+*{cgLRD_+g@kT|}Ka5nD9%KjxLHd(HqS1U#_EW(5( zm<5a91k_FIQW2p6%}b(QPEm2ZDXD;W&%;a zp$&!cnRc$f6t(6b^T0M^XaXC!Yc~&canh9v6Goz1+mwUoL~RH_nsS#wWXOk$Q^1QI z!2@%(TmbcsDG&Kf7>f9S-o7@!#2V-ANSieETb_xXD^??6FVWT|QkHSGUj|Rkg?_ub zRg`B%OWv)i`fL?m1dfjIx!_s zTA1T(yuWgjJS_N;8NBwaiARt!xYHmh5e(+a_~UhZ0_KdobM&=Lm6tVRS_|*wtT$EN z^$XJ~AyepWN?`^f*Qc~JbFR+{?#T(SCAHzmwOgC-UO}su1$l#(Iy@phGJQ3T^o{@W zmS;y5kC9Ho8ZcTr#(7I1iwGCZYv=7!p<5YGzavdVkgY|98lsm=d$$X%YPZ8Bh*0LkN?bCEI%f8I6M81*yG;@)BlV- zx)Y|M`src9t^=>-9osg^!ozdW5xXOK`7avz+FMF03hnF!KtN}+%Ho5)|G+nD>xAiQ zQ`jF@hiaP=jAE&|w9eYE*pWFQ;LNJ7a7kg=4%SnR6dlHTMxTbSPc@07Okk~Hd#yvl) zZ@4^S91kf$XlNlAB|frma)oqbKCc(b_dP|A$HDjgXdd3#IVJS3xo?{fMCb zC#L%U6$Rt}6h(FXge5QojL37ySI{i)k~CUDvU?+Bh_%ogVE+>L$xFat>Dcyi!Hg@x zjEq|%EhndWSJ#V14#xyaP=G31KKsf^DLsZe&+qD7eu;t|^Vk4bZ4Lcp9$xD>Zlww- zMp+5v5)cOZ)WlrGq1X!vXK5VExsi*C1y=a<(Vp4fcH2zYqivWIG-(%mu)Dq*ft=b3 z-LEX%ci+bDxTj4g3OCvOm@hO56GgmsjF~sDm9sM_cfF!dxtONB=M3JnICP>bE3%iQ zw$3Fsa_x_<_n)BiKm8jNmp`81hyVZ(8UO$o|DhrO>c+nUY1WpCTW3e=p{xHExG|s$ zYOV>(TfY=&tLXy~Z|oys>dOU-q;bP;psB05k~MAk_Nf|86h~V{;z8E=AmB?GHEejf zRaxfq-MkJg`*7Yu3(L}VXE_0VHBhN;3wzJns>Ap5WH|*rX5^}F(s3BI^W463x*mDm z{&xM;&hE*^zw3tK@89*F_oA5CuioaX!@Kiw?V*Z&1$1N`vdBxhd3N6B!wcv43hh)q zoQ-Tx=4k1rZy0aeu9Y3?SV>l^GTcrRX|m$Dl#B7aQsYJ4G%KTv8&M;8fk=7p-n5yp zEA0HO|0nZz4x&DNi60t;Un&67_HU!T8M_wXLC=eM7fE7lWn zLtf$l)TfWf%b!>+TY^gYpCD!4PV-%`W)|$?2*d<`Z0?Vnp13HQrt$A|dZ_MM#-Y9_ zB0s}aS|_#(YAy(D094h>_PDl&bmMErFO|OV?Ad-#i)f&Efj|J$5n4D=eT~8k`cwR-AX$PY z&5{$BP<+q;gX6PW)SsndIputjcz~EW;oLTk>vB}M;I&yk9FVbdWPubL(?@~z zQaPd5mk$))%0rpYW+J+eF7kVPwhV-r8WfD43pRA8^we9m*kzQC$Hpz zq7zH3s36{#_D{hnOp$KACwCBDIY^<26=poOaWC6gy0F?9JzRr7?DWtB&PhlvbeP(% zJ7;Ee7Jjhyt>8;3c$mZh^n2q}|9GlK#$=t`kQ2Zr9+h7xD{vXg6o2Z>7D$U4ueF-q z71TnhQpy;@g?R{(tpb=i#2LT|6A9mB*{;hsWTvx7I#<8==e`m&wTVSZv8N=yq&7PC z!`~>}81G2j5oA@%etznT%psOx3Pk;1BE!0*ijl&Y@+3M5`;^p32K6D9 zCgfK{24+S!=M^L>B*}e|%$W5=h@y0g?D}B!@%icxeAeHja^fu@LQMqEa+a;ORw#fi zGwTdEO`7cV`w0;m;?b&*x$%~eqNKegUnckbnAJ3bwhh6U5xVKZ3jJ7Cgn*i;?t+!1 z7%CW9D)wE=~vA`G%<8ngeVUP^Mk^q1nN`Ac%jK{lqGV&zRNoxYr)ro*(JREVWh*cJeA7 z39Q@sGK#En8(XrE(aVzb0n5+O=0jk0CR@MVg@fo2d5FM;910-c!6qS!%AznkF$V-h zMluhorx0F{5StrYle62I0-@2)Q-O%HktK6HfMFKa0Exj&C1OUboscP{1fGI)W^@Sv zJM2#t*uf4pbA85k=q`MI2y7y>>MR$|K*Q(bky&Xcf%HN(jHd}Q1*t^A03HVTOYK_x zzHd!T`BLZ}vGEBKCUH$2hG4(v08p49MQ#BcnfYme1mwOVm=V6rczgSRR3-h~I^}^d zqy-h3-%PsEA&A>^}l5XHoTnu!w`~=g#3q)?kZEW^qNq;ImxEAx8q0)0ECEUh!LObSIZ-|s@F4ttNahrb*I}bY zf>N5-q^XID@M4b`$^ChRS&o1gERZ3r;BY=x>?ClClI7K56c=%>5Niy5=QnJpa|Hrz zcO+i1 zXSXxgSolv@R$32)+*_aqWO8){nKY)Akc<@g!%3J5FUWIt#mf~_Xt4oSz43M@95Bbd zgE&&;3#DR66skS~R*9_#+mAvLMwp)h^9IM0a4^ph5=N7dS26dJ!zah!NzUriAmxv~6l)-6eS2wV$b4HauUaYJ=5|lT%4x4WW(oce20ZT#} zW4mt<1|T4;*H><9QCo}MCt`&Zc4|Cu_TH+Bx9?YnQ{bE>BFD#&`z;B2}x}^l< zF;+*+LO>`U3imE2{ux(^&>2J)9gB;%0!_B!yijO|y`V@s+V7WNT8SiKx}3(z4Z{?A z3((|i5Ag-)ya6QAQM%q}6cUL-bht>9>cp9JXCe1?p5n_jVmnw-XY z4a2;8%Ft$q5Ah64hsnwGG)H?v693*;%f7dz!ouXEK$l%LFVv~~GKV6dxvy-!~x|o})8S zE~XN9CuqOj{S`g4gy_%_wx!fA?PZYM_ya^2nwI0^c%hW#Y${1?R;T{aWFyNYXK}p{ zYmp=5OJ#uVAcFF(e(xAF0SqJjY&umheZ_u^b>Hzl=}TvEHRPPyDLdqr2%Os%??9}z z-GdzZ$uKf+e#!uxr)@&15RO)8BXmeyeS~c_I^w{mE(}kVg4A3NwevJ;w_w+#K zbs(4C=Rf<$0@{Ps1D;P-_eCBCtiOqlibU=0sf^o)+Jgka=?{7@3CIuFztBsjiw@lO z76&_=mJS>$b-xy3j>|LDrcbj#SW*lyqHr2n`2SsOARX(24d@K3-%3XsE{TR?>kn%# zsj?JH1Qe3Kx+;IH|LHNZvFOhe;B zrW8hfCta0d**V+ncDmgdjG%WW83N;*q)_i0m3+^YhNRSg9)T(2FNS@I9gMC(Nm$5h znsS2)YO>#BzX@O@iwR-ujM5{%|090j(n|L>M&qWVXnDx}t_x$(Em`@IDkR?heCrKh z)zXnP9EjqqTuH}_Ty}#@BvFiNjT$($qn*MKT|M52d~0rmg4ns6T2TV?)6S}j;?TD_ z8#Iq~T|SOLt31Ce-zGF^3t@RP zPO+JczISD!z-yHYKBX>T2FgJT=KBA`oIjlqA^Uo%KZ;x+Ub@E~ej4-k{k$t|rLE(g zP6kvlU8~kWfOi~0_aZ5~?@{u>PPLRx987XUR*G9a;&c{D<(;r7S>xT(qRseHn-$qo zIDtTDSalNf^!S@KCsDjjq7myT+tzsxvN?g_66SA)`(_%$Vq)iT1KBzen3~r05(B&v z5f~b!b;It@S{epqQPQj-h~}yivdX?9%$Ybe21l=X+lq)nabCj{ z{%jpe5ee_X8F9NPg`;EQBhvdUiu-#+p`u(JEE8W|LtVx{5m+=o9j*d@P7M8=Xxxiv zG{k41)3{aEXb8gy7%mF;-q-g`K!t9uVv?q7Gz@T!>==zK`|0pNM2%){WqN?5B5>caiwV0c3=#3!VEWn8l7nD%w1n6G(?d=mNrP{lM z(J`Ia^ND+0ogpA>R4047E6IL0w%5~*rA23x0jpl#&-=t03{Le`x(~YRB6#cj>X2Iz zF4mK%z5y83bU23I!lZ5CPDc+j9SqcFgE$IHM)*}9`2@yPvFgYSg;oUVEf+Lo0s%LQYG zU=Gw1b_4rO{DLoXlhe!g5x47y1ZFP}-ZOF&GcE9ia2Iyt2l84k3{bcIao0XkVNFe+ zv}^_e`|J{AGF&7%GT+KBpx>K?$B6;q{_J^w`#>T10E*y$o16kFTr&QBpMH6B#Uh;R zwPA9<^@lK=_~LU`55k;Gcm9s^r0~q;q_tb`xwieohCa8lt>Dj{pVs%%D`z;`vH8Rj zStwaBrEin%%}y~D&0C{v7EoMW<#IvLMI+@+af2sz=g?H9A*{fM?}V$?%dmZJic~cJ zrzzTF_~w(gpz_FOt$WY9Nf;dw*y3w}yRQ#BZ>rt>ea4;&SbBP{?9iBavH&(Zv9*yH zTkTJVTc*lZ%f)KTrpi{&<+&4ENe=pW=GNCwZ9#`FnA*T}sI$U6mgT#hhT&)*97634 z#y~94-2X>czoY6w>l5X@dpCG@?Re9o(bTJOX3fn)XRPn zI6)#_6arDn1f)v!jFl?ON$-~jF3%m&MS2~9b}1P7H&(7qyFPVSgmL5n1H#g%E-nyVA{OETwc5&CNRNZz2ZrisbcK`C`Rr|7)JUKbBa5Y@P*2J z5qthBcGvKEt%tyia>ML2OXqo@mS1t!ejmr!w;d>XfAsSg_&>byQLtanb6)-+ZHgh#^IiQgF#6uBwbs>kMrY6 z{lJ8|Vrg+&Nwj@nr5D57#|dxpgQ#(gc?b+i)P3o5%cIUn(`tfoL{#csDJo+D=I-&B zDylJY!1g-C z18~wS3C0%Dbf2q_7+p~vG1JIqTrP}aWE)n5x_`sgNrv(0DN>m%Sz{q!>a54^xQEq> z5Q{I`NLifnowcUsUlYEEOHTv}gG-FF&Pzt~JPMmIOkQF zImVo+Bsy|^VIpW&2#R?aw1#*s9zK{`8FYtuhTEW2_tklEdPZdw!yau608oO)l$&Cx zLNih{2(NpuF0Dy{PSo0ruU6XpcO3yblPYx29uebG>p#Yc5NHnTH-QLSb?pTR=5z`vw$ z!No!NOhM>~A{9_rW373vk#2MO#iR~2tjL%w(}@<$ zRlFIME>$pZ4|8^$v>i1GNf?y5mO?Z&VGD^ic3aD9Op6f7an@bNc{QS;C5L|VDHFV~ zWk~r-rl6&yU{~Zpw9sl=TLeuU&v_r_1h%g^S1ly~u*ep4VF6z| zOkH>13U?s=9hd^ji`wj5R%q^X+hw)<5Z7c++aqdlr?p&$&0|vMBHhuD@00y=@RbPA zYrvnFYtjo(rRh9;N`}cLFc52jA`i_5+xLNnm!GnT|K#=nD3jjjhuh)*J-7d^>?W(~ z*sal{`229Ie`sJA53&~A7$2d~pmN5#;BwyNfMdwgz_gCC()``yWs{Fy7>V>Eg5*%hk4M-nnl-x&DrjQAuc~3%%3(-N`SC>G4 zrL5asN+&6Au-`e9m&kkyMqkEg^Mn_aEoCTo`)x_f@ zf}IWvPo;PY&ttQ53)*%c!3arGbmzVVFS8hq$iwip9(V5qXt`zU=CZqtfxm&$oi?`a z90gHWvp|7u3S?^wOI$Oq&}>yKiqWE_hIfOTi13N#9QevfjZqpS73Pul3ReF z(Hun9Zh9Tg?o(XpYCjnXv$+Pno)5&+#HdWB29#YFXqVSklz5abM)DID7SRkf#)i@J z%7U`zUt+|3Lh{e?zvSLE=Y_~2Ac67uZ|pyP4~v++pMK|T=J>C}$%V(}`P1h8#fgD; z*xzp-<7hXBX}?($Baw*RFFoEVyd|{t#6fpCKVZ+lCA`{Uw}nwVik{;?AAorN3i8&S zwW+#F#t6#I9>A=Ti)Iv`RpOSYQrbBZ#_ z8?CfuX`15iB`!Js%92re^&v~hGjO#z)mO@o$cxZ~uoWJs#-Ic(YPk^Cg(@{l{vD0^ z=(g$t`+N4wo1PUY1aD(avUFN?b6ki)e}Tc-Hy%qBW~gjfP|+mZ+baeLo6(?O39MU6 z4oTHfhs4~>zd~6r*R`IzU8lLMK?Y&Xgj0MURwv1o6z&VY8GSy_a;Mso9ME`)O?Rb$ zJcgH_meilgq-aF@=w^<})1LOH*gf!FXm4kw=E{>wf4}%}M${%!y#2OoA?N|${5Gev zrhtCUbXa}|?|DAfXu_Ma{gWhD>7Ok)(<6R`jT?>M!x(vn+mQ>-EFkM1 z(|;m60mD%2@Plil3IG7?e_y9?a`vz`ar(CcLt7zkjUB<4@AOM3*$t~7CbvPF@?h>=x%K`T?;swxT zOP+0;*(JtZ$yCXXcj4O`gUz!O&3>YZCd|XQyiOwj5BBHV1i_9~n71B6KMTPwsE|+J z>)jH4;AvpH>P;w31o)r7>DQV#wx1n{zkCc=0a+b!ix#b2VV4VY@f6!#%BY03C;YT& zu$7KzX=KS43cP8|PcylGe{w&k+sWYQKMq-I&8N4vOC-3RE|>vk-Lmmd={I5KBr>P@ z6xjik%<2zw#$vR5ZhlT%w{~+C7qJl@Z_p7Gr@6 zUQjxs*DK1E(GBNW@H(RPg_t>@lXOOb`8i<#5n`VKgm&>A(dhRjLZNgdbg(xi~@G$j1A8iwFa% zFIcf}ec=dBL(h!?+skLa=VjDBTX-J!h?IWcn-Wqg*`0R(w9&R?T2-_~pbyuQ5cL|S z<28>)X5IMRPCZh<#P(0enez7P(riSDG7dWoP2GJ@~AsU2yXs48Q zr(=Ni%0vyS*-1$QrY}KZ-A(I`P<_D-BfS@1ckWM)j}@gJTBW+ypvNCUQQ^;=+x%Ke zPv(rxub78TP7{uqCOY}dOlBv5;;03gkh|;+MpbiYLq3JkSoDUN5ucrfM6`SLW4j`y zs{?ajZOK0^pg^cy%}QR|^qvzgsfU53MCz!H8Q{9LOd#@16J7C@4V4HiBLn#`uULOY z5r3Us91Lk6ep8Mr$CpH7`=nfXz2PB7W`N5x`-Pm|B(qPsWw(8?tpAO$)3?26obOKI za(y)$)fC*qWE#08J%B8nuz$ne>SZ&DkrqESawRNEF{MeHdOIJ_LGb&9^t|V^M_H=S z>gHy+*Yn%&dZyzTNje(Xudt6T&w=sK&_JLVq8R2;ZZJM!kV}{k(7R0w%Hz@`wJH$1 zqu1daK}cJr*IC3JJqT}`oPWdxoO&ssRiF10P{!eN_gba*)VgM$3ceP$m)Ksf^XWos z0{o6>RLG7&*Yu8dzLVb9Aza+^g|Y1=3HUl8)`W1Wy}DNk3;XPjjRHu zuF)YQsHG8=$L=bT6_06k#InbhIqIRm(?h~2Z6YUvTf`uZ(W@&#nY)|X{;Z&X8gD@uV^s3bCsVg+$>cJFg$FJP{LKx zTN8=2RZ#SZv=tyKhwwfqHgj8C6?UWF<&|stEucn|2EU=QOU(paoHErjUYN-9se}$MO2^Oo2BsWy6yuB7wbB~o7cY+6Pf3nq_q1`% z?Yb@uN>!Z~xSelLO>{ej#to^>rnENaq!G~s>dN?U#gS7%Jj4Q*fjej+?Ux5ds&^z@ z;?oj%vRK3`Ksbi4K0w<)c$MWCo8FuYHjs3@$;UGibG|9uS;DGLpa)s$S6)(9{Mwq{ zZJVT|2j)lYFJd_0yvSOgAZ3x?;2!aemi@JORTp*_259u@RnZn&A@QowkALlN`XJ^g zJIz=Za$rOSP5#*f<00QoL9!Y0?YewoMVRzmwWYM)&lPl!caUe?pCNd$jn-z2yM-hg zPbP>^L@l`i(F5hyDN#BHRokT8bH2y@Du=#_Y}A02GKK zuhDgwpg4rdc=i$AuQ zbbu(`fq&M<%Y;7j;@s@spYca(MC&}3t(xt`%Vw`PHrY5Y;oY8}_kEidKW^*_1CJ0N znM88r*!3-2?SR26t=|&r5%0I#rb9jV$c*(so_k#rpM9&=y|)>%e&WV?>*g-iy4mwB zXRQ6$)z0hIYhKsk9FXfA$L=hd0pl4hnO6NyHc%zA zU%g9+(Q1F6@!21x#1BL4YoiJuI*{2d5mD(`QWsI_K5Vzc5Y?jKsdSK;LA4=3?;8h` ziySt`^e-Lay5=ntPlU=SQ`_2 z&JfoJNbh>?-a$RD%TDgUNq6WC-`eCXp zK4?igF#3*mTeu&daR<+-wl};O9tOn~IKtH@iv1`!K*|_Cu`0tTdl3RvAcArrmF_uW+Sd8A9{}`lQj&69pcv0KsL$Ec~sRw4IOMT&o z2DHI{b!qo{jm1ltRLj2m)@Ejlh))XS(p3u<;a7y$?1_Rtdb{PNe7PMWdBhKB%z-N` zQ@W>l^z2wM*g;KQR2b+6e)ao_wk%#JH5nw^*Qe-;!l`@@favx2ECiKh6O18zdT$vd z5G66=E;mr(oTc7@s05#QwuVmX9K2#PrNRyjniv{T8O2g^5RMi~iMoVdy%Qc~8enw! zCc?u8%$!vkUw3H8a&ml)975!m104>2swEQ}t$eKmTFB7?b>&u7TehcQ+Knep_8rSy zl4Y1;xYcTbz0@Z)nve}Z*$cYwAVpVnm9&pC2NXa?0C?DAf4Lw)G3Lh_0c03IV8K=4$Cs$?66xr(@+eLOoXE+>x-z(Pjo}4K zE$b+6cc3|Q2}^6QHsX`igI=;aA)bpiBqfXiNIa=$j3K{&Ceu|#(P2V338K9wXWPsJ>6=GDQssrg+e{=F(-5A^qJ&x|XMUuG`{J ze1n<*6T1rHNPHFq5E1YfA>6p@@||c}okqo>6d_6EVnxn=4nS4xLdYAKwQK#VDcgKB zLiSce?I~QhOAugj6M*xJ$@TleZr8eg0?6zdX4aCId?zS?q7Y00|8)jmm)vl1FVrwN zbB~3f2TdU106Ts?XNAy;j($OX5Mt8B9&uyEzqNLAxeg%<)H(_S6tJ0R)Zp3XQGVnJ z`FjZjcI;fhCIx8vfS^pOno)qr>UHS(7z5tl)N`MZj*)?hgPq~$9fixcij;h3jkIHQ zR|!*8nW^6bVmI*yORa;1MYhyKUH+_`zr6Y@N?GbJ6}AS5aRB&P7@;o}+$%7>%C*OY zc2<)Qw0kSOAVwyQREY_vd4A<06X(M9Rh z6x`c6<-bKiD#WpgqV@z+PQ-uhjU{PGN5}M!DLTT>v*I2mRYUCeW0cb(3)zj)D=6C= z+<|X&aR~NI!Rmv0&v`tEVp=&m<);S}(eq=rUC`o&r(N6i2e?1JvBCgYWpgkS;K*D1 z1FaSAp8f?bPABGm7Nm`r3Y;Y(kNm00%aYV25b>Q@6SkLDPJQ`>x4fi9>2w{BMS-wD zIf>akP+DQ2D)5K&2HoieoOzC@p;!2O!iUwr7Z%G%S}8dlz8#*K7#?WWp$QyD)#8PJ zix?FN3Z6BWl{*fwn-l{@CYmN6HFO6zCI*8(#hz`$rqgNUlA#}o%b*OV*M>V<8x=R| z!kXNOG4~JqJS!7Yj<*o>;IYVgo1`52T1d;}ZSA6l53G6;QYwSJ6_HLbx0!^4?CGBW58fSc-jqeH! zRn*K;ebvq(svZ=-e2M0JG>5O{V!!8h=4X=YRxQ2S2eNg%K49y9H%m3+^x`4BKfsEaH;sXoO!4@(`BI^?@<43LB-L-Z-+0jyOgSIDPH zs1UK15R{?>3yE8-#s+_Yl{$L{X^^IQb{!?OYc(7JswogG)q;r{Qr=+ao;WE9S;hB) zxRO~QV@!2=Bsr37T4K)5zl+H{?u9=bWAXLZ0SSSi)b2~L@=WIRAu)UTDvNl{{s9t^ zlFJDo#q_i%l!7(hQIk6n9IhHVrAY_F5;CzDF61|+hg6=7P?ue0eWeINO?4h$y#nZV zjbq+(S22{l)?TCWeHp=z1I4@h48t;x=}@l%|A-A54P^IBda8-~$}7{~>ZlI*<8*u# zMxO6pn8E^ue*Z-CNt{m(_8Ua0r2KCN1-eZm>%jMsL$I!)yVa8+)cv5J44L)Ayewh$ z8HYm_iGBpAetCvkNs6hACy;}GCD_n$rK#z`BX9{pOS5$ptufV+*#5pN7Bu$L^alK~ z6c)^&d^~C94MhrWOqO#2p?WYRORFO4(LAsK7YSY-*D=GSjT%=adipE@fF>8@2bnL%05J|Iyf$N)P4P8>c5uyf9m{id81%Q6cBa3WiO8scTq=#z)p zp(}CqakRHT~)SSeV;k^DrAX(2A z{lszmxoC+B7iLD0{`Ac^+TSlAIf{@Ikv(rL_`fq5f$pnL2FBrH41$_Apj+cnE_Z$2 z0;zIwdCr3@<^2-Z2H)0+9cV8l zQ+>D~!sa}sYZ5N>CX(#XUfVvw?ZkDwo?s_A&Dzqg^}f74T;A_5<(BE*;dL90WtC7T z_b=0`ulwFKz_twaKG`fDyecW<%$ZOnAy6fvb&CA+C79~2>mF$r<{s#_#>^Mr0LHO= zH!Pai5xyNc9!$^S=-qkGK6LH2#%>tA-u`RP+JZ1F}cTj zk5f(OYGW<@-;Wt+e~vG5)@}FMkwUM*)7=mj(0!7ug(VB&Y{1hmhc+&0>%lJ$`5The z=Nrw{BlmO5@~9LWMdTXQ(@A8+nJ_P8rcb|9Tl{Ci}Ltx;s90olm~oZJa#yTPfwR$)xoTp4PZ^Tv2^5 zt?Id7W?)a9w9pQd*^D)0ptU>KX;DiBabZzCj}L}7M28>e#ZwdOn7DoKfn4*%{c?=l znWiI-F~_iG=UWhZ*J^^JG*ECR_YDKQFoMsEKJPUEeYf1G9oW<%Ps2ax%<*PtneXc( zj{*Oxf%HAJ;fvnpS~;)9%?jdf1b_o|L+Qq;?6i4P$fo*kg%kVeg}r_^W!iJ79RTLe znl^I)I&RX)9pfj;3=P=0NpkeOBjCM$or$Hno;b7E**stI?n_!z2}^7JbDeqIU`(6#v+b0fpn@-yjjrxgnZdoM`ObMR?f&bYp3X_`^W@<|ZQOliJMJ$#y*DJf)+7w*dL##YAf%52Hn2ccx6dItCU{Ve67FcW7q3smSOLH-Cp_uRb6*~D*ai#3*xT# z-vX^}haT18-z5(Sqv(NlbSKy0$sRxKtRKnSN%jq;{&;a(gpE-*@DZ^r*|NHBla+yK=zxY)K5~y7ny7;0VD~iAO|wG5VUUr zIojc@NecwHl?2rG8VCR#GnNsuKL3W*KM5Wn76t(3JIOp`+YP{U2x*783xKpEB;8H79&q>LkUCB&aVL6R0J@YhSpt)d_ao*wwE zh$)~d*j@nt$q=}A&cHhs08_&y7YH&igSr~fA0c|;C=BWOkZ}KiK0)E)T!S!7Fxy=^ zBJF&b*qw;*^tLgGrvwDnUi;jv*nW>@jFH(7A|fc5sit84Ts^l}83!Ej9im=_!9A3c z`q1$DQM&|8HN*^@Rhj*E7%`7|c3N3s`&`T^?tv>tm^rn|a11fm7a==xbx}JmszQ3a zfH6U^BxSfWvcM*7LiT5nE-8BB>2hI=N8n(igy&8fK?Fk7Y5-{>LrxH-Kmj+XUJ|s? zDS!!*b(}zG`1&q@BuZGo1dIiGxHG62gbxKq89k7o41-*KlpdzO)kOV-7WOX81n?Cb z{{T&#egj1ephi(LK~BO{L3?YQ9p{X20+ z9yfzEhWHdvWIzOgJq$WzR?eF968rMSgDGtTmwMC1&6nBag z_u>?JINj&`x;J~D=M|jf%9Z4g^|^9S*33OKYt46M3?tQn2w{BLnhLwC+k)`JM`)&V zrOZ)tQlN#kuZs8JHZu7_(JkPZIuKEz1X7nE8jEc0Y8 z5R#XU_AnhY4pJ{ajf1v<7i9f_f!_yHm!e70H`OIoh_d&c^?2k=llBTGb2taU1x1TM zIMaz5ScG4~MV)~zkQzSk;hcgMA)?I~P*dC_STx%zv{Orr!-XDT6tYcNxWEbH$_>v= z9A+AlcvAO;aq~DsH&TOZ9hpBAuaA9r(6p~L2(Z2~#)^Hv6y6o?(Dajper7{2yi2h? ztrx0IzRELw%slFO%|^inWenGcPYv6!J4w}7(1YE>7qW$lR=8UH^NT327+KC>b?=Cz z$+C3}V!;uub}1EtU0ymg+og2oFq~mjGt{(X`Hr(nq_n5lJZh2F;nN;R=E`O`9teGkbR^U@XMIkwiA5q}>=Pz52kr#ZoABzd5E^jMH7@p|{UwTd(G#IUXD?NYE16viQd*SKb*R|ue19F)RB__CS;TA7O_1K3h=o?C}Y zxu@b?bIoh0@%_YSM-@zL!yV=eF+CY=8aw@<(hWO`5#D1`fXd-uSAEYu$U2C_(PpUR zgy(HLW*)@Cb;355ToGB_o9k||JSPjfbR)1CJ=Ij6Zviov83VeNK;=r#Iz>Y?H7QtQ zQ33?DY%a4H5yWH3t9l!4eEskr)i8=f-xP8oYj>N3OIobX3?#}y;32HZA??_pDYvri z@OIT66D2}5a@wNV)u=FWoY-L1?toCbNZkFXSCc`hMj0APlvLHzupi<1ymd>Q>}ouj zISfue7Di4Gs^4lB709=8?XY*Ec@;!;$VO$#;r0bw4c^fE zCNX85#D&OXjMG;)tCS*VA;^@0WwW!qQ3-8kQz}4lh|J&La60V{CASVRsfhtJ>M&%a zj~7b~nbF$BNw&9!nruAq^$#B!e}$WYMofIT@4^Yx`qPaF;m9e zy}O8AX=O<_?5#2CkE!if#EqJx-yl}2y4jF!rm8)KIJw$WW<`>oXJ9a`%ct#*+?zLV zQTwOQ+ndVSx{5^366P(dOP44zD!M6m$~Y-d%g$=O(WJUjvebgAzwox&yOe>_`0BFMoTs zq#cvKF`3uCf;Vc_{+YjQEM)-7aNi`}Huw?EX7hc)<8oEjYCSoOVIVTG!V1}*)a4DU zQ8Xrbq08Xv0xgL<-8X(BAm zv91K8ggx!+-PL|ZWA%M=Hr;lsUjNQXna_udPI2=X&DidW0a|kw6iMT4$gIo#;@TkI zH#!8vDboW?Wg*PNMz6*a_=6HG`GVmbh+ut(fy2J1{V`KNcCLj`sG?!gZiO^d0n`z*q)Tw?-x{w|1_!^)8kjb9WKIrTjaetI%)dm92ev<2>WPLHqy!++Nd+{bbJcw z9X~b_cME#G&OhGv*5;tA;x2h};f?;;FmYkd@yC>*(JcETkyUoDxGIbBMyKnp$s}cx z6QPO~0Ya7a@%J~D{0rV`8;*fr)^R~59Lr}vbv=@9MzpD!ERHj~*$su)B4-o~r|(K0 z=o|11)0YHCweB{U4O0e&E?48S=877fw?|7|UeWL#1QkVFwy)QzZX1S9QmeqhaedzJ zu@|FTg|Qr>9=3R_XKgRfQ8#?|n95eAALtJAWS@T0=AXoua4VITVg~QuWMr3gtIjiJ z+NfV6i?~A%+A&wB)El*MuNi9e9FtfI92&t1PEQpuG`q}lJ9&CMZt6z0vyWz}#eUzn zF0z)Bde+NfdpdBkvUjR>8ODNhnT0gV&DYo`*ts29#V^U16Q(<4=&_kUZLs3Yst~ zYfZzkM%J~kb65Wyx~y5?&5E)2C|k$*x-+S@dD!gk*3#sWRy!=A*6WL)z&guO__3P4 zFv1KDB+x)J>YK3N=)uZ%x9!O!OVtL~H=Pi~6W8>2wt8qht`4@7Kvbejz#9le5e29s_G&#KRF3$QA~-%kw7CLjIYTN`7Yr9329j&>9Fg&D0<` zg(!0*ID!gYqDY+W+jUeK78Ec4EM%_7PX~`{N1k5{AFjZW9-k9SHmWA*mPnO9r!F;K z+YlG{$g4_>1hX_IjKJ!6Cw`W*O%C-A8@D-sFnia3FWSJX6xaf*uHQm0Q*J)lv>TMX zh1SJ4AWW~AMzMxz9zS635+90=_esh+@HBk|FY|lTm!>Q!D;be?;V*H$fH3SLmMnfa z9;r(0#P+W3k1Kfy6|o&R)Dlr(s2@Y}{j)xnL~>U}0MouAWiV&n_}mBjiH`Nw6-gb% zc8vgJ*G|_L3omk3ecztm+jFv1HZYHPOD<`dK^ z=CIvcpgHFtSt8c+X&<9O3gif})d(FKwVlW^4oSF$s#z2qMWg9J7G1SAA1SGd@kdoL z&=MMfo@BAtOt+GuoC>_;l`gC|b(o)d_{MC?guCQ~&G&;Z0H$RPM$u9hIN7v~KrSAQ z<`zpKVNBT`TM?-O{w^B{Z*sqjYQW8|LHyXM_ruW=?7L;fs?lX07+~9sd0GfE&jHfb zNU)1)7!XPM`a=Z{N^x4gq3BzL!#-BlWjrT(eqT{HL{QqS0+bW$8AP_MVE_H$?%LL_ z4{t}GQq*cOtW2ngpp4NB*bhvzQf)Y{)(_f67_|gNG15AxJiG>Bx`B05azgw~mF7nT zrY6_E7FP`+))T5Qhdrc#+%?wtw~%9mI$*l9va1$s=ljN>o1FzoKa)@G`Yxga^7I|Hifi{znH z%%pB@r}XZj?UmZKavok%4s zu*Gp0A-}JNMTrRz!-`PyYda~2`!06kgea*a(CD(xYeEBzU;&=&gY2KA(2n`@1O_n^+8!c8X z15FXKgO<77)F3-{wH{ltjo823)S~z3Eqn(&7~z@DM;Lt6#q^Pdn*xRR!??Wlj2s?; z*4)La(U1qLDMSGsp*mR>+~=9!p8uTU23A}X zZxc4;;61QH#b;%Wk!y?vL2`JY3H zXk6pY2iln{sl()Aw_i#r_Nu~`{pEpkr_V6Ci5$h>E`{C3PF zs<6HxsiU4|ZQU*Ww00Bu9OUl<%K8D|{UE7)CMW0~zCK)D;d>^(ERqs0Oz4#yRCrQY zfa4%qKvTl8D4s8kN)pGr)pu`C&mRwP-#uABogN{AEUzn@6m&5zbGk{fc5^F?*^ztj zZ`ySb~+kh{o}0<}8?Xx(X9X9~=1215x#g-YFzrX?OE?OXh}&ZPd>jr>pG zVQe#d3NU0xY*st>&5T{Mx^_aE7?3gO^TT2Mm zNsP97-k!WTZ55|$6ri;cI5M>a0?Fb|aC51_%sl5F`l1z20u1dXRVP}#U~r$EMJ7Hx zf;e3zIMw|8SfD}7r_fLg1h{KMfJh?)u(qznkaQ!Q^gTVUtcmgkSo~Ij?CpnGF8p_d ze((Sy)nsoNK;N#0nZ#K?E|XS1n}{S8Dd(w_@u#o|*_krSNh>0uAs;^w4>ZvbSpD(o zUSk8v(XGC!WCrR2z7Sq&=DP}daB(0@RNst@)`3TTPKS1sbaN_lAiiA)^JC00&6bmD zE}VHOUO-XyyG4i@3x*`yP9F(OmZeKzMg#Hyz`iZ_0ICpCTvxC=tufILB|a!qOKAP3 zV+KDxY1zc`?d%Vt2YE*&9k{7uw&@-fF5H>8A)T2IM&L$f(5Hu&YJlL?s#qKv;wGCz znq2N>czFPZD@NhyyiNXl2T$KN=~lg0>Tv_p!^?3hk*C4UWX|`o7TIoO^InIB0R4@- z=Of+tV7nbPkGD9E6 z;^>C3D1(Bb4EN;;4wUan)?CKWkaYICo9 zQ6g4R>eUP}6-zL+72QDIV^#xk%X&pM_#Zk9WRfAyFd9^Pru50qmL3n|U=A#z`1Yssj| z(_W%9+bOMYDLTS*gJ{O$@gaUqSv6IolH%dy#tQa5k4w+^Bd{SmmOjb~qVU@yK`Tbh zTlm-pNyU8|krtZTykJL&tVSqb-eO7dejRcn#`->s0&9VyM0QnqI{OtY+mS8_(tmy}e}V2m#+>r~k(b-kCA>4_s^j?6UCx!19pcguAFb)U_p&hxk*)yk z4hLj)?;D7ot~KZ-H%;N03``>FH+BYx0&}8~b=;?((t2-(*x1lhYq0G}UZ*dW_$p$8 zbr%JXO&w#rZg4P)GhTb;$YBhQn>dPnB+9~-Rz)@L--v2ayLXQ|;~WJo2}xOL70cLx zaGhW&T~uj1Fi=F0?c<5tRmJ-K=VG0Nqs`|VhTfHJGuZl%YTF-r&_|oyO=3$_^lcfV zU3kReHh7IP=^%M|EZRJ1xYY(7)+?)z1n*+LPg=AEg1fDx)Hn#6li;|NoM`y)TMV1d zgb|rQ`fD#pA+aX|V6r%n&^=9%B>SFF;ZaFa*3Z6kdlJR??aH`StH~nDPX!4G9(sgJ zWKS7>nD4UY*(ahH54YRr$cigeQY`)+2A*n%ZFD$oe(`(UlTaiS8P53u#(=pb2Y@eWS_{g5YP5qLqY{_ znJ8;X$}q|*D;=xoSd$F!^EW;}SW(g=QN~d6XBw9FKzJPhI&BI2<@)BN`gzMD&tpo| znQ#qTd_Gg>D(#|g@J-(Fu>}N&x1%;W*Tljn3ge+P-N)X}FV{5e8VXRD-S38?mXVj( z>ExJllc&ZBIzzIDaI)Yq`&Nl7q?@3JXivaMY9Cj4JC6n(K2hwt+sAGny#J6we6u0) zbjRap)=_TlB9`-0u6cdtq#JHn^s+M1z}Fe9PL#_sqF(xOS5mQVY`m1FyX`1gs})QT zGse|f+P5ONtmhQ3Bo=atv8@ao@cepz0_5%Als6Q4Fih)*hkOh4ET;+Mi|;FiDZt)vu zpBv%B>}qJCwHb0^$sCatl4+lEx7X2E7qKVx7~+d<0-v&c*2|A$Z-GZ%@6(IMHv}eK zXr-jTXxG)2TG-+AXv^VAGBzW{Cwyl#+KK8-e$ylyQ6?jQ_pq6QF)BcE*P$dF=!UT+ zy)hQ)=u~-EA(8&g2GKW>D?qk8`J9sw>=9$jOw?1Vx?CE`4rB8=@T@dZYuV|i!uN!f zF<%9rn!ee2)mABBrH;?_*E@WPm;}EJ6w z5Crkz&{gMSs|jn;K*TO61qd7gOk}C&1>&#onB0LDoO=8Z8Ua#|Y%wBl<|*c}Ci84a z&4e~v`<|$jG9501LtWM5jOdt4OIcr&WvZ11(neC25gp*_ z>uZ3w`MCJvI)fnvOo@Iw96CGv%w6;&pCEfF`e)WS|FWoj$Vl{w$*%Y zIz4p{d;n7OX}>3kz_H78d<>${zo)z+>e`-dYu;rR_`c(a!mJ0RTS8;inCm<4dfVWZ zOu5dN%#v=B$bd>G zAI}2y|1i$8-vShTp1VW!vxWltpSy#pqqF({`on*E0~nZ3yuLy=DwVd2dJe@as$Brc~1mfS38LCJ|oydVCo7KXwH zpNKnxrGkUJrzkx^c|e;DHeS_B90@8%63q-+vDrV2N0tiK?0P$mIGfTR25J6TauDzK z2aHqSljm0k0p+~z+Q>}qH|`7amA#!0>z77)j5vGbC#F63QG!Y*$3IKM8_Oyv*J@Sb z6=2EhD>H0>h*n>fB90+j123T$;K4U=%YX1fS;FM*Yg&<Dui3Np!E%#m14rd5=gU*gkLS4G-y?$C z@UU=a&wtGPv&;S`B4})9Dq&@8?eH&;HH%+Th9tw1`lfV;`n~lN64SIoh&6tmVK#{< z;83y49HM9b3vTpl*DtZvq(93+*&?mb;|BW7pop}dLW=ENrA@+DX&!Sj%CWno-ty zZa;VAX$8)Ckz}rfnmd!04#oC-F)Y5zTt5a`%n;3BB_UKruS6^TeRTCpzde4TSek#t zmv>4sqU}@($bpi855e%kx}iN)WtD&yM)>s+J(e-s9efZX9-6vaH_Wi@JWGVH^&f9= zaK__EOwT=f_4)M=0qI|oCuXrL%3Y#p!6!;Sp`)wAI8hNnNr=7}7#qR6kWoh;9BM^I z$4D=Zh>B_ZhWT2~GeH*o0$xSJY;n|dV&klz=XsV=~+G+k>gUW^=*UIGX!5?A_F-S26o5o8$fjvoIqrb9+*YnQWip6|{hD1t! zQyxio$X8izs<-+-L7 z6>%|lBNyr4L_WdeKAhR@TAW92T~izW`4j&&pEbb^O(s96mT72$YIINg%SE2W7vJ80 z9x%((XqhOUn|9@&oA*~t+ALP-6~w

rg+27P{||%OV*kXNLp@Iic}+lpiuK zbsh1j#1=K;Qfemq7-!b&Iz{H7pQsIqd`&Rl$G5T;E2bt`Mj!7ZerFPcLohx2=Ra4c z`#tRb@#!CG)u|}_74X-BSAPZ^KX;QqmA`sv_}8*Oe>Nn0mM8h|MSxy%Ue%+% z#rbpPmzTyb3t9X&o<{m*{IaaYOTbGl@!x>>=Rx$}b!Yy6%Hl79FBQ3e12dmTmH!I- zt>JrrRmEGiz3li~2MZ~qS-OEmic literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Design.xlsx b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Design.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e41db23076f23d532645a64d34a219f9f7a08bdb GIT binary patch literal 24983 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 literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Unit_Test.xls b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Unit_Test.xls new file mode 100644 index 0000000000000000000000000000000000000000..2076b23a47591c0d5124e8643cac5e1b5107d56b GIT binary patch literal 51200 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%0Dt_5!72&2h|18X7UIZN zQ}a`haWlCJ`5e1R+>@s#D&3d75RY6TJPxW}P`;pc;l&@FMK?&NqDUJ(@t$mYDaX`6 z8Gps>aLIIy$C<1VR9d(wKRh&IO}ed7RS9_mVZW#zWjX^&-{lsBa?sZmPaZPl_O-xH z0#$q|IFZ(m5MzP>cu$R{bRD4|+)v*qDnqHZg|M-4byin}1_nTE@c6^Ww(|rN5w!}N zM3Mm@UlsI5?VzY=iLn({bW?U71@?e_jh%*0SpnDB!icJ47ody^r4RNM?UH&&DJF8% z$yq5+#Pv4L3>(5nE;c$g_cw7WPuECb2bmKkz8a~q!AZrq`3>DvW%tvEvMY;Ip1=1+)(1u>PNNOU6y^UrMrF4M<#I;ba1M~PV^^x#^MJa>+6brpGbc> zu=ExT;Oto`Bg<_DSLixCR~oO}V8phEg!b8&cMC>xwFjBbnM&`cteYHDcDzylXz=$3#p>^euyzhd0$wqoHf&{@NR}q7 zZ-@Z9usQOt2cnGt@Z1jG>~I0tD|<}9ep%l}67~Tq)n5+{^|^eG1%))ofFGLc6X3-i zdHSM4B8ZZQSF-JJKpR;iL>BC^-`(5|d?z#%ONH#kkgSaKvv!?mzykcs z4gdQS@VO>L;79m{hn(-GBOteVGzBiPUAR6X5!0|uAO|=djCD)V60PJ4IzzB?nxUXa zI^AL1?COK4hZn*NSVE5h``G)!OMUd6G)+DUe_HjlN1?HfyPoC2?y?Q9 zBk$hw+1kqU4z~XkjKWXiHy++l?W;5aU1Dik+~PbsUP6n@ABY3`A&-5cnh%p$J!Z)# zsxx)Ht#KEd>2C8|#(=V8!AIraXi9Yz_&52$4s~+#D@dl;mG)j1Hf+L5nnepN2mlO; z4duo4Js;o3qi2S*xom@&uPfA0KfeEx79UQ&LRw#ydUEP0FFO`EZ`WTc0({JyUCo2C zI`JLTF zeZnC)?cR)7izmn0AT*vx1DjhFwnczh`57%q*Bv2C;^PkwpdK`cNg&wA-!@3KkKIziayHLFW^-YIom9 zx0fqknSZ&_%JxmoQqIyO4;IH4yDCMSTml=T&H+8j!PW`l47^RS2V9u0tJPR#{4D!E z1Nh2%g8ap)M1)X7f`hqYG@2^u0nhS~4p8dS^0jbN)}~+&Eq>ay@_nWP&k&KUUBk`J zcjNEgy|FW`|FZmV)*?f&iJ%BpY#e;iZO*C0R&dPjL68+YVs5s;xHT#_Y9i?AfZ0)C zDHbCtftA!BJp!Du4HD`53CAF-CK@96%SWNB=;qSuo_)_k+C1LH+-J?q z`}#)_K)C0tnzDeP@N?UCkG`D#;QGAH;FWKByY%{|>xKtj4(@3iZY@5VuF>}Hx4S{L zHtV^08?uz;%jxrPf?4J(TP!MeD|rL^DgtH7@-Q;p!5H z4kWsjWKe#8@KRny_Iz4D>94Er-!FT9T2YhITyp?3fQ?)3LysuPYR)o$`YiY8MugwD^8my0(}Y zzeYEt94_1E&Lp_LVl#+5zchhKMQ$PmBNLJ9(KvH;Cc2`GGOxtN#-bI7D}*bCsuo@g z_|1dGa4wsrMo{RPt765CL@!(cRR2SrO-QLA)DJMlAdwV=jC(-*p86t|-GGxHELyNEoVxCIx%pVBt8^YhB6soEgV%M} zO%dN7`n|MLqfA&lfv63{2m!yoyYknxk!_1xC;WT8kag z66M6kZGK-z8BiowW9MZ#=#dLT*>rAaO+K+JZ~MTm1~g6FLzjf3pb}fmYU1mWwkFps zkVa}1Q{APE$8Ki-i^fqwM4b zBdo&cY-HI2OMdv4FR?JKb>dk;*^-%$y5xL@mpry~FxMdP-kZD5pATkSD*ko8Lw`I& zr|wgb>xC)neu`3^i+-2g3r#l4wfC+nS0n0vPSC#I&)I)J=YRJx?msBE@Oy`a{b<8& z;>01b_qZtl+w#)>dVqcsd|nzTE-SlQ0TzztNF);X3D?4VctB9Ssme0~q#GfUkdh4u zt_b%$jf32RM~z}hYiH=X-Af^$rrKYN^AA}2Xk-Up%PFpRM7Pi6XBo=xNZC*3*a^%$ z>7MunsiM4a0{1$G?UpD+Lnk{0Vx>y{MbT|D)3P9s!vI|Cg0(R%WhdL2VQ}HZRFY8l z^s*QQ2eCsV*YJ?B1ed}fK<|GNt#zo14m#I`aFyVpIHXi^^H2&nQYNBnsRVFRzz*BfAD5f^by4)tHS00=}7wn4hwg=C3X@m7NU69}6~lp$zDc`mFG8p1ui0GnFg{u^9_RBp3E zjWQ!vXwD70KcnE`TFgG~-)CT;msrE7s=GRT?c-4bgAa20QlW@8mV)qjIVjzJ!N(ls zMI>w^t(Z0>zG75^lx1}_1ry`=hadFA<+CRicYJvSURKgCkWlt>T{2=5Y;~wsa3P{D ziyDOc+|KP9&F0U5m7f)tMkNm9$@k2m_7nDs5{P?*R-yv>o>}ZluuHJw8I{V!ZlokB z$Ur7!T%{Yet3x11>?d!eZv{bwq-IPEX_HVIC|39>um-QtscujhPK7nwIA>xwm@Tm6 zF{tgs!gGT}wVhx+ju3zi4j$%_o9GB$TFO4m)fx~6grXUX$ zkST*8pe~)Jo4@f1q;HTWHRS;_0{wGXij#5E3MU-_7Mkd03f49ki49h3J+5IjjN?hY~4?d4N ztr~Q$r=|bx)J;li;XK=E*5-mrp#8o#(Ye+ZO7W#OD!8VFE9ed4y`bA0YQ}CA9^ggo zdd3T}!mI}zv|r#di00f+Ff1Z$fOQMn!*Oh!wADn1*EA1L!|*K03dP|C+sD0Lj}<@b zXsK>E9G&*}H|<+6>O>LpvDO@!SK}$lAw=-*@O?#jpjjQC1*kchsN#)p=R`DOIOMceaIPV8?GfD>s8n1&%78;Kmu0c&{=F%hfr zd0j5B8}$+cF+VTffv;!gZA<Fi0&&R$nxS{coMN@L1CP<>9)q@y76MR zfn+dB<7(4rbA(u>$AIv2XtC$4YmPs?Cj7ofS4ktq1HQ?$<;hoHb6doy=F%DWgGT!I z&#FY0#TGAi;nb=MW>38L%lEgE23t@N73EQq=XVaCjSXQig=Sy2-iXly9zns84TSs7_yJ9(S(p%nU^tfTTsl2%R5_MWO2Pg@-wGDebvr6(QJZD#hI&-k%etKeORU&Mm7ZWSjz!|7&H zsFwEm11-h@+B;hvACE19KYI0t)k1hU&QLsRBOGyvXPl&0T`xdv7FxqD(36*{Ye$-9 z77aENuy8V)7U!efP?zS=U-i_U%tt~ zhJjsj3ULF^H5qCR01R9GR`dWR4}9b2P^vK?g|3i?@qilzdO}xVwP1FhXUIWZUg}C% z#V3dgv7DM@GgF>LGaU)9;$E5fov3dc@Q^?lsK#x=TX8lO1_^#4T!PyQXZ1M@sX*}- zUMqEufduOVdNhI`XNPXBYipvtZf_bl7z+l zp1$9n0S#+sXZF&8w+An3={EJ1y6#Rcy~RTeF4{b;Jv407+`vV~Ww~VAhkrU-RN>QE ze4Gt+bTdmn+}-0uahhGqPi=KByi%5!LOroawJ@Z_7bfPsnv6g0ijd#fx8*_i7g=r# zdCr1E9+70aBDaY59gg5F152waOro;HTqpU7adX=G5jcj4QsN!vSF+Jt@$vlKJ#-@= z@xisIBT^?M*CA* z;gM}4SZ0|U+aM7g*rgzTd3KcGgOt-lIz#twPo$bokme0}Os^+HA1?6wKGkCX@Nz&SW+a|j zlPA?LR1!$F35?&s=g`T@Q*)ms=BS(wRFu9U^Gg{mwE+Rr(ULjgsck7{KSQpV;V-}T znpyJ{k1QjG1H|h;@+8=pxf@*U@EGv5A-$I1ABC^rpc?je*n*3hyTk3UZB-^WF90=e zZf1Eg^pUIBYQEJ$l!y+nK7FRaoF{vzrvZnHj(8~a87RlP@HXX!si}pOg?OpwtLzVQ zESfSiQaOcn(u*}Q3hHZP2eVQ2&BJku8w-^hyf+?RJZf~@wRB^fdOQ(bVUG@2}uKk8yX?6g z#q24)E;5G`1rEeltabYY-dIi-5Tom|iJ8#=x`ka7Ovufc0 z#ldb4${JEbi@Vke#GBvylcb|lw$kPn)Te01FpF2pH|1Rr?-$(??ZNz>b4G?eHl|)v^=P~A@M6tkfnyB;`PGpy1G2{tEv+AlQ;#Q!N?b;kPLr1|_ zDs0)RZ#%8OmA{#ncZKu7NZ-H-4i73mP8=Rr72P{su3t`Y4-XV0-!mTV$`x$0J%z5G z3m-(WzcJK){x@g-xt~5}aqs7$~moo#d8oSZwt3bClzz6knz-;eU2&=`PJ- z?qyD9Q1{OqLb?@OmZ7v#gB_cDS|*o@Gn|@_y?XqRsPUOxT17BrhICq_FH`;jC9ti3%)u1O@6z#2o+?oM~O`OkD^>*fIwHM%3GK# zi$aw`RvfK31{)30X(f2TqlHU39ge_>Ww|DDD(MV;oAAhxSrG8$^D%^PZ7)Y zpfq_4$pp*s-A@MfjmpmP#e)Gzw;^^mxa+jkbC9vDn-hv2k;?2~!h4bPCgnCJTW z;o7~W7TGt8b`3n8F6p1qk=J%|a93f-ntZyeZjXQCt&@3vb(PtOWaU5T0(JMSGFu^ywgBIY;Fkyq}o_J4)n%aOljT)@ek zx4-MV#vsTw_n?jAWb96R*UaEl?XH^}=1VTjSifj7+H$@>E`zP~ag1>;)8@uCZ+Vl) z*Hj8^?likGef#eZE``Zu>)ed5Dw*z~@~4;!$*8SxHV2vFqu4!H-EO;Zl`OLjWb)Ql zdq(Mocw1m=;qw!SMCv8>^yzTZ+2mZ6K(zEHTg%%1AA51x?$rY)yv>Fi10G-r*#eVb zG=yQqDqGD<@SG;P=5;3))Ph)uUH(1jAcJIvG~*0SM%`A`>df#miH6It3(CyYtkmM5wSbcH5Q`q z{TQM=bRaHi#Q6FyA(33gYC%eZ-9I${4PiBG1;zXHeL`M!B~^?+n;^+yVUi}tQEZ@X;_`Vpm(bj?Q+ zMz9ehwp>wsoB3A$4$-|Tax!r zz!~CTg_>l=PXmnZxigzGd^VMN^fdOBUjBVIEIdtpS$x!-VCi{~r>2AVaB`XLd3in< ze_CJf{x#A4FwtY4lB*{Ebh_HiZz(0Uz6BJI@ICb2xJ@dZdD{_tnLRJ34^>f1jx~4f zYUYA<%cE@5>D7*Nf^cw1yjk4&b%inj%}KFeSICEB z*22IrAAIkR1x8vGT8UzXnQZn;NF)#rLM)JR%7{m=rlUg08!;_ow){Yt$|FsbWw((fV70!Z z{o&qGUOdGZ0OM-4dPEP#vqPd4z14mM{`}Poa`1-NfhHXTH%M_9qw22E{`^8XBiNNmBL5XD5f$3yAadktKpc5 zG-<-gK1L7*;e(&$cZq6=NQ9*DCur!oz9CyP5gJDSN{Szfq|6nT-5HB$iqyQ14#LTd z%;xQYK#YkU2eEM+=x^WUv!AW<=`TnwRna5XTDl*#v+koMq}p=#91PdFjacs>~<> zwG`?8#`5^>052Eiy9?{}UaBB%cQ7%Mciv@$ZAl4vVJn;PY5Q;+g$_`8p+JFP zc>ae#wVjVE28-%NMTGE8X%F$9N3w0I2lE9+o!P~j+-tePRhdU|PddGJJI`7kbKW_5 z(C(-va@5Xu=O8VTvh5W>ePeSb$ zo`ca)VG}^QMwt#k$4!mQ@I!I#gM>Y7T%23TgkV(U={R_yLnmZ(_D(Gk&07%4lKD4z zY0uMQM$(dmI5sH>Ssic{9SHK*vs*&S5P$_-#PA~{gn`y58Mu@m1`X!=3v7t(z|&4_ z1neHo44|at#*ugX(&B-?{6d1+;e5aliF|VP0!hgW-*t4(OdT{`Y&eFESv3yh?6cXM z(xSqlHu3r%cJj`B3-W}MJfpm14tf~L&*Kfvuj2h+id7K0Wpk`rRB=ZV%}!Jh_V5&w z8-h4Uxmh3et5e5#a>R|--HWfkZ^|jvuA{ba9=|cS>CZPYLKT9yk(yTgB7yG`VrCv$ zJzxT1Bu|^hMqZfVY|p2dO|5ghnR&pO=~6yzZPGuPR(xB8k?=lXvpZG~wW+8Q?U(4h z=XC-A!I$>)j2^KHkd>r)bI6ll0qw8nDNbNhs|-|NPbNtQcob<58hkP*fuNLOd?lNd zVuW26a?IPBor?3Wu8en84y7eEm`W{mlv7C)tj%zUcU|9wr2)OL^N_?5Vb|E7DeRXqPn~^&lF{6z#yk zAPI$>_1RVh&w|9U2Fycd0B?x@E4(pp1AK>FN|whG9ARrgx*txzI5YR*@{q?}{@@e- z$6&V?{;D7H_4e#IhxM_#KRo^AoVRyf)$)2@U%y`;|2`WM5W3>JoP$G_awaZPUgO1j zCvv6e|7-7BgPJ;f_i^`BjmXz@W<-pVokqFtGbu#!rItdb11T-+N9R6ot5l6 z0M%-mfqGc5#Bjp1aj+_eJ4oyH6uU(Q1co+}(<>ZfJj-JDeYLIo182R`4b*zy!G?)R z4Ra~tb1CWGFS=BUklfMxU4Bj={R z?_ug}w6Q_&oqMm1;BouA?dz0uPY!lOvDMFTr(1fk<@t~TU&eDqP~ud}7`C+?$ZOHs z@;Z~o(J9W>MZLA&@NU!89rICBbm`5lhUf(x!Z4s0WaGo@sPK05>GdtVB6QAVQHzXn z&@^_jc?~=L=3%C8=9?E?I9!jtDJkL#pE!(D9JG>~3>kmtY+C&J{Z+*nt6L$OvqF>ld*T7WNyn% zPShDo$NY!n$3;9o7ymH*)9c!FR@9=QZ6n_i4}&hJnzkC+RdhLXfD6*A>xce{c(oP) zE~c8KcAIE0o}669R)%nbFYtsLyG}3|#JWYk(H_Bdo-wO`v#yS(-+ptcn9iY8T0s*;?)|H1i@R-kJ4pTV;0WTkK`ou9u`T>k?k6hf6e=&FZYEpz%vFc0H@Swx z)%MWnB1%q_rWl~*!3HEFC`^?@=#kXJ3^}p~yymn;##ukG3F0-U(l)i3LW=ZwG{bvR zgMBh?-Uj>C+xtiPWuTa%7qoHxZ9fqmSkP*Nu-oRK7proOXY336-5*4^4|=G_96O+- zx+a)r>B+)8;J=o;pjHY|kJ1v_N{M8~l6OlI1}Sh~5B+bIGu(c*>qJ-{hdKd%ZHPOZ z3yoUzBcPEE@Yt^0;W`Dm3oGC*H!({{_-KfF7>+XFA5$m91;ov!D)aektpisT^P&EV8=j{<;oQdvez4Vi7BN6 zF9>EjAX~IXg%EYOZ^y5bJA4L-*NfaZlL=o}Nn>PgD-Xv6vcHvRNU9BzivvY2xM*x) zeNi#B>>o|mJ;#4|oA~Ao<@vr^@_N<%O2Vrng|c!@w{i`oOcF4YvFvsm?fd-hqp8E{ zBri89YDF>Mm|RSZ(v4$a<~B%J$hzmJwtGTxWeu=UMf;1%E>4uCB-jgN@!KT~%>A-v zMkP8YUD}X(3LRqU;EIm0P8`ck3#P2R(dSm`mri+(FC-_T$_d!Ekn;dB(Pzq<7(4ea z>HJBzu#{l ze&!oFE6r1BVsD9kd=Auv2119X%6(#_Ue?gqn#c_`UpDr}NOomTZQj+ecC%*bfFM;C zp}u@(oyVpBTsxfW`Qute{L_EYSNVV0|99P%8-Q#VP%WUQ>mihGvRjBoj)5-SCTmz4 zX)7cwxalZE@cl^q`vp$5?bh|&A)b>+n<*jTkT2oGI#=U0K!zbKyzs6Ep)w`Bq^C6c z!N+5^GbzB2i!0!J?-zu>waIy=78{VNAOO~%4_YxWgMN1WwXkl~0-Qbi5y0XB=and(J_x*&00dkyeHl58z5-Ux-XEFxfZ9EaVU-IL#hh+m5J4dAfXFNYf(Xegyg-8u5s+C(D~(Jljfg}DiOM{tTNxCD zh=9l#5fEiafCSP?D>5r6A&H7ivbR9klIia5_td#xeV>24_nuSd)~))Wc0nyRi}gI~ z8Gg@%^o?{HvBSmD*%7f};|9c!@Fzk#iLgg(_+R|^Ym@)QEjDbBb|I9uZcNztMP|cZ z#73nJGD;hyECd>X*s%Fudn5kG$A*nEn>KHe-6|)q0Kd?(1F>;~jLgPOGMhJV+62Fy z2>%?hNon)WJ*LOED7&AL-5afP`1 zxy2DntE1NT|8#J4`qA0N^OTpjkFTG9@Gl|fLc_u%VlKyCi6dN%PfAWnO-s+nym>1x zzo78;oud2Y6_pRF9#+>pZfb6M()#pSTMv`f+sFRn`HP|9kUG;73Mj)8;*EkCMeu`Ustwrfw1)D&$r^U?kEeh~^Ll z3_aP=F@iA^IYBUJ$RFJ`mw=_@OqesI_x*Z#_R#HT2KJ-$G`0<;V zMh2S2H?ZrL55<+_4^8B540&OR7%oNBDG8%|{=~PgE%Iw6eRvh((dZ~HO%>uh3^LB* zCuxGxkq*T(e7p=~-#umADZbr2kkmF-d=JXJfSYcm5Xl#6=fe5BCy_`3rH6zC=t1m<{Zuu~uo5=Z)r0MG_gkoiyx*08oR^KBH6os%Leh>~#z-NhFGtcBp&><~J+wSM zmL>EOdE#Y6-VlY$ktHPcp-N>&M0&!VQ^bv+ZVx_LZ3+uamGPvAUBn1+1@_!Pdf^nR z5yWRSzyo3LNtwcqjH#MOm9DT zJ@cz?O=jxh7WvZIPxh#^>a^;ts5vqk=yQp zyWZ_x@7tLl@8UuE>?AU$^+l~a4J;-|5h+y*N>apN=XV$JiVTq|me&s{2p&S6=!I^8 z;S2=`ZArsu6)EButXxFtA#wHUqCy`BMKTv*pz#W#!O$;*5_CAe37yd*CsOCt@AG^* zR@Y2RX)ElbPAH!S$L?76V3VbYCPwdo(wv5IdG*z$ZVF^b?L|)n_ec?PD^YJb0>f5t zU=hW~ZkLQ>j)3fL+%8eVIB8p$L<3+fTm}0bAX&bVNjJ#~q6)1)YwM0nbP3CS+IqmB zr5gcsA3B-S)LT#-6;n4M@&luK#5lW~ua-5f2~W8nQ{9?+e-8U}S+CnNh#>#%7qi=E zOVQBEXSROz33QN`9&_$ZL~{hs>)>eB%hAlN?o%uemSoQNG*da>r#Rx&ncHVfN5B5* zsC4#+k9L(|=XOOv=G7xb)j@ZwhhnZUW-b4H_U7YN$KvG9N>N?ao`mh>?; z(aqnAE?n@0B{LmkBHD{pS?OOSv#CuV**$^#>;O~`PMOd?9o36fgc4X2cy^Q);fr}A zklR8d8V_EUB9u8&M2{KeN!5ay&Wn*i+%FG?BPXpwc2*sK`k*|6X1HuzmD1x}7i8?E ze?q~o#o9|>cbD7cO8-N}Rq7+jMOhaT^wl32w>YRSxuk46;Ckn5^sd|0XMpBMEtn?n zyzxDPw11zYDv};D;ANsM84o%tE)v=D2i_(zrHIWUBjIV%3x*Ol!sN!(K46J0q-GVp z^N;JnYl@Bn=-iGyu#S#XH<8r*Ah*R;Wcqqg?X)(;aXEVJtF~DJ1Q9O6~Z1_m`PNy8>P*AUCJoJm1p9tG7YD5?3ICt1oI;sYHWYtvbcsCr#4iMaSLHpKg zyF6~z$vZiqcQC;^Mv(g?FoQXom1eH@iq=H4HmeNuSVKeM_-xJ!g*ve&MJV9j?2{tO z<0;=;WEk04!o2fv5BKu4 zN^kn!7GJL(rs4@?AlKBhw=U4e1~{=f+oOxm&rXs1IeM@FiPEsT-DcI3GPMLs(i>^XB zkvVXrm^U*>JYF7wISMRw=`q6a3eUN&aqhRcGmFR&@|G;Vmmo@u-0i+XRV1RvG5Uni z=_j51t1CzuqGI!ChY?ro*{5wfx`Lj-^Es?YYRbCq0+$ws-a=9#o`LdXYKXR=YRc+( z?@N3aRuL9%4%6C6@Jp!%-))n$iUJr?(8-5&f504#f?n}y2h zkJ#{S)-GRtUpzgn$=7r|Q!v~YqA^nSa$(NyeyW=9TbH|hE4G|ly>+bVcJ~X`=6r9f zJ7Yc-j}Ec;&!&`RDD|o9X%Y<|zNL8IjGz;?F~fqbQpD$}^6xFuYys@zpapxu9z+S) zP%p5LSJ>kx*$Kt*NS%CKiX~|aH1Gf__RiwgMjWo>FcXpds&4$-89plGvWfbeiMQ_{ zJNOb9G7_zM|GaTpq!h8W$Kvsc*bf{T>~sa)5G+h-rm0C@qnms(u;)06y&yqk1X6Q} z;TMEXL@acbD|C(G_LcLo8wu>=?P40^7s{JSo=?{0#Hil*0Ff@Zt%~cGR7r?o$1_qd zTuw~rJ5to|8dBotnARc~%F%I5RaW*IiBL+>O#IQK`}qr3hZmjxd9yu57i+3LcI55T zbFkESbXV`yc8?rCz8m7X^*{dyDc`fo!h zFfOZ#qyr*VD7sA2M@HG;6ZrUzL`|p+yu|4tsferSdn54*L}hTTw@r`%ESe{9 zZr~pydpXI4Qzk^+SDs(jN?$H>oyy?4u`+JMEpOA{=Zl{jW3&M*8Gl40@0PMRsa#5l) zA&RLyM4ASlX4Wjq~14Gm%*-X+tLO+kT*mRYT&nVRa@u?zpq01!E7z&@> zEmr1^-Qki`=_)KPxsPNS=KADLIJW{= zOt$oHZE?)2UADfsv*K~xxhQ$?Zm46!Zkghb>Ie3g9QBML`{i05?UBqy-#Asx(>>bb zUM~Nx#q`vyy_{ZOMQC>4^rIbR2d&1ce9-wb>V4XkVYqy|>_=A*96tTR<8GymS(V%6 z+5}(Na(^d)`QBpfw|k@5ut{998R7Z3z#71_(efg!xDaAD$>%4yQdk~ zNj6YFXy4b0Vkky+97m;E;I~OegEls|w+~0rf8d0*a^zc(J0dXX*CIOFe?bxttqR3CfN3yvkioLZZ*Q^4+6%-BX86xk#0oWy zqhzyN==M2i16Y{J1p;%{Qq3d%Fx#P9Ops93jaDP6i>yIyim|eDE9#f~oQmlg)aU8D zovLpKUure9Fs4WF?++B#V#!!;CCQ9DgdsD=439 zl8r?(&T-@jF3V{vIcresjWXwImso?kbFnv~V=8J+-V--C zWZeztMV_qp$T@A~f2v9&-!`i^U~8rROUJv19{0Y8uN_LUQS>kE%NvR0z29|iS5%at zmZ5|7PO4FOkDETe3=Ir1)ETpAY|D~Fjrzz*if~;0-Wp+hlaNHj0qj)zQ6g!a5i;5? z&cz@nNP~hgDMCf01?HlaMRB7)`cR=e8Vw2K`A0jgybtKaG%sp zV{`DTqBtVH+lOuf;ivn_O7k2bg>WtfwsfWthezE6VSC#+3vg%;WAxlQ(jmfp&rOl} ziKtwvqDTjfV@_#^3+RT#OX-m3X>k+d4DxL&ADN}0CsMq6-?b8o;#x9&4JCWRCpNi@ zaG+&!gGGt5UvaNpY{)^o5*sbU#PCyh!^L>m>Mq?3bhZqnUTERSicnBdTPw>T z@;!=ml7M0souly;v2P?glJ{mJ3vs%QuJCjudV@sYm%!{Bqi$<v*`I;(drm|NHpQf^bYC?^na<>6GDN z`|xj>ebmhtJM5>axpCGeX&pfrJxF7%4~>#+pKJ3E!^+Xogg8M4q$IQ!1&)pLajCK1 zph*u+iBQW$UAL$|9~PuHTm|Sn8ssuYVlFVIE2oaMi|dWa=jL&5&3HleT#8&|Jf2B~ zm0PvLf*UoF)N8GKO=1)z+CL;Qm^;!44cLo+qhUi5ILUN$7OPYpXrS>2lqF-N&Csna z&mIQ8!fe*stEDYPu#`M1^a4*^RL)gAx3lu#bMIU^p8gq9qrRHp#ob6d&BbmjkKPa{ z;~{t1klwIA$Ny4Vb9P>}_^hv!MVx9ziiU5Ro!eNBk7GsE)??OGuRnuvMSelSnkFMs z#J{P?q}X{p;DMaru<;5V=vsn-;0kmcXlIjbN3qi-SXBvnVvf=Lpq001z#=y-EnWv_ zJ2qE`1sxf6TBy<&VWF}RblPN3snMVfmdi<(Xb+jAwJc%n1}*(TRO&4!as>=zIMBfd zRbacI3u+M_Ak1)4X(Rn$PPm2wV_ordQw z+$gcM3isLH|Mea7Flpj2Ay(7I%*D#@_?XvJu#;+`5MA#sxKwj9N6*5tB78c+CAy=! z^3IFLT_)iw(^JMJs0`-UR*k1FdC@2H9(pBnUSq$*%}d&{;$~tTh<4}%kxAH}mnPQy z23M9)B0E6!9?~Sa%FkjQ6URZI6#m z@&A92Z3r6lPyeRyy>R6FF$yj09`ZNFzvcAT1(}Hd-ugcPqyJ{ee?p4?&5-|Q$bZm} z?*tD2yCmcTW)Eosa||v^p*4v(aA`qH81xyl1&Zb(cS37@@&9re)#4m3R`zo%eGjNs zE51`sn()tUd?-bPhONhboOyG(9wYQ<|4JGN4vmf7e-isX|0_zQvRm@gJ^^gmo9y8F z)#^{s&^1iw{mg?hA512EBquCI$}^HzYkk!9ZuFDY%M5L7@W9&v!JQGuT9Cozhz^YN zr`P)M*X+p9iH=w<18Qb8D^gSIFvbw>1whGI*-GX$Gy~+cvy%5;VJxfjn%vYeur1Qs zur+QV_9OX8P9dcQttIImBX6@g!9~hKpQ0w#Se!Scz2MUIRa&}4dANh|CQ>j|=qVWm zLeuDbhz4U8)Rxb)4}IT=DeN|+;7Vm|Xw5rvg#Vj?@(5e9Xb-uSA=acVz(GK|JyiuF|c7Zxl9G zpH?m3tUp@jeRp;w#l=F$twP_UT7INTuDj2@M1N#)rK2zuo9=LZ|Z0>(VA(^PTyM$+}`4ovCgk`=ZWhg#o@2;egc3NpejE#B^jS!DyP%Z zbKEWx#_RnbM^rk$I6YYDV*b(5e6}z9VWRh`@~t(Odc*<9r1j?Niu<1vJrz=VglZ+& z+B1(LF>aRAvaXyC1-@ytUN_TPWE@9cF|C{?a0v8>KdPQu2BYoMUK-^ms5b)PUM6M8`o2 zGb-D^;~Gr4#J3B?E4> zH*0-#I6IvayOiSp+lb_c0Fhi$@A{E6(1)*^VzZ$RyU@?0Y$GtHZG|EufX327aZ5^D zfJr|fF0FjfLVT>pyXf77VhKCB#nt{K@SwK#bL%jaAd#C9?j;29kCcHk|Ag>06VMl7 zpY~xWC#qrq4B#KA1hSY^Wzycyh1#0nQZH_!WFVf(+C6X$zg=QL=yx2ks5McBLw+<9 zx1F%&FGVC5_n|b>(i@CBf_ZmV6Qlmh{6>-2kK*4dND({I_;A(ZCk@JXS95)Z^94s9 zHvaywt`quXR_1vqdu6S_`oV5Ro3r_22MF;yX#@JF-o<3PS815Kn3wA-=Nz1MGwT_w zPV0GfC}^%gBPC+wptHeXxp$@h#Y5Ex+c{eqXO`Z^O*_nVb=q@rOeExR5e_^U$s|ii z8SsdLTuFQ8sXz*>VH6&6D^%V`Qu``$=Dj~_0#|O&&(k*n^=pEeEaf0jyF{EX2sH3% zY@(0UFWJtp;1Ws4Za#Jg(FVk2n3ETc61cdGRTFi>7AZn#@6{yf1`pIvbCgBc5et*Y zZ}9$a=cr)-CA-79LQL^*9XY>OG9)CbHAY;yf_lQRA@`t!aLst|h2#%Bl#Eqptp7an zowd>Cno+8Wt;?+s`B&|WE*0)?w5oGFrhM={-S4dFn>z2q?cTA`zIPq>mgh%|>h3GB zeE7|4u5U-p0?k7O7y&MG-IuJGvW~fGO8Fzdj#R&P_DDYajHXHMwju{}(!G7GNep1J zSIv73uKrf@XD7SyyCt?Fi*`6=pIcZkQPszgGcJQ;FLFv055j^8fz7R;6Km<(>vwFx ziCt>q2&QFX&=IA&1%ZA-tr&r}_;!Z_82J-4SWUDUDeR38SxSk$N<3OgbcU+$5m6vI z!$!6uAPln+q*AbLqPLnDUw}KVIO^aQny3~7O<$GVRVumq-6xYQjuiVw~-S3siOLv1qwh9}a!%ltFr|g(> ze#zrzRAt6o#3|#{19^?Vv5p3gr5Y&fX0ZCI%p=Dyws=|R{P6;UZ)($u_;hCd{vaVhEN&sz*+!DY#i2aqu~NgD&_PgEgGZcs5Fn@;-S5o8M#ca>UWC+XUd z0Z=p9&Dm=BhpRb3t2z0^=0ywan_)r3s7MCP;^xmVtx(-kgf{&^1X-Paz~2{^&I#|v zheZF8r4^%}i9Z7DEOXjUKSDc~kz;;=%+yAM*kl_AVEigUrPwl0l3H|QC3n;=wf!+#Icw`n8MLg5i0@SxAi7bP;7c3>ptYM<%gV~eeZCaHn z$%Sger(wY|5x`a3@_g}c3~(!)J6`FA5!QcQtbV`j7DpW2W0&`l9Df;T@;Wr~X)W*2 z>dum_NBEB6E=5^BI*$70Kitpzbu`k4>9D^%jh2zUFTMWw1($}shms>tJt((sOjdQ$ zQ7IVj#lB$*euV}=vmQK({sW}!$p8nEjYK9Ps(ne|ZeH5;4hz1PK^Og?_7Olk1tfQA zZvv}QJ2rsBOwtDM>NC*tn#dBYVrpYv6IB}`;>RkviN~DV#$)e9mCz)8*d~022!K7NQ{4ypx5F9aMf z;QXuxVfz|$hm+=sG`MDmUtE$RoD76}$h;kYH4x1v!MV%tte$Evv2>{T{Os)hS@RN0 zL;T@hXD0U(tJ?Xj7A>GCXz<0CH941(FrMCvldR)sP8oDR9lOyrB-o{+(HIf!>!LW= zQ>n8Wk8iJhuDI3QSiL6d zqHdUTGUV4i6SY?0>M}-ezz!UnzBQ5dW2SQWbyJuUt#=eCA|t20@zO% zW@B~|9mQ2Pt~JDe0OOe=6v*dEs35tAr1l89T0;o!MI&2|Vl<%L+?h;siV|Ur&%`K?K>=FTUfrQje`o4G z#gsoEojOpt-Op;6dG1^O!NFUX$rE#~!?7wlXePl11>ji>dAk1T@E{#=VTUfL%f~L5 zPE)R{Nsf%#1Xj(Wm2lY=05X?&tYMa{^u?j~gFiXN9HL=RlTOj);bw%MZygp_A3%?_ z0^9%`Gw0Zk%UkL4M9g3rNbaSoiV^|awVaCAa03lmHGpUiIQ0#rlJ>*-;uebLJi7T} z8Nle0s5FyrkdROczc>NzIvT;NJs4eGwC^SDV&Hebn=QD4Q5_dqM3?(Q2J5Kr>D+e} z@u9~}*8@Wd6^n^FTI9vI&R44~nk>SP6g#)HtVd8k-CA{~+C^X$iAuGQ6k!jQSBJSz z5oVaB@^EpW6YW>9=4l#0uw)l8l4Ch)VUNS+BU9!?k+T&Oc% zyb!f&Wr8``3WLq_lD;Q}X!)7P5T0kS6{9#Cv>RATYR^*C zRAn2zaPSCPk$4`81Il|_ef+Dsm(s}UD^xULA9s_Fr3Rj9E7MbC^Yx9T&v*6c``YD^ zboo7M%QUbYd+3Yye3^$=bnLs&6H_lP(y>~8FEk&=Mn7%KS>{C^eJ1$|=hto5eQ)>e z%Jf{T9#2-?ywy9IrqOt#hnp8{p`)61?`BXR)yQA~(p_4h)Ijrn63jSB4Y0gzrR#1N2d>duw-0jw*fSSW28pBkhI zj%S|*3n>gP9IM`+!h+?IlX!XZS(CTz(|-UXQwjhjixx|k6aAwNDyx86;p{v)hodec zTjpFO?V2NR2_A`s!#nCO`d(;>9b`DX!bn-~E1MqJ4n_8o_KbCyaufH4u~Szr=zkg; z;>qLxO+}M?+U@CD6N$uat*#0))X~3HdqVzR=P2B;0tb+vC*Sr|I=?dY$Sc-w4Z2tv zw^(ESH1kU=`Kl!z<)UKhb+_uO_0ysqDVh$B-{w7%^+qlwdpMR0WhMQVoJ}H>&~}n& zGe$H8#<{dCla5$mQlbhsJm9j?iljXvD=@XXhLCk?)W!)A@^Q>1G$E9ay%BriCjz6_ z-?%)MOGeM)$kS59&dAcu?aLjgnxN0hacwgTEdYvzMZkSvZ^<4|VgzH;QNeBENA*gHMhiS-0hJGm6Cu=r0Upez$(3pBJ>%#!o~4y#kP*FTQsitO`Gq-L)S zsQ5!QQ$}Y9Cf~*1-$&)QMo(ppSwwoWyl@fupZg9~2Hl^Ct+rE2vA)^C-PLD$(|P~5 z%0)fzcEL#aNTp*vr@7Ll{wgnGxDuOLVtu~hhzjM{tVWSDNM=Q$Aogh}1Jvz}Ya45? z4V?EcWRX>%$G9E!eE&$M$KyoEaN}u^YRk}N#bdo=6G3U^ z{%=CQ1Hr!w%MWLVsyjw!m+QHBWZ%pS(HrdHR_Wwy7b;gh0^wNLj(NZU2QkxF6Pm3+PT7x!> z)tM`z;5uhFGG$#8?hvX3<9f9By(X#)tq6aL>>z{Sd(dzX>DVAK^nL_=3wYhSmzLRF zPa5uxZ&wcHX+`-AJ2xF6X_8l@MJ`s&m(YWQPQ1!`5CON&N-SU~Nx60o zN~*T6BYaurqPx+%ME2u!1<|e%o8anyt_A6i(3J@?-Er&usk!Qh@7_7o%{@%|G4$}myN>~f@{b13AGQ2*j$i4L*O1N& zmv-%Z2a3ChnQ;f*Xb)$v#8cB3Y<&c-fJqh|EmC*Ivg5I$eIz|FsyAvvm%qJ|8^;)4 z4WP-f!6iW&R0T3!VbERudCjs7Q&vy#bb(TWxrth6&S=zE5L9yaRG<0cg6Kf@!4IsnnqKeZU>?{YUk zLQ8lsTiBMCPV`HNyzrMt>kTp)GpaXPl;qSs98N_eofI5x@(z9NbIUXS*l)-@-1iB3 ze)Rc^nAl}arh3N3ON9n?v%??C=do$(RpNTJ`czh!LOIklcT0YOZz5C!QDh)b4ou&Xz)7v}zA<@cr;#+(0--SPh}S^ED_R#X90F6Njh9+!nz z>)12h8NgM`f}6{x^ntb1%Oju@6Q@p~1$Ih?p#ZoYy0EZyqTv>Jt2>@7B11!8UQA4I z?9!e$J#Ibx?)0Buo&CbWLc#rDDPmt?m+2qqulA%prHr*p`zp`QA3suWv>WHpb|o>P z{F6R-F2JRec&suz4_KW)^NH(1F{rky`#kdT63gM~a*vBqWo$iVP{UxEi!mmRz&(m) zv@X*=@`n_WJy!VjY#kfK3GUyLgi@{rOFrXRW^btLN8M+gTGPT4`$gT+L3pD_(2NxE zE5Kyjec3$&nG*oO-4lfO~v8*-`3$NxTWj7+8W zgh>VcBdm*83!YLp8$EgoZ+7tv`5SHEzrZNz+asZW zCiL6}Cv?Y(Mqq00lAkk(_O?xMaC*#pJW%|wSQ3HnGL<5(d;_;h5laJ^q(QPF<11eB z<6vlW=^MkCc`4!$UNn)I;y}#Nt`)lfXa@IdADf2TE8F9t)CA;uo6@|u$C}_ik=#27 zZ84*MYo(-zN)e=7N*JR6|II{-*zf-;*yz!&nflhQrDZnS*Bx(EE*ZhWWcW<)`at<+ z8I>M-Z$PYduvQPb_)pHVH)caF{8tXl{(Yoj`G~lQ!!WOijLuIvYN2`;3WH0ZK##=| z!t!jJ!Kcp)*a%&=D3Eb27`u8AzhmG$oEsdGe_VuJbcBt6Ry(jQR8r66sY?-@8ZD^m zPbuOio{0Un&mp%)&>uZe#V#Z-cdhTu1Q>7I`9^7MN>b1!C}Z;&71LTn2<}ZXvNe(H5Y4-*_DZujLJ=Y4hbsPdebMPj)~v}h^4Fkqzw?MHPkQ)N@v{_ssS*0JJ6=gQha7Q$Ejn#-Em&8Q z4&(X(iQ9QE7U=V@3(fiKLLbVq%vPm{;*#~zgj0g-za@4wdb@VO&)|UMeGlpBK$p-l z6PmR-E_8n?D^c_5GNrD!a{eZfK)yTrbTw)s7x%520aHH7`J29fU|-pW39`Pyw{TO6 z`0AK-?17+*PsM$^0W0G0e2u}!txMPl%Y71K%HNw&($gp+mp!ZNF+Q+KN-c*KU=-S7 zO@7%XvbQCFnRU7tUd;*Xmm+kehz~iz#W5EO`P2af!zOxFRdw0UUosMP9oD7b>0JZj z0P5dIz(Hbza&a;J@EallvY5uD{}vd&JRe_`YGW+1fZ_Hc-gRh&q8SAF*p1sbmxn)! zbPRZAF2*eRD!qNxI#FSAG1y_$q%zkp%cH%?^_XRSo4?TVebl?pWw~B+HHVqJL(BPk zqiIjp+dWf`dZsv`?3IFE9j?bYe|_%)erm4&lIQN={!RtP3jg)NZy@mbZ1zKmp(p@I zyRjOT>~E3^CueJ!Q|iN>y=X<75MJk%H6e~0#bjs)1#u$UaDBMVvoI@nfR&^9EiLpE z+-T83yeoT(}U0SWX_m?G!Q*qI`+vgwT=tH+h^CEq6wUx@ZzPeaZ?N!%M zX{Dp>V%Gj?>bY*r(uBeCBVwrdVFp`t0E>WowE9H$a4-JvwQ?X?a6g&~xned@gk{tn z12pmJ-&P(9fJB`&lVzLO-nZwUl;y_bAwnXZP`+ZEDH5U8un~Lz0jE$V|Kk5i+TW6K z(kmY-6S^N75b0w7QVH0SJ;JVBqOT+nt`xpw{5cryy0$B1yL^e7ZkOq>Bn-(i8<%{E zYQaWo!+pa4GKnZ9Zt0t!uCx)YaO1lYn;eKibp5~gil%SKhH)W7WDjdfQ%UtOi`=3t zMZ9!|wqU<-=zB`v!b#jx74dzEANd1A^m`=czMwmpzJNMG9*HW#JikxJXe=%M(~-;# z`Ac`BsBk8E{h@74+X6DxS5GL-}e(PQ{fo`w+MT)3>uvV*ZLFj%2 z%Ucl1sKd7YRt%IjOI^2)Kf1y&tYa`I;G@22x#PT87)-@y!CvXp@@%}pjOs9KYX(Gt z1J{Dls~53%8GM*H~xqOrZQA>tuQQ zjhiX)r{<5l>gZ@Z^31&H=IpGuf9RI;)XRFi%!3ai{-esOez&cG-bwq7F@2Bo^$hyS znz#tHXdp$@g!biaSY3pHK6(#ni1F2rF-^q^;^^j5#25^sYv(7v{T*K1gbTZyV3};{ z1gj*EU>uDPdc6S#&;R+6{j{Bq<%uN2Sb-OD&pPQ9exoA!Xpk;E_J>YI13p>_y%?Cw zDXu~{Vi-{DBWmX)yqg`w3;k1d6U?;9xpzce;lfC7{p*mUG%-cOiDe`?xMvB zMI<*anZ6%xqSXT=<$SbqnDRR~hvB%sCMqOPL`q&%C1Y3b(&5rqN@Ukjtv=bgQ9XJX(+ zv&oxCE;0qP@iY|dm(`2eH7b#nj4(8%h%j0P-3Tw=T}#0GfZOw@;Z$Gzm&PTMzW5Pb za2-fFLe>yjBnlnpBnJmk(@P>{EZ?{jZ0hA~!^j0ha2}6eCr5Cyf~)|`MFalQ_F0KC z1gFn7M_}aOpr50_$R?V_fC)^p5<6+%6RIybR?p)g!{h7Xu!F4ND&k!!g8HIm&n`So zilD8J``5c1{^T3sh6PIEmGhk(*qd*M`YyPlEUfsdhJ8m1WMwm|xBX)Jx+mn+XAibx ziOY`e*nV}px?jp~q?pg2opbzky(5A>Zw^J|V1jqxu@7ty;7 zEo=i$fQ*!udWEhlBsoC9ARkDoItbkY>>U6dYWm895xD0@{fPEfFyu={+6Aah&>B^%dbeI&e zMWO{Mu&qBns4gcgd5zfkOfM-xS-pbwPmM5YP-%fDs*EqJB;e-G?yy>yBKGup!9BdN zdD=yY3Irb1N7MYnN&AN^6qViEfY!_o+;r5=Nxz7KA^+2^_n`i6e@2?<3^y>yDkN@L zbex+L<22q}T$#D%GE%p6CY5{iSFjX~G_*d+YDp?fEz|f~>z0k7bzS0W;J*x2d1Ojn zS6%1n818@QU7p_U!Q{?))@xi%!FsFbYCJiR67fcZm|3rJJ4-({;?xbkO{l7mPl?sh zg!2cEJaFCLUhut=kF>1MN7C0UUU9zowtv;khV3zWF7=zmCFv^-XmC`^!;l99`XX=jNYj%AwuMQ6Ze*Lo%*;C9;KW2hsR+^TC=4# zbg+pwNZEwWp`9M77eGIe*!BDQ*5v?JVlbw8F*0A z@D{qn_8hk;@lZ6fQ1n>;M1BY>L08P`bM{x7U5U%(Mk^Z!tJVd*;4>cgt6Wk|PpGqY zysE~@WmTe9BW`cAwf6JYrZrZh98=_9z2I%6ollpzBz4EIHUPoiH_v=X-?9Vbrx@iMa>`` zfb_u45-XEb;y$iIWKKZ$$ytmiU?PBl?Tzaq_dzKlIC7CJ5JI%G*a$RqfWu}?@Yx=O zxM|wLg{pUu0T0ax^ziD;X; z{#GH|WIB-o_Z+q8B%_y?%PupT-%TJ@cqvMnjeUV7`wrM!v~WA$NN+!o;CnLE7LzI{Ca1`Zlzs z#;4~U1MOwqPCa_&pRZwcC#SpH zqjGcqwsx6huTPcoPm5L{{Js~avC;6*Y|x9mrn}pNi+dV2(v>Y~0ccMpAInPXS1HI( zY_9HNvGC$)cpkx(9{`UXB&&s(42DPfORZfCmmb zNX;UL4or;m)-tdWxa%5gIU+?ExU7pSNH&DY>7`VQL=-Qo*W?XfkPZ0%NmS%2Ms)?D z;iHg6Y5;j*HkNC91+50*{2^IkAn7%}dAt{|p__bRl`0n*q%%ZRg@+0>IIHtpZGItN zCIv>i>=}MH^Hqvi^^q^vz2=LL^spF5GIdieEElW!KFHA*`k_ZU=Xj0kDdC}B+6Q7m zmB?YHXLs$O3UZ(l5ZS}gBx#fc^pH1S4m6Oc1cYODG>`EqECJk3Y5pGbB2kw`R$k>O zyoV?_cm}N=m+CWdt`?9Yx+WfEfC>_|v7CpH6SHsv*Nc4u*?Yhs>-PumXVnVTf{saE zLx~jxa#tJ&CipN z#)7Pz6!CDSC-Y#pgOE#K_{E$g_feT$5&4Qeq*xv-SH!h+Z(8fCu8VHp< z$1xw1f!|=8y8glE$UZ_mZuvT(8Ai)`E=A1uh0)jVxGy|1MhMhJIP}Ard4Iv|bxFLC zRQ|O_$v7Iu*M?*l7F>>uN+aomxNMOEm#ht$uu6|Wk(i7NAgX%;nR(eZxHo7+8)#f2 zrg8hp8W0&re>&P>fMHZ17hTn~uDt4A4Yb-lsaiUDcueldgv+AC%gWl5*=4dv3TpIY z^}72*^nc5W%k%v9;@1dN)8lA2?<=PV3gkL(-5RotZw-mz<0jdH$54*Yc$S0w1#rxm z?!>Tr7kT_z(N9oi)m%J-$=Hs`s0_$&>=+hV@R9P+orVsJ@;U!C_L5pLc5!zW1NJQ& z=?3A}YDE)MWylPXItXjzMO=1UoJeJo3#&bB0V09iCg9T&-v+(W1~0_EBT%O$S-gPc zQN}MgHPIzthV>G~4JrXBY%X-0#ZeXb{X;ZHz1%TP_1d2xe)(PRk;|NP!)%ok0utZ)lwEjPV$3 zhC7&N+bpv#_baq#akfXarKPo8Fu*?^UQIV#GH$+r!;SusdSdrv_{Ymf%Z@IenCKnq z)zS9VZ_M4p4QtE1X!d|!i}KhNQQGU0e?CyZDc_~}-dsZ7+z=srICtmvsLlATwJz`S zB1gRfHGlEazg+85r|+VwBM%idka~xh0}6H(v*=fx400F@in8!BM2iNfNg^L!|DNy| znSpOKVc{o2xuhImO%M%;TNiBk)#M0D%9yqefXWczvE9Pqg^|HnJC~M9 z-L{gmn@gn1kk2EtV@QLR6P2YoW#QItO?B{H{u1w$Ze#IqeqFmWv0h|9EILsSr3%*9 zyxU6og3|Yg4wE|Dq=>r`yT`<1e9lI~EtbR#z^4%}aJ9&Nc*U95i<(3J z<0#)9V|LSmz4Ol>@VUO8U7Xzbdv_0En^}HnR)H~T@=eF7tL3_r-jT|Nr^;lV#|3zw zB7r`^$5FMjBaz z2{XZ2;7ATI*+Xr4P*p?R30>#g+QVpLVZ0m`eA6KkQgjNU0=RB+Bm7^6GRX2aO1uHZ zZnzX3I7&B?yulWsajjc6l0pzd zByK3!Tj>JLlD@=N89K<>D=vfvxj(3`=~&f0aAm9|qVQg4vUYeT+eIzK?Y!1`9YYLy z18S?gfb2t)J6q{}H#n`<`c{g~c5UyPpjO=Y^%YU#7Sg@3Kjr=}_TDtAsdQ@>#j-&~ zj0lLdDMh3Q8yaa-Y6%4hkxmqZh?LSqL@T80i}!5dx$X5oseJ zq*IY5k_dz)X}qud+%wL;wcX#hzkBaE-~MsNkYTc5ki}Z-ednCde4b|xh(VpVV$gf7 zV%Y}?k|V23UJq&{TM}Qx`%tWZohVmC)uO~L1U0-skB@zBDC1s`G{^D=K#-jYULYqT z{$V?B*>-pZ-FC$yg0U4|fCa&PRSN)s{0H!}cAyjSXr3+c86!fczdrwTy*?=6o6J)U z{5bDRH~jt}fIFuF9RH6^P8_7QY& zL6T2drLa7_m6(X&ev=tHgAG>yCi5p1pi5Pic7O$S6Bkr(kk~ zBg7g8KzW?DwA(sXtgU5`H!B5{;4vy1cKs;zt^JNhX_o+g^B!6&Sct2#6l;$zWtY7> zK^0n*H_Yypk~$dzc$x1&THL!U@aZs})mBF$!uGw|qF>=~Vn#NtC?%S=@3q|MBm3Um z^W|ITqnrzV&DWVZ4V7K*3f!HdF(;Q)lyqdWz&_UDd@ixJbjUe2vcXI(AE#Gmxc6%T zRB>MnYL)9@kalM#Ca4p?ntIBHH0C2L9QXjC_*ufs46JOK^d1x{t{^y;M1|SzRe4TagLNMGCKLWmCJnU(w+)lmhOhOBS9$&i z%dMl``mBe&3Py)4s!T9gH{BU8z{i}Y?LW0k zd0M0f;a)IGP%s0$kJn7EY)Y}G@;cA7$>grdec0De4BQj8UU}0VNUi?l>J${}*};v3 z2V|c>8Y4augnK}yx({n7DWw>QjVS$f%tWS)*i#e>BBtvY;7l3cgCZ&cJ{inI1PW|A z)g}q}V1xoX_t^~CJFM=HV0^~{1da(G>iSx2fXg4w?2V~et7&I5kfp0f-oyIL6M=TA z6<{EtYq6JzLD4Ha`pgo~Caxesr| zjvRG6Sz!#oW~JLxSwmx}kX%X*yJu&2#}SYs5B@Ajq?n6Po1lAA2eCD%9JgavNpg1b zVY4?wf!=8qUz5xmXU`?THL2m$5i%EO*1<}^nWS>a*Dm4^1JZ3`xPaJ2x(2WFX(Ns} zwH)VMiCBT%2GtbN`F>nk8bV%tY-sVJ_RuK-y`vkU5dwd^K4y9So1{RzsQ~f1HSL@} zckfxI*^K}#t5&Q|*qzHBwN1O;9ZKxAC!-X%wwLP4St|*S$=--8iLbCdMGt!VcKVKy zyqd;wk3>2BmtS5!U7oFeX_ajdQ!(P{9r<;~o;yK$>|zzQV=t9M`??Gk4NmF0nNcco z@Mj)7SWpbVHt`8O8&R~_y-^a6Qv>Rz<=_M&9dQlLKY~mG5xGxfhqdFwQhGZo_p(%y zZDp7;EfFPXcx}!sk>xLYtdaW0+)1%x!i;Y^D`DYpAXF9#g4_iS?Ic)ep|U`QCW-w8 zN)^^gp4nT8vEM5%?BP1eeQM~qAxo3oL4~wsY4CK^2At}Y77RLA=8GFgY_&JV+CjxI z9xPBD)7y^QA?TUK%Nf_g)}qR8P=m+u?AJvs7<3qxA-+7yxVpOVCQNuLUs;RUU(4MJ z|3ggpCKJ#Y8C}ldTP3b*U%&6|YlTYpE6$A=HE|cZ zqMzPEd$)PNjC;J(V(Vqdc?KqWrQ>tdL@`a{!MvLWz0*1DR!La&g%ju2Nv+tNZ}}@U&Ij&c1nf4@5;_P)@$-a1&`k~qcsFRmR7jPJ zBG|7Q#$FKw)2J(3w1K16S;;+necx$E4=B5ARD1@C6CDQ`g*o5lC={u|+}dIu%4V(< z?;pknF86{^_entItrI-!gxBSCBGM4GuvD=RI|BT{^^Uw)krj3iWEu(*mg~(hTI))X zc(*gtJVK=F1#8M5eZsG+?M=N*?U0ALRZ;nmEgMiull;VcD?q#hG?_wSMf~$ZDTJoO2ImyzvQx2t*$|T`Wb<02~I0Na?!5DD(ckvh3d4f zTV6qK2?kA{4Ha_wy35pVb_O}*2VSGG${ozI)tU^2x7cfOT!Xer=yIbqw#r+dEvTD6 z+o0(EvgGiu!;T5X>Et^O4|Ef#Tc0DYifep0@Lif!#6fSpXZTjBa?#qaRMR(##{!1O zN?J{F-uF7lp|VghsZ(zx_*d%KB9bzN zLuC_tiEq(TXCK~85KZRjq~#{5mCvVETr`e``r<)7OB9*nY(Z7nD|ksgG#$uy6z>+_ z%<%apv;EaG>GSiXW#VDbz%Oq6A6@+Ko%|FT!}q2?;uytUL2bhW&w%&si10a)8IY6$ z|C-)(y_GYgdiSr||CnS{_vLTR8J#@ox_KbqxWYwBP7=p1Q(Eu+^t}%K%NHycI5+-D zU4gT4GX5r$Zo8WOr>#p&`P6b@2{%r?eL_C9Ym_cLlVy?|TsAG$8EP?q9Hy3dcVppj zl}-t*;kH?;!M+C>>Utcq%r_ZA0Ir+5AkU!kVeH9oGB(SSE%(cAn_}pnQST#rO}Z!b z-7p#&lU7!4QSEPTmFQc1(06KUa(1mB3$GtLH#vzETh9yqzscM?2dGw8@i4?!CMbqC zwn%dDpVY~C7M#{Aja^(eKBV!7^w>8UmZ3OV`l=iM$^RO7HV-4d$rvK6@oWaEdQP%3 zW=^~ky7W!vwUh|OOwK<0CiBbqm2WaKQZ4*E6;$zh?+IV%AeThFhmYKikjOnnKu+Mv z{}BBD;w<7td%?vkx+n`s7`uQM(PMEL6a>~+7o>cN-Rg`2Wp;-z?kQ;##l&}HtUH)x z+>ddla~jf(T2=y*KP&HrZ7cG5y;NhcXv|>$2mi8>%Cq4u6^8f&Ke(nMSr#+3j--xp zJT@G|Xvh=-6D@kg+ULV>jBA4&AiRLefnOC{r>kYEaZF)Q#Nmw37h?VWcQA~UOAYLf zmhK`Lg>MxbVk&ryS0A2#xa-+=a@=;!=I9BPjZ?3mD8hKBWt}yu%R|h0I_g#X(Wfza`FKY`e9+kTi8RENh&o%udx<)|L zA!WxfXMG2Ky$67eo$35yN3E0bX5Ss4ce-*tSdQz(DH0MxY826yHN!7vGs=+AuVzu= zCNX+(n7Ts6??VfFDVxzZA-^tW{alJpKj`+kUNGH={p~5^K_A6n$}$)1=H^KYr0ZI12Gw08 z$!5mZ`gQVXcHQz=U1?Ftu}xf8xgAyOO77yJfd34jjr(*-m7rpQny3R_>o`k|75#=;=_w&$6@&QN`yureLtrOT zKMoo)L6E3@*%>ONISAGi-FFNu$&pA2+@Y_HpxB8 ziVeYBLYrU_%3)Q_B0ieG+1NCd`#wz@er42IIp|jZi*lc0L=Xy=P?0m#z4thK+CfOp zC^j-aYxB6GzgvLWU}B(DF<2JWRh%Cf=+?UNETzQA0U>g(v~@i;Tw?2{)l#K;s@!QP zUB9o5QQ;dCs29b_KD2d^b|C=OLr=viijP5z@39gZXPYWRXz6+?r+0LHH>(#koO?&r z+kk)U6MV>9oMsrcmO;SjKOm`s5+c~nK=@^h6Or-x_ApEdogy|g_y`xXps}C;sA1@NKwOl;kJ`%d=i27Sko5) z2dnlFAY?Qo%$ngwTbjKkgYa^9TpzQhQ5&HpmD_kl?7`pH zWsQFoB~BS63Nt17bQF=fTJ{{y0Hbo%zIkq5_@w#R!-1G^w;Mqzh3LgQ9?t9fUd=bF zauZeV4q=?$R5%oFG_fCmd9FsvIUn;j(osvTwz|EZO!ZMshzY#fesaofUz)LAbK?mu zzZ;-2Fy)Ys?yBgXOcNrWWgA@#yfa)JU>50iU2MwVfNHQM!EG%i>6SdQEbl6{4%9W; zy1Z2r_NY-1wA<|8OHzvgSl@XYQiZisA(vBmLcMYOLd2PeVr$%{)shEvq91*dV_S8M zm|ShzWo?>)h_I1Iu@N-#b$bx+uHQJ08`T0GqU*9x9le4#wS!F zM#kI*Tb%e2G&ub80Bg7+h&{InBKlWB?iFIisz%9Ovpb99>&Ms$ovjn)Tr<)#APywn zl;oBsuo@u|-{ROA$CQvWP&rF~`)ys1Oh==LC$})~JzoC#yuwiVoxgtlWtfSTXn~XcuBk~l-Nt(@&S0}bZch3o?0&Ib!>JCVyYhsI_ z5CHpd*g~aZTW)My+?h$CHY<)PR*Vvc^~Y3#0=Y$!gp>J%+c9`@sKv1utK0~|_+%%> zqMu)2a76ixZ|pVF{+gkfwZ<~F*M-Zfp9AZETKnNx;>#rn*j!!-k?fFu*iLp$CIAi^-q44a#}Yz@ZeWU6bSl1#%a@ewJH7Q1>!@c=Am`Sn({Eq( zo0laeT5mn8U3~XswskG&iJrgp?&-e#)$5;j^(SsmtKi?(O*k4-r8MnPZaW&Wc|PB5 z=k(@RdMC&AJS!40FDJTLb8=HaQ%5J*!i(QQ*XN!1^@I`#@A^y-oCrghwh9!mj1ybqonqnAA&Tm&cT@D5FHG8`CZ5^T9Ei6B-{@A_TGJU;659?On z4>LBd1^Ic3e&L%RsRev`;A)89QCF#&4{m>x=>n$o@3nNA2Nxtr4*?~e9kHg98y+Ou z>y-0r&A=jl^Ynz;u(|xf!vrMySY|(atXnN0Tf@Uq{#K+<|AI%TT|W*y>vyxmly)l| z>2NOzSnuqtT;BfJD>Kx|Au`j$*~6(MI?t!(zmR>K{DwEe^OdEJmclcB-((KV!lau6 z0dM{Iznrc*?m*l|K!7Il^S@`hDlQY0i51mZ-qd7!g-&)a3`&`Eq(BMfzR)t;NW8k? zFh3Kk4;5Sqjql8z+5I-&=IB-xz$OFx(TY9No z^KtAiP{m`6V~2~GoLT0lVbm)7J(w@6YXA5n{G4o(tzyw{0}s!jk9`hL8oThy?r6yY zm7HhrR8$P!=;9a2xeM$sugZt$7g)P8GduTt0SlI|fr#>xqv?hRp>ugmU#zJ$dzi~AC-M9&*f*J% zy{}3CSj`nnH7|)wzRA3?3;-=>1c4-;n_2KpvDzlC0`Gmk%Kke(AXl-nfUT`1eO+G& z94q2X>W#36fcZ(DvHQaQ&|t|;lPWXBNd4%}g!>00gvoW!Mj~uGNIf~-H*HJj4+E2l zL&|<Jb14%_xxL}dUq{QXO7$T6^U;swRIlHN;vH&CLX7;CsFmlx$&C8V zX}Q!Fj8UG*vg-)(waksv7Sh$NB3!C2kz$BqB87KNTBuv6sY=+ON7!Gh=YRig1Yd*u zIRHa)6YcWUB#q!+D85iyryV<3%&!;~`h_>Rghm|PV3EO7EHa6FJ&ZtZ4rYjT#` zYj95g(7>%HEY7V%0SJLCOSe5D<#JC$lIw%f6M|vwiqM#u12wj@Ykor&902*>3@vjFcxj*`KGrc$kX$NV|f@uO`Lo~2# zKr}RhO&nNjU-n5Ws}&H^a)%?7LnqV+&WaD3*Br+rj`mc(A7Zy)TuWNEbXj<=+I^@> zh4=D{>4?Znpw+}zVco9du3MBNZ_?ZW-^XeV3&AXiw6K8^w&d-0WWV&$5&K79aTe=D3Zm` zT4DiZ+YbKM199d+$q0BP|L_Z*0{eR~b0i_xyq6%By$=Fys7h}BXira>Fr%{kYi@RD zW%exwB4jvXQSJc~T{hDBp1$Wf#ceV9_e>w$^#1_y{vOc#k6yE|L7Y}o8j#+5J_u8D z6lODtws8+3&x0*v=a_ur^liKxNUT1FqxKd%7hX(e^#tu7KNHl57`vj{Q|zz3H1r(m zqO~zV&&D&7bA?$wG5Vb8qy6tnx*8Yn*x01RqeE`l#Ein%zxkoe1 zMY5x`yWv3@Zp)byei3ETpBm<=xZ6`f>rHS2%Dn~`Qpn1#`{}uxmg`j;hpJt@Vlhk)?t-GB5~egEEnAB_1Au%;E{$I2rUq^g4phTSu92SAT8iMbVfHfzjr zhdUiDFy%1QrP^=bR(IdFR6CuM!dn~7QvwlxOZw%v%Cp3FSR6^sV;$?g`&H8vbAb07ws~{)Qrb zN0R>8*E}hH!lD_<;b*ZUI}96gHi0Wl3xnyJ>c3hmpEERduBSzBrNA##cJYN{x-Ay$0hOLsnQ&H zV!Qja&?&$v9M^sSMUd-!(-t9=*%um7*vNPh1M{8(=Bw_d`3wn)E_<8da#-*)&N}h*=$(g)zAT(N zhU_9B5n?n^j{S%#Vl+vGVct*$K=P+i-R(;*jKy)DBZEWImVfY~{x>l6w;=3K)jh zfUPANG)n3P))=?&i<*W<84D=b%;ohM3gb7ejRNfQ9IX=Hg_9RpGNfAuYwy~gemJ#B z>>}-FoRzAH_YFo!VG?TF9(=ocNtks`MrAEIi8*rH*9fiQl#X+d3Sj{o z0BV)s{~lxN&{tQ9p!+m`tSaeo@V@kz>)m!R`&pYu+K{78O_cDD^O4m@(#Dba+cv}Z zKCz$f%QnGqKIC?}yJva@_@M}&^qQV^c|4w9jyi{XnXm1jH09NCDpG+qurO-)C74C$ zg^Db(W|A^Q1mYTHhvc60Cn#2!CJ5#oe}Ka7gJe0qX>gd>N)Sa~$}O8s7402^PK~uQ zUURH7m(skp&2NB*?!Vl(!@;}?4){D*iZB^Kp@Mo9_IkAN{d29yH z^}g5>s5$M*5?NsWnQkS-eBRvHU-~lDn|-ywrY__8d8xr(bdJ0m?vOiZ8hnzpgr}E-N2gR0y_>)M`gjz`rBVAoKZTHs| zVkNiEV%JbNfk7o;jvgLO+&Y6-r~_;tHG4%2f~}H54Wy3NaG72HK`eiA!UF6kG+Z7` zSd5kA+3&%w8^r#S+rX21h9x*4`K)mEn)V3GIBoRBOUqzu zBRkTo!XXi7Ik z8=`k0>Vo5=k&y0(-Zo}@p(BqBcNi;N?}< zn??m%31FG&)0u}zqrRoCi-xa5+uK4`ri5kcMzD3{@M21EuLEp{!_8e#BU!=%$x}0c zi%kK`bz3Am+{C89l)cnO8kytFrNtO4b}jkZ^xA-#T4BtDJyWBt)TBjMpY~-^0@kz$ zvm^8YhU;EW)oUBZoR;6BEq9gf?BS8NEs_3FZiTByrQTx;gre%B>@9E;a%xn9l{pY| z9eI2JbNSA)=d;4qle=<^!t5_MnfUqbee!7ke$FnXioT+wThBTKA6)Hxq3q~`{E+^F zLn6yV*kqBtzf%bqLid!S^{GDdAPaD*UHOhFX4!|IKWRwDK7SSXSu^>x6fWvFGItMy$4b&*1kaCl%|^o z68s!T+jp10K;~uYk2{C;W_vv>ug^bi;QSz4Ei2U}Ge%#}Eqb7QeblX@^+W8f!*>rU zdHyZhg6asFU`AabHi5!f;V{rPz7hW`KNy61Agu`)KL-eBmjPSS29Tt1WJ=Hb+6bPZ z%f1Lp-)CbD1$Q*>8zAEXy!pEA*1a@v5SCS4)Jq3v|fgL1p21SL^(K6fYWHb)jBeskQY( zSZqbSq=&L)W~{(+&a{H!uR-+wU%UK2ssjI7JO2H9*=+1V!NnRtxW%sPtED%%m?puM zV~A^^A|HIN=dvB^Rzdh0_$M zv=?X}=||K)5ntl+9NTj>KaO1l*9`Af1NjSd>3hSz7N~j6*CN-T)i%!T)ohcFy?q_7 zHU+0VXt>?L_`DQUHdBUMvU+GU)P?&xSijRSvmXU6`tR-3Q{-X~YC}uh7z54m0Eyk* z{=cutfAsplPk;IMS9V3fIzcK|dXpb}0(je+VApZyG-vG1`&;}gr-V3Jt<}hvvwzw_N1aj_8RsF0%e6Z@G=JzRm>QaO8Fl}UQBk1IW zq+7bx5swO%h`FPEi|QiHz0S4Gsl0~aVT;UnWgr*+!8q10gcKk&5L{VFmCywL;L zJ>=n+xqB|SB7gyDxcLC`U=RB+T{)vTr6l>5j)v(_@xjb&>l3#o)vAD*_SS=$2DdKR zja9s`GJjbNa=U+dR%t+=AKdr53(dbey@pZy-GAl>^D%xjHVD|&02iMh{c;~!fh8xl zBO(DCfYOb)5k(RXcf^SD(&*0V;cAXUX#hSGC>w^`4YlzM;E9&Gl;YPpdjOO_!+Zg8x2o^%_)l zi^0V{3;6-BQ*0b7#Qd%8ZV*jBO30w|0XemJb71P2L=HX)_4IYcL$tlFz-}HD)?8Xt z4xpR{Z)x#`UqtqIAB?<+J`0o#J(h>~WCAamDj(u&krg!jqXEW10Un()wbrv_b-&Wo z0kbL3l+j&fZVF{?>-%ni>!5pd)#H>s)ceeh_w!m{O&cZJnpxmAE?xs{vi zOIPau=b<9xb_8UUBUaKDzJ=rjxMC43_OF(A}3!aKF4cd5Zp7Q zGICpLxltWzHJBGTCa7^8`k5b>JY*~J>$H$6Gi+@_InVN#Kh5m!wM;TK>zzK+63j83 z74SVdbLmnI>>;QC47C*WrrK}b&%xMh1z>KPEE-$VsQf!9$i|y-&XX23ZkbqTw|@~y zkZv5TZABjMH`jEejV2NzF0p4SO+KQVOk@zi4jSAO{oYP^Ivf`M8Mp8I;6fZ6`&)IN zt<@8MCsw5=JA01CREJ_aJkZS-v$*7+dcmWfJON|m(3(G1vXPrjNavC{aeHhG{hYuJ zR>Nf2;0MKbBt!=9{uDJE#Pdax@qaq|Fy*u_VECYaYG5)sd#g=zwj&?i~{Q zaPp?kwd@vHo)ExC7EAaM$)-l8zw;{_b2%=@=1vayzJGiI(Z!PG9pbRo$N;{Nt&H^w zU_SyA5;;wHdHjo5$zAH~BMfM(2gd;^#zu$?3s^SPni4Y>NRIPF4`C}IN56DR<=D&=Oxu0)UeZt-~K5M^3U)Q zaC{$p>syTVdfklb zeO=U(qGM6Uk0W0&eexkDn5%3kux#U9oLHXdhbNL0>JaLv{bm6Z=s4>K@{iEd9M zUYrH>E(2~WewwiggZN=|6=w-h;714uAqsJZDhWX*dM}T-ALM~Nl`4vS&vzTic>?>= z2|VTeWygOgy7)UG20R}R(9rjvT2LSZgR$_^$B0q;A3Ucq@PFyYA`zT#GVcK0aH<3M z{p>R{5kikZ#A4*Hl3(waPb)CH1LL-2$Aq4K6?rh^)!BywBJym3qF8QJ2z_TBWa*$VC>-pEx>i| zgr{n0f`MQ`?E!FTDTq7n=_o0}%JOynB_#W`Q-44-8e)TZlh*uEK0VEBE-44M6?#@0 zidtz-8r6!}GKLLmf}F;k_f(>$1*xe*w?`G0%7+|m`?AW-#){SsemDA0O4qP#=wjPtX(b0SQYI8a*DS?56|k!%g)yiVpGXR} znjF$K+?L^(DIEL+CXXGF7K2)cxkA&@=x;G)r_QNC1p4ZI&3|-w)uhmd6I4_k&Xt@C z(;6S5d4Q?jWanJTkdtTXEp(mh{`$NI*GIQP^$)n!Z#>2@*O~paKdA60v#Pxp)72Kk z$~^KI~0IFQ1+X8Td-6G3wkuGNLcwdW7c?fkQZa4NgUl-6! z!+O=AgU^Ax!yIl?C_;G=6HSKu;yQC zg+>c+Ys(jV^#ypbas?NE!+wkOwR9K$E&hlA(E%GpvY!--_G3)h!R>QO(jho}u9h_N zO~!>kNi!TVwe@)fhN_0ZX0?G zxxSi6Rk05DN_hGu;Wu+VpA1vE6nbDuLgrGWJNa5$(C*p^&7qHN>9I4`ad(8u#;0j7Xb(ErxqXFLd z(+*qlB!`vm!}$&%Q&&mVox(*E@$}dnEH~Wn^sNCoXX;{}oAvLwkN72<%51D&gUH8wLvb4w|>mj|9=)lGt zoub4}P7$F5rFw@I($@G=;rVH?F%Q2hs4I=8g4Z|51E*a+z4blomw3ILQeV)4O?>N zu31~$5l)>JtmHhYV#5`T-Wc_}6d%WKf?ja{+}wX)e_f;2&wRH8ZMUMkl|fDQ+Tq>1 z7JakP-D2P6FZ76PO0WrhM07S*J1=Lri04(=tw!=_8}Y1vqSZa}Vxo7{`TodGQ2V+M z{-^-{`(ytm#V~3$SWRF2D68=!hLR%uqKPE0V$S)80rB`zsYWZ{p_FudeFDUMnRwN2 zGN>=T5?>Zk_6I=@m5DP1Kfs@qc2CYSfOdWz|0UJWKrfE^UAJ}4ws76pp2arlv3vJZ z4DX4a{wJ-JmGeX{UR#$Lqd}73vG_}1rE55aivoh7f{odM~AmKMaHW82fS-T%Vb_E zPH&C)!DpDV$zK5lqsCH_jZ^_uvlTY>iLMwWN`*`I5$OU8kQ!=Vp+YZqJ+nbe$PVLL z$s=_`p)ps;Q4GYnIY^h0RO=r^TPE>ZMY>?#XLCSN@icsdS?Ac^qj*HLu`JX)oB7tf zQjxQU^ms~z^6Qtl9It-U*%+I3LjSh`e*TA)UVQO+UVxOYTPHGyE-=B&55zgL?5Dy_ z10XGy`LwKZqs0l3L($Lx7&$6cd?Qsw=eo55bqfsArZE-2$)FKiKS@{fKRh1YNh(I$ zYw_a>lkY>%+EQb_b0dXnbJt>wU1$yXr-MG>h<8H;VW{Rx_amMa$afXyi7_7%J5XWOXp2zxs#eGoQX_I-vCaU6EUHh1=%vc4fa3ux-S;KO9#xey#7kP;N7k zAI=X3e6X{?JEb8FOx&FBwBI4AqW*5|5&(H};#|4{R)D-Zu>|r9mc(;h{n{wH5dL8p z>hx160Ui7(uDIQPk6>q(&@PPW{xntO!sGjPmXEv*7=_BZU|{5oroG+F#LogmCw??Y zcu3&T$|0?TtwdkGg|Bx^#M+qmCi(yeYKjIu=qHRHN1D7bFG@C^VlO`4&s&V!V`z6~ z6t6^o>^H42gVW;Im)ysZ-48mu-`desq@(xJ^w`V2Cu-8}FNC@GJ5@M^d?u*A-t2kf z!@82S6?r#5^{EZBG!L~QWivOlz(GM;3?&FeZ4-LHi-!*GLMJSv z>-B5k)L*D7X|VMaSfDg8@olILF^Erf*EVG zH-eZEEZ+8Qae|ezYV!HF5e`^K$u;U}R0?Gkgyb_jsW9w*SOR4&vxGc^Ld#5-Tmwz1vaH)nYrP09wpXwis6s4Ll3lCd+#K5dKB0m-C1Du^2?3g%G@o* zzV~lA>`rLfUKD1!vB@L->1U;>=JmsMD(k)OO_@ezX7Bqls^IcoeeNwn=t~8hbHI5~ zplG3wA{1IoIpK12HRC7W$5Fuu_FKj<-+hhN;1ktg9cbcJ3S1z(%h&aQvP#8fzeBOI z9j-`r=VZFy^V`Grn{xcKXv=XK1rduolkXja;>`7Cb%)FReSC+^Ma7j+R!4wNrXeqY zHSXV5+Rd@^@y>DR3%r%xFSaahB@&`-u*W|&A0>rU$c)~3K6h}_+`Hhnh|-1R4t6ionK10R6kB-!-tHdD!^?1)hH#{A={P* z2&i50&9CU^@%6&Jc@E8va~0PF>4bPPnAlUw?O39o9> zj(#>{s;_W+z8k`qV`kh%W|bOfA*_zDXOyl{u&C2g&qRt>M@-@*#{FGNCnTkYgn4mKO$BB{jvW>YvsQymR4g`L|*t8 z=OATJERlr(ARK%qJV$N?y2H_8sY~p0vPcJCYbq^a*2J9lgDxx*q&bQo8>vz!aj*p6 zjaWoqw}p4&XQUdy791BO!|r` z^tMHPlX?6>Fwso>!OsO)a!4tNjW{_-#Io$@P1Q2zGikjtV7Ei2MgW9&3#P`qu5ZEL zLLVPY%D7lx^&&QQyHP`K!mMx^ms94KTqp12(Of$aJ%+BBskm}!A4!1!Y=mFnAmAOP zP^N_s5R7N7mAdS^KlarabyKwB5Y7Qdhx3oYuj3n#yeRJ6NCV6CdW$=rMfwT*vp}VT zEg*L^p!mdtoIEBBGxvN#K3tc^gqcL&HE*nyKfvtbqqpF+1zO~L=n&!NDF$wB!+ifT zf?>@=ocx{&{{N!<`v-o)|9#P6Rs!nvb1goci1<-n>tgEzguK0W7|w!nJ>>l*a~nUf z`;wF>8anC4y4~^}vD8gQi#s#Vc7;ca?hximl8E1_Gg*K-b3~9cD~Y|o|DkJX2wo+o z(z9#x@t1W72|QN^*awp zw1OxCKT-q;6w9U9P*ebbLw?|fF9Sx8>V2Pe9E$pC#N;DMA{(X}er6SJ49wK|=VtgJ z|0&mnd>s^j#IMH8pQy9h(l^xQ99+-PQppcj;o}PY#(<~aWcoQ+2FR&iAku)J;#c5E zecmzt9~T$-1p=&LG86?E{PRLI@Zh`wokmq=E7>z8&j7TmgTA z{Gty-mHr6_rLg1}zBcZHR1M_JbE3WY5ibE=T9ZS+%)x^*XsiHbtmFHwiQJB=$Z*6W zas87#xBi|_T`q2!sgdY2c}NFrl*kz0wo-dO3VD+dLLzQG^Zko^57|CiTV-U3+XC}`jM z^K~5tw8o7nKV!XzZM8W%xvO)XqS4?CRBbQ)B|hs5TEk4Y6I9=+_?4w6Ps#mDGS&)0pns*gi# z9>0o}6-5MD)uJEZ0R7OHiF!7kL3&akdiU|(oR6w#(&O!&CoWELC`s0ONeU(1SvnzD zitr~Ve<$7s|Mr9D^Z$`P{GVX@zbTmhAm}#!uXxyrf8hid>F**fH{Qn;zU$txg`wCP zZa4e1&8TW*%)I)<_zR7*Q{m?rIa_Y0+Rm0|$2Cg9OE$&DiGgM3O+g zeUwN;CQ9WP=KJb;)LCYu2g0NZ43VDY;`I5-HT;;+mj#!rGgI1o46;KRMQV`+VM7L9 zB^%@~$DI81hQ>wI>d_TZGGD~8v*sFcgvPv%D`6V>)$YV<%qxw^fbrLR+|$l`bPmy8 z-Y^)<4)Z8Fn(O`P)Gle3=vV1Lz$Qs9*?#i`_7`b)e~TPwBq?L&9R&np40V%9!UODH zK7%%Q4X;eGoC(-7SR7{}i9zc{&m}O_Tsw0{7ZMwYUg6%RCMcvosPuccf&L~z`Z7vv z-VEKh^%huYTK96?^7yz2!VBby_q>5PP##K)HEP%3s7odymn zAT=cjtH1;zLsKF}QLwRGK?QnVQw*Cd4HcK~!8hpEN&Rz!B zhiYIvpLro(i&LBNtsQOUmGLSr3E)x{SW+};%cuGXKEsU)p-<{}?U799R8O`$c%+3z z=?%TwRf~SPKHb)9#v0?qF>u>ll$fZNe>y!K8|S;};E=s~^6V`9g?%e}l-uoRLoVjDjv zIYDt^VP+Gp27GCE< zOv1tOZT8eKJNfSp;Mf+Q)R42srQ1K{)EAtvH&EJ@Ne1;z z*wGT7pNcoQZAmb|tYtj_kEb7*_jLXi+`@`|fmEGU?wddJCC+b!fs$Q*AWzrelI`Br zN0oEx%Tm&Pn@X^@TH6cN%+3!59`$(4_o{-QLE$Et)vt3nuoQc(LGdL{xHbjS+8xSParm%QeZp-NMQkzV2X#)^3lQ;jd3HX( z3bqhSfu^SN^ywk&K?zy90=tXQ1?Oi%Ii0zMl`Om(CW<{##hN3K)>3wh{UPE*h|w9a zcEDaI6kuLHG}sO43Q(RPlU2(3OWuU8(E+RtpPmvf-pxkaMV$~BEjtvjshi$~;`5s= z#R{pgV2AE|?PO$fLa^^;wvLr&lvilr^r>m9KCj}{e#)wDCTZx8Z`z$TmI^d1RMvSK zS6DgcpVlFE^r|{!e_~Ht9w0G7K6sT@?GXuS!uta_?U~CC@gmz$HQCOw0wfC|Hf@S9 zM{Y%7?W+f(VahMapQvlh;v7cj+9+V8W8Nb%D4%YKgNw!wR$%b1O?;i4Yqp`W965dL z!IG&7h2hq2Hlf1~Fn(#hYp^c-m#Bk9&={>5mGt=RqF+qSuvy!~u^kLGi-uFxugoN| zhnn|JSx@AjzPTVd`ufXD$KY$}fW8wUL<<~euW?)fSA|WD54YEYa9p7?-?UvGeFzF= zM_i|_SWt&0!E0WZ2pqd`u$*?(2D4AojN)NCU;u+q@ zqkDoo?aiMqrwW51WE>yCa-<=^bjjlI3Jif30H3!#{^;0UL`@7#4ZXBP*(oUbm|5Kx zZgkm>p0ZeQ%743RIP13j?#jT-9nl8XJIgxz^ zpf~5#KlixhfrDSKDO*~?t#q92uZ<+XwI9~#Mr&M%9h$VaesYvkn6ZdBF&{xz^MV~Ml6@Ik-pot`J8s7;cEDuqvjx4-m{N~F`@ zbqEVy*@ykI^#+g%D(gDY0SIrJ?$OK7UbwoYTqHI*tRMBi<$h@IJ&-Q{hcbYF6OGOf zS%E$i*?bhw9bl`^SU!?W>L{psJ?2K5t1HD;mqBOFC3*e?Kzepa_e!ZBNXvC?S}+cE z5rBF4SqiQPzx;-@p<=O`x}*`U*AWq3I46B~$yTxc^h~_C zYX2c6pZ!aLKT`Dl-7(ooILIEpTAPA18CeMd;JN~^UdTI!#j-_Wm%lYsY&v2m_6|fB zxNzu6C5_L30S}x5Z;w#w8is=nkuC?VA#q6wg?jvm^x8Y`3rF|O1@?;%25%|(ePF6N z#XpqcV^MRN`GZe+f&zw8zzyk4gvg)}AYa25pt%!Bh`O`|u^b5}a{Nv>sasIFJK8JF z`aUjr2Bce%qG#hk(`Um$U?xmJjxGUgOaA-3`vvE|A0A~eYJEaQD*#Dx_y5)2cgHoE zt?TMIii#R((uCOPB07R7LNe+A0t1nbve;Pyk_I?S^E7%Jeuz8o^n#dDADE6yVq(2X;0?ZH4QkQKvL#C3jI3^iv zSfa(&Y$S9N#q8;Dob;qzq3sf%1i9P0Xr17fEAV!$`%HTZKQ6;y06*@mMal%7mxb=F z|5e_~l93_*iL(03`*sbyn4n3F?-UXndbbQ{_ZuUV>W9j?Yj#fHXJ-iqOdq3D>J9HM zJlGkp(?8l)PmifAP8d3+R??okJK0=sr*DJrpDU7`Dld|f(7qnCZ|i=TV2F@`SAPn= zurOe8C-c!s=P8ea`eB2Nk%$8aM?^L*UONB+ddKX_Kfs5>$e%T~m>Stn*7zd18iv%RecgV}YQTrZvLKh~)0Pode3C{o=xg0!&lCwrv z=LZN&d=ugcZ$c|LsZ5ds@Zhm-rmGUp@)givXGD_o@)TS1ccyFK_fsN2My1pZU$SH} z(UWE|?Uy+QUKeXn8;?&iyEB6$ZjHV0Y#OKy_VIWj_$!OZ74(IR->y51N;r|1;l9uj z8;)t9<~jwKY4fx*oJaQMf9 z>@C``7QZg8hP3fDO=*w>LZDaOI32u5?eCxGZG2tpPTV+PGD=eZGF#yLq%g(ebbadU zMCoA?FrDDr^nl9ekfe#W<2CIdI2~NHCJa!e&muP;Vw0H$Vb5=rUn!ef>ZPHWjimq+Tuuv4BW^7h07*xrIgL zN##iQtUoS0v_6bXA^Y|M8#{&x0bKQ4VBw}imeOXp#b^aWv;AoBf> zz(dixt^DMP0>ip~QccxP9_22N*tX7Oes+nxvZXT2{x)_Vu}9#W&1T6F^gtHNc9AWw zqX02L&?_7ZtiwUp^L9wkP9g;Fqul5%K^^>xf9C$pH`RNd!)Ke4U-njA6HNi}uiyA| z5BU2J1s1%K&`N_2Cg@o(9wPd8z?r^#(gAdqziXlM=~t&4-%8dNz|<0 z54HC@bRunV;1mE$#p?r$ZWnStMj44oe3f~?(mnC^O>WofNUwFz14gv(m|eZqmpL(0 zYR}4S+Xgb8&Mozp{BrCQ)#AT_YOxdzqWHf~mjFhR*3ze6>qx6~$z>UiXl1d6gxaVi z$nId(n8t>{WuRWdR=z<8YaLMoJ0*&XtB}wtc>SyB|-!5 z-d>w6RU1TX32>yua{K3u6bMHKs^)Mp3t#!}9XNQB=aQm3?d13}S$@d9^2mk^QqG0S zgklFp?!|6b<(-~RSfMONSv<{(+VjU<%|cfj%}kGD8z}1`a$8Cz;UpvoAIBx`g=B39 zcZzkw+2~cfZtzFjO{E6V4GOfk`DOpn`@=?!_C*(40GaN~S>VY#&89N|2EpDy7g>Ph z67(`~Xk;oI!Jl=v;A=A+0{+5B_4+`XKh#Pfh?La-x`Ph>MjDI+9dNj3DArND;5!vzn_| zq{D{ELq+d8%;fR$l|$uxGO&gM_x%pHIa_Fkx@t_1C95_%kK3z{^V%xIADgv_J&jsn zFfcK)lID9p!-g@dQaG~*tp?`o&kVJ^I8bi2OTj5a$)l~U+%~uHh~gbflW>{XR`&h1 z*cU>TL?ztJRDZ_(47OUx)KkY4{qD7yHa7a9KDJcdL(aK`>R^g(rOJi6F1LK!fOpYF zw6r3cEOc$rf?JY9TZ5-?kkQiJP(83P86d3SAQeWunFKQkE&59AKQNangI9lyUTq%4 z?TJUq&j8xex`9drFuQ#G3@pG=5TiYKs$dJ`#g3Hq=7ZcZSc0c-K{u!U+Jy){YTO2as62`2o>hAc~8L zo8byxjgw}Y#ycB;z3WJrGFp*lB1V(HwCgWp;R{~vG-!oYYk^dIbxEm)EJ9g zJ7*LJ-%Oz?vFs4p+!rwRu16foCdeAdYV3{Lh^o&_Dz_i+tKr=yssezcr>$q@Bm&8g zq$dY99;|#)-chQPicl9@LMV=ng6$wKtu;FjjzLX#CxW62kT{Y=JU%308*VF$sk zxPAE?)P@%U1sa1jO-_Qhw%s;*hji_j&H*K+YH8q>r+6H2&Nq8d?CMmmy5B_@{8L88 z>2HhoKi!iS=2UK`XS3gKw6D~b>M0*Ra9V8+7*#q|s%p7q==WzHwRAA$0h)eV%Wv%Y zKXu|kF8!xYyyDWG_-y{LIGZ$*3!*EN0P7}?c5v8niH7|X6Z&%CfGO1>c8_fkXuMCJ zdjTk7_c?m!c1hu4YbcJN+qQ=qH}i3sphdd86cFLgCYq~r1GNw6)LuRKV+eiYNL%@F zLmzPGQ(+KDb2p0lhizWv-YV4w0TRqrDaexZR8SnZM7b6X4c|Ag-0jZma( z*yE``PPd~K%^gJtp!b|rnI+;c`-m$bq!l0Cjs}Z;4Qp1NOweDkU2PG(}O5AvlWCI!0C_B}K03vyv zS-iwp6_Zq7HtqagzjH*dTfh6RzuDN+d@RN@d6SL;{G_WxdaRC|!?E)ex4n`pz6+(Q zCHtMqruw7%^0qoTmHa4SGjv>V@Jq;DWbPq0=bL1U zP2%Dk*Kjjvk{d*zGj$p?-y^bs!r7&%=F4wSXKAh%SWr5!I2Esef~}g{2U8QNFHr67 z=(C_W*(e5#hQfX!aOG}`A_DU5<@A5zlamE;|w6 zyfCzFEj}^y)awDE{JCg92LzfwE!2nNP6~9I>6>YL#bNxOR&;U>uHz!Y7!UqmkKrqM zL`8z>u%R(;q_`bfZ5m^)G)`WDMJf{w@Y&7#m|+Q=>tYONeMBo+o~Dh4qS~;P&84IG zlZ>2#xFS5N2YChtX~VA2&mfse9b~xpAVAL8LAUX7UeF*X@-uKXSogDA$g7Bh%9n;a zQa2l=HacSk>B5$}p-{34!HM4yL$%|{y&hZED>eb$VP+mtX&@v}hl7qM>W<;h^tjf~ zf}M;zgY_B0oY-1VX7p$hdszY>Y44Z`UpYC1q$wR@QIP;NSp%hldbXWRC0{M>16oCp zg4e+%ul9+|Zj-L!XUBhwBOj6W_0Jn_=#EhDB(ZkVi$fi=t1H$Ha2@j4ag^B9>QaZi z$Sm!AeUEJY^U0WQD!wnd;>20i69KN7p6~8V4_7+f4lY&8D7M0M%azBJ<(25T+R3=f zp*J)&5J&oByj?L*)5|7ZiJhZ|ix})dqb`yP*pHjj**gLDi4t1@-;*W@8K{c4@;ihH zP_P8lva4m7bT(jG#eCpXgx`SF$7)G2I2mf4cn6vfsLl-2zlN-wjf^`ieF0!XAd;D7 zg4h{4ZaDIYFjbO8+e+~0r=Om6W}AX6CxR}NDbg1o#ers$0G>jW_Z55d(Fvh?v{hmU zNIkq5qC94z+l-n=8g@<#zGJ@~=26ZxLb7 z8sQ?B_1b*BY=onDYyC|#LgEjT;VB(lb53v=!X;0&IUKUuj^c| zx6|}`frXqQu9>yz8`N6+Vhl}Xux8Di#EFMqptqv$zXAkGu^|O|NInHFaEZuI{JG>V z=_ki`K-WWOA0;t>gJRo?kIS~3BblJL02m6fAD3OLkZOTIC^|nABn&;OAo-D6xwDrH zY+cVDE-@R(^K;75;!Hj{tT`Kgm|}(%t1lDL98_JieLFA1t9K%@YbZB4acXQr6Y%w(?8$+=Ea2NX0Q8o;aQhW zPwJ?)2c=)VVG-b|zwNodAODH;m8_M@CAmuvouW&1+q%X=;U+e9W@-602O|2y+_Y4l zRtC&!InlPuC4dv#I(y#$rq-RW%gj_ex8K{`&njc9RWhcmx77ZC9so+V{+90W6Qioe zanWBuWD6*L0Oz|x0R56N2;fv6+l6Bk3ic-uULmzJ6)U`wcE4{YFEqnz=OZKjIXvqh zm}>tY(3AfQjH)6>^g-xf0uKLA5Q{%GQ~w)tTmGXbv{*m>?{21E1)Lh#Ul6*0HNuNQ zeojyqWVe%+gGP;-*jk`O1s#{qo_vAbBzIi=IW!s>e#@t_M4Dda?XS6wT9^BkU}Zu6 z-AQ-Tdi&YIiWhcgO$Jj~Ka$n|hyeU=%I?4SWWLJ7XBm3(;`zOUI=89=94{FU&b%lP zgk^Z9*%P(FrpE|5o=&bs%|wYJ2sXWha4tHYwb~qB4x)1RM=_8!?vE`@fy&t2gnK}N zgKJLU@_pWv2uj(oHq?5E_{uFAjdgr&))Q@RDERC{qk3rB>tQ%Q*$cbES$dVk&Y|rk z^&O&v2JE(v%f3mKUQt_kDqR@<`hL>@<)v4IhFRasg}3Z?4`jWL`f@mDAM1R3to_Z8 zpR*lS62FzUkom`^QKLHSSMk!Fc77sr%kjmwZ%nPHOdS0TiFvRMv}D>*YkLG}mo&za zUOI*xE!`x^L%;)oV``G|bOaAJrK#1sYn}w39NTaov2U<3lmlCf$FhYKj(XLUW9FsI za>t}{XP9kFKyM;$grOAg@wI*iP03j){$)u_F)1)1Q~ynh*|oys{gNv-Es9fiM~5i$ z0cKSJgC8`GI~UtW%=?&OnQkFm-DgqB)BCN0a4(Qcob^&;Y!Z$>>LpbvZ6V1t9{P#c z9me9Uu&SNrZDAMYtZHkYN^T4HR zUN9d+9HZLe6YmGP+{-LHBIo4f!nUong(%p*RXqtl{i;^T&jMppw%SY=jZTnk*0;F+~g4}{^G ziflRE3k%)vXO1y|3gU@p_-wPtEC9Z-(UkuXit1P(C5cfb7}HwbU4S!-3h_o?4b9V6 z)wOCIWK&XTx>(XWV_qx?M%>pm-mDzo^BAoO)iKa&?0%z=@;BzoVZ!!|x`Id))WrJmB%1s4ShdaJ1 zp#)#YNT3jVv7mftNq9!h_Z?<<(p&9}Ga5qcWG(g)qsR=-H zsLUAK3ST)6WtZR=;Gg4r0GLwli7D6^5eVv{TatVvrUxK1^0eLHW^ETVjH9n0FA7J_y+tzk?-ji`MDD>WbTWVxB^4`_$N^unq*|oxRLC5Z7 z->e!2ihcOZcx?vi=D=%TlC@|2?Af zKiUaR!xC2jrl#0IlHaJoImlC;tam68oNRS^?gLVgQUx%!Y2ryNY~5N zqlh!*z+6M0Qd;)asF2_C?Q3gcS_&zB+s97FFtyz8*3;aJnRCYK&wstP%)i~Ldh z(WFRk+P*tuVtuib%bxw;o`wfxHr4oZ?p^=ZQa|(}+kvV(5bcteJ8uM5I~h9rr1(oo zfq5ucM3jZ5VqJ8?*mfvIk}0|NR~QE^-T_}F)gfp}+eP8R{8XXx2$FpgOwflU#X^gd zJ<@jRQ_(sk6UlT#DiMdteEUgc04W}EKp;k{_CGe&G=hAv{5Qk)>1+o6frj>*j&b@d zU~TmK7O)8s?6`s1n4Vd8<%C_v{+xcT9N03OLd(0OPdIHu;yrWlB}i#Y5!GC~cDXC* zS(=#OpS0K&=zkHE=b5KUAz1XwUhlt1BGkaUCQ0Fv^Qqxs2+B7 zE!Cs>(@s6t>4JqoAD0~kg{%w4jYVw)q~&uBmBgpgEduLAkZHpKBosv-X$x{a70%R0 zC7HQ52Ob=spQX1Tnb>v&QjndDkRz-b@H+I2fW`73L!@>PNr0@fuA0m-nuTH66u_X~ zGy;c{#;+k%0KsNhXvM!J-73i^xN}$|XUEs~%y2h65;+pv$S@MtXc-nEH#i52t3P+2 z%ljNC$6j3xF~EVo?%XVzeLLn3NKdXq=nGy&&E+3-66nN=gZNyIYiyz4zH279*C^0rytLl>U^gU`w`CB7bD1S zzSMDLkxC#7-ZCt|bapwL&OCv;{2pHYCLfvlhPK_Gv_=cEk7U14=PJiZweil)08mF& zSPMxSZQ~-Nzqli|J!?F(>uv~IgDF0cj)EdfA{qQ@_PKO^6LH(VTr3+pN8CC!3!Rz5`tuwdtFy+&1mfUlp?cGdqhfTKd1_lVav_ z587+PT#7P{%Ma8C?9Q|e#kgdgDAwz(JQBz6FV@q#=;%RIVlx%X_f0-4$zba}OWEIU zd+yd&*S_FrucFsa$@N9WPSNk~+^h7zRT7`+yRCc5t@Vi+lyf6X8=shYR`+3sqvc9q zfAzb7$>u++&3pJ~4b*`DS>POi;@za-yuKGZ{VaQ!Cmu~WIJ$Dm%l5xJ40mIgs@2-u zxmsLqTyil&uRnYu=qPXl$o(yN?XPFPwB6ZXu_Z{?RD2z%SO8h}uMpJK4ME8=;CQLH zXpmV$5oh5bogPU(F9kV&1sOQCAfzpwom%ssM1@O<4#95mpWV(xeM?s0Zm#q=BM;JK z5CRMKfj^PkNyFl5pk05sy?F_SvinbD(AWBB=g~wsZV@IQP1U&)_CwQoQkE{Dc)v!> z{2tL;%!ODVm+4r7&bnv|31GtWe$w9gPLN<|N1y2eC5$s@F)VbWHKxn{=oi8Ipe*Hd z072Gvf!JM~0Z1JW($@e|XQIxOmeMFhviitRehrG(9 z@m2l8MOF2Rr4htGWrhFqC45I#hqR~Lh}w`v)hNr0d4%83*;mTNzSh2Ko$gGfLpB0C zc8dq|3&OqU))9iwdYmxYKb#pxJ&GqTc*M^IyfsQNL&wjuH(d&=F7Y0lG_7-^gc{}zyP1+sEJZe6l9mh%=)tTJ(rGS+J zRxEnt28dkV&H z_@ghG6>c!iT+;aBOSo^Zr6Q1iENx{3=8mPDFMgLRt+b?mhc>sQ?L{Vz-8lqb@J8i; zHR^+ofIJV(DS&5L)oMOTX(=m<4?0W8eTw2nfx87s$bB-NUv1R}DP2VWrf z|1tlGDFo~P`S)MXg6K~|zzC-6KoEAL(p z1!G2VqDsC?`SHb}mpHK#MCAk9>?NTTLM# zC#EX>_WF};1v>|7Qe?h1yIK)>`nHGcD71d8@FMm!?xpv0OLZw++Nmi6k;lm@&mmK; zM#t;{t_O%Ih6!tvgi-yw=%;ZCVgw+vcp$dmv);EIgF1wpCAXyt;thOO2PFlrfH2=T z8_~W|EH5c0n&KN=hUT?~c8XQ`cI`RvSR&k?UJRU9;4)$-LC1`U9SIvxWWZa2&#FIY z9m2f$FDoj=76Me8y)t7DgahcSGbI3FBuM>BqbY~A44>PosmL!#FZIR8wGHv1>E`Mq zMHptxATMF==uPsmD1G_z_`>w3##4uHpGm*s|KvYW!k=^gMWut5qzsZJJX4~gM-#k&`8AROas(A%h7 z`6K>pyBR%p9<~8 zRd@$R2TL7^G5QNyrcw3|zQF?`-NyGXMsviGVU0Rv&^t!mrNKCm(dfrPZi14I_P!DO z6r%CCR<}zXv9r7#Lm{0_D?IC(9$X33|F8u-Ud5s>qywxKbPW76f^Xw+BT7&^%+bsj zyyKY8R&wAY!Q-i|lMajVjB-~>#@ z9mlr5EcPr=5D4=zA~(W8h{}0|*zr22bf@MDW!qaP1jc(_OwXi}gF4B*5GDzt~ z=6vRJ8;i<``~lbw<$ZO#Z8i_R-}t@2Ug6fYhV2IGuHvV7#$icA6>+DuV^h#5!BLXg z2rnXRmR!FH1V$vGkK`IX04*n0uNKT96+$cES3xdCSQKAbH~<|H84-IBDz#7qj^At?GKdg};s84bz?uO@4uQrY~u< zy-6xRK9%(ymZ&yl1RhKaO>C}eX{@0;L%OAJ-cZ)7|HTl`cF1^o_6wWMAv)wZs>ov?Mc15aXVY2~_iJG14K^($azH*B3NC3k7%@|jt3q7=^g>)u{e zOWi&pl=n{7+~UKD315Y$+nx3VMdxWHMo;z^$kmg5K=J#Z!b2DLO<>b=k01Ifo~HO5 zU+{jWekhYW3tAoQ=Wt9KY}QES3BLh&&_$f+kC0d)yxu^-+`B?9ZNT$U<*0c}kB=P@7#RALez zFXBvVN*7hoR)dRvUbsc!;v}JW$x$Go{%Z(J&LS;#E)e}dS*rcM9VgB1g7g1*?B@`c z|DO)urnzkZ8HiSXJv_DNUA2VDnKZ+T_1a*{rIr%KNxKy%yJ2 zxvMV{*IM89KEBcVu6^K1aFlmfR724l@lh@V)EBs8A=oB&j{zL@;D^$thKB{Hn%6hY z>wOMhEZIT68xFPSAV%0VtM2D}789K%w_`IjD?G9fEG1A&@ir9Yo8Rx}VkdInIx6#1SuHSI!? z2l3gZx>lph1v><*>bRtlxBZ?psEdmw$#<6EE1aK+HOe4snuCqyApyfV*ew4 z_2jTnnfcTD@qN;A0$X1xE2UbT0$!Y`mFI+ z4AeTtZC?yskyis2TYn=JpWAg<4ka34%x}SiXh@@xsqXzZ`zgdN$DzOYJi(P8F=WM7 z-tIXdfKv&R>EY%bDt1D3&s>2k^XDx>} z6g{qTU*pVZxvQwO7Gvo$fiX4Fvvne!0fvl2#Jr!OiC_Etq|p7hRp?rVk?;K)u=rc! z@D$P?dA`~|F8d>2Q-WR9Oa(CAS*}DB5J@^x2OU2<9}j({)Te! zm*0c6(=Vgnens2>vI`)v3o5&M4Sk9To~S9Lf2znRi@wl9T88D4{=kRmqa^ka+#3q3pWJ-C3|94P-^OzogUwPSN7;7a$ z79#rCvW^I@rWQ`40Y7NeQh@~n zw`Tvp{_fK&@h^HMreTTjYDB7FZ^r||SEvNCLZeLObLa?TOqNdNqs0ctYnqPO@oCkZ z+2ErOA4YW`*Ea@+Zzx>PN}+x~k=4G?Jr)s0wK4p=>euT)jY5i)Tj1c`GeE{FPDN(3XK181%~@<;3mphf!#Pcezs8y z zlC6=|Tv~)NC}aMBQJ2zVu^yctRskrHwdMRbKnx0e6vyE*Xh_*XWSm9%1^|w6A=9br zjz^}sr+J|tynf)(EX3?cJ8DkXdvU`~bKxO82BFv|mH|hoyIcc&Xyw-{G#4!AhsPL4 zMuav1&>BQMgNDN`%mPhhn$}CNsocqK1YXeR#=^b{i!V2rH3U+19z4H}{#3GVN9p_> zL#y1c9cI0^%+TFNaOkDUQhDuA7aTk?a^Nm_B#U<0v zPB+P~KODIC2-Hv+P_R3#+x_a;Fe9C?5*jUH_Ec>9{z{}pqgMsw$=siR=FlB)O!aC; zOIq7Bbpn9mK6fEp8|$->z&*2logA4qpOYnb58ud&H zMnm6GQOm`Sg4D~@F7&3dYjEhO34Ozqn(*Z+(1WX~8#B)iJXja$4P#(oGC+nf5Ga<7 z5K1&qd;%L830y;Q}R`e);{i2Y_rQ{<2Yk$QOQd`yldxBuytxSKf+O zZq0V5&eV>c%jz48RdF|sWtgRvnq7@ib_&V!(d!xMC~$f1lvJwc)7+-}mU`+t0JL|t z{N7~VSTT-@4kgC{U<DL}+f28RA)UVu#}*WEJ~O=`67#`KPqH zY8OeZ3{%hW!-UbP$&nE&6Qc^Zc_xVDnEK69^XF92fB4)FSAi&Yd>-gAOsd6Rlaz#W zd*A^G#b>;Iqjlo#3nk@SsK9;>9@qa}%4(-!1)Xhdb~Ig@YGT{WzoFt%@n&bN6_IoB)| zolSrDbpJi7>mtCV>n3gjgg5Zq$A((0eY?Oq27IkKrtNU`9m3uxia|`V9Rx7Jc;UXC z4<=IDZ=B{dMDBZYNc55G3;Usg{>bQw zYDoA^)ZKh&hgwa{6oCkfAO{3u7y>Sy>ggAgYMy080a2eH~G0!xEj6Kh_p6XY(#DpFE%2h9D&8kKaaZqy%G7( zhx&B*s81K?)06Y*wfg1!@@Z1|G%0*qPW~TXYu)n*CnRKKU}_3$HBC>fB0$d`5*cEo z%1{H?x4_q#+mL`0S21VsHvQyHyog~|8e@{wwPD&x(nJk38}+E|r($o^bS6m*oFBx_ fZ%La*HC{edn?5K1+Yuwbh7)}n|L?hOA4mQVpe8QH literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/WriteEventBuffer.jpg b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/WriteEventBuffer.jpg new file mode 100644 index 0000000000000000000000000000000000000000..67678a5e2a0d35cefa42efa99a7964bd3b123a8a GIT binary patch literal 38763 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 LKmPYJUwi)-Wbo_S literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md new file mode 100644 index 00000000000..e93416293d7 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md @@ -0,0 +1,117 @@ +# Svc::ActiveLogger Component + +## 1. Introduction + +The `Svc::ActiveLogger` component processes events from other components. The events are put in packets and sent to an +external component like the ground interface. The component provides event filtering capability such that events may +be turned off via ID or severity. + +## 2. Requirements + +The requirements for `Svc::ActiveLogger` are as follows: + +Requirement | Description | Verification Method +----------- | ----------- | ------------------- +AL-001 | The `Svc::ActiveLogger` component shall receive events and compose them into downlink packets. | Inspection; Unit Test +AL-002 | The `Svc::ActiveLogger` component shall have commands to filter events based on event severity. | Unit Test +AL-003 | The `Svc::ActiveLogger` component shall have commands to filter events based on the event ID. | Unit Test +AL-004 | The `Svc::ActiveLogger` component shall call fatalOut port when FATAL is received | Inspection; Unit Test + +## 3. Design + +### 3.1 Context + +#### 3.1.1 Component Diagram + +The `Svc::ActiveLogger` component has the following component diagram: + +![`Svc::ActiveLogger` Diagram](img/ActiveLoggerBDD.jpg "Svc::ActiveLogger") + +#### 3.1.2 Ports + +The `Svc::ActiveLogger` component uses the following port types: + +Port Data Type | Name | Direction | Kind | Usage +-------------- | ---- | --------- | ---- | ----- +[`Fw::Log`](../../../Fw/Log/docs/sdd.md) | LogRecv | Input | Synchronous | Receive events from components +[`Fw::Com`](../../../Fw/Log/docs/sdd.md) | PktSend | Output | n/a | Send event packets to external user +[`Svc::FatalEvent`](../../../Svc/Fatal/docs/sdd.md) | FatalAnnounce | Output | n/a | Send FATAL event (to health) + +### 3.2 Functional Description + +The `Svc::ActiveLogger` component provides an event logging function for the software. The framework autocoder allows +developers to specify a set of events in the component XML +(see [Events](../../../docs/user-manual/overview/04-cmd-evt-chn-prm.md). For these components, the +autocoder will add an `Fw::Log` output port to send events in serialized form. The ActiveLogger receives these port +calls and provides commands to filter these events. The filtered events are sent to other components such as the ground +interface. + +**Note:** the Event ID value 0 is reserved for the logger. + +Should a FATAL severity event arrive, it is announced using a FATAL out port allow the system to respond when a FATAL +event is seen. + +#### 3.2.1 Filtering + +The `Svc::ActiveLogger` `LogRecv` input port handler filters events to lessen the load on the downstream components. The +filters can be set by severity and ID. By default, the DIAGNOSTIC events are filtered out since the number of DIAGNOSTIC +events can be quite high. All defaults can be globally configured in `config/ActiveLoggerImplCfg.hpp`. Filters are +modified at runtime by the `SET_EVENT_FILTER` command. + +The component also allows filtering events by event ID. There is a configuration parameter that sets the number of IDs +that can be filtered. This allows operators to mute a particular event that might be flooding the downstream components. +These filters are modified at runtime by the `SET_ID_FILTER` command. + +FATAL events are never filtered, so they can be caught and broadcast to the system. Outgoing events are converted into +the F´ ground format and sent out using the `PktSend` port. + + + +#### 3.2.2 Fatal Announce + +When the `ActiveLogger` component receives a FATAL event, it calls the FatalAnnounce port. Another component that +handles the system response to FATALs (such as resetting the system) can connect to this port to be informed when a +FATAL has occurred. + +### 3.3 Scenarios + +#### 3.3.1 Receive Events + +The `Svc::ActiveLogger` component accepts events from other components. + +### 3.4 State + +`Svc::ActiveLogger` has no state machines, but stores the state of the event severity and event ID filters. + +### 3.5 Algorithms + +`Svc::ActiveLogger` has no significant algorithms. + +## 4. Dictionaries + +TBD + +## 5. Module Checklists + +Checklist | +-------- | +[Design](Checklist_Design.xlsx) | +[Code](Checklist_Code.xlsx) | +[Unit Test](Checklist_Unit_Test.xls) | + +## 6. Unit Testing + +To see unit test coverage run fprime-util check --coverage + +## 7. Change Log + +Date | Description +---- | ----------- +6/25/2015 | Design review edits +7/22/2015 | Design review actions +9/7/2015 | Unit Test updates +10/28/2015 | Added FATAL announce port +12/1/2020 | Removed event buffers and post-filter + + + diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore new file mode 100644 index 00000000000..f8f1e57a822 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore @@ -0,0 +1 @@ +dump.dat diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp new file mode 100644 index 00000000000..513b88f4a3d --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp @@ -0,0 +1,625 @@ +/* + * ActiveLoggerImplTester.cpp + * + * Created on: Mar 18, 2015 + * Author: tcanham + */ + +#include +#include +#include +#include +#include +#include + +#include + +namespace Svc { + + typedef ActiveLogger_Enabled Enabled; + typedef ActiveLogger_FilterSeverity FilterSeverity; + + ActiveLoggerImplTester::ActiveLoggerImplTester(Svc::ActiveLoggerImpl& inst) : + Svc::ActiveLoggerGTestBase("testerbase",100), + m_impl(inst), + m_receivedPacket(false), + m_receivedFatalEvent(false) { + } + + ActiveLoggerImplTester::~ActiveLoggerImplTester() { + } + + void ActiveLoggerImplTester::from_PktSend_handler( + const FwIndexType portNum, //!< The port number + Fw::ComBuffer &data, //!< Buffer containing packet data + U32 context //!< context; not used + ) { + this->m_sentPacket = data; + this->m_receivedPacket = true; + } + + void ActiveLoggerImplTester::from_FatalAnnounce_handler( + const FwIndexType portNum, //!< The port number + FwEventIdType Id //!< The ID of the FATAL event + ) { + this->m_receivedFatalEvent = true; + this->m_fatalID = Id; + } + + void ActiveLoggerImplTester::runEventNominal() { + REQUIREMENT("AL-001"); + + this->writeEvent(29,Fw::LogSeverity::WARNING_HI,10); + } + + void ActiveLoggerImplTester::runWithFilters(Fw::LogSeverity filter) { + + REQUIREMENT("AL-002"); + + Fw::LogBuffer buff; + U32 val = 10; + FwEventIdType id = 29; + + Fw::SerializeStatus stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + Fw::Time timeTag(TB_NONE,0,0); + U32 cmdSeq = 21; + + // enable report filter + this->clearHistory(); + FilterSeverity reportFilterLevel = FilterSeverity::WARNING_HI; + + switch (filter.e) { + case Fw::LogSeverity::WARNING_HI: + reportFilterLevel = FilterSeverity::WARNING_HI; + break; + case Fw::LogSeverity::WARNING_LO: + reportFilterLevel = FilterSeverity::WARNING_LO; + break; + case Fw::LogSeverity::COMMAND: + reportFilterLevel = FilterSeverity::COMMAND; + break; + case Fw::LogSeverity::ACTIVITY_HI: + reportFilterLevel = FilterSeverity::ACTIVITY_HI; + break; + case Fw::LogSeverity::ACTIVITY_LO: + reportFilterLevel = FilterSeverity::ACTIVITY_LO; + break; + case Fw::LogSeverity::DIAGNOSTIC: + reportFilterLevel = FilterSeverity::DIAGNOSTIC; + break; + default: + ASSERT_TRUE(false); + break; + } + + this->clearHistory(); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,Enabled::ENABLED); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, + cmdSeq, + Fw::CmdResponse::OK + ); + + this->m_receivedPacket = false; + + this->invoke_to_LogRecv(0,id,timeTag,filter,buff); + + // should not have received packet + ASSERT_FALSE(this->m_receivedPacket); + // dispatch message + this->m_impl.doDispatch(); + // should have received packet + ASSERT_TRUE(this->m_receivedPacket); + // verify contents + // first piece should be log packet descriptor + FwPacketDescriptorType desc; + stat = this->m_sentPacket.deserialize(desc); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); + // next piece should be event ID + FwEventIdType sentId; + stat = this->m_sentPacket.deserialize(sentId); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(sentId,id); + // next piece is time tag + Fw::Time recTimeTag(TB_NONE,0,0); + stat = this->m_sentPacket.deserialize(recTimeTag); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_TRUE(timeTag == recTimeTag); + // next piece is event argument + U32 readVal; + stat = this->m_sentPacket.deserialize(readVal); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(readVal, val); + // packet should be empty + ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); + + // Disable severity filter + this->clearHistory(); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,Enabled::DISABLED); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, + cmdSeq, + Fw::CmdResponse::OK + ); + + this->m_receivedPacket = false; + + this->invoke_to_LogRecv(0,id,timeTag,filter,buff); + + // should not have received packet - all we can check since no message is dispatched. + ASSERT_FALSE(this->m_receivedPacket); + } + + void ActiveLoggerImplTester::runFilterInvalidCommands() { + + U32 cmdSeq = 21; + this->clearHistory(); + FilterSeverity reportFilterLevel = FilterSeverity::WARNING_HI; + Enabled filterEnabled(static_cast(10)); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,filterEnabled); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, + cmdSeq, + Fw::CmdResponse::FORMAT_ERROR + ); + this->clearHistory(); + reportFilterLevel = FilterSeverity::WARNING_HI; + filterEnabled.e = static_cast(-2); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,filterEnabled); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, + cmdSeq, + Fw::CmdResponse::FORMAT_ERROR + ); + FilterSeverity eventLevel; + this->clearHistory(); + Enabled reportEnable = Enabled::ENABLED; + eventLevel.e = static_cast(-1); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,eventLevel,reportEnable); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, + cmdSeq, + Fw::CmdResponse::FORMAT_ERROR + ); + + this->clearHistory(); + + reportEnable = Enabled::ENABLED; + eventLevel.e = static_cast(100); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,eventLevel,reportEnable); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, + cmdSeq, + Fw::CmdResponse::FORMAT_ERROR + ); + + } + + void ActiveLoggerImplTester::runFilterEventNominal() { + + for (Fw::LogSeverity::t sev = Fw::LogSeverity::WARNING_HI; sev <= Fw::LogSeverity::DIAGNOSTIC; sev = static_cast(sev + 1)) { + this->runWithFilters(sev); + } + + } + + void ActiveLoggerImplTester::runFilterIdNominal() { + + U32 cmdSeq = 21; + + // for a set of IDs, fill filter + + REQUIREMENT("AL-003"); + + for (FwSizeType filterID = 1; filterID <= TELEM_ID_FILTER_SIZE; filterID++) { + this->clearHistory(); + this->clearEvents(); + this->sendCmd_SET_ID_FILTER(0,cmdSeq,filterID,Enabled::ENABLED); + // dispatch message + this->m_impl.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_ID_FILTER, + cmdSeq, + Fw::CmdResponse::OK + ); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_ID_FILTER_ENABLED_SIZE(1); + ASSERT_EVENTS_ID_FILTER_ENABLED(0,filterID); + // send it again, to verify it will accept a second add + this->clearHistory(); + this->clearEvents(); + this->sendCmd_SET_ID_FILTER(0,cmdSeq,filterID,Enabled::ENABLED); + // dispatch message + this->m_impl.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_ID_FILTER, + cmdSeq, + Fw::CmdResponse::OK + ); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_ID_FILTER_ENABLED_SIZE(1); + ASSERT_EVENTS_ID_FILTER_ENABLED(0,filterID); + + } + + // Try to send the IDs that are filtered + for (FwSizeType filterID = 1; filterID <= TELEM_ID_FILTER_SIZE; filterID++) { + this->clearHistory(); + this->clearEvents(); + + Fw::LogBuffer buff; + U32 val = 10; + FwEventIdType id = filterID; + + Fw::SerializeStatus stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + Fw::Time timeTag(TB_NONE,0,0); + + this->m_receivedPacket = false; + + this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::ACTIVITY_HI,buff); + + // should not get a packet + ASSERT_FALSE(this->m_receivedPacket); + + } + + // send one of the IDs as a FATAL, it should not be filtered event thought the ID is in the filter + this->clearHistory(); + this->clearEvents(); + + Fw::LogBuffer buff; + U32 val = 10; + FwEventIdType id = 1; + + Fw::SerializeStatus stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + Fw::Time timeTag(TB_NONE,0,0); + + this->m_receivedPacket = false; + + this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::FATAL,buff); + this->m_impl.doDispatch(); + + // should get a packet anyway + ASSERT_TRUE(this->m_receivedPacket); + + // Try to add to the full filter. It should be rejected + this->clearHistory(); + this->clearEvents(); + this->sendCmd_SET_ID_FILTER(0,cmdSeq,TELEM_ID_FILTER_SIZE+1,Enabled::ENABLED); + // dispatch message + this->m_impl.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_ID_FILTER, + cmdSeq, + Fw::CmdResponse::EXECUTION_ERROR + ); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_ID_FILTER_LIST_FULL_SIZE(1); + ASSERT_EVENTS_ID_FILTER_LIST_FULL(0,TELEM_ID_FILTER_SIZE+1); + + // Now clear them + + for (FwSizeType filterID = 1; filterID <= TELEM_ID_FILTER_SIZE; filterID++) { + this->clearHistory(); + this->clearEvents(); + this->sendCmd_SET_ID_FILTER(0,cmdSeq,filterID,Enabled::DISABLED); + // dispatch message + this->m_impl.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_ID_FILTER, + cmdSeq, + Fw::CmdResponse::OK + ); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_ID_FILTER_REMOVED_SIZE(1); + ASSERT_EVENTS_ID_FILTER_REMOVED(0,filterID); + } + + // Try to clear one that doesn't exist + + this->clearHistory(); + this->clearEvents(); + this->sendCmd_SET_ID_FILTER(0,cmdSeq,10,Enabled::DISABLED); + // dispatch message + this->m_impl.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_ID_FILTER, + cmdSeq, + Fw::CmdResponse::EXECUTION_ERROR + ); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_ID_FILTER_NOT_FOUND_SIZE(1); + ASSERT_EVENTS_ID_FILTER_NOT_FOUND(0,10); + + // Send an invalid argument + this->clearHistory(); + this->clearEvents(); + Enabled idEnabled(static_cast(10)); + this->sendCmd_SET_ID_FILTER(0,cmdSeq,10,idEnabled); + // dispatch message + this->m_impl.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_ID_FILTER, + cmdSeq, + Fw::CmdResponse::FORMAT_ERROR + ); + ASSERT_EVENTS_SIZE(0); + + } + + void ActiveLoggerImplTester::runFilterDump() { + U32 cmdSeq = 21; + // set random set of filters + + this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::WARNING_HI,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::WARNING_LO,Enabled::DISABLED); + this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::COMMAND,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::ACTIVITY_HI,Enabled::DISABLED); + this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::ACTIVITY_LO,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::DIAGNOSTIC,Enabled::ENABLED); + + this->sendCmd_SET_ID_FILTER(0,cmdSeq,4,Enabled::ENABLED); + // dispatch message + this->m_impl.doDispatch(); + + this->sendCmd_SET_ID_FILTER(0,cmdSeq,13,Enabled::ENABLED); + // dispatch message + this->m_impl.doDispatch(); + + this->sendCmd_SET_ID_FILTER(0,cmdSeq,4000,Enabled::ENABLED); + // dispatch message + this->m_impl.doDispatch(); + + // send command to dump the filters + + this->clearHistory(); + this->clearEvents(); + this->sendCmd_DUMP_FILTER_STATE(0,cmdSeq); + // dispatch message + this->m_impl.doDispatch(); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_DUMP_FILTER_STATE, + cmdSeq, + Fw::CmdResponse::OK + ); + ASSERT_EVENTS_SIZE(6+3); + ASSERT_EVENTS_SEVERITY_FILTER_STATE_SIZE(6); + ASSERT_EVENTS_SEVERITY_FILTER_STATE(0,FilterSeverity::WARNING_HI,true); + ASSERT_EVENTS_SEVERITY_FILTER_STATE(1,FilterSeverity::WARNING_LO,false); + ASSERT_EVENTS_SEVERITY_FILTER_STATE(2,FilterSeverity::COMMAND,true); + ASSERT_EVENTS_SEVERITY_FILTER_STATE(3,FilterSeverity::ACTIVITY_HI,false); + ASSERT_EVENTS_SEVERITY_FILTER_STATE(4,FilterSeverity::ACTIVITY_LO,true); + ASSERT_EVENTS_SEVERITY_FILTER_STATE(5,FilterSeverity::DIAGNOSTIC,true); + } + + void ActiveLoggerImplTester::runEventFatal() { + Fw::LogBuffer buff; + U32 val = 10; + FwEventIdType id = 29; + U32 cmdSeq = 21; + REQUIREMENT("AL-004"); + + Fw::SerializeStatus stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + Fw::Time timeTag(TB_NONE,0,0); + + this->m_receivedPacket = false; + + this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::FATAL,buff); + + // should not have received packet + ASSERT_FALSE(this->m_receivedPacket); + // should have seen event port + ASSERT_TRUE(this->m_receivedFatalEvent); + ASSERT_EQ(this->m_fatalID,id); + // dispatch message + this->m_impl.doDispatch(); + // should have received packet + ASSERT_TRUE(this->m_receivedPacket); + // verify contents + // first piece should be log packet descriptor + FwPacketDescriptorType desc; + stat = this->m_sentPacket.deserialize(desc); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); + // next piece should be event ID + FwEventIdType sentId; + stat = this->m_sentPacket.deserialize(sentId); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(sentId,id); + // next piece is time tag + Fw::Time recTimeTag(TB_NONE,0,0); + stat = this->m_sentPacket.deserialize(recTimeTag); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_TRUE(timeTag == recTimeTag); + // next piece is event argument + U32 readVal; + stat = this->m_sentPacket.deserialize(readVal); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(readVal, val); + // packet should be empty + ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); + // Turn on all filters and make sure FATAL still gets through + + this->clearHistory(); + this->clearEvents(); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_HI,Enabled::DISABLED); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE( + 0, + ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, + cmdSeq, + Fw::CmdResponse::OK + ); + + + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_LO,Enabled::DISABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::COMMAND,Enabled::DISABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_HI,Enabled::DISABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_LO,Enabled::DISABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::DIAGNOSTIC,Enabled::DISABLED); + + this->m_receivedPacket = false; + + this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::FATAL,buff); + + // should not have received packet + ASSERT_FALSE(this->m_receivedPacket); + // dispatch message + this->m_impl.doDispatch(); + // should have received packet + ASSERT_TRUE(this->m_receivedPacket); + // verify contents + // first piece should be log packet descriptor + stat = this->m_sentPacket.deserialize(desc); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); + // next piece should be event ID + stat = this->m_sentPacket.deserialize(sentId); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(sentId,id); + // next piece is time tag + stat = this->m_sentPacket.deserialize(recTimeTag); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_TRUE(timeTag == recTimeTag); + // next piece is event argument + stat = this->m_sentPacket.deserialize(readVal); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(readVal, val); + // packet should be empty + ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); + + // turn off filters + + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_HI,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_LO,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::COMMAND,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_HI,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_LO,Enabled::ENABLED); + this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::DIAGNOSTIC,Enabled::ENABLED); + + } + + void ActiveLoggerImplTester::writeEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value) { + Fw::LogBuffer buff; + + Fw::SerializeStatus stat = buff.serialize(value); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + Fw::Time timeTag(TB_NONE,1,2); + + this->m_receivedPacket = false; + + this->invoke_to_LogRecv(0,id,timeTag,severity,buff); + + // should not have received packet + ASSERT_FALSE(this->m_receivedPacket); + // dispatch message + this->m_impl.doDispatch(); + // should have received packet + ASSERT_TRUE(this->m_receivedPacket); + // verify contents + // first piece should be log packet descriptor + FwPacketDescriptorType desc; + stat = this->m_sentPacket.deserialize(desc); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); + // next piece should be event ID + FwEventIdType sentId; + stat = this->m_sentPacket.deserialize(sentId); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(sentId,id); + // next piece is time tag + Fw::Time recTimeTag(TB_NONE,1,2); + stat = this->m_sentPacket.deserialize(recTimeTag); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_TRUE(timeTag == recTimeTag); + // next piece is event argument + U32 readVal; + stat = this->m_sentPacket.deserialize(readVal); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); + ASSERT_EQ(readVal, value); + // packet should be empty + ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); + + } + + void ActiveLoggerImplTester::readEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value, Os::File& file) { + static const BYTE delimiter = 0xA5; + + // first read should be delimiter + BYTE de; + FwSizeType readSize = static_cast(sizeof(de)); + + ASSERT_EQ(file.read(&de,readSize,Os::File::WaitType::WAIT),Os::File::OP_OK); + ASSERT_EQ(delimiter,de); + // next is LogPacket + Fw::ComBuffer comBuff; + // size is specific to this test + readSize = sizeof(FwPacketDescriptorType) + sizeof(FwEventIdType) + Fw::Time::SERIALIZED_SIZE + sizeof(U32); + ASSERT_EQ(file.read(comBuff.getBuffAddr(),readSize,Os::File::WaitType::WAIT),Os::File::OP_OK); + comBuff.setBuffLen(readSize); + + // deserialize LogPacket + Fw::LogPacket packet; + Fw::Time time(TB_NONE,1,2); + Fw::LogBuffer logBuff; + ASSERT_EQ(comBuff.deserialize(packet),Fw::FW_SERIALIZE_OK); + + // read back values + ASSERT_EQ(id,packet.getId()); + ASSERT_EQ(time,packet.getTimeTag()); + logBuff = packet.getLogBuffer(); + U32 readValue; + ASSERT_EQ(logBuff.deserialize(readValue),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(value,readValue); + + } + + void ActiveLoggerImplTester::textLogIn(const FwEventIdType id, //!< The event ID + const Fw::Time& timeTag, //!< The time + const Fw::LogSeverity severity, //!< The severity + const Fw::TextLogString& text //!< The event string + ) { + TextLogEntry e = { id, timeTag, severity, text }; + + printTextLogHistoryEntry(e, stdout); + } + void ActiveLoggerImplTester :: + from_pingOut_handler( + const FwIndexType portNum, + U32 key + ) + { + this->pushFromPortEntry_pingOut(key); + } +} /* namespace SvcTest */ diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp new file mode 100644 index 00000000000..55fadd8d0e3 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp @@ -0,0 +1,80 @@ +/* + * ActiveLoggerImplTester.hpp + * + * Created on: Mar 18, 2015 + * Author: tcanham + */ + +#ifndef ACTIVELOGGER_TEST_UT_ACTIVELOGGERIMPLTESTER_HPP_ +#define ACTIVELOGGER_TEST_UT_ACTIVELOGGERIMPLTESTER_HPP_ + +#include +#include +#include + +namespace Svc { + + class ActiveLoggerImplTester: public Svc::ActiveLoggerGTestBase { + public: + ActiveLoggerImplTester(Svc::ActiveLoggerImpl& inst); + virtual ~ActiveLoggerImplTester(); + + void runEventNominal(); + void runFilterEventNominal(); + void runFilterIdNominal(); + void runFilterDump(); + void runFilterInvalidCommands(); + void runEventFatal(); + void runFileDump(); + void runFileDumpErrors(); + + private: + + void from_PktSend_handler( + const FwIndexType portNum, //!< The port number + Fw::ComBuffer &data, //!< Buffer containing packet data + U32 context //!< context (not used) + ) override; + void from_FatalAnnounce_handler( + const FwIndexType portNum, //!< The port number + FwEventIdType Id //!< The ID of the FATAL event + ) override; + + Svc::ActiveLoggerImpl& m_impl; + + bool m_receivedPacket; + Fw::ComBuffer m_sentPacket; + + bool m_receivedFatalEvent; + FwEventIdType m_fatalID; + + void runWithFilters(Fw::LogSeverity filter); + + void writeEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value); + void readEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value, Os::File& file); + + // enumeration to tell what kind of error to inject + typedef enum { + FILE_WRITE_WRITE_ERROR, // return a bad read status + FILE_WRITE_SIZE_ERROR, // return a bad size + } FileWriteTestType; + FileWriteTestType m_writeTestType; + FwSizeType m_writeSize; + + void textLogIn(const FwEventIdType id, //!< The event ID + const Fw::Time& timeTag, //!< The time + const Fw::LogSeverity severity, //!< The severity + const Fw::TextLogString& text //!< The event string + ) override; + + //! Handler for from_pingOut + //! + void from_pingOut_handler( + const FwIndexType portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ) override; + }; + +} /* namespace Svc */ + +#endif /* ACTIVELOGGER_TEST_UT_ACTIVELOGGERIMPLTESTER_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp new file mode 100644 index 00000000000..013eecf59f9 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp @@ -0,0 +1,158 @@ +/* + * PrmDbTester.cpp + * + * Created on: Mar 18, 2015 + * Author: tcanham + */ + +#include +#include +#include +#include + +#include + +#if FW_OBJECT_REGISTRATION == 1 +static Fw::SimpleObjRegistry simpleReg; +#endif + +void connectPorts(Svc::ActiveLoggerImpl& impl, Svc::ActiveLoggerImplTester& tester) { + + tester.connect_to_CmdDisp(0,impl.get_CmdDisp_InputPort(0)); + impl.set_CmdStatus_OutputPort(0,tester.get_from_CmdStatus(0)); + impl.set_FatalAnnounce_OutputPort(0,tester.get_from_FatalAnnounce(0)); + + tester.connect_to_LogRecv(0,impl.get_LogRecv_InputPort(0)); + + impl.set_Log_OutputPort(0,tester.get_from_Log(0)); + impl.set_LogText_OutputPort(0,tester.get_from_LogText(0)); + + impl.set_PktSend_OutputPort(0,tester.get_from_PktSend(0)); + +#if FW_PORT_TRACING + // Fw::PortBase::setTrace(true); +#endif + + // simpleReg.dump(); +} + +TEST(ActiveLoggerTest,NominalEventSend) { + + TEST_CASE(100.1.1,"Nominal Event Logging"); + + Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); + + impl.init(10,0); + + Svc::ActiveLoggerImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runEventNominal(); + +} + +TEST(ActiveLoggerTest,FilteredEventSend) { + + TEST_CASE(100.1.2,"Nominal Event Filtering"); + + Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); + + impl.init(10,0); + + Svc::ActiveLoggerImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runFilterEventNominal(); + +} + +TEST(ActiveLoggerTest,FilterIdTest) { + + TEST_CASE(100.1.3,"Filter events by ID"); + + Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); + + impl.init(10,0); + + Svc::ActiveLoggerImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runFilterIdNominal(); + +} + +TEST(ActiveLoggerTest,FilterDumpTest) { + + TEST_CASE(100.1.3,"Dump filter values"); + + Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); + + impl.init(10,0); + + Svc::ActiveLoggerImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runFilterDump(); + +} + +TEST(ActiveLoggerTest,InvalidCommands) { + + TEST_CASE(100.2.1,"Off-Nominal Invalid Commands"); + + Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); + + impl.init(10,0); + + Svc::ActiveLoggerImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runFilterInvalidCommands(); + +} + +TEST(ActiveLoggerTest,FatalTesting) { + + TEST_CASE(100.2.2,"Off-Nominal FATAL processing"); + + Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); + + impl.init(10,0); + + Svc::ActiveLoggerImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runEventFatal(); + +} + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + + diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt new file mode 100644 index 00000000000..2d4c5415272 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt @@ -0,0 +1,9 @@ +This test can be run by executing the following: + +From Svc/ActiveLogger: + +"make ut run_ut" + +Note that the Ref application needs to be built first. +The test will return a pass/fail error code depending on the +success of the test. \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CMakeLists.txt new file mode 100644 index 00000000000..c30a7807936 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CMakeLists.txt @@ -0,0 +1 @@ +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Subtopology/") \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt new file mode 100644 index 00000000000..6820e752a53 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt @@ -0,0 +1,22 @@ + +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# +# Note: using PROJECT_NAME as EXECUTABLE_NAME +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/CmdDispatcher.fpp" + "${CMAKE_CURRENT_LIST_DIR}/CommandDispatcherImpl.cpp" +) + +register_fprime_module() +### UTs ### +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/CmdDispatcher.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherImplTester.cpp" +) +register_fprime_ut() diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp new file mode 100644 index 00000000000..b7be3c3f963 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp @@ -0,0 +1,199 @@ + +module Svc { + + @ A component for dispatching commands + active component CommandDispatcher { + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Command dispatch port + output port compCmdSend: [CmdDispatcherComponentCommandPorts] Fw.Cmd + + @ Command Registration Port. max_number should match dispatch port. + guarded input port compCmdReg: [CmdDispatcherComponentCommandPorts] Fw.CmdReg + + @ Input Command Status Port + async input port compCmdStat: Fw.CmdResponse + + @ Output Command Status Port + output port seqCmdStatus: [CmdDispatcherSequencePorts] Fw.CmdResponse + + @ Command buffer input port for sequencers or other sources of command buffers + async input port seqCmdBuff: [CmdDispatcherSequencePorts] Fw.Com + + @ Ping input port + async input port pingIn: Svc.Ping + + @ Ping output port + output port pingOut: Svc.Ping + + # ---------------------------------------------------------------------- + # Port matching specifiers + # ---------------------------------------------------------------------- + + match compCmdSend with compCmdReg + + match seqCmdStatus with seqCmdBuff + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + + @ Command receive port + command recv port CmdDisp + + @ Command registration port + command reg port CmdReg + + @ Command response port + command resp port CmdStatus + + @ Event port + event port Log + + @ Text event port + text event port LogText + + @ Time get port + time get port Time + + @ Telemetry port + telemetry port Tlm + + # ---------------------------------------------------------------------- + # Commands + # ---------------------------------------------------------------------- + + @ No-op command + async command CMD_NO_OP \ + opcode 0 + + @ No-op string command + async command CMD_NO_OP_STRING( + arg1: string size 40 @< The String command argument + ) \ + opcode 1 + + @ No-op command + async command CMD_TEST_CMD_1( + arg1: I32 @< The I32 command argument + arg2: F32 @< The F32 command argument + arg3: U8 @< The U8 command argument + ) \ + opcode 2 + + @ Clear command tracking info to recover from components not returning status + async command CMD_CLEAR_TRACKING \ + opcode 3 + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + event OpCodeRegistered( + Opcode: U32 @< The opcode to register + $port: I32 @< The registration port + slot: I32 @< The dispatch slot it was placed in + ) \ + severity diagnostic \ + id 0 \ + format "Opcode 0x{x} registered to port {} slot {}" + + @ Op code dispatched event + event OpCodeDispatched( + Opcode: U32 @< The opcode dispatched + $port: I32 @< The port dispatched to + ) \ + severity command \ + id 1 \ + format "Opcode 0x{x} dispatched to port {}" + + @ Op code completed event + event OpCodeCompleted( + Opcode: U32 @< The I32 command argument + ) \ + severity command \ + id 2 \ + format "Opcode 0x{x} completed" + + @ Op code completed with error event + event OpCodeError( + Opcode: U32 @< The opcode with the error + error: Fw.CmdResponse @< The error value + ) \ + severity command \ + id 3 \ + format "Opcode 0x{x} completed with error {}" + + @ Received a malformed command packet + event MalformedCommand( + Status: Fw.DeserialStatus @< The deserialization error + ) \ + severity warning high \ + id 4 \ + format "Received malformed command packet. Status: {}" + + @ Received an invalid opcode + event InvalidCommand( + Opcode: U32 @< Invalid opcode + ) \ + severity warning high \ + id 5 \ + format "Invalid opcode 0x{x} received" + + @ Exceeded the number of commands that can be simultaneously executed + event TooManyCommands( + Opcode: U32 @< The opcode that overflowed the list + ) \ + severity warning high \ + id 6 \ + format "Too many outstanding commands. opcode=0x{x}" + + @ The command dispatcher has successfully received a NO-OP command + event NoOpReceived \ + severity activity high \ + id 7 \ + format "Received a NO-OP command" + + @ The command dispatcher has successfully received a NO-OP command from GUI with a string + event NoOpStringReceived( + message: string size 40 @< The NO-OP string that is generated + ) \ + severity activity high \ + id 8 \ + format "Received a NO-OP string={}" + + @ This log event message returns the TEST_CMD_1 arguments. + event TestCmd1Args( + arg1: I32 @< Arg1 + arg2: F32 @< Arg2 + arg3: U8 @< Arg3 + ) \ + severity activity high \ + id 9 \ + format "TEST_CMD_1 args: I32: {}, F32: {f}, U8: {}" + + @ Op code reregistered event + event OpCodeReregistered( + Opcode: U32 @< The opcode reregistered + $port: I32 @< The reregistration port + ) \ + severity diagnostic \ + id 10 \ + format "Opcode 0x{x} is already registered to port {}" + + # ---------------------------------------------------------------------- + # Telemetry + # ---------------------------------------------------------------------- + + @ Number of commands dispatched + telemetry CommandsDispatched: U32 id 0 update on change + + @ Number of command errors + telemetry CommandErrors: U32 id 1 update on change + + } + +} diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp new file mode 100644 index 00000000000..442c93206f8 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp @@ -0,0 +1,17 @@ +// ====================================================================== +// CommandDispatcher.hpp +// Standardization header for CommandDispatcher +// ====================================================================== + +#ifndef Svc_CommandDispatcher_HPP +#define Svc_CommandDispatcher_HPP + +#include "Svc/CmdDispatcher/CommandDispatcherImpl.hpp" + +namespace Svc { + + typedef CommandDispatcherImpl CommandDispatcher; + +} + +#endif diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp new file mode 100644 index 00000000000..a340c9a64b2 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp @@ -0,0 +1,201 @@ +/* + * CommandDispatcherImpl.cpp + * + * Created on: May 13, 2014 + * Author: Timothy Canham + */ + +#include +#include +#include +#include + +// Check the CMD_DISPATCHER_DISPATCH_TABLE_SIZE and CMD_DISPATCHER_SEQUENCER_TABLE_SIZE for overflow +static_assert(CMD_DISPATCHER_DISPATCH_TABLE_SIZE <= std::numeric_limits::max(), "Opcode table limited to opcode range"); +static_assert(CMD_DISPATCHER_SEQUENCER_TABLE_SIZE <= std::numeric_limits::max(), "Sequencer table limited to range of U32"); + +namespace Svc { + CommandDispatcherImpl::CommandDispatcherImpl(const char* name) : + CommandDispatcherComponentBase(name), + m_seq(0), + m_numCmdsDispatched(0), + m_numCmdErrors(0) + { + memset(this->m_entryTable,0,sizeof(this->m_entryTable)); + memset(this->m_sequenceTracker,0,sizeof(this->m_sequenceTracker)); + } + + CommandDispatcherImpl::~CommandDispatcherImpl() { + } + + void CommandDispatcherImpl::compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode) { + // search for an empty slot + bool slotFound = false; + for (FwOpcodeType slot = 0; slot < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); slot++) { + if ((not this->m_entryTable[slot].used) and (not slotFound)) { + this->m_entryTable[slot].opcode = opCode; + this->m_entryTable[slot].port = portNum; + this->m_entryTable[slot].used = true; + this->log_DIAGNOSTIC_OpCodeRegistered(opCode,portNum,static_cast(slot)); + slotFound = true; + } else if ((this->m_entryTable[slot].used) && + (this->m_entryTable[slot].opcode == opCode) && + (this->m_entryTable[slot].port == portNum) && + (not slotFound)) { + slotFound = true; + this->log_DIAGNOSTIC_OpCodeReregistered(opCode,portNum); + } else if (this->m_entryTable[slot].used) { // make sure no duplicates + FW_ASSERT(this->m_entryTable[slot].opcode != opCode, static_cast(opCode)); + } + } + FW_ASSERT(slotFound,static_cast(opCode)); + } + + void CommandDispatcherImpl::compCmdStat_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response) { + // check response and log + if (Fw::CmdResponse::OK == response.e) { + this->log_COMMAND_OpCodeCompleted(opCode); + } else { + this->m_numCmdErrors++; + this->tlmWrite_CommandErrors(this->m_numCmdErrors); + FW_ASSERT(response.e != Fw::CmdResponse::OK); + this->log_COMMAND_OpCodeError(opCode,response); + } + // look for command source + FwIndexType portToCall = -1; + U32 context; + for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) { + if ( + (this->m_sequenceTracker[pending].seq == cmdSeq) && + (this->m_sequenceTracker[pending].used) + ) { + portToCall = this->m_sequenceTracker[pending].callerPort; + context = this->m_sequenceTracker[pending].context; + FW_ASSERT(opCode == this->m_sequenceTracker[pending].opCode); + FW_ASSERT(portToCall < this->getNum_seqCmdStatus_OutputPorts()); + this->m_sequenceTracker[pending].used = false; + break; + } + } + + if (portToCall != -1) { + // call port to report status + if (this->isConnected_seqCmdStatus_OutputPort(portToCall)) { + // NOTE: seqCmdStatus port forwards three arguments: (opCode, cmdSeq, response). + // However, the cmdSeq value has no meaning for the calling sequencer. + // Instead, the context value is forwarded to allow the caller to utilize it if needed. + this->seqCmdStatus_out(portToCall,opCode,context,response); + } + } + } + + void CommandDispatcherImpl::seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer &data, U32 context) { + + Fw::CmdPacket cmdPkt; + Fw::SerializeStatus stat = cmdPkt.deserialize(data); + + if (stat != Fw::FW_SERIALIZE_OK) { + Fw::DeserialStatus serErr(static_cast(stat)); + this->log_WARNING_HI_MalformedCommand(serErr); + if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { + this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::VALIDATION_ERROR); + } + return; + } + + // search for opcode in dispatch table + FwOpcodeType entry; + bool entryFound = false; + + for (entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); entry++) { + if ((this->m_entryTable[entry].used) and (cmdPkt.getOpCode() == this->m_entryTable[entry].opcode)) { + entryFound = true; + break; + } + } + if (entryFound and this->isConnected_compCmdSend_OutputPort(this->m_entryTable[entry].port)) { + // register command in command tracker only if response port is connect + if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { + bool pendingFound = false; + + for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) { + if (not this->m_sequenceTracker[pending].used) { + pendingFound = true; + this->m_sequenceTracker[pending].used = true; + this->m_sequenceTracker[pending].opCode = cmdPkt.getOpCode(); + this->m_sequenceTracker[pending].seq = this->m_seq; + this->m_sequenceTracker[pending].context = context; + this->m_sequenceTracker[pending].callerPort = portNum; + break; + } + } + + // if we couldn't find a slot to track the command, quit + if (not pendingFound) { + this->log_WARNING_HI_TooManyCommands(cmdPkt.getOpCode()); + if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { + this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::EXECUTION_ERROR); + } + return; + } + } // end if status port connected + // pass arguments to argument buffer + this->compCmdSend_out( + this->m_entryTable[entry].port, + cmdPkt.getOpCode(), + this->m_seq, + cmdPkt.getArgBuffer()); + // log dispatched command + this->log_COMMAND_OpCodeDispatched(cmdPkt.getOpCode(),this->m_entryTable[entry].port); + + // increment command count + this->m_numCmdsDispatched++; + // write telemetry channel for dispatched commands + this->tlmWrite_CommandsDispatched(this->m_numCmdsDispatched); + } else { + this->log_WARNING_HI_InvalidCommand(cmdPkt.getOpCode()); + this->m_numCmdErrors++; + // Fail command back to port, if connected + if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { + this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::INVALID_OPCODE); + } + this->tlmWrite_CommandErrors(this->m_numCmdErrors); + } + + // increment sequence number + this->m_seq++; + } + + void CommandDispatcherImpl::CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + Fw::LogStringArg no_op_string("Hello, World!"); + // Log event for NO_OP here. + this->log_ACTIVITY_HI_NoOpReceived(); + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void CommandDispatcherImpl::CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1) { + Fw::LogStringArg msg(arg1.toChar()); + // Echo the NO_OP_STRING args here. + this->log_ACTIVITY_HI_NoOpStringReceived(msg); + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void CommandDispatcherImpl::CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3) { + this->log_ACTIVITY_HI_TestCmd1Args(arg1,arg2,arg3); + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void CommandDispatcherImpl::CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + // clear tracking table + for (FwOpcodeType entry = 0; entry < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE; entry++) { + this->m_sequenceTracker[entry].used = false; + } + this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); + } + + void CommandDispatcherImpl::pingIn_handler(FwIndexType portNum, U32 key) { + // respond to ping + this->pingOut_out(0,key); + } + +} diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp new file mode 100644 index 00000000000..4f22c802288 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp @@ -0,0 +1,168 @@ +/** + * \file + * \author T.Canham + * \brief Component responsible for dispatching incoming commands to registered components + * + * \copyright + * Copyright 2009-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + *

+ */ + + +#ifndef COMMANDDISPATCHERIMPL_HPP_ +#define COMMANDDISPATCHERIMPL_HPP_ + +#include +#include +#include + +namespace Svc { + + //! \class CommandDispatcherImpl + //! \brief Command Dispatcher component class + //! + //! The command dispatcher takes incoming Fw::Com packets that contain + //! encoded commands. It extracts the opcode and looks it up in a table + //! that is populated by components at registration time. If a component + //! is connected to the seqCmdStatus port with the same number + //! as the port that submitted the command, the command status will be returned. + + class CommandDispatcherImpl final : public CommandDispatcherComponentBase { + public: + //! \brief Command Dispatcher constructor + //! + //! The constructor initializes the state of the component. + //! In this component, the opcode dispatch and tracking tables + //! are initialized. + //! + //! \param name the component instance name + CommandDispatcherImpl(const char* name); + //! \brief Component destructor + //! + //! The destructor for this component is empty + virtual ~CommandDispatcherImpl(); + PROTECTED: + PRIVATE: + //! \brief component command status handler + //! + //! The command status handler is called when a component + //! reports the completion of a command. + //! + //! \param portNum the number of the incoming port. + //! \param opCode the opcode of the completed command. + //! \param cmdSeq the sequence number assigned to the command when it was dispatched + //! \param response the completion status of the command + void compCmdStat_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response); + //! \brief component command buffer handler + //! + //! The command buffer handler is called to submit a new + //! command packet to be decoded + //! + //! \param portNum the number of the incoming port. + //! \param data the buffer containing the command. + //! \param context a user value returned with the status + void seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer &data, U32 context); + //! \brief component command registration handler + //! + //! The command registration handler is called to register + //! new opcodes. The port number called is used to indicate + //! which port should be used to dispatch the opcode. + //! + //! \param portNum the number of the incoming port. + //! \param opCode the opcode being registered. + void compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode); + //! \brief component ping handler + //! + //! The ping handler responds to messages to verify that the task + //! is still executing. Will call output ping port + //! + //! \param portNum the number of the incoming port. + //! \param opCode the opcode being registered. + //! \param key the key value that is returned with the ping response + void pingIn_handler(FwIndexType portNum, U32 key); + //! \brief NO_OP command handler + //! + //! A test command that does nothing + //! + //! \param opCode the NO_OP opcode. + //! \param cmdSeq the assigned sequence number for the command + void CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq); + //! \brief NO_OP with string command handler + //! + //! A test command that receives a string and sends an event + //! with the string as an argument + //! + //! \param opCode the NO_OP_STRING opcode. + //! \param cmdSeq the assigned sequence number for the command + //! \param arg1 the string argument + void CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1); + //! \brief A test command with different argument types + //! + //! A test command that receives a set of arguments of different types + //! + //! \param opCode the TEST_CMD_1 opcode. + //! \param cmdSeq the assigned sequence number for the command + //! \param arg1 the I32 argument + //! \param arg2 the F32 argument + //! \param arg3 the U8 argument + void CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3); + //! \brief A command to clear the command tracking + //! + //! This command will clear the table tracking the completion of commands. + //! It is meant to be used if the tracking table has gotten full because of + //! a software failure. It is dangerous in that it can clear a command + //! that a sequencer is waiting for. + //! + //! \param opCode the CLEAR_TRACKING opcode. + //! \param cmdSeq the assigned sequence number for the command + void CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq); + + //! \struct DispatchEntry + //! \brief table used to store opcode to port mappings + //! + //! The DispatchEntry table is used to map incoming opcodes to the port + //! connected to the component that implements the opcode. + //! As each command opcode is registered, a new entry is found + //! in the table by checking for the "used" flag. The opcode + //! member is set to the opcode, and the port member set to the + //! port to dispatch to. When a new opcode is received for + //! execution, the table is traversed until the opcode is located. + + struct DispatchEntry { + bool used; //!< if entry has been used yet + FwOpcodeType opcode; //!< opcode of entry + FwIndexType port; //!< which port the entry invokes + } m_entryTable[CMD_DISPATCHER_DISPATCH_TABLE_SIZE]; //!< table of dispatch entries + + //! \struct SequenceTracker + //! \brief table used to store opcode that are being executed + //! + //! The SequenceTracker table is used to track commands that are being executed + //! but are not yet complete. When a new command opcode is received, + //! the status port that would be used to report the completion status + //! is checked. If it is connected, then an entry is placed in this table. + //! The "used" flag is set, and the "seq" member is set to the + //! assigned sequence number for the command. The "opCode" field is + //! used for the opcode, and the "callerPort" field is used to store + //! the port number of the caller so the status can be reported back to + //! correct port. + + struct SequenceTracker { + bool used; //!< if this slot is used + U32 seq; //!< command sequence number + FwOpcodeType opCode; //!< opcode being tracked + U32 context; //!< context passed by user + FwIndexType callerPort; //!< port command source port + } m_sequenceTracker[CMD_DISPATCHER_SEQUENCER_TABLE_SIZE]; //!< sequence tracking port for command completions; + + U32 m_seq; //!< current command sequence number + + U32 m_numCmdsDispatched; //!< number of commands dispatched + U32 m_numCmdErrors; //!< number of commands with an error + + }; +} + +#endif /* COMMANDDISPATCHERIMPL_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/README b/Svc/Subtopologies/CDHCore/CmdDispatcher/README new file mode 100644 index 00000000000..76fd4a64ba4 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/README @@ -0,0 +1,6 @@ +This directory contains the CmdDispatcher component. This component takes incoming Com packets that have commands encoded in them and decodes them. +It looks up opcodes in a table build by component registrations. It also handles completions, passing the status back to the sender of the packet. + +CommandDispatcherComponentAi.xml - Command dispatcher component specification +CommandDispatcherImpl.hpp(.cpp) - Command dispatcher implementation +CommandDispatcherImplCfg.hpp - Command dispatcher configuration \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt b/Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt new file mode 100644 index 00000000000..bab0c3a8e60 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt @@ -0,0 +1,41 @@ +Old Symbol +New Symbol + +Svc::CommandDispatcherComponentBase::ErrorResponse +Fw::CmdResponse + +Svc::CommandDispatcherComponentBase::ERR_INVALID_OPCODE +Fw::CmdResponse::INVALID_OPCODE + +Svc::CommandDispatcherComponentBase::ERR_VALIDATION_ERROR +Fw::CmdResponse::VALIDATION_ERROR + +Svc::CommandDispatcherComponentBase::ERR_FORMAT_ERROR +Fw::CmdResponse::FORMAT_ERROR + +Svc::CommandDispatcherComponentBase::ERR_EXECUTION_ERROR +Fw::CmdResponse::EXECUTION_ERROR + +Svc::CommandDispatcherComponentBase::ERR_BUSY +Fw::CmdResponse::BUSY + +Svc::CommandDispatcherComponentBase::ERR_UNEXP +N/A + +Svc::CommandDispatcherComponentBase::CmdSerError +Fw::DeserialStatus + +Svc::CommandDispatcherComponentBase::ERR_BUFFER_TOO_SMALL +Fw::DeserialStatus::BUFFER_EMPTY + +Svc::CommandDispatcherComponentBase::ERR_BUFFER_FORMAT +Fw::DeserialStatus::FORMAT_ERROR + +Svc::CommandDispatcherComponentBase::ERR_SIZE_MISMATCH +Fw::DeserialStatus::SIZE_MISMATCH + +Svc::CommandDispatcherComponentBase::ERR_TYPE_MISMATCH +Fw::DeserialStatus::TYPE_MISMATCH + +Svc::CommandDispatcherComponentBase::ERR_UNEXP_STAT +N/A diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore new file mode 100644 index 00000000000..0b84df0f025 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore @@ -0,0 +1 @@ +*.html \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Code.xlsx b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Code.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0ea2389ebefebdb3375ea35c3ebf74c203fef777 GIT binary patch literal 29709 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 z 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 K_}c&D=>GweUw%6P literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Design.xlsx b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Design.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..fd2af919bc9f055efd1ecd7c3cd4bee2be4c1e17 GIT binary patch literal 25044 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 JBEmBL{|^8q84Umc literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/img/CommandDispatcherBDD.jpg b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/img/CommandDispatcherBDD.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1098ba53b9bb5d70dc86cf4e26df3c7387c4bd70 GIT binary patch literal 142623 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 z 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 literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md new file mode 100644 index 00000000000..3d78de27519 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md @@ -0,0 +1,127 @@ +# Svc::CmdDispatcher Component + +## 1. Introduction + +The `Svc::CmdDispatcher` is responsible for dispatching incoming commands to the components that implement those commands. The commands are sent in encoded `Fw::Com` form from an external sender like a ground system or a sequencer. The dispatcher decodes the packet and extracts the opcode. This opcode is looked up in a table and dispatched to the component via a port indicated in the table. The output port for each opcode is set by a call to a registration port. + +## 2. Requirements + +The requirements for `Svc::CmdDispatcher` are as follows: + +Requirement | Description | Verification Method +----------- | ----------- | ------------------- +CD-001 | The `Svc::CmdDispatcher` component shall accept command buffers and decode them into commands | Inspection, Unit Test +CD-002 | The `Svc::CmdDispatcher` component shall dispatch commands to components | Unit Test +CD-003 | The `Svc::CmdDispatcher` component shall provide an interface to register commands | Inspection +CD-004 | The `Svc::CmdDispatcher` component shall process command status from components and report the results to the command buffer sender. | Unit Test + +## 3. Design + +### 3.1 Context + +#### 3.1.1 Component Diagram + +The `Svc::CmdDispatcher` component has the following component diagram: + +![`Svc::CmdDispatcher` Diagram](img/CommandDispatcherBDD.jpg "Svc::CmdDispatcher") + +#### 3.1.2 Ports + +The `Svc::CmdDispatcher` component uses the following port types: + +Port Data Type | Name | Direction | Kind | Usage +-------------- | ---- | --------- | ---- | ----- +[`Fw::Cmd`](../../../Fw/Cmd/docs/sdd.md) | cmdSend | Output | n/a | Send commands to components +[`Fw::CmdResponse`](../../../Fw/Cmd/docs/sdd.md) | compCmdStat | Input | Asynchronous | Port for components to report command status +[`Fw::CmdResponse`](../../../Fw/Cmd/docs/sdd.md) | seqCmdStatus | Output | n/a | Send command status to command buffer source +[`Fw::Com`](../../../Fw/Com/docs/sdd.md) | seqCmdBuff | Input | Asynchronous | Receive command buffer +[`Fw::CmdReg`](../../../Fw/Cmd/docs/sdd.md) | cmdReg | Input | Synchronous | Command Registration + +### 3.2 Functional Description + +The `Svc::CmdDispatcher` component provides command dispatching. The architecture autocoder generates port instances for components that specify commands that implement the commanding pattern. `Svc::CommandDispatcher` implements the command decoding and dispatching to supply the components with commands. + +#### 3.2.1 Command Registration + +An autogenerated function on components create a public function `regCommands` that tells components to register the set of op codes that are implemented by the component. The autogenerated port is connected to the `compCmdReg` input port on `Svc::CmdDispatcher` that corresponds to the number of the `compCmdSend` port used to dispatch commands. The port handler looks through the dispatch table for an unused entry and adds the opcode. It maps the opcode to the dispatch port number corresponding to the registration port number. + +#### 3.2.2 Command Dispatch + +When the command dispatcher receives a command buffer, it decodes the opcode. It searches the dispatch table for the opcode, then assigns a sequence number to the command and stores the opcode, sequence number, context value and source port in a pending command table. The command is then dispatched to the component that implements the command. When the component completes execution of the command, it reports the status back via the `compCmdStat` port. The sequence number is matched to the entry in the pending command table, and the `seqCmdStatus` output port corresponding to the source port is called (if it is connected) with the status and the context value. +Note #1: this requires that the component sending the command buffer have connections to the same `seqCmdBuff` and `seqCmdStatus` port numbers. +Note #2: the `seqCmdStatus` port utilize the same type as the `compCmdStat`, the `Fw::CmdResponse`. This has been done to avoid creation of similar types for status ports. However, the `Fw::CmdResponse::cmdSeq` argument of the `seqCmdStatus` doesn't have any meaning for the calling sequencer. Therefore, as it has been mentioned before, instead of forwarding a command sequence number, the context value is transferred. + +### 3.3 Scenarios + +#### 3.3.1 Command Registration + +The `Svc::CmdDispatcher` component accepts command registration from other components: + +```mermaid +sequenceDiagram + Initialization->>Component: get_ComdReg_InputPort() + activate Initialization + deactivate Initialization + activate Component + deactivate Component + Initialization->>Component: regCommands() + activate Initialization + activate Component + loop for each opcode + Component->>CommandDispatcher: cmdReg() + end + deactivate Initialization + deactivate Component +``` + +#### 3.3.1 Dispatch Commands + +The `Svc::CmdDispatcher` component dispatches commands to other components: + +```mermaid +sequenceDiagram + Command Buffer Source->>CommandDispatcher: seqCmdBuff() + activate Command Buffer Source + activate CommandDispatcher + CommandDispatcher->>Component: seqCmdBuff() + activate Component + Component->>CommandDispatcher: compCmdStat() + deactivate Component + CommandDispatcher->>Command Buffer Source: seqCmdStatus() + deactivate CommandDispatcher + deactivate Command Buffer Source +``` + +### 3.4 State + +`Svc::CmdDispatcher` has no state machines. + +### 3.5 Algorithms + +`Svc::CmdDispatcher` has no significant algorithms. + +## 4. Module Checklists + +Checklist | +-------- | +[Design](Checklist_Design.xlsx) | +[Code](Checklist_Code.xlsx) | +[Unit Test](Checklist_Unit_Test.xls) | + +## 5. Unit Testing + +To see unit test coverage run `fprime-util check --coverage` + +## 6. Change Log + +Date | Description +---- | ----------- +6/25/2015 | Design review edits +7/22/2015 | Design review actions +9/16/2015 | Unit Test additions +1/28/2016 | Added context value discussion +5/17/2021 | Added CMD Reregistration option +5/05/2025 | Added a note about Fw::CmdResponse::cmdSeq usage in seqCmdStatus + + + diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/int/test_cmd_dispatcher.py b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/int/test_cmd_dispatcher.py new file mode 100644 index 00000000000..035f9fb9b44 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/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/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp new file mode 100644 index 00000000000..360e98fc64c --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp @@ -0,0 +1,887 @@ +/* + * CommandDispatcherImplTester.cpp + * + * Created on: Mar 18, 2015 + * Author: tcanham + */ + +#include +#include +#include +#include + +#include + +#include +#include + +static_assert(CMD_DISPATCHER_SEQUENCER_TABLE_SIZE + 1 <= std::numeric_limits::max(), "Unit test depends on CMD_DISPATCHER_SEQUENCER_TABLE_SIZE + 1 within range of U32"); + +namespace Svc { + CommandDispatcherImplTester::CommandDispatcherImplTester(Svc::CommandDispatcherImpl& inst) : + CommandDispatcherGTestBase("testerbase",100), + m_impl(inst) { + } + + CommandDispatcherImplTester::~CommandDispatcherImplTester() { + } + + void CommandDispatcherImplTester::from_compCmdSend_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, Fw::CmdArgBuffer &args) { + this->m_cmdSendOpCode = opCode; + this->m_cmdSendCmdSeq = cmdSeq; + this->m_cmdSendArgs = args; + this->m_cmdSendRcvd = true; + } + + void CommandDispatcherImplTester::from_seqCmdStatus_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response) { + this->m_seqStatusRcvd = true; + this->m_seqStatusOpCode = opCode; + this->m_seqStatusCmdSeq = cmdSeq; + this->m_seqStatusCmdResponse = response; + } + + void CommandDispatcherImplTester::runNominalDispatch() { + + // verify dispatch table is empty + for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { + ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); + } + + // verify sequence tracker table is empty + + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + // clear reg events + this->clearEvents(); + // register built-in commands + this->m_impl.regCommands(); + // verify registrations + ASSERT_TRUE(this->m_impl.m_entryTable[0].used); + ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); + ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[1].used); + ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); + ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[2].used); + ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); + ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[3].used); + ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); + ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); + + // verify event + printTextLogHistory(stdout); + ASSERT_EVENTS_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); + ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); + ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); + ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); + + + REQUIREMENT("CD-003"); + // register our own command + FwOpcodeType testOpCode = 0x50; + + this->clearEvents(); + this->invoke_to_compCmdReg(0,0x50); + ASSERT_TRUE(this->m_impl.m_entryTable[4].used); + ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); + ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); + + // verify registration event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); + + // dispatch a test command + REQUIREMENT("CD-001"); + + U32 testCmdArg = 100; + U32 testContext = 110; + this->clearEvents(); + Fw::ComBuffer buff; + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + REQUIREMENT("CD-002"); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); + + // verify sequence table entry + ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].seq, 0u); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort, 0); + + // verify command received + ASSERT_TRUE(this->m_cmdSendRcvd); + ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); + ASSERT_EQ(this->m_cmdSendCmdSeq,0); + // check argument + U32 checkVal; + ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(checkVal,testCmdArg); + + this->clearEvents(); + this->m_seqStatusRcvd = false; + // perform command response + this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::OK); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // Check dispatch table + ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].seq,0u); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + + // Verify completed event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeCompleted_SIZE(1); + ASSERT_EVENTS_OpCodeCompleted(0u,testOpCode); + + REQUIREMENT("CD-004"); + + // Verify status passed back to port + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(this->m_seqStatusOpCode,testOpCode); + ASSERT_EQ(this->m_seqStatusCmdSeq,testContext); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); + } + + void CommandDispatcherImplTester::runNopCommands() { + + // verify dispatch table is empty + for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { + ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); + } + + // verify sequence tracker table is empty + + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + + // clear reg events + this->clearEvents(); + // register built-in commands + this->m_impl.regCommands(); + // verify registrations + ASSERT_TRUE(this->m_impl.m_entryTable[0].used); + ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); + ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[1].used); + ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); + ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[2].used); + ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); + ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[3].used); + ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); + ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); + + // verify event + + ASSERT_EVENTS_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); + ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); + ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); + ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); + + // send NO_OP command + this->m_seqStatusRcvd = false; + Fw::ComBuffer buff; + ASSERT_EQ(buff.serialize(static_cast(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(static_cast(CommandDispatcherImpl::OPCODE_CMD_NO_OP)),Fw::FW_SERIALIZE_OK); + + this->clearEvents(); + this->invoke_to_seqCmdBuff(0,buff,12); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1); + + // dispatch for async command + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + // dispatch for async command response + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + // Verify status passed back to port + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(CommandDispatcherImpl::OPCODE_CMD_NO_OP,this->m_seqStatusOpCode); + // Verify correct context value is passed back. + ASSERT_EQ(12u,this->m_seqStatusCmdSeq); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); + + // send NO_OP_STRING command + this->clearEvents(); + this->m_seqStatusRcvd = false; + buff.resetSer(); + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(FwOpcodeType(CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING)),Fw::FW_SERIALIZE_OK); + // serialize arg1 + Fw::CmdStringArg argString("BOO!"); + ASSERT_EQ(buff.serialize(argString),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,13); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1); + + // dispatch for async command + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + // dispatch for async command response + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + // Verify status passed back to port + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,this->m_seqStatusOpCode); + ASSERT_EQ(13u,this->m_seqStatusCmdSeq); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); + + // send TEST_CMD_1 command + this->m_seqStatusRcvd = false; + buff.resetSer(); + ASSERT_EQ(buff.serialize(static_cast(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(static_cast(CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1)),Fw::FW_SERIALIZE_OK); + // serialize arg1 + ASSERT_EQ(buff.serialize(static_cast(1)),Fw::FW_SERIALIZE_OK); + // serialize arg2 + ASSERT_EQ(buff.serialize(static_cast(2.3)),Fw::FW_SERIALIZE_OK); + // serialize arg3 + ASSERT_EQ(buff.serialize(static_cast(4)),Fw::FW_SERIALIZE_OK); + + this->clearEvents(); + this->invoke_to_seqCmdBuff(0,buff,14); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1); + + // dispatch for async command + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + // dispatch for async command response + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + // Verify status passed back to port + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,this->m_seqStatusOpCode); + ASSERT_EQ(14u,this->m_seqStatusCmdSeq); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); + } + + void CommandDispatcherImplTester::runCommandReregister() { + // register built-in commands + this->m_impl.regCommands(); + // clear reg events + this->clearEvents(); + + // register our own command + FwOpcodeType testOpCode = 0x50; + this->invoke_to_compCmdReg(0,0x50); + ASSERT_TRUE(this->m_impl.m_entryTable[4].used); + ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); + ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); + + // verify registration event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); + + // clear reg events + this->clearEvents(); + + // verify we can call cmdReg port again with the same opcode + this->invoke_to_compCmdReg(0,0x50); + ASSERT_TRUE(this->m_impl.m_entryTable[4].used); + ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); + ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); + + // verify re-registration event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeReregistered_SIZE(1); + ASSERT_EVENTS_OpCodeReregistered(0,testOpCode,0); + } + + void CommandDispatcherImplTester::runInvalidOpcodeDispatch() { + + // verify dispatch table is empty + for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { + ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); + } + + // verify sequence tracker table is empty + + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + // clear reg events + this->clearEvents(); + // register built-in commands + this->m_impl.regCommands(); + // verify registrations + ASSERT_TRUE(this->m_impl.m_entryTable[0].used); + ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); + ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[1].used); + ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); + ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[2].used); + ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); + ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[3].used); + ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); + ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); + + // verify event + ASSERT_EVENTS_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); + ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); + ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); + ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); + + // register our own command + FwOpcodeType testOpCode = 0x50; + + this->clearEvents(); + this->invoke_to_compCmdReg(0,0x50); + ASSERT_TRUE(this->m_impl.m_entryTable[4].used); + ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); + ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); + + // verify registration event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); + + // dispatch a test command with a bad opcode + U32 testCmdArg = 100; + U32 testContext = 13; + this->clearEvents(); + this->m_seqStatusRcvd = false; + Fw::ComBuffer buff; + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(FwOpcodeType(testOpCode + 1)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->clearEvents(); + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_InvalidCommand_SIZE(1); + ASSERT_EVENTS_InvalidCommand(0u,testOpCode+1); + + // Verify status passed back to port + + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(this->m_seqStatusOpCode,testOpCode+1); + ASSERT_EQ(this->m_seqStatusCmdSeq,testContext); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::INVALID_OPCODE); + } + + void CommandDispatcherImplTester::runFailedCommand() { + + // verify dispatch table is empty + for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { + ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); + } + + // verify sequence tracker table is empty + + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + // clear reg events + this->clearEvents(); + // register built-in commands + this->m_impl.regCommands(); + // verify registrations + ASSERT_TRUE(this->m_impl.m_entryTable[0].used); + ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); + ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[1].used); + ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); + ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[2].used); + ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); + ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[3].used); + ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); + ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); + + // verify event + ASSERT_EVENTS_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); + ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); + ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); + ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); + // register our own command + FwOpcodeType testOpCode = 0x50; + + this->clearEvents(); + this->invoke_to_compCmdReg(0,0x50); + ASSERT_TRUE(this->m_impl.m_entryTable[4].used); + ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); + ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); + + // verify registration event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); + + U32 currSeq = 0; + + // dispatch a test command + U32 testCmdArg = 100; + U32 testContext = 13; + this->clearEvents(); + Fw::ComBuffer buff; + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); + + // verify sequence table entry + ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + + // verify command received + ASSERT_TRUE(this->m_cmdSendRcvd); + ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); + ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq); + // check argument + U32 checkVal; + ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(checkVal,testCmdArg); + + this->clearEvents(); + this->m_seqStatusRcvd = false; + // perform command response + this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::EXECUTION_ERROR); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // Check dispatch table + ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + + // Verify completed event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeError_SIZE(1); + ASSERT_EVENTS_OpCodeError(0,testOpCode, Fw::CmdResponse::EXECUTION_ERROR); + + // Verify status passed back to port + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(this->m_seqStatusCmdSeq,testContext); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::EXECUTION_ERROR); + + // dispatch a test command + currSeq++; + this->clearEvents(); + buff.resetSer(); + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); + + // verify sequence table entry + ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + + // verify command received + ASSERT_TRUE(this->m_cmdSendRcvd); + ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); + ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq); + // check argument + ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(checkVal,testCmdArg); + + this->clearEvents(); + this->m_seqStatusRcvd = false; + // perform command response + this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::INVALID_OPCODE); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // Check dispatch table + ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + + // Verify completed event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeError_SIZE(1); + ASSERT_EVENTS_OpCodeError(0,testOpCode,Fw::CmdResponse::INVALID_OPCODE); + + // Verify status passed back to port + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(this->m_seqStatusOpCode,testOpCode); + ASSERT_EQ(testContext,this->m_seqStatusCmdSeq); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::INVALID_OPCODE); + + currSeq++; + // dispatch a test command + this->clearEvents(); + buff.resetSer(); + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); + + // verify sequence table entry + ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); + + // verify command received + ASSERT_TRUE(this->m_cmdSendRcvd); + ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); + ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq); + // check argument + ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(checkVal,testCmdArg); + + this->clearEvents(); + this->m_seqStatusRcvd = false; + // perform command response + this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::VALIDATION_ERROR); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // Check dispatch table + ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + + // Verify completed event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeError_SIZE(1); + ASSERT_EVENTS_OpCodeError(0,testOpCode,Fw::CmdResponse::VALIDATION_ERROR); + + // Verify status passed back to port + ASSERT_TRUE(this->m_seqStatusRcvd); + ASSERT_EQ(this->m_seqStatusOpCode,testOpCode); + ASSERT_EQ(testContext,this->m_seqStatusCmdSeq); + ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::VALIDATION_ERROR); + } + + void CommandDispatcherImplTester::runInvalidCommand() { + // verify dispatch table is empty + for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { + ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); + } + + // verify sequence tracker table is empty + + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + // clear reg events + this->clearEvents(); + + // dispatch a flawed command + U32 testCmdArg = 100; + U32 testContext = 13; + FwOpcodeType testOpCode = 0x50; + this->clearEvents(); + Fw::ComBuffer buff; + ASSERT_EQ(buff.serialize(U32(100)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_MalformedCommand_SIZE(1); + ASSERT_EVENTS_MalformedCommand(0,Fw::DeserialStatus::TYPE_MISMATCH); + + } + + void CommandDispatcherImplTester::runOverflowCommands() { + + // verify dispatch table is empty + for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { + ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); + } + + // verify sequence tracker table is empty + + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + // clear reg events + this->clearEvents(); + // register built-in commands + this->m_impl.regCommands(); + // verify registrations + ASSERT_TRUE(this->m_impl.m_entryTable[0].used); + ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); + ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[1].used); + ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); + ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[2].used); + ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); + ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[3].used); + ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); + ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); + + // verify event + ASSERT_EVENTS_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); + ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); + ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); + ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); + + // register our own command + FwOpcodeType testOpCode = 0x50; + + this->clearEvents(); + this->invoke_to_compCmdReg(0,0x50); + ASSERT_TRUE(this->m_impl.m_entryTable[4].used); + ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); + ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); + + // verify registration event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); + + for (U32 disp = 0; disp < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE + 1; disp++) { + // dispatch a test command + U32 testCmdArg = 100; + U32 testContext = 13; + this->clearEvents(); + Fw::ComBuffer buff; + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + if (disp < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE) { + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); + + // verify sequence table entry + ASSERT_TRUE(this->m_impl.m_sequenceTracker[disp].used); + ASSERT_EQ(disp,this->m_impl.m_sequenceTracker[disp].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].context,testContext); + ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].callerPort,0); + + // verify command received + ASSERT_TRUE(this->m_cmdSendRcvd); + ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); + ASSERT_EQ(disp,this->m_cmdSendCmdSeq); + // check argument + U32 checkVal; + ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(checkVal,testCmdArg); + } else { + // verify failed to find slot + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_TooManyCommands_SIZE(1); + } + } + + } + + void CommandDispatcherImplTester::runClearCommandTracking() { + + // verify dispatch table is empty + for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { + ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); + } + + // verify sequence tracker table is empty + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + // clear reg events + this->clearEvents(); + // register built-in commands + this->m_impl.regCommands(); + // verify registrations + ASSERT_TRUE(this->m_impl.m_entryTable[0].used); + ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); + ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[1].used); + ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); + ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[2].used); + ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); + ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); + + ASSERT_TRUE(this->m_impl.m_entryTable[3].used); + ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); + ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); + + // verify event + ASSERT_EVENTS_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered_SIZE(4); + ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); + ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); + ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); + ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); + + // register our own command + FwOpcodeType testOpCode = 0x50; + U32 testContext = 13; + + this->clearEvents(); + this->invoke_to_compCmdReg(0,testOpCode); + ASSERT_TRUE(this->m_impl.m_entryTable[4].used); + ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); + ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); + + // verify registration event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered_SIZE(1); + ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); + + // dispatch a test command + U32 testCmdArg = 100; + this->clearEvents(); + Fw::ComBuffer buff; + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); + + // verify sequence table entry + ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); + ASSERT_EQ(0u,this->m_impl.m_sequenceTracker[0].seq); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); + ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); + + // verify command received + ASSERT_TRUE(this->m_cmdSendRcvd); + ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); + ASSERT_EQ(0u,this->m_cmdSendCmdSeq); + // check argument + U32 checkVal; + ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(checkVal,testCmdArg); + this->clearEvents(); + + // dispatch command to clear sequence tracker table + + buff.resetSer(); + ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buff.serialize(static_cast(CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING)),Fw::FW_SERIALIZE_OK); + + this->invoke_to_seqCmdBuff(0,buff,testContext); + // send buffer to command dispatcher + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify dispatch event + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched_SIZE(1); + ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1); + + // dispatch command from dispatcher to command handler + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + // verify tracking table empty + for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { + ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); + } + + clearHistory(); + // send command complete + this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::OK); + ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); + + // verify no status returned + ASSERT_CMD_RESPONSE_SIZE(0); + + } + + void CommandDispatcherImplTester::from_pingOut_handler( + const FwIndexType portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ) { + + } + +} /* namespace SvcTest */ diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp new file mode 100644 index 00000000000..756c9cb11a1 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp @@ -0,0 +1,55 @@ +/* + * CommandDispatcherImplTester.hpp + * + * Created on: Mar 18, 2015 + * Author: tcanham + */ + +#ifndef CMDDISP_TEST_UT_TLMCHANIMPLTESTER_HPP_ +#define CMDDISP_TEST_UT_TLMCHANIMPLTESTER_HPP_ + +#include +#include + +namespace Svc { + + class CommandDispatcherImplTester: public CommandDispatcherGTestBase { + public: + CommandDispatcherImplTester(Svc::CommandDispatcherImpl& inst); + virtual ~CommandDispatcherImplTester(); + + void runNominalDispatch(); + void runInvalidOpcodeDispatch(); + void runCommandReregister(); + void runFailedCommand(); + void runInvalidCommand(); + void runOverflowCommands(); + void runNopCommands(); + void runClearCommandTracking(); + + private: + Svc::CommandDispatcherImpl& m_impl; + + void from_compCmdSend_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, Fw::CmdArgBuffer &args); + + void from_pingOut_handler( + const FwIndexType portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ); // store port call + bool m_cmdSendRcvd; + FwOpcodeType m_cmdSendOpCode; + U32 m_cmdSendCmdSeq; + Fw::CmdArgBuffer m_cmdSendArgs; + + void from_seqCmdStatus_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response); + + bool m_seqStatusRcvd; + FwOpcodeType m_seqStatusOpCode; + U32 m_seqStatusCmdSeq; + Fw::CmdResponse m_seqStatusCmdResponse; + + }; + +} /* namespace Svc */ + +#endif /* CMDDISP_TEST_UT_TLMCHANIMPLTESTER_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp new file mode 100644 index 00000000000..eb236b79fa2 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp @@ -0,0 +1,211 @@ +/* + * CommandDispatcherTester.cpp + * + * Created on: Mar 18, 2015 + * Author: tcanham + */ + +#include +#include +#include +#include +#include + +void connectPorts(Svc::CommandDispatcherImpl& impl, Svc::CommandDispatcherImplTester& tester) { + + //Fw::SimpleObjRegistry simpleReg; + + // command ports + tester.connect_to_compCmdStat(0,impl.get_compCmdStat_InputPort(0)); + tester.connect_to_seqCmdBuff(0,impl.get_seqCmdBuff_InputPort(0)); + tester.connect_to_compCmdReg(0,impl.get_compCmdReg_InputPort(0)); + + impl.set_compCmdSend_OutputPort(0,tester.get_from_compCmdSend(0)); + impl.set_seqCmdStatus_OutputPort(0,tester.get_from_seqCmdStatus(0)); + // local dispatcher command registration + impl.set_CmdReg_OutputPort(0,impl.get_compCmdReg_InputPort(1)); + impl.set_CmdStatus_OutputPort(0,impl.get_compCmdStat_InputPort(0)); + + impl.set_compCmdSend_OutputPort(1,impl.get_CmdDisp_InputPort(0)); + + impl.set_Tlm_OutputPort(0,tester.get_from_Tlm(0)); + impl.set_Time_OutputPort(0,tester.get_from_Time(0)); + + impl.set_Log_OutputPort(0,tester.get_from_Log(0)); + impl.set_LogText_OutputPort(0,tester.get_from_LogText(0)); + +#if FW_PORT_TRACING + //Fw::PortBase::setTrace(true); +#endif + + //simpleReg.dump(); + +} + +TEST(CmdDispTestNominal,NominalDispatch) { + + TEST_CASE(102.1.1,"Nominal Dispatch"); + COMMENT("Dispatch a series of commands and verify they are dispatched correctly."); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runNominalDispatch(); + +} + +TEST(CmdDispTestNominal,NopTest) { + + TEST_CASE(102.1.2,"NO_OP Command Test"); + COMMENT("Verify the test NO_OP commands by dispatching them."); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runNopCommands(); + +} + +TEST(CmdDispTestNominal, ReregisterCommand) { + + TEST_CASE(102.1.3,"Reregister Command"); + COMMENT("Verify user can call command registration port with the same opcode multiple times safely."); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runCommandReregister(); +} + +TEST(CmdDispTestOffNominal,InvalidOpcodeDispatch) { + + TEST_CASE(102.2.1,"Off-nominal Dispatch"); + COMMENT("Verify the correct handling of unregistered opcodes."); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runInvalidOpcodeDispatch(); + +} + +TEST(CmdDispTestOffNominal,FailedCommand) { + + TEST_CASE(102.2.2,"Off-nominal Failed command"); + COMMENT("Verify that failed commands operate correctly"); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runFailedCommand(); + +} + +TEST(CmdDispTestOffNominal,InvalidCommand) { + + TEST_CASE(102.2.3,"Off-nominal Invalid Command"); + COMMENT("Verify that malformed commands are detected."); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runInvalidCommand(); + +} + +TEST(CmdDispTestOffNominal,CommandOverflow) { + + TEST_CASE(102.2.4,"Off-nominal Command Overflow"); + COMMENT("Verify error case where there are too many outstanding commands."); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runOverflowCommands(); + +} + +TEST(CmdDispTestOffNominal,ClearSequenceTracker) { + + TEST_CASE(102.1.3,"Clear Command Tracker"); + COMMENT("Verify command to clear command tracker."); + + Svc::CommandDispatcherImpl impl("CmdDispImpl"); + + impl.init(10,0); + + Svc::CommandDispatcherImplTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl,tester); + + tester.runClearCommandTracking(); + +} + +#ifndef TGT_OS_TYPE_VXWORKS +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +#endif + diff --git a/Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp b/Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp new file mode 100644 index 00000000000..6b6942e68ca --- /dev/null +++ b/Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp @@ -0,0 +1,28 @@ +module CDHCore { + + instance cmdDisp: Svc.CommandDispatcher base id 0xFF2FF \ + queue size Defaults.QUEUE_SIZE \ + stack size Defaults.STACK_SIZE \ + priority 101 + + instance eventLogger: Svc.ActiveLogger base id 0x0B00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 98 + + instance tlmSend: Svc.TlmChan base id 0x0C00 \ + queue size Default.queueSize \ + stack size Default.stackSize \ + priority 97 + + topology Subtopology { + instance cmdDisp + instance eventLogger + instance tlmSend + + command connections instance cmdDisp + event connections instance eventLogger + telemetry connections instance tlmSend + + } # end topology +} # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/Subtopology/CDHCoreTopologyDefs.hpp b/Svc/Subtopologies/CDHCore/Subtopology/CDHCoreTopologyDefs.hpp new file mode 100644 index 00000000000..726d31b59e3 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/Subtopology/CDHCoreTopologyDefs.hpp @@ -0,0 +1,15 @@ +#ifndef CDHCORESUBTOPOLOGY_DEFS_HPP +#define CDHCORESUBTOPOLOGY_DEFS_HPP + +namespace CDHCore { + struct CDHCoreState { + /* include any variables that are needed for + configuring/starting/tearing down the topology */ + }; +} + +namespace GlobalDefs { + +} + +#endif \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt b/Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt new file mode 100644 index 00000000000..bd026d036bd --- /dev/null +++ b/Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt @@ -0,0 +1,13 @@ +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/CDHCore.fpp" + "${CMAKE_CURRENT_LIST_DIR}/intentionally-empty.cpp" +) + +register_fprime_module() + +# Set the module name explicitly to match what the build system expects +set_target_properties( + ${FPRIME_CURRENT_MODULE} + PROPERTIES + SOURCES "${CMAKE_CURRENT_LIST_DIR}/intentionally-empty.cpp" +) diff --git a/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt b/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt new file mode 100644 index 00000000000..c9aa9731749 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt @@ -0,0 +1,5 @@ +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/config.fpp" +) + +register_fprime_module() diff --git a/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp b/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp new file mode 100644 index 00000000000..ac2f8abaeac --- /dev/null +++ b/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp @@ -0,0 +1,13 @@ +module Config { + # Base ID for your subtopology. All instantiated components will be offsets of this + constant CDHCoreSubtopology_BASE_ID = 0xFFFF0000 + + # include default Queue and Stack sizes here + module Defaults { + constant QUEUE_SIZE = 10 + constant STACK_SIZE = 64 * 1024 + } + + module Priorities { + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/Subtopology/intentionally-empty.cpp b/Svc/Subtopologies/CDHCore/Subtopology/intentionally-empty.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt b/Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt new file mode 100644 index 00000000000..273f4bfd2ff --- /dev/null +++ b/Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt @@ -0,0 +1,23 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# +# Note: using PROJECT_NAME as EXECUTABLE_NAME +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/TlmChan.fpp" + "${CMAKE_CURRENT_LIST_DIR}/TlmChan.cpp" +) + +register_fprime_module() + +### UTs ### +set(UT_SOURCE_FILES + "${FPRIME_FRAMEWORK_PATH}/Svc/TlmChan/TlmChan.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanMain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanTester.cpp" +) +register_fprime_ut() + diff --git a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp new file mode 100644 index 00000000000..03fe9370db5 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp @@ -0,0 +1,241 @@ +/** + * \file + * \author T. Canham + * \brief Implementation file for channelized telemetry storage component + * + * \copyright + * Copyright 2009-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + *

+ */ +#include +#include +#include +#include + +namespace Svc { + +// Definition of TLMCHAN_HASH_BUCKETS is >= number of telemetry ids +static_assert(std::numeric_limits::max() >= TLMCHAN_HASH_BUCKETS, + "Cannot have more hash buckets than maximum telemetry ids in the system"); +// TLMCHAN_HASH_BUCKETS >= TLMCHAN_NUM_TLM_HASH_SLOTS >= 0 +static_assert(std::numeric_limits::max() >= TLMCHAN_NUM_TLM_HASH_SLOTS, + "Cannot have more hash slots than maximum telemetry ids in the system"); + +TlmChan::TlmChan(const char* name) : TlmChanComponentBase(name), m_activeBuffer(0) { + // clear slot pointers + for (FwChanIdType entry = 0; entry < TLMCHAN_NUM_TLM_HASH_SLOTS; entry++) { + this->m_tlmEntries[0].slots[entry] = nullptr; + this->m_tlmEntries[1].slots[entry] = nullptr; + } + // clear buckets + for (FwChanIdType entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + this->m_tlmEntries[0].buckets[entry].used = false; + this->m_tlmEntries[0].buckets[entry].updated = false; + this->m_tlmEntries[0].buckets[entry].bucketNo = entry; + this->m_tlmEntries[0].buckets[entry].next = nullptr; + this->m_tlmEntries[0].buckets[entry].id = 0; + this->m_tlmEntries[1].buckets[entry].used = false; + this->m_tlmEntries[1].buckets[entry].updated = false; + this->m_tlmEntries[1].buckets[entry].bucketNo = entry; + this->m_tlmEntries[1].buckets[entry].next = nullptr; + this->m_tlmEntries[1].buckets[entry].id = 0; + } + // clear free index + this->m_tlmEntries[0].free = 0; + this->m_tlmEntries[1].free = 0; +} + +TlmChan::~TlmChan() {} + +FwChanIdType TlmChan::doHash(FwChanIdType id) { + return (id % TLMCHAN_HASH_MOD_VALUE) % TLMCHAN_NUM_TLM_HASH_SLOTS; +} + +void TlmChan::pingIn_handler(const FwIndexType portNum, U32 key) { + // return key + this->pingOut_out(0, key); +} + +Fw::TlmValid TlmChan::TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { + // Compute index for entry + + FwChanIdType index = this->doHash(id); + + // Search to see if channel has been stored + // check both buffers + // don't need to lock because this port is guarded + TlmEntry* activeEntry = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + if (activeEntry) { // If bucket exists, check id + if (activeEntry->id == id) { + break; + } else { // otherwise go to next bucket + activeEntry = activeEntry->next; + } + } else { // no buckets left to search + break; + } + } + + TlmEntry* inactiveEntry = this->m_tlmEntries[1 - this->m_activeBuffer].slots[index]; + for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + if (inactiveEntry) { // If bucket exists, check id + if (inactiveEntry->id == id) { + break; + } else { // otherwise go to next bucket + inactiveEntry = inactiveEntry->next; + } + } else { // no buckets left to search + break; + } + } + + if (activeEntry && inactiveEntry) { + Fw::Time::Comparison cmp = Fw::Time::compare(inactiveEntry->lastUpdate, activeEntry->lastUpdate); + // two entries. grab the one with the most recent time tag + if (cmp == Fw::Time::Comparison::GT) { + // inactive entry is more recent + val = inactiveEntry->buffer; + timeTag = inactiveEntry->lastUpdate; + return Fw::TlmValid::VALID; + } else if (cmp != Fw::Time::Comparison::INCOMPARABLE) { + // active entry is more recent, or they are equal + val = activeEntry->buffer; + timeTag = activeEntry->lastUpdate; + return Fw::TlmValid::VALID; + } else { + // times are incomparable + // return the one that is updated, or if neither, + // default to active + if (inactiveEntry->updated) { + val = inactiveEntry->buffer; + timeTag = inactiveEntry->lastUpdate; + return Fw::TlmValid::VALID; + } else { + val = activeEntry->buffer; + timeTag = activeEntry->lastUpdate; + return Fw::TlmValid::VALID; + } + } + } else if (activeEntry) { + // only one entry, and it's in the active buf + val = activeEntry->buffer; + timeTag = activeEntry->lastUpdate; + return Fw::TlmValid::VALID; + } else if (inactiveEntry) { + // only one entry, and it's in the inactive buf + val = inactiveEntry->buffer; + timeTag = inactiveEntry->lastUpdate; + return Fw::TlmValid::VALID; + } else { + val.resetSer(); + } + return Fw::TlmValid::INVALID; +} + +void TlmChan::TlmRecv_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { + // Compute index for entry + + FwChanIdType index = this->doHash(id); + TlmEntry* entryToUse = nullptr; + TlmEntry* prevEntry = nullptr; + + // Search to see if channel has already been stored or a bucket needs to be added + if (this->m_tlmEntries[this->m_activeBuffer].slots[index]) { + entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + // Loop one extra time so that we don't inadvertently fall through the end of the loop early. + for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS + 1; bucket++) { + if (entryToUse) { + if (entryToUse->id == id) { // found the matching entry + break; + } else { // try next entry + prevEntry = entryToUse; + entryToUse = entryToUse->next; + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); + // add new bucket from free list + entryToUse = + &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; + FW_ASSERT(prevEntry); + prevEntry->next = entryToUse; + // clear next pointer + entryToUse->next = nullptr; + break; + } + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); + // create new entry at slot head + this->m_tlmEntries[this->m_activeBuffer].slots[index] = + &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; + entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + entryToUse->next = nullptr; + } + + // copy into entry + FW_ASSERT(entryToUse); + entryToUse->used = true; + entryToUse->id = id; + entryToUse->updated = true; + entryToUse->lastUpdate = timeTag; + entryToUse->buffer = val; +} + +void TlmChan::Run_handler(FwIndexType portNum, U32 context) { + // Only write packets if connected + if (not this->isConnected_PktSend_OutputPort(0)) { + return; + } + + // lock mutex long enough to modify active telemetry buffer + // so the data can be read without worrying about updates + this->lock(); + this->m_activeBuffer = 1 - this->m_activeBuffer; + // set activeBuffer to not updated + for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + this->m_tlmEntries[this->m_activeBuffer].buckets[entry].updated = false; + } + this->unLock(); + + // go through each entry and send a packet if it has been updated + Fw::TlmPacket pkt; + pkt.resetPktSer(); + + for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + TlmEntry* p_entry = &this->m_tlmEntries[1 - this->m_activeBuffer].buckets[entry]; + if ((p_entry->updated) && (p_entry->used)) { + Fw::SerializeStatus stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer); + + // check to see if this packet is full, if so, send it + if (Fw::FW_SERIALIZE_NO_ROOM_LEFT == stat) { + this->PktSend_out(0, pkt.getBuffer(), 0); + // reset packet for more entries + pkt.resetPktSer(); + // add entry to new packet + stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer); + // if this doesn't work, that means packet isn't big enough for + // even one channel, so assert + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast(stat)); + } else if (Fw::FW_SERIALIZE_OK == stat) { + // if there was still room, do nothing move on to the next channel in the packet + } else // any other status is an assert, since it shouldn't happen + { + FW_ASSERT(0, static_cast(stat)); + } + // flag as updated + p_entry->updated = false; + } // end if entry was updated + } // end for each entry + + // send remnant entries + if (pkt.getNumEntries() > 0) { + this->PktSend_out(0, pkt.getBuffer(), 0); + } +} // end run handler + +} // namespace Svc diff --git a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp new file mode 100644 index 00000000000..d15072ed08a --- /dev/null +++ b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp @@ -0,0 +1,26 @@ +module Svc { + + @ A component for storing telemetry + active component TlmChan { + + @ Guarded port for receiving telemetry values + guarded input port TlmRecv: Fw.Tlm + + @ Guarded port for returning telemetry values by reference + guarded input port TlmGet: Fw.TlmGet + + @ Run port for starting packet send cycle + async input port Run: Svc.Sched + + @ Packet send port + output port PktSend: Fw.Com + + @ Ping input port + async input port pingIn: Svc.Ping + + @ Ping output port + output port pingOut: Svc.Ping + + } + +} diff --git a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp new file mode 100644 index 00000000000..2bff852c880 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp @@ -0,0 +1,63 @@ +/** + * \file + * \author T. Canham + * \brief Component that stores telemetry channel values + * + * \copyright + * Copyright 2009-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + *

+ */ + +#ifndef TELEMCHANIMPL_HPP_ +#define TELEMCHANIMPL_HPP_ + +#include +#include +#include + +namespace Svc { + +class TlmChan final : public TlmChanComponentBase { + public: + TlmChan(const char* compName); + virtual ~TlmChan(); + + PROTECTED: + // can be overridden for alternate algorithms + virtual FwChanIdType doHash(FwChanIdType id); + + PRIVATE: + // Port functions + void TlmRecv_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val); + Fw::TlmValid TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val); + void Run_handler(FwIndexType portNum, U32 context); + //! Handler implementation for pingIn + //! + void pingIn_handler(const FwIndexType portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ); + + typedef struct tlmEntry { + FwChanIdType id; //!< telemetry id stored in slot + bool updated; //!< set whenever a value has been written. Used to skip if writing out values for downlinking + Fw::Time lastUpdate; //!< last updated time + Fw::TlmBuffer buffer; //!< buffer to store serialized telemetry + tlmEntry* next; //!< pointer to next bucket in table + bool used; //!< if entry has been used + FwChanIdType bucketNo; //!< for testing + } TlmEntry; + + struct TlmSet { + TlmEntry* slots[TLMCHAN_NUM_TLM_HASH_SLOTS]; //!< set of hash slots in hash table + TlmEntry buckets[TLMCHAN_HASH_BUCKETS]; //!< set of buckets used in hash table + FwChanIdType free; //!< next free bucket + } m_tlmEntries[2]; + + U32 m_activeBuffer; // !< which buffer is active for storing telemetry +}; + +} // namespace Svc + +#endif /* TELEMCHANIMPL_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore b/Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore new file mode 100644 index 00000000000..0b84df0f025 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore @@ -0,0 +1 @@ +*.html \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Code.xlsx b/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Code.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e26db5630788353a8370595962b77bc29059b1aa GIT binary patch literal 31188 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 Nje+Qsr_O&}{Xe{#LI?l= literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Design.xlsx b/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Design.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6562659be0cd899f6ef9ec482a06ee07d0c91937 GIT binary patch literal 24324 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 W#71Uj|26qgph+S3A8HK$`t^U6*@cY& literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Unit_Test.xls b/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Unit_Test.xls new file mode 100644 index 0000000000000000000000000000000000000000..a0ceaa4b2702761f799c16c23ae3c1abcff967a0 GIT binary patch literal 51712 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 literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/img/ExternalUserScenario.jpg b/Svc/Subtopologies/CDHCore/TlmChan/docs/img/ExternalUserScenario.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b8cd0ba4453ce5faede457b2ee01c89573c503ae GIT binary patch literal 72528 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 literal 0 HcmV?d00001 diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/img/TlmChanBDD.jpg b/Svc/Subtopologies/CDHCore/TlmChan/docs/img/TlmChanBDD.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b61e1ab6742f06608673332aa57c43bdc4c50d1 GIT binary patch literal 60478 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 I(NC}c4 +#include +#include +#include "TlmChanTester.hpp" + +TEST(TlmChanTest, InitTest) { + Svc::TlmChanTester tester; +} + +TEST(TlmChanTest, NominalChannelTest) { + TEST_CASE(107.1.1, "Nominal channelized telemetry"); + COMMENT("Write a single channel and verify it is read back and pushed correctly."); + + Svc::TlmChanTester tester; + // run test + tester.runNominalChannel(); +} + +TEST(TlmChanTest, MultiChannelTest) { + TEST_CASE(107.1.2, "Nominal Multi-channel channelized telemetry"); + COMMENT("Write multiple channels and verify they are read back and pushed correctly."); + + Svc::TlmChanTester tester; + + // run test + tester.runMultiChannel(); +} + +TEST(TlmChanTest, OffNominal) { + TEST_CASE(107.2.1, "Off-nominal channelized telemetry"); + COMMENT("Attempt to read a channel that hasn't been written."); + + Svc::TlmChanTester tester; + + // run test + tester.runOffNominal(); +} + +// TEST(TlmChanTest,TooManyChannels) { + +// COMMENT("Too Many Channel Test"); + +// Svc::TlmChanImpl impl("TlmChanImpl"); + +// impl.init(10,0); + +// Svc::TlmChanImplTester tester(impl); + +// tester.init(); + +// // connect ports +// connectPorts(impl,tester); + +// // run test +// tester.runTooManyChannels(); + +// } diff --git a/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp b/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp new file mode 100644 index 00000000000..201e0026394 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp @@ -0,0 +1,351 @@ +// ====================================================================== +// \title TlmChan.hpp +// \author tcanham +// \brief cpp file for TlmChan test harness implementation class +// ====================================================================== + +#include "TlmChanTester.hpp" +#include + +#define INSTANCE 0 +#define MAX_HISTORY_SIZE 10 +#define QUEUE_DEPTH 10 + +static const FwChanIdType TEST_CHAN_SIZE = sizeof(FwChanIdType) + Fw::Time::SERIALIZED_SIZE + sizeof(U32); +static const FwChanIdType CHANS_PER_COMBUFFER = + (FW_COM_BUFFER_MAX_SIZE - sizeof(FwPacketDescriptorType)) / TEST_CHAN_SIZE; +static constexpr FwSizeType INTEGER_DIVISION_ROUNDED_UP(FwSizeType a, FwSizeType b) { + return ((a % b) == 0) ? (a / b) : (a / b) + 1; +} + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +TlmChanTester ::TlmChanTester() + : TlmChanGTestBase("Tester", MAX_HISTORY_SIZE), component("TlmChan"), m_numBuffs(0), m_bufferRecv(false) { + this->initComponents(); + this->connectPorts(); +} + +TlmChanTester ::~TlmChanTester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void TlmChanTester::runNominalChannel() { + this->clearBuffs(); + // send first buffer + this->sendBuff(27, 10); + this->doRun(true); + this->checkBuff(0, 1, 27, 10); + + this->clearBuffs(); + // send again to other buffer + this->sendBuff(27, 10); + + static bool tlc003 = false; + + if (not tlc003) { + REQUIREMENT("TLC-003"); + tlc003 = true; + } + + this->doRun(true); + this->checkBuff(0, 1, 27, 10); + + // do an update to make sure it gets updated and returned correctly + this->clearBuffs(); + this->sendBuff(27, 20); +} + +void TlmChanTester::runMultiChannel() { + FwChanIdType ID_0[] = {// Test channel IDs + 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1100, 0x1101, 0x1102, 0x1103, 0x300, + 0x301, 0x400, 0x401, 0x402, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105}; + + this->clearBuffs(); + // send all updates + for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_0); n++) { + this->sendBuff(ID_0[n], n); + } + + ASSERT_EQ(0, this->component.m_activeBuffer); + + // do a run, and all the packets should be sent + this->doRun(true); + ASSERT_TRUE(this->m_bufferRecv); + ASSERT_EQ(INTEGER_DIVISION_ROUNDED_UP(FW_NUM_ARRAY_ELEMENTS(ID_0), CHANS_PER_COMBUFFER), this->m_numBuffs); + ASSERT_EQ(1, this->component.m_activeBuffer); + + // verify packets + for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_0); n++) { + // printf("#: %d\n",n); + this->checkBuff(n, FW_NUM_ARRAY_ELEMENTS(ID_0), ID_0[n], n); + } + + // send another set + + FwChanIdType ID_1[] = {// Test channel IDs + 0x5000, 0x5001, 0x5002, 0x5003, 0x5004, 0x5005, 0x5100, 0x5101, 0x5102, + 0x5103, 0x6300, 0x6301, 0x6400, 0x6401, 0x6402, 0x6100, 0x6101, 0x6102, + 0x6103, 0x6104, 0x6105, 0x8101, 0x8102, 0x8103, 0x8104, 0x8105}; + + this->clearBuffs(); + // send all updates + for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_1); n++) { + this->sendBuff(ID_1[n], n); + } + + ASSERT_EQ(1, this->component.m_activeBuffer); + + // do a run, and all the packets should be sent + this->doRun(true); + ASSERT_TRUE(this->m_bufferRecv); + ASSERT_EQ(INTEGER_DIVISION_ROUNDED_UP(FW_NUM_ARRAY_ELEMENTS(ID_1), CHANS_PER_COMBUFFER), this->m_numBuffs); + ASSERT_EQ(0, this->component.m_activeBuffer); + + // verify packets + for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_1); n++) { + // printf("#: %d\n",n); + this->checkBuff(n, FW_NUM_ARRAY_ELEMENTS(ID_1), ID_1[n], n); + } +} + +void TlmChanTester::runOffNominal() { + // Ask for a packet that isn't written yet + Fw::TlmBuffer buff; + Fw::SerializeStatus stat; + Fw::Time timeTag; + U32 val = 10; + + // create Telemetry item and put dummy data in to make sure it gets erased + buff.resetSer(); + stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + // Read back value + Fw::TlmValid valid = this->invoke_to_TlmGet(0, 10, timeTag, buff); + ASSERT_EQ(0u, buff.getBuffLength()); + ASSERT_EQ(valid, Fw::TlmValid::INVALID); + +} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void TlmChanTester ::from_PktSend_handler(const FwIndexType portNum, Fw::ComBuffer& data, U32 context) { + this->pushFromPortEntry_PktSend(data, context); + this->m_bufferRecv = true; + this->m_rcvdBuffer[this->m_numBuffs] = data; + this->m_numBuffs++; +} + +void TlmChanTester ::from_pingOut_handler(const FwIndexType portNum, U32 key) { + this->pushFromPortEntry_pingOut(key); +} + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +bool TlmChanTester::doRun(bool check) { + // execute run port to send packet + this->invoke_to_Run(0, 0); + // dispatch run message + this->m_bufferRecv = false; + this->component.doDispatch(); + if (check) { + EXPECT_TRUE(this->m_bufferRecv); + } + return this->m_bufferRecv; +} + +void TlmChanTester::checkBuff(FwChanIdType chanNum, FwChanIdType totalChan, FwChanIdType id, U32 val) { + Fw::Time timeTag; + // deserialize packet + Fw::SerializeStatus stat; + + static bool tlc004 = false; + + if (not tlc004) { + REQUIREMENT("TLC-004"); + tlc004 = true; + } + + FwChanIdType currentChan = 0; + + // Search for channel ID + for (FwChanIdType packet = 0; packet < this->m_numBuffs; packet++) { + // Look at packet descriptor for current packet + this->m_rcvdBuffer[packet].resetDeser(); + // first piece should be tlm packet descriptor + FwPacketDescriptorType desc; + stat = this->m_rcvdBuffer[packet].deserialize(desc); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + ASSERT_EQ(desc, static_cast(Fw::ComPacket::FW_PACKET_TELEM)); + + for (FwChanIdType chan = 0; chan < CHANS_PER_COMBUFFER; chan++) { + // decode channel ID + FwEventIdType sentId; + stat = this->m_rcvdBuffer[packet].deserialize(sentId); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + // next piece is time tag + Fw::Time recTimeTag(TB_NONE, 0, 0); + stat = this->m_rcvdBuffer[packet].deserialize(recTimeTag); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + ASSERT_TRUE(timeTag == recTimeTag); + // next piece is event argument + U32 readVal; + stat = this->m_rcvdBuffer[packet].deserialize(readVal); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + if (chanNum == currentChan) { + ASSERT_EQ(id, sentId); + ASSERT_EQ(val, readVal); + } + + // quit if we are at max channel entry + if (currentChan == (totalChan - 1)) { + break; + } + + currentChan++; + } + + // packet should be empty + ASSERT_EQ(0, this->m_rcvdBuffer[packet].getBuffLeft()); + } +} + +void TlmChanTester::sendBuff(FwChanIdType id, U32 val) { + Fw::TlmBuffer buff; + Fw::TlmBuffer readBack; + Fw::SerializeStatus stat; + Fw::Time timeTag; + U32 retestVal; + + // create telemetry item + buff.resetSer(); + stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + static bool tlc001 = false; + + if (not tlc001) { + REQUIREMENT("TLC-001"); + tlc001 = true; + } + + this->invoke_to_TlmRecv(0, id, timeTag, buff); + // Read back value + static bool tlc002 = false; + + if (not tlc002) { + REQUIREMENT("TLC-002"); + tlc002 = true; + } + + Fw::TlmValid valid = this->invoke_to_TlmGet(0, id, timeTag, readBack); + // deserialize value + retestVal = 0; + readBack.deserialize(retestVal); + ASSERT_EQ(retestVal, val); + ASSERT_EQ(valid, Fw::TlmValid::VALID); +} + +void TlmChanTester::clearBuffs() { + this->m_numBuffs = 0; + for (FwChanIdType n = 0; n < TLMCHAN_HASH_BUCKETS; n++) { + this->m_rcvdBuffer[n].resetSer(); + } +} + +void TlmChanTester::dumpTlmEntry(TlmChan::TlmEntry* entry) { + printf( + "Entry " + " Ptr: %p" + " id: 0x%08X" + " bucket: %d" + " next: %p\n", + static_cast(entry), entry->id, entry->bucketNo, static_cast(entry->next)); +} + +void TlmChanTester::dumpHash() { + // printf("**Buffer 0\n"); + for (FwChanIdType slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { + printf("Slot: %d\n", slot); + if (this->component.m_tlmEntries[0].slots[slot]) { + TlmChan::TlmEntry* entry = component.m_tlmEntries[0].slots[slot]; + for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + dumpTlmEntry(entry); + if (entry->next == nullptr) { + break; + } else { + entry = entry->next; + } + } + } else { + printf("EMPTY\n"); + } + } + printf("\n"); + // for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + // printf("Bucket: %d ",bucket); + // dumpTlmEntry(&m_impl.m_tlmEntries[0].buckets[bucket]); + // } + // printf("**Buffer 1\n"); + // for (FwChanIdType slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { + // printf("Slot: %d\n",slot); + // if (m_impl.m_tlmEntries[1].slots[slot]) { + // TlmChanImpl::TlmEntry* entry = m_impl.m_tlmEntries[1].slots[slot]; + // for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + // dumpTlmEntry(entry); + // if (entry->next == 0) { + // break; + // } else { + // entry = entry->next; + // } + // } + // } else { + // printf("EMPTY\n"); + // } + // } + // printf("\n"); + // for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + // printf("Bucket: %d\n",bucket); + // dumpTlmEntry(&m_impl.m_tlmEntries[1].buckets[bucket]); + // } +} + +void TlmChanTester ::connectPorts() { + // Run + this->connect_to_Run(0, this->component.get_Run_InputPort(0)); + + // TlmGet + this->connect_to_TlmGet(0, this->component.get_TlmGet_InputPort(0)); + + // TlmRecv + this->connect_to_TlmRecv(0, this->component.get_TlmRecv_InputPort(0)); + + // pingIn + this->connect_to_pingIn(0, this->component.get_pingIn_InputPort(0)); + + // PktSend + this->component.set_PktSend_OutputPort(0, this->get_from_PktSend(0)); + + // pingOut + this->component.set_pingOut_OutputPort(0, this->get_from_pingOut(0)); +} + +void TlmChanTester ::initComponents() { + this->init(); + this->component.init(QUEUE_DEPTH, INSTANCE); +} + +} // end namespace Svc diff --git a/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp b/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp new file mode 100644 index 00000000000..b0dc4c88e7e --- /dev/null +++ b/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp @@ -0,0 +1,95 @@ +// ====================================================================== +// \title TlmChan/test/ut/Tester.hpp +// \author tcanham +// \brief hpp file for TlmChan test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "TlmChanGTestBase.hpp" +#include "Svc/TlmChan/TlmChan.hpp" + +namespace Svc { + +class TlmChanTester : public TlmChanGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + //! Construct object TlmChanTester + //! + TlmChanTester(); + + //! Destroy object TlmChanTester + //! + ~TlmChanTester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + void runNominalChannel(); + void runMultiChannel(); + void runOffNominal(); + + private: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_PktSend + //! + void from_PktSend_handler(const FwIndexType 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 FwIndexType portNum, //!< The port number + U32 key //!< Value to return to pinger + ); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + void sendBuff(FwChanIdType id, U32 val); + bool doRun(bool check); + void checkBuff(FwChanIdType chanNum, FwChanIdType totalChan, FwChanIdType id, U32 val); + + void clearBuffs(); + + // dump functions + void dumpHash(); + static void dumpTlmEntry(TlmChan::TlmEntry* entry); + + private: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + TlmChan component; + // Keep a history + FwChanIdType m_numBuffs; + Fw::ComBuffer m_rcvdBuffer[TLMCHAN_HASH_BUCKETS]; + bool m_bufferRecv; +}; + +} // end namespace Svc + +#endif diff --git a/Svc/Subtopologies/CMakeLists.txt b/Svc/Subtopologies/CMakeLists.txt new file mode 100644 index 00000000000..31a6bed3130 --- /dev/null +++ b/Svc/Subtopologies/CMakeLists.txt @@ -0,0 +1 @@ +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") \ No newline at end of file From 8cc262de936840ce18b4569375c2d4a75be8aa26 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 5 Jun 2025 13:07:41 -0700 Subject: [PATCH 05/52] CDHCore Subtopology added under Svc and integrated into Ref --- Ref/Top/RefPackets.fppi | 7 +- Ref/Top/RefTopology.cpp | 6 +- Ref/Top/RefTopologyDefs.hpp | 87 +- Ref/Top/instances.fpp | 24 +- Ref/Top/topology.fpp | 30 +- Svc/CMakeLists.txt | 2 + .../CDHCore/ActiveLogger/ActiveLogger.fpp | 152 --- .../CDHCore/ActiveLogger/ActiveLogger.hpp | 17 - .../CDHCore/ActiveLogger/ActiveLoggerImpl.cpp | 205 ---- .../CDHCore/ActiveLogger/ActiveLoggerImpl.hpp | 67 -- .../CDHCore/ActiveLogger/CMakeLists.txt | 26 - Svc/Subtopologies/CDHCore/ActiveLogger/README | 6 - .../CDHCore/ActiveLogger/changed-symbols.txt | 86 -- .../CDHCore/ActiveLogger/docs/.gitignore | 1 - .../ActiveLogger/docs/Checklist_Code.xlsx | Bin 29740 -> 0 bytes .../ActiveLogger/docs/Checklist_Design.xlsx | Bin 24983 -> 0 bytes .../ActiveLogger/docs/Checklist_Unit_Test.xls | Bin 51200 -> 0 bytes .../ActiveLogger/docs/img/ActiveLoggerBDD.jpg | Bin 103324 -> 0 bytes .../ActiveLogger/docs/img/ReceiveEvents.jpg | Bin 67078 -> 0 bytes .../docs/img/WriteEventBuffer.jpg | Bin 38763 -> 0 bytes .../CDHCore/ActiveLogger/docs/sdd.md | 117 --- .../CDHCore/ActiveLogger/test/ut/.gitignore | 1 - .../test/ut/ActiveLoggerImplTester.cpp | 625 ------------ .../test/ut/ActiveLoggerImplTester.hpp | 80 -- .../test/ut/ActiveLoggerTester.cpp | 158 ---- .../CDHCore/ActiveLogger/test/ut/Readme.txt | 9 - Svc/Subtopologies/CDHCore/CDHCore.fpp | 33 + .../CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 25 + .../CDHCore/CDHCoreConfig/CMakeLists.txt | 5 + .../{Subtopology => }/CDHCoreTopologyDefs.hpp | 6 +- Svc/Subtopologies/CDHCore/CMakeLists.txt | 10 +- .../CDHCore/CmdDispatcher/CMakeLists.txt | 22 - .../CDHCore/CmdDispatcher/CmdDispatcher.fpp | 199 ---- .../CmdDispatcher/CommandDispatcher.hpp | 17 - .../CmdDispatcher/CommandDispatcherImpl.cpp | 201 ---- .../CmdDispatcher/CommandDispatcherImpl.hpp | 168 ---- .../CDHCore/CmdDispatcher/README | 6 - .../CDHCore/CmdDispatcher/changed-symbols.txt | 41 - .../CDHCore/CmdDispatcher/docs/.gitignore | 1 - .../CmdDispatcher/docs/Checklist_Code.xlsx | Bin 29709 -> 0 bytes .../CmdDispatcher/docs/Checklist_Design.xlsx | Bin 25044 -> 0 bytes .../docs/Checklist_Unit_Test.xls | Bin 51200 -> 0 bytes .../docs/img/CommandDispatcherBDD.jpg | Bin 142623 -> 0 bytes .../CDHCore/CmdDispatcher/docs/sdd.md | 127 --- .../test/int/test_cmd_dispatcher.py | 12 - .../test/ut/CommandDispatcherImplTester.cpp | 887 ------------------ .../test/ut/CommandDispatcherImplTester.hpp | 55 -- .../test/ut/CommandDispatcherTester.cpp | 211 ----- .../CDHCore/Subtopology/CDHCore.fpp | 28 - .../CDHCore/Subtopology/CMakeLists.txt | 13 - .../SubtopologyConfig/CmakeLists.txt | 5 - .../Subtopology/SubtopologyConfig/config.fpp | 13 - .../Subtopology/intentionally-empty.cpp | 0 .../CDHCore/TlmChan/CMakeLists.txt | 23 - Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp | 241 ----- Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp | 26 - Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp | 63 -- .../CDHCore/TlmChan/docs/.gitignore | 1 - .../CDHCore/TlmChan/docs/Checklist_Code.xlsx | Bin 31188 -> 0 bytes .../TlmChan/docs/Checklist_Design.xlsx | Bin 24324 -> 0 bytes .../TlmChan/docs/Checklist_Unit_Test.xls | Bin 51712 -> 0 bytes .../TlmChan/docs/img/DatabaseScenario.jpg | Bin 48738 -> 0 bytes .../TlmChan/docs/img/ExternalUserScenario.jpg | Bin 72528 -> 0 bytes .../CDHCore/TlmChan/docs/img/TlmChanBDD.jpg | Bin 60478 -> 0 bytes Svc/Subtopologies/CDHCore/TlmChan/docs/sdd.md | 98 -- .../CDHCore/TlmChan/test/ut/TlmChanMain.cpp | 65 -- .../CDHCore/TlmChan/test/ut/TlmChanTester.cpp | 351 ------- .../CDHCore/TlmChan/test/ut/TlmChanTester.hpp | 95 -- Svc/Subtopologies/CMakeLists.txt | 3 +- 69 files changed, 164 insertions(+), 4593 deletions(-) delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/CMakeLists.txt delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/README delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/changed-symbols.txt delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/.gitignore delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Code.xlsx delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Design.xlsx delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Unit_Test.xls delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/ActiveLoggerBDD.jpg delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/ReceiveEvents.jpg delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/WriteEventBuffer.jpg delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp delete mode 100644 Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt create mode 100644 Svc/Subtopologies/CDHCore/CDHCore.fpp create mode 100644 Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp create mode 100644 Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt rename Svc/Subtopologies/CDHCore/{Subtopology => }/CDHCoreTopologyDefs.hpp (56%) delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/README delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Code.xlsx delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Design.xlsx delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Unit_Test.xls delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/img/CommandDispatcherBDD.jpg delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/int/test_cmd_dispatcher.py delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp delete mode 100644 Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp delete mode 100644 Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp delete mode 100644 Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt delete mode 100644 Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt delete mode 100644 Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp delete mode 100644 Svc/Subtopologies/CDHCore/Subtopology/intentionally-empty.cpp delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Code.xlsx delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Design.xlsx delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Unit_Test.xls delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/img/DatabaseScenario.jpg delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/img/ExternalUserScenario.jpg delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/img/TlmChanBDD.jpg delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/docs/sdd.md delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanMain.cpp delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp delete mode 100644 Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index 526400ffd76..79f7a0fc4d8 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -1,7 +1,8 @@ telemetry packets RefPackets { packet CDH id 1 group 1 { - Ref.cmdDisp.CommandsDispatched + #Ref.cmdDisp.CommandsDispatched + CDHCore.cmdDisp.CommandsDispatched Ref.rateGroup1Comp.RgMaxTime Ref.rateGroup2Comp.RgMaxTime Ref.rateGroup3Comp.RgMaxTime @@ -29,7 +30,7 @@ telemetry packets RefPackets { Ref.cmdSeq.CS_Errors Ref.fileUplink.Warnings Ref.fileDownlink.Warnings - Ref.$health.PingLateWarnings + CDHCore.$health.PingLateWarnings Ref.fileManager.Errors Ref.commsBufferManager.NoBuffs Ref.commsBufferManager.EmptyBuffs @@ -264,5 +265,5 @@ telemetry packets RefPackets { } } omit { - Ref.cmdDisp.CommandErrors + CDHCore.cmdDisp.CommandErrors } diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 88217576601..cf5a4282f3b 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -21,7 +21,7 @@ #include //Subtopology includes -#include +#include // Allows easy reference to objects in FPP/autocoder required namespaces using namespace Ref; @@ -99,8 +99,8 @@ void configureTopology() { prmDb.readParamFile(); // Health is supplied a set of ping entires. - health.setPingEntries(ConfigObjects::Ref_health::pingEntries, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::Ref_health::pingEntries), HEALTH_WATCHDOG_CODE); + CDHCore::health.setPingEntries(ConfigObjects::CDHCore_health::pingEntries, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::CDHCore_health::pingEntries), HEALTH_WATCHDOG_CODE); // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. Svc::BufferManager::BufferBins commsBuffMgrBins; diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 8158cc3be73..6d8cb189b11 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -17,57 +17,28 @@ #include "Svc/Health/Health.hpp" // Subtopology includes -#include +#include "Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp" -// Definitions are placed within a namespace named after the deployment -namespace Ref { - -/** - * \brief required type definition to carry state - * - * The topology autocoder requires an object that carries state with the name `Ref::TopologyState`. Only the type - * definition is required by the autocoder and the contents of this object are otherwise opaque to the autocoder. The - * contents are entirely up to the definition of the project. This reference application specifies hostname and port - * fields, which are derived by command line inputs. - */ -struct TopologyState { - const char* hostname; - U16 port; -}; - -/** - * \brief required ping constants - * - * The topology autocoder requires a WARN and FATAL constant definition for each component that supports the health-ping - * interface. These are expressed as enum constants placed in a namespace named for the component instance. These - * are all placed in the PingEntries namespace. - * - * Each constant specifies how many missed pings are allowed before a WARNING_HI/FATAL event is triggered. In the - * following example, the health component will emit a WARNING_HI event if the component instance cmdDisp does not - * respond for 3 pings and will FATAL if responses are not received after a total of 5 pings. - * - * ```c++ - * namespace PingEntries { - * namespace cmdDisp { - * enum { WARN = 3, FATAL = 5 }; - * } - * } - * ``` - */ +namespace GlobalDefs { namespace PingEntries { namespace Ref_blockDrv { enum { WARN = 3, FATAL = 5 }; } +/* For the purposes of the subtopology namespace Ref_tlmSend { enum { WARN = 3, FATAL = 5 }; } + namespace Ref_cmdDisp { enum { WARN = 3, FATAL = 5 }; } -namespace Ref_cmdSeq { + +namespace Ref_eventLogger { enum { WARN = 3, FATAL = 5 }; } -namespace Ref_eventLogger { + +*/ +namespace Ref_cmdSeq { enum { WARN = 3, FATAL = 5 }; } namespace Ref_fileDownlink { @@ -98,5 +69,45 @@ namespace Ref_dpCat { enum { WARN = 3, FATAL = 5 }; } } // namespace PingEntries +} +/** + * \brief required ping constants + * + * The topology autocoder requires a WARN and FATAL constant definition for each component that supports the health-ping + * interface. These are expressed as enum constants placed in a namespace named for the component instance. These + * are all placed in the PingEntries namespace. + * + * Each constant specifies how many missed pings are allowed before a WARNING_HI/FATAL event is triggered. In the + * following example, the health component will emit a WARNING_HI event if the component instance cmdDisp does not + * respond for 3 pings and will FATAL if responses are not received after a total of 5 pings. + * + * ```c++ + * namespace PingEntries { + * namespace cmdDisp { + * enum { WARN = 3, FATAL = 5 }; + * } + * } + * ``` + */ + +// Definitions are placed within a namespace named after the deployment +namespace Ref { + +/** + * \brief required type definition to carry state + * + * The topology autocoder requires an object that carries state with the name `Ref::TopologyState`. Only the type + * definition is required by the autocoder and the contents of this object are otherwise opaque to the autocoder. The + * contents are entirely up to the definition of the project. This reference application specifies hostname and port + * fields, which are derived by command line inputs. + */ +struct TopologyState { + const char* hostname; + U16 port; +}; + +namespace PingEntries = ::GlobalDefs::PingEntries; + } // namespace Ref + #endif diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 78884e00c0d..c04b770baa5 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -33,10 +33,10 @@ module Ref { stack size Default.STACK_SIZE \ priority 118 - instance cmdDisp: Svc.CommandDispatcher base id 0x0500 \ - queue size 20 \ - stack size Default.STACK_SIZE \ - priority 101 + #instance cmdDisp: Svc.CommandDispatcher base id 0x0500 \ + # queue size 20 \ + # stack size Default.STACK_SIZE \ + # priority 101 instance cmdSeq: Svc.CmdSequencer base id 0x0600 \ queue size Default.QUEUE_SIZE \ @@ -63,19 +63,19 @@ module Ref { stack size Default.STACK_SIZE \ priority 100 - instance eventLogger: Svc.ActiveLogger base id 0x0B00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 98 + #instance eventLogger: Svc.ActiveLogger base id 0x0B00 \ + # queue size Default.QUEUE_SIZE \ + # stack size Default.STACK_SIZE \ + # priority 98 # comment in Svc.TlmChan or Svc.TlmPacketizer # depending on which form of telemetry downlink # you wish to use - instance tlmSend: Svc.TlmChan base id 0x0C00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 97 + #instance tlmSend: Svc.TlmChan base id 0x0C00 \ + # queue size Default.QUEUE_SIZE \ + # stack size Default.STACK_SIZE \ + # priority 97 # instance tlmSend: Svc.TlmPacketizer base id 0x0C00 \ # queue size Default.QUEUE_SIZE \ diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index c41ae91a966..25369f824a9 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -1,5 +1,6 @@ module Ref { + # ---------------------------------------------------------------------- # Symbolic constants for port numbers # ---------------------------------------------------------------------- @@ -20,7 +21,6 @@ module Ref { } topology Ref { - # ---------------------------------------------------------------------- # Subtopology imports # ---------------------------------------------------------------------- @@ -30,7 +30,7 @@ module Ref { # Instances used in the topology # ---------------------------------------------------------------------- - instance $health + #instance $health instance SG1 instance SG2 instance SG3 @@ -76,19 +76,19 @@ module Ref { # Pattern graph specifiers # ---------------------------------------------------------------------- - #command connections instance cmdDisp + command connections instance CDHCore.cmdDisp - #event connections instance eventLogger + event connections instance CDHCore.eventLogger param connections instance prmDb - #telemetry connections instance tlmSend + telemetry connections instance CDHCore.tlmSend text event connections instance textLogger time connections instance posixTime - health connections instance $health + health connections instance CDHCore.$health # ---------------------------------------------------------------------- # Telemetry packets @@ -105,8 +105,8 @@ module Ref { dpCat.fileOut -> fileDownlink.SendFile fileDownlink.FileComplete -> dpCat.fileDone # Inputs to ComQueue (events, telemetry, file) - Subtopology.eventLogger.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] - Subtopology.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] + CDHCore.eventLogger.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] + CDHCore.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn # ComQueue <-> Framer @@ -128,7 +128,7 @@ module Ref { } connections FaultProtection { - Subtopology.eventLogger.FatalAnnounce -> fatalHandler.FatalReceive + CDHCore.eventLogger.FatalAnnounce -> fatalHandler.FatalReceive } connections RateGroups { @@ -140,7 +140,7 @@ module Ref { rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup1] -> rateGroup1Comp.CycleIn rateGroup1Comp.RateGroupMemberOut[0] -> SG1.schedIn rateGroup1Comp.RateGroupMemberOut[1] -> SG2.schedIn - rateGroup1Comp.RateGroupMemberOut[2] -> Subtopology.tlmSend.Run + rateGroup1Comp.RateGroupMemberOut[2] -> CDHCore.tlmSend.Run rateGroup1Comp.RateGroupMemberOut[3] -> fileDownlink.Run rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run rateGroup1Comp.RateGroupMemberOut[5] -> comQueue.run @@ -154,7 +154,7 @@ module Ref { # Rate group 3 rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup3] -> rateGroup3Comp.CycleIn - rateGroup3Comp.RateGroupMemberOut[0] -> $health.Run + rateGroup3Comp.RateGroupMemberOut[0] -> CDHCore.$health.Run rateGroup3Comp.RateGroupMemberOut[1] -> SG5.schedIn rateGroup3Comp.RateGroupMemberOut[2] -> blockDrv.Sched rateGroup3Comp.RateGroupMemberOut[3] -> commsBufferManager.schedIn @@ -169,8 +169,8 @@ module Ref { } connections Sequencer { - cmdSeq.comCmdOut -> Subtopology.cmdDisp.seqCmdBuff - Subtopology.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn + cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn } connections Uplink { @@ -196,8 +196,8 @@ module Ref { fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn # Router <-> CmdDispatcher/FileUplink - fprimeRouter.commandOut -> Subtopology.cmdDisp.seqCmdBuff - Subtopology.cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn + fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn fprimeRouter.fileOut -> fileUplink.bufferSendIn fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn } diff --git a/Svc/CMakeLists.txt b/Svc/CMakeLists.txt index b8487361a16..25000808f05 100644 --- a/Svc/CMakeLists.txt +++ b/Svc/CMakeLists.txt @@ -53,6 +53,8 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/StaticMemory/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TlmChan/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TlmPacketizer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SystemResources/") + +# Subtopologies add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Subtopologies/") # Text logger components included by default, diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp deleted file mode 100644 index acd06a8e175..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.fpp +++ /dev/null @@ -1,152 +0,0 @@ -module Svc { - - @ A component for logging events - active component ActiveLogger { - - # ---------------------------------------------------------------------- - # Types - # ---------------------------------------------------------------------- - - @ Severity level for event filtering - @ Similar to Fw::LogSeverity, but no FATAL event - enum FilterSeverity { - WARNING_HI = 0 @< Filter WARNING_HI events - WARNING_LO = 1 @< Filter WARNING_LO events - COMMAND = 2 @< Filter COMMAND events - ACTIVITY_HI = 3 @< Filter ACTIVITY_HI events - ACTIVITY_LO = 4 @< Filter ACTIVITY_LO events - DIAGNOSTIC = 5 @< Filter DIAGNOSTIC events - } - - # TODO: Consider replacing this enum with Fw::Enabled - # However, the sense of 0 and 1 are reversed - @ Enabled and disabled state - enum Enabled { - ENABLED = 0 @< Enabled state - DISABLED = 1 @< Disabled state - } - - # ---------------------------------------------------------------------- - # Internal ports - # ---------------------------------------------------------------------- - - @ Internal interface to send log messages to component thread - internal port loqQueue( - $id: FwEventIdType @< Log ID - timeTag: Fw.Time @< Time Tag - $severity: Fw.LogSeverity @< The severity argument - args: Fw.LogBuffer @< Buffer containing serialized log entry - ) \ - drop - - # ---------------------------------------------------------------------- - # General ports - # ---------------------------------------------------------------------- - - @ Event input port - sync input port LogRecv: Fw.Log - - @ Packet send port - output port PktSend: Fw.Com - - @ FATAL event announce port - output port FatalAnnounce: Svc.FatalEvent - - @ Ping input port - async input port pingIn: Svc.Ping - - @ Ping output port - output port pingOut: Svc.Ping - - # ---------------------------------------------------------------------- - # Special ports - # ---------------------------------------------------------------------- - - @ Port for receiving commands - command recv port CmdDisp - - @ Port for sending command registration requests - command reg port CmdReg - - @ Port for sending command responses - command resp port CmdStatus - - @ Port for emitting events - event port Log - - @ Port for emitting text events - text event port LogText - - @ Port for getting the time - time get port Time - - # ---------------------------------------------------------------------- - # Commands - # ---------------------------------------------------------------------- - - @ Set filter for reporting events. Events are not stored in component. - sync command SET_EVENT_FILTER( - filterLevel: FilterSeverity @< Filter level - filterEnabled: Enabled @< Filter state - ) \ - opcode 0 - - @ Filter a particular ID - async command SET_ID_FILTER( - ID: U32 - idFilterEnabled: Enabled @< ID filter state - ) \ - opcode 2 - - @ Dump the filter states via events - async command DUMP_FILTER_STATE \ - opcode 3 - - # ---------------------------------------------------------------------- - # Events - # ---------------------------------------------------------------------- - - @ Dump severity filter state - event SEVERITY_FILTER_STATE( - $severity: FilterSeverity @< The severity level - enabled: bool - ) \ - severity activity low \ - id 0 \ - format "{} filter state. {}" - - @ Indicate ID is filtered - event ID_FILTER_ENABLED( - ID: U32 @< The ID filtered - ) \ - severity activity high \ - id 1 \ - format "ID {} is filtered." - - @ Attempted to add ID to full ID filter ID - event ID_FILTER_LIST_FULL( - ID: U32 @< The ID filtered - ) \ - severity warning low \ - id 2 \ - format "ID filter list is full. Cannot filter {} ." - - @ Removed an ID from the filter - event ID_FILTER_REMOVED( - ID: U32 @< The ID removed - ) \ - severity activity high \ - id 3 \ - format "ID filter ID {} removed." - - @ ID not in filter - event ID_FILTER_NOT_FOUND( - ID: U32 @< The ID removed - ) \ - severity warning low \ - id 4 \ - format "ID filter ID {} not found." - - } - -} diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp deleted file mode 100644 index e7ecdde9346..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLogger.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// ====================================================================== -// ActiveLogger.hpp -// Standardization header for ActiveLogger -// ====================================================================== - -#ifndef Svc_ActiveLogger_HPP -#define Svc_ActiveLogger_HPP - -#include "Svc/ActiveLogger/ActiveLoggerImpl.hpp" - -namespace Svc { - - typedef ActiveLoggerImpl ActiveLogger; - -} - -#endif diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp deleted file mode 100644 index 3be0b42bcd8..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * TestCommand1Impl.cpp - * - * Created on: Mar 28, 2014 - * Author: tcanham - */ - -#include - -#include -#include -#include - -namespace Svc { - static_assert(std::numeric_limits::max() >= TELEM_ID_FILTER_SIZE, "TELEM_ID_FILTER_SIZE must fit within range of FwSizeType"); - typedef ActiveLogger_Enabled Enabled; - typedef ActiveLogger_FilterSeverity FilterSeverity; - - ActiveLoggerImpl::ActiveLoggerImpl(const char* name) : - ActiveLoggerComponentBase(name) - { - // set filter defaults - this->m_filterState[FilterSeverity::WARNING_HI].enabled = - FILTER_WARNING_HI_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; - this->m_filterState[FilterSeverity::WARNING_LO].enabled = - FILTER_WARNING_LO_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; - this->m_filterState[FilterSeverity::COMMAND].enabled = - FILTER_COMMAND_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; - this->m_filterState[FilterSeverity::ACTIVITY_HI].enabled = - FILTER_ACTIVITY_HI_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; - this->m_filterState[FilterSeverity::ACTIVITY_LO].enabled = - FILTER_ACTIVITY_LO_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; - this->m_filterState[FilterSeverity::DIAGNOSTIC].enabled = - FILTER_DIAGNOSTIC_DEFAULT?Enabled::ENABLED:Enabled::DISABLED; - - memset(m_filteredIDs,0,sizeof(m_filteredIDs)); - - } - - ActiveLoggerImpl::~ActiveLoggerImpl() { - } - - void ActiveLoggerImpl::LogRecv_handler(FwIndexType portNum, FwEventIdType id, Fw::Time &timeTag, const Fw::LogSeverity& severity, Fw::LogBuffer &args) { - - // make sure ID is not zero. Zero is reserved for ID filter. - FW_ASSERT(id != 0); - - switch (severity.e) { - case Fw::LogSeverity::FATAL: // always pass FATAL - break; - case Fw::LogSeverity::WARNING_HI: - if (this->m_filterState[FilterSeverity::WARNING_HI].enabled == Enabled::DISABLED) { - return; - } - break; - case Fw::LogSeverity::WARNING_LO: - if (this->m_filterState[FilterSeverity::WARNING_LO].enabled == Enabled::DISABLED) { - return; - } - break; - case Fw::LogSeverity::COMMAND: - if (this->m_filterState[FilterSeverity::COMMAND].enabled == Enabled::DISABLED) { - return; - } - break; - case Fw::LogSeverity::ACTIVITY_HI: - if (this->m_filterState[FilterSeverity::ACTIVITY_HI].enabled == Enabled::DISABLED) { - return; - } - break; - case Fw::LogSeverity::ACTIVITY_LO: - if (this->m_filterState[FilterSeverity::ACTIVITY_LO].enabled == Enabled::DISABLED) { - return; - } - break; - case Fw::LogSeverity::DIAGNOSTIC: - if (this->m_filterState[FilterSeverity::DIAGNOSTIC].enabled == Enabled::DISABLED) { - return; - } - break; - default: - FW_ASSERT(0,static_cast(severity.e)); - return; - } - - // check ID filters - for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { - if ( - (m_filteredIDs[entry] == id) && - (severity != Fw::LogSeverity::FATAL) - ) { - return; - } - } - - // send event to the logger thread - this->loqQueue_internalInterfaceInvoke(id,timeTag,severity,args); - - // if connected, announce the FATAL - if (Fw::LogSeverity::FATAL == severity.e) { - if (this->isConnected_FatalAnnounce_OutputPort(0)) { - this->FatalAnnounce_out(0,id); - } - } - } - - void ActiveLoggerImpl::loqQueue_internalInterfaceHandler(FwEventIdType id, const Fw::Time &timeTag, const Fw::LogSeverity& severity, const Fw::LogBuffer &args) { - - // Serialize event - this->m_logPacket.setId(id); - this->m_logPacket.setTimeTag(timeTag); - this->m_logPacket.setLogBuffer(args); - this->m_comBuffer.resetSer(); - Fw::SerializeStatus stat = this->m_logPacket.serialize(this->m_comBuffer); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); - - if (this->isConnected_PktSend_OutputPort(0)) { - this->PktSend_out(0, this->m_comBuffer,0); - } - } - - void ActiveLoggerImpl::SET_EVENT_FILTER_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, FilterSeverity filterLevel, Enabled filterEnable) { - this->m_filterState[filterLevel.e].enabled = filterEnable; - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void ActiveLoggerImpl::SET_ID_FILTER_cmdHandler( - FwOpcodeType opCode, //!< The opcode - U32 cmdSeq, //!< The command sequence number - U32 ID, - Enabled idEnabled //!< ID filter state - ) { - - if (Enabled::ENABLED == idEnabled.e) { // add ID - // search list for existing entry - for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { - if (this->m_filteredIDs[entry] == ID) { - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - this->log_ACTIVITY_HI_ID_FILTER_ENABLED(ID); - return; - } - } - // if not already a match, search for an open slot - for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { - if (this->m_filteredIDs[entry] == 0) { - this->m_filteredIDs[entry] = ID; - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - this->log_ACTIVITY_HI_ID_FILTER_ENABLED(ID); - return; - } - } - // if an empty slot was not found, send an error event - this->log_WARNING_LO_ID_FILTER_LIST_FULL(ID); - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::EXECUTION_ERROR); - } else { // remove ID - // search list for existing entry - for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { - if (this->m_filteredIDs[entry] == ID) { - this->m_filteredIDs[entry] = 0; // zero entry - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - this->log_ACTIVITY_HI_ID_FILTER_REMOVED(ID); - return; - } - } - // if it gets here, wasn't found - this->log_WARNING_LO_ID_FILTER_NOT_FOUND(ID); - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::EXECUTION_ERROR); - } - - } - - void ActiveLoggerImpl::DUMP_FILTER_STATE_cmdHandler( - FwOpcodeType opCode, //!< The opcode - U32 cmdSeq //!< The command sequence number - ) { - - // first, iterate through severity filters - for (FwEnumStoreType filter = 0; filter < FilterSeverity::NUM_CONSTANTS; filter++) { - FilterSeverity filterState(static_cast(filter)); - this->log_ACTIVITY_LO_SEVERITY_FILTER_STATE( - filterState, - Enabled::ENABLED == this->m_filterState[filter].enabled.e - ); - } - - // iterate through ID filter - for (FwSizeType entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { - if (this->m_filteredIDs[entry] != 0) { - this->log_ACTIVITY_HI_ID_FILTER_ENABLED(this->m_filteredIDs[entry]); - } - } - - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void ActiveLoggerImpl::pingIn_handler( - const FwIndexType portNum, - U32 key - ) - { - // return key - this->pingOut_out(0,key); - } - -} // namespace Svc diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp b/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp deleted file mode 100644 index 140933275d7..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/ActiveLoggerImpl.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ActiveLoggerImpl.hpp - * - * Created on: Mar 28, 2014 - * Author: tcanham - */ - -#ifndef ACTIVELOGGERIMPL_HPP_ -#define ACTIVELOGGERIMPL_HPP_ - -#include -#include -#include - -namespace Svc { - - class ActiveLoggerImpl final : public ActiveLoggerComponentBase { - public: - ActiveLoggerImpl(const char* compName); //!< constructor - virtual ~ActiveLoggerImpl(); //!< destructor - PROTECTED: - PRIVATE: - void LogRecv_handler(FwIndexType portNum, FwEventIdType id, Fw::Time &timeTag, const Fw::LogSeverity& severity, Fw::LogBuffer &args); - void loqQueue_internalInterfaceHandler(FwEventIdType id, const Fw::Time &timeTag, const Fw::LogSeverity& severity, const Fw::LogBuffer &args); - - void SET_EVENT_FILTER_cmdHandler( - FwOpcodeType opCode, - U32 cmdSeq, - ActiveLogger_FilterSeverity filterLevel, - ActiveLogger_Enabled filterEnabled); - - void SET_ID_FILTER_cmdHandler( - FwOpcodeType opCode, //!< The opcode - U32 cmdSeq, //!< The command sequence number - U32 ID, - ActiveLogger_Enabled idFilterEnabled //!< ID filter state - ); - - void DUMP_FILTER_STATE_cmdHandler( - FwOpcodeType opCode, //!< The opcode - U32 cmdSeq //!< The command sequence number - ); - - //! Handler implementation for pingIn - //! - void pingIn_handler( - const FwIndexType portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ); - - // Filter state - struct t_filterState { - ActiveLogger_Enabled enabled; //~ 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

rg+27P{||%OV*kXNLp@Iic}+lpiuK zbsh1j#1=K;Qfemq7-!b&Iz{H7pQsIqd`&Rl$G5T;E2bt`Mj!7ZerFPcLohx2=Ra4c z`#tRb@#!CG)u|}_74X-BSAPZ^KX;QqmA`sv_}8*Oe>Nn0mM8h|MSxy%Ue%+% z#rbpPmzTyb3t9X&o<{m*{IaaYOTbGl@!x>>=Rx$}b!Yy6%Hl79FBQ3e12dmTmH!I- zt>JrrRmEGiz3li~2MZ~qS-OEmic diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Design.xlsx b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Design.xlsx deleted file mode 100644 index e41db23076f23d532645a64d34a219f9f7a08bdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24983 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 diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Unit_Test.xls b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/Checklist_Unit_Test.xls deleted file mode 100644 index 2076b23a47591c0d5124e8643cac5e1b5107d56b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51200 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%0Dt_5!72&2h|18X7UIZN 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 z zlC6=|Tv~)NC}aMBQJ2zVu^yctRskrHwdMRbKnx0e6vyE*Xh_*XWSm9%1^|w6A=9br zjz^}sr+J|tynf)(EX3?cJ8DkXdvU`~bKxO82BFv|mH|hoyIcc&Xyw-{G#4!AhsPL4 zMuav1&>BQMgNDN`%mPhhn$}CNsocqK1YXeR#=^b{i!V2rH3U+19z4H}{#3GVN9p_> zL#y1c9cI0^%+TFNaOkDUQhDuA7aTk?a^Nm_B#U<0v zPB+P~KODIC2-Hv+P_R3#+x_a;Fe9C?5*jUH_Ec>9{z{}pqgMsw$=siR=FlB)O!aC; zOIq7Bbpn9mK6fEp8|$->z&*2logA4qpOYnb58ud&H zMnm6GQOm`Sg4D~@F7&3dYjEhO34Ozqn(*Z+(1WX~8#B)iJXja$4P#(oGC+nf5Ga<7 z5K1&qd;%L830y;Q}R`e);{i2Y_rQ{<2Yk$QOQd`yldxBuytxSKf+O zZq0V5&eV>c%jz48RdF|sWtgRvnq7@ib_&V!(d!xMC~$f1lvJwc)7+-}mU`+t0JL|t z{N7~VSTT-@4kgC{U<DL}+f28RA)UVu#}*WEJ~O=`67#`KPqH zY8OeZ3{%hW!-UbP$&nE&6Qc^Zc_xVDnEK69^XF92fB4)FSAi&Yd>-gAOsd6Rlaz#W zd*A^G#b>;Iqjlo#3nk@SsK9;>9@qa}%4(-!1)Xhdb~Ig@YGT{WzoFt%@n&bN6_IoB)| zolSrDbpJi7>mtCV>n3gjgg5Zq$A((0eY?Oq27IkKrtNU`9m3uxia|`V9Rx7Jc;UXC z4<=IDZ=B{dMDBZYNc55G3;Usg{>bQw zYDoA^)ZKh&hgwa{6oCkfAO{3u7y>Sy>ggAgYMy080a2eH~G0!xEj6Kh_p6XY(#DpFE%2h9D&8kKaaZqy%G7( zhx&B*s81K?)06Y*wfg1!@@Z1|G%0*qPW~TXYu)n*CnRKKU}_3$HBC>fB0$d`5*cEo z%1{H?x4_q#+mL`0S21VsHvQyHyog~|8e@{wwPD&x(nJk38}+E|r($o^bS6m*oFBx_ fZ%La*HC{edn?5K1+Yuwbh7)}n|L?hOA4mQVpe8QH diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/WriteEventBuffer.jpg b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/img/WriteEventBuffer.jpg deleted file mode 100644 index 67678a5e2a0d35cefa42efa99a7964bd3b123a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38763 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 LKmPYJUwi)-Wbo_S diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md b/Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md deleted file mode 100644 index e93416293d7..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/docs/sdd.md +++ /dev/null @@ -1,117 +0,0 @@ -# Svc::ActiveLogger Component - -## 1. Introduction - -The `Svc::ActiveLogger` component processes events from other components. The events are put in packets and sent to an -external component like the ground interface. The component provides event filtering capability such that events may -be turned off via ID or severity. - -## 2. Requirements - -The requirements for `Svc::ActiveLogger` are as follows: - -Requirement | Description | Verification Method ------------ | ----------- | ------------------- -AL-001 | The `Svc::ActiveLogger` component shall receive events and compose them into downlink packets. | Inspection; Unit Test -AL-002 | The `Svc::ActiveLogger` component shall have commands to filter events based on event severity. | Unit Test -AL-003 | The `Svc::ActiveLogger` component shall have commands to filter events based on the event ID. | Unit Test -AL-004 | The `Svc::ActiveLogger` component shall call fatalOut port when FATAL is received | Inspection; Unit Test - -## 3. Design - -### 3.1 Context - -#### 3.1.1 Component Diagram - -The `Svc::ActiveLogger` component has the following component diagram: - -![`Svc::ActiveLogger` Diagram](img/ActiveLoggerBDD.jpg "Svc::ActiveLogger") - -#### 3.1.2 Ports - -The `Svc::ActiveLogger` component uses the following port types: - -Port Data Type | Name | Direction | Kind | Usage --------------- | ---- | --------- | ---- | ----- -[`Fw::Log`](../../../Fw/Log/docs/sdd.md) | LogRecv | Input | Synchronous | Receive events from components -[`Fw::Com`](../../../Fw/Log/docs/sdd.md) | PktSend | Output | n/a | Send event packets to external user -[`Svc::FatalEvent`](../../../Svc/Fatal/docs/sdd.md) | FatalAnnounce | Output | n/a | Send FATAL event (to health) - -### 3.2 Functional Description - -The `Svc::ActiveLogger` component provides an event logging function for the software. The framework autocoder allows -developers to specify a set of events in the component XML -(see [Events](../../../docs/user-manual/overview/04-cmd-evt-chn-prm.md). For these components, the -autocoder will add an `Fw::Log` output port to send events in serialized form. The ActiveLogger receives these port -calls and provides commands to filter these events. The filtered events are sent to other components such as the ground -interface. - -**Note:** the Event ID value 0 is reserved for the logger. - -Should a FATAL severity event arrive, it is announced using a FATAL out port allow the system to respond when a FATAL -event is seen. - -#### 3.2.1 Filtering - -The `Svc::ActiveLogger` `LogRecv` input port handler filters events to lessen the load on the downstream components. The -filters can be set by severity and ID. By default, the DIAGNOSTIC events are filtered out since the number of DIAGNOSTIC -events can be quite high. All defaults can be globally configured in `config/ActiveLoggerImplCfg.hpp`. Filters are -modified at runtime by the `SET_EVENT_FILTER` command. - -The component also allows filtering events by event ID. There is a configuration parameter that sets the number of IDs -that can be filtered. This allows operators to mute a particular event that might be flooding the downstream components. -These filters are modified at runtime by the `SET_ID_FILTER` command. - -FATAL events are never filtered, so they can be caught and broadcast to the system. Outgoing events are converted into -the F´ ground format and sent out using the `PktSend` port. - - - -#### 3.2.2 Fatal Announce - -When the `ActiveLogger` component receives a FATAL event, it calls the FatalAnnounce port. Another component that -handles the system response to FATALs (such as resetting the system) can connect to this port to be informed when a -FATAL has occurred. - -### 3.3 Scenarios - -#### 3.3.1 Receive Events - -The `Svc::ActiveLogger` component accepts events from other components. - -### 3.4 State - -`Svc::ActiveLogger` has no state machines, but stores the state of the event severity and event ID filters. - -### 3.5 Algorithms - -`Svc::ActiveLogger` has no significant algorithms. - -## 4. Dictionaries - -TBD - -## 5. Module Checklists - -Checklist | --------- | -[Design](Checklist_Design.xlsx) | -[Code](Checklist_Code.xlsx) | -[Unit Test](Checklist_Unit_Test.xls) | - -## 6. Unit Testing - -To see unit test coverage run fprime-util check --coverage - -## 7. Change Log - -Date | Description ----- | ----------- -6/25/2015 | Design review edits -7/22/2015 | Design review actions -9/7/2015 | Unit Test updates -10/28/2015 | Added FATAL announce port -12/1/2020 | Removed event buffers and post-filter - - - diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore deleted file mode 100644 index f8f1e57a822..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dump.dat diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp deleted file mode 100644 index 513b88f4a3d..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp +++ /dev/null @@ -1,625 +0,0 @@ -/* - * ActiveLoggerImplTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include -#include -#include -#include - -#include - -namespace Svc { - - typedef ActiveLogger_Enabled Enabled; - typedef ActiveLogger_FilterSeverity FilterSeverity; - - ActiveLoggerImplTester::ActiveLoggerImplTester(Svc::ActiveLoggerImpl& inst) : - Svc::ActiveLoggerGTestBase("testerbase",100), - m_impl(inst), - m_receivedPacket(false), - m_receivedFatalEvent(false) { - } - - ActiveLoggerImplTester::~ActiveLoggerImplTester() { - } - - void ActiveLoggerImplTester::from_PktSend_handler( - const FwIndexType portNum, //!< The port number - Fw::ComBuffer &data, //!< Buffer containing packet data - U32 context //!< context; not used - ) { - this->m_sentPacket = data; - this->m_receivedPacket = true; - } - - void ActiveLoggerImplTester::from_FatalAnnounce_handler( - const FwIndexType portNum, //!< The port number - FwEventIdType Id //!< The ID of the FATAL event - ) { - this->m_receivedFatalEvent = true; - this->m_fatalID = Id; - } - - void ActiveLoggerImplTester::runEventNominal() { - REQUIREMENT("AL-001"); - - this->writeEvent(29,Fw::LogSeverity::WARNING_HI,10); - } - - void ActiveLoggerImplTester::runWithFilters(Fw::LogSeverity filter) { - - REQUIREMENT("AL-002"); - - Fw::LogBuffer buff; - U32 val = 10; - FwEventIdType id = 29; - - Fw::SerializeStatus stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - Fw::Time timeTag(TB_NONE,0,0); - U32 cmdSeq = 21; - - // enable report filter - this->clearHistory(); - FilterSeverity reportFilterLevel = FilterSeverity::WARNING_HI; - - switch (filter.e) { - case Fw::LogSeverity::WARNING_HI: - reportFilterLevel = FilterSeverity::WARNING_HI; - break; - case Fw::LogSeverity::WARNING_LO: - reportFilterLevel = FilterSeverity::WARNING_LO; - break; - case Fw::LogSeverity::COMMAND: - reportFilterLevel = FilterSeverity::COMMAND; - break; - case Fw::LogSeverity::ACTIVITY_HI: - reportFilterLevel = FilterSeverity::ACTIVITY_HI; - break; - case Fw::LogSeverity::ACTIVITY_LO: - reportFilterLevel = FilterSeverity::ACTIVITY_LO; - break; - case Fw::LogSeverity::DIAGNOSTIC: - reportFilterLevel = FilterSeverity::DIAGNOSTIC; - break; - default: - ASSERT_TRUE(false); - break; - } - - this->clearHistory(); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,Enabled::ENABLED); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, - cmdSeq, - Fw::CmdResponse::OK - ); - - this->m_receivedPacket = false; - - this->invoke_to_LogRecv(0,id,timeTag,filter,buff); - - // should not have received packet - ASSERT_FALSE(this->m_receivedPacket); - // dispatch message - this->m_impl.doDispatch(); - // should have received packet - ASSERT_TRUE(this->m_receivedPacket); - // verify contents - // first piece should be log packet descriptor - FwPacketDescriptorType desc; - stat = this->m_sentPacket.deserialize(desc); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); - // next piece should be event ID - FwEventIdType sentId; - stat = this->m_sentPacket.deserialize(sentId); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(sentId,id); - // next piece is time tag - Fw::Time recTimeTag(TB_NONE,0,0); - stat = this->m_sentPacket.deserialize(recTimeTag); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_TRUE(timeTag == recTimeTag); - // next piece is event argument - U32 readVal; - stat = this->m_sentPacket.deserialize(readVal); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(readVal, val); - // packet should be empty - ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); - - // Disable severity filter - this->clearHistory(); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,Enabled::DISABLED); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, - cmdSeq, - Fw::CmdResponse::OK - ); - - this->m_receivedPacket = false; - - this->invoke_to_LogRecv(0,id,timeTag,filter,buff); - - // should not have received packet - all we can check since no message is dispatched. - ASSERT_FALSE(this->m_receivedPacket); - } - - void ActiveLoggerImplTester::runFilterInvalidCommands() { - - U32 cmdSeq = 21; - this->clearHistory(); - FilterSeverity reportFilterLevel = FilterSeverity::WARNING_HI; - Enabled filterEnabled(static_cast(10)); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,filterEnabled); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, - cmdSeq, - Fw::CmdResponse::FORMAT_ERROR - ); - this->clearHistory(); - reportFilterLevel = FilterSeverity::WARNING_HI; - filterEnabled.e = static_cast(-2); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,reportFilterLevel,filterEnabled); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, - cmdSeq, - Fw::CmdResponse::FORMAT_ERROR - ); - FilterSeverity eventLevel; - this->clearHistory(); - Enabled reportEnable = Enabled::ENABLED; - eventLevel.e = static_cast(-1); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,eventLevel,reportEnable); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, - cmdSeq, - Fw::CmdResponse::FORMAT_ERROR - ); - - this->clearHistory(); - - reportEnable = Enabled::ENABLED; - eventLevel.e = static_cast(100); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,eventLevel,reportEnable); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, - cmdSeq, - Fw::CmdResponse::FORMAT_ERROR - ); - - } - - void ActiveLoggerImplTester::runFilterEventNominal() { - - for (Fw::LogSeverity::t sev = Fw::LogSeverity::WARNING_HI; sev <= Fw::LogSeverity::DIAGNOSTIC; sev = static_cast(sev + 1)) { - this->runWithFilters(sev); - } - - } - - void ActiveLoggerImplTester::runFilterIdNominal() { - - U32 cmdSeq = 21; - - // for a set of IDs, fill filter - - REQUIREMENT("AL-003"); - - for (FwSizeType filterID = 1; filterID <= TELEM_ID_FILTER_SIZE; filterID++) { - this->clearHistory(); - this->clearEvents(); - this->sendCmd_SET_ID_FILTER(0,cmdSeq,filterID,Enabled::ENABLED); - // dispatch message - this->m_impl.doDispatch(); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_ID_FILTER, - cmdSeq, - Fw::CmdResponse::OK - ); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_ID_FILTER_ENABLED_SIZE(1); - ASSERT_EVENTS_ID_FILTER_ENABLED(0,filterID); - // send it again, to verify it will accept a second add - this->clearHistory(); - this->clearEvents(); - this->sendCmd_SET_ID_FILTER(0,cmdSeq,filterID,Enabled::ENABLED); - // dispatch message - this->m_impl.doDispatch(); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_ID_FILTER, - cmdSeq, - Fw::CmdResponse::OK - ); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_ID_FILTER_ENABLED_SIZE(1); - ASSERT_EVENTS_ID_FILTER_ENABLED(0,filterID); - - } - - // Try to send the IDs that are filtered - for (FwSizeType filterID = 1; filterID <= TELEM_ID_FILTER_SIZE; filterID++) { - this->clearHistory(); - this->clearEvents(); - - Fw::LogBuffer buff; - U32 val = 10; - FwEventIdType id = filterID; - - Fw::SerializeStatus stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - Fw::Time timeTag(TB_NONE,0,0); - - this->m_receivedPacket = false; - - this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::ACTIVITY_HI,buff); - - // should not get a packet - ASSERT_FALSE(this->m_receivedPacket); - - } - - // send one of the IDs as a FATAL, it should not be filtered event thought the ID is in the filter - this->clearHistory(); - this->clearEvents(); - - Fw::LogBuffer buff; - U32 val = 10; - FwEventIdType id = 1; - - Fw::SerializeStatus stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - Fw::Time timeTag(TB_NONE,0,0); - - this->m_receivedPacket = false; - - this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::FATAL,buff); - this->m_impl.doDispatch(); - - // should get a packet anyway - ASSERT_TRUE(this->m_receivedPacket); - - // Try to add to the full filter. It should be rejected - this->clearHistory(); - this->clearEvents(); - this->sendCmd_SET_ID_FILTER(0,cmdSeq,TELEM_ID_FILTER_SIZE+1,Enabled::ENABLED); - // dispatch message - this->m_impl.doDispatch(); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_ID_FILTER, - cmdSeq, - Fw::CmdResponse::EXECUTION_ERROR - ); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_ID_FILTER_LIST_FULL_SIZE(1); - ASSERT_EVENTS_ID_FILTER_LIST_FULL(0,TELEM_ID_FILTER_SIZE+1); - - // Now clear them - - for (FwSizeType filterID = 1; filterID <= TELEM_ID_FILTER_SIZE; filterID++) { - this->clearHistory(); - this->clearEvents(); - this->sendCmd_SET_ID_FILTER(0,cmdSeq,filterID,Enabled::DISABLED); - // dispatch message - this->m_impl.doDispatch(); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_ID_FILTER, - cmdSeq, - Fw::CmdResponse::OK - ); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_ID_FILTER_REMOVED_SIZE(1); - ASSERT_EVENTS_ID_FILTER_REMOVED(0,filterID); - } - - // Try to clear one that doesn't exist - - this->clearHistory(); - this->clearEvents(); - this->sendCmd_SET_ID_FILTER(0,cmdSeq,10,Enabled::DISABLED); - // dispatch message - this->m_impl.doDispatch(); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_ID_FILTER, - cmdSeq, - Fw::CmdResponse::EXECUTION_ERROR - ); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_ID_FILTER_NOT_FOUND_SIZE(1); - ASSERT_EVENTS_ID_FILTER_NOT_FOUND(0,10); - - // Send an invalid argument - this->clearHistory(); - this->clearEvents(); - Enabled idEnabled(static_cast(10)); - this->sendCmd_SET_ID_FILTER(0,cmdSeq,10,idEnabled); - // dispatch message - this->m_impl.doDispatch(); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_ID_FILTER, - cmdSeq, - Fw::CmdResponse::FORMAT_ERROR - ); - ASSERT_EVENTS_SIZE(0); - - } - - void ActiveLoggerImplTester::runFilterDump() { - U32 cmdSeq = 21; - // set random set of filters - - this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::WARNING_HI,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::WARNING_LO,Enabled::DISABLED); - this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::COMMAND,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::ACTIVITY_HI,Enabled::DISABLED); - this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::ACTIVITY_LO,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,0,FilterSeverity::DIAGNOSTIC,Enabled::ENABLED); - - this->sendCmd_SET_ID_FILTER(0,cmdSeq,4,Enabled::ENABLED); - // dispatch message - this->m_impl.doDispatch(); - - this->sendCmd_SET_ID_FILTER(0,cmdSeq,13,Enabled::ENABLED); - // dispatch message - this->m_impl.doDispatch(); - - this->sendCmd_SET_ID_FILTER(0,cmdSeq,4000,Enabled::ENABLED); - // dispatch message - this->m_impl.doDispatch(); - - // send command to dump the filters - - this->clearHistory(); - this->clearEvents(); - this->sendCmd_DUMP_FILTER_STATE(0,cmdSeq); - // dispatch message - this->m_impl.doDispatch(); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_DUMP_FILTER_STATE, - cmdSeq, - Fw::CmdResponse::OK - ); - ASSERT_EVENTS_SIZE(6+3); - ASSERT_EVENTS_SEVERITY_FILTER_STATE_SIZE(6); - ASSERT_EVENTS_SEVERITY_FILTER_STATE(0,FilterSeverity::WARNING_HI,true); - ASSERT_EVENTS_SEVERITY_FILTER_STATE(1,FilterSeverity::WARNING_LO,false); - ASSERT_EVENTS_SEVERITY_FILTER_STATE(2,FilterSeverity::COMMAND,true); - ASSERT_EVENTS_SEVERITY_FILTER_STATE(3,FilterSeverity::ACTIVITY_HI,false); - ASSERT_EVENTS_SEVERITY_FILTER_STATE(4,FilterSeverity::ACTIVITY_LO,true); - ASSERT_EVENTS_SEVERITY_FILTER_STATE(5,FilterSeverity::DIAGNOSTIC,true); - } - - void ActiveLoggerImplTester::runEventFatal() { - Fw::LogBuffer buff; - U32 val = 10; - FwEventIdType id = 29; - U32 cmdSeq = 21; - REQUIREMENT("AL-004"); - - Fw::SerializeStatus stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - Fw::Time timeTag(TB_NONE,0,0); - - this->m_receivedPacket = false; - - this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::FATAL,buff); - - // should not have received packet - ASSERT_FALSE(this->m_receivedPacket); - // should have seen event port - ASSERT_TRUE(this->m_receivedFatalEvent); - ASSERT_EQ(this->m_fatalID,id); - // dispatch message - this->m_impl.doDispatch(); - // should have received packet - ASSERT_TRUE(this->m_receivedPacket); - // verify contents - // first piece should be log packet descriptor - FwPacketDescriptorType desc; - stat = this->m_sentPacket.deserialize(desc); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); - // next piece should be event ID - FwEventIdType sentId; - stat = this->m_sentPacket.deserialize(sentId); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(sentId,id); - // next piece is time tag - Fw::Time recTimeTag(TB_NONE,0,0); - stat = this->m_sentPacket.deserialize(recTimeTag); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_TRUE(timeTag == recTimeTag); - // next piece is event argument - U32 readVal; - stat = this->m_sentPacket.deserialize(readVal); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(readVal, val); - // packet should be empty - ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); - // Turn on all filters and make sure FATAL still gets through - - this->clearHistory(); - this->clearEvents(); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_HI,Enabled::DISABLED); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE( - 0, - ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, - cmdSeq, - Fw::CmdResponse::OK - ); - - - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_LO,Enabled::DISABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::COMMAND,Enabled::DISABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_HI,Enabled::DISABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_LO,Enabled::DISABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::DIAGNOSTIC,Enabled::DISABLED); - - this->m_receivedPacket = false; - - this->invoke_to_LogRecv(0,id,timeTag,Fw::LogSeverity::FATAL,buff); - - // should not have received packet - ASSERT_FALSE(this->m_receivedPacket); - // dispatch message - this->m_impl.doDispatch(); - // should have received packet - ASSERT_TRUE(this->m_receivedPacket); - // verify contents - // first piece should be log packet descriptor - stat = this->m_sentPacket.deserialize(desc); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); - // next piece should be event ID - stat = this->m_sentPacket.deserialize(sentId); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(sentId,id); - // next piece is time tag - stat = this->m_sentPacket.deserialize(recTimeTag); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_TRUE(timeTag == recTimeTag); - // next piece is event argument - stat = this->m_sentPacket.deserialize(readVal); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(readVal, val); - // packet should be empty - ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); - - // turn off filters - - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_HI,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::WARNING_LO,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::COMMAND,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_HI,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::ACTIVITY_LO,Enabled::ENABLED); - this->sendCmd_SET_EVENT_FILTER(0,cmdSeq,FilterSeverity::DIAGNOSTIC,Enabled::ENABLED); - - } - - void ActiveLoggerImplTester::writeEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value) { - Fw::LogBuffer buff; - - Fw::SerializeStatus stat = buff.serialize(value); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - Fw::Time timeTag(TB_NONE,1,2); - - this->m_receivedPacket = false; - - this->invoke_to_LogRecv(0,id,timeTag,severity,buff); - - // should not have received packet - ASSERT_FALSE(this->m_receivedPacket); - // dispatch message - this->m_impl.doDispatch(); - // should have received packet - ASSERT_TRUE(this->m_receivedPacket); - // verify contents - // first piece should be log packet descriptor - FwPacketDescriptorType desc; - stat = this->m_sentPacket.deserialize(desc); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(desc,static_cast(Fw::ComPacket::FW_PACKET_LOG)); - // next piece should be event ID - FwEventIdType sentId; - stat = this->m_sentPacket.deserialize(sentId); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(sentId,id); - // next piece is time tag - Fw::Time recTimeTag(TB_NONE,1,2); - stat = this->m_sentPacket.deserialize(recTimeTag); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_TRUE(timeTag == recTimeTag); - // next piece is event argument - U32 readVal; - stat = this->m_sentPacket.deserialize(readVal); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(readVal, value); - // packet should be empty - ASSERT_EQ(this->m_sentPacket.getBuffLeft(),0u); - - } - - void ActiveLoggerImplTester::readEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value, Os::File& file) { - static const BYTE delimiter = 0xA5; - - // first read should be delimiter - BYTE de; - FwSizeType readSize = static_cast(sizeof(de)); - - ASSERT_EQ(file.read(&de,readSize,Os::File::WaitType::WAIT),Os::File::OP_OK); - ASSERT_EQ(delimiter,de); - // next is LogPacket - Fw::ComBuffer comBuff; - // size is specific to this test - readSize = sizeof(FwPacketDescriptorType) + sizeof(FwEventIdType) + Fw::Time::SERIALIZED_SIZE + sizeof(U32); - ASSERT_EQ(file.read(comBuff.getBuffAddr(),readSize,Os::File::WaitType::WAIT),Os::File::OP_OK); - comBuff.setBuffLen(readSize); - - // deserialize LogPacket - Fw::LogPacket packet; - Fw::Time time(TB_NONE,1,2); - Fw::LogBuffer logBuff; - ASSERT_EQ(comBuff.deserialize(packet),Fw::FW_SERIALIZE_OK); - - // read back values - ASSERT_EQ(id,packet.getId()); - ASSERT_EQ(time,packet.getTimeTag()); - logBuff = packet.getLogBuffer(); - U32 readValue; - ASSERT_EQ(logBuff.deserialize(readValue),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(value,readValue); - - } - - void ActiveLoggerImplTester::textLogIn(const FwEventIdType id, //!< The event ID - const Fw::Time& timeTag, //!< The time - const Fw::LogSeverity severity, //!< The severity - const Fw::TextLogString& text //!< The event string - ) { - TextLogEntry e = { id, timeTag, severity, text }; - - printTextLogHistoryEntry(e, stdout); - } - void ActiveLoggerImplTester :: - from_pingOut_handler( - const FwIndexType portNum, - U32 key - ) - { - this->pushFromPortEntry_pingOut(key); - } -} /* namespace SvcTest */ diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp deleted file mode 100644 index 55fadd8d0e3..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerImplTester.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ActiveLoggerImplTester.hpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#ifndef ACTIVELOGGER_TEST_UT_ACTIVELOGGERIMPLTESTER_HPP_ -#define ACTIVELOGGER_TEST_UT_ACTIVELOGGERIMPLTESTER_HPP_ - -#include -#include -#include - -namespace Svc { - - class ActiveLoggerImplTester: public Svc::ActiveLoggerGTestBase { - public: - ActiveLoggerImplTester(Svc::ActiveLoggerImpl& inst); - virtual ~ActiveLoggerImplTester(); - - void runEventNominal(); - void runFilterEventNominal(); - void runFilterIdNominal(); - void runFilterDump(); - void runFilterInvalidCommands(); - void runEventFatal(); - void runFileDump(); - void runFileDumpErrors(); - - private: - - void from_PktSend_handler( - const FwIndexType portNum, //!< The port number - Fw::ComBuffer &data, //!< Buffer containing packet data - U32 context //!< context (not used) - ) override; - void from_FatalAnnounce_handler( - const FwIndexType portNum, //!< The port number - FwEventIdType Id //!< The ID of the FATAL event - ) override; - - Svc::ActiveLoggerImpl& m_impl; - - bool m_receivedPacket; - Fw::ComBuffer m_sentPacket; - - bool m_receivedFatalEvent; - FwEventIdType m_fatalID; - - void runWithFilters(Fw::LogSeverity filter); - - void writeEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value); - void readEvent(FwEventIdType id, Fw::LogSeverity severity, U32 value, Os::File& file); - - // enumeration to tell what kind of error to inject - typedef enum { - FILE_WRITE_WRITE_ERROR, // return a bad read status - FILE_WRITE_SIZE_ERROR, // return a bad size - } FileWriteTestType; - FileWriteTestType m_writeTestType; - FwSizeType m_writeSize; - - void textLogIn(const FwEventIdType id, //!< The event ID - const Fw::Time& timeTag, //!< The time - const Fw::LogSeverity severity, //!< The severity - const Fw::TextLogString& text //!< The event string - ) override; - - //! Handler for from_pingOut - //! - void from_pingOut_handler( - const FwIndexType portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ) override; - }; - -} /* namespace Svc */ - -#endif /* ACTIVELOGGER_TEST_UT_ACTIVELOGGERIMPLTESTER_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp deleted file mode 100644 index 013eecf59f9..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/ActiveLoggerTester.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * PrmDbTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include -#include - -#include - -#if FW_OBJECT_REGISTRATION == 1 -static Fw::SimpleObjRegistry simpleReg; -#endif - -void connectPorts(Svc::ActiveLoggerImpl& impl, Svc::ActiveLoggerImplTester& tester) { - - tester.connect_to_CmdDisp(0,impl.get_CmdDisp_InputPort(0)); - impl.set_CmdStatus_OutputPort(0,tester.get_from_CmdStatus(0)); - impl.set_FatalAnnounce_OutputPort(0,tester.get_from_FatalAnnounce(0)); - - tester.connect_to_LogRecv(0,impl.get_LogRecv_InputPort(0)); - - impl.set_Log_OutputPort(0,tester.get_from_Log(0)); - impl.set_LogText_OutputPort(0,tester.get_from_LogText(0)); - - impl.set_PktSend_OutputPort(0,tester.get_from_PktSend(0)); - -#if FW_PORT_TRACING - // Fw::PortBase::setTrace(true); -#endif - - // simpleReg.dump(); -} - -TEST(ActiveLoggerTest,NominalEventSend) { - - TEST_CASE(100.1.1,"Nominal Event Logging"); - - Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); - - impl.init(10,0); - - Svc::ActiveLoggerImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runEventNominal(); - -} - -TEST(ActiveLoggerTest,FilteredEventSend) { - - TEST_CASE(100.1.2,"Nominal Event Filtering"); - - Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); - - impl.init(10,0); - - Svc::ActiveLoggerImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runFilterEventNominal(); - -} - -TEST(ActiveLoggerTest,FilterIdTest) { - - TEST_CASE(100.1.3,"Filter events by ID"); - - Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); - - impl.init(10,0); - - Svc::ActiveLoggerImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runFilterIdNominal(); - -} - -TEST(ActiveLoggerTest,FilterDumpTest) { - - TEST_CASE(100.1.3,"Dump filter values"); - - Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); - - impl.init(10,0); - - Svc::ActiveLoggerImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runFilterDump(); - -} - -TEST(ActiveLoggerTest,InvalidCommands) { - - TEST_CASE(100.2.1,"Off-Nominal Invalid Commands"); - - Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); - - impl.init(10,0); - - Svc::ActiveLoggerImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runFilterInvalidCommands(); - -} - -TEST(ActiveLoggerTest,FatalTesting) { - - TEST_CASE(100.2.2,"Off-Nominal FATAL processing"); - - Svc::ActiveLoggerImpl impl("ActiveLoggerImpl"); - - impl.init(10,0); - - Svc::ActiveLoggerImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runEventFatal(); - -} - -int main(int argc, char* argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - - diff --git a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt b/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt deleted file mode 100644 index 2d4c5415272..00000000000 --- a/Svc/Subtopologies/CDHCore/ActiveLogger/test/ut/Readme.txt +++ /dev/null @@ -1,9 +0,0 @@ -This test can be run by executing the following: - -From Svc/ActiveLogger: - -"make ut run_ut" - -Note that the Ref application needs to be built first. -The test will return a pass/fail error code depending on the -success of the test. \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp new file mode 100644 index 00000000000..bd4fa965f33 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -0,0 +1,33 @@ +module CDHCore { + + instance cmdDisp: Svc.CommandDispatcher base id CDHCoreConfig.CDHCore_BASE_ID + 0x0100 \ + queue size CDHCoreConfig.Defaults.cmdDisp_QUEUE_SIZE \ + stack size CDHCoreConfig.Defaults.cmdDisp_STACK_SIZE \ + priority CDHCoreConfig.Priorities.cmdDisp_PRIORITY + + instance eventLogger: Svc.ActiveLogger base id CDHCoreConfig.CDHCore_BASE_ID + 0x0200 \ + queue size CDHCoreConfig.Defaults.eventLogger_QUEUE_SIZE \ + stack size CDHCoreConfig.Defaults.eventLogger_STACK_SIZE \ + priority CDHCoreConfig.Priorities.eventLogger_PRIORITY + + instance tlmSend: Svc.TlmChan base id CDHCoreConfig.CDHCore_BASE_ID + 0x0300 \ + queue size CDHCoreConfig.Defaults.tlmSend_QUEUE_SIZE \ + stack size CDHCoreConfig.Defaults.tlmSend_STACK_SIZE \ + priority CDHCoreConfig.Priorities.tlmSend_PRIORITY + + instance $health: Svc.Health base id CDHCoreConfig.CDHCore_BASE_ID + 0x0400 \ + queue size 25 + + topology Subtopology { + instance cmdDisp + instance eventLogger + instance tlmSend + + instance $health + + command connections instance cmdDisp + event connections instance eventLogger + telemetry connections instance tlmSend + + } # end topology +} # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp new file mode 100644 index 00000000000..7b9faa0ff11 --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -0,0 +1,25 @@ +module CDHCoreConfig { + # Base ID for your subtopology. All instantiated components will be offsets of this + constant CDHCore_BASE_ID = 0xFFFF0000 + + # include default Queue and Stack sizes here + module Defaults { + constant cmdDisp_QUEUE_SIZE = 10 + constant cmdDisp_STACK_SIZE = 64 * 1024 + + constant eventLogger_QUEUE_SIZE = 10 + constant eventLogger_STACK_SIZE = 10 + + constant tlmSend_QUEUE_SIZE = 10 + constant tlmSend_STACK_SIZE = 64 * 1024 + + constant $health_QUEUE_SIZE = 25 + } + + module Priorities { + constant cmdDisp_PRIORITY = 101 + constant $health_PRIORITY = 100 + constant eventLogger_PRIORITY = 99 + constant tlmSend_PRIORITY = 98 + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt new file mode 100644 index 00000000000..5aa5279fa9c --- /dev/null +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt @@ -0,0 +1,5 @@ +register_fprime_config( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/CDHCoreConfig.fpp" + INTERFACE +) diff --git a/Svc/Subtopologies/CDHCore/Subtopology/CDHCoreTopologyDefs.hpp b/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp similarity index 56% rename from Svc/Subtopologies/CDHCore/Subtopology/CDHCoreTopologyDefs.hpp rename to Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp index 726d31b59e3..e922962e632 100644 --- a/Svc/Subtopologies/CDHCore/Subtopology/CDHCoreTopologyDefs.hpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp @@ -9,7 +9,11 @@ namespace CDHCore { } namespace GlobalDefs { - + namespace PingEntries { + struct CDHCore_cmdDisp { enum { WARN=3, FATAL=5 }; }; + struct CDHCore_eventLogger { enum { WARN=3, FATAL=5 }; }; + struct CDHCore_tlmSend { enum { WARN=3, FATAL=5 }; }; + } } #endif \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CMakeLists.txt index c30a7807936..490135b9b5a 100644 --- a/Svc/Subtopologies/CDHCore/CMakeLists.txt +++ b/Svc/Subtopologies/CDHCore/CMakeLists.txt @@ -1 +1,9 @@ -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Subtopology/") \ No newline at end of file +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCoreConfig/") + +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/CDHCore.fpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/CDHCoreTopologyDefs.hpp" + INTERFACE +) diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt deleted file mode 100644 index 6820e752a53..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ - -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding files -# MOD_DEPS: (optional) module dependencies -# -# Note: using PROJECT_NAME as EXECUTABLE_NAME -#### -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/CmdDispatcher.fpp" - "${CMAKE_CURRENT_LIST_DIR}/CommandDispatcherImpl.cpp" -) - -register_fprime_module() -### UTs ### -set(UT_SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/CmdDispatcher.fpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherTester.cpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherImplTester.cpp" -) -register_fprime_ut() diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp deleted file mode 100644 index b7be3c3f963..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/CmdDispatcher.fpp +++ /dev/null @@ -1,199 +0,0 @@ - -module Svc { - - @ A component for dispatching commands - active component CommandDispatcher { - - # ---------------------------------------------------------------------- - # General ports - # ---------------------------------------------------------------------- - - @ Command dispatch port - output port compCmdSend: [CmdDispatcherComponentCommandPorts] Fw.Cmd - - @ Command Registration Port. max_number should match dispatch port. - guarded input port compCmdReg: [CmdDispatcherComponentCommandPorts] Fw.CmdReg - - @ Input Command Status Port - async input port compCmdStat: Fw.CmdResponse - - @ Output Command Status Port - output port seqCmdStatus: [CmdDispatcherSequencePorts] Fw.CmdResponse - - @ Command buffer input port for sequencers or other sources of command buffers - async input port seqCmdBuff: [CmdDispatcherSequencePorts] Fw.Com - - @ Ping input port - async input port pingIn: Svc.Ping - - @ Ping output port - output port pingOut: Svc.Ping - - # ---------------------------------------------------------------------- - # Port matching specifiers - # ---------------------------------------------------------------------- - - match compCmdSend with compCmdReg - - match seqCmdStatus with seqCmdBuff - - # ---------------------------------------------------------------------- - # Special ports - # ---------------------------------------------------------------------- - - @ Command receive port - command recv port CmdDisp - - @ Command registration port - command reg port CmdReg - - @ Command response port - command resp port CmdStatus - - @ Event port - event port Log - - @ Text event port - text event port LogText - - @ Time get port - time get port Time - - @ Telemetry port - telemetry port Tlm - - # ---------------------------------------------------------------------- - # Commands - # ---------------------------------------------------------------------- - - @ No-op command - async command CMD_NO_OP \ - opcode 0 - - @ No-op string command - async command CMD_NO_OP_STRING( - arg1: string size 40 @< The String command argument - ) \ - opcode 1 - - @ No-op command - async command CMD_TEST_CMD_1( - arg1: I32 @< The I32 command argument - arg2: F32 @< The F32 command argument - arg3: U8 @< The U8 command argument - ) \ - opcode 2 - - @ Clear command tracking info to recover from components not returning status - async command CMD_CLEAR_TRACKING \ - opcode 3 - - # ---------------------------------------------------------------------- - # Events - # ---------------------------------------------------------------------- - - event OpCodeRegistered( - Opcode: U32 @< The opcode to register - $port: I32 @< The registration port - slot: I32 @< The dispatch slot it was placed in - ) \ - severity diagnostic \ - id 0 \ - format "Opcode 0x{x} registered to port {} slot {}" - - @ Op code dispatched event - event OpCodeDispatched( - Opcode: U32 @< The opcode dispatched - $port: I32 @< The port dispatched to - ) \ - severity command \ - id 1 \ - format "Opcode 0x{x} dispatched to port {}" - - @ Op code completed event - event OpCodeCompleted( - Opcode: U32 @< The I32 command argument - ) \ - severity command \ - id 2 \ - format "Opcode 0x{x} completed" - - @ Op code completed with error event - event OpCodeError( - Opcode: U32 @< The opcode with the error - error: Fw.CmdResponse @< The error value - ) \ - severity command \ - id 3 \ - format "Opcode 0x{x} completed with error {}" - - @ Received a malformed command packet - event MalformedCommand( - Status: Fw.DeserialStatus @< The deserialization error - ) \ - severity warning high \ - id 4 \ - format "Received malformed command packet. Status: {}" - - @ Received an invalid opcode - event InvalidCommand( - Opcode: U32 @< Invalid opcode - ) \ - severity warning high \ - id 5 \ - format "Invalid opcode 0x{x} received" - - @ Exceeded the number of commands that can be simultaneously executed - event TooManyCommands( - Opcode: U32 @< The opcode that overflowed the list - ) \ - severity warning high \ - id 6 \ - format "Too many outstanding commands. opcode=0x{x}" - - @ The command dispatcher has successfully received a NO-OP command - event NoOpReceived \ - severity activity high \ - id 7 \ - format "Received a NO-OP command" - - @ The command dispatcher has successfully received a NO-OP command from GUI with a string - event NoOpStringReceived( - message: string size 40 @< The NO-OP string that is generated - ) \ - severity activity high \ - id 8 \ - format "Received a NO-OP string={}" - - @ This log event message returns the TEST_CMD_1 arguments. - event TestCmd1Args( - arg1: I32 @< Arg1 - arg2: F32 @< Arg2 - arg3: U8 @< Arg3 - ) \ - severity activity high \ - id 9 \ - format "TEST_CMD_1 args: I32: {}, F32: {f}, U8: {}" - - @ Op code reregistered event - event OpCodeReregistered( - Opcode: U32 @< The opcode reregistered - $port: I32 @< The reregistration port - ) \ - severity diagnostic \ - id 10 \ - format "Opcode 0x{x} is already registered to port {}" - - # ---------------------------------------------------------------------- - # Telemetry - # ---------------------------------------------------------------------- - - @ Number of commands dispatched - telemetry CommandsDispatched: U32 id 0 update on change - - @ Number of command errors - telemetry CommandErrors: U32 id 1 update on change - - } - -} diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp deleted file mode 100644 index 442c93206f8..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcher.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// ====================================================================== -// CommandDispatcher.hpp -// Standardization header for CommandDispatcher -// ====================================================================== - -#ifndef Svc_CommandDispatcher_HPP -#define Svc_CommandDispatcher_HPP - -#include "Svc/CmdDispatcher/CommandDispatcherImpl.hpp" - -namespace Svc { - - typedef CommandDispatcherImpl CommandDispatcher; - -} - -#endif diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp deleted file mode 100644 index a340c9a64b2..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * CommandDispatcherImpl.cpp - * - * Created on: May 13, 2014 - * Author: Timothy Canham - */ - -#include -#include -#include -#include - -// Check the CMD_DISPATCHER_DISPATCH_TABLE_SIZE and CMD_DISPATCHER_SEQUENCER_TABLE_SIZE for overflow -static_assert(CMD_DISPATCHER_DISPATCH_TABLE_SIZE <= std::numeric_limits::max(), "Opcode table limited to opcode range"); -static_assert(CMD_DISPATCHER_SEQUENCER_TABLE_SIZE <= std::numeric_limits::max(), "Sequencer table limited to range of U32"); - -namespace Svc { - CommandDispatcherImpl::CommandDispatcherImpl(const char* name) : - CommandDispatcherComponentBase(name), - m_seq(0), - m_numCmdsDispatched(0), - m_numCmdErrors(0) - { - memset(this->m_entryTable,0,sizeof(this->m_entryTable)); - memset(this->m_sequenceTracker,0,sizeof(this->m_sequenceTracker)); - } - - CommandDispatcherImpl::~CommandDispatcherImpl() { - } - - void CommandDispatcherImpl::compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode) { - // search for an empty slot - bool slotFound = false; - for (FwOpcodeType slot = 0; slot < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); slot++) { - if ((not this->m_entryTable[slot].used) and (not slotFound)) { - this->m_entryTable[slot].opcode = opCode; - this->m_entryTable[slot].port = portNum; - this->m_entryTable[slot].used = true; - this->log_DIAGNOSTIC_OpCodeRegistered(opCode,portNum,static_cast(slot)); - slotFound = true; - } else if ((this->m_entryTable[slot].used) && - (this->m_entryTable[slot].opcode == opCode) && - (this->m_entryTable[slot].port == portNum) && - (not slotFound)) { - slotFound = true; - this->log_DIAGNOSTIC_OpCodeReregistered(opCode,portNum); - } else if (this->m_entryTable[slot].used) { // make sure no duplicates - FW_ASSERT(this->m_entryTable[slot].opcode != opCode, static_cast(opCode)); - } - } - FW_ASSERT(slotFound,static_cast(opCode)); - } - - void CommandDispatcherImpl::compCmdStat_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response) { - // check response and log - if (Fw::CmdResponse::OK == response.e) { - this->log_COMMAND_OpCodeCompleted(opCode); - } else { - this->m_numCmdErrors++; - this->tlmWrite_CommandErrors(this->m_numCmdErrors); - FW_ASSERT(response.e != Fw::CmdResponse::OK); - this->log_COMMAND_OpCodeError(opCode,response); - } - // look for command source - FwIndexType portToCall = -1; - U32 context; - for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) { - if ( - (this->m_sequenceTracker[pending].seq == cmdSeq) && - (this->m_sequenceTracker[pending].used) - ) { - portToCall = this->m_sequenceTracker[pending].callerPort; - context = this->m_sequenceTracker[pending].context; - FW_ASSERT(opCode == this->m_sequenceTracker[pending].opCode); - FW_ASSERT(portToCall < this->getNum_seqCmdStatus_OutputPorts()); - this->m_sequenceTracker[pending].used = false; - break; - } - } - - if (portToCall != -1) { - // call port to report status - if (this->isConnected_seqCmdStatus_OutputPort(portToCall)) { - // NOTE: seqCmdStatus port forwards three arguments: (opCode, cmdSeq, response). - // However, the cmdSeq value has no meaning for the calling sequencer. - // Instead, the context value is forwarded to allow the caller to utilize it if needed. - this->seqCmdStatus_out(portToCall,opCode,context,response); - } - } - } - - void CommandDispatcherImpl::seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer &data, U32 context) { - - Fw::CmdPacket cmdPkt; - Fw::SerializeStatus stat = cmdPkt.deserialize(data); - - if (stat != Fw::FW_SERIALIZE_OK) { - Fw::DeserialStatus serErr(static_cast(stat)); - this->log_WARNING_HI_MalformedCommand(serErr); - if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { - this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::VALIDATION_ERROR); - } - return; - } - - // search for opcode in dispatch table - FwOpcodeType entry; - bool entryFound = false; - - for (entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_entryTable); entry++) { - if ((this->m_entryTable[entry].used) and (cmdPkt.getOpCode() == this->m_entryTable[entry].opcode)) { - entryFound = true; - break; - } - } - if (entryFound and this->isConnected_compCmdSend_OutputPort(this->m_entryTable[entry].port)) { - // register command in command tracker only if response port is connect - if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { - bool pendingFound = false; - - for (U32 pending = 0; pending < FW_NUM_ARRAY_ELEMENTS(this->m_sequenceTracker); pending++) { - if (not this->m_sequenceTracker[pending].used) { - pendingFound = true; - this->m_sequenceTracker[pending].used = true; - this->m_sequenceTracker[pending].opCode = cmdPkt.getOpCode(); - this->m_sequenceTracker[pending].seq = this->m_seq; - this->m_sequenceTracker[pending].context = context; - this->m_sequenceTracker[pending].callerPort = portNum; - break; - } - } - - // if we couldn't find a slot to track the command, quit - if (not pendingFound) { - this->log_WARNING_HI_TooManyCommands(cmdPkt.getOpCode()); - if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { - this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::EXECUTION_ERROR); - } - return; - } - } // end if status port connected - // pass arguments to argument buffer - this->compCmdSend_out( - this->m_entryTable[entry].port, - cmdPkt.getOpCode(), - this->m_seq, - cmdPkt.getArgBuffer()); - // log dispatched command - this->log_COMMAND_OpCodeDispatched(cmdPkt.getOpCode(),this->m_entryTable[entry].port); - - // increment command count - this->m_numCmdsDispatched++; - // write telemetry channel for dispatched commands - this->tlmWrite_CommandsDispatched(this->m_numCmdsDispatched); - } else { - this->log_WARNING_HI_InvalidCommand(cmdPkt.getOpCode()); - this->m_numCmdErrors++; - // Fail command back to port, if connected - if (this->isConnected_seqCmdStatus_OutputPort(portNum)) { - this->seqCmdStatus_out(portNum,cmdPkt.getOpCode(),context,Fw::CmdResponse::INVALID_OPCODE); - } - this->tlmWrite_CommandErrors(this->m_numCmdErrors); - } - - // increment sequence number - this->m_seq++; - } - - void CommandDispatcherImpl::CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { - Fw::LogStringArg no_op_string("Hello, World!"); - // Log event for NO_OP here. - this->log_ACTIVITY_HI_NoOpReceived(); - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void CommandDispatcherImpl::CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1) { - Fw::LogStringArg msg(arg1.toChar()); - // Echo the NO_OP_STRING args here. - this->log_ACTIVITY_HI_NoOpStringReceived(msg); - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void CommandDispatcherImpl::CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3) { - this->log_ACTIVITY_HI_TestCmd1Args(arg1,arg2,arg3); - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void CommandDispatcherImpl::CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { - // clear tracking table - for (FwOpcodeType entry = 0; entry < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE; entry++) { - this->m_sequenceTracker[entry].used = false; - } - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); - } - - void CommandDispatcherImpl::pingIn_handler(FwIndexType portNum, U32 key) { - // respond to ping - this->pingOut_out(0,key); - } - -} diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp deleted file mode 100644 index 4f22c802288..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/CommandDispatcherImpl.hpp +++ /dev/null @@ -1,168 +0,0 @@ -/** - * \file - * \author T.Canham - * \brief Component responsible for dispatching incoming commands to registered components - * - * \copyright - * Copyright 2009-2015, by the California Institute of Technology. - * ALL RIGHTS RESERVED. United States Government Sponsorship - * acknowledged. - *

- */ - - -#ifndef COMMANDDISPATCHERIMPL_HPP_ -#define COMMANDDISPATCHERIMPL_HPP_ - -#include -#include -#include - -namespace Svc { - - //! \class CommandDispatcherImpl - //! \brief Command Dispatcher component class - //! - //! The command dispatcher takes incoming Fw::Com packets that contain - //! encoded commands. It extracts the opcode and looks it up in a table - //! that is populated by components at registration time. If a component - //! is connected to the seqCmdStatus port with the same number - //! as the port that submitted the command, the command status will be returned. - - class CommandDispatcherImpl final : public CommandDispatcherComponentBase { - public: - //! \brief Command Dispatcher constructor - //! - //! The constructor initializes the state of the component. - //! In this component, the opcode dispatch and tracking tables - //! are initialized. - //! - //! \param name the component instance name - CommandDispatcherImpl(const char* name); - //! \brief Component destructor - //! - //! The destructor for this component is empty - virtual ~CommandDispatcherImpl(); - PROTECTED: - PRIVATE: - //! \brief component command status handler - //! - //! The command status handler is called when a component - //! reports the completion of a command. - //! - //! \param portNum the number of the incoming port. - //! \param opCode the opcode of the completed command. - //! \param cmdSeq the sequence number assigned to the command when it was dispatched - //! \param response the completion status of the command - void compCmdStat_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response); - //! \brief component command buffer handler - //! - //! The command buffer handler is called to submit a new - //! command packet to be decoded - //! - //! \param portNum the number of the incoming port. - //! \param data the buffer containing the command. - //! \param context a user value returned with the status - void seqCmdBuff_handler(FwIndexType portNum, Fw::ComBuffer &data, U32 context); - //! \brief component command registration handler - //! - //! The command registration handler is called to register - //! new opcodes. The port number called is used to indicate - //! which port should be used to dispatch the opcode. - //! - //! \param portNum the number of the incoming port. - //! \param opCode the opcode being registered. - void compCmdReg_handler(FwIndexType portNum, FwOpcodeType opCode); - //! \brief component ping handler - //! - //! The ping handler responds to messages to verify that the task - //! is still executing. Will call output ping port - //! - //! \param portNum the number of the incoming port. - //! \param opCode the opcode being registered. - //! \param key the key value that is returned with the ping response - void pingIn_handler(FwIndexType portNum, U32 key); - //! \brief NO_OP command handler - //! - //! A test command that does nothing - //! - //! \param opCode the NO_OP opcode. - //! \param cmdSeq the assigned sequence number for the command - void CMD_NO_OP_cmdHandler(FwOpcodeType opCode, U32 cmdSeq); - //! \brief NO_OP with string command handler - //! - //! A test command that receives a string and sends an event - //! with the string as an argument - //! - //! \param opCode the NO_OP_STRING opcode. - //! \param cmdSeq the assigned sequence number for the command - //! \param arg1 the string argument - void CMD_NO_OP_STRING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& arg1); - //! \brief A test command with different argument types - //! - //! A test command that receives a set of arguments of different types - //! - //! \param opCode the TEST_CMD_1 opcode. - //! \param cmdSeq the assigned sequence number for the command - //! \param arg1 the I32 argument - //! \param arg2 the F32 argument - //! \param arg3 the U8 argument - void CMD_TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3); - //! \brief A command to clear the command tracking - //! - //! This command will clear the table tracking the completion of commands. - //! It is meant to be used if the tracking table has gotten full because of - //! a software failure. It is dangerous in that it can clear a command - //! that a sequencer is waiting for. - //! - //! \param opCode the CLEAR_TRACKING opcode. - //! \param cmdSeq the assigned sequence number for the command - void CMD_CLEAR_TRACKING_cmdHandler(FwOpcodeType opCode, U32 cmdSeq); - - //! \struct DispatchEntry - //! \brief table used to store opcode to port mappings - //! - //! The DispatchEntry table is used to map incoming opcodes to the port - //! connected to the component that implements the opcode. - //! As each command opcode is registered, a new entry is found - //! in the table by checking for the "used" flag. The opcode - //! member is set to the opcode, and the port member set to the - //! port to dispatch to. When a new opcode is received for - //! execution, the table is traversed until the opcode is located. - - struct DispatchEntry { - bool used; //!< if entry has been used yet - FwOpcodeType opcode; //!< opcode of entry - FwIndexType port; //!< which port the entry invokes - } m_entryTable[CMD_DISPATCHER_DISPATCH_TABLE_SIZE]; //!< table of dispatch entries - - //! \struct SequenceTracker - //! \brief table used to store opcode that are being executed - //! - //! The SequenceTracker table is used to track commands that are being executed - //! but are not yet complete. When a new command opcode is received, - //! the status port that would be used to report the completion status - //! is checked. If it is connected, then an entry is placed in this table. - //! The "used" flag is set, and the "seq" member is set to the - //! assigned sequence number for the command. The "opCode" field is - //! used for the opcode, and the "callerPort" field is used to store - //! the port number of the caller so the status can be reported back to - //! correct port. - - struct SequenceTracker { - bool used; //!< if this slot is used - U32 seq; //!< command sequence number - FwOpcodeType opCode; //!< opcode being tracked - U32 context; //!< context passed by user - FwIndexType callerPort; //!< port command source port - } m_sequenceTracker[CMD_DISPATCHER_SEQUENCER_TABLE_SIZE]; //!< sequence tracking port for command completions; - - U32 m_seq; //!< current command sequence number - - U32 m_numCmdsDispatched; //!< number of commands dispatched - U32 m_numCmdErrors; //!< number of commands with an error - - }; -} - -#endif /* COMMANDDISPATCHERIMPL_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/README b/Svc/Subtopologies/CDHCore/CmdDispatcher/README deleted file mode 100644 index 76fd4a64ba4..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/README +++ /dev/null @@ -1,6 +0,0 @@ -This directory contains the CmdDispatcher component. This component takes incoming Com packets that have commands encoded in them and decodes them. -It looks up opcodes in a table build by component registrations. It also handles completions, passing the status back to the sender of the packet. - -CommandDispatcherComponentAi.xml - Command dispatcher component specification -CommandDispatcherImpl.hpp(.cpp) - Command dispatcher implementation -CommandDispatcherImplCfg.hpp - Command dispatcher configuration \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt b/Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt deleted file mode 100644 index bab0c3a8e60..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/changed-symbols.txt +++ /dev/null @@ -1,41 +0,0 @@ -Old Symbol -New Symbol - -Svc::CommandDispatcherComponentBase::ErrorResponse -Fw::CmdResponse - -Svc::CommandDispatcherComponentBase::ERR_INVALID_OPCODE -Fw::CmdResponse::INVALID_OPCODE - -Svc::CommandDispatcherComponentBase::ERR_VALIDATION_ERROR -Fw::CmdResponse::VALIDATION_ERROR - -Svc::CommandDispatcherComponentBase::ERR_FORMAT_ERROR -Fw::CmdResponse::FORMAT_ERROR - -Svc::CommandDispatcherComponentBase::ERR_EXECUTION_ERROR -Fw::CmdResponse::EXECUTION_ERROR - -Svc::CommandDispatcherComponentBase::ERR_BUSY -Fw::CmdResponse::BUSY - -Svc::CommandDispatcherComponentBase::ERR_UNEXP -N/A - -Svc::CommandDispatcherComponentBase::CmdSerError -Fw::DeserialStatus - -Svc::CommandDispatcherComponentBase::ERR_BUFFER_TOO_SMALL -Fw::DeserialStatus::BUFFER_EMPTY - -Svc::CommandDispatcherComponentBase::ERR_BUFFER_FORMAT -Fw::DeserialStatus::FORMAT_ERROR - -Svc::CommandDispatcherComponentBase::ERR_SIZE_MISMATCH -Fw::DeserialStatus::SIZE_MISMATCH - -Svc::CommandDispatcherComponentBase::ERR_TYPE_MISMATCH -Fw::DeserialStatus::TYPE_MISMATCH - -Svc::CommandDispatcherComponentBase::ERR_UNEXP_STAT -N/A diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore deleted file mode 100644 index 0b84df0f025..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.html \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Code.xlsx b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Code.xlsx deleted file mode 100644 index 0ea2389ebefebdb3375ea35c3ebf74c203fef777..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29709 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 z 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 K_}c&D=>GweUw%6P diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Design.xlsx b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/Checklist_Design.xlsx deleted file mode 100644 index fd2af919bc9f055efd1ecd7c3cd4bee2be4c1e17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25044 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 JBEmBL{|^8q84Umc diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/img/CommandDispatcherBDD.jpg b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/img/CommandDispatcherBDD.jpg deleted file mode 100644 index 1098ba53b9bb5d70dc86cf4e26df3c7387c4bd70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142623 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 z 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 diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md b/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md deleted file mode 100644 index 3d78de27519..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/docs/sdd.md +++ /dev/null @@ -1,127 +0,0 @@ -# Svc::CmdDispatcher Component - -## 1. Introduction - -The `Svc::CmdDispatcher` is responsible for dispatching incoming commands to the components that implement those commands. The commands are sent in encoded `Fw::Com` form from an external sender like a ground system or a sequencer. The dispatcher decodes the packet and extracts the opcode. This opcode is looked up in a table and dispatched to the component via a port indicated in the table. The output port for each opcode is set by a call to a registration port. - -## 2. Requirements - -The requirements for `Svc::CmdDispatcher` are as follows: - -Requirement | Description | Verification Method ------------ | ----------- | ------------------- -CD-001 | The `Svc::CmdDispatcher` component shall accept command buffers and decode them into commands | Inspection, Unit Test -CD-002 | The `Svc::CmdDispatcher` component shall dispatch commands to components | Unit Test -CD-003 | The `Svc::CmdDispatcher` component shall provide an interface to register commands | Inspection -CD-004 | The `Svc::CmdDispatcher` component shall process command status from components and report the results to the command buffer sender. | Unit Test - -## 3. Design - -### 3.1 Context - -#### 3.1.1 Component Diagram - -The `Svc::CmdDispatcher` component has the following component diagram: - -![`Svc::CmdDispatcher` Diagram](img/CommandDispatcherBDD.jpg "Svc::CmdDispatcher") - -#### 3.1.2 Ports - -The `Svc::CmdDispatcher` component uses the following port types: - -Port Data Type | Name | Direction | Kind | Usage --------------- | ---- | --------- | ---- | ----- -[`Fw::Cmd`](../../../Fw/Cmd/docs/sdd.md) | cmdSend | Output | n/a | Send commands to components -[`Fw::CmdResponse`](../../../Fw/Cmd/docs/sdd.md) | compCmdStat | Input | Asynchronous | Port for components to report command status -[`Fw::CmdResponse`](../../../Fw/Cmd/docs/sdd.md) | seqCmdStatus | Output | n/a | Send command status to command buffer source -[`Fw::Com`](../../../Fw/Com/docs/sdd.md) | seqCmdBuff | Input | Asynchronous | Receive command buffer -[`Fw::CmdReg`](../../../Fw/Cmd/docs/sdd.md) | cmdReg | Input | Synchronous | Command Registration - -### 3.2 Functional Description - -The `Svc::CmdDispatcher` component provides command dispatching. The architecture autocoder generates port instances for components that specify commands that implement the commanding pattern. `Svc::CommandDispatcher` implements the command decoding and dispatching to supply the components with commands. - -#### 3.2.1 Command Registration - -An autogenerated function on components create a public function `regCommands` that tells components to register the set of op codes that are implemented by the component. The autogenerated port is connected to the `compCmdReg` input port on `Svc::CmdDispatcher` that corresponds to the number of the `compCmdSend` port used to dispatch commands. The port handler looks through the dispatch table for an unused entry and adds the opcode. It maps the opcode to the dispatch port number corresponding to the registration port number. - -#### 3.2.2 Command Dispatch - -When the command dispatcher receives a command buffer, it decodes the opcode. It searches the dispatch table for the opcode, then assigns a sequence number to the command and stores the opcode, sequence number, context value and source port in a pending command table. The command is then dispatched to the component that implements the command. When the component completes execution of the command, it reports the status back via the `compCmdStat` port. The sequence number is matched to the entry in the pending command table, and the `seqCmdStatus` output port corresponding to the source port is called (if it is connected) with the status and the context value. -Note #1: this requires that the component sending the command buffer have connections to the same `seqCmdBuff` and `seqCmdStatus` port numbers. -Note #2: the `seqCmdStatus` port utilize the same type as the `compCmdStat`, the `Fw::CmdResponse`. This has been done to avoid creation of similar types for status ports. However, the `Fw::CmdResponse::cmdSeq` argument of the `seqCmdStatus` doesn't have any meaning for the calling sequencer. Therefore, as it has been mentioned before, instead of forwarding a command sequence number, the context value is transferred. - -### 3.3 Scenarios - -#### 3.3.1 Command Registration - -The `Svc::CmdDispatcher` component accepts command registration from other components: - -```mermaid -sequenceDiagram - Initialization->>Component: get_ComdReg_InputPort() - activate Initialization - deactivate Initialization - activate Component - deactivate Component - Initialization->>Component: regCommands() - activate Initialization - activate Component - loop for each opcode - Component->>CommandDispatcher: cmdReg() - end - deactivate Initialization - deactivate Component -``` - -#### 3.3.1 Dispatch Commands - -The `Svc::CmdDispatcher` component dispatches commands to other components: - -```mermaid -sequenceDiagram - Command Buffer Source->>CommandDispatcher: seqCmdBuff() - activate Command Buffer Source - activate CommandDispatcher - CommandDispatcher->>Component: seqCmdBuff() - activate Component - Component->>CommandDispatcher: compCmdStat() - deactivate Component - CommandDispatcher->>Command Buffer Source: seqCmdStatus() - deactivate CommandDispatcher - deactivate Command Buffer Source -``` - -### 3.4 State - -`Svc::CmdDispatcher` has no state machines. - -### 3.5 Algorithms - -`Svc::CmdDispatcher` has no significant algorithms. - -## 4. Module Checklists - -Checklist | --------- | -[Design](Checklist_Design.xlsx) | -[Code](Checklist_Code.xlsx) | -[Unit Test](Checklist_Unit_Test.xls) | - -## 5. Unit Testing - -To see unit test coverage run `fprime-util check --coverage` - -## 6. Change Log - -Date | Description ----- | ----------- -6/25/2015 | Design review edits -7/22/2015 | Design review actions -9/16/2015 | Unit Test additions -1/28/2016 | Added context value discussion -5/17/2021 | Added CMD Reregistration option -5/05/2025 | Added a note about Fw::CmdResponse::cmdSeq usage in seqCmdStatus - - - diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/int/test_cmd_dispatcher.py b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/int/test_cmd_dispatcher.py deleted file mode 100644 index 035f9fb9b44..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/int/test_cmd_dispatcher.py +++ /dev/null @@ -1,12 +0,0 @@ -""" 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/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp deleted file mode 100644 index 360e98fc64c..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.cpp +++ /dev/null @@ -1,887 +0,0 @@ -/* - * CommandDispatcherImplTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include -#include - -#include - -#include -#include - -static_assert(CMD_DISPATCHER_SEQUENCER_TABLE_SIZE + 1 <= std::numeric_limits::max(), "Unit test depends on CMD_DISPATCHER_SEQUENCER_TABLE_SIZE + 1 within range of U32"); - -namespace Svc { - CommandDispatcherImplTester::CommandDispatcherImplTester(Svc::CommandDispatcherImpl& inst) : - CommandDispatcherGTestBase("testerbase",100), - m_impl(inst) { - } - - CommandDispatcherImplTester::~CommandDispatcherImplTester() { - } - - void CommandDispatcherImplTester::from_compCmdSend_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, Fw::CmdArgBuffer &args) { - this->m_cmdSendOpCode = opCode; - this->m_cmdSendCmdSeq = cmdSeq; - this->m_cmdSendArgs = args; - this->m_cmdSendRcvd = true; - } - - void CommandDispatcherImplTester::from_seqCmdStatus_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response) { - this->m_seqStatusRcvd = true; - this->m_seqStatusOpCode = opCode; - this->m_seqStatusCmdSeq = cmdSeq; - this->m_seqStatusCmdResponse = response; - } - - void CommandDispatcherImplTester::runNominalDispatch() { - - // verify dispatch table is empty - for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { - ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); - } - - // verify sequence tracker table is empty - - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - // clear reg events - this->clearEvents(); - // register built-in commands - this->m_impl.regCommands(); - // verify registrations - ASSERT_TRUE(this->m_impl.m_entryTable[0].used); - ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); - ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[1].used); - ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); - ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[2].used); - ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); - ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[3].used); - ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); - ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); - - // verify event - printTextLogHistory(stdout); - ASSERT_EVENTS_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); - ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); - ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); - ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); - - - REQUIREMENT("CD-003"); - // register our own command - FwOpcodeType testOpCode = 0x50; - - this->clearEvents(); - this->invoke_to_compCmdReg(0,0x50); - ASSERT_TRUE(this->m_impl.m_entryTable[4].used); - ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); - ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); - - // verify registration event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); - - // dispatch a test command - REQUIREMENT("CD-001"); - - U32 testCmdArg = 100; - U32 testContext = 110; - this->clearEvents(); - Fw::ComBuffer buff; - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - REQUIREMENT("CD-002"); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); - - // verify sequence table entry - ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].seq, 0u); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort, 0); - - // verify command received - ASSERT_TRUE(this->m_cmdSendRcvd); - ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); - ASSERT_EQ(this->m_cmdSendCmdSeq,0); - // check argument - U32 checkVal; - ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(checkVal,testCmdArg); - - this->clearEvents(); - this->m_seqStatusRcvd = false; - // perform command response - this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::OK); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // Check dispatch table - ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].seq,0u); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - - // Verify completed event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeCompleted_SIZE(1); - ASSERT_EVENTS_OpCodeCompleted(0u,testOpCode); - - REQUIREMENT("CD-004"); - - // Verify status passed back to port - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(this->m_seqStatusOpCode,testOpCode); - ASSERT_EQ(this->m_seqStatusCmdSeq,testContext); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); - } - - void CommandDispatcherImplTester::runNopCommands() { - - // verify dispatch table is empty - for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { - ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); - } - - // verify sequence tracker table is empty - - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - - // clear reg events - this->clearEvents(); - // register built-in commands - this->m_impl.regCommands(); - // verify registrations - ASSERT_TRUE(this->m_impl.m_entryTable[0].used); - ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); - ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[1].used); - ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); - ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[2].used); - ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); - ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[3].used); - ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); - ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); - - // verify event - - ASSERT_EVENTS_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); - ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); - ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); - ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); - - // send NO_OP command - this->m_seqStatusRcvd = false; - Fw::ComBuffer buff; - ASSERT_EQ(buff.serialize(static_cast(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(static_cast(CommandDispatcherImpl::OPCODE_CMD_NO_OP)),Fw::FW_SERIALIZE_OK); - - this->clearEvents(); - this->invoke_to_seqCmdBuff(0,buff,12); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1); - - // dispatch for async command - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - // dispatch for async command response - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - // Verify status passed back to port - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(CommandDispatcherImpl::OPCODE_CMD_NO_OP,this->m_seqStatusOpCode); - // Verify correct context value is passed back. - ASSERT_EQ(12u,this->m_seqStatusCmdSeq); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); - - // send NO_OP_STRING command - this->clearEvents(); - this->m_seqStatusRcvd = false; - buff.resetSer(); - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(FwOpcodeType(CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING)),Fw::FW_SERIALIZE_OK); - // serialize arg1 - Fw::CmdStringArg argString("BOO!"); - ASSERT_EQ(buff.serialize(argString),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,13); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1); - - // dispatch for async command - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - // dispatch for async command response - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - // Verify status passed back to port - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,this->m_seqStatusOpCode); - ASSERT_EQ(13u,this->m_seqStatusCmdSeq); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); - - // send TEST_CMD_1 command - this->m_seqStatusRcvd = false; - buff.resetSer(); - ASSERT_EQ(buff.serialize(static_cast(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(static_cast(CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1)),Fw::FW_SERIALIZE_OK); - // serialize arg1 - ASSERT_EQ(buff.serialize(static_cast(1)),Fw::FW_SERIALIZE_OK); - // serialize arg2 - ASSERT_EQ(buff.serialize(static_cast(2.3)),Fw::FW_SERIALIZE_OK); - // serialize arg3 - ASSERT_EQ(buff.serialize(static_cast(4)),Fw::FW_SERIALIZE_OK); - - this->clearEvents(); - this->invoke_to_seqCmdBuff(0,buff,14); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1); - - // dispatch for async command - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - // dispatch for async command response - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - // Verify status passed back to port - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,this->m_seqStatusOpCode); - ASSERT_EQ(14u,this->m_seqStatusCmdSeq); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::OK); - } - - void CommandDispatcherImplTester::runCommandReregister() { - // register built-in commands - this->m_impl.regCommands(); - // clear reg events - this->clearEvents(); - - // register our own command - FwOpcodeType testOpCode = 0x50; - this->invoke_to_compCmdReg(0,0x50); - ASSERT_TRUE(this->m_impl.m_entryTable[4].used); - ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); - ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); - - // verify registration event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); - - // clear reg events - this->clearEvents(); - - // verify we can call cmdReg port again with the same opcode - this->invoke_to_compCmdReg(0,0x50); - ASSERT_TRUE(this->m_impl.m_entryTable[4].used); - ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); - ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); - - // verify re-registration event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeReregistered_SIZE(1); - ASSERT_EVENTS_OpCodeReregistered(0,testOpCode,0); - } - - void CommandDispatcherImplTester::runInvalidOpcodeDispatch() { - - // verify dispatch table is empty - for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { - ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); - } - - // verify sequence tracker table is empty - - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - // clear reg events - this->clearEvents(); - // register built-in commands - this->m_impl.regCommands(); - // verify registrations - ASSERT_TRUE(this->m_impl.m_entryTable[0].used); - ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); - ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[1].used); - ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); - ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[2].used); - ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); - ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[3].used); - ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); - ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); - - // verify event - ASSERT_EVENTS_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); - ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); - ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); - ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); - - // register our own command - FwOpcodeType testOpCode = 0x50; - - this->clearEvents(); - this->invoke_to_compCmdReg(0,0x50); - ASSERT_TRUE(this->m_impl.m_entryTable[4].used); - ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); - ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); - - // verify registration event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); - - // dispatch a test command with a bad opcode - U32 testCmdArg = 100; - U32 testContext = 13; - this->clearEvents(); - this->m_seqStatusRcvd = false; - Fw::ComBuffer buff; - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(FwOpcodeType(testOpCode + 1)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->clearEvents(); - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_InvalidCommand_SIZE(1); - ASSERT_EVENTS_InvalidCommand(0u,testOpCode+1); - - // Verify status passed back to port - - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(this->m_seqStatusOpCode,testOpCode+1); - ASSERT_EQ(this->m_seqStatusCmdSeq,testContext); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::INVALID_OPCODE); - } - - void CommandDispatcherImplTester::runFailedCommand() { - - // verify dispatch table is empty - for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { - ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); - } - - // verify sequence tracker table is empty - - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - // clear reg events - this->clearEvents(); - // register built-in commands - this->m_impl.regCommands(); - // verify registrations - ASSERT_TRUE(this->m_impl.m_entryTable[0].used); - ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); - ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[1].used); - ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); - ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[2].used); - ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); - ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[3].used); - ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); - ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); - - // verify event - ASSERT_EVENTS_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); - ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); - ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); - ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); - // register our own command - FwOpcodeType testOpCode = 0x50; - - this->clearEvents(); - this->invoke_to_compCmdReg(0,0x50); - ASSERT_TRUE(this->m_impl.m_entryTable[4].used); - ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); - ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); - - // verify registration event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); - - U32 currSeq = 0; - - // dispatch a test command - U32 testCmdArg = 100; - U32 testContext = 13; - this->clearEvents(); - Fw::ComBuffer buff; - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); - - // verify sequence table entry - ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - - // verify command received - ASSERT_TRUE(this->m_cmdSendRcvd); - ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); - ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq); - // check argument - U32 checkVal; - ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(checkVal,testCmdArg); - - this->clearEvents(); - this->m_seqStatusRcvd = false; - // perform command response - this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::EXECUTION_ERROR); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // Check dispatch table - ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - - // Verify completed event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeError_SIZE(1); - ASSERT_EVENTS_OpCodeError(0,testOpCode, Fw::CmdResponse::EXECUTION_ERROR); - - // Verify status passed back to port - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(this->m_seqStatusCmdSeq,testContext); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::EXECUTION_ERROR); - - // dispatch a test command - currSeq++; - this->clearEvents(); - buff.resetSer(); - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); - - // verify sequence table entry - ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - - // verify command received - ASSERT_TRUE(this->m_cmdSendRcvd); - ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); - ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq); - // check argument - ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(checkVal,testCmdArg); - - this->clearEvents(); - this->m_seqStatusRcvd = false; - // perform command response - this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::INVALID_OPCODE); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // Check dispatch table - ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - - // Verify completed event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeError_SIZE(1); - ASSERT_EVENTS_OpCodeError(0,testOpCode,Fw::CmdResponse::INVALID_OPCODE); - - // Verify status passed back to port - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(this->m_seqStatusOpCode,testOpCode); - ASSERT_EQ(testContext,this->m_seqStatusCmdSeq); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::INVALID_OPCODE); - - currSeq++; - // dispatch a test command - this->clearEvents(); - buff.resetSer(); - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); - - // verify sequence table entry - ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); - - // verify command received - ASSERT_TRUE(this->m_cmdSendRcvd); - ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); - ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq); - // check argument - ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(checkVal,testCmdArg); - - this->clearEvents(); - this->m_seqStatusRcvd = false; - // perform command response - this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::VALIDATION_ERROR); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // Check dispatch table - ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - - // Verify completed event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeError_SIZE(1); - ASSERT_EVENTS_OpCodeError(0,testOpCode,Fw::CmdResponse::VALIDATION_ERROR); - - // Verify status passed back to port - ASSERT_TRUE(this->m_seqStatusRcvd); - ASSERT_EQ(this->m_seqStatusOpCode,testOpCode); - ASSERT_EQ(testContext,this->m_seqStatusCmdSeq); - ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::CmdResponse::VALIDATION_ERROR); - } - - void CommandDispatcherImplTester::runInvalidCommand() { - // verify dispatch table is empty - for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { - ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); - } - - // verify sequence tracker table is empty - - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - // clear reg events - this->clearEvents(); - - // dispatch a flawed command - U32 testCmdArg = 100; - U32 testContext = 13; - FwOpcodeType testOpCode = 0x50; - this->clearEvents(); - Fw::ComBuffer buff; - ASSERT_EQ(buff.serialize(U32(100)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_MalformedCommand_SIZE(1); - ASSERT_EVENTS_MalformedCommand(0,Fw::DeserialStatus::TYPE_MISMATCH); - - } - - void CommandDispatcherImplTester::runOverflowCommands() { - - // verify dispatch table is empty - for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { - ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); - } - - // verify sequence tracker table is empty - - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - // clear reg events - this->clearEvents(); - // register built-in commands - this->m_impl.regCommands(); - // verify registrations - ASSERT_TRUE(this->m_impl.m_entryTable[0].used); - ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); - ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[1].used); - ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); - ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[2].used); - ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); - ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[3].used); - ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); - ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); - - // verify event - ASSERT_EVENTS_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); - ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); - ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); - ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); - - // register our own command - FwOpcodeType testOpCode = 0x50; - - this->clearEvents(); - this->invoke_to_compCmdReg(0,0x50); - ASSERT_TRUE(this->m_impl.m_entryTable[4].used); - ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); - ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); - - // verify registration event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); - - for (U32 disp = 0; disp < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE + 1; disp++) { - // dispatch a test command - U32 testCmdArg = 100; - U32 testContext = 13; - this->clearEvents(); - Fw::ComBuffer buff; - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - if (disp < CMD_DISPATCHER_SEQUENCER_TABLE_SIZE) { - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); - - // verify sequence table entry - ASSERT_TRUE(this->m_impl.m_sequenceTracker[disp].used); - ASSERT_EQ(disp,this->m_impl.m_sequenceTracker[disp].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].context,testContext); - ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].callerPort,0); - - // verify command received - ASSERT_TRUE(this->m_cmdSendRcvd); - ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); - ASSERT_EQ(disp,this->m_cmdSendCmdSeq); - // check argument - U32 checkVal; - ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(checkVal,testCmdArg); - } else { - // verify failed to find slot - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_TooManyCommands_SIZE(1); - } - } - - } - - void CommandDispatcherImplTester::runClearCommandTracking() { - - // verify dispatch table is empty - for (FwOpcodeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) { - ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false); - } - - // verify sequence tracker table is empty - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - // clear reg events - this->clearEvents(); - // register built-in commands - this->m_impl.regCommands(); - // verify registrations - ASSERT_TRUE(this->m_impl.m_entryTable[0].used); - ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP); - ASSERT_EQ(this->m_impl.m_entryTable[0].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[1].used); - ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING); - ASSERT_EQ(this->m_impl.m_entryTable[1].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[2].used); - ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1); - ASSERT_EQ(this->m_impl.m_entryTable[2].port,1); - - ASSERT_TRUE(this->m_impl.m_entryTable[3].used); - ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING); - ASSERT_EQ(this->m_impl.m_entryTable[3].port,1); - - // verify event - ASSERT_EVENTS_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered_SIZE(4); - ASSERT_EVENTS_OpCodeRegistered(0,CommandDispatcherImpl::OPCODE_CMD_NO_OP,1,0); - ASSERT_EVENTS_OpCodeRegistered(1,CommandDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1); - ASSERT_EVENTS_OpCodeRegistered(2,CommandDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2); - ASSERT_EVENTS_OpCodeRegistered(3,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3); - - // register our own command - FwOpcodeType testOpCode = 0x50; - U32 testContext = 13; - - this->clearEvents(); - this->invoke_to_compCmdReg(0,testOpCode); - ASSERT_TRUE(this->m_impl.m_entryTable[4].used); - ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode); - ASSERT_EQ(this->m_impl.m_entryTable[4].port,0); - - // verify registration event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered_SIZE(1); - ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4); - - // dispatch a test command - U32 testCmdArg = 100; - this->clearEvents(); - Fw::ComBuffer buff; - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,testOpCode,0); - - // verify sequence table entry - ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used); - ASSERT_EQ(0u,this->m_impl.m_sequenceTracker[0].seq); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext); - ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,0); - - // verify command received - ASSERT_TRUE(this->m_cmdSendRcvd); - ASSERT_EQ(this->m_cmdSendOpCode,testOpCode); - ASSERT_EQ(0u,this->m_cmdSendCmdSeq); - // check argument - U32 checkVal; - ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(checkVal,testCmdArg); - this->clearEvents(); - - // dispatch command to clear sequence tracker table - - buff.resetSer(); - ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK); - ASSERT_EQ(buff.serialize(static_cast(CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING)),Fw::FW_SERIALIZE_OK); - - this->invoke_to_seqCmdBuff(0,buff,testContext); - // send buffer to command dispatcher - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify dispatch event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched_SIZE(1); - ASSERT_EVENTS_OpCodeDispatched(0,CommandDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1); - - // dispatch command from dispatcher to command handler - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - // verify tracking table empty - for (U32 entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) { - ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false); - } - - clearHistory(); - // send command complete - this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::CmdResponse::OK); - ASSERT_EQ(Fw::QueuedComponentBase::MSG_DISPATCH_OK,this->m_impl.doDispatch()); - - // verify no status returned - ASSERT_CMD_RESPONSE_SIZE(0); - - } - - void CommandDispatcherImplTester::from_pingOut_handler( - const FwIndexType portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ) { - - } - -} /* namespace SvcTest */ diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp deleted file mode 100644 index 756c9cb11a1..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherImplTester.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * CommandDispatcherImplTester.hpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#ifndef CMDDISP_TEST_UT_TLMCHANIMPLTESTER_HPP_ -#define CMDDISP_TEST_UT_TLMCHANIMPLTESTER_HPP_ - -#include -#include - -namespace Svc { - - class CommandDispatcherImplTester: public CommandDispatcherGTestBase { - public: - CommandDispatcherImplTester(Svc::CommandDispatcherImpl& inst); - virtual ~CommandDispatcherImplTester(); - - void runNominalDispatch(); - void runInvalidOpcodeDispatch(); - void runCommandReregister(); - void runFailedCommand(); - void runInvalidCommand(); - void runOverflowCommands(); - void runNopCommands(); - void runClearCommandTracking(); - - private: - Svc::CommandDispatcherImpl& m_impl; - - void from_compCmdSend_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, Fw::CmdArgBuffer &args); - - void from_pingOut_handler( - const FwIndexType portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ); // store port call - bool m_cmdSendRcvd; - FwOpcodeType m_cmdSendOpCode; - U32 m_cmdSendCmdSeq; - Fw::CmdArgBuffer m_cmdSendArgs; - - void from_seqCmdStatus_handler(FwIndexType portNum, FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdResponse &response); - - bool m_seqStatusRcvd; - FwOpcodeType m_seqStatusOpCode; - U32 m_seqStatusCmdSeq; - Fw::CmdResponse m_seqStatusCmdResponse; - - }; - -} /* namespace Svc */ - -#endif /* CMDDISP_TEST_UT_TLMCHANIMPLTESTER_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp b/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp deleted file mode 100644 index eb236b79fa2..00000000000 --- a/Svc/Subtopologies/CDHCore/CmdDispatcher/test/ut/CommandDispatcherTester.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * CommandDispatcherTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include -#include -#include - -void connectPorts(Svc::CommandDispatcherImpl& impl, Svc::CommandDispatcherImplTester& tester) { - - //Fw::SimpleObjRegistry simpleReg; - - // command ports - tester.connect_to_compCmdStat(0,impl.get_compCmdStat_InputPort(0)); - tester.connect_to_seqCmdBuff(0,impl.get_seqCmdBuff_InputPort(0)); - tester.connect_to_compCmdReg(0,impl.get_compCmdReg_InputPort(0)); - - impl.set_compCmdSend_OutputPort(0,tester.get_from_compCmdSend(0)); - impl.set_seqCmdStatus_OutputPort(0,tester.get_from_seqCmdStatus(0)); - // local dispatcher command registration - impl.set_CmdReg_OutputPort(0,impl.get_compCmdReg_InputPort(1)); - impl.set_CmdStatus_OutputPort(0,impl.get_compCmdStat_InputPort(0)); - - impl.set_compCmdSend_OutputPort(1,impl.get_CmdDisp_InputPort(0)); - - impl.set_Tlm_OutputPort(0,tester.get_from_Tlm(0)); - impl.set_Time_OutputPort(0,tester.get_from_Time(0)); - - impl.set_Log_OutputPort(0,tester.get_from_Log(0)); - impl.set_LogText_OutputPort(0,tester.get_from_LogText(0)); - -#if FW_PORT_TRACING - //Fw::PortBase::setTrace(true); -#endif - - //simpleReg.dump(); - -} - -TEST(CmdDispTestNominal,NominalDispatch) { - - TEST_CASE(102.1.1,"Nominal Dispatch"); - COMMENT("Dispatch a series of commands and verify they are dispatched correctly."); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runNominalDispatch(); - -} - -TEST(CmdDispTestNominal,NopTest) { - - TEST_CASE(102.1.2,"NO_OP Command Test"); - COMMENT("Verify the test NO_OP commands by dispatching them."); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runNopCommands(); - -} - -TEST(CmdDispTestNominal, ReregisterCommand) { - - TEST_CASE(102.1.3,"Reregister Command"); - COMMENT("Verify user can call command registration port with the same opcode multiple times safely."); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runCommandReregister(); -} - -TEST(CmdDispTestOffNominal,InvalidOpcodeDispatch) { - - TEST_CASE(102.2.1,"Off-nominal Dispatch"); - COMMENT("Verify the correct handling of unregistered opcodes."); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runInvalidOpcodeDispatch(); - -} - -TEST(CmdDispTestOffNominal,FailedCommand) { - - TEST_CASE(102.2.2,"Off-nominal Failed command"); - COMMENT("Verify that failed commands operate correctly"); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runFailedCommand(); - -} - -TEST(CmdDispTestOffNominal,InvalidCommand) { - - TEST_CASE(102.2.3,"Off-nominal Invalid Command"); - COMMENT("Verify that malformed commands are detected."); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runInvalidCommand(); - -} - -TEST(CmdDispTestOffNominal,CommandOverflow) { - - TEST_CASE(102.2.4,"Off-nominal Command Overflow"); - COMMENT("Verify error case where there are too many outstanding commands."); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runOverflowCommands(); - -} - -TEST(CmdDispTestOffNominal,ClearSequenceTracker) { - - TEST_CASE(102.1.3,"Clear Command Tracker"); - COMMENT("Verify command to clear command tracker."); - - Svc::CommandDispatcherImpl impl("CmdDispImpl"); - - impl.init(10,0); - - Svc::CommandDispatcherImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - tester.runClearCommandTracking(); - -} - -#ifndef TGT_OS_TYPE_VXWORKS -int main(int argc, char* argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -#endif - diff --git a/Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp b/Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp deleted file mode 100644 index 6b6942e68ca..00000000000 --- a/Svc/Subtopologies/CDHCore/Subtopology/CDHCore.fpp +++ /dev/null @@ -1,28 +0,0 @@ -module CDHCore { - - instance cmdDisp: Svc.CommandDispatcher base id 0xFF2FF \ - queue size Defaults.QUEUE_SIZE \ - stack size Defaults.STACK_SIZE \ - priority 101 - - instance eventLogger: Svc.ActiveLogger base id 0x0B00 \ - queue size Default.queueSize \ - stack size Default.stackSize \ - priority 98 - - instance tlmSend: Svc.TlmChan base id 0x0C00 \ - queue size Default.queueSize \ - stack size Default.stackSize \ - priority 97 - - topology Subtopology { - instance cmdDisp - instance eventLogger - instance tlmSend - - command connections instance cmdDisp - event connections instance eventLogger - telemetry connections instance tlmSend - - } # end topology -} # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt b/Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt deleted file mode 100644 index bd026d036bd..00000000000 --- a/Svc/Subtopologies/CDHCore/Subtopology/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/CDHCore.fpp" - "${CMAKE_CURRENT_LIST_DIR}/intentionally-empty.cpp" -) - -register_fprime_module() - -# Set the module name explicitly to match what the build system expects -set_target_properties( - ${FPRIME_CURRENT_MODULE} - PROPERTIES - SOURCES "${CMAKE_CURRENT_LIST_DIR}/intentionally-empty.cpp" -) diff --git a/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt b/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt deleted file mode 100644 index c9aa9731749..00000000000 --- a/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/CmakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/config.fpp" -) - -register_fprime_module() diff --git a/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp b/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp deleted file mode 100644 index ac2f8abaeac..00000000000 --- a/Svc/Subtopologies/CDHCore/Subtopology/SubtopologyConfig/config.fpp +++ /dev/null @@ -1,13 +0,0 @@ -module Config { - # Base ID for your subtopology. All instantiated components will be offsets of this - constant CDHCoreSubtopology_BASE_ID = 0xFFFF0000 - - # include default Queue and Stack sizes here - module Defaults { - constant QUEUE_SIZE = 10 - constant STACK_SIZE = 64 * 1024 - } - - module Priorities { - } -} \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/Subtopology/intentionally-empty.cpp b/Svc/Subtopologies/CDHCore/Subtopology/intentionally-empty.cpp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt b/Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt deleted file mode 100644 index 273f4bfd2ff..00000000000 --- a/Svc/Subtopologies/CDHCore/TlmChan/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding files -# MOD_DEPS: (optional) module dependencies -# -# Note: using PROJECT_NAME as EXECUTABLE_NAME -#### -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/TlmChan.fpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChan.cpp" -) - -register_fprime_module() - -### UTs ### -set(UT_SOURCE_FILES - "${FPRIME_FRAMEWORK_PATH}/Svc/TlmChan/TlmChan.fpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanMain.cpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanTester.cpp" -) -register_fprime_ut() - diff --git a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp deleted file mode 100644 index 03fe9370db5..00000000000 --- a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/** - * \file - * \author T. Canham - * \brief Implementation file for channelized telemetry storage component - * - * \copyright - * Copyright 2009-2015, by the California Institute of Technology. - * ALL RIGHTS RESERVED. United States Government Sponsorship - * acknowledged. - *

- */ -#include -#include -#include -#include - -namespace Svc { - -// Definition of TLMCHAN_HASH_BUCKETS is >= number of telemetry ids -static_assert(std::numeric_limits::max() >= TLMCHAN_HASH_BUCKETS, - "Cannot have more hash buckets than maximum telemetry ids in the system"); -// TLMCHAN_HASH_BUCKETS >= TLMCHAN_NUM_TLM_HASH_SLOTS >= 0 -static_assert(std::numeric_limits::max() >= TLMCHAN_NUM_TLM_HASH_SLOTS, - "Cannot have more hash slots than maximum telemetry ids in the system"); - -TlmChan::TlmChan(const char* name) : TlmChanComponentBase(name), m_activeBuffer(0) { - // clear slot pointers - for (FwChanIdType entry = 0; entry < TLMCHAN_NUM_TLM_HASH_SLOTS; entry++) { - this->m_tlmEntries[0].slots[entry] = nullptr; - this->m_tlmEntries[1].slots[entry] = nullptr; - } - // clear buckets - for (FwChanIdType entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { - this->m_tlmEntries[0].buckets[entry].used = false; - this->m_tlmEntries[0].buckets[entry].updated = false; - this->m_tlmEntries[0].buckets[entry].bucketNo = entry; - this->m_tlmEntries[0].buckets[entry].next = nullptr; - this->m_tlmEntries[0].buckets[entry].id = 0; - this->m_tlmEntries[1].buckets[entry].used = false; - this->m_tlmEntries[1].buckets[entry].updated = false; - this->m_tlmEntries[1].buckets[entry].bucketNo = entry; - this->m_tlmEntries[1].buckets[entry].next = nullptr; - this->m_tlmEntries[1].buckets[entry].id = 0; - } - // clear free index - this->m_tlmEntries[0].free = 0; - this->m_tlmEntries[1].free = 0; -} - -TlmChan::~TlmChan() {} - -FwChanIdType TlmChan::doHash(FwChanIdType id) { - return (id % TLMCHAN_HASH_MOD_VALUE) % TLMCHAN_NUM_TLM_HASH_SLOTS; -} - -void TlmChan::pingIn_handler(const FwIndexType portNum, U32 key) { - // return key - this->pingOut_out(0, key); -} - -Fw::TlmValid TlmChan::TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { - // Compute index for entry - - FwChanIdType index = this->doHash(id); - - // Search to see if channel has been stored - // check both buffers - // don't need to lock because this port is guarded - TlmEntry* activeEntry = this->m_tlmEntries[this->m_activeBuffer].slots[index]; - for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - if (activeEntry) { // If bucket exists, check id - if (activeEntry->id == id) { - break; - } else { // otherwise go to next bucket - activeEntry = activeEntry->next; - } - } else { // no buckets left to search - break; - } - } - - TlmEntry* inactiveEntry = this->m_tlmEntries[1 - this->m_activeBuffer].slots[index]; - for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - if (inactiveEntry) { // If bucket exists, check id - if (inactiveEntry->id == id) { - break; - } else { // otherwise go to next bucket - inactiveEntry = inactiveEntry->next; - } - } else { // no buckets left to search - break; - } - } - - if (activeEntry && inactiveEntry) { - Fw::Time::Comparison cmp = Fw::Time::compare(inactiveEntry->lastUpdate, activeEntry->lastUpdate); - // two entries. grab the one with the most recent time tag - if (cmp == Fw::Time::Comparison::GT) { - // inactive entry is more recent - val = inactiveEntry->buffer; - timeTag = inactiveEntry->lastUpdate; - return Fw::TlmValid::VALID; - } else if (cmp != Fw::Time::Comparison::INCOMPARABLE) { - // active entry is more recent, or they are equal - val = activeEntry->buffer; - timeTag = activeEntry->lastUpdate; - return Fw::TlmValid::VALID; - } else { - // times are incomparable - // return the one that is updated, or if neither, - // default to active - if (inactiveEntry->updated) { - val = inactiveEntry->buffer; - timeTag = inactiveEntry->lastUpdate; - return Fw::TlmValid::VALID; - } else { - val = activeEntry->buffer; - timeTag = activeEntry->lastUpdate; - return Fw::TlmValid::VALID; - } - } - } else if (activeEntry) { - // only one entry, and it's in the active buf - val = activeEntry->buffer; - timeTag = activeEntry->lastUpdate; - return Fw::TlmValid::VALID; - } else if (inactiveEntry) { - // only one entry, and it's in the inactive buf - val = inactiveEntry->buffer; - timeTag = inactiveEntry->lastUpdate; - return Fw::TlmValid::VALID; - } else { - val.resetSer(); - } - return Fw::TlmValid::INVALID; -} - -void TlmChan::TlmRecv_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { - // Compute index for entry - - FwChanIdType index = this->doHash(id); - TlmEntry* entryToUse = nullptr; - TlmEntry* prevEntry = nullptr; - - // Search to see if channel has already been stored or a bucket needs to be added - if (this->m_tlmEntries[this->m_activeBuffer].slots[index]) { - entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; - // Loop one extra time so that we don't inadvertently fall through the end of the loop early. - for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS + 1; bucket++) { - if (entryToUse) { - if (entryToUse->id == id) { // found the matching entry - break; - } else { // try next entry - prevEntry = entryToUse; - entryToUse = entryToUse->next; - } - } else { - // Make sure that we haven't run out of buckets - FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); - // add new bucket from free list - entryToUse = - &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; - FW_ASSERT(prevEntry); - prevEntry->next = entryToUse; - // clear next pointer - entryToUse->next = nullptr; - break; - } - } - } else { - // Make sure that we haven't run out of buckets - FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); - // create new entry at slot head - this->m_tlmEntries[this->m_activeBuffer].slots[index] = - &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; - entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; - entryToUse->next = nullptr; - } - - // copy into entry - FW_ASSERT(entryToUse); - entryToUse->used = true; - entryToUse->id = id; - entryToUse->updated = true; - entryToUse->lastUpdate = timeTag; - entryToUse->buffer = val; -} - -void TlmChan::Run_handler(FwIndexType portNum, U32 context) { - // Only write packets if connected - if (not this->isConnected_PktSend_OutputPort(0)) { - return; - } - - // lock mutex long enough to modify active telemetry buffer - // so the data can be read without worrying about updates - this->lock(); - this->m_activeBuffer = 1 - this->m_activeBuffer; - // set activeBuffer to not updated - for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { - this->m_tlmEntries[this->m_activeBuffer].buckets[entry].updated = false; - } - this->unLock(); - - // go through each entry and send a packet if it has been updated - Fw::TlmPacket pkt; - pkt.resetPktSer(); - - for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { - TlmEntry* p_entry = &this->m_tlmEntries[1 - this->m_activeBuffer].buckets[entry]; - if ((p_entry->updated) && (p_entry->used)) { - Fw::SerializeStatus stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer); - - // check to see if this packet is full, if so, send it - if (Fw::FW_SERIALIZE_NO_ROOM_LEFT == stat) { - this->PktSend_out(0, pkt.getBuffer(), 0); - // reset packet for more entries - pkt.resetPktSer(); - // add entry to new packet - stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer); - // if this doesn't work, that means packet isn't big enough for - // even one channel, so assert - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast(stat)); - } else if (Fw::FW_SERIALIZE_OK == stat) { - // if there was still room, do nothing move on to the next channel in the packet - } else // any other status is an assert, since it shouldn't happen - { - FW_ASSERT(0, static_cast(stat)); - } - // flag as updated - p_entry->updated = false; - } // end if entry was updated - } // end for each entry - - // send remnant entries - if (pkt.getNumEntries() > 0) { - this->PktSend_out(0, pkt.getBuffer(), 0); - } -} // end run handler - -} // namespace Svc diff --git a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp deleted file mode 100644 index d15072ed08a..00000000000 --- a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.fpp +++ /dev/null @@ -1,26 +0,0 @@ -module Svc { - - @ A component for storing telemetry - active component TlmChan { - - @ Guarded port for receiving telemetry values - guarded input port TlmRecv: Fw.Tlm - - @ Guarded port for returning telemetry values by reference - guarded input port TlmGet: Fw.TlmGet - - @ Run port for starting packet send cycle - async input port Run: Svc.Sched - - @ Packet send port - output port PktSend: Fw.Com - - @ Ping input port - async input port pingIn: Svc.Ping - - @ Ping output port - output port pingOut: Svc.Ping - - } - -} diff --git a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp b/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp deleted file mode 100644 index 2bff852c880..00000000000 --- a/Svc/Subtopologies/CDHCore/TlmChan/TlmChan.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * \file - * \author T. Canham - * \brief Component that stores telemetry channel values - * - * \copyright - * Copyright 2009-2015, by the California Institute of Technology. - * ALL RIGHTS RESERVED. United States Government Sponsorship - * acknowledged. - *

- */ - -#ifndef TELEMCHANIMPL_HPP_ -#define TELEMCHANIMPL_HPP_ - -#include -#include -#include - -namespace Svc { - -class TlmChan final : public TlmChanComponentBase { - public: - TlmChan(const char* compName); - virtual ~TlmChan(); - - PROTECTED: - // can be overridden for alternate algorithms - virtual FwChanIdType doHash(FwChanIdType id); - - PRIVATE: - // Port functions - void TlmRecv_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val); - Fw::TlmValid TlmGet_handler(FwIndexType portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val); - void Run_handler(FwIndexType portNum, U32 context); - //! Handler implementation for pingIn - //! - void pingIn_handler(const FwIndexType portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ); - - typedef struct tlmEntry { - FwChanIdType id; //!< telemetry id stored in slot - bool updated; //!< set whenever a value has been written. Used to skip if writing out values for downlinking - Fw::Time lastUpdate; //!< last updated time - Fw::TlmBuffer buffer; //!< buffer to store serialized telemetry - tlmEntry* next; //!< pointer to next bucket in table - bool used; //!< if entry has been used - FwChanIdType bucketNo; //!< for testing - } TlmEntry; - - struct TlmSet { - TlmEntry* slots[TLMCHAN_NUM_TLM_HASH_SLOTS]; //!< set of hash slots in hash table - TlmEntry buckets[TLMCHAN_HASH_BUCKETS]; //!< set of buckets used in hash table - FwChanIdType free; //!< next free bucket - } m_tlmEntries[2]; - - U32 m_activeBuffer; // !< which buffer is active for storing telemetry -}; - -} // namespace Svc - -#endif /* TELEMCHANIMPL_HPP_ */ diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore b/Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore deleted file mode 100644 index 0b84df0f025..00000000000 --- a/Svc/Subtopologies/CDHCore/TlmChan/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.html \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Code.xlsx b/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Code.xlsx deleted file mode 100644 index e26db5630788353a8370595962b77bc29059b1aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31188 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 Nje+Qsr_O&}{Xe{#LI?l= diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Design.xlsx b/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Design.xlsx deleted file mode 100644 index 6562659be0cd899f6ef9ec482a06ee07d0c91937..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24324 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 W#71Uj|26qgph+S3A8HK$`t^U6*@cY& diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Unit_Test.xls b/Svc/Subtopologies/CDHCore/TlmChan/docs/Checklist_Unit_Test.xls deleted file mode 100644 index a0ceaa4b2702761f799c16c23ae3c1abcff967a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51712 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 diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/img/ExternalUserScenario.jpg b/Svc/Subtopologies/CDHCore/TlmChan/docs/img/ExternalUserScenario.jpg deleted file mode 100644 index b8cd0ba4453ce5faede457b2ee01c89573c503ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72528 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 diff --git a/Svc/Subtopologies/CDHCore/TlmChan/docs/img/TlmChanBDD.jpg b/Svc/Subtopologies/CDHCore/TlmChan/docs/img/TlmChanBDD.jpg deleted file mode 100644 index 7b61e1ab6742f06608673332aa57c43bdc4c50d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60478 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 I(NC}c4 -#include -#include -#include "TlmChanTester.hpp" - -TEST(TlmChanTest, InitTest) { - Svc::TlmChanTester tester; -} - -TEST(TlmChanTest, NominalChannelTest) { - TEST_CASE(107.1.1, "Nominal channelized telemetry"); - COMMENT("Write a single channel and verify it is read back and pushed correctly."); - - Svc::TlmChanTester tester; - // run test - tester.runNominalChannel(); -} - -TEST(TlmChanTest, MultiChannelTest) { - TEST_CASE(107.1.2, "Nominal Multi-channel channelized telemetry"); - COMMENT("Write multiple channels and verify they are read back and pushed correctly."); - - Svc::TlmChanTester tester; - - // run test - tester.runMultiChannel(); -} - -TEST(TlmChanTest, OffNominal) { - TEST_CASE(107.2.1, "Off-nominal channelized telemetry"); - COMMENT("Attempt to read a channel that hasn't been written."); - - Svc::TlmChanTester tester; - - // run test - tester.runOffNominal(); -} - -// TEST(TlmChanTest,TooManyChannels) { - -// COMMENT("Too Many Channel Test"); - -// Svc::TlmChanImpl impl("TlmChanImpl"); - -// impl.init(10,0); - -// Svc::TlmChanImplTester tester(impl); - -// tester.init(); - -// // connect ports -// connectPorts(impl,tester); - -// // run test -// tester.runTooManyChannels(); - -// } diff --git a/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp b/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp deleted file mode 100644 index 201e0026394..00000000000 --- a/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.cpp +++ /dev/null @@ -1,351 +0,0 @@ -// ====================================================================== -// \title TlmChan.hpp -// \author tcanham -// \brief cpp file for TlmChan test harness implementation class -// ====================================================================== - -#include "TlmChanTester.hpp" -#include - -#define INSTANCE 0 -#define MAX_HISTORY_SIZE 10 -#define QUEUE_DEPTH 10 - -static const FwChanIdType TEST_CHAN_SIZE = sizeof(FwChanIdType) + Fw::Time::SERIALIZED_SIZE + sizeof(U32); -static const FwChanIdType CHANS_PER_COMBUFFER = - (FW_COM_BUFFER_MAX_SIZE - sizeof(FwPacketDescriptorType)) / TEST_CHAN_SIZE; -static constexpr FwSizeType INTEGER_DIVISION_ROUNDED_UP(FwSizeType a, FwSizeType b) { - return ((a % b) == 0) ? (a / b) : (a / b) + 1; -} - -namespace Svc { - -// ---------------------------------------------------------------------- -// Construction and destruction -// ---------------------------------------------------------------------- - -TlmChanTester ::TlmChanTester() - : TlmChanGTestBase("Tester", MAX_HISTORY_SIZE), component("TlmChan"), m_numBuffs(0), m_bufferRecv(false) { - this->initComponents(); - this->connectPorts(); -} - -TlmChanTester ::~TlmChanTester() {} - -// ---------------------------------------------------------------------- -// Tests -// ---------------------------------------------------------------------- - -void TlmChanTester::runNominalChannel() { - this->clearBuffs(); - // send first buffer - this->sendBuff(27, 10); - this->doRun(true); - this->checkBuff(0, 1, 27, 10); - - this->clearBuffs(); - // send again to other buffer - this->sendBuff(27, 10); - - static bool tlc003 = false; - - if (not tlc003) { - REQUIREMENT("TLC-003"); - tlc003 = true; - } - - this->doRun(true); - this->checkBuff(0, 1, 27, 10); - - // do an update to make sure it gets updated and returned correctly - this->clearBuffs(); - this->sendBuff(27, 20); -} - -void TlmChanTester::runMultiChannel() { - FwChanIdType ID_0[] = {// Test channel IDs - 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1100, 0x1101, 0x1102, 0x1103, 0x300, - 0x301, 0x400, 0x401, 0x402, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105}; - - this->clearBuffs(); - // send all updates - for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_0); n++) { - this->sendBuff(ID_0[n], n); - } - - ASSERT_EQ(0, this->component.m_activeBuffer); - - // do a run, and all the packets should be sent - this->doRun(true); - ASSERT_TRUE(this->m_bufferRecv); - ASSERT_EQ(INTEGER_DIVISION_ROUNDED_UP(FW_NUM_ARRAY_ELEMENTS(ID_0), CHANS_PER_COMBUFFER), this->m_numBuffs); - ASSERT_EQ(1, this->component.m_activeBuffer); - - // verify packets - for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_0); n++) { - // printf("#: %d\n",n); - this->checkBuff(n, FW_NUM_ARRAY_ELEMENTS(ID_0), ID_0[n], n); - } - - // send another set - - FwChanIdType ID_1[] = {// Test channel IDs - 0x5000, 0x5001, 0x5002, 0x5003, 0x5004, 0x5005, 0x5100, 0x5101, 0x5102, - 0x5103, 0x6300, 0x6301, 0x6400, 0x6401, 0x6402, 0x6100, 0x6101, 0x6102, - 0x6103, 0x6104, 0x6105, 0x8101, 0x8102, 0x8103, 0x8104, 0x8105}; - - this->clearBuffs(); - // send all updates - for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_1); n++) { - this->sendBuff(ID_1[n], n); - } - - ASSERT_EQ(1, this->component.m_activeBuffer); - - // do a run, and all the packets should be sent - this->doRun(true); - ASSERT_TRUE(this->m_bufferRecv); - ASSERT_EQ(INTEGER_DIVISION_ROUNDED_UP(FW_NUM_ARRAY_ELEMENTS(ID_1), CHANS_PER_COMBUFFER), this->m_numBuffs); - ASSERT_EQ(0, this->component.m_activeBuffer); - - // verify packets - for (FwChanIdType n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_1); n++) { - // printf("#: %d\n",n); - this->checkBuff(n, FW_NUM_ARRAY_ELEMENTS(ID_1), ID_1[n], n); - } -} - -void TlmChanTester::runOffNominal() { - // Ask for a packet that isn't written yet - Fw::TlmBuffer buff; - Fw::SerializeStatus stat; - Fw::Time timeTag; - U32 val = 10; - - // create Telemetry item and put dummy data in to make sure it gets erased - buff.resetSer(); - stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); - - // Read back value - Fw::TlmValid valid = this->invoke_to_TlmGet(0, 10, timeTag, buff); - ASSERT_EQ(0u, buff.getBuffLength()); - ASSERT_EQ(valid, Fw::TlmValid::INVALID); - -} - -// ---------------------------------------------------------------------- -// Handlers for typed from ports -// ---------------------------------------------------------------------- - -void TlmChanTester ::from_PktSend_handler(const FwIndexType portNum, Fw::ComBuffer& data, U32 context) { - this->pushFromPortEntry_PktSend(data, context); - this->m_bufferRecv = true; - this->m_rcvdBuffer[this->m_numBuffs] = data; - this->m_numBuffs++; -} - -void TlmChanTester ::from_pingOut_handler(const FwIndexType portNum, U32 key) { - this->pushFromPortEntry_pingOut(key); -} - -// ---------------------------------------------------------------------- -// Helper methods -// ---------------------------------------------------------------------- - -bool TlmChanTester::doRun(bool check) { - // execute run port to send packet - this->invoke_to_Run(0, 0); - // dispatch run message - this->m_bufferRecv = false; - this->component.doDispatch(); - if (check) { - EXPECT_TRUE(this->m_bufferRecv); - } - return this->m_bufferRecv; -} - -void TlmChanTester::checkBuff(FwChanIdType chanNum, FwChanIdType totalChan, FwChanIdType id, U32 val) { - Fw::Time timeTag; - // deserialize packet - Fw::SerializeStatus stat; - - static bool tlc004 = false; - - if (not tlc004) { - REQUIREMENT("TLC-004"); - tlc004 = true; - } - - FwChanIdType currentChan = 0; - - // Search for channel ID - for (FwChanIdType packet = 0; packet < this->m_numBuffs; packet++) { - // Look at packet descriptor for current packet - this->m_rcvdBuffer[packet].resetDeser(); - // first piece should be tlm packet descriptor - FwPacketDescriptorType desc; - stat = this->m_rcvdBuffer[packet].deserialize(desc); - ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); - ASSERT_EQ(desc, static_cast(Fw::ComPacket::FW_PACKET_TELEM)); - - for (FwChanIdType chan = 0; chan < CHANS_PER_COMBUFFER; chan++) { - // decode channel ID - FwEventIdType sentId; - stat = this->m_rcvdBuffer[packet].deserialize(sentId); - ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); - - // next piece is time tag - Fw::Time recTimeTag(TB_NONE, 0, 0); - stat = this->m_rcvdBuffer[packet].deserialize(recTimeTag); - ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); - ASSERT_TRUE(timeTag == recTimeTag); - // next piece is event argument - U32 readVal; - stat = this->m_rcvdBuffer[packet].deserialize(readVal); - ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); - - if (chanNum == currentChan) { - ASSERT_EQ(id, sentId); - ASSERT_EQ(val, readVal); - } - - // quit if we are at max channel entry - if (currentChan == (totalChan - 1)) { - break; - } - - currentChan++; - } - - // packet should be empty - ASSERT_EQ(0, this->m_rcvdBuffer[packet].getBuffLeft()); - } -} - -void TlmChanTester::sendBuff(FwChanIdType id, U32 val) { - Fw::TlmBuffer buff; - Fw::TlmBuffer readBack; - Fw::SerializeStatus stat; - Fw::Time timeTag; - U32 retestVal; - - // create telemetry item - buff.resetSer(); - stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); - - static bool tlc001 = false; - - if (not tlc001) { - REQUIREMENT("TLC-001"); - tlc001 = true; - } - - this->invoke_to_TlmRecv(0, id, timeTag, buff); - // Read back value - static bool tlc002 = false; - - if (not tlc002) { - REQUIREMENT("TLC-002"); - tlc002 = true; - } - - Fw::TlmValid valid = this->invoke_to_TlmGet(0, id, timeTag, readBack); - // deserialize value - retestVal = 0; - readBack.deserialize(retestVal); - ASSERT_EQ(retestVal, val); - ASSERT_EQ(valid, Fw::TlmValid::VALID); -} - -void TlmChanTester::clearBuffs() { - this->m_numBuffs = 0; - for (FwChanIdType n = 0; n < TLMCHAN_HASH_BUCKETS; n++) { - this->m_rcvdBuffer[n].resetSer(); - } -} - -void TlmChanTester::dumpTlmEntry(TlmChan::TlmEntry* entry) { - printf( - "Entry " - " Ptr: %p" - " id: 0x%08X" - " bucket: %d" - " next: %p\n", - static_cast(entry), entry->id, entry->bucketNo, static_cast(entry->next)); -} - -void TlmChanTester::dumpHash() { - // printf("**Buffer 0\n"); - for (FwChanIdType slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { - printf("Slot: %d\n", slot); - if (this->component.m_tlmEntries[0].slots[slot]) { - TlmChan::TlmEntry* entry = component.m_tlmEntries[0].slots[slot]; - for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - dumpTlmEntry(entry); - if (entry->next == nullptr) { - break; - } else { - entry = entry->next; - } - } - } else { - printf("EMPTY\n"); - } - } - printf("\n"); - // for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - // printf("Bucket: %d ",bucket); - // dumpTlmEntry(&m_impl.m_tlmEntries[0].buckets[bucket]); - // } - // printf("**Buffer 1\n"); - // for (FwChanIdType slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { - // printf("Slot: %d\n",slot); - // if (m_impl.m_tlmEntries[1].slots[slot]) { - // TlmChanImpl::TlmEntry* entry = m_impl.m_tlmEntries[1].slots[slot]; - // for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - // dumpTlmEntry(entry); - // if (entry->next == 0) { - // break; - // } else { - // entry = entry->next; - // } - // } - // } else { - // printf("EMPTY\n"); - // } - // } - // printf("\n"); - // for (FwChanIdType bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - // printf("Bucket: %d\n",bucket); - // dumpTlmEntry(&m_impl.m_tlmEntries[1].buckets[bucket]); - // } -} - -void TlmChanTester ::connectPorts() { - // Run - this->connect_to_Run(0, this->component.get_Run_InputPort(0)); - - // TlmGet - this->connect_to_TlmGet(0, this->component.get_TlmGet_InputPort(0)); - - // TlmRecv - this->connect_to_TlmRecv(0, this->component.get_TlmRecv_InputPort(0)); - - // pingIn - this->connect_to_pingIn(0, this->component.get_pingIn_InputPort(0)); - - // PktSend - this->component.set_PktSend_OutputPort(0, this->get_from_PktSend(0)); - - // pingOut - this->component.set_pingOut_OutputPort(0, this->get_from_pingOut(0)); -} - -void TlmChanTester ::initComponents() { - this->init(); - this->component.init(QUEUE_DEPTH, INSTANCE); -} - -} // end namespace Svc diff --git a/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp b/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp deleted file mode 100644 index b0dc4c88e7e..00000000000 --- a/Svc/Subtopologies/CDHCore/TlmChan/test/ut/TlmChanTester.hpp +++ /dev/null @@ -1,95 +0,0 @@ -// ====================================================================== -// \title TlmChan/test/ut/Tester.hpp -// \author tcanham -// \brief hpp file for TlmChan test harness implementation class -// ====================================================================== - -#ifndef TESTER_HPP -#define TESTER_HPP - -#include "TlmChanGTestBase.hpp" -#include "Svc/TlmChan/TlmChan.hpp" - -namespace Svc { - -class TlmChanTester : public TlmChanGTestBase { - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - //! Construct object TlmChanTester - //! - TlmChanTester(); - - //! Destroy object TlmChanTester - //! - ~TlmChanTester(); - - public: - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void runNominalChannel(); - void runMultiChannel(); - void runOffNominal(); - - private: - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_PktSend - //! - void from_PktSend_handler(const FwIndexType 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 FwIndexType portNum, //!< The port number - U32 key //!< Value to return to pinger - ); - - private: - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - //! Connect ports - //! - void connectPorts(); - - //! Initialize components - //! - void initComponents(); - - void sendBuff(FwChanIdType id, U32 val); - bool doRun(bool check); - void checkBuff(FwChanIdType chanNum, FwChanIdType totalChan, FwChanIdType id, U32 val); - - void clearBuffs(); - - // dump functions - void dumpHash(); - static void dumpTlmEntry(TlmChan::TlmEntry* entry); - - private: - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - TlmChan component; - // Keep a history - FwChanIdType m_numBuffs; - Fw::ComBuffer m_rcvdBuffer[TLMCHAN_HASH_BUCKETS]; - bool m_bufferRecv; -}; - -} // end namespace Svc - -#endif diff --git a/Svc/Subtopologies/CMakeLists.txt b/Svc/Subtopologies/CMakeLists.txt index 31a6bed3130..e97b2bfb41a 100644 --- a/Svc/Subtopologies/CMakeLists.txt +++ b/Svc/Subtopologies/CMakeLists.txt @@ -1 +1,2 @@ -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") \ No newline at end of file +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") + From 7bdd72aeb5a0806c5dbf9fb6fb5f46a311e59473 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 5 Jun 2025 13:21:07 -0700 Subject: [PATCH 06/52] Health instance within CDHCore references CDHCoreConfig for queue size --- Svc/Subtopologies/CDHCore/CDHCore.fpp | 5 ++++- Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index bd4fa965f33..a5bfba858b2 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -16,18 +16,21 @@ module CDHCore { priority CDHCoreConfig.Priorities.tlmSend_PRIORITY instance $health: Svc.Health base id CDHCoreConfig.CDHCore_BASE_ID + 0x0400 \ - queue size 25 + queue size CDHCoreConfig.Defaults.$health_QUEUE_SIZE \ topology Subtopology { + #Active Components instance cmdDisp instance eventLogger instance tlmSend + #Queued Components instance $health command connections instance cmdDisp event connections instance eventLogger telemetry connections instance tlmSend + health connections instance $health } # end topology } # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp index 7b9faa0ff11..322046d9bb7 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -1,5 +1,5 @@ module CDHCoreConfig { - # Base ID for your subtopology. All instantiated components will be offsets of this + #Base ID for the CDHCore Subtopology, all components are offsets from this base ID constant CDHCore_BASE_ID = 0xFFFF0000 # include default Queue and Stack sizes here From 99f9deed13faf052c31193fcad2069ee9fc24a96 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 5 Jun 2025 20:22:22 +0000 Subject: [PATCH 07/52] Update metadata check-spelling run (push) for add-subtopologies Signed-off-by: check-spelling-bot on-behalf-of: @check-spelling --- .github/actions/spelling/expect.txt | 451 +--------------------------- 1 file changed, 3 insertions(+), 448 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index b816ce9ad15..4a513e2bcc6 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -1,7 +1,4 @@ Aadil -aarch -abcd -accurev AClass ACTIVELOGGER ACTIVELOGGERIMPL @@ -11,77 +8,40 @@ ACTIVERATEGROUP ACTIVERATEGROUPCFG ACTIVERATEGROUPIMPLTESTER ACTIVETEXTLOGGERIMPL -actools -addoffset adminlist -aeiouy -afterstatinfo ALLEXTERNALS alphanums ampcs -aname ANamespace -anotherchan -anotherparam -apad apid APIDOCS -aports -apos APPENDFILE aps -apxs -AQuat -AQueued -Arcsecond arduino ARef argcomplete -argcount ARGN -argname -argtype ARINC arpa ASize -ASTRING -ATester ATL -ATMs -ATSAM -atypes AUTOBRIEF autocode autocoded autocoders autocoding -autodocs -Autodocumentation -autogen -automodule AYYYY -backslashreplace baremetal -bashcompinit batchmode BDV bfree bibtex Bies BINDIR -binrel -Bitfields bitmaps -blogs bocchino -bodychars -bodytext -bools boolt -brc -bre bsd -bslash BUFFERALLOCATE BUFFERALLOCATIONFAILED BUFFERGETOUT @@ -90,50 +50,36 @@ BUFFERMGR BUFFERQUEUEIN BUFFERTOOSMALLFORDATA BUFFERTOOSMALLFORPACKET -buffsize BUGLIST bugprone -builddir -buildroot buildstep -bysource BYTEDRV calcu callergraph callgraph -caltech Campuzano carg -caselessmatch CBF CBLOCK CCB CComponent CCSDS ccsparc -cdefs CDH -cdn +CDHCORESUBTOPOLOGY cerrno -cface CFDP cff cflag cfsetispeed cfsetospeed -changeme -CHANNELID CHANS -cheetahtemplate Chieu CHIPINFO CHK CHNG CIRCULARSTATE classdiagram -classdoc -classtype -CLion CLOSEFILE cloudbees CMDDISP @@ -141,48 +87,33 @@ CMDDISPATCHER CMDPACKET CMDREG cmdresponse -cmds cmdseq cmdsequencer cntx -cobj CODEFILE -codeql -codestyle -coldarm COLORSTYLE colorwheel COMBUFFER comlogger COMMANDDISPATCHERIMPL COMMANDDISPATCHERIMPLCFG -commandline -commasepitem COMPACKET COMPACKETQUEUEIN -componentipcbuf -COMPONENTTESTERIMPL COMQUEUE -COMQUEUEIN COMSPLITTER COMSTUB constexpr cookiecutter cooldown -coor coravy coreutils -cosmosgen Coverity CPHA -Cpkt cplusplus CPOL -cpos cppcheck cppcheckxml cpplint -cprogramming CRCAMPCS crcccitt crcdnp @@ -195,63 +126,37 @@ crsmith crt CRTSCTS cryptsoft -csh -cshrc -cstat csum ctest ctu culates -currentxml cuz CYCLEOUT -daringfireball DATAROOTDIR -dawbarton DDDTHH -ddmm -dealloc Debian deconstructor -defaultgen -defname deframe deframed deframer deframing -delchars deployables DEPRECATEDLIST deser Deserial DEVICESM -dhesikan DHTML diafile -dictgen -dictvalue -diffs -digitalcommons diles dinkel -dlog dnp -docblocks docbook docset -docstyle -doctag -doinit -dontcare dontinclude doodie -dotfile DOTFONTPATH downcall -downfiles -dox doxyfile -doxygen doxygenversion doxyindexer doxyrules @@ -268,58 +173,34 @@ DPWRITER DRAINBUFFERS drv drvtcpserversocket -dsdl dspal Dstate -duey -dumparch -dumpobj DVI DWN eabi eabihf eay ECLIPSEHELP -edu -EGB EHAs eip -elist Elts -emoji -endcode endcond endfunction -endloc endmacro endraw enduml -ENQUEUEX -enumchan -enumname -enumparam -eobj -errfile ERRORCHECK errornum ert esb -ethanchee etl EVENTARRAY EVENTBOOL eventflags -EVENTID -eventname EVENTPRIMITIVE evr evt -EXAMPLECOMPONENTIMPL -excinfo -Exoplanets -exprtokens externalproject -Fabcdef FAKELOGGER fbuild fdp @@ -330,21 +211,15 @@ Ffs FILEDOWNLINK FILEDOWNLINKCFG FILEID -fileopen FILEOPENERROR FILEWRITEERROR fio -Firefox FLDP -flist FNDELAY -fns FONTPATH foodoodie foodoodiehoo -formatline FPCONFIG -fpi FPL fpp fppi @@ -352,71 +227,34 @@ fpptest fprime fptr fputil -fpv fpy FPYSEQUENCER freeram Fregoso -frox frsize fsblkcnt fsw FWCASSERT -gaurav -gbl gcda gcgandhi gcov gdiplus -gencode -genfile GENHUB -genshi -getarg -getargument -getblocks -getbody -getchildren -getcontext -getcrc -getdata -getdefaultencoding -getduration -getextern -getf -getfooter -geti -getinput -getlength -getm -getop -getquaternion -getschema -getstart -getstatement -gett gettime getty -getu -getwakeup ghprb gitmodules gmock -Gnc Gnd gnueabihf -google googletest Gorang -GPGGA -gpio gpiochip gpioevent gpiohandle gpioline Graphviz grayscales -grnd GROUNDINTERFACERULES GSE gtags @@ -432,10 +270,6 @@ hdr HEADERSIZE headlessly heapifying -hexid -hexnums -hexopcode -HFiles hhc hhk hhp @@ -447,37 +281,17 @@ HLTH HPSC htags HTH -htmlfile HTMLHELP -huey -HVisitor -hyperlinks ibd ieeetr -ifcomment iflag -ifname ifstr -ignorables -iif -ime imple -implgen -importables -INADDR inbool INCLUDEDIR -inin -initfiles initstate inkscape -Inputline installable -instantiator -instring -instrlen -integertypename -interoperate intlimits inttypes INVALIDBUFFER @@ -489,36 +303,23 @@ ioctl ipas IPCFG IPHELPER -ipriority -isequal isf -ishii -isoschematron isr -iss itimerspec itr itval -itype janamian Jax jdk jdperez jenkins jenkinsci -jishii Joaquim jobrestrictions -joshuaa jpl jplffs jre -jsdelivr -JSO -jsonable kermit -kevin -kislyuk kubiak Lammert lammertbies @@ -526,9 +327,7 @@ LASTLOG LBLOCK LCHILD leisher -lemstarch lestarch -levelname lflag lhash LIBCRYPTO @@ -536,32 +335,20 @@ LIBDIR LIBEXECDIR LIBLOC lic -lindent LINEEVENT LINEHANDLE linelength lineoffset -lineroo -linux -listdir -Listst -LJR lld llu LOCALSTATEDIR LOGGERRULES -loglvl LOGPACKET -logpath -Lps lseek -ltab -LTLT lvar LVL lxml MACROFILE -maincpp makefiles MAKEFLAGS makeindex @@ -569,24 +356,15 @@ MAKEVAR MALLOCALLOCATOR mallocator mathjax -maxdepth -maxloc -maxspew -mcomment MCT -mday MDFILE MEMALLOCATOR MEMB -membername memcheck -memname MEMTEST mentations mereweth Merewether -methoddoc -methodstub microcontrollers mkdocs mlc @@ -596,109 +374,58 @@ MML modbus MOSI MOVEFILE -mozilla -Mrf -Msap msc mscfile mseconds -msgs -msgtypeenum mstarch mstat MState -mstring -mtype multiarch -multioptionals -multirequired multitool -munmap mutexattr Mutexed -mval -MVC mycompany NACI nasafprime nbits ncsl -ndiffs -neascout -newloc -newroot -newself -newstring newtio -ninjaaron -NMEA nmsgs -noargport NOBLOCK -nogen -noncomma -NONINFRINGEMENT noparent norecords -normalwidths -NOSIZE NOSPEC nostdlib nosubgrouping notask -notchars -nproc NPROCESSORS NSHUFF NSPACES ntohs -nukenewlines -numargs -nxt -objclass objcopy -objdoc -objdump -objmodule -oclc oflag okidocki -oldeol OLDINCLUDEDIR OMG ONLN -OPCODEBASE openmct openpyxl openssldir -oper optarg optind -oran orgslist -ORhex -origfile -origstatinfo ortega OSAL -osaves -osets -ossw ostate OSTIME -otherdictitems -otheritems otherside outbool outdir -outout ovr packetization packetize packetized packetizer -Packetizing -Paetz PARAMARRAY PARAMARRAYEXTERNAL PARAMBOOL @@ -712,43 +439,26 @@ PARAMSTRINGEXTERNAL PARAMSTRUCT PARAMSTRUCTEXTERNAL PARAMU -parseable PASSIVERATEGROUP PASSIVERATEGROUPIMPLTESTER -pathmaker patsubst -pbuild -pcmake -pcomp pdflatex PEB -Peet penv PERLMOD PINGSEND -pinit pkill PKTS plainnat plantuml -pname PNGs pollfd POLLIN POLYDB -popd -portlist PORTOUT PORTSELECTOR -PORTSOUT ppandian -pport -PREDEF -preds pregen -preloc -preparse -printables prioritization PRIORITYQUEUE prm @@ -758,8 +468,6 @@ PRMDBIMPLTESTER PRMDBIMPLTESTERCFG PRMDBLIMPLCFG PRMLEDINITSTATE -prmname -probs PROCBUFFERSENDOUT PRODUCTGETIN PRODUCTREQUESTIN @@ -774,34 +482,17 @@ projectnumber propget propput protothreading -prototypetext -pstr -psyco ptbool -ptestrun ptf pthread -ptmcg ptrt -puml -punc -pushd -PYS -PYTHONPATH qch qhelpgenerator QHG qhp -QNX qsf -qthelpproject -Qualcomm -quatchan -RAbrack RAII -rancherdesktop randtbl -rapidscat raspberrypi raspi RATEGROUPDRIVER @@ -816,79 +507,46 @@ rcvd rdwr Readback Recvd -reder refspec REFTOPOLOGY REFTOPOLOGYDEFS regexs -relaxng REMOVEDIRECTORY REMOVEFILE -reparse reprioritize -reserializing -resname -resultlist -retobj RGD RHH -riverbankcomputing Rizvi ROOTDIR -ror -rowspan -rpaetz rpi RPIDEMO RPIDEMOCOMPONENTIMPLCFG rptr RSend -rtd -RTEMS -runperiod RXD -saddr SAlias sanitizers sats -savelist -saveop -sbb SBF SBINDIR sbom -Scatterometer -scc -schematron -sclk scm -scons sdd -SDFLIGHT searchdata SENDPARTIAL seqgen serializables setaffinity -setblocks -setdata -setid setinheritsched setlocalvar SETLOGGING -setm -setop setprotocol -setquaternion setschedparam setschedpolicy setstacksize settime -setversion sev -sface sfregoso -sgl SGN SHAREDSTATEDIR SHELLCOMMAND @@ -897,62 +555,38 @@ sideeffect sighandler Signedness Silveira -sinc sloc -smallsat -smcit socio SOCKETHELPER SOCKETIPDRIVER socklen -somechan -someenumchan -SOMEEVENT -Someother -someparam sometask somevalue sourced -SOURCEDIR -sourceforge -Sourcetrail sourcing -spacetech spdx -SPHINXBUILD -SPHINXOPTS spi spidev srandom -srange SRCS sreddy sss STAMEM -startloc startuml stdbool -STDC stddef stdint stest -stmtidx Stl +stmtidx STREQ STREQUAL -strg -stri -stringbuffer -stringchan -Stringpacket -stringparam STRINGUTILS STRNE strnlen subgrouping subhist subhistory -subpage subseconds subtargets subtopology @@ -962,12 +596,9 @@ SVCLOGFILE SVCLOGFILEL swcaegitadmin syft -synchronicity synopsys sysconf SYSCONFDIR -sysroot -tabbedwidths tabccitt tabdnp tabkermit @@ -976,43 +607,16 @@ tbase tcanham tcflush tcgetattr -tclist -tcomp -tcort TCPCLIENT TCPHELPER tcpserver TCSANOW -tcsh -tdir -tdirection telem TELEMCHANIMPL -testcmd -TESTCOMMAND -TESTCOMMANDSOURCEIMPL -testcomp -TESTCOMPONENTIMPL testerbase -testgen TESTLIST -TESTLOGRECVIMPL testmark -TESTPARAMIMPL -TESTPARAMRECVIMPL -TESTPTSOURCEIMPL -teststring -TESTTELEMRECVIMPL -TESTTEXTLOGIMPL -TESTTIMEIMPL -testutdir TESTUTILS -tfile -tflat -tfn -thepihut -Thhmmss -thiscol thisdirdoesnotexist thisfiledoesnotexist Thu @@ -1025,103 +629,54 @@ tions tjh TKC tlc -tlist tlm TLMCHAN TLMCHANIMPLCFG TLMCHANIMPLTESTER -tlmname TLMPACKET TLMPACKETIZER TLMPACKETIZERCOMPONENTIMPLCFG TLMPACKETIZERTYPES -tlmval -TML -tmpl -tmptokens -tmptree -tname -toctree TODOLIST -tokdict TOKENBUCKETTESTER -tokenlist -toklist -topologyapp topologydefs -TOTALFF -TOTALISFLOGEVENTMSG -TOTALISFTELMMSG -TOTALQUEUEFULL totalram tparam TPP -trimwhitespace trinomials -truncstring tts TXD -typedef typedef'ed -typelist -typeslist -typetoken +typedef uart -UBSAN -UDPRECEIVER -UDPRECEIVERCOMPONENTIMPLCFG -UDPSENDER -UDPSENDERCOMPONENTIMPLCFG UDPSOCKET UML UNEXP -UNINSTANTIATED unistd UNITTESTASSERT unittests -unprintables -upfiles -upl -usb useconds usecs -ustr -utdir valgrind vbai -vfd VFILE VID -viewcontent -viewforum vla -vlist VOXL -vtype -vuejs vwong vxworks -waitrel watney Wdog whitebox WLE -Wno WORKDIR -worklist wrs -wsl wxgui wxy -Xabcdefx Xapian xdf xdffe -Xelect -xmlfile xsltproc xxxx XXYY -yacgen zimri -zmq From 55bd6450d58553067fe68f7979eefea11277a14f Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 6 Jun 2025 10:21:43 -0700 Subject: [PATCH 08/52] Added AssertFatalAdapter Version PassiveTextLogger to Subtopology, config clarity improvements --- Ref/Top/RefPackets.fppi | 44 ++++++------ Ref/Top/RefTopology.cpp | 2 +- Ref/Top/RefTopologyDefs.hpp | 70 ++++++------------- Ref/Top/instances.fpp | 6 +- Ref/Top/topology.fpp | 14 ++-- Svc/Subtopologies/CDHCore/CDHCore.fpp | 48 ++++++++----- .../CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 30 ++++---- .../CDHCore/CDHCoreTopologyDefs.hpp | 6 +- 8 files changed, 104 insertions(+), 116 deletions(-) diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index 79f7a0fc4d8..7c35779c8a3 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -195,73 +195,73 @@ telemetry packets RefPackets { } packet Version1 id 22 group 2 { - Ref.version.FrameworkVersion - Ref.version.ProjectVersion + CDHCore.version.FrameworkVersion + CDHCore.version.ProjectVersion } packet Version_Library1 id 23 group 2 { - Ref.version.LibraryVersion01 - Ref.version.LibraryVersion02 + CDHCore.version.LibraryVersion01 + CDHCore.version.LibraryVersion02 } packet Version_Library2 id 24 group 2 { - Ref.version.LibraryVersion03 - Ref.version.LibraryVersion04 + CDHCore.version.LibraryVersion03 + CDHCore.version.LibraryVersion04 } packet Version_Library3 id 25 group 2 { - Ref.version.LibraryVersion05 - Ref.version.LibraryVersion06 + CDHCore.version.LibraryVersion05 + CDHCore.version.LibraryVersion06 } packet Version_Library4 id 26 group 2 { - Ref.version.LibraryVersion07 - Ref.version.LibraryVersion08 + CDHCore.version.LibraryVersion07 + CDHCore.version.LibraryVersion08 } packet Version_Library5 id 27 group 2 { - Ref.version.LibraryVersion09 - Ref.version.LibraryVersion10 + CDHCore.version.LibraryVersion09 + CDHCore.version.LibraryVersion10 } packet Version_Custom1 id 28 group 2 { - Ref.version.CustomVersion01 + CDHCore.version.CustomVersion01 } packet Version_Custom2 id 29 group 2 { - Ref.version.CustomVersion02 + CDHCore.version.CustomVersion02 } packet Version_Custom3 id 30 group 2 { - Ref.version.CustomVersion03 + CDHCore.version.CustomVersion03 } packet Version_Custom4 id 31 group 2 { - Ref.version.CustomVersion04 + CDHCore.version.CustomVersion04 } packet Version_Custom5 id 32 group 2 { - Ref.version.CustomVersion05 + CDHCore.version.CustomVersion05 } packet Version_Custom6 id 33 group 2 { - Ref.version.CustomVersion06 + CDHCore.version.CustomVersion06 } packet Version_Custom7 id 34 group 2 { - Ref.version.CustomVersion07 + CDHCore.version.CustomVersion07 } packet Version_Custom8 id 35 group 2 { - Ref.version.CustomVersion08 + CDHCore.version.CustomVersion08 } packet Version_Custom9 id 36 group 2 { - Ref.version.CustomVersion09 + CDHCore.version.CustomVersion09 } packet Version_Custom10 id 37 group 2 { - Ref.version.CustomVersion10 + CDHCore.version.CustomVersion10 } } omit { diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 2d27408c125..a3be7fb081a 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -168,7 +168,7 @@ void setupTopology(const TopologyState& state) { // Autocoded task kick-off (active components). Function provided by autocoder. startTasks(state); // Startup TLM and Config verbosity for Versions - version.config(true); + CDHCore::version.config(true); // Initialize socket client communication if and only if there is a valid specification if (state.hostname != nullptr && state.port != 0) { Os::TaskString name("ReceiveTask"); diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index c4f63019444..a431a87fadb 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -19,57 +19,33 @@ // Subtopology includes #include "Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp" -namespace GlobalDefs { namespace PingEntries { -namespace Ref_blockDrv { -enum { WARN = 3, FATAL = 5 }; -} -/* For the purposes of the subtopology -namespace Ref_tlmSend { -enum { WARN = 3, FATAL = 5 }; -} + namespace Ref_blockDrv {enum { WARN = 3, FATAL = 5 };} + namespace Ref_cmdSeq {enum { WARN = 3, FATAL = 5 };} + namespace Ref_fileDownlink {enum { WARN = 3, FATAL = 5 };} + namespace Ref_fileManager {enum { WARN = 3, FATAL = 5 };} + namespace Ref_fileUplink {enum { WARN = 3, FATAL = 5 };} + namespace Ref_pingRcvr {enum { WARN = 3, FATAL = 5 };} + namespace Ref_prmDb {enum { WARN = 3, FATAL = 5 };} + namespace Ref_rateGroup1Comp {enum { WARN = 3, FATAL = 5 };} + namespace Ref_rateGroup2Comp {enum { WARN = 3, FATAL = 5 };} + namespace Ref_rateGroup3Comp {enum { WARN = 3, FATAL = 5 };} + namespace Ref_dpCat {enum { WARN = 3, FATAL = 5 };} + /* For the purposes of the subtopology, we comment out what is included in the it + namespace Ref_tlmSend { + enum { WARN = 3, FATAL = 5 }; + } -namespace Ref_cmdDisp { -enum { WARN = 3, FATAL = 5 }; -} + namespace Ref_cmdDisp { + enum { WARN = 3, FATAL = 5 }; + } -namespace Ref_eventLogger { -enum { WARN = 3, FATAL = 5 }; -} + namespace Ref_eventLogger { + enum { WARN = 3, FATAL = 5 }; + } -*/ -namespace Ref_cmdSeq { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_fileDownlink { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_fileManager { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_fileUplink { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_pingRcvr { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_prmDb { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_rateGroup1Comp { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_rateGroup2Comp { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_rateGroup3Comp { -enum { WARN = 3, FATAL = 5 }; -} -namespace Ref_dpCat { -enum { WARN = 3, FATAL = 5 }; -} + */ } // namespace PingEntries -} /** * \brief required ping constants * @@ -106,7 +82,7 @@ struct TopologyState { U16 port; }; -namespace PingEntries = ::GlobalDefs::PingEntries; +namespace PingEntries = ::PingEntries; } // namespace Ref diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 398189f2992..63b015ddd94 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -145,7 +145,7 @@ module Ref { @ Communications driver. May be swapped with other comm drivers like UART instance comDriver: Drv.TcpClient base id 0x4000 - instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4100 + #instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4100 instance fatalHandler: Svc.FatalHandler base id 0x4200 @@ -157,9 +157,9 @@ module Ref { instance recvBuffComp: Ref.RecvBuff base id 0x4600 - instance version: Svc.Version base id 0x4700 + #instance version: Svc.Version base id 0x4700 - instance textLogger: Svc.PassiveTextLogger base id 0x4800 + #instance textLogger: Svc.PassiveTextLogger base id 0x4800 instance systemResources: Svc.SystemResources base id 0x4900 diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 2b183f4b547..df2c6919821 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -45,7 +45,7 @@ module Ref { instance comQueue instance deframer #instance eventLogger - instance fatalAdapter + #instance fatalAdapter instance fatalHandler instance fileDownlink instance fileManager @@ -63,14 +63,14 @@ module Ref { instance recvBuffComp instance fprimeRouter instance sendBuffComp - instance textLogger + #instance textLogger instance typeDemo instance systemResources instance dpCat instance dpMgr instance dpWriter instance dpBufferManager - instance version + #instance version instance linuxTimer # ---------------------------------------------------------------------- @@ -79,13 +79,13 @@ module Ref { command connections instance CDHCore.cmdDisp - event connections instance CDHCore.eventLogger + event connections instance CDHCore.events param connections instance prmDb telemetry connections instance CDHCore.tlmSend - text event connections instance textLogger + text event connections instance CDHCore.textLogger time connections instance posixTime @@ -106,7 +106,7 @@ module Ref { dpCat.fileOut -> fileDownlink.SendFile fileDownlink.FileComplete -> dpCat.fileDone # Inputs to ComQueue (events, telemetry, file) - CDHCore.eventLogger.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] + CDHCore.events.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] CDHCore.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn @@ -129,7 +129,7 @@ module Ref { } connections FaultProtection { - CDHCore.eventLogger.FatalAnnounce -> fatalHandler.FatalReceive + CDHCore.events.FatalAnnounce -> fatalHandler.FatalReceive } connections RateGroups { diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index a5bfba858b2..4fc32e272ab 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -1,36 +1,50 @@ module CDHCore { - + # ---------------------------------------------------------------------- + # Active Components + # ---------------------------------------------------------------------- instance cmdDisp: Svc.CommandDispatcher base id CDHCoreConfig.CDHCore_BASE_ID + 0x0100 \ - queue size CDHCoreConfig.Defaults.cmdDisp_QUEUE_SIZE \ - stack size CDHCoreConfig.Defaults.cmdDisp_STACK_SIZE \ - priority CDHCoreConfig.Priorities.cmdDisp_PRIORITY + queue size CDHCoreConfig.QueueSizes.cmdDisp \ + stack size CDHCoreConfig.StackSizes.cmdDisp \ + priority CDHCoreConfig.Priorities.cmdDisp - instance eventLogger: Svc.ActiveLogger base id CDHCoreConfig.CDHCore_BASE_ID + 0x0200 \ - queue size CDHCoreConfig.Defaults.eventLogger_QUEUE_SIZE \ - stack size CDHCoreConfig.Defaults.eventLogger_STACK_SIZE \ - priority CDHCoreConfig.Priorities.eventLogger_PRIORITY + instance events: Svc.ActiveLogger base id CDHCoreConfig.CDHCore_BASE_ID + 0x0200 \ + queue size CDHCoreConfig.QueueSizes.events \ + stack size CDHCoreConfig.StackSizes.events \ + priority CDHCoreConfig.Priorities.events instance tlmSend: Svc.TlmChan base id CDHCoreConfig.CDHCore_BASE_ID + 0x0300 \ - queue size CDHCoreConfig.Defaults.tlmSend_QUEUE_SIZE \ - stack size CDHCoreConfig.Defaults.tlmSend_STACK_SIZE \ - priority CDHCoreConfig.Priorities.tlmSend_PRIORITY + queue size CDHCoreConfig.QueueSizes.tlmSend \ + stack size CDHCoreConfig.StackSizes.tlmSend \ + priority CDHCoreConfig.Priorities.tlmSend + # ---------------------------------------------------------------------- + # Queued Components + # ---------------------------------------------------------------------- instance $health: Svc.Health base id CDHCoreConfig.CDHCore_BASE_ID + 0x0400 \ - queue size CDHCoreConfig.Defaults.$health_QUEUE_SIZE \ + queue size CDHCoreConfig.QueueSizes.$health \ + + # ---------------------------------------------------------------------- + # Passive Components + # ---------------------------------------------------------------------- + instance version: Svc.Version base id CDHCoreConfig.CDHCore_BASE_ID + 0x0500 \ + + instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.CDHCore_BASE_ID + 0x0600 \ + + instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.CDHCore_BASE_ID + 0x0700 \ topology Subtopology { #Active Components instance cmdDisp - instance eventLogger + instance events instance tlmSend #Queued Components instance $health - command connections instance cmdDisp - event connections instance eventLogger - telemetry connections instance tlmSend - health connections instance $health + #Passive Components + instance version + instance textLogger + instance fatalAdapter } # end topology } # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp index 322046d9bb7..2bcb2687cbe 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -2,24 +2,24 @@ module CDHCoreConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID constant CDHCore_BASE_ID = 0xFFFF0000 - # include default Queue and Stack sizes here - module Defaults { - constant cmdDisp_QUEUE_SIZE = 10 - constant cmdDisp_STACK_SIZE = 64 * 1024 - - constant eventLogger_QUEUE_SIZE = 10 - constant eventLogger_STACK_SIZE = 10 - - constant tlmSend_QUEUE_SIZE = 10 - constant tlmSend_STACK_SIZE = 64 * 1024 + module QueueSizes { + constant cmdDisp = 10 + constant events = 10 + constant tlmSend = 10 + constant $health = 25 + } + - constant $health_QUEUE_SIZE = 25 + module StackSizes { + constant cmdDisp = 64 * 1024 + constant events = 10 + constant tlmSend = 64 * 1024 } module Priorities { - constant cmdDisp_PRIORITY = 101 - constant $health_PRIORITY = 100 - constant eventLogger_PRIORITY = 99 - constant tlmSend_PRIORITY = 98 + constant cmdDisp = 101 + constant $health = 100 + constant events = 99 + constant tlmSend = 98 } } \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp b/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp index e922962e632..14816869c20 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp @@ -8,12 +8,10 @@ namespace CDHCore { }; } -namespace GlobalDefs { namespace PingEntries { - struct CDHCore_cmdDisp { enum { WARN=3, FATAL=5 }; }; - struct CDHCore_eventLogger { enum { WARN=3, FATAL=5 }; }; + struct CDHCore_cmdDisp { enum { WARN=3, FATAL=5 }; }; + struct CDHCore_events { enum { WARN=3, FATAL=5 }; }; struct CDHCore_tlmSend { enum { WARN=3, FATAL=5 }; }; } -} #endif \ No newline at end of file From 747d8de5f8549b10b1bb5fd6a10fc2322a9ff753 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 6 Jun 2025 14:22:25 -0700 Subject: [PATCH 09/52] Comms subtopology without cmdSeq created, integrated in Ref --- Ref/Top/RefPackets.fppi | 14 +-- Ref/Top/RefTopology.cpp | 19 +-- Ref/Top/instances.fpp | 14 +-- Ref/Top/topology.fpp | 77 ++----------- Svc/Subtopologies/CDHCore/CDHCore.fpp | 14 +-- .../CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 2 +- Svc/Subtopologies/CMakeLists.txt | 1 + Svc/Subtopologies/Comms/CMakeLists.txt | 9 ++ Svc/Subtopologies/Comms/Comms.fpp | 108 ++++++++++++++++++ .../Comms/CommsConfig/CMakeLists.txt | 5 + .../Comms/CommsConfig/CommsConfig.fpp | 17 +++ Svc/Subtopologies/Comms/CommsTopologyDefs.hpp | 14 +++ 12 files changed, 197 insertions(+), 97 deletions(-) create mode 100644 Svc/Subtopologies/Comms/CMakeLists.txt create mode 100644 Svc/Subtopologies/Comms/Comms.fpp create mode 100644 Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt create mode 100644 Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp create mode 100644 Svc/Subtopologies/Comms/CommsTopologyDefs.hpp diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index 7c35779c8a3..cf0bc1365c0 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -12,14 +12,14 @@ telemetry packets RefPackets { Ref.cmdSeq.CS_SequencesCompleted Ref.fileUplink.FilesReceived Ref.fileUplink.PacketsReceived - Ref.commsBufferManager.TotalBuffs - Ref.commsBufferManager.CurrBuffs - Ref.commsBufferManager.HiBuffs + Comms.commsBufferManager.TotalBuffs + Comms.commsBufferManager.CurrBuffs + Comms.commsBufferManager.HiBuffs Ref.fileDownlink.FilesSent Ref.fileDownlink.PacketsSent Ref.fileManager.CommandsExecuted - Ref.comQueue.comQueueDepth - Ref.comQueue.buffQueueDepth + Comms.comQueue.comQueueDepth + Comms.comQueue.buffQueueDepth # Ref.tlmSend.SendLevel } @@ -32,8 +32,8 @@ telemetry packets RefPackets { Ref.fileDownlink.Warnings CDHCore.$health.PingLateWarnings Ref.fileManager.Errors - Ref.commsBufferManager.NoBuffs - Ref.commsBufferManager.EmptyBuffs + Comms.commsBufferManager.NoBuffs + Comms.commsBufferManager.EmptyBuffs Ref.fileManager.Errors } diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index a3be7fb081a..fc971c9a1d1 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -22,6 +22,7 @@ //Subtopology includes #include +#include // Allows easy reference to objects in FPP/autocoder required namespaces using namespace Ref; @@ -109,7 +110,7 @@ void configureTopology() { commsBuffMgrBins.bins[0].numBuffers = COMMS_BUFFER_MANAGER_STORE_COUNT; commsBuffMgrBins.bins[1].bufferSize = COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; commsBuffMgrBins.bins[1].numBuffers = COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; - commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins); + Comms::commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins); Svc::BufferManager::BufferBins dpBuffMgrBins; memset(&dpBuffMgrBins, 0, sizeof(dpBuffMgrBins)); @@ -117,7 +118,7 @@ void configureTopology() { dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT; dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins); - frameAccumulator.configure(frameDetector, 1, mallocator, 2048); + Comms::frameAccumulator.configure(frameDetector, 1, mallocator, 2048); Fw::FileNameString dpDir("./DpCat"); Fw::FileNameString dpState("./DpCat/DpState.dat"); @@ -139,7 +140,7 @@ void configureTopology() { configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100; configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1; // Allocation identifier is 0 as the MallocAllocator discards it - comQueue.configure(configurationTable, 0, mallocator); + Comms::comQueue.configure(configurationTable, 0, mallocator); // Note: Uncomment when using Svc:TlmPacketizer // tlmSend.setPacketList(Ref::Ref_RefPacketsTlmPackets::packetList, Ref::Ref_RefPacketsTlmPackets::omittedChannels, 1); @@ -159,7 +160,7 @@ void setupTopology(const TopologyState& state) { // Autocoded configuration. Function provided by autocoder. configComponents(state); if (state.hostname != nullptr && state.port != 0) { - comDriver.configure(state.hostname, state.port); + Comms::comDriver.configure(state.hostname, state.port); } // Project-specific component configuration. Function provided above. May be inlined, if desired. configureTopology(); @@ -173,7 +174,7 @@ void setupTopology(const TopologyState& state) { if (state.hostname != nullptr && state.port != 0) { Os::TaskString name("ReceiveTask"); // Uplink is configured for receive so a socket task is started - comDriver.start(name, COMM_PRIORITY, Default::STACK_SIZE); + Comms::comDriver.start(name, COMM_PRIORITY, Default::STACK_SIZE); } } @@ -195,12 +196,12 @@ void teardownTopology(const TopologyState& state) { freeThreads(state); // Other task clean-up. - comDriver.stop(); - (void)comDriver.join(); + Comms::comDriver.stop(); + (void)Comms::comDriver.join(); // Resource deallocation cmdSeq.deallocateBuffer(mallocator); - commsBufferManager.cleanup(); - frameAccumulator.cleanup(); + Comms::commsBufferManager.cleanup(); + Comms::frameAccumulator.cleanup(); } } // namespace Ref diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 63b015ddd94..05166ba6a83 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -143,13 +143,13 @@ module Ref { # ---------------------------------------------------------------------- @ Communications driver. May be swapped with other comm drivers like UART - instance comDriver: Drv.TcpClient base id 0x4000 + #instance comDriver: Drv.TcpClient base id 0x4000 #instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4100 instance fatalHandler: Svc.FatalHandler base id 0x4200 - instance commsBufferManager: Svc.BufferManager base id 0x4300 + #instance commsBufferManager: Svc.BufferManager base id 0x4300 instance posixTime: Svc.PosixTime base id 0x4400 @@ -165,15 +165,15 @@ module Ref { instance dpBufferManager: Svc.BufferManager base id 0x4A00 - instance frameAccumulator: Svc.FrameAccumulator base id 0x4B00 + #instance frameAccumulator: Svc.FrameAccumulator base id 0x4B00 - instance deframer: Svc.FprimeDeframer base id 0x4C00 + #instance deframer: Svc.FprimeDeframer base id 0x4C00 - instance fprimeRouter: Svc.FprimeRouter base id 0x4D00 + #instance fprimeRouter: Svc.FprimeRouter base id 0x4D00 - instance fprimeFramer: Svc.FprimeFramer base id 0x4E00 + #instance fprimeFramer: Svc.FprimeFramer base id 0x4E00 - instance comStub: Svc.ComStub base id 0x4F00 + #instance comStub: Svc.ComStub base id 0x4F00 instance linuxTimer: Svc.LinuxTimer base id 0x5000 diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index df2c6919821..0f474c2d50d 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -25,6 +25,7 @@ module Ref { # Subtopology imports # ---------------------------------------------------------------------- import CDHCore.Subtopology + import Comms.Subtopology # ---------------------------------------------------------------------- # Instances used in the topology @@ -40,19 +41,19 @@ module Ref { #instance tlmSend #instance cmdDisp instance cmdSeq - instance comDriver - instance comStub - instance comQueue - instance deframer + #instance comDriver + #instance comStub + #instance comQueue + #instance deframer #instance eventLogger #instance fatalAdapter instance fatalHandler instance fileDownlink instance fileManager instance fileUplink - instance commsBufferManager - instance frameAccumulator - instance fprimeFramer + #instance Comms.commsBufferManager + #instance frameAccumulator + #instance fprimeFramer instance posixTime instance pingRcvr instance prmDb @@ -61,7 +62,7 @@ module Ref { instance rateGroup3Comp instance rateGroupDriverComp instance recvBuffComp - instance fprimeRouter + #instance fprimeRouter instance sendBuffComp #instance textLogger instance typeDemo @@ -101,33 +102,6 @@ module Ref { # Direct graph specifiers # ---------------------------------------------------------------------- - connections Downlink { - # Data Products - dpCat.fileOut -> fileDownlink.SendFile - fileDownlink.FileComplete -> dpCat.fileDone - # Inputs to ComQueue (events, telemetry, file) - CDHCore.events.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] - CDHCore.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] - fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] - comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn - # ComQueue <-> Framer - comQueue.dataOut -> fprimeFramer.dataIn - fprimeFramer.dataReturnOut -> comQueue.dataReturnIn - # Buffer Management for Framer - fprimeFramer.bufferAllocate -> commsBufferManager.bufferGetCallee - fprimeFramer.bufferDeallocate -> commsBufferManager.bufferSendIn - # Framer <-> ComStub - fprimeFramer.dataOut -> comStub.dataIn - comStub.dataReturnOut -> fprimeFramer.dataReturnIn - # ComStub <-> ComDriver - comStub.drvSendOut -> comDriver.$send - comDriver.sendReturnOut -> comStub.drvSendReturnIn - comDriver.ready -> comStub.drvConnected - # ComStatus - comStub.comStatusOut -> fprimeFramer.comStatusIn - fprimeFramer.comStatusOut -> comQueue.comStatusIn - } - connections FaultProtection { CDHCore.events.FatalAnnounce -> fatalHandler.FatalReceive } @@ -144,7 +118,7 @@ module Ref { rateGroup1Comp.RateGroupMemberOut[2] -> CDHCore.tlmSend.Run rateGroup1Comp.RateGroupMemberOut[3] -> fileDownlink.Run rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run - rateGroup1Comp.RateGroupMemberOut[5] -> comQueue.run + rateGroup1Comp.RateGroupMemberOut[5] -> Comms.comQueue.run # Rate group 2 rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup2] -> rateGroup2Comp.CycleIn @@ -158,7 +132,7 @@ module Ref { rateGroup3Comp.RateGroupMemberOut[0] -> CDHCore.$health.Run rateGroup3Comp.RateGroupMemberOut[1] -> SG5.schedIn rateGroup3Comp.RateGroupMemberOut[2] -> blockDrv.Sched - rateGroup3Comp.RateGroupMemberOut[3] -> commsBufferManager.schedIn + rateGroup3Comp.RateGroupMemberOut[3] -> Comms.commsBufferManager.schedIn rateGroup3Comp.RateGroupMemberOut[4] -> dpBufferManager.schedIn rateGroup3Comp.RateGroupMemberOut[5] -> dpWriter.schedIn rateGroup3Comp.RateGroupMemberOut[6] -> dpMgr.schedIn @@ -174,35 +148,6 @@ module Ref { CDHCore.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn } - connections Uplink { - # ComDriver buffer allocations - comDriver.allocate -> commsBufferManager.bufferGetCallee - comDriver.deallocate -> commsBufferManager.bufferSendIn - # ComDriver <-> ComStub - comDriver.$recv -> comStub.drvReceiveIn - comStub.drvReceiveReturnOut -> comDriver.recvReturnIn - # ComStub <-> FrameAccumulator - comStub.dataOut -> frameAccumulator.dataIn - frameAccumulator.dataReturnOut -> comStub.dataReturnIn - # FrameAccumulator buffer allocations - frameAccumulator.bufferDeallocate -> commsBufferManager.bufferSendIn - frameAccumulator.bufferAllocate -> commsBufferManager.bufferGetCallee - # FrameAccumulator <-> Deframer - frameAccumulator.dataOut -> deframer.dataIn - deframer.dataReturnOut -> frameAccumulator.dataReturnIn - # Deframer <-> Router - deframer.dataOut -> fprimeRouter.dataIn - fprimeRouter.dataReturnOut -> deframer.dataReturnIn - # Router buffer allocations - fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee - fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn - # Router <-> CmdDispatcher/FileUplink - fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn - fprimeRouter.fileOut -> fileUplink.bufferSendIn - fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn - } - connections DataProducts { # DpMgr and DpWriter connections. Have explicit port indexes for demo dpMgr.bufferGetOut[0] -> dpBufferManager.bufferGetCallee diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index 4fc32e272ab..238ca222d02 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -2,17 +2,17 @@ module CDHCore { # ---------------------------------------------------------------------- # Active Components # ---------------------------------------------------------------------- - instance cmdDisp: Svc.CommandDispatcher base id CDHCoreConfig.CDHCore_BASE_ID + 0x0100 \ + instance cmdDisp: Svc.CommandDispatcher base id CDHCoreConfig.BASE_ID + 0x0100 \ queue size CDHCoreConfig.QueueSizes.cmdDisp \ stack size CDHCoreConfig.StackSizes.cmdDisp \ priority CDHCoreConfig.Priorities.cmdDisp - instance events: Svc.ActiveLogger base id CDHCoreConfig.CDHCore_BASE_ID + 0x0200 \ + instance events: Svc.ActiveLogger base id CDHCoreConfig.BASE_ID + 0x0200 \ queue size CDHCoreConfig.QueueSizes.events \ stack size CDHCoreConfig.StackSizes.events \ priority CDHCoreConfig.Priorities.events - instance tlmSend: Svc.TlmChan base id CDHCoreConfig.CDHCore_BASE_ID + 0x0300 \ + instance tlmSend: Svc.TlmChan base id CDHCoreConfig.BASE_ID + 0x0300 \ queue size CDHCoreConfig.QueueSizes.tlmSend \ stack size CDHCoreConfig.StackSizes.tlmSend \ priority CDHCoreConfig.Priorities.tlmSend @@ -20,17 +20,17 @@ module CDHCore { # ---------------------------------------------------------------------- # Queued Components # ---------------------------------------------------------------------- - instance $health: Svc.Health base id CDHCoreConfig.CDHCore_BASE_ID + 0x0400 \ + instance $health: Svc.Health base id CDHCoreConfig.BASE_ID + 0x0400 \ queue size CDHCoreConfig.QueueSizes.$health \ # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - instance version: Svc.Version base id CDHCoreConfig.CDHCore_BASE_ID + 0x0500 \ + instance version: Svc.Version base id CDHCoreConfig.BASE_ID + 0x0500 \ - instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.CDHCore_BASE_ID + 0x0600 \ + instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.BASE_ID + 0x0600 \ - instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.CDHCore_BASE_ID + 0x0700 \ + instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.BASE_ID + 0x0700 \ topology Subtopology { #Active Components diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp index 2bcb2687cbe..7ff0c6d6203 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -1,6 +1,6 @@ module CDHCoreConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant CDHCore_BASE_ID = 0xFFFF0000 + constant BASE_ID = 0x7000 module QueueSizes { constant cmdDisp = 10 diff --git a/Svc/Subtopologies/CMakeLists.txt b/Svc/Subtopologies/CMakeLists.txt index e97b2bfb41a..1cc3c9db586 100644 --- a/Svc/Subtopologies/CMakeLists.txt +++ b/Svc/Subtopologies/CMakeLists.txt @@ -1,2 +1,3 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Comms/") diff --git a/Svc/Subtopologies/Comms/CMakeLists.txt b/Svc/Subtopologies/Comms/CMakeLists.txt new file mode 100644 index 00000000000..2152d880827 --- /dev/null +++ b/Svc/Subtopologies/Comms/CMakeLists.txt @@ -0,0 +1,9 @@ +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsConfig/") + +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/Comms.fpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/CommsTopologyDefs.hpp" + INTERFACE +) diff --git a/Svc/Subtopologies/Comms/Comms.fpp b/Svc/Subtopologies/Comms/Comms.fpp new file mode 100644 index 00000000000..5a70506d633 --- /dev/null +++ b/Svc/Subtopologies/Comms/Comms.fpp @@ -0,0 +1,108 @@ +module Comms { + + enum Ports_ComPacketQueue { + EVENTS, + TELEMETRY + } + + # ---------------------------------------------------------------------- + # Active Components + # ---------------------------------------------------------------------- + instance comQueue: Svc.ComQueue base id CommsConfig.BASE_ID + 0x0100 \ + queue size CommsConfig.QueueSizes.comQueue\ + stack size CommsConfig.StackSizes.comQueue\ + priority CommsConfig.Priorities.comQueue + + + # ---------------------------------------------------------------------- + # Queued Components + # ---------------------------------------------------------------------- + #none + + + # ---------------------------------------------------------------------- + # Passive Components + # ---------------------------------------------------------------------- + instance commsBufferManager: Svc.BufferManager base id CommsConfig.BASE_ID + 0x0500 \ + + instance frameAccumulator: Svc.FrameAccumulator base id CommsConfig.BASE_ID + 0x0600 \ + + instance deframer: Svc.FprimeDeframer base id CommsConfig.BASE_ID + 0x0700 \ + + instance fprimeFramer: Svc.FprimeFramer base id CommsConfig.BASE_ID + 0x0800 \ + + instance fprimeRouter: Svc.FprimeRouter base id CommsConfig.BASE_ID + 0x0900 \ + + instance comStub: Svc.ComStub base id CommsConfig.BASE_ID + 0x0A00 \ + + instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ + + topology Subtopology { + #Active Components + instance comQueue + + #Passive Components + instance commsBufferManager + instance frameAccumulator + instance deframer + instance fprimeFramer + instance fprimeRouter + instance comStub + instance comDriver + + import CDHCore.Subtopology + + connections Downlink { + # Inputs to ComQueue (events, telemetry, file) + CDHCore.events.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] + CDHCore.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] + #fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn + # ComQueue <-> Framer + comQueue.dataOut -> fprimeFramer.dataIn + fprimeFramer.dataReturnOut -> comQueue.dataReturnIn + # Buffer Management for Framer + fprimeFramer.bufferAllocate -> commsBufferManager.bufferGetCallee + fprimeFramer.bufferDeallocate -> commsBufferManager.bufferSendIn + # Framer <-> ComStub + fprimeFramer.dataOut -> comStub.dataIn + comStub.dataReturnOut -> fprimeFramer.dataReturnIn + # ComStub <-> ComDriver + comStub.drvSendOut -> comDriver.$send + comDriver.sendReturnOut -> comStub.drvSendReturnIn + comDriver.ready -> comStub.drvConnected + # ComStatus + comStub.comStatusOut -> fprimeFramer.comStatusIn + fprimeFramer.comStatusOut -> comQueue.comStatusIn + } + + connections Uplink { + # ComDriver buffer allocations + comDriver.allocate -> commsBufferManager.bufferGetCallee + comDriver.deallocate -> commsBufferManager.bufferSendIn + # ComDriver <-> ComStub + comDriver.$recv -> comStub.drvReceiveIn + comStub.drvReceiveReturnOut -> comDriver.recvReturnIn + # ComStub <-> FrameAccumulator + comStub.dataOut -> frameAccumulator.dataIn + frameAccumulator.dataReturnOut -> comStub.dataReturnIn + # FrameAccumulator buffer allocations + frameAccumulator.bufferDeallocate -> commsBufferManager.bufferSendIn + frameAccumulator.bufferAllocate -> commsBufferManager.bufferGetCallee + # FrameAccumulator <-> Deframer + frameAccumulator.dataOut -> deframer.dataIn + deframer.dataReturnOut -> frameAccumulator.dataReturnIn + # Deframer <-> Router + deframer.dataOut -> fprimeRouter.dataIn + fprimeRouter.dataReturnOut -> deframer.dataReturnIn + # Router buffer allocations + fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee + fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn + # Router <-> CmdDispatcher/FileUplink + fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn + #fprimeRouter.fileOut -> fileUplink.bufferSendIn + #fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn + } + + } # end topology +} # end Comms Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt b/Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt new file mode 100644 index 00000000000..48132f2b192 --- /dev/null +++ b/Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt @@ -0,0 +1,5 @@ +register_fprime_config( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/CommsConfig.fpp" + INTERFACE +) diff --git a/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp b/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp new file mode 100644 index 00000000000..32b730b0e0d --- /dev/null +++ b/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp @@ -0,0 +1,17 @@ +module CommsConfig { + #Base ID for the CDHCore Subtopology, all components are offsets from this base ID + constant BASE_ID = 0x6000 + + module QueueSizes { + constant comQueue = 10 + } + + + module StackSizes { + constant comQueue = 64 * 1024 + } + + module Priorities { + constant comQueue = 101 + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp b/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp new file mode 100644 index 00000000000..7c260a13f59 --- /dev/null +++ b/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp @@ -0,0 +1,14 @@ +#ifndef COMMSSUBTOPOLOGY_DEFS_HPP +#define COMMSSUBTOPOLOGY_DEFS_HPP + +namespace Comms { + struct CommsState { + /* include any variables that are needed for + configuring/starting/tearing down the topology */ + }; +} + + namespace PingEntries { + } + +#endif \ No newline at end of file From 06802d3fcb92640ad54be286241864e2292c8c9b Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 6 Jun 2025 15:23:20 -0700 Subject: [PATCH 10/52] Added cmdSeq to Comms Subtopology, integrated into Ref --- Ref/Top/RefPackets.fppi | 10 ++-- Ref/Top/RefTopology.cpp | 4 +- Ref/Top/RefTopologyDefs.hpp | 16 +----- Ref/Top/instances.fpp | 57 ++----------------- Ref/Top/topology.fpp | 25 ++------ Svc/Subtopologies/Comms/Comms.fpp | 25 +++++--- .../Comms/CommsConfig/CommsConfig.fpp | 3 + Svc/Subtopologies/Comms/CommsTopologyDefs.hpp | 1 + 8 files changed, 38 insertions(+), 103 deletions(-) diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index cf0bc1365c0..af86a0d081c 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -6,10 +6,10 @@ telemetry packets RefPackets { Ref.rateGroup1Comp.RgMaxTime Ref.rateGroup2Comp.RgMaxTime Ref.rateGroup3Comp.RgMaxTime - Ref.cmdSeq.CS_LoadCommands - Ref.cmdSeq.CS_CancelCommands - Ref.cmdSeq.CS_CommandsExecuted - Ref.cmdSeq.CS_SequencesCompleted + Comms.cmdSeq.CS_LoadCommands + Comms.cmdSeq.CS_CancelCommands + Comms.cmdSeq.CS_CommandsExecuted + Comms.cmdSeq.CS_SequencesCompleted Ref.fileUplink.FilesReceived Ref.fileUplink.PacketsReceived Comms.commsBufferManager.TotalBuffs @@ -27,7 +27,7 @@ telemetry packets RefPackets { Ref.rateGroup1Comp.RgCycleSlips Ref.rateGroup2Comp.RgCycleSlips Ref.rateGroup3Comp.RgCycleSlips - Ref.cmdSeq.CS_Errors + Comms.cmdSeq.CS_Errors Ref.fileUplink.Warnings Ref.fileDownlink.Warnings CDHCore.$health.PingLateWarnings diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index fc971c9a1d1..387e37c1c59 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -81,7 +81,7 @@ enum TopologyConstants { */ void configureTopology() { // Command sequencer needs to allocate memory to hold contents of command sequences - cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE); + Comms::cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE); // Rate group driver needs a divisor list rateGroupDriverComp.configure(rateGroupDivisorsSet); @@ -200,7 +200,7 @@ void teardownTopology(const TopologyState& state) { (void)Comms::comDriver.join(); // Resource deallocation - cmdSeq.deallocateBuffer(mallocator); + Comms::cmdSeq.deallocateBuffer(mallocator); Comms::commsBufferManager.cleanup(); Comms::frameAccumulator.cleanup(); } diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index a431a87fadb..885040c9f07 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -18,10 +18,10 @@ // Subtopology includes #include "Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp" +#include "Svc/Subtopologies/Comms/CommsTopologyDefs.hpp" namespace PingEntries { namespace Ref_blockDrv {enum { WARN = 3, FATAL = 5 };} - namespace Ref_cmdSeq {enum { WARN = 3, FATAL = 5 };} namespace Ref_fileDownlink {enum { WARN = 3, FATAL = 5 };} namespace Ref_fileManager {enum { WARN = 3, FATAL = 5 };} namespace Ref_fileUplink {enum { WARN = 3, FATAL = 5 };} @@ -31,20 +31,6 @@ namespace PingEntries { namespace Ref_rateGroup2Comp {enum { WARN = 3, FATAL = 5 };} namespace Ref_rateGroup3Comp {enum { WARN = 3, FATAL = 5 };} namespace Ref_dpCat {enum { WARN = 3, FATAL = 5 };} - /* For the purposes of the subtopology, we comment out what is included in the it - namespace Ref_tlmSend { - enum { WARN = 3, FATAL = 5 }; - } - - namespace Ref_cmdDisp { - enum { WARN = 3, FATAL = 5 }; - } - - namespace Ref_eventLogger { - enum { WARN = 3, FATAL = 5 }; - } - - */ } // namespace PingEntries /** * \brief required ping constants diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 05166ba6a83..d46c322fb7c 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -33,16 +33,6 @@ module Ref { stack size Default.STACK_SIZE \ priority 118 - #instance cmdDisp: Svc.CommandDispatcher base id 0x0500 \ - # queue size 20 \ - # stack size Default.STACK_SIZE \ - # priority 101 - - instance cmdSeq: Svc.CmdSequencer base id 0x0600 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 100 - instance fileDownlink: Svc.FileDownlink base id 0x0700 \ queue size 30 \ stack size Default.STACK_SIZE \ @@ -63,24 +53,20 @@ module Ref { stack size Default.STACK_SIZE \ priority 100 - #instance eventLogger: Svc.ActiveLogger base id 0x0B00 \ - # queue size Default.QUEUE_SIZE \ - # stack size Default.STACK_SIZE \ - # priority 98 - # comment in Svc.TlmChan or Svc.TlmPacketizer # depending on which form of telemetry downlink # you wish to use + # NOTE: Svc.TlmChan is provided in the CDHCore Subtopology #instance tlmSend: Svc.TlmChan base id 0x0C00 \ # queue size Default.QUEUE_SIZE \ # stack size Default.STACK_SIZE \ # priority 97 -# instance tlmSend: Svc.TlmPacketizer base id 0x0C00 \ -# queue size Default.QUEUE_SIZE \ -# stack size Default.STACK_SIZE \ -# priority 97 + #instance tlmSend: Svc.TlmPacketizer base id 0x0C00 \ + # queue size Default.QUEUE_SIZE \ + # stack size Default.STACK_SIZE \ + # priority 97 instance prmDb: Svc.PrmDb base id 0x0D00 \ queue size Default.QUEUE_SIZE \ @@ -102,22 +88,12 @@ module Ref { stack size Default.STACK_SIZE \ priority 96 - # ComQueue has a deeper queue to be resilient to spikes in com throughput - instance comQueue: Svc.ComQueue base id 0x1100 \ - queue size 50 \ - stack size Default.STACK_SIZE \ - priority 100 - - instance typeDemo: Ref.TypeDemo base id 0x1200 # ---------------------------------------------------------------------- # Queued component instances # ---------------------------------------------------------------------- - instance $health: Svc.Health base id 0x2000 \ - queue size 25 - instance SG1: Ref.SignalGen base id 0x2100 \ queue size Default.QUEUE_SIZE @@ -136,45 +112,22 @@ module Ref { instance sendBuffComp: Ref.SendBuff base id 0x2600 \ queue size Default.QUEUE_SIZE - - # ---------------------------------------------------------------------- # Passive component instances # ---------------------------------------------------------------------- - @ Communications driver. May be swapped with other comm drivers like UART - #instance comDriver: Drv.TcpClient base id 0x4000 - - #instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4100 - instance fatalHandler: Svc.FatalHandler base id 0x4200 - #instance commsBufferManager: Svc.BufferManager base id 0x4300 - instance posixTime: Svc.PosixTime base id 0x4400 instance rateGroupDriverComp: Svc.RateGroupDriver base id 0x4500 instance recvBuffComp: Ref.RecvBuff base id 0x4600 - #instance version: Svc.Version base id 0x4700 - - #instance textLogger: Svc.PassiveTextLogger base id 0x4800 - instance systemResources: Svc.SystemResources base id 0x4900 instance dpBufferManager: Svc.BufferManager base id 0x4A00 - #instance frameAccumulator: Svc.FrameAccumulator base id 0x4B00 - - #instance deframer: Svc.FprimeDeframer base id 0x4C00 - - #instance fprimeRouter: Svc.FprimeRouter base id 0x4D00 - - #instance fprimeFramer: Svc.FprimeFramer base id 0x4E00 - - #instance comStub: Svc.ComStub base id 0x4F00 - instance linuxTimer: Svc.LinuxTimer base id 0x5000 } diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 0f474c2d50d..8642c3589f0 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -11,6 +11,9 @@ module Ref { rateGroup3 } + + #The topology CPP expects these enums to be defined here, so though the actual comms subtopology does not use it, we cannot remove yet. + #Comms.fpp subtopology file has its own enum, and that is what is really used in the subtopology. enum Ports_ComPacketQueue { EVENTS, TELEMETRY @@ -31,29 +34,16 @@ module Ref { # Instances used in the topology # ---------------------------------------------------------------------- - #instance $health instance SG1 instance SG2 instance SG3 instance SG4 instance SG5 instance blockDrv - #instance tlmSend - #instance cmdDisp - instance cmdSeq - #instance comDriver - #instance comStub - #instance comQueue - #instance deframer - #instance eventLogger - #instance fatalAdapter instance fatalHandler instance fileDownlink instance fileManager instance fileUplink - #instance Comms.commsBufferManager - #instance frameAccumulator - #instance fprimeFramer instance posixTime instance pingRcvr instance prmDb @@ -62,16 +52,13 @@ module Ref { instance rateGroup3Comp instance rateGroupDriverComp instance recvBuffComp - #instance fprimeRouter instance sendBuffComp - #instance textLogger instance typeDemo instance systemResources instance dpCat instance dpMgr instance dpWriter instance dpBufferManager - #instance version instance linuxTimer # ---------------------------------------------------------------------- @@ -122,7 +109,7 @@ module Ref { # Rate group 2 rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup2] -> rateGroup2Comp.CycleIn - rateGroup2Comp.RateGroupMemberOut[0] -> cmdSeq.schedIn + rateGroup2Comp.RateGroupMemberOut[0] -> Comms.cmdSeq.schedIn rateGroup2Comp.RateGroupMemberOut[1] -> sendBuffComp.SchedIn rateGroup2Comp.RateGroupMemberOut[2] -> SG3.schedIn rateGroup2Comp.RateGroupMemberOut[3] -> SG4.schedIn @@ -143,10 +130,6 @@ module Ref { blockDrv.BufferOut -> recvBuffComp.Data } - connections Sequencer { - cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn - } connections DataProducts { # DpMgr and DpWriter connections. Have explicit port indexes for demo diff --git a/Svc/Subtopologies/Comms/Comms.fpp b/Svc/Subtopologies/Comms/Comms.fpp index 5a70506d633..2ca9616602e 100644 --- a/Svc/Subtopologies/Comms/Comms.fpp +++ b/Svc/Subtopologies/Comms/Comms.fpp @@ -9,10 +9,15 @@ module Comms { # Active Components # ---------------------------------------------------------------------- instance comQueue: Svc.ComQueue base id CommsConfig.BASE_ID + 0x0100 \ - queue size CommsConfig.QueueSizes.comQueue\ - stack size CommsConfig.StackSizes.comQueue\ + queue size CommsConfig.QueueSizes.comQueue \ + stack size CommsConfig.StackSizes.comQueue \ priority CommsConfig.Priorities.comQueue + instance cmdSeq: Svc.CmdSequencer base id CommsConfig.BASE_ID + 0x0200 \ + queue size CommsConfig.QueueSizes.cmdSeq \ + stack size CommsConfig.StackSizes.cmdSeq \ + priority CommsConfig.Priorities.cmdSeq + # ---------------------------------------------------------------------- # Queued Components @@ -35,11 +40,13 @@ module Comms { instance comStub: Svc.ComStub base id CommsConfig.BASE_ID + 0x0A00 \ + @ Communications driver. May be swapped with other comm drivers like UART instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ topology Subtopology { #Active Components instance comQueue + instance cmdSeq #Passive Components instance commsBufferManager @@ -53,10 +60,9 @@ module Comms { import CDHCore.Subtopology connections Downlink { - # Inputs to ComQueue (events, telemetry, file) + # Inputs to ComQueue (events, telemetry) CDHCore.events.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] CDHCore.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] - #fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn # ComQueue <-> Framer comQueue.dataOut -> fprimeFramer.dataIn fprimeFramer.dataReturnOut -> comQueue.dataReturnIn @@ -97,12 +103,15 @@ module Comms { # Router buffer allocations fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn - # Router <-> CmdDispatcher/FileUplink + # Router <-> CmdDispatcher fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff CDHCore.cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn - #fprimeRouter.fileOut -> fileUplink.bufferSendIn - #fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn - } + } + + connections Sequencer { + cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn + } } # end topology } # end Comms Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp b/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp index 32b730b0e0d..689a63a3038 100644 --- a/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp +++ b/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp @@ -4,14 +4,17 @@ module CommsConfig { module QueueSizes { constant comQueue = 10 + constant cmdSeq = 10 } module StackSizes { constant comQueue = 64 * 1024 + constant cmdSeq = 64 * 1024 } module Priorities { constant comQueue = 101 + constant cmdSeq = 100 } } \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp b/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp index 7c260a13f59..31f4a69e52e 100644 --- a/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp +++ b/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp @@ -9,6 +9,7 @@ namespace Comms { } namespace PingEntries { + namespace Comms_cmdSeq {enum { WARN = 3, FATAL = 5 };} } #endif \ No newline at end of file From 102bfc2d7f29186667dc87bee5d8b715f67c8e3b Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 6 Jun 2025 15:52:40 -0700 Subject: [PATCH 11/52] Add FileHandling Subtopology, initial structure --- Svc/Subtopologies/CMakeLists.txt | 1 + Svc/Subtopologies/Comms/Comms.fpp | 13 ++-- Svc/Subtopologies/FileHandling/CMakeLists.txt | 9 +++ .../FileHandling/FileHandling.fpp | 60 +++++++++++++++++++ .../FileHandlingConfig/CMakeLists.txt | 5 ++ .../FileHandlingConfig/FlieHandlingConfig.fpp | 20 +++++++ .../FileHandling/FileHandlingTopologyDefs.hpp | 15 +++++ 7 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 Svc/Subtopologies/FileHandling/CMakeLists.txt create mode 100644 Svc/Subtopologies/FileHandling/FileHandling.fpp create mode 100644 Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt create mode 100644 Svc/Subtopologies/FileHandling/FileHandlingConfig/FlieHandlingConfig.fpp create mode 100644 Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp diff --git a/Svc/Subtopologies/CMakeLists.txt b/Svc/Subtopologies/CMakeLists.txt index 1cc3c9db586..186c140a2e9 100644 --- a/Svc/Subtopologies/CMakeLists.txt +++ b/Svc/Subtopologies/CMakeLists.txt @@ -1,3 +1,4 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Comms/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileHandling/") diff --git a/Svc/Subtopologies/Comms/Comms.fpp b/Svc/Subtopologies/Comms/Comms.fpp index 2ca9616602e..7313781d48f 100644 --- a/Svc/Subtopologies/Comms/Comms.fpp +++ b/Svc/Subtopologies/Comms/Comms.fpp @@ -19,12 +19,6 @@ module Comms { priority CommsConfig.Priorities.cmdSeq - # ---------------------------------------------------------------------- - # Queued Components - # ---------------------------------------------------------------------- - #none - - # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- @@ -40,15 +34,15 @@ module Comms { instance comStub: Svc.ComStub base id CommsConfig.BASE_ID + 0x0A00 \ - @ Communications driver. May be swapped with other comm drivers like UART + @ Communications driver. May be swapped with other comm drivers like UART instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ topology Subtopology { - #Active Components + # Active Components instance comQueue instance cmdSeq - #Passive Components + # Passive Components instance commsBufferManager instance frameAccumulator instance deframer @@ -57,6 +51,7 @@ module Comms { instance comStub instance comDriver + # Subtopology imports import CDHCore.Subtopology connections Downlink { diff --git a/Svc/Subtopologies/FileHandling/CMakeLists.txt b/Svc/Subtopologies/FileHandling/CMakeLists.txt new file mode 100644 index 00000000000..33b85112ec5 --- /dev/null +++ b/Svc/Subtopologies/FileHandling/CMakeLists.txt @@ -0,0 +1,9 @@ +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileHandlingConfig/") + +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/FileHandling.fpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/FileHandlingTopologyDefs.hpp" + INTERFACE +) diff --git a/Svc/Subtopologies/FileHandling/FileHandling.fpp b/Svc/Subtopologies/FileHandling/FileHandling.fpp new file mode 100644 index 00000000000..fc0e153c1cd --- /dev/null +++ b/Svc/Subtopologies/FileHandling/FileHandling.fpp @@ -0,0 +1,60 @@ +module FileHandling{ + + enum Ports_ComPacketQueue { + EVENTS, + TELEMETRY + } + + # ---------------------------------------------------------------------- + # Active Components + # ---------------------------------------------------------------------- + + #ex: + #instance comQueue: Svc.ComQueue base id CommsConfig.BASE_ID + 0x0100 \ + # queue size CommsConfig.QueueSizes.comQueue \ + # stack size CommsConfig.StackSizes.comQueue \ + # priority CommsConfig.Priorities.comQueue + + + + # ---------------------------------------------------------------------- + # Queued Components + # ---------------------------------------------------------------------- + #none + + + # ---------------------------------------------------------------------- + # Passive Components + # ---------------------------------------------------------------------- + + #ex: + #instance commsBufferManager: Svc.BufferManager base id CommsConfig.BASE_ID + 0x0500 \ + + + @ Communications driver. May be swapped with other comm drivers like UART + instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ + + topology Subtopology { + #Active Components + + #Passive Components + + # Subtopology imports + # DataProducts does not exist yet, but we will need it for the file handling subtopology + #import DataProducts.Subtopology + + connections FileHandling { + # Data Products + dpCat.fileOut -> fileDownlink.SendFile + fileDownlink.FileComplete -> dpCat.fileDone + + # File Downlink <-> ComQueue + fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] + comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn + + # Router <-> FileUplink + fprimeRouter.fileOut -> fileUplink.bufferSendIn + fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn + } + } # end topology +} # end Comms Subtopology diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt b/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt new file mode 100644 index 00000000000..c1bd7b8e64b --- /dev/null +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt @@ -0,0 +1,5 @@ +register_fprime_config( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/FileHandlingConfig.fpp" + INTERFACE +) diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FlieHandlingConfig.fpp b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FlieHandlingConfig.fpp new file mode 100644 index 00000000000..689a63a3038 --- /dev/null +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FlieHandlingConfig.fpp @@ -0,0 +1,20 @@ +module CommsConfig { + #Base ID for the CDHCore Subtopology, all components are offsets from this base ID + constant BASE_ID = 0x6000 + + module QueueSizes { + constant comQueue = 10 + constant cmdSeq = 10 + } + + + module StackSizes { + constant comQueue = 64 * 1024 + constant cmdSeq = 64 * 1024 + } + + module Priorities { + constant comQueue = 101 + constant cmdSeq = 100 + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp new file mode 100644 index 00000000000..31f4a69e52e --- /dev/null +++ b/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp @@ -0,0 +1,15 @@ +#ifndef COMMSSUBTOPOLOGY_DEFS_HPP +#define COMMSSUBTOPOLOGY_DEFS_HPP + +namespace Comms { + struct CommsState { + /* include any variables that are needed for + configuring/starting/tearing down the topology */ + }; +} + + namespace PingEntries { + namespace Comms_cmdSeq {enum { WARN = 3, FATAL = 5 };} + } + +#endif \ No newline at end of file From 910c775b4b606256243c6b7eb74cef4e4064b908 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 6 Jun 2025 18:00:18 -0700 Subject: [PATCH 12/52] Fixed Spelling, Flie -> File --- .../{FlieHandlingConfig.fpp => FileHandlingConfig.fpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Svc/Subtopologies/FileHandling/FileHandlingConfig/{FlieHandlingConfig.fpp => FileHandlingConfig.fpp} (100%) diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FlieHandlingConfig.fpp b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp similarity index 100% rename from Svc/Subtopologies/FileHandling/FileHandlingConfig/FlieHandlingConfig.fpp rename to Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp From 7a1d68c43338995cf93c0b2b5a100d41ce2c296d Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Sat, 7 Jun 2025 01:01:37 +0000 Subject: [PATCH 13/52] Update metadata check-spelling run (push) for add-subtopologies Signed-off-by: check-spelling-bot on-behalf-of: @check-spelling --- .github/actions/spelling/expect.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 4a513e2bcc6..203fa43f0dc 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -97,6 +97,7 @@ COMBUFFER comlogger COMMANDDISPATCHERIMPL COMMANDDISPATCHERIMPLCFG +COMMSSUBTOPOLOGY COMPACKET COMPACKETQUEUEIN COMQUEUE From 954f32caf05fc5bdbca90065b28711c5e2303071 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 9 Jun 2025 10:02:29 -0700 Subject: [PATCH 14/52] Added working FileHandling, DataProducts subtopology, integrated into Ref --- Ref/Top/RefPackets.fppi | 50 ++++++++-------- Ref/Top/RefTopology.cpp | 10 ++-- Ref/Top/RefTopologyDefs.hpp | 6 +- Ref/Top/instances.fpp | 30 ---------- Ref/Top/topology.fpp | 38 ++++-------- Svc/Subtopologies/CDHCore/CDHCore.fpp | 1 + Svc/Subtopologies/CMakeLists.txt | 1 + Svc/Subtopologies/DataProducts/CMakeLists.txt | 9 +++ .../DataProducts/DataProducts.fpp | 60 +++++++++++++++++++ .../DataProductsConfig/CMakeLists.txt | 5 ++ .../DataProductsConfig/DataProductsConfig.fpp | 26 ++++++++ .../DataProducts/DataProductsTopologyDefs.hpp | 15 +++++ .../FileHandling/FileHandling.fpp | 42 ++++++++----- .../FileHandlingConfig/FileHandlingConfig.fpp | 19 +++--- .../FileHandling/FileHandlingTopologyDefs.hpp | 12 ++-- 15 files changed, 205 insertions(+), 119 deletions(-) create mode 100644 Svc/Subtopologies/DataProducts/CMakeLists.txt create mode 100644 Svc/Subtopologies/DataProducts/DataProducts.fpp create mode 100644 Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt create mode 100644 Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp create mode 100644 Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index af86a0d081c..f472f9ca69e 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -10,14 +10,14 @@ telemetry packets RefPackets { Comms.cmdSeq.CS_CancelCommands Comms.cmdSeq.CS_CommandsExecuted Comms.cmdSeq.CS_SequencesCompleted - Ref.fileUplink.FilesReceived - Ref.fileUplink.PacketsReceived + FileHandling.fileUplink.FilesReceived + FileHandling.fileUplink.PacketsReceived Comms.commsBufferManager.TotalBuffs Comms.commsBufferManager.CurrBuffs Comms.commsBufferManager.HiBuffs - Ref.fileDownlink.FilesSent - Ref.fileDownlink.PacketsSent - Ref.fileManager.CommandsExecuted + FileHandling.fileDownlink.FilesSent + FileHandling.fileDownlink.PacketsSent + FileHandling.fileManager.CommandsExecuted Comms.comQueue.comQueueDepth Comms.comQueue.buffQueueDepth # Ref.tlmSend.SendLevel @@ -28,13 +28,13 @@ telemetry packets RefPackets { Ref.rateGroup2Comp.RgCycleSlips Ref.rateGroup3Comp.RgCycleSlips Comms.cmdSeq.CS_Errors - Ref.fileUplink.Warnings - Ref.fileDownlink.Warnings + FileHandling.fileUplink.Warnings + FileHandling.fileDownlink.Warnings CDHCore.$health.PingLateWarnings - Ref.fileManager.Errors + FileHandling.fileManager.Errors Comms.commsBufferManager.NoBuffs Comms.commsBufferManager.EmptyBuffs - Ref.fileManager.Errors + FileHandling.fileManager.Errors } packet DriveTlm id 3 group 1 { @@ -176,22 +176,22 @@ telemetry packets RefPackets { } packet DataProducts id 21 group 3 { - Ref.dpCat.CatalogDps - Ref.dpCat.DpsSent - Ref.dpMgr.NumSuccessfulAllocations - Ref.dpMgr.NumFailedAllocations - Ref.dpMgr.NumDataProducts - Ref.dpMgr.NumBytes - Ref.dpWriter.NumBuffersReceived - Ref.dpWriter.NumBytesWritten - Ref.dpWriter.NumSuccessfulWrites - Ref.dpWriter.NumFailedWrites - Ref.dpWriter.NumErrors - Ref.dpBufferManager.TotalBuffs - Ref.dpBufferManager.CurrBuffs - Ref.dpBufferManager.HiBuffs - Ref.dpBufferManager.NoBuffs - Ref.dpBufferManager.EmptyBuffs + DataProducts.dpCat.CatalogDps + DataProducts.dpCat.DpsSent + DataProducts.dpMgr.NumSuccessfulAllocations + DataProducts.dpMgr.NumFailedAllocations + DataProducts.dpMgr.NumDataProducts + DataProducts.dpMgr.NumBytes + DataProducts.dpWriter.NumBuffersReceived + DataProducts.dpWriter.NumBytesWritten + DataProducts.dpWriter.NumSuccessfulWrites + DataProducts.dpWriter.NumFailedWrites + DataProducts.dpWriter.NumErrors + DataProducts.dpBufferManager.TotalBuffs + DataProducts.dpBufferManager.CurrBuffs + DataProducts.dpBufferManager.HiBuffs + DataProducts.dpBufferManager.NoBuffs + DataProducts.dpBufferManager.EmptyBuffs } packet Version1 id 22 group 2 { diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 387e37c1c59..76724101e57 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -21,8 +21,6 @@ #include //Subtopology includes -#include -#include // Allows easy reference to objects in FPP/autocoder required namespaces using namespace Ref; @@ -92,7 +90,7 @@ void configureTopology() { rateGroup3Comp.configure(rateGroup3Context, FW_NUM_ARRAY_ELEMENTS(rateGroup3Context)); // File downlink requires some project-derived properties. - fileDownlink.configure(FILE_DOWNLINK_TIMEOUT, FILE_DOWNLINK_COOLDOWN, FILE_DOWNLINK_CYCLE_TIME, + FileHandling::fileDownlink.configure(FILE_DOWNLINK_TIMEOUT, FILE_DOWNLINK_COOLDOWN, FILE_DOWNLINK_CYCLE_TIME, FILE_DOWNLINK_FILE_QUEUE_DEPTH); // Parameter database is configured with a database file name, and that file must be initially read. @@ -116,7 +114,7 @@ void configureTopology() { memset(&dpBuffMgrBins, 0, sizeof(dpBuffMgrBins)); dpBuffMgrBins.bins[0].bufferSize = DP_BUFFER_MANAGER_STORE_SIZE; dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT; - dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins); + DataProducts::dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins); Comms::frameAccumulator.configure(frameDetector, 1, mallocator, 2048); @@ -126,8 +124,8 @@ void configureTopology() { // create the DP directory if it doesn't exist Os::FileSystem::createDirectory(dpDir.toChar()); - dpCat.configure(&dpDir,1,dpState,0,mallocator); - dpWriter.configure(dpDir); + DataProducts::dpCat.configure(&dpDir,1,dpState,0,mallocator); + DataProducts::dpWriter.configure(dpDir); // ComQueue configuration // Events (highest-priority) diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 885040c9f07..50a87a6a65f 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -19,18 +19,16 @@ // Subtopology includes #include "Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp" #include "Svc/Subtopologies/Comms/CommsTopologyDefs.hpp" +#include "Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp" +#include "Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp" namespace PingEntries { namespace Ref_blockDrv {enum { WARN = 3, FATAL = 5 };} - namespace Ref_fileDownlink {enum { WARN = 3, FATAL = 5 };} - namespace Ref_fileManager {enum { WARN = 3, FATAL = 5 };} - namespace Ref_fileUplink {enum { WARN = 3, FATAL = 5 };} namespace Ref_pingRcvr {enum { WARN = 3, FATAL = 5 };} namespace Ref_prmDb {enum { WARN = 3, FATAL = 5 };} namespace Ref_rateGroup1Comp {enum { WARN = 3, FATAL = 5 };} namespace Ref_rateGroup2Comp {enum { WARN = 3, FATAL = 5 };} namespace Ref_rateGroup3Comp {enum { WARN = 3, FATAL = 5 };} - namespace Ref_dpCat {enum { WARN = 3, FATAL = 5 };} } // namespace PingEntries /** * \brief required ping constants diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index d46c322fb7c..5b0d3b0f008 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -33,21 +33,6 @@ module Ref { stack size Default.STACK_SIZE \ priority 118 - instance fileDownlink: Svc.FileDownlink base id 0x0700 \ - queue size 30 \ - stack size Default.STACK_SIZE \ - priority 100 - - instance fileManager: Svc.FileManager base id 0x0800 \ - queue size 30 \ - stack size Default.STACK_SIZE \ - priority 100 - - instance fileUplink: Svc.FileUplink base id 0x0900 \ - queue size 30 \ - stack size Default.STACK_SIZE \ - priority 100 - instance pingRcvr: Ref.PingReceiver base id 0x0A00 \ queue size Default.QUEUE_SIZE \ stack size Default.STACK_SIZE \ @@ -73,20 +58,6 @@ module Ref { stack size Default.STACK_SIZE \ priority 96 - instance dpCat: Svc.DpCatalog base id 0x0E00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 96 - - instance dpMgr: Svc.DpManager base id 0x0F00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 96 - - instance dpWriter: Svc.DpWriter base id 0x1000 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 96 instance typeDemo: Ref.TypeDemo base id 0x1200 @@ -126,7 +97,6 @@ module Ref { instance systemResources: Svc.SystemResources base id 0x4900 - instance dpBufferManager: Svc.BufferManager base id 0x4A00 instance linuxTimer: Svc.LinuxTimer base id 0x5000 diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 8642c3589f0..92c7be37ea6 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -19,6 +19,7 @@ module Ref { TELEMETRY } + #Same here enum Ports_ComBufferQueue { FILE_DOWNLINK } @@ -29,6 +30,8 @@ module Ref { # ---------------------------------------------------------------------- import CDHCore.Subtopology import Comms.Subtopology + import FileHandling.Subtopology + import DataProducts.Subtopology # ---------------------------------------------------------------------- # Instances used in the topology @@ -41,9 +44,6 @@ module Ref { instance SG5 instance blockDrv instance fatalHandler - instance fileDownlink - instance fileManager - instance fileUplink instance posixTime instance pingRcvr instance prmDb @@ -55,10 +55,6 @@ module Ref { instance sendBuffComp instance typeDemo instance systemResources - instance dpCat - instance dpMgr - instance dpWriter - instance dpBufferManager instance linuxTimer # ---------------------------------------------------------------------- @@ -103,7 +99,7 @@ module Ref { rateGroup1Comp.RateGroupMemberOut[0] -> SG1.schedIn rateGroup1Comp.RateGroupMemberOut[1] -> SG2.schedIn rateGroup1Comp.RateGroupMemberOut[2] -> CDHCore.tlmSend.Run - rateGroup1Comp.RateGroupMemberOut[3] -> fileDownlink.Run + rateGroup1Comp.RateGroupMemberOut[3] -> FileHandling.fileDownlink.Run rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run rateGroup1Comp.RateGroupMemberOut[5] -> Comms.comQueue.run @@ -120,33 +116,23 @@ module Ref { rateGroup3Comp.RateGroupMemberOut[1] -> SG5.schedIn rateGroup3Comp.RateGroupMemberOut[2] -> blockDrv.Sched rateGroup3Comp.RateGroupMemberOut[3] -> Comms.commsBufferManager.schedIn - rateGroup3Comp.RateGroupMemberOut[4] -> dpBufferManager.schedIn - rateGroup3Comp.RateGroupMemberOut[5] -> dpWriter.schedIn - rateGroup3Comp.RateGroupMemberOut[6] -> dpMgr.schedIn + rateGroup3Comp.RateGroupMemberOut[4] -> DataProducts.dpBufferManager.schedIn + rateGroup3Comp.RateGroupMemberOut[5] -> DataProducts.dpWriter.schedIn + rateGroup3Comp.RateGroupMemberOut[6] -> DataProducts.dpMgr.schedIn } connections Ref { sendBuffComp.Data -> blockDrv.BufferIn blockDrv.BufferOut -> recvBuffComp.Data - } - - - connections DataProducts { - # DpMgr and DpWriter connections. Have explicit port indexes for demo - dpMgr.bufferGetOut[0] -> dpBufferManager.bufferGetCallee - dpMgr.productSendOut[0] -> dpWriter.bufferSendIn - dpWriter.deallocBufferSendOut -> dpBufferManager.bufferSendIn - - # Component DP connections + ### Moved this out of DataProducts Subtopology --> anything specific to deployment should live in Ref connections # Synchronous request. Will have both request kinds for demo purposes, not typical - SG1.productGetOut -> dpMgr.productGetIn[0] + SG1.productGetOut -> DataProducts.dpMgr.productGetIn[0] # Asynchronous request - SG1.productRequestOut -> dpMgr.productRequestIn[0] - dpMgr.productResponseOut[0] -> SG1.productRecvIn + SG1.productRequestOut -> DataProducts.dpMgr.productRequestIn[0] + DataProducts.dpMgr.productResponseOut[0] -> SG1.productRecvIn # Send filled DP - SG1.productSendOut -> dpMgr.productSendIn[0] - + SG1.productSendOut -> DataProducts.dpMgr.productSendIn[0] } } diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index 238ca222d02..cdc39a6efc0 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -46,5 +46,6 @@ module CDHCore { instance textLogger instance fatalAdapter + } # end topology } # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CMakeLists.txt b/Svc/Subtopologies/CMakeLists.txt index 186c140a2e9..a1532e2d555 100644 --- a/Svc/Subtopologies/CMakeLists.txt +++ b/Svc/Subtopologies/CMakeLists.txt @@ -1,4 +1,5 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Comms/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileHandling/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DataProducts/") diff --git a/Svc/Subtopologies/DataProducts/CMakeLists.txt b/Svc/Subtopologies/DataProducts/CMakeLists.txt new file mode 100644 index 00000000000..3868483f380 --- /dev/null +++ b/Svc/Subtopologies/DataProducts/CMakeLists.txt @@ -0,0 +1,9 @@ +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig/") + +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/DataProducts.fpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/DataProductsTopologyDefs.hpp" + INTERFACE +) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp new file mode 100644 index 00000000000..64341902b6f --- /dev/null +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -0,0 +1,60 @@ +module DataProducts{ + + enum Ports_ComBufferQueue { + FILE_DOWNLINK + } + + # ---------------------------------------------------------------------- + # Active Components + # ---------------------------------------------------------------------- + + instance dpCat: Svc.DpCatalog base id DataProductsConfig.BASE_ID + 0x0100 \ + queue size DataProductsConfig.QueueSizes.dpCat \ + stack size DataProductsConfig.StackSizes.dpCat \ + priority DataProductsConfig.Priorities.dpCat + + instance dpMgr: Svc.DpManager base id DataProductsConfig.BASE_ID + 0x0200 \ + queue size DataProductsConfig.QueueSizes.dpMgr \ + stack size DataProductsConfig.StackSizes.dpMgr \ + priority DataProductsConfig.Priorities.dpMgr + + instance dpWriter: Svc.DpWriter base id DataProductsConfig.BASE_ID + 0x0300 \ + queue size DataProductsConfig.QueueSizes.dpWriter \ + stack size DataProductsConfig.StackSizes.dpWriter \ + priority DataProductsConfig.Priorities.dpWriter + + # ---------------------------------------------------------------------- + # Queued Components + # ---------------------------------------------------------------------- + #none + + + # ---------------------------------------------------------------------- + # Passive Components + # ---------------------------------------------------------------------- + + instance dpBufferManager: Svc.BufferManager base id 0x4A00 + + topology Subtopology { + #Active Components + instance dpCat + instance dpMgr + instance dpWriter + + #Passive Components + instance dpBufferManager + + # Subtopology imports + import Comms.Subtopology + + connections DataProducts { + # DpMgr and DpWriter connections. Have explicit port indexes for demo + dpMgr.bufferGetOut[0] -> dpBufferManager.bufferGetCallee + dpMgr.productSendOut[0] -> dpWriter.bufferSendIn + dpWriter.deallocBufferSendOut -> dpBufferManager.bufferSendIn + + # Component DP connections + + } + } # end topology +} # end Comms Subtopology diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt new file mode 100644 index 00000000000..f704c7bac96 --- /dev/null +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt @@ -0,0 +1,5 @@ +register_fprime_config( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig.fpp" + INTERFACE +) diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp new file mode 100644 index 00000000000..6279e2af06f --- /dev/null +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp @@ -0,0 +1,26 @@ +module DataProductsConfig { + #Base ID for the CDHCore Subtopology, all components are offsets from this base ID + constant BASE_ID = 0x8000 + + module QueueSizes { + constant dpCat = 10 + constant dpMgr = 10 + constant dpWriter = 10 + constant dpBufferManager = 10 + } + + + module StackSizes { + constant dpCat = 64 * 1024 + constant dpMgr = 64 * 1024 + constant dpWriter = 64 * 1024 + constant dpBufferManager = 64 * 1024 + } + + module Priorities { + constant dpCat = 101 + constant dpMgr = 100 + constant dpWriter = 99 + constant dpBufferManager = 98 + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp b/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp new file mode 100644 index 00000000000..0ea4854b00d --- /dev/null +++ b/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp @@ -0,0 +1,15 @@ +#ifndef DATAPRODUCTSSUBTOPOLOGY_DEFS_HPP +#define DATAPRODUCTSSUBTOPOLOGY_DEFS_HPP + +namespace DataProducts { + struct DataProductsState { + /* include any variables that are needed for + configuring/starting/tearing down the topology */ + }; +} + + namespace PingEntries { + namespace DataProducts_dpCat {enum { WARN = 3, FATAL = 5 };} + } + +#endif \ No newline at end of file diff --git a/Svc/Subtopologies/FileHandling/FileHandling.fpp b/Svc/Subtopologies/FileHandling/FileHandling.fpp index fc0e153c1cd..d658a30e18a 100644 --- a/Svc/Subtopologies/FileHandling/FileHandling.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandling.fpp @@ -1,9 +1,8 @@ module FileHandling{ - enum Ports_ComPacketQueue { - EVENTS, - TELEMETRY - } + enum Ports_ComBufferQueue { + FILE_DOWNLINK + } # ---------------------------------------------------------------------- # Active Components @@ -15,7 +14,20 @@ module FileHandling{ # stack size CommsConfig.StackSizes.comQueue \ # priority CommsConfig.Priorities.comQueue + instance fileUplink: Svc.FileUplink base id FileHandlingConfig.BASE_ID + 0x0100 \ + queue size FileHandlingConfig.QueueSizes.fileUplink \ + stack size FileHandlingConfig.StackSizes.fileUplink \ + priority FileHandlingConfig.Priorities.fileUplink + instance fileDownlink: Svc.FileDownlink base id FileHandlingConfig.BASE_ID + 0x0200 \ + queue size FileHandlingConfig.QueueSizes.fileDownlink \ + stack size FileHandlingConfig.StackSizes.fileDownlink \ + priority FileHandlingConfig.Priorities.fileDownlink + + instance fileManager: Svc.FileManager base id FileHandlingConfig.BASE_ID + 0x0300 \ + queue size FileHandlingConfig.QueueSizes.fileManager \ + stack size FileHandlingConfig.StackSizes.fileManager \ + priority FileHandlingConfig.Priorities.fileManager # ---------------------------------------------------------------------- # Queued Components @@ -30,31 +42,31 @@ module FileHandling{ #ex: #instance commsBufferManager: Svc.BufferManager base id CommsConfig.BASE_ID + 0x0500 \ - - @ Communications driver. May be swapped with other comm drivers like UART - instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ - topology Subtopology { #Active Components + instance fileUplink + instance fileDownlink + instance fileManager #Passive Components # Subtopology imports # DataProducts does not exist yet, but we will need it for the file handling subtopology - #import DataProducts.Subtopology + import DataProducts.Subtopology + import Comms.Subtopology connections FileHandling { # Data Products - dpCat.fileOut -> fileDownlink.SendFile - fileDownlink.FileComplete -> dpCat.fileDone + DataProducts.dpCat.fileOut -> fileDownlink.SendFile + fileDownlink.FileComplete -> DataProducts.dpCat.fileDone # File Downlink <-> ComQueue - fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] - comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn + fileDownlink.bufferSendOut -> Comms.comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] + Comms.comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn # Router <-> FileUplink - fprimeRouter.fileOut -> fileUplink.bufferSendIn - fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn + Comms.fprimeRouter.fileOut -> fileUplink.bufferSendIn + fileUplink.bufferSendOut -> Comms.fprimeRouter.fileBufferReturnIn } } # end topology } # end Comms Subtopology diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp index 689a63a3038..cb56f24230a 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp @@ -1,20 +1,23 @@ -module CommsConfig { +module FileHandlingConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x6000 + constant BASE_ID = 0x9000 module QueueSizes { - constant comQueue = 10 - constant cmdSeq = 10 + constant fileUplink = 10 + constant fileDownlink = 10 + constant fileManager = 10 } module StackSizes { - constant comQueue = 64 * 1024 - constant cmdSeq = 64 * 1024 + constant fileUplink = 64 * 1024 + constant fileDownlink = 64 * 1024 + constant fileManager = 64 * 1024 } module Priorities { - constant comQueue = 101 - constant cmdSeq = 100 + constant fileUplink = 101 + constant fileDownlink = 100 + constant fileManager = 99 } } \ No newline at end of file diff --git a/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp index 31f4a69e52e..f2b6f64d145 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp @@ -1,15 +1,17 @@ -#ifndef COMMSSUBTOPOLOGY_DEFS_HPP -#define COMMSSUBTOPOLOGY_DEFS_HPP +#ifndef FILEHANDLINGSUBTOPOLOGY_DEFS_HPP +#define FILEHANDLINGSUBTOPOLOGY_DEFS_HPP -namespace Comms { - struct CommsState { +namespace FileHandling { + struct FileHandlingState { /* include any variables that are needed for configuring/starting/tearing down the topology */ }; } namespace PingEntries { - namespace Comms_cmdSeq {enum { WARN = 3, FATAL = 5 };} + namespace FileHandling_fileDownlink {enum { WARN = 3, FATAL = 5 };} + namespace FileHandling_fileManager {enum { WARN = 3, FATAL = 5 };} + namespace FileHandling_fileUplink {enum { WARN = 3, FATAL = 5 };} } #endif \ No newline at end of file From d39aa5daaeaee44d156668846fb793a811f6758f Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 9 Jun 2025 10:27:25 -0700 Subject: [PATCH 15/52] prmDb part of FileHandling, fatalHandler part of CDHCore --- Ref/Top/RefTopology.cpp | 6 ++---- Ref/Top/RefTopologyDefs.hpp | 1 - Ref/Top/instances.fpp | 8 -------- Ref/Top/topology.fpp | 15 ++++----------- Svc/Subtopologies/CDHCore/CDHCore.fpp | 6 ++++++ Svc/Subtopologies/FileHandling/FileHandling.fpp | 6 ++++++ .../FileHandlingConfig/FileHandlingConfig.fpp | 5 ++++- .../FileHandling/FileHandlingTopologyDefs.hpp | 1 + 8 files changed, 23 insertions(+), 25 deletions(-) diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 76724101e57..6425eeff79f 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -20,8 +20,6 @@ // Used for 1Hz synthetic cycling #include -//Subtopology includes - // Allows easy reference to objects in FPP/autocoder required namespaces using namespace Ref; @@ -94,8 +92,8 @@ void configureTopology() { FILE_DOWNLINK_FILE_QUEUE_DEPTH); // Parameter database is configured with a database file name, and that file must be initially read. - prmDb.configure("PrmDb.dat"); - prmDb.readParamFile(); + FileHandling::prmDb.configure("PrmDb.dat"); + FileHandling::prmDb.readParamFile(); // Health is supplied a set of ping entires. CDHCore::health.setPingEntries(ConfigObjects::CDHCore_health::pingEntries, diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 50a87a6a65f..251a6aad248 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -25,7 +25,6 @@ namespace PingEntries { namespace Ref_blockDrv {enum { WARN = 3, FATAL = 5 };} namespace Ref_pingRcvr {enum { WARN = 3, FATAL = 5 };} - namespace Ref_prmDb {enum { WARN = 3, FATAL = 5 };} namespace Ref_rateGroup1Comp {enum { WARN = 3, FATAL = 5 };} namespace Ref_rateGroup2Comp {enum { WARN = 3, FATAL = 5 };} namespace Ref_rateGroup3Comp {enum { WARN = 3, FATAL = 5 };} diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 5b0d3b0f008..1a1db6d87b6 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -53,12 +53,6 @@ module Ref { # stack size Default.STACK_SIZE \ # priority 97 - instance prmDb: Svc.PrmDb base id 0x0D00 \ - queue size Default.QUEUE_SIZE \ - stack size Default.STACK_SIZE \ - priority 96 - - instance typeDemo: Ref.TypeDemo base id 0x1200 # ---------------------------------------------------------------------- @@ -87,7 +81,6 @@ module Ref { # Passive component instances # ---------------------------------------------------------------------- - instance fatalHandler: Svc.FatalHandler base id 0x4200 instance posixTime: Svc.PosixTime base id 0x4400 @@ -97,7 +90,6 @@ module Ref { instance systemResources: Svc.SystemResources base id 0x4900 - instance linuxTimer: Svc.LinuxTimer base id 0x5000 } diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 92c7be37ea6..ff8c8cd6e82 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -1,6 +1,5 @@ module Ref { - # ---------------------------------------------------------------------- # Symbolic constants for port numbers # ---------------------------------------------------------------------- @@ -11,7 +10,6 @@ module Ref { rateGroup3 } - #The topology CPP expects these enums to be defined here, so though the actual comms subtopology does not use it, we cannot remove yet. #Comms.fpp subtopology file has its own enum, and that is what is really used in the subtopology. enum Ports_ComPacketQueue { @@ -43,10 +41,8 @@ module Ref { instance SG4 instance SG5 instance blockDrv - instance fatalHandler instance posixTime instance pingRcvr - instance prmDb instance rateGroup1Comp instance rateGroup2Comp instance rateGroup3Comp @@ -65,16 +61,16 @@ module Ref { event connections instance CDHCore.events - param connections instance prmDb - telemetry connections instance CDHCore.tlmSend text event connections instance CDHCore.textLogger - time connections instance posixTime - health connections instance CDHCore.$health + param connections instance FileHandling.prmDb + + time connections instance posixTime + # ---------------------------------------------------------------------- # Telemetry packets # ---------------------------------------------------------------------- @@ -85,9 +81,6 @@ module Ref { # Direct graph specifiers # ---------------------------------------------------------------------- - connections FaultProtection { - CDHCore.events.FatalAnnounce -> fatalHandler.FatalReceive - } connections RateGroups { diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index cdc39a6efc0..a2012052f98 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -31,6 +31,8 @@ module CDHCore { instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.BASE_ID + 0x0600 \ instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.BASE_ID + 0x0700 \ + + instance fatalHandler: Svc.FatalHandler base id CDHCoreConfig.BASE_ID + 0x0800 \ topology Subtopology { #Active Components @@ -45,7 +47,11 @@ module CDHCore { instance version instance textLogger instance fatalAdapter + instance fatalHandler + connections FaultProtection { + events.FatalAnnounce -> fatalHandler.FatalReceive + } } # end topology } # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/FileHandling/FileHandling.fpp b/Svc/Subtopologies/FileHandling/FileHandling.fpp index d658a30e18a..8f946fdb9dd 100644 --- a/Svc/Subtopologies/FileHandling/FileHandling.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandling.fpp @@ -29,6 +29,11 @@ module FileHandling{ stack size FileHandlingConfig.StackSizes.fileManager \ priority FileHandlingConfig.Priorities.fileManager + instance prmDb: Svc.PrmDb base id FileHandlingConfig.BASE_ID + 0x0400 \ + queue size FileHandlingConfig.QueueSizes.prmDb \ + stack size FileHandlingConfig.StackSizes.prmDb \ + priority FileHandlingConfig.Priorities.prmDb + # ---------------------------------------------------------------------- # Queued Components # ---------------------------------------------------------------------- @@ -47,6 +52,7 @@ module FileHandling{ instance fileUplink instance fileDownlink instance fileManager + instance prmDb #Passive Components diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp index cb56f24230a..7e11f6da095 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp @@ -6,6 +6,7 @@ module FileHandlingConfig { constant fileUplink = 10 constant fileDownlink = 10 constant fileManager = 10 + constant prmDb = 10 } @@ -13,11 +14,13 @@ module FileHandlingConfig { constant fileUplink = 64 * 1024 constant fileDownlink = 64 * 1024 constant fileManager = 64 * 1024 + constant prmDb = 64 * 1024 } module Priorities { constant fileUplink = 101 constant fileDownlink = 100 constant fileManager = 99 + constant prmDb = 98 } -} \ No newline at end of file +} diff --git a/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp index f2b6f64d145..0d36c95c0fd 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp @@ -12,6 +12,7 @@ namespace FileHandling { namespace FileHandling_fileDownlink {enum { WARN = 3, FATAL = 5 };} namespace FileHandling_fileManager {enum { WARN = 3, FATAL = 5 };} namespace FileHandling_fileUplink {enum { WARN = 3, FATAL = 5 };} + namespace FileHandling_prmDb {enum { WARN = 3, FATAL = 5 };} } #endif \ No newline at end of file From 84c922d7246513d43561e8384ca1e667703f8170 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 9 Jun 2025 17:28:39 +0000 Subject: [PATCH 16/52] Update metadata check-spelling run (push) for add-subtopologies Signed-off-by: check-spelling-bot on-behalf-of: @check-spelling --- .github/actions/spelling/expect.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 203fa43f0dc..2eefbc6a136 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -133,6 +133,7 @@ ctu culates cuz CYCLEOUT +DATAPRODUCTSSUBTOPOLOGY DATAROOTDIR DDDTHH Debian @@ -211,6 +212,7 @@ ffff Ffs FILEDOWNLINK FILEDOWNLINKCFG +FILEHANDLINGSUBTOPOLOGY FILEID FILEOPENERROR FILEWRITEERROR From c05a94274ff64e573f1de989367ab39da5cb2885 Mon Sep 17 00:00:00 2001 From: Moises Mata <123202308+moisesmata@users.noreply.github.com> Date: Mon, 9 Jun 2025 10:41:01 -0700 Subject: [PATCH 17/52] Update comment for clarity --- Svc/Subtopologies/FileHandling/FileHandling.fpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Svc/Subtopologies/FileHandling/FileHandling.fpp b/Svc/Subtopologies/FileHandling/FileHandling.fpp index 8f946fdb9dd..a6d9387fac4 100644 --- a/Svc/Subtopologies/FileHandling/FileHandling.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandling.fpp @@ -57,7 +57,6 @@ module FileHandling{ #Passive Components # Subtopology imports - # DataProducts does not exist yet, but we will need it for the file handling subtopology import DataProducts.Subtopology import Comms.Subtopology From b0deda5cafe4969c9e87dfdbc8fde6c2eef6db67 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 9 Jun 2025 16:18:22 -0700 Subject: [PATCH 18/52] Initial move to phasing components --- Ref/Top/RefTopology.cpp | 96 ++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 6425eeff79f..12fd948346d 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -32,7 +32,7 @@ Fw::MallocAllocator mallocator; // The reference topology uses the F´ packet protocol when communicating with the ground and therefore uses the F´ // framing and deframing implementations. -Svc::FrameDetectors::FprimeFrameDetector frameDetector; +Svc::FrameDetector::FprimeFrameDetector frameDetector; // The reference topology divides the incoming clock signal (1Hz) into sub-signals: 1Hz, 1/2Hz, and 1/4Hz and @@ -49,23 +49,23 @@ Svc::ComQueue::QueueConfigurationTable configurationTable; // A number of constants are needed for construction of the topology. These are specified here. enum TopologyConstants { - CMD_SEQ_BUFFER_SIZE = 5 * 1024, - FILE_DOWNLINK_TIMEOUT = 1000, - FILE_DOWNLINK_COOLDOWN = 1000, - FILE_DOWNLINK_CYCLE_TIME = 1000, - FILE_DOWNLINK_FILE_QUEUE_DEPTH = 10, - HEALTH_WATCHDOG_CODE = 0x123, + //CMD_SEQ_BUFFER_SIZE = 5 * 1024, + //FILE_DOWNLINK_TIMEOUT = 1000, + //FILE_DOWNLINK_COOLDOWN = 1000, + //FILE_DOWNLINK_CYCLE_TIME = 1000, + //FILE_DOWNLINK_FILE_QUEUE_DEPTH = 10, + //HEALTH_WATCHDOG_CODE = 0x123, COMM_PRIORITY = 100, // Buffer manager for Uplink/Downlink - COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, - COMMS_BUFFER_MANAGER_STORE_COUNT = 20, - COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, - COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30, - COMMS_BUFFER_MANAGER_ID = 200, + //COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, + //COMMS_BUFFER_MANAGER_STORE_COUNT = 20, + //COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, + //COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30, + //COMMS_BUFFER_MANAGER_ID = 200, // Buffer manager for Data Products - DP_BUFFER_MANAGER_STORE_SIZE = 10000, - DP_BUFFER_MANAGER_STORE_COUNT = 10, - DP_BUFFER_MANAGER_ID = 300, + //DP_BUFFER_MANAGER_STORE_SIZE = 10000, + //DP_BUFFER_MANAGER_STORE_COUNT = 10, + //DP_BUFFER_MANAGER_ID = 300, }; /** @@ -77,7 +77,7 @@ enum TopologyConstants { */ void configureTopology() { // Command sequencer needs to allocate memory to hold contents of command sequences - Comms::cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE); + Comms::cmdSeq.allocateBuffer(0, mallocator, Ref::ConfigConstants::Comms_cmdSeq::CMD_SEQ_BUFFER_SIZE); // Rate group driver needs a divisor list rateGroupDriverComp.configure(rateGroupDivisorsSet); @@ -88,55 +88,55 @@ void configureTopology() { rateGroup3Comp.configure(rateGroup3Context, FW_NUM_ARRAY_ELEMENTS(rateGroup3Context)); // File downlink requires some project-derived properties. - FileHandling::fileDownlink.configure(FILE_DOWNLINK_TIMEOUT, FILE_DOWNLINK_COOLDOWN, FILE_DOWNLINK_CYCLE_TIME, - FILE_DOWNLINK_FILE_QUEUE_DEPTH); + //FileHandling::fileDownlink.configure(FILE_DOWNLINK_TIMEOUT, FILE_DOWNLINK_COOLDOWN, FILE_DOWNLINK_CYCLE_TIME, + //FILE_DOWNLINK_FILE_QUEUE_DEPTH); // Parameter database is configured with a database file name, and that file must be initially read. - FileHandling::prmDb.configure("PrmDb.dat"); - FileHandling::prmDb.readParamFile(); + //FileHandling::prmDb.configure("PrmDb.dat"); + //FileHandling::prmDb.readParamFile(); // Health is supplied a set of ping entires. - CDHCore::health.setPingEntries(ConfigObjects::CDHCore_health::pingEntries, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::CDHCore_health::pingEntries), HEALTH_WATCHDOG_CODE); + //CDHCore::health.setPingEntries(ConfigObjects::CDHCore_health::pingEntries, + // FW_NUM_ARRAY_ELEMENTS(ConfigObjects::CDHCore_health::pingEntries), HEALTH_WATCHDOG_CODE); // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. - Svc::BufferManager::BufferBins commsBuffMgrBins; - memset(&commsBuffMgrBins, 0, sizeof(commsBuffMgrBins)); - commsBuffMgrBins.bins[0].bufferSize = COMMS_BUFFER_MANAGER_STORE_SIZE; - commsBuffMgrBins.bins[0].numBuffers = COMMS_BUFFER_MANAGER_STORE_COUNT; - commsBuffMgrBins.bins[1].bufferSize = COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - commsBuffMgrBins.bins[1].numBuffers = COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; - Comms::commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins); + //Svc::BufferManager::BufferBins commsBuffMgrBins; + //memset(&commsBuffMgrBins, 0, sizeof(commsBuffMgrBins)); + //commsBuffMgrBins.bins[0].bufferSize = COMMS_BUFFER_MANAGER_STORE_SIZE; + //commsBuffMgrBins.bins[0].numBuffers = COMMS_BUFFER_MANAGER_STORE_COUNT; + //commsBuffMgrBins.bins[1].bufferSize = COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; + //commsBuffMgrBins.bins[1].numBuffers = COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + //Comms::commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins); - Svc::BufferManager::BufferBins dpBuffMgrBins; - memset(&dpBuffMgrBins, 0, sizeof(dpBuffMgrBins)); - dpBuffMgrBins.bins[0].bufferSize = DP_BUFFER_MANAGER_STORE_SIZE; - dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT; - DataProducts::dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins); + //Svc::BufferManager::BufferBins dpBuffMgrBins; + //memset(&dpBuffMgrBins, 0, sizeof(dpBuffMgrBins)); + //dpBuffMgrBins.bins[0].bufferSize = DP_BUFFER_MANAGER_STORE_SIZE; + //dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT; + //DataProducts::dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins); - Comms::frameAccumulator.configure(frameDetector, 1, mallocator, 2048); + //Comms::frameAccumulator.configure(frameDetector, 1, mallocator, 2048); - Fw::FileNameString dpDir("./DpCat"); - Fw::FileNameString dpState("./DpCat/DpState.dat"); + //Fw::FileNameString dpDir("./DpCat"); + //Fw::FileNameString dpState("./DpCat/DpState.dat"); // create the DP directory if it doesn't exist - Os::FileSystem::createDirectory(dpDir.toChar()); + //Os::FileSystem::createDirectory(dpDir.toChar()); - DataProducts::dpCat.configure(&dpDir,1,dpState,0,mallocator); - DataProducts::dpWriter.configure(dpDir); + //DataProducts::dpCat.configure(&dpDir,1,dpState,0,mallocator); + //DataProducts::dpWriter.configure(dpDir); // ComQueue configuration // Events (highest-priority) - configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].depth = 100; - configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].priority = 0; + //configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].depth = 100; + //configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].priority = 0; // Telemetry - configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].depth = 500; - configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].priority = 2; + //configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].depth = 500; + //configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].priority = 2; // File Downlink (first entry after the ComPacket queues = NUM_CONSTANTS) - configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100; - configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1; + //configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100; + //configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1; // Allocation identifier is 0 as the MallocAllocator discards it - Comms::comQueue.configure(configurationTable, 0, mallocator); + //Comms::comQueue.configure(configurationTable, 0, mallocator); // Note: Uncomment when using Svc:TlmPacketizer // tlmSend.setPacketList(Ref::Ref_RefPacketsTlmPackets::packetList, Ref::Ref_RefPacketsTlmPackets::omittedChannels, 1); @@ -165,7 +165,7 @@ void setupTopology(const TopologyState& state) { // Autocoded task kick-off (active components). Function provided by autocoder. startTasks(state); // Startup TLM and Config verbosity for Versions - CDHCore::version.config(true); + //CDHCore::version.config(true); // Initialize socket client communication if and only if there is a valid specification if (state.hostname != nullptr && state.port != 0) { Os::TaskString name("ReceiveTask"); From 5dc46cf8b12d466354b6aae0f357dfec2865bf9c Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Tue, 10 Jun 2025 10:29:57 -0700 Subject: [PATCH 19/52] Fixing Phasing: Adding initial Phasing for CDHCore, DataProducts, FileHandling --- Ref/Top/RefTopology.cpp | 52 +++++++++---------- Ref/Top/RefTopology.hpp | 1 + Svc/Subtopologies/CDHCore/CDHCore.fpp | 33 +++++++++--- .../DataProducts/DataProducts.fpp | 43 +++++++++++++-- .../FileHandling/FileHandling.fpp | 39 +++++++++++--- 5 files changed, 124 insertions(+), 44 deletions(-) diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 12fd948346d..386b4315e2b 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -32,7 +32,7 @@ Fw::MallocAllocator mallocator; // The reference topology uses the F´ packet protocol when communicating with the ground and therefore uses the F´ // framing and deframing implementations. -Svc::FrameDetector::FprimeFrameDetector frameDetector; +Svc::FrameDetectors::FprimeFrameDetector frameDetector; // The reference topology divides the incoming clock signal (1Hz) into sub-signals: 1Hz, 1/2Hz, and 1/4Hz and @@ -49,7 +49,7 @@ Svc::ComQueue::QueueConfigurationTable configurationTable; // A number of constants are needed for construction of the topology. These are specified here. enum TopologyConstants { - //CMD_SEQ_BUFFER_SIZE = 5 * 1024, + CMD_SEQ_BUFFER_SIZE = 5 * 1024, //FILE_DOWNLINK_TIMEOUT = 1000, //FILE_DOWNLINK_COOLDOWN = 1000, //FILE_DOWNLINK_CYCLE_TIME = 1000, @@ -57,11 +57,11 @@ enum TopologyConstants { //HEALTH_WATCHDOG_CODE = 0x123, COMM_PRIORITY = 100, // Buffer manager for Uplink/Downlink - //COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, - //COMMS_BUFFER_MANAGER_STORE_COUNT = 20, - //COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, - //COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30, - //COMMS_BUFFER_MANAGER_ID = 200, + COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, + COMMS_BUFFER_MANAGER_STORE_COUNT = 20, + COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, + COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30, + COMMS_BUFFER_MANAGER_ID = 200, // Buffer manager for Data Products //DP_BUFFER_MANAGER_STORE_SIZE = 10000, //DP_BUFFER_MANAGER_STORE_COUNT = 10, @@ -77,7 +77,7 @@ enum TopologyConstants { */ void configureTopology() { // Command sequencer needs to allocate memory to hold contents of command sequences - Comms::cmdSeq.allocateBuffer(0, mallocator, Ref::ConfigConstants::Comms_cmdSeq::CMD_SEQ_BUFFER_SIZE); + Comms::cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE); // Rate group driver needs a divisor list rateGroupDriverComp.configure(rateGroupDivisorsSet); @@ -96,17 +96,17 @@ void configureTopology() { //FileHandling::prmDb.readParamFile(); // Health is supplied a set of ping entires. - //CDHCore::health.setPingEntries(ConfigObjects::CDHCore_health::pingEntries, - // FW_NUM_ARRAY_ELEMENTS(ConfigObjects::CDHCore_health::pingEntries), HEALTH_WATCHDOG_CODE); + //health.setPingEntries(ConfigObjects::Ref_health::pingEntries, + //FW_NUM_ARRAY_ELEMENTS(ConfigObjects::Ref_health::pingEntries), HEALTH_WATCHDOG_CODE); // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. - //Svc::BufferManager::BufferBins commsBuffMgrBins; - //memset(&commsBuffMgrBins, 0, sizeof(commsBuffMgrBins)); - //commsBuffMgrBins.bins[0].bufferSize = COMMS_BUFFER_MANAGER_STORE_SIZE; - //commsBuffMgrBins.bins[0].numBuffers = COMMS_BUFFER_MANAGER_STORE_COUNT; - //commsBuffMgrBins.bins[1].bufferSize = COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - //commsBuffMgrBins.bins[1].numBuffers = COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; - //Comms::commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins); + Svc::BufferManager::BufferBins commsBuffMgrBins; + memset(&commsBuffMgrBins, 0, sizeof(commsBuffMgrBins)); + commsBuffMgrBins.bins[0].bufferSize = COMMS_BUFFER_MANAGER_STORE_SIZE; + commsBuffMgrBins.bins[0].numBuffers = COMMS_BUFFER_MANAGER_STORE_COUNT; + commsBuffMgrBins.bins[1].bufferSize = COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; + commsBuffMgrBins.bins[1].numBuffers = COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + Comms::commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins); //Svc::BufferManager::BufferBins dpBuffMgrBins; //memset(&dpBuffMgrBins, 0, sizeof(dpBuffMgrBins)); @@ -114,7 +114,7 @@ void configureTopology() { //dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT; //DataProducts::dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins); - //Comms::frameAccumulator.configure(frameDetector, 1, mallocator, 2048); + Comms::frameAccumulator.configure(frameDetector, 1, mallocator, 2048); //Fw::FileNameString dpDir("./DpCat"); //Fw::FileNameString dpState("./DpCat/DpState.dat"); @@ -127,16 +127,16 @@ void configureTopology() { // ComQueue configuration // Events (highest-priority) - //configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].depth = 100; - //configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].priority = 0; + configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].depth = 100; + configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].priority = 0; // Telemetry - //configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].depth = 500; - //configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].priority = 2; + configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].depth = 500; + configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].priority = 2; // File Downlink (first entry after the ComPacket queues = NUM_CONSTANTS) - //configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100; - //configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1; + configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100; + configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1; // Allocation identifier is 0 as the MallocAllocator discards it - //Comms::comQueue.configure(configurationTable, 0, mallocator); + Comms::comQueue.configure(configurationTable, 0, mallocator); // Note: Uncomment when using Svc:TlmPacketizer // tlmSend.setPacketList(Ref::Ref_RefPacketsTlmPackets::packetList, Ref::Ref_RefPacketsTlmPackets::omittedChannels, 1); @@ -200,4 +200,4 @@ void teardownTopology(const TopologyState& state) { Comms::commsBufferManager.cleanup(); Comms::frameAccumulator.cleanup(); } -} // namespace Ref +} // namespace Ref \ No newline at end of file diff --git a/Ref/Top/RefTopology.hpp b/Ref/Top/RefTopology.hpp index 9fd39628d8a..19502fce4ac 100644 --- a/Ref/Top/RefTopology.hpp +++ b/Ref/Top/RefTopology.hpp @@ -14,6 +14,7 @@ // autocoder, but are also used in this hand-coded topology. #include + // Remove unnecessary Ref:: qualifications using namespace Ref; namespace Ref { diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index a2012052f98..f6ab03ffa76 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -22,21 +22,40 @@ module CDHCore { # ---------------------------------------------------------------------- instance $health: Svc.Health base id CDHCoreConfig.BASE_ID + 0x0400 \ queue size CDHCoreConfig.QueueSizes.$health \ - + { + phase Fpp.ToCpp.Phases.configConstants """ + enum { + HEALTH_WATCHDOG_CODE = 0x123 + }; + """ + phase Fpp.ToCpp.Phases.configComponents """ + CDHCore::health.setPingEntries( + ConfigObjects::CDHCore_health::pingEntries, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::CDHCore_health::pingEntries), + ConfigConstants::CDHCore_health::HEALTH_WATCHDOG_CODE + ); + """ + } + # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- instance version: Svc.Version base id CDHCoreConfig.BASE_ID + 0x0500 \ + { + phase Fpp.ToCpp.Phases.configComponents """ + CDHCore::version.config(true); + """ + } + + instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.BASE_ID + 0x0600 + + instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.BASE_ID + 0x0700 - instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.BASE_ID + 0x0600 \ - - instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.BASE_ID + 0x0700 \ + instance fatalHandler: Svc.FatalHandler base id CDHCoreConfig.BASE_ID + 0x0800 - instance fatalHandler: Svc.FatalHandler base id CDHCoreConfig.BASE_ID + 0x0800 \ - topology Subtopology { #Active Components - instance cmdDisp + instance cmdDisp instance events instance tlmSend diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 64341902b6f..edd35ebda3f 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -11,7 +11,15 @@ module DataProducts{ instance dpCat: Svc.DpCatalog base id DataProductsConfig.BASE_ID + 0x0100 \ queue size DataProductsConfig.QueueSizes.dpCat \ stack size DataProductsConfig.StackSizes.dpCat \ - priority DataProductsConfig.Priorities.dpCat + priority DataProductsConfig.Priorities.dpCat \ + { + phase Fpp.ToCpp.Phases.configComponents """ + Fw::FileNameString dpDir("./DpCat"); + Fw::FileNameString dpState("./DpCat/DpState.dat"); + Os::FileSystem::createDirectory(dpDir.toChar()); + DataProducts::dpCat.configure(&dpDir,1,dpState,0,mallocator); + """ + } instance dpMgr: Svc.DpManager base id DataProductsConfig.BASE_ID + 0x0200 \ queue size DataProductsConfig.QueueSizes.dpMgr \ @@ -21,8 +29,12 @@ module DataProducts{ instance dpWriter: Svc.DpWriter base id DataProductsConfig.BASE_ID + 0x0300 \ queue size DataProductsConfig.QueueSizes.dpWriter \ stack size DataProductsConfig.StackSizes.dpWriter \ - priority DataProductsConfig.Priorities.dpWriter - + priority DataProductsConfig.Priorities.dpWriter \ + { + phase Fpp.ToCpp.Phases.configComponents """ + DataProducts::dpWriter.configure(dpDir); + """ + } # ---------------------------------------------------------------------- # Queued Components # ---------------------------------------------------------------------- @@ -32,9 +44,30 @@ module DataProducts{ # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - - instance dpBufferManager: Svc.BufferManager base id 0x4A00 + instance dpBufferManager: Svc.BufferManager base id 0x4A00 \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum { + DP_BUFFER_MANAGER_STORE_SIZE = 10000, + DP_BUFFER_MANAGER_STORE_COUNT = 10, + DP_BUFFER_MANAGER_ID = 300 + }; + """ + phase Fpp.ToCpp.Phases.configComponents """ + Fw::MallocAllocator mallocator; + Svc::BufferManager::BufferBins bins; + memset(&bins, 0, sizeof(bins)); + bins.bins[0].bufferSize = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_SIZE; + bins.bins[0].numBuffers = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_COUNT; + DataProducts::dpBufferManager.setup( + ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_ID, + 0, + mallocator, + bins + ); + """ + } topology Subtopology { #Active Components instance dpCat diff --git a/Svc/Subtopologies/FileHandling/FileHandling.fpp b/Svc/Subtopologies/FileHandling/FileHandling.fpp index a6d9387fac4..57716de43fb 100644 --- a/Svc/Subtopologies/FileHandling/FileHandling.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandling.fpp @@ -1,8 +1,8 @@ -module FileHandling{ +module FileHandling { - enum Ports_ComBufferQueue { - FILE_DOWNLINK - } + enum Ports_ComBufferQueue { + FILE_DOWNLINK + } # ---------------------------------------------------------------------- # Active Components @@ -22,7 +22,25 @@ module FileHandling{ instance fileDownlink: Svc.FileDownlink base id FileHandlingConfig.BASE_ID + 0x0200 \ queue size FileHandlingConfig.QueueSizes.fileDownlink \ stack size FileHandlingConfig.StackSizes.fileDownlink \ - priority FileHandlingConfig.Priorities.fileDownlink + priority FileHandlingConfig.Priorities.fileDownlink \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum { + FILE_DOWNLINK_TIMEOUT = 1000, + FILE_DOWNLINK_COOLDOWN = 1000, + FILE_DOWNLINK_CYCLE_TIME = 1000, + FILE_DOWNLINK_FILE_QUEUE_DEPTH = 10 + }; + """ + phase Fpp.ToCpp.Phases.configComponents """ + FileHandling::fileDownlink.configure( + ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_TIMEOUT, + ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_COOLDOWN, + ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_CYCLE_TIME, + ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_FILE_QUEUE_DEPTH + ); + """ + } instance fileManager: Svc.FileManager base id FileHandlingConfig.BASE_ID + 0x0300 \ queue size FileHandlingConfig.QueueSizes.fileManager \ @@ -32,7 +50,15 @@ module FileHandling{ instance prmDb: Svc.PrmDb base id FileHandlingConfig.BASE_ID + 0x0400 \ queue size FileHandlingConfig.QueueSizes.prmDb \ stack size FileHandlingConfig.StackSizes.prmDb \ - priority FileHandlingConfig.Priorities.prmDb + priority FileHandlingConfig.Priorities.prmDb \ + { + phase Fpp.ToCpp.Phases.configComponents """ + FileHandling::prmDb.configure("PrmDb.dat"); + """ + phase Fpp.ToCpp.Phases.readParameters """ + FileHandling::prmDb.readParamFile(); + """ + } # ---------------------------------------------------------------------- # Queued Components @@ -57,6 +83,7 @@ module FileHandling{ #Passive Components # Subtopology imports + # DataProducts does not exist yet, but we will need it for the file handling subtopology import DataProducts.Subtopology import Comms.Subtopology From 03f158ce3a9b7edcfba738adf82c4c3d60b612ee Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Tue, 10 Jun 2025 16:12:31 -0700 Subject: [PATCH 20/52] Renaming topologydefs.hpp, phasing fully working on all four subtopologies, needs cleaning up --- RPI/Top/topology.fpp | 1 + Ref/Top/RefTopology.cpp | 109 +-------------- Ref/Top/RefTopologyDefs.hpp | 8 +- Ref/Top/topology.fpp | 35 ++++- Svc/Subtopologies/CDHCore/CMakeLists.txt | 2 +- ...gyDefs.hpp => SubtopologyTopologyDefs.hpp} | 6 +- Svc/Subtopologies/Comms/CMakeLists.txt | 5 +- Svc/Subtopologies/Comms/Comms.fpp | 131 +++++++++++++++--- Svc/Subtopologies/Comms/CommsTopologyDefs.cpp | 15 ++ Svc/Subtopologies/Comms/CommsTopologyDefs.hpp | 15 -- .../Comms/SubtopologyTopologyDefs.hpp | 36 +++++ Svc/Subtopologies/DataProducts/CMakeLists.txt | 5 +- .../DataProducts/DataProducts.fpp | 31 +---- .../DataProducts/DataProductsTopologyDefs.cpp | 11 ++ .../DataProducts/DataProductsTopologyDefs.hpp | 15 -- .../DataProducts/SubtopologyTopologyDefs.hpp | 28 ++++ Svc/Subtopologies/FileHandling/CMakeLists.txt | 2 +- .../FileHandling/FileHandling.fpp | 42 +----- ...gyDefs.hpp => SubtopologyTopologyDefs.hpp} | 5 +- 19 files changed, 263 insertions(+), 239 deletions(-) rename Svc/Subtopologies/CDHCore/{CDHCoreTopologyDefs.hpp => SubtopologyTopologyDefs.hpp} (70%) create mode 100644 Svc/Subtopologies/Comms/CommsTopologyDefs.cpp delete mode 100644 Svc/Subtopologies/Comms/CommsTopologyDefs.hpp create mode 100644 Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp create mode 100644 Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.cpp delete mode 100644 Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp create mode 100644 Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp rename Svc/Subtopologies/FileHandling/{FileHandlingTopologyDefs.hpp => SubtopologyTopologyDefs.hpp} (75%) diff --git a/RPI/Top/topology.fpp b/RPI/Top/topology.fpp index a8abd2cc987..4e3c3ff60f2 100644 --- a/RPI/Top/topology.fpp +++ b/RPI/Top/topology.fpp @@ -162,6 +162,7 @@ module RPI { fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn } + } } diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 386b4315e2b..0ada2870e0f 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +//#include // Used for 1Hz synthetic cycling #include @@ -26,15 +26,6 @@ using namespace Ref; // Instantiate a system logger that will handle Fw::Logger::log calls Os::Console logger; -// The reference topology uses a malloc-based allocator for components that need to allocate memory during the -// initialization phase. -Fw::MallocAllocator mallocator; - -// The reference topology uses the F´ packet protocol when communicating with the ground and therefore uses the F´ -// framing and deframing implementations. -Svc::FrameDetectors::FprimeFrameDetector frameDetector; - - // The reference topology divides the incoming clock signal (1Hz) into sub-signals: 1Hz, 1/2Hz, and 1/4Hz and // zero offset for all the dividers Svc::RateGroupDriver::DividerSet rateGroupDivisorsSet{{{1, 0}, {2, 0}, {4, 0}}}; @@ -45,29 +36,6 @@ U32 rateGroup1Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; U32 rateGroup2Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; U32 rateGroup3Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; -Svc::ComQueue::QueueConfigurationTable configurationTable; - -// A number of constants are needed for construction of the topology. These are specified here. -enum TopologyConstants { - CMD_SEQ_BUFFER_SIZE = 5 * 1024, - //FILE_DOWNLINK_TIMEOUT = 1000, - //FILE_DOWNLINK_COOLDOWN = 1000, - //FILE_DOWNLINK_CYCLE_TIME = 1000, - //FILE_DOWNLINK_FILE_QUEUE_DEPTH = 10, - //HEALTH_WATCHDOG_CODE = 0x123, - COMM_PRIORITY = 100, - // Buffer manager for Uplink/Downlink - COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, - COMMS_BUFFER_MANAGER_STORE_COUNT = 20, - COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, - COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30, - COMMS_BUFFER_MANAGER_ID = 200, - // Buffer manager for Data Products - //DP_BUFFER_MANAGER_STORE_SIZE = 10000, - //DP_BUFFER_MANAGER_STORE_COUNT = 10, - //DP_BUFFER_MANAGER_ID = 300, -}; - /** * \brief configure/setup components in project-specific way * @@ -76,9 +44,6 @@ enum TopologyConstants { * desired, but is extracted here for clarity. */ void configureTopology() { - // Command sequencer needs to allocate memory to hold contents of command sequences - Comms::cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE); - // Rate group driver needs a divisor list rateGroupDriverComp.configure(rateGroupDivisorsSet); @@ -87,56 +52,6 @@ void configureTopology() { rateGroup2Comp.configure(rateGroup2Context, FW_NUM_ARRAY_ELEMENTS(rateGroup2Context)); rateGroup3Comp.configure(rateGroup3Context, FW_NUM_ARRAY_ELEMENTS(rateGroup3Context)); - // File downlink requires some project-derived properties. - //FileHandling::fileDownlink.configure(FILE_DOWNLINK_TIMEOUT, FILE_DOWNLINK_COOLDOWN, FILE_DOWNLINK_CYCLE_TIME, - //FILE_DOWNLINK_FILE_QUEUE_DEPTH); - - // Parameter database is configured with a database file name, and that file must be initially read. - //FileHandling::prmDb.configure("PrmDb.dat"); - //FileHandling::prmDb.readParamFile(); - - // Health is supplied a set of ping entires. - //health.setPingEntries(ConfigObjects::Ref_health::pingEntries, - //FW_NUM_ARRAY_ELEMENTS(ConfigObjects::Ref_health::pingEntries), HEALTH_WATCHDOG_CODE); - - // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. - Svc::BufferManager::BufferBins commsBuffMgrBins; - memset(&commsBuffMgrBins, 0, sizeof(commsBuffMgrBins)); - commsBuffMgrBins.bins[0].bufferSize = COMMS_BUFFER_MANAGER_STORE_SIZE; - commsBuffMgrBins.bins[0].numBuffers = COMMS_BUFFER_MANAGER_STORE_COUNT; - commsBuffMgrBins.bins[1].bufferSize = COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - commsBuffMgrBins.bins[1].numBuffers = COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; - Comms::commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins); - - //Svc::BufferManager::BufferBins dpBuffMgrBins; - //memset(&dpBuffMgrBins, 0, sizeof(dpBuffMgrBins)); - //dpBuffMgrBins.bins[0].bufferSize = DP_BUFFER_MANAGER_STORE_SIZE; - //dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT; - //DataProducts::dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins); - - Comms::frameAccumulator.configure(frameDetector, 1, mallocator, 2048); - - //Fw::FileNameString dpDir("./DpCat"); - //Fw::FileNameString dpState("./DpCat/DpState.dat"); - - // create the DP directory if it doesn't exist - //Os::FileSystem::createDirectory(dpDir.toChar()); - - //DataProducts::dpCat.configure(&dpDir,1,dpState,0,mallocator); - //DataProducts::dpWriter.configure(dpDir); - - // ComQueue configuration - // Events (highest-priority) - configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].depth = 100; - configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].priority = 0; - // Telemetry - configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].depth = 500; - configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].priority = 2; - // File Downlink (first entry after the ComPacket queues = NUM_CONSTANTS) - configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100; - configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1; - // Allocation identifier is 0 as the MallocAllocator discards it - Comms::comQueue.configure(configurationTable, 0, mallocator); // Note: Uncomment when using Svc:TlmPacketizer // tlmSend.setPacketList(Ref::Ref_RefPacketsTlmPackets::packetList, Ref::Ref_RefPacketsTlmPackets::omittedChannels, 1); @@ -155,9 +70,9 @@ void setupTopology(const TopologyState& state) { regCommands(); // Autocoded configuration. Function provided by autocoder. configComponents(state); - if (state.hostname != nullptr && state.port != 0) { - Comms::comDriver.configure(state.hostname, state.port); - } + //if (state.hostname != nullptr && state.port != 0) { + //Comms::comDriver.configure(state.hostname, state.port); + //} // Project-specific component configuration. Function provided above. May be inlined, if desired. configureTopology(); // Autocoded parameter loading. Function provided by autocoder. @@ -165,13 +80,6 @@ void setupTopology(const TopologyState& state) { // Autocoded task kick-off (active components). Function provided by autocoder. startTasks(state); // Startup TLM and Config verbosity for Versions - //CDHCore::version.config(true); - // Initialize socket client communication if and only if there is a valid specification - if (state.hostname != nullptr && state.port != 0) { - Os::TaskString name("ReceiveTask"); - // Uplink is configured for receive so a socket task is started - Comms::comDriver.start(name, COMM_PRIORITY, Default::STACK_SIZE); - } } void startRateGroups(Fw::TimeInterval interval) { @@ -190,14 +98,5 @@ void teardownTopology(const TopologyState& state) { // Autocoded (active component) task clean-up. Functions provided by topology autocoder. stopTasks(state); freeThreads(state); - - // Other task clean-up. - Comms::comDriver.stop(); - (void)Comms::comDriver.join(); - - // Resource deallocation - Comms::cmdSeq.deallocateBuffer(mallocator); - Comms::commsBufferManager.cleanup(); - Comms::frameAccumulator.cleanup(); } } // namespace Ref \ No newline at end of file diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 251a6aad248..c4bb4be2bff 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -17,10 +17,10 @@ #include "Svc/Health/Health.hpp" // Subtopology includes -#include "Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp" -#include "Svc/Subtopologies/Comms/CommsTopologyDefs.hpp" -#include "Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp" -#include "Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp" +#include "Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp" +#include "Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp" +#include "Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp" +#include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" namespace PingEntries { namespace Ref_blockDrv {enum { WARN = 3, FATAL = 5 };} diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index ff8c8cd6e82..27fd56095f9 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -17,10 +17,6 @@ module Ref { TELEMETRY } - #Same here - enum Ports_ComBufferQueue { - FILE_DOWNLINK - } topology Ref { # ---------------------------------------------------------------------- @@ -126,8 +122,39 @@ module Ref { DataProducts.dpMgr.productResponseOut[0] -> SG1.productRecvIn # Send filled DP SG1.productSendOut -> DataProducts.dpMgr.productSendIn[0] + + + } + + connections Comms_CDHCore{ + + # events and telemetry to comQueue + CDHCore.events.PktSend -> Comms.comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] + CDHCore.tlmSend.PktSend -> Comms.comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] + + # Router <-> CmdDispatcher + Comms.fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> Comms.fprimeRouter.cmdResponseIn + Comms.cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> Comms.cmdSeq.cmdResponseIn + } + + connections Comms_FileHandling { + # File Downlink <-> ComQueue + FileHandling.fileDownlink.bufferSendOut -> Comms.comQueue.bufferQueueIn[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] + Comms.comQueue.bufferReturnOut[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] -> FileHandling.fileDownlink.bufferReturn + + # Router <-> FileUplink + Comms.fprimeRouter.fileOut -> FileHandling.fileUplink.bufferSendIn + FileHandling.fileUplink.bufferSendOut -> Comms.fprimeRouter.fileBufferReturnIn } + connections FileHandling_DataProducts{ + # Data Products + DataProducts.dpCat.fileOut -> FileHandling.fileDownlink.SendFile + FileHandling.fileDownlink.FileComplete -> DataProducts.dpCat.fileDone + } + } } diff --git a/Svc/Subtopologies/CDHCore/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CMakeLists.txt index 490135b9b5a..f88798369ef 100644 --- a/Svc/Subtopologies/CDHCore/CMakeLists.txt +++ b/Svc/Subtopologies/CDHCore/CMakeLists.txt @@ -4,6 +4,6 @@ register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/CDHCore.fpp" HEADERS - "${CMAKE_CURRENT_LIST_DIR}/CDHCoreTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" INTERFACE ) diff --git a/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp b/Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp similarity index 70% rename from Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp rename to Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp index 14816869c20..09e42fc04e5 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreTopologyDefs.hpp +++ b/Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp @@ -2,9 +2,9 @@ #define CDHCORESUBTOPOLOGY_DEFS_HPP namespace CDHCore { - struct CDHCoreState { - /* include any variables that are needed for - configuring/starting/tearing down the topology */ + + // State for topology construction + struct TopologyState { }; } diff --git a/Svc/Subtopologies/Comms/CMakeLists.txt b/Svc/Subtopologies/Comms/CMakeLists.txt index 2152d880827..8088d665c6f 100644 --- a/Svc/Subtopologies/Comms/CMakeLists.txt +++ b/Svc/Subtopologies/Comms/CMakeLists.txt @@ -3,7 +3,8 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsConfig/") register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/Comms.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/CommsTopologyDefs.cpp" HEADERS - "${CMAKE_CURRENT_LIST_DIR}/CommsTopologyDefs.hpp" - INTERFACE + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" ) diff --git a/Svc/Subtopologies/Comms/Comms.fpp b/Svc/Subtopologies/Comms/Comms.fpp index 7313781d48f..b17902726b6 100644 --- a/Svc/Subtopologies/Comms/Comms.fpp +++ b/Svc/Subtopologies/Comms/Comms.fpp @@ -2,8 +2,9 @@ module Comms { enum Ports_ComPacketQueue { EVENTS, - TELEMETRY - } + TELEMETRY, + FILE_QUEUE + }; # ---------------------------------------------------------------------- # Active Components @@ -11,21 +12,102 @@ module Comms { instance comQueue: Svc.ComQueue base id CommsConfig.BASE_ID + 0x0100 \ queue size CommsConfig.QueueSizes.comQueue \ stack size CommsConfig.StackSizes.comQueue \ - priority CommsConfig.Priorities.comQueue + priority CommsConfig.Priorities.comQueue \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum{ + EVENTS, + TELEMETRY, + FILE_QUEUE + }; + """ + phase Fpp.ToCpp.Phases.configComponents """ + Svc::ComQueue::QueueConfigurationTable configurationTable; + // Events (highest-priority) + configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].depth = 100; + configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].priority = 0; + // Telemetry + configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].depth = 500; + configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].priority = 2; + // File Downlink Queue + configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].depth = 100; + configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].priority = 1; + // Allocation identifier is 0 as the MallocAllocator discards it + Comms::comQueue.configure(configurationTable, 0, Comms::Allocation::mallocator); + """ + } instance cmdSeq: Svc.CmdSequencer base id CommsConfig.BASE_ID + 0x0200 \ queue size CommsConfig.QueueSizes.cmdSeq \ stack size CommsConfig.StackSizes.cmdSeq \ - priority CommsConfig.Priorities.cmdSeq - + priority CommsConfig.Priorities.cmdSeq \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum { + CMD_SEQ_BUFFER_SIZE = 5 * 1024 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + Comms::cmdSeq.allocateBuffer(0, Comms::Allocation::mallocator, ConfigConstants::Comms_cmdSeq::CMD_SEQ_BUFFER_SIZE); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + Comms::cmdSeq.deallocateBuffer(Comms::Allocation::mallocator); + """ + } # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- instance commsBufferManager: Svc.BufferManager base id CommsConfig.BASE_ID + 0x0500 \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum { + COMMS_BUFFER_MANAGER_ID = 200, + COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, + COMMS_BUFFER_MANAGER_STORE_COUNT = 20, + COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, + COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + memset(&Comms::BufferManagerBins::bins, 0, sizeof(Comms::BufferManagerBins::bins)); + Comms::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; + Comms::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; + Comms::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; + Comms::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + Comms::commsBufferManager.setup( + ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_ID, + 0, + Comms::Allocation::mallocator, + Comms::BufferManagerBins::bins + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + Comms::commsBufferManager.cleanup(); + """ + } + + instance frameAccumulator: Svc.FrameAccumulator base id CommsConfig.BASE_ID + 0x0600 \ + { + + phase Fpp.ToCpp.Phases.configComponents """ + Comms::frameAccumulator.configure( + Comms::Detector::frameDetector, + 1, + Comms::Allocation::mallocator, + 2048 + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + Comms::frameAccumulator.cleanup(); + """ + } - instance frameAccumulator: Svc.FrameAccumulator base id CommsConfig.BASE_ID + 0x0600 \ - instance deframer: Svc.FprimeDeframer base id CommsConfig.BASE_ID + 0x0700 \ instance fprimeFramer: Svc.FprimeFramer base id CommsConfig.BASE_ID + 0x0800 \ @@ -35,7 +117,29 @@ module Comms { instance comStub: Svc.ComStub base id CommsConfig.BASE_ID + 0x0A00 \ @ Communications driver. May be swapped with other comm drivers like UART - instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ + instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ + { + phase Fpp.ToCpp.Phases.configComponents """ + if (state.hostname != nullptr && state.port != 0) { + Comms::comDriver.configure(state.hostname, state.port); + } + """ + + phase Fpp.ToCpp.Phases.startTasks """ + if (state.hostname != nullptr && state.port != 0) { + Os::TaskString name("ReceiveTask"); + Comms::comDriver.start(name, 100, 100); + } + """ + + phase Fpp.ToCpp.Phases.stopTasks """ + Comms::comDriver.stop(); + """ + + phase Fpp.ToCpp.Phases.freeThreads """ + (void)Comms::comDriver.join(); + """ + } topology Subtopology { # Active Components @@ -51,13 +155,9 @@ module Comms { instance comStub instance comDriver - # Subtopology imports - import CDHCore.Subtopology connections Downlink { # Inputs to ComQueue (events, telemetry) - CDHCore.events.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] - CDHCore.tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] # ComQueue <-> Framer comQueue.dataOut -> fprimeFramer.dataIn fprimeFramer.dataReturnOut -> comQueue.dataReturnIn @@ -98,15 +198,8 @@ module Comms { # Router buffer allocations fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn - # Router <-> CmdDispatcher - fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn } - connections Sequencer { - cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn - } } # end topology } # end Comms Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/CommsTopologyDefs.cpp b/Svc/Subtopologies/Comms/CommsTopologyDefs.cpp new file mode 100644 index 00000000000..f2aa89a0fb0 --- /dev/null +++ b/Svc/Subtopologies/Comms/CommsTopologyDefs.cpp @@ -0,0 +1,15 @@ +#include "SubtopologyTopologyDefs.hpp" + +namespace Comms { + namespace Allocation { + Fw::MallocAllocator mallocator; + } + + namespace BufferManagerBins { + Svc::BufferManager::BufferBins bins; + } + + namespace Detector { + Svc::FrameDetectors::FprimeFrameDetector frameDetector; + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp b/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp deleted file mode 100644 index 31f4a69e52e..00000000000 --- a/Svc/Subtopologies/Comms/CommsTopologyDefs.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef COMMSSUBTOPOLOGY_DEFS_HPP -#define COMMSSUBTOPOLOGY_DEFS_HPP - -namespace Comms { - struct CommsState { - /* include any variables that are needed for - configuring/starting/tearing down the topology */ - }; -} - - namespace PingEntries { - namespace Comms_cmdSeq {enum { WARN = 3, FATAL = 5 };} - } - -#endif \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp new file mode 100644 index 00000000000..e4a2dab201d --- /dev/null +++ b/Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp @@ -0,0 +1,36 @@ +#ifndef COMMSSUBTOPOLOGY_DEFS_HPP +#define COMMSSUBTOPOLOGY_DEFS_HPP + +#include +#include +#include + +namespace Comms { + namespace Allocation { + // Malloc allocator for topology construction + extern Fw::MallocAllocator mallocator; + } + + namespace BufferManagerBins { + // Buffer manager bins for Comms + extern Svc::BufferManager::BufferBins bins; + } + + namespace Detector { + // Frame detector for Comms + extern Svc::FrameDetectors::FprimeFrameDetector frameDetector; + } + + // State for topology construction + struct TopologyState { + const char* hostname; + U16 port; + }; + +} + + namespace PingEntries { + namespace Comms_cmdSeq {enum { WARN = 3, FATAL = 5 };} + } + +#endif \ No newline at end of file diff --git a/Svc/Subtopologies/DataProducts/CMakeLists.txt b/Svc/Subtopologies/DataProducts/CMakeLists.txt index 3868483f380..9faac7c3d02 100644 --- a/Svc/Subtopologies/DataProducts/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/CMakeLists.txt @@ -3,7 +3,8 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig/") register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/DataProducts.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/DataProductsTopologyDefs.cpp" HEADERS - "${CMAKE_CURRENT_LIST_DIR}/DataProductsTopologyDefs.hpp" - INTERFACE + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" ) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index edd35ebda3f..29c762bfb59 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -1,9 +1,5 @@ module DataProducts{ - enum Ports_ComBufferQueue { - FILE_DOWNLINK - } - # ---------------------------------------------------------------------- # Active Components # ---------------------------------------------------------------------- @@ -17,7 +13,7 @@ module DataProducts{ Fw::FileNameString dpDir("./DpCat"); Fw::FileNameString dpState("./DpCat/DpState.dat"); Os::FileSystem::createDirectory(dpDir.toChar()); - DataProducts::dpCat.configure(&dpDir,1,dpState,0,mallocator); + DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::mallocator); """ } @@ -35,11 +31,6 @@ module DataProducts{ DataProducts::dpWriter.configure(dpDir); """ } - # ---------------------------------------------------------------------- - # Queued Components - # ---------------------------------------------------------------------- - #none - # ---------------------------------------------------------------------- # Passive Components @@ -55,16 +46,14 @@ module DataProducts{ }; """ phase Fpp.ToCpp.Phases.configComponents """ - Fw::MallocAllocator mallocator; - Svc::BufferManager::BufferBins bins; - memset(&bins, 0, sizeof(bins)); - bins.bins[0].bufferSize = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_SIZE; - bins.bins[0].numBuffers = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_COUNT; + memset(&DataProducts::BufferManagerBins::bins, 0, sizeof(DataProducts::BufferManagerBins::bins)); + DataProducts::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_SIZE; + DataProducts::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_COUNT; DataProducts::dpBufferManager.setup( ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_ID, 0, - mallocator, - bins + DataProducts::Allocation::mallocator, + DataProducts::BufferManagerBins::bins ); """ } @@ -77,17 +66,11 @@ module DataProducts{ #Passive Components instance dpBufferManager - # Subtopology imports - import Comms.Subtopology - connections DataProducts { # DpMgr and DpWriter connections. Have explicit port indexes for demo dpMgr.bufferGetOut[0] -> dpBufferManager.bufferGetCallee dpMgr.productSendOut[0] -> dpWriter.bufferSendIn dpWriter.deallocBufferSendOut -> dpBufferManager.bufferSendIn - - # Component DP connections - } } # end topology -} # end Comms Subtopology +} # end DataProducts Subtopology diff --git a/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.cpp b/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.cpp new file mode 100644 index 00000000000..0296d9f058c --- /dev/null +++ b/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.cpp @@ -0,0 +1,11 @@ +#include "SubtopologyTopologyDefs.hpp" + +namespace DataProducts { + namespace Allocation { + Fw::MallocAllocator mallocator; + } + + namespace BufferManagerBins { + Svc::BufferManager::BufferBins bins; + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp b/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp deleted file mode 100644 index 0ea4854b00d..00000000000 --- a/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef DATAPRODUCTSSUBTOPOLOGY_DEFS_HPP -#define DATAPRODUCTSSUBTOPOLOGY_DEFS_HPP - -namespace DataProducts { - struct DataProductsState { - /* include any variables that are needed for - configuring/starting/tearing down the topology */ - }; -} - - namespace PingEntries { - namespace DataProducts_dpCat {enum { WARN = 3, FATAL = 5 };} - } - -#endif \ No newline at end of file diff --git a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp new file mode 100644 index 00000000000..58c7d74ce96 --- /dev/null +++ b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp @@ -0,0 +1,28 @@ +#ifndef DATAPRODUCTSSUBTOPOLOGY_DEFS_HPP +#define DATAPRODUCTSSUBTOPOLOGY_DEFS_HPP + +#include +#include +#include + +namespace DataProducts { + namespace Allocation { + // Malloc allocator for topology construction + extern Fw::MallocAllocator mallocator; + } + + namespace BufferManagerBins{ + // Buffer manager bins for Data Products + extern Svc::BufferManager::BufferBins bins; + } + + // State for topology construction + struct TopologyState { + }; +} + + namespace PingEntries { + namespace DataProducts_dpCat {enum { WARN = 3, FATAL = 5 };} + } + +#endif \ No newline at end of file diff --git a/Svc/Subtopologies/FileHandling/CMakeLists.txt b/Svc/Subtopologies/FileHandling/CMakeLists.txt index 33b85112ec5..800caa24e18 100644 --- a/Svc/Subtopologies/FileHandling/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/CMakeLists.txt @@ -4,6 +4,6 @@ register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/FileHandling.fpp" HEADERS - "${CMAKE_CURRENT_LIST_DIR}/FileHandlingTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" INTERFACE ) diff --git a/Svc/Subtopologies/FileHandling/FileHandling.fpp b/Svc/Subtopologies/FileHandling/FileHandling.fpp index 57716de43fb..de13eec2368 100644 --- a/Svc/Subtopologies/FileHandling/FileHandling.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandling.fpp @@ -7,13 +7,6 @@ module FileHandling { # ---------------------------------------------------------------------- # Active Components # ---------------------------------------------------------------------- - - #ex: - #instance comQueue: Svc.ComQueue base id CommsConfig.BASE_ID + 0x0100 \ - # queue size CommsConfig.QueueSizes.comQueue \ - # stack size CommsConfig.StackSizes.comQueue \ - # priority CommsConfig.Priorities.comQueue - instance fileUplink: Svc.FileUplink base id FileHandlingConfig.BASE_ID + 0x0100 \ queue size FileHandlingConfig.QueueSizes.fileUplink \ stack size FileHandlingConfig.StackSizes.fileUplink \ @@ -60,19 +53,6 @@ module FileHandling { """ } - # ---------------------------------------------------------------------- - # Queued Components - # ---------------------------------------------------------------------- - #none - - - # ---------------------------------------------------------------------- - # Passive Components - # ---------------------------------------------------------------------- - - #ex: - #instance commsBufferManager: Svc.BufferManager base id CommsConfig.BASE_ID + 0x0500 \ - topology Subtopology { #Active Components instance fileUplink @@ -80,25 +60,5 @@ module FileHandling { instance fileManager instance prmDb - #Passive Components - - # Subtopology imports - # DataProducts does not exist yet, but we will need it for the file handling subtopology - import DataProducts.Subtopology - import Comms.Subtopology - - connections FileHandling { - # Data Products - DataProducts.dpCat.fileOut -> fileDownlink.SendFile - fileDownlink.FileComplete -> DataProducts.dpCat.fileDone - - # File Downlink <-> ComQueue - fileDownlink.bufferSendOut -> Comms.comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK] - Comms.comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn - - # Router <-> FileUplink - Comms.fprimeRouter.fileOut -> fileUplink.bufferSendIn - fileUplink.bufferSendOut -> Comms.fprimeRouter.fileBufferReturnIn - } } # end topology -} # end Comms Subtopology +} # end FileHandling Subtopology diff --git a/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp similarity index 75% rename from Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp rename to Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp index 0d36c95c0fd..e64b72c3d7e 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp @@ -2,9 +2,8 @@ #define FILEHANDLINGSUBTOPOLOGY_DEFS_HPP namespace FileHandling { - struct FileHandlingState { - /* include any variables that are needed for - configuring/starting/tearing down the topology */ + // State for topology construction + struct TopologyState { }; } From 3bbc05579613f5304652ccd27c2a8096c61396bb Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Wed, 11 Jun 2025 10:57:01 -0700 Subject: [PATCH 21/52] Cleanup with Ports_ComPacketQueue, definition only in Comms.fpp now --- Ref/Top/topology.fpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 27fd56095f9..86c353e874e 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -10,12 +10,6 @@ module Ref { rateGroup3 } - #The topology CPP expects these enums to be defined here, so though the actual comms subtopology does not use it, we cannot remove yet. - #Comms.fpp subtopology file has its own enum, and that is what is really used in the subtopology. - enum Ports_ComPacketQueue { - EVENTS, - TELEMETRY - } topology Ref { @@ -129,8 +123,8 @@ module Ref { connections Comms_CDHCore{ # events and telemetry to comQueue - CDHCore.events.PktSend -> Comms.comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS] - CDHCore.tlmSend.PktSend -> Comms.comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY] + CDHCore.events.PktSend -> Comms.comQueue.comPacketQueueIn[Comms.Ports_ComPacketQueue.EVENTS] + CDHCore.tlmSend.PktSend -> Comms.comQueue.comPacketQueueIn[Comms.Ports_ComPacketQueue.TELEMETRY] # Router <-> CmdDispatcher Comms.fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff From f6f5737f64410f0f9fe2a31223b8b5ed3febf88e Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 16 Jun 2025 09:46:44 -0700 Subject: [PATCH 22/52] Base project with all 4 subtopologies, integrated into Ref, and passing CI --- Ref/Top/RefTopologyDefs.hpp | 2 +- Ref/Top/topology.fpp | 1 - Ref/test/int/ref_integration_test.py | 28 ++++++------- Ref/test/int/test_seq.seq | 4 +- Svc/Subtopologies/CDHCore/CDHCore.fpp | 20 ++------- .../CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 41 ++++++++++++++++--- .../CDHCore/CDHCoreConfig/CMakeLists.txt | 4 +- Svc/Subtopologies/CDHCore/CMakeLists.txt | 4 +- ...pologyTopologyDefs.hpp => PingEntries.hpp} | 11 +---- cmake/test/data/TestDeployment/CMakeLists.txt | 1 + 10 files changed, 63 insertions(+), 53 deletions(-) rename Svc/Subtopologies/CDHCore/{SubtopologyTopologyDefs.hpp => PingEntries.hpp} (56%) diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index c4bb4be2bff..53dd5353ca6 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -17,7 +17,7 @@ #include "Svc/Health/Health.hpp" // Subtopology includes -#include "Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp" +#include "Svc/Subtopologies/CDHCore/PingEntries.hpp" #include "Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 86c353e874e..a12435ab5a0 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -121,7 +121,6 @@ module Ref { } connections Comms_CDHCore{ - # events and telemetry to comQueue CDHCore.events.PktSend -> Comms.comQueue.comPacketQueueIn[Comms.Ports_ComPacketQueue.EVENTS] CDHCore.tlmSend.PktSend -> Comms.comQueue.comPacketQueueIn[Comms.Ports_ComPacketQueue.TELEMETRY] diff --git a/Ref/test/int/ref_integration_test.py b/Ref/test/int/ref_integration_test.py index 3db982d670d..898914fbfa3 100644 --- a/Ref/test/int/ref_integration_test.py +++ b/Ref/test/int/ref_integration_test.py @@ -57,7 +57,7 @@ def set_event_filter(fprime_test_api, severity, enabled): severity = FilterSeverity[severity].name try: fprime_test_api.send_command( - "Ref.eventLogger.SET_EVENT_FILTER", + "CDHCore.events.SET_EVENT_FILTER", [severity, enabled], ) return True @@ -80,9 +80,9 @@ def test_send_command(fprime_test_api): 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("Ref.cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("CDHCore.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("Ref.cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("CDHCore.cmdDisp.CMD_NO_OP", max_delay=0.1) assert fprime_test_api.get_command_test_history().size() == 2 @@ -93,10 +93,10 @@ def test_send_command_args(fprime_test_api): """ for count, value in enumerate(["Test String 1", "Some other string"], 1): events = [ - fprime_test_api.get_event_pred("Ref.cmdDisp.NoOpStringReceived", [value]) + fprime_test_api.get_event_pred("CDHCore.cmdDisp.NoOpStringReceived", [value]) ] fprime_test_api.send_and_assert_command( - "Ref.cmdDisp.CMD_NO_OP_STRING", + "CDHCore.cmdDisp.CMD_NO_OP_STRING", [ value, ], @@ -115,15 +115,15 @@ def test_send_and_assert_no_op(fprime_test_api): length = 100 failed = 0 evr_seq = [ - "Ref.cmdDisp.OpCodeDispatched", - "Ref.cmdDisp.NoOpReceived", - "Ref.cmdDisp.OpCodeCompleted", + "CDHCore.cmdDisp.OpCodeDispatched", + "CDHCore.cmdDisp.NoOpReceived", + "CDHCore.cmdDisp.OpCodeCompleted", ] any_reordered = False dropped = False for i in range(0, length): results = fprime_test_api.send_and_await_event( - "Ref.cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 + "CDHCore.cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 ) msg = "Send and assert NO_OP Trial #{}".format(i) if not fprime_test_api.test_assert(len(results) == 3, msg, True): @@ -230,8 +230,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) - fprime_test_api.send_and_assert_command("Ref.cmdDisp.CMD_NO_OP") - fprime_test_api.send_and_assert_command("Ref.cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("CDHCore.cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("CDHCore.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -242,8 +242,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) fprime_test_api.clear_histories() - fprime_test_api.send_command("Ref.cmdDisp.CMD_NO_OP") - fprime_test_api.send_command("Ref.cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("CDHCore.cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("CDHCore.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -283,5 +283,5 @@ def test_seqgen(fprime_test_api): == 0 ), "Failed to run fprime-seqgen" fprime_test_api.send_and_assert_command( - "Ref.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + "Comms.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 ) diff --git a/Ref/test/int/test_seq.seq b/Ref/test/int/test_seq.seq index c80b1f5578d..bc45caf026e 100644 --- a/Ref/test/int/test_seq.seq +++ b/Ref/test/int/test_seq.seq @@ -1,6 +1,6 @@ ; A test sequence ; -R00:00:00 Ref.cmdDisp.CMD_NO_OP +R00:00:00 CDHCore.cmdDisp.CMD_NO_OP ; Let's try out some commands with arguments -R00:00:01.050 Ref.cmdDisp.CMD_NO_OP_STRING "Awesome string!"; \ No newline at end of file +R00:00:01.050 CDHCore.cmdDisp.CMD_NO_OP_STRING "Awesome string!"; diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index f6ab03ffa76..f9ffe15f4ac 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -12,15 +12,10 @@ module CDHCore { stack size CDHCoreConfig.StackSizes.events \ priority CDHCoreConfig.Priorities.events - instance tlmSend: Svc.TlmChan base id CDHCoreConfig.BASE_ID + 0x0300 \ - queue size CDHCoreConfig.QueueSizes.tlmSend \ - stack size CDHCoreConfig.StackSizes.tlmSend \ - priority CDHCoreConfig.Priorities.tlmSend - # ---------------------------------------------------------------------- # Queued Components # ---------------------------------------------------------------------- - instance $health: Svc.Health base id CDHCoreConfig.BASE_ID + 0x0400 \ + instance $health: Svc.Health base id CDHCoreConfig.BASE_ID + 0x0300 \ queue size CDHCoreConfig.QueueSizes.$health \ { phase Fpp.ToCpp.Phases.configConstants """ @@ -40,18 +35,16 @@ module CDHCore { # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - instance version: Svc.Version base id CDHCoreConfig.BASE_ID + 0x0500 \ + instance version: Svc.Version base id CDHCoreConfig.BASE_ID + 0x0400 \ { phase Fpp.ToCpp.Phases.configComponents """ CDHCore::version.config(true); """ } - instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.BASE_ID + 0x0600 - - instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.BASE_ID + 0x0700 + instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.BASE_ID + 0x0500 - instance fatalHandler: Svc.FatalHandler base id CDHCoreConfig.BASE_ID + 0x0800 + instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.BASE_ID + 0x0600 topology Subtopology { #Active Components @@ -66,11 +59,6 @@ module CDHCore { instance version instance textLogger instance fatalAdapter - instance fatalHandler - - connections FaultProtection { - events.FatalAnnounce -> fatalHandler.FatalReceive - } } # end topology } # end CDHCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp index 7ff0c6d6203..265cb98aab2 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -1,6 +1,6 @@ module CDHCoreConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x7000 + constant BASE_ID = 0x3000 module QueueSizes { constant cmdDisp = 10 @@ -12,14 +12,43 @@ module CDHCoreConfig { module StackSizes { constant cmdDisp = 64 * 1024 - constant events = 10 + constant events = 64 * 1024 constant tlmSend = 64 * 1024 } module Priorities { - constant cmdDisp = 101 - constant $health = 100 - constant events = 99 - constant tlmSend = 98 + constant cmdDisp = 102 + constant $health = 101 + constant events = 100 + constant tlmSend = 99 + } +} + + +module CDHCore { + + instance tlmSend: Svc.TlmChan base id CDHCoreConfig.BASE_ID + 0x0700 \ + queue size CDHCoreConfig.QueueSizes.tlmSend \ + stack size CDHCoreConfig.StackSizes.tlmSend \ + priority CDHCoreConfig.Priorities.tlmSend \ + + # Uncomment the following block and comment the above block to use TlmPacketizer instead of TlmChan + #instance tlmSend: Svc.TlmPacketizer base id CDHCoreConfig.BASE_ID + 0x0700 \ + # queue size CDHCoreConfig.QueueSizes.tlmSend \ + # stack size CDHCoreConfig.StackSizes.tlmSend \ + # priority CDHCoreConfig.Priorities.tlmSend \ + #{ + # # NOTE: The Name Ref is specific to the Reference deployment, Ref + # # This name will need to be updated if wishing to use this in a custom deployment + # phase Fpp.ToCpp.Phases.configComponents """ + # CDHCore::tlmSend.setPacketList( + # Ref::Ref_RefPacketsTlmPackets::packetList, + # Ref::Ref_RefPacketsTlmPackets::omittedChannels, + # 1 + # ); + # """ + #} + + } \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt index 5aa5279fa9c..ba6b42fc956 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt @@ -1,5 +1,5 @@ -register_fprime_config( +register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/CDHCoreConfig.fpp" INTERFACE -) +) \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CMakeLists.txt index f88798369ef..29fd34c8258 100644 --- a/Svc/Subtopologies/CDHCore/CMakeLists.txt +++ b/Svc/Subtopologies/CDHCore/CMakeLists.txt @@ -4,6 +4,6 @@ register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/CDHCore.fpp" HEADERS - "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE -) +) \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/CDHCore/PingEntries.hpp similarity index 56% rename from Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp rename to Svc/Subtopologies/CDHCore/PingEntries.hpp index 09e42fc04e5..cff55279985 100644 --- a/Svc/Subtopologies/CDHCore/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/CDHCore/PingEntries.hpp @@ -1,12 +1,5 @@ -#ifndef CDHCORESUBTOPOLOGY_DEFS_HPP -#define CDHCORESUBTOPOLOGY_DEFS_HPP - -namespace CDHCore { - - // State for topology construction - struct TopologyState { - }; -} +#ifndef CDHCORE_PINGENTRIES_HPP +#define CDHCORE_PINGENTRIES_HPP namespace PingEntries { struct CDHCore_cmdDisp { enum { WARN=3, FATAL=5 }; }; diff --git a/cmake/test/data/TestDeployment/CMakeLists.txt b/cmake/test/data/TestDeployment/CMakeLists.txt index 7a90d9ae54b..cb7f31d7702 100644 --- a/cmake/test/data/TestDeployment/CMakeLists.txt +++ b/cmake/test/data/TestDeployment/CMakeLists.txt @@ -23,3 +23,4 @@ add_fprime_subdirectory(./TestRelative) set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Main.cpp") set(MOD_DEPS Svc_CmdDispatcher TestLibrary_TestComponent TestLibrary2_TestComponent) register_fprime_deployment() +add_dependencies(TestDeployment Svc_Subtopologies_CDHCore Svc_Subtopologies_Comms Svc_Subtopologies_DataProducts Svc_Subtopologies_FileHandling) From 1e70dcdc8b5a02b1e8aceb9ca7956eb07d72357d Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Tue, 17 Jun 2025 10:27:48 -0700 Subject: [PATCH 23/52] Initial Commit with all Subtopologies in Svc/Subtopologies --- Svc/Subtopologies/CommsCCSDS/CMakeLists.txt | 11 + Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp | 205 ++++++++++++++++++ .../CommsCCSDS/CommsCCSDSTopologyefs.cpp | 15 ++ Svc/Subtopologies/CommsCCSDS/PingEntries.hpp | 9 + .../CommsCCSDS/SubtopologyTopologyDefs.hpp | 33 +++ .../CommsCCSDS/config/CMakeLists.txt | 5 + .../CommsCCSDS/config/CommsCCSDSConfig.fpp | 49 +++++ 7 files changed, 327 insertions(+) create mode 100644 Svc/Subtopologies/CommsCCSDS/CMakeLists.txt create mode 100644 Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp create mode 100644 Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyefs.cpp create mode 100644 Svc/Subtopologies/CommsCCSDS/PingEntries.hpp create mode 100644 Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp create mode 100644 Svc/Subtopologies/CommsCCSDS/config/CMakeLists.txt create mode 100644 Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp diff --git a/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt b/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt new file mode 100644 index 00000000000..046229ab889 --- /dev/null +++ b/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt @@ -0,0 +1,11 @@ +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsCCSDSConfig/") + +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/CommsCCSDS.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/CommsCCSDSTopologyDefs.cpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" +) diff --git a/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp b/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp new file mode 100644 index 00000000000..ba95d2e6d94 --- /dev/null +++ b/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp @@ -0,0 +1,205 @@ +module CommsCCSDS { + + enum Ports_ComPacketQueue { + EVENTS, + TELEMETRY, + FILE_QUEUE + }; + + # ---------------------------------------------------------------------- + # Active Components + # ---------------------------------------------------------------------- + instance comQueue: Svc.ComQueue base id CommsCCSDSConfig.BASE_ID + 0x0100 \ + queue size CommsCCSDSConfig.QueueSizes.comQueue \ + stack size CommsCCSDSConfig.StackSizes.comQueue \ + priority CommsCCSDSConfig.Priorities.comQueue \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum{ + EVENTS, + TELEMETRY, + FILE_QUEUE + }; + """ + phase Fpp.ToCpp.Phases.configComponents """ + Svc::ComQueue::QueueConfigurationTable configurationTable; + // Events (highest-priority) + configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].depth = 100; + configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].priority = 0; + // Telemetry + configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].depth = 500; + configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].priority = 2; + // File Downlink Queue + configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].depth = 100; + configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].priority = 1; + // Allocation identifier is 0 as the MallocAllocator discards it + Comms::comQueue.configure(configurationTable, 0, Comms::Allocation::mallocator); + """ + } + + instance cmdSeq: Svc.CmdSequencer base id CommsCCSDSConfig.BASE_ID + 0x0200 \ + queue size CommsCCSDSConfig.QueueSizes.cmdSeq \ + stack size CommsCCSDSConfig.StackSizes.cmdSeq \ + priority CommsCCSDSConfig.Priorities.cmdSeq \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum { + CMD_SEQ_BUFFER_SIZE = 5 * 1024 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + Comms::cmdSeq.allocateBuffer(0, Comms::Allocation::mallocator, ConfigConstants::Comms_cmdSeq::CMD_SEQ_BUFFER_SIZE); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + Comms::cmdSeq.deallocateBuffer(Comms::Allocation::mallocator); + """ + } + + # ---------------------------------------------------------------------- + # Passive Components + # ---------------------------------------------------------------------- + instance commsBufferManager: Svc.BufferManager base id CommsCCSDSConfig.BASE_ID + 0x0500 \ + { + phase Fpp.ToCpp.Phases.configConstants """ + enum { + // Buffer Manager for Uplink/Downlink + COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, + COMMS_BUFFER_MANAGER_STORE_COUNT = 20, + COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, + COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30, + COMMS_BUFFER_MANAGER_ID = 200 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. + memset(&Comms::BufferManagerBins::bins, 0, sizeof(Comms::BufferManagerBins::bins)); + Comms::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; + Comms::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; + Comms::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; + Comms::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + Comms::commsBufferManager.setup( + ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_ID, + 0, + Comms::Allocation::mallocator, + Comms::BufferManagerBins::bins + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + Comms::commsBufferManager.cleanup(); + """ + } + + instance frameAccumulator: Svc.FrameAccumulator base id CommsCCSDSConfig.BASE_ID + 0x0600 \ + { + + phase Fpp.ToCpp.Phases.configComponents """ + Comms::frameAccumulator.configure( + Comms::Detector::frameDetector, + 1, + Comms::Allocation::mallocator, + 2048 + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + Comms::frameAccumulator.cleanup(); + """ + } + + instance fprimeRouter: Svc.FprimeRouter base id CommsCCSDSConfig.BASE_ID + 0x0700 \ + + instance comStub: Svc.ComStub base id CommsCCSDSConfig.BASE_ID + 0x0800 \ + + instance tcDeframer: Svc.CCSDS.TcDeframer base id CommsCCSDSConfig.BASE_ID + 0x0900 \ + + instance spacePacketDeframer: Svc.CCSDS.SpacePacketDeframer base id CommsCCSDSConfig.BASE_ID + 0x0A00 \ + + instance tmFramer: Svc.CCSDS.TmFramer base id CommsCCSDSConfig.BASE_ID + 0x0B00 \ + + instance spacePacketFramer: Svc.CCSDS.SpacePacketFramer base id CommsCCSDSConfig.BASE_ID + 0x0C00 \ + + instance apidManager: Svc.CCSDS.ApidManager base id CommsCCSDSConfig.BASE_ID + 0x0D00 \ + + topology Subtopology { + # Active Components + instance comQueue + instance cmdSeq + + # Passive Components + instance commsBufferManager + instance frameAccumulator + instance fprimeRouter + instance comStub + instance comDriver + instance tcDeframer + instance spacePacketDeframer + instance tmFramer + instance spacePacketFramer + instance apidManager + + connections Downlink { + + + # ComQueue <-> SpacePacketFramer + comQueue.dataOut -> spacePacketFramer.dataIn + spacePacketFramer.dataReturnOut -> comQueue.dataReturnIn + # SpacePacketFramer buffer and APID management + spacePacketFramer.bufferAllocate -> commsBufferManager.bufferGetCallee + spacePacketFramer.bufferDeallocate -> commsBufferManager.bufferSendIn + spacePacketFramer.getApidSeqCount -> apidManager.getApidSeqCountIn + # SpacePacketFramer <-> TmFramer + spacePacketFramer.dataOut -> tmFramer.dataIn + tmFramer.dataReturnOut -> spacePacketFramer.dataReturnIn + # Framer <-> ComStub + tmFramer.dataOut -> comStub.dataIn + comStub.dataReturnOut -> tmFramer.dataReturnIn + # ComStub <-> ComDriver + comStub.drvSendOut -> comDriver.$send + comDriver.sendReturnOut -> comStub.drvSendReturnIn + comDriver.ready -> comStub.drvConnected + # ComStatus + comStub.comStatusOut -> tmFramer.comStatusIn + tmFramer.comStatusOut -> spacePacketFramer.comStatusIn + spacePacketFramer.comStatusOut -> comQueue.comStatusIn + } + + connections Uplink { + # ComDriver buffer allocations + comDriver.allocate -> commsBufferManager.bufferGetCallee + comDriver.deallocate -> commsBufferManager.bufferSendIn + # ComDriver <-> ComStub + comDriver.$recv -> comStub.drvReceiveIn + comStub.drvReceiveReturnOut -> comDriver.recvReturnIn + # ComStub <-> FrameAccumulator + comStub.dataOut -> frameAccumulator.dataIn + frameAccumulator.dataReturnOut -> comStub.dataReturnIn + # FrameAccumulator buffer allocations + frameAccumulator.bufferDeallocate -> commsBufferManager.bufferSendIn + frameAccumulator.bufferAllocate -> commsBufferManager.bufferGetCallee + # FrameAccumulator <-> Deframer + frameAccumulator.dataOut -> tcDeframer.dataIn + tcDeframer.dataReturnOut -> frameAccumulator.dataReturnIn + # TcDeframer <-> SpacePacketDeframer + tcDeframer.dataOut -> spacePacketDeframer.dataIn + spacePacketDeframer.dataReturnOut -> tcDeframer.dataReturnIn + # SpacePacketDeframer APID validation + spacePacketDeframer.validateApidSeqCount -> apidManager.validateApidSeqCountIn + # SpacePacketDeframer <-> Router + spacePacketDeframer.dataOut -> fprimeRouter.dataIn + fprimeRouter.dataReturnOut -> spacePacketDeframer.dataReturnIn + # Router buffer allocations + fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee + fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn + # Router <-> CmdDispatcher/FileUplink + fprimeRouter.commandOut -> cmdDisp.seqCmdBuff + cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn + fprimeRouter.fileOut -> fileUplink.bufferSendIn + fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn + } + + } # end topology +} # end Comms Subtopology diff --git a/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyefs.cpp b/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyefs.cpp new file mode 100644 index 00000000000..38290a0befb --- /dev/null +++ b/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyefs.cpp @@ -0,0 +1,15 @@ +#include "SubtopologyTopologyDefs.hpp" + +namespace Comms { + namespace Allocation { + Fw::MallocAllocator mallocator; + } + + namespace BufferManagerBins { + Svc::BufferManager::BufferBins bins; + } + + namespace Detector { + Svc::FrameDetectors::CcsdsTcFrameDetector frameDetector; + } +} diff --git a/Svc/Subtopologies/CommsCCSDS/PingEntries.hpp b/Svc/Subtopologies/CommsCCSDS/PingEntries.hpp new file mode 100644 index 00000000000..940d95e9281 --- /dev/null +++ b/Svc/Subtopologies/CommsCCSDS/PingEntries.hpp @@ -0,0 +1,9 @@ + +#ifndef COMMSCCSDS_PINGENTRIES_HPP +#define COMMSCCSDS_PINGENTRIES_HPP + + namespace PingEntries { + namespace CommsCCSDS_cmdSeq {enum { WARN = 3, FATAL = 5 };} + } + +#endif diff --git a/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp new file mode 100644 index 00000000000..0cef8763df3 --- /dev/null +++ b/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp @@ -0,0 +1,33 @@ +#ifndef COMMSCCSDSSUBTOPOLOGY_DEFS_HPP +#define COMMSCCSDSSUBTOPOLOGY_DEFS_HPP + +#include +#include +#include + +namespace Comms { + namespace Allocation { + // Malloc allocator for topology construction + extern Fw::MallocAllocator mallocator; + } + + namespace BufferManagerBins { + // Buffer manager bins for Comms + extern Svc::BufferManager::BufferBins bins; + } + + namespace Detector { + // The subtopology uses the CCSDS packet protocol when communicating with the ground and therefore uses the CCSDS + // framing and deframing implementations. + extern Svc::FrameDetectors::CcsdsTcFrameDetector frameDetector; + } + + // State for topology construction + struct TopologyState { + const char* hostname; + U16 port; + }; + +} + +#endif diff --git a/Svc/Subtopologies/CommsCCSDS/config/CMakeLists.txt b/Svc/Subtopologies/CommsCCSDS/config/CMakeLists.txt new file mode 100644 index 00000000000..a981dc90ea5 --- /dev/null +++ b/Svc/Subtopologies/CommsCCSDS/config/CMakeLists.txt @@ -0,0 +1,5 @@ +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/CommsCCSDSConfig.fpp" + INTERFACE +) diff --git a/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp b/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp new file mode 100644 index 00000000000..9a1859eb775 --- /dev/null +++ b/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp @@ -0,0 +1,49 @@ +module CommsCCSDSConfig { + #Base ID for the CDHCore Subtopology, all components are offsets from this base ID + constant BASE_ID = 0x6000 + + module QueueSizes { + constant comQueue = 10 + constant cmdSeq = 10 + } + + + module StackSizes { + constant comQueue = 64 * 1024 + constant cmdSeq = 64 * 1024 + } + + module Priorities { + constant comQueue = 101 + constant cmdSeq = 100 + } +} + +module CommsCCSDS { + # Communications driver. May be swapped out with other comm drivers like UART in this file + # to use another driver in the Comms Subtopology + instance comDriver: Drv.TcpClient base id CommsCCSDSConfig.BASE_ID + 0x0B00 \ + { + phase Fpp.ToCpp.Phases.configComponents """ + if (state.hostname != nullptr && state.port != 0) { + Comms::comDriver.configure(state.hostname, state.port); + } + """ + + phase Fpp.ToCpp.Phases.startTasks """ + // Initialize socket client communication if and only if there is a valid specification + if (state.hostname != nullptr && state.port != 0) { + Os::TaskString name("ReceiveTask"); + Comms::comDriver.start(name, CommsConfig::Priorities::comQueue, CommsConfig::StackSizes::comQueue); + } + """ + + phase Fpp.ToCpp.Phases.stopTasks """ + Comms::comDriver.stop(); + """ + + phase Fpp.ToCpp.Phases.freeThreads """ + (void)Comms::comDriver.join(); + """ + } +} From 797717fd5dbc85cc6714a4e0366b7e92c751e688 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Tue, 17 Jun 2025 14:20:52 -0700 Subject: [PATCH 24/52] Added posixtime back in to Ref Deployment (Accidentally Deleted) --- Ref/Top/instances.fpp | 2 ++ Ref/Top/topology.fpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index b672c8cfb3b..36dc4352acd 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -82,6 +82,8 @@ module Ref { # Passive component instances # ---------------------------------------------------------------------- + instance posixTime: Svc.PosixTime base id 0x4300 + instance rateGroupDriverComp: Svc.RateGroupDriver base id 0x4400 instance recvBuffComp: Ref.RecvBuff base id 0x4500 diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index a210bfede2b..8bd04c12ba5 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -42,7 +42,6 @@ module Ref { instance typeDemo instance systemResources instance linuxTimer - instance fatalHandler # ---------------------------------------------------------------------- # Pattern graph specifiers From a78cbeea623b32809b883cf2e7f64ea729e5c786 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Tue, 17 Jun 2025 23:02:30 -0700 Subject: [PATCH 25/52] Updates to match new subtopology structure, integrate CCSDS into Ref --- Ref/Top/RefPackets.fppi | 24 ++++++++++----------- Ref/Top/RefTopologyDefs.hpp | 5 ++++- Ref/Top/topology.fpp | 32 ++++++++++++++-------------- Ref/test/int/ref_integration_test.py | 2 +- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index 23164e23c84..d88cc08d11c 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -8,20 +8,20 @@ telemetry packets RefPackets { Ref.rateGroup1Comp.RgMaxTime Ref.rateGroup2Comp.RgMaxTime Ref.rateGroup3Comp.RgMaxTime - Comms.cmdSeq.CS_LoadCommands - Comms.cmdSeq.CS_CancelCommands - Comms.cmdSeq.CS_CommandsExecuted - Comms.cmdSeq.CS_SequencesCompleted + CommsCCSDS.cmdSeq.CS_LoadCommands + CommsCCSDS.cmdSeq.CS_CancelCommands + CommsCCSDS.cmdSeq.CS_CommandsExecuted + CommsCCSDS.cmdSeq.CS_SequencesCompleted FileHandling.fileUplink.FilesReceived FileHandling.fileUplink.PacketsReceived - Comms.commsBufferManager.TotalBuffs - Comms.commsBufferManager.CurrBuffs - Comms.commsBufferManager.HiBuffs + CommsCCSDS.commsBufferManager.TotalBuffs + CommsCCSDS.commsBufferManager.CurrBuffs + CommsCCSDS.commsBufferManager.HiBuffs FileHandling.fileDownlink.FilesSent FileHandling.fileDownlink.PacketsSent FileHandling.fileManager.CommandsExecuted - Comms.comQueue.comQueueDepth - Comms.comQueue.buffQueueDepth + CommsCCSDS.comQueue.comQueueDepth + CommsCCSDS.comQueue.buffQueueDepth # Ref.tlmSend.SendLevel } @@ -29,13 +29,13 @@ telemetry packets RefPackets { Ref.rateGroup1Comp.RgCycleSlips Ref.rateGroup2Comp.RgCycleSlips Ref.rateGroup3Comp.RgCycleSlips - Comms.cmdSeq.CS_Errors + CommsCCSDS.cmdSeq.CS_Errors FileHandling.fileUplink.Warnings FileHandling.fileDownlink.Warnings CDHCore.$health.PingLateWarnings FileHandling.fileManager.Errors - Comms.commsBufferManager.NoBuffs - Comms.commsBufferManager.EmptyBuffs + CommsCCSDS.commsBufferManager.NoBuffs + CommsCCSDS.commsBufferManager.EmptyBuffs FileHandling.fileManager.Errors } diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index e001f8500f7..b5f2ae4bb8c 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -19,7 +19,10 @@ // Subtopology includes #include "Svc/Subtopologies/CDHCore/PingEntries.hpp" -#include "Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp" +#include "Svc/Subtopologies/CommsCCSDS/PingEntries.hpp" + +#include "Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp" + #include "Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 8bd04c12ba5..f23a1b77f3d 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -17,7 +17,7 @@ module Ref { # Subtopology imports # ---------------------------------------------------------------------- import CDHCore.Subtopology - import Comms.Subtopology + import CommsCCSDS.Subtopology import FileHandling.Subtopology import DataProducts.Subtopology @@ -83,11 +83,11 @@ module Ref { rateGroup1Comp.RateGroupMemberOut[2] -> CDHCore.tlmSend.Run rateGroup1Comp.RateGroupMemberOut[3] -> FileHandling.fileDownlink.Run rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run - rateGroup1Comp.RateGroupMemberOut[5] -> Comms.comQueue.run + rateGroup1Comp.RateGroupMemberOut[5] -> CommsCCSDS.comQueue.run # Rate group 2 rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup2] -> rateGroup2Comp.CycleIn - rateGroup2Comp.RateGroupMemberOut[0] -> Comms.cmdSeq.schedIn + rateGroup2Comp.RateGroupMemberOut[0] -> CommsCCSDS.cmdSeq.schedIn rateGroup2Comp.RateGroupMemberOut[1] -> sendBuffComp.SchedIn rateGroup2Comp.RateGroupMemberOut[2] -> SG3.schedIn rateGroup2Comp.RateGroupMemberOut[3] -> SG4.schedIn @@ -97,7 +97,7 @@ module Ref { rateGroup3Comp.RateGroupMemberOut[0] -> CDHCore.$health.Run rateGroup3Comp.RateGroupMemberOut[1] -> SG5.schedIn rateGroup3Comp.RateGroupMemberOut[2] -> blockDrv.Sched - rateGroup3Comp.RateGroupMemberOut[3] -> Comms.commsBufferManager.schedIn + rateGroup3Comp.RateGroupMemberOut[3] -> CommsCCSDS.commsBufferManager.schedIn rateGroup3Comp.RateGroupMemberOut[4] -> DataProducts.dpBufferManager.schedIn rateGroup3Comp.RateGroupMemberOut[5] -> DataProducts.dpWriter.schedIn rateGroup3Comp.RateGroupMemberOut[6] -> DataProducts.dpMgr.schedIn @@ -118,26 +118,26 @@ module Ref { } - connections Comms_CDHCore{ + connections CommsCCSDS_CDHCore{ # events and telemetry to comQueue - CDHCore.events.PktSend -> Comms.comQueue.comPacketQueueIn[Comms.Ports_ComPacketQueue.EVENTS] - CDHCore.tlmSend.PktSend -> Comms.comQueue.comPacketQueueIn[Comms.Ports_ComPacketQueue.TELEMETRY] + CDHCore.events.PktSend -> CommsCCSDS.comQueue.comPacketQueueIn[CommsCCSDS.Ports_ComPacketQueue.EVENTS] + CDHCore.tlmSend.PktSend -> CommsCCSDS.comQueue.comPacketQueueIn[CommsCCSDS.Ports_ComPacketQueue.TELEMETRY] # Router <-> CmdDispatcher - Comms.fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> Comms.fprimeRouter.cmdResponseIn - Comms.cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> Comms.cmdSeq.cmdResponseIn + CommsCCSDS.fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> CommsCCSDS.fprimeRouter.cmdResponseIn + CommsCCSDS.cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff + CDHCore.cmdDisp.seqCmdStatus -> CommsCCSDS.cmdSeq.cmdResponseIn } - connections Comms_FileHandling { + connections CommsCCSDS_FileHandling { # File Downlink <-> ComQueue - FileHandling.fileDownlink.bufferSendOut -> Comms.comQueue.bufferQueueIn[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] - Comms.comQueue.bufferReturnOut[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] -> FileHandling.fileDownlink.bufferReturn + FileHandling.fileDownlink.bufferSendOut -> CommsCCSDS.comQueue.bufferQueueIn[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] + CommsCCSDS.comQueue.bufferReturnOut[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] -> FileHandling.fileDownlink.bufferReturn # Router <-> FileUplink - Comms.fprimeRouter.fileOut -> FileHandling.fileUplink.bufferSendIn - FileHandling.fileUplink.bufferSendOut -> Comms.fprimeRouter.fileBufferReturnIn + CommsCCSDS.fprimeRouter.fileOut -> FileHandling.fileUplink.bufferSendIn + FileHandling.fileUplink.bufferSendOut -> CommsCCSDS.fprimeRouter.fileBufferReturnIn } connections FileHandling_DataProducts{ diff --git a/Ref/test/int/ref_integration_test.py b/Ref/test/int/ref_integration_test.py index 6a749554455..e23448d3b47 100644 --- a/Ref/test/int/ref_integration_test.py +++ b/Ref/test/int/ref_integration_test.py @@ -285,5 +285,5 @@ def test_seqgen(fprime_test_api): == 0 ), "Failed to run fprime-seqgen" fprime_test_api.send_and_assert_command( - "Comms.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + "CommsCCSDS.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 ) From 8fd198b3fa2a13909e4b14858c26a8205fe876b6 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Wed, 18 Jun 2025 09:24:52 -0700 Subject: [PATCH 26/52] Changes to CommCCSDS that go with last changes --- Ref/Top/RefTopologyDefs.hpp | 4 +- .../CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 2 +- Svc/Subtopologies/CDHCore/config/config.fpp | 0 Svc/Subtopologies/CMakeLists.txt | 1 + .../Comms/CommsConfig/CommsConfig.fpp | 2 +- Svc/Subtopologies/CommsCCSDS/CMakeLists.txt | 2 +- Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp | 54 +++++++++---------- ...logyefs.cpp => CommsCCSDSTopologyDefs.cpp} | 2 +- .../CommsCCSDS/SubtopologyTopologyDefs.hpp | 4 +- .../CommsCCSDS/config/CommsCCSDSConfig.fpp | 10 ++-- .../DataProductsConfig/DataProductsConfig.fpp | 2 +- .../FileHandlingConfig/FileHandlingConfig.fpp | 2 +- 12 files changed, 41 insertions(+), 44 deletions(-) create mode 100644 Svc/Subtopologies/CDHCore/config/config.fpp rename Svc/Subtopologies/CommsCCSDS/{CommsCCSDSTopologyefs.cpp => CommsCCSDSTopologyDefs.cpp} (92%) diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index b5f2ae4bb8c..30de72e38a2 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -17,12 +17,12 @@ #include "Svc/Health/Health.hpp" -// Subtopology includes +// Subtopology PingEntries includes #include "Svc/Subtopologies/CDHCore/PingEntries.hpp" #include "Svc/Subtopologies/CommsCCSDS/PingEntries.hpp" +// SubtopologyTopologyDefs includes #include "Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp" - #include "Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp index 265cb98aab2..f7bbfd5be24 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -1,6 +1,6 @@ module CDHCoreConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x3000 + constant BASE_ID = 0x6000 module QueueSizes { constant cmdDisp = 10 diff --git a/Svc/Subtopologies/CDHCore/config/config.fpp b/Svc/Subtopologies/CDHCore/config/config.fpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Svc/Subtopologies/CMakeLists.txt b/Svc/Subtopologies/CMakeLists.txt index 63ba9dd22c3..ca3eb69a333 100644 --- a/Svc/Subtopologies/CMakeLists.txt +++ b/Svc/Subtopologies/CMakeLists.txt @@ -1,4 +1,5 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Comms/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsCCSDS/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileHandling/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DataProducts/") diff --git a/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp b/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp index 689a63a3038..f0b52609e9a 100644 --- a/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp +++ b/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp @@ -1,6 +1,6 @@ module CommsConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x6000 + constant BASE_ID = 0x7000 module QueueSizes { constant comQueue = 10 diff --git a/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt b/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt index 046229ab889..3932a98273b 100644 --- a/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt +++ b/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt @@ -1,4 +1,4 @@ -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsCCSDSConfig/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/config/") register_fprime_module( AUTOCODER_INPUTS diff --git a/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp b/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp index ba95d2e6d94..035b858b9e5 100644 --- a/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp +++ b/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp @@ -24,16 +24,16 @@ module CommsCCSDS { phase Fpp.ToCpp.Phases.configComponents """ Svc::ComQueue::QueueConfigurationTable configurationTable; // Events (highest-priority) - configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].depth = 100; - configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].priority = 0; + configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::EVENTS].depth = 100; + configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::EVENTS].priority = 0; // Telemetry - configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].depth = 500; - configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].priority = 2; + configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::TELEMETRY].depth = 500; + configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::TELEMETRY].priority = 2; // File Downlink Queue - configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].depth = 100; - configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].priority = 1; + configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::FILE_QUEUE].depth = 100; + configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::FILE_QUEUE].priority = 1; // Allocation identifier is 0 as the MallocAllocator discards it - Comms::comQueue.configure(configurationTable, 0, Comms::Allocation::mallocator); + CommsCCSDS::comQueue.configure(configurationTable, 0, CommsCCSDS::Allocation::mallocator); """ } @@ -49,11 +49,11 @@ module CommsCCSDS { """ phase Fpp.ToCpp.Phases.configComponents """ - Comms::cmdSeq.allocateBuffer(0, Comms::Allocation::mallocator, ConfigConstants::Comms_cmdSeq::CMD_SEQ_BUFFER_SIZE); + CommsCCSDS::cmdSeq.allocateBuffer(0, CommsCCSDS::Allocation::mallocator, ConfigConstants::CommsCCSDS_cmdSeq::CMD_SEQ_BUFFER_SIZE); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - Comms::cmdSeq.deallocateBuffer(Comms::Allocation::mallocator); + CommsCCSDS::cmdSeq.deallocateBuffer(CommsCCSDS::Allocation::mallocator); """ } @@ -75,21 +75,21 @@ module CommsCCSDS { phase Fpp.ToCpp.Phases.configComponents """ // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. - memset(&Comms::BufferManagerBins::bins, 0, sizeof(Comms::BufferManagerBins::bins)); - Comms::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; - Comms::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; - Comms::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - Comms::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; - Comms::commsBufferManager.setup( - ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_ID, + memset(&CommsCCSDS::BufferManagerBins::bins, 0, sizeof(CommsCCSDS::BufferManagerBins::bins)); + CommsCCSDS::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; + CommsCCSDS::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; + CommsCCSDS::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; + CommsCCSDS::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + CommsCCSDS::commsBufferManager.setup( + ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_ID, 0, - Comms::Allocation::mallocator, - Comms::BufferManagerBins::bins + CommsCCSDS::Allocation::mallocator, + CommsCCSDS::BufferManagerBins::bins ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - Comms::commsBufferManager.cleanup(); + CommsCCSDS::commsBufferManager.cleanup(); """ } @@ -97,16 +97,16 @@ module CommsCCSDS { { phase Fpp.ToCpp.Phases.configComponents """ - Comms::frameAccumulator.configure( - Comms::Detector::frameDetector, + CommsCCSDS::frameAccumulator.configure( + CommsCCSDS::Detector::frameDetector, 1, - Comms::Allocation::mallocator, + CommsCCSDS::Allocation::mallocator, 2048 ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - Comms::frameAccumulator.cleanup(); + CommsCCSDS::frameAccumulator.cleanup(); """ } @@ -194,12 +194,8 @@ module CommsCCSDS { # Router buffer allocations fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn - # Router <-> CmdDispatcher/FileUplink - fprimeRouter.commandOut -> cmdDisp.seqCmdBuff - cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn - fprimeRouter.fileOut -> fileUplink.bufferSendIn - fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn + } } # end topology -} # end Comms Subtopology +} # end CommsCCSDS Subtopology diff --git a/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyefs.cpp b/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyDefs.cpp similarity index 92% rename from Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyefs.cpp rename to Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyDefs.cpp index 38290a0befb..a6e1b0445f8 100644 --- a/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyefs.cpp +++ b/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyDefs.cpp @@ -1,6 +1,6 @@ #include "SubtopologyTopologyDefs.hpp" -namespace Comms { +namespace CommsCCSDS { namespace Allocation { Fw::MallocAllocator mallocator; } diff --git a/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp index 0cef8763df3..f5c9a2864bf 100644 --- a/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp @@ -5,14 +5,14 @@ #include #include -namespace Comms { +namespace CommsCCSDS { namespace Allocation { // Malloc allocator for topology construction extern Fw::MallocAllocator mallocator; } namespace BufferManagerBins { - // Buffer manager bins for Comms + // Buffer manager bins for CommsCCSDS extern Svc::BufferManager::BufferBins bins; } diff --git a/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp b/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp index 9a1859eb775..0f1e5f6dbe3 100644 --- a/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp +++ b/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp @@ -1,6 +1,6 @@ module CommsCCSDSConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x6000 + constant BASE_ID = 0x8000 module QueueSizes { constant comQueue = 10 @@ -26,7 +26,7 @@ module CommsCCSDS { { phase Fpp.ToCpp.Phases.configComponents """ if (state.hostname != nullptr && state.port != 0) { - Comms::comDriver.configure(state.hostname, state.port); + CommsCCSDS::comDriver.configure(state.hostname, state.port); } """ @@ -34,16 +34,16 @@ module CommsCCSDS { // Initialize socket client communication if and only if there is a valid specification if (state.hostname != nullptr && state.port != 0) { Os::TaskString name("ReceiveTask"); - Comms::comDriver.start(name, CommsConfig::Priorities::comQueue, CommsConfig::StackSizes::comQueue); + CommsCCSDS::comDriver.start(name, 100, 100); } """ phase Fpp.ToCpp.Phases.stopTasks """ - Comms::comDriver.stop(); + CommsCCSDS::comDriver.stop(); """ phase Fpp.ToCpp.Phases.freeThreads """ - (void)Comms::comDriver.join(); + (void)CommsCCSDS::comDriver.join(); """ } } diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp index 6279e2af06f..0302a7ee84c 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp @@ -1,6 +1,6 @@ module DataProductsConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x8000 + constant BASE_ID = 0x9000 module QueueSizes { constant dpCat = 10 diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp index 7e11f6da095..00ef61ed92e 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp @@ -1,6 +1,6 @@ module FileHandlingConfig { #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x9000 + constant BASE_ID = 0xA000 module QueueSizes { constant fileUplink = 10 From 3900bc02ec6bf2234655b90166ac684fd8afb53b Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Wed, 18 Jun 2025 11:10:29 -0700 Subject: [PATCH 27/52] Standardize subtopology structure and naming to PascalCase --- Ref/Top/RefPackets.fppi | 74 ++++++------- Ref/Top/RefTopologyDefs.hpp | 9 +- Ref/Top/topology.fpp | 48 ++++---- Ref/test/int/ref_integration_test.py | 28 ++--- Ref/test/int/test_seq.seq | 4 +- Svc/Subtopologies/CDHCore/CDHCore.fpp | 40 +++---- .../CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 24 ++-- .../CDHCore/CDHCoreConfig/CMakeLists.txt | 2 +- Svc/Subtopologies/CDHCore/CMakeLists.txt | 4 +- Svc/Subtopologies/CDHCore/PingEntries.hpp | 6 +- Svc/Subtopologies/CDHCore/config/config.fpp | 0 Svc/Subtopologies/CMakeLists.txt | 6 +- .../{CommsCCSDS => ComCcsds}/CMakeLists.txt | 6 +- .../CommsCCSDS.fpp => ComCcsds/ComCcsds.fpp} | 84 +++++++------- .../ComCcsdsConfig}/CMakeLists.txt | 2 +- .../ComCcsdsConfig/ComCcsdsConfig.fpp} | 16 +-- Svc/Subtopologies/ComCcsds/PingEntries.hpp | 9 ++ .../SubtopologyTopologyDefs.cpp} | 2 +- .../SubtopologyTopologyDefs.hpp | 8 +- Svc/Subtopologies/ComFprime/CMakeLists.txt | 11 ++ .../Comms.fpp => ComFprime/ComFprime.fpp} | 103 +++++++----------- .../ComFprime/ComFprimeConfig/CMakeLists.txt | 5 + .../ComFprimeConfig/ComFprimeConfig.fpp | 49 +++++++++ Svc/Subtopologies/ComFprime/PingEntries.hpp | 8 ++ .../SubtopologyTopologyDefs.cpp} | 0 .../SubtopologyTopologyDefs.hpp | 14 +-- Svc/Subtopologies/Comms/CMakeLists.txt | 10 -- .../Comms/CommsConfig/CMakeLists.txt | 5 - .../Comms/CommsConfig/CommsConfig.fpp | 20 ---- Svc/Subtopologies/CommsCCSDS/PingEntries.hpp | 9 -- Svc/Subtopologies/DataProducts/CMakeLists.txt | 3 +- .../DataProducts/PingEntries.hpp | 8 ++ ...gyDefs.cpp => SubtopologyTopologyDefs.cpp} | 0 .../DataProducts/SubtopologyTopologyDefs.hpp | 4 - Svc/Subtopologies/FileHandling/CMakeLists.txt | 2 +- .../FileHandling/PingEntries.hpp | 11 ++ .../FileHandling/SubtopologyTopologyDefs.cpp | 5 + .../FileHandling/SubtopologyTopologyDefs.hpp | 7 -- 38 files changed, 335 insertions(+), 311 deletions(-) delete mode 100644 Svc/Subtopologies/CDHCore/config/config.fpp rename Svc/Subtopologies/{CommsCCSDS => ComCcsds}/CMakeLists.txt (50%) rename Svc/Subtopologies/{CommsCCSDS/CommsCCSDS.fpp => ComCcsds/ComCcsds.fpp} (63%) rename Svc/Subtopologies/{CommsCCSDS/config => ComCcsds/ComCcsdsConfig}/CMakeLists.txt (51%) rename Svc/Subtopologies/{CommsCCSDS/config/CommsCCSDSConfig.fpp => ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp} (70%) create mode 100644 Svc/Subtopologies/ComCcsds/PingEntries.hpp rename Svc/Subtopologies/{CommsCCSDS/CommsCCSDSTopologyDefs.cpp => ComCcsds/SubtopologyTopologyDefs.cpp} (92%) rename Svc/Subtopologies/{CommsCCSDS => ComCcsds}/SubtopologyTopologyDefs.hpp (84%) create mode 100644 Svc/Subtopologies/ComFprime/CMakeLists.txt rename Svc/Subtopologies/{Comms/Comms.fpp => ComFprime/ComFprime.fpp} (55%) create mode 100644 Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt create mode 100644 Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp create mode 100644 Svc/Subtopologies/ComFprime/PingEntries.hpp rename Svc/Subtopologies/{Comms/CommsTopologyDefs.cpp => ComFprime/SubtopologyTopologyDefs.cpp} (100%) rename Svc/Subtopologies/{Comms => ComFprime}/SubtopologyTopologyDefs.hpp (70%) delete mode 100644 Svc/Subtopologies/Comms/CMakeLists.txt delete mode 100644 Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt delete mode 100644 Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp delete mode 100644 Svc/Subtopologies/CommsCCSDS/PingEntries.hpp create mode 100644 Svc/Subtopologies/DataProducts/PingEntries.hpp rename Svc/Subtopologies/DataProducts/{DataProductsTopologyDefs.cpp => SubtopologyTopologyDefs.cpp} (100%) create mode 100644 Svc/Subtopologies/FileHandling/PingEntries.hpp create mode 100644 Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index d88cc08d11c..e01b2f0109a 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -4,24 +4,24 @@ telemetry packets RefPackets { #Ref.cmdDisp.CommandsDispatched - CDHCore.cmdDisp.CommandsDispatched + CdhCore.cmdDisp.CommandsDispatched Ref.rateGroup1Comp.RgMaxTime Ref.rateGroup2Comp.RgMaxTime Ref.rateGroup3Comp.RgMaxTime - CommsCCSDS.cmdSeq.CS_LoadCommands - CommsCCSDS.cmdSeq.CS_CancelCommands - CommsCCSDS.cmdSeq.CS_CommandsExecuted - CommsCCSDS.cmdSeq.CS_SequencesCompleted + ComCcsds.cmdSeq.CS_LoadCommands + ComCcsds.cmdSeq.CS_CancelCommands + ComCcsds.cmdSeq.CS_CommandsExecuted + ComCcsds.cmdSeq.CS_SequencesCompleted FileHandling.fileUplink.FilesReceived FileHandling.fileUplink.PacketsReceived - CommsCCSDS.commsBufferManager.TotalBuffs - CommsCCSDS.commsBufferManager.CurrBuffs - CommsCCSDS.commsBufferManager.HiBuffs + ComCcsds.commsBufferManager.TotalBuffs + ComCcsds.commsBufferManager.CurrBuffs + ComCcsds.commsBufferManager.HiBuffs FileHandling.fileDownlink.FilesSent FileHandling.fileDownlink.PacketsSent FileHandling.fileManager.CommandsExecuted - CommsCCSDS.comQueue.comQueueDepth - CommsCCSDS.comQueue.buffQueueDepth + ComCcsds.comQueue.comQueueDepth + ComCcsds.comQueue.buffQueueDepth # Ref.tlmSend.SendLevel } @@ -29,13 +29,13 @@ telemetry packets RefPackets { Ref.rateGroup1Comp.RgCycleSlips Ref.rateGroup2Comp.RgCycleSlips Ref.rateGroup3Comp.RgCycleSlips - CommsCCSDS.cmdSeq.CS_Errors + ComCcsds.cmdSeq.CS_Errors FileHandling.fileUplink.Warnings FileHandling.fileDownlink.Warnings - CDHCore.$health.PingLateWarnings + CdhCore.$health.PingLateWarnings FileHandling.fileManager.Errors - CommsCCSDS.commsBufferManager.NoBuffs - CommsCCSDS.commsBufferManager.EmptyBuffs + ComCcsds.commsBufferManager.NoBuffs + ComCcsds.commsBufferManager.EmptyBuffs FileHandling.fileManager.Errors } @@ -198,75 +198,75 @@ telemetry packets RefPackets { } packet Version1 id 22 group 2 { - CDHCore.version.FrameworkVersion - CDHCore.version.ProjectVersion + CdhCore.version.FrameworkVersion + CdhCore.version.ProjectVersion } packet Version_Library1 id 23 group 2 { - CDHCore.version.LibraryVersion01 - CDHCore.version.LibraryVersion02 + CdhCore.version.LibraryVersion01 + CdhCore.version.LibraryVersion02 } packet Version_Library2 id 24 group 2 { - CDHCore.version.LibraryVersion03 - CDHCore.version.LibraryVersion04 + CdhCore.version.LibraryVersion03 + CdhCore.version.LibraryVersion04 } packet Version_Library3 id 25 group 2 { - CDHCore.version.LibraryVersion05 - CDHCore.version.LibraryVersion06 + CdhCore.version.LibraryVersion05 + CdhCore.version.LibraryVersion06 } packet Version_Library4 id 26 group 2 { - CDHCore.version.LibraryVersion07 - CDHCore.version.LibraryVersion08 + CdhCore.version.LibraryVersion07 + CdhCore.version.LibraryVersion08 } packet Version_Library5 id 27 group 2 { - CDHCore.version.LibraryVersion09 - CDHCore.version.LibraryVersion10 + CdhCore.version.LibraryVersion09 + CdhCore.version.LibraryVersion10 } packet Version_Custom1 id 28 group 2 { - CDHCore.version.CustomVersion01 + CdhCore.version.CustomVersion01 } packet Version_Custom2 id 29 group 2 { - CDHCore.version.CustomVersion02 + CdhCore.version.CustomVersion02 } packet Version_Custom3 id 30 group 2 { - CDHCore.version.CustomVersion03 + CdhCore.version.CustomVersion03 } packet Version_Custom4 id 31 group 2 { - CDHCore.version.CustomVersion04 + CdhCore.version.CustomVersion04 } packet Version_Custom5 id 32 group 2 { - CDHCore.version.CustomVersion05 + CdhCore.version.CustomVersion05 } packet Version_Custom6 id 33 group 2 { - CDHCore.version.CustomVersion06 + CdhCore.version.CustomVersion06 } packet Version_Custom7 id 34 group 2 { - CDHCore.version.CustomVersion07 + CdhCore.version.CustomVersion07 } packet Version_Custom8 id 35 group 2 { - CDHCore.version.CustomVersion08 + CdhCore.version.CustomVersion08 } packet Version_Custom9 id 36 group 2 { - CDHCore.version.CustomVersion09 + CdhCore.version.CustomVersion09 } packet Version_Custom10 id 37 group 2 { - CDHCore.version.CustomVersion10 + CdhCore.version.CustomVersion10 } } omit { - CDHCore.cmdDisp.CommandErrors + CdhCore.cmdDisp.CommandErrors } diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 30de72e38a2..4719575af01 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -18,13 +18,14 @@ // Subtopology PingEntries includes -#include "Svc/Subtopologies/CDHCore/PingEntries.hpp" -#include "Svc/Subtopologies/CommsCCSDS/PingEntries.hpp" +#include "Svc/Subtopologies/CdhCore/PingEntries.hpp" +#include "Svc/Subtopologies/ComCcsds/PingEntries.hpp" +#include "Svc/Subtopologies/DataProducts/PingEntries.hpp" +#include "Svc/Subtopologies/FileHandling/PingEntries.hpp" // SubtopologyTopologyDefs includes -#include "Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp" +#include "Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp" -#include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" namespace PingEntries { namespace Ref_blockDrv {enum { WARN = 3, FATAL = 5 };} diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index f23a1b77f3d..58d13c5b82b 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -16,8 +16,8 @@ module Ref { # ---------------------------------------------------------------------- # Subtopology imports # ---------------------------------------------------------------------- - import CDHCore.Subtopology - import CommsCCSDS.Subtopology + import CdhCore.Subtopology + import ComCcsds.Subtopology import FileHandling.Subtopology import DataProducts.Subtopology @@ -47,15 +47,15 @@ module Ref { # Pattern graph specifiers # ---------------------------------------------------------------------- - command connections instance CDHCore.cmdDisp + command connections instance CdhCore.cmdDisp - event connections instance CDHCore.events + event connections instance CdhCore.events - telemetry connections instance CDHCore.tlmSend + telemetry connections instance CdhCore.tlmSend - text event connections instance CDHCore.textLogger + text event connections instance CdhCore.textLogger - health connections instance CDHCore.$health + health connections instance CdhCore.$health param connections instance FileHandling.prmDb @@ -80,24 +80,24 @@ module Ref { rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup1] -> rateGroup1Comp.CycleIn rateGroup1Comp.RateGroupMemberOut[0] -> SG1.schedIn rateGroup1Comp.RateGroupMemberOut[1] -> SG2.schedIn - rateGroup1Comp.RateGroupMemberOut[2] -> CDHCore.tlmSend.Run + rateGroup1Comp.RateGroupMemberOut[2] -> CdhCore.tlmSend.Run rateGroup1Comp.RateGroupMemberOut[3] -> FileHandling.fileDownlink.Run rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run - rateGroup1Comp.RateGroupMemberOut[5] -> CommsCCSDS.comQueue.run + rateGroup1Comp.RateGroupMemberOut[5] -> ComCcsds.comQueue.run # Rate group 2 rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup2] -> rateGroup2Comp.CycleIn - rateGroup2Comp.RateGroupMemberOut[0] -> CommsCCSDS.cmdSeq.schedIn + rateGroup2Comp.RateGroupMemberOut[0] -> ComCcsds.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] -> CDHCore.$health.Run + rateGroup3Comp.RateGroupMemberOut[0] -> CdhCore.$health.Run rateGroup3Comp.RateGroupMemberOut[1] -> SG5.schedIn rateGroup3Comp.RateGroupMemberOut[2] -> blockDrv.Sched - rateGroup3Comp.RateGroupMemberOut[3] -> CommsCCSDS.commsBufferManager.schedIn + rateGroup3Comp.RateGroupMemberOut[3] -> ComCcsds.commsBufferManager.schedIn rateGroup3Comp.RateGroupMemberOut[4] -> DataProducts.dpBufferManager.schedIn rateGroup3Comp.RateGroupMemberOut[5] -> DataProducts.dpWriter.schedIn rateGroup3Comp.RateGroupMemberOut[6] -> DataProducts.dpMgr.schedIn @@ -118,26 +118,26 @@ module Ref { } - connections CommsCCSDS_CDHCore{ + connections ComCcsds_CdhCore{ # events and telemetry to comQueue - CDHCore.events.PktSend -> CommsCCSDS.comQueue.comPacketQueueIn[CommsCCSDS.Ports_ComPacketQueue.EVENTS] - CDHCore.tlmSend.PktSend -> CommsCCSDS.comQueue.comPacketQueueIn[CommsCCSDS.Ports_ComPacketQueue.TELEMETRY] + CdhCore.events.PktSend -> ComCcsds.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.EVENTS] + CdhCore.tlmSend.PktSend -> ComCcsds.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.TELEMETRY] # Router <-> CmdDispatcher - CommsCCSDS.fprimeRouter.commandOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> CommsCCSDS.fprimeRouter.cmdResponseIn - CommsCCSDS.cmdSeq.comCmdOut -> CDHCore.cmdDisp.seqCmdBuff - CDHCore.cmdDisp.seqCmdStatus -> CommsCCSDS.cmdSeq.cmdResponseIn + ComCcsds.fprimeRouter.commandOut -> CdhCore.cmdDisp.seqCmdBuff + CdhCore.cmdDisp.seqCmdStatus -> ComCcsds.fprimeRouter.cmdResponseIn + ComCcsds.cmdSeq.comCmdOut -> CdhCore.cmdDisp.seqCmdBuff + CdhCore.cmdDisp.seqCmdStatus -> ComCcsds.cmdSeq.cmdResponseIn } - connections CommsCCSDS_FileHandling { + connections ComCcsds_FileHandling { # File Downlink <-> ComQueue - FileHandling.fileDownlink.bufferSendOut -> CommsCCSDS.comQueue.bufferQueueIn[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] - CommsCCSDS.comQueue.bufferReturnOut[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] -> FileHandling.fileDownlink.bufferReturn + FileHandling.fileDownlink.bufferSendOut -> ComCcsds.comQueue.bufferQueueIn[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] + ComCcsds.comQueue.bufferReturnOut[FileHandling.Ports_ComBufferQueue.FILE_DOWNLINK] -> FileHandling.fileDownlink.bufferReturn # Router <-> FileUplink - CommsCCSDS.fprimeRouter.fileOut -> FileHandling.fileUplink.bufferSendIn - FileHandling.fileUplink.bufferSendOut -> CommsCCSDS.fprimeRouter.fileBufferReturnIn + ComCcsds.fprimeRouter.fileOut -> FileHandling.fileUplink.bufferSendIn + FileHandling.fileUplink.bufferSendOut -> ComCcsds.fprimeRouter.fileBufferReturnIn } connections FileHandling_DataProducts{ diff --git a/Ref/test/int/ref_integration_test.py b/Ref/test/int/ref_integration_test.py index e23448d3b47..ebf2fc63d02 100644 --- a/Ref/test/int/ref_integration_test.py +++ b/Ref/test/int/ref_integration_test.py @@ -57,7 +57,7 @@ def set_event_filter(fprime_test_api, severity, enabled): severity = FilterSeverity[severity].name try: fprime_test_api.send_command( - "CDHCore.events.SET_EVENT_FILTER", + "CdhCore.events.SET_EVENT_FILTER", [severity, enabled], ) return True @@ -80,9 +80,9 @@ def test_send_command(fprime_test_api): 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("CDHCore.cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("CdhCore.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("CDHCore.cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("CdhCore.cmdDisp.CMD_NO_OP", max_delay=0.1) assert fprime_test_api.get_command_test_history().size() == 2 @@ -94,11 +94,11 @@ def test_send_command_args(fprime_test_api): for count, value in enumerate(["Test String 1", "Some other string"], 1): events = [ fprime_test_api.get_event_pred( - "CDHCore.cmdDisp.NoOpStringReceived", [value] + "CdhCore.cmdDisp.NoOpStringReceived", [value] ) ] fprime_test_api.send_and_assert_command( - "CDHCore.cmdDisp.CMD_NO_OP_STRING", + "CdhCore.cmdDisp.CMD_NO_OP_STRING", [ value, ], @@ -117,15 +117,15 @@ def test_send_and_assert_no_op(fprime_test_api): length = 100 failed = 0 evr_seq = [ - "CDHCore.cmdDisp.OpCodeDispatched", - "CDHCore.cmdDisp.NoOpReceived", - "CDHCore.cmdDisp.OpCodeCompleted", + "CdhCore.cmdDisp.OpCodeDispatched", + "CdhCore.cmdDisp.NoOpReceived", + "CdhCore.cmdDisp.OpCodeCompleted", ] any_reordered = False dropped = False for i in range(0, length): results = fprime_test_api.send_and_await_event( - "CDHCore.cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 + "CdhCore.cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 ) msg = "Send and assert NO_OP Trial #{}".format(i) if not fprime_test_api.test_assert(len(results) == 3, msg, True): @@ -232,8 +232,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) - fprime_test_api.send_and_assert_command("CDHCore.cmdDisp.CMD_NO_OP") - fprime_test_api.send_and_assert_command("CDHCore.cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("CdhCore.cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("CdhCore.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -244,8 +244,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) fprime_test_api.clear_histories() - fprime_test_api.send_command("CDHCore.cmdDisp.CMD_NO_OP") - fprime_test_api.send_command("CDHCore.cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("CdhCore.cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("CdhCore.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -285,5 +285,5 @@ def test_seqgen(fprime_test_api): == 0 ), "Failed to run fprime-seqgen" fprime_test_api.send_and_assert_command( - "CommsCCSDS.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + "ComCcsds.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 ) diff --git a/Ref/test/int/test_seq.seq b/Ref/test/int/test_seq.seq index bc45caf026e..5f93c9c611b 100644 --- a/Ref/test/int/test_seq.seq +++ b/Ref/test/int/test_seq.seq @@ -1,6 +1,6 @@ ; A test sequence ; -R00:00:00 CDHCore.cmdDisp.CMD_NO_OP +R00:00:00 CdhCore.cmdDisp.CMD_NO_OP ; Let's try out some commands with arguments -R00:00:01.050 CDHCore.cmdDisp.CMD_NO_OP_STRING "Awesome string!"; +R00:00:01.050 CdhCore.cmdDisp.CMD_NO_OP_STRING "Awesome string!"; diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CDHCore/CDHCore.fpp index b362379b9ad..2840dcd6631 100644 --- a/Svc/Subtopologies/CDHCore/CDHCore.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCore.fpp @@ -1,22 +1,22 @@ -module CDHCore { +module CdhCore { # ---------------------------------------------------------------------- # Active Components # ---------------------------------------------------------------------- - instance cmdDisp: Svc.CommandDispatcher base id CDHCoreConfig.BASE_ID + 0x0100 \ - queue size CDHCoreConfig.QueueSizes.cmdDisp \ - stack size CDHCoreConfig.StackSizes.cmdDisp \ - priority CDHCoreConfig.Priorities.cmdDisp + instance cmdDisp: Svc.CommandDispatcher base id CdhCoreConfig.BASE_ID + 0x0100 \ + queue size CdhCoreConfig.QueueSizes.cmdDisp \ + stack size CdhCoreConfig.StackSizes.cmdDisp \ + priority CdhCoreConfig.Priorities.cmdDisp - instance events: Svc.ActiveLogger base id CDHCoreConfig.BASE_ID + 0x0200 \ - queue size CDHCoreConfig.QueueSizes.events \ - stack size CDHCoreConfig.StackSizes.events \ - priority CDHCoreConfig.Priorities.events + instance events: Svc.ActiveLogger base id CdhCoreConfig.BASE_ID + 0x0200 \ + queue size CdhCoreConfig.QueueSizes.events \ + stack size CdhCoreConfig.StackSizes.events \ + priority CdhCoreConfig.Priorities.events # ---------------------------------------------------------------------- # Queued Components # ---------------------------------------------------------------------- - instance $health: Svc.Health base id CDHCoreConfig.BASE_ID + 0x0300 \ - queue size CDHCoreConfig.QueueSizes.$health \ + instance $health: Svc.Health base id CdhCoreConfig.BASE_ID + 0x0300 \ + queue size CdhCoreConfig.QueueSizes.$health \ { phase Fpp.ToCpp.Phases.configConstants """ enum { @@ -25,10 +25,10 @@ module CDHCore { """ phase Fpp.ToCpp.Phases.configComponents """ // Health is supplied a set of ping entires. - CDHCore::health.setPingEntries( - ConfigObjects::CDHCore_health::pingEntries, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::CDHCore_health::pingEntries), - ConfigConstants::CDHCore_health::HEALTH_WATCHDOG_CODE + CdhCore::health.setPingEntries( + ConfigObjects::CdhCore_health::pingEntries, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::CdhCore_health::pingEntries), + ConfigConstants::CdhCore_health::HEALTH_WATCHDOG_CODE ); """ } @@ -36,17 +36,17 @@ module CDHCore { # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - instance version: Svc.Version base id CDHCoreConfig.BASE_ID + 0x0400 \ + instance version: Svc.Version base id CdhCoreConfig.BASE_ID + 0x0400 \ { phase Fpp.ToCpp.Phases.configComponents """ // Startup TLM and Config verbosity for Versions - CDHCore::version.config(true); + CdhCore::version.config(true); """ } - instance textLogger: Svc.PassiveTextLogger base id CDHCoreConfig.BASE_ID + 0x0500 + instance textLogger: Svc.PassiveTextLogger base id CdhCoreConfig.BASE_ID + 0x0500 - instance fatalAdapter: Svc.AssertFatalAdapter base id CDHCoreConfig.BASE_ID + 0x0600 + instance fatalAdapter: Svc.AssertFatalAdapter base id CdhCoreConfig.BASE_ID + 0x0600 topology Subtopology { #Active Components @@ -63,4 +63,4 @@ module CDHCore { instance fatalAdapter } # end topology -} # end CDHCore Subtopology \ No newline at end of file +} # end CdhCore Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp index f7bbfd5be24..d9f0a987662 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -1,5 +1,5 @@ -module CDHCoreConfig { - #Base ID for the CDHCore Subtopology, all components are offsets from this base ID +module CdhCoreConfig { + #Base ID for the CdhCore Subtopology, all components are offsets from this base ID constant BASE_ID = 0x6000 module QueueSizes { @@ -26,23 +26,23 @@ module CDHCoreConfig { } -module CDHCore { +module CdhCore { - instance tlmSend: Svc.TlmChan base id CDHCoreConfig.BASE_ID + 0x0700 \ - queue size CDHCoreConfig.QueueSizes.tlmSend \ - stack size CDHCoreConfig.StackSizes.tlmSend \ - priority CDHCoreConfig.Priorities.tlmSend \ + instance tlmSend: Svc.TlmChan base id CdhCoreConfig.BASE_ID + 0x0700 \ + queue size CdhCoreConfig.QueueSizes.tlmSend \ + stack size CdhCoreConfig.StackSizes.tlmSend \ + priority CdhCoreConfig.Priorities.tlmSend \ # Uncomment the following block and comment the above block to use TlmPacketizer instead of TlmChan - #instance tlmSend: Svc.TlmPacketizer base id CDHCoreConfig.BASE_ID + 0x0700 \ - # queue size CDHCoreConfig.QueueSizes.tlmSend \ - # stack size CDHCoreConfig.StackSizes.tlmSend \ - # priority CDHCoreConfig.Priorities.tlmSend \ + #instance tlmSend: Svc.TlmPacketizer base id CdhCoreConfig.BASE_ID + 0x0700 \ + # queue size CdhCoreConfig.QueueSizes.tlmSend \ + # stack size CdhCoreConfig.StackSizes.tlmSend \ + # priority CdhCoreConfig.Priorities.tlmSend \ #{ # # NOTE: The Name Ref is specific to the Reference deployment, Ref # # This name will need to be updated if wishing to use this in a custom deployment # phase Fpp.ToCpp.Phases.configComponents """ - # CDHCore::tlmSend.setPacketList( + # CdhCore::tlmSend.setPacketList( # Ref::Ref_RefPacketsTlmPackets::packetList, # Ref::Ref_RefPacketsTlmPackets::omittedChannels, # 1 diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt index ba6b42fc956..28245922458 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt @@ -1,5 +1,5 @@ register_fprime_module( AUTOCODER_INPUTS - "${CMAKE_CURRENT_LIST_DIR}/CDHCoreConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/CdhCoreConfig.fpp" INTERFACE ) \ No newline at end of file diff --git a/Svc/Subtopologies/CDHCore/CMakeLists.txt b/Svc/Subtopologies/CDHCore/CMakeLists.txt index 29fd34c8258..4dff3feba88 100644 --- a/Svc/Subtopologies/CDHCore/CMakeLists.txt +++ b/Svc/Subtopologies/CDHCore/CMakeLists.txt @@ -1,8 +1,8 @@ -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCoreConfig/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CdhCoreConfig/") register_fprime_module( AUTOCODER_INPUTS - "${CMAKE_CURRENT_LIST_DIR}/CDHCore.fpp" + "${CMAKE_CURRENT_LIST_DIR}/CdhCore.fpp" HEADERS "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE diff --git a/Svc/Subtopologies/CDHCore/PingEntries.hpp b/Svc/Subtopologies/CDHCore/PingEntries.hpp index 94316250fea..39756520fc0 100644 --- a/Svc/Subtopologies/CDHCore/PingEntries.hpp +++ b/Svc/Subtopologies/CDHCore/PingEntries.hpp @@ -2,9 +2,9 @@ #define CDHCORE_PINGENTRIES_HPP namespace PingEntries { - struct CDHCore_cmdDisp { enum { WARN=3, FATAL=5 }; }; - struct CDHCore_events { enum { WARN=3, FATAL=5 }; }; - struct CDHCore_tlmSend { enum { WARN=3, FATAL=5 }; }; + struct CdhCore_cmdDisp { enum { WARN=3, FATAL=5 }; }; + struct CdhCore_events { enum { WARN=3, FATAL=5 }; }; + struct CdhCore_tlmSend { enum { WARN=3, FATAL=5 }; }; } #endif diff --git a/Svc/Subtopologies/CDHCore/config/config.fpp b/Svc/Subtopologies/CDHCore/config/config.fpp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Svc/Subtopologies/CMakeLists.txt b/Svc/Subtopologies/CMakeLists.txt index ca3eb69a333..08a05ef41f7 100644 --- a/Svc/Subtopologies/CMakeLists.txt +++ b/Svc/Subtopologies/CMakeLists.txt @@ -1,5 +1,5 @@ -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CDHCore/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Comms/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsCCSDS/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CdhCore/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComCcsds/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComFprime/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileHandling/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DataProducts/") diff --git a/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/CMakeLists.txt similarity index 50% rename from Svc/Subtopologies/CommsCCSDS/CMakeLists.txt rename to Svc/Subtopologies/ComCcsds/CMakeLists.txt index 3932a98273b..19f4260efd5 100644 --- a/Svc/Subtopologies/CommsCCSDS/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/CMakeLists.txt @@ -1,10 +1,10 @@ -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/config/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig/") register_fprime_module( AUTOCODER_INPUTS - "${CMAKE_CURRENT_LIST_DIR}/CommsCCSDS.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ComCcsds.fpp" SOURCES - "${CMAKE_CURRENT_LIST_DIR}/CommsCCSDSTopologyDefs.cpp" + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" diff --git a/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp similarity index 63% rename from Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp rename to Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 035b858b9e5..95f3b639bde 100644 --- a/Svc/Subtopologies/CommsCCSDS/CommsCCSDS.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -1,4 +1,4 @@ -module CommsCCSDS { +module ComCcsds { enum Ports_ComPacketQueue { EVENTS, @@ -9,10 +9,10 @@ module CommsCCSDS { # ---------------------------------------------------------------------- # Active Components # ---------------------------------------------------------------------- - instance comQueue: Svc.ComQueue base id CommsCCSDSConfig.BASE_ID + 0x0100 \ - queue size CommsCCSDSConfig.QueueSizes.comQueue \ - stack size CommsCCSDSConfig.StackSizes.comQueue \ - priority CommsCCSDSConfig.Priorities.comQueue \ + instance comQueue: Svc.ComQueue base id ComCcsdsConfig.BASE_ID + 0x0100 \ + queue size ComCcsdsConfig.QueueSizes.comQueue \ + stack size ComCcsdsConfig.StackSizes.comQueue \ + priority ComCcsdsConfig.Priorities.comQueue \ { phase Fpp.ToCpp.Phases.configConstants """ enum{ @@ -24,23 +24,23 @@ module CommsCCSDS { phase Fpp.ToCpp.Phases.configComponents """ Svc::ComQueue::QueueConfigurationTable configurationTable; // Events (highest-priority) - configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::EVENTS].depth = 100; - configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::EVENTS].priority = 0; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::EVENTS].depth = 100; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::EVENTS].priority = 0; // Telemetry - configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::TELEMETRY].depth = 500; - configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::TELEMETRY].priority = 2; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::TELEMETRY].depth = 500; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::TELEMETRY].priority = 2; // File Downlink Queue - configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::FILE_QUEUE].depth = 100; - configurationTable.entries[ConfigConstants::CommsCCSDS_comQueue::FILE_QUEUE].priority = 1; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::FILE_QUEUE].depth = 100; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::FILE_QUEUE].priority = 1; // Allocation identifier is 0 as the MallocAllocator discards it - CommsCCSDS::comQueue.configure(configurationTable, 0, CommsCCSDS::Allocation::mallocator); + ComCcsds::comQueue.configure(configurationTable, 0, ComCcsds::Allocation::mallocator); """ } - instance cmdSeq: Svc.CmdSequencer base id CommsCCSDSConfig.BASE_ID + 0x0200 \ - queue size CommsCCSDSConfig.QueueSizes.cmdSeq \ - stack size CommsCCSDSConfig.StackSizes.cmdSeq \ - priority CommsCCSDSConfig.Priorities.cmdSeq \ + instance cmdSeq: Svc.CmdSequencer base id ComCcsdsConfig.BASE_ID + 0x0200 \ + queue size ComCcsdsConfig.QueueSizes.cmdSeq \ + stack size ComCcsdsConfig.StackSizes.cmdSeq \ + priority ComCcsdsConfig.Priorities.cmdSeq \ { phase Fpp.ToCpp.Phases.configConstants """ enum { @@ -49,18 +49,18 @@ module CommsCCSDS { """ phase Fpp.ToCpp.Phases.configComponents """ - CommsCCSDS::cmdSeq.allocateBuffer(0, CommsCCSDS::Allocation::mallocator, ConfigConstants::CommsCCSDS_cmdSeq::CMD_SEQ_BUFFER_SIZE); + ComCcsds::cmdSeq.allocateBuffer(0, ComCcsds::Allocation::mallocator, ConfigConstants::ComCcsds_cmdSeq::CMD_SEQ_BUFFER_SIZE); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - CommsCCSDS::cmdSeq.deallocateBuffer(CommsCCSDS::Allocation::mallocator); + ComCcsds::cmdSeq.deallocateBuffer(ComCcsds::Allocation::mallocator); """ } # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - instance commsBufferManager: Svc.BufferManager base id CommsCCSDSConfig.BASE_ID + 0x0500 \ + instance commsBufferManager: Svc.BufferManager base id ComCcsdsConfig.BASE_ID + 0x0500 \ { phase Fpp.ToCpp.Phases.configConstants """ enum { @@ -75,54 +75,54 @@ module CommsCCSDS { phase Fpp.ToCpp.Phases.configComponents """ // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. - memset(&CommsCCSDS::BufferManagerBins::bins, 0, sizeof(CommsCCSDS::BufferManagerBins::bins)); - CommsCCSDS::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; - CommsCCSDS::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; - CommsCCSDS::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - CommsCCSDS::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; - CommsCCSDS::commsBufferManager.setup( - ConfigConstants::CommsCCSDS_commsBufferManager::COMMS_BUFFER_MANAGER_ID, + memset(&ComCcsds::BufferManagerBins::bins, 0, sizeof(ComCcsds::BufferManagerBins::bins)); + ComCcsds::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; + ComCcsds::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; + ComCcsds::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; + ComCcsds::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + ComCcsds::commsBufferManager.setup( + ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_ID, 0, - CommsCCSDS::Allocation::mallocator, - CommsCCSDS::BufferManagerBins::bins + ComCcsds::Allocation::mallocator, + ComCcsds::BufferManagerBins::bins ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - CommsCCSDS::commsBufferManager.cleanup(); + ComCcsds::commsBufferManager.cleanup(); """ } - instance frameAccumulator: Svc.FrameAccumulator base id CommsCCSDSConfig.BASE_ID + 0x0600 \ + instance frameAccumulator: Svc.FrameAccumulator base id ComCcsdsConfig.BASE_ID + 0x0600 \ { phase Fpp.ToCpp.Phases.configComponents """ - CommsCCSDS::frameAccumulator.configure( - CommsCCSDS::Detector::frameDetector, + ComCcsds::frameAccumulator.configure( + ComCcsds::Detector::frameDetector, 1, - CommsCCSDS::Allocation::mallocator, + ComCcsds::Allocation::mallocator, 2048 ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - CommsCCSDS::frameAccumulator.cleanup(); + ComCcsds::frameAccumulator.cleanup(); """ } - instance fprimeRouter: Svc.FprimeRouter base id CommsCCSDSConfig.BASE_ID + 0x0700 \ + instance fprimeRouter: Svc.FprimeRouter base id ComCcsdsConfig.BASE_ID + 0x0700 \ - instance comStub: Svc.ComStub base id CommsCCSDSConfig.BASE_ID + 0x0800 \ + instance comStub: Svc.ComStub base id ComCcsdsConfig.BASE_ID + 0x0800 \ - instance tcDeframer: Svc.CCSDS.TcDeframer base id CommsCCSDSConfig.BASE_ID + 0x0900 \ + instance tcDeframer: Svc.CCSDS.TcDeframer base id ComCcsdsConfig.BASE_ID + 0x0900 \ - instance spacePacketDeframer: Svc.CCSDS.SpacePacketDeframer base id CommsCCSDSConfig.BASE_ID + 0x0A00 \ + instance spacePacketDeframer: Svc.CCSDS.SpacePacketDeframer base id ComCcsdsConfig.BASE_ID + 0x0A00 \ - instance tmFramer: Svc.CCSDS.TmFramer base id CommsCCSDSConfig.BASE_ID + 0x0B00 \ + instance tmFramer: Svc.CCSDS.TmFramer base id ComCcsdsConfig.BASE_ID + 0x0B00 \ - instance spacePacketFramer: Svc.CCSDS.SpacePacketFramer base id CommsCCSDSConfig.BASE_ID + 0x0C00 \ + instance spacePacketFramer: Svc.CCSDS.SpacePacketFramer base id ComCcsdsConfig.BASE_ID + 0x0C00 \ - instance apidManager: Svc.CCSDS.ApidManager base id CommsCCSDSConfig.BASE_ID + 0x0D00 \ + instance apidManager: Svc.CCSDS.ApidManager base id ComCcsdsConfig.BASE_ID + 0x0D00 \ topology Subtopology { # Active Components @@ -198,4 +198,4 @@ module CommsCCSDS { } } # end topology -} # end CommsCCSDS Subtopology +} # end ComCcsds Subtopology diff --git a/Svc/Subtopologies/CommsCCSDS/config/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt similarity index 51% rename from Svc/Subtopologies/CommsCCSDS/config/CMakeLists.txt rename to Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt index a981dc90ea5..c57b2e500b4 100644 --- a/Svc/Subtopologies/CommsCCSDS/config/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt @@ -1,5 +1,5 @@ register_fprime_module( AUTOCODER_INPUTS - "${CMAKE_CURRENT_LIST_DIR}/CommsCCSDSConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig.fpp" INTERFACE ) diff --git a/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp similarity index 70% rename from Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp rename to Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp index 0f1e5f6dbe3..1d59ad91a28 100644 --- a/Svc/Subtopologies/CommsCCSDS/config/CommsCCSDSConfig.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp @@ -1,5 +1,5 @@ -module CommsCCSDSConfig { - #Base ID for the CDHCore Subtopology, all components are offsets from this base ID +module ComCcsdsConfig { + #Base ID for the ComCcsds Subtopology, all components are offsets from this base ID constant BASE_ID = 0x8000 module QueueSizes { @@ -19,14 +19,14 @@ module CommsCCSDSConfig { } } -module CommsCCSDS { +module ComCcsds { # Communications driver. May be swapped out with other comm drivers like UART in this file # to use another driver in the Comms Subtopology - instance comDriver: Drv.TcpClient base id CommsCCSDSConfig.BASE_ID + 0x0B00 \ + instance comDriver: Drv.TcpClient base id ComCcsdsConfig.BASE_ID + 0x0B00 \ { phase Fpp.ToCpp.Phases.configComponents """ if (state.hostname != nullptr && state.port != 0) { - CommsCCSDS::comDriver.configure(state.hostname, state.port); + ComCcsds::comDriver.configure(state.hostname, state.port); } """ @@ -34,16 +34,16 @@ module CommsCCSDS { // Initialize socket client communication if and only if there is a valid specification if (state.hostname != nullptr && state.port != 0) { Os::TaskString name("ReceiveTask"); - CommsCCSDS::comDriver.start(name, 100, 100); + ComCcsds::comDriver.start(name, 100, 100); } """ phase Fpp.ToCpp.Phases.stopTasks """ - CommsCCSDS::comDriver.stop(); + ComCcsds::comDriver.stop(); """ phase Fpp.ToCpp.Phases.freeThreads """ - (void)CommsCCSDS::comDriver.join(); + (void)ComCcsds::comDriver.join(); """ } } diff --git a/Svc/Subtopologies/ComCcsds/PingEntries.hpp b/Svc/Subtopologies/ComCcsds/PingEntries.hpp new file mode 100644 index 00000000000..ef7f06f6940 --- /dev/null +++ b/Svc/Subtopologies/ComCcsds/PingEntries.hpp @@ -0,0 +1,9 @@ + +#ifndef COMCCSDS_PINGENTRIES_HPP +#define COMCCSDS_PINGENTRIES_HPP + + namespace PingEntries { + namespace ComCcsds_cmdSeq {enum { WARN = 3, FATAL = 5 };} + } + +#endif diff --git a/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyDefs.cpp b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.cpp similarity index 92% rename from Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyDefs.cpp rename to Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.cpp index a6e1b0445f8..14d94d6cf7e 100644 --- a/Svc/Subtopologies/CommsCCSDS/CommsCCSDSTopologyDefs.cpp +++ b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.cpp @@ -1,6 +1,6 @@ #include "SubtopologyTopologyDefs.hpp" -namespace CommsCCSDS { +namespace ComCcsds { namespace Allocation { Fw::MallocAllocator mallocator; } diff --git a/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp similarity index 84% rename from Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp rename to Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp index f5c9a2864bf..d114d982d65 100644 --- a/Svc/Subtopologies/CommsCCSDS/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp @@ -1,18 +1,18 @@ -#ifndef COMMSCCSDSSUBTOPOLOGY_DEFS_HPP -#define COMMSCCSDSSUBTOPOLOGY_DEFS_HPP +#ifndef COMCCSDSSUBTOPOLOGY_DEFS_HPP +#define COMCCSDSSUBTOPOLOGY_DEFS_HPP #include #include #include -namespace CommsCCSDS { +namespace ComCcsds { namespace Allocation { // Malloc allocator for topology construction extern Fw::MallocAllocator mallocator; } namespace BufferManagerBins { - // Buffer manager bins for CommsCCSDS + // Buffer manager bins for ComCcsds extern Svc::BufferManager::BufferBins bins; } diff --git a/Svc/Subtopologies/ComFprime/CMakeLists.txt b/Svc/Subtopologies/ComFprime/CMakeLists.txt new file mode 100644 index 00000000000..04d895e6e0d --- /dev/null +++ b/Svc/Subtopologies/ComFprime/CMakeLists.txt @@ -0,0 +1,11 @@ +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComFprimeConfig/") + +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/ComFprime.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" +) diff --git a/Svc/Subtopologies/Comms/Comms.fpp b/Svc/Subtopologies/ComFprime/ComFprime.fpp similarity index 55% rename from Svc/Subtopologies/Comms/Comms.fpp rename to Svc/Subtopologies/ComFprime/ComFprime.fpp index b17902726b6..48addf56a9c 100644 --- a/Svc/Subtopologies/Comms/Comms.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprime.fpp @@ -1,4 +1,4 @@ -module Comms { +module ComFprime { enum Ports_ComPacketQueue { EVENTS, @@ -9,10 +9,10 @@ module Comms { # ---------------------------------------------------------------------- # Active Components # ---------------------------------------------------------------------- - instance comQueue: Svc.ComQueue base id CommsConfig.BASE_ID + 0x0100 \ - queue size CommsConfig.QueueSizes.comQueue \ - stack size CommsConfig.StackSizes.comQueue \ - priority CommsConfig.Priorities.comQueue \ + instance comQueue: Svc.ComQueue base id ComFprimeConfig.BASE_ID + 0x0100 \ + queue size ComFprimeConfig.QueueSizes.comQueue \ + stack size ComFprimeConfig.StackSizes.comQueue \ + priority ComFprimeConfig.Priorities.comQueue \ { phase Fpp.ToCpp.Phases.configConstants """ enum{ @@ -24,23 +24,23 @@ module Comms { phase Fpp.ToCpp.Phases.configComponents """ Svc::ComQueue::QueueConfigurationTable configurationTable; // Events (highest-priority) - configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].depth = 100; - configurationTable.entries[ConfigConstants::Comms_comQueue::EVENTS].priority = 0; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::EVENTS].depth = 100; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::EVENTS].priority = 0; // Telemetry - configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].depth = 500; - configurationTable.entries[ConfigConstants::Comms_comQueue::TELEMETRY].priority = 2; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::TELEMETRY].depth = 500; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::TELEMETRY].priority = 2; // File Downlink Queue - configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].depth = 100; - configurationTable.entries[ConfigConstants::Comms_comQueue::FILE_QUEUE].priority = 1; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].depth = 100; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].priority = 1; // Allocation identifier is 0 as the MallocAllocator discards it - Comms::comQueue.configure(configurationTable, 0, Comms::Allocation::mallocator); + ComFprime::comQueue.configure(configurationTable, 0, ComFprime::Allocation::mallocator); """ } - instance cmdSeq: Svc.CmdSequencer base id CommsConfig.BASE_ID + 0x0200 \ - queue size CommsConfig.QueueSizes.cmdSeq \ - stack size CommsConfig.StackSizes.cmdSeq \ - priority CommsConfig.Priorities.cmdSeq \ + instance cmdSeq: Svc.CmdSequencer base id ComFprimeConfig.BASE_ID + 0x0200 \ + queue size ComFprimeConfig.QueueSizes.cmdSeq \ + stack size ComFprimeConfig.StackSizes.cmdSeq \ + priority ComFprimeConfig.Priorities.cmdSeq \ { phase Fpp.ToCpp.Phases.configConstants """ enum { @@ -49,18 +49,18 @@ module Comms { """ phase Fpp.ToCpp.Phases.configComponents """ - Comms::cmdSeq.allocateBuffer(0, Comms::Allocation::mallocator, ConfigConstants::Comms_cmdSeq::CMD_SEQ_BUFFER_SIZE); + ComFprime::cmdSeq.allocateBuffer(0, ComFprime::Allocation::mallocator, ConfigConstants::ComFprime_cmdSeq::CMD_SEQ_BUFFER_SIZE); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - Comms::cmdSeq.deallocateBuffer(Comms::Allocation::mallocator); + ComFprime::cmdSeq.deallocateBuffer(ComFprime::Allocation::mallocator); """ } # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - instance commsBufferManager: Svc.BufferManager base id CommsConfig.BASE_ID + 0x0500 \ + instance commsBufferManager: Svc.BufferManager base id ComFprimeConfig.BASE_ID + 0x0500 \ { phase Fpp.ToCpp.Phases.configConstants """ enum { @@ -73,73 +73,48 @@ module Comms { """ phase Fpp.ToCpp.Phases.configComponents """ - memset(&Comms::BufferManagerBins::bins, 0, sizeof(Comms::BufferManagerBins::bins)); - Comms::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; - Comms::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; - Comms::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - Comms::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; - Comms::commsBufferManager.setup( - ConfigConstants::Comms_commsBufferManager::COMMS_BUFFER_MANAGER_ID, + memset(&ComFprime::BufferManagerBins::bins, 0, sizeof(ComFprime::BufferManagerBins::bins)); + ComFprime::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; + ComFprime::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; + ComFprime::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; + ComFprime::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + ComFprime::commsBufferManager.setup( + ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_ID, 0, - Comms::Allocation::mallocator, - Comms::BufferManagerBins::bins + ComFprime::Allocation::mallocator, + ComFprime::BufferManagerBins::bins ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - Comms::commsBufferManager.cleanup(); + ComFprime::commsBufferManager.cleanup(); """ } - instance frameAccumulator: Svc.FrameAccumulator base id CommsConfig.BASE_ID + 0x0600 \ + instance frameAccumulator: Svc.FrameAccumulator base id ComFprimeConfig.BASE_ID + 0x0600 \ { phase Fpp.ToCpp.Phases.configComponents """ - Comms::frameAccumulator.configure( - Comms::Detector::frameDetector, + ComFprime::frameAccumulator.configure( + ComFprime::Detector::frameDetector, 1, - Comms::Allocation::mallocator, + ComFprime::Allocation::mallocator, 2048 ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - Comms::frameAccumulator.cleanup(); + ComFprime::frameAccumulator.cleanup(); """ } - instance deframer: Svc.FprimeDeframer base id CommsConfig.BASE_ID + 0x0700 \ + instance deframer: Svc.FprimeDeframer base id ComFprimeConfig.BASE_ID + 0x0700 \ - instance fprimeFramer: Svc.FprimeFramer base id CommsConfig.BASE_ID + 0x0800 \ + instance fprimeFramer: Svc.FprimeFramer base id ComFprimeConfig.BASE_ID + 0x0800 \ - instance fprimeRouter: Svc.FprimeRouter base id CommsConfig.BASE_ID + 0x0900 \ + instance fprimeRouter: Svc.FprimeRouter base id ComFprimeConfig.BASE_ID + 0x0900 \ - instance comStub: Svc.ComStub base id CommsConfig.BASE_ID + 0x0A00 \ - - @ Communications driver. May be swapped with other comm drivers like UART - instance comDriver: Drv.TcpClient base id CommsConfig.BASE_ID + 0x0B00 \ - { - phase Fpp.ToCpp.Phases.configComponents """ - if (state.hostname != nullptr && state.port != 0) { - Comms::comDriver.configure(state.hostname, state.port); - } - """ - - phase Fpp.ToCpp.Phases.startTasks """ - if (state.hostname != nullptr && state.port != 0) { - Os::TaskString name("ReceiveTask"); - Comms::comDriver.start(name, 100, 100); - } - """ - - phase Fpp.ToCpp.Phases.stopTasks """ - Comms::comDriver.stop(); - """ - - phase Fpp.ToCpp.Phases.freeThreads """ - (void)Comms::comDriver.join(); - """ - } + instance comStub: Svc.ComStub base id ComFprimeConfig.BASE_ID + 0x0A00 \ topology Subtopology { # Active Components @@ -202,4 +177,4 @@ module Comms { } # end topology -} # end Comms Subtopology \ No newline at end of file +} # end ComFprime Subtopology \ No newline at end of file diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt new file mode 100644 index 00000000000..580d2af6de3 --- /dev/null +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt @@ -0,0 +1,5 @@ +register_fprime_module( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/ComFprimeConfig.fpp" + INTERFACE +) diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp new file mode 100644 index 00000000000..6d17fe1c9c3 --- /dev/null +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp @@ -0,0 +1,49 @@ +module ComFprimeConfig { + #Base ID for the ComFprime Subtopology, all components are offsets from this base ID + constant BASE_ID = 0x7000 + + module QueueSizes { + constant comQueue = 10 + constant cmdSeq = 10 + } + + + module StackSizes { + constant comQueue = 64 * 1024 + constant cmdSeq = 64 * 1024 + } + + module Priorities { + constant comQueue = 101 + constant cmdSeq = 100 + } +} + +module ComFprime { + # Communications driver. May be swapped out with other comm drivers like UART in this file + # to use another driver in the Comms Subtopology + instance comDriver: Drv.TcpClient base id ComFprimeConfig.BASE_ID + 0x0B00 \ + { + phase Fpp.ToCpp.Phases.configComponents """ + if (state.hostname != nullptr && state.port != 0) { + ComFprime::comDriver.configure(state.hostname, state.port); + } + """ + + phase Fpp.ToCpp.Phases.startTasks """ + // Initialize socket client communication if and only if there is a valid specification + if (state.hostname != nullptr && state.port != 0) { + Os::TaskString name("ReceiveTask"); + ComFprime::comDriver.start(name, 100, 100); + } + """ + + phase Fpp.ToCpp.Phases.stopTasks """ + ComFprime::comDriver.stop(); + """ + + phase Fpp.ToCpp.Phases.freeThreads """ + (void)ComFprime::comDriver.join(); + """ + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/ComFprime/PingEntries.hpp b/Svc/Subtopologies/ComFprime/PingEntries.hpp new file mode 100644 index 00000000000..3e07c871b64 --- /dev/null +++ b/Svc/Subtopologies/ComFprime/PingEntries.hpp @@ -0,0 +1,8 @@ +#ifndef COMFPRIME_PINGENTRIES_HPP +#define COMFPRIME_PINGENTRIES_HPP + + namespace PingEntries { + namespace ComFprime_cmdSeq {enum { WARN = 3, FATAL = 5 };} + } + +#endif diff --git a/Svc/Subtopologies/Comms/CommsTopologyDefs.cpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp similarity index 100% rename from Svc/Subtopologies/Comms/CommsTopologyDefs.cpp rename to Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp diff --git a/Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp similarity index 70% rename from Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp rename to Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp index e4a2dab201d..59a6c7ebacb 100644 --- a/Svc/Subtopologies/Comms/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp @@ -1,23 +1,23 @@ -#ifndef COMMSSUBTOPOLOGY_DEFS_HPP -#define COMMSSUBTOPOLOGY_DEFS_HPP +#ifndef COMFPRIMESUBTOPOLOGY_DEFS_HPP +#define COMFPRIMESUBTOPOLOGY_DEFS_HPP #include #include #include -namespace Comms { +namespace ComFprime { namespace Allocation { // Malloc allocator for topology construction extern Fw::MallocAllocator mallocator; } namespace BufferManagerBins { - // Buffer manager bins for Comms + // Buffer manager bins for ComFprime extern Svc::BufferManager::BufferBins bins; } namespace Detector { - // Frame detector for Comms + // Frame detector for ComFprime extern Svc::FrameDetectors::FprimeFrameDetector frameDetector; } @@ -29,8 +29,4 @@ namespace Comms { } - namespace PingEntries { - namespace Comms_cmdSeq {enum { WARN = 3, FATAL = 5 };} - } - #endif \ No newline at end of file diff --git a/Svc/Subtopologies/Comms/CMakeLists.txt b/Svc/Subtopologies/Comms/CMakeLists.txt deleted file mode 100644 index 8088d665c6f..00000000000 --- a/Svc/Subtopologies/Comms/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsConfig/") - -register_fprime_module( - AUTOCODER_INPUTS - "${CMAKE_CURRENT_LIST_DIR}/Comms.fpp" - SOURCES - "${CMAKE_CURRENT_LIST_DIR}/CommsTopologyDefs.cpp" - HEADERS - "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" -) diff --git a/Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt b/Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt deleted file mode 100644 index 48132f2b192..00000000000 --- a/Svc/Subtopologies/Comms/CommsConfig/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -register_fprime_config( - AUTOCODER_INPUTS - "${CMAKE_CURRENT_LIST_DIR}/CommsConfig.fpp" - INTERFACE -) diff --git a/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp b/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp deleted file mode 100644 index f0b52609e9a..00000000000 --- a/Svc/Subtopologies/Comms/CommsConfig/CommsConfig.fpp +++ /dev/null @@ -1,20 +0,0 @@ -module CommsConfig { - #Base ID for the CDHCore Subtopology, all components are offsets from this base ID - constant BASE_ID = 0x7000 - - module QueueSizes { - constant comQueue = 10 - constant cmdSeq = 10 - } - - - module StackSizes { - constant comQueue = 64 * 1024 - constant cmdSeq = 64 * 1024 - } - - module Priorities { - constant comQueue = 101 - constant cmdSeq = 100 - } -} \ No newline at end of file diff --git a/Svc/Subtopologies/CommsCCSDS/PingEntries.hpp b/Svc/Subtopologies/CommsCCSDS/PingEntries.hpp deleted file mode 100644 index 940d95e9281..00000000000 --- a/Svc/Subtopologies/CommsCCSDS/PingEntries.hpp +++ /dev/null @@ -1,9 +0,0 @@ - -#ifndef COMMSCCSDS_PINGENTRIES_HPP -#define COMMSCCSDS_PINGENTRIES_HPP - - namespace PingEntries { - namespace CommsCCSDS_cmdSeq {enum { WARN = 3, FATAL = 5 };} - } - -#endif diff --git a/Svc/Subtopologies/DataProducts/CMakeLists.txt b/Svc/Subtopologies/DataProducts/CMakeLists.txt index 9faac7c3d02..bf9142ec8b0 100644 --- a/Svc/Subtopologies/DataProducts/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/CMakeLists.txt @@ -4,7 +4,8 @@ register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/DataProducts.fpp" SOURCES - "${CMAKE_CURRENT_LIST_DIR}/DataProductsTopologyDefs.cpp" + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" ) diff --git a/Svc/Subtopologies/DataProducts/PingEntries.hpp b/Svc/Subtopologies/DataProducts/PingEntries.hpp new file mode 100644 index 00000000000..78a745da8a8 --- /dev/null +++ b/Svc/Subtopologies/DataProducts/PingEntries.hpp @@ -0,0 +1,8 @@ +#ifndef DATAPRODUCTS_PINGENTRIES_HPP +#define DATAPRODUCTS_PINGENTRIES_HPP + + namespace PingEntries { + namespace DataProducts_dpCat {enum { WARN = 3, FATAL = 5 };} + } + +#endif diff --git a/Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.cpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp similarity index 100% rename from Svc/Subtopologies/DataProducts/DataProductsTopologyDefs.cpp rename to Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp diff --git a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp index 58c7d74ce96..b3a4030b35d 100644 --- a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp @@ -21,8 +21,4 @@ namespace DataProducts { }; } - namespace PingEntries { - namespace DataProducts_dpCat {enum { WARN = 3, FATAL = 5 };} - } - #endif \ No newline at end of file diff --git a/Svc/Subtopologies/FileHandling/CMakeLists.txt b/Svc/Subtopologies/FileHandling/CMakeLists.txt index 800caa24e18..9c9988ffba3 100644 --- a/Svc/Subtopologies/FileHandling/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/CMakeLists.txt @@ -4,6 +4,6 @@ register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/FileHandling.fpp" HEADERS - "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE ) diff --git a/Svc/Subtopologies/FileHandling/PingEntries.hpp b/Svc/Subtopologies/FileHandling/PingEntries.hpp new file mode 100644 index 00000000000..8d24ec9a7c9 --- /dev/null +++ b/Svc/Subtopologies/FileHandling/PingEntries.hpp @@ -0,0 +1,11 @@ +#ifndef FILEHANDLING_PINGENTRIES_HPP +#define FILEHANDLING_PINGENTRIES_HPP + + namespace PingEntries { + namespace FileHandling_fileDownlink {enum { WARN = 3, FATAL = 5 };} + namespace FileHandling_fileManager {enum { WARN = 3, FATAL = 5 };} + namespace FileHandling_fileUplink {enum { WARN = 3, FATAL = 5 };} + namespace FileHandling_prmDb {enum { WARN = 3, FATAL = 5 };} + } + +#endif diff --git a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp new file mode 100644 index 00000000000..d2f276afd92 --- /dev/null +++ b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp @@ -0,0 +1,5 @@ +#include "SubtopologyTopologyDefs.hpp" + +namespace FileHandling { + // Implementation for FileHandling subtopology +} diff --git a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp index e64b72c3d7e..3c67c2a7e02 100644 --- a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp @@ -7,11 +7,4 @@ namespace FileHandling { }; } - namespace PingEntries { - namespace FileHandling_fileDownlink {enum { WARN = 3, FATAL = 5 };} - namespace FileHandling_fileManager {enum { WARN = 3, FATAL = 5 };} - namespace FileHandling_fileUplink {enum { WARN = 3, FATAL = 5 };} - namespace FileHandling_prmDb {enum { WARN = 3, FATAL = 5 };} - } - #endif \ No newline at end of file From 0c8ee99e7ae13a8e494ed64aa0294085268aa3eb Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Wed, 18 Jun 2025 16:16:58 -0700 Subject: [PATCH 28/52] Namespace fixe for ComFprime --- Ref/Top/RefTopology.cpp | 6 ------ Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 92605bf7982..96897353746 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -15,9 +15,6 @@ #include #include -#include - - // Used for 1Hz synthetic cycling #include @@ -76,9 +73,6 @@ void setupTopology(const TopologyState& state) { loadParameters(); // Autocoded task kick-off (active components). Function provided by autocoder. startTasks(state); - - // Startup TLM and Config verbosity for Versions - } void startRateGroups(Fw::TimeInterval interval) { diff --git a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp index f2aa89a0fb0..f4f4490fcf9 100644 --- a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp +++ b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp @@ -1,6 +1,6 @@ #include "SubtopologyTopologyDefs.hpp" -namespace Comms { +namespace ComFprime { namespace Allocation { Fw::MallocAllocator mallocator; } From 7c0b08ec975758244d1669141ed94a1ae63a0ac9 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Wed, 18 Jun 2025 16:24:18 -0700 Subject: [PATCH 29/52] CDHCore->Cdhcore for consistency --- Ref/Top/instances.fpp | 2 +- Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp | 2 +- .../DataProducts/DataProductsConfig/DataProductsConfig.fpp | 2 +- .../FileHandling/FileHandlingConfig/FileHandlingConfig.fpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 36dc4352acd..3b435d20cf0 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -41,7 +41,7 @@ module Ref { # comment in Svc.TlmChan or Svc.TlmPacketizer # depending on which form of telemetry downlink # you wish to use - # NOTE: Svc.TlmChan is provided in the CDHCore Subtopology + # NOTE: Svc.TlmChan is provided in the CdhCore Subtopology #instance tlmSend: Svc.TlmChan base id 0x0C00 \ # queue size Default.QUEUE_SIZE \ diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp index 66c2da5dac4..fc6d10fe972 100644 --- a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp +++ b/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp @@ -51,6 +51,6 @@ module CdhCore { #} # Update this as a custom fatal handler if needed - instance fatalHandler: Svc.FatalHandler base id CDHCoreConfig.BASE_ID + 0x0800 + instance fatalHandler: Svc.FatalHandler base id CdhCoreConfig.BASE_ID + 0x0800 } \ No newline at end of file diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp index 0302a7ee84c..baa2aba7aed 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp @@ -1,5 +1,5 @@ module DataProductsConfig { - #Base ID for the CDHCore Subtopology, all components are offsets from this base ID + #Base ID for the DataProducts Subtopology, all components are offsets from this base ID constant BASE_ID = 0x9000 module QueueSizes { diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp index 00ef61ed92e..b754e6c2150 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp @@ -1,5 +1,5 @@ module FileHandlingConfig { - #Base ID for the CDHCore Subtopology, all components are offsets from this base ID + #Base ID for the FileHandling Subtopology, all components are offsets from this base ID constant BASE_ID = 0xA000 module QueueSizes { From 01849bebdbcd4ef8a0aae7a7f0d17af9f71f0011 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 19 Jun 2025 09:32:11 -0700 Subject: [PATCH 30/52] Rename CDHCore to CdhCore for consistency --- Svc/Subtopologies/{CDHCore => CdhCore}/CMakeLists.txt | 0 Svc/Subtopologies/{CDHCore/CDHCore.fpp => CdhCore/CdhCore.fpp} | 0 .../CDHCoreConfig => CdhCore/CdhCoreConfig}/CMakeLists.txt | 0 .../CDHCoreConfig.fpp => CdhCore/CdhCoreConfig/CdhCoreConfig.fpp} | 0 Svc/Subtopologies/{CDHCore => CdhCore}/PingEntries.hpp | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename Svc/Subtopologies/{CDHCore => CdhCore}/CMakeLists.txt (100%) rename Svc/Subtopologies/{CDHCore/CDHCore.fpp => CdhCore/CdhCore.fpp} (100%) rename Svc/Subtopologies/{CDHCore/CDHCoreConfig => CdhCore/CdhCoreConfig}/CMakeLists.txt (100%) rename Svc/Subtopologies/{CDHCore/CDHCoreConfig/CDHCoreConfig.fpp => CdhCore/CdhCoreConfig/CdhCoreConfig.fpp} (100%) rename Svc/Subtopologies/{CDHCore => CdhCore}/PingEntries.hpp (100%) diff --git a/Svc/Subtopologies/CDHCore/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CMakeLists.txt similarity index 100% rename from Svc/Subtopologies/CDHCore/CMakeLists.txt rename to Svc/Subtopologies/CdhCore/CMakeLists.txt diff --git a/Svc/Subtopologies/CDHCore/CDHCore.fpp b/Svc/Subtopologies/CdhCore/CdhCore.fpp similarity index 100% rename from Svc/Subtopologies/CDHCore/CDHCore.fpp rename to Svc/Subtopologies/CdhCore/CdhCore.fpp diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt similarity index 100% rename from Svc/Subtopologies/CDHCore/CDHCoreConfig/CMakeLists.txt rename to Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt diff --git a/Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreConfig.fpp similarity index 100% rename from Svc/Subtopologies/CDHCore/CDHCoreConfig/CDHCoreConfig.fpp rename to Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreConfig.fpp diff --git a/Svc/Subtopologies/CDHCore/PingEntries.hpp b/Svc/Subtopologies/CdhCore/PingEntries.hpp similarity index 100% rename from Svc/Subtopologies/CDHCore/PingEntries.hpp rename to Svc/Subtopologies/CdhCore/PingEntries.hpp From eb7a4530044793218ecf221dbb328ba10f63f041 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 19 Jun 2025 16:33:50 +0000 Subject: [PATCH 31/52] Update metadata check-spelling run (pull_request_target) for add-subtopologies Signed-off-by: check-spelling-bot on-behalf-of: @check-spelling --- .github/actions/spelling/expect.txt | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 1c2e95c23f0..7551a816e93 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -66,7 +66,8 @@ CCB CComponent ccsds ccsparc -CDH +cdh +CDHCORE cerrno CFDP cff @@ -92,6 +93,10 @@ CODEFILE COLORSTYLE colorwheel COMBUFFER +COMCCSDS +COMCCSDSSUBTOPOLOGY +COMFPRIME +COMFPRIMESUBTOPOLOGY comlogger COMMANDDISPATCHERIMPL COMMANDDISPATCHERIMPLCFG @@ -130,6 +135,8 @@ ctu culates cuz CYCLEOUT +DATAPRODUCTS +DATAPRODUCTSSUBTOPOLOGY DATAROOTDIR DDDTHH Debian @@ -147,6 +154,7 @@ DHTML diafile diles dinkel +dnf dnp docbook docset @@ -209,12 +217,12 @@ ffff Ffs FILEDOWNLINK FILEDOWNLINKCFG +FILEHANDLING FILEHANDLINGSUBTOPOLOGY FILEID FILEOPENERROR FILEWRITEERROR fio -FLDP FNDELAY FONTPATH foodoodie @@ -239,6 +247,8 @@ gcgandhi gcov gdiplus GENHUB +getfooter +getstatements gettime getty ghprb @@ -385,10 +395,10 @@ multitool mutexattr Mutexed mycompany -NACI nasafprime nbits ncsl +netinet newtio nmsgs NOBLOCK @@ -403,6 +413,8 @@ NSHUFF NSPACES ntohs objcopy +OCF +ODR oflag okidocki OLDINCLUDEDIR @@ -443,7 +455,6 @@ PASSIVERATEGROUP PASSIVERATEGROUPIMPLTESTER patsubst pdflatex -PEB penv PERLMOD PINGENTRIES @@ -487,6 +498,7 @@ ptbool ptf pthread ptrt +Pvn qch qhelpgenerator QHG @@ -508,6 +520,7 @@ rcvd rdwr Readback Recvd +redhat refspec REFTOPOLOGY REFTOPOLOGYDEFS @@ -531,6 +544,7 @@ sats SBF SBINDIR sbom +scid scm sdd searchdata @@ -611,6 +625,7 @@ TCPCLIENT TCPHELPER TCPSERVER TCSANOW +Telecommand telem TELEMCHANIMPL testerbase @@ -659,6 +674,9 @@ useconds usecs valgrind vbai +VCA +vcid +VCP VFILE VID vla From 05a5c8fadf3dd64590be5464d74d4bbe2a130ffa Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 19 Jun 2025 10:27:07 -0700 Subject: [PATCH 32/52] Reorder on teardown phases for Com Subtopolgies --- Svc/Subtopologies/ComCcsds/ComCcsds.fpp | 36 +++++++++++------------ Svc/Subtopologies/ComFprime/ComFprime.fpp | 36 +++++++++++------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 95f3b639bde..3b215f64abb 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -60,7 +60,24 @@ module ComCcsds { # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - instance commsBufferManager: Svc.BufferManager base id ComCcsdsConfig.BASE_ID + 0x0500 \ + instance frameAccumulator: Svc.FrameAccumulator base id ComCcsdsConfig.BASE_ID + 0x0500 \ + { + + phase Fpp.ToCpp.Phases.configComponents """ + ComCcsds::frameAccumulator.configure( + ComCcsds::Detector::frameDetector, + 1, + ComCcsds::Allocation::mallocator, + 2048 + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + ComCcsds::frameAccumulator.cleanup(); + """ + } + + instance commsBufferManager: Svc.BufferManager base id ComCcsdsConfig.BASE_ID + 0x0600 \ { phase Fpp.ToCpp.Phases.configConstants """ enum { @@ -93,23 +110,6 @@ module ComCcsds { """ } - instance frameAccumulator: Svc.FrameAccumulator base id ComCcsdsConfig.BASE_ID + 0x0600 \ - { - - phase Fpp.ToCpp.Phases.configComponents """ - ComCcsds::frameAccumulator.configure( - ComCcsds::Detector::frameDetector, - 1, - ComCcsds::Allocation::mallocator, - 2048 - ); - """ - - phase Fpp.ToCpp.Phases.tearDownComponents """ - ComCcsds::frameAccumulator.cleanup(); - """ - } - instance fprimeRouter: Svc.FprimeRouter base id ComCcsdsConfig.BASE_ID + 0x0700 \ instance comStub: Svc.ComStub base id ComCcsdsConfig.BASE_ID + 0x0800 \ diff --git a/Svc/Subtopologies/ComFprime/ComFprime.fpp b/Svc/Subtopologies/ComFprime/ComFprime.fpp index 48addf56a9c..839bdbebabc 100644 --- a/Svc/Subtopologies/ComFprime/ComFprime.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprime.fpp @@ -60,7 +60,24 @@ module ComFprime { # ---------------------------------------------------------------------- # Passive Components # ---------------------------------------------------------------------- - instance commsBufferManager: Svc.BufferManager base id ComFprimeConfig.BASE_ID + 0x0500 \ + instance frameAccumulator: Svc.FrameAccumulator base id ComFprimeConfig.BASE_ID + 0x0500 \ + { + + phase Fpp.ToCpp.Phases.configComponents """ + ComFprime::frameAccumulator.configure( + ComFprime::Detector::frameDetector, + 1, + ComFprime::Allocation::mallocator, + 2048 + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + ComFprime::frameAccumulator.cleanup(); + """ + } + + instance commsBufferManager: Svc.BufferManager base id ComFprimeConfig.BASE_ID + 0x0600 \ { phase Fpp.ToCpp.Phases.configConstants """ enum { @@ -91,23 +108,6 @@ module ComFprime { """ } - instance frameAccumulator: Svc.FrameAccumulator base id ComFprimeConfig.BASE_ID + 0x0600 \ - { - - phase Fpp.ToCpp.Phases.configComponents """ - ComFprime::frameAccumulator.configure( - ComFprime::Detector::frameDetector, - 1, - ComFprime::Allocation::mallocator, - 2048 - ); - """ - - phase Fpp.ToCpp.Phases.tearDownComponents """ - ComFprime::frameAccumulator.cleanup(); - """ - } - instance deframer: Svc.FprimeDeframer base id ComFprimeConfig.BASE_ID + 0x0700 \ instance fprimeFramer: Svc.FprimeFramer base id ComFprimeConfig.BASE_ID + 0x0800 \ From f00ecc5212fa2018fa5338d6a6a3cca5e4dd01d7 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 19 Jun 2025 10:29:08 -0700 Subject: [PATCH 33/52] Cpp check style fix --- Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp | 2 +- Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp | 2 +- Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp | 2 +- Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp | 2 +- Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp index f4f4490fcf9..2d409e9afae 100644 --- a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp +++ b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp @@ -12,4 +12,4 @@ namespace ComFprime { namespace Detector { Svc::FrameDetectors::FprimeFrameDetector frameDetector; } -} \ No newline at end of file +} diff --git a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp index 59a6c7ebacb..b64da4532cc 100644 --- a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp @@ -29,4 +29,4 @@ namespace ComFprime { } -#endif \ No newline at end of file +#endif diff --git a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp index 0296d9f058c..18d2d75ede6 100644 --- a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp +++ b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp @@ -8,4 +8,4 @@ namespace DataProducts { namespace BufferManagerBins { Svc::BufferManager::BufferBins bins; } -} \ No newline at end of file +} diff --git a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp index b3a4030b35d..0817532a3f3 100644 --- a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp @@ -21,4 +21,4 @@ namespace DataProducts { }; } -#endif \ No newline at end of file +#endif diff --git a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp index 3c67c2a7e02..a24f6761735 100644 --- a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp @@ -7,4 +7,4 @@ namespace FileHandling { }; } -#endif \ No newline at end of file +#endif From 6372c80cab237ffbc4e47f4ddf0cbedafe0faa0e Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 08:55:20 -0700 Subject: [PATCH 34/52] Fix: Add missing tearDownComponents cleanup for DataProducts dpBufferManager --- Svc/Subtopologies/DataProducts/DataProducts.fpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 29c762bfb59..28eb911cc81 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -56,6 +56,10 @@ module DataProducts{ DataProducts::BufferManagerBins::bins ); """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + DataProducts::dpBufferManager.cleanup(); + """ } topology Subtopology { #Active Components From f4142035dbead4d94ff22ea2cdd05ac8ee0e7765 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 09:37:26 -0700 Subject: [PATCH 35/52] Delete old comments, test using same mallocator for all subtopologies --- Ref/Top/instances.fpp | 16 ---------------- Svc/Subtopologies/DataProducts/DataProducts.fpp | 4 ++-- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 3b435d20cf0..f3f3786c537 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -38,28 +38,12 @@ module Ref { stack size Default.STACK_SIZE \ priority 100 - # comment in Svc.TlmChan or Svc.TlmPacketizer - # depending on which form of telemetry downlink - # you wish to use - # NOTE: Svc.TlmChan is provided in the CdhCore Subtopology - - #instance tlmSend: Svc.TlmChan base id 0x0C00 \ - # queue size Default.QUEUE_SIZE \ - # stack size Default.STACK_SIZE \ - # priority 97 - - #instance tlmSend: Svc.TlmPacketizer base id 0x0C00 \ - # queue size Default.QUEUE_SIZE \ - # stack size Default.STACK_SIZE \ - # priority 97 - instance typeDemo: Ref.TypeDemo base id 0x1200 # ---------------------------------------------------------------------- # Queued component instances # ---------------------------------------------------------------------- - instance sendBuffComp: Ref.SendBuff base id 0x2000 \ queue size Default.QUEUE_SIZE diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 28eb911cc81..b65a04fd7ff 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -13,7 +13,7 @@ module DataProducts{ Fw::FileNameString dpDir("./DpCat"); Fw::FileNameString dpState("./DpCat/DpState.dat"); Os::FileSystem::createDirectory(dpDir.toChar()); - DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::mallocator); + DataProducts::dpCat.configure(&dpDir,1,dpState,0, CommsCcsds::Allocation::mallocator); """ } @@ -52,7 +52,7 @@ module DataProducts{ DataProducts::dpBufferManager.setup( ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_ID, 0, - DataProducts::Allocation::mallocator, + CommsCcsds::Allocation::mallocator, DataProducts::BufferManagerBins::bins ); """ From be7896f95426bcf21dc55cef73e045607a47e7a5 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 09:46:20 -0700 Subject: [PATCH 36/52] fix: Deallocated DataProducts BufferMgr --- Svc/Subtopologies/DataProducts/DataProducts.fpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index b65a04fd7ff..bdba07a54ce 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -13,7 +13,7 @@ module DataProducts{ Fw::FileNameString dpDir("./DpCat"); Fw::FileNameString dpState("./DpCat/DpState.dat"); Os::FileSystem::createDirectory(dpDir.toChar()); - DataProducts::dpCat.configure(&dpDir,1,dpState,0, CommsCcsds::Allocation::mallocator); + DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::mallocator); """ } @@ -52,13 +52,12 @@ module DataProducts{ DataProducts::dpBufferManager.setup( ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_ID, 0, - CommsCcsds::Allocation::mallocator, + DataProducts::Allocation::mallocator, DataProducts::BufferManagerBins::bins ); """ - phase Fpp.ToCpp.Phases.tearDownComponents """ - DataProducts::dpBufferManager.cleanup(); + DataProducts::dpBufferManager.deallocateBuffer(DataProducts::Allocation::mallocator); """ } topology Subtopology { From 485e847283561e793ab211c2f88a90ee4a60c32e Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 10:14:45 -0700 Subject: [PATCH 37/52] Fix DataProducts subtopology memory cleanup --- Svc/Subtopologies/DataProducts/DataProducts.fpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index bdba07a54ce..8db3a833f80 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -15,6 +15,9 @@ module DataProducts{ Os::FileSystem::createDirectory(dpDir.toChar()); DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::mallocator); """ + phase Fpp.ToCpp.Phases.tearDownComponents """ + DataProducts::dpCat.shutdown(); + """ } instance dpMgr: Svc.DpManager base id DataProductsConfig.BASE_ID + 0x0200 \ @@ -57,7 +60,7 @@ module DataProducts{ ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - DataProducts::dpBufferManager.deallocateBuffer(DataProducts::Allocation::mallocator); + DataProducts::dpBufferManager.cleanup(); """ } topology Subtopology { From ed3efd675bf1cfb8a0654bcec6eeae91c3662e31 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 10:31:32 -0700 Subject: [PATCH 38/52] Fix: Dataproducts subtopology teardown order --- Svc/Subtopologies/DataProducts/DataProducts.fpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 8db3a833f80..142518c3002 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -15,9 +15,6 @@ module DataProducts{ Os::FileSystem::createDirectory(dpDir.toChar()); DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::mallocator); """ - phase Fpp.ToCpp.Phases.tearDownComponents """ - DataProducts::dpCat.shutdown(); - """ } instance dpMgr: Svc.DpManager base id DataProductsConfig.BASE_ID + 0x0200 \ @@ -60,6 +57,7 @@ module DataProducts{ ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ + DataProducts::dpCat.shutdown(); DataProducts::dpBufferManager.cleanup(); """ } From 5f8067357727bd3a16f8c8278da16b35cf941430 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 10:47:21 -0700 Subject: [PATCH 39/52] Added tearDownComponents(state) --- Ref/Top/RefTopology.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 96897353746..33fdbe95d74 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -91,5 +91,6 @@ void teardownTopology(const TopologyState& state) { // Autocoded (active component) task clean-up. Functions provided by topology autocoder. stopTasks(state); freeThreads(state); + tearDownComponents(state); } } // namespace Ref \ No newline at end of file From 4aa18333a09ae89653b0ee32aa030358a099ada1 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 12:03:45 -0700 Subject: [PATCH 40/52] Consolidate all cleanup to teardowncomponents --- Svc/Subtopologies/ComCcsds/ComCcsds.fpp | 6 +++--- Svc/Subtopologies/DataProducts/DataProducts.fpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 3b215f64abb..1bdb779fee6 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -53,7 +53,7 @@ module ComCcsds { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - ComCcsds::cmdSeq.deallocateBuffer(ComCcsds::Allocation::mallocator); + //ComCcsds::cmdSeq.deallocateBuffer(ComCcsds::Allocation::mallocator); """ } @@ -73,7 +73,7 @@ module ComCcsds { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - ComCcsds::frameAccumulator.cleanup(); + //ComCcsds::frameAccumulator.cleanup(); """ } @@ -106,7 +106,7 @@ module ComCcsds { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - ComCcsds::commsBufferManager.cleanup(); + //ComCcsds::commsBufferManager.cleanup(); """ } diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 142518c3002..f379fb84da0 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -57,8 +57,8 @@ module DataProducts{ ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - DataProducts::dpCat.shutdown(); - DataProducts::dpBufferManager.cleanup(); + //DataProducts::dpCat.shutdown(); + //DataProducts::dpBufferManager.cleanup(); """ } topology Subtopology { From 5d60b983d799876544c672c53782689f884ae19f Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 14:02:03 -0700 Subject: [PATCH 41/52] Fix memory leaks: restore teardown phases --- Svc/Subtopologies/ComCcsds/ComCcsds.fpp | 9 ++++++--- Svc/Subtopologies/DataProducts/DataProducts.fpp | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 1bdb779fee6..0ceafb325b5 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -35,6 +35,9 @@ module ComCcsds { // Allocation identifier is 0 as the MallocAllocator discards it ComCcsds::comQueue.configure(configurationTable, 0, ComCcsds::Allocation::mallocator); """ + phase Fpp.ToCpp.Phases.tearDownComponents """ + ComCcsds::comQueue.cleanup(); + """ } instance cmdSeq: Svc.CmdSequencer base id ComCcsdsConfig.BASE_ID + 0x0200 \ @@ -53,7 +56,7 @@ module ComCcsds { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - //ComCcsds::cmdSeq.deallocateBuffer(ComCcsds::Allocation::mallocator); + ComCcsds::cmdSeq.deallocateBuffer(ComCcsds::Allocation::mallocator); """ } @@ -73,7 +76,7 @@ module ComCcsds { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - //ComCcsds::frameAccumulator.cleanup(); + ComCcsds::frameAccumulator.cleanup(); """ } @@ -106,7 +109,7 @@ module ComCcsds { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - //ComCcsds::commsBufferManager.cleanup(); + ComCcsds::commsBufferManager.cleanup(); """ } diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index f379fb84da0..142518c3002 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -57,8 +57,8 @@ module DataProducts{ ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - //DataProducts::dpCat.shutdown(); - //DataProducts::dpBufferManager.cleanup(); + DataProducts::dpCat.shutdown(); + DataProducts::dpBufferManager.cleanup(); """ } topology Subtopology { From 29d4ff8242574f1afc1bb6aacdf5cfef4d79987d Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 14:26:10 -0700 Subject: [PATCH 42/52] Removal of redundant teardowncomponents() --- Ref/Top/RefTopology.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 33fdbe95d74..96897353746 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -91,6 +91,5 @@ void teardownTopology(const TopologyState& state) { // Autocoded (active component) task clean-up. Functions provided by topology autocoder. stopTasks(state); freeThreads(state); - tearDownComponents(state); } } // namespace Ref \ No newline at end of file From db8639ea61a4556ecf1997868e9fb1b5238cd13f Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 14:38:53 -0700 Subject: [PATCH 43/52] Revert "Removal of redundant teardowncomponents()" This reverts commit 29d4ff8242574f1afc1bb6aacdf5cfef4d79987d. --- Ref/Top/RefTopology.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 96897353746..33fdbe95d74 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -91,5 +91,6 @@ void teardownTopology(const TopologyState& state) { // Autocoded (active component) task clean-up. Functions provided by topology autocoder. stopTasks(state); freeThreads(state); + tearDownComponents(state); } } // namespace Ref \ No newline at end of file From 440f25d3bf792037147fbb83b3746825ca1bade7 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Fri, 20 Jun 2025 14:47:38 -0700 Subject: [PATCH 44/52] Fix formatting, remove commented out code --- RPI/Top/topology.fpp | 1 - Ref/CMakeLists.txt | 2 +- Ref/Top/CMakeLists.txt | 1 - Ref/Top/RefPackets.fppi | 3 --- Ref/Top/RefTopology.cpp | 5 +---- Ref/Top/RefTopology.hpp | 1 - Ref/Top/RefTopologyDefs.hpp | 2 -- 7 files changed, 2 insertions(+), 13 deletions(-) diff --git a/RPI/Top/topology.fpp b/RPI/Top/topology.fpp index 4e3c3ff60f2..a8abd2cc987 100644 --- a/RPI/Top/topology.fpp +++ b/RPI/Top/topology.fpp @@ -162,7 +162,6 @@ module RPI { fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn } - } } diff --git a/Ref/CMakeLists.txt b/Ref/CMakeLists.txt index b8dd892fd2c..d6ee05c470f 100644 --- a/Ref/CMakeLists.txt +++ b/Ref/CMakeLists.txt @@ -45,7 +45,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime.cmake") # NOTE: register custom targets between these two lines fprime_setup_included_code() ## -# Section 3: Components and Topology and Subtopologies +# 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. diff --git a/Ref/Top/CMakeLists.txt b/Ref/Top/CMakeLists.txt index eaa235b403d..62ac01e3760 100644 --- a/Ref/Top/CMakeLists.txt +++ b/Ref/Top/CMakeLists.txt @@ -7,7 +7,6 @@ add_compile_options( -Wno-shadow ) - set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/instances.fpp" "${CMAKE_CURRENT_LIST_DIR}/topology.fpp" diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index e01b2f0109a..64f5428a054 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -1,9 +1,6 @@ telemetry packets RefPackets { packet CDH id 1 group 1 { - - #Ref.cmdDisp.CommandsDispatched - CdhCore.cmdDisp.CommandsDispatched Ref.rateGroup1Comp.RgMaxTime Ref.rateGroup2Comp.RgMaxTime diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 33fdbe95d74..80cecc61e63 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -64,9 +64,6 @@ void setupTopology(const TopologyState& state) { regCommands(); // Autocoded configuration. Function provided by autocoder. configComponents(state); - //if (state.hostname != nullptr && state.port != 0) { - //Comms::comDriver.configure(state.hostname, state.port); - //} // Project-specific component configuration. Function provided above. May be inlined, if desired. configureTopology(); // Autocoded parameter loading. Function provided by autocoder. @@ -93,4 +90,4 @@ void teardownTopology(const TopologyState& state) { freeThreads(state); tearDownComponents(state); } -} // namespace Ref \ No newline at end of file +} // namespace Ref diff --git a/Ref/Top/RefTopology.hpp b/Ref/Top/RefTopology.hpp index 19502fce4ac..9fd39628d8a 100644 --- a/Ref/Top/RefTopology.hpp +++ b/Ref/Top/RefTopology.hpp @@ -14,7 +14,6 @@ // autocoder, but are also used in this hand-coded topology. #include - // Remove unnecessary Ref:: qualifications using namespace Ref; namespace Ref { diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 4719575af01..7130811e4aa 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -16,7 +16,6 @@ #include "Ref/Top/FppConstantsAc.hpp" #include "Svc/Health/Health.hpp" - // Subtopology PingEntries includes #include "Svc/Subtopologies/CdhCore/PingEntries.hpp" #include "Svc/Subtopologies/ComCcsds/PingEntries.hpp" @@ -72,5 +71,4 @@ namespace Ref { namespace PingEntries = ::PingEntries; } // namespace Ref - #endif From b161d793df8a30782c6cf2517fe71a3615d10a16 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 23 Jun 2025 11:59:17 -0700 Subject: [PATCH 45/52] Swap hardcoded numbers to config constants in subtopologies --- Ref/Top/RefPackets.fppi | 41 +++++++++------ Ref/Top/RefTopologyDefs.hpp | 1 + Ref/Top/topology.fpp | 8 +-- Svc/Subtopologies/ComCcsds/ComCcsds.fpp | 52 +++++++------------ .../ComCcsds/ComCcsdsConfig/CMakeLists.txt | 2 +- .../ComCcsdsConfig/ComCcsdsConfig.fpp | 29 ++++++++++- .../ComCcsds/SubtopologyTopologyDefs.hpp | 1 + Svc/Subtopologies/ComFprime/ComFprime.fpp | 42 +++++---------- .../ComFprimeConfig/ComFprimeConfig.fpp | 29 ++++++++++- .../ComFprime/SubtopologyTopologyDefs.hpp | 1 + .../DataProducts/DataProducts.fpp | 15 ++---- .../DataProductsConfig/DataProductsConfig.fpp | 7 +++ .../DataProducts/SubtopologyTopologyDefs.hpp | 1 + Svc/Subtopologies/FileHandling/CMakeLists.txt | 4 +- .../FileHandling/FileHandling.fpp | 16 ++---- .../FileHandlingConfig/FileHandlingConfig.fpp | 9 +++- .../FileHandling/SubtopologyTopologyDefs.hpp | 1 + 17 files changed, 147 insertions(+), 112 deletions(-) diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index 64f5428a054..c3f5a5bc8f1 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -2,39 +2,43 @@ telemetry packets RefPackets { packet CDH id 1 group 1 { CdhCore.cmdDisp.CommandsDispatched - Ref.rateGroup1Comp.RgMaxTime - Ref.rateGroup2Comp.RgMaxTime - Ref.rateGroup3Comp.RgMaxTime - ComCcsds.cmdSeq.CS_LoadCommands - ComCcsds.cmdSeq.CS_CancelCommands - ComCcsds.cmdSeq.CS_CommandsExecuted - ComCcsds.cmdSeq.CS_SequencesCompleted + FileHandling.fileUplink.FilesReceived FileHandling.fileUplink.PacketsReceived - ComCcsds.commsBufferManager.TotalBuffs - ComCcsds.commsBufferManager.CurrBuffs - ComCcsds.commsBufferManager.HiBuffs FileHandling.fileDownlink.FilesSent FileHandling.fileDownlink.PacketsSent FileHandling.fileManager.CommandsExecuted + + ComCcsds.cmdSeq.CS_LoadCommands + ComCcsds.cmdSeq.CS_CancelCommands + ComCcsds.cmdSeq.CS_CommandsExecuted + ComCcsds.cmdSeq.CS_SequencesCompleted ComCcsds.comQueue.comQueueDepth ComCcsds.comQueue.buffQueueDepth - # Ref.tlmSend.SendLevel + ComCcsds.commsBufferManager.TotalBuffs + ComCcsds.commsBufferManager.CurrBuffs + ComCcsds.commsBufferManager.HiBuffs + #ComCcsds.tlmSend.SendLevel + + Ref.rateGroup1Comp.RgMaxTime + Ref.rateGroup2Comp.RgMaxTime + Ref.rateGroup3Comp.RgMaxTime } packet CDHErrors id 2 group 1 { - Ref.rateGroup1Comp.RgCycleSlips - Ref.rateGroup2Comp.RgCycleSlips - Ref.rateGroup3Comp.RgCycleSlips - ComCcsds.cmdSeq.CS_Errors + CdhCore.$health.PingLateWarnings + FileHandling.fileUplink.Warnings FileHandling.fileDownlink.Warnings - CdhCore.$health.PingLateWarnings FileHandling.fileManager.Errors + + ComCcsds.cmdSeq.CS_Errors ComCcsds.commsBufferManager.NoBuffs ComCcsds.commsBufferManager.EmptyBuffs - FileHandling.fileManager.Errors + Ref.rateGroup1Comp.RgCycleSlips + Ref.rateGroup2Comp.RgCycleSlips + Ref.rateGroup3Comp.RgCycleSlips } packet DriveTlm id 3 group 1 { @@ -178,15 +182,18 @@ telemetry packets RefPackets { packet DataProducts id 21 group 3 { DataProducts.dpCat.CatalogDps DataProducts.dpCat.DpsSent + DataProducts.dpMgr.NumSuccessfulAllocations DataProducts.dpMgr.NumFailedAllocations DataProducts.dpMgr.NumDataProducts DataProducts.dpMgr.NumBytes + DataProducts.dpWriter.NumBuffersReceived DataProducts.dpWriter.NumBytesWritten DataProducts.dpWriter.NumSuccessfulWrites DataProducts.dpWriter.NumFailedWrites DataProducts.dpWriter.NumErrors + DataProducts.dpBufferManager.TotalBuffs DataProducts.dpBufferManager.CurrBuffs DataProducts.dpBufferManager.HiBuffs diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 7130811e4aa..945f78d55bc 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -25,6 +25,7 @@ // SubtopologyTopologyDefs includes #include "Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp" +#include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" namespace PingEntries { namespace Ref_blockDrv {enum { WARN = 3, FATAL = 5 };} diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index 58d13c5b82b..1154c5cb2e7 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -109,12 +109,12 @@ module Ref { ### Moved this out of DataProducts Subtopology --> anything specific to deployment should live in Ref connections # Synchronous request. Will have both request kinds for demo purposes, not typical - SG1.productGetOut -> DataProducts.dpMgr.productGetIn[0] + SG1.productGetOut -> DataProducts.dpMgr.productGetIn # Asynchronous request - SG1.productRequestOut -> DataProducts.dpMgr.productRequestIn[0] - DataProducts.dpMgr.productResponseOut[0] -> SG1.productRecvIn + SG1.productRequestOut -> DataProducts.dpMgr.productRequestIn + DataProducts.dpMgr.productResponseOut -> SG1.productRecvIn # Send filled DP - SG1.productSendOut -> DataProducts.dpMgr.productSendIn[0] + SG1.productSendOut -> DataProducts.dpMgr.productSendIn } diff --git a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 0ceafb325b5..01b9fe0a431 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -1,10 +1,11 @@ module ComCcsds { + # ComPacket Queue enum for queue types enum Ports_ComPacketQueue { EVENTS, TELEMETRY, FILE_QUEUE - }; + } # ---------------------------------------------------------------------- # Active Components @@ -15,7 +16,7 @@ module ComCcsds { priority ComCcsdsConfig.Priorities.comQueue \ { phase Fpp.ToCpp.Phases.configConstants """ - enum{ + enum { EVENTS, TELEMETRY, FILE_QUEUE @@ -23,15 +24,19 @@ module ComCcsds { """ phase Fpp.ToCpp.Phases.configComponents """ Svc::ComQueue::QueueConfigurationTable configurationTable; + // Events (highest-priority) - configurationTable.entries[ConfigConstants::ComCcsds_comQueue::EVENTS].depth = 100; - configurationTable.entries[ConfigConstants::ComCcsds_comQueue::EVENTS].priority = 0; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::EVENTS].depth = ComCcsdsConfig::QueueDepths::events; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::EVENTS].priority = ComCcsdsConfig::QueuePriorities::events; + // Telemetry - configurationTable.entries[ConfigConstants::ComCcsds_comQueue::TELEMETRY].depth = 500; - configurationTable.entries[ConfigConstants::ComCcsds_comQueue::TELEMETRY].priority = 2; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::TELEMETRY].depth = ComCcsdsConfig::QueueDepths::tlm; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::TELEMETRY].priority = ComCcsdsConfig::QueuePriorities::tlm; + // File Downlink Queue - configurationTable.entries[ConfigConstants::ComCcsds_comQueue::FILE_QUEUE].depth = 100; - configurationTable.entries[ConfigConstants::ComCcsds_comQueue::FILE_QUEUE].priority = 1; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::FILE_QUEUE].depth = ComCcsdsConfig::QueueDepths::file; + configurationTable.entries[ConfigConstants::ComCcsds_comQueue::FILE_QUEUE].priority = ComCcsdsConfig::QueuePriorities::file; + // Allocation identifier is 0 as the MallocAllocator discards it ComCcsds::comQueue.configure(configurationTable, 0, ComCcsds::Allocation::mallocator); """ @@ -45,14 +50,8 @@ module ComCcsds { stack size ComCcsdsConfig.StackSizes.cmdSeq \ priority ComCcsdsConfig.Priorities.cmdSeq \ { - phase Fpp.ToCpp.Phases.configConstants """ - enum { - CMD_SEQ_BUFFER_SIZE = 5 * 1024 - }; - """ - phase Fpp.ToCpp.Phases.configComponents """ - ComCcsds::cmdSeq.allocateBuffer(0, ComCcsds::Allocation::mallocator, ConfigConstants::ComCcsds_cmdSeq::CMD_SEQ_BUFFER_SIZE); + ComCcsds::cmdSeq.allocateBuffer(0, ComCcsds::Allocation::mallocator, ComCcsdsConfig::BufferMgr::cmdSeqBuffer); """ phase Fpp.ToCpp.Phases.tearDownComponents """ @@ -71,7 +70,7 @@ module ComCcsds { ComCcsds::Detector::frameDetector, 1, ComCcsds::Allocation::mallocator, - 2048 + ComCcsdsConfig::BufferMgr::frameAccumulator ); """ @@ -82,26 +81,15 @@ module ComCcsds { instance commsBufferManager: Svc.BufferManager base id ComCcsdsConfig.BASE_ID + 0x0600 \ { - phase Fpp.ToCpp.Phases.configConstants """ - enum { - // Buffer Manager for Uplink/Downlink - COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, - COMMS_BUFFER_MANAGER_STORE_COUNT = 20, - COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, - COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30, - COMMS_BUFFER_MANAGER_ID = 200 - }; - """ - phase Fpp.ToCpp.Phases.configComponents """ // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. memset(&ComCcsds::BufferManagerBins::bins, 0, sizeof(ComCcsds::BufferManagerBins::bins)); - ComCcsds::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; - ComCcsds::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; - ComCcsds::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - ComCcsds::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + ComCcsds::BufferManagerBins::bins.bins[0].bufferSize = ComCcsdsConfig::BufferMgr::commsBufferStore; + ComCcsds::BufferManagerBins::bins.bins[0].numBuffers = ComCcsdsConfig::BufferMgr::commsBufferCount; + ComCcsds::BufferManagerBins::bins.bins[1].bufferSize = ComCcsdsConfig::BufferMgr::commsFileBufferStore; + ComCcsds::BufferManagerBins::bins.bins[1].numBuffers = ComCcsdsConfig::BufferMgr::commsFileBufferCount; ComCcsds::commsBufferManager.setup( - ConfigConstants::ComCcsds_commsBufferManager::COMMS_BUFFER_MANAGER_ID, + ComCcsdsConfig::BufferMgr::commsBufferManager, 0, ComCcsds::Allocation::mallocator, ComCcsds::BufferManagerBins::bins diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt index c57b2e500b4..1eded39dc3d 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt @@ -1,4 +1,4 @@ -register_fprime_module( +register_fprime_config( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig.fpp" INTERFACE diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp index 1d59ad91a28..6403905d4ad 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp @@ -7,15 +7,40 @@ module ComCcsdsConfig { constant cmdSeq = 10 } - module StackSizes { constant comQueue = 64 * 1024 constant cmdSeq = 64 * 1024 + constant comDriver = 100 } module Priorities { constant comQueue = 101 constant cmdSeq = 100 + constant comDriver = 100 + } + + # Queue configuration constants + module QueueDepths { + constant events = 100 + constant tlm = 500 + constant file = 100 + } + + module QueuePriorities { + constant events = 0 + constant tlm = 2 + constant file = 1 + } + + # Buffer management constants + module BufferMgr { + constant cmdSeqBuffer = 5 * 1024 # 5KB for command sequencer buffer + constant frameAccumulator = 2048 # 2KB frame accumulator buffer + constant commsBufferStore = 2048 # 2KB communications buffer store + constant commsFileBufferStore = 3000 # 3KB file buffer store + constant commsBufferCount = 20 # Number of comms buffers + constant commsFileBufferCount = 30 # File queue buffer count + constant commsBufferManager = 200 # Buffer manager identifier } } @@ -34,7 +59,7 @@ module ComCcsds { // Initialize socket client communication if and only if there is a valid specification if (state.hostname != nullptr && state.port != 0) { Os::TaskString name("ReceiveTask"); - ComCcsds::comDriver.start(name, 100, 100); + ComCcsds::comDriver.start(name, ComCcsdsConfig::Priorities::comDriver, ComCcsdsConfig::StackSizes::comDriver); } """ diff --git a/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp index d114d982d65..6cb3fb878eb 100644 --- a/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp @@ -4,6 +4,7 @@ #include #include #include +#include "Svc/Subtopologies/ComCcsds/ComCcsdsConfig/FppConstantsAc.hpp" namespace ComCcsds { namespace Allocation { diff --git a/Svc/Subtopologies/ComFprime/ComFprime.fpp b/Svc/Subtopologies/ComFprime/ComFprime.fpp index 839bdbebabc..f779b129d4a 100644 --- a/Svc/Subtopologies/ComFprime/ComFprime.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprime.fpp @@ -24,14 +24,14 @@ module ComFprime { phase Fpp.ToCpp.Phases.configComponents """ Svc::ComQueue::QueueConfigurationTable configurationTable; // Events (highest-priority) - configurationTable.entries[ConfigConstants::ComFprime_comQueue::EVENTS].depth = 100; - configurationTable.entries[ConfigConstants::ComFprime_comQueue::EVENTS].priority = 0; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::EVENTS].depth = ComFprimeConfig::QueueDepths::events; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::EVENTS].priority = ComFprimeConfig::QueuePriorities::events; // Telemetry - configurationTable.entries[ConfigConstants::ComFprime_comQueue::TELEMETRY].depth = 500; - configurationTable.entries[ConfigConstants::ComFprime_comQueue::TELEMETRY].priority = 2; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::TELEMETRY].depth = ComFprimeConfig::QueueDepths::tlm; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::TELEMETRY].priority = ComFprimeConfig::QueuePriorities::tlm; // File Downlink Queue - configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].depth = 100; - configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].priority = 1; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].depth = ComFprimeConfig::QueueDepths::file; + configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].priority = ComFprimeConfig::QueuePriorities::file; // Allocation identifier is 0 as the MallocAllocator discards it ComFprime::comQueue.configure(configurationTable, 0, ComFprime::Allocation::mallocator); """ @@ -42,14 +42,8 @@ module ComFprime { stack size ComFprimeConfig.StackSizes.cmdSeq \ priority ComFprimeConfig.Priorities.cmdSeq \ { - phase Fpp.ToCpp.Phases.configConstants """ - enum { - CMD_SEQ_BUFFER_SIZE = 5 * 1024 - }; - """ - phase Fpp.ToCpp.Phases.configComponents """ - ComFprime::cmdSeq.allocateBuffer(0, ComFprime::Allocation::mallocator, ConfigConstants::ComFprime_cmdSeq::CMD_SEQ_BUFFER_SIZE); + ComFprime::cmdSeq.allocateBuffer(0, ComFprime::Allocation::mallocator, ComFprimeConfig::BufferMgr::cmdSeqBuffer); """ phase Fpp.ToCpp.Phases.tearDownComponents """ @@ -68,7 +62,7 @@ module ComFprime { ComFprime::Detector::frameDetector, 1, ComFprime::Allocation::mallocator, - 2048 + ComFprimeConfig::BufferMgr::frameAccumulator ); """ @@ -79,24 +73,14 @@ module ComFprime { instance commsBufferManager: Svc.BufferManager base id ComFprimeConfig.BASE_ID + 0x0600 \ { - phase Fpp.ToCpp.Phases.configConstants """ - enum { - COMMS_BUFFER_MANAGER_ID = 200, - COMMS_BUFFER_MANAGER_STORE_SIZE = 2048, - COMMS_BUFFER_MANAGER_STORE_COUNT = 20, - COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000, - COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30 - }; - """ - phase Fpp.ToCpp.Phases.configComponents """ memset(&ComFprime::BufferManagerBins::bins, 0, sizeof(ComFprime::BufferManagerBins::bins)); - ComFprime::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_SIZE; - ComFprime::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_STORE_COUNT; - ComFprime::BufferManagerBins::bins.bins[1].bufferSize = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_STORE_SIZE; - ComFprime::BufferManagerBins::bins.bins[1].numBuffers = ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE; + ComFprime::BufferManagerBins::bins.bins[0].bufferSize = ComFprimeConfig::BufferMgr::commsBufferStore; + ComFprime::BufferManagerBins::bins.bins[0].numBuffers = ComFprimeConfig::BufferMgr::commsBufferCount; + ComFprime::BufferManagerBins::bins.bins[1].bufferSize = ComFprimeConfig::BufferMgr::commsFileBufferStore; + ComFprime::BufferManagerBins::bins.bins[1].numBuffers = ComFprimeConfig::BufferMgr::commsFileBufferQueue; ComFprime::commsBufferManager.setup( - ConfigConstants::ComFprime_commsBufferManager::COMMS_BUFFER_MANAGER_ID, + ComFprimeConfig::BufferMgr::commsBufferManager, 0, ComFprime::Allocation::mallocator, ComFprime::BufferManagerBins::bins diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp index 6d17fe1c9c3..056d3eb810e 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp @@ -7,15 +7,40 @@ module ComFprimeConfig { constant cmdSeq = 10 } - module StackSizes { constant comQueue = 64 * 1024 constant cmdSeq = 64 * 1024 + constant comDriver = 100 } module Priorities { constant comQueue = 101 constant cmdSeq = 100 + constant comDriver = 100 + } + + # Queue configuration constants + module QueueDepths { + constant events = 100 # Event queue depth + constant tlm = 500 # Telemetry queue depth + constant file = 100 # File downlink queue depth + } + + module QueuePriorities { + constant events = 0 # Highest priority for events + constant tlm = 2 # Lower priority for telemetry + constant file = 1 # Medium priority for file transfers + } + + # Buffer management constants + module BufferMgr { + constant cmdSeqBuffer = 5 * 1024 # 5KB for command sequencer buffer + constant frameAccumulator = 2048 # 2KB frame accumulator buffer + constant commsBufferStore = 2048 # 2KB communications buffer store + constant commsFileBufferStore = 3000 # 3KB file buffer store + constant commsBufferCount = 20 # Number of comms buffers + constant commsFileBufferQueue = 30 # File queue buffer count + constant commsBufferManager = 200 # Buffer manager identifier } } @@ -34,7 +59,7 @@ module ComFprime { // Initialize socket client communication if and only if there is a valid specification if (state.hostname != nullptr && state.port != 0) { Os::TaskString name("ReceiveTask"); - ComFprime::comDriver.start(name, 100, 100); + ComFprime::comDriver.start(name, ComFprimeConfig::Priorities::comDriver, ComFprimeConfig::StackSizes::comDriver); } """ diff --git a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp index b64da4532cc..d36ff4ce6e8 100644 --- a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp @@ -4,6 +4,7 @@ #include #include #include +#include "Svc/Subtopologies/ComFprime/ComFprimeConfig/FppConstantsAc.hpp" namespace ComFprime { namespace Allocation { diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 142518c3002..540d13a67cf 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -36,21 +36,14 @@ module DataProducts{ # Passive Components # ---------------------------------------------------------------------- - instance dpBufferManager: Svc.BufferManager base id 0x4A00 \ + instance dpBufferManager: Svc.BufferManager base id DataProductsConfig.BASE_ID + 0x0400 \ { - phase Fpp.ToCpp.Phases.configConstants """ - enum { - DP_BUFFER_MANAGER_STORE_SIZE = 10000, - DP_BUFFER_MANAGER_STORE_COUNT = 10, - DP_BUFFER_MANAGER_ID = 300 - }; - """ phase Fpp.ToCpp.Phases.configComponents """ memset(&DataProducts::BufferManagerBins::bins, 0, sizeof(DataProducts::BufferManagerBins::bins)); - DataProducts::BufferManagerBins::bins.bins[0].bufferSize = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_SIZE; - DataProducts::BufferManagerBins::bins.bins[0].numBuffers = ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_STORE_COUNT; + DataProducts::BufferManagerBins::bins.bins[0].bufferSize = DataProductsConfig::BufferMgr::dpBufferStoreSize; + DataProducts::BufferManagerBins::bins.bins[0].numBuffers = DataProductsConfig::BufferMgr::dpBufferStoreCount; DataProducts::dpBufferManager.setup( - ConfigConstants::DataProducts_dpBufferManager::DP_BUFFER_MANAGER_ID, + DataProductsConfig::BufferMgr::dpBufferManagerId, 0, DataProducts::Allocation::mallocator, DataProducts::BufferManagerBins::bins diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp index baa2aba7aed..78e079d1046 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp @@ -23,4 +23,11 @@ module DataProductsConfig { constant dpWriter = 99 constant dpBufferManager = 98 } + + # Buffer management constants + module BufferMgr { + constant dpBufferStoreSize = 10000 # Data products buffer store size + constant dpBufferStoreCount = 10 # Number of data products buffers + constant dpBufferManagerId = 300 # Buffer manager identifier + } } \ No newline at end of file diff --git a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp index 0817532a3f3..ff14be62904 100644 --- a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp @@ -4,6 +4,7 @@ #include #include #include +#include "Svc/Subtopologies/DataProducts/DataProductsConfig/FppConstantsAc.hpp" namespace DataProducts { namespace Allocation { diff --git a/Svc/Subtopologies/FileHandling/CMakeLists.txt b/Svc/Subtopologies/FileHandling/CMakeLists.txt index 9c9988ffba3..043254a390d 100644 --- a/Svc/Subtopologies/FileHandling/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/CMakeLists.txt @@ -3,7 +3,9 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileHandlingConfig/") register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/FileHandling.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" HEADERS + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" - INTERFACE ) diff --git a/Svc/Subtopologies/FileHandling/FileHandling.fpp b/Svc/Subtopologies/FileHandling/FileHandling.fpp index de13eec2368..72e7d3c6391 100644 --- a/Svc/Subtopologies/FileHandling/FileHandling.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandling.fpp @@ -17,20 +17,12 @@ module FileHandling { stack size FileHandlingConfig.StackSizes.fileDownlink \ priority FileHandlingConfig.Priorities.fileDownlink \ { - phase Fpp.ToCpp.Phases.configConstants """ - enum { - FILE_DOWNLINK_TIMEOUT = 1000, - FILE_DOWNLINK_COOLDOWN = 1000, - FILE_DOWNLINK_CYCLE_TIME = 1000, - FILE_DOWNLINK_FILE_QUEUE_DEPTH = 10 - }; - """ phase Fpp.ToCpp.Phases.configComponents """ FileHandling::fileDownlink.configure( - ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_TIMEOUT, - ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_COOLDOWN, - ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_CYCLE_TIME, - ConfigConstants::FileHandling_fileDownlink::FILE_DOWNLINK_FILE_QUEUE_DEPTH + FileHandlingConfig::DownlinkConfig::timeout, + FileHandlingConfig::DownlinkConfig::cooldown, + FileHandlingConfig::DownlinkConfig::cycleTime, + FileHandlingConfig::DownlinkConfig::fileQueueDepth ); """ } diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp index b754e6c2150..e2cdeb054de 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/FileHandlingConfig.fpp @@ -9,7 +9,6 @@ module FileHandlingConfig { constant prmDb = 10 } - module StackSizes { constant fileUplink = 64 * 1024 constant fileDownlink = 64 * 1024 @@ -23,4 +22,12 @@ module FileHandlingConfig { constant fileManager = 99 constant prmDb = 98 } + + # File downlink configuration constants + module DownlinkConfig { + constant timeout = 1000 # File downlink timeout in ms + constant cooldown = 1000 # File downlink cooldown in ms + constant cycleTime = 1000 # File downlink cycle time in ms + constant fileQueueDepth = 10 # File downlink queue depth + } } diff --git a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp index a24f6761735..adc36798018 100644 --- a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp @@ -1,6 +1,7 @@ #ifndef FILEHANDLINGSUBTOPOLOGY_DEFS_HPP #define FILEHANDLINGSUBTOPOLOGY_DEFS_HPP +#include "Svc/Subtopologies/FileHandling/FileHandlingConfig/FppConstantsAc.hpp" namespace FileHandling { // State for topology construction struct TopologyState { From d35a7f8aa32e16955af5a722320cb3226cc43e5e Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 23 Jun 2025 13:44:03 -0700 Subject: [PATCH 46/52] register_fprime_config() in config modules, isolated ComDriver into a separate config fpp file --- .../CdhCore/CdhCoreConfig/CMakeLists.txt | 2 +- .../ComCcsds/ComCcsdsConfig/CMakeLists.txt | 1 + .../ComCcsdsComDriverConfig.fpp | 28 +++++++++++++++++ .../ComCcsdsConfig/ComCcsdsConfig.fpp | 31 +------------------ .../ComFprime/ComFprimeConfig/CMakeLists.txt | 3 +- .../ComFprimeComDriverConfig.fpp | 28 +++++++++++++++++ .../ComFprimeConfig/ComFprimeConfig.fpp | 29 ----------------- 7 files changed, 61 insertions(+), 61 deletions(-) create mode 100644 Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp create mode 100644 Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeComDriverConfig.fpp diff --git a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt index 28245922458..e348bf3bac2 100644 --- a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt @@ -1,4 +1,4 @@ -register_fprime_module( +register_fprime_config( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/CdhCoreConfig.fpp" INTERFACE diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt index 1eded39dc3d..def3faef3ce 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt @@ -1,5 +1,6 @@ register_fprime_config( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsComDriverConfig.fpp" INTERFACE ) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp new file mode 100644 index 00000000000..4df7640fbb2 --- /dev/null +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp @@ -0,0 +1,28 @@ +module ComCcsds { + # Communications driver. May be swapped out with other comm drivers like UART in this file + # to use another driver in the Comms Subtopology + instance comDriver: Drv.TcpClient base id ComCcsdsConfig.BASE_ID + 0x0B00 \ + { + phase Fpp.ToCpp.Phases.configComponents """ + if (state.hostname != nullptr && state.port != 0) { + ComCcsds::comDriver.configure(state.hostname, state.port); + } + """ + + phase Fpp.ToCpp.Phases.startTasks """ + // Initialize socket client communication if and only if there is a valid specification + if (state.hostname != nullptr && state.port != 0) { + Os::TaskString name("ReceiveTask"); + ComCcsds::comDriver.start(name, ComCcsdsConfig::Priorities::comDriver, ComCcsdsConfig::StackSizes::comDriver); + } + """ + + phase Fpp.ToCpp.Phases.stopTasks """ + ComCcsds::comDriver.stop(); + """ + + phase Fpp.ToCpp.Phases.freeThreads """ + (void)ComCcsds::comDriver.join(); + """ + } +} \ No newline at end of file diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp index 6403905d4ad..40165f87c94 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp @@ -42,33 +42,4 @@ module ComCcsdsConfig { constant commsFileBufferCount = 30 # File queue buffer count constant commsBufferManager = 200 # Buffer manager identifier } -} - -module ComCcsds { - # Communications driver. May be swapped out with other comm drivers like UART in this file - # to use another driver in the Comms Subtopology - instance comDriver: Drv.TcpClient base id ComCcsdsConfig.BASE_ID + 0x0B00 \ - { - phase Fpp.ToCpp.Phases.configComponents """ - if (state.hostname != nullptr && state.port != 0) { - ComCcsds::comDriver.configure(state.hostname, state.port); - } - """ - - phase Fpp.ToCpp.Phases.startTasks """ - // Initialize socket client communication if and only if there is a valid specification - if (state.hostname != nullptr && state.port != 0) { - Os::TaskString name("ReceiveTask"); - ComCcsds::comDriver.start(name, ComCcsdsConfig::Priorities::comDriver, ComCcsdsConfig::StackSizes::comDriver); - } - """ - - phase Fpp.ToCpp.Phases.stopTasks """ - ComCcsds::comDriver.stop(); - """ - - phase Fpp.ToCpp.Phases.freeThreads """ - (void)ComCcsds::comDriver.join(); - """ - } -} +} \ No newline at end of file diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt index 580d2af6de3..fd68703af9a 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt @@ -1,5 +1,6 @@ -register_fprime_module( +register_fprime_config( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComFprimeConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ComFprimeComDriverConfig.fpp" INTERFACE ) diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeComDriverConfig.fpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeComDriverConfig.fpp new file mode 100644 index 00000000000..b51721b7ff2 --- /dev/null +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeComDriverConfig.fpp @@ -0,0 +1,28 @@ +module ComFprime { + # Communications driver. May be swapped out with other comm drivers like UART in this file + # to use another driver in the Comms Subtopology + instance comDriver: Drv.TcpClient base id ComFprimeConfig.BASE_ID + 0x0B00 \ + { + phase Fpp.ToCpp.Phases.configComponents """ + if (state.hostname != nullptr && state.port != 0) { + ComFprime::comDriver.configure(state.hostname, state.port); + } + """ + + phase Fpp.ToCpp.Phases.startTasks """ + // Initialize socket client communication if and only if there is a valid specification + if (state.hostname != nullptr && state.port != 0) { + Os::TaskString name("ReceiveTask"); + ComFprime::comDriver.start(name, ComFprimeConfig::Priorities::comDriver, ComFprimeConfig::StackSizes::comDriver); + } + """ + + phase Fpp.ToCpp.Phases.stopTasks """ + ComFprime::comDriver.stop(); + """ + + phase Fpp.ToCpp.Phases.freeThreads """ + (void)ComFprime::comDriver.join(); + """ + } +} diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp index 056d3eb810e..f1a45d2fb3d 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp @@ -43,32 +43,3 @@ module ComFprimeConfig { constant commsBufferManager = 200 # Buffer manager identifier } } - -module ComFprime { - # Communications driver. May be swapped out with other comm drivers like UART in this file - # to use another driver in the Comms Subtopology - instance comDriver: Drv.TcpClient base id ComFprimeConfig.BASE_ID + 0x0B00 \ - { - phase Fpp.ToCpp.Phases.configComponents """ - if (state.hostname != nullptr && state.port != 0) { - ComFprime::comDriver.configure(state.hostname, state.port); - } - """ - - phase Fpp.ToCpp.Phases.startTasks """ - // Initialize socket client communication if and only if there is a valid specification - if (state.hostname != nullptr && state.port != 0) { - Os::TaskString name("ReceiveTask"); - ComFprime::comDriver.start(name, ComFprimeConfig::Priorities::comDriver, ComFprimeConfig::StackSizes::comDriver); - } - """ - - phase Fpp.ToCpp.Phases.stopTasks """ - ComFprime::comDriver.stop(); - """ - - phase Fpp.ToCpp.Phases.freeThreads """ - (void)ComFprime::comDriver.join(); - """ - } -} \ No newline at end of file From 6b96feae27f19cb1679f0a5244addca7425c7f8a Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Mon, 23 Jun 2025 14:25:27 -0700 Subject: [PATCH 47/52] Added explicit CMake Module Names and Depends between Subtopologies and their Configs --- Svc/Subtopologies/CdhCore/CMakeLists.txt | 2 ++ .../CdhCore/CdhCoreConfig/CMakeLists.txt | 3 ++ .../CdhCore/CdhCoreConfig/CdhCoreConfig.fpp | 30 ------------------- .../CdhCoreFatalHandlerConfig.fpp | 6 ++++ .../CdhCoreConfig/CdhCoreTlmConfig.fpp | 24 +++++++++++++++ Svc/Subtopologies/ComCcsds/CMakeLists.txt | 2 ++ .../ComCcsds/ComCcsdsConfig/CMakeLists.txt | 1 + Svc/Subtopologies/ComFprime/CMakeLists.txt | 2 ++ .../ComFprime/ComFprimeConfig/CMakeLists.txt | 1 + Svc/Subtopologies/DataProducts/CMakeLists.txt | 2 ++ .../DataProductsConfig/CMakeLists.txt | 1 + Svc/Subtopologies/FileHandling/CMakeLists.txt | 5 ++-- .../FileHandlingConfig/CMakeLists.txt | 1 + .../FileHandling/SubtopologyTopologyDefs.cpp | 5 ---- .../FileHandling/SubtopologyTopologyDefs.hpp | 2 -- 15 files changed, 48 insertions(+), 39 deletions(-) create mode 100644 Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreFatalHandlerConfig.fpp create mode 100644 Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreTlmConfig.fpp delete mode 100644 Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp diff --git a/Svc/Subtopologies/CdhCore/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CMakeLists.txt index 4dff3feba88..32bbf8d5da9 100644 --- a/Svc/Subtopologies/CdhCore/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CMakeLists.txt @@ -6,4 +6,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE + DEPENDS + CdhCoreConfig ) \ No newline at end of file diff --git a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt index e348bf3bac2..a66d0fe5941 100644 --- a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt @@ -1,5 +1,8 @@ register_fprime_config( + CdhCoreConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/CdhCoreConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/CdhCoreFatalHandlerConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/CdhCoreTlmConfig.fpp" INTERFACE ) \ No newline at end of file diff --git a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreConfig.fpp b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreConfig.fpp index fc6d10fe972..43191eaffaf 100644 --- a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreConfig.fpp +++ b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreConfig.fpp @@ -24,33 +24,3 @@ module CdhCoreConfig { } } - - -module CdhCore { - - instance tlmSend: Svc.TlmChan base id CdhCoreConfig.BASE_ID + 0x0700 \ - queue size CdhCoreConfig.QueueSizes.tlmSend \ - stack size CdhCoreConfig.StackSizes.tlmSend \ - priority CdhCoreConfig.Priorities.tlmSend \ - - # Uncomment the following block and comment the above block to use TlmPacketizer instead of TlmChan - #instance tlmSend: Svc.TlmPacketizer base id CdhCoreConfig.BASE_ID + 0x0700 \ - # queue size CdhCoreConfig.QueueSizes.tlmSend \ - # stack size CdhCoreConfig.StackSizes.tlmSend \ - # priority CdhCoreConfig.Priorities.tlmSend \ - #{ - # # NOTE: The Name Ref is specific to the Reference deployment, Ref - # # This name will need to be updated if wishing to use this in a custom deployment - # phase Fpp.ToCpp.Phases.configComponents """ - # CdhCore::tlmSend.setPacketList( - # Ref::Ref_RefPacketsTlmPackets::packetList, - # Ref::Ref_RefPacketsTlmPackets::omittedChannels, - # 1 - # ); - # """ - #} - - # Update this as a custom fatal handler if needed - instance fatalHandler: Svc.FatalHandler base id CdhCoreConfig.BASE_ID + 0x0800 - -} \ No newline at end of file diff --git a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreFatalHandlerConfig.fpp b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreFatalHandlerConfig.fpp new file mode 100644 index 00000000000..76a0df61625 --- /dev/null +++ b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreFatalHandlerConfig.fpp @@ -0,0 +1,6 @@ +module CdhCore { + + # Update this as a custom fatal handler if needed + instance fatalHandler: Svc.FatalHandler base id CdhCoreConfig.BASE_ID + 0x0800 + +} diff --git a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreTlmConfig.fpp b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreTlmConfig.fpp new file mode 100644 index 00000000000..30b2ba36b75 --- /dev/null +++ b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CdhCoreTlmConfig.fpp @@ -0,0 +1,24 @@ +module CdhCore{ + + instance tlmSend: Svc.TlmChan base id CdhCoreConfig.BASE_ID + 0x0700 \ + queue size CdhCoreConfig.QueueSizes.tlmSend \ + stack size CdhCoreConfig.StackSizes.tlmSend \ + priority CdhCoreConfig.Priorities.tlmSend \ + + # Uncomment the following block and comment the above block to use TlmPacketizer instead of TlmChan + #instance tlmSend: Svc.TlmPacketizer base id CdhCoreConfig.BASE_ID + 0x0700 \ + # queue size CdhCoreConfig.QueueSizes.tlmSend \ + # stack size CdhCoreConfig.StackSizes.tlmSend \ + # priority CdhCoreConfig.Priorities.tlmSend \ + #{ + # # NOTE: The Name Ref is specific to the Reference deployment, Ref + # # This name will need to be updated if wishing to use this in a custom deployment + # phase Fpp.ToCpp.Phases.configComponents """ + # CdhCore::tlmSend.setPacketList( + # Ref::Ref_RefPacketsTlmPackets::packetList, + # Ref::Ref_RefPacketsTlmPackets::omittedChannels, + # 1 + # ); + # """ + #} +} diff --git a/Svc/Subtopologies/ComCcsds/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/CMakeLists.txt index 19f4260efd5..11c5e2430bd 100644 --- a/Svc/Subtopologies/ComCcsds/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/CMakeLists.txt @@ -8,4 +8,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + DEPENDS + ComCcsdsConfig ) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt index def3faef3ce..04889fa90f7 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt @@ -1,4 +1,5 @@ register_fprime_config( + ComCcsdsConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsComDriverConfig.fpp" diff --git a/Svc/Subtopologies/ComFprime/CMakeLists.txt b/Svc/Subtopologies/ComFprime/CMakeLists.txt index 04d895e6e0d..a28d476f93e 100644 --- a/Svc/Subtopologies/ComFprime/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/CMakeLists.txt @@ -8,4 +8,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + DEPENDS + ComFprimeConfig ) diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt index fd68703af9a..b892952fbfc 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt @@ -1,4 +1,5 @@ register_fprime_config( + ComFprimeConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComFprimeConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/ComFprimeComDriverConfig.fpp" diff --git a/Svc/Subtopologies/DataProducts/CMakeLists.txt b/Svc/Subtopologies/DataProducts/CMakeLists.txt index bf9142ec8b0..5266b7f4d58 100644 --- a/Svc/Subtopologies/DataProducts/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/CMakeLists.txt @@ -8,4 +8,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + DEPENDS + DataProductsConfig ) diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt index f704c7bac96..ca5fba9c1cf 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt @@ -1,4 +1,5 @@ register_fprime_config( + DataProductsConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig.fpp" INTERFACE diff --git a/Svc/Subtopologies/FileHandling/CMakeLists.txt b/Svc/Subtopologies/FileHandling/CMakeLists.txt index 043254a390d..0fd4ab96f8a 100644 --- a/Svc/Subtopologies/FileHandling/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/CMakeLists.txt @@ -3,9 +3,10 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileHandlingConfig/") register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/FileHandling.fpp" - SOURCES - "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + INTERFACE + DEPENDS + FileHandlingConfig ) diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt b/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt index c1bd7b8e64b..3c5cf6b14ad 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt @@ -1,4 +1,5 @@ register_fprime_config( + FileHandlingConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/FileHandlingConfig.fpp" INTERFACE diff --git a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp deleted file mode 100644 index d2f276afd92..00000000000 --- a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "SubtopologyTopologyDefs.hpp" - -namespace FileHandling { - // Implementation for FileHandling subtopology -} diff --git a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp index adc36798018..cd779bd61b3 100644 --- a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp @@ -4,8 +4,6 @@ #include "Svc/Subtopologies/FileHandling/FileHandlingConfig/FppConstantsAc.hpp" namespace FileHandling { // State for topology construction - struct TopologyState { - }; } #endif From 71dda8fd0def7b49dd490e3a084b3b727e991082 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Tue, 24 Jun 2025 16:16:53 -0700 Subject: [PATCH 48/52] Fixed CCSDS case, more config constants --- Svc/Subtopologies/CdhCore/CMakeLists.txt | 2 -- Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt | 1 - Svc/Subtopologies/ComCcsds/CMakeLists.txt | 2 -- Svc/Subtopologies/ComCcsds/ComCcsds.fpp | 10 +++++----- Svc/Subtopologies/ComFprime/CMakeLists.txt | 2 -- Svc/Subtopologies/DataProducts/CMakeLists.txt | 2 -- Svc/Subtopologies/DataProducts/DataProducts.fpp | 4 ++-- .../DataProducts/DataProductsConfig/CMakeLists.txt | 1 - .../DataProductsConfig/DataProductsConfig.fpp | 6 ++++++ Svc/Subtopologies/FileHandling/CMakeLists.txt | 2 -- 10 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Svc/Subtopologies/CdhCore/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CMakeLists.txt index 32bbf8d5da9..4dff3feba88 100644 --- a/Svc/Subtopologies/CdhCore/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CMakeLists.txt @@ -6,6 +6,4 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE - DEPENDS - CdhCoreConfig ) \ No newline at end of file diff --git a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt index a66d0fe5941..d6aca02a24f 100644 --- a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt @@ -1,5 +1,4 @@ register_fprime_config( - CdhCoreConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/CdhCoreConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/CdhCoreFatalHandlerConfig.fpp" diff --git a/Svc/Subtopologies/ComCcsds/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/CMakeLists.txt index 11c5e2430bd..19f4260efd5 100644 --- a/Svc/Subtopologies/ComCcsds/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/CMakeLists.txt @@ -8,6 +8,4 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" - DEPENDS - ComCcsdsConfig ) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 01b9fe0a431..315fc5c5e64 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -105,15 +105,15 @@ module ComCcsds { instance comStub: Svc.ComStub base id ComCcsdsConfig.BASE_ID + 0x0800 \ - instance tcDeframer: Svc.CCSDS.TcDeframer base id ComCcsdsConfig.BASE_ID + 0x0900 \ + instance tcDeframer: Svc.Ccsds.TcDeframer base id ComCcsdsConfig.BASE_ID + 0x0900 \ - instance spacePacketDeframer: Svc.CCSDS.SpacePacketDeframer base id ComCcsdsConfig.BASE_ID + 0x0A00 \ + instance spacePacketDeframer: Svc.Ccsds.SpacePacketDeframer base id ComCcsdsConfig.BASE_ID + 0x0A00 \ - instance tmFramer: Svc.CCSDS.TmFramer base id ComCcsdsConfig.BASE_ID + 0x0B00 \ + instance tmFramer: Svc.Ccsds.TmFramer base id ComCcsdsConfig.BASE_ID + 0x0B00 \ - instance spacePacketFramer: Svc.CCSDS.SpacePacketFramer base id ComCcsdsConfig.BASE_ID + 0x0C00 \ + instance spacePacketFramer: Svc.Ccsds.SpacePacketFramer base id ComCcsdsConfig.BASE_ID + 0x0C00 \ - instance apidManager: Svc.CCSDS.ApidManager base id ComCcsdsConfig.BASE_ID + 0x0D00 \ + instance apidManager: Svc.Ccsds.ApidManager base id ComCcsdsConfig.BASE_ID + 0x0D00 \ topology Subtopology { # Active Components diff --git a/Svc/Subtopologies/ComFprime/CMakeLists.txt b/Svc/Subtopologies/ComFprime/CMakeLists.txt index a28d476f93e..04d895e6e0d 100644 --- a/Svc/Subtopologies/ComFprime/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/CMakeLists.txt @@ -8,6 +8,4 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" - DEPENDS - ComFprimeConfig ) diff --git a/Svc/Subtopologies/DataProducts/CMakeLists.txt b/Svc/Subtopologies/DataProducts/CMakeLists.txt index 5266b7f4d58..bf9142ec8b0 100644 --- a/Svc/Subtopologies/DataProducts/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/CMakeLists.txt @@ -8,6 +8,4 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" - DEPENDS - DataProductsConfig ) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 540d13a67cf..5d5d7e6e68f 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -10,8 +10,8 @@ module DataProducts{ priority DataProductsConfig.Priorities.dpCat \ { phase Fpp.ToCpp.Phases.configComponents """ - Fw::FileNameString dpDir("./DpCat"); - Fw::FileNameString dpState("./DpCat/DpState.dat"); + Fw::FileNameString dpDir(DataProductsConfig::Paths::DP_DIR); + Fw::FileNameString dpState(DataProductsConfig::Paths::DP_STATE); Os::FileSystem::createDirectory(dpDir.toChar()); DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::mallocator); """ diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt index ca5fba9c1cf..f55917b6183 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt @@ -2,5 +2,4 @@ register_fprime_config( DataProductsConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig.fpp" - INTERFACE ) diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp index 78e079d1046..85c592e39bd 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp @@ -30,4 +30,10 @@ module DataProductsConfig { constant dpBufferStoreCount = 10 # Number of data products buffers constant dpBufferManagerId = 300 # Buffer manager identifier } + + # Directory and file paths + module Paths { + constant DP_DIR = "./DpCat" # Data products directory + constant DP_STATE = "./DpCat/DpState.dat" # Data products state file + } } \ No newline at end of file diff --git a/Svc/Subtopologies/FileHandling/CMakeLists.txt b/Svc/Subtopologies/FileHandling/CMakeLists.txt index 0fd4ab96f8a..9d934c5af63 100644 --- a/Svc/Subtopologies/FileHandling/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/CMakeLists.txt @@ -7,6 +7,4 @@ register_fprime_module( "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE - DEPENDS - FileHandlingConfig ) From de21d776450c6d10cff1b36b6a1147b35f55cdb6 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Wed, 25 Jun 2025 14:59:54 -0700 Subject: [PATCH 49/52] Added explicit depends for each subtopology config --- Svc/Subtopologies/CdhCore/CMakeLists.txt | 2 ++ Svc/Subtopologies/ComCcsds/CMakeLists.txt | 2 ++ Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt | 1 - Svc/Subtopologies/ComFprime/CMakeLists.txt | 2 ++ Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt | 1 - Svc/Subtopologies/DataProducts/CMakeLists.txt | 2 ++ .../DataProducts/DataProductsConfig/CMakeLists.txt | 3 ++- Svc/Subtopologies/FileHandling/CMakeLists.txt | 2 ++ .../FileHandling/FileHandlingConfig/CMakeLists.txt | 1 - 9 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Svc/Subtopologies/CdhCore/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CMakeLists.txt index 4dff3feba88..bed12149b8a 100644 --- a/Svc/Subtopologies/CdhCore/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CMakeLists.txt @@ -6,4 +6,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE + DEPENDS + Svc_Subtopologies_CdhCore_CdhCoreConfig ) \ No newline at end of file diff --git a/Svc/Subtopologies/ComCcsds/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/CMakeLists.txt index 19f4260efd5..f4c20e68961 100644 --- a/Svc/Subtopologies/ComCcsds/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/CMakeLists.txt @@ -8,4 +8,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + DEPENDS + Svc_Subtopologies_ComCcsds_ComCcsdsConfig ) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt index 04889fa90f7..def3faef3ce 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt @@ -1,5 +1,4 @@ register_fprime_config( - ComCcsdsConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsComDriverConfig.fpp" diff --git a/Svc/Subtopologies/ComFprime/CMakeLists.txt b/Svc/Subtopologies/ComFprime/CMakeLists.txt index 04d895e6e0d..abbc11f7c3b 100644 --- a/Svc/Subtopologies/ComFprime/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/CMakeLists.txt @@ -8,4 +8,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + DEPENDS + Svc_Subtopologies_ComFprime_ComFprimeConfig ) diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt index b892952fbfc..fd68703af9a 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt @@ -1,5 +1,4 @@ register_fprime_config( - ComFprimeConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComFprimeConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/ComFprimeComDriverConfig.fpp" diff --git a/Svc/Subtopologies/DataProducts/CMakeLists.txt b/Svc/Subtopologies/DataProducts/CMakeLists.txt index bf9142ec8b0..3bf8bff897b 100644 --- a/Svc/Subtopologies/DataProducts/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/CMakeLists.txt @@ -8,4 +8,6 @@ register_fprime_module( HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + DEPENDS + Svc_Subtopologies_DataProducts_DataProductsConfig ) diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt index f55917b6183..092b35e1e99 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt @@ -1,5 +1,6 @@ register_fprime_config( - DataProductsConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig.fpp" + DEPENDS + Fw_Types ) diff --git a/Svc/Subtopologies/FileHandling/CMakeLists.txt b/Svc/Subtopologies/FileHandling/CMakeLists.txt index 9d934c5af63..3e024505a4b 100644 --- a/Svc/Subtopologies/FileHandling/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/CMakeLists.txt @@ -7,4 +7,6 @@ register_fprime_module( "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" INTERFACE + DEPENDS + Svc_Subtopologies_FileHandling_FileHandlingConfig ) diff --git a/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt b/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt index 3c5cf6b14ad..c1bd7b8e64b 100644 --- a/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt +++ b/Svc/Subtopologies/FileHandling/FileHandlingConfig/CMakeLists.txt @@ -1,5 +1,4 @@ register_fprime_config( - FileHandlingConfig AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/FileHandlingConfig.fpp" INTERFACE From eea963daf7617cff52d6dcee3541161597a2ec14 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 26 Jun 2025 10:02:30 -0700 Subject: [PATCH 50/52] added mallocator config, subtopology state structure --- Ref/Main.cpp | 4 +-- Ref/Top/RefTopologyDefs.hpp | 3 +- Svc/Subtopologies/ComCcsds/CMakeLists.txt | 3 +- Svc/Subtopologies/ComCcsds/ComCcsds.fpp | 32 +++++++++++-------- .../ComCcsds/ComCcsdsConfig/CMakeLists.txt | 7 +++- .../ComCcsdsComDriverConfig.fpp | 6 ++-- .../ComCcsdsSubtopologyConfig.cpp | 9 ++++++ .../ComCcsdsSubtopologyConfig.hpp | 12 +++++++ .../ComCcsds/SubtopologyTopologyDefs.cpp | 15 --------- .../ComCcsds/SubtopologyTopologyDefs.hpp | 25 ++++----------- Svc/Subtopologies/ComFprime/CMakeLists.txt | 3 +- Svc/Subtopologies/ComFprime/ComFprime.fpp | 10 +++--- .../ComFprime/ComFprimeConfig/CMakeLists.txt | 5 ++- .../ComFprimeSubtopologyConfig.cpp | 9 ++++++ .../ComFprimeSubtopologyConfig.hpp | 12 +++++++ .../ComFprime/SubtopologyTopologyDefs.cpp | 15 --------- .../ComFprime/SubtopologyTopologyDefs.hpp | 23 +++---------- Svc/Subtopologies/DataProducts/CMakeLists.txt | 3 +- .../DataProducts/DataProducts.fpp | 15 +++++---- .../DataProductsConfig/CMakeLists.txt | 4 +++ .../DataProductsSubtopologyConfig.cpp | 9 ++++++ .../DataProductsSubtopologyConfig.hpp | 12 +++++++ .../DataProducts/SubtopologyTopologyDefs.cpp | 11 ------- .../DataProducts/SubtopologyTopologyDefs.hpp | 11 +------ .../FileHandling/SubtopologyTopologyDefs.hpp | 2 ++ 25 files changed, 133 insertions(+), 127 deletions(-) create mode 100644 Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.cpp create mode 100644 Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp delete mode 100644 Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.cpp create mode 100644 Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.cpp create mode 100644 Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp delete mode 100644 Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp create mode 100644 Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.cpp create mode 100644 Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp delete mode 100644 Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp diff --git a/Ref/Main.cpp b/Ref/Main.cpp index 1b41c76a9f7..500c317ebed 100644 --- a/Ref/Main.cpp +++ b/Ref/Main.cpp @@ -82,8 +82,8 @@ int main(int argc, char* argv[]) { } // Object for communicating state to the reference topology Ref::TopologyState inputs; - inputs.hostname = hostname; - inputs.port = port_number; + inputs.comCcsds.hostname = hostname; + inputs.comCcsds.port = port_number; // Setup program shutdown via Ctrl-C signal(SIGINT, signalHandler); diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 945f78d55bc..2a146c15dd1 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -66,8 +66,7 @@ namespace Ref { * fields, which are derived by command line inputs. */ struct TopologyState { - const char* hostname; - U16 port; + ComCcsds::SubtopologyState comCcsds; //!< Subtopology state for ComCcsds }; namespace PingEntries = ::PingEntries; diff --git a/Svc/Subtopologies/ComCcsds/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/CMakeLists.txt index f4c20e68961..e1e0e6715ce 100644 --- a/Svc/Subtopologies/ComCcsds/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/CMakeLists.txt @@ -3,11 +3,10 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig/") register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComCcsds.fpp" - SOURCES - "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" DEPENDS Svc_Subtopologies_ComCcsds_ComCcsdsConfig + INTERFACE ) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 315fc5c5e64..39b6946975c 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -38,7 +38,7 @@ module ComCcsds { configurationTable.entries[ConfigConstants::ComCcsds_comQueue::FILE_QUEUE].priority = ComCcsdsConfig::QueuePriorities::file; // Allocation identifier is 0 as the MallocAllocator discards it - ComCcsds::comQueue.configure(configurationTable, 0, ComCcsds::Allocation::mallocator); + ComCcsds::comQueue.configure(configurationTable, 0, ComCcsds::Allocation::memAllocator); """ phase Fpp.ToCpp.Phases.tearDownComponents """ ComCcsds::comQueue.cleanup(); @@ -51,11 +51,11 @@ module ComCcsds { priority ComCcsdsConfig.Priorities.cmdSeq \ { phase Fpp.ToCpp.Phases.configComponents """ - ComCcsds::cmdSeq.allocateBuffer(0, ComCcsds::Allocation::mallocator, ComCcsdsConfig::BufferMgr::cmdSeqBuffer); + ComCcsds::cmdSeq.allocateBuffer(0, ComCcsds::Allocation::memAllocator, ComCcsdsConfig::BufferMgr::cmdSeqBuffer); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - ComCcsds::cmdSeq.deallocateBuffer(ComCcsds::Allocation::mallocator); + ComCcsds::cmdSeq.deallocateBuffer(ComCcsds::Allocation::memAllocator); """ } @@ -65,11 +65,14 @@ module ComCcsds { instance frameAccumulator: Svc.FrameAccumulator base id ComCcsdsConfig.BASE_ID + 0x0500 \ { + phase Fpp.ToCpp.Phases.configObjects """ + Svc::FrameDetectors::CcsdsTcFrameDetector frameDetector; + """ phase Fpp.ToCpp.Phases.configComponents """ ComCcsds::frameAccumulator.configure( - ComCcsds::Detector::frameDetector, + ConfigObjects::ComCcsds_frameAccumulator::frameDetector, 1, - ComCcsds::Allocation::mallocator, + ComCcsds::Allocation::memAllocator, ComCcsdsConfig::BufferMgr::frameAccumulator ); """ @@ -81,18 +84,21 @@ module ComCcsds { instance commsBufferManager: Svc.BufferManager base id ComCcsdsConfig.BASE_ID + 0x0600 \ { + phase Fpp.ToCpp.Phases.configObjects """ + Svc::BufferManager::BufferBins bins; + """ + phase Fpp.ToCpp.Phases.configComponents """ - // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. - memset(&ComCcsds::BufferManagerBins::bins, 0, sizeof(ComCcsds::BufferManagerBins::bins)); - ComCcsds::BufferManagerBins::bins.bins[0].bufferSize = ComCcsdsConfig::BufferMgr::commsBufferStore; - ComCcsds::BufferManagerBins::bins.bins[0].numBuffers = ComCcsdsConfig::BufferMgr::commsBufferCount; - ComCcsds::BufferManagerBins::bins.bins[1].bufferSize = ComCcsdsConfig::BufferMgr::commsFileBufferStore; - ComCcsds::BufferManagerBins::bins.bins[1].numBuffers = ComCcsdsConfig::BufferMgr::commsFileBufferCount; + memset(&ConfigObjects::ComCcsds_commsBufferManager::bins, 0, sizeof(ConfigObjects::ComCcsds_commsBufferManager::bins)); + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[0].bufferSize = ComCcsdsConfig::BufferMgr::commsBufferStore; + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[0].numBuffers = ComCcsdsConfig::BufferMgr::commsBufferCount; + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[1].bufferSize = ComCcsdsConfig::BufferMgr::commsFileBufferStore; + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[1].numBuffers = ComCcsdsConfig::BufferMgr::commsFileBufferCount; ComCcsds::commsBufferManager.setup( ComCcsdsConfig::BufferMgr::commsBufferManager, 0, - ComCcsds::Allocation::mallocator, - ComCcsds::BufferManagerBins::bins + ComCcsds::Allocation::memAllocator, + ConfigObjects::ComCcsds_commsBufferManager::bins ); """ diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt index def3faef3ce..81a1eb79a0a 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/CMakeLists.txt @@ -1,6 +1,11 @@ register_fprime_config( + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsSubtopologyConfig.cpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsSubtopologyConfig.hpp" AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsComDriverConfig.fpp" - INTERFACE + DEPENDS + Fw_Types ) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp index 4df7640fbb2..f9f586d2cd1 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp @@ -4,14 +4,14 @@ module ComCcsds { instance comDriver: Drv.TcpClient base id ComCcsdsConfig.BASE_ID + 0x0B00 \ { phase Fpp.ToCpp.Phases.configComponents """ - if (state.hostname != nullptr && state.port != 0) { - ComCcsds::comDriver.configure(state.hostname, state.port); + if (state.comCcsds.hostname != nullptr && state.comCcsds.port != 0) { + ComCcsds::comDriver.configure(state.comCcsds.hostname, state.comCcsds.port); } """ phase Fpp.ToCpp.Phases.startTasks """ // Initialize socket client communication if and only if there is a valid specification - if (state.hostname != nullptr && state.port != 0) { + if (state.comCcsds.hostname != nullptr && state.comCcsds.port != 0) { Os::TaskString name("ReceiveTask"); ComCcsds::comDriver.start(name, ComCcsdsConfig::Priorities::comDriver, ComCcsdsConfig::StackSizes::comDriver); } diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.cpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.cpp new file mode 100644 index 00000000000..769b4dc9d6e --- /dev/null +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.cpp @@ -0,0 +1,9 @@ +#include "ComCcsdsSubtopologyConfig.hpp" + +namespace ComCcsds{ + namespace Allocation{ + //This instance can be changed to use a different allocator in the ComCcsds Subtopology + Fw::MallocAllocator mallocatorInstance; + Fw::MemAllocator& memAllocator = mallocatorInstance; + } +} diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp new file mode 100644 index 00000000000..eb55b53d9f4 --- /dev/null +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp @@ -0,0 +1,12 @@ +#ifndef COMCCSDSSUBTOPOLOGY_CONFIG_HPP +#define COMCCSDSSUBTOPOLOGY_CONFIG_HPP + +#include "Fw/Types/MallocAllocator.hpp" + +namespace ComCcsds { + namespace Allocation { + extern Fw::MemAllocator& memAllocator; + } +} + +#endif \ No newline at end of file diff --git a/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.cpp deleted file mode 100644 index 14d94d6cf7e..00000000000 --- a/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "SubtopologyTopologyDefs.hpp" - -namespace ComCcsds { - namespace Allocation { - Fw::MallocAllocator mallocator; - } - - namespace BufferManagerBins { - Svc::BufferManager::BufferBins bins; - } - - namespace Detector { - Svc::FrameDetectors::CcsdsTcFrameDetector frameDetector; - } -} diff --git a/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp index 6cb3fb878eb..8df71f76c5b 100644 --- a/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp @@ -5,30 +5,17 @@ #include #include #include "Svc/Subtopologies/ComCcsds/ComCcsdsConfig/FppConstantsAc.hpp" +#include "ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp" namespace ComCcsds { - namespace Allocation { - // Malloc allocator for topology construction - extern Fw::MallocAllocator mallocator; - } - - namespace BufferManagerBins { - // Buffer manager bins for ComCcsds - extern Svc::BufferManager::BufferBins bins; - } - - namespace Detector { - // The subtopology uses the CCSDS packet protocol when communicating with the ground and therefore uses the CCSDS - // framing and deframing implementations. - extern Svc::FrameDetectors::CcsdsTcFrameDetector frameDetector; - } + struct SubtopologyState { + const char* hostname; + U16 port; + }; - // State for topology construction struct TopologyState { - const char* hostname; - U16 port; + SubtopologyState comCcsds; }; - } #endif diff --git a/Svc/Subtopologies/ComFprime/CMakeLists.txt b/Svc/Subtopologies/ComFprime/CMakeLists.txt index abbc11f7c3b..3065da507c7 100644 --- a/Svc/Subtopologies/ComFprime/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/CMakeLists.txt @@ -3,11 +3,10 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComFprimeConfig/") register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComFprime.fpp" - SOURCES - "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" DEPENDS Svc_Subtopologies_ComFprime_ComFprimeConfig + INTERFACE ) diff --git a/Svc/Subtopologies/ComFprime/ComFprime.fpp b/Svc/Subtopologies/ComFprime/ComFprime.fpp index f779b129d4a..acba6a7d5e0 100644 --- a/Svc/Subtopologies/ComFprime/ComFprime.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprime.fpp @@ -33,7 +33,7 @@ module ComFprime { configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].depth = ComFprimeConfig::QueueDepths::file; configurationTable.entries[ConfigConstants::ComFprime_comQueue::FILE_QUEUE].priority = ComFprimeConfig::QueuePriorities::file; // Allocation identifier is 0 as the MallocAllocator discards it - ComFprime::comQueue.configure(configurationTable, 0, ComFprime::Allocation::mallocator); + ComFprime::comQueue.configure(configurationTable, 0, ComFprime::Allocation::memAllocator); """ } @@ -43,11 +43,11 @@ module ComFprime { priority ComFprimeConfig.Priorities.cmdSeq \ { phase Fpp.ToCpp.Phases.configComponents """ - ComFprime::cmdSeq.allocateBuffer(0, ComFprime::Allocation::mallocator, ComFprimeConfig::BufferMgr::cmdSeqBuffer); + ComFprime::cmdSeq.allocateBuffer(0, ComFprime::Allocation::memAllocator, ComFprimeConfig::BufferMgr::cmdSeqBuffer); """ phase Fpp.ToCpp.Phases.tearDownComponents """ - ComFprime::cmdSeq.deallocateBuffer(ComFprime::Allocation::mallocator); + ComFprime::cmdSeq.deallocateBuffer(ComFprime::Allocation::memAllocator); """ } @@ -61,7 +61,7 @@ module ComFprime { ComFprime::frameAccumulator.configure( ComFprime::Detector::frameDetector, 1, - ComFprime::Allocation::mallocator, + ComFprime::Allocation::memAllocator, ComFprimeConfig::BufferMgr::frameAccumulator ); """ @@ -82,7 +82,7 @@ module ComFprime { ComFprime::commsBufferManager.setup( ComFprimeConfig::BufferMgr::commsBufferManager, 0, - ComFprime::Allocation::mallocator, + ComFprime::Allocation::memAllocator, ComFprime::BufferManagerBins::bins ); """ diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt index fd68703af9a..5661ffde58b 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/CMakeLists.txt @@ -1,6 +1,9 @@ register_fprime_config( + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/ComFprimeSubtopologyConfig.cpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/ComFprimeSubtopologyConfig.hpp" AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/ComFprimeConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/ComFprimeComDriverConfig.fpp" - INTERFACE ) diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.cpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.cpp new file mode 100644 index 00000000000..c3be3fa3b00 --- /dev/null +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.cpp @@ -0,0 +1,9 @@ +#include "ComFprimeSubtopologyConfig.hpp" + +namespace ComFprime { + namespace Allocation{ + //This instance can be changed to use a different allocator in the ComFprime Subtopology + Fw::MallocAllocator mallocatorInstance; + Fw::MemAllocator& memAllocator = mallocatorInstance; + } +} diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp new file mode 100644 index 00000000000..ba383be3ede --- /dev/null +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp @@ -0,0 +1,12 @@ +#ifndef COMFPRIMESUBTOPOLOGY_CONFIG_HPP +#define COMFPRIMESUBTOPOLOGY_CONFIG_HPP + +#include "Fw/Types/MallocAllocator.hpp" + +namespace ComFprime { + namespace Allocation { + extern Fw::MemAllocator& memAllocator; + } +} + +#endif \ No newline at end of file diff --git a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp deleted file mode 100644 index 2d409e9afae..00000000000 --- a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "SubtopologyTopologyDefs.hpp" - -namespace ComFprime { - namespace Allocation { - Fw::MallocAllocator mallocator; - } - - namespace BufferManagerBins { - Svc::BufferManager::BufferBins bins; - } - - namespace Detector { - Svc::FrameDetectors::FprimeFrameDetector frameDetector; - } -} diff --git a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp index d36ff4ce6e8..5d0c173e8fd 100644 --- a/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/ComFprime/SubtopologyTopologyDefs.hpp @@ -5,29 +5,16 @@ #include #include #include "Svc/Subtopologies/ComFprime/ComFprimeConfig/FppConstantsAc.hpp" +#include "ComFprimeConfig/ComFprimeSubtopologyConfig.hpp" namespace ComFprime { - namespace Allocation { - // Malloc allocator for topology construction - extern Fw::MallocAllocator mallocator; - } - - namespace BufferManagerBins { - // Buffer manager bins for ComFprime - extern Svc::BufferManager::BufferBins bins; - } - - namespace Detector { - // Frame detector for ComFprime - extern Svc::FrameDetectors::FprimeFrameDetector frameDetector; - } - - // State for topology construction - struct TopologyState { + struct SubtopologyState { const char* hostname; U16 port; }; + struct TopologyState { + SubtopologyState comFprime; + }; } - #endif diff --git a/Svc/Subtopologies/DataProducts/CMakeLists.txt b/Svc/Subtopologies/DataProducts/CMakeLists.txt index 3bf8bff897b..bb381f5ccbf 100644 --- a/Svc/Subtopologies/DataProducts/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/CMakeLists.txt @@ -3,11 +3,10 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig/") register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/DataProducts.fpp" - SOURCES - "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.cpp" HEADERS "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" DEPENDS Svc_Subtopologies_DataProducts_DataProductsConfig + INTERFACE ) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 5d5d7e6e68f..7092c76e0a3 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -13,7 +13,7 @@ module DataProducts{ Fw::FileNameString dpDir(DataProductsConfig::Paths::DP_DIR); Fw::FileNameString dpState(DataProductsConfig::Paths::DP_STATE); Os::FileSystem::createDirectory(dpDir.toChar()); - DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::mallocator); + DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::memAllocator); """ } @@ -38,15 +38,18 @@ module DataProducts{ instance dpBufferManager: Svc.BufferManager base id DataProductsConfig.BASE_ID + 0x0400 \ { + phase Fpp.ToCpp.Phases.configObjects """ + Svc::BufferManager::BufferBins bins; + """ phase Fpp.ToCpp.Phases.configComponents """ - memset(&DataProducts::BufferManagerBins::bins, 0, sizeof(DataProducts::BufferManagerBins::bins)); - DataProducts::BufferManagerBins::bins.bins[0].bufferSize = DataProductsConfig::BufferMgr::dpBufferStoreSize; - DataProducts::BufferManagerBins::bins.bins[0].numBuffers = DataProductsConfig::BufferMgr::dpBufferStoreCount; + memset(&ConfigObjects::DataProducts_dpBufferManager::bins, 0, sizeof(ConfigObjects::DataProducts_dpBufferManager::bins)); + ConfigObjects::DataProducts_dpBufferManager::bins.bins[0].bufferSize = DataProductsConfig::BufferMgr::dpBufferStoreSize; + ConfigObjects::DataProducts_dpBufferManager::bins.bins[0].numBuffers = DataProductsConfig::BufferMgr::dpBufferStoreCount; DataProducts::dpBufferManager.setup( DataProductsConfig::BufferMgr::dpBufferManagerId, 0, - DataProducts::Allocation::mallocator, - DataProducts::BufferManagerBins::bins + DataProducts::Allocation::memAllocator, + ConfigObjects::DataProducts_dpBufferManager::bins ); """ phase Fpp.ToCpp.Phases.tearDownComponents """ diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt index 092b35e1e99..3c7fd0c2e7c 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/CMakeLists.txt @@ -1,4 +1,8 @@ register_fprime_config( + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/DataProductsSubtopologyConfig.cpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/DataProductsSubtopologyConfig.hpp" AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/DataProductsConfig.fpp" DEPENDS diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.cpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.cpp new file mode 100644 index 00000000000..03d69a20aae --- /dev/null +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.cpp @@ -0,0 +1,9 @@ +#include "DataProductsSubtopologyConfig.hpp" + +namespace DataProducts { + namespace Allocation{ + //This instance can be changed to use a different allocator in the DataProducts Subtopology + Fw::MallocAllocator mallocatorInstance; + Fw::MemAllocator& memAllocator = mallocatorInstance; + } +} diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp new file mode 100644 index 00000000000..eae63341852 --- /dev/null +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp @@ -0,0 +1,12 @@ +#ifndef DATAPRODUCTSSUBTOPOLOGY_CONFIG_HPP +#define DATAPRODUCTSSUBTOPOLOGY_CONFIG_HPP + +#include "Fw/Types/MallocAllocator.hpp" + +namespace DataProducts { + namespace Allocation { + extern Fw::MemAllocator& memAllocator; + } +} + +#endif \ No newline at end of file diff --git a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp deleted file mode 100644 index 18d2d75ede6..00000000000 --- a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "SubtopologyTopologyDefs.hpp" - -namespace DataProducts { - namespace Allocation { - Fw::MallocAllocator mallocator; - } - - namespace BufferManagerBins { - Svc::BufferManager::BufferBins bins; - } -} diff --git a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp index ff14be62904..d5edee6fd86 100644 --- a/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp @@ -5,18 +5,9 @@ #include #include #include "Svc/Subtopologies/DataProducts/DataProductsConfig/FppConstantsAc.hpp" +#include "DataProductsConfig/DataProductsSubtopologyConfig.hpp" namespace DataProducts { - namespace Allocation { - // Malloc allocator for topology construction - extern Fw::MallocAllocator mallocator; - } - - namespace BufferManagerBins{ - // Buffer manager bins for Data Products - extern Svc::BufferManager::BufferBins bins; - } - // State for topology construction struct TopologyState { }; diff --git a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp index cd779bd61b3..adc36798018 100644 --- a/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp +++ b/Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp @@ -4,6 +4,8 @@ #include "Svc/Subtopologies/FileHandling/FileHandlingConfig/FppConstantsAc.hpp" namespace FileHandling { // State for topology construction + struct TopologyState { + }; } #endif From 254c1afe28bc1b9213fb3286c285929f03f2b0cb Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 26 Jun 2025 10:47:11 -0700 Subject: [PATCH 51/52] Update subtopology config names for clarity, fixes #3571 --- Svc/Subtopologies/CdhCore/CMakeLists.txt | 2 +- Svc/Subtopologies/CdhCore/CdhCore.fpp | 2 +- .../CdhCore/CdhCoreConfig/CMakeLists.txt | 2 +- Svc/Subtopologies/ComCcsds/ComCcsds.fpp | 14 +++++----- .../ComCcsdsComDriverConfig.fpp | 2 +- .../ComCcsdsConfig/ComCcsdsConfig.fpp | 18 ++++++------ .../ComCcsdsSubtopologyConfig.hpp | 2 +- Svc/Subtopologies/ComFprime/ComFprime.fpp | 16 +++++------ .../ComFprimeConfig/ComFprimeConfig.fpp | 28 +++++++++---------- .../ComFprimeSubtopologyConfig.hpp | 2 +- .../DataProducts/DataProducts.fpp | 4 +-- .../DataProductsConfig/DataProductsConfig.fpp | 14 +++++----- .../DataProductsSubtopologyConfig.hpp | 2 +- 13 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Svc/Subtopologies/CdhCore/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CMakeLists.txt index bed12149b8a..4485f2b5744 100644 --- a/Svc/Subtopologies/CdhCore/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CMakeLists.txt @@ -8,4 +8,4 @@ register_fprime_module( INTERFACE DEPENDS Svc_Subtopologies_CdhCore_CdhCoreConfig -) \ No newline at end of file +) diff --git a/Svc/Subtopologies/CdhCore/CdhCore.fpp b/Svc/Subtopologies/CdhCore/CdhCore.fpp index f7811d71124..9dec9db1726 100644 --- a/Svc/Subtopologies/CdhCore/CdhCore.fpp +++ b/Svc/Subtopologies/CdhCore/CdhCore.fpp @@ -68,4 +68,4 @@ module CdhCore { } } # end topology -} # end CdhCore Subtopology \ No newline at end of file +} # end CdhCore Subtopology diff --git a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt index d6aca02a24f..90315c71f2e 100644 --- a/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt +++ b/Svc/Subtopologies/CdhCore/CdhCoreConfig/CMakeLists.txt @@ -4,4 +4,4 @@ register_fprime_config( "${CMAKE_CURRENT_LIST_DIR}/CdhCoreFatalHandlerConfig.fpp" "${CMAKE_CURRENT_LIST_DIR}/CdhCoreTlmConfig.fpp" INTERFACE -) \ No newline at end of file +) diff --git a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp index 39b6946975c..dab7ae12981 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsds.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsds.fpp @@ -51,7 +51,7 @@ module ComCcsds { priority ComCcsdsConfig.Priorities.cmdSeq \ { phase Fpp.ToCpp.Phases.configComponents """ - ComCcsds::cmdSeq.allocateBuffer(0, ComCcsds::Allocation::memAllocator, ComCcsdsConfig::BufferMgr::cmdSeqBuffer); + ComCcsds::cmdSeq.allocateBuffer(0, ComCcsds::Allocation::memAllocator, ComCcsdsConfig::BuffMgr::cmdSeqBuffSize); """ phase Fpp.ToCpp.Phases.tearDownComponents """ @@ -73,7 +73,7 @@ module ComCcsds { ConfigObjects::ComCcsds_frameAccumulator::frameDetector, 1, ComCcsds::Allocation::memAllocator, - ComCcsdsConfig::BufferMgr::frameAccumulator + ComCcsdsConfig::BuffMgr::frameAccumulatorSize ); """ @@ -90,12 +90,12 @@ module ComCcsds { phase Fpp.ToCpp.Phases.configComponents """ memset(&ConfigObjects::ComCcsds_commsBufferManager::bins, 0, sizeof(ConfigObjects::ComCcsds_commsBufferManager::bins)); - ConfigObjects::ComCcsds_commsBufferManager::bins.bins[0].bufferSize = ComCcsdsConfig::BufferMgr::commsBufferStore; - ConfigObjects::ComCcsds_commsBufferManager::bins.bins[0].numBuffers = ComCcsdsConfig::BufferMgr::commsBufferCount; - ConfigObjects::ComCcsds_commsBufferManager::bins.bins[1].bufferSize = ComCcsdsConfig::BufferMgr::commsFileBufferStore; - ConfigObjects::ComCcsds_commsBufferManager::bins.bins[1].numBuffers = ComCcsdsConfig::BufferMgr::commsFileBufferCount; + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[0].bufferSize = ComCcsdsConfig::BuffMgr::commsBuffSize; + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[0].numBuffers = ComCcsdsConfig::BuffMgr::commsBuffCount; + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[1].bufferSize = ComCcsdsConfig::BuffMgr::commsFileBuffSize; + ConfigObjects::ComCcsds_commsBufferManager::bins.bins[1].numBuffers = ComCcsdsConfig::BuffMgr::commsFileBuffCount; ComCcsds::commsBufferManager.setup( - ComCcsdsConfig::BufferMgr::commsBufferManager, + ComCcsdsConfig::BuffMgr::commsBuffMgrId, 0, ComCcsds::Allocation::memAllocator, ConfigObjects::ComCcsds_commsBufferManager::bins diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp index f9f586d2cd1..7ea2b44f4c5 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsComDriverConfig.fpp @@ -25,4 +25,4 @@ module ComCcsds { (void)ComCcsds::comDriver.join(); """ } -} \ No newline at end of file +} diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp index 40165f87c94..ba71e3e5de9 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsConfig.fpp @@ -33,13 +33,13 @@ module ComCcsdsConfig { } # Buffer management constants - module BufferMgr { - constant cmdSeqBuffer = 5 * 1024 # 5KB for command sequencer buffer - constant frameAccumulator = 2048 # 2KB frame accumulator buffer - constant commsBufferStore = 2048 # 2KB communications buffer store - constant commsFileBufferStore = 3000 # 3KB file buffer store - constant commsBufferCount = 20 # Number of comms buffers - constant commsFileBufferCount = 30 # File queue buffer count - constant commsBufferManager = 200 # Buffer manager identifier + module BuffMgr { + constant cmdSeqBuffSize = 5 * 1024 + constant frameAccumulatorSize = 2048 + constant commsBuffSize = 2048 + constant commsFileBuffSize = 3000 + constant commsBuffCount = 20 + constant commsFileBuffCount = 30 + constant commsBuffMgrId = 200 } -} \ No newline at end of file +} diff --git a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp index eb55b53d9f4..4582c13eadb 100644 --- a/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp +++ b/Svc/Subtopologies/ComCcsds/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp @@ -9,4 +9,4 @@ namespace ComCcsds { } } -#endif \ No newline at end of file +#endif diff --git a/Svc/Subtopologies/ComFprime/ComFprime.fpp b/Svc/Subtopologies/ComFprime/ComFprime.fpp index acba6a7d5e0..62b9a08c618 100644 --- a/Svc/Subtopologies/ComFprime/ComFprime.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprime.fpp @@ -43,7 +43,7 @@ module ComFprime { priority ComFprimeConfig.Priorities.cmdSeq \ { phase Fpp.ToCpp.Phases.configComponents """ - ComFprime::cmdSeq.allocateBuffer(0, ComFprime::Allocation::memAllocator, ComFprimeConfig::BufferMgr::cmdSeqBuffer); + ComFprime::cmdSeq.allocateBuffer(0, ComFprime::Allocation::memAllocator, ComFprimeConfig::BuffMgr::cmdSeqBuffSize); """ phase Fpp.ToCpp.Phases.tearDownComponents """ @@ -62,7 +62,7 @@ module ComFprime { ComFprime::Detector::frameDetector, 1, ComFprime::Allocation::memAllocator, - ComFprimeConfig::BufferMgr::frameAccumulator + ComFprimeConfig::BuffMgr::frameAccumulatorSize ); """ @@ -75,12 +75,12 @@ module ComFprime { { phase Fpp.ToCpp.Phases.configComponents """ memset(&ComFprime::BufferManagerBins::bins, 0, sizeof(ComFprime::BufferManagerBins::bins)); - ComFprime::BufferManagerBins::bins.bins[0].bufferSize = ComFprimeConfig::BufferMgr::commsBufferStore; - ComFprime::BufferManagerBins::bins.bins[0].numBuffers = ComFprimeConfig::BufferMgr::commsBufferCount; - ComFprime::BufferManagerBins::bins.bins[1].bufferSize = ComFprimeConfig::BufferMgr::commsFileBufferStore; - ComFprime::BufferManagerBins::bins.bins[1].numBuffers = ComFprimeConfig::BufferMgr::commsFileBufferQueue; + ComFprime::BufferManagerBins::bins.bins[0].bufferSize = ComFprimeConfig::BuffMgr::commsBuffSize; + ComFprime::BufferManagerBins::bins.bins[0].numBuffers = ComFprimeConfig::BuffMgr::commsBuffCount; + ComFprime::BufferManagerBins::bins.bins[1].bufferSize = ComFprimeConfig::BuffMgr::commsFileBuffSize; + ComFprime::BufferManagerBins::bins.bins[1].numBuffers = ComFprimeConfig::BuffMgr::commsFileBuffCount; ComFprime::commsBufferManager.setup( - ComFprimeConfig::BufferMgr::commsBufferManager, + ComFprimeConfig::BuffMgr::commsBuffMgrId, 0, ComFprime::Allocation::memAllocator, ComFprime::BufferManagerBins::bins @@ -161,4 +161,4 @@ module ComFprime { } # end topology -} # end ComFprime Subtopology \ No newline at end of file +} # end ComFprime Subtopology diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp index f1a45d2fb3d..17e23c6fc3d 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeConfig.fpp @@ -21,25 +21,25 @@ module ComFprimeConfig { # Queue configuration constants module QueueDepths { - constant events = 100 # Event queue depth - constant tlm = 500 # Telemetry queue depth - constant file = 100 # File downlink queue depth + constant events = 100 + constant tlm = 500 + constant file = 100 } module QueuePriorities { - constant events = 0 # Highest priority for events - constant tlm = 2 # Lower priority for telemetry - constant file = 1 # Medium priority for file transfers + constant events = 0 + constant tlm = 2 + constant file = 1 } # Buffer management constants - module BufferMgr { - constant cmdSeqBuffer = 5 * 1024 # 5KB for command sequencer buffer - constant frameAccumulator = 2048 # 2KB frame accumulator buffer - constant commsBufferStore = 2048 # 2KB communications buffer store - constant commsFileBufferStore = 3000 # 3KB file buffer store - constant commsBufferCount = 20 # Number of comms buffers - constant commsFileBufferQueue = 30 # File queue buffer count - constant commsBufferManager = 200 # Buffer manager identifier + module BuffMgr { + constant cmdSeqBuffSize = 5 * 1024 + constant frameAccumulatorSize = 2048 + constant commsBuffSize = 2048 + constant commsFileBuffSize = 3000 + constant commsBuffCount = 20 + constant commsFileBuffCount = 30 + constant commsBuffMgrId = 200 } } diff --git a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp index ba383be3ede..32f868be7ac 100644 --- a/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp +++ b/Svc/Subtopologies/ComFprime/ComFprimeConfig/ComFprimeSubtopologyConfig.hpp @@ -9,4 +9,4 @@ namespace ComFprime { } } -#endif \ No newline at end of file +#endif diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 7092c76e0a3..728a72aa8b3 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -10,8 +10,8 @@ module DataProducts{ priority DataProductsConfig.Priorities.dpCat \ { phase Fpp.ToCpp.Phases.configComponents """ - Fw::FileNameString dpDir(DataProductsConfig::Paths::DP_DIR); - Fw::FileNameString dpState(DataProductsConfig::Paths::DP_STATE); + Fw::FileNameString dpDir(DataProductsConfig::Paths::dpDir); + Fw::FileNameString dpState(DataProductsConfig::Paths::dpState); Os::FileSystem::createDirectory(dpDir.toChar()); DataProducts::dpCat.configure(&dpDir,1,dpState,0, DataProducts::Allocation::memAllocator); """ diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp index 85c592e39bd..f58ac2f1ba3 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsConfig.fpp @@ -25,15 +25,15 @@ module DataProductsConfig { } # Buffer management constants - module BufferMgr { - constant dpBufferStoreSize = 10000 # Data products buffer store size - constant dpBufferStoreCount = 10 # Number of data products buffers - constant dpBufferManagerId = 300 # Buffer manager identifier + module BuffMgr { + constant dpBufferStoreSize = 10000 + constant dpBufferStoreCount = 10 + constant dpBufferManagerId = 300 } # Directory and file paths module Paths { - constant DP_DIR = "./DpCat" # Data products directory - constant DP_STATE = "./DpCat/DpState.dat" # Data products state file + constant dpDir = "./DpCat" + constant dpState = "./DpCat/DpState.dat" } -} \ No newline at end of file +} diff --git a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp index eae63341852..0ba6db35a0f 100644 --- a/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp +++ b/Svc/Subtopologies/DataProducts/DataProductsConfig/DataProductsSubtopologyConfig.hpp @@ -9,4 +9,4 @@ namespace DataProducts { } } -#endif \ No newline at end of file +#endif From d96350995c4be4e7ca2967aa74cada056a932521 Mon Sep 17 00:00:00 2001 From: Moises Mata Date: Thu, 26 Jun 2025 10:55:40 -0700 Subject: [PATCH 52/52] Fix reference to dpBuffer config Constants --- Svc/Subtopologies/DataProducts/DataProducts.fpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Svc/Subtopologies/DataProducts/DataProducts.fpp b/Svc/Subtopologies/DataProducts/DataProducts.fpp index 728a72aa8b3..d4a765d6ccc 100644 --- a/Svc/Subtopologies/DataProducts/DataProducts.fpp +++ b/Svc/Subtopologies/DataProducts/DataProducts.fpp @@ -43,10 +43,10 @@ module DataProducts{ """ phase Fpp.ToCpp.Phases.configComponents """ memset(&ConfigObjects::DataProducts_dpBufferManager::bins, 0, sizeof(ConfigObjects::DataProducts_dpBufferManager::bins)); - ConfigObjects::DataProducts_dpBufferManager::bins.bins[0].bufferSize = DataProductsConfig::BufferMgr::dpBufferStoreSize; - ConfigObjects::DataProducts_dpBufferManager::bins.bins[0].numBuffers = DataProductsConfig::BufferMgr::dpBufferStoreCount; + ConfigObjects::DataProducts_dpBufferManager::bins.bins[0].bufferSize = DataProductsConfig::BuffMgr::dpBufferStoreSize; + ConfigObjects::DataProducts_dpBufferManager::bins.bins[0].numBuffers = DataProductsConfig::BuffMgr::dpBufferStoreCount; DataProducts::dpBufferManager.setup( - DataProductsConfig::BufferMgr::dpBufferManagerId, + DataProductsConfig::BuffMgr::dpBufferManagerId, 0, DataProducts::Allocation::memAllocator, ConfigObjects::DataProducts_dpBufferManager::bins