├── .clang-format ├── .editorconfig ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── .idea ├── .name ├── ccsds-tm-packets.iml ├── codeStyles │ └── codeStyleConfig.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── ci ├── .clang-tidy ├── clang-format.sh ├── clang-tidy.sh ├── cppcheck-misra.sh ├── cppcheck.sh ├── lcovrc ├── page_style │ ├── custom_format.css │ ├── doxygen_dark_theme │ │ ├── LICENSE │ │ ├── README.md │ │ ├── custom.css │ │ ├── custom_dark_theme.css │ │ ├── html_footer.html │ │ └── html_header.html │ └── epilog.html ├── pages_deploy.sh ├── summarizer.py ├── vera.profile └── vera.sh ├── doxygen.conf ├── inc ├── Alert.hpp ├── CCSDSChannel.hpp ├── CCSDSLogger.h ├── CCSDSLoggerImpl.h ├── CCSDSServiceChannel.hpp ├── CCSDS_Definitions.hpp ├── CLCW.hpp ├── FrameAcceptanceReporting.hpp ├── FrameOperationProcedure.hpp ├── Logger.hpp ├── MemoryPool.hpp ├── TransferFrame.hpp ├── TransferFrameTC.hpp ├── TransferFrameTM.hpp ├── etl │ └── String.hpp ├── etl_profile.h └── logOperators.h ├── servicesAndBuffersGraph.mmd ├── src ├── CCSDSChannel.cpp ├── CCSDSServiceChannel.cpp ├── CLCW.cpp ├── FrameAcceptanceReporting.cpp ├── FrameOperationProcedure.cpp ├── Logger.cpp ├── MemoryPool.cpp ├── Packet.cpp ├── Platform │ └── x86 │ │ └── Logger.cpp ├── TransferFrameTC.cpp ├── logOperators.cpp └── main.cpp └── test ├── CCSDSChannel.cpp ├── CCSDSServiceChannel.cpp ├── FrameOperationProcedure.cpp ├── MemoryPool.cpp ├── TmFunctionalTesting.cpp ├── TransferFrame.cpp ├── tests └── tests.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: false 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: Empty 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: Yes 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BreakBeforeBinaryOperators: None 24 | BreakBeforeBraces: Custom 25 | BraceWrapping: 26 | AfterClass: false 27 | AfterControlStatement: false 28 | AfterEnum: false 29 | AfterFunction: false 30 | AfterNamespace: true 31 | AfterStruct: false 32 | AfterUnion: false 33 | AfterExternBlock: false 34 | BeforeCatch: false 35 | BeforeElse: false 36 | SplitEmptyFunction: false 37 | SplitEmptyRecord: false 38 | SplitEmptyNamespace: false 39 | BreakBeforeInheritanceComma: false 40 | BreakInheritanceList: BeforeColon 41 | BreakBeforeTernaryOperators: true 42 | BreakConstructorInitializersBeforeComma: false 43 | BreakConstructorInitializers: BeforeColon 44 | BreakAfterJavaFieldAnnotations: false 45 | BreakStringLiterals: true 46 | ColumnLimit: 120 47 | CommentPragmas: '^ IWYU pragma:' 48 | CompactNamespaces: false 49 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 50 | ConstructorInitializerIndentWidth: 4 51 | ContinuationIndentWidth: 4 52 | Cpp11BracedListStyle: true 53 | DerivePointerAlignment: false 54 | DisableFormat: false 55 | ExperimentalAutoDetectBinPacking: false 56 | FixNamespaceComments: true 57 | ForEachMacros: 58 | - foreach 59 | - Q_FOREACH 60 | - BOOST_FOREACH 61 | IncludeBlocks: Merge 62 | IncludeCategories: 63 | - Regex: '^"' 64 | Priority: 2 65 | - Regex: '^<' 66 | Priority: 3 67 | - Regex: '.*' 68 | Priority: 1 69 | IncludeIsMainRegex: '(Test)?$' 70 | IndentCaseLabels: true 71 | IndentPPDirectives: None 72 | IndentWidth: 4 73 | IndentWrappedFunctionNames: false 74 | JavaScriptQuotes: Leave 75 | JavaScriptWrapImports: true 76 | KeepEmptyLinesAtTheStartOfBlocks: false 77 | MacroBlockBegin: '' 78 | MacroBlockEnd: '' 79 | MaxEmptyLinesToKeep: 1 80 | NamespaceIndentation: None 81 | ObjCBinPackProtocolList: Auto 82 | ObjCBlockIndentWidth: 2 83 | ObjCSpaceAfterProperty: false 84 | ObjCSpaceBeforeProtocolList: true 85 | PenaltyBreakAssignment: 2 86 | PenaltyBreakBeforeFirstCallParameter: 19 87 | PenaltyBreakComment: 300 88 | PenaltyBreakFirstLessLess: 120 89 | PenaltyBreakString: 1000 90 | PenaltyBreakTemplateDeclaration: 10 91 | PenaltyExcessCharacter: 1000000 92 | PenaltyReturnTypeOnItsOwnLine: 60 93 | PointerAlignment: Left 94 | ReflowComments: true 95 | SortIncludes: false 96 | SortUsingDeclarations: true 97 | SpaceAfterCStyleCast: false 98 | SpaceAfterTemplateKeyword: true 99 | SpaceBeforeAssignmentOperators: true 100 | SpaceBeforeCpp11BracedList: false 101 | SpaceBeforeCtorInitializerColon: true 102 | SpaceBeforeInheritanceColon: true 103 | SpaceBeforeParens: ControlStatements 104 | SpaceBeforeRangeBasedForLoopColon: true 105 | SpaceInEmptyParentheses: false 106 | SpacesBeforeTrailingComments: 1 107 | SpacesInAngles: false 108 | SpacesInContainerLiterals: true 109 | SpacesInCStyleCastParentheses: false 110 | SpacesInParentheses: false 111 | SpacesInSquareBrackets: false 112 | Standard: Cpp11 113 | TabWidth: 4 114 | UseTab: ForIndentation 115 | ... 116 | 117 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig file: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # 4 space indentation 12 | [*.{c,cpp,h,hpp}, CMakeLists.txt] 13 | indent_style = tab 14 | indent_size = 4 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build files 2 | build 3 | cmake-build-debug 4 | docs 5 | 6 | # Dump and continuous integration files 7 | *.dump 8 | __pycache__ 9 | /ci/cppcheckdata.py 10 | /ci/misra.py 11 | /ci/report.msr 12 | 13 | # Prerequisites 14 | *.d 15 | 16 | # Hidden files 17 | .* 18 | 19 | # Don't ignore gitignore :( 20 | !/.gitignore 21 | 22 | # Compiled Object files 23 | *.slo 24 | *.lo 25 | *.o 26 | *.obj 27 | 28 | # Precompiled Headers 29 | *.gch 30 | *.pch 31 | 32 | # Compiled Dynamic libraries 33 | *.so 34 | *.dylib 35 | *.dll 36 | 37 | # Fortran module files 38 | *.mod 39 | *.smod 40 | 41 | # Compiled Static libraries 42 | *.lai 43 | *.la 44 | *.a 45 | *.lib 46 | 47 | # Executables 48 | *.exe 49 | *.out 50 | *.app 51 | 52 | # User-specific stuff 53 | .idea/**/workspace.xml 54 | .idea/**/tasks.xml 55 | .idea/**/usage.statistics.xml 56 | .idea/**/dictionaries 57 | .idea/**/shelf 58 | 59 | # Generated files 60 | .idea/**/contentModel.xml 61 | 62 | # Sensitive or high-churn files 63 | .idea/**/dataSources/ 64 | .idea/**/dataSources.ids 65 | .idea/**/dataSources.local.xml 66 | .idea/**/sqlDataSources.xml 67 | .idea/**/dynamic.xml 68 | .idea/**/uiDesigner.xml 69 | .idea/**/dbnavigator.xml 70 | .idea/**/markdown-* 71 | 72 | # Virtual environment 73 | venv/** 74 | 75 | # IDEs 76 | .vscode -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | GIT_SUBMODULE_STRATEGY: recursive 3 | 4 | stages: 5 | - build 6 | - analyze 7 | - test 8 | - deploy 9 | 10 | 11 | check-build: 12 | image: spacedot/build-base # TODO: push build-base 13 | stage: build 14 | variables: 15 | GCC_COLORS: "error=31;1:warning=35;1:note=36;1:range1=32:range2=34:locus=39;1:quote=39;1:fixit-insert=32:fixit-delete=31:diff-filename=39;1:diff-hunk=32:diff-delete=31:diff-insert=32:type-diff=32;1" 16 | CLICOLOR_FORCE: 1 # Necessary for cmake to output colours 17 | script: 18 | - mkdir build 19 | - cd build 20 | - cmake .. -DCMAKE_CXX_FLAGS="-Wall -Wextra -pedantic -fdiagnostics-color=always" 21 | - make -j$(nproc) 22 | 23 | cppcheck: 24 | image: spacedot/cppcheck:2.5 25 | stage: analyze 26 | before_script: 27 | - cppcheck --version 28 | allow_failure: true 29 | script: 30 | - cd $CI_PROJECT_DIR 31 | - cppcheck --enable=all --addon=misra --suppress=misra-c2012-3.1 --suppress=misra-c2012-5.1 --suppress=misra-c2012-5.2 \ 32 | --suppress=misra-c2012-5.3 --suppress=misra-c2012-12.3 --suppress=misra-c2012-13.4 --suppress=misra-c2012-14.4 \ 33 | --suppress=misra-c2012-15.5 --suppress=misra-c2012-16.3 --suppress=misra-c2012-18.4 --suppress=misra-c2012-18.8 \ 34 | --suppress=unusedFunction --suppress=noExplicitConstructor --force --inline-suppr --error-exitcode=1 \ 35 | --xml --xml-version=2 2>report.xml -I ./inc ./src 36 | after_script: 37 | - mkdir cppcheck-html-report 38 | - cppcheck-htmlreport --source-dir=. --title=html-report --file=report.xml --report-dir=cppcheck-html-report 39 | artifacts: 40 | when: on_failure 41 | paths: 42 | - ./cppcheck-html-report 43 | 44 | clang-tidy: 45 | image: spacedot/clang-tools:13.0.0-html-1.4.1 46 | stage: analyze 47 | script: 48 | - cd $CI_PROJECT_DIR 49 | - cmake -B ./build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 50 | - clang-tidy -p $CI_PROJECT_DIR/build/compile_commands.json --checks=* `find $CI_PROJECT_DIR/src -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` >> clang-tidy-output.log 51 | after_script: 52 | - mkdir clang-tidy-html-report 53 | - clang-tidy-html clang-tidy-output.log 54 | - mv clang.html clang-tidy-html-report 55 | artifacts: 56 | paths: 57 | - ./clang-tidy-html-report 58 | 59 | clang-analyzer: 60 | image: spacedot/clang-tools:13.0.0-html-1.3.7 61 | stage: analyze 62 | before_script: 63 | - mkdir scan-build-html-report 64 | script: 65 | - cd $CI_PROJECT_DIR/scan-build-html-report 66 | - scan-build cmake ../ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ 67 | - scan-build -o ./scan-build-html-report make 68 | artifacts: 69 | paths: 70 | - ./scan-build-html-report 71 | 72 | doxygen: 73 | image: spacedot/doxygen:1.9.4-4-awesomecss-1.6.0 74 | stage: analyze 75 | script: 76 | - cd $CI_PROJECT_DIR 77 | - doxygen doxygen.conf 78 | artifacts: 79 | paths: 80 | - ./docs 81 | 82 | ikos: 83 | image: spacedot/ikos:3.0 84 | stage: analyze 85 | before_script: 86 | - mkdir ikos-report 87 | script: 88 | - cd $CI_PROJECT_DIR/ikos-report 89 | - ikos-scan cmake .. 90 | - ikos-scan make 91 | - ikos-report -o=ikos-report.txt ccsds_tm_packets.db 92 | artifacts: 93 | paths: 94 | - ./ikos-report 95 | tests: 96 | image: spacedot/coverage:gcovr-5.0-lcov-1.15 97 | stage: test 98 | when: always 99 | before_script: 100 | - mkdir gcovr 101 | script: 102 | - cd $CI_PROJECT_DIR 103 | - mkdir build 104 | - cd build 105 | - cmake .. -DCMAKE_CXX_FLAGS="-g -O0 --coverage" && make tests -j$(nproc) 106 | - lcov -q --capture --initial --directory . -o coverage_base 107 | - ./tests --colour-mode ansi 108 | - lcov -q --capture --directory . -o coverage_tests 109 | - lcov -q -a coverage_base -a coverage_tests -o coverage_total_unfiltered 110 | - lcov -q --remove coverage_total_unfiltered "${PWD}/lib/*" "${PWD}/CMakeFiles/*" "${PWD}/test/*" "${PWD}/src/main.cpp" -o coverage_total_filtered 111 | - gcovr -s -p -e "^.*(test|lib|main.cpp|CMakeFiles)" --html --html-details --html-title "Code coverage ${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}" -o ../gcovr/gcovr.html 112 | - gcovr -e "^.*(test|lib|main.cpp|CMakeFiles)" 113 | - genhtml --demangle-cpp -t "${CI_COMMIT_REF_NAME}" --html-epilog ../ci/page_style/epilog.html -o ../gcovr coverage_total_filtered 114 | artifacts: 115 | paths: 116 | - ./gcovr 117 | pages: 118 | image: spacedot/build-base:latest # TODO: Latest tag is temporary 119 | stage: deploy 120 | script: 121 | - mkdir .public 122 | - cp -r ./{docs,gcovr,ikos-report,scan-build-html-report,clang-tidy-html-report,cppcheck-html-report} ./.public/ 123 | - ls ./.public 124 | - find ./.public 125 | - mv .public public 126 | artifacts: 127 | paths: 128 | - public # Upload the resulting website 129 | # only: 130 | # - branches # Deploy on all branches 131 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/Catch2"] 2 | path = lib/Catch2 3 | url = https://github.com/catchorg/Catch2.git 4 | [submodule "lib/etl"] 5 | path = lib/etl 6 | url = https://github.com/ETLCPP/etl.git 7 | 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | ccsds_tm_packets -------------------------------------------------------------------------------- /.idea/ccsds-tm-packets.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | ApexVCS 21 | 22 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7) 2 | project(ccsds_tm_packets) 3 | 4 | # Set C++ version to c++17 5 | set(CMAKE_CXX_STANDARD 17) 6 | 7 | # Specify the directories for #includes 8 | include_directories("${PROJECT_SOURCE_DIR}/inc" "${PROJECT_SOURCE_DIR}/lib/etl/include") 9 | 10 | add_compile_options(-Wvla) 11 | 12 | add_custom_target(check 13 | COMMAND ./cppcheck.sh 14 | COMMAND ./vera.sh 15 | COMMAND ./clang-tidy.sh 16 | COMMAND ./cppcheck-misra.sh 17 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/ci") 18 | 19 | # Specify the .cpp files common across all targets 20 | add_library(common OBJECT 21 | src/Logger.cpp 22 | src/Platform/x86/Logger.cpp 23 | src/CCSDSServiceChannel.cpp 24 | src/CCSDSChannel.cpp 25 | src/FrameOperationProcedure.cpp 26 | src/FrameAcceptanceReporting.cpp 27 | src/logOperators.cpp 28 | src/MemoryPool.cpp 29 | src/CLCW.cpp 30 | ) 31 | 32 | # Specify the .cpp files for the executables 33 | file(GLOB x86_main_SRC "src/Platform/x86/*.cpp") 34 | add_executable(ccsds_tm_packets 35 | src/main.cpp 36 | $ 37 | # ${x86_main_SRC} 38 | ) 39 | 40 | IF (EXISTS "${PROJECT_SOURCE_DIR}/lib/Catch2/CMakeLists.txt") 41 | # Gather all the .cpp files corresponding to tests 42 | file(GLOB test_main_SRC "test/*.cpp") 43 | file(GLOB test_SRC "test/**/*.cpp") 44 | 45 | add_subdirectory(lib/Catch2) 46 | add_executable(tests 47 | $ 48 | ${test_main_SRC} 49 | ${test_SRC}) 50 | target_link_libraries(tests Catch2::Catch2WithMain) 51 | ENDIF () 52 | set_target_properties(common PROPERTIES COMPILE_DEFINITIONS LOGLEVEL_TRACE) 53 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ") 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 AcubeSAT / Communications / Software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CCSDS Data Link 2 | 3 | Implementation of the CCSDS TM and TC Data Link standards (232.0-B-4, CCSDS 232.1-B-2, 132.0-B-3). 4 | 5 | For more information refer to 6 | the [wiki](https://gitlab.com/acubesat/comms/software/ccsds-telemetry-packets/-/wikis/Creating-a-Service-Channel) (WIP). 7 | 8 | (Note: There is no planned support for SDLS) 9 | -------------------------------------------------------------------------------- /ci/.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: > 3 | -clang-diagnostic-error, 4 | clang-analyzer-*, 5 | bugprone-*, 6 | cert-*, 7 | cppcoreguidelines-*,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-avoid-c-arrays, 8 | misc-*,-misc-non-private-member-variables-in-classes, 9 | fuchsia-multiple-inheritance, 10 | google-*,-google-readability-todo, 11 | fuchsia-statically-constructed-objects, 12 | hicpp-exception-baseclass, 13 | hicpp-signed-bitwise, 14 | llvm-*,-llvm-include-order,-llvm-header-guard, 15 | modernize-use-auto, 16 | modernize-use-equals-default, 17 | misc-*, 18 | -misc-non-private-member-variables-in-classes, 19 | performance-*, 20 | readability-*,-readability-magic-numbers, 21 | zircon-* 22 | WarningsAsErrors: '*,-misc-unused-parameters,-llvm-header-guard,-cppcoreguidelines-pro-type-member-init,-google-runtime-references,-clang-diagnostic-tautological-constant-out-of-range-compare,-readability-redundant-declaration,-modernize-use-equals-default,-fuchsia-statically-constructed-objects,-hicpp-signed-bitwise,-cert-err58-cpp,-clang-diagnostic-error,-misc-noexcept-move-constructor' 23 | HeaderFilterRegex: 'ecss-services\/((?!lib\/).)*$' 24 | AnalyzeTemporaryDtors: false 25 | ... 26 | 27 | -------------------------------------------------------------------------------- /ci/clang-format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Edit files, performing code style corrections using clang-format 5 | # 6 | # Usage: 7 | # $ ci/clang-format.sh 8 | # 9 | 10 | echo -e "\033[0;34mRunning clang-format...\033[0m" 11 | 12 | cd "$(dirname "$0")" 13 | clang-format-7 -i `find ../src/ ../inc/ ../test/ -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` \ 14 | -verbose $@ 15 | -------------------------------------------------------------------------------- /ci/clang-tidy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Code style checks using clang-tidy 5 | # 6 | # Usage: 7 | # $ ci/clang-tidy.sh 8 | # 9 | 10 | echo -e "\033[0;34mRunning clang-tidy...\033[0m" 11 | 12 | cd "$(dirname "$0")" 13 | GCCVERSION=`g++ -dumpversion` 14 | 15 | clang-tidy `find ../src/ -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` \ 16 | -extra-arg=-fcolor-diagnostics -- -std=c++17 -I../inc -I../lib/etl/include -I../inc/Platform/x86 \ 17 | -I/usr/include/c++/$GCCVERSION -I/usr/include/x86_64-linux-gnu/c++/$GCCVERSION \ 18 | -I/usr/include/c++/$GCCVERSION/$MACHTYPE] 19 | 20 | 21 | -------------------------------------------------------------------------------- /ci/cppcheck-misra.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Static code analysis for MISRA C-2012 compliance using cppcheck 5 | # 6 | # Usage: 7 | # $ ci/cppcheck-misra.sh 8 | # 9 | 10 | # make sure we are in the correct directory, regardless of where the script was called from 11 | cd "$(dirname "$0")/.." 12 | 13 | echo -e "\u001b[34;1mGetting prerequisites...\u001b[0m" 14 | # get the current cppcheck version 15 | CPCVERSION=`cppcheck --version | awk '{print $2}'` 16 | 17 | # grab the MISRA addon and the cppcheck addon interface from github 18 | curl https://raw.githubusercontent.com/danmar/cppcheck/$CPCVERSION/addons/misra.py > ci/misra.py 19 | curl https://raw.githubusercontent.com/danmar/cppcheck/$CPCVERSION/addons/cppcheckdata.py > ci/cppcheckdata.py 20 | 21 | # generate dump files (XML representations of AST etc.) for all headers, source files etc. 22 | echo -e "\u001b[34;1mGenerating dump files...\u001b[0m" 23 | find inc/ src/ -type f \( -iname "*.cpp" -or -iname "*.hpp" \) | xargs cppcheck --dump 24 | 25 | # run the MISRA checks against the dumps and send the results to a file 26 | echo -e "\u001b[34;1mRunning MISRA C(2012) rule compliance tests...\u001b[0m" 27 | find inc/ src/ -type f -name "*.dump" | xargs python3 ci/misra.py >> ci/report.msr 2>&1 28 | 29 | # pre-process the generated report to remove all useless strings 30 | echo -e "\u001b[34;1mPre-processing report...\u001b[0m" 31 | sed -i -r 's/(.*Script.*)|(.*Checking.*)|(.*MISRA.*)|(.*Undefined: .*)|(.* \(-\):.*)//gm; /(^$)/d; s/(\s\(.*\)\s)//gm; s/(\]|\[)//gm; s/(misra-c2012-)/:/gm' ci/report.msr 32 | 33 | # run the summarizer for a nice, clean summary of errors 34 | echo -e "\u001b[34;1mSummarizing results...\u001b[0m" 35 | python3 ci/summarizer.py --report ci/report.msr --suppress 3.1 5.1 5.2 5.3 12.3 13.4 14.4 15.5 16.3 18.4 18.8 36 | EXIT_CODE=$? 37 | 38 | # clean up old files 39 | echo -e "\u001b[34;1mRemoving dump files...\u001b[0m" 40 | echo > ci/report.msr # clear the report file 41 | find inc/ src/ -type f -name "*.dump" | xargs rm -rf 42 | 43 | # finally return the return value of the summarizer.py script 44 | exit $EXIT_CODE 45 | 46 | -------------------------------------------------------------------------------- /ci/cppcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Static code analysis using cppcheck 5 | # 6 | # Usage: 7 | # $ ci/cppcheck.sh 8 | # 9 | 10 | echo -e "\u001b[34;1mStarting cppcheck...\u001b[0m" 11 | 12 | echo -e "\u001b[34;1mRunning cppcheck with default checklist...\u001b[0m" 13 | 14 | cd "$(dirname "$0")/.." 15 | cppcheck --enable=all --suppress=unusedFunction --suppress=noExplicitConstructor \ 16 | --force --inline-suppr --error-exitcode=1 -I inc src test 17 | -------------------------------------------------------------------------------- /ci/lcovrc: -------------------------------------------------------------------------------- 1 | # genhtml configuration 2 | 3 | # External style sheet file 4 | #genhtml_css_file = gcov.css 5 | 6 | # Width of line coverage field in source code view 7 | genhtml_line_field_width = 12 8 | 9 | # Width of branch coverage field in source code view 10 | genhtml_branch_field_width = 16 11 | 12 | # Width of overview image 13 | genhtml_overview_width = 80 14 | 15 | # Resolution of overview navigation 16 | genhtml_nav_resolution = 4 17 | 18 | # Offset for source code navigation 19 | genhtml_nav_offset = 10 20 | 21 | # Do not remove unused test descriptions if non-zero 22 | genhtml_keep_descriptions = 1 23 | 24 | # Do not remove prefix from directory names if non-zero 25 | genhtml_no_prefix = 0 26 | 27 | # Specify size of tabs 28 | # genhtml_num_spaces = 8 29 | 30 | # Highlight lines with converted-only data if non-zero 31 | genhtml_highlight = 1 32 | 33 | # Include color legend in HTML output if non-zero 34 | genhtml_legend = 1 35 | 36 | # Compress all generated html files with gzip. 37 | genhtml_html_gzip = 0 38 | 39 | # Include sorted overview pages 40 | genhtml_sort = 1 41 | 42 | # Include function coverage data display 43 | genhtml_function_coverage = 1 44 | 45 | # Include branch coverage data display 46 | genhtml_branch_coverage = 1 47 | 48 | # Specify the character set of all generated HTML pages 49 | genhtml_charset=UTF-8 50 | 51 | 52 | 53 | 54 | 55 | # geninfo configuration 56 | 57 | # Calculate a checksum for each line if non-zero 58 | geninfo_checksum = 0 59 | 60 | # Enable libtool compatibility mode if non-zero 61 | geninfo_compat_libtool = 0 62 | 63 | # Specify whether to capture coverage data for external source 64 | # files 65 | geninfo_external = 0 66 | 67 | # Use gcov's --all-blocks option if non-zero 68 | geninfo_gcov_all_blocks = 1 69 | 70 | # Specify if geninfo should try to automatically determine 71 | # the base-directory when collecting coverage data. 72 | geninfo_auto_base = 1 73 | 74 | 75 | 76 | 77 | 78 | # lcov configuration 79 | 80 | # Show full paths during list operation if non-zero 81 | lcov_list_full_path = 1 82 | 83 | # Specify the maximum width for list output. This value is 84 | # ignored when lcov_list_full_path is non-zero. 85 | #lcov_list_width = 80 86 | 87 | # Specify the maximum percentage of file names which may be 88 | # truncated when choosing a directory prefix in list output. 89 | # This value is ignored when lcov_list_full_path is non-zero. 90 | #lcov_list_truncate_max = 20 91 | 92 | # Specify if function coverage data should be collected and processed. 93 | lcov_function_coverage = 1 94 | 95 | # Specify if branch coverage data should be collected andprocessed. 96 | lcov_branch_coverage = 1 97 | -------------------------------------------------------------------------------- /ci/page_style/custom_format.css: -------------------------------------------------------------------------------- 1 | .coverLegendCovLo, .coverLegendCovMed, .coverLegendCovHi { 2 | border-radius: 15px; 3 | } 4 | 5 | #td.headerCovTableEntry { 6 | border-radius: 15px; 7 | } 8 | 9 | .headerCovTableEntryLo, .headerCovTableEntryMed, .headerCovTableEntryHi { 10 | border-radius: 15px; 11 | } 12 | 13 | .headerCovTableEntry { 14 | border-radius: 15px; 15 | } 16 | -------------------------------------------------------------------------------- /ci/page_style/doxygen_dark_theme/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tilen Majerle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ci/page_style/doxygen_dark_theme/README.md: -------------------------------------------------------------------------------- 1 | # Doxygen dark theme 2 | 3 | Theme implements dark colors implementation for doxygen documentation generator. Selected colors are inspiration from 4 | Sublime Text syntax highligher for C language. 5 | 6 | ## Demo 7 | 8 | Demo of the dark theme is available at https://majerle.eu/documentation/esp_at/html/index.html 9 | 10 | # How to use it 11 | 12 | Usage is very simple. You just need to modify your doxygen input file 13 | 14 | ``` 15 | # Add files to extra stylesheet 16 | 17 | HTML_EXTRA_STYLESHEET = "custom.css" \ 18 | "custom_dark_theme.css" 19 | ``` 20 | 21 | If you wish to use custom made HTML header and footer, enable this feature with 22 | 23 | ``` 24 | # Custom header 25 | HTML_HEADER = "html_header.html" 26 | 27 | # Custom footer 28 | HTML_FOOTER = "html_footer.html" 29 | ``` 30 | -------------------------------------------------------------------------------- /ci/page_style/doxygen_dark_theme/custom.css: -------------------------------------------------------------------------------- 1 | div.fragment, pre.fragment { 2 | margin: 0; 3 | padding: 4px; 4 | } 5 | 6 | /*********************************************/ 7 | /** Main content **/ 8 | /*********************************************/ 9 | .contents { 10 | margin: 10px auto !important; 11 | padding: 0 10px; 12 | max-width: 1200px; 13 | } 14 | 15 | /*********************************************/ 16 | /** Inline code **/ 17 | /*********************************************/ 18 | p code, 19 | li code, 20 | td code, 21 | dd code { 22 | display: inline; 23 | padding: 0px 6px; 24 | -webkit-border-radius: 4px; 25 | -moz-border-radius: 4px; 26 | border-radius: 4px; 27 | 28 | background-color: #CCCCCC; 29 | border: 1px solid #333333; 30 | 31 | color: #333333; 32 | } 33 | 34 | /*********************************************/ 35 | /** Table of Contents (ToC) **/ 36 | /*********************************************/ 37 | div.toc { 38 | margin: 0 !important; 39 | border-radius: 4px !important; 40 | } 41 | 42 | div.toc h3 { 43 | font-size: 150%; 44 | color: inherit; 45 | } 46 | 47 | /*********************************************/ 48 | /** Content table **/ 49 | /*********************************************/ 50 | .contents table.doxtable { 51 | margin: 0 auto; 52 | } 53 | 54 | /*********************************************/ 55 | /** Field table **/ 56 | /*********************************************/ 57 | .fieldtable { 58 | box-shadow: none !important; 59 | -webkit-box-shadow: none; 60 | -moz-box-shadow: none; 61 | } 62 | 63 | /*********************************************/ 64 | /** Memitem and memtitle **/ 65 | /*********************************************/ 66 | .memitem, 67 | .memproto, 68 | .memdoc { 69 | box-shadow: none; 70 | -webkit-box-shadow: none; 71 | -moz-box-shadow: none; 72 | background-image: none; 73 | } 74 | 75 | /*********************************************/ 76 | /** TOP navigation **/ 77 | /*********************************************/ 78 | .tablist a:hover, 79 | .tablist li.current a { 80 | text-shadow: none; 81 | -moz-text-shadow: none; 82 | -webkit-text-shadow: none; 83 | } 84 | 85 | /*********************************************/ 86 | /** H1 in textblocks **/ 87 | /*********************************************/ 88 | .textblock h1 { 89 | border-bottom: 1px solid #32363d; 90 | border-left: 3px solid #32363d; 91 | margin: 40px 0px 10px 0px; 92 | padding-bottom: 10px; 93 | padding-top: 10px; 94 | padding-left: 5px; 95 | } 96 | 97 | .textblock h1:first-child { 98 | margin-top: 10px; 99 | } 100 | 101 | /*********************************************/ 102 | /** Note, warning **/ 103 | /*********************************************/ 104 | dl.note, 105 | dl.warning, 106 | dl.todo, 107 | dl.deprecated, 108 | dl.reflist { 109 | border: 0; 110 | padding: 0px; 111 | margin: 4px 0px 4px 0px; 112 | border-radius: 4px; 113 | } 114 | 115 | dl.note dt, 116 | dl.warning dt, 117 | dl.todo dt, 118 | dl.deprecated dt, 119 | dl.reflist dt { 120 | margin: 0; 121 | font-size: 14px; 122 | padding: 2px 4px; 123 | 124 | border: none; 125 | border-top-left-radius: 0px; 126 | border-top-right-radius: 0px; 127 | 128 | font-weight: bold; 129 | text-transform: uppercase; 130 | color: #FFFFFF !important; 131 | 132 | box-shadow: none; 133 | -webkit-box-shadow: none; 134 | -moz-box-shadow: none; 135 | text-shadow: none; 136 | } 137 | 138 | dl.note dd, 139 | dl.warning dd, 140 | dl.todo dd, 141 | dl.deprecated dd, 142 | dl.reflist dd { 143 | margin: 0; 144 | padding: 4px; 145 | background: none; 146 | 147 | color: #222222; 148 | 149 | border: 1px solid; 150 | border-bottom-left-radius: 0px; 151 | border-bottom-right-radius: 0px; 152 | border-top: none; 153 | 154 | box-shadow: none; 155 | -webkit-box-shadow: none; 156 | -moz-box-shadow: none; 157 | text-shadow: none; 158 | } 159 | 160 | dl.reflist dd { 161 | margin-bottom: 15px; 162 | } 163 | 164 | /* Background colors */ 165 | dl.note { 166 | } 167 | 168 | dl.warning { 169 | } 170 | 171 | dl.todo { 172 | } 173 | 174 | dl.deprecated { 175 | } 176 | 177 | dl.reflist { 178 | } 179 | 180 | /* Header */ 181 | dl.note dt { 182 | background-color: #cbc693; 183 | } 184 | 185 | dl.warning dt { 186 | background-color: #bf5f82; 187 | } 188 | 189 | dl.todo dt { 190 | background-color: #82b3c9; 191 | } 192 | 193 | dl.deprecated dt { 194 | background-color: #af8eb5; 195 | } 196 | 197 | dl.reflist dt { 198 | background-color: #cbae82; 199 | } 200 | 201 | /* Content */ 202 | dl.note dd { 203 | background-color: #fff9c4; 204 | border-color: #cbc693; 205 | } 206 | 207 | dl.warning dd { 208 | background-color: #f48fb1; 209 | border-color: #bf5f82; 210 | } 211 | 212 | dl.todo dd { 213 | background-color: #b3e5fc; 214 | border-color: #82b3c9; 215 | } 216 | 217 | dl.deprecated dd { 218 | background-color: #e1bee7; 219 | border-color: #af8eb5; 220 | } 221 | 222 | dl.reflist dd { 223 | background-color: #ffe0b2; 224 | border-color: #cbae82; 225 | } 226 | 227 | /*********************************************/ 228 | /** Reference list **/ 229 | /**Similar to warning/note/todo/... messages**/ 230 | /*********************************************/ 231 | dl.reflist { 232 | 233 | } 234 | 235 | /*********************************************/ 236 | /** Note, warning **/ 237 | /*********************************************/ 238 | #docs_list { 239 | padding: 0 10px; 240 | } 241 | 242 | #docs_list ul { 243 | margin: 0; 244 | padding: 0; 245 | list-style: none; 246 | } 247 | 248 | #docs_list ul li { 249 | display: inline-block; 250 | border-right: 1px solid #BFBFBF; 251 | } 252 | 253 | #docs_list ul li:last-child { 254 | border-right: none; 255 | } 256 | 257 | #docs_list ul li a { 258 | display: block; 259 | padding: 8px 13px; 260 | font-weight: bold; 261 | font-size: 15px; 262 | } 263 | 264 | #docs_list ul li a:hover, 265 | #docs_list ul li a.docs_current { 266 | text-decoration: underline; 267 | } 268 | 269 | /*********************************************/ 270 | /** Resizable UI **/ 271 | /*********************************************/ 272 | .ui-resizable-e { 273 | width: 3px; 274 | } 275 | 276 | /*********************************************/ 277 | /** Download url **/ 278 | /*********************************************/ 279 | .download_url { 280 | font-weight: bold; 281 | font-size: 150%; 282 | line-height: 150%; 283 | } 284 | 285 | /*********************************************/ 286 | /** Syntax folor **/ 287 | /*********************************************/ 288 | div.line a { 289 | text-decoration: underline; 290 | } 291 | 292 | span.lineno a { 293 | text-decoration: none; 294 | } 295 | 296 | /*********************************************/ 297 | /** Modules/Directory table **/ 298 | /*********************************************/ 299 | .directory .arrow { 300 | height: initial; 301 | } 302 | 303 | .directory td.entry { 304 | padding: 3px 6px; 305 | } 306 | 307 | /*********************************************/ 308 | /** Mem items **/ 309 | /*********************************************/ 310 | .memproto table td { 311 | font-family: monospace, fixed !important; 312 | } 313 | 314 | td.memItemLeft, td.memItemRight { 315 | font-family: monospace, fixed; 316 | } 317 | 318 | .paramname, .paramname em { 319 | font-style: italic; 320 | } 321 | 322 | .memdoc { 323 | text-shadow: none; 324 | } 325 | 326 | .memItem { 327 | font-family: monospace, fixed; 328 | } 329 | 330 | .memItem table { 331 | font-family: inherit; 332 | } 333 | 334 | /*********************************************/ 335 | /** Footer **/ 336 | /*********************************************/ 337 | img.footer { 338 | height: 22px; 339 | } 340 | 341 | /*********************************************/ 342 | /** Custom scrollbar **/ 343 | /*********************************************/ 344 | 345 | /*********************************************/ 346 | /** Custom scrollbar **/ 347 | /*********************************************/ 348 | -------------------------------------------------------------------------------- /ci/page_style/doxygen_dark_theme/custom_dark_theme.css: -------------------------------------------------------------------------------- 1 | /* Light background: #3 5 3 6 2 9; */ 2 | /* New light dark background #3 2 3 6 3 d */ 3 | /* Dark background: #d f e 5 f 2; */ 4 | 5 | /* TOP MENU */ 6 | .sm-dox { 7 | background: #dfe5f2 !important; 8 | } 9 | 10 | .sm-dox a { 11 | background: none; 12 | } 13 | 14 | body { 15 | background: #282923; 16 | background-image: none; 17 | color: #D8D8D8; 18 | } 19 | 20 | div.fragment, pre.fragment { 21 | border: 1px solid #000000; 22 | background: #32363d; 23 | } 24 | 25 | a, a:link, a:visited { 26 | color: #67d8ef !important; 27 | } 28 | 29 | .highlighted { 30 | background: none !important; 31 | } 32 | 33 | a.highlighted { 34 | background: none !important; 35 | } 36 | 37 | /*********************************************/ 38 | /** Top main menu **/ 39 | /*********************************************/ 40 | #main-nav { 41 | /* display: none; */ 42 | border-bottom: 1px solid #32363d; 43 | } 44 | 45 | #main-nav .sm-dox { 46 | background: transparent !important; 47 | } 48 | 49 | .sm-dox a { 50 | text-shadow: none !important; 51 | background: transparent !important; 52 | } 53 | 54 | .sm-dox a:hover { 55 | background: #282923 !important; 56 | } 57 | 58 | .sm-dox { 59 | text-shadow: none !important; 60 | box-shadow: none !important; 61 | } 62 | 63 | .sm-dox ul { 64 | border: 1px solid #000000; 65 | background: #32363d; 66 | } 67 | 68 | .directory tr.even { 69 | background: #32363d; 70 | } 71 | 72 | 73 | /*********************************************/ 74 | /** Top search **/ 75 | /*********************************************/ 76 | #MSearchSelectWindow { 77 | border: 1px solid #000000; 78 | background: #32363d; 79 | } 80 | 81 | a.selectItem { 82 | padding: 3px; 83 | } 84 | 85 | a.SelectItem:hover { 86 | background: #282923 !important; 87 | } 88 | 89 | #MSearchResultsWindow { 90 | border: 1px solid #000000; 91 | background: #32363d; 92 | color: #67d8ef !important;; 93 | } 94 | 95 | /*********************************************/ 96 | /** Main menu **/ 97 | /*********************************************/ 98 | #nav-tree { 99 | background: transparent; 100 | } 101 | 102 | #nav-tree .selected { 103 | background-image: none; 104 | background: #32363d; 105 | } 106 | 107 | /*********************************************/ 108 | /** Main content **/ 109 | /*********************************************/ 110 | 111 | /*********************************************/ 112 | /** Inline code **/ 113 | /*********************************************/ 114 | p code, 115 | li code, 116 | td code, 117 | dd code { 118 | background-color: #000000; 119 | border: 1px solid #A8B8D9; 120 | 121 | color: #D8D8D8; 122 | } 123 | 124 | /*********************************************/ 125 | /** Table of Contents (ToC) **/ 126 | /*********************************************/ 127 | div.toc { 128 | background: #32363d; 129 | border: 1px solid #000000; 130 | } 131 | 132 | div.toc h3 { 133 | font-size: 150%; 134 | color: inherit; 135 | } 136 | 137 | /*********************************************/ 138 | /** Content table **/ 139 | /*********************************************/ 140 | table.doxtable tr:nth-child(even) td { 141 | background: #32363d; 142 | } 143 | 144 | div.header { 145 | background: transparent; 146 | border-bottom: 1px solid #32363d; 147 | } 148 | 149 | /*********************************************/ 150 | /** Field table **/ 151 | /*********************************************/ 152 | .fieldtable th { 153 | background: #282923; 154 | color: inherit; 155 | } 156 | 157 | /*********************************************/ 158 | /** Memitem and memtitle **/ 159 | /*********************************************/ 160 | .memdoc { 161 | border: 1px solid #A8B8D9; 162 | } 163 | 164 | /*********************************************/ 165 | /** TOP navigation **/ 166 | /*********************************************/ 167 | .tabs, .tabs2, .tabs3 { 168 | background: #DDDDDD; 169 | } 170 | 171 | .tablist li { 172 | background: transparent !important; 173 | } 174 | 175 | .tablist a { 176 | background-image: none; 177 | border-right: 1px solid #999999; 178 | 179 | color: #32363d; 180 | } 181 | 182 | .tablist a:hover, 183 | .tablist li.current a { 184 | text-decoration: none; 185 | color: #000000; 186 | background: #CCCCCC; 187 | background-image: none; 188 | } 189 | 190 | /*********************************************/ 191 | /** H1 in textblocks **/ 192 | /*********************************************/ 193 | 194 | /*********************************************/ 195 | /** Note, warning **/ 196 | /*********************************************/ 197 | 198 | /*********************************************/ 199 | /** Reference list **/ 200 | /**Similar to warning/note/todo/... messages**/ 201 | /*********************************************/ 202 | dl.reflist { 203 | 204 | } 205 | 206 | 207 | /*********************************************/ 208 | /** Note, warning **/ 209 | /*********************************************/ 210 | #docs_list { 211 | background: #32363d; 212 | } 213 | 214 | #docs_list ul li { 215 | border-right: 1px solid #BFBFBF; 216 | } 217 | 218 | #docs_list ul li a { 219 | color: #1b1e21; 220 | } 221 | 222 | #docs_list ul li a:hover, 223 | #docs_list ul li a.docs_current { 224 | background: #282923; 225 | } 226 | 227 | /*********************************************/ 228 | /** Resizable UI **/ 229 | /*********************************************/ 230 | .ui-resizable-e { 231 | background: #32363d; 232 | } 233 | 234 | /*********************************************/ 235 | /** Download url **/ 236 | /*********************************************/ 237 | 238 | /*********************************************/ 239 | /** Syntax folor **/ 240 | /*********************************************/ 241 | div.line { 242 | background: transparent; 243 | color: inherit; 244 | } 245 | 246 | div.line a { 247 | color: inherit; 248 | } 249 | 250 | span.keyword { 251 | color: #f92472; 252 | font-style: italic; 253 | } 254 | 255 | span.keywordtype { 256 | color: #67cfc1; 257 | font-style: italic; 258 | } 259 | 260 | span.keywordflow { 261 | color: #f92472; 262 | font-style: italic; 263 | } 264 | 265 | span.comment { 266 | color: #74705a; 267 | } 268 | 269 | span.preprocessor { 270 | color: #a6e22b; 271 | } 272 | 273 | span.stringliteral { 274 | color: #e7db74; 275 | } 276 | 277 | span.charliteral { 278 | color: #e7db74; 279 | } 280 | 281 | span.vhdldigit { 282 | color: #ff00ff; 283 | } 284 | 285 | span.vhdlchar { 286 | color: #000000; 287 | } 288 | 289 | span.vhdlkeyword { 290 | color: #700070; 291 | } 292 | 293 | span.vhdllogic { 294 | color: #ff0000; 295 | } 296 | 297 | span.lineno { 298 | background: transparent; 299 | } 300 | 301 | span.lineno a { 302 | background: transparent; 303 | } 304 | 305 | /*********************************************/ 306 | /** Modules/Directory table **/ 307 | /*********************************************/ 308 | .mdescLeft, .mdescRight, .memItemLeft, .memItemRight, 309 | .memTemplItemLeft, .memTemplItemRight, .memTemplParams { 310 | background: #32363d; 311 | color: inherit; 312 | } 313 | 314 | .memSeparator { 315 | border: none; 316 | background: transparent; 317 | } 318 | 319 | h2.groupheader { 320 | color: #67d8ef; 321 | } 322 | 323 | /*********************************************/ 324 | /** Mem items **/ 325 | /*********************************************/ 326 | .memtitle { 327 | background: #32363d !important; 328 | border-color: #000000; 329 | } 330 | 331 | .memitem { 332 | background: #32363d !important; 333 | color: inherit; 334 | text-shadow: none; 335 | } 336 | 337 | .memproto { 338 | background: inherit; 339 | border-color: #000000; 340 | color: inherit; 341 | text-shadow: none; 342 | } 343 | 344 | .memproto table td { 345 | font-family: monospace, fixed !important; 346 | } 347 | 348 | td.memItemLeft, td.memItemRight { 349 | font-family: monospace, fixed; 350 | } 351 | 352 | .paramname, .paramname em { 353 | color: #bf5f82; 354 | } 355 | 356 | .memdoc { 357 | background: inherit; 358 | border-color: #000000; 359 | } 360 | 361 | 362 | /*********************************************/ 363 | /** Footer **/ 364 | /*********************************************/ 365 | .titlearea { 366 | border-bottom: 1px solid #32363d; 367 | } 368 | 369 | /*********************************************/ 370 | /** Footer **/ 371 | /*********************************************/ 372 | #nav-path { 373 | background: transparent; 374 | } 375 | 376 | #nav-path ul { 377 | background: transparent; 378 | color: inherit; 379 | border: none; 380 | border-top: 1px solid #32363d; 381 | } 382 | 383 | .navpath li.footer { 384 | color: inherit; 385 | } 386 | 387 | .navpath li.navelem a { 388 | text-shadow: none; 389 | } 390 | 391 | /*********************************************/ 392 | /** Custom scrollbar **/ 393 | /*********************************************/ 394 | ::-webkit-scrollbar { 395 | width: 10px; 396 | } 397 | 398 | /* Track */ 399 | ::-webkit-scrollbar-track { 400 | border-radius: 10px; 401 | } 402 | 403 | /* Handle */ 404 | ::-webkit-scrollbar-thumb { 405 | background: #234567; 406 | border: none; 407 | } 408 | 409 | /* Handle on hover */ 410 | ::-webkit-scrollbar-thumb:hover { 411 | background: #32363d; 412 | } 413 | 414 | /*********************************************/ 415 | /** Custom scrollbar **/ 416 | /*********************************************/ 417 | h1.glow, h2.glow, h3.glow, 418 | h4.glow, h5.glow, h6.glow { 419 | text-shadow: 0 0 15px #67d8ef; 420 | } -------------------------------------------------------------------------------- /ci/page_style/doxygen_dark_theme/html_footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ci/page_style/doxygen_dark_theme/html_header.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $projectname: $title 10 | $title 11 | 12 | 13 | 14 | $treeview 15 | $search 16 | $mathjax 17 | 18 | $extrastylesheet 19 | 20 | 21 |
22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
33 |
$projectname 34 |  $projectnumber 35 | 36 |
37 | 38 |
$projectbrief
39 |
44 |
$projectbrief
45 |
$searchbox
56 |
57 | 58 | -------------------------------------------------------------------------------- /ci/page_style/epilog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ci/pages_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Bash color ouput 4 | # https://misc.flogisoft.com/bash/tip_colors_and_formatting 5 | 6 | # Variables used in gcovr 7 | EXCLUDED_FILES="^.*(test|lib|main.cpp|CMakeFiles)" 8 | HTML_TITLE="Code coverage ${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}" 9 | 10 | # Variables to use with lcov 11 | cp ci/lcovrc ~/.lcovrc # The coverage configuration file resides in ~/ as ~/.lcovrc 12 | PAGE_TITLE="${CI_COMMIT_REF_NAME}" 13 | 14 | # Assign the correct folder names 15 | if [[ ${CI_COMMIT_REF_NAME} == "master" ]]; 16 | then 17 | ROOT_PATH="" 18 | COVERAGE_PATH="coverage" 19 | DOCUMENT_PATH="docs" 20 | else 21 | ROOT_PATH="${CI_COMMIT_REF_NAME}" 22 | COVERAGE_PATH="coverage/${CI_COMMIT_REF_NAME}" 23 | DOCUMENT_PATH="docs/${CI_COMMIT_REF_NAME}" 24 | fi 25 | 26 | # Empty the contents from the stored cache, if any 27 | rm -rf public/${DOCUMENT_PATH}/* 28 | 29 | # Create the necessary directories 30 | mkdir -p public/${DOCUMENT_PATH} 31 | 32 | 33 | # Try to make and build the application 34 | cmake . -DCMAKE_CXX_FLAGS="-g -O0 --coverage" && make all -j4 35 | 36 | # If the command above returned something different than zero, generate only the docs 37 | if [[ $? -ne 0 ]]; 38 | then 39 | echo -e "\e[1;5;91mProgram build failed, only the documentation will be generated.\e[0m" 40 | else 41 | # Coverage generation using lcov 42 | # Generate coverage baseline 43 | lcov -q --capture --initial --directory . -o coverage_base 44 | ./tests --use-colour yes # Run the tests to generate coverage notes 45 | 46 | # In the event of test failure, generate only the documentation 47 | if [[ $? -ne 0 ]]; 48 | then 49 | echo -e "\e[1;5;91mTests failed, only documentation will be generated.\e[0m" 50 | else 51 | # Empty the contents from the stored cache, if any, and create the necessary directories 52 | rm -rf public/${COVERAGE_PATH}/* 53 | mkdir -p public/${COVERAGE_PATH} "public/${COVERAGE_PATH}/gcovr" 54 | 55 | # Generate the tracefile for the coverage reports 56 | lcov -q --capture --directory . -o coverage_tests 57 | lcov -q -a coverage_base -a coverage_tests -o coverage_total_unfiltered 58 | 59 | # Remove any unwanted files from coverage report, like external libraries 60 | lcov -q --remove coverage_total_unfiltered "${PWD}/lib/*" "${PWD}/CMakeFiles/*" "${PWD}/test/*" "${PWD}/src/main.cpp" -o coverage_total_filtered 61 | 62 | 63 | # Coverage generation using gcovr. Also generates the html page with the results 64 | # Output a summary (-s), sort by ascending percentage (-p), exclude files (-e) 65 | gcovr -s -p -e "${EXCLUDED_FILES}" --html --html-details --html-title "${HTML_TITLE}" -o public/${COVERAGE_PATH}/gcovr/gcovr.html 66 | gcovr -e "^.*(test|lib|main.cpp|CMakeFiles)" # Generate coverage report for the CI 67 | 68 | # Render the html page for the lcov results 69 | genhtml --demangle-cpp -t "${PAGE_TITLE}" --html-epilog ci/page_style/epilog.html -o public/${COVERAGE_PATH} coverage_total_filtered 70 | cp ci/page_style/custom_format.css ci/page_style/epilog.html public/${COVERAGE_PATH} 71 | 72 | echo \ 73 | " 74 | .title:after { 75 | content: \" for the ${CI_COMMIT_REF_NAME} branch\"; 76 | } 77 | " >> public/${COVERAGE_PATH}/custom_format.css 78 | fi # Test failure check 79 | fi # Build failure check 80 | 81 | 82 | # Documentation generation 83 | doxygen doxygen.conf 84 | mv docs/html/* public/${DOCUMENT_PATH} 85 | 86 | # Expired branch deletion 87 | git branch -a | grep "remote" | xargs -n 1 -i sh -c "path=\"{}\"; basename \"\$path\"" > branches_list 88 | ls -d public/coverage/*/ | xargs -n 1 -i sh -c "name=\"{}\"; basename \"\$name\"" > directory_list 89 | 90 | # Condition the directory list (Remove unwanted instances) 91 | sed -i -e '/gcovr/d;/inc/d;/src/d' directory_list 92 | 93 | # Output for debugging purposes 94 | echo -e "\e[1;36mBranch names list\e[0m" 95 | cat branches_list 96 | 97 | echo -e "\n\e[1;36mPublic directory contents list\e[0m" 98 | cat directory_list 99 | 100 | 101 | # Remove any expired branch folders 102 | while read directory; 103 | do 104 | if ! grep -q "^${directory}$" branches_list 105 | then 106 | echo -e "\e[1;33m${directory} will be removed from the pages.\e[0m" 107 | rm -rf "public/${directory}" "public/coverage/${directory}" "public/docs/${directory}" 108 | fi 109 | done < directory_list 110 | 111 | echo -e "\e[1;92mDocumentation page for this branch:\e[0m \e[0;36m${CI_PAGES_URL}/${DOCUMENT_PATH}\e[0m" 112 | echo -e "\e[1;92mCoverage Reports page for this branch:\e[0m \e[0;36m${CI_PAGES_URL}/${COVERAGE_PATH}\e[0m\n" 113 | -------------------------------------------------------------------------------- /ci/summarizer.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python3 2 | 3 | import os 4 | from argparse import ArgumentParser 5 | 6 | """ 7 | Naive parser and pretty printer for the MISRA reports by cppcheck. 8 | 9 | Usage: 10 | python3 summarizer.py --report 11 | --suppress (as they are given on the 12 | MISRA handbook) 13 | 14 | e.g.: python3 summarizer.py --report ci/report.msr --suppress 5.2 10.4 15.5 15 | 16 | You can also mark lines you wish to be skipped by adding 17 | "// Ignore-MISRA" at a suitable position on the line you want to ignore 18 | from assessing (NOTE: the double slashes are part of the string!) 19 | 20 | (Credits to @dimst23 for the feature!) 21 | 22 | TODO: Keep track of line numbers and filenames of suppressed lines. 23 | """ 24 | 25 | 26 | class Summarizer(object): 27 | def __init__(self, report_name, suppression_list): 28 | with open(report_name, 'r') as f: 29 | self.file_lines = f.readlines() # read the report file 30 | f.close() 31 | 32 | self.red = "\033[91m" # terminal colors 33 | self.yellow = "\033[93m" 34 | self.green = "\033[92m" 35 | self.bold = "\033[1m" 36 | self.end = "\033[0m" 37 | 38 | self.violations_map = {} # dictionary containing filenames, rule violations and line where the violation 39 | # occurred 40 | self.suppression_list = suppression_list # list of rule numbers to be suppressed 41 | 42 | def analyze(self): 43 | """ 44 | A really dumb parser for the pre-processed report generated by cppcheck 45 | """ 46 | 47 | lines_seen = set() # contains the unique lines from the file 48 | 49 | for line in self.file_lines: # remove duplicate lines 50 | if line not in lines_seen: 51 | lines_seen.add(line) 52 | 53 | line_contents = line.split(':') 54 | file_name = line_contents[0] # first part is the filename (index 0) 55 | violation = (line_contents[1], line_contents[2].strip( 56 | '\n')) # index 1 is the line number, index 2 is the number of violated rule (both are strings) 57 | 58 | with open(os.path.abspath(file_name)) as code_file: 59 | code_lines = code_file.readlines() # Read the source code file 60 | line_of_interest = code_lines[int(violation[0]) - 1] # Get the desired violation line 61 | if line_of_interest.find("// Ignore-MISRA") >= 0 or line_of_interest.find("/* Ignore-MISRA */") >= 0: 62 | continue 63 | 64 | if file_name not in self.violations_map.keys(): 65 | self.violations_map[ 66 | file_name] = list() # create a new list for the new filename and append the tuple w/ line & 67 | # rule no. 68 | self.violations_map[file_name].append(violation) 69 | else: 70 | self.violations_map[file_name].append(violation) # do not create a key if it already exists 71 | 72 | for e in self.suppression_list: 73 | for file_name in self.violations_map.keys(): 74 | self.violations_map[file_name] = [x for x in self.violations_map[file_name] if x[1] != str(e)] 75 | # replace the list of infractions with a new one, containing everything except the suppressed rules 76 | 77 | self.violations_map = {k: v for (k, v) in self.violations_map.items() if len(v) != 0} 78 | # "delete" all keys whose lists are empty 79 | 80 | def pretty_print_violations(self): 81 | """ 82 | Just a pretty printing function, no fancy logic here. 83 | """ 84 | print(self.bold + self.red + "=========================================================\n" + self.end) 85 | print(self.bold + self.red + " Static analysis results: Infraction summary \n" + self.end) 86 | for file_name in self.violations_map: 87 | print("") 88 | for violation in sorted(self.violations_map[file_name], key=lambda x: int(x[0])): 89 | name_string = f"{self.bold}{self.red}File {self.yellow}{file_name}{self.red}" 90 | rule_violated_string = f"violates rule {self.yellow}#{violation[1]}{self.red} " \ 91 | f"of the MISRA C 2012 standard" 92 | line_number_string = f"at line {self.yellow}{violation[0]}{self.end}" 93 | 94 | print(f"{name_string.ljust(75)} {rule_violated_string} {line_number_string}") 95 | 96 | print("") 97 | print("") 98 | print(self.bold + self.red + "=================================================" + self.end) 99 | 100 | def suppression_info(self): 101 | """ 102 | Pretty-prints the suppressed rule numbers. 103 | """ 104 | if (len(self.suppression_list) != 0): 105 | print("\n") 106 | print(self.bold + self.yellow + "WARNING: Suppressed infractions of rules: ", end="") 107 | print(f", ".join(self.suppression_list), end=".") 108 | print("") 109 | print("") 110 | else: 111 | print(self.bold + self.green + "All available rules enforced - no suppressions") 112 | 113 | 114 | if __name__ == "__main__": 115 | cli = ArgumentParser() 116 | cli.add_argument("--report", nargs=1, default="./report.msr") 117 | cli.add_argument("--suppress", nargs="*", type=str, default="") 118 | 119 | args = cli.parse_args() 120 | s = Summarizer(str(args.report[0]), args.suppress) 121 | s.analyze() 122 | s.suppression_info() 123 | 124 | if len(s.violations_map) != 0: 125 | s.pretty_print_violations() 126 | exit(127) 127 | elif len(s.violations_map) == 0: 128 | print(s.bold + s.green + "Static analysis for MISRA compliance complete. No infractions found." + s.end) 129 | exit(0) 130 | -------------------------------------------------------------------------------- /ci/vera.profile: -------------------------------------------------------------------------------- 1 | 2 | set rules { 3 | F001 4 | F002 5 | L001 6 | L003 7 | L004 8 | L005 9 | L006 10 | T001 11 | T002 12 | T004 13 | T005 14 | T006 15 | T007 16 | T008 17 | T009 18 | T010 19 | T012 20 | T015 21 | T016 22 | T017 23 | T018 24 | T019 25 | } 26 | -------------------------------------------------------------------------------- /ci/vera.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Code style checks using vera++ 5 | # 6 | # Usage: 7 | # $ ci/vera.sh 8 | # 9 | 10 | echo -e "\033[0;34mRunning vera++...\033[0m" 11 | 12 | cd "$(dirname "$0")/.." 13 | vera++ --error --parameter max-line-length=120 --profile custom \ 14 | `find src inc test -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)' -not -wholename 'inc/Logger.hpp'` 15 | -------------------------------------------------------------------------------- /inc/Alert.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum ServiceChannelNotification : int { 4 | NO_SERVICE_EVENT = 0x01, 5 | MAP_CHANNEL_FRAME_BUFFER_FULL = 0x02, 6 | MASTER_CHANNEL_FRAME_BUFFER_FULL = 0x03, 7 | VC_MC_FRAME_BUFFER_FULL = 0x04, 8 | TX_MC_FRAME_BUFFER_FULL = 0x05, 9 | NO_TX_PACKETS_TO_PROCESS = 0x06, 10 | NO_RX_PACKETS_TO_PROCESS = 0x07, 11 | PACKET_EXCEEDS_MAX_SIZE = 0x08, 12 | FOP_SENT_QUEUE_FULL = 0x09, 13 | TX_TO_BE_TRANSMITTED_FRAMES_LIST_EMPTY = 0x0A, 14 | TX_TO_BE_TRANSMITTED_FRAMES_LIST_FULL = 0x0B, 15 | FOP_REQUEST_REJECTED = 0x0C, 16 | RX_IN_MC_FULL = 0x0D, 17 | RX_IN_BUFFER_FULL = 0x0E, 18 | RX_OUT_BUFFER_FULL = 0x0F, 19 | RX_INVALID_TFVN = 0x10, 20 | RX_INVALID_SCID = 0x11, 21 | RX_INVALID_LENGTH = 0x12, 22 | VC_RX_WAIT_QUEUE_FULL = 0x13, 23 | TX_FOP_REJECTED = 0x14, 24 | VC_MC_FRAME_BUFFER_EMPTY = 0x15, 25 | INVALID_VC_ID = 0x16, 26 | INVALID_MAP_ID = 0x17, 27 | VC_RECEPTION_BUFFER_AFTER_FARM_FULL = 0x18, 28 | NO_PACKETS_TO_PROCESS_IN_VC_RECEPTION_BEFORE_FARM = 0x19, 29 | RX_INVALID_CRC = 0x1A, 30 | INVALID_SERVICE_CALL = 0x1B, 31 | PACKET_BUFFER_EMPTY = 0x1C, 32 | NO_TX_PACKETS_TO_TRANSFER_FRAME = 0x1D, 33 | MC_RX_INVALID_COUNT = 0x1E, 34 | MEMORY_POOL_FULL = 0x1F, 35 | }; 36 | 37 | enum SynchronizationFlag : bool { OCTET = 0, FORWARD_ORDERED = 1 }; 38 | 39 | enum FOPNotification : uint8_t { 40 | NO_FOP_EVENT = 0x01, 41 | SENT_QUEUE_FULL = 0x02, 42 | WAIT_QUEUE_EMPTY = 0x03, 43 | }; 44 | 45 | enum COPDirectiveResponse : uint8_t { 46 | ACCEPT = 0x01, 47 | REJECT = 0x02, 48 | }; 49 | 50 | enum VirtualChannelAlert : uint8_t { 51 | NO_VC_ALERT = 0x01, 52 | UNPROCESSED_PACKET_LIST_FULL = 0x02, 53 | TX_WAIT_QUEUE_FULL = 0x03, 54 | RX_WAIT_QUEUE_FULL = 0x04, 55 | }; 56 | 57 | enum MasterChannelAlert : uint8_t { 58 | NO_MC_ALERT = 0x01, 59 | OUT_FRAMES_LIST_FULL = 0x02, 60 | TO_BE_TRANSMITTED_FRAMES_LIST_FULL = 0x03, 61 | MAX_AMOUNT_OF_VIRT_CHANNELS = 0x04, 62 | NO_SPACE = 0x05 63 | }; 64 | 65 | enum TxRx : uint8_t { Rx = 0x00, Tx = 0x01 }; 66 | 67 | enum NotificationType : uint8_t { 68 | 69 | TypeVirtualChannelAlert = 0x00, 70 | TypeMasterChannelAlert = 0x01, 71 | TypeServiceChannelNotif = 0x02, 72 | TypeCOPDirectiveResponse = 0x03, 73 | TypeFOPNotif = 0x04, 74 | TypeFDURequestType = 0x05 75 | 76 | }; 77 | -------------------------------------------------------------------------------- /inc/CCSDSChannel.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CCSDS_CHANNEL_HPP 2 | #define CCSDS_CHANNEL_HPP 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "MemoryPool.hpp" 19 | #include "CLCW.hpp" 20 | 21 | class MasterChannel; 22 | 23 | /** 24 | * @see Table 5-1 from TC SPACE DATA LINK PROTOCOL 25 | */ 26 | struct PhysicalChannel { 27 | private: 28 | /** 29 | * Maximum length of a single transfer frame 30 | */ 31 | const uint16_t maxFrameLength; 32 | 33 | /** 34 | * Sets the maximum number of transfer frames that can be transferred in a single data unit 35 | */ 36 | const uint16_t maxFramePdu; 37 | 38 | /** 39 | * Maximum length of a data unit 40 | */ 41 | const uint16_t maxPDULength; 42 | 43 | /** 44 | * Maximum bit rate (bits per second) 45 | */ 46 | const uint32_t bitrate; 47 | 48 | /** 49 | * Maximum number of retransmissions for a data unit 50 | */ 51 | const uint16_t repetitions; 52 | 53 | public: 54 | PhysicalChannel(const uint16_t maxFrameLength, const uint16_t maxFramesPdu, const uint16_t maxPduLength, 55 | const uint32_t bitrate, const uint16_t repetitions) 56 | : maxFrameLength(maxFrameLength), maxFramePdu(maxFramesPdu), maxPDULength(maxPduLength), bitrate(bitrate), 57 | repetitions(repetitions) {} 58 | 59 | uint16_t getMaxFrameLength() const { 60 | return maxFrameLength; 61 | } 62 | 63 | /** 64 | * Empty default constructor 65 | */ 66 | PhysicalChannel() : maxFrameLength(0), maxFramePdu(0), maxPDULength(0), bitrate(0), repetitions(0) {} 67 | 68 | /** 69 | * Sets the maximum number of transfer frames that can be transferred in a single data unit 70 | */ 71 | uint16_t getMaxFramePdu() const { 72 | return maxFramePdu; 73 | }; 74 | 75 | /** 76 | * Maximum length of a data unit 77 | */ 78 | uint16_t getMaxPDULength() const { 79 | return maxPDULength; 80 | }; 81 | 82 | /** 83 | * Maximum bit rate (bits per second) 84 | */ 85 | uint32_t getBitrate() const { 86 | return bitrate; 87 | }; 88 | 89 | /** 90 | * Maximum number of retransmissions for a data unit 91 | */ 92 | uint16_t getRepetitions() const { 93 | return repetitions; 94 | } 95 | }; 96 | 97 | /** 98 | * @see Table 5-4 from TC SPACE DATA LINK PROTOCOL 99 | */ 100 | class MAPChannel { 101 | friend class ServiceChannel; 102 | 103 | private: 104 | /** 105 | * MAP Channel Identifier 106 | */ 107 | const uint8_t MAPID; // 6 bits 108 | 109 | public: 110 | template 111 | void storeMAPChannel(TransferFrameType packet); 112 | 113 | /** 114 | * Returns availableBufferTC space in the MAP Channel buffer 115 | */ 116 | uint16_t availableBufferTC() const { 117 | return unprocessedFrameListBufferTC.available(); 118 | } 119 | 120 | /** 121 | * Returns availableBufferTM space in the MAP Channel buffer 122 | */ 123 | uint16_t availableBufferTM() const { 124 | return unprocessedFrameListBufferTM.available(); 125 | } 126 | 127 | MAPChannel(const uint8_t mapid, bool blockingTC, bool segmentationTC) 128 | : MAPID(mapid), blockingTC(blockingTC), segmentationTC(segmentationTC) { 129 | uint8_t d = unprocessedFrameListBufferTC.size(); 130 | unprocessedFrameListBufferTC.full(); 131 | }; 132 | 133 | protected: 134 | bool blockingTC; 135 | bool segmentationTC; 136 | 137 | /** 138 | * Store unprocessed received TCs 139 | */ 140 | etl::list unprocessedFrameListBufferTC; 141 | /** 142 | * Store unprocessed received TMs 143 | * TODO i don't think that this should exist,since MAP channels exist for TC Frames only 144 | */ 145 | etl::list unprocessedFrameListBufferTM; 146 | /** 147 | * Store frames before being extracted 148 | */ 149 | etl::list inFramesAfterVCReceptionRxTC; 150 | /** 151 | * @brief Queue that stores the pointers of the packets that will eventually be concatenated to transfer frame data. 152 | * Applicable to Type-A Frames 153 | */ 154 | etl::queue packetLengthBufferTxTcTypeA; 155 | 156 | /** 157 | * @brief Queue that stores the packets that will eventually be concatenated to transfer frame data. 158 | * Applicable to Type-A Frames 159 | */ 160 | etl::queue packetBufferTxTcTypeA; 161 | /** 162 | * @brief Queue that stores the pointers of the packets that will eventually be concatenated to transfer frame data. 163 | * Applicable to Type-B Frames 164 | */ 165 | etl::queue packetLengthBufferTxTcTypeB; 166 | 167 | /** 168 | * @brief Queue that stores the packets that will eventually be concatenated to transfer frame data. 169 | * Applicable to Type-A Frames 170 | */ 171 | etl::queue packetBufferTxTcTypeB; 172 | }; 173 | 174 | /** 175 | * @see Table 5-3 from TC SPACE DATA LINK PROTOCOL 176 | */ 177 | class VirtualChannel { 178 | friend class ServiceChannel; 179 | 180 | friend class MasterChannel; 181 | 182 | friend class FrameOperationProcedure; 183 | 184 | // TODO: Those variables shouldn't be public 185 | public: 186 | /** 187 | * Virtual Channel Identifier 188 | */ 189 | const uint8_t VCID; // 6 bits 190 | 191 | /** 192 | * Global Virtual Channel Identifier 193 | */ 194 | const uint16_t GVCID; // 16 bits (assumes TFVN is set to 0) 195 | 196 | /** 197 | * Determines whether the Segment Header is present (enables MAP services) 198 | */ 199 | const bool segmentHeaderPresent; 200 | 201 | /** 202 | * Maximum length of a single transfer frame 203 | */ 204 | const uint16_t maxFrameLengthTC; 205 | 206 | /** 207 | * Determines whether smaller data units can be combined into a single transfer frame 208 | */ 209 | const bool blocking; 210 | 211 | /** 212 | * Determines the maximum number of times Type A frames will be re-transmitted 213 | */ 214 | const uint8_t repetitionTypeAFrame; 215 | 216 | /** 217 | * Determines the maximum number of times Type B frames will be re-transmitted 218 | */ 219 | const uint8_t repetitionTypeBFrame; 220 | 221 | /** 222 | * Determines the number of times a frame will be repeated in transmission in the Physical Layer 223 | */ 224 | const uint8_t vcRepetitions; 225 | 226 | /** 227 | * Determines the number of TM Transfer Frames transmitted 228 | */ 229 | uint8_t frameCountTM; 230 | 231 | /** 232 | * Returns availableVCBufferTC space in the VC TC buffer 233 | */ 234 | uint16_t availableBufferTC() const { 235 | return unprocessedFrameListBufferVcCopyTxTC.available(); 236 | } 237 | 238 | /** 239 | * Returns availableVCBufferTC space in the VC TC buffer 240 | */ 241 | uint16_t availableFramesVcCopyRxTM() const { 242 | return framesAfterMcReceptionRxTM.available(); 243 | } 244 | 245 | /** 246 | * Defines whether the OCF service is present 247 | */ 248 | const bool operationalControlFieldTMPresent; 249 | 250 | /** 251 | * Defines whether the ECF service is present 252 | */ 253 | const bool frameErrorControlFieldPresent; 254 | 255 | /** 256 | * Defines whether octet or forward-ordered synchronization is used 257 | */ 258 | const SynchronizationFlag synchronization; 259 | 260 | /** 261 | * Indicates whether secondary header is present in this VC 262 | */ 263 | const bool secondaryHeaderTMPresent; 264 | 265 | /** 266 | * Indicates the length of the secondary header for this VC. If secondary header is disabled for this VC, 267 | * it is ignored 268 | */ 269 | const uint8_t secondaryHeaderTMLength; 270 | 271 | /** 272 | * 273 | * MAP channels of the virtual channel 274 | */ 275 | etl::flat_map mapChannels; 276 | 277 | uint16_t availablePacketLengthBufferTxTM() { 278 | return packetLengthBufferTxTM.available(); 279 | } 280 | 281 | uint16_t availablePacketBufferTxTM() { 282 | return packetBufferTxTM.available(); 283 | } 284 | 285 | VirtualChannel(std::reference_wrapper masterChannel, const uint8_t vcid, 286 | const bool segmentHeaderPresent, const uint16_t maxFrameLength, const bool blockingTC, 287 | const uint8_t repetitionTypeAFrame, const uint8_t repetitionTypeBFrame, 288 | const bool secondaryHeaderTMPresent, const uint8_t secondaryHeaderTMLength, 289 | const bool operationalControlFieldTMPresent, bool frameErrorControlFieldPresent, 290 | const SynchronizationFlag synchronization, const uint8_t farmSlidingWinWidth, 291 | const uint8_t farmPositiveWinWidth, const uint8_t farmNegativeWinWidth, const uint8_t vcRepetitions, 292 | etl::flat_map mapChan) 293 | : masterChannel(masterChannel), VCID(vcid & 0x3FU), GVCID((MCID << 0x06U) + VCID), 294 | secondaryHeaderTMPresent(secondaryHeaderTMPresent), secondaryHeaderTMLength(secondaryHeaderTMLength), 295 | segmentHeaderPresent(segmentHeaderPresent), maxFrameLengthTC(maxFrameLength), blocking(blockingTC), 296 | repetitionTypeAFrame(repetitionTypeAFrame), vcRepetitions(vcRepetitions), 297 | repetitionTypeBFrame(repetitionTypeBFrame), waitQueueTxTC(), sentQueueTxTC(), waitQueueRxTC(), 298 | sentQueueRxTC(), frameErrorControlFieldPresent(frameErrorControlFieldPresent), 299 | operationalControlFieldTMPresent(operationalControlFieldTMPresent), synchronization(synchronization), 300 | currentlyProcessedCLCW(0), frameCountTM(0), 301 | fop(FrameOperationProcedure(this, &waitQueueTxTC, &sentQueueTxTC, repetitionTypeBFrame)), 302 | farm(FrameAcceptanceReporting(this, &waitQueueRxTC, &sentQueueRxTC, farmSlidingWinWidth, farmPositiveWinWidth, 303 | farmNegativeWinWidth)) { 304 | mapChannels = mapChan; 305 | } 306 | 307 | VirtualChannel(const VirtualChannel& v) 308 | : VCID(v.VCID), GVCID(v.GVCID), segmentHeaderPresent(v.segmentHeaderPresent), 309 | maxFrameLengthTC(v.maxFrameLengthTC), repetitionTypeAFrame(v.repetitionTypeAFrame), 310 | repetitionTypeBFrame(v.repetitionTypeBFrame), vcRepetitions(v.vcRepetitions), frameCountTM(v.frameCountTM), 311 | waitQueueTxTC(v.waitQueueTxTC), sentQueueTxTC(v.sentQueueTxTC), waitQueueRxTC(v.waitQueueRxTC), 312 | sentQueueRxTC(v.waitQueueRxTC), unprocessedFrameListBufferVcCopyTxTC(v.unprocessedFrameListBufferVcCopyTxTC), 313 | fop(v.fop), farm(v.farm), masterChannel(v.masterChannel), blocking(v.blocking), 314 | synchronization(v.synchronization), secondaryHeaderTMPresent(v.secondaryHeaderTMPresent), 315 | secondaryHeaderTMLength(v.secondaryHeaderTMLength), 316 | frameErrorControlFieldPresent(v.frameErrorControlFieldPresent), 317 | operationalControlFieldTMPresent(v.operationalControlFieldTMPresent), mapChannels(v.mapChannels), 318 | currentlyProcessedCLCW(0) { 319 | fop.vchan = this; 320 | fop.sentQueueFOP = &sentQueueTxTC; 321 | fop.waitQueueFOP = &waitQueueTxTC; 322 | fop.sentQueueFARM = &sentQueueRxTC; 323 | fop.waitQueueFARM = &sentQueueRxTC; 324 | farm.waitQueue = &waitQueueRxTC; 325 | farm.sentQueue = &sentQueueRxTC; 326 | } 327 | 328 | VirtualChannelAlert storeVC(TransferFrameTC* transferFrameTc); 329 | 330 | /** 331 | * @bried Add MAP channel to virtual channel 332 | */ 333 | VirtualChannelAlert add_map(const uint8_t mapid); 334 | 335 | MasterChannel& master_channel() { 336 | return masterChannel; 337 | } 338 | 339 | private: 340 | /** 341 | * TM transfer frames after being processed by the MasterChannelReception Service 342 | */ 343 | etl::list framesAfterMcReceptionRxTM; 344 | 345 | /** 346 | * Buffer to store incoming transfer frames BEFORE being processed by COP 347 | */ 348 | etl::list waitQueueTxTC; 349 | 350 | /** 351 | * Buffer to store incoming transfer frames BEFORE being processed by COP 352 | */ 353 | etl::list waitQueueRxTC; 354 | 355 | /** 356 | * Buffer to store outcoming transfer frames AFTER being processed by COP 357 | */ 358 | etl::list sentQueueTxTC; 359 | 360 | /** 361 | * Buffer to storeOut outcoming transfer frames AFTER being processed by COP 362 | */ 363 | etl::list sentQueueRxTC; 364 | 365 | /** 366 | * Buffer to store incoming transfer frames AFTER being processed by FARM 367 | */ 368 | etl::list inFramesAfterVCReceptionRxTC; 369 | 370 | /** 371 | * Buffer to storeOut unprocessed transfer frames that are directly processed in the virtual instead of MAP channel 372 | */ 373 | etl::list unprocessedFrameListBufferVcCopyTxTC; 374 | 375 | /** 376 | * Holds the FOP state of the virtual channel 377 | */ 378 | FrameOperationProcedure fop; 379 | 380 | /** 381 | * Buffer holding the master copy of the CLCW that is currently being processed 382 | */ 383 | CLCW currentlyProcessedCLCW; 384 | 385 | /** 386 | * Holds the FARM state of the virtual channel 387 | */ 388 | FrameAcceptanceReporting farm; 389 | 390 | /** 391 | * The Master Channel the Virtual Channel belongs in 392 | */ 393 | std::reference_wrapper masterChannel; 394 | 395 | /** 396 | * Queue that stores the pointers of the packets that will eventually be concatenated to transfer frame data. 397 | */ 398 | etl::queue packetLengthBufferTxTM; 399 | 400 | /** 401 | * Queue that stores the packet data that will eventually be concatenated to transfer frame data 402 | */ 403 | etl::queue packetBufferTxTM; 404 | }; 405 | 406 | struct MasterChannel { 407 | friend class ServiceChannel; 408 | 409 | friend class FrameOperationProcedure; 410 | 411 | friend class FrameAcceptanceReporting; 412 | 413 | /** 414 | * Virtual channels of the master channel 415 | */ 416 | // TODO: Type aliases because this is getting out of hand 417 | etl::flat_map virtualChannels; 418 | uint8_t frameCount{}; 419 | 420 | MasterChannel() 421 | : virtualChannels(), toBeTransmittedFramesAfterAllFramesGenerationListTxTC(), 422 | outFramesBeforeAllFramesGenerationListTxTC(), currFrameCountTM(0) {} 423 | 424 | MasterChannel(const MasterChannel& m) 425 | : virtualChannels(m.virtualChannels), frameCount(m.frameCount), 426 | outFramesBeforeAllFramesGenerationListTxTC(m.outFramesBeforeAllFramesGenerationListTxTC), 427 | toBeTransmittedFramesAfterAllFramesGenerationListTxTC( 428 | m.toBeTransmittedFramesAfterAllFramesGenerationListTxTC), 429 | masterCopyRxTC(m.masterCopyRxTC), masterCopyRxTM(m.masterCopyRxTM), currFrameCountTM(m.currFrameCountTM) { 430 | for (auto& vc : virtualChannels) { 431 | vc.second.masterChannel = *this; 432 | } 433 | } 434 | 435 | /** 436 | * 437 | * @param transferFrameTm TM 438 | * stores TM transfer frames in order to be processed by the All Frames Generation Service 439 | */ 440 | MasterChannelAlert storeOut(TransferFrameTM* transferFrameTm); 441 | 442 | /** 443 | * 444 | * @param transferFrameTm TM 445 | * stores TM transfer frames after they have been processed by the All Frames Generation Service 446 | */ 447 | MasterChannelAlert storeTransmittedOut(TransferFrameTM* transferFrameTm); 448 | 449 | /** 450 | * Keeps track of last master channel frame count. If lost frames in a master channel are detected, then a warning 451 | * is logged. However, this isn't considered a reason for raising an error as per CCSDS TM Data Link. 452 | * Upon initialization of the channel, a MC count of 0 is expected. 453 | */ 454 | uint8_t currFrameCountTM; 455 | 456 | /** 457 | * 458 | * @param transferFrameTc TC 459 | * stores TC transfer frames in order to be processed by the All Frames Generation Service 460 | */ 461 | MasterChannelAlert storeOut(TransferFrameTC* transferFrameTc); 462 | 463 | /** 464 | * 465 | * @param transferFrameTc TC 466 | * stores TC transfer frames after they have been processed by the All Frames Generation Service 467 | */ 468 | MasterChannelAlert storeTransmittedOut(TransferFrameTC* transferFrameTc); 469 | 470 | /** 471 | * Returns the last stored Transfer Frame in txMasterCopyTc 472 | */ 473 | TransferFrameTC getLastTxMasterCopyTcFrame(); 474 | 475 | /** 476 | * Returns the first stored Transfer Frame in masterCopyTxTC 477 | */ 478 | TransferFrameTC geFirstTxMasterCopyTcFrame(); 479 | 480 | /** 481 | * Add virtual channel to master channel 482 | */ 483 | MasterChannelAlert addVC(const uint8_t vcid, const uint16_t maxFrameLength, const bool blocking, 484 | const uint8_t repetitionTypeAFrame, const uint8_t repetitionTypeBFrame, 485 | const bool frameErrorControlFieldPresent, const bool secondaryHeaderTMPresent, 486 | const uint8_t secondaryHeaderTMLength, const bool operationalControlFieldTMPresent, 487 | SynchronizationFlag synchronization, const uint8_t farmSlidingWinWidth, 488 | const uint8_t farmPositiveWinWidth, const uint8_t farmNegativeWinWidth, 489 | const uint8_t vcRepetitions, etl::flat_map mapChan); 490 | 491 | /** 492 | * Add virtual channel to master channel 493 | */ 494 | MasterChannelAlert addVC(const uint8_t vcid, const uint16_t maxFrameLength, const bool blocking, 495 | const uint8_t repetitionTypeAFrame, const uint8_t repetitionCopCtrl, 496 | const bool frameErrorControlFieldPresent, const bool secondaryHeaderTMPresent, 497 | const uint8_t secondaryHeaderTMLength, const bool operationalControlFieldTMPresent, 498 | SynchronizationFlag synchronization, const uint8_t farmSlidingWinWidth, 499 | const uint8_t farmPositiveWinWidth, const uint8_t farmNegativeWinWidth, 500 | const uint8_t vcRepetitions); 501 | 502 | private: 503 | // TC transfer frames stored in frames list, before being processed by the all frames generation service 504 | etl::list outFramesBeforeAllFramesGenerationListTxTC; 505 | // TC transfer frames ready to be transmitted having passed through the all frames generation service 506 | etl::list toBeTransmittedFramesAfterAllFramesGenerationListTxTC; 507 | 508 | // TM transfer frames stored in frames list, before being processed by the vc generation service 509 | etl::list txOutFramesBeforeMCGenerationListTM; 510 | // TM transfer frames ready to be transmitted having passed through the vc generation service 511 | etl::list toBeTransmittedFramesAfterMCGenerationListTxTM; 512 | 513 | // TM transfer frames stored in frames list, before being processed by the vc reception service 514 | etl::list txOutFramesBeforeMCReceptionListTM; 515 | // TM transfer frames ready to be transmitted having passed through the vc reception service 516 | // TODO seems unused 517 | etl::list txToBeTransmittedFramesAfterMCReceptionListTM; 518 | 519 | // TM transfer frames stored in frames list, before being processed by the all frames generation service 520 | // TODO seems redundant 521 | etl::list txOutFramesBeforeAllFramesGenerationListTM; 522 | // TM transfer frames ready to be transmitted having passed through the all frames generation service 523 | // TODO Just like the other chains, TM TX ends by assigning the frame to a pointer 524 | // TODO and the frame is deleted from the master Copy buffer (look allFramesGenerationRequestTxTM). 525 | // TODO Therefore, this buffer is not needed. 526 | etl::list toBeTransmittedFramesAfterAllFramesGenerationListTxTM; 527 | 528 | // TC transfer frames that are received, before being received by the all frames reception service 529 | etl::list inFramesBeforeAllFramesReceptionListRxTC; 530 | // TM transfer frames that are ready to be transmitted to higher procedures following all frames generation service 531 | // @TODO seems redundant. No service is using it, there is already the wait Queue and a master copy buffer exists 532 | etl::list toBeTransmittedFramesAfterAllFramesReceptionListRxTC; 533 | 534 | // Buffer to store TM transfer frames that are processed by VC Generation services 535 | etl::list framesAfterVcGenerationServiceTxTM; 536 | 537 | /** 538 | * Buffer holding the master copy of TC TX transfer frames that are currently being processed 539 | */ 540 | etl::list masterCopyTxTC; 541 | 542 | /** 543 | * Removes TC transfer frames from the Tx master buffer 544 | */ 545 | void removeMasterTx(TransferFrameTC* frame_ptr); 546 | 547 | /** 548 | * Buffer holding the master copy of TM TX transfer frames that are currently being processed 549 | */ 550 | etl::list masterCopyTxTM; 551 | 552 | /** 553 | * Removes TM transfer frames from the Tx master buffer 554 | */ 555 | void removeMasterTx(TransferFrameTM* frame_ptr); 556 | 557 | /** 558 | * Buffer holding the master copy of TC RX transfer frames that are currently being processed (held up until 559 | * packet extraction, or discarded upon all frames generation in case they are invalid) 560 | */ 561 | etl::list masterCopyRxTC; 562 | 563 | /** 564 | * Removes TC transfer frames from the Rx master buffer 565 | */ 566 | void removeMasterRx(TransferFrameTC* frame_ptr); 567 | 568 | /** 569 | * Buffer holding the master copy of TM RX transfer frames that are currently being processed 570 | */ 571 | etl::list masterCopyRxTM; 572 | 573 | /** 574 | * Removes TM frames from the RX master buffer 575 | */ 576 | void removeMasterRx(TransferFrameTM* frame_ptr); 577 | 578 | /** 579 | * Sets the acknowledgement flag of a transfer frame to true 580 | */ 581 | void acknowledgeFrame(uint8_t frameSequenceNumber); 582 | 583 | /** 584 | * Sets the toBeRetransmitted flag of a transfer frame to true 585 | */ 586 | void setRetransmitFrame(uint8_t frameSequenceNumber); 587 | 588 | MemoryPool masterChannelPoolTM = MemoryPool(); 589 | MemoryPool masterChannelPoolTC = MemoryPool(); 590 | }; 591 | 592 | #endif // CCSDS_CHANNEL_HPP 593 | -------------------------------------------------------------------------------- /inc/CCSDSLogger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | void ccsdsLogNotice(TxRx txRx, NotificationType notificationType, MyNotif Notif); 5 | -------------------------------------------------------------------------------- /inc/CCSDSLoggerImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "etl/basic_string.h" 8 | #include "Logger.hpp" 9 | 10 | /** 11 | * Allows to log additional data of interest 12 | * 13 | * @note The CCSDS standards define the error handling procedures of the CCSDS Services. Currently, 14 | * the logger is simply used for extra observability and that is why the log level is restricted to 15 | * that of a notice 16 | */ 17 | template 18 | void ccsdsLogNotice(TxRx txRx, NotificationType notificationType, CCSDSNotification Notif, T message) { 19 | LOG_NOTICE << txRx << ":" << notificationType << ":" << Notif << ":" << message; 20 | } 21 | 22 | template 23 | void ccsdsLogNotice(TxRx txRx, NotificationType notificationType, CCSDSNotification Notif) { 24 | switch (log_verbose) { 25 | case 0: 26 | LOG_NOTICE << txRx << ":" << notificationType << ":" << Notif; 27 | break; 28 | case 1: 29 | uint16_t a; 30 | a = (static_cast(txRx) << 8U) | (static_cast(notificationType) << 5U) | 31 | (static_cast(Notif)); 32 | LOG_NOTICE << std::hex << a; 33 | break; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /inc/CCSDS_Definitions.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * All necessary definitions used throughout the program 3 | */ 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | inline constexpr uint16_t SpacecraftIdentifier = 567; // A 10-bit unique identifier, assigned by the SANA 10 | 11 | // TODO? See if some of those inline constants don't need to be global and can be defined in the class instead 12 | 13 | inline constexpr uint16_t TmTransferFrameSize = 128; 14 | inline constexpr uint8_t TmPrimaryHeaderSize = 6; 15 | inline constexpr uint8_t TmTrailerSize = 6; 16 | 17 | inline constexpr uint16_t MaxTcTransferFrameSize = 128; 18 | inline const uint8_t TcPrimaryHeaderSize = 5; 19 | 20 | inline constexpr uint16_t MCID = SpacecraftIdentifier; 21 | 22 | // @todo Make this specific to each MAP/virtual channel. Probably requires some clever memory management 23 | inline constexpr uint8_t MaxReceivedTcInMapChannel = 5; 24 | inline constexpr uint8_t MaxReceivedTmInMapChannel = 5; 25 | 26 | inline constexpr uint8_t MaxReceivedTxTcInWaitQueue = 10; ///> Maximum received TX TCs in wait queue (before COP checks). 27 | inline constexpr uint8_t MaxReceivedRxTcInWaitQueue = 10; ///> Maximum received RX TCs in wait queue (before COP checks). 28 | 29 | inline constexpr uint8_t MaxReceivedTxTcInFOPSentQueue = 30 | 10; ///> Maximum received TX TCs in sent queue (following COP checks). 31 | inline constexpr uint8_t MaxReceivedRxTcInFOPSentQueue = 32 | 10; ///> Maximum received RX TCs in sent queue (following COP checks). 33 | inline constexpr uint8_t MaxReceivedRxTmInVirtBuffer = 10; ///> Maxiumm received RX TMs in Virtual channel buffer 34 | 35 | inline constexpr uint8_t MaxReceivedTxTcInFARMSentQueue = 36 | 10; ///> Maximum received TX TMs in sent queue (following COP checks). 37 | inline constexpr uint8_t MaxReceivedRxTcInFARMSentQueue = 38 | 10; ///> Maximum received RX TCs in sent queue (following COP checks). 39 | 40 | inline constexpr uint8_t MaxReceivedTxTcInMasterBuffer = 100; ///> Maximum received TX TC in the master buffer 41 | 42 | /** 43 | * Maximum received TX TCs in the master buffer, ready to be transmitted to the lower procedures (doesn't include 44 | * repetitions) 45 | */ 46 | inline constexpr uint8_t MaxReceivedTxTcOutInMasterBuffer = 100; 47 | 48 | /** 49 | * Maximum received TX TMs in the master buffer, ready to be transmitted to the lower procedures (doesn't include 50 | * repetitions) 51 | */ 52 | inline constexpr uint8_t MaxReceivedTxTmInMasterBuffer = 100; 53 | 54 | inline constexpr uint8_t MaxReceivedTxTmOutInVCBuffer = 55 | 100; ///> Maximum received TM in the master buffer, after passing through the all frames generation service 56 | inline const uint8_t MaxReceivedTxTmInVCBuffer = 57 | 100; ///> Maximum received TM in the master buffer, before being passed to the all frames generation service 58 | 59 | inline constexpr uint8_t MaxReceivedTxTmOutInMasterBuffer = 60 | 100; ///> Maximum received fully-processed TX TMs in the master buffer 61 | inline constexpr uint8_t MaxReceivedRxTcInMasterBuffer = 100; ///> Maximum received unprocessed RX TCs in the master buffer 62 | inline constexpr uint8_t MaxReceivedRxTcInVirtualChannelBuffer = 100; ///> Maximum received RX TCs in virtual channel buffer 63 | inline constexpr uint8_t MaxReceivedRxTcInMAPBuffer = 100; ///> Maximum received RX TCs in MAP buffer 64 | inline constexpr uint8_t MaxReceivedRxTcOutInMasterBuffer = 100; ///> Maximum received fully processed RX TCs in MAP buffer 65 | 66 | inline constexpr uint8_t MaxVirtualChannels = 10; 67 | inline constexpr uint8_t MaxMapChannels = 3; 68 | 69 | // Number of master copies of TX transfer frames that are stored in the master channel. This holds all the transfer 70 | // frames that are stored in all services 71 | inline constexpr uint8_t MaxTxInMasterChannel = 200; 72 | /** 73 | * Number of master copies of RX transfer frames that are stored in the master channel. 74 | * This holds all the transfer frames that are stored in all services 75 | */ 76 | 77 | inline constexpr uint8_t MaxRxInMasterChannel = 200; 78 | 79 | inline constexpr uint8_t MaxReceivedUnprocessedTxTcInVirtBuffer = 80 | 6; ///> Raw TX TC transfer frames stored directly in the virtual channel buffer. 81 | /// Set to 0 if VC processing service isn't used 82 | inline constexpr uint8_t MaxReceivedUnprocessedTxTmInVirtBuffer = 83 | 6; ///> Raw TX TM transfer frames stored directly in the virtual channel buffer. 84 | /// Set to 0 if VC processing service isn't used 85 | 86 | inline constexpr uint8_t FopSlidingWindowInitial = 255; 87 | inline constexpr uint8_t FopTimerInitial = 60; // sec 88 | 89 | inline constexpr uint16_t MemoryPoolMemorySize = 5 * 128; // Size of memory pool 90 | inline constexpr uint16_t MaxAllocatedPackets = 50; 91 | 92 | enum FlagState { NOT_READY = 0, READY = 1 }; 93 | 94 | inline constexpr uint16_t PacketBufferTmSize = 512; 95 | inline constexpr uint16_t PacketBufferTcSize = 512; 96 | 97 | inline constexpr uint8_t idle_data[] = { 98 | 0x53, 0x45, 0x24, 0x3, 0xce, 0xf0, 0xd2, 0x75, 0x50, 0xb9, 0x57, 0x24, 0x70, 0x83, 0xa8, 0x4e, 0x44, 0xd4, 0xa6, 99 | 0x90, 0xc2, 0x9d, 0x1a, 0xb, 0x42, 0xe9, 0x42, 0x66, 0x28, 0x80, 0x5e, 0x30, 0x1f, 0x75, 0x3b, 0x5, 0xcb, 0x93, 100 | 0xe3, 0x2d, 0xfc, 0xc4, 0x3c, 0x91, 0xd0, 0x17, 0xde, 0xf3, 0x9d, 0xb6, 0x6a, 0xcf, 0x3, 0x3a, 0x5b, 0x67, 0x78, 101 | 0x3d, 0xce, 0x2, 0x4, 0x3, 0xa8, 0xd, 0x52, 0xd4, 0x6f, 0x2, 0xab, 0xd3, 0x1a, 0x1c, 0x4e, 0xde, 0x87, 0x28, 102 | 0xda, 0xfe, 0x7c, 0xfe, 0xb2, 0x63, 0x9b, 0x24, 0x10, 0x4, 0x7, 0x1a, 0xaa, 0xa0, 0x2f, 0x40, 0x1e, 0x6f, 0x2e, 103 | 0xb9, 0x2b, 0x69, 0x7, 0xf0, 0x62, 0x42, 0xfd, 0x75, 0xb5, 0xe8, 0xd2, 0x18, 0xe, 0x19, 0xeb, 0x2a, 0x86, 0xda, 104 | 0x55, 0x8c, 0x48, 0xaf, 0xd6, 0x1d, 0x17, 0x71, 0x2b, 0x0, 0x58, 0x90, 0xd2, 0x81, 0x92, 0x38, 0x5a, 0xf9, 0x72, 105 | 0x58, 0xbb, 0xea, 0xa6, 0x17, 0x3f, 0x14, 0x8b, 0x78, 0xe3, 0xec, 0x2c, 0x8e, 0x94, 0x3b, 0x3d, 0x8, 0x20, 0x51, 106 | 0x5c, 0x60, 0xe5, 0x80, 0x5d, 0xdb, 0x7c, 0x8e, 0xbf, 0xe0, 0xfd, 0x73, 0xef, 0xf0, 0xd8, 0x50, 0x1c, 0xa6, 0xc6, 107 | 0x7e, 0x2, 0x11, 0x44, 0xe8, 0x31, 0x54, 0x83, 0x2f, 0x18, 0xf5, 0x44, 0x36, 0x36, 0xe5, 0xf6, 0x2f, 0x4c, 0x10, 108 | 0xf8, 0xc4, 0x4, 0x41, 0x1f, 0xa5, 0x99, 0x88, 0xac, 0x54, 0x74, 0x13, 0xba, 0x3, 0x21, 0xde, 0xdb, 0x56, 0x5e, 109 | 0x14, 0x67, 0xe2, 0xae, 0xcb, 0xb6, 0x93, 0x99, 0x95, 0xdf, 0xbc, 0x51, 0xd2, 0x7b, 0x74, 0xa, 0xbb, 0x87, 0x8, 110 | 0x4f, 0x82, 0x1b, 0x24, 0xfd, 0xd1, 0xf9, 0xc1, 0x21, 0x8e, 0x23, 0xce, 0xa0, 0xcc, 0xa, 0x50, 0xa6, 0x29, 0x60, 111 | 0x53, 0x32, 0x1f, 0xe3, 0x5e, 0x9c, 0x6b, 0x5f, 0x2e, 0xbf, 0x3d, 0xd6, 0xf2, 0x9f, 0xd7, 0xf6, 0x5, 0xcc, 0xc8, 112 | 0x80, 0xdb, 0x7b, 0x61, 0x1c, 0x17, 0xbb, 0xf3, 0xcd, 0x13, 0x16, 0x31, 0x33, 0xcb, 0xa7, 0xbb, 0x3a, 0x5a, 0x52, 113 | 0x58, 0x3e, 0xa7, 0x27, 0x81, 0xe7, 0xec, 0x19, 0x91, 0xa4, 0x61, 0xa2, 0x66, 0x7e, 0x2c, 0xde, 0xc4, 0x9c, 0x3d, 114 | 0xc9, 0xe9, 0xb4, 0xb, 0x1d, 0x8a, 0xa, 0x89, 0x43, 0x80, 0x1d, 0xfd, 0xab, 0xbd, 0xd2, 0x58, 0xf6, 0x25, 0x26, 115 | 0xcc, 0xe7, 0x88, 0xf, 0xd, 0x2, 0x16, 0x74, 0x3, 0xc7, 0x64, 0xed, 0x91, 0xa5, 0xd, 0x2d, 0x9a, 0xc, 0x74, 116 | 0x30, 0xb4, 0x5c, 0xbd, 0x19, 0x2, 0xd3, 0x6c, 0xd, 0x62, 0x4d, 0xa0, 0xa9, 0xa5, 0x4, 0x2, 0xba, 0x16, 0xae, 117 | 0x2d, 0x19, 0xe2, 0xa1, 0xad, 0x3e, 0x83, 0x3c, 0x3d, 0x8d, 0x72, 0x34, 0xca, 0x9a, 0x19, 0x5d, 0x2b, 0x77, 0x1c, 118 | 0x40, 0x42, 0x64, 0xc5, 0xac, 0x59, 0x72, 0x8f, 0xac, 0x6b, 0xc9, 0x88, 0x1, 0x63, 0xb5, 0xfa, 0x4, 0x70, 0x3a, 119 | 0x2d, 0xcf, 0x93, 0x50, 0xc1, 0x32, 0xf3, 0xf, 0xf8, 0x44, 0x9c, 0x84, 0x87, 0xe8, 0x62, 0xc7, 0x28, 0x2b, 0xdd, 120 | 0x7d, 0xfd, 0xa2, 0xb4, 0xad, 0xbd, 0xbf, 0xfe, 0x5e, 0x98, 0x31, 0xfc, 0xdd, 0x6e, 0xfe, 0x6, 0x82, 0xc2, 0xe5, 121 | 0x50, 0xac, 0x3d, 0xe4, 0x4c, 0xf4, 0x7a, 0xf1, 0x3a, 0x6e, 0xdd, 0x5f, 0x99, 0x5e, 0xd4, 0x12, 0xe7, 0xfb, 0x5d, 122 | 0xfa, 0x61, 0xfa, 0xda, 0x89, 0x34, 0xa6, 0x22, 0x92, 0x1c, 0xd0, 0x2d, 0x19, 0x6f, 0xd6, 0x53, 0x4e, 0x71, 0xf4, 123 | 0x2d, 0x35, 0xe6, 0x99, 0xde, 0x1d, 0xff, 0x7f, 0x4a, 0x2a, 0xab, 0xe, 0xe6, 0x2, 0xc0, 0x68, 0x49, 0x54, 0x2a, 124 | 0x50, 0xc6, 0xef, 0x1f, 0x7, 0x12, 0xc1, 0x54, 0x36, 0x68, 0xa6, 0xc9, 0x3c, 0x8d, 0xfe, 0x74, 0x7, 0x16, 0x7b, 125 | 0x1f, 0xc4, 0x8b, 0x30, 0x5, 0xd3, 0x7, 0x28, 0xf9, 0x4, 0x7c, 0x9c, 0x86, 0x24, 0xc8, 0x65, 0x5a, 0x65, 0xa3, 126 | 0xfa, 0xfa, 0xe1, 0xac, 0xc0, 0xef, 0xc1, 0xe2, 0x44, 0x4a, 0x9f, 0xbe, 0x84, 0xda, 0x83, 0x85, 0xd1, 0xc3, 0x5a, 127 | 0xfe, 0x3a, 0xd3, 0x4d, 0x5a, 0x42, 0x28, 0x1a, 0x94, 0x81, 0xab, 0x6, 0xd, 0x49, 0x27, 0x27, 0x2c, 0x5a, 0x12, 128 | 0xe, 0x56, 0x6b, 0x2d, 0xa4, 0x47, 0xa3, 0x89, 0xed, 0x6, 0xcf, 0xef, 0x71, 0x8a, 0x41, 0x86, 0x93, 0x50, 0x38, 129 | 0x9e, 0xf2, 0x14, 0xfe, 0x97, 0x80, 0x84, 0xb3, 0x5a, 0xd, 0x60, 0x92, 0x48, 0xae, 0xb5, 0xea, 0xeb, 0x13, 0xf7, 130 | 0xce, 0x1a, 0xfa, 0xfb, 0x83, 0xbf, 0x3c, 0x8f, 0x11, 0x63, 0xff, 0xad, 0x3b, 0x5c, 0x34, 0x33, 0x7, 0x50, 0x46, 131 | 0x7b, 0x2, 0x9f, 0x4b, 0x15, 0xbb, 0x8d, 0x90, 0x8b, 0x9c, 0x51, 0x22, 0xed, 0xa, 0xf4, 0xa4, 0x9b, 0x6c, 0xe4, 132 | 0x9f, 0x2c, 0x88, 0x6c, 0xd0, 0xc9, 0x47, 0x2e, 0xe9, 0xf, 0x76, 0x7, 0xa5, 0xe, 0x86, 0xd, 0xf7, 0x3d, 0x26, 133 | 0xf3, 0xfe, 0xd7, 0xb5, 0x9f, 0x80, 0x0, 0x9e, 0xc4, 0x67, 0xde, 0xc8, 0xf4, 0x9, 0xdc, 0xa, 0xf2, 0x46, 0xe8, 134 | 0x98, 0x86, 0xe5, 0x34, 0xab, 0xf2, 0xbd, 0xf4, 0x2a, 0x65, 0xb6, 0x90, 0xba, 0xdd, 0xda, 0x8b, 0xaf, 0x42, 0x25, 135 | 0x42, 0xd7, 0x68, 0xd1, 0x91, 0x70, 0x1d, 0x3c, 0xf3, 0xfc, 0x84, 0x8d, 0x99, 0x1d, 0x27, 0xb5, 0xd0, 0xab, 0xbf, 136 | 0xbd, 0xbb, 0xf, 0x6, 0x95, 0xfd, 0x96, 0x95, 0xb2, 0x1b, 0xaa, 0x90, 0x90, 0x73, 0xb5, 0xc, 0x3b, 0x4e, 0xcf, 137 | 0x7f, 0x33, 0x14, 0x14, 0x72, 0x4d, 0xa9, 0x9, 0x65, 0x1f, 0x50, 0x6f, 0x39, 0xa2, 0xe3, 0x53, 0x8d, 0x48, 0xb6, 138 | 0x82, 0xd1, 0x3e, 0x10, 0x9b, 0x2c, 0x23, 0x10, 0x1e, 0xd5, 0x7e, 0x87, 0x7, 0x2e, 0x81, 0xf4, 0x76, 0xb5, 0xa6, 139 | 0x7b, 0x4c, 0xd0, 0x34, 0x35, 0x50, 0x0, 0x4c, 0x25, 0xa6, 0xbf, 0xa1, 0xee, 0x93, 0x20, 0xb, 0x81, 0x94, 0x4, 140 | 0xc9, 0xc, 0x64, 0x19, 0xdf, 0x90, 0x1, 0x7d, 0xf7, 0x5a, 0x24, 0xb3, 0x5d, 0xca, 0xe0, 0x9a, 0x8e, 0x53, 0x52, 141 | 0xd4, 0x54, 0xa, 0xab, 0x9a, 0x88, 0x7c, 0x99, 0x21, 0x74, 0xc6, 0x6f, 0xbe, 0x49, 0x75, 0x3d, 0x38, 0xa3, 0x99, 142 | 0x8, 0xbd, 0x2, 0x12, 0x23, 0x43, 0xcb, 0x5d, 0x85, 0x7b, 0x45, 0xac, 0xe0, 0x2f, 0x71, 0x85, 0x6f, 0x79, 0x7c, 143 | 0xdf, 0x9e, 0x7, 0xfe, 0x1b, 0x99, 0x11, 0x3f, 0xdd, 0xc5, 0xd1, 0xac, 0x9e, 0x1, 0x7e, 0xf0, 0x6d, 0xde, 0x11, 144 | 0x64, 0xf, 0x5e, 0xcc, 0x39, 0x70, 0x2e, 0x79, 0x13, 0xac, 0x52, 0xbd, 0xe7, 0xb1, 0xe5, 0x81, 0x4c, 0xd7, 0x7f, 145 | 0x8d, 0x59, 0x4a, 0x52, 0xe0, 0x26, 0x66, 0xf2, 0x8a, 0x10, 0xb6, 0x38, 0x53, 0x60, 0x3d, 0xbc, 0x58, 0xa4, 0x9c, 146 | 0x91, 0xcb, 0x68, 0x5e, 0xdc, 0xe1, 0x94, 0x1c, 0x38, 0x73, 0xb0, 0x45, 0xdb, 0x41, 0xe4, 0x1f, 0xa3, 0x6a, 0xb, 147 | 0x58, 0x7, 0x2, 0x4b, 0xcf, 0xfb, 0x2f, 0x16, 0x7e, 0x9b, 0xdb, 0x7a, 0xa6, 0xe8, 0x15, 0xd5, 0x9b, 0x44, 0x32, 148 | 0x13, 0x52, 0x5, 0x77, 0xb, 0xce, 0xf5, 0xa0, 0x15, 0x5f, 0xda, 0x25, 0xb4, 0xdb, 0xc9, 0xdb, 0x6d, 0xdc, 0xb0, 149 | 0x2f, 0xf7, 0x3a, 0xae, 0xeb, 0xf6, 0xcc, 0x0, 0xd9, 0xce, 0x37, 0x1b, 0xb3, 0xf2, 0x93, 0xa5, 0x75, 0xef, 0xfd, 150 | 0x72, 0xf8, 0xb, 0x24, 0xa7, 0xa5, 0x39, 0x21, 0x8d, 0xaa, 0x11, 0x5b, 0xe5, 0xd1, 0x77, 0xaf, 0x80, 0x4, 0x53, 151 | 0x84, 0x6a, 0x52, 0x98, 0x1c, 0x19, 0x8d, 0x1f, 0xde, 0x7a, 0x27, 0xd7, 0xe8, 0x4f, 0x13, 0x17, 0xa0, 0x53, 0x45, 152 | 0x24, 0x3, 0xce, 0xf0, 0xd2, 0x75, 0x50, 0xb9, 0x57, 0x24, 0x70, 0x83, 0xa8, 0x4e, 0x44, 0xd4, 0xa6, 0x90, 0xc2, 153 | 0x9d, 0x1a, 0xb, 0x42, 0xe9, 0x42, 0x66, 0x28, 0x80, 0x5e, 0x30, 0x1f, 0x75, 0x3b, 0x5, 0xcb, 0x93, 0xe3, 0x2d, 154 | 0xfc, 0xc4, 0x3c, 0x91, 0xd0, 0x17, 0xde, 0xf3, 0x9d, 0xb6, 0x6a, 0xcf, 0x3, 0x3a, 0x5b, 0x67, 0x78, 0x3d, 0xce, 155 | 0x2, 0x4, 0x3, 0xa8, 0xd, 0x52, 0xd4, 0x6f, 0x2, 0xab, 0xd3, 0x1a, 0x1c, 0x4e, 0xde, 0x87, 0x28, 0xda, 0xfe, 156 | 0x7c, 0xfe, 0xb2, 0x63, 0x9b, 0x24, 0x10, 0x4, 0x7, 0x1a, 0xaa, 0xa0, 0x2f, 0x40, 0x1e, 0x6f, 0x2e, 0xb9, 0x2b, 157 | 0x69, 0x7, 0xf0, 0x62, 0x42, 0xfd, 0x75, 0xb5, 0xe8, 0xd2, 0x18, 0xe, 0x19, 0xeb, 0x2a, 0x86, 0xda, 0x55, 0x8c, 158 | 0x48, 0xaf, 0xd6, 0x1d, 0x17, 0x71, 0x2b, 0x0, 0x58, 0x90, 0xd2, 0x81, 0x92, 0x38, 0x5a, 0xf9, 0x72, 0x58, 0xbb, 159 | 0xea, 0xa6, 0x17, 0x3f, 0x14, 0x8b, 0x78, 0xe3, 0xec, 0x2c, 0x8e, 0x94, 0x3b, 0x3d, 0x8, 0x20, 0x51, 0x5c, 0x60, 160 | 0xe5, 0x80, 0x5d, 0xdb, 0x7c, 0x8e, 0xbf, 0xe0, 0xfd, 0x73, 0xef, 0xf0, 0xd8, 0x50, 0x1c, 0xa6, 0xc6, 0x7e, 0x2, 161 | 0x11, 0x44, 0xe8, 0x31, 0x54, 0x83, 0x2f, 0x18, 0xf5, 0x44, 0x36, 0x36, 0xe5, 0xf6, 0x2f, 0x4c, 0x10, 0xf8, 0xc4, 162 | 0x4, 0x41, 0x1f, 0xa5, 0x99, 0x88, 0xac, 0x54, 0x74, 0x13, 0xba, 0x3, 0x21, 0xde, 0xdb, 0x56, 0x5e, 0x14, 0x67, 163 | 0xe2, 0xae, 0xcb, 0xb6, 0x93, 0x99, 0x95, 0xdf, 0xbc, 0x51, 0xd2, 0x7b, 0x74, 0xa, 0xbb, 0x87, 0x8, 0x4f, 0x82, 164 | 0x1b, 0x24, 0xfd, 0xd1, 0xf9, 0xc1, 0x21, 0x8e, 0x23, 0xce, 0xa0, 0xcc, 0xa, 0x50, 0xa6, 0x29, 0x60, 0x53, 0x32, 165 | 0x1f, 0xe3, 0x5e, 0x9c, 0x6b, 0x5f, 0x2e, 0xbf, 0x3d, 0xd6, 0xf2, 0x9f, 0xd7, 0xf6, 0x5, 0xcc, 0xc8, 0x80, 0xdb, 166 | 0x7b, 0x61, 0x1c, 0x17, 0xbb, 0xf3, 0xcd, 0x13, 0x16, 0x31, 0x33, 0xcb, 0xa7, 0xbb, 0x3a, 0x5a, 0x52, 0x58, 0x3e, 167 | 0xa7, 0x27, 0x81, 0xe7, 0xec, 0x19, 0x91, 0xa4, 0x61, 0xa2, 0x66, 0x7e, 0x2c, 0xde, 0xc4, 0x9c, 0x3d, 0xc9, 0xe9, 168 | 0xb4, 0xb, 0x1d, 0x8a, 0xa, 0x89, 0x43, 0x80, 0x1d, 0xfd, 0xab, 0xbd, 0xd2, 0x58, 0xf6, 0x25, 0x26, 0xcc, 0xe7, 169 | 0x88, 0xf, 0xd, 0x2, 0x16, 0x74, 0x3, 0xc7, 0x64, 0xed, 0x91, 0xa5, 0xd, 0x2d, 0x9a, 0xc, 0x74, 0x30, 0xb4, 170 | 0x5c, 0xbd, 0x19, 0x2, 0xd3, 0x6c, 0xd, 0x62, 0x4d, 0xa0, 0xa9, 0xa5, 0x4, 0x2, 0xba, 0x16, 0xae, 0x2d, 0x19, 171 | 0xe2, 0xa1, 0xad, 0x3e, 0x83, 0x3c, 0x3d, 0x8d, 0x72, 0x34, 0xca, 0x9a, 0x19, 0x5d, 0x2b, 0x77, 0x1c, 0x40, 0x42, 172 | 0x64, 0xc5, 0xac, 0x59, 0x72, 0x8f, 0xac, 0x6b, 0xc9, 0x88, 0x1, 0x63, 0xb5, 0xfa, 0x4, 0x70, 0x3a, 0x2d, 0xcf, 173 | 0x93, 0x50, 0xc1, 0x32, 0xf3, 0xf, 0xf8, 0x44, 0x9c, 0x84, 0x87, 0xe8, 0x62, 0xc7, 0x28, 0x2b, 0xdd, 0x7d, 0xfd, 174 | 0xa2, 0xb4, 0xad, 0xbd, 0xbf, 0xfe, 0x5e, 0x98, 0x31, 0xfc, 0xdd, 0x6e, 0xfe, 0x6, 0x82, 0xc2, 0xe5, 0x50, 0xac, 175 | 0x3d, 0xe4, 0x4c, 0xf4, 0x7a, 0xf1, 0x3a, 0x6e, 0xdd, 0x5f, 0x99, 0x5e, 0xd4, 0x12, 0xe7, 0xfb, 0x5d, 0xfa, 0x61, 176 | 0xfa, 0xda, 0x89, 0x34, 0xa6, 0x22, 0x92, 0x1c, 0xd0, 0x2d, 0x19, 0x6f, 0xd6, 0x53, 0x4e, 0x71, 0xf4, 0x2d, 0x35, 177 | 0xe6, 0x99, 0xde, 0x1d, 0xff, 0x7f, 0x4a, 0x2a, 0xab, 0xe, 0xe6, 0x2, 0xc0, 0x68, 0x49, 0x54, 0x2a, 0x50, 0xc6, 178 | 0xef, 0x1f, 0x7, 0x12, 0xc1, 0x54, 0x36, 0x68, 0xa6, 0xc9, 0x3c, 0x8d, 0xfe, 0x74, 0x7, 0x16, 0x7b, 0x1f, 0xc4, 179 | 0x8b, 0x30, 0x5, 0xd3, 0x7, 0x28, 0xf9, 0x4, 0x7c, 0x9c, 0x86, 0x24, 0xc8, 0x65, 0x5a, 0x65, 0xa3, 0xfa, 0xfa, 180 | 0xe1, 0xac}; 181 | 182 | inline constexpr uint16_t crc_16_ccitt_table[]{ 183 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 184 | 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 185 | 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 186 | 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 187 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 188 | 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 189 | 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 190 | 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 191 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 192 | 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 193 | 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 194 | 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 195 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 196 | 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 197 | 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 198 | 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 199 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 200 | 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 201 | 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; 202 | 203 | inline constexpr uint16_t logger_max_message_size = 512; 204 | 205 | inline constexpr uint8_t log_verbose = 0; 206 | -------------------------------------------------------------------------------- /inc/CLCW.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct CLCW { 5 | uint32_t clcw; 6 | 7 | CLCW(const uint32_t operationalControlField) : clcw(operationalControlField){}; 8 | 9 | CLCW(const bool controlWordType, const uint8_t clcwVersion, const uint8_t statusField, const uint8_t copInEffect, 10 | const uint8_t vcId, const uint8_t spare, const bool noRfAvailable, const bool noBitLock, const bool lockout, 11 | const bool wait, const bool retransmit, const uint8_t farmBCounter, bool spare2, uint8_t reportValue) 12 | : clcw(controlWordType << 31U | clcwVersion << 29U | statusField << 26U | copInEffect << 24U | vcId << 18U | 13 | noRfAvailable << 15U | noBitLock << 14U | lockout << 13U | wait << 12U | retransmit << 11U | 14 | farmBCounter << 9U | reportValue){}; 15 | 16 | public: 17 | const uint32_t getClcw() { 18 | return clcw; 19 | } 20 | 21 | /** 22 | * Control Word Type is set to 0 to indicate that the Operational Control Field contains a CLCW 23 | * @return bit 0 of the CLCW 24 | * @see 4.2.2 from Telecommand Part 2 25 | */ 26 | const bool getControlWordType() { 27 | return clcw >> 31U; 28 | } 29 | 30 | /** 31 | * Clcw Version Number is set to value "00" to indicate the Version-1 CLCW is used. 32 | * @return bits 1,2 of the CLCW 33 | * @see 4.2.2 from Telecommand Part 2 34 | */ 35 | const uint8_t getClcwVersion() { 36 | return (clcw >> 29U) & 0x3; 37 | } 38 | 39 | /** 40 | * Field status is mission-specific and not used in the CCSDS data link protocol 41 | * @return Bits 3-5 of the CLCW (the Status Field). 42 | * @see p. 4.2.1.4 from TC SPACE DATA LINK PROTOCOL 43 | */ 44 | const uint8_t getStatusField() { 45 | return (clcw >> 26U) & 0x7; 46 | } 47 | 48 | /** 49 | * Used to indicate the COP that is being used. 50 | * @return Bits 6-7 of the CLCW (the COP in Effect parameter) 51 | * @see p. 4.2.1.5 from TC SPACE DATA LINK PROTOCOL 52 | */ 53 | const uint8_t getCopInEffect() { 54 | return (clcw >> 24U) & 0x3; 55 | } 56 | 57 | /** 58 | * @return Bits 8-13 of the CLCW (the Virtual Channel Identifier of the Virtual Channel 59 | * with which this COP report is associated). 60 | * @see p. 4.2.1.6 from TC SPACE DATA LINK PROTOCOL 61 | */ 62 | const uint8_t getVcId() { 63 | return (clcw >> 18U) & 0x3F; 64 | } 65 | 66 | /** 67 | * The No RF Available Flag shall provide a logical indication of the ‘ready’ status 68 | * of the radio frequency (RF) elements within the space link provided by the Physical Layer. 69 | * @return Bit 16 of the CLCW (the No RF Available Flag). 70 | * @see p. 4.2.1.8.2 from TC SPACE DATA LINK PROTOCOL 71 | */ 72 | const bool getNoRfAvailable() { 73 | return (clcw >> 15U) & 0x1; 74 | } 75 | 76 | /** 77 | * Indicates whether "bit lock" is achieved 78 | * @return Bit 17 of the CLCW (the No Bit Lock Flag). 79 | * @see p. 4.2.1.8.3 from TC SPACE DATA LINK PROTOCOL 80 | */ 81 | const bool getNoBitLock() { 82 | return (clcw >> 14U) & 0x1; 83 | } 84 | 85 | /** 86 | * Indicates whether FARM is in the Lockout state 87 | * @return Bit 18 of the CLCW (the Lockout Flag). 88 | * @see p. 4.2.1.8.4 from TC SPACE DATA LINK PROTOCOL 89 | */ 90 | const bool getLockout() { 91 | return (clcw >> 13U) & 0x1; 92 | } 93 | 94 | /** 95 | * Indicates whether the receiver doesn't accept any transfer frames 96 | * @return Bit 19 of the CLCW (the Wait Flag) 97 | * @see p. 4.1.2.8.5 from TC SPACE DATA LINK PROTOCOL 98 | */ 99 | const bool getWait() { 100 | return (clcw >> 12U) & 0x1; 101 | } 102 | 103 | /** 104 | * Indicates whether there are Type-A Frames that will need to be retransmitted 105 | * @return Bit 20 of the CLCW (the Retransmit Flag). 106 | * @see p. 4.2.1.8.6 from TC SPACE DATA LINK PROTOCOL 107 | */ 108 | const bool getRetransmit() { 109 | return (clcw >> 11U) & 0x1; 110 | } 111 | 112 | /** 113 | * The two least significant bits of the virtual channel 114 | * @return Bits 21-22 of the CLCW (the FARM-B Counter). 115 | * @see p. 4.2.1.9 from TC SPACE DATA LINK PROTOCOL 116 | */ 117 | const uint8_t getFarmBCounter() { 118 | return (clcw >> 9U) & 0x3; 119 | } 120 | 121 | /** 122 | * Next expected transfer frame number 123 | * @return Bits 24-31 of the CLCW (the Report Value). 124 | * @see p. 4.2.11.1 from TC SPACE DATA LINK PROTOCOL 125 | */ 126 | const uint8_t getReportValue() { 127 | return clcw & 0xFF; 128 | } 129 | }; 130 | -------------------------------------------------------------------------------- /inc/FrameAcceptanceReporting.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | * @see p. 6.1.2 from COP-1 CCSDS 10 | */ 11 | enum FARMState { 12 | OPEN = 1, 13 | WAIT = 2, 14 | LOCKOUT = 3, 15 | }; 16 | 17 | class VirtualChannel; 18 | 19 | class MAPChannel; 20 | 21 | /** 22 | * @see p. 6 from COP-1 CCSDS 23 | */ 24 | class FrameAcceptanceReporting { 25 | friend class ServiceChannel; 26 | 27 | private: 28 | FARMState state; 29 | FlagState lockout; 30 | FlagState wait; 31 | FlagState retransmit; 32 | uint16_t receiverFrameSeqNumber; 33 | uint16_t farmBCount; 34 | const uint8_t farmSlidingWinWidth; 35 | const uint8_t farmPositiveWinWidth; 36 | const uint8_t farmNegativeWidth; 37 | 38 | public: 39 | /* Directives */ 40 | 41 | /** 42 | * FARM actions according to the table 6-1 43 | * @see p. 6.2-6.3 and table 6-1 from COP-1 CCSDS 44 | */ 45 | COPDirectiveResponse frameArrives(); 46 | 47 | /** 48 | * signals when sufficient buffer space becomes available for at least one more maximum-size Frame. 49 | * @see p. 6.3.2.3 from COP-1 CCSDS 50 | */ 51 | COPDirectiveResponse bufferRelease(); 52 | 53 | /** 54 | * Buffer for storing TC transfer frames, BEFORE being processed by FARM. 55 | */ 56 | etl::list* waitQueue; 57 | /** 58 | * Buffer for storing TC transfer frames, AFTER being processed by FARM. 59 | */ 60 | etl::list* sentQueue; 61 | 62 | /** 63 | * The Virtual Channel in which FOP is initialized 64 | */ 65 | VirtualChannel* vchan; 66 | 67 | FrameAcceptanceReporting(VirtualChannel* vchan, etl::list* waitQueue, 68 | etl::list* sentQueue, 69 | const uint8_t farmSlidingWinWidth, const uint8_t farmPositiveWinWidth, 70 | const uint8_t farmNegativeWinWidth) 71 | : waitQueue(waitQueue), sentQueue(sentQueue), vchan(vchan), farmSlidingWinWidth(farmSlidingWinWidth), 72 | farmNegativeWidth(farmNegativeWinWidth), farmPositiveWinWidth(farmPositiveWinWidth), 73 | receiverFrameSeqNumber(0), farmBCount(0), lockout(FlagState::NOT_READY), wait(FlagState::NOT_READY), 74 | retransmit(FlagState::NOT_READY), state(FARMState::OPEN){}; 75 | }; -------------------------------------------------------------------------------- /inc/FrameOperationProcedure.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | *@see p. 5.1.2 from COP-1 CCSDS 10 | */ 11 | enum FOPState { 12 | ACTIVE = 1, 13 | RETRANSMIT_WITHOUT_WAIT = 2, 14 | RETRANSMIT_WITH_WAIT = 3, 15 | INITIALIZING_WITHOUT_BC_FRAME = 4, 16 | INITIALIZING_WITH_BC_FRAME = 5, 17 | INITIAL = 6 18 | }; 19 | 20 | /** 21 | * @see p.4.3.2 from COP-1 CCSDS 22 | */ 23 | enum AlertEvent { 24 | ALRT_SYNCH = 0, 25 | ALRT_CLCW = 1, 26 | ALRT_LIMIT = 2, 27 | ALRT_TERM = 3, 28 | ALRT_LLIF = 4, 29 | ALRT_NNR = 5, 30 | ALRT_LOCKOUT = 6, 31 | }; 32 | 33 | class VirtualChannel; 34 | class MAPChannel; 35 | 36 | class FrameOperationProcedure { 37 | friend class ServiceChannel; 38 | friend class MasterChannel; 39 | 40 | public: 41 | /** 42 | * TC transfer frames stored in list, before being processed by the FOP service 43 | * @see p. 5.1.4 from COP-1 CCSDS 44 | */ 45 | etl::list* waitQueueFOP; 46 | /** 47 | * TC transfer frames stored in list, after being processed by the FOP service 48 | * @see p. 5.1.7 from COP-1 CCSDS 49 | */ 50 | etl::list* sentQueueFOP; 51 | 52 | /** 53 | * TC transfer frames stored in list, before being processed by the FOP service 54 | * @see p. 5.1.4 from COP-1 CCSDS 55 | */ 56 | etl::list* waitQueueFARM; 57 | /** 58 | * TC transfer frames stored in list, after being processed by the FOP service 59 | * @see p. 5.1.7 from COP-1 CCSDS 60 | */ 61 | etl::list* sentQueueFARM; 62 | 63 | VirtualChannel* vchan; 64 | 65 | private: 66 | /** 67 | * This variable represents the state of FOP-1 for the specific Virtual Channel. 68 | * @see p. 5.1.2 from COP-1 CCSDS 69 | */ 70 | FOPState state; 71 | /** 72 | * It records the state that FOP-1 was in when the AD Service was suspended (as described in 5.1.10). 73 | * This is the state to which FOP-1 will return should the AD Service be resumed. 74 | * @see p. 5.1.11 from COP-1 CCSDS 75 | */ 76 | FOPState suspendState; 77 | 78 | /** 79 | * It contains the value of the Frame Sequence Number to be put in the Transfer Frame Primary Header of 80 | * the next Type-AD Transfer Frame to be transmitted. 81 | * @see p. 5.1.3 from COP-1 CCSDS 82 | */ 83 | uint8_t transmitterFrameSeqNumber; 84 | /** 85 | * @see p. 5.1.6 from COP-1 CCSDS 86 | */ 87 | bool adOut; 88 | /** 89 | * @see p. 5.1.6 from COP-1 CCSDS 90 | */ 91 | bool bdOut; 92 | /** 93 | * @see p. 5.1.6 from COP-1 CCSDS 94 | */ 95 | bool bcOut; 96 | /** 97 | * @see p. 5.1.8 from COP-1 CCSDS 98 | */ 99 | uint8_t expectedAcknowledgementSeqNumber; 100 | /** 101 | * Timer 102 | * @see p. 5.1.9 from COP-1 CCSDS 103 | */ 104 | uint16_t tiInitial; 105 | /** 106 | * The Transmission Limit holds a value which represents the maximum number of times the first 107 | * Transfer Frame on the Sent_Queue may be transmitted 108 | * @see p. 5.1.10.2 from COP-1 CCSDS 109 | */ 110 | uint16_t transmissionLimit; 111 | /** 112 | * The Transmission Count variable is used to count the number of transmissions of the first 113 | * Transfer Frame on the Sent_Queue 114 | * @see p. 5.1.10.4 from COP-1 CCSDS 115 | */ 116 | uint16_t transmissionCount; 117 | /** 118 | * The FOP Sliding Window is a mechanism which limits the number of Transfer Frames which can be 119 | * transmitted ahead of the last acknowledged Transfer Frame 120 | * @see p. 5.1.12 from COP-1 CCSDS 121 | */ 122 | uint8_t fopSlidingWindow; 123 | /** 124 | * It specifies the action to be performed when both the Timer expires and the Transmission 125 | * Count (see 5.1.10.4) has reached the Transmission_Limit. 126 | * @see p. 5.1.10.3 from COP-1 CCSDS 127 | */ 128 | bool timeoutType; 129 | /** 130 | * Purge the sent queue of the virtual channel and generate a response 131 | * @see p. 5.2.2 from COP-1 CCSDS 132 | */ 133 | FOPNotification purgeSentQueue(); 134 | 135 | /** 136 | * Purge the wait queue of the virtual channel and generate a response 137 | * @see p. 5.2.3 from COP-1 CCSDS 138 | */ 139 | FOPNotification purgeWaitQueue(); 140 | 141 | /** 142 | * Prepares a Type-AD Frame for transmission 143 | * @see p. 5.2.4 from COP-1 CCSDS 144 | */ 145 | FOPNotification transmitAdFrame(); 146 | 147 | /** 148 | * Prepares a Type-BC Frame for transmission 149 | * @see p. 5.2.5 from COP-1 CCSDS 150 | */ 151 | FOPNotification transmitBcFrame(TransferFrameTC* bc_frame); 152 | 153 | /** 154 | * Prepares a Type-BD Frame for transmission 155 | * @see p. 5.2.6 from COP-1 CCSDS 156 | */ 157 | FOPNotification transmitBdFrame(TransferFrameTC* bd_frame); 158 | 159 | /** 160 | * Marks AD Frames stored in the sent queue to be retransmitted 161 | * @see p. 5.2.7 from COP-1 CCSDS 162 | */ 163 | void initiateAdRetransmission(); 164 | 165 | /** 166 | * Marks BC Frames stored in the sent queue to be retransmitted 167 | * @see p. 5.2.7 from COP-1 CCSDS 168 | */ 169 | void initiateBcRetransmission(); 170 | 171 | /** 172 | * Remove acknowledged frames from sent queue 173 | * @see p. 5.2.8 from COP-1 CCSDS 174 | */ 175 | void removeAcknowledgedFrames(); 176 | 177 | /** 178 | * Search for directives in the sent queue and transmit any eligible frames 179 | * @see p. 5.2.9 from COP-1 CCSDS 180 | */ 181 | void lookForDirective(); 182 | 183 | /** 184 | * stores TC transfer frames, that have being processed by the FOP service, to the 185 | * outFramesBeforeAllFramesGenerationListTxTC list, in order to be processed by All Frames Generation Service 186 | */ 187 | COPDirectiveResponse pushSentQueue(); 188 | /** 189 | * Search for a FDU that can be transmitted in the sent_queue. If none are found also search in 190 | * the wait_queue 191 | * @see p. 5.2.10 from COP-1 CCSDS 192 | */ 193 | COPDirectiveResponse lookForFdu(); 194 | 195 | /** 196 | * initializes FOP service 197 | * @see p. 5.2.14 from COP-1 CCSDS 198 | */ 199 | void initialize(); 200 | 201 | /** 202 | * @see p. 5.2.15 from COP-1 CCSDS 203 | */ 204 | void alert(AlertEvent event); 205 | 206 | /* CLCW arrival*/ 207 | 208 | /** 209 | * Process event where a valid CLCW arrives 210 | * @see Table 5-1 from COP-1 CCSDS (E1 - E14) 211 | */ 212 | COPDirectiveResponse validClcwArrival(); 213 | 214 | // TODO: Check for invalid CLCW 215 | /** 216 | * Process invalid CLCW arrival 217 | * @see Table 5-1 from COP-1 CCSDS (E15) 218 | */ 219 | void invalidClcwArrival(); 220 | 221 | /** 222 | * acknowledges TC transfer frames with frame_seq_num, that have being processed by the FOP service and that have 223 | * @param frame_seq_num 224 | */ 225 | void acknowledgeFrame(uint8_t frame_seq_num); 226 | 227 | /* Directives (@see Table 5-1 from COP-1 CCSDS)*/ 228 | 229 | /** 230 | * E23 231 | * @see Table 5-1 from COP-1 CCSDS 232 | */ 233 | FDURequestType initiateAdNoClcw(); 234 | /** 235 | * E24 236 | * @see Table 5-1 from COP-1 CCSDS 237 | */ 238 | FDURequestType initiateAdClcw(); 239 | /** 240 | * E25-E26 241 | * @see Table 5-1 from COP-1 CCSDS 242 | */ 243 | FDURequestType initiateAdUnlock(); 244 | /** 245 | * E27-E28 246 | * @see Table 5-1 from COP-1 CCSDS 247 | */ 248 | FDURequestType initiateAdVr(uint8_t vr); 249 | /** 250 | * E29-E30 251 | * @see Table 5-1 from COP-1 CCSDS 252 | */ 253 | FDURequestType terminateAdService(); 254 | /** 255 | * E30-E34 256 | * @see Table 5-1 from COP-1 CCSDS 257 | */ 258 | FDURequestType resumeAdService(); 259 | /** 260 | * E35 261 | * @see Table 5-1 from COP-1 CCSDS 262 | */ 263 | COPDirectiveResponse setVs(uint8_t vs); 264 | /** 265 | * E36 266 | * @see Table 5-1 from COP-1 CCSDS 267 | */ 268 | COPDirectiveResponse setFopWidth(uint8_t width); 269 | /** 270 | * E37 271 | * @see Table 5-1 from COP-1 CCSDS 272 | */ 273 | COPDirectiveResponse setT1Initial(uint16_t t1_init); 274 | /** 275 | * E38 276 | * @see Table 5-1 from COP-1 CCSDS 277 | */ 278 | COPDirectiveResponse setTransmissionLimit(uint8_t vr); 279 | /** 280 | * E39 281 | * @see Table 5-1 from COP-1 CCSDS 282 | */ 283 | COPDirectiveResponse setTimeoutType(bool vr); 284 | /** 285 | * E40 286 | * @see Table 5-1 from COP-1 CCSDS 287 | */ 288 | COPDirectiveResponse invalidDirective(); 289 | 290 | /** Response from lower procedures*/ 291 | 292 | /** 293 | * E41 294 | * @see Table 5-1 Page 5 - 22 from COP-1 CCSDS 295 | */ 296 | void adAccept(); 297 | /** 298 | * E42 299 | * @see Table 5-1 Page 5 - 22 from COP-1 CCSDS 300 | */ 301 | void adReject(); 302 | /** 303 | * E43 304 | * @see Table 5-1 Page 5 - 22 from COP-1 CCSDS 305 | */ 306 | void bcAccept(); 307 | /** 308 | * E44 309 | * @see Table 5-1 Page 5 - 22 from COP-1 CCSDS 310 | */ 311 | void bcReject(); 312 | /** 313 | * E45 314 | * @see Table 5-1 Page 5 - 22 from COP-1 CCSDS 315 | */ 316 | COPDirectiveResponse bdAccept(); 317 | /** 318 | * E46 319 | * @see Table 5-1 Page 5 - 22 from COP-1 CCSDS 320 | */ 321 | void bdReject(); 322 | 323 | /** 324 | * E19 - E22 Table 5-1 COP-1 CCSDS 325 | * @see p. 3.2.2.3.2 from COP-1 CCSDS 326 | */ 327 | COPDirectiveResponse transferFdu(); 328 | 329 | /** 330 | * Function that acknowledges all the unacknowledged frames in the masterCopyTxTC buffer before the received report 331 | * value from the CLCW 332 | */ 333 | void acknowledgePreviousFrames(uint8_t frameSequenceNumber); 334 | 335 | public: 336 | FrameOperationProcedure(VirtualChannel* vchan, etl::list* waitQueue, 337 | etl::list* sentQueue, 338 | const uint8_t repetitionCopCtrl) 339 | : waitQueueFOP(waitQueue), sentQueueFOP(sentQueue), vchan(vchan), state(FOPState::INITIAL), 340 | suspendState(FOPState::INITIAL), transmitterFrameSeqNumber(0), adOut(FlagState::READY), 341 | bdOut(FlagState::READY), bcOut(FlagState::READY), expectedAcknowledgementSeqNumber(0), 342 | tiInitial(FopTimerInitial), transmissionLimit(repetitionCopCtrl), transmissionCount(1), 343 | fopSlidingWindow(FopSlidingWindowInitial), timeoutType(false){}; 344 | }; 345 | -------------------------------------------------------------------------------- /inc/Logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "CCSDS_Definitions.hpp" 7 | #define LOGLEVEL_TRACE 8 | #if defined LOGLEVEL_TRACE 9 | #define LOGLEVEL Logger::trace // Ignore-MISRA 10 | #elif defined LOGLEVEL_DEBUG 11 | #define LOGLEVEL Logger::debug // Ignore-MISRA 12 | #elif defined LOGLEVEL_INFO 13 | #define LOGLEVEL Logger::info // Ignore-MISRA 14 | #elif defined LOGLEVEL_NOTICE 15 | #define LOGLEVEL Logger::notice // Ignore-MISRA 16 | #elif defined LOGLEVEL_WARNING 17 | #define LOGLEVEL Logger::warning // Ignore-MISRA 18 | #elif defined LOGLEVEL_ERROR 19 | #define LOGLEVEL Logger::error // Ignore-MISRA 20 | #elif defined LOGLEVEL_EMERGENCY 21 | #define LOGLEVEL Logger::emergency // Ignore-MISRA 22 | #elif !defined LOGLEVEL 23 | #define LOGLEVEL Logger::disabled // Ignore-MISRA 24 | #endif 25 | 26 | #define LOG_TRACE (LOG()) ///< @see LOG @relates Logger 27 | #define LOG_DEBUG (LOG()) ///< @see LOG @relates Logger 28 | #define LOG_INFO (LOG()) ///< @see LOG @relates Logger 29 | #define LOG_NOTICE (LOG()) ///< @see LOG @relates Logger 30 | #define LOG_WARNING (LOG()) ///< @see LOG @relates Logger 31 | #define LOG_ERROR (LOG()) ///< @see LOG @relates Logger 32 | #define LOG_EMERGENCY (LOG()) ///< @see LOG @relates Logger 33 | 34 | /** 35 | * A logging class for ECSS Services that supports ETL's String and is lightweight enough to be used in embedded 36 | * development. 37 | * 38 | * @note Always use the \ref LOG function and its associated utility macros to log. Do not directly use the Logger 39 | * class. 40 | */ 41 | class Logger { 42 | public: 43 | /** 44 | * No need to instantiate a Logger object for now. 45 | */ 46 | Logger() = delete; 47 | 48 | /** 49 | * The underlying type to be used for values of Logger::LogLevel. 50 | */ 51 | typedef uint8_t LogLevelType; 52 | 53 | /** 54 | * ETL's string format specification, to be used for all logged messages 55 | */ 56 | static etl::format_spec format; 57 | 58 | /** 59 | * Log levels supported by the logger. Each level represents a different severity of the logged Message, 60 | * and messages of lower severities can be filtered on top of more significant ones. 61 | * 62 | * Each severity is tied to a number. The higher the number, the higher the severity. 63 | */ 64 | enum LogLevel : LogLevelType { 65 | trace = 32, ///< Very detailed information, useful for tracking the individual steps of an operation 66 | debug = 64, ///< General debugging information 67 | info = 96, ///< Noteworthy or periodical events 68 | notice = 128, ///< Uncommon but expected events 69 | warning = 160, ///< Unexpected events that do not compromise the operability of a function 70 | error = 192, ///< Unexpected failure of an operation 71 | emergency = 254, ///< Unexpected failure that renders the entire system unusable 72 | disabled = 255, ///< Use this log level to disable logging entirely. No message should be logged as disabled. 73 | }; 74 | 75 | /** 76 | * An empty enum representing a dummy log entry that will not be logged due to an insufficient level. 77 | * 78 | * @internal 79 | */ 80 | enum class NoLogEntry {}; 81 | 82 | /** 83 | * A class that defines a log message. 84 | * 85 | * Instead of using this class, prefer one of the above macros. 86 | * @see LOG 87 | * @internal 88 | */ 89 | struct LogEntry { 90 | String message; ///< The current log message itself, starting from a blank slate 91 | LogLevel level; ///< The log level of this message 92 | 93 | explicit LogEntry(LogLevel level); ///< Create a new LogEntry 94 | 95 | /** 96 | * The LogEntry destructor gets called whenever a log message is finalized, and ready to be shown to the 97 | * user. This function is responsible for calling the Logger::log function. 98 | * 99 | * According to the C++ standard, a variable used only within an expression will be immediately destroyed once 100 | * the processing of this expression is over. This allows a syntax such as `LogEntry(...) << "some" << "text"`, 101 | * where the destructor will be called strictly **after** all the `<<` operations have been completed. This 102 | * allows the destructor to send the finalized log entry for further processing. 103 | */ 104 | ~LogEntry(); 105 | 106 | LogEntry(LogEntry const&) = delete; ///< Unimplemented copy constructor 107 | 108 | /** 109 | * Stream operator to append new values to a log record 110 | * 111 | * @tparam T The type of value to append 112 | * @param value The new value to add 113 | * @todo See if noexcept can be added here without triggering warnings 114 | * @return The current Logger::LogEntry where the value has been appended 115 | */ 116 | template 117 | Logger::LogEntry& operator<<(const T value) { 118 | etl::to_string(value, message, format, true); 119 | 120 | return *this; 121 | } 122 | 123 | Logger::LogEntry& operator<<(const std::string& value); 124 | }; 125 | 126 | /** 127 | * Returns whether a log entry of level \p level is logged, based on the compilation constants 128 | * @param level The level of the log entry 129 | * @return True if the logging is enabled for \p level, false if not 130 | */ 131 | static constexpr bool isLogged(LogLevelType level) { 132 | return static_cast(LOGLEVEL) <= level; 133 | } 134 | 135 | /** 136 | * Store a new log message 137 | */ 138 | static void log(LogLevel level, etl::istring& message); 139 | }; 140 | 141 | /** 142 | * Create a stream to log a Message 143 | * 144 | * This functions appends one line to the Logs (which could be printed to screen, transferred via UART or stored for 145 | * later use.) 146 | * 147 | * Examples of usage: 148 | * @code 149 | * LOG() << "Reached point of no return"; 150 | * LOG() << "More than " << 50 << " dogs found!"; 151 | * @endcode 152 | * 153 | * You can also use one of the \ref LOG_TRACE, \ref LOG_DEBUG, \ref LOG_INFO, \ref LOG_NOTICE, \ref LOG_WARNING, 154 | * \ref LOG_ERROR or \ref LOG_EMERGENCY defines, which avoid the need of explicitly passing the log level: 155 | * @code 156 | * LOG_DEBUG << "Reached point of no return"; 157 | * LOG_ERROR << "More than " << 50 << " dogs found!"; 158 | * @endcode 159 | * 160 | * See \ref Logger::LogLevel for an explanation of the different log levels. 161 | * 162 | * @par Implementation details 163 | * Functions here are defined as `constexpr` in order to let them be optimized as soon as possible. The LOG() 164 | * function returns an instance of \ref Logger::LogEntry if the level is high enough to be shown, or an instance of 165 | * \ref Logger::NoLogEntry if the log entry will not be displayed. As this is a templated function, it is acceptable 166 | * to support different return types using the `auto` keyword. 167 | * 168 | * @warning For messages that will not be logged, any calls to functions that contain **side effects will still take 169 | * place**. 170 | * @code 171 | * LOG_DEBUG << "The temperature is: " << getTemperature(); 172 | * @endcode 173 | * In the above example, if `getTemperature()` will cause a side effect (e.g. an I2C connection or a `std::cout` print), 174 | * it will still be executed, even if the debug message will not be printed to the screen due to an insufficient 175 | * LOGLEVEL. 176 | * 177 | * @section GlobalLogLevels Global log levels 178 | * The **global log level** defines the minimum severity of events to be displayed. Log entries with a severity equal 179 | * to or higher than the global log level will be shown. Log entries with a severity smaller than the global log level 180 | * will not be shown. 181 | * 182 | * The global log level can be set by defining one of the following constants: 183 | * - `LOGLEVEL_TRACE` 184 | * - `LOGLEVEL_DEBUG` 185 | * - `LOGLEVEL_INFO` 186 | * - `LOGLEVEL_NOTICE` 187 | * - `LOGLEVEL_WARNING` 188 | * - `LOGLEVEL_ERROR` 189 | * - `LOGLEVEL_EMERGENCY` 190 | * 191 | * @relates Logger 192 | * @tparam level The log level. A value of \ref Logger::LogLevel 193 | * @return Returns \ref Logger::LogEntry if the level is sufficient to be logged, or \ref Logger::NoLogEntry if the 194 | * message will not be logged. This is determined at compile-time. 195 | */ 196 | template 197 | constexpr __attribute__((always_inline)) inline auto LOG() { 198 | if constexpr (Logger::isLogged(level)) { 199 | return Logger::LogEntry(level); 200 | } else { 201 | return Logger::NoLogEntry(); 202 | } 203 | }; 204 | 205 | /** 206 | * A no-op function that considers an empty log entry that will not be displayed, processed or stored. 207 | * 208 | * @warning Note that functions containing **side effects** will get properly executed. Only use functions that return 209 | * plain values as parts of the log function, so they might be optimized away at compile time. 210 | * 211 | * @tparam T The type of the data that will be ignored 212 | * @param noLogEntry A dummy no-op log entry 213 | * @param value The data that will be ignored 214 | * @return A dummy no-op log entry 215 | * @see Logger::LogEntry::operator<<(const T value) 216 | * @relates Logger::LogEntry 217 | */ 218 | template 219 | [[maybe_unused]] constexpr Logger::NoLogEntry operator<<(const Logger::NoLogEntry noLogEntry, T value) { 220 | return noLogEntry; 221 | } 222 | -------------------------------------------------------------------------------- /inc/MemoryPool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "etl/map.h" 6 | 7 | #include "Alert.hpp" 8 | #include "CCSDS_Definitions.hpp" 9 | /** 10 | * @class MemoryPool This class defines a custom memory pool which is a statically allocated block of memory. 11 | * This helps better keep track of data and reduce the memory needed for storing them. 12 | */ 13 | 14 | class MemoryPool { 15 | private: 16 | /** 17 | * @var The size of the block of memory in bytes 18 | */ 19 | static constexpr uint16_t memorySize = MemoryPoolMemorySize; 20 | 21 | /** 22 | * @var Maximum number of packets that can be allocated to the memory buffer 23 | */ 24 | static constexpr uint16_t maxAllocatedPackets = MaxAllocatedPackets; 25 | /** 26 | * @var An array that allocates statically memory to be used for the packet data 27 | */ 28 | uint8_t memory[memorySize]; 29 | 30 | /** 31 | * @var Keep track of currently used slots. It uses an ordered map to keep track of the beginning position of each 32 | * stored packet mapped to the packet's length. We used this instead of an interval tree since we are assuming 33 | * non-overlapping intervals 34 | */ 35 | etl::map usedMemory; 36 | 37 | public: 38 | MemoryPool() = default; 39 | 40 | /** 41 | * This method finds the head of a contiguous block in the memory pool of a given size 42 | * @param packetLength length of the data (bytes) 43 | * @return A `MasterChannelAlert` is raised if there was not enough space for the data, else returns the index of 44 | * the first memory where the data will be stored. 45 | */ 46 | std::pair findFit(uint16_t packetLength); 47 | 48 | /** 49 | * Method that copies the packet data to the first contiguous block of memory of the memory pool. 50 | * Calls the `findFit` method in order to find the index of the array that is first available. 51 | * @param packet pointer to the packet data. 52 | * @param packetLength the length of the packet data. 53 | * @return `uint8_t` pointer to the packet data in the memory pool or `nullptr` if packet could not be allocated. 54 | */ 55 | uint8_t* allocatePacket(uint8_t* packet, uint16_t packetLength); 56 | 57 | /** 58 | * This method is called when we want to delete the data of a packet. 59 | * @param packet pointer to the packet data in the pool. 60 | * @param packetLength length of the data. 61 | * @return true if the delete was successful and false if the packet was not found. 62 | */ 63 | bool deletePacket(uint8_t* packet, uint16_t packetLength); 64 | 65 | /** 66 | * @return pointer to the array that stores the data. 67 | */ 68 | uint8_t* getMemory(); 69 | 70 | /** 71 | * @return the bitset that shows if each memory slot is used. 72 | */ 73 | etl::map& getUsedMemory() { 74 | return usedMemory; 75 | } 76 | }; 77 | -------------------------------------------------------------------------------- /inc/TransferFrame.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | enum FrameType { TC, TM }; 7 | 8 | struct TransferFrameHeader { 9 | TransferFrameHeader(uint8_t* frameData) { 10 | transferFrameHeader = frameData; 11 | } 12 | 13 | /** 14 | * The ID of the spacecraft 15 | * TC: Bits 6–15 of the Transfer Frame Primary Header 16 | * TM: Bits 2–11 of the Transfer Frame Primary Header 17 | */ 18 | uint16_t spacecraftId(enum FrameType frameType) const { 19 | if (frameType == TC) { 20 | return (static_cast(transferFrameHeader[0] & 0x03) << 8U) | (static_cast(transferFrameHeader[1])); 21 | } else { 22 | return ((static_cast(transferFrameHeader[0]) & 0x3F) << 2U) | 23 | ((static_cast(transferFrameHeader[1])) & 0xC0) >> 6U; 24 | } 25 | } 26 | 27 | /** 28 | * The virtual channel ID this channel is transferred in 29 | * TC: Bits 16–21 of the Transfer Frame Primary Header 30 | * TM: Bits 12–14 of the Transfer Frame Primary Header 31 | */ 32 | uint8_t vcid(enum FrameType frameType) const { 33 | if (frameType == TC) { 34 | return (transferFrameHeader[2] >> 2U) & 0x3F; 35 | } else { 36 | return ((transferFrameHeader[1] & 0x0E)) >> 1U; 37 | } 38 | } 39 | 40 | protected: 41 | uint8_t* transferFrameHeader; 42 | }; 43 | 44 | class TransferFrame { 45 | private: 46 | FrameType type; 47 | 48 | public: 49 | TransferFrame(FrameType t, uint16_t transferFrameLength, uint8_t* frameData) 50 | : type(t), transferFrameLength(transferFrameLength), transferFrameData(frameData){}; 51 | 52 | virtual ~TransferFrame() {} 53 | 54 | virtual uint16_t calculateCRC(const uint8_t* data, uint16_t len) = 0; 55 | 56 | /** 57 | * Appends the CRC code (given that the corresponding Error Correction field is present in the given 58 | * virtual channel) 59 | * @see p. 4.1.4.2 from TC SPACE DATA LINK PROTOCOL 60 | */ 61 | void appendCRC() { 62 | uint16_t len = transferFrameLength - 2; 63 | uint16_t crc = calculateCRC(transferFrameData, len); 64 | 65 | uint16_t frameLength = (type == FrameType::TC) ? transferFrameLength : TmTransferFrameSize; 66 | 67 | // append CRC 68 | transferFrameData[frameLength - 2] = (crc >> 8) & 0xFF; 69 | transferFrameData[frameLength - 1] = crc & 0xFF; 70 | } 71 | 72 | protected: 73 | uint16_t transferFrameLength; 74 | uint8_t* transferFrameData; 75 | }; 76 | -------------------------------------------------------------------------------- /inc/TransferFrameTC.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "TransferFrame.hpp" 9 | 10 | class TransferFrameTC; 11 | 12 | /** 13 | * The transferFrameData's service type 14 | * @see p. 2.2.2 from TC SPACE DATA LINK PROTOCOL 15 | */ 16 | enum class ServiceType { 17 | TYPE_AD = 0x0, 18 | TYPE_AC = 0x1, 19 | TYPE_BD = 0x2, 20 | TYPE_BC = 0x3, 21 | }; 22 | 23 | enum FDURequestType : uint8_t { 24 | REQUEST_PENDING = 0, 25 | REQUEST_POSITIVE_CONFIRM = 1, 26 | REQUEST_NEGATIVE_CONFIRM = 2, 27 | }; 28 | 29 | struct TransferFrameHeaderTC : public TransferFrameHeader { 30 | public: 31 | /** 32 | * @see p. 4.1.2 from TC SPACE DATA LINK PROTOCOL 33 | */ 34 | TransferFrameHeaderTC(uint8_t* frameData) : TransferFrameHeader(frameData) {} 35 | 36 | /** 37 | * The bypass Flag determines whether the transferFrameData will bypass FARM checks 38 | * @details Bit 2 of the Transfer Frame Primary Header 39 | * @see p. 4.1.2.3.1 from TC SPACE DATA LINK PROTOCOL 40 | */ 41 | bool bypassFlag() const { 42 | return (transferFrameHeader[0] >> 5U) & 0x01; 43 | } 44 | 45 | /** 46 | * The control and command Flag determines whether the transferFrameData carries control commands (Type-C) or 47 | * data (Type-D) 48 | * @details Bit 3 of the Transfer Frame Primary Header 49 | * @see p. 4.1.2.3.2 from TC SPACE DATA LINK PROTOCOL 50 | */ 51 | bool ctrlAndCmdFlag() const { 52 | return (transferFrameHeader[0] >> 4U) & 0x01; 53 | } 54 | 55 | /** 56 | * The length of the transfer frame 57 | * @details Bits 22–31 of the Transfer Frame Primary Header 58 | * @see p. 4.1.2.7 from TC SPACE DATA LINK PROTOCOL 59 | */ 60 | uint16_t transferFrameLength() const { 61 | return (static_cast(transferFrameHeader[2] & 0x03) << 8U) | (static_cast(transferFrameHeader[3])); 62 | } 63 | }; 64 | 65 | class TransferFrameTC : public TransferFrame { 66 | public: 67 | void setConfSignal(FDURequestType reqSignal) { 68 | confSignal = reqSignal; 69 | // TODO Maybe signal the higher procedures here instead of having them manually take care of them 70 | } 71 | 72 | /** 73 | * Compares two frames 74 | */ 75 | friend bool operator==(const TransferFrameTC& frame1, const TransferFrameTC& frame2) { 76 | if (frame1.transferFrameLength != frame2.transferFrameLength) { 77 | return false; 78 | } 79 | for (uint16_t i = 0; i < frame1.transferFrameLength; i++) { 80 | if (frame1.frameData()[i] != frame2.frameData()[i]) { 81 | return false; 82 | } 83 | } 84 | return true; 85 | } 86 | 87 | // TODO: Handle CLCWs without any ambiguities 88 | 89 | // seems redundant? 90 | const uint8_t* packetPlData() const { 91 | return transferFrameData; 92 | } 93 | 94 | // see p. 4.2.1.1.2 from TC SPACE DATA LINK PROTOCOL 95 | 96 | /** 97 | * @return Bit 0 of the CLCW (the Control Word Type). 98 | * @details This one-bit field shall be set to ‘0’. 99 | * @see p. 4.2.1.2 from TC SPACE DATA LINK PROTOCOL 100 | */ 101 | uint8_t controlWordType() const { 102 | return (transferFrameData[0] & 0x80 >> 7U); 103 | } 104 | 105 | /** 106 | * @return Bits 3-5 of the CLCW (the Status Field). 107 | * @see p. 4.2.1.4 from TC SPACE DATA LINK PROTOCOL 108 | * 109 | */ 110 | uint8_t statusField() const { 111 | return (transferFrameData[0] & 0x1C) >> 2U; 112 | } 113 | 114 | /** 115 | * Used to indicate the COP that is being used. 116 | * @return Bits 6-7 of the CLCW (the COP in Effect parameter) 117 | * @see p. 4.2.1.5 from TC SPACE DATA LINK PROTOCOL 118 | */ 119 | uint8_t copInEffect() const { 120 | return transferFrameData[0] & 0x03; 121 | } 122 | 123 | /** 124 | * @return Bits 8-13 of the CLCW (the Virtual Channel Identifier of the Virtual Channel 125 | * with which this COP report is associated). 126 | * @see p. 4.2.1.6 from TC SPACE DATA LINK PROTOCOL 127 | */ 128 | uint8_t vcIdentification() const { 129 | return (transferFrameData[1] & 0xFC) >> 2U; 130 | } 131 | 132 | /** 133 | * The No RF Available Flag shall provide a logical indication of the ‘ready’ status 134 | * of the radio frequency (RF) elements within the space link provided by the Physical Layer. 135 | * @return Bit 16 of the CLCW (the No RF Available Flag). 136 | * @see p. 4.2.1.8.2 from TC SPACE DATA LINK PROTOCOL 137 | */ 138 | uint8_t noRfAvail() const { 139 | return (transferFrameData[2] & 0x80) >> 7U; 140 | } 141 | 142 | /** 143 | * @return Bit 17 of the CLCW (the No Bit Lock Flag). 144 | * @see p. 4.2.1.8.3 from TC SPACE DATA LINK PROTOCOL 145 | */ 146 | uint8_t noBitLock() const { 147 | return (transferFrameData[2] & 0x20) >> 5U; 148 | } 149 | 150 | /** 151 | * @return Bit 18 of the CLCW (the Lockout Flag). 152 | * @see p. 4.2.1.8.4 from TC SPACE DATA LINK PROTOCOL 153 | */ 154 | uint8_t lockout() const { 155 | return (transferFrameData[2] & 0x20) >> 5U; 156 | } 157 | 158 | /** 159 | * @return Bit 19 of the CLCW (the Wait Flag) 160 | * @see p. 4.1.2.8.5 from TC SPACE DATA LINK PROTOCOL 161 | */ 162 | uint8_t wait() const { 163 | return (transferFrameData[2] & 0x10) >> 4U; 164 | } 165 | 166 | /** 167 | * @return Bit 20 of the CLCW (the Retransmit Flag). 168 | * @see p. 4.2.1.8.6 from TC SPACE DATA LINK PROTOCOL 169 | */ 170 | uint8_t retransmit() const { 171 | return (transferFrameData[2] & 0x08) >> 3U; 172 | } 173 | 174 | /** 175 | * @return Bits 21-22 of the CLCW (the FARM-B Counter). 176 | * @see p. 4.2.1.9 from TC SPACE DATA LINK PROTOCOL 177 | */ 178 | uint8_t farmBCounter() const { 179 | return (transferFrameData[2] & 0x06) >> 1U; 180 | } 181 | 182 | /** 183 | * @return Bits 24-31 of the CLCW (the Report Value). 184 | * @see p. 4.2.11.1 from TC SPACE DATA LINK PROTOCOL 185 | */ 186 | uint8_t reportValue() const { 187 | return transferFrameData[3]; 188 | } 189 | 190 | /** 191 | * Set the number of repetitions that is determined by the virtual channel 192 | */ 193 | void setRepetitions(const uint8_t repetitions) { 194 | reps = repetitions; 195 | } 196 | 197 | /** 198 | * Determines whether the transfer frame is marked for retransmission while in the sent queue 199 | */ 200 | bool isToBeRetransmitted() const { 201 | return toBeRetransmitted; 202 | } 203 | 204 | void setToBeRetransmitted(bool f) { 205 | toBeRetransmitted = f; 206 | } 207 | 208 | /** 209 | * @return TC transfer frame primary header (the first 5 octets of the TC transfer frame) 210 | * @see p. 4.1.2 from TC SPACE DATA LINK PROTOCOL 211 | */ 212 | TransferFrameHeaderTC transferFrameHeader() const { 213 | return hdr; 214 | } 215 | 216 | /** 217 | * @return Bits 22–31 of the Transfer Frame Primary Header (the Frame Length) 218 | * @see p. 4.1.2.7 from TC SPACE DATA LINK PROTOCOL 219 | */ 220 | uint16_t getFrameLength() const { 221 | return transferFrameLength; 222 | } 223 | 224 | /** 225 | * @see p. 4.1.3.2.2 from TC SPACE DATA LINK PROTOCOL 226 | */ 227 | // TODO: Use std::optional 228 | uint8_t segmentationHeader() const { 229 | return transferFrameData[5]; 230 | } 231 | 232 | /** 233 | * @return Bits 16–21 of the Transfer Frame Primary Header (the Virtual Channel Identifier (VCID)). 234 | * @see p. 4.1.2.6 from TC SPACE DATA LINK PROTOCOL 235 | */ 236 | uint8_t virtualChannelId() const { 237 | return (transferFrameData[2] & 0xFC) >> 2; 238 | }; 239 | 240 | // Assumes MAP Id exists 241 | // TODO: Replace with std::optional 242 | uint8_t mapId() const { 243 | if (segmentationHeaderPresent) { 244 | return transferFrameData[5] & 0x3F; 245 | } 246 | return 0; 247 | } 248 | 249 | uint8_t getTransferFrameVersionNumber() const { 250 | return (transferFrameData[0] >> 6) & 0x3; 251 | } 252 | /** 253 | * @return Bits 6–15 of the Transfer Frame Primary Header (the Spacecraft Identifier (SCID)). 254 | * @see p. 4.1.2.5 from TC SPACE DATA LINK PROTOCOL 255 | */ 256 | uint16_t spacecraftId() const { 257 | return SpacecraftIdentifier; 258 | } 259 | 260 | /** 261 | * @return Bits 32–39 of the Transfer Frame Primary Header (the Frame Sequence Number, N(S)). 262 | * @see p. 4.1.2.8 from TC SPACE DATA LINK PROTOCOL. 263 | */ 264 | uint8_t transferFrameSequenceNumber() const { 265 | return transferFrameData[4]; 266 | } 267 | 268 | /** 269 | * @see p. 2.2.2 from TC SPACE DATA LINK PROTOCOL 270 | */ 271 | ServiceType getServiceType() const { 272 | bool bypass = (transferFrameData[0] >> 6) & 0x1; 273 | bool ctrl = (transferFrameData[0] >> 5) & 0x1; 274 | 275 | if (bypass && ctrl) { 276 | return ServiceType::TYPE_BC; 277 | } else if (bypass && !ctrl) { 278 | return ServiceType::TYPE_BD; 279 | } else if (!bypass && !ctrl) { 280 | return ServiceType::TYPE_AD; 281 | } 282 | // Reserved type not normally used as per the standard 283 | return ServiceType::TYPE_AC; 284 | } 285 | 286 | bool acknowledged() const { 287 | return ack; 288 | } 289 | 290 | /** 291 | * @see p. 2.4.2 from TC SPACE DATA LINK PROTOCOL 292 | */ 293 | uint8_t repetitions() const { 294 | return reps; 295 | } 296 | 297 | uint8_t* frameData() const { 298 | return transferFrameData; 299 | } 300 | 301 | // Setters are not strictly needed in this case. They are just offered as a utility functions for the VC/MAP 302 | // generation services when segmenting or blocking transfer frames. 303 | void setSegmentationHeader(uint8_t segmentation_hdr) { 304 | transferFrameData[5] = segmentation_hdr; 305 | } 306 | 307 | void setFrameData(uint8_t* frame_data) { 308 | transferFrameData = frame_data; 309 | } 310 | 311 | void setFrameLength() { 312 | transferFrameData[2] = ((virtualChannelId() & 0x3F) << 2) | (transferFrameLength & 0x300 >> 8); 313 | transferFrameData[3] = transferFrameLength & 0xFF; 314 | } 315 | 316 | uint16_t frameLength() { 317 | return (static_cast(transferFrameData[2] & 0x3) << 8) | transferFrameData[3]; 318 | } 319 | 320 | void setServiceType(ServiceType service_type) { 321 | serviceType = service_type; 322 | } 323 | 324 | void setAcknowledgement(bool acknowledgement) { 325 | ack = acknowledgement; 326 | } 327 | 328 | void setTransferFrameSequenceNumber(uint8_t frame_seq_number) { 329 | transferFrameData[4] = frame_seq_number; 330 | } 331 | 332 | /** 333 | * Indicates that the frame has been passed to the physical layer and supposedly transmitted 334 | */ 335 | void setToTransmitted() { 336 | transmit = true; 337 | } 338 | 339 | /** 340 | * Indicates whether transfer frame has been transmitted 341 | */ 342 | bool isTransmitted() { 343 | return transmit; 344 | } 345 | 346 | /** 347 | * Indicates that the frame has gone through the FOP checks 348 | */ 349 | void setToProcessedByFOP() { 350 | processedByFOP = true; 351 | } 352 | 353 | /** 354 | * Indicates whether the frame has gone through the FOP checks 355 | */ 356 | bool getProcessedByFOP() { 357 | return processedByFOP; 358 | } 359 | 360 | TransferFrameTC(uint8_t* frameData, uint16_t frameLength, uint8_t gvcid, ServiceType serviceType, bool segHdrPresent, 361 | FrameType t = TC) 362 | : TransferFrame(t, frameLength, frameData), hdr(frameData), serviceType(serviceType), ack(false), 363 | toBeRetransmitted(false), segmentationHeaderPresent(segHdrPresent), transmit(false), processedByFOP(false) { 364 | uint8_t bypassFlag = (serviceType == ServiceType::TYPE_AD) ? 0 : 1; 365 | uint8_t ctrlCmdFlag = (serviceType == ServiceType::TYPE_BC) ? 1 : 0; 366 | frameData[0] = (bypassFlag << 6) | (ctrlCmdFlag << 5) | ((SpacecraftIdentifier & 0x300) >> 8); 367 | frameData[1] = SpacecraftIdentifier & 0xFF; 368 | frameData[2] = ((gvcid & 0x3F) << 2) | (frameLength & 0x300 >> 8); 369 | frameData[3] = frameLength & 0xFF; 370 | } 371 | 372 | TransferFrameTC(uint8_t* frameData, uint16_t frameLength, FrameType t = TC) 373 | : TransferFrame(FrameType::TC, frameLength, frameData), hdr(frameData), transmit(false){}; 374 | /** 375 | * Calculates the CRC code 376 | * @see p. 4.1.4.2 from TC SPACE DATA LINK PROTOCOL 377 | */ 378 | uint16_t calculateCRC(const uint8_t* data, uint16_t len) override { 379 | uint16_t crc = 0xFFFF; 380 | 381 | // calculate remainder of binary polynomial division 382 | for (uint16_t i = 0; i < len; i++) { 383 | crc = crc_16_ccitt_table[(data[i] ^ (crc >> 8)) & 0xFF] ^ (crc << 8); 384 | } 385 | 386 | return crc; 387 | } 388 | 389 | private: 390 | bool toBeRetransmitted; 391 | // This is used by COP to signal the higher procedures 392 | FDURequestType confSignal; 393 | TransferFrameHeaderTC hdr; 394 | ServiceType serviceType; 395 | bool segmentationHeaderPresent; 396 | bool ack; 397 | bool transmit; 398 | bool processedByFOP; 399 | uint8_t reps; 400 | }; 401 | -------------------------------------------------------------------------------- /inc/TransferFrameTM.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TransferFrame.hpp" 4 | #include "Alert.hpp" 5 | #include "CCSDS_Definitions.hpp" 6 | #include "optional" 7 | 8 | struct TransferFrameHeaderTM : public TransferFrameHeader { 9 | public: 10 | /** 11 | * @see p. 4.1.2 from TM SPACE DATA LINK PROTOCOL 12 | */ 13 | TransferFrameHeaderTM(uint8_t* frameData) : TransferFrameHeader(frameData) {} 14 | 15 | /** 16 | * The Operational Control Field Flag indicates the presence or absence of the Operational Control Field 17 | * @details Bit 15 of the Transfer Frame Primary Header 18 | * @see p. 4.1.2.4 from TM SPACE DATA LINK PROTOCOL 19 | */ 20 | bool operationalControlFieldFlag() const { 21 | return (transferFrameHeader[1]) & 0x01; 22 | } 23 | 24 | /** 25 | * Provides a running count of the Transfer Frames which have been transmitted through the 26 | * same Master Channel. 27 | * @details Bits 16–23 of the Transfer Frame Primary Header 28 | * @see p. 4.1.2.5 from TM SPACE DATA LINK PROTOCOL 29 | */ 30 | uint8_t masterChannelFrameCount() const { 31 | return transferFrameHeader[2]; 32 | } 33 | 34 | /** 35 | * contain a sequential binary count (modulo-256) of each Transfer Frame transmitted within a 36 | * specific Virtual Channel. 37 | * @details Bits 24–31 of the Transfer Frame Primary Header 38 | * @see p. 4.1.2.6 from TM SPACE DATA LINK PROTOCOL 39 | */ 40 | uint8_t virtualChannelFrameCount() const { 41 | return transferFrameHeader[3]; 42 | } 43 | 44 | /** 45 | * Indicates the presence of the secondary header. 46 | * @details Bit 32 of the Transfer Frame Primary Header 47 | * @see p. 4.1.2.7.2 from TM SPACE DATA LINK PROTOCOL 48 | */ 49 | 50 | bool transferFrameSecondaryHeaderFlag() const { 51 | return (transferFrameHeader[4] & 0x80) >> 7U; 52 | } 53 | 54 | /** 55 | * Signals the type of data which are inserted into the Transfer Frame Data Field (VCA_SDU or Packets). 56 | * @details Bit 33 of the Transfer Frame Primary Header 57 | * @see p. 4.1.2.7.3 from TM SPACE DATA LINK PROTOCOL 58 | */ 59 | 60 | bool synchronizationFlag() const { 61 | return (transferFrameHeader[4] & 0x40) >> 6U; 62 | } 63 | 64 | /** 65 | * If the Synchronization Flag is set to ‘0’,t he TransferFrame Order Flag is reserved for 66 | future use by the CCSDS and shall be set to ‘0’. If the Synchronization Flag is 67 | set to ‘1’, the use of the TransferFrame Order Flag is undefined. 68 | * @details Bit 34 of the Transfer Frame Primary Header 69 | * @see p. 4.1.2.7.4 from TM SPACE DATA LINK PROTOCOL 70 | */ 71 | bool packetOrderFlag() const { 72 | return (transferFrameHeader[4] & 0x20) >> 5U; 73 | } 74 | 75 | /** 76 | * Segment Length Id indicates the order of the segmented packets 77 | * Bits 35 and 36 of the Transfer Frame Primary Header. 78 | */ 79 | uint8_t segmentLengthId() const { 80 | return (transferFrameHeader[4] >> 3) & 0x3; 81 | } 82 | 83 | /** 84 | * If the Synchronization Flag is set to ‘0’, the First Header Pointer shall contain 85 | * the position of the first octet of the first TransferFrame that starts in the Transfer Frame Data Field. 86 | * Otherwise it is undefined. 87 | * @details Bits 37–47 of the Transfer Frame Primary Header 88 | * @see p. 4.1.2.7.6 from TM SPACE DATA LINK PROTOCOL 89 | */ 90 | uint16_t firstHeaderPointer() const { 91 | return (static_cast((transferFrameHeader[4]) & 0x07)) << 8U | (static_cast((transferFrameHeader[5]))); 92 | } 93 | 94 | /** 95 | * Contains the a)Transfer Frame Secondary Header Flag (1 bit) 96 | * b) Synchronization Flag (1 bit) 97 | * c) TransferFrame Order Flag (1 bit) 98 | * d) Segment Length Identifier (2 bits) 99 | * e) First Header Pointer (11 bits) 100 | * @details Bits 32–47 of the Transfer Frame Primary Header. 101 | * @see p. 4.1.2.7 from TM SPACE DATA LINK PROTOCOL 102 | */ 103 | uint16_t transferFrameDataFieldStatus() const { 104 | return (static_cast((transferFrameHeader[4])) << 8U | (static_cast((transferFrameHeader[5])))); 105 | } 106 | }; 107 | 108 | struct TransferFrameTM : public TransferFrame { 109 | /** 110 | * The Virtual Channel Identifier provides the identification of the Virtual Channel. 111 | * @details Bits 12–14 of the Transfer Frame Primary Header. 112 | * @see p. 4.1.2.3 from TM SPACE DATA LINK PROTOCOL 113 | */ 114 | uint8_t virtualChannelId() const { 115 | return (transferFrameData[1] & 0xE) >> 1U; 116 | } 117 | 118 | /** 119 | * This 8-bit field shall contain a sequential binary count (modulo-256) of each 120 | * Transfer Frame transmitted within a specific Master Channel. 121 | * @details Bits 16–23 of the Transfer Frame Primary Header. 122 | * @see p. 4.1.2.5 from TM SPACE DATA LINK PROTOCOL 123 | */ 124 | uint8_t getMasterChannelFrameCount() const { 125 | return transferFrameData[2]; 126 | } 127 | 128 | /** 129 | * This 8-bit field shall contain a sequential binary count (modulo-256) of each 130 | * Transfer Frame transmitted within a specific Virtual Channel. 131 | * @details Bits 24-31 of the Transfer Frame Primary Header. 132 | * @see p. 4.1.2.6 from TM SPACE DATA LINK PROTOCOL 133 | */ 134 | uint8_t getVirtualChannelFrameCount() const { 135 | return transferFrameData[3]; 136 | } 137 | 138 | /** 139 | * 140 | * Contains the a)Transfer Frame Secondary Header Flag (1 bit) 141 | * b) Synchronization Flag (1 bit) 142 | * c) TransferFrame Order Flag (1 bit) 143 | * d) Segment Length Identifier (2 bits) 144 | * e) First Header Pointer (11 bits) 145 | * @details Bits 32–47 of the Transfer Frame Primary Header. 146 | * @see p. 4.1.2.7 from TM SPACE DATA LINK PROTOCOL 147 | */ 148 | uint16_t getTransferFrameDataFieldStatus() const { 149 | return static_cast((transferFrameData[4]) << 8) | transferFrameData[5]; 150 | } 151 | 152 | uint16_t getFrameLength() const { 153 | return transferFrameLength; 154 | } 155 | 156 | uint8_t* frameData() const { 157 | return transferFrameData; 158 | } 159 | 160 | bool operationalControlFieldExists() const { 161 | return transferFrameData[1] & 0x1; 162 | } 163 | uint8_t segmentLengthId() const { 164 | return (transferFrameData[4] >> 3) & 0x3; 165 | } 166 | 167 | /** 168 | * @see p. 4.1.5 from TM SPACE DATA LINK PROTOCOL 169 | */ 170 | std::optional getOperationalControlField() const { 171 | uint32_t operationalControlField; 172 | uint8_t* operationalControlFieldPointer; 173 | if (!operationalControlFieldExists()) { 174 | return {}; 175 | } 176 | operationalControlFieldPointer = transferFrameData + transferFrameLength - 4 - 2 * eccFieldExists; 177 | operationalControlField = (operationalControlFieldPointer[0] << 24U) | 178 | (operationalControlFieldPointer[1] << 16U) | 179 | (operationalControlFieldPointer[2] << 8U) | operationalControlFieldPointer[3]; 180 | return operationalControlField; 181 | } 182 | 183 | void setMasterChannelFrameCount(uint8_t masterChannelFrameCount) { 184 | transferFrameData[2] = masterChannelFrameCount; 185 | } 186 | 187 | TransferFrameTM(uint8_t* frameData, uint16_t frameLength, uint8_t virtualChannelFrameCount, uint16_t vcid, 188 | bool eccFieldExists, bool transferFrameSecondaryHeaderPresent, uint8_t segmentationLengthId, 189 | SynchronizationFlag syncFlag, FrameType type = TM) 190 | : TransferFrame(type, frameLength, frameData), hdr(frameData), scid(scid), eccFieldExists(eccFieldExists), 191 | firstHeaderPointer(firstHeaderPointer) { 192 | // Transfer Frame Version Number + Spacecraft Id 193 | frameData[0] = SpacecraftIdentifier & 0xE0 >> 4; 194 | // Spacecraft Id + Virtual Channel ID + Operational Control Field 195 | frameData[1] = ((SpacecraftIdentifier & 0x0F) << 4) | ((vcid & 0x7) << 1); 196 | // Master Channel Frame Count is set by the MC Generation Service 197 | frameData[2] = 0; 198 | frameData[3] = virtualChannelFrameCount; 199 | // Data field status. TransferFrame Order Flag and Segment Length ID are unused 200 | frameData[4] = (transferFrameSecondaryHeaderPresent << 7) | (static_cast(syncFlag << 6)) | 201 | (segmentationLengthId << 3) | (firstHeaderPointer & 0x700 >> 8); 202 | frameData[5] = firstHeaderPointer & 0xFF; 203 | } 204 | 205 | /** 206 | * Constructor with operational control field 207 | */ 208 | TransferFrameTM(uint8_t* frameData, uint16_t frameLength, uint8_t virtualChannelFrameCount, uint16_t vcid, 209 | bool eccFieldExists, bool transferFrameSecondaryHeaderPresent, uint8_t segmentationLengthId, 210 | SynchronizationFlag syncFlag, uint32_t operationalControlField, FrameType type = TM) 211 | : TransferFrame(type, frameLength, frameData), hdr(frameData), scid(scid), eccFieldExists(eccFieldExists), 212 | firstHeaderPointer(firstHeaderPointer) { 213 | // Transfer Frame Version Number + Spacecraft Id 214 | frameData[0] = SpacecraftIdentifier & 0xE0 >> 4; 215 | // Spacecraft Id + Virtual Channel ID + Operational Control Field 216 | frameData[1] = ((SpacecraftIdentifier & 0x0F) << 4) | ((vcid & 0x7) << 1) | 1; 217 | // Master Channel Frame Count is set by the MC Generation Service 218 | frameData[2] = 0; 219 | frameData[3] = virtualChannelFrameCount; 220 | // Data field status. TransferFrame Order Flag and Segment Length ID are unused 221 | frameData[4] = (transferFrameSecondaryHeaderPresent << 7) | (static_cast(syncFlag << 6)) | 222 | (segmentationLengthId << 3) | (firstHeaderPointer & 0x700 >> 8); 223 | frameData[5] = firstHeaderPointer & 0xFF; 224 | uint8_t* ocfPointer = frameData + transferFrameLength - 4 - 2 * eccFieldExists; 225 | ocfPointer[0] = operationalControlField >> 24; 226 | ocfPointer[1] = (operationalControlField >> 16) & 0xFF; 227 | ocfPointer[2] = (operationalControlField >> 8) & 0xFF; 228 | ocfPointer[3] = operationalControlField & 0xFF; 229 | } 230 | 231 | TransferFrameTM(uint8_t* frameData, uint16_t frameLength, bool eccFieldExists) 232 | : TransferFrame(FrameType::TM, frameLength, frameData), hdr(frameData), 233 | eccFieldExists(eccFieldExists) {} 234 | /** 235 | * Calculates the CRC code 236 | * @see p. 4.1.4.2 from TC SPACE DATA LINK PROTOCOL 237 | */ 238 | uint16_t calculateCRC(const uint8_t* data, uint16_t len) override { 239 | 240 | uint16_t crc = 0xFFFF; 241 | 242 | // calculate remainder of binary polynomial division 243 | for (uint16_t i = 0; i < len; i++) { 244 | crc = crc_16_ccitt_table[(data[i] ^ (crc >> 8)) & 0xFF] ^ (crc << 8); 245 | } 246 | 247 | for (uint16_t i = 0; i < TmTransferFrameSize - len - 4*operationalControlFieldExists() - 2; i++) { 248 | crc = crc_16_ccitt_table[(idle_data[i] ^ (crc >> 8)) & 0xFF] ^ (crc << 8); 249 | } 250 | 251 | return crc; 252 | } 253 | 254 | 255 | private: 256 | TransferFrameHeaderTM hdr; 257 | uint8_t scid; 258 | bool eccFieldExists; 259 | uint16_t firstHeaderPointer; 260 | }; 261 | -------------------------------------------------------------------------------- /inc/etl/String.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * A fixed-size string 8 | * 9 | * This class implements a string (i.e. an array of bytes) that has a maximum size (\p MAX_SIZE) 10 | * known at compile time. As such, we can predict how much space the string will take, and prevent 11 | * memory issues. 12 | * 13 | * Even though the maximum size (capacity) of the script should be specified beforehand, the size 14 | * of the actual content is variable, and can be accessed quickly using the `String::size()` 15 | * function. 16 | * 17 | * This class is a child of etl::string that provides some extra functionality that might be 18 | * useful to us. For the full documentation, look at https://www.etlcpp.com/string.html 19 | * 20 | * Strings defined using the String class do NOT have a null-terminating byte 21 | * 22 | * @tparam MAX_SIZE The maximum size of the strings 23 | */ 24 | template 25 | class String : public etl::string { 26 | public: 27 | /** 28 | * String constructor from a uint8_t array, with a length equal to \p MAX_SIZE 29 | * 30 | * The array does NOT need to be null-terminated. 31 | * 32 | * @param data The array of uint8_t data 33 | */ 34 | explicit String(const uint8_t *data) // NOLINTNEXTLINE(google-explicit-constructor) 35 | : etl::string(reinterpret_cast(data), MAX_SIZE) {} 36 | 37 | /** 38 | * An empty string constructor. An empty etl::string is allocated. 39 | */ 40 | String() : etl::string() {} 41 | 42 | /** 43 | * String constructor from a uint8_t array 44 | * 45 | * The array does NOT need to be null-terminated. 46 | * 47 | * @param data The array of uint8_t data 48 | * @param count The number of bytes to include 49 | */ 50 | String(const uint8_t *data, size_t count) : etl::string(reinterpret_cast(data), count) {} 51 | 52 | /** 53 | * Declaration of the constructor from const char*s that calls the parent constructor 54 | * 55 | * This is required for some reason, so that C++ recognises and converts string literals 56 | * automatically 57 | * 58 | * @param text The pointer to a null terminated string 59 | * 60 | */ 61 | explicit String(const char *text) // NOLINTNEXTLINE(google-explicit-constructor) 62 | : etl::string(text) {} 63 | }; 64 | -------------------------------------------------------------------------------- /inc/etl_profile.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Configuration for the ETL standard library replacement 3 | */ 4 | 5 | #pragma once 6 | 7 | #define ETL_THROW_EXCEPTIONS 8 | #define ETL_VERBOSE_ERRORS 9 | #define ETL_CHECK_PUSH_POP 10 | 11 | // Only GCC is used as a compiler 12 | #include "etl/profiles/gcc_linux_x86.h" 13 | -------------------------------------------------------------------------------- /inc/logOperators.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "map" 5 | #include 6 | #include "Alert.hpp" 7 | #include "TransferFrameTC.hpp" 8 | std::ostream& operator<<(std::ostream& out, const TxRx value); 9 | std::ostream& operator<<(std::ostream& out, const NotificationType value); 10 | std::ostream& operator<<(std::ostream& out, const ServiceChannelNotification value); 11 | std::ostream& operator<<(std::ostream& out, const COPDirectiveResponse value); 12 | std::ostream& operator<<(std::ostream& out, const FOPNotification value); 13 | -------------------------------------------------------------------------------- /servicesAndBuffersGraph.mmd: -------------------------------------------------------------------------------- 1 | flowchart TB 2 | subgraph A["TC Tx Services"] 3 | subgraph A1 ["Map Packet Processing"] 4 | A1s1[["storePacketTxTc(packet, packetLength, vid, mapid)"]] 5 | A1s2[["mappRequestTxTC(vid, mapid, transferFrameDataLength, serviceType)
calls internally:
-segmentationTC
-blockingTC"]] 6 | A1s3[["frontUnprocessedFrameMcCopyTxTC()"]] 7 | A1s4[["getLastMasterCopyTcFrame()"]] 8 | A1s5[["frontUnprocessedFrameVcCopyTxTC(vid)"]] 9 | A1s6[["backUnprocessedFrameMcCopyTxTC()"]] 10 | A1s7[["availableUnprocessedFramesVcCopyTxTC(vid)"]] 11 | 12 | A1s1 --> A1s2 13 | A1s1 -.-> A1r1{"Type of Packet?"} 14 | A1r1 -.-> A1r2["Type A"] & A1r3["Type B"] 15 | A1r2 -.-> map4 & map5 16 | A1r3 -.-> map6 & map7 17 | A1s2 -..-x|"(from segmentation,blocking)"| A1r4{"Type of Packet?"} 18 | A1r4 -.-x A1r5["Type A"] & A1r6["Type B"] 19 | A1r5 -.-x map4 & map5 20 | A1r6 -.-x map6 & map7 21 | A1s2 -.->|"(from segmentation,blocking)"| master16 22 | A1s2 -.->|"(from segmentation,blocking)"| vc7 23 | A1s2 -.->|"(from segmentation,blocking)"| master12 24 | A1s2 -.check if full.-vc2 25 | A1s3 -.front reference.-master12 26 | A1s4 -.back reference.-master12 27 | A1s5 -.front reference.-vc7 28 | A1s6 -.back reference.-master12 29 | A1s7 -.remaining space.-vc7 30 | end 31 | 32 | subgraph A2 ["Virtual Channel Generation"] 33 | A2s1[["vcGenerationRequestTxTC
Calls internally:
-transferFdu (fop service)"]] 34 | A2s2[["frontFrameBeforeAllFramesGenerationTxTC()"]] 35 | 36 | A1s2 --> A2s1 37 | A2s1 -.->|"Push and deletion from fop"| vc2 38 | A2s1 -.->|"Push and deletion from fop"| vc4 39 | A2s1 -.-x|"From fop"| master12 40 | A2s1 -.-x|"From fop"| master16 41 | A2s1 -.-x|"After fop finishes"| vc7 42 | A2s1 -.->|"from vcGenerationRequestTC() AND transferFdu()?"| master1 43 | A2s2 -.-|"front reference"| master1 44 | end 45 | 46 | subgraph A3 ["All Frames Generation"] 47 | A3s1[["allFramesGenerationRequestTxTC()"]] 48 | A3s2[["frameTransmission(frameTarget)
NOTE:is a fop service"]] 49 | A3s3[["frontFrameAfterAllFramesGenerationTxTC()"]] 50 | A3s4[["availableFramesAfterAllFramesGenerationTxTC()"]] 51 | 52 | A2s1 --> A3s1 --> A3s2 53 | A3s1 -.-x master1 54 | A3s1 -.-> master2 55 | A3s2 -.-x master2 56 | A3s3 -.-|"front reference"| master2 57 | A3s4 -.-|"remaining space"| master2 58 | end 59 | end 60 | 61 | subgraph B ["TC Rx Services"] 62 | subgraph B1["All Frames Reception"] 63 | B1s1[["storeFrameRxTC(frameData, frameLength)"]] 64 | B1s2[["allFramesReceptionRequestRxTC()"]] 65 | B1s4[["txAvailableTc(const uint8_t vid, const uint8_t mapid)"]] 66 | B1s5[["txOutFrameTC(uint8_t vid,uint8_t mapid)"]] 67 | B1s6[["availableFramesBeforeAllFramesReceptionRxTC()"]] 68 | B1s7[["getAvailableWaitQueueRxTC(vid)"]] 69 | 70 | B1s1 -->B1s2 71 | B1s1 -.->master14 & master9 72 | B1s2 -..-x|"discard TC frame if invalid"| master14 73 | B1s2 -.-xmaster9 74 | B1s2 -.->vc3 75 | B1s4 -.remaining space.-map1 76 | B1s5 -.front reference.-map1 77 | B1s6 -.remaining space.-master9 78 | B1s2 -.checks if full.-master10 79 | B1s7 -..-|"remaining space"| vc3 80 | end 81 | 82 | subgraph B2["Virtual Channel Reception"] 83 | B2s1[["vcReceptionRxTC(vid)
calls internally:
frameArrives
(FARM)"]] 84 | B2s2[["getAvailableinFramesAfterVCReceptionRxTC(vid)"]] 85 | B2s3[["getAvailableinFramesAfterVCReceptionRxTC(vid, mapid)"]] 86 | 87 | B1s2 --> B2s1 88 | B2s1 --->|"frameArrives insertion"| vc5 89 | B2s1 --->|"push report TM frame (clcw frame)"| service1 90 | B2s1 --> B3r1{"MAP exists in this VC?"} 91 | B3r1 --> B3r2["yes"] & B3r3["no"] 92 | B3r2 -.-> map3 93 | B3r3 -.-> vc6 94 | B2s1 -..-x|"frameArrives deletion"| vc3 95 | B2s2 -.-|"remaining space"| map3 96 | B2s3 -.-|"remaining space"| vc6 97 | end 98 | 99 | subgraph B3["Virtual Channel Extraction"] 100 | B3s1[["packetExtractionTC(vid, packetTarget)"]] 101 | 102 | B3r3 --> B3s1 103 | B3s1 -.-x map3 104 | end 105 | 106 | subgraph B4["MAP Packet Extraction"] 107 | B4s1[["packetExtractionTC(vid, mapid, packetTarget)"]] 108 | 109 | B3r2 --> B4s1 110 | B4s1 -.-x vc6 111 | B4s1 -.-x master14 112 | end 113 | end 114 | 115 | subgraph C ["TM Tx Services"] 116 | subgraph C1["Packet Processing"] 117 | C1s1[["storePacketTxTM(packet, packetLength, vid)"]] 118 | C1s2[["availablePacketLengthBufferTxTM(gvcid)"]] 119 | C1s3[["availablePacketBufferTxTM(gvcid)"]] 120 | 121 | C1s1 -.-> vc8 & vc9 122 | C1s2 -.-|"available space"| vc8 123 | C1s3 -.-|"available space"| vc9 124 | end 125 | 126 | subgraph C2["Virtual Channel Generation"] 127 | C2s1[["vcGenerationServiceTxTM(transferFrameDataFieldLength, vid)
calls internally:
-segmentationTM
-blockingTM"]] 128 | C2s2[["availableFramesAfterVcGenerationTxTM()"]] 129 | C2s3[["backFrameAfterVcGenerationTxTM()"]] 130 | C2s4[["frontFrameAfterVcGenerationTxTM()"]] 131 | C1s1 --> C2s1 132 | C2s1 -.-x|"(from segmentation,blocking)"| vc8 & vc9 133 | C2s1 -.->|"(from segmentation,blocking)"| master13 & master11 & master17 134 | C2s2 -.-|"remaining space"| master13 135 | C2s3 -.-|"back reference"| master13 136 | C2s4 -.-|"front reference"| master11 137 | end 138 | 139 | subgraph C3["Master Channel Generation"] 140 | C3s1[["mcGenerationRequestTxTM()"]] 141 | 142 | C2s1 --> C3s1 143 | C3s1 -.-> master4 144 | C3s1 -.-x master11 145 | end 146 | 147 | subgraph C4["All Frames Generation"] 148 | C4s1[["allFramesGenerationRequestTxTM(frameDataTarget, frameLength)"]] 149 | C4s2[["frontFrameAfterAllFramesGenerationTxTM()"]] 150 | 151 | C3s1 --> C4s1 152 | C4s1 -.-x master4 & master17 & master13 153 | C4s2 -.-|"front reference"| master8 154 | end 155 | end 156 | 157 | subgraph D["TM Rx Services"] 158 | subgraph D1["All Frames Reception"] 159 | D1s1[["allFramesReceptionRequestRxTM(frameData, frameLength)"]] 160 | D1s2[["availableFramesVcCopyRxTM(vid)"]] 161 | D1s3[["availableFramesMcCopyRxTM()"]] 162 | 163 | D1s1 -.-> master15 & vc1 164 | D1s2 -.-|remaining space| vc1 165 | D1s3 -.-|remaining space| master15 166 | end 167 | 168 | subgraph D2["Packet Extraction"] 169 | D2s1[["packetExtractionRxTM(vid, packetTarget)"]] 170 | D1s1 --> D2s1 171 | D2s1 -.-x master15 & vc1 172 | end 173 | end 174 | 175 | subgraph E["Legend"] 176 | E1[[Necessary Service]] 177 | E2[[Service for Debugging/Utility]] 178 | E3[(MAP Channel Buffer)] 179 | E4[(Virtual Channel Buffer)] 180 | E5[(Master Channel Buffer)] 181 | 182 | E6[ ] -->|"logical calling order of main services"| E7[ ] 183 | E8[ ] -.->|"push object to buffer"| E9[ ] 184 | E10[ ] -.-x|"pop object from buffer"| E11[ ] 185 | E12[ ] -.-|"other action related to this buffer"| E13[ ] 186 | 187 | style E1 height:0px; 188 | style E2 height:0px; 189 | style E3 height:0px; 190 | style E4 height:0px; 191 | style E5 height:0px; 192 | end 193 | 194 | E~~~A~~~B~~~C~~~D 195 | 196 | map1[("unprocessedFrameListBufferTC (frameTC*)
This belongs in TC TX chain,although seems unused")] 197 | map2[("unprocessedFrameListBufferTM
NOTE:this should probably not exist")] 198 | map3[("inFramesAfterVCReceptionRxTC (frameTC*)")] 199 | map4[("packetLengthBufferTxTcTypeA (uint16_t)")] 200 | map5[("packetBufferTxTcTypeA (uint8_t)")] 201 | map6[("packetLengthBufferTxTcTypeB (uint16_t)")] 202 | map7[("packetBufferTxTcTypeB (uint8_t)")] 203 | 204 | vc1[("framesAfterMCReceptionRxTM (frameTM*)")] 205 | vc2[("waitQueueTxTC (frameTC*)")] 206 | vc3[("waitQueueRxTC (frameTC*)")] 207 | vc4[("sentQueueTxTC (frameTC*)")] 208 | vc5[("sentQueueRxTC (frameTC*)")] 209 | vc6[("inFramesAfterVCReceptionRxTC (frameTC*)")] 210 | vc7[("unprocessedFrameListBufferTxTC (frameTC*)")] 211 | vc8[("packetLengthBufferTxTM (uint16_t)")] 212 | vc9[("packetBufferTxTM (uint8_t)")] 213 | 214 | master1[("outFramesBeforeAllFramesGenerationListTxTC (frameTC*)")] 215 | master2[("toBeTransmittedFramesAfterAllFramesGenerationListTxTC (frameTC*)")] 216 | master3[("txOutFramesBeforeMCGenerationListTM
Note: Seems unused")] 217 | master4[("toBeTransmittedFramesAfterMCGenerationListTxTM (frameTM*)")] 218 | master5[("txOutFramesBeforeMCReceptionListTM
Note:seems unused")] 219 | master6[("txToBeTransmittedFramesAfterMCReceptionListTM
Note:seems unused")] 220 | master7[("txOutFramesBeforeAllFramesGenerationListTM
Note:seems redundant")] 221 | master8[("toBeTransmittedFramesAfterAllFramesGenerationListTxTM (frameTM*)")] 222 | master9[("inFramesBeforeAllFramesReceptionListRxTC (frameTC*)")] 223 | master10[("toBeTransmittedFramesAfterAllFramesReceptionListRxTC (frameTC*)")] 224 | master11[("framesAfterVcGenerationServiceTxTM (frameTM*)")] 225 | master12[("masterCopyTxTC (frame TC)")] 226 | master13[("masterCopyTxTM (frameTM)")] 227 | master14[("masterCopyRxTC (frame TC)")] 228 | master15[("masterCopyRxTM (frameTM)")] 229 | master16[("masterChannelPoolTC (uint8_t)
Note: Stores transfer frame data of masterCopyTxTC frames")] 230 | master17[("masterChannelPoolTM (uint8_t)
Note: Stores transfer frame data of masterCopyTxTM frames")] 231 | 232 | service1[("clcwTransferFrameBuffer (frameTM)
Single capacity")] 233 | 234 | classDef map_channel_buffer fill:#3d8215; 235 | classDef virtual_channel_buffer fill:#a6161f; 236 | classDef master_channel_buffer fill:#244fb5; 237 | classDef main_services fill:#B06F2A; 238 | classDef utility_services fill:#648D98; 239 | 240 | class map1,map2,map3,map4,map5,map6,map7,E3 map_channel_buffer; 241 | class vc1,vc2,vc3,vc4,vc5,vc6,vc7,vc8,vc9,E4 virtual_channel_buffer; 242 | class master1,master2,master3,master4,master5,master6,master7,master8,master9,master10,master11,master12,master13,master14,master15,master16,master17,E5 master_channel_buffer 243 | class A1s1,A1s2,A2s1,A3s1,A3s2,B1s1,B1s2,B2s1,B3s1,B4s1,C1s1,C2s1,C3s1,C4s1,D1s1,D2s1,E1 main_services; 244 | class A1s3,A1s4,A1s5,A1s6,A1s7,A2s2,A3s3,A3s4,B1s4,B1s5,B1s6,B1s7,B2s2,B2s3,C1s2,C1s3,C2s2,C2s3,C2s4,C4s2,D1s2,D1s3,E2 utility_services; -------------------------------------------------------------------------------- /src/CCSDSChannel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "CCSDSLoggerImpl.h" 4 | #include "MemoryPool.hpp" 5 | // Virtual Channel 6 | 7 | VirtualChannelAlert VirtualChannel::storeVC(TransferFrameTC* transferFrameTc) { 8 | // Limit the amount of transfer frames that can be stored at any given time 9 | if (unprocessedFrameListBufferVcCopyTxTC.full()) { 10 | ccsdsLogNotice(Tx, TypeVirtualChannelAlert, TX_WAIT_QUEUE_FULL); 11 | return VirtualChannelAlert::TX_WAIT_QUEUE_FULL; 12 | } 13 | unprocessedFrameListBufferVcCopyTxTC.push_back(transferFrameTc); 14 | ccsdsLogNotice(Tx, TypeVirtualChannelAlert, NO_VC_ALERT); 15 | return VirtualChannelAlert::NO_VC_ALERT; 16 | } 17 | // Master Channel 18 | 19 | // Technically not a transfer frame, but it has identical information 20 | // @todo consider another data structure 21 | 22 | MasterChannelAlert MasterChannel::storeOut(TransferFrameTC* transferFrameTc) { 23 | if (outFramesBeforeAllFramesGenerationListTxTC.full()) { 24 | // Log that buffer is full 25 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, OUT_FRAMES_LIST_FULL); 26 | return MasterChannelAlert::OUT_FRAMES_LIST_FULL; 27 | } 28 | outFramesBeforeAllFramesGenerationListTxTC.push_back(transferFrameTc); 29 | uint8_t vid = transferFrameTc->virtualChannelId(); 30 | // virtChannels.at(0).fop. 31 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, NO_MC_ALERT); 32 | return MasterChannelAlert::NO_MC_ALERT; 33 | } 34 | 35 | MasterChannelAlert MasterChannel::storeOut(TransferFrameTM* transferFrameTm) { 36 | if (txOutFramesBeforeAllFramesGenerationListTM.full()) { 37 | // Log that buffer is full 38 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, OUT_FRAMES_LIST_FULL); 39 | return MasterChannelAlert::OUT_FRAMES_LIST_FULL; 40 | } 41 | txOutFramesBeforeAllFramesGenerationListTM.push_back(transferFrameTm); 42 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, NO_MC_ALERT); 43 | return MasterChannelAlert::NO_MC_ALERT; 44 | } 45 | 46 | MasterChannelAlert MasterChannel::storeTransmittedOut(TransferFrameTC* transferFrameTc) { 47 | if (toBeTransmittedFramesAfterAllFramesGenerationListTxTC.full()) { 48 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, TO_BE_TRANSMITTED_FRAMES_LIST_FULL); 49 | return MasterChannelAlert::TO_BE_TRANSMITTED_FRAMES_LIST_FULL; 50 | } 51 | toBeTransmittedFramesAfterAllFramesGenerationListTxTC.push_back(transferFrameTc); 52 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, NO_MC_ALERT); 53 | return MasterChannelAlert::NO_MC_ALERT; 54 | } 55 | 56 | MasterChannelAlert MasterChannel::storeTransmittedOut(TransferFrameTM* transferFrameTm) { 57 | if (toBeTransmittedFramesAfterAllFramesGenerationListTxTM.full()) { 58 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, TO_BE_TRANSMITTED_FRAMES_LIST_FULL); 59 | return MasterChannelAlert::TO_BE_TRANSMITTED_FRAMES_LIST_FULL; 60 | } 61 | toBeTransmittedFramesAfterAllFramesGenerationListTxTM.push_back(transferFrameTm); 62 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, NO_MC_ALERT); 63 | return MasterChannelAlert::NO_MC_ALERT; 64 | } 65 | 66 | MasterChannelAlert MasterChannel::addVC(const uint8_t vcid, const uint16_t maxFrameLength, const bool blocking, 67 | const uint8_t repetitionTypeAFrame, const uint8_t repetitionTypeBFrame, 68 | const bool frameErrorControlFieldPresent, const bool secondaryHeaderTMPresent, 69 | const uint8_t secondaryHeaderTMLength, 70 | const bool operationalControlFieldTMPresent, 71 | SynchronizationFlag synchronization, const uint8_t farmSlidingWinWidth, 72 | const uint8_t farmPositiveWinWidth, const uint8_t farmNegativeWinWidth, const uint8_t vcRepetitions, 73 | etl::flat_map mapChan) { 74 | if (virtualChannels.full()) { 75 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, MAX_AMOUNT_OF_VIRT_CHANNELS); 76 | return MasterChannelAlert::MAX_AMOUNT_OF_VIRT_CHANNELS; 77 | } 78 | 79 | virtualChannels.emplace(vcid, VirtualChannel(*this, vcid, true, maxFrameLength, blocking, repetitionTypeAFrame, 80 | repetitionTypeBFrame, secondaryHeaderTMPresent, secondaryHeaderTMLength, 81 | operationalControlFieldTMPresent, frameErrorControlFieldPresent, 82 | synchronization, farmSlidingWinWidth, farmPositiveWinWidth, 83 | farmNegativeWinWidth, vcRepetitions, mapChan)); 84 | return MasterChannelAlert::NO_MC_ALERT; 85 | } 86 | 87 | MasterChannelAlert MasterChannel::addVC(const uint8_t vcid, const uint16_t maxFrameLength, const bool blocking, 88 | const uint8_t repetitionTypeAFrame, const uint8_t repetitionCopCtrl, 89 | const bool frameErrorControlFieldPresent, const bool secondaryHeaderTMPresent, 90 | const uint8_t secondaryHeaderTMLength, 91 | const bool operationalControlFieldTMPresent, 92 | SynchronizationFlag synchronization, const uint8_t farmSlidingWinWidth, 93 | const uint8_t farmPositiveWinWidth, const uint8_t farmNegativeWinWidth, const uint8_t vcRepetitions) { 94 | if (virtualChannels.full()) { 95 | ccsdsLogNotice(Tx, TypeMasterChannelAlert, MAX_AMOUNT_OF_VIRT_CHANNELS); 96 | return MasterChannelAlert::MAX_AMOUNT_OF_VIRT_CHANNELS; 97 | } 98 | 99 | virtualChannels.emplace(vcid, 100 | VirtualChannel(*this, vcid, false, maxFrameLength, blocking, repetitionTypeAFrame, 101 | repetitionCopCtrl, secondaryHeaderTMPresent, secondaryHeaderTMLength, 102 | frameErrorControlFieldPresent, operationalControlFieldTMPresent, 103 | synchronization, farmSlidingWinWidth, farmPositiveWinWidth, 104 | farmNegativeWinWidth, vcRepetitions, etl::flat_map())); 105 | return MasterChannelAlert::NO_MC_ALERT; 106 | } 107 | 108 | void MasterChannel::removeMasterTx(TransferFrameTC* frame_ptr) { 109 | etl::list::iterator it; 110 | for (it = masterCopyTxTC.begin(); it != masterCopyTxTC.end(); ++it) { 111 | if (&it == frame_ptr) { 112 | masterCopyTxTC.erase(it); 113 | return; 114 | } 115 | } 116 | } 117 | 118 | void MasterChannel::removeMasterTx(TransferFrameTM* frame_ptr) { 119 | etl::list::iterator it; 120 | for (it = masterCopyTxTM.begin(); it != masterCopyTxTM.end(); ++it) { 121 | if (&it == frame_ptr) { 122 | masterCopyTxTM.erase(it); 123 | return; 124 | } 125 | } 126 | } 127 | 128 | void MasterChannel::removeMasterRx(TransferFrameTC* frame_ptr) { 129 | etl::list::iterator it; 130 | for (it = masterCopyRxTC.begin(); it != masterCopyRxTC.end(); ++it) { 131 | if (&it == frame_ptr) { 132 | masterCopyRxTC.erase(it); 133 | return; 134 | } 135 | } 136 | } 137 | 138 | void MasterChannel::removeMasterRx(TransferFrameTM* frame_ptr) { 139 | etl::list::iterator it; 140 | for (it = masterCopyRxTM.begin(); it != masterCopyRxTM.end(); ++it) { 141 | if (&it == frame_ptr) { 142 | masterCopyRxTM.erase(it); 143 | return; 144 | } 145 | } 146 | } 147 | void MasterChannel::acknowledgeFrame(uint8_t frameSequenceNumber) { 148 | for (TransferFrameTC& transferFrame : masterCopyTxTC) { 149 | if (transferFrame.transferFrameSequenceNumber() == frameSequenceNumber) { 150 | transferFrame.setAcknowledgement(true); 151 | return; 152 | } 153 | } 154 | } 155 | 156 | void MasterChannel::setRetransmitFrame(uint8_t frameSequenceNumber) { 157 | for (TransferFrameTC transferFrame : masterCopyTxTC) { 158 | if (transferFrame.transferFrameSequenceNumber() == frameSequenceNumber) { 159 | transferFrame.setToBeRetransmitted(true); 160 | return; 161 | } 162 | } 163 | } 164 | 165 | TransferFrameTC MasterChannel::getLastTxMasterCopyTcFrame() { 166 | return masterCopyTxTC.back(); 167 | } 168 | 169 | TransferFrameTC MasterChannel::geFirstTxMasterCopyTcFrame() { 170 | return masterCopyTxTC.front(); 171 | } -------------------------------------------------------------------------------- /src/CLCW.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CLCW.hpp" 3 | -------------------------------------------------------------------------------- /src/FrameAcceptanceReporting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CCSDSLogger.h" 3 | 4 | COPDirectiveResponse FrameAcceptanceReporting::frameArrives() { 5 | TransferFrameTC* frame = waitQueue->front(); 6 | waitQueue->pop_front(); 7 | 8 | if ((frame->getServiceType() == ServiceType::TYPE_AD)) { 9 | if (frame->transferFrameSequenceNumber() == receiverFrameSeqNumber) { 10 | if (!sentQueue->full()) { 11 | // E1 12 | if (state == FARMState::OPEN) { 13 | sentQueue->push_back(frame); 14 | receiverFrameSeqNumber += 1; 15 | retransmit = FlagState::NOT_READY; 16 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, ACCEPT); 17 | return COPDirectiveResponse::ACCEPT; 18 | } else { 19 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, REJECT); 20 | return COPDirectiveResponse::REJECT; 21 | } 22 | } else { 23 | // E2 24 | if (state == FARMState::OPEN) { 25 | retransmit = FlagState::READY; 26 | wait = FlagState::READY; 27 | state = FARMState::WAIT; 28 | } 29 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, REJECT); 30 | return COPDirectiveResponse::REJECT; 31 | } 32 | } else if ((frame->transferFrameSequenceNumber() > receiverFrameSeqNumber) && 33 | (frame->transferFrameSequenceNumber() <= receiverFrameSeqNumber + farmPositiveWinWidth - 1)) { 34 | // E3 35 | if (state == FARMState::OPEN) { 36 | retransmit = FlagState::READY; 37 | } 38 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, REJECT); 39 | return COPDirectiveResponse::REJECT; 40 | } else if ((frame->transferFrameSequenceNumber() < receiverFrameSeqNumber) && 41 | (frame->transferFrameSequenceNumber() >= receiverFrameSeqNumber - farmNegativeWidth)) { 42 | // E4 43 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, REJECT); 44 | return COPDirectiveResponse::REJECT; 45 | } else if ((frame->transferFrameSequenceNumber() > receiverFrameSeqNumber + farmPositiveWinWidth - 1) && 46 | (frame->transferFrameSequenceNumber() < (receiverFrameSeqNumber > farmNegativeWidth) 47 | ? receiverFrameSeqNumber - farmNegativeWidth 48 | : 256 - farmNegativeWidth)) { 49 | // E5 50 | state = FARMState::LOCKOUT; 51 | lockout = FlagState::READY; 52 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, REJECT); 53 | return COPDirectiveResponse::REJECT; 54 | } 55 | } else if (((frame->getServiceType() == ServiceType::TYPE_BC) || 56 | (frame->getServiceType() == ServiceType::TYPE_BD)) && 57 | !frame->transferFrameHeader().ctrlAndCmdFlag()) { 58 | // E6 59 | farmBCount += 1; 60 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, ACCEPT); 61 | return COPDirectiveResponse::ACCEPT; 62 | } else if (frame->getServiceType() == ServiceType::TYPE_BC) { 63 | if (frame->controlWordType() == 0) { 64 | if (frame->frameData()[5] == 0) { 65 | // E7 66 | farmBCount += 1; 67 | retransmit = FlagState::NOT_READY; 68 | 69 | if (state == FARMState::WAIT) { 70 | wait = FlagState::NOT_READY; 71 | } else if (state == FARMState::LOCKOUT) { 72 | wait = FlagState::NOT_READY; 73 | lockout = FlagState::NOT_READY; 74 | } 75 | state = FARMState::OPEN; 76 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, ACCEPT); 77 | return COPDirectiveResponse::ACCEPT; 78 | } else if (frame->frameData()[5] == 130 && frame->frameData()[6] == 0) { 79 | // E8 80 | farmBCount += 1; 81 | retransmit = FlagState::NOT_READY; 82 | receiverFrameSeqNumber = frame->frameData()[6]; 83 | ccsdsLogNotice(Tx, TypeCOPDirectiveResponse, ACCEPT); 84 | return COPDirectiveResponse::ACCEPT; 85 | } 86 | } 87 | } 88 | // Invalid Directive 89 | return COPDirectiveResponse::REJECT; 90 | } 91 | 92 | COPDirectiveResponse FrameAcceptanceReporting::bufferRelease() { 93 | if (state == FARMState::LOCKOUT) { 94 | state = FARMState::OPEN; 95 | wait = FlagState::NOT_READY; 96 | } else if (state == FARMState::WAIT) { 97 | wait = FlagState::NOT_READY; 98 | } 99 | return COPDirectiveResponse::ACCEPT; 100 | } -------------------------------------------------------------------------------- /src/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | etl::format_spec Logger::format; 4 | 5 | Logger::LogEntry::LogEntry(LogLevel level) : level(level) {} 6 | 7 | // Reimplementation of the function for variable C strings 8 | template <> 9 | Logger::LogEntry& Logger::LogEntry::operator<<(char* value) { 10 | message.append(value); 11 | return *this; 12 | } 13 | 14 | // Reimplementation of the function for C strings 15 | template <> 16 | Logger::LogEntry& Logger::LogEntry::operator<<(const char* value) { 17 | message.append(value); 18 | return *this; 19 | } 20 | 21 | Logger::LogEntry::~LogEntry() { 22 | // When the destructor is called, the log message is fully "designed". Now we can finally "display" it to the user. 23 | Logger::log(level, message); 24 | } 25 | -------------------------------------------------------------------------------- /src/MemoryPool.cpp: -------------------------------------------------------------------------------- 1 | #include "MemoryPool.hpp" 2 | #include "cstring" 3 | #include "Logger.hpp" 4 | #include "Alert.hpp" 5 | #include "CCSDS_Definitions.hpp" 6 | 7 | uint8_t* MemoryPool::allocatePacket(uint8_t* packet, uint16_t packetLength) { 8 | std::pair index = findFit(packetLength); 9 | uint16_t start = index.first; 10 | if (index.second == NO_SPACE) { 11 | LOG_ERROR << "There is no space in memory pool for the packet."; 12 | return nullptr; 13 | } 14 | std::memcpy(memory + start, packet, packetLength * sizeof(uint8_t)); 15 | 16 | usedMemory[index.first] = packetLength; 17 | 18 | return memory + start; 19 | } 20 | 21 | bool MemoryPool::deletePacket(uint8_t* packet, uint16_t packetLength) { 22 | int32_t indexInMemory = packet - &memory[0]; 23 | if (indexInMemory >= 0 && indexInMemory + packetLength < memorySize) { 24 | usedMemory.erase(indexInMemory); 25 | return true; 26 | } 27 | LOG() << "Packet not found, index is out of bounds"; 28 | return false; 29 | } 30 | 31 | std::pair MemoryPool::findFit(uint16_t packetLength) { 32 | std::pair fit; 33 | fit.second = MasterChannelAlert::NO_MC_ALERT; 34 | 35 | if (packetLength > memorySize) { 36 | fit.second = NO_SPACE; 37 | return fit; 38 | } 39 | 40 | const etl::imap::iterator iteratorBegin = usedMemory.begin(); 41 | const etl::imap::iterator iteratorEnd = --usedMemory.end(); 42 | 43 | // Check whether list is empty or the packet can fit in the beginning 44 | if (usedMemory.empty() || (iteratorBegin->first >= packetLength)) { 45 | usedMemory[0] = packetLength; 46 | fit.first = 0; 47 | return fit; 48 | } 49 | 50 | uint16_t gapSize; 51 | 52 | etl::imap::iterator mapIterator = iteratorBegin; 53 | 54 | for (mapIterator; mapIterator != iteratorEnd; mapIterator++) { 55 | gapSize = etl::next(mapIterator)->first - (mapIterator->first + mapIterator->second); 56 | if (gapSize >= packetLength) { 57 | usedMemory[mapIterator->first + mapIterator->second] = packetLength; 58 | fit.first = mapIterator->first + mapIterator->second; 59 | return fit; 60 | } 61 | } 62 | 63 | gapSize = memorySize - (iteratorEnd->first + iteratorEnd->second); 64 | 65 | // Check whether list is empty or the packet can fit in the end 66 | if (gapSize >= packetLength) { 67 | usedMemory[iteratorEnd->first + iteratorEnd->second] = packetLength; 68 | fit.first = iteratorEnd->first + iteratorEnd->second; 69 | return fit; 70 | } 71 | 72 | fit.second = NO_SPACE; 73 | return fit; 74 | } 75 | 76 | uint8_t* MemoryPool::getMemory() { 77 | return &memory[0]; 78 | } 79 | -------------------------------------------------------------------------------- /src/Packet.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AcubeSAT/ccsds-space-data-link-protocols/d55722f2d474ce6dc952cddbb34b6c39b8d06466/src/Packet.cpp -------------------------------------------------------------------------------- /src/Platform/x86/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | // The implementation of this function appends ANSI codes that should add colours to a compatible terminal 9 | void Logger::log(Logger::LogLevel level, etl::istring& message) { 10 | // Get the current time & date 11 | std::time_t t = std::time(nullptr); 12 | std::tm tm = *std::localtime(&t); 13 | 14 | // Get the log level and its colour 15 | std::string name; 16 | std::string colour; 17 | bool keepColour = false; // Whether to keep the colour in the rest of the message 18 | 19 | if (level <= Logger::trace) { 20 | name = "trace"; 21 | colour = "90"; // bright black 22 | keepColour = true; 23 | } else if (level <= Logger::debug) { 24 | name = "debug"; 25 | colour = "90"; // bright black 26 | } else if (level <= Logger::info) { 27 | name = "info"; 28 | colour = "32"; // green 29 | } else if (level <= Logger::notice) { 30 | name = "notice"; 31 | colour = "36"; // cyan 32 | } else if (level <= Logger::warning) { 33 | name = "warning"; 34 | colour = "33"; // yellow 35 | } else if (level <= Logger::error) { 36 | name = "error"; 37 | colour = "31"; // red 38 | } else { 39 | name = "emergency"; 40 | colour = "31"; // red 41 | keepColour = true; 42 | } 43 | 44 | std::ostringstream ss; // A string stream to create the log message 45 | ss << "\033" 46 | "[0;90m" 47 | << std::put_time(&tm, "%FT%T%z") 48 | << "\033" 49 | "[0m "; // The date 50 | ss << "[\033" 51 | "[1;" 52 | << colour << "m" << std::setfill(' ') << std::setw(7) << std::right // Ignore-MISRA 53 | << name << std::setw(0) 54 | << "\033" 55 | "[0m] "; // The log level // Ignore-MISRA 56 | 57 | if (keepColour) { 58 | ss << "\033" 59 | "[0;" 60 | << colour << "m"; // Ignore-MISRA 61 | } 62 | ss << message.c_str(); // The message itself 63 | if (keepColour) { 64 | ss << "\033" 65 | "[0m"; 66 | } 67 | 68 | ss << "\n"; 69 | std::cerr << ss.str(); 70 | } 71 | 72 | // Reimplementation of the log function for C++ strings 73 | // This is kept in the Platform files, since we don't want to mess with std::strings in the microcontroller 74 | Logger::LogEntry& Logger::LogEntry::operator<<(const std::string& value) { 75 | message.append(value.c_str()); 76 | 77 | return *this; 78 | } 79 | -------------------------------------------------------------------------------- /src/TransferFrameTC.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AcubeSAT/ccsds-space-data-link-protocols/d55722f2d474ce6dc952cddbb34b6c39b8d06466/src/TransferFrameTC.cpp -------------------------------------------------------------------------------- /src/logOperators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | std::ostream& operator<<(std::ostream& out, const TxRx value) { 4 | static std::map strings; 5 | if (strings.empty()) { 6 | #define INSERT_ELEMENT(p) strings[p] = #p 7 | INSERT_ELEMENT(Tx); 8 | INSERT_ELEMENT(Rx); 9 | #undef INSERT_ELEMENT 10 | } 11 | return out << strings[value]; 12 | } 13 | 14 | std::ostream& operator<<(std::ostream& out, const NotificationType value) { 15 | static std::map strings; 16 | if (strings.empty()) { 17 | #define INSERT_ELEMENT(p) strings[p] = #p 18 | INSERT_ELEMENT(TypeVirtualChannelAlert); 19 | INSERT_ELEMENT(TypeMasterChannelAlert); 20 | INSERT_ELEMENT(TypeServiceChannelNotif); 21 | INSERT_ELEMENT(TypeCOPDirectiveResponse); 22 | INSERT_ELEMENT(TypeFOPNotif); 23 | INSERT_ELEMENT(TypeFDURequestType); 24 | #undef INSERT_ELEMENT 25 | } 26 | return out << strings[value]; 27 | } 28 | 29 | std::ostream& operator<<(std::ostream& out, const ServiceChannelNotification value) { 30 | static std::map strings; 31 | if (strings.empty()) { 32 | #define INSERT_ELEMENT(p) strings[p] = #p 33 | INSERT_ELEMENT(NO_SERVICE_EVENT); 34 | INSERT_ELEMENT(MAP_CHANNEL_FRAME_BUFFER_FULL); 35 | INSERT_ELEMENT(MASTER_CHANNEL_FRAME_BUFFER_FULL); 36 | INSERT_ELEMENT(VC_MC_FRAME_BUFFER_FULL); 37 | INSERT_ELEMENT(TX_MC_FRAME_BUFFER_FULL); 38 | INSERT_ELEMENT(NO_TX_PACKETS_TO_PROCESS); 39 | INSERT_ELEMENT(NO_RX_PACKETS_TO_PROCESS); 40 | INSERT_ELEMENT(PACKET_EXCEEDS_MAX_SIZE); 41 | INSERT_ELEMENT(FOP_SENT_QUEUE_FULL); 42 | INSERT_ELEMENT(TX_TO_BE_TRANSMITTED_FRAMES_LIST_EMPTY); 43 | INSERT_ELEMENT(TX_TO_BE_TRANSMITTED_FRAMES_LIST_FULL); 44 | INSERT_ELEMENT(FOP_REQUEST_REJECTED); 45 | INSERT_ELEMENT(RX_IN_MC_FULL); 46 | INSERT_ELEMENT(RX_IN_BUFFER_FULL); 47 | INSERT_ELEMENT(RX_OUT_BUFFER_FULL); 48 | INSERT_ELEMENT(RX_INVALID_TFVN); 49 | INSERT_ELEMENT(RX_INVALID_SCID); 50 | INSERT_ELEMENT(RX_INVALID_LENGTH); 51 | INSERT_ELEMENT(VC_RX_WAIT_QUEUE_FULL); 52 | INSERT_ELEMENT(TX_FOP_REJECTED); 53 | #undef INSERT_ELEMENT 54 | } 55 | return out << strings[value]; 56 | } 57 | 58 | std::ostream& operator<<(std::ostream& out, const COPDirectiveResponse value) { 59 | static std::map strings; 60 | if (strings.empty()) { 61 | #define INSERT_ELEMENT(p) strings[p] = #p 62 | INSERT_ELEMENT(ACCEPT); 63 | INSERT_ELEMENT(REJECT); 64 | #undef INSERT_ELEMENT 65 | } 66 | return out << strings[value]; 67 | } 68 | 69 | std::ostream& operator<<(std::ostream& out, const FOPNotification value) { 70 | static std::map strings; 71 | if (strings.empty()) { 72 | #define INSERT_ELEMENT(p) strings[p] = #p 73 | INSERT_ELEMENT(NO_FOP_EVENT); 74 | INSERT_ELEMENT(SENT_QUEUE_FULL); 75 | INSERT_ELEMENT(WAIT_QUEUE_EMPTY); 76 | #undef INSERT_ELEMENT 77 | } 78 | return out << strings[value]; 79 | } 80 | 81 | std::ostream& operator<<(std::ostream& out, const MasterChannelAlert value) { 82 | static std::map strings; 83 | if (strings.empty()) { 84 | #define INSERT_ELEMENT(p) strings[p] = #p 85 | INSERT_ELEMENT(NO_MC_ALERT); 86 | INSERT_ELEMENT(OUT_FRAMES_LIST_FULL); 87 | INSERT_ELEMENT(TO_BE_TRANSMITTED_FRAMES_LIST_FULL); 88 | INSERT_ELEMENT(MAX_AMOUNT_OF_VIRT_CHANNELS); 89 | #undef INSERT_ELEMENT 90 | } 91 | return out << strings[value]; 92 | } 93 | 94 | std::ostream& operator<<(std::ostream& out, const VirtualChannelAlert value) { 95 | static std::map strings; 96 | if (strings.empty()) { 97 | #define INSERT_ELEMENT(p) strings[p] = #p 98 | INSERT_ELEMENT(NO_VC_ALERT); 99 | INSERT_ELEMENT(UNPROCESSED_PACKET_LIST_FULL); 100 | INSERT_ELEMENT(TX_WAIT_QUEUE_FULL); 101 | INSERT_ELEMENT(RX_WAIT_QUEUE_FULL); 102 | #undef INSERT_ELEMENT 103 | } 104 | return out << strings[value]; 105 | } 106 | 107 | std::ostream& operator<<(std::ostream& out, const FDURequestType value) { 108 | static std::map strings; 109 | if (strings.empty()) { 110 | #define INSERT_ELEMENT(p) strings[p] = #p 111 | INSERT_ELEMENT(REQUEST_PENDING); 112 | INSERT_ELEMENT(REQUEST_POSITIVE_CONFIRM); 113 | INSERT_ELEMENT(REQUEST_NEGATIVE_CONFIRM); 114 | #undef INSERT_ELEMENT 115 | } 116 | return out << strings[value]; 117 | } 118 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.hpp" 2 | #include "CCSDSChannel.hpp" 3 | #include "CCSDSLogger.h" 4 | 5 | int main() { 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/CCSDSChannel.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "CLCW.hpp" 7 | 8 | TEST_CASE("CCSDS TC Channel Model") { 9 | // @todo add more and better test cases :) 10 | 11 | PhysicalChannel phy_channel = PhysicalChannel(1024, 12, 1024, 220000, 20); 12 | 13 | etl::flat_map map_channels = {{2, MAPChannel(2, false, false)}, 14 | {3, MAPChannel(3, true, true)}}; 15 | 16 | uint8_t data[] = {0x00, 0xDA, 0x42, 0x32, 0x43, 0x12, 0x77, 0xFA, 0x3C, 0xBB, 0x92}; 17 | MasterChannel master_channel = MasterChannel(); 18 | master_channel.addVC(3, 1024, true, 32, 32, true, true, true, 8, SynchronizationFlag::FORWARD_ORDERED, 255, 10, 10, 3, 19 | map_channels); 20 | 21 | CHECK(master_channel.virtualChannels.at(3).VCID == 0x03); 22 | PhysicalChannel physical_channel = 23 | PhysicalChannel(TmTransferFrameSize, 100, 50, 20000, 5); 24 | ServiceChannel serv_channel = ServiceChannel(std::move(master_channel), std::move(physical_channel)); 25 | } 26 | 27 | TEST_CASE("MAPP blocking") { 28 | ServiceChannelNotification err; 29 | PhysicalChannel physical_channel = 30 | PhysicalChannel(TmTransferFrameSize, 100, 50, 20000, 5); 31 | 32 | etl::flat_map map_channels = {{2, MAPChannel(2, true, true)}}; 33 | 34 | MasterChannel master_channel = MasterChannel(); 35 | master_channel.addVC(3, 8, true, 32, 32, true, true, true, 11, SynchronizationFlag::FORWARD_ORDERED, 255, 10, 10, 3, 36 | map_channels); 37 | 38 | CHECK(master_channel.virtualChannels.at(3).VCID == 3); 39 | ServiceChannel serv_channel = ServiceChannel(std::move(master_channel), std::move(physical_channel)); 40 | 41 | uint8_t data[] = {0x00, 0x01, 0x02, 0x30, 0x40, 0x05, 0x06, 0x07, 0x80, 0x90, 0xA0}; 42 | 43 | // TODO: Rework with Memory Pool 44 | // serv_channel.mappRequestTxTC(3, 2); 45 | 46 | // CHECK(serv_channel.availableUnprocessedFramesVcCopyTxTC(3) == MaxReceivedUnprocessedTxTcInVirtBuffer - 6); 47 | // CHECK(serv_channel.availableUnprocessedFramesVcCopyTxTC(3, 2) == MaxReceivedTcInMapChannel - 0); 48 | } 49 | 50 | TEST_CASE("Virtual Channel Generation") {} 51 | 52 | TEST_CASE("CLCW parsing") { 53 | uint32_t operationalControlField = 0xD342269; 54 | bool operationalControlFieldExists = true; 55 | CLCW clcw = CLCW(operationalControlField); 56 | bool controlWordType = clcw.getControlWordType(); 57 | uint8_t clcwVersion = clcw.getClcwVersion(); 58 | uint8_t statusField = clcw.getStatusField(); 59 | uint8_t copInEffect = clcw.getCopInEffect(); 60 | uint8_t vcId = clcw.getVcId(); 61 | uint8_t spare = 0; 62 | bool noRfAvailable = clcw.getNoRfAvailable(); 63 | bool bitLock = clcw.getNoBitLock(); 64 | bool lockout = clcw.getLockout(); 65 | bool wait = clcw.getWait(); 66 | bool retransmit = clcw.getRetransmit(); 67 | uint8_t farmBCounter = clcw.getFarmBCounter(); 68 | bool spare2 = 0; 69 | uint8_t reportValue = clcw.getReportValue(); 70 | 71 | CHECK(controlWordType == 0); 72 | CHECK(clcwVersion == 0); 73 | CHECK(statusField == 3); 74 | CHECK(copInEffect == 1); 75 | CHECK(vcId == 13); 76 | CHECK(spare == 0); 77 | CHECK(noRfAvailable == 0); 78 | CHECK(bitLock == 0); 79 | CHECK(lockout == 1); 80 | CHECK(wait == 0); 81 | CHECK(retransmit == 0); 82 | CHECK(farmBCounter == 1); 83 | CHECK(spare2 == 0); 84 | CHECK(reportValue == 105); 85 | 86 | CLCW parsedClcw = CLCW(controlWordType, clcwVersion, statusField, copInEffect, vcId, spare, noRfAvailable, bitLock, 87 | lockout, wait, retransmit, farmBCounter, spare2, reportValue); 88 | 89 | CHECK(operationalControlField == parsedClcw.getClcw()); 90 | } 91 | -------------------------------------------------------------------------------- /test/FrameOperationProcedure.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | TEST_CASE("Initiate FOP Directives") { 8 | PhysicalChannel phy_channel_fop = PhysicalChannel(1024, 12, 1024, 220000, 20); 9 | 10 | etl::flat_map map_channels_fop = {{2, MAPChannel(2, true, false)}, 11 | {3, MAPChannel(3, false, false)}}; 12 | 13 | uint8_t data[] = {0x00, 0xDA, 0x42, 0x32, 0x43, 0x12, 0x77, 0xFA, 0x3C, 0xBB, 0x92}; 14 | MasterChannel master_channel_fop = MasterChannel(); 15 | master_channel_fop.addVC(3, 1024, true, 32, 32, true, true, true, 32, SynchronizationFlag::FORWARD_ORDERED, 255, 10, 16 | 10, 3, map_channels_fop); 17 | 18 | ServiceChannel serv_channel_fop = ServiceChannel(master_channel_fop, phy_channel_fop); 19 | 20 | serv_channel_fop.storePacketTxTC(data, 11, 3, 2, ServiceType::TYPE_AD); 21 | serv_channel_fop.mappRequestTxTC(3, 2, 11, ServiceType::TYPE_AD); 22 | 23 | CHECK(serv_channel_fop.txAvailableTC(3, 2) == MaxReceivedTcInMapChannel); 24 | 25 | CHECK(serv_channel_fop.fopState(3) == FOPState::INITIAL); 26 | serv_channel_fop.initiateAdNoClcw(3); 27 | CHECK(serv_channel_fop.fopState(3) == FOPState::ACTIVE); 28 | serv_channel_fop.terminateAdService(3); 29 | serv_channel_fop.setVs(3, 6); 30 | CHECK(serv_channel_fop.expectedFrameSeqNumber(3) == 6); 31 | CHECK(serv_channel_fop.transmitterFrameSeqNumber(3) == 6); 32 | CHECK(serv_channel_fop.fopState(3) == FOPState::INITIAL); 33 | serv_channel_fop.initiateAdUnlock(3); 34 | 35 | CHECK(serv_channel_fop.timeoutType(3) == 0); 36 | serv_channel_fop.setTimeoutType(3, 1); 37 | CHECK(serv_channel_fop.timeoutType(3) == 1); 38 | 39 | CHECK(serv_channel_fop.t1Timer(3) == FopTimerInitial); 40 | serv_channel_fop.setT1Initial(3, 55); 41 | CHECK(serv_channel_fop.t1Timer(3) == 55); 42 | 43 | CHECK(serv_channel_fop.fopSlidingWindowWidth(3) == FopSlidingWindowInitial); 44 | serv_channel_fop.setFopWidth(3, 100); 45 | CHECK(serv_channel_fop.fopSlidingWindowWidth(3) == 100); 46 | } 47 | TEST_CASE("Retransmission"){ 48 | PhysicalChannel phy_channel_fop = PhysicalChannel(1024, 12, 1024, 220000, 20); 49 | 50 | etl::flat_map map_channels = { 51 | {0, MAPChannel(0, true, true)}, 52 | {1, MAPChannel(1, false, false)}, 53 | {2, MAPChannel(2, true, false)}, 54 | }; 55 | 56 | MasterChannel master_channel = MasterChannel(); 57 | master_channel.addVC(0, 128, true, 2, 2, false, false, 0, 8, SynchronizationFlag::FORWARD_ORDERED, 255, 10, 10, 3, 58 | map_channels); 59 | master_channel.addVC(1, 128, true, 2, 2, false, false, 0, 8, SynchronizationFlag::FORWARD_ORDERED, 255, 10, 10, 3, 60 | map_channels); 61 | 62 | ServiceChannel serv_channel = ServiceChannel(master_channel, phy_channel_fop); 63 | VirtualChannel virtualChannel = master_channel.virtualChannels.at(0); 64 | 65 | uint8_t packet1[] = {0x10, 0xB1, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x1C, 0xD3, 0x8C}; 66 | uint8_t packet2[] = {0x10, 0xB1, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x1C, 0xD3, 0x8C}; 67 | uint8_t packet3[] = {0x10, 0xB1, 0x00, 0x0A, 0x12, 0x00, 0x00, 0x1C, 0xD3, 0x8C}; 68 | 69 | 70 | //Send 3 frames 71 | serv_channel.initiateAdClcw(0); 72 | serv_channel.storePacketTxTC(packet1, 9, 0, 0, ServiceType::TYPE_AD); 73 | serv_channel.storePacketTxTC(packet2, 9, 0, 0, ServiceType::TYPE_AD); 74 | serv_channel.storePacketTxTC(packet3, 9, 0, 0, ServiceType::TYPE_AD); 75 | for (uint8_t i = 0; i < 3; i++){ 76 | serv_channel.mappRequestTxTC(0, 0, 9, ServiceType::TYPE_AD); 77 | serv_channel.vcGenerationRequestTxTC(0); 78 | serv_channel.allFramesGenerationRequestTxTC(); 79 | } 80 | CHECK(serv_channel.getLastMasterCopyTcFrame().transferFrameSequenceNumber() == 2); 81 | CHECK(serv_channel.frontUnprocessedFrameMcCopyTxTC().transferFrameSequenceNumber() == 0); 82 | 83 | //Create a CLCW that indicates that retransmission is needed aka a negative acknowledgement 84 | CLCW clcw = CLCW(0,0,0,1,0,0,1,0,0,0,1,0,0,0); 85 | uint8_t clcwData[TmTransferFrameSize] = {0}; 86 | for (uint8_t i = TmPrimaryHeaderSize; i < TmTransferFrameSize ; i++) { 87 | // add idle data 88 | clcwData[i] = idle_data[i]; 89 | } 90 | //Create a transfer frame that carries the above CLCW 91 | TransferFrameTM clcwTransferFrame = 92 | TransferFrameTM(clcwData, TmTransferFrameSize, 0, 0, 93 | false, false, NoSegmentation, 94 | FORWARD_ORDERED, clcw.clcw, TM); 95 | //Receive the CLCW frame 96 | serv_channel.allFramesReceptionRequestRxTM(clcwData, TmTransferFrameSize); 97 | //E10 enters 98 | CHECK(serv_channel.fopState(0) == RETRANSMIT_WITHOUT_WAIT); 99 | } 100 | -------------------------------------------------------------------------------- /test/MemoryPool.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include 3 | #include 4 | 5 | TEST_CASE("Packet Insertions") { 6 | // Initialize packets 7 | uint8_t data[5] = {1, 2, 3, 4, 5}; 8 | uint8_t data2[5] = {1, 2, 3, 4, 5}; 9 | uint8_t data3[1] = {100}; 10 | uint8_t data4[1] = {65}; 11 | uint8_t data5[1] = {71}; 12 | 13 | // Insertions 14 | SECTION("Packet insertion with empty memory") { 15 | // Initialize memory pool 16 | MemoryPool pool = MemoryPool(); 17 | 18 | uint8_t* packet = pool.allocatePacket(data, 5); 19 | CHECK(pool.getUsedMemory()[0] == 5); 20 | for (unsigned int i = 0; i < 5; i++) { 21 | CHECK(pool.getMemory()[i] == data[i]); 22 | } 23 | } 24 | SECTION("Bigger packet than empty space") { 25 | // Initialize memory pool 26 | MemoryPool pool = MemoryPool(); 27 | 28 | uint8_t* packet = pool.allocatePacket(data, 5); 29 | CHECK(packet != nullptr); 30 | // TODO: When the buffers are templated change this test 31 | uint8_t* packet2 = pool.allocatePacket(data2, 5); 32 | CHECK(packet2 != nullptr); 33 | CHECK(pool.getUsedMemory()[0] == 5); 34 | CHECK(pool.getUsedMemory()[5] == 5); 35 | } 36 | SECTION("Packet insertions with some space left") { 37 | // Initialize memory pool 38 | MemoryPool pool = MemoryPool(); 39 | 40 | uint8_t* packet = pool.allocatePacket(data, 5); 41 | uint8_t* packet3 = pool.allocatePacket(data3, 1); 42 | CHECK(packet3 != nullptr); 43 | CHECK(pool.getUsedMemory()[0] == 5); 44 | CHECK(pool.getUsedMemory()[5] == 1); 45 | CHECK(pool.getMemory()[5] == 100); 46 | 47 | uint8_t* packet4 = pool.allocatePacket(data4, 1); 48 | CHECK(packet4 != nullptr); 49 | CHECK(pool.getUsedMemory()[6] == 1); 50 | CHECK(pool.getMemory()[6] == data4[0]); 51 | } 52 | SECTION("Packet length equals space left") { 53 | // Initialize memory pool 54 | MemoryPool pool = MemoryPool(); 55 | 56 | uint8_t* packet = pool.allocatePacket(data, 5); 57 | uint8_t* packet3 = pool.allocatePacket(data3, 1); 58 | uint8_t* packet4 = pool.allocatePacket(data4, 1); 59 | uint8_t* packet5 = pool.allocatePacket(data5, 1); 60 | CHECK(pool.getUsedMemory()[7] == true); 61 | CHECK(pool.getMemory()[7] == data5[0]); 62 | } 63 | } 64 | 65 | TEST_CASE("Packet deletions") { 66 | // Initialize memory pool 67 | MemoryPool pool = MemoryPool(); 68 | 69 | // Initialize packets 70 | uint8_t data[5] = {1, 2, 3, 4, 5}; 71 | uint8_t data2[5] = {1, 2, 3, 4, 5}; 72 | uint8_t data3[1] = {100}; 73 | uint8_t data4[1] = {65}; 74 | uint8_t data5[1] = {71}; 75 | 76 | // Allocate the packets as before 77 | uint8_t* packet = pool.allocatePacket(data, 5); 78 | uint8_t* packet2 = pool.allocatePacket(data2, 5); 79 | uint8_t* packet3 = pool.allocatePacket(data3, 1); 80 | uint8_t* packet4 = pool.allocatePacket(data4, 1); 81 | uint8_t* packet5 = pool.allocatePacket(data5, 1); 82 | 83 | SECTION("Delete packets that have not been stored") { 84 | pool.deletePacket(packet2, 5); 85 | CHECK(pool.deletePacket(packet2, 5) == true); 86 | CHECK(pool.deletePacket(packet2, 5) == true); 87 | CHECK(pool.getUsedMemory()[5] == 0); 88 | } 89 | 90 | SECTION("Delete packets that have been stored") { 91 | pool.deletePacket(packet4, 1); 92 | CHECK(pool.deletePacket(packet4, 1) == true); 93 | CHECK(pool.getUsedMemory()[11] == 0); 94 | 95 | pool.deletePacket(packet, 5); 96 | CHECK(pool.deletePacket(packet, 5) == true); 97 | CHECK(pool.getUsedMemory()[0] == 0); 98 | } 99 | } -------------------------------------------------------------------------------- /test/TmFunctionalTesting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CCSDSChannel.hpp" 3 | #include "CCSDSServiceChannel.hpp" 4 | #include "CLCW.hpp" 5 | #include "stdlib.h" 6 | 7 | ServiceChannelNotification randomServiceCallTx(uint16_t frameLength, uint8_t* frame, ServiceChannel* serviceChannel, 8 | etl::queue* packetsVC, 9 | etl::queue* packetsVCLength, 10 | etl::queue* framesSent, 11 | etl::queue* framesSentLength, 12 | uint8_t sentFrame[TmTransferFrameSize], uint8_t gcvid) { 13 | uint8_t randomServicePicker = rand() % 4; 14 | ServiceChannelNotification ser2; 15 | if (randomServicePicker == 0) { 16 | printf("Push frame VC%d - length(%d): \n", gcvid, frameLength); 17 | 18 | for (uint16_t i = 0; i < frameLength; i++) { 19 | printf("%d ", frame[i]); 20 | } 21 | printf("\n"); 22 | 23 | serviceChannel->storePacketTxTM(frame, frameLength, gcvid); 24 | packetsVCLength->push(frameLength); 25 | for (int j = 0; j < frameLength; j++) { 26 | packetsVC->push(frame[j]); 27 | } 28 | printf("Buffer%d: ", gcvid); 29 | for (size_t i = 0; i < packetsVC->size(); i++) { 30 | printf("%d ", packetsVC->front()); 31 | packetsVC->push(packetsVC->front()); 32 | packetsVC->pop(); 33 | } 34 | printf("\n"); 35 | return ServiceChannelNotification::VC_RX_WAIT_QUEUE_FULL; 36 | } else if (randomServicePicker == 1) { 37 | serviceChannel->vcGenerationServiceTxTM(10, gcvid); 38 | return ServiceChannelNotification::VC_RX_WAIT_QUEUE_FULL; 39 | } else if (randomServicePicker == 2) { 40 | serviceChannel->mcGenerationRequestTxTM(); 41 | return ServiceChannelNotification::VC_RX_WAIT_QUEUE_FULL; 42 | ; 43 | } else if (randomServicePicker == 3) { 44 | ser2 = serviceChannel->allFramesGenerationRequestTxTM(sentFrame, TmTransferFrameSize); 45 | 46 | if (ser2 == ServiceChannelNotification::NO_SERVICE_EVENT) { 47 | framesSentLength->push(TmTransferFrameSize); 48 | for (uint8_t j = 0; j < TmTransferFrameSize; j++) { 49 | framesSent->push(sentFrame[j]); 50 | } 51 | } 52 | return ser2; 53 | } 54 | } 55 | 56 | ServiceChannelNotification randomServiceCallRx(bool* flag, uint8_t* sentPacket, uint8_t* sentPacketLength, 57 | ServiceChannel* serviceChannel, 58 | etl::queue* packetsVC, 59 | etl::queue* packetsVCLength, 60 | etl::queue* framesSent, 61 | etl::queue* framesSentLength, 62 | uint8_t receivedPacket[TmTransferFrameSize], uint8_t vid) { 63 | uint8_t randomServicePicker = rand() % 2; 64 | ServiceChannelNotification ser; 65 | if (randomServicePicker == 0) { 66 | if (!framesSentLength->empty()) { 67 | *sentPacketLength = framesSentLength->front(); 68 | framesSentLength->pop(); 69 | for (uint16_t t = 0; t < *sentPacketLength; t++) { 70 | sentPacket[t] = framesSent->front(); 71 | framesSent->pop(); 72 | } 73 | ser = serviceChannel->allFramesReceptionRequestRxTM(sentPacket, TmTransferFrameSize); 74 | } 75 | 76 | } else if (randomServicePicker == 1) { 77 | ser = serviceChannel->packetExtractionRxTM(vid, receivedPacket); 78 | if (ser == ServiceChannelNotification::NO_SERVICE_EVENT) { 79 | if (!packetsVCLength->empty()) { 80 | *flag = true; 81 | *sentPacketLength = packetsVCLength->front(); 82 | packetsVCLength->pop(); 83 | for (uint16_t t = 0; t < *sentPacketLength; t++) { 84 | sentPacket[t] = packetsVC->front(); 85 | packetsVC->pop(); 86 | } 87 | } 88 | printf("Popping frame VC%d - length(%d): \n", vid, *sentPacketLength); 89 | printf("Buffer%d: ", vid); 90 | for (size_t i = 0; i < packetsVC->size(); i++) { 91 | printf("%d ", packetsVC->front()); 92 | packetsVC->push(packetsVC->front()); 93 | packetsVC->pop(); 94 | } 95 | printf("\n"); 96 | } 97 | } 98 | return ser; 99 | } 100 | 101 | TEST_CASE("TM Tx and Rx Testing") { 102 | PhysicalChannel physicalChannel = PhysicalChannel(1024,12, 1024, 103 | 220000, 20); 104 | 105 | etl::flat_map mapChannels = {}; 106 | 107 | MasterChannel masterChannel = MasterChannel(); 108 | 109 | masterChannel.addVC(0, 128, true, 3, 2, 110 | true, false, 0, 111 | true, SynchronizationFlag::FORWARD_ORDERED, 112 | 255, 20, 20, 113 | 10); 114 | 115 | masterChannel.addVC(1, 128, false, 3, 2, 116 | true, false, 0, 117 | true, SynchronizationFlag::FORWARD_ORDERED, 118 | 255, 20, 20, 119 | 10); 120 | 121 | masterChannel.addVC(2, 128, false, 3, 2, 122 | true, false, 0, 123 | true, SynchronizationFlag::FORWARD_ORDERED, 124 | 255, 3, 3, 10); 125 | 126 | ServiceChannel serviceChannel = ServiceChannel(masterChannel, physicalChannel); 127 | uint8_t sentFrame[TmTransferFrameSize] = {0}; 128 | uint8_t receivedPacket[TmTransferFrameSize] = {0}; 129 | uint8_t sentPacket[TmTransferFrameSize] = {0}; 130 | etl::queue packetsVC0; 131 | etl::queue packetsVC1; 132 | etl::queue packetsVC2; 133 | etl::queue packetsVC0Length; 134 | etl::queue packetsVC1Length; 135 | etl::queue packetsVC2Length; 136 | etl::queue framesSent; 137 | etl::queue framesSentLength; 138 | uint8_t maximumPacketLength = 10; 139 | uint8_t frame[TmTransferFrameSize]; 140 | uint8_t numberOfErrors = 0; 141 | uint8_t sentPacketLength = 0; 142 | ServiceChannelNotification serviceNotification; 143 | bool extractedPacket = false; 144 | uint16_t maximumServiceCallsTx = 100; 145 | uint16_t maximumServiceCallsRx = 50; 146 | uint16_t frameLength = maximumPacketLength; 147 | uint8_t virtualChannelPicker; 148 | uint8_t VC1UpperBoundProbability = 50; 149 | uint8_t VC2UpperBoundProbability = 60; 150 | uint8_t VC2LowerBoundProbability = 50; 151 | uint8_t probabilityMaximumNumber = 100; 152 | 153 | for (uint16_t i = 0; i < maximumServiceCallsTx; i++) { 154 | for (uint16_t j = 0; j < frameLength; j++) { 155 | frame[j] = i; 156 | } 157 | virtualChannelPicker = rand() % probabilityMaximumNumber; 158 | if (virtualChannelPicker <= VC1UpperBoundProbability) { 159 | serviceNotification = randomServiceCallTx(frameLength, frame, &serviceChannel, 160 | &packetsVC0,&packetsVC0Length, 161 | &framesSent,&framesSentLength, 162 | sentFrame, 0); 163 | } else if (virtualChannelPicker > VC2LowerBoundProbability && virtualChannelPicker < VC2UpperBoundProbability) { 164 | serviceNotification = randomServiceCallTx(frameLength, frame, &serviceChannel, 165 | &packetsVC1,&packetsVC1Length, 166 | &framesSent, &framesSentLength, 167 | sentFrame, 1); 168 | } else { 169 | serviceNotification = randomServiceCallTx(frameLength, frame, &serviceChannel, 170 | &packetsVC2,&packetsVC2Length, 171 | &framesSent,&framesSentLength, 172 | sentFrame, 2); 173 | } 174 | 175 | if (serviceNotification == ServiceChannelNotification::NO_SERVICE_EVENT) { 176 | for (uint16_t l = 0; l < maximumServiceCallsRx; l++) { 177 | uint8_t virtualChannelPicker2 = rand() % probabilityMaximumNumber; 178 | if (virtualChannelPicker2 <= VC1UpperBoundProbability) { 179 | randomServiceCallRx(&extractedPacket, sentPacket, &sentPacketLength, 180 | &serviceChannel, &packetsVC0, 181 | &packetsVC0Length, &framesSent, 182 | &framesSentLength, receivedPacket, 0); 183 | } else if (virtualChannelPicker2 > VC2LowerBoundProbability && 184 | virtualChannelPicker2 < VC2UpperBoundProbability) { 185 | randomServiceCallRx(&extractedPacket, sentPacket, &sentPacketLength, 186 | &serviceChannel, &packetsVC1, 187 | &packetsVC1Length, &framesSent, 188 | &framesSentLength, receivedPacket, 1); 189 | } else { 190 | randomServiceCallRx(&extractedPacket, sentPacket, &sentPacketLength, 191 | &serviceChannel, &packetsVC2, 192 | &packetsVC2Length, &framesSent, 193 | &framesSentLength, receivedPacket, 2); 194 | } 195 | if (extractedPacket) { 196 | printf("\n -------------------------------------\n"); 197 | printf("Packet temp: "); 198 | 199 | for (uint8_t k = 0; k < sentPacketLength; k++) { 200 | printf("%d ", sentPacket[k]); 201 | printf("%d\n", receivedPacket[k]); 202 | if (sentPacket[k] != receivedPacket[k]) { 203 | numberOfErrors++; 204 | printf("FAILURE :"); 205 | } 206 | } 207 | 208 | printf("\n"); 209 | printf("Packet dest: "); 210 | 211 | for (uint8_t k = 0; k < sentPacketLength; k++) { 212 | printf("%d ", receivedPacket[k]); 213 | } 214 | 215 | printf("\n"); 216 | 217 | extractedPacket = false; 218 | } 219 | } 220 | } 221 | } 222 | CHECK(numberOfErrors == 0); 223 | } 224 | -------------------------------------------------------------------------------- /test/TransferFrame.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | #include 3 | #include 4 | #include 5 | 6 | TEST_CASE("TransferFrameTC Generation") { 7 | uint8_t data[] = {0, 11, 128, 33, 4, 5}; 8 | TransferFrameTC frame = TransferFrameTC(data, 5); 9 | 10 | CHECK(frame.segmentationHeader() == 5); 11 | CHECK(frame.frameData()[0] == 0); 12 | CHECK(frame.frameData()[1] == 11); 13 | CHECK(frame.frameData()[2] == 128); 14 | CHECK(frame.frameData()[3] == 33); 15 | CHECK(frame.frameData()[4] == 4); 16 | } 17 | 18 | TEST_CASE("TC Header Generation") { 19 | uint8_t data[] = {200, 155, 32, 40, 66}; 20 | TransferFrameHeaderTC transfer_frame_header_tc = TransferFrameHeaderTC(data); 21 | CHECK(transfer_frame_header_tc.bypassFlag() == 0x0); 22 | CHECK(transfer_frame_header_tc.vcid(TC) == 0x08); 23 | CHECK(transfer_frame_header_tc.spacecraftId(TC) == 0x9B); 24 | CHECK(transfer_frame_header_tc.ctrlAndCmdFlag() == 0x0); 25 | CHECK(transfer_frame_header_tc.transferFrameLength() == 0x28); 26 | } 27 | 28 | TEST_CASE("TM Header Generation") { 29 | uint8_t data[] = {200, 184, 99, 23, 40, 190}; 30 | TransferFrameHeaderTM transfer_frame_header_tm = TransferFrameHeaderTM(data); 31 | CHECK(transfer_frame_header_tm.spacecraftId(TM) == 0x22); 32 | CHECK(transfer_frame_header_tm.operationalControlFieldFlag() == 0x0); 33 | CHECK(transfer_frame_header_tm.vcid(TM) == 0x04); 34 | CHECK(transfer_frame_header_tm.masterChannelFrameCount() == 0x63); 35 | CHECK(transfer_frame_header_tm.virtualChannelFrameCount() == 0x17); 36 | CHECK(transfer_frame_header_tm.transferFrameSecondaryHeaderFlag() == 0x0); 37 | CHECK(transfer_frame_header_tm.synchronizationFlag() == 0x0); 38 | CHECK(transfer_frame_header_tm.packetOrderFlag() == 0x01); 39 | CHECK(transfer_frame_header_tm.firstHeaderPointer() == 0xBE); 40 | } 41 | 42 | TEST_CASE("PacketTΜ Generation") { 43 | uint8_t data[] = {200, 185, 99, 23, 40, 6, 0, 11, 128, 33, 4, 5, 9, 10}; 44 | TransferFrameTM frame = TransferFrameTM(data, 14, true); 45 | CHECK(frame.frameData()[0] == 200); 46 | CHECK(frame.frameData()[1] == 185); 47 | CHECK(frame.frameData()[2] == 99); 48 | CHECK(frame.frameData()[3] == 23); 49 | CHECK(frame.frameData()[4] == 40); 50 | CHECK(frame.frameData()[5] == 6); 51 | CHECK(frame.getOperationalControlField() == 0x80210405); 52 | // CHECK(frame.global_virtual_channel_id() == 32); 53 | } -------------------------------------------------------------------------------- /test/tests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AcubeSAT/ccsds-space-data-link-protocols/d55722f2d474ce6dc952cddbb34b6c39b8d06466/test/tests -------------------------------------------------------------------------------- /test/tests.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | 3 | #include 4 | --------------------------------------------------------------------------------